xref: /openbmc/linux/drivers/hwtracing/coresight/coresight-tmc-etf.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1ad0dfdfdSMathieu Poirier // SPDX-License-Identifier: GPL-2.0
26c6ed1e2SMathieu Poirier /*
36c6ed1e2SMathieu Poirier  * Copyright(C) 2016 Linaro Limited. All rights reserved.
46c6ed1e2SMathieu Poirier  * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
56c6ed1e2SMathieu Poirier  */
66c6ed1e2SMathieu Poirier 
7f973d88bSMathieu Poirier #include <linux/atomic.h>
82e499bbcSMathieu Poirier #include <linux/circ_buf.h>
96c6ed1e2SMathieu Poirier #include <linux/coresight.h>
102e499bbcSMathieu Poirier #include <linux/perf_event.h>
11de546197SMathieu Poirier #include <linux/slab.h>
126c6ed1e2SMathieu Poirier #include "coresight-priv.h"
136c6ed1e2SMathieu Poirier #include "coresight-tmc.h"
143d6e8935SSuzuki K Poulose #include "coresight-etm-perf.h"
153d6e8935SSuzuki K Poulose 
163d6e8935SSuzuki K Poulose static int tmc_set_etf_buffer(struct coresight_device *csdev,
173d6e8935SSuzuki K Poulose 			      struct perf_output_handle *handle);
186c6ed1e2SMathieu Poirier 
__tmc_etb_enable_hw(struct tmc_drvdata * drvdata)19669c4614SYabin Cui static int __tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
206c6ed1e2SMathieu Poirier {
21669c4614SYabin Cui 	int rc = 0;
22669c4614SYabin Cui 
236c6ed1e2SMathieu Poirier 	CS_UNLOCK(drvdata->base);
246c6ed1e2SMathieu Poirier 
256c6ed1e2SMathieu Poirier 	/* Wait for TMCSReady bit to be set */
26669c4614SYabin Cui 	rc = tmc_wait_for_tmcready(drvdata);
27669c4614SYabin Cui 	if (rc) {
28669c4614SYabin Cui 		dev_err(&drvdata->csdev->dev,
29669c4614SYabin Cui 			"Failed to enable: TMC not ready\n");
30669c4614SYabin Cui 		CS_LOCK(drvdata->base);
31669c4614SYabin Cui 		return rc;
32669c4614SYabin Cui 	}
336c6ed1e2SMathieu Poirier 
346c6ed1e2SMathieu Poirier 	writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
356c6ed1e2SMathieu Poirier 	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
366c6ed1e2SMathieu Poirier 		       TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
376c6ed1e2SMathieu Poirier 		       TMC_FFCR_TRIGON_TRIGIN,
386c6ed1e2SMathieu Poirier 		       drvdata->base + TMC_FFCR);
396c6ed1e2SMathieu Poirier 
406c6ed1e2SMathieu Poirier 	writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
416c6ed1e2SMathieu Poirier 	tmc_enable_hw(drvdata);
426c6ed1e2SMathieu Poirier 
436c6ed1e2SMathieu Poirier 	CS_LOCK(drvdata->base);
44669c4614SYabin Cui 	return rc;
456c6ed1e2SMathieu Poirier }
466c6ed1e2SMathieu Poirier 
tmc_etb_enable_hw(struct tmc_drvdata * drvdata)471d364034SSuzuki K Poulose static int tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
481d364034SSuzuki K Poulose {
498ce00296SSuzuki K Poulose 	int rc = coresight_claim_device(drvdata->csdev);
504d3ebd36SSuzuki K Poulose 
514d3ebd36SSuzuki K Poulose 	if (rc)
524d3ebd36SSuzuki K Poulose 		return rc;
534d3ebd36SSuzuki K Poulose 
54669c4614SYabin Cui 	rc = __tmc_etb_enable_hw(drvdata);
55669c4614SYabin Cui 	if (rc)
56669c4614SYabin Cui 		coresight_disclaim_device(drvdata->csdev);
57669c4614SYabin Cui 	return rc;
581d364034SSuzuki K Poulose }
591d364034SSuzuki K Poulose 
tmc_etb_dump_hw(struct tmc_drvdata * drvdata)606c6ed1e2SMathieu Poirier static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
616c6ed1e2SMathieu Poirier {
626c6ed1e2SMathieu Poirier 	char *bufp;
636f755e85SSuzuki K Poulose 	u32 read_data, lost;
646c6ed1e2SMathieu Poirier 
656f755e85SSuzuki K Poulose 	/* Check if the buffer wrapped around. */
666f755e85SSuzuki K Poulose 	lost = readl_relaxed(drvdata->base + TMC_STS) & TMC_STS_FULL;
676c6ed1e2SMathieu Poirier 	bufp = drvdata->buf;
688505feaeSSuzuki K Poulose 	drvdata->len = 0;
696c6ed1e2SMathieu Poirier 	while (1) {
706c6ed1e2SMathieu Poirier 		read_data = readl_relaxed(drvdata->base + TMC_RRD);
716c6ed1e2SMathieu Poirier 		if (read_data == 0xFFFFFFFF)
72b3bee19eSLeo Yan 			break;
736c6ed1e2SMathieu Poirier 		memcpy(bufp, &read_data, 4);
746c6ed1e2SMathieu Poirier 		bufp += 4;
758505feaeSSuzuki K Poulose 		drvdata->len += 4;
766c6ed1e2SMathieu Poirier 	}
77b3bee19eSLeo Yan 
786f755e85SSuzuki K Poulose 	if (lost)
796f755e85SSuzuki K Poulose 		coresight_insert_barrier_packet(drvdata->buf);
806f755e85SSuzuki K Poulose 	return;
816c6ed1e2SMathieu Poirier }
826c6ed1e2SMathieu Poirier 
__tmc_etb_disable_hw(struct tmc_drvdata * drvdata)834d3ebd36SSuzuki K Poulose static void __tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
846c6ed1e2SMathieu Poirier {
856c6ed1e2SMathieu Poirier 	CS_UNLOCK(drvdata->base);
866c6ed1e2SMathieu Poirier 
876c6ed1e2SMathieu Poirier 	tmc_flush_and_stop(drvdata);
88a40318fbSMathieu Poirier 	/*
89a40318fbSMathieu Poirier 	 * When operating in sysFS mode the content of the buffer needs to be
90a40318fbSMathieu Poirier 	 * read before the TMC is disabled.
91a40318fbSMathieu Poirier 	 */
92297ab90fSSuzuki K. Poulose 	if (drvdata->mode == CS_MODE_SYSFS)
936c6ed1e2SMathieu Poirier 		tmc_etb_dump_hw(drvdata);
946c6ed1e2SMathieu Poirier 	tmc_disable_hw(drvdata);
956c6ed1e2SMathieu Poirier 
966c6ed1e2SMathieu Poirier 	CS_LOCK(drvdata->base);
976c6ed1e2SMathieu Poirier }
986c6ed1e2SMathieu Poirier 
tmc_etb_disable_hw(struct tmc_drvdata * drvdata)994d3ebd36SSuzuki K Poulose static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
1004d3ebd36SSuzuki K Poulose {
1014d3ebd36SSuzuki K Poulose 	__tmc_etb_disable_hw(drvdata);
1028ce00296SSuzuki K Poulose 	coresight_disclaim_device(drvdata->csdev);
1034d3ebd36SSuzuki K Poulose }
1044d3ebd36SSuzuki K Poulose 
__tmc_etf_enable_hw(struct tmc_drvdata * drvdata)105669c4614SYabin Cui static int __tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
1066c6ed1e2SMathieu Poirier {
107669c4614SYabin Cui 	int rc = 0;
108669c4614SYabin Cui 
1096c6ed1e2SMathieu Poirier 	CS_UNLOCK(drvdata->base);
1106c6ed1e2SMathieu Poirier 
1116c6ed1e2SMathieu Poirier 	/* Wait for TMCSReady bit to be set */
112669c4614SYabin Cui 	rc = tmc_wait_for_tmcready(drvdata);
113669c4614SYabin Cui 	if (rc) {
114669c4614SYabin Cui 		dev_err(&drvdata->csdev->dev,
115669c4614SYabin Cui 			"Failed to enable : TMC is not ready\n");
116669c4614SYabin Cui 		CS_LOCK(drvdata->base);
117669c4614SYabin Cui 		return rc;
118669c4614SYabin Cui 	}
1196c6ed1e2SMathieu Poirier 
1206c6ed1e2SMathieu Poirier 	writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE);
1216c6ed1e2SMathieu Poirier 	writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI,
1226c6ed1e2SMathieu Poirier 		       drvdata->base + TMC_FFCR);
1236c6ed1e2SMathieu Poirier 	writel_relaxed(0x0, drvdata->base + TMC_BUFWM);
1246c6ed1e2SMathieu Poirier 	tmc_enable_hw(drvdata);
1256c6ed1e2SMathieu Poirier 
1266c6ed1e2SMathieu Poirier 	CS_LOCK(drvdata->base);
127669c4614SYabin Cui 	return rc;
1286c6ed1e2SMathieu Poirier }
1296c6ed1e2SMathieu Poirier 
tmc_etf_enable_hw(struct tmc_drvdata * drvdata)1301d364034SSuzuki K Poulose static int tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
1311d364034SSuzuki K Poulose {
1328ce00296SSuzuki K Poulose 	int rc = coresight_claim_device(drvdata->csdev);
1334d3ebd36SSuzuki K Poulose 
1344d3ebd36SSuzuki K Poulose 	if (rc)
1354d3ebd36SSuzuki K Poulose 		return rc;
1364d3ebd36SSuzuki K Poulose 
137669c4614SYabin Cui 	rc = __tmc_etf_enable_hw(drvdata);
138669c4614SYabin Cui 	if (rc)
139669c4614SYabin Cui 		coresight_disclaim_device(drvdata->csdev);
140669c4614SYabin Cui 	return rc;
1411d364034SSuzuki K Poulose }
1421d364034SSuzuki K Poulose 
tmc_etf_disable_hw(struct tmc_drvdata * drvdata)1436c6ed1e2SMathieu Poirier static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
1446c6ed1e2SMathieu Poirier {
1458ce00296SSuzuki K Poulose 	struct coresight_device *csdev = drvdata->csdev;
1468ce00296SSuzuki K Poulose 
1476c6ed1e2SMathieu Poirier 	CS_UNLOCK(drvdata->base);
1486c6ed1e2SMathieu Poirier 
1496c6ed1e2SMathieu Poirier 	tmc_flush_and_stop(drvdata);
1506c6ed1e2SMathieu Poirier 	tmc_disable_hw(drvdata);
1518ce00296SSuzuki K Poulose 	coresight_disclaim_device_unlocked(csdev);
1526c6ed1e2SMathieu Poirier 	CS_LOCK(drvdata->base);
1536c6ed1e2SMathieu Poirier }
1546c6ed1e2SMathieu Poirier 
1553495722aSSuzuki K Poulose /*
1563495722aSSuzuki K Poulose  * Return the available trace data in the buffer from @pos, with
1573495722aSSuzuki K Poulose  * a maximum limit of @len, updating the @bufpp on where to
1583495722aSSuzuki K Poulose  * find it.
1593495722aSSuzuki K Poulose  */
tmc_etb_get_sysfs_trace(struct tmc_drvdata * drvdata,loff_t pos,size_t len,char ** bufpp)1603495722aSSuzuki K Poulose ssize_t tmc_etb_get_sysfs_trace(struct tmc_drvdata *drvdata,
1613495722aSSuzuki K Poulose 				loff_t pos, size_t len, char **bufpp)
1623495722aSSuzuki K Poulose {
1633495722aSSuzuki K Poulose 	ssize_t actual = len;
1643495722aSSuzuki K Poulose 
1653495722aSSuzuki K Poulose 	/* Adjust the len to available size @pos */
1663495722aSSuzuki K Poulose 	if (pos + actual > drvdata->len)
1673495722aSSuzuki K Poulose 		actual = drvdata->len - pos;
1683495722aSSuzuki K Poulose 	if (actual > 0)
1693495722aSSuzuki K Poulose 		*bufpp = drvdata->buf + pos;
1703495722aSSuzuki K Poulose 	return actual;
1713495722aSSuzuki K Poulose }
1723495722aSSuzuki K Poulose 
tmc_enable_etf_sink_sysfs(struct coresight_device * csdev)173c38e505eSSuzuki K. Poulose static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
1746c6ed1e2SMathieu Poirier {
175de546197SMathieu Poirier 	int ret = 0;
176de546197SMathieu Poirier 	bool used = false;
177de546197SMathieu Poirier 	char *buf = NULL;
1786c6ed1e2SMathieu Poirier 	unsigned long flags;
1796c6ed1e2SMathieu Poirier 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
1806c6ed1e2SMathieu Poirier 
181de546197SMathieu Poirier 	/*
182de546197SMathieu Poirier 	 * If we don't have a buffer release the lock and allocate memory.
183de546197SMathieu Poirier 	 * Otherwise keep the lock and move along.
184de546197SMathieu Poirier 	 */
1856c6ed1e2SMathieu Poirier 	spin_lock_irqsave(&drvdata->spinlock, flags);
186de546197SMathieu Poirier 	if (!drvdata->buf) {
1876c6ed1e2SMathieu Poirier 		spin_unlock_irqrestore(&drvdata->spinlock, flags);
188de546197SMathieu Poirier 
189de546197SMathieu Poirier 		/* Allocating the memory here while outside of the spinlock */
190de546197SMathieu Poirier 		buf = kzalloc(drvdata->size, GFP_KERNEL);
191de546197SMathieu Poirier 		if (!buf)
192de546197SMathieu Poirier 			return -ENOMEM;
193de546197SMathieu Poirier 
194de546197SMathieu Poirier 		/* Let's try again */
195de546197SMathieu Poirier 		spin_lock_irqsave(&drvdata->spinlock, flags);
196de546197SMathieu Poirier 	}
197de546197SMathieu Poirier 
198de546197SMathieu Poirier 	if (drvdata->reading) {
199de546197SMathieu Poirier 		ret = -EBUSY;
200de546197SMathieu Poirier 		goto out;
201de546197SMathieu Poirier 	}
202de546197SMathieu Poirier 
203f2facc33SMathieu Poirier 	/*
204f2facc33SMathieu Poirier 	 * In sysFS mode we can have multiple writers per sink.  Since this
205f2facc33SMathieu Poirier 	 * sink is already enabled no memory is needed and the HW need not be
206f2facc33SMathieu Poirier 	 * touched.
207f2facc33SMathieu Poirier 	 */
208f973d88bSMathieu Poirier 	if (drvdata->mode == CS_MODE_SYSFS) {
209ae7f2b5aSJames Clark 		atomic_inc(&csdev->refcnt);
210f2facc33SMathieu Poirier 		goto out;
211f973d88bSMathieu Poirier 	}
212f2facc33SMathieu Poirier 
213de546197SMathieu Poirier 	/*
214de546197SMathieu Poirier 	 * If drvdata::buf isn't NULL, memory was allocated for a previous
215de546197SMathieu Poirier 	 * trace run but wasn't read.  If so simply zero-out the memory.
216de546197SMathieu Poirier 	 * Otherwise use the memory allocated above.
217de546197SMathieu Poirier 	 *
218de546197SMathieu Poirier 	 * The memory is freed when users read the buffer using the
219de546197SMathieu Poirier 	 * /dev/xyz.{etf|etb} interface.  See tmc_read_unprepare_etf() for
220de546197SMathieu Poirier 	 * details.
221de546197SMathieu Poirier 	 */
222de546197SMathieu Poirier 	if (drvdata->buf) {
223de546197SMathieu Poirier 		memset(drvdata->buf, 0, drvdata->size);
224de546197SMathieu Poirier 	} else {
225de546197SMathieu Poirier 		used = true;
226de546197SMathieu Poirier 		drvdata->buf = buf;
2276c6ed1e2SMathieu Poirier 	}
2286c6ed1e2SMathieu Poirier 
2291d364034SSuzuki K Poulose 	ret = tmc_etb_enable_hw(drvdata);
230f973d88bSMathieu Poirier 	if (!ret) {
231297ab90fSSuzuki K. Poulose 		drvdata->mode = CS_MODE_SYSFS;
232ae7f2b5aSJames Clark 		atomic_inc(&csdev->refcnt);
233f973d88bSMathieu Poirier 	} else {
2341d364034SSuzuki K Poulose 		/* Free up the buffer if we failed to enable */
2351d364034SSuzuki K Poulose 		used = false;
236f973d88bSMathieu Poirier 	}
237de546197SMathieu Poirier out:
2386c6ed1e2SMathieu Poirier 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
2396c6ed1e2SMathieu Poirier 
240de546197SMathieu Poirier 	/* Free memory outside the spinlock if need be */
2411d37ae50SMarkus Elfring 	if (!used)
242de546197SMathieu Poirier 		kfree(buf);
243de546197SMathieu Poirier 
244de546197SMathieu Poirier 	return ret;
2456c6ed1e2SMathieu Poirier }
2466c6ed1e2SMathieu Poirier 
tmc_enable_etf_sink_perf(struct coresight_device * csdev,void * data)2473d6e8935SSuzuki K Poulose static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
248b217601eSMathieu Poirier {
249b217601eSMathieu Poirier 	int ret = 0;
250880af782SMathieu Poirier 	pid_t pid;
251b217601eSMathieu Poirier 	unsigned long flags;
252b217601eSMathieu Poirier 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
2533d6e8935SSuzuki K Poulose 	struct perf_output_handle *handle = data;
254868663ddSSai Prakash Ranjan 	struct cs_buffers *buf = etm_perf_sink_config(handle);
255b217601eSMathieu Poirier 
256b217601eSMathieu Poirier 	spin_lock_irqsave(&drvdata->spinlock, flags);
2571d364034SSuzuki K Poulose 	do {
258b217601eSMathieu Poirier 		ret = -EINVAL;
2591d364034SSuzuki K Poulose 		if (drvdata->reading)
2601d364034SSuzuki K Poulose 			break;
261b217601eSMathieu Poirier 		/*
262880af782SMathieu Poirier 		 * No need to continue if the ETB/ETF is already operated
263880af782SMathieu Poirier 		 * from sysFS.
264b217601eSMathieu Poirier 		 */
265880af782SMathieu Poirier 		if (drvdata->mode == CS_MODE_SYSFS) {
266880af782SMathieu Poirier 			ret = -EBUSY;
2671d364034SSuzuki K Poulose 			break;
268880af782SMathieu Poirier 		}
269880af782SMathieu Poirier 
270880af782SMathieu Poirier 		/* Get a handle on the pid of the process to monitor */
271868663ddSSai Prakash Ranjan 		pid = buf->pid;
272880af782SMathieu Poirier 
273880af782SMathieu Poirier 		if (drvdata->pid != -1 && drvdata->pid != pid) {
274880af782SMathieu Poirier 			ret = -EBUSY;
275880af782SMathieu Poirier 			break;
276880af782SMathieu Poirier 		}
277b217601eSMathieu Poirier 
2783d6e8935SSuzuki K Poulose 		ret = tmc_set_etf_buffer(csdev, handle);
2791d364034SSuzuki K Poulose 		if (ret)
2801d364034SSuzuki K Poulose 			break;
281880af782SMathieu Poirier 
282880af782SMathieu Poirier 		/*
283880af782SMathieu Poirier 		 * No HW configuration is needed if the sink is already in
284880af782SMathieu Poirier 		 * use for this session.
285880af782SMathieu Poirier 		 */
286880af782SMathieu Poirier 		if (drvdata->pid == pid) {
287ae7f2b5aSJames Clark 			atomic_inc(&csdev->refcnt);
288880af782SMathieu Poirier 			break;
289880af782SMathieu Poirier 		}
290880af782SMathieu Poirier 
2911d364034SSuzuki K Poulose 		ret  = tmc_etb_enable_hw(drvdata);
292f973d88bSMathieu Poirier 		if (!ret) {
293880af782SMathieu Poirier 			/* Associate with monitored process. */
294880af782SMathieu Poirier 			drvdata->pid = pid;
295c38e505eSSuzuki K. Poulose 			drvdata->mode = CS_MODE_PERF;
296ae7f2b5aSJames Clark 			atomic_inc(&csdev->refcnt);
297f973d88bSMathieu Poirier 		}
2981d364034SSuzuki K Poulose 	} while (0);
299b217601eSMathieu Poirier 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
300b217601eSMathieu Poirier 
301b217601eSMathieu Poirier 	return ret;
302b217601eSMathieu Poirier }
303b217601eSMathieu Poirier 
tmc_enable_etf_sink(struct coresight_device * csdev,enum cs_mode mode,void * data)3043d6e8935SSuzuki K Poulose static int tmc_enable_etf_sink(struct coresight_device *csdev,
3059fa36828SJames Clark 			       enum cs_mode mode, void *data)
306b217601eSMathieu Poirier {
3072cd54140SLeo Yan 	int ret;
3082cd54140SLeo Yan 
309b217601eSMathieu Poirier 	switch (mode) {
310b217601eSMathieu Poirier 	case CS_MODE_SYSFS:
3112cd54140SLeo Yan 		ret = tmc_enable_etf_sink_sysfs(csdev);
3122cd54140SLeo Yan 		break;
313b217601eSMathieu Poirier 	case CS_MODE_PERF:
3143d6e8935SSuzuki K Poulose 		ret = tmc_enable_etf_sink_perf(csdev, data);
3152cd54140SLeo Yan 		break;
3162cd54140SLeo Yan 	/* We shouldn't be here */
3172cd54140SLeo Yan 	default:
3182cd54140SLeo Yan 		ret = -EINVAL;
3192cd54140SLeo Yan 		break;
320b217601eSMathieu Poirier 	}
321b217601eSMathieu Poirier 
3222cd54140SLeo Yan 	if (ret)
3232cd54140SLeo Yan 		return ret;
3242cd54140SLeo Yan 
3259dd0a920SSuzuki K Poulose 	dev_dbg(&csdev->dev, "TMC-ETB/ETF enabled\n");
3262cd54140SLeo Yan 	return 0;
327b217601eSMathieu Poirier }
328b217601eSMathieu Poirier 
tmc_disable_etf_sink(struct coresight_device * csdev)3296c817a95SMathieu Poirier static int tmc_disable_etf_sink(struct coresight_device *csdev)
3306c6ed1e2SMathieu Poirier {
3316c6ed1e2SMathieu Poirier 	unsigned long flags;
3326c6ed1e2SMathieu Poirier 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
3336c6ed1e2SMathieu Poirier 
3346c6ed1e2SMathieu Poirier 	spin_lock_irqsave(&drvdata->spinlock, flags);
335f973d88bSMathieu Poirier 
3366c6ed1e2SMathieu Poirier 	if (drvdata->reading) {
3376c6ed1e2SMathieu Poirier 		spin_unlock_irqrestore(&drvdata->spinlock, flags);
3386c817a95SMathieu Poirier 		return -EBUSY;
3396c6ed1e2SMathieu Poirier 	}
3406c6ed1e2SMathieu Poirier 
341ae7f2b5aSJames Clark 	if (atomic_dec_return(&csdev->refcnt)) {
342f973d88bSMathieu Poirier 		spin_unlock_irqrestore(&drvdata->spinlock, flags);
343f973d88bSMathieu Poirier 		return -EBUSY;
344f973d88bSMathieu Poirier 	}
345f973d88bSMathieu Poirier 
34612dfc9e0SMathieu Poirier 	/* Complain if we (somehow) got out of sync */
34712dfc9e0SMathieu Poirier 	WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
3486c6ed1e2SMathieu Poirier 	tmc_etb_disable_hw(drvdata);
349880af782SMathieu Poirier 	/* Dissociate from monitored process. */
350880af782SMathieu Poirier 	drvdata->pid = -1;
351297ab90fSSuzuki K. Poulose 	drvdata->mode = CS_MODE_DISABLED;
352f2facc33SMathieu Poirier 
3536c6ed1e2SMathieu Poirier 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
3546c6ed1e2SMathieu Poirier 
3559dd0a920SSuzuki K Poulose 	dev_dbg(&csdev->dev, "TMC-ETB/ETF disabled\n");
3566c817a95SMathieu Poirier 	return 0;
3576c6ed1e2SMathieu Poirier }
3586c6ed1e2SMathieu Poirier 
tmc_enable_etf_link(struct coresight_device * csdev,struct coresight_connection * in,struct coresight_connection * out)3596c6ed1e2SMathieu Poirier static int tmc_enable_etf_link(struct coresight_device *csdev,
360ae7f2b5aSJames Clark 			       struct coresight_connection *in,
361ae7f2b5aSJames Clark 			       struct coresight_connection *out)
3626c6ed1e2SMathieu Poirier {
363edda32daSYabin Cui 	int ret = 0;
3646c6ed1e2SMathieu Poirier 	unsigned long flags;
3656c6ed1e2SMathieu Poirier 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
366edda32daSYabin Cui 	bool first_enable = false;
3676c6ed1e2SMathieu Poirier 
3686c6ed1e2SMathieu Poirier 	spin_lock_irqsave(&drvdata->spinlock, flags);
3696c6ed1e2SMathieu Poirier 	if (drvdata->reading) {
3706c6ed1e2SMathieu Poirier 		spin_unlock_irqrestore(&drvdata->spinlock, flags);
3716c6ed1e2SMathieu Poirier 		return -EBUSY;
3726c6ed1e2SMathieu Poirier 	}
3736c6ed1e2SMathieu Poirier 
374ae7f2b5aSJames Clark 	if (atomic_read(&csdev->refcnt) == 0) {
3751d364034SSuzuki K Poulose 		ret = tmc_etf_enable_hw(drvdata);
376edda32daSYabin Cui 		if (!ret) {
377297ab90fSSuzuki K. Poulose 			drvdata->mode = CS_MODE_SYSFS;
378edda32daSYabin Cui 			first_enable = true;
379edda32daSYabin Cui 		}
380edda32daSYabin Cui 	}
381edda32daSYabin Cui 	if (!ret)
382ae7f2b5aSJames Clark 		atomic_inc(&csdev->refcnt);
3836c6ed1e2SMathieu Poirier 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
3846c6ed1e2SMathieu Poirier 
385edda32daSYabin Cui 	if (first_enable)
3869dd0a920SSuzuki K Poulose 		dev_dbg(&csdev->dev, "TMC-ETF enabled\n");
3871d364034SSuzuki K Poulose 	return ret;
3886c6ed1e2SMathieu Poirier }
3896c6ed1e2SMathieu Poirier 
tmc_disable_etf_link(struct coresight_device * csdev,struct coresight_connection * in,struct coresight_connection * out)3906c6ed1e2SMathieu Poirier static void tmc_disable_etf_link(struct coresight_device *csdev,
391ae7f2b5aSJames Clark 				 struct coresight_connection *in,
392ae7f2b5aSJames Clark 				 struct coresight_connection *out)
3936c6ed1e2SMathieu Poirier {
3946c6ed1e2SMathieu Poirier 	unsigned long flags;
3956c6ed1e2SMathieu Poirier 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
396edda32daSYabin Cui 	bool last_disable = false;
3976c6ed1e2SMathieu Poirier 
3986c6ed1e2SMathieu Poirier 	spin_lock_irqsave(&drvdata->spinlock, flags);
3996c6ed1e2SMathieu Poirier 	if (drvdata->reading) {
4006c6ed1e2SMathieu Poirier 		spin_unlock_irqrestore(&drvdata->spinlock, flags);
4016c6ed1e2SMathieu Poirier 		return;
4026c6ed1e2SMathieu Poirier 	}
4036c6ed1e2SMathieu Poirier 
404ae7f2b5aSJames Clark 	if (atomic_dec_return(&csdev->refcnt) == 0) {
4056c6ed1e2SMathieu Poirier 		tmc_etf_disable_hw(drvdata);
406297ab90fSSuzuki K. Poulose 		drvdata->mode = CS_MODE_DISABLED;
407edda32daSYabin Cui 		last_disable = true;
408edda32daSYabin Cui 	}
4096c6ed1e2SMathieu Poirier 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
4106c6ed1e2SMathieu Poirier 
411edda32daSYabin Cui 	if (last_disable)
4129dd0a920SSuzuki K Poulose 		dev_dbg(&csdev->dev, "TMC-ETF disabled\n");
4136c6ed1e2SMathieu Poirier }
4146c6ed1e2SMathieu Poirier 
tmc_alloc_etf_buffer(struct coresight_device * csdev,struct perf_event * event,void ** pages,int nr_pages,bool overwrite)415a0f08a6aSMathieu Poirier static void *tmc_alloc_etf_buffer(struct coresight_device *csdev,
416a0f08a6aSMathieu Poirier 				  struct perf_event *event, void **pages,
417a0f08a6aSMathieu Poirier 				  int nr_pages, bool overwrite)
4182e499bbcSMathieu Poirier {
419024c1fd9SSuzuki K Poulose 	int node;
4202e499bbcSMathieu Poirier 	struct cs_buffers *buf;
4212e499bbcSMathieu Poirier 
422024c1fd9SSuzuki K Poulose 	node = (event->cpu == -1) ? NUMA_NO_NODE : cpu_to_node(event->cpu);
4232e499bbcSMathieu Poirier 
4242e499bbcSMathieu Poirier 	/* Allocate memory structure for interaction with Perf */
4252e499bbcSMathieu Poirier 	buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node);
4262e499bbcSMathieu Poirier 	if (!buf)
4272e499bbcSMathieu Poirier 		return NULL;
4282e499bbcSMathieu Poirier 
429868663ddSSai Prakash Ranjan 	buf->pid = task_pid_nr(event->owner);
4302e499bbcSMathieu Poirier 	buf->snapshot = overwrite;
4312e499bbcSMathieu Poirier 	buf->nr_pages = nr_pages;
4322e499bbcSMathieu Poirier 	buf->data_pages = pages;
4332e499bbcSMathieu Poirier 
4342e499bbcSMathieu Poirier 	return buf;
4352e499bbcSMathieu Poirier }
4362e499bbcSMathieu Poirier 
tmc_free_etf_buffer(void * config)4372e499bbcSMathieu Poirier static void tmc_free_etf_buffer(void *config)
4382e499bbcSMathieu Poirier {
4392e499bbcSMathieu Poirier 	struct cs_buffers *buf = config;
4402e499bbcSMathieu Poirier 
4412e499bbcSMathieu Poirier 	kfree(buf);
4422e499bbcSMathieu Poirier }
4432e499bbcSMathieu Poirier 
tmc_set_etf_buffer(struct coresight_device * csdev,struct perf_output_handle * handle)4442e499bbcSMathieu Poirier static int tmc_set_etf_buffer(struct coresight_device *csdev,
4453d6e8935SSuzuki K Poulose 			      struct perf_output_handle *handle)
4462e499bbcSMathieu Poirier {
4472e499bbcSMathieu Poirier 	int ret = 0;
4482e499bbcSMathieu Poirier 	unsigned long head;
4493d6e8935SSuzuki K Poulose 	struct cs_buffers *buf = etm_perf_sink_config(handle);
4503d6e8935SSuzuki K Poulose 
4513d6e8935SSuzuki K Poulose 	if (!buf)
4523d6e8935SSuzuki K Poulose 		return -EINVAL;
4532e499bbcSMathieu Poirier 
4542e499bbcSMathieu Poirier 	/* wrap head around to the amount of space we have */
455*fd380097SRuidong Tian 	head = handle->head & (((unsigned long)buf->nr_pages << PAGE_SHIFT) - 1);
4562e499bbcSMathieu Poirier 
4572e499bbcSMathieu Poirier 	/* find the page to write to */
4582e499bbcSMathieu Poirier 	buf->cur = head / PAGE_SIZE;
4592e499bbcSMathieu Poirier 
4602e499bbcSMathieu Poirier 	/* and offset within that page */
4612e499bbcSMathieu Poirier 	buf->offset = head % PAGE_SIZE;
4622e499bbcSMathieu Poirier 
4632e499bbcSMathieu Poirier 	local_set(&buf->data_size, 0);
4642e499bbcSMathieu Poirier 
4652e499bbcSMathieu Poirier 	return ret;
4662e499bbcSMathieu Poirier }
4672e499bbcSMathieu Poirier 
tmc_update_etf_buffer(struct coresight_device * csdev,struct perf_output_handle * handle,void * sink_config)4687ec786adSSuzuki K Poulose static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
4692e499bbcSMathieu Poirier 				  struct perf_output_handle *handle,
4702e499bbcSMathieu Poirier 				  void *sink_config)
4712e499bbcSMathieu Poirier {
472cfd9f630SMathieu Poirier 	bool lost = false;
4732e499bbcSMathieu Poirier 	int i, cur;
4740c3fc4d5SMathieu Poirier 	const u32 *barrier;
4752e499bbcSMathieu Poirier 	u32 *buf_ptr;
4766f6ab4fcSSuzuki K Poulose 	u64 read_ptr, write_ptr;
4777ec786adSSuzuki K Poulose 	u32 status;
478880af782SMathieu Poirier 	unsigned long offset, to_read = 0, flags;
4792e499bbcSMathieu Poirier 	struct cs_buffers *buf = sink_config;
4802e499bbcSMathieu Poirier 	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
4812e499bbcSMathieu Poirier 
4822e499bbcSMathieu Poirier 	if (!buf)
4837ec786adSSuzuki K Poulose 		return 0;
4842e499bbcSMathieu Poirier 
4852e499bbcSMathieu Poirier 	/* This shouldn't happen */
486297ab90fSSuzuki K. Poulose 	if (WARN_ON_ONCE(drvdata->mode != CS_MODE_PERF))
4877ec786adSSuzuki K Poulose 		return 0;
4882e499bbcSMathieu Poirier 
4890916447cSMathieu Poirier 	spin_lock_irqsave(&drvdata->spinlock, flags);
490880af782SMathieu Poirier 
491880af782SMathieu Poirier 	/* Don't do anything if another tracer is using this sink */
492ae7f2b5aSJames Clark 	if (atomic_read(&csdev->refcnt) != 1)
493880af782SMathieu Poirier 		goto out;
494880af782SMathieu Poirier 
4952e499bbcSMathieu Poirier 	CS_UNLOCK(drvdata->base);
4962e499bbcSMathieu Poirier 
4972e499bbcSMathieu Poirier 	tmc_flush_and_stop(drvdata);
4982e499bbcSMathieu Poirier 
4996f6ab4fcSSuzuki K Poulose 	read_ptr = tmc_read_rrp(drvdata);
5006f6ab4fcSSuzuki K Poulose 	write_ptr = tmc_read_rwp(drvdata);
5012e499bbcSMathieu Poirier 
5022e499bbcSMathieu Poirier 	/*
5032e499bbcSMathieu Poirier 	 * Get a hold of the status register and see if a wrap around
5042e499bbcSMathieu Poirier 	 * has occurred.  If so adjust things accordingly.
5052e499bbcSMathieu Poirier 	 */
5062e499bbcSMathieu Poirier 	status = readl_relaxed(drvdata->base + TMC_STS);
5072e499bbcSMathieu Poirier 	if (status & TMC_STS_FULL) {
508cfd9f630SMathieu Poirier 		lost = true;
5092e499bbcSMathieu Poirier 		to_read = drvdata->size;
5102e499bbcSMathieu Poirier 	} else {
5112e499bbcSMathieu Poirier 		to_read = CIRC_CNT(write_ptr, read_ptr, drvdata->size);
5122e499bbcSMathieu Poirier 	}
5132e499bbcSMathieu Poirier 
5142e499bbcSMathieu Poirier 	/*
5152e499bbcSMathieu Poirier 	 * The TMC RAM buffer may be bigger than the space available in the
5162e499bbcSMathieu Poirier 	 * perf ring buffer (handle->size).  If so advance the RRP so that we
51799f81eb9SMathieu Poirier 	 * get the latest trace data.  In snapshot mode none of that matters
51899f81eb9SMathieu Poirier 	 * since we are expected to clobber stale data in favour of the latest
51999f81eb9SMathieu Poirier 	 * traces.
5202e499bbcSMathieu Poirier 	 */
52199f81eb9SMathieu Poirier 	if (!buf->snapshot && to_read > handle->size) {
52200bb485cSMathieu Poirier 		u32 mask = tmc_get_memwidth_mask(drvdata);
5232e499bbcSMathieu Poirier 
5242e499bbcSMathieu Poirier 		/*
5252e499bbcSMathieu Poirier 		 * Make sure the new size is aligned in accordance with the
52600bb485cSMathieu Poirier 		 * requirement explained in function tmc_get_memwidth_mask().
5272e499bbcSMathieu Poirier 		 */
5282e499bbcSMathieu Poirier 		to_read = handle->size & mask;
5292e499bbcSMathieu Poirier 		/* Move the RAM read pointer up */
5302e499bbcSMathieu Poirier 		read_ptr = (write_ptr + drvdata->size) - to_read;
5312e499bbcSMathieu Poirier 		/* Make sure we are still within our limits */
5322e499bbcSMathieu Poirier 		if (read_ptr > (drvdata->size - 1))
5332e499bbcSMathieu Poirier 			read_ptr -= drvdata->size;
5342e499bbcSMathieu Poirier 		/* Tell the HW */
5356f6ab4fcSSuzuki K Poulose 		tmc_write_rrp(drvdata, read_ptr);
536cfd9f630SMathieu Poirier 		lost = true;
5372e499bbcSMathieu Poirier 	}
5382e499bbcSMathieu Poirier 
5395aafd9bfSMathieu Poirier 	/*
5405aafd9bfSMathieu Poirier 	 * Don't set the TRUNCATED flag in snapshot mode because 1) the
5415aafd9bfSMathieu Poirier 	 * captured buffer is expected to be truncated and 2) a full buffer
5425aafd9bfSMathieu Poirier 	 * prevents the event from being re-enabled by the perf core,
5435aafd9bfSMathieu Poirier 	 * resulting in stale data being send to user space.
5445aafd9bfSMathieu Poirier 	 */
5455aafd9bfSMathieu Poirier 	if (!buf->snapshot && lost)
546cfd9f630SMathieu Poirier 		perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
547cfd9f630SMathieu Poirier 
5482e499bbcSMathieu Poirier 	cur = buf->cur;
5492e499bbcSMathieu Poirier 	offset = buf->offset;
55092fc7d81STingwei Zhang 	barrier = coresight_barrier_pkt;
5512e499bbcSMathieu Poirier 
5522e499bbcSMathieu Poirier 	/* for every byte to read */
5532e499bbcSMathieu Poirier 	for (i = 0; i < to_read; i += 4) {
5542e499bbcSMathieu Poirier 		buf_ptr = buf->data_pages[cur] + offset;
5552e499bbcSMathieu Poirier 		*buf_ptr = readl_relaxed(drvdata->base + TMC_RRD);
5562e499bbcSMathieu Poirier 
5575fae8a94SSai Prakash Ranjan 		if (lost && i < CORESIGHT_BARRIER_PKT_SIZE) {
5580c3fc4d5SMathieu Poirier 			*buf_ptr = *barrier;
5590c3fc4d5SMathieu Poirier 			barrier++;
5600c3fc4d5SMathieu Poirier 		}
5610c3fc4d5SMathieu Poirier 
5622e499bbcSMathieu Poirier 		offset += 4;
5632e499bbcSMathieu Poirier 		if (offset >= PAGE_SIZE) {
5642e499bbcSMathieu Poirier 			offset = 0;
5652e499bbcSMathieu Poirier 			cur++;
5662e499bbcSMathieu Poirier 			/* wrap around at the end of the buffer */
5672e499bbcSMathieu Poirier 			cur &= buf->nr_pages - 1;
5682e499bbcSMathieu Poirier 		}
5692e499bbcSMathieu Poirier 	}
5702e499bbcSMathieu Poirier 
5710402f75eSMathieu Poirier 	/*
5720402f75eSMathieu Poirier 	 * In snapshot mode we simply increment the head by the number of byte
5737ba7ae1dSLeo Yan 	 * that were written.  User space will figure out how many bytes to get
5747ba7ae1dSLeo Yan 	 * from the AUX buffer based on the position of the head.
5750402f75eSMathieu Poirier 	 */
5760402f75eSMathieu Poirier 	if (buf->snapshot)
5770402f75eSMathieu Poirier 		handle->head += to_read;
5780402f75eSMathieu Poirier 
579bd8d0688SLeo Yan 	/*
580bd8d0688SLeo Yan 	 * CS_LOCK() contains mb() so it can ensure visibility of the AUX trace
581bd8d0688SLeo Yan 	 * data before the aux_head is updated via perf_aux_output_end(), which
582bd8d0688SLeo Yan 	 * is expected by the perf ring buffer.
583bd8d0688SLeo Yan 	 */
5842e499bbcSMathieu Poirier 	CS_LOCK(drvdata->base);
585880af782SMathieu Poirier out:
5860916447cSMathieu Poirier 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
5877ec786adSSuzuki K Poulose 
5887ec786adSSuzuki K Poulose 	return to_read;
5892e499bbcSMathieu Poirier }
5902e499bbcSMathieu Poirier 
5916c6ed1e2SMathieu Poirier static const struct coresight_ops_sink tmc_etf_sink_ops = {
5926c6ed1e2SMathieu Poirier 	.enable		= tmc_enable_etf_sink,
5936c6ed1e2SMathieu Poirier 	.disable	= tmc_disable_etf_sink,
5942e499bbcSMathieu Poirier 	.alloc_buffer	= tmc_alloc_etf_buffer,
5952e499bbcSMathieu Poirier 	.free_buffer	= tmc_free_etf_buffer,
5962e499bbcSMathieu Poirier 	.update_buffer	= tmc_update_etf_buffer,
5976c6ed1e2SMathieu Poirier };
5986c6ed1e2SMathieu Poirier 
5996c6ed1e2SMathieu Poirier static const struct coresight_ops_link tmc_etf_link_ops = {
6006c6ed1e2SMathieu Poirier 	.enable		= tmc_enable_etf_link,
6016c6ed1e2SMathieu Poirier 	.disable	= tmc_disable_etf_link,
6026c6ed1e2SMathieu Poirier };
6036c6ed1e2SMathieu Poirier 
6046c6ed1e2SMathieu Poirier const struct coresight_ops tmc_etb_cs_ops = {
6056c6ed1e2SMathieu Poirier 	.sink_ops	= &tmc_etf_sink_ops,
6066c6ed1e2SMathieu Poirier };
6076c6ed1e2SMathieu Poirier 
6086c6ed1e2SMathieu Poirier const struct coresight_ops tmc_etf_cs_ops = {
6096c6ed1e2SMathieu Poirier 	.sink_ops	= &tmc_etf_sink_ops,
6106c6ed1e2SMathieu Poirier 	.link_ops	= &tmc_etf_link_ops,
6116c6ed1e2SMathieu Poirier };
6124525412aSMathieu Poirier 
tmc_read_prepare_etb(struct tmc_drvdata * drvdata)6134525412aSMathieu Poirier int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
6144525412aSMathieu Poirier {
6154525412aSMathieu Poirier 	enum tmc_mode mode;
6164525412aSMathieu Poirier 	int ret = 0;
6174525412aSMathieu Poirier 	unsigned long flags;
6184525412aSMathieu Poirier 
6194525412aSMathieu Poirier 	/* config types are set a boot time and never change */
6204525412aSMathieu Poirier 	if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETB &&
6214525412aSMathieu Poirier 			 drvdata->config_type != TMC_CONFIG_TYPE_ETF))
6224525412aSMathieu Poirier 		return -EINVAL;
6234525412aSMathieu Poirier 
6244525412aSMathieu Poirier 	spin_lock_irqsave(&drvdata->spinlock, flags);
6254525412aSMathieu Poirier 
626f74debbeSMathieu Poirier 	if (drvdata->reading) {
627f74debbeSMathieu Poirier 		ret = -EBUSY;
628f74debbeSMathieu Poirier 		goto out;
629f74debbeSMathieu Poirier 	}
630f74debbeSMathieu Poirier 
631b217601eSMathieu Poirier 	/* Don't interfere if operated from Perf */
632297ab90fSSuzuki K. Poulose 	if (drvdata->mode == CS_MODE_PERF) {
633b217601eSMathieu Poirier 		ret = -EINVAL;
634b217601eSMathieu Poirier 		goto out;
635b217601eSMathieu Poirier 	}
636b217601eSMathieu Poirier 
637de546197SMathieu Poirier 	/* If drvdata::buf is NULL the trace data has been read already */
638de546197SMathieu Poirier 	if (drvdata->buf == NULL) {
639de546197SMathieu Poirier 		ret = -EINVAL;
640de546197SMathieu Poirier 		goto out;
641de546197SMathieu Poirier 	}
642de546197SMathieu Poirier 
6434525412aSMathieu Poirier 	/* Disable the TMC if need be */
644347adb0dSSai Prakash Ranjan 	if (drvdata->mode == CS_MODE_SYSFS) {
645347adb0dSSai Prakash Ranjan 		/* There is no point in reading a TMC in HW FIFO mode */
646347adb0dSSai Prakash Ranjan 		mode = readl_relaxed(drvdata->base + TMC_MODE);
647347adb0dSSai Prakash Ranjan 		if (mode != TMC_MODE_CIRCULAR_BUFFER) {
648347adb0dSSai Prakash Ranjan 			ret = -EINVAL;
649347adb0dSSai Prakash Ranjan 			goto out;
650347adb0dSSai Prakash Ranjan 		}
6514d3ebd36SSuzuki K Poulose 		__tmc_etb_disable_hw(drvdata);
652347adb0dSSai Prakash Ranjan 	}
6534525412aSMathieu Poirier 
6544525412aSMathieu Poirier 	drvdata->reading = true;
6554525412aSMathieu Poirier out:
6564525412aSMathieu Poirier 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
6574525412aSMathieu Poirier 
6584525412aSMathieu Poirier 	return ret;
6594525412aSMathieu Poirier }
6604525412aSMathieu Poirier 
tmc_read_unprepare_etb(struct tmc_drvdata * drvdata)6614525412aSMathieu Poirier int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
6624525412aSMathieu Poirier {
663de546197SMathieu Poirier 	char *buf = NULL;
6644525412aSMathieu Poirier 	enum tmc_mode mode;
6654525412aSMathieu Poirier 	unsigned long flags;
666669c4614SYabin Cui 	int rc = 0;
6674525412aSMathieu Poirier 
6684525412aSMathieu Poirier 	/* config types are set a boot time and never change */
6694525412aSMathieu Poirier 	if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETB &&
6704525412aSMathieu Poirier 			 drvdata->config_type != TMC_CONFIG_TYPE_ETF))
6714525412aSMathieu Poirier 		return -EINVAL;
6724525412aSMathieu Poirier 
6734525412aSMathieu Poirier 	spin_lock_irqsave(&drvdata->spinlock, flags);
6744525412aSMathieu Poirier 
675d021f5c5SSai Prakash Ranjan 	/* Re-enable the TMC if need be */
676d021f5c5SSai Prakash Ranjan 	if (drvdata->mode == CS_MODE_SYSFS) {
6774525412aSMathieu Poirier 		/* There is no point in reading a TMC in HW FIFO mode */
6784525412aSMathieu Poirier 		mode = readl_relaxed(drvdata->base + TMC_MODE);
6794525412aSMathieu Poirier 		if (mode != TMC_MODE_CIRCULAR_BUFFER) {
6804525412aSMathieu Poirier 			spin_unlock_irqrestore(&drvdata->spinlock, flags);
6814525412aSMathieu Poirier 			return -EINVAL;
6824525412aSMathieu Poirier 		}
683de546197SMathieu Poirier 		/*
684de546197SMathieu Poirier 		 * The trace run will continue with the same allocated trace
685de546197SMathieu Poirier 		 * buffer. As such zero-out the buffer so that we don't end
686de546197SMathieu Poirier 		 * up with stale data.
687de546197SMathieu Poirier 		 *
688de546197SMathieu Poirier 		 * Since the tracer is still enabled drvdata::buf
689de546197SMathieu Poirier 		 * can't be NULL.
690de546197SMathieu Poirier 		 */
691de546197SMathieu Poirier 		memset(drvdata->buf, 0, drvdata->size);
692669c4614SYabin Cui 		rc = __tmc_etb_enable_hw(drvdata);
693669c4614SYabin Cui 		if (rc) {
694669c4614SYabin Cui 			spin_unlock_irqrestore(&drvdata->spinlock, flags);
695669c4614SYabin Cui 			return rc;
696669c4614SYabin Cui 		}
697de546197SMathieu Poirier 	} else {
698de546197SMathieu Poirier 		/*
699de546197SMathieu Poirier 		 * The ETB/ETF is not tracing and the buffer was just read.
700de546197SMathieu Poirier 		 * As such prepare to free the trace buffer.
701de546197SMathieu Poirier 		 */
702de546197SMathieu Poirier 		buf = drvdata->buf;
703de546197SMathieu Poirier 		drvdata->buf = NULL;
704de546197SMathieu Poirier 	}
7054525412aSMathieu Poirier 
7064525412aSMathieu Poirier 	drvdata->reading = false;
7074525412aSMathieu Poirier 	spin_unlock_irqrestore(&drvdata->spinlock, flags);
7084525412aSMathieu Poirier 
709de546197SMathieu Poirier 	/*
710de546197SMathieu Poirier 	 * Free allocated memory outside of the spinlock.  There is no need
711de546197SMathieu Poirier 	 * to assert the validity of 'buf' since calling kfree(NULL) is safe.
712de546197SMathieu Poirier 	 */
713de546197SMathieu Poirier 	kfree(buf);
714de546197SMathieu Poirier 
7154525412aSMathieu Poirier 	return 0;
7164525412aSMathieu Poirier }
717