Commit c0fa4078 authored by Jiang Liu's avatar Jiang Liu Committed by Bjorn Helgaas

x86/PCI: update MMCONFIG information when hot-plugging PCI host bridges

This patch enhances x86 arch-specific code to update MMCONFIG information
when PCI host bridge hotplug event happens.
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 f4b57a3b
...@@ -100,6 +100,7 @@ struct pci_raw_ops { ...@@ -100,6 +100,7 @@ struct pci_raw_ops {
extern const struct pci_raw_ops *raw_pci_ops; extern const struct pci_raw_ops *raw_pci_ops;
extern const struct pci_raw_ops *raw_pci_ext_ops; extern const struct pci_raw_ops *raw_pci_ext_ops;
extern const struct pci_raw_ops pci_mmcfg;
extern const struct pci_raw_ops pci_direct_conf1; extern const struct pci_raw_ops pci_direct_conf1;
extern bool port_cf9_safe; extern bool port_cf9_safe;
......
...@@ -13,6 +13,12 @@ struct pci_root_info { ...@@ -13,6 +13,12 @@ struct pci_root_info {
unsigned int res_num; unsigned int res_num;
struct resource *res; struct resource *res;
struct pci_sysdata sd; struct pci_sysdata sd;
#ifdef CONFIG_PCI_MMCONFIG
bool mcfg_added;
u16 segment;
u8 start_bus;
u8 end_bus;
#endif
}; };
static bool pci_use_crs = true; static bool pci_use_crs = true;
...@@ -119,6 +125,81 @@ void __init pci_acpi_crs_quirks(void) ...@@ -119,6 +125,81 @@ void __init pci_acpi_crs_quirks(void)
pci_use_crs ? "nocrs" : "use_crs"); pci_use_crs ? "nocrs" : "use_crs");
} }
#ifdef CONFIG_PCI_MMCONFIG
static int __devinit check_segment(u16 seg, struct device *dev, char *estr)
{
if (seg) {
dev_err(dev,
"%s can't access PCI configuration "
"space under this host bridge.\n",
estr);
return -EIO;
}
/*
* Failure in adding MMCFG information is not fatal,
* just can't access extended configuration space of
* devices under this host bridge.
*/
dev_warn(dev,
"%s can't access extended PCI configuration "
"space under this bridge.\n",
estr);
return 0;
}
static int __devinit setup_mcfg_map(struct pci_root_info *info,
u16 seg, u8 start, u8 end,
phys_addr_t addr)
{
int result;
struct device *dev = &info->bridge->dev;
info->start_bus = start;
info->end_bus = end;
info->mcfg_added = false;
/* return success if MMCFG is not in use */
if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg)
return 0;
if (!(pci_probe & PCI_PROBE_MMCONF))
return check_segment(seg, dev, "MMCONFIG is disabled,");
result = pci_mmconfig_insert(dev, seg, start, end, addr);
if (result == 0) {
/* enable MMCFG if it hasn't been enabled yet */
if (raw_pci_ext_ops == NULL)
raw_pci_ext_ops = &pci_mmcfg;
info->mcfg_added = true;
} else if (result != -EEXIST)
return check_segment(seg, dev,
"fail to add MMCONFIG information,");
return 0;
}
static void teardown_mcfg_map(struct pci_root_info *info)
{
if (info->mcfg_added) {
pci_mmconfig_delete(info->segment, info->start_bus,
info->end_bus);
info->mcfg_added = false;
}
}
#else
static int __devinit setup_mcfg_map(struct pci_root_info *info,
u16 seg, u8 start, u8 end,
phys_addr_t addr)
{
return 0;
}
static void teardown_mcfg_map(struct pci_root_info *info)
{
}
#endif
static acpi_status static acpi_status
resource_to_addr(struct acpi_resource *resource, resource_to_addr(struct acpi_resource *resource,
struct acpi_resource_address64 *addr) struct acpi_resource_address64 *addr)
...@@ -331,8 +412,11 @@ static void __release_pci_root_info(struct pci_root_info *info) ...@@ -331,8 +412,11 @@ static void __release_pci_root_info(struct pci_root_info *info)
free_pci_root_info_res(info); free_pci_root_info_res(info);
teardown_mcfg_map(info);
kfree(info); kfree(info);
} }
static void release_pci_root_info(struct pci_host_bridge *bridge) static void release_pci_root_info(struct pci_host_bridge *bridge)
{ {
struct pci_root_info *info = bridge->release_data; struct pci_root_info *info = bridge->release_data;
...@@ -372,7 +456,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) ...@@ -372,7 +456,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
int domain = root->segment; int domain = root->segment;
int busnum = root->secondary.start; int busnum = root->secondary.start;
LIST_HEAD(resources); LIST_HEAD(resources);
struct pci_bus *bus; struct pci_bus *bus = NULL;
struct pci_sysdata *sd; struct pci_sysdata *sd;
int node; int node;
#ifdef CONFIG_ACPI_NUMA #ifdef CONFIG_ACPI_NUMA
...@@ -438,8 +522,11 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) ...@@ -438,8 +522,11 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
x86_pci_root_bus_resources(busnum, &resources); x86_pci_root_bus_resources(busnum, &resources);
} }
bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd, if (!setup_mcfg_map(info, domain, (u8)root->secondary.start,
&resources); (u8)root->secondary.end, root->mcfg_addr))
bus = pci_create_root_bus(NULL, busnum, &pci_root_ops,
sd, &resources);
if (bus) { if (bus) {
pci_scan_child_bus(bus); pci_scan_child_bus(bus);
pci_set_host_bridge_release( pci_set_host_bridge_release(
......
...@@ -126,7 +126,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus, ...@@ -126,7 +126,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
return 0; return 0;
} }
static const struct pci_raw_ops pci_mmcfg = { const struct pci_raw_ops pci_mmcfg = {
.read = pci_mmcfg_read, .read = pci_mmcfg_read,
.write = pci_mmcfg_write, .write = pci_mmcfg_write,
}; };
......
...@@ -90,7 +90,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus, ...@@ -90,7 +90,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
return 0; return 0;
} }
static const struct pci_raw_ops pci_mmcfg = { const struct pci_raw_ops pci_mmcfg = {
.read = pci_mmcfg_read, .read = pci_mmcfg_read,
.write = pci_mmcfg_write, .write = pci_mmcfg_write,
}; };
......
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