]> git.hungrycats.org Git - linux/commitdiff
Move arch/i386/kernel/pci/ to arch/i386/pci/
authorPatrick Mochel <mochel@segfault.osdl.org>
Tue, 7 May 2002 03:09:44 +0000 (20:09 -0700)
committerPatrick Mochel <mochel@segfault.osdl.org>
Tue, 7 May 2002 03:09:44 +0000 (20:09 -0700)
30 files changed:
arch/i386/Makefile
arch/i386/kernel/Makefile
arch/i386/kernel/pci/Makefile [deleted file]
arch/i386/kernel/pci/acpi.c [deleted file]
arch/i386/kernel/pci/changelog [deleted file]
arch/i386/kernel/pci/common.c [deleted file]
arch/i386/kernel/pci/direct.c [deleted file]
arch/i386/kernel/pci/dma.c [deleted file]
arch/i386/kernel/pci/fixup.c [deleted file]
arch/i386/kernel/pci/i386.c [deleted file]
arch/i386/kernel/pci/irq.c [deleted file]
arch/i386/kernel/pci/legacy.c [deleted file]
arch/i386/kernel/pci/numa.c [deleted file]
arch/i386/kernel/pci/pcbios.c [deleted file]
arch/i386/kernel/pci/pci.h [deleted file]
arch/i386/kernel/pci/visws.c [deleted file]
arch/i386/pci/Makefile [new file with mode: 0644]
arch/i386/pci/acpi.c [new file with mode: 0644]
arch/i386/pci/changelog [new file with mode: 0644]
arch/i386/pci/common.c [new file with mode: 0644]
arch/i386/pci/direct.c [new file with mode: 0644]
arch/i386/pci/dma.c [new file with mode: 0644]
arch/i386/pci/fixup.c [new file with mode: 0644]
arch/i386/pci/i386.c [new file with mode: 0644]
arch/i386/pci/irq.c [new file with mode: 0644]
arch/i386/pci/legacy.c [new file with mode: 0644]
arch/i386/pci/numa.c [new file with mode: 0644]
arch/i386/pci/pcbios.c [new file with mode: 0644]
arch/i386/pci/pci.h [new file with mode: 0644]
arch/i386/pci/visws.c [new file with mode: 0644]

index 9fc7ca5d6e39755c11333a6fe3fc917bd95e08d3..02174a51a9e53fe9f13ace68e3cb09e74f2dff21 100644 (file)
@@ -98,6 +98,11 @@ SUBDIRS += arch/i386/math-emu
 DRIVERS += arch/i386/math-emu/math.o
 endif
 
+ifdef CONFIG_PCI
+SUBDIRS        += arch/i386/pci
+DRIVERS        += arch/i386/pci/pci.o
+endif
+
 arch/i386/kernel: dummy
        $(MAKE) linuxsubdirs SUBDIRS=arch/i386/kernel
 
index 12f530e688fae860a483d793d70751e764f50b75..d1c3ad476f67415ffb5d05b60c7b43eaca4b2e23 100644 (file)
@@ -10,7 +10,7 @@
 .S.o:
        $(CC) $(AFLAGS) -traditional -c $< -o $*.o
 
-all: first_rule kernel.o head.o init_task.o
+all: kernel.o head.o init_task.o
 
 O_TARGET := kernel.o
 
@@ -37,8 +37,4 @@ obj-y += setup-visws.o
 obj-$(CONFIG_X86_VISWS_APIC)   += visws_apic.o
 endif
 
-kernel-subdir-$(CONFIG_PCI)    += pci
-subdir-y                       := $(kernel-subdir-y)
-obj-y                          += $(foreach dir,$(subdir-y),$(dir)/$(dir).o)
-
 include $(TOPDIR)/Rules.make
