mptable/ioapic: Properly routing PCI interrupts
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 20 Mar 2011 06:40:30 +0000 (14:40 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 20 Mar 2011 07:54:28 +0000 (15:54 +0800)
12 files changed:
sys/bus/pci/i386/mptable_pci.c
sys/bus/pci/x86_64/mptable_pci.c
sys/platform/pc32/apic/ioapic_abi.c
sys/platform/pc32/apic/ioapic_abi.h
sys/platform/pc32/apic/mpapic.c
sys/platform/pc32/i386/mp_machdep.c
sys/platform/pc32/include/smp.h
sys/platform/pc64/apic/ioapic_abi.c
sys/platform/pc64/apic/ioapic_abi.h
sys/platform/pc64/apic/mpapic.c
sys/platform/pc64/include/smp.h
sys/platform/pc64/x86_64/mp_machdep.c

index 1c3cbeb..36f26e9 100644 (file)
@@ -59,27 +59,35 @@ mptable_pci_route_interrupt(device_t pcib, device_t dev, int pin)
        bus = pci_get_bus(dev);
        slot = pci_get_slot(dev);
 
-       line = pci_apic_irq(bus, slot, pin);
-       if (line >= 0) {
-               goto done;
+       if (ioapic_use_old) {
+               line = pci_apic_irq(bus, slot, pin);
+               if (line >= 0) {
+                       goto done;
+               } else {
+                       int irq = pci_get_irq(dev);
+
+                       /* 
+                        * PCI interrupts might be redirected to the
+                        * ISA bus according to some MP tables.  Use the
+                        * same methods as used by the ISA devices
+                        * devices to find the proper IOAPIC int pin.
+                        */
+                       kprintf("MPTable: Try routing through ISA bus for "
+                               "bus %d slot %d INT%c irq %d\n",
+                               bus, slot, 'A' + pin - 1, irq);
+                       line = isa_apic_irq(irq);
+                       if (line >= 0)
+                               goto done;
+               }
        } else {
                int irq = pci_get_irq(dev);
 
-               /* 
-                * PCI interrupts might be redirected to the
-                * ISA bus according to some MP tables.  Use the
-                * same methods as used by the ISA devices
-                * devices to find the proper IOAPIC int pin.
-                */
-               kprintf("MPTable: Try routing through ISA bus for "
-                       "bus %d slot %d INT%c irq %d\n",
-                       bus, slot, 'A' + pin - 1, irq);
-               line = isa_apic_irq(irq);
+               line = mptable_pci_int_route(bus, slot, pin, irq);
                if (line >= 0)
                        goto done;
        }
 
-       kprintf("MPTable: Unable to route for bus %d slot %d INT%c\n",
+       kprintf("MPTABLE: Unable to route for bus %d slot %d INT%c\n",
                bus, slot, 'A' + pin - 1);
        return PCI_INVALID_IRQ;
 
@@ -102,7 +110,12 @@ mptable_hostb_probe(device_t dev)
        if (mptable_pci_probe_table(pcib_get_bus(dev)) != 0)
                return (ENXIO);
 #endif
-       device_set_desc(dev, "MPTable Host-PCI bridge");
+       if (!ioapic_use_old) {
+               if (bootverbose)
+                       mptable_pci_int_dump();
+       }
+
+       device_set_desc(dev, "MPTABLE Host-PCI bridge");
        return (0);
 }
 
@@ -203,7 +216,7 @@ mptable_pcib_probe(device_t dev)
        if (mptable_pci_probe_table(bus) != 0)
                return (ENXIO);
 #endif
-       device_set_desc(dev, "MPTable PCI-PCI bridge");
+       device_set_desc(dev, "MPTABLE PCI-PCI bridge");
        return (-500);
 }
 
index 1c3cbeb..84a9ed8 100644 (file)
@@ -59,27 +59,35 @@ mptable_pci_route_interrupt(device_t pcib, device_t dev, int pin)
        bus = pci_get_bus(dev);
        slot = pci_get_slot(dev);
 
-       line = pci_apic_irq(bus, slot, pin);
-       if (line >= 0) {
-               goto done;
+       if (ioapic_use_old) {
+               line = pci_apic_irq(bus, slot, pin);
+               if (line >= 0) {
+                       goto done;
+               } else {
+                       int irq = pci_get_irq(dev);
+
+                       /* 
+                        * PCI interrupts might be redirected to the
+                        * ISA bus according to some MP tables.  Use the
+                        * same methods as used by the ISA devices
+                        * devices to find the proper IOAPIC int pin.
+                        */
+                       kprintf("MPTable: Try routing through ISA bus for "
+                               "bus %d slot %d INT%c irq %d\n",
+                               bus, slot, 'A' + pin - 1, irq);
+                       line = isa_apic_irq(irq);
+                       if (line >= 0)
+                               goto done;
+               }
        } else {
                int irq = pci_get_irq(dev);
 
-               /* 
-                * PCI interrupts might be redirected to the
-                * ISA bus according to some MP tables.  Use the
-                * same methods as used by the ISA devices
-                * devices to find the proper IOAPIC int pin.
-                */
-               kprintf("MPTable: Try routing through ISA bus for "
-                       "bus %d slot %d INT%c irq %d\n",
-                       bus, slot, 'A' + pin - 1, irq);
-               line = isa_apic_irq(irq);
+               line = mptable_pci_int_route(bus, slot, pin, irq);
                if (line >= 0)
                        goto done;
        }
 
-       kprintf("MPTable: Unable to route for bus %d slot %d INT%c\n",
+       kprintf("MPTABLE: Unable to route for bus %d slot %d INT%c\n",
                bus, slot, 'A' + pin - 1);
        return PCI_INVALID_IRQ;
 
@@ -102,7 +110,13 @@ mptable_hostb_probe(device_t dev)
        if (mptable_pci_probe_table(pcib_get_bus(dev)) != 0)
                return (ENXIO);
 #endif
-       device_set_desc(dev, "MPTable Host-PCI bridge");
+
+       if (!ioapic_use_old) {
+               if (bootverbose)
+                       mptable_pci_int_dump();
+       }
+
+       device_set_desc(dev, "MPTABLE Host-PCI bridge");
        return (0);
 }
 
@@ -203,7 +217,7 @@ mptable_pcib_probe(device_t dev)
        if (mptable_pci_probe_table(bus) != 0)
                return (ENXIO);
 #endif
-       device_set_desc(dev, "MPTable PCI-PCI bridge");
+       device_set_desc(dev, "MPTABLE PCI-PCI bridge");
        return (-500);
 }
 
index 3835d6c..8db3d45 100644 (file)
@@ -726,6 +726,57 @@ ioapic_abi_fixup_irqmap(void)
        }
 }
 
+int
+ioapic_abi_find_gsi(int gsi, enum intr_trigger trig, enum intr_polarity pola)
+{
+       int irq;
+
+       KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL);
+       KKASSERT(pola == INTR_POLARITY_HIGH || pola == INTR_POLARITY_LOW);
+       KKASSERT((trig == INTR_TRIGGER_EDGE && pola == INTR_POLARITY_HIGH) ||
+                (trig == INTR_TRIGGER_LEVEL && pola == INTR_POLARITY_LOW));
+
+       for (irq = 0; irq < IOAPIC_HWI_VECTORS; ++irq) {
+               const struct ioapic_irqmap *map = &ioapic_irqmaps[irq];
+
+               if (map->im_gsi == gsi) {
+                       KKASSERT(map->im_type == IOAPIC_IMT_LINE);
+
+                       if (map->im_flags & IOAPIC_IMF_CONF) {
+                               if (map->im_trig != trig ||
+                                   map->im_pola != pola)
+                                       return -1;
+                       }
+                       return irq;
+               }
+       }
+       return -1;
+}
+
+int
+ioapic_abi_find_irq(int irq, enum intr_trigger trig, enum intr_polarity pola)
+{
+       const struct ioapic_irqmap *map;
+
+       KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL);
+       KKASSERT(pola == INTR_POLARITY_HIGH || pola == INTR_POLARITY_LOW);
+       KKASSERT((trig == INTR_TRIGGER_EDGE && pola == INTR_POLARITY_HIGH) ||
+                (trig == INTR_TRIGGER_LEVEL && pola == INTR_POLARITY_LOW));
+
+       if (irq < 0 || irq >= IOAPIC_HWI_VECTORS)
+               return -1;
+       map = &ioapic_irqmaps[irq];
+
+       if (map->im_type != IOAPIC_IMT_LINE)
+               return -1;
+
+       if (map->im_flags & IOAPIC_IMF_CONF) {
+               if (map->im_trig != trig || map->im_pola != pola)
+                       return -1;
+       }
+       return irq;
+}
+
 static void
 ioapic_intr_config(int irq, enum intr_trigger trig, enum intr_polarity pola)
 {
index 7216236..34c11a5 100644 (file)
@@ -52,6 +52,9 @@ extern struct machintr_abi MachIntrABI_IOAPIC;
 void   ioapic_abi_set_irqmap(int, int, enum intr_trigger, enum intr_polarity);
 void   ioapic_abi_fixup_irqmap(void);
 
+int    ioapic_abi_find_gsi(int, enum intr_trigger, enum intr_polarity);
+int    ioapic_abi_find_irq(int, enum intr_trigger, enum intr_polarity);
+
 #endif /* SMP */
 
 #endif /* !_ARCH_APIC_IOAPIC_ABI_H_ */
index 570a9cf..5b9be8f 100644 (file)
@@ -1207,8 +1207,6 @@ ioapic_config(void)
                MachIntrABI.cleanup();
 
                crit_exit();
-
-               panic("ioapic_config: new ioapic not working yet\n");
        }
 }
 
@@ -1369,6 +1367,22 @@ ioapic_gsi_search(int gsi)
        panic("ioapic_gsi_search: no I/O APIC\n");
 }
 
+int
+ioapic_gsi(int idx, int pin)
+{
+       const struct ioapic_info *info;
+
+       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
+               if (info->io_idx == idx)
+                       break;
+       }
+       if (info == NULL)
+               return -1;
+       if (pin >= info->io_npin)
+               return -1;
+       return info->io_gsi_base + pin;
+}
+
 void
 ioapic_extpin_setup(void *addr, int pin, int vec)
 {
index 797fea9..d8b7718 100644 (file)
@@ -3720,3 +3720,54 @@ mptable_ioapic_enum_register(void)
 }
 SYSINIT(mptable_ioapic, SI_BOOT2_PRESMP, SI_ORDER_ANY,
        mptable_ioapic_enum_register, 0);
+
+void
+mptable_pci_int_dump(void)
+{
+       const struct mptable_pci_int *pci_int;
+
+       TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
+               kprintf("MPTABLE: %d:%d:%d -> IOAPIC %d.%d\n",
+                       pci_int->mpci_bus,
+                       pci_int->mpci_dev,
+                       pci_int->mpci_pin,
+                       pci_int->mpci_ioapic_idx,
+                       pci_int->mpci_ioapic_pin);
+       }
+}
+
+int
+mptable_pci_int_route(int bus, int dev, int pin, int intline)
+{
+       const struct mptable_pci_int *pci_int;
+       int irq = -1;
+
+       KKASSERT(pin >= 1);
+       --pin;  /* zero based */
+
+       TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
+               if (pci_int->mpci_bus == bus &&
+                   pci_int->mpci_dev == dev &&
+                   pci_int->mpci_pin == pin)
+                       break;
+       }
+       if (pci_int != NULL) {
+               int gsi;
+
+               gsi = ioapic_gsi(pci_int->mpci_ioapic_idx,
+                       pci_int->mpci_ioapic_pin);
+               if (gsi >= 0) {
+                       irq = ioapic_abi_find_gsi(gsi,
+                               INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
+               }
+       }
+
+       if (irq < 0) {
+               if (bootverbose)
+                       kprintf("MPTABLE: fixed interrupt routing\n");
+
+               irq = ioapic_abi_find_irq(intline,
+                       INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
+       }
+       return irq;
+}
index ef86c54..737dc96 100644 (file)
@@ -113,6 +113,8 @@ int stop_cpus               (cpumask_t);
 void   ap_init                 (void);
 int    restart_cpus            (cpumask_t);
 void   forward_signal          (struct proc *);
+int    mptable_pci_int_route(int, int, int, int);
+void   mptable_pci_int_dump(void);
 
 #ifndef _SYS_QUEUE_H_
 #include <sys/queue.h>
@@ -171,6 +173,7 @@ int ioapic_gsi_pin(int);
 void   ioapic_pin_setup(void *, int, int,
            enum intr_trigger, enum intr_polarity);
 void   ioapic_extpin_setup(void *, int, int);
+int    ioapic_gsi(int, int);
 
 extern int apic_io_enable;
 extern int ioapic_use_old;
index 63bee9f..1c3ecc3 100644 (file)
@@ -719,6 +719,57 @@ ioapic_abi_fixup_irqmap(void)
        }
 }
 
