xref: /linux/drivers/cpuidle/cpuidle.c (revision 3810631332465d967ba5e27ea2c7dff2c9afac6c)
14f86d3a8SLen Brown /*
24f86d3a8SLen Brown  * cpuidle.c - core cpuidle infrastructure
34f86d3a8SLen Brown  *
44f86d3a8SLen Brown  * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
54f86d3a8SLen Brown  *               Shaohua Li <shaohua.li@intel.com>
64f86d3a8SLen Brown  *               Adam Belay <abelay@novell.com>
74f86d3a8SLen Brown  *
84f86d3a8SLen Brown  * This code is licenced under the GPL.
94f86d3a8SLen Brown  */
104f86d3a8SLen Brown 
11b60e6a0eSDaniel Lezcano #include <linux/clockchips.h>
124f86d3a8SLen Brown #include <linux/kernel.h>
134f86d3a8SLen Brown #include <linux/mutex.h>
144f86d3a8SLen Brown #include <linux/sched.h>
154f86d3a8SLen Brown #include <linux/notifier.h>
16e8db0be1SJean Pihet #include <linux/pm_qos.h>
174f86d3a8SLen Brown #include <linux/cpu.h>
184f86d3a8SLen Brown #include <linux/cpuidle.h>
199a0b8415Svenkatesh.pallipadi@intel.com #include <linux/ktime.h>
202e94d1f7SArjan van de Ven #include <linux/hrtimer.h>
21884b17e1SPaul Gortmaker #include <linux/module.h>
22*38106313SRafael J. Wysocki #include <linux/suspend.h>
23288f023eSArjan van de Ven #include <trace/events/power.h>
244f86d3a8SLen Brown 
254f86d3a8SLen Brown #include "cpuidle.h"
264f86d3a8SLen Brown 
274f86d3a8SLen Brown DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
284c637b21SDaniel Lezcano DEFINE_PER_CPU(struct cpuidle_device, cpuidle_dev);
294f86d3a8SLen Brown 
304f86d3a8SLen Brown DEFINE_MUTEX(cpuidle_lock);
314f86d3a8SLen Brown LIST_HEAD(cpuidle_detected_devices);
324f86d3a8SLen Brown 
334f86d3a8SLen Brown static int enabled_devices;
3462027aeaSLen Brown static int off __read_mostly;
35a0bfa137SLen Brown static int initialized __read_mostly;
3662027aeaSLen Brown 
3762027aeaSLen Brown int cpuidle_disabled(void)
3862027aeaSLen Brown {
3962027aeaSLen Brown 	return off;
4062027aeaSLen Brown }
41d91ee586SLen Brown void disable_cpuidle(void)
42d91ee586SLen Brown {
43d91ee586SLen Brown 	off = 1;
44d91ee586SLen Brown }
454f86d3a8SLen Brown 
464f86d3a8SLen Brown /**
471a022e3fSBoris Ostrovsky  * cpuidle_play_dead - cpu off-lining
481a022e3fSBoris Ostrovsky  *
49ee01e663SToshi Kani  * Returns in case of an error or no driver
501a022e3fSBoris Ostrovsky  */
511a022e3fSBoris Ostrovsky int cpuidle_play_dead(void)
521a022e3fSBoris Ostrovsky {
531a022e3fSBoris Ostrovsky 	struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
54bf4d1b5dSDaniel Lezcano 	struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
558aef33a7SDaniel Lezcano 	int i;
561a022e3fSBoris Ostrovsky 
57ee01e663SToshi Kani 	if (!drv)
58ee01e663SToshi Kani 		return -ENODEV;
59ee01e663SToshi Kani 
601a022e3fSBoris Ostrovsky 	/* Find lowest-power state that supports long-term idle */
618aef33a7SDaniel Lezcano 	for (i = drv->state_count - 1; i >= CPUIDLE_DRIVER_STATE_START; i--)
628aef33a7SDaniel Lezcano 		if (drv->states[i].enter_dead)
638aef33a7SDaniel Lezcano 			return drv->states[i].enter_dead(dev, i);
641a022e3fSBoris Ostrovsky 
651a022e3fSBoris Ostrovsky 	return -ENODEV;
661a022e3fSBoris Ostrovsky }
671a022e3fSBoris Ostrovsky 
681a022e3fSBoris Ostrovsky /**
69*38106313SRafael J. Wysocki  * cpuidle_find_deepest_state - Find deepest state meeting specific conditions.
70*38106313SRafael J. Wysocki  * @drv: cpuidle driver for the given CPU.
71*38106313SRafael J. Wysocki  * @dev: cpuidle device for the given CPU.
72a6220fc1SRafael J. Wysocki  */
73a6220fc1SRafael J. Wysocki static int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
74a6220fc1SRafael J. Wysocki 				      struct cpuidle_device *dev)
75a6220fc1SRafael J. Wysocki {
76a6220fc1SRafael J. Wysocki 	unsigned int latency_req = 0;
77a6220fc1SRafael J. Wysocki 	int i, ret = CPUIDLE_DRIVER_STATE_START - 1;
78a6220fc1SRafael J. Wysocki 
79a6220fc1SRafael J. Wysocki 	for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
80a6220fc1SRafael J. Wysocki 		struct cpuidle_state *s = &drv->states[i];
81a6220fc1SRafael J. Wysocki 		struct cpuidle_state_usage *su = &dev->states_usage[i];
82a6220fc1SRafael J. Wysocki 
83a6220fc1SRafael J. Wysocki 		if (s->disabled || su->disable || s->exit_latency <= latency_req)
84a6220fc1SRafael J. Wysocki 			continue;
85a6220fc1SRafael J. Wysocki 
86a6220fc1SRafael J. Wysocki 		latency_req = s->exit_latency;
87a6220fc1SRafael J. Wysocki 		ret = i;
88a6220fc1SRafael J. Wysocki 	}
89a6220fc1SRafael J. Wysocki 	return ret;
90a6220fc1SRafael J. Wysocki }
91a6220fc1SRafael J. Wysocki 
92a6220fc1SRafael J. Wysocki /**
93*38106313SRafael J. Wysocki  * cpuidle_enter_freeze - Enter an idle state suitable for suspend-to-idle.
94*38106313SRafael J. Wysocki  *
95*38106313SRafael J. Wysocki  * Find the deepest state available and enter it.
96*38106313SRafael J. Wysocki  */
97*38106313SRafael J. Wysocki void cpuidle_enter_freeze(void)
98*38106313SRafael J. Wysocki {
99*38106313SRafael J. Wysocki 	struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
100*38106313SRafael J. Wysocki 	struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
101*38106313SRafael J. Wysocki 	int index;
102*38106313SRafael J. Wysocki 
103*38106313SRafael J. Wysocki 	index = cpuidle_find_deepest_state(drv, dev);
104*38106313SRafael J. Wysocki 	if (index >= 0)
105*38106313SRafael J. Wysocki 		cpuidle_enter(drv, dev, index);
106*38106313SRafael J. Wysocki 	else
107*38106313SRafael J. Wysocki 		arch_cpu_idle();
108*38106313SRafael J. Wysocki 
109*38106313SRafael J. Wysocki 	/* Interrupts are enabled again here. */
110*38106313SRafael J. Wysocki 	local_irq_disable();
111*38106313SRafael J. Wysocki }
112*38106313SRafael J. Wysocki 
113*38106313SRafael J. Wysocki /**
11456cfbf74SColin Cross  * cpuidle_enter_state - enter the state and update stats
11556cfbf74SColin Cross  * @dev: cpuidle device for this cpu
11656cfbf74SColin Cross  * @drv: cpuidle driver for this cpu
11756cfbf74SColin Cross  * @next_state: index into drv->states of the state to enter
11856cfbf74SColin Cross  */
11956cfbf74SColin Cross int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
120554c06baSDaniel Lezcano 			int index)
12156cfbf74SColin Cross {
12256cfbf74SColin Cross 	int entered_state;
12356cfbf74SColin Cross 
124554c06baSDaniel Lezcano 	struct cpuidle_state *target_state = &drv->states[index];
125554c06baSDaniel Lezcano 	ktime_t time_start, time_end;
126554c06baSDaniel Lezcano 	s64 diff;
127554c06baSDaniel Lezcano 
12830fe6884SSandeep Tripathy 	trace_cpu_idle_rcuidle(index, dev->cpu);
129554c06baSDaniel Lezcano 	time_start = ktime_get();
130554c06baSDaniel Lezcano 
131554c06baSDaniel Lezcano 	entered_state = target_state->enter(dev, drv, index);
132554c06baSDaniel Lezcano 
133554c06baSDaniel Lezcano 	time_end = ktime_get();
13430fe6884SSandeep Tripathy 	trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
135554c06baSDaniel Lezcano 
1360b89e9aaSPaul Burton 	if (!cpuidle_state_is_coupled(dev, drv, entered_state))
137554c06baSDaniel Lezcano 		local_irq_enable();
138554c06baSDaniel Lezcano 
139554c06baSDaniel Lezcano 	diff = ktime_to_us(ktime_sub(time_end, time_start));
140554c06baSDaniel Lezcano 	if (diff > INT_MAX)
141554c06baSDaniel Lezcano 		diff = INT_MAX;
142554c06baSDaniel Lezcano 
143554c06baSDaniel Lezcano 	dev->last_residency = (int) diff;
14456cfbf74SColin Cross 
14556cfbf74SColin Cross 	if (entered_state >= 0) {
14656cfbf74SColin Cross 		/* Update cpuidle counters */
14756cfbf74SColin Cross 		/* This can be moved to within driver enter routine
14856cfbf74SColin Cross 		 * but that results in multiple copies of same code.
14956cfbf74SColin Cross 		 */
150a474a515SJulius Werner 		dev->states_usage[entered_state].time += dev->last_residency;
15156cfbf74SColin Cross 		dev->states_usage[entered_state].usage++;
15256cfbf74SColin Cross 	} else {
15356cfbf74SColin Cross 		dev->last_residency = 0;
15456cfbf74SColin Cross 	}
15556cfbf74SColin Cross 
15656cfbf74SColin Cross 	return entered_state;
15756cfbf74SColin Cross }
15856cfbf74SColin Cross 
15956cfbf74SColin Cross /**
160907e30f1SDaniel Lezcano  * cpuidle_select - ask the cpuidle framework to choose an idle state
1614f86d3a8SLen Brown  *
162907e30f1SDaniel Lezcano  * @drv: the cpuidle driver
163907e30f1SDaniel Lezcano  * @dev: the cpuidle device
164907e30f1SDaniel Lezcano  *
165907e30f1SDaniel Lezcano  * Returns the index of the idle state.
1664f86d3a8SLen Brown  */
167907e30f1SDaniel Lezcano int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
1684f86d3a8SLen Brown {
16952c324f8SRafael J. Wysocki 	if (off || !initialized)
17052c324f8SRafael J. Wysocki 		return -ENODEV;
17152c324f8SRafael J. Wysocki 
17252c324f8SRafael J. Wysocki 	if (!drv || !dev || !dev->enabled)
17352c324f8SRafael J. Wysocki 		return -EBUSY;
17452c324f8SRafael J. Wysocki 
175907e30f1SDaniel Lezcano 	return cpuidle_curr_governor->select(drv, dev);
176246eb7f0SKevin Hilman }
177246eb7f0SKevin Hilman 
178907e30f1SDaniel Lezcano /**
179907e30f1SDaniel Lezcano  * cpuidle_enter - enter into the specified idle state
180907e30f1SDaniel Lezcano  *
181907e30f1SDaniel Lezcano  * @drv:   the cpuidle driver tied with the cpu
182907e30f1SDaniel Lezcano  * @dev:   the cpuidle device
183907e30f1SDaniel Lezcano  * @index: the index in the idle state table
184907e30f1SDaniel Lezcano  *
185907e30f1SDaniel Lezcano  * Returns the index in the idle state, < 0 in case of error.
186907e30f1SDaniel Lezcano  * The error code depends on the backend driver
187907e30f1SDaniel Lezcano  */
188907e30f1SDaniel Lezcano int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev,
189907e30f1SDaniel Lezcano 		  int index)
190907e30f1SDaniel Lezcano {
191907e30f1SDaniel Lezcano 	if (cpuidle_state_is_coupled(dev, drv, index))
192907e30f1SDaniel Lezcano 		return cpuidle_enter_state_coupled(dev, drv, index);
193907e30f1SDaniel Lezcano 	return cpuidle_enter_state(dev, drv, index);
194907e30f1SDaniel Lezcano }
195fb11c9c6SViresh Kumar 
196907e30f1SDaniel Lezcano /**
197907e30f1SDaniel Lezcano  * cpuidle_reflect - tell the underlying governor what was the state
198907e30f1SDaniel Lezcano  * we were in
199907e30f1SDaniel Lezcano  *
200907e30f1SDaniel Lezcano  * @dev  : the cpuidle device
201907e30f1SDaniel Lezcano  * @index: the index in the idle state table
202907e30f1SDaniel Lezcano  *
203907e30f1SDaniel Lezcano  */
204907e30f1SDaniel Lezcano void cpuidle_reflect(struct cpuidle_device *dev, int index)
205907e30f1SDaniel Lezcano {
206*38106313SRafael J. Wysocki 	if (cpuidle_curr_governor->reflect)
207907e30f1SDaniel Lezcano 		cpuidle_curr_governor->reflect(dev, index);
2084f86d3a8SLen Brown }
2094f86d3a8SLen Brown 
2104f86d3a8SLen Brown /**
2114f86d3a8SLen Brown  * cpuidle_install_idle_handler - installs the cpuidle idle loop handler
2124f86d3a8SLen Brown  */
2134f86d3a8SLen Brown void cpuidle_install_idle_handler(void)
2144f86d3a8SLen Brown {
215a0bfa137SLen Brown 	if (enabled_devices) {
2164f86d3a8SLen Brown 		/* Make sure all changes finished before we switch to new idle */
2174f86d3a8SLen Brown 		smp_wmb();
218a0bfa137SLen Brown 		initialized = 1;
2194f86d3a8SLen Brown 	}
2204f86d3a8SLen Brown }
2214f86d3a8SLen Brown 
2224f86d3a8SLen Brown /**
2234f86d3a8SLen Brown  * cpuidle_uninstall_idle_handler - uninstalls the cpuidle idle loop handler
2244f86d3a8SLen Brown  */
2254f86d3a8SLen Brown void cpuidle_uninstall_idle_handler(void)
2264f86d3a8SLen Brown {
227a0bfa137SLen Brown 	if (enabled_devices) {
228a0bfa137SLen Brown 		initialized = 0;
2292ed903c5SChuansheng Liu 		wake_up_all_idle_cpus();
2304f86d3a8SLen Brown 	}
231442bf3aaSDaniel Lezcano 
232442bf3aaSDaniel Lezcano 	/*
233442bf3aaSDaniel Lezcano 	 * Make sure external observers (such as the scheduler)
234442bf3aaSDaniel Lezcano 	 * are done looking at pointed idle states.
235442bf3aaSDaniel Lezcano 	 */
236442bf3aaSDaniel Lezcano 	synchronize_rcu();
2374f86d3a8SLen Brown }
2384f86d3a8SLen Brown 
2394f86d3a8SLen Brown /**
2404f86d3a8SLen Brown  * cpuidle_pause_and_lock - temporarily disables CPUIDLE
2414f86d3a8SLen Brown  */
2424f86d3a8SLen Brown void cpuidle_pause_and_lock(void)
2434f86d3a8SLen Brown {
2444f86d3a8SLen Brown 	mutex_lock(&cpuidle_lock);
2454f86d3a8SLen Brown 	cpuidle_uninstall_idle_handler();
2464f86d3a8SLen Brown }
2474f86d3a8SLen Brown 
2484f86d3a8SLen Brown EXPORT_SYMBOL_GPL(cpuidle_pause_and_lock);
2494f86d3a8SLen Brown 
2504f86d3a8SLen Brown /**
2514f86d3a8SLen Brown  * cpuidle_resume_and_unlock - resumes CPUIDLE operation
2524f86d3a8SLen Brown  */
2534f86d3a8SLen Brown void cpuidle_resume_and_unlock(void)
2544f86d3a8SLen Brown {
2554f86d3a8SLen Brown 	cpuidle_install_idle_handler();
2564f86d3a8SLen Brown 	mutex_unlock(&cpuidle_lock);
2574f86d3a8SLen Brown }
2584f86d3a8SLen Brown 
2594f86d3a8SLen Brown EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
2604f86d3a8SLen Brown 
2618651f97bSPreeti U Murthy /* Currently used in suspend/resume path to suspend cpuidle */
2628651f97bSPreeti U Murthy void cpuidle_pause(void)
2638651f97bSPreeti U Murthy {
2648651f97bSPreeti U Murthy 	mutex_lock(&cpuidle_lock);
2658651f97bSPreeti U Murthy 	cpuidle_uninstall_idle_handler();
2668651f97bSPreeti U Murthy 	mutex_unlock(&cpuidle_lock);
2678651f97bSPreeti U Murthy }
2688651f97bSPreeti U Murthy 
2698651f97bSPreeti U Murthy /* Currently used in suspend/resume path to resume cpuidle */
2708651f97bSPreeti U Murthy void cpuidle_resume(void)
2718651f97bSPreeti U Murthy {
2728651f97bSPreeti U Murthy 	mutex_lock(&cpuidle_lock);
2738651f97bSPreeti U Murthy 	cpuidle_install_idle_handler();
2748651f97bSPreeti U Murthy 	mutex_unlock(&cpuidle_lock);
2758651f97bSPreeti U Murthy }
2768651f97bSPreeti U Murthy 
2774f86d3a8SLen Brown /**
2784f86d3a8SLen Brown  * cpuidle_enable_device - enables idle PM for a CPU
2794f86d3a8SLen Brown  * @dev: the CPU
2804f86d3a8SLen Brown  *
2814f86d3a8SLen Brown  * This function must be called between cpuidle_pause_and_lock and
2824f86d3a8SLen Brown  * cpuidle_resume_and_unlock when used externally.
2834f86d3a8SLen Brown  */
2844f86d3a8SLen Brown int cpuidle_enable_device(struct cpuidle_device *dev)
2854f86d3a8SLen Brown {
2865df0aa73SDaniel Lezcano 	int ret;
287bf4d1b5dSDaniel Lezcano 	struct cpuidle_driver *drv;
2884f86d3a8SLen Brown 
2891b0a0e9aSSrivatsa S. Bhat 	if (!dev)
2901b0a0e9aSSrivatsa S. Bhat 		return -EINVAL;
2911b0a0e9aSSrivatsa S. Bhat 
2924f86d3a8SLen Brown 	if (dev->enabled)
2934f86d3a8SLen Brown 		return 0;
294bf4d1b5dSDaniel Lezcano 
295bf4d1b5dSDaniel Lezcano 	drv = cpuidle_get_cpu_driver(dev);
296bf4d1b5dSDaniel Lezcano 
297e1689795SRobert Lee 	if (!drv || !cpuidle_curr_governor)
2984f86d3a8SLen Brown 		return -EIO;
299bf4d1b5dSDaniel Lezcano 
30010b9d3f8SDaniel Lezcano 	if (!dev->registered)
30110b9d3f8SDaniel Lezcano 		return -EINVAL;
30210b9d3f8SDaniel Lezcano 
3034f86d3a8SLen Brown 	if (!dev->state_count)
304fc850f39SDaniel Lezcano 		dev->state_count = drv->state_count;
3054f86d3a8SLen Brown 
306bf4d1b5dSDaniel Lezcano 	ret = cpuidle_add_device_sysfs(dev);
307bf4d1b5dSDaniel Lezcano 	if (ret)
3084f86d3a8SLen Brown 		return ret;
3094f86d3a8SLen Brown 
3104f86d3a8SLen Brown 	if (cpuidle_curr_governor->enable &&
311e1689795SRobert Lee 	    (ret = cpuidle_curr_governor->enable(drv, dev)))
3124f86d3a8SLen Brown 		goto fail_sysfs;
3134f86d3a8SLen Brown 
3144f86d3a8SLen Brown 	smp_wmb();
3154f86d3a8SLen Brown 
3164f86d3a8SLen Brown 	dev->enabled = 1;
3174f86d3a8SLen Brown 
3184f86d3a8SLen Brown 	enabled_devices++;
3194f86d3a8SLen Brown 	return 0;
3204f86d3a8SLen Brown 
3214f86d3a8SLen Brown fail_sysfs:
322bf4d1b5dSDaniel Lezcano 	cpuidle_remove_device_sysfs(dev);
3234f86d3a8SLen Brown 
3244f86d3a8SLen Brown 	return ret;
3254f86d3a8SLen Brown }
3264f86d3a8SLen Brown 
3274f86d3a8SLen Brown EXPORT_SYMBOL_GPL(cpuidle_enable_device);
3284f86d3a8SLen Brown 
3294f86d3a8SLen Brown /**
3304f86d3a8SLen Brown  * cpuidle_disable_device - disables idle PM for a CPU
3314f86d3a8SLen Brown  * @dev: the CPU
3324f86d3a8SLen Brown  *
3334f86d3a8SLen Brown  * This function must be called between cpuidle_pause_and_lock and
3344f86d3a8SLen Brown  * cpuidle_resume_and_unlock when used externally.
3354f86d3a8SLen Brown  */
3364f86d3a8SLen Brown void cpuidle_disable_device(struct cpuidle_device *dev)
3374f86d3a8SLen Brown {
338bf4d1b5dSDaniel Lezcano 	struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
339bf4d1b5dSDaniel Lezcano 
340cf31cd1aSSrivatsa S. Bhat 	if (!dev || !dev->enabled)
3414f86d3a8SLen Brown 		return;
342bf4d1b5dSDaniel Lezcano 
343bf4d1b5dSDaniel Lezcano 	if (!drv || !cpuidle_curr_governor)
3444f86d3a8SLen Brown 		return;
3454f86d3a8SLen Brown 
3464f86d3a8SLen Brown 	dev->enabled = 0;
3474f86d3a8SLen Brown 
3484f86d3a8SLen Brown 	if (cpuidle_curr_governor->disable)
349bf4d1b5dSDaniel Lezcano 		cpuidle_curr_governor->disable(drv, dev);
3504f86d3a8SLen Brown 
351bf4d1b5dSDaniel Lezcano 	cpuidle_remove_device_sysfs(dev);
3524f86d3a8SLen Brown 	enabled_devices--;
3534f86d3a8SLen Brown }
3544f86d3a8SLen Brown 
3554f86d3a8SLen Brown EXPORT_SYMBOL_GPL(cpuidle_disable_device);
3564f86d3a8SLen Brown 
357f6bb51a5SDaniel Lezcano static void __cpuidle_unregister_device(struct cpuidle_device *dev)
358f6bb51a5SDaniel Lezcano {
359f6bb51a5SDaniel Lezcano 	struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
360f6bb51a5SDaniel Lezcano 
361f6bb51a5SDaniel Lezcano 	list_del(&dev->device_list);
362f6bb51a5SDaniel Lezcano 	per_cpu(cpuidle_devices, dev->cpu) = NULL;
363f6bb51a5SDaniel Lezcano 	module_put(drv->owner);
364f6bb51a5SDaniel Lezcano }
365f6bb51a5SDaniel Lezcano 
366267d4bf8SViresh Kumar static void __cpuidle_device_init(struct cpuidle_device *dev)
3675df0aa73SDaniel Lezcano {
3685df0aa73SDaniel Lezcano 	memset(dev->states_usage, 0, sizeof(dev->states_usage));
3695df0aa73SDaniel Lezcano 	dev->last_residency = 0;
3705df0aa73SDaniel Lezcano }
3715df0aa73SDaniel Lezcano 
3724f86d3a8SLen Brown /**
373dcb84f33SVenkatesh Pallipadi  * __cpuidle_register_device - internal register function called before register
374dcb84f33SVenkatesh Pallipadi  * and enable routines
3754f86d3a8SLen Brown  * @dev: the cpu
376dcb84f33SVenkatesh Pallipadi  *
377dcb84f33SVenkatesh Pallipadi  * cpuidle_lock mutex must be held before this is called
3784f86d3a8SLen Brown  */
379dcb84f33SVenkatesh Pallipadi static int __cpuidle_register_device(struct cpuidle_device *dev)
3804f86d3a8SLen Brown {
3814f86d3a8SLen Brown 	int ret;
382bf4d1b5dSDaniel Lezcano 	struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
3834f86d3a8SLen Brown 
384bf4d1b5dSDaniel Lezcano 	if (!try_module_get(drv->owner))
3854f86d3a8SLen Brown 		return -EINVAL;
3864f86d3a8SLen Brown 
3874f86d3a8SLen Brown 	per_cpu(cpuidle_devices, dev->cpu) = dev;
3884f86d3a8SLen Brown 	list_add(&dev->device_list, &cpuidle_detected_devices);
3894f86d3a8SLen Brown 
3904126c019SColin Cross 	ret = cpuidle_coupled_register_device(dev);
39147182668SViresh Kumar 	if (ret)
392f6bb51a5SDaniel Lezcano 		__cpuidle_unregister_device(dev);
39347182668SViresh Kumar 	else
394dcb84f33SVenkatesh Pallipadi 		dev->registered = 1;
39547182668SViresh Kumar 
39647182668SViresh Kumar 	return ret;
397dcb84f33SVenkatesh Pallipadi }
398dcb84f33SVenkatesh Pallipadi 
399dcb84f33SVenkatesh Pallipadi /**
400dcb84f33SVenkatesh Pallipadi  * cpuidle_register_device - registers a CPU's idle PM feature
401dcb84f33SVenkatesh Pallipadi  * @dev: the cpu
402dcb84f33SVenkatesh Pallipadi  */
403dcb84f33SVenkatesh Pallipadi int cpuidle_register_device(struct cpuidle_device *dev)
404dcb84f33SVenkatesh Pallipadi {
405c878a52dSDaniel Lezcano 	int ret = -EBUSY;
406dcb84f33SVenkatesh Pallipadi 
4071b0a0e9aSSrivatsa S. Bhat 	if (!dev)
4081b0a0e9aSSrivatsa S. Bhat 		return -EINVAL;
4091b0a0e9aSSrivatsa S. Bhat 
410dcb84f33SVenkatesh Pallipadi 	mutex_lock(&cpuidle_lock);
411dcb84f33SVenkatesh Pallipadi 
412c878a52dSDaniel Lezcano 	if (dev->registered)
413c878a52dSDaniel Lezcano 		goto out_unlock;
414c878a52dSDaniel Lezcano 
415267d4bf8SViresh Kumar 	__cpuidle_device_init(dev);
4165df0aa73SDaniel Lezcano 
417f6bb51a5SDaniel Lezcano 	ret = __cpuidle_register_device(dev);
418f6bb51a5SDaniel Lezcano 	if (ret)
419f6bb51a5SDaniel Lezcano 		goto out_unlock;
420f6bb51a5SDaniel Lezcano 
421f6bb51a5SDaniel Lezcano 	ret = cpuidle_add_sysfs(dev);
422f6bb51a5SDaniel Lezcano 	if (ret)
423f6bb51a5SDaniel Lezcano 		goto out_unregister;
424dcb84f33SVenkatesh Pallipadi 
42510b9d3f8SDaniel Lezcano 	ret = cpuidle_enable_device(dev);
426f6bb51a5SDaniel Lezcano 	if (ret)
427f6bb51a5SDaniel Lezcano 		goto out_sysfs;
42810b9d3f8SDaniel Lezcano 
4294f86d3a8SLen Brown 	cpuidle_install_idle_handler();
4304f86d3a8SLen Brown 
431f6bb51a5SDaniel Lezcano out_unlock:
4324f86d3a8SLen Brown 	mutex_unlock(&cpuidle_lock);
4334f86d3a8SLen Brown 
434f6bb51a5SDaniel Lezcano 	return ret;
435f6bb51a5SDaniel Lezcano 
436f6bb51a5SDaniel Lezcano out_sysfs:
437f6bb51a5SDaniel Lezcano 	cpuidle_remove_sysfs(dev);
438f6bb51a5SDaniel Lezcano out_unregister:
439f6bb51a5SDaniel Lezcano 	__cpuidle_unregister_device(dev);
440f6bb51a5SDaniel Lezcano 	goto out_unlock;
4414f86d3a8SLen Brown }
4424f86d3a8SLen Brown 
4434f86d3a8SLen Brown EXPORT_SYMBOL_GPL(cpuidle_register_device);
4444f86d3a8SLen Brown 
4454f86d3a8SLen Brown /**
4464f86d3a8SLen Brown  * cpuidle_unregister_device - unregisters a CPU's idle PM feature
4474f86d3a8SLen Brown  * @dev: the cpu
4484f86d3a8SLen Brown  */
4494f86d3a8SLen Brown void cpuidle_unregister_device(struct cpuidle_device *dev)
4504f86d3a8SLen Brown {
451813e8e3dSKonrad Rzeszutek Wilk 	if (!dev || dev->registered == 0)
452dcb84f33SVenkatesh Pallipadi 		return;
453dcb84f33SVenkatesh Pallipadi 
4544f86d3a8SLen Brown 	cpuidle_pause_and_lock();
4554f86d3a8SLen Brown 
4564f86d3a8SLen Brown 	cpuidle_disable_device(dev);
4574f86d3a8SLen Brown 
4581aef40e2SDaniel Lezcano 	cpuidle_remove_sysfs(dev);
459f6bb51a5SDaniel Lezcano 
460f6bb51a5SDaniel Lezcano 	__cpuidle_unregister_device(dev);
4614f86d3a8SLen Brown 
4624126c019SColin Cross 	cpuidle_coupled_unregister_device(dev);
4634126c019SColin Cross 
4644f86d3a8SLen Brown 	cpuidle_resume_and_unlock();
4654f86d3a8SLen Brown }
4664f86d3a8SLen Brown 
4674f86d3a8SLen Brown EXPORT_SYMBOL_GPL(cpuidle_unregister_device);
4684f86d3a8SLen Brown 
4691c192d04SDaniel Lezcano /**
4704c637b21SDaniel Lezcano  * cpuidle_unregister: unregister a driver and the devices. This function
4714c637b21SDaniel Lezcano  * can be used only if the driver has been previously registered through
4724c637b21SDaniel Lezcano  * the cpuidle_register function.
4734c637b21SDaniel Lezcano  *
4744c637b21SDaniel Lezcano  * @drv: a valid pointer to a struct cpuidle_driver
4754c637b21SDaniel Lezcano  */
4764c637b21SDaniel Lezcano void cpuidle_unregister(struct cpuidle_driver *drv)
4774c637b21SDaniel Lezcano {
4784c637b21SDaniel Lezcano 	int cpu;
4794c637b21SDaniel Lezcano 	struct cpuidle_device *device;
4804c637b21SDaniel Lezcano 
48182467a5aSDaniel Lezcano 	for_each_cpu(cpu, drv->cpumask) {
4824c637b21SDaniel Lezcano 		device = &per_cpu(cpuidle_dev, cpu);
4834c637b21SDaniel Lezcano 		cpuidle_unregister_device(device);
4844c637b21SDaniel Lezcano 	}
4854c637b21SDaniel Lezcano 
4864c637b21SDaniel Lezcano 	cpuidle_unregister_driver(drv);
4874c637b21SDaniel Lezcano }
4884c637b21SDaniel Lezcano EXPORT_SYMBOL_GPL(cpuidle_unregister);
4894c637b21SDaniel Lezcano 
4904c637b21SDaniel Lezcano /**
4914c637b21SDaniel Lezcano  * cpuidle_register: registers the driver and the cpu devices with the
4924c637b21SDaniel Lezcano  * coupled_cpus passed as parameter. This function is used for all common
4934c637b21SDaniel Lezcano  * initialization pattern there are in the arch specific drivers. The
4944c637b21SDaniel Lezcano  * devices is globally defined in this file.
4954c637b21SDaniel Lezcano  *
4964c637b21SDaniel Lezcano  * @drv         : a valid pointer to a struct cpuidle_driver
4974c637b21SDaniel Lezcano  * @coupled_cpus: a cpumask for the coupled states
4984c637b21SDaniel Lezcano  *
4994c637b21SDaniel Lezcano  * Returns 0 on success, < 0 otherwise
5004c637b21SDaniel Lezcano  */
5014c637b21SDaniel Lezcano int cpuidle_register(struct cpuidle_driver *drv,
5024c637b21SDaniel Lezcano 		     const struct cpumask *const coupled_cpus)
5034c637b21SDaniel Lezcano {
5044c637b21SDaniel Lezcano 	int ret, cpu;
5054c637b21SDaniel Lezcano 	struct cpuidle_device *device;
5064c637b21SDaniel Lezcano 
5074c637b21SDaniel Lezcano 	ret = cpuidle_register_driver(drv);
5084c637b21SDaniel Lezcano 	if (ret) {
5094c637b21SDaniel Lezcano 		pr_err("failed to register cpuidle driver\n");
5104c637b21SDaniel Lezcano 		return ret;
5114c637b21SDaniel Lezcano 	}
5124c637b21SDaniel Lezcano 
51382467a5aSDaniel Lezcano 	for_each_cpu(cpu, drv->cpumask) {
5144c637b21SDaniel Lezcano 		device = &per_cpu(cpuidle_dev, cpu);
5154c637b21SDaniel Lezcano 		device->cpu = cpu;
5164c637b21SDaniel Lezcano 
5174c637b21SDaniel Lezcano #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
5184c637b21SDaniel Lezcano 		/*
519caf4a36eSViresh Kumar 		 * On multiplatform for ARM, the coupled idle states could be
5204c637b21SDaniel Lezcano 		 * enabled in the kernel even if the cpuidle driver does not
5214c637b21SDaniel Lezcano 		 * use it. Note, coupled_cpus is a struct copy.
5224c637b21SDaniel Lezcano 		 */
5234c637b21SDaniel Lezcano 		if (coupled_cpus)
5244c637b21SDaniel Lezcano 			device->coupled_cpus = *coupled_cpus;
5254c637b21SDaniel Lezcano #endif
5264c637b21SDaniel Lezcano 		ret = cpuidle_register_device(device);
5274c637b21SDaniel Lezcano 		if (!ret)
5284c637b21SDaniel Lezcano 			continue;
5294c637b21SDaniel Lezcano 
5304c637b21SDaniel Lezcano 		pr_err("Failed to register cpuidle device for cpu%d\n", cpu);
5314c637b21SDaniel Lezcano 
5324c637b21SDaniel Lezcano 		cpuidle_unregister(drv);
5334c637b21SDaniel Lezcano 		break;
5344c637b21SDaniel Lezcano 	}
5354c637b21SDaniel Lezcano 
5364c637b21SDaniel Lezcano 	return ret;
5374c637b21SDaniel Lezcano }
5384c637b21SDaniel Lezcano EXPORT_SYMBOL_GPL(cpuidle_register);
5394c637b21SDaniel Lezcano 
5404f86d3a8SLen Brown #ifdef CONFIG_SMP
5414f86d3a8SLen Brown 
5424f86d3a8SLen Brown /*
5434f86d3a8SLen Brown  * This function gets called when a part of the kernel has a new latency
5444f86d3a8SLen Brown  * requirement.  This means we need to get all processors out of their C-state,
5454f86d3a8SLen Brown  * and then recalculate a new suitable C-state. Just do a cross-cpu IPI; that
5464f86d3a8SLen Brown  * wakes them all right up.
5474f86d3a8SLen Brown  */
5484f86d3a8SLen Brown static int cpuidle_latency_notify(struct notifier_block *b,
5494f86d3a8SLen Brown 		unsigned long l, void *v)
5504f86d3a8SLen Brown {
5512ed903c5SChuansheng Liu 	wake_up_all_idle_cpus();
5524f86d3a8SLen Brown 	return NOTIFY_OK;
5534f86d3a8SLen Brown }
5544f86d3a8SLen Brown 
5554f86d3a8SLen Brown static struct notifier_block cpuidle_latency_notifier = {
5564f86d3a8SLen Brown 	.notifier_call = cpuidle_latency_notify,
5574f86d3a8SLen Brown };
5584f86d3a8SLen Brown 
559d82b3518SMark Gross static inline void latency_notifier_init(struct notifier_block *n)
560d82b3518SMark Gross {
561d82b3518SMark Gross 	pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY, n);
562d82b3518SMark Gross }
5634f86d3a8SLen Brown 
5644f86d3a8SLen Brown #else /* CONFIG_SMP */
5654f86d3a8SLen Brown 
5664f86d3a8SLen Brown #define latency_notifier_init(x) do { } while (0)
5674f86d3a8SLen Brown 
5684f86d3a8SLen Brown #endif /* CONFIG_SMP */
5694f86d3a8SLen Brown 
5704f86d3a8SLen Brown /**
5714f86d3a8SLen Brown  * cpuidle_init - core initializer
5724f86d3a8SLen Brown  */
5734f86d3a8SLen Brown static int __init cpuidle_init(void)
5744f86d3a8SLen Brown {
5754f86d3a8SLen Brown 	int ret;
5764f86d3a8SLen Brown 
57762027aeaSLen Brown 	if (cpuidle_disabled())
57862027aeaSLen Brown 		return -ENODEV;
57962027aeaSLen Brown 
5808a25a2fdSKay Sievers 	ret = cpuidle_add_interface(cpu_subsys.dev_root);
5814f86d3a8SLen Brown 	if (ret)
5824f86d3a8SLen Brown 		return ret;
5834f86d3a8SLen Brown 
5844f86d3a8SLen Brown 	latency_notifier_init(&cpuidle_latency_notifier);
5854f86d3a8SLen Brown 
5864f86d3a8SLen Brown 	return 0;
5874f86d3a8SLen Brown }
5884f86d3a8SLen Brown 
58962027aeaSLen Brown module_param(off, int, 0444);
5904f86d3a8SLen Brown core_initcall(cpuidle_init);
591