Commit ff097ddd authored by Bjorn Helgaas's avatar Bjorn Helgaas Committed by Jesse Barnes

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: default avatarYinghai Lu <yinghai@kernel.org>
Signed-off-by: default avatarBjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent 987c367b
...@@ -122,6 +122,7 @@ extern int __init pcibios_init(void); ...@@ -122,6 +122,7 @@ extern int __init pcibios_init(void);
#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2) #define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
struct pci_mmcfg_region { struct pci_mmcfg_region {
struct list_head list;
struct resource res; struct resource res;
u64 address; u64 address;
char __iomem *virt; char __iomem *virt;
...@@ -134,8 +135,7 @@ struct pci_mmcfg_region { ...@@ -134,8 +135,7 @@ struct pci_mmcfg_region {
extern int __init pci_mmcfg_arch_init(void); extern int __init pci_mmcfg_arch_init(void);
extern void __init pci_mmcfg_arch_free(void); extern void __init pci_mmcfg_arch_free(void);
extern struct pci_mmcfg_region *pci_mmcfg_config; extern struct list_head pci_mmcfg_list;
extern int pci_mmcfg_config_num;
#define PCI_MMCFG_BUS_OFFSET(bus) ((bus) << 20) #define PCI_MMCFG_BUS_OFFSET(bus) ((bus) << 20)
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include <linux/sfi_acpi.h> #include <linux/sfi_acpi.h>
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/sort.h>
#include <asm/e820.h> #include <asm/e820.h>
#include <asm/pci_x86.h> #include <asm/pci_x86.h>
#include <asm/acpi.h> #include <asm/acpi.h>
...@@ -26,53 +25,58 @@ ...@@ -26,53 +25,58 @@
/* Indicate if the mmcfg resources have been placed into the resource table. */ /* Indicate if the mmcfg resources have been placed into the resource table. */
static int __initdata pci_mmcfg_resources_inserted; static int __initdata pci_mmcfg_resources_inserted;
LIST_HEAD(pci_mmcfg_list);
static __init void free_all_mmcfg(void) static __init void free_all_mmcfg(void)
{ {
int i; struct pci_mmcfg_region *cfg, *tmp;
struct pci_mmcfg_region *cfg;
pci_mmcfg_arch_free(); pci_mmcfg_arch_free();
for (i = 0; i < pci_mmcfg_config_num; i++) { list_for_each_entry_safe(cfg, tmp, &pci_mmcfg_list, list) {
cfg = &pci_mmcfg_config[i];
if (cfg->res.parent) if (cfg->res.parent)
release_resource(&cfg->res); 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, static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
int end, u64 addr) int end, u64 addr)
{ {
struct pci_mmcfg_region *new; struct pci_mmcfg_region *new;
int new_num = pci_mmcfg_config_num + 1;
int i = pci_mmcfg_config_num;
int num_buses; int num_buses;
struct resource *res; struct resource *res;
if (addr == 0) if (addr == 0)
return NULL; return NULL;
new = kzalloc(sizeof(pci_mmcfg_config[0]) * new_num, GFP_KERNEL); new = kzalloc(sizeof(*new), GFP_KERNEL);
if (!new) if (!new)
return NULL; 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->address = addr;
new->segment = segment; new->segment = segment;
new->start_bus = start; new->start_bus = start;
new->end_bus = end; new->end_bus = end;
list_add_sorted(new);
num_buses = end - start + 1; num_buses = end - start + 1;
res = &new->res; res = &new->res;
res->start = addr + PCI_MMCFG_BUS_OFFSET(start); 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,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); "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
res->name = new->name; res->name = new->name;
return &pci_mmcfg_config[i]; return new;
} }
static const char __init *pci_mmcfg_e7520(void) static const char __init *pci_mmcfg_e7520(void)
...@@ -214,7 +218,7 @@ static const char __init *pci_mmcfg_nvidia_mcp55(void) ...@@ -214,7 +218,7 @@ static const char __init *pci_mmcfg_nvidia_mcp55(void)
/* /*
* do check if amd fam10h already took over * 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; return NULL;
mcp55_checked = true; mcp55_checked = true;
...@@ -275,44 +279,26 @@ static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { ...@@ -275,44 +279,26 @@ static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
0x0369, pci_mmcfg_nvidia_mcp55 }, 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) static void __init pci_mmcfg_check_end_bus_number(void)
{ {
int i;
struct pci_mmcfg_region *cfg, *cfgx; 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*/ /* last one*/
if (pci_mmcfg_config_num > 0) { cfg = list_entry(pci_mmcfg_list.prev, typeof(*cfg), list);
i = pci_mmcfg_config_num - 1; if (cfg)
cfg = &pci_mmcfg_config[i];
if (cfg->end_bus < cfg->start_bus) if (cfg->end_bus < cfg->start_bus)
cfg->end_bus = 255; cfg->end_bus = 255;
}
/* don't overlap please */ if (list_is_singular(&pci_mmcfg_list))
for (i = 0; i < pci_mmcfg_config_num - 1; i++) { return;
cfg = &pci_mmcfg_config[i];
cfgx = &pci_mmcfg_config[i+1];
/* don't overlap please */
list_for_each_entry(cfg, &pci_mmcfg_list, list) {
if (cfg->end_bus < cfg->start_bus) if (cfg->end_bus < cfg->start_bus)
cfg->end_bus = 255; 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; cfg->end_bus = cfgx->start_bus - 1;
} }
} }
...@@ -350,18 +336,15 @@ static int __init pci_mmcfg_check_hostbridge(void) ...@@ -350,18 +336,15 @@ static int __init pci_mmcfg_check_hostbridge(void)
/* some end_bus_number is crazy, fix it */ /* some end_bus_number is crazy, fix it */
pci_mmcfg_check_end_bus_number(); 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) static void __init pci_mmcfg_insert_resources(void)
{ {
int i;
struct pci_mmcfg_region *cfg; struct pci_mmcfg_region *cfg;
for (i = 0; i < pci_mmcfg_config_num; i++) { list_for_each_entry(cfg, &pci_mmcfg_list, list)
cfg = &pci_mmcfg_config[i];
insert_resource(&iomem_resource, &cfg->res); insert_resource(&iomem_resource, &cfg->res);
}
/* Mark that the resources have been inserted. */ /* Mark that the resources have been inserted. */
pci_mmcfg_resources_inserted = 1; pci_mmcfg_resources_inserted = 1;
...@@ -482,18 +465,15 @@ static void __init pci_mmcfg_reject_broken(int early) ...@@ -482,18 +465,15 @@ static void __init pci_mmcfg_reject_broken(int early)
struct pci_mmcfg_region *cfg; struct pci_mmcfg_region *cfg;
int i; int i;
if (pci_mmcfg_config_num == 0) list_for_each_entry(cfg, &pci_mmcfg_list, list) {
return;
for (i = 0; i < pci_mmcfg_config_num; i++) {
int valid = 0; int valid = 0;
cfg = &pci_mmcfg_config[i];
printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx " printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "
"segment %hu buses %u - %u\n", "segment %hu buses %u - %u\n",
i, (unsigned long)cfg->address, cfg->segment, i, (unsigned long)cfg->address, cfg->segment,
(unsigned int)cfg->start_bus, (unsigned int)cfg->start_bus,
(unsigned int)cfg->end_bus); (unsigned int)cfg->end_bus);
i++;
if (!early && !acpi_disabled) if (!early && !acpi_disabled)
valid = is_mmconf_reserved(is_acpi_reserved, i, cfg, 0); valid = is_mmconf_reserved(is_acpi_reserved, i, cfg, 0);
...@@ -524,10 +504,6 @@ static void __init pci_mmcfg_reject_broken(int early) ...@@ -524,10 +504,6 @@ static void __init pci_mmcfg_reject_broken(int early)
static int __initdata known_bridge; 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, static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
struct acpi_mcfg_allocation *cfg) struct acpi_mcfg_allocation *cfg)
{ {
...@@ -620,7 +596,7 @@ static void __init __pci_mmcfg_init(int early) ...@@ -620,7 +596,7 @@ static void __init __pci_mmcfg_init(int early)
pci_mmcfg_reject_broken(early); pci_mmcfg_reject_broken(early);
if (pci_mmcfg_config_num == 0) if (list_empty(&pci_mmcfg_list))
return; return;
if (pci_mmcfg_arch_init()) if (pci_mmcfg_arch_init())
...@@ -652,7 +628,7 @@ static int __init pci_mmcfg_late_insert_resources(void) ...@@ -652,7 +628,7 @@ static int __init pci_mmcfg_late_insert_resources(void)
*/ */
if ((pci_mmcfg_resources_inserted == 1) || if ((pci_mmcfg_resources_inserted == 1) ||
(pci_probe & PCI_PROBE_MMCONF) == 0 || (pci_probe & PCI_PROBE_MMCONF) == 0 ||
(pci_mmcfg_config_num == 0)) list_empty(&pci_mmcfg_list))
return 1; return 1;
/* /*
......
...@@ -28,15 +28,12 @@ static int mmcfg_last_accessed_cpu; ...@@ -28,15 +28,12 @@ static int mmcfg_last_accessed_cpu;
static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
{ {
struct pci_mmcfg_region *cfg; struct pci_mmcfg_region *cfg;
int cfg_num;
for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { list_for_each_entry(cfg, &pci_mmcfg_list, list)
cfg = &pci_mmcfg_config[cfg_num];
if (cfg->segment == seg && if (cfg->segment == seg &&
(cfg->start_bus <= bus) && (cfg->start_bus <= bus) &&
(cfg->end_bus >= bus)) (cfg->end_bus >= bus))
return cfg->address; return cfg->address;
}
/* Fall back to type 0 */ /* Fall back to type 0 */
return 0; return 0;
......
...@@ -14,16 +14,13 @@ ...@@ -14,16 +14,13 @@
static char __iomem *get_virt(unsigned int seg, unsigned bus) static char __iomem *get_virt(unsigned int seg, unsigned bus)
{ {
int i;
struct pci_mmcfg_region *cfg; struct pci_mmcfg_region *cfg;
for (i = 0; i < pci_mmcfg_config_num; ++i) { list_for_each_entry(cfg, &pci_mmcfg_list, list)
cfg = &pci_mmcfg_config[i];
if (cfg->segment == seg && if (cfg->segment == seg &&
(cfg->start_bus <= bus) && (cfg->start_bus <= bus) &&
(cfg->end_bus >= bus)) (cfg->end_bus >= bus))
return cfg->virt; return cfg->virt;
}
/* Fall back to type 0 */ /* Fall back to type 0 */
return NULL; return NULL;
...@@ -122,11 +119,9 @@ static void __iomem * __init mcfg_ioremap(struct pci_mmcfg_region *cfg) ...@@ -122,11 +119,9 @@ static void __iomem * __init mcfg_ioremap(struct pci_mmcfg_region *cfg)
int __init pci_mmcfg_arch_init(void) int __init pci_mmcfg_arch_init(void)
{ {
int i;
struct pci_mmcfg_region *cfg; struct pci_mmcfg_region *cfg;
for (i = 0; i < pci_mmcfg_config_num; ++i) { list_for_each_entry(cfg, &pci_mmcfg_list, list) {
cfg = &pci_mmcfg_config[i];
cfg->virt = mcfg_ioremap(cfg); cfg->virt = mcfg_ioremap(cfg);
if (!cfg->virt) { if (!cfg->virt) {
printk(KERN_ERR "PCI: Cannot map mmconfig aperture for " printk(KERN_ERR "PCI: Cannot map mmconfig aperture for "
...@@ -142,11 +137,9 @@ int __init pci_mmcfg_arch_init(void) ...@@ -142,11 +137,9 @@ int __init pci_mmcfg_arch_init(void)
void __init pci_mmcfg_arch_free(void) void __init pci_mmcfg_arch_free(void)
{ {
int i;
struct pci_mmcfg_region *cfg; struct pci_mmcfg_region *cfg;
for (i = 0; i < pci_mmcfg_config_num; ++i) { list_for_each_entry(cfg, &pci_mmcfg_list, list) {
cfg = &pci_mmcfg_config[i];
if (cfg->virt) { if (cfg->virt) {
iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus)); iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
cfg->virt = NULL; cfg->virt = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment