diff options
author | Bjorn Helgaas <bjorn.helgaas@hp.com> | 2009-11-13 19:34:49 -0500 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-11-24 18:30:14 -0500 |
commit | ff097ddd4aeac790fd51d013c79c2f18ec9a7117 (patch) | |
tree | 4a77f081e4ac7e93aa74a102bf372419699468b9 /arch/x86 | |
parent | 987c367b4e93be6826394e7c9cc14d28bb5c8810 (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')
-rw-r--r-- | arch/x86/include/asm/pci_x86.h | 4 | ||||
-rw-r--r-- | arch/x86/pci/mmconfig-shared.c | 106 | ||||
-rw-r--r-- | arch/x86/pci/mmconfig_32.c | 5 | ||||
-rw-r--r-- | arch/x86/pci/mmconfig_64.c | 13 |
4 files changed, 47 insertions, 81 deletions
diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h index 7aa2ed8f25ab..0b7c316a70c3 100644 --- a/arch/x86/include/asm/pci_x86.h +++ b/arch/x86/include/asm/pci_x86.h | |||
@@ -122,6 +122,7 @@ extern int __init pcibios_init(void); | |||
122 | #define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2) | 122 | #define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2) |
123 | 123 | ||
124 | struct pci_mmcfg_region { | 124 | struct pci_mmcfg_region { |
125 | struct list_head list; | ||
125 | struct resource res; | 126 | struct resource res; |
126 | u64 address; | 127 | u64 address; |
127 | char __iomem *virt; | 128 | char __iomem *virt; |
@@ -134,8 +135,7 @@ struct pci_mmcfg_region { | |||
134 | extern int __init pci_mmcfg_arch_init(void); | 135 | extern int __init pci_mmcfg_arch_init(void); |
135 | extern void __init pci_mmcfg_arch_free(void); | 136 | extern void __init pci_mmcfg_arch_free(void); |
136 | 137 | ||
137 | extern struct pci_mmcfg_region *pci_mmcfg_config; | 138 | extern struct list_head pci_mmcfg_list; |
138 | extern int pci_mmcfg_config_num; | ||
139 | 139 | ||
140 | #define PCI_MMCFG_BUS_OFFSET(bus) ((bus) << 20) | 140 | #define PCI_MMCFG_BUS_OFFSET(bus) ((bus) << 20) |
141 | 141 | ||
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. */ |
27 | static int __initdata pci_mmcfg_resources_inserted; | 26 | static int __initdata pci_mmcfg_resources_inserted; |
28 | 27 | ||
28 | LIST_HEAD(pci_mmcfg_list); | ||
29 | |||
29 | static __init void free_all_mmcfg(void) | 30 | static __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; | 43 | static __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 | ||
45 | static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start, | 59 | static __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 | ||
88 | static const char __init *pci_mmcfg_e7520(void) | 92 | static 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 | ||
278 | static 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 | |||
290 | static void __init pci_mmcfg_check_end_bus_number(void) | 282 | static 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 | ||
356 | static void __init pci_mmcfg_insert_resources(void) | 342 | static 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 | ||
525 | static int __initdata known_bridge; | 505 | static int __initdata known_bridge; |
526 | 506 | ||
527 | /* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ | ||
528 | struct pci_mmcfg_region *pci_mmcfg_config; | ||
529 | int pci_mmcfg_config_num; | ||
530 | |||
531 | static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg, | 507 | static 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 | /* |
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c index a3cee532c935..c04523e09649 100644 --- a/arch/x86/pci/mmconfig_32.c +++ b/arch/x86/pci/mmconfig_32.c | |||
@@ -28,15 +28,12 @@ static int mmcfg_last_accessed_cpu; | |||
28 | static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) | 28 | static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) |
29 | { | 29 | { |
30 | struct pci_mmcfg_region *cfg; | 30 | struct pci_mmcfg_region *cfg; |
31 | int cfg_num; | ||
32 | 31 | ||
33 | for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { | 32 | list_for_each_entry(cfg, &pci_mmcfg_list, list) |
34 | cfg = &pci_mmcfg_config[cfg_num]; | ||
35 | if (cfg->segment == seg && | 33 | if (cfg->segment == seg && |
36 | (cfg->start_bus <= bus) && | 34 | (cfg->start_bus <= bus) && |
37 | (cfg->end_bus >= bus)) | 35 | (cfg->end_bus >= bus)) |
38 | return cfg->address; | 36 | return cfg->address; |
39 | } | ||
40 | 37 | ||
41 | /* Fall back to type 0 */ | 38 | /* Fall back to type 0 */ |
42 | return 0; | 39 | return 0; |
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c index 78fa05c6c04d..ed1f479b4d0e 100644 --- a/arch/x86/pci/mmconfig_64.c +++ b/arch/x86/pci/mmconfig_64.c | |||
@@ -14,16 +14,13 @@ | |||
14 | 14 | ||
15 | static char __iomem *get_virt(unsigned int seg, unsigned bus) | 15 | static char __iomem *get_virt(unsigned int seg, unsigned bus) |
16 | { | 16 | { |
17 | int i; | ||
18 | struct pci_mmcfg_region *cfg; | 17 | struct pci_mmcfg_region *cfg; |
19 | 18 | ||
20 | for (i = 0; i < pci_mmcfg_config_num; ++i) { | 19 | list_for_each_entry(cfg, &pci_mmcfg_list, list) |
21 | cfg = &pci_mmcfg_config[i]; | ||
22 | if (cfg->segment == seg && | 20 | if (cfg->segment == seg && |
23 | (cfg->start_bus <= bus) && | 21 | (cfg->start_bus <= bus) && |
24 | (cfg->end_bus >= bus)) | 22 | (cfg->end_bus >= bus)) |
25 | return cfg->virt; | 23 | return cfg->virt; |
26 | } | ||
27 | 24 | ||
28 | /* Fall back to type 0 */ | 25 | /* Fall back to type 0 */ |
29 | return NULL; | 26 | return NULL; |
@@ -122,11 +119,9 @@ static void __iomem * __init mcfg_ioremap(struct pci_mmcfg_region *cfg) | |||
122 | 119 | ||
123 | int __init pci_mmcfg_arch_init(void) | 120 | int __init pci_mmcfg_arch_init(void) |
124 | { | 121 | { |
125 | int i; | ||
126 | struct pci_mmcfg_region *cfg; | 122 | struct pci_mmcfg_region *cfg; |
127 | 123 | ||
128 | for (i = 0; i < pci_mmcfg_config_num; ++i) { | 124 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { |
129 | cfg = &pci_mmcfg_config[i]; | ||
130 | cfg->virt = mcfg_ioremap(cfg); | 125 | cfg->virt = mcfg_ioremap(cfg); |
131 | if (!cfg->virt) { | 126 | if (!cfg->virt) { |
132 | printk(KERN_ERR "PCI: Cannot map mmconfig aperture for " | 127 | printk(KERN_ERR "PCI: Cannot map mmconfig aperture for " |
@@ -142,11 +137,9 @@ int __init pci_mmcfg_arch_init(void) | |||
142 | 137 | ||
143 | void __init pci_mmcfg_arch_free(void) | 138 | void __init pci_mmcfg_arch_free(void) |
144 | { | 139 | { |
145 | int i; | ||
146 | struct pci_mmcfg_region *cfg; | 140 | struct pci_mmcfg_region *cfg; |
147 | 141 | ||
148 | for (i = 0; i < pci_mmcfg_config_num; ++i) { | 142 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { |
149 | cfg = &pci_mmcfg_config[i]; | ||
150 | if (cfg->virt) { | 143 | if (cfg->virt) { |
151 | iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus)); | 144 | iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus)); |
152 | cfg->virt = NULL; | 145 | cfg->virt = NULL; |