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