blob: f7bb7ebf41eafa06d4c25a4b315dd7e16fbdf1f5 [file] [log] [blame]
Archana Sriram7b8ec632018-11-21 18:23:48 +05301/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
Oleg Perelet5d612102017-04-05 11:03:38 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/devfreq.h>
15#include <linux/module.h>
16#include <linux/msm_adreno_devfreq.h>
17#include <linux/slab.h>
18
19#include "devfreq_trace.h"
20#include "governor.h"
21
22#define MIN_BUSY 1000
23#define LONG_FLOOR 50000
24#define HIST 5
25#define TARGET 80
26#define CAP 75
27/* AB vote is in multiple of BW_STEP Mega bytes */
28#define BW_STEP 160
29
30static void _update_cutoff(struct devfreq_msm_adreno_tz_data *priv,
31 unsigned int norm_max)
32{
33 int i;
34
35 priv->bus.max = norm_max;
36 for (i = 0; i < priv->bus.num; i++) {
37 priv->bus.up[i] = priv->bus.p_up[i] * norm_max / 100;
38 priv->bus.down[i] = priv->bus.p_down[i] * norm_max / 100;
39 }
40}
41
42static inline int devfreq_get_freq_level(struct devfreq *devfreq,
43 unsigned long freq)
44{
45 int lev;
46
47 for (lev = 0; lev < devfreq->profile->max_state; lev++)
48 if (freq == devfreq->profile->freq_table[lev])
49 return lev;
50
51 return -EINVAL;
52}
53
54static int devfreq_gpubw_get_target(struct devfreq *df,
55 unsigned long *freq)
56{
57
58 struct devfreq_msm_adreno_tz_data *priv = df->data;
59 struct msm_busmon_extended_profile *bus_profile = container_of(
60 (df->profile),
61 struct msm_busmon_extended_profile,
62 profile);
63 struct devfreq_dev_status stats;
64 struct xstats b;
65 int result;
66 int level = 0;
67 int act_level;
68 int norm_cycles;
69 int gpu_percent;
70 /*
71 * Normalized AB should at max usage be the gpu_bimc frequency in MHz.
72 * Start with a reasonable value and let the system push it up to max.
73 */
74 static int norm_ab_max = 300;
75 int norm_ab;
76 unsigned long ab_mbytes = 0;
77
78 if (priv == NULL)
79 return 0;
80
81 stats.private_data = &b;
82
83 result = df->profile->get_dev_status(df->dev.parent, &stats);
84
85 *freq = stats.current_frequency;
86
87 priv->bus.total_time += stats.total_time;
88 priv->bus.gpu_time += stats.busy_time;
89 priv->bus.ram_time += b.ram_time;
90 priv->bus.ram_wait += b.ram_wait;
91
92 level = devfreq_get_freq_level(df, stats.current_frequency);
93
94 if (priv->bus.total_time < LONG_FLOOR)
95 return result;
96
97 norm_cycles = (unsigned int)(priv->bus.ram_time + priv->bus.ram_wait) /
98 (unsigned int) priv->bus.total_time;
99 gpu_percent = (100 * (unsigned int)priv->bus.gpu_time) /
100 (unsigned int) priv->bus.total_time;
101
102 /*
103 * If there's a new high watermark, update the cutoffs and send the
104 * FAST hint. Otherwise check the current value against the current
105 * cutoffs.
106 */
107 if (norm_cycles > priv->bus.max) {
108 _update_cutoff(priv, norm_cycles);
109 bus_profile->flag = DEVFREQ_FLAG_FAST_HINT;
110 } else {
111 /* GPU votes for IB not AB so don't under vote the system */
112 norm_cycles = (100 * norm_cycles) / TARGET;
113 act_level = priv->bus.index[level] + b.mod;
114 act_level = (act_level < 0) ? 0 : act_level;
115 act_level = (act_level >= priv->bus.num) ?
116 (priv->bus.num - 1) : act_level;
117 if (norm_cycles > priv->bus.up[act_level] &&
118 gpu_percent > CAP)
119 bus_profile->flag = DEVFREQ_FLAG_FAST_HINT;
120 else if (norm_cycles < priv->bus.down[act_level] && level)
121 bus_profile->flag = DEVFREQ_FLAG_SLOW_HINT;
122 }
123
124 /* Calculate the AB vote based on bus width if defined */
125 if (priv->bus.width) {
126 norm_ab = (unsigned int)priv->bus.ram_time /
127 (unsigned int) priv->bus.total_time;
128 /* Calculate AB in Mega Bytes and roundup in BW_STEP */
129 ab_mbytes = (norm_ab * priv->bus.width * 1000000ULL) >> 20;
130 bus_profile->ab_mbytes = roundup(ab_mbytes, BW_STEP);
131 } else if (bus_profile->flag) {
132 /* Re-calculate the AB percentage for a new IB vote */
133 norm_ab = (unsigned int)priv->bus.ram_time /
134 (unsigned int) priv->bus.total_time;
135 if (norm_ab > norm_ab_max)
136 norm_ab_max = norm_ab;
137 bus_profile->percent_ab = (100 * norm_ab) / norm_ab_max;
138 }
139
140 priv->bus.total_time = 0;
141 priv->bus.gpu_time = 0;
142 priv->bus.ram_time = 0;
143 priv->bus.ram_wait = 0;
144
145 return result;
146}
147
148static int gpubw_start(struct devfreq *devfreq)
149{
150 struct devfreq_msm_adreno_tz_data *priv;
151
152 struct msm_busmon_extended_profile *bus_profile = container_of(
153 (devfreq->profile),
154 struct msm_busmon_extended_profile,
155 profile);
156 unsigned int t1, t2 = 2 * HIST;
157 int i, bus_size;
158
159
160 devfreq->data = bus_profile->private_data;
161 priv = devfreq->data;
162
163 bus_size = sizeof(u32) * priv->bus.num;
164 priv->bus.up = kzalloc(bus_size, GFP_KERNEL);
165 priv->bus.down = kzalloc(bus_size, GFP_KERNEL);
166 priv->bus.p_up = kzalloc(bus_size, GFP_KERNEL);
167 priv->bus.p_down = kzalloc(bus_size, GFP_KERNEL);
168 if (priv->bus.up == NULL || priv->bus.down == NULL ||
169 priv->bus.p_up == NULL || priv->bus.p_down == NULL)
170 return -ENOMEM;
171
172 /* Set up the cut-over percentages for the bus calculation. */
173 for (i = 0; i < priv->bus.num; i++) {
174 t1 = (u32)(100 * priv->bus.ib[i]) /
175 (u32)priv->bus.ib[priv->bus.num - 1];
176 priv->bus.p_up[i] = t1 - HIST;
177 priv->bus.p_down[i] = t2 - 2 * HIST;
178 t2 = t1;
179 }
180 /* Set the upper-most and lower-most bounds correctly. */
181 priv->bus.p_down[0] = 0;
182 priv->bus.p_down[1] = (priv->bus.p_down[1] > (2 * HIST)) ?
183 priv->bus.p_down[1] : (2 * HIST);
184 if (priv->bus.num >= 1)
185 priv->bus.p_up[priv->bus.num - 1] = 100;
186 _update_cutoff(priv, priv->bus.max);
187
188 return 0;
189}
190
191static int gpubw_stop(struct devfreq *devfreq)
192{
193 struct devfreq_msm_adreno_tz_data *priv = devfreq->data;
194
195 if (priv) {
196 kfree(priv->bus.up);
197 kfree(priv->bus.down);
198 kfree(priv->bus.p_up);
199 kfree(priv->bus.p_down);
200 }
201 devfreq->data = NULL;
202 return 0;
203}
204
205static int devfreq_gpubw_event_handler(struct devfreq *devfreq,
206 unsigned int event, void *data)
207{
208 int result = 0;
209 unsigned long freq;
210
211 mutex_lock(&devfreq->lock);
212 freq = devfreq->previous_freq;
213 switch (event) {
214 case DEVFREQ_GOV_START:
215 result = gpubw_start(devfreq);
216 break;
217 case DEVFREQ_GOV_STOP:
218 result = gpubw_stop(devfreq);
219 break;
220 case DEVFREQ_GOV_RESUME:
221 /* TODO ..... */
222 /* ret = update_devfreq(devfreq); */
223 break;
224 case DEVFREQ_GOV_SUSPEND:
225 {
226 struct devfreq_msm_adreno_tz_data *priv = devfreq->data;
Archana Sriram7b8ec632018-11-21 18:23:48 +0530227 if (priv) {
228 priv->bus.total_time = 0;
229 priv->bus.gpu_time = 0;
230 priv->bus.ram_time = 0;
231 }
Oleg Perelet5d612102017-04-05 11:03:38 -0700232 }
233 break;
234 default:
235 result = 0;
236 break;
237 }
238 mutex_unlock(&devfreq->lock);
239 return result;
240}
241
242static struct devfreq_governor devfreq_gpubw = {
243 .name = "gpubw_mon",
244 .get_target_freq = devfreq_gpubw_get_target,
245 .event_handler = devfreq_gpubw_event_handler,
246};
247
248static int __init devfreq_gpubw_init(void)
249{
250 return devfreq_add_governor(&devfreq_gpubw);
251}
252subsys_initcall(devfreq_gpubw_init);
253
254static void __exit devfreq_gpubw_exit(void)
255{
256 int ret;
257
258 ret = devfreq_remove_governor(&devfreq_gpubw);
259 if (ret)
260 pr_err("%s: failed remove governor %d\n", __func__, ret);
261
262}
263module_exit(devfreq_gpubw_exit);
264
265MODULE_DESCRIPTION("GPU bus bandwidth voting driver. Uses VBIF counters");
266MODULE_LICENSE("GPL v2");
267