diff options
Diffstat (limited to 'drivers/cpufreq/intel_pstate.c')
| -rw-r--r-- | drivers/cpufreq/intel_pstate.c | 79 | 
1 files changed, 62 insertions, 17 deletions
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 001a532e342e..cd83d477e32d 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -66,6 +66,7 @@ static inline int ceiling_fp(int32_t x)  struct sample {  	int32_t core_pct_busy; +	int32_t busy_scaled;  	u64 aperf;  	u64 mperf;  	u64 tsc; @@ -112,6 +113,7 @@ struct cpudata {  	u64	prev_aperf;  	u64	prev_mperf;  	u64	prev_tsc; +	u64	prev_cummulative_iowait;  	struct sample sample;  }; @@ -133,6 +135,7 @@ struct pstate_funcs {  	int (*get_scaling)(void);  	void (*set)(struct cpudata*, int pstate);  	void (*get_vid)(struct cpudata *); +	int32_t (*get_target_pstate)(struct cpudata *);  };  struct cpu_defaults { @@ -140,6 +143,9 @@ struct cpu_defaults {  	struct pstate_funcs funcs;  }; +static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu); +static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu); +  static struct pstate_adjust_policy pid_params;  static struct pstate_funcs pstate_funcs;  static int hwp_active; @@ -738,6 +744,7 @@ static struct cpu_defaults core_params = {  		.get_turbo = core_get_turbo_pstate,  		.get_scaling = core_get_scaling,  		.set = core_set_pstate, +		.get_target_pstate = get_target_pstate_use_performance,  	},  }; @@ -758,6 +765,7 @@ static struct cpu_defaults silvermont_params = {  		.set = atom_set_pstate,  		.get_scaling = silvermont_get_scaling,  		.get_vid = atom_get_vid, +		.get_target_pstate = get_target_pstate_use_cpu_load,  	},  }; @@ -778,6 +786,7 @@ static struct cpu_defaults airmont_params = {  		.set = atom_set_pstate,  		.get_scaling = airmont_get_scaling,  		.get_vid = atom_get_vid, +		.get_target_pstate = get_target_pstate_use_cpu_load,  	},  }; @@ -797,6 +806,7 @@ static struct cpu_defaults knl_params = {  		.get_turbo = knl_get_turbo_pstate,  		.get_scaling = core_get_scaling,  		.set = core_set_pstate, +		.get_target_pstate = get_target_pstate_use_performance,  	},  }; @@ -882,12 +892,11 @@ static inline void intel_pstate_sample(struct cpudata *cpu)  	local_irq_save(flags);  	rdmsrl(MSR_IA32_APERF, aperf);  	rdmsrl(MSR_IA32_MPERF, mperf); -	if (cpu->prev_mperf == mperf) { +	tsc = rdtsc(); +	if ((cpu->prev_mperf == mperf) || (cpu->prev_tsc == tsc)) {  		local_irq_restore(flags);  		return;  	} - -	tsc = rdtsc();  	local_irq_restore(flags);  	cpu->last_sample_time = cpu->sample.time; @@ -922,7 +931,43 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu)  	mod_timer_pinned(&cpu->timer, jiffies + delay);  } -static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu) +static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu) +{ +	struct sample *sample = &cpu->sample; +	u64 cummulative_iowait, delta_iowait_us; +	u64 delta_iowait_mperf; +	u64 mperf, now; +	int32_t cpu_load; + +	cummulative_iowait = get_cpu_iowait_time_us(cpu->cpu, &now); + +	/* +	 * Convert iowait time into number of IO cycles spent at max_freq. +	 * IO is considered as busy only for the cpu_load algorithm. For +	 * performance this is not needed since we always try to reach the +	 * maximum P-State, so we are already boosting the IOs. +	 */ +	delta_iowait_us = cummulative_iowait - cpu->prev_cummulative_iowait; +	delta_iowait_mperf = div64_u64(delta_iowait_us * cpu->pstate.scaling * +		cpu->pstate.max_pstate, MSEC_PER_SEC); + +	mperf = cpu->sample.mperf + delta_iowait_mperf; +	cpu->prev_cummulative_iowait = cummulative_iowait; + + +	/* +	 * The load can be estimated as the ratio of the mperf counter +	 * running at a constant frequency during active periods +	 * (C0) and the time stamp counter running at the same frequency +	 * also during C-states. +	 */ +	cpu_load = div64_u64(int_tofp(100) * mperf, sample->tsc); +	cpu->sample.busy_scaled = cpu_load; + +	return cpu->pstate.current_pstate - pid_calc(&cpu->pid, cpu_load); +} + +static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu)  {  	int32_t core_busy, max_pstate, current_pstate, sample_ratio;  	s64 duration_us; @@ -960,30 +1005,24 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)  		core_busy = mul_fp(core_busy, sample_ratio);  	} -	return core_busy; +	cpu->sample.busy_scaled = core_busy; +	return cpu->pstate.current_pstate - pid_calc(&cpu->pid, core_busy);  }  static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)  { -	int32_t busy_scaled; -	struct _pid *pid; -	signed int ctl; -	int from; +	int from, target_pstate;  	struct sample *sample;  	from = cpu->pstate.current_pstate; -	pid = &cpu->pid; -	busy_scaled = intel_pstate_get_scaled_busy(cpu); +	target_pstate = pstate_funcs.get_target_pstate(cpu); -	ctl = pid_calc(pid, busy_scaled); - -	/* Negative values of ctl increase the pstate and vice versa */ -	intel_pstate_set_pstate(cpu, cpu->pstate.current_pstate - ctl, true); +	intel_pstate_set_pstate(cpu, target_pstate, true);  	sample = &cpu->sample;  	trace_pstate_sample(fp_toint(sample->core_pct_busy), -		fp_toint(busy_scaled), +		fp_toint(sample->busy_scaled),  		from,  		cpu->pstate.current_pstate,  		sample->mperf, @@ -1101,6 +1140,8 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)  	    policy->max >= policy->cpuinfo.max_freq) {  		pr_debug("intel_pstate: set performance\n");  		limits = &performance_limits; +		if (hwp_active) +			intel_pstate_hwp_set();  		return 0;  	} @@ -1108,7 +1149,8 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)  	limits = &powersave_limits;  	limits->min_policy_pct = (policy->min * 100) / policy->cpuinfo.max_freq;  	limits->min_policy_pct = clamp_t(int, limits->min_policy_pct, 0 , 100); -	limits->max_policy_pct = (policy->max * 100) / policy->cpuinfo.max_freq; +	limits->max_policy_pct = DIV_ROUND_UP(policy->max * 100, +					      policy->cpuinfo.max_freq);  	limits->max_policy_pct = clamp_t(int, limits->max_policy_pct, 0 , 100);  	/* Normalize user input to [min_policy_pct, max_policy_pct] */ @@ -1120,6 +1162,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)  				   limits->max_sysfs_pct);  	limits->max_perf_pct = max(limits->min_policy_pct,  				   limits->max_perf_pct); +	limits->max_perf = round_up(limits->max_perf, FRAC_BITS);  	/* Make sure min_perf_pct <= max_perf_pct */  	limits->min_perf_pct = min(limits->max_perf_pct, limits->min_perf_pct); @@ -1233,6 +1276,8 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs)  	pstate_funcs.get_scaling = funcs->get_scaling;  	pstate_funcs.set       = funcs->set;  	pstate_funcs.get_vid   = funcs->get_vid; +	pstate_funcs.get_target_pstate = funcs->get_target_pstate; +  }  #if IS_ENABLED(CONFIG_ACPI)  | 
