linux/drivers/devfreq/governor_simpleondemand.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  linux/drivers/devfreq/governor_simpleondemand.c
   4 *
   5 *  Copyright (C) 2011 Samsung Electronics
   6 *      MyungJoo Ham <myungjoo.ham@samsung.com>
   7 */
   8
   9#include <linux/errno.h>
  10#include <linux/module.h>
  11#include <linux/devfreq.h>
  12#include <linux/math64.h>
  13#include "governor.h"
  14
  15/* Default constants for DevFreq-Simple-Ondemand (DFSO) */
  16#define DFSO_UPTHRESHOLD        (90)
  17#define DFSO_DOWNDIFFERENCTIAL  (5)
  18static int devfreq_simple_ondemand_func(struct devfreq *df,
  19                                        unsigned long *freq)
  20{
  21        int err;
  22        struct devfreq_dev_status *stat;
  23        unsigned long long a, b;
  24        unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD;
  25        unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL;
  26        struct devfreq_simple_ondemand_data *data = df->data;
  27
  28        err = devfreq_update_stats(df);
  29        if (err)
  30                return err;
  31
  32        stat = &df->last_status;
  33
  34        if (data) {
  35                if (data->upthreshold)
  36                        dfso_upthreshold = data->upthreshold;
  37                if (data->downdifferential)
  38                        dfso_downdifferential = data->downdifferential;
  39        }
  40        if (dfso_upthreshold > 100 ||
  41            dfso_upthreshold < dfso_downdifferential)
  42                return -EINVAL;
  43
  44        /* Assume MAX if it is going to be divided by zero */
  45        if (stat->total_time == 0) {
  46                *freq = DEVFREQ_MAX_FREQ;
  47                return 0;
  48        }
  49
  50        /* Prevent overflow */
  51        if (stat->busy_time >= (1 << 24) || stat->total_time >= (1 << 24)) {
  52                stat->busy_time >>= 7;
  53                stat->total_time >>= 7;
  54        }
  55
  56        /* Set MAX if it's busy enough */
  57        if (stat->busy_time * 100 >
  58            stat->total_time * dfso_upthreshold) {
  59                *freq = DEVFREQ_MAX_FREQ;
  60                return 0;
  61        }
  62
  63        /* Set MAX if we do not know the initial frequency */
  64        if (stat->current_frequency == 0) {
  65                *freq = DEVFREQ_MAX_FREQ;
  66                return 0;
  67        }
  68
  69        /* Keep the current frequency */
  70        if (stat->busy_time * 100 >
  71            stat->total_time * (dfso_upthreshold - dfso_downdifferential)) {
  72                *freq = stat->current_frequency;
  73                return 0;
  74        }
  75
  76        /* Set the desired frequency based on the load */
  77        a = stat->busy_time;
  78        a *= stat->current_frequency;
  79        b = div_u64(a, stat->total_time);
  80        b *= 100;
  81        b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2));
  82        *freq = (unsigned long) b;
  83
  84        return 0;
  85}
  86
  87static int devfreq_simple_ondemand_handler(struct devfreq *devfreq,
  88                                unsigned int event, void *data)
  89{
  90        switch (event) {
  91        case DEVFREQ_GOV_START:
  92                devfreq_monitor_start(devfreq);
  93                break;
  94
  95        case DEVFREQ_GOV_STOP:
  96                devfreq_monitor_stop(devfreq);
  97                break;
  98
  99        case DEVFREQ_GOV_UPDATE_INTERVAL:
 100                devfreq_update_interval(devfreq, (unsigned int *)data);
 101                break;
 102
 103        case DEVFREQ_GOV_SUSPEND:
 104                devfreq_monitor_suspend(devfreq);
 105                break;
 106
 107        case DEVFREQ_GOV_RESUME:
 108                devfreq_monitor_resume(devfreq);
 109                break;
 110
 111        default:
 112                break;
 113        }
 114
 115        return 0;
 116}
 117
 118static struct devfreq_governor devfreq_simple_ondemand = {
 119        .name = DEVFREQ_GOV_SIMPLE_ONDEMAND,
 120        .get_target_freq = devfreq_simple_ondemand_func,
 121        .event_handler = devfreq_simple_ondemand_handler,
 122};
 123
 124static int __init devfreq_simple_ondemand_init(void)
 125{
 126        return devfreq_add_governor(&devfreq_simple_ondemand);
 127}
 128subsys_initcall(devfreq_simple_ondemand_init);
 129
 130static void __exit devfreq_simple_ondemand_exit(void)
 131{
 132        int ret;
 133
 134        ret = devfreq_remove_governor(&devfreq_simple_ondemand);
 135        if (ret)
 136                pr_err("%s: failed remove governor %d\n", __func__, ret);
 137
 138        return;
 139}
 140module_exit(devfreq_simple_ondemand_exit);
 141MODULE_LICENSE("GPL");
 142