diff options
-rw-r--r-- | arch/x86/pci/acpi.c | 42 | ||||
-rw-r--r-- | arch/x86/pci/i386.c | 13 | ||||
-rw-r--r-- | arch/x86/pci/pci.h | 1 | ||||
-rw-r--r-- | drivers/pci/probe.c | 4 |
4 files changed, 58 insertions, 2 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index bc8a44bddaa7..1dd6f3fc077d 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -2,15 +2,57 @@ #include <linux/acpi.h> #include <linux/init.h> #include <linux/irq.h> +#include <linux/dmi.h> #include <asm/numa.h> #include "pci.h" +static int __devinit can_skip_ioresource_align(struct dmi_system_id *d) +{ + pci_probe |= PCI_CAN_SKIP_ISA_ALIGN; + printk(KERN_INFO "PCI: %s detected, can skip ISA alignment\n", d->ident); + return 0; +} + +static struct dmi_system_id acpi_pciprobe_dmi_table[] = { +/* + * Systems where PCI IO resource ISA alignment can be skipped + * when the ISA enable bit in the bridge control is not set + */ + { + .callback = can_skip_ioresource_align, + .ident = "IBM System x3800", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IBM"), + DMI_MATCH(DMI_PRODUCT_NAME, "x3800"), + }, + }, + { + .callback = can_skip_ioresource_align, + .ident = "IBM System x3850", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IBM"), + DMI_MATCH(DMI_PRODUCT_NAME, "x3850"), + }, + }, + { + .callback = can_skip_ioresource_align, + .ident = "IBM System x3950", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IBM"), + DMI_MATCH(DMI_PRODUCT_NAME, "x3950"), + }, + }, + {} +}; + 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; + dmi_check_system(acpi_pciprobe_dmi_table); + /* 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. diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index bcd2f94b732c..055187bc255a 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -33,6 +33,15 @@ #include "pci.h" +static int +skip_isa_ioresource_align(struct pci_dev *dev) { + + if ((pci_probe & PCI_CAN_SKIP_ISA_ALIGN) && + (dev->bus->bridge_ctl & PCI_BRIDGE_CTL_NO_ISA)) + return 1; + return 0; +} + /* * We need to avoid collisions with `mirrored' VGA ports * and other strange ISA hardware, so we always want the @@ -50,9 +59,13 @@ void pcibios_align_resource(void *data, struct resource *res, resource_size_t size, resource_size_t align) { + struct pci_dev *dev = data; + if (res->flags & IORESOURCE_IO) { resource_size_t start = res->start; + if (skip_isa_ioresource_align(dev)) + return; if (start & 0x300) { start = (start + 0x3ff) & ~0x3ff; res->start = start; diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h index 8c66f275756f..057f335fa3f6 100644 --- a/arch/x86/pci/pci.h +++ b/arch/x86/pci/pci.h @@ -26,6 +26,7 @@ #define PCI_ASSIGN_ROMS 0x1000 #define PCI_BIOS_IRQ_SCAN 0x2000 #define PCI_ASSIGN_ALL_BUSSES 0x4000 +#define PCI_CAN_SKIP_ISA_ALIGN 0x8000 extern unsigned int pci_probe; extern unsigned long pirq_table_addr; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 40e571d3c392..59d6c3092812 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -544,7 +544,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass goto out; child->primary = buses & 0xFF; child->subordinate = (buses >> 16) & 0xFF; - child->bridge_ctl = bctl; + child->bridge_ctl = bctl ^ PCI_BRIDGE_CTL_NO_ISA; cmax = pci_scan_child_bus(child); if (cmax > max) @@ -597,7 +597,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); if (!is_cardbus) { - child->bridge_ctl = bctl | PCI_BRIDGE_CTL_NO_ISA; + child->bridge_ctl = bctl ^ PCI_BRIDGE_CTL_NO_ISA; /* * Adjust subordinate busnr in parent buses. * We do this before scanning for children because |