diff options
Diffstat (limited to 'arch/x86/pci/mmconfig-shared.c')
-rw-r--r-- | arch/x86/pci/mmconfig-shared.c | 356 |
1 files changed, 171 insertions, 185 deletions
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 602c172d3bd5..39b9ebe8f886 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c | |||
@@ -15,48 +15,99 @@ | |||
15 | #include <linux/acpi.h> | 15 | #include <linux/acpi.h> |
16 | #include <linux/sfi_acpi.h> | 16 | #include <linux/sfi_acpi.h> |
17 | #include <linux/bitmap.h> | 17 | #include <linux/bitmap.h> |
18 | #include <linux/sort.h> | 18 | #include <linux/dmi.h> |
19 | #include <linux/slab.h> | ||
19 | #include <asm/e820.h> | 20 | #include <asm/e820.h> |
20 | #include <asm/pci_x86.h> | 21 | #include <asm/pci_x86.h> |
21 | #include <asm/acpi.h> | 22 | #include <asm/acpi.h> |
22 | 23 | ||
23 | #define PREFIX "PCI: " | 24 | #define PREFIX "PCI: " |
24 | 25 | ||
25 | /* aperture is up to 256MB but BIOS may reserve less */ | ||
26 | #define MMCONFIG_APER_MIN (2 * 1024*1024) | ||
27 | #define MMCONFIG_APER_MAX (256 * 1024*1024) | ||
28 | |||
29 | /* Indicate if the mmcfg resources have been placed into the resource table. */ | 26 | /* Indicate if the mmcfg resources have been placed into the resource table. */ |
30 | static int __initdata pci_mmcfg_resources_inserted; | 27 | static int __initdata pci_mmcfg_resources_inserted; |
31 | 28 | ||
32 | static __init int extend_mmcfg(int num) | 29 | LIST_HEAD(pci_mmcfg_list); |
30 | |||
31 | static __init void pci_mmconfig_remove(struct pci_mmcfg_region *cfg) | ||
33 | { | 32 | { |
34 | struct acpi_mcfg_allocation *new; | 33 | if (cfg->res.parent) |
35 | int new_num = pci_mmcfg_config_num + num; | 34 | release_resource(&cfg->res); |
35 | list_del(&cfg->list); | ||
36 | kfree(cfg); | ||
37 | } | ||
36 | 38 | ||
37 | new = kzalloc(sizeof(pci_mmcfg_config[0]) * new_num, GFP_KERNEL); | 39 | static __init void free_all_mmcfg(void) |
38 | if (!new) | 40 | { |
39 | return -1; | 41 | struct pci_mmcfg_region *cfg, *tmp; |
42 | |||
43 | pci_mmcfg_arch_free(); | ||
44 | list_for_each_entry_safe(cfg, tmp, &pci_mmcfg_list, list) | ||
45 | pci_mmconfig_remove(cfg); | ||
46 | } | ||
40 | 47 | ||
41 | if (pci_mmcfg_config) { | 48 | static __init void list_add_sorted(struct pci_mmcfg_region *new) |
42 | memcpy(new, pci_mmcfg_config, | 49 | { |
43 | sizeof(pci_mmcfg_config[0]) * new_num); | 50 | struct pci_mmcfg_region *cfg; |
44 | kfree(pci_mmcfg_config); | 51 | |
52 | /* keep list sorted by segment and starting bus number */ | ||
53 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { | ||
54 | if (cfg->segment > new->segment || | ||
55 | (cfg->segment == new->segment && | ||
56 | cfg->start_bus >= new->start_bus)) { | ||
57 | list_add_tail(&new->list, &cfg->list); | ||
58 | return; | ||
59 | } | ||
45 | } | 60 | } |
46 | pci_mmcfg_config = new; | 61 | list_add_tail(&new->list, &pci_mmcfg_list); |
62 | } | ||
47 | 63 | ||
48 | return 0; | 64 | static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start, |
65 | int end, u64 addr) | ||
66 | { | ||
67 | struct pci_mmcfg_region *new; | ||
68 | int num_buses; | ||
69 | struct resource *res; | ||
70 | |||
71 | if (addr == 0) | ||
72 | return NULL; | ||
73 | |||
74 | new = kzalloc(sizeof(*new), GFP_KERNEL); | ||
75 | if (!new) | ||
76 | return NULL; | ||
77 | |||
78 | new->address = addr; | ||
79 | new->segment = segment; | ||
80 | new->start_bus = start; | ||
81 | new->end_bus = end; | ||
82 | |||
83 | list_add_sorted(new); | ||
84 | |||
85 | num_buses = end - start + 1; | ||
86 | res = &new->res; | ||
87 | res->start = addr + PCI_MMCFG_BUS_OFFSET(start); | ||
88 | res->end = addr + PCI_MMCFG_BUS_OFFSET(num_buses) - 1; | ||
89 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
90 | snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN, | ||
91 | "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end); | ||
92 | res->name = new->name; | ||
93 | |||
94 | printk(KERN_INFO PREFIX "MMCONFIG for domain %04x [bus %02x-%02x] at " | ||
95 | "%pR (base %#lx)\n", segment, start, end, &new->res, | ||
96 | (unsigned long) addr); | ||
97 | |||
98 | return new; | ||
49 | } | 99 | } |
50 | 100 | ||
51 | static __init void fill_one_mmcfg(u64 addr, int segment, int start, int end) | 101 | struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus) |
52 | { | 102 | { |
53 | int i = pci_mmcfg_config_num; | 103 | struct pci_mmcfg_region *cfg; |
54 | 104 | ||
55 | pci_mmcfg_config_num++; | 105 | list_for_each_entry(cfg, &pci_mmcfg_list, list) |
56 | pci_mmcfg_config[i].address = addr; | 106 | if (cfg->segment == segment && |
57 | pci_mmcfg_config[i].pci_segment = segment; | 107 | cfg->start_bus <= bus && bus <= cfg->end_bus) |
58 | pci_mmcfg_config[i].start_bus_number = start; | 108 | return cfg; |
59 | pci_mmcfg_config[i].end_bus_number = end; | 109 | |
110 | return NULL; | ||
60 | } | 111 | } |
61 | 112 | ||
62 | static const char __init *pci_mmcfg_e7520(void) | 113 | static const char __init *pci_mmcfg_e7520(void) |
@@ -68,11 +119,9 @@ static const char __init *pci_mmcfg_e7520(void) | |||
68 | if (win == 0x0000 || win == 0xf000) | 119 | if (win == 0x0000 || win == 0xf000) |
69 | return NULL; | 120 | return NULL; |
70 | 121 | ||
71 | if (extend_mmcfg(1) == -1) | 122 | if (pci_mmconfig_add(0, 0, 255, win << 16) == NULL) |
72 | return NULL; | 123 | return NULL; |
73 | 124 | ||
74 | fill_one_mmcfg(win << 16, 0, 0, 255); | ||
75 | |||
76 | return "Intel Corporation E7520 Memory Controller Hub"; | 125 | return "Intel Corporation E7520 Memory Controller Hub"; |
77 | } | 126 | } |
78 | 127 | ||
@@ -114,11 +163,9 @@ static const char __init *pci_mmcfg_intel_945(void) | |||
114 | if ((pciexbar & mask) >= 0xf0000000U) | 163 | if ((pciexbar & mask) >= 0xf0000000U) |
115 | return NULL; | 164 | return NULL; |
116 | 165 | ||
117 | if (extend_mmcfg(1) == -1) | 166 | if (pci_mmconfig_add(0, 0, (len >> 20) - 1, pciexbar & mask) == NULL) |
118 | return NULL; | 167 | return NULL; |
119 | 168 | ||
120 | fill_one_mmcfg(pciexbar & mask, 0, 0, (len >> 20) - 1); | ||
121 | |||
122 | return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; | 169 | return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; |
123 | } | 170 | } |
124 | 171 | ||
@@ -127,7 +174,7 @@ static const char __init *pci_mmcfg_amd_fam10h(void) | |||
127 | u32 low, high, address; | 174 | u32 low, high, address; |
128 | u64 base, msr; | 175 | u64 base, msr; |
129 | int i; | 176 | int i; |
130 | unsigned segnbits = 0, busnbits; | 177 | unsigned segnbits = 0, busnbits, end_bus; |
131 | 178 | ||
132 | if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF)) | 179 | if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF)) |
133 | return NULL; | 180 | return NULL; |
@@ -161,11 +208,13 @@ static const char __init *pci_mmcfg_amd_fam10h(void) | |||
161 | busnbits = 8; | 208 | busnbits = 8; |
162 | } | 209 | } |
163 | 210 | ||
164 | if (extend_mmcfg(1 << segnbits) == -1) | 211 | end_bus = (1 << busnbits) - 1; |
165 | return NULL; | ||
166 | |||
167 | for (i = 0; i < (1 << segnbits); i++) | 212 | for (i = 0; i < (1 << segnbits); i++) |
168 | fill_one_mmcfg(base + (1<<28) * i, i, 0, (1 << busnbits) - 1); | 213 | if (pci_mmconfig_add(i, 0, end_bus, |
214 | base + (1<<28) * i) == NULL) { | ||
215 | free_all_mmcfg(); | ||
216 | return NULL; | ||
217 | } | ||
169 | 218 | ||
170 | return "AMD Family 10h NB"; | 219 | return "AMD Family 10h NB"; |
171 | } | 220 | } |
@@ -190,7 +239,7 @@ static const char __init *pci_mmcfg_nvidia_mcp55(void) | |||
190 | /* | 239 | /* |
191 | * do check if amd fam10h already took over | 240 | * do check if amd fam10h already took over |
192 | */ | 241 | */ |
193 | if (!acpi_disabled || pci_mmcfg_config_num || mcp55_checked) | 242 | if (!acpi_disabled || !list_empty(&pci_mmcfg_list) || mcp55_checked) |
194 | return NULL; | 243 | return NULL; |
195 | 244 | ||
196 | mcp55_checked = true; | 245 | mcp55_checked = true; |
@@ -213,16 +262,14 @@ static const char __init *pci_mmcfg_nvidia_mcp55(void) | |||
213 | if (!(extcfg & extcfg_enable_mask)) | 262 | if (!(extcfg & extcfg_enable_mask)) |
214 | continue; | 263 | continue; |
215 | 264 | ||
216 | if (extend_mmcfg(1) == -1) | ||
217 | continue; | ||
218 | |||
219 | size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift; | 265 | size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift; |
220 | base = extcfg & extcfg_base_mask[size_index]; | 266 | base = extcfg & extcfg_base_mask[size_index]; |
221 | /* base could > 4G */ | 267 | /* base could > 4G */ |
222 | base <<= extcfg_base_lshift; | 268 | base <<= extcfg_base_lshift; |
223 | start = (extcfg & extcfg_start_mask) >> extcfg_start_shift; | 269 | start = (extcfg & extcfg_start_mask) >> extcfg_start_shift; |
224 | end = start + extcfg_sizebus[size_index] - 1; | 270 | end = start + extcfg_sizebus[size_index] - 1; |
225 | fill_one_mmcfg(base, 0, start, end); | 271 | if (pci_mmconfig_add(0, start, end, base) == NULL) |
272 | continue; | ||
226 | mcp55_mmconf_found++; | 273 | mcp55_mmconf_found++; |
227 | } | 274 | } |
228 | 275 | ||
@@ -253,45 +300,22 @@ static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { | |||
253 | 0x0369, pci_mmcfg_nvidia_mcp55 }, | 300 | 0x0369, pci_mmcfg_nvidia_mcp55 }, |
254 | }; | 301 | }; |
255 | 302 | ||
256 | static int __init cmp_mmcfg(const void *x1, const void *x2) | ||
257 | { | ||
258 | const typeof(pci_mmcfg_config[0]) *m1 = x1; | ||
259 | const typeof(pci_mmcfg_config[0]) *m2 = x2; | ||
260 | int start1, start2; | ||
261 | |||
262 | start1 = m1->start_bus_number; | ||
263 | start2 = m2->start_bus_number; | ||
264 | |||
265 | return start1 - start2; | ||
266 | } | ||
267 | |||
268 | static void __init pci_mmcfg_check_end_bus_number(void) | 303 | static void __init pci_mmcfg_check_end_bus_number(void) |
269 | { | 304 | { |
270 | int i; | 305 | struct pci_mmcfg_region *cfg, *cfgx; |
271 | typeof(pci_mmcfg_config[0]) *cfg, *cfgx; | ||
272 | |||
273 | /* sort them at first */ | ||
274 | sort(pci_mmcfg_config, pci_mmcfg_config_num, | ||
275 | sizeof(pci_mmcfg_config[0]), cmp_mmcfg, NULL); | ||
276 | |||
277 | /* last one*/ | ||
278 | if (pci_mmcfg_config_num > 0) { | ||
279 | i = pci_mmcfg_config_num - 1; | ||
280 | cfg = &pci_mmcfg_config[i]; | ||
281 | if (cfg->end_bus_number < cfg->start_bus_number) | ||
282 | cfg->end_bus_number = 255; | ||
283 | } | ||
284 | 306 | ||
285 | /* don't overlap please */ | 307 | /* Fixup overlaps */ |
286 | for (i = 0; i < pci_mmcfg_config_num - 1; i++) { | 308 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { |
287 | cfg = &pci_mmcfg_config[i]; | 309 | if (cfg->end_bus < cfg->start_bus) |
288 | cfgx = &pci_mmcfg_config[i+1]; | 310 | cfg->end_bus = 255; |
289 | 311 | ||
290 | if (cfg->end_bus_number < cfg->start_bus_number) | 312 | /* Don't access the list head ! */ |
291 | cfg->end_bus_number = 255; | 313 | if (cfg->list.next == &pci_mmcfg_list) |
314 | break; | ||
292 | 315 | ||
293 | if (cfg->end_bus_number >= cfgx->start_bus_number) | 316 | cfgx = list_entry(cfg->list.next, typeof(*cfg), list); |
294 | cfg->end_bus_number = cfgx->start_bus_number - 1; | 317 | if (cfg->end_bus >= cfgx->start_bus) |
318 | cfg->end_bus = cfgx->start_bus - 1; | ||
295 | } | 319 | } |
296 | } | 320 | } |
297 | 321 | ||
@@ -306,8 +330,7 @@ static int __init pci_mmcfg_check_hostbridge(void) | |||
306 | if (!raw_pci_ops) | 330 | if (!raw_pci_ops) |
307 | return 0; | 331 | return 0; |
308 | 332 | ||
309 | pci_mmcfg_config_num = 0; | 333 | free_all_mmcfg(); |
310 | pci_mmcfg_config = NULL; | ||
311 | 334 | ||
312 | for (i = 0; i < ARRAY_SIZE(pci_mmcfg_probes); i++) { | 335 | for (i = 0; i < ARRAY_SIZE(pci_mmcfg_probes); i++) { |
313 | bus = pci_mmcfg_probes[i].bus; | 336 | bus = pci_mmcfg_probes[i].bus; |
@@ -322,45 +345,22 @@ static int __init pci_mmcfg_check_hostbridge(void) | |||
322 | name = pci_mmcfg_probes[i].probe(); | 345 | name = pci_mmcfg_probes[i].probe(); |
323 | 346 | ||
324 | if (name) | 347 | if (name) |
325 | printk(KERN_INFO "PCI: Found %s with MMCONFIG support.\n", | 348 | printk(KERN_INFO PREFIX "%s with MMCONFIG support\n", |
326 | name); | 349 | name); |
327 | } | 350 | } |
328 | 351 | ||
329 | /* some end_bus_number is crazy, fix it */ | 352 | /* some end_bus_number is crazy, fix it */ |
330 | pci_mmcfg_check_end_bus_number(); | 353 | pci_mmcfg_check_end_bus_number(); |
331 | 354 | ||
332 | return pci_mmcfg_config_num != 0; | 355 | return !list_empty(&pci_mmcfg_list); |
333 | } | 356 | } |
334 | 357 | ||
335 | static void __init pci_mmcfg_insert_resources(void) | 358 | static void __init pci_mmcfg_insert_resources(void) |
336 | { | 359 | { |
337 | #define PCI_MMCFG_RESOURCE_NAME_LEN 24 | 360 | struct pci_mmcfg_region *cfg; |
338 | int i; | ||
339 | struct resource *res; | ||
340 | char *names; | ||
341 | unsigned num_buses; | ||
342 | |||
343 | res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res), | ||
344 | pci_mmcfg_config_num, GFP_KERNEL); | ||
345 | if (!res) { | ||
346 | printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n"); | ||
347 | return; | ||
348 | } | ||
349 | 361 | ||
350 | names = (void *)&res[pci_mmcfg_config_num]; | 362 | list_for_each_entry(cfg, &pci_mmcfg_list, list) |
351 | for (i = 0; i < pci_mmcfg_config_num; i++, res++) { | 363 | insert_resource(&iomem_resource, &cfg->res); |
352 | struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i]; | ||
353 | num_buses = cfg->end_bus_number - cfg->start_bus_number + 1; | ||
354 | res->name = names; | ||
355 | snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, | ||
356 | "PCI MMCONFIG %u [%02x-%02x]", cfg->pci_segment, | ||
357 | cfg->start_bus_number, cfg->end_bus_number); | ||
358 | res->start = cfg->address + (cfg->start_bus_number << 20); | ||
359 | res->end = res->start + (num_buses << 20) - 1; | ||
360 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
361 | insert_resource(&iomem_resource, res); | ||
362 | names += PCI_MMCFG_RESOURCE_NAME_LEN; | ||
363 | } | ||
364 | 364 | ||
365 | /* Mark that the resources have been inserted. */ | 365 | /* Mark that the resources have been inserted. */ |
366 | pci_mmcfg_resources_inserted = 1; | 366 | pci_mmcfg_resources_inserted = 1; |
@@ -437,11 +437,12 @@ static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used) | |||
437 | typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type); | 437 | typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type); |
438 | 438 | ||
439 | static int __init is_mmconf_reserved(check_reserved_t is_reserved, | 439 | static int __init is_mmconf_reserved(check_reserved_t is_reserved, |
440 | u64 addr, u64 size, int i, | 440 | struct pci_mmcfg_region *cfg, int with_e820) |
441 | typeof(pci_mmcfg_config[0]) *cfg, int with_e820) | ||
442 | { | 441 | { |
442 | u64 addr = cfg->res.start; | ||
443 | u64 size = resource_size(&cfg->res); | ||
443 | u64 old_size = size; | 444 | u64 old_size = size; |
444 | int valid = 0; | 445 | int valid = 0, num_buses; |
445 | 446 | ||
446 | while (!is_reserved(addr, addr + size, E820_RESERVED)) { | 447 | while (!is_reserved(addr, addr + size, E820_RESERVED)) { |
447 | size >>= 1; | 448 | size >>= 1; |
@@ -450,19 +451,25 @@ static int __init is_mmconf_reserved(check_reserved_t is_reserved, | |||
450 | } | 451 | } |
451 | 452 | ||
452 | if (size >= (16UL<<20) || size == old_size) { | 453 | if (size >= (16UL<<20) || size == old_size) { |
453 | printk(KERN_NOTICE | 454 | printk(KERN_INFO PREFIX "MMCONFIG at %pR reserved in %s\n", |
454 | "PCI: MCFG area at %Lx reserved in %s\n", | 455 | &cfg->res, |
455 | addr, with_e820?"E820":"ACPI motherboard resources"); | 456 | with_e820 ? "E820" : "ACPI motherboard resources"); |
456 | valid = 1; | 457 | valid = 1; |
457 | 458 | ||
458 | if (old_size != size) { | 459 | if (old_size != size) { |
459 | /* update end_bus_number */ | 460 | /* update end_bus */ |
460 | cfg->end_bus_number = cfg->start_bus_number + ((size>>20) - 1); | 461 | cfg->end_bus = cfg->start_bus + ((size>>20) - 1); |
461 | printk(KERN_NOTICE "PCI: updated MCFG configuration %d: base %lx " | 462 | num_buses = cfg->end_bus - cfg->start_bus + 1; |
462 | "segment %hu buses %u - %u\n", | 463 | cfg->res.end = cfg->res.start + |
463 | i, (unsigned long)cfg->address, cfg->pci_segment, | 464 | PCI_MMCFG_BUS_OFFSET(num_buses) - 1; |
464 | (unsigned int)cfg->start_bus_number, | 465 | snprintf(cfg->name, PCI_MMCFG_RESOURCE_NAME_LEN, |
465 | (unsigned int)cfg->end_bus_number); | 466 | "PCI MMCONFIG %04x [bus %02x-%02x]", |
467 | cfg->segment, cfg->start_bus, cfg->end_bus); | ||
468 | printk(KERN_INFO PREFIX | ||
469 | "MMCONFIG for %04x [bus%02x-%02x] " | ||
470 | "at %pR (base %#lx) (size reduced!)\n", | ||
471 | cfg->segment, cfg->start_bus, cfg->end_bus, | ||
472 | &cfg->res, (unsigned long) cfg->address); | ||
466 | } | 473 | } |
467 | } | 474 | } |
468 | 475 | ||
@@ -471,45 +478,26 @@ static int __init is_mmconf_reserved(check_reserved_t is_reserved, | |||
471 | 478 | ||
472 | static void __init pci_mmcfg_reject_broken(int early) | 479 | static void __init pci_mmcfg_reject_broken(int early) |
473 | { | 480 | { |
474 | typeof(pci_mmcfg_config[0]) *cfg; | 481 | struct pci_mmcfg_region *cfg; |
475 | int i; | ||
476 | 482 | ||
477 | if ((pci_mmcfg_config_num == 0) || | 483 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { |
478 | (pci_mmcfg_config == NULL) || | ||
479 | (pci_mmcfg_config[0].address == 0)) | ||
480 | return; | ||
481 | |||
482 | for (i = 0; i < pci_mmcfg_config_num; i++) { | ||
483 | int valid = 0; | 484 | int valid = 0; |
484 | u64 addr, size; | ||
485 | |||
486 | cfg = &pci_mmcfg_config[i]; | ||
487 | addr = cfg->start_bus_number; | ||
488 | addr <<= 20; | ||
489 | addr += cfg->address; | ||
490 | size = cfg->end_bus_number + 1 - cfg->start_bus_number; | ||
491 | size <<= 20; | ||
492 | printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx " | ||
493 | "segment %hu buses %u - %u\n", | ||
494 | i, (unsigned long)cfg->address, cfg->pci_segment, | ||
495 | (unsigned int)cfg->start_bus_number, | ||
496 | (unsigned int)cfg->end_bus_number); | ||
497 | 485 | ||
498 | if (!early && !acpi_disabled) | 486 | if (!early && !acpi_disabled) |
499 | valid = is_mmconf_reserved(is_acpi_reserved, addr, size, i, cfg, 0); | 487 | valid = is_mmconf_reserved(is_acpi_reserved, cfg, 0); |
500 | 488 | ||
501 | if (valid) | 489 | if (valid) |
502 | continue; | 490 | continue; |
503 | 491 | ||
504 | if (!early) | 492 | if (!early) |
505 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not" | 493 | printk(KERN_ERR FW_BUG PREFIX |
506 | " reserved in ACPI motherboard resources\n", | 494 | "MMCONFIG at %pR not reserved in " |
507 | cfg->address); | 495 | "ACPI motherboard resources\n", &cfg->res); |
508 | 496 | ||
509 | /* Don't try to do this check unless configuration | 497 | /* Don't try to do this check unless configuration |
510 | type 1 is available. how about type 2 ?*/ | 498 | type 1 is available. how about type 2 ?*/ |
511 | if (raw_pci_ops) | 499 | if (raw_pci_ops) |
512 | valid = is_mmconf_reserved(e820_all_mapped, addr, size, i, cfg, 1); | 500 | valid = is_mmconf_reserved(e820_all_mapped, cfg, 1); |
513 | 501 | ||
514 | if (!valid) | 502 | if (!valid) |
515 | goto reject; | 503 | goto reject; |
@@ -518,34 +506,41 @@ static void __init pci_mmcfg_reject_broken(int early) | |||
518 | return; | 506 | return; |
519 | 507 | ||
520 | reject: | 508 | reject: |
521 | printk(KERN_INFO "PCI: Not using MMCONFIG.\n"); | 509 | printk(KERN_INFO PREFIX "not using MMCONFIG\n"); |
522 | pci_mmcfg_arch_free(); | 510 | free_all_mmcfg(); |
523 | kfree(pci_mmcfg_config); | ||
524 | pci_mmcfg_config = NULL; | ||
525 | pci_mmcfg_config_num = 0; | ||
526 | } | 511 | } |
527 | 512 | ||
528 | static int __initdata known_bridge; | 513 | static int __initdata known_bridge; |
529 | 514 | ||
530 | static int acpi_mcfg_64bit_base_addr __initdata = FALSE; | 515 | static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg, |
516 | struct acpi_mcfg_allocation *cfg) | ||
517 | { | ||
518 | int year; | ||
531 | 519 | ||
532 | /* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ | 520 | if (cfg->address < 0xFFFFFFFF) |
533 | struct acpi_mcfg_allocation *pci_mmcfg_config; | 521 | return 0; |
534 | int pci_mmcfg_config_num; | ||
535 | 522 | ||
536 | static int __init acpi_mcfg_oem_check(struct acpi_table_mcfg *mcfg) | ||
537 | { | ||
538 | if (!strcmp(mcfg->header.oem_id, "SGI")) | 523 | if (!strcmp(mcfg->header.oem_id, "SGI")) |
539 | acpi_mcfg_64bit_base_addr = TRUE; | 524 | return 0; |
540 | 525 | ||
541 | return 0; | 526 | if (mcfg->header.revision >= 1) { |
527 | if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && | ||
528 | year >= 2010) | ||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | printk(KERN_ERR PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx " | ||
533 | "is above 4GB, ignored\n", cfg->pci_segment, | ||
534 | cfg->start_bus_number, cfg->end_bus_number, cfg->address); | ||
535 | return -EINVAL; | ||
542 | } | 536 | } |
543 | 537 | ||
544 | static int __init pci_parse_mcfg(struct acpi_table_header *header) | 538 | static int __init pci_parse_mcfg(struct acpi_table_header *header) |
545 | { | 539 | { |
546 | struct acpi_table_mcfg *mcfg; | 540 | struct acpi_table_mcfg *mcfg; |
541 | struct acpi_mcfg_allocation *cfg_table, *cfg; | ||
547 | unsigned long i; | 542 | unsigned long i; |
548 | int config_size; | 543 | int entries; |
549 | 544 | ||
550 | if (!header) | 545 | if (!header) |
551 | return -EINVAL; | 546 | return -EINVAL; |
@@ -553,38 +548,33 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header) | |||
553 | mcfg = (struct acpi_table_mcfg *)header; | 548 | mcfg = (struct acpi_table_mcfg *)header; |
554 | 549 | ||
555 | /* how many config structures do we have */ | 550 | /* how many config structures do we have */ |
556 | pci_mmcfg_config_num = 0; | 551 | free_all_mmcfg(); |
552 | entries = 0; | ||
557 | i = header->length - sizeof(struct acpi_table_mcfg); | 553 | i = header->length - sizeof(struct acpi_table_mcfg); |
558 | while (i >= sizeof(struct acpi_mcfg_allocation)) { | 554 | while (i >= sizeof(struct acpi_mcfg_allocation)) { |
559 | ++pci_mmcfg_config_num; | 555 | entries++; |
560 | i -= sizeof(struct acpi_mcfg_allocation); | 556 | i -= sizeof(struct acpi_mcfg_allocation); |
561 | }; | 557 | }; |
562 | if (pci_mmcfg_config_num == 0) { | 558 | if (entries == 0) { |
563 | printk(KERN_ERR PREFIX "MMCONFIG has no entries\n"); | 559 | printk(KERN_ERR PREFIX "MMCONFIG has no entries\n"); |
564 | return -ENODEV; | 560 | return -ENODEV; |
565 | } | 561 | } |
566 | 562 | ||
567 | config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config); | 563 | cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1]; |
568 | pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL); | 564 | for (i = 0; i < entries; i++) { |
569 | if (!pci_mmcfg_config) { | 565 | cfg = &cfg_table[i]; |
570 | printk(KERN_WARNING PREFIX | 566 | if (acpi_mcfg_check_entry(mcfg, cfg)) { |
571 | "No memory for MCFG config tables\n"); | 567 | free_all_mmcfg(); |
572 | return -ENOMEM; | ||
573 | } | ||
574 | |||
575 | memcpy(pci_mmcfg_config, &mcfg[1], config_size); | ||
576 | |||
577 | acpi_mcfg_oem_check(mcfg); | ||
578 | |||
579 | for (i = 0; i < pci_mmcfg_config_num; ++i) { | ||
580 | if ((pci_mmcfg_config[i].address > 0xFFFFFFFF) && | ||
581 | !acpi_mcfg_64bit_base_addr) { | ||
582 | printk(KERN_ERR PREFIX | ||
583 | "MMCONFIG not in low 4GB of memory\n"); | ||
584 | kfree(pci_mmcfg_config); | ||
585 | pci_mmcfg_config_num = 0; | ||
586 | return -ENODEV; | 568 | return -ENODEV; |
587 | } | 569 | } |
570 | |||
571 | if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number, | ||
572 | cfg->end_bus_number, cfg->address) == NULL) { | ||
573 | printk(KERN_WARNING PREFIX | ||
574 | "no memory for MCFG entries\n"); | ||
575 | free_all_mmcfg(); | ||
576 | return -ENOMEM; | ||
577 | } | ||
588 | } | 578 | } |
589 | 579 | ||
590 | return 0; | 580 | return 0; |
@@ -614,9 +604,7 @@ static void __init __pci_mmcfg_init(int early) | |||
614 | 604 | ||
615 | pci_mmcfg_reject_broken(early); | 605 | pci_mmcfg_reject_broken(early); |
616 | 606 | ||
617 | if ((pci_mmcfg_config_num == 0) || | 607 | if (list_empty(&pci_mmcfg_list)) |
618 | (pci_mmcfg_config == NULL) || | ||
619 | (pci_mmcfg_config[0].address == 0)) | ||
620 | return; | 608 | return; |
621 | 609 | ||
622 | if (pci_mmcfg_arch_init()) | 610 | if (pci_mmcfg_arch_init()) |
@@ -648,9 +636,7 @@ static int __init pci_mmcfg_late_insert_resources(void) | |||
648 | */ | 636 | */ |
649 | if ((pci_mmcfg_resources_inserted == 1) || | 637 | if ((pci_mmcfg_resources_inserted == 1) || |
650 | (pci_probe & PCI_PROBE_MMCONF) == 0 || | 638 | (pci_probe & PCI_PROBE_MMCONF) == 0 || |
651 | (pci_mmcfg_config_num == 0) || | 639 | list_empty(&pci_mmcfg_list)) |
652 | (pci_mmcfg_config == NULL) || | ||
653 | (pci_mmcfg_config[0].address == 0)) | ||
654 | return 1; | 640 | return 1; |
655 | 641 | ||
656 | /* | 642 | /* |