1616#include <linux/export.h>
1717#include <linux/module.h>
1818#include <linux/pm_opp.h>
19+ #include <linux/pm_qos.h>
1920#include <linux/slab.h>
2021#include <linux/scmi_protocol.h>
2122#include <linux/types.h>
@@ -26,6 +27,8 @@ struct scmi_data {
2627 int nr_opp ;
2728 struct device * cpu_dev ;
2829 cpumask_var_t opp_shared_cpus ;
30+ struct notifier_block limit_notify_nb ;
31+ struct freq_qos_request limits_freq_req ;
2932};
3033
3134static struct scmi_protocol_handle * ph ;
@@ -174,13 +177,30 @@ static struct freq_attr *scmi_cpufreq_hw_attr[] = {
174177 NULL ,
175178};
176179
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+
177196static int scmi_cpufreq_init (struct cpufreq_policy * policy )
178197{
179198 int ret , nr_opp , domain ;
180199 unsigned int latency ;
181200 struct device * cpu_dev ;
182201 struct scmi_data * priv ;
183202 struct cpufreq_frequency_table * freq_table ;
203+ struct scmi_device * sdev = cpufreq_get_driver_data ();
184204
185205 cpu_dev = get_cpu_device (policy -> cpu );
186206 if (!cpu_dev ) {
@@ -294,6 +314,23 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
294314 }
295315 }
296316
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+
297334 return 0 ;
298335
299336out_free_table :
@@ -313,7 +350,13 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
313350static void scmi_cpufreq_exit (struct cpufreq_policy * policy )
314351{
315352 struct scmi_data * priv = policy -> driver_data ;
353+ struct scmi_device * sdev = cpufreq_get_driver_data ();
316354
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 );
317360 dev_pm_opp_free_cpufreq_table (priv -> cpu_dev , & policy -> freq_table );
318361 dev_pm_opp_remove_all_dynamic (priv -> cpu_dev );
319362 free_cpumask_var (priv -> opp_shared_cpus );
@@ -372,6 +415,8 @@ static int scmi_cpufreq_probe(struct scmi_device *sdev)
372415 if (!handle )
373416 return - ENODEV ;
374417
418+ scmi_cpufreq_driver .driver_data = sdev ;
419+
375420 perf_ops = handle -> devm_protocol_get (sdev , SCMI_PROTOCOL_PERF , & ph );
376421 if (IS_ERR (perf_ops ))
377422 return PTR_ERR (perf_ops );
0 commit comments