coresight: Properly address concurrency in sink::update() functions
authorMathieu Poirier <mathieu.poirier@linaro.org>
Thu, 25 Apr 2019 19:52:58 +0000 (13:52 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 25 Apr 2019 20:00:17 +0000 (22:00 +0200)
When operating in CPU-wide trace scenarios and working with an N:1
source/sink HW topology, update() functions need to be made atomic
in order to avoid racing with start and stop operations.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Tested-by: Leo Yan <leo.yan@linaro.org>
Tested-by: Robert Walker <robert.walker@arm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/hwtracing/coresight/coresight-etb10.c
drivers/hwtracing/coresight/coresight-tmc-etf.c

index 6b73bc2e0dbd56ac7949dcd0625225b7579d4d46..00d664c6a40104a17705d4c27616bdfa4c54f344 100644 (file)
@@ -405,7 +405,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
        const u32 *barrier;
        u32 read_ptr, write_ptr, capacity;
        u32 status, read_data;
-       unsigned long offset, to_read;
+       unsigned long offset, to_read, flags;
        struct cs_buffers *buf = sink_config;
        struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
@@ -414,6 +414,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
 
        capacity = drvdata->buffer_depth * ETB_FRAME_SIZE_WORDS;
 
+       spin_lock_irqsave(&drvdata->spinlock, flags);
        __etb_disable_hw(drvdata);
        CS_UNLOCK(drvdata->base);
 
@@ -524,6 +525,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
        }
        __etb_enable_hw(drvdata);
        CS_LOCK(drvdata->base);
+       spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
        return to_read;
 }
index 30f8686765400cde98d034a75f76d5cd7aedf880..a38ad2b0d95a3fa0cf567f3d58338d6b8f501900 100644 (file)
@@ -413,7 +413,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
        u32 *buf_ptr;
        u64 read_ptr, write_ptr;
        u32 status;
-       unsigned long offset, to_read;
+       unsigned long offset, to_read, flags;
        struct cs_buffers *buf = sink_config;
        struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
@@ -424,6 +424,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
        if (WARN_ON_ONCE(drvdata->mode != CS_MODE_PERF))
                return 0;
 
+       spin_lock_irqsave(&drvdata->spinlock, flags);
        CS_UNLOCK(drvdata->base);
 
        tmc_flush_and_stop(drvdata);
@@ -517,6 +518,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
                to_read = buf->nr_pages << PAGE_SHIFT;
        }
        CS_LOCK(drvdata->base);
+       spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
        return to_read;
 }