2006-12-07 18:17:31

by Olivier Galibert

[permalink] [raw]
Subject: [0/5] PCI MMConfig per-chipset support - v2

I'll try to be less messy this time.

OG.

1/5: PCI MMConfig: Share what's shareable.
Share code between i386 and x86-64

2/5: PCI MMConfig: Only call unreachable_devices() when type 1 is available.
Trivial fix.

3/5: PCI MMConfig: Only map what's necessary.
Trivial fix too.

4/5: PCI MMConfig: Detect and support the E7520 and the 945G/GZ/P/PL
The actual per-chipset support.

5/5: PCI MMConfig: Reserve resources but only when we're sure about them.
Add the resources in /proc/iomem when the chipset in known.


2006-12-07 18:29:43

by Olivier Galibert

[permalink] [raw]
Subject: [PATCH 2/5] PCI MMConfig: Only call unreachable_devices() when type 1 is available.

unreachable_devices compares between the results of pci configuration
accesses through type1 and mmconfig, so it should be called only if
type1 actually works in the first place.

Signed-off-by: Olivier Galibert <[email protected]>
---
arch/i386/pci/mmconfig-shared.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/i386/pci/mmconfig-shared.c
index b3ab210..7b19639 100644
--- a/arch/i386/pci/mmconfig-shared.c
+++ b/arch/i386/pci/mmconfig-shared.c
@@ -80,7 +80,8 @@ void __init pci_mmcfg_init(int type)
}

if (pci_mmcfg_arch_init()) {
- unreachable_devices();
+ if (type == 1)
+ unreachable_devices();
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
}
}
--
1.4.4.1.g278f

2006-12-07 18:30:15

by Olivier Galibert

[permalink] [raw]
Subject: [PATCH 3/5] PCI MMConfig: Only map what's necessary.

The x86-64 mmconfig code always map a range of MMCONFIG_APER_MAX
bytes, i.e. 256MB, whatever the number of accessible busses is. Fix
it, and add the end of the zone in the printk while we're at it.

Signed-off-by: Olivier Galibert <[email protected]>
---
arch/x86_64/pci/mmconfig.c | 12 +++++-------
1 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
index c71c181..3d13220 100644
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -13,10 +13,6 @@

#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)
-
/* Verify the first 16 busses. We assume that systems with more busses
get MCFG right. */
#define PCI_MMCFG_MAX_CHECK_BUS 16
@@ -143,17 +139,19 @@ int __init pci_mmcfg_arch_init(void)
}

for (i = 0; i < pci_mmcfg_config_num; ++i) {
+ u32 size = (pci_mmcfg_config[0].end_bus_number - pci_mmcfg_config[0].start_bus_number + 1) << 20;
pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address,
- MMCONFIG_APER_MAX);
+ size);
if (!pci_mmcfg_virt[i].virt) {
printk(KERN_ERR "PCI: Cannot map mmconfig aperture for "
"segment %d\n",
pci_mmcfg_config[i].pci_segment_group_number);
return 0;
}
- printk(KERN_INFO "PCI: Using MMCONFIG at %x\n",
- pci_mmcfg_config[i].base_address);
+ printk(KERN_INFO "PCI: Using MMCONFIG at %x-%x\n",
+ pci_mmcfg_config[i].base_address,
+ pci_mmcfg_config[i].base_address + size - 1);
}

raw_pci_ops = &pci_mmcfg;
--
1.4.4.1.g278f

2006-12-07 18:30:49

by Olivier Galibert

[permalink] [raw]
Subject: [PATCH 4/5] PCI MMConfig: Detect and support the E7520 and the 945G/GZ/P/PL

It seems that the only way to reliably support mmconfig in the
presence of funky biosen is to detect the hostbridge and read where
the window is mapped from its registers. Do that for the E7520 and
the 945G/GZ/P/PL for a start.

Signed-off-by: Olivier Galibert <[email protected]>
---
arch/i386/pci/mmconfig-shared.c | 116 ++++++++++++++++++++++++++++++++++++++-
1 files changed, 113 insertions(+), 3 deletions(-)

diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/i386/pci/mmconfig-shared.c
index 7b19639..302d495 100644
--- a/arch/i386/pci/mmconfig-shared.c
+++ b/arch/i386/pci/mmconfig-shared.c
@@ -3,6 +3,7 @@
* 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
@@ -55,12 +56,121 @@ static __init void unreachable_devices(void)
}
}

