From 80424c6f0d38ea3c869b6cb5bffb3f859e38cce9 Mon Sep 17 00:00:00 2001 From: Richard Raya Date: Wed, 29 May 2024 14:21:13 -0300 Subject: [PATCH] msm-4.14: Revert TEO cpuidle Change-Id: Ibfb8d0f59f5ce68e494a048bbccd621771f9cbed Signed-off-by: Richard Raya --- arch/arm64/configs/surya_defconfig | 3 +- drivers/cpuidle/Kconfig | 9 - drivers/cpuidle/cpuidle-powernv.c | 7 +- drivers/cpuidle/cpuidle.c | 16 +- drivers/cpuidle/governor.c | 19 +- drivers/cpuidle/governors/Makefile | 1 - drivers/cpuidle/governors/ladder.c | 4 +- drivers/cpuidle/governors/menu.c | 17 +- drivers/cpuidle/governors/teo.c | 534 ----------------------------- drivers/cpuidle/poll_state.c | 21 +- drivers/cpuidle/sysfs.c | 51 ++- include/linux/cpuidle.h | 5 - 12 files changed, 43 insertions(+), 644 deletions(-) delete mode 100644 drivers/cpuidle/governors/teo.c diff --git a/arch/arm64/configs/surya_defconfig b/arch/arm64/configs/surya_defconfig index bd07c12df4e1..a4b80bed137d 100644 --- a/arch/arm64/configs/surya_defconfig +++ b/arch/arm64/configs/surya_defconfig @@ -748,8 +748,7 @@ CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_CPU_IDLE=y CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y # CONFIG_CPU_IDLE_GOV_LADDER is not set -# CONFIG_CPU_IDLE_GOV_MENU is not set -CONFIG_CPU_IDLE_GOV_TEO=y +CONFIG_CPU_IDLE_GOV_MENU=y # # ARM CPU Idle Drivers diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index 3210e70225a8..cdf3e45fa942 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -21,15 +21,6 @@ config CPU_IDLE_GOV_LADDER config CPU_IDLE_GOV_MENU bool "Menu governor (for tickless system)" -config CPU_IDLE_GOV_TEO - bool "Timer events oriented (TEO) governor (for tickless systems)" - help - This governor implements a simplified idle state selection method - focused on timer events and does not do any interactivity boosting. - - Some workloads benefit from using it and it generally should be safe - to use. Say Y here if you are not happy with the alternatives. - config DT_IDLE_STATES bool diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c index 27dd0fa69eb6..1d7d5d121d55 100644 --- a/drivers/cpuidle/cpuidle-powernv.c +++ b/drivers/cpuidle/cpuidle-powernv.c @@ -56,10 +56,13 @@ static u64 get_snooze_timeout(struct cpuidle_device *dev, return default_snooze_timeout; for (i = index + 1; i < drv->state_count; i++) { - if (dev->states_usage[i].disable) + struct cpuidle_state *s = &drv->states[i]; + struct cpuidle_state_usage *su = &dev->states_usage[i]; + + if (s->disabled || su->disable) continue; - return drv->states[i].target_residency * tb_ticks_per_usec; + return s->target_residency * tb_ticks_per_usec; } return default_snooze_timeout; diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 5e6bb6f507fd..1b113dcccbb5 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -103,12 +103,12 @@ static int find_deepest_state(struct cpuidle_driver *drv, for (i = 1; i < drv->state_count; i++) { struct cpuidle_state *s = &drv->states[i]; + struct cpuidle_state_usage *su = &dev->states_usage[i]; - if (dev->states_usage[i].disable || - s->exit_latency <= latency_req || - s->exit_latency > max_latency || - (s->flags & forbidden_flags) || - (s2idle && !s->enter_s2idle)) + if (s->disabled || su->disable || s->exit_latency <= latency_req + || s->exit_latency > max_latency + || (s->flags & forbidden_flags) + || (s2idle && !s->enter_s2idle)) continue; latency_req = s->exit_latency; @@ -494,16 +494,12 @@ static void __cpuidle_device_init(struct cpuidle_device *dev) */ static int __cpuidle_register_device(struct cpuidle_device *dev) { + int ret; struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); - int i, ret; if (!try_module_get(drv->owner)) return -EINVAL; - for (i = 0; i < drv->state_count; i++) - if (drv->states[i].disabled) - dev->states_usage[i].disable |= CPUIDLE_STATE_DISABLED_BY_DRIVER; - per_cpu(cpuidle_devices, dev->cpu) = dev; list_add(&dev->device_list, &cpuidle_detected_devices); diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c index 86d492793a18..4e78263e34a4 100644 --- a/drivers/cpuidle/governor.c +++ b/drivers/cpuidle/governor.c @@ -8,10 +8,8 @@ * This code is licenced under the GPL. */ -#include -#include #include -#include +#include #include "cpuidle.h" @@ -94,18 +92,3 @@ int cpuidle_register_governor(struct cpuidle_governor *gov) return ret; } -EXPORT_SYMBOL_GPL(cpuidle_register_governor); - -/** - * cpuidle_governor_latency_req - Compute a latency constraint for CPU - * @cpu: Target CPU - */ -int cpuidle_governor_latency_req(unsigned int cpu) -{ - int global_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); - struct device *device = get_cpu_device(cpu); - int device_req = dev_pm_qos_raw_read_value(device); - - return device_req < global_req ? device_req : global_req; -} -EXPORT_SYMBOL_GPL(cpuidle_governor_latency_req); diff --git a/drivers/cpuidle/governors/Makefile b/drivers/cpuidle/governors/Makefile index 4d8aff5248a8..1b512722689f 100644 --- a/drivers/cpuidle/governors/Makefile +++ b/drivers/cpuidle/governors/Makefile @@ -4,4 +4,3 @@ obj-$(CONFIG_CPU_IDLE_GOV_LADDER) += ladder.o obj-$(CONFIG_CPU_IDLE_GOV_MENU) += menu.o -obj-$(CONFIG_CPU_IDLE_GOV_TEO) += teo.o diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index 8f1f8d45d33b..0213e07abe9c 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -85,6 +85,7 @@ static int ladder_select_state(struct cpuidle_driver *drv, /* consider promotion */ if (last_idx < drv->state_count - 1 && + !drv->states[last_idx + 1].disabled && !dev->states_usage[last_idx + 1].disable && last_residency > last_state->threshold.promotion_time && drv->states[last_idx + 1].exit_latency <= latency_req) { @@ -98,7 +99,8 @@ static int ladder_select_state(struct cpuidle_driver *drv, /* consider demotion */ if (last_idx > first_idx && - (dev->states_usage[last_idx].disable || + (drv->states[last_idx].disabled || + dev->states_usage[last_idx].disable || drv->states[last_idx].exit_latency > latency_req)) { int i; diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index d694f1358126..8698b8a4dead 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -332,6 +332,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) if (drv->states[0].flags & CPUIDLE_FLAG_POLLING) { struct cpuidle_state *s = &drv->states[1]; unsigned int polling_threshold; + /* * We want to default to C1 (hlt), not to busy polling * unless the timer is happening really really soon, or @@ -378,8 +379,9 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) idx = -1; for (i = first_idx; i < drv->state_count; i++) { struct cpuidle_state *s = &drv->states[i]; + struct cpuidle_state_usage *su = &dev->states_usage[i]; - if (dev->states_usage[i].disable) + if (s->disabled || su->disable) continue; if (idx == -1) idx = i; /* first enabled state */ @@ -442,7 +444,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) * tick, so try to correct that. */ for (i = idx - 1; i >= 0; i--) { - if (dev->states_usage[i].disable) + if (drv->states[i].disabled || + dev->states_usage[i].disable) continue; idx = i; @@ -514,16 +517,6 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) * duration predictor do a better job next time. */ measured_us = 9 * MAX_INTERESTING / 10; - } else if ((drv->states[last_idx].flags & CPUIDLE_FLAG_POLLING) && - dev->poll_time_limit) { - /* - * The CPU exited the "polling" state due to a time limit, so - * the idle duration prediction leading to the selection of that - * state was inaccurate. If a better prediction had been made, - * the CPU might have been woken up from idle by the next timer. - * Assume that to be the case. - */ - measured_us = data->next_timer_us; } else { /* measured value */ measured_us = cpuidle_get_last_residency(dev); diff --git a/drivers/cpuidle/governors/teo.c b/drivers/cpuidle/governors/teo.c deleted file mode 100644 index c1ba26f2e304..000000000000 --- a/drivers/cpuidle/governors/teo.c +++ /dev/null @@ -1,534 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Timer events oriented CPU idle governor - * - * Copyright (C) 2018 - 2021 Intel Corporation - * Author: Rafael J. Wysocki - * - * The idea of this governor is based on the observation that on many systems - * timer events are two or more orders of magnitude more frequent than any - * other interrupts, so they are likely to be the most significant cause of CPU - * wakeups from idle states. Moreover, information about what happened in the - * (relatively recent) past can be used to estimate whether or not the deepest - * idle state with target residency within the (known) time till the closest - * timer event, referred to as the sleep length, is likely to be suitable for - * the upcoming CPU idle period and, if not, then which of the shallower idle - * states to choose instead of it. - * - * Of course, non-timer wakeup sources are more important in some use cases - * which can be covered by taking a few most recent idle time intervals of the - * CPU into account. However, even in that context it is not necessary to - * consider idle duration values greater than the sleep length, because the - * closest timer will ultimately wake up the CPU anyway unless it is woken up - * earlier. - * - * Thus this governor estimates whether or not the prospective idle duration of - * a CPU is likely to be significantly shorter than the sleep length and selects - * an idle state for it accordingly. - * - * The computations carried out by this governor are based on using bins whose - * boundaries are aligned with the target residency parameter values of the CPU - * idle states provided by the cpuidle driver in the ascending order. That is, - * the first bin spans from 0 up to, but not including, the target residency of - * the second idle state (idle state 1), the second bin spans from the target - * residency of idle state 1 up to, but not including, the target residency of - * idle state 2, the third bin spans from the target residency of idle state 2 - * up to, but not including, the target residency of idle state 3 and so on. - * The last bin spans from the target residency of the deepest idle state - * supplied by the driver to infinity. - * - * Two metrics called "hits" and "intercepts" are associated with each bin. - * They are updated every time before selecting an idle state for the given CPU - * in accordance with what happened last time. - * - * The "hits" metric reflects the relative frequency of situations in which the - * sleep length and the idle duration measured after CPU wakeup fall into the - * same bin (that is, the CPU appears to wake up "on time" relative to the sleep - * length). In turn, the "intercepts" metric reflects the relative frequency of - * situations in which the measured idle duration is so much shorter than the - * sleep length that the bin it falls into corresponds to an idle state - * shallower than the one whose bin is fallen into by the sleep length (these - * situations are referred to as "intercepts" below). - * - * In addition to the metrics described above, the governor counts recent - * intercepts (that is, intercepts that have occurred during the last NR_RECENT - * invocations of it for the given CPU) for each bin. - * - * In order to select an idle state for a CPU, the governor takes the following - * steps (modulo the possible latency constraint that must be taken into account - * too): - * - * 1. Find the deepest CPU idle state whose target residency does not exceed - * the current sleep length (the candidate idle state) and compute 3 sums as - * follows: - * - * - The sum of the "hits" and "intercepts" metrics for the candidate state - * and all of the deeper idle states (it represents the cases in which the - * CPU was idle long enough to avoid being intercepted if the sleep length - * had been equal to the current one). - * - * - The sum of the "intercepts" metrics for all of the idle states shallower - * than the candidate one (it represents the cases in which the CPU was not - * idle long enough to avoid being intercepted if the sleep length had been - * equal to the current one). - * - * - The sum of the numbers of recent intercepts for all of the idle states - * shallower than the candidate one. - * - * 2. If the second sum is greater than the first one or the third sum is - * greater than NR_RECENT / 2, the CPU is likely to wake up early, so look - * for an alternative idle state to select. - * - * - Traverse the idle states shallower than the candidate one in the - * descending order. - * - * - For each of them compute the sum of the "intercepts" metrics and the sum - * of the numbers of recent intercepts over all of the idle states between - * it and the candidate one (including the former and excluding the - * latter). - * - * - If each of these sums that needs to be taken into account (because the - * check related to it has indicated that the CPU is likely to wake up - * early) is greater than a half of the corresponding sum computed in step - * 1 (which means that the target residency of the state in question had - * not exceeded the idle duration in over a half of the relevant cases), - * select the given idle state instead of the candidate one. - * - * 3. By default, select the candidate state. - */ - -#include -#include -#include -#include -#include - -/* - * The PULSE value is added to metrics when they grow and the DECAY_SHIFT value - * is used for decreasing metrics on a regular basis. - */ -#define PULSE 1024 -#define DECAY_SHIFT 3 - -/* - * Number of the most recent idle duration values to take into consideration for - * the detection of recent early wakeup patterns. - */ -#define NR_RECENT 9 - -/** - * struct teo_bin - Metrics used by the TEO cpuidle governor. - * @intercepts: The "intercepts" metric. - * @hits: The "hits" metric. - * @recent: The number of recent "intercepts". - */ -struct teo_bin { - unsigned int intercepts; - unsigned int hits; - unsigned int recent; -}; - -/** - * struct teo_cpu - CPU data used by the TEO cpuidle governor. - * @time_span_ns: Time between idle state selection and post-wakeup update. - * @sleep_length_ns: Time till the closest timer event (at the selection time). - * @state_bins: Idle state data bins for this CPU. - * @total: Grand total of the "intercepts" and "hits" mertics for all bins. - * @last_state: Idle state entered by the CPU last time. - * @next_recent_idx: Index of the next @recent_idx entry to update. - * @recent_idx: Indices of bins corresponding to recent "intercepts". - */ -struct teo_cpu { - s64 time_span_ns; - s64 sleep_length_ns; - struct teo_bin state_bins[CPUIDLE_STATE_MAX]; - unsigned int total; - int last_state; - int next_recent_idx; - int recent_idx[NR_RECENT]; -}; - -static DEFINE_PER_CPU(struct teo_cpu, teo_cpus); - -/** - * teo_update - Update CPU metrics after wakeup. - * @drv: cpuidle driver containing state data. - * @dev: Target CPU. - */ -static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) -{ - struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); - unsigned int sleep_length_us = ktime_to_us(cpu_data->sleep_length_ns); - int i, idx_timer = 0, idx_duration = 0; - unsigned int measured_us; - - if (cpu_data->time_span_ns >= cpu_data->sleep_length_ns) { - /* - * One of the safety nets has triggered or the wakeup was close - * enough to the closest timer event expected at the idle state - * selection time to be discarded. - */ - measured_us = UINT_MAX; - } else { - unsigned int lat = drv->states[cpu_data->last_state].exit_latency; - - /* - * The computations below are to determine whether or not the - * (saved) time till the next timer event and the measured idle - * duration fall into the same "bin", so use last_residency_ns - * for that instead of time_span_ns which includes the cpuidle - * overhead. - */ - measured_us = dev->last_residency; - - /* - * The delay between the wakeup and the first instruction - * executed by the CPU is not likely to be worst-case every - * time, so take 1/2 of the exit latency as a very rough - * approximation of the average of it. - */ - if (measured_us >= lat) - measured_us -= lat / 2; - else - measured_us /= 2; - } - - cpu_data->total = 0; - - /* - * Decay the "hits" and "intercepts" metrics for all of the bins and - * find the bins that the sleep length and the measured idle duration - * fall into. - */ - for (i = 0; i < drv->state_count; i++) { - int target_residency = drv->states[i].target_residency; - struct teo_bin *bin = &cpu_data->state_bins[i]; - - bin->hits -= bin->hits >> DECAY_SHIFT; - bin->intercepts -= bin->intercepts >> DECAY_SHIFT; - - cpu_data->total += bin->hits + bin->intercepts; - - if (target_residency <= sleep_length_us) { - idx_timer = i; - if (target_residency <= measured_us) - idx_duration = i; - } - } - - i = cpu_data->next_recent_idx++; - if (cpu_data->next_recent_idx >= NR_RECENT) - cpu_data->next_recent_idx = 0; - - if (cpu_data->recent_idx[i] >= 0) - cpu_data->state_bins[cpu_data->recent_idx[i]].recent--; - - /* - * If the measured idle duration falls into the same bin as the sleep - * length, this is a "hit", so update the "hits" metric for that bin. - * Otherwise, update the "intercepts" metric for the bin fallen into by - * the measured idle duration. - */ - if (idx_timer == idx_duration) { - cpu_data->state_bins[idx_timer].hits += PULSE; - cpu_data->recent_idx[i] = -1; - } else { - cpu_data->state_bins[idx_duration].intercepts += PULSE; - cpu_data->state_bins[idx_duration].recent++; - cpu_data->recent_idx[i] = idx_duration; - } - - cpu_data->total += PULSE; -} - -static bool teo_time_ok(unsigned int interval_us) -{ - return !tick_nohz_tick_stopped() || interval_us >= TICK_USEC; -} - -static unsigned int teo_middle_of_bin(int idx, struct cpuidle_driver *drv) -{ - return (drv->states[idx].target_residency + - drv->states[idx+1].target_residency) / 2; -} - -/** - * teo_find_shallower_state - Find shallower idle state matching given duration. - * @drv: cpuidle driver containing state data. - * @dev: Target CPU. - * @state_idx: Index of the capping idle state. - * @duration_us: Idle duration value to match. - * @no_poll: Don't consider polling states. - */ -static int teo_find_shallower_state(struct cpuidle_driver *drv, - struct cpuidle_device *dev, int state_idx, - int duration_us, bool no_poll) -{ - int i; - - for (i = state_idx - 1; i >= 0; i--) { - if (dev->states_usage[i].disable || - (no_poll && drv->states[i].flags & CPUIDLE_FLAG_POLLING)) - continue; - - state_idx = i; - if (drv->states[i].target_residency <= duration_us) - break; - } - return state_idx; -} - -/** - * teo_select - Selects the next idle state to enter. - * @drv: cpuidle driver containing state data. - * @dev: Target CPU. - */ -static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) -{ - struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); - int latency_req = cpuidle_governor_latency_req(dev->cpu); - unsigned int idx_intercept_sum = 0; - unsigned int intercept_sum = 0; - unsigned int idx_recent_sum = 0; - unsigned int recent_sum = 0; - unsigned int idx_hit_sum = 0; - unsigned int hit_sum = 0; - int constraint_idx = 0; - int idx0 = 0, idx = -1; - int i; - int duration_us; - bool alt_intercepts, alt_recent; - ktime_t delta_tick; - - if (cpu_data->last_state >= 0) { - teo_update(drv, dev); - cpu_data->last_state = -1; - } - - cpu_data->time_span_ns = local_clock(); - - cpu_data->sleep_length_ns = tick_nohz_get_sleep_length(&delta_tick); - duration_us = ktime_to_us(cpu_data->sleep_length_ns); - - /* Check if there is any choice in the first place. */ - if (drv->state_count < 2) { - idx = 0; - goto end; - } - if (!dev->states_usage[0].disable) { - idx = 0; - if (drv->states[1].target_residency > duration_us) - goto end; - } - - /* - * Find the deepest idle state whose target residency does not exceed - * the current sleep length and the deepest idle state not deeper than - * the former whose exit latency does not exceed the current latency - * constraint. Compute the sums of metrics for early wakeup pattern - * detection. - */ - for (i = 1; i < drv->state_count; i++) { - struct teo_bin *prev_bin = &cpu_data->state_bins[i-1]; - struct cpuidle_state *s = &drv->states[i]; - - /* - * Update the sums of idle state mertics for all of the states - * shallower than the current one. - */ - intercept_sum += prev_bin->intercepts; - hit_sum += prev_bin->hits; - recent_sum += prev_bin->recent; - - if (dev->states_usage[i].disable) - continue; - - if (idx < 0) { - idx = i; /* first enabled state */ - idx0 = i; - } - - if (s->target_residency > duration_us) - break; - - idx = i; - - if (s->exit_latency <= latency_req) - constraint_idx = i; - - idx_intercept_sum = intercept_sum; - idx_hit_sum = hit_sum; - idx_recent_sum = recent_sum; - } - - /* Avoid unnecessary overhead. */ - if (idx < 0) { - idx = 0; /* No states enabled, must use 0. */ - goto end; - } else if (idx == idx0) { - goto end; - } - - /* - * If the sum of the intercepts metric for all of the idle states - * shallower than the current candidate one (idx) is greater than the - * sum of the intercepts and hits metrics for the candidate state and - * all of the deeper states, or the sum of the numbers of recent - * intercepts over all of the states shallower than the candidate one - * is greater than a half of the number of recent events taken into - * account, the CPU is likely to wake up early, so find an alternative - * idle state to select. - */ - alt_intercepts = 2 * idx_intercept_sum > cpu_data->total - idx_hit_sum; - alt_recent = idx_recent_sum > NR_RECENT / 2; - if (alt_recent || alt_intercepts) { - s64 first_suitable_span_us = duration_us; - int first_suitable_idx = idx; - - /* - * Look for the deepest idle state whose target residency had - * not exceeded the idle duration in over a half of the relevant - * cases (both with respect to intercepts overall and with - * respect to the recent intercepts only) in the past. - * - * Take the possible latency constraint and duration limitation - * present if the tick has been stopped already into account. - */ - intercept_sum = 0; - recent_sum = 0; - - for (i = idx - 1; i >= 0; i--) { - struct teo_bin *bin = &cpu_data->state_bins[i]; - s64 span_us; - - intercept_sum += bin->intercepts; - recent_sum += bin->recent; - - span_us = teo_middle_of_bin(i, drv); - - if ((!alt_recent || 2 * recent_sum > idx_recent_sum) && - (!alt_intercepts || - 2 * intercept_sum > idx_intercept_sum)) { - if (teo_time_ok(span_us) && - !dev->states_usage[i].disable) { - idx = i; - duration_us = span_us; - } else { - /* - * The current state is too shallow or - * disabled, so take the first enabled - * deeper state with suitable time span. - */ - idx = first_suitable_idx; - duration_us = first_suitable_span_us; - } - break; - } - - if (dev->states_usage[i].disable) - continue; - - if (!teo_time_ok(span_us)) { - /* - * The current state is too shallow, but if an - * alternative candidate state has been found, - * it may still turn out to be a better choice. - */ - if (first_suitable_idx != idx) - continue; - - break; - } - - first_suitable_span_us = span_us; - first_suitable_idx = i; - } - } - - /* - * If there is a latency constraint, it may be necessary to select an - * idle state shallower than the current candidate one. - */ - if (idx > constraint_idx) - idx = constraint_idx; - -end: - /* - * Don't stop the tick if the selected state is a polling one or if the - * expected idle duration is shorter than the tick period length. - */ - if (((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) || - duration_us < TICK_USEC) && !tick_nohz_tick_stopped()) { - unsigned int delta_tick_us = ktime_to_us(delta_tick); - - /* - * The tick is not going to be stopped, so if the target - * residency of the state to be returned is not within the time - * till the closest timer including the tick, try to correct - * that. - */ - if (idx > idx0 && - drv->states[idx].target_residency > delta_tick_us) - idx = teo_find_shallower_state(drv, dev, idx, delta_tick_us, false); - } - - return idx; -} - -/** - * teo_reflect - Note that governor data for the CPU need to be updated. - * @dev: Target CPU. - * @state: Entered state. - */ -static void teo_reflect(struct cpuidle_device *dev, int state) -{ - struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); - - cpu_data->last_state = state; - /* - * If the wakeup was not "natural", but triggered by one of the safety - * nets, assume that the CPU might have been idle for the entire sleep - * length time. - */ - if (dev->poll_time_limit || - (tick_nohz_idle_got_tick() && cpu_data->sleep_length_ns > TICK_NSEC)) { - dev->poll_time_limit = false; - cpu_data->time_span_ns = cpu_data->sleep_length_ns; - } else { - cpu_data->time_span_ns = local_clock() - cpu_data->time_span_ns; - } -} - -/** - * teo_enable_device - Initialize the governor's data for the target CPU. - * @drv: cpuidle driver (not used). - * @dev: Target CPU. - */ -static int teo_enable_device(struct cpuidle_driver *drv, - struct cpuidle_device *dev) -{ - struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); - int i; - - memset(cpu_data, 0, sizeof(*cpu_data)); - - for (i = 0; i < NR_RECENT; i++) - cpu_data->recent_idx[i] = -1; - - return 0; -} - -static struct cpuidle_governor teo_governor = { - .name = "teo", - .rating = 50, - .enable = teo_enable_device, - .select = teo_select, - .reflect = teo_reflect, -}; - -static int __init teo_governor_init(void) -{ - return cpuidle_register_governor(&teo_governor); -} - -postcore_initcall(teo_governor_init); diff --git a/drivers/cpuidle/poll_state.c b/drivers/cpuidle/poll_state.c index 36ff5a1d9422..7416b16287de 100644 --- a/drivers/cpuidle/poll_state.c +++ b/drivers/cpuidle/poll_state.c @@ -6,34 +6,15 @@ #include #include -#include #include -#define POLL_IDLE_TIME_LIMIT (TICK_NSEC / 16) -#define POLL_IDLE_RELAX_COUNT 200 - static int __cpuidle poll_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - u64 time_start = local_clock(); - - dev->poll_time_limit = false; - local_irq_enable(); if (!current_set_polling_and_test()) { - unsigned int loop_count = 0; - - while (!need_resched()) { + while (!need_resched()) cpu_relax(); - if (loop_count++ < POLL_IDLE_RELAX_COUNT) - continue; - - loop_count = 0; - if (local_clock() - time_start > POLL_IDLE_TIME_LIMIT) { - dev->poll_time_limit = true; - break; - } - } } current_clr_polling(); diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index ebe13fa28ccf..a29d7a6e6848 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -255,6 +255,25 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, \ return sprintf(buf, "%u\n", state->_name);\ } +#define define_store_state_ull_function(_name) \ +static ssize_t store_state_##_name(struct cpuidle_state *state, \ + struct cpuidle_state_usage *state_usage, \ + const char *buf, size_t size) \ +{ \ + unsigned long long value; \ + int err; \ + if (!capable(CAP_SYS_ADMIN)) \ + return -EPERM; \ + err = kstrtoull(buf, 0, &value); \ + if (err) \ + return err; \ + if (value) \ + state_usage->_name = 1; \ + else \ + state_usage->_name = 0; \ + return size; \ +} + #define define_show_state_ull_function(_name) \ static ssize_t show_state_##_name(struct cpuidle_state *state, \ struct cpuidle_state_usage *state_usage, \ @@ -280,36 +299,8 @@ define_show_state_ull_function(usage) define_show_state_ull_function(time) define_show_state_str_function(name) define_show_state_str_function(desc) - -static ssize_t show_state_disable(struct cpuidle_state *state, - struct cpuidle_state_usage *state_usage, - char *buf) -{ - return sprintf(buf, "%llu\n", - state_usage->disable & CPUIDLE_STATE_DISABLED_BY_USER); -} - -static ssize_t store_state_disable(struct cpuidle_state *state, - struct cpuidle_state_usage *state_usage, - const char *buf, size_t size) -{ - unsigned int value; - int err; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - err = kstrtouint(buf, 0, &value); - if (err) - return err; - - if (value) - state_usage->disable |= CPUIDLE_STATE_DISABLED_BY_USER; - else - state_usage->disable &= ~CPUIDLE_STATE_DISABLED_BY_USER; - - return size; -} +define_show_state_ull_function(disable) +define_store_state_ull_function(disable) define_one_state_ro(name, show_state_name); define_one_state_ro(desc, show_state_desc); diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 16ea7f487a02..993f244a21a3 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -29,9 +29,6 @@ struct cpuidle_driver; * CPUIDLE DEVICE INTERFACE * ****************************/ -#define CPUIDLE_STATE_DISABLED_BY_USER BIT(0) -#define CPUIDLE_STATE_DISABLED_BY_DRIVER BIT(1) - struct cpuidle_state_usage { unsigned long long disable; unsigned long long usage; @@ -80,7 +77,6 @@ struct cpuidle_device { unsigned int registered:1; unsigned int enabled:1; unsigned int use_deepest_state:1; - unsigned int poll_time_limit:1; unsigned int cpu; int last_residency; @@ -256,7 +252,6 @@ struct cpuidle_governor { #ifdef CONFIG_CPU_IDLE extern int cpuidle_register_governor(struct cpuidle_governor *gov); -extern int cpuidle_governor_latency_req(unsigned int cpu); #else static inline int cpuidle_register_governor(struct cpuidle_governor *gov) {return 0;}