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