📄 io_apic.c
字号:
{ enable_IO_APIC(); if (acpi_ioapic) io_apic_irqs = ~0; /* all IRQs go through IOAPIC */ else io_apic_irqs = ~PIC_IRQS; printk("ENABLING IO-APIC IRQs\n"); printk(" -> Using %s ACK method\n", ioapic_ack_new ? "new" : "old"); /* * Set up IO-APIC IRQ routing. */ if (!acpi_ioapic) setup_ioapic_ids_from_mpc(); sync_Arb_IDs(); setup_IO_APIC_irqs(); init_IO_APIC_traps(); check_timer(); print_IO_APIC(); register_keyhandler('z', print_IO_APIC_keyhandler, "print ioapic info");}struct IO_APIC_route_entry *ioapic_pm_state=NULL;void ioapic_pm_state_alloc(void){ int i, nr_entry = 0; if (ioapic_pm_state != NULL) return; for (i = 0; i < nr_ioapics; i++) nr_entry += nr_ioapic_registers[i]; ioapic_pm_state = _xmalloc(sizeof(struct IO_APIC_route_entry)*nr_entry, sizeof(struct IO_APIC_route_entry));}int ioapic_suspend(void){ struct IO_APIC_route_entry *entry; unsigned long flags; int apic,i; ioapic_pm_state_alloc(); if (ioapic_pm_state == NULL) { printk("Cannot suspend ioapic due to lack of memory\n"); return 1; } entry = ioapic_pm_state; spin_lock_irqsave(&ioapic_lock, flags); for (apic = 0; apic < nr_ioapics; apic++) { for (i = 0; i < nr_ioapic_registers[apic]; i ++, entry ++ ) { *(((int *)entry) + 1) = io_apic_read(apic, 0x11 + 2 * i); *(((int *)entry) + 0) = io_apic_read(apic, 0x10 + 2 * i); } } spin_unlock_irqrestore(&ioapic_lock, flags); return 0;}int ioapic_resume(void){ struct IO_APIC_route_entry *entry; unsigned long flags; union IO_APIC_reg_00 reg_00; int i,apic; if (ioapic_pm_state == NULL){ printk("Cannot resume ioapic due to lack of memory\n"); return 1; } entry = ioapic_pm_state; spin_lock_irqsave(&ioapic_lock, flags); for (apic = 0; apic < nr_ioapics; apic++){ reg_00.raw = io_apic_read(apic, 0); if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid) { reg_00.bits.ID = mp_ioapics[apic].mpc_apicid; io_apic_write(apic, 0, reg_00.raw); } for (i = 0; i < nr_ioapic_registers[apic]; i++, entry++) { io_apic_write(apic, 0x11+2*i, *(((int *)entry)+1)); io_apic_write(apic, 0x10+2*i, *(((int *)entry)+0)); } } spin_unlock_irqrestore(&ioapic_lock, flags); return 0;}/* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration -------------------------------------------------------------------------- */#ifdef CONFIG_ACPI_BOOTint __init io_apic_get_unique_id (int ioapic, int apic_id){ union IO_APIC_reg_00 reg_00; static physid_mask_t apic_id_map = PHYSID_MASK_NONE; physid_mask_t tmp; unsigned long flags; int i = 0; /* * The P4 platform supports up to 256 APIC IDs on two separate APIC * buses (one for LAPICs, one for IOAPICs), where predecessors only * supports up to 16 on one shared APIC bus. * * TBD: Expand LAPIC/IOAPIC support on P4-class systems to take full * advantage of new APIC bus architecture. */ if (physids_empty(apic_id_map)) apic_id_map = ioapic_phys_id_map(phys_cpu_present_map); spin_lock_irqsave(&ioapic_lock, flags); reg_00.raw = io_apic_read(ioapic, 0); spin_unlock_irqrestore(&ioapic_lock, flags); if (apic_id >= get_physical_broadcast()) { printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying " "%d\n", ioapic, apic_id, reg_00.bits.ID); apic_id = reg_00.bits.ID; } /* * Every APIC in a system must have a unique ID or we get lots of nice * 'stuck on smp_invalidate_needed IPI wait' messages. */ if (check_apicid_used(apic_id_map, apic_id)) { for (i = 0; i < get_physical_broadcast(); i++) { if (!check_apicid_used(apic_id_map, i)) break; } if (i == get_physical_broadcast()) panic("Max apic_id exceeded!\n"); printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, " "trying %d\n", ioapic, apic_id, i); apic_id = i; } tmp = apicid_to_cpu_present(apic_id); physids_or(apic_id_map, apic_id_map, tmp); if (reg_00.bits.ID != apic_id) { reg_00.bits.ID = apic_id; spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(ioapic, 0, reg_00.raw); reg_00.raw = io_apic_read(ioapic, 0); spin_unlock_irqrestore(&ioapic_lock, flags); /* Sanity check */ if (reg_00.bits.ID != apic_id) { printk("IOAPIC[%d]: Unable to change apic_id!\n", ioapic); return -1; } } apic_printk(APIC_VERBOSE, KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); return apic_id;}int __init io_apic_get_version (int ioapic){ union IO_APIC_reg_01 reg_01; unsigned long flags; spin_lock_irqsave(&ioapic_lock, flags); reg_01.raw = io_apic_read(ioapic, 1); spin_unlock_irqrestore(&ioapic_lock, flags); return reg_01.bits.version;}int __init io_apic_get_redir_entries (int ioapic){ union IO_APIC_reg_01 reg_01; unsigned long flags; spin_lock_irqsave(&ioapic_lock, flags); reg_01.raw = io_apic_read(ioapic, 1); spin_unlock_irqrestore(&ioapic_lock, flags); return reg_01.bits.entries;}int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int active_high_low){ struct IO_APIC_route_entry entry; unsigned long flags; if (!IO_APIC_IRQ(irq)) { printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", ioapic); return -EINVAL; } /* * Generate a PCI IRQ routing entry and program the IOAPIC accordingly. * Note that we mask (disable) IRQs now -- these get enabled when the * corresponding device driver registers for this IRQ. */ memset(&entry,0,sizeof(entry)); entry.delivery_mode = INT_DELIVERY_MODE; entry.dest_mode = INT_DEST_MODE; entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); entry.trigger = edge_level; entry.polarity = active_high_low; entry.mask = 1; /* * IRQs < 16 are already in the irq_2_pin[] map */ if (irq >= 16) add_pin_to_irq(irq, ioapic, pin); entry.vector = assign_irq_vector(irq); apic_printk(APIC_DEBUG, KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry " "(%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i)\n", ioapic, mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); ioapic_register_intr(irq, entry.vector, edge_level); if (!ioapic && (irq < 16)) disable_8259A_irq(irq); spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1)); io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0)); set_native_irq_info(entry.vector, TARGET_CPUS); spin_unlock_irqrestore(&ioapic_lock, flags); return 0;}#endif /*CONFIG_ACPI_BOOT*/static int ioapic_physbase_to_id(unsigned long physbase){ int apic; for ( apic = 0; apic < nr_ioapics; apic++ ) if ( mp_ioapics[apic].mpc_apicaddr == physbase ) return apic; return -EINVAL;}int ioapic_guest_read(unsigned long physbase, unsigned int reg, u32 *pval){ int apic; unsigned long flags; if ( (apic = ioapic_physbase_to_id(physbase)) < 0 ) return apic; spin_lock_irqsave(&ioapic_lock, flags); *pval = io_apic_read(apic, reg); spin_unlock_irqrestore(&ioapic_lock, flags); return 0;}#define WARN_BOGUS_WRITE(f, a...) \ dprintk(XENLOG_INFO, "\n%s: " \ "apic=%d, pin=%d, old_irq=%d, new_irq=%d\n" \ "%s: old_entry=%08x, new_entry=%08x\n" \ "%s: " f, __FUNCTION__, apic, pin, old_irq, new_irq, \ __FUNCTION__, *(u32 *)&old_rte, *(u32 *)&new_rte, \ __FUNCTION__ , ##a )int ioapic_guest_write(unsigned long physbase, unsigned int reg, u32 val){ int apic, pin, old_irq = -1, new_irq = -1; struct IO_APIC_route_entry old_rte = { 0 }, new_rte = { 0 }; unsigned long flags; if ( (apic = ioapic_physbase_to_id(physbase)) < 0 ) return apic; /* Only write to the first half of a route entry. */ if ( (reg < 0x10) || (reg & 1) ) return 0; pin = (reg - 0x10) >> 1; /* Write first half from guest; second half is target info. */ *(u32 *)&new_rte = val; new_rte.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); /* * What about weird destination types? * SMI: Ignore? Ought to be set up by the BIOS. * NMI: Ignore? Watchdog functionality is Xen's concern. * INIT: Definitely ignore: probably a guest OS bug. * ExtINT: Ignore? Linux only asserts this at start of day. * For now, print a message and return an error. We can fix up on demand. */ if ( new_rte.delivery_mode > dest_LowestPrio ) { printk("ERROR: Attempt to write weird IOAPIC destination mode!\n"); printk(" APIC=%d/%d, lo-reg=%x\n", apic, pin, val); return -EINVAL; } /* * The guest does not know physical APIC arrangement (flat vs. cluster). * Apply genapic conventions for this platform. */ new_rte.delivery_mode = INT_DELIVERY_MODE; new_rte.dest_mode = INT_DEST_MODE; spin_lock_irqsave(&ioapic_lock, flags); /* Read first (interesting) half of current routing entry. */ *(u32 *)&old_rte = io_apic_read(apic, 0x10 + 2 * pin); /* No change to the first half of the routing entry? Bail quietly. */ if ( *(u32 *)&old_rte == *(u32 *)&new_rte ) { spin_unlock_irqrestore(&ioapic_lock, flags); return 0; } /* Special delivery modes (SMI,NMI,INIT,ExtInt) should have no vector. */ if ( (old_rte.delivery_mode > dest_LowestPrio) && (old_rte.vector != 0) ) { WARN_BOGUS_WRITE("Special delivery mode %d with non-zero vector " "%02x\n", old_rte.delivery_mode, old_rte.vector); /* Nobble the vector here as it does not relate to a valid irq. */ old_rte.vector = 0; } if ( old_rte.vector >= FIRST_DYNAMIC_VECTOR ) old_irq = vector_irq[old_rte.vector]; if ( new_rte.vector >= FIRST_DYNAMIC_VECTOR ) new_irq = vector_irq[new_rte.vector]; if ( (old_irq != new_irq) && (old_irq != -1) && IO_APIC_IRQ(old_irq) ) { if ( irq_desc[IO_APIC_VECTOR(old_irq)].action ) { WARN_BOGUS_WRITE("Attempt to remove IO-APIC pin of in-use IRQ!\n"); spin_unlock_irqrestore(&ioapic_lock, flags); return 0; } remove_pin_at_irq(old_irq, apic, pin); } if ( (new_irq != -1) && IO_APIC_IRQ(new_irq) ) { if ( irq_desc[IO_APIC_VECTOR(new_irq)].action ) { WARN_BOGUS_WRITE("Attempt to %s IO-APIC pin for in-use IRQ!\n", (old_irq != new_irq) ? "add" : "modify"); spin_unlock_irqrestore(&ioapic_lock, flags); return 0; } /* Set the correct irq-handling type. */ irq_desc[IO_APIC_VECTOR(new_irq)].handler = new_rte.trigger ? &ioapic_level_type: &ioapic_edge_type; if ( old_irq != new_irq ) add_pin_to_irq(new_irq, apic, pin); /* Mask iff level triggered. */ new_rte.mask = new_rte.trigger; } else if ( !new_rte.mask ) { /* This pin leads nowhere but the guest has not masked it. */ WARN_BOGUS_WRITE("Installing bogus unmasked IO-APIC entry!\n"); new_rte.mask = 1; } io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&new_rte) + 0)); io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&new_rte) + 1)); spin_unlock_irqrestore(&ioapic_lock, flags); return 0;}void dump_ioapic_irq_info(void){ struct irq_pin_list *entry; struct IO_APIC_route_entry rte; unsigned int irq, pin, printed = 0; unsigned long flags; for ( irq = 0; irq < NR_IRQS; irq++ ) { entry = &irq_2_pin[irq]; if ( entry->pin == -1 ) continue; if ( !printed++ ) printk("IO-APIC interrupt information:\n"); printk(" IRQ%3d Vec%3d:\n", irq, irq_to_vector(irq)); for ( ; ; ) { pin = entry->pin; printk(" Apic 0x%02x, Pin %2d: ", entry->apic, pin); spin_lock_irqsave(&ioapic_lock, flags); *(((int *)&rte) + 0) = io_apic_read(entry->apic, 0x10 + 2 * pin); *(((int *)&rte) + 1) = io_apic_read(entry->apic, 0x11 + 2 * pin); spin_unlock_irqrestore(&ioapic_lock, flags); printk("vector=%u, delivery_mode=%u, dest_mode=%s, " "delivery_status=%d
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -