From e90e7ac4efa9c9c686a72d3805ef6f6220b6f1fd Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Sun, 20 Mar 2011 14:40:30 +0800 Subject: [PATCH] mptable/ioapic: Properly routing PCI interrupts --- sys/bus/pci/i386/mptable_pci.c | 45 ++++++++++++++--------- sys/bus/pci/x86_64/mptable_pci.c | 46 +++++++++++++++--------- sys/platform/pc32/apic/ioapic_abi.c | 51 +++++++++++++++++++++++++++ sys/platform/pc32/apic/ioapic_abi.h | 3 ++ sys/platform/pc32/apic/mpapic.c | 18 ++++++++-- sys/platform/pc32/i386/mp_machdep.c | 51 +++++++++++++++++++++++++++ sys/platform/pc32/include/smp.h | 3 ++ sys/platform/pc64/apic/ioapic_abi.c | 51 +++++++++++++++++++++++++++ sys/platform/pc64/apic/ioapic_abi.h | 3 ++ sys/platform/pc64/apic/mpapic.c | 18 ++++++++-- sys/platform/pc64/include/smp.h | 3 ++ sys/platform/pc64/x86_64/mp_machdep.c | 51 +++++++++++++++++++++++++++ 12 files changed, 307 insertions(+), 36 deletions(-) diff --git a/sys/bus/pci/i386/mptable_pci.c b/sys/bus/pci/i386/mptable_pci.c index 1c3cbebacd..36f26e9cd1 100644 --- a/sys/bus/pci/i386/mptable_pci.c +++ b/sys/bus/pci/i386/mptable_pci.c @@ -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); } diff --git a/sys/bus/pci/x86_64/mptable_pci.c b/sys/bus/pci/x86_64/mptable_pci.c index 1c3cbebacd..84a9ed8df5 100644 --- a/sys/bus/pci/x86_64/mptable_pci.c +++ b/sys/bus/pci/x86_64/mptable_pci.c @@ -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); } diff --git a/sys/platform/pc32/apic/ioapic_abi.c b/sys/platform/pc32/apic/ioapic_abi.c index 3835d6ce22..8db3d450d5 100644 --- a/sys/platform/pc32/apic/ioapic_abi.c +++ b/sys/platform/pc32/apic/ioapic_abi.c @@ -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) { diff --git a/sys/platform/pc32/apic/ioapic_abi.h b/sys/platform/pc32/apic/ioapic_abi.h index 7216236775..34c11a5338 100644 --- a/sys/platform/pc32/apic/ioapic_abi.h +++ b/sys/platform/pc32/apic/ioapic_abi.h @@ -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_ */ diff --git a/sys/platform/pc32/apic/mpapic.c b/sys/platform/pc32/apic/mpapic.c index 570a9cf01e..5b9be8feb6 100644 --- a/sys/platform/pc32/apic/mpapic.c +++ b/sys/platform/pc32/apic/mpapic.c @@ -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) { diff --git a/sys/platform/pc32/i386/mp_machdep.c b/sys/platform/pc32/i386/mp_machdep.c index 797fea9530..d8b77185b8 100644 --- a/sys/platform/pc32/i386/mp_machdep.c +++ b/sys/platform/pc32/i386/mp_machdep.c @@ -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; +} diff --git a/sys/platform/pc32/include/smp.h b/sys/platform/pc32/include/smp.h index ef86c54321..737dc96bc6 100644 --- a/sys/platform/pc32/include/smp.h +++ b/sys/platform/pc32/include/smp.h @@ -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 @@ -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; diff --git a/sys/platform/pc64/apic/ioapic_abi.c b/sys/platform/pc64/apic/ioapic_abi.c index 63bee9f2a4..1c3ecc3849 100644 --- a/sys/platform/pc64/apic/ioapic_abi.c +++ b/sys/platform/pc64/apic/ioapic_abi.c @@ -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) { diff --git a/sys/platform/pc64/apic/ioapic_abi.h b/sys/platform/pc64/apic/ioapic_abi.h index 7216236775..34c11a5338 100644 --- a/sys/platform/pc64/apic/ioapic_abi.h +++ b/sys/platform/pc64/apic/ioapic_abi.h @@ -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_ */ diff --git a/sys/platform/pc64/apic/mpapic.c b/sys/platform/pc64/apic/mpapic.c index 8d8bc4a7ac..849d555cb2 100644 --- a/sys/platform/pc64/apic/mpapic.c +++ b/sys/platform/pc64/apic/mpapic.c @@ -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) { diff --git a/sys/platform/pc64/include/smp.h b/sys/platform/pc64/include/smp.h index 1868bfd8fc..8846aa2636 100644 --- a/sys/platform/pc64/include/smp.h +++ b/sys/platform/pc64/include/smp.h @@ -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 @@ -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); diff --git a/sys/platform/pc64/x86_64/mp_machdep.c b/sys/platform/pc64/x86_64/mp_machdep.c index babf010fcd..f43221e17d 100644 --- a/sys/platform/pc64/x86_64/mp_machdep.c +++ b/sys/platform/pc64/x86_64/mp_machdep.c @@ -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; +} -- 2.41.0