Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c67cc907 authored by Mulu He's avatar Mulu He Committed by Gerrit - the friendly Code Review server
Browse files

coresight: tmc: etr: Add sys interface for ETR



Add usb streaming support to collect trace data externally.
Add support to enable USB mode for coresight devices.
Set memory as the default mode on ETR.

Change-Id: I3bd2bd92c676ff79a3ae5a045a54e7d1e867543d
Signed-off-by: default avatarMulu He <muluhe@codeaurora.org>
parent 82760b29
Loading
Loading
Loading
Loading
+13 −11
Original line number Diff line number Diff line
@@ -13,13 +13,6 @@
#include "coresight-priv.h"
#include "coresight-tmc.h"

struct etr_flat_buf {
	struct device	*dev;
	dma_addr_t	daddr;
	void		*vaddr;
	size_t		size;
};

/*
 * The TMC ETR SG has a page size of 4K. The SG table contains pointers
 * to 4KB buffers. However, the OS may use a PAGE_SIZE different from
@@ -895,7 +888,7 @@ static void tmc_sync_etr_buf(struct tmc_drvdata *drvdata)
		tmc_etr_buf_insert_barrier_packet(etr_buf, etr_buf->offset);
}

static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
{
	u32 axictl, sts;
	struct etr_buf *etr_buf = drvdata->etr_buf;
@@ -1007,7 +1000,7 @@ static void tmc_etr_sync_sysfs_buf(struct tmc_drvdata *drvdata)
	tmc_sync_etr_buf(drvdata);
}

static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
{
	CS_UNLOCK(drvdata->base);

@@ -1081,7 +1074,10 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
	}

	drvdata->mode = CS_MODE_SYSFS;

	if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
		tmc_etr_enable_hw(drvdata);

	drvdata->enable = true;
out:
	spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -1132,7 +1128,9 @@ static void tmc_disable_etr_sink(struct coresight_device *csdev)

	/* Disable the TMC only if it needs to */
	if (drvdata->mode != CS_MODE_DISABLED) {
		if (drvdata->out_mode != TMC_ETR_OUT_MODE_USB)
			tmc_etr_disable_hw(drvdata);

		drvdata->mode = CS_MODE_DISABLED;
	}

