mmconfig-shared.c revision a83fe32fa668c0a17b3f99a1480b006f7d649924
1b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert/*
2b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert * mmconfig-shared.c - Low-level direct PCI config space access via
3b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert *                     MMCONFIG - common code between i386 and x86-64.
4b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert *
5b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert * This code does:
69358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert * - known chipset handling
7b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert * - ACPI decoding and validation
8b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert *
9b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert * Per-architecture code takes care of the mappings and accesses
10b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert * themselves.
11b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert */
12b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert
13b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert#include <linux/pci.h>
14b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert#include <linux/init.h>
15b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert#include <linux/acpi.h>
16b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert#include <linux/bitmap.h>
17b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert#include <asm/e820.h>
18b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert
19b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert#include "pci.h"
20b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert
21b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert/* aperture is up to 256MB but BIOS may reserve less */
22b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert#define MMCONFIG_APER_MIN	(2 * 1024*1024)
23b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert#define MMCONFIG_APER_MAX	(256 * 1024*1024)
24b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert
25a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin/* Indicate if the mmcfg resources have been placed into the resource table. */
26a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbinstatic int __initdata pci_mmcfg_resources_inserted;
27a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin
28429d512e532ec9c969aa6f66ddbc542f3a5fe4daOGAWA Hirofumistatic const char __init *pci_mmcfg_e7520(void)
299358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert{
309358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	u32 win;
31bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu	raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0xce, 2, &win);
329358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
33b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert	win = win & 0xf000;
34b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert	if(win == 0x0000 || win == 0xf000)
35b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert		pci_mmcfg_config_num = 0;
36b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert	else {
37b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert		pci_mmcfg_config_num = 1;
38b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert		pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
39b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert		if (!pci_mmcfg_config)
40b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert			return NULL;
41b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert		pci_mmcfg_config[0].address = win << 16;
42b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert		pci_mmcfg_config[0].pci_segment = 0;
43b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert		pci_mmcfg_config[0].start_bus_number = 0;
44b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert		pci_mmcfg_config[0].end_bus_number = 255;
45b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert	}
469358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
479358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	return "Intel Corporation E7520 Memory Controller Hub";
489358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert}
499358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
50429d512e532ec9c969aa6f66ddbc542f3a5fe4daOGAWA Hirofumistatic const char __init *pci_mmcfg_intel_945(void)
519358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert{
529358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	u32 pciexbar, mask = 0, len = 0;
539358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
549358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	pci_mmcfg_config_num = 1;
559358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
56bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu	raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0x48, 4, &pciexbar);
579358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
589358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	/* Enable bit */
599358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	if (!(pciexbar & 1))
609358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		pci_mmcfg_config_num = 0;
619358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
629358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	/* Size bits */
639358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	switch ((pciexbar >> 1) & 3) {
649358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	case 0:
659358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		mask = 0xf0000000U;
669358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		len  = 0x10000000U;
679358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		break;
689358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	case 1:
699358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		mask = 0xf8000000U;
709358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		len  = 0x08000000U;
719358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		break;
729358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	case 2:
739358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		mask = 0xfc000000U;
749358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		len  = 0x04000000U;
759358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		break;
769358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	default:
779358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		pci_mmcfg_config_num = 0;
789358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	}
799358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
809358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	/* Errata #2, things break when not aligned on a 256Mb boundary */
819358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	/* Can only happen in 64M/128M mode */
829358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
839358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	if ((pciexbar & mask) & 0x0fffffffU)
849358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		pci_mmcfg_config_num = 0;
859358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
86b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert	/* Don't hit the APIC registers and their friends */
87b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert	if ((pciexbar & mask) >= 0xf0000000U)
88b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert		pci_mmcfg_config_num = 0;
89b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert
909358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	if (pci_mmcfg_config_num) {
919358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
929358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		if (!pci_mmcfg_config)
939358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert			return NULL;
949358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		pci_mmcfg_config[0].address = pciexbar & mask;
959358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		pci_mmcfg_config[0].pci_segment = 0;
969358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		pci_mmcfg_config[0].start_bus_number = 0;
979358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert		pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
989358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	}
999358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
1009358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
1019358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert}
1029358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
1037fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lustatic const char __init *pci_mmcfg_amd_fam10h(void)
1047fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu{
1057fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	u32 low, high, address;
1067fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	u64 base, msr;
1077fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	int i;
1087fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	unsigned segnbits = 0, busnbits;
1097fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu
1105f0b2976cb2b62668a076f54419c24b8ab677167Yinghai Lu	if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF))
1115f0b2976cb2b62668a076f54419c24b8ab677167Yinghai Lu		return NULL;
1125f0b2976cb2b62668a076f54419c24b8ab677167Yinghai Lu
1137fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	address = MSR_FAM10H_MMIO_CONF_BASE;
1147fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	if (rdmsr_safe(address, &low, &high))
1157fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu		return NULL;
1167fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu
1177fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	msr = high;
1187fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	msr <<= 32;
1197fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	msr |= low;
1207fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu
1217fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	/* mmconfig is not enable */
1227fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	if (!(msr & FAM10H_MMIO_CONF_ENABLE))
1237fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu		return NULL;
1247fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu
1257fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
1267fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu
1277fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	busnbits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
1287fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu			 FAM10H_MMIO_CONF_BUSRANGE_MASK;
1297fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu
1307fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	/*
1317fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	 * only handle bus 0 ?
1327fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	 * need to skip it
1337fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	 */
1347fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	if (!busnbits)
1357fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu		return NULL;
1367fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu
1377fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	if (busnbits > 8) {
1387fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu		segnbits = busnbits - 8;
1397fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu		busnbits = 8;
1407fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	}
1417fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu
1427fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	pci_mmcfg_config_num = (1 << segnbits);
1437fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]) *
1447fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu				   pci_mmcfg_config_num, GFP_KERNEL);
1457fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	if (!pci_mmcfg_config)
1467fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu		return NULL;
1477fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu
1487fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	for (i = 0; i < (1 << segnbits); i++) {
1497fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu		pci_mmcfg_config[i].address = base + (1<<28) * i;
1507fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu		pci_mmcfg_config[i].pci_segment = i;
1517fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu		pci_mmcfg_config[i].start_bus_number = 0;
1527fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu		pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1;
1537fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	}
1547fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu
1557fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	return "AMD Family 10h NB";
1567fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu}
1577fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu
1589358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibertstruct pci_mmcfg_hostbridge_probe {
1597fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	u32 bus;
1607fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	u32 devfn;
1619358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	u32 vendor;
1629358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	u32 device;
1639358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	const char *(*probe)(void);
1649358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert};
1659358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
166429d512e532ec9c969aa6f66ddbc542f3a5fe4daOGAWA Hirofumistatic struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
1677fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	{ 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
1687fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	  PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
1697fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	{ 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
1707fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	  PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
1717fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	{ 0, PCI_DEVFN(0x18, 0), PCI_VENDOR_ID_AMD,
1727fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	  0x1200, pci_mmcfg_amd_fam10h },
1737fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	{ 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD,
1747fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	  0x1200, pci_mmcfg_amd_fam10h },
1759358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert};
1769358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
1779358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibertstatic int __init pci_mmcfg_check_hostbridge(void)
1789358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert{
1799358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	u32 l;
1807fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu	u32 bus, devfn;
1819358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	u16 vendor, device;
1829358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	int i;
1839358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	const char *name;
1849358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
185bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu	if (!raw_pci_ops)
186bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu		return 0;
187bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu
1889358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	pci_mmcfg_config_num = 0;
1899358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	pci_mmcfg_config = NULL;
1909358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	name = NULL;
1919358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
192429d512e532ec9c969aa6f66ddbc542f3a5fe4daOGAWA Hirofumi	for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
1937fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu		bus =  pci_mmcfg_probes[i].bus;
1947fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu		devfn = pci_mmcfg_probes[i].devfn;
195bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu		raw_pci_ops->read(0, bus, devfn, 0, 4, &l);
1967fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu		vendor = l & 0xffff;
1977fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu		device = (l >> 16) & 0xffff;
1987fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu
199429d512e532ec9c969aa6f66ddbc542f3a5fe4daOGAWA Hirofumi		if (pci_mmcfg_probes[i].vendor == vendor &&
200429d512e532ec9c969aa6f66ddbc542f3a5fe4daOGAWA Hirofumi		    pci_mmcfg_probes[i].device == device)
2019358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert			name = pci_mmcfg_probes[i].probe();
202429d512e532ec9c969aa6f66ddbc542f3a5fe4daOGAWA Hirofumi	}
2039358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
2049358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	if (name) {
205429d512e532ec9c969aa6f66ddbc542f3a5fe4daOGAWA Hirofumi		printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n",
206429d512e532ec9c969aa6f66ddbc542f3a5fe4daOGAWA Hirofumi		       name, pci_mmcfg_config_num ? "with" : "without");
2079358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	}
2089358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
2099358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert	return name != NULL;
2109358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert}
2119358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
212a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbinstatic void __init pci_mmcfg_insert_resources(unsigned long resource_flags)
2136a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert{
2146a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert#define PCI_MMCFG_RESOURCE_NAME_LEN 19
2156a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert	int i;
2166a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert	struct resource *res;
2176a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert	char *names;
2186a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert	unsigned num_buses;
2196a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert
2206a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert	res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res),
2216a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert			pci_mmcfg_config_num, GFP_KERNEL);
2226a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert	if (!res) {
2236a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert		printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n");
2246a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert		return;
2256a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert	}
2266a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert
2276a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert	names = (void *)&res[pci_mmcfg_config_num];
2286a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert	for (i = 0; i < pci_mmcfg_config_num; i++, res++) {
229429d512e532ec9c969aa6f66ddbc542f3a5fe4daOGAWA Hirofumi		struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i];
230429d512e532ec9c969aa6f66ddbc542f3a5fe4daOGAWA Hirofumi		num_buses = cfg->end_bus_number - cfg->start_bus_number + 1;
2316a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert		res->name = names;
2326a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert		snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u",
233429d512e532ec9c969aa6f66ddbc542f3a5fe4daOGAWA Hirofumi			 cfg->pci_segment);
234429d512e532ec9c969aa6f66ddbc542f3a5fe4daOGAWA Hirofumi		res->start = cfg->address;
2356a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert		res->end = res->start + (num_buses << 20) - 1;
236a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin		res->flags = IORESOURCE_MEM | resource_flags;
2376a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert		insert_resource(&iomem_resource, res);
2386a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert		names += PCI_MMCFG_RESOURCE_NAME_LEN;
2396a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert	}
240a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin
241a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	/* Mark that the resources have been inserted. */
242a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	pci_mmcfg_resources_inserted = 1;
2436a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert}
2446a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert
2457752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancockstatic acpi_status __init check_mcfg_resource(struct acpi_resource *res,
2467752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock					      void *data)
2477752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock{
2487752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	struct resource *mcfg_res = data;
2497752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	struct acpi_resource_address64 address;
2507752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	acpi_status status;
2517752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
2527752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
2537752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		struct acpi_resource_fixed_memory32 *fixmem32 =
2547752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock			&res->data.fixed_memory32;
2557752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		if (!fixmem32)
2567752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock			return AE_OK;
2577752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		if ((mcfg_res->start >= fixmem32->address) &&
2587752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		    (mcfg_res->end < (fixmem32->address +
2597752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock				      fixmem32->address_length))) {
2607752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock			mcfg_res->flags = 1;
2617752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock			return AE_CTRL_TERMINATE;
2627752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		}
2637752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	}
2647752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	if ((res->type != ACPI_RESOURCE_TYPE_ADDRESS32) &&
2657752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	    (res->type != ACPI_RESOURCE_TYPE_ADDRESS64))
2667752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		return AE_OK;
2677752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
2687752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	status = acpi_resource_to_address64(res, &address);
2697752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	if (ACPI_FAILURE(status) ||
2707752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	   (address.address_length <= 0) ||
2717752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	   (address.resource_type != ACPI_MEMORY_RANGE))
2727752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		return AE_OK;
2737752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
2747752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	if ((mcfg_res->start >= address.minimum) &&
2757752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	    (mcfg_res->end < (address.minimum + address.address_length))) {
2767752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		mcfg_res->flags = 1;
2777752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		return AE_CTRL_TERMINATE;
2787752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	}
2797752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	return AE_OK;
2807752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock}
2817752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
2827752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancockstatic acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl,
2837752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		void *context, void **rv)
2847752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock{
2857752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	struct resource *mcfg_res = context;
2867752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
2877752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	acpi_walk_resources(handle, METHOD_NAME__CRS,
2887752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock			    check_mcfg_resource, context);
2897752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
2907752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	if (mcfg_res->flags)
2917752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		return AE_CTRL_TERMINATE;
2927752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
2937752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	return AE_OK;
2947752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock}
2957752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
296a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lustatic int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used)
2977752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock{
2987752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	struct resource mcfg_res;
2997752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
3007752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	mcfg_res.start = start;
3017752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	mcfg_res.end = end;
3027752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	mcfg_res.flags = 0;
3037752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
3047752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	acpi_get_devices("PNP0C01", find_mboard_resource, &mcfg_res, NULL);
3057752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
3067752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	if (!mcfg_res.flags)
3077752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		acpi_get_devices("PNP0C02", find_mboard_resource, &mcfg_res,
3087752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock				 NULL);
3097752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
3107752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	return mcfg_res.flags;
3117752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock}
3127752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
313a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lutypedef int (*check_reserved_t)(u64 start, u64 end, unsigned type);
314a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu
315a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lustatic int __init is_mmconf_reserved(check_reserved_t is_reserved,
316a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		u64 addr, u64 size, int i,
317a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		typeof(pci_mmcfg_config[0]) *cfg, int with_e820)
318a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu{
319a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu	u64 old_size = size;
320a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu	int valid = 0;
321a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu
322a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu	while (!is_reserved(addr, addr + size - 1, E820_RESERVED)) {
323a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		size >>= 1;
324a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		if (size < (16UL<<20))
325a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu			break;
326a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu	}
327a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu
328a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu	if (size >= (16UL<<20) || size == old_size) {
329a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		printk(KERN_NOTICE
330a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		       "PCI: MCFG area at %Lx reserved in %s\n",
331a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu			addr, with_e820?"E820":"ACPI motherboard resources");
332a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		valid = 1;
333a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu
334a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		if (old_size != size) {
335a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu			/* update end_bus_number */
336a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu			cfg->end_bus_number = cfg->start_bus_number + ((size>>20) - 1);
337a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu			printk(KERN_NOTICE "PCI: updated MCFG configuration %d: base %lx "
338a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu			       "segment %hu buses %u - %u\n",
339a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu			       i, (unsigned long)cfg->address, cfg->pci_segment,
340a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu			       (unsigned int)cfg->start_bus_number,
341a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu			       (unsigned int)cfg->end_bus_number);
342a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		}
343a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu	}
344a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu
345a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu	return valid;
346a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu}
347a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu
348bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lustatic void __init pci_mmcfg_reject_broken(int early)
34944de0203fab205417b24322272c53ee0883c36e7OGAWA Hirofumi{
35026054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumi	typeof(pci_mmcfg_config[0]) *cfg;
3517752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	int i;
35226054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumi
35326054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumi	if ((pci_mmcfg_config_num == 0) ||
35426054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumi	    (pci_mmcfg_config == NULL) ||
35526054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumi	    (pci_mmcfg_config[0].address == 0))
35626054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumi		return;
35726054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumi
35826054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumi	cfg = &pci_mmcfg_config[0];
35944de0203fab205417b24322272c53ee0883c36e7OGAWA Hirofumi
3607752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	for (i = 0; i < pci_mmcfg_config_num; i++) {
36105c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu		int valid = 0;
362a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		u64 addr, size;
363a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu
3647752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		cfg = &pci_mmcfg_config[i];
365a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		addr = cfg->start_bus_number;
366a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		addr <<= 20;
367a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		addr += cfg->address;
368a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		size = cfg->end_bus_number + 1 - cfg->start_bus_number;
369a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		size <<= 20;
37005c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu		printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "
3717752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		       "segment %hu buses %u - %u\n",
3727752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		       i, (unsigned long)cfg->address, cfg->pci_segment,
3737752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		       (unsigned int)cfg->start_bus_number,
3747752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		       (unsigned int)cfg->end_bus_number);
37505c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu
376a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		if (!early)
377a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu			valid = is_mmconf_reserved(is_acpi_reserved, addr, size, i, cfg, 0);
37805c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu
37905c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu		if (valid)
38005c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu			continue;
38105c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu
38205c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu		if (!early)
3837752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock			printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not"
3847752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock			       " reserved in ACPI motherboard resources\n",
3857752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock			       cfg->address);
386a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu
38705c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu		/* Don't try to do this check unless configuration
388bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu		   type 1 is available. how about type 2 ?*/
389a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu		if (raw_pci_ops)
390a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu			valid = is_mmconf_reserved(e820_all_mapped, addr, size, i, cfg, 1);
39105c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu
39205c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu		if (!valid)
39305c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu			goto reject;
39444de0203fab205417b24322272c53ee0883c36e7OGAWA Hirofumi	}
3957752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
39626054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumi	return;
39726054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumi
39826054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumireject:
39926054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumi	printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
4000b64ad7123eb013c3de26750f2d4c356cd566231Yinghai Lu	pci_mmcfg_arch_free();
40126054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumi	kfree(pci_mmcfg_config);
40226054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumi	pci_mmcfg_config = NULL;
40326054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumi	pci_mmcfg_config_num = 0;
40444de0203fab205417b24322272c53ee0883c36e7OGAWA Hirofumi}
40544de0203fab205417b24322272c53ee0883c36e7OGAWA Hirofumi
40605c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lustatic int __initdata known_bridge;
4077752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
408968cbfad1a727b5689ae620f4d970abf6ce73340Thomas Gleixnerstatic void __init __pci_mmcfg_init(int early)
409b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert{
4107752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	/* MMCONFIG disabled */
411b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert	if ((pci_probe & PCI_PROBE_MMCONF) == 0)
412b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert		return;
413b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert
4147752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock	/* MMCONFIG already enabled */
41505c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu	if (!early && !(pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF))
4167752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock		return;
4179358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert
41805c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu	/* for late to exit */
41905c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu	if (known_bridge)
42005c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu		return;
4217752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock
422bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu	if (early) {
42305c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu		if (pci_mmcfg_check_hostbridge())
42405c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu			known_bridge = 1;
42505c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu	}
42605c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu
42705c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu	if (!known_bridge) {
42805c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu		acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
429bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu		pci_mmcfg_reject_broken(early);
43005c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu	}
431b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert
432b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert	if ((pci_mmcfg_config_num == 0) ||
433b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert	    (pci_mmcfg_config == NULL) ||
434b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert	    (pci_mmcfg_config[0].address == 0))
435b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert		return;
436b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert
437b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert	if (pci_mmcfg_arch_init()) {
4386a0668fc41fa479df617151c2d4e297299a4ffe2Olivier Galibert		if (known_bridge)
439a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin			pci_mmcfg_insert_resources(IORESOURCE_BUSY);
440b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert		pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
441a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	} else {
442a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin		/*
443a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin		 * Signal not to attempt to insert mmcfg resources because
444a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin		 * the architecture mmcfg setup could not initialize.
445a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin		 */
446a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin		pci_mmcfg_resources_inserted = 1;
447b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert	}
448b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert}
449a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin
450bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Luvoid __init pci_mmcfg_early_init(void)
45105c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu{
452bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu	__pci_mmcfg_init(1);
45305c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu}
45405c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu
45505c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Luvoid __init pci_mmcfg_late_init(void)
45605c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu{
457bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu	__pci_mmcfg_init(0);
45805c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu}
45905c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu
460a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbinstatic int __init pci_mmcfg_late_insert_resources(void)
461a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin{
462a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	/*
463a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	 * If resources are already inserted or we are not using MMCONFIG,
464a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	 * don't insert the resources.
465a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	 */
466a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	if ((pci_mmcfg_resources_inserted == 1) ||
467a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	    (pci_probe & PCI_PROBE_MMCONF) == 0 ||
468a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	    (pci_mmcfg_config_num == 0) ||
469a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	    (pci_mmcfg_config == NULL) ||
470a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	    (pci_mmcfg_config[0].address == 0))
471a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin		return 1;
472a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin
473a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	/*
474a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	 * Attempt to insert the mmcfg resources but not with the busy flag
475a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	 * marked so it won't cause request errors when __request_region is
476a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	 * called.
477a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	 */
478a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	pci_mmcfg_insert_resources(0);
479a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin
480a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin	return 0;
481a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin}
482a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin
483a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin/*
484a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin * Perform MMCONFIG resource insertion after PCI initialization to allow for
485a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin * misprogrammed MCFG tables that state larger sizes but actually conflict
486a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin * with other system resources.
487a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin */
488a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbinlate_initcall(pci_mmcfg_late_insert_resources);
489