coresight: etm3x: adding operation mode for etm_enable()
authorMathieu Poirier <mathieu.poirier@linaro.org>
Thu, 18 Feb 2016 00:51:52 +0000 (17:51 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 20 Feb 2016 22:11:01 +0000 (14:11 -0800)
Adding a new mode to source API enable() in order to
distinguish where the request comes from.  That way it is
possible to perform different operations based on where
the request was issued from.

The ETM4x driver is also modified to keep in sync with the
new interface.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/hwtracing/coresight/coresight-etm.h
drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
drivers/hwtracing/coresight/coresight-etm3x.c
drivers/hwtracing/coresight/coresight-etm4x.c
drivers/hwtracing/coresight/coresight-priv.h
drivers/hwtracing/coresight/coresight.c
include/linux/coresight.h

index 371fb7d2e829c14d649219ae37be226e4165cab2..5b29d5540fe58a075e7018610ddbf1530b5d5242 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef _CORESIGHT_CORESIGHT_ETM_H
 #define _CORESIGHT_CORESIGHT_ETM_H
 
+#include <asm/local.h>
 #include <linux/spinlock.h>
 #include "coresight-priv.h"
 
@@ -214,7 +215,7 @@ struct etm_config {
  * @port_size: port size as reported by ETMCR bit 4-6 and 21.
  * @arch:      ETM/PTM version number.
  * @use_cpu14: true if management registers need to be accessed via CP14.
- * @enable:    is this ETM/PTM currently tracing.
+ * @mode:      this tracer's mode, i.e sysFS, Perf or disabled.
  * @sticky_enable: true if ETM base configuration has been done.
  * @boot_enable:true if we should start tracing at boot time.
  * @os_unlock: true if access to management registers is allowed.
@@ -238,7 +239,7 @@ struct etm_drvdata {
        int                             port_size;
        u8                              arch;
        bool                            use_cp14;
-       bool                            enable;
+       local_t                         mode;
        bool                            sticky_enable;
        bool                            boot_enable;
        bool                            os_unlock;
index 456df2378a6f2278f4eb5b225db8a5aec87ec6db..387c79fd9d5ec93eadc5ecebb368799eb7ac7264 100644 (file)
@@ -716,7 +716,7 @@ static ssize_t cntr_val_show(struct device *dev,
        struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
        struct etm_config *config = &drvdata->config;
 
-       if (!drvdata->enable) {
+       if (!local_read(&drvdata->mode)) {
                spin_lock(&drvdata->spinlock);
                for (i = 0; i < drvdata->nr_cntr; i++)
                        ret += sprintf(buf, "counter %d: %x\n",
@@ -935,7 +935,7 @@ static ssize_t seq_curr_state_show(struct device *dev,
        struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
        struct etm_config *config = &drvdata->config;
 
-       if (!drvdata->enable) {
+       if (!local_read(&drvdata->mode)) {
                val = config->seq_curr_state;
                goto out;
        }
index 1952dc31fee41c154299ec03ae2f6c95cb632c15..e16501b41ed851ec97760f39dd0a832b59ce65b6 100644 (file)
@@ -306,7 +306,7 @@ int etm_get_trace_id(struct etm_drvdata *drvdata)
        if (!drvdata)
                goto out;
 
-       if (!drvdata->enable)
+       if (!local_read(&drvdata->mode))
                return drvdata->traceid;
 
        pm_runtime_get_sync(drvdata->dev);
@@ -332,7 +332,7 @@ static int etm_trace_id(struct coresight_device *csdev)
        return etm_get_trace_id(drvdata);
 }
 
-static int etm_enable(struct coresight_device *csdev)
+static int etm_enable_sysfs(struct coresight_device *csdev)
 {
        struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
        int ret;
@@ -351,18 +351,44 @@ static int etm_enable(struct coresight_device *csdev)
                        goto err;
        }
 
-       drvdata->enable = true;
        drvdata->sticky_enable = true;
-
        spin_unlock(&drvdata->spinlock);
 
        dev_info(drvdata->dev, "ETM tracing enabled\n");
        return 0;
+
 err:
        spin_unlock(&drvdata->spinlock);
        return ret;
 }
 
+static int etm_enable(struct coresight_device *csdev, u32 mode)
+{
+       int ret;
+       u32 val;
+       struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+       val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode);
+
+       /* Someone is already using the tracer */
+       if (val)
+               return -EBUSY;
+
+       switch (mode) {
+       case CS_MODE_SYSFS:
+               ret = etm_enable_sysfs(csdev);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       /* The tracer didn't start */
+       if (ret)
+               local_set(&drvdata->mode, CS_MODE_DISABLED);
+
+       return ret;
+}
+
 static void etm_disable_hw(void *info)
 {
        int i;
@@ -387,7 +413,7 @@ static void etm_disable_hw(void *info)
        dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
 }
 
-static void etm_disable(struct coresight_device *csdev)
+static void etm_disable_sysfs(struct coresight_device *csdev)
 {
        struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
@@ -405,7 +431,6 @@ static void etm_disable(struct coresight_device *csdev)
         * ensures that register writes occur when cpu is powered.
         */
        smp_call_function_single(drvdata->cpu, etm_disable_hw, drvdata, 1);
-       drvdata->enable = false;
 
        spin_unlock(&drvdata->spinlock);
        put_online_cpus();
@@ -413,6 +438,33 @@ static void etm_disable(struct coresight_device *csdev)
        dev_info(drvdata->dev, "ETM tracing disabled\n");
 }
 
+static void etm_disable(struct coresight_device *csdev)
+{
+       u32 mode;
+       struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+       /*
+        * For as long as the tracer isn't disabled another entity can't
+        * change its status.  As such we can read the status here without
+        * fearing it will change under us.
+        */
+       mode = local_read(&drvdata->mode);
+
+       switch (mode) {
+       case CS_MODE_DISABLED:
+               break;
+       case CS_MODE_SYSFS:
+               etm_disable_sysfs(csdev);
+               break;
+       default:
+               WARN_ON_ONCE(mode);
+               return;
+       }
+
+       if (mode)
+               local_set(&drvdata->mode, CS_MODE_DISABLED);
+}
+
 static const struct coresight_ops_source etm_source_ops = {
        .cpu_id         = etm_cpu_id,
        .trace_id       = etm_trace_id,
@@ -440,7 +492,7 @@ static int etm_cpu_callback(struct notifier_block *nfb, unsigned long action,
                        etmdrvdata[cpu]->os_unlock = true;
                }
 
-               if (etmdrvdata[cpu]->enable)
+               if (local_read(&etmdrvdata[cpu]->mode))
                        etm_enable_hw(etmdrvdata[cpu]);
                spin_unlock(&etmdrvdata[cpu]->spinlock);
                break;
@@ -453,7 +505,7 @@ static int etm_cpu_callback(struct notifier_block *nfb, unsigned long action,
 
        case CPU_DYING:
                spin_lock(&etmdrvdata[cpu]->spinlock);
-               if (etmdrvdata[cpu]->enable)
+               if (local_read(&etmdrvdata[cpu]->mode))
                        etm_disable_hw(etmdrvdata[cpu]);
                spin_unlock(&etmdrvdata[cpu]->spinlock);
                break;
index c2f518fbc9a8a9c1489e30a8d2eac354fabfe648..0026092fec7f0c50272b8add086c0809faa9266f 100644 (file)
@@ -187,7 +187,7 @@ static void etm4_enable_hw(void *info)
        dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
 }
 
-static int etm4_enable(struct coresight_device *csdev)
+static int etm4_enable(struct coresight_device *csdev, u32 mode)
 {
        struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
        int ret;
index 14f245a2018d69b8af738630e3aab469ec1df55f..ed116b303e87afeb426491722bff8508a77c00a7 100644 (file)
 #define TIMEOUT_US             100
 #define BMVAL(val, lsb, msb)   ((val & GENMASK(msb, lsb)) >> lsb)
 
+enum cs_mode {
+       CS_MODE_DISABLED,
+       CS_MODE_SYSFS,
+       CS_MODE_PERF,
+};
+
 static inline void CS_LOCK(void __iomem *addr)
 {
        do {
index 6b44928c10764d7b8ebeb19ff57496d7e02bdbb6..b20afb7091413b9f6655256ab56d22d20e9b9ae4 100644 (file)
@@ -222,7 +222,7 @@ static void coresight_disable_link(struct coresight_device *csdev,
        csdev->enable = false;
 }
 
-static int coresight_enable_source(struct coresight_device *csdev)
+static int coresight_enable_source(struct coresight_device *csdev, u32 mode)
 {
        int ret;
 
@@ -234,7 +234,7 @@ static int coresight_enable_source(struct coresight_device *csdev)
 
        if (!csdev->enable) {
                if (source_ops(csdev)->enable) {
-                       ret = source_ops(csdev)->enable(csdev);
+                       ret = source_ops(csdev)->enable(csdev, mode);
                        if (ret)
                                return ret;
                }
@@ -458,7 +458,7 @@ int coresight_enable(struct coresight_device *csdev)
        if (ret)
                goto err_path;
 
-       ret = coresight_enable_source(csdev);
+       ret = coresight_enable_source(csdev, CS_MODE_SYSFS);
        if (ret)
                goto err_source;
 
index 851ecb22397e01033101d61209de94dffc29ecd1..61dfb8d511eaf0ec1bc2f4cbf56c666c2710d0e8 100644 (file)
@@ -213,7 +213,7 @@ struct coresight_ops_link {
 struct coresight_ops_source {
        int (*cpu_id)(struct coresight_device *csdev);
        int (*trace_id)(struct coresight_device *csdev);
-       int (*enable)(struct coresight_device *csdev);
+       int (*enable)(struct coresight_device *csdev, u32 mode);
        void (*disable)(struct coresight_device *csdev);
 };