blob: 037c5e1e916cca247251878a4a060df0b04a7079 [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>
18#include <linux/sysrq.h>
19#include <linux/device.h>
20#include <linux/clk.h>
21#include <linux/amba/bus.h>
22#include <linux/fs.h>
23#include <linux/uaccess.h>
24#include <linux/miscdevice.h>
25#include <linux/vmalloc.h>
26#include <linux/mutex.h>
27#include <asm/hardware/coresight.h>
28#include <asm/sections.h>
29
30MODULE_LICENSE("GPL");
31MODULE_AUTHOR("Alexander Shishkin");
32
Alexander Shishkin8234eae2010-08-04 11:22:43 +010033/*
34 * ETM tracer state
35 */
36struct tracectx {
37 unsigned int etb_bufsz;
38 void __iomem *etb_regs;
39 void __iomem *etm_regs;
40 unsigned long flags;
41 int ncmppairs;
42 int etm_portsz;
Arve Hjønnevåg51495972011-01-28 23:44:43 -080043 unsigned long range_start;
44 unsigned long range_end;
Arve Hjønnevåg81e43122011-01-31 18:33:55 -080045 unsigned long data_range_start;
46 unsigned long data_range_end;
Arve Hjønnevåg97aba2e2011-02-04 22:38:14 -080047 bool dump_initial_etb;
Alexander Shishkin8234eae2010-08-04 11:22:43 +010048 struct device *dev;
49 struct clk *emu_clk;
50 struct mutex mutex;
51};
52
Arve Hjønnevåg51495972011-01-28 23:44:43 -080053static struct tracectx tracer = {
54 .range_start = (unsigned long)_stext,
55 .range_end = (unsigned long)_etext,
56};
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010057
58static inline bool trace_isrunning(struct tracectx *t)
59{
60 return !!(t->flags & TRACER_RUNNING);
61}
62
63static int etm_setup_address_range(struct tracectx *t, int n,
64 unsigned long start, unsigned long end, int exclude, int data)
65{
Arve Hjønnevågccd3dbc2011-01-28 23:33:11 -080066 u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_IGNSECURITY |
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010067 ETMAAT_NOVALCMP;
68
69 if (n < 1 || n > t->ncmppairs)
70 return -EINVAL;
71
72 /* comparators and ranges are numbered starting with 1 as opposed
73 * to bits in a word */
74 n--;
75
76 if (data)
77 flags |= ETMAAT_DLOADSTORE;
78 else
79 flags |= ETMAAT_IEXEC;
80
81 /* first comparator for the range */
82 etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2));
83 etm_writel(t, start, ETMR_COMP_VAL(n * 2));
84
85 /* second comparator is right next to it */
86 etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
87 etm_writel(t, end, ETMR_COMP_VAL(n * 2 + 1));
88
Arve Hjønnevåg81e43122011-01-31 18:33:55 -080089 if (data) {
90 flags = exclude ? ETMVDC3_EXCLONLY : 0;
91 if (exclude)
92 n += 8;
93 etm_writel(t, flags | BIT(n), ETMR_VIEWDATACTRL3);
94 } else {
95 flags = exclude ? ETMTE_INCLEXCL : 0;
96 etm_writel(t, flags | (1 << n), ETMR_TRACEENCTRL);
97 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010098
99 return 0;
100}
101
102static int trace_start(struct tracectx *t)
103{
104 u32 v;
105 unsigned long timeout = TRACER_TIMEOUT;
106
107 etb_unlock(t);
108
Arve Hjønnevåg97aba2e2011-02-04 22:38:14 -0800109 t->dump_initial_etb = false;
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800110 etb_writel(t, 0, ETBR_WRITEADDR);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100111 etb_writel(t, 0, ETBR_FORMATTERCTRL);
112 etb_writel(t, 1, ETBR_CTRL);
113
114 etb_lock(t);
115
116 /* configure etm */
117 v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz);
118
119 if (t->flags & TRACER_CYCLE_ACC)
120 v |= ETMCTRL_CYCLEACCURATE;
121
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800122 if (t->flags & TRACER_TRACE_DATA)
123 v |= ETMCTRL_DATA_DO_ADDR;
124
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100125 etm_unlock(t);
126
127 etm_writel(t, v, ETMR_CTRL);
128
129 while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
130 ;
131 if (!timeout) {
132 dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
133 etm_lock(t);
134 return -EFAULT;
135 }
136
Arve Hjønnevåg51495972011-01-28 23:44:43 -0800137 if (t->range_start || t->range_end)
138 etm_setup_address_range(t, 1,
139 t->range_start, t->range_end, 0, 0);
140 else
141 etm_writel(t, ETMTE_INCLEXCL, ETMR_TRACEENCTRL);
142
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100143 etm_writel(t, 0, ETMR_TRACEENCTRL2);
144 etm_writel(t, 0, ETMR_TRACESSCTRL);
145 etm_writel(t, 0x6f, ETMR_TRACEENEVT);
146
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800147 etm_writel(t, 0, ETMR_VIEWDATACTRL1);
148 etm_writel(t, 0, ETMR_VIEWDATACTRL2);
149
150 if (t->data_range_start || t->data_range_end)
151 etm_setup_address_range(t, 2, t->data_range_start,
152 t->data_range_end, 0, 1);
153 else
154 etm_writel(t, ETMVDC3_EXCLONLY, ETMR_VIEWDATACTRL3);
155
156 etm_writel(t, 0x6f, ETMR_VIEWDATAEVT);
157
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100158 v &= ~ETMCTRL_PROGRAM;
159 v |= ETMCTRL_PORTSEL;
160
161 etm_writel(t, v, ETMR_CTRL);
162
163 timeout = TRACER_TIMEOUT;
164 while (etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout)
165 ;
166 if (!timeout) {
167 dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n");
168 etm_lock(t);
169 return -EFAULT;
170 }
171
172 etm_lock(t);
173
174 t->flags |= TRACER_RUNNING;
175
176 return 0;
177}
178
179static int trace_stop(struct tracectx *t)
180{
181 unsigned long timeout = TRACER_TIMEOUT;
182
183 etm_unlock(t);
184
185 etm_writel(t, 0x440, ETMR_CTRL);
186 while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
187 ;
188 if (!timeout) {
189 dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
190 etm_lock(t);
191 return -EFAULT;
192 }
193
194 etm_lock(t);
195
196 etb_unlock(t);
197 etb_writel(t, ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
198
199 timeout = TRACER_TIMEOUT;
200 while (etb_readl(t, ETBR_FORMATTERCTRL) &
201 ETBFF_MANUAL_FLUSH && --timeout)
202 ;
203 if (!timeout) {
204 dev_dbg(t->dev, "Waiting for formatter flush to commence "
205 "timed out\n");
206 etb_lock(t);
207 return -EFAULT;
208 }
209
210 etb_writel(t, 0, ETBR_CTRL);
211
212 etb_lock(t);
213
214 t->flags &= ~TRACER_RUNNING;
215
216 return 0;
217}
218
219static int etb_getdatalen(struct tracectx *t)
220{
221 u32 v;
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800222 int wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100223
224 v = etb_readl(t, ETBR_STATUS);
225
226 if (v & 1)
227 return t->etb_bufsz;
228
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100229 wp = etb_readl(t, ETBR_WRITEADDR);
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800230 return wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100231}
232
233/* sysrq+v will always stop the running trace and leave it at that */
234static void etm_dump(void)
235{
236 struct tracectx *t = &tracer;
237 u32 first = 0;
238 int length;
239
240 if (!t->etb_regs) {
241 printk(KERN_INFO "No tracing hardware found\n");
242 return;
243 }
244
245 if (trace_isrunning(t))
246 trace_stop(t);
247
248 etb_unlock(t);
249
250 length = etb_getdatalen(t);
251
252 if (length == t->etb_bufsz)
253 first = etb_readl(t, ETBR_WRITEADDR);
254
255 etb_writel(t, first, ETBR_READADDR);
256
257 printk(KERN_INFO "Trace buffer contents length: %d\n", length);
258 printk(KERN_INFO "--- ETB buffer begin ---\n");
259 for (; length; length--)
260 printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
261 printk(KERN_INFO "\n--- ETB buffer end ---\n");
262
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100263 etb_lock(t);
264}
265
Dmitry Torokhov1495cc92010-08-17 21:15:46 -0700266static void sysrq_etm_dump(int key)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100267{
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800268 if (!mutex_trylock(&tracer.mutex)) {
269 printk(KERN_INFO "Tracing hardware busy\n");
270 return;
271 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100272 dev_dbg(tracer.dev, "Dumping ETB buffer\n");
273 etm_dump();
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800274 mutex_unlock(&tracer.mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100275}
276
277static struct sysrq_key_op sysrq_etm_op = {
278 .handler = sysrq_etm_dump,
279 .help_msg = "ETM buffer dump",
280 .action_msg = "etm",
281};
282
283static int etb_open(struct inode *inode, struct file *file)
284{
285 if (!tracer.etb_regs)
286 return -ENODEV;
287
288 file->private_data = &tracer;
289
290 return nonseekable_open(inode, file);
291}
292
293static ssize_t etb_read(struct file *file, char __user *data,
294 size_t len, loff_t *ppos)
295{
296 int total, i;
297 long length;
298 struct tracectx *t = file->private_data;
299 u32 first = 0;
300 u32 *buf;
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800301 int wpos;
302 int skip;
303 long wlength;
304 loff_t pos = *ppos;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100305
306 mutex_lock(&t->mutex);
307
308 if (trace_isrunning(t)) {
309 length = 0;
310 goto out;
311 }
312
313 etb_unlock(t);
314
315 total = etb_getdatalen(t);
Arve Hjønnevåg97aba2e2011-02-04 22:38:14 -0800316 if (total == 0 && t->dump_initial_etb)
317 total = t->etb_bufsz;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100318 if (total == t->etb_bufsz)
319 first = etb_readl(t, ETBR_WRITEADDR);
320
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800321 if (pos > total * 4) {
322 skip = 0;
323 wpos = total;
324 } else {
325 skip = (int)pos % 4;
326 wpos = (int)pos / 4;
327 }
328 total -= wpos;
329 first = (first + wpos) % t->etb_bufsz;
330
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100331 etb_writel(t, first, ETBR_READADDR);
332
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800333 wlength = min(total, DIV_ROUND_UP(skip + (int)len, 4));
334 length = min(total * 4 - skip, (int)len);
335 buf = vmalloc(wlength * 4);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100336
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800337 dev_dbg(t->dev, "ETB read %ld bytes to %lld from %ld words at %d\n",
338 length, pos, wlength, first);
339 dev_dbg(t->dev, "ETB buffer length: %d\n", total + wpos);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100340 dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800341 for (i = 0; i < wlength; i++)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100342 buf[i] = etb_readl(t, ETBR_READMEM);
343
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100344 etb_lock(t);
345
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800346 length -= copy_to_user(data, (u8 *)buf + skip, length);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100347 vfree(buf);
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800348 *ppos = pos + length;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100349
350out:
351 mutex_unlock(&t->mutex);
352
353 return length;
354}
355
356static int etb_release(struct inode *inode, struct file *file)
357{
358 /* there's nothing to do here, actually */
359 return 0;
360}
361
362static const struct file_operations etb_fops = {
363 .owner = THIS_MODULE,
364 .read = etb_read,
365 .open = etb_open,
366 .release = etb_release,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200367 .llseek = no_llseek,
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100368};
369
370static struct miscdevice etb_miscdev = {
371 .name = "tracebuf",
372 .minor = 0,
373 .fops = &etb_fops,
374};
375
Ming Lei8e880692011-03-28 06:10:25 +0100376static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100377{
378 struct tracectx *t = &tracer;
379 int ret = 0;
380
381 ret = amba_request_regions(dev, NULL);
382 if (ret)
383 goto out;
384
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800385 mutex_lock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100386 t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
387 if (!t->etb_regs) {
388 ret = -ENOMEM;
389 goto out_release;
390 }
391
Arve Hjønnevåg97aba2e2011-02-04 22:38:14 -0800392 t->dump_initial_etb = true;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100393 amba_set_drvdata(dev, t);
394
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800395 etb_unlock(t);
396 t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
397 dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
398
399 /* make sure trace capture is disabled */
400 etb_writel(t, 0, ETBR_CTRL);
401 etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
402 etb_lock(t);
403 mutex_unlock(&t->mutex);
404
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100405 etb_miscdev.parent = &dev->dev;
406
407 ret = misc_register(&etb_miscdev);
408 if (ret)
409 goto out_unmap;
410
Arve Hjønnevåg875e2e12011-01-28 23:12:32 -0800411 /* Get optional clock. Currently used to select clock source on omap3 */
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100412 t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
Arve Hjønnevåg875e2e12011-01-28 23:12:32 -0800413 if (IS_ERR(t->emu_clk))
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100414 dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
Arve Hjønnevåg875e2e12011-01-28 23:12:32 -0800415 else
416 clk_enable(t->emu_clk);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100417
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100418 dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n");
419
420out:
421 return ret;
422
423out_unmap:
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800424 mutex_lock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100425 amba_set_drvdata(dev, NULL);
426 iounmap(t->etb_regs);
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800427 t->etb_regs = NULL;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100428
429out_release:
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800430 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100431 amba_release_regions(dev);
432
433 return ret;
434}
435
436static int etb_remove(struct amba_device *dev)
437{
438 struct tracectx *t = amba_get_drvdata(dev);
439
440 amba_set_drvdata(dev, NULL);
441
442 iounmap(t->etb_regs);
443 t->etb_regs = NULL;
444
Arve Hjønnevåg875e2e12011-01-28 23:12:32 -0800445 if (!IS_ERR(t->emu_clk)) {
446 clk_disable(t->emu_clk);
447 clk_put(t->emu_clk);
448 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100449
450 amba_release_regions(dev);
451
452 return 0;
453}
454
455static struct amba_id etb_ids[] = {
456 {
457 .id = 0x0003b907,
458 .mask = 0x0007ffff,
459 },
460 { 0, 0 },
461};
462
463static struct amba_driver etb_driver = {
464 .drv = {
465 .name = "etb",
466 .owner = THIS_MODULE,
467 },
468 .probe = etb_probe,
469 .remove = etb_remove,
470 .id_table = etb_ids,
471};
472
473/* use a sysfs file "trace_running" to start/stop tracing */
474static ssize_t trace_running_show(struct kobject *kobj,
475 struct kobj_attribute *attr,
476 char *buf)
477{
478 return sprintf(buf, "%x\n", trace_isrunning(&tracer));
479}
480
481static ssize_t trace_running_store(struct kobject *kobj,
482 struct kobj_attribute *attr,
483 const char *buf, size_t n)
484{
485 unsigned int value;
486 int ret;
487
488 if (sscanf(buf, "%u", &value) != 1)
489 return -EINVAL;
490
491 mutex_lock(&tracer.mutex);
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800492 if (!tracer.etb_regs)
493 ret = -ENODEV;
494 else
495 ret = value ? trace_start(&tracer) : trace_stop(&tracer);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100496 mutex_unlock(&tracer.mutex);
497
498 return ret ? : n;
499}
500
501static struct kobj_attribute trace_running_attr =
502 __ATTR(trace_running, 0644, trace_running_show, trace_running_store);
503
504static ssize_t trace_info_show(struct kobject *kobj,
505 struct kobj_attribute *attr,
506 char *buf)
507{
508 u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
509 int datalen;
510
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800511 mutex_lock(&tracer.mutex);
512 if (tracer.etb_regs) {
513 etb_unlock(&tracer);
514 datalen = etb_getdatalen(&tracer);
515 etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
516 etb_ra = etb_readl(&tracer, ETBR_READADDR);
517 etb_st = etb_readl(&tracer, ETBR_STATUS);
518 etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
519 etb_lock(&tracer);
520 } else {
521 etb_wa = etb_ra = etb_st = etb_fc = ~0;
522 datalen = -1;
523 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100524
525 etm_unlock(&tracer);
526 etm_ctrl = etm_readl(&tracer, ETMR_CTRL);
527 etm_st = etm_readl(&tracer, ETMR_STATUS);
528 etm_lock(&tracer);
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800529 mutex_unlock(&tracer.mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100530
531 return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
532 "ETBR_WRITEADDR:\t%08x\n"
533 "ETBR_READADDR:\t%08x\n"
534 "ETBR_STATUS:\t%08x\n"
535 "ETBR_FORMATTERCTRL:\t%08x\n"
536 "ETMR_CTRL:\t%08x\n"
537 "ETMR_STATUS:\t%08x\n",
538 datalen,
539 tracer.ncmppairs,
540 etb_wa,
541 etb_ra,
542 etb_st,
543 etb_fc,
544 etm_ctrl,
545 etm_st
546 );
547}
548
549static struct kobj_attribute trace_info_attr =
550 __ATTR(trace_info, 0444, trace_info_show, NULL);
551
552static ssize_t trace_mode_show(struct kobject *kobj,
553 struct kobj_attribute *attr,
554 char *buf)
555{
556 return sprintf(buf, "%d %d\n",
557 !!(tracer.flags & TRACER_CYCLE_ACC),
558 tracer.etm_portsz);
559}
560
561static ssize_t trace_mode_store(struct kobject *kobj,
562 struct kobj_attribute *attr,
563 const char *buf, size_t n)
564{
565 unsigned int cycacc, portsz;
566
567 if (sscanf(buf, "%u %u", &cycacc, &portsz) != 2)
568 return -EINVAL;
569
570 mutex_lock(&tracer.mutex);
571 if (cycacc)
572 tracer.flags |= TRACER_CYCLE_ACC;
573 else
574 tracer.flags &= ~TRACER_CYCLE_ACC;
575
576 tracer.etm_portsz = portsz & 0x0f;
577 mutex_unlock(&tracer.mutex);
578
579 return n;
580}
581
582static struct kobj_attribute trace_mode_attr =
583 __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
584
Arve Hjønnevåg51495972011-01-28 23:44:43 -0800585static ssize_t trace_range_show(struct kobject *kobj,
586 struct kobj_attribute *attr,
587 char *buf)
588{
589 return sprintf(buf, "%08lx %08lx\n",
590 tracer.range_start, tracer.range_end);
591}
592
593static ssize_t trace_range_store(struct kobject *kobj,
594 struct kobj_attribute *attr,
595 const char *buf, size_t n)
596{
597 unsigned long range_start, range_end;
598
599 if (sscanf(buf, "%lx %lx", &range_start, &range_end) != 2)
600 return -EINVAL;
601
602 mutex_lock(&tracer.mutex);
603 tracer.range_start = range_start;
604 tracer.range_end = range_end;
605 mutex_unlock(&tracer.mutex);
606
607 return n;
608}
609
610
611static struct kobj_attribute trace_range_attr =
612 __ATTR(trace_range, 0644, trace_range_show, trace_range_store);
613
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800614static ssize_t trace_data_range_show(struct kobject *kobj,
615 struct kobj_attribute *attr,
616 char *buf)
617{
618 unsigned long range_start;
619 u64 range_end;
620 mutex_lock(&tracer.mutex);
621 range_start = tracer.data_range_start;
622 range_end = tracer.data_range_end;
623 if (!range_end && (tracer.flags & TRACER_TRACE_DATA))
624 range_end = 0x100000000ULL;
625 mutex_unlock(&tracer.mutex);
626 return sprintf(buf, "%08lx %08llx\n", range_start, range_end);
627}
628
629static ssize_t trace_data_range_store(struct kobject *kobj,
630 struct kobj_attribute *attr,
631 const char *buf, size_t n)
632{
633 unsigned long range_start;
634 u64 range_end;
635
636 if (sscanf(buf, "%lx %llx", &range_start, &range_end) != 2)
637 return -EINVAL;
638
639 mutex_lock(&tracer.mutex);
640 tracer.data_range_start = range_start;
641 tracer.data_range_end = (unsigned long)range_end;
642 if (range_end)
643 tracer.flags |= TRACER_TRACE_DATA;
644 else
645 tracer.flags &= ~TRACER_TRACE_DATA;
646 mutex_unlock(&tracer.mutex);
647
648 return n;
649}
650
651
652static struct kobj_attribute trace_data_range_attr =
653 __ATTR(trace_data_range, 0644,
654 trace_data_range_show, trace_data_range_store);
655
Ming Lei8e880692011-03-28 06:10:25 +0100656static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100657{
658 struct tracectx *t = &tracer;
659 int ret = 0;
660
661 if (t->etm_regs) {
662 dev_dbg(&dev->dev, "ETM already initialized\n");
663 ret = -EBUSY;
664 goto out;
665 }
666
667 ret = amba_request_regions(dev, NULL);
668 if (ret)
669 goto out;
670
671 t->etm_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
672 if (!t->etm_regs) {
673 ret = -ENOMEM;
674 goto out_release;
675 }
676
677 amba_set_drvdata(dev, t);
678
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100679 t->dev = &dev->dev;
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800680 t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100681 t->etm_portsz = 1;
682
683 etm_unlock(t);
Alexander Shishkin988257c2010-08-04 11:27:33 +0100684 (void)etm_readl(t, ETMMR_PDSR);
685 /* dummy first read */
686 (void)etm_readl(&tracer, ETMMR_OSSRR);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100687
688 t->ncmppairs = etm_readl(t, ETMR_CONFCODE) & 0xf;
689 etm_writel(t, 0x440, ETMR_CTRL);
690 etm_lock(t);
691
692 ret = sysfs_create_file(&dev->dev.kobj,
693 &trace_running_attr.attr);
694 if (ret)
695 goto out_unmap;
696
697 /* failing to create any of these two is not fatal */
698 ret = sysfs_create_file(&dev->dev.kobj, &trace_info_attr.attr);
699 if (ret)
700 dev_dbg(&dev->dev, "Failed to create trace_info in sysfs\n");
701
702 ret = sysfs_create_file(&dev->dev.kobj, &trace_mode_attr.attr);
703 if (ret)
704 dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n");
705
Arve Hjønnevåg51495972011-01-28 23:44:43 -0800706 ret = sysfs_create_file(&dev->dev.kobj, &trace_range_attr.attr);
707 if (ret)
708 dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n");
709
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800710 ret = sysfs_create_file(&dev->dev.kobj, &trace_data_range_attr.attr);
711 if (ret)
712 dev_dbg(&dev->dev,
713 "Failed to create trace_data_range in sysfs\n");
714
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100715 dev_dbg(t->dev, "ETM AMBA driver initialized.\n");
716
717out:
718 return ret;
719
720out_unmap:
721 amba_set_drvdata(dev, NULL);
722 iounmap(t->etm_regs);
723
724out_release:
725 amba_release_regions(dev);
726
727 return ret;
728}
729
730static int etm_remove(struct amba_device *dev)
731{
732 struct tracectx *t = amba_get_drvdata(dev);
733
734 amba_set_drvdata(dev, NULL);
735
736 iounmap(t->etm_regs);
737 t->etm_regs = NULL;
738
739 amba_release_regions(dev);
740
741 sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr);
742 sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
743 sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr);
Arve Hjønnevåg51495972011-01-28 23:44:43 -0800744 sysfs_remove_file(&dev->dev.kobj, &trace_range_attr.attr);
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800745 sysfs_remove_file(&dev->dev.kobj, &trace_data_range_attr.attr);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100746
747 return 0;
748}
749
750static struct amba_id etm_ids[] = {
751 {
752 .id = 0x0003b921,
753 .mask = 0x0007ffff,
754 },
755 { 0, 0 },
756};
757
758static struct amba_driver etm_driver = {
759 .drv = {
760 .name = "etm",
761 .owner = THIS_MODULE,
762 },
763 .probe = etm_probe,
764 .remove = etm_remove,
765 .id_table = etm_ids,
766};
767
768static int __init etm_init(void)
769{
770 int retval;
771
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800772 mutex_init(&tracer.mutex);
773
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100774 retval = amba_driver_register(&etb_driver);
775 if (retval) {
776 printk(KERN_ERR "Failed to register etb\n");
777 return retval;
778 }
779
780 retval = amba_driver_register(&etm_driver);
781 if (retval) {
782 amba_driver_unregister(&etb_driver);
783 printk(KERN_ERR "Failed to probe etm\n");
784 return retval;
785 }
786
787 /* not being able to install this handler is not fatal */
788 (void)register_sysrq_key('v', &sysrq_etm_op);
789
790 return 0;
791}
792
793device_initcall(etm_init);
794