linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v9 0/3] Fix wakeup problems on some AMD platforms
@ 2023-08-04  1:02 Mario Limonciello
  2023-08-04  1:02 ` [PATCH v9 1/3] ACPI: Add comments to clarify some #ifdef statements Mario Limonciello
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Mario Limonciello @ 2023-08-04  1:02 UTC (permalink / raw)
  To: Rafael J . Wysocki, Mika Westerberg, Bjorn Helgaas
  Cc: linux-pci, linux-kernel, Andy Shevchenko, linux-acpi,
	Kuppuswamy Sathyanarayanan, Iain Lane, Shyam-sundar S-k,
	Mario Limonciello

Problems have been reported on AMD laptops with suspend/resume
where particular root ports are put into D3 and then the system is unable
to resume properly.

The issue boils down to the currently selected kernel policy for root port
behavior at suspend time:
0) If the machine is from 2015 or later
1) If a PCIe root port is power manageable by the platform then platform
   will be used to determine the power state of the root port at suspend.
2) If the PCIe root is not power manageable by the platform then the kernel
   will check if it was configured to wakeup.
3) If it was, then it will be put into the deepest state that supports
   wakeup from PME.
4) If it wasn't, then it will be put into D3hot.

This patch adjusts it so that device constraints for low power idle are
considered if the device is not power manageable by the platform.

Mario Limonciello (3):
  ACPI: Add comments to clarify some #ifdef statements
  ACPI: x86: s2idle: Adjust constraints logic building
  PCI/ACPI: Use device constraints to decide PCI target state fallback
    policy

 drivers/acpi/x86/s2idle.c | 71 ++++++++++++++++++++++++++-------------
 drivers/pci/pci-acpi.c    | 22 ++++++++++++
 drivers/pci/pci.c         | 14 ++++++++
 drivers/pci/pci.h         |  5 +++
 include/linux/acpi.h      | 14 +++++---
 5 files changed, 99 insertions(+), 27 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v9 1/3] ACPI: Add comments to clarify some #ifdef statements
  2023-08-04  1:02 [PATCH v9 0/3] Fix wakeup problems on some AMD platforms Mario Limonciello
@ 2023-08-04  1:02 ` Mario Limonciello
  2023-08-04  1:02 ` [PATCH v9 2/3] ACPI: x86: s2idle: Adjust constraints logic building Mario Limonciello
  2023-08-04  1:02 ` [PATCH v9 3/3] PCI/ACPI: Use device constraints to decide PCI target state fallback policy Mario Limonciello
  2 siblings, 0 replies; 10+ messages in thread
From: Mario Limonciello @ 2023-08-04  1:02 UTC (permalink / raw)
  To: Rafael J . Wysocki, Mika Westerberg, Bjorn Helgaas
  Cc: linux-pci, linux-kernel, Andy Shevchenko, linux-acpi,
	Kuppuswamy Sathyanarayanan, Iain Lane, Shyam-sundar S-k,
	Mario Limonciello

With nested #ifdef statements it's sometimes difficult to tell
which code goes with which statement.  One comment was wrong,
so fix it and add another comment to clarify another.

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
 include/linux/acpi.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 641dc48439873..0d5277b7c6323 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -1117,10 +1117,10 @@ static inline void arch_reserve_mem_area(acpi_physical_address addr,
 					  size_t size)
 {
 }
-#endif /* CONFIG_X86 */
+#endif /* CONFIG_IA64 */
 #else
 #define acpi_os_set_prepare_sleep(func, pm1a_ctrl, pm1b_ctrl) do { } while (0)
-#endif
+#endif /* CONFIG_ACPI */
 
 #if defined(CONFIG_ACPI) && defined(CONFIG_PM)
 int acpi_dev_suspend(struct device *dev, bool wakeup);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v9 2/3] ACPI: x86: s2idle: Adjust constraints logic building
  2023-08-04  1:02 [PATCH v9 0/3] Fix wakeup problems on some AMD platforms Mario Limonciello
  2023-08-04  1:02 ` [PATCH v9 1/3] ACPI: Add comments to clarify some #ifdef statements Mario Limonciello
@ 2023-08-04  1:02 ` Mario Limonciello
  2023-08-04  4:31   ` Andy Shevchenko
  2023-08-04  1:02 ` [PATCH v9 3/3] PCI/ACPI: Use device constraints to decide PCI target state fallback policy Mario Limonciello
  2 siblings, 1 reply; 10+ messages in thread
