blob: e7d373b6c665b907e92b70768e775126abe952a2 [file] [log] [blame]
Saravana Kannanc7a851a2013-09-23 19:27:57 -07001/*
Saravana Kannan922799a2014-01-17 12:51:38 -08002 * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
Saravana Kannanc7a851a2013-09-23 19:27:57 -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) "cpubw-hwmon: " fmt
15
16#include <linux/kernel.h>
17#include <asm/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
33#include <mach/msm-krait-l2-accessors.h>
34
35#define L2PMRESR2 0x412
36#define L2PMCR 0x400
37#define L2PMCNTENCLR 0x402
38#define L2PMCNTENSET 0x403
39#define L2PMINTENCLR 0x404
40#define L2PMINTENSET 0x405
41#define L2PMOVSR 0x406
42#define L2PMOVSSET 0x407
43#define L2PMnEVCNTCR(n) (0x420 + n * 0x10)
44#define L2PMnEVCNTR(n) (0x421 + n * 0x10)
45#define L2PMnEVCNTSR(n) (0x422 + n * 0x10)
46#define L2PMnEVFILTER(n) (0x423 + n * 0x10)
47#define L2PMnEVTYPER(n) (0x424 + n * 0x10)
48
49#define show_attr(name) \
50static ssize_t show_##name(struct device *dev, \
51 struct device_attribute *attr, char *buf) \
52{ \
53 return sprintf(buf, "%u\n", name); \
54}
55
56#define store_attr(name, _min, _max) \
57static ssize_t store_##name(struct device *dev, \
58 struct device_attribute *attr, const char *buf, \
59 size_t count) \
60{ \
61 int ret; \
62 unsigned int val; \
63 ret = sscanf(buf, "%u", &val); \
64 if (ret != 1) \
65 return -EINVAL; \
66 val = max(val, _min); \
67 val = min(val, _max); \
68 name = val; \
69 return count; \
70}
71
72#define gov_attr(__attr, min, max) \
73show_attr(__attr) \
74store_attr(__attr, min, max) \
75static DEVICE_ATTR(__attr, 0644, show_##__attr, store_##__attr)
76
77
78static int l2pm_irq;
79static unsigned int bytes_per_beat;
Saravana Kannanc7a851a2013-09-23 19:27:57 -070080static unsigned int tolerance_percent = 10;
81static unsigned int guard_band_mbps = 100;
82static unsigned int decay_rate = 90;
Saravana Kannan922799a2014-01-17 12:51:38 -080083static unsigned int io_percent = 16;
84static unsigned int bw_step = 190;
Saravana Kannanc7a851a2013-09-23 19:27:57 -070085
Saravana Kannan922799a2014-01-17 12:51:38 -080086#define MIN_MS 10U
87#define MAX_MS 500U
88static unsigned int sample_ms = 50;
Saravana Kannanc7a851a2013-09-23 19:27:57 -070089static u32 prev_r_start_val;
90static u32 prev_w_start_val;
91static unsigned long prev_ab;
92static ktime_t prev_ts;
93
94#define RD_MON 0
95#define WR_MON 1
96static void mon_init(void)
97{
98 /* Set up counters 0/1 to count write/read beats */
99 set_l2_indirect_reg(L2PMRESR2, 0x8B0B0000);
100 set_l2_indirect_reg(L2PMnEVCNTCR(RD_MON), 0x0);
101 set_l2_indirect_reg(L2PMnEVCNTCR(WR_MON), 0x0);
102 set_l2_indirect_reg(L2PMnEVCNTR(RD_MON), 0xFFFFFFFF);
103 set_l2_indirect_reg(L2PMnEVCNTR(WR_MON), 0xFFFFFFFF);
104 set_l2_indirect_reg(L2PMnEVFILTER(RD_MON), 0xF003F);
105 set_l2_indirect_reg(L2PMnEVFILTER(WR_MON), 0xF003F);
106 set_l2_indirect_reg(L2PMnEVTYPER(RD_MON), 0xA);
107 set_l2_indirect_reg(L2PMnEVTYPER(WR_MON), 0xB);
108}
109
110static void global_mon_enable(bool en)
111{
112 u32 regval;
113
114 /* Global counter enable */
115 regval = get_l2_indirect_reg(L2PMCR);
116 if (en)
117 regval |= BIT(0);
118 else
119 regval &= ~BIT(0);
120 set_l2_indirect_reg(L2PMCR, regval);
121}
122
123static void mon_enable(int n)
124{
125 /* Clear previous overflow state for event counter n */
126 set_l2_indirect_reg(L2PMOVSR, BIT(n));
127
128 /* Enable event counter n */
129 set_l2_indirect_reg(L2PMCNTENSET, BIT(n));
130}
131
132static void mon_disable(int n)
133{
134 /* Disable event counter n */
135 set_l2_indirect_reg(L2PMCNTENCLR, BIT(n));
136}
137
138static void mon_irq_enable(int n, bool en)
139{
140 if (en)
141 set_l2_indirect_reg(L2PMINTENSET, BIT(n));
142 else
143 set_l2_indirect_reg(L2PMINTENCLR, BIT(n));
144}
145
146/* Returns start counter value to be used with mon_get_mbps() */
147static u32 mon_set_limit_mbyte(int n, unsigned int mbytes)
148{
149 u32 regval, beats;
150
151 beats = mult_frac(mbytes, SZ_1M, bytes_per_beat);
152 regval = 0xFFFFFFFF - beats;
153 set_l2_indirect_reg(L2PMnEVCNTR(n), regval);
154 pr_debug("EV%d MB: %d, start val: %x\n", n, mbytes, regval);
155
156 return regval;
157}
158
159long mon_get_count(int n, u32 start_val)
160{
161 u32 overflow, count;
162
163 count = get_l2_indirect_reg(L2PMnEVCNTR(n));
164 overflow = get_l2_indirect_reg(L2PMOVSR);
165
166 pr_debug("EV%d ov: %x, cnt: %x\n", n, overflow, count);
167
168 if (overflow & BIT(n))
169 return 0xFFFFFFFF - start_val + count;
170 else
171 return count - start_val;
172}
173
174/* Returns MBps of read/writes for the sampling window. */
175unsigned int beats_to_mbps(long long beats, unsigned int us)
176{
177 beats *= USEC_PER_SEC;
178 beats *= bytes_per_beat;
179 do_div(beats, us);
180 beats = DIV_ROUND_UP_ULL(beats, SZ_1M);
181
182 return beats;
183}
184
185static int to_limit(int mbps)
186{
187 mbps *= (100 + tolerance_percent) * sample_ms;
188 mbps /= 100;
189 mbps = DIV_ROUND_UP(mbps, MSEC_PER_SEC);
190 return mbps;
191}
192
193unsigned long measure_bw_and_set_irq(void)
194{
195 long r_mbps, w_mbps, mbps;
196 ktime_t ts;
197 unsigned int us;
198
199 /*
200 * Since we are stopping the counters, we don't want this short work
201 * to be interrupted by other tasks and cause the measurements to be
202 * wrong. Not blocking interrupts to avoid affecting interrupt
203 * latency and since they should be short anyway because they run in
204 * atomic context.
205 */
206 preempt_disable();
207
208 ts = ktime_get();
209 us = ktime_to_us(ktime_sub(ts, prev_ts));
210 if (!us)
211 us = 1;
212
213 mon_disable(RD_MON);
214 mon_disable(WR_MON);
215
216 r_mbps = mon_get_count(RD_MON, prev_r_start_val);
217 r_mbps = beats_to_mbps(r_mbps, us);
218 w_mbps = mon_get_count(WR_MON, prev_w_start_val);
219 w_mbps = beats_to_mbps(w_mbps, us);
220
221 prev_r_start_val = mon_set_limit_mbyte(RD_MON, to_limit(r_mbps));
222 prev_w_start_val = mon_set_limit_mbyte(WR_MON, to_limit(w_mbps));
223 prev_ts = ts;
224
225 mon_enable(RD_MON);
226 mon_enable(WR_MON);
227
228 preempt_enable();
229
230 mbps = r_mbps + w_mbps;
231 pr_debug("R/W/BW/us = %ld/%ld/%ld/%d\n", r_mbps, w_mbps, mbps, us);
232
233 return mbps;
234}
235
236static void compute_bw(int mbps, unsigned long *freq, unsigned long *ab)
237{
238 int new_bw;
239
240 mbps += guard_band_mbps;
241
242 if (mbps > prev_ab) {
243 new_bw = mbps;
244 } else {
245 new_bw = mbps * decay_rate + prev_ab * (100 - decay_rate);
246 new_bw /= 100;
247 }
248
249 *ab = roundup(mbps, bw_step);
Saravana Kannan922799a2014-01-17 12:51:38 -0800250 *freq = (mbps * 100) / io_percent;
Saravana Kannanc7a851a2013-09-23 19:27:57 -0700251}
252
253#define TOO_SOON_US (1 * USEC_PER_MSEC)
254static irqreturn_t mon_intr_handler(int irq, void *dev)
255{
256 struct devfreq *df = dev;
257 ktime_t ts;
258 unsigned int us;
259 u32 regval;
260 int ret;
261
262 regval = get_l2_indirect_reg(L2PMOVSR);
263 pr_debug("Got interrupt: %x\n", regval);
264
265 devfreq_monitor_stop(df);
266
267 /*
268 * Don't recalc bandwidth if the interrupt comes right after a
269 * previous bandwidth calculation. This is done for two reasons:
270 *
271 * 1. Sampling the BW during a very short duration can result in a
272 * very inaccurate measurement due to very short bursts.
273 * 2. This can only happen if the limit was hit very close to the end
274 * of the previous sample period. Which means the current BW
275 * estimate is not very off and doesn't need to be readjusted.
276 */
277 ts = ktime_get();
278 us = ktime_to_us(ktime_sub(ts, prev_ts));
279 if (us > TOO_SOON_US) {
280 mutex_lock(&df->lock);
281 ret = update_devfreq(df);
282 if (ret)
283 pr_err("Unable to update freq on IRQ!\n");
284 mutex_unlock(&df->lock);
285 }
286
287 devfreq_monitor_start(df);
288
289 return IRQ_HANDLED;
290}
291
292static int start_monitoring(struct devfreq *df)
293{
294 int ret, mbyte;
295
296 ret = request_threaded_irq(l2pm_irq, NULL, mon_intr_handler,
297 IRQF_ONESHOT | IRQF_SHARED,
298 "cpubw_hwmon", df);
299 if (ret) {
300 pr_err("Unable to register interrupt handler\n");
301 return ret;
302 }
303
304 mon_init();
305 mon_disable(RD_MON);
306 mon_disable(WR_MON);
307
308 mbyte = (df->previous_freq * io_percent) / (2 * 100);
309 prev_r_start_val = mon_set_limit_mbyte(RD_MON, mbyte);
310 prev_w_start_val = mon_set_limit_mbyte(WR_MON, mbyte);
311 prev_ts = ktime_get();
312 prev_ab = 0;
313
314 mon_irq_enable(RD_MON, true);
315 mon_irq_enable(WR_MON, true);
316 mon_enable(RD_MON);
317 mon_enable(WR_MON);
318 global_mon_enable(true);
319
320 return 0;
321}
322
323static void stop_monitoring(struct devfreq *df)
324{
325 global_mon_enable(false);
326 mon_disable(RD_MON);
327 mon_disable(WR_MON);
328 mon_irq_enable(RD_MON, false);
329 mon_irq_enable(WR_MON, false);
330
331 disable_irq(l2pm_irq);
332 free_irq(l2pm_irq, df);
333}
334
335static int devfreq_cpubw_hwmon_get_freq(struct devfreq *df,
336 unsigned long *freq,
337 u32 *flag)
338{
339 unsigned long mbps;
340
341 mbps = measure_bw_and_set_irq();
342 compute_bw(mbps, freq, df->data);
343 prev_ab = *(unsigned long *) df->data;
344
345 return 0;
346}
347
Saravana Kannanc7a851a2013-09-23 19:27:57 -0700348gov_attr(tolerance_percent, 0U, 30U);
349gov_attr(guard_band_mbps, 0U, 2000U);
350gov_attr(decay_rate, 0U, 100U);
351gov_attr(io_percent, 1U, 100U);
352gov_attr(bw_step, 50U, 1000U);
353
354static struct attribute *dev_attr[] = {
Saravana Kannanc7a851a2013-09-23 19:27:57 -0700355 &dev_attr_tolerance_percent.attr,
356 &dev_attr_guard_band_mbps.attr,
357 &dev_attr_decay_rate.attr,
358 &dev_attr_io_percent.attr,
359 &dev_attr_bw_step.attr,
360 NULL,
361};
362
363static struct attribute_group dev_attr_group = {
364 .name = "cpubw_hwmon",
365 .attrs = dev_attr,
366};
367
368static int devfreq_cpubw_hwmon_ev_handler(struct devfreq *df,
369 unsigned int event, void *data)
370{
371 int ret;
372
373 switch (event) {
374 case DEVFREQ_GOV_START:
375 ret = start_monitoring(df);
376 if (ret)
377 return ret;
378 ret = sysfs_create_group(&df->dev.kobj, &dev_attr_group);
379 if (ret)
380 return ret;
Saravana Kannan922799a2014-01-17 12:51:38 -0800381
382 sample_ms = df->profile->polling_ms;
383 sample_ms = max(MIN_MS, sample_ms);
384 sample_ms = min(MAX_MS, sample_ms);
385 df->profile->polling_ms = sample_ms;
Saravana Kannanc7a851a2013-09-23 19:27:57 -0700386 devfreq_monitor_start(df);
Saravana Kannan922799a2014-01-17 12:51:38 -0800387
Saravana Kannanc7a851a2013-09-23 19:27:57 -0700388 pr_debug("Enabled CPU BW HW monitor governor\n");
389 break;
390
391 case DEVFREQ_GOV_STOP:
392 sysfs_remove_group(&df->dev.kobj, &dev_attr_group);
393 devfreq_monitor_stop(df);
394 *(unsigned long *)df->data = 0;
395 stop_monitoring(df);
396 pr_debug("Disabled CPU BW HW monitor governor\n");
397 break;
398
399 case DEVFREQ_GOV_INTERVAL:
Saravana Kannan922799a2014-01-17 12:51:38 -0800400 sample_ms = *(unsigned int *)data;
401 sample_ms = max(MIN_MS, sample_ms);
402 sample_ms = min(MAX_MS, sample_ms);
403 devfreq_interval_update(df, &sample_ms);
Saravana Kannanc7a851a2013-09-23 19:27:57 -0700404 break;
405 }
406
407 return 0;
408}
409
410static struct devfreq_governor devfreq_cpubw_hwmon = {
411 .name = "cpubw_hwmon",
412 .get_target_freq = devfreq_cpubw_hwmon_get_freq,
413 .event_handler = devfreq_cpubw_hwmon_ev_handler,
414};
415
416static int cpubw_hwmon_driver_probe(struct platform_device *pdev)
417{
418 struct device *dev = &pdev->dev;
419 int ret;
420
421 l2pm_irq = platform_get_irq(pdev, 0);
422 if (l2pm_irq < 0) {
423 pr_err("Unable to get IRQ number\n");
424 return l2pm_irq;
425 }
426
427 ret = of_property_read_u32(dev->of_node, "qcom,bytes-per-beat",
428 &bytes_per_beat);
429 if (ret) {
430 pr_err("Unable to read bytes per beat\n");
431 return ret;
432 }
433
434 ret = devfreq_add_governor(&devfreq_cpubw_hwmon);
435 if (ret) {
436 pr_err("devfreq governor registration failed\n");
437 return ret;
438 }
439
440 return 0;
441}
442
443static struct of_device_id match_table[] = {
444 { .compatible = "qcom,kraitbw-l2pm" },
445 {}
446};
447
448static struct platform_driver cpubw_hwmon_driver = {
449 .probe = cpubw_hwmon_driver_probe,
450 .driver = {
451 .name = "kraitbw-l2pm",
452 .of_match_table = match_table,
453 .owner = THIS_MODULE,
454 },
455};
456
457static int __init cpubw_hwmon_init(void)
458{
459 return platform_driver_register(&cpubw_hwmon_driver);
460}
461module_init(cpubw_hwmon_init);
462
463static void __exit cpubw_hwmon_exit(void)
464{
465 platform_driver_unregister(&cpubw_hwmon_driver);
466}
467module_exit(cpubw_hwmon_exit);
468
469MODULE_DESCRIPTION("HW monitor based CPU DDR bandwidth voting driver");
470MODULE_LICENSE("GPL v2");