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