coresight: Move all sysfs code to sysfs file

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>
This commit is contained in:
James Clark 2024-01-29 15:40:37 +00:00 committed by Suzuki K Poulose
parent d5e83f97eb
commit 1f5149c775
7 changed files with 407 additions and 402 deletions

View 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>
@ -25,15 +24,12 @@
#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);

View 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;
}

View 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;
}

View 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

View 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

View File

@ -5,10 +5,400 @@
*/
#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.

View 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)