diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/i386/pci/mmconfig-shared.c index 779c987acc5b..d72f0439147c 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,128 @@ 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); + if (!pci_mmcfg_config) + return NULL; + pci_mmcfg_config[0].address = (win & 0xf000) << 16; + pci_mmcfg_config[0].pci_segment = 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); + if (!pci_mmcfg_config) + return NULL; + pci_mmcfg_config[0].address = pciexbar & mask; + pci_mmcfg_config[0].pci_segment = 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 < ARRAY_SIZE(pci_mmcfg_probes); 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_SIG_MCFG, acpi_parse_mcfg); + if (type == 1 && pci_mmcfg_check_hostbridge()) + known_bridge = 1; + + if (!known_bridge) + acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); if ((pci_mmcfg_config_num == 0) || (pci_mmcfg_config == NULL) || @@ -69,7 +186,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].address, pci_mmcfg_config[0].address + MMCONFIG_APER_MIN, E820_RESERVED)) {