public inbox for linux-omap@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] arm/omap3: a driver for on-chip ETM and ETB
@ 2009-10-07 21:36 virtuoso
  2009-10-09 19:32 ` Tony Lindgren
  2009-10-10 13:48 ` Shilimkar, Santosh
  0 siblings, 2 replies; 4+ messages in thread
From: virtuoso @ 2009-10-07 21:36 UTC (permalink / raw)
  To: linux-omap; +Cc: Alexander Shishkin

From: Alexander Shishkin <virtuoso@slind.org>

This driver implements /dev/tracebuf and some control files for ETM
and ETB in sysfs.

Signed-off-by: Alexander Shishkin <virtuoso@slind.org>
---
 arch/arm/Kconfig.debug                    |    8 +
 arch/arm/include/asm/hardware/coresight.h |  164 ++++++++
 arch/arm/kernel/Makefile                  |    2 +
 arch/arm/kernel/etm.c                     |  584 +++++++++++++++++++++++++++++
 arch/arm/mach-omap2/Kconfig               |    7 +
 arch/arm/mach-omap2/Makefile              |    3 +
 arch/arm/mach-omap2/emu.c                 |   70 ++++
 7 files changed, 838 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/asm/hardware/coresight.h
 create mode 100644 arch/arm/kernel/etm.c
 create mode 100644 arch/arm/mach-omap2/emu.c

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 1a6f70e..ac83c03 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -83,6 +83,14 @@ config DEBUG_ICEDCC
 	  It does include a timeout to ensure that the system does not
 	  totally freeze when there is nothing connected to read.
 
+config OC_ETM
+	tristate "On-chip ETM and ETB"
+	depends on ARCH_OMAP3
+	help
+	  Enables the on-chip embedded trace macrocell and embedded trace
+	  buffer driver that will allow you to collect traces of the
+	  kernel code.
+
 config DEBUG_DC21285_PORT
 	bool "Kernel low-level debugging messages via footbridge serial port"
 	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 0000000..ba22df9
