aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/cppc_cpufreq.c
diff options
context:
space:
mode:
authorPrashanth Prakash <pprakash@codeaurora.org>2018-04-04 14:14:52 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-04-24 06:33:28 -0400
commit256f19d212f260c955a90a0efc7753e11b18e34c (patch)
tree6c9203ba7e37647e92a451a48085d9704569af42 /drivers/cpufreq/cppc_cpufreq.c
parent6fa12d584dcba18f67425ce17e9317311a624f81 (diff)
cpufreq / CPPC: Support for CPPC v3
Use CPPC v3 entries to convert the abstract processor performance to processor frequency in KHz. Signed-off-by: Prashanth Prakash <pprakash@codeaurora.org> Acked-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpufreq/cppc_cpufreq.c')
-rw-r--r--drivers/cpufreq/cppc_cpufreq.c80
1 files changed, 68 insertions, 12 deletions
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index bc5fc1630876..e67e94b0ec14 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -42,9 +42,6 @@
42 */ 42 */
43static struct cppc_cpudata **all_cpu_data; 43static struct cppc_cpudata **all_cpu_data;
44 44
45/* Capture the max KHz from DMI */
46static u64 cppc_dmi_max_khz;
47
48/* Callback function used to retrieve the max frequency from DMI */ 45/* Callback function used to retrieve the max frequency from DMI */
49static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private) 46static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private)
50{ 47{
@@ -75,6 +72,64 @@ static u64 cppc_get_dmi_max_khz(void)
75 return (1000 * mhz); 72 return (1000 * mhz);
76} 73}
77 74
75/*
76 * If CPPC lowest_freq and nominal_freq registers are exposed then we can
77 * use them to convert perf to freq and vice versa
78 *
79 * If the perf/freq point lies between Nominal and Lowest, we can treat
80 * (Low perf, Low freq) and (Nom Perf, Nom freq) as 2D co-ordinates of a line
81 * and extrapolate the rest
82 * For perf/freq > Nominal, we use the ratio perf:freq at Nominal for conversion
83 */
84static unsigned int cppc_cpufreq_perf_to_khz(struct cppc_cpudata *cpu,
85 unsigned int perf)
86{
87 static u64 max_khz;
88 struct cppc_perf_caps *caps = &cpu->perf_caps;
89 u64 mul, div;
90
91 if (caps->lowest_freq && caps->nominal_freq) {
92 if (perf >= caps->nominal_perf) {
93 mul = caps->nominal_freq;
94 div = caps->nominal_perf;
95 } else {
96 mul = caps->nominal_freq - caps->lowest_freq;
97 div = caps->nominal_perf - caps->lowest_perf;
98 }
99 } else {
100 if (!max_khz)
101 max_khz = cppc_get_dmi_max_khz();
102 mul = max_khz;
103 div = cpu->perf_caps.highest_perf;
104 }
105 return (u64)perf * mul / div;
106}
107
108static unsigned int cppc_cpufreq_khz_to_perf(struct cppc_cpudata *cpu,
109 unsigned int freq)
110{
111 static u64 max_khz;
112 struct cppc_perf_caps *caps = &cpu->perf_caps;
113 u64 mul, div;
114
115 if (caps->lowest_freq && caps->nominal_freq) {
116 if (freq >= caps->nominal_freq) {
117 mul = caps->nominal_perf;
118 div = caps->nominal_freq;
119 } else {
120 mul = caps->lowest_perf;
121 div = caps->lowest_freq;
122 }
123 } else {
124 if (!max_khz)
125 max_khz = cppc_get_dmi_max_khz();
126 mul = cpu->perf_caps.highest_perf;
127 div = max_khz;
128 }
129
130 return (u64)freq * mul / div;
131}
132
78static int cppc_cpufreq_set_target(struct cpufreq_policy *policy, 133static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
79 unsigned int target_freq, 134 unsigned int target_freq,
80 unsigned int relation) 135 unsigned int relation)
@@ -86,7 +141,7 @@ static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
86 141
87 cpu = all_cpu_data[policy->cpu]; 142 cpu = all_cpu_data[policy->cpu];
88 143
89 desired_perf = (u64)target_freq * cpu->perf_caps.highest_perf / cppc_dmi_max_khz; 144 desired_perf = cppc_cpufreq_khz_to_perf(cpu, target_freq);
90 /* Return if it is exactly the same perf */ 145 /* Return if it is exactly the same perf */
91 if (desired_perf == cpu->perf_ctrls.desired_perf) 146 if (desired_perf == cpu->perf_ctrls.desired_perf)
92 return ret; 147 return ret;
@@ -143,24 +198,24 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
143 return ret; 198 return ret;
144 } 199 }
145 200
146 cppc_dmi_max_khz = cppc_get_dmi_max_khz(); 201 /* Convert the lowest and nominal freq from MHz to KHz */
202 cpu->perf_caps.lowest_freq *= 1000;
203 cpu->perf_caps.nominal_freq *= 1000;
147 204
148 /* 205 /*
149 * Set min to lowest nonlinear perf to avoid any efficiency penalty (see 206 * Set min to lowest nonlinear perf to avoid any efficiency penalty (see
150 * Section 8.4.7.1.1.5 of ACPI 6.1 spec) 207 * Section 8.4.7.1.1.5 of ACPI 6.1 spec)
151 */ 208 */
152 policy->min = cpu->perf_caps.lowest_nonlinear_perf * cppc_dmi_max_khz / 209 policy->min = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.lowest_nonlinear_perf);
153 cpu->perf_caps.highest_perf; 210 policy->max = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.highest_perf);
154 policy->max = cppc_dmi_max_khz;
155 211
156 /* 212 /*
157 * Set cpuinfo.min_freq to Lowest to make the full range of performance 213 * Set cpuinfo.min_freq to Lowest to make the full range of performance
158 * available if userspace wants to use any perf between lowest & lowest 214 * available if userspace wants to use any perf between lowest & lowest
159 * nonlinear perf 215 * nonlinear perf
160 */ 216 */
161 policy->cpuinfo.min_freq = cpu->perf_caps.lowest_perf * cppc_dmi_max_khz / 217 policy->cpuinfo.min_freq = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.lowest_perf);
162 cpu->perf_caps.highest_perf; 218 policy->cpuinfo.max_freq = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.highest_perf);
163 policy->cpuinfo.max_freq = cppc_dmi_max_khz;
164 219
165 policy->transition_delay_us = cppc_get_transition_latency(cpu_num) / 220 policy->transition_delay_us = cppc_get_transition_latency(cpu_num) /
166 NSEC_PER_USEC; 221 NSEC_PER_USEC;
@@ -187,7 +242,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
187 cpu->cur_policy = policy; 242 cpu->cur_policy = policy;
188 243
189 /* Set policy->cur to max now. The governors will adjust later. */ 244 /* Set policy->cur to max now. The governors will adjust later. */
190 policy->cur = cppc_dmi_max_khz; 245 policy->cur = cppc_cpufreq_perf_to_khz(cpu,
246 cpu->perf_caps.highest_perf);
191 cpu->perf_ctrls.desired_perf = cpu->perf_caps.highest_perf; 247 cpu->perf_ctrls.desired_perf = cpu->perf_caps.highest_perf;
192 248
193 ret = cppc_set_perf(cpu_num, &cpu->perf_ctrls); 249 ret = cppc_set_perf(cpu_num, &cpu->perf_ctrls);