coresight: reset "enable_sink" flag when need be
authorMathieu Poirier <mathieu.poirier@linaro.org>
Tue, 29 Nov 2016 16:47:14 +0000 (09:47 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 29 Nov 2016 19:05:32 +0000 (20:05 +0100)
When using coresight from the perf interface sinks are specified
as part of the perf command line.  As such the sink needs to be
disabled once it has been acknowledged by the coresight framework.
Otherwise the sink stays enabled, which may interfere with other
sessions.

This patch removes the sink selection check from the build path
process and make it a function on it's own.  The function is
then used when operating from sysFS or perf to determine what
sink has been selected.

If operated from perf the status of the "enable_sink" flag is
reset so that concurrent session can use a different sink.  When
used from sysFS the status of the flag is left untouched since
users have full control.

The implementation doesn't handle a scenario where a sink has
been enabled from sysFS and another sink is selected from the
perf command line as both modes of operation are mutually
exclusive.

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-etm-perf.c
drivers/hwtracing/coresight/coresight-priv.h
drivers/hwtracing/coresight/coresight.c

index 2cd7c718198a82e3a2aeecc5aed1c3a5643157d7..5a346fc8ce064413632e1fd82c871562dabb8fae 100644 (file)
@@ -202,6 +202,21 @@ static void *etm_setup_aux(int event_cpu, void **pages,
        if (!event_data)
                return NULL;
 
+       /*
+        * In theory nothing prevent tracers in a trace session from being
+        * associated with different sinks, nor having a sink per tracer.  But
+        * until we have HW with this kind of topology we need to assume tracers
+        * in a trace session are using the same sink.  Therefore go through
+        * the coresight bus and pick the first enabled sink.
+        *
+        * When operated from sysFS users are responsible to enable the sink
+        * while from perf, the perf tools will do it based on the choice made
+        * on the cmd line.  As such the "enable_sink" flag in sysFS is reset.
+        */
+       sink = coresight_get_enabled_sink(true);
+       if (!sink)
+               return NULL;
+
        INIT_WORK(&event_data->work, free_event_data);
 
        mask = &event_data->mask;
@@ -219,25 +234,11 @@ static void *etm_setup_aux(int event_cpu, void **pages,
                 * list of devices from source to sink that can be
                 * referenced later when the path is actually needed.
                 */
-               event_data->path[cpu] = coresight_build_path(csdev);
+               event_data->path[cpu] = coresight_build_path(csdev, sink);
                if (IS_ERR(event_data->path[cpu]))
                        goto err;
        }
 
-       /*
-        * In theory nothing prevent tracers in a trace session from being
-        * associated with different sinks, nor having a sink per tracer.  But
-        * until we have HW with this kind of topology and a way to convey
-        * sink assignement from the perf cmd line we need to assume tracers
-        * in a trace session are using the same sink.  Therefore pick the sink
-        * found at the end of the first available path.
-        */
-       cpu = cpumask_first(mask);
-       /* Grab the sink at the end of the path */
-       sink = coresight_get_sink(event_data->path[cpu]);
-       if (!sink)
-               goto err;
-
        if (!sink_ops(sink)->alloc_buffer)
                goto err;
 
index 196a14be4b3da95306ff0a8994e9ecdaad86162b..ef9d8e93e3b2e0b6959107b57b2689695e33604d 100644 (file)
@@ -111,7 +111,9 @@ static inline void CS_UNLOCK(void __iomem *addr)
 void coresight_disable_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);
+struct coresight_device *coresight_get_enabled_sink(bool reset);
+struct list_head *coresight_build_path(struct coresight_device *csdev,
+                                      struct coresight_device *sink);
 void coresight_release_path(struct list_head *path);
 
 #ifdef CONFIG_CORESIGHT_SOURCE_ETM3X
index 7bf00a0beb6f14b4c69cdaf619a2d981e58f612a..0c37356e417ca66131717e83f359357f092df6d3 100644 (file)
@@ -368,6 +368,52 @@ struct coresight_device *coresight_get_sink(struct list_head *path)
        return csdev;
 }
 
