aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/pci
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@huawei.com>2012-06-22 02:55:17 -0400
committerBjorn Helgaas <bhelgaas@google.com>2012-06-22 17:17:00 -0400
commitc0fa40784cce9cc66b54499a3762cfe07e35353f (patch)
tree4dbb2c3b42a04be757ff44705af56e047aa66862 /arch/x86/pci
parentf4b57a3b4352f72e461e362cb25917e28bdba80f (diff)
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: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Jiang Liu <liuj97@gmail.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'arch/x86/pci')
-rw-r--r--arch/x86/pci/acpi.c93
-rw-r--r--arch/x86/pci/mmconfig_32.c2
-rw-r--r--arch/x86/pci/mmconfig_64.c2
3 files changed, 92 insertions, 5 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 2bb885afe103..912b54b26d6a 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -13,6 +13,12 @@ struct pci_root_info {
13 unsigned int res_num; 13 unsigned int res_num;
14 struct resource *res; 14 struct resource *res;
15 struct pci_sysdata sd; 15 struct pci_sysdata sd;
16#ifdef CONFIG_PCI_MMCONFIG
17 bool mcfg_added;
18 u16 segment;
19 u8 start_bus;
20 u8 end_bus;
21#endif
16}; 22};
17 23
18static bool pci_use_crs = true; 24static bool pci_use_crs = true;
@@ -119,6 +125,81 @@ void __init pci_acpi_crs_quirks(void)
119 pci_use_crs ? "nocrs" : "use_crs"); 125 pci_use_crs ? "nocrs" : "use_crs");
120} 126}
121 127
128#ifdef CONFIG_PCI_MMCONFIG
129static int __devinit check_segment(u16 seg, struct device *dev, char *estr)
130{
131 if (seg) {
132 dev_err(dev,
133 "%s can't access PCI configuration "
134 "space under this host bridge.\n",
135 estr);
136 return -EIO;
137 }
138
139 /*
140 * Failure in adding MMCFG information is not fatal,
141 * just can't access extended configuration space of
142 * devices under this host bridge.
143 */
144 dev_warn(dev,
145 "%s can't access extended PCI configuration "
146 "space under this bridge.\n",
147 estr);
148
149 return 0;
150}
151
152static int __devinit setup_mcfg_map(struct pci_root_info *info,
153 u16 seg, u8 start, u8 end,
154 phys_addr_t addr)
155{
156 int result;
157 struct device *dev = &info->bridge->dev;
158
159 info->start_bus = start;
160 info->end_bus = end;
161 info->mcfg_added = false;
162
163 /* return success if MMCFG is not in use */
164 if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg)
165 return 0;
166
167 if (!(pci_probe & PCI_PROBE_MMCONF))
168 return check_segment(seg, dev, "MMCONFIG is disabled,");
169
170 result = pci_mmconfig_insert(dev, seg, start, end, addr);
171 if (result == 0) {
172 /* enable MMCFG if it hasn't been enabled yet */
173 if (raw_pci_ext_ops == NULL)
174 raw_pci_ext_ops = &pci_mmcfg;
175 info->mcfg_added = true;
176 } else if (result != -EEXIST)
177 return check_segment(seg, dev,
178 "fail to add MMCONFIG information,");
179
180 return 0;
181}
182
183static void teardown_mcfg_map(struct pci_root_info *info)
184{
185 if (info->mcfg_added) {
186 pci_mmconfig_delete(info->segment, info->start_bus,
187 info->end_bus);
188 info->mcfg_added = false;
189 }
190}
191#else
192static int __devinit setup_mcfg_map(struct pci_root_info *info,
193 u16 seg, u8 start, u8 end,
194 phys_addr_t addr)
195{
196 return 0;
197}
198static void teardown_mcfg_map(struct pci_root_info *info)
199{
200}
201#endif
202
122static acpi_status 203static acpi_status
123resource_to_addr(struct acpi_resource *resource, 204resource_to_addr(struct acpi_resource *resource,
124 struct acpi_resource_address64 *addr) 205 struct acpi_resource_address64 *addr)
@@ -331,8 +412,11 @@ static void __release_pci_root_info(struct pci_root_info *info)
331 412
332 free_pci_root_info_res(info); 413 free_pci_root_info_res(info);
333 414
415 teardown_mcfg_map(info);
416
334 kfree(info); 417 kfree(info);
335} 418}
419
336static void release_pci_root_info(struct pci_host_bridge *bridge) 420static void release_pci_root_info(struct pci_host_bridge *bridge)
337{ 421{
338 struct pci_root_info *info = bridge->release_data; 422 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 int domain = root->segment; 456 int domain = root->segment;
373 int busnum = root->secondary.start; 457 int busnum = root->secondary.start;
374 LIST_HEAD(resources); 458 LIST_HEAD(resources);
375 struct pci_bus *bus; 459 struct pci_bus *bus = NULL;
376 struct pci_sysdata *sd; 460 struct pci_sysdata *sd;
377 int node; 461 int node;
378#ifdef CONFIG_ACPI_NUMA 462#ifdef CONFIG_ACPI_NUMA
@@ -438,8 +522,11 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
438 x86_pci_root_bus_resources(busnum, &resources); 522 x86_pci_root_bus_resources(busnum, &resources);
439 } 523 }
440 524
441 bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd, 525 if (!setup_mcfg_map(info, domain, (u8)root->secondary.start,
442 &resources); 526 (u8)root->secondary.end, root->mcfg_addr))
527 bus = pci_create_root_bus(NULL, busnum, &pci_root_ops,
528 sd, &resources);
529
443 if (bus) { 530 if (bus) {
444 pci_scan_child_bus(bus); 531 pci_scan_child_bus(bus);
445 pci_set_host_bridge_release( 532 pci_set_host_bridge_release(
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c
index a22785deb50e..db63ac23e3d9 100644
--- a/arch/x86/pci/mmconfig_32.c
+++ b/arch/x86/pci/mmconfig_32.c
@@ -126,7 +126,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
126 return 0; 126 return 0;
127} 127}
128 128
129static const struct pci_raw_ops pci_mmcfg = { 129const struct pci_raw_ops pci_mmcfg = {
130 .read = pci_mmcfg_read, 130 .read = pci_mmcfg_read,
131 .write = pci_mmcfg_write, 131 .write = pci_mmcfg_write,
132}; 132};
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c
index ebefea5107a7..c206521fe98e 100644
--- a/arch/x86/pci/mmconfig_64.c
+++ b/arch/x86/pci/mmconfig_64.c
@@ -90,7 +90,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
90 return 0; 90 return 0;
91} 91}
92 92
93static const struct pci_raw_ops pci_mmcfg = { 93const struct pci_raw_ops pci_mmcfg = {
94 .read = pci_mmcfg_read, 94 .read = pci_mmcfg_read,
95 .write = pci_mmcfg_write, 95 .write = pci_mmcfg_write,
96}; 96};