xref: /linux/tools/perf/arch/arm/util/cs-etm.c (revision 315c0a1f0ccdd44c65f80ccbc62202fed8a23050)
18a9fd832SMathieu Poirier // SPDX-License-Identifier: GPL-2.0
2a818c563SMathieu Poirier /*
3a818c563SMathieu Poirier  * Copyright(C) 2015 Linaro Limited. All rights reserved.
4a818c563SMathieu Poirier  * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
5a818c563SMathieu Poirier  */
6a818c563SMathieu Poirier 
7a818c563SMathieu Poirier #include <api/fs/fs.h>
8fa4e819bSMathieu Poirier #include <linux/bits.h>
9a818c563SMathieu Poirier #include <linux/bitops.h>
10afaed6d3SArnaldo Carvalho de Melo #include <linux/compiler.h>
11a818c563SMathieu Poirier #include <linux/coresight-pmu.h>
12a818c563SMathieu Poirier #include <linux/kernel.h>
13a818c563SMathieu Poirier #include <linux/log2.h>
14a818c563SMathieu Poirier #include <linux/types.h>
157f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
16a818c563SMathieu Poirier 
17a818c563SMathieu Poirier #include "cs-etm.h"
18a818c563SMathieu Poirier #include "../../perf.h"
19a818c563SMathieu Poirier #include "../../util/auxtrace.h"
20a818c563SMathieu Poirier #include "../../util/cpumap.h"
21a818c563SMathieu Poirier #include "../../util/evlist.h"
223becf452SMathieu Poirier #include "../../util/evsel.h"
23a818c563SMathieu Poirier #include "../../util/pmu.h"
24a818c563SMathieu Poirier #include "../../util/thread_map.h"
25a818c563SMathieu Poirier #include "../../util/cs-etm.h"
261b2fc358SArnaldo Carvalho de Melo #include "../../util/util.h"
27a818c563SMathieu Poirier 
28fa4e819bSMathieu Poirier #include <errno.h>
29a818c563SMathieu Poirier #include <stdlib.h>
307a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h>
31a818c563SMathieu Poirier 
32a818c563SMathieu Poirier struct cs_etm_recording {
33a818c563SMathieu Poirier 	struct auxtrace_record	itr;
34a818c563SMathieu Poirier 	struct perf_pmu		*cs_etm_pmu;
3563503dbaSJiri Olsa 	struct evlist		*evlist;
36e45c48a9SMathieu Poirier 	int			wrapped_cnt;
37e45c48a9SMathieu Poirier 	bool			*wrapped;
38a818c563SMathieu Poirier 	bool			snapshot_mode;
39a818c563SMathieu Poirier 	size_t			snapshot_size;
40a818c563SMathieu Poirier };
41a818c563SMathieu Poirier 
423399ad9aSMathieu Poirier static const char *metadata_etmv3_ro[CS_ETM_PRIV_MAX] = {
433399ad9aSMathieu Poirier 	[CS_ETM_ETMCCER]	= "mgmt/etmccer",
443399ad9aSMathieu Poirier 	[CS_ETM_ETMIDR]		= "mgmt/etmidr",
453399ad9aSMathieu Poirier };
463399ad9aSMathieu Poirier 
473399ad9aSMathieu Poirier static const char *metadata_etmv4_ro[CS_ETMV4_PRIV_MAX] = {
483399ad9aSMathieu Poirier 	[CS_ETMV4_TRCIDR0]		= "trcidr/trcidr0",
493399ad9aSMathieu Poirier 	[CS_ETMV4_TRCIDR1]		= "trcidr/trcidr1",
503399ad9aSMathieu Poirier 	[CS_ETMV4_TRCIDR2]		= "trcidr/trcidr2",
513399ad9aSMathieu Poirier 	[CS_ETMV4_TRCIDR8]		= "trcidr/trcidr8",
523399ad9aSMathieu Poirier 	[CS_ETMV4_TRCAUTHSTATUS]	= "mgmt/trcauthstatus",
533399ad9aSMathieu Poirier };
543399ad9aSMathieu Poirier 
55a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu);
56a818c563SMathieu Poirier 
573399ad9aSMathieu Poirier static int cs_etm_set_context_id(struct auxtrace_record *itr,
5832dcd021SJiri Olsa 				 struct evsel *evsel, int cpu)
593399ad9aSMathieu Poirier {
603399ad9aSMathieu Poirier 	struct cs_etm_recording *ptr;
613399ad9aSMathieu Poirier 	struct perf_pmu *cs_etm_pmu;
623399ad9aSMathieu Poirier 	char path[PATH_MAX];
633399ad9aSMathieu Poirier 	int err = -EINVAL;
643399ad9aSMathieu Poirier 	u32 val;
653399ad9aSMathieu Poirier 
663399ad9aSMathieu Poirier 	ptr = container_of(itr, struct cs_etm_recording, itr);
673399ad9aSMathieu Poirier 	cs_etm_pmu = ptr->cs_etm_pmu;
683399ad9aSMathieu Poirier 
693399ad9aSMathieu Poirier 	if (!cs_etm_is_etmv4(itr, cpu))
703399ad9aSMathieu Poirier 		goto out;
713399ad9aSMathieu Poirier 
723399ad9aSMathieu Poirier 	/* Get a handle on TRCIRD2 */
733399ad9aSMathieu Poirier 	snprintf(path, PATH_MAX, "cpu%d/%s",
743399ad9aSMathieu Poirier 		 cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2]);
753399ad9aSMathieu Poirier 	err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val);
763399ad9aSMathieu Poirier 
773399ad9aSMathieu Poirier 	/* There was a problem reading the file, bailing out */
783399ad9aSMathieu Poirier 	if (err != 1) {
793399ad9aSMathieu Poirier 		pr_err("%s: can't read file %s\n",
803399ad9aSMathieu Poirier 		       CORESIGHT_ETM_PMU_NAME, path);
813399ad9aSMathieu Poirier 		goto out;
823399ad9aSMathieu Poirier 	}
833399ad9aSMathieu Poirier 
843399ad9aSMathieu Poirier 	/*
853399ad9aSMathieu Poirier 	 * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID tracing
863399ad9aSMathieu Poirier 	 * is supported:
873399ad9aSMathieu Poirier 	 *  0b00000 Context ID tracing is not supported.
883399ad9aSMathieu Poirier 	 *  0b00100 Maximum of 32-bit Context ID size.
893399ad9aSMathieu Poirier 	 *  All other values are reserved.
903399ad9aSMathieu Poirier 	 */
913399ad9aSMathieu Poirier 	val = BMVAL(val, 5, 9);
923399ad9aSMathieu Poirier 	if (!val || val != 0x4) {
933399ad9aSMathieu Poirier 		err = -EINVAL;
943399ad9aSMathieu Poirier 		goto out;
953399ad9aSMathieu Poirier 	}
963399ad9aSMathieu Poirier 
973399ad9aSMathieu Poirier 	/* All good, let the kernel know */
981fc632ceSJiri Olsa 	evsel->core.attr.config |= (1 << ETM_OPT_CTXTID);
993399ad9aSMathieu Poirier 	err = 0;
1003399ad9aSMathieu Poirier 
1013399ad9aSMathieu Poirier out:
1023399ad9aSMathieu Poirier 
1033399ad9aSMathieu Poirier 	return err;
1043399ad9aSMathieu Poirier }
1053399ad9aSMathieu Poirier 
1061c839a5aSMathieu Poirier static int cs_etm_set_timestamp(struct auxtrace_record *itr,
10732dcd021SJiri Olsa 				struct evsel *evsel, int cpu)
1081c839a5aSMathieu Poirier {
1091c839a5aSMathieu Poirier 	struct cs_etm_recording *ptr;
1101c839a5aSMathieu Poirier 	struct perf_pmu *cs_etm_pmu;
1111c839a5aSMathieu Poirier 	char path[PATH_MAX];
1121c839a5aSMathieu Poirier 	int err = -EINVAL;
1131c839a5aSMathieu Poirier 	u32 val;
1141c839a5aSMathieu Poirier 
1151c839a5aSMathieu Poirier 	ptr = container_of(itr, struct cs_etm_recording, itr);
1161c839a5aSMathieu Poirier 	cs_etm_pmu = ptr->cs_etm_pmu;
1171c839a5aSMathieu Poirier 
1181c839a5aSMathieu Poirier 	if (!cs_etm_is_etmv4(itr, cpu))
1191c839a5aSMathieu Poirier 		goto out;
1201c839a5aSMathieu Poirier 
1211c839a5aSMathieu Poirier 	/* Get a handle on TRCIRD0 */
1221c839a5aSMathieu Poirier 	snprintf(path, PATH_MAX, "cpu%d/%s",
1231c839a5aSMathieu Poirier 		 cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]);
1241c839a5aSMathieu Poirier 	err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val);
1251c839a5aSMathieu Poirier 
1261c839a5aSMathieu Poirier 	/* There was a problem reading the file, bailing out */
1271c839a5aSMathieu Poirier 	if (err != 1) {
1281c839a5aSMathieu Poirier 		pr_err("%s: can't read file %s\n",
1291c839a5aSMathieu Poirier 		       CORESIGHT_ETM_PMU_NAME, path);
1301c839a5aSMathieu Poirier 		goto out;
1311c839a5aSMathieu Poirier 	}
1321c839a5aSMathieu Poirier 
1331c839a5aSMathieu Poirier 	/*
1341c839a5aSMathieu Poirier 	 * TRCIDR0.TSSIZE, bit [28-24], indicates whether global timestamping
1351c839a5aSMathieu Poirier 	 * is supported:
1361c839a5aSMathieu Poirier 	 *  0b00000 Global timestamping is not implemented
1371c839a5aSMathieu Poirier 	 *  0b00110 Implementation supports a maximum timestamp of 48bits.
1381c839a5aSMathieu Poirier 	 *  0b01000 Implementation supports a maximum timestamp of 64bits.
1391c839a5aSMathieu Poirier 	 */
1401c839a5aSMathieu Poirier 	val &= GENMASK(28, 24);
1411c839a5aSMathieu Poirier 	if (!val) {
1421c839a5aSMathieu Poirier 		err = -EINVAL;
1431c839a5aSMathieu Poirier 		goto out;
1441c839a5aSMathieu Poirier 	}
1451c839a5aSMathieu Poirier 
1461c839a5aSMathieu Poirier 	/* All good, let the kernel know */
1471fc632ceSJiri Olsa 	evsel->core.attr.config |= (1 << ETM_OPT_TS);
1481c839a5aSMathieu Poirier 	err = 0;
1491c839a5aSMathieu Poirier 
1501c839a5aSMathieu Poirier out:
1511c839a5aSMathieu Poirier 	return err;
1521c839a5aSMathieu Poirier }
1531c839a5aSMathieu Poirier 
1543399ad9aSMathieu Poirier static int cs_etm_set_option(struct auxtrace_record *itr,
15532dcd021SJiri Olsa 			     struct evsel *evsel, u32 option)
1563399ad9aSMathieu Poirier {
1573399ad9aSMathieu Poirier 	int i, err = -EINVAL;
158f72f901dSJiri Olsa 	struct perf_cpu_map *event_cpus = evsel->evlist->core.cpus;
1599c3516d1SJiri Olsa 	struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL);
1603399ad9aSMathieu Poirier 
1613399ad9aSMathieu Poirier 	/* Set option of each CPU we have */
1623399ad9aSMathieu Poirier 	for (i = 0; i < cpu__max_cpu(); i++) {
1633399ad9aSMathieu Poirier 		if (!cpu_map__has(event_cpus, i) ||
1643399ad9aSMathieu Poirier 		    !cpu_map__has(online_cpus, i))
1653399ad9aSMathieu Poirier 			continue;
1663399ad9aSMathieu Poirier 
167374d910fSMathieu Poirier 		if (option & ETM_OPT_CTXTID) {
1683399ad9aSMathieu Poirier 			err = cs_etm_set_context_id(itr, evsel, i);
1693399ad9aSMathieu Poirier 			if (err)
1703399ad9aSMathieu Poirier 				goto out;
171374d910fSMathieu Poirier 		}
172374d910fSMathieu Poirier 		if (option & ETM_OPT_TS) {
1731c839a5aSMathieu Poirier 			err = cs_etm_set_timestamp(itr, evsel, i);
1741c839a5aSMathieu Poirier 			if (err)
1751c839a5aSMathieu Poirier 				goto out;
1763399ad9aSMathieu Poirier 		}
177374d910fSMathieu Poirier 		if (option & ~(ETM_OPT_CTXTID | ETM_OPT_TS))
178374d910fSMathieu Poirier 			/* Nothing else is currently supported */
179374d910fSMathieu Poirier 			goto out;
1803399ad9aSMathieu Poirier 	}
1813399ad9aSMathieu Poirier 
1823399ad9aSMathieu Poirier 	err = 0;
1833399ad9aSMathieu Poirier out:
18438f01d8dSJiri Olsa 	perf_cpu_map__put(online_cpus);
1853399ad9aSMathieu Poirier 	return err;
1863399ad9aSMathieu Poirier }
1873399ad9aSMathieu Poirier 
188a818c563SMathieu Poirier static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr,
189a818c563SMathieu Poirier 					 struct record_opts *opts,
190a818c563SMathieu Poirier 					 const char *str)
191a818c563SMathieu Poirier {
192a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
193a818c563SMathieu Poirier 				container_of(itr, struct cs_etm_recording, itr);
194a818c563SMathieu Poirier 	unsigned long long snapshot_size = 0;
195a818c563SMathieu Poirier 	char *endptr;
196a818c563SMathieu Poirier 
197a818c563SMathieu Poirier 	if (str) {
198a818c563SMathieu Poirier 		snapshot_size = strtoull(str, &endptr, 0);
199a818c563SMathieu Poirier 		if (*endptr || snapshot_size > SIZE_MAX)
200a818c563SMathieu Poirier 			return -1;
201a818c563SMathieu Poirier 	}
202a818c563SMathieu Poirier 
203a818c563SMathieu Poirier 	opts->auxtrace_snapshot_mode = true;
204a818c563SMathieu Poirier 	opts->auxtrace_snapshot_size = snapshot_size;
205a818c563SMathieu Poirier 	ptr->snapshot_size = snapshot_size;
206a818c563SMathieu Poirier 
207a818c563SMathieu Poirier 	return 0;
208a818c563SMathieu Poirier }
209a818c563SMathieu Poirier 
210fa4e819bSMathieu Poirier static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
21132dcd021SJiri Olsa 				struct evsel *evsel)
212fa4e819bSMathieu Poirier {
213fa4e819bSMathieu Poirier 	char msg[BUFSIZ], path[PATH_MAX], *sink;
214fa4e819bSMathieu Poirier 	struct perf_evsel_config_term *term;
215fa4e819bSMathieu Poirier 	int ret = -EINVAL;
216fa4e819bSMathieu Poirier 	u32 hash;
217fa4e819bSMathieu Poirier 
2181fc632ceSJiri Olsa 	if (evsel->core.attr.config2 & GENMASK(31, 0))
219fa4e819bSMathieu Poirier 		return 0;
220fa4e819bSMathieu Poirier 
221fa4e819bSMathieu Poirier 	list_for_each_entry(term, &evsel->config_terms, list) {
222fa4e819bSMathieu Poirier 		if (term->type != PERF_EVSEL__CONFIG_TERM_DRV_CFG)
223fa4e819bSMathieu Poirier 			continue;
224fa4e819bSMathieu Poirier 
225fa4e819bSMathieu Poirier 		sink = term->val.drv_cfg;
226fa4e819bSMathieu Poirier 		snprintf(path, PATH_MAX, "sinks/%s", sink);
227fa4e819bSMathieu Poirier 
228fa4e819bSMathieu Poirier 		ret = perf_pmu__scan_file(pmu, path, "%x", &hash);
229fa4e819bSMathieu Poirier 		if (ret != 1) {
230fa4e819bSMathieu Poirier 			pr_err("failed to set sink \"%s\" on event %s with %d (%s)\n",
231fa4e819bSMathieu Poirier 			       sink, perf_evsel__name(evsel), errno,
232fa4e819bSMathieu Poirier 			       str_error_r(errno, msg, sizeof(msg)));
233fa4e819bSMathieu Poirier 			return ret;
234fa4e819bSMathieu Poirier 		}
235fa4e819bSMathieu Poirier 
2361fc632ceSJiri Olsa 		evsel->core.attr.config2 |= hash;
237fa4e819bSMathieu Poirier 		return 0;
238fa4e819bSMathieu Poirier 	}
239fa4e819bSMathieu Poirier 
240fa4e819bSMathieu Poirier 	/*
241fa4e819bSMathieu Poirier 	 * No sink was provided on the command line - for _now_ treat
242fa4e819bSMathieu Poirier 	 * this as an error.
243fa4e819bSMathieu Poirier 	 */
244fa4e819bSMathieu Poirier 	return ret;
245fa4e819bSMathieu Poirier }
246fa4e819bSMathieu Poirier 
247a818c563SMathieu Poirier static int cs_etm_recording_options(struct auxtrace_record *itr,
24863503dbaSJiri Olsa 				    struct evlist *evlist,
249a818c563SMathieu Poirier 				    struct record_opts *opts)
250a818c563SMathieu Poirier {
251fa4e819bSMathieu Poirier 	int ret;
252a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
253a818c563SMathieu Poirier 				container_of(itr, struct cs_etm_recording, itr);
254a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
25532dcd021SJiri Olsa 	struct evsel *evsel, *cs_etm_evsel = NULL;
256f72f901dSJiri Olsa 	struct perf_cpu_map *cpus = evlist->core.cpus;
257a818c563SMathieu Poirier 	bool privileged = (geteuid() == 0 || perf_event_paranoid() < 0);
2583399ad9aSMathieu Poirier 	int err = 0;
259a818c563SMathieu Poirier 
260a818c563SMathieu Poirier 	ptr->evlist = evlist;
261a818c563SMathieu Poirier 	ptr->snapshot_mode = opts->auxtrace_snapshot_mode;
262a818c563SMathieu Poirier 
263e5993c42SMathieu Poirier 	if (perf_can_record_switch_events())
264e5993c42SMathieu Poirier 		opts->record_switch_events = true;
265e5993c42SMathieu Poirier 
266a818c563SMathieu Poirier 	evlist__for_each_entry(evlist, evsel) {
2671fc632ceSJiri Olsa 		if (evsel->core.attr.type == cs_etm_pmu->type) {
268a818c563SMathieu Poirier 			if (cs_etm_evsel) {
269a818c563SMathieu Poirier 				pr_err("There may be only one %s event\n",
270a818c563SMathieu Poirier 				       CORESIGHT_ETM_PMU_NAME);
271a818c563SMathieu Poirier 				return -EINVAL;
272a818c563SMathieu Poirier 			}
2731fc632ceSJiri Olsa 			evsel->core.attr.freq = 0;
2741fc632ceSJiri Olsa 			evsel->core.attr.sample_period = 1;
275a818c563SMathieu Poirier 			cs_etm_evsel = evsel;
276a818c563SMathieu Poirier 			opts->full_auxtrace = true;
277a818c563SMathieu Poirier 		}
278a818c563SMathieu Poirier 	}
279a818c563SMathieu Poirier 
280a818c563SMathieu Poirier 	/* no need to continue if at least one event of interest was found */
281a818c563SMathieu Poirier 	if (!cs_etm_evsel)
282a818c563SMathieu Poirier 		return 0;
283a818c563SMathieu Poirier 
284fa4e819bSMathieu Poirier 	ret = cs_etm_set_sink_attr(cs_etm_pmu, cs_etm_evsel);
285fa4e819bSMathieu Poirier 	if (ret)
286fa4e819bSMathieu Poirier 		return ret;
287fa4e819bSMathieu Poirier 
288a818c563SMathieu Poirier 	if (opts->use_clockid) {
289a818c563SMathieu Poirier 		pr_err("Cannot use clockid (-k option) with %s\n",
290a818c563SMathieu Poirier 		       CORESIGHT_ETM_PMU_NAME);
291a818c563SMathieu Poirier 		return -EINVAL;
292a818c563SMathieu Poirier 	}
293a818c563SMathieu Poirier 
294a818c563SMathieu Poirier 	/* we are in snapshot mode */
295a818c563SMathieu Poirier 	if (opts->auxtrace_snapshot_mode) {
296a818c563SMathieu Poirier 		/*
297a818c563SMathieu Poirier 		 * No size were given to '-S' or '-m,', so go with
298a818c563SMathieu Poirier 		 * the default
299a818c563SMathieu Poirier 		 */
300a818c563SMathieu Poirier 		if (!opts->auxtrace_snapshot_size &&
301a818c563SMathieu Poirier 		    !opts->auxtrace_mmap_pages) {
302a818c563SMathieu Poirier 			if (privileged) {
303a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages = MiB(4) / page_size;
304a818c563SMathieu Poirier 			} else {
305a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages =
306a818c563SMathieu Poirier 							KiB(128) / page_size;
307a818c563SMathieu Poirier 				if (opts->mmap_pages == UINT_MAX)
308a818c563SMathieu Poirier 					opts->mmap_pages = KiB(256) / page_size;
309a818c563SMathieu Poirier 			}
310a818c563SMathieu Poirier 		} else if (!opts->auxtrace_mmap_pages && !privileged &&
311a818c563SMathieu Poirier 						opts->mmap_pages == UINT_MAX) {
312a818c563SMathieu Poirier 			opts->mmap_pages = KiB(256) / page_size;
313a818c563SMathieu Poirier 		}
314a818c563SMathieu Poirier 
315a818c563SMathieu Poirier 		/*
316a818c563SMathieu Poirier 		 * '-m,xyz' was specified but no snapshot size, so make the
317a818c563SMathieu Poirier 		 * snapshot size as big as the auxtrace mmap area.
318a818c563SMathieu Poirier 		 */
319a818c563SMathieu Poirier 		if (!opts->auxtrace_snapshot_size) {
320a818c563SMathieu Poirier 			opts->auxtrace_snapshot_size =
321a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages * (size_t)page_size;
322a818c563SMathieu Poirier 		}
323a818c563SMathieu Poirier 
324a818c563SMathieu Poirier 		/*
325a818c563SMathieu Poirier 		 * -Sxyz was specified but no auxtrace mmap area, so make the
326a818c563SMathieu Poirier 		 * auxtrace mmap area big enough to fit the requested snapshot
327a818c563SMathieu Poirier 		 * size.
328a818c563SMathieu Poirier 		 */
329a818c563SMathieu Poirier 		if (!opts->auxtrace_mmap_pages) {
330a818c563SMathieu Poirier 			size_t sz = opts->auxtrace_snapshot_size;
331a818c563SMathieu Poirier 
332a818c563SMathieu Poirier 			sz = round_up(sz, page_size) / page_size;
333a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = roundup_pow_of_two(sz);
334a818c563SMathieu Poirier 		}
335a818c563SMathieu Poirier 
336a818c563SMathieu Poirier 		/* Snapshost size can't be bigger than the auxtrace area */
337a818c563SMathieu Poirier 		if (opts->auxtrace_snapshot_size >
338a818c563SMathieu Poirier 				opts->auxtrace_mmap_pages * (size_t)page_size) {
339a818c563SMathieu Poirier 			pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n",
340a818c563SMathieu Poirier 			       opts->auxtrace_snapshot_size,
341a818c563SMathieu Poirier 			       opts->auxtrace_mmap_pages * (size_t)page_size);
342a818c563SMathieu Poirier 			return -EINVAL;
343a818c563SMathieu Poirier 		}
344a818c563SMathieu Poirier 
345a818c563SMathieu Poirier 		/* Something went wrong somewhere - this shouldn't happen */
346a818c563SMathieu Poirier 		if (!opts->auxtrace_snapshot_size ||
347a818c563SMathieu Poirier 		    !opts->auxtrace_mmap_pages) {
348a818c563SMathieu Poirier 			pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n");
349a818c563SMathieu Poirier 			return -EINVAL;
350a818c563SMathieu Poirier 		}
351a818c563SMathieu Poirier 	}
352a818c563SMathieu Poirier 
353a818c563SMathieu Poirier 	/* We are in full trace mode but '-m,xyz' wasn't specified */
354a818c563SMathieu Poirier 	if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) {
355a818c563SMathieu Poirier 		if (privileged) {
356a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = MiB(4) / page_size;
357a818c563SMathieu Poirier 		} else {
358a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = KiB(128) / page_size;
359a818c563SMathieu Poirier 			if (opts->mmap_pages == UINT_MAX)
360a818c563SMathieu Poirier 				opts->mmap_pages = KiB(256) / page_size;
361a818c563SMathieu Poirier 		}
362a818c563SMathieu Poirier 
363a818c563SMathieu Poirier 	}
364a818c563SMathieu Poirier 
365a818c563SMathieu Poirier 	/* Validate auxtrace_mmap_pages provided by user */
366a818c563SMathieu Poirier 	if (opts->auxtrace_mmap_pages) {
367a818c563SMathieu Poirier 		unsigned int max_page = (KiB(128) / page_size);
368a818c563SMathieu Poirier 		size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size;
369a818c563SMathieu Poirier 
370a818c563SMathieu Poirier 		if (!privileged &&
371a818c563SMathieu Poirier 		    opts->auxtrace_mmap_pages > max_page) {
372a818c563SMathieu Poirier 			opts->auxtrace_mmap_pages = max_page;
373a818c563SMathieu Poirier 			pr_err("auxtrace too big, truncating to %d\n",
374a818c563SMathieu Poirier 			       max_page);
375a818c563SMathieu Poirier 		}
376a818c563SMathieu Poirier 
377a818c563SMathieu Poirier 		if (!is_power_of_2(sz)) {
378a818c563SMathieu Poirier 			pr_err("Invalid mmap size for %s: must be a power of 2\n",
379a818c563SMathieu Poirier 			       CORESIGHT_ETM_PMU_NAME);
380a818c563SMathieu Poirier 			return -EINVAL;
381a818c563SMathieu Poirier 		}
382a818c563SMathieu Poirier 	}
383a818c563SMathieu Poirier 
384a818c563SMathieu Poirier 	if (opts->auxtrace_snapshot_mode)
385a818c563SMathieu Poirier 		pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME,
386a818c563SMathieu Poirier 			  opts->auxtrace_snapshot_size);
387a818c563SMathieu Poirier 
388a818c563SMathieu Poirier 	/*
389a818c563SMathieu Poirier 	 * To obtain the auxtrace buffer file descriptor, the auxtrace
390a818c563SMathieu Poirier 	 * event must come first.
391a818c563SMathieu Poirier 	 */
392a818c563SMathieu Poirier 	perf_evlist__to_front(evlist, cs_etm_evsel);
3930c788d47SKim Phillips 
394a818c563SMathieu Poirier 	/*
395a818c563SMathieu Poirier 	 * In the case of per-cpu mmaps, we need the CPU on the
3963399ad9aSMathieu Poirier 	 * AUX event.  We also need the contextID in order to be notified
3973399ad9aSMathieu Poirier 	 * when a context switch happened.
398a818c563SMathieu Poirier 	 */
399*315c0a1fSJiri Olsa 	if (!perf_cpu_map__empty(cpus)) {
400a818c563SMathieu Poirier 		perf_evsel__set_sample_bit(cs_etm_evsel, CPU);
401a818c563SMathieu Poirier 
402374d910fSMathieu Poirier 		err = cs_etm_set_option(itr, cs_etm_evsel,
403374d910fSMathieu Poirier 					ETM_OPT_CTXTID | ETM_OPT_TS);
4041c839a5aSMathieu Poirier 		if (err)
4051c839a5aSMathieu Poirier 			goto out;
4063399ad9aSMathieu Poirier 	}
4073399ad9aSMathieu Poirier 
408a818c563SMathieu Poirier 	/* Add dummy event to keep tracking */
409a818c563SMathieu Poirier 	if (opts->full_auxtrace) {
41032dcd021SJiri Olsa 		struct evsel *tracking_evsel;
411a818c563SMathieu Poirier 
412a818c563SMathieu Poirier 		err = parse_events(evlist, "dummy:u", NULL);
413a818c563SMathieu Poirier 		if (err)
4143399ad9aSMathieu Poirier 			goto out;
415a818c563SMathieu Poirier 
416a818c563SMathieu Poirier 		tracking_evsel = perf_evlist__last(evlist);
417a818c563SMathieu Poirier 		perf_evlist__set_tracking_event(evlist, tracking_evsel);
418a818c563SMathieu Poirier 
4191fc632ceSJiri Olsa 		tracking_evsel->core.attr.freq = 0;
4201fc632ceSJiri Olsa 		tracking_evsel->core.attr.sample_period = 1;
421a818c563SMathieu Poirier 
422a818c563SMathieu Poirier 		/* In per-cpu case, always need the time of mmap events etc */
423*315c0a1fSJiri Olsa 		if (!perf_cpu_map__empty(cpus))
424a818c563SMathieu Poirier 			perf_evsel__set_sample_bit(tracking_evsel, TIME);
425a818c563SMathieu Poirier 	}
426a818c563SMathieu Poirier 
4273399ad9aSMathieu Poirier out:
4283399ad9aSMathieu Poirier 	return err;
429a818c563SMathieu Poirier }
430a818c563SMathieu Poirier 
431a818c563SMathieu Poirier static u64 cs_etm_get_config(struct auxtrace_record *itr)
432a818c563SMathieu Poirier {
433a818c563SMathieu Poirier 	u64 config = 0;
434a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
435a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
436a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
43763503dbaSJiri Olsa 	struct evlist *evlist = ptr->evlist;
43832dcd021SJiri Olsa 	struct evsel *evsel;
439a818c563SMathieu Poirier 
440a818c563SMathieu Poirier 	evlist__for_each_entry(evlist, evsel) {
4411fc632ceSJiri Olsa 		if (evsel->core.attr.type == cs_etm_pmu->type) {
442a818c563SMathieu Poirier 			/*
443a818c563SMathieu Poirier 			 * Variable perf_event_attr::config is assigned to
444a818c563SMathieu Poirier 			 * ETMv3/PTM.  The bit fields have been made to match
445a818c563SMathieu Poirier 			 * the ETMv3.5 ETRMCR register specification.  See the
446a818c563SMathieu Poirier 			 * PMU_FORMAT_ATTR() declarations in
447a818c563SMathieu Poirier 			 * drivers/hwtracing/coresight/coresight-perf.c for
448a818c563SMathieu Poirier 			 * details.
449a818c563SMathieu Poirier 			 */
4501fc632ceSJiri Olsa 			config = evsel->core.attr.config;
451a818c563SMathieu Poirier 			break;
452a818c563SMathieu Poirier 		}
453a818c563SMathieu Poirier 	}
454a818c563SMathieu Poirier 
455a818c563SMathieu Poirier 	return config;
456a818c563SMathieu Poirier }
457a818c563SMathieu Poirier 
458df770ff0SMike Leach #ifndef BIT
459df770ff0SMike Leach #define BIT(N) (1UL << (N))
460df770ff0SMike Leach #endif
461df770ff0SMike Leach 
462df770ff0SMike Leach static u64 cs_etmv4_get_config(struct auxtrace_record *itr)
463df770ff0SMike Leach {
464df770ff0SMike Leach 	u64 config = 0;
465df770ff0SMike Leach 	u64 config_opts = 0;
466df770ff0SMike Leach 
467df770ff0SMike Leach 	/*
468df770ff0SMike Leach 	 * The perf event variable config bits represent both
469df770ff0SMike Leach 	 * the command line options and register programming
470df770ff0SMike Leach 	 * bits in ETMv3/PTM. For ETMv4 we must remap options
471df770ff0SMike Leach 	 * to real bits
472df770ff0SMike Leach 	 */
473df770ff0SMike Leach 	config_opts = cs_etm_get_config(itr);
474df770ff0SMike Leach 	if (config_opts & BIT(ETM_OPT_CYCACC))
475df770ff0SMike Leach 		config |= BIT(ETM4_CFG_BIT_CYCACC);
4763399ad9aSMathieu Poirier 	if (config_opts & BIT(ETM_OPT_CTXTID))
4773399ad9aSMathieu Poirier 		config |= BIT(ETM4_CFG_BIT_CTXTID);
478df770ff0SMike Leach 	if (config_opts & BIT(ETM_OPT_TS))
479df770ff0SMike Leach 		config |= BIT(ETM4_CFG_BIT_TS);
480df770ff0SMike Leach 	if (config_opts & BIT(ETM_OPT_RETSTK))
481df770ff0SMike Leach 		config |= BIT(ETM4_CFG_BIT_RETSTK);
482df770ff0SMike Leach 
483df770ff0SMike Leach 	return config;
484df770ff0SMike Leach }
485df770ff0SMike Leach 
486a818c563SMathieu Poirier static size_t
487a818c563SMathieu Poirier cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused,
48863503dbaSJiri Olsa 		      struct evlist *evlist __maybe_unused)
489a818c563SMathieu Poirier {
490a818c563SMathieu Poirier 	int i;
491a818c563SMathieu Poirier 	int etmv3 = 0, etmv4 = 0;
492f72f901dSJiri Olsa 	struct perf_cpu_map *event_cpus = evlist->core.cpus;
4939c3516d1SJiri Olsa 	struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL);
494a818c563SMathieu Poirier 
495a818c563SMathieu Poirier 	/* cpu map is not empty, we have specific CPUs to work with */
496*315c0a1fSJiri Olsa 	if (!perf_cpu_map__empty(event_cpus)) {
497796bfaddSMathieu Poirier 		for (i = 0; i < cpu__max_cpu(); i++) {
498796bfaddSMathieu Poirier 			if (!cpu_map__has(event_cpus, i) ||
499796bfaddSMathieu Poirier 			    !cpu_map__has(online_cpus, i))
500796bfaddSMathieu Poirier 				continue;
501796bfaddSMathieu Poirier 
502796bfaddSMathieu Poirier 			if (cs_etm_is_etmv4(itr, i))
503a818c563SMathieu Poirier 				etmv4++;
504a818c563SMathieu Poirier 			else
505a818c563SMathieu Poirier 				etmv3++;
506a818c563SMathieu Poirier 		}
507a818c563SMathieu Poirier 	} else {
508a818c563SMathieu Poirier 		/* get configuration for all CPUs in the system */
509a818c563SMathieu Poirier 		for (i = 0; i < cpu__max_cpu(); i++) {
510796bfaddSMathieu Poirier 			if (!cpu_map__has(online_cpus, i))
511796bfaddSMathieu Poirier 				continue;
512796bfaddSMathieu Poirier 
513a818c563SMathieu Poirier 			if (cs_etm_is_etmv4(itr, i))
514a818c563SMathieu Poirier 				etmv4++;
515a818c563SMathieu Poirier 			else
516a818c563SMathieu Poirier 				etmv3++;
517a818c563SMathieu Poirier 		}
518a818c563SMathieu Poirier 	}
519a818c563SMathieu Poirier 
52038f01d8dSJiri Olsa 	perf_cpu_map__put(online_cpus);
521796bfaddSMathieu Poirier 
522a818c563SMathieu Poirier 	return (CS_ETM_HEADER_SIZE +
523a818c563SMathieu Poirier 	       (etmv4 * CS_ETMV4_PRIV_SIZE) +
524a818c563SMathieu Poirier 	       (etmv3 * CS_ETMV3_PRIV_SIZE));
525a818c563SMathieu Poirier }
526a818c563SMathieu Poirier 
527a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu)
528a818c563SMathieu Poirier {
529a818c563SMathieu Poirier 	bool ret = false;
530a818c563SMathieu Poirier 	char path[PATH_MAX];
531a818c563SMathieu Poirier 	int scan;
532a818c563SMathieu Poirier 	unsigned int val;
533a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
534a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
535a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
536a818c563SMathieu Poirier 
537a818c563SMathieu Poirier 	/* Take any of the RO files for ETMv4 and see if it present */
538a818c563SMathieu Poirier 	snprintf(path, PATH_MAX, "cpu%d/%s",
539a818c563SMathieu Poirier 		 cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]);
540a818c563SMathieu Poirier 	scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val);
541a818c563SMathieu Poirier 
542a818c563SMathieu Poirier 	/* The file was read successfully, we have a winner */
543a818c563SMathieu Poirier 	if (scan == 1)
544a818c563SMathieu Poirier 		ret = true;
545a818c563SMathieu Poirier 
546a818c563SMathieu Poirier 	return ret;
547a818c563SMathieu Poirier }
548a818c563SMathieu Poirier 
549a818c563SMathieu Poirier static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path)
550a818c563SMathieu Poirier {
551a818c563SMathieu Poirier 	char pmu_path[PATH_MAX];
552a818c563SMathieu Poirier 	int scan;
553a818c563SMathieu Poirier 	unsigned int val = 0;
554a818c563SMathieu Poirier 
555a818c563SMathieu Poirier 	/* Get RO metadata from sysfs */
556a818c563SMathieu Poirier 	snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path);
557a818c563SMathieu Poirier 
558a818c563SMathieu Poirier 	scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val);
559a818c563SMathieu Poirier 	if (scan != 1)
560a818c563SMathieu Poirier 		pr_err("%s: error reading: %s\n", __func__, pmu_path);
561a818c563SMathieu Poirier 
562a818c563SMathieu Poirier 	return val;
563a818c563SMathieu Poirier }
564a818c563SMathieu Poirier 
565a818c563SMathieu Poirier static void cs_etm_get_metadata(int cpu, u32 *offset,
566a818c563SMathieu Poirier 				struct auxtrace_record *itr,
567a818c563SMathieu Poirier 				struct auxtrace_info_event *info)
568a818c563SMathieu Poirier {
569a818c563SMathieu Poirier 	u32 increment;
570a818c563SMathieu Poirier 	u64 magic;
571a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
572a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
573a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
574a818c563SMathieu Poirier 
575a818c563SMathieu Poirier 	/* first see what kind of tracer this cpu is affined to */
576a818c563SMathieu Poirier 	if (cs_etm_is_etmv4(itr, cpu)) {
577a818c563SMathieu Poirier 		magic = __perf_cs_etmv4_magic;
578a818c563SMathieu Poirier 		/* Get trace configuration register */
579a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCCONFIGR] =
580df770ff0SMike Leach 						cs_etmv4_get_config(itr);
581a818c563SMathieu Poirier 		/* Get traceID from the framework */
582a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCTRACEIDR] =
583a818c563SMathieu Poirier 						coresight_get_trace_id(cpu);
584a818c563SMathieu Poirier 		/* Get read-only information from sysFS */
585a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR0] =
586a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
587a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR0]);
588a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR1] =
589a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
590a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR1]);
591a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR2] =
592a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
593a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR2]);
594a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCIDR8] =
595a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
596a818c563SMathieu Poirier 				      metadata_etmv4_ro[CS_ETMV4_TRCIDR8]);
597a818c563SMathieu Poirier 		info->priv[*offset + CS_ETMV4_TRCAUTHSTATUS] =
598a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
599a818c563SMathieu Poirier 				      metadata_etmv4_ro
600a818c563SMathieu Poirier 				      [CS_ETMV4_TRCAUTHSTATUS]);
601a818c563SMathieu Poirier 
602a818c563SMathieu Poirier 		/* How much space was used */
603a818c563SMathieu Poirier 		increment = CS_ETMV4_PRIV_MAX;
604a818c563SMathieu Poirier 	} else {
605a818c563SMathieu Poirier 		magic = __perf_cs_etmv3_magic;
606a818c563SMathieu Poirier 		/* Get configuration register */
607a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
608a818c563SMathieu Poirier 		/* Get traceID from the framework */
609a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMTRACEIDR] =
610a818c563SMathieu Poirier 						coresight_get_trace_id(cpu);
611a818c563SMathieu Poirier 		/* Get read-only information from sysFS */
612a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMCCER] =
613a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
614a818c563SMathieu Poirier 				      metadata_etmv3_ro[CS_ETM_ETMCCER]);
615a818c563SMathieu Poirier 		info->priv[*offset + CS_ETM_ETMIDR] =
616a818c563SMathieu Poirier 			cs_etm_get_ro(cs_etm_pmu, cpu,
617a818c563SMathieu Poirier 				      metadata_etmv3_ro[CS_ETM_ETMIDR]);
618a818c563SMathieu Poirier 
619a818c563SMathieu Poirier 		/* How much space was used */
620a818c563SMathieu Poirier 		increment = CS_ETM_PRIV_MAX;
621a818c563SMathieu Poirier 	}
622a818c563SMathieu Poirier 
623a818c563SMathieu Poirier 	/* Build generic header portion */
624a818c563SMathieu Poirier 	info->priv[*offset + CS_ETM_MAGIC] = magic;
625a818c563SMathieu Poirier 	info->priv[*offset + CS_ETM_CPU] = cpu;
626a818c563SMathieu Poirier 	/* Where the next CPU entry should start from */
627a818c563SMathieu Poirier 	*offset += increment;
628a818c563SMathieu Poirier }
629a818c563SMathieu Poirier 
630a818c563SMathieu Poirier static int cs_etm_info_fill(struct auxtrace_record *itr,
631a818c563SMathieu Poirier 			    struct perf_session *session,
632a818c563SMathieu Poirier 			    struct auxtrace_info_event *info,
633a818c563SMathieu Poirier 			    size_t priv_size)
634a818c563SMathieu Poirier {
635a818c563SMathieu Poirier 	int i;
636a818c563SMathieu Poirier 	u32 offset;
637a818c563SMathieu Poirier 	u64 nr_cpu, type;
638f854839bSJiri Olsa 	struct perf_cpu_map *cpu_map;
639f72f901dSJiri Olsa 	struct perf_cpu_map *event_cpus = session->evlist->core.cpus;
6409c3516d1SJiri Olsa 	struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL);
641a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
642a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
643a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
644a818c563SMathieu Poirier 
645a818c563SMathieu Poirier 	if (priv_size != cs_etm_info_priv_size(itr, session->evlist))
646a818c563SMathieu Poirier 		return -EINVAL;
647a818c563SMathieu Poirier 
648a818c563SMathieu Poirier 	if (!session->evlist->nr_mmaps)
649a818c563SMathieu Poirier 		return -EINVAL;
650a818c563SMathieu Poirier 
651796bfaddSMathieu Poirier 	/* If the cpu_map is empty all online CPUs are involved */
652*315c0a1fSJiri Olsa 	if (perf_cpu_map__empty(event_cpus)) {
653796bfaddSMathieu Poirier 		cpu_map = online_cpus;
654796bfaddSMathieu Poirier 	} else {
655796bfaddSMathieu Poirier 		/* Make sure all specified CPUs are online */
6566549cd8fSJiri Olsa 		for (i = 0; i < perf_cpu_map__nr(event_cpus); i++) {
657796bfaddSMathieu Poirier 			if (cpu_map__has(event_cpus, i) &&
658796bfaddSMathieu Poirier 			    !cpu_map__has(online_cpus, i))
659796bfaddSMathieu Poirier 				return -EINVAL;
660796bfaddSMathieu Poirier 		}
661796bfaddSMathieu Poirier 
662796bfaddSMathieu Poirier 		cpu_map = event_cpus;
663796bfaddSMathieu Poirier 	}
664796bfaddSMathieu Poirier 
6656549cd8fSJiri Olsa 	nr_cpu = perf_cpu_map__nr(cpu_map);
666a818c563SMathieu Poirier 	/* Get PMU type as dynamically assigned by the core */
667a818c563SMathieu Poirier 	type = cs_etm_pmu->type;
668a818c563SMathieu Poirier 
669a818c563SMathieu Poirier 	/* First fill out the session header */
670a818c563SMathieu Poirier 	info->type = PERF_AUXTRACE_CS_ETM;
671a818c563SMathieu Poirier 	info->priv[CS_HEADER_VERSION_0] = 0;
672a818c563SMathieu Poirier 	info->priv[CS_PMU_TYPE_CPUS] = type << 32;
673a818c563SMathieu Poirier 	info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu;
674a818c563SMathieu Poirier 	info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode;
675a818c563SMathieu Poirier 
676a818c563SMathieu Poirier 	offset = CS_ETM_SNAPSHOT + 1;
677a818c563SMathieu Poirier 
678796bfaddSMathieu Poirier 	for (i = 0; i < cpu__max_cpu() && offset < priv_size; i++)
679796bfaddSMathieu Poirier 		if (cpu_map__has(cpu_map, i))
680a818c563SMathieu Poirier 			cs_etm_get_metadata(i, &offset, itr, info);
681796bfaddSMathieu Poirier 
68238f01d8dSJiri Olsa 	perf_cpu_map__put(online_cpus);
683a818c563SMathieu Poirier 
684a818c563SMathieu Poirier 	return 0;
685a818c563SMathieu Poirier }
686a818c563SMathieu Poirier 
687e45c48a9SMathieu Poirier static int cs_etm_alloc_wrapped_array(struct cs_etm_recording *ptr, int idx)
688e45c48a9SMathieu Poirier {
689e45c48a9SMathieu Poirier 	bool *wrapped;
690e45c48a9SMathieu Poirier 	int cnt = ptr->wrapped_cnt;
691e45c48a9SMathieu Poirier 
692e45c48a9SMathieu Poirier 	/* Make @ptr->wrapped as big as @idx */
693e45c48a9SMathieu Poirier 	while (cnt <= idx)
694e45c48a9SMathieu Poirier 		cnt++;
695e45c48a9SMathieu Poirier 
696e45c48a9SMathieu Poirier 	/*
697e45c48a9SMathieu Poirier 	 * Free'ed in cs_etm_recording_free().  Using realloc() to avoid
698e45c48a9SMathieu Poirier 	 * cross compilation problems where the host's system supports
699e45c48a9SMathieu Poirier 	 * reallocarray() but not the target.
700e45c48a9SMathieu Poirier 	 */
701e45c48a9SMathieu Poirier 	wrapped = realloc(ptr->wrapped, cnt * sizeof(bool));
702e45c48a9SMathieu Poirier 	if (!wrapped)
703e45c48a9SMathieu Poirier 		return -ENOMEM;
704e45c48a9SMathieu Poirier 
705e45c48a9SMathieu Poirier 	wrapped[cnt - 1] = false;
706e45c48a9SMathieu Poirier 	ptr->wrapped_cnt = cnt;
707e45c48a9SMathieu Poirier 	ptr->wrapped = wrapped;
708e45c48a9SMathieu Poirier 
709e45c48a9SMathieu Poirier 	return 0;
710e45c48a9SMathieu Poirier }
711e45c48a9SMathieu Poirier 
712e45c48a9SMathieu Poirier static bool cs_etm_buffer_has_wrapped(unsigned char *buffer,
713e45c48a9SMathieu Poirier 				      size_t buffer_size, u64 head)
714e45c48a9SMathieu Poirier {
715e45c48a9SMathieu Poirier 	u64 i, watermark;
716e45c48a9SMathieu Poirier 	u64 *buf = (u64 *)buffer;
717e45c48a9SMathieu Poirier 	size_t buf_size = buffer_size;
718e45c48a9SMathieu Poirier 
719e45c48a9SMathieu Poirier 	/*
720e45c48a9SMathieu Poirier 	 * We want to look the very last 512 byte (chosen arbitrarily) in
721e45c48a9SMathieu Poirier 	 * the ring buffer.
722e45c48a9SMathieu Poirier 	 */
723e45c48a9SMathieu Poirier 	watermark = buf_size - 512;
724e45c48a9SMathieu Poirier 
725e45c48a9SMathieu Poirier 	/*
726e45c48a9SMathieu Poirier 	 * @head is continuously increasing - if its value is equal or greater
727e45c48a9SMathieu Poirier 	 * than the size of the ring buffer, it has wrapped around.
728e45c48a9SMathieu Poirier 	 */
729e45c48a9SMathieu Poirier 	if (head >= buffer_size)
730e45c48a9SMathieu Poirier 		return true;
731e45c48a9SMathieu Poirier 
732e45c48a9SMathieu Poirier 	/*
733e45c48a9SMathieu Poirier 	 * The value of @head is somewhere within the size of the ring buffer.
734e45c48a9SMathieu Poirier 	 * This can be that there hasn't been enough data to fill the ring
735e45c48a9SMathieu Poirier 	 * buffer yet or the trace time was so long that @head has numerically
736e45c48a9SMathieu Poirier 	 * wrapped around.  To find we need to check if we have data at the very
737e45c48a9SMathieu Poirier 	 * end of the ring buffer.  We can reliably do this because mmap'ed
738e45c48a9SMathieu Poirier 	 * pages are zeroed out and there is a fresh mapping with every new
739e45c48a9SMathieu Poirier 	 * session.
740e45c48a9SMathieu Poirier 	 */
741e45c48a9SMathieu Poirier 
742e45c48a9SMathieu Poirier 	/* @head is less than 512 byte from the end of the ring buffer */
743e45c48a9SMathieu Poirier 	if (head > watermark)
744e45c48a9SMathieu Poirier 		watermark = head;
745e45c48a9SMathieu Poirier 
746e45c48a9SMathieu Poirier 	/*
747e45c48a9SMathieu Poirier 	 * Speed things up by using 64 bit transactions (see "u64 *buf" above)
748e45c48a9SMathieu Poirier 	 */
749e45c48a9SMathieu Poirier 	watermark >>= 3;
750e45c48a9SMathieu Poirier 	buf_size >>= 3;
751e45c48a9SMathieu Poirier 
752e45c48a9SMathieu Poirier 	/*
753e45c48a9SMathieu Poirier 	 * If we find trace data at the end of the ring buffer, @head has
754e45c48a9SMathieu Poirier 	 * been there and has numerically wrapped around at least once.
755e45c48a9SMathieu Poirier 	 */
756e45c48a9SMathieu Poirier 	for (i = watermark; i < buf_size; i++)
757e45c48a9SMathieu Poirier 		if (buf[i])
758e45c48a9SMathieu Poirier 			return true;
759e45c48a9SMathieu Poirier 
760e45c48a9SMathieu Poirier 	return false;
761e45c48a9SMathieu Poirier }
762e45c48a9SMathieu Poirier 
763e45c48a9SMathieu Poirier static int cs_etm_find_snapshot(struct auxtrace_record *itr,
764a818c563SMathieu Poirier 				int idx, struct auxtrace_mmap *mm,
765e45c48a9SMathieu Poirier 				unsigned char *data,
766a818c563SMathieu Poirier 				u64 *head, u64 *old)
767a818c563SMathieu Poirier {
768e45c48a9SMathieu Poirier 	int err;
769e45c48a9SMathieu Poirier 	bool wrapped;
770e45c48a9SMathieu Poirier 	struct cs_etm_recording *ptr =
771e45c48a9SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
772e45c48a9SMathieu Poirier 
773e45c48a9SMathieu Poirier 	/*
774e45c48a9SMathieu Poirier 	 * Allocate memory to keep track of wrapping if this is the first
775e45c48a9SMathieu Poirier 	 * time we deal with this *mm.
776e45c48a9SMathieu Poirier 	 */
777e45c48a9SMathieu Poirier 	if (idx >= ptr->wrapped_cnt) {
778e45c48a9SMathieu Poirier 		err = cs_etm_alloc_wrapped_array(ptr, idx);
779e45c48a9SMathieu Poirier 		if (err)
780e45c48a9SMathieu Poirier 			return err;
781e45c48a9SMathieu Poirier 	}
782e45c48a9SMathieu Poirier 
783e45c48a9SMathieu Poirier 	/*
784e45c48a9SMathieu Poirier 	 * Check to see if *head has wrapped around.  If it hasn't only the
785e45c48a9SMathieu Poirier 	 * amount of data between *head and *old is snapshot'ed to avoid
786e45c48a9SMathieu Poirier 	 * bloating the perf.data file with zeros.  But as soon as *head has
787e45c48a9SMathieu Poirier 	 * wrapped around the entire size of the AUX ring buffer it taken.
788e45c48a9SMathieu Poirier 	 */
789e45c48a9SMathieu Poirier 	wrapped = ptr->wrapped[idx];
790e45c48a9SMathieu Poirier 	if (!wrapped && cs_etm_buffer_has_wrapped(data, mm->len, *head)) {
791e45c48a9SMathieu Poirier 		wrapped = true;
792e45c48a9SMathieu Poirier 		ptr->wrapped[idx] = true;
793e45c48a9SMathieu Poirier 	}
794e45c48a9SMathieu Poirier 
795a818c563SMathieu Poirier 	pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n",
796a818c563SMathieu Poirier 		  __func__, idx, (size_t)*old, (size_t)*head, mm->len);
797a818c563SMathieu Poirier 
798e45c48a9SMathieu Poirier 	/* No wrap has occurred, we can just use *head and *old. */
799e45c48a9SMathieu Poirier 	if (!wrapped)
800e45c48a9SMathieu Poirier 		return 0;
801e45c48a9SMathieu Poirier 
802e45c48a9SMathieu Poirier 	/*
803e45c48a9SMathieu Poirier 	 * *head has wrapped around - adjust *head and *old to pickup the
804e45c48a9SMathieu Poirier 	 * entire content of the AUX buffer.
805e45c48a9SMathieu Poirier 	 */
806e45c48a9SMathieu Poirier 	if (*head >= mm->len) {
807e45c48a9SMathieu Poirier 		*old = *head - mm->len;
808e45c48a9SMathieu Poirier 	} else {
809a818c563SMathieu Poirier 		*head += mm->len;
810e45c48a9SMathieu Poirier 		*old = *head - mm->len;
811e45c48a9SMathieu Poirier 	}
812a818c563SMathieu Poirier 
813a818c563SMathieu Poirier 	return 0;
814a818c563SMathieu Poirier }
815a818c563SMathieu Poirier 
816a818c563SMathieu Poirier static int cs_etm_snapshot_start(struct auxtrace_record *itr)
817a818c563SMathieu Poirier {
818a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
819a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
82032dcd021SJiri Olsa 	struct evsel *evsel;
821a818c563SMathieu Poirier 
822a818c563SMathieu Poirier 	evlist__for_each_entry(ptr->evlist, evsel) {
8231fc632ceSJiri Olsa 		if (evsel->core.attr.type == ptr->cs_etm_pmu->type)
8249a10bb22SJiri Olsa 			return evsel__disable(evsel);
825a818c563SMathieu Poirier 	}
826a818c563SMathieu Poirier 	return -EINVAL;
827a818c563SMathieu Poirier }
828a818c563SMathieu Poirier 
829a818c563SMathieu Poirier static int cs_etm_snapshot_finish(struct auxtrace_record *itr)
830a818c563SMathieu Poirier {
831a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
832a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
83332dcd021SJiri Olsa 	struct evsel *evsel;
834a818c563SMathieu Poirier 
835a818c563SMathieu Poirier 	evlist__for_each_entry(ptr->evlist, evsel) {
8361fc632ceSJiri Olsa 		if (evsel->core.attr.type == ptr->cs_etm_pmu->type)
837ec7f24efSJiri Olsa 			return evsel__enable(evsel);
838a818c563SMathieu Poirier 	}
839a818c563SMathieu Poirier 	return -EINVAL;
840a818c563SMathieu Poirier }
841a818c563SMathieu Poirier 
842a818c563SMathieu Poirier static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused)
843a818c563SMathieu Poirier {
844a818c563SMathieu Poirier 	return (((u64) rand() <<  0) & 0x00000000FFFFFFFFull) |
845a818c563SMathieu Poirier 		(((u64) rand() << 32) & 0xFFFFFFFF00000000ull);
846a818c563SMathieu Poirier }
847a818c563SMathieu Poirier 
848a818c563SMathieu Poirier static void cs_etm_recording_free(struct auxtrace_record *itr)
849a818c563SMathieu Poirier {
850a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
851a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
852e45c48a9SMathieu Poirier 
853e45c48a9SMathieu Poirier 	zfree(&ptr->wrapped);
854a818c563SMathieu Poirier 	free(ptr);
855a818c563SMathieu Poirier }
856a818c563SMathieu Poirier 
857a818c563SMathieu Poirier static int cs_etm_read_finish(struct auxtrace_record *itr, int idx)
858a818c563SMathieu Poirier {
859a818c563SMathieu Poirier 	struct cs_etm_recording *ptr =
860a818c563SMathieu Poirier 			container_of(itr, struct cs_etm_recording, itr);
86132dcd021SJiri Olsa 	struct evsel *evsel;
862a818c563SMathieu Poirier 
863a818c563SMathieu Poirier 	evlist__for_each_entry(ptr->evlist, evsel) {
8641fc632ceSJiri Olsa 		if (evsel->core.attr.type == ptr->cs_etm_pmu->type)
865a818c563SMathieu Poirier 			return perf_evlist__enable_event_idx(ptr->evlist,
866a818c563SMathieu Poirier 							     evsel, idx);
867a818c563SMathieu Poirier 	}
868a818c563SMathieu Poirier 
869a818c563SMathieu Poirier 	return -EINVAL;
870a818c563SMathieu Poirier }
871a818c563SMathieu Poirier 
872a818c563SMathieu Poirier struct auxtrace_record *cs_etm_record_init(int *err)
873a818c563SMathieu Poirier {
874a818c563SMathieu Poirier 	struct perf_pmu *cs_etm_pmu;
875a818c563SMathieu Poirier 	struct cs_etm_recording *ptr;
876a818c563SMathieu Poirier 
877a818c563SMathieu Poirier 	cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
878a818c563SMathieu Poirier 
879a818c563SMathieu Poirier 	if (!cs_etm_pmu) {
880a818c563SMathieu Poirier 		*err = -EINVAL;
881a818c563SMathieu Poirier 		goto out;
882a818c563SMathieu Poirier 	}
883a818c563SMathieu Poirier 
884a818c563SMathieu Poirier 	ptr = zalloc(sizeof(struct cs_etm_recording));
885a818c563SMathieu Poirier 	if (!ptr) {
886a818c563SMathieu Poirier 		*err = -ENOMEM;
887a818c563SMathieu Poirier 		goto out;
888a818c563SMathieu Poirier 	}
889a818c563SMathieu Poirier 
890a818c563SMathieu Poirier 	ptr->cs_etm_pmu			= cs_etm_pmu;
891a818c563SMathieu Poirier 	ptr->itr.parse_snapshot_options	= cs_etm_parse_snapshot_options;
892a818c563SMathieu Poirier 	ptr->itr.recording_options	= cs_etm_recording_options;
893a818c563SMathieu Poirier 	ptr->itr.info_priv_size		= cs_etm_info_priv_size;
894a818c563SMathieu Poirier 	ptr->itr.info_fill		= cs_etm_info_fill;
895a818c563SMathieu Poirier 	ptr->itr.find_snapshot		= cs_etm_find_snapshot;
896a818c563SMathieu Poirier 	ptr->itr.snapshot_start		= cs_etm_snapshot_start;
897a818c563SMathieu Poirier 	ptr->itr.snapshot_finish	= cs_etm_snapshot_finish;
898a818c563SMathieu Poirier 	ptr->itr.reference		= cs_etm_reference;
899a818c563SMathieu Poirier 	ptr->itr.free			= cs_etm_recording_free;
900a818c563SMathieu Poirier 	ptr->itr.read_finish		= cs_etm_read_finish;
901a818c563SMathieu Poirier 
902a818c563SMathieu Poirier 	*err = 0;
903a818c563SMathieu Poirier 	return &ptr->itr;
904a818c563SMathieu Poirier out:
905a818c563SMathieu Poirier 	return NULL;
906a818c563SMathieu Poirier }
907