aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/pci/mmconfig-shared.c
diff options
context:
space:
mode:
authorBjorn Helgaas <bjorn.helgaas@hp.com>2009-11-13 19:34:49 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-11-24 18:30:14 -0500
commitff097ddd4aeac790fd51d013c79c2f18ec9a7117 (patch)
tree4a77f081e4ac7e93aa74a102bf372419699468b9 /arch/x86/pci/mmconfig-shared.c
parent987c367b4e93be6826394e7c9cc14d28bb5c8810 (diff)
x86/PCI: MMCONFIG: manage pci_mmcfg_region as a list, not a table
This changes pci_mmcfg_region from a table to a list, to make it easier to add and remove MMCONFIG regions for PCI host bridge hotplug. Reviewed-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'arch/x86/pci/mmconfig-shared.c')
-rw-r--r--arch/x86/pci/mmconfig-shared.c106
1 files changed, 41 insertions, 65 deletions
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index 6eeeac0d25f4..2709aa81801d 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -16,7 +16,6 @@
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/dmi.h> 18#include <linux/dmi.h>
19#include <linux/sort.h>
20#include <asm/e820.h> 19#include <asm/e820.h>
21#include <asm/pci_x86.h> 20#include <asm/pci_x86.h>
22#include <asm/acpi.h> 21#include <asm/acpi.h>
@@ -26,53 +25,58 @@
26/* Indicate if the mmcfg resources have been placed into the resource table. */ 25/* Indicate if the mmcfg resources have been placed into the resource table. */
27static int __initdata pci_mmcfg_resources_inserted; 26static int __initdata pci_mmcfg_resources_inserted;
28 27
28LIST_HEAD(pci_mmcfg_list);
29
29static __init void free_all_mmcfg(void) 30static __init void free_all_mmcfg(void)
30{ 31{
31 int i; 32 struct pci_mmcfg_region *cfg, *tmp;
32 struct pci_mmcfg_region *cfg;
33 33
34 pci_mmcfg_arch_free(); 34 pci_mmcfg_arch_free();
35 for (i = 0; i < pci_mmcfg_config_num; i++) { 35 list_for_each_entry_safe(cfg, tmp, &pci_mmcfg_list, list) {
36 cfg = &pci_mmcfg_config[i];
37 if (cfg->res.parent) 36 if (cfg->res.parent)
38 release_resource(&cfg->res); 37 release_resource(&cfg->res);
38 list_del(&cfg->list);
39 kfree(cfg);
39 } 40 }
40 pci_mmcfg_config_num = 0; 41}
41 kfree(pci_mmcfg_config); 42
42 pci_mmcfg_config = NULL; 43static __init void list_add_sorted(struct pci_mmcfg_region *new)
44{
45 struct pci_mmcfg_region *cfg;
46
47 /* keep list sorted by segment and starting bus number */
48 list_for_each_entry(cfg, &pci_mmcfg_list, list) {
49 if (cfg->segment > new->segment ||
50 (cfg->segment == new->segment &&
51 cfg->start_bus >= new->start_bus)) {
52 list_add_tail(&new->list, &cfg->list);
53 return;
54 }
55 }
56 list_add_tail(&new->list, &pci_mmcfg_list);
43} 57}
44 58
45static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start, 59static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
46 int end, u64 addr) 60 int end, u64 addr)
47{ 61{
48 struct pci_mmcfg_region *new; 62 struct pci_mmcfg_region *new;
49 int new_num = pci_mmcfg_config_num + 1;
50 int i = pci_mmcfg_config_num;
51 int num_buses; 63 int num_buses;
52 struct resource *res; 64 struct resource *res;
53 65
54 if (addr == 0) 66 if (addr == 0)
55 return NULL; 67 return NULL;
56 68
57 new = kzalloc(sizeof(pci_mmcfg_config[0]) * new_num, GFP_KERNEL); 69 new = kzalloc(sizeof(*new), GFP_KERNEL);
58 if (!new) 70 if (!new)
59 return NULL; 71 return NULL;
60 72
61 if (pci_mmcfg_config) {
62 memcpy(new, pci_mmcfg_config,
63 sizeof(pci_mmcfg_config[0]) * new_num);
64 kfree(pci_mmcfg_config);
65 }
66 pci_mmcfg_config = new;
67 pci_mmcfg_config_num++;
68
69 new = &pci_mmcfg_config[i];
70
71 new->address = addr; 73 new->address = addr;
72 new->segment = segment; 74 new->segment = segment;
73 new->start_bus = start; 75 new->start_bus = start;
74 new->end_bus = end; 76 new->end_bus = end;
75 77
78 list_add_sorted(new);
79
76 num_buses = end - start + 1; 80 num_buses = end - start + 1;
77 res = &new->res; 81 res = &new->res;
78 res->start = addr + PCI_MMCFG_BUS_OFFSET(start); 82 res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
@@ -82,7 +86,7 @@ static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
82 "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end); 86 "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
83 res->name = new->name; 87 res->name = new->name;
84 88
85 return &pci_mmcfg_config[i]; 89 return new;
86} 90}
87 91
88static const char __init *pci_mmcfg_e7520(void) 92static const char __init *pci_mmcfg_e7520(void)
@@ -214,7 +218,7 @@ static const char __init *pci_mmcfg_nvidia_mcp55(void)
214 /* 218 /*
215 * do check if amd fam10h already took over 219 * do check if amd fam10h already took over
216 */ 220 */
217 if (!acpi_disabled || pci_mmcfg_config_num || mcp55_checked) 221 if (!acpi_disabled || !list_empty(&pci_mmcfg_list) || mcp55_checked)
218 return NULL; 222 return NULL;
219 223
220 mcp55_checked = true; 224 mcp55_checked = true;
@@ -275,44 +279,26 @@ static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
275 0x0369, pci_mmcfg_nvidia_mcp55 }, 279 0x0369, pci_mmcfg_nvidia_mcp55 },
276}; 280};
277 281
278static int __init cmp_mmcfg(const void *x1, const void *x2)
279{
280 const struct pci_mmcfg_region *m1 = x1;
281 const struct pci_mmcfg_region *m2 = x2;
282 int start1, start2;
283
284 start1 = m1->start_bus;
285 start2 = m2->start_bus;
286
287 return start1 - start2;
288}
289
290static void __init pci_mmcfg_check_end_bus_number(void) 282static void __init pci_mmcfg_check_end_bus_number(void)
291{ 283{
292 int i;
293 struct pci_mmcfg_region *cfg, *cfgx; 284 struct pci_mmcfg_region *cfg, *cfgx;
294 285
295 /* sort them at first */
296 sort(pci_mmcfg_config, pci_mmcfg_config_num,
297 sizeof(pci_mmcfg_config[0]), cmp_mmcfg, NULL);
298
299 /* last one*/ 286 /* last one*/
300 if (pci_mmcfg_config_num > 0) { 287 cfg = list_entry(pci_mmcfg_list.prev, typeof(*cfg), list);
301 i = pci_mmcfg_config_num - 1; 288 if (cfg)
302 cfg = &pci_mmcfg_config[i];
303 if (cfg->end_bus < cfg->start_bus) 289 if (cfg->end_bus < cfg->start_bus)
304 cfg->end_bus = 255; 290 cfg->end_bus = 255;
305 }
306 291
307 /* don't overlap please */ 292 if (list_is_singular(&pci_mmcfg_list))
308 for (i = 0; i < pci_mmcfg_config_num - 1; i++) { 293 return;
309 cfg = &pci_mmcfg_config[i];
310 cfgx = &pci_mmcfg_config[i+1];
311 294
295 /* don't overlap please */
296 list_for_each_entry(cfg, &pci_mmcfg_list, list) {
312 if (cfg->end_bus < cfg->start_bus) 297 if (cfg->end_bus < cfg->start_bus)
313 cfg->end_bus = 255; 298 cfg->end_bus = 255;
314 299
315 if (cfg->end_bus >= cfgx->start_bus) 300 cfgx = list_entry(cfg->list.next, typeof(*cfg), list);
301 if (cfg != cfgx && cfg->end_bus >= cfgx->start_bus)
316 cfg->end_bus = cfgx->start_bus - 1; 302 cfg->end_bus = cfgx->start_bus - 1;
317 } 303 }
318} 304}
@@ -350,18 +336,15 @@ static int __init pci_mmcfg_check_hostbridge(void)
350 /* some end_bus_number is crazy, fix it */ 336 /* some end_bus_number is crazy, fix it */
351 pci_mmcfg_check_end_bus_number(); 337 pci_mmcfg_check_end_bus_number();
352 338
353 return pci_mmcfg_config_num != 0; 339 return !list_empty(&pci_mmcfg_list);
354} 340}
355 341
356static void __init pci_mmcfg_insert_resources(void) 342static void __init pci_mmcfg_insert_resources(void)
357{ 343{
358 int i;
359 struct pci_mmcfg_region *cfg; 344 struct pci_mmcfg_region *cfg;
360 345
361 for (i = 0; i < pci_mmcfg_config_num; i++) { 346 list_for_each_entry(cfg, &pci_mmcfg_list, list)
362 cfg = &pci_mmcfg_config[i];
363 insert_resource(&iomem_resource, &cfg->res); 347 insert_resource(&iomem_resource, &cfg->res);
364 }
365 348
366 /* Mark that the resources have been inserted. */ 349 /* Mark that the resources have been inserted. */
367 pci_mmcfg_resources_inserted = 1; 350 pci_mmcfg_resources_inserted = 1;
@@ -482,18 +465,15 @@ static void __init pci_mmcfg_reject_broken(int early)
482 struct pci_mmcfg_region *cfg; 465 struct pci_mmcfg_region *cfg;
483 int i; 466 int i;
484 467
485 if (pci_mmcfg_config_num == 0) 468 list_for_each_entry(cfg, &pci_mmcfg_list, list) {
486 return;
487
488 for (i = 0; i < pci_mmcfg_config_num; i++) {
489 int valid = 0; 469 int valid = 0;
490 470
491 cfg = &pci_mmcfg_config[i];
492 printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx " 471 printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "
493 "segment %hu buses %u - %u\n", 472 "segment %hu buses %u - %u\n",
494 i, (unsigned long)cfg->address, cfg->segment, 473 i, (unsigned long)cfg->address, cfg->segment,
495 (unsigned int)cfg->start_bus, 474 (unsigned int)cfg->start_bus,
496 (unsigned int)cfg->end_bus); 475 (unsigned int)cfg->end_bus);
476 i++;
497 477
498 if (!early && !acpi_disabled) 478 if (!early && !acpi_disabled)
499 valid = is_mmconf_reserved(is_acpi_reserved, i, cfg, 0); 479 valid = is_mmconf_reserved(is_acpi_reserved, i, cfg, 0);
@@ -524,10 +504,6 @@ reject:
524 504
525static int __initdata known_bridge; 505static int __initdata known_bridge;
526 506
527/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
528struct pci_mmcfg_region *pci_mmcfg_config;
529int pci_mmcfg_config_num;
530
531static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg, 507static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
532 struct acpi_mcfg_allocation *cfg) 508 struct acpi_mcfg_allocation *cfg)
533{ 509{
@@ -620,7 +596,7 @@ static void __init __pci_mmcfg_init(int early)
620 596
621 pci_mmcfg_reject_broken(early); 597 pci_mmcfg_reject_broken(early);
622 598
623 if (pci_mmcfg_config_num == 0) 599 if (list_empty(&pci_mmcfg_list))
624 return; 600 return;
625 601
626 if (pci_mmcfg_arch_init()) 602 if (pci_mmcfg_arch_init())
@@ -652,7 +628,7 @@ static int __init pci_mmcfg_late_insert_resources(void)
652 */ 628 */
653 if ((pci_mmcfg_resources_inserted == 1) || 629 if ((pci_mmcfg_resources_inserted == 1) ||
654 (pci_probe & PCI_PROBE_MMCONF) == 0 || 630 (pci_probe & PCI_PROBE_MMCONF) == 0 ||
655 (pci_mmcfg_config_num == 0)) 631 list_empty(&pci_mmcfg_list))
656 return 1; 632 return 1;
657 633
658 /* 634 /*