From: Mario Limonciello @ 2023-08-04  1:02 UTC (permalink / raw)
  To: Rafael J . Wysocki, Mika Westerberg, Bjorn Helgaas
  Cc: linux-pci, linux-kernel, Andy Shevchenko, linux-acpi,
	Kuppuswamy Sathyanarayanan, Iain Lane, Shyam-sundar S-k,
	Mario Limonciello

Constraints are currently only stored when enabled.  To enable
the ability to check if constraints are present they need to be
stored even if disabled.

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
v8->v9:
 * New patch
---
 drivers/acpi/x86/s2idle.c | 48 ++++++++++++++++++++-------------------
 1 file changed, 25 insertions(+), 23 deletions(-)

diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
index ce62e61a9605e..cb2ea92af3eb7 100644
--- a/drivers/acpi/x86/s2idle.c
+++ b/drivers/acpi/x86/s2idle.c
@@ -78,6 +78,7 @@ struct lpi_device_constraint {
 struct lpi_constraints {
 	acpi_handle handle;
 	int min_dstate;
+	bool enabled;
 };
 
 /* AMD Constraint package structure */
@@ -120,8 +121,7 @@ static void lpi_device_get_constraints_amd(void)
 			if (!lpi_constraints_table)
 				goto free_acpi_buffer;
 
-			acpi_handle_debug(lps0_device_handle,
-					  "LPI: constraints list begin:\n");
+			acpi_handle_debug(lps0_device_handle, "LPI: constraints list begin:\n");
 
 			for (j = 0; j < package->package.count; ++j) {
 				union acpi_object *info_obj = &package->package.elements[j];
@@ -129,12 +129,12 @@ static void lpi_device_get_constraints_amd(void)
 				struct lpi_constraints *list;
 				acpi_status status;
 
+				list = &lpi_constraints_table[j];
+				list->min_dstate = -EINVAL;
+
 				for (k = 0; k < info_obj->package.count; ++k) {
 					union acpi_object *obj = &info_obj->package.elements[k];
 
-					list = &lpi_constraints_table[lpi_constraints_table_size];
-					list->min_dstate = -1;
-
 					switch (k) {
 					case 0:
 						dev_info.enabled = obj->integer.value;
@@ -149,27 +149,29 @@ static void lpi_device_get_constraints_amd(void)
 						dev_info.min_dstate = obj->integer.value;
 						break;
 					}
+				}
 
-					if (!dev_info.enabled || !dev_info.name ||
-					    !dev_info.min_dstate)
-						continue;
+				if (!dev_info.name)
+					continue;
 
-					status = acpi_get_handle(NULL, dev_info.name,
-								 &list->handle);
-					if (ACPI_FAILURE(status))
-						continue;
+				status = acpi_get_handle(NULL, dev_info.name, &list->handle);
+				if (ACPI_FAILURE(status))
+					continue;
 
-					acpi_handle_debug(lps0_device_handle,
-							  "Name:%s\n", dev_info.name);
+				acpi_handle_debug(lps0_device_handle,
+						  "Name:%s, Enabled: %d, States: %d, MinDstate: %d\n",
+						  dev_info.name,
+						  dev_info.enabled,
+						  dev_info.function_states,
+						  dev_info.min_dstate);
 
-					list->min_dstate = dev_info.min_dstate;
+				list->min_dstate = dev_info.min_dstate;
 
-					if (list->min_dstate < 0) {
-						acpi_handle_debug(lps0_device_handle,
-								  "Incomplete constraint defined\n");
-						continue;
-					}
+				if (list->min_dstate < 0) {
+					acpi_handle_debug(lps0_device_handle, "Incomplete constraint defined\n");
+					continue;
 				}
+				list->enabled = dev_info.enabled;
 				lpi_constraints_table_size++;
 			}
 		}
@@ -232,7 +234,7 @@ static void lpi_device_get_constraints(void)
 			}
 		}
 
-		if (!info.enabled || !info.package || !info.name)
+		if (!info.package || !info.name)
 			continue;
 
 		constraint = &lpi_constraints_table[lpi_constraints_table_size];
@@ -244,7 +246,7 @@ static void lpi_device_get_constraints(void)
 		acpi_handle_debug(lps0_device_handle,
 				  "index:%d Name:%s\n", i, info.name);
 
