aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorAlexander Shishkin <virtuoso@slind.org>2009-12-01 08:00:51 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-12-02 05:25:22 -0500
commitc5d6c7708c3e58015b2e4e13e6cea02c8567a94e (patch)
tree2ea9eb6d16be3de06d1172ed83e6bfe2c1c7d376 /arch/arm
parent29e553631b2a0d4eebd23db630572e1027a9967a (diff)
ARM: 5841/1: a driver for on-chip ETM and ETB
This driver implements support for on-chip Embedded Tracing Macrocell and Embedded Trace Buffer. It allows to trigger tracing of kernel execution flow and exporting trace output to userspace via character device and a sysrq combo. Trace output can then be decoded by a fairly simple open source tool [1] which is already sufficient to get the idea of what the kernel is doing. [1]: http://github.com/virtuoso/etm2human Signed-off-by: Alexander Shishkin <virtuoso@slind.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/Kconfig.debug8
-rw-r--r--arch/arm/include/asm/hardware/coresight.h165
-rw-r--r--arch/arm/kernel/Makefile2
-rw-r--r--arch/arm/kernel/etm.c641
4 files changed, 816 insertions, 0 deletions
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 1a6f70e52921..ff54c23d085e 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -83,6 +83,14 @@ config DEBUG_ICEDCC
83 It does include a timeout to ensure that the system does not 83 It does include a timeout to ensure that the system does not
84 totally freeze when there is nothing connected to read. 84 totally freeze when there is nothing connected to read.
85 85
86config OC_ETM
87 bool "On-chip ETM and ETB"
88 select ARM_AMBA
89 help
90 Enables the on-chip embedded trace macrocell and embedded trace
91 buffer driver that will allow you to collect traces of the
92 kernel code.
93
86config DEBUG_DC21285_PORT 94config DEBUG_DC21285_PORT
87 bool "Kernel low-level debugging messages via footbridge serial port" 95 bool "Kernel low-level debugging messages via footbridge serial port"
88 depends on DEBUG_LL && FOOTBRIDGE 96 depends on DEBUG_LL && FOOTBRIDGE
diff --git a/arch/arm/include/asm/hardware/coresight.h b/arch/arm/include/asm/hardware/coresight.h
new file mode 100644
index 000000000000..f82b25d4f73e
--- /dev/null
+++ b/arch/arm/include/asm/hardware/coresight.h
@@ -0,0 +1,165 @@
1/*
2 * linux/arch/arm/include/asm/hardware/coresight.h
3 *
4 * CoreSight components' registers
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#ifndef __ASM_HARDWARE_CORESIGHT_H
15#define __ASM_HARDWARE_CORESIGHT_H
16
17#define TRACER_ACCESSED_BIT 0
18#define TRACER_RUNNING_BIT 1
19#define TRACER_CYCLE_ACC_BIT 2
20#define TRACER_ACCESSED BIT(TRACER_ACCESSED_BIT)
21#define TRACER_RUNNING BIT(TRACER_RUNNING_BIT)
22#define TRACER_CYCLE_ACC BIT(TRACER_CYCLE_ACC_BIT)
23
24struct tracectx {
25 unsigned int etb_bufsz;
26 void __iomem *etb_regs;
27 void __iomem *etm_regs;
28 unsigned long flags;
29 int ncmppairs;
30 int etm_portsz;
31 struct device *dev;
32 struct clk *emu_clk;
33 struct mutex mutex;
34};
35
36#define TRACER_TIMEOUT 10000
37
38#define etm_writel(t, v, x) \
39 (__raw_writel((v), (t)->etm_regs + (x)))
40#define etm_readl(t, x) (__raw_readl((t)->etm_regs + (x)))
41
42/* CoreSight Management Registers */
43#define CSMR_LOCKACCESS 0xfb0
44#define CSMR_LOCKSTATUS 0xfb4
45#define CSMR_AUTHSTATUS 0xfb8
46#define CSMR_DEVID 0xfc8
47#define CSMR_DEVTYPE 0xfcc
48/* CoreSight Component Registers */
49#define CSCR_CLASS 0xff4
50
51#define CSCR_PRSR 0x314
52
53#define UNLOCK_MAGIC 0xc5acce55
54
55/* ETM control register, "ETM Architecture", 3.3.1 */
56#define ETMR_CTRL 0
57#define ETMCTRL_POWERDOWN 1
58#define ETMCTRL_PROGRAM (1 << 10)
59#define ETMCTRL_PORTSEL (1 << 11)
60#define ETMCTRL_DO_CONTEXTID (3 << 14)
61#define ETMCTRL_PORTMASK1 (7 << 4)
62#define ETMCTRL_PORTMASK2 (1 << 21)
63#define ETMCTRL_PORTMASK (ETMCTRL_PORTMASK1 | ETMCTRL_PORTMASK2)
64#define ETMCTRL_PORTSIZE(x) ((((x) & 7) << 4) | (!!((x) & 8)) << 21)
65#define ETMCTRL_DO_CPRT (1 << 1)
66#define ETMCTRL_DATAMASK (3 << 2)
67#define ETMCTRL_DATA_DO_DATA (1 << 2)
68#define ETMCTRL_DATA_DO_ADDR (1 << 3)
69#define ETMCTRL_DATA_DO_BOTH (ETMCTRL_DATA_DO_DATA | ETMCTRL_DATA_DO_ADDR)
70#define ETMCTRL_BRANCH_OUTPUT (1 << 8)
71#define ETMCTRL_CYCLEACCURATE (1 << 12)
72
73/* ETM configuration code register */
74#define ETMR_CONFCODE (0x04)
75
76/* ETM trace start/stop resource control register */
77#define ETMR_TRACESSCTRL (0x18)
78
79/* ETM trigger event register */
80#define ETMR_TRIGEVT (0x08)
81
82/* address access type register bits, "ETM architecture",
83 * table 3-27 */
84/* - access type */
85#define ETMAAT_IFETCH 0
86#define ETMAAT_IEXEC 1
87#define ETMAAT_IEXECPASS 2
88#define ETMAAT_IEXECFAIL 3
89#define ETMAAT_DLOADSTORE 4
90#define ETMAAT_DLOAD 5
91#define ETMAAT_DSTORE 6
92/* - comparison access size */
93#define ETMAAT_JAVA (0 << 3)
94#define ETMAAT_THUMB (1 << 3)
95#define ETMAAT_ARM (3 << 3)
96/* - data value comparison control */
97#define ETMAAT_NOVALCMP (0 << 5)
98#define ETMAAT_VALMATCH (1 << 5)
99#define ETMAAT_VALNOMATCH (3 << 5)
100/* - exact match */
101#define ETMAAT_EXACTMATCH (1 << 7)
102/* - context id comparator control */
103#define ETMAAT_IGNCONTEXTID (0 << 8)
104#define ETMAAT_VALUE1 (1 << 8)
105#define ETMAAT_VALUE2 (2 << 8)
106#define ETMAAT_VALUE3 (3 << 8)
107/* - security level control */
108#define ETMAAT_IGNSECURITY (0 << 10)
109#define ETMAAT_NSONLY (1 << 10)
110#define ETMAAT_SONLY (2 << 10)
111
112#define ETMR_COMP_VAL(x) (0x40 + (x) * 4)
113#define ETMR_COMP_ACC_TYPE(x) (0x80 + (x) * 4)
114
115/* ETM status register, "ETM Architecture", 3.3.2 */
116#define ETMR_STATUS (0x10)
117#define ETMST_OVERFLOW (1 << 0)
118#define ETMST_PROGBIT (1 << 1)
119#define ETMST_STARTSTOP (1 << 2)
120#define ETMST_TRIGGER (1 << 3)
121
122#define etm_progbit(t) (etm_readl((t), ETMR_STATUS) & ETMST_PROGBIT)
123#define etm_started(t) (etm_readl((t), ETMR_STATUS) & ETMST_STARTSTOP)
124#define etm_triggered(t) (etm_readl((t), ETMR_STATUS) & ETMST_TRIGGER)
125
126#define ETMR_TRACEENCTRL2 0x1c
127#define ETMR_TRACEENCTRL 0x24
128#define ETMTE_INCLEXCL (1 << 24)
129#define ETMR_TRACEENEVT 0x20
130#define ETMCTRL_OPTS (ETMCTRL_DO_CPRT | \
131 ETMCTRL_DATA_DO_ADDR | \
132 ETMCTRL_BRANCH_OUTPUT | \
133 ETMCTRL_DO_CONTEXTID)
134
135/* ETB registers, "CoreSight Components TRM", 9.3 */
136#define ETBR_DEPTH 0x04
137#define ETBR_STATUS 0x0c
138#define ETBR_READMEM 0x10
139#define ETBR_READADDR 0x14
140#define ETBR_WRITEADDR 0x18
141#define ETBR_TRIGGERCOUNT 0x1c
142#define ETBR_CTRL 0x20
143#define ETBR_FORMATTERCTRL 0x304
144#define ETBFF_ENFTC 1
145#define ETBFF_ENFCONT (1 << 1)
146#define ETBFF_FONFLIN (1 << 4)
147#define ETBFF_MANUAL_FLUSH (1 << 6)
148#define ETBFF_TRIGIN (1 << 8)
149#define ETBFF_TRIGEVT (1 << 9)
150#define ETBFF_TRIGFL (1 << 10)
151
152#define etb_writel(t, v, x) \
153 (__raw_writel((v), (t)->etb_regs + (x)))
154#define etb_readl(t, x) (__raw_readl((t)->etb_regs + (x)))
155
156#define etm_lock(t) do { etm_writel((t), 0, CSMR_LOCKACCESS); } while (0)
157#define etm_unlock(t) \
158 do { etm_writel((t), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0)
159
160#define etb_lock(t) do { etb_writel((t), 0, CSMR_LOCKACCESS); } while (0)
161#define etb_unlock(t) \
162 do { etb_writel((t), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0)
163
164#endif /* __ASM_HARDWARE_CORESIGHT_H */
165
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 79087dd6d869..e7ccf7e697ce 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -17,6 +17,8 @@ obj-y := compat.o elf.o entry-armv.o entry-common.o irq.o \
17 process.o ptrace.o return_address.o setup.o signal.o \ 17 process.o ptrace.o return_address.o setup.o signal.o \
18 sys_arm.o stacktrace.o time.o traps.o 18 sys_arm.o stacktrace.o time.o traps.o
19 19
20obj-$(CONFIG_OC_ETM) += etm.o
21
20obj-$(CONFIG_ISA_DMA_API) += dma.o 22obj-$(CONFIG_ISA_DMA_API) += dma.o
21obj-$(CONFIG_ARCH_ACORN) += ecard.o 23obj-$(CONFIG_ARCH_ACORN) += ecard.o
22obj-$(CONFIG_FIQ) += fiq.o 24obj-$(CONFIG_FIQ) += fiq.o
diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
new file mode 100644
index 000000000000..827753966301
--- /dev/null
+++ b/arch/arm/kernel/etm.c
@@ -0,0 +1,641 @@
1/*
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
33static struct tracectx tracer;
34
35static inline bool trace_isrunning(struct tracectx *t)
36{
37 return !!(t->flags & TRACER_RUNNING);
38}
39
40static int etm_setup_address_range(struct tracectx *t, int n,
41 unsigned long start, unsigned long end, int exclude, int data)
42{
43 u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_NSONLY | \
44 ETMAAT_NOVALCMP;
45
46 if (n < 1 || n > t->ncmppairs)
47 return -EINVAL;
48
49 /* comparators and ranges are numbered starting with 1 as opposed
50 * to bits in a word */
51 n--;
52
53 if (data)
54 flags |= ETMAAT_DLOADSTORE;
55 else
56 flags |= ETMAAT_IEXEC;
57
58 /* first comparator for the range */
59 etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2));
60 etm_writel(t, start, ETMR_COMP_VAL(n * 2));
61
62 /* second comparator is right next to it */
63 etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
64 etm_writel(t, end, ETMR_COMP_VAL(n * 2 + 1));
65
66 flags = exclude ? ETMTE_INCLEXCL : 0;
67 etm_writel(t, flags | (1 << n), ETMR_TRACEENCTRL);
68
69 return 0;
70}
71
72static int trace_start(struct tracectx *t)
73{
74 u32 v;
75 unsigned long timeout = TRACER_TIMEOUT;
76
77 etb_unlock(t);
78
79 etb_writel(t, 0, ETBR_FORMATTERCTRL);
80 etb_writel(t, 1, ETBR_CTRL);
81
82 etb_lock(t);
83
84 /* configure etm */
85 v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz);
86
87 if (t->flags & TRACER_CYCLE_ACC)
88 v |= ETMCTRL_CYCLEACCURATE;
89
90 etm_unlock(t);
91
92 etm_writel(t, v, ETMR_CTRL);
93
94 while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
95 ;
96 if (!timeout) {
97 dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
98 etm_lock(t);
99 return -EFAULT;
100 }
101
102 etm_setup_address_range(t, 1, (unsigned long)_stext,
103 (unsigned long)_etext, 0, 0);
104 etm_writel(t, 0, ETMR_TRACEENCTRL2);
105 etm_writel(t, 0, ETMR_TRACESSCTRL);
106 etm_writel(t, 0x6f, ETMR_TRACEENEVT);
107
108 v &= ~ETMCTRL_PROGRAM;
109 v |= ETMCTRL_PORTSEL;
110
111 etm_writel(t, v, ETMR_CTRL);
112
113 timeout = TRACER_TIMEOUT;
114 while (etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout)
115 ;
116 if (!timeout) {
117 dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n");
118 etm_lock(t);
119 return -EFAULT;
120 }
121
122 etm_lock(t);
123
124 t->flags |= TRACER_RUNNING;
125
126 return 0;
127}
128
129static int trace_stop(struct tracectx *t)
130{
131 unsigned long timeout = TRACER_TIMEOUT;
132
133 etm_unlock(t);
134
135 etm_writel(t, 0x440, ETMR_CTRL);
136 while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
137 ;
138 if (!timeout) {
139 dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
140 etm_lock(t);
141 return -EFAULT;
142 }
143
144 etm_lock(t);
145
146 etb_unlock(t);
147 etb_writel(t, ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
148
149 timeout = TRACER_TIMEOUT;
150 while (etb_readl(t, ETBR_FORMATTERCTRL) &
151 ETBFF_MANUAL_FLUSH && --timeout)
152 ;
153 if (!timeout) {
154 dev_dbg(t->dev, "Waiting for formatter flush to commence "
155 "timed out\n");
156 etb_lock(t);
157 return -EFAULT;
158 }
159
160 etb_writel(t, 0, ETBR_CTRL);
161
162 etb_lock(t);
163
164 t->flags &= ~TRACER_RUNNING;
165
166 return 0;
167}
168
169static int etb_getdatalen(struct tracectx *t)
170{
171 u32 v;
172 int rp, wp;
173
174 v = etb_readl(t, ETBR_STATUS);
175
176 if (v & 1)
177 return t->etb_bufsz;
178
179 rp = etb_readl(t, ETBR_READADDR);
180 wp = etb_readl(t, ETBR_WRITEADDR);
181
182 if (rp > wp) {
183 etb_writel(t, 0, ETBR_READADDR);
184 etb_writel(t, 0, ETBR_WRITEADDR);
185
186 return 0;
187 }
188
189 return wp - rp;
190}
191
192/* sysrq+v will always stop the running trace and leave it at that */
193static void etm_dump(void)
194{
195 struct tracectx *t = &tracer;
196 u32 first = 0;
197 int length;
198
199 if (!t->etb_regs) {
200 printk(KERN_INFO "No tracing hardware found\n");
201 return;
202 }
203
204 if (trace_isrunning(t))
205 trace_stop(t);
206
207 etb_unlock(t);
208
209 length = etb_getdatalen(t);
210
211 if (length == t->etb_bufsz)
212 first = etb_readl(t, ETBR_WRITEADDR);
213
214 etb_writel(t, first, ETBR_READADDR);
215
216 printk(KERN_INFO "Trace buffer contents length: %d\n", length);
217 printk(KERN_INFO "--- ETB buffer begin ---\n");
218 for (; length; length--)
219 printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
220 printk(KERN_INFO "\n--- ETB buffer end ---\n");
221
222 /* deassert the overflow bit */
223 etb_writel(t, 1, ETBR_CTRL);
224 etb_writel(t, 0, ETBR_CTRL);
225
226 etb_writel(t, 0, ETBR_TRIGGERCOUNT);
227 etb_writel(t, 0, ETBR_READADDR);
228 etb_writel(t, 0, ETBR_WRITEADDR);
229
230 etb_lock(t);
231}
232
233static void sysrq_etm_dump(int key, struct tty_struct *tty)
234{
235 dev_dbg(tracer.dev, "Dumping ETB buffer\n");
236 etm_dump();
237}
238
239static struct sysrq_key_op sysrq_etm_op = {
240 .handler = sysrq_etm_dump,
241 .help_msg = "ETM buffer dump",
242 .action_msg = "etm",
243};
244
245static int etb_open(struct inode *inode, struct file *file)
246{
247 if (!tracer.etb_regs)
248 return -ENODEV;
249
250 file->private_data = &tracer;
251
252 return nonseekable_open(inode, file);
253}
254
255static ssize_t etb_read(struct file *file, char __user *data,
256 size_t len, loff_t *ppos)
257{
258 int total, i;
259 long length;
260 struct tracectx *t = file->private_data;
261 u32 first = 0;
262 u32 *buf;
263
264 mutex_lock(&t->mutex);
265
266 if (trace_isrunning(t)) {
267 length = 0;
268 goto out;
269 }
270
271 etb_unlock(t);
272
273 total = etb_getdatalen(t);
274 if (total == t->etb_bufsz)
275 first = etb_readl(t, ETBR_WRITEADDR);
276
277 etb_writel(t, first, ETBR_READADDR);
278
279 length = min(total * 4, (int)len);
280 buf = vmalloc(length);
281
282 dev_dbg(t->dev, "ETB buffer length: %d\n", total);
283 dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
284 for (i = 0; i < length / 4; i++)
285 buf[i] = etb_readl(t, ETBR_READMEM);
286
287 /* the only way to deassert overflow bit in ETB status is this */
288 etb_writel(t, 1, ETBR_CTRL);
289 etb_writel(t, 0, ETBR_CTRL);
290
291 etb_writel(t, 0, ETBR_WRITEADDR);
292 etb_writel(t, 0, ETBR_READADDR);
293 etb_writel(t, 0, ETBR_TRIGGERCOUNT);
294
295 etb_lock(t);
296
297 length -= copy_to_user(data, buf, length);
298 vfree(buf);
299
300out:
301 mutex_unlock(&t->mutex);
302
303 return length;
304}
305
306static int etb_release(struct inode *inode, struct file *file)
307{
308 /* there's nothing to do here, actually */
309 return 0;
310}
311
312static const struct file_operations etb_fops = {
313 .owner = THIS_MODULE,
314 .read = etb_read,
315 .open = etb_open,
316 .release = etb_release,
317};
318
319static struct miscdevice etb_miscdev = {
320 .name = "tracebuf",
321 .minor = 0,
322 .fops = &etb_fops,
323};
324
325static int __init etb_probe(struct amba_device *dev, struct amba_id *id)
326{
327 struct tracectx *t = &tracer;
328 int ret = 0;
329
330 ret = amba_request_regions(dev, NULL);
331 if (ret)
332 goto out;
333
334 t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
335 if (!t->etb_regs) {
336 ret = -ENOMEM;
337 goto out_release;
338 }
339
340 amba_set_drvdata(dev, t);
341
342 etb_miscdev.parent = &dev->dev;
343
344 ret = misc_register(&etb_miscdev);
345 if (ret)
346 goto out_unmap;
347
348 t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
349 if (IS_ERR(t->emu_clk)) {
350 dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
351 return -EFAULT;
352 }
353
354 clk_enable(t->emu_clk);
355
356 etb_unlock(t);
357 t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
358 dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
359
360 /* make sure trace capture is disabled */
361 etb_writel(t, 0, ETBR_CTRL);
362 etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
363 etb_lock(t);
364
365 dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n");
366
367out:
368 return ret;
369
370out_unmap:
371 amba_set_drvdata(dev, NULL);
372 iounmap(t->etb_regs);
373
374out_release:
375 amba_release_regions(dev);
376
377 return ret;
378}
379
380static int etb_remove(struct amba_device *dev)
381{
382 struct tracectx *t = amba_get_drvdata(dev);
383
384 amba_set_drvdata(dev, NULL);
385
386 iounmap(t->etb_regs);
387 t->etb_regs = NULL;
388
389 clk_disable(t->emu_clk);
390 clk_put(t->emu_clk);
391
392 amba_release_regions(dev);
393
394 return 0;
395}
396
397static struct amba_id etb_ids[] = {
398 {
399 .id = 0x0003b907,
400 .mask = 0x0007ffff,
401 },
402 { 0, 0 },
403};
404
405static struct amba_driver etb_driver = {
406 .drv = {
407 .name = "etb",
408 .owner = THIS_MODULE,
409 },
410 .probe = etb_probe,
411 .remove = etb_remove,
412 .id_table = etb_ids,
413};
414
415/* use a sysfs file "trace_running" to start/stop tracing */
416static ssize_t trace_running_show(struct kobject *kobj,
417 struct kobj_attribute *attr,
418 char *buf)
419{
420 return sprintf(buf, "%x\n", trace_isrunning(&tracer));
421}
422
423static ssize_t trace_running_store(struct kobject *kobj,
424 struct kobj_attribute *attr,
425 const char *buf, size_t n)
426{
427 unsigned int value;
428 int ret;
429
430 if (sscanf(buf, "%u", &value) != 1)
431 return -EINVAL;
432
433 mutex_lock(&tracer.mutex);
434 ret = value ? trace_start(&tracer) : trace_stop(&tracer);
435 mutex_unlock(&tracer.mutex);
436
437 return ret ? : n;
438}
439
440static struct kobj_attribute trace_running_attr =
441 __ATTR(trace_running, 0644, trace_running_show, trace_running_store);
442
443static ssize_t trace_info_show(struct kobject *kobj,
444 struct kobj_attribute *attr,
445 char *buf)
446{
447 u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
448 int datalen;
449
450 etb_unlock(&tracer);
451 datalen = etb_getdatalen(&tracer);
452 etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
453 etb_ra = etb_readl(&tracer, ETBR_READADDR);
454 etb_st = etb_readl(&tracer, ETBR_STATUS);
455 etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
456 etb_lock(&tracer);
457
458 etm_unlock(&tracer);
459 etm_ctrl = etm_readl(&tracer, ETMR_CTRL);
460 etm_st = etm_readl(&tracer, ETMR_STATUS);
461 etm_lock(&tracer);
462
463 return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
464 "ETBR_WRITEADDR:\t%08x\n"
465 "ETBR_READADDR:\t%08x\n"
466 "ETBR_STATUS:\t%08x\n"
467 "ETBR_FORMATTERCTRL:\t%08x\n"
468 "ETMR_CTRL:\t%08x\n"
469 "ETMR_STATUS:\t%08x\n",
470 datalen,
471 tracer.ncmppairs,
472 etb_wa,
473 etb_ra,
474 etb_st,
475 etb_fc,
476 etm_ctrl,
477 etm_st
478 );
479}
480
481static struct kobj_attribute trace_info_attr =
482 __ATTR(trace_info, 0444, trace_info_show, NULL);
483
484static ssize_t trace_mode_show(struct kobject *kobj,
485 struct kobj_attribute *attr,
486 char *buf)
487{
488 return sprintf(buf, "%d %d\n",
489 !!(tracer.flags & TRACER_CYCLE_ACC),
490 tracer.etm_portsz);
491}
492
493static ssize_t trace_mode_store(struct kobject *kobj,
494 struct kobj_attribute *attr,
495 const char *buf, size_t n)
496{
497 unsigned int cycacc, portsz;
498
499 if (sscanf(buf, "%u %u", &cycacc, &portsz) != 2)
500 return -EINVAL;
501
502 mutex_lock(&tracer.mutex);
503 if (cycacc)
504 tracer.flags |= TRACER_CYCLE_ACC;
505 else
506 tracer.flags &= ~TRACER_CYCLE_ACC;
507
508 tracer.etm_portsz = portsz & 0x0f;
509 mutex_unlock(&tracer.mutex);
510
511 return n;
512}
513
514static struct kobj_attribute trace_mode_attr =
515 __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
516
517static int __init etm_probe(struct amba_device *dev, struct amba_id *id)
518{
519 struct tracectx *t = &tracer;
520 int ret = 0;
521
522 if (t->etm_regs) {
523 dev_dbg(&dev->dev, "ETM already initialized\n");
524 ret = -EBUSY;
525 goto out;
526 }
527
528 ret = amba_request_regions(dev, NULL);
529 if (ret)
530 goto out;
531
532 t->etm_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
533 if (!t->etm_regs) {
534 ret = -ENOMEM;
535 goto out_release;
536 }
537
538 amba_set_drvdata(dev, t);
539
540 mutex_init(&t->mutex);
541 t->dev = &dev->dev;
542 t->flags = TRACER_CYCLE_ACC;
543 t->etm_portsz = 1;
544
545 etm_unlock(t);
546 ret = etm_readl(t, CSCR_PRSR);
547
548 t->ncmppairs = etm_readl(t, ETMR_CONFCODE) & 0xf;
549 etm_writel(t, 0x440, ETMR_CTRL);
550 etm_lock(t);
551
552 ret = sysfs_create_file(&dev->dev.kobj,
553 &trace_running_attr.attr);
554 if (ret)
555 goto out_unmap;
556
557 /* failing to create any of these two is not fatal */
558 ret = sysfs_create_file(&dev->dev.kobj, &trace_info_attr.attr);
559 if (ret)
560 dev_dbg(&dev->dev, "Failed to create trace_info in sysfs\n");
561
562 ret = sysfs_create_file(&dev->dev.kobj, &trace_mode_attr.attr);
563 if (ret)
564 dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n");
565
566 dev_dbg(t->dev, "ETM AMBA driver initialized.\n");
567
568out:
569 return ret;
570
571out_unmap:
572 amba_set_drvdata(dev, NULL);
573 iounmap(t->etm_regs);
574
575out_release:
576 amba_release_regions(dev);
577
578 return ret;
579}
580
581static int etm_remove(struct amba_device *dev)
582{
583 struct tracectx *t = amba_get_drvdata(dev);
584
585 amba_set_drvdata(dev, NULL);
586
587 iounmap(t->etm_regs);
588 t->etm_regs = NULL;
589
590 amba_release_regions(dev);
591
592 sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr);
593 sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
594 sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr);
595
596 return 0;
597}
598
599static struct amba_id etm_ids[] = {
600 {
601 .id = 0x0003b921,
602 .mask = 0x0007ffff,
603 },
604 { 0, 0 },
605};
606
607static struct amba_driver etm_driver = {
608 .drv = {
609 .name = "etm",
610 .owner = THIS_MODULE,
611 },
612 .probe = etm_probe,
613 .remove = etm_remove,
614 .id_table = etm_ids,
615};
616
617static int __init etm_init(void)
618{
619 int retval;
620
621 retval = amba_driver_register(&etb_driver);
622 if (retval) {
623 printk(KERN_ERR "Failed to register etb\n");
624 return retval;
625 }
626
627 retval = amba_driver_register(&etm_driver);
628 if (retval) {
629 amba_driver_unregister(&etb_driver);
630 printk(KERN_ERR "Failed to probe etm\n");
631 return retval;
632 }
633
634 /* not being able to install this handler is not fatal */
635 (void)register_sysrq_key('v', &sysrq_etm_op);
636
637 return 0;
638}
639
640device_initcall(etm_init);
641