Skip to content
Snippets Groups Projects
io_apic.c 99.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • #ifdef CONFIG_SMP
    void __init setup_ioapic_dest(void)
    {
    
    	int pin, ioapic = 0, irq, irq_entry;
    
    	const struct cpumask *mask;
    
    
    	if (skip_ioapic_setup == 1)
    		return;
    
    
    #ifdef CONFIG_ACPI
    	if (!acpi_disabled && acpi_ioapic) {
    		ioapic = mp_find_ioapic(0);
    		if (ioapic < 0)
    			ioapic = 0;
    	}
    #endif
    
    	for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) {
    		irq_entry = find_irq_entry(ioapic, pin, mp_INT);
    		if (irq_entry == -1)
    			continue;
    		irq = pin_2_irq(irq_entry, ioapic, pin);
    
    		desc = irq_to_desc(irq);
    
    		/*
    		 * Honour affinities which have been set in early boot
    		 */
    		if (desc->status &
    		    (IRQ_NO_BALANCING | IRQ_AFFINITY_SET))
    			mask = desc->affinity;
    		else
    			mask = apic->target_cpus();
    
    		if (intr_remapping_enabled)
    			set_ir_ioapic_affinity_irq_desc(desc, mask);
    		else
    			set_ioapic_affinity_irq_desc(desc, mask);
    
    #define IOAPIC_RESOURCE_NAME_SIZE 11
    
    static struct resource *ioapic_resources;
    
    
    static struct resource * __init ioapic_setup_resources(int nr_ioapics)
    
    {
    	unsigned long n;
    	struct resource *res;
    	char *mem;
    	int i;
    
    	if (nr_ioapics <= 0)
    		return NULL;
    
    	n = IOAPIC_RESOURCE_NAME_SIZE + sizeof(struct resource);
    	n *= nr_ioapics;
    
    	mem = alloc_bootmem(n);
    	res = (void *)mem;
    
    
    	mem += sizeof(struct resource) * nr_ioapics;
    
    	for (i = 0; i < nr_ioapics; i++) {
    		res[i].name = mem;
    		res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
    
    		snprintf(mem, IOAPIC_RESOURCE_NAME_SIZE, "IOAPIC %u", i);
    
    void __init ioapic_init_mappings(void)
    {
    	unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
    
    	struct resource *ioapic_res;
    
    Thomas Gleixner's avatar
    Thomas Gleixner committed
    	int i;
    
    	ioapic_res = ioapic_setup_resources(nr_ioapics);
    
    	for (i = 0; i < nr_ioapics; i++) {
    		if (smp_found_config) {
    
    			ioapic_phys = mp_ioapics[i].apicaddr;
    
    #ifdef CONFIG_X86_32
    
    Thomas Gleixner's avatar
    Thomas Gleixner committed
    			if (!ioapic_phys) {
    				printk(KERN_ERR
    				       "WARNING: bogus zero IO-APIC "
    				       "address found in MPTABLE, "
    				       "disabling IO/APIC support!\n");
    				smp_found_config = 0;
    				skip_ioapic_setup = 1;
    				goto fake_ioapic_page;
    			}
    
    #ifdef CONFIG_X86_32
    
    			ioapic_phys = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
    
    			ioapic_phys = __pa(ioapic_phys);
    		}
    		set_fixmap_nocache(idx, ioapic_phys);
    
    		apic_printk(APIC_VERBOSE, "mapped IOAPIC to %08lx (%08lx)\n",
    			__fix_to_virt(idx) + (ioapic_phys & ~PAGE_MASK),
    			ioapic_phys);
    
    		ioapic_res->end = ioapic_phys + IO_APIC_SLOT_SIZE - 1;
    
    void __init ioapic_insert_resources(void)
    
    {
    	int i;
    	struct resource *r = ioapic_resources;
    
    	if (!r) {
    
    			printk(KERN_ERR
    				"IO APIC resources couldn't be allocated.\n");
    
    	}
    
    	for (i = 0; i < nr_ioapics; i++) {
    		insert_resource(&iomem_resource, r);
    		r++;
    	}
    }
    
    
    int mp_find_ioapic(int gsi)
    {
    	int i = 0;
    
    	/* Find the IOAPIC that manages this GSI. */
    	for (i = 0; i < nr_ioapics; i++) {
    		if ((gsi >= mp_gsi_routing[i].gsi_base)
    		    && (gsi <= mp_gsi_routing[i].gsi_end))
    			return i;
    	}
    
    	printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
    	return -1;
    }
    
    int mp_find_ioapic_pin(int ioapic, int gsi)
    {
    	if (WARN_ON(ioapic == -1))
    		return -1;
    	if (WARN_ON(gsi > mp_gsi_routing[ioapic].gsi_end))
    		return -1;
    
    	return gsi - mp_gsi_routing[ioapic].gsi_base;
    }
    
    static int bad_ioapic(unsigned long address)
    {
    	if (nr_ioapics >= MAX_IO_APICS) {
    		printk(KERN_WARNING "WARING: Max # of I/O APICs (%d) exceeded "
    		       "(found %d), skipping\n", MAX_IO_APICS, nr_ioapics);
    		return 1;
    	}
    	if (!address) {
    		printk(KERN_WARNING "WARNING: Bogus (zero) I/O APIC address"
    		       " found in table, skipping!\n");
    		return 1;
    	}
    
    void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
    {
    	int idx = 0;
    
    	if (bad_ioapic(address))
    		return;
    
    	idx = nr_ioapics;
    
    	mp_ioapics[idx].type = MP_IOAPIC;
    	mp_ioapics[idx].flags = MPC_APIC_USABLE;
    	mp_ioapics[idx].apicaddr = address;
    
    	set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
    	mp_ioapics[idx].apicid = io_apic_unique_id(id);
    	mp_ioapics[idx].apicver = io_apic_get_version(idx);
    
    	/*
    	 * Build basic GSI lookup table to facilitate gsi->io_apic lookups
    	 * and to prevent reprogramming of IOAPIC pins (PCI GSIs).
    	 */
    	mp_gsi_routing[idx].gsi_base = gsi_base;
    	mp_gsi_routing[idx].gsi_end = gsi_base +
    	    io_apic_get_redir_entries(idx);
    
    	printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, "
    	       "GSI %d-%d\n", idx, mp_ioapics[idx].apicid,
    	       mp_ioapics[idx].apicver, mp_ioapics[idx].apicaddr,
    	       mp_gsi_routing[idx].gsi_base, mp_gsi_routing[idx].gsi_end);
    
    	nr_ioapics++;
    }