xref: /linux/tools/perf/arch/arm/util/cs-etm.c (revision 3399ad9ac234364396f75531203c38be5d2872c7)
18a9fd832SMathieu Poirier // SPDX-License-Identifier: GPL-2.0
2a818c563SMathieu Poirier /*
3a818c563SMathieu Poirier  * Copyright(C) 2015 Linaro Limited. All rights reserved.
4a818c563SMathieu Poirier  * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
5a818c563SMathieu Poirier  */
6a818c563SMathieu Poirier 
7a818c563SMathieu Poirier #include <api/fs/fs.h>
8fa4e819bSMathieu Poirier #include <linux/bits.h>
9a818c563SMathieu Poirier #include <linux/bitops.h>
10afaed6d3SArnaldo Carvalho de Melo #include <linux/compiler.h>
11a818c563SMathieu Poirier #include <linux/coresight-pmu.h>
12a818c563SMathieu Poirier #include <linux/kernel.h>
13a818c563SMathieu Poirier #include <linux/log2.h>
14a818c563SMathieu Poirier #include <linux/types.h>
15a818c563SMathieu Poirier 
16a818c563SMathieu Poirier #include "cs-etm.h"
17a818c563SMathieu Poirier #include "../../perf.h"
18a818c563SMathieu Poirier #include "../../util/auxtrace.h"
19a818c563SMathieu Poirier #include "../../util/cpumap.h"
20a818c563SMathieu Poirier #include "../../util/evlist.h"
213becf452SMathieu Poirier #include "../../util/evsel.h"
22a818c563SMathieu Poirier #include "../../util/pmu.h"
23a818c563SMathieu Poirier #include "../../util/thread_map.h"
24a818c563SMathieu Poirier #include "../../util/cs-etm.h"
25a818c563SMathieu Poirier 
26fa4e819bSMathieu Poirier #include <errno.h>
27a818c563SMathieu Poirier #include <stdlib.h>
287a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h>
29a818c563SMathieu Poirier 
30a818c563SMathieu Poirier struct cs_etm_recording {
31a818c563SMathieu Poirier 	struct auxtrace_record	itr;
32a818c563SMathieu Poirier 	struct perf_pmu		*cs_etm_pmu;
33a818c563SMathieu Poirier 	struct perf_evlist	*evlist;
34a818c563SMathieu Poirier 	bool			snapshot_mode;
35a818c563SMathieu Poirier 	size_t			snapshot_size;
36a818c563SMathieu Poirier };
37a818c563SMathieu Poirier 
38*3399ad9aSMathieu Poirier static const char *metadata_etmv3_ro[CS_ETM_PRIV_MAX] = {
39*3399ad9aSMathieu Poirier 	[CS_ETM_ETMCCER]	= "mgmt/etmccer",
40*3399ad9aSMathieu Poirier 	[CS_ETM_ETMIDR]		= "mgmt/etmidr",
41*3399ad9aSMathieu Poirier };
42*3399ad9aSMathieu Poirier 
43*3399ad9aSMathieu Poirier static const char *metadata_etmv4_ro[CS_ETMV4_PRIV_MAX] = {
44*3399ad9aSMathieu Poirier 	[CS_ETMV4_TRCIDR0]		= "trcidr/trcidr0",
45*3399ad9aSMathieu Poirier 	[CS_ETMV4_TRCIDR1]		= "trcidr/trcidr1",
46*3399ad9aSMathieu Poirier 	[CS_ETMV4_TRCIDR2]		= "trcidr/trcidr2",
47*3399ad9aSMathieu Poirier 	[CS_ETMV4_TRCIDR8]		= "trcidr/trcidr8",
48*3399ad9aSMathieu Poirier 	[CS_ETMV4_TRCAUTHSTATUS]	= "mgmt/trcauthstatus",
49*3399ad9aSMathieu Poirier };
50*3399ad9aSMathieu Poirier 
51a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu);
52a818c563SMathieu Poirier 
53*3399ad9aSMathieu Poirier static int cs_etm_set_context_id(struct auxtrace_record *itr,
54*3399ad9aSMathieu Poirier 				 struct perf_evsel *evsel, int cpu)
55*3399ad9aSMathieu Poirier {
56*3399ad9aSMathieu Poirier 	struct cs_etm_recording *ptr;
57*3399ad9aSMathieu Poirier 	struct perf_pmu *cs_etm_pmu;
58*3399ad9aSMathieu Poirier 	char path[PATH_MAX];
59*3399ad9aSMathieu Poirier 	int err = -EINVAL;
60*3399ad9aSMathieu Poirier 	u32 val;
61*3399ad9aSMathieu Poirier 
62*3399ad9aSMathieu Poirier 	ptr = container_of(itr, struct cs_etm_recording, itr);
63*3399ad9aSMathieu Poirier 	cs_etm_pmu = ptr->cs_etm_pmu;
64*3399ad9aSMathieu Poirier 
65*3399ad9aSMathieu Poirier 	if (!cs_etm_is_etmv4(itr, cpu))
66*3399ad9aSMathieu Poirier 		goto out;
67*3399ad9aSMathieu Poirier 
68*3399ad9aSMathieu Poirier 	/* Get a handle on TRCIRD2 */
69*3399ad9aSMathieu Poirier 	snprintf(path, PATH_MAX, "cpu%d/%s",
70*3399ad9aSMathieu Poirier 		 cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2]);
71*3399ad9aSMathieu Poirier 	err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val);
72*3399ad9aSMathieu Poirier 
73*3399ad9aSMathieu Poirier 	/* There was a problem reading the file, bailing out */
74*3399ad9aSMathieu Poirier 	if (err != 1) {
75*3399ad9aSMathieu Poirier 		pr_err("%s: can't read file %s\n",
76*3399ad9aSMathieu Poirier 		       CORESIGHT_ETM_PMU_NAME, path);
77*3399ad9aSMathieu Poirier 		goto out;
78*3399ad9aSMathieu Poirier 	}
79*3399ad9aSMathieu Poirier 
80*3399ad9aSMathieu Poirier 	/*
81*3399ad9aSMathieu Poirier 	 * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID tracing
82*3399ad9aSMathieu Poirier 	 * is supported:
83*3399ad9aSMathieu Poirier 	 *  0b00000 Context ID tracing is not supported.
84*3399ad9aSMathieu Poirier 	 *  0b00100 Maximum of 32-bit Context ID size.
85*3399ad9aSMathieu Poirier 	 *  All other values are reserved.
86*3399ad9aSMathieu Poirier 	 */
87*3399ad9aSMathieu Poirier 	val = BMVAL(val, 5, 9);
88*3399ad9aSMathieu Poirier 	if (!val || val != 0x4) {
89*3399ad9aSMathieu Poirier 		err = -EINVAL;
90*3399ad9aSMathieu Poirier 		goto out;
91*3399ad9aSMathieu Poirier 	}
92*3399ad9aSMathieu Poirier 
93*3399ad9aSMathieu Poirier 	/* All good, let the kernel know */
94*3399ad9aSMathieu Poirier 	evsel->attr.config |= (1 << ETM_OPT_CTXTID);
95*3399ad9aSMathieu Poirier 	err = 0;
96*3399ad9aSMathieu Poirier 
97*3399ad9aSMathieu Poirier out:
98*3399ad9aSMathieu Poirier 
99*3399ad9aSMathieu Poirier 	return err;
100*3399ad9aSMathieu Poirier }
101*3399ad9aSMathieu Poirier 
102*3399ad9aSMathieu Poirier static int cs_etm_set_option(struct auxtrace_record *itr,
103*3399ad9aSMathieu Poirier 			     struct perf_evsel *evsel, u32 option)
104*3399ad9aSMathieu Poirier {
105*3399ad9aSMathieu Poirier 	int i, err = -EINVAL;
106*3399ad9aSMathieu Poirier 	struct cpu_map *event_cpus = evsel->evlist->cpus;
107*3399ad9aSMathieu Poirier 	struct cpu_map *online_cpus = cpu_map__new(NULL);
108*3399ad9aSMathieu Poirier 
109*3399ad9aSMathieu Poirier 	/* Set option of each CPU we have */
110*3399ad9aSMathieu Poirier 	for (i = 0; i < cpu__max_cpu(); i++) {
111*3399ad9aSMathieu Poirier 		if (!cpu_map__has(event_cpus, i) ||
112*3399ad9aSMathieu Poirier 		    !cpu_map__has(online_cpus, i))
113*3399ad9aSMathieu Poirier 			continue;
114*3399ad9aSMathieu Poirier 
115*3399ad9aSMathieu Poirier 		switch (option) {
116*3399ad9aSMathieu Poirier 		case ETM_OPT_CTXTID:
117*3399ad9aSMathieu Poirier 			err = cs_etm_set_context_id(itr, evsel, i);
118*3399ad9aSMathieu Poirier 			if (err)
119*3399ad9aSMathieu Poirier 				goto out;
120*3399ad9aSMathieu Poirier 			break;
121*3399ad9aSMathieu Poirier 		default:
122*3399ad9aSMathieu Poirier 			goto out;
123*3399ad9aSMathieu Poirier 		}
124*3399ad9aSMathieu Poirier 	}
125*3399ad9aSMathieu Poirier 
126*3399ad9aSMathieu Poirier 	err = 0;
127*3399ad9aSMathieu Poirier out:
128*3399ad9aSMathieu Poirier 	cpu_map__put(online_cpus);
129*3399ad9aSMathieu Poirier 	return err;
130*3399ad9aSMathieu Poirier }
131*3399ad9aSMathieu Poirier 
132a818c563SMathieu Poirier static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr,
133a818c563SMathieu Poirier 					 struct record_opts *opts,
134a818c563SMathieu Poirier 					 const char *str)
135a818c563SMathieu Poirier {
136a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
137a818c563SMathieu Poirier 				container_of(itr, struct cs_etm_recording, itr);
138a818c563SMathieu Poirier 	unsigned long long snapshot_size = 0;
139a818c563SMathieu Poirier 	char *endptr;
140a818c563SMathieu Poirier 
141a818c563SMathieu Poirier 	if (str) {
142a818c563SMathieu Poirier 		snapshot_size = strtoull(str, &endptr, 0);
143a818c563SMathieu Poirier 		if (*endptr || snapshot_size > SIZE_MAX)
144a818c563SMathieu Poirier 			return -1;
145a818c563SMathieu Poirier 	}
146a818c563SMathieu Poirier 
147a818c563SMathieu Poirier 	opts->auxtrace_snapshot_mode = true;
148a818c563SMathieu Poirier 	opts->auxtrace_snapshot_size = snapshot_size;
149a818c563SMathieu Poirier 	ptr->snapshot_size = snapshot_size;
150a818c563SMathieu Poirier 
151a818c563SMathieu Poirier 	return 0;
152a818c563SMathieu Poirier }
153a818c563SMathieu Poirier 
154fa4e819bSMathieu Poirier static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
155fa4e819bSMathieu Poirier 				struct perf_evsel *evsel)
156fa4e819bSMathieu Poirier {
157fa4e819bSMathieu Poirier 	char msg[BUFSIZ], path[PATH_MAX], *sink;
158fa4e819bSMathieu Poirier 	struct perf_evsel_config_term *term;
159fa4e819bSMathieu Poirier 	int ret = -EINVAL;
160fa4e819bSMathieu Poirier 	u32 hash;
161fa4e819bSMathieu Poirier 
162fa4e819bSMathieu Poirier 	if (evsel->attr.config2 & GENMASK(31, 0))
163fa4e819bSMathieu Poirier 		return 0;
164fa4e819bSMathieu Poirier 
165fa4e819bSMathieu Poirier 	list_for_each_entry(term, &evsel->config_terms, list) {
166fa4e819bSMathieu Poirier 		if (term->type != PERF_EVSEL__CONFIG_TERM_DRV_CFG)
167fa4e819bSMathieu Poirier 			continue;
168fa4e819bSMathieu Poirier 
169fa4e819bSMathieu Poirier 		sink = term->val.drv_cfg;
170fa4e819bSMathieu Poirier 		snprintf(path, PATH_MAX, "sinks/%s", sink);
171fa4e819bSMathieu Poirier 
172fa4e819bSMathieu Poirier 		ret = perf_pmu__scan_file(pmu, path, "%x", &hash);
173fa4e819bSMathieu Poirier 		if (ret != 1) {
174fa4e819bSMathieu Poirier 			pr_err("failed to set sink \"%s\" on event %s with %d (%s)\n",
175fa4e819bSMathieu Poirier 			       sink, perf_evsel__name(evsel), errno,
176fa4e819bSMathieu Poirier 			       str_error_r(errno, msg, sizeof(msg)));
177fa4e819bSMathieu Poirier 			return ret;
178fa4e819bSMathieu Poirier 		}
179fa4e819bSMathieu Poirier 
180fa4e819bSMathieu Poirier 		evsel->attr.config2 |= hash;
181fa4e819bSMathieu Poirier 		return 0;
182fa4e819bSMathieu Poirier 	}
183fa4e819bSMathieu Poirier 
184fa4e819bSMathieu Poirier 	/*
185fa4e819bSMathieu Poirier 	 * No sink was provided on the command line - for _now_ treat
186fa4e819bSMathieu Poirier 	 * this as an error.
187fa4e819bSMathieu Poirier 	 */
188fa4e819bSMathieu Poirier 	return ret;
189fa4e819bSMathieu Poirier }
190fa4e819bSMathieu Poirier 
191a818c563SMathieu Poirier static int cs_etm_recording_options(struct auxtrace_record *itr,
192a818c563SMathieu Poirier 				    struct perf_evlist *evlist,
193a818c563SMathieu Poirier 				    struct record_opts *opts)
194a818c563SMathieu Poirier {
195fa4e819bSMathieu Poirier 	int ret;
196a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
197a818c563SMathieu Poirier 				container_of(itr, struct cs_etm_recording, itr);
198a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
199a818c563SMathieu Poirier 	struct perf_evsel *evsel, *cs_etm_evsel = NULL;
200*3399ad9aSMathieu Poirier 	struct cpu_map *cpus = evlist->cpus;
201a818c563SMathieu Poirier 	bool privileged = (geteuid() == 0 || perf_event_paranoid() < 0);
202*3399ad9aSMathieu Poirier 	int err = 0;
203a818c563SMathieu Poirier 
204a818c563SMathieu Poirier 	ptr->evlist = evlist;
205a818c563SMathieu Poirier 	ptr->snapshot_mode = opts->auxtrace_snapshot_mode;
206a818c563SMathieu Poirier 
207a818c563SMathieu Poirier 	evlist__for_each_entry(evlist, evsel) {
208a818c563SMathieu Poirier 		if (evsel->attr.type == cs_etm_pmu->type) {
209a818c563SMathieu Poirier 			if (cs_etm_evsel) {
210a818c563SMathieu Poirier 				pr_err("There may be only one %s event\n",
211a818c563SMathieu Poirier 				       CORESIGHT_ETM_PMU_NAME);
212a818c563SMathieu Poirier 				return -EINVAL;
213a818c563SMathieu Poirier 			}
214a818c563SMathieu Poirier 			evsel->attr.freq = 0;
215a818c563SMathieu Poirier 			evsel->attr.sample_period = 1;
216a818c563SMathieu Poirier 			cs_etm_evsel = evsel;
217a818c563SMathieu Poirier 			opts->full_auxtrace = true;
218a818c563SMathieu Poirier 		}
219a818c563SMathieu Poirier 	}
220a818c563SMathieu Poirier 
221a818c563SMathieu Poirier 	/* no need to continue if at least one event of interest was found */
222a818c563SMathieu Poirier 	if (!cs_etm_evsel)
223a818c563SMathieu Poirier 		return 0;
224a818c563SMathieu Poirier 
225fa4e819bSMathieu Poirier 	ret = cs_etm_set_sink_attr(cs_etm_pmu, cs_etm_evsel);
226fa4e819bSMathieu Poirier 	if (ret)
227fa4e819bSMathieu Poirier 		return ret;
228fa4e819bSMathieu Poirier 
229a818c563SMathieu Poirier 	if (opts->use_clockid) {
230a818c563SMathieu Poirier 		pr_err("Cannot use clockid (-k option) with %s\n",
231a818c563SMathieu Poirier 		       CORESIGHT_ETM_PMU_NAME);
232a818c563SMathieu Poirier 		return -EINVAL;
233a818c563SMathieu Poirier 	}
234a818c563SMathieu Poirier 
235a818c563SMathieu Poirier 	/* we are in snapshot mode */
236a818c563SMathieu Poirier 	if (opts->auxtrace_snapshot_mode) {
237a818c563SMathieu Poirier 		/*
238a818c563SMathieu Poirier 		 * No size were given to '-S' or '-m,', so go with
239a818c563SMathieu Poirier 		 * the default
240a818c563SMathieu Poirier 		 */
241a818c563SMathieu Poirier 		if (!opts->auxtrace_snapshot_size &&
242a818c563SMathieu Poirier 		    !opts->auxtrace_mmap_pages) {
243a818c563SMathieu Poirier 			if (privileged) {
244a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages = MiB(4) / page_size;
245a818c563SMathieu Poirier 			} else {
246a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages =
247a818c563SMathieu Poirier 							KiB(128) / page_size;
248a818c563SMathieu Poirier 				if (opts->mmap_pages == UINT_MAX)
249a818c563SMathieu Poirier 					opts->mmap_pages = KiB(256) / page_size;
250a818c563SMathieu Poirier 			}
251a818c563SMathieu Poirier 		} else if (!opts->auxtrace_mmap_pages && !privileged &&
252a818c563SMathieu Poirier 						opts->mmap_pages == UINT_MAX) {
253a818c563SMathieu Poirier 			opts->mmap_pages = KiB(256) / page_size;
254a818c563SMathieu Poirier 		}
255a818c563SMathieu Poirier 
256a818c563SMathieu Poirier 		/*
257a818c563SMathieu Poirier 		 * '-m,xyz' was specified but no snapshot size, so make the
258a818c563SMathieu Poirier 		 * snapshot size as big as the auxtrace mmap area.
259a818c563SMathieu Poirier 		 */
260a818c563SMathieu Poirier 		if (!opts->auxtrace_snapshot_size) {
261a818c563SMathieu Poirier 			opts->auxtrace_snapshot_size =
262a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages * (size_t)page_size;
263a818c563SMathieu Poirier 		}
264a818c563SMathieu Poirier 
265a818c563SMathieu Poirier 		/*
266a818c563SMathieu Poirier 		 * -Sxyz was specified but no auxtrace mmap area, so make the
267a818c563SMathieu Poirier 		 * auxtrace mmap area big enough to fit the requested snapshot
268a818c563SMathieu Poirier 		 * size.
269a818c563SMathieu Poirier 		 */
270a818c563SMathieu Poirier 		if (!opts->auxtrace_mmap_pages) {
271a818c563SMathieu Poirier 			size_t sz = opts->auxtrace_snapshot_size;
272a818c563SMathieu Poirier 
273a818c563SMathieu Poirier 			sz = round_up(sz, page_size) / page_size;
274a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = roundup_pow_of_two(sz);
275a818c563SMathieu Poirier 		}
276a818c563SMathieu Poirier 
277a818c563SMathieu Poirier 		/* Snapshost size can't be bigger than the auxtrace area */
278a818c563SMathieu Poirier 		if (opts->auxtrace_snapshot_size >
279a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages * (size_t)page_size) {
280a818c563SMathieu Poirier 			pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n",
281a818c563SMathieu Poirier 			       opts->auxtrace_snapshot_size,
282a818c563SMathieu Poirier 			       opts->auxtrace_mmap_pages * (size_t)page_size);
283a818c563SMathieu Poirier 			return -EINVAL;
284a818c563SMathieu Poirier 		}
285a818c563SMathieu Poirier 
286a818c563SMathieu Poirier 		/* Something went wrong somewhere - this shouldn't happen */
287a818c563SMathieu Poirier 		if (!opts->auxtrace_snapshot_size ||
288a818c563SMathieu Poirier 		    !opts->auxtrace_mmap_pages) {
289a818c563SMathieu Poirier 			pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n");
290a818c563SMathieu Poirier 			return -EINVAL;
291a818c563SMathieu Poirier 		}
292a818c563SMathieu Poirier 	}
293a818c563SMathieu Poirier 
294a818c563SMathieu Poirier 	/* We are in full trace mode but '-m,xyz' wasn't specified */
295a818c563SMathieu Poirier 	if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) {
296a818c563SMathieu Poirier 		if (privileged) {
297a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = MiB(4) / page_size;
298a818c563SMathieu Poirier 		} else {
299a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = KiB(128) / page_size;
300a818c563SMathieu Poirier 			if (opts->mmap_pages == UINT_MAX)
301a818c563SMathieu Poirier 				opts->mmap_pages = KiB(256) / page_size;
302a818c563SMathieu Poirier 		}
303a818c563SMathieu Poirier 
304a818c563SMathieu Poirier 	}
305a818c563SMathieu Poirier 
306a818c563SMathieu Poirier 	/* Validate auxtrace_mmap_pages provided by user */
307a818c563SMathieu Poirier 	if (opts->auxtrace_mmap_pages) {
308a818c563SMathieu Poirier 		unsigned int max_page = (KiB(128) / page_size);
309a818c563SMathieu Poirier 		size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size;
310a818c563SMathieu Poirier 
311a818c563SMathieu Poirier 		if (!privileged &&
312a818c563SMathieu Poirier 		    opts->auxtrace_mmap_pages > max_page) {
313a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = max_page;
314a818c563SMathieu Poirier 			pr_err("auxtrace too big, truncating to %d\n",
315a818c563SMathieu Poirier 			       max_page);
316a818c563SMathieu Poirier 		}
317a818c563SMathieu Poirier 
318a818c563SMathieu Poirier 		if (!is_power_of_2(sz)) {
319a818c563SMathieu Poirier 			pr_err("Invalid mmap size for %s: must be a power of 2\n",
320a818c563SMathieu Poirier 			       CORESIGHT_ETM_PMU_NAME);
321a818c563SMathieu Poirier 			return -EINVAL;
322a818c563SMathieu Poirier 		}
323a818c563SMathieu Poirier 	}
324a818c563SMathieu Poirier 
325a818c563SMathieu Poirier 	if (opts->auxtrace_snapshot_mode)
326a818c563SMathieu Poirier 		pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME,
327a818c563SMathieu Poirier 			  opts->auxtrace_snapshot_size);
328a818c563SMathieu Poirier 
329a818c563SMathieu Poirier 	/*
330a818c563SMathieu Poirier 	 * To obtain the auxtrace buffer file descriptor, the auxtrace
331a818c563SMathieu Poirier 	 * event must come first.
332a818c563SMathieu Poirier 	 */
333a818c563SMathieu Poirier 	perf_evlist__to_front(evlist, cs_etm_evsel);
3340c788d47SKim Phillips 
335a818c563SMathieu Poirier 	/*
336a818c563SMathieu Poirier 	 * In the case of per-cpu mmaps, we need the CPU on the
337*3399ad9aSMathieu Poirier 	 * AUX event.  We also need the contextID in order to be notified
338*3399ad9aSMathieu Poirier 	 * when a context switch happened.
339a818c563SMathieu Poirier 	 */
340*3399ad9aSMathieu Poirier 	if (!cpu_map__empty(cpus)) {
341a818c563SMathieu Poirier 		perf_evsel__set_sample_bit(cs_etm_evsel, CPU);
342a818c563SMathieu Poirier 
343*3399ad9aSMathieu Poirier 		err = cs_etm_set_option(itr, cs_etm_evsel, ETM_OPT_CTXTID);
344*3399ad9aSMathieu Poirier 		if (err)
345*3399ad9aSMathieu Poirier 			goto out;
346*3399ad9aSMathieu Poirier 	}
347*3399ad9aSMathieu Poirier 
348a818c563SMathieu Poirier 	/* Add dummy event to keep tracking */
349a818c563SMathieu Poirier 	if (opts->full_auxtrace) {
350a818c563SMathieu Poirier 		struct perf_evsel *tracking_evsel;
351a818c563SMathieu Poirier 
352a818c563SMathieu Poirier 		err = parse_events(evlist, "dummy:u", NULL);
353a818c563SMathieu Poirier 		if (err)
354*3399ad9aSMathieu Poirier 			goto out;
355a818c563SMathieu Poirier 
356a818c563SMathieu Poirier 		tracking_evsel = perf_evlist__last(evlist);
357a818c563SMathieu Poirier 		perf_evlist__set_tracking_event(evlist, tracking_evsel);
358a818c563SMathieu Poirier 
359a818c563SMathieu Poirier 		tracking_evsel->attr.freq = 0;
360a818c563SMathieu Poirier 		tracking_evsel->attr.sample_period = 1;
361a818c563SMathieu Poirier 
362a818c563SMathieu Poirier 		/* In per-cpu case, always need the time of mmap events etc */
363a818c563SMathieu Poirier 		if (!cpu_map__empty(cpus))
364a818c563SMathieu Poirier 			perf_evsel__set_sample_bit(tracking_evsel, TIME);
365a818c563SMathieu Poirier 	}
366a818c563SMathieu Poirier 
367*3399ad9aSMathieu Poirier out:
368*3399ad9aSMathieu Poirier 	return err;
369a818c563SMathieu Poirier }
370a818c563SMathieu Poirier 
371a818c563SMathieu Poirier static u64 cs_etm_get_config(struct auxtrace_record *itr)
372a818c563SMathieu Poirier {
373a818c563SMathieu Poirier 	u64 config = 0;
374a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
375a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
376a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
377a818c563SMathieu Poirier 	struct perf_evlist *evlist = ptr->evlist;
378a818c563SMathieu Poirier 	struct perf_evsel *evsel;
379a818c563SMathieu Poirier 
380a818c563SMathieu Poirier 	evlist__for_each_entry(evlist, evsel) {
381a818c563SMathieu Poirier 		if (evsel->attr.type == cs_etm_pmu->type) {
382a818c563SMathieu Poirier 			/*
383a818c563SMathieu Poirier 			 * Variable perf_event_attr::config is assigned to
384a818c563SMathieu Poirier 			 * ETMv3/PTM.  The bit fields have been made to match
385a818c563SMathieu Poirier 			 * the ETMv3.5 ETRMCR register specification.  See the
386a818c563SMathieu Poirier 			 * PMU_FORMAT_ATTR() declarations in
387a818c563SMathieu Poirier 			 * drivers/hwtracing/coresight/coresight-perf.c for
388a818c563SMathieu Poirier 			 * details.
389a818c563SMathieu Poirier 			 */
390a818c563SMathieu Poirier 			config = evsel->attr.config;
391a818c563SMathieu Poirier 			break;
392a818c563SMathieu Poirier 		}
393a818c563SMathieu Poirier 	}
394a818c563SMathieu Poirier 
395a818c563SMathieu Poirier 	return config;
396a818c563SMathieu Poirier }
397a818c563SMathieu Poirier 
398df770ff0SMike Leach #ifndef BIT
399df770ff0SMike Leach #define BIT(N) (1UL << (N))
400df770ff0SMike Leach #endif
401df770ff0SMike Leach 
402df770ff0SMike Leach static u64 cs_etmv4_get_config(struct auxtrace_record *itr)
403df770ff0SMike Leach {
404df770ff0SMike Leach 	u64 config = 0;
405df770ff0SMike Leach 	u64 config_opts = 0;
406df770ff0SMike Leach 
407df770ff0SMike Leach 	/*
408df770ff0SMike Leach 	 * The perf event variable config bits represent both
409df770ff0SMike Leach 	 * the command line options and register programming
410df770ff0SMike Leach 	 * bits in ETMv3/PTM. For ETMv4 we must remap options
411df770ff0SMike Leach 	 * to real bits
412df770ff0SMike Leach 	 */
413df770ff0SMike Leach 	config_opts = cs_etm_get_config(itr);
414df770ff0SMike Leach 	if (config_opts & BIT(ETM_OPT_CYCACC))
415df770ff0SMike Leach 		config |= BIT(ETM4_CFG_BIT_CYCACC);
416*3399ad9aSMathieu Poirier 	if (config_opts & BIT(ETM_OPT_CTXTID))
417*3399ad9aSMathieu Poirier 		config |= BIT(ETM4_CFG_BIT_CTXTID);
418df770ff0SMike Leach 	if (config_opts & BIT(ETM_OPT_TS))
419df770ff0SMike Leach 		config |= BIT(ETM4_CFG_BIT_TS);
420df770ff0SMike Leach 	if (config_opts & BIT(ETM_OPT_RETSTK))
421df770ff0SMike Leach 		config |= BIT(ETM4_CFG_BIT_RETSTK);
422df770ff0SMike Leach 
423df770ff0SMike Leach 	return config;
424df770ff0SMike Leach }
425df770ff0SMike Leach 
426a818c563SMathieu Poirier static size_t
427a818c563SMathieu Poirier cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused,
428a818c563SMathieu Poirier 		      struct perf_evlist *evlist __maybe_unused)
429a818c563SMathieu Poirier {
430a818c563SMathieu Poirier 	int i;
431a818c563SMathieu Poirier 	int etmv3 = 0, etmv4 = 0;
432796bfaddSMathieu Poirier 	struct cpu_map *event_cpus = evlist->cpus;
433796bfaddSMathieu Poirier 	struct cpu_map *online_cpus = cpu_map__new(NULL);
434a818c563SMathieu Poirier 
435a818c563SMathieu Poirier 	/* cpu map is not empty, we have specific CPUs to work with */
436796bfaddSMathieu Poirier 	if (!cpu_map__empty(event_cpus)) {
437796bfaddSMathieu Poirier 		for (i = 0; i < cpu__max_cpu(); i++) {
438796bfaddSMathieu Poirier 			if (!cpu_map__has(event_cpus, i) ||
439796bfaddSMathieu Poirier 			    !cpu_map__has(online_cpus, i))
440796bfaddSMathieu Poirier 				continue;
441796bfaddSMathieu Poirier 
442796bfaddSMathieu Poirier 			if (cs_etm_is_etmv4(itr, i))
443a818c563SMathieu Poirier 				etmv4++;
444a818c563SMathieu Poirier 			else
445a818c563SMathieu Poirier 				etmv3++;
446a818c563SMathieu Poirier 		}
447a818c563SMathieu Poirier 	} else {
448a818c563SMathieu Poirier 		/* get configuration for all CPUs in the system */
449a818c563SMathieu Poirier 		for (i = 0; i < cpu__max_cpu(); i++) {
450796bfaddSMathieu Poirier 			if (!cpu_map__has(online_cpus, i))
451796bfaddSMathieu Poirier 				continue;
452796bfaddSMathieu Poirier 
453a818c563SMathieu Poirier 			if (cs_etm_is_etmv4(itr, i))
454a818c563SMathieu Poirier 				etmv4++;
455a818c563SMathieu Poirier 			else
456a818c563SMathieu Poirier 				etmv3++;
457a818c563SMathieu Poirier 		}
458a818c563SMathieu Poirier 	}
459a818c563SMathieu Poirier 
460796bfaddSMathieu Poirier 	cpu_map__put(online_cpus);
461796bfaddSMathieu Poirier 
462a818c563SMathieu Poirier 	return (CS_ETM_HEADER_SIZE +
463a818c563SMathieu Poirier 	       (etmv4 * CS_ETMV4_PRIV_SIZE) +
464a818c563SMathieu Poirier 	       (etmv3 * CS_ETMV3_PRIV_SIZE));
465a818c563SMathieu Poirier }
466a818c563SMathieu Poirier 
467a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu)
468a818c563SMathieu Poirier {
469a818c563SMathieu Poirier 	bool ret = false;
470a818c563SMathieu Poirier 	char path[PATH_MAX];
471a818c563SMathieu Poirier 	int scan;
472a818c563SMathieu Poirier 	unsigned int val;
473a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
474a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
475a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
476a818c563SMathieu Poirier 
477a818c563SMathieu Poirier 	/* Take any of the RO files for ETMv4 and see if it present */
478a818c563SMathieu Poirier 	snprintf(path, PATH_MAX, "cpu%d/%s",
479a818c563SMathieu Poirier 		 cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]);
480a818c563SMathieu Poirier 	scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val);
481a818c563SMathieu Poirier 
482a818c563SMathieu Poirier 	/* The file was read successfully, we have a winner */
483a818c563SMathieu Poirier 	if (scan == 1)
484a818c563SMathieu Poirier 		ret = true;
485a818c563SMathieu Poirier 
486a818c563SMathieu Poirier 	return ret;
487a818c563SMathieu Poirier }
488a818c563SMathieu Poirier 
489a818c563SMathieu Poirier static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path)
490a818c563SMathieu Poirier {
491a818c563SMathieu Poirier 	char pmu_path[PATH_MAX];
492a818c563SMathieu Poirier 	int scan;
493a818c563SMathieu Poirier 	unsigned int val = 0;
494a818c563SMathieu Poirier 
495a818c563SMathieu Poirier 	/* Get RO metadata from sysfs */
496a818c563SMathieu Poirier 	snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path);
497a818c563SMathieu Poirier 
498a818c563SMathieu Poirier 	scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val);
499a818c563SMathieu Poirier 	if (scan != 1)
500a818c563SMathieu Poirier 		pr_err("%s: error reading: %s\n", __func__, pmu_path);
501a818c563SMathieu Poirier 
502a818c563SMathieu Poirier 	return val;
503a818c563SMathieu Poirier }
504a818c563SMathieu Poirier 
505a818c563SMathieu Poirier static void cs_etm_get_metadata(int cpu, u32 *offset,
506a818c563SMathieu Poirier 				struct auxtrace_record *itr,
507a818c563SMathieu Poirier 				struct auxtrace_info_event *info)
508a818c563SMathieu Poirier {
509a818c563SMathieu Poirier 	u32 increment;
510a818c563SMathieu Poirier 	u64 magic;
511a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
512a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
513a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
514a818c563SMathieu Poirier 
515a818c563SMathieu Poirier 	/* first see what kind of tracer this cpu is affined to */
516a818c563SMathieu Poirier 	if (cs_etm_is_etmv4(itr, cpu)) {
517a818c563SMathieu Poirier 		magic = __perf_cs_etmv4_magic;
518a818c563SMathieu Poirier 		/* Get trace configuration register */
519a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCCONFIGR] =
520df770ff0SMike Leach 						cs_etmv4_get_config(itr);
521a818c563SMathieu Poirier 		/* Get traceID from the framework */
522a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCTRACEIDR] =
523a818c563SMathieu Poirier 						coresight_get_trace_id(cpu);
524a818c563SMathieu Poirier 		/* Get read-only information from sysFS */
525a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR0] =
526a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
527a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR0]);
528a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR1] =
529a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
530a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR1]);
531a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR2] =
532a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
533a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR2]);
534a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR8] =
535a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
536a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR8]);
537a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCAUTHSTATUS] =
538a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
539a818c563SMathieu Poirier 				      metadata_etmv4_ro
540a818c563SMathieu Poirier 				      [CS_ETMV4_TRCAUTHSTATUS]);
541a818c563SMathieu Poirier 
542a818c563SMathieu Poirier 		/* How much space was used */
543a818c563SMathieu Poirier 		increment = CS_ETMV4_PRIV_MAX;
544a818c563SMathieu Poirier 	} else {
545a818c563SMathieu Poirier 		magic = __perf_cs_etmv3_magic;
546a818c563SMathieu Poirier 		/* Get configuration register */
547a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
548a818c563SMathieu Poirier 		/* Get traceID from the framework */
549a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMTRACEIDR] =
550a818c563SMathieu Poirier 						coresight_get_trace_id(cpu);
551a818c563SMathieu Poirier 		/* Get read-only information from sysFS */
552a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMCCER] =
553a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
554a818c563SMathieu Poirier 				      metadata_etmv3_ro[CS_ETM_ETMCCER]);
555a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMIDR] =
556a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
557a818c563SMathieu Poirier 				      metadata_etmv3_ro[CS_ETM_ETMIDR]);
558a818c563SMathieu Poirier 
559a818c563SMathieu Poirier 		/* How much space was used */
560a818c563SMathieu Poirier 		increment = CS_ETM_PRIV_MAX;
561a818c563SMathieu Poirier 	}
562a818c563SMathieu Poirier 
563a818c563SMathieu Poirier 	/* Build generic header portion */
564a818c563SMathieu Poirier 	info->priv[*offset + CS_ETM_MAGIC] = magic;
565a818c563SMathieu Poirier 	info->priv[*offset + CS_ETM_CPU] = cpu;
566a818c563SMathieu Poirier 	/* Where the next CPU entry should start from */
567a818c563SMathieu Poirier 	*offset += increment;
568a818c563SMathieu Poirier }
569a818c563SMathieu Poirier 
570a818c563SMathieu Poirier static int cs_etm_info_fill(struct auxtrace_record *itr,
571a818c563SMathieu Poirier 			    struct perf_session *session,
572a818c563SMathieu Poirier 			    struct auxtrace_info_event *info,
573a818c563SMathieu Poirier 			    size_t priv_size)
574a818c563SMathieu Poirier {
575a818c563SMathieu Poirier 	int i;
576a818c563SMathieu Poirier 	u32 offset;
577a818c563SMathieu Poirier 	u64 nr_cpu, type;
578796bfaddSMathieu Poirier 	struct cpu_map *cpu_map;
579796bfaddSMathieu Poirier 	struct cpu_map *event_cpus = session->evlist->cpus;
580796bfaddSMathieu Poirier 	struct cpu_map *online_cpus = cpu_map__new(NULL);
581a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
582a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
583a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
584a818c563SMathieu Poirier 
585a818c563SMathieu Poirier 	if (priv_size != cs_etm_info_priv_size(itr, session->evlist))
586a818c563SMathieu Poirier 		return -EINVAL;
587a818c563SMathieu Poirier 
588a818c563SMathieu Poirier 	if (!session->evlist->nr_mmaps)
589a818c563SMathieu Poirier 		return -EINVAL;
590a818c563SMathieu Poirier 
591796bfaddSMathieu Poirier 	/* If the cpu_map is empty all online CPUs are involved */
592796bfaddSMathieu Poirier 	if (cpu_map__empty(event_cpus)) {
593796bfaddSMathieu Poirier 		cpu_map = online_cpus;
594796bfaddSMathieu Poirier 	} else {
595796bfaddSMathieu Poirier 		/* Make sure all specified CPUs are online */
596796bfaddSMathieu Poirier 		for (i = 0; i < cpu_map__nr(event_cpus); i++) {
597796bfaddSMathieu Poirier 			if (cpu_map__has(event_cpus, i) &&
598796bfaddSMathieu Poirier 			    !cpu_map__has(online_cpus, i))
599796bfaddSMathieu Poirier 				return -EINVAL;
600796bfaddSMathieu Poirier 		}
601796bfaddSMathieu Poirier 
602796bfaddSMathieu Poirier 		cpu_map = event_cpus;
603796bfaddSMathieu Poirier 	}
604796bfaddSMathieu Poirier 
605796bfaddSMathieu Poirier 	nr_cpu = cpu_map__nr(cpu_map);
606a818c563SMathieu Poirier 	/* Get PMU type as dynamically assigned by the core */
607a818c563SMathieu Poirier 	type = cs_etm_pmu->type;
608a818c563SMathieu Poirier 
609a818c563SMathieu Poirier 	/* First fill out the session header */
610a818c563SMathieu Poirier 	info->type = PERF_AUXTRACE_CS_ETM;
611a818c563SMathieu Poirier 	info->priv[CS_HEADER_VERSION_0] = 0;
612a818c563SMathieu Poirier 	info->priv[CS_PMU_TYPE_CPUS] = type << 32;
613a818c563SMathieu Poirier 	info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu;
614a818c563SMathieu Poirier 	info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode;
615a818c563SMathieu Poirier 
616a818c563SMathieu Poirier 	offset = CS_ETM_SNAPSHOT + 1;
617a818c563SMathieu Poirier 
618796bfaddSMathieu Poirier 	for (i = 0; i < cpu__max_cpu() && offset < priv_size; i++)
619796bfaddSMathieu Poirier 		if (cpu_map__has(cpu_map, i))
620a818c563SMathieu Poirier 			cs_etm_get_metadata(i, &offset, itr, info);
621796bfaddSMathieu Poirier 
622796bfaddSMathieu Poirier 	cpu_map__put(online_cpus);
623a818c563SMathieu Poirier 
624a818c563SMathieu Poirier 	return 0;
625a818c563SMathieu Poirier }
626a818c563SMathieu Poirier 
627a818c563SMathieu Poirier static int cs_etm_find_snapshot(struct auxtrace_record *itr __maybe_unused,
628a818c563SMathieu Poirier 				int idx, struct auxtrace_mmap *mm,
629a818c563SMathieu Poirier 				unsigned char *data __maybe_unused,
630a818c563SMathieu Poirier 				u64 *head, u64 *old)
631a818c563SMathieu Poirier {
632a818c563SMathieu Poirier 	pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n",
633a818c563SMathieu Poirier 		  __func__, idx, (size_t)*old, (size_t)*head, mm->len);
634a818c563SMathieu Poirier 
635a818c563SMathieu Poirier 	*old = *head;
636a818c563SMathieu Poirier 	*head += mm->len;
637a818c563SMathieu Poirier 
638a818c563SMathieu Poirier 	return 0;
639a818c563SMathieu Poirier }
640a818c563SMathieu Poirier 
641a818c563SMathieu Poirier static int cs_etm_snapshot_start(struct auxtrace_record *itr)
642a818c563SMathieu Poirier {
643a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
644a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
645a818c563SMathieu Poirier 	struct perf_evsel *evsel;
646a818c563SMathieu Poirier 
647a818c563SMathieu Poirier 	evlist__for_each_entry(ptr->evlist, evsel) {
648a818c563SMathieu Poirier 		if (evsel->attr.type == ptr->cs_etm_pmu->type)
649a818c563SMathieu Poirier 			return perf_evsel__disable(evsel);
650a818c563SMathieu Poirier 	}
651a818c563SMathieu Poirier 	return -EINVAL;
652a818c563SMathieu Poirier }
653a818c563SMathieu Poirier 
654a818c563SMathieu Poirier static int cs_etm_snapshot_finish(struct auxtrace_record *itr)
655a818c563SMathieu Poirier {
656a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
657a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
658a818c563SMathieu Poirier 	struct perf_evsel *evsel;
659a818c563SMathieu Poirier 
660a818c563SMathieu Poirier 	evlist__for_each_entry(ptr->evlist, evsel) {
661a818c563SMathieu Poirier 		if (evsel->attr.type == ptr->cs_etm_pmu->type)
662a818c563SMathieu Poirier 			return perf_evsel__enable(evsel);
663a818c563SMathieu Poirier 	}
664a818c563SMathieu Poirier 	return -EINVAL;
665a818c563SMathieu Poirier }
666a818c563SMathieu Poirier 
667a818c563SMathieu Poirier static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused)
668a818c563SMathieu Poirier {
669a818c563SMathieu Poirier 	return (((u64) rand() <<  0) & 0x00000000FFFFFFFFull) |
670a818c563SMathieu Poirier 		(((u64) rand() << 32) & 0xFFFFFFFF00000000ull);
671a818c563SMathieu Poirier }
672a818c563SMathieu Poirier 
673a818c563SMathieu Poirier static void cs_etm_recording_free(struct auxtrace_record *itr)
674a818c563SMathieu Poirier {
675a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
676a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
677a818c563SMathieu Poirier 	free(ptr);
678a818c563SMathieu Poirier }
679a818c563SMathieu Poirier 
680a818c563SMathieu Poirier static int cs_etm_read_finish(struct auxtrace_record *itr, int idx)
681a818c563SMathieu Poirier {
682a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
683a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
684a818c563SMathieu Poirier 	struct perf_evsel *evsel;
685a818c563SMathieu Poirier 
686a818c563SMathieu Poirier 	evlist__for_each_entry(ptr->evlist, evsel) {
687a818c563SMathieu Poirier 		if (evsel->attr.type == ptr->cs_etm_pmu->type)
688a818c563SMathieu Poirier 			return perf_evlist__enable_event_idx(ptr->evlist,
689a818c563SMathieu Poirier 							     evsel, idx);
690a818c563SMathieu Poirier 	}
691a818c563SMathieu Poirier 
692a818c563SMathieu Poirier 	return -EINVAL;
693a818c563SMathieu Poirier }
694a818c563SMathieu Poirier 
695a818c563SMathieu Poirier struct auxtrace_record *cs_etm_record_init(int *err)
696a818c563SMathieu Poirier {
697a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu;
698a818c563SMathieu Poirier 	struct cs_etm_recording *ptr;
699a818c563SMathieu Poirier 
700a818c563SMathieu Poirier 	cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
701a818c563SMathieu Poirier 
702a818c563SMathieu Poirier 	if (!cs_etm_pmu) {
703a818c563SMathieu Poirier 		*err = -EINVAL;
704a818c563SMathieu Poirier 		goto out;
705a818c563SMathieu Poirier 	}
706a818c563SMathieu Poirier 
707a818c563SMathieu Poirier 	ptr = zalloc(sizeof(struct cs_etm_recording));
708a818c563SMathieu Poirier 	if (!ptr) {
709a818c563SMathieu Poirier 		*err = -ENOMEM;
710a818c563SMathieu Poirier 		goto out;
711a818c563SMathieu Poirier 	}
712a818c563SMathieu Poirier 
713a818c563SMathieu Poirier 	ptr->cs_etm_pmu			= cs_etm_pmu;
714a818c563SMathieu Poirier 	ptr->itr.parse_snapshot_options	= cs_etm_parse_snapshot_options;
715a818c563SMathieu Poirier 	ptr->itr.recording_options	= cs_etm_recording_options;
716a818c563SMathieu Poirier 	ptr->itr.info_priv_size		= cs_etm_info_priv_size;
717a818c563SMathieu Poirier 	ptr->itr.info_fill		= cs_etm_info_fill;
718a818c563SMathieu Poirier 	ptr->itr.find_snapshot		= cs_etm_find_snapshot;
719a818c563SMathieu Poirier 	ptr->itr.snapshot_start		= cs_etm_snapshot_start;
720a818c563SMathieu Poirier 	ptr->itr.snapshot_finish	= cs_etm_snapshot_finish;
721a818c563SMathieu Poirier 	ptr->itr.reference		= cs_etm_reference;
722a818c563SMathieu Poirier 	ptr->itr.free			= cs_etm_recording_free;
723a818c563SMathieu Poirier 	ptr->itr.read_finish		= cs_etm_read_finish;
724a818c563SMathieu Poirier 
725a818c563SMathieu Poirier 	*err = 0;
726a818c563SMathieu Poirier 	return &ptr->itr;
727a818c563SMathieu Poirier out:
728a818c563SMathieu Poirier 	return NULL;
729a818c563SMathieu Poirier }
730