Power management fixes for 5.2-rc4
- Fix a crash that occurs when a kernel with 'nosmt' in the command line is used to resume the system from hibernation (as the "restore" kernel), because memory mapping differences between the restore and image kernels cause SMT siblings to be woken up from idle states and subsequently they try to fetch instructions from incorrect memory locations (Jiri Kosina). - Cause the new Performance and Energy Bias Hint (EPB) code to be built only if CONFIG_PM is set, because that code is not really necessary otherwise (Rafael Wysocki). - Add kerneldoc comments to documents some helper functions related to system-wide suspend to avoid possible confusion regarding their purpose (Rafael Wysocki). -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAlz6Kf8SHHJqd0Byand5 c29ja2kubmV0AAoJEILEb/54YlRxcxkP/05X18Js4yZb7aUc9p6k0rAhI2kwE8OM MiF68H2b57qBinR5Amc/tCtMLvdScieVThFmti8nxO1Fvm4Ld+ZUfRPXZUmCc7VJ rQ7r1uEeWXC+vb5b2587jFVzRzARzQ9xF590tneI/T4p3yBvWaj6W/t0pxU4+Lok hAUeeMNIyBhNHkCZVeX3ZxNM03fFWbZBU1GIFhmDxMaXRAsYt5N0dtes/mjbhAFw /iXDuPv2FL4JqU/vuVWR5/icd35IZVDq1bCz5ChRlUKweoj+KhK9uxoKTYrAh3zo jhXE6RBZgVbVUzSWjhkWHEN2RkylIE2uhUvVpAwWFuqoHUfFOdXfF/PcRwkNC9tx XPNYHMzWKNXS/OIzBHqqv3AhNelou7onh78OROpIsw0AkbA2afN4RjywnybdzIwX Lb3q7B1DQt6Nv/sf7zyOzUuE0kJLJ4FGm4mCOkXb+CLQ9X/kkePlaOWi4/UBvT5x L07M4nTQla65UVIL1nnru8yTNSy2dESOj9QHlKJnkwOTJK1RfxLMmeUbao3EZkzh 5woshADVHlRNCt/2fo2bllzJeDNjeXfiOjOOVsnf+vjiQ034d1CD9IXlVgW/QC32 V/DjiWCai1HvHq5j5KurLDJOyMmDl8O9tqCLNSYAzOkvMJsuLN7rhzJossZtYCT4 kTpy2BLIOrMI =r5bv -----END PGP SIGNATURE----- Merge tag 'pm-5.2-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull power management fixes from Rafael Wysocki: "These fix a crash during resume from hibernation introduced during the 4.19 cycle, cause the new Performance and Energy Bias Hint (EPB) code to be built only if CONFIG_PM is set and add a few missing kerneldoc comments. Specifics: - Fix a crash that occurs when a kernel with 'nosmt' in the command line is used to resume the system from hibernation (as the "restore" kernel), because memory mapping differences between the restore and image kernels cause SMT siblings to be woken up from idle states and subsequently they try to fetch instructions from incorrect memory locations (Jiri Kosina). - Cause the new Performance and Energy Bias Hint (EPB) code to be built only if CONFIG_PM is set, because that code is not really necessary otherwise (Rafael Wysocki). - Add kerneldoc comments to documents some helper functions related to system-wide suspend to avoid possible confusion regarding their purpose (Rafael Wysocki)" * tag 'pm-5.2-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: x86/power: Fix 'nosmt' vs hibernation triple fault during resume PM: sleep: Add kerneldoc comments to some functions x86: intel_epb: Do not build when CONFIG_PM is unset
This commit is contained in:
commit
a373ec23ab
|
@ -28,7 +28,10 @@ obj-y += cpuid-deps.o
|
||||||
obj-$(CONFIG_PROC_FS) += proc.o
|
obj-$(CONFIG_PROC_FS) += proc.o
|
||||||
obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
|
obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
|
||||||
|
|
||||||
obj-$(CONFIG_CPU_SUP_INTEL) += intel.o intel_pconfig.o intel_epb.o
|
ifdef CONFIG_CPU_SUP_INTEL
|
||||||
|
obj-y += intel.o intel_pconfig.o
|
||||||
|
obj-$(CONFIG_PM) += intel_epb.o
|
||||||
|
endif
|
||||||
obj-$(CONFIG_CPU_SUP_AMD) += amd.o
|
obj-$(CONFIG_CPU_SUP_AMD) += amd.o
|
||||||
obj-$(CONFIG_CPU_SUP_HYGON) += hygon.o
|
obj-$(CONFIG_CPU_SUP_HYGON) += hygon.o
|
||||||
obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o
|
obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o
|
||||||
|
|
|
@ -97,7 +97,6 @@ static void intel_epb_restore(void)
|
||||||
wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, (epb & ~EPB_MASK) | val);
|
wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, (epb & ~EPB_MASK) | val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
|
||||||
static struct syscore_ops intel_epb_syscore_ops = {
|
static struct syscore_ops intel_epb_syscore_ops = {
|
||||||
.suspend = intel_epb_save,
|
.suspend = intel_epb_save,
|
||||||
.resume = intel_epb_restore,
|
.resume = intel_epb_restore,
|
||||||
|
@ -194,25 +193,6 @@ static int intel_epb_offline(unsigned int cpu)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void register_intel_ebp_syscore_ops(void)
|
|
||||||
{
|
|
||||||
register_syscore_ops(&intel_epb_syscore_ops);
|
|
||||||
}
|
|
||||||
#else /* !CONFIG_PM */
|
|
||||||
static int intel_epb_online(unsigned int cpu)
|
|
||||||
{
|
|
||||||
intel_epb_restore();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int intel_epb_offline(unsigned int cpu)
|
|
||||||
{
|
|
||||||
return intel_epb_save();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void register_intel_ebp_syscore_ops(void) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static __init int intel_epb_init(void)
|
static __init int intel_epb_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -226,7 +206,7 @@ static __init int intel_epb_init(void)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_out_online;
|
goto err_out_online;
|
||||||
|
|
||||||
register_intel_ebp_syscore_ops();
|
register_syscore_ops(&intel_epb_syscore_ops);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_out_online:
|
err_out_online:
|
||||||
|
|
|
@ -299,7 +299,17 @@ int hibernate_resume_nonboot_cpu_disable(void)
|
||||||
* address in its instruction pointer may not be possible to resolve
|
* address in its instruction pointer may not be possible to resolve
|
||||||
* any more at that point (the page tables used by it previously may
|
* any more at that point (the page tables used by it previously may
|
||||||
* have been overwritten by hibernate image data).
|
* have been overwritten by hibernate image data).
|
||||||
|
*
|
||||||
|
* First, make sure that we wake up all the potentially disabled SMT
|
||||||
|
* threads which have been initially brought up and then put into
|
||||||
|
* mwait/cpuidle sleep.
|
||||||
|
* Those will be put to proper (not interfering with hibernation
|
||||||
|
* resume) sleep afterwards, and the resumed kernel will decide itself
|
||||||
|
* what to do with them.
|
||||||
*/
|
*/
|
||||||
|
ret = cpuhp_smt_enable();
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
smp_ops.play_dead = resume_play_dead;
|
smp_ops.play_dead = resume_play_dead;
|
||||||
ret = disable_nonboot_cpus();
|
ret = disable_nonboot_cpus();
|
||||||
smp_ops.play_dead = play_dead;
|
smp_ops.play_dead = play_dead;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
#include <linux/kdebug.h>
|
#include <linux/kdebug.h>
|
||||||
|
#include <linux/cpu.h>
|
||||||
|
|
||||||
#include <crypto/hash.h>
|
#include <crypto/hash.h>
|
||||||
|
|
||||||
|
@ -245,3 +246,35 @@ int relocate_restore_code(void)
|
||||||
__flush_tlb_all();
|
__flush_tlb_all();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int arch_resume_nosmt(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
/*
|
||||||
|
* We reached this while coming out of hibernation. This means
|
||||||
|
* that SMT siblings are sleeping in hlt, as mwait is not safe
|
||||||
|
* against control transition during resume (see comment in
|
||||||
|
* hibernate_resume_nonboot_cpu_disable()).
|
||||||
|
*
|
||||||
|
* If the resumed kernel has SMT disabled, we have to take all the
|
||||||
|
* SMT siblings out of hlt, and offline them again so that they
|
||||||
|
* end up in mwait proper.
|
||||||
|
*
|
||||||
|
* Called with hotplug disabled.
|
||||||
|
*/
|
||||||
|
cpu_hotplug_enable();
|
||||||
|
if (cpu_smt_control == CPU_SMT_DISABLED ||
|
||||||
|
cpu_smt_control == CPU_SMT_FORCE_DISABLED) {
|
||||||
|
enum cpuhp_smt_control old = cpu_smt_control;
|
||||||
|
|
||||||
|
ret = cpuhp_smt_enable();
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
ret = cpuhp_smt_disable(old);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
cpu_hotplug_disable();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -201,10 +201,14 @@ enum cpuhp_smt_control {
|
||||||
extern enum cpuhp_smt_control cpu_smt_control;
|
extern enum cpuhp_smt_control cpu_smt_control;
|
||||||
extern void cpu_smt_disable(bool force);
|
extern void cpu_smt_disable(bool force);
|
||||||
extern void cpu_smt_check_topology(void);
|
extern void cpu_smt_check_topology(void);
|
||||||
|
extern int cpuhp_smt_enable(void);
|
||||||
|
extern int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval);
|
||||||
#else
|
#else
|
||||||
# define cpu_smt_control (CPU_SMT_NOT_IMPLEMENTED)
|
# define cpu_smt_control (CPU_SMT_NOT_IMPLEMENTED)
|
||||||
static inline void cpu_smt_disable(bool force) { }
|
static inline void cpu_smt_disable(bool force) { }
|
||||||
static inline void cpu_smt_check_topology(void) { }
|
static inline void cpu_smt_check_topology(void) { }
|
||||||
|
static inline int cpuhp_smt_enable(void) { return 0; }
|
||||||
|
static inline int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval) { return 0; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -227,11 +227,42 @@ static inline void pm_set_resume_via_firmware(void)
|
||||||
pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_RESUME;
|
pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_RESUME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pm_suspend_via_firmware - Check if platform firmware will suspend the system.
|
||||||
|
*
|
||||||
|
* To be called during system-wide power management transitions to sleep states
|
||||||
|
* or during the subsequent system-wide transitions back to the working state.
|
||||||
|
*
|
||||||
|
* Return 'true' if the platform firmware is going to be invoked at the end of
|
||||||
|
* the system-wide power management transition (to a sleep state) in progress in
|
||||||
|
* order to complete it, or if the platform firmware has been invoked in order
|
||||||
|
* to complete the last (or preceding) transition of the system to a sleep
|
||||||
|
* state.
|
||||||
|
*
|
||||||
|
* This matters if the caller needs or wants to carry out some special actions
|
||||||
|
* depending on whether or not control will be passed to the platform firmware
|
||||||
|
* subsequently (for example, the device may need to be reset before letting the
|
||||||
|
* platform firmware manipulate it, which is not necessary when the platform
|
||||||
|
* firmware is not going to be invoked) or when such special actions may have
|
||||||
|
* been carried out during the preceding transition of the system to a sleep
|
||||||
|
* state (as they may need to be taken into account).
|
||||||
|
*/
|
||||||
static inline bool pm_suspend_via_firmware(void)
|
static inline bool pm_suspend_via_firmware(void)
|
||||||
{
|
{
|
||||||
return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_SUSPEND);
|
return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_SUSPEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pm_resume_via_firmware - Check if platform firmware has woken up the system.
|
||||||
|
*
|
||||||
|
* To be called during system-wide power management transitions from sleep
|
||||||
|
* states.
|
||||||
|
*
|
||||||
|
* Return 'true' if the platform firmware has passed control to the kernel at
|
||||||
|
* the beginning of the system-wide power management transition in progress, so
|
||||||
|
* the event that woke up the system from sleep has been handled by the platform
|
||||||
|
* firmware.
|
||||||
|
*/
|
||||||
static inline bool pm_resume_via_firmware(void)
|
static inline bool pm_resume_via_firmware(void)
|
||||||
{
|
{
|
||||||
return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_RESUME);
|
return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_RESUME);
|
||||||
|
|
|
@ -2061,7 +2061,7 @@ static void cpuhp_online_cpu_device(unsigned int cpu)
|
||||||
kobject_uevent(&dev->kobj, KOBJ_ONLINE);
|
kobject_uevent(&dev->kobj, KOBJ_ONLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval)
|
int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval)
|
||||||
{
|
{
|
||||||
int cpu, ret = 0;
|
int cpu, ret = 0;
|
||||||
|
|
||||||
|
@ -2093,7 +2093,7 @@ static int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cpuhp_smt_enable(void)
|
int cpuhp_smt_enable(void)
|
||||||
{
|
{
|
||||||
int cpu, ret = 0;
|
int cpu, ret = 0;
|
||||||
|
|
||||||
|
|
|
@ -257,6 +257,11 @@ void swsusp_show_speed(ktime_t start, ktime_t stop,
|
||||||
(kps % 1000) / 10);
|
(kps % 1000) / 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__weak int arch_resume_nosmt(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create_image - Create a hibernation image.
|
* create_image - Create a hibernation image.
|
||||||
* @platform_mode: Whether or not to use the platform driver.
|
* @platform_mode: Whether or not to use the platform driver.
|
||||||
|
@ -324,6 +329,10 @@ static int create_image(int platform_mode)
|
||||||
Enable_cpus:
|
Enable_cpus:
|
||||||
suspend_enable_secondary_cpus();
|
suspend_enable_secondary_cpus();
|
||||||
|
|
||||||
|
/* Allow architectures to do nosmt-specific post-resume dances */
|
||||||
|
if (!in_suspend)
|
||||||
|
error = arch_resume_nosmt();
|
||||||
|
|
||||||
Platform_finish:
|
Platform_finish:
|
||||||
platform_finish(platform_mode);
|
platform_finish(platform_mode);
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,12 @@ static DECLARE_SWAIT_QUEUE_HEAD(s2idle_wait_head);
|
||||||
enum s2idle_states __read_mostly s2idle_state;
|
enum s2idle_states __read_mostly s2idle_state;
|
||||||
static DEFINE_RAW_SPINLOCK(s2idle_lock);
|
static DEFINE_RAW_SPINLOCK(s2idle_lock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pm_suspend_via_s2idle - Check if suspend-to-idle is the default suspend.
|
||||||
|
*
|
||||||
|
* Return 'true' if suspend-to-idle has been selected as the default system
|
||||||
|
* suspend method.
|
||||||
|
*/
|
||||||
bool pm_suspend_via_s2idle(void)
|
bool pm_suspend_via_s2idle(void)
|
||||||
{
|
{
|
||||||
return mem_sleep_current == PM_SUSPEND_TO_IDLE;
|
return mem_sleep_current == PM_SUSPEND_TO_IDLE;
|
||||||
|
|
Loading…
Reference in New Issue