-		constraint->min_dstate = -1;
+		constraint->min_dstate = -EINVAL;
 
 		for (j = 0; j < package_count; ++j) {
 			union acpi_object *info_obj = &info.package[j];
@@ -281,7 +283,7 @@ static void lpi_device_get_constraints(void)
 					  "Incomplete constraint defined\n");
 			continue;
 		}
-
+		constraint->enabled = info.enabled;
 		lpi_constraints_table_size++;
 	}
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v9 3/3] PCI/ACPI: Use device constraints to decide PCI target state fallback policy
  2023-08-04  1:02 [PATCH v9 0/3] Fix wakeup problems on some AMD platforms Mario Limonciello
  2023-08-04  1:02 ` [PATCH v9 1/3] ACPI: Add comments to clarify some #ifdef statements Mario Limonciello
  2023-08-04  1:02 ` [PATCH v9 2/3] ACPI: x86: s2idle: Adjust constraints logic building Mario Limonciello
@ 2023-08-04  1:02 ` Mario Limonciello
  2023-08-04  4:30   ` Andy Shevchenko
  2023-08-04 13:17   ` Mika Westerberg
  2 siblings, 2 replies; 10+ messages in thread
From: Mario Limonciello @ 2023-08-04  1:02 UTC (permalink / raw)
  To: Rafael J . Wysocki, Mika Westerberg, Bjorn Helgaas
  Cc: linux-pci, linux-kernel, Andy Shevchenko, linux-acpi,
	Kuppuswamy Sathyanarayanan, Iain Lane, Shyam-sundar S-k,
	Mario Limonciello

Since commit 9d26d3a8f1b0 ("PCI: Put PCIe ports into D3 during suspend")
PCIe ports from modern machines (>=2015) are allowed to be put into D3 by
storing a value to the `bridge_d3` variable in the `struct pci_dev`
structure.

pci_power_manageable() uses this variable to indicate a PCIe port can
enter D3.
pci_pm_suspend_noirq() uses the return from pci_power_manageable() to
decide whether to try to put a device into its target state for a sleep
cycle via pci_prepare_to_sleep().

For devices that support D3, the target state is selected by this policy:
1. If platform_pci_power_manageable():
   Use platform_pci_choose_state()
2. If the device is armed for wakeup:
   Select the deepest D-state that supports a PME.
3. Else:
   Use D3hot.

Devices are considered power manageable by the platform when they have
one or more objects described in the table in section 7.3 of the ACPI 6.5
specification.

When devices are not considered power manageable; specs are ambiguous as
to what should happen.  In this situation Windows 11 leaves PCIe
ports in D0 while Linux puts them into D3 due to the above mentioned
commit.

In Windows systems that support Modern Standby specify hardware
pre-conditions for the SoC to achieve the lowest power state by device
constraints in a SOC specific "Power Engine Plugin" (PEP) [2] [3].
They can be marked as disabled or enabled and when enabled can specify
the minimum power state required for an ACPI device.

When it is ambiguous what should happen, adjust the logic for
pci_target_state() to check whether a device constraint is present
and enabled.
* If power manageable by ACPI use this to get to select target state
* If a device constraint is present but disabled then choose D0
* If a device constraint is present and enabled then use it
* If a device constraint is not present, then continue to existing
  logic (if marked for wakeup use deepest state that PME works)
* If not marked for wakeup choose D3hot

Link: https://uefi.org/specs/ACPI/6.5/07_Power_and_Performance_Mgmt.html#device-power-management-objects [1]
Link: https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/platform-design-for-modern-standby#low-power-core-silicon-cpu-soc-dram [2]
Link: https://uefi.org/sites/default/files/resources/Intel_ACPI_Low_Power_S0_Idle.pdf [3]
Fixes: 9d26d3a8f1b0 ("PCI: Put PCIe ports into D3 during suspend")
Reported-by: Iain Lane <iain@orangesquash.org.uk>
Closes: https://forums.lenovo.com/t5/Ubuntu/Z13-can-t-resume-from-suspend-with-external-USB-keyboard/m-p/5217121
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
v8->v9:
 * Use device_match_acpi_handle instead
 * Move the logic to run at the state selection time
 * Small fixups suggested by Andy
 * Call from pci_target_state() instead
v7->v8:
 * Use device constraints instead
 * Update commit message and links
---
 drivers/acpi/x86/s2idle.c | 23 +++++++++++++++++++++++
 drivers/pci/pci-acpi.c    | 22 ++++++++++++++++++++++
 drivers/pci/pci.c         | 14 ++++++++++++++
 drivers/pci/pci.h         |  5 +++++
 include/linux/acpi.h      | 10 ++++++++--
 5 files changed, 72 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
index cb2ea92af3eb7..c0e2c82e9ef63 100644
--- a/drivers/acpi/x86/s2idle.c
+++ b/drivers/acpi/x86/s2idle.c
@@ -293,6 +293,29 @@ static void lpi_device_get_constraints(void)
 	ACPI_FREE(out_obj);
 }
 
+/**
+ * acpi_get_lps0_constraint - get any LPS0 constraint for a device
+ * @dev: device to get constraint for
+ *
+ * If a constraint has been specified in the _DSM method for the device,
+ * and the constraint is enabled return it.  If the constraint is disabled,
+ * return 0. Otherwise, return -ENODEV.
+ */
+int acpi_get_lps0_constraint(struct device *dev)
+{
+	int i;
+
+	for (i = 0; i < lpi_constraints_table_size; ++i) {
+		if (!device_match_acpi_handle(dev, lpi_constraints_table[i].handle))
+			continue;
+		if (!lpi_constraints_table[i].enabled)
+			return 0;
+		return lpi_constraints_table[i].min_dstate;
+	}
+
+	return -ENODEV;
+}
+
 static void lpi_check_constraints(void)
 {
 	int i;
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index a05350a4e49cb..499dcb7fa3651 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -1043,6 +1043,28 @@ bool acpi_pci_bridge_d3(struct pci_dev *dev)
 	return false;
 }
 
+/**
+ * acpi_pci_device_constraint - determine if the platform has a contraint for the device
+ * @dev: PCI device to check
+ * @result (out): the constraint specified by the platform
+ *
+ * If the platform has specified a constraint for a device, this function will
+ * return 0 and set @result to the constraint.
+ * Otherwise, it will return an error code.
+ */
+int acpi_pci_device_constraint(struct pci_dev *dev, int *result)
+{
+	int constraint;
+
+	constraint = acpi_get_lps0_constraint(&dev->dev);
+	pci_dbg(dev, "ACPI device constraint: %d\n", constraint);
+	if (constraint < 0)
+		return constraint;
+	*result = constraint;
+
+	return 0;
+}
+
 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 60230da957e0c..6c70f921467c6 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 int platform_get_constraint(struct pci_dev *dev, int *result)
+{
+	if (pci_use_mid_pm())
+		return -ENODEV;
+
+	return acpi_pci_device_constraint(dev, result);
+}
+
 /**
  * pci_update_current_state - Read power state of given device and cache it
  * @dev: PCI device to handle.
@@ -2671,6 +2679,8 @@ EXPORT_SYMBOL(pci_wake_from_d3);
  */
 static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup)
 {
+	int val;
+
 	if (platform_pci_power_manageable(dev)) {
 		/*
 		 * Call the platform to find the target state for the device.
@@ -2691,6 +2701,10 @@ static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup)
 		return state;
 	}
 
+	/* if platform indicates in a device constraint, use it */
+	if (!platform_get_constraint(dev, &val))
+		return val;
+
 	/*
 	 * If the device is in D3cold even though it's not power-manageable by
 	 * the platform, it may have been powered down by non-standard means.
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index a4c3974340576..8001f34ec535b 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);
+int acpi_pci_device_constraint(struct pci_dev *dev, int *result);
 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 int acpi_pci_device_constraint(struct pci_dev *dev, int *result)
+{
+	return -ENODEV;
+}
 static inline int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 {
 	return -ENODEV;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 0d5277b7c6323..024075cce09e5 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -1100,7 +1100,7 @@ void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state,
 
 acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state,
 					   u32 val_a, u32 val_b);
-#ifdef CONFIG_X86
+#if defined(CONFIG_ACPI_SLEEP) && defined(CONFIG_X86)
 struct acpi_s2idle_dev_ops {
 	struct list_head list_node;
 	void (*prepare)(void);
@@ -1109,7 +1109,13 @@ struct acpi_s2idle_dev_ops {
 };
 int acpi_register_lps0_dev(struct acpi_s2idle_dev_ops *arg);
 void acpi_unregister_lps0_dev(struct acpi_s2idle_dev_ops *arg);
-#endif /* CONFIG_X86 */
+int acpi_get_lps0_constraint(struct device *dev);
+#else
+static inline int acpi_get_lps0_constraint(struct device *dev)
+{
+	return false;
+}
+#endif /* CONFIG_ACPI_SLEEP && CONFIG_X86 */
 #ifndef CONFIG_IA64
 void arch_reserve_mem_area(acpi_physical_address addr, size_t size);
 #else
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v9 3/3] PCI/ACPI: Use device constraints to decide PCI target state fallback policy
  2023-08-04  1:02 ` [PATCH v9 3/3] PCI/ACPI: Use device constraints to decide PCI target state fallback policy Mario Limonciello
