coresight: Move all sysfs code to sysfs file
authorJames Clark <james.clark@arm.com>
Mon, 29 Jan 2024 15:40:37 +0000 (15:40 +0000)
committerSuzuki K Poulose <suzuki.poulose@arm.com>
Mon, 12 Feb 2024 10:21:38 +0000 (10:21 +0000)
At the moment the core file contains both sysfs functionality and
core functionality, while the Perf mode is in a separate file in
coresight-etm-perf.c

Many of the functions have ambiguous names like
coresight_enable_source() which actually only work in relation to the
sysfs mode. To avoid further confusion, move everything that isn't core
functionality into the sysfs file and append  _sysfs to the ambiguous
functions.

Signed-off-by: James Clark <james.clark@arm.com>
Link: https://lore.kernel.org/r/20240129154050.569566-7-james.clark@arm.com
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
drivers/hwtracing/coresight/coresight-core.c
drivers/hwtracing/coresight/coresight-etm3x-core.c
drivers/hwtracing/coresight/coresight-etm4x-core.c
drivers/hwtracing/coresight/coresight-priv.h
drivers/hwtracing/coresight/coresight-stm.c
drivers/hwtracing/coresight/coresight-sysfs.c
include/linux/coresight.h

index b8d6520..b83613e 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/types.h>
 #include <linux/device.h>
 #include <linux/io.h>
-#include <linux/idr.h>
 #include <linux/err.h>
 #include <linux/export.h>
 #include <linux/slab.h>
 #include "coresight-priv.h"
 #include "coresight-syscfg.h"
 
-static DEFINE_MUTEX(coresight_mutex);
-static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
-
 /*
- * Use IDR to map the hash of the source's device name
- * to the pointer of path for the source. The idr is for
- * the sources which aren't associated with CPU.
+ * Mutex used to lock all sysfs enable and disable actions and loading and
+ * unloading devices by the Coresight core.
  */
-static DEFINE_IDR(path_idr);
+DEFINE_MUTEX(coresight_mutex);
+static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
 
 /**
  * struct coresight_node - elements of a path, from source to sink
@@ -45,12 +41,6 @@ struct coresight_node {
        struct list_head link;
 };
 
-/*
- * When operating Coresight drivers from the sysFS interface, only a single
- * path can exist from a tracer (associated to a CPU) to a sink.
- */
-static DEFINE_PER_CPU(struct list_head *, tracer_path);
-
 /*
  * When losing synchronisation a new barrier packet needs to be inserted at the
  * beginning of the data collected in a buffer.  That way the decoder knows that
@@ -61,34 +51,6 @@ EXPORT_SYMBOL_GPL(coresight_barrier_pkt);
 
 static const struct cti_assoc_op *cti_assoc_ops;
 
-ssize_t coresight_simple_show_pair(struct device *_dev,
-                             struct device_attribute *attr, char *buf)
-{
-       struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
-       struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr);
-       u64 val;
-
-       pm_runtime_get_sync(_dev->parent);
-       val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off);
-       pm_runtime_put_sync(_dev->parent);
-       return sysfs_emit(buf, "0x%llx\n", val);
-}
-EXPORT_SYMBOL_GPL(coresight_simple_show_pair);
-
-ssize_t coresight_simple_show32(struct device *_dev,
-                             struct device_attribute *attr, char *buf)
-{
-       struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
-       struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr);
-       u64 val;
-
-       pm_runtime_get_sync(_dev->parent);
-       val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off);
-       pm_runtime_put_sync(_dev->parent);
-       return sysfs_emit(buf, "0x%llx\n", val);
-}
-EXPORT_SYMBOL_GPL(coresight_simple_show32);
-
 void coresight_set_cti_ops(const struct cti_assoc_op *cti_op)
 {
        cti_assoc_ops = cti_op;
@@ -324,29 +286,6 @@ static void coresight_disable_link(struct coresight_device *csdev,
        link_ops(csdev)->disable(csdev, inconn, outconn);
 }
 
-int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
-                           void *data)
-{
-       int ret;
-
-       /*
-        * Comparison with CS_MODE_SYSFS works without taking any device
-        * specific spinlock because the truthyness of that comparison can only
-        * change with coresight_mutex held, which we already have here.
-        */
-       lockdep_assert_held(&coresight_mutex);
-       if (local_read(&csdev->mode) != CS_MODE_SYSFS) {
-               ret = source_ops(csdev)->enable(csdev, data, mode);
-               if (ret)
-                       return ret;
-       }
-
-       atomic_inc(&csdev->refcnt);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(coresight_enable_source);
-
 static bool coresight_is_helper(struct coresight_device *csdev)
 {
        return csdev->type == CORESIGHT_DEV_TYPE_HELPER;
@@ -392,30 +331,6 @@ void coresight_disable_source(struct coresight_device *csdev, void *data)
 }
 EXPORT_SYMBOL_GPL(coresight_disable_source);
 
