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