Commit f74debbe authored by Mathieu Poirier's avatar Mathieu Poirier Committed by Greg Kroah-Hartman

coresight: tmc: getting rid of multiple read access

Allowing multiple readers to access the trace data simultaniously
via sysFS provides no shortage of opportunity for race condition,
mandates two variable to be maintained (drvdata::read_count and
drvdata::reading), makes the code complex and provide little
advantages, if any.

This patch streamlines the read process by restricting trace data
access to a single user.  That way drvdata::read_count can
be eliminated and race conditions (along with faulty error handling)
in function tmc_open() and tmc_release() eliminated.
Signed-off-by: default avatarMathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: default avatarSuzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent de546197
...@@ -260,6 +260,11 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata) ...@@ -260,6 +260,11 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
spin_lock_irqsave(&drvdata->spinlock, flags); spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
ret = -EBUSY;
goto out;
}
/* There is no point in reading a TMC in HW FIFO mode */ /* There is no point in reading a TMC in HW FIFO mode */
mode = readl_relaxed(drvdata->base + TMC_MODE); mode = readl_relaxed(drvdata->base + TMC_MODE);
if (mode != TMC_MODE_CIRCULAR_BUFFER) { if (mode != TMC_MODE_CIRCULAR_BUFFER) {
......
...@@ -188,6 +188,10 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) ...@@ -188,6 +188,10 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&drvdata->spinlock, flags); spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
ret = -EBUSY;
goto out;
}
/* If drvdata::buf is NULL the trace data has been read already */ /* If drvdata::buf is NULL the trace data has been read already */
if (drvdata->buf == NULL) { if (drvdata->buf == NULL) {
......
...@@ -95,7 +95,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) ...@@ -95,7 +95,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
return ret; return ret;
} }
static void tmc_read_unprepare(struct tmc_drvdata *drvdata) static int tmc_read_unprepare(struct tmc_drvdata *drvdata)
{ {
int ret = 0; int ret = 0;
...@@ -113,21 +113,20 @@ static void tmc_read_unprepare(struct tmc_drvdata *drvdata) ...@@ -113,21 +113,20 @@ static void tmc_read_unprepare(struct tmc_drvdata *drvdata)
if (!ret) if (!ret)
dev_info(drvdata->dev, "TMC read end\n"); dev_info(drvdata->dev, "TMC read end\n");
return ret;
} }
static int tmc_open(struct inode *inode, struct file *file) static int tmc_open(struct inode *inode, struct file *file)
{ {
int ret;
struct tmc_drvdata *drvdata = container_of(file->private_data, struct tmc_drvdata *drvdata = container_of(file->private_data,
struct tmc_drvdata, miscdev); struct tmc_drvdata, miscdev);
int ret = 0;
if (drvdata->read_count++)
goto out;
ret = tmc_read_prepare(drvdata); ret = tmc_read_prepare(drvdata);
if (ret) if (ret)
return ret; return ret;
out:
nonseekable_open(inode, file); nonseekable_open(inode, file);
dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__); dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
...@@ -167,19 +166,14 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, ...@@ -167,19 +166,14 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
static int tmc_release(struct inode *inode, struct file *file) static int tmc_release(struct inode *inode, struct file *file)
{ {
int ret;
struct tmc_drvdata *drvdata = container_of(file->private_data, struct tmc_drvdata *drvdata = container_of(file->private_data,
struct tmc_drvdata, miscdev); struct tmc_drvdata, miscdev);
if (--drvdata->read_count) { ret = tmc_read_unprepare(drvdata);
if (drvdata->read_count < 0) { if (ret)
dev_err(drvdata->dev, "mismatched close\n"); return ret;
drvdata->read_count = 0;
}
goto out;
}
tmc_read_unprepare(drvdata);
out:
dev_dbg(drvdata->dev, "%s: released\n", __func__); dev_dbg(drvdata->dev, "%s: released\n", __func__);
return 0; return 0;
} }
......
...@@ -94,7 +94,6 @@ enum tmc_mem_intf_width { ...@@ -94,7 +94,6 @@ enum tmc_mem_intf_width {
* @csdev: component vitals needed by the framework. * @csdev: component vitals needed by the framework.
* @miscdev: specifics to handle "/dev/xyz.tmc" entry. * @miscdev: specifics to handle "/dev/xyz.tmc" entry.
* @spinlock: only one at a time pls. * @spinlock: only one at a time pls.
* @read_count: manages preparation of buffer for reading.
* @buf: area of memory where trace data get sent. * @buf: area of memory where trace data get sent.
* @paddr: DMA start location in RAM. * @paddr: DMA start location in RAM.
* @vaddr: virtual representation of @paddr. * @vaddr: virtual representation of @paddr.
...@@ -109,7 +108,6 @@ struct tmc_drvdata { ...@@ -109,7 +108,6 @@ struct tmc_drvdata {
struct coresight_device *csdev; struct coresight_device *csdev;
struct miscdevice miscdev; struct miscdevice miscdev;
spinlock_t spinlock; spinlock_t spinlock;
int read_count;
bool reading; bool reading;
char *buf; char *buf;
dma_addr_t paddr; dma_addr_t paddr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment