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