Commit 8da5f1d4 authored by Patrick Mochel's avatar Patrick Mochel Committed by Linus Torvalds

Further break-up-age

Make ACPI PCI IRQ routing work a bit better...
parent 6af072e1
...@@ -2,15 +2,22 @@ O_TARGET := pci.o ...@@ -2,15 +2,22 @@ O_TARGET := pci.o
obj-y := dma.o i386.o obj-y := dma.o i386.o
ifdef CONFIG_VISWS ifdef CONFIG_VISWS
obj-y += visws.o obj-y += visws.o
else else
ifdef CONFIG_MULTIQUAD ifdef CONFIG_MULTIQUAD
obj-y += numa.o obj-y += numa.o
else else
obj-$(CONFIG_PCI_BIOS) += pcbios.o obj-$(CONFIG_PCI_BIOS) += pcbios.o
obj-$(CONFIG_PCI_DIRECT) += direct.o obj-$(CONFIG_PCI_DIRECT) += direct.o
obj-y += fixup.o obj-y += fixup.o
ifdef CONFIG_ACPI_PCI
obj-y += acpi.o
else
obj-y += legacy.o
endif
endif # CONFIG_MULTIQUAD endif # CONFIG_MULTIQUAD
obj-y += irq.o common.o obj-y += irq.o common.o
endif # CONFIG_VISWS endif # CONFIG_VISWS
......
#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);
...@@ -4,12 +4,8 @@ ...@@ -4,12 +4,8 @@
* (c) 1999--2000 Martin Mares <mj@ucw.cz> * (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/sched.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/init.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <asm/segment.h> #include <asm/segment.h>
...@@ -90,37 +86,6 @@ static void __devinit pcibios_fixup_ghosts(struct pci_bus *b) ...@@ -90,37 +86,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 * Called after each bus is probed, but before its children
* are examined. * are examined.
...@@ -158,15 +123,6 @@ static int __init pcibios_init(void) ...@@ -158,15 +123,6 @@ static int __init pcibios_init(void)
return 0; 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(); pcibios_resource_survey();
#ifdef CONFIG_PCI_BIOS #ifdef CONFIG_PCI_BIOS
......
...@@ -46,6 +46,8 @@ struct irq_router { ...@@ -46,6 +46,8 @@ struct irq_router {
int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq, int new); 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. * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
*/ */
...@@ -116,7 +118,7 @@ static void __init pirq_peer_trick(void) ...@@ -116,7 +118,7 @@ static void __init pirq_peer_trick(void)
* Code for querying and setting of IRQ routes on various interrupt routers. * 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 char mask = 1 << (irq & 7);
unsigned int port = 0x4d0 + (irq >> 3); 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 ...@@ -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) static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
{ {
u8 pin; u8 pin;
...@@ -623,12 +577,6 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) ...@@ -623,12 +577,6 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
} }
pin = pin - 1; 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 */ /* Find IRQ routing entry */
if (!pirq_table) if (!pirq_table)
...@@ -736,21 +684,12 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) ...@@ -736,21 +684,12 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
return 1; return 1;
} }
void __init pcibios_irq_init(void) static int __init pcibios_irq_init(void)
{ {
DBG("PCI: IRQ init\n"); DBG("PCI: IRQ init\n");
#ifdef CONFIG_ACPI_PCI if (pci_lookup_irq)
if (!(pci_probe & PCI_NO_ACPI_ROUTING)) { return 0;
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
pirq_table = pirq_find_routing_table(); pirq_table = pirq_find_routing_table();
...@@ -771,8 +710,13 @@ void __init pcibios_irq_init(void) ...@@ -771,8 +710,13 @@ void __init pcibios_irq_init(void)
if (io_apic_assign_pci_irqs) if (io_apic_assign_pci_irqs)
pirq_table = NULL; 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) void __init pcibios_fixup_irqs(void)
{ {
struct pci_dev *dev; struct pci_dev *dev;
...@@ -835,7 +779,7 @@ void __init pcibios_fixup_irqs(void) ...@@ -835,7 +779,7 @@ void __init pcibios_fixup_irqs(void)
* Still no IRQ? Try to lookup one... * Still no IRQ? Try to lookup one...
*/ */
if (pin && !dev->irq) 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) ...@@ -852,7 +796,7 @@ void pcibios_enable_irq(struct pci_dev *dev)
{ {
u8 pin; u8 pin;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &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; char *msg;
if (io_apic_assign_pci_irqs) if (io_apic_assign_pci_irqs)
msg = " Probably buggy MP table."; msg = " Probably buggy MP table.";
......
/*
* 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);
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
(0x80000000 | (BUS2LOCAL(bus) << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) (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; unsigned long flags;
...@@ -40,7 +40,7 @@ static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, ...@@ -40,7 +40,7 @@ static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len,
return 0; 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; unsigned long flags;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* (c) 1999 Martin Mares <mj@ucw.cz> * (c) 1999 Martin Mares <mj@ucw.cz>
*/ */
#undef DEBUG #define DEBUG
#ifdef DEBUG #ifdef DEBUG
#define DBG(x...) printk(x) #define DBG(x...) printk(x)
...@@ -69,6 +69,7 @@ extern unsigned int pcibios_irq_mask; ...@@ -69,6 +69,7 @@ extern unsigned int pcibios_irq_mask;
extern int pci_use_acpi_routing; extern int pci_use_acpi_routing;
extern spinlock_t pci_config_lock; extern spinlock_t pci_config_lock;
void pcibios_irq_init(void);
void pcibios_fixup_irqs(void); void pcibios_fixup_irqs(void);
void pcibios_enable_irq(struct pci_dev *dev); void pcibios_enable_irq(struct pci_dev *dev);
extern int (*pci_lookup_irq)(struct pci_dev * dev, int assign);
...@@ -77,12 +77,13 @@ acpi_os_initialize(void) ...@@ -77,12 +77,13 @@ acpi_os_initialize(void)
* Initialize PCI configuration space access, as we'll need to access * Initialize PCI configuration space access, as we'll need to access
* it while walking the namespace (bus 0 and root bridges w/ _BBNs). * it while walking the namespace (bus 0 and root bridges w/ _BBNs).
*/ */
#if 0
pcibios_config_init(); pcibios_config_init();
if (!pci_config_read || !pci_config_write) { if (!pci_config_read || !pci_config_write) {
printk(KERN_ERR PREFIX "Access to PCI configuration space unavailable\n"); printk(KERN_ERR PREFIX "Access to PCI configuration space unavailable\n");
return AE_NULL_ENTRY; return AE_NULL_ENTRY;
} }
#endif
return AE_OK; return AE_OK;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment