From ff097ddd4aeac790fd51d013c79c2f18ec9a7117 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 13 Nov 2009 17:34:49 -0700 Subject: [PATCH] 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 Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- arch/x86/include/asm/pci_x86.h | 4 +- arch/x86/pci/mmconfig-shared.c | 106 ++++++++++++++++------------------------- arch/x86/pci/mmconfig_32.c | 5 +- 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 7aa2ed8..0b7c316 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); #define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2) struct pci_mmcfg_region { + struct list_head list; struct resource res; u64 address; char __iomem *virt; @@ -134,8 +135,7 @@ struct pci_mmcfg_region { extern int __init pci_mmcfg_arch_init(void); extern void __init pci_mmcfg_arch_free(void); -extern struct pci_mmcfg_region *pci_mmcfg_config; -extern int pci_mmcfg_config_num; +extern struct list_head pci_mmcfg_list; #define PCI_MMCFG_BUS_OFFSET(bus) ((bus) << 20) diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 6eeeac0..2709aa8 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -26,53 +25,58 @@ /* Indicate if the mmcfg resources have been placed into the resource table. */ static int __initdata pci_mmcfg_resources_inserted; +LIST_HEAD(pci_mmcfg_list); + static __init void free_all_mmcfg(void) { - int i; - struct pci_mmcfg_region *cfg; + struct pci_mmcfg_region *cfg, *tmp; pci_mmcfg_arch_free(); - for (i = 0; i < pci_mmcfg_config_num; i++) { - cfg = &pci_mmcfg_config[i]; + list_for_each_entry_safe(cfg, tmp, &pci_mmcfg_list, list) { if (cfg->res.parent) release_resource(&cfg->res); + list_del(&cfg->list); + kfree(cfg); } - pci_mmcfg_config_num = 0; - kfree(pci_mmcfg_config); - pci_mmcfg_config = NULL; +} + +static __init void list_add_sorted(struct pci_mmcfg_region *new) +{ + struct pci_mmcfg_region *cfg; + + /* keep list sorted by segment and starting bus number */ + list_for_each_entry(cfg, &pci_mmcfg_list, list) { + if (cfg->segment > new->segment || + (cfg->segment == new->segment && + cfg->start_bus >= new->start_bus)) { + list_add_tail(&new->list, &cfg->list); + return; + } + } + list_add_tail(&new->list, &pci_mmcfg_list); } static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start, int end, u64 addr) { struct pci_mmcfg_region *new; - int new_num = pci_mmcfg_config_num + 1; - int i = pci_mmcfg_config_num; int num_buses; struct resource *res; if (addr == 0) return NULL; - new = kzalloc(sizeof(pci_mmcfg_config[0]) * new_num, GFP_KERNEL); + new = kzalloc(sizeof(*new), GFP_KERNEL); if (!new) return NULL; - if (pci_mmcfg_config) { - memcpy(new, pci_mmcfg_config, - sizeof(pci_mmcfg_config[0]) * new_num); - kfree(pci_mmcfg_config); - } - pci_mmcfg_config = new; - pci_mmcfg_config_num++; - - new = &pci_mmcfg_config[i]; - new->address = addr; new->segment = segment; new->start_bus = start; new->end_bus = end; + list_add_sorted(new); + num_buses = end - start + 1; res = &new->res; 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, "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end); res->name = new->name; - return &pci_mmcfg_config[i]; + return new; } static const char __init *pci_mmcfg_e7520(void) @@ -214,7 +218,7 @@ static const char __init *pci_mmcfg_nvidia_mcp55(void) /* * do check if amd fam10h already took over */ - if (!acpi_disabled || pci_mmcfg_config_num || mcp55_checked) + if (!acpi_disabled || !list_empty(&pci_mmcfg_list) || mcp55_checked) return NULL; mcp55_checked = true; @@ -275,44 +279,26 @@ static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { 0x0369, pci_mmcfg_nvidia_mcp55 }, }; -static int __init cmp_mmcfg(const void *x1, const void *x2) -{ - const struct pci_mmcfg_region *m1 = x1; - const struct pci_mmcfg_region *m2 = x2; - int start1, start2; - - start1 = m1->start_bus; - start2 = m2->start_bus; - - return start1 - start2; -} - static void __init pci_mmcfg_check_end_bus_number(void) { - int i; struct pci_mmcfg_region *cfg, *cfgx; - /* sort them at first */ - sort(pci_mmcfg_config, pci_mmcfg_config_num, - sizeof(pci_mmcfg_config[0]), cmp_mmcfg, NULL); - /* last one*/ - if (pci_mmcfg_config_num > 0) { - i = pci_mmcfg_config_num - 1; - cfg = &pci_mmcfg_config[i]; + cfg = list_entry(pci_mmcfg_list.prev, typeof(*cfg), list); + if (cfg) if (cfg->end_bus < cfg->start_bus) cfg->end_bus = 255; - } - /* don't overlap please */ - for (i = 0; i < pci_mmcfg_config_num - 1; i++) { - cfg = &pci_mmcfg_config[i]; - cfgx = &pci_mmcfg_config[i+1]; + if (list_is_singular(&pci_mmcfg_list)) + return; + /* don't overlap please */ + list_for_each_entry(cfg, &pci_mmcfg_list, list) { if (cfg->end_bus < cfg->start_bus) cfg->end_bus = 255; - if (cfg->end_bus >= cfgx->start_bus) + cfgx = list_entry(cfg->list.next, typeof(*cfg), list); + if (cfg != cfgx && cfg->end_bus >= cfgx->start_bus) cfg->end_bus = cfgx->start_bus - 1; } } @@ -350,18 +336,15 @@ static int __init pci_mmcfg_check_hostbridge(void) /* some end_bus_number is crazy, fix it */ pci_mmcfg_check_end_bus_number(); - return pci_mmcfg_config_num != 0; + return !list_empty(&pci_mmcfg_list); } static void __init pci_mmcfg_insert_resources(void) { - int i; struct pci_mmcfg_region *cfg; - for (i = 0; i < pci_mmcfg_config_num; i++) { - cfg = &pci_mmcfg_config[i]; + list_for_each_entry(cfg, &pci_mmcfg_list, list) insert_resource(&iomem_resource, &cfg->res); - } /* Mark that the resources have been inserted. */ pci_mmcfg_resources_inserted = 1; @@ -482,18 +465,15 @@ static void __init pci_mmcfg_reject_broken(int early) struct pci_mmcfg_region *cfg; int i; - if (pci_mmcfg_config_num == 0) - return; - - for (i = 0; i < pci_mmcfg_config_num; i++) { + list_for_each_entry(cfg, &pci_mmcfg_list, list) { int valid = 0; - cfg = &pci_mmcfg_config[i]; printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx " "segment %hu buses %u - %u\n", i, (unsigned long)cfg->address, cfg->segment, (unsigned int)cfg->start_bus, (unsigned int)cfg->end_bus); + i++; if (!early && !acpi_disabled) valid = is_mmconf_reserved(is_acpi_reserved, i, cfg, 0); @@ -524,10 +504,6 @@ reject: static int __initdata known_bridge; -/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ -struct pci_mmcfg_region *pci_mmcfg_config; -int pci_mmcfg_config_num; - static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg, struct acpi_mcfg_allocation *cfg) { @@ -620,7 +596,7 @@ static void __init __pci_mmcfg_init(int early) pci_mmcfg_reject_broken(early); - if (pci_mmcfg_config_num == 0) + if (list_empty(&pci_mmcfg_list)) return; if (pci_mmcfg_arch_init()) @@ -652,7 +628,7 @@ static int __init pci_mmcfg_late_insert_resources(void) */ if ((pci_mmcfg_resources_inserted == 1) || (pci_probe & PCI_PROBE_MMCONF) == 0 || - (pci_mmcfg_config_num == 0)) + list_empty(&pci_mmcfg_list)) return 1; /* diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c index a3cee53..c04523e 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; static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) { struct pci_mmcfg_region *cfg; - int cfg_num; - for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { - cfg = &pci_mmcfg_config[cfg_num]; + list_for_each_entry(cfg, &pci_mmcfg_list, list) if (cfg->segment == seg && (cfg->start_bus <= bus) && (cfg->end_bus >= bus)) return cfg->address; - } /* Fall back to type 0 */ return 0; diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c index 78fa05c..ed1f479 100644 --- a/arch/x86/pci/mmconfig_64.c +++ b/arch/x86/pci/mmconfig_64.c @@ -14,16 +14,13 @@ static char __iomem *get_virt(unsigned int seg, unsigned bus) { - int i; struct pci_mmcfg_region *cfg; - for (i = 0; i < pci_mmcfg_config_num; ++i) { - cfg = &pci_mmcfg_config[i]; + list_for_each_entry(cfg, &pci_mmcfg_list, list) if (cfg->segment == seg && (cfg->start_bus <= bus) && (cfg->end_bus >= bus)) return cfg->virt; - } /* Fall back to type 0 */ return NULL; @@ -122,11 +119,9 @@ static void __iomem * __init mcfg_ioremap(struct pci_mmcfg_region *cfg) int __init pci_mmcfg_arch_init(void) { - int i; struct pci_mmcfg_region *cfg; - for (i = 0; i < pci_mmcfg_config_num; ++i) { - cfg = &pci_mmcfg_config[i]; + list_for_each_entry(cfg, &pci_mmcfg_list, list) { cfg->virt = mcfg_ioremap(cfg); if (!cfg->virt) { printk(KERN_ERR "PCI: Cannot map mmconfig aperture for " @@ -142,11 +137,9 @@ int __init pci_mmcfg_arch_init(void) void __init pci_mmcfg_arch_free(void) { - int i; struct pci_mmcfg_region *cfg; - for (i = 0; i < pci_mmcfg_config_num; ++i) { - cfg = &pci_mmcfg_config[i]; + list_for_each_entry(cfg, &pci_mmcfg_list, list) { if (cfg->virt) { iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus)); cfg->virt = NULL; -- 2.7.4