1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright(C) 2015 Linaro Limited. All rights reserved.
4 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
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>
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"
37 struct cs_etm_recording
{
38 struct auxtrace_record itr
;
39 struct perf_pmu
*cs_etm_pmu
;
40 struct evlist
*evlist
;
45 static const char *metadata_etmv3_ro
[CS_ETM_PRIV_MAX
] = {
46 [CS_ETM_ETMCCER
] = "mgmt/etmccer",
47 [CS_ETM_ETMIDR
] = "mgmt/etmidr",
50 static 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",
59 static 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",
69 enum cs_etm_version
{ CS_NOT_PRESENT
, CS_ETMV3
, CS_ETMV4
, CS_ETE
};
71 static bool cs_etm_is_ete(struct perf_pmu
*cs_etm_pmu
, struct perf_cpu cpu
);
72 static int cs_etm_get_ro(struct perf_pmu
*pmu
, struct perf_cpu cpu
, const char *path
, __u64
*val
);
73 static bool cs_etm_pmu_path_exists(struct perf_pmu
*pmu
, struct perf_cpu cpu
, const char *path
);
75 static enum cs_etm_version
cs_etm_get_version(struct perf_pmu
*cs_etm_pmu
,
78 if (cs_etm_is_ete(cs_etm_pmu
, cpu
))
80 else if (cs_etm_pmu_path_exists(cs_etm_pmu
, cpu
, metadata_etmv4_ro
[CS_ETMV4_TRCIDR0
]))
82 else if (cs_etm_pmu_path_exists(cs_etm_pmu
, cpu
, metadata_etmv3_ro
[CS_ETM_ETMCCER
]))
85 return CS_NOT_PRESENT
;
88 static int cs_etm_validate_context_id(struct perf_pmu
*cs_etm_pmu
, struct evsel
*evsel
,
93 u64 contextid
= evsel
->core
.attr
.config
&
94 (perf_pmu__format_bits(cs_etm_pmu
, "contextid") |
95 perf_pmu__format_bits(cs_etm_pmu
, "contextid1") |
96 perf_pmu__format_bits(cs_etm_pmu
, "contextid2"));
101 /* Not supported in etmv3 */
102 if (cs_etm_get_version(cs_etm_pmu
, cpu
) == CS_ETMV3
) {
103 pr_err("%s: contextid not supported in ETMv3, disable with %s/contextid=0/\n",
104 CORESIGHT_ETM_PMU_NAME
, CORESIGHT_ETM_PMU_NAME
);
108 /* Get a handle on TRCIDR2 */
109 err
= cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_etmv4_ro
[CS_ETMV4_TRCIDR2
], &val
);
114 perf_pmu__format_bits(cs_etm_pmu
, "contextid1")) {
116 * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID
117 * tracing is supported:
118 * 0b00000 Context ID tracing is not supported.
119 * 0b00100 Maximum of 32-bit Context ID size.
120 * All other values are reserved.
122 if (BMVAL(val
, 5, 9) != 0x4) {
123 pr_err("%s: CONTEXTIDR_EL1 isn't supported, disable with %s/contextid1=0/\n",
124 CORESIGHT_ETM_PMU_NAME
, CORESIGHT_ETM_PMU_NAME
);
130 perf_pmu__format_bits(cs_etm_pmu
, "contextid2")) {
132 * TRCIDR2.VMIDOPT[30:29] != 0 and
133 * TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid)
134 * We can't support CONTEXTIDR in VMID if the size of the
135 * virtual context id is < 32bit.
136 * Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us.
138 if (!BMVAL(val
, 29, 30) || BMVAL(val
, 10, 14) < 4) {
139 pr_err("%s: CONTEXTIDR_EL2 isn't supported, disable with %s/contextid2=0/\n",
140 CORESIGHT_ETM_PMU_NAME
, CORESIGHT_ETM_PMU_NAME
);
148 static int cs_etm_validate_timestamp(struct perf_pmu
*cs_etm_pmu
, struct evsel
*evsel
,
154 if (!(evsel
->core
.attr
.config
&
155 perf_pmu__format_bits(cs_etm_pmu
, "timestamp")))
158 if (cs_etm_get_version(cs_etm_pmu
, cpu
) == CS_ETMV3
) {
159 pr_err("%s: timestamp not supported in ETMv3, disable with %s/timestamp=0/\n",
160 CORESIGHT_ETM_PMU_NAME
, CORESIGHT_ETM_PMU_NAME
);
164 /* Get a handle on TRCIRD0 */
165 err
= cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_etmv4_ro
[CS_ETMV4_TRCIDR0
], &val
);
170 * TRCIDR0.TSSIZE, bit [28-24], indicates whether global timestamping
172 * 0b00000 Global timestamping is not implemented
173 * 0b00110 Implementation supports a maximum timestamp of 48bits.
174 * 0b01000 Implementation supports a maximum timestamp of 64bits.
176 val
&= GENMASK(28, 24);
184 static struct perf_pmu
*cs_etm_get_pmu(struct auxtrace_record
*itr
)
186 struct cs_etm_recording
*ptr
= container_of(itr
, struct cs_etm_recording
, itr
);
188 return ptr
->cs_etm_pmu
;
192 * Check whether the requested timestamp and contextid options should be
193 * available on all requested CPUs and if not, tell the user how to override.
194 * The kernel will silently disable any unavailable options so a warning here
195 * first is better. In theory the kernel could still disable the option for
196 * some other reason so this is best effort only.
198 static int cs_etm_validate_config(struct perf_pmu
*cs_etm_pmu
,
202 struct perf_cpu_map
*event_cpus
= evsel
->evlist
->core
.user_requested_cpus
;
203 struct perf_cpu_map
*intersect_cpus
;
207 * Set option of each CPU we have. In per-cpu case, do the validation
208 * for CPUs to work with. In per-thread case, the CPU map has the "any"
209 * CPU value. Since the traced program can run on any CPUs in this case,
210 * thus don't skip validation.
212 if (!perf_cpu_map__has_any_cpu(event_cpus
)) {
213 struct perf_cpu_map
*online_cpus
= perf_cpu_map__new_online_cpus();
215 intersect_cpus
= perf_cpu_map__intersect(event_cpus
, online_cpus
);
216 perf_cpu_map__put(online_cpus
);
218 intersect_cpus
= perf_cpu_map__new_online_cpus();
221 perf_cpu_map__for_each_cpu_skip_any(cpu
, idx
, intersect_cpus
) {
222 if (cs_etm_get_version(cs_etm_pmu
, cpu
) == CS_NOT_PRESENT
) {
223 pr_err("%s: Not found on CPU %d. Check hardware and firmware support and that all Coresight drivers are loaded\n",
224 CORESIGHT_ETM_PMU_NAME
, cpu
.cpu
);
227 err
= cs_etm_validate_context_id(cs_etm_pmu
, evsel
, cpu
);
231 err
= cs_etm_validate_timestamp(cs_etm_pmu
, evsel
, cpu
);
236 perf_cpu_map__put(intersect_cpus
);
240 static int cs_etm_parse_snapshot_options(struct auxtrace_record
*itr
,
241 struct record_opts
*opts
,
244 struct cs_etm_recording
*ptr
=
245 container_of(itr
, struct cs_etm_recording
, itr
);
246 unsigned long long snapshot_size
= 0;
250 snapshot_size
= strtoull(str
, &endptr
, 0);
251 if (*endptr
|| snapshot_size
> SIZE_MAX
)
255 opts
->auxtrace_snapshot_mode
= true;
256 opts
->auxtrace_snapshot_size
= snapshot_size
;
257 ptr
->snapshot_size
= snapshot_size
;
262 static int cs_etm_set_sink_attr(struct perf_pmu
*pmu
,
265 char msg
[BUFSIZ
], path
[PATH_MAX
], *sink
;
266 struct evsel_config_term
*term
;
270 if (evsel
->core
.attr
.config2
& GENMASK(31, 0))
273 list_for_each_entry(term
, &evsel
->config_terms
, list
) {
274 if (term
->type
!= EVSEL__CONFIG_TERM_DRV_CFG
)
277 sink
= term
->val
.str
;
278 snprintf(path
, PATH_MAX
, "sinks/%s", sink
);
280 ret
= perf_pmu__scan_file(pmu
, path
, "%x", &hash
);
283 pr_err("Couldn't find sink \"%s\" on event %s\n"
284 "Missing kernel or device support?\n\n"
285 "Hint: An appropriate sink will be picked automatically if one isn't specified.\n",
286 sink
, evsel__name(evsel
));
288 pr_err("Failed to set sink \"%s\" on event %s with %d (%s)\n",
289 sink
, evsel__name(evsel
), errno
,
290 str_error_r(errno
, msg
, sizeof(msg
)));
294 evsel
->core
.attr
.config2
|= hash
;
299 * No sink was provided on the command line - allow the CoreSight
300 * system to look for a default
305 static int cs_etm_recording_options(struct auxtrace_record
*itr
,
306 struct evlist
*evlist
,
307 struct record_opts
*opts
)
310 struct cs_etm_recording
*ptr
=
311 container_of(itr
, struct cs_etm_recording
, itr
);
312 struct perf_pmu
*cs_etm_pmu
= ptr
->cs_etm_pmu
;
313 struct evsel
*evsel
, *cs_etm_evsel
= NULL
;
314 struct perf_cpu_map
*cpus
= evlist
->core
.user_requested_cpus
;
315 bool privileged
= perf_event_paranoid_check(-1);
318 evlist__for_each_entry(evlist
, evsel
) {
319 if (evsel
->core
.attr
.type
== cs_etm_pmu
->type
) {
321 pr_err("There may be only one %s event\n",
322 CORESIGHT_ETM_PMU_NAME
);
325 cs_etm_evsel
= evsel
;
329 /* no need to continue if at least one event of interest was found */
333 ptr
->evlist
= evlist
;
334 ptr
->snapshot_mode
= opts
->auxtrace_snapshot_mode
;
336 if (!record_opts__no_switch_events(opts
) &&
337 perf_can_record_switch_events())
338 opts
->record_switch_events
= true;
340 cs_etm_evsel
->needs_auxtrace_mmap
= true;
341 opts
->full_auxtrace
= true;
343 ret
= cs_etm_set_sink_attr(cs_etm_pmu
, cs_etm_evsel
);
347 if (opts
->use_clockid
) {
348 pr_err("Cannot use clockid (-k option) with %s\n",
349 CORESIGHT_ETM_PMU_NAME
);
353 /* we are in snapshot mode */
354 if (opts
->auxtrace_snapshot_mode
) {
356 * No size were given to '-S' or '-m,', so go with
359 if (!opts
->auxtrace_snapshot_size
&&
360 !opts
->auxtrace_mmap_pages
) {
362 opts
->auxtrace_mmap_pages
= MiB(4) / page_size
;
364 opts
->auxtrace_mmap_pages
=
365 KiB(128) / page_size
;
366 if (opts
->mmap_pages
== UINT_MAX
)
367 opts
->mmap_pages
= KiB(256) / page_size
;
369 } else if (!opts
->auxtrace_mmap_pages
&& !privileged
&&
370 opts
->mmap_pages
== UINT_MAX
) {
371 opts
->mmap_pages
= KiB(256) / page_size
;
375 * '-m,xyz' was specified but no snapshot size, so make the
376 * snapshot size as big as the auxtrace mmap area.
378 if (!opts
->auxtrace_snapshot_size
) {
379 opts
->auxtrace_snapshot_size
=
380 opts
->auxtrace_mmap_pages
* (size_t)page_size
;
384 * -Sxyz was specified but no auxtrace mmap area, so make the
385 * auxtrace mmap area big enough to fit the requested snapshot
388 if (!opts
->auxtrace_mmap_pages
) {
389 size_t sz
= opts
->auxtrace_snapshot_size
;
391 sz
= round_up(sz
, page_size
) / page_size
;
392 opts
->auxtrace_mmap_pages
= roundup_pow_of_two(sz
);
395 /* Snapshot size can't be bigger than the auxtrace area */
396 if (opts
->auxtrace_snapshot_size
>
397 opts
->auxtrace_mmap_pages
* (size_t)page_size
) {
398 pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n",
399 opts
->auxtrace_snapshot_size
,
400 opts
->auxtrace_mmap_pages
* (size_t)page_size
);
404 /* Something went wrong somewhere - this shouldn't happen */
405 if (!opts
->auxtrace_snapshot_size
||
406 !opts
->auxtrace_mmap_pages
) {
407 pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n");
412 /* Buffer sizes weren't specified with '-m,xyz' so give some defaults */
413 if (!opts
->auxtrace_mmap_pages
) {
415 opts
->auxtrace_mmap_pages
= MiB(4) / page_size
;
417 opts
->auxtrace_mmap_pages
= KiB(128) / page_size
;
418 if (opts
->mmap_pages
== UINT_MAX
)
419 opts
->mmap_pages
= KiB(256) / page_size
;
423 if (opts
->auxtrace_snapshot_mode
)
424 pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME
,
425 opts
->auxtrace_snapshot_size
);
428 * To obtain the auxtrace buffer file descriptor, the auxtrace
429 * event must come first.
431 evlist__to_front(evlist
, cs_etm_evsel
);
434 * get the CPU on the sample - need it to associate trace ID in the
435 * AUX_OUTPUT_HW_ID event, and the AUX event for per-cpu mmaps.
437 evsel__set_sample_bit(cs_etm_evsel
, CPU
);
440 * Also the case of per-cpu mmaps, need the contextID in order to be notified
441 * when a context switch happened.
443 if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus
)) {
444 evsel__set_config_if_unset(cs_etm_pmu
, cs_etm_evsel
,
446 evsel__set_config_if_unset(cs_etm_pmu
, cs_etm_evsel
,
451 * When the option '--timestamp' or '-T' is enabled, the PERF_SAMPLE_TIME
452 * bit is set for all events. In this case, always enable Arm CoreSight
455 if (opts
->sample_time_set
)
456 evsel__set_config_if_unset(cs_etm_pmu
, cs_etm_evsel
,
459 /* Add dummy event to keep tracking */
460 err
= parse_event(evlist
, "dummy:u");
463 evsel
= evlist__last(evlist
);
464 evlist__set_tracking_event(evlist
, evsel
);
465 evsel
->core
.attr
.freq
= 0;
466 evsel
->core
.attr
.sample_period
= 1;
468 /* In per-cpu case, always need the time of mmap events etc */
469 if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus
))
470 evsel__set_sample_bit(evsel
, TIME
);
472 err
= cs_etm_validate_config(cs_etm_pmu
, cs_etm_evsel
);
477 static u64
cs_etm_get_config(struct auxtrace_record
*itr
)
480 struct cs_etm_recording
*ptr
=
481 container_of(itr
, struct cs_etm_recording
, itr
);
482 struct perf_pmu
*cs_etm_pmu
= ptr
->cs_etm_pmu
;
483 struct evlist
*evlist
= ptr
->evlist
;
486 evlist__for_each_entry(evlist
, evsel
) {
487 if (evsel
->core
.attr
.type
== cs_etm_pmu
->type
) {
489 * Variable perf_event_attr::config is assigned to
490 * ETMv3/PTM. The bit fields have been made to match
491 * the ETMv3.5 ETRMCR register specification. See the
492 * PMU_FORMAT_ATTR() declarations in
493 * drivers/hwtracing/coresight/coresight-perf.c for
496 config
= evsel
->core
.attr
.config
;
505 #define BIT(N) (1UL << (N))
508 static u64
cs_etmv4_get_config(struct auxtrace_record
*itr
)
514 * The perf event variable config bits represent both
515 * the command line options and register programming
516 * bits in ETMv3/PTM. For ETMv4 we must remap options
519 config_opts
= cs_etm_get_config(itr
);
520 if (config_opts
& BIT(ETM_OPT_CYCACC
))
521 config
|= BIT(ETM4_CFG_BIT_CYCACC
);
522 if (config_opts
& BIT(ETM_OPT_CTXTID
))
523 config
|= BIT(ETM4_CFG_BIT_CTXTID
);
524 if (config_opts
& BIT(ETM_OPT_TS
))
525 config
|= BIT(ETM4_CFG_BIT_TS
);
526 if (config_opts
& BIT(ETM_OPT_RETSTK
))
527 config
|= BIT(ETM4_CFG_BIT_RETSTK
);
528 if (config_opts
& BIT(ETM_OPT_CTXTID2
))
529 config
|= BIT(ETM4_CFG_BIT_VMID
) |
530 BIT(ETM4_CFG_BIT_VMID_OPT
);
531 if (config_opts
& BIT(ETM_OPT_BRANCH_BROADCAST
))
532 config
|= BIT(ETM4_CFG_BIT_BB
);
538 cs_etm_info_priv_size(struct auxtrace_record
*itr
,
539 struct evlist
*evlist
)
542 int etmv3
= 0, etmv4
= 0, ete
= 0;
543 struct perf_cpu_map
*event_cpus
= evlist
->core
.user_requested_cpus
;
544 struct perf_cpu_map
*intersect_cpus
;
546 struct perf_pmu
*cs_etm_pmu
= cs_etm_get_pmu(itr
);
548 if (!perf_cpu_map__has_any_cpu(event_cpus
)) {
549 /* cpu map is not "any" CPU , we have specific CPUs to work with */
550 struct perf_cpu_map
*online_cpus
= perf_cpu_map__new_online_cpus();
552 intersect_cpus
= perf_cpu_map__intersect(event_cpus
, online_cpus
);
553 perf_cpu_map__put(online_cpus
);
555 /* Event can be "any" CPU so count all online CPUs. */
556 intersect_cpus
= perf_cpu_map__new_online_cpus();
558 /* Count number of each type of ETM. Don't count if that CPU has CS_NOT_PRESENT. */
559 perf_cpu_map__for_each_cpu_skip_any(cpu
, idx
, intersect_cpus
) {
560 enum cs_etm_version v
= cs_etm_get_version(cs_etm_pmu
, cpu
);
563 etmv4
+= v
== CS_ETMV4
;
564 etmv3
+= v
== CS_ETMV3
;
566 perf_cpu_map__put(intersect_cpus
);
568 return (CS_ETM_HEADER_SIZE
+
569 (ete
* CS_ETE_PRIV_SIZE
) +
570 (etmv4
* CS_ETMV4_PRIV_SIZE
) +
571 (etmv3
* CS_ETMV3_PRIV_SIZE
));
574 static int cs_etm_get_ro(struct perf_pmu
*pmu
, struct perf_cpu cpu
, const char *path
, __u64
*val
)
576 char pmu_path
[PATH_MAX
];
579 /* Get RO metadata from sysfs */
580 snprintf(pmu_path
, PATH_MAX
, "cpu%d/%s", cpu
.cpu
, path
);
582 scan
= perf_pmu__scan_file(pmu
, pmu_path
, "%llx", val
);
584 pr_err("%s: error reading: %s\n", __func__
, pmu_path
);
591 static int cs_etm_get_ro_signed(struct perf_pmu
*pmu
, struct perf_cpu cpu
, const char *path
,
594 char pmu_path
[PATH_MAX
];
598 /* Get RO metadata from sysfs */
599 snprintf(pmu_path
, PATH_MAX
, "cpu%d/%s", cpu
.cpu
, path
);
601 scan
= perf_pmu__scan_file(pmu
, pmu_path
, "%d", &val
);
603 pr_err("%s: error reading: %s\n", __func__
, pmu_path
);
607 *out_val
= (__u64
) val
;
611 static bool cs_etm_pmu_path_exists(struct perf_pmu
*pmu
, struct perf_cpu cpu
, const char *path
)
613 char pmu_path
[PATH_MAX
];
615 /* Get RO metadata from sysfs */
616 snprintf(pmu_path
, PATH_MAX
, "cpu%d/%s", cpu
.cpu
, path
);
618 return perf_pmu__file_exists(pmu
, pmu_path
);
621 #define TRCDEVARCH_ARCHPART_SHIFT 0
622 #define TRCDEVARCH_ARCHPART_MASK GENMASK(11, 0)
623 #define TRCDEVARCH_ARCHPART(x) (((x) & TRCDEVARCH_ARCHPART_MASK) >> TRCDEVARCH_ARCHPART_SHIFT)
625 #define TRCDEVARCH_ARCHVER_SHIFT 12
626 #define TRCDEVARCH_ARCHVER_MASK GENMASK(15, 12)
627 #define TRCDEVARCH_ARCHVER(x) (((x) & TRCDEVARCH_ARCHVER_MASK) >> TRCDEVARCH_ARCHVER_SHIFT)
629 static bool cs_etm_is_ete(struct perf_pmu
*cs_etm_pmu
, struct perf_cpu cpu
)
633 if (!cs_etm_pmu_path_exists(cs_etm_pmu
, cpu
, metadata_ete_ro
[CS_ETE_TRCDEVARCH
]))
636 cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_ete_ro
[CS_ETE_TRCDEVARCH
], &trcdevarch
);
638 * ETE if ARCHVER is 5 (ARCHVER is 4 for ETM) and ARCHPART is 0xA13.
639 * See ETM_DEVARCH_ETE_ARCH in coresight-etm4x.h
641 return TRCDEVARCH_ARCHVER(trcdevarch
) == 5 && TRCDEVARCH_ARCHPART(trcdevarch
) == 0xA13;
644 static __u64
cs_etm_get_legacy_trace_id(struct perf_cpu cpu
)
646 /* Wrap at 48 so that invalid trace IDs aren't saved into files. */
647 return CORESIGHT_LEGACY_CPU_TRACE_ID(cpu
.cpu
% 48);
650 static void cs_etm_save_etmv4_header(__u64 data
[], struct auxtrace_record
*itr
, struct perf_cpu cpu
)
652 struct cs_etm_recording
*ptr
= container_of(itr
, struct cs_etm_recording
, itr
);
653 struct perf_pmu
*cs_etm_pmu
= ptr
->cs_etm_pmu
;
655 /* Get trace configuration register */
656 data
[CS_ETMV4_TRCCONFIGR
] = cs_etmv4_get_config(itr
);
657 /* traceID set to legacy version, in case new perf running on older system */
658 data
[CS_ETMV4_TRCTRACEIDR
] = cs_etm_get_legacy_trace_id(cpu
);
660 /* Get read-only information from sysFS */
661 cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_etmv4_ro
[CS_ETMV4_TRCIDR0
],
662 &data
[CS_ETMV4_TRCIDR0
]);
663 cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_etmv4_ro
[CS_ETMV4_TRCIDR1
],
664 &data
[CS_ETMV4_TRCIDR1
]);
665 cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_etmv4_ro
[CS_ETMV4_TRCIDR2
],
666 &data
[CS_ETMV4_TRCIDR2
]);
667 cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_etmv4_ro
[CS_ETMV4_TRCIDR8
],
668 &data
[CS_ETMV4_TRCIDR8
]);
669 cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_etmv4_ro
[CS_ETMV4_TRCAUTHSTATUS
],
670 &data
[CS_ETMV4_TRCAUTHSTATUS
]);
672 /* Kernels older than 5.19 may not expose ts_source */
673 if (!cs_etm_pmu_path_exists(cs_etm_pmu
, cpu
, metadata_etmv4_ro
[CS_ETMV4_TS_SOURCE
]) ||
674 cs_etm_get_ro_signed(cs_etm_pmu
, cpu
, metadata_etmv4_ro
[CS_ETMV4_TS_SOURCE
],
675 &data
[CS_ETMV4_TS_SOURCE
])) {
676 pr_debug3("[%03d] pmu file 'ts_source' not found. Fallback to safe value (-1)\n",
678 data
[CS_ETMV4_TS_SOURCE
] = (__u64
) -1;
682 static void cs_etm_save_ete_header(__u64 data
[], struct auxtrace_record
*itr
, struct perf_cpu cpu
)
684 struct cs_etm_recording
*ptr
= container_of(itr
, struct cs_etm_recording
, itr
);
685 struct perf_pmu
*cs_etm_pmu
= ptr
->cs_etm_pmu
;
687 /* Get trace configuration register */
688 data
[CS_ETE_TRCCONFIGR
] = cs_etmv4_get_config(itr
);
689 /* traceID set to legacy version, in case new perf running on older system */
690 data
[CS_ETE_TRCTRACEIDR
] = cs_etm_get_legacy_trace_id(cpu
);
692 /* Get read-only information from sysFS */
693 cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_ete_ro
[CS_ETE_TRCIDR0
], &data
[CS_ETE_TRCIDR0
]);
694 cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_ete_ro
[CS_ETE_TRCIDR1
], &data
[CS_ETE_TRCIDR1
]);
695 cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_ete_ro
[CS_ETE_TRCIDR2
], &data
[CS_ETE_TRCIDR2
]);
696 cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_ete_ro
[CS_ETE_TRCIDR8
], &data
[CS_ETE_TRCIDR8
]);
697 cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_ete_ro
[CS_ETE_TRCAUTHSTATUS
],
698 &data
[CS_ETE_TRCAUTHSTATUS
]);
699 /* ETE uses the same registers as ETMv4 plus TRCDEVARCH */
700 cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_ete_ro
[CS_ETE_TRCDEVARCH
],
701 &data
[CS_ETE_TRCDEVARCH
]);
703 /* Kernels older than 5.19 may not expose ts_source */
704 if (!cs_etm_pmu_path_exists(cs_etm_pmu
, cpu
, metadata_ete_ro
[CS_ETE_TS_SOURCE
]) ||
705 cs_etm_get_ro_signed(cs_etm_pmu
, cpu
, metadata_ete_ro
[CS_ETE_TS_SOURCE
],
706 &data
[CS_ETE_TS_SOURCE
])) {
707 pr_debug3("[%03d] pmu file 'ts_source' not found. Fallback to safe value (-1)\n",
709 data
[CS_ETE_TS_SOURCE
] = (__u64
) -1;
713 static void cs_etm_get_metadata(struct perf_cpu cpu
, u32
*offset
,
714 struct auxtrace_record
*itr
,
715 struct perf_record_auxtrace_info
*info
)
717 u32 increment
, nr_trc_params
;
719 struct perf_pmu
*cs_etm_pmu
= cs_etm_get_pmu(itr
);
721 /* first see what kind of tracer this cpu is affined to */
722 switch (cs_etm_get_version(cs_etm_pmu
, cpu
)) {
724 magic
= __perf_cs_ete_magic
;
725 cs_etm_save_ete_header(&info
->priv
[*offset
], itr
, cpu
);
727 /* How much space was used */
728 increment
= CS_ETE_PRIV_MAX
;
729 nr_trc_params
= CS_ETE_PRIV_MAX
- CS_ETM_COMMON_BLK_MAX_V1
;
733 magic
= __perf_cs_etmv4_magic
;
734 cs_etm_save_etmv4_header(&info
->priv
[*offset
], itr
, cpu
);
736 /* How much space was used */
737 increment
= CS_ETMV4_PRIV_MAX
;
738 nr_trc_params
= CS_ETMV4_PRIV_MAX
- CS_ETMV4_TRCCONFIGR
;
742 magic
= __perf_cs_etmv3_magic
;
743 /* Get configuration register */
744 info
->priv
[*offset
+ CS_ETM_ETMCR
] = cs_etm_get_config(itr
);
745 /* traceID set to legacy value in case new perf running on old system */
746 info
->priv
[*offset
+ CS_ETM_ETMTRACEIDR
] = cs_etm_get_legacy_trace_id(cpu
);
747 /* Get read-only information from sysFS */
748 cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_etmv3_ro
[CS_ETM_ETMCCER
],
749 &info
->priv
[*offset
+ CS_ETM_ETMCCER
]);
750 cs_etm_get_ro(cs_etm_pmu
, cpu
, metadata_etmv3_ro
[CS_ETM_ETMIDR
],
751 &info
->priv
[*offset
+ CS_ETM_ETMIDR
]);
753 /* How much space was used */
754 increment
= CS_ETM_PRIV_MAX
;
755 nr_trc_params
= CS_ETM_PRIV_MAX
- CS_ETM_ETMCR
;
760 /* Unreachable, CPUs already validated in cs_etm_validate_config() */
765 /* Build generic header portion */
766 info
->priv
[*offset
+ CS_ETM_MAGIC
] = magic
;
767 info
->priv
[*offset
+ CS_ETM_CPU
] = cpu
.cpu
;
768 info
->priv
[*offset
+ CS_ETM_NR_TRC_PARAMS
] = nr_trc_params
;
769 /* Where the next CPU entry should start from */
770 *offset
+= increment
;
773 static int cs_etm_info_fill(struct auxtrace_record
*itr
,
774 struct perf_session
*session
,
775 struct perf_record_auxtrace_info
*info
,
781 struct perf_cpu_map
*cpu_map
;
782 struct perf_cpu_map
*event_cpus
= session
->evlist
->core
.user_requested_cpus
;
783 struct perf_cpu_map
*online_cpus
= perf_cpu_map__new_online_cpus();
784 struct cs_etm_recording
*ptr
=
785 container_of(itr
, struct cs_etm_recording
, itr
);
786 struct perf_pmu
*cs_etm_pmu
= ptr
->cs_etm_pmu
;
789 if (priv_size
!= cs_etm_info_priv_size(itr
, session
->evlist
))
792 if (!session
->evlist
->core
.nr_mmaps
)
795 /* If the cpu_map has the "any" CPU all online CPUs are involved */
796 if (perf_cpu_map__has_any_cpu(event_cpus
)) {
797 cpu_map
= online_cpus
;
799 /* Make sure all specified CPUs are online */
800 perf_cpu_map__for_each_cpu(cpu
, i
, event_cpus
) {
801 if (!perf_cpu_map__has(online_cpus
, cpu
))
805 cpu_map
= event_cpus
;
808 nr_cpu
= perf_cpu_map__nr(cpu_map
);
809 /* Get PMU type as dynamically assigned by the core */
810 type
= cs_etm_pmu
->type
;
812 /* First fill out the session header */
813 info
->type
= PERF_AUXTRACE_CS_ETM
;
814 info
->priv
[CS_HEADER_VERSION
] = CS_HEADER_CURRENT_VERSION
;
815 info
->priv
[CS_PMU_TYPE_CPUS
] = type
<< 32;
816 info
->priv
[CS_PMU_TYPE_CPUS
] |= nr_cpu
;
817 info
->priv
[CS_ETM_SNAPSHOT
] = ptr
->snapshot_mode
;
819 offset
= CS_ETM_SNAPSHOT
+ 1;
821 perf_cpu_map__for_each_cpu(cpu
, i
, cpu_map
) {
822 assert(offset
< priv_size
);
823 cs_etm_get_metadata(cpu
, &offset
, itr
, info
);
826 perf_cpu_map__put(online_cpus
);
831 static int cs_etm_snapshot_start(struct auxtrace_record
*itr
)
833 struct cs_etm_recording
*ptr
=
834 container_of(itr
, struct cs_etm_recording
, itr
);
837 evlist__for_each_entry(ptr
->evlist
, evsel
) {
838 if (evsel
->core
.attr
.type
== ptr
->cs_etm_pmu
->type
)
839 return evsel__disable(evsel
);
844 static int cs_etm_snapshot_finish(struct auxtrace_record
*itr
)
846 struct cs_etm_recording
*ptr
=
847 container_of(itr
, struct cs_etm_recording
, itr
);
850 evlist__for_each_entry(ptr
->evlist
, evsel
) {
851 if (evsel
->core
.attr
.type
== ptr
->cs_etm_pmu
->type
)
852 return evsel__enable(evsel
);
857 static u64
cs_etm_reference(struct auxtrace_record
*itr __maybe_unused
)
859 return (((u64
) rand() << 0) & 0x00000000FFFFFFFFull
) |
860 (((u64
) rand() << 32) & 0xFFFFFFFF00000000ull
);
863 static void cs_etm_recording_free(struct auxtrace_record
*itr
)
865 struct cs_etm_recording
*ptr
=
866 container_of(itr
, struct cs_etm_recording
, itr
);
871 struct auxtrace_record
*cs_etm_record_init(int *err
)
873 struct perf_pmu
*cs_etm_pmu
;
874 struct cs_etm_recording
*ptr
;
876 cs_etm_pmu
= perf_pmus__find(CORESIGHT_ETM_PMU_NAME
);
883 ptr
= zalloc(sizeof(struct cs_etm_recording
));
889 ptr
->cs_etm_pmu
= cs_etm_pmu
;
890 ptr
->itr
.parse_snapshot_options
= cs_etm_parse_snapshot_options
;
891 ptr
->itr
.recording_options
= cs_etm_recording_options
;
892 ptr
->itr
.info_priv_size
= cs_etm_info_priv_size
;
893 ptr
->itr
.info_fill
= cs_etm_info_fill
;
894 ptr
->itr
.snapshot_start
= cs_etm_snapshot_start
;
895 ptr
->itr
.snapshot_finish
= cs_etm_snapshot_finish
;
896 ptr
->itr
.reference
= cs_etm_reference
;
897 ptr
->itr
.free
= cs_etm_recording_free
;
898 ptr
->itr
.read_finish
= auxtrace_record__read_finish
;
907 * Set a default config to enable the user changed config tracking mechanism
908 * (CFG_CHG and evsel__set_config_if_unset()). If no default is set then user
909 * changes aren't tracked.
912 cs_etm_get_default_config(const struct perf_pmu
*pmu __maybe_unused
,
913 struct perf_event_attr
*attr
)
915 attr
->sample_period
= 1;