Linux Audio

Check our new training course

Real-Time Linux with PREEMPT_RT training

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