Skip to content

Commit 256f19d

Browse files
Prashanth Prakashrafaeljw
authored andcommitted
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 <[email protected]> Acked-by: Viresh Kumar <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 6fa12d5 commit 256f19d

File tree

1 file changed

+68
-12
lines changed

1 file changed

+68
-12
lines changed

drivers/cpufreq/cppc_cpufreq.c

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,6 @@
4242
*/
4343
static struct cppc_cpudata **all_cpu_data;
4444

45-
/* Capture the max KHz from DMI */
46-
static u64 cppc_dmi_max_khz;
47-
4845
/* Callback function used to retrieve the max frequency from DMI */
4946
static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private)
5047
{
@@ -75,6 +72,64 @@ static u64 cppc_get_dmi_max_khz(void)
7572
return (1000 * mhz);
7673
}
7774

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+
*/
84+
static 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+
108+
static 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+
78133
static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
79134
unsigned int target_freq,
80135
unsigned int relation)
@@ -86,7 +141,7 @@ static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
86141

87142
cpu = all_cpu_data[policy->cpu];
88143

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);
90145
/* Return if it is exactly the same perf */
91146
if (desired_perf == cpu->perf_ctrls.desired_perf)
92147
return ret;
@@ -143,24 +198,24 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
143198
return ret;
144199
}
145200

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;
147204

148205
/*
149206
* Set min to lowest nonlinear perf to avoid any efficiency penalty (see
150207
* Section 8.4.7.1.1.5 of ACPI 6.1 spec)
151208
*/
152-
policy->min = cpu->perf_caps.lowest_nonlinear_perf * cppc_dmi_max_khz /
153-
cpu->perf_caps.highest_perf;
154-
policy->max = cppc_dmi_max_khz;
209+
policy->min = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.lowest_nonlinear_perf);
210+
policy->max = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.highest_perf);
155211

156212
/*
157213
* Set cpuinfo.min_freq to Lowest to make the full range of performance
158214
* available if userspace wants to use any perf between lowest & lowest
159215
* nonlinear perf
160216
*/
161-
policy->cpuinfo.min_freq = cpu->perf_caps.lowest_perf * cppc_dmi_max_khz /
162-
cpu->perf_caps.highest_perf;
163-
policy->cpuinfo.max_freq = cppc_dmi_max_khz;
217+
policy->cpuinfo.min_freq = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.lowest_perf);
218+
policy->cpuinfo.max_freq = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.highest_perf);
164219

165220
policy->transition_delay_us = cppc_get_transition_latency(cpu_num) /
166221
NSEC_PER_USEC;
@@ -187,7 +242,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
187242
cpu->cur_policy = policy;
188243

189244
/* 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);
191247
cpu->perf_ctrls.desired_perf = cpu->perf_caps.highest_perf;
192248

193249
ret = cppc_set_perf(cpu_num, &cpu->perf_ctrls);

0 commit comments

Comments
 (0)