aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/pci_root.c81
-rw-r--r--include/acpi/acpi_drivers.h1
2 files changed, 82 insertions, 0 deletions
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 888cb9f5c5fb..e5099919e574 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -329,6 +329,87 @@ static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
329 return NULL; 329 return NULL;
330} 330}
331 331
332struct acpi_handle_node {
333 struct list_head node;
334 acpi_handle handle;
335};
336
337/**
338 * acpi_get_pci_dev - convert ACPI CA handle to struct pci_dev
339 * @handle: the handle in question
340 *
341 * Given an ACPI CA handle, the desired PCI device is located in the
342 * list of PCI devices.
343 *
344 * If the device is found, its reference count is increased and this
345 * function returns a pointer to its data structure. The caller must
346 * decrement the reference count by calling pci_dev_put().
347 * If no device is found, %NULL is returned.
348 */
349struct pci_dev *acpi_get_pci_dev(acpi_handle handle)
350{
351 int dev, fn;
352 unsigned long long adr;
353 acpi_status status;
354 acpi_handle phandle;
355 struct pci_bus *pbus;
356 struct pci_dev *pdev = NULL;
357 struct acpi_handle_node *node, *tmp;
358 struct acpi_pci_root *root;
359 LIST_HEAD(device_list);
360
361 /*
362 * Walk up the ACPI CA namespace until we reach a PCI root bridge.
363 */
364 phandle = handle;
365 while (!acpi_is_root_bridge(phandle)) {
366 node = kzalloc(sizeof(struct acpi_handle_node), GFP_KERNEL);
367 if (!node)
368 goto out;
369
370 INIT_LIST_HEAD(&node->node);
371 node->handle = phandle;
372 list_add(&node->node, &device_list);
373
374 status = acpi_get_parent(phandle, &phandle);
375 if (ACPI_FAILURE(status))
376 goto out;
377 }
378
379 root = acpi_pci_find_root(phandle);
380 if (!root)
381 goto out;
382
383 pbus = root->bus;
384
385 /*
386 * Now, walk back down the PCI device tree until we return to our
387 * original handle. Assumes that everything between the PCI root
388 * bridge and the device we're looking for must be a P2P bridge.
389 */
390 list_for_each_entry(node, &device_list, node) {
391 acpi_handle hnd = node->handle;
392 status = acpi_evaluate_integer(hnd, "_ADR", NULL, &adr);
393 if (ACPI_FAILURE(status))
394 goto out;
395 dev = (adr >> 16) & 0xffff;
396 fn = adr & 0xffff;
397
398 pdev = pci_get_slot(pbus, PCI_DEVFN(dev, fn));
399 if (hnd == handle)
400 break;
401
402 pbus = pdev->subordinate;
403 pci_dev_put(pdev);
404 }
405out:
406 list_for_each_entry_safe(node, tmp, &device_list, node)
407 kfree(node);
408
409 return pdev;
410}
411EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
412
332/** 413/**
333 * acpi_pci_osc_control_set - commit requested control to Firmware 414 * acpi_pci_osc_control_set - commit requested control to Firmware
334 * @handle: acpi_handle for the target ACPI object 415 * @handle: acpi_handle for the target ACPI object
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index 7a2ce53146aa..dbe3989952ee 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -98,6 +98,7 @@ void acpi_pci_irq_del_prt(int segment, int bus);
98 98
99struct pci_bus; 99struct pci_bus;
100 100
101struct pci_dev *acpi_get_pci_dev(acpi_handle);
101acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id); 102acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id);
102int acpi_pci_bind_root(struct acpi_device *device, struct acpi_pci_id *id, 103int acpi_pci_bind_root(struct acpi_device *device, struct acpi_pci_id *id,
103 struct pci_bus *bus); 104 struct pci_bus *bus);