42
42
*/
43
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
45
/* Callback function used to retrieve the max frequency from DMI */
49
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
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
133
static int cppc_cpufreq_set_target (struct cpufreq_policy * policy ,
79
134
unsigned int target_freq ,
80
135
unsigned int relation )
@@ -86,7 +141,7 @@ static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
86
141
87
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
145
/* Return if it is exactly the same perf */
91
146
if (desired_perf == cpu -> perf_ctrls .desired_perf )
92
147
return ret ;
@@ -143,24 +198,24 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
143
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
206
* Set min to lowest nonlinear perf to avoid any efficiency penalty (see
150
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 /
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 );
155
211
156
212
/*
157
213
* Set cpuinfo.min_freq to Lowest to make the full range of performance
158
214
* available if userspace wants to use any perf between lowest & lowest
159
215
* nonlinear perf
160
216
*/
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 );
164
219
165
220
policy -> transition_delay_us = cppc_get_transition_latency (cpu_num ) /
166
221
NSEC_PER_USEC ;
@@ -187,7 +242,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
187
242
cpu -> cur_policy = policy ;
188
243
189
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
247
cpu -> perf_ctrls .desired_perf = cpu -> perf_caps .highest_perf ;
192
248
193
249
ret = cppc_set_perf (cpu_num , & cpu -> perf_ctrls );
0 commit comments