brintos

brintos / linux-shallow public Read only

0
0
Text · 27.1 KiB · ea891d1 Raw
917 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright(C) 2015 Linaro Limited. All rights reserved.4 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>5 */6 7#include <api/fs/fs.h>8#include <linux/bits.h>9#include <linux/bitops.h>10#include <linux/compiler.h>11#include <linux/coresight-pmu.h>12#include <linux/kernel.h>13#include <linux/log2.h>14#include <linux/string.h>15#include <linux/types.h>16#include <linux/zalloc.h>17 18#include "cs-etm.h"19#include "../../../util/debug.h"20#include "../../../util/record.h"21#include "../../../util/auxtrace.h"22#include "../../../util/cpumap.h"23#include "../../../util/event.h"24#include "../../../util/evlist.h"25#include "../../../util/evsel.h"26#include "../../../util/perf_api_probe.h"27#include "../../../util/evsel_config.h"28#include "../../../util/pmus.h"29#include "../../../util/cs-etm.h"30#include <internal/lib.h> // page_size31#include "../../../util/session.h"32 33#include <errno.h>34#include <stdlib.h>35#include <sys/stat.h>36 37struct cs_etm_recording {38	struct auxtrace_record	itr;39	struct perf_pmu		*cs_etm_pmu;40	struct evlist		*evlist;41	bool			snapshot_mode;42	size_t			snapshot_size;43};44 45static const char *metadata_etmv3_ro[CS_ETM_PRIV_MAX] = {46	[CS_ETM_ETMCCER]	= "mgmt/etmccer",47	[CS_ETM_ETMIDR]		= "mgmt/etmidr",48};49 50static const char * const metadata_etmv4_ro[] = {51	[CS_ETMV4_TRCIDR0]		= "trcidr/trcidr0",52	[CS_ETMV4_TRCIDR1]		= "trcidr/trcidr1",53	[CS_ETMV4_TRCIDR2]		= "trcidr/trcidr2",54	[CS_ETMV4_TRCIDR8]		= "trcidr/trcidr8",55	[CS_ETMV4_TRCAUTHSTATUS]	= "mgmt/trcauthstatus",56	[CS_ETMV4_TS_SOURCE]		= "ts_source",57};58 59static const char * const metadata_ete_ro[] = {60	[CS_ETE_TRCIDR0]		= "trcidr/trcidr0",61	[CS_ETE_TRCIDR1]		= "trcidr/trcidr1",62	[CS_ETE_TRCIDR2]		= "trcidr/trcidr2",63	[CS_ETE_TRCIDR8]		= "trcidr/trcidr8",64	[CS_ETE_TRCAUTHSTATUS]		= "mgmt/trcauthstatus",65	[CS_ETE_TRCDEVARCH]		= "mgmt/trcdevarch",66	[CS_ETE_TS_SOURCE]		= "ts_source",67};68 69enum cs_etm_version { CS_NOT_PRESENT, CS_ETMV3, CS_ETMV4, CS_ETE };70 71static bool cs_etm_is_ete(struct perf_pmu *cs_etm_pmu, struct perf_cpu cpu);72static int cs_etm_get_ro(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path, __u64 *val);73static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path);74 75static enum cs_etm_version cs_etm_get_version(struct perf_pmu *cs_etm_pmu,76					      struct perf_cpu cpu)77{78	if (cs_etm_is_ete(cs_etm_pmu, cpu))79		return CS_ETE;80	else if (cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]))81		return CS_ETMV4;82	else if (cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_etmv3_ro[CS_ETM_ETMCCER]))83		return CS_ETMV3;84 85	return CS_NOT_PRESENT;86}87 88static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel *evsel,89				      struct perf_cpu cpu)90{91	int err;92	__u64 val;93	u64 contextid = evsel->core.attr.config &94		(perf_pmu__format_bits(cs_etm_pmu, "contextid") |95		 perf_pmu__format_bits(cs_etm_pmu, "contextid1") |96		 perf_pmu__format_bits(cs_etm_pmu, "contextid2"));97 98	if (!contextid)99		return 0;100 101	/* Not supported in etmv3 */102	if (cs_etm_get_version(cs_etm_pmu, cpu) == CS_ETMV3) {103		pr_err("%s: contextid not supported in ETMv3, disable with %s/contextid=0/\n",104		       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);105		return -EINVAL;106	}107 108	/* Get a handle on TRCIDR2 */109	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &val);110	if (err)111		return err;112 113	if (contextid &114	    perf_pmu__format_bits(cs_etm_pmu, "contextid1")) {115		/*116		 * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID117		 * tracing is supported:118		 *  0b00000 Context ID tracing is not supported.119		 *  0b00100 Maximum of 32-bit Context ID size.120		 *  All other values are reserved.121		 */122		if (BMVAL(val, 5, 9) != 0x4) {123			pr_err("%s: CONTEXTIDR_EL1 isn't supported, disable with %s/contextid1=0/\n",124			       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);125			return -EINVAL;126		}127	}128 129	if (contextid &130	    perf_pmu__format_bits(cs_etm_pmu, "contextid2")) {131		/*132		 * TRCIDR2.VMIDOPT[30:29] != 0 and133		 * TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid)134		 * We can't support CONTEXTIDR in VMID if the size of the135		 * virtual context id is < 32bit.136		 * Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us.137		 */138		if (!BMVAL(val, 29, 30) || BMVAL(val, 10, 14) < 4) {139			pr_err("%s: CONTEXTIDR_EL2 isn't supported, disable with %s/contextid2=0/\n",140			       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);141			return -EINVAL;142		}143	}144 145	return 0;146}147 148static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *evsel,149				     struct perf_cpu cpu)150{151	int err;152	__u64 val;153 154	if (!(evsel->core.attr.config &155	      perf_pmu__format_bits(cs_etm_pmu, "timestamp")))156		return 0;157 158	if (cs_etm_get_version(cs_etm_pmu, cpu) == CS_ETMV3) {159		pr_err("%s: timestamp not supported in ETMv3, disable with %s/timestamp=0/\n",160		       CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);161		return -EINVAL;162	}163 164	/* Get a handle on TRCIRD0 */165	err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0], &val);166	if (err)167		return err;168 169	/*170	 * TRCIDR0.TSSIZE, bit [28-24], indicates whether global timestamping171	 * is supported:172	 *  0b00000 Global timestamping is not implemented173	 *  0b00110 Implementation supports a maximum timestamp of 48bits.174	 *  0b01000 Implementation supports a maximum timestamp of 64bits.175	 */176	val &= GENMASK(28, 24);177	if (!val) {178		return -EINVAL;179	}180 181	return 0;182}183 184static struct perf_pmu *cs_etm_get_pmu(struct auxtrace_record *itr)185{186	struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr);187 188	return ptr->cs_etm_pmu;189}190 191/*192 * Check whether the requested timestamp and contextid options should be193 * available on all requested CPUs and if not, tell the user how to override.194 * The kernel will silently disable any unavailable options so a warning here195 * first is better. In theory the kernel could still disable the option for196 * some other reason so this is best effort only.197 */198static int cs_etm_validate_config(struct perf_pmu *cs_etm_pmu,199				  struct evsel *evsel)200{201	int idx, err = 0;202	struct perf_cpu_map *event_cpus = evsel->evlist->core.user_requested_cpus;203	struct perf_cpu_map *intersect_cpus;204	struct perf_cpu cpu;205 206	/*207	 * Set option of each CPU we have. In per-cpu case, do the validation208	 * for CPUs to work with. In per-thread case, the CPU map has the "any"209	 * CPU value. Since the traced program can run on any CPUs in this case,210	 * thus don't skip validation.211	 */212	if (!perf_cpu_map__has_any_cpu(event_cpus)) {213		struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus();214 215		intersect_cpus = perf_cpu_map__intersect(event_cpus, online_cpus);216		perf_cpu_map__put(online_cpus);217	} else {218		intersect_cpus = perf_cpu_map__new_online_cpus();219	}220 221	perf_cpu_map__for_each_cpu_skip_any(cpu, idx, intersect_cpus) {222		if (cs_etm_get_version(cs_etm_pmu, cpu) == CS_NOT_PRESENT) {223			pr_err("%s: Not found on CPU %d. Check hardware and firmware support and that all Coresight drivers are loaded\n",224			       CORESIGHT_ETM_PMU_NAME, cpu.cpu);225			return -EINVAL;226		}227		err = cs_etm_validate_context_id(cs_etm_pmu, evsel, cpu);228		if (err)229			break;230 231		err = cs_etm_validate_timestamp(cs_etm_pmu, evsel, cpu);232		if (err)233			break;234	}235 236	perf_cpu_map__put(intersect_cpus);237	return err;238}239 240static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr,241					 struct record_opts *opts,242					 const char *str)243{244	struct cs_etm_recording *ptr =245				container_of(itr, struct cs_etm_recording, itr);246	unsigned long long snapshot_size = 0;247	char *endptr;248 249	if (str) {250		snapshot_size = strtoull(str, &endptr, 0);251		if (*endptr || snapshot_size > SIZE_MAX)252			return -1;253	}254 255	opts->auxtrace_snapshot_mode = true;256	opts->auxtrace_snapshot_size = snapshot_size;257	ptr->snapshot_size = snapshot_size;258 259	return 0;260}261 262static int cs_etm_set_sink_attr(struct perf_pmu *pmu,263				struct evsel *evsel)264{265	char msg[BUFSIZ], path[PATH_MAX], *sink;266	struct evsel_config_term *term;267	int ret = -EINVAL;268	u32 hash;269 270	if (evsel->core.attr.config2 & GENMASK(31, 0))271		return 0;272 273	list_for_each_entry(term, &evsel->config_terms, list) {274		if (term->type != EVSEL__CONFIG_TERM_DRV_CFG)275			continue;276 277		sink = term->val.str;278		snprintf(path, PATH_MAX, "sinks/%s", sink);279 280		ret = perf_pmu__scan_file(pmu, path, "%x", &hash);281		if (ret != 1) {282			if (errno == ENOENT)283				pr_err("Couldn't find sink \"%s\" on event %s\n"284				       "Missing kernel or device support?\n\n"285				       "Hint: An appropriate sink will be picked automatically if one isn't specified.\n",286				       sink, evsel__name(evsel));287			else288				pr_err("Failed to set sink \"%s\" on event %s with %d (%s)\n",289				       sink, evsel__name(evsel), errno,290				       str_error_r(errno, msg, sizeof(msg)));291			return ret;292		}293 294		evsel->core.attr.config2 |= hash;295		return 0;296	}297 298	/*299	 * No sink was provided on the command line - allow the CoreSight300	 * system to look for a default301	 */302	return 0;303}304 305static int cs_etm_recording_options(struct auxtrace_record *itr,306				    struct evlist *evlist,307				    struct record_opts *opts)308{309	int ret;310	struct cs_etm_recording *ptr =311				container_of(itr, struct cs_etm_recording, itr);312	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;313	struct evsel *evsel, *cs_etm_evsel = NULL;314	struct perf_cpu_map *cpus = evlist->core.user_requested_cpus;315	bool privileged = perf_event_paranoid_check(-1);316	int err = 0;317 318	evlist__for_each_entry(evlist, evsel) {319		if (evsel->core.attr.type == cs_etm_pmu->type) {320			if (cs_etm_evsel) {321				pr_err("There may be only one %s event\n",322				       CORESIGHT_ETM_PMU_NAME);323				return -EINVAL;324			}325			cs_etm_evsel = evsel;326		}327	}328 329	/* no need to continue if at least one event of interest was found */330	if (!cs_etm_evsel)331		return 0;332 333	ptr->evlist = evlist;334	ptr->snapshot_mode = opts->auxtrace_snapshot_mode;335 336	if (!record_opts__no_switch_events(opts) &&337	    perf_can_record_switch_events())338		opts->record_switch_events = true;339 340	cs_etm_evsel->needs_auxtrace_mmap = true;341	opts->full_auxtrace = true;342 343	ret = cs_etm_set_sink_attr(cs_etm_pmu, cs_etm_evsel);344	if (ret)345		return ret;346 347	if (opts->use_clockid) {348		pr_err("Cannot use clockid (-k option) with %s\n",349		       CORESIGHT_ETM_PMU_NAME);350		return -EINVAL;351	}352 353	/* we are in snapshot mode */354	if (opts->auxtrace_snapshot_mode) {355		/*356		 * No size were given to '-S' or '-m,', so go with357		 * the default358		 */359		if (!opts->auxtrace_snapshot_size &&360		    !opts->auxtrace_mmap_pages) {361			if (privileged) {362				opts->auxtrace_mmap_pages = MiB(4) / page_size;363			} else {364				opts->auxtrace_mmap_pages =365							KiB(128) / page_size;366				if (opts->mmap_pages == UINT_MAX)367					opts->mmap_pages = KiB(256) / page_size;368			}369		} else if (!opts->auxtrace_mmap_pages && !privileged &&370						opts->mmap_pages == UINT_MAX) {371			opts->mmap_pages = KiB(256) / page_size;372		}373 374		/*375		 * '-m,xyz' was specified but no snapshot size, so make the376		 * snapshot size as big as the auxtrace mmap area.377		 */378		if (!opts->auxtrace_snapshot_size) {379			opts->auxtrace_snapshot_size =380				opts->auxtrace_mmap_pages * (size_t)page_size;381		}382 383		/*384		 * -Sxyz was specified but no auxtrace mmap area, so make the385		 * auxtrace mmap area big enough to fit the requested snapshot386		 * size.387		 */388		if (!opts->auxtrace_mmap_pages) {389			size_t sz = opts->auxtrace_snapshot_size;390 391			sz = round_up(sz, page_size) / page_size;392			opts->auxtrace_mmap_pages = roundup_pow_of_two(sz);393		}394 395		/* Snapshot size can't be bigger than the auxtrace area */396		if (opts->auxtrace_snapshot_size >397				opts->auxtrace_mmap_pages * (size_t)page_size) {398			pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n",399			       opts->auxtrace_snapshot_size,400			       opts->auxtrace_mmap_pages * (size_t)page_size);401			return -EINVAL;402		}403 404		/* Something went wrong somewhere - this shouldn't happen */405		if (!opts->auxtrace_snapshot_size ||406		    !opts->auxtrace_mmap_pages) {407			pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n");408			return -EINVAL;409		}410	}411 412	/* Buffer sizes weren't specified with '-m,xyz' so give some defaults */413	if (!opts->auxtrace_mmap_pages) {414		if (privileged) {415			opts->auxtrace_mmap_pages = MiB(4) / page_size;416		} else {417			opts->auxtrace_mmap_pages = KiB(128) / page_size;418			if (opts->mmap_pages == UINT_MAX)419				opts->mmap_pages = KiB(256) / page_size;420		}421	}422 423	if (opts->auxtrace_snapshot_mode)424		pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME,425			  opts->auxtrace_snapshot_size);426 427	/*428	 * To obtain the auxtrace buffer file descriptor, the auxtrace429	 * event must come first.430	 */431	evlist__to_front(evlist, cs_etm_evsel);432 433	/*434	 * get the CPU on the sample - need it to associate trace ID in the435	 * AUX_OUTPUT_HW_ID event, and the AUX event for per-cpu mmaps.436	 */437	evsel__set_sample_bit(cs_etm_evsel, CPU);438 439	/*440	 * Also the case of per-cpu mmaps, need the contextID in order to be notified441	 * when a context switch happened.442	 */443	if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) {444		evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel,445					   "timestamp", 1);446		evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel,447					   "contextid", 1);448	}449 450	/*451	 * When the option '--timestamp' or '-T' is enabled, the PERF_SAMPLE_TIME452	 * bit is set for all events.  In this case, always enable Arm CoreSight453	 * timestamp tracing.454	 */455	if (opts->sample_time_set)456		evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel,457					   "timestamp", 1);458 459	/* Add dummy event to keep tracking */460	err = parse_event(evlist, "dummy:u");461	if (err)462		goto out;463	evsel = evlist__last(evlist);464	evlist__set_tracking_event(evlist, evsel);465	evsel->core.attr.freq = 0;466	evsel->core.attr.sample_period = 1;467 468	/* In per-cpu case, always need the time of mmap events etc */469	if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus))470		evsel__set_sample_bit(evsel, TIME);471 472	err = cs_etm_validate_config(cs_etm_pmu, cs_etm_evsel);473out:474	return err;475}476 477static u64 cs_etm_get_config(struct auxtrace_record *itr)478{479	u64 config = 0;480	struct cs_etm_recording *ptr =481			container_of(itr, struct cs_etm_recording, itr);482	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;483	struct evlist *evlist = ptr->evlist;484	struct evsel *evsel;485 486	evlist__for_each_entry(evlist, evsel) {487		if (evsel->core.attr.type == cs_etm_pmu->type) {488			/*489			 * Variable perf_event_attr::config is assigned to490			 * ETMv3/PTM.  The bit fields have been made to match491			 * the ETMv3.5 ETRMCR register specification.  See the492			 * PMU_FORMAT_ATTR() declarations in493			 * drivers/hwtracing/coresight/coresight-perf.c for494			 * details.495			 */496			config = evsel->core.attr.config;497			break;498		}499	}500 501	return config;502}503 504#ifndef BIT505#define BIT(N) (1UL << (N))506#endif507 508static u64 cs_etmv4_get_config(struct auxtrace_record *itr)509{510	u64 config = 0;511	u64 config_opts = 0;512 513	/*514	 * The perf event variable config bits represent both515	 * the command line options and register programming516	 * bits in ETMv3/PTM. For ETMv4 we must remap options517	 * to real bits518	 */519	config_opts = cs_etm_get_config(itr);520	if (config_opts & BIT(ETM_OPT_CYCACC))521		config |= BIT(ETM4_CFG_BIT_CYCACC);522	if (config_opts & BIT(ETM_OPT_CTXTID))523		config |= BIT(ETM4_CFG_BIT_CTXTID);524	if (config_opts & BIT(ETM_OPT_TS))525		config |= BIT(ETM4_CFG_BIT_TS);526	if (config_opts & BIT(ETM_OPT_RETSTK))527		config |= BIT(ETM4_CFG_BIT_RETSTK);528	if (config_opts & BIT(ETM_OPT_CTXTID2))529		config |= BIT(ETM4_CFG_BIT_VMID) |530			  BIT(ETM4_CFG_BIT_VMID_OPT);531	if (config_opts & BIT(ETM_OPT_BRANCH_BROADCAST))532		config |= BIT(ETM4_CFG_BIT_BB);533 534	return config;535}536 537static size_t538cs_etm_info_priv_size(struct auxtrace_record *itr,539		      struct evlist *evlist)540{541	int idx;542	int etmv3 = 0, etmv4 = 0, ete = 0;543	struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus;544	struct perf_cpu_map *intersect_cpus;545	struct perf_cpu cpu;546	struct perf_pmu *cs_etm_pmu = cs_etm_get_pmu(itr);547 548	if (!perf_cpu_map__has_any_cpu(event_cpus)) {549		/* cpu map is not "any" CPU , we have specific CPUs to work with */550		struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus();551 552		intersect_cpus = perf_cpu_map__intersect(event_cpus, online_cpus);553		perf_cpu_map__put(online_cpus);554	} else {555		/* Event can be "any" CPU so count all online CPUs. */556		intersect_cpus = perf_cpu_map__new_online_cpus();557	}558	/* Count number of each type of ETM. Don't count if that CPU has CS_NOT_PRESENT. */559	perf_cpu_map__for_each_cpu_skip_any(cpu, idx, intersect_cpus) {560		enum cs_etm_version v = cs_etm_get_version(cs_etm_pmu, cpu);561 562		ete   += v == CS_ETE;563		etmv4 += v == CS_ETMV4;564		etmv3 += v == CS_ETMV3;565	}566	perf_cpu_map__put(intersect_cpus);567 568	return (CS_ETM_HEADER_SIZE +569	       (ete   * CS_ETE_PRIV_SIZE) +570	       (etmv4 * CS_ETMV4_PRIV_SIZE) +571	       (etmv3 * CS_ETMV3_PRIV_SIZE));572}573 574static int cs_etm_get_ro(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path, __u64 *val)575{576	char pmu_path[PATH_MAX];577	int scan;578 579	/* Get RO metadata from sysfs */580	snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu.cpu, path);581 582	scan = perf_pmu__scan_file(pmu, pmu_path, "%llx", val);583	if (scan != 1) {584		pr_err("%s: error reading: %s\n", __func__, pmu_path);585		return -EINVAL;586	}587 588	return 0;589}590 591static int cs_etm_get_ro_signed(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path,592				__u64 *out_val)593{594	char pmu_path[PATH_MAX];595	int scan;596	int val = 0;597 598	/* Get RO metadata from sysfs */599	snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu.cpu, path);600 601	scan = perf_pmu__scan_file(pmu, pmu_path, "%d", &val);602	if (scan != 1) {603		pr_err("%s: error reading: %s\n", __func__, pmu_path);604		return -EINVAL;605	}606 607	*out_val = (__u64) val;608	return 0;609}610 611static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path)612{613	char pmu_path[PATH_MAX];614 615	/* Get RO metadata from sysfs */616	snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu.cpu, path);617 618	return perf_pmu__file_exists(pmu, pmu_path);619}620 621#define TRCDEVARCH_ARCHPART_SHIFT 0622#define TRCDEVARCH_ARCHPART_MASK  GENMASK(11, 0)623#define TRCDEVARCH_ARCHPART(x)    (((x) & TRCDEVARCH_ARCHPART_MASK) >> TRCDEVARCH_ARCHPART_SHIFT)624 625#define TRCDEVARCH_ARCHVER_SHIFT 12626#define TRCDEVARCH_ARCHVER_MASK  GENMASK(15, 12)627#define TRCDEVARCH_ARCHVER(x)    (((x) & TRCDEVARCH_ARCHVER_MASK) >> TRCDEVARCH_ARCHVER_SHIFT)628 629static bool cs_etm_is_ete(struct perf_pmu *cs_etm_pmu, struct perf_cpu cpu)630{631	__u64 trcdevarch;632 633	if (!cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH]))634		return false;635 636	cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH], &trcdevarch);637	/*638	 * ETE if ARCHVER is 5 (ARCHVER is 4 for ETM) and ARCHPART is 0xA13.639	 * See ETM_DEVARCH_ETE_ARCH in coresight-etm4x.h640	 */641	return TRCDEVARCH_ARCHVER(trcdevarch) == 5 && TRCDEVARCH_ARCHPART(trcdevarch) == 0xA13;642}643 644static __u64 cs_etm_get_legacy_trace_id(struct perf_cpu cpu)645{646	/* Wrap at 48 so that invalid trace IDs aren't saved into files. */647	return CORESIGHT_LEGACY_CPU_TRACE_ID(cpu.cpu % 48);648}649 650static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr, struct perf_cpu cpu)651{652	struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr);653	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;654 655	/* Get trace configuration register */656	data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_get_config(itr);657	/* traceID set to legacy version, in case new perf running on older system */658	data[CS_ETMV4_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);659 660	/* Get read-only information from sysFS */661	cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0],662		      &data[CS_ETMV4_TRCIDR0]);663	cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR1],664		      &data[CS_ETMV4_TRCIDR1]);665	cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2],666		      &data[CS_ETMV4_TRCIDR2]);667	cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR8],668		      &data[CS_ETMV4_TRCIDR8]);669	cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCAUTHSTATUS],670		      &data[CS_ETMV4_TRCAUTHSTATUS]);671 672	/* Kernels older than 5.19 may not expose ts_source */673	if (!cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TS_SOURCE]) ||674	    cs_etm_get_ro_signed(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TS_SOURCE],675				 &data[CS_ETMV4_TS_SOURCE])) {676		pr_debug3("[%03d] pmu file 'ts_source' not found. Fallback to safe value (-1)\n",677			  cpu.cpu);678		data[CS_ETMV4_TS_SOURCE] = (__u64) -1;679	}680}681 682static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *itr, struct perf_cpu cpu)683{684	struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr);685	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;686 687	/* Get trace configuration register */688	data[CS_ETE_TRCCONFIGR] = cs_etmv4_get_config(itr);689	/* traceID set to legacy version, in case new perf running on older system */690	data[CS_ETE_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);691 692	/* Get read-only information from sysFS */693	cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCIDR0], &data[CS_ETE_TRCIDR0]);694	cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCIDR1], &data[CS_ETE_TRCIDR1]);695	cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCIDR2], &data[CS_ETE_TRCIDR2]);696	cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCIDR8], &data[CS_ETE_TRCIDR8]);697	cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCAUTHSTATUS],698		      &data[CS_ETE_TRCAUTHSTATUS]);699	/* ETE uses the same registers as ETMv4 plus TRCDEVARCH */700	cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH],701		      &data[CS_ETE_TRCDEVARCH]);702 703	/* Kernels older than 5.19 may not expose ts_source */704	if (!cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TS_SOURCE]) ||705	    cs_etm_get_ro_signed(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TS_SOURCE],706				 &data[CS_ETE_TS_SOURCE])) {707		pr_debug3("[%03d] pmu file 'ts_source' not found. Fallback to safe value (-1)\n",708			  cpu.cpu);709		data[CS_ETE_TS_SOURCE] = (__u64) -1;710	}711}712 713static void cs_etm_get_metadata(struct perf_cpu cpu, u32 *offset,714				struct auxtrace_record *itr,715				struct perf_record_auxtrace_info *info)716{717	u32 increment, nr_trc_params;718	u64 magic;719	struct perf_pmu *cs_etm_pmu = cs_etm_get_pmu(itr);720 721	/* first see what kind of tracer this cpu is affined to */722	switch (cs_etm_get_version(cs_etm_pmu, cpu)) {723	case CS_ETE:724		magic = __perf_cs_ete_magic;725		cs_etm_save_ete_header(&info->priv[*offset], itr, cpu);726 727		/* How much space was used */728		increment = CS_ETE_PRIV_MAX;729		nr_trc_params = CS_ETE_PRIV_MAX - CS_ETM_COMMON_BLK_MAX_V1;730		break;731 732	case CS_ETMV4:733		magic = __perf_cs_etmv4_magic;734		cs_etm_save_etmv4_header(&info->priv[*offset], itr, cpu);735 736		/* How much space was used */737		increment = CS_ETMV4_PRIV_MAX;738		nr_trc_params = CS_ETMV4_PRIV_MAX - CS_ETMV4_TRCCONFIGR;739		break;740 741	case CS_ETMV3:742		magic = __perf_cs_etmv3_magic;743		/* Get configuration register */744		info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);745		/* traceID set to legacy value in case new perf running on old system */746		info->priv[*offset + CS_ETM_ETMTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);747		/* Get read-only information from sysFS */748		cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv3_ro[CS_ETM_ETMCCER],749			      &info->priv[*offset + CS_ETM_ETMCCER]);750		cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv3_ro[CS_ETM_ETMIDR],751			      &info->priv[*offset + CS_ETM_ETMIDR]);752 753		/* How much space was used */754		increment = CS_ETM_PRIV_MAX;755		nr_trc_params = CS_ETM_PRIV_MAX - CS_ETM_ETMCR;756		break;757 758	default:759	case CS_NOT_PRESENT:760		/* Unreachable, CPUs already validated in cs_etm_validate_config() */761		assert(true);762		return;763	}764 765	/* Build generic header portion */766	info->priv[*offset + CS_ETM_MAGIC] = magic;767	info->priv[*offset + CS_ETM_CPU] = cpu.cpu;768	info->priv[*offset + CS_ETM_NR_TRC_PARAMS] = nr_trc_params;769	/* Where the next CPU entry should start from */770	*offset += increment;771}772 773static int cs_etm_info_fill(struct auxtrace_record *itr,774			    struct perf_session *session,775			    struct perf_record_auxtrace_info *info,776			    size_t priv_size)777{778	int i;779	u32 offset;780	u64 nr_cpu, type;781	struct perf_cpu_map *cpu_map;782	struct perf_cpu_map *event_cpus = session->evlist->core.user_requested_cpus;783	struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus();784	struct cs_etm_recording *ptr =785			container_of(itr, struct cs_etm_recording, itr);786	struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;787	struct perf_cpu cpu;788 789	if (priv_size != cs_etm_info_priv_size(itr, session->evlist))790		return -EINVAL;791 792	if (!session->evlist->core.nr_mmaps)793		return -EINVAL;794 795	/* If the cpu_map has the "any" CPU all online CPUs are involved */796	if (perf_cpu_map__has_any_cpu(event_cpus)) {797		cpu_map = online_cpus;798	} else {799		/* Make sure all specified CPUs are online */800		perf_cpu_map__for_each_cpu(cpu, i, event_cpus) {801			if (!perf_cpu_map__has(online_cpus, cpu))802				return -EINVAL;803		}804 805		cpu_map = event_cpus;806	}807 808	nr_cpu = perf_cpu_map__nr(cpu_map);809	/* Get PMU type as dynamically assigned by the core */810	type = cs_etm_pmu->type;811 812	/* First fill out the session header */813	info->type = PERF_AUXTRACE_CS_ETM;814	info->priv[CS_HEADER_VERSION] = CS_HEADER_CURRENT_VERSION;815	info->priv[CS_PMU_TYPE_CPUS] = type << 32;816	info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu;817	info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode;818 819	offset = CS_ETM_SNAPSHOT + 1;820 821	perf_cpu_map__for_each_cpu(cpu, i, cpu_map) {822		assert(offset < priv_size);823		cs_etm_get_metadata(cpu, &offset, itr, info);824	}825 826	perf_cpu_map__put(online_cpus);827 828	return 0;829}830 831static int cs_etm_snapshot_start(struct auxtrace_record *itr)832{833	struct cs_etm_recording *ptr =834			container_of(itr, struct cs_etm_recording, itr);835	struct evsel *evsel;836 837	evlist__for_each_entry(ptr->evlist, evsel) {838		if (evsel->core.attr.type == ptr->cs_etm_pmu->type)839			return evsel__disable(evsel);840	}841	return -EINVAL;842}843 844static int cs_etm_snapshot_finish(struct auxtrace_record *itr)845{846	struct cs_etm_recording *ptr =847			container_of(itr, struct cs_etm_recording, itr);848	struct evsel *evsel;849 850	evlist__for_each_entry(ptr->evlist, evsel) {851		if (evsel->core.attr.type == ptr->cs_etm_pmu->type)852			return evsel__enable(evsel);853	}854	return -EINVAL;855}856 857static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused)858{859	return (((u64) rand() <<  0) & 0x00000000FFFFFFFFull) |860		(((u64) rand() << 32) & 0xFFFFFFFF00000000ull);861}862 863static void cs_etm_recording_free(struct auxtrace_record *itr)864{865	struct cs_etm_recording *ptr =866			container_of(itr, struct cs_etm_recording, itr);867 868	free(ptr);869}870 871struct auxtrace_record *cs_etm_record_init(int *err)872{873	struct perf_pmu *cs_etm_pmu;874	struct cs_etm_recording *ptr;875 876	cs_etm_pmu = perf_pmus__find(CORESIGHT_ETM_PMU_NAME);877 878	if (!cs_etm_pmu) {879		*err = -EINVAL;880		goto out;881	}882 883	ptr = zalloc(sizeof(struct cs_etm_recording));884	if (!ptr) {885		*err = -ENOMEM;886		goto out;887	}888 889	ptr->cs_etm_pmu			= cs_etm_pmu;890	ptr->itr.parse_snapshot_options	= cs_etm_parse_snapshot_options;891	ptr->itr.recording_options	= cs_etm_recording_options;892	ptr->itr.info_priv_size		= cs_etm_info_priv_size;893	ptr->itr.info_fill		= cs_etm_info_fill;894	ptr->itr.snapshot_start		= cs_etm_snapshot_start;895	ptr->itr.snapshot_finish	= cs_etm_snapshot_finish;896	ptr->itr.reference		= cs_etm_reference;897	ptr->itr.free			= cs_etm_recording_free;898	ptr->itr.read_finish		= auxtrace_record__read_finish;899 900	*err = 0;901	return &ptr->itr;902out:903	return NULL;904}905 906/*907 * Set a default config to enable the user changed config tracking mechanism908 * (CFG_CHG and evsel__set_config_if_unset()). If no default is set then user909 * changes aren't tracked.910 */911void912cs_etm_get_default_config(const struct perf_pmu *pmu __maybe_unused,913			  struct perf_event_attr *attr)914{915	attr->sample_period = 1;916}917