blob: 66bf592844428e0bfd0a64a877e77faba9aa268b [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åg42469832011-02-23 16:51:58 -0800203 etm_writel(t, id, 0x441, 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) {
207 dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800208 etm_lock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100209 return -EFAULT;
210 }
211
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800212 etm_lock(t, id);
213 return 0;
214}
215
216static int trace_stop(struct tracectx *t)
217{
218 int id;
219 int ret;
220 unsigned long timeout = TRACER_TIMEOUT;
221 u32 etb_fc = t->etb_fc;
222
223 for (id = 0; id < t->etm_regs_count; id++) {
224 ret = trace_stop_etm(t, id);
225 if (ret)
226 return ret;
227 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100228
229 etb_unlock(t);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800230 if (etb_fc) {
231 etb_fc |= ETBFF_STOPFL;
232 etb_writel(t, t->etb_fc, ETBR_FORMATTERCTRL);
233 }
234 etb_writel(t, etb_fc | ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100235
236 timeout = TRACER_TIMEOUT;
237 while (etb_readl(t, ETBR_FORMATTERCTRL) &
238 ETBFF_MANUAL_FLUSH && --timeout)
239 ;
240 if (!timeout) {
241 dev_dbg(t->dev, "Waiting for formatter flush to commence "
242 "timed out\n");
243 etb_lock(t);
244 return -EFAULT;
245 }
246
247 etb_writel(t, 0, ETBR_CTRL);
248
249 etb_lock(t);
250
251 t->flags &= ~TRACER_RUNNING;
252
253 return 0;
254}
255
256static int etb_getdatalen(struct tracectx *t)
257{
258 u32 v;
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800259 int wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100260
261 v = etb_readl(t, ETBR_STATUS);
262
263 if (v & 1)
264 return t->etb_bufsz;
265
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100266 wp = etb_readl(t, ETBR_WRITEADDR);
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800267 return wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100268}
269
270/* sysrq+v will always stop the running trace and leave it at that */
271static void etm_dump(void)
272{
273 struct tracectx *t = &tracer;
274 u32 first = 0;
275 int length;
276
277 if (!t->etb_regs) {
278 printk(KERN_INFO "No tracing hardware found\n");
279 return;
280 }
281
282 if (trace_isrunning(t))
283 trace_stop(t);
284
285 etb_unlock(t);
286
287 length = etb_getdatalen(t);
288
289 if (length == t->etb_bufsz)
290 first = etb_readl(t, ETBR_WRITEADDR);
291
292 etb_writel(t, first, ETBR_READADDR);
293
294 printk(KERN_INFO "Trace buffer contents length: %d\n", length);
295 printk(KERN_INFO "--- ETB buffer begin ---\n");
296 for (; length; length--)
297 printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
298 printk(KERN_INFO "\n--- ETB buffer end ---\n");
299
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100300 etb_lock(t);
301}
302
Dmitry Torokhov1495cc92010-08-17 21:15:46 -0700303static void sysrq_etm_dump(int key)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100304{
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800305 if (!mutex_trylock(&tracer.mutex)) {
306 printk(KERN_INFO "Tracing hardware busy\n");
307 return;
308 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100309 dev_dbg(tracer.dev, "Dumping ETB buffer\n");
310 etm_dump();
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800311 mutex_unlock(&tracer.mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100312}
313
314static struct sysrq_key_op sysrq_etm_op = {
315 .handler = sysrq_etm_dump,
316 .help_msg = "ETM buffer dump",
317 .action_msg = "etm",
318};
319
320static int etb_open(struct inode *inode, struct file *file)
321{
322 if (!tracer.etb_regs)
323 return -ENODEV;
324
325 file->private_data = &tracer;
326
327 return nonseekable_open(inode, file);
328}
329
330static ssize_t etb_read(struct file *file, char __user *data,
331 size_t len, loff_t *ppos)
332{
333 int total, i;
334 long length;
335 struct tracectx *t = file->private_data;
336 u32 first = 0;
337 u32 *buf;
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800338 int wpos;
339 int skip;
340 long wlength;
341 loff_t pos = *ppos;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100342
343 mutex_lock(&t->mutex);
344
345 if (trace_isrunning(t)) {
346 length = 0;
347 goto out;
348 }
349
350 etb_unlock(t);
351
352 total = etb_getdatalen(t);
Arve Hjønnevåg3a91f3e2011-02-04 22:38:14 -0800353 if (total == 0 && t->dump_initial_etb)
354 total = t->etb_bufsz;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100355 if (total == t->etb_bufsz)
356 first = etb_readl(t, ETBR_WRITEADDR);
357
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800358 if (pos > total * 4) {
359 skip = 0;
360 wpos = total;
361 } else {
362 skip = (int)pos % 4;
363 wpos = (int)pos / 4;
364 }
365 total -= wpos;
366 first = (first + wpos) % t->etb_bufsz;
367
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100368 etb_writel(t, first, ETBR_READADDR);
369
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800370 wlength = min(total, DIV_ROUND_UP(skip + (int)len, 4));
371 length = min(total * 4 - skip, (int)len);
372 buf = vmalloc(wlength * 4);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100373
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800374 dev_dbg(t->dev, "ETB read %ld bytes to %lld from %ld words at %d\n",
375 length, pos, wlength, first);
376 dev_dbg(t->dev, "ETB buffer length: %d\n", total + wpos);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100377 dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800378 for (i = 0; i < wlength; i++)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100379 buf[i] = etb_readl(t, ETBR_READMEM);
380
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100381 etb_lock(t);
382
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800383 length -= copy_to_user(data, (u8 *)buf + skip, length);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100384 vfree(buf);
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800385 *ppos = pos + length;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100386
387out:
388 mutex_unlock(&t->mutex);
389
390 return length;
391}
392
393static int etb_release(struct inode *inode, struct file *file)
394{
395 /* there's nothing to do here, actually */
396 return 0;
397}
398
399static const struct file_operations etb_fops = {
400 .owner = THIS_MODULE,
401 .read = etb_read,
402 .open = etb_open,
403 .release = etb_release,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200404 .llseek = no_llseek,
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100405};
406
407static struct miscdevice etb_miscdev = {
408 .name = "tracebuf",
409 .minor = 0,
410 .fops = &etb_fops,
411};
412
Ming Lei8e880692011-03-28 06:10:25 +0100413static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100414{
415 struct tracectx *t = &tracer;
416 int ret = 0;
417
418 ret = amba_request_regions(dev, NULL);
419 if (ret)
420 goto out;
421
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800422 mutex_lock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100423 t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
424 if (!t->etb_regs) {
425 ret = -ENOMEM;
426 goto out_release;
427 }
428
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800429 t->dev = &dev->dev;
Arve Hjønnevåg3a91f3e2011-02-04 22:38:14 -0800430 t->dump_initial_etb = true;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100431 amba_set_drvdata(dev, t);
432
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800433 etb_unlock(t);
434 t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
435 dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
436
437 /* make sure trace capture is disabled */
438 etb_writel(t, 0, ETBR_CTRL);
439 etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
440 etb_lock(t);
441 mutex_unlock(&t->mutex);
442
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100443 etb_miscdev.parent = &dev->dev;
444
445 ret = misc_register(&etb_miscdev);
446 if (ret)
447 goto out_unmap;
448
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800449 /* Get optional clock. Currently used to select clock source on omap3 */
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100450 t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800451 if (IS_ERR(t->emu_clk))
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100452 dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800453 else
454 clk_enable(t->emu_clk);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100455
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100456 dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n");
457
458out:
459 return ret;
460
461out_unmap:
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800462 mutex_lock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100463 amba_set_drvdata(dev, NULL);
464 iounmap(t->etb_regs);
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800465 t->etb_regs = NULL;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100466
467out_release:
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800468 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100469 amba_release_regions(dev);
470
471 return ret;
472}
473
474static int etb_remove(struct amba_device *dev)
475{
476 struct tracectx *t = amba_get_drvdata(dev);
477
478 amba_set_drvdata(dev, NULL);
479
480 iounmap(t->etb_regs);
481 t->etb_regs = NULL;
482
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800483 if (!IS_ERR(t->emu_clk)) {
484 clk_disable(t->emu_clk);
485 clk_put(t->emu_clk);
486 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100487
488 amba_release_regions(dev);
489
490 return 0;
491}
492
493static struct amba_id etb_ids[] = {
494 {
495 .id = 0x0003b907,
496 .mask = 0x0007ffff,
497 },
498 { 0, 0 },
499};
500
501static struct amba_driver etb_driver = {
502 .drv = {
503 .name = "etb",
504 .owner = THIS_MODULE,
505 },
506 .probe = etb_probe,
507 .remove = etb_remove,
508 .id_table = etb_ids,
509};
510
511/* use a sysfs file "trace_running" to start/stop tracing */
512static ssize_t trace_running_show(struct kobject *kobj,
513 struct kobj_attribute *attr,
514 char *buf)
515{
516 return sprintf(buf, "%x\n", trace_isrunning(&tracer));
517}
518
519static ssize_t trace_running_store(struct kobject *kobj,
520 struct kobj_attribute *attr,
521 const char *buf, size_t n)
522{
523 unsigned int value;
524 int ret;
525
526 if (sscanf(buf, "%u", &value) != 1)
527 return -EINVAL;
528
529 mutex_lock(&tracer.mutex);
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800530 if (!tracer.etb_regs)
531 ret = -ENODEV;
532 else
533 ret = value ? trace_start(&tracer) : trace_stop(&tracer);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100534 mutex_unlock(&tracer.mutex);
535
536 return ret ? : n;
537}
538
539static struct kobj_attribute trace_running_attr =
540 __ATTR(trace_running, 0644, trace_running_show, trace_running_store);
541
542static ssize_t trace_info_show(struct kobject *kobj,
543 struct kobj_attribute *attr,
544 char *buf)
545{
546 u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
547 int datalen;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800548 int id;
549 int ret;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100550
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800551 mutex_lock(&tracer.mutex);
552 if (tracer.etb_regs) {
553 etb_unlock(&tracer);
554 datalen = etb_getdatalen(&tracer);
555 etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
556 etb_ra = etb_readl(&tracer, ETBR_READADDR);
557 etb_st = etb_readl(&tracer, ETBR_STATUS);
558 etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
559 etb_lock(&tracer);
560 } else {
561 etb_wa = etb_ra = etb_st = etb_fc = ~0;
562 datalen = -1;
563 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100564
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800565 ret = sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100566 "ETBR_WRITEADDR:\t%08x\n"
567 "ETBR_READADDR:\t%08x\n"
568 "ETBR_STATUS:\t%08x\n"
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800569 "ETBR_FORMATTERCTRL:\t%08x\n",
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100570 datalen,
571 tracer.ncmppairs,
572 etb_wa,
573 etb_ra,
574 etb_st,
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800575 etb_fc
576 );
577
578 for (id = 0; id < tracer.etm_regs_count; id++) {
579 etm_unlock(&tracer, id);
580 etm_ctrl = etm_readl(&tracer, id, ETMR_CTRL);
581 etm_st = etm_readl(&tracer, id, ETMR_STATUS);
582 etm_lock(&tracer, id);
583 ret += sprintf(buf + ret, "ETMR_CTRL:\t%08x\n"
584 "ETMR_STATUS:\t%08x\n",
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100585 etm_ctrl,
586 etm_st
587 );
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800588 }
589 mutex_unlock(&tracer.mutex);
590
591 return ret;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100592}
593
594static struct kobj_attribute trace_info_attr =
595 __ATTR(trace_info, 0444, trace_info_show, NULL);
596
597static ssize_t trace_mode_show(struct kobject *kobj,
598 struct kobj_attribute *attr,
599 char *buf)
600{
601 return sprintf(buf, "%d %d\n",
602 !!(tracer.flags & TRACER_CYCLE_ACC),
603 tracer.etm_portsz);
604}
605
606static ssize_t trace_mode_store(struct kobject *kobj,
607 struct kobj_attribute *attr,
608 const char *buf, size_t n)
609{
610 unsigned int cycacc, portsz;
611
612 if (sscanf(buf, "%u %u", &cycacc, &portsz) != 2)
613 return -EINVAL;
614
615 mutex_lock(&tracer.mutex);
616 if (cycacc)
617 tracer.flags |= TRACER_CYCLE_ACC;
618 else
619 tracer.flags &= ~TRACER_CYCLE_ACC;
620
621 tracer.etm_portsz = portsz & 0x0f;
622 mutex_unlock(&tracer.mutex);
623
624 return n;
625}
626
627static struct kobj_attribute trace_mode_attr =
628 __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
629
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800630static ssize_t trace_range_show(struct kobject *kobj,
631 struct kobj_attribute *attr,
632 char *buf)
633{
634 return sprintf(buf, "%08lx %08lx\n",
635 tracer.range_start, tracer.range_end);
636}
637
638static ssize_t trace_range_store(struct kobject *kobj,
639 struct kobj_attribute *attr,
640 const char *buf, size_t n)
641{
642 unsigned long range_start, range_end;
643
644 if (sscanf(buf, "%lx %lx", &range_start, &range_end) != 2)
645 return -EINVAL;
646
647 mutex_lock(&tracer.mutex);
648 tracer.range_start = range_start;
649 tracer.range_end = range_end;
650 mutex_unlock(&tracer.mutex);
651
652 return n;
653}
654
655
656static struct kobj_attribute trace_range_attr =
657 __ATTR(trace_range, 0644, trace_range_show, trace_range_store);
658
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800659static ssize_t trace_data_range_show(struct kobject *kobj,
660 struct kobj_attribute *attr,
661 char *buf)
662{
663 unsigned long range_start;
664 u64 range_end;
665 mutex_lock(&tracer.mutex);
666 range_start = tracer.data_range_start;
667 range_end = tracer.data_range_end;
668 if (!range_end && (tracer.flags & TRACER_TRACE_DATA))
669 range_end = 0x100000000ULL;
670 mutex_unlock(&tracer.mutex);
671 return sprintf(buf, "%08lx %08llx\n", range_start, range_end);
672}
673
674static ssize_t trace_data_range_store(struct kobject *kobj,
675 struct kobj_attribute *attr,
676 const char *buf, size_t n)
677{
678 unsigned long range_start;
679 u64 range_end;
680
681 if (sscanf(buf, "%lx %llx", &range_start, &range_end) != 2)
682 return -EINVAL;
683
684 mutex_lock(&tracer.mutex);
685 tracer.data_range_start = range_start;
686 tracer.data_range_end = (unsigned long)range_end;
687 if (range_end)
688 tracer.flags |= TRACER_TRACE_DATA;
689 else
690 tracer.flags &= ~TRACER_TRACE_DATA;
691 mutex_unlock(&tracer.mutex);
692
693 return n;
694}
695
696
697static struct kobj_attribute trace_data_range_attr =
698 __ATTR(trace_data_range, 0644,
699 trace_data_range_show, trace_data_range_store);
700
Ming Lei8e880692011-03-28 06:10:25 +0100701static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100702{
703 struct tracectx *t = &tracer;
704 int ret = 0;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800705 void __iomem **new_regs;
706 int new_count;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100707
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800708 mutex_lock(&t->mutex);
709 new_count = t->etm_regs_count + 1;
710 new_regs = krealloc(t->etm_regs,
711 sizeof(t->etm_regs[0]) * new_count, GFP_KERNEL);
712
713 if (!new_regs) {
714 dev_dbg(&dev->dev, "Failed to allocate ETM register array\n");
715 ret = -ENOMEM;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100716 goto out;
717 }
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800718 t->etm_regs = new_regs;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100719
720 ret = amba_request_regions(dev, NULL);
721 if (ret)
722 goto out;
723
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800724 t->etm_regs[t->etm_regs_count] =
725 ioremap_nocache(dev->res.start, resource_size(&dev->res));
726 if (!t->etm_regs[t->etm_regs_count]) {
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100727 ret = -ENOMEM;
728 goto out_release;
729 }
730
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800731 amba_set_drvdata(dev, t->etm_regs[t->etm_regs_count]);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100732
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800733 t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100734 t->etm_portsz = 1;
735
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800736 etm_unlock(t, t->etm_regs_count);
737 (void)etm_readl(t, t->etm_regs_count, ETMMR_PDSR);
Alexander Shishkin988257c2010-08-04 11:27:33 +0100738 /* dummy first read */
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800739 (void)etm_readl(&tracer, t->etm_regs_count, ETMMR_OSSRR);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100740
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800741 t->ncmppairs = etm_readl(t, t->etm_regs_count, ETMR_CONFCODE) & 0xf;
Arve Hjønnevåg42469832011-02-23 16:51:58 -0800742 etm_writel(t, t->etm_regs_count, 0x441, ETMR_CTRL);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800743 etm_writel(t, t->etm_regs_count, new_count, ETMR_TRACEIDR);
744 etm_lock(t, t->etm_regs_count);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100745
746 ret = sysfs_create_file(&dev->dev.kobj,
747 &trace_running_attr.attr);
748 if (ret)
749 goto out_unmap;
750
751 /* failing to create any of these two is not fatal */
752 ret = sysfs_create_file(&dev->dev.kobj, &trace_info_attr.attr);
753 if (ret)
754 dev_dbg(&dev->dev, "Failed to create trace_info in sysfs\n");
755
756 ret = sysfs_create_file(&dev->dev.kobj, &trace_mode_attr.attr);
757 if (ret)
758 dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n");
759
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800760 ret = sysfs_create_file(&dev->dev.kobj, &trace_range_attr.attr);
761 if (ret)
762 dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n");
763
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800764 ret = sysfs_create_file(&dev->dev.kobj, &trace_data_range_attr.attr);
765 if (ret)
766 dev_dbg(&dev->dev,
767 "Failed to create trace_data_range in sysfs\n");
768
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800769 dev_dbg(&dev->dev, "ETM AMBA driver initialized.\n");
770
771 /* Enable formatter if there are multiple trace sources */
772 if (new_count > 1)
773 t->etb_fc = ETBFF_ENFCONT | ETBFF_ENFTC;
774
775 t->etm_regs_count = new_count;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100776
777out:
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800778 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100779 return ret;
780
781out_unmap:
782 amba_set_drvdata(dev, NULL);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800783 iounmap(t->etm_regs[t->etm_regs_count]);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100784
785out_release:
786 amba_release_regions(dev);
787
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800788 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100789 return ret;
790}
791
792static int etm_remove(struct amba_device *dev)
793{
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800794 int i;
795 struct tracectx *t = &tracer;
796 void __iomem *etm_regs = amba_get_drvdata(dev);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100797
798 sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr);
799 sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
800 sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr);
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800801 sysfs_remove_file(&dev->dev.kobj, &trace_range_attr.attr);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800802 sysfs_remove_file(&dev->dev.kobj, &trace_data_range_attr.attr);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100803
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800804 amba_set_drvdata(dev, NULL);
805
806 mutex_lock(&t->mutex);
807 for (i = 0; i < t->etm_regs_count; i++)
808 if (t->etm_regs[i] == etm_regs)
809 break;
810 for (; i < t->etm_regs_count - 1; i++)
811 t->etm_regs[i] = t->etm_regs[i + 1];
812 t->etm_regs_count--;
813 if (!t->etm_regs_count) {
814 kfree(t->etm_regs);
815 t->etm_regs = NULL;
816 }
817 mutex_unlock(&t->mutex);
818
819 iounmap(etm_regs);
820 amba_release_regions(dev);
821
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100822 return 0;
823}
824
825static struct amba_id etm_ids[] = {
826 {
827 .id = 0x0003b921,
828 .mask = 0x0007ffff,
829 },
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800830 {
831 .id = 0x0003b950,
832 .mask = 0x0007ffff,
833 },
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100834 { 0, 0 },
835};
836
837static struct amba_driver etm_driver = {
838 .drv = {
839 .name = "etm",
840 .owner = THIS_MODULE,
841 },
842 .probe = etm_probe,
843 .remove = etm_remove,
844 .id_table = etm_ids,
845};
846
847static int __init etm_init(void)
848{
849 int retval;
850
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800851 mutex_init(&tracer.mutex);
852
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100853 retval = amba_driver_register(&etb_driver);
854 if (retval) {
855 printk(KERN_ERR "Failed to register etb\n");
856 return retval;
857 }
858
859 retval = amba_driver_register(&etm_driver);
860 if (retval) {
861 amba_driver_unregister(&etb_driver);
862 printk(KERN_ERR "Failed to probe etm\n");
863 return retval;
864 }
865
866 /* not being able to install this handler is not fatal */
867 (void)register_sysrq_key('v', &sysrq_etm_op);
868
869 return 0;
870}
871
872device_initcall(etm_init);
873