+int
+ioapic_abi_find_gsi(int gsi, enum intr_trigger trig, enum intr_polarity pola)
+{
+       int irq;
+
+       KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL);
+       KKASSERT(pola == INTR_POLARITY_HIGH || pola == INTR_POLARITY_LOW);
+       KKASSERT((trig == INTR_TRIGGER_EDGE && pola == INTR_POLARITY_HIGH) ||
+                (trig == INTR_TRIGGER_LEVEL && pola == INTR_POLARITY_LOW));
+
+       for (irq = 0; irq < IOAPIC_HWI_VECTORS; ++irq) {
+               const struct ioapic_irqmap *map = &ioapic_irqmaps[irq];
+
+               if (map->im_gsi == gsi) {
+                       KKASSERT(map->im_type == IOAPIC_IMT_LINE);
+
+                       if (map->im_flags & IOAPIC_IMF_CONF) {
+                               if (map->im_trig != trig ||
+                                   map->im_pola != pola)
+                                       return -1;
+                       }
+                       return irq;
+               }
+       }
+       return -1;
+}
+
+int
+ioapic_abi_find_irq(int irq, enum intr_trigger trig, enum intr_polarity pola)
+{
+       const struct ioapic_irqmap *map;
+
+       KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL);
+       KKASSERT(pola == INTR_POLARITY_HIGH || pola == INTR_POLARITY_LOW);
+       KKASSERT((trig == INTR_TRIGGER_EDGE && pola == INTR_POLARITY_HIGH) ||
+                (trig == INTR_TRIGGER_LEVEL && pola == INTR_POLARITY_LOW));
+
+       if (irq < 0 || irq >= IOAPIC_HWI_VECTORS)
+               return -1;
+       map = &ioapic_irqmaps[irq];
+
+       if (map->im_type != IOAPIC_IMT_LINE)
+               return -1;
+
+       if (map->im_flags & IOAPIC_IMF_CONF) {
+               if (map->im_trig != trig || map->im_pola != pola)
+                       return -1;
+       }
+       return irq;
+}
+
 static void
 ioapic_intr_config(int irq, enum intr_trigger trig, enum intr_polarity pola)
 {
index 7216236..34c11a5 100644 (file)
@@ -52,6 +52,9 @@ extern struct machintr_abi MachIntrABI_IOAPIC;
 void   ioapic_abi_set_irqmap(int, int, enum intr_trigger, enum intr_polarity);
 void   ioapic_abi_fixup_irqmap(void);
 
+int    ioapic_abi_find_gsi(int, enum intr_trigger, enum intr_polarity);
+int    ioapic_abi_find_irq(int, enum intr_trigger, enum intr_polarity);
+
 #endif /* SMP */
 
 #endif /* !_ARCH_APIC_IOAPIC_ABI_H_ */
index 8d8bc4a..849d555 100644 (file)
@@ -1269,8 +1269,6 @@ ioapic_config(void)
                MachIntrABI.cleanup();
 
                crit_exit();
-
-               panic("ioapic_config: new ioapic not working yet\n");
        }
 }
 
