Skip to content

Commit ec9903d

Browse files
Tao ZhangSuzuki K Poulose
authored andcommitted
coresight: Add support for trace filtering by source
Some replicators have hard coded filtering of "trace" data, based on the source device. This is different from the trace filtering based on TraceID, available in the standard programmable replicators. e.g., Qualcomm replicators have filtering based on custom trace protocol format and is not programmable. The source device could be connected to the replicator via intermediate components (e.g., a funnel). Thus we need platform information from the firmware tables to decide the source device corresponding to a given output port from the replicator. Given this affects "trace path building" and traversing the path back from the sink to source, add the concept of "filtering by source" to the generic coresight connection. The specified source will be marked like below in the Devicetree. test-replicator { ... ... ... ... out-ports { ... ... ... ... port@0 { reg = <0>; xyz: endpoint { remote-endpoint = <&zyx>; filter-source = <&source_1>; <-- To specify the source to }; be filtered out here. }; port@1 { reg = <1>; abc: endpoint { remote-endpoint = <&cba>; filter-source = <&source_2>; <-- To specify the source to }; be filtered out here. }; }; }; Signed-off-by: Tao Zhang <[email protected]> Signed-off-by: Suzuki K Poulose <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 62374ce commit ec9903d

File tree

3 files changed

+120
-19
lines changed

3 files changed

+120
-19
lines changed

drivers/hwtracing/coresight/coresight-core.c

Lines changed: 94 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -75,22 +75,54 @@ struct coresight_device *coresight_get_percpu_sink(int cpu)
7575
}
7676
EXPORT_SYMBOL_GPL(coresight_get_percpu_sink);
7777

78+
static struct coresight_device *coresight_get_source(struct list_head *path)
79+
{
80+
struct coresight_device *csdev;
81+
82+
if (!path)
83+
return NULL;
84+
85+
csdev = list_first_entry(path, struct coresight_node, link)->csdev;
86+
if (!coresight_is_device_source(csdev))
87+
return NULL;
88+
89+
return csdev;
90+
}
91+
92+
/**
93+
* coresight_blocks_source - checks whether the connection matches the source
94+
* of path if connection is bound to specific source.
95+
* @src: The source device of the trace path
96+
* @conn: The connection of one outport
97+
*
98+
* Return false if the connection doesn't have a source binded or source of the
99+
* path matches the source binds to connection.
100+
*/
101+
static bool coresight_blocks_source(struct coresight_device *src,
102+
struct coresight_connection *conn)
103+
{
104+
return conn->filter_src_fwnode && (conn->filter_src_dev != src);
105+
}
106+
78107
static struct coresight_connection *
79-
coresight_find_out_connection(struct coresight_device *src_dev,
80-
struct coresight_device *dest_dev)
108+
coresight_find_out_connection(struct coresight_device *csdev,
109+
struct coresight_device *out_dev,
110+
struct coresight_device *trace_src)
81111
{
82112
int i;
83113
struct coresight_connection *conn;
84114

85-
for (i = 0; i < src_dev->pdata->nr_outconns; i++) {
86-
conn = src_dev->pdata->out_conns[i];
87-
if (conn->dest_dev == dest_dev)
115+
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
116+
conn = csdev->pdata->out_conns[i];
117+
if (coresight_blocks_source(trace_src, conn))
118+
continue;
119+
if (conn->dest_dev == out_dev)
88120
return conn;
89121
}
90122

91-
dev_err(&src_dev->dev,
92-
"couldn't find output connection, src_dev: %s, dest_dev: %s\n",
93-
dev_name(&src_dev->dev), dev_name(&dest_dev->dev));
123+
dev_err(&csdev->dev,
124+
"couldn't find output connection, csdev: %s, out_dev: %s\n",
125+
dev_name(&csdev->dev), dev_name(&out_dev->dev));
94126

95127
return ERR_PTR(-ENODEV);
96128
}
@@ -251,16 +283,17 @@ static void coresight_disable_sink(struct coresight_device *csdev)
251283

