summaryrefslogtreecommitdiff
path: root/drivers/hwtracing/coresight/coresight-core.c
diff options
context:
space:
mode:
authorJames Clark <james.clark@arm.com>2023-04-25 17:35:39 +0300
committerSuzuki K Poulose <suzuki.poulose@arm.com>2023-06-05 17:46:47 +0300
commit6148652807ba89b0c9af05ebed3e005b626f90eb (patch)
treeb8455beca23f4c1ecbfb8535e7c98480fc8c1147 /drivers/hwtracing/coresight/coresight-core.c
parent296b01fd106e787d4463974a7f42d286a5df08cd (diff)
downloadlinux-6148652807ba89b0c9af05ebed3e005b626f90eb.tar.xz
coresight: Enable and disable helper devices adjacent to the path
Currently CATU is the only helper device, and its enable and disable calls are hard coded. To allow more helper devices to be added in a generic way, remove these hard coded calls and just enable and disable all helper devices. This has to apply to helpers adjacent to the path, because they will never be in the path. CATU was already discovered in this way, so there is no change there. One change that is needed is for CATU to call back into ETR to allocate the buffer. Because the enable call was previously hard coded, it was done at a point where the buffer was already allocated, but this is no longer the case. Reviewed-by: Mike Leach <mike.leach@linaro.org> Signed-off-by: James Clark <james.clark@arm.com> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> Link: https://lore.kernel.org/r/20230425143542.2305069-13-james.clark@arm.com
Diffstat (limited to 'drivers/hwtracing/coresight/coresight-core.c')
-rw-r--r--drivers/hwtracing/coresight/coresight-core.c161
1 files changed, 150 insertions, 11 deletions
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 939b7fb751b5..1e9a596a15bc 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -403,8 +403,8 @@ static void coresight_disable_link(struct coresight_device *csdev,
csdev->enable = false;
}
-static int coresight_enable_source(struct coresight_device *csdev,
- enum cs_mode mode)
+int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
+ void *data)
{
int ret;
@@ -413,7 +413,7 @@ static int coresight_enable_source(struct coresight_device *csdev,
ret = coresight_control_assoc_ectdev(csdev, true);
if (ret)
return ret;
- ret = source_ops(csdev)->enable(csdev, NULL, mode);
+ ret = source_ops(csdev)->enable(csdev, data, mode);
if (ret) {
coresight_control_assoc_ectdev(csdev, false);
return ret;
@@ -426,25 +426,75 @@ static int coresight_enable_source(struct coresight_device *csdev,
return 0;
}
+EXPORT_SYMBOL_GPL(coresight_enable_source);
+
+static bool coresight_is_helper(struct coresight_device *csdev)
+{
+ return csdev->type == CORESIGHT_DEV_TYPE_HELPER;
+}
+
+static int coresight_enable_helper(struct coresight_device *csdev,
+ enum cs_mode mode, void *data)
+{
+ int ret;
+
+ if (!helper_ops(csdev)->enable)
+ return 0;
+ ret = helper_ops(csdev)->enable(csdev, mode, data);
+ if (ret)
+ return ret;
+
+ csdev->enable = true;
+ return 0;
+}
+
+static void coresight_disable_helper(struct coresight_device *csdev)
+{
+ int ret;
+
+ if (!helper_ops(csdev)->disable)
+ return;
+
+ ret = helper_ops(csdev)->disable(csdev, NULL);
+ if (ret)
+ return;
+ csdev->enable = false;
+}
+
+static void coresight_disable_helpers(struct coresight_device *csdev)
+{
+ int i;
+ struct coresight_device *helper;
+
+ for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
+ helper = csdev->pdata->out_conns[i]->dest_dev;
+ if (helper && coresight_is_helper(helper))
+ coresight_disable_helper(helper);
+ }
+}
/**
* coresight_disable_source - 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(struct coresight_device *csdev)
+bool coresight_disable_source(struct coresight_device *csdev, void *data)
{
if (atomic_dec_return(&csdev->refcnt) == 0) {
if (source_ops(csdev)->disable)
- source_ops(csdev)->disable(csdev, NULL);
+ source_ops(csdev)->disable(csdev, data);
coresight_control_assoc_ectdev(csdev, false);
+ coresight_disable_helpers(csdev);
csdev->enable = false;
}
return !csdev->enable;
}
+EXPORT_SYMBOL_GPL(coresight_disable_source);
/*
* coresight_disable_path_from : Disable components in the given path beyond
@@ -495,6 +545,9 @@ static void coresight_disable_path_from(struct list_head *path,
default:
break;
}
+
+ /* Disable all helpers adjacent along the path last */
+ coresight_disable_helpers(csdev);
}
}
@@ -504,9 +557,28 @@ void coresight_disable_path(struct list_head *path)
}
EXPORT_SYMBOL_GPL(coresight_disable_path);
-int coresight_enable_path(struct list_head *path, enum cs_mode mode, void *sink_data)
+static int coresight_enable_helpers(struct coresight_device *csdev,
+ enum cs_mode mode, void *data)
{
+ int i, ret = 0;
+ struct coresight_device *helper;
+
+ for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
+ helper = csdev->pdata->out_conns[i]->dest_dev;
+ if (!helper || !coresight_is_helper(helper))
+ continue;
+
+ ret = coresight_enable_helper(helper, mode, data);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+int coresight_enable_path(struct list_head *path, enum cs_mode mode,
+ void *sink_data)
+{
int ret = 0;
u32 type;
struct coresight_node *nd;
@@ -516,6 +588,10 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode, void *sink_
csdev = nd->csdev;
type = csdev->type;
+ /* Enable all helpers adjacent to the path first */
+ ret = coresight_enable_helpers(csdev, mode, sink_data);
+ if (ret)
+ goto err;
/*
* ETF devices are tricky... They can be a link or a sink,
* depending on how they are configured. If an ETF has been
@@ -710,7 +786,7 @@ static int coresight_grab_device(struct coresight_device *csdev)
struct coresight_device *child;
child = csdev->pdata->out_conns[i]->dest_dev;
- if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
+ if (child && coresight_is_helper(child))
if (!coresight_get_ref(child))
goto err;
}
@@ -721,7 +797,7 @@ err:
struct coresight_device *child;
child = csdev->pdata->out_conns[i]->dest_dev;
- if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
+ if (child && coresight_is_helper(child))
coresight_put_ref(child);
}
return -ENODEV;
@@ -740,7 +816,7 @@ static void coresight_drop_device(struct coresight_device *csdev)
struct coresight_device *child;
child = csdev->pdata->out_conns[i]->dest_dev;
- if (child && child->type == CORESIGHT_DEV_TYPE_HELPER)
+ if (child && coresight_is_helper(child))
coresight_put_ref(child);
}
}
@@ -1102,7 +1178,7 @@ int coresight_enable(struct coresight_device *csdev)
if (ret)
goto err_path;
- ret = coresight_enable_source(csdev, CS_MODE_SYSFS);
+ ret = coresight_enable_source(csdev, CS_MODE_SYSFS, NULL);
if (ret)
goto err_source;
@@ -1159,7 +1235,7 @@ void coresight_disable(struct coresight_device *csdev)
if (ret)
goto out;
- if (!csdev->enable || !coresight_disable_source(csdev))
+ if (!csdev->enable || !coresight_disable_source(csdev, NULL))
goto out;
switch (csdev->subtype.source_subtype) {
@@ -1644,6 +1720,69 @@ static inline int coresight_search_device_idx(struct coresight_dev_list *dict,
return -ENOENT;
}
+static bool coresight_compare_type(enum coresight_dev_type type_a,
+ union coresight_dev_subtype subtype_a,
+ enum coresight_dev_type type_b,
+ union coresight_dev_subtype subtype_b)
+{
+ if (type_a != type_b)
+ return false;
+
+ switch (type_a) {
+ case CORESIGHT_DEV_TYPE_SINK:
+ return subtype_a.sink_subtype == subtype_b.sink_subtype;
+ case CORESIGHT_DEV_TYPE_LINK:
+ return subtype_a.link_subtype == subtype_b.link_subtype;
+ case CORESIGHT_DEV_TYPE_LINKSINK:
+ return subtype_a.link_subtype == subtype_b.link_subtype &&
+ subtype_a.sink_subtype == subtype_b.sink_subtype;
+ case CORESIGHT_DEV_TYPE_SOURCE:
+ return subtype_a.source_subtype == subtype_b.source_subtype;
+ case CORESIGHT_DEV_TYPE_HELPER:
+ return subtype_a.helper_subtype == subtype_b.helper_subtype;
+ default:
+ return false;
+ }
+}
+
+struct coresight_device *
+coresight_find_input_type(struct coresight_platform_data *pdata,
+ enum coresight_dev_type type,
+ union coresight_dev_subtype subtype)
+{
+ int i;
+ struct coresight_connection *conn;
+
+ for (i = 0; i < pdata->nr_inconns; ++i) {
+ conn = pdata->in_conns[i];
+ if (conn &&
+ coresight_compare_type(type, subtype, conn->src_dev->type,
+ conn->src_dev->subtype))
+ return conn->src_dev;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(coresight_find_input_type);
+
+struct coresight_device *
+coresight_find_output_type(struct coresight_platform_data *pdata,
+ enum coresight_dev_type type,
+ union coresight_dev_subtype subtype)
+{
+ int i;
+ struct coresight_connection *conn;
+
+ for (i = 0; i < pdata->nr_outconns; ++i) {
+ conn = pdata->out_conns[i];
+ if (conn->dest_dev &&
+ coresight_compare_type(type, subtype, conn->dest_dev->type,
+ conn->dest_dev->subtype))
+ return conn->dest_dev;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(coresight_find_output_type);
+
bool coresight_loses_context_with_cpu(struct device *dev)
{
return fwnode_property_present(dev_fwnode(dev),