• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/arch/arm/kernel/
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)
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	(void)etm_readl(t, ETMMR_PDSR);
547	/* dummy first read */
548	(void)etm_readl(&tracer, ETMMR_OSSRR);
549
550	t->ncmppairs = etm_readl(t, ETMR_CONFCODE) & 0xf;
551	etm_writel(t, 0x440, ETMR_CTRL);
552	etm_lock(t);
553
554	ret = sysfs_create_file(&dev->dev.kobj,
555			&trace_running_attr.attr);
556	if (ret)
557		goto out_unmap;
558
559	/* failing to create any of these two is not fatal */
560	ret = sysfs_create_file(&dev->dev.kobj, &trace_info_attr.attr);
561	if (ret)
562		dev_dbg(&dev->dev, "Failed to create trace_info in sysfs\n");
563
564	ret = sysfs_create_file(&dev->dev.kobj, &trace_mode_attr.attr);
565	if (ret)
566		dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n");
567
568	dev_dbg(t->dev, "ETM AMBA driver initialized.\n");
569
570out:
571	return ret;
572
573out_unmap:
574	amba_set_drvdata(dev, NULL);
575	iounmap(t->etm_regs);
576
577out_release:
578	amba_release_regions(dev);
579
580	return ret;
581}
582
583static int etm_remove(struct amba_device *dev)
584{
585	struct tracectx *t = amba_get_drvdata(dev);
586
587	amba_set_drvdata(dev, NULL);
588
589	iounmap(t->etm_regs);
590	t->etm_regs = NULL;
591
592	amba_release_regions(dev);
593
594	sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr);
595	sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
596	sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr);
597
598	return 0;
599}
600
601static struct amba_id etm_ids[] = {
602	{
603		.id	= 0x0003b921,
604		.mask	= 0x0007ffff,
605	},
606	{ 0, 0 },
607};
608
609static struct amba_driver etm_driver = {
610	.drv		= {
611		.name   = "etm",
612		.owner  = THIS_MODULE,
613	},
614	.probe		= etm_probe,
615	.remove		= etm_remove,
616	.id_table	= etm_ids,
617};
618
619static int __init etm_init(void)
620{
621	int retval;
622
623	retval = amba_driver_register(&etb_driver);
624	if (retval) {
625		printk(KERN_ERR "Failed to register etb\n");
626		return retval;
627	}
628
629	retval = amba_driver_register(&etm_driver);
630	if (retval) {
631		amba_driver_unregister(&etb_driver);
632		printk(KERN_ERR "Failed to probe etm\n");
633		return retval;
634	}
635
636	/* not being able to install this handler is not fatal */
637	(void)register_sysrq_key('v', &sysrq_etm_op);
638
639	return 0;
640}
641
642device_initcall(etm_init);
643