summaryrefslogtreecommitdiff
path: root/drivers/hwtracing/coresight/coresight-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwtracing/coresight/coresight-core.c')
-rw-r--r--drivers/hwtracing/coresight/coresight-core.c86
1 files changed, 29 insertions, 57 deletions
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 5e93b52df105..b8d6520d47c9 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -279,29 +279,18 @@ EXPORT_SYMBOL_GPL(coresight_add_helper);
static int coresight_enable_sink(struct coresight_device *csdev,
enum cs_mode mode, void *data)
{
- int ret = sink_ops(csdev)->enable(csdev, mode, data);
-
- if (ret)
- return ret;
-
- csdev->enable = true;
-
- return 0;
+ return sink_ops(csdev)->enable(csdev, mode, data);
}
static void coresight_disable_sink(struct coresight_device *csdev)
{
- int ret = sink_ops(csdev)->disable(csdev);
- if (ret)
- return;
- csdev->enable = false;
+ sink_ops(csdev)->disable(csdev);
}
static int coresight_enable_link(struct coresight_device *csdev,
struct coresight_device *parent,
struct coresight_device *child)
{
- int ret = 0;
int link_subtype;
struct coresight_connection *inconn, *outconn;
@@ -317,19 +306,13 @@ static int coresight_enable_link(struct coresight_device *csdev,
if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn))
return PTR_ERR(outconn);
- ret = link_ops(csdev)->enable(csdev, inconn, outconn);
- if (!ret)
- csdev->enable = true;
-
- return ret;
+ return link_ops(csdev)->enable(csdev, inconn, outconn);
}
static void coresight_disable_link(struct coresight_device *csdev,
struct coresight_device *parent,
struct coresight_device *child)
{
- int i;
- int link_subtype;
struct coresight_connection *inconn, *outconn;
if (!parent || !child)
@@ -337,26 +320,8 @@ static void coresight_disable_link(struct coresight_device *csdev,
inconn = coresight_find_out_connection(parent, csdev);
outconn = coresight_find_out_connection(csdev, child);
- link_subtype = csdev->subtype.link_subtype;
link_ops(csdev)->disable(csdev, inconn, outconn);
-
- if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
- for (i = 0; i < csdev->pdata->nr_inconns; i++)
- if (atomic_read(&csdev->pdata->in_conns[i]->dest_refcnt) !=
- 0)
- return;
- } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
- for (i = 0; i < csdev->pdata->nr_outconns; i++)
- if (atomic_read(&csdev->pdata->out_conns[i]->src_refcnt) !=
- 0)
- return;
- } else {
- if (atomic_read(&csdev->refcnt) != 0)
- return;
- }
-
- csdev->enable = false;
}
int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
@@ -364,11 +329,16 @@ int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
{
int ret;
- if (!csdev->enable) {
+ /*
+ * 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;
- csdev->enable = true;
}
atomic_inc(&csdev->refcnt);
@@ -385,22 +355,12 @@ static bool coresight_is_helper(struct coresight_device *csdev)
static int coresight_enable_helper(struct coresight_device *csdev,
enum cs_mode mode, void *data)
{
- int ret = helper_ops(csdev)->enable(csdev, mode, data);
-
- if (ret)
- return ret;
-
- csdev->enable = true;
- return 0;
+ return helper_ops(csdev)->enable(csdev, mode, data);
}
static void coresight_disable_helper(struct coresight_device *csdev)
{
- int ret = helper_ops(csdev)->disable(csdev, NULL);
-
- if (ret)
- return;
- csdev->enable = false;
+ helper_ops(csdev)->disable(csdev, NULL);
}
static void coresight_disable_helpers(struct coresight_device *csdev)
@@ -445,11 +405,15 @@ EXPORT_SYMBOL_GPL(coresight_disable_source);
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);
- csdev->enable = false;
+ return true;
}
- return !csdev->enable;
+ return false;
}
/*
@@ -1097,7 +1061,13 @@ int coresight_enable(struct coresight_device *csdev)
if (ret)
goto out;
- if (csdev->enable) {
+ /*
+ * 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
@@ -1183,7 +1153,7 @@ void coresight_disable(struct coresight_device *csdev)
if (ret)
goto out;
- if (!csdev->enable || !coresight_disable_source_sysfs(csdev, NULL))
+ if (!coresight_disable_source_sysfs(csdev, NULL))
goto out;
switch (csdev->subtype.source_subtype) {
@@ -1249,7 +1219,9 @@ static ssize_t enable_source_show(struct device *dev,
{
struct coresight_device *csdev = to_coresight_device(dev);
- return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->enable);
+ 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,