OSDN Git Service

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