+static __init const char *pci_mmcfg_e7520(void)
+{
+ u32 win;
+ pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win);
+
+ pci_mmcfg_config_num = 1;
+ pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
+ pci_mmcfg_config[0].base_address = (win & 0xf000) << 16;
+ pci_mmcfg_config[0].pci_segment_group_number = 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 __init const char *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;
+
+ if (pci_mmcfg_config_num) {
+ pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
+ pci_mmcfg_config[0].base_address = pciexbar & mask;
+ pci_mmcfg_config[0].pci_segment_group_number = 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 __initdata struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] = {
+ { 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 < sizeof(pci_mmcfg_probes) / sizeof(pci_mmcfg_probes[0]); i++)
+ if ((pci_mmcfg_probes[i].vendor == PCI_ANY_ID || pci_mmcfg_probes[i].vendor == vendor) &&
+ (pci_mmcfg_probes[i].device == PCI_ANY_ID || pci_mmcfg_probes[i].device == device))
+ name = pci_mmcfg_probes[i].probe();
+
+ if (name) {
+ if (pci_mmcfg_config_num)
+ printk(KERN_INFO "PCI: Found %s with MMCONFIG support.\n", name);
+ else
+ printk(KERN_INFO "PCI: Found %s without MMCONFIG support.\n", name);
+ }
+
+ return name != NULL;
+}
+
void __init pci_mmcfg_init(int type)
{
+ int known_bridge = 0;
+
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
return;

- acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+ if (type == 1 && pci_mmcfg_check_hostbridge())
+ known_bridge = 1;
+
+ if (!known_bridge)
+ acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);

if ((pci_mmcfg_config_num == 0) ||
(pci_mmcfg_config == NULL) ||
@@ -68,8 +178,8 @@ void __init pci_mmcfg_init(int type)
return;

/* 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 &&
+ assume we run on a Mac and always use MCFG */
+ if (type == 1 && !known_bridge &&
!e820_all_mapped(pci_mmcfg_config[0].base_address,
pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
E820_RESERVED)) {
--
1.4.4.1.g278f

2006-12-07 18:29:16

by Olivier Galibert

[permalink] [raw]
Subject: [PATCH 1/5] PCI MMConfig: Share what's shareable.

i386 and x86-64 pci mmconfig code have a lot in common. So share
what's shareable between the two.

Signed-off-by: Olivier Galibert <[email protected]>
---
arch/i386/pci/Makefile | 2 +-
arch/i386/pci/mmconfig-shared.c | 86 +++++++++++++++++++++++++++++++++++++++
arch/i386/pci/mmconfig.c | 74 ++-------------------------------
arch/i386/pci/pci.h | 6 +++
arch/x86_64/pci/Makefile | 3 +-
arch/x86_64/pci/mmconfig.c | 71 +++++---------------------------
6 files changed, 109 insertions(+), 133 deletions(-)

diff --git a/arch/i386/pci/Makefile b/arch/i386/pci/Makefile
index 1594d2f..44650e0 100644
--- a/arch/i386/pci/Makefile
+++ b/arch/i386/pci/Makefile
@@ -1,7 +1,7 @@
obj-y := i386.o init.o

obj-$(CONFIG_PCI_BIOS) += pcbios.o
-obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o
+obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o mmconfig-shared.o
obj-$(CONFIG_PCI_DIRECT) += direct.o

pci-y := fixup.o
diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/i386/pci/mmconfig-shared.c
new file mode 100644
index 0000000..b3ab210
--- /dev/null
+++ b/arch/i386/pci/mmconfig-shared.c
@@ -0,0 +1,86 @@
+/*
+ * mmconfig-shared.c - Low-level direct PCI config space access via
+ * MMCONFIG - common code between i386 and x86-64.
+ *
+ * This code does:
+ * - 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)
+
+/* Verify the first 16 busses. We assume that systems with more busses
+ get MCFG right. */
+#define PCI_MMCFG_MAX_CHECK_BUS 16
+
+DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS);
+
+/* 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 __init void unreachable_devices(void)
+{
+ int i, k;
+ /* Use the max bus number from ACPI here? */
+ for (k = 0; k < PCI_MMCFG_MAX_CHECK_BUS; k++) {
+ for (i = 0; i < 32; i++) {
+ u32 val1, val2;
+
+ pci_conf1_read(0, k, PCI_DEVFN(i,0), 0, 4, &val1);
+ if (val1 == 0xffffffff)
+ continue;
+
+ raw_pci_ops->read(0, k, PCI_DEVFN(i, 0), 0, 4, &val2);
+ if (val1 != val2) {
+ set_bit(i + 32*k, pci_mmcfg_fallback_slots);
+ printk(KERN_NOTICE "PCI: No mmconfig possible"
+ " on device %02x:%02x\n", k, i);
+ }
+ }
+ }
+}
+
+void __init pci_mmcfg_init(int type)
+{
+ if ((pci_probe & PCI_PROBE_MMCONF) == 0)
+ return;
+
+ acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+
+ if ((pci_mmcfg_config_num == 0) ||
+ (pci_mmcfg_config == NULL) ||
+ (pci_mmcfg_config[0].base_address == 0))
+ return;
+
+ /* 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(pci_mmcfg_config[0].base_address,
+ pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
+ E820_RESERVED)) {
+ printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
+ pci_mmcfg_config[0].base_address);
+ printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
+ return;
+ }
+
+ if (pci_mmcfg_arch_init()) {
+ unreachable_devices();
+ pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
+ }
+}
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c
index c6b6d9b..507426f 100644
--- a/arch/i386/pci/mmconfig.c
+++ b/arch/i386/pci/mmconfig.c
@@ -15,20 +15,12 @@
#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)
-
/* Assume systems with more busses have correct MCFG */
-#define MAX_CHECK_BUS 16
-
#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 DECLARE_BITMAP(fallback_slots, MAX_CHECK_BUS*32);
-
/*
* Functions for accessing PCI configuration space with MMCONFIG accesses
*/
@@ -37,8 +29,8 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
int cfg_num = -1;
struct acpi_table_mcfg_config *cfg;

- if (seg == 0 && bus < MAX_CHECK_BUS &&
- test_bit(PCI_SLOT(devfn) + 32*bus, fallback_slots))
+ if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS &&
+ test_bit(PCI_SLOT(devfn) + 32*bus, pci_mmcfg_fallback_slots))
return 0;

