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