18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2018 Linaro Limited
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * The idle injection framework provides a way to force CPUs to enter idle
88c2ecf20Sopenharmony_ci * states for a specified fraction of time over a specified period.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * It relies on the smpboot kthreads feature providing common code for CPU
118c2ecf20Sopenharmony_ci * hotplug and thread [un]parking.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * All of the kthreads used for idle injection are created at init time.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * Next, the users of the the idle injection framework provide a cpumask via
168c2ecf20Sopenharmony_ci * its register function. The kthreads will be synchronized with respect to
178c2ecf20Sopenharmony_ci * this cpumask.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * The idle + run duration is specified via separate helpers and that allows
208c2ecf20Sopenharmony_ci * idle injection to be started.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * The idle injection kthreads will call play_idle_precise() with the idle
238c2ecf20Sopenharmony_ci * duration and max allowed latency specified as per the above.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * After all of them have been woken up, a timer is set to start the next idle
268c2ecf20Sopenharmony_ci * injection cycle.
278c2ecf20Sopenharmony_ci *
288c2ecf20Sopenharmony_ci * The timer interrupt handler will wake up the idle injection kthreads for
298c2ecf20Sopenharmony_ci * all of the CPUs in the cpumask provided by the user.
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci * Idle injection is stopped synchronously and no leftover idle injection
328c2ecf20Sopenharmony_ci * kthread activity after its completion is guaranteed.
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci * It is up to the user of this framework to provide a lock for higher-level
358c2ecf20Sopenharmony_ci * synchronization to prevent race conditions like starting idle injection
368c2ecf20Sopenharmony_ci * while unregistering from the framework.
378c2ecf20Sopenharmony_ci */
388c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "ii_dev: " fmt
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#include <linux/cpu.h>
418c2ecf20Sopenharmony_ci#include <linux/hrtimer.h>
428c2ecf20Sopenharmony_ci#include <linux/kthread.h>
438c2ecf20Sopenharmony_ci#include <linux/sched.h>
448c2ecf20Sopenharmony_ci#include <linux/slab.h>
458c2ecf20Sopenharmony_ci#include <linux/smpboot.h>
468c2ecf20Sopenharmony_ci#include <linux/idle_inject.h>
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#include <uapi/linux/sched/types.h>
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/**
518c2ecf20Sopenharmony_ci * struct idle_inject_thread - task on/off switch structure
528c2ecf20Sopenharmony_ci * @tsk: task injecting the idle cycles
538c2ecf20Sopenharmony_ci * @should_run: whether or not to run the task (for the smpboot kthread API)
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_cistruct idle_inject_thread {
568c2ecf20Sopenharmony_ci	struct task_struct *tsk;
578c2ecf20Sopenharmony_ci	int should_run;
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/**
618c2ecf20Sopenharmony_ci * struct idle_inject_device - idle injection data
628c2ecf20Sopenharmony_ci * @timer: idle injection period timer
638c2ecf20Sopenharmony_ci * @idle_duration_us: duration of CPU idle time to inject
648c2ecf20Sopenharmony_ci * @run_duration_us: duration of CPU run time to allow
658c2ecf20Sopenharmony_ci * @latency_us: max allowed latency
668c2ecf20Sopenharmony_ci * @cpumask: mask of CPUs affected by idle injection
678c2ecf20Sopenharmony_ci */
688c2ecf20Sopenharmony_cistruct idle_inject_device {
698c2ecf20Sopenharmony_ci	struct hrtimer timer;
708c2ecf20Sopenharmony_ci	unsigned int idle_duration_us;
718c2ecf20Sopenharmony_ci	unsigned int run_duration_us;
728c2ecf20Sopenharmony_ci	unsigned int latency_us;
738c2ecf20Sopenharmony_ci	unsigned long cpumask[];
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct idle_inject_thread, idle_inject_thread);
778c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct idle_inject_device *, idle_inject_device);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/**
808c2ecf20Sopenharmony_ci * idle_inject_wakeup - Wake up idle injection threads
818c2ecf20Sopenharmony_ci * @ii_dev: target idle injection device
828c2ecf20Sopenharmony_ci *
838c2ecf20Sopenharmony_ci * Every idle injection task associated with the given idle injection device
848c2ecf20Sopenharmony_ci * and running on an online CPU will be woken up.
858c2ecf20Sopenharmony_ci */
868c2ecf20Sopenharmony_cistatic void idle_inject_wakeup(struct idle_inject_device *ii_dev)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	struct idle_inject_thread *iit;
898c2ecf20Sopenharmony_ci	unsigned int cpu;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	for_each_cpu_and(cpu, to_cpumask(ii_dev->cpumask), cpu_online_mask) {
928c2ecf20Sopenharmony_ci		iit = per_cpu_ptr(&idle_inject_thread, cpu);
938c2ecf20Sopenharmony_ci		iit->should_run = 1;
948c2ecf20Sopenharmony_ci		wake_up_process(iit->tsk);
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci/**
998c2ecf20Sopenharmony_ci * idle_inject_timer_fn - idle injection timer function
1008c2ecf20Sopenharmony_ci * @timer: idle injection hrtimer
1018c2ecf20Sopenharmony_ci *
1028c2ecf20Sopenharmony_ci * This function is called when the idle injection timer expires.  It wakes up
1038c2ecf20Sopenharmony_ci * idle injection tasks associated with the timer and they, in turn, invoke
1048c2ecf20Sopenharmony_ci * play_idle_precise() to inject a specified amount of CPU idle time.
1058c2ecf20Sopenharmony_ci *
1068c2ecf20Sopenharmony_ci * Return: HRTIMER_RESTART.
1078c2ecf20Sopenharmony_ci */
1088c2ecf20Sopenharmony_cistatic enum hrtimer_restart idle_inject_timer_fn(struct hrtimer *timer)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	unsigned int duration_us;
1118c2ecf20Sopenharmony_ci	struct idle_inject_device *ii_dev =
1128c2ecf20Sopenharmony_ci		container_of(timer, struct idle_inject_device, timer);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	duration_us = READ_ONCE(ii_dev->run_duration_us);
1158c2ecf20Sopenharmony_ci	duration_us += READ_ONCE(ii_dev->idle_duration_us);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	idle_inject_wakeup(ii_dev);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	hrtimer_forward_now(timer, ns_to_ktime(duration_us * NSEC_PER_USEC));
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	return HRTIMER_RESTART;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci/**
1258c2ecf20Sopenharmony_ci * idle_inject_fn - idle injection work function
1268c2ecf20Sopenharmony_ci * @cpu: the CPU owning the task
1278c2ecf20Sopenharmony_ci *
1288c2ecf20Sopenharmony_ci * This function calls play_idle_precise() to inject a specified amount of CPU
1298c2ecf20Sopenharmony_ci * idle time.
1308c2ecf20Sopenharmony_ci */
1318c2ecf20Sopenharmony_cistatic void idle_inject_fn(unsigned int cpu)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	struct idle_inject_device *ii_dev;
1348c2ecf20Sopenharmony_ci	struct idle_inject_thread *iit;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	ii_dev = per_cpu(idle_inject_device, cpu);
1378c2ecf20Sopenharmony_ci	iit = per_cpu_ptr(&idle_inject_thread, cpu);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	/*
1408c2ecf20Sopenharmony_ci	 * Let the smpboot main loop know that the task should not run again.
1418c2ecf20Sopenharmony_ci	 */
1428c2ecf20Sopenharmony_ci	iit->should_run = 0;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	play_idle_precise(READ_ONCE(ii_dev->idle_duration_us) * NSEC_PER_USEC,
1458c2ecf20Sopenharmony_ci			  READ_ONCE(ii_dev->latency_us) * NSEC_PER_USEC);
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci/**
1498c2ecf20Sopenharmony_ci * idle_inject_set_duration - idle and run duration update helper
1508c2ecf20Sopenharmony_ci * @run_duration_us: CPU run time to allow in microseconds
1518c2ecf20Sopenharmony_ci * @idle_duration_us: CPU idle time to inject in microseconds
1528c2ecf20Sopenharmony_ci */
1538c2ecf20Sopenharmony_civoid idle_inject_set_duration(struct idle_inject_device *ii_dev,
1548c2ecf20Sopenharmony_ci			      unsigned int run_duration_us,
1558c2ecf20Sopenharmony_ci			      unsigned int idle_duration_us)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	if (run_duration_us && idle_duration_us) {
1588c2ecf20Sopenharmony_ci		WRITE_ONCE(ii_dev->run_duration_us, run_duration_us);
1598c2ecf20Sopenharmony_ci		WRITE_ONCE(ii_dev->idle_duration_us, idle_duration_us);
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci/**
1648c2ecf20Sopenharmony_ci * idle_inject_get_duration - idle and run duration retrieval helper
1658c2ecf20Sopenharmony_ci * @run_duration_us: memory location to store the current CPU run time
1668c2ecf20Sopenharmony_ci * @idle_duration_us: memory location to store the current CPU idle time
1678c2ecf20Sopenharmony_ci */
1688c2ecf20Sopenharmony_civoid idle_inject_get_duration(struct idle_inject_device *ii_dev,
1698c2ecf20Sopenharmony_ci			      unsigned int *run_duration_us,
1708c2ecf20Sopenharmony_ci			      unsigned int *idle_duration_us)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	*run_duration_us = READ_ONCE(ii_dev->run_duration_us);
1738c2ecf20Sopenharmony_ci	*idle_duration_us = READ_ONCE(ii_dev->idle_duration_us);
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci/**
1778c2ecf20Sopenharmony_ci * idle_inject_set_latency - set the maximum latency allowed
1788c2ecf20Sopenharmony_ci * @latency_us: set the latency requirement for the idle state
1798c2ecf20Sopenharmony_ci */
1808c2ecf20Sopenharmony_civoid idle_inject_set_latency(struct idle_inject_device *ii_dev,
1818c2ecf20Sopenharmony_ci			     unsigned int latency_us)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	WRITE_ONCE(ii_dev->latency_us, latency_us);
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci/**
1878c2ecf20Sopenharmony_ci * idle_inject_start - start idle injections
1888c2ecf20Sopenharmony_ci * @ii_dev: idle injection control device structure
1898c2ecf20Sopenharmony_ci *
1908c2ecf20Sopenharmony_ci * The function starts idle injection by first waking up all of the idle
1918c2ecf20Sopenharmony_ci * injection kthreads associated with @ii_dev to let them inject CPU idle time
1928c2ecf20Sopenharmony_ci * sets up a timer to start the next idle injection period.
1938c2ecf20Sopenharmony_ci *
1948c2ecf20Sopenharmony_ci * Return: -EINVAL if the CPU idle or CPU run time is not set or 0 on success.
1958c2ecf20Sopenharmony_ci */
1968c2ecf20Sopenharmony_ciint idle_inject_start(struct idle_inject_device *ii_dev)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	unsigned int idle_duration_us = READ_ONCE(ii_dev->idle_duration_us);
1998c2ecf20Sopenharmony_ci	unsigned int run_duration_us = READ_ONCE(ii_dev->run_duration_us);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	if (!idle_duration_us || !run_duration_us)
2028c2ecf20Sopenharmony_ci		return -EINVAL;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	pr_debug("Starting injecting idle cycles on CPUs '%*pbl'\n",
2058c2ecf20Sopenharmony_ci		 cpumask_pr_args(to_cpumask(ii_dev->cpumask)));
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	idle_inject_wakeup(ii_dev);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	hrtimer_start(&ii_dev->timer,
2108c2ecf20Sopenharmony_ci		      ns_to_ktime((idle_duration_us + run_duration_us) *
2118c2ecf20Sopenharmony_ci				  NSEC_PER_USEC),
2128c2ecf20Sopenharmony_ci		      HRTIMER_MODE_REL);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	return 0;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci/**
2188c2ecf20Sopenharmony_ci * idle_inject_stop - stops idle injections
2198c2ecf20Sopenharmony_ci * @ii_dev: idle injection control device structure
2208c2ecf20Sopenharmony_ci *
2218c2ecf20Sopenharmony_ci * The function stops idle injection and waits for the threads to finish work.
2228c2ecf20Sopenharmony_ci * If CPU idle time is being injected when this function runs, then it will
2238c2ecf20Sopenharmony_ci * wait until the end of the cycle.
2248c2ecf20Sopenharmony_ci *
2258c2ecf20Sopenharmony_ci * When it returns, there is no more idle injection kthread activity.  The
2268c2ecf20Sopenharmony_ci * kthreads are scheduled out and the periodic timer is off.
2278c2ecf20Sopenharmony_ci */
2288c2ecf20Sopenharmony_civoid idle_inject_stop(struct idle_inject_device *ii_dev)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	struct idle_inject_thread *iit;
2318c2ecf20Sopenharmony_ci	unsigned int cpu;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	pr_debug("Stopping idle injection on CPUs '%*pbl'\n",
2348c2ecf20Sopenharmony_ci		 cpumask_pr_args(to_cpumask(ii_dev->cpumask)));
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	hrtimer_cancel(&ii_dev->timer);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	/*
2398c2ecf20Sopenharmony_ci	 * Stopping idle injection requires all of the idle injection kthreads
2408c2ecf20Sopenharmony_ci	 * associated with the given cpumask to be parked and stay that way, so
2418c2ecf20Sopenharmony_ci	 * prevent CPUs from going online at this point.  Any CPUs going online
2428c2ecf20Sopenharmony_ci	 * after the loop below will be covered by clearing the should_run flag
2438c2ecf20Sopenharmony_ci	 * that will cause the smpboot main loop to schedule them out.
2448c2ecf20Sopenharmony_ci	 */
2458c2ecf20Sopenharmony_ci	cpu_hotplug_disable();
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	/*
2488c2ecf20Sopenharmony_ci	 * Iterate over all (online + offline) CPUs here in case one of them
2498c2ecf20Sopenharmony_ci	 * goes offline with the should_run flag set so as to prevent its idle
2508c2ecf20Sopenharmony_ci	 * injection kthread from running when the CPU goes online again after
2518c2ecf20Sopenharmony_ci	 * the ii_dev has been freed.
2528c2ecf20Sopenharmony_ci	 */
2538c2ecf20Sopenharmony_ci	for_each_cpu(cpu, to_cpumask(ii_dev->cpumask)) {
2548c2ecf20Sopenharmony_ci		iit = per_cpu_ptr(&idle_inject_thread, cpu);
2558c2ecf20Sopenharmony_ci		iit->should_run = 0;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci		wait_task_inactive(iit->tsk, 0);
2588c2ecf20Sopenharmony_ci	}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	cpu_hotplug_enable();
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci/**
2648c2ecf20Sopenharmony_ci * idle_inject_setup - prepare the current task for idle injection
2658c2ecf20Sopenharmony_ci * @cpu: not used
2668c2ecf20Sopenharmony_ci *
2678c2ecf20Sopenharmony_ci * Called once, this function is in charge of setting the current task's
2688c2ecf20Sopenharmony_ci * scheduler parameters to make it an RT task.
2698c2ecf20Sopenharmony_ci */
2708c2ecf20Sopenharmony_cistatic void idle_inject_setup(unsigned int cpu)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	sched_set_fifo(current);
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci/**
2768c2ecf20Sopenharmony_ci * idle_inject_should_run - function helper for the smpboot API
2778c2ecf20Sopenharmony_ci * @cpu: CPU the kthread is running on
2788c2ecf20Sopenharmony_ci *
2798c2ecf20Sopenharmony_ci * Return: whether or not the thread can run.
2808c2ecf20Sopenharmony_ci */
2818c2ecf20Sopenharmony_cistatic int idle_inject_should_run(unsigned int cpu)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	struct idle_inject_thread *iit =
2848c2ecf20Sopenharmony_ci		per_cpu_ptr(&idle_inject_thread, cpu);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	return iit->should_run;
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci/**
2908c2ecf20Sopenharmony_ci * idle_inject_register - initialize idle injection on a set of CPUs
2918c2ecf20Sopenharmony_ci * @cpumask: CPUs to be affected by idle injection
2928c2ecf20Sopenharmony_ci *
2938c2ecf20Sopenharmony_ci * This function creates an idle injection control device structure for the
2948c2ecf20Sopenharmony_ci * given set of CPUs and initializes the timer associated with it.  It does not
2958c2ecf20Sopenharmony_ci * start any injection cycles.
2968c2ecf20Sopenharmony_ci *
2978c2ecf20Sopenharmony_ci * Return: NULL if memory allocation fails, idle injection control device
2988c2ecf20Sopenharmony_ci * pointer on success.
2998c2ecf20Sopenharmony_ci */
3008c2ecf20Sopenharmony_cistruct idle_inject_device *idle_inject_register(struct cpumask *cpumask)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct idle_inject_device *ii_dev;
3038c2ecf20Sopenharmony_ci	int cpu, cpu_rb;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	ii_dev = kzalloc(sizeof(*ii_dev) + cpumask_size(), GFP_KERNEL);
3068c2ecf20Sopenharmony_ci	if (!ii_dev)
3078c2ecf20Sopenharmony_ci		return NULL;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	cpumask_copy(to_cpumask(ii_dev->cpumask), cpumask);
3108c2ecf20Sopenharmony_ci	hrtimer_init(&ii_dev->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
3118c2ecf20Sopenharmony_ci	ii_dev->timer.function = idle_inject_timer_fn;
3128c2ecf20Sopenharmony_ci	ii_dev->latency_us = UINT_MAX;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	for_each_cpu(cpu, to_cpumask(ii_dev->cpumask)) {
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci		if (per_cpu(idle_inject_device, cpu)) {
3178c2ecf20Sopenharmony_ci			pr_err("cpu%d is already registered\n", cpu);
3188c2ecf20Sopenharmony_ci			goto out_rollback;
3198c2ecf20Sopenharmony_ci		}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci		per_cpu(idle_inject_device, cpu) = ii_dev;
3228c2ecf20Sopenharmony_ci	}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	return ii_dev;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ciout_rollback:
3278c2ecf20Sopenharmony_ci	for_each_cpu(cpu_rb, to_cpumask(ii_dev->cpumask)) {
3288c2ecf20Sopenharmony_ci		if (cpu == cpu_rb)
3298c2ecf20Sopenharmony_ci			break;
3308c2ecf20Sopenharmony_ci		per_cpu(idle_inject_device, cpu_rb) = NULL;
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	kfree(ii_dev);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	return NULL;
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci/**
3398c2ecf20Sopenharmony_ci * idle_inject_unregister - unregister idle injection control device
3408c2ecf20Sopenharmony_ci * @ii_dev: idle injection control device to unregister
3418c2ecf20Sopenharmony_ci *
3428c2ecf20Sopenharmony_ci * The function stops idle injection for the given control device,
3438c2ecf20Sopenharmony_ci * unregisters its kthreads and frees memory allocated when that device was
3448c2ecf20Sopenharmony_ci * created.
3458c2ecf20Sopenharmony_ci */
3468c2ecf20Sopenharmony_civoid idle_inject_unregister(struct idle_inject_device *ii_dev)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	unsigned int cpu;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	idle_inject_stop(ii_dev);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	for_each_cpu(cpu, to_cpumask(ii_dev->cpumask))
3538c2ecf20Sopenharmony_ci		per_cpu(idle_inject_device, cpu) = NULL;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	kfree(ii_dev);
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic struct smp_hotplug_thread idle_inject_threads = {
3598c2ecf20Sopenharmony_ci	.store = &idle_inject_thread.tsk,
3608c2ecf20Sopenharmony_ci	.setup = idle_inject_setup,
3618c2ecf20Sopenharmony_ci	.thread_fn = idle_inject_fn,
3628c2ecf20Sopenharmony_ci	.thread_comm = "idle_inject/%u",
3638c2ecf20Sopenharmony_ci	.thread_should_run = idle_inject_should_run,
3648c2ecf20Sopenharmony_ci};
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic int __init idle_inject_init(void)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	return smpboot_register_percpu_thread(&idle_inject_threads);
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ciearly_initcall(idle_inject_init);
371