1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright(C) 2015 Linaro Limited. All rights reserved. 4 * Author: Mathieu Poirier <mathieu.poirier@linaro.org> 5 */ 6 7 #include <api/fs/fs.h> 8 #include <linux/bits.h> 9 #include <linux/bitops.h> 10 #include <linux/compiler.h> 11 #include <linux/coresight-pmu.h> 12 #include <linux/kernel.h> 13 #include <linux/log2.h> 14 #include <linux/string.h> 15 #include <linux/types.h> 16 #include <linux/zalloc.h> 17 18 #include "cs-etm.h" 19 #include "../../util/debug.h" 20 #include "../../util/record.h" 21 #include "../../util/auxtrace.h" 22 #include "../../util/cpumap.h" 23 #include "../../util/event.h" 24 #include "../../util/evlist.h" 25 #include "../../util/evsel.h" 26 #include "../../util/perf_api_probe.h" 27 #include "../../util/evsel_config.h" 28 #include "../../util/pmu.h" 29 #include "../../util/cs-etm.h" 30 #include <internal/lib.h> // page_size 31 #include "../../util/session.h" 32 33 #include <errno.h> 34 #include <stdlib.h> 35 #include <sys/stat.h> 36 37 struct cs_etm_recording { 38 struct auxtrace_record itr; 39 struct perf_pmu *cs_etm_pmu; 40 struct evlist *evlist; 41 bool snapshot_mode; 42 size_t snapshot_size; 43 }; 44 45 static const char *metadata_etmv3_ro[CS_ETM_PRIV_MAX] = { 46 [CS_ETM_ETMCCER] = "mgmt/etmccer", 47 [CS_ETM_ETMIDR] = "mgmt/etmidr", 48 }; 49 50 static const char *metadata_etmv4_ro[CS_ETMV4_PRIV_MAX] = { 51 [CS_ETMV4_TRCIDR0] = "trcidr/trcidr0", 52 [CS_ETMV4_TRCIDR1] = "trcidr/trcidr1", 53 [CS_ETMV4_TRCIDR2] = "trcidr/trcidr2", 54 [CS_ETMV4_TRCIDR8] = "trcidr/trcidr8", 55 [CS_ETMV4_TRCAUTHSTATUS] = "mgmt/trcauthstatus", 56 }; 57 58 static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu); 59 60 static int cs_etm_set_context_id(struct auxtrace_record *itr, 61 struct evsel *evsel, int cpu) 62 { 63 struct cs_etm_recording *ptr; 64 struct perf_pmu *cs_etm_pmu; 65 char path[PATH_MAX]; 66 int err = -EINVAL; 67 u32 val; 68 u64 contextid; 69 70 ptr = container_of(itr, struct cs_etm_recording, itr); 71 cs_etm_pmu = ptr->cs_etm_pmu; 72 73 if (!cs_etm_is_etmv4(itr, cpu)) 74 goto out; 75 76 /* Get a handle on TRCIRD2 */ 77 snprintf(path, PATH_MAX, "cpu%d/%s", 78 cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); 79 err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 80 81 /* There was a problem reading the file, bailing out */ 82 if (err != 1) { 83 pr_err("%s: can't read file %s\n", 84 CORESIGHT_ETM_PMU_NAME, path); 85 goto out; 86 } 87 88 /* User has configured for PID tracing, respects it. */ 89 contextid = evsel->core.attr.config & 90 (BIT(ETM_OPT_CTXTID) | BIT(ETM_OPT_CTXTID2)); 91 92 /* 93 * If user doesn't configure the contextid format, parse PMU format and 94 * enable PID tracing according to the "contextid" format bits: 95 * 96 * If bit ETM_OPT_CTXTID is set, trace CONTEXTIDR_EL1; 97 * If bit ETM_OPT_CTXTID2 is set, trace CONTEXTIDR_EL2. 98 */ 99 if (!contextid) 100 contextid = perf_pmu__format_bits(&cs_etm_pmu->format, 101 "contextid"); 102 103 if (contextid & BIT(ETM_OPT_CTXTID)) { 104 /* 105 * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID 106 * tracing is supported: 107 * 0b00000 Context ID tracing is not supported. 108 * 0b00100 Maximum of 32-bit Context ID size. 109 * All other values are reserved. 110 */ 111 val = BMVAL(val, 5, 9); 112 if (!val || val != 0x4) { 113 pr_err("%s: CONTEXTIDR_EL1 isn't supported\n", 114 CORESIGHT_ETM_PMU_NAME); 115 err = -EINVAL; 116 goto out; 117 } 118 } 119 120 if (contextid & BIT(ETM_OPT_CTXTID2)) { 121 /* 122 * TRCIDR2.VMIDOPT[30:29] != 0 and 123 * TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid) 124 * We can't support CONTEXTIDR in VMID if the size of the 125 * virtual context id is < 32bit. 126 * Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us. 127 */ 128 if (!BMVAL(val, 29, 30) || BMVAL(val, 10, 14) < 4) { 129 pr_err("%s: CONTEXTIDR_EL2 isn't supported\n", 130 CORESIGHT_ETM_PMU_NAME); 131 err = -EINVAL; 132 goto out; 133 } 134 } 135 136 /* All good, let the kernel know */ 137 evsel->core.attr.config |= contextid; 138 err = 0; 139 140 out: 141 return err; 142 } 143 144 static int cs_etm_set_timestamp(struct auxtrace_record *itr, 145 struct evsel *evsel, int cpu) 146 { 147 struct cs_etm_recording *ptr; 148 struct perf_pmu *cs_etm_pmu; 149 char path[PATH_MAX]; 150 int err = -EINVAL; 151 u32 val; 152 153 ptr = container_of(itr, struct cs_etm_recording, itr); 154 cs_etm_pmu = ptr->cs_etm_pmu; 155 156 if (!cs_etm_is_etmv4(itr, cpu)) 157 goto out; 158 159 /* Get a handle on TRCIRD0 */ 160 snprintf(path, PATH_MAX, "cpu%d/%s", 161 cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 162 err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 163 164 /* There was a problem reading the file, bailing out */ 165 if (err != 1) { 166 pr_err("%s: can't read file %s\n", 167 CORESIGHT_ETM_PMU_NAME, path); 168 goto out; 169 } 170 171 /* 172 * TRCIDR0.TSSIZE, bit [28-24], indicates whether global timestamping 173 * is supported: 174 * 0b00000 Global timestamping is not implemented 175 * 0b00110 Implementation supports a maximum timestamp of 48bits. 176 * 0b01000 Implementation supports a maximum timestamp of 64bits. 177 */ 178 val &= GENMASK(28, 24); 179 if (!val) { 180 err = -EINVAL; 181 goto out; 182 } 183 184 /* All good, let the kernel know */ 185 evsel->core.attr.config |= (1 << ETM_OPT_TS); 186 err = 0; 187 188 out: 189 return err; 190 } 191 192 #define ETM_SET_OPT_CTXTID (1 << 0) 193 #define ETM_SET_OPT_TS (1 << 1) 194 #define ETM_SET_OPT_MASK (ETM_SET_OPT_CTXTID | ETM_SET_OPT_TS) 195 196 static int cs_etm_set_option(struct auxtrace_record *itr, 197 struct evsel *evsel, u32 option) 198 { 199 int i, err = -EINVAL; 200 struct perf_cpu_map *event_cpus = evsel->evlist->core.cpus; 201 struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); 202 203 /* Set option of each CPU we have */ 204 for (i = 0; i < cpu__max_cpu(); i++) { 205 if (!cpu_map__has(event_cpus, i) || 206 !cpu_map__has(online_cpus, i)) 207 continue; 208 209 if (option & BIT(ETM_OPT_CTXTID)) { 210 err = cs_etm_set_context_id(itr, evsel, i); 211 if (err) 212 goto out; 213 } 214 if (option & BIT(ETM_OPT_TS)) { 215 err = cs_etm_set_timestamp(itr, evsel, i); 216 if (err) 217 goto out; 218 } 219 if (option & ~(BIT(ETM_OPT_CTXTID) | BIT(ETM_OPT_TS))) 220 /* Nothing else is currently supported */ 221 goto out; 222 } 223 224 err = 0; 225 out: 226 perf_cpu_map__put(online_cpus); 227 return err; 228 } 229 230 static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr, 231 struct record_opts *opts, 232 const char *str) 233 { 234 struct cs_etm_recording *ptr = 235 container_of(itr, struct cs_etm_recording, itr); 236 unsigned long long snapshot_size = 0; 237 char *endptr; 238 239 if (str) { 240 snapshot_size = strtoull(str, &endptr, 0); 241 if (*endptr || snapshot_size > SIZE_MAX) 242 return -1; 243 } 244 245 opts->auxtrace_snapshot_mode = true; 246 opts->auxtrace_snapshot_size = snapshot_size; 247 ptr->snapshot_size = snapshot_size; 248 249 return 0; 250 } 251 252 static int cs_etm_set_sink_attr(struct perf_pmu *pmu, 253 struct evsel *evsel) 254 { 255 char msg[BUFSIZ], path[PATH_MAX], *sink; 256 struct evsel_config_term *term; 257 int ret = -EINVAL; 258 u32 hash; 259 260 if (evsel->core.attr.config2 & GENMASK(31, 0)) 261 return 0; 262 263 list_for_each_entry(term, &evsel->config_terms, list) { 264 if (term->type != EVSEL__CONFIG_TERM_DRV_CFG) 265 continue; 266 267 sink = term->val.str; 268 snprintf(path, PATH_MAX, "sinks/%s", sink); 269 270 ret = perf_pmu__scan_file(pmu, path, "%x", &hash); 271 if (ret != 1) { 272 pr_err("failed to set sink \"%s\" on event %s with %d (%s)\n", 273 sink, evsel__name(evsel), errno, 274 str_error_r(errno, msg, sizeof(msg))); 275 return ret; 276 } 277 278 evsel->core.attr.config2 |= hash; 279 return 0; 280 } 281 282 /* 283 * No sink was provided on the command line - allow the CoreSight 284 * system to look for a default 285 */ 286 return 0; 287 } 288 289 static int cs_etm_recording_options(struct auxtrace_record *itr, 290 struct evlist *evlist, 291 struct record_opts *opts) 292 { 293 int ret; 294 struct cs_etm_recording *ptr = 295 container_of(itr, struct cs_etm_recording, itr); 296 struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 297 struct evsel *evsel, *cs_etm_evsel = NULL; 298 struct perf_cpu_map *cpus = evlist->core.cpus; 299 bool privileged = perf_event_paranoid_check(-1); 300 int err = 0; 301 302 ptr->evlist = evlist; 303 ptr->snapshot_mode = opts->auxtrace_snapshot_mode; 304 305 if (!record_opts__no_switch_events(opts) && 306 perf_can_record_switch_events()) 307 opts->record_switch_events = true; 308 309 evlist__for_each_entry(evlist, evsel) { 310 if (evsel->core.attr.type == cs_etm_pmu->type) { 311 if (cs_etm_evsel) { 312 pr_err("There may be only one %s event\n", 313 CORESIGHT_ETM_PMU_NAME); 314 return -EINVAL; 315 } 316 evsel->core.attr.freq = 0; 317 evsel->core.attr.sample_period = 1; 318 cs_etm_evsel = evsel; 319 opts->full_auxtrace = true; 320 } 321 } 322 323 /* no need to continue if at least one event of interest was found */ 324 if (!cs_etm_evsel) 325 return 0; 326 327 ret = cs_etm_set_sink_attr(cs_etm_pmu, cs_etm_evsel); 328 if (ret) 329 return ret; 330 331 if (opts->use_clockid) { 332 pr_err("Cannot use clockid (-k option) with %s\n", 333 CORESIGHT_ETM_PMU_NAME); 334 return -EINVAL; 335 } 336 337 /* we are in snapshot mode */ 338 if (opts->auxtrace_snapshot_mode) { 339 /* 340 * No size were given to '-S' or '-m,', so go with 341 * the default 342 */ 343 if (!opts->auxtrace_snapshot_size && 344 !opts->auxtrace_mmap_pages) { 345 if (privileged) { 346 opts->auxtrace_mmap_pages = MiB(4) / page_size; 347 } else { 348 opts->auxtrace_mmap_pages = 349 KiB(128) / page_size; 350 if (opts->mmap_pages == UINT_MAX) 351 opts->mmap_pages = KiB(256) / page_size; 352 } 353 } else if (!opts->auxtrace_mmap_pages && !privileged && 354 opts->mmap_pages == UINT_MAX) { 355 opts->mmap_pages = KiB(256) / page_size; 356 } 357 358 /* 359 * '-m,xyz' was specified but no snapshot size, so make the 360 * snapshot size as big as the auxtrace mmap area. 361 */ 362 if (!opts->auxtrace_snapshot_size) { 363 opts->auxtrace_snapshot_size = 364 opts->auxtrace_mmap_pages * (size_t)page_size; 365 } 366 367 /* 368 * -Sxyz was specified but no auxtrace mmap area, so make the 369 * auxtrace mmap area big enough to fit the requested snapshot 370 * size. 371 */ 372 if (!opts->auxtrace_mmap_pages) { 373 size_t sz = opts->auxtrace_snapshot_size; 374 375 sz = round_up(sz, page_size) / page_size; 376 opts->auxtrace_mmap_pages = roundup_pow_of_two(sz); 377 } 378 379 /* Snapshot size can't be bigger than the auxtrace area */ 380 if (opts->auxtrace_snapshot_size > 381 opts->auxtrace_mmap_pages * (size_t)page_size) { 382 pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n", 383 opts->auxtrace_snapshot_size, 384 opts->auxtrace_mmap_pages * (size_t)page_size); 385 return -EINVAL; 386 } 387 388 /* Something went wrong somewhere - this shouldn't happen */ 389 if (!opts->auxtrace_snapshot_size || 390 !opts->auxtrace_mmap_pages) { 391 pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n"); 392 return -EINVAL; 393 } 394 } 395 396 /* We are in full trace mode but '-m,xyz' wasn't specified */ 397 if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) { 398 if (privileged) { 399 opts->auxtrace_mmap_pages = MiB(4) / page_size; 400 } else { 401 opts->auxtrace_mmap_pages = KiB(128) / page_size; 402 if (opts->mmap_pages == UINT_MAX) 403 opts->mmap_pages = KiB(256) / page_size; 404 } 405 406 } 407 408 /* Validate auxtrace_mmap_pages provided by user */ 409 if (opts->auxtrace_mmap_pages) { 410 unsigned int max_page = (KiB(128) / page_size); 411 size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size; 412 413 if (!privileged && 414 opts->auxtrace_mmap_pages > max_page) { 415 opts->auxtrace_mmap_pages = max_page; 416 pr_err("auxtrace too big, truncating to %d\n", 417 max_page); 418 } 419 420 if (!is_power_of_2(sz)) { 421 pr_err("Invalid mmap size for %s: must be a power of 2\n", 422 CORESIGHT_ETM_PMU_NAME); 423 return -EINVAL; 424 } 425 } 426 427 if (opts->auxtrace_snapshot_mode) 428 pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME, 429 opts->auxtrace_snapshot_size); 430 431 /* 432 * To obtain the auxtrace buffer file descriptor, the auxtrace 433 * event must come first. 434 */ 435 evlist__to_front(evlist, cs_etm_evsel); 436 437 /* 438 * In the case of per-cpu mmaps, we need the CPU on the 439 * AUX event. We also need the contextID in order to be notified 440 * when a context switch happened. 441 */ 442 if (!perf_cpu_map__empty(cpus)) { 443 evsel__set_sample_bit(cs_etm_evsel, CPU); 444 445 err = cs_etm_set_option(itr, cs_etm_evsel, 446 BIT(ETM_OPT_CTXTID) | BIT(ETM_OPT_TS)); 447 if (err) 448 goto out; 449 } 450 451 /* Add dummy event to keep tracking */ 452 if (opts->full_auxtrace) { 453 struct evsel *tracking_evsel; 454 455 err = parse_events(evlist, "dummy:u", NULL); 456 if (err) 457 goto out; 458 459 tracking_evsel = evlist__last(evlist); 460 evlist__set_tracking_event(evlist, tracking_evsel); 461 462 tracking_evsel->core.attr.freq = 0; 463 tracking_evsel->core.attr.sample_period = 1; 464 465 /* In per-cpu case, always need the time of mmap events etc */ 466 if (!perf_cpu_map__empty(cpus)) 467 evsel__set_sample_bit(tracking_evsel, TIME); 468 } 469 470 out: 471 return err; 472 } 473 474 static u64 cs_etm_get_config(struct auxtrace_record *itr) 475 { 476 u64 config = 0; 477 struct cs_etm_recording *ptr = 478 container_of(itr, struct cs_etm_recording, itr); 479 struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 480 struct evlist *evlist = ptr->evlist; 481 struct evsel *evsel; 482 483 evlist__for_each_entry(evlist, evsel) { 484 if (evsel->core.attr.type == cs_etm_pmu->type) { 485 /* 486 * Variable perf_event_attr::config is assigned to 487 * ETMv3/PTM. The bit fields have been made to match 488 * the ETMv3.5 ETRMCR register specification. See the 489 * PMU_FORMAT_ATTR() declarations in 490 * drivers/hwtracing/coresight/coresight-perf.c for 491 * details. 492 */ 493 config = evsel->core.attr.config; 494 break; 495 } 496 } 497 498 return config; 499 } 500 501 #ifndef BIT 502 #define BIT(N) (1UL << (N)) 503 #endif 504 505 static u64 cs_etmv4_get_config(struct auxtrace_record *itr) 506 { 507 u64 config = 0; 508 u64 config_opts = 0; 509 510 /* 511 * The perf event variable config bits represent both 512 * the command line options and register programming 513 * bits in ETMv3/PTM. For ETMv4 we must remap options 514 * to real bits 515 */ 516 config_opts = cs_etm_get_config(itr); 517 if (config_opts & BIT(ETM_OPT_CYCACC)) 518 config |= BIT(ETM4_CFG_BIT_CYCACC); 519 if (config_opts & BIT(ETM_OPT_CTXTID)) 520 config |= BIT(ETM4_CFG_BIT_CTXTID); 521 if (config_opts & BIT(ETM_OPT_TS)) 522 config |= BIT(ETM4_CFG_BIT_TS); 523 if (config_opts & BIT(ETM_OPT_RETSTK)) 524 config |= BIT(ETM4_CFG_BIT_RETSTK); 525 if (config_opts & BIT(ETM_OPT_CTXTID2)) 526 config |= BIT(ETM4_CFG_BIT_VMID) | 527 BIT(ETM4_CFG_BIT_VMID_OPT); 528 return config; 529 } 530 531 static size_t 532 cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, 533 struct evlist *evlist __maybe_unused) 534 { 535 int i; 536 int etmv3 = 0, etmv4 = 0; 537 struct perf_cpu_map *event_cpus = evlist->core.cpus; 538 struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); 539 540 /* cpu map is not empty, we have specific CPUs to work with */ 541 if (!perf_cpu_map__empty(event_cpus)) { 542 for (i = 0; i < cpu__max_cpu(); i++) { 543 if (!cpu_map__has(event_cpus, i) || 544 !cpu_map__has(online_cpus, i)) 545 continue; 546 547 if (cs_etm_is_etmv4(itr, i)) 548 etmv4++; 549 else 550 etmv3++; 551 } 552 } else { 553 /* get configuration for all CPUs in the system */ 554 for (i = 0; i < cpu__max_cpu(); i++) { 555 if (!cpu_map__has(online_cpus, i)) 556 continue; 557 558 if (cs_etm_is_etmv4(itr, i)) 559 etmv4++; 560 else 561 etmv3++; 562 } 563 } 564 565 perf_cpu_map__put(online_cpus); 566 567 return (CS_ETM_HEADER_SIZE + 568 (etmv4 * CS_ETMV4_PRIV_SIZE) + 569 (etmv3 * CS_ETMV3_PRIV_SIZE)); 570 } 571 572 static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu) 573 { 574 bool ret = false; 575 char path[PATH_MAX]; 576 int scan; 577 unsigned int val; 578 struct cs_etm_recording *ptr = 579 container_of(itr, struct cs_etm_recording, itr); 580 struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 581 582 /* Take any of the RO files for ETMv4 and see if it present */ 583 snprintf(path, PATH_MAX, "cpu%d/%s", 584 cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 585 scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 586 587 /* The file was read successfully, we have a winner */ 588 if (scan == 1) 589 ret = true; 590 591 return ret; 592 } 593 594 static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path) 595 { 596 char pmu_path[PATH_MAX]; 597 int scan; 598 unsigned int val = 0; 599 600 /* Get RO metadata from sysfs */ 601 snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 602 603 scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val); 604 if (scan != 1) 605 pr_err("%s: error reading: %s\n", __func__, pmu_path); 606 607 return val; 608 } 609 610 static void cs_etm_get_metadata(int cpu, u32 *offset, 611 struct auxtrace_record *itr, 612 struct perf_record_auxtrace_info *info) 613 { 614 u32 increment, nr_trc_params; 615 u64 magic; 616 struct cs_etm_recording *ptr = 617 container_of(itr, struct cs_etm_recording, itr); 618 struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 619 620 /* first see what kind of tracer this cpu is affined to */ 621 if (cs_etm_is_etmv4(itr, cpu)) { 622 magic = __perf_cs_etmv4_magic; 623 /* Get trace configuration register */ 624 info->priv[*offset + CS_ETMV4_TRCCONFIGR] = 625 cs_etmv4_get_config(itr); 626 /* Get traceID from the framework */ 627 info->priv[*offset + CS_ETMV4_TRCTRACEIDR] = 628 coresight_get_trace_id(cpu); 629 /* Get read-only information from sysFS */ 630 info->priv[*offset + CS_ETMV4_TRCIDR0] = 631 cs_etm_get_ro(cs_etm_pmu, cpu, 632 metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 633 info->priv[*offset + CS_ETMV4_TRCIDR1] = 634 cs_etm_get_ro(cs_etm_pmu, cpu, 635 metadata_etmv4_ro[CS_ETMV4_TRCIDR1]); 636 info->priv[*offset + CS_ETMV4_TRCIDR2] = 637 cs_etm_get_ro(cs_etm_pmu, cpu, 638 metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); 639 info->priv[*offset + CS_ETMV4_TRCIDR8] = 640 cs_etm_get_ro(cs_etm_pmu, cpu, 641 metadata_etmv4_ro[CS_ETMV4_TRCIDR8]); 642 info->priv[*offset + CS_ETMV4_TRCAUTHSTATUS] = 643 cs_etm_get_ro(cs_etm_pmu, cpu, 644 metadata_etmv4_ro 645 [CS_ETMV4_TRCAUTHSTATUS]); 646 647 /* How much space was used */ 648 increment = CS_ETMV4_PRIV_MAX; 649 nr_trc_params = CS_ETMV4_PRIV_MAX - CS_ETMV4_TRCCONFIGR; 650 } else { 651 magic = __perf_cs_etmv3_magic; 652 /* Get configuration register */ 653 info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr); 654 /* Get traceID from the framework */ 655 info->priv[*offset + CS_ETM_ETMTRACEIDR] = 656 coresight_get_trace_id(cpu); 657 /* Get read-only information from sysFS */ 658 info->priv[*offset + CS_ETM_ETMCCER] = 659 cs_etm_get_ro(cs_etm_pmu, cpu, 660 metadata_etmv3_ro[CS_ETM_ETMCCER]); 661 info->priv[*offset + CS_ETM_ETMIDR] = 662 cs_etm_get_ro(cs_etm_pmu, cpu, 663 metadata_etmv3_ro[CS_ETM_ETMIDR]); 664 665 /* How much space was used */ 666 increment = CS_ETM_PRIV_MAX; 667 nr_trc_params = CS_ETM_PRIV_MAX - CS_ETM_ETMCR; 668 } 669 670 /* Build generic header portion */ 671 info->priv[*offset + CS_ETM_MAGIC] = magic; 672 info->priv[*offset + CS_ETM_CPU] = cpu; 673 info->priv[*offset + CS_ETM_NR_TRC_PARAMS] = nr_trc_params; 674 /* Where the next CPU entry should start from */ 675 *offset += increment; 676 } 677 678 static int cs_etm_info_fill(struct auxtrace_record *itr, 679 struct perf_session *session, 680 struct perf_record_auxtrace_info *info, 681 size_t priv_size) 682 { 683 int i; 684 u32 offset; 685 u64 nr_cpu, type; 686 struct perf_cpu_map *cpu_map; 687 struct perf_cpu_map *event_cpus = session->evlist->core.cpus; 688 struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); 689 struct cs_etm_recording *ptr = 690 container_of(itr, struct cs_etm_recording, itr); 691 struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 692 693 if (priv_size != cs_etm_info_priv_size(itr, session->evlist)) 694 return -EINVAL; 695 696 if (!session->evlist->core.nr_mmaps) 697 return -EINVAL; 698 699 /* If the cpu_map is empty all online CPUs are involved */ 700 if (perf_cpu_map__empty(event_cpus)) { 701 cpu_map = online_cpus; 702 } else { 703 /* Make sure all specified CPUs are online */ 704 for (i = 0; i < perf_cpu_map__nr(event_cpus); i++) { 705 if (cpu_map__has(event_cpus, i) && 706 !cpu_map__has(online_cpus, i)) 707 return -EINVAL; 708 } 709 710 cpu_map = event_cpus; 711 } 712 713 nr_cpu = perf_cpu_map__nr(cpu_map); 714 /* Get PMU type as dynamically assigned by the core */ 715 type = cs_etm_pmu->type; 716 717 /* First fill out the session header */ 718 info->type = PERF_AUXTRACE_CS_ETM; 719 info->priv[CS_HEADER_VERSION] = CS_HEADER_CURRENT_VERSION; 720 info->priv[CS_PMU_TYPE_CPUS] = type << 32; 721 info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu; 722 info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode; 723 724 offset = CS_ETM_SNAPSHOT + 1; 725 726 for (i = 0; i < cpu__max_cpu() && offset < priv_size; i++) 727 if (cpu_map__has(cpu_map, i)) 728 cs_etm_get_metadata(i, &offset, itr, info); 729 730 perf_cpu_map__put(online_cpus); 731 732 return 0; 733 } 734 735 static int cs_etm_snapshot_start(struct auxtrace_record *itr) 736 { 737 struct cs_etm_recording *ptr = 738 container_of(itr, struct cs_etm_recording, itr); 739 struct evsel *evsel; 740 741 evlist__for_each_entry(ptr->evlist, evsel) { 742 if (evsel->core.attr.type == ptr->cs_etm_pmu->type) 743 return evsel__disable(evsel); 744 } 745 return -EINVAL; 746 } 747 748 static int cs_etm_snapshot_finish(struct auxtrace_record *itr) 749 { 750 struct cs_etm_recording *ptr = 751 container_of(itr, struct cs_etm_recording, itr); 752 struct evsel *evsel; 753 754 evlist__for_each_entry(ptr->evlist, evsel) { 755 if (evsel->core.attr.type == ptr->cs_etm_pmu->type) 756 return evsel__enable(evsel); 757 } 758 return -EINVAL; 759 } 760 761 static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused) 762 { 763 return (((u64) rand() << 0) & 0x00000000FFFFFFFFull) | 764 (((u64) rand() << 32) & 0xFFFFFFFF00000000ull); 765 } 766 767 static void cs_etm_recording_free(struct auxtrace_record *itr) 768 { 769 struct cs_etm_recording *ptr = 770 container_of(itr, struct cs_etm_recording, itr); 771 772 free(ptr); 773 } 774 775 struct auxtrace_record *cs_etm_record_init(int *err) 776 { 777 struct perf_pmu *cs_etm_pmu; 778 struct cs_etm_recording *ptr; 779 780 cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME); 781 782 if (!cs_etm_pmu) { 783 *err = -EINVAL; 784 goto out; 785 } 786 787 ptr = zalloc(sizeof(struct cs_etm_recording)); 788 if (!ptr) { 789 *err = -ENOMEM; 790 goto out; 791 } 792 793 ptr->cs_etm_pmu = cs_etm_pmu; 794 ptr->itr.pmu = cs_etm_pmu; 795 ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options; 796 ptr->itr.recording_options = cs_etm_recording_options; 797 ptr->itr.info_priv_size = cs_etm_info_priv_size; 798 ptr->itr.info_fill = cs_etm_info_fill; 799 ptr->itr.snapshot_start = cs_etm_snapshot_start; 800 ptr->itr.snapshot_finish = cs_etm_snapshot_finish; 801 ptr->itr.reference = cs_etm_reference; 802 ptr->itr.free = cs_etm_recording_free; 803 ptr->itr.read_finish = auxtrace_record__read_finish; 804 805 *err = 0; 806 return &ptr->itr; 807 out: 808 return NULL; 809 } 810