blob: bad28deb698dac24d9f294947f398bae0ad38cb5 [file] [log] [blame]
Alexander Shishkinc5d6c772009-12-01 14:00:51 +01001/*
2 * linux/arch/arm/kernel/etm.c
3 *
4 * Driver for ARM's Embedded Trace Macrocell and Embedded Trace Buffer.
5 *
6 * Copyright (C) 2009 Nokia Corporation.
7 * Alexander Shishkin
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/types.h>
17#include <linux/io.h>
Arve Hjønnevåg992cd592011-02-04 22:38:14 -080018#include <linux/slab.h>
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010019#include <linux/sysrq.h>
20#include <linux/device.h>
21#include <linux/clk.h>
22#include <linux/amba/bus.h>
23#include <linux/fs.h>
24#include <linux/uaccess.h>
25#include <linux/miscdevice.h>
26#include <linux/vmalloc.h>
27#include <linux/mutex.h>
Paul Gortmaker73017a52011-07-31 16:14:14 -040028#include <linux/module.h>
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010029#include <asm/hardware/coresight.h>
30#include <asm/sections.h>
31
32MODULE_LICENSE("GPL");
33MODULE_AUTHOR("Alexander Shishkin");
34
Alexander Shishkin8234eae2010-08-04 11:22:43 +010035/*
36 * ETM tracer state
37 */
38struct tracectx {
39 unsigned int etb_bufsz;
40 void __iomem *etb_regs;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -080041 void __iomem **etm_regs;
42 int etm_regs_count;
Alexander Shishkin8234eae2010-08-04 11:22:43 +010043 unsigned long flags;
44 int ncmppairs;
45 int etm_portsz;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -080046 u32 etb_fc;
Arve Hjønnevågd71c6952011-01-28 23:44:43 -080047 unsigned long range_start;
48 unsigned long range_end;
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -080049 unsigned long data_range_start;
50 unsigned long data_range_end;
Arve Hjønnevåg3a91f3e2011-02-04 22:38:14 -080051 bool dump_initial_etb;
Alexander Shishkin8234eae2010-08-04 11:22:43 +010052 struct device *dev;
53 struct clk *emu_clk;
54 struct mutex mutex;
55};
56
Arve Hjønnevågd71c6952011-01-28 23:44:43 -080057static struct tracectx tracer = {
58 .range_start = (unsigned long)_stext,
59 .range_end = (unsigned long)_etext,
60};
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010061
62static inline bool trace_isrunning(struct tracectx *t)
63{
64 return !!(t->flags & TRACER_RUNNING);
65}
66
Arve Hjønnevåg992cd592011-02-04 22:38:14 -080067static int etm_setup_address_range(struct tracectx *t, int id, int n,
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010068 unsigned long start, unsigned long end, int exclude, int data)
69{
Arve Hjønnevåg8511b5b2011-01-28 23:33:11 -080070 u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_IGNSECURITY |
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010071 ETMAAT_NOVALCMP;
72
73 if (n < 1 || n > t->ncmppairs)
74 return -EINVAL;
75
76 /* comparators and ranges are numbered starting with 1 as opposed
77 * to bits in a word */
78 n--;
79
80 if (data)
81 flags |= ETMAAT_DLOADSTORE;
82 else
83 flags |= ETMAAT_IEXEC;
84
85 /* first comparator for the range */
Arve Hjønnevåg992cd592011-02-04 22:38:14 -080086 etm_writel(t, id, flags, ETMR_COMP_ACC_TYPE(n * 2));
87 etm_writel(t, id, start, ETMR_COMP_VAL(n * 2));
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010088
89 /* second comparator is right next to it */
Arve Hjønnevåg992cd592011-02-04 22:38:14 -080090 etm_writel(t, id, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
91 etm_writel(t, id, end, ETMR_COMP_VAL(n * 2 + 1));
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010092
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -080093 if (data) {
94 flags = exclude ? ETMVDC3_EXCLONLY : 0;
95 if (exclude)
96 n += 8;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -080097 etm_writel(t, id, flags | BIT(n), ETMR_VIEWDATACTRL3);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -080098 } else {
99 flags = exclude ? ETMTE_INCLEXCL : 0;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800100 etm_writel(t, id, flags | (1 << n), ETMR_TRACEENCTRL);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800101 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100102
103 return 0;
104}
105
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800106static int trace_start_etm(struct tracectx *t, int id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100107{
108 u32 v;
109 unsigned long timeout = TRACER_TIMEOUT;
110
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100111 v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz);
112
113 if (t->flags & TRACER_CYCLE_ACC)
114 v |= ETMCTRL_CYCLEACCURATE;
115
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800116 if (t->flags & TRACER_TRACE_DATA)
117 v |= ETMCTRL_DATA_DO_ADDR;
118
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800119 etm_unlock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100120
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800121 etm_writel(t, id, v, ETMR_CTRL);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100122
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800123 while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100124 ;
125 if (!timeout) {
126 dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800127 etm_lock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100128 return -EFAULT;
129 }
130
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800131 if (t->range_start || t->range_end)
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800132 etm_setup_address_range(t, id, 1,
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800133 t->range_start, t->range_end, 0, 0);
134 else
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800135 etm_writel(t, id, ETMTE_INCLEXCL, ETMR_TRACEENCTRL);
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800136
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800137 etm_writel(t, id, 0, ETMR_TRACEENCTRL2);
138 etm_writel(t, id, 0, ETMR_TRACESSCTRL);
139 etm_writel(t, id, 0x6f, ETMR_TRACEENEVT);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100140
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800141 etm_writel(t, id, 0, ETMR_VIEWDATACTRL1);
142 etm_writel(t, id, 0, ETMR_VIEWDATACTRL2);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800143
144 if (t->data_range_start || t->data_range_end)
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800145 etm_setup_address_range(t, id, 2, t->data_range_start,
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800146 t->data_range_end, 0, 1);
147 else
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800148 etm_writel(t, id, ETMVDC3_EXCLONLY, ETMR_VIEWDATACTRL3);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800149
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800150 etm_writel(t, id, 0x6f, ETMR_VIEWDATAEVT);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800151
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100152 v &= ~ETMCTRL_PROGRAM;
153 v |= ETMCTRL_PORTSEL;
154
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800155 etm_writel(t, id, v, ETMR_CTRL);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100156
157 timeout = TRACER_TIMEOUT;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800158 while (etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100159 ;
160 if (!timeout) {
161 dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n");
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800162 etm_lock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100163 return -EFAULT;
164 }
165
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800166 etm_lock(t, id);
167 return 0;
168}
169
170static int trace_start(struct tracectx *t)
171{
172 int ret;
173 int id;
174 u32 etb_fc = t->etb_fc;
175
176 etb_unlock(t);
177
178 t->dump_initial_etb = false;
179 etb_writel(t, 0, ETBR_WRITEADDR);
180 etb_writel(t, etb_fc, ETBR_FORMATTERCTRL);
181 etb_writel(t, 1, ETBR_CTRL);
182
183 etb_lock(t);
184
185 /* configure etm(s) */
186 for (id = 0; id < t->etm_regs_count; id++) {
187 ret = trace_start_etm(t, id);
188 if (ret)
189 return ret;
190 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100191
192 t->flags |= TRACER_RUNNING;
193
194 return 0;
195}
196
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800197static int trace_stop_etm(struct tracectx *t, int id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100198{
199 unsigned long timeout = TRACER_TIMEOUT;
200
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800201 etm_unlock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100202
Arve Hjønnevågeff62a82012-03-28 21:03:13 -0700203 etm_writel(t, id, 0x440, ETMR_CTRL);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800204 while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100205 ;
206 if (!timeout) {
Arve Hjønnevågeff62a82012-03-28 21:03:13 -0700207 dev_err(t->dev,
208 "etm%d: Waiting for progbit to assert timed out\n",
209 id);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800210 etm_lock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100211 return -EFAULT;
212 }
213
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800214 etm_lock(t, id);
215 return 0;
216}
217
Arve Hjønnevågeff62a82012-03-28 21:03:13 -0700218static int trace_power_down_etm(struct tracectx *t, int id)
219{
220 unsigned long timeout = TRACER_TIMEOUT;
221 etm_unlock(t, id);
222 while (!(etm_readl(t, id, ETMR_STATUS) & ETMST_PROGBIT) && --timeout)
223 ;
224 if (!timeout) {
225 dev_err(t->dev, "etm%d: Waiting for status progbit to assert timed out\n",
226 id);
227 etm_lock(t, id);
228 return -EFAULT;
229 }
230
231 etm_writel(t, id, 0x441, ETMR_CTRL);
232
233 etm_lock(t, id);
234 return 0;
235}
236
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800237static int trace_stop(struct tracectx *t)
238{
239 int id;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800240 unsigned long timeout = TRACER_TIMEOUT;
241 u32 etb_fc = t->etb_fc;
242
Arve Hjønnevågeff62a82012-03-28 21:03:13 -0700243 for (id = 0; id < t->etm_regs_count; id++)
244 trace_stop_etm(t, id);
245
246 for (id = 0; id < t->etm_regs_count; id++)
247 trace_power_down_etm(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100248
249 etb_unlock(t);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800250 if (etb_fc) {
251 etb_fc |= ETBFF_STOPFL;
252 etb_writel(t, t->etb_fc, ETBR_FORMATTERCTRL);
253 }
254 etb_writel(t, etb_fc | ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100255
256 timeout = TRACER_TIMEOUT;
257 while (etb_readl(t, ETBR_FORMATTERCTRL) &
258 ETBFF_MANUAL_FLUSH && --timeout)
259 ;
260 if (!timeout) {
261 dev_dbg(t->dev, "Waiting for formatter flush to commence "
262 "timed out\n");
263 etb_lock(t);
264 return -EFAULT;
265 }
266
267 etb_writel(t, 0, ETBR_CTRL);
268
269 etb_lock(t);
270
271 t->flags &= ~TRACER_RUNNING;
272
273 return 0;
274}
275
276static int etb_getdatalen(struct tracectx *t)
277{
278 u32 v;
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800279 int wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100280
281 v = etb_readl(t, ETBR_STATUS);
282
283 if (v & 1)
284 return t->etb_bufsz;
285
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100286 wp = etb_readl(t, ETBR_WRITEADDR);
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800287 return wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100288}
289
290/* sysrq+v will always stop the running trace and leave it at that */
291static void etm_dump(void)
292{
293 struct tracectx *t = &tracer;
294 u32 first = 0;
295 int length;
296
297 if (!t->etb_regs) {
298 printk(KERN_INFO "No tracing hardware found\n");
299 return;
300 }
301
302 if (trace_isrunning(t))
303 trace_stop(t);
304
305 etb_unlock(t);
306
307 length = etb_getdatalen(t);
308
309 if (length == t->etb_bufsz)
310 first = etb_readl(t, ETBR_WRITEADDR);
311
312 etb_writel(t, first, ETBR_READADDR);
313
314 printk(KERN_INFO "Trace buffer contents length: %d\n", length);
315 printk(KERN_INFO "--- ETB buffer begin ---\n");
316 for (; length; length--)
317 printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
318 printk(KERN_INFO "\n--- ETB buffer end ---\n");
319
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100320 etb_lock(t);
321}
322
Dmitry Torokhov1495cc92010-08-17 21:15:46 -0700323static void sysrq_etm_dump(int key)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100324{
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800325 if (!mutex_trylock(&tracer.mutex)) {
326 printk(KERN_INFO "Tracing hardware busy\n");
327 return;
328 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100329 dev_dbg(tracer.dev, "Dumping ETB buffer\n");
330 etm_dump();
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800331 mutex_unlock(&tracer.mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100332}
333
334static struct sysrq_key_op sysrq_etm_op = {
335 .handler = sysrq_etm_dump,
336 .help_msg = "ETM buffer dump",
337 .action_msg = "etm",
338};
339
340static int etb_open(struct inode *inode, struct file *file)
341{
342 if (!tracer.etb_regs)
343 return -ENODEV;
344
345 file->private_data = &tracer;
346
347 return nonseekable_open(inode, file);
348}
349
350static ssize_t etb_read(struct file *file, char __user *data,
351 size_t len, loff_t *ppos)
352{
353 int total, i;
354 long length;
355 struct tracectx *t = file->private_data;
356 u32 first = 0;
357 u32 *buf;
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800358 int wpos;
359 int skip;
360 long wlength;
361 loff_t pos = *ppos;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100362
363 mutex_lock(&t->mutex);
364
365 if (trace_isrunning(t)) {
366 length = 0;
367 goto out;
368 }
369
370 etb_unlock(t);
371
372 total = etb_getdatalen(t);
Arve Hjønnevåg3a91f3e2011-02-04 22:38:14 -0800373 if (total == 0 && t->dump_initial_etb)
374 total = t->etb_bufsz;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100375 if (total == t->etb_bufsz)
376 first = etb_readl(t, ETBR_WRITEADDR);
377
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800378 if (pos > total * 4) {
379 skip = 0;
380 wpos = total;
381 } else {
382 skip = (int)pos % 4;
383 wpos = (int)pos / 4;
384 }
385 total -= wpos;
386 first = (first + wpos) % t->etb_bufsz;
387
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100388 etb_writel(t, first, ETBR_READADDR);
389
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800390 wlength = min(total, DIV_ROUND_UP(skip + (int)len, 4));
391 length = min(total * 4 - skip, (int)len);
392 buf = vmalloc(wlength * 4);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100393
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800394 dev_dbg(t->dev, "ETB read %ld bytes to %lld from %ld words at %d\n",
395 length, pos, wlength, first);
396 dev_dbg(t->dev, "ETB buffer length: %d\n", total + wpos);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100397 dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800398 for (i = 0; i < wlength; i++)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100399 buf[i] = etb_readl(t, ETBR_READMEM);
400
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100401 etb_lock(t);
402
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800403 length -= copy_to_user(data, (u8 *)buf + skip, length);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100404 vfree(buf);
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800405 *ppos = pos + length;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100406
407out:
408 mutex_unlock(&t->mutex);
409
410 return length;
411}
412
413static int etb_release(struct inode *inode, struct file *file)
414{
415 /* there's nothing to do here, actually */
416 return 0;
417}
418
419static const struct file_operations etb_fops = {
420 .owner = THIS_MODULE,
421 .read = etb_read,
422 .open = etb_open,
423 .release = etb_release,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200424 .llseek = no_llseek,
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100425};
426
427static struct miscdevice etb_miscdev = {
428 .name = "tracebuf",
429 .minor = 0,
430 .fops = &etb_fops,
431};
432
Ming Lei8e880692011-03-28 06:10:25 +0100433static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100434{
435 struct tracectx *t = &tracer;
436 int ret = 0;
437
438 ret = amba_request_regions(dev, NULL);
439 if (ret)
440 goto out;
441
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800442 mutex_lock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100443 t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
444 if (!t->etb_regs) {
445 ret = -ENOMEM;
446 goto out_release;
447 }
448
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800449 t->dev = &dev->dev;
Arve Hjønnevåg3a91f3e2011-02-04 22:38:14 -0800450 t->dump_initial_etb = true;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100451 amba_set_drvdata(dev, t);
452
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800453 etb_unlock(t);
454 t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
455 dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
456
457 /* make sure trace capture is disabled */
458 etb_writel(t, 0, ETBR_CTRL);
459 etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
460 etb_lock(t);
461 mutex_unlock(&t->mutex);
462
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100463 etb_miscdev.parent = &dev->dev;
464
465 ret = misc_register(&etb_miscdev);
466 if (ret)
467 goto out_unmap;
468
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800469 /* Get optional clock. Currently used to select clock source on omap3 */
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100470 t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800471 if (IS_ERR(t->emu_clk))
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100472 dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800473 else
474 clk_enable(t->emu_clk);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100475
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100476 dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n");
477
478out:
479 return ret;
480
481out_unmap:
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800482 mutex_lock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100483 amba_set_drvdata(dev, NULL);
484 iounmap(t->etb_regs);
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800485 t->etb_regs = NULL;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100486
487out_release:
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800488 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100489 amba_release_regions(dev);
490
491 return ret;
492}
493
494static int etb_remove(struct amba_device *dev)
495{
496 struct tracectx *t = amba_get_drvdata(dev);
497
498 amba_set_drvdata(dev, NULL);
499
500 iounmap(t->etb_regs);
501 t->etb_regs = NULL;
502
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800503 if (!IS_ERR(t->emu_clk)) {
504 clk_disable(t->emu_clk);
505 clk_put(t->emu_clk);
506 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100507
508 amba_release_regions(dev);
509
510 return 0;
511}
512
513static struct amba_id etb_ids[] = {
514 {
515 .id = 0x0003b907,
516 .mask = 0x0007ffff,
517 },
518 { 0, 0 },
519};
520
521static struct amba_driver etb_driver = {
522 .drv = {
523 .name = "etb",
524 .owner = THIS_MODULE,
525 },
526 .probe = etb_probe,
527 .remove = etb_remove,
528 .id_table = etb_ids,
529};
530
531/* use a sysfs file "trace_running" to start/stop tracing */
532static ssize_t trace_running_show(struct kobject *kobj,
533 struct kobj_attribute *attr,
534 char *buf)
535{
536 return sprintf(buf, "%x\n", trace_isrunning(&tracer));
537}
538
539static ssize_t trace_running_store(struct kobject *kobj,
540 struct kobj_attribute *attr,
541 const char *buf, size_t n)
542{
543 unsigned int value;
544 int ret;
545
546 if (sscanf(buf, "%u", &value) != 1)
547 return -EINVAL;
548
549 mutex_lock(&tracer.mutex);
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800550 if (!tracer.etb_regs)
551 ret = -ENODEV;
552 else
553 ret = value ? trace_start(&tracer) : trace_stop(&tracer);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100554 mutex_unlock(&tracer.mutex);
555
556 return ret ? : n;
557}
558
559static struct kobj_attribute trace_running_attr =
560 __ATTR(trace_running, 0644, trace_running_show, trace_running_store);
561
562static ssize_t trace_info_show(struct kobject *kobj,
563 struct kobj_attribute *attr,
564 char *buf)
565{
566 u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
567 int datalen;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800568 int id;
569 int ret;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100570
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800571 mutex_lock(&tracer.mutex);
572 if (tracer.etb_regs) {
573 etb_unlock(&tracer);
574 datalen = etb_getdatalen(&tracer);
575 etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
576 etb_ra = etb_readl(&tracer, ETBR_READADDR);
577 etb_st = etb_readl(&tracer, ETBR_STATUS);
578 etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
579 etb_lock(&tracer);
580 } else {
581 etb_wa = etb_ra = etb_st = etb_fc = ~0;
582 datalen = -1;
583 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100584
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800585 ret = sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100586 "ETBR_WRITEADDR:\t%08x\n"
587 "ETBR_READADDR:\t%08x\n"
588 "ETBR_STATUS:\t%08x\n"
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800589 "ETBR_FORMATTERCTRL:\t%08x\n",
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100590 datalen,
591 tracer.ncmppairs,
592 etb_wa,
593 etb_ra,
594 etb_st,
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800595 etb_fc
596 );
597
598 for (id = 0; id < tracer.etm_regs_count; id++) {
599 etm_unlock(&tracer, id);
600 etm_ctrl = etm_readl(&tracer, id, ETMR_CTRL);
601 etm_st = etm_readl(&tracer, id, ETMR_STATUS);
602 etm_lock(&tracer, id);
603 ret += sprintf(buf + ret, "ETMR_CTRL:\t%08x\n"
604 "ETMR_STATUS:\t%08x\n",
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100605 etm_ctrl,
606 etm_st
607 );
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800608 }
609 mutex_unlock(&tracer.mutex);
610
611 return ret;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100612}
613
614static struct kobj_attribute trace_info_attr =
615 __ATTR(trace_info, 0444, trace_info_show, NULL);
616
617static ssize_t trace_mode_show(struct kobject *kobj,
618 struct kobj_attribute *attr,
619 char *buf)
620{
621 return sprintf(buf, "%d %d\n",
622 !!(tracer.flags & TRACER_CYCLE_ACC),
623 tracer.etm_portsz);
624}
625
626static ssize_t trace_mode_store(struct kobject *kobj,
627 struct kobj_attribute *attr,
628 const char *buf, size_t n)
629{
630 unsigned int cycacc, portsz;
631
632 if (sscanf(buf, "%u %u", &cycacc, &portsz) != 2)
633 return -EINVAL;
634
635 mutex_lock(&tracer.mutex);
636 if (cycacc)
637 tracer.flags |= TRACER_CYCLE_ACC;
638 else
639 tracer.flags &= ~TRACER_CYCLE_ACC;
640
641 tracer.etm_portsz = portsz & 0x0f;
642 mutex_unlock(&tracer.mutex);
643
644 return n;
645}
646
647static struct kobj_attribute trace_mode_attr =
648 __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
649
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800650static ssize_t trace_range_show(struct kobject *kobj,
651 struct kobj_attribute *attr,
652 char *buf)
653{
654 return sprintf(buf, "%08lx %08lx\n",
655 tracer.range_start, tracer.range_end);
656}
657
658static ssize_t trace_range_store(struct kobject *kobj,
659 struct kobj_attribute *attr,
660 const char *buf, size_t n)
661{
662 unsigned long range_start, range_end;
663
664 if (sscanf(buf, "%lx %lx", &range_start, &range_end) != 2)
665 return -EINVAL;
666
667 mutex_lock(&tracer.mutex);
668 tracer.range_start = range_start;
669 tracer.range_end = range_end;
670 mutex_unlock(&tracer.mutex);
671
672 return n;
673}
674
675
676static struct kobj_attribute trace_range_attr =
677 __ATTR(trace_range, 0644, trace_range_show, trace_range_store);
678
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800679static ssize_t trace_data_range_show(struct kobject *kobj,
680 struct kobj_attribute *attr,
681 char *buf)
682{
683 unsigned long range_start;
684 u64 range_end;
685 mutex_lock(&tracer.mutex);
686 range_start = tracer.data_range_start;
687 range_end = tracer.data_range_end;
688 if (!range_end && (tracer.flags & TRACER_TRACE_DATA))
689 range_end = 0x100000000ULL;
690 mutex_unlock(&tracer.mutex);
691 return sprintf(buf, "%08lx %08llx\n", range_start, range_end);
692}
693
694static ssize_t trace_data_range_store(struct kobject *kobj,
695 struct kobj_attribute *attr,
696 const char *buf, size_t n)
697{
698 unsigned long range_start;
699 u64 range_end;
700
701 if (sscanf(buf, "%lx %llx", &range_start, &range_end) != 2)
702 return -EINVAL;
703
704 mutex_lock(&tracer.mutex);
705 tracer.data_range_start = range_start;
706 tracer.data_range_end = (unsigned long)range_end;
707 if (range_end)
708 tracer.flags |= TRACER_TRACE_DATA;
709 else
710 tracer.flags &= ~TRACER_TRACE_DATA;
711 mutex_unlock(&tracer.mutex);
712
713 return n;
714}
715
716
717static struct kobj_attribute trace_data_range_attr =
718 __ATTR(trace_data_range, 0644,
719 trace_data_range_show, trace_data_range_store);
720
Ming Lei8e880692011-03-28 06:10:25 +0100721static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100722{
723 struct tracectx *t = &tracer;
724 int ret = 0;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800725 void __iomem **new_regs;
726 int new_count;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100727
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800728 mutex_lock(&t->mutex);
729 new_count = t->etm_regs_count + 1;
730 new_regs = krealloc(t->etm_regs,
731 sizeof(t->etm_regs[0]) * new_count, GFP_KERNEL);
732
733 if (!new_regs) {
734 dev_dbg(&dev->dev, "Failed to allocate ETM register array\n");
735 ret = -ENOMEM;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100736 goto out;
737 }
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800738 t->etm_regs = new_regs;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100739
740 ret = amba_request_regions(dev, NULL);
741 if (ret)
742 goto out;
743
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800744 t->etm_regs[t->etm_regs_count] =
745 ioremap_nocache(dev->res.start, resource_size(&dev->res));
746 if (!t->etm_regs[t->etm_regs_count]) {
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100747 ret = -ENOMEM;
748 goto out_release;
749 }
750
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800751 amba_set_drvdata(dev, t->etm_regs[t->etm_regs_count]);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100752
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800753 t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100754 t->etm_portsz = 1;
755
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800756 etm_unlock(t, t->etm_regs_count);
757 (void)etm_readl(t, t->etm_regs_count, ETMMR_PDSR);
Alexander Shishkin988257c2010-08-04 11:27:33 +0100758 /* dummy first read */
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800759 (void)etm_readl(&tracer, t->etm_regs_count, ETMMR_OSSRR);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100760
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800761 t->ncmppairs = etm_readl(t, t->etm_regs_count, ETMR_CONFCODE) & 0xf;
Arve Hjønnevåg42469832011-02-23 16:51:58 -0800762 etm_writel(t, t->etm_regs_count, 0x441, ETMR_CTRL);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800763 etm_writel(t, t->etm_regs_count, new_count, ETMR_TRACEIDR);
764 etm_lock(t, t->etm_regs_count);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100765
766 ret = sysfs_create_file(&dev->dev.kobj,
767 &trace_running_attr.attr);
768 if (ret)
769 goto out_unmap;
770
771 /* failing to create any of these two is not fatal */
772 ret = sysfs_create_file(&dev->dev.kobj, &trace_info_attr.attr);
773 if (ret)
774 dev_dbg(&dev->dev, "Failed to create trace_info in sysfs\n");
775
776 ret = sysfs_create_file(&dev->dev.kobj, &trace_mode_attr.attr);
777 if (ret)
778 dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n");
779
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800780 ret = sysfs_create_file(&dev->dev.kobj, &trace_range_attr.attr);
781 if (ret)
782 dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n");
783
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800784 ret = sysfs_create_file(&dev->dev.kobj, &trace_data_range_attr.attr);
785 if (ret)
786 dev_dbg(&dev->dev,
787 "Failed to create trace_data_range in sysfs\n");
788
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800789 dev_dbg(&dev->dev, "ETM AMBA driver initialized.\n");
790
791 /* Enable formatter if there are multiple trace sources */
792 if (new_count > 1)
793 t->etb_fc = ETBFF_ENFCONT | ETBFF_ENFTC;
794
795 t->etm_regs_count = new_count;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100796
797out:
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800798 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100799 return ret;
800
801out_unmap:
802 amba_set_drvdata(dev, NULL);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800803 iounmap(t->etm_regs[t->etm_regs_count]);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100804
805out_release:
806 amba_release_regions(dev);
807
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800808 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100809 return ret;
810}
811
812static int etm_remove(struct amba_device *dev)
813{
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800814 int i;
815 struct tracectx *t = &tracer;
816 void __iomem *etm_regs = amba_get_drvdata(dev);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100817
818 sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr);
819 sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
820 sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr);
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800821 sysfs_remove_file(&dev->dev.kobj, &trace_range_attr.attr);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800822 sysfs_remove_file(&dev->dev.kobj, &trace_data_range_attr.attr);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100823
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800824 amba_set_drvdata(dev, NULL);
825
826 mutex_lock(&t->mutex);
827 for (i = 0; i < t->etm_regs_count; i++)
828 if (t->etm_regs[i] == etm_regs)
829 break;
830 for (; i < t->etm_regs_count - 1; i++)
831 t->etm_regs[i] = t->etm_regs[i + 1];
832 t->etm_regs_count--;
833 if (!t->etm_regs_count) {
834 kfree(t->etm_regs);
835 t->etm_regs = NULL;
836 }
837 mutex_unlock(&t->mutex);
838
839 iounmap(etm_regs);
840 amba_release_regions(dev);
841
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100842 return 0;
843}
844
845static struct amba_id etm_ids[] = {
846 {
847 .id = 0x0003b921,
848 .mask = 0x0007ffff,
849 },
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800850 {
851 .id = 0x0003b950,
852 .mask = 0x0007ffff,
853 },
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100854 { 0, 0 },
855};
856
857static struct amba_driver etm_driver = {
858 .drv = {
859 .name = "etm",
860 .owner = THIS_MODULE,
861 },
862 .probe = etm_probe,
863 .remove = etm_remove,
864 .id_table = etm_ids,
865};
866
867static int __init etm_init(void)
868{
869 int retval;
870
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800871 mutex_init(&tracer.mutex);
872
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100873 retval = amba_driver_register(&etb_driver);
874 if (retval) {
875 printk(KERN_ERR "Failed to register etb\n");
876 return retval;
877 }
878
879 retval = amba_driver_register(&etm_driver);
880 if (retval) {
881 amba_driver_unregister(&etb_driver);
882 printk(KERN_ERR "Failed to probe etm\n");
883 return retval;
884 }
885
886 /* not being able to install this handler is not fatal */
887 (void)register_sysrq_key('v', &sysrq_etm_op);
888
889 return 0;
890}
891
892device_initcall(etm_init);
893