@ 2023-08-04  4:30   ` Andy Shevchenko
  2023-08-04  4:37     ` Mario Limonciello
  2023-08-04 13:17   ` Mika Westerberg
  1 sibling, 1 reply; 10+ messages in thread
From: Andy Shevchenko @ 2023-08-04  4:30 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Rafael J . Wysocki, Mika Westerberg, Bjorn Helgaas, linux-pci,
	linux-kernel, linux-acpi, Kuppuswamy Sathyanarayanan, Iain Lane,
	Shyam-sundar S-k

On Thu, Aug 03, 2023 at 08:02:29PM -0500, Mario Limonciello wrote:
> Since commit 9d26d3a8f1b0 ("PCI: Put PCIe ports into D3 during suspend")
> PCIe ports from modern machines (>=2015) are allowed to be put into D3 by
> storing a value to the `bridge_d3` variable in the `struct pci_dev`
> structure.
> 
> pci_power_manageable() uses this variable to indicate a PCIe port can
> enter D3.
> pci_pm_suspend_noirq() uses the return from pci_power_manageable() to
> decide whether to try to put a device into its target state for a sleep
> cycle via pci_prepare_to_sleep().
> 
> For devices that support D3, the target state is selected by this policy:
> 1. If platform_pci_power_manageable():
>    Use platform_pci_choose_state()
> 2. If the device is armed for wakeup:
>    Select the deepest D-state that supports a PME.
> 3. Else:
>    Use D3hot.
> 
> Devices are considered power manageable by the platform when they have
> one or more objects described in the table in section 7.3 of the ACPI 6.5
> specification.
> 
> When devices are not considered power manageable; specs are ambiguous as
> to what should happen.  In this situation Windows 11 leaves PCIe
> ports in D0 while Linux puts them into D3 due to the above mentioned
> commit.
> 
> In Windows systems that support Modern Standby specify hardware
> pre-conditions for the SoC to achieve the lowest power state by device
> constraints in a SOC specific "Power Engine Plugin" (PEP) [2] [3].
> They can be marked as disabled or enabled and when enabled can specify
> the minimum power state required for an ACPI device.
> 
> When it is ambiguous what should happen, adjust the logic for
> pci_target_state() to check whether a device constraint is present
> and enabled.
> * If power manageable by ACPI use this to get to select target state
> * If a device constraint is present but disabled then choose D0
> * If a device constraint is present and enabled then use it
> * If a device constraint is not present, then continue to existing
>   logic (if marked for wakeup use deepest state that PME works)
> * If not marked for wakeup choose D3hot

...

> +/**
> + * acpi_get_lps0_constraint - get any LPS0 constraint for a device
> + * @dev: device to get constraint for
> + *
> + * If a constraint has been specified in the _DSM method for the device,
> + * and the constraint is enabled return it.  If the constraint is disabled,
> + * return 0. Otherwise, return -ENODEV.
> + */

I believe you get a kernel-doc warning. Always test kernel doc with

	scripts/kernel-doc -v -none -Wall ...your file...

...

> +/**
> + * acpi_pci_device_constraint - determine if the platform has a contraint for the device
> + * @dev: PCI device to check
> + * @result (out): the constraint specified by the platform
> + *
> + * If the platform has specified a constraint for a device, this function will
> + * return 0 and set @result to the constraint.
> + * Otherwise, it will return an error code.
> + */

Ditto.

...

> +int acpi_pci_device_constraint(struct pci_dev *dev, int *result)
> +{
> +	int constraint;
> +
> +	constraint = acpi_get_lps0_constraint(&dev->dev);

> +	pci_dbg(dev, "ACPI device constraint: %d\n", constraint);

Does it make sense before the below check? Why can we be interested in the
_exact_ negative values? (Note that non-printing is already a sign that either
we don't call this or have negative constraint.)

> +	if (constraint < 0)
> +		return constraint;
> +	*result = constraint;
> +
> +	return 0;
> +}

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v9 2/3] ACPI: x86: s2idle: Adjust constraints logic building
  2023-08-04  1:02 ` [PATCH v9 2/3] ACPI: x86: s2idle: Adjust constraints logic building Mario Limonciello
