New PCI IRQ routing code for pre9-2

From: Martin Mares (mj@suse.cz)
Date: Thu May 18 2000 - 14:28:20 EST


Hello!

This is a new version of the PCI IRQ routing code. Changes:

o Fixed ID of the 82440MX router (by Dave Hinds).
o ISAPnP and PCI now interact in order to avoid assignment of the
   same IRQ to both PCI and ISA devices. Checking of collision with
   PCI IRQ's has been moved from isapnp_init() to isapnp_check_interrupt(),
   so that dynamically assigned PCI interrupts are detected as well.
   Also, when scanning card configuration, ISAPnP notifies the PCI
   subsystem by calling pcibios_penalize_isa_irq() that the particular
   IRQ's can be used by ISAPnP cards and therefore should not be
   assigned to PCI devices if possible. [It would be nice to have
   some central arch-dependent piece code doing IRQ assignments
   properly instead of kludging it on many places as we do now, but
   it's a 2.5 project.]
o PCI interrupt assignments are avoided if IO-APIC is really found,
   not if it's only configured.
o When trying to assign an IRQ, try request_irq() on it.
o If BIOS reports some IRQ's as exclusive for PCI, increase penalties
   for the other ones.
o Better reporting of error messages when IRQ is not found.

I hope this patch fixes all known IRQ assignment problems.

Linus, I wasn't able to test it on any SMP machine, so I'm not sure
about the IO-APIC part, so please decide yourself whether you want
to apply it or not.

                                                        Martin

--- include/linux/pci_ids.h.mj Thu May 18 19:00:44 2000
+++ include/linux/pci_ids.h Thu May 18 19:00:44 2000
@@ -1175,7 +1175,6 @@
 #define PCI_DEVICE_ID_INTEL_82443BX_0 0x7190
 #define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191
 #define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192
-#define PCI_DEVICE_ID_INTEL_82440MX_1 0x7194
 #define PCI_DEVICE_ID_INTEL_82443MX_0 0x7198
 #define PCI_DEVICE_ID_INTEL_82443MX_1 0x7199
 #define PCI_DEVICE_ID_INTEL_82443MX_2 0x719a
--- include/asm-i386/pci.h.mj Thu May 18 19:53:59 2000
+++ include/asm-i386/pci.h Thu May 18 20:45:31 2000
@@ -13,6 +13,7 @@
 #define PCIBIOS_MIN_MEM 0x10000000
 
 void pcibios_set_master(struct pci_dev *dev);
+void pcibios_penalize_isa_irq(int irq);
 
 /* Dynamic DMA mapping stuff.
  * i386 has everything mapped statically.
--- include/asm-i386/io_apic.h.mj Thu May 18 20:23:11 2000
+++ include/asm-i386/io_apic.h Thu May 18 20:45:29 2000
@@ -9,6 +9,8 @@
  * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar
  */
 
+#ifdef CONFIG_X86_IO_APIC
+
 #define IO_APIC_BASE(idx) \
                 ((volatile int *)__fix_to_virt(FIX_IO_APIC_BASE_0 + idx))
 
@@ -130,5 +132,14 @@
 extern int skip_ioapic_setup;
 extern void IO_APIC_init_uniprocessor (void);
 
+/*
+ * If we use the IO-APIC for IRQ routing, disable automatic
+ * assignment of PCI IRQ's.
+ */
+#define io_apic_assign_pci_irqs (!mp_irq_entries)
+
+#else /* !CONFIG_X86_IO_APIC */
+#define io_apic_assign_pci_irqs 0
 #endif
 
+#endif
--- include/asm-mips/pci.h.mj Thu May 18 19:53:59 2000
+++ include/asm-mips/pci.h Thu May 18 19:55:46 2000
@@ -23,6 +23,11 @@
         /* No special bus mastering setup handling */
 }
 
+extern inline void pcibios_penalize_isa_irq(int irq)
+{
+ /* We don't do dynamic PCI IRQ allocation */
+}
+
 /*
  * Dynamic DMA mapping stuff.
  * MIPS has everything mapped statically.
--- include/asm-alpha/pci.h.mj Thu May 18 19:53:59 2000
+++ include/asm-alpha/pci.h Thu May 18 19:54:55 2000
@@ -56,6 +56,11 @@
         /* No special bus mastering setup handling */
 }
 
+extern inline void pcibios_penalize_isa_irq(int irq)
+{
+ /* We don't do dynamic PCI IRQ allocation */
+}
+
 /* IOMMU controls. */
 
 /* Allocate and map kernel buffer using consistant mode DMA for PCI
--- include/asm-m68k/pci.h.mj Thu May 18 19:53:59 2000
+++ include/asm-m68k/pci.h Thu May 18 19:55:43 2000
@@ -40,4 +40,9 @@
         /* No special bus mastering setup handling */
 }
 
