Path: blob/master/drivers/devfreq/governor_simpleondemand.c
26378 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* linux/drivers/devfreq/governor_simpleondemand.c3*4* Copyright (C) 2011 Samsung Electronics5* MyungJoo Ham <[email protected]>6*/78#include <linux/errno.h>9#include <linux/module.h>10#include <linux/devfreq.h>11#include <linux/math64.h>12#include "governor.h"1314/* Default constants for DevFreq-Simple-Ondemand (DFSO) */15#define DFSO_UPTHRESHOLD (90)16#define DFSO_DOWNDIFFERENCTIAL (5)17static int devfreq_simple_ondemand_func(struct devfreq *df,18unsigned long *freq)19{20int err;21struct devfreq_dev_status *stat;22unsigned long long a, b;23unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD;24unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL;25struct devfreq_simple_ondemand_data *data = df->data;2627err = devfreq_update_stats(df);28if (err)29return err;3031stat = &df->last_status;3233if (data) {34if (data->upthreshold)35dfso_upthreshold = data->upthreshold;36if (data->downdifferential)37dfso_downdifferential = data->downdifferential;38}39if (dfso_upthreshold > 100 ||40dfso_upthreshold < dfso_downdifferential)41return -EINVAL;4243/* Assume MAX if it is going to be divided by zero */44if (stat->total_time == 0) {45*freq = DEVFREQ_MAX_FREQ;46return 0;47}4849/* Prevent overflow */50if (stat->busy_time >= (1 << 24) || stat->total_time >= (1 << 24)) {51stat->busy_time >>= 7;52stat->total_time >>= 7;53}5455/* Set MAX if it's busy enough */56if (stat->busy_time * 100 >57stat->total_time * dfso_upthreshold) {58*freq = DEVFREQ_MAX_FREQ;59return 0;60}6162/* Set MAX if we do not know the initial frequency */63if (stat->current_frequency == 0) {64*freq = DEVFREQ_MAX_FREQ;65return 0;66}6768/* Keep the current frequency */69if (stat->busy_time * 100 >70stat->total_time * (dfso_upthreshold - dfso_downdifferential)) {71*freq = stat->current_frequency;72return 0;73}7475/* Set the desired frequency based on the load */76a = stat->busy_time;77a *= stat->current_frequency;78b = div_u64(a, stat->total_time);79b *= 100;80b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2));81*freq = (unsigned long) b;8283return 0;84}8586static int devfreq_simple_ondemand_handler(struct devfreq *devfreq,87unsigned int event, void *data)88{89switch (event) {90case DEVFREQ_GOV_START:91devfreq_monitor_start(devfreq);92break;9394case DEVFREQ_GOV_STOP:95devfreq_monitor_stop(devfreq);96break;9798case DEVFREQ_GOV_UPDATE_INTERVAL:99devfreq_update_interval(devfreq, (unsigned int *)data);100break;101102case DEVFREQ_GOV_SUSPEND:103devfreq_monitor_suspend(devfreq);104break;105106case DEVFREQ_GOV_RESUME:107devfreq_monitor_resume(devfreq);108break;109110default:111break;112}113114return 0;115}116117static struct devfreq_governor devfreq_simple_ondemand = {118.name = DEVFREQ_GOV_SIMPLE_ONDEMAND,119.attrs = DEVFREQ_GOV_ATTR_POLLING_INTERVAL120| DEVFREQ_GOV_ATTR_TIMER,121.get_target_freq = devfreq_simple_ondemand_func,122.event_handler = devfreq_simple_ondemand_handler,123};124125static int __init devfreq_simple_ondemand_init(void)126{127return devfreq_add_governor(&devfreq_simple_ondemand);128}129subsys_initcall(devfreq_simple_ondemand_init);130131static void __exit devfreq_simple_ondemand_exit(void)132{133int ret;134135ret = devfreq_remove_governor(&devfreq_simple_ondemand);136if (ret)137pr_err("%s: failed remove governor %d\n", __func__, ret);138139return;140}141module_exit(devfreq_simple_ondemand_exit);142MODULE_DESCRIPTION("DEVFREQ Simple On-demand governor");143MODULE_LICENSE("GPL");144145146