@ 2023-08-04  4:31   ` Andy Shevchenko
  0 siblings, 0 replies; 10+ messages in thread
From: Andy Shevchenko @ 2023-08-04  4:31 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Rafael J . Wysocki, Mika Westerberg, Bjorn Helgaas, linux-pci,
	linux-kernel, linux-acpi, Kuppuswamy Sathyanarayanan, Iain Lane,
	Shyam-sundar S-k

On Thu, Aug 03, 2023 at 08:02:28PM -0500, Mario Limonciello wrote:
> Constraints are currently only stored when enabled.  To enable
> the ability to check if constraints are present they need to be
> stored even if disabled.

...

> @@ -120,8 +121,7 @@ static void lpi_device_get_constraints_amd(void)
>  			if (!lpi_constraints_table)
>  				goto free_acpi_buffer;
>  
> -			acpi_handle_debug(lps0_device_handle,
> -					  "LPI: constraints list begin:\n");
> +			acpi_handle_debug(lps0_device_handle, "LPI: constraints list begin:\n");
>  
>  			for (j = 0; j < package->package.count; ++j) {
>  				union acpi_object *info_obj = &package->package.elements[j];

Unrelated change.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v9 3/3] PCI/ACPI: Use device constraints to decide PCI target state fallback policy
  2023-08-04  4:30   ` Andy Shevchenko
