blob: f22337bba90da3fefabbcc72392a9d0f3ed811e0 [file] [log] [blame]
Rohit Gupta5e4358c2014-07-18 16:16:02 -07001/*
2 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
3 *
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;
38 unsigned int freq_thresh_mhz;
39 unsigned int mult_factor;
40 bool mon_started;
41 struct list_head list;
42 void *orig_data;
43 struct memlat_hwmon *hw;
44 struct devfreq_governor *gov;
45 struct attribute_group *attr_grp;
46};
47
48static LIST_HEAD(memlat_list);
49static DEFINE_MUTEX(list_lock);
50
51static int use_cnt;
52static DEFINE_MUTEX(state_lock);
53
54#define show_attr(name) \
55static ssize_t show_##name(struct device *dev, \
56 struct device_attribute *attr, char *buf) \
57{ \
58 struct devfreq *df = to_devfreq(dev); \
59 struct memlat_node *hw = df->data; \
60 return snprintf(buf, PAGE_SIZE, "%u\n", hw->name); \
61}
62
63#define store_attr(name, _min, _max) \
64static ssize_t store_##name(struct device *dev, \
65 struct device_attribute *attr, const char *buf, \
66 size_t count) \
67{ \
68 struct devfreq *df = to_devfreq(dev); \
69 struct memlat_node *hw = df->data; \
70 int ret; \
71 unsigned int val; \
72 ret = kstrtouint(buf, 10, &val); \
73 if (ret) \
74 return ret; \
75 val = max(val, _min); \
76 val = min(val, _max); \
77 hw->name = val; \
78 return count; \
79}
80
81#define gov_attr(__attr, min, max) \
82show_attr(__attr) \
83store_attr(__attr, min, max) \
84static DEVICE_ATTR(__attr, 0644, show_##__attr, store_##__attr)
85
86static unsigned long compute_dev_vote(struct devfreq *df)
87{
88 int i, lat_dev;
89 struct memlat_node *node = df->data;
90 struct memlat_hwmon *hw = node->hw;
91 unsigned long max_freq = 0;
92 unsigned int ratio;
93
94 hw->get_cnt(hw);
95
96 for (i = 0; i < hw->num_cores; i++) {
97 ratio = hw->core_stats[i].inst_count;
98
99 if (hw->core_stats[i].mem_count)
100 ratio /= hw->core_stats[i].mem_count;
101
102 trace_memlat_dev_meas(dev_name(df->dev.parent),
103 hw->core_stats[i].id,
104 hw->core_stats[i].inst_count,
105 hw->core_stats[i].mem_count,
106 hw->core_stats[i].freq, ratio);
107
108 if (ratio && ratio <= node->ratio_ceil
109 && hw->core_stats[i].freq >= node->freq_thresh_mhz
110 && hw->core_stats[i].freq > max_freq) {
111 lat_dev = i;
112 max_freq = hw->core_stats[i].freq;
113 }
114 }
115
116 if (max_freq)
117 trace_memlat_dev_update(dev_name(df->dev.parent),
118 hw->core_stats[lat_dev].id,
119 hw->core_stats[lat_dev].inst_count,
120 hw->core_stats[lat_dev].mem_count,
121 hw->core_stats[lat_dev].freq,
122 max_freq * node->mult_factor);
123
124 return max_freq;
125}
126
127static struct memlat_node *find_memlat_node(struct devfreq *df)
128{
129 struct memlat_node *node, *found = NULL;
130
131 mutex_lock(&list_lock);
132 list_for_each_entry(node, &memlat_list, list)
133 if (node->hw->dev == df->dev.parent ||
134 node->hw->of_node == df->dev.parent->of_node) {
135 found = node;
136 break;
137 }
138 mutex_unlock(&list_lock);
139
140 return found;
141}
142
143static int start_monitor(struct devfreq *df)
144{
145 struct memlat_node *node = df->data;
146 struct memlat_hwmon *hw = node->hw;
147 struct device *dev = df->dev.parent;
148 int ret;
149
150 ret = hw->start_hwmon(hw);
151
152 if (ret) {
153 dev_err(dev, "Unable to start HW monitor! (%d)\n", ret);
154 return ret;
155 }
156
157 devfreq_monitor_start(df);
158
159 node->mon_started = true;
160
161 return 0;
162}
163
164static void stop_monitor(struct devfreq *df)
165{
166 struct memlat_node *node = df->data;
167 struct memlat_hwmon *hw = node->hw;
168
169 node->mon_started = false;
170
171 devfreq_monitor_stop(df);
172 hw->stop_hwmon(hw);
173}
174
175static int gov_start(struct devfreq *df)
176{
177 int ret = 0;
178 struct device *dev = df->dev.parent;
179 struct memlat_node *node;
180 struct memlat_hwmon *hw;
181
182 node = find_memlat_node(df);
183 if (!node) {
184 dev_err(dev, "Unable to find HW monitor!\n");
185 return -ENODEV;
186 }
187 hw = node->hw;
188
189 hw->df = df;
190 node->orig_data = df->data;
191 df->data = node;
192
193 if (start_monitor(df))
194 goto err_start;
195
196 ret = sysfs_create_group(&df->dev.kobj, node->attr_grp);
197 if (ret)
198 goto err_sysfs;
199
200 return 0;
201
202err_sysfs:
203 stop_monitor(df);
204err_start:
205 df->data = node->orig_data;
206 node->orig_data = NULL;
207 hw->df = NULL;
208 return ret;
209}
210
211static void gov_stop(struct devfreq *df)
212{
213 struct memlat_node *node = df->data;
214 struct memlat_hwmon *hw = node->hw;
215
216 sysfs_remove_group(&df->dev.kobj, node->attr_grp);
217 stop_monitor(df);
218 df->data = node->orig_data;
219 node->orig_data = NULL;
220 hw->df = NULL;
221}
222
223static int devfreq_memlat_get_freq(struct devfreq *df,
224 unsigned long *freq)
225{
226 unsigned long mhz;
227 struct memlat_node *node = df->data;
228
229 mhz = compute_dev_vote(df);
230 *freq = mhz ? (mhz * node->mult_factor) : 0;
231
232 return 0;
233}
234
235gov_attr(ratio_ceil, 1U, 1000U);
236gov_attr(freq_thresh_mhz, 300U, 5000U);
237gov_attr(mult_factor, 1U, 10U);
238
239static struct attribute *dev_attr[] = {
240 &dev_attr_ratio_ceil.attr,
241 &dev_attr_freq_thresh_mhz.attr,
242 &dev_attr_mult_factor.attr,
243 NULL,
244};
245
246static struct attribute_group dev_attr_group = {
247 .name = "mem_latency",
248 .attrs = dev_attr,
249};
250
251#define MIN_MS 10U
252#define MAX_MS 500U
253static int devfreq_memlat_ev_handler(struct devfreq *df,
254 unsigned int event, void *data)
255{
256 int ret;
257 unsigned int sample_ms;
258
259 switch (event) {
260 case DEVFREQ_GOV_START:
261 sample_ms = df->profile->polling_ms;
262 sample_ms = max(MIN_MS, sample_ms);
263 sample_ms = min(MAX_MS, sample_ms);
264 df->profile->polling_ms = sample_ms;
265
266 ret = gov_start(df);
267 if (ret)
268 return ret;
269
270 dev_dbg(df->dev.parent,
271 "Enabled Memory Latency governor\n");
272 break;
273
274 case DEVFREQ_GOV_STOP:
275 gov_stop(df);
276 dev_dbg(df->dev.parent,
277 "Disabled Memory Latency governor\n");
278 break;
279
280 case DEVFREQ_GOV_INTERVAL:
281 sample_ms = *(unsigned int *)data;
282 sample_ms = max(MIN_MS, sample_ms);
283 sample_ms = min(MAX_MS, sample_ms);
284 devfreq_interval_update(df, &sample_ms);
285 break;
286 }
287
288 return 0;
289}
290
291static struct devfreq_governor devfreq_gov_memlat = {
292 .name = "mem_latency",
293 .get_target_freq = devfreq_memlat_get_freq,
294 .event_handler = devfreq_memlat_ev_handler,
295};
296
297int register_memlat(struct device *dev, struct memlat_hwmon *hw)
298{
299 int ret = 0;
300 struct memlat_node *node;
301
302 if (!hw->dev && !hw->of_node)
303 return -EINVAL;
304
305 node = devm_kzalloc(dev, sizeof(*node), GFP_KERNEL);
306 if (!node)
307 return -ENOMEM;
308
309 node->gov = &devfreq_gov_memlat;
310 node->attr_grp = &dev_attr_group;
311
312 node->ratio_ceil = 10;
313 node->freq_thresh_mhz = 900;
314 node->mult_factor = 8;
315 node->hw = hw;
316
317 mutex_lock(&list_lock);
318 list_add_tail(&node->list, &memlat_list);
319 mutex_unlock(&list_lock);
320
321 mutex_lock(&state_lock);
322 if (!use_cnt)
323 ret = devfreq_add_governor(&devfreq_gov_memlat);
324 if (!ret)
325 use_cnt++;
326 mutex_unlock(&state_lock);
327
328 if (!ret)
329 dev_info(dev, "Memory Latency governor registered.\n");
330 else
331 dev_err(dev, "Memory Latency governor registration failed!\n");
332
333 return ret;
334}
335
336MODULE_DESCRIPTION("HW monitor based dev DDR bandwidth voting driver");
337MODULE_LICENSE("GPL v2");