+extern inline void pcibios_penalize_isa_irq(int irq)
+{
+ /* We don't do dynamic PCI IRQ allocation */
+}
+
 #endif /* _ASM_M68K_PCI_H */
--- include/asm-sparc/pci.h.mj Thu May 18 19:53:59 2000
+++ include/asm-sparc/pci.h Thu May 18 19:56:01 2000
@@ -17,6 +17,11 @@
         /* No special bus mastering setup handling */
 }
 
+extern inline void pcibios_penalize_isa_irq(int irq)
+{
+ /* We don't do dynamic PCI IRQ allocation */
+}
+
 /* Dynamic DMA mapping stuff.
  */
 
--- include/asm-ppc/pci.h.mj Thu May 18 19:53:59 2000
+++ include/asm-ppc/pci.h Thu May 18 19:55:54 2000
@@ -15,6 +15,11 @@
         /* No special bus mastering setup handling */
 }
 
+extern inline void pcibios_penalize_isa_irq(int irq)
+{
+ /* We don't do dynamic PCI IRQ allocation */
+}
+
 /* Dynamic DMA Mapping stuff
  * ++ajoshi
  */
--- include/asm-sparc64/pci.h.mj Thu May 18 19:53:59 2000
+++ include/asm-sparc64/pci.h Thu May 18 19:56:04 2000
@@ -17,6 +17,11 @@
         /* No special bus mastering setup handling */
 }
 
+extern inline void pcibios_penalize_isa_irq(int irq)
+{
+ /* We don't do dynamic PCI IRQ allocation */
+}
+
 /* Dynamic DMA mapping stuff.
  */
 
--- include/asm-arm/pci.h.mj Thu May 18 19:53:59 2000
+++ include/asm-arm/pci.h Thu May 18 19:55:11 2000
@@ -13,6 +13,11 @@
         /* No special bus mastering setup handling */
 }
 
+extern inline void pcibios_penalize_isa_irq(int irq)
+{
+ /* We don't do dynamic PCI IRQ allocation */
+}
+
 #include <asm/scatterlist.h>
 #include <asm/io.h>
 
--- include/asm-sh/pci.h.mj Thu May 18 19:53:59 2000
+++ include/asm-sh/pci.h Thu May 18 19:55:58 2000
@@ -14,6 +14,11 @@
         /* No special bus mastering setup handling */
 }
 
+extern inline void pcibios_penalize_isa_irq(int irq)
+{
+ /* We don't do dynamic PCI IRQ allocation */
+}
+
 /* Dynamic DMA mapping stuff.
  * SuperH has everything mapped statically like x86.
  */
--- include/asm-ia64/pci.h.mj Thu May 18 19:53:59 2000
+++ include/asm-ia64/pci.h Thu May 18 19:55:38 2000
@@ -16,6 +16,11 @@
         /* No special bus mastering setup handling */
 }
 
+extern inline void pcibios_penalize_isa_irq(int irq)
+{
+ /* We don't do dynamic PCI IRQ allocation */
+}
+
 /*
  * Dynamic DMA mapping API.
  * IA-64 has everything mapped statically.
--- include/asm-mips64/pci.h.mj Thu May 18 19:53:59 2000
+++ include/asm-mips64/pci.h Thu May 18 19:55:50 2000
@@ -23,6 +23,11 @@
         /* No special bus mastering setup handling */
 }
 