@ 2023-08-04  4:37     ` Mario Limonciello
  2023-08-04  4:57       ` Andy Shevchenko
  0 siblings, 1 reply; 10+ messages in thread
From: Mario Limonciello @ 2023-08-04  4:37 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Rafael J . Wysocki, Mika Westerberg, Bjorn Helgaas, linux-pci,
	linux-kernel, linux-acpi, Kuppuswamy Sathyanarayanan, Iain Lane,
	Shyam-sundar S-k

On 8/3/23 23:30, Andy Shevchenko wrote:
> On Thu, Aug 03, 2023 at 08:02:29PM -0500, Mario Limonciello wrote:
>> Since commit 9d26d3a8f1b0 ("PCI: Put PCIe ports into D3 during suspend")
>> PCIe ports from modern machines (>=2015) are allowed to be put into D3 by
>> storing a value to the `bridge_d3` variable in the `struct pci_dev`
>> structure.
>>
>> pci_power_manageable() uses this variable to indicate a PCIe port can
>> enter D3.
>> pci_pm_suspend_noirq() uses the return from pci_power_manageable() to
>> decide whether to try to put a device into its target state for a sleep
>> cycle via pci_prepare_to_sleep().
>>
>> For devices that support D3, the target state is selected by this policy:
>> 1. If platform_pci_power_manageable():
>>     Use platform_pci_choose_state()
>> 2. If the device is armed for wakeup:
>>     Select the deepest D-state that supports a PME.
>> 3. Else:
>>     Use D3hot.
>>
>> Devices are considered power manageable by the platform when they have
>> one or more objects described in the table in section 7.3 of the ACPI 6.5
>> specification.
>>
>> When devices are not considered power manageable; specs are ambiguous as
>> to what should happen.  In this situation Windows 11 leaves PCIe
>> ports in D0 while Linux puts them into D3 due to the above mentioned
>> commit.
>>
>> In Windows systems that support Modern Standby specify hardware
>> pre-conditions for the SoC to achieve the lowest power state by device
>> constraints in a SOC specific "Power Engine Plugin" (PEP) [2] [3].
>> They can be marked as disabled or enabled and when enabled can specify
>> the minimum power state required for an ACPI device.
>>
>> When it is ambiguous what should happen, adjust the logic for
>> pci_target_state() to check whether a device constraint is present
>> and enabled.
>> * If power manageable by ACPI use this to get to select target state
>> * If a device constraint is present but disabled then choose D0
>> * If a device constraint is present and enabled then use it
>> * If a device constraint is not present, then continue to existing
>>    logic (if marked for wakeup use deepest state that PME works)
>> * If not marked for wakeup choose D3hot
> 
> ...
> 
>> +/**
>> + * acpi_get_lps0_constraint - get any LPS0 constraint for a device
>> + * @dev: device to get constraint for
>> + *
>> + * If a constraint has been specified in the _DSM method for the device,
>> + * and the constraint is enabled return it.  If the constraint is disabled,
>> + * return 0. Otherwise, return -ENODEV.
>> + */
> 
> I believe you get a kernel-doc warning. Always test kernel doc with
> 
> 	scripts/kernel-doc -v -none -Wall ...your file...
> 

