PCI: Setup ACPI fwnode early and at the same time with OF
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>
This commit is contained in:
parent
4273e64cc4
commit
375553a932
@ -952,46 +952,36 @@ static bool acpi_pci_power_manageable(struct pci_dev *dev)
|
|||||||
|
|
||||||
static bool acpi_pci_bridge_d3(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 acpi_device *adev;
|
||||||
struct pci_dev *root;
|
struct pci_dev *rpdev;
|
||||||
u8 val;
|
|
||||||
|
|
||||||
if (!dev->is_hotplug_bridge)
|
if (!dev->is_hotplug_bridge)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Assume D3 support if the bridge is power-manageable by ACPI. */
|
/* Assume D3 support if the bridge is power-manageable by ACPI. */
|
||||||
pci_set_acpi_fwnode(dev);
|
|
||||||
|
|
||||||
if (acpi_pci_power_manageable(dev))
|
if (acpi_pci_power_manageable(dev))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look for a special _DSD property for the root port and if it
|
* The ACPI firmware will provide the device-specific properties through
|
||||||
* is set we know the hierarchy behind it supports D3 just fine.
|
* _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);
|
rpdev = pcie_find_root_port(dev);
|
||||||
if (!root)
|
if (!rpdev)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
adev = ACPI_COMPANION(&root->dev);
|
adev = ACPI_COMPANION(&rpdev->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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!adev)
|
if (!adev)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
fwnode = acpi_fwnode_handle(adev);
|
if (acpi_dev_get_property(adev, "HotPlugSupportInD3",
|
||||||
if (fwnode_property_read_u8(fwnode, "HotPlugSupportInD3", &val))
|
ACPI_TYPE_INTEGER, &obj) < 0)
|
||||||
return false;
|
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)
|
static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
|
||||||
|
@ -1810,6 +1810,9 @@ int pci_setup_device(struct pci_dev *dev)
|
|||||||
dev->error_state = pci_channel_io_normal;
|
dev->error_state = pci_channel_io_normal;
|
||||||
set_pcie_port_type(dev);
|
set_pcie_port_type(dev);
|
||||||
|
|
||||||
|
pci_set_of_node(dev);
|
||||||
|
pci_set_acpi_fwnode(dev);
|
||||||
|
|
||||||
pci_dev_assign_slot(dev);
|
pci_dev_assign_slot(dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1947,6 +1950,7 @@ int pci_setup_device(struct pci_dev *dev)
|
|||||||
default: /* unknown header */
|
default: /* unknown header */
|
||||||
pci_err(dev, "unknown header type %02x, ignoring device\n",
|
pci_err(dev, "unknown header type %02x, ignoring device\n",
|
||||||
dev->hdr_type);
|
dev->hdr_type);
|
||||||
|
pci_release_of_node(dev);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
@ -2375,10 +2379,7 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
|
|||||||
dev->vendor = l & 0xffff;
|
dev->vendor = l & 0xffff;
|
||||||
dev->device = (l >> 16) & 0xffff;
|
dev->device = (l >> 16) & 0xffff;
|
||||||
|
|
||||||
pci_set_of_node(dev);
|
|
||||||
|
|
||||||
if (pci_setup_device(dev)) {
|
if (pci_setup_device(dev)) {
|
||||||
pci_release_of_node(dev);
|
|
||||||
pci_bus_put(dev->bus);
|
pci_bus_put(dev->bus);
|
||||||
kfree(dev);
|
kfree(dev);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user