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