+static int coresight_enabled_sink(struct device *dev, void *data)
+{
+       bool *reset = data;
+       struct coresight_device *csdev = to_coresight_device(dev);
+
+       if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
+            csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
+            csdev->activated) {
+               /*
+                * Now that we have a handle on the sink for this session,
+                * disable the sysFS "enable_sink" flag so that possible
+                * concurrent perf session that wish to use another sink don't
+                * trip on it.  Doing so has no ramification for the current
+                * session.
+                */
+               if (*reset)
+                       csdev->activated = false;
+
+               return 1;
+       }
+
+       return 0;
+}
+
+/**
+ * coresight_get_enabled_sink - returns the first enabled sink found on the bus
+ * @deactivate:        Whether the 'enable_sink' flag should be reset
+ *
+ * When operated from perf the deactivate parameter should be set to 'true'.
+ * That way the "enabled_sink" flag of the sink that was selected can be reset,
+ * allowing for other concurrent perf sessions to choose a different sink.
+ *
+ * When operated from sysFS users have full control and as such the deactivate
+ * parameter should be set to 'false', hence mandating users to explicitly
+ * clear the flag.
+ */
+struct coresight_device *coresight_get_enabled_sink(bool deactivate)
+{
+       struct device *dev = NULL;
+
+       dev = bus_find_device(&coresight_bustype, NULL, &deactivate,
+                             coresight_enabled_sink);
+
+       return dev ? to_coresight_device(dev) : NULL;
+}
+
 /**
  * _coresight_build_path - recursively build a path from a @csdev to a sink.
  * @csdev:     The device to start from.
@@ -380,6 +426,7 @@ struct coresight_device *coresight_get_sink(struct list_head *path)
  * last one.
  */
 static int _coresight_build_path(struct coresight_device *csdev,
+                                struct coresight_device *sink,
                                 struct list_head *path)
 {
        int i;
@@ -387,15 +434,15 @@ static int _coresight_build_path(struct coresight_device *csdev,
        struct coresight_node *node;
 
        /* An activated sink has been found.  Enqueue the element */
-       if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
-            csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && csdev->activated)
+       if (csdev == sink)
                goto out;
 
        /* Not a sink - recursively explore each port found on this element */
        for (i = 0; i < csdev->nr_outport; i++) {
                struct coresight_device *child_dev = csdev->conns[i].child_dev;
 
-               if (child_dev && _coresight_build_path(child_dev, path) == 0) {
+               if (child_dev &&
+                   _coresight_build_path(child_dev, sink, path) == 0) {
                        found = true;
                        break;
                }
@@ -422,18 +469,22 @@ out:
        return 0;
 }
 
-struct list_head *coresight_build_path(struct coresight_device *csdev)
+struct list_head *coresight_build_path(struct coresight_device *source,
+                                      struct coresight_device *sink)
 {
        struct list_head *path;
        int rc;
 
+       if (!sink)
+               return ERR_PTR(-EINVAL);
+
        path = kzalloc(sizeof(struct list_head), GFP_KERNEL);
        if (!path)
                return ERR_PTR(-ENOMEM);
 
        INIT_LIST_HEAD(path);
 
-       rc = _coresight_build_path(csdev, path);
+       rc = _coresight_build_path(source, sink, path);
        if (rc) {
                kfree(path);
                return ERR_PTR(rc);
@@ -497,6 +548,7 @@ static int coresight_validate_source(struct coresight_device *csdev,
 int coresight_enable(struct coresight_device *csdev)
 {
        int cpu, ret = 0;
+       struct coresight_device *sink;
        struct list_head *path;
 
        mutex_lock(&coresight_mutex);
@@ -508,7 +560,17 @@ int coresight_enable(struct coresight_device *csdev)
        if (csdev->enable)
                goto out;
 
-       path = coresight_build_path(csdev);
+       /*
+        * Search for a valid sink for this session but don't reset the
+        * "enable_sink" flag in sysFS.  Users get to do that explicitly.
+        */
+       sink = coresight_get_enabled_sink(false);
+       if (!sink) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       path = coresight_build_path(csdev, sink);
        if (IS_ERR(path)) {
                pr_err("building path(s) failed\n");
                ret = PTR_ERR(path);