1717#include <linux/cpufreq.h>
1818#include <linux/init.h>
1919#include <linux/percpu.h>
20+ #include <linux/sched/isolation.h>
2021
2122#include <asm/cpu.h>
2223#include <asm/cputype.h>
@@ -88,18 +89,28 @@ int __init parse_acpi_topology(void)
8889 * initialized.
8990 */
9091static DEFINE_PER_CPU_READ_MOSTLY (unsigned long, arch_max_freq_scale ) = 1UL << (2 * SCHED_CAPACITY_SHIFT );
91- static DEFINE_PER_CPU (u64 , arch_const_cycles_prev ) ;
92- static DEFINE_PER_CPU (u64 , arch_core_cycles_prev ) ;
9392static cpumask_var_t amu_fie_cpus ;
9493
94+ struct amu_cntr_sample {
95+ u64 arch_const_cycles_prev ;
96+ u64 arch_core_cycles_prev ;
97+ unsigned long last_scale_update ;
98+ };
99+
100+ static DEFINE_PER_CPU_SHARED_ALIGNED (struct amu_cntr_sample , cpu_amu_samples ) ;
101+
95102void update_freq_counters_refs (void )
96103{
97- this_cpu_write (arch_core_cycles_prev , read_corecnt ());
98- this_cpu_write (arch_const_cycles_prev , read_constcnt ());
104+ struct amu_cntr_sample * amu_sample = this_cpu_ptr (& cpu_amu_samples );
105+
106+ amu_sample -> arch_core_cycles_prev = read_corecnt ();
107+ amu_sample -> arch_const_cycles_prev = read_constcnt ();
99108}
100109
101110static inline bool freq_counters_valid (int cpu )
102111{
112+ struct amu_cntr_sample * amu_sample = per_cpu_ptr (& cpu_amu_samples , cpu );
113+
103114 if ((cpu >= nr_cpu_ids ) || !cpumask_test_cpu (cpu , cpu_present_mask ))
104115 return false;
105116
@@ -108,8 +119,8 @@ static inline bool freq_counters_valid(int cpu)
108119 return false;
109120 }
110121
111- if (unlikely (!per_cpu ( arch_const_cycles_prev , cpu ) ||
112- !per_cpu ( arch_core_cycles_prev , cpu ) )) {
122+ if (unlikely (!amu_sample -> arch_const_cycles_prev ||
123+ !amu_sample -> arch_core_cycles_prev )) {
113124 pr_debug ("CPU%d: cycle counters are not enabled.\n" , cpu );
114125 return false;
115126 }
@@ -152,17 +163,22 @@ void freq_inv_set_max_ratio(int cpu, u64 max_rate)
152163
153164static void amu_scale_freq_tick (void )
154165{
166+ struct amu_cntr_sample * amu_sample = this_cpu_ptr (& cpu_amu_samples );
155167 u64 prev_core_cnt , prev_const_cnt ;
156168 u64 core_cnt , const_cnt , scale ;
157169
158- prev_const_cnt = this_cpu_read ( arch_const_cycles_prev ) ;
159- prev_core_cnt = this_cpu_read ( arch_core_cycles_prev ) ;
170+ prev_const_cnt = amu_sample -> arch_const_cycles_prev ;
171+ prev_core_cnt = amu_sample -> arch_core_cycles_prev ;
160172
161173 update_freq_counters_refs ();
162174
163- const_cnt = this_cpu_read ( arch_const_cycles_prev ) ;
164- core_cnt = this_cpu_read ( arch_core_cycles_prev ) ;
175+ const_cnt = amu_sample -> arch_const_cycles_prev ;
176+ core_cnt = amu_sample -> arch_core_cycles_prev ;
165177
178+ /*
179+ * This should not happen unless the AMUs have been reset and the
180+ * counter values have not been restored - unlikely
181+ */
166182 if (unlikely (core_cnt <= prev_core_cnt ||
167183 const_cnt <= prev_const_cnt ))
168184 return ;
@@ -182,24 +198,123 @@ static void amu_scale_freq_tick(void)
182198
183199 scale = min_t (unsigned long , scale , SCHED_CAPACITY_SCALE );
184200 this_cpu_write (arch_freq_scale , (unsigned long )scale );
201+
202+ amu_sample -> last_scale_update = jiffies ;
185203}
186204
187205static struct scale_freq_data amu_sfd = {
188206 .source = SCALE_FREQ_SOURCE_ARCH ,
189207 .set_freq_scale = amu_scale_freq_tick ,
190208};
191209
210+ static __always_inline bool amu_fie_cpu_supported (unsigned int cpu )
211+ {
212+ return cpumask_available (amu_fie_cpus ) &&
213+ cpumask_test_cpu (cpu , amu_fie_cpus );
214+ }
215+
216+ void arch_cpu_idle_enter (void )
217+ {
218+ unsigned int cpu = smp_processor_id ();
219+
220+ if (!amu_fie_cpu_supported (cpu ))
221+ return ;
222+
223+ /* Kick in AMU update but only if one has not happened already */
224+ if (housekeeping_cpu (cpu , HK_TYPE_TICK ) &&
225+ time_is_before_jiffies (per_cpu (cpu_amu_samples .last_scale_update , cpu )))
226+ amu_scale_freq_tick ();
227+ }
228+
229+ #define AMU_SAMPLE_EXP_MS 20
230+
231+ int arch_freq_get_on_cpu (int cpu )
232+ {
233+ struct amu_cntr_sample * amu_sample ;
234+ unsigned int start_cpu = cpu ;
235+ unsigned long last_update ;
236+ unsigned int freq = 0 ;
237+ u64 scale ;
238+
239+ if (!amu_fie_cpu_supported (cpu ) || !arch_scale_freq_ref (cpu ))
240+ return - EOPNOTSUPP ;
241+
242+ while (1 ) {
243+
244+ amu_sample = per_cpu_ptr (& cpu_amu_samples , cpu );
245+
246+ last_update = amu_sample -> last_scale_update ;
247+
248+ /*
249+ * For those CPUs that are in full dynticks mode, or those that have
250+ * not seen tick for a while, try an alternative source for the counters
251+ * (and thus freq scale), if available, for given policy: this boils
252+ * down to identifying an active cpu within the same freq domain, if any.
253+ */
254+ if (!housekeeping_cpu (cpu , HK_TYPE_TICK ) ||
255+ time_is_before_jiffies (last_update + msecs_to_jiffies (AMU_SAMPLE_EXP_MS ))) {
256+ struct cpufreq_policy * policy = cpufreq_cpu_get (cpu );
257+ int ref_cpu ;
258+
259+ if (!policy )
260+ return - EINVAL ;
261+
262+ if (!cpumask_intersects (policy -> related_cpus ,
263+ housekeeping_cpumask (HK_TYPE_TICK ))) {
264+ cpufreq_cpu_put (policy );
265+ return - EOPNOTSUPP ;
266+ }
267+
268+ for_each_cpu_wrap (ref_cpu , policy -> cpus , cpu + 1 ) {
269+ if (ref_cpu == start_cpu ) {
270+ /* Prevent verifying same CPU twice */
271+ ref_cpu = nr_cpu_ids ;
272+ break ;
273+ }
274+ if (!idle_cpu (ref_cpu ))
275+ break ;
276+ }
277+
278+ cpufreq_cpu_put (policy );
279+
280+ if (ref_cpu >= nr_cpu_ids )
281+ /* No alternative to pull info from */
282+ return - EAGAIN ;
283+
284+ cpu = ref_cpu ;
285+ } else {
286+ break ;
287+ }
288+ }
289+ /*
290+ * Reversed computation to the one used to determine
291+ * the arch_freq_scale value
292+ * (see amu_scale_freq_tick for details)
293+ */
294+ scale = arch_scale_freq_capacity (cpu );
295+ freq = scale * arch_scale_freq_ref (cpu );
296+ freq >>= SCHED_CAPACITY_SHIFT ;
297+ return freq ;
298+ }
299+
192300static void amu_fie_setup (const struct cpumask * cpus )
193301{
194302 int cpu ;
195303
196304 /* We are already set since the last insmod of cpufreq driver */
197- if (unlikely (cpumask_subset (cpus , amu_fie_cpus )))
305+ if (cpumask_available (amu_fie_cpus ) &&
306+ unlikely (cpumask_subset (cpus , amu_fie_cpus )))
198307 return ;
199308
200- for_each_cpu (cpu , cpus ) {
309+ for_each_cpu (cpu , cpus )
201310 if (!freq_counters_valid (cpu ))
202311 return ;
312+
313+ if (!cpumask_available (amu_fie_cpus ) &&
314+ !zalloc_cpumask_var (& amu_fie_cpus , GFP_KERNEL )) {
315+ WARN_ONCE (1 , "Failed to allocate FIE cpumask for CPUs[%*pbl]\n" ,
316+ cpumask_pr_args (cpus ));
317+ return ;
203318 }
204319
205320 cpumask_or (amu_fie_cpus , amu_fie_cpus , cpus );
@@ -237,17 +352,8 @@ static struct notifier_block init_amu_fie_notifier = {
237352
238353static int __init init_amu_fie (void )
239354{
240- int ret ;
241-
242- if (!zalloc_cpumask_var (& amu_fie_cpus , GFP_KERNEL ))
243- return - ENOMEM ;
244-
245- ret = cpufreq_register_notifier (& init_amu_fie_notifier ,
355+ return cpufreq_register_notifier (& init_amu_fie_notifier ,
246356 CPUFREQ_POLICY_NOTIFIER );
247- if (ret )
248- free_cpumask_var (amu_fie_cpus );
249-
250- return ret ;
251357}
252358core_initcall (init_amu_fie );
253359
0 commit comments