diff options
author | Prashanth Prakash <pprakash@codeaurora.org> | 2018-04-04 14:14:52 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2018-04-24 06:33:28 -0400 |
commit | 256f19d212f260c955a90a0efc7753e11b18e34c (patch) | |
tree | 6c9203ba7e37647e92a451a48085d9704569af42 /drivers/cpufreq/cppc_cpufreq.c | |
parent | 6fa12d584dcba18f67425ce17e9317311a624f81 (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.c | 80 |
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 | */ |
43 | static struct cppc_cpudata **all_cpu_data; | 43 | static struct cppc_cpudata **all_cpu_data; |
44 | 44 | ||
45 | /* Capture the max KHz from DMI */ | ||
46 | static 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 */ |
49 | static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private) | 46 | static 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 | */ | ||
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 | |||
78 | static int cppc_cpufreq_set_target(struct cpufreq_policy *policy, | 133 | static 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); |