xref: /linux/tools/perf/arch/arm/util/cs-etm.c (revision 862b2f8fbc5b3a13d096b06560b6408f93388cf9)
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>
148520a98dSArnaldo Carvalho de Melo #include <linux/string.h>
15a818c563SMathieu Poirier #include <linux/types.h>
167f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
17a818c563SMathieu Poirier 
18a818c563SMathieu Poirier #include "cs-etm.h"
19b4209025SArnaldo Carvalho de Melo #include "../../util/debug.h"
20aeb00b1aSArnaldo Carvalho de Melo #include "../../util/record.h"
21a818c563SMathieu Poirier #include "../../util/auxtrace.h"
22a818c563SMathieu Poirier #include "../../util/cpumap.h"
23dda1bf8eSIgor Lubashev #include "../../util/event.h"
24a818c563SMathieu Poirier #include "../../util/evlist.h"
253becf452SMathieu Poirier #include "../../util/evsel.h"
2640c7d246SArnaldo Carvalho de Melo #include "../../util/perf_api_probe.h"
2795be9d19SArnaldo Carvalho de Melo #include "../../util/evsel_config.h"
28a818c563SMathieu Poirier #include "../../util/pmu.h"
29a818c563SMathieu Poirier #include "../../util/cs-etm.h"
3020f2be1dSJiri Olsa #include <internal/lib.h> // page_size
31f2a39fe8SArnaldo Carvalho de Melo #include "../../util/session.h"
32a818c563SMathieu Poirier 
33fa4e819bSMathieu Poirier #include <errno.h>
34a818c563SMathieu Poirier #include <stdlib.h>
357a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h>
36a818c563SMathieu Poirier 
37a818c563SMathieu Poirier struct cs_etm_recording {
38a818c563SMathieu Poirier 	struct auxtrace_record	itr;
39a818c563SMathieu Poirier 	struct perf_pmu		*cs_etm_pmu;
4063503dbaSJiri Olsa 	struct evlist		*evlist;
41e45c48a9SMathieu Poirier 	int			wrapped_cnt;
42e45c48a9SMathieu Poirier 	bool			*wrapped;
43a818c563SMathieu Poirier 	bool			snapshot_mode;
44a818c563SMathieu Poirier 	size_t			snapshot_size;
45a818c563SMathieu Poirier };
46a818c563SMathieu Poirier 
473399ad9aSMathieu Poirier static const char *metadata_etmv3_ro[CS_ETM_PRIV_MAX] = {
483399ad9aSMathieu Poirier 	[CS_ETM_ETMCCER]	= "mgmt/etmccer",
493399ad9aSMathieu Poirier 	[CS_ETM_ETMIDR]		= "mgmt/etmidr",
503399ad9aSMathieu Poirier };
513399ad9aSMathieu Poirier 
523399ad9aSMathieu Poirier static const char *metadata_etmv4_ro[CS_ETMV4_PRIV_MAX] = {
533399ad9aSMathieu Poirier 	[CS_ETMV4_TRCIDR0]		= "trcidr/trcidr0",
543399ad9aSMathieu Poirier 	[CS_ETMV4_TRCIDR1]		= "trcidr/trcidr1",
553399ad9aSMathieu Poirier 	[CS_ETMV4_TRCIDR2]		= "trcidr/trcidr2",
563399ad9aSMathieu Poirier 	[CS_ETMV4_TRCIDR8]		= "trcidr/trcidr8",
573399ad9aSMathieu Poirier 	[CS_ETMV4_TRCAUTHSTATUS]	= "mgmt/trcauthstatus",
583399ad9aSMathieu Poirier };
593399ad9aSMathieu Poirier 
60a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu);
61a818c563SMathieu Poirier 
623399ad9aSMathieu Poirier static int cs_etm_set_context_id(struct auxtrace_record *itr,
6332dcd021SJiri Olsa 				 struct evsel *evsel, int cpu)
643399ad9aSMathieu Poirier {
653399ad9aSMathieu Poirier 	struct cs_etm_recording *ptr;
663399ad9aSMathieu Poirier 	struct perf_pmu *cs_etm_pmu;
673399ad9aSMathieu Poirier 	char path[PATH_MAX];
683399ad9aSMathieu Poirier 	int err = -EINVAL;
693399ad9aSMathieu Poirier 	u32 val;
703399ad9aSMathieu Poirier 
713399ad9aSMathieu Poirier 	ptr = container_of(itr, struct cs_etm_recording, itr);
723399ad9aSMathieu Poirier 	cs_etm_pmu = ptr->cs_etm_pmu;
733399ad9aSMathieu Poirier 
743399ad9aSMathieu Poirier 	if (!cs_etm_is_etmv4(itr, cpu))
753399ad9aSMathieu Poirier 		goto out;
763399ad9aSMathieu Poirier 
773399ad9aSMathieu Poirier 	/* Get a handle on TRCIRD2 */
783399ad9aSMathieu Poirier 	snprintf(path, PATH_MAX, "cpu%d/%s",
793399ad9aSMathieu Poirier 		 cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2]);
803399ad9aSMathieu Poirier 	err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val);
813399ad9aSMathieu Poirier 
823399ad9aSMathieu Poirier 	/* There was a problem reading the file, bailing out */
833399ad9aSMathieu Poirier 	if (err != 1) {
843399ad9aSMathieu Poirier 		pr_err("%s: can't read file %s\n",
853399ad9aSMathieu Poirier 		       CORESIGHT_ETM_PMU_NAME, path);
863399ad9aSMathieu Poirier 		goto out;
873399ad9aSMathieu Poirier 	}
883399ad9aSMathieu Poirier 
893399ad9aSMathieu Poirier 	/*
903399ad9aSMathieu Poirier 	 * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID tracing
913399ad9aSMathieu Poirier 	 * is supported:
923399ad9aSMathieu Poirier 	 *  0b00000 Context ID tracing is not supported.
933399ad9aSMathieu Poirier 	 *  0b00100 Maximum of 32-bit Context ID size.
943399ad9aSMathieu Poirier 	 *  All other values are reserved.
953399ad9aSMathieu Poirier 	 */
963399ad9aSMathieu Poirier 	val = BMVAL(val, 5, 9);
973399ad9aSMathieu Poirier 	if (!val || val != 0x4) {
983399ad9aSMathieu Poirier 		err = -EINVAL;
993399ad9aSMathieu Poirier 		goto out;
1003399ad9aSMathieu Poirier 	}
1013399ad9aSMathieu Poirier 
1023399ad9aSMathieu Poirier 	/* All good, let the kernel know */
1031fc632ceSJiri Olsa 	evsel->core.attr.config |= (1 << ETM_OPT_CTXTID);
1043399ad9aSMathieu Poirier 	err = 0;
1053399ad9aSMathieu Poirier 
1063399ad9aSMathieu Poirier out:
1073399ad9aSMathieu Poirier 
1083399ad9aSMathieu Poirier 	return err;
1093399ad9aSMathieu Poirier }
1103399ad9aSMathieu Poirier 
1111c839a5aSMathieu Poirier static int cs_etm_set_timestamp(struct auxtrace_record *itr,
11232dcd021SJiri Olsa 				struct evsel *evsel, int cpu)
1131c839a5aSMathieu Poirier {
1141c839a5aSMathieu Poirier 	struct cs_etm_recording *ptr;
1151c839a5aSMathieu Poirier 	struct perf_pmu *cs_etm_pmu;
1161c839a5aSMathieu Poirier 	char path[PATH_MAX];
1171c839a5aSMathieu Poirier 	int err = -EINVAL;
1181c839a5aSMathieu Poirier 	u32 val;
1191c839a5aSMathieu Poirier 
1201c839a5aSMathieu Poirier 	ptr = container_of(itr, struct cs_etm_recording, itr);
1211c839a5aSMathieu Poirier 	cs_etm_pmu = ptr->cs_etm_pmu;
1221c839a5aSMathieu Poirier 
1231c839a5aSMathieu Poirier 	if (!cs_etm_is_etmv4(itr, cpu))
1241c839a5aSMathieu Poirier 		goto out;
1251c839a5aSMathieu Poirier 
1261c839a5aSMathieu Poirier 	/* Get a handle on TRCIRD0 */
1271c839a5aSMathieu Poirier 	snprintf(path, PATH_MAX, "cpu%d/%s",
1281c839a5aSMathieu Poirier 		 cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]);
1291c839a5aSMathieu Poirier 	err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val);
1301c839a5aSMathieu Poirier 
1311c839a5aSMathieu Poirier 	/* There was a problem reading the file, bailing out */
1321c839a5aSMathieu Poirier 	if (err != 1) {
1331c839a5aSMathieu Poirier 		pr_err("%s: can't read file %s\n",
1341c839a5aSMathieu Poirier 		       CORESIGHT_ETM_PMU_NAME, path);
1351c839a5aSMathieu Poirier 		goto out;
1361c839a5aSMathieu Poirier 	}
1371c839a5aSMathieu Poirier 
1381c839a5aSMathieu Poirier 	/*
1391c839a5aSMathieu Poirier 	 * TRCIDR0.TSSIZE, bit [28-24], indicates whether global timestamping
1401c839a5aSMathieu Poirier 	 * is supported:
1411c839a5aSMathieu Poirier 	 *  0b00000 Global timestamping is not implemented
1421c839a5aSMathieu Poirier 	 *  0b00110 Implementation supports a maximum timestamp of 48bits.
1431c839a5aSMathieu Poirier 	 *  0b01000 Implementation supports a maximum timestamp of 64bits.
1441c839a5aSMathieu Poirier 	 */
1451c839a5aSMathieu Poirier 	val &= GENMASK(28, 24);
1461c839a5aSMathieu Poirier 	if (!val) {
1471c839a5aSMathieu Poirier 		err = -EINVAL;
1481c839a5aSMathieu Poirier 		goto out;
1491c839a5aSMathieu Poirier 	}
1501c839a5aSMathieu Poirier 
1511c839a5aSMathieu Poirier 	/* All good, let the kernel know */
1521fc632ceSJiri Olsa 	evsel->core.attr.config |= (1 << ETM_OPT_TS);
1531c839a5aSMathieu Poirier 	err = 0;
1541c839a5aSMathieu Poirier 
1551c839a5aSMathieu Poirier out:
1561c839a5aSMathieu Poirier 	return err;
1571c839a5aSMathieu Poirier }
1581c839a5aSMathieu Poirier 
1593399ad9aSMathieu Poirier static int cs_etm_set_option(struct auxtrace_record *itr,
16032dcd021SJiri Olsa 			     struct evsel *evsel, u32 option)
1613399ad9aSMathieu Poirier {
1623399ad9aSMathieu Poirier 	int i, err = -EINVAL;
163f72f901dSJiri Olsa 	struct perf_cpu_map *event_cpus = evsel->evlist->core.cpus;
1649c3516d1SJiri Olsa 	struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL);
1653399ad9aSMathieu Poirier 
1663399ad9aSMathieu Poirier 	/* Set option of each CPU we have */
1673399ad9aSMathieu Poirier 	for (i = 0; i < cpu__max_cpu(); i++) {
1683399ad9aSMathieu Poirier 		if (!cpu_map__has(event_cpus, i) ||
1693399ad9aSMathieu Poirier 		    !cpu_map__has(online_cpus, i))
1703399ad9aSMathieu Poirier 			continue;
1713399ad9aSMathieu Poirier 
172374d910fSMathieu Poirier 		if (option & ETM_OPT_CTXTID) {
1733399ad9aSMathieu Poirier 			err = cs_etm_set_context_id(itr, evsel, i);
1743399ad9aSMathieu Poirier 			if (err)
1753399ad9aSMathieu Poirier 				goto out;
176374d910fSMathieu Poirier 		}
177374d910fSMathieu Poirier 		if (option & ETM_OPT_TS) {
1781c839a5aSMathieu Poirier 			err = cs_etm_set_timestamp(itr, evsel, i);
1791c839a5aSMathieu Poirier 			if (err)
1801c839a5aSMathieu Poirier 				goto out;
1813399ad9aSMathieu Poirier 		}
182374d910fSMathieu Poirier 		if (option & ~(ETM_OPT_CTXTID | ETM_OPT_TS))
183374d910fSMathieu Poirier 			/* Nothing else is currently supported */
184374d910fSMathieu Poirier 			goto out;
1853399ad9aSMathieu Poirier 	}
1863399ad9aSMathieu Poirier 
1873399ad9aSMathieu Poirier 	err = 0;
1883399ad9aSMathieu Poirier out:
18938f01d8dSJiri Olsa 	perf_cpu_map__put(online_cpus);
1903399ad9aSMathieu Poirier 	return err;
1913399ad9aSMathieu Poirier }
1923399ad9aSMathieu Poirier 
193a818c563SMathieu Poirier static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr,
194a818c563SMathieu Poirier 					 struct record_opts *opts,
195a818c563SMathieu Poirier 					 const char *str)
196a818c563SMathieu Poirier {
197a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
198a818c563SMathieu Poirier 				container_of(itr, struct cs_etm_recording, itr);
199a818c563SMathieu Poirier 	unsigned long long snapshot_size = 0;
200a818c563SMathieu Poirier 	char *endptr;
201a818c563SMathieu Poirier 
202a818c563SMathieu Poirier 	if (str) {
203a818c563SMathieu Poirier 		snapshot_size = strtoull(str, &endptr, 0);
204a818c563SMathieu Poirier 		if (*endptr || snapshot_size > SIZE_MAX)
205a818c563SMathieu Poirier 			return -1;
206a818c563SMathieu Poirier 	}
207a818c563SMathieu Poirier 
208a818c563SMathieu Poirier 	opts->auxtrace_snapshot_mode = true;
209a818c563SMathieu Poirier 	opts->auxtrace_snapshot_size = snapshot_size;
210a818c563SMathieu Poirier 	ptr->snapshot_size = snapshot_size;
211a818c563SMathieu Poirier 
212a818c563SMathieu Poirier 	return 0;
213a818c563SMathieu Poirier }
214a818c563SMathieu Poirier 
215fa4e819bSMathieu Poirier static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
21632dcd021SJiri Olsa 				struct evsel *evsel)
217fa4e819bSMathieu Poirier {
218fa4e819bSMathieu Poirier 	char msg[BUFSIZ], path[PATH_MAX], *sink;
219fa4e819bSMathieu Poirier 	struct perf_evsel_config_term *term;
220fa4e819bSMathieu Poirier 	int ret = -EINVAL;
221fa4e819bSMathieu Poirier 	u32 hash;
222fa4e819bSMathieu Poirier 
2231fc632ceSJiri Olsa 	if (evsel->core.attr.config2 & GENMASK(31, 0))
224fa4e819bSMathieu Poirier 		return 0;
225fa4e819bSMathieu Poirier 
226fa4e819bSMathieu Poirier 	list_for_each_entry(term, &evsel->config_terms, list) {
227fa4e819bSMathieu Poirier 		if (term->type != PERF_EVSEL__CONFIG_TERM_DRV_CFG)
228fa4e819bSMathieu Poirier 			continue;
229fa4e819bSMathieu Poirier 
230e884602bSLeo Yan 		sink = term->val.str;
231fa4e819bSMathieu Poirier 		snprintf(path, PATH_MAX, "sinks/%s", sink);
232fa4e819bSMathieu Poirier 
233fa4e819bSMathieu Poirier 		ret = perf_pmu__scan_file(pmu, path, "%x", &hash);
234fa4e819bSMathieu Poirier 		if (ret != 1) {
235fa4e819bSMathieu Poirier 			pr_err("failed to set sink \"%s\" on event %s with %d (%s)\n",
2368ab2e96dSArnaldo Carvalho de Melo 			       sink, evsel__name(evsel), errno,
237fa4e819bSMathieu Poirier 			       str_error_r(errno, msg, sizeof(msg)));
238fa4e819bSMathieu Poirier 			return ret;
239fa4e819bSMathieu Poirier 		}
240fa4e819bSMathieu Poirier 
2411fc632ceSJiri Olsa 		evsel->core.attr.config2 |= hash;
242fa4e819bSMathieu Poirier 		return 0;
243fa4e819bSMathieu Poirier 	}
244fa4e819bSMathieu Poirier 
245fa4e819bSMathieu Poirier 	/*
246fa4e819bSMathieu Poirier 	 * No sink was provided on the command line - for _now_ treat
247fa4e819bSMathieu Poirier 	 * this as an error.
248fa4e819bSMathieu Poirier 	 */
249fa4e819bSMathieu Poirier 	return ret;
250fa4e819bSMathieu Poirier }
251fa4e819bSMathieu Poirier 
252a818c563SMathieu Poirier static int cs_etm_recording_options(struct auxtrace_record *itr,
25363503dbaSJiri Olsa 				    struct evlist *evlist,
254a818c563SMathieu Poirier 				    struct record_opts *opts)
255a818c563SMathieu Poirier {
256fa4e819bSMathieu Poirier 	int ret;
257a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
258a818c563SMathieu Poirier 				container_of(itr, struct cs_etm_recording, itr);
259a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
26032dcd021SJiri Olsa 	struct evsel *evsel, *cs_etm_evsel = NULL;
261f72f901dSJiri Olsa 	struct perf_cpu_map *cpus = evlist->core.cpus;
262dda1bf8eSIgor Lubashev 	bool privileged = perf_event_paranoid_check(-1);
2633399ad9aSMathieu Poirier 	int err = 0;
264a818c563SMathieu Poirier 
265a818c563SMathieu Poirier 	ptr->evlist = evlist;
266a818c563SMathieu Poirier 	ptr->snapshot_mode = opts->auxtrace_snapshot_mode;
267a818c563SMathieu Poirier 
268e5993c42SMathieu Poirier 	if (perf_can_record_switch_events())
269e5993c42SMathieu Poirier 		opts->record_switch_events = true;
270e5993c42SMathieu Poirier 
271a818c563SMathieu Poirier 	evlist__for_each_entry(evlist, evsel) {
2721fc632ceSJiri Olsa 		if (evsel->core.attr.type == cs_etm_pmu->type) {
273a818c563SMathieu Poirier 			if (cs_etm_evsel) {
274a818c563SMathieu Poirier 				pr_err("There may be only one %s event\n",
275a818c563SMathieu Poirier 				       CORESIGHT_ETM_PMU_NAME);
276a818c563SMathieu Poirier 				return -EINVAL;
277a818c563SMathieu Poirier 			}
2781fc632ceSJiri Olsa 			evsel->core.attr.freq = 0;
2791fc632ceSJiri Olsa 			evsel->core.attr.sample_period = 1;
280a818c563SMathieu Poirier 			cs_etm_evsel = evsel;
281a818c563SMathieu Poirier 			opts->full_auxtrace = true;
282a818c563SMathieu Poirier 		}
283a818c563SMathieu Poirier 	}
284a818c563SMathieu Poirier 
285a818c563SMathieu Poirier 	/* no need to continue if at least one event of interest was found */
286a818c563SMathieu Poirier 	if (!cs_etm_evsel)
287a818c563SMathieu Poirier 		return 0;
288a818c563SMathieu Poirier 
289fa4e819bSMathieu Poirier 	ret = cs_etm_set_sink_attr(cs_etm_pmu, cs_etm_evsel);
290fa4e819bSMathieu Poirier 	if (ret)
291fa4e819bSMathieu Poirier 		return ret;
292fa4e819bSMathieu Poirier 
293a818c563SMathieu Poirier 	if (opts->use_clockid) {
294a818c563SMathieu Poirier 		pr_err("Cannot use clockid (-k option) with %s\n",
295a818c563SMathieu Poirier 		       CORESIGHT_ETM_PMU_NAME);
296a818c563SMathieu Poirier 		return -EINVAL;
297a818c563SMathieu Poirier 	}
298a818c563SMathieu Poirier 
299a818c563SMathieu Poirier 	/* we are in snapshot mode */
300a818c563SMathieu Poirier 	if (opts->auxtrace_snapshot_mode) {
301a818c563SMathieu Poirier 		/*
302a818c563SMathieu Poirier 		 * No size were given to '-S' or '-m,', so go with
303a818c563SMathieu Poirier 		 * the default
304a818c563SMathieu Poirier 		 */
305a818c563SMathieu Poirier 		if (!opts->auxtrace_snapshot_size &&
306a818c563SMathieu Poirier 		    !opts->auxtrace_mmap_pages) {
307a818c563SMathieu Poirier 			if (privileged) {
308a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages = MiB(4) / page_size;
309a818c563SMathieu Poirier 			} else {
310a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages =
311a818c563SMathieu Poirier 							KiB(128) / page_size;
312a818c563SMathieu Poirier 				if (opts->mmap_pages == UINT_MAX)
313a818c563SMathieu Poirier 					opts->mmap_pages = KiB(256) / page_size;
314a818c563SMathieu Poirier 			}
315a818c563SMathieu Poirier 		} else if (!opts->auxtrace_mmap_pages && !privileged &&
316a818c563SMathieu Poirier 						opts->mmap_pages == UINT_MAX) {
317a818c563SMathieu Poirier 			opts->mmap_pages = KiB(256) / page_size;
318a818c563SMathieu Poirier 		}
319a818c563SMathieu Poirier 
320a818c563SMathieu Poirier 		/*
321a818c563SMathieu Poirier 		 * '-m,xyz' was specified but no snapshot size, so make the
322a818c563SMathieu Poirier 		 * snapshot size as big as the auxtrace mmap area.
323a818c563SMathieu Poirier 		 */
324a818c563SMathieu Poirier 		if (!opts->auxtrace_snapshot_size) {
325a818c563SMathieu Poirier 			opts->auxtrace_snapshot_size =
326a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages * (size_t)page_size;
327a818c563SMathieu Poirier 		}
328a818c563SMathieu Poirier 
329a818c563SMathieu Poirier 		/*
330a818c563SMathieu Poirier 		 * -Sxyz was specified but no auxtrace mmap area, so make the
331a818c563SMathieu Poirier 		 * auxtrace mmap area big enough to fit the requested snapshot
332a818c563SMathieu Poirier 		 * size.
333a818c563SMathieu Poirier 		 */
334a818c563SMathieu Poirier 		if (!opts->auxtrace_mmap_pages) {
335a818c563SMathieu Poirier 			size_t sz = opts->auxtrace_snapshot_size;
336a818c563SMathieu Poirier 
337a818c563SMathieu Poirier 			sz = round_up(sz, page_size) / page_size;
338a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = roundup_pow_of_two(sz);
339a818c563SMathieu Poirier 		}
340a818c563SMathieu Poirier 
341a818c563SMathieu Poirier 		/* Snapshost size can't be bigger than the auxtrace area */
342a818c563SMathieu Poirier 		if (opts->auxtrace_snapshot_size >
343a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages * (size_t)page_size) {
344a818c563SMathieu Poirier 			pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n",
345a818c563SMathieu Poirier 			       opts->auxtrace_snapshot_size,
346a818c563SMathieu Poirier 			       opts->auxtrace_mmap_pages * (size_t)page_size);
347a818c563SMathieu Poirier 			return -EINVAL;
348a818c563SMathieu Poirier 		}
349a818c563SMathieu Poirier 
350a818c563SMathieu Poirier 		/* Something went wrong somewhere - this shouldn't happen */
351a818c563SMathieu Poirier 		if (!opts->auxtrace_snapshot_size ||
352a818c563SMathieu Poirier 		    !opts->auxtrace_mmap_pages) {
353a818c563SMathieu Poirier 			pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n");
354a818c563SMathieu Poirier 			return -EINVAL;
355a818c563SMathieu Poirier 		}
356a818c563SMathieu Poirier 	}
357a818c563SMathieu Poirier 
358a818c563SMathieu Poirier 	/* We are in full trace mode but '-m,xyz' wasn't specified */
359a818c563SMathieu Poirier 	if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) {
360a818c563SMathieu Poirier 		if (privileged) {
361a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = MiB(4) / page_size;
362a818c563SMathieu Poirier 		} else {
363a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = KiB(128) / page_size;
364a818c563SMathieu Poirier 			if (opts->mmap_pages == UINT_MAX)
365a818c563SMathieu Poirier 				opts->mmap_pages = KiB(256) / page_size;
366a818c563SMathieu Poirier 		}
367a818c563SMathieu Poirier 
368a818c563SMathieu Poirier 	}
369a818c563SMathieu Poirier 
370a818c563SMathieu Poirier 	/* Validate auxtrace_mmap_pages provided by user */
371a818c563SMathieu Poirier 	if (opts->auxtrace_mmap_pages) {
372a818c563SMathieu Poirier 		unsigned int max_page = (KiB(128) / page_size);
373a818c563SMathieu Poirier 		size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size;
374a818c563SMathieu Poirier 
375a818c563SMathieu Poirier 		if (!privileged &&
376a818c563SMathieu Poirier 		    opts->auxtrace_mmap_pages > max_page) {
377a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = max_page;
378a818c563SMathieu Poirier 			pr_err("auxtrace too big, truncating to %d\n",
379a818c563SMathieu Poirier 			       max_page);
380a818c563SMathieu Poirier 		}
381a818c563SMathieu Poirier 
382a818c563SMathieu Poirier 		if (!is_power_of_2(sz)) {
383a818c563SMathieu Poirier 			pr_err("Invalid mmap size for %s: must be a power of 2\n",
384a818c563SMathieu Poirier 			       CORESIGHT_ETM_PMU_NAME);
385a818c563SMathieu Poirier 			return -EINVAL;
386a818c563SMathieu Poirier 		}
387a818c563SMathieu Poirier 	}
388a818c563SMathieu Poirier 
389a818c563SMathieu Poirier 	if (opts->auxtrace_snapshot_mode)
390a818c563SMathieu Poirier 		pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME,
391a818c563SMathieu Poirier 			  opts->auxtrace_snapshot_size);
392a818c563SMathieu Poirier 
393a818c563SMathieu Poirier 	/*
394a818c563SMathieu Poirier 	 * To obtain the auxtrace buffer file descriptor, the auxtrace
395a818c563SMathieu Poirier 	 * event must come first.
396a818c563SMathieu Poirier 	 */
397a818c563SMathieu Poirier 	perf_evlist__to_front(evlist, cs_etm_evsel);
3980c788d47SKim Phillips 
399a818c563SMathieu Poirier 	/*
400a818c563SMathieu Poirier 	 * In the case of per-cpu mmaps, we need the CPU on the
4013399ad9aSMathieu Poirier 	 * AUX event.  We also need the contextID in order to be notified
4023399ad9aSMathieu Poirier 	 * when a context switch happened.
403a818c563SMathieu Poirier 	 */
404315c0a1fSJiri Olsa 	if (!perf_cpu_map__empty(cpus)) {
405*862b2f8fSArnaldo Carvalho de Melo 		evsel__set_sample_bit(cs_etm_evsel, CPU);
406a818c563SMathieu Poirier 
407374d910fSMathieu Poirier 		err = cs_etm_set_option(itr, cs_etm_evsel,
408374d910fSMathieu Poirier 					ETM_OPT_CTXTID | ETM_OPT_TS);
4091c839a5aSMathieu Poirier 		if (err)
4101c839a5aSMathieu Poirier 			goto out;
4113399ad9aSMathieu Poirier 	}
4123399ad9aSMathieu Poirier 
413a818c563SMathieu Poirier 	/* Add dummy event to keep tracking */
414a818c563SMathieu Poirier 	if (opts->full_auxtrace) {
41532dcd021SJiri Olsa 		struct evsel *tracking_evsel;
416a818c563SMathieu Poirier 
417a818c563SMathieu Poirier 		err = parse_events(evlist, "dummy:u", NULL);
418a818c563SMathieu Poirier 		if (err)
4193399ad9aSMathieu Poirier 			goto out;
420a818c563SMathieu Poirier 
421515dbe48SJiri Olsa 		tracking_evsel = evlist__last(evlist);
422a818c563SMathieu Poirier 		perf_evlist__set_tracking_event(evlist, tracking_evsel);
423a818c563SMathieu Poirier 
4241fc632ceSJiri Olsa 		tracking_evsel->core.attr.freq = 0;
4251fc632ceSJiri Olsa 		tracking_evsel->core.attr.sample_period = 1;
426a818c563SMathieu Poirier 
427a818c563SMathieu Poirier 		/* In per-cpu case, always need the time of mmap events etc */
428315c0a1fSJiri Olsa 		if (!perf_cpu_map__empty(cpus))
429*862b2f8fSArnaldo Carvalho de Melo 			evsel__set_sample_bit(tracking_evsel, TIME);
430a818c563SMathieu Poirier 	}
431a818c563SMathieu Poirier 
4323399ad9aSMathieu Poirier out:
4333399ad9aSMathieu Poirier 	return err;
434a818c563SMathieu Poirier }
435a818c563SMathieu Poirier 
436a818c563SMathieu Poirier static u64 cs_etm_get_config(struct auxtrace_record *itr)
437a818c563SMathieu Poirier {
438a818c563SMathieu Poirier 	u64 config = 0;
439a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
440a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
441a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
44263503dbaSJiri Olsa 	struct evlist *evlist = ptr->evlist;
44332dcd021SJiri Olsa 	struct evsel *evsel;
444a818c563SMathieu Poirier 
445a818c563SMathieu Poirier 	evlist__for_each_entry(evlist, evsel) {
4461fc632ceSJiri Olsa 		if (evsel->core.attr.type == cs_etm_pmu->type) {
447a818c563SMathieu Poirier 			/*
448a818c563SMathieu Poirier 			 * Variable perf_event_attr::config is assigned to
449a818c563SMathieu Poirier 			 * ETMv3/PTM.  The bit fields have been made to match
450a818c563SMathieu Poirier 			 * the ETMv3.5 ETRMCR register specification.  See the
451a818c563SMathieu Poirier 			 * PMU_FORMAT_ATTR() declarations in
452a818c563SMathieu Poirier 			 * drivers/hwtracing/coresight/coresight-perf.c for
453a818c563SMathieu Poirier 			 * details.
454a818c563SMathieu Poirier 			 */
4551fc632ceSJiri Olsa 			config = evsel->core.attr.config;
456a818c563SMathieu Poirier 			break;
457a818c563SMathieu Poirier 		}
458a818c563SMathieu Poirier 	}
459a818c563SMathieu Poirier 
460a818c563SMathieu Poirier 	return config;
461a818c563SMathieu Poirier }
462a818c563SMathieu Poirier 
463df770ff0SMike Leach #ifndef BIT
464df770ff0SMike Leach #define BIT(N) (1UL << (N))
465df770ff0SMike Leach #endif
466df770ff0SMike Leach 
467df770ff0SMike Leach static u64 cs_etmv4_get_config(struct auxtrace_record *itr)
468df770ff0SMike Leach {
469df770ff0SMike Leach 	u64 config = 0;
470df770ff0SMike Leach 	u64 config_opts = 0;
471df770ff0SMike Leach 
472df770ff0SMike Leach 	/*
473df770ff0SMike Leach 	 * The perf event variable config bits represent both
474df770ff0SMike Leach 	 * the command line options and register programming
475df770ff0SMike Leach 	 * bits in ETMv3/PTM. For ETMv4 we must remap options
476df770ff0SMike Leach 	 * to real bits
477df770ff0SMike Leach 	 */
478df770ff0SMike Leach 	config_opts = cs_etm_get_config(itr);
479df770ff0SMike Leach 	if (config_opts & BIT(ETM_OPT_CYCACC))
480df770ff0SMike Leach 		config |= BIT(ETM4_CFG_BIT_CYCACC);
4813399ad9aSMathieu Poirier 	if (config_opts & BIT(ETM_OPT_CTXTID))
4823399ad9aSMathieu Poirier 		config |= BIT(ETM4_CFG_BIT_CTXTID);
483df770ff0SMike Leach 	if (config_opts & BIT(ETM_OPT_TS))
484df770ff0SMike Leach 		config |= BIT(ETM4_CFG_BIT_TS);
485df770ff0SMike Leach 	if (config_opts & BIT(ETM_OPT_RETSTK))
486df770ff0SMike Leach 		config |= BIT(ETM4_CFG_BIT_RETSTK);
487df770ff0SMike Leach 
488df770ff0SMike Leach 	return config;
489df770ff0SMike Leach }
490df770ff0SMike Leach 
491a818c563SMathieu Poirier static size_t
492a818c563SMathieu Poirier cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused,
49363503dbaSJiri Olsa 		      struct evlist *evlist __maybe_unused)
494a818c563SMathieu Poirier {
495a818c563SMathieu Poirier 	int i;
496a818c563SMathieu Poirier 	int etmv3 = 0, etmv4 = 0;
497f72f901dSJiri Olsa 	struct perf_cpu_map *event_cpus = evlist->core.cpus;
4989c3516d1SJiri Olsa 	struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL);
499a818c563SMathieu Poirier 
500a818c563SMathieu Poirier 	/* cpu map is not empty, we have specific CPUs to work with */
501315c0a1fSJiri Olsa 	if (!perf_cpu_map__empty(event_cpus)) {
502796bfaddSMathieu Poirier 		for (i = 0; i < cpu__max_cpu(); i++) {
503796bfaddSMathieu Poirier 			if (!cpu_map__has(event_cpus, i) ||
504796bfaddSMathieu Poirier 			    !cpu_map__has(online_cpus, i))
505796bfaddSMathieu Poirier 				continue;
506796bfaddSMathieu Poirier 
507796bfaddSMathieu Poirier 			if (cs_etm_is_etmv4(itr, i))
508a818c563SMathieu Poirier 				etmv4++;
509a818c563SMathieu Poirier 			else
510a818c563SMathieu Poirier 				etmv3++;
511a818c563SMathieu Poirier 		}
512a818c563SMathieu Poirier 	} else {
513a818c563SMathieu Poirier 		/* get configuration for all CPUs in the system */
514a818c563SMathieu Poirier 		for (i = 0; i < cpu__max_cpu(); i++) {
515796bfaddSMathieu Poirier 			if (!cpu_map__has(online_cpus, i))
516796bfaddSMathieu Poirier 				continue;
517796bfaddSMathieu Poirier 
518a818c563SMathieu Poirier 			if (cs_etm_is_etmv4(itr, i))
519a818c563SMathieu Poirier 				etmv4++;
520a818c563SMathieu Poirier 			else
521a818c563SMathieu Poirier 				etmv3++;
522a818c563SMathieu Poirier 		}
523a818c563SMathieu Poirier 	}
524a818c563SMathieu Poirier 
52538f01d8dSJiri Olsa 	perf_cpu_map__put(online_cpus);
526796bfaddSMathieu Poirier 
527a818c563SMathieu Poirier 	return (CS_ETM_HEADER_SIZE +
528a818c563SMathieu Poirier 	       (etmv4 * CS_ETMV4_PRIV_SIZE) +
529a818c563SMathieu Poirier 	       (etmv3 * CS_ETMV3_PRIV_SIZE));
530a818c563SMathieu Poirier }
531a818c563SMathieu Poirier 
532a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu)
533a818c563SMathieu Poirier {
534a818c563SMathieu Poirier 	bool ret = false;
535a818c563SMathieu Poirier 	char path[PATH_MAX];
536a818c563SMathieu Poirier 	int scan;
537a818c563SMathieu Poirier 	unsigned int val;
538a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
539a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
540a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
541a818c563SMathieu Poirier 
542a818c563SMathieu Poirier 	/* Take any of the RO files for ETMv4 and see if it present */
543a818c563SMathieu Poirier 	snprintf(path, PATH_MAX, "cpu%d/%s",
544a818c563SMathieu Poirier 		 cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]);
545a818c563SMathieu Poirier 	scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val);
546a818c563SMathieu Poirier 
547a818c563SMathieu Poirier 	/* The file was read successfully, we have a winner */
548a818c563SMathieu Poirier 	if (scan == 1)
549a818c563SMathieu Poirier 		ret = true;
550a818c563SMathieu Poirier 
551a818c563SMathieu Poirier 	return ret;
552a818c563SMathieu Poirier }
553a818c563SMathieu Poirier 
554a818c563SMathieu Poirier static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path)
555a818c563SMathieu Poirier {
556a818c563SMathieu Poirier 	char pmu_path[PATH_MAX];
557a818c563SMathieu Poirier 	int scan;
558a818c563SMathieu Poirier 	unsigned int val = 0;
559a818c563SMathieu Poirier 
560a818c563SMathieu Poirier 	/* Get RO metadata from sysfs */
561a818c563SMathieu Poirier 	snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path);
562a818c563SMathieu Poirier 
563a818c563SMathieu Poirier 	scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val);
564a818c563SMathieu Poirier 	if (scan != 1)
565a818c563SMathieu Poirier 		pr_err("%s: error reading: %s\n", __func__, pmu_path);
566a818c563SMathieu Poirier 
567a818c563SMathieu Poirier 	return val;
568a818c563SMathieu Poirier }
569a818c563SMathieu Poirier 
570a818c563SMathieu Poirier static void cs_etm_get_metadata(int cpu, u32 *offset,
571a818c563SMathieu Poirier 				struct auxtrace_record *itr,
57272932371SJiri Olsa 				struct perf_record_auxtrace_info *info)
573a818c563SMathieu Poirier {
574a818c563SMathieu Poirier 	u32 increment;
575a818c563SMathieu Poirier 	u64 magic;
576a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
577a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
578a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
579a818c563SMathieu Poirier 
580a818c563SMathieu Poirier 	/* first see what kind of tracer this cpu is affined to */
581a818c563SMathieu Poirier 	if (cs_etm_is_etmv4(itr, cpu)) {
582a818c563SMathieu Poirier 		magic = __perf_cs_etmv4_magic;
583a818c563SMathieu Poirier 		/* Get trace configuration register */
584a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCCONFIGR] =
585df770ff0SMike Leach 						cs_etmv4_get_config(itr);
586a818c563SMathieu Poirier 		/* Get traceID from the framework */
587a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCTRACEIDR] =
588a818c563SMathieu Poirier 						coresight_get_trace_id(cpu);
589a818c563SMathieu Poirier 		/* Get read-only information from sysFS */
590a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR0] =
591a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
592a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR0]);
593a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR1] =
594a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
595a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR1]);
596a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR2] =
597a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
598a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR2]);
599a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR8] =
600a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
601a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR8]);
602a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCAUTHSTATUS] =
603a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
604a818c563SMathieu Poirier 				      metadata_etmv4_ro
605a818c563SMathieu Poirier 				      [CS_ETMV4_TRCAUTHSTATUS]);
606a818c563SMathieu Poirier 
607a818c563SMathieu Poirier 		/* How much space was used */
608a818c563SMathieu Poirier 		increment = CS_ETMV4_PRIV_MAX;
609a818c563SMathieu Poirier 	} else {
610a818c563SMathieu Poirier 		magic = __perf_cs_etmv3_magic;
611a818c563SMathieu Poirier 		/* Get configuration register */
612a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
613a818c563SMathieu Poirier 		/* Get traceID from the framework */
614a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMTRACEIDR] =
615a818c563SMathieu Poirier 						coresight_get_trace_id(cpu);
616a818c563SMathieu Poirier 		/* Get read-only information from sysFS */
617a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMCCER] =
618a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
619a818c563SMathieu Poirier 				      metadata_etmv3_ro[CS_ETM_ETMCCER]);
620a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMIDR] =
621a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
622a818c563SMathieu Poirier 				      metadata_etmv3_ro[CS_ETM_ETMIDR]);
623a818c563SMathieu Poirier 
624a818c563SMathieu Poirier 		/* How much space was used */
625a818c563SMathieu Poirier 		increment = CS_ETM_PRIV_MAX;
626a818c563SMathieu Poirier 	}
627a818c563SMathieu Poirier 
628a818c563SMathieu Poirier 	/* Build generic header portion */
629a818c563SMathieu Poirier 	info->priv[*offset + CS_ETM_MAGIC] = magic;
630a818c563SMathieu Poirier 	info->priv[*offset + CS_ETM_CPU] = cpu;
631a818c563SMathieu Poirier 	/* Where the next CPU entry should start from */
632a818c563SMathieu Poirier 	*offset += increment;
633a818c563SMathieu Poirier }
634a818c563SMathieu Poirier 
635a818c563SMathieu Poirier static int cs_etm_info_fill(struct auxtrace_record *itr,
636a818c563SMathieu Poirier 			    struct perf_session *session,
63772932371SJiri Olsa 			    struct perf_record_auxtrace_info *info,
638a818c563SMathieu Poirier 			    size_t priv_size)
639a818c563SMathieu Poirier {
640a818c563SMathieu Poirier 	int i;
641a818c563SMathieu Poirier 	u32 offset;
642a818c563SMathieu Poirier 	u64 nr_cpu, type;
643f854839bSJiri Olsa 	struct perf_cpu_map *cpu_map;
644f72f901dSJiri Olsa 	struct perf_cpu_map *event_cpus = session->evlist->core.cpus;
6459c3516d1SJiri Olsa 	struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL);
646a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
647a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
648a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
649a818c563SMathieu Poirier 
650a818c563SMathieu Poirier 	if (priv_size != cs_etm_info_priv_size(itr, session->evlist))
651a818c563SMathieu Poirier 		return -EINVAL;
652a818c563SMathieu Poirier 
653c976ee11SJiri Olsa 	if (!session->evlist->core.nr_mmaps)
654a818c563SMathieu Poirier 		return -EINVAL;
655a818c563SMathieu Poirier 
656796bfaddSMathieu Poirier 	/* If the cpu_map is empty all online CPUs are involved */
657315c0a1fSJiri Olsa 	if (perf_cpu_map__empty(event_cpus)) {
658796bfaddSMathieu Poirier 		cpu_map = online_cpus;
659796bfaddSMathieu Poirier 	} else {
660796bfaddSMathieu Poirier 		/* Make sure all specified CPUs are online */
6616549cd8fSJiri Olsa 		for (i = 0; i < perf_cpu_map__nr(event_cpus); i++) {
662796bfaddSMathieu Poirier 			if (cpu_map__has(event_cpus, i) &&
663796bfaddSMathieu Poirier 			    !cpu_map__has(online_cpus, i))
664796bfaddSMathieu Poirier 				return -EINVAL;
665796bfaddSMathieu Poirier 		}
666796bfaddSMathieu Poirier 
667796bfaddSMathieu Poirier 		cpu_map = event_cpus;
668796bfaddSMathieu Poirier 	}
669796bfaddSMathieu Poirier 
6706549cd8fSJiri Olsa 	nr_cpu = perf_cpu_map__nr(cpu_map);
671a818c563SMathieu Poirier 	/* Get PMU type as dynamically assigned by the core */
672a818c563SMathieu Poirier 	type = cs_etm_pmu->type;
673a818c563SMathieu Poirier 
674a818c563SMathieu Poirier 	/* First fill out the session header */
675a818c563SMathieu Poirier 	info->type = PERF_AUXTRACE_CS_ETM;
676a818c563SMathieu Poirier 	info->priv[CS_HEADER_VERSION_0] = 0;
677a818c563SMathieu Poirier 	info->priv[CS_PMU_TYPE_CPUS] = type << 32;
678a818c563SMathieu Poirier 	info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu;
679a818c563SMathieu Poirier 	info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode;
680a818c563SMathieu Poirier 
681a818c563SMathieu Poirier 	offset = CS_ETM_SNAPSHOT + 1;
682a818c563SMathieu Poirier 
683796bfaddSMathieu Poirier 	for (i = 0; i < cpu__max_cpu() && offset < priv_size; i++)
684796bfaddSMathieu Poirier 		if (cpu_map__has(cpu_map, i))
685a818c563SMathieu Poirier 			cs_etm_get_metadata(i, &offset, itr, info);
686796bfaddSMathieu Poirier 
68738f01d8dSJiri Olsa 	perf_cpu_map__put(online_cpus);
688a818c563SMathieu Poirier 
689a818c563SMathieu Poirier 	return 0;
690a818c563SMathieu Poirier }
691a818c563SMathieu Poirier 
692e45c48a9SMathieu Poirier static int cs_etm_alloc_wrapped_array(struct cs_etm_recording *ptr, int idx)
693e45c48a9SMathieu Poirier {
694e45c48a9SMathieu Poirier 	bool *wrapped;
695e45c48a9SMathieu Poirier 	int cnt = ptr->wrapped_cnt;
696e45c48a9SMathieu Poirier 
697e45c48a9SMathieu Poirier 	/* Make @ptr->wrapped as big as @idx */
698e45c48a9SMathieu Poirier 	while (cnt <= idx)
699e45c48a9SMathieu Poirier 		cnt++;
700e45c48a9SMathieu Poirier 
701e45c48a9SMathieu Poirier 	/*
702e45c48a9SMathieu Poirier 	 * Free'ed in cs_etm_recording_free().  Using realloc() to avoid
703e45c48a9SMathieu Poirier 	 * cross compilation problems where the host's system supports
704e45c48a9SMathieu Poirier 	 * reallocarray() but not the target.
705e45c48a9SMathieu Poirier 	 */
706e45c48a9SMathieu Poirier 	wrapped = realloc(ptr->wrapped, cnt * sizeof(bool));
707e45c48a9SMathieu Poirier 	if (!wrapped)
708e45c48a9SMathieu Poirier 		return -ENOMEM;
709e45c48a9SMathieu Poirier 
710e45c48a9SMathieu Poirier 	wrapped[cnt - 1] = false;
711e45c48a9SMathieu Poirier 	ptr->wrapped_cnt = cnt;
712e45c48a9SMathieu Poirier 	ptr->wrapped = wrapped;
713e45c48a9SMathieu Poirier 
714e45c48a9SMathieu Poirier 	return 0;
715e45c48a9SMathieu Poirier }
716e45c48a9SMathieu Poirier 
717e45c48a9SMathieu Poirier static bool cs_etm_buffer_has_wrapped(unsigned char *buffer,
718e45c48a9SMathieu Poirier 				      size_t buffer_size, u64 head)
719e45c48a9SMathieu Poirier {
720e45c48a9SMathieu Poirier 	u64 i, watermark;
721e45c48a9SMathieu Poirier 	u64 *buf = (u64 *)buffer;
722e45c48a9SMathieu Poirier 	size_t buf_size = buffer_size;
723e45c48a9SMathieu Poirier 
724e45c48a9SMathieu Poirier 	/*
725e45c48a9SMathieu Poirier 	 * We want to look the very last 512 byte (chosen arbitrarily) in
726e45c48a9SMathieu Poirier 	 * the ring buffer.
727e45c48a9SMathieu Poirier 	 */
728e45c48a9SMathieu Poirier 	watermark = buf_size - 512;
729e45c48a9SMathieu Poirier 
730e45c48a9SMathieu Poirier 	/*
731e45c48a9SMathieu Poirier 	 * @head is continuously increasing - if its value is equal or greater
732e45c48a9SMathieu Poirier 	 * than the size of the ring buffer, it has wrapped around.
733e45c48a9SMathieu Poirier 	 */
734e45c48a9SMathieu Poirier 	if (head >= buffer_size)
735e45c48a9SMathieu Poirier 		return true;
736e45c48a9SMathieu Poirier 
737e45c48a9SMathieu Poirier 	/*
738e45c48a9SMathieu Poirier 	 * The value of @head is somewhere within the size of the ring buffer.
739e45c48a9SMathieu Poirier 	 * This can be that there hasn't been enough data to fill the ring
740e45c48a9SMathieu Poirier 	 * buffer yet or the trace time was so long that @head has numerically
741e45c48a9SMathieu Poirier 	 * wrapped around.  To find we need to check if we have data at the very
742e45c48a9SMathieu Poirier 	 * end of the ring buffer.  We can reliably do this because mmap'ed
743e45c48a9SMathieu Poirier 	 * pages are zeroed out and there is a fresh mapping with every new
744e45c48a9SMathieu Poirier 	 * session.
745e45c48a9SMathieu Poirier 	 */
746e45c48a9SMathieu Poirier 
747e45c48a9SMathieu Poirier 	/* @head is less than 512 byte from the end of the ring buffer */
748e45c48a9SMathieu Poirier 	if (head > watermark)
749e45c48a9SMathieu Poirier 		watermark = head;
750e45c48a9SMathieu Poirier 
751e45c48a9SMathieu Poirier 	/*
752e45c48a9SMathieu Poirier 	 * Speed things up by using 64 bit transactions (see "u64 *buf" above)
753e45c48a9SMathieu Poirier 	 */
754e45c48a9SMathieu Poirier 	watermark >>= 3;
755e45c48a9SMathieu Poirier 	buf_size >>= 3;
756e45c48a9SMathieu Poirier 
757e45c48a9SMathieu Poirier 	/*
758e45c48a9SMathieu Poirier 	 * If we find trace data at the end of the ring buffer, @head has
759e45c48a9SMathieu Poirier 	 * been there and has numerically wrapped around at least once.
760e45c48a9SMathieu Poirier 	 */
761e45c48a9SMathieu Poirier 	for (i = watermark; i < buf_size; i++)
762e45c48a9SMathieu Poirier 		if (buf[i])
763e45c48a9SMathieu Poirier 			return true;
764e45c48a9SMathieu Poirier 
765e45c48a9SMathieu Poirier 	return false;
766e45c48a9SMathieu Poirier }
767e45c48a9SMathieu Poirier 
768e45c48a9SMathieu Poirier static int cs_etm_find_snapshot(struct auxtrace_record *itr,
769a818c563SMathieu Poirier 				int idx, struct auxtrace_mmap *mm,
770e45c48a9SMathieu Poirier 				unsigned char *data,
771a818c563SMathieu Poirier 				u64 *head, u64 *old)
772a818c563SMathieu Poirier {
773e45c48a9SMathieu Poirier 	int err;
774e45c48a9SMathieu Poirier 	bool wrapped;
775e45c48a9SMathieu Poirier 	struct cs_etm_recording *ptr =
776e45c48a9SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
777e45c48a9SMathieu Poirier 
778e45c48a9SMathieu Poirier 	/*
779e45c48a9SMathieu Poirier 	 * Allocate memory to keep track of wrapping if this is the first
780e45c48a9SMathieu Poirier 	 * time we deal with this *mm.
781e45c48a9SMathieu Poirier 	 */
782e45c48a9SMathieu Poirier 	if (idx >= ptr->wrapped_cnt) {
783e45c48a9SMathieu Poirier 		err = cs_etm_alloc_wrapped_array(ptr, idx);
784e45c48a9SMathieu Poirier 		if (err)
785e45c48a9SMathieu Poirier 			return err;
786e45c48a9SMathieu Poirier 	}
787e45c48a9SMathieu Poirier 
788e45c48a9SMathieu Poirier 	/*
789e45c48a9SMathieu Poirier 	 * Check to see if *head has wrapped around.  If it hasn't only the
790e45c48a9SMathieu Poirier 	 * amount of data between *head and *old is snapshot'ed to avoid
791e45c48a9SMathieu Poirier 	 * bloating the perf.data file with zeros.  But as soon as *head has
792e45c48a9SMathieu Poirier 	 * wrapped around the entire size of the AUX ring buffer it taken.
793e45c48a9SMathieu Poirier 	 */
794e45c48a9SMathieu Poirier 	wrapped = ptr->wrapped[idx];
795e45c48a9SMathieu Poirier 	if (!wrapped && cs_etm_buffer_has_wrapped(data, mm->len, *head)) {
796e45c48a9SMathieu Poirier 		wrapped = true;
797e45c48a9SMathieu Poirier 		ptr->wrapped[idx] = true;
798e45c48a9SMathieu Poirier 	}
799e45c48a9SMathieu Poirier 
800a818c563SMathieu Poirier 	pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n",
801a818c563SMathieu Poirier 		  __func__, idx, (size_t)*old, (size_t)*head, mm->len);
802a818c563SMathieu Poirier 
803e45c48a9SMathieu Poirier 	/* No wrap has occurred, we can just use *head and *old. */
804e45c48a9SMathieu Poirier 	if (!wrapped)
805e45c48a9SMathieu Poirier 		return 0;
806e45c48a9SMathieu Poirier 
807e45c48a9SMathieu Poirier 	/*
808e45c48a9SMathieu Poirier 	 * *head has wrapped around - adjust *head and *old to pickup the
809e45c48a9SMathieu Poirier 	 * entire content of the AUX buffer.
810e45c48a9SMathieu Poirier 	 */
811e45c48a9SMathieu Poirier 	if (*head >= mm->len) {
812e45c48a9SMathieu Poirier 		*old = *head - mm->len;
813e45c48a9SMathieu Poirier 	} else {
814a818c563SMathieu Poirier 		*head += mm->len;
815e45c48a9SMathieu Poirier 		*old = *head - mm->len;
816e45c48a9SMathieu Poirier 	}
817a818c563SMathieu Poirier 
818a818c563SMathieu Poirier 	return 0;
819a818c563SMathieu Poirier }
820a818c563SMathieu Poirier 
821a818c563SMathieu Poirier static int cs_etm_snapshot_start(struct auxtrace_record *itr)
822a818c563SMathieu Poirier {
823a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
824a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
82532dcd021SJiri Olsa 	struct evsel *evsel;
826a818c563SMathieu Poirier 
827a818c563SMathieu Poirier 	evlist__for_each_entry(ptr->evlist, evsel) {
8281fc632ceSJiri Olsa 		if (evsel->core.attr.type == ptr->cs_etm_pmu->type)
8299a10bb22SJiri Olsa 			return evsel__disable(evsel);
830a818c563SMathieu Poirier 	}
831a818c563SMathieu Poirier 	return -EINVAL;
832a818c563SMathieu Poirier }
833a818c563SMathieu Poirier 
834a818c563SMathieu Poirier static int cs_etm_snapshot_finish(struct auxtrace_record *itr)
835a818c563SMathieu Poirier {
836a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
837a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
83832dcd021SJiri Olsa 	struct evsel *evsel;
839a818c563SMathieu Poirier 
840a818c563SMathieu Poirier 	evlist__for_each_entry(ptr->evlist, evsel) {
8411fc632ceSJiri Olsa 		if (evsel->core.attr.type == ptr->cs_etm_pmu->type)
842ec7f24efSJiri Olsa 			return evsel__enable(evsel);
843a818c563SMathieu Poirier 	}
844a818c563SMathieu Poirier 	return -EINVAL;
845a818c563SMathieu Poirier }
846a818c563SMathieu Poirier 
847a818c563SMathieu Poirier static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused)
848a818c563SMathieu Poirier {
849a818c563SMathieu Poirier 	return (((u64) rand() <<  0) & 0x00000000FFFFFFFFull) |
850a818c563SMathieu Poirier 		(((u64) rand() << 32) & 0xFFFFFFFF00000000ull);
851a818c563SMathieu Poirier }
852a818c563SMathieu Poirier 
853a818c563SMathieu Poirier static void cs_etm_recording_free(struct auxtrace_record *itr)
854a818c563SMathieu Poirier {
855a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
856a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
857e45c48a9SMathieu Poirier 
858e45c48a9SMathieu Poirier 	zfree(&ptr->wrapped);
859a818c563SMathieu Poirier 	free(ptr);
860a818c563SMathieu Poirier }
861a818c563SMathieu Poirier 
862a818c563SMathieu Poirier struct auxtrace_record *cs_etm_record_init(int *err)
863a818c563SMathieu Poirier {
864a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu;
865a818c563SMathieu Poirier 	struct cs_etm_recording *ptr;
866a818c563SMathieu Poirier 
867a818c563SMathieu Poirier 	cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
868a818c563SMathieu Poirier 
869a818c563SMathieu Poirier 	if (!cs_etm_pmu) {
870a818c563SMathieu Poirier 		*err = -EINVAL;
871a818c563SMathieu Poirier 		goto out;
872a818c563SMathieu Poirier 	}
873a818c563SMathieu Poirier 
874a818c563SMathieu Poirier 	ptr = zalloc(sizeof(struct cs_etm_recording));
875a818c563SMathieu Poirier 	if (!ptr) {
876a818c563SMathieu Poirier 		*err = -ENOMEM;
877a818c563SMathieu Poirier 		goto out;
878a818c563SMathieu Poirier 	}
879a818c563SMathieu Poirier 
880a818c563SMathieu Poirier 	ptr->cs_etm_pmu			= cs_etm_pmu;
881ad60ba0cSAdrian Hunter 	ptr->itr.pmu			= cs_etm_pmu;
882a818c563SMathieu Poirier 	ptr->itr.parse_snapshot_options	= cs_etm_parse_snapshot_options;
883a818c563SMathieu Poirier 	ptr->itr.recording_options	= cs_etm_recording_options;
884a818c563SMathieu Poirier 	ptr->itr.info_priv_size		= cs_etm_info_priv_size;
885a818c563SMathieu Poirier 	ptr->itr.info_fill		= cs_etm_info_fill;
886a818c563SMathieu Poirier 	ptr->itr.find_snapshot		= cs_etm_find_snapshot;
887a818c563SMathieu Poirier 	ptr->itr.snapshot_start		= cs_etm_snapshot_start;
888a818c563SMathieu Poirier 	ptr->itr.snapshot_finish	= cs_etm_snapshot_finish;
889a818c563SMathieu Poirier 	ptr->itr.reference		= cs_etm_reference;
890a818c563SMathieu Poirier 	ptr->itr.free			= cs_etm_recording_free;
891ad60ba0cSAdrian Hunter 	ptr->itr.read_finish		= auxtrace_record__read_finish;
892a818c563SMathieu Poirier 
893a818c563SMathieu Poirier 	*err = 0;
894a818c563SMathieu Poirier 	return &ptr->itr;
895a818c563SMathieu Poirier out:
896a818c563SMathieu Poirier 	return NULL;
897a818c563SMathieu Poirier }
898