+extern inline void pcibios_penalize_isa_irq(int irq)
+{
+ /* We don't do dynamic PCI IRQ allocation */
+}
+
 /*
  * Dynamic DMA mapping stuff.
  * MIPS has everything mapped statically.
--- drivers/pnp/isapnp.c.mj Thu May 18 19:52:46 2000
+++ drivers/pnp/isapnp.c Thu May 18 21:10:50 2000
@@ -500,6 +500,7 @@
                                                int dependent, int size)
 {
         unsigned char tmp[3];
+ int i;
         struct isapnp_irq *irq, *ptr;
 
         isapnp_peek(tmp, size);
@@ -526,6 +527,9 @@
                 ptr->next = irq;
         else
                 (*res)->irq = irq;
+ for (i=0; i<16; i++)
+ if (irq->map & i)
+ pcibios_penalize_isa_irq(i);
 }
 
 /*
@@ -1603,6 +1607,14 @@
                                 return 1;
                 }
         }
+#ifdef CONFIG_PCI
+ if (!isapnp_skip_pci_scan) {
+ pci_for_each_dev(dev) {
+ if (dev->irq == irq)
+ return 1;
+ }
+ }
+#endif
         if (request_irq(irq, isapnp_test_handler, SA_INTERRUPT, "isapnp", NULL))
                 return 1;
         free_irq(irq, NULL);
@@ -2070,45 +2082,6 @@
 #endif
 }
 
-static int __init isapnp_do_reserve_irq(int irq)
-{
- int i;
-
- if (irq < 0 || irq > 15)
- return -EINVAL;
- for (i = 0; i < 16; i++) {
- if (isapnp_reserve_irq[i] == irq)
- return 0;
- }
- for (i = 0; i < 16; i++) {
- if (isapnp_reserve_irq[i] < 0) {
- isapnp_reserve_irq[i] = irq;
-#ifdef ISAPNP_DEBUG
- printk("isapnp: IRQ %i is reserved now.\n", irq);
-#endif
- return 0;
- }
- }
- return -ENOMEM;
-}
-
-#ifdef CONFIG_PCI
-
-static void __init isapnp_pci_init(void)
-{
- struct pci_dev *dev;
-
- pci_for_each_dev(dev) {
-#ifdef ISAPNP_DEBUG
- printk("isapnp: PCI: reserved IRQ: %i\n", dev->irq);
-#endif
- if (dev->irq > 0)
- isapnp_do_reserve_irq(dev->irq);
- }
-}
-
-#endif /* CONFIG_PCI */
-
 EXPORT_SYMBOL(isapnp_cards);
 EXPORT_SYMBOL(isapnp_devices);
 EXPORT_SYMBOL(isapnp_present);
@@ -2200,10 +2173,6 @@
         } else {
                 printk("isapnp: No Plug & Play card found\n");
         }
-#ifdef CONFIG_PCI
- if (!isapnp_skip_pci_scan)
- isapnp_pci_init();
-#endif
 #ifdef CONFIG_PROC_FS
         isapnp_proc_init();
 #endif
--- arch/i386/kernel/pci-irq.c.mj Thu May 18 19:01:08 2000
+++ arch/i386/kernel/pci-irq.c Thu May 18 20:55:51 2000
@@ -14,11 +14,11 @@
 #include <linux/irq.h>
 
 #include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/io_apic.h>
 
 #include "pci-i386.h"
 
-extern int skip_ioapic_setup;
-
 #define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
 #define PIRQ_VERSION 0x0100
 
