Commit 036fff4c authored by Gary Hade's avatar Gary Hade Committed by Greg Kroah-Hartman

PCI: skip ISA ioresource alignment on some systems

Skip ISA ioresource alignment on some systems

To conserve limited PCI i/o resource on some IBM multi-node systems, the
BIOS allocates (via _CRS) and expects the kernel to use addresses in
ranges currently excluded by pcibios_align_resource() [i386/pci/i386.c].
This change allows the kernel to use the currently excluded address
ranges on the IBM x3800, x3850, and x3950.
Signed-off-by: default avatarGary Hade <gary.hade@us.ibm.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 8fa5913d
...@@ -2,15 +2,57 @@ ...@@ -2,15 +2,57 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/dmi.h>
#include <asm/numa.h> #include <asm/numa.h>
#include "pci.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 * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
{ {
struct pci_bus *bus; struct pci_bus *bus;
struct pci_sysdata *sd; struct pci_sysdata *sd;
int pxm; int pxm;
dmi_check_system(acpi_pciprobe_dmi_table);
/* Allocate per-root-bus (not per bus) arch-specific data. /* Allocate per-root-bus (not per bus) arch-specific data.
* TODO: leak; this memory is never freed. * TODO: leak; this memory is never freed.
* It's arguable whether it's worth the trouble to care. * It's arguable whether it's worth the trouble to care.
......
...@@ -33,6 +33,15 @@ ...@@ -33,6 +33,15 @@
#include "pci.h" #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 * We need to avoid collisions with `mirrored' VGA ports
* and other strange ISA hardware, so we always want the * and other strange ISA hardware, so we always want the
...@@ -50,9 +59,13 @@ void ...@@ -50,9 +59,13 @@ void
pcibios_align_resource(void *data, struct resource *res, pcibios_align_resource(void *data, struct resource *res,
resource_size_t size, resource_size_t align) resource_size_t size, resource_size_t align)
{ {
struct pci_dev *dev = data;
if (res->flags & IORESOURCE_IO) { if (res->flags & IORESOURCE_IO) {
resource_size_t start = res->start; resource_size_t start = res->start;
if (skip_isa_ioresource_align(dev))
return;
if (start & 0x300) { if (start & 0x300) {
start = (start + 0x3ff) & ~0x3ff; start = (start + 0x3ff) & ~0x3ff;
res->start = start; res->start = start;
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#define PCI_ASSIGN_ROMS 0x1000 #define PCI_ASSIGN_ROMS 0x1000
#define PCI_BIOS_IRQ_SCAN 0x2000 #define PCI_BIOS_IRQ_SCAN 0x2000
#define PCI_ASSIGN_ALL_BUSSES 0x4000 #define PCI_ASSIGN_ALL_BUSSES 0x4000
#define PCI_CAN_SKIP_ISA_ALIGN 0x8000
extern unsigned int pci_probe; extern unsigned int pci_probe;
extern unsigned long pirq_table_addr; extern unsigned long pirq_table_addr;
......
...@@ -544,7 +544,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass ...@@ -544,7 +544,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass
goto out; goto out;
child->primary = buses & 0xFF; child->primary = buses & 0xFF;
child->subordinate = (buses >> 16) & 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); cmax = pci_scan_child_bus(child);
if (cmax > max) if (cmax > max)
...@@ -597,7 +597,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass ...@@ -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); pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
if (!is_cardbus) { 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. * Adjust subordinate busnr in parent buses.
* We do this before scanning for children because * We do this before scanning for children because
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment