Skip to content
  • Rafael J. Wysocki's avatar
    ACPI: Try harder to resolve _ADR collisions for bridges · 6e4fdb80
    Rafael J. Wysocki authored
    commit 60f75b8e97daf4a39790a20d962cb861b9220af5 upstream.
    
    In theory, under a given ACPI namespace node there should be only
    one child device object with _ADR whose value matches a given bus
    address exactly.  In practice, however, there are systems in which
    multiple child device objects under a given parent have _ADR matching
    exactly the same address.  In those cases we use _STA to determine
    which of the multiple matching devices is enabled, since some systems
    are known to indicate which ACPI device object to associate with the
    given physical (usually PCI) device this way.
    
    Unfortunately, as it turns out, there are systems in which many
    device objects under the same parent have _ADR matching exactly the
    same bus address and none of them has _STA, in which case they all
    should be regarded as enabled according to the spec.  Still, if
    those device objects are supposed to represent bridges (e.g. this
    is the case for device objects corresponding to PCIe ports), we can
    try harder and skip the ones that have no child device objects in the
    ACPI namespace.  With luck, we can avoid using device objects that we
    are not expected to use this way.
    
    Although this only works for bridges whose children also have ACPI
    namespace representation, it is sufficient to address graphics
    adapter detection issues on some systems, so rework the code finding
    a matching device ACPI handle for a given bus address to implement
    this idea.
    
    Introduce a new function, acpi_find_child(), taking three arguments:
    the ACPI handle of the device's parent, a bus address suitable for
    the device's bus type and a bool indicating if the device is a
    bridge and make it work as outlined above.  Reimplement the function
    currently used for this purpose, acpi_get_child(), as a call to
    acpi_find_child() with the last argument set to 'false' and make
    the PCI subsystem use acpi_find_child() with the bridge information
    passed as the last argument to it.  [Lan Tianyu notices that it is
    not sufficient to use pci_is_bridge() for that, because the device's
    subordinate pointer hasn't been set yet at this point, so use
    hdr_type instead.]
    
    This change fixes a regression introduced inadvertently by commit
    33f767d7 (ACPI: Rework acpi_get_child() to be more efficient) which
    overlooked the fact that for acpi_walk_namespace() "post-order" means
    "after all children have been visited" rather than "on the way back",
    so for device objects without children and for namespace walks of
    depth 1, as in the acpi_get_child() case, the "post-order" callbacks
    ordering is actually the same as the ordering of "pre-order" ones.
    Since that commit changed the namespace walk in acpi_get_child() to
    terminate after finding the first matching object instead of going
    through all of them and returning the last one, it effectively
    changed the result returned by that function in some rare cases and
    that led to problems (the switch from a "pre-order" to a "post-order"
    callback was supposed to prevent that from happening, but it was
    ineffective).
    
    As it turns out, the systems where the change made by commit
    33f767d7 actually matters are those where there are multiple ACPI
    device objects representing the same PCIe port (which effectively
    is a bridge).  Moreover, only one of them, and the one we are
    expected to use, has child device objects in the ACPI namespace,
    so the regression can be addressed as described above.
    
    References: https://bugzilla.kernel.org/show_bug.cgi?id=60561
    
    
    Reported-by: default avatarPeter Wu <lekensteyn@gmail.com>
    Tested-by: default avatarVladimir Lalov <mail@vlalov.com>
    Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
    Acked-by: default avatarBjorn Helgaas <bhelgaas@google.com>
    Cc: Peter Wu <lekensteyn@gmail.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    6e4fdb80