On Tue, Sep 04, 2018 at 01:45:47PM +0300, mike@perception-point.io wrote:
From: Mike Bazov mike@perception-point.io
Introducing the get_trace() sink operation. This is merely exposing the tmc_etr_get_sysfs_trace() functionality as a sink operation, and also implementing for CS_MODE_API.
When using get_trace() with request CS_MODE_API, the trace is fetched from the __current__ etr buffer, which is assumed to be the CS_MODE_API buffer set by set_buffer(). The get_trace() can be further exposed to kernel clients to easily get the trace buffer and copy trace data from it.
In addition, the tmc-etf is also made aware of this sink op, without supporting CS_MODE_API.
Signed-off-by: Mike Bazov mike@perception-point.io
drivers/hwtracing/coresight/coresight-tmc-etf.c | 14 ++++ drivers/hwtracing/coresight/coresight-tmc-etr.c | 100 +++++++++++++++++++++--- include/linux/coresight.h | 3 + 3 files changed, 108 insertions(+), 9 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 897dfc1bcbaa..656a786de808 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -120,6 +120,19 @@ ssize_t tmc_etb_get_sysfs_trace(struct tmc_drvdata *drvdata, return actual; } +ssize_t tmc_etf_get_trace(struct coresight_device *csdev, u32 mode,
loff_t pos, size_t len, char **bufpp)
+{
- struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- switch (mode) {
- case CS_MODE_SYSFS:
return tmc_etb_get_sysfs_trace(drvdata, pos, len, bufpp);
- default:
return -EINVAL;
- }
+}
I'm wondering who will be using bufpp and how it will be used. This patchset gives us a better understanding of what you need but nothing about why you need it.
static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev) { int ret = 0; @@ -490,6 +503,7 @@ static const struct coresight_ops_sink tmc_etf_sink_ops = { .alloc_buffer = tmc_alloc_etf_buffer, .free_buffer = tmc_free_etf_buffer, .update_buffer = tmc_update_etf_buffer,
- .get_trace = tmc_etf_get_trace,
}; static const struct coresight_ops_link tmc_etf_link_ops = { diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 6ffcaaf76680..f60ac8942c1f 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -37,6 +37,8 @@ struct etr_perf_buffer { void **pages; }; +static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata);
/* Convert the perf index to an offset within the ETR buffer */ #define PERF_IDX2OFF(idx, buf) ((idx) % ((buf)->nr_pages << PAGE_SHIFT)) @@ -907,6 +909,7 @@ static void tmc_sync_etr_buf(struct tmc_drvdata *drvdata) rrp = tmc_read_rrp(drvdata); rwp = tmc_read_rwp(drvdata); status = readl_relaxed(drvdata->base + TMC_STS);
Extra line
etr_buf->full = status & TMC_STS_FULL; WARN_ON(!etr_buf->ops || !etr_buf->ops->sync); @@ -988,29 +991,91 @@ static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata,
- also updating the @bufpp on where to find it. Since the trace data
- starts at anywhere in the buffer, depending on the RRP, we adjust the
- @len returned to handle buffer wrapping around.
- We are protected here by drvdata->reading != 0, which ensures the
*/
- sysfs_buf stays alive.
-ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata,
loff_t pos, size_t len, char **bufpp)
+static ssize_t etr_buf_get_trace(struct etr_buf *etr_buf,
loff_t pos, size_t len, char **bufpp)
{ s64 offset; ssize_t actual = len;
- struct etr_buf *etr_buf = drvdata->sysfs_buf;
- if (!etr_buf)
return -EINVAL;
if (pos + actual > etr_buf->len) actual = etr_buf->len - pos; if (actual <= 0)
return actual;
return 0;
I'll have to think further about this one.
/* Compute the offset from which we read the data */ offset = etr_buf->offset + pos; if (offset >= etr_buf->size) offset -= etr_buf->size;
Extra line
return tmc_etr_buf_get_data(etr_buf, offset, actual, bufpp); } +/* We are protected here by drvdata->reading != 0, which ensures
- the sysfs_buf stays alive.
- */
/* * We are protected here by drvdata->reading != 0, which ensures * the sysfs_buf stays alive. */
+ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata,
loff_t pos, size_t len, char **bufpp)
+{
- return etr_buf_get_trace(drvdata->sysfs_buf, pos, len, bufpp);
+}
+/* It is the user's responsbility to keep the coresight session buffer
- valid.
- */
Same as above
+static ssize_t tmc_etr_get_api_trace(struct tmc_drvdata *drvdata,
loff_t pos, size_t len, char **bufpp)
+{
- ssize_t ret = 0;
- unsigned long flags;
- spin_lock_irqsave(&drvdata->spinlock, flags);
- if (drvdata->mode != CS_MODE_API) {
ret = -EINVAL;
goto out;
- }
- if (drvdata->api_buf == NULL) {
ret = -ENOENT;
goto out;
- }
- /* Make sure to stop and sync the buffer if we're getting a trace
* from a running session.
*/
- tmc_etr_disable_hw(drvdata);
- ret = etr_buf_get_trace(drvdata->api_buf, pos, len, bufpp);
- /* Re-enable the trace session. Again, it is entirely up the user to
* read the actual trace data before reusing the existing buffer, or,
* perhaps, use a different buffer.
*/
- tmc_etr_enable_hw(drvdata, drvdata->api_buf);
+out:
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
- return ret;
+}
+ssize_t tmc_etr_get_trace(struct coresight_device *csdev, u32 mode,
loff_t poss, size_t len, char **buffpp)
+{
- struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- switch (mode) {
- case CS_MODE_SYSFS:
return tmc_etr_get_sysfs_trace(drvdata, poss, len, buffpp);
- case CS_MODE_API:
return tmc_etr_get_api_trace(drvdata, poss, len, buffpp);
- default:
return -EINVAL;
- }
+}
static struct etr_buf * tmc_etr_setup_sysfs_buf(struct tmc_drvdata *drvdata) { @@ -1037,6 +1102,17 @@ static void tmc_etr_sync_sysfs_buf(struct tmc_drvdata *drvdata) } } +static void tmc_etr_sync_api_buf(struct tmc_drvdata *drvdata) +{
- struct etr_buf *etr_buf = drvdata->etr_buf;
- /* We aren't certain there is indeed an etr buffer here, the user
* might set it to NULL, he is controling the buffer.
*/
- if (etr_buf && !WARN_ON(drvdata->api_buf != etr_buf))
tmc_sync_etr_buf(drvdata);
+}
static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) { CS_UNLOCK(drvdata->base); @@ -1048,9 +1124,10 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) */ if (drvdata->mode == CS_MODE_SYSFS) tmc_etr_sync_sysfs_buf(drvdata);
- else if (drvdata->mode == CS_MODE_API)
tmc_etr_sync_api_buf(drvdata);
tmc_disable_hw(drvdata);
- CS_LOCK(drvdata->base);
/* Disable CATU device if this ETR is connected to one */ @@ -1460,7 +1537,11 @@ void tmc_disable_etr_sink(struct coresight_device *csdev) /* Disable the TMC only if it needs to */ if (drvdata->mode != CS_MODE_DISABLED) {
tmc_etr_disable_hw(drvdata);
/* Only disable the hardware if the mode isn't API,
* or, if the mode is API, only if we have a valid buffer.
*/
if (drvdata->mode != CS_MODE_API || drvdata->api_buf != NULL)
tmc_etr_disable_hw(drvdata);
In order to avoid this kind of complexity please split the function in accordance to the mode of operation. I will be releasing a patchset later today or early next week that adds a mode of operation to sinks' disable function. I will CC you on the patchset.
drvdata->mode = CS_MODE_DISABLED;
} @@ -1476,6 +1557,7 @@ static const struct coresight_ops_sink tmc_etr_sink_ops = { .update_buffer = tmc_update_etr_buffer, .set_buffer = tmc_etr_set_buffer, .free_buffer = tmc_free_etr_buffer,
- .get_trace = tmc_etr_get_trace
}; const struct coresight_ops tmc_etr_cs_ops = { diff --git a/include/linux/coresight.h b/include/linux/coresight.h index c29a3bb4c386..0a57a2ce8d4d 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -187,6 +187,7 @@ struct coresight_device {
- @free_buffer: release memory allocated in @get_config.
- @set_buffer: set the trace buffer.
- @update_buffer: update buffer pointers after a trace session.
*/
- @get_trace: get a pointer to the trace data.
struct coresight_ops_sink { int (*enable)(struct coresight_device *csdev, u32 mode, void *data); @@ -200,6 +201,8 @@ struct coresight_ops_sink { unsigned long (*update_buffer)(struct coresight_device *csdev, struct perf_output_handle *handle, void *sink_config);
- ssize_t (*get_trace)(struct coresight_device *csdev, u32 mode,
loff_t poss, size_t len, char **buf);
Tabulation problem
}; /** -- 2.16.2