blob: 460a7d85e626e3ef017f5984535ad3c23897884c [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ågcfb8dc52012-04-02 17:20:32 -0700119 if (t->flags & TRACER_TIMESTAMP)
120 v |= ETMCTRL_TIMESTAMP_EN;
121
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800122 etm_unlock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100123
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800124 etm_writel(t, id, v, ETMR_CTRL);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100125
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800126 while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100127 ;
128 if (!timeout) {
129 dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800130 etm_lock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100131 return -EFAULT;
132 }
133
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800134 if (t->range_start || t->range_end)
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800135 etm_setup_address_range(t, id, 1,
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800136 t->range_start, t->range_end, 0, 0);
137 else
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800138 etm_writel(t, id, ETMTE_INCLEXCL, ETMR_TRACEENCTRL);
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800139
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800140 etm_writel(t, id, 0, ETMR_TRACEENCTRL2);
141 etm_writel(t, id, 0, ETMR_TRACESSCTRL);
142 etm_writel(t, id, 0x6f, ETMR_TRACEENEVT);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100143
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800144 etm_writel(t, id, 0, ETMR_VIEWDATACTRL1);
145 etm_writel(t, id, 0, ETMR_VIEWDATACTRL2);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800146
147 if (t->data_range_start || t->data_range_end)
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800148 etm_setup_address_range(t, id, 2, t->data_range_start,
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800149 t->data_range_end, 0, 1);
150 else
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800151 etm_writel(t, id, ETMVDC3_EXCLONLY, ETMR_VIEWDATACTRL3);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800152
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800153 etm_writel(t, id, 0x6f, ETMR_VIEWDATAEVT);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800154
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100155 v &= ~ETMCTRL_PROGRAM;
156 v |= ETMCTRL_PORTSEL;
157
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800158 etm_writel(t, id, v, ETMR_CTRL);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100159
160 timeout = TRACER_TIMEOUT;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800161 while (etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100162 ;
163 if (!timeout) {
164 dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n");
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800165 etm_lock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100166 return -EFAULT;
167 }
168
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800169 etm_lock(t, id);
170 return 0;
171}
172
173static int trace_start(struct tracectx *t)
174{
175 int ret;
176 int id;
177 u32 etb_fc = t->etb_fc;
178
179 etb_unlock(t);
180
181 t->dump_initial_etb = false;
182 etb_writel(t, 0, ETBR_WRITEADDR);
183 etb_writel(t, etb_fc, ETBR_FORMATTERCTRL);
184 etb_writel(t, 1, ETBR_CTRL);
185
186 etb_lock(t);
187
188 /* configure etm(s) */
189 for (id = 0; id < t->etm_regs_count; id++) {
190 ret = trace_start_etm(t, id);
191 if (ret)
192 return ret;
193 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100194
195 t->flags |= TRACER_RUNNING;
196
197 return 0;
198}
199
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800200static int trace_stop_etm(struct tracectx *t, int id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100201{
202 unsigned long timeout = TRACER_TIMEOUT;
203
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800204 etm_unlock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100205
Arve Hjønnevågeff62a82012-03-28 21:03:13 -0700206 etm_writel(t, id, 0x440, ETMR_CTRL);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800207 while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100208 ;
209 if (!timeout) {
Arve Hjønnevågeff62a82012-03-28 21:03:13 -0700210 dev_err(t->dev,
211 "etm%d: Waiting for progbit to assert timed out\n",
212 id);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800213 etm_lock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100214 return -EFAULT;
215 }
216
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800217 etm_lock(t, id);
218 return 0;
219}
220
Arve Hjønnevågeff62a82012-03-28 21:03:13 -0700221static int trace_power_down_etm(struct tracectx *t, int id)
222{
223 unsigned long timeout = TRACER_TIMEOUT;
224 etm_unlock(t, id);
225 while (!(etm_readl(t, id, ETMR_STATUS) & ETMST_PROGBIT) && --timeout)
226 ;
227 if (!timeout) {
228 dev_err(t->dev, "etm%d: Waiting for status progbit to assert timed out\n",
229 id);
230 etm_lock(t, id);
231 return -EFAULT;
232 }
233
234 etm_writel(t, id, 0x441, ETMR_CTRL);
235
236 etm_lock(t, id);
237 return 0;
238}
239
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800240static int trace_stop(struct tracectx *t)
241{
242 int id;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800243 unsigned long timeout = TRACER_TIMEOUT;
244 u32 etb_fc = t->etb_fc;
245
Arve Hjønnevågeff62a82012-03-28 21:03:13 -0700246 for (id = 0; id < t->etm_regs_count; id++)
247 trace_stop_etm(t, id);
248
249 for (id = 0; id < t->etm_regs_count; id++)
250 trace_power_down_etm(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100251
252 etb_unlock(t);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800253 if (etb_fc) {
254 etb_fc |= ETBFF_STOPFL;
255 etb_writel(t, t->etb_fc, ETBR_FORMATTERCTRL);
256 }
257 etb_writel(t, etb_fc | ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100258
259 timeout = TRACER_TIMEOUT;
260 while (etb_readl(t, ETBR_FORMATTERCTRL) &
261 ETBFF_MANUAL_FLUSH && --timeout)
262 ;
263 if (!timeout) {
264 dev_dbg(t->dev, "Waiting for formatter flush to commence "
265 "timed out\n");
266 etb_lock(t);
267 return -EFAULT;
268 }
269
270 etb_writel(t, 0, ETBR_CTRL);
271
272 etb_lock(t);
273
274 t->flags &= ~TRACER_RUNNING;
275
276 return 0;
277}
278
279static int etb_getdatalen(struct tracectx *t)
280{
281 u32 v;
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800282 int wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100283
284 v = etb_readl(t, ETBR_STATUS);
285
286 if (v & 1)
287 return t->etb_bufsz;
288
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100289 wp = etb_readl(t, ETBR_WRITEADDR);
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800290 return wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100291}
292
293/* sysrq+v will always stop the running trace and leave it at that */
294static void etm_dump(void)
295{
296 struct tracectx *t = &tracer;
297 u32 first = 0;
298 int length;
299
300 if (!t->etb_regs) {
301 printk(KERN_INFO "No tracing hardware found\n");
302 return;
303 }
304
305 if (trace_isrunning(t))
306 trace_stop(t);
307
308 etb_unlock(t);
309
310 length = etb_getdatalen(t);
311
312 if (length == t->etb_bufsz)
313 first = etb_readl(t, ETBR_WRITEADDR);
314
315 etb_writel(t, first, ETBR_READADDR);
316
317 printk(KERN_INFO "Trace buffer contents length: %d\n", length);
318 printk(KERN_INFO "--- ETB buffer begin ---\n");
319 for (; length; length--)
320 printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
321 printk(KERN_INFO "\n--- ETB buffer end ---\n");
322
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100323 etb_lock(t);
324}
325
Dmitry Torokhov1495cc92010-08-17 21:15:46 -0700326static void sysrq_etm_dump(int key)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100327{
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800328 if (!mutex_trylock(&tracer.mutex)) {
329 printk(KERN_INFO "Tracing hardware busy\n");
330 return;
331 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100332 dev_dbg(tracer.dev, "Dumping ETB buffer\n");
333 etm_dump();
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800334 mutex_unlock(&tracer.mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100335}
336
337static struct sysrq_key_op sysrq_etm_op = {
338 .handler = sysrq_etm_dump,
339 .help_msg = "ETM buffer dump",
340 .action_msg = "etm",
341};
342
343static int etb_open(struct inode *inode, struct file *file)
344{
345 if (!tracer.etb_regs)
346 return -ENODEV;
347
348 file->private_data = &tracer;
349
350 return nonseekable_open(inode, file);
351}
352
353static ssize_t etb_read(struct file *file, char __user *data,
354 size_t len, loff_t *ppos)
355{
356 int total, i;
357 long length;
358 struct tracectx *t = file->private_data;
359 u32 first = 0;
360 u32 *buf;
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800361 int wpos;
362 int skip;
363 long wlength;
364 loff_t pos = *ppos;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100365
366 mutex_lock(&t->mutex);
367
368 if (trace_isrunning(t)) {
369 length = 0;
370 goto out;
371 }
372
373 etb_unlock(t);
374
375 total = etb_getdatalen(t);
Arve Hjønnevåg3a91f3e2011-02-04 22:38:14 -0800376 if (total == 0 && t->dump_initial_etb)
377 total = t->etb_bufsz;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100378 if (total == t->etb_bufsz)
379 first = etb_readl(t, ETBR_WRITEADDR);
380
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800381 if (pos > total * 4) {
382 skip = 0;
383 wpos = total;
384 } else {
385 skip = (int)pos % 4;
386 wpos = (int)pos / 4;
387 }
388 total -= wpos;
389 first = (first + wpos) % t->etb_bufsz;
390
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100391 etb_writel(t, first, ETBR_READADDR);
392
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800393 wlength = min(total, DIV_ROUND_UP(skip + (int)len, 4));
394 length = min(total * 4 - skip, (int)len);
395 buf = vmalloc(wlength * 4);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100396
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800397 dev_dbg(t->dev, "ETB read %ld bytes to %lld from %ld words at %d\n",
398 length, pos, wlength, first);
399 dev_dbg(t->dev, "ETB buffer length: %d\n", total + wpos);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100400 dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800401 for (i = 0; i < wlength; i++)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100402 buf[i] = etb_readl(t, ETBR_READMEM);
403
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100404 etb_lock(t);
405
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800406 length -= copy_to_user(data, (u8 *)buf + skip, length);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100407 vfree(buf);
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800408 *ppos = pos + length;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100409
410out:
411 mutex_unlock(&t->mutex);
412
413 return length;
414}
415
416static int etb_release(struct inode *inode, struct file *file)
417{
418 /* there's nothing to do here, actually */
419 return 0;
420}
421
422static const struct file_operations etb_fops = {
423 .owner = THIS_MODULE,
424 .read = etb_read,
425 .open = etb_open,
426 .release = etb_release,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200427 .llseek = no_llseek,
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100428};
429
430static struct miscdevice etb_miscdev = {
431 .name = "tracebuf",
432 .minor = 0,
433 .fops = &etb_fops,
434};
435
Ming Lei8e880692011-03-28 06:10:25 +0100436static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100437{
438 struct tracectx *t = &tracer;
439 int ret = 0;
440
441 ret = amba_request_regions(dev, NULL);
442 if (ret)
443 goto out;
444
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800445 mutex_lock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100446 t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
447 if (!t->etb_regs) {
448 ret = -ENOMEM;
449 goto out_release;
450 }
451
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800452 t->dev = &dev->dev;
Arve Hjønnevåg3a91f3e2011-02-04 22:38:14 -0800453 t->dump_initial_etb = true;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100454 amba_set_drvdata(dev, t);
455
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800456 etb_unlock(t);
457 t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
458 dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
459
460 /* make sure trace capture is disabled */
461 etb_writel(t, 0, ETBR_CTRL);
462 etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
463 etb_lock(t);
464 mutex_unlock(&t->mutex);
465
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100466 etb_miscdev.parent = &dev->dev;
467
468 ret = misc_register(&etb_miscdev);
469 if (ret)
470 goto out_unmap;
471
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800472 /* Get optional clock. Currently used to select clock source on omap3 */
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100473 t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800474 if (IS_ERR(t->emu_clk))
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100475 dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800476 else
477 clk_enable(t->emu_clk);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100478
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100479 dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n");
480
481out:
482 return ret;
483
484out_unmap:
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800485 mutex_lock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100486 amba_set_drvdata(dev, NULL);
487 iounmap(t->etb_regs);
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800488 t->etb_regs = NULL;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100489
490out_release:
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800491 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100492 amba_release_regions(dev);
493
494 return ret;
495}
496
497static int etb_remove(struct amba_device *dev)
498{
499 struct tracectx *t = amba_get_drvdata(dev);
500
501 amba_set_drvdata(dev, NULL);
502
503 iounmap(t->etb_regs);
504 t->etb_regs = NULL;
505
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800506 if (!IS_ERR(t->emu_clk)) {
507 clk_disable(t->emu_clk);
508 clk_put(t->emu_clk);
509 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100510
511 amba_release_regions(dev);
512
513 return 0;
514}
515
516static struct amba_id etb_ids[] = {
517 {
518 .id = 0x0003b907,
519 .mask = 0x0007ffff,
520 },
521 { 0, 0 },
522};
523
524static struct amba_driver etb_driver = {
525 .drv = {
526 .name = "etb",
527 .owner = THIS_MODULE,
528 },
529 .probe = etb_probe,
530 .remove = etb_remove,
531 .id_table = etb_ids,
532};
533
534/* use a sysfs file "trace_running" to start/stop tracing */
535static ssize_t trace_running_show(struct kobject *kobj,
536 struct kobj_attribute *attr,
537 char *buf)
538{
539 return sprintf(buf, "%x\n", trace_isrunning(&tracer));
540}
541
542static ssize_t trace_running_store(struct kobject *kobj,
543 struct kobj_attribute *attr,
544 const char *buf, size_t n)
545{
546 unsigned int value;
547 int ret;
548
549 if (sscanf(buf, "%u", &value) != 1)
550 return -EINVAL;
551
552 mutex_lock(&tracer.mutex);
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800553 if (!tracer.etb_regs)
554 ret = -ENODEV;
555 else
556 ret = value ? trace_start(&tracer) : trace_stop(&tracer);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100557 mutex_unlock(&tracer.mutex);
558
559 return ret ? : n;
560}
561
562static struct kobj_attribute trace_running_attr =
563 __ATTR(trace_running, 0644, trace_running_show, trace_running_store);
564
565static ssize_t trace_info_show(struct kobject *kobj,
566 struct kobj_attribute *attr,
567 char *buf)
568{
569 u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
570 int datalen;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800571 int id;
572 int ret;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100573
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800574 mutex_lock(&tracer.mutex);
575 if (tracer.etb_regs) {
576 etb_unlock(&tracer);
577 datalen = etb_getdatalen(&tracer);
578 etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
579 etb_ra = etb_readl(&tracer, ETBR_READADDR);
580 etb_st = etb_readl(&tracer, ETBR_STATUS);
581 etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
582 etb_lock(&tracer);
583 } else {
584 etb_wa = etb_ra = etb_st = etb_fc = ~0;
585 datalen = -1;
586 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100587
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800588 ret = sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100589 "ETBR_WRITEADDR:\t%08x\n"
590 "ETBR_READADDR:\t%08x\n"
591 "ETBR_STATUS:\t%08x\n"
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800592 "ETBR_FORMATTERCTRL:\t%08x\n",
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100593 datalen,
594 tracer.ncmppairs,
595 etb_wa,
596 etb_ra,
597 etb_st,
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800598 etb_fc
599 );
600
601 for (id = 0; id < tracer.etm_regs_count; id++) {
602 etm_unlock(&tracer, id);
603 etm_ctrl = etm_readl(&tracer, id, ETMR_CTRL);
604 etm_st = etm_readl(&tracer, id, ETMR_STATUS);
605 etm_lock(&tracer, id);
606 ret += sprintf(buf + ret, "ETMR_CTRL:\t%08x\n"
607 "ETMR_STATUS:\t%08x\n",
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100608 etm_ctrl,
609 etm_st
610 );
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800611 }
612 mutex_unlock(&tracer.mutex);
613
614 return ret;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100615}
616
617static struct kobj_attribute trace_info_attr =
618 __ATTR(trace_info, 0444, trace_info_show, NULL);
619
620static ssize_t trace_mode_show(struct kobject *kobj,
621 struct kobj_attribute *attr,
622 char *buf)
623{
624 return sprintf(buf, "%d %d\n",
625 !!(tracer.flags & TRACER_CYCLE_ACC),
626 tracer.etm_portsz);
627}
628
629static ssize_t trace_mode_store(struct kobject *kobj,
630 struct kobj_attribute *attr,
631 const char *buf, size_t n)
632{
633 unsigned int cycacc, portsz;
634
635 if (sscanf(buf, "%u %u", &cycacc, &portsz) != 2)
636 return -EINVAL;
637
638 mutex_lock(&tracer.mutex);
639 if (cycacc)
640 tracer.flags |= TRACER_CYCLE_ACC;
641 else
642 tracer.flags &= ~TRACER_CYCLE_ACC;
643
644 tracer.etm_portsz = portsz & 0x0f;
645 mutex_unlock(&tracer.mutex);
646
647 return n;
648}
649
650static struct kobj_attribute trace_mode_attr =
651 __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
652
Arve Hjønnevågcfb8dc52012-04-02 17:20:32 -0700653static ssize_t trace_timestamp_show(struct kobject *kobj,
654 struct kobj_attribute *attr,
655 char *buf)
656{
657 return sprintf(buf, "%d\n", !!(tracer.flags & TRACER_TIMESTAMP));
658}
659
660static ssize_t trace_timestamp_store(struct kobject *kobj,
661 struct kobj_attribute *attr,
662 const char *buf, size_t n)
663{
664 unsigned int timestamp;
665
666 if (sscanf(buf, "%u", &timestamp) != 1)
667 return -EINVAL;
668
669 mutex_lock(&tracer.mutex);
670 if (timestamp)
671 tracer.flags |= TRACER_TIMESTAMP;
672 else
673 tracer.flags &= ~TRACER_TIMESTAMP;
674 mutex_unlock(&tracer.mutex);
675
676 return n;
677}
678
679static struct kobj_attribute trace_timestamp_attr =
680 __ATTR(trace_timestamp, 0644,
681 trace_timestamp_show, trace_timestamp_store);
682
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800683static ssize_t trace_range_show(struct kobject *kobj,
684 struct kobj_attribute *attr,
685 char *buf)
686{
687 return sprintf(buf, "%08lx %08lx\n",
688 tracer.range_start, tracer.range_end);
689}
690
691static ssize_t trace_range_store(struct kobject *kobj,
692 struct kobj_attribute *attr,
693 const char *buf, size_t n)
694{
695 unsigned long range_start, range_end;
696
697 if (sscanf(buf, "%lx %lx", &range_start, &range_end) != 2)
698 return -EINVAL;
699
700 mutex_lock(&tracer.mutex);
701 tracer.range_start = range_start;
702 tracer.range_end = range_end;
703 mutex_unlock(&tracer.mutex);
704
705 return n;
706}
707
708
709static struct kobj_attribute trace_range_attr =
710 __ATTR(trace_range, 0644, trace_range_show, trace_range_store);
711
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800712static ssize_t trace_data_range_show(struct kobject *kobj,
713 struct kobj_attribute *attr,
714 char *buf)
715{
716 unsigned long range_start;
717 u64 range_end;
718 mutex_lock(&tracer.mutex);
719 range_start = tracer.data_range_start;
720 range_end = tracer.data_range_end;
721 if (!range_end && (tracer.flags & TRACER_TRACE_DATA))
722 range_end = 0x100000000ULL;
723 mutex_unlock(&tracer.mutex);
724 return sprintf(buf, "%08lx %08llx\n", range_start, range_end);
725}
726
727static ssize_t trace_data_range_store(struct kobject *kobj,
728 struct kobj_attribute *attr,
729 const char *buf, size_t n)
730{
731 unsigned long range_start;
732 u64 range_end;
733
734 if (sscanf(buf, "%lx %llx", &range_start, &range_end) != 2)
735 return -EINVAL;
736
737 mutex_lock(&tracer.mutex);
738 tracer.data_range_start = range_start;
739 tracer.data_range_end = (unsigned long)range_end;
740 if (range_end)
741 tracer.flags |= TRACER_TRACE_DATA;
742 else
743 tracer.flags &= ~TRACER_TRACE_DATA;
744 mutex_unlock(&tracer.mutex);
745
746 return n;
747}
748
749
750static struct kobj_attribute trace_data_range_attr =
751 __ATTR(trace_data_range, 0644,
752 trace_data_range_show, trace_data_range_store);
753
Ming Lei8e880692011-03-28 06:10:25 +0100754static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100755{
756 struct tracectx *t = &tracer;
757 int ret = 0;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800758 void __iomem **new_regs;
759 int new_count;
Arve Hjønnevågd263bc72012-04-02 20:18:56 -0700760 u32 etmccr;
761 u32 etmidr;
Arve Hjønnevågcfb8dc52012-04-02 17:20:32 -0700762 u32 etmccer = 0;
Arve Hjønnevågd263bc72012-04-02 20:18:56 -0700763 u8 etm_version = 0;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100764
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800765 mutex_lock(&t->mutex);
766 new_count = t->etm_regs_count + 1;
767 new_regs = krealloc(t->etm_regs,
768 sizeof(t->etm_regs[0]) * new_count, GFP_KERNEL);
769
770 if (!new_regs) {
771 dev_dbg(&dev->dev, "Failed to allocate ETM register array\n");
772 ret = -ENOMEM;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100773 goto out;
774 }
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800775 t->etm_regs = new_regs;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100776
777 ret = amba_request_regions(dev, NULL);
778 if (ret)
779 goto out;
780
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800781 t->etm_regs[t->etm_regs_count] =
782 ioremap_nocache(dev->res.start, resource_size(&dev->res));
783 if (!t->etm_regs[t->etm_regs_count]) {
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100784 ret = -ENOMEM;
785 goto out_release;
786 }
787
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800788 amba_set_drvdata(dev, t->etm_regs[t->etm_regs_count]);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100789
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800790 t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100791 t->etm_portsz = 1;
792
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800793 etm_unlock(t, t->etm_regs_count);
794 (void)etm_readl(t, t->etm_regs_count, ETMMR_PDSR);
Alexander Shishkin988257c2010-08-04 11:27:33 +0100795 /* dummy first read */
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800796 (void)etm_readl(&tracer, t->etm_regs_count, ETMMR_OSSRR);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100797
Arve Hjønnevågd263bc72012-04-02 20:18:56 -0700798 etmccr = etm_readl(t, t->etm_regs_count, ETMR_CONFCODE);
799 t->ncmppairs = etmccr & 0xf;
800 if (etmccr & ETMCCR_ETMIDR_PRESENT) {
801 etmidr = etm_readl(t, t->etm_regs_count, ETMR_ID);
802 etm_version = ETMIDR_VERSION(etmidr);
Arve Hjønnevågcfb8dc52012-04-02 17:20:32 -0700803 if (etm_version >= ETMIDR_VERSION_3_1)
804 etmccer = etm_readl(t, t->etm_regs_count, ETMR_CCE);
Arve Hjønnevågd263bc72012-04-02 20:18:56 -0700805 }
Arve Hjønnevåg42469832011-02-23 16:51:58 -0800806 etm_writel(t, t->etm_regs_count, 0x441, ETMR_CTRL);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800807 etm_writel(t, t->etm_regs_count, new_count, ETMR_TRACEIDR);
808 etm_lock(t, t->etm_regs_count);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100809
810 ret = sysfs_create_file(&dev->dev.kobj,
811 &trace_running_attr.attr);
812 if (ret)
813 goto out_unmap;
814
815 /* failing to create any of these two is not fatal */
816 ret = sysfs_create_file(&dev->dev.kobj, &trace_info_attr.attr);
817 if (ret)
818 dev_dbg(&dev->dev, "Failed to create trace_info in sysfs\n");
819
820 ret = sysfs_create_file(&dev->dev.kobj, &trace_mode_attr.attr);
821 if (ret)
822 dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n");
823
Arve Hjønnevågcfb8dc52012-04-02 17:20:32 -0700824 if (etmccer & ETMCCER_TIMESTAMPING_IMPLEMENTED) {
825 ret = sysfs_create_file(&dev->dev.kobj,
826 &trace_timestamp_attr.attr);
827 if (ret)
828 dev_dbg(&dev->dev,
829 "Failed to create trace_timestamp in sysfs\n");
830 }
831
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800832 ret = sysfs_create_file(&dev->dev.kobj, &trace_range_attr.attr);
833 if (ret)
834 dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n");
835
Arve Hjønnevågd263bc72012-04-02 20:18:56 -0700836 if (etm_version < ETMIDR_VERSION_PFT_1_0) {
837 ret = sysfs_create_file(&dev->dev.kobj,
838 &trace_data_range_attr.attr);
839 if (ret)
840 dev_dbg(&dev->dev,
841 "Failed to create trace_data_range in sysfs\n");
842 } else {
843 tracer.flags &= ~TRACER_TRACE_DATA;
844 }
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800845
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800846 dev_dbg(&dev->dev, "ETM AMBA driver initialized.\n");
847
848 /* Enable formatter if there are multiple trace sources */
849 if (new_count > 1)
850 t->etb_fc = ETBFF_ENFCONT | ETBFF_ENFTC;
851
852 t->etm_regs_count = new_count;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100853
854out:
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800855 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100856 return ret;
857
858out_unmap:
859 amba_set_drvdata(dev, NULL);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800860 iounmap(t->etm_regs[t->etm_regs_count]);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100861
862out_release:
863 amba_release_regions(dev);
864
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800865 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100866 return ret;
867}
868
869static int etm_remove(struct amba_device *dev)
870{
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800871 int i;
872 struct tracectx *t = &tracer;
873 void __iomem *etm_regs = amba_get_drvdata(dev);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100874
875 sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr);
876 sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
877 sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr);
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800878 sysfs_remove_file(&dev->dev.kobj, &trace_range_attr.attr);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800879 sysfs_remove_file(&dev->dev.kobj, &trace_data_range_attr.attr);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100880
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800881 amba_set_drvdata(dev, NULL);
882
883 mutex_lock(&t->mutex);
884 for (i = 0; i < t->etm_regs_count; i++)
885 if (t->etm_regs[i] == etm_regs)
886 break;
887 for (; i < t->etm_regs_count - 1; i++)
888 t->etm_regs[i] = t->etm_regs[i + 1];
889 t->etm_regs_count--;
890 if (!t->etm_regs_count) {
891 kfree(t->etm_regs);
892 t->etm_regs = NULL;
893 }
894 mutex_unlock(&t->mutex);
895
896 iounmap(etm_regs);
897 amba_release_regions(dev);
898
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100899 return 0;
900}
901
902static struct amba_id etm_ids[] = {
903 {
904 .id = 0x0003b921,
905 .mask = 0x0007ffff,
906 },
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800907 {
908 .id = 0x0003b950,
909 .mask = 0x0007ffff,
910 },
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100911 { 0, 0 },
912};
913
914static struct amba_driver etm_driver = {
915 .drv = {
916 .name = "etm",
917 .owner = THIS_MODULE,
918 },
919 .probe = etm_probe,
920 .remove = etm_remove,
921 .id_table = etm_ids,
922};
923
924static int __init etm_init(void)
925{
926 int retval;
927
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800928 mutex_init(&tracer.mutex);
929
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100930 retval = amba_driver_register(&etb_driver);
931 if (retval) {
932 printk(KERN_ERR "Failed to register etb\n");
933 return retval;
934 }
935
936 retval = amba_driver_register(&etm_driver);
937 if (retval) {
938 amba_driver_unregister(&etb_driver);
939 printk(KERN_ERR "Failed to probe etm\n");
940 return retval;
941 }
942
943 /* not being able to install this handler is not fatal */
944 (void)register_sysrq_key('v', &sysrq_etm_op);
945
946 return 0;
947}
948
949device_initcall(etm_init);
950