-/**
- *  coresight_disable_source_sysfs - Drop the reference count by 1 and disable
- *  the device if there are no users left.
- *
- *  @csdev: The coresight device to disable
- *  @data: Opaque data to pass on to the disable function of the source device.
- *         For example in perf mode this is a pointer to the struct perf_event.
- *
- *  Returns true if the device has been disabled.
- */
-static bool coresight_disable_source_sysfs(struct coresight_device *csdev,
-                                          void *data)
-{
-       lockdep_assert_held(&coresight_mutex);
-       if (local_read(&csdev->mode) != CS_MODE_SYSFS)
-               return false;
-
-       if (atomic_dec_return(&csdev->refcnt) == 0) {
-               coresight_disable_source(csdev, data);
-               return true;
-       }
-       return false;
-}
-
 /*
  * coresight_disable_path_from : Disable components in the given path beyond
  * @nd in the list. If @nd is NULL, all the components, except the SOURCE are
@@ -572,39 +487,6 @@ struct coresight_device *coresight_get_sink(struct list_head *path)
        return csdev;
 }
 
-/**
- * coresight_find_activated_sysfs_sink - returns the first sink activated via
- * sysfs using connection based search starting from the source reference.
- *
- * @csdev: Coresight source device reference
- */
-static struct coresight_device *
-coresight_find_activated_sysfs_sink(struct coresight_device *csdev)
-{
-       int i;
-       struct coresight_device *sink = NULL;
-
-       if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
-            csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
-            csdev->sysfs_sink_activated)
-               return csdev;
-
-       /*
-        * Recursively explore each port found on this element.
-        */
-       for (i = 0; i < csdev->pdata->nr_outconns; i++) {
-               struct coresight_device *child_dev;
-
-               child_dev = csdev->pdata->out_conns[i]->dest_dev;
-               if (child_dev)
-                       sink = coresight_find_activated_sysfs_sink(child_dev);
-               if (sink)
-                       return sink;
-       }
-
-       return NULL;
-}
-
 static int coresight_sink_by_id(struct device *dev, const void *data)
 {
        struct coresight_device *csdev = to_coresight_device(dev);
@@ -1015,274 +897,6 @@ static void coresight_clear_default_sink(struct coresight_device *csdev)
        }
 }
 
