diff options
author | Gary Hade <garyhade@us.ibm.com> | 2007-10-03 18:56:14 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-10-12 18:03:18 -0400 |
commit | 036fff4cf732c4d69f99a2915924935705744b00 (patch) | |
tree | 87f6f02e40e8f5c28e6d629e009e6e64a45eec58 | |
parent | 8fa5913d54f3b1e09948e6a0db34da887e05ff1f (diff) |
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: Gary Hade <gary.hade@us.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-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 @@ | |||
2 | #include <linux/acpi.h> | 2 | #include <linux/acpi.h> |
3 | #include <linux/init.h> | 3 | #include <linux/init.h> |
4 | #include <linux/irq.h> | 4 | #include <linux/irq.h> |
5 | #include <linux/dmi.h> | ||
5 | #include <asm/numa.h> | 6 | #include <asm/numa.h> |
6 | #include "pci.h" | 7 | #include "pci.h" |
7 | 8 | ||
9 | static int __devinit can_skip_ioresource_align(struct dmi_system_id *d) | ||
10 | { | ||
11 | pci_probe |= PCI_CAN_SKIP_ISA_ALIGN; | ||
12 | printk(KERN_INFO "PCI: %s detected, can skip ISA alignment\n", d->ident); | ||
13 | return 0; | ||
14 | } | ||
15 | |||
16 | static struct dmi_system_id acpi_pciprobe_dmi_table[] = { | ||
17 | /* | ||
18 | * Systems where PCI IO resource ISA alignment can be skipped | ||
19 | * when the ISA enable bit in the bridge control is not set | ||
20 | */ | ||
21 | { | ||
22 | .callback = can_skip_ioresource_align, | ||
23 | .ident = "IBM System x3800", | ||
24 | .matches = { | ||
25 | DMI_MATCH(DMI_SYS_VENDOR, "IBM"), | ||
26 | DMI_MATCH(DMI_PRODUCT_NAME, "x3800"), | ||
27 | }, | ||
28 | }, | ||
29 | { | ||
30 | .callback = can_skip_ioresource_align, | ||
31 | .ident = "IBM System x3850", | ||
32 | .matches = { | ||
33 | DMI_MATCH(DMI_SYS_VENDOR, "IBM"), | ||
34 | DMI_MATCH(DMI_PRODUCT_NAME, "x3850"), | ||
35 | }, | ||
36 | }, | ||
37 | { | ||
38 | .callback = can_skip_ioresource_align, | ||
39 | .ident = "IBM System x3950", | ||
40 | .matches = { | ||
41 | DMI_MATCH(DMI_SYS_VENDOR, "IBM"), | ||
42 | DMI_MATCH(DMI_PRODUCT_NAME, "x3950"), | ||
43 | }, | ||
44 | }, | ||
45 | {} | ||
46 | }; | ||
47 | |||
8 | struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum) | 48 | struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum) |
9 | { | 49 | { |
10 | struct pci_bus *bus; | 50 | struct pci_bus *bus; |
11 | struct pci_sysdata *sd; | 51 | struct pci_sysdata *sd; |
12 | int pxm; | 52 | int pxm; |
13 | 53 | ||
54 | dmi_check_system(acpi_pciprobe_dmi_table); | ||
55 | |||
14 | /* Allocate per-root-bus (not per bus) arch-specific data. | 56 | /* Allocate per-root-bus (not per bus) arch-specific data. |
15 | * TODO: leak; this memory is never freed. | 57 | * TODO: leak; this memory is never freed. |
16 | * It's arguable whether it's worth the trouble to care. | 58 | * 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 @@ | |||
33 | 33 | ||
34 | #include "pci.h" | 34 | #include "pci.h" |
35 | 35 | ||
36 | static int | ||
37 | skip_isa_ioresource_align(struct pci_dev *dev) { | ||
38 | |||
39 | if ((pci_probe & PCI_CAN_SKIP_ISA_ALIGN) && | ||
40 | (dev->bus->bridge_ctl & PCI_BRIDGE_CTL_NO_ISA)) | ||
41 | return 1; | ||
42 | return 0; | ||
43 | } | ||
44 | |||
36 | /* | 45 | /* |
37 | * We need to avoid collisions with `mirrored' VGA ports | 46 | * We need to avoid collisions with `mirrored' VGA ports |
38 | * and other strange ISA hardware, so we always want the | 47 | * and other strange ISA hardware, so we always want the |
@@ -50,9 +59,13 @@ void | |||
50 | pcibios_align_resource(void *data, struct resource *res, | 59 | pcibios_align_resource(void *data, struct resource *res, |
51 | resource_size_t size, resource_size_t align) | 60 | resource_size_t size, resource_size_t align) |
52 | { | 61 | { |
62 | struct pci_dev *dev = data; | ||
63 | |||
53 | if (res->flags & IORESOURCE_IO) { | 64 | if (res->flags & IORESOURCE_IO) { |
54 | resource_size_t start = res->start; | 65 | resource_size_t start = res->start; |
55 | 66 | ||
67 | if (skip_isa_ioresource_align(dev)) | ||
68 | return; | ||
56 | if (start & 0x300) { | 69 | if (start & 0x300) { |
57 | start = (start + 0x3ff) & ~0x3ff; | 70 | start = (start + 0x3ff) & ~0x3ff; |
58 | res->start = start; | 71 | 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 @@ | |||
26 | #define PCI_ASSIGN_ROMS 0x1000 | 26 | #define PCI_ASSIGN_ROMS 0x1000 |
27 | #define PCI_BIOS_IRQ_SCAN 0x2000 | 27 | #define PCI_BIOS_IRQ_SCAN 0x2000 |
28 | #define PCI_ASSIGN_ALL_BUSSES 0x4000 | 28 | #define PCI_ASSIGN_ALL_BUSSES 0x4000 |
29 | #define PCI_CAN_SKIP_ISA_ALIGN 0x8000 | ||
29 | 30 | ||
30 | extern unsigned int pci_probe; | 31 | extern unsigned int pci_probe; |
31 | extern unsigned long pirq_table_addr; | 32 | 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 | |||
544 | goto out; | 544 | goto out; |
545 | child->primary = buses & 0xFF; | 545 | child->primary = buses & 0xFF; |
546 | child->subordinate = (buses >> 16) & 0xFF; | 546 | child->subordinate = (buses >> 16) & 0xFF; |
547 | child->bridge_ctl = bctl; | 547 | child->bridge_ctl = bctl ^ PCI_BRIDGE_CTL_NO_ISA; |
548 | 548 | ||
549 | cmax = pci_scan_child_bus(child); | 549 | cmax = pci_scan_child_bus(child); |
550 | if (cmax > max) | 550 | if (cmax > max) |
@@ -597,7 +597,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass | |||
597 | pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); | 597 | pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); |
598 | 598 | ||
599 | if (!is_cardbus) { | 599 | if (!is_cardbus) { |
600 | child->bridge_ctl = bctl | PCI_BRIDGE_CTL_NO_ISA; | 600 | child->bridge_ctl = bctl ^ PCI_BRIDGE_CTL_NO_ISA; |
601 | /* | 601 | /* |
602 | * Adjust subordinate busnr in parent buses. | 602 | * Adjust subordinate busnr in parent buses. |
603 | * We do this before scanning for children because | 603 | * We do this before scanning for children because |