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 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, 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 */ 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 * 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 */ 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 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 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 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 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 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 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 */ 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 */ 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 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 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 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 */ 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 */ 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