while (1) {
@@ -154,67 +146,9 @@ static struct pci_raw_ops pci_mmcfg = {
.write = pci_mmcfg_write,
};

-/* 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 __init void unreachable_devices(void)
+int __init pci_mmcfg_arch_init(void)
{
- int i, k;
- unsigned long flags;
-
- for (k = 0; k < MAX_CHECK_BUS; k++) {
- for (i = 0; i < 32; i++) {
- u32 val1;
- u32 addr;
-
- pci_conf1_read(0, k, PCI_DEVFN(i, 0), 0, 4, &val1);
- if (val1 == 0xffffffff)
- continue;
-
- /* Locking probably not needed, but safer */
- spin_lock_irqsave(&pci_config_lock, flags);
- addr = get_base_addr(0, k, PCI_DEVFN(i, 0));
- if (addr != 0)
- pci_exp_set_dev_base(addr, k, PCI_DEVFN(i, 0));
- if (addr == 0 ||
- readl((u32 __iomem *)mmcfg_virt_addr) != val1) {
- set_bit(i + 32*k, fallback_slots);
- printk(KERN_NOTICE
- "PCI: No mmconfig possible on %x:%x\n", k, i);
- }
- spin_unlock_irqrestore(&pci_config_lock, flags);
- }
- }
-}
-
-void __init pci_mmcfg_init(int type)
-{
- if ((pci_probe & PCI_PROBE_MMCONF) == 0)
- return;
-
- acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
- if ((pci_mmcfg_config_num == 0) ||
- (pci_mmcfg_config == NULL) ||
- (pci_mmcfg_config[0].base_address == 0))
- return;
-
- /* 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(pci_mmcfg_config[0].base_address,
- pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
- E820_RESERVED)) {
- printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
- pci_mmcfg_config[0].base_address);
- printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
- return;
- }
-
printk(KERN_INFO "PCI: Using MMCONFIG\n");
raw_pci_ops = &pci_mmcfg;
- pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
-
- unreachable_devices();
+ return 1;
}
diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h
index a0a2518..0270c80 100644
--- a/arch/i386/pci/pci.h
+++ b/arch/i386/pci/pci.h
@@ -94,3 +94,9 @@ extern void pci_pcbios_init(void);
extern void pci_mmcfg_init(int type);
extern void pcibios_sort(void);

+/* pci-mmconfig.c */
+
+#define PCI_MMCFG_MAX_CHECK_BUS 16
+extern DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS);
+
+extern int pci_mmcfg_arch_init(void);
diff --git a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile
index 149aba0..c9eddc8 100644
--- a/arch/x86_64/pci/Makefile
+++ b/arch/x86_64/pci/Makefile
@@ -11,7 +11,7 @@ obj-y += fixup.o init.o
obj-$(CONFIG_ACPI) += acpi.o
obj-y += legacy.o irq.o common.o early.o
# mmconfig has a 64bit special
-obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o
+obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o direct.o mmconfig-shared.o

obj-$(CONFIG_NUMA) += k8-bus.o

@@ -24,3 +24,4 @@ fixup-y += ../../i386/pci/fixup.o
i386-y += ../../i386/pci/i386.o
init-y += ../../i386/pci/init.o
early-y += ../../i386/pci/early.o
+mmconfig-shared-y += ../../i386/pci/mmconfig-shared.o
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
index f8b6b28..c71c181 100644
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -19,9 +19,7 @@

/* Verify the first 16 busses. We assume that systems with more busses
get MCFG right. */
-#define MAX_CHECK_BUS 16
-
-static DECLARE_BITMAP(fallback_slots, 32*MAX_CHECK_BUS);
+#define PCI_MMCFG_MAX_CHECK_BUS 16

/* Static virtual mapping of the MMCONFIG aperture */
struct mmcfg_virt {
@@ -63,8 +61,8 @@ static char __iomem *get_virt(unsigned int seg, unsigned bus)
static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
{
char __iomem *addr;
- if (seg == 0 && bus < MAX_CHECK_BUS &&
- test_bit(32*bus + PCI_SLOT(devfn), fallback_slots))
+ if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS &&
+ test_bit(32*bus + PCI_SLOT(devfn), pci_mmcfg_fallback_slots))
return NULL;
addr = get_virt(seg, bus);
if (!addr)
@@ -135,63 +133,15 @@ static struct pci_raw_ops pci_mmcfg = {
.write = pci_mmcfg_write,
};

-/* 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 __init void unreachable_devices(void)
-{
- int i, k;
- /* Use the max bus number from ACPI here? */
- for (k = 0; k < MAX_CHECK_BUS; k++) {
- for (i = 0; i < 32; i++) {
- u32 val1;
- char __iomem *addr;
-
- pci_conf1_read(0, k, PCI_DEVFN(i,0), 0, 4, &val1);
- if (val1 == 0xffffffff)
- continue;
- addr = pci_dev_base(0, k, PCI_DEVFN(i, 0));
- if (addr == NULL|| readl(addr) != val1) {
- set_bit(i + 32*k, fallback_slots);
- printk(KERN_NOTICE "PCI: No mmconfig possible"
- " on device %02x:%02x\n", k, i);
- }
- }
- }
-}
-
-void __init pci_mmcfg_init(int type)
+int __init pci_mmcfg_arch_init(void)
{
int i;
-
- if ((pci_probe & PCI_PROBE_MMCONF) == 0)
- return;
-
- acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
- if ((pci_mmcfg_config_num == 0) ||
- (pci_mmcfg_config == NULL) ||
- (pci_mmcfg_config[0].base_address == 0))
- return;
-
- /* 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(pci_mmcfg_config[0].base_address,
- pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
- E820_RESERVED)) {
- printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
- pci_mmcfg_config[0].base_address);
- printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
- return;
- }
-
pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL);
if (pci_mmcfg_virt == NULL) {
printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n");
- return;
+ return 0;
}
+
for (i = 0; i < pci_mmcfg_config_num; ++i) {
pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address,
@@ -200,13 +150,12 @@ void __init pci_mmcfg_init(int type)
printk(KERN_ERR "PCI: Cannot map mmconfig aperture for "
"segment %d\n",
pci_mmcfg_config[i].pci_segment_group_number);
- return;
+ return 0;
}
- printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
+ printk(KERN_INFO "PCI: Using MMCONFIG at %x\n",
+ pci_mmcfg_config[i].base_address);
}

- unreachable_devices();
-
raw_pci_ops = &pci_mmcfg;
- pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
+ return 1;
}
--
1.4.4.1.g278f

2006-12-07 18:31:14

by Olivier Galibert

[permalink] [raw]
Subject: [PATCH 5/5] PCI MMConfig: Reserve resources but only when we're sure about them.

Put back the resource reservation as per
4c6e052adfe285ede5884e4e8c4d33af33932c13 but use it *only* when the
range(s) come from a chipset probe instead of the bios.

Signed-off-by: Olivier Galibert <[email protected]>
---
arch/i386/pci/mmconfig-shared.c | 33 +++++++++++++++++++++++++++++++++
1 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/i386/pci/mmconfig-shared.c
index 302d495..0da1e3b 100644
--- a/arch/i386/pci/mmconfig-shared.c
+++ b/arch/i386/pci/mmconfig-shared.c
@@ -159,6 +159,37 @@ static int __init pci_mmcfg_check_hostbridge(void)
return name != NULL;
}

+static __init void pci_mmcfg_insert_resources(void)
+{
+#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++) {
+ num_buses = pci_mmcfg_config[i].end_bus_number -
+ pci_mmcfg_config[i].start_bus_number + 1;
+ res->name = names;
+ snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u",
+ pci_mmcfg_config[i].pci_segment_group_number);
+ res->start = pci_mmcfg_config[i].base_address;
+ res->end = res->start + (num_buses << 20) - 1;
+ res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ insert_resource(&iomem_resource, res);
+ names += PCI_MMCFG_RESOURCE_NAME_LEN;
+ }
+}
+
void __init pci_mmcfg_init(int type)
{
int known_bridge = 0;
@@ -192,6 +223,8 @@ void __init pci_mmcfg_init(int type)
if (pci_mmcfg_arch_init()) {
if (type == 1)
unreachable_devices();
+ if (known_bridge)
+ pci_mmcfg_insert_resources();
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
}
}
--
1.4.4.1.g278f