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> 155f0db7a2fb78895a197f64e548333b3bbd433996Feng Tang#include <linux/sfi_acpi.h> 16b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert#include <linux/bitmap.h> 179a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas#include <linux/dmi.h> 185a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 19376f70acfe4bd97493299cdfc00a8d235279d267Jiang Liu#include <linux/mutex.h> 20376f70acfe4bd97493299cdfc00a8d235279d267Jiang Liu#include <linux/rculist.h> 21b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert#include <asm/e820.h> 22824877111cd7f2b4fd2fe6947c5c5cbbb3ac5bd8Jaswinder Singh Rajput#include <asm/pci_x86.h> 235f0db7a2fb78895a197f64e548333b3bbd433996Feng Tang#include <asm/acpi.h> 24b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert 25f4a2d5840e9f0e48d1a787b66e7346087a756029Len Brown#define PREFIX "PCI: " 26a192a9580bcc41692be1f36b77c3b681827f566aLen Brown 27a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin/* Indicate if the mmcfg resources have been placed into the resource table. */ 2895c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liustatic bool pci_mmcfg_running_state; 299c95111b330d2ddf851444528a7608f267cbb50cJiang Liustatic bool pci_mmcfg_arch_init_failed; 30376f70acfe4bd97493299cdfc00a8d235279d267Jiang Liustatic DEFINE_MUTEX(pci_mmcfg_lock); 31a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin 32ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn HelgaasLIST_HEAD(pci_mmcfg_list); 33ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas 3464474b5235e83cc5e6002dcdb37145850ad86194Mathias Krausestatic void __init pci_mmconfig_remove(struct pci_mmcfg_region *cfg) 35ba2afbabfc44d6322e8607c004f37868ff786cf8Bjorn Helgaas{ 36ba2afbabfc44d6322e8607c004f37868ff786cf8Bjorn Helgaas if (cfg->res.parent) 37ba2afbabfc44d6322e8607c004f37868ff786cf8Bjorn Helgaas release_resource(&cfg->res); 38ba2afbabfc44d6322e8607c004f37868ff786cf8Bjorn Helgaas list_del(&cfg->list); 39ba2afbabfc44d6322e8607c004f37868ff786cf8Bjorn Helgaas kfree(cfg); 40ba2afbabfc44d6322e8607c004f37868ff786cf8Bjorn Helgaas} 41ba2afbabfc44d6322e8607c004f37868ff786cf8Bjorn Helgaas 4264474b5235e83cc5e6002dcdb37145850ad86194Mathias Krausestatic void __init free_all_mmcfg(void) 437da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas{ 44ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas struct pci_mmcfg_region *cfg, *tmp; 4556ddf4d3cf04e80254d3d721c6bea2f8ec44c41aBjorn Helgaas 467da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas pci_mmcfg_arch_free(); 47ba2afbabfc44d6322e8607c004f37868ff786cf8Bjorn Helgaas list_for_each_entry_safe(cfg, tmp, &pci_mmcfg_list, list) 48ba2afbabfc44d6322e8607c004f37868ff786cf8Bjorn Helgaas pci_mmconfig_remove(cfg); 49ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas} 50ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas 51a18e3690a52790a034d6540d54e8e1f1cd125da2Greg Kroah-Hartmanstatic void list_add_sorted(struct pci_mmcfg_region *new) 52ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas{ 53ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas struct pci_mmcfg_region *cfg; 54ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas 55ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas /* keep list sorted by segment and starting bus number */ 56376f70acfe4bd97493299cdfc00a8d235279d267Jiang Liu list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) { 57ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas if (cfg->segment > new->segment || 58ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas (cfg->segment == new->segment && 59ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas cfg->start_bus >= new->start_bus)) { 60376f70acfe4bd97493299cdfc00a8d235279d267Jiang Liu list_add_tail_rcu(&new->list, &cfg->list); 61ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas return; 62ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas } 63ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas } 64376f70acfe4bd97493299cdfc00a8d235279d267Jiang Liu list_add_tail_rcu(&new->list, &pci_mmcfg_list); 657da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas} 667da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas 67a18e3690a52790a034d6540d54e8e1f1cd125da2Greg Kroah-Hartmanstatic struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start, 68a18e3690a52790a034d6540d54e8e1f1cd125da2Greg Kroah-Hartman int end, u64 addr) 69068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu{ 70d215a9c8b46e55a1d3bc1cd907c943ef95938a0eBjorn Helgaas struct pci_mmcfg_region *new; 7156ddf4d3cf04e80254d3d721c6bea2f8ec44c41aBjorn Helgaas struct resource *res; 72068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu 73f7ca69848786bb99fdfafb511791b078c298438eBjorn Helgaas if (addr == 0) 74f7ca69848786bb99fdfafb511791b078c298438eBjorn Helgaas return NULL; 75f7ca69848786bb99fdfafb511791b078c298438eBjorn Helgaas 76ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas new = kzalloc(sizeof(*new), GFP_KERNEL); 77068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu if (!new) 787da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas return NULL; 79068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu 8095cf1cf0c5a767feb811dfed298b95b1df8824c7Bjorn Helgaas new->address = addr; 8195cf1cf0c5a767feb811dfed298b95b1df8824c7Bjorn Helgaas new->segment = segment; 8295cf1cf0c5a767feb811dfed298b95b1df8824c7Bjorn Helgaas new->start_bus = start; 8395cf1cf0c5a767feb811dfed298b95b1df8824c7Bjorn Helgaas new->end_bus = end; 847da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas 8556ddf4d3cf04e80254d3d721c6bea2f8ec44c41aBjorn Helgaas res = &new->res; 8656ddf4d3cf04e80254d3d721c6bea2f8ec44c41aBjorn Helgaas res->start = addr + PCI_MMCFG_BUS_OFFSET(start); 871ca98fa652bb5dc3c8793335db9ccc5d0f2e1f65Bjorn Helgaas res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1; 8856ddf4d3cf04e80254d3d721c6bea2f8ec44c41aBjorn Helgaas res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; 8956ddf4d3cf04e80254d3d721c6bea2f8ec44c41aBjorn Helgaas snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN, 9056ddf4d3cf04e80254d3d721c6bea2f8ec44c41aBjorn Helgaas "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end); 9156ddf4d3cf04e80254d3d721c6bea2f8ec44c41aBjorn Helgaas res->name = new->name; 9256ddf4d3cf04e80254d3d721c6bea2f8ec44c41aBjorn Helgaas 93ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas return new; 94068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu} 95068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu 9664474b5235e83cc5e6002dcdb37145850ad86194Mathias Krausestatic struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start, 97846e402300ffa2131239dcf82265b5366cd755f4Jiang Liu int end, u64 addr) 98846e402300ffa2131239dcf82265b5366cd755f4Jiang Liu{ 99846e402300ffa2131239dcf82265b5366cd755f4Jiang Liu struct pci_mmcfg_region *new; 100846e402300ffa2131239dcf82265b5366cd755f4Jiang Liu 101846e402300ffa2131239dcf82265b5366cd755f4Jiang Liu new = pci_mmconfig_alloc(segment, start, end, addr); 102376f70acfe4bd97493299cdfc00a8d235279d267Jiang Liu if (new) { 103376f70acfe4bd97493299cdfc00a8d235279d267Jiang Liu mutex_lock(&pci_mmcfg_lock); 104846e402300ffa2131239dcf82265b5366cd755f4Jiang Liu list_add_sorted(new); 105376f70acfe4bd97493299cdfc00a8d235279d267Jiang Liu mutex_unlock(&pci_mmcfg_lock); 1069c95111b330d2ddf851444528a7608f267cbb50cJiang Liu 10724c97f04c4570e02c5cf4b97c73ab9dc27bacdbeJiang Liu pr_info(PREFIX 1089c95111b330d2ddf851444528a7608f267cbb50cJiang Liu "MMCONFIG for domain %04x [bus %02x-%02x] at %pR " 1099c95111b330d2ddf851444528a7608f267cbb50cJiang Liu "(base %#lx)\n", 1109c95111b330d2ddf851444528a7608f267cbb50cJiang Liu segment, start, end, &new->res, (unsigned long)addr); 111376f70acfe4bd97493299cdfc00a8d235279d267Jiang Liu } 112846e402300ffa2131239dcf82265b5366cd755f4Jiang Liu 113846e402300ffa2131239dcf82265b5366cd755f4Jiang Liu return new; 114846e402300ffa2131239dcf82265b5366cd755f4Jiang Liu} 115846e402300ffa2131239dcf82265b5366cd755f4Jiang Liu 116f6e1d8cc38b3776038fb15d3acc82ed8bb552f82Bjorn Helgaasstruct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus) 117f6e1d8cc38b3776038fb15d3acc82ed8bb552f82Bjorn Helgaas{ 118f6e1d8cc38b3776038fb15d3acc82ed8bb552f82Bjorn Helgaas struct pci_mmcfg_region *cfg; 119f6e1d8cc38b3776038fb15d3acc82ed8bb552f82Bjorn Helgaas 120376f70acfe4bd97493299cdfc00a8d235279d267Jiang Liu list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) 121f6e1d8cc38b3776038fb15d3acc82ed8bb552f82Bjorn Helgaas if (cfg->segment == segment && 122f6e1d8cc38b3776038fb15d3acc82ed8bb552f82Bjorn Helgaas cfg->start_bus <= bus && bus <= cfg->end_bus) 123f6e1d8cc38b3776038fb15d3acc82ed8bb552f82Bjorn Helgaas return cfg; 124f6e1d8cc38b3776038fb15d3acc82ed8bb552f82Bjorn Helgaas 125f6e1d8cc38b3776038fb15d3acc82ed8bb552f82Bjorn Helgaas return NULL; 126f6e1d8cc38b3776038fb15d3acc82ed8bb552f82Bjorn Helgaas} 127f6e1d8cc38b3776038fb15d3acc82ed8bb552f82Bjorn Helgaas 12864474b5235e83cc5e6002dcdb37145850ad86194Mathias Krausestatic const char *__init pci_mmcfg_e7520(void) 1299358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert{ 1309358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert u32 win; 131bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0xce, 2, &win); 1329358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 133b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert win = win & 0xf000; 134068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu if (win == 0x0000 || win == 0xf000) 135068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu return NULL; 136068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu 1377da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas if (pci_mmconfig_add(0, 0, 255, win << 16) == NULL) 138068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu return NULL; 139068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu 1409358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert return "Intel Corporation E7520 Memory Controller Hub"; 1419358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert} 1429358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 14364474b5235e83cc5e6002dcdb37145850ad86194Mathias Krausestatic const char *__init pci_mmcfg_intel_945(void) 1449358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert{ 1459358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert u32 pciexbar, mask = 0, len = 0; 1469358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 147bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0x48, 4, &pciexbar); 1489358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 1499358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert /* Enable bit */ 1509358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert if (!(pciexbar & 1)) 151068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu return NULL; 1529358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 1539358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert /* Size bits */ 1549358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert switch ((pciexbar >> 1) & 3) { 1559358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert case 0: 1569358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert mask = 0xf0000000U; 1579358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert len = 0x10000000U; 1589358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert break; 1599358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert case 1: 1609358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert mask = 0xf8000000U; 1619358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert len = 0x08000000U; 1629358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert break; 1639358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert case 2: 1649358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert mask = 0xfc000000U; 1659358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert len = 0x04000000U; 1669358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert break; 1679358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert default: 168068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu return NULL; 1699358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert } 1709358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 1719358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert /* Errata #2, things break when not aligned on a 256Mb boundary */ 1729358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert /* Can only happen in 64M/128M mode */ 1739358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 1749358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert if ((pciexbar & mask) & 0x0fffffffU) 175068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu return NULL; 1769358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 177b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert /* Don't hit the APIC registers and their friends */ 178b5229dbb857f61d77d8d4048d9033387a5411b8eOlivier Galibert if ((pciexbar & mask) >= 0xf0000000U) 179068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu return NULL; 180068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu 1817da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas if (pci_mmconfig_add(0, 0, (len >> 20) - 1, pciexbar & mask) == NULL) 182068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu return NULL; 183068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu 1849358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; 1859358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert} 1869358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 18764474b5235e83cc5e6002dcdb37145850ad86194Mathias Krausestatic const char *__init pci_mmcfg_amd_fam10h(void) 1887fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu{ 1897fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu u32 low, high, address; 1907fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu u64 base, msr; 1917fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu int i; 1927da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas unsigned segnbits = 0, busnbits, end_bus; 1937fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu 1945f0b2976cb2b62668a076f54419c24b8ab677167Yinghai Lu if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF)) 1955f0b2976cb2b62668a076f54419c24b8ab677167Yinghai Lu return NULL; 1965f0b2976cb2b62668a076f54419c24b8ab677167Yinghai Lu 1977fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu address = MSR_FAM10H_MMIO_CONF_BASE; 1987fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu if (rdmsr_safe(address, &low, &high)) 1997fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu return NULL; 2007fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu 2017fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu msr = high; 2027fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu msr <<= 32; 2037fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu msr |= low; 2047fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu 2057fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu /* mmconfig is not enable */ 2067fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu if (!(msr & FAM10H_MMIO_CONF_ENABLE)) 2077fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu return NULL; 2087fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu 2097fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT); 2107fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu 2117fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu busnbits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) & 2127fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu FAM10H_MMIO_CONF_BUSRANGE_MASK; 2137fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu 2147fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu /* 2157fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu * only handle bus 0 ? 2167fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu * need to skip it 2177fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu */ 2187fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu if (!busnbits) 2197fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu return NULL; 2207fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu 2217fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu if (busnbits > 8) { 2227fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu segnbits = busnbits - 8; 2237fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu busnbits = 8; 2247fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu } 2257fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu 2267da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas end_bus = (1 << busnbits) - 1; 227068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu for (i = 0; i < (1 << segnbits); i++) 2287da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas if (pci_mmconfig_add(i, 0, end_bus, 2297da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas base + (1<<28) * i) == NULL) { 2307da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas free_all_mmcfg(); 2317da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas return NULL; 2327da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas } 2337fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu 2347fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu return "AMD Family 10h NB"; 2357fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu} 2367fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu 2375546d6f56807115a035d140f7364ce5807dbcc87Ed Swierkstatic bool __initdata mcp55_checked; 23864474b5235e83cc5e6002dcdb37145850ad86194Mathias Krausestatic const char *__init pci_mmcfg_nvidia_mcp55(void) 2395546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk{ 2405546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk int bus; 2415546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk int mcp55_mmconf_found = 0; 2425546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk 243776f7ad6322817a5a021c5c479d688d322fb4b27Mathias Krause static const u32 extcfg_regnum __initconst = 0x90; 244776f7ad6322817a5a021c5c479d688d322fb4b27Mathias Krause static const u32 extcfg_regsize __initconst = 4; 245776f7ad6322817a5a021c5c479d688d322fb4b27Mathias Krause static const u32 extcfg_enable_mask __initconst = 1 << 31; 246776f7ad6322817a5a021c5c479d688d322fb4b27Mathias Krause static const u32 extcfg_start_mask __initconst = 0xff << 16; 247776f7ad6322817a5a021c5c479d688d322fb4b27Mathias Krause static const int extcfg_start_shift __initconst = 16; 248776f7ad6322817a5a021c5c479d688d322fb4b27Mathias Krause static const u32 extcfg_size_mask __initconst = 0x3 << 28; 249776f7ad6322817a5a021c5c479d688d322fb4b27Mathias Krause static const int extcfg_size_shift __initconst = 28; 250776f7ad6322817a5a021c5c479d688d322fb4b27Mathias Krause static const int extcfg_sizebus[] __initconst = { 251776f7ad6322817a5a021c5c479d688d322fb4b27Mathias Krause 0x100, 0x80, 0x40, 0x20 252776f7ad6322817a5a021c5c479d688d322fb4b27Mathias Krause }; 253776f7ad6322817a5a021c5c479d688d322fb4b27Mathias Krause static const u32 extcfg_base_mask[] __initconst = { 254776f7ad6322817a5a021c5c479d688d322fb4b27Mathias Krause 0x7ff8, 0x7ffc, 0x7ffe, 0x7fff 255776f7ad6322817a5a021c5c479d688d322fb4b27Mathias Krause }; 256776f7ad6322817a5a021c5c479d688d322fb4b27Mathias Krause static const int extcfg_base_lshift __initconst = 25; 2575546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk 2585546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk /* 2595546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk * do check if amd fam10h already took over 2605546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk */ 261ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas if (!acpi_disabled || !list_empty(&pci_mmcfg_list) || mcp55_checked) 2625546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk return NULL; 2635546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk 2645546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk mcp55_checked = true; 2655546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk for (bus = 0; bus < 256; bus++) { 2665546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk u64 base; 2675546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk u32 l, extcfg; 2685546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk u16 vendor, device; 2695546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk int start, size_index, end; 2705546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk 2715546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), 0, 4, &l); 2725546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk vendor = l & 0xffff; 2735546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk device = (l >> 16) & 0xffff; 2745546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk 2755546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk if (PCI_VENDOR_ID_NVIDIA != vendor || 0x0369 != device) 2765546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk continue; 2775546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk 2785546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), extcfg_regnum, 2795546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk extcfg_regsize, &extcfg); 2805546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk 2815546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk if (!(extcfg & extcfg_enable_mask)) 2825546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk continue; 2835546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk 2845546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift; 2855546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk base = extcfg & extcfg_base_mask[size_index]; 2865546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk /* base could > 4G */ 2875546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk base <<= extcfg_base_lshift; 2885546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk start = (extcfg & extcfg_start_mask) >> extcfg_start_shift; 2895546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk end = start + extcfg_sizebus[size_index] - 1; 2907da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas if (pci_mmconfig_add(0, start, end, base) == NULL) 2917da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas continue; 2925546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk mcp55_mmconf_found++; 2935546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk } 2945546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk 2955546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk if (!mcp55_mmconf_found) 2965546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk return NULL; 2975546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk 2985546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk return "nVidia MCP55"; 2995546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk} 3005546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk 3019358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibertstruct pci_mmcfg_hostbridge_probe { 3027fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu u32 bus; 3037fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu u32 devfn; 3049358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert u32 vendor; 3059358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert u32 device; 3069358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert const char *(*probe)(void); 3079358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert}; 3089358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 3096af13bac777aaec7460475a9fea8e9640c4b606eMathias Krausestatic const struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initconst = { 3107fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL, 3117fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 }, 3127fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL, 3137fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 }, 3147fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu { 0, PCI_DEVFN(0x18, 0), PCI_VENDOR_ID_AMD, 3157fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu 0x1200, pci_mmcfg_amd_fam10h }, 3167fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD, 3177fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu 0x1200, pci_mmcfg_amd_fam10h }, 3185546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_NVIDIA, 3195546d6f56807115a035d140f7364ce5807dbcc87Ed Swierk 0x0369, pci_mmcfg_nvidia_mcp55 }, 3209358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert}; 3219358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 322068258bc15439c11a966e873f931cc8e513dca61Yinghai Lustatic void __init pci_mmcfg_check_end_bus_number(void) 323068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu{ 324987c367b4e93be6826394e7c9cc14d28bb5c8810Bjorn Helgaas struct pci_mmcfg_region *cfg, *cfgx; 325068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu 326bb8d41330ce27edb91adb6922d3f8e1a8923f727Thomas Gleixner /* Fixup overlaps */ 327ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas list_for_each_entry(cfg, &pci_mmcfg_list, list) { 328d7e6b66fe87c9f42480d73fc314aecaeae84ca6bBjorn Helgaas if (cfg->end_bus < cfg->start_bus) 329d7e6b66fe87c9f42480d73fc314aecaeae84ca6bBjorn Helgaas cfg->end_bus = 255; 330068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu 331bb8d41330ce27edb91adb6922d3f8e1a8923f727Thomas Gleixner /* Don't access the list head ! */ 332bb8d41330ce27edb91adb6922d3f8e1a8923f727Thomas Gleixner if (cfg->list.next == &pci_mmcfg_list) 333bb8d41330ce27edb91adb6922d3f8e1a8923f727Thomas Gleixner break; 334bb8d41330ce27edb91adb6922d3f8e1a8923f727Thomas Gleixner 335ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas cfgx = list_entry(cfg->list.next, typeof(*cfg), list); 336bb8d41330ce27edb91adb6922d3f8e1a8923f727Thomas Gleixner if (cfg->end_bus >= cfgx->start_bus) 337d7e6b66fe87c9f42480d73fc314aecaeae84ca6bBjorn Helgaas cfg->end_bus = cfgx->start_bus - 1; 338068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu } 339068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu} 340068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu 3419358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibertstatic int __init pci_mmcfg_check_hostbridge(void) 3429358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert{ 3439358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert u32 l; 3447fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu u32 bus, devfn; 3459358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert u16 vendor, device; 3469358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert int i; 3479358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert const char *name; 3489358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 349bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu if (!raw_pci_ops) 350bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu return 0; 351bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu 3527da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas free_all_mmcfg(); 3539358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 354068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu for (i = 0; i < ARRAY_SIZE(pci_mmcfg_probes); i++) { 3557fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu bus = pci_mmcfg_probes[i].bus; 3567fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu devfn = pci_mmcfg_probes[i].devfn; 357bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lu raw_pci_ops->read(0, bus, devfn, 0, 4, &l); 3587fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu vendor = l & 0xffff; 3597fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu device = (l >> 16) & 0xffff; 3607fd0da4085d5b012a6bdcbbd63da7ead9fc69ad4Yinghai Lu 361068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu name = NULL; 362429d512e532ec9c969aa6f66ddbc542f3a5fe4daOGAWA Hirofumi if (pci_mmcfg_probes[i].vendor == vendor && 363429d512e532ec9c969aa6f66ddbc542f3a5fe4daOGAWA Hirofumi pci_mmcfg_probes[i].device == device) 3649358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert name = pci_mmcfg_probes[i].probe(); 3659358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 366068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu if (name) 36724c97f04c4570e02c5cf4b97c73ab9dc27bacdbeJiang Liu pr_info(PREFIX "%s with MMCONFIG support\n", name); 3689358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert } 3699358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 370068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu /* some end_bus_number is crazy, fix it */ 371068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu pci_mmcfg_check_end_bus_number(); 372068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu 373ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas return !list_empty(&pci_mmcfg_list); 3749358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert} 3759358c693c5ac1afde28f24ac651f7903d32a850cOlivier Galibert 376a18e3690a52790a034d6540d54e8e1f1cd125da2Greg Kroah-Hartmanstatic acpi_status check_mcfg_resource(struct acpi_resource *res, void *data) 3777752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock{ 3787752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock struct resource *mcfg_res = data; 3797752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock struct acpi_resource_address64 address; 3807752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock acpi_status status; 3817752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock 3827752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) { 3837752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock struct acpi_resource_fixed_memory32 *fixmem32 = 3847752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock &res->data.fixed_memory32; 3857752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock if (!fixmem32) 3867752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock return AE_OK; 3877752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock if ((mcfg_res->start >= fixmem32->address) && 38875e613cdc7bb2ba3795b1bc3ddf19476c767ba68Yinghai Lu (mcfg_res->end < (fixmem32->address + 3897752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock fixmem32->address_length))) { 3907752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock mcfg_res->flags = 1; 3917752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock return AE_CTRL_TERMINATE; 3927752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock } 3937752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock } 3947752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock if ((res->type != ACPI_RESOURCE_TYPE_ADDRESS32) && 3957752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock (res->type != ACPI_RESOURCE_TYPE_ADDRESS64)) 3967752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock return AE_OK; 3977752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock 3987752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock status = acpi_resource_to_address64(res, &address); 3997752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock if (ACPI_FAILURE(status) || 4007752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock (address.address_length <= 0) || 4017752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock (address.resource_type != ACPI_MEMORY_RANGE)) 4027752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock return AE_OK; 4037752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock 4047752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock if ((mcfg_res->start >= address.minimum) && 40575e613cdc7bb2ba3795b1bc3ddf19476c767ba68Yinghai Lu (mcfg_res->end < (address.minimum + address.address_length))) { 4067752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock mcfg_res->flags = 1; 4077752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock return AE_CTRL_TERMINATE; 4087752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock } 4097752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock return AE_OK; 4107752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock} 4117752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock 412a18e3690a52790a034d6540d54e8e1f1cd125da2Greg Kroah-Hartmanstatic acpi_status find_mboard_resource(acpi_handle handle, u32 lvl, 413a18e3690a52790a034d6540d54e8e1f1cd125da2Greg Kroah-Hartman void *context, void **rv) 4147752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock{ 4157752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock struct resource *mcfg_res = context; 4167752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock 4177752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock acpi_walk_resources(handle, METHOD_NAME__CRS, 4187752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock check_mcfg_resource, context); 4197752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock 4207752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock if (mcfg_res->flags) 4217752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock return AE_CTRL_TERMINATE; 4227752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock 4237752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock return AE_OK; 4247752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock} 4257752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock 426a18e3690a52790a034d6540d54e8e1f1cd125da2Greg Kroah-Hartmanstatic int is_acpi_reserved(u64 start, u64 end, unsigned not_used) 4277752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock{ 4287752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock struct resource mcfg_res; 4297752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock 4307752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock mcfg_res.start = start; 43175e613cdc7bb2ba3795b1bc3ddf19476c767ba68Yinghai Lu mcfg_res.end = end - 1; 4327752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock mcfg_res.flags = 0; 4337752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock 4347752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock acpi_get_devices("PNP0C01", find_mboard_resource, &mcfg_res, NULL); 4357752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock 4367752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock if (!mcfg_res.flags) 4377752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock acpi_get_devices("PNP0C02", find_mboard_resource, &mcfg_res, 4387752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock NULL); 4397752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock 4407752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock return mcfg_res.flags; 4417752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock} 4427752d5cfe3d11ca0bb9c673ec38bd78ba6578f8eRobert Hancock 443a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lutypedef int (*check_reserved_t)(u64 start, u64 end, unsigned type); 444a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu 44595c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liustatic int __ref is_mmconf_reserved(check_reserved_t is_reserved, 44695c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu struct pci_mmcfg_region *cfg, 44795c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu struct device *dev, int with_e820) 448a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu{ 4492f2a8b9c90279e75f87aaf322a948bdced27e89fBjorn Helgaas u64 addr = cfg->res.start; 4502f2a8b9c90279e75f87aaf322a948bdced27e89fBjorn Helgaas u64 size = resource_size(&cfg->res); 451a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu u64 old_size = size; 45295c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu int num_buses; 45395c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu char *method = with_e820 ? "E820" : "ACPI motherboard resources"; 454a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu 455044cd80942e47b9de0915b627902adf05c52377fYinghai Lu while (!is_reserved(addr, addr + size, E820_RESERVED)) { 456a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu size >>= 1; 457a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu if (size < (16UL<<20)) 458a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu break; 459a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu } 460a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu 46195c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu if (size < (16UL<<20) && size != old_size) 46295c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu return 0; 46395c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu 46495c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu if (dev) 46595c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu dev_info(dev, "MMCONFIG at %pR reserved in %s\n", 46695c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu &cfg->res, method); 46795c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu else 46824c97f04c4570e02c5cf4b97c73ab9dc27bacdbeJiang Liu pr_info(PREFIX "MMCONFIG at %pR reserved in %s\n", 46995c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu &cfg->res, method); 47095c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu 47195c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu if (old_size != size) { 47295c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu /* update end_bus */ 47395c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu cfg->end_bus = cfg->start_bus + ((size>>20) - 1); 47495c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu num_buses = cfg->end_bus - cfg->start_bus + 1; 47595c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu cfg->res.end = cfg->res.start + 47695c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu PCI_MMCFG_BUS_OFFSET(num_buses) - 1; 47795c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu snprintf(cfg->name, PCI_MMCFG_RESOURCE_NAME_LEN, 47895c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu "PCI MMCONFIG %04x [bus %02x-%02x]", 47995c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu cfg->segment, cfg->start_bus, cfg->end_bus); 48095c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu 48195c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu if (dev) 48295c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu dev_info(dev, 48395c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu "MMCONFIG " 48495c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu "at %pR (base %#lx) (size reduced!)\n", 48595c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu &cfg->res, (unsigned long) cfg->address); 48695c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu else 48724c97f04c4570e02c5cf4b97c73ab9dc27bacdbeJiang Liu pr_info(PREFIX 48895c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu "MMCONFIG for %04x [bus%02x-%02x] " 48995c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu "at %pR (base %#lx) (size reduced!)\n", 49095c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu cfg->segment, cfg->start_bus, cfg->end_bus, 49195c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu &cfg->res, (unsigned long) cfg->address); 492a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu } 493a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu 49495c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu return 1; 495a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu} 496a83fe32fa668c0a17b3f99a1480b006f7d649924Yinghai Lu 49795c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liustatic int __ref pci_mmcfg_check_reserved(struct device *dev, 49895c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu struct pci_mmcfg_region *cfg, int early) 4992a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu{ 5002a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu if (!early && !acpi_disabled) { 50195c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu if (is_mmconf_reserved(is_acpi_reserved, cfg, dev, 0)) 5022a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu return 1; 50395c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu 50495c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu if (dev) 50595c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu dev_info(dev, FW_INFO 50695c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu "MMCONFIG at %pR not reserved in " 50795c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu "ACPI motherboard resources\n", 50895c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu &cfg->res); 5092a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu else 51024c97f04c4570e02c5cf4b97c73ab9dc27bacdbeJiang Liu pr_info(FW_INFO PREFIX 5112a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu "MMCONFIG at %pR not reserved in " 5122a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu "ACPI motherboard resources\n", 5132a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu &cfg->res); 5142a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu } 5152a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu 51695c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu /* 51795c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu * e820_all_mapped() is marked as __init. 51895c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu * All entries from ACPI MCFG table have been checked at boot time. 51995c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu * For MCFG information constructed from hotpluggable host bridge's 52095c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu * _CBA method, just assume it's reserved. 52195c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu */ 52295c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu if (pci_mmcfg_running_state) 52395c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu return 1; 52495c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu 5252a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu /* Don't try to do this check unless configuration 5262a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu type 1 is available. how about type 2 ?*/ 5272a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu if (raw_pci_ops) 52895c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu return is_mmconf_reserved(e820_all_mapped, cfg, dev, 1); 5292a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu 5302a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu return 0; 5312a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu} 5322a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu 533bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Lustatic void __init pci_mmcfg_reject_broken(int early) 53444de0203fab205417b24322272c53ee0883c36e7OGAWA Hirofumi{ 535987c367b4e93be6826394e7c9cc14d28bb5c8810Bjorn Helgaas struct pci_mmcfg_region *cfg; 53626054ed02bb20f5b2e02d92cb6f0be0e2b0196d5OGAWA Hirofumi 537ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas list_for_each_entry(cfg, &pci_mmcfg_list, list) { 53895c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu if (pci_mmcfg_check_reserved(NULL, cfg, early) == 0) { 53924c97f04c4570e02c5cf4b97c73ab9dc27bacdbeJiang Liu pr_info(PREFIX "not using MMCONFIG\n"); 5402a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu free_all_mmcfg(); 5412a76c450bd0377f715caf313ded530290d7dc7d7Jiang Liu return; 542a02ce953a14d6a8aab721b129b3c8ff4981a76e6Feng Tang } 54344de0203fab205417b24322272c53ee0883c36e7OGAWA Hirofumi } 54444de0203fab205417b24322272c53ee0883c36e7OGAWA Hirofumi} 54544de0203fab205417b24322272c53ee0883c36e7OGAWA Hirofumi 5469a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaasstatic int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg, 5479a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas struct acpi_mcfg_allocation *cfg) 548c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown{ 5499a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas int year; 5509a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas 5519a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas if (cfg->address < 0xFFFFFFFF) 5529a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas return 0; 5539a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas 554526018bc5eccfe3177780f03d2aaba0efee40720Mike Travis if (!strncmp(mcfg->header.oem_id, "SGI", 3)) 5559a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas return 0; 556c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown 5579a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas if (mcfg->header.revision >= 1) { 5589a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && 5599a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas year >= 2010) 5609a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas return 0; 5619a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas } 5629a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas 56324c97f04c4570e02c5cf4b97c73ab9dc27bacdbeJiang Liu pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx " 5649a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas "is above 4GB, ignored\n", cfg->pci_segment, 5659a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas cfg->start_bus_number, cfg->end_bus_number, cfg->address); 5669a08f7d3506019e3833cd4394ca0d7da0ae3689fBjorn Helgaas return -EINVAL; 567c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown} 568c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown 569c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brownstatic int __init pci_parse_mcfg(struct acpi_table_header *header) 570c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown{ 571c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown struct acpi_table_mcfg *mcfg; 572d3578ef7aab5b9bb874d085609b3ed5d9abffc48Bjorn Helgaas struct acpi_mcfg_allocation *cfg_table, *cfg; 573c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown unsigned long i; 5747da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas int entries; 575c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown 576c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown if (!header) 577c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown return -EINVAL; 578c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown 579c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown mcfg = (struct acpi_table_mcfg *)header; 580c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown 581c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown /* how many config structures do we have */ 5827da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas free_all_mmcfg(); 583e823d6ff581c5d1d76aa8c73a202d7d1419d34b8Bjorn Helgaas entries = 0; 584c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown i = header->length - sizeof(struct acpi_table_mcfg); 585c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown while (i >= sizeof(struct acpi_mcfg_allocation)) { 586e823d6ff581c5d1d76aa8c73a202d7d1419d34b8Bjorn Helgaas entries++; 587c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown i -= sizeof(struct acpi_mcfg_allocation); 5884b8073e467e6a66b6a5a8e799d28bc3b243c0d78Peter Senna Tschudin } 589e823d6ff581c5d1d76aa8c73a202d7d1419d34b8Bjorn Helgaas if (entries == 0) { 59024c97f04c4570e02c5cf4b97c73ab9dc27bacdbeJiang Liu pr_err(PREFIX "MMCONFIG has no entries\n"); 591c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown return -ENODEV; 592c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown } 593c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown 594d3578ef7aab5b9bb874d085609b3ed5d9abffc48Bjorn Helgaas cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1]; 595e823d6ff581c5d1d76aa8c73a202d7d1419d34b8Bjorn Helgaas for (i = 0; i < entries; i++) { 596d3578ef7aab5b9bb874d085609b3ed5d9abffc48Bjorn Helgaas cfg = &cfg_table[i]; 597d3578ef7aab5b9bb874d085609b3ed5d9abffc48Bjorn Helgaas if (acpi_mcfg_check_entry(mcfg, cfg)) { 5987da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas free_all_mmcfg(); 599c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown return -ENODEV; 600c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown } 6017da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas 6027da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number, 6037da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas cfg->end_bus_number, cfg->address) == NULL) { 60424c97f04c4570e02c5cf4b97c73ab9dc27bacdbeJiang Liu pr_warn(PREFIX "no memory for MCFG entries\n"); 6057da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas free_all_mmcfg(); 6067da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas return -ENOMEM; 6077da7d360ae025158d09aab18d66f5d2fe3c02252Bjorn Helgaas } 608c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown } 609c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown 610c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown return 0; 611c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown} 612c4bf2f372db09ef8d16a25a60d523bfa1c50f7b5Len Brown 613968cbfad1a727b5689ae620f4d970abf6ce73340Thomas Gleixnerstatic void __init __pci_mmcfg_init(int early) 614b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert{ 615068258bc15439c11a966e873f931cc8e513dca61Yinghai Lu pci_mmcfg_reject_broken(early); 616ff097ddd4aeac790fd51d013c79c2f18ec9a7117Bjorn Helgaas if (list_empty(&pci_mmcfg_list)) 617b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert return; 618b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert 619a3170c1f924ce2565c4e160b9b095e65c03b2dc6Jan Beulich if (pcibios_last_bus < 0) { 620a3170c1f924ce2565c4e160b9b095e65c03b2dc6Jan Beulich const struct pci_mmcfg_region *cfg; 621a3170c1f924ce2565c4e160b9b095e65c03b2dc6Jan Beulich 622a3170c1f924ce2565c4e160b9b095e65c03b2dc6Jan Beulich list_for_each_entry(cfg, &pci_mmcfg_list, list) { 623a3170c1f924ce2565c4e160b9b095e65c03b2dc6Jan Beulich if (cfg->segment) 624a3170c1f924ce2565c4e160b9b095e65c03b2dc6Jan Beulich break; 625a3170c1f924ce2565c4e160b9b095e65c03b2dc6Jan Beulich pcibios_last_bus = cfg->end_bus; 626a3170c1f924ce2565c4e160b9b095e65c03b2dc6Jan Beulich } 627a3170c1f924ce2565c4e160b9b095e65c03b2dc6Jan Beulich } 628a3170c1f924ce2565c4e160b9b095e65c03b2dc6Jan Beulich 629ebd60cd64f8ab1170102c3ab072eb73042b7a33dYinghai Lu if (pci_mmcfg_arch_init()) 630b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; 631ebd60cd64f8ab1170102c3ab072eb73042b7a33dYinghai Lu else { 63266e8850a2a34e6c52105d92a0f0054b304cb7140Jiang Liu free_all_mmcfg(); 6339c95111b330d2ddf851444528a7608f267cbb50cJiang Liu pci_mmcfg_arch_init_failed = true; 634b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert } 635b78673944b22b662b270c8bba5c198f19e4ee4e1Olivier Galibert} 636a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin 637574a59414083df3911e5a1514742959b412b6947Jiang Liustatic int __initdata known_bridge; 638574a59414083df3911e5a1514742959b412b6947Jiang Liu 639bb63b4219976d48ed6d22ac33c18be334fb5a78cYinghai Luvoid __init pci_mmcfg_early_init(void) 64005c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu{ 641574a59414083df3911e5a1514742959b412b6947Jiang Liu if (pci_probe & PCI_PROBE_MMCONF) { 642574a59414083df3911e5a1514742959b412b6947Jiang Liu if (pci_mmcfg_check_hostbridge()) 643574a59414083df3911e5a1514742959b412b6947Jiang Liu known_bridge = 1; 644574a59414083df3911e5a1514742959b412b6947Jiang Liu else 645574a59414083df3911e5a1514742959b412b6947Jiang Liu acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg); 646574a59414083df3911e5a1514742959b412b6947Jiang Liu __pci_mmcfg_init(1); 647574a59414083df3911e5a1514742959b412b6947Jiang Liu } 64805c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu} 64905c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu 65005c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Luvoid __init pci_mmcfg_late_init(void) 65105c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu{ 652574a59414083df3911e5a1514742959b412b6947Jiang Liu /* MMCONFIG disabled */ 653574a59414083df3911e5a1514742959b412b6947Jiang Liu if ((pci_probe & PCI_PROBE_MMCONF) == 0) 654574a59414083df3911e5a1514742959b412b6947Jiang Liu return; 655574a59414083df3911e5a1514742959b412b6947Jiang Liu 656574a59414083df3911e5a1514742959b412b6947Jiang Liu if (known_bridge) 657574a59414083df3911e5a1514742959b412b6947Jiang Liu return; 658574a59414083df3911e5a1514742959b412b6947Jiang Liu 659574a59414083df3911e5a1514742959b412b6947Jiang Liu /* MMCONFIG hasn't been enabled yet, try again */ 660574a59414083df3911e5a1514742959b412b6947Jiang Liu if (pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF) { 661574a59414083df3911e5a1514742959b412b6947Jiang Liu acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg); 662574a59414083df3911e5a1514742959b412b6947Jiang Liu __pci_mmcfg_init(0); 663574a59414083df3911e5a1514742959b412b6947Jiang Liu } 66405c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu} 66505c58b8ac77639c17205f0b2a2d9eb1971dc47adYinghai Lu 666a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbinstatic int __init pci_mmcfg_late_insert_resources(void) 667a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin{ 66866e8850a2a34e6c52105d92a0f0054b304cb7140Jiang Liu struct pci_mmcfg_region *cfg; 66966e8850a2a34e6c52105d92a0f0054b304cb7140Jiang Liu 67095c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu pci_mmcfg_running_state = true; 67195c5e92f4f691bbaba40bbf3decfc8e13b6ea897Jiang Liu 67266e8850a2a34e6c52105d92a0f0054b304cb7140Jiang Liu /* If we are not using MMCONFIG, don't insert the resources. */ 67366e8850a2a34e6c52105d92a0f0054b304cb7140Jiang Liu if ((pci_probe & PCI_PROBE_MMCONF) == 0) 674a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin return 1; 675a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin 676a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin /* 677a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin * Attempt to insert the mmcfg resources but not with the busy flag 678a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin * marked so it won't cause request errors when __request_region is 679a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin * called. 680a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin */ 68166e8850a2a34e6c52105d92a0f0054b304cb7140Jiang Liu list_for_each_entry(cfg, &pci_mmcfg_list, list) 68266e8850a2a34e6c52105d92a0f0054b304cb7140Jiang Liu if (!cfg->res.parent) 68366e8850a2a34e6c52105d92a0f0054b304cb7140Jiang Liu insert_resource(&iomem_resource, &cfg->res); 684a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin 685a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin return 0; 686a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin} 687a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin 688a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin/* 689a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin * Perform MMCONFIG resource insertion after PCI initialization to allow for 690a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin * misprogrammed MCFG tables that state larger sizes but actually conflict 691a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin * with other system resources. 692a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbin */ 693a5ba7971045a90a36cef8f7d5a3075600b475b74Aaron Durbinlate_initcall(pci_mmcfg_late_insert_resources); 6949c95111b330d2ddf851444528a7608f267cbb50cJiang Liu 6959c95111b330d2ddf851444528a7608f267cbb50cJiang Liu/* Add MMCFG information for host bridges */ 696a18e3690a52790a034d6540d54e8e1f1cd125da2Greg Kroah-Hartmanint pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end, 697a18e3690a52790a034d6540d54e8e1f1cd125da2Greg Kroah-Hartman phys_addr_t addr) 6989c95111b330d2ddf851444528a7608f267cbb50cJiang Liu{ 6999c95111b330d2ddf851444528a7608f267cbb50cJiang Liu int rc; 7009c95111b330d2ddf851444528a7608f267cbb50cJiang Liu struct resource *tmp = NULL; 7019c95111b330d2ddf851444528a7608f267cbb50cJiang Liu struct pci_mmcfg_region *cfg; 7029c95111b330d2ddf851444528a7608f267cbb50cJiang Liu 7039c95111b330d2ddf851444528a7608f267cbb50cJiang Liu if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed) 7049c95111b330d2ddf851444528a7608f267cbb50cJiang Liu return -ENODEV; 7059c95111b330d2ddf851444528a7608f267cbb50cJiang Liu 70667d470e0e1711ca4a4c3a0e5524e0d580654053eBjorn Helgaas if (start > end) 7079c95111b330d2ddf851444528a7608f267cbb50cJiang Liu return -EINVAL; 7089c95111b330d2ddf851444528a7608f267cbb50cJiang Liu 7099c95111b330d2ddf851444528a7608f267cbb50cJiang Liu mutex_lock(&pci_mmcfg_lock); 7109c95111b330d2ddf851444528a7608f267cbb50cJiang Liu cfg = pci_mmconfig_lookup(seg, start); 7119c95111b330d2ddf851444528a7608f267cbb50cJiang Liu if (cfg) { 7129c95111b330d2ddf851444528a7608f267cbb50cJiang Liu if (cfg->end_bus < end) 7139c95111b330d2ddf851444528a7608f267cbb50cJiang Liu dev_info(dev, FW_INFO 7149c95111b330d2ddf851444528a7608f267cbb50cJiang Liu "MMCONFIG for " 7159c95111b330d2ddf851444528a7608f267cbb50cJiang Liu "domain %04x [bus %02x-%02x] " 7169c95111b330d2ddf851444528a7608f267cbb50cJiang Liu "only partially covers this bridge\n", 7179c95111b330d2ddf851444528a7608f267cbb50cJiang Liu cfg->segment, cfg->start_bus, cfg->end_bus); 7189c95111b330d2ddf851444528a7608f267cbb50cJiang Liu mutex_unlock(&pci_mmcfg_lock); 7199c95111b330d2ddf851444528a7608f267cbb50cJiang Liu return -EEXIST; 7209c95111b330d2ddf851444528a7608f267cbb50cJiang Liu } 7219c95111b330d2ddf851444528a7608f267cbb50cJiang Liu 72267d470e0e1711ca4a4c3a0e5524e0d580654053eBjorn Helgaas if (!addr) { 72367d470e0e1711ca4a4c3a0e5524e0d580654053eBjorn Helgaas mutex_unlock(&pci_mmcfg_lock); 72467d470e0e1711ca4a4c3a0e5524e0d580654053eBjorn Helgaas return -EINVAL; 72567d470e0e1711ca4a4c3a0e5524e0d580654053eBjorn Helgaas } 72667d470e0e1711ca4a4c3a0e5524e0d580654053eBjorn Helgaas 7279c95111b330d2ddf851444528a7608f267cbb50cJiang Liu rc = -EBUSY; 7289c95111b330d2ddf851444528a7608f267cbb50cJiang Liu cfg = pci_mmconfig_alloc(seg, start, end, addr); 7299c95111b330d2ddf851444528a7608f267cbb50cJiang Liu if (cfg == NULL) { 7309c95111b330d2ddf851444528a7608f267cbb50cJiang Liu dev_warn(dev, "fail to add MMCONFIG (out of memory)\n"); 7319c95111b330d2ddf851444528a7608f267cbb50cJiang Liu rc = -ENOMEM; 7329c95111b330d2ddf851444528a7608f267cbb50cJiang Liu } else if (!pci_mmcfg_check_reserved(dev, cfg, 0)) { 7339c95111b330d2ddf851444528a7608f267cbb50cJiang Liu dev_warn(dev, FW_BUG "MMCONFIG %pR isn't reserved\n", 7349c95111b330d2ddf851444528a7608f267cbb50cJiang Liu &cfg->res); 7359c95111b330d2ddf851444528a7608f267cbb50cJiang Liu } else { 7369c95111b330d2ddf851444528a7608f267cbb50cJiang Liu /* Insert resource if it's not in boot stage */ 7379c95111b330d2ddf851444528a7608f267cbb50cJiang Liu if (pci_mmcfg_running_state) 7389c95111b330d2ddf851444528a7608f267cbb50cJiang Liu tmp = insert_resource_conflict(&iomem_resource, 7399c95111b330d2ddf851444528a7608f267cbb50cJiang Liu &cfg->res); 7409c95111b330d2ddf851444528a7608f267cbb50cJiang Liu 7419c95111b330d2ddf851444528a7608f267cbb50cJiang Liu if (tmp) { 7429c95111b330d2ddf851444528a7608f267cbb50cJiang Liu dev_warn(dev, 7439c95111b330d2ddf851444528a7608f267cbb50cJiang Liu "MMCONFIG %pR conflicts with " 7449c95111b330d2ddf851444528a7608f267cbb50cJiang Liu "%s %pR\n", 7459c95111b330d2ddf851444528a7608f267cbb50cJiang Liu &cfg->res, tmp->name, tmp); 7469c95111b330d2ddf851444528a7608f267cbb50cJiang Liu } else if (pci_mmcfg_arch_map(cfg)) { 7479c95111b330d2ddf851444528a7608f267cbb50cJiang Liu dev_warn(dev, "fail to map MMCONFIG %pR.\n", 7489c95111b330d2ddf851444528a7608f267cbb50cJiang Liu &cfg->res); 7499c95111b330d2ddf851444528a7608f267cbb50cJiang Liu } else { 7509c95111b330d2ddf851444528a7608f267cbb50cJiang Liu list_add_sorted(cfg); 7519c95111b330d2ddf851444528a7608f267cbb50cJiang Liu dev_info(dev, "MMCONFIG at %pR (base %#lx)\n", 7529c95111b330d2ddf851444528a7608f267cbb50cJiang Liu &cfg->res, (unsigned long)addr); 7539c95111b330d2ddf851444528a7608f267cbb50cJiang Liu cfg = NULL; 7549c95111b330d2ddf851444528a7608f267cbb50cJiang Liu rc = 0; 7559c95111b330d2ddf851444528a7608f267cbb50cJiang Liu } 7569c95111b330d2ddf851444528a7608f267cbb50cJiang Liu } 7579c95111b330d2ddf851444528a7608f267cbb50cJiang Liu 7589c95111b330d2ddf851444528a7608f267cbb50cJiang Liu if (cfg) { 7599c95111b330d2ddf851444528a7608f267cbb50cJiang Liu if (cfg->res.parent) 7609c95111b330d2ddf851444528a7608f267cbb50cJiang Liu release_resource(&cfg->res); 7619c95111b330d2ddf851444528a7608f267cbb50cJiang Liu kfree(cfg); 7629c95111b330d2ddf851444528a7608f267cbb50cJiang Liu } 7639c95111b330d2ddf851444528a7608f267cbb50cJiang Liu 7649c95111b330d2ddf851444528a7608f267cbb50cJiang Liu mutex_unlock(&pci_mmcfg_lock); 7659c95111b330d2ddf851444528a7608f267cbb50cJiang Liu 7669c95111b330d2ddf851444528a7608f267cbb50cJiang Liu return rc; 7679c95111b330d2ddf851444528a7608f267cbb50cJiang Liu} 7689c95111b330d2ddf851444528a7608f267cbb50cJiang Liu 7699c95111b330d2ddf851444528a7608f267cbb50cJiang Liu/* Delete MMCFG information for host bridges */ 7709c95111b330d2ddf851444528a7608f267cbb50cJiang Liuint pci_mmconfig_delete(u16 seg, u8 start, u8 end) 7719c95111b330d2ddf851444528a7608f267cbb50cJiang Liu{ 7729c95111b330d2ddf851444528a7608f267cbb50cJiang Liu struct pci_mmcfg_region *cfg; 7739c95111b330d2ddf851444528a7608f267cbb50cJiang Liu 7749c95111b330d2ddf851444528a7608f267cbb50cJiang Liu mutex_lock(&pci_mmcfg_lock); 7759c95111b330d2ddf851444528a7608f267cbb50cJiang Liu list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) 7769c95111b330d2ddf851444528a7608f267cbb50cJiang Liu if (cfg->segment == seg && cfg->start_bus == start && 7779c95111b330d2ddf851444528a7608f267cbb50cJiang Liu cfg->end_bus == end) { 7789c95111b330d2ddf851444528a7608f267cbb50cJiang Liu list_del_rcu(&cfg->list); 7799c95111b330d2ddf851444528a7608f267cbb50cJiang Liu synchronize_rcu(); 7809c95111b330d2ddf851444528a7608f267cbb50cJiang Liu pci_mmcfg_arch_unmap(cfg); 7819c95111b330d2ddf851444528a7608f267cbb50cJiang Liu if (cfg->res.parent) 7829c95111b330d2ddf851444528a7608f267cbb50cJiang Liu release_resource(&cfg->res); 7839c95111b330d2ddf851444528a7608f267cbb50cJiang Liu mutex_unlock(&pci_mmcfg_lock); 7849c95111b330d2ddf851444528a7608f267cbb50cJiang Liu kfree(cfg); 7859c95111b330d2ddf851444528a7608f267cbb50cJiang Liu return 0; 7869c95111b330d2ddf851444528a7608f267cbb50cJiang Liu } 7879c95111b330d2ddf851444528a7608f267cbb50cJiang Liu mutex_unlock(&pci_mmcfg_lock); 7889c95111b330d2ddf851444528a7608f267cbb50cJiang Liu 7899c95111b330d2ddf851444528a7608f267cbb50cJiang Liu return -ENOENT; 7909c95111b330d2ddf851444528a7608f267cbb50cJiang Liu} 791