@@ -1431,6 +1429,22 @@ ioapic_gsi_search(int gsi)
        panic("ioapic_gsi_search: no I/O APIC\n");
 }
 
+int
+ioapic_gsi(int idx, int pin)
+{
+       const struct ioapic_info *info;
+
+       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
+               if (info->io_idx == idx)
+                       break;
+       }
+       if (info == NULL)
+               return -1;
+       if (pin >= info->io_npin)
+               return -1;
+       return info->io_gsi_base + pin;
+}
+
 void
 ioapic_extpin_setup(void *addr, int pin, int vec)
 {
index 1868bfd..8846aa2 100644 (file)
@@ -124,6 +124,8 @@ int stop_cpus               (cpumask_t);
 void   ap_init                 (void);
 int    restart_cpus            (cpumask_t);
 void   forward_signal          (struct proc *);
+int    mptable_pci_int_route(int, int, int, int);
+void   mptable_pci_int_dump(void);
 
 #ifndef _SYS_QUEUE_H_
 #include <sys/queue.h>
@@ -182,6 +184,7 @@ int ioapic_gsi_pin(int);
 void   ioapic_pin_setup(void *, int, int,
            enum intr_trigger, enum intr_polarity);
 void   ioapic_extpin_setup(void *, int, int);
+int    ioapic_gsi(int, int);
 
 #if defined(READY)
 void   clr_io_apic_mask24      (int, u_int32_t);
index babf010..f43221e 100644 (file)
@@ -3715,3 +3715,54 @@ mptable_ioapic_enum_register(void)
 }
 SYSINIT(mptable_ioapic, SI_BOOT2_PRESMP, SI_ORDER_ANY,
        mptable_ioapic_enum_register, 0);
+
+void
+mptable_pci_int_dump(void)
+{
+       const struct mptable_pci_int *pci_int;
+
+       TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
+               kprintf("MPTABLE: %d:%d:%d -> IOAPIC %d.%d\n",
+                       pci_int->mpci_bus,
+                       pci_int->mpci_dev,
+                       pci_int->mpci_pin,
+                       pci_int->mpci_ioapic_idx,
+                       pci_int->mpci_ioapic_pin);
+       }
+}
+
+int
+mptable_pci_int_route(int bus, int dev, int pin, int intline)
+{
+       const struct mptable_pci_int *pci_int;
+       int irq = -1;
+
+       KKASSERT(pin >= 1);
+       --pin;  /* zero based */
+
+       TAILQ_FOREACH(pci_int, &mptable_pci_int_list, mpci_link) {
+               if (pci_int->mpci_bus == bus &&
+                   pci_int->mpci_dev == dev &&
+                   pci_int->mpci_pin == pin)
+                       break;
+       }
+       if (pci_int != NULL) {
+               int gsi;
+
+               gsi = ioapic_gsi(pci_int->mpci_ioapic_idx,
+                       pci_int->mpci_ioapic_pin);
+               if (gsi >= 0) {
+                       irq = ioapic_abi_find_gsi(gsi,
+                               INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
+               }
+       }
+
+       if (irq < 0) {
+               if (bootverbose)
+                       kprintf("MPTABLE: fixed interrupt routing\n");
+
+               irq = ioapic_abi_find_irq(intline,
+                       INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
+       }
+       return irq;
+}