diff --git a/arch/i386/kernel/pci/Makefile b/arch/i386/kernel/pci/Makefile
deleted file mode 100644 (file)
index e07ba54..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-O_TARGET        := pci.o
-
-obj-y          := dma.o i386.o
-
-ifdef  CONFIG_VISWS
-obj-y          += visws.o
-else
-
-obj-$(CONFIG_PCI_BIOS)         += pcbios.o
-obj-$(CONFIG_PCI_DIRECT)       += direct.o
-
-ifdef  CONFIG_MULTIQUAD
-obj-y          += numa.o
-else
-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
-
-export-objs     +=      $(obj-y)
-
-include $(TOPDIR)/Rules.make
diff --git a/arch/i386/kernel/pci/acpi.c b/arch/i386/kernel/pci/acpi.c
deleted file mode 100644 (file)
index dd2c45d..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#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/changelog b/arch/i386/kernel/pci/changelog
deleted file mode 100644 (file)
index f92eb1c..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * CHANGELOG :
- * Jun 17, 1994 : Modified to accommodate the broken pre-PCI BIOS SPECIFICATION
- *     Revision 2.0 present on <thys@dennis.ee.up.ac.za>'s ASUS mainboard.
- *
- * Jan 5,  1995 : Modified to probe PCI hardware at boot time by Frederic
- *     Potter, potter@cao-vlsi.ibp.fr
- *
- * Jan 10, 1995 : Modified to store the information about configured pci
- *      devices into a list, which can be accessed via /proc/pci by
- *      Curtis Varner, cvarner@cs.ucr.edu
- *
- * Jan 12, 1995 : CPU-PCI bridge optimization support by Frederic Potter.
- *     Alpha version. Intel & UMC chipset support only.
- *
- * Apr 16, 1995 : Source merge with the DEC Alpha PCI support. Most of the code
- *     moved to drivers/pci/pci.c.
- *
- * Dec 7, 1996  : Added support for direct configuration access of boards
- *      with Intel compatible access schemes (tsbogend@alpha.franken.de)
- *
- * Feb 3, 1997  : Set internal functions to static, save/restore flags
- *     avoid dead locks reading broken PCI BIOS, werner@suse.de 
- *
- * Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS
- *     (mj@atrey.karlin.mff.cuni.cz)
- *
- * May 7,  1997 : Added some missing cli()'s. [mj]
- * 
- * Jun 20, 1997 : Corrected problems in "conf1" type accesses.
- *      (paubert@iram.es)
- *
- * Aug 2,  1997 : Split to PCI BIOS handling and direct PCI access parts
- *     and cleaned it up...     Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- *
- * Feb 6,  1998 : No longer using BIOS to find devices and device classes. [mj]
- *
- * May 1,  1998 : Support for peer host bridges. [mj]
- *
- * Jun 19, 1998 : Changed to use spinlocks, so that PCI configuration space
- *     can be accessed from interrupts even on SMP systems. [mj]
- *
- * August  1998 : Better support for peer host bridges and more paranoid
- *     checks for direct hardware access. Ugh, this file starts to look as
- *     a large gallery of common hardware bug workarounds (watch the comments)
- *     -- the PCI specs themselves are sane, but most implementors should be
- *     hit hard with \hammer scaled \magstep5. [mj]
- *
- * Jan 23, 1999 : More improvements to peer host bridge logic. i450NX fixup. [mj]
- *
- * Feb 8,  1999 : Added UM8886BF I/O address fixup. [mj]
- *
- * August  1999 : New resource management and configuration access stuff. [mj]
- *
- * Sep 19, 1999 : Use PCI IRQ routing tables for detection of peer host bridges.
- *               Based on ideas by Chris Frantz and David Hinds. [mj]
- *
- * Sep 28, 1999 : Handle unreported/unassigned IRQs. Thanks to Shuu Yamaguchi
- *               for a lot of patience during testing. [mj]
- *
- * Oct  8, 1999 : Split to pci-i386.c, pci-pc.c and pci-visws.c. [mj]
- */
\ No newline at end of file
diff --git a/arch/i386/kernel/pci/common.c b/arch/i386/kernel/pci/common.c
deleted file mode 100644 (file)
index 35a721f..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- *     Low-Level PCI Support for PC
- *
- *     (c) 1999--2000 Martin Mares <mj@ucw.cz>
- */
-
-#include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-
-#include "pci.h"
-
-#ifdef CONFIG_PCI_BIOS
-extern  void pcibios_sort(void);
-#endif
-
-unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
-
-int pcibios_last_bus = -1;
-struct pci_bus *pci_root_bus = NULL;
-struct pci_ops *pci_root_ops = NULL;
-
-int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value) = NULL;
-int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value) = NULL;
-
-/*
- * This interrupt-safe spinlock protects all accesses to PCI
- * configuration space.
- */
-spinlock_t pci_config_lock = SPIN_LOCK_UNLOCKED;
-
-/*
- * Several buggy motherboards address only 16 devices and mirror
- * them to next 16 IDs. We try to detect this `feature' on all
- * primary buses (those containing host bridges as they are
- * expected to be unique) and remove the ghost devices.
- */
-
-static void __devinit pcibios_fixup_ghosts(struct pci_bus *b)
-{
-       struct list_head *ln, *mn;
-       struct pci_dev *d, *e;
-       int mirror = PCI_DEVFN(16,0);
-       int seen_host_bridge = 0;
-       int i;
-
-       DBG("PCI: Scanning for ghost devices on bus %d\n", b->number);
-       for (ln=b->devices.next; ln != &b->devices; ln=ln->next) {
-               d = pci_dev_b(ln);
-               if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
-                       seen_host_bridge++;
-               for (mn=ln->next; mn != &b->devices; mn=mn->next) {
-                       e = pci_dev_b(mn);
-                       if (e->devfn != d->devfn + mirror ||
-                           e->vendor != d->vendor ||
-                           e->device != d->device ||
-                           e->class != d->class)
-                               continue;
-                       for(i=0; i<PCI_NUM_RESOURCES; i++)
-                               if (e->resource[i].start != d->resource[i].start ||
-                                   e->resource[i].end != d->resource[i].end ||
-                                   e->resource[i].flags != d->resource[i].flags)
-                                       continue;
-                       break;
-               }
-               if (mn == &b->devices)
-                       return;
-       }
-       if (!seen_host_bridge)
-               return;
-       printk(KERN_WARNING "PCI: Ignoring ghost devices on bus %02x\n", b->number);
-
-       ln = &b->devices;
-       while (ln->next != &b->devices) {
-               d = pci_dev_b(ln->next);
-               if (d->devfn >= mirror) {
-                       list_del(&d->global_list);
-                       list_del(&d->bus_list);
-                       kfree(d);
-               } else
-                       ln = ln->next;
-       }
-}
-
-/*
- *  Called after each bus is probed, but before its children
- *  are examined.
- */
-
-void __devinit  pcibios_fixup_bus(struct pci_bus *b)
-{
-       pcibios_fixup_ghosts(b);
-       pci_read_bridge_bases(b);
-}
-
-
-struct pci_bus * __devinit pcibios_scan_root(int busnum)
-{
-       struct list_head *list;
-       struct pci_bus *bus;
-
-       list_for_each(list, &pci_root_buses) {
-               bus = pci_bus_b(list);
-               if (bus->number == busnum) {
-                       /* Already scanned */
-                       return bus;
-               }
-       }
-
-       printk("PCI: Probing PCI hardware (bus %02x)\n", busnum);
-
-       return pci_scan_bus(busnum, pci_root_ops, NULL);
-}
-
-static int __init pcibios_init(void)
-{
-       if (!pci_root_ops) {
-               printk("PCI: System does not support PCI\n");
-               return 0;
-       }
-
-       pcibios_resource_survey();
-
-#ifdef CONFIG_PCI_BIOS
-       if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
-               pcibios_sort();
-#endif
-       return 0;
-}
-
-subsys_initcall(pcibios_init);
-
-char * __devinit  pcibios_setup(char *str)
-{
-       if (!strcmp(str, "off")) {
-               pci_probe = 0;
-               return NULL;
-       }
-#ifdef CONFIG_PCI_BIOS
-       else if (!strcmp(str, "bios")) {
-               pci_probe = PCI_PROBE_BIOS;
-               return NULL;
-       } else if (!strcmp(str, "nobios")) {
-               pci_probe &= ~PCI_PROBE_BIOS;
-               return NULL;
-       } else if (!strcmp(str, "nosort")) {
-               pci_probe |= PCI_NO_SORT;
-               return NULL;
-       } else if (!strcmp(str, "biosirq")) {
-               pci_probe |= PCI_BIOS_IRQ_SCAN;
-               return NULL;
-       }
-#endif
-#ifdef CONFIG_PCI_DIRECT
-       else if (!strcmp(str, "conf1")) {
-               pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS;
-               return NULL;
-       }
-       else if (!strcmp(str, "conf2")) {
-               pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS;
-               return NULL;
-       }
-#endif
-#ifdef CONFIG_ACPI_PCI
-       else if (!strcmp(str, "noacpi")) {
-               pci_probe |= PCI_NO_ACPI_ROUTING;
-               return NULL;
-       }
-#endif
-       else if (!strcmp(str, "rom")) {
-               pci_probe |= PCI_ASSIGN_ROMS;
-               return NULL;
-       } else if (!strcmp(str, "assign-busses")) {
-               pci_probe |= PCI_ASSIGN_ALL_BUSSES;
-               return NULL;
-       } else if (!strcmp(str, "usepirqmask")) {
-               pci_probe |= PCI_USE_PIRQ_MASK;
-               return NULL;
-       } else if (!strncmp(str, "irqmask=", 8)) {
-               pcibios_irq_mask = simple_strtol(str+8, NULL, 0);
-               return NULL;
-       } else if (!strncmp(str, "lastbus=", 8)) {
-               pcibios_last_bus = simple_strtol(str+8, NULL, 0);
-               return NULL;
-       }
-       return str;
-}
-
-unsigned int pcibios_assign_all_busses(void)
-{
-       return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
-}
-
-int pcibios_enable_device(struct pci_dev *dev)
-{
-       int err;
-
-       if ((err = pcibios_enable_resources(dev)) < 0)
-               return err;
-       pcibios_enable_irq(dev);
-       return 0;
-}
diff --git a/arch/i386/kernel/pci/direct.c b/arch/i386/kernel/pci/direct.c
deleted file mode 100644 (file)
index 594a556..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * direct.c - Low-level direct PCI config space access
- */
-
-#include <linux/pci.h>
-#include "pci.h"
-
-/*
- * Functions for accessing PCI configuration space with type 1 accesses
- */
-
-#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
-       (0x80000000 | (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)
-{
-       unsigned long flags;
-
-       if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
-               return -EINVAL;
-
-       spin_lock_irqsave(&pci_config_lock, flags);
-
-       outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
-
-       switch (len) {
-       case 1:
-               *value = inb(0xCFC + (reg & 3));
-               break;
-       case 2:
-               *value = inw(0xCFC + (reg & 2));
-               break;
-       case 4:
-               *value = inl(0xCFC);
-               break;
-       }
-
-       spin_unlock_irqrestore(&pci_config_lock, flags);
-
-       return 0;
-}
-
-static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
-{
-       unsigned long flags;
-
-       if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
-               return -EINVAL;
-
-       spin_lock_irqsave(&pci_config_lock, flags);
-
-       outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
-
-       switch (len) {
-       case 1:
-               outb((u8)value, 0xCFC + (reg & 3));
-               break;
-       case 2:
-               outw((u16)value, 0xCFC + (reg & 2));
-               break;
-       case 4:
-               outl((u32)value, 0xCFC);
-               break;
-       }
-
-       spin_unlock_irqrestore(&pci_config_lock, flags);
-
-       return 0;
-}
-
-
-#undef PCI_CONF1_ADDRESS
-
-static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-       int result; 
-       u32 data;
-
-       if (!value) 
-               return -EINVAL;
-
-       result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 1, &data);
-
-       *value = (u8)data;
-
-       return result;
-}
-
-static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-       int result; 
-       u32 data;
-
-       if (!value) 
-               return -EINVAL;
-
-       result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 2, &data);
-
-       *value = (u16)data;
-
-       return result;
-}
-
-static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-       if (!value) 
-               return -EINVAL;
-
-       return pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 4, value);
-}
-
-static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-       return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 1, value);
-}
-
-static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-       return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 2, value);
-}
-
-static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-       return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 4, value);
-}
-
-static struct pci_ops pci_direct_conf1 = {
-       pci_conf1_read_config_byte,
-       pci_conf1_read_config_word,
-       pci_conf1_read_config_dword,
-       pci_conf1_write_config_byte,
-       pci_conf1_write_config_word,
-       pci_conf1_write_config_dword
-};
-
-
-/*
- * Functions for accessing PCI configuration space with type 2 accesses
- */
-
-#define PCI_CONF2_ADDRESS(dev, reg)    (u16)(0xC000 | (dev << 8) | reg)
-
-static int pci_conf2_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
-{
-       unsigned long flags;
-
-       if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
-               return -EINVAL;
-
-       if (dev & 0x10) 
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       spin_lock_irqsave(&pci_config_lock, flags);
-
-       outb((u8)(0xF0 | (fn << 1)), 0xCF8);
-       outb((u8)bus, 0xCFA);
-
-       switch (len) {
-       case 1:
-               *value = inb(PCI_CONF2_ADDRESS(dev, reg));
-               break;
-       case 2:
-               *value = inw(PCI_CONF2_ADDRESS(dev, reg));
-               break;
-       case 4:
-               *value = inl(PCI_CONF2_ADDRESS(dev, reg));
-               break;
-       }
-
-       outb (0, 0xCF8);
-
-       spin_unlock_irqrestore(&pci_config_lock, flags);
-
-       return 0;
-}
-
-static int pci_conf2_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
-{
-       unsigned long flags;
-
-       if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
-               return -EINVAL;
-
-       if (dev & 0x10) 
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       spin_lock_irqsave(&pci_config_lock, flags);
-
-       outb((u8)(0xF0 | (fn << 1)), 0xCF8);
-       outb((u8)bus, 0xCFA);
-
-       switch (len) {
-       case 1:
-               outb ((u8)value, PCI_CONF2_ADDRESS(dev, reg));
-               break;
-       case 2:
-               outw ((u16)value, PCI_CONF2_ADDRESS(dev, reg));
-               break;
-       case 4:
-               outl ((u32)value, PCI_CONF2_ADDRESS(dev, reg));
-               break;
-       }
-
-       outb (0, 0xCF8);    
-
-       spin_unlock_irqrestore(&pci_config_lock, flags);
-
-       return 0;
-}
-
-#undef PCI_CONF2_ADDRESS
-
-static int pci_conf2_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-       int result; 
-       u32 data;
-       result = pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 1, &data);
-       *value = (u8)data;
-       return result;
-}
-
-static int pci_conf2_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-       int result; 
-       u32 data;
-       result = pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 2, &data);
-       *value = (u16)data;
-       return result;
-}
-
-static int pci_conf2_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-       return pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 4, value);
-}
-
-static int pci_conf2_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-       return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 1, value);
-}
-
-static int pci_conf2_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-       return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 2, value);
-}
-
-static int pci_conf2_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-       return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 4, value);
-}
-
-static struct pci_ops pci_direct_conf2 = {
-       pci_conf2_read_config_byte,
-       pci_conf2_read_config_word,
-       pci_conf2_read_config_dword,
-       pci_conf2_write_config_byte,
-       pci_conf2_write_config_word,
-       pci_conf2_write_config_dword
-};
-
-
-/*
- * Before we decide to use direct hardware access mechanisms, we try to do some
- * trivial checks to ensure it at least _seems_ to be working -- we just test
- * whether bus 00 contains a host bridge (this is similar to checking
- * techniques used in XFree86, but ours should be more reliable since we
- * attempt to make use of direct access hints provided by the PCI BIOS).
- *
- * This should be close to trivial, but it isn't, because there are buggy
- * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
- */
-static int __devinit pci_sanity_check(struct pci_ops *o)
-{
-       u16 x;
-       struct pci_bus bus;             /* Fake bus and device */
-       struct pci_dev dev;
-
-       if (pci_probe & PCI_NO_CHECKS)
-               return 1;
-       bus.number = 0;
-       dev.bus = &bus;
-       for(dev.devfn=0; dev.devfn < 0x100; dev.devfn++)
-               if ((!o->read_word(&dev, PCI_CLASS_DEVICE, &x) &&
-                    (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) ||
-                   (!o->read_word(&dev, PCI_VENDOR_ID, &x) &&
-                    (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ)))
-                       return 1;
-       DBG("PCI: Sanity check failed\n");
-       return 0;
-}
-
-static struct pci_ops * __devinit pci_check_direct(void)
-{
-       unsigned int tmp;
-       unsigned long flags;
-
-       __save_flags(flags); __cli();
-
-       /*
-        * Check if configuration type 1 works.
-        */
-       if (pci_probe & PCI_PROBE_CONF1) {
-               outb (0x01, 0xCFB);
-               tmp = inl (0xCF8);
-               outl (0x80000000, 0xCF8);
-               if (inl (0xCF8) == 0x80000000 &&
-                   pci_sanity_check(&pci_direct_conf1)) {
-                       outl (tmp, 0xCF8);
-                       __restore_flags(flags);
-                       printk(KERN_INFO "PCI: Using configuration type 1\n");
-                       if (!request_region(0xCF8, 8, "PCI conf1"))
-                               return NULL;
-                       return &pci_direct_conf1;
-               }
-               outl (tmp, 0xCF8);
-       }
-
-       /*
-        * Check if configuration type 2 works.
-        */
-       if (pci_probe & PCI_PROBE_CONF2) {
-               outb (0x00, 0xCFB);
-               outb (0x00, 0xCF8);
-               outb (0x00, 0xCFA);
-               if (inb (0xCF8) == 0x00 && inb (0xCFA) == 0x00 &&
-                   pci_sanity_check(&pci_direct_conf2)) {
-                       __restore_flags(flags);
-                       printk(KERN_INFO "PCI: Using configuration type 2\n");
-                       if (!request_region(0xCF8, 4, "PCI conf2"))
-                               return NULL;
-                       return &pci_direct_conf2;
-               }
-       }
-
-       __restore_flags(flags);
-       return NULL;
-}
-
-static int __init pci_direct_init(void)
-{
-       if ((pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2)) 
-               && (pci_root_ops = pci_check_direct())) {
-               if (pci_root_ops == &pci_direct_conf1) {
-                       pci_config_read = pci_conf1_read;
-                       pci_config_write = pci_conf1_write;
-               }
-               else {
-                       pci_config_read = pci_conf2_read;
-                       pci_config_write = pci_conf2_write;
-               }
-       }
-       return 0;
-}
-
-subsys_initcall(pci_direct_init);
diff --git a/arch/i386/kernel/pci/dma.c b/arch/i386/kernel/pci/dma.c
deleted file mode 100644 (file)
index 2031b85..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Dynamic DMA mapping support.
- *
- * On i386 there is no hardware dynamic DMA address translation,
- * so consistent alloc/free are merely page allocation/freeing.
- * The rest of the dynamic DMA mapping interface is implemented
- * in asm/pci.h.
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-                          dma_addr_t *dma_handle)
-{
-       void *ret;
-       int gfp = GFP_ATOMIC;
-
-       if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
-               gfp |= GFP_DMA;
-       ret = (void *)__get_free_pages(gfp, get_order(size));
-
-       if (ret != NULL) {
-               memset(ret, 0, size);
-               *dma_handle = virt_to_phys(ret);
-       }
-       return ret;
-}
-
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
-                        void *vaddr, dma_addr_t dma_handle)
-{
-       free_pages((unsigned long)vaddr, get_order(size));
-}
diff --git a/arch/i386/kernel/pci/fixup.c b/arch/i386/kernel/pci/fixup.c
deleted file mode 100644 (file)
index ca14f00..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Exceptions for specific devices. Usually work-arounds for fatal design flaws.
- */
-
-#include <linux/pci.h>
-#include "pci.h"
-
-
-static void __devinit pci_fixup_i450nx(struct pci_dev *d)
-{
-       /*
-        * i450NX -- Find and scan all secondary buses on all PXB's.
-        */
-       int pxb, reg;
-       u8 busno, suba, subb;
-
-       printk(KERN_WARNING "PCI: Searching for i450NX host bridges on %s\n", d->slot_name);
-       reg = 0xd0;
-       for(pxb=0; pxb<2; pxb++) {
-               pci_read_config_byte(d, reg++, &busno);
-               pci_read_config_byte(d, reg++, &suba);
-               pci_read_config_byte(d, reg++, &subb);
-               DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
-               if (busno)
-                       pci_scan_bus(busno, pci_root_ops, NULL);        /* Bus A */
-               if (suba < subb)
-                       pci_scan_bus(suba+1, pci_root_ops, NULL);       /* Bus B */
-       }
-       pcibios_last_bus = -1;
-}
-
-static void __devinit pci_fixup_i450gx(struct pci_dev *d)
-{
-       /*
-        * i450GX and i450KX -- Find and scan all secondary buses.
-        * (called separately for each PCI bridge found)
-        */
-       u8 busno;
-       pci_read_config_byte(d, 0x4a, &busno);
-       printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", d->slot_name, busno);
-       pci_scan_bus(busno, pci_root_ops, NULL);
-       pcibios_last_bus = -1;
-}
-
-static void __devinit  pci_fixup_umc_ide(struct pci_dev *d)
-{
-       /*
-        * UM8886BF IDE controller sets region type bits incorrectly,
-        * therefore they look like memory despite of them being I/O.
-        */
-       int i;
-
-       printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", d->slot_name);
-       for(i=0; i<4; i++)
-               d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
-}
-
-static void __devinit  pci_fixup_ncr53c810(struct pci_dev *d)
-{
-       /*
-        * NCR 53C810 returns class code 0 (at least on some systems).
-        * Fix class to be PCI_CLASS_STORAGE_SCSI
-        */
-       if (!d->class) {
-               printk(KERN_WARNING "PCI: fixing NCR 53C810 class code for %s\n", d->slot_name);
-               d->class = PCI_CLASS_STORAGE_SCSI << 8;
-       }
-}
-
-static void __devinit pci_fixup_ide_bases(struct pci_dev *d)
-{
-       int i;
-
-       /*
-        * PCI IDE controllers use non-standard I/O port decoding, respect it.
-        */
-       if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
-               return;
-       DBG("PCI: IDE base address fixup for %s\n", d->slot_name);
-       for(i=0; i<4; i++) {
-               struct resource *r = &d->resource[i];
-               if ((r->start & ~0x80) == 0x374) {
-                       r->start |= 2;
-                       r->end = r->start;
-               }
-       }
-}
-
-static void __devinit  pci_fixup_ide_trash(struct pci_dev *d)
-{
-       int i;
-
-       /*
-        * There exist PCI IDE controllers which have utter garbage
-        * in first four base registers. Ignore that.
-        */
-       DBG("PCI: IDE base address trash cleared for %s\n", d->slot_name);
-       for(i=0; i<4; i++)
-               d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0;
-}
-
-static void __devinit  pci_fixup_latency(struct pci_dev *d)
-{
-       /*
-        *  SiS 5597 and 5598 chipsets require latency timer set to
-        *  at most 32 to avoid lockups.
-        */
-       DBG("PCI: Setting max latency to 32\n");
-       pcibios_max_latency = 32;
-}
-
-static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d)
-{
-       /*
-        * PIIX4 ACPI device: hardwired IRQ9
-        */
-       d->irq = 9;
-}
-
-/*
- * Addresses issues with problems in the memory write queue timer in
- * certain VIA Northbridges.  This bugfix is per VIA's specifications.
- *
- * VIA 8363,8622,8361 Northbridges:
- *  - bits  5, 6, 7 at offset 0x55 need to be turned off
- * VIA 8367 (KT266x) Northbridges:
- *  - bits  5, 6, 7 at offset 0x95 need to be turned off
- */
-static void __init pci_fixup_via_northbridge_bug(struct pci_dev *d)
-{
-       u8 v;
-       int where = 0x55;
-
-       if (d->device == PCI_DEVICE_ID_VIA_8367_0) {
-               where = 0x95; /* the memory write queue timer register is 
-                                 different for the kt266x's: 0x95 not 0x55 */
-       }
-
-        pci_read_config_byte(d, where, &v);
-       if (v & 0xe0) {
-               printk(KERN_WARNING "Disabling broken memory write queue: [%02x] %02x->%02x\n",
-                       where, v, v & 0x1f);
-               v &= 0x1f; /* clear bits 5, 6, 7 */
-               pci_write_config_byte(d, where, v);
-       }
-}
-
-struct pci_fixup pcibios_fixups[] = {
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82451NX,    pci_fixup_i450nx },
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82454GX,    pci_fixup_i450gx },
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_UMC,      PCI_DEVICE_ID_UMC_UM8886BF,     pci_fixup_umc_ide },
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_SI,       PCI_DEVICE_ID_SI_5513,          pci_fixup_ide_trash },
-       { PCI_FIXUP_HEADER,     PCI_ANY_ID,             PCI_ANY_ID,                     pci_fixup_ide_bases },
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_SI,       PCI_DEVICE_ID_SI_5597,          pci_fixup_latency },
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_SI,       PCI_DEVICE_ID_SI_5598,          pci_fixup_latency },
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82371AB_3,  pci_fixup_piix4_acpi },
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_8363_0,       pci_fixup_via_northbridge_bug },
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_8622,         pci_fixup_via_northbridge_bug },
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_8361,         pci_fixup_via_northbridge_bug },
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_8367_0,       pci_fixup_via_northbridge_bug },
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_NCR,      PCI_DEVICE_ID_NCR_53C810,       pci_fixup_ncr53c810 },
-       { 0 }
-};
diff --git a/arch/i386/kernel/pci/i386.c b/arch/i386/kernel/pci/i386.c
deleted file mode 100644 (file)
index 27a14f0..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- *     Low-Level PCI Access for i386 machines
- *
- * Copyright 1993, 1994 Drew Eckhardt
- *      Visionary Computing
- *      (Unix and Linux consulting and custom programming)
- *      Drew@Colorado.EDU
- *      +1 (303) 786-7975
- *
- * Drew's work was sponsored by:
- *     iX Multiuser Multitasking Magazine
- *     Hannover, Germany
- *     hm@ix.de
- *
- * Copyright 1997--2000 Martin Mares <mj@ucw.cz>
- *
- * For more information, please consult the following manuals (look at
- * http://www.pcisig.com/ for how to get them):
- *
- * PCI BIOS Specification
- * PCI Local Bus Specification
- * PCI to PCI Bridge Specification
- * PCI System Design Guide
- *
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/errno.h>
-
-#include "pci.h"
-
-void
-pcibios_update_resource(struct pci_dev *dev, struct resource *root,
-                       struct resource *res, int resource)
-{
-       u32 new, check;
-       int reg;
-
-       new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
-       if (resource < 6) {
-               reg = PCI_BASE_ADDRESS_0 + 4*resource;
-       } else if (resource == PCI_ROM_RESOURCE) {
-               res->flags |= PCI_ROM_ADDRESS_ENABLE;
-               new |= PCI_ROM_ADDRESS_ENABLE;
-               reg = dev->rom_base_reg;
-       } else {
-               /* Somebody might have asked allocation of a non-standard resource */
-               return;
-       }
-       
-       pci_write_config_dword(dev, reg, new);
-       pci_read_config_dword(dev, reg, &check);
-       if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
-               printk(KERN_ERR "PCI: Error while updating region "
-                      "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
-                      new, check);
-       }
-}
-
-/*
- * We need to avoid collisions with `mirrored' VGA ports
- * and other strange ISA hardware, so we always want the
- * addresses to be allocated in the 0x000-0x0ff region
- * modulo 0x400.
- *
- * Why? Because some silly external IO cards only decode
- * the low 10 bits of the IO address. The 0x00-0xff region
- * is reserved for motherboard devices that decode all 16
- * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
- * but we want to try to avoid allocating at 0x2900-0x2bff
- * which might have be mirrored at 0x0100-0x03ff..
- */
-void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size)
-{
-       if (res->flags & IORESOURCE_IO) {
-               unsigned long start = res->start;
-
-               if (start & 0x300) {
-                       start = (start + 0x3ff) & ~0x3ff;
-                       res->start = start;
-               }
-       }
-}
-
-
-/*
- *  Handle resources of PCI devices.  If the world were perfect, we could
- *  just allocate all the resource regions and do nothing more.  It isn't.
- *  On the other hand, we cannot just re-allocate all devices, as it would
- *  require us to know lots of host bridge internals.  So we attempt to
- *  keep as much of the original configuration as possible, but tweak it
- *  when it's found to be wrong.
- *
- *  Known BIOS problems we have to work around:
- *     - I/O or memory regions not configured
- *     - regions configured, but not enabled in the command register
- *     - bogus I/O addresses above 64K used
- *     - expansion ROMs left enabled (this may sound harmless, but given
- *       the fact the PCI specs explicitly allow address decoders to be
- *       shared between expansion ROMs and other resource regions, it's
- *       at least dangerous)
- *
- *  Our solution:
- *     (1) Allocate resources for all buses behind PCI-to-PCI bridges.
- *         This gives us fixed barriers on where we can allocate.
- *     (2) Allocate resources for all enabled devices.  If there is
- *         a collision, just mark the resource as unallocated. Also
- *         disable expansion ROMs during this step.
- *     (3) Try to allocate resources for disabled devices.  If the
- *         resources were assigned correctly, everything goes well,
- *         if they weren't, they won't disturb allocation of other
- *         resources.
- *     (4) Assign new addresses to resources which were either
- *         not configured at all or misconfigured.  If explicitly
- *         requested by the user, configure expansion ROM address
- *         as well.
- */
-
-static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
-{
-       struct list_head *ln;
-       struct pci_bus *bus;
-       struct pci_dev *dev;
-       int idx;
-       struct resource *r, *pr;
-
-       /* Depth-First Search on bus tree */
-       for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
-               bus = pci_bus_b(ln);
-               if ((dev = bus->self)) {
-                       for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
-                               r = &dev->resource[idx];
-                               if (!r->start)
-                                       continue;
-                               pr = pci_find_parent_resource(dev, r);
-                               if (!pr || request_resource(pr, r) < 0)
-                                       printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
-                       }
-               }
-               pcibios_allocate_bus_resources(&bus->children);
-       }
-}
-
-static void __init pcibios_allocate_resources(int pass)
-{
-       struct pci_dev *dev;
-       int idx, disabled;
-       u16 command;
-       struct resource *r, *pr;
-
-       pci_for_each_dev(dev) {
-               pci_read_config_word(dev, PCI_COMMAND, &command);
-               for(idx = 0; idx < 6; idx++) {
-                       r = &dev->resource[idx];
-                       if (r->parent)          /* Already allocated */
-                               continue;
-                       if (!r->start)          /* Address not assigned at all */
-                               continue;
-                       if (r->flags & IORESOURCE_IO)
-                               disabled = !(command & PCI_COMMAND_IO);
-                       else
-                               disabled = !(command & PCI_COMMAND_MEMORY);
-                       if (pass == disabled) {
-                               DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
-                                   r->start, r->end, r->flags, disabled, pass);
-                               pr = pci_find_parent_resource(dev, r);
-                               if (!pr || request_resource(pr, r) < 0) {
-                                       printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name);
-                                       /* We'll assign a new address later */
-                                       r->end -= r->start;
-                                       r->start = 0;
-                               }
-                       }
-               }
-               if (!pass) {
-                       r = &dev->resource[PCI_ROM_RESOURCE];
-                       if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
-                               /* Turn the ROM off, leave the resource region, but keep it unregistered. */
-                               u32 reg;
-                               DBG("PCI: Switching off ROM of %s\n", dev->slot_name);
-                               r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
-                               pci_read_config_dword(dev, dev->rom_base_reg, &reg);
-                               pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
-                       }
-               }
-       }
-}
-
-static void __init pcibios_assign_resources(void)
-{
-       struct pci_dev *dev;
-       int idx;
-       struct resource *r;
-
-       pci_for_each_dev(dev) {
-               int class = dev->class >> 8;
-
-               /* Don't touch classless devices and host bridges */
-               if (!class || class == PCI_CLASS_BRIDGE_HOST)
-                       continue;
-
-               for(idx=0; idx<6; idx++) {
-                       r = &dev->resource[idx];
-
-                       /*
-                        *  Don't touch IDE controllers and I/O ports of video cards!
-                        */
-                       if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
-                           (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
-                               continue;
-
-                       /*
-                        *  We shall assign a new address to this resource, either because
-                        *  the BIOS forgot to do so or because we have decided the old
-                        *  address was unusable for some reason.
-                        */
-                       if (!r->start && r->end)
-                               pci_assign_resource(dev, idx);
-               }
-
-               if (pci_probe & PCI_ASSIGN_ROMS) {
-                       r = &dev->resource[PCI_ROM_RESOURCE];
-                       r->end -= r->start;
-                       r->start = 0;
-                       if (r->end)
-                               pci_assign_resource(dev, PCI_ROM_RESOURCE);
-               }
-       }
-}
-
-void __init pcibios_resource_survey(void)
-{
-       DBG("PCI: Allocating resources\n");
-       pcibios_allocate_bus_resources(&pci_root_buses);
-       pcibios_allocate_resources(0);
-       pcibios_allocate_resources(1);
-       pcibios_assign_resources();
-}
-
-int pcibios_enable_resources(struct pci_dev *dev)
-{
-       u16 cmd, old_cmd;
-       int idx;
-       struct resource *r;
-
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
-       old_cmd = cmd;
-       for(idx=0; idx<6; idx++) {
-               r = &dev->resource[idx];
-               if (!r->start && r->end) {
-                       printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
-                       return -EINVAL;
-               }
-               if (r->flags & IORESOURCE_IO)
-                       cmd |= PCI_COMMAND_IO;
-               if (r->flags & IORESOURCE_MEM)
-                       cmd |= PCI_COMMAND_MEMORY;
-       }
-       if (dev->resource[PCI_ROM_RESOURCE].start)
-               cmd |= PCI_COMMAND_MEMORY;
-       if (cmd != old_cmd) {
-               printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
-               pci_write_config_word(dev, PCI_COMMAND, cmd);
-       }
-       return 0;
-}
-
-/*
- *  If we set up a device for bus mastering, we need to check the latency
- *  timer as certain crappy BIOSes forget to set it properly.
- */
-unsigned int pcibios_max_latency = 255;
-
-void pcibios_set_master(struct pci_dev *dev)
-{
-       u8 lat;
-       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
-       if (lat < 16)
-               lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
-       else if (lat > pcibios_max_latency)
-               lat = pcibios_max_latency;
-       else
-               return;
-       printk("PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
-}
-
-int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
-                       enum pci_mmap_state mmap_state, int write_combine)
-{
-       unsigned long prot;
-
-       /* I/O space cannot be accessed via normal processor loads and
-        * stores on this platform.
-        */
-       if (mmap_state == pci_mmap_io)
-               return -EINVAL;
-
-       /* Leave vm_pgoff as-is, the PCI space address is the physical
-        * address on this platform.
-        */
-       vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
-
-       prot = pgprot_val(vma->vm_page_prot);
-       if (boot_cpu_data.x86 > 3)
-               prot |= _PAGE_PCD | _PAGE_PWT;
-       vma->vm_page_prot = __pgprot(prot);
-
-       /* Write-combine setting is ignored, it is changed via the mtrr
-        * interfaces on this platform.
-        */
-       if (remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
-                            vma->vm_end - vma->vm_start,
-                            vma->vm_page_prot))
-               return -EAGAIN;
-
-       return 0;
-}
diff --git a/arch/i386/kernel/pci/irq.c b/arch/i386/kernel/pci/irq.c
deleted file mode 100644 (file)
index 68eb183..0000000
+++ /dev/null
@@ -1,810 +0,0 @@
-/*
- *     Low-Level PCI Support for PC -- Routing of Interrupts
- *
- *     (c) 1999--2000 Martin Mares <mj@ucw.cz>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/acpi.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/io_apic.h>
-
-#include "pci.h"
-
-#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
-#define PIRQ_VERSION 0x0100
-
-int pci_use_acpi_routing = 0;
-int broken_hp_bios_irq9;
-
-static struct irq_routing_table *pirq_table;
-
-/*
- * Never use: 0, 1, 2 (timer, keyboard, and cascade)
- * Avoid using: 13, 14 and 15 (FP error and IDE).
- * Penalize: 3, 4, 6, 7, 12 (known ISA uses: serial, floppy, parallel and mouse)
- */
-unsigned int pcibios_irq_mask = 0xfff8;
-
-static int pirq_penalty[16] = {
-       1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000,
-       0, 0, 0, 0, 1000, 100000, 100000, 100000
-};
-
-struct irq_router {
-       char *name;
-       u16 vendor, device;
-       int (*get)(struct pci_dev *router, struct pci_dev *dev, int pirq);
-       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.
- */
-
-static struct irq_routing_table * __init pirq_find_routing_table(void)
-{
-       u8 *addr;
-       struct irq_routing_table *rt;
-       int i;
-       u8 sum;
-
-       for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
-               rt = (struct irq_routing_table *) addr;
-               if (rt->signature != PIRQ_SIGNATURE ||
-                   rt->version != PIRQ_VERSION ||
-                   rt->size % 16 ||
-                   rt->size < sizeof(struct irq_routing_table))
-                       continue;
-               sum = 0;
-               for(i=0; i<rt->size; i++)
-                       sum += addr[i];
-               if (!sum) {
-                       DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt);
-                       return rt;
-               }
-       }
-       return NULL;
-}
-
-/*
- *  If we have a IRQ routing table, use it to search for peer host
- *  bridges.  It's a gross hack, but since there are no other known
- *  ways how to get a list of buses, we have to go this way.
- */
-
-static void __init pirq_peer_trick(void)
-{
-       struct irq_routing_table *rt = pirq_table;
-       u8 busmap[256];
-       int i;
-       struct irq_info *e;
-
-       memset(busmap, 0, sizeof(busmap));
-       for(i=0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) {
-               e = &rt->slots[i];
-#ifdef DEBUG
-               {
-                       int j;
-                       DBG("%02x:%02x slot=%02x", e->bus, e->devfn/8, e->slot);
-                       for(j=0; j<4; j++)
-                               DBG(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap);
-                       DBG("\n");
-               }
-#endif
-               busmap[e->bus] = 1;
-       }
-       for(i=1; i<256; i++)
-               /*
-                *  It might be a secondary bus, but in this case its parent is already
-                *  known (ascending bus order) and therefore pci_scan_bus returns immediately.
-                */
-               if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL))
-                       printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i);
-       pcibios_last_bus = -1;
-}
-
-/*
- *  Code for querying and setting of IRQ routes on various interrupt routers.
- */
-
-void eisa_set_level_irq(unsigned int irq)
-{
-       unsigned char mask = 1 << (irq & 7);
-       unsigned int port = 0x4d0 + (irq >> 3);
-       unsigned char val = inb(port);
-
-       if (!(val & mask)) {
-               DBG(" -> edge");
-               outb(val | mask, port);
-       }
-}
-
-/*
- * Common IRQ routing practice: nybbles in config space,
- * offset by some magic constant.
- */
-static unsigned int read_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr)
-{
-       u8 x;
-       unsigned reg = offset + (nr >> 1);
-
-       pci_read_config_byte(router, reg, &x);
-       return (nr & 1) ? (x >> 4) : (x & 0xf);
-}
-
-static void write_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr, unsigned int val)
-{
-       u8 x;
-       unsigned reg = offset + (nr >> 1);
-
-       pci_read_config_byte(router, reg, &x);
-       x = (nr & 1) ? ((x & 0x0f) | (val << 4)) : ((x & 0xf0) | val);
-       pci_write_config_byte(router, reg, x);
-}
-
-/*
- * ALI pirq entries are damn ugly, and completely undocumented.
- * This has been figured out from pirq tables, and it's not a pretty
- * picture.
- */
-static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-       static unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
-
-       return irqmap[read_config_nybble(router, 0x48, pirq-1)];
-}
-
-static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-       static unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
-       unsigned int val = irqmap[irq];
-               
-       if (val) {
-               write_config_nybble(router, 0x48, pirq-1, val);
-               return 1;
-       }
-       return 0;
-}
-
-/*
- * The Intel PIIX4 pirq rules are fairly simple: "pirq" is
- * just a pointer to the config space.
- */
-static int pirq_piix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-       u8 x;
-
-       pci_read_config_byte(router, pirq, &x);
-       return (x < 16) ? x : 0;
-}
-
-static int pirq_piix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-       pci_write_config_byte(router, pirq, irq);
-       return 1;
-}
-
-/*
- * The VIA pirq rules are nibble-based, like ALI,
- * but without the ugly irq number munging.
- */
-static int pirq_via_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-       return read_config_nybble(router, 0x55, pirq);
-}
-
-static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-       write_config_nybble(router, 0x55, pirq, irq);
-       return 1;
-}
-
-/*
- * ITE 8330G pirq rules are nibble-based
- * FIXME: pirqmap may be { 1, 0, 3, 2 },
- *       2+3 are both mapped to irq 9 on my system
- */
-static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-       static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
-       return read_config_nybble(router,0x43, pirqmap[pirq-1]);
-}
-
-static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-       static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
-       write_config_nybble(router, 0x43, pirqmap[pirq-1], irq);
-       return 1;
-}
-
-/*
- * OPTI: high four bits are nibble pointer..
- * I wonder what the low bits do?
- */
-static int pirq_opti_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-       return read_config_nybble(router, 0xb8, pirq >> 4);
-}
-
-static int pirq_opti_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-       write_config_nybble(router, 0xb8, pirq >> 4, irq);
-       return 1;
-}
-
-/*
- * Cyrix: nibble offset 0x5C
- */
-static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-       return read_config_nybble(router, 0x5C, (pirq-1)^1);
-}
-
-static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-       write_config_nybble(router, 0x5C, (pirq-1)^1, irq);
-       return 1;
-}
-
-/*
- *     PIRQ routing for SiS 85C503 router used in several SiS chipsets
- *     According to the SiS 5595 datasheet (preliminary V1.0, 12/24/1997)
- *     the related registers work as follows:
- *     
- *     general: one byte per re-routable IRQ,
- *              bit 7      IRQ mapping enabled (0) or disabled (1)
- *              bits [6:4] reserved
- *              bits [3:0] IRQ to map to
- *                  allowed: 3-7, 9-12, 14-15
- *                  reserved: 0, 1, 2, 8, 13
- *
- *     individual registers in device config space:
- *
- *     0x41/0x42/0x43/0x44:    PCI INT A/B/C/D - bits as in general case
- *
- *     0x61:                   IDEIRQ: bits as in general case - but:
- *                             bits [6:5] must be written 01
- *                             bit 4 channel-select primary (0), secondary (1)
- *
- *     0x62:                   USBIRQ: bits as in general case - but:
- *                             bit 4 OHCI function disabled (0), enabled (1)
- *     
- *     0x6a:                   ACPI/SCI IRQ - bits as in general case
- *
- *     0x7e:                   Data Acq. Module IRQ - bits as in general case
- *
- *     Apparently there are systems implementing PCI routing table using both
- *     link values 0x01-0x04 and 0x41-0x44 for PCI INTA..D, but register offsets
- *     like 0x62 as link values for USBIRQ e.g. So there is no simple
- *     "register = offset + pirq" relation.
- *     Currently we support PCI INTA..D and USBIRQ and try our best to handle
- *     both link mappings.
- *     IDE/ACPI/DAQ mapping is currently unsupported (left untouched as set by BIOS).
- */
-
-static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-       u8 x;
-       int reg = pirq;
-
-       switch(pirq) {
-               case 0x01:
-               case 0x02:
-               case 0x03:
-               case 0x04:
-                       reg += 0x40;
-               case 0x41:
-               case 0x42:
-               case 0x43:
-               case 0x44:
-               case 0x62:
-                       pci_read_config_byte(router, reg, &x);
-                       if (reg != 0x62)
-                               break;
-                       if (!(x & 0x40))
-                               return 0;
-                       break;
-               case 0x61:
-               case 0x6a:
-               case 0x7e:
-                       printk(KERN_INFO "SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n");
-                       return 0;
-               default:                        
-                       printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
-                       return 0;
-       }
-       return (x & 0x80) ? 0 : (x & 0x0f);
-}
-
-static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-       u8 x;
-       int reg = pirq;
-
-       switch(pirq) {
-               case 0x01:
-               case 0x02:
-               case 0x03:
-               case 0x04:
-                       reg += 0x40;
-               case 0x41:
-               case 0x42:
-               case 0x43:
-               case 0x44:
-               case 0x62:
-                       x = (irq&0x0f) ? (irq&0x0f) : 0x80;
-                       if (reg != 0x62)
-                               break;
-                       /* always mark OHCI enabled, as nothing else knows about this */
-                       x |= 0x40;
-                       break;
-               case 0x61:
-               case 0x6a:
-               case 0x7e:
-                       printk(KERN_INFO "advanced SiS pirq mapping not yet implemented\n");
-                       return 0;
-               default:                        
-                       printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
-                       return 0;
-       }
-       pci_write_config_byte(router, reg, x);
-
-       return 1;
-}
-
-/*
- * VLSI: nibble offset 0x74 - educated guess due to routing table and
- *       config space of VLSI 82C534 PCI-bridge/router (1004:0102)
- *       Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard
- *       devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6
- *       for the busbridge to the docking station.
- */
-
-static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-       if (pirq > 8) {
-               printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
-               return 0;
-       }
-       return read_config_nybble(router, 0x74, pirq-1);
-}
-
-static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-       if (pirq > 8) {
-               printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
-               return 0;
-       }
-       write_config_nybble(router, 0x74, pirq-1, irq);
-       return 1;
-}
-
-/*
- * ServerWorks: PCI interrupts mapped to system IRQ lines through Index
- * and Redirect I/O registers (0x0c00 and 0x0c01).  The Index register
- * format is (PCIIRQ## | 0x10), e.g.: PCIIRQ10=0x1a.  The Redirect
- * register is a straight binary coding of desired PIC IRQ (low nibble).
- *
- * The 'link' value in the PIRQ table is already in the correct format
- * for the Index register.  There are some special index values:
- * 0x00 for ACPI (SCI), 0x01 for USB, 0x02 for IDE0, 0x04 for IDE1,
- * and 0x03 for SMBus.
- */
-static int pirq_serverworks_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-       outb_p(pirq, 0xc00);
-       return inb(0xc01) & 0xf;
-}
-
-static int pirq_serverworks_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-       outb_p(pirq, 0xc00);
-       outb_p(irq, 0xc01);
-       return 1;
-}
-
-/* Support for AMD756 PCI IRQ Routing
- * Jhon H. Caicedo <jhcaiced@osso.org.co>
- * Jun/21/2001 0.2.0 Release, fixed to use "nybble" functions... (jhcaiced)
- * Jun/19/2001 Alpha Release 0.1.0 (jhcaiced)
- * The AMD756 pirq rules are nibble-based
- * offset 0x56 0-3 PIRQA  4-7  PIRQB
- * offset 0x57 0-3 PIRQC  4-7  PIRQD
- */
-static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
-{
-       u8 irq;
-       irq = 0;
-       if (pirq <= 4)
-       {
-               irq = read_config_nybble(router, 0x56, pirq - 1);
-       }
-       printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n",
-               dev->vendor, dev->device, pirq, irq);
-       return irq;
-}
-
-static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-       printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n", 
-               dev->vendor, dev->device, pirq, irq);
-       if (pirq <= 4)
-       {
-               write_config_nybble(router, 0x56, pirq - 1, irq);
-       }
-       return 1;
-}
-
-#ifdef CONFIG_PCI_BIOS
-
-static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
-{
-       struct pci_dev *bridge;
-       int pin = pci_get_interrupt_pin(dev, &bridge);
-       return pcibios_set_irq_routing(bridge, pin, irq);
-}
-
-static struct irq_router pirq_bios_router =
-       { "BIOS", 0, 0, NULL, pirq_bios_set };
-
-#endif
-
-static struct irq_router pirq_routers[] = {
-       { "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_82371MX,   pirq_piix_get, pirq_piix_set },
-       { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
-       { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, pirq_piix_get, pirq_piix_set },
-       { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, pirq_piix_get, pirq_piix_set },
-       { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set },
-       { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, pirq_piix_get, pirq_piix_set },
-       { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, pirq_piix_get, pirq_piix_set },
-       { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, pirq_piix_get, pirq_piix_set },
-
-       { "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
-
-       { "ITE", PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8330G_0, pirq_ite_get, pirq_ite_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 },
-       { "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, pirq_via_get, pirq_via_set },
-
-       { "OPTI", PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C700, pirq_opti_get, pirq_opti_set },
-
-       { "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set },
-       { "SIS", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, pirq_sis_get, pirq_sis_set },
-       { "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set },
-       { "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4,
-         pirq_serverworks_get, pirq_serverworks_set },
-       { "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5,
-         pirq_serverworks_get, pirq_serverworks_set },
-       { "AMD756 VIPER", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B,
-               pirq_amd756_get, pirq_amd756_set },
-
-       { "default", 0, 0, NULL, NULL }
-};
-
-static struct irq_router *pirq_router;
-static struct pci_dev *pirq_router_dev;
-
-static void __init pirq_find_router(void)
-{
-       struct irq_routing_table *rt = pirq_table;
-       struct irq_router *r;
-
-#ifdef CONFIG_PCI_BIOS
-       if (!rt->signature) {
-               printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n");
-               pirq_router = &pirq_bios_router;
-               return;
-       }
-#endif
-
-       DBG("PCI: Attempting to find IRQ router for %04x:%04x\n",
-           rt->rtr_vendor, rt->rtr_device);
-
-       /* fall back to default router if nothing else found */
-       pirq_router = &pirq_routers[ARRAY_SIZE(pirq_routers) - 1];
-
-       pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn);
-       if (!pirq_router_dev) {
-               DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
-               return;
-       }
-
-       for(r=pirq_routers; r->vendor; r++) {
-               /* Exact match against router table entry? Use it! */
-               if (r->vendor == rt->rtr_vendor && r->device == rt->rtr_device) {
-                       pirq_router = r;
-                       break;
-               }
-               /* Match against router device entry? Use it as a fallback */
-               if (r->vendor == pirq_router_dev->vendor && r->device == pirq_router_dev->device) {
-                       pirq_router = r;
-               }
-       }
-       printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n",
-               pirq_router->name,
-               pirq_router_dev->vendor,
-               pirq_router_dev->device,
-               pirq_router_dev->slot_name);
-}
-
-static struct irq_info *pirq_get_info(struct pci_dev *dev)
-{
-       struct irq_routing_table *rt = pirq_table;
-       int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
-       struct irq_info *info;
-
-       for (info = rt->slots; entries--; info++)
-               if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn))
-                       return info;
-       return NULL;
-}
-
-static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
-}
-
-static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
-{
-       u8 pin;
-       struct irq_info *info;
-       int i, pirq, newirq;
-       int irq = 0;
-       u32 mask;
-       struct irq_router *r = pirq_router;
-       struct pci_dev *dev2;
-       char *msg = NULL;
-
-       /* Find IRQ pin */
-       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-       if (!pin) {
-               DBG(" -> no interrupt pin\n");
-               return 0;
-       }
-       pin = pin - 1;
-
-       /* Find IRQ routing entry */
-
-       if (!pirq_table)
-               return 0;
-       
-       DBG("IRQ for %s:%d", dev->slot_name, pin);
-       info = pirq_get_info(dev);
-       if (!info) {
-               DBG(" -> not found in routing table\n");
-               return 0;
-       }
-       pirq = info->irq[pin].link;
-       mask = info->irq[pin].bitmap;
-       if (!pirq) {
-               DBG(" -> not routed\n");
-               return 0;
-       }
-       DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
-       mask &= pcibios_irq_mask;
-
-       /* Work around broken HP Pavilion Notebooks which assign USB to
-          IRQ 9 even though it is actually wired to IRQ 11 */
-
-       if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) {
-               dev->irq = 11;
-               pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
-               r->set(pirq_router_dev, dev, pirq, 11);
-       }
-
-       /*
-        * Find the best IRQ to assign: use the one
-        * reported by the device if possible.
-        */
-       newirq = dev->irq;
-       if (!((1 << newirq) & mask)) {
-               if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0;
-               else printk(KERN_WARNING "PCI: IRQ %i for device %s doesn't match PIRQ mask - try pci=usepirqmask\n", newirq, dev->slot_name);
-       }
-       if (!newirq && 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);
-
-       /* Check if it is hardcoded */
-       if ((pirq & 0xf0) == 0xf0) {
-               irq = pirq & 0xf;
-               DBG(" -> hardcoded IRQ %d\n", irq);
-               msg = "Hardcoded";
-       } else if ( r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \
-       ((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask)) ) {
-               DBG(" -> got IRQ %d\n", irq);
-               msg = "Found";
-       } else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
-               DBG(" -> assigning IRQ %d", newirq);
-               if (r->set(pirq_router_dev, dev, pirq, newirq)) {
-                       eisa_set_level_irq(newirq);
-                       DBG(" ... OK\n");
-                       msg = "Assigned";
-                       irq = newirq;
-               }
-       }
-
-       if (!irq) {
-               DBG(" ... failed\n");
-               if (newirq && mask == (1 << newirq)) {
-                       msg = "Guessed";
-                       irq = newirq;
-               } else
-                       return 0;
-       }
-       printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name);
-
-       /* Update IRQ for all devices with the same pirq value */
-       pci_for_each_dev(dev2) {
-               pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin);
-               if (!pin)
-                       continue;
-               pin--;
-               info = pirq_get_info(dev2);
-               if (!info)
-                       continue;
-               if (info->irq[pin].link == pirq) {
-                       /* We refuse to override the dev->irq information. Give a warning! */
-                       if ( dev2->irq && dev2->irq != irq && \
-                       (!(pci_probe & PCI_USE_PIRQ_MASK) || \
-                       ((1 << dev2->irq) & mask)) ) {
-                               printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n",
-                                      dev2->slot_name, dev2->irq, irq);
-                               continue;
-                       }
-                       dev2->irq = irq;
-                       pirq_penalty[irq]++;
-                       if (dev != dev2)
-                               printk(KERN_INFO "PCI: Sharing IRQ %d with %s\n", irq, dev2->slot_name);
-               }
-       }
-       return 1;
-}
-
-static int __init pcibios_irq_init(void)
-{
-       DBG("PCI: IRQ init\n");
-
-       if (pci_lookup_irq)
-               return 0;
-
-       pirq_table = pirq_find_routing_table();
-
-#ifdef CONFIG_PCI_BIOS
-       if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
-               pirq_table = pcibios_get_irq_routing_table();
-#endif
-       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;
-       }
-       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;
-       u8 pin;
-
-       DBG("PCI: IRQ fixup\n");
-       pci_for_each_dev(dev) {
-               /*
-                * If the BIOS has set an out of range IRQ number, just ignore it.
-                * Also keep track of which IRQ's are already in use.
-                */
-               if (dev->irq >= 16) {
-                       DBG("%s: ignoring bogus IRQ %d\n", dev->slot_name, dev->irq);
-                       dev->irq = 0;
-               }
-               /* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */
-               if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000)
-                       pirq_penalty[dev->irq] = 0;
-               pirq_penalty[dev->irq]++;
-       }
-
-       pci_for_each_dev(dev) {
-               pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-#ifdef CONFIG_X86_IO_APIC
-               /*
-                * Recalculate IRQ numbers if we use the I/O APIC.
-                */
-               if (io_apic_assign_pci_irqs)
-               {
-                       int irq;
-
-                       if (pin) {
-                               pin--;          /* interrupt pins are numbered starting from 1 */
-                               irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
-       /*
-        * Busses behind bridges are typically not listed in the MP-table.
-        * In this case we have to look up the IRQ based on the parent bus,
-        * parent slot, and pin number. The SMP code detects such bridged
-        * busses itself so we should get into this branch reliably.
-        */
-                               if (irq < 0 && dev->bus->parent) { /* go back to the bridge */
-                                       struct pci_dev * bridge = dev->bus->self;
-
-                                       pin = (pin + PCI_SLOT(dev->devfn)) % 4;
-                                       irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, 
-                                                       PCI_SLOT(bridge->devfn), pin);
-                                       if (irq >= 0)
-                                               printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", 
-                                                       bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);
-                               }
-                               if (irq >= 0) {
-                                       printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
-                                               dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
-                                       dev->irq = irq;
-                               }
-                       }
-               }
-#endif
-               /*
-                * Still no IRQ? Try to lookup one...
-                */
-               if (pin && !dev->irq)
-                       pci_lookup_irq(dev, 0);
-       }
-}
-
-void 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)
-{
-       u8 pin;
-       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-       if (pin && !pci_lookup_irq(dev, 1) && !dev->irq) {
-               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);
-       }
-}
diff --git a/arch/i386/kernel/pci/legacy.c b/arch/i386/kernel/pci/legacy.c
deleted file mode 100644 (file)
index 4e4510e..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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(KERN_INFO "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
deleted file mode 100644 (file)
index ad3fcb3..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * numa.c - Low-level PCI access for NUMA-Q machines
- */
-#include <linux/pci.h>
-
-#include "pci.h"
-
-#define BUS2QUAD(global) (mp_bus_id_to_node[global])
-#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
-#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
-
-#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)
-{
-       unsigned long flags;
-
-       if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
-               return -EINVAL;
-
-       spin_lock_irqsave(&pci_config_lock, flags);
-
-       outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus));
-
-       switch (len) {
-       case 1:
-               *value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus));
-               break;
-       case 2:
-               *value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus));
-               break;
-       case 4:
-               *value = inl_quad(0xCFC, BUS2QUAD(bus));
-               break;
-       }
-
-       spin_unlock_irqrestore(&pci_config_lock, flags);
-
-       return 0;
-}
-
-static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
-{
-       unsigned long flags;
-
-       if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
-               return -EINVAL;
-
-       spin_lock_irqsave(&pci_config_lock, flags);
-
-       outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus));
-
-       switch (len) {
-       case 1:
-               outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus));
-               break;
-       case 2:
-               outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus));
-               break;
-       case 4:
-               outl_quad((u32)value, 0xCFC, BUS2QUAD(bus));
-               break;
-       }
-
-       spin_unlock_irqrestore(&pci_config_lock, flags);
-
-       return 0;
-}
-
-
-static void __devinit pci_fixup_i450nx(struct pci_dev *d)
-{
-       /*
-        * i450NX -- Find and scan all secondary buses on all PXB's.
-        */
-       int pxb, reg;
-       u8 busno, suba, subb;
-       int quad = BUS2QUAD(d->bus->number);
-
-       printk("PCI: Searching for i450NX host bridges on %s\n", d->slot_name);
-       reg = 0xd0;
-       for(pxb=0; pxb<2; pxb++) {
-               pci_read_config_byte(d, reg++, &busno);
-               pci_read_config_byte(d, reg++, &suba);
-               pci_read_config_byte(d, reg++, &subb);
-               DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
-               if (busno)
-                       pci_scan_bus(QUADLOCAL2BUS(quad,busno), pci_root_ops, NULL);    /* Bus A */
-               if (suba < subb)
-                       pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), pci_root_ops, NULL);   /* Bus B */
-       }
-       pcibios_last_bus = -1;
-}
-
-struct pci_fixup pcibios_fixups[] = {
-       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82451NX,    pci_fixup_i450nx },
-};
-
-static int __init pci_numa_init(void)
-{
-       int quad;
-
-       pci_config_read = pci_conf1_read;
-       pci_config_write = pci_conf1_write;
-
-       pci_root_bus = pcibios_scan_root(0);
-       if (clustered_apic_mode && (numnodes > 1)) {
-               for (quad = 1; quad < numnodes; ++quad) {
-                       printk("Scanning PCI bus %d for quad %d\n", 
-                               QUADLOCAL2BUS(quad,0), quad);
-                       pci_scan_bus(QUADLOCAL2BUS(quad,0), 
-                               pci_root_ops, NULL);
-               }
-       }
-       return 0;
-}
-
-subsys_initcall(pci_numa_init);
diff --git a/arch/i386/kernel/pci/pcbios.c b/arch/i386/kernel/pci/pcbios.c
deleted file mode 100644 (file)
index c1ef996..0000000
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * BIOS32 and PCI BIOS handling.
- */
-
-#include <linux/pci.h>
-#include "pci.h"
-
-
-#define PCIBIOS_PCI_FUNCTION_ID        0xb1XX
-#define PCIBIOS_PCI_BIOS_PRESENT       0xb101
-#define PCIBIOS_FIND_PCI_DEVICE                0xb102
-#define PCIBIOS_FIND_PCI_CLASS_CODE    0xb103
-#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106
-#define PCIBIOS_READ_CONFIG_BYTE       0xb108
-#define PCIBIOS_READ_CONFIG_WORD       0xb109
-#define PCIBIOS_READ_CONFIG_DWORD      0xb10a
-#define PCIBIOS_WRITE_CONFIG_BYTE      0xb10b
-#define PCIBIOS_WRITE_CONFIG_WORD      0xb10c
-#define PCIBIOS_WRITE_CONFIG_DWORD     0xb10d
-#define PCIBIOS_GET_ROUTING_OPTIONS    0xb10e
-#define PCIBIOS_SET_PCI_HW_INT         0xb10f
-
-/* BIOS32 signature: "_32_" */
-#define BIOS32_SIGNATURE       (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
-
-/* PCI signature: "PCI " */
-#define PCI_SIGNATURE          (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
-
-/* PCI service signature: "$PCI" */
-#define PCI_SERVICE            (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
-
-/* PCI BIOS hardware mechanism flags */
-#define PCIBIOS_HW_TYPE1               0x01
-#define PCIBIOS_HW_TYPE2               0x02
-#define PCIBIOS_HW_TYPE1_SPEC          0x10
-#define PCIBIOS_HW_TYPE2_SPEC          0x20
-
-/*
- * This is the standard structure used to identify the entry point
- * to the BIOS32 Service Directory, as documented in
- *     Standard BIOS 32-bit Service Directory Proposal
- *     Revision 0.4 May 24, 1993
- *     Phoenix Technologies Ltd.
- *     Norwood, MA
- * and the PCI BIOS specification.
- */
-
-union bios32 {
-       struct {
-               unsigned long signature;        /* _32_ */
-               unsigned long entry;            /* 32 bit physical address */
-               unsigned char revision;         /* Revision level, 0 */
-               unsigned char length;           /* Length in paragraphs should be 01 */
-               unsigned char checksum;         /* All bytes must add up to zero */
-               unsigned char reserved[5];      /* Must be zero */
-       } fields;
-       char chars[16];
-};
-
-/*
- * Physical address of the service directory.  I don't know if we're
- * allowed to have more than one of these or not, so just in case
- * we'll make pcibios_present() take a memory start parameter and store
- * the array there.
- */
-
-static struct {
-       unsigned long address;
-       unsigned short segment;
-} bios32_indirect = { 0, __KERNEL_CS };
-
-/*
- * Returns the entry point for the given service, NULL on error
- */
-
-static unsigned long bios32_service(unsigned long service)
-{
-       unsigned char return_code;      /* %al */
-       unsigned long address;          /* %ebx */
-       unsigned long length;           /* %ecx */
-       unsigned long entry;            /* %edx */
-       unsigned long flags;
-
-       __save_flags(flags); __cli();
-       __asm__("lcall *(%%edi); cld"
-               : "=a" (return_code),
-                 "=b" (address),
-                 "=c" (length),
-                 "=d" (entry)
-               : "0" (service),
-                 "1" (0),
-                 "D" (&bios32_indirect));
-       __restore_flags(flags);
-
-       switch (return_code) {
-               case 0:
-                       return address + entry;
-               case 0x80:      /* Not present */
-                       printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service);
-                       return 0;
-               default: /* Shouldn't happen */
-                       printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n",
-                               service, return_code);
-                       return 0;
-       }
-}
-
-static struct {
-       unsigned long address;
-       unsigned short segment;
-} pci_indirect = { 0, __KERNEL_CS };
-
-static int pci_bios_present;
-
-static int __devinit check_pcibios(void)
-{
-       u32 signature, eax, ebx, ecx;
-       u8 status, major_ver, minor_ver, hw_mech;
-       unsigned long flags, pcibios_entry;
-
-       if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
-               pci_indirect.address = pcibios_entry + PAGE_OFFSET;
-
-               __save_flags(flags); __cli();
-               __asm__(
-                       "lcall *(%%edi); cld\n\t"
-                       "jc 1f\n\t"
-                       "xor %%ah, %%ah\n"
-                       "1:"
-                       : "=d" (signature),
-                         "=a" (eax),
-                         "=b" (ebx),
-                         "=c" (ecx)
-                       : "1" (PCIBIOS_PCI_BIOS_PRESENT),
-                         "D" (&pci_indirect)
-                       : "memory");
-               __restore_flags(flags);
-
-               status = (eax >> 8) & 0xff;
-               hw_mech = eax & 0xff;
-               major_ver = (ebx >> 8) & 0xff;
-               minor_ver = ebx & 0xff;
-               if (pcibios_last_bus < 0)
-                       pcibios_last_bus = ecx & 0xff;
-               DBG("PCI: BIOS probe returned s=%02x hw=%02x ver=%02x.%02x l=%02x\n",
-                       status, hw_mech, major_ver, minor_ver, pcibios_last_bus);
-               if (status || signature != PCI_SIGNATURE) {
-                       printk (KERN_ERR "PCI: BIOS BUG #%x[%08x] found\n",
-                               status, signature);
-                       return 0;
-               }
-               printk(KERN_INFO "PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n",
-                       major_ver, minor_ver, pcibios_entry, pcibios_last_bus);
-#ifdef CONFIG_PCI_DIRECT
-               if (!(hw_mech & PCIBIOS_HW_TYPE1))
-                       pci_probe &= ~PCI_PROBE_CONF1;
-               if (!(hw_mech & PCIBIOS_HW_TYPE2))
-                       pci_probe &= ~PCI_PROBE_CONF2;
-#endif
-               return 1;
-       }
-       return 0;
-}
-
-static int __devinit pci_bios_find_device (unsigned short vendor, unsigned short device_id,
-                                       unsigned short index, unsigned char *bus, unsigned char *device_fn)
-{
-       unsigned short bx;
-       unsigned short ret;
-
-       __asm__("lcall *(%%edi); cld\n\t"
-               "jc 1f\n\t"
-               "xor %%ah, %%ah\n"
-               "1:"
-               : "=b" (bx),
-                 "=a" (ret)
-               : "1" (PCIBIOS_FIND_PCI_DEVICE),
-                 "c" (device_id),
-                 "d" (vendor),
-                 "S" ((int) index),
-                 "D" (&pci_indirect));
-       *bus = (bx >> 8) & 0xff;
-       *device_fn = bx & 0xff;
-       return (int) (ret & 0xff00) >> 8;
-}
-
-static int pci_bios_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
-{
-       unsigned long result = 0;
-       unsigned long flags;
-       unsigned long bx = ((bus << 8) | (dev << 3) | fn);
-
-       if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
-               return -EINVAL;
-
-       spin_lock_irqsave(&pci_config_lock, flags);
-
-       switch (len) {
-       case 1:
-               __asm__("lcall *(%%esi); cld\n\t"
-                       "jc 1f\n\t"
-                       "xor %%ah, %%ah\n"
-                       "1:"
-                       : "=c" (*value),
-                         "=a" (result)
-                       : "1" (PCIBIOS_READ_CONFIG_BYTE),
-                         "b" (bx),
-                         "D" ((long)reg),
-                         "S" (&pci_indirect));
-               break;
-       case 2:
-               __asm__("lcall *(%%esi); cld\n\t"
-                       "jc 1f\n\t"
-                       "xor %%ah, %%ah\n"
-                       "1:"
-                       : "=c" (*value),
-                         "=a" (result)
-                       : "1" (PCIBIOS_READ_CONFIG_WORD),
-                         "b" (bx),
-                         "D" ((long)reg),
-                         "S" (&pci_indirect));
-               break;
-       case 4:
-               __asm__("lcall *(%%esi); cld\n\t"
-                       "jc 1f\n\t"
-                       "xor %%ah, %%ah\n"
-                       "1:"
-                       : "=c" (*value),
-                         "=a" (result)
-                       : "1" (PCIBIOS_READ_CONFIG_DWORD),
-                         "b" (bx),
-                         "D" ((long)reg),
-                         "S" (&pci_indirect));
-               break;
-       }
-
-       spin_unlock_irqrestore(&pci_config_lock, flags);
-
-       return (int)((result & 0xff00) >> 8);
-}
-
-static int pci_bios_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
-{
-       unsigned long result = 0;
-       unsigned long flags;
-       unsigned long bx = ((bus << 8) | (dev << 3) | fn);
-
-       if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
-               return -EINVAL;
-
-       spin_lock_irqsave(&pci_config_lock, flags);
-
-       switch (len) {
-       case 1:
-               __asm__("lcall *(%%esi); cld\n\t"
-                       "jc 1f\n\t"
-                       "xor %%ah, %%ah\n"
-                       "1:"
-                       : "=a" (result)
-                       : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
-                         "c" (value),
-                         "b" (bx),
-                         "D" ((long)reg),
-                         "S" (&pci_indirect));
-               break;
-       case 2:
-               __asm__("lcall *(%%esi); cld\n\t"
-                       "jc 1f\n\t"
-                       "xor %%ah, %%ah\n"
-                       "1:"
-                       : "=a" (result)
-                       : "0" (PCIBIOS_WRITE_CONFIG_WORD),
-                         "c" (value),
-                         "b" (bx),
-                         "D" ((long)reg),
-                         "S" (&pci_indirect));
-               break;
-       case 4:
-               __asm__("lcall *(%%esi); cld\n\t"
-                       "jc 1f\n\t"
-                       "xor %%ah, %%ah\n"
-                       "1:"
-                       : "=a" (result)
-                       : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
-                         "c" (value),
-                         "b" (bx),
-                         "D" ((long)reg),
-                         "S" (&pci_indirect));
-               break;
-       }
-
-       spin_unlock_irqrestore(&pci_config_lock, flags);
-
-       return (int)((result & 0xff00) >> 8);
-}
-
-static int pci_bios_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-       int result; 
-       u32 data;
-
-       if (!value) 
-               return -EINVAL;
-
-       result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 1, &data);
-
-       *value = (u8)data;
-
-       return result;
-}
-
-static int pci_bios_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-       int result; 
-       u32 data;
-
-       if (!value) 
-               return -EINVAL;
-
-       result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 2, &data);
-
-       *value = (u16)data;
-
-       return result;
-}
-
-static int pci_bios_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-       if (!value) 
-               return -EINVAL;
-       
-       return pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 4, value);
-}
-
-static int pci_bios_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-       return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 1, value);
-}
-
-static int pci_bios_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-       return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 2, value);
-}
-
-static int pci_bios_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-       return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
-               PCI_FUNC(dev->devfn), where, 4, value);
-}
-
-
-/*
- * Function table for BIOS32 access
- */
-
-static struct pci_ops pci_bios_access = {
-      pci_bios_read_config_byte,
-      pci_bios_read_config_word,
-      pci_bios_read_config_dword,
-      pci_bios_write_config_byte,
-      pci_bios_write_config_word,
-      pci_bios_write_config_dword
-};
-
-/*
- * Try to find PCI BIOS.
- */
-
-static struct pci_ops * __devinit pci_find_bios(void)
-{
-       union bios32 *check;
-       unsigned char sum;
-       int i, length;
-
-       /*
-        * Follow the standard procedure for locating the BIOS32 Service
-        * directory by scanning the permissible address range from
-        * 0xe0000 through 0xfffff for a valid BIOS32 structure.
-        */
-
-       for (check = (union bios32 *) __va(0xe0000);
-            check <= (union bios32 *) __va(0xffff0);
-            ++check) {
-               if (check->fields.signature != BIOS32_SIGNATURE)
-                       continue;
-               length = check->fields.length * 16;
-               if (!length)
-                       continue;
-               sum = 0;
-               for (i = 0; i < length ; ++i)
-                       sum += check->chars[i];
-               if (sum != 0)
-                       continue;
-               if (check->fields.revision != 0) {
-                       printk("PCI: unsupported BIOS32 revision %d at 0x%p\n",
-                               check->fields.revision, check);
-                       continue;
-               }
-               DBG("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
-               if (check->fields.entry >= 0x100000) {
-                       printk("PCI: BIOS32 entry (0x%p) in high memory, cannot use.\n", check);
-                       return NULL;
-               } else {
-                       unsigned long bios32_entry = check->fields.entry;
-                       DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
-                       bios32_indirect.address = bios32_entry + PAGE_OFFSET;
-                       if (check_pcibios())
-                               return &pci_bios_access;
-               }
-               break;  /* Hopefully more than one BIOS32 cannot happen... */
-       }
-
-       return NULL;
-}
-
-/*
- * Sort the device list according to PCI BIOS. Nasty hack, but since some
- * fool forgot to define the `correct' device order in the PCI BIOS specs
- * and we want to be (possibly bug-to-bug ;-]) compatible with older kernels
- * which used BIOS ordering, we are bound to do this...
- */
-
-void __devinit pcibios_sort(void)
-{
-       LIST_HEAD(sorted_devices);
-       struct list_head *ln;
-       struct pci_dev *dev, *d;
-       int idx, found;
-       unsigned char bus, devfn;
-
-       DBG("PCI: Sorting device list...\n");
-       while (!list_empty(&pci_devices)) {
-               ln = pci_devices.next;
-               dev = pci_dev_g(ln);
-               idx = found = 0;
-               while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
-                       idx++;
-                       for (ln=pci_devices.next; ln != &pci_devices; ln=ln->next) {
-                               d = pci_dev_g(ln);
-                               if (d->bus->number == bus && d->devfn == devfn) {
-                                       list_del(&d->global_list);
-                                       list_add_tail(&d->global_list, &sorted_devices);
-                                       if (d == dev)
-                                               found = 1;
-                                       break;
-                               }
-                       }
-                       if (ln == &pci_devices) {
-                               printk(KERN_WARNING "PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
-                               /*
-                                * We must not continue scanning as several buggy BIOSes
-                                * return garbage after the last device. Grr.
-                                */
-                               break;
-                       }
-               }
-               if (!found) {
-                       printk(KERN_WARNING "PCI: Device %02x:%02x not found by BIOS\n",
-                               dev->bus->number, dev->devfn);
-                       list_del(&dev->global_list);
-                       list_add_tail(&dev->global_list, &sorted_devices);
-               }
-       }
-       list_splice(&sorted_devices, &pci_devices);
-}
-
-/*
- *  BIOS Functions for IRQ Routing
- */
-
-struct irq_routing_options {
-       u16 size;
-       struct irq_info *table;
-       u16 segment;
-} __attribute__((packed));
-
-struct irq_routing_table * __devinit pcibios_get_irq_routing_table(void)
-{
-       struct irq_routing_options opt;
-       struct irq_routing_table *rt = NULL;
-       int ret, map;
-       unsigned long page;
-
-       if (!pci_bios_present)
-               return NULL;
-       page = __get_free_page(GFP_KERNEL);
-       if (!page)
-               return NULL;
-       opt.table = (struct irq_info *) page;
-       opt.size = PAGE_SIZE;
-       opt.segment = __KERNEL_DS;
-
-       DBG("PCI: Fetching IRQ routing table... ");
-       __asm__("push %%es\n\t"
-               "push %%ds\n\t"
-               "pop  %%es\n\t"
-               "lcall *(%%esi); cld\n\t"
-               "pop %%es\n\t"
-               "jc 1f\n\t"
-               "xor %%ah, %%ah\n"
-               "1:"
-               : "=a" (ret),
-                 "=b" (map)
-               : "0" (PCIBIOS_GET_ROUTING_OPTIONS),
-                 "1" (0),
-                 "D" ((long) &opt),
-                 "S" (&pci_indirect));
-       DBG("OK  ret=%d, size=%d, map=%x\n", ret, opt.size, map);
-       if (ret & 0xff00)
-               printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff);
-       else if (opt.size) {
-               rt = kmalloc(sizeof(struct irq_routing_table) + opt.size, GFP_KERNEL);
-               if (rt) {
-                       memset(rt, 0, sizeof(struct irq_routing_table));
-                       rt->size = opt.size + sizeof(struct irq_routing_table);
-                       rt->exclusive_irqs = map;
-                       memcpy(rt->slots, (void *) page, opt.size);
-                       printk(KERN_INFO "PCI: Using BIOS Interrupt Routing Table\n");
-               }
-       }
-       free_page(page);
-       return rt;
-}
-
-
-int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq)
-{
-       int ret;
-
-       __asm__("lcall *(%%esi); cld\n\t"
-               "jc 1f\n\t"
-               "xor %%ah, %%ah\n"
-               "1:"
-               : "=a" (ret)
-               : "0" (PCIBIOS_SET_PCI_HW_INT),
-                 "b" ((dev->bus->number << 8) | dev->devfn),
-                 "c" ((irq << 8) | (pin + 10)),
-                 "S" (&pci_indirect));
-       return !(ret & 0xff00);
-}
-
-static int __init pci_pcbios_init(void)
-{
-       if ((pci_probe & PCI_PROBE_BIOS) 
-               && ((pci_root_ops = pci_find_bios()))) {
-               pci_probe |= PCI_BIOS_SORT;
-               pci_bios_present = 1;
-               pci_config_read = pci_bios_read;
-               pci_config_write = pci_bios_write;
-       }
-       return 0;
-}
-
-subsys_initcall(pci_pcbios_init);
diff --git a/arch/i386/kernel/pci/pci.h b/arch/i386/kernel/pci/pci.h
deleted file mode 100644 (file)
index 2240a68..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- *     Low-Level PCI Access for i386 machines.
- *
- *     (c) 1999 Martin Mares <mj@ucw.cz>
- */
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-#define PCI_PROBE_BIOS         0x0001
-#define PCI_PROBE_CONF1                0x0002
-#define PCI_PROBE_CONF2                0x0004
-#define PCI_NO_SORT            0x0100
-#define PCI_BIOS_SORT          0x0200
-#define PCI_NO_CHECKS          0x0400
-#define PCI_USE_PIRQ_MASK      0x0800
-#define PCI_ASSIGN_ROMS                0x1000
-#define PCI_BIOS_IRQ_SCAN      0x2000
-#define PCI_ASSIGN_ALL_BUSSES  0x4000
-#define PCI_NO_ACPI_ROUTING    0x8000
-
-extern unsigned int pci_probe;
-
-/* pci-i386.c */
-
-extern unsigned int pcibios_max_latency;
-
-void pcibios_resource_survey(void);
-int pcibios_enable_resources(struct pci_dev *);
-
-/* pci-pc.c */
-
-extern int pcibios_last_bus;
-extern struct pci_bus *pci_root_bus;
-extern struct pci_ops *pci_root_ops;
-
-/* pci-irq.c */
-
-struct irq_info {
-       u8 bus, devfn;                  /* Bus, device and function */
-       struct {
-               u8 link;                /* IRQ line ID, chipset dependent, 0=not routed */
-               u16 bitmap;             /* Available IRQs */
-       } __attribute__((packed)) irq[4];
-       u8 slot;                        /* Slot number, 0=onboard */
-       u8 rfu;
-} __attribute__((packed));
-
-struct irq_routing_table {
-       u32 signature;                  /* PIRQ_SIGNATURE should be here */
-       u16 version;                    /* PIRQ_VERSION */
-       u16 size;                       /* Table size in bytes */
-       u8 rtr_bus, rtr_devfn;          /* Where the interrupt router lies */
-       u16 exclusive_irqs;             /* IRQs devoted exclusively to PCI usage */
-       u16 rtr_vendor, rtr_device;     /* Vendor and device ID of interrupt router */
-       u32 miniport_data;              /* Crap */
-       u8 rfu[11];
-       u8 checksum;                    /* Modulo 256 checksum must give zero */
-       struct irq_info slots[0];
-} __attribute__((packed));
-
-extern unsigned int pcibios_irq_mask;
-
-extern int pci_use_acpi_routing;
-extern spinlock_t pci_config_lock;
-
-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/arch/i386/kernel/pci/visws.c b/arch/i386/kernel/pci/visws.c
deleted file mode 100644 (file)
index c583be6..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- *     Low-Level PCI Support for SGI Visual Workstation
- *
- *     (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/irq.h>
-
-#include <asm/smp.h>
-#include <asm/lithium.h>
-#include <asm/io.h>
-
-#include "pci-i386.h"
-
-unsigned int pci_probe = 0;
-
-/*
- *  The VISWS uses configuration access type 1 only.
- */
-
-#define CONFIG_CMD(dev, where)   (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
-
-static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-       outl(CONFIG_CMD(dev,where), 0xCF8);
-       *value = inb(0xCFC + (where&3));
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-       outl(CONFIG_CMD(dev,where), 0xCF8);    
-       *value = inw(0xCFC + (where&2));
-       return PCIBIOS_SUCCESSFUL;    
-}
-
-static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-       outl(CONFIG_CMD(dev,where), 0xCF8);
-       *value = inl(0xCFC);
-       return PCIBIOS_SUCCESSFUL;    
-}
-
-static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-       outl(CONFIG_CMD(dev,where), 0xCF8);    
-       outb(value, 0xCFC + (where&3));
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-       outl(CONFIG_CMD(dev,where), 0xCF8);
-       outw(value, 0xCFC + (where&2));
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-       outl(CONFIG_CMD(dev,where), 0xCF8);
-       outl(value, 0xCFC);
-       return PCIBIOS_SUCCESSFUL;
-}
-
-#undef CONFIG_CMD
-
-static struct pci_ops visws_pci_ops = {
-       pci_conf1_read_config_byte,
-       pci_conf1_read_config_word,
-       pci_conf1_read_config_dword,
-       pci_conf1_write_config_byte,
-       pci_conf1_write_config_word,
-       pci_conf1_write_config_dword
-};
-
-static void __init pcibios_fixup_irqs(void)
-{
-       struct pci_dev *dev, *p;
-       u8 pin;
-       int irq;
-
-       pci_for_each_dev(dev) {
-               pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-               dev->irq = 0;
-               if (!pin)
-                       continue;
-               pin--;
-               if (dev->bus->parent) {
-                       p = dev->bus->parent->self;
-                       pin = (pin + PCI_SLOT(dev->devfn)) % 4;
-               } else
-                       p = dev;
-               irq = visws_get_PCI_irq_vector(p->bus->number, PCI_SLOT(p->devfn), pin+1);
-               if (irq >= 0)
-                       dev->irq = irq;
-               DBG("PCI IRQ: %s pin %d -> %d\n", dev->slot_name, pin, irq);
-       }
-}
-
-void __init pcibios_fixup_bus(struct pci_bus *b)
-{
-       pci_read_bridge_bases(b);
-}
-
-#if 0
-static struct resource visws_pci_bus_resources[2] = {
-       { "Host bus 1", 0xf4000000, 0xf7ffffff, 0 },
-       { "Host bus 2", 0xf0000000, 0xf3ffffff, 0 }
-};
-#endif
-
-void __init pcibios_init(void)
-{
-       unsigned int sec_bus = li_pcib_read16(LI_PCI_BUSNUM) & 0xff;
-
-       printk("PCI: Probing PCI hardware on host buses 00 and %02x\n", sec_bus);
-       pci_scan_bus(0, &visws_pci_ops, NULL);
-       pci_scan_bus(sec_bus, &visws_pci_ops, NULL);
-       pcibios_fixup_irqs();
-       pcibios_resource_survey();
-}
-
-char * __init pcibios_setup(char *str)
-{
-       return str;
-}
-
-int pcibios_enable_device(struct pci_dev *dev)
-{
-       return pcibios_enable_resources(dev);
-}
-
-void __init pcibios_penalize_isa_irq(irq)
-{
-}
diff --git a/arch/i386/pci/Makefile b/arch/i386/pci/Makefile
new file mode 100644 (file)
index 0000000..e07ba54
--- /dev/null
@@ -0,0 +1,29 @@
+O_TARGET        := pci.o
+
+obj-y          := dma.o i386.o
+
+ifdef  CONFIG_VISWS
+obj-y          += visws.o
+else
+
+obj-$(CONFIG_PCI_BIOS)         += pcbios.o
+obj-$(CONFIG_PCI_DIRECT)       += direct.o
+
+ifdef  CONFIG_MULTIQUAD
+obj-y          += numa.o
+else
+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
+
+export-objs     +=      $(obj-y)
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/i386/pci/acpi.c b/arch/i386/pci/acpi.c
new file mode 100644 (file)
index 0000000..dd2c45d
--- /dev/null
@@ -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/pci/changelog b/arch/i386/pci/changelog
new file mode 100644 (file)
index 0000000..f92eb1c
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * CHANGELOG :
+ * Jun 17, 1994 : Modified to accommodate the broken pre-PCI BIOS SPECIFICATION
+ *     Revision 2.0 present on <thys@dennis.ee.up.ac.za>'s ASUS mainboard.
+ *
+ * Jan 5,  1995 : Modified to probe PCI hardware at boot time by Frederic
+ *     Potter, potter@cao-vlsi.ibp.fr
+ *
+ * Jan 10, 1995 : Modified to store the information about configured pci
+ *      devices into a list, which can be accessed via /proc/pci by
+ *      Curtis Varner, cvarner@cs.ucr.edu
+ *
+ * Jan 12, 1995 : CPU-PCI bridge optimization support by Frederic Potter.
+ *     Alpha version. Intel & UMC chipset support only.
+ *
+ * Apr 16, 1995 : Source merge with the DEC Alpha PCI support. Most of the code
+ *     moved to drivers/pci/pci.c.
+ *
+ * Dec 7, 1996  : Added support for direct configuration access of boards
+ *      with Intel compatible access schemes (tsbogend@alpha.franken.de)
+ *
+ * Feb 3, 1997  : Set internal functions to static, save/restore flags
+ *     avoid dead locks reading broken PCI BIOS, werner@suse.de 
+ *
+ * Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS
+ *     (mj@atrey.karlin.mff.cuni.cz)
+ *
+ * May 7,  1997 : Added some missing cli()'s. [mj]
+ * 
+ * Jun 20, 1997 : Corrected problems in "conf1" type accesses.
+ *      (paubert@iram.es)
+ *
+ * Aug 2,  1997 : Split to PCI BIOS handling and direct PCI access parts
+ *     and cleaned it up...     Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * Feb 6,  1998 : No longer using BIOS to find devices and device classes. [mj]
+ *
+ * May 1,  1998 : Support for peer host bridges. [mj]
+ *
+ * Jun 19, 1998 : Changed to use spinlocks, so that PCI configuration space
+ *     can be accessed from interrupts even on SMP systems. [mj]
+ *
+ * August  1998 : Better support for peer host bridges and more paranoid
+ *     checks for direct hardware access. Ugh, this file starts to look as
+ *     a large gallery of common hardware bug workarounds (watch the comments)
+ *     -- the PCI specs themselves are sane, but most implementors should be
+ *     hit hard with \hammer scaled \magstep5. [mj]
+ *
+ * Jan 23, 1999 : More improvements to peer host bridge logic. i450NX fixup. [mj]
+ *
+ * Feb 8,  1999 : Added UM8886BF I/O address fixup. [mj]
+ *
+ * August  1999 : New resource management and configuration access stuff. [mj]
+ *
+ * Sep 19, 1999 : Use PCI IRQ routing tables for detection of peer host bridges.
+ *               Based on ideas by Chris Frantz and David Hinds. [mj]
+ *
+ * Sep 28, 1999 : Handle unreported/unassigned IRQs. Thanks to Shuu Yamaguchi
+ *               for a lot of patience during testing. [mj]
+ *
+ * Oct  8, 1999 : Split to pci-i386.c, pci-pc.c and pci-visws.c. [mj]
+ */
\ No newline at end of file
diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c
new file mode 100644 (file)
index 0000000..35a721f
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ *     Low-Level PCI Support for PC
+ *
+ *     (c) 1999--2000 Martin Mares <mj@ucw.cz>
+ */
+
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+
+#include "pci.h"
+
+#ifdef CONFIG_PCI_BIOS
+extern  void pcibios_sort(void);
+#endif
+
+unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
+
+int pcibios_last_bus = -1;
+struct pci_bus *pci_root_bus = NULL;
+struct pci_ops *pci_root_ops = NULL;
+
+int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value) = NULL;
+int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value) = NULL;
+
+/*
+ * This interrupt-safe spinlock protects all accesses to PCI
+ * configuration space.
+ */
+spinlock_t pci_config_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Several buggy motherboards address only 16 devices and mirror
+ * them to next 16 IDs. We try to detect this `feature' on all
+ * primary buses (those containing host bridges as they are
+ * expected to be unique) and remove the ghost devices.
+ */
+
+static void __devinit pcibios_fixup_ghosts(struct pci_bus *b)
+{
+       struct list_head *ln, *mn;
+       struct pci_dev *d, *e;
+       int mirror = PCI_DEVFN(16,0);
+       int seen_host_bridge = 0;
+       int i;
+
+       DBG("PCI: Scanning for ghost devices on bus %d\n", b->number);
+       for (ln=b->devices.next; ln != &b->devices; ln=ln->next) {
+               d = pci_dev_b(ln);
+               if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+                       seen_host_bridge++;
+               for (mn=ln->next; mn != &b->devices; mn=mn->next) {
+                       e = pci_dev_b(mn);
+                       if (e->devfn != d->devfn + mirror ||
+                           e->vendor != d->vendor ||
+                           e->device != d->device ||
+                           e->class != d->class)
+                               continue;
+                       for(i=0; i<PCI_NUM_RESOURCES; i++)
+                               if (e->resource[i].start != d->resource[i].start ||
+                                   e->resource[i].end != d->resource[i].end ||
+                                   e->resource[i].flags != d->resource[i].flags)
+                                       continue;
+                       break;
+               }
+               if (mn == &b->devices)
+                       return;
+       }
+       if (!seen_host_bridge)
+               return;
+       printk(KERN_WARNING "PCI: Ignoring ghost devices on bus %02x\n", b->number);
+
+       ln = &b->devices;
+       while (ln->next != &b->devices) {
+               d = pci_dev_b(ln->next);
+               if (d->devfn >= mirror) {
+                       list_del(&d->global_list);
+                       list_del(&d->bus_list);
+                       kfree(d);
+               } else
+                       ln = ln->next;
+       }
+}
+
+/*
+ *  Called after each bus is probed, but before its children
+ *  are examined.
+ */
+
+void __devinit  pcibios_fixup_bus(struct pci_bus *b)
+{
+       pcibios_fixup_ghosts(b);
+       pci_read_bridge_bases(b);
+}
+
+
+struct pci_bus * __devinit pcibios_scan_root(int busnum)
+{
+       struct list_head *list;
+       struct pci_bus *bus;
+
+       list_for_each(list, &pci_root_buses) {
+               bus = pci_bus_b(list);
+               if (bus->number == busnum) {
+                       /* Already scanned */
+                       return bus;
+               }
+       }
+
+       printk("PCI: Probing PCI hardware (bus %02x)\n", busnum);
+
+       return pci_scan_bus(busnum, pci_root_ops, NULL);
+}
+
+static int __init pcibios_init(void)
+{
+       if (!pci_root_ops) {
+               printk("PCI: System does not support PCI\n");
+               return 0;
+       }
+
+       pcibios_resource_survey();
+
+#ifdef CONFIG_PCI_BIOS
+       if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
+               pcibios_sort();
+#endif
+       return 0;
+}
+
+subsys_initcall(pcibios_init);
+
+char * __devinit  pcibios_setup(char *str)
+{
+       if (!strcmp(str, "off")) {
+               pci_probe = 0;
+               return NULL;
+       }
+#ifdef CONFIG_PCI_BIOS
+       else if (!strcmp(str, "bios")) {
+               pci_probe = PCI_PROBE_BIOS;
+               return NULL;
+       } else if (!strcmp(str, "nobios")) {
+               pci_probe &= ~PCI_PROBE_BIOS;
+               return NULL;
+       } else if (!strcmp(str, "nosort")) {
+               pci_probe |= PCI_NO_SORT;
+               return NULL;
+       } else if (!strcmp(str, "biosirq")) {
+               pci_probe |= PCI_BIOS_IRQ_SCAN;
+               return NULL;
+       }
+#endif
+#ifdef CONFIG_PCI_DIRECT
+       else if (!strcmp(str, "conf1")) {
+               pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS;
+               return NULL;
+       }
+       else if (!strcmp(str, "conf2")) {
+               pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS;
+               return NULL;
+       }
+#endif
+#ifdef CONFIG_ACPI_PCI
+       else if (!strcmp(str, "noacpi")) {
+               pci_probe |= PCI_NO_ACPI_ROUTING;
+               return NULL;
+       }
+#endif
+       else if (!strcmp(str, "rom")) {
+               pci_probe |= PCI_ASSIGN_ROMS;
+               return NULL;
+       } else if (!strcmp(str, "assign-busses")) {
+               pci_probe |= PCI_ASSIGN_ALL_BUSSES;
+               return NULL;
+       } else if (!strcmp(str, "usepirqmask")) {
+               pci_probe |= PCI_USE_PIRQ_MASK;
+               return NULL;
+       } else if (!strncmp(str, "irqmask=", 8)) {
+               pcibios_irq_mask = simple_strtol(str+8, NULL, 0);
+               return NULL;
+       } else if (!strncmp(str, "lastbus=", 8)) {
+               pcibios_last_bus = simple_strtol(str+8, NULL, 0);
+               return NULL;
+       }
+       return str;
+}
+
+unsigned int pcibios_assign_all_busses(void)
+{
+       return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
+}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+       int err;
+
+       if ((err = pcibios_enable_resources(dev)) < 0)
+               return err;
+       pcibios_enable_irq(dev);
+       return 0;
+}
diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c
new file mode 100644 (file)
index 0000000..594a556
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * direct.c - Low-level direct PCI config space access
+ */
+
+#include <linux/pci.h>
+#include "pci.h"
+
+/*
+ * Functions for accessing PCI configuration space with type 1 accesses
+ */
+
+#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
+       (0x80000000 | (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)
+{
+       unsigned long flags;
+
+       if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+               return -EINVAL;
+
+       spin_lock_irqsave(&pci_config_lock, flags);
+
+       outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
+
+       switch (len) {
+       case 1:
+               *value = inb(0xCFC + (reg & 3));
+               break;
+       case 2:
+               *value = inw(0xCFC + (reg & 2));
+               break;
+       case 4:
+               *value = inl(0xCFC);
+               break;
+       }
+
+       spin_unlock_irqrestore(&pci_config_lock, flags);
+
+       return 0;
+}
+
+static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
+{
+       unsigned long flags;
+
+       if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+               return -EINVAL;
+
+       spin_lock_irqsave(&pci_config_lock, flags);
+
+       outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8);
+
+       switch (len) {
+       case 1:
+               outb((u8)value, 0xCFC + (reg & 3));
+               break;
+       case 2:
+               outw((u16)value, 0xCFC + (reg & 2));
+               break;
+       case 4:
+               outl((u32)value, 0xCFC);
+               break;
+       }
+
+       spin_unlock_irqrestore(&pci_config_lock, flags);
+
+       return 0;
+}
+
+
+#undef PCI_CONF1_ADDRESS
+
+static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+       int result; 
+       u32 data;
+
+       if (!value) 
+               return -EINVAL;
+
+       result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 1, &data);
+
+       *value = (u8)data;
+
+       return result;
+}
+
+static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+       int result; 
+       u32 data;
+
+       if (!value) 
+               return -EINVAL;
+
+       result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 2, &data);
+
+       *value = (u16)data;
+
+       return result;
+}
+
+static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+       if (!value) 
+               return -EINVAL;
+
+       return pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+       return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 1, value);
+}
+
+static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+       return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 2, value);
+}
+
+static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+       return pci_conf1_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+static struct pci_ops pci_direct_conf1 = {
+       pci_conf1_read_config_byte,
+       pci_conf1_read_config_word,
+       pci_conf1_read_config_dword,
+       pci_conf1_write_config_byte,
+       pci_conf1_write_config_word,
+       pci_conf1_write_config_dword
+};
+
+
+/*
+ * Functions for accessing PCI configuration space with type 2 accesses
+ */
+
+#define PCI_CONF2_ADDRESS(dev, reg)    (u16)(0xC000 | (dev << 8) | reg)
+
+static int pci_conf2_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
+{
+       unsigned long flags;
+
+       if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+               return -EINVAL;
+
+       if (dev & 0x10) 
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       spin_lock_irqsave(&pci_config_lock, flags);
+
+       outb((u8)(0xF0 | (fn << 1)), 0xCF8);
+       outb((u8)bus, 0xCFA);
+
+       switch (len) {
+       case 1:
+               *value = inb(PCI_CONF2_ADDRESS(dev, reg));
+               break;
+       case 2:
+               *value = inw(PCI_CONF2_ADDRESS(dev, reg));
+               break;
+       case 4:
+               *value = inl(PCI_CONF2_ADDRESS(dev, reg));
+               break;
+       }
+
+       outb (0, 0xCF8);
+
+       spin_unlock_irqrestore(&pci_config_lock, flags);
+
+       return 0;
+}
+
+static int pci_conf2_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
+{
+       unsigned long flags;
+
+       if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+               return -EINVAL;
+
+       if (dev & 0x10) 
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       spin_lock_irqsave(&pci_config_lock, flags);
+
+       outb((u8)(0xF0 | (fn << 1)), 0xCF8);
+       outb((u8)bus, 0xCFA);
+
+       switch (len) {
+       case 1:
+               outb ((u8)value, PCI_CONF2_ADDRESS(dev, reg));
+               break;
+       case 2:
+               outw ((u16)value, PCI_CONF2_ADDRESS(dev, reg));
+               break;
+       case 4:
+               outl ((u32)value, PCI_CONF2_ADDRESS(dev, reg));
+               break;
+       }
+
+       outb (0, 0xCF8);    
+
+       spin_unlock_irqrestore(&pci_config_lock, flags);
+
+       return 0;
+}
+
+#undef PCI_CONF2_ADDRESS
+
+static int pci_conf2_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+       int result; 
+       u32 data;
+       result = pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 1, &data);
+       *value = (u8)data;
+       return result;
+}
+
+static int pci_conf2_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+       int result; 
+       u32 data;
+       result = pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 2, &data);
+       *value = (u16)data;
+       return result;
+}
+
+static int pci_conf2_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+       return pci_conf2_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+static int pci_conf2_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+       return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 1, value);
+}
+
+static int pci_conf2_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+       return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 2, value);
+}
+
+static int pci_conf2_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+       return pci_conf2_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+static struct pci_ops pci_direct_conf2 = {
+       pci_conf2_read_config_byte,
+       pci_conf2_read_config_word,
+       pci_conf2_read_config_dword,
+       pci_conf2_write_config_byte,
+       pci_conf2_write_config_word,
+       pci_conf2_write_config_dword
+};
+
+
+/*
+ * Before we decide to use direct hardware access mechanisms, we try to do some
+ * trivial checks to ensure it at least _seems_ to be working -- we just test
+ * whether bus 00 contains a host bridge (this is similar to checking
+ * techniques used in XFree86, but ours should be more reliable since we
+ * attempt to make use of direct access hints provided by the PCI BIOS).
+ *
+ * This should be close to trivial, but it isn't, because there are buggy
+ * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
+ */
+static int __devinit pci_sanity_check(struct pci_ops *o)
+{
+       u16 x;
+       struct pci_bus bus;             /* Fake bus and device */
+       struct pci_dev dev;
+
+       if (pci_probe & PCI_NO_CHECKS)
+               return 1;
+       bus.number = 0;
+       dev.bus = &bus;
+       for(dev.devfn=0; dev.devfn < 0x100; dev.devfn++)
+               if ((!o->read_word(&dev, PCI_CLASS_DEVICE, &x) &&
+                    (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) ||
+                   (!o->read_word(&dev, PCI_VENDOR_ID, &x) &&
+                    (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ)))
+                       return 1;
+       DBG("PCI: Sanity check failed\n");
+       return 0;
+}
+
+static struct pci_ops * __devinit pci_check_direct(void)
+{
+       unsigned int tmp;
+       unsigned long flags;
+
+       __save_flags(flags); __cli();
+
+       /*
+        * Check if configuration type 1 works.
+        */
+       if (pci_probe & PCI_PROBE_CONF1) {
+               outb (0x01, 0xCFB);
+               tmp = inl (0xCF8);
+               outl (0x80000000, 0xCF8);
+               if (inl (0xCF8) == 0x80000000 &&
+                   pci_sanity_check(&pci_direct_conf1)) {
+                       outl (tmp, 0xCF8);
+                       __restore_flags(flags);
+                       printk(KERN_INFO "PCI: Using configuration type 1\n");
+                       if (!request_region(0xCF8, 8, "PCI conf1"))
+                               return NULL;
+                       return &pci_direct_conf1;
+               }
+               outl (tmp, 0xCF8);
+       }
+
+       /*
+        * Check if configuration type 2 works.
+        */
+       if (pci_probe & PCI_PROBE_CONF2) {
+               outb (0x00, 0xCFB);
+               outb (0x00, 0xCF8);
+               outb (0x00, 0xCFA);
+               if (inb (0xCF8) == 0x00 && inb (0xCFA) == 0x00 &&
+                   pci_sanity_check(&pci_direct_conf2)) {
+                       __restore_flags(flags);
+                       printk(KERN_INFO "PCI: Using configuration type 2\n");
+                       if (!request_region(0xCF8, 4, "PCI conf2"))
+                               return NULL;
+                       return &pci_direct_conf2;
+               }
+       }
+
+       __restore_flags(flags);
+       return NULL;
+}
+
+static int __init pci_direct_init(void)
+{
+       if ((pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2)) 
+               && (pci_root_ops = pci_check_direct())) {
+               if (pci_root_ops == &pci_direct_conf1) {
+                       pci_config_read = pci_conf1_read;
+                       pci_config_write = pci_conf1_write;
+               }
+               else {
+                       pci_config_read = pci_conf2_read;
+                       pci_config_write = pci_conf2_write;
+               }
+       }
+       return 0;
+}
+
+subsys_initcall(pci_direct_init);
diff --git a/arch/i386/pci/dma.c b/arch/i386/pci/dma.c
new file mode 100644 (file)
index 0000000..2031b85
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Dynamic DMA mapping support.
+ *
+ * On i386 there is no hardware dynamic DMA address translation,
+ * so consistent alloc/free are merely page allocation/freeing.
+ * The rest of the dynamic DMA mapping interface is implemented
+ * in asm/pci.h.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+                          dma_addr_t *dma_handle)
+{
+       void *ret;
+       int gfp = GFP_ATOMIC;
+
+       if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
+               gfp |= GFP_DMA;
+       ret = (void *)__get_free_pages(gfp, get_order(size));
+
+       if (ret != NULL) {
+               memset(ret, 0, size);
+               *dma_handle = virt_to_phys(ret);
+       }
+       return ret;
+}
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+                        void *vaddr, dma_addr_t dma_handle)
+{
+       free_pages((unsigned long)vaddr, get_order(size));
+}
diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
new file mode 100644 (file)
index 0000000..ca14f00
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Exceptions for specific devices. Usually work-arounds for fatal design flaws.
+ */
+
+#include <linux/pci.h>
+#include "pci.h"
+
+
+static void __devinit pci_fixup_i450nx(struct pci_dev *d)
+{
+       /*
+        * i450NX -- Find and scan all secondary buses on all PXB's.
+        */
+       int pxb, reg;
+       u8 busno, suba, subb;
+
+       printk(KERN_WARNING "PCI: Searching for i450NX host bridges on %s\n", d->slot_name);
+       reg = 0xd0;
+       for(pxb=0; pxb<2; pxb++) {
+               pci_read_config_byte(d, reg++, &busno);
+               pci_read_config_byte(d, reg++, &suba);
+               pci_read_config_byte(d, reg++, &subb);
+               DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
+               if (busno)
+                       pci_scan_bus(busno, pci_root_ops, NULL);        /* Bus A */
+               if (suba < subb)
+                       pci_scan_bus(suba+1, pci_root_ops, NULL);       /* Bus B */
+       }
+       pcibios_last_bus = -1;
+}
+
+static void __devinit pci_fixup_i450gx(struct pci_dev *d)
+{
+       /*
+        * i450GX and i450KX -- Find and scan all secondary buses.
+        * (called separately for each PCI bridge found)
+        */
+       u8 busno;
+       pci_read_config_byte(d, 0x4a, &busno);
+       printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", d->slot_name, busno);
+       pci_scan_bus(busno, pci_root_ops, NULL);
+       pcibios_last_bus = -1;
+}
+
+static void __devinit  pci_fixup_umc_ide(struct pci_dev *d)
+{
+       /*
+        * UM8886BF IDE controller sets region type bits incorrectly,
+        * therefore they look like memory despite of them being I/O.
+        */
+       int i;
+
+       printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", d->slot_name);
+       for(i=0; i<4; i++)
+               d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
+}
+
+static void __devinit  pci_fixup_ncr53c810(struct pci_dev *d)
+{
+       /*
+        * NCR 53C810 returns class code 0 (at least on some systems).
+        * Fix class to be PCI_CLASS_STORAGE_SCSI
+        */
+       if (!d->class) {
+               printk(KERN_WARNING "PCI: fixing NCR 53C810 class code for %s\n", d->slot_name);
+               d->class = PCI_CLASS_STORAGE_SCSI << 8;
+       }
+}
+
+static void __devinit pci_fixup_ide_bases(struct pci_dev *d)
+{
+       int i;
+
+       /*
+        * PCI IDE controllers use non-standard I/O port decoding, respect it.
+        */
+       if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+               return;
+       DBG("PCI: IDE base address fixup for %s\n", d->slot_name);
+       for(i=0; i<4; i++) {
+               struct resource *r = &d->resource[i];
+               if ((r->start & ~0x80) == 0x374) {
+                       r->start |= 2;
+                       r->end = r->start;
+               }
+       }
+}
+
+static void __devinit  pci_fixup_ide_trash(struct pci_dev *d)
+{
+       int i;
+
+       /*
+        * There exist PCI IDE controllers which have utter garbage
+        * in first four base registers. Ignore that.
+        */
+       DBG("PCI: IDE base address trash cleared for %s\n", d->slot_name);
+       for(i=0; i<4; i++)
+               d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0;
+}
+
+static void __devinit  pci_fixup_latency(struct pci_dev *d)
+{
+       /*
+        *  SiS 5597 and 5598 chipsets require latency timer set to
+        *  at most 32 to avoid lockups.
+        */
+       DBG("PCI: Setting max latency to 32\n");
+       pcibios_max_latency = 32;
+}
+
+static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d)
+{
+       /*
+        * PIIX4 ACPI device: hardwired IRQ9
+        */
+       d->irq = 9;
+}
+
+/*
+ * Addresses issues with problems in the memory write queue timer in
+ * certain VIA Northbridges.  This bugfix is per VIA's specifications.
+ *
+ * VIA 8363,8622,8361 Northbridges:
+ *  - bits  5, 6, 7 at offset 0x55 need to be turned off
+ * VIA 8367 (KT266x) Northbridges:
+ *  - bits  5, 6, 7 at offset 0x95 need to be turned off
+ */
+static void __init pci_fixup_via_northbridge_bug(struct pci_dev *d)
+{
+       u8 v;
+       int where = 0x55;
+
+       if (d->device == PCI_DEVICE_ID_VIA_8367_0) {
+               where = 0x95; /* the memory write queue timer register is 
+                                 different for the kt266x's: 0x95 not 0x55 */
+       }
+
+        pci_read_config_byte(d, where, &v);
+       if (v & 0xe0) {
+               printk(KERN_WARNING "Disabling broken memory write queue: [%02x] %02x->%02x\n",
+                       where, v, v & 0x1f);
+               v &= 0x1f; /* clear bits 5, 6, 7 */
+               pci_write_config_byte(d, where, v);
+       }
+}
+
+struct pci_fixup pcibios_fixups[] = {
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82451NX,    pci_fixup_i450nx },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82454GX,    pci_fixup_i450gx },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_UMC,      PCI_DEVICE_ID_UMC_UM8886BF,     pci_fixup_umc_ide },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_SI,       PCI_DEVICE_ID_SI_5513,          pci_fixup_ide_trash },
+       { PCI_FIXUP_HEADER,     PCI_ANY_ID,             PCI_ANY_ID,                     pci_fixup_ide_bases },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_SI,       PCI_DEVICE_ID_SI_5597,          pci_fixup_latency },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_SI,       PCI_DEVICE_ID_SI_5598,          pci_fixup_latency },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82371AB_3,  pci_fixup_piix4_acpi },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_8363_0,       pci_fixup_via_northbridge_bug },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_8622,         pci_fixup_via_northbridge_bug },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_8361,         pci_fixup_via_northbridge_bug },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_8367_0,       pci_fixup_via_northbridge_bug },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_NCR,      PCI_DEVICE_ID_NCR_53C810,       pci_fixup_ncr53c810 },
+       { 0 }
+};
diff --git a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c
new file mode 100644 (file)
index 0000000..27a14f0
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ *     Low-Level PCI Access for i386 machines
+ *
+ * Copyright 1993, 1994 Drew Eckhardt
+ *      Visionary Computing
+ *      (Unix and Linux consulting and custom programming)
+ *      Drew@Colorado.EDU
+ *      +1 (303) 786-7975
+ *
+ * Drew's work was sponsored by:
+ *     iX Multiuser Multitasking Magazine
+ *     Hannover, Germany
+ *     hm@ix.de
+ *
+ * Copyright 1997--2000 Martin Mares <mj@ucw.cz>
+ *
+ * For more information, please consult the following manuals (look at
+ * http://www.pcisig.com/ for how to get them):
+ *
+ * PCI BIOS Specification
+ * PCI Local Bus Specification
+ * PCI to PCI Bridge Specification
+ * PCI System Design Guide
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+
+#include "pci.h"
+
+void
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+                       struct resource *res, int resource)
+{
+       u32 new, check;
+       int reg;
+
+       new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
+       if (resource < 6) {
+               reg = PCI_BASE_ADDRESS_0 + 4*resource;
+       } else if (resource == PCI_ROM_RESOURCE) {
+               res->flags |= PCI_ROM_ADDRESS_ENABLE;
+               new |= PCI_ROM_ADDRESS_ENABLE;
+               reg = dev->rom_base_reg;
+       } else {
+               /* Somebody might have asked allocation of a non-standard resource */
+               return;
+       }
+       
+       pci_write_config_dword(dev, reg, new);
+       pci_read_config_dword(dev, reg, &check);
+       if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
+               printk(KERN_ERR "PCI: Error while updating region "
+                      "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
+                      new, check);
+       }
+}
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ *
+ * Why? Because some silly external IO cards only decode
+ * the low 10 bits of the IO address. The 0x00-0xff region
+ * is reserved for motherboard devices that decode all 16
+ * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
+ * but we want to try to avoid allocating at 0x2900-0x2bff
+ * which might have be mirrored at 0x0100-0x03ff..
+ */
+void
+pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+{
+       if (res->flags & IORESOURCE_IO) {
+               unsigned long start = res->start;
+
+               if (start & 0x300) {
+                       start = (start + 0x3ff) & ~0x3ff;
+                       res->start = start;
+               }
+       }
+}
+
+
+/*
+ *  Handle resources of PCI devices.  If the world were perfect, we could
+ *  just allocate all the resource regions and do nothing more.  It isn't.
+ *  On the other hand, we cannot just re-allocate all devices, as it would
+ *  require us to know lots of host bridge internals.  So we attempt to
+ *  keep as much of the original configuration as possible, but tweak it
+ *  when it's found to be wrong.
+ *
+ *  Known BIOS problems we have to work around:
+ *     - I/O or memory regions not configured
+ *     - regions configured, but not enabled in the command register
+ *     - bogus I/O addresses above 64K used
+ *     - expansion ROMs left enabled (this may sound harmless, but given
+ *       the fact the PCI specs explicitly allow address decoders to be
+ *       shared between expansion ROMs and other resource regions, it's
+ *       at least dangerous)
+ *
+ *  Our solution:
+ *     (1) Allocate resources for all buses behind PCI-to-PCI bridges.
+ *         This gives us fixed barriers on where we can allocate.
+ *     (2) Allocate resources for all enabled devices.  If there is
+ *         a collision, just mark the resource as unallocated. Also
+ *         disable expansion ROMs during this step.
+ *     (3) Try to allocate resources for disabled devices.  If the
+ *         resources were assigned correctly, everything goes well,
+ *         if they weren't, they won't disturb allocation of other
+ *         resources.
+ *     (4) Assign new addresses to resources which were either
+ *         not configured at all or misconfigured.  If explicitly
+ *         requested by the user, configure expansion ROM address
+ *         as well.
+ */
+
+static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
+{
+       struct list_head *ln;
+       struct pci_bus *bus;
+       struct pci_dev *dev;
+       int idx;
+       struct resource *r, *pr;
+
+       /* Depth-First Search on bus tree */
+       for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+               bus = pci_bus_b(ln);
+               if ((dev = bus->self)) {
+                       for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
+                               r = &dev->resource[idx];
+                               if (!r->start)
+                                       continue;
+                               pr = pci_find_parent_resource(dev, r);
+                               if (!pr || request_resource(pr, r) < 0)
+                                       printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
+                       }
+               }
+               pcibios_allocate_bus_resources(&bus->children);
+       }
+}
+
+static void __init pcibios_allocate_resources(int pass)
+{
+       struct pci_dev *dev;
+       int idx, disabled;
+       u16 command;
+       struct resource *r, *pr;
+
+       pci_for_each_dev(dev) {
+               pci_read_config_word(dev, PCI_COMMAND, &command);
+               for(idx = 0; idx < 6; idx++) {
+                       r = &dev->resource[idx];
+                       if (r->parent)          /* Already allocated */
+                               continue;
+                       if (!r->start)          /* Address not assigned at all */
+                               continue;
+                       if (r->flags & IORESOURCE_IO)
+                               disabled = !(command & PCI_COMMAND_IO);
+                       else
+                               disabled = !(command & PCI_COMMAND_MEMORY);
+                       if (pass == disabled) {
+                               DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
+                                   r->start, r->end, r->flags, disabled, pass);
+                               pr = pci_find_parent_resource(dev, r);
+                               if (!pr || request_resource(pr, r) < 0) {
+                                       printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name);
+                                       /* We'll assign a new address later */
+                                       r->end -= r->start;
+                                       r->start = 0;
+                               }
+                       }
+               }
+               if (!pass) {
+                       r = &dev->resource[PCI_ROM_RESOURCE];
+                       if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
+                               /* Turn the ROM off, leave the resource region, but keep it unregistered. */
+                               u32 reg;
+                               DBG("PCI: Switching off ROM of %s\n", dev->slot_name);
+                               r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
+                               pci_read_config_dword(dev, dev->rom_base_reg, &reg);
+                               pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
+                       }
+               }
+       }
+}
+
+static void __init pcibios_assign_resources(void)
+{
+       struct pci_dev *dev;
+       int idx;
+       struct resource *r;
+
+       pci_for_each_dev(dev) {
+               int class = dev->class >> 8;
+
+               /* Don't touch classless devices and host bridges */
+               if (!class || class == PCI_CLASS_BRIDGE_HOST)
+                       continue;
+
+               for(idx=0; idx<6; idx++) {
+                       r = &dev->resource[idx];
+
+                       /*
+                        *  Don't touch IDE controllers and I/O ports of video cards!
+                        */
+                       if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
+                           (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
+                               continue;
+
+                       /*
+                        *  We shall assign a new address to this resource, either because
+                        *  the BIOS forgot to do so or because we have decided the old
+                        *  address was unusable for some reason.
+                        */
+                       if (!r->start && r->end)
+                               pci_assign_resource(dev, idx);
+               }
+
+               if (pci_probe & PCI_ASSIGN_ROMS) {
+                       r = &dev->resource[PCI_ROM_RESOURCE];
+                       r->end -= r->start;
+                       r->start = 0;
+                       if (r->end)
+                               pci_assign_resource(dev, PCI_ROM_RESOURCE);
+               }
+       }
+}
+
+void __init pcibios_resource_survey(void)
+{
+       DBG("PCI: Allocating resources\n");
+       pcibios_allocate_bus_resources(&pci_root_buses);
+       pcibios_allocate_resources(0);
+       pcibios_allocate_resources(1);
+       pcibios_assign_resources();
+}
+
+int pcibios_enable_resources(struct pci_dev *dev)
+{
+       u16 cmd, old_cmd;
+       int idx;
+       struct resource *r;
+
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       old_cmd = cmd;
+       for(idx=0; idx<6; idx++) {
+               r = &dev->resource[idx];
+               if (!r->start && r->end) {
+                       printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
+                       return -EINVAL;
+               }
+               if (r->flags & IORESOURCE_IO)
+                       cmd |= PCI_COMMAND_IO;
+               if (r->flags & IORESOURCE_MEM)
+                       cmd |= PCI_COMMAND_MEMORY;
+       }
+       if (dev->resource[PCI_ROM_RESOURCE].start)
+               cmd |= PCI_COMMAND_MEMORY;
+       if (cmd != old_cmd) {
+               printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
+       return 0;
+}
+
+/*
+ *  If we set up a device for bus mastering, we need to check the latency
+ *  timer as certain crappy BIOSes forget to set it properly.
+ */
+unsigned int pcibios_max_latency = 255;
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+       u8 lat;
+       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+       if (lat < 16)
+               lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+       else if (lat > pcibios_max_latency)
+               lat = pcibios_max_latency;
+       else
+               return;
+       printk("PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
+
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+                       enum pci_mmap_state mmap_state, int write_combine)
+{
+       unsigned long prot;
+
+       /* I/O space cannot be accessed via normal processor loads and
+        * stores on this platform.
+        */
+       if (mmap_state == pci_mmap_io)
+               return -EINVAL;
+
+       /* Leave vm_pgoff as-is, the PCI space address is the physical
+        * address on this platform.
+        */
+       vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
+
+       prot = pgprot_val(vma->vm_page_prot);
+       if (boot_cpu_data.x86 > 3)
+               prot |= _PAGE_PCD | _PAGE_PWT;
+       vma->vm_page_prot = __pgprot(prot);
+
+       /* Write-combine setting is ignored, it is changed via the mtrr
+        * interfaces on this platform.
+        */
+       if (remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+                            vma->vm_end - vma->vm_start,
+                            vma->vm_page_prot))
+               return -EAGAIN;
+
+       return 0;
+}
diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c
new file mode 100644 (file)
index 0000000..68eb183
--- /dev/null
@@ -0,0 +1,810 @@
+/*
+ *     Low-Level PCI Support for PC -- Routing of Interrupts
+ *
+ *     (c) 1999--2000 Martin Mares <mj@ucw.cz>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/acpi.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/io_apic.h>
+
+#include "pci.h"
+
+#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
+#define PIRQ_VERSION 0x0100
+
+int pci_use_acpi_routing = 0;
+int broken_hp_bios_irq9;
+
+static struct irq_routing_table *pirq_table;
+
+/*
+ * Never use: 0, 1, 2 (timer, keyboard, and cascade)
+ * Avoid using: 13, 14 and 15 (FP error and IDE).
+ * Penalize: 3, 4, 6, 7, 12 (known ISA uses: serial, floppy, parallel and mouse)
+ */
+unsigned int pcibios_irq_mask = 0xfff8;
+
+static int pirq_penalty[16] = {
+       1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000,
+       0, 0, 0, 0, 1000, 100000, 100000, 100000
+};
+
+struct irq_router {
+       char *name;
+       u16 vendor, device;
+       int (*get)(struct pci_dev *router, struct pci_dev *dev, int pirq);
+       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.
+ */
+
+static struct irq_routing_table * __init pirq_find_routing_table(void)
+{
+       u8 *addr;
+       struct irq_routing_table *rt;
+       int i;
+       u8 sum;
+
+       for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
+               rt = (struct irq_routing_table *) addr;
+               if (rt->signature != PIRQ_SIGNATURE ||
+                   rt->version != PIRQ_VERSION ||
+                   rt->size % 16 ||
+                   rt->size < sizeof(struct irq_routing_table))
+                       continue;
+               sum = 0;
+               for(i=0; i<rt->size; i++)
+                       sum += addr[i];
+               if (!sum) {
+                       DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt);
+                       return rt;
+               }
+       }
+       return NULL;
+}
+
+/*
+ *  If we have a IRQ routing table, use it to search for peer host
+ *  bridges.  It's a gross hack, but since there are no other known
+ *  ways how to get a list of buses, we have to go this way.
+ */
+
+static void __init pirq_peer_trick(void)
+{
+       struct irq_routing_table *rt = pirq_table;
+       u8 busmap[256];
+       int i;
+       struct irq_info *e;
+
+       memset(busmap, 0, sizeof(busmap));
+       for(i=0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) {
+               e = &rt->slots[i];
+#ifdef DEBUG
+               {
+                       int j;
+                       DBG("%02x:%02x slot=%02x", e->bus, e->devfn/8, e->slot);
+                       for(j=0; j<4; j++)
+                               DBG(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap);
+                       DBG("\n");
+               }
+#endif
+               busmap[e->bus] = 1;
+       }
+       for(i=1; i<256; i++)
+               /*
+                *  It might be a secondary bus, but in this case its parent is already
+                *  known (ascending bus order) and therefore pci_scan_bus returns immediately.
+                */
+               if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL))
+                       printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i);
+       pcibios_last_bus = -1;
+}
+
+/*
+ *  Code for querying and setting of IRQ routes on various interrupt routers.
+ */
+
+void eisa_set_level_irq(unsigned int irq)
+{
+       unsigned char mask = 1 << (irq & 7);
+       unsigned int port = 0x4d0 + (irq >> 3);
+       unsigned char val = inb(port);
+
+       if (!(val & mask)) {
+               DBG(" -> edge");
+               outb(val | mask, port);
+       }
+}
+
+/*
+ * Common IRQ routing practice: nybbles in config space,
+ * offset by some magic constant.
+ */
+static unsigned int read_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr)
+{
+       u8 x;
+       unsigned reg = offset + (nr >> 1);
+
+       pci_read_config_byte(router, reg, &x);
+       return (nr & 1) ? (x >> 4) : (x & 0xf);
+}
+
+static void write_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr, unsigned int val)
+{
+       u8 x;
+       unsigned reg = offset + (nr >> 1);
+
+       pci_read_config_byte(router, reg, &x);
+       x = (nr & 1) ? ((x & 0x0f) | (val << 4)) : ((x & 0xf0) | val);
+       pci_write_config_byte(router, reg, x);
+}
+
+/*
+ * ALI pirq entries are damn ugly, and completely undocumented.
+ * This has been figured out from pirq tables, and it's not a pretty
+ * picture.
+ */
+static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+       static unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
+
+       return irqmap[read_config_nybble(router, 0x48, pirq-1)];
+}
+
+static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+       static unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
+       unsigned int val = irqmap[irq];
+               
+       if (val) {
+               write_config_nybble(router, 0x48, pirq-1, val);
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * The Intel PIIX4 pirq rules are fairly simple: "pirq" is
+ * just a pointer to the config space.
+ */
+static int pirq_piix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+       u8 x;
+
+       pci_read_config_byte(router, pirq, &x);
+       return (x < 16) ? x : 0;
+}
+
+static int pirq_piix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+       pci_write_config_byte(router, pirq, irq);
+       return 1;
+}
+
+/*
+ * The VIA pirq rules are nibble-based, like ALI,
+ * but without the ugly irq number munging.
+ */
+static int pirq_via_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+       return read_config_nybble(router, 0x55, pirq);
+}
+
+static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+       write_config_nybble(router, 0x55, pirq, irq);
+       return 1;
+}
+
+/*
+ * ITE 8330G pirq rules are nibble-based
+ * FIXME: pirqmap may be { 1, 0, 3, 2 },
+ *       2+3 are both mapped to irq 9 on my system
+ */
+static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+       static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
+       return read_config_nybble(router,0x43, pirqmap[pirq-1]);
+}
+
+static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+       static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
+       write_config_nybble(router, 0x43, pirqmap[pirq-1], irq);
+       return 1;
+}
+
+/*
+ * OPTI: high four bits are nibble pointer..
+ * I wonder what the low bits do?
+ */
+static int pirq_opti_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+       return read_config_nybble(router, 0xb8, pirq >> 4);
+}
+
+static int pirq_opti_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+       write_config_nybble(router, 0xb8, pirq >> 4, irq);
+       return 1;
+}
+
+/*
+ * Cyrix: nibble offset 0x5C
+ */
+static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+       return read_config_nybble(router, 0x5C, (pirq-1)^1);
+}
+
+static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+       write_config_nybble(router, 0x5C, (pirq-1)^1, irq);
+       return 1;
+}
+
+/*
+ *     PIRQ routing for SiS 85C503 router used in several SiS chipsets
+ *     According to the SiS 5595 datasheet (preliminary V1.0, 12/24/1997)
+ *     the related registers work as follows:
+ *     
+ *     general: one byte per re-routable IRQ,
+ *              bit 7      IRQ mapping enabled (0) or disabled (1)
+ *              bits [6:4] reserved
+ *              bits [3:0] IRQ to map to
+ *                  allowed: 3-7, 9-12, 14-15
+ *                  reserved: 0, 1, 2, 8, 13
+ *
+ *     individual registers in device config space:
+ *
+ *     0x41/0x42/0x43/0x44:    PCI INT A/B/C/D - bits as in general case
+ *
+ *     0x61:                   IDEIRQ: bits as in general case - but:
+ *                             bits [6:5] must be written 01
+ *                             bit 4 channel-select primary (0), secondary (1)
+ *
+ *     0x62:                   USBIRQ: bits as in general case - but:
+ *                             bit 4 OHCI function disabled (0), enabled (1)
+ *     
+ *     0x6a:                   ACPI/SCI IRQ - bits as in general case
+ *
+ *     0x7e:                   Data Acq. Module IRQ - bits as in general case
+ *
+ *     Apparently there are systems implementing PCI routing table using both
+ *     link values 0x01-0x04 and 0x41-0x44 for PCI INTA..D, but register offsets
+ *     like 0x62 as link values for USBIRQ e.g. So there is no simple
+ *     "register = offset + pirq" relation.
+ *     Currently we support PCI INTA..D and USBIRQ and try our best to handle
+ *     both link mappings.
+ *     IDE/ACPI/DAQ mapping is currently unsupported (left untouched as set by BIOS).
+ */
+
+static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+       u8 x;
+       int reg = pirq;
+
+       switch(pirq) {
+               case 0x01:
+               case 0x02:
+               case 0x03:
+               case 0x04:
+                       reg += 0x40;
+               case 0x41:
+               case 0x42:
+               case 0x43:
+               case 0x44:
+               case 0x62:
+                       pci_read_config_byte(router, reg, &x);
+                       if (reg != 0x62)
+                               break;
+                       if (!(x & 0x40))
+                               return 0;
+                       break;
+               case 0x61:
+               case 0x6a:
+               case 0x7e:
+                       printk(KERN_INFO "SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n");
+                       return 0;
+               default:                        
+                       printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
+                       return 0;
+       }
+       return (x & 0x80) ? 0 : (x & 0x0f);
+}
+
+static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+       u8 x;
+       int reg = pirq;
+
+       switch(pirq) {
+               case 0x01:
+               case 0x02:
+               case 0x03:
+               case 0x04:
+                       reg += 0x40;
+               case 0x41:
+               case 0x42:
+               case 0x43:
+               case 0x44:
+               case 0x62:
+                       x = (irq&0x0f) ? (irq&0x0f) : 0x80;
+                       if (reg != 0x62)
+                               break;
+                       /* always mark OHCI enabled, as nothing else knows about this */
+                       x |= 0x40;
+                       break;
+               case 0x61:
+               case 0x6a:
+               case 0x7e:
+                       printk(KERN_INFO "advanced SiS pirq mapping not yet implemented\n");
+                       return 0;
+               default:                        
+                       printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
+                       return 0;
+       }
+       pci_write_config_byte(router, reg, x);
+
+       return 1;
+}
+
+/*
+ * VLSI: nibble offset 0x74 - educated guess due to routing table and
+ *       config space of VLSI 82C534 PCI-bridge/router (1004:0102)
+ *       Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard
+ *       devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6
+ *       for the busbridge to the docking station.
+ */
+
+static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+       if (pirq > 8) {
+               printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
+               return 0;
+       }
+       return read_config_nybble(router, 0x74, pirq-1);
+}
+
+static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+       if (pirq > 8) {
+               printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
+               return 0;
+       }
+       write_config_nybble(router, 0x74, pirq-1, irq);
+       return 1;
+}
+
+/*
+ * ServerWorks: PCI interrupts mapped to system IRQ lines through Index
+ * and Redirect I/O registers (0x0c00 and 0x0c01).  The Index register
+ * format is (PCIIRQ## | 0x10), e.g.: PCIIRQ10=0x1a.  The Redirect
+ * register is a straight binary coding of desired PIC IRQ (low nibble).
+ *
+ * The 'link' value in the PIRQ table is already in the correct format
+ * for the Index register.  There are some special index values:
+ * 0x00 for ACPI (SCI), 0x01 for USB, 0x02 for IDE0, 0x04 for IDE1,
+ * and 0x03 for SMBus.
+ */
+static int pirq_serverworks_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+       outb_p(pirq, 0xc00);
+       return inb(0xc01) & 0xf;
+}
+
+static int pirq_serverworks_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+       outb_p(pirq, 0xc00);
+       outb_p(irq, 0xc01);
+       return 1;
+}
+
+/* Support for AMD756 PCI IRQ Routing
+ * Jhon H. Caicedo <jhcaiced@osso.org.co>
+ * Jun/21/2001 0.2.0 Release, fixed to use "nybble" functions... (jhcaiced)
+ * Jun/19/2001 Alpha Release 0.1.0 (jhcaiced)
+ * The AMD756 pirq rules are nibble-based
+ * offset 0x56 0-3 PIRQA  4-7  PIRQB
+ * offset 0x57 0-3 PIRQC  4-7  PIRQD
+ */
+static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+       u8 irq;
+       irq = 0;
+       if (pirq <= 4)
+       {
+               irq = read_config_nybble(router, 0x56, pirq - 1);
+       }
+       printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n",
+               dev->vendor, dev->device, pirq, irq);
+       return irq;
+}
+
+static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+       printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n", 
+               dev->vendor, dev->device, pirq, irq);
+       if (pirq <= 4)
+       {
+               write_config_nybble(router, 0x56, pirq - 1, irq);
+       }
+       return 1;
+}
+
+#ifdef CONFIG_PCI_BIOS
+
+static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+       struct pci_dev *bridge;
+       int pin = pci_get_interrupt_pin(dev, &bridge);
+       return pcibios_set_irq_routing(bridge, pin, irq);
+}
+
+static struct irq_router pirq_bios_router =
+       { "BIOS", 0, 0, NULL, pirq_bios_set };
+
+#endif
+
+static struct irq_router pirq_routers[] = {
+       { "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_82371MX,   pirq_piix_get, pirq_piix_set },
+       { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
+       { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, pirq_piix_get, pirq_piix_set },
+       { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, pirq_piix_get, pirq_piix_set },
+       { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set },
+       { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, pirq_piix_get, pirq_piix_set },
+       { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, pirq_piix_get, pirq_piix_set },
+       { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, pirq_piix_get, pirq_piix_set },
+
+       { "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
+
+       { "ITE", PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8330G_0, pirq_ite_get, pirq_ite_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 },
+       { "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, pirq_via_get, pirq_via_set },
+
+       { "OPTI", PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C700, pirq_opti_get, pirq_opti_set },
+
+       { "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set },
+       { "SIS", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, pirq_sis_get, pirq_sis_set },
+       { "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set },
+       { "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4,
+         pirq_serverworks_get, pirq_serverworks_set },
+       { "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5,
+         pirq_serverworks_get, pirq_serverworks_set },
+       { "AMD756 VIPER", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B,
+               pirq_amd756_get, pirq_amd756_set },
+
+       { "default", 0, 0, NULL, NULL }
+};
+
+static struct irq_router *pirq_router;
+static struct pci_dev *pirq_router_dev;
+
+static void __init pirq_find_router(void)
+{
+       struct irq_routing_table *rt = pirq_table;
+       struct irq_router *r;
+
+#ifdef CONFIG_PCI_BIOS
+       if (!rt->signature) {
+               printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n");
+               pirq_router = &pirq_bios_router;
+               return;
+       }
+#endif
+
+       DBG("PCI: Attempting to find IRQ router for %04x:%04x\n",
+           rt->rtr_vendor, rt->rtr_device);
+
+       /* fall back to default router if nothing else found */
+       pirq_router = &pirq_routers[ARRAY_SIZE(pirq_routers) - 1];
+
+       pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn);
+       if (!pirq_router_dev) {
+               DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
+               return;
+       }
+
+       for(r=pirq_routers; r->vendor; r++) {
+               /* Exact match against router table entry? Use it! */
+               if (r->vendor == rt->rtr_vendor && r->device == rt->rtr_device) {
+                       pirq_router = r;
+                       break;
+               }
+               /* Match against router device entry? Use it as a fallback */
+               if (r->vendor == pirq_router_dev->vendor && r->device == pirq_router_dev->device) {
+                       pirq_router = r;
+               }
+       }
+       printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n",
+               pirq_router->name,
+               pirq_router_dev->vendor,
+               pirq_router_dev->device,
+               pirq_router_dev->slot_name);
+}
+
+static struct irq_info *pirq_get_info(struct pci_dev *dev)
+{
+       struct irq_routing_table *rt = pirq_table;
+       int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
+       struct irq_info *info;
+
+       for (info = rt->slots; entries--; info++)
+               if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn))
+                       return info;
+       return NULL;
+}
+
+static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
+{
+       u8 pin;
+       struct irq_info *info;
+       int i, pirq, newirq;
+       int irq = 0;
+       u32 mask;
+       struct irq_router *r = pirq_router;
+       struct pci_dev *dev2;
+       char *msg = NULL;
+
+       /* Find IRQ pin */
+       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+       if (!pin) {
+               DBG(" -> no interrupt pin\n");
+               return 0;
+       }
+       pin = pin - 1;
+
+       /* Find IRQ routing entry */
+
+       if (!pirq_table)
+               return 0;
+       
+       DBG("IRQ for %s:%d", dev->slot_name, pin);
+       info = pirq_get_info(dev);
+       if (!info) {
+               DBG(" -> not found in routing table\n");
+               return 0;
+       }
+       pirq = info->irq[pin].link;
+       mask = info->irq[pin].bitmap;
+       if (!pirq) {
+               DBG(" -> not routed\n");
+               return 0;
+       }
+       DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
+       mask &= pcibios_irq_mask;
+
+       /* Work around broken HP Pavilion Notebooks which assign USB to
+          IRQ 9 even though it is actually wired to IRQ 11 */
+
+       if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) {
+               dev->irq = 11;
+               pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
+               r->set(pirq_router_dev, dev, pirq, 11);
+       }
+
+       /*
+        * Find the best IRQ to assign: use the one
+        * reported by the device if possible.
+        */
+       newirq = dev->irq;
+       if (!((1 << newirq) & mask)) {
+               if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0;
+               else printk(KERN_WARNING "PCI: IRQ %i for device %s doesn't match PIRQ mask - try pci=usepirqmask\n", newirq, dev->slot_name);
+       }
+       if (!newirq && 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);
+
+       /* Check if it is hardcoded */
+       if ((pirq & 0xf0) == 0xf0) {
+               irq = pirq & 0xf;
+               DBG(" -> hardcoded IRQ %d\n", irq);
+               msg = "Hardcoded";
+       } else if ( r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \
+       ((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask)) ) {
+               DBG(" -> got IRQ %d\n", irq);
+               msg = "Found";
+       } else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
+               DBG(" -> assigning IRQ %d", newirq);
+               if (r->set(pirq_router_dev, dev, pirq, newirq)) {
+                       eisa_set_level_irq(newirq);
+                       DBG(" ... OK\n");
+                       msg = "Assigned";
+                       irq = newirq;
+               }
+       }
+
+       if (!irq) {
+               DBG(" ... failed\n");
+               if (newirq && mask == (1 << newirq)) {
+                       msg = "Guessed";
+                       irq = newirq;
+               } else
+                       return 0;
+       }
+       printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name);
+
+       /* Update IRQ for all devices with the same pirq value */
+       pci_for_each_dev(dev2) {
+               pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin);
+               if (!pin)
+                       continue;
+               pin--;
+               info = pirq_get_info(dev2);
+               if (!info)
+                       continue;
+               if (info->irq[pin].link == pirq) {
+                       /* We refuse to override the dev->irq information. Give a warning! */
+                       if ( dev2->irq && dev2->irq != irq && \
+                       (!(pci_probe & PCI_USE_PIRQ_MASK) || \
+                       ((1 << dev2->irq) & mask)) ) {
+                               printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n",
+                                      dev2->slot_name, dev2->irq, irq);
+                               continue;
+                       }
+                       dev2->irq = irq;
+                       pirq_penalty[irq]++;
+                       if (dev != dev2)
+                               printk(KERN_INFO "PCI: Sharing IRQ %d with %s\n", irq, dev2->slot_name);
+               }
+       }
+       return 1;
+}
+
+static int __init pcibios_irq_init(void)
+{
+       DBG("PCI: IRQ init\n");
+
+       if (pci_lookup_irq)
+               return 0;
+
+       pirq_table = pirq_find_routing_table();
+
+#ifdef CONFIG_PCI_BIOS
+       if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
+               pirq_table = pcibios_get_irq_routing_table();
+#endif
+       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;
+       }
+       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;
+       u8 pin;
+
+       DBG("PCI: IRQ fixup\n");
+       pci_for_each_dev(dev) {
+               /*
+                * If the BIOS has set an out of range IRQ number, just ignore it.
+                * Also keep track of which IRQ's are already in use.
+                */
+               if (dev->irq >= 16) {
+                       DBG("%s: ignoring bogus IRQ %d\n", dev->slot_name, dev->irq);
+                       dev->irq = 0;
+               }
+               /* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */
+               if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000)
+                       pirq_penalty[dev->irq] = 0;
+               pirq_penalty[dev->irq]++;
+       }
+
+       pci_for_each_dev(dev) {
+               pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+#ifdef CONFIG_X86_IO_APIC
+               /*
+                * Recalculate IRQ numbers if we use the I/O APIC.
+                */
+               if (io_apic_assign_pci_irqs)
+               {
+                       int irq;
+
+                       if (pin) {
+                               pin--;          /* interrupt pins are numbered starting from 1 */
+                               irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
+       /*
+        * Busses behind bridges are typically not listed in the MP-table.
+        * In this case we have to look up the IRQ based on the parent bus,
+        * parent slot, and pin number. The SMP code detects such bridged
+        * busses itself so we should get into this branch reliably.
+        */
+                               if (irq < 0 && dev->bus->parent) { /* go back to the bridge */
+                                       struct pci_dev * bridge = dev->bus->self;
+
+                                       pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+                                       irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, 
+                                                       PCI_SLOT(bridge->devfn), pin);
+                                       if (irq >= 0)
+                                               printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", 
+                                                       bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);
+                               }
+                               if (irq >= 0) {
+                                       printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
+                                               dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
+                                       dev->irq = irq;
+                               }
+                       }
+               }
+#endif
+               /*
+                * Still no IRQ? Try to lookup one...
+                */
+               if (pin && !dev->irq)
+                       pci_lookup_irq(dev, 0);
+       }
+}
+
+void 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)
+{
+       u8 pin;
+       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+       if (pin && !pci_lookup_irq(dev, 1) && !dev->irq) {
+               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);
+       }
+}
diff --git a/arch/i386/pci/legacy.c b/arch/i386/pci/legacy.c
new file mode 100644 (file)
index 0000000..4e4510e
--- /dev/null
@@ -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(KERN_INFO "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/pci/numa.c b/arch/i386/pci/numa.c
new file mode 100644 (file)
index 0000000..ad3fcb3
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * numa.c - Low-level PCI access for NUMA-Q machines
+ */
+#include <linux/pci.h>
+
+#include "pci.h"
+
+#define BUS2QUAD(global) (mp_bus_id_to_node[global])
+#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
+#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
+
+#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)
+{
+       unsigned long flags;
+
+       if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+               return -EINVAL;
+
+       spin_lock_irqsave(&pci_config_lock, flags);
+
+       outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus));
+
+       switch (len) {
+       case 1:
+               *value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus));
+               break;
+       case 2:
+               *value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus));
+               break;
+       case 4:
+               *value = inl_quad(0xCFC, BUS2QUAD(bus));
+               break;
+       }
+
+       spin_unlock_irqrestore(&pci_config_lock, flags);
+
+       return 0;
+}
+
+static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
+{
+       unsigned long flags;
+
+       if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+               return -EINVAL;
+
+       spin_lock_irqsave(&pci_config_lock, flags);
+
+       outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus));
+
+       switch (len) {
+       case 1:
+               outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus));
+               break;
+       case 2:
+               outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus));
+               break;
+       case 4:
+               outl_quad((u32)value, 0xCFC, BUS2QUAD(bus));
+               break;
+       }
+
+       spin_unlock_irqrestore(&pci_config_lock, flags);
+
+       return 0;
+}
+
+
+static void __devinit pci_fixup_i450nx(struct pci_dev *d)
+{
+       /*
+        * i450NX -- Find and scan all secondary buses on all PXB's.
+        */
+       int pxb, reg;
+       u8 busno, suba, subb;
+       int quad = BUS2QUAD(d->bus->number);
+
+       printk("PCI: Searching for i450NX host bridges on %s\n", d->slot_name);
+       reg = 0xd0;
+       for(pxb=0; pxb<2; pxb++) {
+               pci_read_config_byte(d, reg++, &busno);
+               pci_read_config_byte(d, reg++, &suba);
+               pci_read_config_byte(d, reg++, &subb);
+               DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
+               if (busno)
+                       pci_scan_bus(QUADLOCAL2BUS(quad,busno), pci_root_ops, NULL);    /* Bus A */
+               if (suba < subb)
+                       pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), pci_root_ops, NULL);   /* Bus B */
+       }
+       pcibios_last_bus = -1;
+}
+
+struct pci_fixup pcibios_fixups[] = {
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82451NX,    pci_fixup_i450nx },
+};
+
+static int __init pci_numa_init(void)
+{
+       int quad;
+
+       pci_config_read = pci_conf1_read;
+       pci_config_write = pci_conf1_write;
+
+       pci_root_bus = pcibios_scan_root(0);
+       if (clustered_apic_mode && (numnodes > 1)) {
+               for (quad = 1; quad < numnodes; ++quad) {
+                       printk("Scanning PCI bus %d for quad %d\n", 
+                               QUADLOCAL2BUS(quad,0), quad);
+                       pci_scan_bus(QUADLOCAL2BUS(quad,0), 
+                               pci_root_ops, NULL);
+               }
+       }
+       return 0;
+}
+
+subsys_initcall(pci_numa_init);
diff --git a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c
new file mode 100644 (file)
index 0000000..c1ef996
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ * BIOS32 and PCI BIOS handling.
+ */
+
+#include <linux/pci.h>
+#include "pci.h"
+
+
+#define PCIBIOS_PCI_FUNCTION_ID        0xb1XX
+#define PCIBIOS_PCI_BIOS_PRESENT       0xb101
+#define PCIBIOS_FIND_PCI_DEVICE                0xb102
+#define PCIBIOS_FIND_PCI_CLASS_CODE    0xb103
+#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106
+#define PCIBIOS_READ_CONFIG_BYTE       0xb108
+#define PCIBIOS_READ_CONFIG_WORD       0xb109
+#define PCIBIOS_READ_CONFIG_DWORD      0xb10a
+#define PCIBIOS_WRITE_CONFIG_BYTE      0xb10b
+#define PCIBIOS_WRITE_CONFIG_WORD      0xb10c
+#define PCIBIOS_WRITE_CONFIG_DWORD     0xb10d
+#define PCIBIOS_GET_ROUTING_OPTIONS    0xb10e
+#define PCIBIOS_SET_PCI_HW_INT         0xb10f
+
+/* BIOS32 signature: "_32_" */
+#define BIOS32_SIGNATURE       (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
+
+/* PCI signature: "PCI " */
+#define PCI_SIGNATURE          (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
+
+/* PCI service signature: "$PCI" */
+#define PCI_SERVICE            (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
+
+/* PCI BIOS hardware mechanism flags */
+#define PCIBIOS_HW_TYPE1               0x01
+#define PCIBIOS_HW_TYPE2               0x02
+#define PCIBIOS_HW_TYPE1_SPEC          0x10
+#define PCIBIOS_HW_TYPE2_SPEC          0x20
+
+/*
+ * This is the standard structure used to identify the entry point
+ * to the BIOS32 Service Directory, as documented in
+ *     Standard BIOS 32-bit Service Directory Proposal
+ *     Revision 0.4 May 24, 1993
+ *     Phoenix Technologies Ltd.
+ *     Norwood, MA
+ * and the PCI BIOS specification.
+ */
+
+union bios32 {
+       struct {
+               unsigned long signature;        /* _32_ */
+               unsigned long entry;            /* 32 bit physical address */
+               unsigned char revision;         /* Revision level, 0 */
+               unsigned char length;           /* Length in paragraphs should be 01 */
+               unsigned char checksum;         /* All bytes must add up to zero */
+               unsigned char reserved[5];      /* Must be zero */
+       } fields;
+       char chars[16];
+};
+
+/*
+ * Physical address of the service directory.  I don't know if we're
+ * allowed to have more than one of these or not, so just in case
+ * we'll make pcibios_present() take a memory start parameter and store
+ * the array there.
+ */
+
+static struct {
+       unsigned long address;
+       unsigned short segment;
+} bios32_indirect = { 0, __KERNEL_CS };
+
+/*
+ * Returns the entry point for the given service, NULL on error
+ */
+
+static unsigned long bios32_service(unsigned long service)
+{
+       unsigned char return_code;      /* %al */
+       unsigned long address;          /* %ebx */
+       unsigned long length;           /* %ecx */
+       unsigned long entry;            /* %edx */
+       unsigned long flags;
+
+       __save_flags(flags); __cli();
+       __asm__("lcall *(%%edi); cld"
+               : "=a" (return_code),
+                 "=b" (address),
+                 "=c" (length),
+                 "=d" (entry)
+               : "0" (service),
+                 "1" (0),
+                 "D" (&bios32_indirect));
+       __restore_flags(flags);
+
+       switch (return_code) {
+               case 0:
+                       return address + entry;
+               case 0x80:      /* Not present */
+                       printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service);
+                       return 0;
+               default: /* Shouldn't happen */
+                       printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n",
+                               service, return_code);
+                       return 0;
+       }
+}
+
+static struct {
+       unsigned long address;
+       unsigned short segment;
+} pci_indirect = { 0, __KERNEL_CS };
+
+static int pci_bios_present;
+
+static int __devinit check_pcibios(void)
+{
+       u32 signature, eax, ebx, ecx;
+       u8 status, major_ver, minor_ver, hw_mech;
+       unsigned long flags, pcibios_entry;
+
+       if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
+               pci_indirect.address = pcibios_entry + PAGE_OFFSET;
+
+               __save_flags(flags); __cli();
+               __asm__(
+                       "lcall *(%%edi); cld\n\t"
+                       "jc 1f\n\t"
+                       "xor %%ah, %%ah\n"
+                       "1:"
+                       : "=d" (signature),
+                         "=a" (eax),
+                         "=b" (ebx),
+                         "=c" (ecx)
+                       : "1" (PCIBIOS_PCI_BIOS_PRESENT),
+                         "D" (&pci_indirect)
+                       : "memory");
+               __restore_flags(flags);
+
+               status = (eax >> 8) & 0xff;
+               hw_mech = eax & 0xff;
+               major_ver = (ebx >> 8) & 0xff;
+               minor_ver = ebx & 0xff;
+               if (pcibios_last_bus < 0)
+                       pcibios_last_bus = ecx & 0xff;
+               DBG("PCI: BIOS probe returned s=%02x hw=%02x ver=%02x.%02x l=%02x\n",
+                       status, hw_mech, major_ver, minor_ver, pcibios_last_bus);
+               if (status || signature != PCI_SIGNATURE) {
+                       printk (KERN_ERR "PCI: BIOS BUG #%x[%08x] found\n",
+                               status, signature);
+                       return 0;
+               }
+               printk(KERN_INFO "PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n",
+                       major_ver, minor_ver, pcibios_entry, pcibios_last_bus);
+#ifdef CONFIG_PCI_DIRECT
+               if (!(hw_mech & PCIBIOS_HW_TYPE1))
+                       pci_probe &= ~PCI_PROBE_CONF1;
+               if (!(hw_mech & PCIBIOS_HW_TYPE2))
+                       pci_probe &= ~PCI_PROBE_CONF2;
+#endif
+               return 1;
+       }
+       return 0;
+}
+
+static int __devinit pci_bios_find_device (unsigned short vendor, unsigned short device_id,
+                                       unsigned short index, unsigned char *bus, unsigned char *device_fn)
+{
+       unsigned short bx;
+       unsigned short ret;
+
+       __asm__("lcall *(%%edi); cld\n\t"
+               "jc 1f\n\t"
+               "xor %%ah, %%ah\n"
+               "1:"
+               : "=b" (bx),
+                 "=a" (ret)
+               : "1" (PCIBIOS_FIND_PCI_DEVICE),
+                 "c" (device_id),
+                 "d" (vendor),
+                 "S" ((int) index),
+                 "D" (&pci_indirect));
+       *bus = (bx >> 8) & 0xff;
+       *device_fn = bx & 0xff;
+       return (int) (ret & 0xff00) >> 8;
+}
+
+static int pci_bios_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
+{
+       unsigned long result = 0;
+       unsigned long flags;
+       unsigned long bx = ((bus << 8) | (dev << 3) | fn);
+
+       if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+               return -EINVAL;
+
+       spin_lock_irqsave(&pci_config_lock, flags);
+
+       switch (len) {
+       case 1:
+               __asm__("lcall *(%%esi); cld\n\t"
+                       "jc 1f\n\t"
+                       "xor %%ah, %%ah\n"
+                       "1:"
+                       : "=c" (*value),
+                         "=a" (result)
+                       : "1" (PCIBIOS_READ_CONFIG_BYTE),
+                         "b" (bx),
+                         "D" ((long)reg),
+                         "S" (&pci_indirect));
+               break;
+       case 2:
+               __asm__("lcall *(%%esi); cld\n\t"
+                       "jc 1f\n\t"
+                       "xor %%ah, %%ah\n"
+                       "1:"
+                       : "=c" (*value),
+                         "=a" (result)
+                       : "1" (PCIBIOS_READ_CONFIG_WORD),
+                         "b" (bx),
+                         "D" ((long)reg),
+                         "S" (&pci_indirect));
+               break;
+       case 4:
+               __asm__("lcall *(%%esi); cld\n\t"
+                       "jc 1f\n\t"
+                       "xor %%ah, %%ah\n"
+                       "1:"
+                       : "=c" (*value),
+                         "=a" (result)
+                       : "1" (PCIBIOS_READ_CONFIG_DWORD),
+                         "b" (bx),
+                         "D" ((long)reg),
+                         "S" (&pci_indirect));
+               break;
+       }
+
+       spin_unlock_irqrestore(&pci_config_lock, flags);
+
+       return (int)((result & 0xff00) >> 8);
+}
+
+static int pci_bios_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
+{
+       unsigned long result = 0;
+       unsigned long flags;
+       unsigned long bx = ((bus << 8) | (dev << 3) | fn);
+
+       if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+               return -EINVAL;
+
+       spin_lock_irqsave(&pci_config_lock, flags);
+
+       switch (len) {
+       case 1:
+               __asm__("lcall *(%%esi); cld\n\t"
+                       "jc 1f\n\t"
+                       "xor %%ah, %%ah\n"
+                       "1:"
+                       : "=a" (result)
+                       : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
+                         "c" (value),
+                         "b" (bx),
+                         "D" ((long)reg),
+                         "S" (&pci_indirect));
+               break;
+       case 2:
+               __asm__("lcall *(%%esi); cld\n\t"
+                       "jc 1f\n\t"
+                       "xor %%ah, %%ah\n"
+                       "1:"
+                       : "=a" (result)
+                       : "0" (PCIBIOS_WRITE_CONFIG_WORD),
+                         "c" (value),
+                         "b" (bx),
+                         "D" ((long)reg),
+                         "S" (&pci_indirect));
+               break;
+       case 4:
+               __asm__("lcall *(%%esi); cld\n\t"
+                       "jc 1f\n\t"
+                       "xor %%ah, %%ah\n"
+                       "1:"
+                       : "=a" (result)
+                       : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
+                         "c" (value),
+                         "b" (bx),
+                         "D" ((long)reg),
+                         "S" (&pci_indirect));
+               break;
+       }
+
+       spin_unlock_irqrestore(&pci_config_lock, flags);
+
+       return (int)((result & 0xff00) >> 8);
+}
+
+static int pci_bios_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+       int result; 
+       u32 data;
+
+       if (!value) 
+               return -EINVAL;
+
+       result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 1, &data);
+
+       *value = (u8)data;
+
+       return result;
+}
+
+static int pci_bios_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+       int result; 
+       u32 data;
+
+       if (!value) 
+               return -EINVAL;
+
+       result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 2, &data);
+
+       *value = (u16)data;
+
+       return result;
+}
+
+static int pci_bios_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+       if (!value) 
+               return -EINVAL;
+       
+       return pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+static int pci_bios_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+       return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 1, value);
+}
+
+static int pci_bios_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+       return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 2, value);
+}
+
+static int pci_bios_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+       return pci_bios_write(0, dev->bus->number, PCI_SLOT(dev->devfn), 
+               PCI_FUNC(dev->devfn), where, 4, value);
+}
+
+
+/*
+ * Function table for BIOS32 access
+ */
+
+static struct pci_ops pci_bios_access = {
+      pci_bios_read_config_byte,
+      pci_bios_read_config_word,
+      pci_bios_read_config_dword,
+      pci_bios_write_config_byte,
+      pci_bios_write_config_word,
+      pci_bios_write_config_dword
+};
+
+/*
+ * Try to find PCI BIOS.
+ */
+
+static struct pci_ops * __devinit pci_find_bios(void)
+{
+       union bios32 *check;
+       unsigned char sum;
+       int i, length;
+
+       /*
+        * Follow the standard procedure for locating the BIOS32 Service
+        * directory by scanning the permissible address range from
+        * 0xe0000 through 0xfffff for a valid BIOS32 structure.
+        */
+
+       for (check = (union bios32 *) __va(0xe0000);
+            check <= (union bios32 *) __va(0xffff0);
+            ++check) {
+               if (check->fields.signature != BIOS32_SIGNATURE)
+                       continue;
+               length = check->fields.length * 16;
+               if (!length)
+                       continue;
+               sum = 0;
+               for (i = 0; i < length ; ++i)
+                       sum += check->chars[i];
+               if (sum != 0)
+                       continue;
+               if (check->fields.revision != 0) {
+                       printk("PCI: unsupported BIOS32 revision %d at 0x%p\n",
+                               check->fields.revision, check);
+                       continue;
+               }
+               DBG("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
+               if (check->fields.entry >= 0x100000) {
+                       printk("PCI: BIOS32 entry (0x%p) in high memory, cannot use.\n", check);
+                       return NULL;
+               } else {
+                       unsigned long bios32_entry = check->fields.entry;
+                       DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
+                       bios32_indirect.address = bios32_entry + PAGE_OFFSET;
+                       if (check_pcibios())
+                               return &pci_bios_access;
+               }
+               break;  /* Hopefully more than one BIOS32 cannot happen... */
+       }
+
+       return NULL;
+}
+
+/*
+ * Sort the device list according to PCI BIOS. Nasty hack, but since some
+ * fool forgot to define the `correct' device order in the PCI BIOS specs
+ * and we want to be (possibly bug-to-bug ;-]) compatible with older kernels
+ * which used BIOS ordering, we are bound to do this...
+ */
+
+void __devinit pcibios_sort(void)
+{
+       LIST_HEAD(sorted_devices);
+       struct list_head *ln;
+       struct pci_dev *dev, *d;
+       int idx, found;
+       unsigned char bus, devfn;
+
+       DBG("PCI: Sorting device list...\n");
+       while (!list_empty(&pci_devices)) {
+               ln = pci_devices.next;
+               dev = pci_dev_g(ln);
+               idx = found = 0;
+               while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
+                       idx++;
+                       for (ln=pci_devices.next; ln != &pci_devices; ln=ln->next) {
+                               d = pci_dev_g(ln);
+                               if (d->bus->number == bus && d->devfn == devfn) {
+                                       list_del(&d->global_list);
+                                       list_add_tail(&d->global_list, &sorted_devices);
+                                       if (d == dev)
+                                               found = 1;
+                                       break;
+                               }
+                       }
+                       if (ln == &pci_devices) {
+                               printk(KERN_WARNING "PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
+                               /*
+                                * We must not continue scanning as several buggy BIOSes
+                                * return garbage after the last device. Grr.
+                                */
+                               break;
+                       }
+               }
+               if (!found) {
+                       printk(KERN_WARNING "PCI: Device %02x:%02x not found by BIOS\n",
+                               dev->bus->number, dev->devfn);
+                       list_del(&dev->global_list);
+                       list_add_tail(&dev->global_list, &sorted_devices);
+               }
+       }
+       list_splice(&sorted_devices, &pci_devices);
+}
+
+/*
+ *  BIOS Functions for IRQ Routing
+ */
+
+struct irq_routing_options {
+       u16 size;
+       struct irq_info *table;
+       u16 segment;
+} __attribute__((packed));
+
+struct irq_routing_table * __devinit pcibios_get_irq_routing_table(void)
+{
+       struct irq_routing_options opt;
+       struct irq_routing_table *rt = NULL;
+       int ret, map;
+       unsigned long page;
+
+       if (!pci_bios_present)
+               return NULL;
+       page = __get_free_page(GFP_KERNEL);
+       if (!page)
+               return NULL;
+       opt.table = (struct irq_info *) page;
+       opt.size = PAGE_SIZE;
+       opt.segment = __KERNEL_DS;
+
+       DBG("PCI: Fetching IRQ routing table... ");
+       __asm__("push %%es\n\t"
+               "push %%ds\n\t"
+               "pop  %%es\n\t"
+               "lcall *(%%esi); cld\n\t"
+               "pop %%es\n\t"
+               "jc 1f\n\t"
+               "xor %%ah, %%ah\n"
+               "1:"
+               : "=a" (ret),
+                 "=b" (map)
+               : "0" (PCIBIOS_GET_ROUTING_OPTIONS),
+                 "1" (0),
+                 "D" ((long) &opt),
+                 "S" (&pci_indirect));
+       DBG("OK  ret=%d, size=%d, map=%x\n", ret, opt.size, map);
+       if (ret & 0xff00)
+               printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff);
+       else if (opt.size) {
+               rt = kmalloc(sizeof(struct irq_routing_table) + opt.size, GFP_KERNEL);
+               if (rt) {
+                       memset(rt, 0, sizeof(struct irq_routing_table));
+                       rt->size = opt.size + sizeof(struct irq_routing_table);
+                       rt->exclusive_irqs = map;
+                       memcpy(rt->slots, (void *) page, opt.size);
+                       printk(KERN_INFO "PCI: Using BIOS Interrupt Routing Table\n");
+               }
+       }
+       free_page(page);
+       return rt;
+}
+
+
+int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq)
+{
+       int ret;
+
+       __asm__("lcall *(%%esi); cld\n\t"
+               "jc 1f\n\t"
+               "xor %%ah, %%ah\n"
+               "1:"
+               : "=a" (ret)
+               : "0" (PCIBIOS_SET_PCI_HW_INT),
+                 "b" ((dev->bus->number << 8) | dev->devfn),
+                 "c" ((irq << 8) | (pin + 10)),
+                 "S" (&pci_indirect));
+       return !(ret & 0xff00);
+}
+
+static int __init pci_pcbios_init(void)
+{
+       if ((pci_probe & PCI_PROBE_BIOS) 
+               && ((pci_root_ops = pci_find_bios()))) {
+               pci_probe |= PCI_BIOS_SORT;
+               pci_bios_present = 1;
+               pci_config_read = pci_bios_read;
+               pci_config_write = pci_bios_write;
+       }
+       return 0;
+}
+
+subsys_initcall(pci_pcbios_init);
diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h
new file mode 100644 (file)
index 0000000..2240a68
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ *     Low-Level PCI Access for i386 machines.
+ *
+ *     (c) 1999 Martin Mares <mj@ucw.cz>
+ */
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#define PCI_PROBE_BIOS         0x0001
+#define PCI_PROBE_CONF1                0x0002
+#define PCI_PROBE_CONF2                0x0004
+#define PCI_NO_SORT            0x0100
+#define PCI_BIOS_SORT          0x0200
+#define PCI_NO_CHECKS          0x0400
+#define PCI_USE_PIRQ_MASK      0x0800
+#define PCI_ASSIGN_ROMS                0x1000
+#define PCI_BIOS_IRQ_SCAN      0x2000
+#define PCI_ASSIGN_ALL_BUSSES  0x4000
+#define PCI_NO_ACPI_ROUTING    0x8000
+
+extern unsigned int pci_probe;
+
+/* pci-i386.c */
+
+extern unsigned int pcibios_max_latency;
+
+void pcibios_resource_survey(void);
+int pcibios_enable_resources(struct pci_dev *);
+
+/* pci-pc.c */
+
+extern int pcibios_last_bus;
+extern struct pci_bus *pci_root_bus;
+extern struct pci_ops *pci_root_ops;
+
+/* pci-irq.c */
+
+struct irq_info {
+       u8 bus, devfn;                  /* Bus, device and function */
+       struct {
+               u8 link;                /* IRQ line ID, chipset dependent, 0=not routed */
+               u16 bitmap;             /* Available IRQs */
+       } __attribute__((packed)) irq[4];
+       u8 slot;                        /* Slot number, 0=onboard */
+       u8 rfu;
+} __attribute__((packed));
+
+struct irq_routing_table {
+       u32 signature;                  /* PIRQ_SIGNATURE should be here */
+       u16 version;                    /* PIRQ_VERSION */
+       u16 size;                       /* Table size in bytes */
+       u8 rtr_bus, rtr_devfn;          /* Where the interrupt router lies */
+       u16 exclusive_irqs;             /* IRQs devoted exclusively to PCI usage */
+       u16 rtr_vendor, rtr_device;     /* Vendor and device ID of interrupt router */
+       u32 miniport_data;              /* Crap */
+       u8 rfu[11];
+       u8 checksum;                    /* Modulo 256 checksum must give zero */
+       struct irq_info slots[0];
+} __attribute__((packed));
+
+extern unsigned int pcibios_irq_mask;
+
+extern int pci_use_acpi_routing;
+extern spinlock_t pci_config_lock;
+
+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/arch/i386/pci/visws.c b/arch/i386/pci/visws.c
new file mode 100644 (file)
index 0000000..c583be6
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ *     Low-Level PCI Support for SGI Visual Workstation
+ *
+ *     (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/irq.h>
+
+#include <asm/smp.h>
+#include <asm/lithium.h>
+#include <asm/io.h>
+
+#include "pci-i386.h"
+
+unsigned int pci_probe = 0;
+
+/*
+ *  The VISWS uses configuration access type 1 only.
+ */
+
+#define CONFIG_CMD(dev, where)   (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
+
+static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+       outl(CONFIG_CMD(dev,where), 0xCF8);
+       *value = inb(0xCFC + (where&3));
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+       outl(CONFIG_CMD(dev,where), 0xCF8);    
+       *value = inw(0xCFC + (where&2));
+       return PCIBIOS_SUCCESSFUL;    
+}
+
+static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+       outl(CONFIG_CMD(dev,where), 0xCF8);
+       *value = inl(0xCFC);
+       return PCIBIOS_SUCCESSFUL;    
+}
+
+static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+       outl(CONFIG_CMD(dev,where), 0xCF8);    
+       outb(value, 0xCFC + (where&3));
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+       outl(CONFIG_CMD(dev,where), 0xCF8);
+       outw(value, 0xCFC + (where&2));
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+       outl(CONFIG_CMD(dev,where), 0xCF8);
+       outl(value, 0xCFC);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+#undef CONFIG_CMD
+
+static struct pci_ops visws_pci_ops = {
+       pci_conf1_read_config_byte,
+       pci_conf1_read_config_word,
+       pci_conf1_read_config_dword,
+       pci_conf1_write_config_byte,
+       pci_conf1_write_config_word,
+       pci_conf1_write_config_dword
+};
+
+static void __init pcibios_fixup_irqs(void)
+{
+       struct pci_dev *dev, *p;
+       u8 pin;
+       int irq;
+
+       pci_for_each_dev(dev) {
+               pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+               dev->irq = 0;
+               if (!pin)
+                       continue;
+               pin--;
+               if (dev->bus->parent) {
+                       p = dev->bus->parent->self;
+                       pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+               } else
+                       p = dev;
+               irq = visws_get_PCI_irq_vector(p->bus->number, PCI_SLOT(p->devfn), pin+1);
+               if (irq >= 0)
+                       dev->irq = irq;
+               DBG("PCI IRQ: %s pin %d -> %d\n", dev->slot_name, pin, irq);
+       }
+}
+
+void __init pcibios_fixup_bus(struct pci_bus *b)
+{
+       pci_read_bridge_bases(b);
+}
+
+#if 0
+static struct resource visws_pci_bus_resources[2] = {
+       { "Host bus 1", 0xf4000000, 0xf7ffffff, 0 },
+       { "Host bus 2", 0xf0000000, 0xf3ffffff, 0 }
+};
+#endif
+
+void __init pcibios_init(void)
+{
+       unsigned int sec_bus = li_pcib_read16(LI_PCI_BUSNUM) & 0xff;
+
+       printk("PCI: Probing PCI hardware on host buses 00 and %02x\n", sec_bus);
+       pci_scan_bus(0, &visws_pci_ops, NULL);
+       pci_scan_bus(sec_bus, &visws_pci_ops, NULL);
+       pcibios_fixup_irqs();
+       pcibios_resource_survey();
+}
+
+char * __init pcibios_setup(char *str)
+{
+       return str;
+}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+       return pcibios_enable_resources(dev);
+}
+
+void __init pcibios_penalize_isa_irq(irq)
+{
+}