aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@linux.intel.com>2015-02-05 00:44:46 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-02-05 09:09:26 -0500
commit593669c2ac0fe18baee04a3cd5539a148aa48574 (patch)
tree67dfe1062d3c565c8fa0ab93e6b7cc6d7fbd5e64
parent812dbd9994f122629db73205a7f7f46b430a6360 (diff)
x86/PCI/ACPI: Use common ACPI resource interfaces to simplify implementation
Use common ACPI resource discovery interfaces to simplify PCI host bridge resource enumeration. Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> Acked-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--arch/x86/pci/acpi.c295
1 files changed, 91 insertions, 204 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 1d725d99963d..6ac273832f28 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -10,9 +10,6 @@
10struct pci_root_info { 10struct pci_root_info {
11 struct acpi_device *bridge; 11 struct acpi_device *bridge;
12 char name[16]; 12 char name[16];
13 unsigned int res_num;
14 struct resource *res;
15 resource_size_t *res_offset;
16 struct pci_sysdata sd; 13 struct pci_sysdata sd;
17#ifdef CONFIG_PCI_MMCONFIG 14#ifdef CONFIG_PCI_MMCONFIG
18 bool mcfg_added; 15 bool mcfg_added;
@@ -218,132 +215,41 @@ static void teardown_mcfg_map(struct pci_root_info *info)
218} 215}
219#endif 216#endif
220 217
221static acpi_status resource_to_addr(struct acpi_resource *resource, 218static void validate_resources(struct device *dev, struct list_head *crs_res,
222 struct acpi_resource_address64 *addr) 219 unsigned long type)
223{
224 acpi_status status;
225 struct acpi_resource_memory24 *memory24;
226 struct acpi_resource_memory32 *memory32;
227 struct acpi_resource_fixed_memory32 *fixed_memory32;
228
229 memset(addr, 0, sizeof(*addr));
230 switch (resource->type) {
231 case ACPI_RESOURCE_TYPE_MEMORY24:
232 memory24 = &resource->data.memory24;
233 addr->resource_type = ACPI_MEMORY_RANGE;
234 addr->address.minimum = memory24->minimum;
235 addr->address.address_length = memory24->address_length;
236 addr->address.maximum = addr->address.minimum + addr->address.address_length - 1;
237 return AE_OK;
238 case ACPI_RESOURCE_TYPE_MEMORY32:
239 memory32 = &resource->data.memory32;
240 addr->resource_type = ACPI_MEMORY_RANGE;
241 addr->address.minimum = memory32->minimum;
242 addr->address.address_length = memory32->address_length;
243 addr->address.maximum = addr->address.minimum + addr->address.address_length - 1;
244 return AE_OK;
245 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
246 fixed_memory32 = &resource->data.fixed_memory32;
247 addr->resource_type = ACPI_MEMORY_RANGE;
248 addr->address.minimum = fixed_memory32->address;
249 addr->address.address_length = fixed_memory32->address_length;
250 addr->address.maximum = addr->address.minimum + addr->address.address_length - 1;
251 return AE_OK;
252 case ACPI_RESOURCE_TYPE_ADDRESS16:
253 case ACPI_RESOURCE_TYPE_ADDRESS32:
254 case ACPI_RESOURCE_TYPE_ADDRESS64:
255 status = acpi_resource_to_address64(resource, addr);
256 if (ACPI_SUCCESS(status) &&
257 (addr->resource_type == ACPI_MEMORY_RANGE ||
258 addr->resource_type == ACPI_IO_RANGE) &&
259 addr->address.address_length > 0) {
260 return AE_OK;
261 }
262 break;
263 }
264 return AE_ERROR;
265}
266
267static acpi_status count_resource(struct acpi_resource *acpi_res, void *data)
268{ 220{
269 struct pci_root_info *info = data; 221 LIST_HEAD(list);
270 struct acpi_resource_address64 addr; 222 struct resource *res1, *res2, *root = NULL;
271 acpi_status status; 223 struct resource_entry *tmp, *entry, *entry2;
272
273 status = resource_to_addr(acpi_res, &addr);
274 if (ACPI_SUCCESS(status))
275 info->res_num++;
276 return AE_OK;
277}
278
279static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data)
280{
281 struct pci_root_info *info = data;
282 struct resource *res;
283 struct acpi_resource_address64 addr;
284 acpi_status status;
285 unsigned long flags;
286 u64 start, orig_end, end, res_end;
287
288 status = resource_to_addr(acpi_res, &addr);
289 if (!ACPI_SUCCESS(status))
290 return AE_OK;
291
292 if (addr.resource_type == ACPI_MEMORY_RANGE) {
293 flags = IORESOURCE_MEM;
294 if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
295 flags |= IORESOURCE_PREFETCH;
296 res_end = (u64)iomem_resource.end;
297 } else if (addr.resource_type == ACPI_IO_RANGE) {
298 flags = IORESOURCE_IO;
299 res_end = (u64)ioport_resource.end;
300 } else
301 return AE_OK;
302
303 start = addr.address.minimum + addr.address.translation_offset;
304 orig_end = end = addr.address.maximum + addr.address.translation_offset;
305
306 /* Exclude non-addressable range or non-addressable portion of range */
307 end = min(end, res_end);
308 if (end <= start) {
309 dev_info(&info->bridge->dev,
310 "host bridge window [%#llx-%#llx] "
311 "(ignored, not CPU addressable)\n", start, orig_end);
312 return AE_OK;
313 } else if (orig_end != end) {
314 dev_info(&info->bridge->dev,
315 "host bridge window [%#llx-%#llx] "
316 "([%#llx-%#llx] ignored, not CPU addressable)\n",
317 start, orig_end, end + 1, orig_end);
318 }
319 224
320 res = &info->res[info->res_num]; 225 BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
321 res->name = info->name; 226 root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
322 res->flags = flags;
323 res->start = start;
324 res->end = end;
325 info->res_offset[info->res_num] = addr.address.translation_offset;
326 info->res_num++;
327 227
328 if (!pci_use_crs) 228 list_splice_init(crs_res, &list);
329 dev_printk(KERN_DEBUG, &info->bridge->dev, 229 resource_list_for_each_entry_safe(entry, tmp, &list) {
330 "host bridge window %pR (ignored)\n", res); 230 bool free = false;
231 resource_size_t end;
331 232
332 return AE_OK; 233 res1 = entry->res;
333}
334
335static void coalesce_windows(struct pci_root_info *info, unsigned long type)
336{
337 int i, j;
338 struct resource *res1, *res2;
339
340 for (i = 0; i < info->res_num; i++) {
341 res1 = &info->res[i];
342 if (!(res1->flags & type)) 234 if (!(res1->flags & type))
343 continue; 235 goto next;
236
237 /* Exclude non-addressable range or non-addressable portion */
238 end = min(res1->end, root->end);
239 if (end <= res1->start) {
240 dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
241 res1);
242 free = true;
243 goto next;
244 } else if (res1->end != end) {
245 dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
246 res1, (unsigned long long)end + 1,
247 (unsigned long long)res1->end);
248 res1->end = end;
249 }
344 250
345 for (j = i + 1; j < info->res_num; j++) { 251 resource_list_for_each_entry(entry2, crs_res) {
346 res2 = &info->res[j]; 252 res2 = entry2->res;
347 if (!(res2->flags & type)) 253 if (!(res2->flags & type))
348 continue; 254 continue;
349 255
@@ -355,118 +261,92 @@ static void coalesce_windows(struct pci_root_info *info, unsigned long type)
355 if (resource_overlaps(res1, res2)) { 261 if (resource_overlaps(res1, res2)) {
356 res2->start = min(res1->start, res2->start); 262 res2->start = min(res1->start, res2->start);
357 res2->end = max(res1->end, res2->end); 263 res2->end = max(res1->end, res2->end);
358 dev_info(&info->bridge->dev, 264 dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
359 "host bridge window expanded to %pR; %pR ignored\n",
360 res2, res1); 265 res2, res1);
361 res1->flags = 0; 266 free = true;
267 goto next;
362 } 268 }
363 } 269 }
270
271next:
272 resource_list_del(entry);
273 if (free)
274 resource_list_free_entry(entry);
275 else
276 resource_list_add_tail(entry, crs_res);
364 } 277 }
365} 278}
366 279
367static void add_resources(struct pci_root_info *info, 280static void add_resources(struct pci_root_info *info,
368 struct list_head *resources) 281 struct list_head *resources,
282 struct list_head *crs_res)
369{ 283{
370 int i; 284 struct resource_entry *entry, *tmp;
371 struct resource *res, *root, *conflict; 285 struct resource *res, *conflict, *root = NULL;
372
373 coalesce_windows(info, IORESOURCE_MEM);
374 coalesce_windows(info, IORESOURCE_IO);
375 286
376 for (i = 0; i < info->res_num; i++) { 287 validate_resources(&info->bridge->dev, crs_res, IORESOURCE_MEM);
377 res = &info->res[i]; 288 validate_resources(&info->bridge->dev, crs_res, IORESOURCE_IO);
378 289
290 resource_list_for_each_entry_safe(entry, tmp, crs_res) {
291 res = entry->res;
379 if (res->flags & IORESOURCE_MEM) 292 if (res->flags & IORESOURCE_MEM)
380 root = &iomem_resource; 293 root = &iomem_resource;
381 else if (res->flags & IORESOURCE_IO) 294 else if (res->flags & IORESOURCE_IO)
382 root = &ioport_resource; 295 root = &ioport_resource;
383 else 296 else
384 continue; 297 BUG_ON(res);
385 298
386 conflict = insert_resource_conflict(root, res); 299 conflict = insert_resource_conflict(root, res);
387 if (conflict) 300 if (conflict) {
388 dev_info(&info->bridge->dev, 301 dev_info(&info->bridge->dev,
389 "ignoring host bridge window %pR (conflicts with %s %pR)\n", 302 "ignoring host bridge window %pR (conflicts with %s %pR)\n",
390 res, conflict->name, conflict); 303 res, conflict->name, conflict);
391 else 304 resource_list_destroy_entry(entry);
392 pci_add_resource_offset(resources, res, 305 }
393 info->res_offset[i]);
394 } 306 }
395}
396 307
397static void free_pci_root_info_res(struct pci_root_info *info) 308 list_splice_tail(crs_res, resources);
398{
399 kfree(info->res);
400 info->res = NULL;
401 kfree(info->res_offset);
402 info->res_offset = NULL;
403 info->res_num = 0;
404} 309}
405 310
406static void __release_pci_root_info(struct pci_root_info *info) 311static void release_pci_root_info(struct pci_host_bridge *bridge)
407{ 312{
408 int i;
409 struct resource *res; 313 struct resource *res;
314 struct resource_entry *entry;
315 struct pci_root_info *info = bridge->release_data;
410 316
411 for (i = 0; i < info->res_num; i++) { 317 resource_list_for_each_entry(entry, &bridge->windows) {
412 res = &info->res[i]; 318 res = entry->res;
413 319 if (res->parent &&
414 if (!res->parent) 320 (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
415 continue; 321 release_resource(res);
416
417 if (!(res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
418 continue;
419
420 release_resource(res);
421 } 322 }
422 323
423 free_pci_root_info_res(info);
424
425 teardown_mcfg_map(info); 324 teardown_mcfg_map(info);
426
427 kfree(info); 325 kfree(info);
428} 326}
429 327
430static void release_pci_root_info(struct pci_host_bridge *bridge)
431{
432 struct pci_root_info *info = bridge->release_data;
433
434 __release_pci_root_info(info);
435}
436
437static void probe_pci_root_info(struct pci_root_info *info, 328static void probe_pci_root_info(struct pci_root_info *info,
438 struct acpi_device *device, 329 struct acpi_device *device,
439 int busnum, int domain) 330 int busnum, int domain,
331 struct list_head *list)
440{ 332{
441 size_t size; 333 int ret;
334 struct resource_entry *entry;
442 335
443 sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum); 336 sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum);
444 info->bridge = device; 337 info->bridge = device;
445 338 ret = acpi_dev_get_resources(device, list,
446 info->res_num = 0; 339 acpi_dev_filter_resource_type_cb,
447 acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, 340 (void *)(IORESOURCE_IO | IORESOURCE_MEM));
448 info); 341 if (ret < 0)
449 if (!info->res_num) 342 dev_warn(&device->dev,
450 return; 343 "failed to parse _CRS method, error code %d\n", ret);
451 344 else if (ret == 0)
452 size = sizeof(*info->res) * info->res_num; 345 dev_dbg(&device->dev,
453 info->res = kzalloc_node(size, GFP_KERNEL, info->sd.node); 346 "no IO and memory resources present in _CRS\n");
454 if (!info->res) { 347 else
455 info->res_num = 0; 348 resource_list_for_each_entry(entry, list)
456 return; 349 entry->res->name = info->name;
457 }
458
459 size = sizeof(*info->res_offset) * info->res_num;
460 info->res_num = 0;
461 info->res_offset = kzalloc_node(size, GFP_KERNEL, info->sd.node);
462 if (!info->res_offset) {
463 kfree(info->res);
464 info->res = NULL;
465 return;
466 }
467
468 acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
469 info);
470} 350}
471 351
472struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) 352struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
@@ -475,6 +355,8 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
475 struct pci_root_info *info; 355 struct pci_root_info *info;
476 int domain = root->segment; 356 int domain = root->segment;
477 int busnum = root->secondary.start; 357 int busnum = root->secondary.start;
358 struct resource_entry *res_entry;
359 LIST_HEAD(crs_res);
478 LIST_HEAD(resources); 360 LIST_HEAD(resources);
479 struct pci_bus *bus; 361 struct pci_bus *bus;
480 struct pci_sysdata *sd; 362 struct pci_sysdata *sd;
@@ -522,18 +404,22 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
522 memcpy(bus->sysdata, sd, sizeof(*sd)); 404 memcpy(bus->sysdata, sd, sizeof(*sd));
523 kfree(info); 405 kfree(info);
524 } else { 406 } else {
525 probe_pci_root_info(info, device, busnum, domain);
526
527 /* insert busn res at first */ 407 /* insert busn res at first */
528 pci_add_resource(&resources, &root->secondary); 408 pci_add_resource(&resources, &root->secondary);
409
529 /* 410 /*
530 * _CRS with no apertures is normal, so only fall back to 411 * _CRS with no apertures is normal, so only fall back to
531 * defaults or native bridge info if we're ignoring _CRS. 412 * defaults or native bridge info if we're ignoring _CRS.
532 */ 413 */
533 if (pci_use_crs) 414 probe_pci_root_info(info, device, busnum, domain, &crs_res);
534 add_resources(info, &resources); 415 if (pci_use_crs) {
535 else { 416 add_resources(info, &resources, &crs_res);
536 free_pci_root_info_res(info); 417 } else {
418 resource_list_for_each_entry(res_entry, &crs_res)
419 dev_printk(KERN_DEBUG, &device->dev,
420 "host bridge window %pR (ignored)\n",
421 res_entry->res);
422 resource_list_free(&crs_res);
537 x86_pci_root_bus_resources(busnum, &resources); 423 x86_pci_root_bus_resources(busnum, &resources);
538 } 424 }
539 425
@@ -548,8 +434,9 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
548 to_pci_host_bridge(bus->bridge), 434 to_pci_host_bridge(bus->bridge),
549 release_pci_root_info, info); 435 release_pci_root_info, info);
550 } else { 436 } else {
551 pci_free_resource_list(&resources); 437 resource_list_free(&resources);
552 __release_pci_root_info(info); 438 teardown_mcfg_map(info);
439 kfree(info);
553 } 440 }
554 } 441 }
555 442