xref: /linux/drivers/cpuidle/poll_state.c (revision c3bdd5e65185f46150b3bac103b3854040487857)
134c2f65bSRafael J. Wysocki /*
234c2f65bSRafael J. Wysocki  * poll_state.c - Polling idle state
334c2f65bSRafael J. Wysocki  *
434c2f65bSRafael J. Wysocki  * This file is released under the GPLv2.
534c2f65bSRafael J. Wysocki  */
634c2f65bSRafael J. Wysocki 
734c2f65bSRafael J. Wysocki #include <linux/cpuidle.h>
834c2f65bSRafael J. Wysocki #include <linux/sched.h>
9a37b969aSRafael J. Wysocki #include <linux/sched/clock.h>
1034c2f65bSRafael J. Wysocki #include <linux/sched/idle.h>
1134c2f65bSRafael J. Wysocki 
124dc2375cSRafael J. Wysocki #define POLL_IDLE_RELAX_COUNT	200
13a37b969aSRafael J. Wysocki 
1434c2f65bSRafael J. Wysocki static int __cpuidle poll_idle(struct cpuidle_device *dev,
1534c2f65bSRafael J. Wysocki 			       struct cpuidle_driver *drv, int index)
1634c2f65bSRafael J. Wysocki {
17a37b969aSRafael J. Wysocki 	u64 time_start = local_clock();
18a37b969aSRafael J. Wysocki 
195f26bdceSRafael J. Wysocki 	dev->poll_time_limit = false;
205f26bdceSRafael J. Wysocki 
2134c2f65bSRafael J. Wysocki 	local_irq_enable();
2234c2f65bSRafael J. Wysocki 	if (!current_set_polling_and_test()) {
234dc2375cSRafael J. Wysocki 		unsigned int loop_count = 0;
24*1617971cSDoug Smythies 		u64 limit = TICK_NSEC;
25800fb34aSRafael J. Wysocki 		int i;
26800fb34aSRafael J. Wysocki 
27800fb34aSRafael J. Wysocki 		for (i = 1; i < drv->state_count; i++) {
28800fb34aSRafael J. Wysocki 			if (drv->states[i].disabled || dev->states_usage[i].disable)
29800fb34aSRafael J. Wysocki 				continue;
30800fb34aSRafael J. Wysocki 
31800fb34aSRafael J. Wysocki 			limit = (u64)drv->states[i].target_residency * NSEC_PER_USEC;
32800fb34aSRafael J. Wysocki 			break;
33800fb34aSRafael J. Wysocki 		}
344dc2375cSRafael J. Wysocki 
35a37b969aSRafael J. Wysocki 		while (!need_resched()) {
3634c2f65bSRafael J. Wysocki 			cpu_relax();
374dc2375cSRafael J. Wysocki 			if (loop_count++ < POLL_IDLE_RELAX_COUNT)
384dc2375cSRafael J. Wysocki 				continue;
39a37b969aSRafael J. Wysocki 
404dc2375cSRafael J. Wysocki 			loop_count = 0;
4101bad1c6SRafael J. Wysocki 			if (local_clock() - time_start > limit) {
425f26bdceSRafael J. Wysocki 				dev->poll_time_limit = true;
43a37b969aSRafael J. Wysocki 				break;
44a37b969aSRafael J. Wysocki 			}
4534c2f65bSRafael J. Wysocki 		}
465f26bdceSRafael J. Wysocki 	}
4734c2f65bSRafael J. Wysocki 	current_clr_polling();
4834c2f65bSRafael J. Wysocki 
4934c2f65bSRafael J. Wysocki 	return index;
5034c2f65bSRafael J. Wysocki }
5134c2f65bSRafael J. Wysocki 
521b39e3f8SRafael J. Wysocki void cpuidle_poll_state_init(struct cpuidle_driver *drv)
5334c2f65bSRafael J. Wysocki {
5434c2f65bSRafael J. Wysocki 	struct cpuidle_state *state = &drv->states[0];
5534c2f65bSRafael J. Wysocki 
5634c2f65bSRafael J. Wysocki 	snprintf(state->name, CPUIDLE_NAME_LEN, "POLL");
5734c2f65bSRafael J. Wysocki 	snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
5834c2f65bSRafael J. Wysocki 	state->exit_latency = 0;
5934c2f65bSRafael J. Wysocki 	state->target_residency = 0;
6034c2f65bSRafael J. Wysocki 	state->power_usage = -1;
6134c2f65bSRafael J. Wysocki 	state->enter = poll_idle;
6234c2f65bSRafael J. Wysocki 	state->disabled = false;
6334c2f65bSRafael J. Wysocki 	state->flags = CPUIDLE_FLAG_POLLING;
6434c2f65bSRafael J. Wysocki }
651b39e3f8SRafael J. Wysocki EXPORT_SYMBOL_GPL(cpuidle_poll_state_init);
66