Linux Audio

Check our new training course

In-person Linux kernel drivers training

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