diff options
author | Andi Kleen <ak@suse.de> | 2005-12-12 22:17:11 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-12-12 22:31:16 -0800 |
commit | d6ece5491ae71ded1237f59def88bcd1b19b6f60 (patch) | |
tree | 3128cb506d050a4007d2724939af15e512d7c5b4 /arch/x86_64 | |
parent | 928cf8c62763349efc550a12f6518e52c3390906 (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')
-rw-r--r-- | arch/x86_64/pci/mmconfig.c | 36 |
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; |