PCI: Setup ACPI fwnode early and at the same time with OF
authorShanker Donthineni <sdonthineni@nvidia.com>
Tue, 17 Aug 2021 18:04:58 +0000 (23:34 +0530)
committerBjorn Helgaas <bhelgaas@google.com>
Wed, 18 Aug 2021 22:16:46 +0000 (17:16 -0500)
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/20210817180500.1253-8-ameynarkhede03@gmail.com
Signed-off-by: Shanker Donthineni <sdonthineni@nvidia.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Alex Williamson <alex.williamson@redhat.com>
drivers/pci/pci-acpi.c
drivers/pci/probe.c

index af2341d..c27dbb2 100644 (file)
@@ -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)
index 3325d46..081b333 100644 (file)
@@ -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);
 
        /*
@@ -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:
@@ -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;