diff options
author | tegge <tegge@FreeBSD.org> | 2001-01-28 01:07:54 +0000 |
---|---|---|
committer | tegge <tegge@FreeBSD.org> | 2001-01-28 01:07:54 +0000 |
commit | 55837ed17a3a2de16bb80beea9044a80a8306d29 (patch) | |
tree | 88f37e01221c649b3f54521ccbe3c0f116907f2d /sys | |
parent | 18f604377b44e23f62badff17ec21171a8ca980e (diff) | |
download | FreeBSD-src-55837ed17a3a2de16bb80beea9044a80a8306d29.zip FreeBSD-src-55837ed17a3a2de16bb80beea9044a80a8306d29.tar.gz |
Defer assignment of low level interrupt handlers for PCI interrupts
described in the MP table until something asks for the interrupt number
later on.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/amd64/amd64/mp_machdep.c | 85 | ||||
-rw-r--r-- | sys/amd64/amd64/mptable.c | 85 | ||||
-rw-r--r-- | sys/amd64/include/mptable.h | 85 | ||||
-rw-r--r-- | sys/amd64/include/smp.h | 1 | ||||
-rw-r--r-- | sys/i386/i386/mp_machdep.c | 85 | ||||
-rw-r--r-- | sys/i386/i386/mpapic.c | 156 | ||||
-rw-r--r-- | sys/i386/i386/mptable.c | 85 | ||||
-rw-r--r-- | sys/i386/include/mptable.h | 85 | ||||
-rw-r--r-- | sys/i386/include/smp.h | 1 | ||||
-rw-r--r-- | sys/kern/subr_smp.c | 85 | ||||
-rw-r--r-- | sys/sys/smp.h | 1 |
11 files changed, 424 insertions, 330 deletions
diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c index 598fbf2..b9e96fe 100644 --- a/sys/amd64/amd64/mp_machdep.c +++ b/sys/amd64/amd64/mp_machdep.c @@ -1068,6 +1068,37 @@ revoke_apic_irq(int irq) } +static void +allocate_apic_irq(int intr) +{ + int apic; + int intpin; + int irq; + + if (io_apic_ints[intr].int_vector != 0xff) + return; /* Interrupt handler already assigned */ + + if (io_apic_ints[intr].int_type != 0 && + (io_apic_ints[intr].int_type != 3 || + (io_apic_ints[intr].dst_apic_id == IO_TO_ID(0) && + io_apic_ints[intr].dst_apic_int == 0))) + return; /* Not INT or ExtInt on != (0, 0) */ + + irq = 0; + while (irq < APIC_INTMAPSIZE && + int_to_apicintpin[irq].ioapic != -1) + irq++; + + if (irq >= APIC_INTMAPSIZE) + return; /* No free interrupt handlers */ + + apic = ID_TO_IO(io_apic_ints[intr].dst_apic_id); + intpin = io_apic_ints[intr].dst_apic_int; + + assign_apic_irq(apic, intpin, irq); + io_apic_setup_intpin(apic, intpin); +} + static void swap_apic_id(int apic, int oldid, int newid) @@ -1310,46 +1341,18 @@ setup_apic_irq_mapping(void) } } - /* Assign first set of interrupts to intpins on IOAPIC #0 */ + /* Assign ExtInt entry if no ISA/EISA interrupt 0 entry */ for (x = 0; x < nintrs; x++) { - int_vector = io_apic_ints[x].dst_apic_int; - if (int_vector < APIC_INTMAPSIZE && + if (io_apic_ints[x].dst_apic_int == 0 && io_apic_ints[x].dst_apic_id == IO_TO_ID(0) && io_apic_ints[x].int_vector == 0xff && - int_to_apicintpin[int_vector].ioapic == -1 && - (io_apic_ints[x].int_type == 0 || - io_apic_ints[x].int_type == 3)) { - assign_apic_irq(0, - io_apic_ints[x].dst_apic_int, - int_vector); - } - } - /* - * Assign interrupts for remaining intpins. - * Skip IOAPIC #0 intpin 0 if the type is ExtInt, since this indicates - * that an entry for ISA/EISA irq 0 exist, and a fallback to mixed mode - * due to 8254 interrupts not being delivered can reuse that low level - * interrupt handler. - */ - int_vector = 0; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; - for (x = 0; x < nintrs && int_vector < APIC_INTMAPSIZE; x++) { - if ((io_apic_ints[x].int_type == 0 || - (io_apic_ints[x].int_type == 3 && - (io_apic_ints[x].dst_apic_id != IO_TO_ID(0) || - io_apic_ints[x].dst_apic_int != 0))) && - io_apic_ints[x].int_vector == 0xff) { - assign_apic_irq(ID_TO_IO(io_apic_ints[x].dst_apic_id), - io_apic_ints[x].dst_apic_int, - int_vector); - int_vector++; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; + int_to_apicintpin[0].ioapic == -1 && + io_apic_ints[x].int_type == 3) { + assign_apic_irq(0, 0, 0); + break; } } + /* PCI interrupt assignment is deferred */ } @@ -1522,8 +1525,11 @@ isa_apic_irq(int isa_irq) if (INTTYPE(intr) == 0) { /* standard INT */ if (SRCBUSIRQ(intr) == isa_irq) { if (apic_int_is_bus_type(intr, ISA) || - apic_int_is_bus_type(intr, EISA)) + apic_int_is_bus_type(intr, EISA)) { + if (INTIRQ(intr) == 0xff) + return -1; /* unassigned */ return INTIRQ(intr); /* found */ + } } } } @@ -1549,8 +1555,13 @@ pci_apic_irq(int pciBus, int pciDevice, int pciInt) && (SRCBUSID(intr) == pciBus) && (SRCBUSDEVICE(intr) == pciDevice) && (SRCBUSLINE(intr) == pciInt)) /* a candidate IRQ */ - if (apic_int_is_bus_type(intr, PCI)) + if (apic_int_is_bus_type(intr, PCI)) { + if (INTIRQ(intr) == 0xff) + allocate_apic_irq(intr); + if (INTIRQ(intr) == 0xff) + return -1; /* unassigned */ return INTIRQ(intr); /* exact match */ + } return -1; /* NOT found */ } diff --git a/sys/amd64/amd64/mptable.c b/sys/amd64/amd64/mptable.c index 598fbf2..b9e96fe 100644 --- a/sys/amd64/amd64/mptable.c +++ b/sys/amd64/amd64/mptable.c @@ -1068,6 +1068,37 @@ revoke_apic_irq(int irq) } +static void +allocate_apic_irq(int intr) +{ + int apic; + int intpin; + int irq; + + if (io_apic_ints[intr].int_vector != 0xff) + return; /* Interrupt handler already assigned */ + + if (io_apic_ints[intr].int_type != 0 && + (io_apic_ints[intr].int_type != 3 || + (io_apic_ints[intr].dst_apic_id == IO_TO_ID(0) && + io_apic_ints[intr].dst_apic_int == 0))) + return; /* Not INT or ExtInt on != (0, 0) */ + + irq = 0; + while (irq < APIC_INTMAPSIZE && + int_to_apicintpin[irq].ioapic != -1) + irq++; + + if (irq >= APIC_INTMAPSIZE) + return; /* No free interrupt handlers */ + + apic = ID_TO_IO(io_apic_ints[intr].dst_apic_id); + intpin = io_apic_ints[intr].dst_apic_int; + + assign_apic_irq(apic, intpin, irq); + io_apic_setup_intpin(apic, intpin); +} + static void swap_apic_id(int apic, int oldid, int newid) @@ -1310,46 +1341,18 @@ setup_apic_irq_mapping(void) } } - /* Assign first set of interrupts to intpins on IOAPIC #0 */ + /* Assign ExtInt entry if no ISA/EISA interrupt 0 entry */ for (x = 0; x < nintrs; x++) { - int_vector = io_apic_ints[x].dst_apic_int; - if (int_vector < APIC_INTMAPSIZE && + if (io_apic_ints[x].dst_apic_int == 0 && io_apic_ints[x].dst_apic_id == IO_TO_ID(0) && io_apic_ints[x].int_vector == 0xff && - int_to_apicintpin[int_vector].ioapic == -1 && - (io_apic_ints[x].int_type == 0 || - io_apic_ints[x].int_type == 3)) { - assign_apic_irq(0, - io_apic_ints[x].dst_apic_int, - int_vector); - } - } - /* - * Assign interrupts for remaining intpins. - * Skip IOAPIC #0 intpin 0 if the type is ExtInt, since this indicates - * that an entry for ISA/EISA irq 0 exist, and a fallback to mixed mode - * due to 8254 interrupts not being delivered can reuse that low level - * interrupt handler. - */ - int_vector = 0; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; - for (x = 0; x < nintrs && int_vector < APIC_INTMAPSIZE; x++) { - if ((io_apic_ints[x].int_type == 0 || - (io_apic_ints[x].int_type == 3 && - (io_apic_ints[x].dst_apic_id != IO_TO_ID(0) || - io_apic_ints[x].dst_apic_int != 0))) && - io_apic_ints[x].int_vector == 0xff) { - assign_apic_irq(ID_TO_IO(io_apic_ints[x].dst_apic_id), - io_apic_ints[x].dst_apic_int, - int_vector); - int_vector++; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; + int_to_apicintpin[0].ioapic == -1 && + io_apic_ints[x].int_type == 3) { + assign_apic_irq(0, 0, 0); + break; } } + /* PCI interrupt assignment is deferred */ } @@ -1522,8 +1525,11 @@ isa_apic_irq(int isa_irq) if (INTTYPE(intr) == 0) { /* standard INT */ if (SRCBUSIRQ(intr) == isa_irq) { if (apic_int_is_bus_type(intr, ISA) || - apic_int_is_bus_type(intr, EISA)) + apic_int_is_bus_type(intr, EISA)) { + if (INTIRQ(intr) == 0xff) + return -1; /* unassigned */ return INTIRQ(intr); /* found */ + } } } } @@ -1549,8 +1555,13 @@ pci_apic_irq(int pciBus, int pciDevice, int pciInt) && (SRCBUSID(intr) == pciBus) && (SRCBUSDEVICE(intr) == pciDevice) && (SRCBUSLINE(intr) == pciInt)) /* a candidate IRQ */ - if (apic_int_is_bus_type(intr, PCI)) + if (apic_int_is_bus_type(intr, PCI)) { + if (INTIRQ(intr) == 0xff) + allocate_apic_irq(intr); + if (INTIRQ(intr) == 0xff) + return -1; /* unassigned */ return INTIRQ(intr); /* exact match */ + } return -1; /* NOT found */ } diff --git a/sys/amd64/include/mptable.h b/sys/amd64/include/mptable.h index 598fbf2..b9e96fe 100644 --- a/sys/amd64/include/mptable.h +++ b/sys/amd64/include/mptable.h @@ -1068,6 +1068,37 @@ revoke_apic_irq(int irq) } +static void +allocate_apic_irq(int intr) +{ + int apic; + int intpin; + int irq; + + if (io_apic_ints[intr].int_vector != 0xff) + return; /* Interrupt handler already assigned */ + + if (io_apic_ints[intr].int_type != 0 && + (io_apic_ints[intr].int_type != 3 || + (io_apic_ints[intr].dst_apic_id == IO_TO_ID(0) && + io_apic_ints[intr].dst_apic_int == 0))) + return; /* Not INT or ExtInt on != (0, 0) */ + + irq = 0; + while (irq < APIC_INTMAPSIZE && + int_to_apicintpin[irq].ioapic != -1) + irq++; + + if (irq >= APIC_INTMAPSIZE) + return; /* No free interrupt handlers */ + + apic = ID_TO_IO(io_apic_ints[intr].dst_apic_id); + intpin = io_apic_ints[intr].dst_apic_int; + + assign_apic_irq(apic, intpin, irq); + io_apic_setup_intpin(apic, intpin); +} + static void swap_apic_id(int apic, int oldid, int newid) @@ -1310,46 +1341,18 @@ setup_apic_irq_mapping(void) } } - /* Assign first set of interrupts to intpins on IOAPIC #0 */ + /* Assign ExtInt entry if no ISA/EISA interrupt 0 entry */ for (x = 0; x < nintrs; x++) { - int_vector = io_apic_ints[x].dst_apic_int; - if (int_vector < APIC_INTMAPSIZE && + if (io_apic_ints[x].dst_apic_int == 0 && io_apic_ints[x].dst_apic_id == IO_TO_ID(0) && io_apic_ints[x].int_vector == 0xff && - int_to_apicintpin[int_vector].ioapic == -1 && - (io_apic_ints[x].int_type == 0 || - io_apic_ints[x].int_type == 3)) { - assign_apic_irq(0, - io_apic_ints[x].dst_apic_int, - int_vector); - } - } - /* - * Assign interrupts for remaining intpins. - * Skip IOAPIC #0 intpin 0 if the type is ExtInt, since this indicates - * that an entry for ISA/EISA irq 0 exist, and a fallback to mixed mode - * due to 8254 interrupts not being delivered can reuse that low level - * interrupt handler. - */ - int_vector = 0; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; - for (x = 0; x < nintrs && int_vector < APIC_INTMAPSIZE; x++) { - if ((io_apic_ints[x].int_type == 0 || - (io_apic_ints[x].int_type == 3 && - (io_apic_ints[x].dst_apic_id != IO_TO_ID(0) || - io_apic_ints[x].dst_apic_int != 0))) && - io_apic_ints[x].int_vector == 0xff) { - assign_apic_irq(ID_TO_IO(io_apic_ints[x].dst_apic_id), - io_apic_ints[x].dst_apic_int, - int_vector); - int_vector++; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; + int_to_apicintpin[0].ioapic == -1 && + io_apic_ints[x].int_type == 3) { + assign_apic_irq(0, 0, 0); + break; } } + /* PCI interrupt assignment is deferred */ } @@ -1522,8 +1525,11 @@ isa_apic_irq(int isa_irq) if (INTTYPE(intr) == 0) { /* standard INT */ if (SRCBUSIRQ(intr) == isa_irq) { if (apic_int_is_bus_type(intr, ISA) || - apic_int_is_bus_type(intr, EISA)) + apic_int_is_bus_type(intr, EISA)) { + if (INTIRQ(intr) == 0xff) + return -1; /* unassigned */ return INTIRQ(intr); /* found */ + } } } } @@ -1549,8 +1555,13 @@ pci_apic_irq(int pciBus, int pciDevice, int pciInt) && (SRCBUSID(intr) == pciBus) && (SRCBUSDEVICE(intr) == pciDevice) && (SRCBUSLINE(intr) == pciInt)) /* a candidate IRQ */ - if (apic_int_is_bus_type(intr, PCI)) + if (apic_int_is_bus_type(intr, PCI)) { + if (INTIRQ(intr) == 0xff) + allocate_apic_irq(intr); + if (INTIRQ(intr) == 0xff) + return -1; /* unassigned */ return INTIRQ(intr); /* exact match */ + } return -1; /* NOT found */ } diff --git a/sys/amd64/include/smp.h b/sys/amd64/include/smp.h index 0ff53bd..1698f2d 100644 --- a/sys/amd64/include/smp.h +++ b/sys/amd64/include/smp.h @@ -135,6 +135,7 @@ void imen_dump __P((void)); int apic_ipi __P((int, int, int)); int selected_apic_ipi __P((u_int, int, int)); int io_apic_setup __P((int)); +void io_apic_setup_intpin __P((int, int)); void io_apic_set_id __P((int, int)); int io_apic_get_id __P((int)); int ext_int_setup __P((int, int)); diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c index 598fbf2..b9e96fe 100644 --- a/sys/i386/i386/mp_machdep.c +++ b/sys/i386/i386/mp_machdep.c @@ -1068,6 +1068,37 @@ revoke_apic_irq(int irq) } +static void +allocate_apic_irq(int intr) +{ + int apic; + int intpin; + int irq; + + if (io_apic_ints[intr].int_vector != 0xff) + return; /* Interrupt handler already assigned */ + + if (io_apic_ints[intr].int_type != 0 && + (io_apic_ints[intr].int_type != 3 || + (io_apic_ints[intr].dst_apic_id == IO_TO_ID(0) && + io_apic_ints[intr].dst_apic_int == 0))) + return; /* Not INT or ExtInt on != (0, 0) */ + + irq = 0; + while (irq < APIC_INTMAPSIZE && + int_to_apicintpin[irq].ioapic != -1) + irq++; + + if (irq >= APIC_INTMAPSIZE) + return; /* No free interrupt handlers */ + + apic = ID_TO_IO(io_apic_ints[intr].dst_apic_id); + intpin = io_apic_ints[intr].dst_apic_int; + + assign_apic_irq(apic, intpin, irq); + io_apic_setup_intpin(apic, intpin); +} + static void swap_apic_id(int apic, int oldid, int newid) @@ -1310,46 +1341,18 @@ setup_apic_irq_mapping(void) } } - /* Assign first set of interrupts to intpins on IOAPIC #0 */ + /* Assign ExtInt entry if no ISA/EISA interrupt 0 entry */ for (x = 0; x < nintrs; x++) { - int_vector = io_apic_ints[x].dst_apic_int; - if (int_vector < APIC_INTMAPSIZE && + if (io_apic_ints[x].dst_apic_int == 0 && io_apic_ints[x].dst_apic_id == IO_TO_ID(0) && io_apic_ints[x].int_vector == 0xff && - int_to_apicintpin[int_vector].ioapic == -1 && - (io_apic_ints[x].int_type == 0 || - io_apic_ints[x].int_type == 3)) { - assign_apic_irq(0, - io_apic_ints[x].dst_apic_int, - int_vector); - } - } - /* - * Assign interrupts for remaining intpins. - * Skip IOAPIC #0 intpin 0 if the type is ExtInt, since this indicates - * that an entry for ISA/EISA irq 0 exist, and a fallback to mixed mode - * due to 8254 interrupts not being delivered can reuse that low level - * interrupt handler. - */ - int_vector = 0; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; - for (x = 0; x < nintrs && int_vector < APIC_INTMAPSIZE; x++) { - if ((io_apic_ints[x].int_type == 0 || - (io_apic_ints[x].int_type == 3 && - (io_apic_ints[x].dst_apic_id != IO_TO_ID(0) || - io_apic_ints[x].dst_apic_int != 0))) && - io_apic_ints[x].int_vector == 0xff) { - assign_apic_irq(ID_TO_IO(io_apic_ints[x].dst_apic_id), - io_apic_ints[x].dst_apic_int, - int_vector); - int_vector++; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; + int_to_apicintpin[0].ioapic == -1 && + io_apic_ints[x].int_type == 3) { + assign_apic_irq(0, 0, 0); + break; } } + /* PCI interrupt assignment is deferred */ } @@ -1522,8 +1525,11 @@ isa_apic_irq(int isa_irq) if (INTTYPE(intr) == 0) { /* standard INT */ if (SRCBUSIRQ(intr) == isa_irq) { if (apic_int_is_bus_type(intr, ISA) || - apic_int_is_bus_type(intr, EISA)) + apic_int_is_bus_type(intr, EISA)) { + if (INTIRQ(intr) == 0xff) + return -1; /* unassigned */ return INTIRQ(intr); /* found */ + } } } } @@ -1549,8 +1555,13 @@ pci_apic_irq(int pciBus, int pciDevice, int pciInt) && (SRCBUSID(intr) == pciBus) && (SRCBUSDEVICE(intr) == pciDevice) && (SRCBUSLINE(intr) == pciInt)) /* a candidate IRQ */ - if (apic_int_is_bus_type(intr, PCI)) + if (apic_int_is_bus_type(intr, PCI)) { + if (INTIRQ(intr) == 0xff) + allocate_apic_irq(intr); + if (INTIRQ(intr) == 0xff) + return -1; /* unassigned */ return INTIRQ(intr); /* exact match */ + } return -1; /* NOT found */ } diff --git a/sys/i386/i386/mpapic.c b/sys/i386/i386/mpapic.c index 33aab28..3143822 100644 --- a/sys/i386/i386/mpapic.c +++ b/sys/i386/i386/mpapic.c @@ -29,6 +29,7 @@ #include <sys/bus.h> #include <sys/systm.h> #include <sys/proc.h> +#include <sys/lock.h> #include <machine/smptests.h> /** TEST_TEST1 */ #include <machine/smp.h> @@ -177,19 +178,98 @@ io_apic_get_id(int apic) /* * Setup the IO APIC. */ + extern int apic_pin_trigger; /* 'opaque' */ -int -io_apic_setup(int apic) + +void +io_apic_setup_intpin(int apic, int pin) { - int maxpin; + int bus, bustype, irq; u_char select; /* the select register is 8 bits */ u_int32_t flags; /* the window register is 32 bits */ u_int32_t target; /* the window register is 32 bits */ u_int32_t vector; /* the window register is 32 bits */ - int pin, level; + int level; target = IOART_DEST; + select = pin * 2 + IOAPIC_REDTBL0; /* register */ + /* + * Always disable interrupts, and by default map + * pin X to IRQX because the disable doesn't stick + * and the uninitialize vector will get translated + * into a panic. + * + * This is correct for IRQs 1 and 3-15. In the other cases, + * any robust driver will handle the spurious interrupt, and + * the effective NOP beats a panic. + * + * A dedicated "bogus interrupt" entry in the IDT would + * be a nicer hack, although some one should find out + * why some systems are generating interrupts when they + * shouldn't and stop the carnage. + */ + vector = NRSVIDT + pin; /* IDT vec */ + mtx_enter(&imen_mtx, MTX_SPIN); + io_apic_write(apic, select, + (io_apic_read(apic, select) & ~IOART_INTMASK + & ~0xff)|IOART_INTMSET|vector); + mtx_exit(&imen_mtx, MTX_SPIN); + + /* we only deal with vectored INTs here */ + if (apic_int_type(apic, pin) != 0) + return; + + irq = apic_irq(apic, pin); + if (irq < 0) + return; + + /* determine the bus type for this pin */ + bus = apic_src_bus_id(apic, pin); + if (bus == -1) + return; + bustype = apic_bus_type(bus); + + if ((bustype == ISA) && + (pin < IOAPIC_ISA_INTS) && + (irq == pin) && + (apic_polarity(apic, pin) == 0x1) && + (apic_trigger(apic, pin) == 0x3)) { + /* + * A broken BIOS might describe some ISA + * interrupts as active-high level-triggered. + * Use default ISA flags for those interrupts. + */ + flags = DEFAULT_ISA_FLAGS; + } else { + /* + * Program polarity and trigger mode according to + * interrupt entry. + */ + flags = DEFAULT_FLAGS; + level = trigger(apic, pin, &flags); + if (level == 1) + apic_pin_trigger |= (1 << irq); + polarity(apic, pin, &flags, level); + } + + /* program the appropriate registers */ + if (apic != 0 || pin != irq) + printf("IOAPIC #%d intpin %d -> irq %d\n", + apic, pin, irq); + vector = NRSVIDT + irq; /* IDT vec */ + mtx_enter(&imen_mtx, MTX_SPIN); + io_apic_write(apic, select, flags | vector); + io_apic_write(apic, select + 1, target); + mtx_exit(&imen_mtx, MTX_SPIN); +} + +int +io_apic_setup(int apic) +{ + int maxpin; + int pin; + if (apic == 0) apic_pin_trigger = 0; /* default to edge-triggered */ @@ -197,73 +277,7 @@ io_apic_setup(int apic) printf("Programming %d pins in IOAPIC #%d\n", maxpin, apic); for (pin = 0; pin < maxpin; ++pin) { - int bus, bustype, irq; - - select = pin * 2 + IOAPIC_REDTBL0; /* register */ - /* - * Always disable interrupts, and by default map - * pin X to IRQX because the disable doesn't stick - * and the uninitialize vector will get translated - * into a panic. - * - * This is correct for IRQs 1 and 3-15. In the other cases, - * any robust driver will handle the spurious interrupt, and - * the effective NOP beats a panic. - * - * A dedicated "bogus interrupt" entry in the IDT would - * be a nicer hack, although some one should find out - * why some systems are generating interrupts when they - * shouldn't and stop the carnage. - */ - vector = NRSVIDT + pin; /* IDT vec */ - io_apic_write(apic, select, - (io_apic_read(apic, select) & ~IOART_INTMASK - & ~0xff)|IOART_INTMSET|vector); - - /* we only deal with vectored INTs here */ - if (apic_int_type(apic, pin) != 0) - continue; - - irq = apic_irq(apic, pin); - if (irq < 0) - continue; - - /* determine the bus type for this pin */ - bus = apic_src_bus_id(apic, pin); - if (bus == -1) - continue; - bustype = apic_bus_type(bus); - - if ((bustype == ISA) && - (pin < IOAPIC_ISA_INTS) && - (irq == pin) && - (apic_polarity(apic, pin) == 0x1) && - (apic_trigger(apic, pin) == 0x3)) { - /* - * A broken BIOS might describe some ISA - * interrupts as active-high level-triggered. - * Use default ISA flags for those interrupts. - */ - flags = DEFAULT_ISA_FLAGS; - } else { - /* - * Program polarity and trigger mode according to - * interrupt entry. - */ - flags = DEFAULT_FLAGS; - level = trigger(apic, pin, &flags); - if (level == 1) - apic_pin_trigger |= (1 << irq); - polarity(apic, pin, &flags, level); - } - - /* program the appropriate registers */ - if (apic != 0 || pin != irq) - printf("IOAPIC #%d intpin %d -> irq %d\n", - apic, pin, irq); - vector = NRSVIDT + irq; /* IDT vec */ - io_apic_write(apic, select, flags | vector); - io_apic_write(apic, select + 1, target); + io_apic_setup_intpin(apic, pin); } /* return GOOD status */ diff --git a/sys/i386/i386/mptable.c b/sys/i386/i386/mptable.c index 598fbf2..b9e96fe 100644 --- a/sys/i386/i386/mptable.c +++ b/sys/i386/i386/mptable.c @@ -1068,6 +1068,37 @@ revoke_apic_irq(int irq) } +static void +allocate_apic_irq(int intr) +{ + int apic; + int intpin; + int irq; + + if (io_apic_ints[intr].int_vector != 0xff) + return; /* Interrupt handler already assigned */ + + if (io_apic_ints[intr].int_type != 0 && + (io_apic_ints[intr].int_type != 3 || + (io_apic_ints[intr].dst_apic_id == IO_TO_ID(0) && + io_apic_ints[intr].dst_apic_int == 0))) + return; /* Not INT or ExtInt on != (0, 0) */ + + irq = 0; + while (irq < APIC_INTMAPSIZE && + int_to_apicintpin[irq].ioapic != -1) + irq++; + + if (irq >= APIC_INTMAPSIZE) + return; /* No free interrupt handlers */ + + apic = ID_TO_IO(io_apic_ints[intr].dst_apic_id); + intpin = io_apic_ints[intr].dst_apic_int; + + assign_apic_irq(apic, intpin, irq); + io_apic_setup_intpin(apic, intpin); +} + static void swap_apic_id(int apic, int oldid, int newid) @@ -1310,46 +1341,18 @@ setup_apic_irq_mapping(void) } } - /* Assign first set of interrupts to intpins on IOAPIC #0 */ + /* Assign ExtInt entry if no ISA/EISA interrupt 0 entry */ for (x = 0; x < nintrs; x++) { - int_vector = io_apic_ints[x].dst_apic_int; - if (int_vector < APIC_INTMAPSIZE && + if (io_apic_ints[x].dst_apic_int == 0 && io_apic_ints[x].dst_apic_id == IO_TO_ID(0) && io_apic_ints[x].int_vector == 0xff && - int_to_apicintpin[int_vector].ioapic == -1 && - (io_apic_ints[x].int_type == 0 || - io_apic_ints[x].int_type == 3)) { - assign_apic_irq(0, - io_apic_ints[x].dst_apic_int, - int_vector); - } - } - /* - * Assign interrupts for remaining intpins. - * Skip IOAPIC #0 intpin 0 if the type is ExtInt, since this indicates - * that an entry for ISA/EISA irq 0 exist, and a fallback to mixed mode - * due to 8254 interrupts not being delivered can reuse that low level - * interrupt handler. - */ - int_vector = 0; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; - for (x = 0; x < nintrs && int_vector < APIC_INTMAPSIZE; x++) { - if ((io_apic_ints[x].int_type == 0 || - (io_apic_ints[x].int_type == 3 && - (io_apic_ints[x].dst_apic_id != IO_TO_ID(0) || - io_apic_ints[x].dst_apic_int != 0))) && - io_apic_ints[x].int_vector == 0xff) { - assign_apic_irq(ID_TO_IO(io_apic_ints[x].dst_apic_id), - io_apic_ints[x].dst_apic_int, - int_vector); - int_vector++; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; + int_to_apicintpin[0].ioapic == -1 && + io_apic_ints[x].int_type == 3) { + assign_apic_irq(0, 0, 0); + break; } } + /* PCI interrupt assignment is deferred */ } @@ -1522,8 +1525,11 @@ isa_apic_irq(int isa_irq) if (INTTYPE(intr) == 0) { /* standard INT */ if (SRCBUSIRQ(intr) == isa_irq) { if (apic_int_is_bus_type(intr, ISA) || - apic_int_is_bus_type(intr, EISA)) + apic_int_is_bus_type(intr, EISA)) { + if (INTIRQ(intr) == 0xff) + return -1; /* unassigned */ return INTIRQ(intr); /* found */ + } } } } @@ -1549,8 +1555,13 @@ pci_apic_irq(int pciBus, int pciDevice, int pciInt) && (SRCBUSID(intr) == pciBus) && (SRCBUSDEVICE(intr) == pciDevice) && (SRCBUSLINE(intr) == pciInt)) /* a candidate IRQ */ - if (apic_int_is_bus_type(intr, PCI)) + if (apic_int_is_bus_type(intr, PCI)) { + if (INTIRQ(intr) == 0xff) + allocate_apic_irq(intr); + if (INTIRQ(intr) == 0xff) + return -1; /* unassigned */ return INTIRQ(intr); /* exact match */ + } return -1; /* NOT found */ } diff --git a/sys/i386/include/mptable.h b/sys/i386/include/mptable.h index 598fbf2..b9e96fe 100644 --- a/sys/i386/include/mptable.h +++ b/sys/i386/include/mptable.h @@ -1068,6 +1068,37 @@ revoke_apic_irq(int irq) } +static void +allocate_apic_irq(int intr) +{ + int apic; + int intpin; + int irq; + + if (io_apic_ints[intr].int_vector != 0xff) + return; /* Interrupt handler already assigned */ + + if (io_apic_ints[intr].int_type != 0 && + (io_apic_ints[intr].int_type != 3 || + (io_apic_ints[intr].dst_apic_id == IO_TO_ID(0) && + io_apic_ints[intr].dst_apic_int == 0))) + return; /* Not INT or ExtInt on != (0, 0) */ + + irq = 0; + while (irq < APIC_INTMAPSIZE && + int_to_apicintpin[irq].ioapic != -1) + irq++; + + if (irq >= APIC_INTMAPSIZE) + return; /* No free interrupt handlers */ + + apic = ID_TO_IO(io_apic_ints[intr].dst_apic_id); + intpin = io_apic_ints[intr].dst_apic_int; + + assign_apic_irq(apic, intpin, irq); + io_apic_setup_intpin(apic, intpin); +} + static void swap_apic_id(int apic, int oldid, int newid) @@ -1310,46 +1341,18 @@ setup_apic_irq_mapping(void) } } - /* Assign first set of interrupts to intpins on IOAPIC #0 */ + /* Assign ExtInt entry if no ISA/EISA interrupt 0 entry */ for (x = 0; x < nintrs; x++) { - int_vector = io_apic_ints[x].dst_apic_int; - if (int_vector < APIC_INTMAPSIZE && + if (io_apic_ints[x].dst_apic_int == 0 && io_apic_ints[x].dst_apic_id == IO_TO_ID(0) && io_apic_ints[x].int_vector == 0xff && - int_to_apicintpin[int_vector].ioapic == -1 && - (io_apic_ints[x].int_type == 0 || - io_apic_ints[x].int_type == 3)) { - assign_apic_irq(0, - io_apic_ints[x].dst_apic_int, - int_vector); - } - } - /* - * Assign interrupts for remaining intpins. - * Skip IOAPIC #0 intpin 0 if the type is ExtInt, since this indicates - * that an entry for ISA/EISA irq 0 exist, and a fallback to mixed mode - * due to 8254 interrupts not being delivered can reuse that low level - * interrupt handler. - */ - int_vector = 0; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; - for (x = 0; x < nintrs && int_vector < APIC_INTMAPSIZE; x++) { - if ((io_apic_ints[x].int_type == 0 || - (io_apic_ints[x].int_type == 3 && - (io_apic_ints[x].dst_apic_id != IO_TO_ID(0) || - io_apic_ints[x].dst_apic_int != 0))) && - io_apic_ints[x].int_vector == 0xff) { - assign_apic_irq(ID_TO_IO(io_apic_ints[x].dst_apic_id), - io_apic_ints[x].dst_apic_int, - int_vector); - int_vector++; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; + int_to_apicintpin[0].ioapic == -1 && + io_apic_ints[x].int_type == 3) { + assign_apic_irq(0, 0, 0); + break; } } + /* PCI interrupt assignment is deferred */ } @@ -1522,8 +1525,11 @@ isa_apic_irq(int isa_irq) if (INTTYPE(intr) == 0) { /* standard INT */ if (SRCBUSIRQ(intr) == isa_irq) { if (apic_int_is_bus_type(intr, ISA) || - apic_int_is_bus_type(intr, EISA)) + apic_int_is_bus_type(intr, EISA)) { + if (INTIRQ(intr) == 0xff) + return -1; /* unassigned */ return INTIRQ(intr); /* found */ + } } } } @@ -1549,8 +1555,13 @@ pci_apic_irq(int pciBus, int pciDevice, int pciInt) && (SRCBUSID(intr) == pciBus) && (SRCBUSDEVICE(intr) == pciDevice) && (SRCBUSLINE(intr) == pciInt)) /* a candidate IRQ */ - if (apic_int_is_bus_type(intr, PCI)) + if (apic_int_is_bus_type(intr, PCI)) { + if (INTIRQ(intr) == 0xff) + allocate_apic_irq(intr); + if (INTIRQ(intr) == 0xff) + return -1; /* unassigned */ return INTIRQ(intr); /* exact match */ + } return -1; /* NOT found */ } diff --git a/sys/i386/include/smp.h b/sys/i386/include/smp.h index 0ff53bd..1698f2d 100644 --- a/sys/i386/include/smp.h +++ b/sys/i386/include/smp.h @@ -135,6 +135,7 @@ void imen_dump __P((void)); int apic_ipi __P((int, int, int)); int selected_apic_ipi __P((u_int, int, int)); int io_apic_setup __P((int)); +void io_apic_setup_intpin __P((int, int)); void io_apic_set_id __P((int, int)); int io_apic_get_id __P((int)); int ext_int_setup __P((int, int)); diff --git a/sys/kern/subr_smp.c b/sys/kern/subr_smp.c index 598fbf2..b9e96fe 100644 --- a/sys/kern/subr_smp.c +++ b/sys/kern/subr_smp.c @@ -1068,6 +1068,37 @@ revoke_apic_irq(int irq) } +static void +allocate_apic_irq(int intr) +{ + int apic; + int intpin; + int irq; + + if (io_apic_ints[intr].int_vector != 0xff) + return; /* Interrupt handler already assigned */ + + if (io_apic_ints[intr].int_type != 0 && + (io_apic_ints[intr].int_type != 3 || + (io_apic_ints[intr].dst_apic_id == IO_TO_ID(0) && + io_apic_ints[intr].dst_apic_int == 0))) + return; /* Not INT or ExtInt on != (0, 0) */ + + irq = 0; + while (irq < APIC_INTMAPSIZE && + int_to_apicintpin[irq].ioapic != -1) + irq++; + + if (irq >= APIC_INTMAPSIZE) + return; /* No free interrupt handlers */ + + apic = ID_TO_IO(io_apic_ints[intr].dst_apic_id); + intpin = io_apic_ints[intr].dst_apic_int; + + assign_apic_irq(apic, intpin, irq); + io_apic_setup_intpin(apic, intpin); +} + static void swap_apic_id(int apic, int oldid, int newid) @@ -1310,46 +1341,18 @@ setup_apic_irq_mapping(void) } } - /* Assign first set of interrupts to intpins on IOAPIC #0 */ + /* Assign ExtInt entry if no ISA/EISA interrupt 0 entry */ for (x = 0; x < nintrs; x++) { - int_vector = io_apic_ints[x].dst_apic_int; - if (int_vector < APIC_INTMAPSIZE && + if (io_apic_ints[x].dst_apic_int == 0 && io_apic_ints[x].dst_apic_id == IO_TO_ID(0) && io_apic_ints[x].int_vector == 0xff && - int_to_apicintpin[int_vector].ioapic == -1 && - (io_apic_ints[x].int_type == 0 || - io_apic_ints[x].int_type == 3)) { - assign_apic_irq(0, - io_apic_ints[x].dst_apic_int, - int_vector); - } - } - /* - * Assign interrupts for remaining intpins. - * Skip IOAPIC #0 intpin 0 if the type is ExtInt, since this indicates - * that an entry for ISA/EISA irq 0 exist, and a fallback to mixed mode - * due to 8254 interrupts not being delivered can reuse that low level - * interrupt handler. - */ - int_vector = 0; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; - for (x = 0; x < nintrs && int_vector < APIC_INTMAPSIZE; x++) { - if ((io_apic_ints[x].int_type == 0 || - (io_apic_ints[x].int_type == 3 && - (io_apic_ints[x].dst_apic_id != IO_TO_ID(0) || - io_apic_ints[x].dst_apic_int != 0))) && - io_apic_ints[x].int_vector == 0xff) { - assign_apic_irq(ID_TO_IO(io_apic_ints[x].dst_apic_id), - io_apic_ints[x].dst_apic_int, - int_vector); - int_vector++; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; + int_to_apicintpin[0].ioapic == -1 && + io_apic_ints[x].int_type == 3) { + assign_apic_irq(0, 0, 0); + break; } } + /* PCI interrupt assignment is deferred */ } @@ -1522,8 +1525,11 @@ isa_apic_irq(int isa_irq) if (INTTYPE(intr) == 0) { /* standard INT */ if (SRCBUSIRQ(intr) == isa_irq) { if (apic_int_is_bus_type(intr, ISA) || - apic_int_is_bus_type(intr, EISA)) + apic_int_is_bus_type(intr, EISA)) { + if (INTIRQ(intr) == 0xff) + return -1; /* unassigned */ return INTIRQ(intr); /* found */ + } } } } @@ -1549,8 +1555,13 @@ pci_apic_irq(int pciBus, int pciDevice, int pciInt) && (SRCBUSID(intr) == pciBus) && (SRCBUSDEVICE(intr) == pciDevice) && (SRCBUSLINE(intr) == pciInt)) /* a candidate IRQ */ - if (apic_int_is_bus_type(intr, PCI)) + if (apic_int_is_bus_type(intr, PCI)) { + if (INTIRQ(intr) == 0xff) + allocate_apic_irq(intr); + if (INTIRQ(intr) == 0xff) + return -1; /* unassigned */ return INTIRQ(intr); /* exact match */ + } return -1; /* NOT found */ } diff --git a/sys/sys/smp.h b/sys/sys/smp.h index 0ff53bd..1698f2d 100644 --- a/sys/sys/smp.h +++ b/sys/sys/smp.h @@ -135,6 +135,7 @@ void imen_dump __P((void)); int apic_ipi __P((int, int, int)); int selected_apic_ipi __P((u_int, int, int)); int io_apic_setup __P((int)); +void io_apic_setup_intpin __P((int, int)); void io_apic_set_id __P((int, int)); int io_apic_get_id __P((int)); int ext_int_setup __P((int, int)); |