-/** coresight_validate_source - make sure a source has the right credentials
- *  @csdev:    the device structure for a source.
- *  @function: the function this was called from.
- *
- * Assumes the coresight_mutex is held.
- */
-static int coresight_validate_source(struct coresight_device *csdev,
-                                    const char *function)
-{
-       u32 type, subtype;
-
-       type = csdev->type;
-       subtype = csdev->subtype.source_subtype;
-
-       if (type != CORESIGHT_DEV_TYPE_SOURCE) {
-               dev_err(&csdev->dev, "wrong device type in %s\n", function);
-               return -EINVAL;
-       }
-
-       if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC &&
-           subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE &&
-           subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM &&
-           subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) {
-               dev_err(&csdev->dev, "wrong device subtype in %s\n", function);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-int coresight_enable(struct coresight_device *csdev)
-{
-       int cpu, ret = 0;
-       struct coresight_device *sink;
-       struct list_head *path;
-       enum coresight_dev_subtype_source subtype;
-       u32 hash;
-
-       subtype = csdev->subtype.source_subtype;
-
-       mutex_lock(&coresight_mutex);
-
-       ret = coresight_validate_source(csdev, __func__);
-       if (ret)
-               goto out;
-
-       /*
-        * mode == SYSFS implies that it's already enabled. Don't look at the
-        * refcount to determine this because we don't claim the source until
-        * coresight_enable_source() so can still race with Perf mode which
-        * doesn't hold coresight_mutex.
-        */
-       if (local_read(&csdev->mode) == CS_MODE_SYSFS) {
-               /*
-                * There could be multiple applications driving the software
-                * source. So keep the refcount for each such user when the
-                * source is already enabled.
-                */
-               if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
-                       atomic_inc(&csdev->refcnt);
-               goto out;
-       }
-
-       sink = coresight_find_activated_sysfs_sink(csdev);
-       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);
-               goto out;
-       }
-
-       ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
-       if (ret)
-               goto err_path;
-
-       ret = coresight_enable_source(csdev, CS_MODE_SYSFS, NULL);
-       if (ret)
-               goto err_source;
-
-       switch (subtype) {
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
-               /*
-                * When working from sysFS it is important to keep track
-                * of the paths that were created so that they can be
-                * undone in 'coresight_disable()'.  Since there can only
-                * be a single session per tracer (when working from sysFS)
-                * a per-cpu variable will do just fine.
-                */
-               cpu = source_ops(csdev)->cpu_id(csdev);
-               per_cpu(tracer_path, cpu) = path;
-               break;
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
-               /*
-                * Use the hash of source's device name as ID
-                * and map the ID to the pointer of the path.
-                */
-               hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
-               ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL);
-               if (ret)
-                       goto err_source;
-               break;
-       default:
-               /* We can't be here */
-               break;
-       }
-
-out:
-       mutex_unlock(&coresight_mutex);
-       return ret;
-
-err_source:
-       coresight_disable_path(path);
-
-err_path:
-       coresight_release_path(path);
-       goto out;
-}
-EXPORT_SYMBOL_GPL(coresight_enable);
-
-void coresight_disable(struct coresight_device *csdev)
-{
-       int cpu, ret;
-       struct list_head *path = NULL;
-       u32 hash;
-
-       mutex_lock(&coresight_mutex);
-
-       ret = coresight_validate_source(csdev, __func__);
-       if (ret)
-               goto out;
-
-       if (!coresight_disable_source_sysfs(csdev, NULL))
-               goto out;
-
-       switch (csdev->subtype.source_subtype) {
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
-               cpu = source_ops(csdev)->cpu_id(csdev);
-               path = per_cpu(tracer_path, cpu);
-               per_cpu(tracer_path, cpu) = NULL;
-               break;
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
-               hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
-               /* Find the path by the hash. */
-               path = idr_find(&path_idr, hash);
-               if (path == NULL) {
-                       pr_err("Path is not found for %s\n", dev_name(&csdev->dev));
-                       goto out;
-               }
-               idr_remove(&path_idr, hash);
-               break;
-       default:
-               /* We can't be here */
-               break;
-       }
-
-       coresight_disable_path(path);
-       coresight_release_path(path);
-
-out:
-       mutex_unlock(&coresight_mutex);
-}
-EXPORT_SYMBOL_GPL(coresight_disable);
-
-static ssize_t enable_sink_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct coresight_device *csdev = to_coresight_device(dev);
-
-       return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->sysfs_sink_activated);
-}
-
-static ssize_t enable_sink_store(struct device *dev,
-                                struct device_attribute *attr,
-                                const char *buf, size_t size)
-{
-       int ret;
-       unsigned long val;
-       struct coresight_device *csdev = to_coresight_device(dev);
-
-       ret = kstrtoul(buf, 10, &val);
-       if (ret)
-               return ret;
-
-       csdev->sysfs_sink_activated = !!val;
-
-       return size;
-
-}
-static DEVICE_ATTR_RW(enable_sink);
-
-static ssize_t enable_source_show(struct device *dev,
-                                 struct device_attribute *attr, char *buf)
-{
-       struct coresight_device *csdev = to_coresight_device(dev);
-
-       guard(mutex)(&coresight_mutex);
-       return scnprintf(buf, PAGE_SIZE, "%u\n",
-                        local_read(&csdev->mode) == CS_MODE_SYSFS);
-}
-
-static ssize_t enable_source_store(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t size)
-{
-       int ret = 0;
-       unsigned long val;
-       struct coresight_device *csdev = to_coresight_device(dev);
-
-       ret = kstrtoul(buf, 10, &val);
-       if (ret)
-               return ret;
-
-       if (val) {
-               ret = coresight_enable(csdev);
-               if (ret)
-                       return ret;
-       } else {
-               coresight_disable(csdev);
-       }
-
-       return size;
-}
-static DEVICE_ATTR_RW(enable_source);
-
-static struct attribute *coresight_sink_attrs[] = {
-       &dev_attr_enable_sink.attr,
-       NULL,
-};
-ATTRIBUTE_GROUPS(coresight_sink);
-
-static struct attribute *coresight_source_attrs[] = {
-       &dev_attr_enable_source.attr,
-       NULL,
-};
-ATTRIBUTE_GROUPS(coresight_source);
-
-static struct device_type coresight_dev_type[] = {
-       {
-               .name = "sink",
-               .groups = coresight_sink_groups,
-       },
-       {
-               .name = "link",
-       },
-       {
-               .name = "linksink",
-               .groups = coresight_sink_groups,
-       },
-       {
-               .name = "source",
-               .groups = coresight_source_groups,
-       },
-       {
-               .name = "helper",
-       }
-};
-/* Ensure the enum matches the names and groups */
-static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX);
-
 static void coresight_device_release(struct device *dev)
 {
        struct coresight_device *csdev = to_coresight_device(dev);
index 333d0a3..de53c3e 100644 (file)
@@ -714,7 +714,7 @@ static int etm_online_cpu(unsigned int cpu)
                return 0;
 
        if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable)
