Merge branch 'acpi-pm'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 25 Aug 2023 18:55:47 +0000 (20:55 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 25 Aug 2023 18:55:47 +0000 (20:55 +0200)
Merge ACPI power management updates for 6.6-rc1:

 - Fix and clean up suspend-to-idle interface for AMD systems (Mario
   Limonciello, Andy Shevchenko).

* acpi-pm:
  ACPI: x86: s2idle: Add a function to get LPS0 constraint for a device
  ACPI: x86: s2idle: Add for_each_lpi_constraint() helper
  ACPI: x86: s2idle: Add more debugging for AMD constraints parsing
  ACPI: x86: s2idle: Fix a logic error parsing AMD constraints table
  ACPI: x86: s2idle: Catch multiple ACPI_TYPE_PACKAGE objects
  ACPI: x86: s2idle: Post-increment variables when getting constraints
  ACPI: Adjust #ifdef for *_lps0_dev use

drivers/acpi/x86/s2idle.c
include/linux/acpi.h

index ce62e61..08f7c67 100644 (file)
@@ -94,6 +94,11 @@ static struct lpi_constraints *lpi_constraints_table;
 static int lpi_constraints_table_size;
 static int rev_id;
 
+#define for_each_lpi_constraint(entry)                                         \
+       for (int i = 0;                                                         \
+            entry = &lpi_constraints_table[i], i < lpi_constraints_table_size; \
+            i++)
+
 static void lpi_device_get_constraints_amd(void)
 {
        union acpi_object *out_obj;
@@ -113,6 +118,12 @@ static void lpi_device_get_constraints_amd(void)
                union acpi_object *package = &out_obj->package.elements[i];
 
                if (package->type == ACPI_TYPE_PACKAGE) {
+                       if (lpi_constraints_table) {
+                               acpi_handle_err(lps0_device_handle,
+                                               "Duplicate constraints list\n");
+                               goto free_acpi_buffer;
+                       }
+
                        lpi_constraints_table = kcalloc(package->package.count,
                                                        sizeof(*lpi_constraints_table),
                                                        GFP_KERNEL);
@@ -123,17 +134,16 @@ static void lpi_device_get_constraints_amd(void)
                        acpi_handle_debug(lps0_device_handle,
                                          "LPI: constraints list begin:\n");
 
-                       for (j = 0; j < package->package.count; ++j) {
+                       for (j = 0; j < package->package.count; j++) {
                                union acpi_object *info_obj = &package->package.elements[j];
                                struct lpi_device_constraint_amd dev_info = {};
                                struct lpi_constraints *list;
                                acpi_status status;
 
-                               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 = &lpi_constraints_table[lpi_constraints_table_size];
-                                       list->min_dstate = -1;
+                               for (k = 0; k < info_obj->package.count; k++) {
+                                       union acpi_object *obj = &info_obj->package.elements[k];
 
                                        switch (k) {
                                        case 0:
@@ -149,27 +159,25 @@ 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;
+                               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);
 
-                                       status = acpi_get_handle(NULL, dev_info.name,
-                                                                &list->handle);
-                                       if (ACPI_FAILURE(status))
-                                               continue;
+                               if (!dev_info.enabled || !dev_info.name ||
+                                   !dev_info.min_dstate)
+                                       continue;
 
-                                       acpi_handle_debug(lps0_device_handle,
-                                                         "Name:%s\n", dev_info.name);
+                               status = acpi_get_handle(NULL, dev_info.name, &list->handle);
+                               if (ACPI_FAILURE(status))
+                                       continue;
 
-                                       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;
-                                       }
-                               }
                                lpi_constraints_table_size++;
                        }
                }
@@ -214,7 +222,7 @@ static void lpi_device_get_constraints(void)
                if (!package)
                        continue;
 
-               for (j = 0; j < package->package.count; ++j) {
+               for (j = 0; j < package->package.count; j++) {
                        union acpi_object *element =
                                        &(package->package.elements[j]);
 
@@ -246,7 +254,7 @@ static void lpi_device_get_constraints(void)
 
                constraint->min_dstate = -1;
 
-               for (j = 0; j < package_count; ++j) {
+               for (j = 0; j < package_count; j++) {
                        union acpi_object *info_obj = &info.package[j];
                        union acpi_object *cnstr_pkg;
                        union acpi_object *obj;
@@ -291,32 +299,55 @@ free_acpi_buffer:
        ACPI_FREE(out_obj);
 }
 
+/**
+ * acpi_get_lps0_constraint - Get the LPS0 constraint for a device.
+ * @adev: Device to get the constraint for.
+ *
+ * The LPS0 constraint is the shallowest (minimum) power state in which the
+ * device can be so as to allow the platform as a whole to achieve additional
+ * energy conservation by utilizing a system-wide low-power state.
+ *
+ * Returns:
+ *  - ACPI power state value of the constraint for @adev on success.
+ *  - Otherwise, ACPI_STATE_UNKNOWN.
+ */
+int acpi_get_lps0_constraint(struct acpi_device *adev)
+{
+       struct lpi_constraints *entry;
+
+       for_each_lpi_constraint(entry) {
+               if (adev->handle == entry->handle)
+                       return entry->min_dstate;
+       }
+
+       return ACPI_STATE_UNKNOWN;
+}
+
 static void lpi_check_constraints(void)
 {
-       int i;
+       struct lpi_constraints *entry;
 
-       for (i = 0; i < lpi_constraints_table_size; ++i) {
-               acpi_handle handle = lpi_constraints_table[i].handle;
-               struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
+       for_each_lpi_constraint(entry) {
+               struct acpi_device *adev = acpi_fetch_acpi_dev(entry->handle);
 
                if (!adev)
                        continue;
 
-               acpi_handle_debug(handle,
+               acpi_handle_debug(entry->handle,
                        "LPI: required min power state:%s current power state:%s\n",
-                       acpi_power_state_string(lpi_constraints_table[i].min_dstate),
+                       acpi_power_state_string(entry->min_dstate),
                        acpi_power_state_string(adev->power.state));
 
                if (!adev->flags.power_manageable) {
-                       acpi_handle_info(handle, "LPI: Device not power manageable\n");
-                       lpi_constraints_table[i].handle = NULL;
+                       acpi_handle_info(entry->handle, "LPI: Device not power manageable\n");
+                       entry->handle = NULL;
                        continue;
                }
 
-               if (adev->power.state < lpi_constraints_table[i].min_dstate)
-                       acpi_handle_info(handle,
+               if (adev->power.state < entry->min_dstate)
+                       acpi_handle_info(entry->handle,
                                "LPI: Constraint not met; min power state:%s current power state:%s\n",
-                               acpi_power_state_string(lpi_constraints_table[i].min_dstate),
+                               acpi_power_state_string(entry->min_dstate),
                                acpi_power_state_string(adev->power.state));
        }
 }
index 58a0fdf..a73246c 100644 (file)
@@ -1098,7 +1098,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_SUSPEND) && defined(CONFIG_X86)
 struct acpi_s2idle_dev_ops {
        struct list_head list_node;
        void (*prepare)(void);
@@ -1107,7 +1107,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 acpi_device *adev);
+#else /* CONFIG_SUSPEND && CONFIG_X86 */
+static inline int acpi_get_lps0_constraint(struct device *dev)
+{
+       return ACPI_STATE_UNKNOWN;
+}
+#endif /* CONFIG_SUSPEND && CONFIG_X86 */
 #ifndef CONFIG_IA64
 void arch_reserve_mem_area(acpi_physical_address addr, size_t size);
 #else