@@ -1166,6 +1164,10 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
		goto out;
	}

	if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
		ret = -EINVAL;
		goto out;
	}
	/* Don't interfere if operated from Perf */
	if (drvdata->mode == CS_MODE_PERF) {
		ret = -EINVAL;
+109 −6
Original line number Diff line number Diff line
@@ -320,14 +320,108 @@ static ssize_t buffer_size_store(struct device *dev,

static DEVICE_ATTR_RW(buffer_size);

static struct attribute *coresight_tmc_attrs[] = {
static ssize_t out_mode_show(struct device *dev,
			     struct device_attribute *attr, char *buf)
{
	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);

	return scnprintf(buf, PAGE_SIZE, "%s\n",
			str_tmc_etr_out_mode[drvdata->out_mode]);
}

static ssize_t out_mode_store(struct device *dev,
			      struct device_attribute *attr,
			      const char *buf, size_t size)
{
	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
	char str[10] = "";
	unsigned long flags;
	int ret;

	if (strlen(buf) >= 10)
		return -EINVAL;
	if (sscanf(buf, "%10s", str) != 1)
		return -EINVAL;

	mutex_lock(&drvdata->mem_lock);
	if (!strcmp(str, str_tmc_etr_out_mode[TMC_ETR_OUT_MODE_MEM])) {
		if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
			goto out;

		spin_lock_irqsave(&drvdata->spinlock, flags);
		if (!drvdata->enable) {
			drvdata->out_mode = TMC_ETR_OUT_MODE_MEM;
			spin_unlock_irqrestore(&drvdata->spinlock, flags);
			goto out;
		}

		tmc_etr_enable_hw(drvdata);
		drvdata->out_mode = TMC_ETR_OUT_MODE_MEM;
		spin_unlock_irqrestore(&drvdata->spinlock, flags);
	} else if (!strcmp(str, str_tmc_etr_out_mode[TMC_ETR_OUT_MODE_USB])) {
		if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB)
			goto out;

		spin_lock_irqsave(&drvdata->spinlock, flags);
		if (!drvdata->enable) {
			drvdata->out_mode = TMC_ETR_OUT_MODE_USB;
			spin_unlock_irqrestore(&drvdata->spinlock, flags);
			goto out;
		}
		if (drvdata->reading) {
			ret = -EBUSY;
			goto err1;
		}
		tmc_etr_disable_hw(drvdata);
		drvdata->out_mode = TMC_ETR_OUT_MODE_USB;
		spin_unlock_irqrestore(&drvdata->spinlock, flags);
	}
out:
	mutex_unlock(&drvdata->mem_lock);
	return size;
err1:
	spin_unlock_irqrestore(&drvdata->spinlock, flags);
	mutex_unlock(&drvdata->mem_lock);
	return ret;
}
static DEVICE_ATTR_RW(out_mode);

static ssize_t available_out_modes_show(struct device *dev,
				       struct device_attribute *attr,
				       char *buf)
{
	ssize_t len = 0;
	int i;

	for (i = 0; i < ARRAY_SIZE(str_tmc_etr_out_mode); i++)
		len += scnprintf(buf + len, PAGE_SIZE - len, "%s ",
				str_tmc_etr_out_mode[i]);

	len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
	return len;
}
static DEVICE_ATTR_RO(available_out_modes);

static struct attribute *coresight_tmc_etf_attrs[] = {
	&dev_attr_trigger_cntr.attr,
	&dev_attr_buffer_size.attr,
	NULL,
};

static struct attribute *coresight_tmc_etr_attrs[] = {
	&dev_attr_trigger_cntr.attr,
	&dev_attr_buffer_size.attr,
	&dev_attr_out_mode.attr,
	&dev_attr_available_out_modes.attr,
	NULL,
};

static const struct attribute_group coresight_tmc_group = {
	.attrs = coresight_tmc_attrs,
static const struct attribute_group coresight_tmc_etf_group = {
	.attrs = coresight_tmc_etf_attrs,
};

static const struct attribute_group coresight_tmc_etr_group = {
	.attrs = coresight_tmc_etr_attrs,
};

static const struct attribute_group coresight_tmc_mgmt_group = {
@@ -335,8 +429,14 @@ static const struct attribute_group coresight_tmc_mgmt_group = {
	.name = "mgmt",
};

const struct attribute_group *coresight_tmc_groups[] = {
	&coresight_tmc_group,
const struct attribute_group *coresight_tmc_etf_groups[] = {
	&coresight_tmc_etf_group,
	&coresight_tmc_mgmt_group,
	NULL,
};

const struct attribute_group *coresight_tmc_etr_groups[] = {
	&coresight_tmc_etr_group,
	&coresight_tmc_mgmt_group,
	NULL,
};
@@ -392,16 +492,19 @@ static int tmc_config_desc(struct tmc_drvdata *drvdata,
	case TMC_CONFIG_TYPE_ETB:
		desc->type = CORESIGHT_DEV_TYPE_SINK;
		desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
		desc->groups = coresight_tmc_etf_groups;
		desc->ops = &tmc_etb_cs_ops;
		break;
	case TMC_CONFIG_TYPE_ETR:
		desc->type = CORESIGHT_DEV_TYPE_SINK;
		desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
		desc->groups = coresight_tmc_etr_groups;
		desc->ops = &tmc_etr_cs_ops;
		break;
	case TMC_CONFIG_TYPE_ETF:
		desc->type = CORESIGHT_DEV_TYPE_LINKSINK;
		desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
		desc->groups = coresight_tmc_etf_groups;
		desc->ops = &tmc_etf_cs_ops;
		break;
	default:
@@ -455,6 +558,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
	drvdata->memwidth = tmc_get_memwidth(devid);

	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
		drvdata->out_mode = TMC_ETR_OUT_MODE_MEM;
		ret = of_property_read_u32(np, "arm,buffer-size",
					   &drvdata->size);
		if (ret)
@@ -478,7 +582,6 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)

	desc.pdata = pdata;
	desc.dev = dev;
	desc.groups = coresight_tmc_groups;
	ret = tmc_config_desc(drvdata, &desc);
	if (ret)
		goto out;
+26 −0
Original line number Diff line number Diff line
@@ -9,6 +9,10 @@

#include <linux/dma-mapping.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/cacheflush.h>
#include <linux/of_address.h>
#include <linux/amba/bus.h>

#define TMC_RSZ			0x004
#define TMC_STS			0x00c
@@ -133,8 +137,27 @@ enum etr_mode {
	ETR_MODE_CATU,		/* Use SG mechanism in CATU */
};

enum tmc_etr_out_mode {
	TMC_ETR_OUT_MODE_NONE,
	TMC_ETR_OUT_MODE_MEM,
	TMC_ETR_OUT_MODE_USB,
};

static const char * const str_tmc_etr_out_mode[] = {
	[TMC_ETR_OUT_MODE_NONE]		= "none",
	[TMC_ETR_OUT_MODE_MEM]		= "mem",
	[TMC_ETR_OUT_MODE_USB]		= "usb",
};

struct etr_buf_operations;

struct etr_flat_buf {
	struct device	*dev;
	dma_addr_t	daddr;
	void		*vaddr;
	size_t		size;
};

/**
 * struct etr_buf - Details of the buffer used by ETR
 * @mode	: Mode of the ETR buffer, contiguous, Scatter Gather etc.
@@ -197,6 +220,7 @@ struct tmc_drvdata {
	struct coresight_csr	*csr;
	const char		*csr_name;
	bool			enable;
	enum tmc_etr_out_mode	out_mode;
};

struct etr_buf_operations {
@@ -257,6 +281,8 @@ ssize_t tmc_etb_get_sysfs_trace(struct tmc_drvdata *drvdata,
/* ETR functions */
int tmc_read_prepare_etr(struct tmc_drvdata *drvdata);
int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata);
void tmc_etr_enable_hw(struct tmc_drvdata *drvdata);
void tmc_etr_disable_hw(struct tmc_drvdata *drvdata);
extern const struct coresight_ops tmc_etr_cs_ops;
ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata,
				loff_t pos, size_t len, char **bufpp);