brintos

brintos / linux-shallow public Read only

0
0
Text · 3.3 KiB · c234357 Raw
145 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  linux/drivers/devfreq/governor_simpleondemand.c4 *5 *  Copyright (C) 2011 Samsung Electronics6 *	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	.attrs = DEVFREQ_GOV_ATTR_POLLING_INTERVAL121		| DEVFREQ_GOV_ATTR_TIMER,122	.get_target_freq = devfreq_simple_ondemand_func,123	.event_handler = devfreq_simple_ondemand_handler,124};125 126static int __init devfreq_simple_ondemand_init(void)127{128	return devfreq_add_governor(&devfreq_simple_ondemand);129}130subsys_initcall(devfreq_simple_ondemand_init);131 132static void __exit devfreq_simple_ondemand_exit(void)133{134	int ret;135 136	ret = devfreq_remove_governor(&devfreq_simple_ondemand);137	if (ret)138		pr_err("%s: failed remove governor %d\n", __func__, ret);139 140	return;141}142module_exit(devfreq_simple_ondemand_exit);143MODULE_DESCRIPTION("DEVFREQ Simple On-demand governor");144MODULE_LICENSE("GPL");145