From 007bea098b869945a462420a1f9d442ff169f722 Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Wed, 18 Dec 2013 10:32:39 -0800 Subject: intel_pstate: Add setting voltage value for baytrail P states. Baytrail requires setting P state and voltage pairs when adjusting the requested P state. Add function for retrieving the valid voltage values and modify *_set_pstate() functions to caluclate the appropriate voltage for the requested P state. Signed-off-by: Dirk Brandewie Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 58 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 4 deletions(-) (limited to 'drivers/cpufreq/intel_pstate.c') diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 5f1cbae36961..c84b280238a4 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -35,6 +35,7 @@ #define SAMPLE_COUNT 3 #define BYT_RATIOS 0x66a +#define BYT_VIDS 0x66b #define FRAC_BITS 8 #define int_tofp(X) ((int64_t)(X) << FRAC_BITS) @@ -64,6 +65,12 @@ struct pstate_data { int turbo_pstate; }; +struct vid_data { + int32_t min; + int32_t max; + int32_t ratio; +}; + struct _pid { int setpoint; int32_t integral; @@ -82,6 +89,7 @@ struct cpudata { struct timer_list timer; struct pstate_data pstate; + struct vid_data vid; struct _pid pid; int min_pstate_count; @@ -106,7 +114,8 @@ struct pstate_funcs { int (*get_max)(void); int (*get_min)(void); int (*get_turbo)(void); - void (*set)(int pstate); + void (*set)(struct cpudata*, int pstate); + void (*get_vid)(struct cpudata *); }; struct cpu_defaults { @@ -358,6 +367,42 @@ static int byt_get_max_pstate(void) return (value >> 16) & 0xFF; } +static void byt_set_pstate(struct cpudata *cpudata, int pstate) +{ + u64 val; + int32_t vid_fp; + u32 vid; + + val = pstate << 8; + if (limits.no_turbo) + val |= (u64)1 << 32; + + vid_fp = cpudata->vid.min + mul_fp( + int_tofp(pstate - cpudata->pstate.min_pstate), + cpudata->vid.ratio); + + vid_fp = clamp_t(int32_t, vid_fp, cpudata->vid.min, cpudata->vid.max); + vid = fp_toint(vid_fp); + + val |= vid; + + wrmsrl(MSR_IA32_PERF_CTL, val); +} + +static void byt_get_vid(struct cpudata *cpudata) +{ + u64 value; + + rdmsrl(BYT_VIDS, value); + cpudata->vid.min = int_tofp((value >> 8) & 0x7f); + cpudata->vid.max = int_tofp((value >> 16) & 0x7f); + cpudata->vid.ratio = div_fp( + cpudata->vid.max - cpudata->vid.min, + int_tofp(cpudata->pstate.max_pstate - + cpudata->pstate.min_pstate)); +} + + static int core_get_min_pstate(void) { u64 value; @@ -384,7 +429,7 @@ static int core_get_turbo_pstate(void) return ret; } -static void core_set_pstate(int pstate) +static void core_set_pstate(struct cpudata *cpudata, int pstate) { u64 val; @@ -425,7 +470,8 @@ static struct cpu_defaults byt_params = { .get_max = byt_get_max_pstate, .get_min = byt_get_min_pstate, .get_turbo = byt_get_max_pstate, - .set = core_set_pstate, + .set = byt_set_pstate, + .get_vid = byt_get_vid, }, }; @@ -462,7 +508,7 @@ static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) cpu->pstate.current_pstate = pstate; - pstate_funcs.set(pstate); + pstate_funcs.set(cpu, pstate); } static inline void intel_pstate_pstate_increase(struct cpudata *cpu, int steps) @@ -488,6 +534,9 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) cpu->pstate.max_pstate = pstate_funcs.get_max(); cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(); + if (pstate_funcs.get_vid) + pstate_funcs.get_vid(cpu); + /* * goto max pstate so we don't slow up boot if we are built-in if we are * a module we will take care of it during normal operation @@ -776,6 +825,7 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs) pstate_funcs.get_min = funcs->get_min; pstate_funcs.get_turbo = funcs->get_turbo; pstate_funcs.set = funcs->set; + pstate_funcs.get_vid = funcs->get_vid; } #if IS_ENABLED(CONFIG_ACPI) -- cgit v1.2.3 From 91a4cd4f3d8169d7398f9123683f64575927c682 Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Tue, 17 Dec 2013 09:42:07 -0800 Subject: intel_pstate: Remove periodic P state boost Remove the periodic P state boost. This code required for some corner case benchmark tests. The calculation of the required P state was incorrect/inaccurate and would not allow P state increase. This was fixed by a combination of commits: 2134ed4 cpufreq / intel_pstate: Change to scale off of max P-state d253d2a intel_pstate: Improve accuracy by not truncating until final result References: https://bugzilla.kernel.org/show_bug.cgi?id=64271 Reported-by: Doug Smythies Signed-off-by: Dirk Brandewie Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers/cpufreq/intel_pstate.c') diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index c84b280238a4..41e21bb01c9c 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -92,8 +92,6 @@ struct cpudata { struct vid_data vid; struct _pid pid; - int min_pstate_count; - u64 prev_aperf; u64 prev_mperf; int sample_ptr; @@ -617,15 +615,6 @@ static void intel_pstate_timer_func(unsigned long __data) intel_pstate_sample(cpu); intel_pstate_adjust_busy_pstate(cpu); - - if (cpu->pstate.current_pstate == cpu->pstate.min_pstate) { - cpu->min_pstate_count++; - if (!(cpu->min_pstate_count % 5)) { - intel_pstate_set_pstate(cpu, cpu->pstate.max_pstate); - } - } else - cpu->min_pstate_count = 0; - intel_pstate_set_sample_time(cpu); } -- cgit v1.2.3 From b69880f9ccf7e13b2e2cb38f49a2451d7aa548b3 Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Thu, 16 Jan 2014 10:32:25 -0800 Subject: intel_pstate: Add trace point to report internal state. Add perf trace event "power:pstate_sample" to report driver state to aid in diagnosing issues reported against intel_pstate. Signed-off-by: Dirk Brandewie Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/cpufreq/intel_pstate.c') diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index fe91dad8f5e2..7e257b233602 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -51,6 +51,8 @@ static inline int32_t div_fp(int32_t x, int32_t y) return div_s64((int64_t)x << FRAC_BITS, (int64_t)y); } +static u64 energy_divisor; + struct sample { int32_t core_pct_busy; u64 aperf; @@ -559,6 +561,7 @@ static inline void intel_pstate_sample(struct cpudata *cpu) rdmsrl(MSR_IA32_APERF, aperf); rdmsrl(MSR_IA32_MPERF, mperf); + cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT; cpu->samples[cpu->sample_ptr].aperf = aperf; cpu->samples[cpu->sample_ptr].mperf = mperf; @@ -603,6 +606,7 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) ctl = pid_calc(pid, busy_scaled); steps = abs(ctl); + if (ctl < 0) intel_pstate_pstate_increase(cpu, steps); else @@ -612,9 +616,24 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) static void intel_pstate_timer_func(unsigned long __data) { struct cpudata *cpu = (struct cpudata *) __data; + struct sample *sample; + u64 energy; intel_pstate_sample(cpu); + + sample = &cpu->samples[cpu->sample_ptr]; + rdmsrl(MSR_PKG_ENERGY_STATUS, energy); + intel_pstate_adjust_busy_pstate(cpu); + + trace_pstate_sample(fp_toint(sample->core_pct_busy), + fp_toint(intel_pstate_get_scaled_busy(cpu)), + cpu->pstate.current_pstate, + sample->mperf, + sample->aperf, + div64_u64(energy, energy_divisor), + sample->freq); + intel_pstate_set_sample_time(cpu); } @@ -894,6 +913,7 @@ static int __init intel_pstate_init(void) int cpu, rc = 0; const struct x86_cpu_id *id; struct cpu_defaults *cpu_info; + u64 units; if (no_load) return -ENODEV; @@ -927,8 +947,12 @@ static int __init intel_pstate_init(void) if (rc) goto out; + rdmsrl(MSR_RAPL_POWER_UNIT, units); + energy_divisor = 1 << ((units >> 8) & 0x1f); /* bits{12:8} */ + intel_pstate_debug_expose_params(); intel_pstate_sysfs_expose_params(); + return rc; out: get_online_cpus(); -- cgit v1.2.3