[PATCH v2] drivers: psci: PSCI checker module

Jean-Philippe Brucker jean-philippe.brucker at arm.com
Tue Oct 18 12:21:46 PDT 2016


Hi Kevin,

On 21/09/16 15:39, Kevin Brodsky wrote:
> On arm and arm64, PSCI is one of the possible firmware interfaces
> used for power management. This includes both turning CPUs on and off,
> and suspending them (entering idle states).
> 
> This patch adds a PSCI checker module that enables basic testing of
> PSCI operations during startup. There are two main tests: CPU
> hotplugging and suspending.
> 
> In the hotplug tests, the hotplug API is used to turn off and on again
> all CPUs in the system, and then all CPUs in each cluster, checking
> the consistency of the return codes.
> 
> In the suspend tests, a high-priority thread is created on each core
> and uses low-level cpuidle functionalities to enter suspend, in all
> the possible states and multiple times. This should allow a maximum
> number of CPUs to enter the same sleep state at the same or slightly
> different time.
> 
> In essence, the suspend tests use a principle similar to that of the
> intel_powerclamp driver (drivers/thermal/intel_powerclamp.c), but the
> threads are only kept for the duration of the test (they are already
> gone when userspace is started).
> 
> While in theory power management PSCI functions (CPU_{ON,OFF,SUSPEND})
> could be directly called, this proved too difficult as it would imply
> the duplication of all the logic used by the kernel to allow for a
> clean shutdown/bringup/suspend of the CPU (the deepest sleep states
> implying potentially the shutdown of the CPU).
> 
> Note that this file cannot be compiled as a loadable module, since it
> uses a number of non-exported identifiers (essentially for
> PSCI-specific checks and direct use of cpuidle) and relies on the
> absence of userspace to avoid races when calling hotplug and cpuidle
> functions.
> 
> Cc: Thomas Gleixner <tglx at linutronix.de>
> Cc: Kevin Hilman <khilman at kernel.org>
> Cc: "Rafael J. Wysocki" <rjw at rjwysocki.net>
> Cc: Peter Zijlstra <peterz at infradead.org>
> Cc: Sudeep Holla <sudeep.holla at arm.com>
> Cc: Lorenzo Pieralisi <lorenzo.pieralisi at arm.com>
> Cc: Mark Rutland <mark.rutland at arm.com>
> Signed-off-by: Kevin Brodsky <kevin.brodsky at arm.com>
> ---
> Changelog v1..v2:
> * Do not count tick_broadcast_enter() failures as errors, as they may
>   be unavoidable. When it happens, fall back to WFI.
> * Do not count unexpected sleep states as errors (currently, the only
>   case is when falling back to WFI). Instead, report the number of
>   times it happens before the suspend thread exits.
> * Use usecs_to_jiffies() to compute the suspend timeout. The previous
>   version resulted in a zero timeout if the target residency was
>   shorter than a jiffy.
> * Various cleanup.
> 
> Thanks to Lorenzo for his help with improving this patch!
> 
> Kevin
[...]
> +
> +static int suspend_tests(void)
> +{
> +	int i, cpu, err = 0;
> +	struct task_struct **threads;
> +	int nb_threads = 0;
> +
> +	threads = kmalloc_array(nb_available_cpus, sizeof(*threads),
> +				GFP_KERNEL);
> +	if (!threads)
> +		return -ENOMEM;
> +
> +	for_each_online_cpu(cpu) {
> +		struct task_struct *thread;
> +		/* Check that cpuidle is available on that CPU. */
> +		struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
> +		struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
> +
> +		if (cpuidle_not_available(drv, dev)) {
> +			pr_warn("cpuidle not available on CPU %d, ignoring\n",
> +				cpu);
> +			continue;
> +		}
> +
> +		thread = kthread_create_on_cpu(suspend_stress_thread,
> +					       (void *)(long)cpu, cpu,
> +					       "psci_suspend_stress");
> +		if (IS_ERR(thread))
> +			pr_err("Failed to create kthread on CPU %d\n", cpu);
> +		else
> +			threads[nb_threads++] = thread;
> +	}
> +	if (nb_threads < 1) {
> +		kfree(threads);
> +		return -ENODEV;
> +	}
> +
> +	atomic_set(&nb_active_threads, nb_threads);
> +
> +	/*
> +	 * Stop cpuidle to prevent the idle tasks from entering a deep sleep
> +	 * mode, as it might interfere with the suspend threads on other CPUs.
> +	 * This does not prevent the suspend threads from using cpuidle (only
> +	 * the idle tasks check this status).
> +	 */
> +	cpuidle_pause();
> +
> +	/*
> +	 * Unpark the suspend threads. To avoid the main thread being preempted
> +	 * before all the threads have been unparked, the suspend threads will
> +	 * wait for the completion of suspend_threads_started.
> +	 */
> +	for (i = 0; i < nb_threads; ++i)
> +		kthread_unpark(threads[i]);

Just a heads up: this doesn't work anymore, since a65d4096
(kthread/smpboot: do not park in kthread_create_on_cpu()), in 4.9-rc1. I
think that the unpark call could be replaced by wake_up_process. The
comment of kthread_create_on_cpu is now misleading.

Thanks,
Jean-Philippe




More information about the linux-arm-kernel mailing list