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