Message ID | 4673285.9aE2nYKHPr@kreacher (mailing list archive) |
---|---|
State | Accepted |
Delegated to: | Bjorn Helgaas |
Headers | show |
Series | PCI: ACPI: Fix up ACPI companion lookup for device 0 on the root bus | expand |
On 11/12/2020 20:17, Rafael J. Wysocki wrote: > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > In some cases acpi_pci_find_companion() returns an incorrect device > object as the ACPI companion for device 0 on the root bus (bus 0). > > On the affected systems that device is the PCI interface to the > host bridge and the "ACPI companion" returned for it corresponds > to a non-PCI device located in the SoC (e.g. a sensor on an I2C > bus). As a result of this, the ACPI device object "attached" > to PCI device 00:00.0 cannot be used for enumerating the device > that is really represented by it which (of course) is problematic. > > Address that issue by preventing acpi_pci_find_companion() from > returning a device object with a valid _HID (which by the spec > should not be present uder ACPI device objects corresponding to > PCI devices) for PCI device 00:00.0. > > Link: https://lore.kernel.org/linux-acpi/1409ba0c-1580-dc09-e6fe-a0c9bcda6462@gmail.com/ > Reported-by: Daniel Scally <djrscally@gmail.com> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested and confirmed working on my devices - thanks. Tested-by: Daniel Scally <djrscally@gmail.com> Reviewed-by: Daniel Scally <djrscally@gmail.com> > --- > drivers/pci/pci-acpi.c | 20 +++++++++++++++++++- > 1 file changed, 19 insertions(+), 1 deletion(-) > > Index: linux-pm/drivers/pci/pci-acpi.c > =================================================================== > --- linux-pm.orig/drivers/pci/pci-acpi.c > +++ linux-pm/drivers/pci/pci-acpi.c > @@ -1162,14 +1162,32 @@ void acpi_pci_remove_bus(struct pci_bus > static struct acpi_device *acpi_pci_find_companion(struct device *dev) > { > struct pci_dev *pci_dev = to_pci_dev(dev); > + struct acpi_device *adev; > bool check_children; > u64 addr; > > check_children = pci_is_bridge(pci_dev); > /* Please ref to ACPI spec for the syntax of _ADR */ > addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); > - return acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, > + adev = acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, > check_children); > + /* > + * There may be ACPI device objects in the ACPI namespace that are > + * children of the device object representing the host bridge, but don't > + * represent PCI devices. Both _HID and _ADR may be present for them, > + * even though that is against the specification (for example, see > + * Section 6.1 of ACPI 6.3), but in many cases the _ADR returns 0 which > + * appears to indicate that they should not be taken into consideration > + * as potential companions of PCI devices on the root bus. > + * > + * To catch this special case, disregard the returned device object if > + * it has a valid _HID, addr is 0 and the PCI device at hand is on the > + * root bus. > + */ > + if (adev && adev->pnp.type.platform_id && !addr && !pci_dev->bus->parent) > + return NULL; > + > + return adev; > } > > /** > > >
On Fri, Dec 11, 2020 at 09:17:35PM +0100, Rafael J. Wysocki wrote: > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > In some cases acpi_pci_find_companion() returns an incorrect device > object as the ACPI companion for device 0 on the root bus (bus 0). > > On the affected systems that device is the PCI interface to the > host bridge and the "ACPI companion" returned for it corresponds > to a non-PCI device located in the SoC (e.g. a sensor on an I2C > bus). As a result of this, the ACPI device object "attached" > to PCI device 00:00.0 cannot be used for enumerating the device > that is really represented by it which (of course) is problematic. > > Address that issue by preventing acpi_pci_find_companion() from > returning a device object with a valid _HID (which by the spec > should not be present uder ACPI device objects corresponding to > PCI devices) for PCI device 00:00.0. > > Link: https://lore.kernel.org/linux-acpi/1409ba0c-1580-dc09-e6fe-a0c9bcda6462@gmail.com/ > Reported-by: Daniel Scally <djrscally@gmail.com> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Applied with Daniel's Tested-by and Reviewed-by to pci/enumeration for v5.11, thanks! > --- > drivers/pci/pci-acpi.c | 20 +++++++++++++++++++- > 1 file changed, 19 insertions(+), 1 deletion(-) > > Index: linux-pm/drivers/pci/pci-acpi.c > =================================================================== > --- linux-pm.orig/drivers/pci/pci-acpi.c > +++ linux-pm/drivers/pci/pci-acpi.c > @@ -1162,14 +1162,32 @@ void acpi_pci_remove_bus(struct pci_bus > static struct acpi_device *acpi_pci_find_companion(struct device *dev) > { > struct pci_dev *pci_dev = to_pci_dev(dev); > + struct acpi_device *adev; > bool check_children; > u64 addr; > > check_children = pci_is_bridge(pci_dev); > /* Please ref to ACPI spec for the syntax of _ADR */ > addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); > - return acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, > + adev = acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, > check_children); > + /* > + * There may be ACPI device objects in the ACPI namespace that are > + * children of the device object representing the host bridge, but don't > + * represent PCI devices. Both _HID and _ADR may be present for them, > + * even though that is against the specification (for example, see > + * Section 6.1 of ACPI 6.3), but in many cases the _ADR returns 0 which > + * appears to indicate that they should not be taken into consideration > + * as potential companions of PCI devices on the root bus. > + * > + * To catch this special case, disregard the returned device object if > + * it has a valid _HID, addr is 0 and the PCI device at hand is on the > + * root bus. > + */ > + if (adev && adev->pnp.type.platform_id && !addr && !pci_dev->bus->parent) > + return NULL; > + > + return adev; > } > > /** > > >
Index: linux-pm/drivers/pci/pci-acpi.c =================================================================== --- linux-pm.orig/drivers/pci/pci-acpi.c +++ linux-pm/drivers/pci/pci-acpi.c @@ -1162,14 +1162,32 @@ void acpi_pci_remove_bus(struct pci_bus static struct acpi_device *acpi_pci_find_companion(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); + struct acpi_device *adev; bool check_children; u64 addr; check_children = pci_is_bridge(pci_dev); /* Please ref to ACPI spec for the syntax of _ADR */ addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); - return acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, + adev = acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, check_children); + /* + * There may be ACPI device objects in the ACPI namespace that are + * children of the device object representing the host bridge, but don't + * represent PCI devices. Both _HID and _ADR may be present for them, + * even though that is against the specification (for example, see + * Section 6.1 of ACPI 6.3), but in many cases the _ADR returns 0 which + * appears to indicate that they should not be taken into consideration + * as potential companions of PCI devices on the root bus. + * + * To catch this special case, disregard the returned device object if + * it has a valid _HID, addr is 0 and the PCI device at hand is on the + * root bus. + */ + if (adev && adev->pnp.type.platform_id && !addr && !pci_dev->bus->parent) + return NULL; + + return adev; } /**