@@ -32,8 +32,8 @@
 unsigned int pcibios_irq_mask = 0xfff8;
 
 static unsigned pirq_penalty[16] = {
- 10000, 10000, 10000, 100, 100, 0, 0, 100,
- 0, 0, 0, 0, 100, 1000, 1000, 1000
+ 1000000, 1000000, 1000000, 1000, 1000, 0, 0, 1000,
+ 0, 0, 0, 0, 1000, 100000, 100000, 100000
 };
 
 struct irq_router {
@@ -222,7 +222,7 @@
         { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, pirq_piix_get, pirq_piix_set },
         { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, pirq_piix_get, pirq_piix_set },
         { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },
- { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82440MX_1, pirq_piix_get, pirq_piix_set },
+ { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
         { "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
         { "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set },
         { "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set },
@@ -287,6 +287,10 @@
         return NULL;
 }
 
+static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
-int pcibios_lookup_irq(struct pci_dev *dev, int assign)
+static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
 {
         struct irq_info *info;
@@ -323,19 +327,24 @@
 
         /* Find the best IRQ to assign */
         newirq = 0;
- for (i = 0; i < 16; i++) {
- if (!(mask & (1 << i)))
- continue;
- if (pirq_penalty[i] < pirq_penalty[newirq])
- newirq = i;
+ if (assign) {
+ for (i = 0; i < 16; i++) {
+ if (!(mask & (1 << i)))
+ continue;
+ if (pirq_penalty[i] < pirq_penalty[newirq] &&
+ !request_irq(i, pcibios_test_irq_handler, SA_SHIRQ, "pci-test", dev)) {
+ free_irq(i, dev);
+ newirq = i;
+ }
+ }
+ DBG(" -> newirq=%d", newirq);
         }
- DBG(" -> newirq=%d", newirq);
 
         /* Try to get current IRQ */
         if (r->get && (irq = r->get(pirq_router_dev, d, pirq))) {
                 DBG(" -> got IRQ %d\n", irq);
                 msg = "Found";
- } else if (assign && newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
+ } else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
                 DBG(" -> assigning IRQ %d", newirq);
                 if (r->set(pirq_router_dev, d, pirq, newirq)) {
                         DBG(" ... OK\n");
@@ -346,7 +355,7 @@
 
         if (!irq) {
                 DBG(" ... failed\n");
- if (assign && newirq && mask == (1 << newirq)) {
+ if (newirq && mask == (1 << newirq)) {
                         msg = "Guessed";
                         irq = newirq;
                 } else
@@ -379,6 +388,15 @@
         if (pirq_table) {
                 pirq_peer_trick();
                 pirq_find_router();
+ if (pirq_table->exclusive_irqs) {
+ int i;
+ for (i=0; i<16; i++)
+ if (!(pirq_table->exclusive_irqs & (1 << i)))
+ pirq_penalty[i] += 100;
+ }
+ /* If we're using the I/O APIC, avoid using the PCI IRQ routing table */
+ if (io_apic_assign_pci_irqs)
+ pirq_table = NULL;
         }
 }
 
@@ -402,11 +420,11 @@
 
         pci_for_each_dev(dev) {
                 pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-#if defined(CONFIG_X86_IO_APIC)
+#ifdef CONFIG_X86_IO_APIC
                 /*
                  * Recalculate IRQ numbers if we use the I/O APIC.
                  */
- if (!skip_ioapic_setup)
+ if (io_apic_assign_pci_irqs)
                 {
                         int irq;
 
@@ -441,5 +459,33 @@
                  */
                 if (pin && !dev->irq)
                         pcibios_lookup_irq(dev, 0);
+ }
+}
+
+void __init pcibios_penalize_isa_irq(int irq)
+{
+ /*
+ * If any ISAPnP device reports an IRQ in its list of possible
+ * IRQ's, we try to avoid assigning it to PCI devices.
+ */
+ pirq_penalty[irq] += 100;
+}
+
+void pcibios_enable_irq(struct pci_dev *dev)
+{
+ if (!dev->irq) {
+ u8 pin;
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin && !pcibios_lookup_irq(dev, 1)) {
+ char *msg;
+ if (io_apic_assign_pci_irqs)
+ msg = " Probably buggy MP table.";
+ else if (pci_probe & PCI_BIOS_IRQ_SCAN)
+ msg = "";
+ else
+ msg = " Please try using pci=biosirq.";
+ printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
+ 'A' + pin - 1, dev->slot_name, msg);
+ }
         }
 }
--- arch/i386/kernel/pci-visws.c.mj Thu May 18 19:56:28 2000
+++ arch/i386/kernel/pci-visws.c Thu May 18 19:56:53 2000
@@ -135,3 +135,7 @@
 {
         return pcibios_enable_resources(dev);
 }
+
+void __init pcibios_penalize_isa_irq(irq)
+{
+}
--- arch/i386/kernel/pci-pc.c.mj Thu May 18 20:26:06 2000
+++ arch/i386/kernel/pci-pc.c Thu May 18 20:40:40 2000
@@ -14,7 +14,6 @@
 
 #include <asm/segment.h>
 #include <asm/io.h>
-#include <asm/smp.h>
 
 #include "pci-i386.h"
 
@@ -1045,13 +1044,6 @@
 
         if ((err = pcibios_enable_resources(dev)) < 0)
                 return err;
- if (!dev->irq) {
- u8 pin;
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (pin && !pcibios_lookup_irq(dev, 1))
- printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
- 'A' + pin - 1, dev->slot_name,
- (pci_probe & PCI_BIOS_IRQ_SCAN) ? "" : " Please try using pci=biosirq.");
- }
+ pcibios_enable_irq(dev);
         return 0;
 }
--- arch/i386/kernel/i386_ksyms.c.mj Thu May 18 20:37:45 2000
+++ arch/i386/kernel/i386_ksyms.c Thu May 18 20:38:55 2000
@@ -100,6 +100,10 @@
 EXPORT_SYMBOL(pci_alloc_consistent);
 EXPORT_SYMBOL(pci_free_consistent);
 
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL(pcibios_penalize_isa_irq);
+#endif
+
 #ifdef CONFIG_X86_USE_3DNOW
 EXPORT_SYMBOL(_mmx_memcpy);
 EXPORT_SYMBOL(mmx_clear_page);
--- arch/i386/kernel/pci-i386.h.mj Thu May 18 20:40:31 2000
+++ arch/i386/kernel/pci-i386.h Thu May 18 20:40:31 2000
@@ -68,4 +68,4 @@
 
 void pcibios_irq_init(void);
 void pcibios_fixup_irqs(void);
-int pcibios_lookup_irq(struct pci_dev *dev, int assign);
+void pcibios_enable_irq(struct pci_dev *dev);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue May 23 2000 - 21:00:16 EST