blob: 2e7bff8fb44abf11fd60ea53aac79b2ce1c4a608 [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;
Alexander Shishkin8234eae2010-08-04 11:22:43 +010045 struct device *dev;
46 struct clk *emu_clk;
47 struct mutex mutex;
48};
49
Arve Hjønnevåg51495972011-01-28 23:44:43 -080050static struct tracectx tracer = {
51 .range_start = (unsigned long)_stext,
52 .range_end = (unsigned long)_etext,
53};
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010054
55static inline bool trace_isrunning(struct tracectx *t)
56{
57 return !!(t->flags & TRACER_RUNNING);
58}
59
60static int etm_setup_address_range(struct tracectx *t, int n,
61 unsigned long start, unsigned long end, int exclude, int data)
62{
Arve Hjønnevågccd3dbc2011-01-28 23:33:11 -080063 u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_IGNSECURITY |
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010064 ETMAAT_NOVALCMP;
65
66 if (n < 1 || n > t->ncmppairs)
67 return -EINVAL;
68
69 /* comparators and ranges are numbered starting with 1 as opposed
70 * to bits in a word */
71 n--;
72
73 if (data)
74 flags |= ETMAAT_DLOADSTORE;
75 else
76 flags |= ETMAAT_IEXEC;
77
78 /* first comparator for the range */
79 etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2));
80 etm_writel(t, start, ETMR_COMP_VAL(n * 2));
81
82 /* second comparator is right next to it */
83 etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
84 etm_writel(t, end, ETMR_COMP_VAL(n * 2 + 1));
85
86 flags = exclude ? ETMTE_INCLEXCL : 0;
87 etm_writel(t, flags | (1 << n), ETMR_TRACEENCTRL);
88
89 return 0;
90}
91
92static int trace_start(struct tracectx *t)
93{
94 u32 v;
95 unsigned long timeout = TRACER_TIMEOUT;
96
97 etb_unlock(t);
98
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -080099 etb_writel(t, 0, ETBR_WRITEADDR);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100100 etb_writel(t, 0, ETBR_FORMATTERCTRL);
101 etb_writel(t, 1, ETBR_CTRL);
102
103 etb_lock(t);
104
105 /* configure etm */
106 v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz);
107
108 if (t->flags & TRACER_CYCLE_ACC)
109 v |= ETMCTRL_CYCLEACCURATE;
110
111 etm_unlock(t);
112
113 etm_writel(t, v, ETMR_CTRL);
114
115 while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
116 ;
117 if (!timeout) {
118 dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
119 etm_lock(t);
120 return -EFAULT;
121 }
122
Arve Hjønnevåg51495972011-01-28 23:44:43 -0800123 if (t->range_start || t->range_end)
124 etm_setup_address_range(t, 1,
125 t->range_start, t->range_end, 0, 0);
126 else
127 etm_writel(t, ETMTE_INCLEXCL, ETMR_TRACEENCTRL);
128
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100129 etm_writel(t, 0, ETMR_TRACEENCTRL2);
130 etm_writel(t, 0, ETMR_TRACESSCTRL);
131 etm_writel(t, 0x6f, ETMR_TRACEENEVT);
132
133 v &= ~ETMCTRL_PROGRAM;
134 v |= ETMCTRL_PORTSEL;
135
136 etm_writel(t, v, ETMR_CTRL);
137
138 timeout = TRACER_TIMEOUT;
139 while (etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout)
140 ;
141 if (!timeout) {
142 dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n");
143 etm_lock(t);
144 return -EFAULT;
145 }
146
147 etm_lock(t);
148
149 t->flags |= TRACER_RUNNING;
150
151 return 0;
152}
153
154static int trace_stop(struct tracectx *t)
155{
156 unsigned long timeout = TRACER_TIMEOUT;
157
158 etm_unlock(t);
159
160 etm_writel(t, 0x440, ETMR_CTRL);
161 while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
162 ;
163 if (!timeout) {
164 dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
165 etm_lock(t);
166 return -EFAULT;
167 }
168
169 etm_lock(t);
170
171 etb_unlock(t);
172 etb_writel(t, ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
173
174 timeout = TRACER_TIMEOUT;
175 while (etb_readl(t, ETBR_FORMATTERCTRL) &
176 ETBFF_MANUAL_FLUSH && --timeout)
177 ;
178 if (!timeout) {
179 dev_dbg(t->dev, "Waiting for formatter flush to commence "
180 "timed out\n");
181 etb_lock(t);
182 return -EFAULT;
183 }
184
185 etb_writel(t, 0, ETBR_CTRL);
186
187 etb_lock(t);
188
189 t->flags &= ~TRACER_RUNNING;
190
191 return 0;
192}
193
194static int etb_getdatalen(struct tracectx *t)
195{
196 u32 v;
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800197 int wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100198
199 v = etb_readl(t, ETBR_STATUS);
200
201 if (v & 1)
202 return t->etb_bufsz;
203
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100204 wp = etb_readl(t, ETBR_WRITEADDR);
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800205 return wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100206}
207
208/* sysrq+v will always stop the running trace and leave it at that */
209static void etm_dump(void)
210{
211 struct tracectx *t = &tracer;
212 u32 first = 0;
213 int length;
214
215 if (!t->etb_regs) {
216 printk(KERN_INFO "No tracing hardware found\n");
217 return;
218 }
219
220 if (trace_isrunning(t))
221 trace_stop(t);
222
223 etb_unlock(t);
224
225 length = etb_getdatalen(t);
226
227 if (length == t->etb_bufsz)
228 first = etb_readl(t, ETBR_WRITEADDR);
229
230 etb_writel(t, first, ETBR_READADDR);
231
232 printk(KERN_INFO "Trace buffer contents length: %d\n", length);
233 printk(KERN_INFO "--- ETB buffer begin ---\n");
234 for (; length; length--)
235 printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
236 printk(KERN_INFO "\n--- ETB buffer end ---\n");
237
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100238 etb_lock(t);
239}
240
Dmitry Torokhov1495cc92010-08-17 21:15:46 -0700241static void sysrq_etm_dump(int key)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100242{
243 dev_dbg(tracer.dev, "Dumping ETB buffer\n");
244 etm_dump();
245}
246
247static struct sysrq_key_op sysrq_etm_op = {
248 .handler = sysrq_etm_dump,
249 .help_msg = "ETM buffer dump",
250 .action_msg = "etm",
251};
252
253static int etb_open(struct inode *inode, struct file *file)
254{
255 if (!tracer.etb_regs)
256 return -ENODEV;
257
258 file->private_data = &tracer;
259
260 return nonseekable_open(inode, file);
261}
262
263static ssize_t etb_read(struct file *file, char __user *data,
264 size_t len, loff_t *ppos)
265{
266 int total, i;
267 long length;
268 struct tracectx *t = file->private_data;
269 u32 first = 0;
270 u32 *buf;
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800271 int wpos;
272 int skip;
273 long wlength;
274 loff_t pos = *ppos;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100275
276 mutex_lock(&t->mutex);
277
278 if (trace_isrunning(t)) {
279 length = 0;
280 goto out;
281 }
282
283 etb_unlock(t);
284
285 total = etb_getdatalen(t);
286 if (total == t->etb_bufsz)
287 first = etb_readl(t, ETBR_WRITEADDR);
288
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800289 if (pos > total * 4) {
290 skip = 0;
291 wpos = total;
292 } else {
293 skip = (int)pos % 4;
294 wpos = (int)pos / 4;
295 }
296 total -= wpos;
297 first = (first + wpos) % t->etb_bufsz;
298
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100299 etb_writel(t, first, ETBR_READADDR);
300
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800301 wlength = min(total, DIV_ROUND_UP(skip + (int)len, 4));
302 length = min(total * 4 - skip, (int)len);
303 buf = vmalloc(wlength * 4);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100304
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800305 dev_dbg(t->dev, "ETB read %ld bytes to %lld from %ld words at %d\n",
306 length, pos, wlength, first);
307 dev_dbg(t->dev, "ETB buffer length: %d\n", total + wpos);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100308 dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800309 for (i = 0; i < wlength; i++)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100310 buf[i] = etb_readl(t, ETBR_READMEM);
311
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100312 etb_lock(t);
313
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800314 length -= copy_to_user(data, (u8 *)buf + skip, length);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100315 vfree(buf);
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800316 *ppos = pos + length;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100317
318out:
319 mutex_unlock(&t->mutex);
320
321 return length;
322}
323
324static int etb_release(struct inode *inode, struct file *file)
325{
326 /* there's nothing to do here, actually */
327 return 0;
328}
329
330static const struct file_operations etb_fops = {
331 .owner = THIS_MODULE,
332 .read = etb_read,
333 .open = etb_open,
334 .release = etb_release,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200335 .llseek = no_llseek,
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100336};
337
338static struct miscdevice etb_miscdev = {
339 .name = "tracebuf",
340 .minor = 0,
341 .fops = &etb_fops,
342};
343
Ming Lei8e880692011-03-28 06:10:25 +0100344static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100345{
346 struct tracectx *t = &tracer;
347 int ret = 0;
348
349 ret = amba_request_regions(dev, NULL);
350 if (ret)
351 goto out;
352
353 t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
354 if (!t->etb_regs) {
355 ret = -ENOMEM;
356 goto out_release;
357 }
358
359 amba_set_drvdata(dev, t);
360
361 etb_miscdev.parent = &dev->dev;
362
363 ret = misc_register(&etb_miscdev);
364 if (ret)
365 goto out_unmap;
366
Arve Hjønnevåg875e2e12011-01-28 23:12:32 -0800367 /* Get optional clock. Currently used to select clock source on omap3 */
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100368 t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
Arve Hjønnevåg875e2e12011-01-28 23:12:32 -0800369 if (IS_ERR(t->emu_clk))
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100370 dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
Arve Hjønnevåg875e2e12011-01-28 23:12:32 -0800371 else
372 clk_enable(t->emu_clk);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100373
374 etb_unlock(t);
375 t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
376 dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
377
378 /* make sure trace capture is disabled */
379 etb_writel(t, 0, ETBR_CTRL);
380 etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
381 etb_lock(t);
382
383 dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n");
384
385out:
386 return ret;
387
388out_unmap:
389 amba_set_drvdata(dev, NULL);
390 iounmap(t->etb_regs);
391
392out_release:
393 amba_release_regions(dev);
394
395 return ret;
396}
397
398static int etb_remove(struct amba_device *dev)
399{
400 struct tracectx *t = amba_get_drvdata(dev);
401
402 amba_set_drvdata(dev, NULL);
403
404 iounmap(t->etb_regs);
405 t->etb_regs = NULL;
406
Arve Hjønnevåg875e2e12011-01-28 23:12:32 -0800407 if (!IS_ERR(t->emu_clk)) {
408 clk_disable(t->emu_clk);
409 clk_put(t->emu_clk);
410 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100411
412 amba_release_regions(dev);
413
414 return 0;
415}
416
417static struct amba_id etb_ids[] = {
418 {
419 .id = 0x0003b907,
420 .mask = 0x0007ffff,
421 },
422 { 0, 0 },
423};
424
425static struct amba_driver etb_driver = {
426 .drv = {
427 .name = "etb",
428 .owner = THIS_MODULE,
429 },
430 .probe = etb_probe,
431 .remove = etb_remove,
432 .id_table = etb_ids,
433};
434
435/* use a sysfs file "trace_running" to start/stop tracing */
436static ssize_t trace_running_show(struct kobject *kobj,
437 struct kobj_attribute *attr,
438 char *buf)
439{
440 return sprintf(buf, "%x\n", trace_isrunning(&tracer));
441}
442
443static ssize_t trace_running_store(struct kobject *kobj,
444 struct kobj_attribute *attr,
445 const char *buf, size_t n)
446{
447 unsigned int value;
448 int ret;
449
450 if (sscanf(buf, "%u", &value) != 1)
451 return -EINVAL;
452
453 mutex_lock(&tracer.mutex);
454 ret = value ? trace_start(&tracer) : trace_stop(&tracer);
455 mutex_unlock(&tracer.mutex);
456
457 return ret ? : n;
458}
459
460static struct kobj_attribute trace_running_attr =
461 __ATTR(trace_running, 0644, trace_running_show, trace_running_store);
462
463static ssize_t trace_info_show(struct kobject *kobj,
464 struct kobj_attribute *attr,
465 char *buf)
466{
467 u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
468 int datalen;
469
470 etb_unlock(&tracer);
471 datalen = etb_getdatalen(&tracer);
472 etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
473 etb_ra = etb_readl(&tracer, ETBR_READADDR);
474 etb_st = etb_readl(&tracer, ETBR_STATUS);
475 etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
476 etb_lock(&tracer);
477
478 etm_unlock(&tracer);
479 etm_ctrl = etm_readl(&tracer, ETMR_CTRL);
480 etm_st = etm_readl(&tracer, ETMR_STATUS);
481 etm_lock(&tracer);
482
483 return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
484 "ETBR_WRITEADDR:\t%08x\n"
485 "ETBR_READADDR:\t%08x\n"
486 "ETBR_STATUS:\t%08x\n"
487 "ETBR_FORMATTERCTRL:\t%08x\n"
488 "ETMR_CTRL:\t%08x\n"
489 "ETMR_STATUS:\t%08x\n",
490 datalen,
491 tracer.ncmppairs,
492 etb_wa,
493 etb_ra,
494 etb_st,
495 etb_fc,
496 etm_ctrl,
497 etm_st
498 );
499}
500
501static struct kobj_attribute trace_info_attr =
502 __ATTR(trace_info, 0444, trace_info_show, NULL);
503
504static ssize_t trace_mode_show(struct kobject *kobj,
505 struct kobj_attribute *attr,
506 char *buf)
507{
508 return sprintf(buf, "%d %d\n",
509 !!(tracer.flags & TRACER_CYCLE_ACC),
510 tracer.etm_portsz);
511}
512
513static ssize_t trace_mode_store(struct kobject *kobj,
514 struct kobj_attribute *attr,
515 const char *buf, size_t n)
516{
517 unsigned int cycacc, portsz;
518
519 if (sscanf(buf, "%u %u", &cycacc, &portsz) != 2)
520 return -EINVAL;
521
522 mutex_lock(&tracer.mutex);
523 if (cycacc)
524 tracer.flags |= TRACER_CYCLE_ACC;
525 else
526 tracer.flags &= ~TRACER_CYCLE_ACC;
527
528 tracer.etm_portsz = portsz & 0x0f;
529 mutex_unlock(&tracer.mutex);
530
531 return n;
532}
533
534static struct kobj_attribute trace_mode_attr =
535 __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
536
Arve Hjønnevåg51495972011-01-28 23:44:43 -0800537static ssize_t trace_range_show(struct kobject *kobj,
538 struct kobj_attribute *attr,
539 char *buf)
540{
541 return sprintf(buf, "%08lx %08lx\n",
542 tracer.range_start, tracer.range_end);
543}
544
545static ssize_t trace_range_store(struct kobject *kobj,
546 struct kobj_attribute *attr,
547 const char *buf, size_t n)
548{
549 unsigned long range_start, range_end;
550
551 if (sscanf(buf, "%lx %lx", &range_start, &range_end) != 2)
552 return -EINVAL;
553
554 mutex_lock(&tracer.mutex);
555 tracer.range_start = range_start;
556 tracer.range_end = range_end;
557 mutex_unlock(&tracer.mutex);
558
559 return n;
560}
561
562
563static struct kobj_attribute trace_range_attr =
564 __ATTR(trace_range, 0644, trace_range_show, trace_range_store);
565
Ming Lei8e880692011-03-28 06:10:25 +0100566static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100567{
568 struct tracectx *t = &tracer;
569 int ret = 0;
570
571 if (t->etm_regs) {
572 dev_dbg(&dev->dev, "ETM already initialized\n");
573 ret = -EBUSY;
574 goto out;
575 }
576
577 ret = amba_request_regions(dev, NULL);
578 if (ret)
579 goto out;
580
581 t->etm_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
582 if (!t->etm_regs) {
583 ret = -ENOMEM;
584 goto out_release;
585 }
586
587 amba_set_drvdata(dev, t);
588
589 mutex_init(&t->mutex);
590 t->dev = &dev->dev;
591 t->flags = TRACER_CYCLE_ACC;
592 t->etm_portsz = 1;
593
594 etm_unlock(t);
Alexander Shishkin988257c2010-08-04 11:27:33 +0100595 (void)etm_readl(t, ETMMR_PDSR);
596 /* dummy first read */
597 (void)etm_readl(&tracer, ETMMR_OSSRR);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100598
599 t->ncmppairs = etm_readl(t, ETMR_CONFCODE) & 0xf;
600 etm_writel(t, 0x440, ETMR_CTRL);
601 etm_lock(t);
602
603 ret = sysfs_create_file(&dev->dev.kobj,
604 &trace_running_attr.attr);
605 if (ret)
606 goto out_unmap;
607
608 /* failing to create any of these two is not fatal */
609 ret = sysfs_create_file(&dev->dev.kobj, &trace_info_attr.attr);
610 if (ret)
611 dev_dbg(&dev->dev, "Failed to create trace_info in sysfs\n");
612
613 ret = sysfs_create_file(&dev->dev.kobj, &trace_mode_attr.attr);
614 if (ret)
615 dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n");
616
Arve Hjønnevåg51495972011-01-28 23:44:43 -0800617 ret = sysfs_create_file(&dev->dev.kobj, &trace_range_attr.attr);
618 if (ret)
619 dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n");
620
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100621 dev_dbg(t->dev, "ETM AMBA driver initialized.\n");
622
623out:
624 return ret;
625
626out_unmap:
627 amba_set_drvdata(dev, NULL);
628 iounmap(t->etm_regs);
629
630out_release:
631 amba_release_regions(dev);
632
633 return ret;
634}
635
636static int etm_remove(struct amba_device *dev)
637{
638 struct tracectx *t = amba_get_drvdata(dev);
639
640 amba_set_drvdata(dev, NULL);
641
642 iounmap(t->etm_regs);
643 t->etm_regs = NULL;
644
645 amba_release_regions(dev);
646
647 sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr);
648 sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
649 sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr);
Arve Hjønnevåg51495972011-01-28 23:44:43 -0800650 sysfs_remove_file(&dev->dev.kobj, &trace_range_attr.attr);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100651
652 return 0;
653}
654
655static struct amba_id etm_ids[] = {
656 {
657 .id = 0x0003b921,
658 .mask = 0x0007ffff,
659 },
660 { 0, 0 },
661};
662
663static struct amba_driver etm_driver = {
664 .drv = {
665 .name = "etm",
666 .owner = THIS_MODULE,
667 },
668 .probe = etm_probe,
669 .remove = etm_remove,
670 .id_table = etm_ids,
671};
672
673static int __init etm_init(void)
674{
675 int retval;
676
677 retval = amba_driver_register(&etb_driver);
678 if (retval) {
679 printk(KERN_ERR "Failed to register etb\n");
680 return retval;
681 }
682
683 retval = amba_driver_register(&etm_driver);
684 if (retval) {
685 amba_driver_unregister(&etb_driver);
686 printk(KERN_ERR "Failed to probe etm\n");
687 return retval;
688 }
689
690 /* not being able to install this handler is not fatal */
691 (void)register_sysrq_key('v', &sysrq_etm_op);
692
693 return 0;
694}
695
696device_initcall(etm_init);
697