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