xref: /linux/drivers/powercap/idle_inject.c (revision cbecf716ca618fd44feda6bd9a64a8179d031fc5)
188763a5cSDaniel Lezcano // SPDX-License-Identifier: GPL-2.0
288763a5cSDaniel Lezcano /*
388763a5cSDaniel Lezcano  * Copyright 2018 Linaro Limited
488763a5cSDaniel Lezcano  *
588763a5cSDaniel Lezcano  * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
688763a5cSDaniel Lezcano  *
788763a5cSDaniel Lezcano  * The idle injection framework provides a way to force CPUs to enter idle
888763a5cSDaniel Lezcano  * states for a specified fraction of time over a specified period.
988763a5cSDaniel Lezcano  *
1088763a5cSDaniel Lezcano  * It relies on the smpboot kthreads feature providing common code for CPU
1188763a5cSDaniel Lezcano  * hotplug and thread [un]parking.
1288763a5cSDaniel Lezcano  *
1388763a5cSDaniel Lezcano  * All of the kthreads used for idle injection are created at init time.
1488763a5cSDaniel Lezcano  *
1588763a5cSDaniel Lezcano  * Next, the users of the the idle injection framework provide a cpumask via
1688763a5cSDaniel Lezcano  * its register function. The kthreads will be synchronized with respect to
1788763a5cSDaniel Lezcano  * this cpumask.
1888763a5cSDaniel Lezcano  *
1988763a5cSDaniel Lezcano  * The idle + run duration is specified via separate helpers and that allows
2088763a5cSDaniel Lezcano  * idle injection to be started.
2188763a5cSDaniel Lezcano  *
220735069cSYangtao Li  * The idle injection kthreads will call play_idle_precise() with the idle
230735069cSYangtao Li  * duration and max allowed latency specified as per the above.
2488763a5cSDaniel Lezcano  *
2588763a5cSDaniel Lezcano  * After all of them have been woken up, a timer is set to start the next idle
2688763a5cSDaniel Lezcano  * injection cycle.
2788763a5cSDaniel Lezcano  *
2888763a5cSDaniel Lezcano  * The timer interrupt handler will wake up the idle injection kthreads for
2988763a5cSDaniel Lezcano  * all of the CPUs in the cpumask provided by the user.
3088763a5cSDaniel Lezcano  *
3188763a5cSDaniel Lezcano  * Idle injection is stopped synchronously and no leftover idle injection
3288763a5cSDaniel Lezcano  * kthread activity after its completion is guaranteed.
3388763a5cSDaniel Lezcano  *
3488763a5cSDaniel Lezcano  * It is up to the user of this framework to provide a lock for higher-level
3588763a5cSDaniel Lezcano  * synchronization to prevent race conditions like starting idle injection
3688763a5cSDaniel Lezcano  * while unregistering from the framework.
3788763a5cSDaniel Lezcano  */
3888763a5cSDaniel Lezcano #define pr_fmt(fmt) "ii_dev: " fmt
3988763a5cSDaniel Lezcano 
4088763a5cSDaniel Lezcano #include <linux/cpu.h>
4188763a5cSDaniel Lezcano #include <linux/hrtimer.h>
4288763a5cSDaniel Lezcano #include <linux/kthread.h>
4388763a5cSDaniel Lezcano #include <linux/sched.h>
4488763a5cSDaniel Lezcano #include <linux/slab.h>
4588763a5cSDaniel Lezcano #include <linux/smpboot.h>
46*00610935SPujin Shi #include <linux/idle_inject.h>
4788763a5cSDaniel Lezcano 
4888763a5cSDaniel Lezcano #include <uapi/linux/sched/types.h>
4988763a5cSDaniel Lezcano 
5088763a5cSDaniel Lezcano /**
5188763a5cSDaniel Lezcano  * struct idle_inject_thread - task on/off switch structure
5288763a5cSDaniel Lezcano  * @tsk: task injecting the idle cycles
5388763a5cSDaniel Lezcano  * @should_run: whether or not to run the task (for the smpboot kthread API)
5488763a5cSDaniel Lezcano  */
5588763a5cSDaniel Lezcano struct idle_inject_thread {
5688763a5cSDaniel Lezcano 	struct task_struct *tsk;
5788763a5cSDaniel Lezcano 	int should_run;
5888763a5cSDaniel Lezcano };
5988763a5cSDaniel Lezcano 
6088763a5cSDaniel Lezcano /**
6188763a5cSDaniel Lezcano  * struct idle_inject_device - idle injection data
6288763a5cSDaniel Lezcano  * @timer: idle injection period timer
63cd4c0763SDaniel Lezcano  * @idle_duration_us: duration of CPU idle time to inject
64cd4c0763SDaniel Lezcano  * @run_duration_us: duration of CPU run time to allow
65333cff6cSDaniel Lezcano  * @latency_us: max allowed latency
6688763a5cSDaniel Lezcano  * @cpumask: mask of CPUs affected by idle injection
6788763a5cSDaniel Lezcano  */
6888763a5cSDaniel Lezcano struct idle_inject_device {
6988763a5cSDaniel Lezcano 	struct hrtimer timer;
70cd4c0763SDaniel Lezcano 	unsigned int idle_duration_us;
71cd4c0763SDaniel Lezcano 	unsigned int run_duration_us;
72333cff6cSDaniel Lezcano 	unsigned int latency_us;
7327565c9eSGustavo A. R. Silva 	unsigned long cpumask[];
7488763a5cSDaniel Lezcano };
7588763a5cSDaniel Lezcano 
7688763a5cSDaniel Lezcano static DEFINE_PER_CPU(struct idle_inject_thread, idle_inject_thread);
7788763a5cSDaniel Lezcano static DEFINE_PER_CPU(struct idle_inject_device *, idle_inject_device);
7888763a5cSDaniel Lezcano 
7988763a5cSDaniel Lezcano /**
8088763a5cSDaniel Lezcano  * idle_inject_wakeup - Wake up idle injection threads
8188763a5cSDaniel Lezcano  * @ii_dev: target idle injection device
8288763a5cSDaniel Lezcano  *
8388763a5cSDaniel Lezcano  * Every idle injection task associated with the given idle injection device
8488763a5cSDaniel Lezcano  * and running on an online CPU will be woken up.
8588763a5cSDaniel Lezcano  */
8688763a5cSDaniel Lezcano static void idle_inject_wakeup(struct idle_inject_device *ii_dev)
8788763a5cSDaniel Lezcano {
8888763a5cSDaniel Lezcano 	struct idle_inject_thread *iit;
8988763a5cSDaniel Lezcano 	unsigned int cpu;
9088763a5cSDaniel Lezcano 
9188763a5cSDaniel Lezcano 	for_each_cpu_and(cpu, to_cpumask(ii_dev->cpumask), cpu_online_mask) {
9288763a5cSDaniel Lezcano 		iit = per_cpu_ptr(&idle_inject_thread, cpu);
9388763a5cSDaniel Lezcano 		iit->should_run = 1;
9488763a5cSDaniel Lezcano 		wake_up_process(iit->tsk);
9588763a5cSDaniel Lezcano 	}
9688763a5cSDaniel Lezcano }
9788763a5cSDaniel Lezcano 
9888763a5cSDaniel Lezcano /**
9988763a5cSDaniel Lezcano  * idle_inject_timer_fn - idle injection timer function
10088763a5cSDaniel Lezcano  * @timer: idle injection hrtimer
10188763a5cSDaniel Lezcano  *
10288763a5cSDaniel Lezcano  * This function is called when the idle injection timer expires.  It wakes up
10388763a5cSDaniel Lezcano  * idle injection tasks associated with the timer and they, in turn, invoke
1040735069cSYangtao Li  * play_idle_precise() to inject a specified amount of CPU idle time.
10588763a5cSDaniel Lezcano  *
10688763a5cSDaniel Lezcano  * Return: HRTIMER_RESTART.
10788763a5cSDaniel Lezcano  */
10888763a5cSDaniel Lezcano static enum hrtimer_restart idle_inject_timer_fn(struct hrtimer *timer)
10988763a5cSDaniel Lezcano {
110cd4c0763SDaniel Lezcano 	unsigned int duration_us;
11188763a5cSDaniel Lezcano 	struct idle_inject_device *ii_dev =
11288763a5cSDaniel Lezcano 		container_of(timer, struct idle_inject_device, timer);
11388763a5cSDaniel Lezcano 
114cd4c0763SDaniel Lezcano 	duration_us = READ_ONCE(ii_dev->run_duration_us);
115cd4c0763SDaniel Lezcano 	duration_us += READ_ONCE(ii_dev->idle_duration_us);
11688763a5cSDaniel Lezcano 
11788763a5cSDaniel Lezcano 	idle_inject_wakeup(ii_dev);
11888763a5cSDaniel Lezcano 
119cd4c0763SDaniel Lezcano 	hrtimer_forward_now(timer, ns_to_ktime(duration_us * NSEC_PER_USEC));
12088763a5cSDaniel Lezcano 
12188763a5cSDaniel Lezcano 	return HRTIMER_RESTART;
12288763a5cSDaniel Lezcano }
12388763a5cSDaniel Lezcano 
12488763a5cSDaniel Lezcano /**
12588763a5cSDaniel Lezcano  * idle_inject_fn - idle injection work function
12688763a5cSDaniel Lezcano  * @cpu: the CPU owning the task
12788763a5cSDaniel Lezcano  *
1280735069cSYangtao Li  * This function calls play_idle_precise() to inject a specified amount of CPU
1290735069cSYangtao Li  * idle time.
13088763a5cSDaniel Lezcano  */
13188763a5cSDaniel Lezcano static void idle_inject_fn(unsigned int cpu)
13288763a5cSDaniel Lezcano {
13388763a5cSDaniel Lezcano 	struct idle_inject_device *ii_dev;
13488763a5cSDaniel Lezcano 	struct idle_inject_thread *iit;
13588763a5cSDaniel Lezcano 
13688763a5cSDaniel Lezcano 	ii_dev = per_cpu(idle_inject_device, cpu);
13788763a5cSDaniel Lezcano 	iit = per_cpu_ptr(&idle_inject_thread, cpu);
13888763a5cSDaniel Lezcano 
13988763a5cSDaniel Lezcano 	/*
14088763a5cSDaniel Lezcano 	 * Let the smpboot main loop know that the task should not run again.
14188763a5cSDaniel Lezcano 	 */
14288763a5cSDaniel Lezcano 	iit->should_run = 0;
14388763a5cSDaniel Lezcano 
144333cff6cSDaniel Lezcano 	play_idle_precise(READ_ONCE(ii_dev->idle_duration_us) * NSEC_PER_USEC,
145333cff6cSDaniel Lezcano 			  READ_ONCE(ii_dev->latency_us) * NSEC_PER_USEC);
14688763a5cSDaniel Lezcano }
14788763a5cSDaniel Lezcano 
14888763a5cSDaniel Lezcano /**
14988763a5cSDaniel Lezcano  * idle_inject_set_duration - idle and run duration update helper
150cd4c0763SDaniel Lezcano  * @run_duration_us: CPU run time to allow in microseconds
151cd4c0763SDaniel Lezcano  * @idle_duration_us: CPU idle time to inject in microseconds
15288763a5cSDaniel Lezcano  */
15388763a5cSDaniel Lezcano void idle_inject_set_duration(struct idle_inject_device *ii_dev,
154cd4c0763SDaniel Lezcano 			      unsigned int run_duration_us,
155cd4c0763SDaniel Lezcano 			      unsigned int idle_duration_us)
15688763a5cSDaniel Lezcano {
157cd4c0763SDaniel Lezcano 	if (run_duration_us && idle_duration_us) {
158cd4c0763SDaniel Lezcano 		WRITE_ONCE(ii_dev->run_duration_us, run_duration_us);
159cd4c0763SDaniel Lezcano 		WRITE_ONCE(ii_dev->idle_duration_us, idle_duration_us);
16088763a5cSDaniel Lezcano 	}
16188763a5cSDaniel Lezcano }
16288763a5cSDaniel Lezcano 
16388763a5cSDaniel Lezcano /**
16488763a5cSDaniel Lezcano  * idle_inject_get_duration - idle and run duration retrieval helper
165cd4c0763SDaniel Lezcano  * @run_duration_us: memory location to store the current CPU run time
166cd4c0763SDaniel Lezcano  * @idle_duration_us: memory location to store the current CPU idle time
16788763a5cSDaniel Lezcano  */
16888763a5cSDaniel Lezcano void idle_inject_get_duration(struct idle_inject_device *ii_dev,
169cd4c0763SDaniel Lezcano 			      unsigned int *run_duration_us,
170cd4c0763SDaniel Lezcano 			      unsigned int *idle_duration_us)
17188763a5cSDaniel Lezcano {
172cd4c0763SDaniel Lezcano 	*run_duration_us = READ_ONCE(ii_dev->run_duration_us);
173cd4c0763SDaniel Lezcano 	*idle_duration_us = READ_ONCE(ii_dev->idle_duration_us);
17488763a5cSDaniel Lezcano }
17588763a5cSDaniel Lezcano 
17688763a5cSDaniel Lezcano /**
177333cff6cSDaniel Lezcano  * idle_inject_set_latency - set the maximum latency allowed
178333cff6cSDaniel Lezcano  * @latency_us: set the latency requirement for the idle state
179333cff6cSDaniel Lezcano  */
180333cff6cSDaniel Lezcano void idle_inject_set_latency(struct idle_inject_device *ii_dev,
181333cff6cSDaniel Lezcano 			     unsigned int latency_us)
182333cff6cSDaniel Lezcano {
183333cff6cSDaniel Lezcano 	WRITE_ONCE(ii_dev->latency_us, latency_us);
184333cff6cSDaniel Lezcano }
185333cff6cSDaniel Lezcano 
186333cff6cSDaniel Lezcano /**
18788763a5cSDaniel Lezcano  * idle_inject_start - start idle injections
18888763a5cSDaniel Lezcano  * @ii_dev: idle injection control device structure
18988763a5cSDaniel Lezcano  *
19088763a5cSDaniel Lezcano  * The function starts idle injection by first waking up all of the idle
19188763a5cSDaniel Lezcano  * injection kthreads associated with @ii_dev to let them inject CPU idle time
19288763a5cSDaniel Lezcano  * sets up a timer to start the next idle injection period.
19388763a5cSDaniel Lezcano  *
19488763a5cSDaniel Lezcano  * Return: -EINVAL if the CPU idle or CPU run time is not set or 0 on success.
19588763a5cSDaniel Lezcano  */
19688763a5cSDaniel Lezcano int idle_inject_start(struct idle_inject_device *ii_dev)
19788763a5cSDaniel Lezcano {
198cd4c0763SDaniel Lezcano 	unsigned int idle_duration_us = READ_ONCE(ii_dev->idle_duration_us);
199cd4c0763SDaniel Lezcano 	unsigned int run_duration_us = READ_ONCE(ii_dev->run_duration_us);
20088763a5cSDaniel Lezcano 
201cd4c0763SDaniel Lezcano 	if (!idle_duration_us || !run_duration_us)
20288763a5cSDaniel Lezcano 		return -EINVAL;
20388763a5cSDaniel Lezcano 
20488763a5cSDaniel Lezcano 	pr_debug("Starting injecting idle cycles on CPUs '%*pbl'\n",
20588763a5cSDaniel Lezcano 		 cpumask_pr_args(to_cpumask(ii_dev->cpumask)));
20688763a5cSDaniel Lezcano 
20788763a5cSDaniel Lezcano 	idle_inject_wakeup(ii_dev);
20888763a5cSDaniel Lezcano 
20988763a5cSDaniel Lezcano 	hrtimer_start(&ii_dev->timer,
210cd4c0763SDaniel Lezcano 		      ns_to_ktime((idle_duration_us + run_duration_us) *
211cd4c0763SDaniel Lezcano 				  NSEC_PER_USEC),
21288763a5cSDaniel Lezcano 		      HRTIMER_MODE_REL);
21388763a5cSDaniel Lezcano 
21488763a5cSDaniel Lezcano 	return 0;
21588763a5cSDaniel Lezcano }
21688763a5cSDaniel Lezcano 
21788763a5cSDaniel Lezcano /**
21888763a5cSDaniel Lezcano  * idle_inject_stop - stops idle injections
21988763a5cSDaniel Lezcano  * @ii_dev: idle injection control device structure
22088763a5cSDaniel Lezcano  *
22188763a5cSDaniel Lezcano  * The function stops idle injection and waits for the threads to finish work.
22288763a5cSDaniel Lezcano  * If CPU idle time is being injected when this function runs, then it will
22388763a5cSDaniel Lezcano  * wait until the end of the cycle.
22488763a5cSDaniel Lezcano  *
22588763a5cSDaniel Lezcano  * When it returns, there is no more idle injection kthread activity.  The
22688763a5cSDaniel Lezcano  * kthreads are scheduled out and the periodic timer is off.
22788763a5cSDaniel Lezcano  */
22888763a5cSDaniel Lezcano void idle_inject_stop(struct idle_inject_device *ii_dev)
22988763a5cSDaniel Lezcano {
23088763a5cSDaniel Lezcano 	struct idle_inject_thread *iit;
23188763a5cSDaniel Lezcano 	unsigned int cpu;
23288763a5cSDaniel Lezcano 
23388763a5cSDaniel Lezcano 	pr_debug("Stopping idle injection on CPUs '%*pbl'\n",
23488763a5cSDaniel Lezcano 		 cpumask_pr_args(to_cpumask(ii_dev->cpumask)));
23588763a5cSDaniel Lezcano 
23688763a5cSDaniel Lezcano 	hrtimer_cancel(&ii_dev->timer);
23788763a5cSDaniel Lezcano 
23888763a5cSDaniel Lezcano 	/*
23988763a5cSDaniel Lezcano 	 * Stopping idle injection requires all of the idle injection kthreads
24088763a5cSDaniel Lezcano 	 * associated with the given cpumask to be parked and stay that way, so
24188763a5cSDaniel Lezcano 	 * prevent CPUs from going online at this point.  Any CPUs going online
24288763a5cSDaniel Lezcano 	 * after the loop below will be covered by clearing the should_run flag
24388763a5cSDaniel Lezcano 	 * that will cause the smpboot main loop to schedule them out.
24488763a5cSDaniel Lezcano 	 */
24588763a5cSDaniel Lezcano 	cpu_hotplug_disable();
24688763a5cSDaniel Lezcano 
24788763a5cSDaniel Lezcano 	/*
24888763a5cSDaniel Lezcano 	 * Iterate over all (online + offline) CPUs here in case one of them
24988763a5cSDaniel Lezcano 	 * goes offline with the should_run flag set so as to prevent its idle
25088763a5cSDaniel Lezcano 	 * injection kthread from running when the CPU goes online again after
25188763a5cSDaniel Lezcano 	 * the ii_dev has been freed.
25288763a5cSDaniel Lezcano 	 */
25388763a5cSDaniel Lezcano 	for_each_cpu(cpu, to_cpumask(ii_dev->cpumask)) {
25488763a5cSDaniel Lezcano 		iit = per_cpu_ptr(&idle_inject_thread, cpu);
25588763a5cSDaniel Lezcano 		iit->should_run = 0;
25688763a5cSDaniel Lezcano 
25788763a5cSDaniel Lezcano 		wait_task_inactive(iit->tsk, 0);
25888763a5cSDaniel Lezcano 	}
25988763a5cSDaniel Lezcano 
26088763a5cSDaniel Lezcano 	cpu_hotplug_enable();
26188763a5cSDaniel Lezcano }
26288763a5cSDaniel Lezcano 
26388763a5cSDaniel Lezcano /**
26488763a5cSDaniel Lezcano  * idle_inject_setup - prepare the current task for idle injection
26588763a5cSDaniel Lezcano  * @cpu: not used
26688763a5cSDaniel Lezcano  *
26788763a5cSDaniel Lezcano  * Called once, this function is in charge of setting the current task's
26888763a5cSDaniel Lezcano  * scheduler parameters to make it an RT task.
26988763a5cSDaniel Lezcano  */
27088763a5cSDaniel Lezcano static void idle_inject_setup(unsigned int cpu)
27188763a5cSDaniel Lezcano {
272c3f47cf9SPeter Zijlstra 	sched_set_fifo(current);
27388763a5cSDaniel Lezcano }
27488763a5cSDaniel Lezcano 
27588763a5cSDaniel Lezcano /**
27688763a5cSDaniel Lezcano  * idle_inject_should_run - function helper for the smpboot API
27788763a5cSDaniel Lezcano  * @cpu: CPU the kthread is running on
27888763a5cSDaniel Lezcano  *
27988763a5cSDaniel Lezcano  * Return: whether or not the thread can run.
28088763a5cSDaniel Lezcano  */
28188763a5cSDaniel Lezcano static int idle_inject_should_run(unsigned int cpu)
28288763a5cSDaniel Lezcano {
28388763a5cSDaniel Lezcano 	struct idle_inject_thread *iit =
28488763a5cSDaniel Lezcano 		per_cpu_ptr(&idle_inject_thread, cpu);
28588763a5cSDaniel Lezcano 
28688763a5cSDaniel Lezcano 	return iit->should_run;
28788763a5cSDaniel Lezcano }
28888763a5cSDaniel Lezcano 
28988763a5cSDaniel Lezcano /**
29088763a5cSDaniel Lezcano  * idle_inject_register - initialize idle injection on a set of CPUs
29188763a5cSDaniel Lezcano  * @cpumask: CPUs to be affected by idle injection
29288763a5cSDaniel Lezcano  *
29388763a5cSDaniel Lezcano  * This function creates an idle injection control device structure for the
29488763a5cSDaniel Lezcano  * given set of CPUs and initializes the timer associated with it.  It does not
29588763a5cSDaniel Lezcano  * start any injection cycles.
29688763a5cSDaniel Lezcano  *
29788763a5cSDaniel Lezcano  * Return: NULL if memory allocation fails, idle injection control device
29888763a5cSDaniel Lezcano  * pointer on success.
29988763a5cSDaniel Lezcano  */
30088763a5cSDaniel Lezcano struct idle_inject_device *idle_inject_register(struct cpumask *cpumask)
30188763a5cSDaniel Lezcano {
30288763a5cSDaniel Lezcano 	struct idle_inject_device *ii_dev;
30388763a5cSDaniel Lezcano 	int cpu, cpu_rb;
30488763a5cSDaniel Lezcano 
30588763a5cSDaniel Lezcano 	ii_dev = kzalloc(sizeof(*ii_dev) + cpumask_size(), GFP_KERNEL);
30688763a5cSDaniel Lezcano 	if (!ii_dev)
30788763a5cSDaniel Lezcano 		return NULL;
30888763a5cSDaniel Lezcano 
30988763a5cSDaniel Lezcano 	cpumask_copy(to_cpumask(ii_dev->cpumask), cpumask);
31088763a5cSDaniel Lezcano 	hrtimer_init(&ii_dev->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
31188763a5cSDaniel Lezcano 	ii_dev->timer.function = idle_inject_timer_fn;
312333cff6cSDaniel Lezcano 	ii_dev->latency_us = UINT_MAX;
31388763a5cSDaniel Lezcano 
31488763a5cSDaniel Lezcano 	for_each_cpu(cpu, to_cpumask(ii_dev->cpumask)) {
31588763a5cSDaniel Lezcano 
31688763a5cSDaniel Lezcano 		if (per_cpu(idle_inject_device, cpu)) {
31788763a5cSDaniel Lezcano 			pr_err("cpu%d is already registered\n", cpu);
31888763a5cSDaniel Lezcano 			goto out_rollback;
31988763a5cSDaniel Lezcano 		}
32088763a5cSDaniel Lezcano 
32188763a5cSDaniel Lezcano 		per_cpu(idle_inject_device, cpu) = ii_dev;
32288763a5cSDaniel Lezcano 	}
32388763a5cSDaniel Lezcano 
32488763a5cSDaniel Lezcano 	return ii_dev;
32588763a5cSDaniel Lezcano 
32688763a5cSDaniel Lezcano out_rollback:
32788763a5cSDaniel Lezcano 	for_each_cpu(cpu_rb, to_cpumask(ii_dev->cpumask)) {
32888763a5cSDaniel Lezcano 		if (cpu == cpu_rb)
32988763a5cSDaniel Lezcano 			break;
33088763a5cSDaniel Lezcano 		per_cpu(idle_inject_device, cpu_rb) = NULL;
33188763a5cSDaniel Lezcano 	}
33288763a5cSDaniel Lezcano 
33388763a5cSDaniel Lezcano 	kfree(ii_dev);
33488763a5cSDaniel Lezcano 
33588763a5cSDaniel Lezcano 	return NULL;
33688763a5cSDaniel Lezcano }
33788763a5cSDaniel Lezcano 
33888763a5cSDaniel Lezcano /**
33988763a5cSDaniel Lezcano  * idle_inject_unregister - unregister idle injection control device
34088763a5cSDaniel Lezcano  * @ii_dev: idle injection control device to unregister
34188763a5cSDaniel Lezcano  *
34288763a5cSDaniel Lezcano  * The function stops idle injection for the given control device,
34388763a5cSDaniel Lezcano  * unregisters its kthreads and frees memory allocated when that device was
34488763a5cSDaniel Lezcano  * created.
34588763a5cSDaniel Lezcano  */
34688763a5cSDaniel Lezcano void idle_inject_unregister(struct idle_inject_device *ii_dev)
34788763a5cSDaniel Lezcano {
34888763a5cSDaniel Lezcano 	unsigned int cpu;
34988763a5cSDaniel Lezcano 
35088763a5cSDaniel Lezcano 	idle_inject_stop(ii_dev);
35188763a5cSDaniel Lezcano 
35288763a5cSDaniel Lezcano 	for_each_cpu(cpu, to_cpumask(ii_dev->cpumask))
35388763a5cSDaniel Lezcano 		per_cpu(idle_inject_device, cpu) = NULL;
35488763a5cSDaniel Lezcano 
35588763a5cSDaniel Lezcano 	kfree(ii_dev);
35688763a5cSDaniel Lezcano }
35788763a5cSDaniel Lezcano 
35888763a5cSDaniel Lezcano static struct smp_hotplug_thread idle_inject_threads = {
35988763a5cSDaniel Lezcano 	.store = &idle_inject_thread.tsk,
36088763a5cSDaniel Lezcano 	.setup = idle_inject_setup,
36188763a5cSDaniel Lezcano 	.thread_fn = idle_inject_fn,
36288763a5cSDaniel Lezcano 	.thread_comm = "idle_inject/%u",
36388763a5cSDaniel Lezcano 	.thread_should_run = idle_inject_should_run,
36488763a5cSDaniel Lezcano };
36588763a5cSDaniel Lezcano 
36688763a5cSDaniel Lezcano static int __init idle_inject_init(void)
36788763a5cSDaniel Lezcano {
36888763a5cSDaniel Lezcano 	return smpboot_register_percpu_thread(&idle_inject_threads);
36988763a5cSDaniel Lezcano }
37088763a5cSDaniel Lezcano early_initcall(idle_inject_init);
371