blob: 82e6d38fb93d5c968b9eddc198034132b15e57dd [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åg628c4942011-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>
28#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;
Arve Hjønnevåg628c4942011-02-04 22:38:14 -080040 void __iomem **etm_regs;
41 int etm_regs_count;
Alexander Shishkin8234eae2010-08-04 11:22:43 +010042 unsigned long flags;
43 int ncmppairs;
44 int etm_portsz;
Arve Hjønnevåg628c4942011-02-04 22:38:14 -080045 u32 etb_fc;
Arve Hjønnevåg51495972011-01-28 23:44:43 -080046 unsigned long range_start;
47 unsigned long range_end;
Arve Hjønnevåg81e43122011-01-31 18:33:55 -080048 unsigned long data_range_start;
49 unsigned long data_range_end;
Arve Hjønnevåg97aba2e2011-02-04 22:38:14 -080050 bool dump_initial_etb;
Alexander Shishkin8234eae2010-08-04 11:22:43 +010051 struct device *dev;
52 struct clk *emu_clk;
53 struct mutex mutex;
54};
55
Arve Hjønnevåg51495972011-01-28 23:44:43 -080056static struct tracectx tracer = {
57 .range_start = (unsigned long)_stext,
58 .range_end = (unsigned long)_etext,
59};
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010060
61static inline bool trace_isrunning(struct tracectx *t)
62{
63 return !!(t->flags & TRACER_RUNNING);
64}
65
Arve Hjønnevåg628c4942011-02-04 22:38:14 -080066static int etm_setup_address_range(struct tracectx *t, int id, int n,
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010067 unsigned long start, unsigned long end, int exclude, int data)
68{
Arve Hjønnevågccd3dbc2011-01-28 23:33:11 -080069 u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_IGNSECURITY |
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010070 ETMAAT_NOVALCMP;
71
72 if (n < 1 || n > t->ncmppairs)
73 return -EINVAL;
74
75 /* comparators and ranges are numbered starting with 1 as opposed
76 * to bits in a word */
77 n--;
78
79 if (data)
80 flags |= ETMAAT_DLOADSTORE;
81 else
82 flags |= ETMAAT_IEXEC;
83
84 /* first comparator for the range */
Arve Hjønnevåg628c4942011-02-04 22:38:14 -080085 etm_writel(t, id, flags, ETMR_COMP_ACC_TYPE(n * 2));
86 etm_writel(t, id, start, ETMR_COMP_VAL(n * 2));
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010087
88 /* second comparator is right next to it */
Arve Hjønnevåg628c4942011-02-04 22:38:14 -080089 etm_writel(t, id, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
90 etm_writel(t, id, end, ETMR_COMP_VAL(n * 2 + 1));
Alexander Shishkinc5d6c772009-12-01 14:00:51 +010091
Arve Hjønnevåg81e43122011-01-31 18:33:55 -080092 if (data) {
93 flags = exclude ? ETMVDC3_EXCLONLY : 0;
94 if (exclude)
95 n += 8;
Arve Hjønnevåg628c4942011-02-04 22:38:14 -080096 etm_writel(t, id, flags | BIT(n), ETMR_VIEWDATACTRL3);
Arve Hjønnevåg81e43122011-01-31 18:33:55 -080097 } else {
98 flags = exclude ? ETMTE_INCLEXCL : 0;
Arve Hjønnevåg628c4942011-02-04 22:38:14 -080099 etm_writel(t, id, flags | (1 << n), ETMR_TRACEENCTRL);
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800100 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100101
102 return 0;
103}
104
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800105static int trace_start_etm(struct tracectx *t, int id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100106{
107 u32 v;
108 unsigned long timeout = TRACER_TIMEOUT;
109
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100110 v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz);
111
112 if (t->flags & TRACER_CYCLE_ACC)
113 v |= ETMCTRL_CYCLEACCURATE;
114
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800115 if (t->flags & TRACER_TRACE_DATA)
116 v |= ETMCTRL_DATA_DO_ADDR;
117
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800118 etm_unlock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100119
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800120 etm_writel(t, id, v, ETMR_CTRL);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100121
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800122 while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100123 ;
124 if (!timeout) {
125 dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800126 etm_lock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100127 return -EFAULT;
128 }
129
Arve Hjønnevåg51495972011-01-28 23:44:43 -0800130 if (t->range_start || t->range_end)
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800131 etm_setup_address_range(t, id, 1,
Arve Hjønnevåg51495972011-01-28 23:44:43 -0800132 t->range_start, t->range_end, 0, 0);
133 else
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800134 etm_writel(t, id, ETMTE_INCLEXCL, ETMR_TRACEENCTRL);
Arve Hjønnevåg51495972011-01-28 23:44:43 -0800135
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800136 etm_writel(t, id, 0, ETMR_TRACEENCTRL2);
137 etm_writel(t, id, 0, ETMR_TRACESSCTRL);
138 etm_writel(t, id, 0x6f, ETMR_TRACEENEVT);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100139
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800140 etm_writel(t, id, 0, ETMR_VIEWDATACTRL1);
141 etm_writel(t, id, 0, ETMR_VIEWDATACTRL2);
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800142
143 if (t->data_range_start || t->data_range_end)
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800144 etm_setup_address_range(t, id, 2, t->data_range_start,
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800145 t->data_range_end, 0, 1);
146 else
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800147 etm_writel(t, id, ETMVDC3_EXCLONLY, ETMR_VIEWDATACTRL3);
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800148
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800149 etm_writel(t, id, 0x6f, ETMR_VIEWDATAEVT);
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800150
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100151 v &= ~ETMCTRL_PROGRAM;
152 v |= ETMCTRL_PORTSEL;
153
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800154 etm_writel(t, id, v, ETMR_CTRL);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100155
156 timeout = TRACER_TIMEOUT;
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800157 while (etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100158 ;
159 if (!timeout) {
160 dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n");
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800161 etm_lock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100162 return -EFAULT;
163 }
164
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800165 etm_lock(t, id);
166 return 0;
167}
168
169static int trace_start(struct tracectx *t)
170{
171 int ret;
172 int id;
173 u32 etb_fc = t->etb_fc;
174
175 etb_unlock(t);
176
177 t->dump_initial_etb = false;
178 etb_writel(t, 0, ETBR_WRITEADDR);
179 etb_writel(t, etb_fc, ETBR_FORMATTERCTRL);
180 etb_writel(t, 1, ETBR_CTRL);
181
182 etb_lock(t);
183
184 /* configure etm(s) */
185 for (id = 0; id < t->etm_regs_count; id++) {
186 ret = trace_start_etm(t, id);
187 if (ret)
188 return ret;
189 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100190
191 t->flags |= TRACER_RUNNING;
192
193 return 0;
194}
195
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800196static int trace_stop_etm(struct tracectx *t, int id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100197{
198 unsigned long timeout = TRACER_TIMEOUT;
199
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800200 etm_unlock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100201
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800202 etm_writel(t, id, 0x440, ETMR_CTRL);
203 while (!(etm_readl(t, id, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100204 ;
205 if (!timeout) {
206 dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800207 etm_lock(t, id);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100208 return -EFAULT;
209 }
210
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800211 etm_lock(t, id);
212 return 0;
213}
214
215static int trace_stop(struct tracectx *t)
216{
217 int id;
218 int ret;
219 unsigned long timeout = TRACER_TIMEOUT;
220 u32 etb_fc = t->etb_fc;
221
222 for (id = 0; id < t->etm_regs_count; id++) {
223 ret = trace_stop_etm(t, id);
224 if (ret)
225 return ret;
226 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100227
228 etb_unlock(t);
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800229 if (etb_fc) {
230 etb_fc |= ETBFF_STOPFL;
231 etb_writel(t, t->etb_fc, ETBR_FORMATTERCTRL);
232 }
233 etb_writel(t, etb_fc | ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100234
235 timeout = TRACER_TIMEOUT;
236 while (etb_readl(t, ETBR_FORMATTERCTRL) &
237 ETBFF_MANUAL_FLUSH && --timeout)
238 ;
239 if (!timeout) {
240 dev_dbg(t->dev, "Waiting for formatter flush to commence "
241 "timed out\n");
242 etb_lock(t);
243 return -EFAULT;
244 }
245
246 etb_writel(t, 0, ETBR_CTRL);
247
248 etb_lock(t);
249
250 t->flags &= ~TRACER_RUNNING;
251
252 return 0;
253}
254
255static int etb_getdatalen(struct tracectx *t)
256{
257 u32 v;
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800258 int wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100259
260 v = etb_readl(t, ETBR_STATUS);
261
262 if (v & 1)
263 return t->etb_bufsz;
264
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100265 wp = etb_readl(t, ETBR_WRITEADDR);
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800266 return wp;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100267}
268
269/* sysrq+v will always stop the running trace and leave it at that */
270static void etm_dump(void)
271{
272 struct tracectx *t = &tracer;
273 u32 first = 0;
274 int length;
275
276 if (!t->etb_regs) {
277 printk(KERN_INFO "No tracing hardware found\n");
278 return;
279 }
280
281 if (trace_isrunning(t))
282 trace_stop(t);
283
284 etb_unlock(t);
285
286 length = etb_getdatalen(t);
287
288 if (length == t->etb_bufsz)
289 first = etb_readl(t, ETBR_WRITEADDR);
290
291 etb_writel(t, first, ETBR_READADDR);
292
293 printk(KERN_INFO "Trace buffer contents length: %d\n", length);
294 printk(KERN_INFO "--- ETB buffer begin ---\n");
295 for (; length; length--)
296 printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
297 printk(KERN_INFO "\n--- ETB buffer end ---\n");
298
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100299 etb_lock(t);
300}
301
Dmitry Torokhov1495cc92010-08-17 21:15:46 -0700302static void sysrq_etm_dump(int key)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100303{
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800304 if (!mutex_trylock(&tracer.mutex)) {
305 printk(KERN_INFO "Tracing hardware busy\n");
306 return;
307 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100308 dev_dbg(tracer.dev, "Dumping ETB buffer\n");
309 etm_dump();
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800310 mutex_unlock(&tracer.mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100311}
312
313static struct sysrq_key_op sysrq_etm_op = {
314 .handler = sysrq_etm_dump,
315 .help_msg = "ETM buffer dump",
316 .action_msg = "etm",
317};
318
319static int etb_open(struct inode *inode, struct file *file)
320{
321 if (!tracer.etb_regs)
322 return -ENODEV;
323
324 file->private_data = &tracer;
325
326 return nonseekable_open(inode, file);
327}
328
329static ssize_t etb_read(struct file *file, char __user *data,
330 size_t len, loff_t *ppos)
331{
332 int total, i;
333 long length;
334 struct tracectx *t = file->private_data;
335 u32 first = 0;
336 u32 *buf;
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800337 int wpos;
338 int skip;
339 long wlength;
340 loff_t pos = *ppos;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100341
342 mutex_lock(&t->mutex);
343
344 if (trace_isrunning(t)) {
345 length = 0;
346 goto out;
347 }
348
349 etb_unlock(t);
350
351 total = etb_getdatalen(t);
Arve Hjønnevåg97aba2e2011-02-04 22:38:14 -0800352 if (total == 0 && t->dump_initial_etb)
353 total = t->etb_bufsz;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100354 if (total == t->etb_bufsz)
355 first = etb_readl(t, ETBR_WRITEADDR);
356
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800357 if (pos > total * 4) {
358 skip = 0;
359 wpos = total;
360 } else {
361 skip = (int)pos % 4;
362 wpos = (int)pos / 4;
363 }
364 total -= wpos;
365 first = (first + wpos) % t->etb_bufsz;
366
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100367 etb_writel(t, first, ETBR_READADDR);
368
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800369 wlength = min(total, DIV_ROUND_UP(skip + (int)len, 4));
370 length = min(total * 4 - skip, (int)len);
371 buf = vmalloc(wlength * 4);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100372
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800373 dev_dbg(t->dev, "ETB read %ld bytes to %lld from %ld words at %d\n",
374 length, pos, wlength, first);
375 dev_dbg(t->dev, "ETB buffer length: %d\n", total + wpos);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100376 dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800377 for (i = 0; i < wlength; i++)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100378 buf[i] = etb_readl(t, ETBR_READMEM);
379
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100380 etb_lock(t);
381
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800382 length -= copy_to_user(data, (u8 *)buf + skip, length);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100383 vfree(buf);
Arve Hjønnevåg5f388f32011-01-31 21:34:47 -0800384 *ppos = pos + length;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100385
386out:
387 mutex_unlock(&t->mutex);
388
389 return length;
390}
391
392static int etb_release(struct inode *inode, struct file *file)
393{
394 /* there's nothing to do here, actually */
395 return 0;
396}
397
398static const struct file_operations etb_fops = {
399 .owner = THIS_MODULE,
400 .read = etb_read,
401 .open = etb_open,
402 .release = etb_release,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200403 .llseek = no_llseek,
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100404};
405
406static struct miscdevice etb_miscdev = {
407 .name = "tracebuf",
408 .minor = 0,
409 .fops = &etb_fops,
410};
411
Ming Lei8e880692011-03-28 06:10:25 +0100412static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100413{
414 struct tracectx *t = &tracer;
415 int ret = 0;
416
417 ret = amba_request_regions(dev, NULL);
418 if (ret)
419 goto out;
420
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800421 mutex_lock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100422 t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
423 if (!t->etb_regs) {
424 ret = -ENOMEM;
425 goto out_release;
426 }
427
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800428 t->dev = &dev->dev;
Arve Hjønnevåg97aba2e2011-02-04 22:38:14 -0800429 t->dump_initial_etb = true;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100430 amba_set_drvdata(dev, t);
431
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800432 etb_unlock(t);
433 t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
434 dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
435
436 /* make sure trace capture is disabled */
437 etb_writel(t, 0, ETBR_CTRL);
438 etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
439 etb_lock(t);
440 mutex_unlock(&t->mutex);
441
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100442 etb_miscdev.parent = &dev->dev;
443
444 ret = misc_register(&etb_miscdev);
445 if (ret)
446 goto out_unmap;
447
Arve Hjønnevåg875e2e12011-01-28 23:12:32 -0800448 /* Get optional clock. Currently used to select clock source on omap3 */
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100449 t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
Arve Hjønnevåg875e2e12011-01-28 23:12:32 -0800450 if (IS_ERR(t->emu_clk))
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100451 dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
Arve Hjønnevåg875e2e12011-01-28 23:12:32 -0800452 else
453 clk_enable(t->emu_clk);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100454
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100455 dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n");
456
457out:
458 return ret;
459
460out_unmap:
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800461 mutex_lock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100462 amba_set_drvdata(dev, NULL);
463 iounmap(t->etb_regs);
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800464 t->etb_regs = NULL;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100465
466out_release:
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800467 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100468 amba_release_regions(dev);
469
470 return ret;
471}
472
473static int etb_remove(struct amba_device *dev)
474{
475 struct tracectx *t = amba_get_drvdata(dev);
476
477 amba_set_drvdata(dev, NULL);
478
479 iounmap(t->etb_regs);
480 t->etb_regs = NULL;
481
Arve Hjønnevåg875e2e12011-01-28 23:12:32 -0800482 if (!IS_ERR(t->emu_clk)) {
483 clk_disable(t->emu_clk);
484 clk_put(t->emu_clk);
485 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100486
487 amba_release_regions(dev);
488
489 return 0;
490}
491
492static struct amba_id etb_ids[] = {
493 {
494 .id = 0x0003b907,
495 .mask = 0x0007ffff,
496 },
497 { 0, 0 },
498};
499
500static struct amba_driver etb_driver = {
501 .drv = {
502 .name = "etb",
503 .owner = THIS_MODULE,
504 },
505 .probe = etb_probe,
506 .remove = etb_remove,
507 .id_table = etb_ids,
508};
509
510/* use a sysfs file "trace_running" to start/stop tracing */
511static ssize_t trace_running_show(struct kobject *kobj,
512 struct kobj_attribute *attr,
513 char *buf)
514{
515 return sprintf(buf, "%x\n", trace_isrunning(&tracer));
516}
517
518static ssize_t trace_running_store(struct kobject *kobj,
519 struct kobj_attribute *attr,
520 const char *buf, size_t n)
521{
522 unsigned int value;
523 int ret;
524
525 if (sscanf(buf, "%u", &value) != 1)
526 return -EINVAL;
527
528 mutex_lock(&tracer.mutex);
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800529 if (!tracer.etb_regs)
530 ret = -ENODEV;
531 else
532 ret = value ? trace_start(&tracer) : trace_stop(&tracer);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100533 mutex_unlock(&tracer.mutex);
534
535 return ret ? : n;
536}
537
538static struct kobj_attribute trace_running_attr =
539 __ATTR(trace_running, 0644, trace_running_show, trace_running_store);
540
541static ssize_t trace_info_show(struct kobject *kobj,
542 struct kobj_attribute *attr,
543 char *buf)
544{
545 u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
546 int datalen;
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800547 int id;
548 int ret;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100549
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800550 mutex_lock(&tracer.mutex);
551 if (tracer.etb_regs) {
552 etb_unlock(&tracer);
553 datalen = etb_getdatalen(&tracer);
554 etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
555 etb_ra = etb_readl(&tracer, ETBR_READADDR);
556 etb_st = etb_readl(&tracer, ETBR_STATUS);
557 etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
558 etb_lock(&tracer);
559 } else {
560 etb_wa = etb_ra = etb_st = etb_fc = ~0;
561 datalen = -1;
562 }
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100563
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800564 ret = sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100565 "ETBR_WRITEADDR:\t%08x\n"
566 "ETBR_READADDR:\t%08x\n"
567 "ETBR_STATUS:\t%08x\n"
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800568 "ETBR_FORMATTERCTRL:\t%08x\n",
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100569 datalen,
570 tracer.ncmppairs,
571 etb_wa,
572 etb_ra,
573 etb_st,
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800574 etb_fc
575 );
576
577 for (id = 0; id < tracer.etm_regs_count; id++) {
578 etm_unlock(&tracer, id);
579 etm_ctrl = etm_readl(&tracer, id, ETMR_CTRL);
580 etm_st = etm_readl(&tracer, id, ETMR_STATUS);
581 etm_lock(&tracer, id);
582 ret += sprintf(buf + ret, "ETMR_CTRL:\t%08x\n"
583 "ETMR_STATUS:\t%08x\n",
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100584 etm_ctrl,
585 etm_st
586 );
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800587 }
588 mutex_unlock(&tracer.mutex);
589
590 return ret;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100591}
592
593static struct kobj_attribute trace_info_attr =
594 __ATTR(trace_info, 0444, trace_info_show, NULL);
595
596static ssize_t trace_mode_show(struct kobject *kobj,
597 struct kobj_attribute *attr,
598 char *buf)
599{
600 return sprintf(buf, "%d %d\n",
601 !!(tracer.flags & TRACER_CYCLE_ACC),
602 tracer.etm_portsz);
603}
604
605static ssize_t trace_mode_store(struct kobject *kobj,
606 struct kobj_attribute *attr,
607 const char *buf, size_t n)
608{
609 unsigned int cycacc, portsz;
610
611 if (sscanf(buf, "%u %u", &cycacc, &portsz) != 2)
612 return -EINVAL;
613
614 mutex_lock(&tracer.mutex);
615 if (cycacc)
616 tracer.flags |= TRACER_CYCLE_ACC;
617 else
618 tracer.flags &= ~TRACER_CYCLE_ACC;
619
620 tracer.etm_portsz = portsz & 0x0f;
621 mutex_unlock(&tracer.mutex);
622
623 return n;
624}
625
626static struct kobj_attribute trace_mode_attr =
627 __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
628
Arve Hjønnevåg51495972011-01-28 23:44:43 -0800629static ssize_t trace_range_show(struct kobject *kobj,
630 struct kobj_attribute *attr,
631 char *buf)
632{
633 return sprintf(buf, "%08lx %08lx\n",
634 tracer.range_start, tracer.range_end);
635}
636
637static ssize_t trace_range_store(struct kobject *kobj,
638 struct kobj_attribute *attr,
639 const char *buf, size_t n)
640{
641 unsigned long range_start, range_end;
642
643 if (sscanf(buf, "%lx %lx", &range_start, &range_end) != 2)
644 return -EINVAL;
645
646 mutex_lock(&tracer.mutex);
647 tracer.range_start = range_start;
648 tracer.range_end = range_end;
649 mutex_unlock(&tracer.mutex);
650
651 return n;
652}
653
654
655static struct kobj_attribute trace_range_attr =
656 __ATTR(trace_range, 0644, trace_range_show, trace_range_store);
657
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800658static ssize_t trace_data_range_show(struct kobject *kobj,
659 struct kobj_attribute *attr,
660 char *buf)
661{
662 unsigned long range_start;
663 u64 range_end;
664 mutex_lock(&tracer.mutex);
665 range_start = tracer.data_range_start;
666 range_end = tracer.data_range_end;
667 if (!range_end && (tracer.flags & TRACER_TRACE_DATA))
668 range_end = 0x100000000ULL;
669 mutex_unlock(&tracer.mutex);
670 return sprintf(buf, "%08lx %08llx\n", range_start, range_end);
671}
672
673static ssize_t trace_data_range_store(struct kobject *kobj,
674 struct kobj_attribute *attr,
675 const char *buf, size_t n)
676{
677 unsigned long range_start;
678 u64 range_end;
679
680 if (sscanf(buf, "%lx %llx", &range_start, &range_end) != 2)
681 return -EINVAL;
682
683 mutex_lock(&tracer.mutex);
684 tracer.data_range_start = range_start;
685 tracer.data_range_end = (unsigned long)range_end;
686 if (range_end)
687 tracer.flags |= TRACER_TRACE_DATA;
688 else
689 tracer.flags &= ~TRACER_TRACE_DATA;
690 mutex_unlock(&tracer.mutex);
691
692 return n;
693}
694
695
696static struct kobj_attribute trace_data_range_attr =
697 __ATTR(trace_data_range, 0644,
698 trace_data_range_show, trace_data_range_store);
699
Ming Lei8e880692011-03-28 06:10:25 +0100700static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id)
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100701{
702 struct tracectx *t = &tracer;
703 int ret = 0;
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800704 void __iomem **new_regs;
705 int new_count;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100706
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800707 mutex_lock(&t->mutex);
708 new_count = t->etm_regs_count + 1;
709 new_regs = krealloc(t->etm_regs,
710 sizeof(t->etm_regs[0]) * new_count, GFP_KERNEL);
711
712 if (!new_regs) {
713 dev_dbg(&dev->dev, "Failed to allocate ETM register array\n");
714 ret = -ENOMEM;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100715 goto out;
716 }
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800717 t->etm_regs = new_regs;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100718
719 ret = amba_request_regions(dev, NULL);
720 if (ret)
721 goto out;
722
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800723 t->etm_regs[t->etm_regs_count] =
724 ioremap_nocache(dev->res.start, resource_size(&dev->res));
725 if (!t->etm_regs[t->etm_regs_count]) {
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100726 ret = -ENOMEM;
727 goto out_release;
728 }
729
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800730 amba_set_drvdata(dev, t->etm_regs[t->etm_regs_count]);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100731
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800732 t->flags = TRACER_CYCLE_ACC | TRACER_TRACE_DATA;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100733 t->etm_portsz = 1;
734
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800735 etm_unlock(t, t->etm_regs_count);
736 (void)etm_readl(t, t->etm_regs_count, ETMMR_PDSR);
Alexander Shishkin988257c2010-08-04 11:27:33 +0100737 /* dummy first read */
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800738 (void)etm_readl(&tracer, t->etm_regs_count, ETMMR_OSSRR);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100739
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800740 t->ncmppairs = etm_readl(t, t->etm_regs_count, ETMR_CONFCODE) & 0xf;
741 etm_writel(t, t->etm_regs_count, 0x440, ETMR_CTRL);
742 etm_writel(t, t->etm_regs_count, new_count, ETMR_TRACEIDR);
743 etm_lock(t, t->etm_regs_count);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100744
745 ret = sysfs_create_file(&dev->dev.kobj,
746 &trace_running_attr.attr);
747 if (ret)
748 goto out_unmap;
749
750 /* failing to create any of these two is not fatal */
751 ret = sysfs_create_file(&dev->dev.kobj, &trace_info_attr.attr);
752 if (ret)
753 dev_dbg(&dev->dev, "Failed to create trace_info in sysfs\n");
754
755 ret = sysfs_create_file(&dev->dev.kobj, &trace_mode_attr.attr);
756 if (ret)
757 dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n");
758
Arve Hjønnevåg51495972011-01-28 23:44:43 -0800759 ret = sysfs_create_file(&dev->dev.kobj, &trace_range_attr.attr);
760 if (ret)
761 dev_dbg(&dev->dev, "Failed to create trace_range in sysfs\n");
762
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800763 ret = sysfs_create_file(&dev->dev.kobj, &trace_data_range_attr.attr);
764 if (ret)
765 dev_dbg(&dev->dev,
766 "Failed to create trace_data_range in sysfs\n");
767
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800768 dev_dbg(&dev->dev, "ETM AMBA driver initialized.\n");
769
770 /* Enable formatter if there are multiple trace sources */
771 if (new_count > 1)
772 t->etb_fc = ETBFF_ENFCONT | ETBFF_ENFTC;
773
774 t->etm_regs_count = new_count;
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100775
776out:
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800777 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100778 return ret;
779
780out_unmap:
781 amba_set_drvdata(dev, NULL);
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800782 iounmap(t->etm_regs[t->etm_regs_count]);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100783
784out_release:
785 amba_release_regions(dev);
786
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800787 mutex_unlock(&t->mutex);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100788 return ret;
789}
790
791static int etm_remove(struct amba_device *dev)
792{
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800793 int i;
794 struct tracectx *t = &tracer;
795 void __iomem *etm_regs = amba_get_drvdata(dev);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100796
797 sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr);
798 sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
799 sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr);
Arve Hjønnevåg51495972011-01-28 23:44:43 -0800800 sysfs_remove_file(&dev->dev.kobj, &trace_range_attr.attr);
Arve Hjønnevåg81e43122011-01-31 18:33:55 -0800801 sysfs_remove_file(&dev->dev.kobj, &trace_data_range_attr.attr);
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100802
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800803 amba_set_drvdata(dev, NULL);
804
805 mutex_lock(&t->mutex);
806 for (i = 0; i < t->etm_regs_count; i++)
807 if (t->etm_regs[i] == etm_regs)
808 break;
809 for (; i < t->etm_regs_count - 1; i++)
810 t->etm_regs[i] = t->etm_regs[i + 1];
811 t->etm_regs_count--;
812 if (!t->etm_regs_count) {
813 kfree(t->etm_regs);
814 t->etm_regs = NULL;
815 }
816 mutex_unlock(&t->mutex);
817
818 iounmap(etm_regs);
819 amba_release_regions(dev);
820
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100821 return 0;
822}
823
824static struct amba_id etm_ids[] = {
825 {
826 .id = 0x0003b921,
827 .mask = 0x0007ffff,
828 },
Arve Hjønnevåg628c4942011-02-04 22:38:14 -0800829 {
830 .id = 0x0003b950,
831 .mask = 0x0007ffff,
832 },
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100833 { 0, 0 },
834};
835
836static struct amba_driver etm_driver = {
837 .drv = {
838 .name = "etm",
839 .owner = THIS_MODULE,
840 },
841 .probe = etm_probe,
842 .remove = etm_remove,
843 .id_table = etm_ids,
844};
845
846static int __init etm_init(void)
847{
848 int retval;
849
Arve Hjønnevåga3216012011-02-14 21:09:51 -0800850 mutex_init(&tracer.mutex);
851
Alexander Shishkinc5d6c772009-12-01 14:00:51 +0100852 retval = amba_driver_register(&etb_driver);
853 if (retval) {
854 printk(KERN_ERR "Failed to register etb\n");
855 return retval;
856 }
857
858 retval = amba_driver_register(&etm_driver);
859 if (retval) {
860 amba_driver_unregister(&etb_driver);
861 printk(KERN_ERR "Failed to probe etm\n");
862 return retval;
863 }
864
865 /* not being able to install this handler is not fatal */
866 (void)register_sysrq_key('v', &sysrq_etm_op);
867
868 return 0;
869}
870
871device_initcall(etm_init);
872