summaryrefslogtreecommitdiff
path: root/arch/x86_64/pci
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2005-12-12 22:17:11 -0800
committerLinus Torvalds <torvalds@g5.osdl.org>2005-12-12 22:31:16 -0800
commitd6ece5491ae71ded1237f59def88bcd1b19b6f60 (patch)
tree3128cb506d050a4007d2724939af15e512d7c5b4 /arch/x86_64/pci
parent928cf8c62763349efc550a12f6518e52c3390906 (diff)
[PATCH] i386/x86-64 Correct for broken MCFG tables on K8 systems
They report all busses as MMCONFIG capable, but it never works for the internal devices in the CPU's builtin northbridge. It just probes all func 0 devices on bus 0 (the internal northbridge is currently always on bus 0) and if they are not accessible using MCFG they are put into a special fallback bitmap. On systems where it isn't we assume the BIOS vendor supplied correct MCFG. Requires the earlier patch for mmconfig type1 fallback Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/x86_64/pci')
-rw-r--r--arch/x86_64/pci/mmconfig.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
index 22ff1b07d4e..9c4f907e301 100644
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -8,10 +8,13 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/acpi.h>
+#include <linux/bitmap.h>
#include "pci.h"
#define MMCONFIG_APER_SIZE (256*1024*1024)
+static DECLARE_BITMAP(fallback_slots, 32);
+
/* Static virtual mapping of the MMCONFIG aperture */
struct mmcfg_virt {
struct acpi_table_mcfg_config *cfg;
@@ -40,9 +43,12 @@ static char *get_virt(unsigned int seg, unsigned bus)
}
}
-static inline char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
+static char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
{
- char *addr = get_virt(seg, bus);
+ char *addr;
+ if (seg == 0 && bus == 0 && test_bit(PCI_SLOT(devfn), &fallback_slots))
+ return NULL;
+ addr = get_virt(seg, bus);
if (!addr)
return NULL;
return addr + ((bus << 20) | (devfn << 12));
@@ -109,6 +115,30 @@ 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.
+ We only do this for bus 0/seg 0 */
+static __init void unreachable_devices(void)
+{
+ int i;
+ for (i = 0; i < 32; i++) {
+ u32 val1;
+ char *addr;
+
+ pci_conf1_read(0, 0, PCI_DEVFN(i,0), 0, 4, &val1);
+ if (val1 == 0xffffffff)
+ continue;
+ addr = pci_dev_base(0, 0, PCI_DEVFN(i, 0));
+ if (addr == NULL|| readl(addr) != val1) {
+ set_bit(i, &fallback_slots);
+ }
+ }
+}
+
static int __init pci_mmcfg_init(void)
{
int i;
@@ -139,6 +169,8 @@ static int __init pci_mmcfg_init(void)
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;