Blob Blame History Raw
From 375553a93201a58a52f142eab19545a07aa1eaf5 Mon Sep 17 00:00:00 2001
From: Shanker Donthineni <sdonthineni@nvidia.com>
Date: Tue, 17 Aug 2021 23:34:58 +0530
Subject: [PATCH] PCI: Setup ACPI fwnode early and at the same time with OF
Git-commit: 375553a93201a58a52f142eab19545a07aa1eaf5
References: jsc#SLE-19357
Patch-mainline: v5.15-rc1

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>
Signed-off-by: Oliver Neukum <oneukum@suse.com>
---
 drivers/pci/pci-acpi.c | 34 ++++++++++++----------------------
 drivers/pci/probe.c    |  7 ++++---
 2 files changed, 16 insertions(+), 25 deletions(-)

diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index af2341d98860..c27dbb2294e3 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -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)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 3325d4682cd6..081b3339fb3d 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -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;
-- 
2.26.2