coresight: byte-cntr: Add support for streaming interface for ETR

Add support for a streaming interface for TMC ETR to allow for continuous
log collection to secondary storage. An interrupt based mechanism is used
to stream out the data from the device. The streaming interface cannot be
used in conjunction with the traditional ETR read operation.

Change-Id: Ie80f817740fe3fddbb7fe95b02263525b0bff6e8
Signed-off-by: Mulu He <muluhe@codeaurora.org>
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 6c45db4..b0b24d1 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1086,8 +1086,10 @@
 	if (free_buf)
 		tmc_etr_free_sysfs_buf(free_buf);
 
-	mutex_unlock(&drvdata->mem_lock);
+	if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
+		tmc_etr_byte_cntr_start(drvdata->byte_cntr);
 
+	mutex_unlock(&drvdata->mem_lock);
 	if (!ret)
 		dev_info(drvdata->dev, "TMC-ETR enabled\n");
 
@@ -1135,6 +1137,10 @@
 	}
 
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
+		tmc_etr_byte_cntr_stop(drvdata->byte_cntr);
+
 	mutex_unlock(&drvdata->mem_lock);
 	dev_info(drvdata->dev, "TMC-ETR disabled\n");
 }
@@ -1180,6 +1186,11 @@
 		goto out;
 	}
 
+	if (drvdata->byte_cntr && drvdata->byte_cntr->enable) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/* Disable the TMC if need be */
 	if (drvdata->mode == CS_MODE_SYSFS)
 		tmc_etr_disable_hw(drvdata);
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 0ff38c7..0b26807 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -402,6 +402,42 @@
 }
 static DEVICE_ATTR_RO(available_out_modes);
 
+static ssize_t block_size_show(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	uint32_t val = 0;
+
+	if (drvdata->byte_cntr)
+		val = drvdata->byte_cntr->block_size;
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n",
+			val);
+}
+
+static ssize_t block_size_store(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf,
+			      size_t size)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	if (!drvdata->byte_cntr)
+		return -EINVAL;
+
+	mutex_lock(&drvdata->byte_cntr->byte_cntr_lock);
+	drvdata->byte_cntr->block_size = val * 8;
+	mutex_unlock(&drvdata->byte_cntr->byte_cntr_lock);
+
+	return size;
+}
+static DEVICE_ATTR_RW(block_size);
+
 static struct attribute *coresight_tmc_etf_attrs[] = {
 	&dev_attr_trigger_cntr.attr,
 	&dev_attr_buffer_size.attr,
@@ -413,6 +449,7 @@
 	&dev_attr_buffer_size.attr,
 	&dev_attr_out_mode.attr,
 	&dev_attr_available_out_modes.attr,
+	&dev_attr_block_size.attr,
 	NULL,
 };
 
@@ -590,6 +627,8 @@
 		ret = tmc_etr_setup_caps(drvdata, devid, id->data);
 		if (ret)
 			goto out;
+
+		drvdata->byte_cntr = byte_cntr_init(adev, drvdata);
 	}
 
 	drvdata->csdev = coresight_register(&desc);
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 0cd1a9d..cdbcba0 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -14,6 +14,8 @@
 #include <linux/of_address.h>
 #include <linux/amba/bus.h>
 
+#include "coresight-byte-cntr.h"
+
 #define TMC_RSZ			0x004
 #define TMC_STS			0x00c
 #define TMC_RRD			0x010
@@ -221,6 +223,7 @@
 	const char		*csr_name;
 	bool			enable;
 	enum tmc_etr_out_mode	out_mode;
+	struct byte_cntr	*byte_cntr;
 };
 
 struct etr_buf_operations {
@@ -283,6 +286,8 @@
 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 struct byte_cntr *byte_cntr_init(struct amba_device *adev,
+					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);