Skip to content

Commit

Permalink
PCI: Setup ACPI fwnode early and at the same time with OF
Browse files Browse the repository at this point in the history
Previously, the ACPI_COMPANION() of a pci_dev was usually set by
acpi_bind_one() in this path:

  pci_device_add
    pci_configure_device
    pci_init_capabilities
    device_add
      device_platform_notify
	acpi_platform_notify
	  acpi_device_notify  # KOBJ_ADD
	    acpi_bind_one
	      ACPI_COMPANION_SET

However, things like pci_configure_device() and pci_init_capabilities()
that run before device_add() need the ACPI_COMPANION, e.g.,
acpi_pci_bridge_d3() uses a _DSD method to learn about D3 support.  These
places had special-case code to manually look up the ACPI_COMPANION.

Set the ACPI_COMPANION earlier, in pci_setup_device(), so it will be
available while configuring the device.  This covers both paths to creating
pci_dev objects:

  pci_scan_single_device           # for normal non-SR-IOV devices
    pci_scan_device
      pci_setup_device
	pci_set_acpi_fwnode
    pci_device_add

  pci_iov_add_virtfn               # for SR-IOV virtual functions
    pci_setup_device
      pci_set_acpi_fwnode

Also move the OF fwnode setup to the same spot.

[bhelgaas: commit log]
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Shanker Donthineni <[email protected]>
Signed-off-by: Bjorn Helgaas <[email protected]>
Reviewed-by: Alex Williamson <[email protected]>
  • Loading branch information
shankerd04 authored and bjorn-helgaas committed Aug 18, 2021
1 parent 4273e64 commit 375553a
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 25 deletions.
34 changes: 12 additions & 22 deletions drivers/pci/pci-acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -952,46 +952,36 @@ static bool acpi_pci_power_manageable(struct pci_dev *dev)

static bool acpi_pci_bridge_d3(struct pci_dev *dev)
{
const struct fwnode_handle *fwnode;
const union acpi_object *obj;
struct acpi_device *adev;
struct pci_dev *root;
u8 val;
struct pci_dev *rpdev;

if (!dev->is_hotplug_bridge)
return false;

/* Assume D3 support if the bridge is power-manageable by ACPI. */
pci_set_acpi_fwnode(dev);

if (acpi_pci_power_manageable(dev))
return true;

/*
* Look for a special _DSD property for the root port and if it
* is set we know the hierarchy behind it supports D3 just fine.
* The ACPI firmware will provide the device-specific properties through
* _DSD configuration object. Look for the 'HotPlugSupportInD3' property
* for the root port and if it is set we know the hierarchy behind it
* supports D3 just fine.
*/
root = pcie_find_root_port(dev);
if (!root)
rpdev = pcie_find_root_port(dev);
if (!rpdev)
return false;

adev = ACPI_COMPANION(&root->dev);
if (root == dev) {
/*
* It is possible that the ACPI companion is not yet bound
* for the root port so look it up manually here.
*/
if (!adev && !pci_dev_is_added(root))
adev = acpi_pci_find_companion(&root->dev);
}

adev = ACPI_COMPANION(&rpdev->dev);
if (!adev)
return false;

fwnode = acpi_fwnode_handle(adev);
if (fwnode_property_read_u8(fwnode, "HotPlugSupportInD3", &val))
if (acpi_dev_get_property(adev, "HotPlugSupportInD3",
ACPI_TYPE_INTEGER, &obj) < 0)
return false;

return val == 1;
return obj->integer.value == 1;
}

static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
Expand Down
7 changes: 4 additions & 3 deletions drivers/pci/probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -1810,6 +1810,9 @@ int pci_setup_device(struct pci_dev *dev)
dev->error_state = pci_channel_io_normal;
set_pcie_port_type(dev);

pci_set_of_node(dev);
pci_set_acpi_fwnode(dev);

pci_dev_assign_slot(dev);

/*
Expand Down Expand Up @@ -1947,6 +1950,7 @@ int pci_setup_device(struct pci_dev *dev)
default: /* unknown header */
pci_err(dev, "unknown header type %02x, ignoring device\n",
dev->hdr_type);
pci_release_of_node(dev);
return -EIO;

bad:
Expand Down Expand Up @@ -2375,10 +2379,7 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;

pci_set_of_node(dev);

if (pci_setup_device(dev)) {
pci_release_of_node(dev);
pci_bus_put(dev->bus);
kfree(dev);
return NULL;
Expand Down

0 comments on commit 375553a

Please sign in to comment.