xref: /linux/drivers/hwtracing/coresight/coresight-sysfs.c (revision e7e2296b0ecf9b6e934f7a1118cee91d4d486a84)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2019, Linaro Limited, All rights reserved.
4  * Author: Mike Leach <mike.leach@linaro.org>
5  */
6 
7 #include <linux/device.h>
8 #include <linux/idr.h>
9 #include <linux/kernel.h>
10 #include <linux/property.h>
11 
12 #include "coresight-priv.h"
13 #include "coresight-trace-id.h"
14 
15 /*
16  * Use IDR to map the hash of the source's device name
17  * to the pointer of path for the source. The idr is for
18  * the sources which aren't associated with CPU.
19  */
20 static DEFINE_IDR(path_idr);
21 
22 /*
23  * When operating Coresight drivers from the sysFS interface, only a single
24  * path can exist from a tracer (associated to a CPU) to a sink.
25  */
26 static DEFINE_PER_CPU(struct coresight_path *, tracer_path);
27 
28 ssize_t coresight_simple_show_pair(struct device *_dev,
29 			      struct device_attribute *attr, char *buf)
30 {
31 	struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
32 	struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr);
33 	u64 val;
34 
35 	pm_runtime_get_sync(_dev->parent);
36 	val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off);
37 	pm_runtime_put_sync(_dev->parent);
38 	return sysfs_emit(buf, "0x%llx\n", val);
39 }
40 EXPORT_SYMBOL_GPL(coresight_simple_show_pair);
41 
42 ssize_t coresight_simple_show32(struct device *_dev,
43 			      struct device_attribute *attr, char *buf)
44 {
45 	struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
46 	struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr);
47 	u64 val;
48 
49 	pm_runtime_get_sync(_dev->parent);
50 	val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off);
51 	pm_runtime_put_sync(_dev->parent);
52 	return sysfs_emit(buf, "0x%llx\n", val);
53 }
54 EXPORT_SYMBOL_GPL(coresight_simple_show32);
55 
56 static int coresight_enable_source_sysfs(struct coresight_device *csdev,
57 					 enum cs_mode mode,
58 					 struct coresight_path *path)
59 {
60 	int ret;
61 
62 	/*
63 	 * Comparison with CS_MODE_SYSFS works without taking any device
64 	 * specific spinlock because the truthyness of that comparison can only
65 	 * change with coresight_mutex held, which we already have here.
66 	 */
67 	lockdep_assert_held(&coresight_mutex);
68 	if (coresight_get_mode(csdev) != CS_MODE_SYSFS) {
69 		ret = source_ops(csdev)->enable(csdev, NULL, mode, path);
70 		if (ret)
71 			return ret;
72 	}
73 
74 	csdev->refcnt++;
75 
76 	return 0;
77 }
78 
79 /**
80  *  coresight_disable_source_sysfs - Drop the reference count by 1 and disable
81  *  the device if there are no users left.
82  *
83  *  @csdev: The coresight device to disable
84  *  @data: Opaque data to pass on to the disable function of the source device.
85  *         For example in perf mode this is a pointer to the struct perf_event.
86  *
87  *  Returns true if the device has been disabled.
88  */
89 static bool coresight_disable_source_sysfs(struct coresight_device *csdev,
90 					   void *data)
91 {
92 	lockdep_assert_held(&coresight_mutex);
93 	if (coresight_get_mode(csdev) != CS_MODE_SYSFS)
94 		return false;
95 
96 	csdev->refcnt--;
97 	if (csdev->refcnt == 0) {
98 		coresight_disable_source(csdev, data);
99 		return true;
100 	}
101 	return false;
102 }
103 
104 /**
105  * coresight_find_activated_sysfs_sink - returns the first sink activated via
106  * sysfs using connection based search starting from the source reference.
107  *
108  * @csdev: Coresight source device reference
109  */
110 static struct coresight_device *
111 coresight_find_activated_sysfs_sink(struct coresight_device *csdev)
112 {
113 	int i;
114 	struct coresight_device *sink = NULL;
115 
116 	if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
117 	     csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
118 	     csdev->sysfs_sink_activated)
119 		return csdev;
120 
121 	/*
122 	 * Recursively explore each port found on this element.
123 	 */
124 	for (i = 0; i < csdev->pdata->nr_outconns; i++) {
125 		struct coresight_device *child_dev;
126 
127 		child_dev = csdev->pdata->out_conns[i]->dest_dev;
128 		if (child_dev)
129 			sink = coresight_find_activated_sysfs_sink(child_dev);
130 		if (sink)
131 			return sink;
132 	}
133 
134 	return NULL;
135 }
136 
137 /** coresight_validate_source - make sure a source has the right credentials to
138  *  be used via sysfs.
139  *  @csdev:	the device structure for a source.
140  *  @function:	the function this was called from.
141  *
142  * Assumes the coresight_mutex is held.
143  */
144 static int coresight_validate_source_sysfs(struct coresight_device *csdev,
145 				     const char *function)
146 {
147 	u32 type, subtype;
148 
149 	type = csdev->type;
150 	subtype = csdev->subtype.source_subtype;
151 
152 	if (type != CORESIGHT_DEV_TYPE_SOURCE) {
153 		dev_err(&csdev->dev, "wrong device type in %s\n", function);
154 		return -EINVAL;
155 	}
156 
157 	if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC &&
158 	    subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE &&
159 	    subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM &&
160 	    subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) {
161 		dev_err(&csdev->dev, "wrong device subtype in %s\n", function);
162 		return -EINVAL;
163 	}
164 
165 	return 0;
166 }
167 
168 int coresight_enable_sysfs(struct coresight_device *csdev)
169 {
170 	int cpu, ret = 0;
171 	struct coresight_device *sink;
172 	struct coresight_path *path;
173 	enum coresight_dev_subtype_source subtype;
174 	u32 hash;
175 
176 	subtype = csdev->subtype.source_subtype;
177 
178 	mutex_lock(&coresight_mutex);
179 
180 	ret = coresight_validate_source_sysfs(csdev, __func__);
181 	if (ret)
182 		goto out;
183 
184 	/*
185 	 * mode == SYSFS implies that it's already enabled. Don't look at the
186 	 * refcount to determine this because we don't claim the source until
187 	 * coresight_enable_source() so can still race with Perf mode which
188 	 * doesn't hold coresight_mutex.
189 	 */
190 	if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
191 		/*
192 		 * There could be multiple applications driving the software
193 		 * source. So keep the refcount for each such user when the
194 		 * source is already enabled.
195 		 */
196 		if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
197 			csdev->refcnt++;
198 		goto out;
199 	}
200 
201 	sink = coresight_find_activated_sysfs_sink(csdev);
202 	if (!sink) {
203 		ret = -EINVAL;
204 		goto out;
205 	}
206 
207 	path = coresight_build_path(csdev, sink);
208 	if (IS_ERR(path)) {
209 		pr_err("building path(s) failed\n");
210 		ret = PTR_ERR(path);
211 		goto out;
212 	}
213 
214 	coresight_path_assign_trace_id(path, CS_MODE_SYSFS);
215 	if (!IS_VALID_CS_TRACE_ID(path->trace_id))
216 		goto err_path;
217 
218 	ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
219 	if (ret)
220 		goto err_path;
221 
222 	ret = coresight_enable_source_sysfs(csdev, CS_MODE_SYSFS, path);
223 	if (ret)
224 		goto err_source;
225 
226 	switch (subtype) {
227 	case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
228 		/*
229 		 * When working from sysFS it is important to keep track
230 		 * of the paths that were created so that they can be
231 		 * undone in 'coresight_disable()'.  Since there can only
232 		 * be a single session per tracer (when working from sysFS)
233 		 * a per-cpu variable will do just fine.
234 		 */
235 		cpu = source_ops(csdev)->cpu_id(csdev);
236 		per_cpu(tracer_path, cpu) = path;
237 		break;
238 	case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
239 	case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
240 	case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
241 		/*
242 		 * Use the hash of source's device name as ID
243 		 * and map the ID to the pointer of the path.
244 		 */
245 		hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
246 		ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL);
247 		if (ret)
248 			goto err_source;
249 		break;
250 	default:
251 		/* We can't be here */
252 		break;
253 	}
254 
255 out:
256 	mutex_unlock(&coresight_mutex);
257 	return ret;
258 
259 err_source:
260 	coresight_disable_path(path);
261 
262 err_path:
263 	coresight_release_path(path);
264 	goto out;
265 }
266 EXPORT_SYMBOL_GPL(coresight_enable_sysfs);
267 
268 void coresight_disable_sysfs(struct coresight_device *csdev)
269 {
270 	int cpu, ret;
271 	struct coresight_path *path = NULL;
272 	u32 hash;
273 
274 	mutex_lock(&coresight_mutex);
275 
276 	ret = coresight_validate_source_sysfs(csdev, __func__);
277 	if (ret)
278 		goto out;
279 
280 	if (!coresight_disable_source_sysfs(csdev, NULL))
281 		goto out;
282 
283 	switch (csdev->subtype.source_subtype) {
284 	case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
285 		cpu = source_ops(csdev)->cpu_id(csdev);
286 		path = per_cpu(tracer_path, cpu);
287 		per_cpu(tracer_path, cpu) = NULL;
288 		break;
289 	case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
290 	case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
291 	case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
292 		hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
293 		/* Find the path by the hash. */
294 		path = idr_find(&path_idr, hash);
295 		if (path == NULL) {
296 			pr_err("Path is not found for %s\n", dev_name(&csdev->dev));
297 			goto out;
298 		}
299 		idr_remove(&path_idr, hash);
300 		break;
301 	default:
302 		/* We can't be here */
303 		break;
304 	}
305 
306 	coresight_disable_path(path);
307 	coresight_release_path(path);
308 
309 out:
310 	mutex_unlock(&coresight_mutex);
311 }
312 EXPORT_SYMBOL_GPL(coresight_disable_sysfs);
313 
314 static ssize_t enable_sink_show(struct device *dev,
315 				struct device_attribute *attr, char *buf)
316 {
317 	struct coresight_device *csdev = to_coresight_device(dev);
318 
319 	return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->sysfs_sink_activated);
320 }
321 
322 static ssize_t enable_sink_store(struct device *dev,
323 				 struct device_attribute *attr,
324 				 const char *buf, size_t size)
325 {
326 	int ret;
327 	unsigned long val;
328 	struct coresight_device *csdev = to_coresight_device(dev);
329 
330 	ret = kstrtoul(buf, 10, &val);
331 	if (ret)
332 		return ret;
333 
334 	csdev->sysfs_sink_activated = !!val;
335 
336 	return size;
337 
338 }
339 static DEVICE_ATTR_RW(enable_sink);
340 
341 static ssize_t enable_source_show(struct device *dev,
342 				  struct device_attribute *attr, char *buf)
343 {
344 	struct coresight_device *csdev = to_coresight_device(dev);
345 
346 	guard(mutex)(&coresight_mutex);
347 	return scnprintf(buf, PAGE_SIZE, "%u\n",
348 			 coresight_get_mode(csdev) == CS_MODE_SYSFS);
349 }
350 
351 static ssize_t enable_source_store(struct device *dev,
352 				   struct device_attribute *attr,
353 				   const char *buf, size_t size)
354 {
355 	int ret = 0;
356 	unsigned long val;
357 	struct coresight_device *csdev = to_coresight_device(dev);
358 
359 	ret = kstrtoul(buf, 10, &val);
360 	if (ret)
361 		return ret;
362 
363 	if (val) {
364 		ret = coresight_enable_sysfs(csdev);
365 		if (ret)
366 			return ret;
367 	} else {
368 		coresight_disable_sysfs(csdev);
369 	}
370 
371 	return size;
372 }
373 static DEVICE_ATTR_RW(enable_source);
374 
375 static ssize_t label_show(struct device *dev,
376 		struct device_attribute *attr, char *buf)
377 {
378 
379 	const char *str;
380 	int ret;
381 
382 	ret = fwnode_property_read_string(dev_fwnode(dev), "label", &str);
383 	if (ret == 0)
384 		return sysfs_emit(buf, "%s\n", str);
385 	else
386 		return ret;
387 }
388 static DEVICE_ATTR_RO(label);
389 
390 static umode_t label_is_visible(struct kobject *kobj,
391 				   struct attribute *attr, int n)
392 {
393 	struct device *dev = kobj_to_dev(kobj);
394 
395 	if (attr == &dev_attr_label.attr) {
396 		if (fwnode_property_present(dev_fwnode(dev), "label"))
397 			return attr->mode;
398 		else
399 			return 0;
400 	}
401 
402 	return attr->mode;
403 }
404 
405 static struct attribute *coresight_sink_attrs[] = {
406 	&dev_attr_enable_sink.attr,
407 	&dev_attr_label.attr,
408 	NULL,
409 };
410 
411 static struct attribute_group coresight_sink_group = {
412 	.attrs = coresight_sink_attrs,
413 	.is_visible = label_is_visible,
414 };
415 __ATTRIBUTE_GROUPS(coresight_sink);
416 
417 static struct attribute *coresight_source_attrs[] = {
418 	&dev_attr_enable_source.attr,
419 	&dev_attr_label.attr,
420 	NULL,
421 };
422 
423 static struct attribute_group coresight_source_group = {
424 	.attrs = coresight_source_attrs,
425 	.is_visible = label_is_visible,
426 };
427 __ATTRIBUTE_GROUPS(coresight_source);
428 
429 static struct attribute *coresight_link_attrs[] = {
430 	&dev_attr_label.attr,
431 	NULL,
432 };
433 
434 static struct attribute_group coresight_link_group = {
435 	.attrs = coresight_link_attrs,
436 	.is_visible = label_is_visible,
437 };
438 __ATTRIBUTE_GROUPS(coresight_link);
439 
440 static struct attribute *coresight_helper_attrs[] = {
441 	&dev_attr_label.attr,
442 	NULL,
443 };
444 
445 static struct attribute_group coresight_helper_group = {
446 	.attrs = coresight_helper_attrs,
447 	.is_visible = label_is_visible,
448 };
449 __ATTRIBUTE_GROUPS(coresight_helper);
450 
451 const struct device_type coresight_dev_type[] = {
452 	[CORESIGHT_DEV_TYPE_SINK] = {
453 		.name = "sink",
454 		.groups = coresight_sink_groups,
455 	},
456 	[CORESIGHT_DEV_TYPE_LINK] = {
457 		.name = "link",
458 		.groups = coresight_link_groups,
459 	},
460 	[CORESIGHT_DEV_TYPE_LINKSINK] = {
461 		.name = "linksink",
462 		.groups = coresight_sink_groups,
463 	},
464 	[CORESIGHT_DEV_TYPE_SOURCE] = {
465 		.name = "source",
466 		.groups = coresight_source_groups,
467 	},
468 	[CORESIGHT_DEV_TYPE_HELPER] = {
469 		.name = "helper",
470 		.groups = coresight_helper_groups,
471 	}
472 };
473 /* Ensure the enum matches the names and groups */
474 static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX);
475 
476 /*
477  * Connections group - links attribute.
478  * Count of created links between coresight components in the group.
479  */
480 static ssize_t nr_links_show(struct device *dev,
481 			     struct device_attribute *attr,
482 			     char *buf)
483 {
484 	struct coresight_device *csdev = to_coresight_device(dev);
485 
486 	return sprintf(buf, "%d\n", csdev->nr_links);
487 }
488 static DEVICE_ATTR_RO(nr_links);
489 
490 static struct attribute *coresight_conns_attrs[] = {
491 	&dev_attr_nr_links.attr,
492 	NULL,
493 };
494 
495 static struct attribute_group coresight_conns_group = {
496 	.attrs = coresight_conns_attrs,
497 	.name = "connections",
498 };
499 
500 /*
501  * Create connections group for CoreSight devices.
502  * This group will then be used to collate the sysfs links between
503  * devices.
504  */
505 int coresight_create_conns_sysfs_group(struct coresight_device *csdev)
506 {
507 	int ret = 0;
508 
509 	if (!csdev)
510 		return -EINVAL;
511 
512 	ret = sysfs_create_group(&csdev->dev.kobj, &coresight_conns_group);
513 	if (ret)
514 		return ret;
515 
516 	csdev->has_conns_grp = true;
517 	return ret;
518 }
519 
520 void coresight_remove_conns_sysfs_group(struct coresight_device *csdev)
521 {
522 	if (!csdev)
523 		return;
524 
525 	if (csdev->has_conns_grp) {
526 		sysfs_remove_group(&csdev->dev.kobj, &coresight_conns_group);
527 		csdev->has_conns_grp = false;
528 	}
529 }
530 
531 int coresight_add_sysfs_link(struct coresight_sysfs_link *info)
532 {
533 	int ret = 0;
534 
535 	if (!info)
536 		return -EINVAL;
537 	if (!info->orig || !info->target ||
538 	    !info->orig_name || !info->target_name)
539 		return -EINVAL;
540 	if (!info->orig->has_conns_grp || !info->target->has_conns_grp)
541 		return -EINVAL;
542 
543 	/* first link orig->target */
544 	ret = sysfs_add_link_to_group(&info->orig->dev.kobj,
545 				      coresight_conns_group.name,
546 				      &info->target->dev.kobj,
547 				      info->orig_name);
548 	if (ret)
549 		return ret;
550 
551 	/* second link target->orig */
552 	ret = sysfs_add_link_to_group(&info->target->dev.kobj,
553 				      coresight_conns_group.name,
554 				      &info->orig->dev.kobj,
555 				      info->target_name);
556 
557 	/* error in second link - remove first - otherwise inc counts */
558 	if (ret) {
559 		sysfs_remove_link_from_group(&info->orig->dev.kobj,
560 					     coresight_conns_group.name,
561 					     info->orig_name);
562 	} else {
563 		info->orig->nr_links++;
564 		info->target->nr_links++;
565 	}
566 
567 	return ret;
568 }
569 EXPORT_SYMBOL_GPL(coresight_add_sysfs_link);
570 
571 void coresight_remove_sysfs_link(struct coresight_sysfs_link *info)
572 {
573 	if (!info)
574 		return;
575 	if (!info->orig || !info->target ||
576 	    !info->orig_name || !info->target_name)
577 		return;
578 
579 	sysfs_remove_link_from_group(&info->orig->dev.kobj,
580 				     coresight_conns_group.name,
581 				     info->orig_name);
582 
583 	sysfs_remove_link_from_group(&info->target->dev.kobj,
584 				     coresight_conns_group.name,
585 				     info->target_name);
586 
587 	info->orig->nr_links--;
588 	info->target->nr_links--;
589 }
590 EXPORT_SYMBOL_GPL(coresight_remove_sysfs_link);
591 
592 /*
593  * coresight_make_links: Make a link for a connection from a @orig
594  * device to @target, represented by @conn.
595  *
596  *   e.g, for devOrig[output_X] -> devTarget[input_Y] is represented
597  *   as two symbolic links :
598  *
599  *	/sys/.../devOrig/out:X	-> /sys/.../devTarget/
600  *	/sys/.../devTarget/in:Y	-> /sys/.../devOrig/
601  *
602  * The link names are allocated for a device where it appears. i.e, the
603  * "out" link on the master and "in" link on the slave device.
604  * The link info is stored in the connection record for avoiding
605  * the reconstruction of names for removal.
606  */
607 int coresight_make_links(struct coresight_device *orig,
608 			 struct coresight_connection *conn,
609 			 struct coresight_device *target)
610 {
611 	int ret = -ENOMEM;
612 	char *outs = NULL, *ins = NULL;
613 	struct coresight_sysfs_link *link = NULL;
614 
615 	/* Helper devices aren't shown in sysfs */
616 	if (conn->dest_port == -1 && conn->src_port == -1)
617 		return 0;
618 
619 	do {
620 		outs = devm_kasprintf(&orig->dev, GFP_KERNEL,
621 				      "out:%d", conn->src_port);
622 		if (!outs)
623 			break;
624 		ins = devm_kasprintf(&target->dev, GFP_KERNEL,
625 				     "in:%d", conn->dest_port);
626 		if (!ins)
627 			break;
628 		link = devm_kzalloc(&orig->dev,
629 				    sizeof(struct coresight_sysfs_link),
630 				    GFP_KERNEL);
631 		if (!link)
632 			break;
633 
634 		link->orig = orig;
635 		link->target = target;
636 		link->orig_name = outs;
637 		link->target_name = ins;
638 
639 		ret = coresight_add_sysfs_link(link);
640 		if (ret)
641 			break;
642 
643 		conn->link = link;
644 		return 0;
645 	} while (0);
646 
647 	return ret;
648 }
649 
650 /*
651  * coresight_remove_links: Remove the sysfs links for a given connection @conn,
652  * from @orig device to @target device. See coresight_make_links() for more
653  * details.
654  */
655 void coresight_remove_links(struct coresight_device *orig,
656 			    struct coresight_connection *conn)
657 {
658 	if (!orig || !conn->link)
659 		return;
660 
661 	coresight_remove_sysfs_link(conn->link);
662 
663 	devm_kfree(&conn->dest_dev->dev, conn->link->target_name);
664 	devm_kfree(&orig->dev, conn->link->orig_name);
665 	devm_kfree(&orig->dev, conn->link);
666 	conn->link = NULL;
667 }
668