199b11b6cSrsc // The I/O APIC manages hardware interrupts for an SMP system.
299b11b6cSrsc // http://www.intel.com/design/chipsets/datashts/29056601.pdf
3eb52c7deSrsc // See also picirq.c.
499b11b6cSrsc
5c8b29f6dSkaashoek #include "types.h"
6c8b29f6dSkaashoek #include "defs.h"
7c8b29f6dSkaashoek #include "traps.h"
8c8b29f6dSkaashoek
999b11b6cSrsc #define IOAPIC 0xFEC00000 // Default physical address of IO APIC
1099b11b6cSrsc
1199b11b6cSrsc #define REG_ID 0x00 // Register index: ID
1299b11b6cSrsc #define REG_VER 0x01 // Register index: version
1399b11b6cSrsc #define REG_TABLE 0x10 // Redirection table base
1499b11b6cSrsc
1599b11b6cSrsc // The redirection table starts at REG_TABLE and uses
1699b11b6cSrsc // two registers to configure each interrupt.
1799b11b6cSrsc // The first (low) register in a pair contains configuration bits.
1899b11b6cSrsc // The second (high) register contains a bitmask telling which
1999b11b6cSrsc // CPUs can serve that interrupt.
20eadbd55aSrsc #define INT_DISABLED 0x00010000 // Interrupt disabled
2199b11b6cSrsc #define INT_LEVEL 0x00008000 // Level-triggered (vs edge-)
2299b11b6cSrsc #define INT_ACTIVELOW 0x00002000 // Active low (vs high)
2399b11b6cSrsc #define INT_LOGICAL 0x00000800 // Destination is CPU id (vs APIC ID)
2499b11b6cSrsc
2599b11b6cSrsc volatile struct ioapic *ioapic;
2699b11b6cSrsc
2799b11b6cSrsc // IO APIC MMIO structure: write reg, then read or write data.
28c8b29f6dSkaashoek struct ioapic {
2999b11b6cSrsc uint reg;
3099b11b6cSrsc uint pad[3];
3199b11b6cSrsc uint data;
32c8b29f6dSkaashoek };
33c8b29f6dSkaashoek
34c8b29f6dSkaashoek static uint
ioapicread(int reg)3521575761Srsc ioapicread(int reg)
36c8b29f6dSkaashoek {
3799b11b6cSrsc ioapic->reg = reg;
3899b11b6cSrsc return ioapic->data;
39c8b29f6dSkaashoek }
40c8b29f6dSkaashoek
41c8b29f6dSkaashoek static void
ioapicwrite(int reg,uint data)4221575761Srsc ioapicwrite(int reg, uint data)
43c8b29f6dSkaashoek {
4499b11b6cSrsc ioapic->reg = reg;
4599b11b6cSrsc ioapic->data = data;
46c8b29f6dSkaashoek }
47c8b29f6dSkaashoek
48c8b29f6dSkaashoek void
ioapicinit(void)4921575761Srsc ioapicinit(void)
50c8b29f6dSkaashoek {
5199b11b6cSrsc int i, id, maxintr;
52c8b29f6dSkaashoek
5399b11b6cSrsc ioapic = (volatile struct ioapic*)IOAPIC;
5421575761Srsc maxintr = (ioapicread(REG_VER) >> 16) & 0xFF;
5521575761Srsc id = ioapicread(REG_ID) >> 24;
5621575761Srsc if(id != ioapicid)
5721575761Srsc cprintf("ioapicinit: id isn't equal to ioapicid; not a MP\n");
5899b11b6cSrsc
5999b11b6cSrsc // Mark all interrupts edge-triggered, active high, disabled,
6099b11b6cSrsc // and not routed to any CPUs.
6199b11b6cSrsc for(i = 0; i <= maxintr; i++){
62*2de1c550SRuss Cox ioapicwrite(REG_TABLE+2*i, INT_DISABLED | (T_IRQ0 + i));
6321575761Srsc ioapicwrite(REG_TABLE+2*i+1, 0);
64c8b29f6dSkaashoek }
65c8b29f6dSkaashoek }
66c8b29f6dSkaashoek
67c8b29f6dSkaashoek void
ioapicenable(int irq,int cpunum)6821575761Srsc ioapicenable(int irq, int cpunum)
69c8b29f6dSkaashoek {
7099b11b6cSrsc // Mark interrupt edge-triggered, active high,
7199b11b6cSrsc // enabled, and routed to the given cpunum,
7299b11b6cSrsc // which happens to be that cpu's APIC ID.
73*2de1c550SRuss Cox ioapicwrite(REG_TABLE+2*irq, T_IRQ0 + irq);
7421575761Srsc ioapicwrite(REG_TABLE+2*irq+1, cpunum << 24);
75c8b29f6dSkaashoek }
76