xref: /xv6-public/ioapic.c (revision 2de1c550)
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
3521575761Srsc ioapicread(int reg)
36c8b29f6dSkaashoek {
3799b11b6cSrsc   ioapic->reg = reg;
3899b11b6cSrsc   return ioapic->data;
39c8b29f6dSkaashoek }
40c8b29f6dSkaashoek 
41c8b29f6dSkaashoek static void
4221575761Srsc ioapicwrite(int reg, uint data)
43c8b29f6dSkaashoek {
4499b11b6cSrsc   ioapic->reg = reg;
4599b11b6cSrsc   ioapic->data = data;
46c8b29f6dSkaashoek }
47c8b29f6dSkaashoek 
48c8b29f6dSkaashoek void
4921575761Srsc ioapicinit(void)
50c8b29f6dSkaashoek {
5199b11b6cSrsc   int i, id, maxintr;
52c8b29f6dSkaashoek 
535c596bb3Skaashoek   if(!ismp)
545c596bb3Skaashoek     return;
555c596bb3Skaashoek 
5699b11b6cSrsc   ioapic = (volatile struct ioapic*)IOAPIC;
5721575761Srsc   maxintr = (ioapicread(REG_VER) >> 16) & 0xFF;
5821575761Srsc   id = ioapicread(REG_ID) >> 24;
5921575761Srsc   if(id != ioapicid)
6021575761Srsc     cprintf("ioapicinit: id isn't equal to ioapicid; not a MP\n");
6199b11b6cSrsc 
6299b11b6cSrsc   // Mark all interrupts edge-triggered, active high, disabled,
6399b11b6cSrsc   // and not routed to any CPUs.
6499b11b6cSrsc   for(i = 0; i <= maxintr; i++){
65*2de1c550SRuss Cox     ioapicwrite(REG_TABLE+2*i, INT_DISABLED | (T_IRQ0 + i));
6621575761Srsc     ioapicwrite(REG_TABLE+2*i+1, 0);
67c8b29f6dSkaashoek   }
68c8b29f6dSkaashoek }
69c8b29f6dSkaashoek 
70c8b29f6dSkaashoek void
7121575761Srsc ioapicenable(int irq, int cpunum)
72c8b29f6dSkaashoek {
735c596bb3Skaashoek   if(!ismp)
745c596bb3Skaashoek     return;
755c596bb3Skaashoek 
7699b11b6cSrsc   // Mark interrupt edge-triggered, active high,
7799b11b6cSrsc   // enabled, and routed to the given cpunum,
7899b11b6cSrsc   // which happens to be that cpu's APIC ID.
79*2de1c550SRuss Cox   ioapicwrite(REG_TABLE+2*irq, T_IRQ0 + irq);
8021575761Srsc   ioapicwrite(REG_TABLE+2*irq+1, cpunum << 24);
81c8b29f6dSkaashoek }
82