Commit 3d031d0d authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branch 'pm-cpuidle'

Fix an issue in the PSCI cpuidle driver introduced recently and a nasty
x86 power regression introduced in 6.15:

 - Prevent freeing an uninitialized pointer in error path of
   dt_idle_state_present() in the PSCI cpuidle driver (Dan Carpenter).

 - Revert an x86 commit that went into 6.15 and caused idle power,
   including power in suspend-to-idle, to rise rather dramatically on
   systems booting with "nosmt" in the kernel command line (Rafael Wysocki).

* pm-cpuidle:
  Revert "x86/smp: Eliminate mwait_play_dead_cpuid_hint()"
  cpuidle: psci: Fix uninitialized variable in dt_idle_state_present()
parents 25961ae6 70523f33
Loading
Loading
Loading
Loading
+47 −7
Original line number Diff line number Diff line
@@ -1244,10 +1244,6 @@ 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);
@@ -1293,6 +1289,50 @@ 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().
@@ -1343,8 +1383,8 @@ void native_play_dead(void)
	play_dead_common();
	tboot_shutdown(TB_SHUTDOWN_WFS);

	/* Below returns only on error. */
	cpuidle_play_dead();
	mwait_play_dead_cpuid_hint();
	if (cpuidle_play_dead())
		hlt_play_dead();
}

+4 −5
Original line number Diff line number Diff line
@@ -456,14 +456,13 @@ static struct faux_device_ops psci_cpuidle_ops = {

static bool __init dt_idle_state_present(void)
{
	struct device_node *cpu_node __free(device_node);
	struct device_node *state_node __free(device_node);

	cpu_node = of_cpu_device_node_get(cpumask_first(cpu_possible_mask));
	struct device_node *cpu_node __free(device_node) =
			of_cpu_device_node_get(cpumask_first(cpu_possible_mask));
	if (!cpu_node)
		return false;

	state_node = of_get_cpu_state_node(cpu_node, 0);
	struct device_node *state_node __free(device_node) =
			of_get_cpu_state_node(cpu_node, 0);
	if (!state_node)
		return false;