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