All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V2 00/15] coresight: tmc: make driver usable by Perf
@ 2016-04-12 17:54 ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

This patchset makes the TMC driver usable from Perf by way of the
recently added AUX area functionality.

The first 12 patches remodel the driver so that the functionality
is compartmented enough to be used as building blocks when interfacing
with the Perf subsystem.

Patch 13 and 14 implement the AUX area API, taking heavily on the existing
ETB10 implementation.

Finally patch 15 allows the TMC to be used as a link rather than a sink,
something that is required when dealing with an ETF component.

Best regards,
Mathieu

Changes for V2:
- Renamed functions tmc_read_prepare/unprepare_etf() to 
  tmc_read_prepare/unprepare_etb().
- Consolidated return points in functions tmc_enable_etf/etr_sink().
- Re-wrote allocation schemed in functions tmc_enable_etf/etr_sink().
- Fixed description typos in patch 7/15.
- Fixed problem with linksink devices when disabling a path in patch 15/15.

Mathieu Poirier (15):
  coresight: tmc: modifying naming convention
  coresight: tmc: waiting for TMCReady bit before programming
  coresight: tmc: re-implementing tmc_read_prepare/unprepare() functions
  coresight: tmc: introducing new header file
  coresight: tmc: splitting driver in ETB/ETF and ETR components
  coresight: tmc: making prepare/unprepare functions generic
  coresight: tmc: allocating memory when needed
  coresight: tmc: getting the right read_count on tmc_open()
  coresight: tmc: adding mode of operation for link/sinks
  coresight: tmc: dump system memory content only when needed
  coresight: tmc: make sysFS and Perf mode mutually exclusive
  coresight: tmc: keep track of memory width
  coresight: tmc: implementing TMC-ETF AUX space API
  coresight: tmc: implementing TMC-ETR AUX space API
  coresight: configuring ETF in FIFO mode when acting as link

 drivers/hwtracing/coresight/Makefile            |   4 +-
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 611 ++++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 467 ++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tmc.c     | 450 ++---------------
 drivers/hwtracing/coresight/coresight-tmc.h     | 166 +++++++
 drivers/hwtracing/coresight/coresight.c         |  32 +-
 6 files changed, 1312 insertions(+), 418 deletions(-)
 create mode 100644 drivers/hwtracing/coresight/coresight-tmc-etf.c
 create mode 100644 drivers/hwtracing/coresight/coresight-tmc-etr.c
 create mode 100644 drivers/hwtracing/coresight/coresight-tmc.h

-- 
2.5.0

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

* [PATCH V2 00/15] coresight: tmc: make driver usable by Perf
@ 2016-04-12 17:54 ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset makes the TMC driver usable from Perf by way of the
recently added AUX area functionality.

The first 12 patches remodel the driver so that the functionality
is compartmented enough to be used as building blocks when interfacing
with the Perf subsystem.

Patch 13 and 14 implement the AUX area API, taking heavily on the existing
ETB10 implementation.

Finally patch 15 allows the TMC to be used as a link rather than a sink,
something that is required when dealing with an ETF component.

Best regards,
Mathieu

Changes for V2:
- Renamed functions tmc_read_prepare/unprepare_etf() to 
  tmc_read_prepare/unprepare_etb().
- Consolidated return points in functions tmc_enable_etf/etr_sink().
- Re-wrote allocation schemed in functions tmc_enable_etf/etr_sink().
- Fixed description typos in patch 7/15.
- Fixed problem with linksink devices when disabling a path in patch 15/15.

Mathieu Poirier (15):
  coresight: tmc: modifying naming convention
  coresight: tmc: waiting for TMCReady bit before programming
  coresight: tmc: re-implementing tmc_read_prepare/unprepare() functions
  coresight: tmc: introducing new header file
  coresight: tmc: splitting driver in ETB/ETF and ETR components
  coresight: tmc: making prepare/unprepare functions generic
  coresight: tmc: allocating memory when needed
  coresight: tmc: getting the right read_count on tmc_open()
  coresight: tmc: adding mode of operation for link/sinks
  coresight: tmc: dump system memory content only when needed
  coresight: tmc: make sysFS and Perf mode mutually exclusive
  coresight: tmc: keep track of memory width
  coresight: tmc: implementing TMC-ETF AUX space API
  coresight: tmc: implementing TMC-ETR AUX space API
  coresight: configuring ETF in FIFO mode when acting as link

 drivers/hwtracing/coresight/Makefile            |   4 +-
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 611 ++++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 467 ++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tmc.c     | 450 ++---------------
 drivers/hwtracing/coresight/coresight-tmc.h     | 166 +++++++
 drivers/hwtracing/coresight/coresight.c         |  32 +-
 6 files changed, 1312 insertions(+), 418 deletions(-)
 create mode 100644 drivers/hwtracing/coresight/coresight-tmc-etf.c
 create mode 100644 drivers/hwtracing/coresight/coresight-tmc-etr.c
 create mode 100644 drivers/hwtracing/coresight/coresight-tmc.h

-- 
2.5.0

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

* [PATCH V2 01/15] coresight: tmc: modifying naming convention
  2016-04-12 17:54 ` Mathieu Poirier
@ 2016-04-12 17:54   ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

According to the TMC architectural state machine, the 'stopped'
state is reached when bit 2 (TMCReady) of the TMC Status register
turns to '1'.  The code is correct but the naming convention isn't.

The 'Triggered' bit occupies position '1' of the TMC Status register
and has nothing to do with the indication of the TMC entering the
stopped state. As such renaming function "tmc_wait_for_triggered()"
and changing the #define to reflect what the code is really doing.

This patch has no effect other than clarifying the semantic.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 2b42ecbd8831..3f646e29a99b 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -77,7 +77,7 @@
 #define TMC_FFCR_TRIGON_TRIGIN	BIT(8)
 #define TMC_FFCR_STOP_ON_FLUSH	BIT(12)
 
-#define TMC_STS_TRIGGERED_BIT	2
+#define TMC_STS_TMCREADY_BIT	2
 #define TMC_FFCR_FLUSHMAN_BIT	6
 
 enum tmc_config_type {
@@ -132,11 +132,11 @@ struct tmc_drvdata {
 	u32			trigger_cntr;
 };
 
-static void tmc_wait_for_ready(struct tmc_drvdata *drvdata)
+static void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
 {
 	/* Ensure formatter, unformatter and hardware fifo are empty */
 	if (coresight_timeout(drvdata->base,
-			      TMC_STS, TMC_STS_TRIGGERED_BIT, 1)) {
+			      TMC_STS, TMC_STS_TMCREADY_BIT, 1)) {
 		dev_err(drvdata->dev,
 			"timeout observed when probing at offset %#x\n",
 			TMC_STS);
@@ -160,7 +160,7 @@ static void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
 			TMC_FFCR);
 	}
 
-	tmc_wait_for_ready(drvdata);
+	tmc_wait_for_tmcready(drvdata);
 }
 
 static void tmc_enable_hw(struct tmc_drvdata *drvdata)
-- 
2.5.0

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

* [PATCH V2 01/15] coresight: tmc: modifying naming convention
@ 2016-04-12 17:54   ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

According to the TMC architectural state machine, the 'stopped'
state is reached when bit 2 (TMCReady) of the TMC Status register
turns to '1'.  The code is correct but the naming convention isn't.

The 'Triggered' bit occupies position '1' of the TMC Status register
and has nothing to do with the indication of the TMC entering the
stopped state. As such renaming function "tmc_wait_for_triggered()"
and changing the #define to reflect what the code is really doing.

This patch has no effect other than clarifying the semantic.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 2b42ecbd8831..3f646e29a99b 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -77,7 +77,7 @@
 #define TMC_FFCR_TRIGON_TRIGIN	BIT(8)
 #define TMC_FFCR_STOP_ON_FLUSH	BIT(12)
 
-#define TMC_STS_TRIGGERED_BIT	2
+#define TMC_STS_TMCREADY_BIT	2
 #define TMC_FFCR_FLUSHMAN_BIT	6
 
 enum tmc_config_type {
@@ -132,11 +132,11 @@ struct tmc_drvdata {
 	u32			trigger_cntr;
 };
 
-static void tmc_wait_for_ready(struct tmc_drvdata *drvdata)
+static void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
 {
 	/* Ensure formatter, unformatter and hardware fifo are empty */
 	if (coresight_timeout(drvdata->base,
-			      TMC_STS, TMC_STS_TRIGGERED_BIT, 1)) {
+			      TMC_STS, TMC_STS_TMCREADY_BIT, 1)) {
 		dev_err(drvdata->dev,
 			"timeout observed when probing at offset %#x\n",
 			TMC_STS);
@@ -160,7 +160,7 @@ static void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
 			TMC_FFCR);
 	}
 
-	tmc_wait_for_ready(drvdata);
+	tmc_wait_for_tmcready(drvdata);
 }
 
 static void tmc_enable_hw(struct tmc_drvdata *drvdata)
-- 
2.5.0

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

* [PATCH V2 02/15] coresight: tmc: waiting for TMCReady bit before programming
  2016-04-12 17:54 ` Mathieu Poirier
@ 2016-04-12 17:54   ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

According to the TRM before programming the TMC in circular
buffer mode (and that for any configuration, ETB, ETR, ETF),
the TMCReady bit in the status register has to be set.

This patch adds a check to make sure the state machine is in
a state where it can be configured, and complains otherwise.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 3f646e29a99b..66fa7736d12f 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -180,6 +180,9 @@ static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
 
 	CS_UNLOCK(drvdata->base);
 
+	/* Wait for TMCSReady bit to be set */
+	tmc_wait_for_tmcready(drvdata);
+
 	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
 	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
 		       TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
@@ -201,6 +204,9 @@ static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
 
 	CS_UNLOCK(drvdata->base);
 
+	/* Wait for TMCSReady bit to be set */
+	tmc_wait_for_tmcready(drvdata);
+
 	writel_relaxed(drvdata->size / 4, drvdata->base + TMC_RSZ);
 	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
 
@@ -230,6 +236,9 @@ static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
 {
 	CS_UNLOCK(drvdata->base);
 
+	/* Wait for TMCSReady bit to be set */
+	tmc_wait_for_tmcready(drvdata);
+
 	writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE);
 	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI,
 		       drvdata->base + TMC_FFCR);
-- 
2.5.0

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

* [PATCH V2 02/15] coresight: tmc: waiting for TMCReady bit before programming
@ 2016-04-12 17:54   ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

According to the TRM before programming the TMC in circular
buffer mode (and that for any configuration, ETB, ETR, ETF),
the TMCReady bit in the status register has to be set.

This patch adds a check to make sure the state machine is in
a state where it can be configured, and complains otherwise.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 3f646e29a99b..66fa7736d12f 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -180,6 +180,9 @@ static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
 
 	CS_UNLOCK(drvdata->base);
 
+	/* Wait for TMCSReady bit to be set */
+	tmc_wait_for_tmcready(drvdata);
+
 	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
 	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
 		       TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
@@ -201,6 +204,9 @@ static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
 
 	CS_UNLOCK(drvdata->base);
 
+	/* Wait for TMCSReady bit to be set */
+	tmc_wait_for_tmcready(drvdata);
+
 	writel_relaxed(drvdata->size / 4, drvdata->base + TMC_RSZ);
 	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
 
@@ -230,6 +236,9 @@ static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
 {
 	CS_UNLOCK(drvdata->base);
 
+	/* Wait for TMCSReady bit to be set */
+	tmc_wait_for_tmcready(drvdata);
+
 	writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE);
 	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI,
 		       drvdata->base + TMC_FFCR);
-- 
2.5.0

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

* [PATCH V2 03/15] coresight: tmc: re-implementing tmc_read_prepare/unprepare() functions
  2016-04-12 17:54 ` Mathieu Poirier
@ 2016-04-12 17:54   ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

In their current implementation the tmc_read_prepare/unprepare()
are a lump of if/else that is difficult to read.  This patch is
alleviating that by using a switch statement.  The latter also
allows for a better control on the error path.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc.c | 56 ++++++++++++++++++-----------
 1 file changed, 36 insertions(+), 20 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 66fa7736d12f..d211aeec49f8 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -431,7 +431,7 @@ static const struct coresight_ops tmc_etf_cs_ops = {
 
 static int tmc_read_prepare(struct tmc_drvdata *drvdata)
 {
-	int ret;
+	int ret = 0;
 	unsigned long flags;
 	enum tmc_mode mode;
 
@@ -439,25 +439,31 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
 	if (!drvdata->enable)
 		goto out;
 
-	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+	switch (drvdata->config_type) {
+	case TMC_CONFIG_TYPE_ETB:
 		tmc_etb_disable_hw(drvdata);
-	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		tmc_etr_disable_hw(drvdata);
-	} else {
+		break;
+	case TMC_CONFIG_TYPE_ETF:
+		/* There is no point in reading a TMC in HW FIFO mode */
 		mode = readl_relaxed(drvdata->base + TMC_MODE);
-		if (mode == TMC_MODE_CIRCULAR_BUFFER) {
-			tmc_etb_disable_hw(drvdata);
-		} else {
-			ret = -ENODEV;
+		if (mode != TMC_MODE_CIRCULAR_BUFFER) {
+			ret = -EINVAL;
 			goto err;
 		}
+
+		tmc_etb_disable_hw(drvdata);
+		break;
+	case TMC_CONFIG_TYPE_ETR:
+		tmc_etr_disable_hw(drvdata);
+		break;
+	default:
+		ret = -EINVAL;
+		goto err;
 	}
+
 out:
 	drvdata->reading = true;
-	spin_unlock_irqrestore(&drvdata->spinlock, flags);
-
 	dev_info(drvdata->dev, "TMC read start\n");
-	return 0;
 err:
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 	return ret;
@@ -472,20 +478,30 @@ static void tmc_read_unprepare(struct tmc_drvdata *drvdata)
 	if (!drvdata->enable)
 		goto out;
 
-	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+	switch (drvdata->config_type) {
+	case TMC_CONFIG_TYPE_ETB:
 		tmc_etb_enable_hw(drvdata);
-	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		tmc_etr_enable_hw(drvdata);
-	} else {
+		break;
+	case TMC_CONFIG_TYPE_ETF:
+		/* Make sure we don't re-enable a TMC in HW FIFO mode */
 		mode = readl_relaxed(drvdata->base + TMC_MODE);
-		if (mode == TMC_MODE_CIRCULAR_BUFFER)
-			tmc_etb_enable_hw(drvdata);
+		if (mode != TMC_MODE_CIRCULAR_BUFFER)
+			goto err;
+
+		tmc_etb_enable_hw(drvdata);
+		break;
+	case TMC_CONFIG_TYPE_ETR:
+		tmc_etr_disable_hw(drvdata);
+		break;
+	default:
+		goto err;
 	}
+
 out:
 	drvdata->reading = false;
-	spin_unlock_irqrestore(&drvdata->spinlock, flags);
-
 	dev_info(drvdata->dev, "TMC read end\n");
+err:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 }
 
 static int tmc_open(struct inode *inode, struct file *file)
-- 
2.5.0

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

* [PATCH V2 03/15] coresight: tmc: re-implementing tmc_read_prepare/unprepare() functions
@ 2016-04-12 17:54   ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

In their current implementation the tmc_read_prepare/unprepare()
are a lump of if/else that is difficult to read.  This patch is
alleviating that by using a switch statement.  The latter also
allows for a better control on the error path.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc.c | 56 ++++++++++++++++++-----------
 1 file changed, 36 insertions(+), 20 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 66fa7736d12f..d211aeec49f8 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -431,7 +431,7 @@ static const struct coresight_ops tmc_etf_cs_ops = {
 
 static int tmc_read_prepare(struct tmc_drvdata *drvdata)
 {
-	int ret;
+	int ret = 0;
 	unsigned long flags;
 	enum tmc_mode mode;
 
@@ -439,25 +439,31 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
 	if (!drvdata->enable)
 		goto out;
 
-	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+	switch (drvdata->config_type) {
+	case TMC_CONFIG_TYPE_ETB:
 		tmc_etb_disable_hw(drvdata);
-	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		tmc_etr_disable_hw(drvdata);
-	} else {
+		break;
+	case TMC_CONFIG_TYPE_ETF:
+		/* There is no point in reading a TMC in HW FIFO mode */
 		mode = readl_relaxed(drvdata->base + TMC_MODE);
-		if (mode == TMC_MODE_CIRCULAR_BUFFER) {
-			tmc_etb_disable_hw(drvdata);
-		} else {
-			ret = -ENODEV;
+		if (mode != TMC_MODE_CIRCULAR_BUFFER) {
+			ret = -EINVAL;
 			goto err;
 		}
+
+		tmc_etb_disable_hw(drvdata);
+		break;
+	case TMC_CONFIG_TYPE_ETR:
+		tmc_etr_disable_hw(drvdata);
+		break;
+	default:
+		ret = -EINVAL;
+		goto err;
 	}
+
 out:
 	drvdata->reading = true;
-	spin_unlock_irqrestore(&drvdata->spinlock, flags);
-
 	dev_info(drvdata->dev, "TMC read start\n");
-	return 0;
 err:
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 	return ret;
@@ -472,20 +478,30 @@ static void tmc_read_unprepare(struct tmc_drvdata *drvdata)
 	if (!drvdata->enable)
 		goto out;
 
-	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+	switch (drvdata->config_type) {
+	case TMC_CONFIG_TYPE_ETB:
 		tmc_etb_enable_hw(drvdata);
-	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		tmc_etr_enable_hw(drvdata);
-	} else {
+		break;
+	case TMC_CONFIG_TYPE_ETF:
+		/* Make sure we don't re-enable a TMC in HW FIFO mode */
 		mode = readl_relaxed(drvdata->base + TMC_MODE);
-		if (mode == TMC_MODE_CIRCULAR_BUFFER)
-			tmc_etb_enable_hw(drvdata);
+		if (mode != TMC_MODE_CIRCULAR_BUFFER)
+			goto err;
+
+		tmc_etb_enable_hw(drvdata);
+		break;
+	case TMC_CONFIG_TYPE_ETR:
+		tmc_etr_disable_hw(drvdata);
+		break;
+	default:
+		goto err;
 	}
+
 out:
 	drvdata->reading = false;
-	spin_unlock_irqrestore(&drvdata->spinlock, flags);
-
 	dev_info(drvdata->dev, "TMC read end\n");
+err:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 }
 
 static int tmc_open(struct inode *inode, struct file *file)
-- 
2.5.0

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

* [PATCH V2 04/15] coresight: tmc: introducing new header file
  2016-04-12 17:54 ` Mathieu Poirier
@ 2016-04-12 17:54   ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

The amount of #define, enumeration and structure definition
is big enough to justify moving them to a new header file.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc.c | 102 +----------------------
 drivers/hwtracing/coresight/coresight-tmc.h | 122 ++++++++++++++++++++++++++++
 2 files changed, 123 insertions(+), 101 deletions(-)
 create mode 100644 drivers/hwtracing/coresight/coresight-tmc.h

diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index d211aeec49f8..01a7ce2974f7 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -30,107 +30,7 @@
 #include <linux/amba/bus.h>
 
 #include "coresight-priv.h"
-
-#define TMC_RSZ			0x004
-#define TMC_STS			0x00c
-#define TMC_RRD			0x010
-#define TMC_RRP			0x014
-#define TMC_RWP			0x018
-#define TMC_TRG			0x01c
-#define TMC_CTL			0x020
-#define TMC_RWD			0x024
-#define TMC_MODE		0x028
-#define TMC_LBUFLEVEL		0x02c
-#define TMC_CBUFLEVEL		0x030
-#define TMC_BUFWM		0x034
-#define TMC_RRPHI		0x038
-#define TMC_RWPHI		0x03c
-#define TMC_AXICTL		0x110
-#define TMC_DBALO		0x118
-#define TMC_DBAHI		0x11c
-#define TMC_FFSR		0x300
-#define TMC_FFCR		0x304
-#define TMC_PSCR		0x308
-#define TMC_ITMISCOP0		0xee0
-#define TMC_ITTRFLIN		0xee8
-#define TMC_ITATBDATA0		0xeec
-#define TMC_ITATBCTR2		0xef0
-#define TMC_ITATBCTR1		0xef4
-#define TMC_ITATBCTR0		0xef8
-
-/* register description */
-/* TMC_CTL - 0x020 */
-#define TMC_CTL_CAPT_EN		BIT(0)
-/* TMC_STS - 0x00C */
-#define TMC_STS_TRIGGERED	BIT(1)
-/* TMC_AXICTL - 0x110 */
-#define TMC_AXICTL_PROT_CTL_B0	BIT(0)
-#define TMC_AXICTL_PROT_CTL_B1	BIT(1)
-#define TMC_AXICTL_SCT_GAT_MODE	BIT(7)
-#define TMC_AXICTL_WR_BURST_LEN 0xF00
-/* TMC_FFCR - 0x304 */
-#define TMC_FFCR_EN_FMT		BIT(0)
-#define TMC_FFCR_EN_TI		BIT(1)
-#define TMC_FFCR_FON_FLIN	BIT(4)
-#define TMC_FFCR_FON_TRIG_EVT	BIT(5)
-#define TMC_FFCR_FLUSHMAN	BIT(6)
-#define TMC_FFCR_TRIGON_TRIGIN	BIT(8)
-#define TMC_FFCR_STOP_ON_FLUSH	BIT(12)
-
-#define TMC_STS_TMCREADY_BIT	2
-#define TMC_FFCR_FLUSHMAN_BIT	6
-
-enum tmc_config_type {
-	TMC_CONFIG_TYPE_ETB,
-	TMC_CONFIG_TYPE_ETR,
-	TMC_CONFIG_TYPE_ETF,
-};
-
-enum tmc_mode {
-	TMC_MODE_CIRCULAR_BUFFER,
-	TMC_MODE_SOFTWARE_FIFO,
-	TMC_MODE_HARDWARE_FIFO,
-};
-
-enum tmc_mem_intf_width {
-	TMC_MEM_INTF_WIDTH_32BITS	= 0x2,
-	TMC_MEM_INTF_WIDTH_64BITS	= 0x3,
-	TMC_MEM_INTF_WIDTH_128BITS	= 0x4,
-	TMC_MEM_INTF_WIDTH_256BITS	= 0x5,
-};
-
-/**
- * struct tmc_drvdata - specifics associated to an TMC component
- * @base:	memory mapped base address for this component.
- * @dev:	the device entity associated to this component.
- * @csdev:	component vitals needed by the framework.
- * @miscdev:	specifics to handle "/dev/xyz.tmc" entry.
- * @spinlock:	only one at a time pls.
- * @read_count:	manages preparation of buffer for reading.
- * @buf:	area of memory where trace data get sent.
- * @paddr:	DMA start location in RAM.
- * @vaddr:	virtual representation of @paddr.
- * @size:	@buf size.
- * @enable:	this TMC is being used.
- * @config_type: TMC variant, must be of type @tmc_config_type.
- * @trigger_cntr: amount of words to store after a trigger.
- */
-struct tmc_drvdata {
-	void __iomem		*base;
-	struct device		*dev;
-	struct coresight_device	*csdev;
-	struct miscdevice	miscdev;
-	spinlock_t		spinlock;
-	int			read_count;
-	bool			reading;
-	char			*buf;
-	dma_addr_t		paddr;
-	void			*vaddr;
-	u32			size;
-	bool			enable;
-	enum tmc_config_type	config_type;
-	u32			trigger_cntr;
-};
+#include "coresight-tmc.h"
 
 static void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
 {
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
new file mode 100644
index 000000000000..2d7d52747b4e
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright(C) 2015 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CORESIGHT_TMC_H
+#define _CORESIGHT_TMC_H
+
+#define TMC_RSZ			0x004
+#define TMC_STS			0x00c
+#define TMC_RRD			0x010
+#define TMC_RRP			0x014
+#define TMC_RWP			0x018
+#define TMC_TRG			0x01c
+#define TMC_CTL			0x020
+#define TMC_RWD			0x024
+#define TMC_MODE		0x028
+#define TMC_LBUFLEVEL		0x02c
+#define TMC_CBUFLEVEL		0x030
+#define TMC_BUFWM		0x034
+#define TMC_RRPHI		0x038
+#define TMC_RWPHI		0x03c
+#define TMC_AXICTL		0x110
+#define TMC_DBALO		0x118
+#define TMC_DBAHI		0x11c
+#define TMC_FFSR		0x300
+#define TMC_FFCR		0x304
+#define TMC_PSCR		0x308
+#define TMC_ITMISCOP0		0xee0
+#define TMC_ITTRFLIN		0xee8
+#define TMC_ITATBDATA0		0xeec
+#define TMC_ITATBCTR2		0xef0
+#define TMC_ITATBCTR1		0xef4
+#define TMC_ITATBCTR0		0xef8
+
+/* register description */
+/* TMC_CTL - 0x020 */
+#define TMC_CTL_CAPT_EN		BIT(0)
+/* TMC_STS - 0x00C */
+#define TMC_STS_TRIGGERED	BIT(1)
+/* TMC_AXICTL - 0x110 */
+#define TMC_AXICTL_PROT_CTL_B0	BIT(0)
+#define TMC_AXICTL_PROT_CTL_B1	BIT(1)
+#define TMC_AXICTL_SCT_GAT_MODE	BIT(7)
+#define TMC_AXICTL_WR_BURST_LEN 0xF00
+/* TMC_FFCR - 0x304 */
+#define TMC_FFCR_EN_FMT		BIT(0)
+#define TMC_FFCR_EN_TI		BIT(1)
+#define TMC_FFCR_FON_FLIN	BIT(4)
+#define TMC_FFCR_FON_TRIG_EVT	BIT(5)
+#define TMC_FFCR_FLUSHMAN	BIT(6)
+#define TMC_FFCR_TRIGON_TRIGIN	BIT(8)
+#define TMC_FFCR_STOP_ON_FLUSH	BIT(12)
+
+#define TMC_STS_TMCREADY_BIT	2
+#define TMC_FFCR_FLUSHMAN_BIT	6
+
+enum tmc_config_type {
+	TMC_CONFIG_TYPE_ETB,
+	TMC_CONFIG_TYPE_ETR,
+	TMC_CONFIG_TYPE_ETF,
+};
+
+enum tmc_mode {
+	TMC_MODE_CIRCULAR_BUFFER,
+	TMC_MODE_SOFTWARE_FIFO,
+	TMC_MODE_HARDWARE_FIFO,
+};
+
+enum tmc_mem_intf_width {
+	TMC_MEM_INTF_WIDTH_32BITS	= 0x2,
+	TMC_MEM_INTF_WIDTH_64BITS	= 0x3,
+	TMC_MEM_INTF_WIDTH_128BITS	= 0x4,
+	TMC_MEM_INTF_WIDTH_256BITS	= 0x5,
+};
+
+/**
+ * struct tmc_drvdata - specifics associated to an TMC component
+ * @base:	memory mapped base address for this component.
+ * @dev:	the device entity associated to this component.
+ * @csdev:	component vitals needed by the framework.
+ * @miscdev:	specifics to handle "/dev/xyz.tmc" entry.
+ * @spinlock:	only one at a time pls.
+ * @read_count:	manages preparation of buffer for reading.
+ * @buf:	area of memory where trace data get sent.
+ * @paddr:	DMA start location in RAM.
+ * @vaddr:	virtual representation of @paddr.
+ * @size:	@buf size.
+ * @enable:	this TMC is being used.
+ * @config_type: TMC variant, must be of type @tmc_config_type.
+ * @trigger_cntr: amount of words to store after a trigger.
+ */
+struct tmc_drvdata {
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+	struct miscdevice	miscdev;
+	spinlock_t		spinlock;
+	int			read_count;
+	bool			reading;
+	char			*buf;
+	dma_addr_t		paddr;
+	void __iomem		*vaddr;
+	u32			size;
+	bool			enable;
+	enum tmc_config_type	config_type;
+	u32			trigger_cntr;
+};
+
+#endif
-- 
2.5.0

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

* [PATCH V2 04/15] coresight: tmc: introducing new header file
@ 2016-04-12 17:54   ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

The amount of #define, enumeration and structure definition
is big enough to justify moving them to a new header file.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc.c | 102 +----------------------
 drivers/hwtracing/coresight/coresight-tmc.h | 122 ++++++++++++++++++++++++++++
 2 files changed, 123 insertions(+), 101 deletions(-)
 create mode 100644 drivers/hwtracing/coresight/coresight-tmc.h

diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index d211aeec49f8..01a7ce2974f7 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -30,107 +30,7 @@
 #include <linux/amba/bus.h>
 
 #include "coresight-priv.h"
-
-#define TMC_RSZ			0x004
-#define TMC_STS			0x00c
-#define TMC_RRD			0x010
-#define TMC_RRP			0x014
-#define TMC_RWP			0x018
-#define TMC_TRG			0x01c
-#define TMC_CTL			0x020
-#define TMC_RWD			0x024
-#define TMC_MODE		0x028
-#define TMC_LBUFLEVEL		0x02c
-#define TMC_CBUFLEVEL		0x030
-#define TMC_BUFWM		0x034
-#define TMC_RRPHI		0x038
-#define TMC_RWPHI		0x03c
-#define TMC_AXICTL		0x110
-#define TMC_DBALO		0x118
-#define TMC_DBAHI		0x11c
-#define TMC_FFSR		0x300
-#define TMC_FFCR		0x304
-#define TMC_PSCR		0x308
-#define TMC_ITMISCOP0		0xee0
-#define TMC_ITTRFLIN		0xee8
-#define TMC_ITATBDATA0		0xeec
-#define TMC_ITATBCTR2		0xef0
-#define TMC_ITATBCTR1		0xef4
-#define TMC_ITATBCTR0		0xef8
-
-/* register description */
-/* TMC_CTL - 0x020 */
-#define TMC_CTL_CAPT_EN		BIT(0)
-/* TMC_STS - 0x00C */
-#define TMC_STS_TRIGGERED	BIT(1)
-/* TMC_AXICTL - 0x110 */
-#define TMC_AXICTL_PROT_CTL_B0	BIT(0)
-#define TMC_AXICTL_PROT_CTL_B1	BIT(1)
-#define TMC_AXICTL_SCT_GAT_MODE	BIT(7)
-#define TMC_AXICTL_WR_BURST_LEN 0xF00
-/* TMC_FFCR - 0x304 */
-#define TMC_FFCR_EN_FMT		BIT(0)
-#define TMC_FFCR_EN_TI		BIT(1)
-#define TMC_FFCR_FON_FLIN	BIT(4)
-#define TMC_FFCR_FON_TRIG_EVT	BIT(5)
-#define TMC_FFCR_FLUSHMAN	BIT(6)
-#define TMC_FFCR_TRIGON_TRIGIN	BIT(8)
-#define TMC_FFCR_STOP_ON_FLUSH	BIT(12)
-
-#define TMC_STS_TMCREADY_BIT	2
-#define TMC_FFCR_FLUSHMAN_BIT	6
-
-enum tmc_config_type {
-	TMC_CONFIG_TYPE_ETB,
-	TMC_CONFIG_TYPE_ETR,
-	TMC_CONFIG_TYPE_ETF,
-};
-
-enum tmc_mode {
-	TMC_MODE_CIRCULAR_BUFFER,
-	TMC_MODE_SOFTWARE_FIFO,
-	TMC_MODE_HARDWARE_FIFO,
-};
-
-enum tmc_mem_intf_width {
-	TMC_MEM_INTF_WIDTH_32BITS	= 0x2,
-	TMC_MEM_INTF_WIDTH_64BITS	= 0x3,
-	TMC_MEM_INTF_WIDTH_128BITS	= 0x4,
-	TMC_MEM_INTF_WIDTH_256BITS	= 0x5,
-};
-
-/**
- * struct tmc_drvdata - specifics associated to an TMC component
- * @base:	memory mapped base address for this component.
- * @dev:	the device entity associated to this component.
- * @csdev:	component vitals needed by the framework.
- * @miscdev:	specifics to handle "/dev/xyz.tmc" entry.
- * @spinlock:	only one at a time pls.
- * @read_count:	manages preparation of buffer for reading.
- * @buf:	area of memory where trace data get sent.
- * @paddr:	DMA start location in RAM.
- * @vaddr:	virtual representation of @paddr.
- * @size:	@buf size.
- * @enable:	this TMC is being used.
- * @config_type: TMC variant, must be of type @tmc_config_type.
- * @trigger_cntr: amount of words to store after a trigger.
- */
-struct tmc_drvdata {
-	void __iomem		*base;
-	struct device		*dev;
-	struct coresight_device	*csdev;
-	struct miscdevice	miscdev;
-	spinlock_t		spinlock;
-	int			read_count;
-	bool			reading;
-	char			*buf;
-	dma_addr_t		paddr;
-	void			*vaddr;
-	u32			size;
-	bool			enable;
-	enum tmc_config_type	config_type;
-	u32			trigger_cntr;
-};
+#include "coresight-tmc.h"
 
 static void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
 {
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
new file mode 100644
index 000000000000..2d7d52747b4e
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright(C) 2015 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CORESIGHT_TMC_H
+#define _CORESIGHT_TMC_H
+
+#define TMC_RSZ			0x004
+#define TMC_STS			0x00c
+#define TMC_RRD			0x010
+#define TMC_RRP			0x014
+#define TMC_RWP			0x018
+#define TMC_TRG			0x01c
+#define TMC_CTL			0x020
+#define TMC_RWD			0x024
+#define TMC_MODE		0x028
+#define TMC_LBUFLEVEL		0x02c
+#define TMC_CBUFLEVEL		0x030
+#define TMC_BUFWM		0x034
+#define TMC_RRPHI		0x038
+#define TMC_RWPHI		0x03c
+#define TMC_AXICTL		0x110
+#define TMC_DBALO		0x118
+#define TMC_DBAHI		0x11c
+#define TMC_FFSR		0x300
+#define TMC_FFCR		0x304
+#define TMC_PSCR		0x308
+#define TMC_ITMISCOP0		0xee0
+#define TMC_ITTRFLIN		0xee8
+#define TMC_ITATBDATA0		0xeec
+#define TMC_ITATBCTR2		0xef0
+#define TMC_ITATBCTR1		0xef4
+#define TMC_ITATBCTR0		0xef8
+
+/* register description */
+/* TMC_CTL - 0x020 */
+#define TMC_CTL_CAPT_EN		BIT(0)
+/* TMC_STS - 0x00C */
+#define TMC_STS_TRIGGERED	BIT(1)
+/* TMC_AXICTL - 0x110 */
+#define TMC_AXICTL_PROT_CTL_B0	BIT(0)
+#define TMC_AXICTL_PROT_CTL_B1	BIT(1)
+#define TMC_AXICTL_SCT_GAT_MODE	BIT(7)
+#define TMC_AXICTL_WR_BURST_LEN 0xF00
+/* TMC_FFCR - 0x304 */
+#define TMC_FFCR_EN_FMT		BIT(0)
+#define TMC_FFCR_EN_TI		BIT(1)
+#define TMC_FFCR_FON_FLIN	BIT(4)
+#define TMC_FFCR_FON_TRIG_EVT	BIT(5)
+#define TMC_FFCR_FLUSHMAN	BIT(6)
+#define TMC_FFCR_TRIGON_TRIGIN	BIT(8)
+#define TMC_FFCR_STOP_ON_FLUSH	BIT(12)
+
+#define TMC_STS_TMCREADY_BIT	2
+#define TMC_FFCR_FLUSHMAN_BIT	6
+
+enum tmc_config_type {
+	TMC_CONFIG_TYPE_ETB,
+	TMC_CONFIG_TYPE_ETR,
+	TMC_CONFIG_TYPE_ETF,
+};
+
+enum tmc_mode {
+	TMC_MODE_CIRCULAR_BUFFER,
+	TMC_MODE_SOFTWARE_FIFO,
+	TMC_MODE_HARDWARE_FIFO,
+};
+
+enum tmc_mem_intf_width {
+	TMC_MEM_INTF_WIDTH_32BITS	= 0x2,
+	TMC_MEM_INTF_WIDTH_64BITS	= 0x3,
+	TMC_MEM_INTF_WIDTH_128BITS	= 0x4,
+	TMC_MEM_INTF_WIDTH_256BITS	= 0x5,
+};
+
+/**
+ * struct tmc_drvdata - specifics associated to an TMC component
+ * @base:	memory mapped base address for this component.
+ * @dev:	the device entity associated to this component.
+ * @csdev:	component vitals needed by the framework.
+ * @miscdev:	specifics to handle "/dev/xyz.tmc" entry.
+ * @spinlock:	only one at a time pls.
+ * @read_count:	manages preparation of buffer for reading.
+ * @buf:	area of memory where trace data get sent.
+ * @paddr:	DMA start location in RAM.
+ * @vaddr:	virtual representation of @paddr.
+ * @size:	@buf size.
+ * @enable:	this TMC is being used.
+ * @config_type: TMC variant, must be of type @tmc_config_type.
+ * @trigger_cntr: amount of words to store after a trigger.
+ */
+struct tmc_drvdata {
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+	struct miscdevice	miscdev;
+	spinlock_t		spinlock;
+	int			read_count;
+	bool			reading;
+	char			*buf;
+	dma_addr_t		paddr;
+	void __iomem		*vaddr;
+	u32			size;
+	bool			enable;
+	enum tmc_config_type	config_type;
+	u32			trigger_cntr;
+};
+
+#endif
-- 
2.5.0

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

* [PATCH V2 05/15] coresight: tmc: splitting driver in ETB/ETF and ETR components
  2016-04-12 17:54 ` Mathieu Poirier
@ 2016-04-12 17:54   ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

The TMC block can operate in 3 modes (ETB, ETF and ETR) and accessed
via two interfaces (sysFS and Perf).  That makes 6 mode to cover, which
is way too much coupling for a single file.

This patch splits the original TMC driver in 2 halves, one for ETB/ETF
and another one for ETR mode.  A common core is kept for functionality
common to all 3 modes.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/Makefile            |   4 +-
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 204 ++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 128 ++++++++++++
 drivers/hwtracing/coresight/coresight-tmc.c     | 264 +-----------------------
 drivers/hwtracing/coresight/coresight-tmc.h     |  18 ++
 5 files changed, 357 insertions(+), 261 deletions(-)
 create mode 100644 drivers/hwtracing/coresight/coresight-tmc-etf.c
 create mode 100644 drivers/hwtracing/coresight/coresight-tmc-etr.c

diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 1d0e32c7dbe4..0cf842ea3fe2 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -3,7 +3,9 @@
 #
 obj-$(CONFIG_CORESIGHT) += coresight.o coresight-etm-perf.o
 obj-$(CONFIG_OF) += of_coresight.o
-obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o
+obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o \
+					     coresight-tmc-etf.o \
+					     coresight-tmc-etr.o
 obj-$(CONFIG_CORESIGHT_SINK_TPIU) += coresight-tpiu.o
 obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o
 obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
new file mode 100644
index 000000000000..467d19221f7b
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright(C) 2016 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/coresight.h>
+#include "coresight-priv.h"
+#include "coresight-tmc.h"
+
+void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
+{
+	/* Zero out the memory to help with debug */
+	memset(drvdata->buf, 0, drvdata->size);
+
+	CS_UNLOCK(drvdata->base);
+
+	/* Wait for TMCSReady bit to be set */
+	tmc_wait_for_tmcready(drvdata);
+
+	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
+	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
+		       TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
+		       TMC_FFCR_TRIGON_TRIGIN,
+		       drvdata->base + TMC_FFCR);
+
+	writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
+	tmc_enable_hw(drvdata);
+
+	CS_LOCK(drvdata->base);
+}
+
+static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
+{
+	enum tmc_mem_intf_width memwidth;
+	u8 memwords;
+	char *bufp;
+	u32 read_data;
+	int i;
+
+	memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID), 8, 10);
+	if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
+		memwords = 1;
+	else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
+		memwords = 2;
+	else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
+		memwords = 4;
+	else
+		memwords = 8;
+
+	bufp = drvdata->buf;
+	while (1) {
+		for (i = 0; i < memwords; i++) {
+			read_data = readl_relaxed(drvdata->base + TMC_RRD);
+			if (read_data == 0xFFFFFFFF)
+				return;
+			memcpy(bufp, &read_data, 4);
+			bufp += 4;
+		}
+	}
+}
+
+void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
+{
+	CS_UNLOCK(drvdata->base);
+
+	tmc_flush_and_stop(drvdata);
+	tmc_etb_dump_hw(drvdata);
+	tmc_disable_hw(drvdata);
+
+	CS_LOCK(drvdata->base);
+}
+
+static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
+{
+	CS_UNLOCK(drvdata->base);
+
+	/* Wait for TMCSReady bit to be set */
+	tmc_wait_for_tmcready(drvdata);
+
+	writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE);
+	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI,
+		       drvdata->base + TMC_FFCR);
+	writel_relaxed(0x0, drvdata->base + TMC_BUFWM);
+	tmc_enable_hw(drvdata);
+
+	CS_LOCK(drvdata->base);
+}
+
+static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
+{
+	CS_UNLOCK(drvdata->base);
+
+	tmc_flush_and_stop(drvdata);
+	tmc_disable_hw(drvdata);
+
+	CS_LOCK(drvdata->base);
+}
+
+static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
+{
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return -EBUSY;
+	}
+
+	tmc_etb_enable_hw(drvdata);
+	drvdata->enable = true;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC-ETB/ETF enabled\n");
+	return 0;
+}
+
+static void tmc_disable_etf_sink(struct coresight_device *csdev)
+{
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return;
+	}
+
+	tmc_etb_disable_hw(drvdata);
+	drvdata->enable = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC-ETB/ETF disabled\n");
+}
+
+static int tmc_enable_etf_link(struct coresight_device *csdev,
+			       int inport, int outport)
+{
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return -EBUSY;
+	}
+
+	tmc_etf_enable_hw(drvdata);
+	drvdata->enable = true;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC-ETF enabled\n");
+	return 0;
+}
+
+static void tmc_disable_etf_link(struct coresight_device *csdev,
+				 int inport, int outport)
+{
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return;
+	}
+
+	tmc_etf_disable_hw(drvdata);
+	drvdata->enable = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC disabled\n");
+}
+
+static const struct coresight_ops_sink tmc_etf_sink_ops = {
+	.enable		= tmc_enable_etf_sink,
+	.disable	= tmc_disable_etf_sink,
+};
+
+static const struct coresight_ops_link tmc_etf_link_ops = {
+	.enable		= tmc_enable_etf_link,
+	.disable	= tmc_disable_etf_link,
+};
+
+const struct coresight_ops tmc_etb_cs_ops = {
+	.sink_ops	= &tmc_etf_sink_ops,
+};
+
+const struct coresight_ops tmc_etf_cs_ops = {
+	.sink_ops	= &tmc_etf_sink_ops,
+	.link_ops	= &tmc_etf_link_ops,
+};
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
new file mode 100644
index 000000000000..910d6f3b7d26
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright(C) 2016 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/coresight.h>
+#include "coresight-priv.h"
+#include "coresight-tmc.h"
+
+void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
+{
+	u32 axictl;
+
+	/* Zero out the memory to help with debug */
+	memset(drvdata->vaddr, 0, drvdata->size);
+
+	CS_UNLOCK(drvdata->base);
+
+	/* Wait for TMCSReady bit to be set */
+	tmc_wait_for_tmcready(drvdata);
+
+	writel_relaxed(drvdata->size / 4, drvdata->base + TMC_RSZ);
+	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
+
+	axictl = readl_relaxed(drvdata->base + TMC_AXICTL);
+	axictl |= TMC_AXICTL_WR_BURST_LEN;
+	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
+	axictl &= ~TMC_AXICTL_SCT_GAT_MODE;
+	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
+	axictl = (axictl &
+		  ~(TMC_AXICTL_PROT_CTL_B0 | TMC_AXICTL_PROT_CTL_B1)) |
+		  TMC_AXICTL_PROT_CTL_B1;
+	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
+
+	writel_relaxed(drvdata->paddr, drvdata->base + TMC_DBALO);
+	writel_relaxed(0x0, drvdata->base + TMC_DBAHI);
+	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
+		       TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
+		       TMC_FFCR_TRIGON_TRIGIN,
+		       drvdata->base + TMC_FFCR);
+	writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
+	tmc_enable_hw(drvdata);
+
+	CS_LOCK(drvdata->base);
+}
+
+static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
+{
+	u32 rwp, val;
+
+	rwp = readl_relaxed(drvdata->base + TMC_RWP);
+	val = readl_relaxed(drvdata->base + TMC_STS);
+
+	/* How much memory do we still have */
+	if (val & BIT(0))
+		drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr;
+	else
+		drvdata->buf = drvdata->vaddr;
+}
+
+void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
+{
+	CS_UNLOCK(drvdata->base);
+
+	tmc_flush_and_stop(drvdata);
+	tmc_etr_dump_hw(drvdata);
+	tmc_disable_hw(drvdata);
+
+	CS_LOCK(drvdata->base);
+}
+
+static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
+{
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return -EBUSY;
+	}
+
+	tmc_etr_enable_hw(drvdata);
+	drvdata->enable = true;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC-ETR enabled\n");
+	return 0;
+}
+
+static void tmc_disable_etr_sink(struct coresight_device *csdev)
+{
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return;
+	}
+
+	tmc_etr_disable_hw(drvdata);
+	drvdata->enable = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC-ETR disabled\n");
+}
+
+static const struct coresight_ops_sink tmc_etr_sink_ops = {
+	.enable		= tmc_enable_etr_sink,
+	.disable	= tmc_disable_etr_sink,
+};
+
+const struct coresight_ops tmc_etr_cs_ops = {
+	.sink_ops	= &tmc_etr_sink_ops,
+};
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 01a7ce2974f7..67b3cd299782 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -32,7 +32,7 @@
 #include "coresight-priv.h"
 #include "coresight-tmc.h"
 
-static void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
+void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
 {
 	/* Ensure formatter, unformatter and hardware fifo are empty */
 	if (coresight_timeout(drvdata->base,
@@ -43,7 +43,7 @@ static void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
 	}
 }
 
-static void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
+void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
 {
 	u32 ffcr;
 
@@ -63,272 +63,16 @@ static void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
 	tmc_wait_for_tmcready(drvdata);
 }
 
-static void tmc_enable_hw(struct tmc_drvdata *drvdata)
+void tmc_enable_hw(struct tmc_drvdata *drvdata)
 {
 	writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL);
 }
 
-static void tmc_disable_hw(struct tmc_drvdata *drvdata)
+void tmc_disable_hw(struct tmc_drvdata *drvdata)
 {
 	writel_relaxed(0x0, drvdata->base + TMC_CTL);
 }
 
-static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
-{
-	/* Zero out the memory to help with debug */
-	memset(drvdata->buf, 0, drvdata->size);
-
-	CS_UNLOCK(drvdata->base);
-
-	/* Wait for TMCSReady bit to be set */
-	tmc_wait_for_tmcready(drvdata);
-
-	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
-	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
-		       TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
-		       TMC_FFCR_TRIGON_TRIGIN,
-		       drvdata->base + TMC_FFCR);
-
-	writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
-	tmc_enable_hw(drvdata);
-
-	CS_LOCK(drvdata->base);
-}
-
-static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
-{
-	u32 axictl;
-
-	/* Zero out the memory to help with debug */
-	memset(drvdata->vaddr, 0, drvdata->size);
-
-	CS_UNLOCK(drvdata->base);
-
-	/* Wait for TMCSReady bit to be set */
-	tmc_wait_for_tmcready(drvdata);
-
-	writel_relaxed(drvdata->size / 4, drvdata->base + TMC_RSZ);
-	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
-
-	axictl = readl_relaxed(drvdata->base + TMC_AXICTL);
-	axictl |= TMC_AXICTL_WR_BURST_LEN;
-	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
-	axictl &= ~TMC_AXICTL_SCT_GAT_MODE;
-	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
-	axictl = (axictl &
-		  ~(TMC_AXICTL_PROT_CTL_B0 | TMC_AXICTL_PROT_CTL_B1)) |
-		  TMC_AXICTL_PROT_CTL_B1;
-	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
-
-	writel_relaxed(drvdata->paddr, drvdata->base + TMC_DBALO);
-	writel_relaxed(0x0, drvdata->base + TMC_DBAHI);
-	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
-		       TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
-		       TMC_FFCR_TRIGON_TRIGIN,
-		       drvdata->base + TMC_FFCR);
-	writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
-	tmc_enable_hw(drvdata);
-
-	CS_LOCK(drvdata->base);
-}
-
-static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
-{
-	CS_UNLOCK(drvdata->base);
-
-	/* Wait for TMCSReady bit to be set */
-	tmc_wait_for_tmcready(drvdata);
-
-	writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE);
-	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI,
-		       drvdata->base + TMC_FFCR);
-	writel_relaxed(0x0, drvdata->base + TMC_BUFWM);
-	tmc_enable_hw(drvdata);
-
-	CS_LOCK(drvdata->base);
-}
-
-static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&drvdata->spinlock, flags);
-	if (drvdata->reading) {
-		spin_unlock_irqrestore(&drvdata->spinlock, flags);
-		return -EBUSY;
-	}
-
-	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
-		tmc_etb_enable_hw(drvdata);
-	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		tmc_etr_enable_hw(drvdata);
-	} else {
-		if (mode == TMC_MODE_CIRCULAR_BUFFER)
-			tmc_etb_enable_hw(drvdata);
-		else
-			tmc_etf_enable_hw(drvdata);
-	}
-	drvdata->enable = true;
-	spin_unlock_irqrestore(&drvdata->spinlock, flags);
-
-	dev_info(drvdata->dev, "TMC enabled\n");
-	return 0;
-}
-
-static int tmc_enable_sink(struct coresight_device *csdev, u32 mode)
-{
-	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-
-	return tmc_enable(drvdata, TMC_MODE_CIRCULAR_BUFFER);
-}
-
-static int tmc_enable_link(struct coresight_device *csdev, int inport,
-			   int outport)
-{
-	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-
-	return tmc_enable(drvdata, TMC_MODE_HARDWARE_FIFO);
-}
-
-static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
-{
-	enum tmc_mem_intf_width memwidth;
-	u8 memwords;
-	char *bufp;
-	u32 read_data;
-	int i;
-
-	memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID), 8, 10);
-	if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
-		memwords = 1;
-	else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
-		memwords = 2;
-	else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
-		memwords = 4;
-	else
-		memwords = 8;
-
-	bufp = drvdata->buf;
-	while (1) {
-		for (i = 0; i < memwords; i++) {
-			read_data = readl_relaxed(drvdata->base + TMC_RRD);
-			if (read_data == 0xFFFFFFFF)
-				return;
-			memcpy(bufp, &read_data, 4);
-			bufp += 4;
-		}
-	}
-}
-
-static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
-{
-	CS_UNLOCK(drvdata->base);
-
-	tmc_flush_and_stop(drvdata);
-	tmc_etb_dump_hw(drvdata);
-	tmc_disable_hw(drvdata);
-
-	CS_LOCK(drvdata->base);
-}
-
-static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
-{
-	u32 rwp, val;
-
-	rwp = readl_relaxed(drvdata->base + TMC_RWP);
-	val = readl_relaxed(drvdata->base + TMC_STS);
-
-	/* How much memory do we still have */
-	if (val & BIT(0))
-		drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr;
-	else
-		drvdata->buf = drvdata->vaddr;
-}
-
-static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
-{
-	CS_UNLOCK(drvdata->base);
-
-	tmc_flush_and_stop(drvdata);
-	tmc_etr_dump_hw(drvdata);
-	tmc_disable_hw(drvdata);
-
-	CS_LOCK(drvdata->base);
-}
-
-static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
-{
-	CS_UNLOCK(drvdata->base);
-
-	tmc_flush_and_stop(drvdata);
-	tmc_disable_hw(drvdata);
-
-	CS_LOCK(drvdata->base);
-}
-
-static void tmc_disable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&drvdata->spinlock, flags);
-	if (drvdata->reading)
-		goto out;
-
-	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
-		tmc_etb_disable_hw(drvdata);
-	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		tmc_etr_disable_hw(drvdata);
-	} else {
-		if (mode == TMC_MODE_CIRCULAR_BUFFER)
-			tmc_etb_disable_hw(drvdata);
-		else
-			tmc_etf_disable_hw(drvdata);
-	}
-out:
-	drvdata->enable = false;
-	spin_unlock_irqrestore(&drvdata->spinlock, flags);
-
-	dev_info(drvdata->dev, "TMC disabled\n");
-}
-
-static void tmc_disable_sink(struct coresight_device *csdev)
-{
-	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-
-	tmc_disable(drvdata, TMC_MODE_CIRCULAR_BUFFER);
-}
-
-static void tmc_disable_link(struct coresight_device *csdev, int inport,
-			     int outport)
-{
-	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-
-	tmc_disable(drvdata, TMC_MODE_HARDWARE_FIFO);
-}
-
-static const struct coresight_ops_sink tmc_sink_ops = {
-	.enable		= tmc_enable_sink,
-	.disable	= tmc_disable_sink,
-};
-
-static const struct coresight_ops_link tmc_link_ops = {
-	.enable		= tmc_enable_link,
-	.disable	= tmc_disable_link,
-};
-
-static const struct coresight_ops tmc_etb_cs_ops = {
-	.sink_ops	= &tmc_sink_ops,
-};
-
-static const struct coresight_ops tmc_etr_cs_ops = {
-	.sink_ops	= &tmc_sink_ops,
-};
-
-static const struct coresight_ops tmc_etf_cs_ops = {
-	.sink_ops	= &tmc_sink_ops,
-	.link_ops	= &tmc_link_ops,
-};
-
 static int tmc_read_prepare(struct tmc_drvdata *drvdata)
 {
 	int ret = 0;
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 2d7d52747b4e..b99d4dfc1d0b 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -18,6 +18,8 @@
 #ifndef _CORESIGHT_TMC_H
 #define _CORESIGHT_TMC_H
 
+#include <linux/miscdevice.h>
+
 #define TMC_RSZ			0x004
 #define TMC_STS			0x00c
 #define TMC_RRD			0x010
@@ -119,4 +121,20 @@ struct tmc_drvdata {
 	u32			trigger_cntr;
 };
 
+/* Generic functions */
+void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata);
+void tmc_flush_and_stop(struct tmc_drvdata *drvdata);
+void tmc_enable_hw(struct tmc_drvdata *drvdata);
+void tmc_disable_hw(struct tmc_drvdata *drvdata);
+
+/* ETB/ETF functions */
+void tmc_etb_enable_hw(struct tmc_drvdata *drvdata);
+void tmc_etb_disable_hw(struct tmc_drvdata *drvdata);
+extern const struct coresight_ops tmc_etb_cs_ops;
+extern const struct coresight_ops tmc_etf_cs_ops;
+
+/* ETR functions */
+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;
 #endif
-- 
2.5.0

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

* [PATCH V2 05/15] coresight: tmc: splitting driver in ETB/ETF and ETR components
@ 2016-04-12 17:54   ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

The TMC block can operate in 3 modes (ETB, ETF and ETR) and accessed
via two interfaces (sysFS and Perf).  That makes 6 mode to cover, which
is way too much coupling for a single file.

This patch splits the original TMC driver in 2 halves, one for ETB/ETF
and another one for ETR mode.  A common core is kept for functionality
common to all 3 modes.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/Makefile            |   4 +-
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 204 ++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 128 ++++++++++++
 drivers/hwtracing/coresight/coresight-tmc.c     | 264 +-----------------------
 drivers/hwtracing/coresight/coresight-tmc.h     |  18 ++
 5 files changed, 357 insertions(+), 261 deletions(-)
 create mode 100644 drivers/hwtracing/coresight/coresight-tmc-etf.c
 create mode 100644 drivers/hwtracing/coresight/coresight-tmc-etr.c

diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 1d0e32c7dbe4..0cf842ea3fe2 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -3,7 +3,9 @@
 #
 obj-$(CONFIG_CORESIGHT) += coresight.o coresight-etm-perf.o
 obj-$(CONFIG_OF) += of_coresight.o
-obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o
+obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o \
+					     coresight-tmc-etf.o \
+					     coresight-tmc-etr.o
 obj-$(CONFIG_CORESIGHT_SINK_TPIU) += coresight-tpiu.o
 obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o
 obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
new file mode 100644
index 000000000000..467d19221f7b
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright(C) 2016 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/coresight.h>
+#include "coresight-priv.h"
+#include "coresight-tmc.h"
+
+void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
+{
+	/* Zero out the memory to help with debug */
+	memset(drvdata->buf, 0, drvdata->size);
+
+	CS_UNLOCK(drvdata->base);
+
+	/* Wait for TMCSReady bit to be set */
+	tmc_wait_for_tmcready(drvdata);
+
+	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
+	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
+		       TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
+		       TMC_FFCR_TRIGON_TRIGIN,
+		       drvdata->base + TMC_FFCR);
+
+	writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
+	tmc_enable_hw(drvdata);
+
+	CS_LOCK(drvdata->base);
+}
+
+static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
+{
+	enum tmc_mem_intf_width memwidth;
+	u8 memwords;
+	char *bufp;
+	u32 read_data;
+	int i;
+
+	memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID), 8, 10);
+	if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
+		memwords = 1;
+	else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
+		memwords = 2;
+	else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
+		memwords = 4;
+	else
+		memwords = 8;
+
+	bufp = drvdata->buf;
+	while (1) {
+		for (i = 0; i < memwords; i++) {
+			read_data = readl_relaxed(drvdata->base + TMC_RRD);
+			if (read_data == 0xFFFFFFFF)
+				return;
+			memcpy(bufp, &read_data, 4);
+			bufp += 4;
+		}
+	}
+}
+
+void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
+{
+	CS_UNLOCK(drvdata->base);
+
+	tmc_flush_and_stop(drvdata);
+	tmc_etb_dump_hw(drvdata);
+	tmc_disable_hw(drvdata);
+
+	CS_LOCK(drvdata->base);
+}
+
+static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
+{
+	CS_UNLOCK(drvdata->base);
+
+	/* Wait for TMCSReady bit to be set */
+	tmc_wait_for_tmcready(drvdata);
+
+	writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE);
+	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI,
+		       drvdata->base + TMC_FFCR);
+	writel_relaxed(0x0, drvdata->base + TMC_BUFWM);
+	tmc_enable_hw(drvdata);
+
+	CS_LOCK(drvdata->base);
+}
+
+static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
+{
+	CS_UNLOCK(drvdata->base);
+
+	tmc_flush_and_stop(drvdata);
+	tmc_disable_hw(drvdata);
+
+	CS_LOCK(drvdata->base);
+}
+
+static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
+{
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return -EBUSY;
+	}
+
+	tmc_etb_enable_hw(drvdata);
+	drvdata->enable = true;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC-ETB/ETF enabled\n");
+	return 0;
+}
+
+static void tmc_disable_etf_sink(struct coresight_device *csdev)
+{
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return;
+	}
+
+	tmc_etb_disable_hw(drvdata);
+	drvdata->enable = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC-ETB/ETF disabled\n");
+}
+
+static int tmc_enable_etf_link(struct coresight_device *csdev,
+			       int inport, int outport)
+{
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return -EBUSY;
+	}
+
+	tmc_etf_enable_hw(drvdata);
+	drvdata->enable = true;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC-ETF enabled\n");
+	return 0;
+}
+
+static void tmc_disable_etf_link(struct coresight_device *csdev,
+				 int inport, int outport)
+{
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return;
+	}
+
+	tmc_etf_disable_hw(drvdata);
+	drvdata->enable = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC disabled\n");
+}
+
+static const struct coresight_ops_sink tmc_etf_sink_ops = {
+	.enable		= tmc_enable_etf_sink,
+	.disable	= tmc_disable_etf_sink,
+};
+
+static const struct coresight_ops_link tmc_etf_link_ops = {
+	.enable		= tmc_enable_etf_link,
+	.disable	= tmc_disable_etf_link,
+};
+
+const struct coresight_ops tmc_etb_cs_ops = {
+	.sink_ops	= &tmc_etf_sink_ops,
+};
+
+const struct coresight_ops tmc_etf_cs_ops = {
+	.sink_ops	= &tmc_etf_sink_ops,
+	.link_ops	= &tmc_etf_link_ops,
+};
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
new file mode 100644
index 000000000000..910d6f3b7d26
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright(C) 2016 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/coresight.h>
+#include "coresight-priv.h"
+#include "coresight-tmc.h"
+
+void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
+{
+	u32 axictl;
+
+	/* Zero out the memory to help with debug */
+	memset(drvdata->vaddr, 0, drvdata->size);
+
+	CS_UNLOCK(drvdata->base);
+
+	/* Wait for TMCSReady bit to be set */
+	tmc_wait_for_tmcready(drvdata);
+
+	writel_relaxed(drvdata->size / 4, drvdata->base + TMC_RSZ);
+	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
+
+	axictl = readl_relaxed(drvdata->base + TMC_AXICTL);
+	axictl |= TMC_AXICTL_WR_BURST_LEN;
+	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
+	axictl &= ~TMC_AXICTL_SCT_GAT_MODE;
+	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
+	axictl = (axictl &
+		  ~(TMC_AXICTL_PROT_CTL_B0 | TMC_AXICTL_PROT_CTL_B1)) |
+		  TMC_AXICTL_PROT_CTL_B1;
+	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
+
+	writel_relaxed(drvdata->paddr, drvdata->base + TMC_DBALO);
+	writel_relaxed(0x0, drvdata->base + TMC_DBAHI);
+	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
+		       TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
+		       TMC_FFCR_TRIGON_TRIGIN,
+		       drvdata->base + TMC_FFCR);
+	writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
+	tmc_enable_hw(drvdata);
+
+	CS_LOCK(drvdata->base);
+}
+
+static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
+{
+	u32 rwp, val;
+
+	rwp = readl_relaxed(drvdata->base + TMC_RWP);
+	val = readl_relaxed(drvdata->base + TMC_STS);
+
+	/* How much memory do we still have */
+	if (val & BIT(0))
+		drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr;
+	else
+		drvdata->buf = drvdata->vaddr;
+}
+
+void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
+{
+	CS_UNLOCK(drvdata->base);
+
+	tmc_flush_and_stop(drvdata);
+	tmc_etr_dump_hw(drvdata);
+	tmc_disable_hw(drvdata);
+
+	CS_LOCK(drvdata->base);
+}
+
+static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
+{
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return -EBUSY;
+	}
+
+	tmc_etr_enable_hw(drvdata);
+	drvdata->enable = true;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC-ETR enabled\n");
+	return 0;
+}
+
+static void tmc_disable_etr_sink(struct coresight_device *csdev)
+{
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return;
+	}
+
+	tmc_etr_disable_hw(drvdata);
+	drvdata->enable = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC-ETR disabled\n");
+}
+
+static const struct coresight_ops_sink tmc_etr_sink_ops = {
+	.enable		= tmc_enable_etr_sink,
+	.disable	= tmc_disable_etr_sink,
+};
+
+const struct coresight_ops tmc_etr_cs_ops = {
+	.sink_ops	= &tmc_etr_sink_ops,
+};
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 01a7ce2974f7..67b3cd299782 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -32,7 +32,7 @@
 #include "coresight-priv.h"
 #include "coresight-tmc.h"
 
-static void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
+void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
 {
 	/* Ensure formatter, unformatter and hardware fifo are empty */
 	if (coresight_timeout(drvdata->base,
@@ -43,7 +43,7 @@ static void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
 	}
 }
 
-static void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
+void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
 {
 	u32 ffcr;
 
@@ -63,272 +63,16 @@ static void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
 	tmc_wait_for_tmcready(drvdata);
 }
 
-static void tmc_enable_hw(struct tmc_drvdata *drvdata)
+void tmc_enable_hw(struct tmc_drvdata *drvdata)
 {
 	writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL);
 }
 
-static void tmc_disable_hw(struct tmc_drvdata *drvdata)
+void tmc_disable_hw(struct tmc_drvdata *drvdata)
 {
 	writel_relaxed(0x0, drvdata->base + TMC_CTL);
 }
 
-static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
-{
-	/* Zero out the memory to help with debug */
-	memset(drvdata->buf, 0, drvdata->size);
-
-	CS_UNLOCK(drvdata->base);
-
-	/* Wait for TMCSReady bit to be set */
-	tmc_wait_for_tmcready(drvdata);
-
-	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
-	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
-		       TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
-		       TMC_FFCR_TRIGON_TRIGIN,
-		       drvdata->base + TMC_FFCR);
-
-	writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
-	tmc_enable_hw(drvdata);
-
-	CS_LOCK(drvdata->base);
-}
-
-static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
-{
-	u32 axictl;
-
-	/* Zero out the memory to help with debug */
-	memset(drvdata->vaddr, 0, drvdata->size);
-
-	CS_UNLOCK(drvdata->base);
-
-	/* Wait for TMCSReady bit to be set */
-	tmc_wait_for_tmcready(drvdata);
-
-	writel_relaxed(drvdata->size / 4, drvdata->base + TMC_RSZ);
-	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
-
-	axictl = readl_relaxed(drvdata->base + TMC_AXICTL);
-	axictl |= TMC_AXICTL_WR_BURST_LEN;
-	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
-	axictl &= ~TMC_AXICTL_SCT_GAT_MODE;
-	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
-	axictl = (axictl &
-		  ~(TMC_AXICTL_PROT_CTL_B0 | TMC_AXICTL_PROT_CTL_B1)) |
-		  TMC_AXICTL_PROT_CTL_B1;
-	writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
-
-	writel_relaxed(drvdata->paddr, drvdata->base + TMC_DBALO);
-	writel_relaxed(0x0, drvdata->base + TMC_DBAHI);
-	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
-		       TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
-		       TMC_FFCR_TRIGON_TRIGIN,
-		       drvdata->base + TMC_FFCR);
-	writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
-	tmc_enable_hw(drvdata);
-
-	CS_LOCK(drvdata->base);
-}
-
-static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
-{
-	CS_UNLOCK(drvdata->base);
-
-	/* Wait for TMCSReady bit to be set */
-	tmc_wait_for_tmcready(drvdata);
-
-	writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE);
-	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI,
-		       drvdata->base + TMC_FFCR);
-	writel_relaxed(0x0, drvdata->base + TMC_BUFWM);
-	tmc_enable_hw(drvdata);
-
-	CS_LOCK(drvdata->base);
-}
-
-static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&drvdata->spinlock, flags);
-	if (drvdata->reading) {
-		spin_unlock_irqrestore(&drvdata->spinlock, flags);
-		return -EBUSY;
-	}
-
-	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
-		tmc_etb_enable_hw(drvdata);
-	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		tmc_etr_enable_hw(drvdata);
-	} else {
-		if (mode == TMC_MODE_CIRCULAR_BUFFER)
-			tmc_etb_enable_hw(drvdata);
-		else
-			tmc_etf_enable_hw(drvdata);
-	}
-	drvdata->enable = true;
-	spin_unlock_irqrestore(&drvdata->spinlock, flags);
-
-	dev_info(drvdata->dev, "TMC enabled\n");
-	return 0;
-}
-
-static int tmc_enable_sink(struct coresight_device *csdev, u32 mode)
-{
-	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-
-	return tmc_enable(drvdata, TMC_MODE_CIRCULAR_BUFFER);
-}
-
-static int tmc_enable_link(struct coresight_device *csdev, int inport,
-			   int outport)
-{
-	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-
-	return tmc_enable(drvdata, TMC_MODE_HARDWARE_FIFO);
-}
-
-static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
-{
-	enum tmc_mem_intf_width memwidth;
-	u8 memwords;
-	char *bufp;
-	u32 read_data;
-	int i;
-
-	memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID), 8, 10);
-	if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
-		memwords = 1;
-	else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
-		memwords = 2;
-	else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
-		memwords = 4;
-	else
-		memwords = 8;
-
-	bufp = drvdata->buf;
-	while (1) {
-		for (i = 0; i < memwords; i++) {
-			read_data = readl_relaxed(drvdata->base + TMC_RRD);
-			if (read_data == 0xFFFFFFFF)
-				return;
-			memcpy(bufp, &read_data, 4);
-			bufp += 4;
-		}
-	}
-}
-
-static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
-{
-	CS_UNLOCK(drvdata->base);
-
-	tmc_flush_and_stop(drvdata);
-	tmc_etb_dump_hw(drvdata);
-	tmc_disable_hw(drvdata);
-
-	CS_LOCK(drvdata->base);
-}
-
-static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
-{
-	u32 rwp, val;
-
-	rwp = readl_relaxed(drvdata->base + TMC_RWP);
-	val = readl_relaxed(drvdata->base + TMC_STS);
-
-	/* How much memory do we still have */
-	if (val & BIT(0))
-		drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr;
-	else
-		drvdata->buf = drvdata->vaddr;
-}
-
-static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
-{
-	CS_UNLOCK(drvdata->base);
-
-	tmc_flush_and_stop(drvdata);
-	tmc_etr_dump_hw(drvdata);
-	tmc_disable_hw(drvdata);
-
-	CS_LOCK(drvdata->base);
-}
-
-static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
-{
-	CS_UNLOCK(drvdata->base);
-
-	tmc_flush_and_stop(drvdata);
-	tmc_disable_hw(drvdata);
-
-	CS_LOCK(drvdata->base);
-}
-
-static void tmc_disable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&drvdata->spinlock, flags);
-	if (drvdata->reading)
-		goto out;
-
-	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
-		tmc_etb_disable_hw(drvdata);
-	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		tmc_etr_disable_hw(drvdata);
-	} else {
-		if (mode == TMC_MODE_CIRCULAR_BUFFER)
-			tmc_etb_disable_hw(drvdata);
-		else
-			tmc_etf_disable_hw(drvdata);
-	}
-out:
-	drvdata->enable = false;
-	spin_unlock_irqrestore(&drvdata->spinlock, flags);
-
-	dev_info(drvdata->dev, "TMC disabled\n");
-}
-
-static void tmc_disable_sink(struct coresight_device *csdev)
-{
-	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-
-	tmc_disable(drvdata, TMC_MODE_CIRCULAR_BUFFER);
-}
-
-static void tmc_disable_link(struct coresight_device *csdev, int inport,
-			     int outport)
-{
-	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-
-	tmc_disable(drvdata, TMC_MODE_HARDWARE_FIFO);
-}
-
-static const struct coresight_ops_sink tmc_sink_ops = {
-	.enable		= tmc_enable_sink,
-	.disable	= tmc_disable_sink,
-};
-
-static const struct coresight_ops_link tmc_link_ops = {
-	.enable		= tmc_enable_link,
-	.disable	= tmc_disable_link,
-};
-
-static const struct coresight_ops tmc_etb_cs_ops = {
-	.sink_ops	= &tmc_sink_ops,
-};
-
-static const struct coresight_ops tmc_etr_cs_ops = {
-	.sink_ops	= &tmc_sink_ops,
-};
-
-static const struct coresight_ops tmc_etf_cs_ops = {
-	.sink_ops	= &tmc_sink_ops,
-	.link_ops	= &tmc_link_ops,
-};
-
 static int tmc_read_prepare(struct tmc_drvdata *drvdata)
 {
 	int ret = 0;
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 2d7d52747b4e..b99d4dfc1d0b 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -18,6 +18,8 @@
 #ifndef _CORESIGHT_TMC_H
 #define _CORESIGHT_TMC_H
 
+#include <linux/miscdevice.h>
+
 #define TMC_RSZ			0x004
 #define TMC_STS			0x00c
 #define TMC_RRD			0x010
@@ -119,4 +121,20 @@ struct tmc_drvdata {
 	u32			trigger_cntr;
 };
 
+/* Generic functions */
+void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata);
+void tmc_flush_and_stop(struct tmc_drvdata *drvdata);
+void tmc_enable_hw(struct tmc_drvdata *drvdata);
+void tmc_disable_hw(struct tmc_drvdata *drvdata);
+
+/* ETB/ETF functions */
+void tmc_etb_enable_hw(struct tmc_drvdata *drvdata);
+void tmc_etb_disable_hw(struct tmc_drvdata *drvdata);
+extern const struct coresight_ops tmc_etb_cs_ops;
+extern const struct coresight_ops tmc_etf_cs_ops;
+
+/* ETR functions */
+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;
 #endif
-- 
2.5.0

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

* [PATCH V2 06/15] coresight: tmc: making prepare/unprepare functions generic
  2016-04-12 17:54 ` Mathieu Poirier
@ 2016-04-12 17:54   ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

Dealing with HW related matters in tmc_read_prepare/unprepare
becomes convoluted when many cases need to be handled distinctively.

As such moving processing related to HW setup to individual driver
files and keep the core driver generic.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 62 ++++++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 42 ++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tmc.c     | 55 +++++-----------------
 drivers/hwtracing/coresight/coresight-tmc.h     |  8 ++--
 4 files changed, 117 insertions(+), 50 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 467d19221f7b..4b8f39bd478b 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -71,7 +71,7 @@ static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
 	}
 }
 
-void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
+static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
 {
 	CS_UNLOCK(drvdata->base);
 
@@ -202,3 +202,63 @@ const struct coresight_ops tmc_etf_cs_ops = {
 	.sink_ops	= &tmc_etf_sink_ops,
 	.link_ops	= &tmc_etf_link_ops,
 };
+
+int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
+{
+	enum tmc_mode mode;
+	int ret = 0;
+	unsigned long flags;
+
+	/* config types are set a boot time and never change */
+	if (drvdata->config_type != TMC_CONFIG_TYPE_ETB &&
+	    drvdata->config_type != TMC_CONFIG_TYPE_ETF)
+		return -EINVAL;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+
+	/* There is no point in reading a TMC in HW FIFO mode */
+	mode = readl_relaxed(drvdata->base + TMC_MODE);
+	if (mode != TMC_MODE_CIRCULAR_BUFFER) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Disable the TMC if need be */
+	if (drvdata->enable)
+		tmc_etb_disable_hw(drvdata);
+
+	drvdata->reading = true;
+out:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	return ret;
+}
+
+int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
+{
+	enum tmc_mode mode;
+	unsigned long flags;
+
+	/* config types are set a boot time and never change */
+	if (drvdata->config_type != TMC_CONFIG_TYPE_ETB &&
+	    drvdata->config_type != TMC_CONFIG_TYPE_ETF)
+		return -EINVAL;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+
+	/* There is no point in reading a TMC in HW FIFO mode */
+	mode = readl_relaxed(drvdata->base + TMC_MODE);
+	if (mode != TMC_MODE_CIRCULAR_BUFFER) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return -EINVAL;
+	}
+
+	/* Re-enable the TMC if need be */
+	if (drvdata->enable)
+		tmc_etb_enable_hw(drvdata);
+
+	drvdata->reading = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	return 0;
+}
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 910d6f3b7d26..495540e9064d 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -70,7 +70,7 @@ static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
 		drvdata->buf = drvdata->vaddr;
 }
 
-void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
+static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 {
 	CS_UNLOCK(drvdata->base);
 
@@ -126,3 +126,43 @@ static const struct coresight_ops_sink tmc_etr_sink_ops = {
 const struct coresight_ops tmc_etr_cs_ops = {
 	.sink_ops	= &tmc_etr_sink_ops,
 };
+
+int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
+{
+	unsigned long flags;
+
+	/* config types are set a boot time and never change */
+	if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
+		return -EINVAL;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+
+	/* Disable the TMC if need be */
+	if (drvdata->enable)
+		tmc_etr_disable_hw(drvdata);
+
+	drvdata->reading = true;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	return 0;
+}
+
+int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
+{
+	unsigned long flags;
+
+	/* config types are set a boot time and never change */
+	if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
+		return -EINVAL;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+
+	/* RE-enable the TMC if need be */
+	if (drvdata->enable)
+		tmc_etr_enable_hw(drvdata);
+
+	drvdata->reading = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	return 0;
+}
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 67b3cd299782..f7e385f18e5f 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -76,76 +76,43 @@ void tmc_disable_hw(struct tmc_drvdata *drvdata)
 static int tmc_read_prepare(struct tmc_drvdata *drvdata)
 {
 	int ret = 0;
-	unsigned long flags;
-	enum tmc_mode mode;
-
-	spin_lock_irqsave(&drvdata->spinlock, flags);
-	if (!drvdata->enable)
-		goto out;
 
 	switch (drvdata->config_type) {
 	case TMC_CONFIG_TYPE_ETB:
-		tmc_etb_disable_hw(drvdata);
-		break;
 	case TMC_CONFIG_TYPE_ETF:
-		/* There is no point in reading a TMC in HW FIFO mode */
-		mode = readl_relaxed(drvdata->base + TMC_MODE);
-		if (mode != TMC_MODE_CIRCULAR_BUFFER) {
-			ret = -EINVAL;
-			goto err;
-		}
-
-		tmc_etb_disable_hw(drvdata);
+		ret = tmc_read_prepare_etb(drvdata);
 		break;
 	case TMC_CONFIG_TYPE_ETR:
-		tmc_etr_disable_hw(drvdata);
+		ret = tmc_read_prepare_etr(drvdata);
 		break;
 	default:
 		ret = -EINVAL;
-		goto err;
 	}
 
-out:
-	drvdata->reading = true;
-	dev_info(drvdata->dev, "TMC read start\n");
-err:
-	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	if (!ret)
+		dev_info(drvdata->dev, "TMC read start\n");
+
 	return ret;
 }
 
 static void tmc_read_unprepare(struct tmc_drvdata *drvdata)
 {
-	unsigned long flags;
-	enum tmc_mode mode;
-
-	spin_lock_irqsave(&drvdata->spinlock, flags);
-	if (!drvdata->enable)
-		goto out;
+	int ret = 0;
 
 	switch (drvdata->config_type) {
 	case TMC_CONFIG_TYPE_ETB:
-		tmc_etb_enable_hw(drvdata);
-		break;
 	case TMC_CONFIG_TYPE_ETF:
-		/* Make sure we don't re-enable a TMC in HW FIFO mode */
-		mode = readl_relaxed(drvdata->base + TMC_MODE);
-		if (mode != TMC_MODE_CIRCULAR_BUFFER)
-			goto err;
-
-		tmc_etb_enable_hw(drvdata);
+		ret = tmc_read_unprepare_etb(drvdata);
 		break;
 	case TMC_CONFIG_TYPE_ETR:
-		tmc_etr_disable_hw(drvdata);
+		ret = tmc_read_unprepare_etr(drvdata);
 		break;
 	default:
-		goto err;
+		ret = -EINVAL;
 	}
 
-out:
-	drvdata->reading = false;
-	dev_info(drvdata->dev, "TMC read end\n");
-err:
-	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	if (!ret)
+		dev_info(drvdata->dev, "TMC read end\n");
 }
 
 static int tmc_open(struct inode *inode, struct file *file)
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index b99d4dfc1d0b..80096fa75326 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -128,13 +128,13 @@ void tmc_enable_hw(struct tmc_drvdata *drvdata);
 void tmc_disable_hw(struct tmc_drvdata *drvdata);
 
 /* ETB/ETF functions */
-void tmc_etb_enable_hw(struct tmc_drvdata *drvdata);
-void tmc_etb_disable_hw(struct tmc_drvdata *drvdata);
+int tmc_read_prepare_etb(struct tmc_drvdata *drvdata);
+int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata);
 extern const struct coresight_ops tmc_etb_cs_ops;
 extern const struct coresight_ops tmc_etf_cs_ops;
 
 /* ETR functions */
-void tmc_etr_enable_hw(struct tmc_drvdata *drvdata);
-void tmc_etr_disable_hw(struct tmc_drvdata *drvdata);
+int tmc_read_prepare_etr(struct tmc_drvdata *drvdata);
+int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata);
 extern const struct coresight_ops tmc_etr_cs_ops;
 #endif
-- 
2.5.0

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

* [PATCH V2 06/15] coresight: tmc: making prepare/unprepare functions generic
@ 2016-04-12 17:54   ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

Dealing with HW related matters in tmc_read_prepare/unprepare
becomes convoluted when many cases need to be handled distinctively.

As such moving processing related to HW setup to individual driver
files and keep the core driver generic.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 62 ++++++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 42 ++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tmc.c     | 55 +++++-----------------
 drivers/hwtracing/coresight/coresight-tmc.h     |  8 ++--
 4 files changed, 117 insertions(+), 50 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 467d19221f7b..4b8f39bd478b 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -71,7 +71,7 @@ static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
 	}
 }
 
-void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
+static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
 {
 	CS_UNLOCK(drvdata->base);
 
@@ -202,3 +202,63 @@ const struct coresight_ops tmc_etf_cs_ops = {
 	.sink_ops	= &tmc_etf_sink_ops,
 	.link_ops	= &tmc_etf_link_ops,
 };
+
+int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
+{
+	enum tmc_mode mode;
+	int ret = 0;
+	unsigned long flags;
+
+	/* config types are set a boot time and never change */
+	if (drvdata->config_type != TMC_CONFIG_TYPE_ETB &&
+	    drvdata->config_type != TMC_CONFIG_TYPE_ETF)
+		return -EINVAL;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+
+	/* There is no point in reading a TMC in HW FIFO mode */
+	mode = readl_relaxed(drvdata->base + TMC_MODE);
+	if (mode != TMC_MODE_CIRCULAR_BUFFER) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Disable the TMC if need be */
+	if (drvdata->enable)
+		tmc_etb_disable_hw(drvdata);
+
+	drvdata->reading = true;
+out:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	return ret;
+}
+
+int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
+{
+	enum tmc_mode mode;
+	unsigned long flags;
+
+	/* config types are set a boot time and never change */
+	if (drvdata->config_type != TMC_CONFIG_TYPE_ETB &&
+	    drvdata->config_type != TMC_CONFIG_TYPE_ETF)
+		return -EINVAL;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+
+	/* There is no point in reading a TMC in HW FIFO mode */
+	mode = readl_relaxed(drvdata->base + TMC_MODE);
+	if (mode != TMC_MODE_CIRCULAR_BUFFER) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return -EINVAL;
+	}
+
+	/* Re-enable the TMC if need be */
+	if (drvdata->enable)
+		tmc_etb_enable_hw(drvdata);
+
+	drvdata->reading = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	return 0;
+}
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 910d6f3b7d26..495540e9064d 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -70,7 +70,7 @@ static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
 		drvdata->buf = drvdata->vaddr;
 }
 
-void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
+static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 {
 	CS_UNLOCK(drvdata->base);
 
@@ -126,3 +126,43 @@ static const struct coresight_ops_sink tmc_etr_sink_ops = {
 const struct coresight_ops tmc_etr_cs_ops = {
 	.sink_ops	= &tmc_etr_sink_ops,
 };
+
+int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
+{
+	unsigned long flags;
+
+	/* config types are set a boot time and never change */
+	if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
+		return -EINVAL;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+
+	/* Disable the TMC if need be */
+	if (drvdata->enable)
+		tmc_etr_disable_hw(drvdata);
+
+	drvdata->reading = true;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	return 0;
+}
+
+int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
+{
+	unsigned long flags;
+
+	/* config types are set a boot time and never change */
+	if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
+		return -EINVAL;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+
+	/* RE-enable the TMC if need be */
+	if (drvdata->enable)
+		tmc_etr_enable_hw(drvdata);
+
+	drvdata->reading = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	return 0;
+}
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 67b3cd299782..f7e385f18e5f 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -76,76 +76,43 @@ void tmc_disable_hw(struct tmc_drvdata *drvdata)
 static int tmc_read_prepare(struct tmc_drvdata *drvdata)
 {
 	int ret = 0;
-	unsigned long flags;
-	enum tmc_mode mode;
-
-	spin_lock_irqsave(&drvdata->spinlock, flags);
-	if (!drvdata->enable)
-		goto out;
 
 	switch (drvdata->config_type) {
 	case TMC_CONFIG_TYPE_ETB:
-		tmc_etb_disable_hw(drvdata);
-		break;
 	case TMC_CONFIG_TYPE_ETF:
-		/* There is no point in reading a TMC in HW FIFO mode */
-		mode = readl_relaxed(drvdata->base + TMC_MODE);
-		if (mode != TMC_MODE_CIRCULAR_BUFFER) {
-			ret = -EINVAL;
-			goto err;
-		}
-
-		tmc_etb_disable_hw(drvdata);
+		ret = tmc_read_prepare_etb(drvdata);
 		break;
 	case TMC_CONFIG_TYPE_ETR:
-		tmc_etr_disable_hw(drvdata);
+		ret = tmc_read_prepare_etr(drvdata);
 		break;
 	default:
 		ret = -EINVAL;
-		goto err;
 	}
 
-out:
-	drvdata->reading = true;
-	dev_info(drvdata->dev, "TMC read start\n");
-err:
-	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	if (!ret)
+		dev_info(drvdata->dev, "TMC read start\n");
+
 	return ret;
 }
 
 static void tmc_read_unprepare(struct tmc_drvdata *drvdata)
 {
-	unsigned long flags;
-	enum tmc_mode mode;
-
-	spin_lock_irqsave(&drvdata->spinlock, flags);
-	if (!drvdata->enable)
-		goto out;
+	int ret = 0;
 
 	switch (drvdata->config_type) {
 	case TMC_CONFIG_TYPE_ETB:
-		tmc_etb_enable_hw(drvdata);
-		break;
 	case TMC_CONFIG_TYPE_ETF:
-		/* Make sure we don't re-enable a TMC in HW FIFO mode */
-		mode = readl_relaxed(drvdata->base + TMC_MODE);
-		if (mode != TMC_MODE_CIRCULAR_BUFFER)
-			goto err;
-
-		tmc_etb_enable_hw(drvdata);
+		ret = tmc_read_unprepare_etb(drvdata);
 		break;
 	case TMC_CONFIG_TYPE_ETR:
-		tmc_etr_disable_hw(drvdata);
+		ret = tmc_read_unprepare_etr(drvdata);
 		break;
 	default:
-		goto err;
+		ret = -EINVAL;
 	}
 
-out:
-	drvdata->reading = false;
-	dev_info(drvdata->dev, "TMC read end\n");
-err:
-	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	if (!ret)
+		dev_info(drvdata->dev, "TMC read end\n");
 }
 
 static int tmc_open(struct inode *inode, struct file *file)
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index b99d4dfc1d0b..80096fa75326 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -128,13 +128,13 @@ void tmc_enable_hw(struct tmc_drvdata *drvdata);
 void tmc_disable_hw(struct tmc_drvdata *drvdata);
 
 /* ETB/ETF functions */
-void tmc_etb_enable_hw(struct tmc_drvdata *drvdata);
-void tmc_etb_disable_hw(struct tmc_drvdata *drvdata);
+int tmc_read_prepare_etb(struct tmc_drvdata *drvdata);
+int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata);
 extern const struct coresight_ops tmc_etb_cs_ops;
 extern const struct coresight_ops tmc_etf_cs_ops;
 
 /* ETR functions */
-void tmc_etr_enable_hw(struct tmc_drvdata *drvdata);
-void tmc_etr_disable_hw(struct tmc_drvdata *drvdata);
+int tmc_read_prepare_etr(struct tmc_drvdata *drvdata);
+int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata);
 extern const struct coresight_ops tmc_etr_cs_ops;
 #endif
-- 
2.5.0

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

* [PATCH V2 07/15] coresight: tmc: allocating memory when needed
  2016-04-12 17:54 ` Mathieu Poirier
@ 2016-04-12 17:54   ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

In it's current form the TMC probe() function allocates
trace buffer memory at boot time, event if coresight isn't
used.  This is highly inefficient since trace buffers can
occupy a lot of memory that could be used otherwised.

This patch allocates trace buffers on the fly, when the
coresight subsystem is solicited.  Allocated buffers are
released when traces are read using the device descriptors
under /dev.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 85 +++++++++++++++++++++++--
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 83 +++++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tmc.c     | 14 ----
 3 files changed, 163 insertions(+), 19 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 4b8f39bd478b..7cb287ef7b9e 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -16,14 +16,12 @@
  */
 
 #include <linux/coresight.h>
+#include <linux/slab.h>
 #include "coresight-priv.h"
 #include "coresight-tmc.h"
 
 void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
 {
-	/* Zero out the memory to help with debug */
-	memset(drvdata->buf, 0, drvdata->size);
-
 	CS_UNLOCK(drvdata->base);
 
 	/* Wait for TMCSReady bit to be set */
@@ -110,19 +108,68 @@ static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
 
 static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
 {
+	bool allocated = false;
+	char *buf = NULL;
 	unsigned long flags;
 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
+	 /* This shouldn't be happening */
+	WARN_ON(mode != CS_MODE_SYSFS);
+
+	/*
+	 * If a buffer is already allocated *keep holding* the lock and
+	 * jump to the fast path.  Otherwise release the lock and allocate
+	 * memory to work with.
+	 */
 	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->buf)
+		goto fast_path;
+
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	/* Allocating the memory here while outside of the spinlock */
+	buf = kzalloc(drvdata->size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	/* Let's try again */
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+fast_path:
 	if (drvdata->reading) {
 		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		/*
+		 * Free allocated memory outside of the spinlock.  There is
+		 * no need to assert the validity of 'buf' since calling
+		 * kfree(NULL) is safe.
+		 */
+		kfree(buf);
 		return -EBUSY;
 	}
 
+	/*
+	 * If drvdata::buf isn't NULL, memory was allocated for a previous
+	 * trace run but wasn't read.  If so simply zero-out the memory.
+	 * Otherwise use the memory allocated above.
+	 *
+	 * The memory is freed when users read the buffer using the
+	 * /dev/xyz.{etf|etb} interface.  See tmc_read_unprepare_etf() for
+	 * details.
+	 */
+	if (drvdata->buf) {
+		memset(drvdata->buf, 0, drvdata->size);
+	} else {
+		allocated = true;
+		drvdata->buf = buf;
+	}
+
 	tmc_etb_enable_hw(drvdata);
 	drvdata->enable = true;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+	/* Free memory outside the spinlock if need be */
+	if (!allocated && buf)
+		kfree(buf);
+
 	dev_info(drvdata->dev, "TMC-ETB/ETF enabled\n");
 	return 0;
 }
@@ -223,6 +270,12 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
 		goto out;
 	}
 
+	/* If drvdata::buf is NULL the trace data has been read already */
+	if (drvdata->buf == NULL) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/* Disable the TMC if need be */
 	if (drvdata->enable)
 		tmc_etb_disable_hw(drvdata);
@@ -236,6 +289,7 @@ out:
 
 int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
 {
+	char *buf = NULL;
 	enum tmc_mode mode;
 	unsigned long flags;
 
@@ -254,11 +308,34 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
 	}
 
 	/* Re-enable the TMC if need be */
-	if (drvdata->enable)
+	if (drvdata->enable) {
+		/*
+		 * The trace run will continue with the same allocated trace
+		 * buffer. As such zero-out the buffer so that we don't end
+		 * up with stale data.
+		 *
+		 * Since the tracer is still enabled drvdata::buf
+		 * can't be NULL.
+		 */
+		memset(drvdata->buf, 0, drvdata->size);
 		tmc_etb_enable_hw(drvdata);
+	} else {
+		/*
+		 * The ETB/ETF is not tracing and the buffer was just read.
+		 * As such prepare to free the trace buffer.
+		 */
+		buf = drvdata->buf;
+		drvdata->buf = NULL;
+	}
 
 	drvdata->reading = false;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+	/*
+	 * Free allocated memory outside of the spinlock.  There is no need
+	 * to assert the validity of 'buf' since calling kfree(NULL) is safe.
+	 */
+	kfree(buf);
+
 	return 0;
 }
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 495540e9064d..6022ff26deba 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -16,6 +16,7 @@
  */
 
 #include <linux/coresight.h>
+#include <linux/dma-mapping.h>
 #include "coresight-priv.h"
 #include "coresight-tmc.h"
 
@@ -83,19 +84,69 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 
 static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
 {
+	bool allocated = false;
 	unsigned long flags;
+	void __iomem *vaddr = NULL;
+	dma_addr_t paddr;
 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
+	 /* This shouldn't be happening */
+	WARN_ON(mode != CS_MODE_SYSFS);
+
+	/*
+	 * If a buffer is already allocated *keep holding* the lock and
+	 * jump to the fast path.  Otherwise release the lock and allocate
+	 * memory to work with.
+	 */
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->vaddr)
+		goto fast_path;
+
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	/*
+	 * Contiguous  memory can't be allocated while a spinlock is held.
+	 * As such allocate memory here and free it if a buffer has already
+	 * been allocated (from a previous session).
+	 */
+	vaddr = dma_alloc_coherent(drvdata->dev, drvdata->size,
+				   &paddr, GFP_KERNEL);
+	if (!vaddr)
+		return -ENOMEM;
+
+	/* Let's try again */
 	spin_lock_irqsave(&drvdata->spinlock, flags);
+fast_path:
 	if (drvdata->reading) {
 		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		if (vaddr)
+			dma_free_coherent(drvdata->dev, drvdata->size,
+					  vaddr, paddr);
 		return -EBUSY;
 	}
 
+	/*
+	 * If drvdata::buf == NULL, use the memory allocated above.
+	 * Otherwise a buffer still exists from a previous session, so
+	 * simply use that.
+	 */
+	if (drvdata->buf == NULL) {
+		allocated = true;
+		drvdata->vaddr = vaddr;
+		drvdata->paddr = paddr;
+		drvdata->buf = drvdata->vaddr;
+	}
+
+	memset(drvdata->vaddr, 0, drvdata->size);
+
 	tmc_etr_enable_hw(drvdata);
 	drvdata->enable = true;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+	/* Free memory outside the spinlock if need be */
+	if (!allocated && vaddr)
+		dma_free_coherent(drvdata->dev, drvdata->size, vaddr, paddr);
+
 	dev_info(drvdata->dev, "TMC-ETR enabled\n");
 	return 0;
 }
@@ -137,6 +188,12 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
 
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 
+	/* If drvdata::buf is NULL the trace data has been read already */
+	if (drvdata->buf == NULL) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return -EINVAL;
+	}
+
 	/* Disable the TMC if need be */
 	if (drvdata->enable)
 		tmc_etr_disable_hw(drvdata);
@@ -150,6 +207,8 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
 int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
 {
 	unsigned long flags;
+	dma_addr_t paddr;
+	void __iomem *vaddr = NULL;
 
 	/* config types are set a boot time and never change */
 	if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
@@ -158,11 +217,33 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 
 	/* RE-enable the TMC if need be */
-	if (drvdata->enable)
+	if (drvdata->enable) {
+		/*
+		 * The trace run will continue with the same allocated trace
+		 * buffer. As such zero-out the buffer so that we don't end
+		 * up with stale data.
+		 *
+		 * Since the tracer is still enabled drvdata::buf
+		 * can't be NULL.
+		 */
+		memset(drvdata->buf, 0, drvdata->size);
 		tmc_etr_enable_hw(drvdata);
+	} else {
+		/*
+		 * The ETR is not tracing and the buffer was just read.
+		 * As such prepare to free the trace buffer.
+		 */
+		vaddr = drvdata->vaddr;
+		paddr = drvdata->paddr;
+		drvdata->buf = NULL;
+	}
 
 	drvdata->reading = false;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+	/* Free allocated memory out side of the spinlock */
+	if (vaddr)
+		dma_free_coherent(drvdata->dev, drvdata->size, vaddr, paddr);
+
 	return 0;
 }
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index f7e385f18e5f..ae336641518f 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -319,20 +319,6 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
 
 	pm_runtime_put(&adev->dev);
 
-	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		drvdata->vaddr = dma_alloc_coherent(dev, drvdata->size,
-						&drvdata->paddr, GFP_KERNEL);
-		if (!drvdata->vaddr)
-			return -ENOMEM;
-
-		memset(drvdata->vaddr, 0, drvdata->size);
-		drvdata->buf = drvdata->vaddr;
-	} else {
-		drvdata->buf = devm_kzalloc(dev, drvdata->size, GFP_KERNEL);
-		if (!drvdata->buf)
-			return -ENOMEM;
-	}
-
 	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
 	if (!desc) {
 		ret = -ENOMEM;
-- 
2.5.0

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

* [PATCH V2 07/15] coresight: tmc: allocating memory when needed
@ 2016-04-12 17:54   ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

In it's current form the TMC probe() function allocates
trace buffer memory at boot time, event if coresight isn't
used.  This is highly inefficient since trace buffers can
occupy a lot of memory that could be used otherwised.

This patch allocates trace buffers on the fly, when the
coresight subsystem is solicited.  Allocated buffers are
released when traces are read using the device descriptors
under /dev.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 85 +++++++++++++++++++++++--
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 83 +++++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tmc.c     | 14 ----
 3 files changed, 163 insertions(+), 19 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 4b8f39bd478b..7cb287ef7b9e 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -16,14 +16,12 @@
  */
 
 #include <linux/coresight.h>
+#include <linux/slab.h>
 #include "coresight-priv.h"
 #include "coresight-tmc.h"
 
 void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
 {
-	/* Zero out the memory to help with debug */
-	memset(drvdata->buf, 0, drvdata->size);
-
 	CS_UNLOCK(drvdata->base);
 
 	/* Wait for TMCSReady bit to be set */
@@ -110,19 +108,68 @@ static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
 
 static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
 {
+	bool allocated = false;
+	char *buf = NULL;
 	unsigned long flags;
 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
+	 /* This shouldn't be happening */
+	WARN_ON(mode != CS_MODE_SYSFS);
+
+	/*
+	 * If a buffer is already allocated *keep holding* the lock and
+	 * jump to the fast path.  Otherwise release the lock and allocate
+	 * memory to work with.
+	 */
 	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->buf)
+		goto fast_path;
+
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	/* Allocating the memory here while outside of the spinlock */
+	buf = kzalloc(drvdata->size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	/* Let's try again */
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+fast_path:
 	if (drvdata->reading) {
 		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		/*
+		 * Free allocated memory outside of the spinlock.  There is
+		 * no need to assert the validity of 'buf' since calling
+		 * kfree(NULL) is safe.
+		 */
+		kfree(buf);
 		return -EBUSY;
 	}
 
+	/*
+	 * If drvdata::buf isn't NULL, memory was allocated for a previous
+	 * trace run but wasn't read.  If so simply zero-out the memory.
+	 * Otherwise use the memory allocated above.
+	 *
+	 * The memory is freed when users read the buffer using the
+	 * /dev/xyz.{etf|etb} interface.  See tmc_read_unprepare_etf() for
+	 * details.
+	 */
+	if (drvdata->buf) {
+		memset(drvdata->buf, 0, drvdata->size);
+	} else {
+		allocated = true;
+		drvdata->buf = buf;
+	}
+
 	tmc_etb_enable_hw(drvdata);
 	drvdata->enable = true;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+	/* Free memory outside the spinlock if need be */
+	if (!allocated && buf)
+		kfree(buf);
+
 	dev_info(drvdata->dev, "TMC-ETB/ETF enabled\n");
 	return 0;
 }
@@ -223,6 +270,12 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
 		goto out;
 	}
 
+	/* If drvdata::buf is NULL the trace data has been read already */
+	if (drvdata->buf == NULL) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/* Disable the TMC if need be */
 	if (drvdata->enable)
 		tmc_etb_disable_hw(drvdata);
@@ -236,6 +289,7 @@ out:
 
 int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
 {
+	char *buf = NULL;
 	enum tmc_mode mode;
 	unsigned long flags;
 
@@ -254,11 +308,34 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
 	}
 
 	/* Re-enable the TMC if need be */
-	if (drvdata->enable)
+	if (drvdata->enable) {
+		/*
+		 * The trace run will continue with the same allocated trace
+		 * buffer. As such zero-out the buffer so that we don't end
+		 * up with stale data.
+		 *
+		 * Since the tracer is still enabled drvdata::buf
+		 * can't be NULL.
+		 */
+		memset(drvdata->buf, 0, drvdata->size);
 		tmc_etb_enable_hw(drvdata);
+	} else {
+		/*
+		 * The ETB/ETF is not tracing and the buffer was just read.
+		 * As such prepare to free the trace buffer.
+		 */
+		buf = drvdata->buf;
+		drvdata->buf = NULL;
+	}
 
 	drvdata->reading = false;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+	/*
+	 * Free allocated memory outside of the spinlock.  There is no need
+	 * to assert the validity of 'buf' since calling kfree(NULL) is safe.
+	 */
+	kfree(buf);
+
 	return 0;
 }
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 495540e9064d..6022ff26deba 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -16,6 +16,7 @@
  */
 
 #include <linux/coresight.h>
+#include <linux/dma-mapping.h>
 #include "coresight-priv.h"
 #include "coresight-tmc.h"
 
@@ -83,19 +84,69 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 
 static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
 {
+	bool allocated = false;
 	unsigned long flags;
+	void __iomem *vaddr = NULL;
+	dma_addr_t paddr;
 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
+	 /* This shouldn't be happening */
+	WARN_ON(mode != CS_MODE_SYSFS);
+
+	/*
+	 * If a buffer is already allocated *keep holding* the lock and
+	 * jump to the fast path.  Otherwise release the lock and allocate
+	 * memory to work with.
+	 */
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->vaddr)
+		goto fast_path;
+
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	/*
+	 * Contiguous  memory can't be allocated while a spinlock is held.
+	 * As such allocate memory here and free it if a buffer has already
+	 * been allocated (from a previous session).
+	 */
+	vaddr = dma_alloc_coherent(drvdata->dev, drvdata->size,
+				   &paddr, GFP_KERNEL);
+	if (!vaddr)
+		return -ENOMEM;
+
+	/* Let's try again */
 	spin_lock_irqsave(&drvdata->spinlock, flags);
+fast_path:
 	if (drvdata->reading) {
 		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		if (vaddr)
+			dma_free_coherent(drvdata->dev, drvdata->size,
+					  vaddr, paddr);
 		return -EBUSY;
 	}
 
+	/*
+	 * If drvdata::buf == NULL, use the memory allocated above.
+	 * Otherwise a buffer still exists from a previous session, so
+	 * simply use that.
+	 */
+	if (drvdata->buf == NULL) {
+		allocated = true;
+		drvdata->vaddr = vaddr;
+		drvdata->paddr = paddr;
+		drvdata->buf = drvdata->vaddr;
+	}
+
+	memset(drvdata->vaddr, 0, drvdata->size);
+
 	tmc_etr_enable_hw(drvdata);
 	drvdata->enable = true;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+	/* Free memory outside the spinlock if need be */
+	if (!allocated && vaddr)
+		dma_free_coherent(drvdata->dev, drvdata->size, vaddr, paddr);
+
 	dev_info(drvdata->dev, "TMC-ETR enabled\n");
 	return 0;
 }
@@ -137,6 +188,12 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
 
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 
+	/* If drvdata::buf is NULL the trace data has been read already */
+	if (drvdata->buf == NULL) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return -EINVAL;
+	}
+
 	/* Disable the TMC if need be */
 	if (drvdata->enable)
 		tmc_etr_disable_hw(drvdata);
@@ -150,6 +207,8 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
 int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
 {
 	unsigned long flags;
+	dma_addr_t paddr;
+	void __iomem *vaddr = NULL;
 
 	/* config types are set a boot time and never change */
 	if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
@@ -158,11 +217,33 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 
 	/* RE-enable the TMC if need be */
-	if (drvdata->enable)
+	if (drvdata->enable) {
+		/*
+		 * The trace run will continue with the same allocated trace
+		 * buffer. As such zero-out the buffer so that we don't end
+		 * up with stale data.
+		 *
+		 * Since the tracer is still enabled drvdata::buf
+		 * can't be NULL.
+		 */
+		memset(drvdata->buf, 0, drvdata->size);
 		tmc_etr_enable_hw(drvdata);
+	} else {
+		/*
+		 * The ETR is not tracing and the buffer was just read.
+		 * As such prepare to free the trace buffer.
+		 */
+		vaddr = drvdata->vaddr;
+		paddr = drvdata->paddr;
+		drvdata->buf = NULL;
+	}
 
 	drvdata->reading = false;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+	/* Free allocated memory out side of the spinlock */
+	if (vaddr)
+		dma_free_coherent(drvdata->dev, drvdata->size, vaddr, paddr);
+
 	return 0;
 }
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index f7e385f18e5f..ae336641518f 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -319,20 +319,6 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
 
 	pm_runtime_put(&adev->dev);
 
-	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-		drvdata->vaddr = dma_alloc_coherent(dev, drvdata->size,
-						&drvdata->paddr, GFP_KERNEL);
-		if (!drvdata->vaddr)
-			return -ENOMEM;
-
-		memset(drvdata->vaddr, 0, drvdata->size);
-		drvdata->buf = drvdata->vaddr;
-	} else {
-		drvdata->buf = devm_kzalloc(dev, drvdata->size, GFP_KERNEL);
-		if (!drvdata->buf)
-			return -ENOMEM;
-	}
-
 	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
 	if (!desc) {
 		ret = -ENOMEM;
-- 
2.5.0

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

* [PATCH V2 08/15] coresight: tmc: getting the right read_count on tmc_open()
  2016-04-12 17:54 ` Mathieu Poirier
@ 2016-04-12 17:54   ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

In function tmc_open(), if tmc_read_prepare() fails variable
drvdata->read_count is not decremented, causing unwanted
access to drvdata->buf and very likely, a crash dump.

By moving the incrementation to a place where we know things
are stable this kind of situation is avoided.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index ae336641518f..4d7b64f69389 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -121,13 +121,14 @@ static int tmc_open(struct inode *inode, struct file *file)
 						   struct tmc_drvdata, miscdev);
 	int ret = 0;
 
-	if (drvdata->read_count++)
+	if (drvdata->read_count)
 		goto out;
 
 	ret = tmc_read_prepare(drvdata);
 	if (ret)
 		return ret;
 out:
+	drvdata->read_count++;
 	nonseekable_open(inode, file);
 
 	dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
-- 
2.5.0

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

* [PATCH V2 08/15] coresight: tmc: getting the right read_count on tmc_open()
@ 2016-04-12 17:54   ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

In function tmc_open(), if tmc_read_prepare() fails variable
drvdata->read_count is not decremented, causing unwanted
access to drvdata->buf and very likely, a crash dump.

By moving the incrementation to a place where we know things
are stable this kind of situation is avoided.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index ae336641518f..4d7b64f69389 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -121,13 +121,14 @@ static int tmc_open(struct inode *inode, struct file *file)
 						   struct tmc_drvdata, miscdev);
 	int ret = 0;
 
-	if (drvdata->read_count++)
+	if (drvdata->read_count)
 		goto out;
 
 	ret = tmc_read_prepare(drvdata);
 	if (ret)
 		return ret;
 out:
+	drvdata->read_count++;
 	nonseekable_open(inode, file);
 
 	dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
-- 
2.5.0

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

* [PATCH V2 09/15] coresight: tmc: adding mode of operation for link/sinks
  2016-04-12 17:54 ` Mathieu Poirier
@ 2016-04-12 17:54   ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

Moving tmc_drvdata::enable to a local_t mode.  That way the
sink interface is aware of it's orgin and the foundation for
mutual exclusion between the sysFS and Perf interface can be
laid out.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 28 ++++++++++++++++++-------
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 24 ++++++++++++++++-----
 drivers/hwtracing/coresight/coresight-tmc.h     |  4 ++--
 3 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 7cb287ef7b9e..5908000e1ae0 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -110,6 +110,7 @@ static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
 {
 	bool allocated = false;
 	char *buf = NULL;
+	u32 val;
 	unsigned long flags;
 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
@@ -146,6 +147,15 @@ fast_path:
 		return -EBUSY;
 	}
 
+	val = local_xchg(&drvdata->mode, mode);
+	/*
+	 * In sysFS mode we can have multiple writers per sink.  Since this
+	 * sink is already enabled no memory is needed and the HW need not be
+	 * touched.
+	 */
+	if (val == CS_MODE_SYSFS)
+		goto out;
+
 	/*
 	 * If drvdata::buf isn't NULL, memory was allocated for a previous
 	 * trace run but wasn't read.  If so simply zero-out the memory.
@@ -163,9 +173,9 @@ fast_path:
 	}
 
 	tmc_etb_enable_hw(drvdata);
-	drvdata->enable = true;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+out:
 	/* Free memory outside the spinlock if need be */
 	if (!allocated && buf)
 		kfree(buf);
@@ -176,6 +186,7 @@ fast_path:
 
 static void tmc_disable_etf_sink(struct coresight_device *csdev)
 {
+	u32 val;
 	unsigned long flags;
 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
@@ -185,8 +196,11 @@ static void tmc_disable_etf_sink(struct coresight_device *csdev)
 		return;
 	}
 
-	tmc_etb_disable_hw(drvdata);
-	drvdata->enable = false;
+	val = local_xchg(&drvdata->mode, CS_MODE_DISABLED);
+	/* Disable the TMC only if it needs to */
+	if (val != CS_MODE_DISABLED)
+		tmc_etb_disable_hw(drvdata);
+
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
 	dev_info(drvdata->dev, "TMC-ETB/ETF disabled\n");
@@ -205,7 +219,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
 	}
 
 	tmc_etf_enable_hw(drvdata);
-	drvdata->enable = true;
+	local_set(&drvdata->mode, CS_MODE_SYSFS);
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
 	dev_info(drvdata->dev, "TMC-ETF enabled\n");
@@ -225,7 +239,7 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
 	}
 
 	tmc_etf_disable_hw(drvdata);
-	drvdata->enable = false;
+	local_set(&drvdata->mode, CS_MODE_DISABLED);
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
 	dev_info(drvdata->dev, "TMC disabled\n");
@@ -277,7 +291,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
 	}
 
 	/* Disable the TMC if need be */
-	if (drvdata->enable)
+	if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
 		tmc_etb_disable_hw(drvdata);
 
 	drvdata->reading = true;
@@ -308,7 +322,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
 	}
 
 	/* Re-enable the TMC if need be */
-	if (drvdata->enable) {
+	if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
 		/*
 		 * The trace run will continue with the same allocated trace
 		 * buffer. As such zero-out the buffer so that we don't end
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 6022ff26deba..8e6fe267195a 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -85,6 +85,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
 {
 	bool allocated = false;
+	u32 val;
 	unsigned long flags;
 	void __iomem *vaddr = NULL;
 	dma_addr_t paddr;
@@ -125,6 +126,15 @@ fast_path:
 		return -EBUSY;
 	}
 
+	val = local_xchg(&drvdata->mode, mode);
+	/*
+	 * In sysFS mode we can have multiple writers per sink.  Since this
+	 * sink is already enabled no memory is needed and the HW need not be
+	 * touched.
+	 */
+	if (val == CS_MODE_SYSFS)
+		goto out;
+
 	/*
 	 * If drvdata::buf == NULL, use the memory allocated above.
 	 * Otherwise a buffer still exists from a previous session, so
@@ -140,9 +150,9 @@ fast_path:
 	memset(drvdata->vaddr, 0, drvdata->size);
 
 	tmc_etr_enable_hw(drvdata);
-	drvdata->enable = true;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+out:
 	/* Free memory outside the spinlock if need be */
 	if (!allocated && vaddr)
 		dma_free_coherent(drvdata->dev, drvdata->size, vaddr, paddr);
@@ -153,6 +163,7 @@ fast_path:
 
 static void tmc_disable_etr_sink(struct coresight_device *csdev)
 {
+	u32 val;
 	unsigned long flags;
 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
@@ -162,8 +173,11 @@ static void tmc_disable_etr_sink(struct coresight_device *csdev)
 		return;
 	}
 
-	tmc_etr_disable_hw(drvdata);
-	drvdata->enable = false;
+	val = local_xchg(&drvdata->mode, CS_MODE_DISABLED);
+	/* Disable the TMC only if it needs to */
+	if (val != CS_MODE_DISABLED)
+		tmc_etr_disable_hw(drvdata);
+
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
 	dev_info(drvdata->dev, "TMC-ETR disabled\n");
@@ -195,7 +209,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
 	}
 
 	/* Disable the TMC if need be */
-	if (drvdata->enable)
+	if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
 		tmc_etr_disable_hw(drvdata);
 
 	drvdata->reading = true;
@@ -217,7 +231,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 
 	/* RE-enable the TMC if need be */
-	if (drvdata->enable) {
+	if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
 		/*
 		 * The trace run will continue with the same allocated trace
 		 * buffer. As such zero-out the buffer so that we don't end
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 80096fa75326..821bdf150ac9 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -100,7 +100,7 @@ enum tmc_mem_intf_width {
  * @paddr:	DMA start location in RAM.
  * @vaddr:	virtual representation of @paddr.
  * @size:	@buf size.
- * @enable:	this TMC is being used.
+ * @mode:	how this TMC is being used.
  * @config_type: TMC variant, must be of type @tmc_config_type.
  * @trigger_cntr: amount of words to store after a trigger.
  */
@@ -116,7 +116,7 @@ struct tmc_drvdata {
 	dma_addr_t		paddr;
 	void __iomem		*vaddr;
 	u32			size;
-	bool			enable;
+	local_t			mode;
 	enum tmc_config_type	config_type;
 	u32			trigger_cntr;
 };
-- 
2.5.0

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

* [PATCH V2 09/15] coresight: tmc: adding mode of operation for link/sinks
@ 2016-04-12 17:54   ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

Moving tmc_drvdata::enable to a local_t mode.  That way the
sink interface is aware of it's orgin and the foundation for
mutual exclusion between the sysFS and Perf interface can be
laid out.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 28 ++++++++++++++++++-------
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 24 ++++++++++++++++-----
 drivers/hwtracing/coresight/coresight-tmc.h     |  4 ++--
 3 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 7cb287ef7b9e..5908000e1ae0 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -110,6 +110,7 @@ static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
 {
 	bool allocated = false;
 	char *buf = NULL;
+	u32 val;
 	unsigned long flags;
 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
@@ -146,6 +147,15 @@ fast_path:
 		return -EBUSY;
 	}
 
+	val = local_xchg(&drvdata->mode, mode);
+	/*
+	 * In sysFS mode we can have multiple writers per sink.  Since this
+	 * sink is already enabled no memory is needed and the HW need not be
+	 * touched.
+	 */
+	if (val == CS_MODE_SYSFS)
+		goto out;
+
 	/*
 	 * If drvdata::buf isn't NULL, memory was allocated for a previous
 	 * trace run but wasn't read.  If so simply zero-out the memory.
@@ -163,9 +173,9 @@ fast_path:
 	}
 
 	tmc_etb_enable_hw(drvdata);
-	drvdata->enable = true;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+out:
 	/* Free memory outside the spinlock if need be */
 	if (!allocated && buf)
 		kfree(buf);
@@ -176,6 +186,7 @@ fast_path:
 
 static void tmc_disable_etf_sink(struct coresight_device *csdev)
 {
+	u32 val;
 	unsigned long flags;
 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
@@ -185,8 +196,11 @@ static void tmc_disable_etf_sink(struct coresight_device *csdev)
 		return;
 	}
 
-	tmc_etb_disable_hw(drvdata);
-	drvdata->enable = false;
+	val = local_xchg(&drvdata->mode, CS_MODE_DISABLED);
+	/* Disable the TMC only if it needs to */
+	if (val != CS_MODE_DISABLED)
+		tmc_etb_disable_hw(drvdata);
+
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
 	dev_info(drvdata->dev, "TMC-ETB/ETF disabled\n");
@@ -205,7 +219,7 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
 	}
 
 	tmc_etf_enable_hw(drvdata);
-	drvdata->enable = true;
+	local_set(&drvdata->mode, CS_MODE_SYSFS);
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
 	dev_info(drvdata->dev, "TMC-ETF enabled\n");
@@ -225,7 +239,7 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
 	}
 
 	tmc_etf_disable_hw(drvdata);
-	drvdata->enable = false;
+	local_set(&drvdata->mode, CS_MODE_DISABLED);
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
 	dev_info(drvdata->dev, "TMC disabled\n");
@@ -277,7 +291,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
 	}
 
 	/* Disable the TMC if need be */
-	if (drvdata->enable)
+	if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
 		tmc_etb_disable_hw(drvdata);
 
 	drvdata->reading = true;
@@ -308,7 +322,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
 	}
 
 	/* Re-enable the TMC if need be */
-	if (drvdata->enable) {
+	if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
 		/*
 		 * The trace run will continue with the same allocated trace
 		 * buffer. As such zero-out the buffer so that we don't end
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 6022ff26deba..8e6fe267195a 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -85,6 +85,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
 {
 	bool allocated = false;
+	u32 val;
 	unsigned long flags;
 	void __iomem *vaddr = NULL;
 	dma_addr_t paddr;
@@ -125,6 +126,15 @@ fast_path:
 		return -EBUSY;
 	}
 
+	val = local_xchg(&drvdata->mode, mode);
+	/*
+	 * In sysFS mode we can have multiple writers per sink.  Since this
+	 * sink is already enabled no memory is needed and the HW need not be
+	 * touched.
+	 */
+	if (val == CS_MODE_SYSFS)
+		goto out;
+
 	/*
 	 * If drvdata::buf == NULL, use the memory allocated above.
 	 * Otherwise a buffer still exists from a previous session, so
@@ -140,9 +150,9 @@ fast_path:
 	memset(drvdata->vaddr, 0, drvdata->size);
 
 	tmc_etr_enable_hw(drvdata);
-	drvdata->enable = true;
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+out:
 	/* Free memory outside the spinlock if need be */
 	if (!allocated && vaddr)
 		dma_free_coherent(drvdata->dev, drvdata->size, vaddr, paddr);
@@ -153,6 +163,7 @@ fast_path:
 
 static void tmc_disable_etr_sink(struct coresight_device *csdev)
 {
+	u32 val;
 	unsigned long flags;
 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
@@ -162,8 +173,11 @@ static void tmc_disable_etr_sink(struct coresight_device *csdev)
 		return;
 	}
 
-	tmc_etr_disable_hw(drvdata);
-	drvdata->enable = false;
+	val = local_xchg(&drvdata->mode, CS_MODE_DISABLED);
+	/* Disable the TMC only if it needs to */
+	if (val != CS_MODE_DISABLED)
+		tmc_etr_disable_hw(drvdata);
+
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
 	dev_info(drvdata->dev, "TMC-ETR disabled\n");
@@ -195,7 +209,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
 	}
 
 	/* Disable the TMC if need be */
-	if (drvdata->enable)
+	if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
 		tmc_etr_disable_hw(drvdata);
 
 	drvdata->reading = true;
@@ -217,7 +231,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 
 	/* RE-enable the TMC if need be */
-	if (drvdata->enable) {
+	if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
 		/*
 		 * The trace run will continue with the same allocated trace
 		 * buffer. As such zero-out the buffer so that we don't end
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 80096fa75326..821bdf150ac9 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -100,7 +100,7 @@ enum tmc_mem_intf_width {
  * @paddr:	DMA start location in RAM.
  * @vaddr:	virtual representation of @paddr.
  * @size:	@buf size.
- * @enable:	this TMC is being used.
+ * @mode:	how this TMC is being used.
  * @config_type: TMC variant, must be of type @tmc_config_type.
  * @trigger_cntr: amount of words to store after a trigger.
  */
@@ -116,7 +116,7 @@ struct tmc_drvdata {
 	dma_addr_t		paddr;
 	void __iomem		*vaddr;
 	u32			size;
-	bool			enable;
+	local_t			mode;
 	enum tmc_config_type	config_type;
 	u32			trigger_cntr;
 };
-- 
2.5.0

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

* [PATCH V2 10/15] coresight: tmc: dump system memory content only when needed
  2016-04-12 17:54 ` Mathieu Poirier
@ 2016-04-12 17:54   ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

Calling tmc_etf/etr_dump_hw() is required only when operating from
sysFS.  When working from Perf, the system memory is harvested
from the AUX trace API.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 7 ++++++-
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 7 ++++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 5908000e1ae0..9b4cdaed09f5 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -74,7 +74,12 @@ static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
 	CS_UNLOCK(drvdata->base);
 
 	tmc_flush_and_stop(drvdata);
-	tmc_etb_dump_hw(drvdata);
+	/*
+	 * When operating in sysFS mode the content of the buffer needs to be
+	 * read before the TMC is disabled.
+	 */
+	if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
+		tmc_etb_dump_hw(drvdata);
 	tmc_disable_hw(drvdata);
 
 	CS_LOCK(drvdata->base);
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 8e6fe267195a..de5cf0056802 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -76,7 +76,12 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 	CS_UNLOCK(drvdata->base);
 
 	tmc_flush_and_stop(drvdata);
-	tmc_etr_dump_hw(drvdata);
+	/*
+	 * When operating in sysFS mode the content of the buffer needs to be
+	 * read before the TMC is disabled.
+	 */
+	if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
+		tmc_etr_dump_hw(drvdata);
 	tmc_disable_hw(drvdata);
 
 	CS_LOCK(drvdata->base);
-- 
2.5.0

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

* [PATCH V2 10/15] coresight: tmc: dump system memory content only when needed
@ 2016-04-12 17:54   ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

Calling tmc_etf/etr_dump_hw() is required only when operating from
sysFS.  When working from Perf, the system memory is harvested
from the AUX trace API.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 7 ++++++-
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 7 ++++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 5908000e1ae0..9b4cdaed09f5 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -74,7 +74,12 @@ static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
 	CS_UNLOCK(drvdata->base);
 
 	tmc_flush_and_stop(drvdata);
-	tmc_etb_dump_hw(drvdata);
+	/*
+	 * When operating in sysFS mode the content of the buffer needs to be
+	 * read before the TMC is disabled.
+	 */
+	if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
+		tmc_etb_dump_hw(drvdata);
 	tmc_disable_hw(drvdata);
 
 	CS_LOCK(drvdata->base);
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 8e6fe267195a..de5cf0056802 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -76,7 +76,12 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 	CS_UNLOCK(drvdata->base);
 
 	tmc_flush_and_stop(drvdata);
-	tmc_etr_dump_hw(drvdata);
+	/*
+	 * When operating in sysFS mode the content of the buffer needs to be
+	 * read before the TMC is disabled.
+	 */
+	if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
+		tmc_etr_dump_hw(drvdata);
 	tmc_disable_hw(drvdata);
 
 	CS_LOCK(drvdata->base);
-- 
2.5.0

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

* [PATCH V2 11/15] coresight: tmc: make sysFS and Perf mode mutually exclusive
  2016-04-12 17:54 ` Mathieu Poirier
@ 2016-04-12 17:54   ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

The sysFS and Perf access methods can't be allowed to interfere
with one another.  As such introducing guards to access
functions that prevents moving forward if a TMC is already
being used.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 59 +++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 67 +++++++++++++++++++++++--
 2 files changed, 119 insertions(+), 7 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 9b4cdaed09f5..50d32e8ef4ea 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -111,7 +111,7 @@ static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
 	CS_LOCK(drvdata->base);
 }
 
-static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
+static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev, u32 mode)
 {
 	bool allocated = false;
 	char *buf = NULL;
@@ -189,6 +189,53 @@ out:
 	return 0;
 }
 
+static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, u32 mode)
+{
+	int ret = 0;
+	u32 val;
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	 /* This shouldn't be happening */
+	WARN_ON(mode != CS_MODE_PERF);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	val = local_xchg(&drvdata->mode, mode);
+	/*
+	 * In Perf mode there can be only one writer per sink.  There
+	 * is also no need to continue if the ETB/ETR is already operated
+	 * from sysFS.
+	 */
+	if (val != CS_MODE_DISABLED) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	tmc_etb_enable_hw(drvdata);
+out:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	return ret;
+}
+
+static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
+{
+	switch (mode) {
+	case CS_MODE_SYSFS:
+		return tmc_enable_etf_sink_sysfs(csdev, mode);
+	case CS_MODE_PERF:
+		return tmc_enable_etf_sink_perf(csdev, mode);
+	}
+
+	/* We shouldn't be here */
+	return -EINVAL;
+}
+
 static void tmc_disable_etf_sink(struct coresight_device *csdev)
 {
 	u32 val;
@@ -271,6 +318,7 @@ const struct coresight_ops tmc_etf_cs_ops = {
 
 int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
 {
+	u32 val;
 	enum tmc_mode mode;
 	int ret = 0;
 	unsigned long flags;
@@ -289,6 +337,13 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
 		goto out;
 	}
 
+	val = local_read(&drvdata->mode);
+	/* Don't interfere if operated from Perf */
+	if (val == CS_MODE_PERF) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/* If drvdata::buf is NULL the trace data has been read already */
 	if (drvdata->buf == NULL) {
 		ret = -EINVAL;
@@ -296,7 +351,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
 	}
 
 	/* Disable the TMC if need be */
-	if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
+	if (val == CS_MODE_SYSFS)
 		tmc_etb_disable_hw(drvdata);
 
 	drvdata->reading = true;
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index de5cf0056802..04fc63d85696 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -87,7 +87,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 	CS_LOCK(drvdata->base);
 }
 
-static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
+static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev, u32 mode)
 {
 	bool allocated = false;
 	u32 val;
@@ -166,6 +166,53 @@ out:
 	return 0;
 }
 
+static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, u32 mode)
+{
+	int ret = 0;
+	u32 val;
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	 /* This shouldn't be happening */
+	WARN_ON(mode != CS_MODE_PERF);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	val = local_xchg(&drvdata->mode, mode);
+	/*
+	 * In Perf mode there can be only one writer per sink.  There
+	 * is also no need to continue if the ETR is already operated
+	 * from sysFS.
+	 */
+	if (val != CS_MODE_DISABLED) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	tmc_etr_enable_hw(drvdata);
+out:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	return ret;
+}
+
+static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
+{
+	switch (mode) {
+	case CS_MODE_SYSFS:
+		return tmc_enable_etr_sink_sysfs(csdev, mode);
+	case CS_MODE_PERF:
+		return tmc_enable_etr_sink_perf(csdev, mode);
+	}
+
+	/* We shouldn't be here */
+	return -EINVAL;
+}
+
 static void tmc_disable_etr_sink(struct coresight_device *csdev)
 {
 	u32 val;
@@ -199,6 +246,8 @@ const struct coresight_ops tmc_etr_cs_ops = {
 
 int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
 {
+	int ret = 0;
+	u32 val;
 	unsigned long flags;
 
 	/* config types are set a boot time and never change */
@@ -207,20 +256,28 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
 
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 
+	val = local_read(&drvdata->mode);
+	/* Don't interfere if operated from Perf */
+	if (val == CS_MODE_PERF) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/* If drvdata::buf is NULL the trace data has been read already */
 	if (drvdata->buf == NULL) {
-		spin_unlock_irqrestore(&drvdata->spinlock, flags);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
 	/* Disable the TMC if need be */
-	if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
+	if (val == CS_MODE_SYSFS)
 		tmc_etr_disable_hw(drvdata);
 
 	drvdata->reading = true;
+out:
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
-	return 0;
+	return ret;
 }
 
 int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
-- 
2.5.0

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

* [PATCH V2 11/15] coresight: tmc: make sysFS and Perf mode mutually exclusive
@ 2016-04-12 17:54   ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

The sysFS and Perf access methods can't be allowed to interfere
with one another.  As such introducing guards to access
functions that prevents moving forward if a TMC is already
being used.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 59 +++++++++++++++++++++-
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 67 +++++++++++++++++++++++--
 2 files changed, 119 insertions(+), 7 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 9b4cdaed09f5..50d32e8ef4ea 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -111,7 +111,7 @@ static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
 	CS_LOCK(drvdata->base);
 }
 
-static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
+static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev, u32 mode)
 {
 	bool allocated = false;
 	char *buf = NULL;
@@ -189,6 +189,53 @@ out:
 	return 0;
 }
 
+static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, u32 mode)
+{
+	int ret = 0;
+	u32 val;
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	 /* This shouldn't be happening */
+	WARN_ON(mode != CS_MODE_PERF);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	val = local_xchg(&drvdata->mode, mode);
+	/*
+	 * In Perf mode there can be only one writer per sink.  There
+	 * is also no need to continue if the ETB/ETR is already operated
+	 * from sysFS.
+	 */
+	if (val != CS_MODE_DISABLED) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	tmc_etb_enable_hw(drvdata);
+out:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	return ret;
+}
+
+static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
+{
+	switch (mode) {
+	case CS_MODE_SYSFS:
+		return tmc_enable_etf_sink_sysfs(csdev, mode);
+	case CS_MODE_PERF:
+		return tmc_enable_etf_sink_perf(csdev, mode);
+	}
+
+	/* We shouldn't be here */
+	return -EINVAL;
+}
+
 static void tmc_disable_etf_sink(struct coresight_device *csdev)
 {
 	u32 val;
@@ -271,6 +318,7 @@ const struct coresight_ops tmc_etf_cs_ops = {
 
 int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
 {
+	u32 val;
 	enum tmc_mode mode;
 	int ret = 0;
 	unsigned long flags;
@@ -289,6 +337,13 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
 		goto out;
 	}
 
+	val = local_read(&drvdata->mode);
+	/* Don't interfere if operated from Perf */
+	if (val == CS_MODE_PERF) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/* If drvdata::buf is NULL the trace data has been read already */
 	if (drvdata->buf == NULL) {
 		ret = -EINVAL;
@@ -296,7 +351,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
 	}
 
 	/* Disable the TMC if need be */
-	if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
+	if (val == CS_MODE_SYSFS)
 		tmc_etb_disable_hw(drvdata);
 
 	drvdata->reading = true;
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index de5cf0056802..04fc63d85696 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -87,7 +87,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
 	CS_LOCK(drvdata->base);
 }
 
-static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
+static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev, u32 mode)
 {
 	bool allocated = false;
 	u32 val;
@@ -166,6 +166,53 @@ out:
 	return 0;
 }
 
+static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, u32 mode)
+{
+	int ret = 0;
+	u32 val;
+	unsigned long flags;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	 /* This shouldn't be happening */
+	WARN_ON(mode != CS_MODE_PERF);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	val = local_xchg(&drvdata->mode, mode);
+	/*
+	 * In Perf mode there can be only one writer per sink.  There
+	 * is also no need to continue if the ETR is already operated
+	 * from sysFS.
+	 */
+	if (val != CS_MODE_DISABLED) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	tmc_etr_enable_hw(drvdata);
+out:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	return ret;
+}
+
+static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
+{
+	switch (mode) {
+	case CS_MODE_SYSFS:
+		return tmc_enable_etr_sink_sysfs(csdev, mode);
+	case CS_MODE_PERF:
+		return tmc_enable_etr_sink_perf(csdev, mode);
+	}
+
+	/* We shouldn't be here */
+	return -EINVAL;
+}
+
 static void tmc_disable_etr_sink(struct coresight_device *csdev)
 {
 	u32 val;
@@ -199,6 +246,8 @@ const struct coresight_ops tmc_etr_cs_ops = {
 
 int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
 {
+	int ret = 0;
+	u32 val;
 	unsigned long flags;
 
 	/* config types are set a boot time and never change */
@@ -207,20 +256,28 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
 
 	spin_lock_irqsave(&drvdata->spinlock, flags);
 
+	val = local_read(&drvdata->mode);
+	/* Don't interfere if operated from Perf */
+	if (val == CS_MODE_PERF) {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/* If drvdata::buf is NULL the trace data has been read already */
 	if (drvdata->buf == NULL) {
-		spin_unlock_irqrestore(&drvdata->spinlock, flags);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
 	/* Disable the TMC if need be */
-	if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
+	if (val == CS_MODE_SYSFS)
 		tmc_etr_disable_hw(drvdata);
 
 	drvdata->reading = true;
+out:
 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
-	return 0;
+	return ret;
 }
 
 int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
-- 
2.5.0

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

* [PATCH V2 12/15] coresight: tmc: keep track of memory width
  2016-04-12 17:54 ` Mathieu Poirier
@ 2016-04-12 17:54   ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

Accessing the HW configuration register each time the memory
width is needed simply doesn't make sense.  It is much more
efficient to read the value once and keep a reference for
later use.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 8 +++-----
 drivers/hwtracing/coresight/coresight-tmc.c     | 1 +
 drivers/hwtracing/coresight/coresight-tmc.h     | 2 ++
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 50d32e8ef4ea..a440784e3b27 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -41,18 +41,16 @@ void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
 
 static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
 {
-	enum tmc_mem_intf_width memwidth;
 	u8 memwords;
 	char *bufp;
 	u32 read_data;
 	int i;
 
-	memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID), 8, 10);
-	if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
+	if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_32BITS)
 		memwords = 1;
-	else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
+	else if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_64BITS)
 		memwords = 2;
-	else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
+	else if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_128BITS)
 		memwords = 4;
 	else
 		memwords = 8;
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 4d7b64f69389..bc013d5f71c3 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -306,6 +306,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
 
 	devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
 	drvdata->config_type = BMVAL(devid, 6, 7);
+	drvdata->memwidth = BMVAL(devid, 8, 10);
 
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
 		if (np)
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 821bdf150ac9..062dd7dcea96 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -102,6 +102,7 @@ enum tmc_mem_intf_width {
  * @size:	@buf size.
  * @mode:	how this TMC is being used.
  * @config_type: TMC variant, must be of type @tmc_config_type.
+ * @memwidth:	width of the memory interface databus, powers of two.
  * @trigger_cntr: amount of words to store after a trigger.
  */
 struct tmc_drvdata {
@@ -118,6 +119,7 @@ struct tmc_drvdata {
 	u32			size;
 	local_t			mode;
 	enum tmc_config_type	config_type;
+	enum tmc_mem_intf_width	memwidth;
 	u32			trigger_cntr;
 };
 
-- 
2.5.0

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

* [PATCH V2 12/15] coresight: tmc: keep track of memory width
@ 2016-04-12 17:54   ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

Accessing the HW configuration register each time the memory
width is needed simply doesn't make sense.  It is much more
efficient to read the value once and keep a reference for
later use.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 8 +++-----
 drivers/hwtracing/coresight/coresight-tmc.c     | 1 +
 drivers/hwtracing/coresight/coresight-tmc.h     | 2 ++
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 50d32e8ef4ea..a440784e3b27 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -41,18 +41,16 @@ void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
 
 static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
 {
-	enum tmc_mem_intf_width memwidth;
 	u8 memwords;
 	char *bufp;
 	u32 read_data;
 	int i;
 
-	memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID), 8, 10);
-	if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
+	if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_32BITS)
 		memwords = 1;
-	else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
+	else if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_64BITS)
 		memwords = 2;
-	else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
+	else if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_128BITS)
 		memwords = 4;
 	else
 		memwords = 8;
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 4d7b64f69389..bc013d5f71c3 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -306,6 +306,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
 
 	devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
 	drvdata->config_type = BMVAL(devid, 6, 7);
+	drvdata->memwidth = BMVAL(devid, 8, 10);
 
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
 		if (np)
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 821bdf150ac9..062dd7dcea96 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -102,6 +102,7 @@ enum tmc_mem_intf_width {
  * @size:	@buf size.
  * @mode:	how this TMC is being used.
  * @config_type: TMC variant, must be of type @tmc_config_type.
+ * @memwidth:	width of the memory interface databus, powers of two.
  * @trigger_cntr: amount of words to store after a trigger.
  */
 struct tmc_drvdata {
@@ -118,6 +119,7 @@ struct tmc_drvdata {
 	u32			size;
 	local_t			mode;
 	enum tmc_config_type	config_type;
+	enum tmc_mem_intf_width	memwidth;
 	u32			trigger_cntr;
 };
 
-- 
2.5.0

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

* [PATCH V2 13/15] coresight: tmc: implementing TMC-ETF AUX space API
  2016-04-12 17:54 ` Mathieu Poirier
@ 2016-04-12 17:54   ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

This patch implement the AUX area interfaces required to
use the TMC (configured as an ETF) from the Perf sub-system.

The heuristic is heavily borrowed from the ETB10 implementation.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 198 ++++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tmc.h     |  21 +++
 2 files changed, 219 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index a440784e3b27..fff175d4020d 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -15,7 +15,9 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/circ_buf.h>
 #include <linux/coresight.h>
+#include <linux/perf_event.h>
 #include <linux/slab.h>
 #include "coresight-priv.h"
 #include "coresight-tmc.h"
@@ -295,9 +297,205 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
 	dev_info(drvdata->dev, "TMC disabled\n");
 }
 
+static void *tmc_alloc_etf_buffer(struct coresight_device *csdev, int cpu,
+				  void **pages, int nr_pages, bool overwrite)
+{
+	int node;
+	struct cs_tmc_buffers *buf;
+
+	if (cpu == -1)
+		cpu = smp_processor_id();
+	node = cpu_to_node(cpu);
+
+	/* Allocate memory structure for interaction with Perf */
+	buf = kzalloc_node(sizeof(struct cs_tmc_buffers), GFP_KERNEL, node);
+	if (!buf)
+		return NULL;
+
+	buf->snapshot = overwrite;
+	buf->nr_pages = nr_pages;
+	buf->data_pages = pages;
+
+	return buf;
+}
+
+static void tmc_free_etf_buffer(void *config)
+{
+	struct cs_tmc_buffers *buf = config;
+
+	kfree(buf);
+}
+
+static int tmc_set_etf_buffer(struct coresight_device *csdev,
+			      struct perf_output_handle *handle,
+			      void *sink_config)
+{
+	int ret = 0;
+	unsigned long head;
+	struct cs_tmc_buffers *buf = sink_config;
+
+	/* wrap head around to the amount of space we have */
+	head = handle->head & ((buf->nr_pages << PAGE_SHIFT) - 1);
+
+	/* find the page to write to */
+	buf->cur = head / PAGE_SIZE;
+
+	/* and offset within that page */
+	buf->offset = head % PAGE_SIZE;
+
+	local_set(&buf->data_size, 0);
+
+	return ret;
+}
+
+static unsigned long tmc_reset_etf_buffer(struct coresight_device *csdev,
+					  struct perf_output_handle *handle,
+					  void *sink_config, bool *lost)
+{
+	unsigned long size = 0;
+	struct cs_tmc_buffers *buf = sink_config;
+
+	if (buf) {
+		/*
+		 * In snapshot mode ->data_size holds the new address of the
+		 * ring buffer's head.  The size itself is the whole address
+		 * range since we want the latest information.
+		 */
+		if (buf->snapshot)
+			handle->head = local_xchg(&buf->data_size,
+						  buf->nr_pages << PAGE_SHIFT);
+		/*
+		 * Tell the tracer PMU how much we got in this run and if
+		 * something went wrong along the way.  Nobody else can use
+		 * this cs_tmc_buffers instance until we are done.  As such
+		 * resetting parameters here and squaring off with the ring
+		 * buffer API in the tracer PMU is fine.
+		 */
+		*lost = !!local_xchg(&buf->lost, 0);
+		size = local_xchg(&buf->data_size, 0);
+	}
+
+	return size;
+}
+
+static void tmc_update_etf_buffer(struct coresight_device *csdev,
+				  struct perf_output_handle *handle,
+				  void *sink_config)
+{
+	int i, cur;
+	u32 *buf_ptr;
+	u32 read_ptr, write_ptr;
+	u32 status, to_read;
+	unsigned long offset;
+	struct cs_tmc_buffers *buf = sink_config;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	if (!buf)
+		return;
+
+	/* This shouldn't happen */
+	if (WARN_ON_ONCE(local_read(&drvdata->mode) != CS_MODE_PERF))
+		return;
+
+	CS_UNLOCK(drvdata->base);
+
+	tmc_flush_and_stop(drvdata);
+
+	read_ptr = readl_relaxed(drvdata->base + TMC_RRP);
+	write_ptr = readl_relaxed(drvdata->base + TMC_RWP);
+
+	/*
+	 * Get a hold of the status register and see if a wrap around
+	 * has occurred.  If so adjust things accordingly.
+	 */
+	status = readl_relaxed(drvdata->base + TMC_STS);
+	if (status & TMC_STS_FULL) {
+		local_inc(&buf->lost);
+		to_read = drvdata->size;
+	} else {
+		to_read = CIRC_CNT(write_ptr, read_ptr, drvdata->size);
+	}
+
+	/*
+	 * The TMC RAM buffer may be bigger than the space available in the
+	 * perf ring buffer (handle->size).  If so advance the RRP so that we
+	 * get the latest trace data.
+	 */
+	if (to_read > handle->size) {
+		u32 mask = 0;
+
+		/*
+		 * The value written to RRP must be byte-address aligned to
+		 * the width of the trace memory databus _and_ to a frame
+		 * boundary (16 byte), whichever is the biggest. For example,
+		 * for 32-bit, 64-bit and 128-bit wide trace memory, the four
+		 * LSBs must be 0s. For 256-bit wide trace memory, the five
+		 * LSBs must be 0s.
+		 */
+		switch (drvdata->memwidth) {
+		case TMC_MEM_INTF_WIDTH_32BITS:
+		case TMC_MEM_INTF_WIDTH_64BITS:
+		case TMC_MEM_INTF_WIDTH_128BITS:
+			mask = GENMASK(31, 5);
+			break;
+		case TMC_MEM_INTF_WIDTH_256BITS:
+			mask = GENMASK(31, 6);
+			break;
+		}
+
+		/*
+		 * Make sure the new size is aligned in accordance with the
+		 * requirement explained above.
+		 */
+		to_read -= handle->size & mask;
+		/* Move the RAM read pointer up */
+		read_ptr = (write_ptr + drvdata->size) - to_read;
+		/* Make sure we are still within our limits */
+		read_ptr &= ~(drvdata->size - 1);
+		/* Tell the HW */
+		writel_relaxed(read_ptr, drvdata->base + TMC_RRP);
+		local_inc(&buf->lost);
+	}
+
+	cur = buf->cur;
+	offset = buf->offset;
+
+	/* for every byte to read */
+	for (i = 0; i < to_read; i += 4) {
+		buf_ptr = buf->data_pages[cur] + offset;
+		*buf_ptr = readl_relaxed(drvdata->base + TMC_RRD);
+
+		offset += 4;
+		if (offset >= PAGE_SIZE) {
+			offset = 0;
+			cur++;
+			/* wrap around at the end of the buffer */
+			cur &= buf->nr_pages - 1;
+		}
+	}
+
+	/*
+	 * In snapshot mode all we have to do is communicate to
+	 * perf_aux_output_end() the address of the current head.  In full
+	 * trace mode the same function expects a size to move rb->aux_head
+	 * forward.
+	 */
+	if (buf->snapshot)
+		local_set(&buf->data_size, (cur * PAGE_SIZE) + offset);
+	else
+		local_add(to_read, &buf->data_size);
+
+	CS_LOCK(drvdata->base);
+}
+
 static const struct coresight_ops_sink tmc_etf_sink_ops = {
 	.enable		= tmc_enable_etf_sink,
 	.disable	= tmc_disable_etf_sink,
+	.alloc_buffer	= tmc_alloc_etf_buffer,
+	.free_buffer	= tmc_free_etf_buffer,
+	.set_buffer	= tmc_set_etf_buffer,
+	.reset_buffer	= tmc_reset_etf_buffer,
+	.update_buffer	= tmc_update_etf_buffer,
 };
 
 static const struct coresight_ops_link tmc_etf_link_ops = {
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 062dd7dcea96..62d568195e8e 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -51,6 +51,7 @@
 /* TMC_CTL - 0x020 */
 #define TMC_CTL_CAPT_EN		BIT(0)
 /* TMC_STS - 0x00C */
+#define TMC_STS_FULL		BIT(0)
 #define TMC_STS_TRIGGERED	BIT(1)
 /* TMC_AXICTL - 0x110 */
 #define TMC_AXICTL_PROT_CTL_B0	BIT(0)
@@ -89,6 +90,26 @@ enum tmc_mem_intf_width {
 };
 
 /**
+ * struct cs_buffer - keep track of a recording session' specifics
+ * @cur:	index of the current buffer
+ * @nr_pages:	max number of pages granted to us
+ * @offset:	offset within the current buffer
+ * @data_size:	how much we collected in this run
+ * @lost:	other than zero if we had a HW buffer wrap around
+ * @snapshot:	is this run in snapshot mode
+ * @data_pages:	a handle the ring buffer
+ */
+struct cs_tmc_buffers {
+	unsigned int		cur;
+	unsigned int		nr_pages;
+	unsigned long		offset;
+	local_t			data_size;
+	local_t			lost;
+	bool			snapshot;
+	void			**data_pages;
+};
+
+/**
  * struct tmc_drvdata - specifics associated to an TMC component
  * @base:	memory mapped base address for this component.
  * @dev:	the device entity associated to this component.
-- 
2.5.0

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

* [PATCH V2 13/15] coresight: tmc: implementing TMC-ETF AUX space API
@ 2016-04-12 17:54   ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

This patch implement the AUX area interfaces required to
use the TMC (configured as an ETF) from the Perf sub-system.

The heuristic is heavily borrowed from the ETB10 implementation.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c | 198 ++++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tmc.h     |  21 +++
 2 files changed, 219 insertions(+)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index a440784e3b27..fff175d4020d 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -15,7 +15,9 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/circ_buf.h>
 #include <linux/coresight.h>
+#include <linux/perf_event.h>
 #include <linux/slab.h>
 #include "coresight-priv.h"
 #include "coresight-tmc.h"
@@ -295,9 +297,205 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
 	dev_info(drvdata->dev, "TMC disabled\n");
 }
 
+static void *tmc_alloc_etf_buffer(struct coresight_device *csdev, int cpu,
+				  void **pages, int nr_pages, bool overwrite)
+{
+	int node;
+	struct cs_tmc_buffers *buf;
+
+	if (cpu == -1)
+		cpu = smp_processor_id();
+	node = cpu_to_node(cpu);
+
+	/* Allocate memory structure for interaction with Perf */
+	buf = kzalloc_node(sizeof(struct cs_tmc_buffers), GFP_KERNEL, node);
+	if (!buf)
+		return NULL;
+
+	buf->snapshot = overwrite;
+	buf->nr_pages = nr_pages;
+	buf->data_pages = pages;
+
+	return buf;
+}
+
+static void tmc_free_etf_buffer(void *config)
+{
+	struct cs_tmc_buffers *buf = config;
+
+	kfree(buf);
+}
+
+static int tmc_set_etf_buffer(struct coresight_device *csdev,
+			      struct perf_output_handle *handle,
+			      void *sink_config)
+{
+	int ret = 0;
+	unsigned long head;
+	struct cs_tmc_buffers *buf = sink_config;
+
+	/* wrap head around to the amount of space we have */
+	head = handle->head & ((buf->nr_pages << PAGE_SHIFT) - 1);
+
+	/* find the page to write to */
+	buf->cur = head / PAGE_SIZE;
+
+	/* and offset within that page */
+	buf->offset = head % PAGE_SIZE;
+
+	local_set(&buf->data_size, 0);
+
+	return ret;
+}
+
+static unsigned long tmc_reset_etf_buffer(struct coresight_device *csdev,
+					  struct perf_output_handle *handle,
+					  void *sink_config, bool *lost)
+{
+	unsigned long size = 0;
+	struct cs_tmc_buffers *buf = sink_config;
+
+	if (buf) {
+		/*
+		 * In snapshot mode ->data_size holds the new address of the
+		 * ring buffer's head.  The size itself is the whole address
+		 * range since we want the latest information.
+		 */
+		if (buf->snapshot)
+			handle->head = local_xchg(&buf->data_size,
+						  buf->nr_pages << PAGE_SHIFT);
+		/*
+		 * Tell the tracer PMU how much we got in this run and if
+		 * something went wrong along the way.  Nobody else can use
+		 * this cs_tmc_buffers instance until we are done.  As such
+		 * resetting parameters here and squaring off with the ring
+		 * buffer API in the tracer PMU is fine.
+		 */
+		*lost = !!local_xchg(&buf->lost, 0);
+		size = local_xchg(&buf->data_size, 0);
+	}
+
+	return size;
+}
+
+static void tmc_update_etf_buffer(struct coresight_device *csdev,
+				  struct perf_output_handle *handle,
+				  void *sink_config)
+{
+	int i, cur;
+	u32 *buf_ptr;
+	u32 read_ptr, write_ptr;
+	u32 status, to_read;
+	unsigned long offset;
+	struct cs_tmc_buffers *buf = sink_config;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	if (!buf)
+		return;
+
+	/* This shouldn't happen */
+	if (WARN_ON_ONCE(local_read(&drvdata->mode) != CS_MODE_PERF))
+		return;
+
+	CS_UNLOCK(drvdata->base);
+
+	tmc_flush_and_stop(drvdata);
+
+	read_ptr = readl_relaxed(drvdata->base + TMC_RRP);
+	write_ptr = readl_relaxed(drvdata->base + TMC_RWP);
+
+	/*
+	 * Get a hold of the status register and see if a wrap around
+	 * has occurred.  If so adjust things accordingly.
+	 */
+	status = readl_relaxed(drvdata->base + TMC_STS);
+	if (status & TMC_STS_FULL) {
+		local_inc(&buf->lost);
+		to_read = drvdata->size;
+	} else {
+		to_read = CIRC_CNT(write_ptr, read_ptr, drvdata->size);
+	}
+
+	/*
+	 * The TMC RAM buffer may be bigger than the space available in the
+	 * perf ring buffer (handle->size).  If so advance the RRP so that we
+	 * get the latest trace data.
+	 */
+	if (to_read > handle->size) {
+		u32 mask = 0;
+
+		/*
+		 * The value written to RRP must be byte-address aligned to
+		 * the width of the trace memory databus _and_ to a frame
+		 * boundary (16 byte), whichever is the biggest. For example,
+		 * for 32-bit, 64-bit and 128-bit wide trace memory, the four
+		 * LSBs must be 0s. For 256-bit wide trace memory, the five
+		 * LSBs must be 0s.
+		 */
+		switch (drvdata->memwidth) {
+		case TMC_MEM_INTF_WIDTH_32BITS:
+		case TMC_MEM_INTF_WIDTH_64BITS:
+		case TMC_MEM_INTF_WIDTH_128BITS:
+			mask = GENMASK(31, 5);
+			break;
+		case TMC_MEM_INTF_WIDTH_256BITS:
+			mask = GENMASK(31, 6);
+			break;
+		}
+
+		/*
+		 * Make sure the new size is aligned in accordance with the
+		 * requirement explained above.
+		 */
+		to_read -= handle->size & mask;
+		/* Move the RAM read pointer up */
+		read_ptr = (write_ptr + drvdata->size) - to_read;
+		/* Make sure we are still within our limits */
+		read_ptr &= ~(drvdata->size - 1);
+		/* Tell the HW */
+		writel_relaxed(read_ptr, drvdata->base + TMC_RRP);
+		local_inc(&buf->lost);
+	}
+
+	cur = buf->cur;
+	offset = buf->offset;
+
+	/* for every byte to read */
+	for (i = 0; i < to_read; i += 4) {
+		buf_ptr = buf->data_pages[cur] + offset;
+		*buf_ptr = readl_relaxed(drvdata->base + TMC_RRD);
+
+		offset += 4;
+		if (offset >= PAGE_SIZE) {
+			offset = 0;
+			cur++;
+			/* wrap around at the end of the buffer */
+			cur &= buf->nr_pages - 1;
+		}
+	}
+
+	/*
+	 * In snapshot mode all we have to do is communicate to
+	 * perf_aux_output_end() the address of the current head.  In full
+	 * trace mode the same function expects a size to move rb->aux_head
+	 * forward.
+	 */
+	if (buf->snapshot)
+		local_set(&buf->data_size, (cur * PAGE_SIZE) + offset);
+	else
+		local_add(to_read, &buf->data_size);
+
+	CS_LOCK(drvdata->base);
+}
+
 static const struct coresight_ops_sink tmc_etf_sink_ops = {
 	.enable		= tmc_enable_etf_sink,
 	.disable	= tmc_disable_etf_sink,
+	.alloc_buffer	= tmc_alloc_etf_buffer,
+	.free_buffer	= tmc_free_etf_buffer,
+	.set_buffer	= tmc_set_etf_buffer,
+	.reset_buffer	= tmc_reset_etf_buffer,
+	.update_buffer	= tmc_update_etf_buffer,
 };
 
 static const struct coresight_ops_link tmc_etf_link_ops = {
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 062dd7dcea96..62d568195e8e 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -51,6 +51,7 @@
 /* TMC_CTL - 0x020 */
 #define TMC_CTL_CAPT_EN		BIT(0)
 /* TMC_STS - 0x00C */
+#define TMC_STS_FULL		BIT(0)
 #define TMC_STS_TRIGGERED	BIT(1)
 /* TMC_AXICTL - 0x110 */
 #define TMC_AXICTL_PROT_CTL_B0	BIT(0)
@@ -89,6 +90,26 @@ enum tmc_mem_intf_width {
 };
 
 /**
+ * struct cs_buffer - keep track of a recording session' specifics
+ * @cur:	index of the current buffer
+ * @nr_pages:	max number of pages granted to us
+ * @offset:	offset within the current buffer
+ * @data_size:	how much we collected in this run
+ * @lost:	other than zero if we had a HW buffer wrap around
+ * @snapshot:	is this run in snapshot mode
+ * @data_pages:	a handle the ring buffer
+ */
+struct cs_tmc_buffers {
+	unsigned int		cur;
+	unsigned int		nr_pages;
+	unsigned long		offset;
+	local_t			data_size;
+	local_t			lost;
+	bool			snapshot;
+	void			**data_pages;
+};
+
+/**
  * struct tmc_drvdata - specifics associated to an TMC component
  * @base:	memory mapped base address for this component.
  * @dev:	the device entity associated to this component.
-- 
2.5.0

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

* [PATCH V2 14/15] coresight: tmc: implementing TMC-ETR AUX space API
  2016-04-12 17:54 ` Mathieu Poirier
@ 2016-04-12 17:54   ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

This patch implement the AUX area interfaces required to
use the TMC (configured as an ETR) from the Perf sub-system.

The heuristic is heavily borrowed from the ETB10 and TMC-ETF
implementation.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c |   6 +-
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 142 ++++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tmc.h     |   3 +
 3 files changed, 148 insertions(+), 3 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index fff175d4020d..6a449e2ddf5f 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -378,9 +378,9 @@ static unsigned long tmc_reset_etf_buffer(struct coresight_device *csdev,
 	return size;
 }
 
-static void tmc_update_etf_buffer(struct coresight_device *csdev,
-				  struct perf_output_handle *handle,
-				  void *sink_config)
+void tmc_update_etf_buffer(struct coresight_device *csdev,
+			   struct perf_output_handle *handle,
+			   void *sink_config)
 {
 	int i, cur;
 	u32 *buf_ptr;
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 04fc63d85696..bf12a6854a5f 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -15,11 +15,30 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/circ_buf.h>
 #include <linux/coresight.h>
 #include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
 #include "coresight-priv.h"
 #include "coresight-tmc.h"
 
+/**
+ * struct cs_etr_buffer - keep track of a recording session' specifics
+ * @tmc:	generic portion of the TMC buffers
+ * @paddr:	the physical address of a DMA'able contiguous memory area
+ * @vaddr:	the virtual address associated to @paddr
+ * @size:	how much memory we have, starting at @paddr
+ * @dev:	the device @vaddr has been tied to
+ */
+struct cs_etr_buffers {
+	struct cs_tmc_buffers	tmc;
+	dma_addr_t		paddr;
+	void __iomem		*vaddr;
+	u32			size;
+	struct device		*dev;
+};
+
 void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
 {
 	u32 axictl;
@@ -235,9 +254,132 @@ static void tmc_disable_etr_sink(struct coresight_device *csdev)
 	dev_info(drvdata->dev, "TMC-ETR disabled\n");
 }
 
+static void *tmc_alloc_etr_buffer(struct coresight_device *csdev, int cpu,
+				  void **pages, int nr_pages, bool overwrite)
+{
+	int node;
+	struct cs_etr_buffers *buf;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	if (cpu == -1)
+		cpu = smp_processor_id();
+	node = cpu_to_node(cpu);
+
+	/* Allocate memory structure for interaction with Perf */
+	buf = kzalloc_node(sizeof(struct cs_etr_buffers), GFP_KERNEL, node);
+	if (!buf)
+		return NULL;
+
+	buf->dev = drvdata->dev;
+	buf->size = drvdata->size;
+	buf->vaddr = dma_alloc_coherent(buf->dev, buf->size,
+					&buf->paddr, GFP_KERNEL);
+	if (!buf->vaddr) {
+		kfree(buf);
+		return NULL;
+	}
+
+	buf->tmc.snapshot = overwrite;
+	buf->tmc.nr_pages = nr_pages;
+	buf->tmc.data_pages = pages;
+
+	return buf;
+}
+
+static void tmc_free_etr_buffer(void *config)
+{
+	struct cs_etr_buffers *buf = config;
+
+	dma_free_coherent(buf->dev, buf->size, buf->vaddr, buf->paddr);
+	kfree(buf);
+}
+
+static int tmc_set_etr_buffer(struct coresight_device *csdev,
+			      struct perf_output_handle *handle,
+			      void *sink_config)
+{
+	int ret = 0;
+	unsigned long head;
+	struct cs_etr_buffers *buf = sink_config;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	/* wrap head around to the amount of space we have */
+	head = handle->head & ((buf->tmc.nr_pages << PAGE_SHIFT) - 1);
+
+	/* find the page to write to */
+	buf->tmc.cur = head / PAGE_SIZE;
+
+	/* and offset within that page */
+	buf->tmc.offset = head % PAGE_SIZE;
+
+	local_set(&buf->tmc.data_size, 0);
+
+	/* Tell the HW where to put the trace data */
+	drvdata->vaddr = buf->vaddr;
+	drvdata->paddr = buf->paddr;
+	memset(drvdata->vaddr, 0, drvdata->size);
+
+	return ret;
+}
+
+static unsigned long tmc_reset_etr_buffer(struct coresight_device *csdev,
+					  struct perf_output_handle *handle,
+					  void *sink_config, bool *lost)
+{
+	unsigned long size = 0;
+	struct cs_etr_buffers *buf = sink_config;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	if (buf) {
+		/*
+		 * In snapshot mode ->data_size holds the new address of the
+		 * ring buffer's head.  The size itself is the whole address
+		 * range since we want the latest information.
+		 */
+		if (buf->tmc.snapshot) {
+			size = buf->tmc.nr_pages << PAGE_SHIFT;
+			handle->head = local_xchg(&buf->tmc.data_size, size);
+		}
+
+		/*
+		 * Tell the tracer PMU how much we got in this run and if
+		 * something went wrong along the way.  Nobody else can use
+		 * this cs_etr_buffers instance until we are done.  As such
+		 * resetting parameters here and squaring off with the ring
+		 * buffer API in the tracer PMU is fine.
+		 */
+		*lost = !!local_xchg(&buf->tmc.lost, 0);
+		size = local_xchg(&buf->tmc.data_size, 0);
+	}
+
+	/* Get ready for another run */
+	drvdata->vaddr = NULL;
+	drvdata->paddr = 0;
+
+	return size;
+}
+
+static void tmc_update_etr_buffer(struct coresight_device *csdev,
+				  struct perf_output_handle *handle,
+				  void *sink_config)
+{
+	struct cs_etr_buffers *buf = sink_config;
+
+	/*
+	 * An ETR configured to work in contiguous memory mode works the same
+	 * was as an ETB or ETF.
+	 */
+	tmc_update_etf_buffer(csdev, handle, &buf->tmc);
+}
+
 static const struct coresight_ops_sink tmc_etr_sink_ops = {
 	.enable		= tmc_enable_etr_sink,
 	.disable	= tmc_disable_etr_sink,
+	.alloc_buffer	= tmc_alloc_etr_buffer,
+	.free_buffer	= tmc_free_etr_buffer,
+	.set_buffer	= tmc_set_etr_buffer,
+	.reset_buffer	= tmc_reset_etr_buffer,
+	.update_buffer	= tmc_update_etr_buffer,
 };
 
 const struct coresight_ops tmc_etr_cs_ops = {
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 62d568195e8e..8f4ab9b511f2 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -153,6 +153,9 @@ void tmc_disable_hw(struct tmc_drvdata *drvdata);
 /* ETB/ETF functions */
 int tmc_read_prepare_etb(struct tmc_drvdata *drvdata);
 int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata);
+void tmc_update_etf_buffer(struct coresight_device *csdev,
+			   struct perf_output_handle *handle,
+			   void *sink_config);
 extern const struct coresight_ops tmc_etb_cs_ops;
 extern const struct coresight_ops tmc_etf_cs_ops;
 
-- 
2.5.0

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

* [PATCH V2 14/15] coresight: tmc: implementing TMC-ETR AUX space API
@ 2016-04-12 17:54   ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

This patch implement the AUX area interfaces required to
use the TMC (configured as an ETR) from the Perf sub-system.

The heuristic is heavily borrowed from the ETB10 and TMC-ETF
implementation.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight-tmc-etf.c |   6 +-
 drivers/hwtracing/coresight/coresight-tmc-etr.c | 142 ++++++++++++++++++++++++
 drivers/hwtracing/coresight/coresight-tmc.h     |   3 +
 3 files changed, 148 insertions(+), 3 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index fff175d4020d..6a449e2ddf5f 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -378,9 +378,9 @@ static unsigned long tmc_reset_etf_buffer(struct coresight_device *csdev,
 	return size;
 }
 
-static void tmc_update_etf_buffer(struct coresight_device *csdev,
-				  struct perf_output_handle *handle,
-				  void *sink_config)
+void tmc_update_etf_buffer(struct coresight_device *csdev,
+			   struct perf_output_handle *handle,
+			   void *sink_config)
 {
 	int i, cur;
 	u32 *buf_ptr;
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 04fc63d85696..bf12a6854a5f 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -15,11 +15,30 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/circ_buf.h>
 #include <linux/coresight.h>
 #include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
 #include "coresight-priv.h"
 #include "coresight-tmc.h"
 
+/**
+ * struct cs_etr_buffer - keep track of a recording session' specifics
+ * @tmc:	generic portion of the TMC buffers
+ * @paddr:	the physical address of a DMA'able contiguous memory area
+ * @vaddr:	the virtual address associated to @paddr
+ * @size:	how much memory we have, starting at @paddr
+ * @dev:	the device @vaddr has been tied to
+ */
+struct cs_etr_buffers {
+	struct cs_tmc_buffers	tmc;
+	dma_addr_t		paddr;
+	void __iomem		*vaddr;
+	u32			size;
+	struct device		*dev;
+};
+
 void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
 {
 	u32 axictl;
@@ -235,9 +254,132 @@ static void tmc_disable_etr_sink(struct coresight_device *csdev)
 	dev_info(drvdata->dev, "TMC-ETR disabled\n");
 }
 
+static void *tmc_alloc_etr_buffer(struct coresight_device *csdev, int cpu,
+				  void **pages, int nr_pages, bool overwrite)
+{
+	int node;
+	struct cs_etr_buffers *buf;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	if (cpu == -1)
+		cpu = smp_processor_id();
+	node = cpu_to_node(cpu);
+
+	/* Allocate memory structure for interaction with Perf */
+	buf = kzalloc_node(sizeof(struct cs_etr_buffers), GFP_KERNEL, node);
+	if (!buf)
+		return NULL;
+
+	buf->dev = drvdata->dev;
+	buf->size = drvdata->size;
+	buf->vaddr = dma_alloc_coherent(buf->dev, buf->size,
+					&buf->paddr, GFP_KERNEL);
+	if (!buf->vaddr) {
+		kfree(buf);
+		return NULL;
+	}
+
+	buf->tmc.snapshot = overwrite;
+	buf->tmc.nr_pages = nr_pages;
+	buf->tmc.data_pages = pages;
+
+	return buf;
+}
+
+static void tmc_free_etr_buffer(void *config)
+{
+	struct cs_etr_buffers *buf = config;
+
+	dma_free_coherent(buf->dev, buf->size, buf->vaddr, buf->paddr);
+	kfree(buf);
+}
+
+static int tmc_set_etr_buffer(struct coresight_device *csdev,
+			      struct perf_output_handle *handle,
+			      void *sink_config)
+{
+	int ret = 0;
+	unsigned long head;
+	struct cs_etr_buffers *buf = sink_config;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	/* wrap head around to the amount of space we have */
+	head = handle->head & ((buf->tmc.nr_pages << PAGE_SHIFT) - 1);
+
+	/* find the page to write to */
+	buf->tmc.cur = head / PAGE_SIZE;
+
+	/* and offset within that page */
+	buf->tmc.offset = head % PAGE_SIZE;
+
+	local_set(&buf->tmc.data_size, 0);
+
+	/* Tell the HW where to put the trace data */
+	drvdata->vaddr = buf->vaddr;
+	drvdata->paddr = buf->paddr;
+	memset(drvdata->vaddr, 0, drvdata->size);
+
+	return ret;
+}
+
+static unsigned long tmc_reset_etr_buffer(struct coresight_device *csdev,
+					  struct perf_output_handle *handle,
+					  void *sink_config, bool *lost)
+{
+	unsigned long size = 0;
+	struct cs_etr_buffers *buf = sink_config;
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	if (buf) {
+		/*
+		 * In snapshot mode ->data_size holds the new address of the
+		 * ring buffer's head.  The size itself is the whole address
+		 * range since we want the latest information.
+		 */
+		if (buf->tmc.snapshot) {
+			size = buf->tmc.nr_pages << PAGE_SHIFT;
+			handle->head = local_xchg(&buf->tmc.data_size, size);
+		}
+
+		/*
+		 * Tell the tracer PMU how much we got in this run and if
+		 * something went wrong along the way.  Nobody else can use
+		 * this cs_etr_buffers instance until we are done.  As such
+		 * resetting parameters here and squaring off with the ring
+		 * buffer API in the tracer PMU is fine.
+		 */
+		*lost = !!local_xchg(&buf->tmc.lost, 0);
+		size = local_xchg(&buf->tmc.data_size, 0);
+	}
+
+	/* Get ready for another run */
+	drvdata->vaddr = NULL;
+	drvdata->paddr = 0;
+
+	return size;
+}
+
+static void tmc_update_etr_buffer(struct coresight_device *csdev,
+				  struct perf_output_handle *handle,
+				  void *sink_config)
+{
+	struct cs_etr_buffers *buf = sink_config;
+
+	/*
+	 * An ETR configured to work in contiguous memory mode works the same
+	 * was as an ETB or ETF.
+	 */
+	tmc_update_etf_buffer(csdev, handle, &buf->tmc);
+}
+
 static const struct coresight_ops_sink tmc_etr_sink_ops = {
 	.enable		= tmc_enable_etr_sink,
 	.disable	= tmc_disable_etr_sink,
+	.alloc_buffer	= tmc_alloc_etr_buffer,
+	.free_buffer	= tmc_free_etr_buffer,
+	.set_buffer	= tmc_set_etr_buffer,
+	.reset_buffer	= tmc_reset_etr_buffer,
+	.update_buffer	= tmc_update_etr_buffer,
 };
 
 const struct coresight_ops tmc_etr_cs_ops = {
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 62d568195e8e..8f4ab9b511f2 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -153,6 +153,9 @@ void tmc_disable_hw(struct tmc_drvdata *drvdata);
 /* ETB/ETF functions */
 int tmc_read_prepare_etb(struct tmc_drvdata *drvdata);
 int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata);
+void tmc_update_etf_buffer(struct coresight_device *csdev,
+			   struct perf_output_handle *handle,
+			   void *sink_config);
 extern const struct coresight_ops tmc_etb_cs_ops;
 extern const struct coresight_ops tmc_etf_cs_ops;
 
-- 
2.5.0

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

* [PATCH V2 15/15] coresight: configuring ETF in FIFO mode when acting as link
  2016-04-12 17:54 ` Mathieu Poirier
@ 2016-04-12 17:54   ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel, Suzuki.Poulose; +Cc: linux-kernel

When part of a path but not identified as a sink, the EFT has to
be configured as a link and placed in HW FIFO mode.  As such when
enabling a path, call the right configuration function based on
the role the ETF if playing in this trace run.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight.c | 32 ++++++++++++++++++++++++++++----
 1 file changed, 28 insertions(+), 4 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c
index 2ea5961092c1..bba9f3d653c9 100644
--- a/drivers/hwtracing/coresight/coresight.c
+++ b/drivers/hwtracing/coresight/coresight.c
@@ -257,15 +257,27 @@ static void coresight_disable_source(struct coresight_device *csdev)
 
 void coresight_disable_path(struct list_head *path)
 {
+	u32 type;
 	struct coresight_node *nd;
 	struct coresight_device *csdev, *parent, *child;
 
 	list_for_each_entry(nd, path, link) {
 		csdev = nd->csdev;
+		type = csdev->type;
 
-		switch (csdev->type) {
+		/*
+		 * ETF devices are tricky... They can be a link or a sink,
+		 * depending on how they are configured.  If an ETF has been
+		 * "activated" it will be configured as a sink, otherwise
+		 * go ahead with the link configuration.
+		 */
+		if (type == CORESIGHT_DEV_TYPE_LINKSINK)
+			type = (csdev == coresight_get_sink(path)) ?
+						CORESIGHT_DEV_TYPE_SINK :
+						CORESIGHT_DEV_TYPE_LINK;
+
+		switch (type) {
 		case CORESIGHT_DEV_TYPE_SINK:
-		case CORESIGHT_DEV_TYPE_LINKSINK:
 			coresight_disable_sink(csdev);
 			break;
 		case CORESIGHT_DEV_TYPE_SOURCE:
@@ -286,15 +298,27 @@ int coresight_enable_path(struct list_head *path, u32 mode)
 {
 
 	int ret = 0;
+	u32 type;
 	struct coresight_node *nd;
 	struct coresight_device *csdev, *parent, *child;
 
 	list_for_each_entry_reverse(nd, path, link) {
 		csdev = nd->csdev;
+		type = csdev->type;
+
+		/*
+		 * ETF devices are tricky... They can be a link or a sink,
+		 * depending on how they are configured.  If an ETF has been
+		 * "activated" it will be configured as a sink, otherwise
+		 * go ahead with the link configuration.
+		 */
+		if (type == CORESIGHT_DEV_TYPE_LINKSINK)
+			type = (csdev == coresight_get_sink(path)) ?
+						CORESIGHT_DEV_TYPE_SINK :
+						CORESIGHT_DEV_TYPE_LINK;
 
-		switch (csdev->type) {
+		switch (type) {
 		case CORESIGHT_DEV_TYPE_SINK:
-		case CORESIGHT_DEV_TYPE_LINKSINK:
 			ret = coresight_enable_sink(csdev, mode);
 			if (ret)
 				goto err;
-- 
2.5.0

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

* [PATCH V2 15/15] coresight: configuring ETF in FIFO mode when acting as link
@ 2016-04-12 17:54   ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-12 17:54 UTC (permalink / raw)
  To: linux-arm-kernel

When part of a path but not identified as a sink, the EFT has to
be configured as a link and placed in HW FIFO mode.  As such when
enabling a path, call the right configuration function based on
the role the ETF if playing in this trace run.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/hwtracing/coresight/coresight.c | 32 ++++++++++++++++++++++++++++----
 1 file changed, 28 insertions(+), 4 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c
index 2ea5961092c1..bba9f3d653c9 100644
--- a/drivers/hwtracing/coresight/coresight.c
+++ b/drivers/hwtracing/coresight/coresight.c
@@ -257,15 +257,27 @@ static void coresight_disable_source(struct coresight_device *csdev)
 
 void coresight_disable_path(struct list_head *path)
 {
+	u32 type;
 	struct coresight_node *nd;
 	struct coresight_device *csdev, *parent, *child;
 
 	list_for_each_entry(nd, path, link) {
 		csdev = nd->csdev;
+		type = csdev->type;
 
-		switch (csdev->type) {
+		/*
+		 * ETF devices are tricky... They can be a link or a sink,
+		 * depending on how they are configured.  If an ETF has been
+		 * "activated" it will be configured as a sink, otherwise
+		 * go ahead with the link configuration.
+		 */
+		if (type == CORESIGHT_DEV_TYPE_LINKSINK)
+			type = (csdev == coresight_get_sink(path)) ?
+						CORESIGHT_DEV_TYPE_SINK :
+						CORESIGHT_DEV_TYPE_LINK;
+
+		switch (type) {
 		case CORESIGHT_DEV_TYPE_SINK:
-		case CORESIGHT_DEV_TYPE_LINKSINK:
 			coresight_disable_sink(csdev);
 			break;
 		case CORESIGHT_DEV_TYPE_SOURCE:
@@ -286,15 +298,27 @@ int coresight_enable_path(struct list_head *path, u32 mode)
 {
 
 	int ret = 0;
+	u32 type;
 	struct coresight_node *nd;
 	struct coresight_device *csdev, *parent, *child;
 
 	list_for_each_entry_reverse(nd, path, link) {
 		csdev = nd->csdev;
+		type = csdev->type;
+
+		/*
+		 * ETF devices are tricky... They can be a link or a sink,
+		 * depending on how they are configured.  If an ETF has been
+		 * "activated" it will be configured as a sink, otherwise
+		 * go ahead with the link configuration.
+		 */
+		if (type == CORESIGHT_DEV_TYPE_LINKSINK)
+			type = (csdev == coresight_get_sink(path)) ?
+						CORESIGHT_DEV_TYPE_SINK :
+						CORESIGHT_DEV_TYPE_LINK;
 
-		switch (csdev->type) {
+		switch (type) {
 		case CORESIGHT_DEV_TYPE_SINK:
-		case CORESIGHT_DEV_TYPE_LINKSINK:
 			ret = coresight_enable_sink(csdev, mode);
 			if (ret)
 				goto err;
-- 
2.5.0

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

* Re: [PATCH V2 12/15] coresight: tmc: keep track of memory width
  2016-04-12 17:54   ` Mathieu Poirier
@ 2016-04-14 11:19     ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-14 11:19 UTC (permalink / raw)
  To: Mathieu Poirier, linux-arm-kernel; +Cc: linux-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> Accessing the HW configuration register each time the memory
> width is needed simply doesn't make sense.  It is much more
> efficient to read the value once and keep a reference for
> later use.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 8 +++-----
>   drivers/hwtracing/coresight/coresight-tmc.c     | 1 +
>   drivers/hwtracing/coresight/coresight-tmc.h     | 2 ++
>   3 files changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> index 50d32e8ef4ea..a440784e3b27 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> @@ -41,18 +41,16 @@ void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
>
>   static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
>   {
> -	enum tmc_mem_intf_width memwidth;
>   	u8 memwords;
>   	char *bufp;
>   	u32 read_data;
>   	int i;
>
> -	memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID), 8, 10);
> -	if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
> +	if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_32BITS)
>   		memwords = 1;
> -	else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
> +	else if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_64BITS)
>   		memwords = 2;
> -	else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
> +	else if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_128BITS)
>   		memwords = 4;


>   struct tmc_drvdata {
> @@ -118,6 +119,7 @@ struct tmc_drvdata {
>   	u32			size;
>   	local_t			mode;
>   	enum tmc_config_type	config_type;
> +	enum tmc_mem_intf_width	memwidth;

Could we not store the converted memwords here, instead of the enum value here
and convert it every time we access it ?

Cheers
Suzuki

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

* [PATCH V2 12/15] coresight: tmc: keep track of memory width
@ 2016-04-14 11:19     ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-14 11:19 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> Accessing the HW configuration register each time the memory
> width is needed simply doesn't make sense.  It is much more
> efficient to read the value once and keep a reference for
> later use.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 8 +++-----
>   drivers/hwtracing/coresight/coresight-tmc.c     | 1 +
>   drivers/hwtracing/coresight/coresight-tmc.h     | 2 ++
>   3 files changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> index 50d32e8ef4ea..a440784e3b27 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> @@ -41,18 +41,16 @@ void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
>
>   static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
>   {
> -	enum tmc_mem_intf_width memwidth;
>   	u8 memwords;
>   	char *bufp;
>   	u32 read_data;
>   	int i;
>
> -	memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID), 8, 10);
> -	if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
> +	if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_32BITS)
>   		memwords = 1;
> -	else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
> +	else if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_64BITS)
>   		memwords = 2;
> -	else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
> +	else if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_128BITS)
>   		memwords = 4;


>   struct tmc_drvdata {
> @@ -118,6 +119,7 @@ struct tmc_drvdata {
>   	u32			size;
>   	local_t			mode;
>   	enum tmc_config_type	config_type;
> +	enum tmc_mem_intf_width	memwidth;

Could we not store the converted memwords here, instead of the enum value here
and convert it every time we access it ?

Cheers
Suzuki

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

* Re: [PATCH V2 01/15] coresight: tmc: modifying naming convention
  2016-04-12 17:54   ` Mathieu Poirier
@ 2016-04-14 17:01     ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-14 17:01 UTC (permalink / raw)
  To: Mathieu Poirier, linux-arm-kernel; +Cc: linux-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> According to the TMC architectural state machine, the 'stopped'
> state is reached when bit 2 (TMCReady) of the TMC Status register
> turns to '1'.  The code is correct but the naming convention isn't.
>
> The 'Triggered' bit occupies position '1' of the TMC Status register
> and has nothing to do with the indication of the TMC entering the
> stopped state. As such renaming function "tmc_wait_for_triggered()"
> and changing the #define to reflect what the code is really doing.
>
> This patch has no effect other than clarifying the semantic.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

Suzuki

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

* [PATCH V2 01/15] coresight: tmc: modifying naming convention
@ 2016-04-14 17:01     ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-14 17:01 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> According to the TMC architectural state machine, the 'stopped'
> state is reached when bit 2 (TMCReady) of the TMC Status register
> turns to '1'.  The code is correct but the naming convention isn't.
>
> The 'Triggered' bit occupies position '1' of the TMC Status register
> and has nothing to do with the indication of the TMC entering the
> stopped state. As such renaming function "tmc_wait_for_triggered()"
> and changing the #define to reflect what the code is really doing.
>
> This patch has no effect other than clarifying the semantic.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

Suzuki

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

* Re: [PATCH V2 02/15] coresight: tmc: waiting for TMCReady bit before programming
  2016-04-12 17:54   ` Mathieu Poirier
@ 2016-04-14 17:05     ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-14 17:05 UTC (permalink / raw)
  To: Mathieu Poirier, linux-arm-kernel; +Cc: linux-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> According to the TRM before programming the TMC in circular
> buffer mode (and that for any configuration, ETB, ETR, ETF),
> the TMCReady bit in the status register has to be set.
>
> This patch adds a check to make sure the state machine is in
> a state where it can be configured, and complains otherwise.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

Suzuki

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

* [PATCH V2 02/15] coresight: tmc: waiting for TMCReady bit before programming
@ 2016-04-14 17:05     ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-14 17:05 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> According to the TRM before programming the TMC in circular
> buffer mode (and that for any configuration, ETB, ETR, ETF),
> the TMCReady bit in the status register has to be set.
>
> This patch adds a check to make sure the state machine is in
> a state where it can be configured, and complains otherwise.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

Suzuki

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

* Re: [PATCH V2 03/15] coresight: tmc: re-implementing tmc_read_prepare/unprepare() functions
  2016-04-12 17:54   ` Mathieu Poirier
@ 2016-04-14 17:11     ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-14 17:11 UTC (permalink / raw)
  To: Mathieu Poirier, linux-arm-kernel; +Cc: linux-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> In their current implementation the tmc_read_prepare/unprepare()
> are a lump of if/else that is difficult to read.  This patch is
> alleviating that by using a switch statement.  The latter also
> allows for a better control on the error path.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>   drivers/hwtracing/coresight/coresight-tmc.c | 56 ++++++++++++++++++-----------
>   1 file changed, 36 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
> index 66fa7736d12f..d211aeec49f8 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc.c
> @@ -431,7 +431,7 @@ static const struct coresight_ops tmc_etf_cs_ops = {
>
>   static int tmc_read_prepare(struct tmc_drvdata *drvdata)
>   {
> -	int ret;
> +	int ret = 0;
>   	unsigned long flags;
>   	enum tmc_mode mode;
>
> @@ -439,25 +439,31 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
>   	if (!drvdata->enable)
>   		goto out;
>
> -	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
> +	switch (drvdata->config_type) {
> +	case TMC_CONFIG_TYPE_ETB:
>   		tmc_etb_disable_hw(drvdata);
> -	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
> -		tmc_etr_disable_hw(drvdata);
> -	} else {
> +		break;
> +	case TMC_CONFIG_TYPE_ETF:
> +		/* There is no point in reading a TMC in HW FIFO mode */
>   		mode = readl_relaxed(drvdata->base + TMC_MODE);
> -		if (mode == TMC_MODE_CIRCULAR_BUFFER) {
> -			tmc_etb_disable_hw(drvdata);
> -		} else {
> -			ret = -ENODEV;
> +		if (mode != TMC_MODE_CIRCULAR_BUFFER) {
> +			ret = -EINVAL;
>   			goto err;
>   		}

Nit. If you move the TMC_CONFIG_TYPE_ETB here, you could fall through from TYPE_ETF: i.e,
		/* Fall through to ETB mode */
	case TMC_CONFIG_TYPE_ETB:
> +
> +		tmc_etb_disable_hw(drvdata);
> +		break;



> +	case TMC_CONFIG_TYPE_ETR:
> +		tmc_etr_disable_hw(drvdata);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		goto err;
>   	}
> +


>   	return ret;
> @@ -472,20 +478,30 @@ static void tmc_read_unprepare(struct tmc_drvdata *drvdata)
>   	if (!drvdata->enable)
>   		goto out;
>
> -	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
> +	switch (drvdata->config_type) {
> +	case TMC_CONFIG_TYPE_ETB:
>   		tmc_etb_enable_hw(drvdata);
> -	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
> -		tmc_etr_enable_hw(drvdata);
> -	} else {
> +		break;
> +	case TMC_CONFIG_TYPE_ETF:
> +		/* Make sure we don't re-enable a TMC in HW FIFO mode */
>   		mode = readl_relaxed(drvdata->base + TMC_MODE);
> -		if (mode == TMC_MODE_CIRCULAR_BUFFER)
> -			tmc_etb_enable_hw(drvdata);
> +		if (mode != TMC_MODE_CIRCULAR_BUFFER)
> +			goto err;
> +
> +		tmc_etb_enable_hw(drvdata);
> +		break;

Same as above.

> +	case TMC_CONFIG_TYPE_ETR:
> +		tmc_etr_disable_hw(drvdata);
> +		break;
> +	default:
> +		goto err;
>   	}
> +

Otherwise,

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

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

* [PATCH V2 03/15] coresight: tmc: re-implementing tmc_read_prepare/unprepare() functions
@ 2016-04-14 17:11     ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-14 17:11 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> In their current implementation the tmc_read_prepare/unprepare()
> are a lump of if/else that is difficult to read.  This patch is
> alleviating that by using a switch statement.  The latter also
> allows for a better control on the error path.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>   drivers/hwtracing/coresight/coresight-tmc.c | 56 ++++++++++++++++++-----------
>   1 file changed, 36 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
> index 66fa7736d12f..d211aeec49f8 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc.c
> @@ -431,7 +431,7 @@ static const struct coresight_ops tmc_etf_cs_ops = {
>
>   static int tmc_read_prepare(struct tmc_drvdata *drvdata)
>   {
> -	int ret;
> +	int ret = 0;
>   	unsigned long flags;
>   	enum tmc_mode mode;
>
> @@ -439,25 +439,31 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
>   	if (!drvdata->enable)
>   		goto out;
>
> -	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
> +	switch (drvdata->config_type) {
> +	case TMC_CONFIG_TYPE_ETB:
>   		tmc_etb_disable_hw(drvdata);
> -	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
> -		tmc_etr_disable_hw(drvdata);
> -	} else {
> +		break;
> +	case TMC_CONFIG_TYPE_ETF:
> +		/* There is no point in reading a TMC in HW FIFO mode */
>   		mode = readl_relaxed(drvdata->base + TMC_MODE);
> -		if (mode == TMC_MODE_CIRCULAR_BUFFER) {
> -			tmc_etb_disable_hw(drvdata);
> -		} else {
> -			ret = -ENODEV;
> +		if (mode != TMC_MODE_CIRCULAR_BUFFER) {
> +			ret = -EINVAL;
>   			goto err;
>   		}

Nit. If you move the TMC_CONFIG_TYPE_ETB here, you could fall through from TYPE_ETF: i.e,
		/* Fall through to ETB mode */
	case TMC_CONFIG_TYPE_ETB:
> +
> +		tmc_etb_disable_hw(drvdata);
> +		break;



> +	case TMC_CONFIG_TYPE_ETR:
> +		tmc_etr_disable_hw(drvdata);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		goto err;
>   	}
> +


>   	return ret;
> @@ -472,20 +478,30 @@ static void tmc_read_unprepare(struct tmc_drvdata *drvdata)
>   	if (!drvdata->enable)
>   		goto out;
>
> -	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
> +	switch (drvdata->config_type) {
> +	case TMC_CONFIG_TYPE_ETB:
>   		tmc_etb_enable_hw(drvdata);
> -	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
> -		tmc_etr_enable_hw(drvdata);
> -	} else {
> +		break;
> +	case TMC_CONFIG_TYPE_ETF:
> +		/* Make sure we don't re-enable a TMC in HW FIFO mode */
>   		mode = readl_relaxed(drvdata->base + TMC_MODE);
> -		if (mode == TMC_MODE_CIRCULAR_BUFFER)
> -			tmc_etb_enable_hw(drvdata);
> +		if (mode != TMC_MODE_CIRCULAR_BUFFER)
> +			goto err;
> +
> +		tmc_etb_enable_hw(drvdata);
> +		break;

Same as above.

> +	case TMC_CONFIG_TYPE_ETR:
> +		tmc_etr_disable_hw(drvdata);
> +		break;
> +	default:
> +		goto err;
>   	}
> +

Otherwise,

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

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

* Re: [PATCH V2 04/15] coresight: tmc: introducing new header file
  2016-04-12 17:54   ` Mathieu Poirier
@ 2016-04-14 17:33     ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-14 17:33 UTC (permalink / raw)
  To: Mathieu Poirier, linux-arm-kernel; +Cc: linux-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> The amount of #define, enumeration and structure definition
> is big enough to justify moving them to a new header file.
>


> +/* TMC_STS - 0x00C */
> +#define TMC_STS_TRIGGERED	BIT(1)

...

> +#define TMC_AXICTL_WR_BURST_LEN 0xF00

Nit: The value above signifies, 16 data transfers per burst.
So ideally it would be good to rename it to reflect that. say,

TMC_AXICTL_WR_BURST_16



> +/* TMC_FFCR - 0x304 */
> +#define TMC_FFCR_EN_FMT		BIT(0)
> +#define TMC_FFCR_EN_TI		BIT(1)
> +#define TMC_FFCR_FON_FLIN	BIT(4)
> +#define TMC_FFCR_FON_TRIG_EVT	BIT(5)
> +#define TMC_FFCR_FLUSHMAN	BIT(6)
> +#define TMC_FFCR_TRIGON_TRIGIN	BIT(8)
> +#define TMC_FFCR_STOP_ON_FLUSH	BIT(12)
> +
> +#define TMC_STS_TMCREADY_BIT	2

> +#define TMC_FFCR_FLUSHMAN_BIT	6

nit: It would be nice to group the STS_ and FFCR_ bits together.
Also I see that the defintion for

TMC_STS_FULL is added in a completely unrelated patch (TMC-ETF AUX SPACE
patch ?). It would be good to add it either here or in a different patch.

Otherwise looks good.

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

Thanks
Suzuki

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

* [PATCH V2 04/15] coresight: tmc: introducing new header file
@ 2016-04-14 17:33     ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-14 17:33 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> The amount of #define, enumeration and structure definition
> is big enough to justify moving them to a new header file.
>


> +/* TMC_STS - 0x00C */
> +#define TMC_STS_TRIGGERED	BIT(1)

...

> +#define TMC_AXICTL_WR_BURST_LEN 0xF00

Nit: The value above signifies, 16 data transfers per burst.
So ideally it would be good to rename it to reflect that. say,

TMC_AXICTL_WR_BURST_16



> +/* TMC_FFCR - 0x304 */
> +#define TMC_FFCR_EN_FMT		BIT(0)
> +#define TMC_FFCR_EN_TI		BIT(1)
> +#define TMC_FFCR_FON_FLIN	BIT(4)
> +#define TMC_FFCR_FON_TRIG_EVT	BIT(5)
> +#define TMC_FFCR_FLUSHMAN	BIT(6)
> +#define TMC_FFCR_TRIGON_TRIGIN	BIT(8)
> +#define TMC_FFCR_STOP_ON_FLUSH	BIT(12)
> +
> +#define TMC_STS_TMCREADY_BIT	2

> +#define TMC_FFCR_FLUSHMAN_BIT	6

nit: It would be nice to group the STS_ and FFCR_ bits together.
Also I see that the defintion for

TMC_STS_FULL is added in a completely unrelated patch (TMC-ETF AUX SPACE
patch ?). It would be good to add it either here or in a different patch.

Otherwise looks good.

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

Thanks
Suzuki

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

* Re: [PATCH V2 03/15] coresight: tmc: re-implementing tmc_read_prepare/unprepare() functions
  2016-04-14 17:11     ` Suzuki K Poulose
@ 2016-04-15 15:40       ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-15 15:40 UTC (permalink / raw)
  To: Suzuki K Poulose; +Cc: linux-arm-kernel, linux-kernel

On 14 April 2016 at 11:11, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> In their current implementation the tmc_read_prepare/unprepare()
>> are a lump of if/else that is difficult to read.  This patch is
>> alleviating that by using a switch statement.  The latter also
>> allows for a better control on the error path.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>   drivers/hwtracing/coresight/coresight-tmc.c | 56
>> ++++++++++++++++++-----------
>>   1 file changed, 36 insertions(+), 20 deletions(-)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc.c
>> b/drivers/hwtracing/coresight/coresight-tmc.c
>> index 66fa7736d12f..d211aeec49f8 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc.c
>> @@ -431,7 +431,7 @@ static const struct coresight_ops tmc_etf_cs_ops = {
>>
>>   static int tmc_read_prepare(struct tmc_drvdata *drvdata)
>>   {
>> -       int ret;
>> +       int ret = 0;
>>         unsigned long flags;
>>         enum tmc_mode mode;
>>
>> @@ -439,25 +439,31 @@ static int tmc_read_prepare(struct tmc_drvdata
>> *drvdata)
>>         if (!drvdata->enable)
>>                 goto out;
>>
>> -       if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
>> +       switch (drvdata->config_type) {
>> +       case TMC_CONFIG_TYPE_ETB:
>>                 tmc_etb_disable_hw(drvdata);
>> -       } else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
>> -               tmc_etr_disable_hw(drvdata);
>> -       } else {
>> +               break;
>> +       case TMC_CONFIG_TYPE_ETF:
>> +               /* There is no point in reading a TMC in HW FIFO mode */
>>                 mode = readl_relaxed(drvdata->base + TMC_MODE);
>> -               if (mode == TMC_MODE_CIRCULAR_BUFFER) {
>> -                       tmc_etb_disable_hw(drvdata);
>> -               } else {
>> -                       ret = -ENODEV;
>> +               if (mode != TMC_MODE_CIRCULAR_BUFFER) {
>> +                       ret = -EINVAL;
>>                         goto err;
>>                 }
>
>
> Nit. If you move the TMC_CONFIG_TYPE_ETB here, you could fall through from
> TYPE_ETF: i.e,

Yes, that's what the end result look like [1].  I will refactor to
make the transition cleaner.

[1]. https://git.linaro.org/kernel/coresight.git/blob/refs/heads/next:/drivers/hwtracing/coresight/coresight-tmc.c#l76

>                 /* Fall through to ETB mode */
>         case TMC_CONFIG_TYPE_ETB:
>>
>> +
>> +               tmc_etb_disable_hw(drvdata);
>> +               break;
>
>
>
>
>> +       case TMC_CONFIG_TYPE_ETR:
>> +               tmc_etr_disable_hw(drvdata);
>> +               break;
>> +       default:
>> +               ret = -EINVAL;
>> +               goto err;
>>         }
>> +
>
>
>
>>         return ret;
>> @@ -472,20 +478,30 @@ static void tmc_read_unprepare(struct tmc_drvdata
>> *drvdata)
>>         if (!drvdata->enable)
>>                 goto out;
>>
>> -       if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
>> +       switch (drvdata->config_type) {
>> +       case TMC_CONFIG_TYPE_ETB:
>>                 tmc_etb_enable_hw(drvdata);
>> -       } else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
>> -               tmc_etr_enable_hw(drvdata);
>> -       } else {
>> +               break;
>> +       case TMC_CONFIG_TYPE_ETF:
>> +               /* Make sure we don't re-enable a TMC in HW FIFO mode */
>>                 mode = readl_relaxed(drvdata->base + TMC_MODE);
>> -               if (mode == TMC_MODE_CIRCULAR_BUFFER)
>> -                       tmc_etb_enable_hw(drvdata);
>> +               if (mode != TMC_MODE_CIRCULAR_BUFFER)
>> +                       goto err;
>> +
>> +               tmc_etb_enable_hw(drvdata);
>> +               break;
>
>
> Same as above.
>
>> +       case TMC_CONFIG_TYPE_ETR:
>> +               tmc_etr_disable_hw(drvdata);
>> +               break;
>> +       default:
>> +               goto err;
>>         }
>> +
>
>
> Otherwise,
>
> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
>
>

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

* [PATCH V2 03/15] coresight: tmc: re-implementing tmc_read_prepare/unprepare() functions
@ 2016-04-15 15:40       ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-15 15:40 UTC (permalink / raw)
  To: linux-arm-kernel

On 14 April 2016 at 11:11, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> In their current implementation the tmc_read_prepare/unprepare()
>> are a lump of if/else that is difficult to read.  This patch is
>> alleviating that by using a switch statement.  The latter also
>> allows for a better control on the error path.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>   drivers/hwtracing/coresight/coresight-tmc.c | 56
>> ++++++++++++++++++-----------
>>   1 file changed, 36 insertions(+), 20 deletions(-)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc.c
>> b/drivers/hwtracing/coresight/coresight-tmc.c
>> index 66fa7736d12f..d211aeec49f8 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc.c
>> @@ -431,7 +431,7 @@ static const struct coresight_ops tmc_etf_cs_ops = {
>>
>>   static int tmc_read_prepare(struct tmc_drvdata *drvdata)
>>   {
>> -       int ret;
>> +       int ret = 0;
>>         unsigned long flags;
>>         enum tmc_mode mode;
>>
>> @@ -439,25 +439,31 @@ static int tmc_read_prepare(struct tmc_drvdata
>> *drvdata)
>>         if (!drvdata->enable)
>>                 goto out;
>>
>> -       if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
>> +       switch (drvdata->config_type) {
>> +       case TMC_CONFIG_TYPE_ETB:
>>                 tmc_etb_disable_hw(drvdata);
>> -       } else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
>> -               tmc_etr_disable_hw(drvdata);
>> -       } else {
>> +               break;
>> +       case TMC_CONFIG_TYPE_ETF:
>> +               /* There is no point in reading a TMC in HW FIFO mode */
>>                 mode = readl_relaxed(drvdata->base + TMC_MODE);
>> -               if (mode == TMC_MODE_CIRCULAR_BUFFER) {
>> -                       tmc_etb_disable_hw(drvdata);
>> -               } else {
>> -                       ret = -ENODEV;
>> +               if (mode != TMC_MODE_CIRCULAR_BUFFER) {
>> +                       ret = -EINVAL;
>>                         goto err;
>>                 }
>
>
> Nit. If you move the TMC_CONFIG_TYPE_ETB here, you could fall through from
> TYPE_ETF: i.e,

Yes, that's what the end result look like [1].  I will refactor to
make the transition cleaner.

[1]. https://git.linaro.org/kernel/coresight.git/blob/refs/heads/next:/drivers/hwtracing/coresight/coresight-tmc.c#l76

>                 /* Fall through to ETB mode */
>         case TMC_CONFIG_TYPE_ETB:
>>
>> +
>> +               tmc_etb_disable_hw(drvdata);
>> +               break;
>
>
>
>
>> +       case TMC_CONFIG_TYPE_ETR:
>> +               tmc_etr_disable_hw(drvdata);
>> +               break;
>> +       default:
>> +               ret = -EINVAL;
>> +               goto err;
>>         }
>> +
>
>
>
>>         return ret;
>> @@ -472,20 +478,30 @@ static void tmc_read_unprepare(struct tmc_drvdata
>> *drvdata)
>>         if (!drvdata->enable)
>>                 goto out;
>>
>> -       if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
>> +       switch (drvdata->config_type) {
>> +       case TMC_CONFIG_TYPE_ETB:
>>                 tmc_etb_enable_hw(drvdata);
>> -       } else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
>> -               tmc_etr_enable_hw(drvdata);
>> -       } else {
>> +               break;
>> +       case TMC_CONFIG_TYPE_ETF:
>> +               /* Make sure we don't re-enable a TMC in HW FIFO mode */
>>                 mode = readl_relaxed(drvdata->base + TMC_MODE);
>> -               if (mode == TMC_MODE_CIRCULAR_BUFFER)
>> -                       tmc_etb_enable_hw(drvdata);
>> +               if (mode != TMC_MODE_CIRCULAR_BUFFER)
>> +                       goto err;
>> +
>> +               tmc_etb_enable_hw(drvdata);
>> +               break;
>
>
> Same as above.
>
>> +       case TMC_CONFIG_TYPE_ETR:
>> +               tmc_etr_disable_hw(drvdata);
>> +               break;
>> +       default:
>> +               goto err;
>>         }
>> +
>
>
> Otherwise,
>
> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
>
>

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

* Re: [PATCH V2 04/15] coresight: tmc: introducing new header file
  2016-04-14 17:33     ` Suzuki K Poulose
@ 2016-04-15 16:03       ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-15 16:03 UTC (permalink / raw)
  To: Suzuki K Poulose; +Cc: linux-arm-kernel, linux-kernel

On 14 April 2016 at 11:33, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> The amount of #define, enumeration and structure definition
>> is big enough to justify moving them to a new header file.
>>
>
>
>> +/* TMC_STS - 0x00C */
>> +#define TMC_STS_TRIGGERED      BIT(1)
>
>
> ...
>
>> +#define TMC_AXICTL_WR_BURST_LEN 0xF00
>
>
> Nit: The value above signifies, 16 data transfers per burst.
> So ideally it would be good to rename it to reflect that. say,
>
> TMC_AXICTL_WR_BURST_16

Will do.  But I'll have to do this in a separate patch then the
grouping of STS_ and FFCR_ defines you're referring to below since it
will also require changes to the .c files.

>
>
>
>> +/* TMC_FFCR - 0x304 */
>> +#define TMC_FFCR_EN_FMT                BIT(0)
>> +#define TMC_FFCR_EN_TI         BIT(1)
>> +#define TMC_FFCR_FON_FLIN      BIT(4)
>> +#define TMC_FFCR_FON_TRIG_EVT  BIT(5)
>> +#define TMC_FFCR_FLUSHMAN      BIT(6)
>> +#define TMC_FFCR_TRIGON_TRIGIN BIT(8)
>> +#define TMC_FFCR_STOP_ON_FLUSH BIT(12)
>> +
>> +#define TMC_STS_TMCREADY_BIT   2
>
>
>> +#define TMC_FFCR_FLUSHMAN_BIT  6
>
>
> nit: It would be nice to group the STS_ and FFCR_ bits together.
> Also I see that the defintion for
> TMC_STS_FULL is added in a completely unrelated patch (TMC-ETF AUX SPACE
> patch ?). It would be good to add it either here or in a different patch.

TMC_STS_FULL is not added here because at this point it is not used by
the code - it is only added later when it is useful.  Please get back
to me if I missed your point.

>
> Otherwise looks good.
>
> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
>
> Thanks
> Suzuki

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

* [PATCH V2 04/15] coresight: tmc: introducing new header file
@ 2016-04-15 16:03       ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-15 16:03 UTC (permalink / raw)
  To: linux-arm-kernel

On 14 April 2016 at 11:33, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> The amount of #define, enumeration and structure definition
>> is big enough to justify moving them to a new header file.
>>
>
>
>> +/* TMC_STS - 0x00C */
>> +#define TMC_STS_TRIGGERED      BIT(1)
>
>
> ...
>
>> +#define TMC_AXICTL_WR_BURST_LEN 0xF00
>
>
> Nit: The value above signifies, 16 data transfers per burst.
> So ideally it would be good to rename it to reflect that. say,
>
> TMC_AXICTL_WR_BURST_16

Will do.  But I'll have to do this in a separate patch then the
grouping of STS_ and FFCR_ defines you're referring to below since it
will also require changes to the .c files.

>
>
>
>> +/* TMC_FFCR - 0x304 */
>> +#define TMC_FFCR_EN_FMT                BIT(0)
>> +#define TMC_FFCR_EN_TI         BIT(1)
>> +#define TMC_FFCR_FON_FLIN      BIT(4)
>> +#define TMC_FFCR_FON_TRIG_EVT  BIT(5)
>> +#define TMC_FFCR_FLUSHMAN      BIT(6)
>> +#define TMC_FFCR_TRIGON_TRIGIN BIT(8)
>> +#define TMC_FFCR_STOP_ON_FLUSH BIT(12)
>> +
>> +#define TMC_STS_TMCREADY_BIT   2
>
>
>> +#define TMC_FFCR_FLUSHMAN_BIT  6
>
>
> nit: It would be nice to group the STS_ and FFCR_ bits together.
> Also I see that the defintion for
> TMC_STS_FULL is added in a completely unrelated patch (TMC-ETF AUX SPACE
> patch ?). It would be good to add it either here or in a different patch.

TMC_STS_FULL is not added here because at this point it is not used by
the code - it is only added later when it is useful.  Please get back
to me if I missed your point.

>
> Otherwise looks good.
>
> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
>
> Thanks
> Suzuki

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

* Re: [PATCH V2 04/15] coresight: tmc: introducing new header file
  2016-04-15 16:03       ` Mathieu Poirier
@ 2016-04-15 16:08         ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-15 16:08 UTC (permalink / raw)
  To: Mathieu Poirier; +Cc: linux-arm-kernel, linux-kernel

On 15/04/16 17:03, Mathieu Poirier wrote:
> On 14 April 2016 at 11:33, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
>> On 12/04/16 18:54, Mathieu Poirier wrote:
>>>
>>> The amount of #define, enumeration and structure definition
>>> is big enough to justify moving them to a new header file.
>>>
>>
>>
>>> +/* TMC_STS - 0x00C */
>>> +#define TMC_STS_TRIGGERED      BIT(1)
>>
>>
>> ...
>>
>>> +#define TMC_AXICTL_WR_BURST_LEN 0xF00
>>
>>
>> Nit: The value above signifies, 16 data transfers per burst.
>> So ideally it would be good to rename it to reflect that. say,
>>
>> TMC_AXICTL_WR_BURST_16
>
> Will do.  But I'll have to do this in a separate patch then the
> grouping of STS_ and FFCR_ defines you're referring to below since it
> will also require changes to the .c files.

Yes, I don't expect this change to be part of the patch. Separate patch
is fine.

>
>>
>>
>>
>>> +/* TMC_FFCR - 0x304 */
>>> +#define TMC_FFCR_EN_FMT                BIT(0)
>>> +#define TMC_FFCR_EN_TI         BIT(1)
>>> +#define TMC_FFCR_FON_FLIN      BIT(4)
>>> +#define TMC_FFCR_FON_TRIG_EVT  BIT(5)
>>> +#define TMC_FFCR_FLUSHMAN      BIT(6)
>>> +#define TMC_FFCR_TRIGON_TRIGIN BIT(8)
>>> +#define TMC_FFCR_STOP_ON_FLUSH BIT(12)
>>> +
>>> +#define TMC_STS_TMCREADY_BIT   2
>>
>>
>>> +#define TMC_FFCR_FLUSHMAN_BIT  6
>>
>>
>> nit: It would be nice to group the STS_ and FFCR_ bits together.
>> Also I see that the defintion for
>> TMC_STS_FULL is added in a completely unrelated patch (TMC-ETF AUX SPACE
>> patch ?). It would be good to add it either here or in a different patch.
>
> TMC_STS_FULL is not added here because at this point it is not used by
> the code - it is only added later when it is useful.

I agree. But the patch which introduces the definition doesn't deal with
TMC_STS_ at all either. Thats why I said, either here or in a different patch
than what is there. May be you could club the change above and the STS_FULL
into a new single patch. Its not mandatory though.

Suzuki

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

* [PATCH V2 04/15] coresight: tmc: introducing new header file
@ 2016-04-15 16:08         ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-15 16:08 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/04/16 17:03, Mathieu Poirier wrote:
> On 14 April 2016 at 11:33, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
>> On 12/04/16 18:54, Mathieu Poirier wrote:
>>>
>>> The amount of #define, enumeration and structure definition
>>> is big enough to justify moving them to a new header file.
>>>
>>
>>
>>> +/* TMC_STS - 0x00C */
>>> +#define TMC_STS_TRIGGERED      BIT(1)
>>
>>
>> ...
>>
>>> +#define TMC_AXICTL_WR_BURST_LEN 0xF00
>>
>>
>> Nit: The value above signifies, 16 data transfers per burst.
>> So ideally it would be good to rename it to reflect that. say,
>>
>> TMC_AXICTL_WR_BURST_16
>
> Will do.  But I'll have to do this in a separate patch then the
> grouping of STS_ and FFCR_ defines you're referring to below since it
> will also require changes to the .c files.

Yes, I don't expect this change to be part of the patch. Separate patch
is fine.

>
>>
>>
>>
>>> +/* TMC_FFCR - 0x304 */
>>> +#define TMC_FFCR_EN_FMT                BIT(0)
>>> +#define TMC_FFCR_EN_TI         BIT(1)
>>> +#define TMC_FFCR_FON_FLIN      BIT(4)
>>> +#define TMC_FFCR_FON_TRIG_EVT  BIT(5)
>>> +#define TMC_FFCR_FLUSHMAN      BIT(6)
>>> +#define TMC_FFCR_TRIGON_TRIGIN BIT(8)
>>> +#define TMC_FFCR_STOP_ON_FLUSH BIT(12)
>>> +
>>> +#define TMC_STS_TMCREADY_BIT   2
>>
>>
>>> +#define TMC_FFCR_FLUSHMAN_BIT  6
>>
>>
>> nit: It would be nice to group the STS_ and FFCR_ bits together.
>> Also I see that the defintion for
>> TMC_STS_FULL is added in a completely unrelated patch (TMC-ETF AUX SPACE
>> patch ?). It would be good to add it either here or in a different patch.
>
> TMC_STS_FULL is not added here because at this point it is not used by
> the code - it is only added later when it is useful.

I agree. But the patch which introduces the definition doesn't deal with
TMC_STS_ at all either. Thats why I said, either here or in a different patch
than what is there. May be you could club the change above and the STS_FULL
into a new single patch. Its not mandatory though.

Suzuki

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

* Re: [PATCH V2 12/15] coresight: tmc: keep track of memory width
  2016-04-14 11:19     ` Suzuki K Poulose
@ 2016-04-15 16:10       ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-15 16:10 UTC (permalink / raw)
  To: Suzuki K Poulose; +Cc: linux-arm-kernel, linux-kernel

On 14 April 2016 at 05:19, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> Accessing the HW configuration register each time the memory
>> width is needed simply doesn't make sense.  It is much more
>> efficient to read the value once and keep a reference for
>> later use.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 8 +++-----
>>   drivers/hwtracing/coresight/coresight-tmc.c     | 1 +
>>   drivers/hwtracing/coresight/coresight-tmc.h     | 2 ++
>>   3 files changed, 6 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> index 50d32e8ef4ea..a440784e3b27 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> @@ -41,18 +41,16 @@ void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
>>
>>   static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
>>   {
>> -       enum tmc_mem_intf_width memwidth;
>>         u8 memwords;
>>         char *bufp;
>>         u32 read_data;
>>         int i;
>>
>> -       memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID),
>> 8, 10);
>> -       if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
>> +       if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_32BITS)
>>                 memwords = 1;
>> -       else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
>> +       else if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_64BITS)
>>                 memwords = 2;
>> -       else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
>> +       else if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_128BITS)
>>                 memwords = 4;
>
>
>
>>   struct tmc_drvdata {
>> @@ -118,6 +119,7 @@ struct tmc_drvdata {
>>         u32                     size;
>>         local_t                 mode;
>>         enum tmc_config_type    config_type;
>> +       enum tmc_mem_intf_width memwidth;
>
>
> Could we not store the converted memwords here, instead of the enum value
> here
> and convert it every time we access it ?

Sure, I can fix that.

Thanks for the review,
Mathieu

>
> Cheers
> Suzuki

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

* [PATCH V2 12/15] coresight: tmc: keep track of memory width
@ 2016-04-15 16:10       ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-15 16:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 14 April 2016 at 05:19, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> Accessing the HW configuration register each time the memory
>> width is needed simply doesn't make sense.  It is much more
>> efficient to read the value once and keep a reference for
>> later use.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 8 +++-----
>>   drivers/hwtracing/coresight/coresight-tmc.c     | 1 +
>>   drivers/hwtracing/coresight/coresight-tmc.h     | 2 ++
>>   3 files changed, 6 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> index 50d32e8ef4ea..a440784e3b27 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> @@ -41,18 +41,16 @@ void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
>>
>>   static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
>>   {
>> -       enum tmc_mem_intf_width memwidth;
>>         u8 memwords;
>>         char *bufp;
>>         u32 read_data;
>>         int i;
>>
>> -       memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID),
>> 8, 10);
>> -       if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
>> +       if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_32BITS)
>>                 memwords = 1;
>> -       else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
>> +       else if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_64BITS)
>>                 memwords = 2;
>> -       else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
>> +       else if (drvdata->memwidth == TMC_MEM_INTF_WIDTH_128BITS)
>>                 memwords = 4;
>
>
>
>>   struct tmc_drvdata {
>> @@ -118,6 +119,7 @@ struct tmc_drvdata {
>>         u32                     size;
>>         local_t                 mode;
>>         enum tmc_config_type    config_type;
>> +       enum tmc_mem_intf_width memwidth;
>
>
> Could we not store the converted memwords here, instead of the enum value
> here
> and convert it every time we access it ?

Sure, I can fix that.

Thanks for the review,
Mathieu

>
> Cheers
> Suzuki

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

* Re: [PATCH V2 04/15] coresight: tmc: introducing new header file
  2016-04-15 16:08         ` Suzuki K Poulose
@ 2016-04-15 16:15           ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-15 16:15 UTC (permalink / raw)
  To: Suzuki K Poulose; +Cc: linux-arm-kernel, linux-kernel

On 15 April 2016 at 10:08, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 15/04/16 17:03, Mathieu Poirier wrote:
>>
>> On 14 April 2016 at 11:33, Suzuki K Poulose <Suzuki.Poulose@arm.com>
>> wrote:
>>>
>>> On 12/04/16 18:54, Mathieu Poirier wrote:
>>>>
>>>>
>>>> The amount of #define, enumeration and structure definition
>>>> is big enough to justify moving them to a new header file.
>>>>
>>>
>>>
>>>> +/* TMC_STS - 0x00C */
>>>> +#define TMC_STS_TRIGGERED      BIT(1)
>>>
>>>
>>>
>>> ...
>>>
>>>> +#define TMC_AXICTL_WR_BURST_LEN 0xF00
>>>
>>>
>>>
>>> Nit: The value above signifies, 16 data transfers per burst.
>>> So ideally it would be good to rename it to reflect that. say,
>>>
>>> TMC_AXICTL_WR_BURST_16
>>
>>
>> Will do.  But I'll have to do this in a separate patch then the
>> grouping of STS_ and FFCR_ defines you're referring to below since it
>> will also require changes to the .c files.
>
>
> Yes, I don't expect this change to be part of the patch. Separate patch
> is fine.
>
>>
>>>
>>>
>>>
>>>> +/* TMC_FFCR - 0x304 */
>>>> +#define TMC_FFCR_EN_FMT                BIT(0)
>>>> +#define TMC_FFCR_EN_TI         BIT(1)
>>>> +#define TMC_FFCR_FON_FLIN      BIT(4)
>>>> +#define TMC_FFCR_FON_TRIG_EVT  BIT(5)
>>>> +#define TMC_FFCR_FLUSHMAN      BIT(6)
>>>> +#define TMC_FFCR_TRIGON_TRIGIN BIT(8)
>>>> +#define TMC_FFCR_STOP_ON_FLUSH BIT(12)
>>>> +
>>>> +#define TMC_STS_TMCREADY_BIT   2
>>>
>>>
>>>
>>>> +#define TMC_FFCR_FLUSHMAN_BIT  6
>>>
>>>
>>>
>>> nit: It would be nice to group the STS_ and FFCR_ bits together.
>>> Also I see that the defintion for
>>> TMC_STS_FULL is added in a completely unrelated patch (TMC-ETF AUX SPACE
>>> patch ?). It would be good to add it either here or in a different patch.
>>
>>
>> TMC_STS_FULL is not added here because at this point it is not used by
>> the code - it is only added later when it is useful.
>
>
> I agree. But the patch which introduces the definition doesn't deal with
> TMC_STS_ at all either.

Patch 13/15 is using the TMC_STS_FULL define on line 147.  Am I
missing your point?

>Thats why I said, either here or in a different
> patch
> than what is there. May be you could club the change above and the STS_FULL
> into a new single patch. Its not mandatory though.
>
> Suzuki

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

* [PATCH V2 04/15] coresight: tmc: introducing new header file
@ 2016-04-15 16:15           ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-15 16:15 UTC (permalink / raw)
  To: linux-arm-kernel

On 15 April 2016 at 10:08, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 15/04/16 17:03, Mathieu Poirier wrote:
>>
>> On 14 April 2016 at 11:33, Suzuki K Poulose <Suzuki.Poulose@arm.com>
>> wrote:
>>>
>>> On 12/04/16 18:54, Mathieu Poirier wrote:
>>>>
>>>>
>>>> The amount of #define, enumeration and structure definition
>>>> is big enough to justify moving them to a new header file.
>>>>
>>>
>>>
>>>> +/* TMC_STS - 0x00C */
>>>> +#define TMC_STS_TRIGGERED      BIT(1)
>>>
>>>
>>>
>>> ...
>>>
>>>> +#define TMC_AXICTL_WR_BURST_LEN 0xF00
>>>
>>>
>>>
>>> Nit: The value above signifies, 16 data transfers per burst.
>>> So ideally it would be good to rename it to reflect that. say,
>>>
>>> TMC_AXICTL_WR_BURST_16
>>
>>
>> Will do.  But I'll have to do this in a separate patch then the
>> grouping of STS_ and FFCR_ defines you're referring to below since it
>> will also require changes to the .c files.
>
>
> Yes, I don't expect this change to be part of the patch. Separate patch
> is fine.
>
>>
>>>
>>>
>>>
>>>> +/* TMC_FFCR - 0x304 */
>>>> +#define TMC_FFCR_EN_FMT                BIT(0)
>>>> +#define TMC_FFCR_EN_TI         BIT(1)
>>>> +#define TMC_FFCR_FON_FLIN      BIT(4)
>>>> +#define TMC_FFCR_FON_TRIG_EVT  BIT(5)
>>>> +#define TMC_FFCR_FLUSHMAN      BIT(6)
>>>> +#define TMC_FFCR_TRIGON_TRIGIN BIT(8)
>>>> +#define TMC_FFCR_STOP_ON_FLUSH BIT(12)
>>>> +
>>>> +#define TMC_STS_TMCREADY_BIT   2
>>>
>>>
>>>
>>>> +#define TMC_FFCR_FLUSHMAN_BIT  6
>>>
>>>
>>>
>>> nit: It would be nice to group the STS_ and FFCR_ bits together.
>>> Also I see that the defintion for
>>> TMC_STS_FULL is added in a completely unrelated patch (TMC-ETF AUX SPACE
>>> patch ?). It would be good to add it either here or in a different patch.
>>
>>
>> TMC_STS_FULL is not added here because at this point it is not used by
>> the code - it is only added later when it is useful.
>
>
> I agree. But the patch which introduces the definition doesn't deal with
> TMC_STS_ at all either.

Patch 13/15 is using the TMC_STS_FULL define on line 147.  Am I
missing your point?

>Thats why I said, either here or in a different
> patch
> than what is there. May be you could club the change above and the STS_FULL
> into a new single patch. Its not mandatory though.
>
> Suzuki

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

* Re: [PATCH V2 04/15] coresight: tmc: introducing new header file
  2016-04-15 16:15           ` Mathieu Poirier
@ 2016-04-15 16:18             ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-15 16:18 UTC (permalink / raw)
  To: Mathieu Poirier; +Cc: linux-arm-kernel, linux-kernel

On 15/04/16 17:15, Mathieu Poirier wrote:
> On 15 April 2016 at 10:08, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
>> On 15/04/16 17:03, Mathieu Poirier wrote:
>> I agree. But the patch which introduces the definition doesn't deal with
>> TMC_STS_ at all either.
>
> Patch 13/15 is using the TMC_STS_FULL define on line 147.  Am I
> missing your point?

Ah, sorry, didn't see that TMC_STS_FULL was used there. Ignore my comments.

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

* [PATCH V2 04/15] coresight: tmc: introducing new header file
@ 2016-04-15 16:18             ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-15 16:18 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/04/16 17:15, Mathieu Poirier wrote:
> On 15 April 2016 at 10:08, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
>> On 15/04/16 17:03, Mathieu Poirier wrote:
>> I agree. But the patch which introduces the definition doesn't deal with
>> TMC_STS_ at all either.
>
> Patch 13/15 is using the TMC_STS_FULL define on line 147.  Am I
> missing your point?

Ah, sorry, didn't see that TMC_STS_FULL was used there. Ignore my comments.

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

* Re: [PATCH V2 03/15] coresight: tmc: re-implementing tmc_read_prepare/unprepare() functions
  2016-04-15 15:40       ` Mathieu Poirier
@ 2016-04-15 17:41         ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-15 17:41 UTC (permalink / raw)
  To: Mathieu Poirier; +Cc: linux-arm-kernel, linux-kernel

On 15/04/16 16:40, Mathieu Poirier wrote:
> On 14 April 2016 at 11:11, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:

>>
>> Nit. If you move the TMC_CONFIG_TYPE_ETB here, you could fall through from
>> TYPE_ETF: i.e,
>
> Yes, that's what the end result look like [1].  I will refactor to
> make the transition cleaner.
>
> [1]. https://git.linaro.org/kernel/coresight.git/blob/refs/heads/next:/drivers/hwtracing/coresight/coresight-tmc.c#l76

Ok, no need to refactor here then.

>>
>> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

Cheers
Suzuki

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

* [PATCH V2 03/15] coresight: tmc: re-implementing tmc_read_prepare/unprepare() functions
@ 2016-04-15 17:41         ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-15 17:41 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/04/16 16:40, Mathieu Poirier wrote:
> On 14 April 2016 at 11:11, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:

>>
>> Nit. If you move the TMC_CONFIG_TYPE_ETB here, you could fall through from
>> TYPE_ETF: i.e,
>
> Yes, that's what the end result look like [1].  I will refactor to
> make the transition cleaner.
>
> [1]. https://git.linaro.org/kernel/coresight.git/blob/refs/heads/next:/drivers/hwtracing/coresight/coresight-tmc.c#l76

Ok, no need to refactor here then.

>>
>> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

Cheers
Suzuki

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

* Re: [PATCH V2 05/15] coresight: tmc: splitting driver in ETB/ETF and ETR components
  2016-04-12 17:54   ` Mathieu Poirier
@ 2016-04-19 12:20     ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 12:20 UTC (permalink / raw)
  To: Mathieu Poirier, linux-arm-kernel; +Cc: linux-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> The TMC block can operate in 3 modes (ETB, ETF and ETR) and accessed
> via two interfaces (sysFS and Perf).  That makes 6 mode to cover, which
> is way too much coupling for a single file.
>
> This patch splits the original TMC driver in 2 halves, one for ETB/ETF
> and another one for ETR mode.  A common core is kept for functionality
> common to all 3 modes.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>


> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
> index 2d7d52747b4e..b99d4dfc1d0b 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc.h
> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
> @@ -18,6 +18,8 @@
>   #ifndef _CORESIGHT_TMC_H
>   #define _CORESIGHT_TMC_H
>
> +#include <linux/miscdevice.h>
> +

What was this for ?

Irrespective of that,

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

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

* [PATCH V2 05/15] coresight: tmc: splitting driver in ETB/ETF and ETR components
@ 2016-04-19 12:20     ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 12:20 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> The TMC block can operate in 3 modes (ETB, ETF and ETR) and accessed
> via two interfaces (sysFS and Perf).  That makes 6 mode to cover, which
> is way too much coupling for a single file.
>
> This patch splits the original TMC driver in 2 halves, one for ETB/ETF
> and another one for ETR mode.  A common core is kept for functionality
> common to all 3 modes.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>


> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
> index 2d7d52747b4e..b99d4dfc1d0b 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc.h
> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
> @@ -18,6 +18,8 @@
>   #ifndef _CORESIGHT_TMC_H
>   #define _CORESIGHT_TMC_H
>
> +#include <linux/miscdevice.h>
> +

What was this for ?

Irrespective of that,

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

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

* Re: [PATCH V2 06/15] coresight: tmc: making prepare/unprepare functions generic
  2016-04-12 17:54   ` Mathieu Poirier
@ 2016-04-19 12:30     ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 12:30 UTC (permalink / raw)
  To: Mathieu Poirier, linux-arm-kernel; +Cc: linux-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> Dealing with HW related matters in tmc_read_prepare/unprepare
> becomes convoluted when many cases need to be handled distinctively.
>
> As such moving processing related to HW setup to individual driver
> files and keep the core driver generic.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 62 ++++++++++++++++++++++++-
>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 42 ++++++++++++++++-
>   drivers/hwtracing/coresight/coresight-tmc.c     | 55 +++++-----------------
>   drivers/hwtracing/coresight/coresight-tmc.h     |  8 ++--
>   4 files changed, 117 insertions(+), 50 deletions(-)
>

> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 910d6f3b7d26..495540e9064d 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -70,7 +70,7 @@ static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
>   		drvdata->buf = drvdata->vaddr;
>   }
>
> -void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
> +static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>   {
>   	CS_UNLOCK(drvdata->base);
>
> @@ -126,3 +126,43 @@ static const struct coresight_ops_sink tmc_etr_sink_ops = {
>   const struct coresight_ops tmc_etr_cs_ops = {
>   	.sink_ops	= &tmc_etr_sink_ops,
>   };
> +
> +int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
> +{
> +	unsigned long flags;
> +
> +	/* config types are set a boot time and never change */
> +	if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
> +		return -EINVAL;

...

> +
> +int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
> +{
> +	unsigned long flags;
> +
> +	/* config types are set a boot time and never change */
> +	if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
> +		return -EINVAL;
> +

For both cases above should we WARN_ON_ONCE() if we encounter such a case ?

Irrespective of that,

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

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

* [PATCH V2 06/15] coresight: tmc: making prepare/unprepare functions generic
@ 2016-04-19 12:30     ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 12:30 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> Dealing with HW related matters in tmc_read_prepare/unprepare
> becomes convoluted when many cases need to be handled distinctively.
>
> As such moving processing related to HW setup to individual driver
> files and keep the core driver generic.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 62 ++++++++++++++++++++++++-
>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 42 ++++++++++++++++-
>   drivers/hwtracing/coresight/coresight-tmc.c     | 55 +++++-----------------
>   drivers/hwtracing/coresight/coresight-tmc.h     |  8 ++--
>   4 files changed, 117 insertions(+), 50 deletions(-)
>

> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 910d6f3b7d26..495540e9064d 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -70,7 +70,7 @@ static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
>   		drvdata->buf = drvdata->vaddr;
>   }
>
> -void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
> +static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>   {
>   	CS_UNLOCK(drvdata->base);
>
> @@ -126,3 +126,43 @@ static const struct coresight_ops_sink tmc_etr_sink_ops = {
>   const struct coresight_ops tmc_etr_cs_ops = {
>   	.sink_ops	= &tmc_etr_sink_ops,
>   };
> +
> +int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
> +{
> +	unsigned long flags;
> +
> +	/* config types are set a boot time and never change */
> +	if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
> +		return -EINVAL;

...

> +
> +int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
> +{
> +	unsigned long flags;
> +
> +	/* config types are set a boot time and never change */
> +	if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
> +		return -EINVAL;
> +

For both cases above should we WARN_ON_ONCE() if we encounter such a case ?

Irrespective of that,

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

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

* Re: [PATCH V2 07/15] coresight: tmc: allocating memory when needed
  2016-04-12 17:54   ` Mathieu Poirier
@ 2016-04-19 12:55     ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 12:55 UTC (permalink / raw)
  To: Mathieu Poirier, linux-arm-kernel; +Cc: linux-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> In it's current form the TMC probe() function allocates
> trace buffer memory at boot time, event if coresight isn't
> used.  This is highly inefficient since trace buffers can
> occupy a lot of memory that could be used otherwised.
>
> This patch allocates trace buffers on the fly, when the
> coresight subsystem is solicited.  Allocated buffers are
> released when traces are read using the device descriptors
> under /dev.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 85 +++++++++++++++++++++++--
>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 83 +++++++++++++++++++++++-
>   drivers/hwtracing/coresight/coresight-tmc.c     | 14 ----
>   3 files changed, 163 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> index 4b8f39bd478b..7cb287ef7b9e 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> @@ -16,14 +16,12 @@
>    */
>
>   #include <linux/coresight.h>
> +#include <linux/slab.h>
>   #include "coresight-priv.h"
>   #include "coresight-tmc.h"
>
>   void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
>   {
> -	/* Zero out the memory to help with debug */
> -	memset(drvdata->buf, 0, drvdata->size);
> -
>   	CS_UNLOCK(drvdata->base);
>
>   	/* Wait for TMCSReady bit to be set */
> @@ -110,19 +108,68 @@ static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
>
>   static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
>   {
> +	bool allocated = false;

nit: does "used" or buf_used sound more suitable than allocated ?

> +	char *buf = NULL;
>   	unsigned long flags;
>   	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>
> +	 /* This shouldn't be happening */
> +	WARN_ON(mode != CS_MODE_SYSFS);
> +
> +	/*
> +	 * If a buffer is already allocated *keep holding* the lock and
> +	 * jump to the fast path.  Otherwise release the lock and allocate
> +	 * memory to work with.
> +	 */
>   	spin_lock_irqsave(&drvdata->spinlock, flags);
> +	if (drvdata->buf)
> +		goto fast_path;
> +
> +	spin_unlock_irqrestore(&drvdata->spinlock, flags);
> +
> +	/* Allocating the memory here while outside of the spinlock */
> +	buf = kzalloc(drvdata->size, GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	/* Let's try again */
> +	spin_lock_irqsave(&drvdata->spinlock, flags);
> +fast_path:
>   	if (drvdata->reading) {
>   		spin_unlock_irqrestore(&drvdata->spinlock, flags);
> +		/*
> +		 * Free allocated memory outside of the spinlock.  There is
> +		 * no need to assert the validity of 'buf' since calling
> +		 * kfree(NULL) is safe.
> +		 */
> +		kfree(buf);
>   		return -EBUSY;
>   	}

We could check do the above check, before the allocation and avoid an unnecessary
alloc/free() if we really don't need that. And may be its better to get rid of the
"jump to fastpath" to avoid complicating the code, by using something like :

	lock();
	if (drvdata->reading) {
		rc = -EBUSY;
		goto unlock_out;
	}

	if (!drvdata->buf) {
	/* Drop the lock here before allocation and retake the lock */
		unlock();
		alloc();
		lock();
		if (!buf) {
			rc = -ENOMEM;
			goto unlock_out;
		}
	}
...

> +
>   	tmc_etb_enable_hw(drvdata);
>   	drvdata->enable = true;

unlock_out:

>   	spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> +	/* Free memory outside the spinlock if need be */
> +	if (!allocated && buf)
> +		kfree(buf);
> +



> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 495540e9064d..6022ff26deba 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -16,6 +16,7 @@
>    */
>
>   #include <linux/coresight.h>
> +#include <linux/dma-mapping.h>
>   #include "coresight-priv.h"
>   #include "coresight-tmc.h"
>
> @@ -83,19 +84,69 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>
>   static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
>   {

> +
> +	/*
> +	 * If a buffer is already allocated *keep holding* the lock and
> +	 * jump to the fast path.  Otherwise release the lock and allocate
> +	 * memory to work with.
> +	 */
> +	spin_lock_irqsave(&drvdata->spinlock, flags);
> +	if (drvdata->vaddr)
> +		goto fast_path;
> +
> +	spin_unlock_irqrestore(&drvdata->spinlock, flags);
> +
> +	/*
> +	 * Contiguous  memory can't be allocated while a spinlock is held.
> +	 * As such allocate memory here and free it if a buffer has already
> +	 * been allocated (from a previous session).
> +	 */
> +	vaddr = dma_alloc_coherent(drvdata->dev, drvdata->size,
> +				   &paddr, GFP_KERNEL);
> +	if (!vaddr)
> +		return -ENOMEM;
> +
> +	/* Let's try again */
>   	spin_lock_irqsave(&drvdata->spinlock, flags);
> +fast_path:
>   	if (drvdata->reading) {
>   		spin_unlock_irqrestore(&drvdata->spinlock, flags);
> +		if (vaddr)
> +			dma_free_coherent(drvdata->dev, drvdata->size,
> +					  vaddr, paddr);
>   		return -EBUSY;
>   	}

Same as above, if you move the check above before allocation, we could avoid
the alloc/free for such cases. And it would be better if simplify the code without
using the fast_path label to the middle of the code.

Otherwise, looks good.

Thanks
Suzuki

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

* [PATCH V2 07/15] coresight: tmc: allocating memory when needed
@ 2016-04-19 12:55     ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 12:55 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> In it's current form the TMC probe() function allocates
> trace buffer memory at boot time, event if coresight isn't
> used.  This is highly inefficient since trace buffers can
> occupy a lot of memory that could be used otherwised.
>
> This patch allocates trace buffers on the fly, when the
> coresight subsystem is solicited.  Allocated buffers are
> released when traces are read using the device descriptors
> under /dev.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 85 +++++++++++++++++++++++--
>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 83 +++++++++++++++++++++++-
>   drivers/hwtracing/coresight/coresight-tmc.c     | 14 ----
>   3 files changed, 163 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> index 4b8f39bd478b..7cb287ef7b9e 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> @@ -16,14 +16,12 @@
>    */
>
>   #include <linux/coresight.h>
> +#include <linux/slab.h>
>   #include "coresight-priv.h"
>   #include "coresight-tmc.h"
>
>   void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
>   {
> -	/* Zero out the memory to help with debug */
> -	memset(drvdata->buf, 0, drvdata->size);
> -
>   	CS_UNLOCK(drvdata->base);
>
>   	/* Wait for TMCSReady bit to be set */
> @@ -110,19 +108,68 @@ static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
>
>   static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
>   {
> +	bool allocated = false;

nit: does "used" or buf_used sound more suitable than allocated ?

> +	char *buf = NULL;
>   	unsigned long flags;
>   	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>
> +	 /* This shouldn't be happening */
> +	WARN_ON(mode != CS_MODE_SYSFS);
> +
> +	/*
> +	 * If a buffer is already allocated *keep holding* the lock and
> +	 * jump to the fast path.  Otherwise release the lock and allocate
> +	 * memory to work with.
> +	 */
>   	spin_lock_irqsave(&drvdata->spinlock, flags);
> +	if (drvdata->buf)
> +		goto fast_path;
> +
> +	spin_unlock_irqrestore(&drvdata->spinlock, flags);
> +
> +	/* Allocating the memory here while outside of the spinlock */
> +	buf = kzalloc(drvdata->size, GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	/* Let's try again */
> +	spin_lock_irqsave(&drvdata->spinlock, flags);
> +fast_path:
>   	if (drvdata->reading) {
>   		spin_unlock_irqrestore(&drvdata->spinlock, flags);
> +		/*
> +		 * Free allocated memory outside of the spinlock.  There is
> +		 * no need to assert the validity of 'buf' since calling
> +		 * kfree(NULL) is safe.
> +		 */
> +		kfree(buf);
>   		return -EBUSY;
>   	}

We could check do the above check, before the allocation and avoid an unnecessary
alloc/free() if we really don't need that. And may be its better to get rid of the
"jump to fastpath" to avoid complicating the code, by using something like :

	lock();
	if (drvdata->reading) {
		rc = -EBUSY;
		goto unlock_out;
	}

	if (!drvdata->buf) {
	/* Drop the lock here before allocation and retake the lock */
		unlock();
		alloc();
		lock();
		if (!buf) {
			rc = -ENOMEM;
			goto unlock_out;
		}
	}
...

> +
>   	tmc_etb_enable_hw(drvdata);
>   	drvdata->enable = true;

unlock_out:

>   	spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> +	/* Free memory outside the spinlock if need be */
> +	if (!allocated && buf)
> +		kfree(buf);
> +



> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 495540e9064d..6022ff26deba 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -16,6 +16,7 @@
>    */
>
>   #include <linux/coresight.h>
> +#include <linux/dma-mapping.h>
>   #include "coresight-priv.h"
>   #include "coresight-tmc.h"
>
> @@ -83,19 +84,69 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>
>   static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
>   {

> +
> +	/*
> +	 * If a buffer is already allocated *keep holding* the lock and
> +	 * jump to the fast path.  Otherwise release the lock and allocate
> +	 * memory to work with.
> +	 */
> +	spin_lock_irqsave(&drvdata->spinlock, flags);
> +	if (drvdata->vaddr)
> +		goto fast_path;
> +
> +	spin_unlock_irqrestore(&drvdata->spinlock, flags);
> +
> +	/*
> +	 * Contiguous  memory can't be allocated while a spinlock is held.
> +	 * As such allocate memory here and free it if a buffer has already
> +	 * been allocated (from a previous session).
> +	 */
> +	vaddr = dma_alloc_coherent(drvdata->dev, drvdata->size,
> +				   &paddr, GFP_KERNEL);
> +	if (!vaddr)
> +		return -ENOMEM;
> +
> +	/* Let's try again */
>   	spin_lock_irqsave(&drvdata->spinlock, flags);
> +fast_path:
>   	if (drvdata->reading) {
>   		spin_unlock_irqrestore(&drvdata->spinlock, flags);
> +		if (vaddr)
> +			dma_free_coherent(drvdata->dev, drvdata->size,
> +					  vaddr, paddr);
>   		return -EBUSY;
>   	}

Same as above, if you move the check above before allocation, we could avoid
the alloc/free for such cases. And it would be better if simplify the code without
using the fast_path label to the middle of the code.

Otherwise, looks good.

Thanks
Suzuki

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

* Re: [PATCH V2 08/15] coresight: tmc: getting the right read_count on tmc_open()
  2016-04-12 17:54   ` Mathieu Poirier
@ 2016-04-19 13:07     ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 13:07 UTC (permalink / raw)
  To: Mathieu Poirier, linux-arm-kernel; +Cc: linux-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> In function tmc_open(), if tmc_read_prepare() fails variable
> drvdata->read_count is not decremented, causing unwanted
> access to drvdata->buf and very likely, a crash dump.
>
> By moving the incrementation to a place where we know things
> are stable this kind of situation is avoided.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

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

* [PATCH V2 08/15] coresight: tmc: getting the right read_count on tmc_open()
@ 2016-04-19 13:07     ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 13:07 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> In function tmc_open(), if tmc_read_prepare() fails variable
> drvdata->read_count is not decremented, causing unwanted
> access to drvdata->buf and very likely, a crash dump.
>
> By moving the incrementation to a place where we know things
> are stable this kind of situation is avoided.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

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

* Re: [PATCH V2 07/15] coresight: tmc: allocating memory when needed
  2016-04-19 12:55     ` Suzuki K Poulose
@ 2016-04-19 13:14       ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 13:14 UTC (permalink / raw)
  To: Mathieu Poirier, linux-arm-kernel; +Cc: linux-kernel

On 19/04/16 13:55, Suzuki K Poulose wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>> In it's current form the TMC probe() function allocates
>> trace buffer memory at boot time, event if coresight isn't
>> used.  This is highly inefficient since trace buffers can
>> occupy a lot of memory that could be used otherwised.
>>
>> This patch allocates trace buffers on the fly, when the
>> coresight subsystem is solicited.  Allocated buffers are
>> released when traces are read using the device descriptors
>> under /dev.
>>

>>       /* Wait for TMCSReady bit to be set */
>> @@ -110,19 +108,68 @@ static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
>>
>>   static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
>>   {
>> +    bool allocated = false;
>
> nit: does "used" or buf_used sound more suitable than allocated ?
>
>> +    char *buf = NULL;
>>       unsigned long flags;
>>       struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>>
>> +     /* This shouldn't be happening */
>> +    WARN_ON(mode != CS_MODE_SYSFS);

And we should proceed no further. Return immediately.

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

* [PATCH V2 07/15] coresight: tmc: allocating memory when needed
@ 2016-04-19 13:14       ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 13:14 UTC (permalink / raw)
  To: linux-arm-kernel

On 19/04/16 13:55, Suzuki K Poulose wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>> In it's current form the TMC probe() function allocates
>> trace buffer memory at boot time, event if coresight isn't
>> used.  This is highly inefficient since trace buffers can
>> occupy a lot of memory that could be used otherwised.
>>
>> This patch allocates trace buffers on the fly, when the
>> coresight subsystem is solicited.  Allocated buffers are
>> released when traces are read using the device descriptors
>> under /dev.
>>

>>       /* Wait for TMCSReady bit to be set */
>> @@ -110,19 +108,68 @@ static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
>>
>>   static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
>>   {
>> +    bool allocated = false;
>
> nit: does "used" or buf_used sound more suitable than allocated ?
>
>> +    char *buf = NULL;
>>       unsigned long flags;
>>       struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>>
>> +     /* This shouldn't be happening */
>> +    WARN_ON(mode != CS_MODE_SYSFS);

And we should proceed no further. Return immediately.

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

* Re: [PATCH V2 09/15] coresight: tmc: adding mode of operation for link/sinks
  2016-04-12 17:54   ` Mathieu Poirier
@ 2016-04-19 13:19     ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 13:19 UTC (permalink / raw)
  To: Mathieu Poirier, linux-arm-kernel; +Cc: linux-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> Moving tmc_drvdata::enable to a local_t mode.  That way the
> sink interface is aware of it's orgin and the foundation for
> mutual exclusion between the sysFS and Perf interface can be
> laid out.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 28 ++++++++++++++++++-------
>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 24 ++++++++++++++++-----
>   drivers/hwtracing/coresight/coresight-tmc.h     |  4 ++--
>   3 files changed, 42 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> index 7cb287ef7b9e..5908000e1ae0 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> @@ -110,6 +110,7 @@ static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
>   {
>   	bool allocated = false;
>   	char *buf = NULL;
> +	u32 val;
>   	unsigned long flags;
>   	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>
> @@ -146,6 +147,15 @@ fast_path:
>   		return -EBUSY;
>   	}
>
> +	val = local_xchg(&drvdata->mode, mode);
> +	/*
> +	 * In sysFS mode we can have multiple writers per sink.  Since this
> +	 * sink is already enabled no memory is needed and the HW need not be
> +	 * touched.
> +	 */
> +	if (val == CS_MODE_SYSFS)
> +		goto out;
> +

We are not dropping the spinlock in this case. Are we ?

>   	/*
>   	 * If drvdata::buf isn't NULL, memory was allocated for a previous
>   	 * trace run but wasn't read.  If so simply zero-out the memory.
> @@ -163,9 +173,9 @@ fast_path:
>   	}
>
>   	tmc_etb_enable_hw(drvdata);
> -	drvdata->enable = true;
>   	spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> +out:
>   	/* Free memory outside the spinlock if need be */
>   	if (!allocated && buf)
>   		kfree(buf);

> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 6022ff26deba..8e6fe267195a 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -85,6 +85,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>   static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
>   {
>   	bool allocated = false;
> +	u32 val;
>   	unsigned long flags;
>   	void __iomem *vaddr = NULL;
>   	dma_addr_t paddr;
> @@ -125,6 +126,15 @@ fast_path:
>   		return -EBUSY;
>   	}
>
> +	val = local_xchg(&drvdata->mode, mode);
> +	/*
> +	 * In sysFS mode we can have multiple writers per sink.  Since this
> +	 * sink is already enabled no memory is needed and the HW need not be
> +	 * touched.
> +	 */
> +	if (val == CS_MODE_SYSFS)
> +		goto out;
> +

Same as above, we should drop the locks in this case.

> @@ -140,9 +150,9 @@ fast_path:
>   	memset(drvdata->vaddr, 0, drvdata->size);
>
>   	tmc_etr_enable_hw(drvdata);
> -	drvdata->enable = true;
>   	spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> +out:
>   	/* Free memory outside the spinlock if need be */
>   	if (!allocated && vaddr)
>   		dma_free_coherent(drvdata->dev, drvdata->size, vaddr, paddr);
> @@ -153,6 +163,7 @@ fast_path:

> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
> index 80096fa75326..821bdf150ac9 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc.h
> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
> @@ -100,7 +100,7 @@ enum tmc_mem_intf_width {
>    * @paddr:	DMA start location in RAM.
>    * @vaddr:	virtual representation of @paddr.
>    * @size:	@buf size.
> - * @enable:	this TMC is being used.
> + * @mode:	how this TMC is being used.
>    * @config_type: TMC variant, must be of type @tmc_config_type.
>    * @trigger_cntr: amount of words to store after a trigger.
>    */
> @@ -116,7 +116,7 @@ struct tmc_drvdata {
>   	dma_addr_t		paddr;
>   	void __iomem		*vaddr;
>   	u32			size;
> -	bool			enable;
> +	local_t			mode;

Since we always deal with the mode under the spinlock, do we really need this to
be local_t ? Or do we plan to get rid of the lock ?

Suzuki

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

* [PATCH V2 09/15] coresight: tmc: adding mode of operation for link/sinks
@ 2016-04-19 13:19     ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 13:19 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> Moving tmc_drvdata::enable to a local_t mode.  That way the
> sink interface is aware of it's orgin and the foundation for
> mutual exclusion between the sysFS and Perf interface can be
> laid out.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 28 ++++++++++++++++++-------
>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 24 ++++++++++++++++-----
>   drivers/hwtracing/coresight/coresight-tmc.h     |  4 ++--
>   3 files changed, 42 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> index 7cb287ef7b9e..5908000e1ae0 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> @@ -110,6 +110,7 @@ static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
>   {
>   	bool allocated = false;
>   	char *buf = NULL;
> +	u32 val;
>   	unsigned long flags;
>   	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>
> @@ -146,6 +147,15 @@ fast_path:
>   		return -EBUSY;
>   	}
>
> +	val = local_xchg(&drvdata->mode, mode);
> +	/*
> +	 * In sysFS mode we can have multiple writers per sink.  Since this
> +	 * sink is already enabled no memory is needed and the HW need not be
> +	 * touched.
> +	 */
> +	if (val == CS_MODE_SYSFS)
> +		goto out;
> +

We are not dropping the spinlock in this case. Are we ?

>   	/*
>   	 * If drvdata::buf isn't NULL, memory was allocated for a previous
>   	 * trace run but wasn't read.  If so simply zero-out the memory.
> @@ -163,9 +173,9 @@ fast_path:
>   	}
>
>   	tmc_etb_enable_hw(drvdata);
> -	drvdata->enable = true;
>   	spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> +out:
>   	/* Free memory outside the spinlock if need be */
>   	if (!allocated && buf)
>   		kfree(buf);

> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index 6022ff26deba..8e6fe267195a 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -85,6 +85,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>   static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
>   {
>   	bool allocated = false;
> +	u32 val;
>   	unsigned long flags;
>   	void __iomem *vaddr = NULL;
>   	dma_addr_t paddr;
> @@ -125,6 +126,15 @@ fast_path:
>   		return -EBUSY;
>   	}
>
> +	val = local_xchg(&drvdata->mode, mode);
> +	/*
> +	 * In sysFS mode we can have multiple writers per sink.  Since this
> +	 * sink is already enabled no memory is needed and the HW need not be
> +	 * touched.
> +	 */
> +	if (val == CS_MODE_SYSFS)
> +		goto out;
> +

Same as above, we should drop the locks in this case.

> @@ -140,9 +150,9 @@ fast_path:
>   	memset(drvdata->vaddr, 0, drvdata->size);
>
>   	tmc_etr_enable_hw(drvdata);
> -	drvdata->enable = true;
>   	spin_unlock_irqrestore(&drvdata->spinlock, flags);
>
> +out:
>   	/* Free memory outside the spinlock if need be */
>   	if (!allocated && vaddr)
>   		dma_free_coherent(drvdata->dev, drvdata->size, vaddr, paddr);
> @@ -153,6 +163,7 @@ fast_path:

> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
> index 80096fa75326..821bdf150ac9 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc.h
> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
> @@ -100,7 +100,7 @@ enum tmc_mem_intf_width {
>    * @paddr:	DMA start location in RAM.
>    * @vaddr:	virtual representation of @paddr.
>    * @size:	@buf size.
> - * @enable:	this TMC is being used.
> + * @mode:	how this TMC is being used.
>    * @config_type: TMC variant, must be of type @tmc_config_type.
>    * @trigger_cntr: amount of words to store after a trigger.
>    */
> @@ -116,7 +116,7 @@ struct tmc_drvdata {
>   	dma_addr_t		paddr;
>   	void __iomem		*vaddr;
>   	u32			size;
> -	bool			enable;
> +	local_t			mode;

Since we always deal with the mode under the spinlock, do we really need this to
be local_t ? Or do we plan to get rid of the lock ?

Suzuki

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

* Re: [PATCH V2 11/15] coresight: tmc: make sysFS and Perf mode mutually exclusive
  2016-04-12 17:54   ` Mathieu Poirier
@ 2016-04-19 13:42     ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 13:42 UTC (permalink / raw)
  To: Mathieu Poirier, linux-arm-kernel; +Cc: linux-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> The sysFS and Perf access methods can't be allowed to interfere
> with one another.  As such introducing guards to access
> functions that prevents moving forward if a TMC is already
> being used.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 59 +++++++++++++++++++++-
>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 67 +++++++++++++++++++++++--
>   2 files changed, 119 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> index 9b4cdaed09f5..50d32e8ef4ea 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> @@ -111,7 +111,7 @@ static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
>   	CS_LOCK(drvdata->base);
>   }
>
> -static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
> +static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev, u32 mode)
>   {
>   	bool allocated = false;
>   	char *buf = NULL;
> @@ -189,6 +189,53 @@ out:
>   	return 0;
>   }
>
> +static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, u32 mode)
> +{
> +	int ret = 0;
> +	u32 val;

To be on the safer side, I believe 'val' should be unsigned long, to match the size of local_t.

> +	unsigned long flags;
> +	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> +
> +	 /* This shouldn't be happening */
> +	WARN_ON(mode != CS_MODE_PERF);

I think the above check, and the mode parameter itself is superfluous, given
that this is a static function used internally only for the PERF mode.
Similarly for the _sysfs version.

> +
> +	spin_lock_irqsave(&drvdata->spinlock, flags);
> +	if (drvdata->reading) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	val = local_xchg(&drvdata->mode, mode);

We should be using local_cmpxchg() here. Otherwise, we could corrupt the mode.
Similarly for the _sysfs version. I though the previous version of your series
did that.

> +	/*
> +	 * In Perf mode there can be only one writer per sink.  There
> +	 * is also no need to continue if the ETB/ETR is already operated
> +	 * from sysFS.
> +	 */
> +	if (val != CS_MODE_DISABLED) {
> +		ret = -EINVAL;
> +		goto out;
> +	}


>   static void tmc_disable_etf_sink(struct coresight_device *csdev)
>   {
>   	u32 val;
> @@ -271,6 +318,7 @@ const struct coresight_ops tmc_etf_cs_ops = {
>
>   int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
>   {
> +	u32 val;
>   	enum tmc_mode mode;
>   	int ret = 0;
>   	unsigned long flags;
> @@ -289,6 +337,13 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
>   		goto out;
>   	}
>
> +	val = local_read(&drvdata->mode);
> +	/* Don't interfere if operated from Perf */
> +	if (val == CS_MODE_PERF) {
> +		ret = -EINVAL;
> +		goto out;
> +	}

Could we get here when CS_DISABLED ? If not, we could get rid of the check
for CS_MODE_SYSFS below.

> +
>   	/* If drvdata::buf is NULL the trace data has been read already */
>   	if (drvdata->buf == NULL) {
>   		ret = -EINVAL;
> @@ -296,7 +351,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
>   	}
>
>   	/* Disable the TMC if need be */
> -	if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
> +	if (val == CS_MODE_SYSFS)
>   		tmc_etb_disable_hw(drvdata);
See above

>   	drvdata->reading = true;
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index de5cf0056802..04fc63d85696 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -87,7 +87,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>   	CS_LOCK(drvdata->base);
>   }
>
> -static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
> +static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev, u32 mode)
>   {
>   	bool allocated = false;
>   	u32 val;
> @@ -166,6 +166,53 @@ out:
>   	return 0;
>   }
>

> +static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, u32 mode)
...

>   static void tmc_disable_etr_sink(struct coresight_device *csdev)

Same comments as for the etb side.

Suzuki

  {

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

* [PATCH V2 11/15] coresight: tmc: make sysFS and Perf mode mutually exclusive
@ 2016-04-19 13:42     ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 13:42 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> The sysFS and Perf access methods can't be allowed to interfere
> with one another.  As such introducing guards to access
> functions that prevents moving forward if a TMC is already
> being used.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 59 +++++++++++++++++++++-
>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 67 +++++++++++++++++++++++--
>   2 files changed, 119 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> index 9b4cdaed09f5..50d32e8ef4ea 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> @@ -111,7 +111,7 @@ static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
>   	CS_LOCK(drvdata->base);
>   }
>
> -static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
> +static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev, u32 mode)
>   {
>   	bool allocated = false;
>   	char *buf = NULL;
> @@ -189,6 +189,53 @@ out:
>   	return 0;
>   }
>
> +static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, u32 mode)
> +{
> +	int ret = 0;
> +	u32 val;

To be on the safer side, I believe 'val' should be unsigned long, to match the size of local_t.

> +	unsigned long flags;
> +	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> +
> +	 /* This shouldn't be happening */
> +	WARN_ON(mode != CS_MODE_PERF);

I think the above check, and the mode parameter itself is superfluous, given
that this is a static function used internally only for the PERF mode.
Similarly for the _sysfs version.

> +
> +	spin_lock_irqsave(&drvdata->spinlock, flags);
> +	if (drvdata->reading) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	val = local_xchg(&drvdata->mode, mode);

We should be using local_cmpxchg() here. Otherwise, we could corrupt the mode.
Similarly for the _sysfs version. I though the previous version of your series
did that.

> +	/*
> +	 * In Perf mode there can be only one writer per sink.  There
> +	 * is also no need to continue if the ETB/ETR is already operated
> +	 * from sysFS.
> +	 */
> +	if (val != CS_MODE_DISABLED) {
> +		ret = -EINVAL;
> +		goto out;
> +	}


>   static void tmc_disable_etf_sink(struct coresight_device *csdev)
>   {
>   	u32 val;
> @@ -271,6 +318,7 @@ const struct coresight_ops tmc_etf_cs_ops = {
>
>   int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
>   {
> +	u32 val;
>   	enum tmc_mode mode;
>   	int ret = 0;
>   	unsigned long flags;
> @@ -289,6 +337,13 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
>   		goto out;
>   	}
>
> +	val = local_read(&drvdata->mode);
> +	/* Don't interfere if operated from Perf */
> +	if (val == CS_MODE_PERF) {
> +		ret = -EINVAL;
> +		goto out;
> +	}

Could we get here when CS_DISABLED ? If not, we could get rid of the check
for CS_MODE_SYSFS below.

> +
>   	/* If drvdata::buf is NULL the trace data has been read already */
>   	if (drvdata->buf == NULL) {
>   		ret = -EINVAL;
> @@ -296,7 +351,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
>   	}
>
>   	/* Disable the TMC if need be */
> -	if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
> +	if (val == CS_MODE_SYSFS)
>   		tmc_etb_disable_hw(drvdata);
See above

>   	drvdata->reading = true;
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> index de5cf0056802..04fc63d85696 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
> @@ -87,7 +87,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>   	CS_LOCK(drvdata->base);
>   }
>
> -static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
> +static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev, u32 mode)
>   {
>   	bool allocated = false;
>   	u32 val;
> @@ -166,6 +166,53 @@ out:
>   	return 0;
>   }
>

> +static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, u32 mode)
...

>   static void tmc_disable_etr_sink(struct coresight_device *csdev)

Same comments as for the etb side.

Suzuki

  {

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

* Re: [PATCH V2 05/15] coresight: tmc: splitting driver in ETB/ETF and ETR components
  2016-04-19 12:20     ` Suzuki K Poulose
@ 2016-04-19 15:14       ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-19 15:14 UTC (permalink / raw)
  To: Suzuki K Poulose; +Cc: linux-arm-kernel, linux-kernel

On 19 April 2016 at 06:20, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> The TMC block can operate in 3 modes (ETB, ETF and ETR) and accessed
>> via two interfaces (sysFS and Perf).  That makes 6 mode to cover, which
>> is way too much coupling for a single file.
>>
>> This patch splits the original TMC driver in 2 halves, one for ETB/ETF
>> and another one for ETR mode.  A common core is kept for functionality
>> common to all 3 modes.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>
>
>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h
>> b/drivers/hwtracing/coresight/coresight-tmc.h
>> index 2d7d52747b4e..b99d4dfc1d0b 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc.h
>> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
>> @@ -18,6 +18,8 @@
>>   #ifndef _CORESIGHT_TMC_H
>>   #define _CORESIGHT_TMC_H
>>
>> +#include <linux/miscdevice.h>
>> +
>
>
> What was this for ?

For the struct tmc_drvdata::miscdev field, used to generate the sink's
entry under /dev.

Thanks,
Mathieu

>
> Irrespective of that,
>
> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
>

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

* [PATCH V2 05/15] coresight: tmc: splitting driver in ETB/ETF and ETR components
@ 2016-04-19 15:14       ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-19 15:14 UTC (permalink / raw)
  To: linux-arm-kernel

On 19 April 2016 at 06:20, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> The TMC block can operate in 3 modes (ETB, ETF and ETR) and accessed
>> via two interfaces (sysFS and Perf).  That makes 6 mode to cover, which
>> is way too much coupling for a single file.
>>
>> This patch splits the original TMC driver in 2 halves, one for ETB/ETF
>> and another one for ETR mode.  A common core is kept for functionality
>> common to all 3 modes.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>
>
>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h
>> b/drivers/hwtracing/coresight/coresight-tmc.h
>> index 2d7d52747b4e..b99d4dfc1d0b 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc.h
>> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
>> @@ -18,6 +18,8 @@
>>   #ifndef _CORESIGHT_TMC_H
>>   #define _CORESIGHT_TMC_H
>>
>> +#include <linux/miscdevice.h>
>> +
>
>
> What was this for ?

For the struct tmc_drvdata::miscdev field, used to generate the sink's
entry under /dev.

Thanks,
Mathieu

>
> Irrespective of that,
>
> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
>

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

* Re: [PATCH V2 06/15] coresight: tmc: making prepare/unprepare functions generic
  2016-04-19 12:30     ` Suzuki K Poulose
@ 2016-04-19 15:22       ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-19 15:22 UTC (permalink / raw)
  To: Suzuki K Poulose; +Cc: linux-arm-kernel, linux-kernel

On 19 April 2016 at 06:30, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> Dealing with HW related matters in tmc_read_prepare/unprepare
>> becomes convoluted when many cases need to be handled distinctively.
>>
>> As such moving processing related to HW setup to individual driver
>> files and keep the core driver generic.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 62
>> ++++++++++++++++++++++++-
>>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 42 ++++++++++++++++-
>>   drivers/hwtracing/coresight/coresight-tmc.c     | 55
>> +++++-----------------
>>   drivers/hwtracing/coresight/coresight-tmc.h     |  8 ++--
>>   4 files changed, 117 insertions(+), 50 deletions(-)
>>
>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> index 910d6f3b7d26..495540e9064d 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> @@ -70,7 +70,7 @@ static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
>>                 drvdata->buf = drvdata->vaddr;
>>   }
>>
>> -void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>> +static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>>   {
>>         CS_UNLOCK(drvdata->base);
>>
>> @@ -126,3 +126,43 @@ static const struct coresight_ops_sink
>> tmc_etr_sink_ops = {
>>   const struct coresight_ops tmc_etr_cs_ops = {
>>         .sink_ops       = &tmc_etr_sink_ops,
>>   };
>> +
>> +int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
>> +{
>> +       unsigned long flags;
>> +
>> +       /* config types are set a boot time and never change */
>> +       if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
>> +               return -EINVAL;
>
>
> ...
>
>> +
>> +int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
>> +{
>> +       unsigned long flags;
>> +
>> +       /* config types are set a boot time and never change */
>> +       if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
>> +               return -EINVAL;
>> +
>
>
> For both cases above should we WARN_ON_ONCE() if we encounter such a case ?

WARN_ON_ONCE() would also be valid, albeit very blunt.  Those
functions are user space triggered and returning -EINVAL will stop
everything - the end result is the same.  I suppose that on such
condition fighting back with a backtrace will force people to pay
attention or report the problem.

>
> Irrespective of that,
>
> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
>

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

* [PATCH V2 06/15] coresight: tmc: making prepare/unprepare functions generic
@ 2016-04-19 15:22       ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-19 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

On 19 April 2016 at 06:30, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> Dealing with HW related matters in tmc_read_prepare/unprepare
>> becomes convoluted when many cases need to be handled distinctively.
>>
>> As such moving processing related to HW setup to individual driver
>> files and keep the core driver generic.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 62
>> ++++++++++++++++++++++++-
>>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 42 ++++++++++++++++-
>>   drivers/hwtracing/coresight/coresight-tmc.c     | 55
>> +++++-----------------
>>   drivers/hwtracing/coresight/coresight-tmc.h     |  8 ++--
>>   4 files changed, 117 insertions(+), 50 deletions(-)
>>
>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> index 910d6f3b7d26..495540e9064d 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> @@ -70,7 +70,7 @@ static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
>>                 drvdata->buf = drvdata->vaddr;
>>   }
>>
>> -void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>> +static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>>   {
>>         CS_UNLOCK(drvdata->base);
>>
>> @@ -126,3 +126,43 @@ static const struct coresight_ops_sink
>> tmc_etr_sink_ops = {
>>   const struct coresight_ops tmc_etr_cs_ops = {
>>         .sink_ops       = &tmc_etr_sink_ops,
>>   };
>> +
>> +int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
>> +{
>> +       unsigned long flags;
>> +
>> +       /* config types are set a boot time and never change */
>> +       if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
>> +               return -EINVAL;
>
>
> ...
>
>> +
>> +int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
>> +{
>> +       unsigned long flags;
>> +
>> +       /* config types are set a boot time and never change */
>> +       if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
>> +               return -EINVAL;
>> +
>
>
> For both cases above should we WARN_ON_ONCE() if we encounter such a case ?

WARN_ON_ONCE() would also be valid, albeit very blunt.  Those
functions are user space triggered and returning -EINVAL will stop
everything - the end result is the same.  I suppose that on such
condition fighting back with a backtrace will force people to pay
attention or report the problem.

>
> Irrespective of that,
>
> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
>

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

* Re: [PATCH V2 06/15] coresight: tmc: making prepare/unprepare functions generic
  2016-04-19 15:22       ` Mathieu Poirier
@ 2016-04-19 15:32         ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 15:32 UTC (permalink / raw)
  To: Mathieu Poirier; +Cc: linux-arm-kernel, linux-kernel

On 19/04/16 16:22, Mathieu Poirier wrote:
> On 19 April 2016 at 06:30, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
>> On 12/04/16 18:54, Mathieu Poirier wrote:
>>>
>>> Dealing with HW related matters in tmc_read_prepare/unprepare
>>> becomes convoluted when many cases need to be handled distinctively.
>>>
>>> As such moving processing related to HW setup to individual driver
>>> files and keep the core driver generic.
>>>
>>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>>> ---
>>>    drivers/hwtracing/coresight/coresight-tmc-etf.c | 62
>>> ++++++++++++++++++++++++-
>>>    drivers/hwtracing/coresight/coresight-tmc-etr.c | 42 ++++++++++++++++-
>>>    drivers/hwtracing/coresight/coresight-tmc.c     | 55
>>> +++++-----------------
>>>    drivers/hwtracing/coresight/coresight-tmc.h     |  8 ++--
>>>    4 files changed, 117 insertions(+), 50 deletions(-)
>>>
>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>> b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>> index 910d6f3b7d26..495540e9064d 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>> @@ -70,7 +70,7 @@ static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
>>>                  drvdata->buf = drvdata->vaddr;
>>>    }
>>>
>>> -void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>>> +static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>>>    {
>>>          CS_UNLOCK(drvdata->base);
>>>
>>> @@ -126,3 +126,43 @@ static const struct coresight_ops_sink
>>> tmc_etr_sink_ops = {
>>>    const struct coresight_ops tmc_etr_cs_ops = {
>>>          .sink_ops       = &tmc_etr_sink_ops,
>>>    };
>>> +
>>> +int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
>>> +{
>>> +       unsigned long flags;
>>> +
>>> +       /* config types are set a boot time and never change */
>>> +       if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
>>> +               return -EINVAL;
>>
>>
>> ...
>>
>>> +
>>> +int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
>>> +{
>>> +       unsigned long flags;
>>> +
>>> +       /* config types are set a boot time and never change */
>>> +       if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
>>> +               return -EINVAL;
>>> +
>>
>>
>> For both cases above should we WARN_ON_ONCE() if we encounter such a case ?
>
> WARN_ON_ONCE() would also be valid, albeit very blunt.  Those
> functions are user space triggered and returning -EINVAL will stop
> everything - the end result is the same.  I suppose that on such
> condition fighting back with a backtrace will force people to pay
> attention or report the problem.

We do necessary checks to route the caller here, so we shouldn't really
hit the condition with the tmc_read_prepare(). So WARN_ON_ONCE() might be a
good check to make sure we don't hit it from say, perf driver or something
really went bad under the hood (corrupted ?). I am not too particular about it.

Suzuki

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

* [PATCH V2 06/15] coresight: tmc: making prepare/unprepare functions generic
@ 2016-04-19 15:32         ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 15:32 UTC (permalink / raw)
  To: linux-arm-kernel

On 19/04/16 16:22, Mathieu Poirier wrote:
> On 19 April 2016 at 06:30, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
>> On 12/04/16 18:54, Mathieu Poirier wrote:
>>>
>>> Dealing with HW related matters in tmc_read_prepare/unprepare
>>> becomes convoluted when many cases need to be handled distinctively.
>>>
>>> As such moving processing related to HW setup to individual driver
>>> files and keep the core driver generic.
>>>
>>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>>> ---
>>>    drivers/hwtracing/coresight/coresight-tmc-etf.c | 62
>>> ++++++++++++++++++++++++-
>>>    drivers/hwtracing/coresight/coresight-tmc-etr.c | 42 ++++++++++++++++-
>>>    drivers/hwtracing/coresight/coresight-tmc.c     | 55
>>> +++++-----------------
>>>    drivers/hwtracing/coresight/coresight-tmc.h     |  8 ++--
>>>    4 files changed, 117 insertions(+), 50 deletions(-)
>>>
>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>> b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>> index 910d6f3b7d26..495540e9064d 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>>> @@ -70,7 +70,7 @@ static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
>>>                  drvdata->buf = drvdata->vaddr;
>>>    }
>>>
>>> -void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>>> +static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
>>>    {
>>>          CS_UNLOCK(drvdata->base);
>>>
>>> @@ -126,3 +126,43 @@ static const struct coresight_ops_sink
>>> tmc_etr_sink_ops = {
>>>    const struct coresight_ops tmc_etr_cs_ops = {
>>>          .sink_ops       = &tmc_etr_sink_ops,
>>>    };
>>> +
>>> +int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
>>> +{
>>> +       unsigned long flags;
>>> +
>>> +       /* config types are set a boot time and never change */
>>> +       if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
>>> +               return -EINVAL;
>>
>>
>> ...
>>
>>> +
>>> +int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
>>> +{
>>> +       unsigned long flags;
>>> +
>>> +       /* config types are set a boot time and never change */
>>> +       if (drvdata->config_type != TMC_CONFIG_TYPE_ETR)
>>> +               return -EINVAL;
>>> +
>>
>>
>> For both cases above should we WARN_ON_ONCE() if we encounter such a case ?
>
> WARN_ON_ONCE() would also be valid, albeit very blunt.  Those
> functions are user space triggered and returning -EINVAL will stop
> everything - the end result is the same.  I suppose that on such
> condition fighting back with a backtrace will force people to pay
> attention or report the problem.

We do necessary checks to route the caller here, so we shouldn't really
hit the condition with the tmc_read_prepare(). So WARN_ON_ONCE() might be a
good check to make sure we don't hit it from say, perf driver or something
really went bad under the hood (corrupted ?). I am not too particular about it.

Suzuki

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

* Re: [PATCH V2 07/15] coresight: tmc: allocating memory when needed
  2016-04-19 12:55     ` Suzuki K Poulose
@ 2016-04-19 15:39       ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-19 15:39 UTC (permalink / raw)
  To: Suzuki K Poulose; +Cc: linux-arm-kernel, linux-kernel

On 19 April 2016 at 06:55, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> In it's current form the TMC probe() function allocates
>> trace buffer memory at boot time, event if coresight isn't
>> used.  This is highly inefficient since trace buffers can
>> occupy a lot of memory that could be used otherwised.
>>
>> This patch allocates trace buffers on the fly, when the
>> coresight subsystem is solicited.  Allocated buffers are
>> released when traces are read using the device descriptors
>> under /dev.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 85
>> +++++++++++++++++++++++--
>>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 83
>> +++++++++++++++++++++++-
>>   drivers/hwtracing/coresight/coresight-tmc.c     | 14 ----
>>   3 files changed, 163 insertions(+), 19 deletions(-)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> index 4b8f39bd478b..7cb287ef7b9e 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> @@ -16,14 +16,12 @@
>>    */
>>
>>   #include <linux/coresight.h>
>> +#include <linux/slab.h>
>>   #include "coresight-priv.h"
>>   #include "coresight-tmc.h"
>>
>>   void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
>>   {
>> -       /* Zero out the memory to help with debug */
>> -       memset(drvdata->buf, 0, drvdata->size);
>> -
>>         CS_UNLOCK(drvdata->base);
>>
>>         /* Wait for TMCSReady bit to be set */
>> @@ -110,19 +108,68 @@ static void tmc_etf_disable_hw(struct tmc_drvdata
>> *drvdata)
>>
>>   static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
>>   {
>> +       bool allocated = false;
>
>
> nit: does "used" or buf_used sound more suitable than allocated ?
>
>> +       char *buf = NULL;
>>         unsigned long flags;
>>         struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>>
>> +        /* This shouldn't be happening */
>> +       WARN_ON(mode != CS_MODE_SYSFS);
>> +
>> +       /*
>> +        * If a buffer is already allocated *keep holding* the lock and
>> +        * jump to the fast path.  Otherwise release the lock and allocate
>> +        * memory to work with.
>> +        */
>>         spin_lock_irqsave(&drvdata->spinlock, flags);
>> +       if (drvdata->buf)
>> +               goto fast_path;
>> +
>> +       spin_unlock_irqrestore(&drvdata->spinlock, flags);
>> +
>> +       /* Allocating the memory here while outside of the spinlock */
>> +       buf = kzalloc(drvdata->size, GFP_KERNEL);
>> +       if (!buf)
>> +               return -ENOMEM;
>> +
>> +       /* Let's try again */
>> +       spin_lock_irqsave(&drvdata->spinlock, flags);
>> +fast_path:
>>         if (drvdata->reading) {
>>                 spin_unlock_irqrestore(&drvdata->spinlock, flags);
>> +               /*
>> +                * Free allocated memory outside of the spinlock.  There
>> is
>> +                * no need to assert the validity of 'buf' since calling
>> +                * kfree(NULL) is safe.
>> +                */
>> +               kfree(buf);
>>                 return -EBUSY;
>>         }
>
>
> We could check do the above check, before the allocation and avoid an
> unnecessary
> alloc/free() if we really don't need that. And may be its better to get rid
> of the
> "jump to fastpath" to avoid complicating the code, by using something like :
>
>         lock();
>         if (drvdata->reading) {
>                 rc = -EBUSY;
>                 goto unlock_out;
>         }
>
>         if (!drvdata->buf) {
>         /* Drop the lock here before allocation and retake the lock */
>                 unlock();
>                 alloc();
>                 lock();

Between the time the lock was released and taken again it is entirely
possible that drvdata->reading has been flipped to 'true', something
the original code does provision for.  When operating manually the
probabilities of something like this happening are infinitely small
but increase seriously when using scripts to control trace collection
and retrieval.

We could check for drvdata->reading again here but then our approach
become very similar.

Thanks,
Mathieu

>                 if (!buf) {
>                         rc = -ENOMEM;
>                         goto unlock_out;
>                 }
>         }
> ...
>
>> +
>>         tmc_etb_enable_hw(drvdata);
>>         drvdata->enable = true;
>
>
> unlock_out:
>
>>         spin_unlock_irqrestore(&drvdata->spinlock, flags);
>>
>> +       /* Free memory outside the spinlock if need be */
>> +       if (!allocated && buf)
>> +               kfree(buf);
>> +
>
>
>
>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> index 495540e9064d..6022ff26deba 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> @@ -16,6 +16,7 @@
>>    */
>>
>>   #include <linux/coresight.h>
>> +#include <linux/dma-mapping.h>
>>   #include "coresight-priv.h"
>>   #include "coresight-tmc.h"
>>
>> @@ -83,19 +84,69 @@ static void tmc_etr_disable_hw(struct tmc_drvdata
>> *drvdata)
>>
>>   static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
>>   {
>
>
>> +
>> +       /*
>> +        * If a buffer is already allocated *keep holding* the lock and
>> +        * jump to the fast path.  Otherwise release the lock and allocate
>> +        * memory to work with.
>> +        */
>> +       spin_lock_irqsave(&drvdata->spinlock, flags);
>> +       if (drvdata->vaddr)
>> +               goto fast_path;
>> +
>> +       spin_unlock_irqrestore(&drvdata->spinlock, flags);
>> +
>> +       /*
>> +        * Contiguous  memory can't be allocated while a spinlock is held.
>> +        * As such allocate memory here and free it if a buffer has
>> already
>> +        * been allocated (from a previous session).
>> +        */
>> +       vaddr = dma_alloc_coherent(drvdata->dev, drvdata->size,
>> +                                  &paddr, GFP_KERNEL);
>> +       if (!vaddr)
>> +               return -ENOMEM;
>> +
>> +       /* Let's try again */
>>         spin_lock_irqsave(&drvdata->spinlock, flags);
>> +fast_path:
>>         if (drvdata->reading) {
>>                 spin_unlock_irqrestore(&drvdata->spinlock, flags);
>> +               if (vaddr)
>> +                       dma_free_coherent(drvdata->dev, drvdata->size,
>> +                                         vaddr, paddr);
>>                 return -EBUSY;
>>         }
>
>
> Same as above, if you move the check above before allocation, we could avoid
> the alloc/free for such cases. And it would be better if simplify the code
> without
> using the fast_path label to the middle of the code.
>
> Otherwise, looks good.
>
> Thanks
> Suzuki

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

* [PATCH V2 07/15] coresight: tmc: allocating memory when needed
@ 2016-04-19 15:39       ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-19 15:39 UTC (permalink / raw)
  To: linux-arm-kernel

On 19 April 2016 at 06:55, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> In it's current form the TMC probe() function allocates
>> trace buffer memory at boot time, event if coresight isn't
>> used.  This is highly inefficient since trace buffers can
>> occupy a lot of memory that could be used otherwised.
>>
>> This patch allocates trace buffers on the fly, when the
>> coresight subsystem is solicited.  Allocated buffers are
>> released when traces are read using the device descriptors
>> under /dev.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 85
>> +++++++++++++++++++++++--
>>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 83
>> +++++++++++++++++++++++-
>>   drivers/hwtracing/coresight/coresight-tmc.c     | 14 ----
>>   3 files changed, 163 insertions(+), 19 deletions(-)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> index 4b8f39bd478b..7cb287ef7b9e 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> @@ -16,14 +16,12 @@
>>    */
>>
>>   #include <linux/coresight.h>
>> +#include <linux/slab.h>
>>   #include "coresight-priv.h"
>>   #include "coresight-tmc.h"
>>
>>   void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
>>   {
>> -       /* Zero out the memory to help with debug */
>> -       memset(drvdata->buf, 0, drvdata->size);
>> -
>>         CS_UNLOCK(drvdata->base);
>>
>>         /* Wait for TMCSReady bit to be set */
>> @@ -110,19 +108,68 @@ static void tmc_etf_disable_hw(struct tmc_drvdata
>> *drvdata)
>>
>>   static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
>>   {
>> +       bool allocated = false;
>
>
> nit: does "used" or buf_used sound more suitable than allocated ?
>
>> +       char *buf = NULL;
>>         unsigned long flags;
>>         struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>>
>> +        /* This shouldn't be happening */
>> +       WARN_ON(mode != CS_MODE_SYSFS);
>> +
>> +       /*
>> +        * If a buffer is already allocated *keep holding* the lock and
>> +        * jump to the fast path.  Otherwise release the lock and allocate
>> +        * memory to work with.
>> +        */
>>         spin_lock_irqsave(&drvdata->spinlock, flags);
>> +       if (drvdata->buf)
>> +               goto fast_path;
>> +
>> +       spin_unlock_irqrestore(&drvdata->spinlock, flags);
>> +
>> +       /* Allocating the memory here while outside of the spinlock */
>> +       buf = kzalloc(drvdata->size, GFP_KERNEL);
>> +       if (!buf)
>> +               return -ENOMEM;
>> +
>> +       /* Let's try again */
>> +       spin_lock_irqsave(&drvdata->spinlock, flags);
>> +fast_path:
>>         if (drvdata->reading) {
>>                 spin_unlock_irqrestore(&drvdata->spinlock, flags);
>> +               /*
>> +                * Free allocated memory outside of the spinlock.  There
>> is
>> +                * no need to assert the validity of 'buf' since calling
>> +                * kfree(NULL) is safe.
>> +                */
>> +               kfree(buf);
>>                 return -EBUSY;
>>         }
>
>
> We could check do the above check, before the allocation and avoid an
> unnecessary
> alloc/free() if we really don't need that. And may be its better to get rid
> of the
> "jump to fastpath" to avoid complicating the code, by using something like :
>
>         lock();
>         if (drvdata->reading) {
>                 rc = -EBUSY;
>                 goto unlock_out;
>         }
>
>         if (!drvdata->buf) {
>         /* Drop the lock here before allocation and retake the lock */
>                 unlock();
>                 alloc();
>                 lock();

Between the time the lock was released and taken again it is entirely
possible that drvdata->reading has been flipped to 'true', something
the original code does provision for.  When operating manually the
probabilities of something like this happening are infinitely small
but increase seriously when using scripts to control trace collection
and retrieval.

We could check for drvdata->reading again here but then our approach
become very similar.

Thanks,
Mathieu

>                 if (!buf) {
>                         rc = -ENOMEM;
>                         goto unlock_out;
>                 }
>         }
> ...
>
>> +
>>         tmc_etb_enable_hw(drvdata);
>>         drvdata->enable = true;
>
>
> unlock_out:
>
>>         spin_unlock_irqrestore(&drvdata->spinlock, flags);
>>
>> +       /* Free memory outside the spinlock if need be */
>> +       if (!allocated && buf)
>> +               kfree(buf);
>> +
>
>
>
>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> index 495540e9064d..6022ff26deba 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> @@ -16,6 +16,7 @@
>>    */
>>
>>   #include <linux/coresight.h>
>> +#include <linux/dma-mapping.h>
>>   #include "coresight-priv.h"
>>   #include "coresight-tmc.h"
>>
>> @@ -83,19 +84,69 @@ static void tmc_etr_disable_hw(struct tmc_drvdata
>> *drvdata)
>>
>>   static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
>>   {
>
>
>> +
>> +       /*
>> +        * If a buffer is already allocated *keep holding* the lock and
>> +        * jump to the fast path.  Otherwise release the lock and allocate
>> +        * memory to work with.
>> +        */
>> +       spin_lock_irqsave(&drvdata->spinlock, flags);
>> +       if (drvdata->vaddr)
>> +               goto fast_path;
>> +
>> +       spin_unlock_irqrestore(&drvdata->spinlock, flags);
>> +
>> +       /*
>> +        * Contiguous  memory can't be allocated while a spinlock is held.
>> +        * As such allocate memory here and free it if a buffer has
>> already
>> +        * been allocated (from a previous session).
>> +        */
>> +       vaddr = dma_alloc_coherent(drvdata->dev, drvdata->size,
>> +                                  &paddr, GFP_KERNEL);
>> +       if (!vaddr)
>> +               return -ENOMEM;
>> +
>> +       /* Let's try again */
>>         spin_lock_irqsave(&drvdata->spinlock, flags);
>> +fast_path:
>>         if (drvdata->reading) {
>>                 spin_unlock_irqrestore(&drvdata->spinlock, flags);
>> +               if (vaddr)
>> +                       dma_free_coherent(drvdata->dev, drvdata->size,
>> +                                         vaddr, paddr);
>>                 return -EBUSY;
>>         }
>
>
> Same as above, if you move the check above before allocation, we could avoid
> the alloc/free for such cases. And it would be better if simplify the code
> without
> using the fast_path label to the middle of the code.
>
> Otherwise, looks good.
>
> Thanks
> Suzuki

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

* Re: [PATCH V2 09/15] coresight: tmc: adding mode of operation for link/sinks
  2016-04-19 13:19     ` Suzuki K Poulose
@ 2016-04-19 15:45       ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-19 15:45 UTC (permalink / raw)
  To: Suzuki K Poulose; +Cc: linux-arm-kernel, linux-kernel

On 19 April 2016 at 07:19, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> Moving tmc_drvdata::enable to a local_t mode.  That way the
>> sink interface is aware of it's orgin and the foundation for
>> mutual exclusion between the sysFS and Perf interface can be
>> laid out.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 28
>> ++++++++++++++++++-------
>>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 24
>> ++++++++++++++++-----
>>   drivers/hwtracing/coresight/coresight-tmc.h     |  4 ++--
>>   3 files changed, 42 insertions(+), 14 deletions(-)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> index 7cb287ef7b9e..5908000e1ae0 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> @@ -110,6 +110,7 @@ static int tmc_enable_etf_sink(struct coresight_device
>> *csdev, u32 mode)
>>   {
>>         bool allocated = false;
>>         char *buf = NULL;
>> +       u32 val;
>>         unsigned long flags;
>>         struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>>
>> @@ -146,6 +147,15 @@ fast_path:
>>                 return -EBUSY;
>>         }
>>
>> +       val = local_xchg(&drvdata->mode, mode);
>> +       /*
>> +        * In sysFS mode we can have multiple writers per sink.  Since
>> this
>> +        * sink is already enabled no memory is needed and the HW need not
>> be
>> +        * touched.
>> +        */
>> +       if (val == CS_MODE_SYSFS)
>> +               goto out;
>> +
>
>
> We are not dropping the spinlock in this case. Are we ?

Definitely - thanks for pointing that out.

>
>>         /*
>>          * If drvdata::buf isn't NULL, memory was allocated for a previous
>>          * trace run but wasn't read.  If so simply zero-out the memory.
>> @@ -163,9 +173,9 @@ fast_path:
>>         }
>>
>>         tmc_etb_enable_hw(drvdata);
>> -       drvdata->enable = true;
>>         spin_unlock_irqrestore(&drvdata->spinlock, flags);
>>
>> +out:
>>         /* Free memory outside the spinlock if need be */
>>         if (!allocated && buf)
>>                 kfree(buf);
>
>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> index 6022ff26deba..8e6fe267195a 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> @@ -85,6 +85,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata
>> *drvdata)
>>   static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
>>   {
>>         bool allocated = false;
>> +       u32 val;
>>         unsigned long flags;
>>         void __iomem *vaddr = NULL;
>>         dma_addr_t paddr;
>> @@ -125,6 +126,15 @@ fast_path:
>>                 return -EBUSY;
>>         }
>>
>> +       val = local_xchg(&drvdata->mode, mode);
>> +       /*
>> +        * In sysFS mode we can have multiple writers per sink.  Since
>> this
>> +        * sink is already enabled no memory is needed and the HW need not
>> be
>> +        * touched.
>> +        */
>> +       if (val == CS_MODE_SYSFS)
>> +               goto out;
>> +
>
>
> Same as above, we should drop the locks in this case.
>
>> @@ -140,9 +150,9 @@ fast_path:
>>         memset(drvdata->vaddr, 0, drvdata->size);
>>
>>         tmc_etr_enable_hw(drvdata);
>> -       drvdata->enable = true;
>>         spin_unlock_irqrestore(&drvdata->spinlock, flags);
>>
>> +out:
>>         /* Free memory outside the spinlock if need be */
>>         if (!allocated && vaddr)
>>                 dma_free_coherent(drvdata->dev, drvdata->size, vaddr,
>> paddr);
>> @@ -153,6 +163,7 @@ fast_path:
>
>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h
>> b/drivers/hwtracing/coresight/coresight-tmc.h
>> index 80096fa75326..821bdf150ac9 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc.h
>> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
>> @@ -100,7 +100,7 @@ enum tmc_mem_intf_width {
>>    * @paddr:    DMA start location in RAM.
>>    * @vaddr:    virtual representation of @paddr.
>>    * @size:     @buf size.
>> - * @enable:    this TMC is being used.
>> + * @mode:      how this TMC is being used.
>>    * @config_type: TMC variant, must be of type @tmc_config_type.
>>    * @trigger_cntr: amount of words to store after a trigger.
>>    */
>> @@ -116,7 +116,7 @@ struct tmc_drvdata {
>>         dma_addr_t              paddr;
>>         void __iomem            *vaddr;
>>         u32                     size;
>> -       bool                    enable;
>> +       local_t                 mode;
>
>
> Since we always deal with the mode under the spinlock, do we really need
> this to
> be local_t ? Or do we plan to get rid of the lock ?

You are correct, using a local_t variable isn't strictly needed here.  But:

1) It greatly simplifies the code.
2) I'm really hoping one day we can do without the spinlocks, though I
don't know when that will happen.

Get back to me if you're resolute on switching the local_t to a normal type.

Mathieu

>
> Suzuki
>

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

* [PATCH V2 09/15] coresight: tmc: adding mode of operation for link/sinks
@ 2016-04-19 15:45       ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-19 15:45 UTC (permalink / raw)
  To: linux-arm-kernel

On 19 April 2016 at 07:19, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> Moving tmc_drvdata::enable to a local_t mode.  That way the
>> sink interface is aware of it's orgin and the foundation for
>> mutual exclusion between the sysFS and Perf interface can be
>> laid out.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 28
>> ++++++++++++++++++-------
>>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 24
>> ++++++++++++++++-----
>>   drivers/hwtracing/coresight/coresight-tmc.h     |  4 ++--
>>   3 files changed, 42 insertions(+), 14 deletions(-)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> index 7cb287ef7b9e..5908000e1ae0 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> @@ -110,6 +110,7 @@ static int tmc_enable_etf_sink(struct coresight_device
>> *csdev, u32 mode)
>>   {
>>         bool allocated = false;
>>         char *buf = NULL;
>> +       u32 val;
>>         unsigned long flags;
>>         struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>>
>> @@ -146,6 +147,15 @@ fast_path:
>>                 return -EBUSY;
>>         }
>>
>> +       val = local_xchg(&drvdata->mode, mode);
>> +       /*
>> +        * In sysFS mode we can have multiple writers per sink.  Since
>> this
>> +        * sink is already enabled no memory is needed and the HW need not
>> be
>> +        * touched.
>> +        */
>> +       if (val == CS_MODE_SYSFS)
>> +               goto out;
>> +
>
>
> We are not dropping the spinlock in this case. Are we ?

Definitely - thanks for pointing that out.

>
>>         /*
>>          * If drvdata::buf isn't NULL, memory was allocated for a previous
>>          * trace run but wasn't read.  If so simply zero-out the memory.
>> @@ -163,9 +173,9 @@ fast_path:
>>         }
>>
>>         tmc_etb_enable_hw(drvdata);
>> -       drvdata->enable = true;
>>         spin_unlock_irqrestore(&drvdata->spinlock, flags);
>>
>> +out:
>>         /* Free memory outside the spinlock if need be */
>>         if (!allocated && buf)
>>                 kfree(buf);
>
>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> index 6022ff26deba..8e6fe267195a 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> @@ -85,6 +85,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata
>> *drvdata)
>>   static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
>>   {
>>         bool allocated = false;
>> +       u32 val;
>>         unsigned long flags;
>>         void __iomem *vaddr = NULL;
>>         dma_addr_t paddr;
>> @@ -125,6 +126,15 @@ fast_path:
>>                 return -EBUSY;
>>         }
>>
>> +       val = local_xchg(&drvdata->mode, mode);
>> +       /*
>> +        * In sysFS mode we can have multiple writers per sink.  Since
>> this
>> +        * sink is already enabled no memory is needed and the HW need not
>> be
>> +        * touched.
>> +        */
>> +       if (val == CS_MODE_SYSFS)
>> +               goto out;
>> +
>
>
> Same as above, we should drop the locks in this case.
>
>> @@ -140,9 +150,9 @@ fast_path:
>>         memset(drvdata->vaddr, 0, drvdata->size);
>>
>>         tmc_etr_enable_hw(drvdata);
>> -       drvdata->enable = true;
>>         spin_unlock_irqrestore(&drvdata->spinlock, flags);
>>
>> +out:
>>         /* Free memory outside the spinlock if need be */
>>         if (!allocated && vaddr)
>>                 dma_free_coherent(drvdata->dev, drvdata->size, vaddr,
>> paddr);
>> @@ -153,6 +163,7 @@ fast_path:
>
>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h
>> b/drivers/hwtracing/coresight/coresight-tmc.h
>> index 80096fa75326..821bdf150ac9 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc.h
>> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
>> @@ -100,7 +100,7 @@ enum tmc_mem_intf_width {
>>    * @paddr:    DMA start location in RAM.
>>    * @vaddr:    virtual representation of @paddr.
>>    * @size:     @buf size.
>> - * @enable:    this TMC is being used.
>> + * @mode:      how this TMC is being used.
>>    * @config_type: TMC variant, must be of type @tmc_config_type.
>>    * @trigger_cntr: amount of words to store after a trigger.
>>    */
>> @@ -116,7 +116,7 @@ struct tmc_drvdata {
>>         dma_addr_t              paddr;
>>         void __iomem            *vaddr;
>>         u32                     size;
>> -       bool                    enable;
>> +       local_t                 mode;
>
>
> Since we always deal with the mode under the spinlock, do we really need
> this to
> be local_t ? Or do we plan to get rid of the lock ?

You are correct, using a local_t variable isn't strictly needed here.  But:

1) It greatly simplifies the code.
2) I'm really hoping one day we can do without the spinlocks, though I
don't know when that will happen.

Get back to me if you're resolute on switching the local_t to a normal type.

Mathieu

>
> Suzuki
>

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

* Re: [PATCH V2 09/15] coresight: tmc: adding mode of operation for link/sinks
  2016-04-19 15:45       ` Mathieu Poirier
@ 2016-04-19 15:49         ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 15:49 UTC (permalink / raw)
  To: Mathieu Poirier; +Cc: linux-arm-kernel, linux-kernel

On 19/04/16 16:45, Mathieu Poirier wrote:
> On 19 April 2016 at 07:19, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
>> On 12/04/16 18:54, Mathieu Poirier wrote:
>>>
>>> Moving tmc_drvdata::enable to a local_t mode.  That way the
>>> sink interface is aware of it's orgin and the foundation for
>>> mutual exclusion between the sysFS and Perf interface can be
>>> laid out.
>>>
>>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>>> ---
>>>    drivers/hwtracing/coresight/coresight-tmc-etf.c | 28
>>> ++++++++++++++++++-------
>>>    drivers/hwtracing/coresight/coresight-tmc-etr.c | 24
>>> ++++++++++++++++-----
>>>    drivers/hwtracing/coresight/coresight-tmc.h     |  4 ++--
>>>    3 files changed, 42 insertions(+), 14 deletions(-)
>>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> index 7cb287ef7b9e..5908000e1ae0 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> @@ -110,6 +110,7 @@ static int tmc_enable_etf_sink(struct coresight_device
>>> *csdev, u32 mode)
>>>    {
>>>          bool allocated = false;
>>>          char *buf = NULL;
>>> +       u32 val;
>>>          unsigned long flags;
>>>          struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>>>
>>> @@ -146,6 +147,15 @@ fast_path:
>>>                  return -EBUSY;
>>>          }
>>>
>>> +       val = local_xchg(&drvdata->mode, mode);
>>> +       /*
>>> +        * In sysFS mode we can have multiple writers per sink.  Since
>>> this
>>> +        * sink is already enabled no memory is needed and the HW need not
>>> be
>>> +        * touched.
>>> +        */
>>> +       if (val == CS_MODE_SYSFS)
>>> +               goto out;
>>> +
>>
>>
>> We are not dropping the spinlock in this case. Are we ?
>
> Definitely - thanks for pointing that out.
>
>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h
>>> b/drivers/hwtracing/coresight/coresight-tmc.h
>>> index 80096fa75326..821bdf150ac9 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tmc.h
>>> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
>>> @@ -100,7 +100,7 @@ enum tmc_mem_intf_width {
>>>     * @paddr:    DMA start location in RAM.
>>>     * @vaddr:    virtual representation of @paddr.
>>>     * @size:     @buf size.
>>> - * @enable:    this TMC is being used.
>>> + * @mode:      how this TMC is being used.
>>>     * @config_type: TMC variant, must be of type @tmc_config_type.
>>>     * @trigger_cntr: amount of words to store after a trigger.
>>>     */
>>> @@ -116,7 +116,7 @@ struct tmc_drvdata {
>>>          dma_addr_t              paddr;
>>>          void __iomem            *vaddr;
>>>          u32                     size;
>>> -       bool                    enable;
>>> +       local_t                 mode;
>>
>>
>> Since we always deal with the mode under the spinlock, do we really need
>> this to
>> be local_t ? Or do we plan to get rid of the lock ?
>
> You are correct, using a local_t variable isn't strictly needed here.  But:
>
> 1) It greatly simplifies the code.

+1

> 2) I'm really hoping one day we can do without the spinlocks, though I
> don't know when that will happen.
>
> Get back to me if you're resolute on switching the local_t to a normal type.

No, leave it as it is, as you said, it does simplify the code.

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

* [PATCH V2 09/15] coresight: tmc: adding mode of operation for link/sinks
@ 2016-04-19 15:49         ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 15:49 UTC (permalink / raw)
  To: linux-arm-kernel

On 19/04/16 16:45, Mathieu Poirier wrote:
> On 19 April 2016 at 07:19, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
>> On 12/04/16 18:54, Mathieu Poirier wrote:
>>>
>>> Moving tmc_drvdata::enable to a local_t mode.  That way the
>>> sink interface is aware of it's orgin and the foundation for
>>> mutual exclusion between the sysFS and Perf interface can be
>>> laid out.
>>>
>>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>>> ---
>>>    drivers/hwtracing/coresight/coresight-tmc-etf.c | 28
>>> ++++++++++++++++++-------
>>>    drivers/hwtracing/coresight/coresight-tmc-etr.c | 24
>>> ++++++++++++++++-----
>>>    drivers/hwtracing/coresight/coresight-tmc.h     |  4 ++--
>>>    3 files changed, 42 insertions(+), 14 deletions(-)
>>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> index 7cb287ef7b9e..5908000e1ae0 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> @@ -110,6 +110,7 @@ static int tmc_enable_etf_sink(struct coresight_device
>>> *csdev, u32 mode)
>>>    {
>>>          bool allocated = false;
>>>          char *buf = NULL;
>>> +       u32 val;
>>>          unsigned long flags;
>>>          struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>>>
>>> @@ -146,6 +147,15 @@ fast_path:
>>>                  return -EBUSY;
>>>          }
>>>
>>> +       val = local_xchg(&drvdata->mode, mode);
>>> +       /*
>>> +        * In sysFS mode we can have multiple writers per sink.  Since
>>> this
>>> +        * sink is already enabled no memory is needed and the HW need not
>>> be
>>> +        * touched.
>>> +        */
>>> +       if (val == CS_MODE_SYSFS)
>>> +               goto out;
>>> +
>>
>>
>> We are not dropping the spinlock in this case. Are we ?
>
> Definitely - thanks for pointing that out.
>
>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-tmc.h
>>> b/drivers/hwtracing/coresight/coresight-tmc.h
>>> index 80096fa75326..821bdf150ac9 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tmc.h
>>> +++ b/drivers/hwtracing/coresight/coresight-tmc.h
>>> @@ -100,7 +100,7 @@ enum tmc_mem_intf_width {
>>>     * @paddr:    DMA start location in RAM.
>>>     * @vaddr:    virtual representation of @paddr.
>>>     * @size:     @buf size.
>>> - * @enable:    this TMC is being used.
>>> + * @mode:      how this TMC is being used.
>>>     * @config_type: TMC variant, must be of type @tmc_config_type.
>>>     * @trigger_cntr: amount of words to store after a trigger.
>>>     */
>>> @@ -116,7 +116,7 @@ struct tmc_drvdata {
>>>          dma_addr_t              paddr;
>>>          void __iomem            *vaddr;
>>>          u32                     size;
>>> -       bool                    enable;
>>> +       local_t                 mode;
>>
>>
>> Since we always deal with the mode under the spinlock, do we really need
>> this to
>> be local_t ? Or do we plan to get rid of the lock ?
>
> You are correct, using a local_t variable isn't strictly needed here.  But:
>
> 1) It greatly simplifies the code.

+1

> 2) I'm really hoping one day we can do without the spinlocks, though I
> don't know when that will happen.
>
> Get back to me if you're resolute on switching the local_t to a normal type.

No, leave it as it is, as you said, it does simplify the code.

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

* Re: [PATCH V2 11/15] coresight: tmc: make sysFS and Perf mode mutually exclusive
  2016-04-19 13:42     ` Suzuki K Poulose
@ 2016-04-19 16:16       ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-19 16:16 UTC (permalink / raw)
  To: Suzuki K Poulose; +Cc: linux-arm-kernel, linux-kernel

On 19 April 2016 at 07:42, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> The sysFS and Perf access methods can't be allowed to interfere
>> with one another.  As such introducing guards to access
>> functions that prevents moving forward if a TMC is already
>> being used.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 59
>> +++++++++++++++++++++-
>>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 67
>> +++++++++++++++++++++++--
>>   2 files changed, 119 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> index 9b4cdaed09f5..50d32e8ef4ea 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> @@ -111,7 +111,7 @@ static void tmc_etf_disable_hw(struct tmc_drvdata
>> *drvdata)
>>         CS_LOCK(drvdata->base);
>>   }
>>
>> -static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
>> +static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev, u32
>> mode)
>>   {
>>         bool allocated = false;
>>         char *buf = NULL;
>> @@ -189,6 +189,53 @@ out:
>>         return 0;
>>   }
>>
>> +static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, u32
>> mode)
>> +{
>> +       int ret = 0;
>> +       u32 val;
>
>
> To be on the safer side, I believe 'val' should be unsigned long, to match
> the size of local_t.
>
>> +       unsigned long flags;
>> +       struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>> +
>> +        /* This shouldn't be happening */
>> +       WARN_ON(mode != CS_MODE_PERF);
>
>
> I think the above check, and the mode parameter itself is superfluous, given
> that this is a static function used internally only for the PERF mode.
> Similarly for the _sysfs version.

We definitely misunderstood each other then - the only reason I added
the checks is after what (I thought) you suggested in the previous
revision.

>
>> +
>> +       spin_lock_irqsave(&drvdata->spinlock, flags);
>> +       if (drvdata->reading) {
>> +               ret = -EINVAL;
>> +               goto out;
>> +       }
>> +
>> +       val = local_xchg(&drvdata->mode, mode);
>
>
> We should be using local_cmpxchg() here. Otherwise, we could corrupt the
> mode.

The newly added (above) check allows us to do that now.  There can
only be one value coming in (CS_MODE_PERF) and the current type can
only be CS_MODE_PERF/DISABLED.

> Similarly for the _sysfs version. I though the previous version of your
> series
> did that.
>
>> +       /*
>> +        * In Perf mode there can be only one writer per sink.  There
>> +        * is also no need to continue if the ETB/ETR is already operated
>> +        * from sysFS.
>> +        */
>> +       if (val != CS_MODE_DISABLED) {
>> +               ret = -EINVAL;
>> +               goto out;
>> +       }
>
>
>
>>   static void tmc_disable_etf_sink(struct coresight_device *csdev)
>>   {
>>         u32 val;
>> @@ -271,6 +318,7 @@ const struct coresight_ops tmc_etf_cs_ops = {
>>
>>   int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
>>   {
>> +       u32 val;
>>         enum tmc_mode mode;
>>         int ret = 0;
>>         unsigned long flags;
>> @@ -289,6 +337,13 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
>>                 goto out;
>>         }
>>
>> +       val = local_read(&drvdata->mode);
>> +       /* Don't interfere if operated from Perf */
>> +       if (val == CS_MODE_PERF) {
>> +               ret = -EINVAL;
>> +               goto out;
>> +       }
>
>
> Could we get here when CS_DISABLED ? If not, we could get rid of the check
> for CS_MODE_SYSFS below.
>
>> +
>>         /* If drvdata::buf is NULL the trace data has been read already */
>>         if (drvdata->buf == NULL) {
>>                 ret = -EINVAL;
>> @@ -296,7 +351,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
>>         }
>>
>>         /* Disable the TMC if need be */
>> -       if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
>> +       if (val == CS_MODE_SYSFS)
>>                 tmc_etb_disable_hw(drvdata);
>
> See above

Yes, we can get here when mode is set to CS_MODE_DISABLED.  Someone
can read the /dev/xyz entry whenever they want, including when a sink
hasn't been enabled.

Thanks,
Mathieu

>
>>         drvdata->reading = true;
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> index de5cf0056802..04fc63d85696 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> @@ -87,7 +87,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata
>> *drvdata)
>>         CS_LOCK(drvdata->base);
>>   }
>>
>> -static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
>> +static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev, u32
>> mode)
>>   {
>>         bool allocated = false;
>>         u32 val;
>> @@ -166,6 +166,53 @@ out:
>>         return 0;
>>   }
>>
>
>> +static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, u32
>> mode)
>
> ...
>
>>   static void tmc_disable_etr_sink(struct coresight_device *csdev)
>
>
> Same comments as for the etb side.
>
> Suzuki
>
>  {
>

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

* [PATCH V2 11/15] coresight: tmc: make sysFS and Perf mode mutually exclusive
@ 2016-04-19 16:16       ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-19 16:16 UTC (permalink / raw)
  To: linux-arm-kernel

On 19 April 2016 at 07:42, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> The sysFS and Perf access methods can't be allowed to interfere
>> with one another.  As such introducing guards to access
>> functions that prevents moving forward if a TMC is already
>> being used.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 59
>> +++++++++++++++++++++-
>>   drivers/hwtracing/coresight/coresight-tmc-etr.c | 67
>> +++++++++++++++++++++++--
>>   2 files changed, 119 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> index 9b4cdaed09f5..50d32e8ef4ea 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> @@ -111,7 +111,7 @@ static void tmc_etf_disable_hw(struct tmc_drvdata
>> *drvdata)
>>         CS_LOCK(drvdata->base);
>>   }
>>
>> -static int tmc_enable_etf_sink(struct coresight_device *csdev, u32 mode)
>> +static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev, u32
>> mode)
>>   {
>>         bool allocated = false;
>>         char *buf = NULL;
>> @@ -189,6 +189,53 @@ out:
>>         return 0;
>>   }
>>
>> +static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, u32
>> mode)
>> +{
>> +       int ret = 0;
>> +       u32 val;
>
>
> To be on the safer side, I believe 'val' should be unsigned long, to match
> the size of local_t.
>
>> +       unsigned long flags;
>> +       struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
>> +
>> +        /* This shouldn't be happening */
>> +       WARN_ON(mode != CS_MODE_PERF);
>
>
> I think the above check, and the mode parameter itself is superfluous, given
> that this is a static function used internally only for the PERF mode.
> Similarly for the _sysfs version.

We definitely misunderstood each other then - the only reason I added
the checks is after what (I thought) you suggested in the previous
revision.

>
>> +
>> +       spin_lock_irqsave(&drvdata->spinlock, flags);
>> +       if (drvdata->reading) {
>> +               ret = -EINVAL;
>> +               goto out;
>> +       }
>> +
>> +       val = local_xchg(&drvdata->mode, mode);
>
>
> We should be using local_cmpxchg() here. Otherwise, we could corrupt the
> mode.

The newly added (above) check allows us to do that now.  There can
only be one value coming in (CS_MODE_PERF) and the current type can
only be CS_MODE_PERF/DISABLED.

> Similarly for the _sysfs version. I though the previous version of your
> series
> did that.
>
>> +       /*
>> +        * In Perf mode there can be only one writer per sink.  There
>> +        * is also no need to continue if the ETB/ETR is already operated
>> +        * from sysFS.
>> +        */
>> +       if (val != CS_MODE_DISABLED) {
>> +               ret = -EINVAL;
>> +               goto out;
>> +       }
>
>
>
>>   static void tmc_disable_etf_sink(struct coresight_device *csdev)
>>   {
>>         u32 val;
>> @@ -271,6 +318,7 @@ const struct coresight_ops tmc_etf_cs_ops = {
>>
>>   int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
>>   {
>> +       u32 val;
>>         enum tmc_mode mode;
>>         int ret = 0;
>>         unsigned long flags;
>> @@ -289,6 +337,13 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
>>                 goto out;
>>         }
>>
>> +       val = local_read(&drvdata->mode);
>> +       /* Don't interfere if operated from Perf */
>> +       if (val == CS_MODE_PERF) {
>> +               ret = -EINVAL;
>> +               goto out;
>> +       }
>
>
> Could we get here when CS_DISABLED ? If not, we could get rid of the check
> for CS_MODE_SYSFS below.
>
>> +
>>         /* If drvdata::buf is NULL the trace data has been read already */
>>         if (drvdata->buf == NULL) {
>>                 ret = -EINVAL;
>> @@ -296,7 +351,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
>>         }
>>
>>         /* Disable the TMC if need be */
>> -       if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
>> +       if (val == CS_MODE_SYSFS)
>>                 tmc_etb_disable_hw(drvdata);
>
> See above

Yes, we can get here when mode is set to CS_MODE_DISABLED.  Someone
can read the /dev/xyz entry whenever they want, including when a sink
hasn't been enabled.

Thanks,
Mathieu

>
>>         drvdata->reading = true;
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> index de5cf0056802..04fc63d85696 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
>> @@ -87,7 +87,7 @@ static void tmc_etr_disable_hw(struct tmc_drvdata
>> *drvdata)
>>         CS_LOCK(drvdata->base);
>>   }
>>
>> -static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode)
>> +static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev, u32
>> mode)
>>   {
>>         bool allocated = false;
>>         u32 val;
>> @@ -166,6 +166,53 @@ out:
>>         return 0;
>>   }
>>
>
>> +static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, u32
>> mode)
>
> ...
>
>>   static void tmc_disable_etr_sink(struct coresight_device *csdev)
>
>
> Same comments as for the etb side.
>
> Suzuki
>
>  {
>

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

* Re: [PATCH V2 13/15] coresight: tmc: implementing TMC-ETF AUX space API
  2016-04-12 17:54   ` Mathieu Poirier
@ 2016-04-19 16:16     ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 16:16 UTC (permalink / raw)
  To: Mathieu Poirier, linux-arm-kernel; +Cc: linux-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> This patch implement the AUX area interfaces required to
> use the TMC (configured as an ETF) from the Perf sub-system.
>
> The heuristic is heavily borrowed from the ETB10 implementation.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 198 ++++++++++++++++++++++++
>   drivers/hwtracing/coresight/coresight-tmc.h     |  21 +++
>   2 files changed, 219 insertions(+)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> index a440784e3b27..fff175d4020d 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> @@ -15,7 +15,9 @@
>    * this program.  If not, see <http://www.gnu.org/licenses/>.
>    */
>
> +#include <linux/circ_buf.h>
>   #include <linux/coresight.h>
> +#include <linux/perf_event.h>
>   #include <linux/slab.h>
>   #include "coresight-priv.h"
>   #include "coresight-tmc.h"
> @@ -295,9 +297,205 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
>   	dev_info(drvdata->dev, "TMC disabled\n");
>   }
>
> +static void *tmc_alloc_etf_buffer(struct coresight_device *csdev, int cpu,
> +				  void **pages, int nr_pages, bool overwrite)



> +
> +static void tmc_free_etf_buffer(void *config)
> +{

> +
> +static int tmc_set_etf_buffer(struct coresight_device *csdev,
> +			      struct perf_output_handle *handle,
> +			      void *sink_config)


> +static unsigned long tmc_reset_etf_buffer(struct coresight_device *csdev,
> +					  struct perf_output_handle *handle,
> +					  void *sink_config, bool *lost)
> +{


>   /**
> + * struct cs_buffer - keep track of a recording session' specifics
> + * @cur:	index of the current buffer
> + * @nr_pages:	max number of pages granted to us
> + * @offset:	offset within the current buffer
> + * @data_size:	how much we collected in this run
> + * @lost:	other than zero if we had a HW buffer wrap around
> + * @snapshot:	is this run in snapshot mode
> + * @data_pages:	a handle the ring buffer
> + */
> +struct cs_tmc_buffers {
> +	unsigned int		cur;
> +	unsigned int		nr_pages;
> +	unsigned long		offset;
> +	local_t			data_size;
> +	local_t			lost;
> +	bool			snapshot;
> +	void			**data_pages;
> +};


All of the above look exactly the same as what we have in etb10.c (as you have mentioned).
Is there any chance we could reuse them under a generic name ?

> +
> +static void tmc_update_etf_buffer(struct coresight_device *csdev,


> +	 * Get a hold of the status register and see if a wrap around
> +	 * has occurred.  If so adjust things accordingly.
> +	 */
> +	status = readl_relaxed(drvdata->base + TMC_STS);
> +	if (status & TMC_STS_FULL) {
> +		local_inc(&buf->lost);
> +		to_read = drvdata->size;
> +	} else {
> +		to_read = CIRC_CNT(write_ptr, read_ptr, drvdata->size);
> +	}
> +
> +	/*
> +	 * The TMC RAM buffer may be bigger than the space available in the
> +	 * perf ring buffer (handle->size).  If so advance the RRP so that we
> +	 * get the latest trace data.
> +	 */
> +	if (to_read > handle->size) {
> +		u32 mask = 0;
> +
> +		/*
> +		 * The value written to RRP must be byte-address aligned to
> +		 * the width of the trace memory databus _and_ to a frame
> +		 * boundary (16 byte), whichever is the biggest. For example,
> +		 * for 32-bit, 64-bit and 128-bit wide trace memory, the four
> +		 * LSBs must be 0s. For 256-bit wide trace memory, the five
> +		 * LSBs must be 0s.
> +		 */
> +		switch (drvdata->memwidth) {
> +		case TMC_MEM_INTF_WIDTH_32BITS:
> +		case TMC_MEM_INTF_WIDTH_64BITS:
> +		case TMC_MEM_INTF_WIDTH_128BITS:
> +			mask = GENMASK(31, 5);
> +			break;
> +		case TMC_MEM_INTF_WIDTH_256BITS:
> +			mask = GENMASK(31, 6);
> +			break;
> +		}
> +
> +		/*
> +		 * Make sure the new size is aligned in accordance with the
> +		 * requirement explained above.
> +		 */
> +		to_read -= handle->size & mask;

Shouldn't this be :

		to_read = handle->size & mask;

> +		/* Move the RAM read pointer up */
> +		read_ptr = (write_ptr + drvdata->size) - to_read;
> +		/* Make sure we are still within our limits */
> +		read_ptr &= ~(drvdata->size - 1);
> +		/* Tell the HW */
> +		writel_relaxed(read_ptr, drvdata->base + TMC_RRP);
> +		local_inc(&buf->lost);
> +	}


Suzuki

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

* [PATCH V2 13/15] coresight: tmc: implementing TMC-ETF AUX space API
@ 2016-04-19 16:16     ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 16:16 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> This patch implement the AUX area interfaces required to
> use the TMC (configured as an ETF) from the Perf sub-system.
>
> The heuristic is heavily borrowed from the ETB10 implementation.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 198 ++++++++++++++++++++++++
>   drivers/hwtracing/coresight/coresight-tmc.h     |  21 +++
>   2 files changed, 219 insertions(+)
>
> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> index a440784e3b27..fff175d4020d 100644
> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
> @@ -15,7 +15,9 @@
>    * this program.  If not, see <http://www.gnu.org/licenses/>.
>    */
>
> +#include <linux/circ_buf.h>
>   #include <linux/coresight.h>
> +#include <linux/perf_event.h>
>   #include <linux/slab.h>
>   #include "coresight-priv.h"
>   #include "coresight-tmc.h"
> @@ -295,9 +297,205 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
>   	dev_info(drvdata->dev, "TMC disabled\n");
>   }
>
> +static void *tmc_alloc_etf_buffer(struct coresight_device *csdev, int cpu,
> +				  void **pages, int nr_pages, bool overwrite)



> +
> +static void tmc_free_etf_buffer(void *config)
> +{

> +
> +static int tmc_set_etf_buffer(struct coresight_device *csdev,
> +			      struct perf_output_handle *handle,
> +			      void *sink_config)


> +static unsigned long tmc_reset_etf_buffer(struct coresight_device *csdev,
> +					  struct perf_output_handle *handle,
> +					  void *sink_config, bool *lost)
> +{


>   /**
> + * struct cs_buffer - keep track of a recording session' specifics
> + * @cur:	index of the current buffer
> + * @nr_pages:	max number of pages granted to us
> + * @offset:	offset within the current buffer
> + * @data_size:	how much we collected in this run
> + * @lost:	other than zero if we had a HW buffer wrap around
> + * @snapshot:	is this run in snapshot mode
> + * @data_pages:	a handle the ring buffer
> + */
> +struct cs_tmc_buffers {
> +	unsigned int		cur;
> +	unsigned int		nr_pages;
> +	unsigned long		offset;
> +	local_t			data_size;
> +	local_t			lost;
> +	bool			snapshot;
> +	void			**data_pages;
> +};


All of the above look exactly the same as what we have in etb10.c (as you have mentioned).
Is there any chance we could reuse them under a generic name ?

> +
> +static void tmc_update_etf_buffer(struct coresight_device *csdev,


> +	 * Get a hold of the status register and see if a wrap around
> +	 * has occurred.  If so adjust things accordingly.
> +	 */
> +	status = readl_relaxed(drvdata->base + TMC_STS);
> +	if (status & TMC_STS_FULL) {
> +		local_inc(&buf->lost);
> +		to_read = drvdata->size;
> +	} else {
> +		to_read = CIRC_CNT(write_ptr, read_ptr, drvdata->size);
> +	}
> +
> +	/*
> +	 * The TMC RAM buffer may be bigger than the space available in the
> +	 * perf ring buffer (handle->size).  If so advance the RRP so that we
> +	 * get the latest trace data.
> +	 */
> +	if (to_read > handle->size) {
> +		u32 mask = 0;
> +
> +		/*
> +		 * The value written to RRP must be byte-address aligned to
> +		 * the width of the trace memory databus _and_ to a frame
> +		 * boundary (16 byte), whichever is the biggest. For example,
> +		 * for 32-bit, 64-bit and 128-bit wide trace memory, the four
> +		 * LSBs must be 0s. For 256-bit wide trace memory, the five
> +		 * LSBs must be 0s.
> +		 */
> +		switch (drvdata->memwidth) {
> +		case TMC_MEM_INTF_WIDTH_32BITS:
> +		case TMC_MEM_INTF_WIDTH_64BITS:
> +		case TMC_MEM_INTF_WIDTH_128BITS:
> +			mask = GENMASK(31, 5);
> +			break;
> +		case TMC_MEM_INTF_WIDTH_256BITS:
> +			mask = GENMASK(31, 6);
> +			break;
> +		}
> +
> +		/*
> +		 * Make sure the new size is aligned in accordance with the
> +		 * requirement explained above.
> +		 */
> +		to_read -= handle->size & mask;

Shouldn't this be :

		to_read = handle->size & mask;

> +		/* Move the RAM read pointer up */
> +		read_ptr = (write_ptr + drvdata->size) - to_read;
> +		/* Make sure we are still within our limits */
> +		read_ptr &= ~(drvdata->size - 1);
> +		/* Tell the HW */
> +		writel_relaxed(read_ptr, drvdata->base + TMC_RRP);
> +		local_inc(&buf->lost);
> +	}


Suzuki

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

* Re: [PATCH V2 13/15] coresight: tmc: implementing TMC-ETF AUX space API
  2016-04-19 16:16     ` Suzuki K Poulose
@ 2016-04-19 16:45       ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-19 16:45 UTC (permalink / raw)
  To: Suzuki K Poulose; +Cc: linux-arm-kernel, linux-kernel

On 19 April 2016 at 10:16, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> This patch implement the AUX area interfaces required to
>> use the TMC (configured as an ETF) from the Perf sub-system.
>>
>> The heuristic is heavily borrowed from the ETB10 implementation.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 198
>> ++++++++++++++++++++++++
>>   drivers/hwtracing/coresight/coresight-tmc.h     |  21 +++
>>   2 files changed, 219 insertions(+)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> index a440784e3b27..fff175d4020d 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> @@ -15,7 +15,9 @@
>>    * this program.  If not, see <http://www.gnu.org/licenses/>.
>>    */
>>
>> +#include <linux/circ_buf.h>
>>   #include <linux/coresight.h>
>> +#include <linux/perf_event.h>
>>   #include <linux/slab.h>
>>   #include "coresight-priv.h"
>>   #include "coresight-tmc.h"
>> @@ -295,9 +297,205 @@ static void tmc_disable_etf_link(struct
>> coresight_device *csdev,
>>         dev_info(drvdata->dev, "TMC disabled\n");
>>   }
>>
>> +static void *tmc_alloc_etf_buffer(struct coresight_device *csdev, int
>> cpu,
>> +                                 void **pages, int nr_pages, bool
>> overwrite)
>
>
>
>
>> +
>> +static void tmc_free_etf_buffer(void *config)
>> +{
>
>
>> +
>> +static int tmc_set_etf_buffer(struct coresight_device *csdev,
>> +                             struct perf_output_handle *handle,
>> +                             void *sink_config)
>
>
>
>> +static unsigned long tmc_reset_etf_buffer(struct coresight_device *csdev,
>> +                                         struct perf_output_handle
>> *handle,
>> +                                         void *sink_config, bool *lost)
>> +{
>
>
>
>>   /**
>> + * struct cs_buffer - keep track of a recording session' specifics
>> + * @cur:       index of the current buffer
>> + * @nr_pages:  max number of pages granted to us
>> + * @offset:    offset within the current buffer
>> + * @data_size: how much we collected in this run
>> + * @lost:      other than zero if we had a HW buffer wrap around
>> + * @snapshot:  is this run in snapshot mode
>> + * @data_pages:        a handle the ring buffer
>> + */
>> +struct cs_tmc_buffers {
>> +       unsigned int            cur;
>> +       unsigned int            nr_pages;
>> +       unsigned long           offset;
>> +       local_t                 data_size;
>> +       local_t                 lost;
>> +       bool                    snapshot;
>> +       void                    **data_pages;
>> +};
>
>
>
> All of the above look exactly the same as what we have in etb10.c (as you
> have mentioned).
> Is there any chance we could reuse them under a generic name ?

I toyed with the idea many times...

Today the structures are similar and can be used in both drivers but
it is only a matter for time (probably months) before someone adds new
functionality on one side that isn't compatible with the other side.
When that happens we'll get a bloated struct with fields that aren't
used, depending on where it gets instantiated.  Or the struct will be
split again, coming back to what we have today.

>
>> +
>> +static void tmc_update_etf_buffer(struct coresight_device *csdev,
>
>
>
>> +        * Get a hold of the status register and see if a wrap around
>> +        * has occurred.  If so adjust things accordingly.
>> +        */
>> +       status = readl_relaxed(drvdata->base + TMC_STS);
>> +       if (status & TMC_STS_FULL) {
>> +               local_inc(&buf->lost);
>> +               to_read = drvdata->size;
>> +       } else {
>> +               to_read = CIRC_CNT(write_ptr, read_ptr, drvdata->size);
>> +       }
>> +
>> +       /*
>> +        * The TMC RAM buffer may be bigger than the space available in
>> the
>> +        * perf ring buffer (handle->size).  If so advance the RRP so that
>> we
>> +        * get the latest trace data.
>> +        */
>> +       if (to_read > handle->size) {
>> +               u32 mask = 0;
>> +
>> +               /*
>> +                * The value written to RRP must be byte-address aligned
>> to
>> +                * the width of the trace memory databus _and_ to a frame
>> +                * boundary (16 byte), whichever is the biggest. For
>> example,
>> +                * for 32-bit, 64-bit and 128-bit wide trace memory, the
>> four
>> +                * LSBs must be 0s. For 256-bit wide trace memory, the
>> five
>> +                * LSBs must be 0s.
>> +                */
>> +               switch (drvdata->memwidth) {
>> +               case TMC_MEM_INTF_WIDTH_32BITS:
>> +               case TMC_MEM_INTF_WIDTH_64BITS:
>> +               case TMC_MEM_INTF_WIDTH_128BITS:
>> +                       mask = GENMASK(31, 5);
>> +                       break;
>> +               case TMC_MEM_INTF_WIDTH_256BITS:
>> +                       mask = GENMASK(31, 6);
>> +                       break;
>> +               }
>> +
>> +               /*
>> +                * Make sure the new size is aligned in accordance with
>> the
>> +                * requirement explained above.
>> +                */
>> +               to_read -= handle->size & mask;
>
>
> Shouldn't this be :
>
>                 to_read = handle->size & mask;

You are correct.

>
>> +               /* Move the RAM read pointer up */
>> +               read_ptr = (write_ptr + drvdata->size) - to_read;
>> +               /* Make sure we are still within our limits */
>> +               read_ptr &= ~(drvdata->size - 1);
>> +               /* Tell the HW */
>> +               writel_relaxed(read_ptr, drvdata->base + TMC_RRP);
>> +               local_inc(&buf->lost);
>> +       }
>
>
>
> Suzuki

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

* [PATCH V2 13/15] coresight: tmc: implementing TMC-ETF AUX space API
@ 2016-04-19 16:45       ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-19 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

On 19 April 2016 at 10:16, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> This patch implement the AUX area interfaces required to
>> use the TMC (configured as an ETF) from the Perf sub-system.
>>
>> The heuristic is heavily borrowed from the ETB10 implementation.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>   drivers/hwtracing/coresight/coresight-tmc-etf.c | 198
>> ++++++++++++++++++++++++
>>   drivers/hwtracing/coresight/coresight-tmc.h     |  21 +++
>>   2 files changed, 219 insertions(+)
>>
>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> index a440784e3b27..fff175d4020d 100644
>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>> @@ -15,7 +15,9 @@
>>    * this program.  If not, see <http://www.gnu.org/licenses/>.
>>    */
>>
>> +#include <linux/circ_buf.h>
>>   #include <linux/coresight.h>
>> +#include <linux/perf_event.h>
>>   #include <linux/slab.h>
>>   #include "coresight-priv.h"
>>   #include "coresight-tmc.h"
>> @@ -295,9 +297,205 @@ static void tmc_disable_etf_link(struct
>> coresight_device *csdev,
>>         dev_info(drvdata->dev, "TMC disabled\n");
>>   }
>>
>> +static void *tmc_alloc_etf_buffer(struct coresight_device *csdev, int
>> cpu,
>> +                                 void **pages, int nr_pages, bool
>> overwrite)
>
>
>
>
>> +
>> +static void tmc_free_etf_buffer(void *config)
>> +{
>
>
>> +
>> +static int tmc_set_etf_buffer(struct coresight_device *csdev,
>> +                             struct perf_output_handle *handle,
>> +                             void *sink_config)
>
>
>
>> +static unsigned long tmc_reset_etf_buffer(struct coresight_device *csdev,
>> +                                         struct perf_output_handle
>> *handle,
>> +                                         void *sink_config, bool *lost)
>> +{
>
>
>
>>   /**
>> + * struct cs_buffer - keep track of a recording session' specifics
>> + * @cur:       index of the current buffer
>> + * @nr_pages:  max number of pages granted to us
>> + * @offset:    offset within the current buffer
>> + * @data_size: how much we collected in this run
>> + * @lost:      other than zero if we had a HW buffer wrap around
>> + * @snapshot:  is this run in snapshot mode
>> + * @data_pages:        a handle the ring buffer
>> + */
>> +struct cs_tmc_buffers {
>> +       unsigned int            cur;
>> +       unsigned int            nr_pages;
>> +       unsigned long           offset;
>> +       local_t                 data_size;
>> +       local_t                 lost;
>> +       bool                    snapshot;
>> +       void                    **data_pages;
>> +};
>
>
>
> All of the above look exactly the same as what we have in etb10.c (as you
> have mentioned).
> Is there any chance we could reuse them under a generic name ?

I toyed with the idea many times...

Today the structures are similar and can be used in both drivers but
it is only a matter for time (probably months) before someone adds new
functionality on one side that isn't compatible with the other side.
When that happens we'll get a bloated struct with fields that aren't
used, depending on where it gets instantiated.  Or the struct will be
split again, coming back to what we have today.

>
>> +
>> +static void tmc_update_etf_buffer(struct coresight_device *csdev,
>
>
>
>> +        * Get a hold of the status register and see if a wrap around
>> +        * has occurred.  If so adjust things accordingly.
>> +        */
>> +       status = readl_relaxed(drvdata->base + TMC_STS);
>> +       if (status & TMC_STS_FULL) {
>> +               local_inc(&buf->lost);
>> +               to_read = drvdata->size;
>> +       } else {
>> +               to_read = CIRC_CNT(write_ptr, read_ptr, drvdata->size);
>> +       }
>> +
>> +       /*
>> +        * The TMC RAM buffer may be bigger than the space available in
>> the
>> +        * perf ring buffer (handle->size).  If so advance the RRP so that
>> we
>> +        * get the latest trace data.
>> +        */
>> +       if (to_read > handle->size) {
>> +               u32 mask = 0;
>> +
>> +               /*
>> +                * The value written to RRP must be byte-address aligned
>> to
>> +                * the width of the trace memory databus _and_ to a frame
>> +                * boundary (16 byte), whichever is the biggest. For
>> example,
>> +                * for 32-bit, 64-bit and 128-bit wide trace memory, the
>> four
>> +                * LSBs must be 0s. For 256-bit wide trace memory, the
>> five
>> +                * LSBs must be 0s.
>> +                */
>> +               switch (drvdata->memwidth) {
>> +               case TMC_MEM_INTF_WIDTH_32BITS:
>> +               case TMC_MEM_INTF_WIDTH_64BITS:
>> +               case TMC_MEM_INTF_WIDTH_128BITS:
>> +                       mask = GENMASK(31, 5);
>> +                       break;
>> +               case TMC_MEM_INTF_WIDTH_256BITS:
>> +                       mask = GENMASK(31, 6);
>> +                       break;
>> +               }
>> +
>> +               /*
>> +                * Make sure the new size is aligned in accordance with
>> the
>> +                * requirement explained above.
>> +                */
>> +               to_read -= handle->size & mask;
>
>
> Shouldn't this be :
>
>                 to_read = handle->size & mask;

You are correct.

>
>> +               /* Move the RAM read pointer up */
>> +               read_ptr = (write_ptr + drvdata->size) - to_read;
>> +               /* Make sure we are still within our limits */
>> +               read_ptr &= ~(drvdata->size - 1);
>> +               /* Tell the HW */
>> +               writel_relaxed(read_ptr, drvdata->base + TMC_RRP);
>> +               local_inc(&buf->lost);
>> +       }
>
>
>
> Suzuki

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

* Re: [PATCH V2 13/15] coresight: tmc: implementing TMC-ETF AUX space API
  2016-04-19 16:45       ` Mathieu Poirier
@ 2016-04-19 16:50         ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 16:50 UTC (permalink / raw)
  To: Mathieu Poirier; +Cc: linux-arm-kernel, linux-kernel

On 19/04/16 17:45, Mathieu Poirier wrote:
> On 19 April 2016 at 10:16, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
>> On 12/04/16 18:54, Mathieu Poirier wrote:
>>>
>>> This patch implement the AUX area interfaces required to
>>> use the TMC (configured as an ETF) from the Perf sub-system.
>>>
>>> The heuristic is heavily borrowed from the ETB10 implementation.
>>>
>>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>>> ---
>>>    drivers/hwtracing/coresight/coresight-tmc-etf.c | 198
>>> ++++++++++++++++++++++++
>>>    drivers/hwtracing/coresight/coresight-tmc.h     |  21 +++
>>>    2 files changed, 219 insertions(+)
>>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> index a440784e3b27..fff175d4020d 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> @@ -15,7 +15,9 @@
>>>     * this program.  If not, see <http://www.gnu.org/licenses/>.
>>>     */
>>>
>>> +#include <linux/circ_buf.h>
>>>    #include <linux/coresight.h>
>>> +#include <linux/perf_event.h>
>>>    #include <linux/slab.h>
>>>    #include "coresight-priv.h"
>>>    #include "coresight-tmc.h"
>>> @@ -295,9 +297,205 @@ static void tmc_disable_etf_link(struct
>>> coresight_device *csdev,
>>>          dev_info(drvdata->dev, "TMC disabled\n");
>>>    }
>>>
>>> +static void *tmc_alloc_etf_buffer(struct coresight_device *csdev, int
>>> cpu,
>>> +                                 void **pages, int nr_pages, bool
>>> overwrite)
>>
>>
>>
>>
>>> +
>>> +static void tmc_free_etf_buffer(void *config)
>>> +{
>>
>>
>>> +
>>> +static int tmc_set_etf_buffer(struct coresight_device *csdev,
>>> +                             struct perf_output_handle *handle,
>>> +                             void *sink_config)
>>
>>
>>
>>> +static unsigned long tmc_reset_etf_buffer(struct coresight_device *csdev,
>>> +                                         struct perf_output_handle
>>> *handle,
>>> +                                         void *sink_config, bool *lost)
>>> +{
>>
>>
>>
>>>    /**
>>> + * struct cs_buffer - keep track of a recording session' specifics
>>> + * @cur:       index of the current buffer
>>> + * @nr_pages:  max number of pages granted to us
>>> + * @offset:    offset within the current buffer
>>> + * @data_size: how much we collected in this run
>>> + * @lost:      other than zero if we had a HW buffer wrap around
>>> + * @snapshot:  is this run in snapshot mode
>>> + * @data_pages:        a handle the ring buffer
>>> + */
>>> +struct cs_tmc_buffers {
>>> +       unsigned int            cur;
>>> +       unsigned int            nr_pages;
>>> +       unsigned long           offset;
>>> +       local_t                 data_size;
>>> +       local_t                 lost;
>>> +       bool                    snapshot;
>>> +       void                    **data_pages;
>>> +};
>>
>>
>>
>> All of the above look exactly the same as what we have in etb10.c (as you
>> have mentioned).
>> Is there any chance we could reuse them under a generic name ?
>
> I toyed with the idea many times...
>
> Today the structures are similar and can be used in both drivers but
> it is only a matter for time (probably months) before someone adds new
> functionality on one side that isn't compatible with the other side.
> When that happens we'll get a bloated struct with fields that aren't
> used, depending on where it gets instantiated.  Or the struct will be
> split again, coming back to what we have today.
>

If that happens in future, we know what to do now :)

>>> +                * Make sure the new size is aligned in accordance with
>>> the
>>> +                * requirement explained above.
>>> +                */
>>> +               to_read -= handle->size & mask;
>>
>>
>> Shouldn't this be :
>>
>>                  to_read = handle->size & mask;
>
> You are correct.

This applies to the etb10 code as well. So you might want to fix that as well.

Cheers
Suzuki

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

* [PATCH V2 13/15] coresight: tmc: implementing TMC-ETF AUX space API
@ 2016-04-19 16:50         ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-19 16:50 UTC (permalink / raw)
  To: linux-arm-kernel

On 19/04/16 17:45, Mathieu Poirier wrote:
> On 19 April 2016 at 10:16, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
>> On 12/04/16 18:54, Mathieu Poirier wrote:
>>>
>>> This patch implement the AUX area interfaces required to
>>> use the TMC (configured as an ETF) from the Perf sub-system.
>>>
>>> The heuristic is heavily borrowed from the ETB10 implementation.
>>>
>>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>>> ---
>>>    drivers/hwtracing/coresight/coresight-tmc-etf.c | 198
>>> ++++++++++++++++++++++++
>>>    drivers/hwtracing/coresight/coresight-tmc.h     |  21 +++
>>>    2 files changed, 219 insertions(+)
>>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> index a440784e3b27..fff175d4020d 100644
>>> --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
>>> @@ -15,7 +15,9 @@
>>>     * this program.  If not, see <http://www.gnu.org/licenses/>.
>>>     */
>>>
>>> +#include <linux/circ_buf.h>
>>>    #include <linux/coresight.h>
>>> +#include <linux/perf_event.h>
>>>    #include <linux/slab.h>
>>>    #include "coresight-priv.h"
>>>    #include "coresight-tmc.h"
>>> @@ -295,9 +297,205 @@ static void tmc_disable_etf_link(struct
>>> coresight_device *csdev,
>>>          dev_info(drvdata->dev, "TMC disabled\n");
>>>    }
>>>
>>> +static void *tmc_alloc_etf_buffer(struct coresight_device *csdev, int
>>> cpu,
>>> +                                 void **pages, int nr_pages, bool
>>> overwrite)
>>
>>
>>
>>
>>> +
>>> +static void tmc_free_etf_buffer(void *config)
>>> +{
>>
>>
>>> +
>>> +static int tmc_set_etf_buffer(struct coresight_device *csdev,
>>> +                             struct perf_output_handle *handle,
>>> +                             void *sink_config)
>>
>>
>>
>>> +static unsigned long tmc_reset_etf_buffer(struct coresight_device *csdev,
>>> +                                         struct perf_output_handle
>>> *handle,
>>> +                                         void *sink_config, bool *lost)
>>> +{
>>
>>
>>
>>>    /**
>>> + * struct cs_buffer - keep track of a recording session' specifics
>>> + * @cur:       index of the current buffer
>>> + * @nr_pages:  max number of pages granted to us
>>> + * @offset:    offset within the current buffer
>>> + * @data_size: how much we collected in this run
>>> + * @lost:      other than zero if we had a HW buffer wrap around
>>> + * @snapshot:  is this run in snapshot mode
>>> + * @data_pages:        a handle the ring buffer
>>> + */
>>> +struct cs_tmc_buffers {
>>> +       unsigned int            cur;
>>> +       unsigned int            nr_pages;
>>> +       unsigned long           offset;
>>> +       local_t                 data_size;
>>> +       local_t                 lost;
>>> +       bool                    snapshot;
>>> +       void                    **data_pages;
>>> +};
>>
>>
>>
>> All of the above look exactly the same as what we have in etb10.c (as you
>> have mentioned).
>> Is there any chance we could reuse them under a generic name ?
>
> I toyed with the idea many times...
>
> Today the structures are similar and can be used in both drivers but
> it is only a matter for time (probably months) before someone adds new
> functionality on one side that isn't compatible with the other side.
> When that happens we'll get a bloated struct with fields that aren't
> used, depending on where it gets instantiated.  Or the struct will be
> split again, coming back to what we have today.
>

If that happens in future, we know what to do now :)

>>> +                * Make sure the new size is aligned in accordance with
>>> the
>>> +                * requirement explained above.
>>> +                */
>>> +               to_read -= handle->size & mask;
>>
>>
>> Shouldn't this be :
>>
>>                  to_read = handle->size & mask;
>
> You are correct.

This applies to the etb10 code as well. So you might want to fix that as well.

Cheers
Suzuki

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

* Re: [PATCH V2 15/15] coresight: configuring ETF in FIFO mode when acting as link
  2016-04-12 17:54   ` Mathieu Poirier
@ 2016-04-21 12:53     ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-21 12:53 UTC (permalink / raw)
  To: Mathieu Poirier, linux-arm-kernel; +Cc: linux-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> When part of a path but not identified as a sink, the EFT has to

nit: s/EFT/ETF

> be configured as a link and placed in HW FIFO mode.  As such when
> enabling a path, call the right configuration function based on
> the role the ETF if playing in this trace run.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

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

* [PATCH V2 15/15] coresight: configuring ETF in FIFO mode when acting as link
@ 2016-04-21 12:53     ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-21 12:53 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> When part of a path but not identified as a sink, the EFT has to

nit: s/EFT/ETF

> be configured as a link and placed in HW FIFO mode.  As such when
> enabling a path, call the right configuration function based on
> the role the ETF if playing in this trace run.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>

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

* Re: [PATCH V2 14/15] coresight: tmc: implementing TMC-ETR AUX space API
  2016-04-12 17:54   ` Mathieu Poirier
@ 2016-04-21 16:10     ` Suzuki K Poulose
  -1 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-21 16:10 UTC (permalink / raw)
  To: Mathieu Poirier, linux-arm-kernel; +Cc: linux-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> This patch implement the AUX area interfaces required to
> use the TMC (configured as an ETR) from the Perf sub-system.
>
> The heuristic is heavily borrowed from the ETB10 and TMC-ETF
> implementation.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>

> +static void tmc_update_etr_buffer(struct coresight_device *csdev,
> +				  struct perf_output_handle *handle,
> +				  void *sink_config)
> +{
> +	struct cs_etr_buffers *buf = sink_config;
> +
> +	/*
> +	 * An ETR configured to work in contiguous memory mode works the same
> +	 * was as an ETB or ETF.
> +	 */
> +	tmc_update_etf_buffer(csdev, handle, &buf->tmc);

Really ? I thought the ETR stores the data to the allocated System RAM and can
be read directly from the memory than using the RRD ?

Suzuki

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

* [PATCH V2 14/15] coresight: tmc: implementing TMC-ETR AUX space API
@ 2016-04-21 16:10     ` Suzuki K Poulose
  0 siblings, 0 replies; 96+ messages in thread
From: Suzuki K Poulose @ 2016-04-21 16:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 12/04/16 18:54, Mathieu Poirier wrote:
> This patch implement the AUX area interfaces required to
> use the TMC (configured as an ETR) from the Perf sub-system.
>
> The heuristic is heavily borrowed from the ETB10 and TMC-ETF
> implementation.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>

> +static void tmc_update_etr_buffer(struct coresight_device *csdev,
> +				  struct perf_output_handle *handle,
> +				  void *sink_config)
> +{
> +	struct cs_etr_buffers *buf = sink_config;
> +
> +	/*
> +	 * An ETR configured to work in contiguous memory mode works the same
> +	 * was as an ETB or ETF.
> +	 */
> +	tmc_update_etf_buffer(csdev, handle, &buf->tmc);

Really ? I thought the ETR stores the data to the allocated System RAM and can
be read directly from the memory than using the RRD ?

Suzuki

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

* Re: [PATCH V2 14/15] coresight: tmc: implementing TMC-ETR AUX space API
  2016-04-21 16:10     ` Suzuki K Poulose
@ 2016-04-21 22:00       ` Mathieu Poirier
  -1 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-21 22:00 UTC (permalink / raw)
  To: Suzuki K Poulose; +Cc: linux-arm-kernel, linux-kernel

On 21 April 2016 at 10:10, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> This patch implement the AUX area interfaces required to
>> use the TMC (configured as an ETR) from the Perf sub-system.
>>
>> The heuristic is heavily borrowed from the ETB10 and TMC-ETF
>> implementation.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>
>
>> +static void tmc_update_etr_buffer(struct coresight_device *csdev,
>> +                                 struct perf_output_handle *handle,
>> +                                 void *sink_config)
>> +{
>> +       struct cs_etr_buffers *buf = sink_config;
>> +
>> +       /*
>> +        * An ETR configured to work in contiguous memory mode works the
>> same
>> +        * was as an ETB or ETF.
>> +        */
>> +       tmc_update_etf_buffer(csdev, handle, &buf->tmc);
>
>
> Really ? I thought the ETR stores the data to the allocated System RAM and
> can
> be read directly from the memory than using the RRD ?

Using an ETR in contiguous mode is inefficient to start with.
Regardless of the approach taken trace data has to be copied to perf's
non-contiguous ring buffer pages.  It would be more efficient to copy
bigger chunks of data to the ring buffer (because we can), but I
rather spend my time enabling scatter-gather mode than optimizing a
sub-optimal mode of operation.

This currently work and enables people to use the IP block while
scatter-gather mode is in flight.  I should probably make that clear
in the commit log.

Thanks,
Mathieu

>
> Suzuki
>
>
>

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

* [PATCH V2 14/15] coresight: tmc: implementing TMC-ETR AUX space API
@ 2016-04-21 22:00       ` Mathieu Poirier
  0 siblings, 0 replies; 96+ messages in thread
From: Mathieu Poirier @ 2016-04-21 22:00 UTC (permalink / raw)
  To: linux-arm-kernel

On 21 April 2016 at 10:10, Suzuki K Poulose <Suzuki.Poulose@arm.com> wrote:
> On 12/04/16 18:54, Mathieu Poirier wrote:
>>
>> This patch implement the AUX area interfaces required to
>> use the TMC (configured as an ETR) from the Perf sub-system.
>>
>> The heuristic is heavily borrowed from the ETB10 and TMC-ETF
>> implementation.
>>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>
>
>> +static void tmc_update_etr_buffer(struct coresight_device *csdev,
>> +                                 struct perf_output_handle *handle,
>> +                                 void *sink_config)
>> +{
>> +       struct cs_etr_buffers *buf = sink_config;
>> +
>> +       /*
>> +        * An ETR configured to work in contiguous memory mode works the
>> same
>> +        * was as an ETB or ETF.
>> +        */
>> +       tmc_update_etf_buffer(csdev, handle, &buf->tmc);
>
>
> Really ? I thought the ETR stores the data to the allocated System RAM and
> can
> be read directly from the memory than using the RRD ?

Using an ETR in contiguous mode is inefficient to start with.
Regardless of the approach taken trace data has to be copied to perf's
non-contiguous ring buffer pages.  It would be more efficient to copy
bigger chunks of data to the ring buffer (because we can), but I
rather spend my time enabling scatter-gather mode than optimizing a
sub-optimal mode of operation.

This currently work and enables people to use the IP block while
scatter-gather mode is in flight.  I should probably make that clear
in the commit log.

Thanks,
Mathieu

>
> Suzuki
>
>
>

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

end of thread, other threads:[~2016-04-21 22:00 UTC | newest]

Thread overview: 96+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-12 17:54 [PATCH V2 00/15] coresight: tmc: make driver usable by Perf Mathieu Poirier
2016-04-12 17:54 ` Mathieu Poirier
2016-04-12 17:54 ` [PATCH V2 01/15] coresight: tmc: modifying naming convention Mathieu Poirier
2016-04-12 17:54   ` Mathieu Poirier
2016-04-14 17:01   ` Suzuki K Poulose
2016-04-14 17:01     ` Suzuki K Poulose
2016-04-12 17:54 ` [PATCH V2 02/15] coresight: tmc: waiting for TMCReady bit before programming Mathieu Poirier
2016-04-12 17:54   ` Mathieu Poirier
2016-04-14 17:05   ` Suzuki K Poulose
2016-04-14 17:05     ` Suzuki K Poulose
2016-04-12 17:54 ` [PATCH V2 03/15] coresight: tmc: re-implementing tmc_read_prepare/unprepare() functions Mathieu Poirier
2016-04-12 17:54   ` Mathieu Poirier
2016-04-14 17:11   ` Suzuki K Poulose
2016-04-14 17:11     ` Suzuki K Poulose
2016-04-15 15:40     ` Mathieu Poirier
2016-04-15 15:40       ` Mathieu Poirier
2016-04-15 17:41       ` Suzuki K Poulose
2016-04-15 17:41         ` Suzuki K Poulose
2016-04-12 17:54 ` [PATCH V2 04/15] coresight: tmc: introducing new header file Mathieu Poirier
2016-04-12 17:54   ` Mathieu Poirier
2016-04-14 17:33   ` Suzuki K Poulose
2016-04-14 17:33     ` Suzuki K Poulose
2016-04-15 16:03     ` Mathieu Poirier
2016-04-15 16:03       ` Mathieu Poirier
2016-04-15 16:08       ` Suzuki K Poulose
2016-04-15 16:08         ` Suzuki K Poulose
2016-04-15 16:15         ` Mathieu Poirier
2016-04-15 16:15           ` Mathieu Poirier
2016-04-15 16:18           ` Suzuki K Poulose
2016-04-15 16:18             ` Suzuki K Poulose
2016-04-12 17:54 ` [PATCH V2 05/15] coresight: tmc: splitting driver in ETB/ETF and ETR components Mathieu Poirier
2016-04-12 17:54   ` Mathieu Poirier
2016-04-19 12:20   ` Suzuki K Poulose
2016-04-19 12:20     ` Suzuki K Poulose
2016-04-19 15:14     ` Mathieu Poirier
2016-04-19 15:14       ` Mathieu Poirier
2016-04-12 17:54 ` [PATCH V2 06/15] coresight: tmc: making prepare/unprepare functions generic Mathieu Poirier
2016-04-12 17:54   ` Mathieu Poirier
2016-04-19 12:30   ` Suzuki K Poulose
2016-04-19 12:30     ` Suzuki K Poulose
2016-04-19 15:22     ` Mathieu Poirier
2016-04-19 15:22       ` Mathieu Poirier
2016-04-19 15:32       ` Suzuki K Poulose
2016-04-19 15:32         ` Suzuki K Poulose
2016-04-12 17:54 ` [PATCH V2 07/15] coresight: tmc: allocating memory when needed Mathieu Poirier
2016-04-12 17:54   ` Mathieu Poirier
2016-04-19 12:55   ` Suzuki K Poulose
2016-04-19 12:55     ` Suzuki K Poulose
2016-04-19 13:14     ` Suzuki K Poulose
2016-04-19 13:14       ` Suzuki K Poulose
2016-04-19 15:39     ` Mathieu Poirier
2016-04-19 15:39       ` Mathieu Poirier
2016-04-12 17:54 ` [PATCH V2 08/15] coresight: tmc: getting the right read_count on tmc_open() Mathieu Poirier
2016-04-12 17:54   ` Mathieu Poirier
2016-04-19 13:07   ` Suzuki K Poulose
2016-04-19 13:07     ` Suzuki K Poulose
2016-04-12 17:54 ` [PATCH V2 09/15] coresight: tmc: adding mode of operation for link/sinks Mathieu Poirier
2016-04-12 17:54   ` Mathieu Poirier
2016-04-19 13:19   ` Suzuki K Poulose
2016-04-19 13:19     ` Suzuki K Poulose
2016-04-19 15:45     ` Mathieu Poirier
2016-04-19 15:45       ` Mathieu Poirier
2016-04-19 15:49       ` Suzuki K Poulose
2016-04-19 15:49         ` Suzuki K Poulose
2016-04-12 17:54 ` [PATCH V2 10/15] coresight: tmc: dump system memory content only when needed Mathieu Poirier
2016-04-12 17:54   ` Mathieu Poirier
2016-04-12 17:54 ` [PATCH V2 11/15] coresight: tmc: make sysFS and Perf mode mutually exclusive Mathieu Poirier
2016-04-12 17:54   ` Mathieu Poirier
2016-04-19 13:42   ` Suzuki K Poulose
2016-04-19 13:42     ` Suzuki K Poulose
2016-04-19 16:16     ` Mathieu Poirier
2016-04-19 16:16       ` Mathieu Poirier
2016-04-12 17:54 ` [PATCH V2 12/15] coresight: tmc: keep track of memory width Mathieu Poirier
2016-04-12 17:54   ` Mathieu Poirier
2016-04-14 11:19   ` Suzuki K Poulose
2016-04-14 11:19     ` Suzuki K Poulose
2016-04-15 16:10     ` Mathieu Poirier
2016-04-15 16:10       ` Mathieu Poirier
2016-04-12 17:54 ` [PATCH V2 13/15] coresight: tmc: implementing TMC-ETF AUX space API Mathieu Poirier
2016-04-12 17:54   ` Mathieu Poirier
2016-04-19 16:16   ` Suzuki K Poulose
2016-04-19 16:16     ` Suzuki K Poulose
2016-04-19 16:45     ` Mathieu Poirier
2016-04-19 16:45       ` Mathieu Poirier
2016-04-19 16:50       ` Suzuki K Poulose
2016-04-19 16:50         ` Suzuki K Poulose
2016-04-12 17:54 ` [PATCH V2 14/15] coresight: tmc: implementing TMC-ETR " Mathieu Poirier
2016-04-12 17:54   ` Mathieu Poirier
2016-04-21 16:10   ` Suzuki K Poulose
2016-04-21 16:10     ` Suzuki K Poulose
2016-04-21 22:00     ` Mathieu Poirier
2016-04-21 22:00       ` Mathieu Poirier
2016-04-12 17:54 ` [PATCH V2 15/15] coresight: configuring ETF in FIFO mode when acting as link Mathieu Poirier
2016-04-12 17:54   ` Mathieu Poirier
2016-04-21 12:53   ` Suzuki K Poulose
2016-04-21 12:53     ` Suzuki K Poulose

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.