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
......@@ -11,6 +11,13 @@ 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
......
#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 @@
* (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>
......@@ -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
* 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
......
......@@ -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.";
......
/*
* 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 @@
#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;
......
......@@ -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);
......@@ -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;
}
......
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