2006-12-07 14:36:10

by Olivier Galibert

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

Done in 5 steps, at Andi's very reasonable request:

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.

OG.


2006-12-07 14:50:27

by Olivier Galibert

[permalink] [raw]
Subject: [PATCH] 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 4ca3f5a..7a8a498 100644
--- a/arch/i386/pci/mmconfig-shared.c
+++ b/arch/i386/pci/mmconfig-shared.c
@@ -82,7 +82,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 14:50:54

by Olivier Galibert

[permalink] [raw]
Subject: [PATCH] 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 | 9 +++------
1 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
index b270f20..091f759 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 MAX_CHECK_BUS 16
@@ -145,16 +141,17 @@ 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 14:51:22

by Olivier Galibert

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

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 | 114 ++++++++++++++++++++++++++++++++++++++-
1 files changed, 112 insertions(+), 2 deletions(-)

diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/i386/pci/mmconfig-shared.c
index 7a8a498..4906741 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,14 +56,123 @@ 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)
{
extern int pci_mmcfg_arch_init(void);

+ 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) ||
@@ -71,7 +181,7 @@ void __init pci_mmcfg_init(int type)

/* 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 &&
+ 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 14:51:55

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 4906741..7599b89 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)
{
extern int pci_mmcfg_arch_init(void);
@@ -194,6 +225,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

2006-12-07 15:02:01

by Muli Ben-Yehuda

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

On Thu, Dec 07, 2006 at 03:50:52PM +0100, Olivier Galibert wrote:
> 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 | 9 +++------
> 1 files changed, 3 insertions(+), 6 deletions(-)
>
> diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
> index b270f20..091f759 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 MAX_CHECK_BUS 16
> @@ -145,16 +141,17 @@ 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);

80 chars per line please...

Cheers,
Muli