|
@@ -895,10 +895,15 @@ static void tmc_sync_etr_buf(struct tmc_drvdata *drvdata)
|
|
tmc_etr_buf_insert_barrier_packet(etr_buf, etr_buf->offset);
|
|
tmc_etr_buf_insert_barrier_packet(etr_buf, etr_buf->offset);
|
|
}
|
|
}
|
|
|
|
|
|
-static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
|
|
|
|
|
|
+static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata,
|
|
|
|
+ struct etr_buf *etr_buf)
|
|
{
|
|
{
|
|
u32 axictl, sts;
|
|
u32 axictl, sts;
|
|
- struct etr_buf *etr_buf = drvdata->etr_buf;
|
|
|
|
|
|
+
|
|
|
|
+ /* Callers should provide an appropriate buffer for use */
|
|
|
|
+ if (WARN_ON(!etr_buf || drvdata->etr_buf))
|
|
|
|
+ return;
|
|
|
|
+ drvdata->etr_buf = etr_buf;
|
|
|
|
|
|
/*
|
|
/*
|
|
* If this ETR is connected to a CATU, enable it before we turn
|
|
* If this ETR is connected to a CATU, enable it before we turn
|
|
@@ -960,13 +965,16 @@ static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
|
|
* also updating the @bufpp on where to find it. Since the trace data
|
|
* 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
|
|
* starts at anywhere in the buffer, depending on the RRP, we adjust the
|
|
* @len returned to handle buffer wrapping around.
|
|
* @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,
|
|
ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata,
|
|
loff_t pos, size_t len, char **bufpp)
|
|
loff_t pos, size_t len, char **bufpp)
|
|
{
|
|
{
|
|
s64 offset;
|
|
s64 offset;
|
|
ssize_t actual = len;
|
|
ssize_t actual = len;
|
|
- struct etr_buf *etr_buf = drvdata->etr_buf;
|
|
|
|
|
|
+ struct etr_buf *etr_buf = drvdata->sysfs_buf;
|
|
|
|
|
|
if (pos + actual > etr_buf->len)
|
|
if (pos + actual > etr_buf->len)
|
|
actual = etr_buf->len - pos;
|
|
actual = etr_buf->len - pos;
|
|
@@ -996,7 +1004,14 @@ tmc_etr_free_sysfs_buf(struct etr_buf *buf)
|
|
|
|
|
|
static void tmc_etr_sync_sysfs_buf(struct tmc_drvdata *drvdata)
|
|
static void tmc_etr_sync_sysfs_buf(struct tmc_drvdata *drvdata)
|
|
{
|
|
{
|
|
- tmc_sync_etr_buf(drvdata);
|
|
|
|
|
|
+ struct etr_buf *etr_buf = drvdata->etr_buf;
|
|
|
|
+
|
|
|
|
+ if (WARN_ON(drvdata->sysfs_buf != etr_buf)) {
|
|
|
|
+ tmc_etr_free_sysfs_buf(drvdata->sysfs_buf);
|
|
|
|
+ drvdata->sysfs_buf = NULL;
|
|
|
|
+ } else {
|
|
|
|
+ tmc_sync_etr_buf(drvdata);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
|
|
static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
|
|
@@ -1017,6 +1032,8 @@ static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
|
|
|
|
|
|
/* Disable CATU device if this ETR is connected to one */
|
|
/* Disable CATU device if this ETR is connected to one */
|
|
tmc_etr_disable_catu(drvdata);
|
|
tmc_etr_disable_catu(drvdata);
|
|
|
|
+ /* Reset the ETR buf used by hardware */
|
|
|
|
+ drvdata->etr_buf = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
|
|
static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
|
|
@@ -1024,7 +1041,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
|
|
int ret = 0;
|
|
int ret = 0;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
|
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
|
|
- struct etr_buf *new_buf = NULL, *free_buf = NULL;
|
|
|
|
|
|
+ struct etr_buf *sysfs_buf = NULL, *new_buf = NULL, *free_buf = NULL;
|
|
|
|
|
|
/*
|
|
/*
|
|
* If we are enabling the ETR from disabled state, we need to make
|
|
* If we are enabling the ETR from disabled state, we need to make
|
|
@@ -1035,7 +1052,8 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
|
|
* with the lock released.
|
|
* with the lock released.
|
|
*/
|
|
*/
|
|
spin_lock_irqsave(&drvdata->spinlock, flags);
|
|
spin_lock_irqsave(&drvdata->spinlock, flags);
|
|
- if (!drvdata->etr_buf || (drvdata->etr_buf->size != drvdata->size)) {
|
|
|
|
|
|
+ sysfs_buf = READ_ONCE(drvdata->sysfs_buf);
|
|
|
|
+ if (!sysfs_buf || (sysfs_buf->size != drvdata->size)) {
|
|
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
|
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
|
|
|
|
|
/* Allocate memory with the locks released */
|
|
/* Allocate memory with the locks released */
|
|
@@ -1064,14 +1082,14 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
|
|
* If we don't have a buffer or it doesn't match the requested size,
|
|
* If we don't have a buffer or it doesn't match the requested size,
|
|
* use the buffer allocated above. Otherwise reuse the existing buffer.
|
|
* use the buffer allocated above. Otherwise reuse the existing buffer.
|
|
*/
|
|
*/
|
|
- if (!drvdata->etr_buf ||
|
|
|
|
- (new_buf && drvdata->etr_buf->size != new_buf->size)) {
|
|
|
|
- free_buf = drvdata->etr_buf;
|
|
|
|
- drvdata->etr_buf = new_buf;
|
|
|
|
|
|
+ sysfs_buf = READ_ONCE(drvdata->sysfs_buf);
|
|
|
|
+ if (!sysfs_buf || (new_buf && sysfs_buf->size != new_buf->size)) {
|
|
|
|
+ free_buf = sysfs_buf;
|
|
|
|
+ drvdata->sysfs_buf = new_buf;
|
|
}
|
|
}
|
|
|
|
|
|
drvdata->mode = CS_MODE_SYSFS;
|
|
drvdata->mode = CS_MODE_SYSFS;
|
|
- tmc_etr_enable_hw(drvdata);
|
|
|
|
|
|
+ tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf);
|
|
out:
|
|
out:
|
|
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
|
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
|
|
|
|
|
@@ -1156,13 +1174,13 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- /* If drvdata::etr_buf is NULL the trace data has been read already */
|
|
|
|
- if (drvdata->etr_buf == NULL) {
|
|
|
|
|
|
+ /* If sysfs_buf is NULL the trace data has been read already */
|
|
|
|
+ if (!drvdata->sysfs_buf) {
|
|
ret = -EINVAL;
|
|
ret = -EINVAL;
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- /* Disable the TMC if need be */
|
|
|
|
|
|
+ /* Disable the TMC if we are trying to read from a running session */
|
|
if (drvdata->mode == CS_MODE_SYSFS)
|
|
if (drvdata->mode == CS_MODE_SYSFS)
|
|
tmc_etr_disable_hw(drvdata);
|
|
tmc_etr_disable_hw(drvdata);
|
|
|
|
|
|
@@ -1176,7 +1194,7 @@ out:
|
|
int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
|
|
int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
|
|
{
|
|
{
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
- struct etr_buf *etr_buf = NULL;
|
|
|
|
|
|
+ struct etr_buf *sysfs_buf = NULL;
|
|
|
|
|
|
/* config types are set a boot time and never change */
|
|
/* config types are set a boot time and never change */
|
|
if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
|
|
if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR))
|
|
@@ -1191,22 +1209,22 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
|
|
* buffer. Since the tracer is still enabled drvdata::buf can't
|
|
* buffer. Since the tracer is still enabled drvdata::buf can't
|
|
* be NULL.
|
|
* be NULL.
|
|
*/
|
|
*/
|
|
- tmc_etr_enable_hw(drvdata);
|
|
|
|
|
|
+ tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf);
|
|
} else {
|
|
} else {
|
|
/*
|
|
/*
|
|
* The ETR is not tracing and the buffer was just read.
|
|
* The ETR is not tracing and the buffer was just read.
|
|
* As such prepare to free the trace buffer.
|
|
* As such prepare to free the trace buffer.
|
|
*/
|
|
*/
|
|
- etr_buf = drvdata->etr_buf;
|
|
|
|
- drvdata->etr_buf = NULL;
|
|
|
|
|
|
+ sysfs_buf = drvdata->sysfs_buf;
|
|
|
|
+ drvdata->sysfs_buf = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
drvdata->reading = false;
|
|
drvdata->reading = false;
|
|
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
|
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
|
|
|
|
|
/* Free allocated memory out side of the spinlock */
|
|
/* Free allocated memory out side of the spinlock */
|
|
- if (etr_buf)
|
|
|
|
- tmc_free_etr_buf(etr_buf);
|
|
|
|
|
|
+ if (sysfs_buf)
|
|
|
|
+ tmc_etr_free_sysfs_buf(sysfs_buf);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|