blob: 8e84d5cb15f33005e8df046ffea582774291f13e [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ågc6b1c352012-04-02 17:20:32 -070046 int etm_contextid_size;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -080047 u32 etb_fc;
Arve Hjønnevågd71c6952011-01-28 23:44:43 -080048 unsigned long range_start;
49 unsigned long range_end;
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -080050 unsigned long data_range_start;
51 unsigned long data_range_end;
Arve Hjønnevåg3a91f3e2011-02-04 22:38:14 -080052 bool dump_initial_etb;
Alexander Shishkin8234eae2010-08-04 11:22:43 +010053 struct device *dev;
54 struct clk *emu_clk;
55 struct mutex mutex;
56};
57
Arve Hjønnevågd71c6952011-01-28 23:44:43 -080058static struct tracectx tracer = {
59 .range_start = (unsigned long)_stext,
60 .range_end = (unsigned long)_etext,
61};
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010062
63static inline bool trace_isrunning(struct tracectx *t)
64{
65 return !!(t->flags & TRACER_RUNNING);
66}
67
Arve Hjønnevåg992cd592011-02-04 22:38:14 -080068static int etm_setup_address_range(struct tracectx *t, int id, int n,
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010069 unsigned long start, unsigned long end, int exclude, int data)
70{
Arve Hjønnevåg8511b5b2011-01-28 23:33:11 -080071 u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_IGNSECURITY |
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010072 ETMAAT_NOVALCMP;
73
74 if (n < 1 || n > t->ncmppairs)
75 return -EINVAL;
76
77 /* comparators and ranges are numbered starting with 1 as opposed
78 * to bits in a word */
79 n--;
80
81 if (data)
82 flags |= ETMAAT_DLOADSTORE;
83 else
84 flags |= ETMAAT_IEXEC;
85
86 /* first comparator for the range */
Arve Hjønnevåg992cd592011-02-04 22:38:14 -080087 etm_writel(t, id, flags, ETMR_COMP_ACC_TYPE(n * 2));
88 etm_writel(t, id, start, ETMR_COMP_VAL(n * 2));
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010089
90 /* second comparator is right next to it */
Arve Hjønnevåg992cd592011-02-04 22:38:14 -080091 etm_writel(t, id, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
92 etm_writel(t, id, end, ETMR_COMP_VAL(n * 2 + 1));
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010093
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -080094 if (data) {
95 flags = exclude ? ETMVDC3_EXCLONLY : 0;
96 if (exclude)
97 n += 8;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -080098 etm_writel(t, id, flags | BIT(n), ETMR_VIEWDATACTRL3);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -080099 } else {
100 flags = exclude ? ETMTE_INCLEXCL : 0;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800101 etm_writel(t, id, flags | (1 << n), ETMR_TRACEENCTRL);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800102 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100103
104 return 0;
105}
106
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800107static int trace_start_etm(struct tracectx *t, int id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100108{
109 u32 v;
110 unsigned long timeout = TRACER_TIMEOUT;
111
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100112 v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz);
Arve Hjønnevågc6b1c352012-04-02 17:20:32 -0700113 v |= ETMCTRL_CONTEXTIDSIZE(t->etm_contextid_size);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100114
115 if (t->flags & TRACER_CYCLE_ACC)
116 v |= ETMCTRL_CYCLEACCURATE;
117
Arve Hjønnevåg434032a2012-04-03 16:15:36 -0700118 if (t->flags & TRACER_BRANCHOUTPUT)
119 v |= ETMCTRL_BRANCH_OUTPUT;
120
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800121 if (t->flags & TRACER_TRACE_DATA)
122 v |= ETMCTRL_DATA_DO_ADDR;
123
Arve Hjønnevågcfb8dc52012-04-02 17:20:32 -0700124 if (t->flags & TRACER_TIMESTAMP)
125 v |= ETMCTRL_TIMESTAMP_EN;
126
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800127 etm_unlock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100128
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800129 etm_writel(t, id, v, ETMR_CTRL);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100130
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800131 while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100132 ;
133 if (!timeout) {
134 dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800135 etm_lock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100136 return -EFAULT;
137 }
138
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800139 if (t->range_start || t->range_end)
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800140 etm_setup_address_range(t, id, 1,
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800141 t->range_start, t->range_end, 0, 0);
142 else
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800143 etm_writel(t, id, ETMTE_INCLEXCL, ETMR_TRACEENCTRL);
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800144
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800145 etm_writel(t, id, 0, ETMR_TRACEENCTRL2);
146 etm_writel(t, id, 0, ETMR_TRACESSCTRL);
147 etm_writel(t, id, 0x6f, ETMR_TRACEENEVT);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100148
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800149 etm_writel(t, id, 0, ETMR_VIEWDATACTRL1);
150 etm_writel(t, id, 0, ETMR_VIEWDATACTRL2);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800151
152 if (t->data_range_start || t->data_range_end)
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800153 etm_setup_address_range(t, id, 2, t->data_range_start,
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800154 t->data_range_end, 0, 1);
155 else
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800156 etm_writel(t, id, ETMVDC3_EXCLONLY, ETMR_VIEWDATACTRL3);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800157
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800158 etm_writel(t, id, 0x6f, ETMR_VIEWDATAEVT);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800159
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100160 v &= ~ETMCTRL_PROGRAM;
161 v |= ETMCTRL_PORTSEL;
162
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800163 etm_writel(t, id, v, ETMR_CTRL);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100164
165 timeout = TRACER_TIMEOUT;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800166 while (etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100167 ;
168 if (!timeout) {
169 dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n");
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800170 etm_lock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100171 return -EFAULT;
172 }
173
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800174 etm_lock(t, id);
175 return 0;
176}
177
178static int trace_start(struct tracectx *t)
179{
180 int ret;
181 int id;
182 u32 etb_fc = t->etb_fc;
183
184 etb_unlock(t);
185
186 t->dump_initial_etb = false;
187 etb_writel(t, 0, ETBR_WRITEADDR);
188 etb_writel(t, etb_fc, ETBR_FORMATTERCTRL);
189 etb_writel(t, 1, ETBR_CTRL);
190
191 etb_lock(t);
192
193 /* configure etm(s) */
194 for (id = 0; id < t->etm_regs_count; id++) {
195 ret = trace_start_etm(t, id);
196 if (ret)
197 return ret;
198 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100199
200 t->flags |= TRACER_RUNNING;
201
202 return 0;
203}
204
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800205static int trace_stop_etm(struct tracectx *t, int id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100206{
207 unsigned long timeout = TRACER_TIMEOUT;
208
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800209 etm_unlock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100210
Arve Hjønnevågeff62a82012-03-28 21:03:13 -0700211 etm_writel(t, id, 0x440, ETMR_CTRL);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800212 while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100213 ;
214 if (!timeout) {
Arve Hjønnevågeff62a82012-03-28 21:03:13 -0700215 dev_err(t->dev,
216 "etm%d: Waiting for progbit to assert timed out\n",
217 id);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800218 etm_lock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100219 return -EFAULT;
220 }
221
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800222 etm_lock(t, id);
223 return 0;
224}
225
Arve Hjønnevågeff62a82012-03-28 21:03:13 -0700226static int trace_power_down_etm(struct tracectx *t, int id)
227{
228 unsigned long timeout = TRACER_TIMEOUT;
229 etm_unlock(t, id);
230 while (!(etm_readl(t, id, ETMR_STATUS) & ETMST_PROGBIT) && --timeout)
231 ;
232 if (!timeout) {
233 dev_err(t->dev, "etm%d: Waiting for status progbit to assert timed out\n",
234 id);
235 etm_lock(t, id);
236 return -EFAULT;
237 }
238
239 etm_writel(t, id, 0x441, ETMR_CTRL);
240
241 etm_lock(t, id);
242 return 0;
243}
244
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800245static int trace_stop(struct tracectx *t)
246{
247 int id;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800248 unsigned long timeout = TRACER_TIMEOUT;
249 u32 etb_fc = t->etb_fc;
250
Arve Hjønnevågeff62a82012-03-28 21:03:13 -0700251 for (id = 0; id < t->etm_regs_count; id++)
252 trace_stop_etm(t, id);
253
254 for (id = 0; id < t->etm_regs_count; id++)
255 trace_power_down_etm(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100256
257 etb_unlock(t);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800258 if (etb_fc) {
259 etb_fc |= ETBFF_STOPFL;
260 etb_writel(t, t->etb_fc, ETBR_FORMATTERCTRL);
261 }
262 etb_writel(t, etb_fc | ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100263
264 timeout = TRACER_TIMEOUT;
265 while (etb_readl(t, ETBR_FORMATTERCTRL) &
266 ETBFF_MANUAL_FLUSH && --timeout)
267 ;
268 if (!timeout) {
269 dev_dbg(t->dev, "Waiting for formatter flush to commence "
270 "timed out\n");
271 etb_lock(t);
272 return -EFAULT;
273 }
274
275 etb_writel(t, 0, ETBR_CTRL);
276
277 etb_lock(t);
278
279 t->flags &= ~TRACER_RUNNING;
280
281 return 0;
282}
283
284static int etb_getdatalen(struct tracectx *t)
285{
286 u32 v;
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800287 int wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100288
289 v = etb_readl(t, ETBR_STATUS);
290
291 if (v & 1)
292 return t->etb_bufsz;
293
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100294 wp = etb_readl(t, ETBR_WRITEADDR);
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800295 return wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100296}
297
298/* sysrq+v will always stop the running trace and leave it at that */
299static void etm_dump(void)
300{
301 struct tracectx *t = &tracer;
302 u32 first = 0;
303 int length;
304
305 if (!t->etb_regs) {
306 printk(KERN_INFO "No tracing hardware found\n");
307 return;
308 }
309
310 if (trace_isrunning(t))
311 trace_stop(t);
312
313 etb_unlock(t);
314
315 length = etb_getdatalen(t);
316
317 if (length == t->etb_bufsz)
318 first = etb_readl(t, ETBR_WRITEADDR);
319
320 etb_writel(t, first, ETBR_READADDR);
321
322 printk(KERN_INFO "Trace buffer contents length: %d\n", length);
323 printk(KERN_INFO "--- ETB buffer begin ---\n");
324 for (; length; length--)
325 printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
326 printk(KERN_INFO "\n--- ETB buffer end ---\n");
327
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100328 etb_lock(t);
329}
330
Dmitry Torokhov1495cc92010-08-17 21:15:46 -0700331static void sysrq_etm_dump(int key)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100332{
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800333 if (!mutex_trylock(&tracer.mutex)) {
334 printk(KERN_INFO "Tracing hardware busy\n");
335 return;
336 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100337 dev_dbg(tracer.dev, "Dumping ETB buffer\n");
338 etm_dump();
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800339 mutex_unlock(&tracer.mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100340}
341
342static struct sysrq_key_op sysrq_etm_op = {
343 .handler = sysrq_etm_dump,
344 .help_msg = "ETM buffer dump",
345 .action_msg = "etm",
346};
347
348static int etb_open(struct inode *inode, struct file *file)
349{
350 if (!tracer.etb_regs)
351 return -ENODEV;
352
353 file->private_data = &tracer;
354
355 return nonseekable_open(inode, file);
356}
357
358static ssize_t etb_read(struct file *file, char __user *data,
359 size_t len, loff_t *ppos)
360{
361 int total, i;
362 long length;
363 struct tracectx *t = file->private_data;
364 u32 first = 0;
365 u32 *buf;
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800366 int wpos;
367 int skip;
368 long wlength;
369 loff_t pos = *ppos;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100370
371 mutex_lock(&t->mutex);
372
373 if (trace_isrunning(t)) {
374 length = 0;
375 goto out;
376 }
377
378 etb_unlock(t);
379
380 total = etb_getdatalen(t);
Arve Hjønnevåg3a91f3e2011-02-04 22:38:14 -0800381 if (total == 0 && t->dump_initial_etb)
382 total = t->etb_bufsz;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100383 if (total == t->etb_bufsz)
384 first = etb_readl(t, ETBR_WRITEADDR);
385
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800386 if (pos > total * 4) {
387 skip = 0;
388 wpos = total;
389 } else {
390 skip = (int)pos % 4;
391 wpos = (int)pos / 4;
392 }
393 total -= wpos;
394 first = (first + wpos) % t->etb_bufsz;
395
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100396 etb_writel(t, first, ETBR_READADDR);
397
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800398 wlength = min(total, DIV_ROUND_UP(skip + (int)len, 4));
399 length = min(total * 4 - skip, (int)len);
400 buf = vmalloc(wlength * 4);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100401
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800402 dev_dbg(t->dev, "ETB read %ld bytes to %lld from %ld words at %d\n",
403 length, pos, wlength, first);
404 dev_dbg(t->dev, "ETB buffer length: %d\n", total + wpos);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100405 dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800406 for (i = 0; i < wlength; i++)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100407 buf[i] = etb_readl(t, ETBR_READMEM);
408
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100409 etb_lock(t);
410
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800411 length -= copy_to_user(data, (u8 *)buf + skip, length);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100412 vfree(buf);
Arve Hjønnevågf13ae472011-01-31 21:34:47 -0800413 *ppos = pos + length;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100414
415out:
416 mutex_unlock(&t->mutex);
417
418 return length;
419}
420
421static int etb_release(struct inode *inode, struct file *file)
422{
423 /* there's nothing to do here, actually */
424 return 0;
425}
426
427static const struct file_operations etb_fops = {
428 .owner = THIS_MODULE,
429 .read = etb_read,
430 .open = etb_open,
431 .release = etb_release,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200432 .llseek = no_llseek,
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100433};
434
435static struct miscdevice etb_miscdev = {
436 .name = "tracebuf",
437 .minor = 0,
438 .fops = &etb_fops,
439};
440
Ming Lei8e880692011-03-28 06:10:25 +0100441static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100442{
443 struct tracectx *t = &tracer;
444 int ret = 0;
445
446 ret = amba_request_regions(dev, NULL);
447 if (ret)
448 goto out;
449
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800450 mutex_lock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100451 t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
452 if (!t->etb_regs) {
453 ret = -ENOMEM;
454 goto out_release;
455 }
456
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800457 t->dev = &dev->dev;
Arve Hjønnevåg3a91f3e2011-02-04 22:38:14 -0800458 t->dump_initial_etb = true;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100459 amba_set_drvdata(dev, t);
460
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800461 etb_unlock(t);
462 t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
463 dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
464
465 /* make sure trace capture is disabled */
466 etb_writel(t, 0, ETBR_CTRL);
467 etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
468 etb_lock(t);
469 mutex_unlock(&t->mutex);
470
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100471 etb_miscdev.parent = &dev->dev;
472
473 ret = misc_register(&etb_miscdev);
474 if (ret)
475 goto out_unmap;
476
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800477 /* Get optional clock. Currently used to select clock source on omap3 */
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100478 t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800479 if (IS_ERR(t->emu_clk))
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100480 dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800481 else
482 clk_enable(t->emu_clk);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100483
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100484 dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n");
485
486out:
487 return ret;
488
489out_unmap:
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800490 mutex_lock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100491 amba_set_drvdata(dev, NULL);
492 iounmap(t->etb_regs);
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800493 t->etb_regs = NULL;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100494
495out_release:
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800496 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100497 amba_release_regions(dev);
498
499 return ret;
500}
501
502static int etb_remove(struct amba_device *dev)
503{
504 struct tracectx *t = amba_get_drvdata(dev);
505
506 amba_set_drvdata(dev, NULL);
507
508 iounmap(t->etb_regs);
509 t->etb_regs = NULL;
510
Arve Hjønnevågd3876592011-01-28 23:12:32 -0800511 if (!IS_ERR(t->emu_clk)) {
512 clk_disable(t->emu_clk);
513 clk_put(t->emu_clk);
514 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100515
516 amba_release_regions(dev);
517
518 return 0;
519}
520
521static struct amba_id etb_ids[] = {
522 {
523 .id = 0x0003b907,
524 .mask = 0x0007ffff,
525 },
526 { 0, 0 },
527};
528
529static struct amba_driver etb_driver = {
530 .drv = {
531 .name = "etb",
532 .owner = THIS_MODULE,
533 },
534 .probe = etb_probe,
535 .remove = etb_remove,
536 .id_table = etb_ids,
537};
538
539/* use a sysfs file "trace_running" to start/stop tracing */
540static ssize_t trace_running_show(struct kobject *kobj,
541 struct kobj_attribute *attr,
542 char *buf)
543{
544 return sprintf(buf, "%x\n", trace_isrunning(&tracer));
545}
546
547static ssize_t trace_running_store(struct kobject *kobj,
548 struct kobj_attribute *attr,
549 const char *buf, size_t n)
550{
551 unsigned int value;
552 int ret;
553
554 if (sscanf(buf, "%u", &value) != 1)
555 return -EINVAL;
556
557 mutex_lock(&tracer.mutex);
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800558 if (!tracer.etb_regs)
559 ret = -ENODEV;
560 else
561 ret = value ? trace_start(&tracer) : trace_stop(&tracer);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100562 mutex_unlock(&tracer.mutex);
563
564 return ret ? : n;
565}
566
567static struct kobj_attribute trace_running_attr =
568 __ATTR(trace_running, 0644, trace_running_show, trace_running_store);
569
570static ssize_t trace_info_show(struct kobject *kobj,
571 struct kobj_attribute *attr,
572 char *buf)
573{
574 u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
575 int datalen;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800576 int id;
577 int ret;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100578
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -0800579 mutex_lock(&tracer.mutex);
580 if (tracer.etb_regs) {
581 etb_unlock(&tracer);
582 datalen = etb_getdatalen(&tracer);
583 etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
584 etb_ra = etb_readl(&tracer, ETBR_READADDR);
585 etb_st = etb_readl(&tracer, ETBR_STATUS);
586 etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
587 etb_lock(&tracer);
588 } else {
589 etb_wa = etb_ra = etb_st = etb_fc = ~0;
590 datalen = -1;
591 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100592
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800593 ret = sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100594 "ETBR_WRITEADDR:\t%08x\n"
595 "ETBR_READADDR:\t%08x\n"
596 "ETBR_STATUS:\t%08x\n"
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800597 "ETBR_FORMATTERCTRL:\t%08x\n",
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100598 datalen,
599 tracer.ncmppairs,
600 etb_wa,
601 etb_ra,
602 etb_st,
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800603 etb_fc
604 );
605
606 for (id = 0; id < tracer.etm_regs_count; id++) {
607 etm_unlock(&tracer, id);
608 etm_ctrl = etm_readl(&tracer, id, ETMR_CTRL);
609 etm_st = etm_readl(&tracer, id, ETMR_STATUS);
610 etm_lock(&tracer, id);
611 ret += sprintf(buf + ret, "ETMR_CTRL:\t%08x\n"
612 "ETMR_STATUS:\t%08x\n",
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100613 etm_ctrl,
614 etm_st
615 );
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800616 }
617 mutex_unlock(&tracer.mutex);
618
619 return ret;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100620}
621
622static struct kobj_attribute trace_info_attr =
623 __ATTR(trace_info, 0444, trace_info_show, NULL);
624
625static ssize_t trace_mode_show(struct kobject *kobj,
626 struct kobj_attribute *attr,
627 char *buf)
628{
629 return sprintf(buf, "%d %d\n",
630 !!(tracer.flags & TRACER_CYCLE_ACC),
631 tracer.etm_portsz);
632}
633
634static ssize_t trace_mode_store(struct kobject *kobj,
635 struct kobj_attribute *attr,
636 const char *buf, size_t n)
637{
638 unsigned int cycacc, portsz;
639
640 if (sscanf(buf, "%u %u", &cycacc, &portsz) != 2)
641 return -EINVAL;
642
643 mutex_lock(&tracer.mutex);
644 if (cycacc)
645 tracer.flags |= TRACER_CYCLE_ACC;
646 else
647 tracer.flags &= ~TRACER_CYCLE_ACC;
648
649 tracer.etm_portsz = portsz & 0x0f;
650 mutex_unlock(&tracer.mutex);
651
652 return n;
653}
654
655static struct kobj_attribute trace_mode_attr =
656 __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
657
Arve Hjønnevågc6b1c352012-04-02 17:20:32 -0700658static ssize_t trace_contextid_size_show(struct kobject *kobj,
659 struct kobj_attribute *attr,
660 char *buf)
661{
662 /* 0: No context id tracing, 1: One byte, 2: Two bytes, 3: Four bytes */
663 return sprintf(buf, "%d\n", (1 << tracer.etm_contextid_size) >> 1);
664}
665
666static ssize_t trace_contextid_size_store(struct kobject *kobj,
667 struct kobj_attribute *attr,
668 const char *buf, size_t n)
669{
670 unsigned int contextid_size;
671
672 if (sscanf(buf, "%u", &contextid_size) != 1)
673 return -EINVAL;
674
675 if (contextid_size == 3 || contextid_size > 4)
676 return -EINVAL;
677
678 mutex_lock(&tracer.mutex);
679 tracer.etm_contextid_size = fls(contextid_size);
680 mutex_unlock(&tracer.mutex);
681
682 return n;
683}
684
685static struct kobj_attribute trace_contextid_size_attr =
686 __ATTR(trace_contextid_size, 0644,
687 trace_contextid_size_show, trace_contextid_size_store);
688
Arve Hjønnevåg434032a2012-04-03 16:15:36 -0700689static ssize_t trace_branch_output_show(struct kobject *kobj,
690 struct kobj_attribute *attr,
691 char *buf)
692{
693 return sprintf(buf, "%d\n", !!(tracer.flags & TRACER_BRANCHOUTPUT));
694}
695
696static ssize_t trace_branch_output_store(struct kobject *kobj,
697 struct kobj_attribute *attr,
698 const char *buf, size_t n)
699{
700 unsigned int branch_output;
701
702 if (sscanf(buf, "%u", &branch_output) != 1)
703 return -EINVAL;
704
705 mutex_lock(&tracer.mutex);
706 if (branch_output)
707 tracer.flags |= TRACER_BRANCHOUTPUT;
708 else
709 tracer.flags &= ~TRACER_BRANCHOUTPUT;
710 mutex_unlock(&tracer.mutex);
711
712 return n;
713}
714
715static struct kobj_attribute trace_branch_output_attr =
716 __ATTR(trace_branch_output, 0644,
717 trace_branch_output_show, trace_branch_output_store);
718
Arve Hjønnevågcfb8dc52012-04-02 17:20:32 -0700719static ssize_t trace_timestamp_show(struct kobject *kobj,
720 struct kobj_attribute *attr,
721 char *buf)
722{
723 return sprintf(buf, "%d\n", !!(tracer.flags & TRACER_TIMESTAMP));
724}
725
726static ssize_t trace_timestamp_store(struct kobject *kobj,
727 struct kobj_attribute *attr,
728 const char *buf, size_t n)
729{
730 unsigned int timestamp;
731
732 if (sscanf(buf, "%u", &timestamp) != 1)
733 return -EINVAL;
734
735 mutex_lock(&tracer.mutex);
736 if (timestamp)
737 tracer.flags |= TRACER_TIMESTAMP;
738 else
739 tracer.flags &= ~TRACER_TIMESTAMP;
740 mutex_unlock(&tracer.mutex);
741
742 return n;
743}
744
745static struct kobj_attribute trace_timestamp_attr =
746 __ATTR(trace_timestamp, 0644,
747 trace_timestamp_show, trace_timestamp_store);
748
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800749static ssize_t trace_range_show(struct kobject *kobj,
750 struct kobj_attribute *attr,
751 char *buf)
752{
753 return sprintf(buf, "%08lx %08lx\n",
754 tracer.range_start, tracer.range_end);
755}
756
757static ssize_t trace_range_store(struct kobject *kobj,
758 struct kobj_attribute *attr,
759 const char *buf, size_t n)
760{
761 unsigned long range_start, range_end;
762
763 if (sscanf(buf, "%lx %lx", &range_start, &range_end) != 2)
764 return -EINVAL;
765
766 mutex_lock(&tracer.mutex);
767 tracer.range_start = range_start;
768 tracer.range_end = range_end;
769 mutex_unlock(&tracer.mutex);
770
771 return n;
772}
773
774
775static struct kobj_attribute trace_range_attr =
776 __ATTR(trace_range, 0644, trace_range_show, trace_range_store);
777
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800778static ssize_t trace_data_range_show(struct kobject *kobj,
779 struct kobj_attribute *attr,
780 char *buf)
781{
782 unsigned long range_start;
783 u64 range_end;
784 mutex_lock(&tracer.mutex);
785 range_start = tracer.data_range_start;
786 range_end = tracer.data_range_end;
787 if (!range_end && (tracer.flags & TRACER_TRACE_DATA))
788 range_end = 0x100000000ULL;
789 mutex_unlock(&tracer.mutex);
790 return sprintf(buf, "%08lx %08llx\n", range_start, range_end);
791}
792
793static ssize_t trace_data_range_store(struct kobject *kobj,
794 struct kobj_attribute *attr,
795 const char *buf, size_t n)
796{
797 unsigned long range_start;
798 u64 range_end;
799
800 if (sscanf(buf, "%lx %llx", &range_start, &range_end) != 2)
801 return -EINVAL;
802
803 mutex_lock(&tracer.mutex);
804 tracer.data_range_start = range_start;
805 tracer.data_range_end = (unsigned long)range_end;
806 if (range_end)
807 tracer.flags |= TRACER_TRACE_DATA;
808 else
809 tracer.flags &= ~TRACER_TRACE_DATA;
810 mutex_unlock(&tracer.mutex);
811
812 return n;
813}
814
815
816static struct kobj_attribute trace_data_range_attr =
817 __ATTR(trace_data_range, 0644,
818 trace_data_range_show, trace_data_range_store);
819
Ming Lei8e880692011-03-28 06:10:25 +0100820static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100821{
822 struct tracectx *t = &tracer;
823 int ret = 0;
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800824 void __iomem **new_regs;
825 int new_count;
Arve Hjønnevågd263bc72012-04-02 20:18:56 -0700826 u32 etmccr;
827 u32 etmidr;
Arve Hjønnevågcfb8dc52012-04-02 17:20:32 -0700828 u32 etmccer = 0;
Arve Hjønnevågd263bc72012-04-02 20:18:56 -0700829 u8 etm_version = 0;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100830
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800831 mutex_lock(&t->mutex);
832 new_count = t->etm_regs_count + 1;
833 new_regs = krealloc(t->etm_regs,
834 sizeof(t->etm_regs[0]) * new_count, GFP_KERNEL);
835
836 if (!new_regs) {
837 dev_dbg(&dev->dev, "Failed to allocate ETM register array\n");
838 ret = -ENOMEM;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100839 goto out;
840 }
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800841 t->etm_regs = new_regs;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100842
843 ret = amba_request_regions(dev, NULL);
844 if (ret)
845 goto out;
846
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800847 t->etm_regs[t->etm_regs_count] =
848 ioremap_nocache(dev->res.start, resource_size(&dev->res));
849 if (!t->etm_regs[t->etm_regs_count]) {
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100850 ret = -ENOMEM;
851 goto out_release;
852 }
853
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800854 amba_set_drvdata(dev, t->etm_regs[t->etm_regs_count]);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100855
Arve Hjønnevåg434032a2012-04-03 16:15:36 -0700856 t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA | TRACER_BRANCHOUTPUT;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100857 t->etm_portsz = 1;
Arve Hjønnevågc6b1c352012-04-02 17:20:32 -0700858 t->etm_contextid_size = 3;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100859
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800860 etm_unlock(t, t->etm_regs_count);
861 (void)etm_readl(t, t->etm_regs_count, ETMMR_PDSR);
Alexander Shishkin988257c2010-08-04 11:27:33 +0100862 /* dummy first read */
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800863 (void)etm_readl(&tracer, t->etm_regs_count, ETMMR_OSSRR);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100864
Arve Hjønnevågd263bc72012-04-02 20:18:56 -0700865 etmccr = etm_readl(t, t->etm_regs_count, ETMR_CONFCODE);
866 t->ncmppairs = etmccr & 0xf;
867 if (etmccr & ETMCCR_ETMIDR_PRESENT) {
868 etmidr = etm_readl(t, t->etm_regs_count, ETMR_ID);
869 etm_version = ETMIDR_VERSION(etmidr);
Arve Hjønnevågcfb8dc52012-04-02 17:20:32 -0700870 if (etm_version >= ETMIDR_VERSION_3_1)
871 etmccer = etm_readl(t, t->etm_regs_count, ETMR_CCE);
Arve Hjønnevågd263bc72012-04-02 20:18:56 -0700872 }
Arve Hjønnevåg42469832011-02-23 16:51:58 -0800873 etm_writel(t, t->etm_regs_count, 0x441, ETMR_CTRL);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800874 etm_writel(t, t->etm_regs_count, new_count, ETMR_TRACEIDR);
875 etm_lock(t, t->etm_regs_count);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100876
877 ret = sysfs_create_file(&dev->dev.kobj,
878 &trace_running_attr.attr);
879 if (ret)
880 goto out_unmap;
881
882 /* failing to create any of these two is not fatal */
883 ret = sysfs_create_file(&dev->dev.kobj, &trace_info_attr.attr);
884 if (ret)
885 dev_dbg(&dev->dev, "Failed to create trace_info in sysfs\n");
886
887 ret = sysfs_create_file(&dev->dev.kobj, &trace_mode_attr.attr);
888 if (ret)
889 dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n");
890
Arve Hjønnevågc6b1c352012-04-02 17:20:32 -0700891 ret = sysfs_create_file(&dev->dev.kobj,
892 &trace_contextid_size_attr.attr);
893 if (ret)
894 dev_dbg(&dev->dev,
895 "Failed to create trace_contextid_size in sysfs\n");
896
Arve Hjønnevåg434032a2012-04-03 16:15:36 -0700897 ret = sysfs_create_file(&dev->dev.kobj,
898 &trace_branch_output_attr.attr);
899 if (ret)
900 dev_dbg(&dev->dev,
901 "Failed to create trace_branch_output in sysfs\n");
902
Arve Hjønnevågcfb8dc52012-04-02 17:20:32 -0700903 if (etmccer & ETMCCER_TIMESTAMPING_IMPLEMENTED) {
904 ret = sysfs_create_file(&dev->dev.kobj,
905 &trace_timestamp_attr.attr);
906 if (ret)
907 dev_dbg(&dev->dev,
908 "Failed to create trace_timestamp in sysfs\n");
909 }
910
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800911 ret = sysfs_create_file(&dev->dev.kobj, &trace_range_attr.attr);
912 if (ret)
913 dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n");
914
Arve Hjønnevågd263bc72012-04-02 20:18:56 -0700915 if (etm_version < ETMIDR_VERSION_PFT_1_0) {
916 ret = sysfs_create_file(&dev->dev.kobj,
917 &trace_data_range_attr.attr);
918 if (ret)
919 dev_dbg(&dev->dev,
920 "Failed to create trace_data_range in sysfs\n");
921 } else {
922 tracer.flags &= ~TRACER_TRACE_DATA;
923 }
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800924
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800925 dev_dbg(&dev->dev, "ETM AMBA driver initialized.\n");
926
927 /* Enable formatter if there are multiple trace sources */
928 if (new_count > 1)
929 t->etb_fc = ETBFF_ENFCONT | ETBFF_ENFTC;
930
931 t->etm_regs_count = new_count;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100932
933out:
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800934 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100935 return ret;
936
937out_unmap:
938 amba_set_drvdata(dev, NULL);
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800939 iounmap(t->etm_regs[t->etm_regs_count]);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100940
941out_release:
942 amba_release_regions(dev);
943
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800944 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100945 return ret;
946}
947
948static int etm_remove(struct amba_device *dev)
949{
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800950 int i;
951 struct tracectx *t = &tracer;
952 void __iomem *etm_regs = amba_get_drvdata(dev);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100953
954 sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr);
955 sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
956 sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr);
Arve Hjønnevågd71c6952011-01-28 23:44:43 -0800957 sysfs_remove_file(&dev->dev.kobj, &trace_range_attr.attr);
Arve Hjønnevåg0c3da532011-01-31 18:33:55 -0800958 sysfs_remove_file(&dev->dev.kobj, &trace_data_range_attr.attr);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100959
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800960 amba_set_drvdata(dev, NULL);
961
962 mutex_lock(&t->mutex);
963 for (i = 0; i < t->etm_regs_count; i++)
964 if (t->etm_regs[i] == etm_regs)
965 break;
966 for (; i < t->etm_regs_count - 1; i++)
967 t->etm_regs[i] = t->etm_regs[i + 1];
968 t->etm_regs_count--;
969 if (!t->etm_regs_count) {
970 kfree(t->etm_regs);
971 t->etm_regs = NULL;
972 }
973 mutex_unlock(&t->mutex);
974
975 iounmap(etm_regs);
976 amba_release_regions(dev);
977
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100978 return 0;
979}
980
981static struct amba_id etm_ids[] = {
982 {
983 .id = 0x0003b921,
984 .mask = 0x0007ffff,
985 },
Arve Hjønnevåg992cd592011-02-04 22:38:14 -0800986 {
987 .id = 0x0003b950,
988 .mask = 0x0007ffff,
989 },
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100990 { 0, 0 },
991};
992
993static struct amba_driver etm_driver = {
994 .drv = {
995 .name = "etm",
996 .owner = THIS_MODULE,
997 },
998 .probe = etm_probe,
999 .remove = etm_remove,
1000 .id_table = etm_ids,
1001};
1002
1003static int __init etm_init(void)
1004{
1005 int retval;
1006
Arve Hjønnevågfe05bda2011-02-14 21:09:51 -08001007 mutex_init(&tracer.mutex);
1008
Alexander Shishkinc5d6c772009-12-01 14:00:51 +01001009 retval = amba_driver_register(&etb_driver);
1010 if (retval) {
1011 printk(KERN_ERR "Failed to register etb\n");
1012 return retval;
1013 }
1014
1015 retval = amba_driver_register(&etm_driver);
1016 if (retval) {
1017 amba_driver_unregister(&etb_driver);
1018 printk(KERN_ERR "Failed to probe etm\n");
1019 return retval;
1020 }
1021
1022 /* not being able to install this handler is not fatal */
1023 (void)register_sysrq_key('v', &sysrq_etm_op);
1024
1025 return 0;
1026}
1027
1028device_initcall(etm_init);
1029