mirror of
https://github.com/torvalds/linux.git
synced 2026-05-26 16:12:59 +02:00
Merge branch 'pm-cpuidle'
Merge cpuidle updates for 6.16-rc2: - Update data types of variables passed as arguments to mwait_idle_with_hints() to match the function definition after recent changes (Uros Bizjak). - Eliminate mwait_play_dead_cpuid_hint() again after reverting its elimination during the merge window due to a problem with handling "dead" SMT siblings, but this time prevent leaving them in C1 after initialization by taking them online and back offline when a proper cpuidle driver for the platform has been registered (Rafael Wysocki). * pm-cpuidle: intel_idle: Update arguments of mwait_idle_with_hints() Reapply "x86/smp: Eliminate mwait_play_dead_cpuid_hint()" ACPI: processor: Rescan "dead" SMT siblings during initialization intel_idle: Rescan "dead" SMT siblings during initialization x86/smp: PM/hibernate: Split arch_resume_nosmt() intel_idle: Use subsys_initcall_sync() for initialization
This commit is contained in:
commit
dd3581853c
|
|
@ -299,3 +299,27 @@ struct smp_ops smp_ops = {
|
|||
.send_call_func_single_ipi = native_send_call_func_single_ipi,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(smp_ops);
|
||||
|
||||
int arch_cpu_rescan_dead_smt_siblings(void)
|
||||
{
|
||||
enum cpuhp_smt_control old = cpu_smt_control;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If SMT has been disabled and SMT siblings are in HLT, bring them back
|
||||
* online and offline them again so that they end up in MWAIT proper.
|
||||
*
|
||||
* Called with hotplug enabled.
|
||||
*/
|
||||
if (old != CPU_SMT_DISABLED && old != CPU_SMT_FORCE_DISABLED)
|
||||
return 0;
|
||||
|
||||
ret = cpuhp_smt_enable();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cpuhp_smt_disable(old);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arch_cpu_rescan_dead_smt_siblings);
|
||||
|
|
|
|||
|
|
@ -1244,6 +1244,10 @@ void play_dead_common(void)
|
|||
local_irq_disable();
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to flush the caches before going to sleep, lest we have
|
||||
* dirty data in our caches when we come back up.
|
||||
*/
|
||||
void __noreturn mwait_play_dead(unsigned int eax_hint)
|
||||
{
|
||||
struct mwait_cpu_dead *md = this_cpu_ptr(&mwait_cpu_dead);
|
||||
|
|
@ -1289,50 +1293,6 @@ void __noreturn mwait_play_dead(unsigned int eax_hint)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to flush the caches before going to sleep, lest we have
|
||||
* dirty data in our caches when we come back up.
|
||||
*/
|
||||
static inline void mwait_play_dead_cpuid_hint(void)
|
||||
{
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
unsigned int highest_cstate = 0;
|
||||
unsigned int highest_subcstate = 0;
|
||||
int i;
|
||||
|
||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
|
||||
boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
|
||||
return;
|
||||
if (!this_cpu_has(X86_FEATURE_MWAIT))
|
||||
return;
|
||||
if (!this_cpu_has(X86_FEATURE_CLFLUSH))
|
||||
return;
|
||||
|
||||
eax = CPUID_LEAF_MWAIT;
|
||||
ecx = 0;
|
||||
native_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
/*
|
||||
* eax will be 0 if EDX enumeration is not valid.
|
||||
* Initialized below to cstate, sub_cstate value when EDX is valid.
|
||||
*/
|
||||
if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED)) {
|
||||
eax = 0;
|
||||
} else {
|
||||
edx >>= MWAIT_SUBSTATE_SIZE;
|
||||
for (i = 0; i < 7 && edx; i++, edx >>= MWAIT_SUBSTATE_SIZE) {
|
||||
if (edx & MWAIT_SUBSTATE_MASK) {
|
||||
highest_cstate = i;
|
||||
highest_subcstate = edx & MWAIT_SUBSTATE_MASK;
|
||||
}
|
||||
}
|
||||
eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
|
||||
(highest_subcstate - 1);
|
||||
}
|
||||
|
||||
mwait_play_dead(eax);
|
||||
}
|
||||
|
||||
/*
|
||||
* Kick all "offline" CPUs out of mwait on kexec(). See comment in
|
||||
* mwait_play_dead().
|
||||
|
|
@ -1383,9 +1343,9 @@ void native_play_dead(void)
|
|||
play_dead_common();
|
||||
tboot_shutdown(TB_SHUTDOWN_WFS);
|
||||
|
||||
mwait_play_dead_cpuid_hint();
|
||||
if (cpuidle_play_dead())
|
||||
hlt_play_dead();
|
||||
/* Below returns only on error. */
|
||||
cpuidle_play_dead();
|
||||
hlt_play_dead();
|
||||
}
|
||||
|
||||
#else /* ... !CONFIG_HOTPLUG_CPU */
|
||||
|
|
|
|||
|
|
@ -192,7 +192,8 @@ int relocate_restore_code(void)
|
|||
|
||||
int arch_resume_nosmt(void)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We reached this while coming out of hibernation. This means
|
||||
* that SMT siblings are sleeping in hlt, as mwait is not safe
|
||||
|
|
@ -206,18 +207,10 @@ int arch_resume_nosmt(void)
|
|||
* 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:
|
||||
ret = arch_cpu_rescan_dead_smt_siblings();
|
||||
|
||||
cpu_hotplug_disable();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -175,6 +175,12 @@ bool processor_physically_present(acpi_handle handle);
|
|||
static inline void acpi_early_processor_control_setup(void) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCESSOR_CSTATE
|
||||
void acpi_idle_rescan_dead_smt_siblings(void);
|
||||
#else
|
||||
static inline void acpi_idle_rescan_dead_smt_siblings(void) {}
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Embedded Controller
|
||||
-------------------------------------------------------------------------- */
|
||||
|
|
|
|||
|
|
@ -279,6 +279,9 @@ static int __init acpi_processor_driver_init(void)
|
|||
* after acpi_cppc_processor_probe() has been called for all online CPUs
|
||||
*/
|
||||
acpi_processor_init_invariance_cppc();
|
||||
|
||||
acpi_idle_rescan_dead_smt_siblings();
|
||||
|
||||
return 0;
|
||||
err:
|
||||
driver_unregister(&acpi_processor_driver);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@
|
|||
#include <acpi/processor.h>
|
||||
#include <linux/context_tracking.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Include the apic definitions for x86 to have the APIC timer related defines
|
||||
* available also for UP (on SMP it gets magically included via linux/smp.h).
|
||||
|
|
@ -55,6 +57,12 @@ struct cpuidle_driver acpi_idle_driver = {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCESSOR_CSTATE
|
||||
void acpi_idle_rescan_dead_smt_siblings(void)
|
||||
{
|
||||
if (cpuidle_get_driver() == &acpi_idle_driver)
|
||||
arch_cpu_rescan_dead_smt_siblings();
|
||||
}
|
||||
|
||||
static
|
||||
DEFINE_PER_CPU(struct acpi_processor_cx * [CPUIDLE_STATE_MAX], acpi_cstate);
|
||||
|
||||
|
|
|
|||
|
|
@ -152,8 +152,8 @@ static __always_inline int __intel_idle(struct cpuidle_device *dev,
|
|||
int index, bool irqoff)
|
||||
{
|
||||
struct cpuidle_state *state = &drv->states[index];
|
||||
unsigned long eax = flg2MWAIT(state->flags);
|
||||
unsigned long ecx = 1*irqoff; /* break on interrupt flag */
|
||||
unsigned int eax = flg2MWAIT(state->flags);
|
||||
unsigned int ecx = 1*irqoff; /* break on interrupt flag */
|
||||
|
||||
mwait_idle_with_hints(eax, ecx);
|
||||
|
||||
|
|
@ -226,9 +226,9 @@ static __cpuidle int intel_idle_xstate(struct cpuidle_device *dev,
|
|||
static __cpuidle int intel_idle_s2idle(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv, int index)
|
||||
{
|
||||
unsigned long ecx = 1; /* break on interrupt flag */
|
||||
struct cpuidle_state *state = &drv->states[index];
|
||||
unsigned long eax = flg2MWAIT(state->flags);
|
||||
unsigned int eax = flg2MWAIT(state->flags);
|
||||
unsigned int ecx = 1; /* break on interrupt flag */
|
||||
|
||||
if (state->flags & CPUIDLE_FLAG_INIT_XSTATE)
|
||||
fpu_idle_fpregs();
|
||||
|
|
@ -2507,6 +2507,8 @@ static int __init intel_idle_init(void)
|
|||
pr_debug("Local APIC timer is reliable in %s\n",
|
||||
boot_cpu_has(X86_FEATURE_ARAT) ? "all C-states" : "C1");
|
||||
|
||||
arch_cpu_rescan_dead_smt_siblings();
|
||||
|
||||
return 0;
|
||||
|
||||
hp_setup_fail:
|
||||
|
|
@ -2518,7 +2520,7 @@ static int __init intel_idle_init(void)
|
|||
return retval;
|
||||
|
||||
}
|
||||
device_initcall(intel_idle_init);
|
||||
subsys_initcall_sync(intel_idle_init);
|
||||
|
||||
/*
|
||||
* We are not really modular, but we used to support that. Meaning we also
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ extern void cpu_maps_update_begin(void);
|
|||
extern void cpu_maps_update_done(void);
|
||||
int bringup_hibernate_cpu(unsigned int sleep_cpu);
|
||||
void bringup_nonboot_cpus(unsigned int max_cpus);
|
||||
int arch_cpu_rescan_dead_smt_siblings(void);
|
||||
|
||||
#else /* CONFIG_SMP */
|
||||
#define cpuhp_tasks_frozen 0
|
||||
|
|
@ -134,6 +135,8 @@ static inline void cpu_maps_update_done(void)
|
|||
|
||||
static inline int add_cpu(unsigned int cpu) { return 0;}
|
||||
|
||||
static inline int arch_cpu_rescan_dead_smt_siblings(void) { return 0; }
|
||||
|
||||
#endif /* CONFIG_SMP */
|
||||
extern const struct bus_type cpu_subsys;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user