2006-11-23 19:51:48

by Olivier Galibert

[permalink] [raw]
Subject: [PATCH] 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 on x86-64 for a start.

The detection and support should eventually be shared with i386 since
you can run a 32bits kernel on a 64bits chip.

Signed-off-by: Olivier Galibert <[email protected]>

---
arch/x86_64/pci/mmconfig.c | 123 ++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 117 insertions(+), 6 deletions(-)


Supersedes the previous patch on the same subject. Found a dell
desktop box with a 945G in it so I added the support.

It should probably be a good idea to resurrect the resource
registration code but to use it only in the known_bridge case.

It's easy to generalize to multiple segments if someone can test it.
I suspect the multi-segment architectures don't use a E7520 or a 945G
as a chipset so this patch shouldn't change anything for them.

Eventually that should be shared with i386 for 32bits kernels on
64bits cpus.


diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
index f8b6b28..c74c967 100644
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -163,14 +163,123 @@ static __init void unreachable_devices(v
}
}

+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 i;
+ 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) ||
(pci_mmcfg_config[0].base_address == 0))
@@ -178,9 +287,10 @@ 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 && !e820_all_mapped(pci_mmcfg_config[0].base_address,
- pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
- E820_RESERVED)) {
+ 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)) {
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");
@@ -193,16 +303,17 @@ void __init pci_mmcfg_init(int type)
return;
}
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;
}
- 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);
}

unreachable_devices();
--
1.4.2.GIT


2006-11-23 19:57:49

by Arjan van de Ven

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

On Thu, 2006-11-23 at 20:51 +0100, Olivier Galibert wrote:
> 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 on x86-64 for a start.


hi,

while I like this approach a lot, I am wondering if this shouldn't be
done as a PCI quirk instead.... it would make a lot of sense to use that
shared infrastructure for this...


2006-11-23 20:40:36

by Matthew Wilcox

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

On Thu, Nov 23, 2006 at 08:57:41PM +0100, Arjan van de Ven wrote:
> On Thu, 2006-11-23 at 20:51 +0100, Olivier Galibert wrote:
> > 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 on x86-64 for a start.
>
> while I like this approach a lot, I am wondering if this shouldn't be
> done as a PCI quirk instead.... it would make a lot of sense to use that
> shared infrastructure for this...

Except the shared infrastructure kind of relies on having the pci
accesses already working ... unless we want the kernel to print messages
like:

PCI: Using type 1 config access method
...
PCI: Whoops, looks like we're going to use MMCONFIG after all. Ignore that

2006-11-23 20:44:40

by Olivier Galibert

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

On Thu, Nov 23, 2006 at 08:57:41PM +0100, Arjan van de Ven wrote:
> On Thu, 2006-11-23 at 20:51 +0100, Olivier Galibert wrote:
> > 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 on x86-64 for a start.
>
>
> hi,
>
> while I like this approach a lot, I am wondering if this shouldn't be
> done as a PCI quirk instead.... it would make a lot of sense to use that
> shared infrastructure for this...

I agree in principle, but aren't the quirks running way too late
compared to that?

OG.

2006-11-25 19:34:46

by Andi Kleen

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

On Thursday 23 November 2006 20:51, Olivier Galibert wrote:

> The detection and support should eventually be shared with i386 since
> you can run a 32bits kernel on a 64bits chip.

Exactly. So please define a mmconfig-shared.c first

-Andi

2006-11-25 20:51:54

by Olivier Galibert

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

On Sat, Nov 25, 2006 at 08:34:34PM +0100, Andi Kleen wrote:
> On Thursday 23 November 2006 20:51, Olivier Galibert wrote:
>
> > The detection and support should eventually be shared with i386 since
> > you can run a 32bits kernel on a 64bits chip.
>
> Exactly. So please define a mmconfig-shared.c first

Ok. On which side (i386 or x86-64) and is there a standard way to
include the object file on the other side?

OG.

2006-11-25 21:00:05

by Andi Kleen

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

On Saturday 25 November 2006 21:51, Olivier Galibert wrote:
> On Sat, Nov 25, 2006 at 08:34:34PM +0100, Andi Kleen wrote:
> > On Thursday 23 November 2006 20:51, Olivier Galibert wrote:
> >
> > > The detection and support should eventually be shared with i386 since
> > > you can run a 32bits kernel on a 64bits chip.
> >
> > Exactly. So please define a mmconfig-shared.c first
>
> Ok. On which side (i386 or x86-64)

What you prefer. And please move the already existing shared code in there
too.

> and is there a standard way to
> include the object file on the other side?

See arch/x86_64/kernel/Makefile for a few examples

-Andi

2006-11-26 13:15:38

by Olivier Galibert

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

