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

source code of linux/tools/perf/arch/arm/util/cs-etm.c