summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mochel <mochel@segfault.osdl.org>2002-04-15 23:26:35 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2002-04-15 23:26:35 -0700
commit8da5f1d4072c4f0d88fbb7a25b2ba1065150ff1d (patch)
treeb4aea8bd8d08e8bceb4ac0e4105b374f466a2b0b
parent6af072e1fd2531cc7c24aca38d38ef1d86c6a41a (diff)
Further break-up-age
Make ACPI PCI IRQ routing work a bit better...
-rw-r--r--arch/i386/kernel/pci/Makefile11
-rw-r--r--arch/i386/kernel/pci/acpi.c70
-rw-r--r--arch/i386/kernel/pci/common.c44
-rw-r--r--arch/i386/kernel/pci/irq.c82
-rw-r--r--arch/i386/kernel/pci/legacy.c53
-rw-r--r--arch/i386/kernel/pci/numa.c4
-rw-r--r--arch/i386/kernel/pci/pci.h5
-rw-r--r--drivers/acpi/acpi_osl.c3
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;
}