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