[PATCH v13 11/12] PCI: ACPI: Use device constraints to opt devices into D3 support

From: Mario Limonciello
Date: Fri Aug 18 2023 - 01:17:52 EST


In Windows, systems that support Modern Standby specify hardware
pre-conditions for the SoC to be able to achieve the lowest power state
by using 'device constraints' in a SOC specific "Power Engine
Plugin" (PEP) [1] [2].

Device constraints are specified in the return value for a _DSM of
a PNP0D80 device, and Linux enumerates the constraints during probing.

In cases that the existing logic for pci_bridge_d3_possible() may not
enable D3 support query for any constraints specified by the device.
If the constraints specify D3 support, then use D3 for the PCI device.

Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/platform-design-for-modern-standby#low-power-core-silicon-cpu-soc-dram [1]
Link: https://uefi.org/sites/default/files/resources/Intel_ACPI_Low_Power_S0_Idle.pdf [2]
Signed-off-by: Mario Limonciello <mario.limonciello@xxxxxxx>
---
v12->v13:
* Move back to PCI code
* Trim commit message
v11->v12:
* Adjust for dropped patch 8/9 from v11.
* Update comment
v10->v11:
* Fix kernel kernel build robot errors and various sparse warnings
related to new handling of pci_power_t.
* Use the new helpers introduced in previous patches
---
drivers/pci/pci-acpi.c | 14 ++++++++++++++
drivers/pci/pci.c | 12 ++++++++++++
drivers/pci/pci.h | 5 +++++
3 files changed, 31 insertions(+)

diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index b5b65cdfa3b8b..bcc76e9d399c5 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -1081,6 +1081,20 @@ bool acpi_pci_bridge_d3(struct pci_dev *dev)
return false;
}

+/**
+ * acpi_pci_check_d3_constraint - Check if device specifies a D3 platform constraint
+ * @dev: PCI device to check
+ *
+ * This function checks if the platform specifies that a given PCI device should
+ * be put into D3 to satisfy a low power platform constraint
+ *
+ * Returns: TRUE if constraint for D3hot or deeper, FALSE otherwise.
+ */
+bool acpi_pci_check_d3_constraint(struct pci_dev *dev)
+{
+ return acpi_get_lps0_constraint(&dev->dev) >= ACPI_STATE_D3_HOT;
+}
+
static void acpi_pci_config_space_access(struct pci_dev *dev, bool enable)
{
int val = enable ? ACPI_REG_CONNECT : ACPI_REG_DISCONNECT;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 051e88ee64c63..0fc8d35154f97 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1082,6 +1082,14 @@ static inline bool platform_pci_bridge_d3(struct pci_dev *dev)
return acpi_pci_bridge_d3(dev);
}

+static inline bool platform_check_d3_constraint(struct pci_dev *dev)
+{
+ if (pci_use_mid_pm())
+ return false;
+
+ return acpi_pci_check_d3_constraint(dev);
+}
+
/**
* pci_update_current_state - Read power state of given device and cache it
* @dev: PCI device to handle.
@@ -3036,6 +3044,10 @@ bool pci_bridge_d3_possible(struct pci_dev *bridge)
if (dmi_check_system(bridge_d3_blacklist))
return false;

+ /* the platform specifies in LPS0 constraints to use D3 */
+ if (platform_check_d3_constraint(bridge))
+ return true;
+
/*
* It is safe to put Intel PCIe ports from 2015 or newer
* to D3.
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index a4c3974340576..ac06c781a9b7c 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -707,6 +707,7 @@ void pci_set_acpi_fwnode(struct pci_dev *dev);
int pci_dev_acpi_reset(struct pci_dev *dev, bool probe);
bool acpi_pci_power_manageable(struct pci_dev *dev);
bool acpi_pci_bridge_d3(struct pci_dev *dev);
+bool acpi_pci_check_d3_constraint(struct pci_dev *dev);
int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state);
pci_power_t acpi_pci_get_power_state(struct pci_dev *dev);
void acpi_pci_refresh_power_state(struct pci_dev *dev);
@@ -731,6 +732,10 @@ static inline bool acpi_pci_bridge_d3(struct pci_dev *dev)
{
return false;
}
+static inline bool acpi_pci_check_d3_constraint(struct pci_dev *dev)
+{
+ return false;
+}
static inline int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
{
return -ENODEV;
--
2.34.1