18a9fd832SMathieu Poirier // SPDX-License-Identifier: GPL-2.0 2a818c563SMathieu Poirier /* 3a818c563SMathieu Poirier * Copyright(C) 2015 Linaro Limited. All rights reserved. 4a818c563SMathieu Poirier * Author: Mathieu Poirier <mathieu.poirier@linaro.org> 5a818c563SMathieu Poirier */ 6a818c563SMathieu Poirier 7a818c563SMathieu Poirier #include <api/fs/fs.h> 8fa4e819bSMathieu Poirier #include <linux/bits.h> 9a818c563SMathieu Poirier #include <linux/bitops.h> 10afaed6d3SArnaldo Carvalho de Melo #include <linux/compiler.h> 11a818c563SMathieu Poirier #include <linux/coresight-pmu.h> 12a818c563SMathieu Poirier #include <linux/kernel.h> 13a818c563SMathieu Poirier #include <linux/log2.h> 148520a98dSArnaldo Carvalho de Melo #include <linux/string.h> 15a818c563SMathieu Poirier #include <linux/types.h> 167f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 17a818c563SMathieu Poirier 18a818c563SMathieu Poirier #include "cs-etm.h" 19c6613bd4SIan Rogers #include "../../../util/debug.h" 20c6613bd4SIan Rogers #include "../../../util/record.h" 21c6613bd4SIan Rogers #include "../../../util/auxtrace.h" 22c6613bd4SIan Rogers #include "../../../util/cpumap.h" 23c6613bd4SIan Rogers #include "../../../util/event.h" 24c6613bd4SIan Rogers #include "../../../util/evlist.h" 25c6613bd4SIan Rogers #include "../../../util/evsel.h" 26c6613bd4SIan Rogers #include "../../../util/perf_api_probe.h" 27c6613bd4SIan Rogers #include "../../../util/evsel_config.h" 281eaf496eSIan Rogers #include "../../../util/pmus.h" 29c6613bd4SIan Rogers #include "../../../util/cs-etm.h" 3020f2be1dSJiri Olsa #include <internal/lib.h> // page_size 31c6613bd4SIan Rogers #include "../../../util/session.h" 32a818c563SMathieu Poirier 33fa4e819bSMathieu Poirier #include <errno.h> 34a818c563SMathieu Poirier #include <stdlib.h> 357a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h> 36a818c563SMathieu Poirier 37a818c563SMathieu Poirier struct cs_etm_recording { 38a818c563SMathieu Poirier struct auxtrace_record itr; 39a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu; 4063503dbaSJiri Olsa struct evlist *evlist; 41a818c563SMathieu Poirier bool snapshot_mode; 42a818c563SMathieu Poirier size_t snapshot_size; 43a818c563SMathieu Poirier }; 44a818c563SMathieu Poirier 453399ad9aSMathieu Poirier static const char *metadata_etmv3_ro[CS_ETM_PRIV_MAX] = { 463399ad9aSMathieu Poirier [CS_ETM_ETMCCER] = "mgmt/etmccer", 473399ad9aSMathieu Poirier [CS_ETM_ETMIDR] = "mgmt/etmidr", 483399ad9aSMathieu Poirier }; 493399ad9aSMathieu Poirier 5051ba8811SJames Clark static const char * const metadata_etmv4_ro[] = { 513399ad9aSMathieu Poirier [CS_ETMV4_TRCIDR0] = "trcidr/trcidr0", 523399ad9aSMathieu Poirier [CS_ETMV4_TRCIDR1] = "trcidr/trcidr1", 533399ad9aSMathieu Poirier [CS_ETMV4_TRCIDR2] = "trcidr/trcidr2", 543399ad9aSMathieu Poirier [CS_ETMV4_TRCIDR8] = "trcidr/trcidr8", 553399ad9aSMathieu Poirier [CS_ETMV4_TRCAUTHSTATUS] = "mgmt/trcauthstatus", 562e2f7ceeSGerman Gomez [CS_ETMV4_TS_SOURCE] = "ts_source", 57326163c5SGerman Gomez }; 58326163c5SGerman Gomez 59326163c5SGerman Gomez static const char * const metadata_ete_ro[] = { 60326163c5SGerman Gomez [CS_ETE_TRCIDR0] = "trcidr/trcidr0", 61326163c5SGerman Gomez [CS_ETE_TRCIDR1] = "trcidr/trcidr1", 62326163c5SGerman Gomez [CS_ETE_TRCIDR2] = "trcidr/trcidr2", 63326163c5SGerman Gomez [CS_ETE_TRCIDR8] = "trcidr/trcidr8", 64326163c5SGerman Gomez [CS_ETE_TRCAUTHSTATUS] = "mgmt/trcauthstatus", 65326163c5SGerman Gomez [CS_ETE_TRCDEVARCH] = "mgmt/trcdevarch", 662e2f7ceeSGerman Gomez [CS_ETE_TS_SOURCE] = "ts_source", 673399ad9aSMathieu Poirier }; 683399ad9aSMathieu Poirier 69a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu); 7051ba8811SJames Clark static bool cs_etm_is_ete(struct auxtrace_record *itr, int cpu); 71a818c563SMathieu Poirier 7235c51f83SJames Clark static int cs_etm_validate_context_id(struct auxtrace_record *itr, 7332dcd021SJiri Olsa struct evsel *evsel, int cpu) 743399ad9aSMathieu Poirier { 7535c51f83SJames Clark struct cs_etm_recording *ptr = 7635c51f83SJames Clark container_of(itr, struct cs_etm_recording, itr); 7735c51f83SJames Clark struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 783399ad9aSMathieu Poirier char path[PATH_MAX]; 7935c51f83SJames Clark int err; 803399ad9aSMathieu Poirier u32 val; 81bfd431cbSJames Clark u64 contextid = evsel->core.attr.config & 82da6a5afdSIan Rogers (perf_pmu__format_bits(cs_etm_pmu, "contextid") | 83da6a5afdSIan Rogers perf_pmu__format_bits(cs_etm_pmu, "contextid1") | 84da6a5afdSIan Rogers perf_pmu__format_bits(cs_etm_pmu, "contextid2")); 853399ad9aSMathieu Poirier 8635c51f83SJames Clark if (!contextid) 8735c51f83SJames Clark return 0; 883399ad9aSMathieu Poirier 8935c51f83SJames Clark /* Not supported in etmv3 */ 9035c51f83SJames Clark if (!cs_etm_is_etmv4(itr, cpu)) { 9135c51f83SJames Clark pr_err("%s: contextid not supported in ETMv3, disable with %s/contextid=0/\n", 9235c51f83SJames Clark CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME); 9335c51f83SJames Clark return -EINVAL; 9435c51f83SJames Clark } 953399ad9aSMathieu Poirier 96050a0fc4SJames Clark /* Get a handle on TRCIDR2 */ 973399ad9aSMathieu Poirier snprintf(path, PATH_MAX, "cpu%d/%s", 983399ad9aSMathieu Poirier cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); 993399ad9aSMathieu Poirier err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 1003399ad9aSMathieu Poirier 1013399ad9aSMathieu Poirier /* There was a problem reading the file, bailing out */ 1023399ad9aSMathieu Poirier if (err != 1) { 10335c51f83SJames Clark pr_err("%s: can't read file %s\n", CORESIGHT_ETM_PMU_NAME, 10435c51f83SJames Clark path); 10535c51f83SJames Clark return err; 1063399ad9aSMathieu Poirier } 1073399ad9aSMathieu Poirier 10835c51f83SJames Clark if (contextid & 109da6a5afdSIan Rogers perf_pmu__format_bits(cs_etm_pmu, "contextid1")) { 11030cb76aaSSuzuki K Poulose /* 11130cb76aaSSuzuki K Poulose * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID 11230cb76aaSSuzuki K Poulose * tracing is supported: 1133399ad9aSMathieu Poirier * 0b00000 Context ID tracing is not supported. 1143399ad9aSMathieu Poirier * 0b00100 Maximum of 32-bit Context ID size. 1153399ad9aSMathieu Poirier * All other values are reserved. 1163399ad9aSMathieu Poirier */ 117bfd431cbSJames Clark if (BMVAL(val, 5, 9) != 0x4) { 11835c51f83SJames Clark pr_err("%s: CONTEXTIDR_EL1 isn't supported, disable with %s/contextid1=0/\n", 11935c51f83SJames Clark CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME); 12035c51f83SJames Clark return -EINVAL; 1213399ad9aSMathieu Poirier } 12230cb76aaSSuzuki K Poulose } 12330cb76aaSSuzuki K Poulose 12435c51f83SJames Clark if (contextid & 125da6a5afdSIan Rogers perf_pmu__format_bits(cs_etm_pmu, "contextid2")) { 12630cb76aaSSuzuki K Poulose /* 12730cb76aaSSuzuki K Poulose * TRCIDR2.VMIDOPT[30:29] != 0 and 12830cb76aaSSuzuki K Poulose * TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid) 12930cb76aaSSuzuki K Poulose * We can't support CONTEXTIDR in VMID if the size of the 13030cb76aaSSuzuki K Poulose * virtual context id is < 32bit. 13130cb76aaSSuzuki K Poulose * Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us. 13230cb76aaSSuzuki K Poulose */ 13330cb76aaSSuzuki K Poulose if (!BMVAL(val, 29, 30) || BMVAL(val, 10, 14) < 4) { 13435c51f83SJames Clark pr_err("%s: CONTEXTIDR_EL2 isn't supported, disable with %s/contextid2=0/\n", 13535c51f83SJames Clark CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME); 13635c51f83SJames Clark return -EINVAL; 13730cb76aaSSuzuki K Poulose } 13830cb76aaSSuzuki K Poulose } 1393399ad9aSMathieu Poirier 14035c51f83SJames Clark return 0; 1413399ad9aSMathieu Poirier } 1423399ad9aSMathieu Poirier 14335c51f83SJames Clark static int cs_etm_validate_timestamp(struct auxtrace_record *itr, 14432dcd021SJiri Olsa struct evsel *evsel, int cpu) 1451c839a5aSMathieu Poirier { 14635c51f83SJames Clark struct cs_etm_recording *ptr = 14735c51f83SJames Clark container_of(itr, struct cs_etm_recording, itr); 14835c51f83SJames Clark struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 1491c839a5aSMathieu Poirier char path[PATH_MAX]; 15035c51f83SJames Clark int err; 1511c839a5aSMathieu Poirier u32 val; 1521c839a5aSMathieu Poirier 15335c51f83SJames Clark if (!(evsel->core.attr.config & 154da6a5afdSIan Rogers perf_pmu__format_bits(cs_etm_pmu, "timestamp"))) 15535c51f83SJames Clark return 0; 1561c839a5aSMathieu Poirier 15735c51f83SJames Clark if (!cs_etm_is_etmv4(itr, cpu)) { 15835c51f83SJames Clark pr_err("%s: timestamp not supported in ETMv3, disable with %s/timestamp=0/\n", 15935c51f83SJames Clark CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME); 16035c51f83SJames Clark return -EINVAL; 16135c51f83SJames Clark } 1621c839a5aSMathieu Poirier 1631c839a5aSMathieu Poirier /* Get a handle on TRCIRD0 */ 1641c839a5aSMathieu Poirier snprintf(path, PATH_MAX, "cpu%d/%s", 1651c839a5aSMathieu Poirier cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 1661c839a5aSMathieu Poirier err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 1671c839a5aSMathieu Poirier 1681c839a5aSMathieu Poirier /* There was a problem reading the file, bailing out */ 1691c839a5aSMathieu Poirier if (err != 1) { 1701c839a5aSMathieu Poirier pr_err("%s: can't read file %s\n", 1711c839a5aSMathieu Poirier CORESIGHT_ETM_PMU_NAME, path); 17235c51f83SJames Clark return err; 1731c839a5aSMathieu Poirier } 1741c839a5aSMathieu Poirier 1751c839a5aSMathieu Poirier /* 1761c839a5aSMathieu Poirier * TRCIDR0.TSSIZE, bit [28-24], indicates whether global timestamping 1771c839a5aSMathieu Poirier * is supported: 1781c839a5aSMathieu Poirier * 0b00000 Global timestamping is not implemented 1791c839a5aSMathieu Poirier * 0b00110 Implementation supports a maximum timestamp of 48bits. 1801c839a5aSMathieu Poirier * 0b01000 Implementation supports a maximum timestamp of 64bits. 1811c839a5aSMathieu Poirier */ 1821c839a5aSMathieu Poirier val &= GENMASK(28, 24); 1831c839a5aSMathieu Poirier if (!val) { 18435c51f83SJames Clark return -EINVAL; 1851c839a5aSMathieu Poirier } 1861c839a5aSMathieu Poirier 18735c51f83SJames Clark return 0; 1881c839a5aSMathieu Poirier } 1891c839a5aSMathieu Poirier 19035c51f83SJames Clark /* 19135c51f83SJames Clark * Check whether the requested timestamp and contextid options should be 19235c51f83SJames Clark * available on all requested CPUs and if not, tell the user how to override. 19335c51f83SJames Clark * The kernel will silently disable any unavailable options so a warning here 19435c51f83SJames Clark * first is better. In theory the kernel could still disable the option for 19535c51f83SJames Clark * some other reason so this is best effort only. 19635c51f83SJames Clark */ 19735c51f83SJames Clark static int cs_etm_validate_config(struct auxtrace_record *itr, 19835c51f83SJames Clark struct evsel *evsel) 1993399ad9aSMathieu Poirier { 2003399ad9aSMathieu Poirier int i, err = -EINVAL; 2010df6ade7SIan Rogers struct perf_cpu_map *event_cpus = evsel->evlist->core.user_requested_cpus; 202*effe957cSIan Rogers struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus(); 2033399ad9aSMathieu Poirier 2043399ad9aSMathieu Poirier /* Set option of each CPU we have */ 2056d18804bSIan Rogers for (i = 0; i < cpu__max_cpu().cpu; i++) { 2066d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 2076d18804bSIan Rogers 208f8ccc2d5SLeo Yan /* 209f8ccc2d5SLeo Yan * In per-cpu case, do the validation for CPUs to work with. 210f8ccc2d5SLeo Yan * In per-thread case, the CPU map is empty. Since the traced 211f8ccc2d5SLeo Yan * program can run on any CPUs in this case, thus don't skip 212f8ccc2d5SLeo Yan * validation. 213f8ccc2d5SLeo Yan */ 214923ca62aSIan Rogers if (!perf_cpu_map__has_any_cpu_or_is_empty(event_cpus) && 215f8ccc2d5SLeo Yan !perf_cpu_map__has(event_cpus, cpu)) 216f8ccc2d5SLeo Yan continue; 217f8ccc2d5SLeo Yan 218f8ccc2d5SLeo Yan if (!perf_cpu_map__has(online_cpus, cpu)) 2193399ad9aSMathieu Poirier continue; 2203399ad9aSMathieu Poirier 22135c51f83SJames Clark err = cs_etm_validate_context_id(itr, evsel, i); 2223399ad9aSMathieu Poirier if (err) 2233399ad9aSMathieu Poirier goto out; 22435c51f83SJames Clark err = cs_etm_validate_timestamp(itr, evsel, i); 2251c839a5aSMathieu Poirier if (err) 2261c839a5aSMathieu Poirier goto out; 2273399ad9aSMathieu Poirier } 2283399ad9aSMathieu Poirier 2293399ad9aSMathieu Poirier err = 0; 2303399ad9aSMathieu Poirier out: 23138f01d8dSJiri Olsa perf_cpu_map__put(online_cpus); 2323399ad9aSMathieu Poirier return err; 2333399ad9aSMathieu Poirier } 2343399ad9aSMathieu Poirier 235a818c563SMathieu Poirier static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr, 236a818c563SMathieu Poirier struct record_opts *opts, 237a818c563SMathieu Poirier const char *str) 238a818c563SMathieu Poirier { 239a818c563SMathieu Poirier struct cs_etm_recording *ptr = 240a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 241a818c563SMathieu Poirier unsigned long long snapshot_size = 0; 242a818c563SMathieu Poirier char *endptr; 243a818c563SMathieu Poirier 244a818c563SMathieu Poirier if (str) { 245a818c563SMathieu Poirier snapshot_size = strtoull(str, &endptr, 0); 246a818c563SMathieu Poirier if (*endptr || snapshot_size > SIZE_MAX) 247a818c563SMathieu Poirier return -1; 248a818c563SMathieu Poirier } 249a818c563SMathieu Poirier 250a818c563SMathieu Poirier opts->auxtrace_snapshot_mode = true; 251a818c563SMathieu Poirier opts->auxtrace_snapshot_size = snapshot_size; 252a818c563SMathieu Poirier ptr->snapshot_size = snapshot_size; 253a818c563SMathieu Poirier 254a818c563SMathieu Poirier return 0; 255a818c563SMathieu Poirier } 256a818c563SMathieu Poirier 257fa4e819bSMathieu Poirier static int cs_etm_set_sink_attr(struct perf_pmu *pmu, 25832dcd021SJiri Olsa struct evsel *evsel) 259fa4e819bSMathieu Poirier { 260fa4e819bSMathieu Poirier char msg[BUFSIZ], path[PATH_MAX], *sink; 26135ac0cadSArnaldo Carvalho de Melo struct evsel_config_term *term; 262fa4e819bSMathieu Poirier int ret = -EINVAL; 263fa4e819bSMathieu Poirier u32 hash; 264fa4e819bSMathieu Poirier 2651fc632ceSJiri Olsa if (evsel->core.attr.config2 & GENMASK(31, 0)) 266fa4e819bSMathieu Poirier return 0; 267fa4e819bSMathieu Poirier 268fa4e819bSMathieu Poirier list_for_each_entry(term, &evsel->config_terms, list) { 26935ac0cadSArnaldo Carvalho de Melo if (term->type != EVSEL__CONFIG_TERM_DRV_CFG) 270fa4e819bSMathieu Poirier continue; 271fa4e819bSMathieu Poirier 272e884602bSLeo Yan sink = term->val.str; 273fa4e819bSMathieu Poirier snprintf(path, PATH_MAX, "sinks/%s", sink); 274fa4e819bSMathieu Poirier 275fa4e819bSMathieu Poirier ret = perf_pmu__scan_file(pmu, path, "%x", &hash); 276fa4e819bSMathieu Poirier if (ret != 1) { 2776bc75b4cSJames Clark if (errno == ENOENT) 2786bc75b4cSJames Clark pr_err("Couldn't find sink \"%s\" on event %s\n" 2796bc75b4cSJames Clark "Missing kernel or device support?\n\n" 2806bc75b4cSJames Clark "Hint: An appropriate sink will be picked automatically if one isn't specified.\n", 2816bc75b4cSJames Clark sink, evsel__name(evsel)); 2826bc75b4cSJames Clark else 2836bc75b4cSJames Clark pr_err("Failed to set sink \"%s\" on event %s with %d (%s)\n", 2848ab2e96dSArnaldo Carvalho de Melo sink, evsel__name(evsel), errno, 285fa4e819bSMathieu Poirier str_error_r(errno, msg, sizeof(msg))); 286fa4e819bSMathieu Poirier return ret; 287fa4e819bSMathieu Poirier } 288fa4e819bSMathieu Poirier 2891fc632ceSJiri Olsa evsel->core.attr.config2 |= hash; 290fa4e819bSMathieu Poirier return 0; 291fa4e819bSMathieu Poirier } 292fa4e819bSMathieu Poirier 293fa4e819bSMathieu Poirier /* 29447446212SMike Leach * No sink was provided on the command line - allow the CoreSight 29547446212SMike Leach * system to look for a default 296fa4e819bSMathieu Poirier */ 29747446212SMike Leach return 0; 298fa4e819bSMathieu Poirier } 299fa4e819bSMathieu Poirier 300a818c563SMathieu Poirier static int cs_etm_recording_options(struct auxtrace_record *itr, 30163503dbaSJiri Olsa struct evlist *evlist, 302a818c563SMathieu Poirier struct record_opts *opts) 303a818c563SMathieu Poirier { 304fa4e819bSMathieu Poirier int ret; 305a818c563SMathieu Poirier struct cs_etm_recording *ptr = 306a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 307a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 30832dcd021SJiri Olsa struct evsel *evsel, *cs_etm_evsel = NULL; 3090df6ade7SIan Rogers struct perf_cpu_map *cpus = evlist->core.user_requested_cpus; 310dda1bf8eSIgor Lubashev bool privileged = perf_event_paranoid_check(-1); 3113399ad9aSMathieu Poirier int err = 0; 312a818c563SMathieu Poirier 313a818c563SMathieu Poirier evlist__for_each_entry(evlist, evsel) { 3141fc632ceSJiri Olsa if (evsel->core.attr.type == cs_etm_pmu->type) { 315a818c563SMathieu Poirier if (cs_etm_evsel) { 316a818c563SMathieu Poirier pr_err("There may be only one %s event\n", 317a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 318a818c563SMathieu Poirier return -EINVAL; 319a818c563SMathieu Poirier } 320a818c563SMathieu Poirier cs_etm_evsel = evsel; 321a818c563SMathieu Poirier } 322a818c563SMathieu Poirier } 323a818c563SMathieu Poirier 324a818c563SMathieu Poirier /* no need to continue if at least one event of interest was found */ 325a818c563SMathieu Poirier if (!cs_etm_evsel) 326a818c563SMathieu Poirier return 0; 327a818c563SMathieu Poirier 3283963d84bSJames Clark ptr->evlist = evlist; 3293963d84bSJames Clark ptr->snapshot_mode = opts->auxtrace_snapshot_mode; 3303963d84bSJames Clark 3313963d84bSJames Clark if (!record_opts__no_switch_events(opts) && 3323963d84bSJames Clark perf_can_record_switch_events()) 3333963d84bSJames Clark opts->record_switch_events = true; 3343963d84bSJames Clark 3353963d84bSJames Clark cs_etm_evsel->needs_auxtrace_mmap = true; 3363963d84bSJames Clark opts->full_auxtrace = true; 3373963d84bSJames Clark 338fa4e819bSMathieu Poirier ret = cs_etm_set_sink_attr(cs_etm_pmu, cs_etm_evsel); 339fa4e819bSMathieu Poirier if (ret) 340fa4e819bSMathieu Poirier return ret; 341fa4e819bSMathieu Poirier 342a818c563SMathieu Poirier if (opts->use_clockid) { 343a818c563SMathieu Poirier pr_err("Cannot use clockid (-k option) with %s\n", 344a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 345a818c563SMathieu Poirier return -EINVAL; 346a818c563SMathieu Poirier } 347a818c563SMathieu Poirier 348a818c563SMathieu Poirier /* we are in snapshot mode */ 349a818c563SMathieu Poirier if (opts->auxtrace_snapshot_mode) { 350a818c563SMathieu Poirier /* 351a818c563SMathieu Poirier * No size were given to '-S' or '-m,', so go with 352a818c563SMathieu Poirier * the default 353a818c563SMathieu Poirier */ 354a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size && 355a818c563SMathieu Poirier !opts->auxtrace_mmap_pages) { 356a818c563SMathieu Poirier if (privileged) { 357a818c563SMathieu Poirier opts->auxtrace_mmap_pages = MiB(4) / page_size; 358a818c563SMathieu Poirier } else { 359a818c563SMathieu Poirier opts->auxtrace_mmap_pages = 360a818c563SMathieu Poirier KiB(128) / page_size; 361a818c563SMathieu Poirier if (opts->mmap_pages == UINT_MAX) 362a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 363a818c563SMathieu Poirier } 364a818c563SMathieu Poirier } else if (!opts->auxtrace_mmap_pages && !privileged && 365a818c563SMathieu Poirier opts->mmap_pages == UINT_MAX) { 366a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 367a818c563SMathieu Poirier } 368a818c563SMathieu Poirier 369a818c563SMathieu Poirier /* 370a818c563SMathieu Poirier * '-m,xyz' was specified but no snapshot size, so make the 371a818c563SMathieu Poirier * snapshot size as big as the auxtrace mmap area. 372a818c563SMathieu Poirier */ 373a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size) { 374a818c563SMathieu Poirier opts->auxtrace_snapshot_size = 375a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size; 376a818c563SMathieu Poirier } 377a818c563SMathieu Poirier 378a818c563SMathieu Poirier /* 379a818c563SMathieu Poirier * -Sxyz was specified but no auxtrace mmap area, so make the 380a818c563SMathieu Poirier * auxtrace mmap area big enough to fit the requested snapshot 381a818c563SMathieu Poirier * size. 382a818c563SMathieu Poirier */ 383a818c563SMathieu Poirier if (!opts->auxtrace_mmap_pages) { 384a818c563SMathieu Poirier size_t sz = opts->auxtrace_snapshot_size; 385a818c563SMathieu Poirier 386a818c563SMathieu Poirier sz = round_up(sz, page_size) / page_size; 387a818c563SMathieu Poirier opts->auxtrace_mmap_pages = roundup_pow_of_two(sz); 388a818c563SMathieu Poirier } 389a818c563SMathieu Poirier 3904d39c89fSIngo Molnar /* Snapshot size can't be bigger than the auxtrace area */ 391a818c563SMathieu Poirier if (opts->auxtrace_snapshot_size > 392a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size) { 393a818c563SMathieu Poirier pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n", 394a818c563SMathieu Poirier opts->auxtrace_snapshot_size, 395a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size); 396a818c563SMathieu Poirier return -EINVAL; 397a818c563SMathieu Poirier } 398a818c563SMathieu Poirier 399a818c563SMathieu Poirier /* Something went wrong somewhere - this shouldn't happen */ 400a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size || 401a818c563SMathieu Poirier !opts->auxtrace_mmap_pages) { 402a818c563SMathieu Poirier pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n"); 403a818c563SMathieu Poirier return -EINVAL; 404a818c563SMathieu Poirier } 405a818c563SMathieu Poirier } 406a818c563SMathieu Poirier 4073963d84bSJames Clark /* Buffer sizes weren't specified with '-m,xyz' so give some defaults */ 4083963d84bSJames Clark if (!opts->auxtrace_mmap_pages) { 409a818c563SMathieu Poirier if (privileged) { 410a818c563SMathieu Poirier opts->auxtrace_mmap_pages = MiB(4) / page_size; 411a818c563SMathieu Poirier } else { 412a818c563SMathieu Poirier opts->auxtrace_mmap_pages = KiB(128) / page_size; 413a818c563SMathieu Poirier if (opts->mmap_pages == UINT_MAX) 414a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 415a818c563SMathieu Poirier } 416a818c563SMathieu Poirier } 417a818c563SMathieu Poirier 418a818c563SMathieu Poirier if (opts->auxtrace_snapshot_mode) 419a818c563SMathieu Poirier pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME, 420a818c563SMathieu Poirier opts->auxtrace_snapshot_size); 421a818c563SMathieu Poirier 422a818c563SMathieu Poirier /* 423a818c563SMathieu Poirier * To obtain the auxtrace buffer file descriptor, the auxtrace 424a818c563SMathieu Poirier * event must come first. 425a818c563SMathieu Poirier */ 426e414fd1aSArnaldo Carvalho de Melo evlist__to_front(evlist, cs_etm_evsel); 4270c788d47SKim Phillips 428a818c563SMathieu Poirier /* 429e5fa5b41SMike Leach * get the CPU on the sample - need it to associate trace ID in the 430e5fa5b41SMike Leach * AUX_OUTPUT_HW_ID event, and the AUX event for per-cpu mmaps. 431e5fa5b41SMike Leach */ 432e5fa5b41SMike Leach evsel__set_sample_bit(cs_etm_evsel, CPU); 433e5fa5b41SMike Leach 434e5fa5b41SMike Leach /* 435e5fa5b41SMike Leach * Also the case of per-cpu mmaps, need the contextID in order to be notified 4363399ad9aSMathieu Poirier * when a context switch happened. 437a818c563SMathieu Poirier */ 438923ca62aSIan Rogers if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) { 4397bfc1544SJames Clark evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel, 4407bfc1544SJames Clark "timestamp", 1); 4417bfc1544SJames Clark evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel, 4427bfc1544SJames Clark "contextid", 1); 4433399ad9aSMathieu Poirier } 4443399ad9aSMathieu Poirier 44578efa7b4SLeo Yan /* 44678efa7b4SLeo Yan * When the option '--timestamp' or '-T' is enabled, the PERF_SAMPLE_TIME 44778efa7b4SLeo Yan * bit is set for all events. In this case, always enable Arm CoreSight 44878efa7b4SLeo Yan * timestamp tracing. 44978efa7b4SLeo Yan */ 45078efa7b4SLeo Yan if (opts->sample_time_set) 45178efa7b4SLeo Yan evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel, 45278efa7b4SLeo Yan "timestamp", 1); 45378efa7b4SLeo Yan 454a818c563SMathieu Poirier /* Add dummy event to keep tracking */ 455806731a9SAdrian Hunter err = parse_event(evlist, "dummy:u"); 456a818c563SMathieu Poirier if (err) 4573399ad9aSMathieu Poirier goto out; 4583963d84bSJames Clark evsel = evlist__last(evlist); 4593963d84bSJames Clark evlist__set_tracking_event(evlist, evsel); 4603963d84bSJames Clark evsel->core.attr.freq = 0; 4613963d84bSJames Clark evsel->core.attr.sample_period = 1; 462a818c563SMathieu Poirier 463a818c563SMathieu Poirier /* In per-cpu case, always need the time of mmap events etc */ 464923ca62aSIan Rogers if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) 4653963d84bSJames Clark evsel__set_sample_bit(evsel, TIME); 466a818c563SMathieu Poirier 46735c51f83SJames Clark err = cs_etm_validate_config(itr, cs_etm_evsel); 4683399ad9aSMathieu Poirier out: 4693399ad9aSMathieu Poirier return err; 470a818c563SMathieu Poirier } 471a818c563SMathieu Poirier 472a818c563SMathieu Poirier static u64 cs_etm_get_config(struct auxtrace_record *itr) 473a818c563SMathieu Poirier { 474a818c563SMathieu Poirier u64 config = 0; 475a818c563SMathieu Poirier struct cs_etm_recording *ptr = 476a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 477a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 47863503dbaSJiri Olsa struct evlist *evlist = ptr->evlist; 47932dcd021SJiri Olsa struct evsel *evsel; 480a818c563SMathieu Poirier 481a818c563SMathieu Poirier evlist__for_each_entry(evlist, evsel) { 4821fc632ceSJiri Olsa if (evsel->core.attr.type == cs_etm_pmu->type) { 483a818c563SMathieu Poirier /* 484a818c563SMathieu Poirier * Variable perf_event_attr::config is assigned to 485a818c563SMathieu Poirier * ETMv3/PTM. The bit fields have been made to match 486a818c563SMathieu Poirier * the ETMv3.5 ETRMCR register specification. See the 487a818c563SMathieu Poirier * PMU_FORMAT_ATTR() declarations in 488a818c563SMathieu Poirier * drivers/hwtracing/coresight/coresight-perf.c for 489a818c563SMathieu Poirier * details. 490a818c563SMathieu Poirier */ 4911fc632ceSJiri Olsa config = evsel->core.attr.config; 492a818c563SMathieu Poirier break; 493a818c563SMathieu Poirier } 494a818c563SMathieu Poirier } 495a818c563SMathieu Poirier 496a818c563SMathieu Poirier return config; 497a818c563SMathieu Poirier } 498a818c563SMathieu Poirier 499df770ff0SMike Leach #ifndef BIT 500df770ff0SMike Leach #define BIT(N) (1UL << (N)) 501df770ff0SMike Leach #endif 502df770ff0SMike Leach 503df770ff0SMike Leach static u64 cs_etmv4_get_config(struct auxtrace_record *itr) 504df770ff0SMike Leach { 505df770ff0SMike Leach u64 config = 0; 506df770ff0SMike Leach u64 config_opts = 0; 507df770ff0SMike Leach 508df770ff0SMike Leach /* 509df770ff0SMike Leach * The perf event variable config bits represent both 510df770ff0SMike Leach * the command line options and register programming 511df770ff0SMike Leach * bits in ETMv3/PTM. For ETMv4 we must remap options 512df770ff0SMike Leach * to real bits 513df770ff0SMike Leach */ 514df770ff0SMike Leach config_opts = cs_etm_get_config(itr); 515df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_CYCACC)) 516df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_CYCACC); 5173399ad9aSMathieu Poirier if (config_opts & BIT(ETM_OPT_CTXTID)) 5183399ad9aSMathieu Poirier config |= BIT(ETM4_CFG_BIT_CTXTID); 519df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_TS)) 520df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_TS); 521df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_RETSTK)) 522df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_RETSTK); 52330cb76aaSSuzuki K Poulose if (config_opts & BIT(ETM_OPT_CTXTID2)) 52430cb76aaSSuzuki K Poulose config |= BIT(ETM4_CFG_BIT_VMID) | 52530cb76aaSSuzuki K Poulose BIT(ETM4_CFG_BIT_VMID_OPT); 526aca8af3cSJames Clark if (config_opts & BIT(ETM_OPT_BRANCH_BROADCAST)) 527aca8af3cSJames Clark config |= BIT(ETM4_CFG_BIT_BB); 528aca8af3cSJames Clark 529df770ff0SMike Leach return config; 530df770ff0SMike Leach } 531df770ff0SMike Leach 532a818c563SMathieu Poirier static size_t 533a818c563SMathieu Poirier cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, 53463503dbaSJiri Olsa struct evlist *evlist __maybe_unused) 535a818c563SMathieu Poirier { 536a818c563SMathieu Poirier int i; 53751ba8811SJames Clark int etmv3 = 0, etmv4 = 0, ete = 0; 5380df6ade7SIan Rogers struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus; 539*effe957cSIan Rogers struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus(); 540a818c563SMathieu Poirier 541a818c563SMathieu Poirier /* cpu map is not empty, we have specific CPUs to work with */ 542923ca62aSIan Rogers if (!perf_cpu_map__has_any_cpu_or_is_empty(event_cpus)) { 5436d18804bSIan Rogers for (i = 0; i < cpu__max_cpu().cpu; i++) { 5446d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 5456d18804bSIan Rogers 5466d18804bSIan Rogers if (!perf_cpu_map__has(event_cpus, cpu) || 5476d18804bSIan Rogers !perf_cpu_map__has(online_cpus, cpu)) 548796bfaddSMathieu Poirier continue; 549796bfaddSMathieu Poirier 55051ba8811SJames Clark if (cs_etm_is_ete(itr, i)) 55151ba8811SJames Clark ete++; 55251ba8811SJames Clark else if (cs_etm_is_etmv4(itr, i)) 553a818c563SMathieu Poirier etmv4++; 554a818c563SMathieu Poirier else 555a818c563SMathieu Poirier etmv3++; 556a818c563SMathieu Poirier } 557a818c563SMathieu Poirier } else { 558a818c563SMathieu Poirier /* get configuration for all CPUs in the system */ 5596d18804bSIan Rogers for (i = 0; i < cpu__max_cpu().cpu; i++) { 5606d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 5616d18804bSIan Rogers 5626d18804bSIan Rogers if (!perf_cpu_map__has(online_cpus, cpu)) 563796bfaddSMathieu Poirier continue; 564796bfaddSMathieu Poirier 56551ba8811SJames Clark if (cs_etm_is_ete(itr, i)) 56651ba8811SJames Clark ete++; 56751ba8811SJames Clark else if (cs_etm_is_etmv4(itr, i)) 568a818c563SMathieu Poirier etmv4++; 569a818c563SMathieu Poirier else 570a818c563SMathieu Poirier etmv3++; 571a818c563SMathieu Poirier } 572a818c563SMathieu Poirier } 573a818c563SMathieu Poirier 57438f01d8dSJiri Olsa perf_cpu_map__put(online_cpus); 575796bfaddSMathieu Poirier 576a818c563SMathieu Poirier return (CS_ETM_HEADER_SIZE + 57751ba8811SJames Clark (ete * CS_ETE_PRIV_SIZE) + 578a818c563SMathieu Poirier (etmv4 * CS_ETMV4_PRIV_SIZE) + 579a818c563SMathieu Poirier (etmv3 * CS_ETMV3_PRIV_SIZE)); 580a818c563SMathieu Poirier } 581a818c563SMathieu Poirier 582a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu) 583a818c563SMathieu Poirier { 584a818c563SMathieu Poirier bool ret = false; 585a818c563SMathieu Poirier char path[PATH_MAX]; 586a818c563SMathieu Poirier int scan; 587a818c563SMathieu Poirier unsigned int val; 588a818c563SMathieu Poirier struct cs_etm_recording *ptr = 589a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 590a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 591a818c563SMathieu Poirier 592a818c563SMathieu Poirier /* Take any of the RO files for ETMv4 and see if it present */ 593a818c563SMathieu Poirier snprintf(path, PATH_MAX, "cpu%d/%s", 594a818c563SMathieu Poirier cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 595a818c563SMathieu Poirier scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 596a818c563SMathieu Poirier 597a818c563SMathieu Poirier /* The file was read successfully, we have a winner */ 598a818c563SMathieu Poirier if (scan == 1) 599a818c563SMathieu Poirier ret = true; 600a818c563SMathieu Poirier 601a818c563SMathieu Poirier return ret; 602a818c563SMathieu Poirier } 603a818c563SMathieu Poirier 604a818c563SMathieu Poirier static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path) 605a818c563SMathieu Poirier { 606a818c563SMathieu Poirier char pmu_path[PATH_MAX]; 607a818c563SMathieu Poirier int scan; 608a818c563SMathieu Poirier unsigned int val = 0; 609a818c563SMathieu Poirier 610a818c563SMathieu Poirier /* Get RO metadata from sysfs */ 611a818c563SMathieu Poirier snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 612a818c563SMathieu Poirier 613a818c563SMathieu Poirier scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val); 614a818c563SMathieu Poirier if (scan != 1) 615a818c563SMathieu Poirier pr_err("%s: error reading: %s\n", __func__, pmu_path); 616a818c563SMathieu Poirier 617a818c563SMathieu Poirier return val; 618a818c563SMathieu Poirier } 619a818c563SMathieu Poirier 6202e2f7ceeSGerman Gomez static int cs_etm_get_ro_signed(struct perf_pmu *pmu, int cpu, const char *path) 6212e2f7ceeSGerman Gomez { 6222e2f7ceeSGerman Gomez char pmu_path[PATH_MAX]; 6232e2f7ceeSGerman Gomez int scan; 6242e2f7ceeSGerman Gomez int val = 0; 6252e2f7ceeSGerman Gomez 6262e2f7ceeSGerman Gomez /* Get RO metadata from sysfs */ 6272e2f7ceeSGerman Gomez snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 6282e2f7ceeSGerman Gomez 6292e2f7ceeSGerman Gomez scan = perf_pmu__scan_file(pmu, pmu_path, "%d", &val); 6302e2f7ceeSGerman Gomez if (scan != 1) 6312e2f7ceeSGerman Gomez pr_err("%s: error reading: %s\n", __func__, pmu_path); 6322e2f7ceeSGerman Gomez 6332e2f7ceeSGerman Gomez return val; 6342e2f7ceeSGerman Gomez } 6352e2f7ceeSGerman Gomez 6362e2f7ceeSGerman Gomez static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, int cpu, const char *path) 6372e2f7ceeSGerman Gomez { 6382e2f7ceeSGerman Gomez char pmu_path[PATH_MAX]; 6392e2f7ceeSGerman Gomez 6402e2f7ceeSGerman Gomez /* Get RO metadata from sysfs */ 6412e2f7ceeSGerman Gomez snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 6422e2f7ceeSGerman Gomez 6432e2f7ceeSGerman Gomez return perf_pmu__file_exists(pmu, pmu_path); 6442e2f7ceeSGerman Gomez } 6452e2f7ceeSGerman Gomez 64651ba8811SJames Clark #define TRCDEVARCH_ARCHPART_SHIFT 0 64751ba8811SJames Clark #define TRCDEVARCH_ARCHPART_MASK GENMASK(11, 0) 64851ba8811SJames Clark #define TRCDEVARCH_ARCHPART(x) (((x) & TRCDEVARCH_ARCHPART_MASK) >> TRCDEVARCH_ARCHPART_SHIFT) 64951ba8811SJames Clark 65051ba8811SJames Clark #define TRCDEVARCH_ARCHVER_SHIFT 12 65151ba8811SJames Clark #define TRCDEVARCH_ARCHVER_MASK GENMASK(15, 12) 65251ba8811SJames Clark #define TRCDEVARCH_ARCHVER(x) (((x) & TRCDEVARCH_ARCHVER_MASK) >> TRCDEVARCH_ARCHVER_SHIFT) 65351ba8811SJames Clark 65451ba8811SJames Clark static bool cs_etm_is_ete(struct auxtrace_record *itr, int cpu) 65551ba8811SJames Clark { 65651ba8811SJames Clark struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); 65751ba8811SJames Clark struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 658e5af1397SJames Clark int trcdevarch; 65951ba8811SJames Clark 660e5af1397SJames Clark if (!cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH])) 661e5af1397SJames Clark return false; 662e5af1397SJames Clark 663e5af1397SJames Clark trcdevarch = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH]); 66451ba8811SJames Clark /* 66551ba8811SJames Clark * ETE if ARCHVER is 5 (ARCHVER is 4 for ETM) and ARCHPART is 0xA13. 66651ba8811SJames Clark * See ETM_DEVARCH_ETE_ARCH in coresight-etm4x.h 66751ba8811SJames Clark */ 66851ba8811SJames Clark return TRCDEVARCH_ARCHVER(trcdevarch) == 5 && TRCDEVARCH_ARCHPART(trcdevarch) == 0xA13; 66951ba8811SJames Clark } 67051ba8811SJames Clark 671c9ccc96bSJames Clark static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr, int cpu) 672c9ccc96bSJames Clark { 673c9ccc96bSJames Clark struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); 674c9ccc96bSJames Clark struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 675c9ccc96bSJames Clark 676c9ccc96bSJames Clark /* Get trace configuration register */ 677c9ccc96bSJames Clark data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_get_config(itr); 678e5fa5b41SMike Leach /* traceID set to legacy version, in case new perf running on older system */ 679e5fa5b41SMike Leach data[CS_ETMV4_TRCTRACEIDR] = 680e5fa5b41SMike Leach CORESIGHT_LEGACY_CPU_TRACE_ID(cpu) | CORESIGHT_TRACE_ID_UNUSED_FLAG; 681e5fa5b41SMike Leach 682c9ccc96bSJames Clark /* Get read-only information from sysFS */ 683c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR0] = cs_etm_get_ro(cs_etm_pmu, cpu, 684c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 685c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR1] = cs_etm_get_ro(cs_etm_pmu, cpu, 686c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR1]); 687c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR2] = cs_etm_get_ro(cs_etm_pmu, cpu, 688c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); 689c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR8] = cs_etm_get_ro(cs_etm_pmu, cpu, 690c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR8]); 691c9ccc96bSJames Clark data[CS_ETMV4_TRCAUTHSTATUS] = cs_etm_get_ro(cs_etm_pmu, cpu, 692c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCAUTHSTATUS]); 6932e2f7ceeSGerman Gomez 6942e2f7ceeSGerman Gomez /* Kernels older than 5.19 may not expose ts_source */ 6952e2f7ceeSGerman Gomez if (cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TS_SOURCE])) 6962e2f7ceeSGerman Gomez data[CS_ETMV4_TS_SOURCE] = (__u64) cs_etm_get_ro_signed(cs_etm_pmu, cpu, 6972e2f7ceeSGerman Gomez metadata_etmv4_ro[CS_ETMV4_TS_SOURCE]); 6982e2f7ceeSGerman Gomez else { 6995f968d28SJames Clark pr_debug3("[%03d] pmu file 'ts_source' not found. Fallback to safe value (-1)\n", 7002e2f7ceeSGerman Gomez cpu); 7012e2f7ceeSGerman Gomez data[CS_ETMV4_TS_SOURCE] = (__u64) -1; 7022e2f7ceeSGerman Gomez } 703c9ccc96bSJames Clark } 704c9ccc96bSJames Clark 705326163c5SGerman Gomez static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *itr, int cpu) 706326163c5SGerman Gomez { 707326163c5SGerman Gomez struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); 708326163c5SGerman Gomez struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 709326163c5SGerman Gomez 710326163c5SGerman Gomez /* Get trace configuration register */ 711326163c5SGerman Gomez data[CS_ETE_TRCCONFIGR] = cs_etmv4_get_config(itr); 712e5fa5b41SMike Leach /* traceID set to legacy version, in case new perf running on older system */ 713e5fa5b41SMike Leach data[CS_ETE_TRCTRACEIDR] = 714e5fa5b41SMike Leach CORESIGHT_LEGACY_CPU_TRACE_ID(cpu) | CORESIGHT_TRACE_ID_UNUSED_FLAG; 715e5fa5b41SMike Leach 716326163c5SGerman Gomez /* Get read-only information from sysFS */ 717326163c5SGerman Gomez data[CS_ETE_TRCIDR0] = cs_etm_get_ro(cs_etm_pmu, cpu, 718326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCIDR0]); 719326163c5SGerman Gomez data[CS_ETE_TRCIDR1] = cs_etm_get_ro(cs_etm_pmu, cpu, 720326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCIDR1]); 721326163c5SGerman Gomez data[CS_ETE_TRCIDR2] = cs_etm_get_ro(cs_etm_pmu, cpu, 722326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCIDR2]); 723326163c5SGerman Gomez data[CS_ETE_TRCIDR8] = cs_etm_get_ro(cs_etm_pmu, cpu, 724326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCIDR8]); 725326163c5SGerman Gomez data[CS_ETE_TRCAUTHSTATUS] = cs_etm_get_ro(cs_etm_pmu, cpu, 726326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCAUTHSTATUS]); 727326163c5SGerman Gomez /* ETE uses the same registers as ETMv4 plus TRCDEVARCH */ 728326163c5SGerman Gomez data[CS_ETE_TRCDEVARCH] = cs_etm_get_ro(cs_etm_pmu, cpu, 729326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCDEVARCH]); 7302e2f7ceeSGerman Gomez 7312e2f7ceeSGerman Gomez /* Kernels older than 5.19 may not expose ts_source */ 7322e2f7ceeSGerman Gomez if (cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TS_SOURCE])) 7332e2f7ceeSGerman Gomez data[CS_ETE_TS_SOURCE] = (__u64) cs_etm_get_ro_signed(cs_etm_pmu, cpu, 7342e2f7ceeSGerman Gomez metadata_ete_ro[CS_ETE_TS_SOURCE]); 7352e2f7ceeSGerman Gomez else { 7365f968d28SJames Clark pr_debug3("[%03d] pmu file 'ts_source' not found. Fallback to safe value (-1)\n", 7372e2f7ceeSGerman Gomez cpu); 7382e2f7ceeSGerman Gomez data[CS_ETE_TS_SOURCE] = (__u64) -1; 7392e2f7ceeSGerman Gomez } 740326163c5SGerman Gomez } 741326163c5SGerman Gomez 742a818c563SMathieu Poirier static void cs_etm_get_metadata(int cpu, u32 *offset, 743a818c563SMathieu Poirier struct auxtrace_record *itr, 74472932371SJiri Olsa struct perf_record_auxtrace_info *info) 745a818c563SMathieu Poirier { 74642b2b570SMike Leach u32 increment, nr_trc_params; 747a818c563SMathieu Poirier u64 magic; 748a818c563SMathieu Poirier struct cs_etm_recording *ptr = 749a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 750a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 751a818c563SMathieu Poirier 752a818c563SMathieu Poirier /* first see what kind of tracer this cpu is affined to */ 75351ba8811SJames Clark if (cs_etm_is_ete(itr, cpu)) { 75451ba8811SJames Clark magic = __perf_cs_ete_magic; 755326163c5SGerman Gomez cs_etm_save_ete_header(&info->priv[*offset], itr, cpu); 75651ba8811SJames Clark 75751ba8811SJames Clark /* How much space was used */ 75851ba8811SJames Clark increment = CS_ETE_PRIV_MAX; 75951ba8811SJames Clark nr_trc_params = CS_ETE_PRIV_MAX - CS_ETM_COMMON_BLK_MAX_V1; 76051ba8811SJames Clark } else if (cs_etm_is_etmv4(itr, cpu)) { 761a818c563SMathieu Poirier magic = __perf_cs_etmv4_magic; 762c9ccc96bSJames Clark cs_etm_save_etmv4_header(&info->priv[*offset], itr, cpu); 763a818c563SMathieu Poirier 764a818c563SMathieu Poirier /* How much space was used */ 765a818c563SMathieu Poirier increment = CS_ETMV4_PRIV_MAX; 76642b2b570SMike Leach nr_trc_params = CS_ETMV4_PRIV_MAX - CS_ETMV4_TRCCONFIGR; 767a818c563SMathieu Poirier } else { 768a818c563SMathieu Poirier magic = __perf_cs_etmv3_magic; 769a818c563SMathieu Poirier /* Get configuration register */ 770a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr); 771e5fa5b41SMike Leach /* traceID set to legacy value in case new perf running on old system */ 772a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMTRACEIDR] = 773e5fa5b41SMike Leach CORESIGHT_LEGACY_CPU_TRACE_ID(cpu) | CORESIGHT_TRACE_ID_UNUSED_FLAG; 774a818c563SMathieu Poirier /* Get read-only information from sysFS */ 775a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMCCER] = 776a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 777a818c563SMathieu Poirier metadata_etmv3_ro[CS_ETM_ETMCCER]); 778a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMIDR] = 779a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 780a818c563SMathieu Poirier metadata_etmv3_ro[CS_ETM_ETMIDR]); 781a818c563SMathieu Poirier 782a818c563SMathieu Poirier /* How much space was used */ 783a818c563SMathieu Poirier increment = CS_ETM_PRIV_MAX; 78442b2b570SMike Leach nr_trc_params = CS_ETM_PRIV_MAX - CS_ETM_ETMCR; 785a818c563SMathieu Poirier } 786a818c563SMathieu Poirier 787a818c563SMathieu Poirier /* Build generic header portion */ 788a818c563SMathieu Poirier info->priv[*offset + CS_ETM_MAGIC] = magic; 789a818c563SMathieu Poirier info->priv[*offset + CS_ETM_CPU] = cpu; 79042b2b570SMike Leach info->priv[*offset + CS_ETM_NR_TRC_PARAMS] = nr_trc_params; 791a818c563SMathieu Poirier /* Where the next CPU entry should start from */ 792a818c563SMathieu Poirier *offset += increment; 793a818c563SMathieu Poirier } 794a818c563SMathieu Poirier 795a818c563SMathieu Poirier static int cs_etm_info_fill(struct auxtrace_record *itr, 796a818c563SMathieu Poirier struct perf_session *session, 79772932371SJiri Olsa struct perf_record_auxtrace_info *info, 798a818c563SMathieu Poirier size_t priv_size) 799a818c563SMathieu Poirier { 800a818c563SMathieu Poirier int i; 801a818c563SMathieu Poirier u32 offset; 802a818c563SMathieu Poirier u64 nr_cpu, type; 803f854839bSJiri Olsa struct perf_cpu_map *cpu_map; 8040df6ade7SIan Rogers struct perf_cpu_map *event_cpus = session->evlist->core.user_requested_cpus; 805*effe957cSIan Rogers struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus(); 806a818c563SMathieu Poirier struct cs_etm_recording *ptr = 807a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 808a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 809a818c563SMathieu Poirier 810a818c563SMathieu Poirier if (priv_size != cs_etm_info_priv_size(itr, session->evlist)) 811a818c563SMathieu Poirier return -EINVAL; 812a818c563SMathieu Poirier 813c976ee11SJiri Olsa if (!session->evlist->core.nr_mmaps) 814a818c563SMathieu Poirier return -EINVAL; 815a818c563SMathieu Poirier 816796bfaddSMathieu Poirier /* If the cpu_map is empty all online CPUs are involved */ 817923ca62aSIan Rogers if (perf_cpu_map__has_any_cpu_or_is_empty(event_cpus)) { 818796bfaddSMathieu Poirier cpu_map = online_cpus; 819796bfaddSMathieu Poirier } else { 820796bfaddSMathieu Poirier /* Make sure all specified CPUs are online */ 8216549cd8fSJiri Olsa for (i = 0; i < perf_cpu_map__nr(event_cpus); i++) { 8226d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 8236d18804bSIan Rogers 8246d18804bSIan Rogers if (perf_cpu_map__has(event_cpus, cpu) && 8256d18804bSIan Rogers !perf_cpu_map__has(online_cpus, cpu)) 826796bfaddSMathieu Poirier return -EINVAL; 827796bfaddSMathieu Poirier } 828796bfaddSMathieu Poirier 829796bfaddSMathieu Poirier cpu_map = event_cpus; 830796bfaddSMathieu Poirier } 831796bfaddSMathieu Poirier 8326549cd8fSJiri Olsa nr_cpu = perf_cpu_map__nr(cpu_map); 833a818c563SMathieu Poirier /* Get PMU type as dynamically assigned by the core */ 834a818c563SMathieu Poirier type = cs_etm_pmu->type; 835a818c563SMathieu Poirier 836a818c563SMathieu Poirier /* First fill out the session header */ 837a818c563SMathieu Poirier info->type = PERF_AUXTRACE_CS_ETM; 83842b2b570SMike Leach info->priv[CS_HEADER_VERSION] = CS_HEADER_CURRENT_VERSION; 839a818c563SMathieu Poirier info->priv[CS_PMU_TYPE_CPUS] = type << 32; 840a818c563SMathieu Poirier info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu; 841a818c563SMathieu Poirier info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode; 842a818c563SMathieu Poirier 843a818c563SMathieu Poirier offset = CS_ETM_SNAPSHOT + 1; 844a818c563SMathieu Poirier 8456d18804bSIan Rogers for (i = 0; i < cpu__max_cpu().cpu && offset < priv_size; i++) { 8466d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 8476d18804bSIan Rogers 8486d18804bSIan Rogers if (perf_cpu_map__has(cpu_map, cpu)) 849a818c563SMathieu Poirier cs_etm_get_metadata(i, &offset, itr, info); 8506d18804bSIan Rogers } 851796bfaddSMathieu Poirier 85238f01d8dSJiri Olsa perf_cpu_map__put(online_cpus); 853a818c563SMathieu Poirier 854a818c563SMathieu Poirier return 0; 855a818c563SMathieu Poirier } 856a818c563SMathieu Poirier 857a818c563SMathieu Poirier static int cs_etm_snapshot_start(struct auxtrace_record *itr) 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) 8659a10bb22SJiri Olsa return evsel__disable(evsel); 866a818c563SMathieu Poirier } 867a818c563SMathieu Poirier return -EINVAL; 868a818c563SMathieu Poirier } 869a818c563SMathieu Poirier 870a818c563SMathieu Poirier static int cs_etm_snapshot_finish(struct auxtrace_record *itr) 871a818c563SMathieu Poirier { 872a818c563SMathieu Poirier struct cs_etm_recording *ptr = 873a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 87432dcd021SJiri Olsa struct evsel *evsel; 875a818c563SMathieu Poirier 876a818c563SMathieu Poirier evlist__for_each_entry(ptr->evlist, evsel) { 8771fc632ceSJiri Olsa if (evsel->core.attr.type == ptr->cs_etm_pmu->type) 878ec7f24efSJiri Olsa return evsel__enable(evsel); 879a818c563SMathieu Poirier } 880a818c563SMathieu Poirier return -EINVAL; 881a818c563SMathieu Poirier } 882a818c563SMathieu Poirier 883a818c563SMathieu Poirier static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused) 884a818c563SMathieu Poirier { 885a818c563SMathieu Poirier return (((u64) rand() << 0) & 0x00000000FFFFFFFFull) | 886a818c563SMathieu Poirier (((u64) rand() << 32) & 0xFFFFFFFF00000000ull); 887a818c563SMathieu Poirier } 888a818c563SMathieu Poirier 889a818c563SMathieu Poirier static void cs_etm_recording_free(struct auxtrace_record *itr) 890a818c563SMathieu Poirier { 891a818c563SMathieu Poirier struct cs_etm_recording *ptr = 892a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 893e45c48a9SMathieu Poirier 894a818c563SMathieu Poirier free(ptr); 895a818c563SMathieu Poirier } 896a818c563SMathieu Poirier 897a818c563SMathieu Poirier struct auxtrace_record *cs_etm_record_init(int *err) 898a818c563SMathieu Poirier { 899a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu; 900a818c563SMathieu Poirier struct cs_etm_recording *ptr; 901a818c563SMathieu Poirier 9021eaf496eSIan Rogers cs_etm_pmu = perf_pmus__find(CORESIGHT_ETM_PMU_NAME); 903a818c563SMathieu Poirier 904a818c563SMathieu Poirier if (!cs_etm_pmu) { 905a818c563SMathieu Poirier *err = -EINVAL; 906a818c563SMathieu Poirier goto out; 907a818c563SMathieu Poirier } 908a818c563SMathieu Poirier 909a818c563SMathieu Poirier ptr = zalloc(sizeof(struct cs_etm_recording)); 910a818c563SMathieu Poirier if (!ptr) { 911a818c563SMathieu Poirier *err = -ENOMEM; 912a818c563SMathieu Poirier goto out; 913a818c563SMathieu Poirier } 914a818c563SMathieu Poirier 915a818c563SMathieu Poirier ptr->cs_etm_pmu = cs_etm_pmu; 916ad60ba0cSAdrian Hunter ptr->itr.pmu = cs_etm_pmu; 917a818c563SMathieu Poirier ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options; 918a818c563SMathieu Poirier ptr->itr.recording_options = cs_etm_recording_options; 919a818c563SMathieu Poirier ptr->itr.info_priv_size = cs_etm_info_priv_size; 920a818c563SMathieu Poirier ptr->itr.info_fill = cs_etm_info_fill; 921a818c563SMathieu Poirier ptr->itr.snapshot_start = cs_etm_snapshot_start; 922a818c563SMathieu Poirier ptr->itr.snapshot_finish = cs_etm_snapshot_finish; 923a818c563SMathieu Poirier ptr->itr.reference = cs_etm_reference; 924a818c563SMathieu Poirier ptr->itr.free = cs_etm_recording_free; 925ad60ba0cSAdrian Hunter ptr->itr.read_finish = auxtrace_record__read_finish; 926a818c563SMathieu Poirier 927a818c563SMathieu Poirier *err = 0; 928a818c563SMathieu Poirier return &ptr->itr; 929a818c563SMathieu Poirier out: 930a818c563SMathieu Poirier return NULL; 931a818c563SMathieu Poirier } 9327bfc1544SJames Clark 9337bfc1544SJames Clark /* 9347bfc1544SJames Clark * Set a default config to enable the user changed config tracking mechanism 9357bfc1544SJames Clark * (CFG_CHG and evsel__set_config_if_unset()). If no default is set then user 9367bfc1544SJames Clark * changes aren't tracked. 9377bfc1544SJames Clark */ 9380197da7aSIan Rogers void 9390197da7aSIan Rogers cs_etm_get_default_config(const struct perf_pmu *pmu __maybe_unused, 9400197da7aSIan Rogers struct perf_event_attr *attr) 9417bfc1544SJames Clark { 9427bfc1544SJames Clark attr->sample_period = 1; 9437bfc1544SJames Clark } 944