Skip to content

Commit 3d031d0

Browse files
committed
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()
2 parents 25961ae + 70523f3 commit 3d031d0

File tree

2 files changed

+51
-12
lines changed

2 files changed

+51
-12
lines changed

arch/x86/kernel/smpboot.c

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,10 +1244,6 @@ void play_dead_common(void)
12441244
local_irq_disable();
12451245
}
12461246

1247-
/*
1248-
* We need to flush the caches before going to sleep, lest we have
1249-
* dirty data in our caches when we come back up.
1250-
*/
12511247
void __noreturn mwait_play_dead(unsigned int eax_hint)
12521248
{
12531249
struct mwait_cpu_dead *md = this_cpu_ptr(&mwait_cpu_dead);
@@ -1293,6 +1289,50 @@ void __noreturn mwait_play_dead(unsigned int eax_hint)
12931289
}
12941290
}
12951291

1292+
/*
1293+
* We need to flush the caches before going to sleep, lest we have
1294+
* dirty data in our caches when we come back up.
1295+
*/
1296+
static inline void mwait_play_dead_cpuid_hint(void)
1297+
{
1298+
unsigned int eax, ebx, ecx, edx;
1299+
unsigned int highest_cstate = 0;
1300+
unsigned int highest_subcstate = 0;
1301+
int i;
1302+
1303+
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
1304+
boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
1305+
return;
1306+
if (!this_cpu_has(X86_FEATURE_MWAIT))
1307+
return;
1308+
if (!this_cpu_has(X86_FEATURE_CLFLUSH))
1309+
return;
1310+
1311+
eax = CPUID_LEAF_MWAIT;
1312+
ecx = 0;
1313+
native_cpuid(&eax, &ebx, &ecx, &edx);
1314+
1315+
/*
1316+
* eax will be 0 if EDX enumeration is not valid.
1317+
* Initialized below to cstate, sub_cstate value when EDX is valid.
1318+
*/
1319+
if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED)) {
1320+
eax = 0;
1321+
} else {
1322+
edx >>= MWAIT_SUBSTATE_SIZE;
1323+
for (i = 0; i < 7 && edx; i++, edx >>= MWAIT_SUBSTATE_SIZE) {
1324+
if (edx & MWAIT_SUBSTATE_MASK) {
1325+
highest_cstate = i;
1326+
highest_subcstate = edx & MWAIT_SUBSTATE_MASK;
1327+
}
1328+
}
1329+
eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
1330+
(highest_subcstate - 1);
1331+
}
1332+
1333+
mwait_play_dead(eax);
1334+
}
1335+
12961336
/*
12971337
* Kick all "offline" CPUs out of mwait on kexec(). See comment in
12981338
* mwait_play_dead().
@@ -1343,9 +1383,9 @@ void native_play_dead(void)
13431383
play_dead_common();
13441384
tboot_shutdown(TB_SHUTDOWN_WFS);
13451385

1346-
/* Below returns only on error. */
1347-
cpuidle_play_dead();
1348-
hlt_play_dead();
1386+
mwait_play_dead_cpuid_hint();
1387+
if (cpuidle_play_dead())
1388+
hlt_play_dead();
13491389
}
13501390

13511391
#else /* ... !CONFIG_HOTPLUG_CPU */

drivers/cpuidle/cpuidle-psci.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -456,14 +456,13 @@ static struct faux_device_ops psci_cpuidle_ops = {
456456

457457
static bool __init dt_idle_state_present(void)
458458
{
459-
struct device_node *cpu_node __free(device_node);
460-
struct device_node *state_node __free(device_node);
461-
462-
cpu_node = of_cpu_device_node_get(cpumask_first(cpu_possible_mask));
459+
struct device_node *cpu_node __free(device_node) =
460+
of_cpu_device_node_get(cpumask_first(cpu_possible_mask));
463461
if (!cpu_node)
464462
return false;
465463

466-
state_node = of_get_cpu_state_node(cpu_node, 0);
464+
struct device_node *state_node __free(device_node) =
465+
of_get_cpu_state_node(cpu_node, 0);
467466
if (!state_node)
468467
return false;
469468

0 commit comments

Comments
 (0)