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