Commit 95c5e92f authored by Jiang Liu's avatar Jiang Liu Committed by Bjorn Helgaas

x86/PCI: prepare pci_mmcfg_check_reserved() to be called at runtime

Prepare function pci_mmcfg_check_reserved() to be called at runtime
for PCI host bridge hot-plugging
Reviewed-by: default avatarYinghai Lu <yinghai@kernel.org>
Signed-off-by: default avatarJiang Liu <liuj97@gmail.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent 9cf0105d
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
/* 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;
static bool pci_mmcfg_running_state;
static DEFINE_MUTEX(pci_mmcfg_lock); static DEFINE_MUTEX(pci_mmcfg_lock);
LIST_HEAD(pci_mmcfg_list); LIST_HEAD(pci_mmcfg_list);
...@@ -375,14 +376,15 @@ static void __init pci_mmcfg_insert_resources(void) ...@@ -375,14 +376,15 @@ static void __init pci_mmcfg_insert_resources(void)
struct pci_mmcfg_region *cfg; struct pci_mmcfg_region *cfg;
list_for_each_entry(cfg, &pci_mmcfg_list, list) list_for_each_entry(cfg, &pci_mmcfg_list, list)
insert_resource(&iomem_resource, &cfg->res); if (!cfg->res.parent)
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;
} }
static acpi_status __init check_mcfg_resource(struct acpi_resource *res, static acpi_status __devinit check_mcfg_resource(struct acpi_resource *res,
void *data) void *data)
{ {
struct resource *mcfg_res = data; struct resource *mcfg_res = data;
struct acpi_resource_address64 address; struct acpi_resource_address64 address;
...@@ -418,8 +420,8 @@ static acpi_status __init check_mcfg_resource(struct acpi_resource *res, ...@@ -418,8 +420,8 @@ static acpi_status __init check_mcfg_resource(struct acpi_resource *res,
return AE_OK; return AE_OK;
} }
static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl, static acpi_status __devinit find_mboard_resource(acpi_handle handle, u32 lvl,
void *context, void **rv) void *context, void **rv)
{ {
struct resource *mcfg_res = context; struct resource *mcfg_res = context;
...@@ -432,7 +434,7 @@ static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl, ...@@ -432,7 +434,7 @@ static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl,
return AE_OK; return AE_OK;
} }
static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used) static int __devinit is_acpi_reserved(u64 start, u64 end, unsigned not_used)
{ {
struct resource mcfg_res; struct resource mcfg_res;
...@@ -451,13 +453,15 @@ static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used) ...@@ -451,13 +453,15 @@ static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used)
typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type); typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type);
static int __init is_mmconf_reserved(check_reserved_t is_reserved, static int __ref is_mmconf_reserved(check_reserved_t is_reserved,
struct pci_mmcfg_region *cfg, int with_e820) struct pci_mmcfg_region *cfg,
struct device *dev, int with_e820)
{ {
u64 addr = cfg->res.start; u64 addr = cfg->res.start;
u64 size = resource_size(&cfg->res); u64 size = resource_size(&cfg->res);
u64 old_size = size; u64 old_size = size;
int valid = 0, num_buses; int num_buses;
char *method = with_e820 ? "E820" : "ACPI motherboard resources";
while (!is_reserved(addr, addr + size, E820_RESERVED)) { while (!is_reserved(addr, addr + size, E820_RESERVED)) {
size >>= 1; size >>= 1;
...@@ -465,49 +469,75 @@ static int __init is_mmconf_reserved(check_reserved_t is_reserved, ...@@ -465,49 +469,75 @@ static int __init is_mmconf_reserved(check_reserved_t is_reserved,
break; break;
} }
if (size >= (16UL<<20) || size == old_size) { if (size < (16UL<<20) && size != old_size)
printk(KERN_INFO PREFIX "MMCONFIG at %pR reserved in %s\n", return 0;
&cfg->res,
with_e820 ? "E820" : "ACPI motherboard resources"); if (dev)
valid = 1; dev_info(dev, "MMCONFIG at %pR reserved in %s\n",
&cfg->res, method);
if (old_size != size) { else
/* update end_bus */ printk(KERN_INFO PREFIX
cfg->end_bus = cfg->start_bus + ((size>>20) - 1); "MMCONFIG at %pR reserved in %s\n",
num_buses = cfg->end_bus - cfg->start_bus + 1; &cfg->res, method);
cfg->res.end = cfg->res.start +
PCI_MMCFG_BUS_OFFSET(num_buses) - 1; if (old_size != size) {
snprintf(cfg->name, PCI_MMCFG_RESOURCE_NAME_LEN, /* update end_bus */
"PCI MMCONFIG %04x [bus %02x-%02x]", cfg->end_bus = cfg->start_bus + ((size>>20) - 1);
cfg->segment, cfg->start_bus, cfg->end_bus); num_buses = cfg->end_bus - cfg->start_bus + 1;
cfg->res.end = cfg->res.start +
PCI_MMCFG_BUS_OFFSET(num_buses) - 1;
snprintf(cfg->name, PCI_MMCFG_RESOURCE_NAME_LEN,
"PCI MMCONFIG %04x [bus %02x-%02x]",
cfg->segment, cfg->start_bus, cfg->end_bus);
if (dev)
dev_info(dev,
"MMCONFIG "
"at %pR (base %#lx) (size reduced!)\n",
&cfg->res, (unsigned long) cfg->address);
else
printk(KERN_INFO PREFIX printk(KERN_INFO PREFIX
"MMCONFIG for %04x [bus%02x-%02x] " "MMCONFIG for %04x [bus%02x-%02x] "
"at %pR (base %#lx) (size reduced!)\n", "at %pR (base %#lx) (size reduced!)\n",
cfg->segment, cfg->start_bus, cfg->end_bus, cfg->segment, cfg->start_bus, cfg->end_bus,
&cfg->res, (unsigned long) cfg->address); &cfg->res, (unsigned long) cfg->address);
}
} }
return valid; return 1;
} }
static int __devinit pci_mmcfg_check_reserved(struct pci_mmcfg_region *cfg, static int __ref pci_mmcfg_check_reserved(struct device *dev,
int early) struct pci_mmcfg_region *cfg, int early)
{ {
if (!early && !acpi_disabled) { if (!early && !acpi_disabled) {
if (is_mmconf_reserved(is_acpi_reserved, cfg, 0)) if (is_mmconf_reserved(is_acpi_reserved, cfg, dev, 0))
return 1; return 1;
if (dev)
dev_info(dev, FW_INFO
"MMCONFIG at %pR not reserved in "
"ACPI motherboard resources\n",
&cfg->res);
else else
printk(KERN_ERR FW_BUG PREFIX printk(KERN_INFO FW_INFO PREFIX
"MMCONFIG at %pR not reserved in " "MMCONFIG at %pR not reserved in "
"ACPI motherboard resources\n", "ACPI motherboard resources\n",
&cfg->res); &cfg->res);
} }
/*
* e820_all_mapped() is marked as __init.
* All entries from ACPI MCFG table have been checked at boot time.
* For MCFG information constructed from hotpluggable host bridge's
* _CBA method, just assume it's reserved.
*/
if (pci_mmcfg_running_state)
return 1;
/* Don't try to do this check unless configuration /* Don't try to do this check unless configuration
type 1 is available. how about type 2 ?*/ type 1 is available. how about type 2 ?*/
if (raw_pci_ops) if (raw_pci_ops)
return is_mmconf_reserved(e820_all_mapped, cfg, 1); return is_mmconf_reserved(e820_all_mapped, cfg, dev, 1);
return 0; return 0;
} }
...@@ -517,7 +547,7 @@ static void __init pci_mmcfg_reject_broken(int early) ...@@ -517,7 +547,7 @@ static void __init pci_mmcfg_reject_broken(int early)
struct pci_mmcfg_region *cfg; struct pci_mmcfg_region *cfg;
list_for_each_entry(cfg, &pci_mmcfg_list, list) { list_for_each_entry(cfg, &pci_mmcfg_list, list) {
if (pci_mmcfg_check_reserved(cfg, early) == 0) { if (pci_mmcfg_check_reserved(NULL, cfg, early) == 0) {
printk(KERN_INFO PREFIX "not using MMCONFIG\n"); printk(KERN_INFO PREFIX "not using MMCONFIG\n");
free_all_mmcfg(); free_all_mmcfg();
return; return;
...@@ -656,6 +686,8 @@ void __init pci_mmcfg_late_init(void) ...@@ -656,6 +686,8 @@ void __init pci_mmcfg_late_init(void)
static int __init pci_mmcfg_late_insert_resources(void) static int __init pci_mmcfg_late_insert_resources(void)
{ {
pci_mmcfg_running_state = true;
/* /*
* If resources are already inserted or we are not using MMCONFIG, * If resources are already inserted or we are not using MMCONFIG,
* don't insert the resources. * don't insert the resources.
......
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