^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * intel_powerclamp.c - package c-state idle injection
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2012, Intel Corporation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Authors:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Arjan van de Ven <arjan@linux.intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Jacob Pan <jacob.jun.pan@linux.intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * TODO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * 1. better handle wakeup from external interrupts, currently a fixed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * compensation is added to clamping duration when excessive amount
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * of wakeups are observed during idle time. the reason is that in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * case of external interrupts without need for ack, clamping down
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * cpu in non-irq context does not reduce irq. for majority of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * cases, clamping down cpu does help reduce irq as well, we should
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * be able to differentiate the two cases and give a quantitative
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * solution for the irqs that we can control. perhaps based on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * get_cpu_iowait_time_us()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * 2. synchronization with other hw blocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/kthread.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/thermal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/tick.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/debugfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/sched/rt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <uapi/linux/sched/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <asm/nmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <asm/msr.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <asm/mwait.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <asm/cpu_device_id.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <asm/hardirq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define MAX_TARGET_RATIO (50U)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /* For each undisturbed clamping period (no extra wake ups during idle time),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * we increment the confidence counter for the given target ratio.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * CONFIDENCE_OK defines the level where runtime calibration results are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * valid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define CONFIDENCE_OK (3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) /* Default idle injection duration, driver adjust sleep time to meet target
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * idle ratio. Similar to frequency modulation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define DEFAULT_DURATION_JIFFIES (6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static unsigned int target_mwait;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static struct dentry *debug_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) /* user selected target */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static unsigned int set_target_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static unsigned int current_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static bool should_skip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static bool reduce_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static atomic_t idle_wakeup_counter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static unsigned int control_cpu; /* The cpu assigned to collect stat and update
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * control parameters. default to BSP but BSP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * can be offlined.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static bool clamping;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct powerclamp_worker_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) struct kthread_worker *worker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct kthread_work balancing_work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct kthread_delayed_work idle_injection_work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) unsigned int cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) unsigned int count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) unsigned int guard;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) unsigned int window_size_now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) unsigned int target_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) unsigned int duration_jiffies;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) bool clamping;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static struct powerclamp_worker_data __percpu *worker_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static struct thermal_cooling_device *cooling_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static unsigned long *cpu_clamping_mask; /* bit map for tracking per cpu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * clamping kthread worker
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static unsigned int duration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static unsigned int pkg_cstate_ratio_cur;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static unsigned int window_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static int duration_set(const char *arg, const struct kernel_param *kp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) unsigned long new_duration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) ret = kstrtoul(arg, 10, &new_duration);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (new_duration > 25 || new_duration < 6) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) pr_err("Out of recommended range %lu, between 6-25ms\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) new_duration);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) duration = clamp(new_duration, 6ul, 25ul);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) smp_mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static const struct kernel_param_ops duration_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) .set = duration_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) .get = param_get_int,
^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)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) module_param_cb(duration, &duration_ops, &duration, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) MODULE_PARM_DESC(duration, "forced idle time for each attempt in msec.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) struct powerclamp_calibration_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) unsigned long confidence; /* used for calibration, basically a counter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * gets incremented each time a clamping
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * period is completed without extra wakeups
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * once that counter is reached given level,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * compensation is deemed usable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) unsigned long steady_comp; /* steady state compensation used when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * no extra wakeups occurred.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) unsigned long dynamic_comp; /* compensate excessive wakeup from idle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * mostly from external interrupts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) static struct powerclamp_calibration_data cal_data[MAX_TARGET_RATIO];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static int window_size_set(const char *arg, const struct kernel_param *kp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) unsigned long new_window_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) ret = kstrtoul(arg, 10, &new_window_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) goto exit_win;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (new_window_size > 10 || new_window_size < 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) pr_err("Out of recommended window size %lu, between 2-10\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) new_window_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) window_size = clamp(new_window_size, 2ul, 10ul);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) smp_mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) exit_win:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) static const struct kernel_param_ops window_size_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .set = window_size_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .get = param_get_int,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) module_param_cb(window_size, &window_size_ops, &window_size, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) MODULE_PARM_DESC(window_size, "sliding window in number of clamping cycles\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) "\tpowerclamp controls idle ratio within this window. larger\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) "\twindow size results in slower response time but more smooth\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) "\tclamping results. default to 2.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) static void find_target_mwait(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) unsigned int eax, ebx, ecx, edx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) unsigned int highest_cstate = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) unsigned int highest_subcstate = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) !(ecx & CPUID5_ECX_INTERRUPT_BREAK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) edx >>= MWAIT_SUBSTATE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) for (i = 0; i < 7 && edx; i++, edx >>= MWAIT_SUBSTATE_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (edx & MWAIT_SUBSTATE_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) highest_cstate = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) highest_subcstate = edx & MWAIT_SUBSTATE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) target_mwait = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) (highest_subcstate - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) struct pkg_cstate_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) bool skip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) int msr_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) int cstate_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) #define PKG_CSTATE_INIT(id) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) .msr_index = MSR_PKG_C##id##_RESIDENCY, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) .cstate_id = id \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) static struct pkg_cstate_info pkg_cstates[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) PKG_CSTATE_INIT(2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) PKG_CSTATE_INIT(3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) PKG_CSTATE_INIT(6),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) PKG_CSTATE_INIT(7),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) PKG_CSTATE_INIT(8),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) PKG_CSTATE_INIT(9),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) PKG_CSTATE_INIT(10),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) {NULL},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) static bool has_pkg_state_counter(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) u64 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) struct pkg_cstate_info *info = pkg_cstates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) /* check if any one of the counter msrs exists */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) while (info->msr_index) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (!rdmsrl_safe(info->msr_index, &val))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) info++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) static u64 pkg_state_counter(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) u64 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) u64 count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) struct pkg_cstate_info *info = pkg_cstates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) while (info->msr_index) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) if (!info->skip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (!rdmsrl_safe(info->msr_index, &val))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) count += val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) info->skip = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) info++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) static unsigned int get_compensation(int ratio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) unsigned int comp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) /* we only use compensation if all adjacent ones are good */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (ratio == 1 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) cal_data[ratio].confidence >= CONFIDENCE_OK &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) cal_data[ratio + 1].confidence >= CONFIDENCE_OK &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) cal_data[ratio + 2].confidence >= CONFIDENCE_OK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) comp = (cal_data[ratio].steady_comp +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) cal_data[ratio + 1].steady_comp +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) cal_data[ratio + 2].steady_comp) / 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) } else if (ratio == MAX_TARGET_RATIO - 1 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) cal_data[ratio].confidence >= CONFIDENCE_OK &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) cal_data[ratio - 1].confidence >= CONFIDENCE_OK &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) cal_data[ratio - 2].confidence >= CONFIDENCE_OK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) comp = (cal_data[ratio].steady_comp +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) cal_data[ratio - 1].steady_comp +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) cal_data[ratio - 2].steady_comp) / 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) } else if (cal_data[ratio].confidence >= CONFIDENCE_OK &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) cal_data[ratio - 1].confidence >= CONFIDENCE_OK &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) cal_data[ratio + 1].confidence >= CONFIDENCE_OK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) comp = (cal_data[ratio].steady_comp +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) cal_data[ratio - 1].steady_comp +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) cal_data[ratio + 1].steady_comp) / 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) /* REVISIT: simple penalty of double idle injection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) if (reduce_irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) comp = ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) /* do not exceed limit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (comp + ratio >= MAX_TARGET_RATIO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) comp = MAX_TARGET_RATIO - ratio - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) return comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) static void adjust_compensation(int target_ratio, unsigned int win)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) int delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) struct powerclamp_calibration_data *d = &cal_data[target_ratio];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) * adjust compensations if confidence level has not been reached or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) * there are too many wakeups during the last idle injection period, we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) * cannot trust the data for compensation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (d->confidence >= CONFIDENCE_OK ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) atomic_read(&idle_wakeup_counter) >
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) win * num_online_cpus())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) delta = set_target_ratio - current_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) /* filter out bad data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if (delta >= 0 && delta <= (1+target_ratio/10)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) if (d->steady_comp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) d->steady_comp =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) roundup(delta+d->steady_comp, 2)/2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) d->steady_comp = delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) d->confidence++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) static bool powerclamp_adjust_controls(unsigned int target_ratio,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) unsigned int guard, unsigned int win)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) static u64 msr_last, tsc_last;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) u64 msr_now, tsc_now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) u64 val64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) /* check result for the last window */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) msr_now = pkg_state_counter();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) tsc_now = rdtsc();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) /* calculate pkg cstate vs tsc ratio */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (!msr_last || !tsc_last)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) current_ratio = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) else if (tsc_now-tsc_last) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) val64 = 100*(msr_now-msr_last);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) do_div(val64, (tsc_now-tsc_last));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) current_ratio = val64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) /* update record */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) msr_last = msr_now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) tsc_last = tsc_now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) adjust_compensation(target_ratio, win);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) * too many external interrupts, set flag such
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) * that we can take measure later.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) reduce_irq = atomic_read(&idle_wakeup_counter) >=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 2 * win * num_online_cpus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) atomic_set(&idle_wakeup_counter, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) /* if we are above target+guard, skip */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return set_target_ratio + guard <= current_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) static void clamp_balancing_func(struct kthread_work *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) struct powerclamp_worker_data *w_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) int sleeptime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) unsigned long target_jiffies;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) unsigned int compensated_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) int interval; /* jiffies to sleep for each attempt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) w_data = container_of(work, struct powerclamp_worker_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) balancing_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) * make sure user selected ratio does not take effect until
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) * the next round. adjust target_ratio if user has changed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) * target such that we can converge quickly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) w_data->target_ratio = READ_ONCE(set_target_ratio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) w_data->guard = 1 + w_data->target_ratio / 20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) w_data->window_size_now = window_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) w_data->duration_jiffies = msecs_to_jiffies(duration);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) w_data->count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) * systems may have different ability to enter package level
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) * c-states, thus we need to compensate the injected idle ratio
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * to achieve the actual target reported by the HW.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) compensated_ratio = w_data->target_ratio +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) get_compensation(w_data->target_ratio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) if (compensated_ratio <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) compensated_ratio = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) interval = w_data->duration_jiffies * 100 / compensated_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) /* align idle time */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) target_jiffies = roundup(jiffies, interval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) sleeptime = target_jiffies - jiffies;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) if (sleeptime <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) sleeptime = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (clamping && w_data->clamping && cpu_online(w_data->cpu))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) kthread_queue_delayed_work(w_data->worker,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) &w_data->idle_injection_work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) sleeptime);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) static void clamp_idle_injection_func(struct kthread_work *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) struct powerclamp_worker_data *w_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) w_data = container_of(work, struct powerclamp_worker_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) idle_injection_work.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) * only elected controlling cpu can collect stats and update
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) * control parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) if (w_data->cpu == control_cpu &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) !(w_data->count % w_data->window_size_now)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) should_skip =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) powerclamp_adjust_controls(w_data->target_ratio,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) w_data->guard,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) w_data->window_size_now);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) smp_mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) if (should_skip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) goto balance;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) play_idle(jiffies_to_usecs(w_data->duration_jiffies));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) balance:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (clamping && w_data->clamping && cpu_online(w_data->cpu))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) kthread_queue_work(w_data->worker, &w_data->balancing_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * 1 HZ polling while clamping is active, useful for userspace
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) * to monitor actual idle ratio.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) static void poll_pkg_cstate(struct work_struct *dummy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) static DECLARE_DELAYED_WORK(poll_pkg_cstate_work, poll_pkg_cstate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) static void poll_pkg_cstate(struct work_struct *dummy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) static u64 msr_last;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) static u64 tsc_last;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) u64 msr_now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) u64 tsc_now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) u64 val64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) msr_now = pkg_state_counter();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) tsc_now = rdtsc();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) /* calculate pkg cstate vs tsc ratio */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) if (!msr_last || !tsc_last)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) pkg_cstate_ratio_cur = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if (tsc_now - tsc_last) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) val64 = 100 * (msr_now - msr_last);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) do_div(val64, (tsc_now - tsc_last));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) pkg_cstate_ratio_cur = val64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) /* update record */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) msr_last = msr_now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) tsc_last = tsc_now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) if (true == clamping)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) schedule_delayed_work(&poll_pkg_cstate_work, HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) static void start_power_clamp_worker(unsigned long cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) struct powerclamp_worker_data *w_data = per_cpu_ptr(worker_data, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) struct kthread_worker *worker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) worker = kthread_create_worker_on_cpu(cpu, 0, "kidle_inj/%ld", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if (IS_ERR(worker))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) w_data->worker = worker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) w_data->count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) w_data->cpu = cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) w_data->clamping = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) set_bit(cpu, cpu_clamping_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) sched_set_fifo(worker->task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) kthread_init_work(&w_data->balancing_work, clamp_balancing_func);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) kthread_init_delayed_work(&w_data->idle_injection_work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) clamp_idle_injection_func);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) kthread_queue_work(w_data->worker, &w_data->balancing_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) static void stop_power_clamp_worker(unsigned long cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) struct powerclamp_worker_data *w_data = per_cpu_ptr(worker_data, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (!w_data->worker)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) w_data->clamping = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) * Make sure that all works that get queued after this point see
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) * the clamping disabled. The counter part is not needed because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) * there is an implicit memory barrier when the queued work
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) * is proceed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) smp_wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) kthread_cancel_work_sync(&w_data->balancing_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) kthread_cancel_delayed_work_sync(&w_data->idle_injection_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) * The balancing work still might be queued here because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) * the handling of the "clapming" variable, cancel, and queue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) * operations are not synchronized via a lock. But it is not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) * a big deal. The balancing work is fast and destroy kthread
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) * will wait for it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) clear_bit(w_data->cpu, cpu_clamping_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) kthread_destroy_worker(w_data->worker);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) w_data->worker = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) static int start_power_clamp(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) unsigned long cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) set_target_ratio = clamp(set_target_ratio, 0U, MAX_TARGET_RATIO - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) /* prevent cpu hotplug */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) get_online_cpus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) /* prefer BSP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) control_cpu = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) if (!cpu_online(control_cpu))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) control_cpu = smp_processor_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) clamping = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) schedule_delayed_work(&poll_pkg_cstate_work, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) /* start one kthread worker per online cpu */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) for_each_online_cpu(cpu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) start_power_clamp_worker(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) put_online_cpus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) static void end_power_clamp(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) * Block requeuing in all the kthread workers. They will flush and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) * stop faster.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) clamping = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) if (bitmap_weight(cpu_clamping_mask, num_possible_cpus())) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) for_each_set_bit(i, cpu_clamping_mask, num_possible_cpus()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) pr_debug("clamping worker for cpu %d alive, destroy\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) stop_power_clamp_worker(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) static int powerclamp_cpu_online(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) if (clamping == false)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) start_power_clamp_worker(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) /* prefer BSP as controlling CPU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (cpu == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) control_cpu = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) smp_mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) static int powerclamp_cpu_predown(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) if (clamping == false)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) stop_power_clamp_worker(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (cpu != control_cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) control_cpu = cpumask_first(cpu_online_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) if (control_cpu == cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) control_cpu = cpumask_next(cpu, cpu_online_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) smp_mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) static int powerclamp_get_max_state(struct thermal_cooling_device *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) unsigned long *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) *state = MAX_TARGET_RATIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) static int powerclamp_get_cur_state(struct thermal_cooling_device *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) unsigned long *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) if (true == clamping)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) *state = pkg_cstate_ratio_cur;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) /* to save power, do not poll idle ratio while not clamping */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) *state = -1; /* indicates invalid state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) static int powerclamp_set_cur_state(struct thermal_cooling_device *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) unsigned long new_target_ratio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) new_target_ratio = clamp(new_target_ratio, 0UL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) (unsigned long) (MAX_TARGET_RATIO-1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) if (set_target_ratio == 0 && new_target_ratio > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) pr_info("Start idle injection to reduce power\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) set_target_ratio = new_target_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) ret = start_power_clamp();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) goto exit_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) } else if (set_target_ratio > 0 && new_target_ratio == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) pr_info("Stop forced idle injection\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) end_power_clamp();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) set_target_ratio = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) } else /* adjust currently running */ {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) set_target_ratio = new_target_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) /* make new set_target_ratio visible to other cpus */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) smp_mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) exit_set:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) /* bind to generic thermal layer as cooling device*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) static struct thermal_cooling_device_ops powerclamp_cooling_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) .get_max_state = powerclamp_get_max_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) .get_cur_state = powerclamp_get_cur_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) .set_cur_state = powerclamp_set_cur_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) static const struct x86_cpu_id __initconst intel_powerclamp_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) X86_MATCH_VENDOR_FEATURE(INTEL, X86_FEATURE_MWAIT, NULL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) static int __init powerclamp_probe(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) if (!x86_match_cpu(intel_powerclamp_ids)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) pr_err("CPU does not support MWAIT\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) /* The goal for idle time alignment is to achieve package cstate. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) if (!has_pkg_state_counter()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) pr_info("No package C-state available\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) /* find the deepest mwait value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) find_target_mwait();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) static int powerclamp_debug_show(struct seq_file *m, void *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) seq_printf(m, "controlling cpu: %d\n", control_cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) seq_printf(m, "pct confidence steady dynamic (compensation)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) for (i = 0; i < MAX_TARGET_RATIO; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) seq_printf(m, "%d\t%lu\t%lu\t%lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) cal_data[i].confidence,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) cal_data[i].steady_comp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) cal_data[i].dynamic_comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) DEFINE_SHOW_ATTRIBUTE(powerclamp_debug);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) static inline void powerclamp_create_debug_files(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) debug_dir = debugfs_create_dir("intel_powerclamp", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) debugfs_create_file("powerclamp_calib", S_IRUGO, debug_dir, cal_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) &powerclamp_debug_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) static enum cpuhp_state hp_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) static int __init powerclamp_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) int bitmap_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) bitmap_size = BITS_TO_LONGS(num_possible_cpus()) * sizeof(long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) cpu_clamping_mask = kzalloc(bitmap_size, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) if (!cpu_clamping_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) /* probe cpu features and ids here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) retval = powerclamp_probe();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) goto exit_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) /* set default limit, maybe adjusted during runtime based on feedback */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) window_size = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) retval = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) "thermal/intel_powerclamp:online",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) powerclamp_cpu_online,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) powerclamp_cpu_predown);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) if (retval < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) goto exit_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) hp_state = retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) worker_data = alloc_percpu(struct powerclamp_worker_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) if (!worker_data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) goto exit_unregister;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) cooling_dev = thermal_cooling_device_register("intel_powerclamp", NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) &powerclamp_cooling_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) if (IS_ERR(cooling_dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) goto exit_free_thread;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) if (!duration)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) duration = jiffies_to_msecs(DEFAULT_DURATION_JIFFIES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) powerclamp_create_debug_files();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) exit_free_thread:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) free_percpu(worker_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) exit_unregister:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) cpuhp_remove_state_nocalls(hp_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) exit_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) kfree(cpu_clamping_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) module_init(powerclamp_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) static void __exit powerclamp_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) end_power_clamp();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) cpuhp_remove_state_nocalls(hp_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) free_percpu(worker_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) thermal_cooling_device_unregister(cooling_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) kfree(cpu_clamping_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) cancel_delayed_work_sync(&poll_pkg_cstate_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) debugfs_remove_recursive(debug_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) module_exit(powerclamp_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@linux.intel.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) MODULE_DESCRIPTION("Package Level C-state Idle Injection for Intel CPUs");