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
coresight_simple_show_pair(struct device * _dev,struct device_attribute * attr,char * buf)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
coresight_simple_show32(struct device * _dev,struct device_attribute * attr,char * buf)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
coresight_enable_source_sysfs(struct coresight_device * csdev,enum cs_mode mode,struct coresight_path * path)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 */
coresight_disable_source_sysfs(struct coresight_device * csdev,void * data)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 *
coresight_find_activated_sysfs_sink(struct coresight_device * csdev)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 */
coresight_validate_source_sysfs(struct coresight_device * csdev,const char * function)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
coresight_enable_sysfs(struct coresight_device * csdev)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);
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
coresight_disable_sysfs(struct coresight_device * csdev)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
enable_sink_show(struct device * dev,struct device_attribute * attr,char * buf)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
enable_sink_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)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
enable_source_show(struct device * dev,struct device_attribute * attr,char * buf)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
enable_source_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)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
label_show(struct device * dev,struct device_attribute * attr,char * buf)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
label_is_visible(struct kobject * kobj,struct attribute * attr,int n)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 */
nr_links_show(struct device * dev,struct device_attribute * attr,char * buf)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 */
coresight_create_conns_sysfs_group(struct coresight_device * csdev)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
coresight_remove_conns_sysfs_group(struct coresight_device * csdev)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
coresight_add_sysfs_link(struct coresight_sysfs_link * info)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
coresight_remove_sysfs_link(struct coresight_sysfs_link * info)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 */
coresight_make_links(struct coresight_device * orig,struct coresight_connection * conn,struct coresight_device * target)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 */
coresight_remove_links(struct coresight_device * orig,struct coresight_connection * conn)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