--- /dev/null
+++ b/arch/arm/include/asm/hardware/coresight.h
@@ -0,0 +1,164 @@
+/*
+ * linux/arch/arm/include/asm/hardware/coresight.h
+ *
+ * CoreSight components' registers
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ * Alexander Shishkin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_HARDWARE_CORESIGHT_H
+#define __ASM_HARDWARE_CORESIGHT_H
+
+#define TRACER_ACCESSED_BIT	0
+#define TRACER_RUNNING_BIT	1
+#define TRACER_CYCLE_ACC_BIT	2
+#define TRACER_ACCESSED		BIT(TRACER_ACCESSED_BIT)
+#define TRACER_RUNNING		BIT(TRACER_RUNNING_BIT)
+#define TRACER_CYCLE_ACC	BIT(TRACER_CYCLE_ACC_BIT)
+
+struct tracectx {
+	unsigned int etb_bufsz;
+	void __iomem *etb_regs;
+	void __iomem *etm_regs;
+	unsigned long flags;
+	int ncmppairs;
+	int etm_portsz;
+	struct device *dev;
+	struct mutex mutex;
+};
+
+#define TRACER_TIMEOUT 10000
+
+#define etm_writel(t, v, x) \
+	(__raw_writel((v), (t)->etm_regs + (x)))
+#define etm_readl(t, x) (__raw_readl((t)->etm_regs + (x)))
+
+/* CoreSight Management Registers */
+#define CSMR_LOCKACCESS 0xfb0
+#define CSMR_LOCKSTATUS 0xfb4
+#define CSMR_AUTHSTATUS 0xfb8
+#define CSMR_DEVID	0xfc8
+#define CSMR_DEVTYPE	0xfcc
+/* CoreSight Component Registers */
+#define CSCR_CLASS	0xff4
+
+#define CSCR_PRSR	0x314
+
+#define UNLOCK_MAGIC	0xc5acce55
+
+/* ETM control register, "ETM Architecture", 3.3.1 */
+#define ETMR_CTRL		0
+#define ETMCTRL_POWERDOWN	1
+#define ETMCTRL_PROGRAM		(1 << 10)
+#define ETMCTRL_PORTSEL		(1 << 11)
+#define ETMCTRL_DO_CONTEXTID	(3 << 14)
+#define ETMCTRL_PORTMASK1	(7 << 4)
+#define ETMCTRL_PORTMASK2	(1 << 21)
+#define ETMCTRL_PORTMASK	(ETMCTRL_PORTMASK1 | ETMCTRL_PORTMASK2)
+#define ETMCTRL_PORTSIZE(x) ((((x) & 7) << 4) | (!!((x) & 8)) << 21)
+#define ETMCTRL_DO_CPRT		(1 << 1)
+#define ETMCTRL_DATAMASK	(3 << 2)
+#define ETMCTRL_DATA_DO_DATA	(1 << 2)
+#define ETMCTRL_DATA_DO_ADDR	(1 << 3)
+#define ETMCTRL_DATA_DO_BOTH	(ETMCTRL_DATA_DO_DATA | ETMCTRL_DATA_DO_ADDR)
+#define ETMCTRL_BRANCH_OUTPUT	(1 << 8)
+#define ETMCTRL_CYCLEACCURATE	(1 << 12)
+
+/* ETM configuration code register */
+#define ETMR_CONFCODE		(0x04)
+
+/* ETM trace start/stop resource control register */
+#define ETMR_TRACESSCTRL	(0x18)
+
+/* ETM trigger event register */
+#define ETMR_TRIGEVT		(0x08)
+
+/* address access type register bits, "ETM architecture",
+ * table 3-27 */
+/* - access type */
+#define ETMAAT_IFETCH		0
+#define ETMAAT_IEXEC		1
+#define ETMAAT_IEXECPASS	2
+#define ETMAAT_IEXECFAIL	3
+#define ETMAAT_DLOADSTORE	4
+#define ETMAAT_DLOAD		5
+#define ETMAAT_DSTORE		6
+/* - comparison access size */
+#define ETMAAT_JAVA		(0 << 3)
+#define ETMAAT_THUMB		(1 << 3)
+#define ETMAAT_ARM		(3 << 3)
+/* - data value comparison control */
+#define ETMAAT_NOVALCMP		(0 << 5)
+#define ETMAAT_VALMATCH		(1 << 5)
+#define ETMAAT_VALNOMATCH	(3 << 5)
+/* - exact match */
+#define ETMAAT_EXACTMATCH	(1 << 7)
+/* - context id comparator control */
+#define ETMAAT_IGNCONTEXTID	(0 << 8)
+#define ETMAAT_VALUE1		(1 << 8)
+#define ETMAAT_VALUE2		(2 << 8)
+#define ETMAAT_VALUE3		(3 << 8)
+/* - security level control */
+#define ETMAAT_IGNSECURITY	(0 << 10)
+#define ETMAAT_NSONLY		(1 << 10)
+#define ETMAAT_SONLY		(2 << 10)
+
+#define ETMR_COMP_VAL(x)	(0x40 + (x) * 4)
+#define ETMR_COMP_ACC_TYPE(x)	(0x80 + (x) * 4)
+
+/* ETM status register, "ETM Architecture", 3.3.2 */
+#define ETMR_STATUS		(0x10)
+#define ETMST_OVERFLOW		(1 << 0)
+#define ETMST_PROGBIT		(1 << 1)
+#define ETMST_STARTSTOP		(1 << 2)
+#define ETMST_TRIGGER		(1 << 3)
+
+#define etm_progbit(t)		(etm_readl((t), ETMR_STATUS) & ETMST_PROGBIT)
+#define etm_started(t)		(etm_readl((t), ETMR_STATUS) & ETMST_STARTSTOP)
+#define etm_triggered(t)	(etm_readl((t), ETMR_STATUS) & ETMST_TRIGGER)
+
+#define ETMR_TRACEENCTRL2	0x1c
+#define ETMR_TRACEENCTRL	0x24
+#define ETMTE_INCLEXCL		(1 << 24)
+#define ETMR_TRACEENEVT		0x20
+#define ETMCTRL_OPTS		(ETMCTRL_DO_CPRT | \
+				ETMCTRL_DATA_DO_ADDR | \
+				ETMCTRL_BRANCH_OUTPUT | \
+				ETMCTRL_DO_CONTEXTID)
+
+/* ETB registers, "CoreSight Components TRM", 9.3 */
+#define ETBR_DEPTH		0x04
+#define ETBR_STATUS		0x0c
+#define ETBR_READMEM		0x10
+#define ETBR_READADDR		0x14
+#define ETBR_WRITEADDR		0x18
+#define ETBR_TRIGGERCOUNT	0x1c
+#define ETBR_CTRL		0x20
+#define ETBR_FORMATTERCTRL	0x304
+#define ETBFF_ENFTC		1
+#define ETBFF_ENFCONT		(1 << 1)
+#define ETBFF_FONFLIN		(1 << 4)
+#define ETBFF_MANUAL_FLUSH	(1 << 6)
+#define ETBFF_TRIGIN		(1 << 8)
+#define ETBFF_TRIGEVT		(1 << 9)
+#define ETBFF_TRIGFL		(1 << 10)
+
+#define etb_writel(t, v, x) \
+	(__raw_writel((v), (t)->etb_regs + (x)))
+#define etb_readl(t, x) (__raw_readl((t)->etb_regs + (x)))
+
+#define etm_lock(t) do { etm_writel((t), 0, CSMR_LOCKACCESS); } while (0)
+#define etm_unlock(t) \
+	do { etm_writel((t), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0)
+
+#define etb_lock(t) do { etb_writel((t), 0, CSMR_LOCKACCESS); } while (0)
+#define etb_unlock(t) \
+	do { etb_writel((t), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0)
+
+#endif /* __ASM_HARDWARE_CORESIGHT_H */
+
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 79087dd..e7ccf7e 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 \
 		   process.o ptrace.o return_address.o setup.o signal.o \
 		   sys_arm.o stacktrace.o time.o traps.o
 
+obj-$(CONFIG_OC_ETM)		+= etm.o
+
 obj-$(CONFIG_ISA_DMA_API)	+= dma.o
 obj-$(CONFIG_ARCH_ACORN)	+= ecard.o 
 obj-$(CONFIG_FIQ)		+= fiq.o
diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
new file mode 100644
index 0000000..fe233b0
--- /dev/null
+++ b/arch/arm/kernel/etm.c
@@ -0,0 +1,584 @@
+/*
+ * linux/arch/arm/kernel/etm.c
+ *
+ * Driver for ARM's Embedded Trace Macrocell and Embedded Trace Buffer.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ * Alexander Shishkin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/mutex.h>
+#include <asm/hardware/coresight.h>
+#include <asm/sections.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexander Shishkin");
+
+static struct tracectx tracer;
+
+static inline bool trace_isrunning(struct tracectx *t)
+{
+	return !!(t->flags & TRACER_RUNNING);
+}
+
+static int etm_setup_address_range(struct tracectx *t, int n,
+		unsigned long start, unsigned long end, int exclude, int data)
+{
+	u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_NSONLY | \
+		    ETMAAT_NOVALCMP;
+
+	if (n < 1 || n > t->ncmppairs)
+		return -EINVAL;
+
+	/* comparators and ranges are numbered starting with 1 as opposed
+	 * to bits in a word */
+	n--;
+
+	if (data)
+		flags |= ETMAAT_DLOADSTORE;
+	else
+		flags |= ETMAAT_IEXEC;
+
+	/* first comparator for the range */
+	etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2));
+	etm_writel(t, start, ETMR_COMP_VAL(n * 2));
+
+	/* second comparator is right next to it */
+	etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
+	etm_writel(t, end, ETMR_COMP_VAL(n * 2 + 1));
+
+	flags = exclude ? ETMTE_INCLEXCL : 0;
+	etm_writel(t, flags | (1 << n), ETMR_TRACEENCTRL);
+
+	return 0;
+}
+
+static int trace_start(struct tracectx *t)
+{
+	u32 v;
+	unsigned long timeout = TRACER_TIMEOUT;
+
+	etb_unlock(t);
+
+	etb_writel(t, 0, ETBR_FORMATTERCTRL);
+	etb_writel(t, 1, ETBR_CTRL);
+
+	etb_lock(t);
+
+	/* configure etm */
+	v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz);
+
+	if (t->flags & TRACER_CYCLE_ACC)
+		v |= ETMCTRL_CYCLEACCURATE;
+
+	etm_unlock(t);
+
+	etm_writel(t, v, ETMR_CTRL);
+
+	while (--timeout && !(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM))
+		;
+	if (!timeout) {
+		dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
+		return -EFAULT;
+	}
+
+	etm_setup_address_range(t, 1, (unsigned long)_stext,
+			(unsigned long)_etext, 0, 0);
+	etm_writel(t, 0, ETMR_TRACEENCTRL2);
+	etm_writel(t, 0, ETMR_TRACESSCTRL);
+	etm_writel(t, 0x6f, ETMR_TRACEENEVT);
+
+	v &= ~ETMCTRL_PROGRAM;
+	v |= ETMCTRL_PORTSEL;
+
+	etm_writel(t, v, ETMR_CTRL);
+
+	timeout = TRACER_TIMEOUT;
+	while (--timeout && etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM)
+		;
+	if (!timeout) {
+		dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n");
+		return -EFAULT;
+	}
+
+	etm_lock(t);
+
+	t->flags |= TRACER_RUNNING;
+
+	return 0;
+}
+
+static int trace_stop(struct tracectx *t)
+{
+	unsigned long timeout = TRACER_TIMEOUT;
+
+	etm_unlock(t);
+
+	etm_writel(t, 0x440, ETMR_CTRL);
+	while (--timeout && !(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM))
+		;
+	if (!timeout) {
+		dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
+		return -EFAULT;
+	}
+
+	etm_lock(t);
+
+	etb_unlock(t);
+	etb_writel(t, ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
+
+	timeout = TRACER_TIMEOUT;
+	while (--timeout && etb_readl(t, ETBR_FORMATTERCTRL) &
+			ETBFF_MANUAL_FLUSH)
+		;
+	if (!timeout) {
+		dev_dbg(t->dev, "Waiting for formatter flush to commence "
+				"timed out\n");
+		return -EFAULT;
+	}
+
+	etb_writel(t, 0, ETBR_CTRL);
+
+	etb_lock(t);
+
+	t->flags &= ~TRACER_RUNNING;
+
+	return 0;
+}
+
+static int etb_getdatalen(struct tracectx *t)
+{
+	u32 v;
+	int rp, wp;
+
+	v = etb_readl(t, ETBR_STATUS);
+
+	if (v & 1)
+		return t->etb_bufsz;
+
+	rp = etb_readl(t, ETBR_READADDR);
+	wp = etb_readl(t, ETBR_WRITEADDR);
+
+	if (rp > wp) {
+		etb_writel(t, 0, ETBR_READADDR);
+		etb_writel(t, 0, ETBR_WRITEADDR);
+
+		return 0;
+	}
+
+	return wp - rp;
+}
+
+/* sysrq+v will always stop the running trace and leave it at that */
+static void etm_dump(void)
+{
+	struct tracectx *t = &tracer;
+	u32 first = 0;
+	int length;
+
+	if (!t->etb_regs) {
+		printk(KERN_INFO "No tracing hardware found\n");
+		return;
+	}
+
+	if (!mutex_trylock(&t->mutex))
+		return;
+
+	if (trace_isrunning(t))
+		trace_stop(t);
+
+	etb_unlock(t);
+
+	length = etb_getdatalen(t);
+
+	if (length == t->etb_bufsz)
+		first = etb_readl(t, ETBR_WRITEADDR);
+
+	etb_writel(t, first, ETBR_READADDR);
+
+	printk(KERN_INFO "Trace buffer contents length: %d\n", length);
+	printk(KERN_INFO "--- ETB buffer begin ---\n");
+	for (; length; length--)
+		printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
+	printk(KERN_INFO "\n--- ETB buffer end ---\n");
+
+	etb_writel(t, 0, ETBR_TRIGGERCOUNT);
+	etb_writel(t, 0, ETBR_READADDR);
+	etb_writel(t, 0, ETBR_WRITEADDR);
+
+	etb_lock(t);
+
+	mutex_unlock(&t->mutex);
+}
+
+static void sysrq_etm_dump(int key, struct tty_struct *tty)
+{
+	dev_dbg(tracer.dev, "Dumping ETB buffer\n");
+	etm_dump();
+}
+
+static struct sysrq_key_op sysrq_etm_op = {
+	.handler = sysrq_etm_dump,
+	.help_msg = "ETM buffer dump",
+	.action_msg = "etm",
+};
+
+static int etb_open(struct inode *inode, struct file *file)
+{
+	if (!tracer.etb_regs)
+		return -ENODEV;
+
+	file->private_data = &tracer;
+
+	return nonseekable_open(inode, file);
+}
+
+static ssize_t etb_read(struct file *file, char __user *data,
+		size_t len, loff_t *ppos)
+{
+	int total, i;
+	long length;
+	struct tracectx *t = file->private_data;
+	u32 first = 0;
+	u32 *buf;
+
+	mutex_lock(&t->mutex);
+
+	if (trace_isrunning(t)) {
+		length = 0;
+		goto out;
+	}
+
+	etb_unlock(t);
+
+	total = etb_getdatalen(t);
+	if (total == t->etb_bufsz)
+		first = etb_readl(t, ETBR_WRITEADDR);
+
+	etb_writel(t, first, ETBR_READADDR);
+
+	length = min(total * 4, (int)len);
+	buf = vmalloc(length);
+
+	dev_dbg(t->dev, "ETB buffer length: %d\n", total);
+	dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
+	for (i = 0; i < length / 4; i++)
+		buf[i] = etb_readl(t, ETBR_READMEM);
+
+	/* the only way to deassert overflow bit in ETB status is this */
+	etb_writel(t, 1, ETBR_CTRL);
+	etb_writel(t, 0, ETBR_CTRL);
+
+	etb_writel(t, 0, ETBR_WRITEADDR);
+	etb_writel(t, 0, ETBR_READADDR);
+	etb_writel(t, 0, ETBR_TRIGGERCOUNT);
+
+	etb_lock(t);
+
+	length = copy_to_user(data, buf, length);
+	vfree(buf);
+
+out:
+	mutex_unlock(&t->mutex);
+
+	return length;
+}
+
+static int etb_release(struct inode *inode, struct file *file)
+{
+	/* there's nothing to do here, actually */
+	return 0;
+}
+
+static struct file_operations etb_fops = {
+	.owner = THIS_MODULE,
+	.read = etb_read,
+	.open = etb_open,
+	.release = etb_release,
+};
+
+static struct miscdevice etb_miscdev = {
+	.name = "tracebuf",
+	.minor = 0,
+	.fops = &etb_fops,
+};
+
+static int __devinit etb_drv_probe(struct platform_device *pdev)
+{
+	struct tracectx *t = platform_get_drvdata(pdev);
+	struct resource *res;
+	struct clk *clk;
+	int ret = 0;
+
+	if (t && t->etb_regs) {
+		dev_dbg(&pdev->dev, "ETB already initialized\n");
+		ret = -EBUSY;
+		goto out;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	if (!request_mem_region(res->start, SZ_4K, "etb")) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	if (!t) {
+		t = &tracer;
+		platform_set_drvdata(pdev, t);
+	}
+
+	t->etb_regs = ioremap_nocache(res->start, SZ_4K);
+	if (!t->etb_regs) {
+		ret = -ENOMEM;
+		platform_set_drvdata(pdev, NULL);
+		release_mem_region(res->start, SZ_4K);
+		goto out;
+	}
+
+	etb_miscdev.parent = &pdev->dev;
+
+	ret = misc_register(&etb_miscdev);
+	if (ret) {
+		platform_set_drvdata(pdev, NULL);
+		iounmap(t->etb_regs);
+		release_mem_region(res->start, SZ_4K);
+		goto out;
+	}
+
+	clk = clk_get(&pdev->dev, "emu_core_alwon_ck");
+	clk_enable(clk);
+
+	clk = clk_get(&pdev->dev, "emu_per_alwon_ck");
+	clk_enable(clk);
+
+	clk = clk_get(&pdev->dev, "emu_mpu_alwon_ck");
+	clk_enable(clk);
+
+	clk = clk_get(&pdev->dev, "emu_src_ck");
+	clk_enable(clk);
+
+	etb_unlock(t);
+	t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
+	dev_dbg(&pdev->dev, "Size: %x\n", t->etb_bufsz);
+
+	/* make sure trace capture is disabled */
+	etb_writel(t, 0, ETBR_CTRL);
+	etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
+	etb_lock(t);
+
+	dev_dbg(&pdev->dev, "ETB platform driver initialized.\n");
+
+	ret = 0;
+out:
+	return ret;
+}
+
+static struct platform_driver etb_driver = {
+	.probe		 = etb_drv_probe,
+	.driver	 = {
+		.name	 = "etb",
+		.owner	= THIS_MODULE,
+	},
+};
+
+/* use a sysfs file "trace_running" to start/stop tracing */
+static ssize_t trace_running_show(struct kobject *kobj,
+				  struct kobj_attribute *attr,
+				  char *buf)
+{
+	return sprintf(buf, "%x\n", trace_isrunning(&tracer));
+}
+
+static ssize_t trace_running_store(struct kobject *kobj,
+				   struct kobj_attribute *attr,
+				   const char *buf, size_t n)
+{
+	unsigned int value;
+	int ret;
+
+	if (sscanf(buf, "%u", &value) != 1)
+		return -EINVAL;
+
+	mutex_lock(&tracer.mutex);
+	ret = value ? trace_start(&tracer) : trace_stop(&tracer);
+	mutex_unlock(&tracer.mutex);
+
+	return ret ? : n;
+}
+
+static struct kobj_attribute trace_running_attr =
+	__ATTR(trace_running, 0644, trace_running_show, trace_running_store);
+
+static ssize_t trace_info_show(struct kobject *kobj,
+				  struct kobj_attribute *attr,
+				  char *buf)
+{
+	u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
+	int datalen;
+
+	etb_unlock(&tracer);
+	datalen = etb_getdatalen(&tracer);
+	etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
+	etb_ra = etb_readl(&tracer, ETBR_READADDR);
+	etb_st = etb_readl(&tracer, ETBR_STATUS);
+	etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
+	etb_lock(&tracer);
+
+	etm_unlock(&tracer);
+	etm_ctrl = etm_readl(&tracer, ETMR_CTRL);
+	etm_st = etm_readl(&tracer, ETMR_STATUS);
+	etm_lock(&tracer);
+
+	return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
+			"ETBR_WRITEADDR:\t%08x\n"
+			"ETBR_READADDR:\t%08x\n"
+			"ETBR_STATUS:\t%08x\n"
+			"ETBR_FORMATTERCTRL:\t%08x\n"
+			"ETMR_CTRL:\t%08x\n"
+			"ETMR_STATUS:\t%08x\n",
+			datalen,
+			tracer.ncmppairs,
+			etb_wa,
+			etb_ra,
+			etb_st,
+			etb_fc,
+			etm_ctrl,
+			etm_st
+			);
+}
+
+static struct kobj_attribute trace_info_attr =
+	__ATTR(trace_info, 0444, trace_info_show, NULL);
+
+static ssize_t trace_mode_show(struct kobject *kobj,
+				  struct kobj_attribute *attr,
+				  char *buf)
+{
+	return sprintf(buf, "%d %d\n",
+			!!(tracer.flags & TRACER_CYCLE_ACC),
+			tracer.etm_portsz);
+}
+
+static ssize_t trace_mode_store(struct kobject *kobj,
+				   struct kobj_attribute *attr,
+				   const char *buf, size_t n)
+{
+	unsigned int cycacc, portsz;
+
+	if (sscanf(buf, "%u %u", &cycacc, &portsz) != 2)
+		return -EINVAL;
+
+	mutex_lock(&tracer.mutex);
+	if (cycacc)
+		tracer.flags |= TRACER_CYCLE_ACC;
+	else
+		tracer.flags &= ~TRACER_CYCLE_ACC;
+
+	tracer.etm_portsz = portsz & 0x0f;
+	mutex_unlock(&tracer.mutex);
+
+	return n;
+}
+
+static struct kobj_attribute trace_mode_attr =
+	__ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
+
+static int __devinit etm_drv_probe(struct platform_device *pdev)
+{
+	struct tracectx *t = platform_get_drvdata(pdev);
+	struct resource *res;
+	int ret = 0;
+
+	if (t && t->etm_regs) {
+		dev_dbg(&pdev->dev, "ETM already initialized\n");
+		ret = -EBUSY;
+		goto out;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	if (!request_mem_region(res->start, SZ_4K, "etm")) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	if (!t) {
+		t = &tracer;
+		platform_set_drvdata(pdev, t);
+	}
+
+	t->etm_regs = ioremap_nocache(res->start, SZ_4K);
+	if (!t->etm_regs) {
+		ret = -ENOMEM;
+		release_mem_region(res->start, SZ_4K);
+		platform_set_drvdata(pdev, NULL);
+		goto out;
+	}
+
+	mutex_init(&t->mutex);
+	t->dev = &pdev->dev;
+	t->flags = TRACER_CYCLE_ACC;
+	t->etm_portsz = 1;
+
+	etm_unlock(t);
+	ret = etm_readl(t, CSCR_PRSR);
+
+	t->ncmppairs = etm_readl(t, ETMR_CONFCODE) & 0xf;
+	etm_writel(t, 0x440, ETMR_CTRL);
+	etm_lock(t);
+
+	ret = sysfs_create_file(&pdev->dev.kobj,
+			&trace_running_attr.attr);
+	ret = sysfs_create_file(&pdev->dev.kobj,
+			&trace_info_attr.attr);
+	ret = sysfs_create_file(&pdev->dev.kobj,
+			&trace_mode_attr.attr);
+	dev_dbg(t->dev, "ETM platform driver initialized.\n");
+
+out:
+	return ret;
+}
+
+static struct platform_driver etm_driver = {
+	.probe           = etm_drv_probe,
+	.driver  = {
+		.name    = "etm",
+		.owner   = THIS_MODULE,
+	},
+};
+
+static int __init etm_init(void)
+{
+	platform_driver_register(&etb_driver);
+	platform_driver_register(&etm_driver);
+	register_sysrq_key('v', &sysrq_etm_op);
+
+	return 0;
+}
+
+module_init(etm_init);
+
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 75b1c7e..87bcc2a 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -88,3 +88,10 @@ config MACH_OMAP_ZOOM2
 config MACH_OMAP_4430SDP
 	bool "OMAP 4430 SDP board"
 	depends on ARCH_OMAP4
+
+config OMAP3_EMU
+	tristate "OMAP3 debugging peripherals"
+	depends on ARCH_OMAP3 && OC_ETM
+	help
+	  Say Y here to enable debugging hardware of omap3
+
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 6b7702f..572dd27 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -44,6 +44,9 @@ obj-$(CONFIG_ARCH_OMAP4)		+= cm4xxx.o
 obj-$(CONFIG_ARCH_OMAP2)		+= clock24xx.o
 obj-$(CONFIG_ARCH_OMAP3)		+= clock34xx.o
 
+# EMU periferals
+obj-$(CONFIG_OMAP3_EMU)		+= emu.o
+
 iommu-y					+= iommu2.o
 iommu-$(CONFIG_ARCH_OMAP3)		+= omap3-iommu.o
 
diff --git a/arch/arm/mach-omap2/emu.c b/arch/arm/mach-omap2/emu.c
new file mode 100644
index 0000000..f98874e
--- /dev/null
+++ b/arch/arm/mach-omap2/emu.c
@@ -0,0 +1,70 @@
+/*
+ * linux/arch/arm/mach-omap2/emu.c
+ *
+ * ETM and ETB CoreSight components' resources as found in OMAP3xxx.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ * Alexander Shishkin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexander Shishkin");
+
+/* Cortex CoreSight components within omap3xxx EMU */
+#define ETM_BASE	(L4_EMU_34XX_PHYS + 0x10000)
+#define DBG_BASE	(L4_EMU_34XX_PHYS + 0x11000)
+#define ETB_BASE	(L4_EMU_34XX_PHYS + 0x1b000)
+#define DAPCTL		(L4_EMU_34XX_PHYS + 0x1d000)
+
+static struct resource rx51_etb_resource = {
+	.start = ETB_BASE,
+	.end   = ETB_BASE + SZ_4K,
+	.flags = IORESOURCE_MEM,
+};
+
+static struct platform_device rx51_etb_device = {
+	.name = "etb",
+	.id   = -1,
+	.num_resources = 1,
+	.resource = &rx51_etb_resource,
+};
+
+static struct resource rx51_etm_resource = {
+	.start = ETM_BASE,
+	.end   = ETM_BASE + SZ_4K,
+	.flags = IORESOURCE_MEM,
+};
+
+static struct platform_device rx51_etm_device = {
+	.name = "etm",
+	.id   = -1,
+	.num_resources = 1,
+	.resource = &rx51_etm_resource,
+};
+
+static struct platform_device *rx51_trace_devices[] = {
+	&rx51_etm_device,
+	&rx51_etb_device,
+};
+
+static int __init emu_init(void)
+{
+	platform_add_devices(rx51_trace_devices,
+			ARRAY_SIZE(rx51_trace_devices));
+
+	return 0;
+}
+
+module_init(emu_init);
+
-- 
1.6.3.3


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/2] arm/omap3: a driver for on-chip ETM and ETB
  2009-10-07 21:36 [PATCH 1/2] arm/omap3: a driver for on-chip ETM and ETB virtuoso
@ 2009-10-09 19:32 ` Tony Lindgren
  2009-10-10 13:48 ` Shilimkar, Santosh
  1 sibling, 0 replies; 4+ messages in thread
From: Tony Lindgren @ 2009-10-09 19:32 UTC (permalink / raw)
  To: virtuoso; +Cc: linux-omap

* virtuoso@slind.org <virtuoso@slind.org> [091007 15:38]:
> From: Alexander Shishkin <virtuoso@slind.org>
> 
> This driver implements /dev/tracebuf and some control files for ETM
> and ETB in sysfs.

Cool. This should go in via the linux-arm-kernel list, can you please
resend? Please also Cc linux-omap list too.

Regards,

Tony
 
> Signed-off-by: Alexander Shishkin <virtuoso@slind.org>
> ---
>  arch/arm/Kconfig.debug                    |    8 +
>  arch/arm/include/asm/hardware/coresight.h |  164 ++++++++
>  arch/arm/kernel/Makefile                  |    2 +
>  arch/arm/kernel/etm.c                     |  584 +++++++++++++++++++++++++++++
>  arch/arm/mach-omap2/Kconfig               |    7 +
>  arch/arm/mach-omap2/Makefile              |    3 +
>  arch/arm/mach-omap2/emu.c                 |   70 ++++
>  7 files changed, 838 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/include/asm/hardware/coresight.h
>  create mode 100644 arch/arm/kernel/etm.c
>  create mode 100644 arch/arm/mach-omap2/emu.c
> 
> diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
> index 1a6f70e..ac83c03 100644
> --- a/arch/arm/Kconfig.debug
> +++ b/arch/arm/Kconfig.debug
> @@ -83,6 +83,14 @@ config DEBUG_ICEDCC
>  	  It does include a timeout to ensure that the system does not
>  	  totally freeze when there is nothing connected to read.
>  
> +config OC_ETM
> +	tristate "On-chip ETM and ETB"
> +	depends on ARCH_OMAP3
> +	help
> +	  Enables the on-chip embedded trace macrocell and embedded trace
> +	  buffer driver that will allow you to collect traces of the
> +	  kernel code.
> +
>  config DEBUG_DC21285_PORT
>  	bool "Kernel low-level debugging messages via footbridge serial port"
>  	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 0000000..ba22df9
> --- /dev/null
> +++ b/arch/arm/include/asm/hardware/coresight.h
> @@ -0,0 +1,164 @@
> +/*
> + * linux/arch/arm/include/asm/hardware/coresight.h
> + *
> + * CoreSight components' registers
> + *
> + * Copyright (C) 2009 Nokia Corporation.
> + * Alexander Shishkin
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef __ASM_HARDWARE_CORESIGHT_H
> +#define __ASM_HARDWARE_CORESIGHT_H
> +
> +#define TRACER_ACCESSED_BIT	0
> +#define TRACER_RUNNING_BIT	1
> +#define TRACER_CYCLE_ACC_BIT	2
> +#define TRACER_ACCESSED		BIT(TRACER_ACCESSED_BIT)
> +#define TRACER_RUNNING		BIT(TRACER_RUNNING_BIT)
> +#define TRACER_CYCLE_ACC	BIT(TRACER_CYCLE_ACC_BIT)
> +
> +struct tracectx {
> +	unsigned int etb_bufsz;
> +	void __iomem *etb_regs;
> +	void __iomem *etm_regs;
> +	unsigned long flags;
> +	int ncmppairs;
> +	int etm_portsz;
> +	struct device *dev;
> +	struct mutex mutex;
> +};
> +
> +#define TRACER_TIMEOUT 10000
> +
> +#define etm_writel(t, v, x) \
> +	(__raw_writel((v), (t)->etm_regs + (x)))
> +#define etm_readl(t, x) (__raw_readl((t)->etm_regs + (x)))
> +
> +/* CoreSight Management Registers */
> +#define CSMR_LOCKACCESS 0xfb0
> +#define CSMR_LOCKSTATUS 0xfb4
> +#define CSMR_AUTHSTATUS 0xfb8
> +#define CSMR_DEVID	0xfc8
> +#define CSMR_DEVTYPE	0xfcc
> +/* CoreSight Component Registers */
> +#define CSCR_CLASS	0xff4
> +
> +#define CSCR_PRSR	0x314
> +
> +#define UNLOCK_MAGIC	0xc5acce55
> +
> +/* ETM control register, "ETM Architecture", 3.3.1 */
> +#define ETMR_CTRL		0
> +#define ETMCTRL_POWERDOWN	1
> +#define ETMCTRL_PROGRAM		(1 << 10)
> +#define ETMCTRL_PORTSEL		(1 << 11)
> +#define ETMCTRL_DO_CONTEXTID	(3 << 14)
> +#define ETMCTRL_PORTMASK1	(7 << 4)
> +#define ETMCTRL_PORTMASK2	(1 << 21)
> +#define ETMCTRL_PORTMASK	(ETMCTRL_PORTMASK1 | ETMCTRL_PORTMASK2)
> +#define ETMCTRL_PORTSIZE(x) ((((x) & 7) << 4) | (!!((x) & 8)) << 21)
> +#define ETMCTRL_DO_CPRT		(1 << 1)
> +#define ETMCTRL_DATAMASK	(3 << 2)
> +#define ETMCTRL_DATA_DO_DATA	(1 << 2)
> +#define ETMCTRL_DATA_DO_ADDR	(1 << 3)
> +#define ETMCTRL_DATA_DO_BOTH	(ETMCTRL_DATA_DO_DATA | ETMCTRL_DATA_DO_ADDR)
> +#define ETMCTRL_BRANCH_OUTPUT	(1 << 8)
> +#define ETMCTRL_CYCLEACCURATE	(1 << 12)
> +
> +/* ETM configuration code register */
> +#define ETMR_CONFCODE		(0x04)
> +
> +/* ETM trace start/stop resource control register */
> +#define ETMR_TRACESSCTRL	(0x18)
> +
> +/* ETM trigger event register */
> +#define ETMR_TRIGEVT		(0x08)
> +
> +/* address access type register bits, "ETM architecture",
> + * table 3-27 */
> +/* - access type */
> +#define ETMAAT_IFETCH		0
> +#define ETMAAT_IEXEC		1
> +#define ETMAAT_IEXECPASS	2
> +#define ETMAAT_IEXECFAIL	3
> +#define ETMAAT_DLOADSTORE	4
> +#define ETMAAT_DLOAD		5
> +#define ETMAAT_DSTORE		6
> +/* - comparison access size */
> +#define ETMAAT_JAVA		(0 << 3)
> +#define ETMAAT_THUMB		(1 << 3)
> +#define ETMAAT_ARM		(3 << 3)
> +/* - data value comparison control */
> +#define ETMAAT_NOVALCMP		(0 << 5)
> +#define ETMAAT_VALMATCH		(1 << 5)
> +#define ETMAAT_VALNOMATCH	(3 << 5)
> +/* - exact match */
> +#define ETMAAT_EXACTMATCH	(1 << 7)
> +/* - context id comparator control */
> +#define ETMAAT_IGNCONTEXTID	(0 << 8)
> +#define ETMAAT_VALUE1		(1 << 8)
> +#define ETMAAT_VALUE2		(2 << 8)
> +#define ETMAAT_VALUE3		(3 << 8)
> +/* - security level control */
> +#define ETMAAT_IGNSECURITY	(0 << 10)
> +#define ETMAAT_NSONLY		(1 << 10)
> +#define ETMAAT_SONLY		(2 << 10)
> +
> +#define ETMR_COMP_VAL(x)	(0x40 + (x) * 4)
> +#define ETMR_COMP_ACC_TYPE(x)	(0x80 + (x) * 4)
> +
> +/* ETM status register, "ETM Architecture", 3.3.2 */
> +#define ETMR_STATUS		(0x10)
> +#define ETMST_OVERFLOW		(1 << 0)
> +#define ETMST_PROGBIT		(1 << 1)
> +#define ETMST_STARTSTOP		(1 << 2)
> +#define ETMST_TRIGGER		(1 << 3)
> +
> +#define etm_progbit(t)		(etm_readl((t), ETMR_STATUS) & ETMST_PROGBIT)
> +#define etm_started(t)		(etm_readl((t), ETMR_STATUS) & ETMST_STARTSTOP)
> +#define etm_triggered(t)	(etm_readl((t), ETMR_STATUS) & ETMST_TRIGGER)
> +
> +#define ETMR_TRACEENCTRL2	0x1c
> +#define ETMR_TRACEENCTRL	0x24
> +#define ETMTE_INCLEXCL		(1 << 24)
> +#define ETMR_TRACEENEVT		0x20
> +#define ETMCTRL_OPTS		(ETMCTRL_DO_CPRT | \
> +				ETMCTRL_DATA_DO_ADDR | \
> +				ETMCTRL_BRANCH_OUTPUT | \
> +				ETMCTRL_DO_CONTEXTID)
> +
> +/* ETB registers, "CoreSight Components TRM", 9.3 */
> +#define ETBR_DEPTH		0x04
> +#define ETBR_STATUS		0x0c
> +#define ETBR_READMEM		0x10
> +#define ETBR_READADDR		0x14
> +#define ETBR_WRITEADDR		0x18
> +#define ETBR_TRIGGERCOUNT	0x1c
> +#define ETBR_CTRL		0x20
> +#define ETBR_FORMATTERCTRL	0x304
> +#define ETBFF_ENFTC		1
> +#define ETBFF_ENFCONT		(1 << 1)
> +#define ETBFF_FONFLIN		(1 << 4)
> +#define ETBFF_MANUAL_FLUSH	(1 << 6)
> +#define ETBFF_TRIGIN		(1 << 8)
> +#define ETBFF_TRIGEVT		(1 << 9)
> +#define ETBFF_TRIGFL		(1 << 10)
> +
> +#define etb_writel(t, v, x) \
> +	(__raw_writel((v), (t)->etb_regs + (x)))
> +#define etb_readl(t, x) (__raw_readl((t)->etb_regs + (x)))
> +
> +#define etm_lock(t) do { etm_writel((t), 0, CSMR_LOCKACCESS); } while (0)
> +#define etm_unlock(t) \
> +	do { etm_writel((t), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0)
> +
> +#define etb_lock(t) do { etb_writel((t), 0, CSMR_LOCKACCESS); } while (0)
> +#define etb_unlock(t) \
> +	do { etb_writel((t), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0)
> +
> +#endif /* __ASM_HARDWARE_CORESIGHT_H */
> +
> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
> index 79087dd..e7ccf7e 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 \
>  		   process.o ptrace.o return_address.o setup.o signal.o \
>  		   sys_arm.o stacktrace.o time.o traps.o
>  
> +obj-$(CONFIG_OC_ETM)		+= etm.o
> +
>  obj-$(CONFIG_ISA_DMA_API)	+= dma.o
>  obj-$(CONFIG_ARCH_ACORN)	+= ecard.o 
>  obj-$(CONFIG_FIQ)		+= fiq.o
> diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
> new file mode 100644
> index 0000000..fe233b0
> --- /dev/null
> +++ b/arch/arm/kernel/etm.c
> @@ -0,0 +1,584 @@
> +/*
> + * linux/arch/arm/kernel/etm.c
> + *
> + * Driver for ARM's Embedded Trace Macrocell and Embedded Trace Buffer.
> + *
> + * Copyright (C) 2009 Nokia Corporation.
> + * Alexander Shishkin
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/types.h>
> +#include <linux/io.h>
> +#include <linux/clk.h>
> +#include <linux/sysrq.h>
> +#include <linux/platform_device.h>
> +#include <linux/fs.h>
> +#include <linux/uaccess.h>
> +#include <linux/miscdevice.h>
> +#include <linux/vmalloc.h>
> +#include <linux/mutex.h>
> +#include <asm/hardware/coresight.h>
> +#include <asm/sections.h>
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Alexander Shishkin");
> +
> +static struct tracectx tracer;
> +
> +static inline bool trace_isrunning(struct tracectx *t)
> +{
> +	return !!(t->flags & TRACER_RUNNING);
> +}
> +
> +static int etm_setup_address_range(struct tracectx *t, int n,
> +		unsigned long start, unsigned long end, int exclude, int data)
> +{
> +	u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_NSONLY | \
> +		    ETMAAT_NOVALCMP;
> +
> +	if (n < 1 || n > t->ncmppairs)
> +		return -EINVAL;
> +
> +	/* comparators and ranges are numbered starting with 1 as opposed
> +	 * to bits in a word */
> +	n--;
> +
> +	if (data)
> +		flags |= ETMAAT_DLOADSTORE;
> +	else
> +		flags |= ETMAAT_IEXEC;
> +
> +	/* first comparator for the range */
> +	etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2));
> +	etm_writel(t, start, ETMR_COMP_VAL(n * 2));
> +
> +	/* second comparator is right next to it */
> +	etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
> +	etm_writel(t, end, ETMR_COMP_VAL(n * 2 + 1));
> +
> +	flags = exclude ? ETMTE_INCLEXCL : 0;
> +	etm_writel(t, flags | (1 << n), ETMR_TRACEENCTRL);
> +
> +	return 0;
> +}
> +
> +static int trace_start(struct tracectx *t)
> +{
> +	u32 v;
> +	unsigned long timeout = TRACER_TIMEOUT;
> +
> +	etb_unlock(t);
> +
> +	etb_writel(t, 0, ETBR_FORMATTERCTRL);
> +	etb_writel(t, 1, ETBR_CTRL);
> +
> +	etb_lock(t);
> +
> +	/* configure etm */
> +	v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz);
> +
> +	if (t->flags & TRACER_CYCLE_ACC)
> +		v |= ETMCTRL_CYCLEACCURATE;
> +
> +	etm_unlock(t);
> +
> +	etm_writel(t, v, ETMR_CTRL);
> +
> +	while (--timeout && !(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM))
> +		;
> +	if (!timeout) {
> +		dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
> +		return -EFAULT;
> +	}
> +
> +	etm_setup_address_range(t, 1, (unsigned long)_stext,
> +			(unsigned long)_etext, 0, 0);
> +	etm_writel(t, 0, ETMR_TRACEENCTRL2);
> +	etm_writel(t, 0, ETMR_TRACESSCTRL);
> +	etm_writel(t, 0x6f, ETMR_TRACEENEVT);
> +
> +	v &= ~ETMCTRL_PROGRAM;
> +	v |= ETMCTRL_PORTSEL;
> +
> +	etm_writel(t, v, ETMR_CTRL);
> +
> +	timeout = TRACER_TIMEOUT;
> +	while (--timeout && etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM)
> +		;
> +	if (!timeout) {
> +		dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n");
> +		return -EFAULT;
> +	}
> +
> +	etm_lock(t);
> +
> +	t->flags |= TRACER_RUNNING;
> +
> +	return 0;
> +}
> +
> +static int trace_stop(struct tracectx *t)
> +{
> +	unsigned long timeout = TRACER_TIMEOUT;
> +
> +	etm_unlock(t);
> +
> +	etm_writel(t, 0x440, ETMR_CTRL);
> +	while (--timeout && !(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM))
> +		;
> +	if (!timeout) {
> +		dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
> +		return -EFAULT;
> +	}
> +
> +	etm_lock(t);
> +
> +	etb_unlock(t);
> +	etb_writel(t, ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
> +
> +	timeout = TRACER_TIMEOUT;
> +	while (--timeout && etb_readl(t, ETBR_FORMATTERCTRL) &
> +			ETBFF_MANUAL_FLUSH)
> +		;
> +	if (!timeout) {
> +		dev_dbg(t->dev, "Waiting for formatter flush to commence "
> +				"timed out\n");
> +		return -EFAULT;
> +	}
> +
> +	etb_writel(t, 0, ETBR_CTRL);
> +
> +	etb_lock(t);
> +
> +	t->flags &= ~TRACER_RUNNING;
> +
> +	return 0;
> +}
> +
> +static int etb_getdatalen(struct tracectx *t)
> +{
> +	u32 v;
> +	int rp, wp;
> +
> +	v = etb_readl(t, ETBR_STATUS);
> +
> +	if (v & 1)
> +		return t->etb_bufsz;
> +
> +	rp = etb_readl(t, ETBR_READADDR);
> +	wp = etb_readl(t, ETBR_WRITEADDR);
> +
> +	if (rp > wp) {
> +		etb_writel(t, 0, ETBR_READADDR);
> +		etb_writel(t, 0, ETBR_WRITEADDR);
> +
> +		return 0;
> +	}
> +
> +	return wp - rp;
> +}
> +
> +/* sysrq+v will always stop the running trace and leave it at that */
> +static void etm_dump(void)
> +{
> +	struct tracectx *t = &tracer;
> +	u32 first = 0;
> +	int length;
> +
> +	if (!t->etb_regs) {
> +		printk(KERN_INFO "No tracing hardware found\n");
> +		return;
> +	}
> +
> +	if (!mutex_trylock(&t->mutex))
> +		return;
> +
> +	if (trace_isrunning(t))
> +		trace_stop(t);
> +
> +	etb_unlock(t);
> +
> +	length = etb_getdatalen(t);
> +
> +	if (length == t->etb_bufsz)
> +		first = etb_readl(t, ETBR_WRITEADDR);
> +
> +	etb_writel(t, first, ETBR_READADDR);
> +
> +	printk(KERN_INFO "Trace buffer contents length: %d\n", length);
> +	printk(KERN_INFO "--- ETB buffer begin ---\n");
> +	for (; length; length--)
> +		printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
> +	printk(KERN_INFO "\n--- ETB buffer end ---\n");
> +
> +	etb_writel(t, 0, ETBR_TRIGGERCOUNT);
> +	etb_writel(t, 0, ETBR_READADDR);
> +	etb_writel(t, 0, ETBR_WRITEADDR);
> +
> +	etb_lock(t);
> +
> +	mutex_unlock(&t->mutex);
> +}
> +
> +static void sysrq_etm_dump(int key, struct tty_struct *tty)
> +{
> +	dev_dbg(tracer.dev, "Dumping ETB buffer\n");
> +	etm_dump();
> +}
> +
> +static struct sysrq_key_op sysrq_etm_op = {
> +	.handler = sysrq_etm_dump,
> +	.help_msg = "ETM buffer dump",
> +	.action_msg = "etm",
> +};
> +
> +static int etb_open(struct inode *inode, struct file *file)
> +{
> +	if (!tracer.etb_regs)
> +		return -ENODEV;
> +
> +	file->private_data = &tracer;
> +
> +	return nonseekable_open(inode, file);
> +}
> +
> +static ssize_t etb_read(struct file *file, char __user *data,
> +		size_t len, loff_t *ppos)
> +{
> +	int total, i;
> +	long length;
> +	struct tracectx *t = file->private_data;
> +	u32 first = 0;
> +	u32 *buf;
> +
> +	mutex_lock(&t->mutex);
> +
> +	if (trace_isrunning(t)) {
> +		length = 0;
> +		goto out;
> +	}
> +
> +	etb_unlock(t);
> +
> +	total = etb_getdatalen(t);
> +	if (total == t->etb_bufsz)
> +		first = etb_readl(t, ETBR_WRITEADDR);
> +
> +	etb_writel(t, first, ETBR_READADDR);
> +
> +	length = min(total * 4, (int)len);
> +	buf = vmalloc(length);
> +
> +	dev_dbg(t->dev, "ETB buffer length: %d\n", total);
> +	dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
> +	for (i = 0; i < length / 4; i++)
> +		buf[i] = etb_readl(t, ETBR_READMEM);
> +
> +	/* the only way to deassert overflow bit in ETB status is this */
> +	etb_writel(t, 1, ETBR_CTRL);
> +	etb_writel(t, 0, ETBR_CTRL);
> +
> +	etb_writel(t, 0, ETBR_WRITEADDR);
> +	etb_writel(t, 0, ETBR_READADDR);
> +	etb_writel(t, 0, ETBR_TRIGGERCOUNT);
> +
> +	etb_lock(t);
> +
> +	length = copy_to_user(data, buf, length);
> +	vfree(buf);
> +
> +out:
> +	mutex_unlock(&t->mutex);
> +
> +	return length;
> +}
> +
> +static int etb_release(struct inode *inode, struct file *file)
> +{
> +	/* there's nothing to do here, actually */
> +	return 0;
> +}
> +
> +static struct file_operations etb_fops = {
> +	.owner = THIS_MODULE,
> +	.read = etb_read,
> +	.open = etb_open,
> +	.release = etb_release,
> +};
> +
> +static struct miscdevice etb_miscdev = {
> +	.name = "tracebuf",
> +	.minor = 0,
> +	.fops = &etb_fops,
> +};
> +
> +static int __devinit etb_drv_probe(struct platform_device *pdev)
> +{
> +	struct tracectx *t = platform_get_drvdata(pdev);
> +	struct resource *res;
> +	struct clk *clk;
> +	int ret = 0;
> +
> +	if (t && t->etb_regs) {
> +		dev_dbg(&pdev->dev, "ETB already initialized\n");
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +
> +	if (!request_mem_region(res->start, SZ_4K, "etb")) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	if (!t) {
> +		t = &tracer;
> +		platform_set_drvdata(pdev, t);
> +	}
> +
> +	t->etb_regs = ioremap_nocache(res->start, SZ_4K);
> +	if (!t->etb_regs) {
> +		ret = -ENOMEM;
> +		platform_set_drvdata(pdev, NULL);
> +		release_mem_region(res->start, SZ_4K);
> +		goto out;
> +	}
> +
> +	etb_miscdev.parent = &pdev->dev;
> +
> +	ret = misc_register(&etb_miscdev);
> +	if (ret) {
> +		platform_set_drvdata(pdev, NULL);
> +		iounmap(t->etb_regs);
> +		release_mem_region(res->start, SZ_4K);
> +		goto out;
> +	}
> +
> +	clk = clk_get(&pdev->dev, "emu_core_alwon_ck");
> +	clk_enable(clk);
> +
> +	clk = clk_get(&pdev->dev, "emu_per_alwon_ck");
> +	clk_enable(clk);
> +
> +	clk = clk_get(&pdev->dev, "emu_mpu_alwon_ck");
> +	clk_enable(clk);
> +
> +	clk = clk_get(&pdev->dev, "emu_src_ck");
> +	clk_enable(clk);
> +
> +	etb_unlock(t);
> +	t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
> +	dev_dbg(&pdev->dev, "Size: %x\n", t->etb_bufsz);
> +
> +	/* make sure trace capture is disabled */
> +	etb_writel(t, 0, ETBR_CTRL);
> +	etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
> +	etb_lock(t);
> +
> +	dev_dbg(&pdev->dev, "ETB platform driver initialized.\n");
> +
> +	ret = 0;
> +out:
> +	return ret;
> +}
> +
> +static struct platform_driver etb_driver = {
> +	.probe		 = etb_drv_probe,
> +	.driver	 = {
> +		.name	 = "etb",
> +		.owner	= THIS_MODULE,
> +	},
> +};
> +
> +/* use a sysfs file "trace_running" to start/stop tracing */
> +static ssize_t trace_running_show(struct kobject *kobj,
> +				  struct kobj_attribute *attr,
> +				  char *buf)
> +{
> +	return sprintf(buf, "%x\n", trace_isrunning(&tracer));
> +}
> +
> +static ssize_t trace_running_store(struct kobject *kobj,
> +				   struct kobj_attribute *attr,
> +				   const char *buf, size_t n)
> +{
> +	unsigned int value;
> +	int ret;
> +
> +	if (sscanf(buf, "%u", &value) != 1)
> +		return -EINVAL;
> +
> +	mutex_lock(&tracer.mutex);
> +	ret = value ? trace_start(&tracer) : trace_stop(&tracer);
> +	mutex_unlock(&tracer.mutex);
> +
> +	return ret ? : n;
> +}
> +
> +static struct kobj_attribute trace_running_attr =
> +	__ATTR(trace_running, 0644, trace_running_show, trace_running_store);
> +
> +static ssize_t trace_info_show(struct kobject *kobj,
> +				  struct kobj_attribute *attr,
> +				  char *buf)
> +{
> +	u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
> +	int datalen;
> +
> +	etb_unlock(&tracer);
> +	datalen = etb_getdatalen(&tracer);
> +	etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
> +	etb_ra = etb_readl(&tracer, ETBR_READADDR);
> +	etb_st = etb_readl(&tracer, ETBR_STATUS);
> +	etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
> +	etb_lock(&tracer);
> +
> +	etm_unlock(&tracer);
> +	etm_ctrl = etm_readl(&tracer, ETMR_CTRL);
> +	etm_st = etm_readl(&tracer, ETMR_STATUS);
> +	etm_lock(&tracer);
> +
> +	return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
> +			"ETBR_WRITEADDR:\t%08x\n"
> +			"ETBR_READADDR:\t%08x\n"
> +			"ETBR_STATUS:\t%08x\n"
> +			"ETBR_FORMATTERCTRL:\t%08x\n"
> +			"ETMR_CTRL:\t%08x\n"
> +			"ETMR_STATUS:\t%08x\n",
> +			datalen,
> +			tracer.ncmppairs,
> +			etb_wa,
> +			etb_ra,
> +			etb_st,
> +			etb_fc,
> +			etm_ctrl,
> +			etm_st
> +			);
> +}
> +
> +static struct kobj_attribute trace_info_attr =
> +	__ATTR(trace_info, 0444, trace_info_show, NULL);
> +
> +static ssize_t trace_mode_show(struct kobject *kobj,
> +				  struct kobj_attribute *attr,
> +				  char *buf)
> +{
> +	return sprintf(buf, "%d %d\n",
> +			!!(tracer.flags & TRACER_CYCLE_ACC),
> +			tracer.etm_portsz);
> +}
> +
> +static ssize_t trace_mode_store(struct kobject *kobj,
> +				   struct kobj_attribute *attr,
> +				   const char *buf, size_t n)
> +{
> +	unsigned int cycacc, portsz;
> +
> +	if (sscanf(buf, "%u %u", &cycacc, &portsz) != 2)
> +		return -EINVAL;
> +
> +	mutex_lock(&tracer.mutex);
> +	if (cycacc)
> +		tracer.flags |= TRACER_CYCLE_ACC;
> +	else
> +		tracer.flags &= ~TRACER_CYCLE_ACC;
> +
> +	tracer.etm_portsz = portsz & 0x0f;
> +	mutex_unlock(&tracer.mutex);
> +
> +	return n;
> +}
> +
> +static struct kobj_attribute trace_mode_attr =
> +	__ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
> +
> +static int __devinit etm_drv_probe(struct platform_device *pdev)
> +{
> +	struct tracectx *t = platform_get_drvdata(pdev);
> +	struct resource *res;
> +	int ret = 0;
> +
> +	if (t && t->etm_regs) {
> +		dev_dbg(&pdev->dev, "ETM already initialized\n");
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +
> +	if (!request_mem_region(res->start, SZ_4K, "etm")) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	if (!t) {
> +		t = &tracer;
> +		platform_set_drvdata(pdev, t);
> +	}
> +
> +	t->etm_regs = ioremap_nocache(res->start, SZ_4K);
> +	if (!t->etm_regs) {
> +		ret = -ENOMEM;
> +		release_mem_region(res->start, SZ_4K);
> +		platform_set_drvdata(pdev, NULL);
> +		goto out;
> +	}
> +
> +	mutex_init(&t->mutex);
> +	t->dev = &pdev->dev;
> +	t->flags = TRACER_CYCLE_ACC;
> +	t->etm_portsz = 1;
> +
> +	etm_unlock(t);
> +	ret = etm_readl(t, CSCR_PRSR);
> +
> +	t->ncmppairs = etm_readl(t, ETMR_CONFCODE) & 0xf;
> +	etm_writel(t, 0x440, ETMR_CTRL);
> +	etm_lock(t);
> +
> +	ret = sysfs_create_file(&pdev->dev.kobj,
> +			&trace_running_attr.attr);
> +	ret = sysfs_create_file(&pdev->dev.kobj,
> +			&trace_info_attr.attr);
> +	ret = sysfs_create_file(&pdev->dev.kobj,
> +			&trace_mode_attr.attr);
> +	dev_dbg(t->dev, "ETM platform driver initialized.\n");
> +
> +out:
> +	return ret;
> +}
> +
> +static struct platform_driver etm_driver = {
> +	.probe           = etm_drv_probe,
> +	.driver  = {
> +		.name    = "etm",
> +		.owner   = THIS_MODULE,
> +	},
> +};
> +
> +static int __init etm_init(void)
> +{
> +	platform_driver_register(&etb_driver);
> +	platform_driver_register(&etm_driver);
> +	register_sysrq_key('v', &sysrq_etm_op);
> +
> +	return 0;
> +}
> +
> +module_init(etm_init);
> +
> diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
> index 75b1c7e..87bcc2a 100644
> --- a/arch/arm/mach-omap2/Kconfig
> +++ b/arch/arm/mach-omap2/Kconfig
> @@ -88,3 +88,10 @@ config MACH_OMAP_ZOOM2
>  config MACH_OMAP_4430SDP
>  	bool "OMAP 4430 SDP board"
>  	depends on ARCH_OMAP4
> +
> +config OMAP3_EMU
> +	tristate "OMAP3 debugging peripherals"
> +	depends on ARCH_OMAP3 && OC_ETM
> +	help
> +	  Say Y here to enable debugging hardware of omap3
> +
> diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
> index 6b7702f..572dd27 100644
> --- a/arch/arm/mach-omap2/Makefile
> +++ b/arch/arm/mach-omap2/Makefile
> @@ -44,6 +44,9 @@ obj-$(CONFIG_ARCH_OMAP4)		+= cm4xxx.o
>  obj-$(CONFIG_ARCH_OMAP2)		+= clock24xx.o
>  obj-$(CONFIG_ARCH_OMAP3)		+= clock34xx.o
>  
> +# EMU periferals
> +obj-$(CONFIG_OMAP3_EMU)		+= emu.o
> +
>  iommu-y					+= iommu2.o
>  iommu-$(CONFIG_ARCH_OMAP3)		+= omap3-iommu.o
>  
> diff --git a/arch/arm/mach-omap2/emu.c b/arch/arm/mach-omap2/emu.c
> new file mode 100644
> index 0000000..f98874e
> --- /dev/null
> +++ b/arch/arm/mach-omap2/emu.c
> @@ -0,0 +1,70 @@
> +/*
> + * linux/arch/arm/mach-omap2/emu.c
> + *
> + * ETM and ETB CoreSight components' resources as found in OMAP3xxx.
> + *
> + * Copyright (C) 2009 Nokia Corporation.
> + * Alexander Shishkin
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/types.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Alexander Shishkin");
> +
> +/* Cortex CoreSight components within omap3xxx EMU */
> +#define ETM_BASE	(L4_EMU_34XX_PHYS + 0x10000)
> +#define DBG_BASE	(L4_EMU_34XX_PHYS + 0x11000)
> +#define ETB_BASE	(L4_EMU_34XX_PHYS + 0x1b000)
> +#define DAPCTL		(L4_EMU_34XX_PHYS + 0x1d000)
> +
> +static struct resource rx51_etb_resource = {
> +	.start = ETB_BASE,
> +	.end   = ETB_BASE + SZ_4K,
> +	.flags = IORESOURCE_MEM,
> +};
> +
> +static struct platform_device rx51_etb_device = {
> +	.name = "etb",
> +	.id   = -1,
> +	.num_resources = 1,
> +	.resource = &rx51_etb_resource,
> +};
> +
> +static struct resource rx51_etm_resource = {
> +	.start = ETM_BASE,
> +	.end   = ETM_BASE + SZ_4K,
> +	.flags = IORESOURCE_MEM,
> +};
> +
> +static struct platform_device rx51_etm_device = {
> +	.name = "etm",
> +	.id   = -1,
> +	.num_resources = 1,
> +	.resource = &rx51_etm_resource,
> +};
> +
> +static struct platform_device *rx51_trace_devices[] = {
> +	&rx51_etm_device,
> +	&rx51_etb_device,
> +};
> +
> +static int __init emu_init(void)
> +{
> +	platform_add_devices(rx51_trace_devices,
> +			ARRAY_SIZE(rx51_trace_devices));
> +
> +	return 0;
> +}
> +
> +module_init(emu_init);
> +
> -- 
> 1.6.3.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 4+ messages in thread

* RE: [PATCH 1/2] arm/omap3: a driver for on-chip ETM and ETB
  2009-10-07 21:36 [PATCH 1/2] arm/omap3: a driver for on-chip ETM and ETB virtuoso
  2009-10-09 19:32 ` Tony Lindgren
@ 2009-10-10 13:48 ` Shilimkar, Santosh
  2009-10-11 17:08   ` Alexander Shishkin
  1 sibling, 1 reply; 4+ messages in thread
From: Shilimkar, Santosh @ 2009-10-10 13:48 UTC (permalink / raw)
  To: virtuoso@slind.org, linux-omap@vger.kernel.org

> -----Original Message-----
> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> owner@vger.kernel.org] On Behalf Of virtuoso@slind.org
> Sent: Thursday, October 08, 2009 3:06 AM
> To: linux-omap@vger.kernel.org
> Cc: Alexander Shishkin
> Subject: [PATCH 1/2] arm/omap3: a driver for on-chip ETM and ETB
>
> From: Alexander Shishkin <virtuoso@slind.org>
>
> This driver implements /dev/tracebuf and some control files for ETM
> and ETB in sysfs.
Looks like a very useful driver for tracing/debug.
Do you have some README link on the usage of this driver ?

> Signed-off-by: Alexander Shishkin <virtuoso@slind.org>
> ---
>  arch/arm/Kconfig.debug                    |    8 +
>  arch/arm/include/asm/hardware/coresight.h |  164 ++++++++
>  arch/arm/kernel/Makefile                  |    2 +
>  arch/arm/kernel/etm.c                     |  584
> +++++++++++++++++++++++++++++
>  arch/arm/mach-omap2/Kconfig               |    7 +
>  arch/arm/mach-omap2/Makefile              |    3 +
>  arch/arm/mach-omap2/emu.c                 |   70 ++++
>  7 files changed, 838 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/include/asm/hardware/coresight.h
>  create mode 100644 arch/arm/kernel/etm.c
>  create mode 100644 arch/arm/mach-omap2/emu.c
>
> diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
> index 1a6f70e..ac83c03 100644
> --- a/arch/arm/Kconfig.debug
> +++ b/arch/arm/Kconfig.debug
> @@ -83,6 +83,14 @@ config DEBUG_ICEDCC
>         It does include a timeout to ensure that the system does not
>         totally freeze when there is nothing connected to read.
>
> +config OC_ETM
> +     tristate "On-chip ETM and ETB"
> +     depends on ARCH_OMAP3
> +     help
> +       Enables the on-chip embedded trace macrocell and embedded trace
> +       buffer driver that will allow you to collect traces of the
> +       kernel code.
> +
>  config DEBUG_DC21285_PORT
>       bool "Kernel low-level debugging messages via footbridge serial
> port"
>       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 0000000..ba22df9
> --- /dev/null
> +++ b/arch/arm/include/asm/hardware/coresight.h
> @@ -0,0 +1,164 @@
> +/*
> + * linux/arch/arm/include/asm/hardware/coresight.h
> + *
> + * CoreSight components' registers
> + *
> + * Copyright (C) 2009 Nokia Corporation.
> + * Alexander Shishkin
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef __ASM_HARDWARE_CORESIGHT_H
> +#define __ASM_HARDWARE_CORESIGHT_H
> +
> +#define TRACER_ACCESSED_BIT  0
> +#define TRACER_RUNNING_BIT   1
> +#define TRACER_CYCLE_ACC_BIT 2
> +#define TRACER_ACCESSED              BIT(TRACER_ACCESSED_BIT)
> +#define TRACER_RUNNING               BIT(TRACER_RUNNING_BIT)
> +#define TRACER_CYCLE_ACC     BIT(TRACER_CYCLE_ACC_BIT)
> +
> +struct tracectx {
> +     unsigned int etb_bufsz;
> +     void __iomem *etb_regs;
> +     void __iomem *etm_regs;
> +     unsigned long flags;
> +     int ncmppairs;
> +     int etm_portsz;
> +     struct device *dev;
> +     struct mutex mutex;
> +};
> +
> +#define TRACER_TIMEOUT 10000
> +
> +#define etm_writel(t, v, x) \
> +     (__raw_writel((v), (t)->etm_regs + (x)))
> +#define etm_readl(t, x) (__raw_readl((t)->etm_regs + (x)))
> +
> +/* CoreSight Management Registers */
> +#define CSMR_LOCKACCESS 0xfb0
> +#define CSMR_LOCKSTATUS 0xfb4
> +#define CSMR_AUTHSTATUS 0xfb8
> +#define CSMR_DEVID   0xfc8
> +#define CSMR_DEVTYPE 0xfcc
> +/* CoreSight Component Registers */
> +#define CSCR_CLASS   0xff4
> +
> +#define CSCR_PRSR    0x314
> +
> +#define UNLOCK_MAGIC 0xc5acce55
> +
> +/* ETM control register, "ETM Architecture", 3.3.1 */
> +#define ETMR_CTRL            0
> +#define ETMCTRL_POWERDOWN    1
> +#define ETMCTRL_PROGRAM              (1 << 10)
> +#define ETMCTRL_PORTSEL              (1 << 11)
> +#define ETMCTRL_DO_CONTEXTID (3 << 14)
> +#define ETMCTRL_PORTMASK1    (7 << 4)
> +#define ETMCTRL_PORTMASK2    (1 << 21)
> +#define ETMCTRL_PORTMASK     (ETMCTRL_PORTMASK1 | ETMCTRL_PORTMASK2)
> +#define ETMCTRL_PORTSIZE(x) ((((x) & 7) << 4) | (!!((x) & 8)) << 21)
> +#define ETMCTRL_DO_CPRT              (1 << 1)
> +#define ETMCTRL_DATAMASK     (3 << 2)
> +#define ETMCTRL_DATA_DO_DATA (1 << 2)
> +#define ETMCTRL_DATA_DO_ADDR (1 << 3)
> +#define ETMCTRL_DATA_DO_BOTH (ETMCTRL_DATA_DO_DATA |
> ETMCTRL_DATA_DO_ADDR)
> +#define ETMCTRL_BRANCH_OUTPUT        (1 << 8)
> +#define ETMCTRL_CYCLEACCURATE        (1 << 12)
> +
> +/* ETM configuration code register */
> +#define ETMR_CONFCODE                (0x04)
> +
> +/* ETM trace start/stop resource control register */
> +#define ETMR_TRACESSCTRL     (0x18)
> +
> +/* ETM trigger event register */
> +#define ETMR_TRIGEVT         (0x08)
> +
> +/* address access type register bits, "ETM architecture",
> + * table 3-27 */
> +/* - access type */
> +#define ETMAAT_IFETCH                0
> +#define ETMAAT_IEXEC         1
> +#define ETMAAT_IEXECPASS     2
> +#define ETMAAT_IEXECFAIL     3
> +#define ETMAAT_DLOADSTORE    4
> +#define ETMAAT_DLOAD         5
> +#define ETMAAT_DSTORE                6
> +/* - comparison access size */
> +#define ETMAAT_JAVA          (0 << 3)
> +#define ETMAAT_THUMB         (1 << 3)
> +#define ETMAAT_ARM           (3 << 3)
> +/* - data value comparison control */
> +#define ETMAAT_NOVALCMP              (0 << 5)
> +#define ETMAAT_VALMATCH              (1 << 5)
> +#define ETMAAT_VALNOMATCH    (3 << 5)
> +/* - exact match */
> +#define ETMAAT_EXACTMATCH    (1 << 7)
> +/* - context id comparator control */
> +#define ETMAAT_IGNCONTEXTID  (0 << 8)
> +#define ETMAAT_VALUE1                (1 << 8)
> +#define ETMAAT_VALUE2                (2 << 8)
> +#define ETMAAT_VALUE3                (3 << 8)
> +/* - security level control */
> +#define ETMAAT_IGNSECURITY   (0 << 10)
> +#define ETMAAT_NSONLY                (1 << 10)
> +#define ETMAAT_SONLY         (2 << 10)
> +
> +#define ETMR_COMP_VAL(x)     (0x40 + (x) * 4)
> +#define ETMR_COMP_ACC_TYPE(x)        (0x80 + (x) * 4)
> +
> +/* ETM status register, "ETM Architecture", 3.3.2 */
> +#define ETMR_STATUS          (0x10)
> +#define ETMST_OVERFLOW               (1 << 0)
> +#define ETMST_PROGBIT                (1 << 1)
> +#define ETMST_STARTSTOP              (1 << 2)
> +#define ETMST_TRIGGER                (1 << 3)
> +
> +#define etm_progbit(t)               (etm_readl((t), ETMR_STATUS) &
> ETMST_PROGBIT)
> +#define etm_started(t)               (etm_readl((t), ETMR_STATUS) &
> ETMST_STARTSTOP)
> +#define etm_triggered(t)     (etm_readl((t), ETMR_STATUS) &
> ETMST_TRIGGER)
> +
> +#define ETMR_TRACEENCTRL2    0x1c
> +#define ETMR_TRACEENCTRL     0x24
> +#define ETMTE_INCLEXCL               (1 << 24)
> +#define ETMR_TRACEENEVT              0x20
> +#define ETMCTRL_OPTS         (ETMCTRL_DO_CPRT | \
> +                             ETMCTRL_DATA_DO_ADDR | \
> +                             ETMCTRL_BRANCH_OUTPUT | \
> +                             ETMCTRL_DO_CONTEXTID)
> +
> +/* ETB registers, "CoreSight Components TRM", 9.3 */
> +#define ETBR_DEPTH           0x04
> +#define ETBR_STATUS          0x0c
> +#define ETBR_READMEM         0x10
> +#define ETBR_READADDR                0x14
> +#define ETBR_WRITEADDR               0x18
> +#define ETBR_TRIGGERCOUNT    0x1c
> +#define ETBR_CTRL            0x20
> +#define ETBR_FORMATTERCTRL   0x304
> +#define ETBFF_ENFTC          1
> +#define ETBFF_ENFCONT                (1 << 1)
> +#define ETBFF_FONFLIN                (1 << 4)
> +#define ETBFF_MANUAL_FLUSH   (1 << 6)
> +#define ETBFF_TRIGIN         (1 << 8)
> +#define ETBFF_TRIGEVT                (1 << 9)
> +#define ETBFF_TRIGFL         (1 << 10)
> +
> +#define etb_writel(t, v, x) \
> +     (__raw_writel((v), (t)->etb_regs + (x)))
> +#define etb_readl(t, x) (__raw_readl((t)->etb_regs + (x)))
> +
> +#define etm_lock(t) do { etm_writel((t), 0, CSMR_LOCKACCESS); } while (0)
> +#define etm_unlock(t) \
> +     do { etm_writel((t), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0)
> +
> +#define etb_lock(t) do { etb_writel((t), 0, CSMR_LOCKACCESS); } while (0)
> +#define etb_unlock(t) \
> +     do { etb_writel((t), UNLOCK_MAGIC, CSMR_LOCKACCESS); } while (0)
> +
> +#endif /* __ASM_HARDWARE_CORESIGHT_H */
> +
> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
> index 79087dd..e7ccf7e 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 \
>                  process.o ptrace.o return_address.o setup.o signal.o \
>                  sys_arm.o stacktrace.o time.o traps.o
>
> +obj-$(CONFIG_OC_ETM)         += etm.o
> +
>  obj-$(CONFIG_ISA_DMA_API)    += dma.o
>  obj-$(CONFIG_ARCH_ACORN)     += ecard.o
>  obj-$(CONFIG_FIQ)            += fiq.o
> diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
> new file mode 100644
> index 0000000..fe233b0
> --- /dev/null
> +++ b/arch/arm/kernel/etm.c
> @@ -0,0 +1,584 @@
> +/*
> + * linux/arch/arm/kernel/etm.c
> + *
> + * Driver for ARM's Embedded Trace Macrocell and Embedded Trace Buffer.
> + *
> + * Copyright (C) 2009 Nokia Corporation.
> + * Alexander Shishkin
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/types.h>
> +#include <linux/io.h>
> +#include <linux/clk.h>
> +#include <linux/sysrq.h>
> +#include <linux/platform_device.h>
> +#include <linux/fs.h>
> +#include <linux/uaccess.h>
> +#include <linux/miscdevice.h>
> +#include <linux/vmalloc.h>
> +#include <linux/mutex.h>
> +#include <asm/hardware/coresight.h>
> +#include <asm/sections.h>
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Alexander Shishkin");
> +
> +static struct tracectx tracer;
> +
> +static inline bool trace_isrunning(struct tracectx *t)
> +{
> +     return !!(t->flags & TRACER_RUNNING);
> +}
> +
> +static int etm_setup_address_range(struct tracectx *t, int n,
> +             unsigned long start, unsigned long end, int exclude, int data)
> +{
> +     u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_NSONLY | \
> +                 ETMAAT_NOVALCMP;
> +
> +     if (n < 1 || n > t->ncmppairs)
> +             return -EINVAL;
> +
> +     /* comparators and ranges are numbered starting with 1 as opposed
> +      * to bits in a word */
> +     n--;
> +
> +     if (data)
> +             flags |= ETMAAT_DLOADSTORE;
> +     else
> +             flags |= ETMAAT_IEXEC;
> +
> +     /* first comparator for the range */
> +     etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2));
> +     etm_writel(t, start, ETMR_COMP_VAL(n * 2));
> +
> +     /* second comparator is right next to it */
> +     etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
> +     etm_writel(t, end, ETMR_COMP_VAL(n * 2 + 1));
> +
> +     flags = exclude ? ETMTE_INCLEXCL : 0;
> +     etm_writel(t, flags | (1 << n), ETMR_TRACEENCTRL);
> +
> +     return 0;
> +}
> +
> +static int trace_start(struct tracectx *t)
> +{
> +     u32 v;
> +     unsigned long timeout = TRACER_TIMEOUT;
> +
> +     etb_unlock(t);
> +
> +     etb_writel(t, 0, ETBR_FORMATTERCTRL);
> +     etb_writel(t, 1, ETBR_CTRL);
> +
> +     etb_lock(t);
> +
> +     /* configure etm */
> +     v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t-
> >etm_portsz);
> +
> +     if (t->flags & TRACER_CYCLE_ACC)
> +             v |= ETMCTRL_CYCLEACCURATE;
> +
> +     etm_unlock(t);
> +
> +     etm_writel(t, v, ETMR_CTRL);
> +
> +     while (--timeout && !(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM))
> +             ;
> +     if (!timeout) {
> +             dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
> +             return -EFAULT;
> +     }
> +
> +     etm_setup_address_range(t, 1, (unsigned long)_stext,
> +                     (unsigned long)_etext, 0, 0);
> +     etm_writel(t, 0, ETMR_TRACEENCTRL2);
> +     etm_writel(t, 0, ETMR_TRACESSCTRL);
> +     etm_writel(t, 0x6f, ETMR_TRACEENEVT);
> +
> +     v &= ~ETMCTRL_PROGRAM;
> +     v |= ETMCTRL_PORTSEL;
> +
> +     etm_writel(t, v, ETMR_CTRL);
> +
> +     timeout = TRACER_TIMEOUT;
> +     while (--timeout && etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM)
> +             ;
> +     if (!timeout) {
> +             dev_dbg(t->dev, "Waiting for progbit to deassert timed
> out\n");
> +             return -EFAULT;
> +     }
> +
> +     etm_lock(t);
> +
> +     t->flags |= TRACER_RUNNING;
> +
> +     return 0;
> +}
> +
> +static int trace_stop(struct tracectx *t)
> +{
> +     unsigned long timeout = TRACER_TIMEOUT;
> +
> +     etm_unlock(t);
> +
> +     etm_writel(t, 0x440, ETMR_CTRL);
> +     while (--timeout && !(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM))
> +             ;
> +     if (!timeout) {
> +             dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
> +             return -EFAULT;
> +     }
> +
> +     etm_lock(t);
> +
> +     etb_unlock(t);
> +     etb_writel(t, ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
> +
> +     timeout = TRACER_TIMEOUT;
> +     while (--timeout && etb_readl(t, ETBR_FORMATTERCTRL) &
> +                     ETBFF_MANUAL_FLUSH)
> +             ;
> +     if (!timeout) {
> +             dev_dbg(t->dev, "Waiting for formatter flush to commence "
> +                             "timed out\n");
> +             return -EFAULT;
> +     }
> +
> +     etb_writel(t, 0, ETBR_CTRL);
> +
> +     etb_lock(t);
> +
> +     t->flags &= ~TRACER_RUNNING;
> +
> +     return 0;
> +}
> +
> +static int etb_getdatalen(struct tracectx *t)
> +{
> +     u32 v;
> +     int rp, wp;
> +
> +     v = etb_readl(t, ETBR_STATUS);
> +
> +     if (v & 1)
> +             return t->etb_bufsz;
> +
> +     rp = etb_readl(t, ETBR_READADDR);
> +     wp = etb_readl(t, ETBR_WRITEADDR);
> +
> +     if (rp > wp) {
> +             etb_writel(t, 0, ETBR_READADDR);
> +             etb_writel(t, 0, ETBR_WRITEADDR);
> +
> +             return 0;
> +     }
> +
> +     return wp - rp;
> +}
> +
> +/* sysrq+v will always stop the running trace and leave it at that */
> +static void etm_dump(void)
> +{
> +     struct tracectx *t = &tracer;
> +     u32 first = 0;
> +     int length;
> +
> +     if (!t->etb_regs) {
> +             printk(KERN_INFO "No tracing hardware found\n");
> +             return;
> +     }
> +
> +     if (!mutex_trylock(&t->mutex))
> +             return;
> +
> +     if (trace_isrunning(t))
> +             trace_stop(t);
> +
> +     etb_unlock(t);
> +
> +     length = etb_getdatalen(t);
> +
> +     if (length == t->etb_bufsz)
> +             first = etb_readl(t, ETBR_WRITEADDR);
> +
> +     etb_writel(t, first, ETBR_READADDR);
> +
> +     printk(KERN_INFO "Trace buffer contents length: %d\n", length);
> +     printk(KERN_INFO "--- ETB buffer begin ---\n");
> +     for (; length; length--)
> +             printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
> +     printk(KERN_INFO "\n--- ETB buffer end ---\n");
> +
> +     etb_writel(t, 0, ETBR_TRIGGERCOUNT);
> +     etb_writel(t, 0, ETBR_READADDR);
> +     etb_writel(t, 0, ETBR_WRITEADDR);
> +
> +     etb_lock(t);
> +
> +     mutex_unlock(&t->mutex);
> +}
> +
> +static void sysrq_etm_dump(int key, struct tty_struct *tty)
> +{
> +     dev_dbg(tracer.dev, "Dumping ETB buffer\n");
> +     etm_dump();
> +}
> +
> +static struct sysrq_key_op sysrq_etm_op = {
> +     .handler = sysrq_etm_dump,
> +     .help_msg = "ETM buffer dump",
> +     .action_msg = "etm",
> +};
> +
> +static int etb_open(struct inode *inode, struct file *file)
> +{
> +     if (!tracer.etb_regs)
> +             return -ENODEV;
> +
> +     file->private_data = &tracer;
> +
> +     return nonseekable_open(inode, file);
> +}
> +
> +static ssize_t etb_read(struct file *file, char __user *data,
> +             size_t len, loff_t *ppos)
> +{
> +     int total, i;
> +     long length;
> +     struct tracectx *t = file->private_data;
> +     u32 first = 0;
> +     u32 *buf;
> +
> +     mutex_lock(&t->mutex);
> +
> +     if (trace_isrunning(t)) {
> +             length = 0;
> +             goto out;
> +     }
> +
> +     etb_unlock(t);
> +
> +     total = etb_getdatalen(t);
> +     if (total == t->etb_bufsz)
> +             first = etb_readl(t, ETBR_WRITEADDR);
> +
> +     etb_writel(t, first, ETBR_READADDR);
> +
> +     length = min(total * 4, (int)len);
> +     buf = vmalloc(length);
> +
> +     dev_dbg(t->dev, "ETB buffer length: %d\n", total);
> +     dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
> +     for (i = 0; i < length / 4; i++)
> +             buf[i] = etb_readl(t, ETBR_READMEM);
> +
> +     /* the only way to deassert overflow bit in ETB status is this */
> +     etb_writel(t, 1, ETBR_CTRL);
> +     etb_writel(t, 0, ETBR_CTRL);
> +
> +     etb_writel(t, 0, ETBR_WRITEADDR);
> +     etb_writel(t, 0, ETBR_READADDR);
> +     etb_writel(t, 0, ETBR_TRIGGERCOUNT);
> +
> +     etb_lock(t);
> +
> +     length = copy_to_user(data, buf, length);
> +     vfree(buf);
> +
> +out:
> +     mutex_unlock(&t->mutex);
> +
> +     return length;
> +}
> +
> +static int etb_release(struct inode *inode, struct file *file)
> +{
> +     /* there's nothing to do here, actually */
> +     return 0;
> +}
> +
> +static struct file_operations etb_fops = {
> +     .owner = THIS_MODULE,
> +     .read = etb_read,
> +     .open = etb_open,
> +     .release = etb_release,
> +};
> +
> +static struct miscdevice etb_miscdev = {
> +     .name = "tracebuf",
> +     .minor = 0,
> +     .fops = &etb_fops,
> +};
> +
> +static int __devinit etb_drv_probe(struct platform_device *pdev)
> +{
> +     struct tracectx *t = platform_get_drvdata(pdev);
> +     struct resource *res;
> +     struct clk *clk;
> +     int ret = 0;
> +
> +     if (t && t->etb_regs) {
> +             dev_dbg(&pdev->dev, "ETB already initialized\n");
> +             ret = -EBUSY;
> +             goto out;
> +     }
> +
> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +     if (!res) {
> +             ret = -ENODEV;
> +             goto out;
> +     }
> +
> +     if (!request_mem_region(res->start, SZ_4K, "etb")) {
> +             ret = -EBUSY;
> +             goto out;
> +     }
> +
> +     if (!t) {
> +             t = &tracer;
> +             platform_set_drvdata(pdev, t);
> +     }
> +
> +     t->etb_regs = ioremap_nocache(res->start, SZ_4K);
> +     if (!t->etb_regs) {
> +             ret = -ENOMEM;
> +             platform_set_drvdata(pdev, NULL);
> +             release_mem_region(res->start, SZ_4K);
> +             goto out;
> +     }
> +
> +     etb_miscdev.parent = &pdev->dev;
> +
> +     ret = misc_register(&etb_miscdev);
> +     if (ret) {
> +             platform_set_drvdata(pdev, NULL);
> +             iounmap(t->etb_regs);
> +             release_mem_region(res->start, SZ_4K);
> +             goto out;
> +     }
> +
> +     clk = clk_get(&pdev->dev, "emu_core_alwon_ck");
> +     clk_enable(clk);
> +
> +     clk = clk_get(&pdev->dev, "emu_per_alwon_ck");
> +     clk_enable(clk);
> +
> +     clk = clk_get(&pdev->dev, "emu_mpu_alwon_ck");
> +     clk_enable(clk);
> +
> +     clk = clk_get(&pdev->dev, "emu_src_ck");
> +     clk_enable(clk);
> +
> +     etb_unlock(t);
> +     t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
> +     dev_dbg(&pdev->dev, "Size: %x\n", t->etb_bufsz);
> +
> +     /* make sure trace capture is disabled */
> +     etb_writel(t, 0, ETBR_CTRL);
> +     etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
> +     etb_lock(t);
> +
> +     dev_dbg(&pdev->dev, "ETB platform driver initialized.\n");
> +
> +     ret = 0;
> +out:
> +     return ret;
> +}
> +
> +static struct platform_driver etb_driver = {
> +     .probe           = etb_drv_probe,
> +     .driver  = {
> +             .name    = "etb",
> +             .owner  = THIS_MODULE,
> +     },
> +};
> +
> +/* use a sysfs file "trace_running" to start/stop tracing */
> +static ssize_t trace_running_show(struct kobject *kobj,
> +                               struct kobj_attribute *attr,
> +                               char *buf)
> +{
> +     return sprintf(buf, "%x\n", trace_isrunning(&tracer));
> +}
> +
> +static ssize_t trace_running_store(struct kobject *kobj,
> +                                struct kobj_attribute *attr,
> +                                const char *buf, size_t n)
> +{
> +     unsigned int value;
> +     int ret;
> +
> +     if (sscanf(buf, "%u", &value) != 1)
> +             return -EINVAL;
> +
> +     mutex_lock(&tracer.mutex);
> +     ret = value ? trace_start(&tracer) : trace_stop(&tracer);
> +     mutex_unlock(&tracer.mutex);
> +
> +     return ret ? : n;
> +}
> +
> +static struct kobj_attribute trace_running_attr =
> +     __ATTR(trace_running, 0644, trace_running_show,
> trace_running_store);
> +
> +static ssize_t trace_info_show(struct kobject *kobj,
> +                               struct kobj_attribute *attr,
> +                               char *buf)
> +{
> +     u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
> +     int datalen;
> +
> +     etb_unlock(&tracer);
> +     datalen = etb_getdatalen(&tracer);
> +     etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
> +     etb_ra = etb_readl(&tracer, ETBR_READADDR);
> +     etb_st = etb_readl(&tracer, ETBR_STATUS);
> +     etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
> +     etb_lock(&tracer);
> +
> +     etm_unlock(&tracer);
> +     etm_ctrl = etm_readl(&tracer, ETMR_CTRL);
> +     etm_st = etm_readl(&tracer, ETMR_STATUS);
> +     etm_lock(&tracer);
> +
> +     return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
> +                     "ETBR_WRITEADDR:\t%08x\n"
> +                     "ETBR_READADDR:\t%08x\n"
> +                     "ETBR_STATUS:\t%08x\n"
> +                     "ETBR_FORMATTERCTRL:\t%08x\n"
> +                     "ETMR_CTRL:\t%08x\n"
> +                     "ETMR_STATUS:\t%08x\n",
> +                     datalen,
> +                     tracer.ncmppairs,
> +                     etb_wa,
> +                     etb_ra,
> +                     etb_st,
> +                     etb_fc,
> +                     etm_ctrl,
> +                     etm_st
> +                     );
> +}
> +
> +static struct kobj_attribute trace_info_attr =
> +     __ATTR(trace_info, 0444, trace_info_show, NULL);
> +
> +static ssize_t trace_mode_show(struct kobject *kobj,
> +                               struct kobj_attribute *attr,
> +                               char *buf)
> +{
> +     return sprintf(buf, "%d %d\n",
> +                     !!(tracer.flags & TRACER_CYCLE_ACC),
> +                     tracer.etm_portsz);
> +}
> +
> +static ssize_t trace_mode_store(struct kobject *kobj,
> +                                struct kobj_attribute *attr,
> +                                const char *buf, size_t n)
> +{
> +     unsigned int cycacc, portsz;
> +
> +     if (sscanf(buf, "%u %u", &cycacc, &portsz) != 2)
> +             return -EINVAL;
> +
> +     mutex_lock(&tracer.mutex);
> +     if (cycacc)
> +             tracer.flags |= TRACER_CYCLE_ACC;
> +     else
> +             tracer.flags &= ~TRACER_CYCLE_ACC;
> +
> +     tracer.etm_portsz = portsz & 0x0f;
> +     mutex_unlock(&tracer.mutex);
> +
> +     return n;
> +}
> +
> +static struct kobj_attribute trace_mode_attr =
> +     __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
> +
> +static int __devinit etm_drv_probe(struct platform_device *pdev)
> +{
> +     struct tracectx *t = platform_get_drvdata(pdev);
> +     struct resource *res;
> +     int ret = 0;
> +
> +     if (t && t->etm_regs) {
> +             dev_dbg(&pdev->dev, "ETM already initialized\n");
> +             ret = -EBUSY;
> +             goto out;
> +     }
> +
> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +     if (!res) {
> +             ret = -ENODEV;
> +             goto out;
> +     }
> +
> +     if (!request_mem_region(res->start, SZ_4K, "etm")) {
> +             ret = -EBUSY;
> +             goto out;
> +     }
> +
> +     if (!t) {
> +             t = &tracer;
> +             platform_set_drvdata(pdev, t);
> +     }
> +
> +     t->etm_regs = ioremap_nocache(res->start, SZ_4K);
> +     if (!t->etm_regs) {
> +             ret = -ENOMEM;
> +             release_mem_region(res->start, SZ_4K);
> +             platform_set_drvdata(pdev, NULL);
> +             goto out;
> +     }
> +
> +     mutex_init(&t->mutex);
> +     t->dev = &pdev->dev;
> +     t->flags = TRACER_CYCLE_ACC;
> +     t->etm_portsz = 1;
> +
> +     etm_unlock(t);
> +     ret = etm_readl(t, CSCR_PRSR);
> +
> +     t->ncmppairs = etm_readl(t, ETMR_CONFCODE) & 0xf;
> +     etm_writel(t, 0x440, ETMR_CTRL);
> +     etm_lock(t);
> +
> +     ret = sysfs_create_file(&pdev->dev.kobj,
> +                     &trace_running_attr.attr);
> +     ret = sysfs_create_file(&pdev->dev.kobj,
> +                     &trace_info_attr.attr);
> +     ret = sysfs_create_file(&pdev->dev.kobj,
> +                     &trace_mode_attr.attr);
> +     dev_dbg(t->dev, "ETM platform driver initialized.\n");
> +
> +out:
> +     return ret;
> +}
> +
> +static struct platform_driver etm_driver = {
> +     .probe           = etm_drv_probe,
> +     .driver  = {
> +             .name    = "etm",
> +             .owner   = THIS_MODULE,
> +     },
> +};
> +
> +static int __init etm_init(void)
> +{
> +     platform_driver_register(&etb_driver);
> +     platform_driver_register(&etm_driver);
> +     register_sysrq_key('v', &sysrq_etm_op);
> +
> +     return 0;
> +}
> +
> +module_init(etm_init);
> +
> diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
> index 75b1c7e..87bcc2a 100644
> --- a/arch/arm/mach-omap2/Kconfig
> +++ b/arch/arm/mach-omap2/Kconfig
> @@ -88,3 +88,10 @@ config MACH_OMAP_ZOOM2
>  config MACH_OMAP_4430SDP
>       bool "OMAP 4430 SDP board"
>       depends on ARCH_OMAP4
> +
> +config OMAP3_EMU
> +     tristate "OMAP3 debugging peripherals"
> +     depends on ARCH_OMAP3 && OC_ETM
> +     help
> +       Say Y here to enable debugging hardware of omap3
> +
> diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
> index 6b7702f..572dd27 100644
> --- a/arch/arm/mach-omap2/Makefile
> +++ b/arch/arm/mach-omap2/Makefile
> @@ -44,6 +44,9 @@ obj-$(CONFIG_ARCH_OMAP4)            += cm4xxx.o
>  obj-$(CONFIG_ARCH_OMAP2)             += clock24xx.o
>  obj-$(CONFIG_ARCH_OMAP3)             += clock34xx.o
>
> +# EMU periferals
> +obj-$(CONFIG_OMAP3_EMU)              += emu.o
> +
>  iommu-y                                      += iommu2.o
>  iommu-$(CONFIG_ARCH_OMAP3)           += omap3-iommu.o
>
> diff --git a/arch/arm/mach-omap2/emu.c b/arch/arm/mach-omap2/emu.c
> new file mode 100644
> index 0000000..f98874e
> --- /dev/null
> +++ b/arch/arm/mach-omap2/emu.c
> @@ -0,0 +1,70 @@
> +/*
> + * linux/arch/arm/mach-omap2/emu.c
> + *
> + * ETM and ETB CoreSight components' resources as found in OMAP3xxx.
> + *
> + * Copyright (C) 2009 Nokia Corporation.
> + * Alexander Shishkin
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/types.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Alexander Shishkin");
> +
> +/* Cortex CoreSight components within omap3xxx EMU */
> +#define ETM_BASE     (L4_EMU_34XX_PHYS + 0x10000)
> +#define DBG_BASE     (L4_EMU_34XX_PHYS + 0x11000)
> +#define ETB_BASE     (L4_EMU_34XX_PHYS + 0x1b000)
> +#define DAPCTL               (L4_EMU_34XX_PHYS + 0x1d000)
> +
> +static struct resource rx51_etb_resource = {
> +     .start = ETB_BASE,
> +     .end   = ETB_BASE + SZ_4K,
> +     .flags = IORESOURCE_MEM,
> +};
> +
> +static struct platform_device rx51_etb_device = {
> +     .name = "etb",
> +     .id   = -1,
> +     .num_resources = 1,
> +     .resource = &rx51_etb_resource,
> +};
> +
> +static struct resource rx51_etm_resource = {
> +     .start = ETM_BASE,
> +     .end   = ETM_BASE + SZ_4K,
> +     .flags = IORESOURCE_MEM,
> +};
> +
> +static struct platform_device rx51_etm_device = {
> +     .name = "etm",
> +     .id   = -1,
> +     .num_resources = 1,
> +     .resource = &rx51_etm_resource,
> +};
> +
> +static struct platform_device *rx51_trace_devices[] = {
> +     &rx51_etm_device,
> +     &rx51_etb_device,
> +};
> +
> +static int __init emu_init(void)
> +{
> +     platform_add_devices(rx51_trace_devices,
> +                     ARRAY_SIZE(rx51_trace_devices));
> +
> +     return 0;
> +}
> +
> +module_init(emu_init);
> +
> --
> 1.6.3.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/2] arm/omap3: a driver for on-chip ETM and ETB
  2009-10-10 13:48 ` Shilimkar, Santosh
@ 2009-10-11 17:08   ` Alexander Shishkin
  0 siblings, 0 replies; 4+ messages in thread
From: Alexander Shishkin @ 2009-10-11 17:08 UTC (permalink / raw)
  To: Shilimkar, Santosh; +Cc: linux-omap@vger.kernel.org

2009/10/10 Shilimkar, Santosh <santosh.shilimkar@ti.com>:
>> -----Original Message-----
>> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
>> owner@vger.kernel.org] On Behalf Of virtuoso@slind.org
>> Sent: Thursday, October 08, 2009 3:06 AM
>> To: linux-omap@vger.kernel.org
>> Cc: Alexander Shishkin
>> Subject: [PATCH 1/2] arm/omap3: a driver for on-chip ETM and ETB
>>
>> From: Alexander Shishkin <virtuoso@slind.org>
>>
>> This driver implements /dev/tracebuf and some control files for ETM
>> and ETB in sysfs.
> Looks like a very useful driver for tracing/debug.
> Do you have some README link on the usage of this driver ?

Well, here's a brief intro into how to collect traces and decode them:
http://wiki.github.com/virtuoso/etm2human/quickstart

That's not much, but if you have any questions, just email them to me
and I'll try to update the page.

Regards,
--
Alex

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2009-10-11 17:09 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-10-07 21:36 [PATCH 1/2] arm/omap3: a driver for on-chip ETM and ETB virtuoso
2009-10-09 19:32 ` Tony Lindgren
2009-10-10 13:48 ` Shilimkar, Santosh
2009-10-11 17:08   ` Alexander Shishkin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox