xref: /linux/tools/perf/arch/arm/util/cs-etm.c (revision 42b2b570b34afb5fb9dc16ac77cb332194136a85)
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;
21935ac0cadSArnaldo Carvalho de Melo 	struct 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) {
22735ac0cadSArnaldo Carvalho de Melo 		if (term->type != 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 	/*
24647446212SMike Leach 	 * No sink was provided on the command line - allow the CoreSight
24747446212SMike Leach 	 * system to look for a default
248fa4e819bSMathieu Poirier 	 */
24947446212SMike Leach 	return 0;
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 
26816b4b4e1SAdrian Hunter 	if (!record_opts__no_switch_events(opts) &&
26916b4b4e1SAdrian Hunter 	    perf_can_record_switch_events())
270e5993c42SMathieu Poirier 		opts->record_switch_events = true;
271e5993c42SMathieu Poirier 
272a818c563SMathieu Poirier 	evlist__for_each_entry(evlist, evsel) {
2731fc632ceSJiri Olsa 		if (evsel->core.attr.type == cs_etm_pmu->type) {
274a818c563SMathieu Poirier 			if (cs_etm_evsel) {
275a818c563SMathieu Poirier 				pr_err("There may be only one %s event\n",
276a818c563SMathieu Poirier 				       CORESIGHT_ETM_PMU_NAME);
277a818c563SMathieu Poirier 				return -EINVAL;
278a818c563SMathieu Poirier 			}
2791fc632ceSJiri Olsa 			evsel->core.attr.freq = 0;
2801fc632ceSJiri Olsa 			evsel->core.attr.sample_period = 1;
281a818c563SMathieu Poirier 			cs_etm_evsel = evsel;
282a818c563SMathieu Poirier 			opts->full_auxtrace = true;
283a818c563SMathieu Poirier 		}
284a818c563SMathieu Poirier 	}
285a818c563SMathieu Poirier 
286a818c563SMathieu Poirier 	/* no need to continue if at least one event of interest was found */
287a818c563SMathieu Poirier 	if (!cs_etm_evsel)
288a818c563SMathieu Poirier 		return 0;
289a818c563SMathieu Poirier 
290fa4e819bSMathieu Poirier 	ret = cs_etm_set_sink_attr(cs_etm_pmu, cs_etm_evsel);
291fa4e819bSMathieu Poirier 	if (ret)
292fa4e819bSMathieu Poirier 		return ret;
293fa4e819bSMathieu Poirier 
294a818c563SMathieu Poirier 	if (opts->use_clockid) {
295a818c563SMathieu Poirier 		pr_err("Cannot use clockid (-k option) with %s\n",
296a818c563SMathieu Poirier 		       CORESIGHT_ETM_PMU_NAME);
297a818c563SMathieu Poirier 		return -EINVAL;
298a818c563SMathieu Poirier 	}
299a818c563SMathieu Poirier 
300a818c563SMathieu Poirier 	/* we are in snapshot mode */
301a818c563SMathieu Poirier 	if (opts->auxtrace_snapshot_mode) {
302a818c563SMathieu Poirier 		/*
303a818c563SMathieu Poirier 		 * No size were given to '-S' or '-m,', so go with
304a818c563SMathieu Poirier 		 * the default
305a818c563SMathieu Poirier 		 */
306a818c563SMathieu Poirier 		if (!opts->auxtrace_snapshot_size &&
307a818c563SMathieu Poirier 		    !opts->auxtrace_mmap_pages) {
308a818c563SMathieu Poirier 			if (privileged) {
309a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages = MiB(4) / page_size;
310a818c563SMathieu Poirier 			} else {
311a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages =
312a818c563SMathieu Poirier 							KiB(128) / page_size;
313a818c563SMathieu Poirier 				if (opts->mmap_pages == UINT_MAX)
314a818c563SMathieu Poirier 					opts->mmap_pages = KiB(256) / page_size;
315a818c563SMathieu Poirier 			}
316a818c563SMathieu Poirier 		} else if (!opts->auxtrace_mmap_pages && !privileged &&
317a818c563SMathieu Poirier 						opts->mmap_pages == UINT_MAX) {
318a818c563SMathieu Poirier 			opts->mmap_pages = KiB(256) / page_size;
319a818c563SMathieu Poirier 		}
320a818c563SMathieu Poirier 
321a818c563SMathieu Poirier 		/*
322a818c563SMathieu Poirier 		 * '-m,xyz' was specified but no snapshot size, so make the
323a818c563SMathieu Poirier 		 * snapshot size as big as the auxtrace mmap area.
324a818c563SMathieu Poirier 		 */
325a818c563SMathieu Poirier 		if (!opts->auxtrace_snapshot_size) {
326a818c563SMathieu Poirier 			opts->auxtrace_snapshot_size =
327a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages * (size_t)page_size;
328a818c563SMathieu Poirier 		}
329a818c563SMathieu Poirier 
330a818c563SMathieu Poirier 		/*
331a818c563SMathieu Poirier 		 * -Sxyz was specified but no auxtrace mmap area, so make the
332a818c563SMathieu Poirier 		 * auxtrace mmap area big enough to fit the requested snapshot
333a818c563SMathieu Poirier 		 * size.
334a818c563SMathieu Poirier 		 */
335a818c563SMathieu Poirier 		if (!opts->auxtrace_mmap_pages) {
336a818c563SMathieu Poirier 			size_t sz = opts->auxtrace_snapshot_size;
337a818c563SMathieu Poirier 
338a818c563SMathieu Poirier 			sz = round_up(sz, page_size) / page_size;
339a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = roundup_pow_of_two(sz);
340a818c563SMathieu Poirier 		}
341a818c563SMathieu Poirier 
342a818c563SMathieu Poirier 		/* Snapshost size can't be bigger than the auxtrace area */
343a818c563SMathieu Poirier 		if (opts->auxtrace_snapshot_size >
344a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages * (size_t)page_size) {
345a818c563SMathieu Poirier 			pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n",
346a818c563SMathieu Poirier 			       opts->auxtrace_snapshot_size,
347a818c563SMathieu Poirier 			       opts->auxtrace_mmap_pages * (size_t)page_size);
348a818c563SMathieu Poirier 			return -EINVAL;
349a818c563SMathieu Poirier 		}
350a818c563SMathieu Poirier 
351a818c563SMathieu Poirier 		/* Something went wrong somewhere - this shouldn't happen */
352a818c563SMathieu Poirier 		if (!opts->auxtrace_snapshot_size ||
353a818c563SMathieu Poirier 		    !opts->auxtrace_mmap_pages) {
354a818c563SMathieu Poirier 			pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n");
355a818c563SMathieu Poirier 			return -EINVAL;
356a818c563SMathieu Poirier 		}
357a818c563SMathieu Poirier 	}
358a818c563SMathieu Poirier 
359a818c563SMathieu Poirier 	/* We are in full trace mode but '-m,xyz' wasn't specified */
360a818c563SMathieu Poirier 	if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) {
361a818c563SMathieu Poirier 		if (privileged) {
362a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = MiB(4) / page_size;
363a818c563SMathieu Poirier 		} else {
364a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = KiB(128) / page_size;
365a818c563SMathieu Poirier 			if (opts->mmap_pages == UINT_MAX)
366a818c563SMathieu Poirier 				opts->mmap_pages = KiB(256) / page_size;
367a818c563SMathieu Poirier 		}
368a818c563SMathieu Poirier 
369a818c563SMathieu Poirier 	}
370a818c563SMathieu Poirier 
371a818c563SMathieu Poirier 	/* Validate auxtrace_mmap_pages provided by user */
372a818c563SMathieu Poirier 	if (opts->auxtrace_mmap_pages) {
373a818c563SMathieu Poirier 		unsigned int max_page = (KiB(128) / page_size);
374a818c563SMathieu Poirier 		size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size;
375a818c563SMathieu Poirier 
376a818c563SMathieu Poirier 		if (!privileged &&
377a818c563SMathieu Poirier 		    opts->auxtrace_mmap_pages > max_page) {
378a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = max_page;
379a818c563SMathieu Poirier 			pr_err("auxtrace too big, truncating to %d\n",
380a818c563SMathieu Poirier 			       max_page);
381a818c563SMathieu Poirier 		}
382a818c563SMathieu Poirier 
383a818c563SMathieu Poirier 		if (!is_power_of_2(sz)) {
384a818c563SMathieu Poirier 			pr_err("Invalid mmap size for %s: must be a power of 2\n",
385a818c563SMathieu Poirier 			       CORESIGHT_ETM_PMU_NAME);
386a818c563SMathieu Poirier 			return -EINVAL;
387a818c563SMathieu Poirier 		}
388a818c563SMathieu Poirier 	}
389a818c563SMathieu Poirier 
390a818c563SMathieu Poirier 	if (opts->auxtrace_snapshot_mode)
391a818c563SMathieu Poirier 		pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME,
392a818c563SMathieu Poirier 			  opts->auxtrace_snapshot_size);
393a818c563SMathieu Poirier 
394a818c563SMathieu Poirier 	/*
395a818c563SMathieu Poirier 	 * To obtain the auxtrace buffer file descriptor, the auxtrace
396a818c563SMathieu Poirier 	 * event must come first.
397a818c563SMathieu Poirier 	 */
398e414fd1aSArnaldo Carvalho de Melo 	evlist__to_front(evlist, cs_etm_evsel);
3990c788d47SKim Phillips 
400a818c563SMathieu Poirier 	/*
401a818c563SMathieu Poirier 	 * In the case of per-cpu mmaps, we need the CPU on the
4023399ad9aSMathieu Poirier 	 * AUX event.  We also need the contextID in order to be notified
4033399ad9aSMathieu Poirier 	 * when a context switch happened.
404a818c563SMathieu Poirier 	 */
405315c0a1fSJiri Olsa 	if (!perf_cpu_map__empty(cpus)) {
406862b2f8fSArnaldo Carvalho de Melo 		evsel__set_sample_bit(cs_etm_evsel, CPU);
407a818c563SMathieu Poirier 
408374d910fSMathieu Poirier 		err = cs_etm_set_option(itr, cs_etm_evsel,
409374d910fSMathieu Poirier 					ETM_OPT_CTXTID | ETM_OPT_TS);
4101c839a5aSMathieu Poirier 		if (err)
4111c839a5aSMathieu Poirier 			goto out;
4123399ad9aSMathieu Poirier 	}
4133399ad9aSMathieu Poirier 
414a818c563SMathieu Poirier 	/* Add dummy event to keep tracking */
415a818c563SMathieu Poirier 	if (opts->full_auxtrace) {
41632dcd021SJiri Olsa 		struct evsel *tracking_evsel;
417a818c563SMathieu Poirier 
418a818c563SMathieu Poirier 		err = parse_events(evlist, "dummy:u", NULL);
419a818c563SMathieu Poirier 		if (err)
4203399ad9aSMathieu Poirier 			goto out;
421a818c563SMathieu Poirier 
422515dbe48SJiri Olsa 		tracking_evsel = evlist__last(evlist);
423e80db255SArnaldo Carvalho de Melo 		evlist__set_tracking_event(evlist, tracking_evsel);
424a818c563SMathieu Poirier 
4251fc632ceSJiri Olsa 		tracking_evsel->core.attr.freq = 0;
4261fc632ceSJiri Olsa 		tracking_evsel->core.attr.sample_period = 1;
427a818c563SMathieu Poirier 
428a818c563SMathieu Poirier 		/* In per-cpu case, always need the time of mmap events etc */
429315c0a1fSJiri Olsa 		if (!perf_cpu_map__empty(cpus))
430862b2f8fSArnaldo Carvalho de Melo 			evsel__set_sample_bit(tracking_evsel, TIME);
431a818c563SMathieu Poirier 	}
432a818c563SMathieu Poirier 
4333399ad9aSMathieu Poirier out:
4343399ad9aSMathieu Poirier 	return err;
435a818c563SMathieu Poirier }
436a818c563SMathieu Poirier 
437a818c563SMathieu Poirier static u64 cs_etm_get_config(struct auxtrace_record *itr)
438a818c563SMathieu Poirier {
439a818c563SMathieu Poirier 	u64 config = 0;
440a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
441a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
442a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
44363503dbaSJiri Olsa 	struct evlist *evlist = ptr->evlist;
44432dcd021SJiri Olsa 	struct evsel *evsel;
445a818c563SMathieu Poirier 
446a818c563SMathieu Poirier 	evlist__for_each_entry(evlist, evsel) {
4471fc632ceSJiri Olsa 		if (evsel->core.attr.type == cs_etm_pmu->type) {
448a818c563SMathieu Poirier 			/*
449a818c563SMathieu Poirier 			 * Variable perf_event_attr::config is assigned to
450a818c563SMathieu Poirier 			 * ETMv3/PTM.  The bit fields have been made to match
451a818c563SMathieu Poirier 			 * the ETMv3.5 ETRMCR register specification.  See the
452a818c563SMathieu Poirier 			 * PMU_FORMAT_ATTR() declarations in
453a818c563SMathieu Poirier 			 * drivers/hwtracing/coresight/coresight-perf.c for
454a818c563SMathieu Poirier 			 * details.
455a818c563SMathieu Poirier 			 */
4561fc632ceSJiri Olsa 			config = evsel->core.attr.config;
457a818c563SMathieu Poirier 			break;
458a818c563SMathieu Poirier 		}
459a818c563SMathieu Poirier 	}
460a818c563SMathieu Poirier 
461a818c563SMathieu Poirier 	return config;
462a818c563SMathieu Poirier }
463a818c563SMathieu Poirier 
464df770ff0SMike Leach #ifndef BIT
465df770ff0SMike Leach #define BIT(N) (1UL << (N))
466df770ff0SMike Leach #endif
467df770ff0SMike Leach 
468df770ff0SMike Leach static u64 cs_etmv4_get_config(struct auxtrace_record *itr)
469df770ff0SMike Leach {
470df770ff0SMike Leach 	u64 config = 0;
471df770ff0SMike Leach 	u64 config_opts = 0;
472df770ff0SMike Leach 
473df770ff0SMike Leach 	/*
474df770ff0SMike Leach 	 * The perf event variable config bits represent both
475df770ff0SMike Leach 	 * the command line options and register programming
476df770ff0SMike Leach 	 * bits in ETMv3/PTM. For ETMv4 we must remap options
477df770ff0SMike Leach 	 * to real bits
478df770ff0SMike Leach 	 */
479df770ff0SMike Leach 	config_opts = cs_etm_get_config(itr);
480df770ff0SMike Leach 	if (config_opts & BIT(ETM_OPT_CYCACC))
481df770ff0SMike Leach 		config |= BIT(ETM4_CFG_BIT_CYCACC);
4823399ad9aSMathieu Poirier 	if (config_opts & BIT(ETM_OPT_CTXTID))
4833399ad9aSMathieu Poirier 		config |= BIT(ETM4_CFG_BIT_CTXTID);
484df770ff0SMike Leach 	if (config_opts & BIT(ETM_OPT_TS))
485df770ff0SMike Leach 		config |= BIT(ETM4_CFG_BIT_TS);
486df770ff0SMike Leach 	if (config_opts & BIT(ETM_OPT_RETSTK))
487df770ff0SMike Leach 		config |= BIT(ETM4_CFG_BIT_RETSTK);
488df770ff0SMike Leach 
489df770ff0SMike Leach 	return config;
490df770ff0SMike Leach }
491df770ff0SMike Leach 
492a818c563SMathieu Poirier static size_t
493a818c563SMathieu Poirier cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused,
49463503dbaSJiri Olsa 		      struct evlist *evlist __maybe_unused)
495a818c563SMathieu Poirier {
496a818c563SMathieu Poirier 	int i;
497a818c563SMathieu Poirier 	int etmv3 = 0, etmv4 = 0;
498f72f901dSJiri Olsa 	struct perf_cpu_map *event_cpus = evlist->core.cpus;
4999c3516d1SJiri Olsa 	struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL);
500a818c563SMathieu Poirier 
501a818c563SMathieu Poirier 	/* cpu map is not empty, we have specific CPUs to work with */
502315c0a1fSJiri Olsa 	if (!perf_cpu_map__empty(event_cpus)) {
503796bfaddSMathieu Poirier 		for (i = 0; i < cpu__max_cpu(); i++) {
504796bfaddSMathieu Poirier 			if (!cpu_map__has(event_cpus, i) ||
505796bfaddSMathieu Poirier 			    !cpu_map__has(online_cpus, i))
506796bfaddSMathieu Poirier 				continue;
507796bfaddSMathieu Poirier 
508796bfaddSMathieu Poirier 			if (cs_etm_is_etmv4(itr, i))
509a818c563SMathieu Poirier 				etmv4++;
510a818c563SMathieu Poirier 			else
511a818c563SMathieu Poirier 				etmv3++;
512a818c563SMathieu Poirier 		}
513a818c563SMathieu Poirier 	} else {
514a818c563SMathieu Poirier 		/* get configuration for all CPUs in the system */
515a818c563SMathieu Poirier 		for (i = 0; i < cpu__max_cpu(); i++) {
516796bfaddSMathieu Poirier 			if (!cpu_map__has(online_cpus, i))
517796bfaddSMathieu Poirier 				continue;
518796bfaddSMathieu Poirier 
519a818c563SMathieu Poirier 			if (cs_etm_is_etmv4(itr, i))
520a818c563SMathieu Poirier 				etmv4++;
521a818c563SMathieu Poirier 			else
522a818c563SMathieu Poirier 				etmv3++;
523a818c563SMathieu Poirier 		}
524a818c563SMathieu Poirier 	}
525a818c563SMathieu Poirier 
52638f01d8dSJiri Olsa 	perf_cpu_map__put(online_cpus);
527796bfaddSMathieu Poirier 
528a818c563SMathieu Poirier 	return (CS_ETM_HEADER_SIZE +
529a818c563SMathieu Poirier 	       (etmv4 * CS_ETMV4_PRIV_SIZE) +
530a818c563SMathieu Poirier 	       (etmv3 * CS_ETMV3_PRIV_SIZE));
531a818c563SMathieu Poirier }
532a818c563SMathieu Poirier 
533a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu)
534a818c563SMathieu Poirier {
535a818c563SMathieu Poirier 	bool ret = false;
536a818c563SMathieu Poirier 	char path[PATH_MAX];
537a818c563SMathieu Poirier 	int scan;
538a818c563SMathieu Poirier 	unsigned int val;
539a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
540a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
541a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
542a818c563SMathieu Poirier 
543a818c563SMathieu Poirier 	/* Take any of the RO files for ETMv4 and see if it present */
544a818c563SMathieu Poirier 	snprintf(path, PATH_MAX, "cpu%d/%s",
545a818c563SMathieu Poirier 		 cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]);
546a818c563SMathieu Poirier 	scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val);
547a818c563SMathieu Poirier 
548a818c563SMathieu Poirier 	/* The file was read successfully, we have a winner */
549a818c563SMathieu Poirier 	if (scan == 1)
550a818c563SMathieu Poirier 		ret = true;
551a818c563SMathieu Poirier 
552a818c563SMathieu Poirier 	return ret;
553a818c563SMathieu Poirier }
554a818c563SMathieu Poirier 
555a818c563SMathieu Poirier static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path)
556a818c563SMathieu Poirier {
557a818c563SMathieu Poirier 	char pmu_path[PATH_MAX];
558a818c563SMathieu Poirier 	int scan;
559a818c563SMathieu Poirier 	unsigned int val = 0;
560a818c563SMathieu Poirier 
561a818c563SMathieu Poirier 	/* Get RO metadata from sysfs */
562a818c563SMathieu Poirier 	snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path);
563a818c563SMathieu Poirier 
564a818c563SMathieu Poirier 	scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val);
565a818c563SMathieu Poirier 	if (scan != 1)
566a818c563SMathieu Poirier 		pr_err("%s: error reading: %s\n", __func__, pmu_path);
567a818c563SMathieu Poirier 
568a818c563SMathieu Poirier 	return val;
569a818c563SMathieu Poirier }
570a818c563SMathieu Poirier 
571a818c563SMathieu Poirier static void cs_etm_get_metadata(int cpu, u32 *offset,
572a818c563SMathieu Poirier 				struct auxtrace_record *itr,
57372932371SJiri Olsa 				struct perf_record_auxtrace_info *info)
574a818c563SMathieu Poirier {
575*42b2b570SMike Leach 	u32 increment, nr_trc_params;
576a818c563SMathieu Poirier 	u64 magic;
577a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
578a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
579a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
580a818c563SMathieu Poirier 
581a818c563SMathieu Poirier 	/* first see what kind of tracer this cpu is affined to */
582a818c563SMathieu Poirier 	if (cs_etm_is_etmv4(itr, cpu)) {
583a818c563SMathieu Poirier 		magic = __perf_cs_etmv4_magic;
584a818c563SMathieu Poirier 		/* Get trace configuration register */
585a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCCONFIGR] =
586df770ff0SMike Leach 						cs_etmv4_get_config(itr);
587a818c563SMathieu Poirier 		/* Get traceID from the framework */
588a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCTRACEIDR] =
589a818c563SMathieu Poirier 						coresight_get_trace_id(cpu);
590a818c563SMathieu Poirier 		/* Get read-only information from sysFS */
591a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR0] =
592a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
593a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR0]);
594a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR1] =
595a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
596a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR1]);
597a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR2] =
598a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
599a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR2]);
600a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR8] =
601a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
602a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR8]);
603a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCAUTHSTATUS] =
604a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
605a818c563SMathieu Poirier 				      metadata_etmv4_ro
606a818c563SMathieu Poirier 				      [CS_ETMV4_TRCAUTHSTATUS]);
607a818c563SMathieu Poirier 
608a818c563SMathieu Poirier 		/* How much space was used */
609a818c563SMathieu Poirier 		increment = CS_ETMV4_PRIV_MAX;
610*42b2b570SMike Leach 		nr_trc_params = CS_ETMV4_PRIV_MAX - CS_ETMV4_TRCCONFIGR;
611a818c563SMathieu Poirier 	} else {
612a818c563SMathieu Poirier 		magic = __perf_cs_etmv3_magic;
613a818c563SMathieu Poirier 		/* Get configuration register */
614a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
615a818c563SMathieu Poirier 		/* Get traceID from the framework */
616a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMTRACEIDR] =
617a818c563SMathieu Poirier 						coresight_get_trace_id(cpu);
618a818c563SMathieu Poirier 		/* Get read-only information from sysFS */
619a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMCCER] =
620a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
621a818c563SMathieu Poirier 				      metadata_etmv3_ro[CS_ETM_ETMCCER]);
622a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMIDR] =
623a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
624a818c563SMathieu Poirier 				      metadata_etmv3_ro[CS_ETM_ETMIDR]);
625a818c563SMathieu Poirier 
626a818c563SMathieu Poirier 		/* How much space was used */
627a818c563SMathieu Poirier 		increment = CS_ETM_PRIV_MAX;
628*42b2b570SMike Leach 		nr_trc_params = CS_ETM_PRIV_MAX - CS_ETM_ETMCR;
629a818c563SMathieu Poirier 	}
630a818c563SMathieu Poirier 
631a818c563SMathieu Poirier 	/* Build generic header portion */
632a818c563SMathieu Poirier 	info->priv[*offset + CS_ETM_MAGIC] = magic;
633a818c563SMathieu Poirier 	info->priv[*offset + CS_ETM_CPU] = cpu;
634*42b2b570SMike Leach 	info->priv[*offset + CS_ETM_NR_TRC_PARAMS] = nr_trc_params;
635a818c563SMathieu Poirier 	/* Where the next CPU entry should start from */
636a818c563SMathieu Poirier 	*offset += increment;
637a818c563SMathieu Poirier }
638a818c563SMathieu Poirier 
639a818c563SMathieu Poirier static int cs_etm_info_fill(struct auxtrace_record *itr,
640a818c563SMathieu Poirier 			    struct perf_session *session,
64172932371SJiri Olsa 			    struct perf_record_auxtrace_info *info,
642a818c563SMathieu Poirier 			    size_t priv_size)
643a818c563SMathieu Poirier {
644a818c563SMathieu Poirier 	int i;
645a818c563SMathieu Poirier 	u32 offset;
646a818c563SMathieu Poirier 	u64 nr_cpu, type;
647f854839bSJiri Olsa 	struct perf_cpu_map *cpu_map;
648f72f901dSJiri Olsa 	struct perf_cpu_map *event_cpus = session->evlist->core.cpus;
6499c3516d1SJiri Olsa 	struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL);
650a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
651a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
652a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
653a818c563SMathieu Poirier 
654a818c563SMathieu Poirier 	if (priv_size != cs_etm_info_priv_size(itr, session->evlist))
655a818c563SMathieu Poirier 		return -EINVAL;
656a818c563SMathieu Poirier 
657c976ee11SJiri Olsa 	if (!session->evlist->core.nr_mmaps)
658a818c563SMathieu Poirier 		return -EINVAL;
659a818c563SMathieu Poirier 
660796bfaddSMathieu Poirier 	/* If the cpu_map is empty all online CPUs are involved */
661315c0a1fSJiri Olsa 	if (perf_cpu_map__empty(event_cpus)) {
662796bfaddSMathieu Poirier 		cpu_map = online_cpus;
663796bfaddSMathieu Poirier 	} else {
664796bfaddSMathieu Poirier 		/* Make sure all specified CPUs are online */
6656549cd8fSJiri Olsa 		for (i = 0; i < perf_cpu_map__nr(event_cpus); i++) {
666796bfaddSMathieu Poirier 			if (cpu_map__has(event_cpus, i) &&
667796bfaddSMathieu Poirier 			    !cpu_map__has(online_cpus, i))
668796bfaddSMathieu Poirier 				return -EINVAL;
669796bfaddSMathieu Poirier 		}
670796bfaddSMathieu Poirier 
671796bfaddSMathieu Poirier 		cpu_map = event_cpus;
672796bfaddSMathieu Poirier 	}
673796bfaddSMathieu Poirier 
6746549cd8fSJiri Olsa 	nr_cpu = perf_cpu_map__nr(cpu_map);
675a818c563SMathieu Poirier 	/* Get PMU type as dynamically assigned by the core */
676a818c563SMathieu Poirier 	type = cs_etm_pmu->type;
677a818c563SMathieu Poirier 
678a818c563SMathieu Poirier 	/* First fill out the session header */
679a818c563SMathieu Poirier 	info->type = PERF_AUXTRACE_CS_ETM;
680*42b2b570SMike Leach 	info->priv[CS_HEADER_VERSION] = CS_HEADER_CURRENT_VERSION;
681a818c563SMathieu Poirier 	info->priv[CS_PMU_TYPE_CPUS] = type << 32;
682a818c563SMathieu Poirier 	info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu;
683a818c563SMathieu Poirier 	info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode;
684a818c563SMathieu Poirier 
685a818c563SMathieu Poirier 	offset = CS_ETM_SNAPSHOT + 1;
686a818c563SMathieu Poirier 
687796bfaddSMathieu Poirier 	for (i = 0; i < cpu__max_cpu() && offset < priv_size; i++)
688796bfaddSMathieu Poirier 		if (cpu_map__has(cpu_map, i))
689a818c563SMathieu Poirier 			cs_etm_get_metadata(i, &offset, itr, info);
690796bfaddSMathieu Poirier 
69138f01d8dSJiri Olsa 	perf_cpu_map__put(online_cpus);
692a818c563SMathieu Poirier 
693a818c563SMathieu Poirier 	return 0;
694a818c563SMathieu Poirier }
695a818c563SMathieu Poirier 
696e45c48a9SMathieu Poirier static int cs_etm_alloc_wrapped_array(struct cs_etm_recording *ptr, int idx)
697e45c48a9SMathieu Poirier {
698e45c48a9SMathieu Poirier 	bool *wrapped;
699e45c48a9SMathieu Poirier 	int cnt = ptr->wrapped_cnt;
700e45c48a9SMathieu Poirier 
701e45c48a9SMathieu Poirier 	/* Make @ptr->wrapped as big as @idx */
702e45c48a9SMathieu Poirier 	while (cnt <= idx)
703e45c48a9SMathieu Poirier 		cnt++;
704e45c48a9SMathieu Poirier 
705e45c48a9SMathieu Poirier 	/*
706e45c48a9SMathieu Poirier 	 * Free'ed in cs_etm_recording_free().  Using realloc() to avoid
707e45c48a9SMathieu Poirier 	 * cross compilation problems where the host's system supports
708e45c48a9SMathieu Poirier 	 * reallocarray() but not the target.
709e45c48a9SMathieu Poirier 	 */
710e45c48a9SMathieu Poirier 	wrapped = realloc(ptr->wrapped, cnt * sizeof(bool));
711e45c48a9SMathieu Poirier 	if (!wrapped)
712e45c48a9SMathieu Poirier 		return -ENOMEM;
713e45c48a9SMathieu Poirier 
714e45c48a9SMathieu Poirier 	wrapped[cnt - 1] = false;
715e45c48a9SMathieu Poirier 	ptr->wrapped_cnt = cnt;
716e45c48a9SMathieu Poirier 	ptr->wrapped = wrapped;
717e45c48a9SMathieu Poirier 
718e45c48a9SMathieu Poirier 	return 0;
719e45c48a9SMathieu Poirier }
720e45c48a9SMathieu Poirier 
721e45c48a9SMathieu Poirier static bool cs_etm_buffer_has_wrapped(unsigned char *buffer,
722e45c48a9SMathieu Poirier 				      size_t buffer_size, u64 head)
723e45c48a9SMathieu Poirier {
724e45c48a9SMathieu Poirier 	u64 i, watermark;
725e45c48a9SMathieu Poirier 	u64 *buf = (u64 *)buffer;
726e45c48a9SMathieu Poirier 	size_t buf_size = buffer_size;
727e45c48a9SMathieu Poirier 
728e45c48a9SMathieu Poirier 	/*
729e45c48a9SMathieu Poirier 	 * We want to look the very last 512 byte (chosen arbitrarily) in
730e45c48a9SMathieu Poirier 	 * the ring buffer.
731e45c48a9SMathieu Poirier 	 */
732e45c48a9SMathieu Poirier 	watermark = buf_size - 512;
733e45c48a9SMathieu Poirier 
734e45c48a9SMathieu Poirier 	/*
735e45c48a9SMathieu Poirier 	 * @head is continuously increasing - if its value is equal or greater
736e45c48a9SMathieu Poirier 	 * than the size of the ring buffer, it has wrapped around.
737e45c48a9SMathieu Poirier 	 */
738e45c48a9SMathieu Poirier 	if (head >= buffer_size)
739e45c48a9SMathieu Poirier 		return true;
740e45c48a9SMathieu Poirier 
741e45c48a9SMathieu Poirier 	/*
742e45c48a9SMathieu Poirier 	 * The value of @head is somewhere within the size of the ring buffer.
743e45c48a9SMathieu Poirier 	 * This can be that there hasn't been enough data to fill the ring
744e45c48a9SMathieu Poirier 	 * buffer yet or the trace time was so long that @head has numerically
745e45c48a9SMathieu Poirier 	 * wrapped around.  To find we need to check if we have data at the very
746e45c48a9SMathieu Poirier 	 * end of the ring buffer.  We can reliably do this because mmap'ed
747e45c48a9SMathieu Poirier 	 * pages are zeroed out and there is a fresh mapping with every new
748e45c48a9SMathieu Poirier 	 * session.
749e45c48a9SMathieu Poirier 	 */
750e45c48a9SMathieu Poirier 
751e45c48a9SMathieu Poirier 	/* @head is less than 512 byte from the end of the ring buffer */
752e45c48a9SMathieu Poirier 	if (head > watermark)
753e45c48a9SMathieu Poirier 		watermark = head;
754e45c48a9SMathieu Poirier 
755e45c48a9SMathieu Poirier 	/*
756e45c48a9SMathieu Poirier 	 * Speed things up by using 64 bit transactions (see "u64 *buf" above)
757e45c48a9SMathieu Poirier 	 */
758e45c48a9SMathieu Poirier 	watermark >>= 3;
759e45c48a9SMathieu Poirier 	buf_size >>= 3;
760e45c48a9SMathieu Poirier 
761e45c48a9SMathieu Poirier 	/*
762e45c48a9SMathieu Poirier 	 * If we find trace data at the end of the ring buffer, @head has
763e45c48a9SMathieu Poirier 	 * been there and has numerically wrapped around at least once.
764e45c48a9SMathieu Poirier 	 */
765e45c48a9SMathieu Poirier 	for (i = watermark; i < buf_size; i++)
766e45c48a9SMathieu Poirier 		if (buf[i])
767e45c48a9SMathieu Poirier 			return true;
768e45c48a9SMathieu Poirier 
769e45c48a9SMathieu Poirier 	return false;
770e45c48a9SMathieu Poirier }
771e45c48a9SMathieu Poirier 
772e45c48a9SMathieu Poirier static int cs_etm_find_snapshot(struct auxtrace_record *itr,
773a818c563SMathieu Poirier 				int idx, struct auxtrace_mmap *mm,
774e45c48a9SMathieu Poirier 				unsigned char *data,
775a818c563SMathieu Poirier 				u64 *head, u64 *old)
776a818c563SMathieu Poirier {
777e45c48a9SMathieu Poirier 	int err;
778e45c48a9SMathieu Poirier 	bool wrapped;
779e45c48a9SMathieu Poirier 	struct cs_etm_recording *ptr =
780e45c48a9SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
781e45c48a9SMathieu Poirier 
782e45c48a9SMathieu Poirier 	/*
783e45c48a9SMathieu Poirier 	 * Allocate memory to keep track of wrapping if this is the first
784e45c48a9SMathieu Poirier 	 * time we deal with this *mm.
785e45c48a9SMathieu Poirier 	 */
786e45c48a9SMathieu Poirier 	if (idx >= ptr->wrapped_cnt) {
787e45c48a9SMathieu Poirier 		err = cs_etm_alloc_wrapped_array(ptr, idx);
788e45c48a9SMathieu Poirier 		if (err)
789e45c48a9SMathieu Poirier 			return err;
790e45c48a9SMathieu Poirier 	}
791e45c48a9SMathieu Poirier 
792e45c48a9SMathieu Poirier 	/*
793e45c48a9SMathieu Poirier 	 * Check to see if *head has wrapped around.  If it hasn't only the
794e45c48a9SMathieu Poirier 	 * amount of data between *head and *old is snapshot'ed to avoid
795e45c48a9SMathieu Poirier 	 * bloating the perf.data file with zeros.  But as soon as *head has
796e45c48a9SMathieu Poirier 	 * wrapped around the entire size of the AUX ring buffer it taken.
797e45c48a9SMathieu Poirier 	 */
798e45c48a9SMathieu Poirier 	wrapped = ptr->wrapped[idx];
799e45c48a9SMathieu Poirier 	if (!wrapped && cs_etm_buffer_has_wrapped(data, mm->len, *head)) {
800e45c48a9SMathieu Poirier 		wrapped = true;
801e45c48a9SMathieu Poirier 		ptr->wrapped[idx] = true;
802e45c48a9SMathieu Poirier 	}
803e45c48a9SMathieu Poirier 
804a818c563SMathieu Poirier 	pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n",
805a818c563SMathieu Poirier 		  __func__, idx, (size_t)*old, (size_t)*head, mm->len);
806a818c563SMathieu Poirier 
807e45c48a9SMathieu Poirier 	/* No wrap has occurred, we can just use *head and *old. */
808e45c48a9SMathieu Poirier 	if (!wrapped)
809e45c48a9SMathieu Poirier 		return 0;
810e45c48a9SMathieu Poirier 
811e45c48a9SMathieu Poirier 	/*
812e45c48a9SMathieu Poirier 	 * *head has wrapped around - adjust *head and *old to pickup the
813e45c48a9SMathieu Poirier 	 * entire content of the AUX buffer.
814e45c48a9SMathieu Poirier 	 */
815e45c48a9SMathieu Poirier 	if (*head >= mm->len) {
816e45c48a9SMathieu Poirier 		*old = *head - mm->len;
817e45c48a9SMathieu Poirier 	} else {
818a818c563SMathieu Poirier 		*head += mm->len;
819e45c48a9SMathieu Poirier 		*old = *head - mm->len;
820e45c48a9SMathieu Poirier 	}
821a818c563SMathieu Poirier 
822a818c563SMathieu Poirier 	return 0;
823a818c563SMathieu Poirier }
824a818c563SMathieu Poirier 
825a818c563SMathieu Poirier static int cs_etm_snapshot_start(struct auxtrace_record *itr)
826a818c563SMathieu Poirier {
827a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
828a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
82932dcd021SJiri Olsa 	struct evsel *evsel;
830a818c563SMathieu Poirier 
831a818c563SMathieu Poirier 	evlist__for_each_entry(ptr->evlist, evsel) {
8321fc632ceSJiri Olsa 		if (evsel->core.attr.type == ptr->cs_etm_pmu->type)
8339a10bb22SJiri Olsa 			return evsel__disable(evsel);
834a818c563SMathieu Poirier 	}
835a818c563SMathieu Poirier 	return -EINVAL;
836a818c563SMathieu Poirier }
837a818c563SMathieu Poirier 
838a818c563SMathieu Poirier static int cs_etm_snapshot_finish(struct auxtrace_record *itr)
839a818c563SMathieu Poirier {
840a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
841a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
84232dcd021SJiri Olsa 	struct evsel *evsel;
843a818c563SMathieu Poirier 
844a818c563SMathieu Poirier 	evlist__for_each_entry(ptr->evlist, evsel) {
8451fc632ceSJiri Olsa 		if (evsel->core.attr.type == ptr->cs_etm_pmu->type)
846ec7f24efSJiri Olsa 			return evsel__enable(evsel);
847a818c563SMathieu Poirier 	}
848a818c563SMathieu Poirier 	return -EINVAL;
849a818c563SMathieu Poirier }
850a818c563SMathieu Poirier 
851a818c563SMathieu Poirier static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused)
852a818c563SMathieu Poirier {
853a818c563SMathieu Poirier 	return (((u64) rand() <<  0) & 0x00000000FFFFFFFFull) |
854a818c563SMathieu Poirier 		(((u64) rand() << 32) & 0xFFFFFFFF00000000ull);
855a818c563SMathieu Poirier }
856a818c563SMathieu Poirier 
857a818c563SMathieu Poirier static void cs_etm_recording_free(struct auxtrace_record *itr)
858a818c563SMathieu Poirier {
859a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
860a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
861e45c48a9SMathieu Poirier 
862e45c48a9SMathieu Poirier 	zfree(&ptr->wrapped);
863a818c563SMathieu Poirier 	free(ptr);
864a818c563SMathieu Poirier }
865a818c563SMathieu Poirier 
866a818c563SMathieu Poirier struct auxtrace_record *cs_etm_record_init(int *err)
867a818c563SMathieu Poirier {
868a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu;
869a818c563SMathieu Poirier 	struct cs_etm_recording *ptr;
870a818c563SMathieu Poirier 
871a818c563SMathieu Poirier 	cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
872a818c563SMathieu Poirier 
873a818c563SMathieu Poirier 	if (!cs_etm_pmu) {
874a818c563SMathieu Poirier 		*err = -EINVAL;
875a818c563SMathieu Poirier 		goto out;
876a818c563SMathieu Poirier 	}
877a818c563SMathieu Poirier 
878a818c563SMathieu Poirier 	ptr = zalloc(sizeof(struct cs_etm_recording));
879a818c563SMathieu Poirier 	if (!ptr) {
880a818c563SMathieu Poirier 		*err = -ENOMEM;
881a818c563SMathieu Poirier 		goto out;
882a818c563SMathieu Poirier 	}
883a818c563SMathieu Poirier 
884a818c563SMathieu Poirier 	ptr->cs_etm_pmu			= cs_etm_pmu;
885ad60ba0cSAdrian Hunter 	ptr->itr.pmu			= cs_etm_pmu;
886a818c563SMathieu Poirier 	ptr->itr.parse_snapshot_options	= cs_etm_parse_snapshot_options;
887a818c563SMathieu Poirier 	ptr->itr.recording_options	= cs_etm_recording_options;
888a818c563SMathieu Poirier 	ptr->itr.info_priv_size		= cs_etm_info_priv_size;
889a818c563SMathieu Poirier 	ptr->itr.info_fill		= cs_etm_info_fill;
890a818c563SMathieu Poirier 	ptr->itr.find_snapshot		= cs_etm_find_snapshot;
891a818c563SMathieu Poirier 	ptr->itr.snapshot_start		= cs_etm_snapshot_start;
892a818c563SMathieu Poirier 	ptr->itr.snapshot_finish	= cs_etm_snapshot_finish;
893a818c563SMathieu Poirier 	ptr->itr.reference		= cs_etm_reference;
894a818c563SMathieu Poirier 	ptr->itr.free			= cs_etm_recording_free;
895ad60ba0cSAdrian Hunter 	ptr->itr.read_finish		= auxtrace_record__read_finish;
896a818c563SMathieu Poirier 
897a818c563SMathieu Poirier 	*err = 0;
898a818c563SMathieu Poirier 	return &ptr->itr;
899a818c563SMathieu Poirier out:
900a818c563SMathieu Poirier 	return NULL;
901a818c563SMathieu Poirier }
902