blob: 81d98d1f82022590538c285f071caee45cb7f79d [file] [log] [blame]
Rohit Gupta5e4358c2014-07-18 16:16:02 -07001/*
Saravana Kannan6f67be82017-09-07 22:22:49 -07002 * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
Rohit Gupta5e4358c2014-07-18 16:16:02 -07003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#define pr_fmt(fmt) "mem_lat: " fmt
15
16#include <linux/kernel.h>
17#include <linux/sizes.h>
18#include <linux/module.h>
19#include <linux/init.h>
20#include <linux/io.h>
21#include <linux/delay.h>
22#include <linux/ktime.h>
23#include <linux/time.h>
24#include <linux/err.h>
25#include <linux/errno.h>
26#include <linux/mutex.h>
27#include <linux/interrupt.h>
28#include <linux/platform_device.h>
29#include <linux/of.h>
30#include <linux/devfreq.h>
31#include "governor.h"
32#include "governor_memlat.h"
33
34#include <trace/events/power.h>
35
36struct memlat_node {
37 unsigned int ratio_ceil;
Rohit Gupta5e4358c2014-07-18 16:16:02 -070038 bool mon_started;
39 struct list_head list;
40 void *orig_data;
41 struct memlat_hwmon *hw;
42 struct devfreq_governor *gov;
43 struct attribute_group *attr_grp;
44};
45
46static LIST_HEAD(memlat_list);
47static DEFINE_MUTEX(list_lock);
48
49static int use_cnt;
50static DEFINE_MUTEX(state_lock);
51
52#define show_attr(name) \
53static ssize_t show_##name(struct device *dev, \
54 struct device_attribute *attr, char *buf) \
55{ \
56 struct devfreq *df = to_devfreq(dev); \
57 struct memlat_node *hw = df->data; \
58 return snprintf(buf, PAGE_SIZE, "%u\n", hw->name); \
59}
60
61#define store_attr(name, _min, _max) \
62static ssize_t store_##name(struct device *dev, \
63 struct device_attribute *attr, const char *buf, \
64 size_t count) \
65{ \
66 struct devfreq *df = to_devfreq(dev); \
67 struct memlat_node *hw = df->data; \
68 int ret; \
69 unsigned int val; \
70 ret = kstrtouint(buf, 10, &val); \
71 if (ret) \
72 return ret; \
73 val = max(val, _min); \
74 val = min(val, _max); \
75 hw->name = val; \
76 return count; \
77}
78
79#define gov_attr(__attr, min, max) \
80show_attr(__attr) \
81store_attr(__attr, min, max) \
82static DEVICE_ATTR(__attr, 0644, show_##__attr, store_##__attr)
83
David Keitel724116e2016-09-13 15:41:52 -070084static ssize_t show_map(struct device *dev, struct device_attribute *attr,
85 char *buf)
86{
87 struct devfreq *df = to_devfreq(dev);
88 struct memlat_node *n = df->data;
89 struct core_dev_map *map = n->hw->freq_map;
90 unsigned int cnt = 0;
91
92 cnt += snprintf(buf, PAGE_SIZE, "Core freq (MHz)\tDevice BW\n");
93
94 while (map->core_mhz && cnt < PAGE_SIZE) {
95 cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%15u\t%9u\n",
96 map->core_mhz, map->target_freq);
97 map++;
98 }
99 if (cnt < PAGE_SIZE)
100 cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "\n");
101
102 return cnt;
103}
104
105static DEVICE_ATTR(freq_map, 0444, show_map, NULL);
106
Rohit Gupta870b1802016-04-13 16:55:04 -0700107static unsigned long core_to_dev_freq(struct memlat_node *node,
108 unsigned long coref)
Rohit Gupta5e4358c2014-07-18 16:16:02 -0700109{
Rohit Gupta5e4358c2014-07-18 16:16:02 -0700110 struct memlat_hwmon *hw = node->hw;
Rohit Gupta870b1802016-04-13 16:55:04 -0700111 struct core_dev_map *map = hw->freq_map;
112 unsigned long freq = 0;
Rohit Gupta5e4358c2014-07-18 16:16:02 -0700113
Rohit Gupta870b1802016-04-13 16:55:04 -0700114 if (!map)
115 goto out;
Rohit Gupta5e4358c2014-07-18 16:16:02 -0700116
Rohit Gupta870b1802016-04-13 16:55:04 -0700117 while (map->core_mhz && map->core_mhz < coref)
118 map++;
119 if (!map->core_mhz)
120 map--;
121 freq = map->target_freq;
Rohit Gupta5e4358c2014-07-18 16:16:02 -0700122
Rohit Gupta870b1802016-04-13 16:55:04 -0700123out:
124 pr_debug("freq: %lu -> dev: %lu\n", coref, freq);
125 return freq;
Rohit Gupta5e4358c2014-07-18 16:16:02 -0700126}
127
128static struct memlat_node *find_memlat_node(struct devfreq *df)
129{
130 struct memlat_node *node, *found = NULL;
131
132 mutex_lock(&list_lock);
133 list_for_each_entry(node, &memlat_list, list)
134 if (node->hw->dev == df->dev.parent ||
135 node->hw->of_node == df->dev.parent->of_node) {
136 found = node;
137 break;
138 }
139 mutex_unlock(&list_lock);
140
141 return found;
142}
143
144static int start_monitor(struct devfreq *df)
145{
146 struct memlat_node *node = df->data;
147 struct memlat_hwmon *hw = node->hw;
148 struct device *dev = df->dev.parent;
149 int ret;
150
151 ret = hw->start_hwmon(hw);
152
153 if (ret) {
154 dev_err(dev, "Unable to start HW monitor! (%d)\n", ret);
155 return ret;
156 }
157
158 devfreq_monitor_start(df);
159
160 node->mon_started = true;
161
162 return 0;
163}
164
165static void stop_monitor(struct devfreq *df)
166{
167 struct memlat_node *node = df->data;
168 struct memlat_hwmon *hw = node->hw;
169
170 node->mon_started = false;
171
172 devfreq_monitor_stop(df);
173 hw->stop_hwmon(hw);
174}
175
176static int gov_start(struct devfreq *df)
177{
178 int ret = 0;
179 struct device *dev = df->dev.parent;
180 struct memlat_node *node;
181 struct memlat_hwmon *hw;
182
183 node = find_memlat_node(df);
184 if (!node) {
185 dev_err(dev, "Unable to find HW monitor!\n");
186 return -ENODEV;
187 }
188 hw = node->hw;
189
190 hw->df = df;
191 node->orig_data = df->data;
192 df->data = node;
193
194 if (start_monitor(df))
195 goto err_start;
196
197 ret = sysfs_create_group(&df->dev.kobj, node->attr_grp);
198 if (ret)
199 goto err_sysfs;
200
201 return 0;
202
203err_sysfs:
204 stop_monitor(df);
205err_start:
206 df->data = node->orig_data;
207 node->orig_data = NULL;
208 hw->df = NULL;
209 return ret;
210}
211
212static void gov_stop(struct devfreq *df)
213{
214 struct memlat_node *node = df->data;
215 struct memlat_hwmon *hw = node->hw;
216
217 sysfs_remove_group(&df->dev.kobj, node->attr_grp);
218 stop_monitor(df);
219 df->data = node->orig_data;
220 node->orig_data = NULL;
221 hw->df = NULL;
222}
223
224static int devfreq_memlat_get_freq(struct devfreq *df,
225 unsigned long *freq)
226{
Rohit Gupta870b1802016-04-13 16:55:04 -0700227 int i, lat_dev;
Rohit Gupta5e4358c2014-07-18 16:16:02 -0700228 struct memlat_node *node = df->data;
Rohit Gupta870b1802016-04-13 16:55:04 -0700229 struct memlat_hwmon *hw = node->hw;
230 unsigned long max_freq = 0;
231 unsigned int ratio;
Rohit Gupta5e4358c2014-07-18 16:16:02 -0700232
Rohit Gupta870b1802016-04-13 16:55:04 -0700233 hw->get_cnt(hw);
Rohit Gupta5e4358c2014-07-18 16:16:02 -0700234
Rohit Gupta870b1802016-04-13 16:55:04 -0700235 for (i = 0; i < hw->num_cores; i++) {
236 ratio = hw->core_stats[i].inst_count;
237
238 if (hw->core_stats[i].mem_count)
239 ratio /= hw->core_stats[i].mem_count;
240
241 trace_memlat_dev_meas(dev_name(df->dev.parent),
242 hw->core_stats[i].id,
243 hw->core_stats[i].inst_count,
244 hw->core_stats[i].mem_count,
245 hw->core_stats[i].freq, ratio);
246
Saravana Kannan6f67be82017-09-07 22:22:49 -0700247 if (!hw->core_stats[i].inst_count
248 || !hw->core_stats[i].freq)
249 continue;
250
251 if (ratio <= node->ratio_ceil
Rohit Gupta870b1802016-04-13 16:55:04 -0700252 && hw->core_stats[i].freq > max_freq) {
253 lat_dev = i;
254 max_freq = hw->core_stats[i].freq;
255 }
256 }
257
258 if (max_freq) {
259 max_freq = core_to_dev_freq(node, max_freq);
260 trace_memlat_dev_update(dev_name(df->dev.parent),
261 hw->core_stats[lat_dev].id,
262 hw->core_stats[lat_dev].inst_count,
263 hw->core_stats[lat_dev].mem_count,
264 hw->core_stats[lat_dev].freq,
265 max_freq);
266 }
267
268 *freq = max_freq;
Rohit Gupta5e4358c2014-07-18 16:16:02 -0700269 return 0;
270}
271
Rohit Gupta870b1802016-04-13 16:55:04 -0700272gov_attr(ratio_ceil, 1U, 10000U);
Rohit Gupta5e4358c2014-07-18 16:16:02 -0700273
274static struct attribute *dev_attr[] = {
275 &dev_attr_ratio_ceil.attr,
David Keitel724116e2016-09-13 15:41:52 -0700276 &dev_attr_freq_map.attr,
Rohit Gupta5e4358c2014-07-18 16:16:02 -0700277 NULL,
278};
279
280static struct attribute_group dev_attr_group = {
281 .name = "mem_latency",
282 .attrs = dev_attr,
283};
284
285#define MIN_MS 10U
286#define MAX_MS 500U
287static int devfreq_memlat_ev_handler(struct devfreq *df,
288 unsigned int event, void *data)
289{
290 int ret;
291 unsigned int sample_ms;
292
293 switch (event) {
294 case DEVFREQ_GOV_START:
295 sample_ms = df->profile->polling_ms;
296 sample_ms = max(MIN_MS, sample_ms);
297 sample_ms = min(MAX_MS, sample_ms);
298 df->profile->polling_ms = sample_ms;
299
300 ret = gov_start(df);
301 if (ret)
302 return ret;
303
304 dev_dbg(df->dev.parent,
305 "Enabled Memory Latency governor\n");
306 break;
307
308 case DEVFREQ_GOV_STOP:
309 gov_stop(df);
310 dev_dbg(df->dev.parent,
311 "Disabled Memory Latency governor\n");
312 break;
313
314 case DEVFREQ_GOV_INTERVAL:
315 sample_ms = *(unsigned int *)data;
316 sample_ms = max(MIN_MS, sample_ms);
317 sample_ms = min(MAX_MS, sample_ms);
318 devfreq_interval_update(df, &sample_ms);
319 break;
320 }
321
322 return 0;
323}
324
325static struct devfreq_governor devfreq_gov_memlat = {
326 .name = "mem_latency",
327 .get_target_freq = devfreq_memlat_get_freq,
328 .event_handler = devfreq_memlat_ev_handler,
329};
330
Rohit Gupta870b1802016-04-13 16:55:04 -0700331#define NUM_COLS 2
332static struct core_dev_map *init_core_dev_map(struct device *dev,
333 char *prop_name)
334{
335 int len, nf, i, j;
336 u32 data;
337 struct core_dev_map *tbl;
338 int ret;
339
340 if (!of_find_property(dev->of_node, prop_name, &len))
341 return NULL;
342 len /= sizeof(data);
343
344 if (len % NUM_COLS || len == 0)
345 return NULL;
346 nf = len / NUM_COLS;
347
348 tbl = devm_kzalloc(dev, (nf + 1) * sizeof(struct core_dev_map),
349 GFP_KERNEL);
350 if (!tbl)
351 return NULL;
352
353 for (i = 0, j = 0; i < nf; i++, j += 2) {
354 ret = of_property_read_u32_index(dev->of_node, prop_name, j,
355 &data);
356 if (ret)
357 return NULL;
358 tbl[i].core_mhz = data / 1000;
359
360 ret = of_property_read_u32_index(dev->of_node, prop_name, j + 1,
361 &data);
362 if (ret)
363 return NULL;
364 tbl[i].target_freq = data;
365 pr_debug("Entry%d CPU:%u, Dev:%u\n", i, tbl[i].core_mhz,
366 tbl[i].target_freq);
367 }
368 tbl[i].core_mhz = 0;
369
370 return tbl;
371}
372
Rohit Gupta5e4358c2014-07-18 16:16:02 -0700373int register_memlat(struct device *dev, struct memlat_hwmon *hw)
374{
375 int ret = 0;
376 struct memlat_node *node;
377
378 if (!hw->dev && !hw->of_node)
379 return -EINVAL;
380
381 node = devm_kzalloc(dev, sizeof(*node), GFP_KERNEL);
382 if (!node)
383 return -ENOMEM;
384
385 node->gov = &devfreq_gov_memlat;
386 node->attr_grp = &dev_attr_group;
387
388 node->ratio_ceil = 10;
Rohit Gupta5e4358c2014-07-18 16:16:02 -0700389 node->hw = hw;
390
Rohit Gupta870b1802016-04-13 16:55:04 -0700391 hw->freq_map = init_core_dev_map(dev, "qcom,core-dev-table");
392 if (!hw->freq_map) {
393 dev_err(dev, "Couldn't find the core-dev freq table!\n");
394 return -EINVAL;
395 }
396
Rohit Gupta5e4358c2014-07-18 16:16:02 -0700397 mutex_lock(&list_lock);
398 list_add_tail(&node->list, &memlat_list);
399 mutex_unlock(&list_lock);
400
401 mutex_lock(&state_lock);
402 if (!use_cnt)
403 ret = devfreq_add_governor(&devfreq_gov_memlat);
404 if (!ret)
405 use_cnt++;
406 mutex_unlock(&state_lock);
407
408 if (!ret)
409 dev_info(dev, "Memory Latency governor registered.\n");
410 else
411 dev_err(dev, "Memory Latency governor registration failed!\n");
412
413 return ret;
414}
415
416MODULE_DESCRIPTION("HW monitor based dev DDR bandwidth voting driver");
417MODULE_LICENSE("GPL v2");