blob: 74444e5cb1bd706dff283362cd77c110ff3b0ef2 [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>
Paul Gortmaker73017a52011-07-31 16:14:14 -040027#include <linux/module.h>
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010028#include <asm/hardware/coresight.h>
29#include <asm/sections.h>
30
31MODULE_LICENSE("GPL");
32MODULE_AUTHOR("Alexander Shishkin");
33
Alexander Shishkin8234eae2010-08-04 11:22:43 +010034/*
35 * ETM tracer state
36 */
37struct tracectx {
38 unsigned int etb_bufsz;
39 void __iomem *etb_regs;
40 void __iomem *etm_regs;
41 unsigned long flags;
42 int ncmppairs;
43 int etm_portsz;
Arve Hjønnevågd71c6952011-01-28 23:44:43 -080044 unsigned long range_start;
45 unsigned long range_end;
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -080046 unsigned long data_range_start;
47 unsigned long data_range_end;
Arve Hjønnevåg3a91f3e2011-02-04 22:38:14 -080048 bool dump_initial_etb;
Alexander Shishkin8234eae2010-08-04 11:22:43 +010049 struct device *dev;
50 struct clk *emu_clk;
51 struct mutex mutex;
52};
53
Arve Hjønnevågd71c6952011-01-28 23:44:43 -080054static struct tracectx tracer = {
55 .range_start = (unsigned long)_stext,
56 .range_end = (unsigned long)_etext,
57};
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010058
59static inline bool trace_isrunning(struct tracectx *t)
60{
61 return !!(t->flags & TRACER_RUNNING);
62}
63
64static int etm_setup_address_range(struct tracectx *t, int n,
65 unsigned long start, unsigned long end, int exclude, int data)
66{
Arve Hjønnevåg8511b5b2011-01-28 23:33:11 -080067 u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_IGNSECURITY |
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010068 ETMAAT_NOVALCMP;
69
70 if (n < 1 || n > t->ncmppairs)
71 return -EINVAL;
72
73 /* comparators and ranges are numbered starting with 1 as opposed
74 * to bits in a word */
75 n--;
76
77 if (data)
78 flags |= ETMAAT_DLOADSTORE;
79 else
80 flags |= ETMAAT_IEXEC;
81
82 /* first comparator for the range */
83 etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2));
84 etm_writel(t, start, ETMR_COMP_VAL(n * 2));
85
86 /* second comparator is right next to it */
87 etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
88 etm_writel(t, end, ETMR_COMP_VAL(n * 2 + 1));
89
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -080090 if (data) {
91 flags = exclude ? ETMVDC3_EXCLONLY : 0;
92 if (exclude)
93 n += 8;
94 etm_writel(t, flags | BIT(n), ETMR_VIEWDATACTRL3);
95 } else {
96 flags = exclude ? ETMTE_INCLEXCL : 0;
97 etm_writel(t, flags | (1 << n), ETMR_TRACEENCTRL);
98 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010099
100 return 0;
101}
102
103static int trace_start(struct tracectx *t)
104{
105 u32 v;
106 unsigned long timeout = TRACER_TIMEOUT;
107
108 etb_unlock(t);
109
Arve Hjønnevåg3a91f3e2011-02-04 22:38:14 -0800110 t->dump_initial_etb = false;
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800111 etb_writel(t, 0, ETBR_WRITEADDR);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100112 etb_writel(t, 0, ETBR_FORMATTERCTRL);
113 etb_writel(t, 1, ETBR_CTRL);
114
115 etb_lock(t);
116
117 /* configure etm */
118 v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz);
119
120 if (t->flags & TRACER_CYCLE_ACC)
121 v |= ETMCTRL_CYCLEACCURATE;
122
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800123 if (t->flags & TRACER_TRACE_DATA)
124 v |= ETMCTRL_DATA_DO_ADDR;
125
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100126 etm_unlock(t);
127
128 etm_writel(t, v, ETMR_CTRL);
129
130 while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
131 ;
132 if (!timeout) {
133 dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
134 etm_lock(t);
135 return -EFAULT;
136 }
137
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800138 if (t->range_start || t->range_end)
139 etm_setup_address_range(t, 1,
140 t->range_start, t->range_end, 0, 0);
141 else
142 etm_writel(t, ETMTE_INCLEXCL, ETMR_TRACEENCTRL);
143
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100144 etm_writel(t, 0, ETMR_TRACEENCTRL2);
145 etm_writel(t, 0, ETMR_TRACESSCTRL);
146 etm_writel(t, 0x6f, ETMR_TRACEENEVT);
147
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800148 etm_writel(t, 0, ETMR_VIEWDATACTRL1);
149 etm_writel(t, 0, ETMR_VIEWDATACTRL2);
150
151 if (t->data_range_start || t->data_range_end)
152 etm_setup_address_range(t, 2, t->data_range_start,
153 t->data_range_end, 0, 1);
154 else
155 etm_writel(t, ETMVDC3_EXCLONLY, ETMR_VIEWDATACTRL3);
156
157 etm_writel(t, 0x6f, ETMR_VIEWDATAEVT);
158
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100159 v &= ~ETMCTRL_PROGRAM;
160 v |= ETMCTRL_PORTSEL;
161
162 etm_writel(t, v, ETMR_CTRL);
163
164 timeout = TRACER_TIMEOUT;
165 while (etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout)
166 ;
167 if (!timeout) {
168 dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n");
169 etm_lock(t);
170 return -EFAULT;
171 }
172
173 etm_lock(t);
174
175 t->flags |= TRACER_RUNNING;
176
177 return 0;
178}
179
180static int trace_stop(struct tracectx *t)
181{
182 unsigned long timeout = TRACER_TIMEOUT;
183
184 etm_unlock(t);
185
186 etm_writel(t, 0x440, ETMR_CTRL);
187 while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
188 ;
189 if (!timeout) {
190 dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
191 etm_lock(t);
192 return -EFAULT;
193 }
194
195 etm_lock(t);
196
197 etb_unlock(t);
198 etb_writel(t, ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
199
200 timeout = TRACER_TIMEOUT;
201 while (etb_readl(t, ETBR_FORMATTERCTRL) &
202 ETBFF_MANUAL_FLUSH && --timeout)
203 ;
204 if (!timeout) {
205 dev_dbg(t->dev, "Waiting for formatter flush to commence "
206 "timed out\n");
207 etb_lock(t);
208 return -EFAULT;
209 }
210
211 etb_writel(t, 0, ETBR_CTRL);
212
213 etb_lock(t);
214
215 t->flags &= ~TRACER_RUNNING;
216
217 return 0;
218}
219
220static int etb_getdatalen(struct tracectx *t)
221{
222 u32 v;
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800223 int wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100224
225 v = etb_readl(t, ETBR_STATUS);
226
227 if (v & 1)
228 return t->etb_bufsz;
229
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100230 wp = etb_readl(t, ETBR_WRITEADDR);
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800231 return wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100232}
233
234/* sysrq+v will always stop the running trace and leave it at that */
235static void etm_dump(void)
236{
237 struct tracectx *t = &tracer;
238 u32 first = 0;
239 int length;
240
241 if (!t->etb_regs) {
242 printk(KERN_INFO "No tracing hardware found\n");
243 return;
244 }
245
246 if (trace_isrunning(t))
247 trace_stop(t);
248
249 etb_unlock(t);
250
251 length = etb_getdatalen(t);
252
253 if (length == t->etb_bufsz)
254 first = etb_readl(t, ETBR_WRITEADDR);
255
256 etb_writel(t, first, ETBR_READADDR);
257
258 printk(KERN_INFO "Trace buffer contents length: %d\n", length);
259 printk(KERN_INFO "--- ETB buffer begin ---\n");
260 for (; length; length--)
261 printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
262 printk(KERN_INFO "\n--- ETB buffer end ---\n");
263
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100264 etb_lock(t);
265}
266
Dmitry Torokhov1495cc92010-08-17 21:15:46 -0700267static void sysrq_etm_dump(int key)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100268{
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800269 if (!mutex_trylock(&tracer.mutex)) {
270 printk(KERN_INFO "Tracing hardware busy\n");
271 return;
272 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100273 dev_dbg(tracer.dev, "Dumping ETB buffer\n");
274 etm_dump();
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800275 mutex_unlock(&tracer.mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100276}
277
278static struct sysrq_key_op sysrq_etm_op = {
279 .handler = sysrq_etm_dump,
280 .help_msg = "ETM buffer dump",
281 .action_msg = "etm",
282};
283
284static int etb_open(struct inode *inode, struct file *file)
285{
286 if (!tracer.etb_regs)
287 return -ENODEV;
288
289 file->private_data = &tracer;
290
291 return nonseekable_open(inode, file);
292}
293
294static ssize_t etb_read(struct file *file, char __user *data,
295 size_t len, loff_t *ppos)
296{
297 int total, i;
298 long length;
299 struct tracectx *t = file->private_data;
300 u32 first = 0;
301 u32 *buf;
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800302 int wpos;
303 int skip;
304 long wlength;
305 loff_t pos = *ppos;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100306
307 mutex_lock(&t->mutex);
308
309 if (trace_isrunning(t)) {
310 length = 0;
311 goto out;
312 }
313
314 etb_unlock(t);
315
316 total = etb_getdatalen(t);
Arve Hjønnevåg3a91f3e2011-02-04 22:38:14 -0800317 if (total == 0 && t->dump_initial_etb)
318 total = t->etb_bufsz;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100319 if (total == t->etb_bufsz)
320 first = etb_readl(t, ETBR_WRITEADDR);
321
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800322 if (pos > total * 4) {
323 skip = 0;
324 wpos = total;
325 } else {
326 skip = (int)pos % 4;
327 wpos = (int)pos / 4;
328 }
329 total -= wpos;
330 first = (first + wpos) % t->etb_bufsz;
331
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100332 etb_writel(t, first, ETBR_READADDR);
333
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800334 wlength = min(total, DIV_ROUND_UP(skip + (int)len, 4));
335 length = min(total * 4 - skip, (int)len);
336 buf = vmalloc(wlength * 4);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100337
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800338 dev_dbg(t->dev, "ETB read %ld bytes to %lld from %ld words at %d\n",
339 length, pos, wlength, first);
340 dev_dbg(t->dev, "ETB buffer length: %d\n", total + wpos);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100341 dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800342 for (i = 0; i < wlength; i++)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100343 buf[i] = etb_readl(t, ETBR_READMEM);
344
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100345 etb_lock(t);
346
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800347 length -= copy_to_user(data, (u8 *)buf + skip, length);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100348 vfree(buf);
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800349 *ppos = pos + length;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100350
351out:
352 mutex_unlock(&t->mutex);
353
354 return length;
355}
356
357static int etb_release(struct inode *inode, struct file *file)
358{
359 /* there's nothing to do here, actually */
360 return 0;
361}
362
363static const struct file_operations etb_fops = {
364 .owner = THIS_MODULE,
365 .read = etb_read,
366 .open = etb_open,
367 .release = etb_release,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200368 .llseek = no_llseek,
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100369};
370
371static struct miscdevice etb_miscdev = {
372 .name = "tracebuf",
373 .minor = 0,
374 .fops = &etb_fops,
375};
376
Ming Lei8e880692011-03-28 06:10:25 +0100377static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100378{
379 struct tracectx *t = &tracer;
380 int ret = 0;
381
382 ret = amba_request_regions(dev, NULL);
383 if (ret)
384 goto out;
385
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800386 mutex_lock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100387 t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
388 if (!t->etb_regs) {
389 ret = -ENOMEM;
390 goto out_release;
391 }
392
Arve Hjønnevåg3a91f3e2011-02-04 22:38:14 -0800393 t->dump_initial_etb = true;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100394 amba_set_drvdata(dev, t);
395
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800396 etb_unlock(t);
397 t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
398 dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
399
400 /* make sure trace capture is disabled */
401 etb_writel(t, 0, ETBR_CTRL);
402 etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
403 etb_lock(t);
404 mutex_unlock(&t->mutex);
405
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100406 etb_miscdev.parent = &dev->dev;
407
408 ret = misc_register(&etb_miscdev);
409 if (ret)
410 goto out_unmap;
411
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800412 /* Get optional clock. Currently used to select clock source on omap3 */
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100413 t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800414 if (IS_ERR(t->emu_clk))
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100415 dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800416 else
417 clk_enable(t->emu_clk);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100418
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100419 dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n");
420
421out:
422 return ret;
423
424out_unmap:
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800425 mutex_lock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100426 amba_set_drvdata(dev, NULL);
427 iounmap(t->etb_regs);
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800428 t->etb_regs = NULL;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100429
430out_release:
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800431 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100432 amba_release_regions(dev);
433
434 return ret;
435}
436
437static int etb_remove(struct amba_device *dev)
438{
439 struct tracectx *t = amba_get_drvdata(dev);
440
441 amba_set_drvdata(dev, NULL);
442
443 iounmap(t->etb_regs);
444 t->etb_regs = NULL;
445
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800446 if (!IS_ERR(t->emu_clk)) {
447 clk_disable(t->emu_clk);
448 clk_put(t->emu_clk);
449 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100450
451 amba_release_regions(dev);
452
453 return 0;
454}
455
456static struct amba_id etb_ids[] = {
457 {
458 .id = 0x0003b907,
459 .mask = 0x0007ffff,
460 },
461 { 0, 0 },
462};
463
464static struct amba_driver etb_driver = {
465 .drv = {
466 .name = "etb",
467 .owner = THIS_MODULE,
468 },
469 .probe = etb_probe,
470 .remove = etb_remove,
471 .id_table = etb_ids,
472};
473
474/* use a sysfs file "trace_running" to start/stop tracing */
475static ssize_t trace_running_show(struct kobject *kobj,
476 struct kobj_attribute *attr,
477 char *buf)
478{
479 return sprintf(buf, "%x\n", trace_isrunning(&tracer));
480}
481
482static ssize_t trace_running_store(struct kobject *kobj,
483 struct kobj_attribute *attr,
484 const char *buf, size_t n)
485{
486 unsigned int value;
487 int ret;
488
489 if (sscanf(buf, "%u", &value) != 1)
490 return -EINVAL;
491
492 mutex_lock(&tracer.mutex);
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800493 if (!tracer.etb_regs)
494 ret = -ENODEV;
495 else
496 ret = value ? trace_start(&tracer) : trace_stop(&tracer);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100497 mutex_unlock(&tracer.mutex);
498
499 return ret ? : n;
500}
501
502static struct kobj_attribute trace_running_attr =
503 __ATTR(trace_running, 0644, trace_running_show, trace_running_store);
504
505static ssize_t trace_info_show(struct kobject *kobj,
506 struct kobj_attribute *attr,
507 char *buf)
508{
509 u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
510 int datalen;
511
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800512 mutex_lock(&tracer.mutex);
513 if (tracer.etb_regs) {
514 etb_unlock(&tracer);
515 datalen = etb_getdatalen(&tracer);
516 etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
517 etb_ra = etb_readl(&tracer, ETBR_READADDR);
518 etb_st = etb_readl(&tracer, ETBR_STATUS);
519 etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
520 etb_lock(&tracer);
521 } else {
522 etb_wa = etb_ra = etb_st = etb_fc = ~0;
523 datalen = -1;
524 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100525
526 etm_unlock(&tracer);
527 etm_ctrl = etm_readl(&tracer, ETMR_CTRL);
528 etm_st = etm_readl(&tracer, ETMR_STATUS);
529 etm_lock(&tracer);
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800530 mutex_unlock(&tracer.mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100531
532 return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
533 "ETBR_WRITEADDR:\t%08x\n"
534 "ETBR_READADDR:\t%08x\n"
535 "ETBR_STATUS:\t%08x\n"
536 "ETBR_FORMATTERCTRL:\t%08x\n"
537 "ETMR_CTRL:\t%08x\n"
538 "ETMR_STATUS:\t%08x\n",
539 datalen,
540 tracer.ncmppairs,
541 etb_wa,
542 etb_ra,
543 etb_st,
544 etb_fc,
545 etm_ctrl,
546 etm_st
547 );
548}
549
550static struct kobj_attribute trace_info_attr =
551 __ATTR(trace_info, 0444, trace_info_show, NULL);
552
553static ssize_t trace_mode_show(struct kobject *kobj,
554 struct kobj_attribute *attr,
555 char *buf)
556{
557 return sprintf(buf, "%d %d\n",
558 !!(tracer.flags & TRACER_CYCLE_ACC),
559 tracer.etm_portsz);
560}
561
562static ssize_t trace_mode_store(struct kobject *kobj,
563 struct kobj_attribute *attr,
564 const char *buf, size_t n)
565{
566 unsigned int cycacc, portsz;
567
568 if (sscanf(buf, "%u %u", &cycacc, &portsz) != 2)
569 return -EINVAL;
570
571 mutex_lock(&tracer.mutex);
572 if (cycacc)
573 tracer.flags |= TRACER_CYCLE_ACC;
574 else
575 tracer.flags &= ~TRACER_CYCLE_ACC;
576
577 tracer.etm_portsz = portsz & 0x0f;
578 mutex_unlock(&tracer.mutex);
579
580 return n;
581}
582
583static struct kobj_attribute trace_mode_attr =
584 __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
585
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800586static ssize_t trace_range_show(struct kobject *kobj,
587 struct kobj_attribute *attr,
588 char *buf)
589{
590 return sprintf(buf, "%08lx %08lx\n",
591 tracer.range_start, tracer.range_end);
592}
593
594static ssize_t trace_range_store(struct kobject *kobj,
595 struct kobj_attribute *attr,
596 const char *buf, size_t n)
597{
598 unsigned long range_start, range_end;
599
600 if (sscanf(buf, "%lx %lx", &range_start, &range_end) != 2)
601 return -EINVAL;
602
603 mutex_lock(&tracer.mutex);
604 tracer.range_start = range_start;
605 tracer.range_end = range_end;
606 mutex_unlock(&tracer.mutex);
607
608 return n;
609}
610
611
612static struct kobj_attribute trace_range_attr =
613 __ATTR(trace_range, 0644, trace_range_show, trace_range_store);
614
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800615static ssize_t trace_data_range_show(struct kobject *kobj,
616 struct kobj_attribute *attr,
617 char *buf)
618{
619 unsigned long range_start;
620 u64 range_end;
621 mutex_lock(&tracer.mutex);
622 range_start = tracer.data_range_start;
623 range_end = tracer.data_range_end;
624 if (!range_end && (tracer.flags & TRACER_TRACE_DATA))
625 range_end = 0x100000000ULL;
626 mutex_unlock(&tracer.mutex);
627 return sprintf(buf, "%08lx %08llx\n", range_start, range_end);
628}
629
630static ssize_t trace_data_range_store(struct kobject *kobj,
631 struct kobj_attribute *attr,
632 const char *buf, size_t n)
633{
634 unsigned long range_start;
635 u64 range_end;
636
637 if (sscanf(buf, "%lx %llx", &range_start, &range_end) != 2)
638 return -EINVAL;
639
640 mutex_lock(&tracer.mutex);
641 tracer.data_range_start = range_start;
642 tracer.data_range_end = (unsigned long)range_end;
643 if (range_end)
644 tracer.flags |= TRACER_TRACE_DATA;
645 else
646 tracer.flags &= ~TRACER_TRACE_DATA;
647 mutex_unlock(&tracer.mutex);
648
649 return n;
650}
651
652
653static struct kobj_attribute trace_data_range_attr =
654 __ATTR(trace_data_range, 0644,
655 trace_data_range_show, trace_data_range_store);
656
Ming Lei8e880692011-03-28 06:10:25 +0100657static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100658{
659 struct tracectx *t = &tracer;
660 int ret = 0;
661
662 if (t->etm_regs) {
663 dev_dbg(&dev->dev, "ETM already initialized\n");
664 ret = -EBUSY;
665 goto out;
666 }
667
668 ret = amba_request_regions(dev, NULL);
669 if (ret)
670 goto out;
671
672 t->etm_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
673 if (!t->etm_regs) {
674 ret = -ENOMEM;
675 goto out_release;
676 }
677
678 amba_set_drvdata(dev, t);
679
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100680 t->dev = &dev->dev;
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800681 t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100682 t->etm_portsz = 1;
683
684 etm_unlock(t);
Alexander Shishkin988257c2010-08-04 11:27:33 +0100685 (void)etm_readl(t, ETMMR_PDSR);
686 /* dummy first read */
687 (void)etm_readl(&tracer, ETMMR_OSSRR);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100688
689 t->ncmppairs = etm_readl(t, ETMR_CONFCODE) & 0xf;
690 etm_writel(t, 0x440, ETMR_CTRL);
691 etm_lock(t);
692
693 ret = sysfs_create_file(&dev->dev.kobj,
694 &trace_running_attr.attr);
695 if (ret)
696 goto out_unmap;
697
698 /* failing to create any of these two is not fatal */
699 ret = sysfs_create_file(&dev->dev.kobj, &trace_info_attr.attr);
700 if (ret)
701 dev_dbg(&dev->dev, "Failed to create trace_info in sysfs\n");
702
703 ret = sysfs_create_file(&dev->dev.kobj, &trace_mode_attr.attr);
704 if (ret)
705 dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n");
706
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800707 ret = sysfs_create_file(&dev->dev.kobj, &trace_range_attr.attr);
708 if (ret)
709 dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n");
710
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800711 ret = sysfs_create_file(&dev->dev.kobj, &trace_data_range_attr.attr);
712 if (ret)
713 dev_dbg(&dev->dev,
714 "Failed to create trace_data_range in sysfs\n");
715
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100716 dev_dbg(t->dev, "ETM AMBA driver initialized.\n");
717
718out:
719 return ret;
720
721out_unmap:
722 amba_set_drvdata(dev, NULL);
723 iounmap(t->etm_regs);
724
725out_release:
726 amba_release_regions(dev);
727
728 return ret;
729}
730
731static int etm_remove(struct amba_device *dev)
732{
733 struct tracectx *t = amba_get_drvdata(dev);
734
735 amba_set_drvdata(dev, NULL);
736
737 iounmap(t->etm_regs);
738 t->etm_regs = NULL;
739
740 amba_release_regions(dev);
741
742 sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr);
743 sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
744 sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr);
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800745 sysfs_remove_file(&dev->dev.kobj, &trace_range_attr.attr);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800746 sysfs_remove_file(&dev->dev.kobj, &trace_data_range_attr.attr);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100747
748 return 0;
749}
750
751static struct amba_id etm_ids[] = {
752 {
753 .id = 0x0003b921,
754 .mask = 0x0007ffff,
755 },
756 { 0, 0 },
757};
758
759static struct amba_driver etm_driver = {
760 .drv = {
761 .name = "etm",
762 .owner = THIS_MODULE,
763 },
764 .probe = etm_probe,
765 .remove = etm_remove,
766 .id_table = etm_ids,
767};
768
769static int __init etm_init(void)
770{
771 int retval;
772
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800773 mutex_init(&tracer.mutex);
774
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100775 retval = amba_driver_register(&etb_driver);
776 if (retval) {
777 printk(KERN_ERR "Failed to register etb\n");
778 return retval;
779 }
780
781 retval = amba_driver_register(&etm_driver);
782 if (retval) {
783 amba_driver_unregister(&etb_driver);
784 printk(KERN_ERR "Failed to probe etm\n");
785 return retval;
786 }
787
788 /* not being able to install this handler is not fatal */
789 (void)register_sysrq_key('v', &sysrq_etm_op);
790
791 return 0;
792}
793
794device_initcall(etm_init);
795