xref: /xv6-public/ioapic.c (revision 4f14d8d1)
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