Skip to content

Commit b0142d6

Browse files
committed
cpuidle: Fix cpuidle_driver_state_disabled()
It turns out that cpuidle_driver_state_disabled() can be called before registering the cpufreq driver on some platforms, which was not expected when it was introduced and which leads to a NULL pointer dereference when trying to walk the CPUs associated with the given cpuidle driver. Fix the problem by making cpuidle_driver_state_disabled() check if the driver's mask of CPUs associated with it is present and to set CPUIDLE_FLAG_UNUSABLE for the given idle state in the driver's states list if that is not the case to cause __cpuidle_register_device() to set CPUIDLE_STATE_DISABLED_BY_DRIVER for that state for all cpuidle devices registered by it later. Fixes: cbda56d ("cpuidle: Introduce cpuidle_driver_state_disabled() for driver quirks") Reported-by: Daniel Lezcano <[email protected]> Tested-by: Daniel Lezcano <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 36fcb42 commit b0142d6

File tree

1 file changed

+10
-0
lines changed

1 file changed

+10
-0
lines changed

drivers/cpuidle/driver.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,13 @@ void cpuidle_driver_state_disabled(struct cpuidle_driver *drv, int idx,
403403

404404
mutex_lock(&cpuidle_lock);
405405

406+
spin_lock(&cpuidle_driver_lock);
407+
408+
if (!drv->cpumask) {
409+
drv->states[idx].flags |= CPUIDLE_FLAG_UNUSABLE;
410+
goto unlock;
411+
}
412+
406413
for_each_cpu(cpu, drv->cpumask) {
407414
struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
408415

@@ -415,5 +422,8 @@ void cpuidle_driver_state_disabled(struct cpuidle_driver *drv, int idx,
415422
dev->states_usage[idx].disable &= ~CPUIDLE_STATE_DISABLED_BY_DRIVER;
416423
}
417424

425+
unlock:
426+
spin_unlock(&cpuidle_driver_lock);
427+
418428
mutex_unlock(&cpuidle_lock);
419429
}

0 commit comments

Comments
 (0)