diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2007-10-11 11:16:36 +0200 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2007-10-11 11:16:36 +0200 |
commit | fb9aa6f1d4a1e11e66a680460b2c2b2b10b62f79 (patch) | |
tree | e0ad51f39b48a342244cef62099bd1a8a93927db /arch/i386/pci | |
parent | 4b60eb8380a0b588a03b6052d7ac93e1964c75b8 (diff) | |
download | op-kernel-dev-fb9aa6f1d4a1e11e66a680460b2c2b2b10b62f79.zip op-kernel-dev-fb9aa6f1d4a1e11e66a680460b2c2b2b10b62f79.tar.gz |
i386: move pci
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/i386/pci')
-rw-r--r-- | arch/i386/pci/Makefile | 5 | ||||
-rw-r--r-- | arch/i386/pci/Makefile_32 | 14 | ||||
-rw-r--r-- | arch/i386/pci/acpi.c | 90 | ||||
-rw-r--r-- | arch/i386/pci/common.c | 480 | ||||
-rw-r--r-- | arch/i386/pci/direct.c | 302 | ||||
-rw-r--r-- | arch/i386/pci/early.c | 59 | ||||
-rw-r--r-- | arch/i386/pci/fixup.c | 446 | ||||
-rw-r--r-- | arch/i386/pci/i386.c | 315 | ||||
-rw-r--r-- | arch/i386/pci/init.c | 37 | ||||
-rw-r--r-- | arch/i386/pci/irq.c | 1173 | ||||
-rw-r--r-- | arch/i386/pci/legacy.c | 56 | ||||
-rw-r--r-- | arch/i386/pci/mmconfig-shared.c | 315 | ||||
-rw-r--r-- | arch/i386/pci/mmconfig_32.c | 148 | ||||
-rw-r--r-- | arch/i386/pci/numa.c | 135 | ||||
-rw-r--r-- | arch/i386/pci/pcbios.c | 492 | ||||
-rw-r--r-- | arch/i386/pci/pci.h | 149 | ||||
-rw-r--r-- | arch/i386/pci/visws.c | 111 |
17 files changed, 0 insertions, 4327 deletions
diff --git a/arch/i386/pci/Makefile b/arch/i386/pci/Makefile deleted file mode 100644 index d04d8f9..0000000 --- a/arch/i386/pci/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ifeq ($(CONFIG_X86_32),y) -include ${srctree}/arch/i386/pci/Makefile_32 -else -include ${srctree}/arch/x86_64/pci/Makefile_64 -endif diff --git a/arch/i386/pci/Makefile_32 b/arch/i386/pci/Makefile_32 deleted file mode 100644 index cdd6828..0000000 --- a/arch/i386/pci/Makefile_32 +++ /dev/null @@ -1,14 +0,0 @@ -obj-y := i386.o init.o - -obj-$(CONFIG_PCI_BIOS) += pcbios.o -obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_32.o direct.o mmconfig-shared.o -obj-$(CONFIG_PCI_DIRECT) += direct.o - -pci-y := fixup.o -pci-$(CONFIG_ACPI) += acpi.o -pci-y += legacy.o irq.o - -pci-$(CONFIG_X86_VISWS) := visws.o fixup.o -pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o - -obj-y += $(pci-y) common.o early.o diff --git a/arch/i386/pci/acpi.c b/arch/i386/pci/acpi.c deleted file mode 100644 index bc8a44b..0000000 --- a/arch/i386/pci/acpi.c +++ /dev/null @@ -1,90 +0,0 @@ -#include <linux/pci.h> -#include <linux/acpi.h> -#include <linux/init.h> -#include <linux/irq.h> -#include <asm/numa.h> -#include "pci.h" - -struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum) -{ - struct pci_bus *bus; - struct pci_sysdata *sd; - int pxm; - - /* Allocate per-root-bus (not per bus) arch-specific data. - * TODO: leak; this memory is never freed. - * It's arguable whether it's worth the trouble to care. - */ - sd = kzalloc(sizeof(*sd), GFP_KERNEL); - if (!sd) { - printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); - return NULL; - } - - if (domain != 0) { - printk(KERN_WARNING "PCI: Multiple domains not supported\n"); - kfree(sd); - return NULL; - } - - sd->node = -1; - - pxm = acpi_get_pxm(device->handle); -#ifdef CONFIG_ACPI_NUMA - if (pxm >= 0) - sd->node = pxm_to_node(pxm); -#endif - - bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); - if (!bus) - kfree(sd); - -#ifdef CONFIG_ACPI_NUMA - if (bus != NULL) { - if (pxm >= 0) { - printk("bus %d -> pxm %d -> node %d\n", - busnum, pxm, sd->node); - } - } -#endif - - return bus; -} - -extern int pci_routeirq; -static int __init pci_acpi_init(void) -{ - struct pci_dev *dev = NULL; - - if (pcibios_scanned) - return 0; - - if (acpi_noirq) - return 0; - - printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); - acpi_irq_penalty_init(); - pcibios_scanned++; - pcibios_enable_irq = acpi_pci_irq_enable; - pcibios_disable_irq = acpi_pci_irq_disable; - - if (pci_routeirq) { - /* - * PCI IRQ routing is set up by pci_enable_device(), but we - * also do it here in case there are still broken drivers that - * don't use pci_enable_device(). - */ - printk(KERN_INFO "PCI: Routing PCI interrupts for all devices because \"pci=routeirq\" specified\n"); - for_each_pci_dev(dev) - acpi_pci_irq_enable(dev); - } else - printk(KERN_INFO "PCI: If a device doesn't work, try \"pci=routeirq\". If it helps, post a report\n"); - -#ifdef CONFIG_X86_IO_APIC - if (acpi_ioapic) - print_IO_APIC(); -#endif - - return 0; -} -subsys_initcall(pci_acpi_init); diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c deleted file mode 100644 index ebc6f3c..0000000 --- a/arch/i386/pci/common.c +++ /dev/null @@ -1,480 +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 <linux/init.h> -#include <linux/dmi.h> - -#include <asm/acpi.h> -#include <asm/segment.h> -#include <asm/io.h> -#include <asm/smp.h> - -#include "pci.h" - -unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | - PCI_PROBE_MMCONF; - -static int pci_bf_sort; -int pci_routeirq; -int pcibios_last_bus = -1; -unsigned long pirq_table_addr; -struct pci_bus *pci_root_bus; -struct pci_raw_ops *raw_pci_ops; - -static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) -{ - return raw_pci_ops->read(0, bus->number, devfn, where, size, value); -} - -static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) -{ - return raw_pci_ops->write(0, bus->number, devfn, where, size, value); -} - -struct pci_ops pci_root_ops = { - .read = pci_read, - .write = pci_write, -}; - -/* - * legacy, numa, and acpi all want to call pcibios_scan_root - * from their initcalls. This flag prevents that. - */ -int pcibios_scanned; - -/* - * This interrupt-safe spinlock protects all accesses to PCI - * configuration space. - */ -DEFINE_SPINLOCK(pci_config_lock); - -/* - * 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); - list_for_each(ln, &b->devices) { - 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); -} - -/* - * Only use DMI information to set this if nothing was passed - * on the kernel command line (which was parsed earlier). - */ - -static int __devinit set_bf_sort(struct dmi_system_id *d) -{ - if (pci_bf_sort == pci_bf_sort_default) { - pci_bf_sort = pci_dmi_bf; - printk(KERN_INFO "PCI: %s detected, enabling pci=bfsort.\n", d->ident); - } - return 0; -} - -/* - * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus) - */ -#ifdef __i386__ -static int __devinit assign_all_busses(struct dmi_system_id *d) -{ - pci_probe |= PCI_ASSIGN_ALL_BUSSES; - printk(KERN_INFO "%s detected: enabling PCI bus# renumbering" - " (pci=assign-busses)\n", d->ident); - return 0; -} -#endif - -static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { -#ifdef __i386__ -/* - * Laptops which need pci=assign-busses to see Cardbus cards - */ - { - .callback = assign_all_busses, - .ident = "Samsung X20 Laptop", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Samsung Electronics"), - DMI_MATCH(DMI_PRODUCT_NAME, "SX20S"), - }, - }, -#endif /* __i386__ */ - { - .callback = set_bf_sort, - .ident = "Dell PowerEdge 1950", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell"), - DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"), - }, - }, - { - .callback = set_bf_sort, - .ident = "Dell PowerEdge 1955", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell"), - DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1955"), - }, - }, - { - .callback = set_bf_sort, - .ident = "Dell PowerEdge 2900", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell"), - DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2900"), - }, - }, - { - .callback = set_bf_sort, - .ident = "Dell PowerEdge 2950", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell"), - DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"), - }, - }, - { - .callback = set_bf_sort, - .ident = "Dell PowerEdge R900", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell"), - DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R900"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL20p G3", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G3"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL20p G4", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G4"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL30p G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL30p G1"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL25p G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL25p G1"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL35p G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL35p G1"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL45p G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G1"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL45p G2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G2"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL460c G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL460c G1"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL465c G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL465c G1"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL480c G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL480c G1"), - }, - }, - { - .callback = set_bf_sort, - .ident = "HP ProLiant BL685c G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL685c G1"), - }, - }, - {} -}; - -struct pci_bus * __devinit pcibios_scan_root(int busnum) -{ - struct pci_bus *bus = NULL; - struct pci_sysdata *sd; - - dmi_check_system(pciprobe_dmi_table); - - while ((bus = pci_find_next_bus(bus)) != NULL) { - if (bus->number == busnum) { - /* Already scanned */ - return bus; - } - } - - /* Allocate per-root-bus (not per bus) arch-specific data. - * TODO: leak; this memory is never freed. - * It's arguable whether it's worth the trouble to care. - */ - sd = kzalloc(sizeof(*sd), GFP_KERNEL); - if (!sd) { - printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); - return NULL; - } - - printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum); - - return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); -} - -extern u8 pci_cache_line_size; - -static int __init pcibios_init(void) -{ - struct cpuinfo_x86 *c = &boot_cpu_data; - - if (!raw_pci_ops) { - printk(KERN_WARNING "PCI: System does not support PCI\n"); - return 0; - } - - /* - * Assume PCI cacheline size of 32 bytes for all x86s except K7/K8 - * and P4. It's also good for 386/486s (which actually have 16) - * as quite a few PCI devices do not support smaller values. - */ - pci_cache_line_size = 32 >> 2; - if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD) - pci_cache_line_size = 64 >> 2; /* K7 & K8 */ - else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL) - pci_cache_line_size = 128 >> 2; /* P4 */ - - pcibios_resource_survey(); - - if (pci_bf_sort >= pci_force_bf) - pci_sort_breadthfirst(); -#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; - } else if (!strcmp(str, "bfsort")) { - pci_bf_sort = pci_force_bf; - return NULL; - } else if (!strcmp(str, "nobfsort")) { - pci_bf_sort = pci_force_nobf; - 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; - } else if (!strncmp(str, "pirqaddr=", 9)) { - pirq_table_addr = simple_strtoul(str+9, NULL, 0); - 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_PCI_MMCONFIG - else if (!strcmp(str, "nommconf")) { - pci_probe &= ~PCI_PROBE_MMCONF; - return NULL; - } -#endif - else if (!strcmp(str, "noacpi")) { - acpi_noirq_set(); - return NULL; - } - else if (!strcmp(str, "noearly")) { - pci_probe |= PCI_PROBE_NOEARLY; - return NULL; - } -#ifndef CONFIG_X86_VISWS - 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; - } -#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, "routeirq")) { - pci_routeirq = 1; - 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 mask) -{ - int err; - - if ((err = pcibios_enable_resources(dev, mask)) < 0) - return err; - - if (!dev->msi_enabled) - return pcibios_enable_irq(dev); - return 0; -} - -void pcibios_disable_device (struct pci_dev *dev) -{ - if (!dev->msi_enabled && pcibios_disable_irq) - pcibios_disable_irq(dev); -} - -struct pci_bus *pci_scan_bus_with_sysdata(int busno) -{ - struct pci_bus *bus = NULL; - struct pci_sysdata *sd; - - /* - * Allocate per-root-bus (not per bus) arch-specific data. - * TODO: leak; this memory is never freed. - * It's arguable whether it's worth the trouble to care. - */ - sd = kzalloc(sizeof(*sd), GFP_KERNEL); - if (!sd) { - printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno); - return NULL; - } - sd->node = -1; - bus = pci_scan_bus(busno, &pci_root_ops, sd); - if (!bus) - kfree(sd); - - return bus; -} diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c deleted file mode 100644 index 431c9a5..0000000 --- a/arch/i386/pci/direct.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * direct.c - Low-level direct PCI config space access - */ - -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/dmi.h> -#include "pci.h" - -/* - * Functions for accessing PCI configuration space with type 1 accesses - */ - -#define PCI_CONF1_ADDRESS(bus, devfn, reg) \ - (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3)) - -int pci_conf1_read(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 *value) -{ - unsigned long flags; - - if ((bus > 255) || (devfn > 255) || (reg > 255)) { - *value = -1; - return -EINVAL; - } - - spin_lock_irqsave(&pci_config_lock, flags); - - outl(PCI_CONF1_ADDRESS(bus, devfn, 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; -} - -int pci_conf1_write(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 value) -{ - unsigned long flags; - - if ((bus > 255) || (devfn > 255) || (reg > 255)) - return -EINVAL; - - spin_lock_irqsave(&pci_config_lock, flags); - - outl(PCI_CONF1_ADDRESS(bus, devfn, 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 - -struct pci_raw_ops pci_direct_conf1 = { - .read = pci_conf1_read, - .write = pci_conf1_write, -}; - - -/* - * 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(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 *value) -{ - unsigned long flags; - int dev, fn; - - if ((bus > 255) || (devfn > 255) || (reg > 255)) { - *value = -1; - return -EINVAL; - } - - dev = PCI_SLOT(devfn); - fn = PCI_FUNC(devfn); - - 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(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 value) -{ - unsigned long flags; - int dev, fn; - - if ((bus > 255) || (devfn > 255) || (reg > 255)) - return -EINVAL; - - dev = PCI_SLOT(devfn); - fn = PCI_FUNC(devfn); - - 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 struct pci_raw_ops pci_direct_conf2 = { - .read = pci_conf2_read, - .write = pci_conf2_write, -}; - - -/* - * 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 __init pci_sanity_check(struct pci_raw_ops *o) -{ - u32 x = 0; - int devfn; - - if (pci_probe & PCI_NO_CHECKS) - return 1; - /* Assume Type 1 works for newer systems. - This handles machines that don't have anything on PCI Bus 0. */ - if (dmi_get_year(DMI_BIOS_DATE) >= 2001) - return 1; - - for (devfn = 0; devfn < 0x100; devfn++) { - if (o->read(0, 0, devfn, PCI_CLASS_DEVICE, 2, &x)) - continue; - if (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA) - return 1; - - if (o->read(0, 0, devfn, PCI_VENDOR_ID, 2, &x)) - continue; - if (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ) - return 1; - } - - DBG(KERN_WARNING "PCI: Sanity check failed\n"); - return 0; -} - -static int __init pci_check_type1(void) -{ - unsigned long flags; - unsigned int tmp; - int works = 0; - - local_irq_save(flags); - - outb(0x01, 0xCFB); - tmp = inl(0xCF8); - outl(0x80000000, 0xCF8); - if (inl(0xCF8) == 0x80000000 && pci_sanity_check(&pci_direct_conf1)) { - works = 1; - } - outl(tmp, 0xCF8); - local_irq_restore(flags); - - return works; -} - -static int __init pci_check_type2(void) -{ - unsigned long flags; - int works = 0; - - local_irq_save(flags); - - outb(0x00, 0xCFB); - outb(0x00, 0xCF8); - outb(0x00, 0xCFA); - if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00 && - pci_sanity_check(&pci_direct_conf2)) { - works = 1; - } - - local_irq_restore(flags); - - return works; -} - -void __init pci_direct_init(int type) -{ - if (type == 0) - return; - printk(KERN_INFO "PCI: Using configuration type %d\n", type); - if (type == 1) - raw_pci_ops = &pci_direct_conf1; - else - raw_pci_ops = &pci_direct_conf2; -} - -int __init pci_direct_probe(void) -{ - struct resource *region, *region2; - - if ((pci_probe & PCI_PROBE_CONF1) == 0) - goto type2; - region = request_region(0xCF8, 8, "PCI conf1"); - if (!region) - goto type2; - - if (pci_check_type1()) - return 1; - release_resource(region); - - type2: - if ((pci_probe & PCI_PROBE_CONF2) == 0) - return 0; - region = request_region(0xCF8, 4, "PCI conf2"); - if (!region) - return 0; - region2 = request_region(0xC000, 0x1000, "PCI conf2"); - if (!region2) - goto fail2; - - if (pci_check_type2()) { - printk(KERN_INFO "PCI: Using configuration type 2\n"); - raw_pci_ops = &pci_direct_conf2; - return 2; - } - - release_resource(region2); - fail2: - release_resource(region); - return 0; -} diff --git a/arch/i386/pci/early.c b/arch/i386/pci/early.c deleted file mode 100644 index 42df4b6..0000000 --- a/arch/i386/pci/early.c +++ /dev/null @@ -1,59 +0,0 @@ -#include <linux/kernel.h> -#include <linux/pci.h> -#include <asm/pci-direct.h> -#include <asm/io.h> -#include "pci.h" - -/* Direct PCI access. This is used for PCI accesses in early boot before - the PCI subsystem works. */ - -#define PDprintk(x...) - -u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset) -{ - u32 v; - outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); - v = inl(0xcfc); - if (v != 0xffffffff) - PDprintk("%x reading 4 from %x: %x\n", slot, offset, v); - return v; -} - -u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset) -{ - u8 v; - outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); - v = inb(0xcfc + (offset&3)); - PDprintk("%x reading 1 from %x: %x\n", slot, offset, v); - return v; -} - -u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset) -{ - u16 v; - outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); - v = inw(0xcfc + (offset&2)); - PDprintk("%x reading 2 from %x: %x\n", slot, offset, v); - return v; -} - -void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset, - u32 val) -{ - PDprintk("%x writing to %x: %x\n", slot, offset, val); - outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); - outl(val, 0xcfc); -} - -void write_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 val) -{ - PDprintk("%x writing to %x: %x\n", slot, offset, val); - outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); - outb(val, 0xcfc); -} - -int early_pci_allowed(void) -{ - return (pci_probe & (PCI_PROBE_CONF1|PCI_PROBE_NOEARLY)) == - PCI_PROBE_CONF1; -} diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c deleted file mode 100644 index c82cbf4..0000000 --- a/arch/i386/pci/fixup.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Exceptions for specific devices. Usually work-arounds for fatal design flaws. - */ - -#include <linux/delay.h> -#include <linux/dmi.h> -#include <linux/pci.h> -#include <linux/init.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", pci_name(d)); - 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_with_sysdata(busno); /* Bus A */ - if (suba < subb) - pci_scan_bus_with_sysdata(suba+1); /* Bus B */ - } - pcibios_last_bus = -1; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx); - -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", pci_name(d), busno); - pci_scan_bus_with_sysdata(busno); - pcibios_last_bus = -1; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx); - -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", pci_name(d)); - for(i=0; i<4; i++) - d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide); - -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", pci_name(d)); - d->class = PCI_CLASS_STORAGE_SCSI << 8; - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810); - -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; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency); - -static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d) -{ - /* - * PIIX4 ACPI device: hardwired IRQ9 - */ - d->irq = 9; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, pci_fixup_piix4_acpi); - -/* - * Addresses issues with problems in the memory write queue timer in - * certain VIA Northbridges. This bugfix is per VIA's specifications, - * except for the KL133/KM133: clearing bit 5 on those Northbridges seems - * to trigger a bug in its integrated ProSavage video card, which - * causes screen corruption. We only clear bits 6 and 7 for that chipset, - * until VIA can provide us with definitive information on why screen - * corruption occurs, and what exactly those bits do. - * - * 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 - * VIA 8363 rev 0x81/0x84 (KL133/KM133) Northbridges: - * - bits 6, 7 at offset 0x55 need to be turned off - */ - -#define VIA_8363_KL133_REVISION_ID 0x81 -#define VIA_8363_KM133_REVISION_ID 0x84 - -static void pci_fixup_via_northbridge_bug(struct pci_dev *d) -{ - u8 v; - int where = 0x55; - int mask = 0x1f; /* clear bits 5, 6, 7 by default */ - - if (d->device == PCI_DEVICE_ID_VIA_8367_0) { - /* fix pci bus latency issues resulted by NB bios error - it appears on bug free^Wreduced kt266x's bios forces - NB latency to zero */ - pci_write_config_byte(d, PCI_LATENCY_TIMER, 0); - - where = 0x95; /* the memory write queue timer register is - different for the KT266x's: 0x95 not 0x55 */ - } else if (d->device == PCI_DEVICE_ID_VIA_8363_0 && - (d->revision == VIA_8363_KL133_REVISION_ID || - d->revision == VIA_8363_KM133_REVISION_ID)) { - mask = 0x3f; /* clear only bits 6 and 7; clearing bit 5 - causes screen corruption on the KL133/KM133 */ - } - - pci_read_config_byte(d, where, &v); - if (v & ~mask) { - printk(KERN_WARNING "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \ - d->device, d->revision, where, v, mask, v & mask); - v &= mask; - pci_write_config_byte(d, where, v); - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_via_northbridge_bug); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_northbridge_bug); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_via_northbridge_bug); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_northbridge_bug); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug); - -/* - * For some reasons Intel decided that certain parts of their - * 815, 845 and some other chipsets must look like PCI-to-PCI bridges - * while they are obviously not. The 82801 family (AA, AB, BAM/CAM, - * BA/CA/DB and E) PCI bridges are actually HUB-to-PCI ones, according - * to Intel terminology. These devices do forward all addresses from - * system to PCI bus no matter what are their window settings, so they are - * "transparent" (or subtractive decoding) from programmers point of view. - */ -static void __devinit pci_fixup_transparent_bridge(struct pci_dev *dev) -{ - if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && - (dev->device & 0xff00) == 0x2400) - dev->transparent = 1; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixup_transparent_bridge); - -/* - * Fixup for C1 Halt Disconnect problem on nForce2 systems. - * - * From information provided by "Allen Martin" <AMartin@nvidia.com>: - * - * A hang is caused when the CPU generates a very fast CONNECT/HALT cycle - * sequence. Workaround is to set the SYSTEM_IDLE_TIMEOUT to 80 ns. - * This allows the state-machine and timer to return to a proper state within - * 80 ns of the CONNECT and probe appearing together. Since the CPU will not - * issue another HALT within 80 ns of the initial HALT, the failure condition - * is avoided. - */ -static void pci_fixup_nforce2(struct pci_dev *dev) -{ - u32 val; - - /* - * Chip Old value New value - * C17 0x1F0FFF01 0x1F01FF01 - * C18D 0x9F0FFF01 0x9F01FF01 - * - * Northbridge chip version may be determined by - * reading the PCI revision ID (0xC1 or greater is C18D). - */ - pci_read_config_dword(dev, 0x6c, &val); - - /* - * Apply fixup if needed, but don't touch disconnect state - */ - if ((val & 0x00FF0000) != 0x00010000) { - printk(KERN_WARNING "PCI: nForce2 C1 Halt Disconnect fixup\n"); - pci_write_config_dword(dev, 0x6c, (val & 0xFF00FFFF) | 0x00010000); - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2); - -/* Max PCI Express root ports */ -#define MAX_PCIEROOT 6 -static int quirk_aspm_offset[MAX_PCIEROOT << 3]; - -#define GET_INDEX(a, b) ((((a) - PCI_DEVICE_ID_INTEL_MCH_PA) << 3) + ((b) & 7)) - -static int quirk_pcie_aspm_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) -{ - return raw_pci_ops->read(0, bus->number, devfn, where, size, value); -} - -/* - * Replace the original pci bus ops for write with a new one that will filter - * the request to insure ASPM cannot be enabled. - */ -static int quirk_pcie_aspm_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) -{ - u8 offset; - - offset = quirk_aspm_offset[GET_INDEX(bus->self->device, devfn)]; - - if ((offset) && (where == offset)) - value = value & 0xfffffffc; - - return raw_pci_ops->write(0, bus->number, devfn, where, size, value); -} - -static struct pci_ops quirk_pcie_aspm_ops = { - .read = quirk_pcie_aspm_read, - .write = quirk_pcie_aspm_write, -}; - -/* - * Prevents PCI Express ASPM (Active State Power Management) being enabled. - * - * Save the register offset, where the ASPM control bits are located, - * for each PCI Express device that is in the device list of - * the root port in an array for fast indexing. Replace the bus ops - * with the modified one. - */ -static void pcie_rootport_aspm_quirk(struct pci_dev *pdev) -{ - int cap_base, i; - struct pci_bus *pbus; - struct pci_dev *dev; - - if ((pbus = pdev->subordinate) == NULL) - return; - - /* - * Check if the DID of pdev matches one of the six root ports. This - * check is needed in the case this function is called directly by the - * hot-plug driver. - */ - if ((pdev->device < PCI_DEVICE_ID_INTEL_MCH_PA) || - (pdev->device > PCI_DEVICE_ID_INTEL_MCH_PC1)) - return; - - if (list_empty(&pbus->devices)) { - /* - * If no device is attached to the root port at power-up or - * after hot-remove, the pbus->devices is empty and this code - * will set the offsets to zero and the bus ops to parent's bus - * ops, which is unmodified. - */ - for (i= GET_INDEX(pdev->device, 0); i <= GET_INDEX(pdev->device, 7); ++i) - quirk_aspm_offset[i] = 0; - - pbus->ops = pbus->parent->ops; - } else { - /* - * If devices are attached to the root port at power-up or - * after hot-add, the code loops through the device list of - * each root port to save the register offsets and replace the - * bus ops. - */ - list_for_each_entry(dev, &pbus->devices, bus_list) { - /* There are 0 to 8 devices attached to this bus */ - cap_base = pci_find_capability(dev, PCI_CAP_ID_EXP); - quirk_aspm_offset[GET_INDEX(pdev->device, dev->devfn)]= cap_base + 0x10; - } - pbus->ops = &quirk_pcie_aspm_ops; - } -} -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA, pcie_rootport_aspm_quirk ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA1, pcie_rootport_aspm_quirk ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB, pcie_rootport_aspm_quirk ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB1, pcie_rootport_aspm_quirk ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC, pcie_rootport_aspm_quirk ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_rootport_aspm_quirk ); - -/* - * Fixup to mark boot BIOS video selected by BIOS before it changes - * - * From information provided by "Jon Smirl" <jonsmirl@gmail.com> - * - * The standard boot ROM sequence for an x86 machine uses the BIOS - * to select an initial video card for boot display. This boot video - * card will have it's BIOS copied to C0000 in system RAM. - * IORESOURCE_ROM_SHADOW is used to associate the boot video - * card with this copy. On laptops this copy has to be used since - * the main ROM may be compressed or combined with another image. - * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW - * is marked here since the boot video device will be the only enabled - * video device at this point. - */ - -static void __devinit pci_fixup_video(struct pci_dev *pdev) -{ - struct pci_dev *bridge; - struct pci_bus *bus; - u16 config; - - if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA) - return; - - /* Is VGA routed to us? */ - bus = pdev->bus; - while (bus) { - bridge = bus->self; - - /* - * From information provided by - * "David Miller" <davem@davemloft.net> - * The bridge control register is valid for PCI header - * type BRIDGE, or CARDBUS. Host to PCI controllers use - * PCI header type NORMAL. - */ - if (bridge - &&((bridge->hdr_type == PCI_HEADER_TYPE_BRIDGE) - ||(bridge->hdr_type == PCI_HEADER_TYPE_CARDBUS))) { - pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, - &config); - if (!(config & PCI_BRIDGE_CTL_VGA)) - return; - } - bus = bus->parent; - } - pci_read_config_word(pdev, PCI_COMMAND, &config); - if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) { - pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW; - printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev)); - } -} -DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video); - -/* - * Some Toshiba laptops need extra code to enable their TI TSB43AB22/A. - * - * We pretend to bring them out of full D3 state, and restore the proper - * IRQ, PCI cache line size, and BARs, otherwise the device won't function - * properly. In some cases, the device will generate an interrupt on - * the wrong IRQ line, causing any devices sharing the line it's - * *supposed* to use to be disabled by the kernel's IRQ debug code. - */ -static u16 toshiba_line_size; - -static struct dmi_system_id __devinitdata toshiba_ohci1394_dmi_table[] = { - { - .ident = "Toshiba PS5 based laptop", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_VERSION, "PS5"), - }, - }, - { - .ident = "Toshiba PSM4 based laptop", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_VERSION, "PSM4"), - }, - }, - { - .ident = "Toshiba A40 based laptop", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_VERSION, "PSA40U"), - }, - }, - { } -}; - -static void __devinit pci_pre_fixup_toshiba_ohci1394(struct pci_dev *dev) -{ - if (!dmi_check_system(toshiba_ohci1394_dmi_table)) - return; /* only applies to certain Toshibas (so far) */ - - dev->current_state = PCI_D3cold; - pci_read_config_word(dev, PCI_CACHE_LINE_SIZE, &toshiba_line_size); -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, 0x8032, - pci_pre_fixup_toshiba_ohci1394); - -static void __devinit pci_post_fixup_toshiba_ohci1394(struct pci_dev *dev) -{ - if (!dmi_check_system(toshiba_ohci1394_dmi_table)) - return; /* only applies to certain Toshibas (so far) */ - - /* Restore config space on Toshiba laptops */ - pci_write_config_word(dev, PCI_CACHE_LINE_SIZE, toshiba_line_size); - pci_read_config_byte(dev, PCI_INTERRUPT_LINE, (u8 *)&dev->irq); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, - pci_resource_start(dev, 0)); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, - pci_resource_start(dev, 1)); -} -DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_TI, 0x8032, - pci_post_fixup_toshiba_ohci1394); - - -/* - * Prevent the BIOS trapping accesses to the Cyrix CS5530A video device - * configuration space. - */ -static void pci_early_fixup_cyrix_5530(struct pci_dev *dev) -{ - u8 r; - /* clear 'F4 Video Configuration Trap' bit */ - pci_read_config_byte(dev, 0x42, &r); - r &= 0xfd; - pci_write_config_byte(dev, 0x42, r); -} -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, - pci_early_fixup_cyrix_5530); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, - pci_early_fixup_cyrix_5530); - -/* - * Siemens Nixdorf AG FSC Multiprocessor Interrupt Controller: - * prevent update of the BAR0, which doesn't look like a normal BAR. - */ -static void __devinit pci_siemens_interrupt_controller(struct pci_dev *dev) -{ - dev->resource[0].flags |= IORESOURCE_PCI_FIXED; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SIEMENS, 0x0015, - pci_siemens_interrupt_controller); diff --git a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c deleted file mode 100644 index bcd2f94..0000000 --- a/arch/i386/pci/i386.c +++ /dev/null @@ -1,315 +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" - -/* - * 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, - resource_size_t size, resource_size_t align) -{ - if (res->flags & IORESOURCE_IO) { - resource_size_t 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 pci_bus *bus; - struct pci_dev *dev; - int idx; - struct resource *r, *pr; - - /* Depth-First Search on bus tree */ - list_for_each_entry(bus, bus_list, node) { - if ((dev = bus->self)) { - for (idx = PCI_BRIDGE_RESOURCES; - idx < PCI_NUM_RESOURCES; idx++) { - r = &dev->resource[idx]; - if (!r->flags) - continue; - pr = pci_find_parent_resource(dev, r); - if (!r->start || !pr || - request_resource(pr, r) < 0) { - printk(KERN_ERR "PCI: Cannot allocate " - "resource region %d " - "of bridge %s\n", - idx, pci_name(dev)); - /* - * Something is wrong with the region. - * Invalidate the resource to prevent - * child resource allocations in this - * range. - */ - r->flags = 0; - } - } - } - pcibios_allocate_bus_resources(&bus->children); - } -} - -static void __init pcibios_allocate_resources(int pass) -{ - struct pci_dev *dev = NULL; - int idx, disabled; - u16 command; - struct resource *r, *pr; - - for_each_pci_dev(dev) { - pci_read_config_word(dev, PCI_COMMAND, &command); - for (idx = 0; idx < PCI_ROM_RESOURCE; 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, pci_name(dev)); - /* 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 & IORESOURCE_ROM_ENABLE) { - /* Turn the ROM off, leave the resource region, - * but keep it unregistered. */ - u32 reg; - DBG("PCI: Switching off ROM of %s\n", - pci_name(dev)); - r->flags &= ~IORESOURCE_ROM_ENABLE; - pci_read_config_dword(dev, - dev->rom_base_reg, ®); - pci_write_config_dword(dev, dev->rom_base_reg, - reg & ~PCI_ROM_ADDRESS_ENABLE); - } - } - } -} - -static int __init pcibios_assign_resources(void) -{ - struct pci_dev *dev = NULL; - struct resource *r, *pr; - - if (!(pci_probe & PCI_ASSIGN_ROMS)) { - /* - * Try to use BIOS settings for ROMs, otherwise let - * pci_assign_unassigned_resources() allocate the new - * addresses. - */ - for_each_pci_dev(dev) { - r = &dev->resource[PCI_ROM_RESOURCE]; - if (!r->flags || !r->start) - continue; - pr = pci_find_parent_resource(dev, r); - if (!pr || request_resource(pr, r) < 0) { - r->end -= r->start; - r->start = 0; - } - } - } - - pci_assign_unassigned_resources(); - - return 0; -} - -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); -} - -/** - * called in fs_initcall (one below subsys_initcall), - * give a chance for motherboard reserve resources - */ -fs_initcall(pcibios_assign_resources); - -int pcibios_enable_resources(struct pci_dev *dev, int mask) -{ - u16 cmd, old_cmd; - int idx; - struct resource *r; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - old_cmd = cmd; - for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { - /* Only set up the requested stuff */ - if (!(mask & (1 << idx))) - continue; - - r = &dev->resource[idx]; - if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM))) - continue; - if ((idx == PCI_ROM_RESOURCE) && - (!(r->flags & IORESOURCE_ROM_ENABLE))) - continue; - if (!r->start && r->end) { - printk(KERN_ERR "PCI: Device %s not available " - "because of resource %d collisions\n", - pci_name(dev), idx); - return -EINVAL; - } - if (r->flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (r->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - if (cmd != old_cmd) { - printk("PCI: Enabling device %s (%04x -> %04x)\n", - pci_name(dev), 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(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", - pci_name(dev), 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. - */ - 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 (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) - return -EAGAIN; - - return 0; -} diff --git a/arch/i386/pci/init.c b/arch/i386/pci/init.c deleted file mode 100644 index 3de9f9b..0000000 --- a/arch/i386/pci/init.c +++ /dev/null @@ -1,37 +0,0 @@ -#include <linux/pci.h> -#include <linux/init.h> -#include "pci.h" - -/* arch_initcall has too random ordering, so call the initializers - in the right sequence from here. */ -static __init int pci_access_init(void) -{ - int type __maybe_unused = 0; - -#ifdef CONFIG_PCI_DIRECT - type = pci_direct_probe(); -#endif -#ifdef CONFIG_PCI_MMCONFIG - pci_mmcfg_init(type); -#endif - if (raw_pci_ops) - return 0; -#ifdef CONFIG_PCI_BIOS - pci_pcbios_init(); -#endif - /* - * don't check for raw_pci_ops here because we want pcbios as last - * fallback, yet it's needed to run first to set pcibios_last_bus - * in case legacy PCI probing is used. otherwise detecting peer busses - * fails. - */ -#ifdef CONFIG_PCI_DIRECT - pci_direct_init(type); -#endif - if (!raw_pci_ops) - printk(KERN_ERR - "PCI: Fatal: No config space access function found\n"); - - return 0; -} -arch_initcall(pci_access_init); diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c deleted file mode 100644 index 8434f23..0000000 --- a/arch/i386/pci/irq.c +++ /dev/null @@ -1,1173 +0,0 @@ -/* - * Low-Level PCI Support for PC -- Routing of Interrupts - * - * (c) 1999--2000 Martin Mares <mj@ucw.cz> - */ - -#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/dmi.h> -#include <asm/io.h> -#include <asm/smp.h> -#include <asm/io_apic.h> -#include <linux/irq.h> -#include <linux/acpi.h> - -#include "pci.h" - -#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) -#define PIRQ_VERSION 0x0100 - -static int broken_hp_bios_irq9; -static int acer_tm360_irqrouting; - -static struct irq_routing_table *pirq_table; - -static int pirq_enable_irq(struct pci_dev *dev); - -/* - * 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); -}; - -struct irq_router_handler { - u16 vendor; - int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device); -}; - -int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL; -void (*pcibios_disable_irq)(struct pci_dev *dev) = NULL; - -/* - * Check passed address for the PCI IRQ Routing Table signature - * and perform checksum verification. - */ - -static inline struct irq_routing_table * pirq_check_routing_table(u8 *addr) -{ - struct irq_routing_table *rt; - int i; - u8 sum; - - 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)) - return NULL; - sum = 0; - for (i=0; i < rt->size; i++) - sum += addr[i]; - if (!sum) { - DBG(KERN_DEBUG "PCI: Interrupt Routing Table found at 0x%p\n", rt); - return rt; - } - return 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; - - if (pirq_table_addr) { - rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr)); - if (rt) - return rt; - printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n"); - } - for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) { - rt = pirq_check_routing_table(addr); - if (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(KERN_DEBUG "%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++) { - if (!busmap[i] || pci_find_bus(0, i)) - continue; - if (pci_scan_bus_with_sysdata(i)) - 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; - static u16 eisa_irq_mask; - - if (irq >= 16 || (1 << irq) & eisa_irq_mask) - return; - - eisa_irq_mask |= (1 << irq); - printk(KERN_DEBUG "PCI: setting IRQ %u as level-triggered\n", irq); - val = inb(port); - if (!(val & mask)) { - DBG(KERN_DEBUG " -> 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 const 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 const 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. - * However, PIRQD is in the upper instead of lower 4 bits. - */ -static int pirq_via_get(struct pci_dev *router, struct pci_dev *dev, int pirq) -{ - return read_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq); -} - -static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) -{ - write_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq, irq); - return 1; -} - -/* - * The VIA pirq rules are nibble-based, like ALI, - * but without the ugly irq number munging. - * However, for 82C586, nibble map is different . - */ -static int pirq_via586_get(struct pci_dev *router, struct pci_dev *dev, int pirq) -{ - static const unsigned int pirqmap[5] = { 3, 2, 5, 1, 1 }; - return read_config_nybble(router, 0x55, pirqmap[pirq-1]); -} - -static int pirq_via586_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) -{ - static const unsigned int pirqmap[5] = { 3, 2, 5, 1, 1 }; - write_config_nybble(router, 0x55, pirqmap[pirq-1], 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 const 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 const 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 - * 0x5C bits 7:4 is INTB bits 3:0 is INTA - * 0x5D bits 7:4 is INTD bits 3:0 is INTC - */ -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. - * We have to deal with the following issues here: - * - vendors have different ideas about the meaning of link values - * - some onboard devices (integrated in the chipset) have special - * links and are thus routed differently (i.e. not via PCI INTA-INTD) - * - different revision of the router have a different layout for - * the routing registers, particularly for the onchip devices - * - * For all routing registers the common thing is we have one byte - * per routeable link which is defined as: - * bit 7 IRQ mapping enabled (0) or disabled (1) - * bits [6:4] reserved (sometimes used for onchip devices) - * bits [3:0] IRQ to map to - * allowed: 3-7, 9-12, 14-15 - * reserved: 0, 1, 2, 8, 13 - * - * The config-space registers located at 0x41/0x42/0x43/0x44 are - * always used to route the normal PCI INT A/B/C/D respectively. - * Apparently there are systems implementing PCI routing table using - * link values 0x01-0x04 and others using 0x41-0x44 for PCI INTA..D. - * We try our best to handle both link mappings. - * - * Currently (2003-05-21) it appears most SiS chipsets follow the - * definition of routing registers from the SiS-5595 southbridge. - * According to the SiS 5595 datasheets the revision id's of the - * router (ISA-bridge) should be 0x01 or 0xb0. - * - * Furthermore we've also seen lspci dumps with revision 0x00 and 0xb1. - * Looks like these are used in a number of SiS 5xx/6xx/7xx chipsets. - * They seem to work with the current routing code. However there is - * some concern because of the two USB-OHCI HCs (original SiS 5595 - * had only one). YMMV. - * - * Onchip routing for router rev-id 0x01/0xb0 and probably 0x00/0xb1: - * - * 0x61: IDEIRQ: - * bits [6:5] must be written 01 - * bit 4 channel-select primary (0), secondary (1) - * - * 0x62: USBIRQ: - * bit 6 OHCI function disabled (0), enabled (1) - * - * 0x6a: ACPI/SCI IRQ: bits 4-6 reserved - * - * 0x7e: Data Acq. Module IRQ - bits 4-6 reserved - * - * We support USBIRQ (in addition to INTA-INTD) and keep the - * IDE, ACPI and DAQ routing untouched as set by the BIOS. - * - * Currently the only reported exception is the new SiS 65x chipset - * which includes the SiS 69x southbridge. Here we have the 85C503 - * router revision 0x04 and there are changes in the register layout - * mostly related to the different USB HCs with USB 2.0 support. - * - * Onchip routing for router rev-id 0x04 (try-and-error observation) - * - * 0x60/0x61/0x62/0x63: 1xEHCI and 3xOHCI (companion) USB-HCs - * bit 6-4 are probably unused, not like 5595 - */ - -#define PIRQ_SIS_IRQ_MASK 0x0f -#define PIRQ_SIS_IRQ_DISABLE 0x80 -#define PIRQ_SIS_USB_ENABLE 0x40 - -static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq) -{ - u8 x; - int reg; - - reg = pirq; - if (reg >= 0x01 && reg <= 0x04) - reg += 0x40; - pci_read_config_byte(router, reg, &x); - return (x & PIRQ_SIS_IRQ_DISABLE) ? 0 : (x & PIRQ_SIS_IRQ_MASK); -} - -static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) -{ - u8 x; - int reg; - - reg = pirq; - if (reg >= 0x01 && reg <= 0x04) - reg += 0x40; - pci_read_config_byte(router, reg, &x); - x &= ~(PIRQ_SIS_IRQ_MASK | PIRQ_SIS_IRQ_DISABLE); - x |= irq ? irq: PIRQ_SIS_IRQ_DISABLE; - 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); -} - -#endif - -static __init int intel_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - static struct pci_device_id __initdata pirq_440gx[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2) }, - { }, - }; - - /* 440GX has a proprietary PIRQ router -- don't use it */ - if (pci_dev_present(pirq_440gx)) - return 0; - - switch(device) - { - case PCI_DEVICE_ID_INTEL_82371FB_0: - case PCI_DEVICE_ID_INTEL_82371SB_0: - case PCI_DEVICE_ID_INTEL_82371AB_0: - case PCI_DEVICE_ID_INTEL_82371MX: - case PCI_DEVICE_ID_INTEL_82443MX_0: - case PCI_DEVICE_ID_INTEL_82801AA_0: - case PCI_DEVICE_ID_INTEL_82801AB_0: - case PCI_DEVICE_ID_INTEL_82801BA_0: - case PCI_DEVICE_ID_INTEL_82801BA_10: - case PCI_DEVICE_ID_INTEL_82801CA_0: - case PCI_DEVICE_ID_INTEL_82801CA_12: - case PCI_DEVICE_ID_INTEL_82801DB_0: - case PCI_DEVICE_ID_INTEL_82801E_0: - case PCI_DEVICE_ID_INTEL_82801EB_0: - case PCI_DEVICE_ID_INTEL_ESB_1: - case PCI_DEVICE_ID_INTEL_ICH6_0: - case PCI_DEVICE_ID_INTEL_ICH6_1: - case PCI_DEVICE_ID_INTEL_ICH7_0: - case PCI_DEVICE_ID_INTEL_ICH7_1: - case PCI_DEVICE_ID_INTEL_ICH7_30: - case PCI_DEVICE_ID_INTEL_ICH7_31: - case PCI_DEVICE_ID_INTEL_ESB2_0: - case PCI_DEVICE_ID_INTEL_ICH8_0: - case PCI_DEVICE_ID_INTEL_ICH8_1: - case PCI_DEVICE_ID_INTEL_ICH8_2: - case PCI_DEVICE_ID_INTEL_ICH8_3: - case PCI_DEVICE_ID_INTEL_ICH8_4: - case PCI_DEVICE_ID_INTEL_ICH9_0: - case PCI_DEVICE_ID_INTEL_ICH9_1: - case PCI_DEVICE_ID_INTEL_ICH9_2: - case PCI_DEVICE_ID_INTEL_ICH9_3: - case PCI_DEVICE_ID_INTEL_ICH9_4: - case PCI_DEVICE_ID_INTEL_ICH9_5: - case PCI_DEVICE_ID_INTEL_TOLAPAI_0: - r->name = "PIIX/ICH"; - r->get = pirq_piix_get; - r->set = pirq_piix_set; - return 1; - } - return 0; -} - -static __init int via_router_probe(struct irq_router *r, - struct pci_dev *router, u16 device) -{ - /* FIXME: We should move some of the quirk fixup stuff here */ - - /* - * work arounds for some buggy BIOSes - */ - if (device == PCI_DEVICE_ID_VIA_82C586_0) { - switch(router->device) { - case PCI_DEVICE_ID_VIA_82C686: - /* - * Asus k7m bios wrongly reports 82C686A - * as 586-compatible - */ - device = PCI_DEVICE_ID_VIA_82C686; - break; - case PCI_DEVICE_ID_VIA_8235: - /** - * Asus a7v-x bios wrongly reports 8235 - * as 586-compatible - */ - device = PCI_DEVICE_ID_VIA_8235; - break; - } - } - - switch(device) { - case PCI_DEVICE_ID_VIA_82C586_0: - r->name = "VIA"; - r->get = pirq_via586_get; - r->set = pirq_via586_set; - return 1; - case PCI_DEVICE_ID_VIA_82C596: - case PCI_DEVICE_ID_VIA_82C686: - case PCI_DEVICE_ID_VIA_8231: - case PCI_DEVICE_ID_VIA_8233A: - case PCI_DEVICE_ID_VIA_8235: - case PCI_DEVICE_ID_VIA_8237: - /* FIXME: add new ones for 8233/5 */ - r->name = "VIA"; - r->get = pirq_via_get; - r->set = pirq_via_set; - return 1; - } - return 0; -} - -static __init int vlsi_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - switch(device) - { - case PCI_DEVICE_ID_VLSI_82C534: - r->name = "VLSI 82C534"; - r->get = pirq_vlsi_get; - r->set = pirq_vlsi_set; - return 1; - } - return 0; -} - - -static __init int serverworks_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - switch(device) - { - case PCI_DEVICE_ID_SERVERWORKS_OSB4: - case PCI_DEVICE_ID_SERVERWORKS_CSB5: - r->name = "ServerWorks"; - r->get = pirq_serverworks_get; - r->set = pirq_serverworks_set; - return 1; - } - return 0; -} - -static __init int sis_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - if (device != PCI_DEVICE_ID_SI_503) - return 0; - - r->name = "SIS"; - r->get = pirq_sis_get; - r->set = pirq_sis_set; - return 1; -} - -static __init int cyrix_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - switch(device) - { - case PCI_DEVICE_ID_CYRIX_5520: - r->name = "NatSemi"; - r->get = pirq_cyrix_get; - r->set = pirq_cyrix_set; - return 1; - } - return 0; -} - -static __init int opti_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - switch(device) - { - case PCI_DEVICE_ID_OPTI_82C700: - r->name = "OPTI"; - r->get = pirq_opti_get; - r->set = pirq_opti_set; - return 1; - } - return 0; -} - -static __init int ite_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - switch(device) - { - case PCI_DEVICE_ID_ITE_IT8330G_0: - r->name = "ITE"; - r->get = pirq_ite_get; - r->set = pirq_ite_set; - return 1; - } - return 0; -} - -static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - switch(device) - { - case PCI_DEVICE_ID_AL_M1533: - case PCI_DEVICE_ID_AL_M1563: - printk(KERN_DEBUG "PCI: Using ALI IRQ Router\n"); - r->name = "ALI"; - r->get = pirq_ali_get; - r->set = pirq_ali_set; - return 1; - } - return 0; -} - -static __init int amd_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) -{ - switch(device) - { - case PCI_DEVICE_ID_AMD_VIPER_740B: - r->name = "AMD756"; - break; - case PCI_DEVICE_ID_AMD_VIPER_7413: - r->name = "AMD766"; - break; - case PCI_DEVICE_ID_AMD_VIPER_7443: - r->name = "AMD768"; - break; - default: - return 0; - } - r->get = pirq_amd756_get; - r->set = pirq_amd756_set; - return 1; -} - -static __initdata struct irq_router_handler pirq_routers[] = { - { PCI_VENDOR_ID_INTEL, intel_router_probe }, - { PCI_VENDOR_ID_AL, ali_router_probe }, - { PCI_VENDOR_ID_ITE, ite_router_probe }, - { PCI_VENDOR_ID_VIA, via_router_probe }, - { PCI_VENDOR_ID_OPTI, opti_router_probe }, - { PCI_VENDOR_ID_SI, sis_router_probe }, - { PCI_VENDOR_ID_CYRIX, cyrix_router_probe }, - { PCI_VENDOR_ID_VLSI, vlsi_router_probe }, - { PCI_VENDOR_ID_SERVERWORKS, serverworks_router_probe }, - { PCI_VENDOR_ID_AMD, amd_router_probe }, - /* Someone with docs needs to add the ATI Radeon IGP */ - { 0, NULL } -}; -static struct irq_router pirq_router; -static struct pci_dev *pirq_router_dev; - - -/* - * FIXME: should we have an option to say "generic for - * chipset" ? - */ - -static void __init pirq_find_router(struct irq_router *r) -{ - struct irq_routing_table *rt = pirq_table; - struct irq_router_handler *h; - -#ifdef CONFIG_PCI_BIOS - if (!rt->signature) { - printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n"); - r->set = pirq_bios_set; - r->name = "BIOS"; - return; - } -#endif - - /* Default unless a driver reloads it */ - r->name = "default"; - r->get = NULL; - r->set = NULL; - - DBG(KERN_DEBUG "PCI: Attempting to find IRQ router for %04x:%04x\n", - rt->rtr_vendor, rt->rtr_device); - - pirq_router_dev = pci_get_bus_and_slot(rt->rtr_bus, rt->rtr_devfn); - if (!pirq_router_dev) { - DBG(KERN_DEBUG "PCI: Interrupt router not found at " - "%02x:%02x\n", rt->rtr_bus, rt->rtr_devfn); - return; - } - - for( h = pirq_routers; h->vendor; h++) { - /* First look for a router match */ - if (rt->rtr_vendor == h->vendor && h->probe(r, pirq_router_dev, rt->rtr_device)) - break; - /* Fall back to a device match */ - if (pirq_router_dev->vendor == h->vendor && h->probe(r, pirq_router_dev, pirq_router_dev->device)) - break; - } - printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n", - pirq_router.name, - pirq_router_dev->vendor, - pirq_router_dev->device, - pci_name(pirq_router_dev)); - - /* The device remains referenced for the kernel lifetime */ -} - -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 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 = NULL; - char *msg = NULL; - - /* Find IRQ pin */ - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - if (!pin) { - DBG(KERN_DEBUG " -> no interrupt pin\n"); - return 0; - } - pin = pin - 1; - - /* Find IRQ routing entry */ - - if (!pirq_table) - return 0; - - DBG(KERN_DEBUG "IRQ for %s[%c]", pci_name(dev), 'A' + pin); - info = pirq_get_info(dev); - if (!info) { - DBG(" -> not found in routing table\n" KERN_DEBUG); - return 0; - } - pirq = info->irq[pin].link; - mask = info->irq[pin].bitmap; - if (!pirq) { - DBG(" -> not routed\n" KERN_DEBUG); - 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); - } - - /* same for Acer Travelmate 360, but with CB and irq 11 -> 10 */ - if (acer_tm360_irqrouting && dev->irq == 11 && dev->vendor == PCI_VENDOR_ID_O2) { - pirq = 0x68; - mask = 0x400; - dev->irq = r->get(pirq_router_dev, dev, pirq); - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - } - - /* - * Find the best IRQ to assign: use the one - * reported by the device if possible. - */ - newirq = dev->irq; - if (newirq && !((1 << newirq) & mask)) { - if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0; - else printk("\n" KERN_WARNING - "PCI: IRQ %i for device %s doesn't match PIRQ mask " - "- try pci=usepirqmask\n" KERN_DEBUG, newirq, - pci_name(dev)); - } - if (!newirq && assign) { - for (i = 0; i < 16; i++) { - if (!(mask & (1 << i))) - continue; - if (pirq_penalty[i] < pirq_penalty[newirq] && can_request_irq(i, IRQF_SHARED)) - 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"; - eisa_set_level_irq(irq); - } 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, pci_name(dev)); - - /* Update IRQ for all devices with the same pirq value */ - while ((dev2 = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) { - 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)) ) { -#ifndef CONFIG_PCI_MSI - printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n", - pci_name(dev2), dev2->irq, irq); -#endif - continue; - } - dev2->irq = irq; - pirq_penalty[irq]++; - if (dev != dev2) - printk(KERN_INFO "PCI: Sharing IRQ %d with %s\n", irq, pci_name(dev2)); - } - } - return 1; -} - -static void __init pcibios_fixup_irqs(void) -{ - struct pci_dev *dev = NULL; - u8 pin; - - DBG(KERN_DEBUG "PCI: IRQ fixup\n"); - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - /* - * 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(KERN_DEBUG "%s: ignoring bogus IRQ %d\n", pci_name(dev), 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]++; - } - - dev = NULL; - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - 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 %s[%c] to get irq %d\n", - pci_name(bridge), 'A' + pin, irq); - } - if (irq >= 0) { - printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", - pci_name(dev), 'A' + pin, irq); - dev->irq = irq; - } - } - } -#endif - /* - * Still no IRQ? Try to lookup one... - */ - if (pin && !dev->irq) - pcibios_lookup_irq(dev, 0); - } -} - -/* - * Work around broken HP Pavilion Notebooks which assign USB to - * IRQ 9 even though it is actually wired to IRQ 11 - */ -static int __init fix_broken_hp_bios_irq9(struct dmi_system_id *d) -{ - if (!broken_hp_bios_irq9) { - broken_hp_bios_irq9 = 1; - printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident); - } - return 0; -} - -/* - * Work around broken Acer TravelMate 360 Notebooks which assign - * Cardbus to IRQ 11 even though it is actually wired to IRQ 10 - */ -static int __init fix_acer_tm360_irqrouting(struct dmi_system_id *d) -{ - if (!acer_tm360_irqrouting) { - acer_tm360_irqrouting = 1; - printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident); - } - return 0; -} - -static struct dmi_system_id __initdata pciirq_dmi_table[] = { - { - .callback = fix_broken_hp_bios_irq9, - .ident = "HP Pavilion N5400 Series Laptop", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_BIOS_VERSION, "GE.M1.03"), - DMI_MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"), - DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"), - }, - }, - { - .callback = fix_acer_tm360_irqrouting, - .ident = "Acer TravelMate 36x Laptop", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), - }, - }, - { } -}; - -static int __init pcibios_irq_init(void) -{ - DBG(KERN_DEBUG "PCI: IRQ init\n"); - - if (pcibios_enable_irq || raw_pci_ops == NULL) - return 0; - - dmi_check_system(pciirq_dmi_table); - - 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(&pirq_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; - } - - pcibios_enable_irq = pirq_enable_irq; - - pcibios_fixup_irqs(); - return 0; -} - -subsys_initcall(pcibios_irq_init); - - -static void pirq_penalize_isa_irq(int irq, int active) -{ - /* - * If any ISAPnP device reports an IRQ in its list of possible - * IRQ's, we try to avoid assigning it to PCI devices. - */ - if (irq < 16) { - if (active) - pirq_penalty[irq] += 1000; - else - pirq_penalty[irq] += 100; - } -} - -void pcibios_penalize_isa_irq(int irq, int active) -{ -#ifdef CONFIG_ACPI - if (!acpi_noirq) - acpi_penalize_isa_irq(irq, active); - else -#endif - pirq_penalize_isa_irq(irq, active); -} - -static int pirq_enable_irq(struct pci_dev *dev) -{ - u8 pin; - struct pci_dev *temp_dev; - - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) { - char *msg = ""; - - pin--; /* interrupt pins are numbered starting from 1 */ - - if (io_apic_assign_pci_irqs) { - int irq; - - 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. - */ - temp_dev = dev; - while (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 %s[%c] to get irq %d\n", - pci_name(bridge), 'A' + pin, irq); - dev = bridge; - } - dev = temp_dev; - if (irq >= 0) { - printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", - pci_name(dev), 'A' + pin, irq); - dev->irq = irq; - return 0; - } else - msg = " Probably buggy MP table."; - } else if (pci_probe & PCI_BIOS_IRQ_SCAN) - msg = ""; - else - msg = " Please try using pci=biosirq."; - - /* With IDE legacy devices the IRQ lookup failure is not a problem.. */ - if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5)) - return 0; - - printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n", - 'A' + pin, pci_name(dev), msg); - } - return 0; -} diff --git a/arch/i386/pci/legacy.c b/arch/i386/pci/legacy.c deleted file mode 100644 index 5565d70..0000000 --- a/arch/i386/pci/legacy.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * legacy.c - traditional, old school PCI bus probing - */ -#include <linux/init.h> -#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, devfn; - - if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff) - return; - DBG("PCI: Peer bridge fixup\n"); - - for (n=0; n <= pcibios_last_bus; n++) { - u32 l; - if (pci_find_bus(0, n)) - continue; - for (devfn = 0; devfn < 256; devfn += 8) { - if (!raw_pci_ops->read(0, n, devfn, PCI_VENDOR_ID, 2, &l) && - l != 0x0000 && l != 0xffff) { - DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l); - printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n); - pci_scan_bus_with_sysdata(n); - break; - } - } - } -} - -static int __init pci_legacy_init(void) -{ - if (!raw_pci_ops) { - printk("PCI: System does not support PCI\n"); - return 0; - } - - if (pcibios_scanned++) - return 0; - - printk("PCI: Probing PCI hardware\n"); - pci_root_bus = pcibios_scan_root(0); - if (pci_root_bus) - pci_bus_add_devices(pci_root_bus); - - pcibios_fixup_peer_bridges(); - - return 0; -} - -subsys_initcall(pci_legacy_init); diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/i386/pci/mmconfig-shared.c deleted file mode 100644 index 4df637e..0000000 --- a/arch/i386/pci/mmconfig-shared.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * mmconfig-shared.c - Low-level direct PCI config space access via - * MMCONFIG - common code between i386 and x86-64. - * - * This code does: - * - known chipset handling - * - ACPI decoding and validation - * - * Per-architecture code takes care of the mappings and accesses - * themselves. - */ - -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/acpi.h> -#include <linux/bitmap.h> -#include <asm/e820.h> - -#include "pci.h" - -/* aperture is up to 256MB but BIOS may reserve less */ -#define MMCONFIG_APER_MIN (2 * 1024*1024) -#define MMCONFIG_APER_MAX (256 * 1024*1024) - -DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS); - -/* Indicate if the mmcfg resources have been placed into the resource table. */ -static int __initdata pci_mmcfg_resources_inserted; - -/* K8 systems have some devices (typically in the builtin northbridge) - that are only accessible using type1 - Normally this can be expressed in the MCFG by not listing them - and assigning suitable _SEGs, but this isn't implemented in some BIOS. - Instead try to discover all devices on bus 0 that are unreachable using MM - and fallback for them. */ -static void __init unreachable_devices(void) -{ - int i, bus; - /* Use the max bus number from ACPI here? */ - for (bus = 0; bus < PCI_MMCFG_MAX_CHECK_BUS; bus++) { - for (i = 0; i < 32; i++) { - unsigned int devfn = PCI_DEVFN(i, 0); - u32 val1, val2; - - pci_conf1_read(0, bus, devfn, 0, 4, &val1); - if (val1 == 0xffffffff) - continue; - - if (pci_mmcfg_arch_reachable(0, bus, devfn)) { - raw_pci_ops->read(0, bus, devfn, 0, 4, &val2); - if (val1 == val2) - continue; - } - set_bit(i + 32 * bus, pci_mmcfg_fallback_slots); - printk(KERN_NOTICE "PCI: No mmconfig possible on device" - " %02x:%02x\n", bus, i); - } - } -} - -static const char __init *pci_mmcfg_e7520(void) -{ - u32 win; - pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win); - - win = win & 0xf000; - if(win == 0x0000 || win == 0xf000) - pci_mmcfg_config_num = 0; - else { - pci_mmcfg_config_num = 1; - pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); - if (!pci_mmcfg_config) - return NULL; - pci_mmcfg_config[0].address = win << 16; - pci_mmcfg_config[0].pci_segment = 0; - pci_mmcfg_config[0].start_bus_number = 0; - pci_mmcfg_config[0].end_bus_number = 255; - } - - return "Intel Corporation E7520 Memory Controller Hub"; -} - -static const char __init *pci_mmcfg_intel_945(void) -{ - u32 pciexbar, mask = 0, len = 0; - - pci_mmcfg_config_num = 1; - - pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar); - - /* Enable bit */ - if (!(pciexbar & 1)) - pci_mmcfg_config_num = 0; - - /* Size bits */ - switch ((pciexbar >> 1) & 3) { - case 0: - mask = 0xf0000000U; - len = 0x10000000U; - break; - case 1: - mask = 0xf8000000U; - len = 0x08000000U; - break; - case 2: - mask = 0xfc000000U; - len = 0x04000000U; - break; - default: - pci_mmcfg_config_num = 0; - } - - /* Errata #2, things break when not aligned on a 256Mb boundary */ - /* Can only happen in 64M/128M mode */ - - if ((pciexbar & mask) & 0x0fffffffU) - pci_mmcfg_config_num = 0; - - /* Don't hit the APIC registers and their friends */ - if ((pciexbar & mask) >= 0xf0000000U) - pci_mmcfg_config_num = 0; - - if (pci_mmcfg_config_num) { - pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); - if (!pci_mmcfg_config) - return NULL; - pci_mmcfg_config[0].address = pciexbar & mask; - pci_mmcfg_config[0].pci_segment = 0; - pci_mmcfg_config[0].start_bus_number = 0; - pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1; - } - - return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; -} - -struct pci_mmcfg_hostbridge_probe { - u32 vendor; - u32 device; - const char *(*probe)(void); -}; - -static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 }, -}; - -static int __init pci_mmcfg_check_hostbridge(void) -{ - u32 l; - u16 vendor, device; - int i; - const char *name; - - pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0, 4, &l); - vendor = l & 0xffff; - device = (l >> 16) & 0xffff; - - pci_mmcfg_config_num = 0; - pci_mmcfg_config = NULL; - name = NULL; - - for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) { - if (pci_mmcfg_probes[i].vendor == vendor && - pci_mmcfg_probes[i].device == device) - name = pci_mmcfg_probes[i].probe(); - } - - if (name) { - printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n", - name, pci_mmcfg_config_num ? "with" : "without"); - } - - return name != NULL; -} - -static void __init pci_mmcfg_insert_resources(unsigned long resource_flags) -{ -#define PCI_MMCFG_RESOURCE_NAME_LEN 19 - int i; - struct resource *res; - char *names; - unsigned num_buses; - - res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res), - pci_mmcfg_config_num, GFP_KERNEL); - if (!res) { - printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n"); - return; - } - - names = (void *)&res[pci_mmcfg_config_num]; - for (i = 0; i < pci_mmcfg_config_num; i++, res++) { - struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i]; - num_buses = cfg->end_bus_number - cfg->start_bus_number + 1; - res->name = names; - snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u", - cfg->pci_segment); - res->start = cfg->address; - res->end = res->start + (num_buses << 20) - 1; - res->flags = IORESOURCE_MEM | resource_flags; - insert_resource(&iomem_resource, res); - names += PCI_MMCFG_RESOURCE_NAME_LEN; - } - - /* Mark that the resources have been inserted. */ - pci_mmcfg_resources_inserted = 1; -} - -static void __init pci_mmcfg_reject_broken(int type) -{ - typeof(pci_mmcfg_config[0]) *cfg; - - if ((pci_mmcfg_config_num == 0) || - (pci_mmcfg_config == NULL) || - (pci_mmcfg_config[0].address == 0)) - return; - - cfg = &pci_mmcfg_config[0]; - - /* - * Handle more broken MCFG tables on Asus etc. - * They only contain a single entry for bus 0-0. - */ - if (pci_mmcfg_config_num == 1 && - cfg->pci_segment == 0 && - (cfg->start_bus_number | cfg->end_bus_number) == 0) { - printk(KERN_ERR "PCI: start and end of bus number is 0. " - "Rejected as broken MCFG.\n"); - goto reject; - } - - /* - * Only do this check when type 1 works. If it doesn't work - * assume we run on a Mac and always use MCFG - */ - if (type == 1 && !e820_all_mapped(cfg->address, - cfg->address + MMCONFIG_APER_MIN, - E820_RESERVED)) { - printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not" - " E820-reserved\n", cfg->address); - goto reject; - } - return; - -reject: - printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); - kfree(pci_mmcfg_config); - pci_mmcfg_config = NULL; - pci_mmcfg_config_num = 0; -} - -void __init pci_mmcfg_init(int type) -{ - int known_bridge = 0; - - if ((pci_probe & PCI_PROBE_MMCONF) == 0) - return; - - if (type == 1 && pci_mmcfg_check_hostbridge()) - known_bridge = 1; - - if (!known_bridge) { - acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); - pci_mmcfg_reject_broken(type); - } - - if ((pci_mmcfg_config_num == 0) || - (pci_mmcfg_config == NULL) || - (pci_mmcfg_config[0].address == 0)) - return; - - if (pci_mmcfg_arch_init()) { - if (type == 1) - unreachable_devices(); - if (known_bridge) - pci_mmcfg_insert_resources(IORESOURCE_BUSY); - pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; - } else { - /* - * Signal not to attempt to insert mmcfg resources because - * the architecture mmcfg setup could not initialize. - */ - pci_mmcfg_resources_inserted = 1; - } -} - -static int __init pci_mmcfg_late_insert_resources(void) -{ - /* - * If resources are already inserted or we are not using MMCONFIG, - * don't insert the resources. - */ - if ((pci_mmcfg_resources_inserted == 1) || - (pci_probe & PCI_PROBE_MMCONF) == 0 || - (pci_mmcfg_config_num == 0) || - (pci_mmcfg_config == NULL) || - (pci_mmcfg_config[0].address == 0)) - return 1; - - /* - * Attempt to insert the mmcfg resources but not with the busy flag - * marked so it won't cause request errors when __request_region is - * called. - */ - pci_mmcfg_insert_resources(0); - - return 0; -} - -/* - * Perform MMCONFIG resource insertion after PCI initialization to allow for - * misprogrammed MCFG tables that state larger sizes but actually conflict - * with other system resources. - */ -late_initcall(pci_mmcfg_late_insert_resources); diff --git a/arch/i386/pci/mmconfig_32.c b/arch/i386/pci/mmconfig_32.c deleted file mode 100644 index 1bf5816..0000000 --- a/arch/i386/pci/mmconfig_32.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2004 Matthew Wilcox <matthew@wil.cx> - * Copyright (C) 2004 Intel Corp. - * - * This code is released under the GNU General Public License version 2. - */ - -/* - * mmconfig.c - Low-level direct PCI config space access via MMCONFIG - */ - -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/acpi.h> -#include <asm/e820.h> -#include "pci.h" - -/* Assume systems with more busses have correct MCFG */ -#define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) - -/* The base address of the last MMCONFIG device accessed */ -static u32 mmcfg_last_accessed_device; -static int mmcfg_last_accessed_cpu; - -/* - * Functions for accessing PCI configuration space with MMCONFIG accesses - */ -static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) -{ - struct acpi_mcfg_allocation *cfg; - int cfg_num; - - if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS && - test_bit(PCI_SLOT(devfn) + 32*bus, pci_mmcfg_fallback_slots)) - return 0; - - for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { - cfg = &pci_mmcfg_config[cfg_num]; - if (cfg->pci_segment == seg && - (cfg->start_bus_number <= bus) && - (cfg->end_bus_number >= bus)) - return cfg->address; - } - - /* Fall back to type 0 */ - return 0; -} - -/* - * This is always called under pci_config_lock - */ -static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn) -{ - u32 dev_base = base | (bus << 20) | (devfn << 12); - int cpu = smp_processor_id(); - if (dev_base != mmcfg_last_accessed_device || - cpu != mmcfg_last_accessed_cpu) { - mmcfg_last_accessed_device = dev_base; - mmcfg_last_accessed_cpu = cpu; - set_fixmap_nocache(FIX_PCIE_MCFG, dev_base); - } -} - -static int pci_mmcfg_read(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 *value) -{ - unsigned long flags; - u32 base; - - if ((bus > 255) || (devfn > 255) || (reg > 4095)) { - *value = -1; - return -EINVAL; - } - - base = get_base_addr(seg, bus, devfn); - if (!base) - return pci_conf1_read(seg,bus,devfn,reg,len,value); - - spin_lock_irqsave(&pci_config_lock, flags); - - pci_exp_set_dev_base(base, bus, devfn); - - switch (len) { - case 1: - *value = mmio_config_readb(mmcfg_virt_addr + reg); - break; - case 2: - *value = mmio_config_readw(mmcfg_virt_addr + reg); - break; - case 4: - *value = mmio_config_readl(mmcfg_virt_addr + reg); - break; - } - spin_unlock_irqrestore(&pci_config_lock, flags); - - return 0; -} - -static int pci_mmcfg_write(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 value) -{ - unsigned long flags; - u32 base; - - if ((bus > 255) || (devfn > 255) || (reg > 4095)) - return -EINVAL; - - base = get_base_addr(seg, bus, devfn); - if (!base) - return pci_conf1_write(seg,bus,devfn,reg,len,value); - - spin_lock_irqsave(&pci_config_lock, flags); - - pci_exp_set_dev_base(base, bus, devfn); - - switch (len) { - case 1: - mmio_config_writeb(mmcfg_virt_addr + reg, value); - break; - case 2: - mmio_config_writew(mmcfg_virt_addr + reg, value); - break; - case 4: - mmio_config_writel(mmcfg_virt_addr + reg, value); - break; - } - spin_unlock_irqrestore(&pci_config_lock, flags); - - return 0; -} - -static struct pci_raw_ops pci_mmcfg = { - .read = pci_mmcfg_read, - .write = pci_mmcfg_write, -}; - -int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus, - unsigned int devfn) -{ - return get_base_addr(seg, bus, devfn) != 0; -} - -int __init pci_mmcfg_arch_init(void) -{ - printk(KERN_INFO "PCI: Using MMCONFIG\n"); - raw_pci_ops = &pci_mmcfg; - return 1; -} diff --git a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c deleted file mode 100644 index f5f165f..0000000 --- a/arch/i386/pci/numa.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * numa.c - Low-level PCI access for NUMA-Q machines - */ - -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/nodemask.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_MQ_ADDRESS(bus, devfn, reg) \ - (0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3)) - -static int pci_conf1_mq_read(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 *value) -{ - unsigned long flags; - - if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) - return -EINVAL; - - spin_lock_irqsave(&pci_config_lock, flags); - - outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, 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_mq_write(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 value) -{ - unsigned long flags; - - if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) - return -EINVAL; - - spin_lock_irqsave(&pci_config_lock, flags); - - outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, 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; -} - -#undef PCI_CONF1_MQ_ADDRESS - -static struct pci_raw_ops pci_direct_conf1_mq = { - .read = pci_conf1_mq_read, - .write = pci_conf1_mq_write -}; - - -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", pci_name(d)); - 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) { - /* Bus A */ - pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, busno)); - } - if (suba < subb) { - /* Bus B */ - pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, suba+1)); - } - } - pcibios_last_bus = -1; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx); - -static int __init pci_numa_init(void) -{ - int quad; - - raw_pci_ops = &pci_direct_conf1_mq; - - if (pcibios_scanned++) - return 0; - - pci_root_bus = pcibios_scan_root(0); - if (pci_root_bus) - pci_bus_add_devices(pci_root_bus); - if (num_online_nodes() > 1) - for_each_online_node(quad) { - if (quad == 0) - continue; - printk("Scanning PCI bus %d for quad %d\n", - QUADLOCAL2BUS(quad,0), quad); - pci_scan_bus_with_sysdata(QUADLOCAL2BUS(quad, 0)); - } - return 0; -} - -subsys_initcall(pci_numa_init); diff --git a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c deleted file mode 100644 index 10ac8c3..0000000 --- a/arch/i386/pci/pcbios.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - * BIOS32 and PCI BIOS handling. - */ - -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/uaccess.h> -#include "pci.h" -#include "pci-functions.h" - - -/* 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; - - local_irq_save(flags); - __asm__("lcall *(%%edi); cld" - : "=a" (return_code), - "=b" (address), - "=c" (length), - "=d" (entry) - : "0" (service), - "1" (0), - "D" (&bios32_indirect)); - local_irq_restore(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; - - local_irq_save(flags); - __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"); - local_irq_restore(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(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 *value) -{ - unsigned long result = 0; - unsigned long flags; - unsigned long bx = (bus << 8) | devfn; - - if (!value || (bus > 255) || (devfn > 255) || (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(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 value) -{ - unsigned long result = 0; - unsigned long flags; - unsigned long bx = (bus << 8) | devfn; - - if ((bus > 255) || (devfn > 255) || (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); -} - - -/* - * Function table for BIOS32 access - */ - -static struct pci_raw_ops pci_bios_access = { - .read = pci_bios_read, - .write = pci_bios_write -}; - -/* - * Try to find PCI BIOS. - */ - -static struct pci_raw_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) { - long sig; - if (probe_kernel_address(&check->fields.signature, sig)) - continue; - - 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++; - list_for_each(ln, &pci_devices) { - d = pci_dev_g(ln); - if (d->bus->number == bus && d->devfn == devfn) { - list_move_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 %s not found by BIOS\n", - pci_name(dev)); - list_move_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 * 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), - "=m" (opt) - : "0" (PCIBIOS_GET_ROUTING_OPTIONS), - "1" (0), - "D" ((long) &opt), - "S" (&pci_indirect), - "m" (opt) - : "memory"); - 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; -} -EXPORT_SYMBOL(pcibios_get_irq_routing_table); - -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); -} -EXPORT_SYMBOL(pcibios_set_irq_routing); - -void __init pci_pcbios_init(void) -{ - if ((pci_probe & PCI_PROBE_BIOS) - && ((raw_pci_ops = pci_find_bios()))) { - pci_probe |= PCI_BIOS_SORT; - pci_bios_present = 1; - } -} - diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h deleted file mode 100644 index 8c66f27..0000000 --- a/arch/i386/pci/pci.h +++ /dev/null @@ -1,149 +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_PROBE_MMCONF 0x0008 -#define PCI_PROBE_MASK 0x000f -#define PCI_PROBE_NOEARLY 0x0010 - -#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 - -extern unsigned int pci_probe; -extern unsigned long pirq_table_addr; - -enum pci_bf_sort_state { - pci_bf_sort_default, - pci_force_nobf, - pci_force_bf, - pci_dmi_bf, -}; - -/* pci-i386.c */ - -extern unsigned int pcibios_max_latency; - -void pcibios_resource_survey(void); -int pcibios_enable_resources(struct pci_dev *, int); - -/* 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 pcibios_scanned; -extern spinlock_t pci_config_lock; - -extern int (*pcibios_enable_irq)(struct pci_dev *dev); -extern void (*pcibios_disable_irq)(struct pci_dev *dev); - -extern int pci_conf1_write(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 value); -extern int pci_conf1_read(unsigned int seg, unsigned int bus, - unsigned int devfn, int reg, int len, u32 *value); - -extern int pci_direct_probe(void); -extern void pci_direct_init(int type); -extern void pci_pcbios_init(void); -extern void pci_mmcfg_init(int type); -extern void pcibios_sort(void); - -/* pci-mmconfig.c */ - -/* Verify the first 16 busses. We assume that systems with more busses - get MCFG right. */ -#define PCI_MMCFG_MAX_CHECK_BUS 16 -extern DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS); - -extern int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus, - unsigned int devfn); -extern int __init pci_mmcfg_arch_init(void); - -/* - * AMD Fam10h CPUs are buggy, and cannot access MMIO config space - * on their northbrige except through the * %eax register. As such, you MUST - * NOT use normal IOMEM accesses, you need to only use the magic mmio-config - * accessor functions. - * In fact just use pci_config_*, nothing else please. - */ -static inline unsigned char mmio_config_readb(void __iomem *pos) -{ - u8 val; - asm volatile("movb (%1),%%al" : "=a" (val) : "r" (pos)); - return val; -} - -static inline unsigned short mmio_config_readw(void __iomem *pos) -{ - u16 val; - asm volatile("movw (%1),%%ax" : "=a" (val) : "r" (pos)); - return val; -} - -static inline unsigned int mmio_config_readl(void __iomem *pos) -{ - u32 val; - asm volatile("movl (%1),%%eax" : "=a" (val) : "r" (pos)); - return val; -} - -static inline void mmio_config_writeb(void __iomem *pos, u8 val) -{ - asm volatile("movb %%al,(%1)" :: "a" (val), "r" (pos) : "memory"); -} - -static inline void mmio_config_writew(void __iomem *pos, u16 val) -{ - asm volatile("movw %%ax,(%1)" :: "a" (val), "r" (pos) : "memory"); -} - -static inline void mmio_config_writel(void __iomem *pos, u32 val) -{ - asm volatile("movl %%eax,(%1)" :: "a" (val), "r" (pos) : "memory"); -} diff --git a/arch/i386/pci/visws.c b/arch/i386/pci/visws.c deleted file mode 100644 index 8ecb1c7..0000000 --- a/arch/i386/pci/visws.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Low-Level PCI Support for SGI Visual Workstation - * - * (c) 1999--2000 Martin Mares <mj@ucw.cz> - */ - -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/init.h> - -#include "cobalt.h" -#include "lithium.h" - -#include "pci.h" - - -extern struct pci_raw_ops pci_direct_conf1; - -static int pci_visws_enable_irq(struct pci_dev *dev) { return 0; } -static void pci_visws_disable_irq(struct pci_dev *dev) { } - -int (*pcibios_enable_irq)(struct pci_dev *dev) = &pci_visws_enable_irq; -void (*pcibios_disable_irq)(struct pci_dev *dev) = &pci_visws_disable_irq; - -void __init pcibios_penalize_isa_irq(int irq, int active) {} - - -unsigned int pci_bus0, pci_bus1; - -static inline u8 bridge_swizzle(u8 pin, u8 slot) -{ - return (((pin - 1) + slot) % 4) + 1; -} - -static u8 __init visws_swizzle(struct pci_dev *dev, u8 *pinp) -{ - u8 pin = *pinp; - - while (dev->bus->self) { /* Move up the chain of bridges. */ - pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); - dev = dev->bus->self; - } - *pinp = pin; - - return PCI_SLOT(dev->devfn); -} - -static int __init visws_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - int irq, bus = dev->bus->number; - - pin--; - - /* Nothing useful at PIIX4 pin 1 */ - if (bus == pci_bus0 && slot == 4 && pin == 0) - return -1; - - /* PIIX4 USB is on Bus 0, Slot 4, Line 3 */ - if (bus == pci_bus0 && slot == 4 && pin == 3) { - irq = CO_IRQ(CO_APIC_PIIX4_USB); - goto out; - } - - /* First pin spread down 1 APIC entry per slot */ - if (pin == 0) { - irq = CO_IRQ((bus == pci_bus0 ? CO_APIC_PCIB_BASE0 : - CO_APIC_PCIA_BASE0) + slot); - goto out; - } - - /* lines 1,2,3 from any slot is shared in this twirly pattern */ - if (bus == pci_bus1) { - /* lines 1-3 from devices 0 1 rotate over 2 apic entries */ - irq = CO_IRQ(CO_APIC_PCIA_BASE123 + ((slot + (pin - 1)) % 2)); - } else { /* bus == pci_bus0 */ - /* lines 1-3 from devices 0-3 rotate over 3 apic entries */ - if (slot == 0) - slot = 3; /* same pattern */ - irq = CO_IRQ(CO_APIC_PCIA_BASE123 + ((3 - slot) + (pin - 1) % 3)); - } -out: - printk(KERN_DEBUG "PCI: Bus %d Slot %d Line %d -> IRQ %d\n", bus, slot, pin, irq); - return irq; -} - -void __init pcibios_update_irq(struct pci_dev *dev, int irq) -{ - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); -} - -static int __init pcibios_init(void) -{ - /* The VISWS supports configuration access type 1 only */ - pci_probe = (pci_probe | PCI_PROBE_CONF1) & - ~(PCI_PROBE_BIOS | PCI_PROBE_CONF2); - - pci_bus0 = li_pcib_read16(LI_PCI_BUSNUM) & 0xff; - pci_bus1 = li_pcia_read16(LI_PCI_BUSNUM) & 0xff; - - printk(KERN_INFO "PCI: Lithium bridge A bus: %u, " - "bridge B (PIIX4) bus: %u\n", pci_bus1, pci_bus0); - - raw_pci_ops = &pci_direct_conf1; - pci_scan_bus_with_sysdata(pci_bus0); - pci_scan_bus_with_sysdata(pci_bus1); - pci_fixup_irqs(visws_swizzle, visws_map_irq); - pcibios_resource_survey(); - return 0; -} - -subsys_initcall(pcibios_init); |