2 * mmconfig-shared.c - Low-level direct PCI config space access via
3 * MMCONFIG - common code between i386 and x86-64.
6 * - known chipset handling
7 * - ACPI decoding and validation
9 * Per-architecture code takes care of the mappings and accesses
13 #include <linux/pci.h>
14 #include <linux/init.h>
15 #include <linux/acpi.h>
16 #include <linux/bitmap.h>
21 /* aperture is up to 256MB but BIOS may reserve less */
22 #define MMCONFIG_APER_MIN (2 * 1024*1024)
23 #define MMCONFIG_APER_MAX (256 * 1024*1024)
25 DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS);
27 /* K8 systems have some devices (typically in the builtin northbridge)
28 that are only accessible using type1
29 Normally this can be expressed in the MCFG by not listing them
30 and assigning suitable _SEGs, but this isn't implemented in some BIOS.
31 Instead try to discover all devices on bus 0 that are unreachable using MM
32 and fallback for them. */
33 static void __init unreachable_devices(void)
36 /* Use the max bus number from ACPI here? */
37 for (bus = 0; bus < PCI_MMCFG_MAX_CHECK_BUS; bus++) {
38 for (i = 0; i < 32; i++) {
39 unsigned int devfn = PCI_DEVFN(i, 0);
42 pci_conf1_read(0, bus, devfn, 0, 4, &val1);
43 if (val1 == 0xffffffff)
46 if (pci_mmcfg_arch_reachable(0, bus, devfn)) {
47 raw_pci_ops->read(0, bus, devfn, 0, 4, &val2);
51 set_bit(i + 32 * bus, pci_mmcfg_fallback_slots);
52 printk(KERN_NOTICE "PCI: No mmconfig possible on device"
53 " %02x:%02x\n", bus, i);
58 static const char __init *pci_mmcfg_e7520(void)
61 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win);
64 if(win == 0x0000 || win == 0xf000)
65 pci_mmcfg_config_num = 0;
67 pci_mmcfg_config_num = 1;
68 pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
69 if (!pci_mmcfg_config)
71 pci_mmcfg_config[0].address = win << 16;
72 pci_mmcfg_config[0].pci_segment = 0;
73 pci_mmcfg_config[0].start_bus_number = 0;
74 pci_mmcfg_config[0].end_bus_number = 255;
77 return "Intel Corporation E7520 Memory Controller Hub";
80 static const char __init *pci_mmcfg_intel_945(void)
82 u32 pciexbar, mask = 0, len = 0;
84 pci_mmcfg_config_num = 1;
86 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar);
90 pci_mmcfg_config_num = 0;
93 switch ((pciexbar >> 1) & 3) {
107 pci_mmcfg_config_num = 0;
110 /* Errata #2, things break when not aligned on a 256Mb boundary */
111 /* Can only happen in 64M/128M mode */
113 if ((pciexbar & mask) & 0x0fffffffU)
114 pci_mmcfg_config_num = 0;
116 /* Don't hit the APIC registers and their friends */
117 if ((pciexbar & mask) >= 0xf0000000U)
118 pci_mmcfg_config_num = 0;
120 if (pci_mmcfg_config_num) {
121 pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
122 if (!pci_mmcfg_config)
124 pci_mmcfg_config[0].address = pciexbar & mask;
125 pci_mmcfg_config[0].pci_segment = 0;
126 pci_mmcfg_config[0].start_bus_number = 0;
127 pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
130 return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
133 struct pci_mmcfg_hostbridge_probe {
136 const char *(*probe)(void);
139 static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
140 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
141 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
144 static int __init pci_mmcfg_check_hostbridge(void)
151 pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0, 4, &l);
153 device = (l >> 16) & 0xffff;
155 pci_mmcfg_config_num = 0;
156 pci_mmcfg_config = NULL;
159 for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
160 if (pci_mmcfg_probes[i].vendor == vendor &&
161 pci_mmcfg_probes[i].device == device)
162 name = pci_mmcfg_probes[i].probe();
166 printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n",
167 name, pci_mmcfg_config_num ? "with" : "without");
173 static void __init pci_mmcfg_insert_resources(void)
175 #define PCI_MMCFG_RESOURCE_NAME_LEN 19
177 struct resource *res;
181 res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res),
182 pci_mmcfg_config_num, GFP_KERNEL);
184 printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n");
188 names = (void *)&res[pci_mmcfg_config_num];
189 for (i = 0; i < pci_mmcfg_config_num; i++, res++) {
190 struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i];
191 num_buses = cfg->end_bus_number - cfg->start_bus_number + 1;
193 snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u",
195 res->start = cfg->address;
196 res->end = res->start + (num_buses << 20) - 1;
197 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
198 insert_resource(&iomem_resource, res);
199 names += PCI_MMCFG_RESOURCE_NAME_LEN;
203 static void __init pci_mmcfg_reject_broken(int type)
205 typeof(pci_mmcfg_config[0]) *cfg;
207 if ((pci_mmcfg_config_num == 0) ||
208 (pci_mmcfg_config == NULL) ||
209 (pci_mmcfg_config[0].address == 0))
212 cfg = &pci_mmcfg_config[0];
215 * Handle more broken MCFG tables on Asus etc.
216 * They only contain a single entry for bus 0-0.
218 if (pci_mmcfg_config_num == 1 &&
219 cfg->pci_segment == 0 &&
220 (cfg->start_bus_number | cfg->end_bus_number) == 0) {
221 printk(KERN_ERR "PCI: start and end of bus number is 0. "
222 "Rejected as broken MCFG.\n");
227 * Only do this check when type 1 works. If it doesn't work
228 * assume we run on a Mac and always use MCFG
230 if (type == 1 && !e820_all_mapped(cfg->address,
231 cfg->address + MMCONFIG_APER_MIN,
233 printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not"
234 " E820-reserved\n", cfg->address);
240 printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
241 kfree(pci_mmcfg_config);
242 pci_mmcfg_config = NULL;
243 pci_mmcfg_config_num = 0;
246 void __init pci_mmcfg_init(int type)
248 int known_bridge = 0;
250 if ((pci_probe & PCI_PROBE_MMCONF) == 0)
253 if (type == 1 && pci_mmcfg_check_hostbridge())
257 acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
258 pci_mmcfg_reject_broken(type);
261 if ((pci_mmcfg_config_num == 0) ||
262 (pci_mmcfg_config == NULL) ||
263 (pci_mmcfg_config[0].address == 0))
266 if (pci_mmcfg_arch_init()) {
268 unreachable_devices();
270 pci_mmcfg_insert_resources();
271 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;