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/pmu.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
;
47 static const char *metadata_etmv3_ro
[CS_ETM_PRIV_MAX
] = {
48 [CS_ETM_ETMCCER
] = "mgmt/etmccer",
49 [CS_ETM_ETMIDR
] = "mgmt/etmidr",
52 static 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",
60 static bool cs_etm_is_etmv4(struct auxtrace_record
*itr
, int cpu
);
62 static int cs_etm_set_context_id(struct auxtrace_record
*itr
,
63 struct evsel
*evsel
, int cpu
)
65 struct cs_etm_recording
*ptr
;
66 struct perf_pmu
*cs_etm_pmu
;
71 ptr
= container_of(itr
, struct cs_etm_recording
, itr
);
72 cs_etm_pmu
= ptr
->cs_etm_pmu
;
74 if (!cs_etm_is_etmv4(itr
, cpu
))
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
);
82 /* There was a problem reading the file, bailing out */
84 pr_err("%s: can't read file %s\n",
85 CORESIGHT_ETM_PMU_NAME
, path
);
90 * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID tracing
92 * 0b00000 Context ID tracing is not supported.
93 * 0b00100 Maximum of 32-bit Context ID size.
94 * All other values are reserved.
96 val
= BMVAL(val
, 5, 9);
97 if (!val
|| val
!= 0x4) {
102 /* All good, let the kernel know */
103 evsel
->core
.attr
.config
|= (1 << ETM_OPT_CTXTID
);
111 static int cs_etm_set_timestamp(struct auxtrace_record
*itr
,
112 struct evsel
*evsel
, int cpu
)
114 struct cs_etm_recording
*ptr
;
115 struct perf_pmu
*cs_etm_pmu
;
120 ptr
= container_of(itr
, struct cs_etm_recording
, itr
);
121 cs_etm_pmu
= ptr
->cs_etm_pmu
;
123 if (!cs_etm_is_etmv4(itr
, cpu
))
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
);
131 /* There was a problem reading the file, bailing out */
133 pr_err("%s: can't read file %s\n",
134 CORESIGHT_ETM_PMU_NAME
, path
);
139 * TRCIDR0.TSSIZE, bit [28-24], indicates whether global timestamping
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.
145 val
&= GENMASK(28, 24);
151 /* All good, let the kernel know */
152 evsel
->core
.attr
.config
|= (1 << ETM_OPT_TS
);
159 static int cs_etm_set_option(struct auxtrace_record
*itr
,
160 struct evsel
*evsel
, u32 option
)
162 int i
, err
= -EINVAL
;
163 struct perf_cpu_map
*event_cpus
= evsel
->evlist
->core
.cpus
;
164 struct perf_cpu_map
*online_cpus
= perf_cpu_map__new(NULL
);
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
))
172 if (option
& ETM_OPT_CTXTID
) {
173 err
= cs_etm_set_context_id(itr
, evsel
, i
);
177 if (option
& ETM_OPT_TS
) {
178 err
= cs_etm_set_timestamp(itr
, evsel
, i
);
182 if (option
& ~(ETM_OPT_CTXTID
| ETM_OPT_TS
))
183 /* Nothing else is currently supported */
189 perf_cpu_map__put(online_cpus
);
193 static int cs_etm_parse_snapshot_options(struct auxtrace_record
*itr
,
194 struct record_opts
*opts
,
197 struct cs_etm_recording
*ptr
=
198 container_of(itr
, struct cs_etm_recording
, itr
);
199 unsigned long long snapshot_size
= 0;
203 snapshot_size
= strtoull(str
, &endptr
, 0);
204 if (*endptr
|| snapshot_size
> SIZE_MAX
)
208 opts
->auxtrace_snapshot_mode
= true;
209 opts
->auxtrace_snapshot_size
= snapshot_size
;
210 ptr
->snapshot_size
= snapshot_size
;
215 static int cs_etm_set_sink_attr(struct perf_pmu
*pmu
,
218 char msg
[BUFSIZ
], path
[PATH_MAX
], *sink
;
219 struct evsel_config_term
*term
;
223 if (evsel
->core
.attr
.config2
& GENMASK(31, 0))
226 list_for_each_entry(term
, &evsel
->config_terms
, list
) {
227 if (term
->type
!= EVSEL__CONFIG_TERM_DRV_CFG
)
230 sink
= term
->val
.str
;
231 snprintf(path
, PATH_MAX
, "sinks/%s", sink
);
233 ret
= perf_pmu__scan_file(pmu
, path
, "%x", &hash
);
235 pr_err("failed to set sink \"%s\" on event %s with %d (%s)\n",
236 sink
, evsel__name(evsel
), errno
,
237 str_error_r(errno
, msg
, sizeof(msg
)));
241 evsel
->core
.attr
.config2
|= hash
;
246 * No sink was provided on the command line - allow the CoreSight
247 * system to look for a default
252 static int cs_etm_recording_options(struct auxtrace_record
*itr
,
253 struct evlist
*evlist
,
254 struct record_opts
*opts
)
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
;
260 struct evsel
*evsel
, *cs_etm_evsel
= NULL
;
261 struct perf_cpu_map
*cpus
= evlist
->core
.cpus
;
262 bool privileged
= perf_event_paranoid_check(-1);
265 ptr
->evlist
= evlist
;
266 ptr
->snapshot_mode
= opts
->auxtrace_snapshot_mode
;
268 if (!record_opts__no_switch_events(opts
) &&
269 perf_can_record_switch_events())
270 opts
->record_switch_events
= true;
272 evlist__for_each_entry(evlist
, evsel
) {
273 if (evsel
->core
.attr
.type
== cs_etm_pmu
->type
) {
275 pr_err("There may be only one %s event\n",
276 CORESIGHT_ETM_PMU_NAME
);
279 evsel
->core
.attr
.freq
= 0;
280 evsel
->core
.attr
.sample_period
= 1;
281 cs_etm_evsel
= evsel
;
282 opts
->full_auxtrace
= true;
286 /* no need to continue if at least one event of interest was found */
290 ret
= cs_etm_set_sink_attr(cs_etm_pmu
, cs_etm_evsel
);
294 if (opts
->use_clockid
) {
295 pr_err("Cannot use clockid (-k option) with %s\n",
296 CORESIGHT_ETM_PMU_NAME
);
300 /* we are in snapshot mode */
301 if (opts
->auxtrace_snapshot_mode
) {
303 * No size were given to '-S' or '-m,', so go with
306 if (!opts
->auxtrace_snapshot_size
&&
307 !opts
->auxtrace_mmap_pages
) {
309 opts
->auxtrace_mmap_pages
= MiB(4) / page_size
;
311 opts
->auxtrace_mmap_pages
=
312 KiB(128) / page_size
;
313 if (opts
->mmap_pages
== UINT_MAX
)
314 opts
->mmap_pages
= KiB(256) / page_size
;
316 } else if (!opts
->auxtrace_mmap_pages
&& !privileged
&&
317 opts
->mmap_pages
== UINT_MAX
) {
318 opts
->mmap_pages
= KiB(256) / page_size
;
322 * '-m,xyz' was specified but no snapshot size, so make the
323 * snapshot size as big as the auxtrace mmap area.
325 if (!opts
->auxtrace_snapshot_size
) {
326 opts
->auxtrace_snapshot_size
=
327 opts
->auxtrace_mmap_pages
* (size_t)page_size
;
331 * -Sxyz was specified but no auxtrace mmap area, so make the
332 * auxtrace mmap area big enough to fit the requested snapshot
335 if (!opts
->auxtrace_mmap_pages
) {
336 size_t sz
= opts
->auxtrace_snapshot_size
;
338 sz
= round_up(sz
, page_size
) / page_size
;
339 opts
->auxtrace_mmap_pages
= roundup_pow_of_two(sz
);
342 /* Snapshost size can't be bigger than the auxtrace area */
343 if (opts
->auxtrace_snapshot_size
>
344 opts
->auxtrace_mmap_pages
* (size_t)page_size
) {
345 pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n",
346 opts
->auxtrace_snapshot_size
,
347 opts
->auxtrace_mmap_pages
* (size_t)page_size
);
351 /* Something went wrong somewhere - this shouldn't happen */
352 if (!opts
->auxtrace_snapshot_size
||
353 !opts
->auxtrace_mmap_pages
) {
354 pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n");
359 /* We are in full trace mode but '-m,xyz' wasn't specified */
360 if (opts
->full_auxtrace
&& !opts
->auxtrace_mmap_pages
) {
362 opts
->auxtrace_mmap_pages
= MiB(4) / page_size
;
364 opts
->auxtrace_mmap_pages
= KiB(128) / page_size
;
365 if (opts
->mmap_pages
== UINT_MAX
)
366 opts
->mmap_pages
= KiB(256) / page_size
;
371 /* Validate auxtrace_mmap_pages provided by user */
372 if (opts
->auxtrace_mmap_pages
) {
373 unsigned int max_page
= (KiB(128) / page_size
);
374 size_t sz
= opts
->auxtrace_mmap_pages
* (size_t)page_size
;
377 opts
->auxtrace_mmap_pages
> max_page
) {
378 opts
->auxtrace_mmap_pages
= max_page
;
379 pr_err("auxtrace too big, truncating to %d\n",
383 if (!is_power_of_2(sz
)) {
384 pr_err("Invalid mmap size for %s: must be a power of 2\n",
385 CORESIGHT_ETM_PMU_NAME
);
390 if (opts
->auxtrace_snapshot_mode
)
391 pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME
,
392 opts
->auxtrace_snapshot_size
);
395 * To obtain the auxtrace buffer file descriptor, the auxtrace
396 * event must come first.
398 evlist__to_front(evlist
, cs_etm_evsel
);
401 * In the case of per-cpu mmaps, we need the CPU on the
402 * AUX event. We also need the contextID in order to be notified
403 * when a context switch happened.
405 if (!perf_cpu_map__empty(cpus
)) {
406 evsel__set_sample_bit(cs_etm_evsel
, CPU
);
408 err
= cs_etm_set_option(itr
, cs_etm_evsel
,
409 ETM_OPT_CTXTID
| ETM_OPT_TS
);
414 /* Add dummy event to keep tracking */
415 if (opts
->full_auxtrace
) {
416 struct evsel
*tracking_evsel
;
418 err
= parse_events(evlist
, "dummy:u", NULL
);
422 tracking_evsel
= evlist__last(evlist
);
423 evlist__set_tracking_event(evlist
, tracking_evsel
);
425 tracking_evsel
->core
.attr
.freq
= 0;
426 tracking_evsel
->core
.attr
.sample_period
= 1;
428 /* In per-cpu case, always need the time of mmap events etc */
429 if (!perf_cpu_map__empty(cpus
))
430 evsel__set_sample_bit(tracking_evsel
, TIME
);
437 static u64
cs_etm_get_config(struct auxtrace_record
*itr
)
440 struct cs_etm_recording
*ptr
=
441 container_of(itr
, struct cs_etm_recording
, itr
);
442 struct perf_pmu
*cs_etm_pmu
= ptr
->cs_etm_pmu
;
443 struct evlist
*evlist
= ptr
->evlist
;
446 evlist__for_each_entry(evlist
, evsel
) {
447 if (evsel
->core
.attr
.type
== cs_etm_pmu
->type
) {
449 * Variable perf_event_attr::config is assigned to
450 * ETMv3/PTM. The bit fields have been made to match
451 * the ETMv3.5 ETRMCR register specification. See the
452 * PMU_FORMAT_ATTR() declarations in
453 * drivers/hwtracing/coresight/coresight-perf.c for
456 config
= evsel
->core
.attr
.config
;
465 #define BIT(N) (1UL << (N))
468 static u64
cs_etmv4_get_config(struct auxtrace_record
*itr
)
474 * The perf event variable config bits represent both
475 * the command line options and register programming
476 * bits in ETMv3/PTM. For ETMv4 we must remap options
479 config_opts
= cs_etm_get_config(itr
);
480 if (config_opts
& BIT(ETM_OPT_CYCACC
))
481 config
|= BIT(ETM4_CFG_BIT_CYCACC
);
482 if (config_opts
& BIT(ETM_OPT_CTXTID
))
483 config
|= BIT(ETM4_CFG_BIT_CTXTID
);
484 if (config_opts
& BIT(ETM_OPT_TS
))
485 config
|= BIT(ETM4_CFG_BIT_TS
);
486 if (config_opts
& BIT(ETM_OPT_RETSTK
))
487 config
|= BIT(ETM4_CFG_BIT_RETSTK
);
493 cs_etm_info_priv_size(struct auxtrace_record
*itr __maybe_unused
,
494 struct evlist
*evlist __maybe_unused
)
497 int etmv3
= 0, etmv4
= 0;
498 struct perf_cpu_map
*event_cpus
= evlist
->core
.cpus
;
499 struct perf_cpu_map
*online_cpus
= perf_cpu_map__new(NULL
);
501 /* cpu map is not empty, we have specific CPUs to work with */
502 if (!perf_cpu_map__empty(event_cpus
)) {
503 for (i
= 0; i
< cpu__max_cpu(); i
++) {
504 if (!cpu_map__has(event_cpus
, i
) ||
505 !cpu_map__has(online_cpus
, i
))
508 if (cs_etm_is_etmv4(itr
, i
))
514 /* get configuration for all CPUs in the system */
515 for (i
= 0; i
< cpu__max_cpu(); i
++) {
516 if (!cpu_map__has(online_cpus
, i
))
519 if (cs_etm_is_etmv4(itr
, i
))
526 perf_cpu_map__put(online_cpus
);
528 return (CS_ETM_HEADER_SIZE
+
529 (etmv4
* CS_ETMV4_PRIV_SIZE
) +
530 (etmv3
* CS_ETMV3_PRIV_SIZE
));
533 static bool cs_etm_is_etmv4(struct auxtrace_record
*itr
, int cpu
)
539 struct cs_etm_recording
*ptr
=
540 container_of(itr
, struct cs_etm_recording
, itr
);
541 struct perf_pmu
*cs_etm_pmu
= ptr
->cs_etm_pmu
;
543 /* Take any of the RO files for ETMv4 and see if it present */
544 snprintf(path
, PATH_MAX
, "cpu%d/%s",
545 cpu
, metadata_etmv4_ro
[CS_ETMV4_TRCIDR0
]);
546 scan
= perf_pmu__scan_file(cs_etm_pmu
, path
, "%x", &val
);
548 /* The file was read successfully, we have a winner */
555 static int cs_etm_get_ro(struct perf_pmu
*pmu
, int cpu
, const char *path
)
557 char pmu_path
[PATH_MAX
];
559 unsigned int val
= 0;
561 /* Get RO metadata from sysfs */
562 snprintf(pmu_path
, PATH_MAX
, "cpu%d/%s", cpu
, path
);
564 scan
= perf_pmu__scan_file(pmu
, pmu_path
, "%x", &val
);
566 pr_err("%s: error reading: %s\n", __func__
, pmu_path
);
571 static void cs_etm_get_metadata(int cpu
, u32
*offset
,
572 struct auxtrace_record
*itr
,
573 struct perf_record_auxtrace_info
*info
)
577 struct cs_etm_recording
*ptr
=
578 container_of(itr
, struct cs_etm_recording
, itr
);
579 struct perf_pmu
*cs_etm_pmu
= ptr
->cs_etm_pmu
;
581 /* first see what kind of tracer this cpu is affined to */
582 if (cs_etm_is_etmv4(itr
, cpu
)) {
583 magic
= __perf_cs_etmv4_magic
;
584 /* Get trace configuration register */
585 info
->priv
[*offset
+ CS_ETMV4_TRCCONFIGR
] =
586 cs_etmv4_get_config(itr
);
587 /* Get traceID from the framework */
588 info
->priv
[*offset
+ CS_ETMV4_TRCTRACEIDR
] =
589 coresight_get_trace_id(cpu
);
590 /* Get read-only information from sysFS */
591 info
->priv
[*offset
+ CS_ETMV4_TRCIDR0
] =
592 cs_etm_get_ro(cs_etm_pmu
, cpu
,
593 metadata_etmv4_ro
[CS_ETMV4_TRCIDR0
]);
594 info
->priv
[*offset
+ CS_ETMV4_TRCIDR1
] =
595 cs_etm_get_ro(cs_etm_pmu
, cpu
,
596 metadata_etmv4_ro
[CS_ETMV4_TRCIDR1
]);
597 info
->priv
[*offset
+ CS_ETMV4_TRCIDR2
] =
598 cs_etm_get_ro(cs_etm_pmu
, cpu
,
599 metadata_etmv4_ro
[CS_ETMV4_TRCIDR2
]);
600 info
->priv
[*offset
+ CS_ETMV4_TRCIDR8
] =
601 cs_etm_get_ro(cs_etm_pmu
, cpu
,
602 metadata_etmv4_ro
[CS_ETMV4_TRCIDR8
]);
603 info
->priv
[*offset
+ CS_ETMV4_TRCAUTHSTATUS
] =
604 cs_etm_get_ro(cs_etm_pmu
, cpu
,
606 [CS_ETMV4_TRCAUTHSTATUS
]);
608 /* How much space was used */
609 increment
= CS_ETMV4_PRIV_MAX
;
611 magic
= __perf_cs_etmv3_magic
;
612 /* Get configuration register */
613 info
->priv
[*offset
+ CS_ETM_ETMCR
] = cs_etm_get_config(itr
);
614 /* Get traceID from the framework */
615 info
->priv
[*offset
+ CS_ETM_ETMTRACEIDR
] =
616 coresight_get_trace_id(cpu
);
617 /* Get read-only information from sysFS */
618 info
->priv
[*offset
+ CS_ETM_ETMCCER
] =
619 cs_etm_get_ro(cs_etm_pmu
, cpu
,
620 metadata_etmv3_ro
[CS_ETM_ETMCCER
]);
621 info
->priv
[*offset
+ CS_ETM_ETMIDR
] =
622 cs_etm_get_ro(cs_etm_pmu
, cpu
,
623 metadata_etmv3_ro
[CS_ETM_ETMIDR
]);
625 /* How much space was used */
626 increment
= CS_ETM_PRIV_MAX
;
629 /* Build generic header portion */
630 info
->priv
[*offset
+ CS_ETM_MAGIC
] = magic
;
631 info
->priv
[*offset
+ CS_ETM_CPU
] = cpu
;
632 /* Where the next CPU entry should start from */
633 *offset
+= increment
;
636 static int cs_etm_info_fill(struct auxtrace_record
*itr
,
637 struct perf_session
*session
,
638 struct perf_record_auxtrace_info
*info
,
644 struct perf_cpu_map
*cpu_map
;
645 struct perf_cpu_map
*event_cpus
= session
->evlist
->core
.cpus
;
646 struct perf_cpu_map
*online_cpus
= perf_cpu_map__new(NULL
);
647 struct cs_etm_recording
*ptr
=
648 container_of(itr
, struct cs_etm_recording
, itr
);
649 struct perf_pmu
*cs_etm_pmu
= ptr
->cs_etm_pmu
;
651 if (priv_size
!= cs_etm_info_priv_size(itr
, session
->evlist
))
654 if (!session
->evlist
->core
.nr_mmaps
)
657 /* If the cpu_map is empty all online CPUs are involved */
658 if (perf_cpu_map__empty(event_cpus
)) {
659 cpu_map
= online_cpus
;
661 /* Make sure all specified CPUs are online */
662 for (i
= 0; i
< perf_cpu_map__nr(event_cpus
); i
++) {
663 if (cpu_map__has(event_cpus
, i
) &&
664 !cpu_map__has(online_cpus
, i
))
668 cpu_map
= event_cpus
;
671 nr_cpu
= perf_cpu_map__nr(cpu_map
);
672 /* Get PMU type as dynamically assigned by the core */
673 type
= cs_etm_pmu
->type
;
675 /* First fill out the session header */
676 info
->type
= PERF_AUXTRACE_CS_ETM
;
677 info
->priv
[CS_HEADER_VERSION_0
] = 0;
678 info
->priv
[CS_PMU_TYPE_CPUS
] = type
<< 32;
679 info
->priv
[CS_PMU_TYPE_CPUS
] |= nr_cpu
;
680 info
->priv
[CS_ETM_SNAPSHOT
] = ptr
->snapshot_mode
;
682 offset
= CS_ETM_SNAPSHOT
+ 1;
684 for (i
= 0; i
< cpu__max_cpu() && offset
< priv_size
; i
++)
685 if (cpu_map__has(cpu_map
, i
))
686 cs_etm_get_metadata(i
, &offset
, itr
, info
);
688 perf_cpu_map__put(online_cpus
);
693 static int cs_etm_alloc_wrapped_array(struct cs_etm_recording
*ptr
, int idx
)
696 int cnt
= ptr
->wrapped_cnt
;
698 /* Make @ptr->wrapped as big as @idx */
703 * Free'ed in cs_etm_recording_free(). Using realloc() to avoid
704 * cross compilation problems where the host's system supports
705 * reallocarray() but not the target.
707 wrapped
= realloc(ptr
->wrapped
, cnt
* sizeof(bool));
711 wrapped
[cnt
- 1] = false;
712 ptr
->wrapped_cnt
= cnt
;
713 ptr
->wrapped
= wrapped
;
718 static bool cs_etm_buffer_has_wrapped(unsigned char *buffer
,
719 size_t buffer_size
, u64 head
)
722 u64
*buf
= (u64
*)buffer
;
723 size_t buf_size
= buffer_size
;
726 * We want to look the very last 512 byte (chosen arbitrarily) in
729 watermark
= buf_size
- 512;
732 * @head is continuously increasing - if its value is equal or greater
733 * than the size of the ring buffer, it has wrapped around.
735 if (head
>= buffer_size
)
739 * The value of @head is somewhere within the size of the ring buffer.
740 * This can be that there hasn't been enough data to fill the ring
741 * buffer yet or the trace time was so long that @head has numerically
742 * wrapped around. To find we need to check if we have data at the very
743 * end of the ring buffer. We can reliably do this because mmap'ed
744 * pages are zeroed out and there is a fresh mapping with every new
748 /* @head is less than 512 byte from the end of the ring buffer */
749 if (head
> watermark
)
753 * Speed things up by using 64 bit transactions (see "u64 *buf" above)
759 * If we find trace data at the end of the ring buffer, @head has
760 * been there and has numerically wrapped around at least once.
762 for (i
= watermark
; i
< buf_size
; i
++)
769 static int cs_etm_find_snapshot(struct auxtrace_record
*itr
,
770 int idx
, struct auxtrace_mmap
*mm
,
776 struct cs_etm_recording
*ptr
=
777 container_of(itr
, struct cs_etm_recording
, itr
);
780 * Allocate memory to keep track of wrapping if this is the first
781 * time we deal with this *mm.
783 if (idx
>= ptr
->wrapped_cnt
) {
784 err
= cs_etm_alloc_wrapped_array(ptr
, idx
);
790 * Check to see if *head has wrapped around. If it hasn't only the
791 * amount of data between *head and *old is snapshot'ed to avoid
792 * bloating the perf.data file with zeros. But as soon as *head has
793 * wrapped around the entire size of the AUX ring buffer it taken.
795 wrapped
= ptr
->wrapped
[idx
];
796 if (!wrapped
&& cs_etm_buffer_has_wrapped(data
, mm
->len
, *head
)) {
798 ptr
->wrapped
[idx
] = true;
801 pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n",
802 __func__
, idx
, (size_t)*old
, (size_t)*head
, mm
->len
);
804 /* No wrap has occurred, we can just use *head and *old. */
809 * *head has wrapped around - adjust *head and *old to pickup the
810 * entire content of the AUX buffer.
812 if (*head
>= mm
->len
) {
813 *old
= *head
- mm
->len
;
816 *old
= *head
- mm
->len
;
822 static int cs_etm_snapshot_start(struct auxtrace_record
*itr
)
824 struct cs_etm_recording
*ptr
=
825 container_of(itr
, struct cs_etm_recording
, itr
);
828 evlist__for_each_entry(ptr
->evlist
, evsel
) {
829 if (evsel
->core
.attr
.type
== ptr
->cs_etm_pmu
->type
)
830 return evsel__disable(evsel
);
835 static int cs_etm_snapshot_finish(struct auxtrace_record
*itr
)
837 struct cs_etm_recording
*ptr
=
838 container_of(itr
, struct cs_etm_recording
, itr
);
841 evlist__for_each_entry(ptr
->evlist
, evsel
) {
842 if (evsel
->core
.attr
.type
== ptr
->cs_etm_pmu
->type
)
843 return evsel__enable(evsel
);
848 static u64
cs_etm_reference(struct auxtrace_record
*itr __maybe_unused
)
850 return (((u64
) rand() << 0) & 0x00000000FFFFFFFFull
) |
851 (((u64
) rand() << 32) & 0xFFFFFFFF00000000ull
);
854 static void cs_etm_recording_free(struct auxtrace_record
*itr
)
856 struct cs_etm_recording
*ptr
=
857 container_of(itr
, struct cs_etm_recording
, itr
);
859 zfree(&ptr
->wrapped
);
863 struct auxtrace_record
*cs_etm_record_init(int *err
)
865 struct perf_pmu
*cs_etm_pmu
;
866 struct cs_etm_recording
*ptr
;
868 cs_etm_pmu
= perf_pmu__find(CORESIGHT_ETM_PMU_NAME
);
875 ptr
= zalloc(sizeof(struct cs_etm_recording
));
881 ptr
->cs_etm_pmu
= cs_etm_pmu
;
882 ptr
->itr
.pmu
= cs_etm_pmu
;
883 ptr
->itr
.parse_snapshot_options
= cs_etm_parse_snapshot_options
;
884 ptr
->itr
.recording_options
= cs_etm_recording_options
;
885 ptr
->itr
.info_priv_size
= cs_etm_info_priv_size
;
886 ptr
->itr
.info_fill
= cs_etm_info_fill
;
887 ptr
->itr
.find_snapshot
= cs_etm_find_snapshot
;
888 ptr
->itr
.snapshot_start
= cs_etm_snapshot_start
;
889 ptr
->itr
.snapshot_finish
= cs_etm_snapshot_finish
;
890 ptr
->itr
.reference
= cs_etm_reference
;
891 ptr
->itr
.free
= cs_etm_recording_free
;
892 ptr
->itr
.read_finish
= auxtrace_record__read_finish
;