Commit 63f534b8 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

ACPI: PCI: Rework acpi_get_pci_dev()

The PCI device returned by acpi_get_pci_dev() needs to be registered,
so if it corresponds to an ACPI device object, the struct acpi_device
representing that object must be registered too and, moreover, it
should be the ACPI companion of the given PCI device.  Thus it should
be sufficient to look for it in the ACPI device object's list of
physical nodes associated with it.

Modify the code accordingly.
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 521a547c
...@@ -312,76 +312,25 @@ struct acpi_handle_node { ...@@ -312,76 +312,25 @@ struct acpi_handle_node {
*/ */
struct pci_dev *acpi_get_pci_dev(acpi_handle handle) struct pci_dev *acpi_get_pci_dev(acpi_handle handle)
{ {
int dev, fn; struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
unsigned long long adr; struct acpi_device_physical_node *pn;
acpi_status status; struct pci_dev *pci_dev = NULL;
acpi_handle phandle;
struct pci_bus *pbus;
struct pci_dev *pdev = NULL;
struct acpi_handle_node *node, *tmp;
struct acpi_pci_root *root;
LIST_HEAD(device_list);
/*
* Walk up the ACPI CA namespace until we reach a PCI root bridge.
*/
phandle = handle;
while (!acpi_is_root_bridge(phandle)) {
node = kzalloc(sizeof(struct acpi_handle_node), GFP_KERNEL);
if (!node)
goto out;
INIT_LIST_HEAD(&node->node);
node->handle = phandle;
list_add(&node->node, &device_list);
status = acpi_get_parent(phandle, &phandle);
if (ACPI_FAILURE(status))
goto out;
}
root = acpi_pci_find_root(phandle);
if (!root)
goto out;
pbus = root->bus; if (!adev)
return NULL;
/*
* Now, walk back down the PCI device tree until we return to our
* original handle. Assumes that everything between the PCI root
* bridge and the device we're looking for must be a P2P bridge.
*/
list_for_each_entry(node, &device_list, node) {
acpi_handle hnd = node->handle;
status = acpi_evaluate_integer(hnd, "_ADR", NULL, &adr);
if (ACPI_FAILURE(status))
goto out;
dev = (adr >> 16) & 0xffff;
fn = adr & 0xffff;
pdev = pci_get_slot(pbus, PCI_DEVFN(dev, fn));
if (!pdev || hnd == handle)
break;
pbus = pdev->subordinate; mutex_lock(&adev->physical_node_lock);
pci_dev_put(pdev);
/* list_for_each_entry(pn, &adev->physical_node_list, node) {
* This function may be called for a non-PCI device that has a if (dev_is_pci(pn->dev)) {
* PCI parent (eg. a disk under a PCI SATA controller). In that pci_dev = to_pci_dev(pn->dev);
* case pdev->subordinate will be NULL for the parent.
*/
if (!pbus) {
dev_dbg(&pdev->dev, "Not a PCI-to-PCI bridge\n");
pdev = NULL;
break; break;
} }
} }
out:
list_for_each_entry_safe(node, tmp, &device_list, node)
kfree(node);
return pdev; mutex_unlock(&adev->physical_node_lock);
return pci_dev;
} }
EXPORT_SYMBOL_GPL(acpi_get_pci_dev); EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
......
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