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