252284
static int coresight_enable_link(struct coresight_device *csdev,
253285
struct coresight_device *parent,
254-
struct coresight_device *child)
286+
struct coresight_device *child,
287+
struct coresight_device *source)
255288
{
256289
int link_subtype;
257290
struct coresight_connection *inconn, *outconn;
258291

259292
if (!parent || !child)
260293
return -EINVAL;
261294

262-
inconn = coresight_find_out_connection(parent, csdev);
263-
outconn = coresight_find_out_connection(csdev, child);
295+
inconn = coresight_find_out_connection(parent, csdev, source);
296+
outconn = coresight_find_out_connection(csdev, child, source);
264297
link_subtype = csdev->subtype.link_subtype;
265298

266299
if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG && IS_ERR(inconn))
@@ -273,15 +306,16 @@ static int coresight_enable_link(struct coresight_device *csdev,
273306

274307
static void coresight_disable_link(struct coresight_device *csdev,
275308
struct coresight_device *parent,
276-
struct coresight_device *child)
309+
struct coresight_device *child,
310+
struct coresight_device *source)
277311
{
278312
struct coresight_connection *inconn, *outconn;
279313

280314
if (!parent || !child)
281315
return;
282316

283-
inconn = coresight_find_out_connection(parent, csdev);
284-
outconn = coresight_find_out_connection(csdev, child);
317+
inconn = coresight_find_out_connection(parent, csdev, source);
318+
outconn = coresight_find_out_connection(csdev, child, source);
285319

286320
link_ops(csdev)->disable(csdev, inconn, outconn);
287321
}
@@ -375,7 +409,8 @@ static void coresight_disable_path_from(struct list_head *path,
375409
case CORESIGHT_DEV_TYPE_LINK:
376410
parent = list_prev_entry(nd, link)->csdev;
377411
child = list_next_entry(nd, link)->csdev;
378-
coresight_disable_link(csdev, parent, child);
412+
coresight_disable_link(csdev, parent, child,
413+
coresight_get_source(path));
379414
break;
380415
default:
381416
break;
@@ -418,7 +453,9 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode,
418453
u32 type;
419454
struct coresight_node *nd;
420455
struct coresight_device *csdev, *parent, *child;
456+
struct coresight_device *source;
421457

458+
source = coresight_get_source(path);
422459
list_for_each_entry_reverse(nd, path, link) {
423460
csdev = nd->csdev;
424461
type = csdev->type;
@@ -456,7 +493,7 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode,
456493
case CORESIGHT_DEV_TYPE_LINK:
457494
parent = list_prev_entry(nd, link)->csdev;
458495
child = list_next_entry(nd, link)->csdev;
459-
ret = coresight_enable_link(csdev, parent, child);
496+
ret = coresight_enable_link(csdev, parent, child, source);
460497
if (ret)
461498
goto err;
462499
break;
@@ -619,6 +656,7 @@ static void coresight_drop_device(struct coresight_device *csdev)
619656
/**
620657
* _coresight_build_path - recursively build a path from a @csdev to a sink.
621658
* @csdev: The device to start from.
659+
* @source: The trace source device of the path.
622660
* @sink: The final sink we want in this path.
623661
* @path: The list to add devices to.
624662
*
@@ -628,6 +666,7 @@ static void coresight_drop_device(struct coresight_device *csdev)
628666
* the source is the first device and the sink the last one.
629667
*/
630668
static int _coresight_build_path(struct coresight_device *csdev,
669+
struct coresight_device *source,
631670
struct coresight_device *sink,
632671
struct list_head *path)
633672
{
@@ -641,7 +680,7 @@ static int _coresight_build_path(struct coresight_device *csdev,
641680

642681
if (coresight_is_percpu_source(csdev) && coresight_is_percpu_sink(sink) &&
643682
sink == per_cpu(csdev_sink, source_ops(csdev)->cpu_id(csdev))) {
644-
if (_coresight_build_path(sink, sink, path) == 0) {
683+
if (_coresight_build_path(sink, source, sink, path) == 0) {
645684
found = true;
646685
goto out;
647686
}
@@ -652,8 +691,12 @@ static int _coresight_build_path(struct coresight_device *csdev,
652691
struct coresight_device *child_dev;
653692

654693
child_dev = csdev->pdata->out_conns[i]->dest_dev;
694+
695+
if (coresight_blocks_source(source, csdev->pdata->out_conns[i]))
696+
continue;
697+
655698
if (child_dev &&
656-
_coresight_build_path(child_dev, sink, path) == 0) {
699+
_coresight_build_path(child_dev, source, sink, path) == 0) {
657700
found = true;
658701
break;
659702
}
@@ -698,7 +741,7 @@ struct list_head *coresight_build_path(struct coresight_device *source,
698741

699742
INIT_LIST_HEAD(path);
700743

701-
rc = _coresight_build_path(source, sink, path);
744+
rc = _coresight_build_path(source, source, sink, path);
702745
if (rc) {
703746
kfree(path);
704747
return ERR_PTR(rc);
@@ -927,6 +970,16 @@ static int coresight_orphan_match(struct device *dev, void *data)
927970
for (i = 0; i < src_csdev->pdata->nr_outconns; i++) {
928971
conn = src_csdev->pdata->out_conns[i];
929972

973+
/* Fix filter source device before skip the port */
974+
if (conn->filter_src_fwnode && !conn->filter_src_dev) {
975+
if (dst_csdev &&
976+
(conn->filter_src_fwnode == dst_csdev->dev.fwnode) &&
977+
!WARN_ON_ONCE(!coresight_is_device_source(dst_csdev)))
978+
conn->filter_src_dev = dst_csdev;
979+
else
980+
still_orphan = true;
981+
}
982+
930983
/* Skip the port if it's already connected. */
931984
if (conn->dest_dev)
932985
continue;
@@ -977,18 +1030,40 @@ static int coresight_fixup_orphan_conns(struct coresight_device *csdev)
9771030
csdev, coresight_orphan_match);
9781031
}
9791032

1033+
static int coresight_clear_filter_source(struct device *dev, void *data)
1034+
{
1035+
int i;
1036+
struct coresight_device *source = data;
1037+
struct coresight_device *csdev = to_coresight_device(dev);
1038+
1039+
for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
1040+
if (csdev->pdata->out_conns[i]->filter_src_dev == source)
1041+
csdev->pdata->out_conns[i]->filter_src_dev = NULL;
1042+
}
1043+
return 0;
1044+
}
1045+
9801046
/* coresight_remove_conns - Remove other device's references to this device */
9811047
static void coresight_remove_conns(struct coresight_device *csdev)
9821048
{
9831049
int i, j;
9841050
struct coresight_connection *conn;
9851051

1052+
if (coresight_is_device_source(csdev))
1053+
bus_for_each_dev(&coresight_bustype, NULL, csdev,
1054+
coresight_clear_filter_source);
1055+
9861056
/*
9871057
* Remove the input connection references from the destination device
9881058
* for each output connection.
9891059
*/
9901060
for (i = 0; i < csdev->pdata->nr_outconns; i++) {
9911061
conn = csdev->pdata->out_conns[i];
1062+
if (conn->filter_src_fwnode) {
1063+
conn->filter_src_dev = NULL;
1064+
fwnode_handle_put(conn->filter_src_fwnode);
1065+
}
1066+
9921067
if (!conn->dest_dev)
9931068
continue;
9941069

drivers/hwtracing/coresight/coresight-platform.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,27 @@ static int of_coresight_parse_endpoint(struct device *dev,
243243
conn.dest_fwnode = fwnode_handle_get(rdev_fwnode);
244244
conn.dest_port = rendpoint.port;
245245

246+
/*
247+
* Get the firmware node of the filter source through the
248+
* reference. This could be used to filter the source in
249+
* building path.
250+
*/
251+
conn.filter_src_fwnode =
252+
fwnode_find_reference(&ep->fwnode, "filter-source", 0);
253+
if (IS_ERR(conn.filter_src_fwnode)) {
254+
conn.filter_src_fwnode = NULL;
255+
} else {
256+
conn.filter_src_dev =
257+
coresight_find_csdev_by_fwnode(conn.filter_src_fwnode);
258+
if (conn.filter_src_dev &&
259+
!coresight_is_device_source(conn.filter_src_dev)) {
260+
dev_warn(dev, "port %d: Filter handle is not a trace source : %s\n",
261+
conn.src_port, dev_name(&conn.filter_src_dev->dev));
262+
conn.filter_src_dev = NULL;
263+
conn.filter_src_fwnode = NULL;
264+
}
265+
}
266+
246267
new_conn = coresight_add_out_conn(dev, pdata, &conn);
247268
if (IS_ERR_VALUE(new_conn)) {
248269
fwnode_handle_put(conn.dest_fwnode);

include/linux/coresight.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ struct coresight_desc {
172172
* @dest_dev: a @coresight_device representation of the component
173173
connected to @src_port. NULL until the device is created
174174
* @link: Representation of the connection as a sysfs link.
175+
* @filter_src_fwnode: filter source component's fwnode handle.
176+
* @filter_src_dev: a @coresight_device representation of the component that
177+
needs to be filtered.
175178
*
176179
* The full connection structure looks like this, where in_conns store
177180
* references to same connection as the source device's out_conns.
@@ -200,6 +203,8 @@ struct coresight_connection {
200203
struct coresight_device *dest_dev;
201204
struct coresight_sysfs_link *link;
202205
struct coresight_device *src_dev;
206+
struct fwnode_handle *filter_src_fwnode;
207+
struct coresight_device *filter_src_dev;
203208
int src_refcnt;
204209
int dest_refcnt;
205210
};

0 commit comments

Comments
 (0)