/*1* driver.c - driver support2*3* (C) 2006-2007 Venkatesh Pallipadi <[email protected]>4* Shaohua Li <[email protected]>5* Adam Belay <[email protected]>6*7* This code is licenced under the GPL.8*/910#include <linux/mutex.h>11#include <linux/module.h>12#include <linux/sched.h>13#include <linux/sched/idle.h>14#include <linux/cpuidle.h>15#include <linux/cpumask.h>16#include <linux/tick.h>17#include <linux/cpu.h>18#include <linux/math64.h>1920#include "cpuidle.h"2122DEFINE_SPINLOCK(cpuidle_driver_lock);2324#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS2526static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);2728/**29* __cpuidle_get_cpu_driver - return the cpuidle driver tied to a CPU.30* @cpu: the CPU handled by the driver31*32* Returns a pointer to struct cpuidle_driver or NULL if no driver has been33* registered for @cpu.34*/35static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)36{37return per_cpu(cpuidle_drivers, cpu);38}3940/**41* __cpuidle_unset_driver - unset per CPU driver variables.42* @drv: a valid pointer to a struct cpuidle_driver43*44* For each CPU in the driver's CPU mask, unset the registered driver per CPU45* variable. If @drv is different from the registered driver, the corresponding46* variable is not cleared.47*/48static inline void __cpuidle_unset_driver(struct cpuidle_driver *drv)49{50int cpu;5152for_each_cpu(cpu, drv->cpumask) {5354if (drv != __cpuidle_get_cpu_driver(cpu))55continue;5657per_cpu(cpuidle_drivers, cpu) = NULL;58}59}6061/**62* __cpuidle_set_driver - set per CPU driver variables for the given driver.63* @drv: a valid pointer to a struct cpuidle_driver64*65* Returns 0 on success, -EBUSY if any CPU in the cpumask have a driver66* different from drv already.67*/68static inline int __cpuidle_set_driver(struct cpuidle_driver *drv)69{70int cpu;7172for_each_cpu(cpu, drv->cpumask) {73struct cpuidle_driver *old_drv;7475old_drv = __cpuidle_get_cpu_driver(cpu);76if (old_drv && old_drv != drv)77return -EBUSY;78}7980for_each_cpu(cpu, drv->cpumask)81per_cpu(cpuidle_drivers, cpu) = drv;8283return 0;84}8586#else8788static struct cpuidle_driver *cpuidle_curr_driver;8990/**91* __cpuidle_get_cpu_driver - return the global cpuidle driver pointer.92* @cpu: ignored without the multiple driver support93*94* Return a pointer to a struct cpuidle_driver object or NULL if no driver was95* previously registered.96*/97static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)98{99return cpuidle_curr_driver;100}101102/**103* __cpuidle_set_driver - assign the global cpuidle driver variable.104* @drv: pointer to a struct cpuidle_driver object105*106* Returns 0 on success, -EBUSY if the driver is already registered.107*/108static inline int __cpuidle_set_driver(struct cpuidle_driver *drv)109{110if (cpuidle_curr_driver)111return -EBUSY;112113cpuidle_curr_driver = drv;114115return 0;116}117118/**119* __cpuidle_unset_driver - unset the global cpuidle driver variable.120* @drv: a pointer to a struct cpuidle_driver121*122* Reset the global cpuidle variable to NULL. If @drv does not match the123* registered driver, do nothing.124*/125static inline void __cpuidle_unset_driver(struct cpuidle_driver *drv)126{127if (drv == cpuidle_curr_driver)128cpuidle_curr_driver = NULL;129}130131#endif132133/**134* cpuidle_setup_broadcast_timer - enable/disable the broadcast timer on a cpu135* @arg: a void pointer used to match the SMP cross call API136*137* If @arg is NULL broadcast is disabled otherwise enabled138*139* This function is executed per CPU by an SMP cross call. It's not140* supposed to be called directly.141*/142static void cpuidle_setup_broadcast_timer(void *arg)143{144if (arg)145tick_broadcast_enable();146else147tick_broadcast_disable();148}149150/**151* __cpuidle_driver_init - initialize the driver's internal data152* @drv: a valid pointer to a struct cpuidle_driver153*/154static void __cpuidle_driver_init(struct cpuidle_driver *drv)155{156int i;157158/*159* Use all possible CPUs as the default, because if the kernel boots160* with some CPUs offline and then we online one of them, the CPU161* notifier has to know which driver to assign.162*/163if (!drv->cpumask)164drv->cpumask = (struct cpumask *)cpu_possible_mask;165166for (i = 0; i < drv->state_count; i++) {167struct cpuidle_state *s = &drv->states[i];168169/*170* Look for the timer stop flag in the different states and if171* it is found, indicate that the broadcast timer has to be set172* up.173*/174if (s->flags & CPUIDLE_FLAG_TIMER_STOP)175drv->bctimer = 1;176177/*178* The core will use the target residency and exit latency179* values in nanoseconds, but allow drivers to provide them in180* microseconds too.181*/182if (s->target_residency > 0)183s->target_residency_ns = s->target_residency * NSEC_PER_USEC;184else if (s->target_residency_ns < 0)185s->target_residency_ns = 0;186else187s->target_residency = div_u64(s->target_residency_ns, NSEC_PER_USEC);188189if (s->exit_latency > 0)190s->exit_latency_ns = mul_u32_u32(s->exit_latency, NSEC_PER_USEC);191else if (s->exit_latency_ns < 0)192s->exit_latency_ns = 0;193else194s->exit_latency = div_u64(s->exit_latency_ns, NSEC_PER_USEC);195}196}197198/**199* __cpuidle_register_driver: register the driver200* @drv: a valid pointer to a struct cpuidle_driver201*202* Do some sanity checks, initialize the driver, assign the driver to the203* global cpuidle driver variable(s) and set up the broadcast timer if the204* cpuidle driver has some states that shut down the local timer.205*206* Returns 0 on success, a negative error code otherwise:207* * -EINVAL if the driver pointer is NULL or no idle states are available208* * -ENODEV if the cpuidle framework is disabled209* * -EBUSY if the driver is already assigned to the global variable(s)210*/211static int __cpuidle_register_driver(struct cpuidle_driver *drv)212{213int ret;214215if (!drv || !drv->state_count)216return -EINVAL;217218ret = cpuidle_coupled_state_verify(drv);219if (ret)220return ret;221222if (cpuidle_disabled())223return -ENODEV;224225__cpuidle_driver_init(drv);226227ret = __cpuidle_set_driver(drv);228if (ret)229return ret;230231if (drv->bctimer)232on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer,233(void *)1, 1);234235return 0;236}237238/**239* __cpuidle_unregister_driver - unregister the driver240* @drv: a valid pointer to a struct cpuidle_driver241*242* Check if the driver is no longer in use, reset the global cpuidle driver243* variable(s) and disable the timer broadcast notification mechanism if it was244* in use.245*246*/247static void __cpuidle_unregister_driver(struct cpuidle_driver *drv)248{249if (drv->bctimer) {250drv->bctimer = 0;251on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer,252NULL, 1);253}254255__cpuidle_unset_driver(drv);256}257258/**259* cpuidle_register_driver - registers a driver260* @drv: a pointer to a valid struct cpuidle_driver261*262* Register the driver under a lock to prevent concurrent attempts to263* [un]register the driver from occurring at the same time.264*265* Returns 0 on success, a negative error code (returned by266* __cpuidle_register_driver()) otherwise.267*/268int cpuidle_register_driver(struct cpuidle_driver *drv)269{270struct cpuidle_governor *gov;271int ret;272273spin_lock(&cpuidle_driver_lock);274ret = __cpuidle_register_driver(drv);275spin_unlock(&cpuidle_driver_lock);276277if (!ret && !strlen(param_governor) && drv->governor &&278(cpuidle_get_driver() == drv)) {279mutex_lock(&cpuidle_lock);280gov = cpuidle_find_governor(drv->governor);281if (gov) {282cpuidle_prev_governor = cpuidle_curr_governor;283if (cpuidle_switch_governor(gov) < 0)284cpuidle_prev_governor = NULL;285}286mutex_unlock(&cpuidle_lock);287}288289return ret;290}291EXPORT_SYMBOL_GPL(cpuidle_register_driver);292293/**294* cpuidle_unregister_driver - unregisters a driver295* @drv: a pointer to a valid struct cpuidle_driver296*297* Unregisters the cpuidle driver under a lock to prevent concurrent attempts298* to [un]register the driver from occurring at the same time. @drv has to299* match the currently registered driver.300*/301void cpuidle_unregister_driver(struct cpuidle_driver *drv)302{303bool enabled = (cpuidle_get_driver() == drv);304305spin_lock(&cpuidle_driver_lock);306__cpuidle_unregister_driver(drv);307spin_unlock(&cpuidle_driver_lock);308309if (!enabled)310return;311312mutex_lock(&cpuidle_lock);313if (cpuidle_prev_governor) {314if (!cpuidle_switch_governor(cpuidle_prev_governor))315cpuidle_prev_governor = NULL;316}317mutex_unlock(&cpuidle_lock);318}319EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);320321/**322* cpuidle_get_driver - return the driver tied to the current CPU.323*324* Returns a struct cpuidle_driver pointer, or NULL if no driver is registered.325*/326struct cpuidle_driver *cpuidle_get_driver(void)327{328struct cpuidle_driver *drv;329int cpu;330331cpu = get_cpu();332drv = __cpuidle_get_cpu_driver(cpu);333put_cpu();334335return drv;336}337EXPORT_SYMBOL_GPL(cpuidle_get_driver);338339/**340* cpuidle_get_cpu_driver - return the driver registered for a CPU.341* @dev: a valid pointer to a struct cpuidle_device342*343* Returns a struct cpuidle_driver pointer, or NULL if no driver is registered344* for the CPU associated with @dev.345*/346struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)347{348if (!dev)349return NULL;350351return __cpuidle_get_cpu_driver(dev->cpu);352}353EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver);354355/**356* cpuidle_driver_state_disabled - Disable or enable an idle state357* @drv: cpuidle driver owning the state358* @idx: State index359* @disable: Whether or not to disable the state360*/361void cpuidle_driver_state_disabled(struct cpuidle_driver *drv, int idx,362bool disable)363{364unsigned int cpu;365366mutex_lock(&cpuidle_lock);367368spin_lock(&cpuidle_driver_lock);369370if (!drv->cpumask) {371drv->states[idx].flags |= CPUIDLE_FLAG_UNUSABLE;372goto unlock;373}374375for_each_cpu(cpu, drv->cpumask) {376struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);377378if (!dev)379continue;380381if (disable)382dev->states_usage[idx].disable |= CPUIDLE_STATE_DISABLED_BY_DRIVER;383else384dev->states_usage[idx].disable &= ~CPUIDLE_STATE_DISABLED_BY_DRIVER;385}386387unlock:388spin_unlock(&cpuidle_driver_lock);389390mutex_unlock(&cpuidle_lock);391}392393394