Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  linux/drivers/devfreq/governor_simpleondemand.c
0004  *
0005  *  Copyright (C) 2011 Samsung Electronics
0006  *  MyungJoo Ham <myungjoo.ham@samsung.com>
0007  */
0008 
0009 #include <linux/errno.h>
0010 #include <linux/module.h>
0011 #include <linux/devfreq.h>
0012 #include <linux/math64.h>
0013 #include "governor.h"
0014 
0015 /* Default constants for DevFreq-Simple-Ondemand (DFSO) */
0016 #define DFSO_UPTHRESHOLD    (90)
0017 #define DFSO_DOWNDIFFERENCTIAL  (5)
0018 static int devfreq_simple_ondemand_func(struct devfreq *df,
0019                     unsigned long *freq)
0020 {
0021     int err;
0022     struct devfreq_dev_status *stat;
0023     unsigned long long a, b;
0024     unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD;
0025     unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL;
0026     struct devfreq_simple_ondemand_data *data = df->data;
0027 
0028     err = devfreq_update_stats(df);
0029     if (err)
0030         return err;
0031 
0032     stat = &df->last_status;
0033 
0034     if (data) {
0035         if (data->upthreshold)
0036             dfso_upthreshold = data->upthreshold;
0037         if (data->downdifferential)
0038             dfso_downdifferential = data->downdifferential;
0039     }
0040     if (dfso_upthreshold > 100 ||
0041         dfso_upthreshold < dfso_downdifferential)
0042         return -EINVAL;
0043 
0044     /* Assume MAX if it is going to be divided by zero */
0045     if (stat->total_time == 0) {
0046         *freq = DEVFREQ_MAX_FREQ;
0047         return 0;
0048     }
0049 
0050     /* Prevent overflow */
0051     if (stat->busy_time >= (1 << 24) || stat->total_time >= (1 << 24)) {
0052         stat->busy_time >>= 7;
0053         stat->total_time >>= 7;
0054     }
0055 
0056     /* Set MAX if it's busy enough */
0057     if (stat->busy_time * 100 >
0058         stat->total_time * dfso_upthreshold) {
0059         *freq = DEVFREQ_MAX_FREQ;
0060         return 0;
0061     }
0062 
0063     /* Set MAX if we do not know the initial frequency */
0064     if (stat->current_frequency == 0) {
0065         *freq = DEVFREQ_MAX_FREQ;
0066         return 0;
0067     }
0068 
0069     /* Keep the current frequency */
0070     if (stat->busy_time * 100 >
0071         stat->total_time * (dfso_upthreshold - dfso_downdifferential)) {
0072         *freq = stat->current_frequency;
0073         return 0;
0074     }
0075 
0076     /* Set the desired frequency based on the load */
0077     a = stat->busy_time;
0078     a *= stat->current_frequency;
0079     b = div_u64(a, stat->total_time);
0080     b *= 100;
0081     b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2));
0082     *freq = (unsigned long) b;
0083 
0084     return 0;
0085 }
0086 
0087 static int devfreq_simple_ondemand_handler(struct devfreq *devfreq,
0088                 unsigned int event, void *data)
0089 {
0090     switch (event) {
0091     case DEVFREQ_GOV_START:
0092         devfreq_monitor_start(devfreq);
0093         break;
0094 
0095     case DEVFREQ_GOV_STOP:
0096         devfreq_monitor_stop(devfreq);
0097         break;
0098 
0099     case DEVFREQ_GOV_UPDATE_INTERVAL:
0100         devfreq_update_interval(devfreq, (unsigned int *)data);
0101         break;
0102 
0103     case DEVFREQ_GOV_SUSPEND:
0104         devfreq_monitor_suspend(devfreq);
0105         break;
0106 
0107     case DEVFREQ_GOV_RESUME:
0108         devfreq_monitor_resume(devfreq);
0109         break;
0110 
0111     default:
0112         break;
0113     }
0114 
0115     return 0;
0116 }
0117 
0118 static struct devfreq_governor devfreq_simple_ondemand = {
0119     .name = DEVFREQ_GOV_SIMPLE_ONDEMAND,
0120     .attrs = DEVFREQ_GOV_ATTR_POLLING_INTERVAL
0121         | DEVFREQ_GOV_ATTR_TIMER,
0122     .get_target_freq = devfreq_simple_ondemand_func,
0123     .event_handler = devfreq_simple_ondemand_handler,
0124 };
0125 
0126 static int __init devfreq_simple_ondemand_init(void)
0127 {
0128     return devfreq_add_governor(&devfreq_simple_ondemand);
0129 }
0130 subsys_initcall(devfreq_simple_ondemand_init);
0131 
0132 static void __exit devfreq_simple_ondemand_exit(void)
0133 {
0134     int ret;
0135 
0136     ret = devfreq_remove_governor(&devfreq_simple_ondemand);
0137     if (ret)
0138         pr_err("%s: failed remove governor %d\n", __func__, ret);
0139 
0140     return;
0141 }
0142 module_exit(devfreq_simple_ondemand_exit);
0143 MODULE_LICENSE("GPL");