Signed-off-by: Tao Zhang <quic_taozha@xxxxxxxxxxx>
---
drivers/hwtracing/coresight/coresight-core.c | 81 ++++++++++++++++---
.../hwtracing/coresight/coresight-platform.c | 5 ++
include/linux/coresight.h | 2 +
3 files changed, 75 insertions(+), 13 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 5dde597403b3..b1b5e6d9ec7a 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -113,15 +113,63 @@ struct coresight_device *coresight_get_percpu_sink(int cpu)
}
EXPORT_SYMBOL_GPL(coresight_get_percpu_sink);
+static struct coresight_device *coresight_get_source(struct list_head *path)
+{
+ struct coresight_device *csdev;
+
+ if (!path)
+ return NULL;
+
+ csdev = list_first_entry(path, struct coresight_node, link)->csdev;
+ if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE)
+ return NULL;
+
+ return csdev;
+}
+
+/**
+ * coresight_source_filter - checks whether the connection matches the source
+ * of path if connection is binded to specific source.
+ * @path: The list of devices
+ * @conn: The connection of one outport
+ *
+ * Return zero if the connection doesn't have a source binded or source of the
+ * path matches the source binds to connection.
+ */
+static int coresight_source_filter(struct list_head *path,
+ struct coresight_connection *conn)
+{
+ int ret = 0;
+ struct coresight_device *source = NULL;
+
+ if (conn->source_label == NULL)
+ return ret;
+
+ source = coresight_get_source(path);
+ if (source == NULL)
+ return ret;
+
+ if (strstr(kobject_get_path(&source->dev.kobj, GFP_KERNEL),
+ conn->source_label))
+ ret = 0;
+ else
+ ret = -1;
+
+ return ret;
+}
+
static struct coresight_connection *
coresight_find_out_connection(struct coresight_device *src_dev,
- struct coresight_device *dest_dev)
+ struct coresight_device *dest_dev,
+ struct list_head *path)
{
int i;
struct coresight_connection *conn;
for (i = 0; i < src_dev->pdata->nr_outconns; i++) {
conn = src_dev->pdata->out_conns[i];
+ if (coresight_source_filter(path, conn))
+ continue;
if (conn->dest_dev == dest_dev)
return conn;
}
@@ -312,7 +360,8 @@ static void coresight_disable_sink(struct coresight_device *csdev)
static int coresight_enable_link(struct coresight_device *csdev,
struct coresight_device *parent,
- struct coresight_device *child)
+ struct coresight_device *child,
+ struct list_head *path)
{
int ret = 0;
int link_subtype;
@@ -321,8 +370,8 @@ static int coresight_enable_link(struct coresight_device *csdev,
if (!parent || !child)
return -EINVAL;
- inconn = coresight_find_out_connection(parent, csdev);
- outconn = coresight_find_out_connection(csdev, child);
+ inconn = coresight_find_out_connection(parent, csdev, path);
+ outconn = coresight_find_out_connection(csdev, child, path);
link_subtype = csdev->subtype.link_subtype;
if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && IS_ERR(inconn))
@@ -341,7 +390,8 @@ static int coresight_enable_link(struct coresight_device *csdev,
static void coresight_disable_link(struct coresight_device *csdev,
struct coresight_device *parent,
- struct coresight_device *child)
+ struct coresight_device *child,
+ struct list_head *path)
{
int i;
int link_subtype;
@@ -350,8 +400,8 @@ static void coresight_disable_link(struct coresight_device *csdev,
if (!parent || !child)
return;
- inconn = coresight_find_out_connection(parent, csdev);
- outconn = coresight_find_out_connection(csdev, child);
+ inconn = coresight_find_out_connection(parent, csdev, path);
+ outconn = coresight_find_out_connection(csdev, child, path);
link_subtype = csdev->subtype.link_subtype;
if (link_ops(csdev)->disable) {
@@ -507,7 +557,7 @@ static void coresight_disable_path_from(struct list_head *path,
case CORESIGHT_DEV_TYPE_LINK:
parent = list_prev_entry(nd, link)->csdev;
child = list_next_entry(nd, link)->csdev;
- coresight_disable_link(csdev, parent, child);
+ coresight_disable_link(csdev, parent, child, path);
break;
default:
break;
@@ -588,7 +638,7 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode,
case CORESIGHT_DEV_TYPE_LINK:
parent = list_prev_entry(nd, link)->csdev;
child = list_next_entry(nd, link)->csdev;
- ret = coresight_enable_link(csdev, parent, child);
+ ret = coresight_enable_link(csdev, parent, child, path);
if (ret)
goto err;
break;
@@ -802,7 +852,8 @@ static void coresight_drop_device(struct coresight_device *csdev)
*/
static int _coresight_build_path(struct coresight_device *csdev,
struct coresight_device *sink,
- struct list_head *path)
+ struct list_head *path,
+ struct coresight_device *source)
{
int i, ret;
bool found = false;
@@ -814,7 +865,7 @@ static int _coresight_build_path(struct coresight_device *csdev,
if (coresight_is_percpu_source(csdev) && coresight_is_percpu_sink(sink) &&
sink == per_cpu(csdev_sink, source_ops(csdev)->cpu_id(csdev))) {
- if (_coresight_build_path(sink, sink, path) == 0) {
+ if (_coresight_build_path(sink, sink, path, source) == 0) {
found = true;
goto out;
}
@@ -825,8 +876,12 @@ static int _coresight_build_path(struct coresight_device *csdev,
struct coresight_device *child_dev;
child_dev = csdev->pdata->out_conns[i]->dest_dev;
+ if (csdev->pdata->out_conns[i]->source_label &&
+ !strstr(kobject_get_path(&source->dev.kobj, GFP_KERNEL),
+ csdev->pdata->out_conns[i]->source_label))
+ continue;
if (child_dev &&
- _coresight_build_path(child_dev, sink, path) == 0) {
+ _coresight_build_path(child_dev, sink, path, source) == 0) {
found = true;
break;
}
@@ -871,7 +926,7 @@ struct list_head *coresight_build_path(struct coresight_device *source,
INIT_LIST_HEAD(path);
- rc = _coresight_build_path(source, sink, path);
+ rc = _coresight_build_path(source, sink, path, source);
if (rc) {
kfree(path);
return ERR_PTR(rc);
diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
index 9d550f5697fa..f553fb20966d 100644
--- a/drivers/hwtracing/coresight/coresight-platform.c
+++ b/drivers/hwtracing/coresight/coresight-platform.c
@@ -205,6 +205,7 @@ static int of_coresight_parse_endpoint(struct device *dev,
struct fwnode_handle *rdev_fwnode;
struct coresight_connection conn = {};
struct coresight_connection *new_conn;
+ const char *label;
do {
/* Parse the local port details */
@@ -243,6 +244,10 @@ static int of_coresight_parse_endpoint(struct device *dev,
conn.dest_fwnode = fwnode_handle_get(rdev_fwnode);
conn.dest_port = rendpoint.port;
+ conn.source_label = NULL;
+ if (!of_property_read_string(ep, "label", &label))
+ conn.source_label = label;
+
new_conn = coresight_add_out_conn(dev, pdata, &conn);
if (IS_ERR_VALUE(new_conn)) {
fwnode_handle_put(conn.dest_fwnode);
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index e8b6e388218c..a9c06ef9bbb2 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -167,6 +167,7 @@ struct coresight_desc {
* struct coresight_connection - representation of a single connection
* @src_port: a connection's output port number.
* @dest_port: destination's input port number @src_port is connected to.
+ * @source_label: source component's label.
* @dest_fwnode: destination component's fwnode handle.
* @dest_dev: a @coresight_device representation of the component
connected to @src_port. NULL until the device is created
@@ -195,6 +196,7 @@ struct coresight_desc {
struct coresight_connection {
int src_port;
int dest_port;
+ const char *source_label;
struct fwnode_handle *dest_fwnode;
struct coresight_device *dest_dev;
struct coresight_sysfs_link *link;