-               coresight_enable(etmdrvdata[cpu]->csdev);
+               coresight_enable_sysfs(etmdrvdata[cpu]->csdev);
        return 0;
 }
 
@@ -924,7 +924,7 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
        dev_info(&drvdata->csdev->dev,
                 "%s initialized\n", (char *)coresight_get_uci_data(id));
        if (boot_enable) {
-               coresight_enable(drvdata->csdev);
+               coresight_enable_sysfs(drvdata->csdev);
                drvdata->boot_enable = true;
        }
 
index 7ceff62..1c64b54 100644 (file)
@@ -1648,7 +1648,7 @@ static int etm4_online_cpu(unsigned int cpu)
                return etm4_probe_cpu(cpu);
 
        if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable)
-               coresight_enable(etmdrvdata[cpu]->csdev);
+               coresight_enable_sysfs(etmdrvdata[cpu]->csdev);
        return 0;
 }
 
@@ -2096,7 +2096,7 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
                 drvdata->cpu, type_name, major, minor);
 
        if (boot_enable) {
-               coresight_enable(drvdata->csdev);
+               coresight_enable_sysfs(drvdata->csdev);
                drvdata->boot_enable = true;
        }
 
index ced5be0..eb36523 100644 (file)
@@ -12,6 +12,9 @@
 #include <linux/coresight.h>
 #include <linux/pm_runtime.h>
 
+extern struct mutex coresight_mutex;
+extern struct device_type coresight_dev_type[];
+
 /*
  * Coresight management registers (0xf00-0xfcc)
  * 0xfa0 - 0xfa4: Management   registers in PFTv1.0
@@ -229,8 +232,6 @@ void coresight_add_helper(struct coresight_device *csdev,
 
 void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev);
 struct coresight_device *coresight_get_percpu_sink(int cpu);
-int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
-                           void *data);
 void coresight_disable_source(struct coresight_device *csdev, void *data);
 
 #endif
index f7fc645..b2ccbe9 100644 (file)
@@ -332,7 +332,7 @@ static int stm_generic_link(struct stm_data *stm_data,
        if (!drvdata || !drvdata->csdev)
                return -EINVAL;
 
-       return coresight_enable(drvdata->csdev);
+       return coresight_enable_sysfs(drvdata->csdev);
 }
 
 static void stm_generic_unlink(struct stm_data *stm_data,
@@ -343,7 +343,7 @@ static void stm_generic_unlink(struct stm_data *stm_data,
        if (!drvdata || !drvdata->csdev)
                return;
 
-       coresight_disable(drvdata->csdev);
+       coresight_disable_sysfs(drvdata->csdev);
 }
 
 static phys_addr_t
index dd78e9f..92cdf81 100644 (file)
  */
 
 #include <linux/device.h>
