ioapic/x86_64: Allow GSI > 191
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 30 Oct 2012 02:53:59 +0000 (10:53 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 1 Nov 2012 01:38:26 +0000 (09:38 +0800)
Some BIOSes seem to assume that all 256 IDT vectors could be used,
while we limit the available IDT vectors percpu to 192.   Find an
unused IRQ for these GSIs, if this ever happens.

Reported-by: thowe on EFnet #dragonflybsd
sys/platform/pc64/apic/ioapic_abi.c

index 367e70f..9d8b79b 100644 (file)
@@ -518,6 +518,7 @@ static void ioapic_abi_initmap(void);
 static void    ioapic_abi_rman_setup(struct rman *);
 
 static int     ioapic_abi_gsi_cpuid(int, int);
+static int     ioapic_find_unused_irqmap(int);
 
 struct machintr_abi MachIntrABI_IOAPIC = {
        MACHINTR_IOAPIC,
@@ -764,6 +765,22 @@ ioapic_abi_initmap(void)
        }
 }
 
+static int
+ioapic_find_unused_irqmap(int gsi)
+{
+       int cpuid, i;
+
+       cpuid = ioapic_abi_gsi_cpuid(-1, gsi);
+
+       for (i = ISA_IRQ_CNT; i < IOAPIC_HWI_VECTORS; ++i) {
+               if (i == acpi_sci_irqno())
+                       continue;
+               if (ioapic_irqmaps[cpuid][i].im_type == IOAPIC_IMT_UNUSED)
+                       return i;
+       }
+       return -1;
+}
+
 void
 ioapic_set_legacy_irqmap(int irq, int gsi, enum intr_trigger trig,
     enum intr_polarity pola)
@@ -776,7 +793,21 @@ ioapic_set_legacy_irqmap(int irq, int gsi, enum intr_trigger trig,
        KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL);
        KKASSERT(pola == INTR_POLARITY_HIGH || pola == INTR_POLARITY_LOW);
 
-       KKASSERT(irq >= 0 && irq < IOAPIC_HWI_VECTORS);
+       KKASSERT(irq >= 0);
+       if (irq >= IOAPIC_HWI_VECTORS) {
+               /*
+                * Some BIOSes seem to assume that all 256 IDT vectors
+                * could be used, while we limit the available IDT
+                * vectors to 192; find an unused IRQ for this GSI.
+                */
+               irq = ioapic_find_unused_irqmap(gsi);
+               if (irq < 0) {
+                       kprintf("failed to find unused irq for gsi %d\n", gsi);
+                       return;
+               }
+       }
+       KKASSERT(irq < IOAPIC_HWI_VECTORS);
+
        if (irq > ioapic_abi_legacy_irq_max)
                ioapic_abi_legacy_irq_max = irq;
 
@@ -1088,6 +1119,7 @@ ioapic_abi_gsi_cpuid(int irq, int gsi)
        KKASSERT(gsi >= 0);
 
        if (irq == 0 || gsi == 0) {
+               KKASSERT(irq >= 0);
                if (bootverbose) {
                        kprintf("IOAPIC: irq %d, gsi %d -> cpu0 (0)\n",
                            irq, gsi);
@@ -1095,7 +1127,7 @@ ioapic_abi_gsi_cpuid(int irq, int gsi)
                return 0;
        }
 
-       if (irq == acpi_sci_irqno()) {
+       if (irq >= 0 && irq == acpi_sci_irqno()) {
                if (bootverbose) {
                        kprintf("IOAPIC: irq %d, gsi %d -> cpu0 (sci)\n",
                            irq, gsi);
@@ -1108,7 +1140,7 @@ ioapic_abi_gsi_cpuid(int irq, int gsi)
 
        if (cpuid < 0) {
                if (!ioapic_abi_gsi_balance) {
-                       if (bootverbose) {
+                       if (irq >= 0 && bootverbose) {
                                kprintf("IOAPIC: irq %d, gsi %d -> cpu0 "
                                    "(fixed)\n", irq, gsi);
                        }
@@ -1116,18 +1148,18 @@ ioapic_abi_gsi_cpuid(int irq, int gsi)
                }
 
                cpuid = gsi % ncpus;
-               if (bootverbose) {
+               if (irq >= 0 && bootverbose) {
                        kprintf("IOAPIC: irq %d, gsi %d -> cpu%d (auto)\n",
                            irq, gsi, cpuid);
                }
        } else if (cpuid >= ncpus) {
                cpuid = ncpus - 1;
-               if (bootverbose) {
+               if (irq >= 0 && bootverbose) {
                        kprintf("IOAPIC: irq %d, gsi %d -> cpu%d (fixup)\n",
                            irq, gsi, cpuid);
                }
        } else {
-               if (bootverbose) {
+               if (irq >= 0 && bootverbose) {
                        kprintf("IOAPIC: irq %d, gsi %d -> cpu%d (user)\n",
                            irq, gsi, cpuid);
                }