Path: blob/master/drivers/cpuidle/governors/ladder.c
15111 views
/*1* ladder.c - the residency ladder algorithm2*3* Copyright (C) 2001, 2002 Andy Grover <[email protected]>4* Copyright (C) 2001, 2002 Paul Diefenbaugh <[email protected]>5* Copyright (C) 2004, 2005 Dominik Brodowski <[email protected]>6*7* (C) 2006-2007 Venkatesh Pallipadi <[email protected]>8* Shaohua Li <[email protected]>9* Adam Belay <[email protected]>10*11* This code is licenced under the GPL.12*/1314#include <linux/kernel.h>15#include <linux/cpuidle.h>16#include <linux/pm_qos_params.h>17#include <linux/moduleparam.h>18#include <linux/jiffies.h>1920#include <asm/io.h>21#include <asm/uaccess.h>2223#define PROMOTION_COUNT 424#define DEMOTION_COUNT 12526struct ladder_device_state {27struct {28u32 promotion_count;29u32 demotion_count;30u32 promotion_time;31u32 demotion_time;32} threshold;33struct {34int promotion_count;35int demotion_count;36} stats;37};3839struct ladder_device {40struct ladder_device_state states[CPUIDLE_STATE_MAX];41int last_state_idx;42};4344static DEFINE_PER_CPU(struct ladder_device, ladder_devices);4546/**47* ladder_do_selection - prepares private data for a state change48* @ldev: the ladder device49* @old_idx: the current state index50* @new_idx: the new target state index51*/52static inline void ladder_do_selection(struct ladder_device *ldev,53int old_idx, int new_idx)54{55ldev->states[old_idx].stats.promotion_count = 0;56ldev->states[old_idx].stats.demotion_count = 0;57ldev->last_state_idx = new_idx;58}5960/**61* ladder_select_state - selects the next state to enter62* @dev: the CPU63*/64static int ladder_select_state(struct cpuidle_device *dev)65{66struct ladder_device *ldev = &__get_cpu_var(ladder_devices);67struct ladder_device_state *last_state;68int last_residency, last_idx = ldev->last_state_idx;69int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);7071/* Special case when user has set very strict latency requirement */72if (unlikely(latency_req == 0)) {73ladder_do_selection(ldev, last_idx, 0);74return 0;75}7677last_state = &ldev->states[last_idx];7879if (dev->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID)80last_residency = cpuidle_get_last_residency(dev) - dev->states[last_idx].exit_latency;81else82last_residency = last_state->threshold.promotion_time + 1;8384/* consider promotion */85if (last_idx < dev->state_count - 1 &&86last_residency > last_state->threshold.promotion_time &&87dev->states[last_idx + 1].exit_latency <= latency_req) {88last_state->stats.promotion_count++;89last_state->stats.demotion_count = 0;90if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) {91ladder_do_selection(ldev, last_idx, last_idx + 1);92return last_idx + 1;93}94}9596/* consider demotion */97if (last_idx > CPUIDLE_DRIVER_STATE_START &&98dev->states[last_idx].exit_latency > latency_req) {99int i;100101for (i = last_idx - 1; i > CPUIDLE_DRIVER_STATE_START; i--) {102if (dev->states[i].exit_latency <= latency_req)103break;104}105ladder_do_selection(ldev, last_idx, i);106return i;107}108109if (last_idx > CPUIDLE_DRIVER_STATE_START &&110last_residency < last_state->threshold.demotion_time) {111last_state->stats.demotion_count++;112last_state->stats.promotion_count = 0;113if (last_state->stats.demotion_count >= last_state->threshold.demotion_count) {114ladder_do_selection(ldev, last_idx, last_idx - 1);115return last_idx - 1;116}117}118119/* otherwise remain at the current state */120return last_idx;121}122123/**124* ladder_enable_device - setup for the governor125* @dev: the CPU126*/127static int ladder_enable_device(struct cpuidle_device *dev)128{129int i;130struct ladder_device *ldev = &per_cpu(ladder_devices, dev->cpu);131struct ladder_device_state *lstate;132struct cpuidle_state *state;133134ldev->last_state_idx = CPUIDLE_DRIVER_STATE_START;135136for (i = 0; i < dev->state_count; i++) {137state = &dev->states[i];138lstate = &ldev->states[i];139140lstate->stats.promotion_count = 0;141lstate->stats.demotion_count = 0;142143lstate->threshold.promotion_count = PROMOTION_COUNT;144lstate->threshold.demotion_count = DEMOTION_COUNT;145146if (i < dev->state_count - 1)147lstate->threshold.promotion_time = state->exit_latency;148if (i > 0)149lstate->threshold.demotion_time = state->exit_latency;150}151152return 0;153}154155static struct cpuidle_governor ladder_governor = {156.name = "ladder",157.rating = 10,158.enable = ladder_enable_device,159.select = ladder_select_state,160.owner = THIS_MODULE,161};162163/**164* init_ladder - initializes the governor165*/166static int __init init_ladder(void)167{168return cpuidle_register_governor(&ladder_governor);169}170171/**172* exit_ladder - exits the governor173*/174static void __exit exit_ladder(void)175{176cpuidle_unregister_governor(&ladder_governor);177}178179MODULE_LICENSE("GPL");180module_init(init_ladder);181module_exit(exit_ladder);182183184