1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2019, Linaro Limited, All rights reserved.
4 * Author: Mike Leach <mike.leach@linaro.org>
7 #include <linux/device.h>
9 #include <linux/kernel.h>
11 #include "coresight-priv.h"
12 #include "coresight-trace-id.h"
15 * Use IDR to map the hash of the source's device name
16 * to the pointer of path for the source. The idr is for
17 * the sources which aren't associated with CPU.
19 static DEFINE_IDR(path_idr
);
22 * When operating Coresight drivers from the sysFS interface, only a single
23 * path can exist from a tracer (associated to a CPU) to a sink.
25 static DEFINE_PER_CPU(struct list_head
*, tracer_path
);
27 ssize_t
coresight_simple_show_pair(struct device
*_dev
,
28 struct device_attribute
*attr
, char *buf
)
30 struct coresight_device
*csdev
= container_of(_dev
, struct coresight_device
, dev
);
31 struct cs_pair_attribute
*cs_attr
= container_of(attr
, struct cs_pair_attribute
, attr
);
34 pm_runtime_get_sync(_dev
->parent
);
35 val
= csdev_access_relaxed_read_pair(&csdev
->access
, cs_attr
->lo_off
, cs_attr
->hi_off
);
36 pm_runtime_put_sync(_dev
->parent
);
37 return sysfs_emit(buf
, "0x%llx\n", val
);
39 EXPORT_SYMBOL_GPL(coresight_simple_show_pair
);
41 ssize_t
coresight_simple_show32(struct device
*_dev
,
42 struct device_attribute
*attr
, char *buf
)
44 struct coresight_device
*csdev
= container_of(_dev
, struct coresight_device
, dev
);
45 struct cs_off_attribute
*cs_attr
= container_of(attr
, struct cs_off_attribute
, attr
);
48 pm_runtime_get_sync(_dev
->parent
);
49 val
= csdev_access_relaxed_read32(&csdev
->access
, cs_attr
->off
);
50 pm_runtime_put_sync(_dev
->parent
);
51 return sysfs_emit(buf
, "0x%llx\n", val
);
53 EXPORT_SYMBOL_GPL(coresight_simple_show32
);
55 static int coresight_enable_source_sysfs(struct coresight_device
*csdev
,
56 enum cs_mode mode
, void *data
)
61 * Comparison with CS_MODE_SYSFS works without taking any device
62 * specific spinlock because the truthyness of that comparison can only
63 * change with coresight_mutex held, which we already have here.
65 lockdep_assert_held(&coresight_mutex
);
66 if (coresight_get_mode(csdev
) != CS_MODE_SYSFS
) {
67 ret
= source_ops(csdev
)->enable(csdev
, data
, mode
, NULL
);
78 * coresight_disable_source_sysfs - Drop the reference count by 1 and disable
79 * the device if there are no users left.
81 * @csdev: The coresight device to disable
82 * @data: Opaque data to pass on to the disable function of the source device.
83 * For example in perf mode this is a pointer to the struct perf_event.
85 * Returns true if the device has been disabled.
87 static bool coresight_disable_source_sysfs(struct coresight_device
*csdev
,
90 lockdep_assert_held(&coresight_mutex
);
91 if (coresight_get_mode(csdev
) != CS_MODE_SYSFS
)
95 if (csdev
->refcnt
== 0) {
96 coresight_disable_source(csdev
, data
);
103 * coresight_find_activated_sysfs_sink - returns the first sink activated via
104 * sysfs using connection based search starting from the source reference.
106 * @csdev: Coresight source device reference
108 static struct coresight_device
*
109 coresight_find_activated_sysfs_sink(struct coresight_device
*csdev
)
112 struct coresight_device
*sink
= NULL
;
114 if ((csdev
->type
== CORESIGHT_DEV_TYPE_SINK
||
115 csdev
->type
== CORESIGHT_DEV_TYPE_LINKSINK
) &&
116 csdev
->sysfs_sink_activated
)
120 * Recursively explore each port found on this element.
122 for (i
= 0; i
< csdev
->pdata
->nr_outconns
; i
++) {
123 struct coresight_device
*child_dev
;
125 child_dev
= csdev
->pdata
->out_conns
[i
]->dest_dev
;
127 sink
= coresight_find_activated_sysfs_sink(child_dev
);
135 /** coresight_validate_source - make sure a source has the right credentials to
137 * @csdev: the device structure for a source.
138 * @function: the function this was called from.
140 * Assumes the coresight_mutex is held.
142 static int coresight_validate_source_sysfs(struct coresight_device
*csdev
,
143 const char *function
)
148 subtype
= csdev
->subtype
.source_subtype
;
150 if (type
!= CORESIGHT_DEV_TYPE_SOURCE
) {
151 dev_err(&csdev
->dev
, "wrong device type in %s\n", function
);
155 if (subtype
!= CORESIGHT_DEV_SUBTYPE_SOURCE_PROC
&&
156 subtype
!= CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE
&&
157 subtype
!= CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM
&&
158 subtype
!= CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS
) {
159 dev_err(&csdev
->dev
, "wrong device subtype in %s\n", function
);
166 int coresight_enable_sysfs(struct coresight_device
*csdev
)
169 struct coresight_device
*sink
;
170 struct list_head
*path
;
171 enum coresight_dev_subtype_source subtype
;
174 subtype
= csdev
->subtype
.source_subtype
;
176 mutex_lock(&coresight_mutex
);
178 ret
= coresight_validate_source_sysfs(csdev
, __func__
);
183 * mode == SYSFS implies that it's already enabled. Don't look at the
184 * refcount to determine this because we don't claim the source until
185 * coresight_enable_source() so can still race with Perf mode which
186 * doesn't hold coresight_mutex.
188 if (coresight_get_mode(csdev
) == CS_MODE_SYSFS
) {
190 * There could be multiple applications driving the software
191 * source. So keep the refcount for each such user when the
192 * source is already enabled.
194 if (subtype
== CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE
)
199 sink
= coresight_find_activated_sysfs_sink(csdev
);
205 path
= coresight_build_path(csdev
, sink
);
207 pr_err("building path(s) failed\n");
212 ret
= coresight_enable_path(path
, CS_MODE_SYSFS
, NULL
);
216 ret
= coresight_enable_source_sysfs(csdev
, CS_MODE_SYSFS
, NULL
);
221 case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC
:
223 * When working from sysFS it is important to keep track
224 * of the paths that were created so that they can be
225 * undone in 'coresight_disable()'. Since there can only
226 * be a single session per tracer (when working from sysFS)
227 * a per-cpu variable will do just fine.
229 cpu
= source_ops(csdev
)->cpu_id(csdev
);
230 per_cpu(tracer_path
, cpu
) = path
;
232 case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE
:
233 case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM
:
234 case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS
:
236 * Use the hash of source's device name as ID
237 * and map the ID to the pointer of the path.
239 hash
= hashlen_hash(hashlen_string(NULL
, dev_name(&csdev
->dev
)));
240 ret
= idr_alloc_u32(&path_idr
, path
, &hash
, hash
, GFP_KERNEL
);
245 /* We can't be here */
250 mutex_unlock(&coresight_mutex
);
254 coresight_disable_path(path
);
257 coresight_release_path(path
);
260 EXPORT_SYMBOL_GPL(coresight_enable_sysfs
);
262 void coresight_disable_sysfs(struct coresight_device
*csdev
)
265 struct list_head
*path
= NULL
;
268 mutex_lock(&coresight_mutex
);
270 ret
= coresight_validate_source_sysfs(csdev
, __func__
);
274 if (!coresight_disable_source_sysfs(csdev
, NULL
))
277 switch (csdev
->subtype
.source_subtype
) {
278 case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC
:
279 cpu
= source_ops(csdev
)->cpu_id(csdev
);
280 path
= per_cpu(tracer_path
, cpu
);
281 per_cpu(tracer_path
, cpu
) = NULL
;
283 case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE
:
284 case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM
:
285 case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS
:
286 hash
= hashlen_hash(hashlen_string(NULL
, dev_name(&csdev
->dev
)));
287 /* Find the path by the hash. */
288 path
= idr_find(&path_idr
, hash
);
290 pr_err("Path is not found for %s\n", dev_name(&csdev
->dev
));
293 idr_remove(&path_idr
, hash
);
296 /* We can't be here */
300 coresight_disable_path(path
);
301 coresight_release_path(path
);
304 mutex_unlock(&coresight_mutex
);
306 EXPORT_SYMBOL_GPL(coresight_disable_sysfs
);
308 static ssize_t
enable_sink_show(struct device
*dev
,
309 struct device_attribute
*attr
, char *buf
)
311 struct coresight_device
*csdev
= to_coresight_device(dev
);
313 return scnprintf(buf
, PAGE_SIZE
, "%u\n", csdev
->sysfs_sink_activated
);
316 static ssize_t
enable_sink_store(struct device
*dev
,
317 struct device_attribute
*attr
,
318 const char *buf
, size_t size
)
322 struct coresight_device
*csdev
= to_coresight_device(dev
);
324 ret
= kstrtoul(buf
, 10, &val
);
328 csdev
->sysfs_sink_activated
= !!val
;
333 static DEVICE_ATTR_RW(enable_sink
);
335 static ssize_t
enable_source_show(struct device
*dev
,
336 struct device_attribute
*attr
, char *buf
)
338 struct coresight_device
*csdev
= to_coresight_device(dev
);
340 guard(mutex
)(&coresight_mutex
);
341 return scnprintf(buf
, PAGE_SIZE
, "%u\n",
342 coresight_get_mode(csdev
) == CS_MODE_SYSFS
);
345 static ssize_t
enable_source_store(struct device
*dev
,
346 struct device_attribute
*attr
,
347 const char *buf
, size_t size
)
351 struct coresight_device
*csdev
= to_coresight_device(dev
);
353 ret
= kstrtoul(buf
, 10, &val
);
358 ret
= coresight_enable_sysfs(csdev
);
362 coresight_disable_sysfs(csdev
);
367 static DEVICE_ATTR_RW(enable_source
);
369 static struct attribute
*coresight_sink_attrs
[] = {
370 &dev_attr_enable_sink
.attr
,
373 ATTRIBUTE_GROUPS(coresight_sink
);
375 static struct attribute
*coresight_source_attrs
[] = {
376 &dev_attr_enable_source
.attr
,
379 ATTRIBUTE_GROUPS(coresight_source
);
381 const struct device_type coresight_dev_type
[] = {
382 [CORESIGHT_DEV_TYPE_SINK
] = {
384 .groups
= coresight_sink_groups
,
386 [CORESIGHT_DEV_TYPE_LINK
] = {
389 [CORESIGHT_DEV_TYPE_LINKSINK
] = {
391 .groups
= coresight_sink_groups
,
393 [CORESIGHT_DEV_TYPE_SOURCE
] = {
395 .groups
= coresight_source_groups
,
397 [CORESIGHT_DEV_TYPE_HELPER
] = {
401 /* Ensure the enum matches the names and groups */
402 static_assert(ARRAY_SIZE(coresight_dev_type
) == CORESIGHT_DEV_TYPE_MAX
);
405 * Connections group - links attribute.
406 * Count of created links between coresight components in the group.
408 static ssize_t
nr_links_show(struct device
*dev
,
409 struct device_attribute
*attr
,
412 struct coresight_device
*csdev
= to_coresight_device(dev
);
414 return sprintf(buf
, "%d\n", csdev
->nr_links
);
416 static DEVICE_ATTR_RO(nr_links
);
418 static struct attribute
*coresight_conns_attrs
[] = {
419 &dev_attr_nr_links
.attr
,
423 static struct attribute_group coresight_conns_group
= {
424 .attrs
= coresight_conns_attrs
,
425 .name
= "connections",
429 * Create connections group for CoreSight devices.
430 * This group will then be used to collate the sysfs links between
433 int coresight_create_conns_sysfs_group(struct coresight_device
*csdev
)
440 ret
= sysfs_create_group(&csdev
->dev
.kobj
, &coresight_conns_group
);
444 csdev
->has_conns_grp
= true;
448 void coresight_remove_conns_sysfs_group(struct coresight_device
*csdev
)
453 if (csdev
->has_conns_grp
) {
454 sysfs_remove_group(&csdev
->dev
.kobj
, &coresight_conns_group
);
455 csdev
->has_conns_grp
= false;
459 int coresight_add_sysfs_link(struct coresight_sysfs_link
*info
)
465 if (!info
->orig
|| !info
->target
||
466 !info
->orig_name
|| !info
->target_name
)
468 if (!info
->orig
->has_conns_grp
|| !info
->target
->has_conns_grp
)
471 /* first link orig->target */
472 ret
= sysfs_add_link_to_group(&info
->orig
->dev
.kobj
,
473 coresight_conns_group
.name
,
474 &info
->target
->dev
.kobj
,
479 /* second link target->orig */
480 ret
= sysfs_add_link_to_group(&info
->target
->dev
.kobj
,
481 coresight_conns_group
.name
,
482 &info
->orig
->dev
.kobj
,
485 /* error in second link - remove first - otherwise inc counts */
487 sysfs_remove_link_from_group(&info
->orig
->dev
.kobj
,
488 coresight_conns_group
.name
,
491 info
->orig
->nr_links
++;
492 info
->target
->nr_links
++;
497 EXPORT_SYMBOL_GPL(coresight_add_sysfs_link
);
499 void coresight_remove_sysfs_link(struct coresight_sysfs_link
*info
)
503 if (!info
->orig
|| !info
->target
||
504 !info
->orig_name
|| !info
->target_name
)
507 sysfs_remove_link_from_group(&info
->orig
->dev
.kobj
,
508 coresight_conns_group
.name
,
511 sysfs_remove_link_from_group(&info
->target
->dev
.kobj
,
512 coresight_conns_group
.name
,
515 info
->orig
->nr_links
--;
516 info
->target
->nr_links
--;
518 EXPORT_SYMBOL_GPL(coresight_remove_sysfs_link
);
521 * coresight_make_links: Make a link for a connection from a @orig
522 * device to @target, represented by @conn.
524 * e.g, for devOrig[output_X] -> devTarget[input_Y] is represented
525 * as two symbolic links :
527 * /sys/.../devOrig/out:X -> /sys/.../devTarget/
528 * /sys/.../devTarget/in:Y -> /sys/.../devOrig/
530 * The link names are allocated for a device where it appears. i.e, the
531 * "out" link on the master and "in" link on the slave device.
532 * The link info is stored in the connection record for avoiding
533 * the reconstruction of names for removal.
535 int coresight_make_links(struct coresight_device
*orig
,
536 struct coresight_connection
*conn
,
537 struct coresight_device
*target
)
540 char *outs
= NULL
, *ins
= NULL
;
541 struct coresight_sysfs_link
*link
= NULL
;
543 /* Helper devices aren't shown in sysfs */
544 if (conn
->dest_port
== -1 && conn
->src_port
== -1)
548 outs
= devm_kasprintf(&orig
->dev
, GFP_KERNEL
,
549 "out:%d", conn
->src_port
);
552 ins
= devm_kasprintf(&target
->dev
, GFP_KERNEL
,
553 "in:%d", conn
->dest_port
);
556 link
= devm_kzalloc(&orig
->dev
,
557 sizeof(struct coresight_sysfs_link
),
563 link
->target
= target
;
564 link
->orig_name
= outs
;
565 link
->target_name
= ins
;
567 ret
= coresight_add_sysfs_link(link
);
579 * coresight_remove_links: Remove the sysfs links for a given connection @conn,
580 * from @orig device to @target device. See coresight_make_links() for more
583 void coresight_remove_links(struct coresight_device
*orig
,
584 struct coresight_connection
*conn
)
586 if (!orig
|| !conn
->link
)
589 coresight_remove_sysfs_link(conn
->link
);
591 devm_kfree(&conn
->dest_dev
->dev
, conn
->link
->target_name
);
592 devm_kfree(&orig
->dev
, conn
->link
->orig_name
);
593 devm_kfree(&orig
->dev
, conn
->link
);