diff options
Diffstat (limited to 'arch/x86/pci/acpi.c')
-rw-r--r-- | arch/x86/pci/acpi.c | 109 |
1 files changed, 95 insertions, 14 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index fc09c2754e08..505acdd6d600 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c | |||
@@ -12,8 +12,13 @@ struct pci_root_info { | |||
12 | char name[16]; | 12 | char name[16]; |
13 | unsigned int res_num; | 13 | unsigned int res_num; |
14 | struct resource *res; | 14 | struct resource *res; |
15 | int busnum; | ||
16 | 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 | ||
17 | }; | 22 | }; |
18 | 23 | ||
19 | static bool pci_use_crs = true; | 24 | static bool pci_use_crs = true; |
@@ -120,6 +125,81 @@ void __init pci_acpi_crs_quirks(void) | |||
120 | pci_use_crs ? "nocrs" : "use_crs"); | 125 | pci_use_crs ? "nocrs" : "use_crs"); |
121 | } | 126 | } |
122 | 127 | ||
128 | #ifdef CONFIG_PCI_MMCONFIG | ||
129 | static 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 | |||
152 | static 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 | |||
183 | static 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 | ||
192 | static 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 | } | ||
198 | static void teardown_mcfg_map(struct pci_root_info *info) | ||
199 | { | ||
200 | } | ||
201 | #endif | ||
202 | |||
123 | static acpi_status | 203 | static acpi_status |
124 | resource_to_addr(struct acpi_resource *resource, | 204 | resource_to_addr(struct acpi_resource *resource, |
125 | struct acpi_resource_address64 *addr) | 205 | struct acpi_resource_address64 *addr) |
@@ -234,13 +314,6 @@ setup_resource(struct acpi_resource *acpi_res, void *data) | |||
234 | } | 314 | } |
235 | 315 | ||
236 | info->res_num++; | 316 | info->res_num++; |
237 | if (addr.translation_offset) | ||
238 | dev_info(&info->bridge->dev, "host bridge window %pR " | ||
239 | "(PCI address [%#llx-%#llx])\n", | ||
240 | res, res->start - addr.translation_offset, | ||
241 | res->end - addr.translation_offset); | ||
242 | else | ||
243 | dev_info(&info->bridge->dev, "host bridge window %pR\n", res); | ||
244 | 317 | ||
245 | return AE_OK; | 318 | return AE_OK; |
246 | } | 319 | } |
@@ -332,8 +405,11 @@ static void __release_pci_root_info(struct pci_root_info *info) | |||
332 | 405 | ||
333 | free_pci_root_info_res(info); | 406 | free_pci_root_info_res(info); |
334 | 407 | ||
408 | teardown_mcfg_map(info); | ||
409 | |||
335 | kfree(info); | 410 | kfree(info); |
336 | } | 411 | } |
412 | |||
337 | static void release_pci_root_info(struct pci_host_bridge *bridge) | 413 | static void release_pci_root_info(struct pci_host_bridge *bridge) |
338 | { | 414 | { |
339 | struct pci_root_info *info = bridge->release_data; | 415 | struct pci_root_info *info = bridge->release_data; |
@@ -347,7 +423,9 @@ probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device, | |||
347 | { | 423 | { |
348 | size_t size; | 424 | size_t size; |
349 | 425 | ||
426 | sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum); | ||
350 | info->bridge = device; | 427 | info->bridge = device; |
428 | |||
351 | info->res_num = 0; | 429 | info->res_num = 0; |
352 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, | 430 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, |
353 | info); | 431 | info); |
@@ -360,8 +438,6 @@ probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device, | |||
360 | if (!info->res) | 438 | if (!info->res) |
361 | return; | 439 | return; |
362 | 440 | ||
363 | sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum); | ||
364 | |||
365 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, | 441 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, |
366 | info); | 442 | info); |
367 | } | 443 | } |
@@ -373,7 +449,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
373 | int domain = root->segment; | 449 | int domain = root->segment; |
374 | int busnum = root->secondary.start; | 450 | int busnum = root->secondary.start; |
375 | LIST_HEAD(resources); | 451 | LIST_HEAD(resources); |
376 | struct pci_bus *bus; | 452 | struct pci_bus *bus = NULL; |
377 | struct pci_sysdata *sd; | 453 | struct pci_sysdata *sd; |
378 | int node; | 454 | int node; |
379 | #ifdef CONFIG_ACPI_NUMA | 455 | #ifdef CONFIG_ACPI_NUMA |
@@ -426,6 +502,8 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
426 | } else { | 502 | } else { |
427 | probe_pci_root_info(info, device, busnum, domain); | 503 | probe_pci_root_info(info, device, busnum, domain); |
428 | 504 | ||
505 | /* insert busn res at first */ | ||
506 | pci_add_resource(&resources, &root->secondary); | ||
429 | /* | 507 | /* |
430 | * _CRS with no apertures is normal, so only fall back to | 508 | * _CRS with no apertures is normal, so only fall back to |
431 | * defaults or native bridge info if we're ignoring _CRS. | 509 | * defaults or native bridge info if we're ignoring _CRS. |
@@ -437,10 +515,13 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
437 | x86_pci_root_bus_resources(busnum, &resources); | 515 | x86_pci_root_bus_resources(busnum, &resources); |
438 | } | 516 | } |
439 | 517 | ||
440 | bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd, | 518 | if (!setup_mcfg_map(info, domain, (u8)root->secondary.start, |
441 | &resources); | 519 | (u8)root->secondary.end, root->mcfg_addr)) |
520 | bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, | ||
521 | sd, &resources); | ||
522 | |||
442 | if (bus) { | 523 | if (bus) { |
443 | bus->subordinate = pci_scan_child_bus(bus); | 524 | pci_scan_child_bus(bus); |
444 | pci_set_host_bridge_release( | 525 | pci_set_host_bridge_release( |
445 | to_pci_host_bridge(bus->bridge), | 526 | to_pci_host_bridge(bus->bridge), |
446 | release_pci_root_info, info); | 527 | release_pci_root_info, info); |