summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authortegge <tegge@FreeBSD.org>2001-01-28 01:07:54 +0000
committertegge <tegge@FreeBSD.org>2001-01-28 01:07:54 +0000
commit55837ed17a3a2de16bb80beea9044a80a8306d29 (patch)
tree88f37e01221c649b3f54521ccbe3c0f116907f2d /sys
parent18f604377b44e23f62badff17ec21171a8ca980e (diff)
downloadFreeBSD-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.c85
-rw-r--r--sys/amd64/amd64/mptable.c85
-rw-r--r--sys/amd64/include/mptable.h85
-rw-r--r--sys/amd64/include/smp.h1
-rw-r--r--sys/i386/i386/mp_machdep.c85
-rw-r--r--sys/i386/i386/mpapic.c156
-rw-r--r--sys/i386/i386/mptable.c85
-rw-r--r--sys/i386/include/mptable.h85
-rw-r--r--sys/i386/include/smp.h1
-rw-r--r--sys/kern/subr_smp.c85
-rw-r--r--sys/sys/smp.h1
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));
OpenPOWER on IntegriCloud