diff options
| author | Patrick Mochel <mochel@segfault.osdl.org> | 2002-04-15 23:26:35 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-04-15 23:26:35 -0700 |
| commit | 8da5f1d4072c4f0d88fbb7a25b2ba1065150ff1d (patch) | |
| tree | b4aea8bd8d08e8bceb4ac0e4105b374f466a2b0b | |
| parent | 6af072e1fd2531cc7c24aca38d38ef1d86c6a41a (diff) | |
Further break-up-age
Make ACPI PCI IRQ routing work a bit better...
| -rw-r--r-- | arch/i386/kernel/pci/Makefile | 11 | ||||
| -rw-r--r-- | arch/i386/kernel/pci/acpi.c | 70 | ||||
| -rw-r--r-- | arch/i386/kernel/pci/common.c | 44 | ||||
| -rw-r--r-- | arch/i386/kernel/pci/irq.c | 82 | ||||
| -rw-r--r-- | arch/i386/kernel/pci/legacy.c | 53 | ||||
| -rw-r--r-- | arch/i386/kernel/pci/numa.c | 4 | ||||
| -rw-r--r-- | arch/i386/kernel/pci/pci.h | 5 | ||||
| -rw-r--r-- | drivers/acpi/acpi_osl.c | 3 |
8 files changed, 152 insertions, 120 deletions
diff --git a/arch/i386/kernel/pci/Makefile b/arch/i386/kernel/pci/Makefile index ce9728a2c58e..0539db71e81d 100644 --- a/arch/i386/kernel/pci/Makefile +++ b/arch/i386/kernel/pci/Makefile @@ -2,15 +2,22 @@ O_TARGET := pci.o obj-y := dma.o i386.o -ifdef CONFIG_VISWS +ifdef CONFIG_VISWS obj-y += visws.o else -ifdef CONFIG_MULTIQUAD +ifdef CONFIG_MULTIQUAD obj-y += numa.o else obj-$(CONFIG_PCI_BIOS) += pcbios.o obj-$(CONFIG_PCI_DIRECT) += direct.o obj-y += fixup.o + +ifdef CONFIG_ACPI_PCI +obj-y += acpi.o +else +obj-y += legacy.o +endif + endif # CONFIG_MULTIQUAD obj-y += irq.o common.o endif # CONFIG_VISWS diff --git a/arch/i386/kernel/pci/acpi.c b/arch/i386/kernel/pci/acpi.c new file mode 100644 index 000000000000..dd2c45d9d48e --- /dev/null +++ b/arch/i386/kernel/pci/acpi.c @@ -0,0 +1,70 @@ +#include <linux/pci.h> +#include <linux/acpi.h> +#include "pci.h" + +extern void eisa_set_level_irq(int irq); + +static int acpi_lookup_irq ( + struct pci_dev *dev, + int assign) +{ + int result = 0; + int irq = 0; + u8 pin; + + /* TBD: Select IRQ from possible to improve routing performance. */ + + /* Find IRQ pin */ + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (!pin) { + DBG(" -> no interrupt pin\n"); + return 0; + } + pin = pin - 1; + + result = acpi_prt_get_irq(dev, pin, &irq); + if (!irq) + result = -ENODEV; + if (0 != result) { + printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s\n", + 'A'+pin, dev->slot_name); + return result; + } + + /* only check for the IRQ */ + if (!assign) { + printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", + irq, dev->slot_name); + return 1; + } + + dev->irq = irq; + + /* also assign an IRQ */ + if (irq && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) { + result = acpi_prt_set_irq(dev, pin, irq); + if (0 != result) { + printk(KERN_WARNING "PCI: Could not assign IRQ %d to device %s\n", irq, dev->slot_name); + return result; + } + + eisa_set_level_irq(irq); + + printk(KERN_INFO "PCI: Assigned IRQ %d for device %s\n", irq, dev->slot_name); + } + + return 1; +} + +static int __init pci_acpi_init(void) +{ + if (!(pci_probe & PCI_NO_ACPI_ROUTING)) { + printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); + printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi'\n"); + pci_use_acpi_routing = 1; + pci_lookup_irq = acpi_lookup_irq; + } + return 0; +} + +subsys_initcall(pci_acpi_init); diff --git a/arch/i386/kernel/pci/common.c b/arch/i386/kernel/pci/common.c index 2a4b078253a3..51a7c4f1858f 100644 --- a/arch/i386/kernel/pci/common.c +++ b/arch/i386/kernel/pci/common.c @@ -4,12 +4,8 @@ * (c) 1999--2000 Martin Mares <mj@ucw.cz> */ -#include <linux/config.h> -#include <linux/types.h> -#include <linux/kernel.h> #include <linux/sched.h> #include <linux/pci.h> -#include <linux/init.h> #include <linux/ioport.h> #include <asm/segment.h> @@ -91,37 +87,6 @@ static void __devinit pcibios_fixup_ghosts(struct pci_bus *b) } /* - * Discover remaining PCI buses in case there are peer host bridges. - * We use the number of last PCI bus provided by the PCI BIOS. - */ -static void __devinit pcibios_fixup_peer_bridges(void) -{ - int n; - struct pci_bus bus; - struct pci_dev dev; - u16 l; - - if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff) - return; - DBG("PCI: Peer bridge fixup\n"); - for (n=0; n <= pcibios_last_bus; n++) { - if (pci_bus_exists(&pci_root_buses, n)) - continue; - bus.number = n; - bus.ops = pci_root_ops; - dev.bus = &bus; - for(dev.devfn=0; dev.devfn<256; dev.devfn += 8) - if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) && - l != 0x0000 && l != 0xffff) { - DBG("Found device at %02x:%02x [%04x]\n", n, dev.devfn, l); - printk("PCI: Discovered peer bus %02x\n", n); - pci_scan_bus(n, pci_root_ops, NULL); - break; - } - } -} - -/* * Called after each bus is probed, but before its children * are examined. */ @@ -158,15 +123,6 @@ static int __init pcibios_init(void) return 0; } - printk("PCI: Probing PCI hardware\n"); - pci_root_bus = pcibios_scan_root(0); - - pcibios_irq_init(); - - if (!pci_use_acpi_routing) - pcibios_fixup_peer_bridges(); - - pcibios_fixup_irqs(); pcibios_resource_survey(); #ifdef CONFIG_PCI_BIOS diff --git a/arch/i386/kernel/pci/irq.c b/arch/i386/kernel/pci/irq.c index 4e0fe015ecaf..68eb183277f3 100644 --- a/arch/i386/kernel/pci/irq.c +++ b/arch/i386/kernel/pci/irq.c @@ -46,6 +46,8 @@ struct irq_router { int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new); }; +int (*pci_lookup_irq)(struct pci_dev * dev, int assign) = NULL; + /* * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table. */ @@ -116,7 +118,7 @@ static void __init pirq_peer_trick(void) * Code for querying and setting of IRQ routes on various interrupt routers. */ -static void eisa_set_level_irq(unsigned int irq) +void eisa_set_level_irq(unsigned int irq) { unsigned char mask = 1 << (irq & 7); unsigned int port = 0x4d0 + (irq >> 3); @@ -556,54 +558,6 @@ static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs { } -#ifdef CONFIG_ACPI_PCI - -static int acpi_lookup_irq ( - struct pci_dev *dev, - u8 pin, - int assign) -{ - int result = 0; - int irq = 0; - - /* TBD: Select IRQ from possible to improve routing performance. */ - - result = acpi_prt_get_irq(dev, pin, &irq); - if (!irq) - result = -ENODEV; - if (0 != result) { - printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s\n", - 'A'+pin, dev->slot_name); - return result; - } - - dev->irq = irq; - - if (!assign) { - /* only check for the IRQ */ - printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", irq, - dev->slot_name); - return 1; - } - - /* also assign an IRQ */ - if (irq && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) { - result = acpi_prt_set_irq(dev, pin, irq); - if (0 != result) { - printk(KERN_WARNING "PCI: Could not assign IRQ %d to device %s\n", irq, dev->slot_name); - return result; - } - - eisa_set_level_irq(irq); - - printk(KERN_INFO "PCI: Assigned IRQ %d for device %s\n", irq, dev->slot_name); - } - - return 1; -} - -#endif /* CONFIG_ACPI_PCI */ - static int pcibios_lookup_irq(struct pci_dev *dev, int assign) { u8 pin; @@ -623,12 +577,6 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) } pin = pin - 1; -#ifdef CONFIG_ACPI_PCI - /* Use ACPI to lookup IRQ */ - if (pci_use_acpi_routing) - return acpi_lookup_irq(dev, pin, assign); -#endif - /* Find IRQ routing entry */ if (!pirq_table) @@ -736,21 +684,12 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) return 1; } -void __init pcibios_irq_init(void) +static int __init pcibios_irq_init(void) { DBG("PCI: IRQ init\n"); -#ifdef CONFIG_ACPI_PCI - if (!(pci_probe & PCI_NO_ACPI_ROUTING)) { - if (acpi_prts.count) { - printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); - pci_use_acpi_routing = 1; - return; - } - else - printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n"); - } -#endif + if (pci_lookup_irq) + return 0; pirq_table = pirq_find_routing_table(); @@ -771,8 +710,13 @@ void __init pcibios_irq_init(void) if (io_apic_assign_pci_irqs) pirq_table = NULL; } + pci_lookup_irq = pcibios_lookup_irq; + pcibios_fixup_irqs(); + return 0; } +subsys_initcall(pcibios_irq_init); + void __init pcibios_fixup_irqs(void) { struct pci_dev *dev; @@ -835,7 +779,7 @@ void __init pcibios_fixup_irqs(void) * Still no IRQ? Try to lookup one... */ if (pin && !dev->irq) - pcibios_lookup_irq(dev, 0); + pci_lookup_irq(dev, 0); } } @@ -852,7 +796,7 @@ void pcibios_enable_irq(struct pci_dev *dev) { u8 pin; pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) { + if (pin && !pci_lookup_irq(dev, 1) && !dev->irq) { char *msg; if (io_apic_assign_pci_irqs) msg = " Probably buggy MP table."; diff --git a/arch/i386/kernel/pci/legacy.c b/arch/i386/kernel/pci/legacy.c new file mode 100644 index 000000000000..51a6f6cdb480 --- /dev/null +++ b/arch/i386/kernel/pci/legacy.c @@ -0,0 +1,53 @@ +/* + * legacy.c - traditional, old school PCI bus probing + */ +#include <linux/pci.h> +#include "pci.h" + +/* + * Discover remaining PCI buses in case there are peer host bridges. + * We use the number of last PCI bus provided by the PCI BIOS. + */ +static void __devinit pcibios_fixup_peer_bridges(void) +{ + int n; + struct pci_bus bus; + struct pci_dev dev; + u16 l; + + if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff) + return; + DBG("PCI: Peer bridge fixup\n"); + for (n=0; n <= pcibios_last_bus; n++) { + if (pci_bus_exists(&pci_root_buses, n)) + continue; + bus.number = n; + bus.ops = pci_root_ops; + dev.bus = &bus; + for(dev.devfn=0; dev.devfn<256; dev.devfn += 8) + if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) && + l != 0x0000 && l != 0xffff) { + DBG("Found device at %02x:%02x [%04x]\n", n, dev.devfn, l); + printk("PCI: Discovered peer bus %02x\n", n); + pci_scan_bus(n, pci_root_ops, NULL); + break; + } + } +} + +static int __init pci_legacy_init(void) +{ + if (!pci_root_ops) { + printk("PCI: System does not support PCI\n"); + return 0; + } + + printk("PCI: Probing PCI hardware\n"); + pci_root_bus = pcibios_scan_root(0); + + if (!pci_use_acpi_routing) + pcibios_fixup_peer_bridges(); + return 0; +} + +subsys_initcall(pci_legacy_init); diff --git a/arch/i386/kernel/pci/numa.c b/arch/i386/kernel/pci/numa.c index a0e0189a64a8..ba2cab5f926a 100644 --- a/arch/i386/kernel/pci/numa.c +++ b/arch/i386/kernel/pci/numa.c @@ -12,7 +12,7 @@ #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ (0x80000000 | (BUS2LOCAL(bus) << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) -static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* CONFIG_MULTIQUAD */ +static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { unsigned long flags; @@ -40,7 +40,7 @@ static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, return 0; } -static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* CONFIG_MULTIQUAD */ +static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { unsigned long flags; diff --git a/arch/i386/kernel/pci/pci.h b/arch/i386/kernel/pci/pci.h index e510dafc12db..a3c632d3ca07 100644 --- a/arch/i386/kernel/pci/pci.h +++ b/arch/i386/kernel/pci/pci.h @@ -4,7 +4,7 @@ * (c) 1999 Martin Mares <mj@ucw.cz> */ -#undef DEBUG +#define DEBUG #ifdef DEBUG #define DBG(x...) printk(x) @@ -69,6 +69,7 @@ extern unsigned int pcibios_irq_mask; extern int pci_use_acpi_routing; extern spinlock_t pci_config_lock; -void pcibios_irq_init(void); void pcibios_fixup_irqs(void); void pcibios_enable_irq(struct pci_dev *dev); + +extern int (*pci_lookup_irq)(struct pci_dev * dev, int assign); diff --git a/drivers/acpi/acpi_osl.c b/drivers/acpi/acpi_osl.c index be3ff063e83e..7c3f6d4366cd 100644 --- a/drivers/acpi/acpi_osl.c +++ b/drivers/acpi/acpi_osl.c @@ -77,12 +77,13 @@ acpi_os_initialize(void) * Initialize PCI configuration space access, as we'll need to access * it while walking the namespace (bus 0 and root bridges w/ _BBNs). */ +#if 0 pcibios_config_init(); if (!pci_config_read || !pci_config_write) { printk(KERN_ERR PREFIX "Access to PCI configuration space unavailable\n"); return AE_NULL_ENTRY; } - +#endif return AE_OK; } |
