Loading Documentation/ABI/testing/sysfs-power +12 −0 Original line number Diff line number Diff line Loading @@ -273,3 +273,15 @@ Description: This output is useful for system wakeup diagnostics of spurious wakeup interrupts. What: /sys/power/pm_debug_messages Date: July 2017 Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/power/pm_debug_messages file controls the printing of debug messages from the system suspend/hiberbation infrastructure to the kernel log. Writing a "1" to this file enables the debug messages and writing a "0" (default) to it disables them. Reads from this file return the current value. Documentation/power/states.txt +3 −1 Original line number Diff line number Diff line Loading @@ -35,7 +35,9 @@ only one way to cause the system to go into the Suspend-To-RAM state (write The default suspend mode (ie. the one to be used without writing anything into /sys/power/mem_sleep) is either "deep" (if Suspend-To-RAM is supported) or "s2idle", but it can be overridden by the value of the "mem_sleep_default" parameter in the kernel command line. parameter in the kernel command line. On some ACPI-based systems, depending on the information in the FADT, the default may be "s2idle" even if Suspend-To-RAM is supported. The properties of all of the sleep states are described below. Loading arch/arm/mach-tegra/cpuidle-tegra114.c +2 −2 Original line number Diff line number Diff line Loading @@ -60,7 +60,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev, return index; } static void tegra114_idle_enter_freeze(struct cpuidle_device *dev, static void tegra114_idle_enter_s2idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { Loading @@ -77,7 +77,7 @@ static struct cpuidle_driver tegra_idle_driver = { #ifdef CONFIG_PM_SLEEP [1] = { .enter = tegra114_idle_power_down, .enter_freeze = tegra114_idle_enter_freeze, .enter_s2idle = tegra114_idle_enter_s2idle, .exit_latency = 500, .target_residency = 1000, .flags = CPUIDLE_FLAG_TIMER_STOP, Loading drivers/acpi/processor_idle.c +3 −3 Original line number Diff line number Diff line Loading @@ -789,7 +789,7 @@ static int acpi_idle_enter(struct cpuidle_device *dev, return index; } static void acpi_idle_enter_freeze(struct cpuidle_device *dev, static void acpi_idle_enter_s2idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); Loading Loading @@ -867,14 +867,14 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr) drv->safe_state_index = count; } /* * Halt-induced C1 is not good for ->enter_freeze, because it * Halt-induced C1 is not good for ->enter_s2idle, because it * re-enables interrupts on exit. Moreover, C1 is generally not * particularly interesting from the suspend-to-idle angle, so * avoid C1 and the situations in which we may need to fall back * to it altogether. */ if (cx->type != ACPI_STATE_C1 && !acpi_idle_fallback_to_c1(pr)) state->enter_freeze = acpi_idle_enter_freeze; state->enter_s2idle = acpi_idle_enter_s2idle; count++; if (count == CPUIDLE_STATE_MAX) Loading drivers/acpi/sleep.c +188 −14 Original line number Diff line number Diff line Loading @@ -669,6 +669,7 @@ static const struct acpi_device_id lps0_device_ids[] = { #define ACPI_LPS0_DSM_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66" #define ACPI_LPS0_GET_DEVICE_CONSTRAINTS 1 #define ACPI_LPS0_SCREEN_OFF 3 #define ACPI_LPS0_SCREEN_ON 4 #define ACPI_LPS0_ENTRY 5 Loading @@ -680,6 +681,166 @@ static acpi_handle lps0_device_handle; static guid_t lps0_dsm_guid; static char lps0_dsm_func_mask; /* Device constraint entry structure */ struct lpi_device_info { char *name; int enabled; union acpi_object *package; }; /* Constraint package structure */ struct lpi_device_constraint { int uid; int min_dstate; int function_states; }; struct lpi_constraints { acpi_handle handle; int min_dstate; }; static struct lpi_constraints *lpi_constraints_table; static int lpi_constraints_table_size; static void lpi_device_get_constraints(void) { union acpi_object *out_obj; int i; out_obj = acpi_evaluate_dsm_typed(lps0_device_handle, &lps0_dsm_guid, 1, ACPI_LPS0_GET_DEVICE_CONSTRAINTS, NULL, ACPI_TYPE_PACKAGE); acpi_handle_debug(lps0_device_handle, "_DSM function 1 eval %s\n", out_obj ? "successful" : "failed"); if (!out_obj) return; lpi_constraints_table = kcalloc(out_obj->package.count, sizeof(*lpi_constraints_table), GFP_KERNEL); if (!lpi_constraints_table) goto free_acpi_buffer; acpi_handle_debug(lps0_device_handle, "LPI: constraints list begin:\n"); for (i = 0; i < out_obj->package.count; i++) { struct lpi_constraints *constraint; acpi_status status; union acpi_object *package = &out_obj->package.elements[i]; struct lpi_device_info info = { }; int package_count = 0, j; if (!package) continue; for (j = 0; j < package->package.count; ++j) { union acpi_object *element = &(package->package.elements[j]); switch (element->type) { case ACPI_TYPE_INTEGER: info.enabled = element->integer.value; break; case ACPI_TYPE_STRING: info.name = element->string.pointer; break; case ACPI_TYPE_PACKAGE: package_count = element->package.count; info.package = element->package.elements; break; } } if (!info.enabled || !info.package || !info.name) continue; constraint = &lpi_constraints_table[lpi_constraints_table_size]; status = acpi_get_handle(NULL, info.name, &constraint->handle); if (ACPI_FAILURE(status)) continue; acpi_handle_debug(lps0_device_handle, "index:%d Name:%s\n", i, info.name); constraint->min_dstate = -1; for (j = 0; j < package_count; ++j) { union acpi_object *info_obj = &info.package[j]; union acpi_object *cnstr_pkg; union acpi_object *obj; struct lpi_device_constraint dev_info; switch (info_obj->type) { case ACPI_TYPE_INTEGER: /* version */ break; case ACPI_TYPE_PACKAGE: if (info_obj->package.count < 2) break; cnstr_pkg = info_obj->package.elements; obj = &cnstr_pkg[0]; dev_info.uid = obj->integer.value; obj = &cnstr_pkg[1]; dev_info.min_dstate = obj->integer.value; acpi_handle_debug(lps0_device_handle, "uid:%d min_dstate:%s\n", dev_info.uid, acpi_power_state_string(dev_info.min_dstate)); constraint->min_dstate = dev_info.min_dstate; break; } } if (constraint->min_dstate < 0) { acpi_handle_debug(lps0_device_handle, "Incomplete constraint defined\n"); continue; } lpi_constraints_table_size++; } acpi_handle_debug(lps0_device_handle, "LPI: constraints list end\n"); free_acpi_buffer: ACPI_FREE(out_obj); } static void lpi_check_constraints(void) { int i; for (i = 0; i < lpi_constraints_table_size; ++i) { struct acpi_device *adev; if (acpi_bus_get_device(lpi_constraints_table[i].handle, &adev)) continue; acpi_handle_debug(adev->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(adev->power.state)); if (!adev->flags.power_manageable) { acpi_handle_info(adev->handle, "LPI: Device not power manageble\n"); continue; } if (adev->power.state < lpi_constraints_table[i].min_dstate) acpi_handle_info(adev->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(adev->power.state)); } } static void acpi_sleep_run_lps0_dsm(unsigned int func) { union acpi_object *out_obj; Loading Loading @@ -714,6 +875,12 @@ static int lps0_device_attach(struct acpi_device *adev, if ((bitmask & ACPI_S2IDLE_FUNC_MASK) == ACPI_S2IDLE_FUNC_MASK) { lps0_dsm_func_mask = bitmask; lps0_device_handle = adev->handle; /* * Use suspend-to-idle by default if the default * suspend mode was not set from the command line. */ if (mem_sleep_default > PM_SUSPEND_MEM) mem_sleep_current = PM_SUSPEND_TO_IDLE; } acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n", Loading @@ -723,6 +890,9 @@ static int lps0_device_attach(struct acpi_device *adev, "_DSM function 0 evaluation failed\n"); } ACPI_FREE(out_obj); lpi_device_get_constraints(); return 0; } Loading @@ -731,14 +901,14 @@ static struct acpi_scan_handler lps0_handler = { .attach = lps0_device_attach, }; static int acpi_freeze_begin(void) static int acpi_s2idle_begin(void) { acpi_scan_lock_acquire(); s2idle_in_progress = true; return 0; } static int acpi_freeze_prepare(void) static int acpi_s2idle_prepare(void) { if (lps0_device_handle) { acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF); Loading @@ -758,8 +928,12 @@ static int acpi_freeze_prepare(void) return 0; } static void acpi_freeze_wake(void) static void acpi_s2idle_wake(void) { if (pm_debug_messages_on) lpi_check_constraints(); /* * If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means * that the SCI has triggered while suspended, so cancel the wakeup in Loading @@ -772,7 +946,7 @@ static void acpi_freeze_wake(void) } } static void acpi_freeze_sync(void) static void acpi_s2idle_sync(void) { /* * Process all pending events in case there are any wakeup ones. Loading @@ -785,7 +959,7 @@ static void acpi_freeze_sync(void) s2idle_wakeup = false; } static void acpi_freeze_restore(void) static void acpi_s2idle_restore(void) { if (acpi_sci_irq_valid()) disable_irq_wake(acpi_sci_irq); Loading @@ -798,19 +972,19 @@ static void acpi_freeze_restore(void) } } static void acpi_freeze_end(void) static void acpi_s2idle_end(void) { s2idle_in_progress = false; acpi_scan_lock_release(); } static const struct platform_freeze_ops acpi_freeze_ops = { .begin = acpi_freeze_begin, .prepare = acpi_freeze_prepare, .wake = acpi_freeze_wake, .sync = acpi_freeze_sync, .restore = acpi_freeze_restore, .end = acpi_freeze_end, static const struct platform_s2idle_ops acpi_s2idle_ops = { .begin = acpi_s2idle_begin, .prepare = acpi_s2idle_prepare, .wake = acpi_s2idle_wake, .sync = acpi_s2idle_sync, .restore = acpi_s2idle_restore, .end = acpi_s2idle_end, }; static void acpi_sleep_suspend_setup(void) Loading @@ -825,7 +999,7 @@ static void acpi_sleep_suspend_setup(void) &acpi_suspend_ops_old : &acpi_suspend_ops); acpi_scan_add_handler(&lps0_handler); freeze_set_ops(&acpi_freeze_ops); s2idle_set_ops(&acpi_s2idle_ops); } #else /* !CONFIG_SUSPEND */ Loading Loading
Documentation/ABI/testing/sysfs-power +12 −0 Original line number Diff line number Diff line Loading @@ -273,3 +273,15 @@ Description: This output is useful for system wakeup diagnostics of spurious wakeup interrupts. What: /sys/power/pm_debug_messages Date: July 2017 Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Description: The /sys/power/pm_debug_messages file controls the printing of debug messages from the system suspend/hiberbation infrastructure to the kernel log. Writing a "1" to this file enables the debug messages and writing a "0" (default) to it disables them. Reads from this file return the current value.
Documentation/power/states.txt +3 −1 Original line number Diff line number Diff line Loading @@ -35,7 +35,9 @@ only one way to cause the system to go into the Suspend-To-RAM state (write The default suspend mode (ie. the one to be used without writing anything into /sys/power/mem_sleep) is either "deep" (if Suspend-To-RAM is supported) or "s2idle", but it can be overridden by the value of the "mem_sleep_default" parameter in the kernel command line. parameter in the kernel command line. On some ACPI-based systems, depending on the information in the FADT, the default may be "s2idle" even if Suspend-To-RAM is supported. The properties of all of the sleep states are described below. Loading
arch/arm/mach-tegra/cpuidle-tegra114.c +2 −2 Original line number Diff line number Diff line Loading @@ -60,7 +60,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev, return index; } static void tegra114_idle_enter_freeze(struct cpuidle_device *dev, static void tegra114_idle_enter_s2idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { Loading @@ -77,7 +77,7 @@ static struct cpuidle_driver tegra_idle_driver = { #ifdef CONFIG_PM_SLEEP [1] = { .enter = tegra114_idle_power_down, .enter_freeze = tegra114_idle_enter_freeze, .enter_s2idle = tegra114_idle_enter_s2idle, .exit_latency = 500, .target_residency = 1000, .flags = CPUIDLE_FLAG_TIMER_STOP, Loading
drivers/acpi/processor_idle.c +3 −3 Original line number Diff line number Diff line Loading @@ -789,7 +789,7 @@ static int acpi_idle_enter(struct cpuidle_device *dev, return index; } static void acpi_idle_enter_freeze(struct cpuidle_device *dev, static void acpi_idle_enter_s2idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); Loading Loading @@ -867,14 +867,14 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr) drv->safe_state_index = count; } /* * Halt-induced C1 is not good for ->enter_freeze, because it * Halt-induced C1 is not good for ->enter_s2idle, because it * re-enables interrupts on exit. Moreover, C1 is generally not * particularly interesting from the suspend-to-idle angle, so * avoid C1 and the situations in which we may need to fall back * to it altogether. */ if (cx->type != ACPI_STATE_C1 && !acpi_idle_fallback_to_c1(pr)) state->enter_freeze = acpi_idle_enter_freeze; state->enter_s2idle = acpi_idle_enter_s2idle; count++; if (count == CPUIDLE_STATE_MAX) Loading
drivers/acpi/sleep.c +188 −14 Original line number Diff line number Diff line Loading @@ -669,6 +669,7 @@ static const struct acpi_device_id lps0_device_ids[] = { #define ACPI_LPS0_DSM_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66" #define ACPI_LPS0_GET_DEVICE_CONSTRAINTS 1 #define ACPI_LPS0_SCREEN_OFF 3 #define ACPI_LPS0_SCREEN_ON 4 #define ACPI_LPS0_ENTRY 5 Loading @@ -680,6 +681,166 @@ static acpi_handle lps0_device_handle; static guid_t lps0_dsm_guid; static char lps0_dsm_func_mask; /* Device constraint entry structure */ struct lpi_device_info { char *name; int enabled; union acpi_object *package; }; /* Constraint package structure */ struct lpi_device_constraint { int uid; int min_dstate; int function_states; }; struct lpi_constraints { acpi_handle handle; int min_dstate; }; static struct lpi_constraints *lpi_constraints_table; static int lpi_constraints_table_size; static void lpi_device_get_constraints(void) { union acpi_object *out_obj; int i; out_obj = acpi_evaluate_dsm_typed(lps0_device_handle, &lps0_dsm_guid, 1, ACPI_LPS0_GET_DEVICE_CONSTRAINTS, NULL, ACPI_TYPE_PACKAGE); acpi_handle_debug(lps0_device_handle, "_DSM function 1 eval %s\n", out_obj ? "successful" : "failed"); if (!out_obj) return; lpi_constraints_table = kcalloc(out_obj->package.count, sizeof(*lpi_constraints_table), GFP_KERNEL); if (!lpi_constraints_table) goto free_acpi_buffer; acpi_handle_debug(lps0_device_handle, "LPI: constraints list begin:\n"); for (i = 0; i < out_obj->package.count; i++) { struct lpi_constraints *constraint; acpi_status status; union acpi_object *package = &out_obj->package.elements[i]; struct lpi_device_info info = { }; int package_count = 0, j; if (!package) continue; for (j = 0; j < package->package.count; ++j) { union acpi_object *element = &(package->package.elements[j]); switch (element->type) { case ACPI_TYPE_INTEGER: info.enabled = element->integer.value; break; case ACPI_TYPE_STRING: info.name = element->string.pointer; break; case ACPI_TYPE_PACKAGE: package_count = element->package.count; info.package = element->package.elements; break; } } if (!info.enabled || !info.package || !info.name) continue; constraint = &lpi_constraints_table[lpi_constraints_table_size]; status = acpi_get_handle(NULL, info.name, &constraint->handle); if (ACPI_FAILURE(status)) continue; acpi_handle_debug(lps0_device_handle, "index:%d Name:%s\n", i, info.name); constraint->min_dstate = -1; for (j = 0; j < package_count; ++j) { union acpi_object *info_obj = &info.package[j]; union acpi_object *cnstr_pkg; union acpi_object *obj; struct lpi_device_constraint dev_info; switch (info_obj->type) { case ACPI_TYPE_INTEGER: /* version */ break; case ACPI_TYPE_PACKAGE: if (info_obj->package.count < 2) break; cnstr_pkg = info_obj->package.elements; obj = &cnstr_pkg[0]; dev_info.uid = obj->integer.value; obj = &cnstr_pkg[1]; dev_info.min_dstate = obj->integer.value; acpi_handle_debug(lps0_device_handle, "uid:%d min_dstate:%s\n", dev_info.uid, acpi_power_state_string(dev_info.min_dstate)); constraint->min_dstate = dev_info.min_dstate; break; } } if (constraint->min_dstate < 0) { acpi_handle_debug(lps0_device_handle, "Incomplete constraint defined\n"); continue; } lpi_constraints_table_size++; } acpi_handle_debug(lps0_device_handle, "LPI: constraints list end\n"); free_acpi_buffer: ACPI_FREE(out_obj); } static void lpi_check_constraints(void) { int i; for (i = 0; i < lpi_constraints_table_size; ++i) { struct acpi_device *adev; if (acpi_bus_get_device(lpi_constraints_table[i].handle, &adev)) continue; acpi_handle_debug(adev->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(adev->power.state)); if (!adev->flags.power_manageable) { acpi_handle_info(adev->handle, "LPI: Device not power manageble\n"); continue; } if (adev->power.state < lpi_constraints_table[i].min_dstate) acpi_handle_info(adev->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(adev->power.state)); } } static void acpi_sleep_run_lps0_dsm(unsigned int func) { union acpi_object *out_obj; Loading Loading @@ -714,6 +875,12 @@ static int lps0_device_attach(struct acpi_device *adev, if ((bitmask & ACPI_S2IDLE_FUNC_MASK) == ACPI_S2IDLE_FUNC_MASK) { lps0_dsm_func_mask = bitmask; lps0_device_handle = adev->handle; /* * Use suspend-to-idle by default if the default * suspend mode was not set from the command line. */ if (mem_sleep_default > PM_SUSPEND_MEM) mem_sleep_current = PM_SUSPEND_TO_IDLE; } acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n", Loading @@ -723,6 +890,9 @@ static int lps0_device_attach(struct acpi_device *adev, "_DSM function 0 evaluation failed\n"); } ACPI_FREE(out_obj); lpi_device_get_constraints(); return 0; } Loading @@ -731,14 +901,14 @@ static struct acpi_scan_handler lps0_handler = { .attach = lps0_device_attach, }; static int acpi_freeze_begin(void) static int acpi_s2idle_begin(void) { acpi_scan_lock_acquire(); s2idle_in_progress = true; return 0; } static int acpi_freeze_prepare(void) static int acpi_s2idle_prepare(void) { if (lps0_device_handle) { acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF); Loading @@ -758,8 +928,12 @@ static int acpi_freeze_prepare(void) return 0; } static void acpi_freeze_wake(void) static void acpi_s2idle_wake(void) { if (pm_debug_messages_on) lpi_check_constraints(); /* * If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means * that the SCI has triggered while suspended, so cancel the wakeup in Loading @@ -772,7 +946,7 @@ static void acpi_freeze_wake(void) } } static void acpi_freeze_sync(void) static void acpi_s2idle_sync(void) { /* * Process all pending events in case there are any wakeup ones. Loading @@ -785,7 +959,7 @@ static void acpi_freeze_sync(void) s2idle_wakeup = false; } static void acpi_freeze_restore(void) static void acpi_s2idle_restore(void) { if (acpi_sci_irq_valid()) disable_irq_wake(acpi_sci_irq); Loading @@ -798,19 +972,19 @@ static void acpi_freeze_restore(void) } } static void acpi_freeze_end(void) static void acpi_s2idle_end(void) { s2idle_in_progress = false; acpi_scan_lock_release(); } static const struct platform_freeze_ops acpi_freeze_ops = { .begin = acpi_freeze_begin, .prepare = acpi_freeze_prepare, .wake = acpi_freeze_wake, .sync = acpi_freeze_sync, .restore = acpi_freeze_restore, .end = acpi_freeze_end, static const struct platform_s2idle_ops acpi_s2idle_ops = { .begin = acpi_s2idle_begin, .prepare = acpi_s2idle_prepare, .wake = acpi_s2idle_wake, .sync = acpi_s2idle_sync, .restore = acpi_s2idle_restore, .end = acpi_s2idle_end, }; static void acpi_sleep_suspend_setup(void) Loading @@ -825,7 +999,7 @@ static void acpi_sleep_suspend_setup(void) &acpi_suspend_ops_old : &acpi_suspend_ops); acpi_scan_add_handler(&lps0_handler); freeze_set_ops(&acpi_freeze_ops); s2idle_set_ops(&acpi_s2idle_ops); } #else /* !CONFIG_SUSPEND */ Loading