16
16
#include <linux/export.h>
17
17
#include <linux/module.h>
18
18
#include <linux/pm_opp.h>
19
+ #include <linux/pm_qos.h>
19
20
#include <linux/slab.h>
20
21
#include <linux/scmi_protocol.h>
21
22
#include <linux/types.h>
@@ -26,6 +27,8 @@ struct scmi_data {
26
27
int nr_opp ;
27
28
struct device * cpu_dev ;
28
29
cpumask_var_t opp_shared_cpus ;
30
+ struct notifier_block limit_notify_nb ;
31
+ struct freq_qos_request limits_freq_req ;
29
32
};
30
33
31
34
static struct scmi_protocol_handle * ph ;
@@ -174,13 +177,30 @@ static struct freq_attr *scmi_cpufreq_hw_attr[] = {
174
177
NULL ,
175
178
};
176
179
180
+ static int scmi_limit_notify_cb (struct notifier_block * nb , unsigned long event , void * data )
181
+ {
182
+ struct scmi_data * priv = container_of (nb , struct scmi_data , limit_notify_nb );
183
+ struct scmi_perf_limits_report * limit_notify = data ;
184
+ unsigned int limit_freq_khz ;
185
+ int ret ;
186
+
187
+ limit_freq_khz = limit_notify -> range_max_freq / HZ_PER_KHZ ;
188
+
189
+ ret = freq_qos_update_request (& priv -> limits_freq_req , limit_freq_khz );
190
+ if (ret < 0 )
191
+ pr_warn ("failed to update freq constraint: %d\n" , ret );
192
+
193
+ return NOTIFY_OK ;
194
+ }
195
+
177
196
static int scmi_cpufreq_init (struct cpufreq_policy * policy )
178
197
{
179
198
int ret , nr_opp , domain ;
180
199
unsigned int latency ;
181
200
struct device * cpu_dev ;
182
201
struct scmi_data * priv ;
183
202
struct cpufreq_frequency_table * freq_table ;
203
+ struct scmi_device * sdev = cpufreq_get_driver_data ();
184
204
185
205
cpu_dev = get_cpu_device (policy -> cpu );
186
206
if (!cpu_dev ) {
@@ -294,6 +314,23 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
294
314
}
295
315
}
296
316
317
+ ret = freq_qos_add_request (& policy -> constraints , & priv -> limits_freq_req , FREQ_QOS_MAX ,
318
+ FREQ_QOS_MAX_DEFAULT_VALUE );
319
+ if (ret < 0 ) {
320
+ dev_err (cpu_dev , "failed to add qos limits request: %d\n" , ret );
321
+ goto out_free_table ;
322
+ }
323
+
324
+ priv -> limit_notify_nb .notifier_call = scmi_limit_notify_cb ;
325
+ ret = sdev -> handle -> notify_ops -> event_notifier_register (sdev -> handle , SCMI_PROTOCOL_PERF ,
326
+ SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED ,
327
+ & priv -> domain_id ,
328
+ & priv -> limit_notify_nb );
329
+ if (ret )
330
+ dev_warn (& sdev -> dev ,
331
+ "failed to register for limits change notifier for domain %d\n" ,
332
+ priv -> domain_id );
333
+
297
334
return 0 ;
298
335
299
336
out_free_table :
@@ -313,7 +350,13 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
313
350
static void scmi_cpufreq_exit (struct cpufreq_policy * policy )
314
351
{
315
352
struct scmi_data * priv = policy -> driver_data ;
353
+ struct scmi_device * sdev = cpufreq_get_driver_data ();
316
354
355
+ sdev -> handle -> notify_ops -> event_notifier_unregister (sdev -> handle , SCMI_PROTOCOL_PERF ,
356
+ SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED ,
357
+ & priv -> domain_id ,
358
+ & priv -> limit_notify_nb );
359
+ freq_qos_remove_request (& priv -> limits_freq_req );
317
360
dev_pm_opp_free_cpufreq_table (priv -> cpu_dev , & policy -> freq_table );
318
361
dev_pm_opp_remove_all_dynamic (priv -> cpu_dev );
319
362
free_cpumask_var (priv -> opp_shared_cpus );
@@ -372,6 +415,8 @@ static int scmi_cpufreq_probe(struct scmi_device *sdev)
372
415
if (!handle )
373
416
return - ENODEV ;
374
417
418
+ scmi_cpufreq_driver .driver_data = sdev ;
419
+
375
420
perf_ops = handle -> devm_protocol_get (sdev , SCMI_PROTOCOL_PERF , & ph );
376
421
if (IS_ERR (perf_ops ))
377
422
return PTR_ERR (perf_ops );
0 commit comments