Ok, here you go, what about that? I'll be able to test it on i386 on
monday, not before. It's hard to doa full 32bits install remotely :-)

OG.

>From 9703313602daaac65e41210444b2ce20b6e340b6 Mon Sep 17 00:00:00 2001
From: Olivier Galibert <[email protected]>
Date: Sun, 26 Nov 2006 14:10:09 +0100
Subject: [PATCH] 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.
---
arch/i386/pci/Makefile | 2
arch/i386/pci/mmconfig-shared.c | 199 +++++++++++++++++++++++++++++++++++++++
arch/i386/pci/mmconfig.c | 71 +-------------
arch/x86_64/pci/Makefile | 3 -
arch/x86_64/pci/mmconfig.c | 73 ++------------
5 files changed, 216 insertions(+), 132 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..4906741
--- /dev/null
+++ b/arch/i386/pci/mmconfig-shared.c
@@ -0,0 +1,199 @@
+/*
+ * mmconfig-shared.c - Low-level direct PCI config space access via
+ * 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
+ * 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 MAX_CHECK_BUS 16
+
+DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*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 < 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);
+ }
+ }
+ }
+}
+
+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;
+
+ 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) ||
+ (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 && !known_bridge &&
+ !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()) {
+ if (type == 1)
+ 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..9fac232 100644
--- a/arch/i386/pci/mmconfig.c
+++ b/arch/i386/pci/mmconfig.c
@@ -15,10 +15,6 @@ #include <linux/acpi.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)
-
/* Assume systems with more busses have correct MCFG */
#define MAX_CHECK_BUS 16

@@ -27,7 +23,7 @@ #define mmcfg_virt_addr ((void __iomem *
/* The base address of the last MMCONFIG device accessed */
static u32 mmcfg_last_accessed_device;

-static DECLARE_BITMAP(fallback_slots, MAX_CHECK_BUS*32);
+extern DECLARE_BITMAP(pci_mmcfg_fallback_slots, MAX_CHECK_BUS*32);

/*
* Functions for accessing PCI configuration space with MMCONFIG accesses
@@ -38,7 +34,7 @@ static u32 get_base_addr(unsigned int se
struct acpi_table_mcfg_config *cfg;

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

while (1) {
@@ -154,67 +150,8 @@ 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/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..091f759 100644
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -13,15 +13,11 @@ #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 MAX_CHECK_BUS 16

-static DECLARE_BITMAP(fallback_slots, 32*MAX_CHECK_BUS);
+extern DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*MAX_CHECK_BUS);

/* Static virtual mapping of the MMCONFIG aperture */
struct mmcfg_virt {
@@ -64,7 +60,7 @@ static char __iomem *pci_dev_base(unsign
{
char __iomem *addr;
if (seg == 0 && bus < MAX_CHECK_BUS &&
- test_bit(32*bus + PCI_SLOT(devfn), fallback_slots))
+ test_bit(32*bus + PCI_SLOT(devfn), pci_mmcfg_fallback_slots))
return NULL;
addr = get_virt(seg, bus);
if (!addr)
@@ -135,78 +131,29 @@ 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) {
+ 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;
+ 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);
}

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


2006-11-26 19:28:42

by Andi Kleen

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

On Sunday 26 November 2006 14:15, Olivier Galibert wrote:
> Ok, here you go, what about that? I'll be able to test it on i386 on
> monday, not before. It's hard to doa full 32bits install remotely :-)

Sorry, please don't put it all into a single patch. Do one patch
that just moves code, then add new functionality later.
Otherwise nobody can review it properly.

-Andi

2006-11-27 19:03:10

by Olivier Galibert

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

On Sun, Nov 26, 2006 at 08:28:04PM +0100, Andi Kleen wrote:
> On Sunday 26 November 2006 14:15, Olivier Galibert wrote:
> > Ok, here you go, what about that? I'll be able to test it on i386 on
> > monday, not before. It's hard to doa full 32bits install remotely :-)
>
> Sorry, please don't put it all into a single patch. Do one patch
> that just moves code, then add new functionality later.
> Otherwise nobody can review it properly.

Ok, I have it split in 5 parts, but the testing on i386 failed simply
because the vanilla code there just does not work. Symptom is the
SATA driver not seeing the disk somehow.

With a 64bits kernel:

ata_piix 0000:00:1f.2: version 2.00ac6
ata_piix 0000:00:1f.2: MAP [ P0 P2 P1 P3 ]
ACPI: PCI Interrupt 0000:00:1f.2[C] -> GSI 20 (level, low) -> IRQ 20
PCI: Setting latency timer of device 0000:00:1f.2 to 64
ata1: SATA max UDMA/133 cmd 0xFE00 ctl 0xFE12 bmdma 0xFEA0 irq 20
ata2: SATA max UDMA/133 cmd 0xFE20 ctl 0xFE32 bmdma 0xFEA8 irq 20
scsi0 : ata_piix
ata1.00: ATA-7, max UDMA/133, 156250000 sectors: LBA48 NCQ (depth 0/32)
ata1.00: ata1: dev 0 multi count 8
ata1.00: configured for UDMA/133
scsi1 : ata_piix
ata2: port is slow to respond, please be patient (Status 0xff)
ata2: port failed to respond (30 secs, Status 0xff)
ata2: SRST failed (status 0xFF)
ata2: SRST failed (err_mask=0x100)
ata2: softreset failed, retrying in 5 secs
ata2: SRST failed (status 0xFF)
ata2: SRST failed (err_mask=0x100)
ata2: softreset failed, retrying in 5 secs
ata2: SRST failed (status 0xFF)
ata2: SRST failed (err_mask=0x100)
ata2: reset failed, giving up
scsi 0:0:0:0: Direct-Access ATA Maxtor 6V080E0 VA13 PQ: 0 ANSI: 5
SCSI device sda: 156250000 512-byte hdwr sectors (80000 MB)
sda: Write Protect is off
sda: Mode Sense: 00 3a 00 00
SCSI device sda: drive cache: write back
SCSI device sda: 156250000 512-byte hdwr sectors (80000 MB)
sda: Write Protect is off
sda: Mode Sense: 00 3a 00 00
SCSI device sda: drive cache: write back
sda: sda1 sda2 sda3 sda4
sd 0:0:0:0: Attached scsi disk sda
sd 0:0:0:0: Attached scsi generic sg0 type 0



With a 32bits, pci=nommconf kernel:

ata_piix 0000:00:1f.2: MAP [ P0 P2 P1 P3 ]
ACPI: PCI Interrupt 0000:00:1f.2[C] -> GSI 20 (level, low) -> IRQ 18
ata1: SATA max UDMA/133 cmd 0xFE00 ctl 0xFE12 bmdma 0xFEA0 irq 18
ata2: SATA max UDMA/133 cmd 0xFE20 ctl 0xFE32 bmdma 0xFEA8 irq 18
scsi0 : ata_piix
ata1.00: ATA-7, max UDMA/133, 156250000 sectors: LBA48 NCQ (depth 0/32)
ata1.00: ata1: dev 0 multi count 8
ata1.00: configured for UDMA/133
scsi1 : ata_piix
ata2: port is slow to respond, please be patient (Status 0xff)
ata2: port failed to respond (30 secs, Status 0xff)
ata2: SRST failed (status 0xFF)
ata2: SRST failed (err_mask=0x100)
ata2: softreset failed, retrying in 5 secs
ata2: SRST failed (status 0xFF)
ata2: SRST failed (err_mask=0x100)
ata2: softreset failed, retrying in 5 secs
ata2: SRST failed (status 0xFF)
ata2: SRST failed (err_mask=0x100)
ata2: reset failed, giving up
scsi 0:0:0:0: Direct-Access ATA Maxtor 6V080E0 VA13 PQ: 0 ANSI: 5
SCSI device sda: 156250000 512-byte hdwr sectors (80000 MB)
sda: Write Protect is off
sda: Mode Sense: 00 3a 00 00
SCSI device sda: drive cache: write back
SCSI device sda: 156250000 512-byte hdwr sectors (80000 MB)
sda: Write Protect is off
sda: Mode Sense: 00 3a 00 00
SCSI device sda: drive cache: write back
sda: sda1 sda2 sda3 sda4
sd 0:0:0:0: Attached scsi disk sda
sd 0:0:0:0: Attached scsi generic sg0 type 0



With a 5d48545e5e88ab7a27ba6a5cb1e8fff617754b61 kernel in 32 bits and
no pci= parameter:

ata_piix 0000:00:1f.2: MAP [ P0 P2 P1 P3 ]
ACPI: PCI Interrupt 0000:00:1f.2[C] -> GSI 20 (level, low) -> IRQ 18
PCI: Setting latency timer of device 0000:00:1f.2 to 64
ata1: SATA max UDMA/133 cmd 0xFE00 ctl 0xFE12 bmdma 0xFEA0 irq 18
ata2: SATA max UDMA/133 cmd 0xFE20 ctl 0xFE32 bmdma 0xFEA8 irq 18
scsi0 : ata_piix
scsi1 : ata_piix
ata2: port is slow to respond, please be patient (Status 0xff)
ata2: port failed to respond (30 secs, Status 0xff)
ata2: SRST failed (status 0xFF)
ata2: SRST failed (err_mask=0x100)
ata2: softreset failed, retrying in 5 secs
ata2: SRST failed (status 0xFF)
ata2: SRST failed (err_mask=0x100)
ata2: softreset failed, retrying in 5 secs
ata2: SRST failed (status 0xFF)
ata2: SRST failed (err_mask=0x100)
ata2: reset failed, giving up


