coresight: tmc: getting rid of multiple read access
authorMathieu Poirier <mathieu.poirier@linaro.org>
Tue, 3 May 2016 17:33:53 +0000 (11:33 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 3 May 2016 21:59:30 +0000 (14:59 -0700)
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: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/hwtracing/coresight/coresight-tmc-etf.c
drivers/hwtracing/coresight/coresight-tmc-etr.c
drivers/hwtracing/coresight/coresight-tmc.c
drivers/hwtracing/coresight/coresight-tmc.h

index 6eb1665cfc9ce2ecff001ae49dde58f48f11fd48..60edf4d1968f2890af9bf86ca041cfbf83456c95 100644 (file)
@@ -260,6 +260,11 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
 
        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 */
        mode = readl_relaxed(drvdata->base + TMC_MODE);
        if (mode != TMC_MODE_CIRCULAR_BUFFER) {
index ac37bf904fb7cd50e82b9425a7342c17bd5f5db6..d6999b457fb82868d6adfa83ed7d81bf5d2ae9cc 100644 (file)
@@ -188,6 +188,10 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
                return -EINVAL;
 
        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 == NULL) {
index e8e12a9b917aff2c20b52f34c1891141ed8e4d6e..ae7525a2b94a6c2f48ee66f0fa26ed2c2f33ffa0 100644 (file)
@@ -95,7 +95,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata)
        return ret;
 }
 
-static void tmc_read_unprepare(struct tmc_drvdata *drvdata)
+static int tmc_read_unprepare(struct tmc_drvdata *drvdata)
 {
        int ret = 0;
 
@@ -113,21 +113,20 @@ static void tmc_read_unprepare(struct tmc_drvdata *drvdata)
 
        if (!ret)
                dev_info(drvdata->dev, "TMC read end\n");
+
+       return ret;
 }
 
 static int tmc_open(struct inode *inode, struct file *file)
 {
+       int ret;
        struct tmc_drvdata *drvdata = container_of(file->private_data,
                                                   struct tmc_drvdata, miscdev);
-       int ret = 0;
-
-       if (drvdata->read_count++)
-               goto out;
 
        ret = tmc_read_prepare(drvdata);
        if (ret)
                return ret;
-out:
+
        nonseekable_open(inode, file);
 
        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,
 
 static int tmc_release(struct inode *inode, struct file *file)
 {
+       int ret;
        struct tmc_drvdata *drvdata = container_of(file->private_data,
                                                   struct tmc_drvdata, miscdev);
 
-       if (--drvdata->read_count) {
-               if (drvdata->read_count < 0) {
-                       dev_err(drvdata->dev, "mismatched close\n");
-                       drvdata->read_count = 0;
-               }
-               goto out;
-       }
+       ret = tmc_read_unprepare(drvdata);
+       if (ret)
+               return ret;
 
-       tmc_read_unprepare(drvdata);
-out:
        dev_dbg(drvdata->dev, "%s: released\n", __func__);
        return 0;
 }
index df661903f83cf0e8a2d8d6be9c264ecc19785b4c..592eb149fe3a5b9dd687626450ff7e8afa877e82 100644 (file)
@@ -94,7 +94,6 @@ enum tmc_mem_intf_width {
  * @csdev:     component vitals needed by the framework.
  * @miscdev:   specifics to handle "/dev/xyz.tmc" entry.
  * @spinlock:  only one at a time pls.
- * @read_count:        manages preparation of buffer for reading.
  * @buf:       area of memory where trace data get sent.
  * @paddr:     DMA start location in RAM.
  * @vaddr:     virtual representation of @paddr.
@@ -109,7 +108,6 @@ struct tmc_drvdata {
        struct coresight_device *csdev;
        struct miscdevice       miscdev;
        spinlock_t              spinlock;
-       int                     read_count;
        bool                    reading;
        char                    *buf;
        dma_addr_t              paddr;