Thanks, will double check these.

> ...
> 
>> +/**
>> + * acpi_pci_device_constraint - determine if the platform has a contraint for the device
>> + * @dev: PCI device to check
>> + * @result (out): the constraint specified by the platform
>> + *
>> + * If the platform has specified a constraint for a device, this function will
>> + * return 0 and set @result to the constraint.
>> + * Otherwise, it will return an error code.
>> + */
> 
> Ditto.
> 
> ...
> 
>> +int acpi_pci_device_constraint(struct pci_dev *dev, int *result)
>> +{
>> +	int constraint;
>> +
>> +	constraint = acpi_get_lps0_constraint(&dev->dev);
> 
>> +	pci_dbg(dev, "ACPI device constraint: %d\n", constraint);
> 
> Does it make sense before the below check? Why can we be interested in the
> _exact_ negative values? (Note that non-printing is already a sign that either
> we don't call this or have negative constraint.)

There are two different negative values that can come up:
-ENODEV or -EINVAL.  Both were interesting while coming up with this 
series because they mean something different about why a constraint 
wasn't selected.

-ENODEV means the constraint wasn't found.
-EINVAL means the constraint was found but something is wrong with the 
table parser or the table itself.  I found the table parser wasn't 
working correctly originaly thanks to this.

Maybe now that I've got it all working you're right and this should go
after the error checking.

> 
>> +	if (constraint < 0)
>> +		return constraint;
>> +	*result = constraint;
>> +
>> +	return 0;
>> +}
> 


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v9 3/3] PCI/ACPI: Use device constraints to decide PCI target state fallback policy
  2023-08-04  4:37     ` Mario Limonciello
@ 2023-08-04  4:57       ` Andy Shevchenko
  0 siblings, 0 replies; 10+ messages in thread
From: Andy Shevchenko @ 2023-08-04  4:57 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Rafael J . Wysocki, Mika Westerberg, Bjorn Helgaas, linux-pci,
	linux-kernel, linux-acpi, Kuppuswamy Sathyanarayanan, Iain Lane,
	Shyam-sundar S-k

On Thu, Aug 03, 2023 at 11:37:10PM -0500, Mario Limonciello wrote:
> On 8/3/23 23:30, Andy Shevchenko wrote:
> > On Thu, Aug 03, 2023 at 08:02:29PM -0500, Mario Limonciello wrote:

...

> > > +	pci_dbg(dev, "ACPI device constraint: %d\n", constraint);
> > 
> > Does it make sense before the below check? Why can we be interested in the
> > _exact_ negative values? (Note that non-printing is already a sign that either
> > we don't call this or have negative constraint.)
> 
> There are two different negative values that can come up:
> -ENODEV or -EINVAL.  Both were interesting while coming up with this series
> because they mean something different about why a constraint wasn't
> selected.
> 
> -ENODEV means the constraint wasn't found.
> -EINVAL means the constraint was found but something is wrong with the table
> parser or the table itself.  I found the table parser wasn't working
> correctly originaly thanks to this.
> 
> Maybe now that I've got it all working you're right and this should go
> after the error checking.

Or maybe moved to the acpi_get_lps0_constraint().

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v9 3/3] PCI/ACPI: Use device constraints to decide PCI target state fallback policy
  2023-08-04  1:02 ` [PATCH v9 3/3] PCI/ACPI: Use device constraints to decide PCI target state fallback policy Mario Limonciello
  2023-08-04  4:30   ` Andy Shevchenko
@ 2023-08-04 13:17   ` Mika Westerberg
  2023-08-04 15:56     ` Limonciello, Mario
  1 sibling, 1 reply; 10+ messages in thread
From: Mika Westerberg @ 2023-08-04 13:17 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Rafael J . Wysocki, Bjorn Helgaas, linux-pci, linux-kernel,
	Andy Shevchenko, linux-acpi, Kuppuswamy Sathyanarayanan,
	Iain Lane, Shyam-sundar S-k

On Thu, Aug 03, 2023 at 08:02:29PM -0500, Mario Limonciello wrote:
> +/**
> + * acpi_pci_device_constraint - determine if the platform has a contraint for the device
> + * @dev: PCI device to check
> + * @result (out): the constraint specified by the platform
> + *
> + * If the platform has specified a constraint for a device, this function will
> + * return 0 and set @result to the constraint.
> + * Otherwise, it will return an error code.
> + */
> +int acpi_pci_device_constraint(struct pci_dev *dev, int *result)
> +{
> +	int constraint;
> +
> +	constraint = acpi_get_lps0_constraint(&dev->dev);
> +	pci_dbg(dev, "ACPI device constraint: %d\n", constraint);
> +	if (constraint < 0)
> +		return constraint;
> +	*result = constraint;

Is there something preventing to return the constraint directly instead
of storing it into "result"?

> +
> +	return 0;
> +}
> +
>  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 60230da957e0c..6c70f921467c6 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 int platform_get_constraint(struct pci_dev *dev, int *result)

Ditto here.

> +{
> +	if (pci_use_mid_pm())
> +		return -ENODEV;
> +
> +	return acpi_pci_device_constraint(dev, result);
> +}
> +

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v9 3/3] PCI/ACPI: Use device constraints to decide PCI target state fallback policy
  2023-08-04 13:17   ` Mika Westerberg
@ 2023-08-04 15:56     ` Limonciello, Mario
  0 siblings, 0 replies; 10+ messages in thread
From: Limonciello, Mario @ 2023-08-04 15:56 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: Rafael J . Wysocki, Bjorn Helgaas, linux-pci, linux-kernel,
	Andy Shevchenko, linux-acpi, Kuppuswamy Sathyanarayanan,
	Iain Lane, Shyam-sundar S-k



On 8/4/2023 8:17 AM, Mika Westerberg wrote:
> On Thu, Aug 03, 2023 at 08:02:29PM -0500, Mario Limonciello wrote:
>> +/**
>> + * acpi_pci_device_constraint - determine if the platform has a contraint for the device
>> + * @dev: PCI device to check
>> + * @result (out): the constraint specified by the platform
>> + *
>> + * If the platform has specified a constraint for a device, this function will
>> + * return 0 and set @result to the constraint.
>> + * Otherwise, it will return an error code.
>> + */
>> +int acpi_pci_device_constraint(struct pci_dev *dev, int *result)
>> +{
>> +	int constraint;
>> +
>> +	constraint = acpi_get_lps0_constraint(&dev->dev);
>> +	pci_dbg(dev, "ACPI device constraint: %d\n", constraint);
>> +	if (constraint < 0)
>> +		return constraint;
>> +	*result = constraint;
> 
> Is there something preventing to return the constraint directly instead
> of storing it into "result"?

My aim was to make the caller use it a pass/fail function.

I'll adjust it so that the caller would look for >= 0 instead.

> 
>> +
>> +	return 0;
>> +}
>> +
>>   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 60230da957e0c..6c70f921467c6 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 int platform_get_constraint(struct pci_dev *dev, int *result)
> 
> Ditto here.
> 
>> +{
>> +	if (pci_use_mid_pm())
>> +		return -ENODEV;
>> +
>> +	return acpi_pci_device_constraint(dev, result);
>> +}
>> +

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2023-08-04 15:56 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-04  1:02 [PATCH v9 0/3] Fix wakeup problems on some AMD platforms Mario Limonciello
2023-08-04  1:02 ` [PATCH v9 1/3] ACPI: Add comments to clarify some #ifdef statements Mario Limonciello
2023-08-04  1:02 ` [PATCH v9 2/3] ACPI: x86: s2idle: Adjust constraints logic building Mario Limonciello
2023-08-04  4:31   ` Andy Shevchenko
2023-08-04  1:02 ` [PATCH v9 3/3] PCI/ACPI: Use device constraints to decide PCI target state fallback policy Mario Limonciello
2023-08-04  4:30   ` Andy Shevchenko
2023-08-04  4:37     ` Mario Limonciello
2023-08-04  4:57       ` Andy Shevchenko
2023-08-04 13:17   ` Mika Westerberg
2023-08-04 15:56     ` Limonciello, Mario

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).