summaryrefslogtreecommitdiffstats
path: root/drivers/devfreq
diff options
context:
space:
mode:
authorArto Merilainen <amerilainen@nvidia.com>2014-11-07 12:47:30 -0500
committermobile promotions <svcmobile_promotions@nvidia.com>2018-07-05 12:58:12 -0400
commit831d08cdc4ca6b5d8a342fb01959305677987e6f (patch)
treebfb2df1ff195a8bddee82b966c1a604cf9ff5c0b /drivers/devfreq
parent622eede67ce0bcbb43b8697f51a821c76d6a1578 (diff)
devfreq: Rename watermark governor
This patch renames watermark governor from "watermark" to "wmark_simple". This allows having more complex watermark based scaling algorithms available. Change-Id: If6a5653300f964173e6581bf256f7bf65041beb9 Signed-off-by: Arto Merilainen <amerilainen@nvidia.com> Reviewed-on: http://git-master/r/598799 Signed-off-by: Shridhar Rasal <srasal@nvidia.com> Reviewed-on: http://git-master/r/1160006 (cherry picked from linux-4.9 commit a47423f57343b9609341065350e399ada5d767d0) [talho: removed Kconfig and Makefile changes from patch] Signed-off-by: Timo Alho <talho@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1770138 Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com> GVS: Gerrit_Virtual_Submit Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/devfreq')
-rw-r--r--drivers/devfreq/governor_wmark_simple.c202
1 files changed, 202 insertions, 0 deletions
diff --git a/drivers/devfreq/governor_wmark_simple.c b/drivers/devfreq/governor_wmark_simple.c
new file mode 100644
index 000000000..ab521ff51
--- /dev/null
+++ b/drivers/devfreq/governor_wmark_simple.c
@@ -0,0 +1,202 @@
1/*
2 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <linux/devfreq.h>
18#include <linux/debugfs.h>
19#include <linux/types.h>
20#include <linux/slab.h>
21#include <linux/device.h>
22#include <linux/notifier.h>
23#include <linux/platform_device.h>
24
25#include <governor.h>
26
27enum watermark_type {
28 NO_WATERMARK_EVENT = 0,
29 HIGH_WATERMARK_EVENT = 1,
30 LOW_WATERMARK_EVENT = 2
31};
32
33struct wmark_gov_info {
34 unsigned long *freqlist;
35 int freq_count;
36 unsigned long last_request;
37
38 enum watermark_type event;
39
40 struct devfreq *df;
41 struct platform_device *pdev;
42};
43
44static unsigned long freqlist_up(struct wmark_gov_info *wmarkinfo,
45 unsigned long curr_freq)
46{
47 int i, pos;
48
49 for (i = 0; i < wmarkinfo->freq_count; i++)
50 if (wmarkinfo->freqlist[i] > curr_freq)
51 break;
52
53 pos = min(wmarkinfo->freq_count - 1, i);
54
55 return wmarkinfo->freqlist[pos];
56}
57
58static unsigned long freqlist_down(struct wmark_gov_info *wmarkinfo,
59 unsigned long curr_freq)
60{
61 int i, pos;
62
63 for (i = wmarkinfo->freq_count - 1; i >= 0; i--)
64 if (wmarkinfo->freqlist[i] < curr_freq)
65 break;
66
67 pos = max(0, i);
68 return wmarkinfo->freqlist[pos];
69}
70
71static int devfreq_watermark_target_freq(struct devfreq *df,
72 unsigned long *freq)
73{
74 struct wmark_gov_info *wmarkinfo = df->data;
75 struct devfreq_dev_status dev_stat;
76 int err;
77
78 err = df->profile->get_dev_status(df->dev.parent, &dev_stat);
79 if (err < 0)
80 return err;
81
82 switch (wmarkinfo->event) {
83 case HIGH_WATERMARK_EVENT:
84 *freq = freqlist_up(wmarkinfo, dev_stat.current_frequency);
85
86 /* always enable low watermark */
87 df->profile->set_low_wmark(df->dev.parent, 100);
88
89 /* disable high watermark if no change */
90 if (*freq == wmarkinfo->last_request)
91 df->profile->set_high_wmark(df->dev.parent, 1000);
92 break;
93 case LOW_WATERMARK_EVENT:
94 *freq = freqlist_down(wmarkinfo, dev_stat.current_frequency);
95
96 /* always enable high watermark */
97 df->profile->set_high_wmark(df->dev.parent, 600);
98
99 /* disable low watermark if no change */
100 if (*freq == wmarkinfo->last_request)
101 df->profile->set_low_wmark(df->dev.parent, 0);
102 break;
103 default:
104 break;
105 }
106
107 /* Mark that you handled event */
108 wmarkinfo->event = NO_WATERMARK_EVENT;
109 wmarkinfo->last_request = *freq;
110
111 return 0;
112}
113
114static int devfreq_watermark_start(struct devfreq *df)
115{
116 struct wmark_gov_info *wmarkinfo;
117 struct platform_device *pdev = to_platform_device(df->dev.parent);
118
119 if (!df->profile->freq_table) {
120 dev_err(&pdev->dev, "Frequency table missing\n");
121 return -EINVAL;
122 }
123
124 wmarkinfo = kzalloc(sizeof(struct wmark_gov_info), GFP_KERNEL);
125 if (!wmarkinfo)
126 return -ENOMEM;
127
128 df->data = (void *)wmarkinfo;
129 wmarkinfo->freqlist = df->profile->freq_table;
130 wmarkinfo->freq_count = df->profile->max_state;
131 wmarkinfo->event = NO_WATERMARK_EVENT;
132 wmarkinfo->df = df;
133 wmarkinfo->pdev = pdev;
134
135 return 0;
136}
137
138static int devfreq_watermark_event_handler(struct devfreq *df,
139 unsigned int event, void *wmark_type)
140{
141 int ret = 0;
142 struct wmark_gov_info *wmarkinfo = df->data;
143 enum watermark_type *type = wmark_type;
144
145 switch (event) {
146 case DEVFREQ_GOV_START:
147 devfreq_watermark_start(df);
148 if (df->profile->set_low_wmark)
149 df->profile->set_low_wmark(df->dev.parent, 100);
150 if (df->profile->set_high_wmark)
151 df->profile->set_high_wmark(df->dev.parent, 600);
152 break;
153 case DEVFREQ_GOV_STOP:
154 break;
155 case DEVFREQ_GOV_SUSPEND:
156 devfreq_monitor_suspend(df);
157 break;
158
159 case DEVFREQ_GOV_RESUME:
160 if (df->profile->set_low_wmark)
161 df->profile->set_low_wmark(df->dev.parent, 100);
162 if (df->profile->set_high_wmark)
163 df->profile->set_high_wmark(df->dev.parent, 600);
164 devfreq_monitor_resume(df);
165 break;
166
167 case DEVFREQ_GOV_WMARK:
168 /* Set watermark interrupt type */
169 wmarkinfo->event = *type;
170
171 mutex_lock(&df->lock);
172 update_devfreq(df);
173 mutex_unlock(&df->lock);
174
175 break;
176
177 default:
178 break;
179 }
180
181 return ret;
182}
183
184static struct devfreq_governor devfreq_watermark = {
185 .name = "wmark_simple",
186 .get_target_freq = devfreq_watermark_target_freq,
187 .event_handler = devfreq_watermark_event_handler,
188};
189
190
191static int __init devfreq_watermark_init(void)
192{
193 return devfreq_add_governor(&devfreq_watermark);
194}
195
196static void __exit devfreq_watermark_exit(void)
197{
198 devfreq_remove_governor(&devfreq_watermark);
199}
200
201rootfs_initcall(devfreq_watermark_init);
202module_exit(devfreq_watermark_exit);