+#include <linux/idr.h>
 #include <linux/kernel.h>
 
 #include "coresight-priv.h"
 
+/*
+ * Use IDR to map the hash of the source's device name
+ * to the pointer of path for the source. The idr is for
+ * the sources which aren't associated with CPU.
+ */
+static DEFINE_IDR(path_idr);
+
+/*
+ * When operating Coresight drivers from the sysFS interface, only a single
+ * path can exist from a tracer (associated to a CPU) to a sink.
+ */
+static DEFINE_PER_CPU(struct list_head *, tracer_path);
+
+ssize_t coresight_simple_show_pair(struct device *_dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
+       struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr);
+       u64 val;
+
+       pm_runtime_get_sync(_dev->parent);
+       val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off);
+       pm_runtime_put_sync(_dev->parent);
+       return sysfs_emit(buf, "0x%llx\n", val);
+}
+EXPORT_SYMBOL_GPL(coresight_simple_show_pair);
+
+ssize_t coresight_simple_show32(struct device *_dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
+       struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr);
+       u64 val;
+
+       pm_runtime_get_sync(_dev->parent);
+       val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off);
+       pm_runtime_put_sync(_dev->parent);
+       return sysfs_emit(buf, "0x%llx\n", val);
+}
+EXPORT_SYMBOL_GPL(coresight_simple_show32);
+
+static int coresight_enable_source_sysfs(struct coresight_device *csdev,
+                                        enum cs_mode mode, void *data)
+{
+       int ret;
+
+       /*
+        * Comparison with CS_MODE_SYSFS works without taking any device
+        * specific spinlock because the truthyness of that comparison can only
+        * change with coresight_mutex held, which we already have here.
+        */
+       lockdep_assert_held(&coresight_mutex);
+       if (local_read(&csdev->mode) != CS_MODE_SYSFS) {
+               ret = source_ops(csdev)->enable(csdev, data, mode);
+               if (ret)
+                       return ret;
+       }
+
+       atomic_inc(&csdev->refcnt);
+
+       return 0;
+}
+
+/**
+ *  coresight_disable_source_sysfs - Drop the reference count by 1 and disable
+ *  the device if there are no users left.
+ *
+ *  @csdev: The coresight device to disable
+ *  @data: Opaque data to pass on to the disable function of the source device.
+ *         For example in perf mode this is a pointer to the struct perf_event.
+ *
+ *  Returns true if the device has been disabled.
+ */
+static bool coresight_disable_source_sysfs(struct coresight_device *csdev,
+                                          void *data)
+{
+       lockdep_assert_held(&coresight_mutex);
+       if (local_read(&csdev->mode) != CS_MODE_SYSFS)
+               return false;
+
+       if (atomic_dec_return(&csdev->refcnt) == 0) {
+               coresight_disable_source(csdev, data);
+               return true;
+       }
+       return false;
+}
+
+/**
+ * coresight_find_activated_sysfs_sink - returns the first sink activated via
+ * sysfs using connection based search starting from the source reference.
+ *
+ * @csdev: Coresight source device reference
+ */
+static struct coresight_device *
+coresight_find_activated_sysfs_sink(struct coresight_device *csdev)
+{
+       int i;
+       struct coresight_device *sink = NULL;
+
+       if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
+            csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
+            csdev->sysfs_sink_activated)
+               return csdev;
+
+       /*
+        * Recursively explore each port found on this element.
+        */
+       for (i = 0; i < csdev->pdata->nr_outconns; i++) {
+               struct coresight_device *child_dev;
+
+               child_dev = csdev->pdata->out_conns[i]->dest_dev;
+               if (child_dev)
+                       sink = coresight_find_activated_sysfs_sink(child_dev);
+               if (sink)
+                       return sink;
+       }
+
+       return NULL;
+}
+
+/** coresight_validate_source - make sure a source has the right credentials to
+ *  be used via sysfs.
+ *  @csdev:    the device structure for a source.
+ *  @function: the function this was called from.
+ *
+ * Assumes the coresight_mutex is held.
+ */
+static int coresight_validate_source_sysfs(struct coresight_device *csdev,
+                                    const char *function)
+{
+       u32 type, subtype;
+
+       type = csdev->type;
+       subtype = csdev->subtype.source_subtype;
+
+       if (type != CORESIGHT_DEV_TYPE_SOURCE) {
+               dev_err(&csdev->dev, "wrong device type in %s\n", function);
+               return -EINVAL;
+       }
+
+       if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC &&
+           subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE &&
+           subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM &&
+           subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) {
+               dev_err(&csdev->dev, "wrong device subtype in %s\n", function);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int coresight_enable_sysfs(struct coresight_device *csdev)
+{
+       int cpu, ret = 0;
+       struct coresight_device *sink;
+       struct list_head *path;
+       enum coresight_dev_subtype_source subtype;
+       u32 hash;
+
+       subtype = csdev->subtype.source_subtype;
+
+       mutex_lock(&coresight_mutex);
+
+       ret = coresight_validate_source_sysfs(csdev, __func__);
+       if (ret)
+               goto out;
+
+       /*
+        * mode == SYSFS implies that it's already enabled. Don't look at the
+        * refcount to determine this because we don't claim the source until
+        * coresight_enable_source() so can still race with Perf mode which
+        * doesn't hold coresight_mutex.
+        */
+       if (local_read(&csdev->mode) == CS_MODE_SYSFS) {
+               /*
+                * There could be multiple applications driving the software
+                * source. So keep the refcount for each such user when the
+                * source is already enabled.
+                */
+               if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
+                       atomic_inc(&csdev->refcnt);
+               goto out;
+       }
+
+       sink = coresight_find_activated_sysfs_sink(csdev);
+       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);
+               goto out;
+       }
+
+       ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
+       if (ret)
+               goto err_path;
+
+       ret = coresight_enable_source_sysfs(csdev, CS_MODE_SYSFS, NULL);
+       if (ret)
+               goto err_source;
+
+       switch (subtype) {
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
+               /*
+                * When working from sysFS it is important to keep track
+                * of the paths that were created so that they can be
+                * undone in 'coresight_disable()'.  Since there can only
+                * be a single session per tracer (when working from sysFS)
+                * a per-cpu variable will do just fine.
+                */
+               cpu = source_ops(csdev)->cpu_id(csdev);
+               per_cpu(tracer_path, cpu) = path;
+               break;
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
+               /*
+                * Use the hash of source's device name as ID
+                * and map the ID to the pointer of the path.
+                */
+               hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
+               ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL);
+               if (ret)
+                       goto err_source;
+               break;
+       default:
+               /* We can't be here */
+               break;
+       }
+
+out:
+       mutex_unlock(&coresight_mutex);
+       return ret;
+
+err_source:
+       coresight_disable_path(path);
+
+err_path:
+       coresight_release_path(path);
+       goto out;
+}
+EXPORT_SYMBOL_GPL(coresight_enable_sysfs);
+
+void coresight_disable_sysfs(struct coresight_device *csdev)
+{
+       int cpu, ret;
+       struct list_head *path = NULL;
+       u32 hash;
+
+       mutex_lock(&coresight_mutex);
+
+       ret = coresight_validate_source_sysfs(csdev, __func__);
+       if (ret)
+               goto out;
+
+       if (!coresight_disable_source_sysfs(csdev, NULL))
+               goto out;
+
+       switch (csdev->subtype.source_subtype) {
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
+               cpu = source_ops(csdev)->cpu_id(csdev);
+               path = per_cpu(tracer_path, cpu);
+               per_cpu(tracer_path, cpu) = NULL;
+               break;
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
+               hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
+               /* Find the path by the hash. */
+               path = idr_find(&path_idr, hash);
+               if (path == NULL) {
+                       pr_err("Path is not found for %s\n", dev_name(&csdev->dev));
+                       goto out;
+               }
+               idr_remove(&path_idr, hash);
+               break;
+       default:
+               /* We can't be here */
+               break;
+       }
+
+       coresight_disable_path(path);
+       coresight_release_path(path);
+
+out:
+       mutex_unlock(&coresight_mutex);
+}
+EXPORT_SYMBOL_GPL(coresight_disable_sysfs);
+
+static ssize_t enable_sink_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct coresight_device *csdev = to_coresight_device(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->sysfs_sink_activated);
+}
+
+static ssize_t enable_sink_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t size)
+{
+       int ret;
+       unsigned long val;
+       struct coresight_device *csdev = to_coresight_device(dev);
+
+       ret = kstrtoul(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       csdev->sysfs_sink_activated = !!val;
+
+       return size;
+
+}
+static DEVICE_ATTR_RW(enable_sink);
+
+static ssize_t enable_source_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct coresight_device *csdev = to_coresight_device(dev);
+
+       guard(mutex)(&coresight_mutex);
+       return scnprintf(buf, PAGE_SIZE, "%u\n",
+                        local_read(&csdev->mode) == CS_MODE_SYSFS);
+}
+
+static ssize_t enable_source_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t size)
+{
+       int ret = 0;
+       unsigned long val;
+       struct coresight_device *csdev = to_coresight_device(dev);
+
+       ret = kstrtoul(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       if (val) {
+               ret = coresight_enable_sysfs(csdev);
+               if (ret)
+                       return ret;
+       } else {
+               coresight_disable_sysfs(csdev);
+       }
+
+       return size;
+}
+static DEVICE_ATTR_RW(enable_source);
+
+static struct attribute *coresight_sink_attrs[] = {
+       &dev_attr_enable_sink.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(coresight_sink);
+
+static struct attribute *coresight_source_attrs[] = {
+       &dev_attr_enable_source.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(coresight_source);
+
+struct device_type coresight_dev_type[] = {
+       {
+               .name = "sink",
+               .groups = coresight_sink_groups,
+       },
+       {
+               .name = "link",
+       },
+       {
+               .name = "linksink",
+               .groups = coresight_sink_groups,
+       },
+       {
+               .name = "source",
+               .groups = coresight_source_groups,
+       },
+       {
+               .name = "helper",
+       }
+};
+/* Ensure the enum matches the names and groups */
+static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX);
+
 /*
  * Connections group - links attribute.
  * Count of created links between coresight components in the group.
index d1fd707..365b280 100644 (file)
@@ -578,8 +578,8 @@ static inline bool coresight_is_percpu_sink(struct coresight_device *csdev)
 extern struct coresight_device *
 coresight_register(struct coresight_desc *desc);
 extern void coresight_unregister(struct coresight_device *csdev);
-extern int coresight_enable(struct coresight_device *csdev);
-extern void coresight_disable(struct coresight_device *csdev);
+extern int coresight_enable_sysfs(struct coresight_device *csdev);
+extern void coresight_disable_sysfs(struct coresight_device *csdev);
 extern int coresight_timeout(struct csdev_access *csa, u32 offset,
                             int position, int value);
 
@@ -609,8 +609,8 @@ static inline struct coresight_device *
 coresight_register(struct coresight_desc *desc) { return NULL; }
 static inline void coresight_unregister(struct coresight_device *csdev) {}
 static inline int
-coresight_enable(struct coresight_device *csdev) { return -ENOSYS; }
-static inline void coresight_disable(struct coresight_device *csdev) {}
+coresight_enable_sysfs(struct coresight_device *csdev) { return -ENOSYS; }
+static inline void coresight_disable_sysfs(struct coresight_device *csdev) {}
 
 static inline int coresight_timeout(struct csdev_access *csa, u32 offset,
                                    int position, int value)