00:00.0 Host bridge: Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub (rev 02)
00:01.0 PCI bridge: Intel Corporation 945G/GZ/P/PL Express PCI Express Root Port (rev 02)
00:1c.0 PCI bridge: Intel Corporation 82801G (ICH7 Family) PCI Express Port 1 (rev 01)
00:1c.1 PCI bridge: Intel Corporation 82801G (ICH7 Family) PCI Express Port 2 (rev 01)
00:1d.0 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI #1 (rev 01)
00:1d.1 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI #2 (rev 01)
00:1d.2 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI #3 (rev 01)
00:1d.3 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI #4 (rev 01)
00:1d.7 USB Controller: Intel Corporation 82801G (ICH7 Family) USB2 EHCI Controller (rev 01)
00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev e1)
00:1e.2 Multimedia audio controller: Intel Corporation 82801G (ICH7 Family) AC'97 Audio Controller (rev 01)
00:1f.0 ISA bridge: Intel Corporation 82801GB/GR (ICH7 Family) LPC Interface Bridge (rev 01)
00:1f.1 IDE interface: Intel Corporation 82801G (ICH7 Family) IDE Controller (rev 01)
00:1f.2 IDE interface: Intel Corporation 82801GB/GR/GH (ICH7 Family) Serial ATA Storage Controller IDE (rev 01)
00:1f.3 SMBus: Intel Corporation 82801G (ICH7 Family) SMBus Controller (rev 01)
01:00.0 VGA compatible controller: ATI Technologies Inc RV380 [Radeon X600 (PCIE)]
01:00.1 Display controller: ATI Technologies Inc RV380 [Radeon X600]
02:00.0 Ethernet controller: Broadcom Corporation NetXtreme BCM5751 Gigabit Ethernet PCI Express (rev 01)


So, do you want the untested-on-i386-because-I-can't version?

OG.

2006-11-27 19:07:55

by Andi Kleen

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

On Mon, Nov 27, 2006 at 08:03:01PM +0100, Olivier Galibert wrote:
> On Sun, Nov 26, 2006 at 08:28:04PM +0100, Andi Kleen wrote:
> > On Sunday 26 November 2006 14:15, Olivier Galibert wrote:
> > > Ok, here you go, what about that? I'll be able to test it on i386 on
> > > monday, not before. It's hard to doa full 32bits install remotely :-)
> >
> > Sorry, please don't put it all into a single patch. Do one patch
> > that just moves code, then add new functionality later.
> > Otherwise nobody can review it properly.
>
> Ok, I have it split in 5 parts, but the testing on i386 failed simply
> because the vanilla code there just does not work. Symptom is the
> SATA driver not seeing the disk somehow.

Weird. That shouldn't happen.

Is that with just the code movement patch or your feature patch
added too? If the later can you test it with only code movement
(and compare against vanilla kernel). at least code movement
only should behave exactly the same as unpatched kernel.

-Andi

2006-11-27 20:24:12

by Olivier Galibert

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

On Mon, Nov 27, 2006 at 08:07:48PM +0100, Andi Kleen wrote:
> Is that with just the code movement patch or your feature patch
> added too? If the later can you test it with only code movement
> (and compare against vanilla kernel). at least code movement
> only should behave exactly the same as unpatched kernel.

You misread. Unpatched kernel does not work. That's why I gave the
git reference of the kernel too. Patched kernel does not work either,
unsurprisingly (bios gives correct tables on that box).

OG.

2006-12-01 00:19:08

by Olivier Galibert

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

On Mon, Nov 27, 2006 at 09:24:06PM +0100, Olivier Galibert wrote:
> On Mon, Nov 27, 2006 at 08:07:48PM +0100, Andi Kleen wrote:
> > Is that with just the code movement patch or your feature patch
> > added too? If the later can you test it with only code movement
> > (and compare against vanilla kernel). at least code movement
> > only should behave exactly the same as unpatched kernel.
>
> You misread. Unpatched kernel does not work. That's why I gave the
> git reference of the kernel too. Patched kernel does not work either,
> unsurprisingly (bios gives correct tables on that box).

Ok, I'm trying to debug it, and it's a pain. It's a timing issue,
mmcfg write accesses are too slow for something. The get_base_addr()
call is enough to slow things down too much, which explains why the
fundamentally simpler x86-64 code works without a hitch.

Finding out what it is too slow for, though, is an interesting
proposition. It's not entirely obvious it is actually related to the
sata accesses.

OG.