coresight: etb10: adding operation mode for sink->enable()
authorMathieu Poirier <mathieu.poirier@linaro.org>
Thu, 18 Feb 2016 00:51:59 +0000 (17:51 -0700)
committerMathieu Poirier <mathieu.poirier@linaro.org>
Wed, 1 Jun 2016 21:31:25 +0000 (15:31 -0600)
Adding an operation mode to the sink->enable() API in order
to prevent simultaneous access from different callers.

TPIU and TMC won't be supplemented with the AUX area
API immediately and as such ignore the new mode.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit e827d4550aa3225b8965ce4c266208cfe0297509)

drivers/hwtracing/coresight/coresight-etb10.c
drivers/hwtracing/coresight/coresight-priv.h
drivers/hwtracing/coresight/coresight-tmc.c
drivers/hwtracing/coresight/coresight-tpiu.c
drivers/hwtracing/coresight/coresight.c
include/linux/coresight.h

index 162c9ccc8c330fc70e04ae9dfb47209d6226beab..79099f95ba3fdff3a8b2ecc5439df529bababb8d 100644 (file)
@@ -73,9 +73,9 @@
  * @miscdev:   specifics to handle "/dev/xyz.etb" entry.
  * @spinlock:  only one at a time pls.
  * @reading:   synchronise user space access to etb buffer.
+ * @mode:      this ETB is being used.
  * @buf:       area of memory where ETB buffer content gets sent.
  * @buffer_depth: size of @buf.
- * @enable:    this ETB is being used.
  * @trigger_cntr: amount of words to store after a trigger.
  */
 struct etb_drvdata {
@@ -86,9 +86,9 @@ struct etb_drvdata {
        struct miscdevice       miscdev;
        spinlock_t              spinlock;
        local_t                 reading;
+       local_t                 mode;
        u8                      *buf;
        u32                     buffer_depth;
-       bool                    enable;
        u32                     trigger_cntr;
 };
 
@@ -133,16 +133,31 @@ static void etb_enable_hw(struct etb_drvdata *drvdata)
        CS_LOCK(drvdata->base);
 }
 
-static int etb_enable(struct coresight_device *csdev)
+static int etb_enable(struct coresight_device *csdev, u32 mode)
 {
-       struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+       u32 val;
        unsigned long flags;
+       struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+       val = local_cmpxchg(&drvdata->mode,
+                           CS_MODE_DISABLED, mode);
+       /*
+        * When accessing from Perf, a HW buffer can be handled
+        * by a single trace entity.  In sysFS mode many tracers
+        * can be logging to the same HW buffer.
+        */
+       if (val == CS_MODE_PERF)
+               return -EBUSY;
+
+       /* Nothing to do, the tracer is already enabled. */
+       if (val == CS_MODE_SYSFS)
+               goto out;
 
        spin_lock_irqsave(&drvdata->spinlock, flags);
        etb_enable_hw(drvdata);
-       drvdata->enable = true;
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+out:
        dev_info(drvdata->dev, "ETB enabled\n");
        return 0;
 }
@@ -243,9 +258,10 @@ static void etb_disable(struct coresight_device *csdev)
        spin_lock_irqsave(&drvdata->spinlock, flags);
        etb_disable_hw(drvdata);
        etb_dump_hw(drvdata);
-       drvdata->enable = false;
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
+       local_set(&drvdata->mode, CS_MODE_DISABLED);
+
        dev_info(drvdata->dev, "ETB disabled\n");
 }
 
@@ -263,7 +279,7 @@ static void etb_dump(struct etb_drvdata *drvdata)
        unsigned long flags;
 
        spin_lock_irqsave(&drvdata->spinlock, flags);
-       if (drvdata->enable) {
+       if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
                etb_disable_hw(drvdata);
                etb_dump_hw(drvdata);
                etb_enable_hw(drvdata);
index 932f34a84d96207541e15f07cbe242f253a744f5..333eddaed33930cb5bda16089c8732b2f4e1fd97 100644 (file)
@@ -62,7 +62,7 @@ static inline void CS_UNLOCK(void __iomem *addr)
 }
 
 void coresight_disable_path(struct list_head *path);
-int coresight_enable_path(struct list_head *path);
+int coresight_enable_path(struct list_head *path, u32 mode);
 struct coresight_device *coresight_get_sink(struct list_head *path);
 struct list_head *coresight_build_path(struct coresight_device *csdev);
 void coresight_release_path(struct list_head *path);
index b526396d80b60526b9a50159ef1af518dab01c54..ac91b0b40ec26374efc03e16d0c3992ced08f70b 100644 (file)
@@ -265,7 +265,7 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
        return 0;
 }
 
-static int tmc_enable_sink(struct coresight_device *csdev)
+static int tmc_enable_sink(struct coresight_device *csdev, u32 mode)
 {
        struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
index 0d8fce651ff75c588408279055014cc9d32b9728..71582f6dfd4c156a83449eae224f5dfd13e8f249 100644 (file)
@@ -70,7 +70,7 @@ static void tpiu_enable_hw(struct tpiu_drvdata *drvdata)
        CS_LOCK(drvdata->base);
 }
 
-static int tpiu_enable(struct coresight_device *csdev)
+static int tpiu_enable(struct coresight_device *csdev, u32 mode)
 {
        struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
index 95cccb179763cfa0585db25b1e5e688049a3b8a2..6ec2b66af9eec3d68203f6b424c1f9f551975d4a 100644 (file)
@@ -121,13 +121,13 @@ static int coresight_find_link_outport(struct coresight_device *csdev,
        return 0;
 }
 
-static int coresight_enable_sink(struct coresight_device *csdev)
+static int coresight_enable_sink(struct coresight_device *csdev, u32 mode)
 {
        int ret;
 
        if (!csdev->enable) {
                if (sink_ops(csdev)->enable) {
-                       ret = sink_ops(csdev)->enable(csdev);
+                       ret = sink_ops(csdev)->enable(csdev, mode);
                        if (ret)
                                return ret;
                }
@@ -283,7 +283,7 @@ void coresight_disable_path(struct list_head *path)
        }
 }
 
-int coresight_enable_path(struct list_head *path)
+int coresight_enable_path(struct list_head *path, u32 mode)
 {
 
        int ret = 0;
@@ -296,7 +296,7 @@ int coresight_enable_path(struct list_head *path)
                switch (csdev->type) {
                case CORESIGHT_DEV_TYPE_SINK:
                case CORESIGHT_DEV_TYPE_LINKSINK:
-                       ret = coresight_enable_sink(csdev);
+                       ret = coresight_enable_sink(csdev, mode);
                        if (ret)
                                goto err;
                        break;
@@ -454,7 +454,7 @@ int coresight_enable(struct coresight_device *csdev)
                goto out;
        }
 
-       ret = coresight_enable_path(path);
+       ret = coresight_enable_path(path, CS_MODE_SYSFS);
        if (ret)
                goto err_path;
 
index 6801dd64ee5d23320d06eecd847deddccbd21258..9fa92dcdd2eaf1d6d49fac9e41d1b4cca252a486 100644 (file)
@@ -186,7 +186,7 @@ struct coresight_device {
  * @disable:   disables the sink.
  */
 struct coresight_ops_sink {
-       int (*enable)(struct coresight_device *csdev);
+       int (*enable)(struct coresight_device *csdev, u32 mode);
        void (*disable)(struct coresight_device *csdev);
 };