linux/drivers/pci
Mika Westerberg 83a16e3f6d PCI / ACPI: Use cached ACPI device state to get PCI device power state
The ACPI power state returned by acpi_device_get_power() may depend on
the configuration of ACPI power resources in the system which may change
any time after acpi_device_get_power() has returned, unless the
reference counters of the ACPI power resources in question are set to
prevent that from happening. Thus it is invalid to use acpi_device_get_power()
in acpi_pci_get_power_state() the way it is done now and the value of
the ->power.state field in the corresponding struct acpi_device objects
(which reflects the ACPI power resources reference counting, among other
things) should be used instead.

As an example where this becomes an issue is Intel Ice Lake where the
Thunderbolt controller (NHI), two PCIe root ports (RP0 and RP1) and xHCI
all share the same power resources. The following picture with power
resources marked with [] shows the topology:

  Host bridge
    |
    +- RP0 ---\
    +- RP1 ---|--+--> [TBT]
    +- NHI --/   |
    |            |
    |            v
    +- xHCI --> [D3C]

Here TBT and D3C are the shared ACPI power resources. ACPI _PR3() method
of the devices in question returns either TBT or D3C or both.

Say we runtime suspend first the root ports RP0 and RP1, then NHI. Now
since the TBT power resource is still on when the root ports are runtime
suspended their dev->current_state is set to D3hot. When NHI is runtime
suspended TBT is finally turned off but state of the root ports remain
to be D3hot. Now when the xHCI is runtime suspended D3C gets also turned
off. PCI core thus has power states of these devices cached in their
dev->current_state as follows:

  RP0 -> D3hot
  RP1 -> D3hot
  NHI -> D3cold
  xHCI -> D3cold

If the user now runs lspci for instance, the result is all 1's like in
the below output (00:07.0 is the first root port, RP0):

00:07.0 PCI bridge: Intel Corporation Device 8a1d (rev ff) (prog-if ff)
    !!! Unknown header type 7f
    Kernel driver in use: pcieport

In short the hardware state is not in sync with the software state
anymore. The exact same thing happens with the PME polling thread which
ends up bringing the root ports back into D0 after they are runtime
suspended.

For this reason, modify acpi_pci_get_power_state() so that it uses the
ACPI device power state that was cached by the ACPI core. This makes the
PCI device power state match the ACPI device power state regardless of
state of the shared power resources which may still be on at this point.

Link: https://lore.kernel.org/r/20190618161858.77834-2-mika.westerberg@linux.intel.com
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2019-06-27 12:31:57 +02:00
..
controller pci-v5.2-changes 2019-05-14 10:30:10 -07:00
endpoint Merge branch 'remotes/lorenzo/pci/misc' 2019-05-13 18:34:44 -05:00
hotplug pci-v5.2-changes 2019-05-14 10:30:10 -07:00
pcie PCI: Add missing link delays required by the PCIe spec 2019-06-18 01:40:41 +02:00
switch pci-v5.2-changes 2019-05-14 10:30:10 -07:00
access.c PCI: Uninline PCI bus accessors for better ftracing 2018-10-04 16:37:37 -05:00
ats.c PCI/ATS: Add pci_ats_page_aligned() interface 2019-02-26 11:08:07 +01:00
bus.c PCI: Replace dev_printk(KERN_DEBUG) with dev_info(), etc 2019-05-09 07:49:58 -05:00
ecam.c
host-bridge.c
iov.c PCI/IOV: Add flag so platforms can skip VF scanning 2019-01-01 19:04:37 -06:00
irq.c PCI: Use IRQF_ONESHOT if pci_request_irq() called with no handler 2018-07-31 10:43:43 -05:00
Kconfig PCI: Fix PCI kconfig menu organization 2019-01-14 17:01:20 -06:00
Makefile PCI: OF: Allow of_pci_get_max_link_speed() to be used by PCI Endpoint drivers 2019-04-15 13:24:02 +01:00
mmap.c
msi.c PCI: Add pci_dev_id() helper 2019-04-29 16:12:05 -05:00
of.c Merge branch 'remotes/lorenzo/pci/keystone' 2019-05-13 18:34:41 -05:00
p2pdma.c mm/devm_memremap_pages: fix final page put race 2019-06-13 17:34:56 -10:00
pci-acpi.c PCI / ACPI: Use cached ACPI device state to get PCI device power state 2019-06-27 12:31:57 +02:00
pci-bridge-emul.c PCI: pci-bridge-emul: Extend pci_bridge_emul_init() with flags 2019-02-22 10:51:14 +00:00
pci-bridge-emul.h PCI: pci-bridge-emul: Extend pci_bridge_emul_init() with flags 2019-02-22 10:51:14 +00:00
pci-driver.c Merge back PCI power management material for v5.3. 2019-06-24 10:11:27 +02:00
pci-label.c
pci-mid.c x86/cpu: Sanitize FAM6_ATOM naming 2018-10-02 10:14:32 +02:00
pci-pf-stub.c PCI/IOV: Add pci-pf-stub driver for PFs that only enable VFs 2018-04-24 16:47:16 -05:00
pci-stub.c PCI: Replace printk(KERN_INFO) with pr_info(), etc 2019-05-09 07:49:54 -05:00
pci-sysfs.c PCI: Use dev_printk() when possible 2019-05-09 07:49:49 -05:00
pci.c PCI: Do not poll for PME if the device is in D3cold 2019-06-18 01:40:41 +02:00
pci.h PCI: Add missing link delays required by the PCIe spec 2019-06-18 01:40:41 +02:00
probe.c pci-v5.2-changes 2019-05-14 10:30:10 -07:00
proc.c PCI: Mark expected switch fall-throughs 2019-03-20 15:11:11 -05:00
quirks.c pci-v5.2-changes 2019-05-14 10:30:10 -07:00
remove.c PCI/ASPM: Fix link_state teardown on device removal 2018-09-17 16:32:23 -05:00
rom.c PCI: Make pci_get_rom_size() static 2018-06-29 21:17:26 -05:00
search.c PCI: Add pci_dev_id() helper 2019-04-29 16:12:05 -05:00
setup-bus.c Merge branch 'pci/trivial' 2019-05-13 18:34:48 -05:00
setup-irq.c
setup-res.c
slot.c PCI: Replace printk(KERN_INFO) with pr_info(), etc 2019-05-09 07:49:54 -05:00
syscall.c
vc.c
vpd.c PCI/VPD: Check for VPD access completion before checking for timeout 2018-08-14 16:04:46 -05:00
xen-pcifront.c Merge branch 'pci/printk' 2019-05-13 18:34:46 -05:00