^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * ladder.c - the residency ladder algorithm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2004, 2005 Dominik Brodowski <linux@brodo.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Shaohua Li <shaohua.li@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Adam Belay <abelay@novell.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * This code is licenced under the GPL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/cpuidle.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/jiffies.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/tick.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define PROMOTION_COUNT 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define DEMOTION_COUNT 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct ladder_device_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) u32 promotion_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) u32 demotion_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) u64 promotion_time_ns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) u64 demotion_time_ns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) } threshold;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) int promotion_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) int demotion_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) } stats;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct ladder_device {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct ladder_device_state states[CPUIDLE_STATE_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static DEFINE_PER_CPU(struct ladder_device, ladder_devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * ladder_do_selection - prepares private data for a state change
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * @ldev: the ladder device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * @old_idx: the current state index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * @new_idx: the new target state index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static inline void ladder_do_selection(struct cpuidle_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) struct ladder_device *ldev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) int old_idx, int new_idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) ldev->states[old_idx].stats.promotion_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) ldev->states[old_idx].stats.demotion_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) dev->last_state_idx = new_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * ladder_select_state - selects the next state to enter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * @drv: cpuidle driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * @dev: the CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * @dummy: not used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static int ladder_select_state(struct cpuidle_driver *drv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) struct cpuidle_device *dev, bool *dummy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct ladder_device *ldev = this_cpu_ptr(&ladder_devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct ladder_device_state *last_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) int last_idx = dev->last_state_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) int first_idx = drv->states[0].flags & CPUIDLE_FLAG_POLLING ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) s64 latency_req = cpuidle_governor_latency_req(dev->cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) s64 last_residency;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) /* Special case when user has set very strict latency requirement */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (unlikely(latency_req == 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) ladder_do_selection(dev, ldev, last_idx, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) last_state = &ldev->states[last_idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) last_residency = dev->last_residency_ns - drv->states[last_idx].exit_latency_ns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) /* consider promotion */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (last_idx < drv->state_count - 1 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) !dev->states_usage[last_idx + 1].disable &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) last_residency > last_state->threshold.promotion_time_ns &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) drv->states[last_idx + 1].exit_latency_ns <= latency_req) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) last_state->stats.promotion_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) last_state->stats.demotion_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) ladder_do_selection(dev, ldev, last_idx, last_idx + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return last_idx + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /* consider demotion */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (last_idx > first_idx &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) (dev->states_usage[last_idx].disable ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) drv->states[last_idx].exit_latency_ns > latency_req)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) for (i = last_idx - 1; i > first_idx; i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (drv->states[i].exit_latency_ns <= latency_req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) ladder_do_selection(dev, ldev, last_idx, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (last_idx > first_idx &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) last_residency < last_state->threshold.demotion_time_ns) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) last_state->stats.demotion_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) last_state->stats.promotion_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (last_state->stats.demotion_count >= last_state->threshold.demotion_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) ladder_do_selection(dev, ldev, last_idx, last_idx - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return last_idx - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /* otherwise remain at the current state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) return last_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * ladder_enable_device - setup for the governor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * @drv: cpuidle driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * @dev: the CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static int ladder_enable_device(struct cpuidle_driver *drv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct cpuidle_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) int first_idx = drv->states[0].flags & CPUIDLE_FLAG_POLLING ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) struct ladder_device *ldev = &per_cpu(ladder_devices, dev->cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) struct ladder_device_state *lstate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) struct cpuidle_state *state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) dev->last_state_idx = first_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) for (i = first_idx; i < drv->state_count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) state = &drv->states[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) lstate = &ldev->states[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) lstate->stats.promotion_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) lstate->stats.demotion_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) lstate->threshold.promotion_count = PROMOTION_COUNT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) lstate->threshold.demotion_count = DEMOTION_COUNT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (i < drv->state_count - 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) lstate->threshold.promotion_time_ns = state->exit_latency_ns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (i > first_idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) lstate->threshold.demotion_time_ns = state->exit_latency_ns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * ladder_reflect - update the correct last_state_idx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * @dev: the CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * @index: the index of actual state entered
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static void ladder_reflect(struct cpuidle_device *dev, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (index > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) dev->last_state_idx = index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static struct cpuidle_governor ladder_governor = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) .name = "ladder",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .rating = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .enable = ladder_enable_device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) .select = ladder_select_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) .reflect = ladder_reflect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * init_ladder - initializes the governor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) static int __init init_ladder(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * When NO_HZ is disabled, or when booting with nohz=off, the ladder
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * governor is better so give it a higher rating than the menu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * governor.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (!tick_nohz_enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) ladder_governor.rating = 25;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return cpuidle_register_governor(&ladder_governor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) postcore_initcall(init_ladder);