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; 2029c3516d1SJiri Olsa struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); 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 2086d18804bSIan Rogers if (!perf_cpu_map__has(event_cpus, cpu) || 2096d18804bSIan Rogers !perf_cpu_map__has(online_cpus, cpu)) 2103399ad9aSMathieu Poirier continue; 2113399ad9aSMathieu Poirier 21235c51f83SJames Clark err = cs_etm_validate_context_id(itr, evsel, i); 2133399ad9aSMathieu Poirier if (err) 2143399ad9aSMathieu Poirier goto out; 21535c51f83SJames Clark err = cs_etm_validate_timestamp(itr, evsel, i); 2161c839a5aSMathieu Poirier if (err) 2171c839a5aSMathieu Poirier goto out; 2183399ad9aSMathieu Poirier } 2193399ad9aSMathieu Poirier 2203399ad9aSMathieu Poirier err = 0; 2213399ad9aSMathieu Poirier out: 22238f01d8dSJiri Olsa perf_cpu_map__put(online_cpus); 2233399ad9aSMathieu Poirier return err; 2243399ad9aSMathieu Poirier } 2253399ad9aSMathieu Poirier 226a818c563SMathieu Poirier static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr, 227a818c563SMathieu Poirier struct record_opts *opts, 228a818c563SMathieu Poirier const char *str) 229a818c563SMathieu Poirier { 230a818c563SMathieu Poirier struct cs_etm_recording *ptr = 231a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 232a818c563SMathieu Poirier unsigned long long snapshot_size = 0; 233a818c563SMathieu Poirier char *endptr; 234a818c563SMathieu Poirier 235a818c563SMathieu Poirier if (str) { 236a818c563SMathieu Poirier snapshot_size = strtoull(str, &endptr, 0); 237a818c563SMathieu Poirier if (*endptr || snapshot_size > SIZE_MAX) 238a818c563SMathieu Poirier return -1; 239a818c563SMathieu Poirier } 240a818c563SMathieu Poirier 241a818c563SMathieu Poirier opts->auxtrace_snapshot_mode = true; 242a818c563SMathieu Poirier opts->auxtrace_snapshot_size = snapshot_size; 243a818c563SMathieu Poirier ptr->snapshot_size = snapshot_size; 244a818c563SMathieu Poirier 245a818c563SMathieu Poirier return 0; 246a818c563SMathieu Poirier } 247a818c563SMathieu Poirier 248fa4e819bSMathieu Poirier static int cs_etm_set_sink_attr(struct perf_pmu *pmu, 24932dcd021SJiri Olsa struct evsel *evsel) 250fa4e819bSMathieu Poirier { 251fa4e819bSMathieu Poirier char msg[BUFSIZ], path[PATH_MAX], *sink; 25235ac0cadSArnaldo Carvalho de Melo struct evsel_config_term *term; 253fa4e819bSMathieu Poirier int ret = -EINVAL; 254fa4e819bSMathieu Poirier u32 hash; 255fa4e819bSMathieu Poirier 2561fc632ceSJiri Olsa if (evsel->core.attr.config2 & GENMASK(31, 0)) 257fa4e819bSMathieu Poirier return 0; 258fa4e819bSMathieu Poirier 259fa4e819bSMathieu Poirier list_for_each_entry(term, &evsel->config_terms, list) { 26035ac0cadSArnaldo Carvalho de Melo if (term->type != EVSEL__CONFIG_TERM_DRV_CFG) 261fa4e819bSMathieu Poirier continue; 262fa4e819bSMathieu Poirier 263e884602bSLeo Yan sink = term->val.str; 264fa4e819bSMathieu Poirier snprintf(path, PATH_MAX, "sinks/%s", sink); 265fa4e819bSMathieu Poirier 266fa4e819bSMathieu Poirier ret = perf_pmu__scan_file(pmu, path, "%x", &hash); 267fa4e819bSMathieu Poirier if (ret != 1) { 2686bc75b4cSJames Clark if (errno == ENOENT) 2696bc75b4cSJames Clark pr_err("Couldn't find sink \"%s\" on event %s\n" 2706bc75b4cSJames Clark "Missing kernel or device support?\n\n" 2716bc75b4cSJames Clark "Hint: An appropriate sink will be picked automatically if one isn't specified.\n", 2726bc75b4cSJames Clark sink, evsel__name(evsel)); 2736bc75b4cSJames Clark else 2746bc75b4cSJames Clark pr_err("Failed to set sink \"%s\" on event %s with %d (%s)\n", 2758ab2e96dSArnaldo Carvalho de Melo sink, evsel__name(evsel), errno, 276fa4e819bSMathieu Poirier str_error_r(errno, msg, sizeof(msg))); 277fa4e819bSMathieu Poirier return ret; 278fa4e819bSMathieu Poirier } 279fa4e819bSMathieu Poirier 2801fc632ceSJiri Olsa evsel->core.attr.config2 |= hash; 281fa4e819bSMathieu Poirier return 0; 282fa4e819bSMathieu Poirier } 283fa4e819bSMathieu Poirier 284fa4e819bSMathieu Poirier /* 28547446212SMike Leach * No sink was provided on the command line - allow the CoreSight 28647446212SMike Leach * system to look for a default 287fa4e819bSMathieu Poirier */ 28847446212SMike Leach return 0; 289fa4e819bSMathieu Poirier } 290fa4e819bSMathieu Poirier 291a818c563SMathieu Poirier static int cs_etm_recording_options(struct auxtrace_record *itr, 29263503dbaSJiri Olsa struct evlist *evlist, 293a818c563SMathieu Poirier struct record_opts *opts) 294a818c563SMathieu Poirier { 295fa4e819bSMathieu Poirier int ret; 296a818c563SMathieu Poirier struct cs_etm_recording *ptr = 297a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 298a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 29932dcd021SJiri Olsa struct evsel *evsel, *cs_etm_evsel = NULL; 3000df6ade7SIan Rogers struct perf_cpu_map *cpus = evlist->core.user_requested_cpus; 301dda1bf8eSIgor Lubashev bool privileged = perf_event_paranoid_check(-1); 3023399ad9aSMathieu Poirier int err = 0; 303a818c563SMathieu Poirier 304a818c563SMathieu Poirier evlist__for_each_entry(evlist, evsel) { 3051fc632ceSJiri Olsa if (evsel->core.attr.type == cs_etm_pmu->type) { 306a818c563SMathieu Poirier if (cs_etm_evsel) { 307a818c563SMathieu Poirier pr_err("There may be only one %s event\n", 308a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 309a818c563SMathieu Poirier return -EINVAL; 310a818c563SMathieu Poirier } 311a818c563SMathieu Poirier cs_etm_evsel = evsel; 312a818c563SMathieu Poirier } 313a818c563SMathieu Poirier } 314a818c563SMathieu Poirier 315a818c563SMathieu Poirier /* no need to continue if at least one event of interest was found */ 316a818c563SMathieu Poirier if (!cs_etm_evsel) 317a818c563SMathieu Poirier return 0; 318a818c563SMathieu Poirier 3193963d84bSJames Clark ptr->evlist = evlist; 3203963d84bSJames Clark ptr->snapshot_mode = opts->auxtrace_snapshot_mode; 3213963d84bSJames Clark 3223963d84bSJames Clark if (!record_opts__no_switch_events(opts) && 3233963d84bSJames Clark perf_can_record_switch_events()) 3243963d84bSJames Clark opts->record_switch_events = true; 3253963d84bSJames Clark 3263963d84bSJames Clark cs_etm_evsel->needs_auxtrace_mmap = true; 3273963d84bSJames Clark opts->full_auxtrace = true; 3283963d84bSJames Clark 329fa4e819bSMathieu Poirier ret = cs_etm_set_sink_attr(cs_etm_pmu, cs_etm_evsel); 330fa4e819bSMathieu Poirier if (ret) 331fa4e819bSMathieu Poirier return ret; 332fa4e819bSMathieu Poirier 333a818c563SMathieu Poirier if (opts->use_clockid) { 334a818c563SMathieu Poirier pr_err("Cannot use clockid (-k option) with %s\n", 335a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 336a818c563SMathieu Poirier return -EINVAL; 337a818c563SMathieu Poirier } 338a818c563SMathieu Poirier 339a818c563SMathieu Poirier /* we are in snapshot mode */ 340a818c563SMathieu Poirier if (opts->auxtrace_snapshot_mode) { 341a818c563SMathieu Poirier /* 342a818c563SMathieu Poirier * No size were given to '-S' or '-m,', so go with 343a818c563SMathieu Poirier * the default 344a818c563SMathieu Poirier */ 345a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size && 346a818c563SMathieu Poirier !opts->auxtrace_mmap_pages) { 347a818c563SMathieu Poirier if (privileged) { 348a818c563SMathieu Poirier opts->auxtrace_mmap_pages = MiB(4) / page_size; 349a818c563SMathieu Poirier } else { 350a818c563SMathieu Poirier opts->auxtrace_mmap_pages = 351a818c563SMathieu Poirier KiB(128) / page_size; 352a818c563SMathieu Poirier if (opts->mmap_pages == UINT_MAX) 353a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 354a818c563SMathieu Poirier } 355a818c563SMathieu Poirier } else if (!opts->auxtrace_mmap_pages && !privileged && 356a818c563SMathieu Poirier opts->mmap_pages == UINT_MAX) { 357a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 358a818c563SMathieu Poirier } 359a818c563SMathieu Poirier 360a818c563SMathieu Poirier /* 361a818c563SMathieu Poirier * '-m,xyz' was specified but no snapshot size, so make the 362a818c563SMathieu Poirier * snapshot size as big as the auxtrace mmap area. 363a818c563SMathieu Poirier */ 364a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size) { 365a818c563SMathieu Poirier opts->auxtrace_snapshot_size = 366a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size; 367a818c563SMathieu Poirier } 368a818c563SMathieu Poirier 369a818c563SMathieu Poirier /* 370a818c563SMathieu Poirier * -Sxyz was specified but no auxtrace mmap area, so make the 371a818c563SMathieu Poirier * auxtrace mmap area big enough to fit the requested snapshot 372a818c563SMathieu Poirier * size. 373a818c563SMathieu Poirier */ 374a818c563SMathieu Poirier if (!opts->auxtrace_mmap_pages) { 375a818c563SMathieu Poirier size_t sz = opts->auxtrace_snapshot_size; 376a818c563SMathieu Poirier 377a818c563SMathieu Poirier sz = round_up(sz, page_size) / page_size; 378a818c563SMathieu Poirier opts->auxtrace_mmap_pages = roundup_pow_of_two(sz); 379a818c563SMathieu Poirier } 380a818c563SMathieu Poirier 3814d39c89fSIngo Molnar /* Snapshot size can't be bigger than the auxtrace area */ 382a818c563SMathieu Poirier if (opts->auxtrace_snapshot_size > 383a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size) { 384a818c563SMathieu Poirier pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n", 385a818c563SMathieu Poirier opts->auxtrace_snapshot_size, 386a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size); 387a818c563SMathieu Poirier return -EINVAL; 388a818c563SMathieu Poirier } 389a818c563SMathieu Poirier 390a818c563SMathieu Poirier /* Something went wrong somewhere - this shouldn't happen */ 391a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size || 392a818c563SMathieu Poirier !opts->auxtrace_mmap_pages) { 393a818c563SMathieu Poirier pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n"); 394a818c563SMathieu Poirier return -EINVAL; 395a818c563SMathieu Poirier } 396a818c563SMathieu Poirier } 397a818c563SMathieu Poirier 3983963d84bSJames Clark /* Buffer sizes weren't specified with '-m,xyz' so give some defaults */ 3993963d84bSJames Clark if (!opts->auxtrace_mmap_pages) { 400a818c563SMathieu Poirier if (privileged) { 401a818c563SMathieu Poirier opts->auxtrace_mmap_pages = MiB(4) / page_size; 402a818c563SMathieu Poirier } else { 403a818c563SMathieu Poirier opts->auxtrace_mmap_pages = KiB(128) / page_size; 404a818c563SMathieu Poirier if (opts->mmap_pages == UINT_MAX) 405a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 406a818c563SMathieu Poirier } 407a818c563SMathieu Poirier } 408a818c563SMathieu Poirier 409a818c563SMathieu Poirier if (opts->auxtrace_snapshot_mode) 410a818c563SMathieu Poirier pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME, 411a818c563SMathieu Poirier opts->auxtrace_snapshot_size); 412a818c563SMathieu Poirier 413a818c563SMathieu Poirier /* 414a818c563SMathieu Poirier * To obtain the auxtrace buffer file descriptor, the auxtrace 415a818c563SMathieu Poirier * event must come first. 416a818c563SMathieu Poirier */ 417e414fd1aSArnaldo Carvalho de Melo evlist__to_front(evlist, cs_etm_evsel); 4180c788d47SKim Phillips 419a818c563SMathieu Poirier /* 420e5fa5b41SMike Leach * get the CPU on the sample - need it to associate trace ID in the 421e5fa5b41SMike Leach * AUX_OUTPUT_HW_ID event, and the AUX event for per-cpu mmaps. 422e5fa5b41SMike Leach */ 423e5fa5b41SMike Leach evsel__set_sample_bit(cs_etm_evsel, CPU); 424e5fa5b41SMike Leach 425e5fa5b41SMike Leach /* 426e5fa5b41SMike Leach * Also the case of per-cpu mmaps, need the contextID in order to be notified 4273399ad9aSMathieu Poirier * when a context switch happened. 428a818c563SMathieu Poirier */ 429315c0a1fSJiri Olsa if (!perf_cpu_map__empty(cpus)) { 4307bfc1544SJames Clark evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel, 4317bfc1544SJames Clark "timestamp", 1); 4327bfc1544SJames Clark evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel, 4337bfc1544SJames Clark "contextid", 1); 4343399ad9aSMathieu Poirier } 4353399ad9aSMathieu Poirier 436a818c563SMathieu Poirier /* Add dummy event to keep tracking */ 437806731a9SAdrian Hunter err = parse_event(evlist, "dummy:u"); 438a818c563SMathieu Poirier if (err) 4393399ad9aSMathieu Poirier goto out; 4403963d84bSJames Clark evsel = evlist__last(evlist); 4413963d84bSJames Clark evlist__set_tracking_event(evlist, evsel); 4423963d84bSJames Clark evsel->core.attr.freq = 0; 4433963d84bSJames Clark evsel->core.attr.sample_period = 1; 444a818c563SMathieu Poirier 445a818c563SMathieu Poirier /* In per-cpu case, always need the time of mmap events etc */ 446315c0a1fSJiri Olsa if (!perf_cpu_map__empty(cpus)) 4473963d84bSJames Clark evsel__set_sample_bit(evsel, TIME); 448a818c563SMathieu Poirier 44935c51f83SJames Clark err = cs_etm_validate_config(itr, cs_etm_evsel); 4503399ad9aSMathieu Poirier out: 4513399ad9aSMathieu Poirier return err; 452a818c563SMathieu Poirier } 453a818c563SMathieu Poirier 454a818c563SMathieu Poirier static u64 cs_etm_get_config(struct auxtrace_record *itr) 455a818c563SMathieu Poirier { 456a818c563SMathieu Poirier u64 config = 0; 457a818c563SMathieu Poirier struct cs_etm_recording *ptr = 458a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 459a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 46063503dbaSJiri Olsa struct evlist *evlist = ptr->evlist; 46132dcd021SJiri Olsa struct evsel *evsel; 462a818c563SMathieu Poirier 463a818c563SMathieu Poirier evlist__for_each_entry(evlist, evsel) { 4641fc632ceSJiri Olsa if (evsel->core.attr.type == cs_etm_pmu->type) { 465a818c563SMathieu Poirier /* 466a818c563SMathieu Poirier * Variable perf_event_attr::config is assigned to 467a818c563SMathieu Poirier * ETMv3/PTM. The bit fields have been made to match 468a818c563SMathieu Poirier * the ETMv3.5 ETRMCR register specification. See the 469a818c563SMathieu Poirier * PMU_FORMAT_ATTR() declarations in 470a818c563SMathieu Poirier * drivers/hwtracing/coresight/coresight-perf.c for 471a818c563SMathieu Poirier * details. 472a818c563SMathieu Poirier */ 4731fc632ceSJiri Olsa config = evsel->core.attr.config; 474a818c563SMathieu Poirier break; 475a818c563SMathieu Poirier } 476a818c563SMathieu Poirier } 477a818c563SMathieu Poirier 478a818c563SMathieu Poirier return config; 479a818c563SMathieu Poirier } 480a818c563SMathieu Poirier 481df770ff0SMike Leach #ifndef BIT 482df770ff0SMike Leach #define BIT(N) (1UL << (N)) 483df770ff0SMike Leach #endif 484df770ff0SMike Leach 485df770ff0SMike Leach static u64 cs_etmv4_get_config(struct auxtrace_record *itr) 486df770ff0SMike Leach { 487df770ff0SMike Leach u64 config = 0; 488df770ff0SMike Leach u64 config_opts = 0; 489df770ff0SMike Leach 490df770ff0SMike Leach /* 491df770ff0SMike Leach * The perf event variable config bits represent both 492df770ff0SMike Leach * the command line options and register programming 493df770ff0SMike Leach * bits in ETMv3/PTM. For ETMv4 we must remap options 494df770ff0SMike Leach * to real bits 495df770ff0SMike Leach */ 496df770ff0SMike Leach config_opts = cs_etm_get_config(itr); 497df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_CYCACC)) 498df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_CYCACC); 4993399ad9aSMathieu Poirier if (config_opts & BIT(ETM_OPT_CTXTID)) 5003399ad9aSMathieu Poirier config |= BIT(ETM4_CFG_BIT_CTXTID); 501df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_TS)) 502df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_TS); 503df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_RETSTK)) 504df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_RETSTK); 50530cb76aaSSuzuki K Poulose if (config_opts & BIT(ETM_OPT_CTXTID2)) 50630cb76aaSSuzuki K Poulose config |= BIT(ETM4_CFG_BIT_VMID) | 50730cb76aaSSuzuki K Poulose BIT(ETM4_CFG_BIT_VMID_OPT); 508aca8af3cSJames Clark if (config_opts & BIT(ETM_OPT_BRANCH_BROADCAST)) 509aca8af3cSJames Clark config |= BIT(ETM4_CFG_BIT_BB); 510aca8af3cSJames Clark 511df770ff0SMike Leach return config; 512df770ff0SMike Leach } 513df770ff0SMike Leach 514a818c563SMathieu Poirier static size_t 515a818c563SMathieu Poirier cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, 51663503dbaSJiri Olsa struct evlist *evlist __maybe_unused) 517a818c563SMathieu Poirier { 518a818c563SMathieu Poirier int i; 51951ba8811SJames Clark int etmv3 = 0, etmv4 = 0, ete = 0; 5200df6ade7SIan Rogers struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus; 5219c3516d1SJiri Olsa struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); 522a818c563SMathieu Poirier 523a818c563SMathieu Poirier /* cpu map is not empty, we have specific CPUs to work with */ 524315c0a1fSJiri Olsa if (!perf_cpu_map__empty(event_cpus)) { 5256d18804bSIan Rogers for (i = 0; i < cpu__max_cpu().cpu; i++) { 5266d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 5276d18804bSIan Rogers 5286d18804bSIan Rogers if (!perf_cpu_map__has(event_cpus, cpu) || 5296d18804bSIan Rogers !perf_cpu_map__has(online_cpus, cpu)) 530796bfaddSMathieu Poirier continue; 531796bfaddSMathieu Poirier 53251ba8811SJames Clark if (cs_etm_is_ete(itr, i)) 53351ba8811SJames Clark ete++; 53451ba8811SJames Clark else if (cs_etm_is_etmv4(itr, i)) 535a818c563SMathieu Poirier etmv4++; 536a818c563SMathieu Poirier else 537a818c563SMathieu Poirier etmv3++; 538a818c563SMathieu Poirier } 539a818c563SMathieu Poirier } else { 540a818c563SMathieu Poirier /* get configuration for all CPUs in the system */ 5416d18804bSIan Rogers for (i = 0; i < cpu__max_cpu().cpu; i++) { 5426d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 5436d18804bSIan Rogers 5446d18804bSIan Rogers if (!perf_cpu_map__has(online_cpus, cpu)) 545796bfaddSMathieu Poirier continue; 546796bfaddSMathieu Poirier 54751ba8811SJames Clark if (cs_etm_is_ete(itr, i)) 54851ba8811SJames Clark ete++; 54951ba8811SJames Clark else if (cs_etm_is_etmv4(itr, i)) 550a818c563SMathieu Poirier etmv4++; 551a818c563SMathieu Poirier else 552a818c563SMathieu Poirier etmv3++; 553a818c563SMathieu Poirier } 554a818c563SMathieu Poirier } 555a818c563SMathieu Poirier 55638f01d8dSJiri Olsa perf_cpu_map__put(online_cpus); 557796bfaddSMathieu Poirier 558a818c563SMathieu Poirier return (CS_ETM_HEADER_SIZE + 55951ba8811SJames Clark (ete * CS_ETE_PRIV_SIZE) + 560a818c563SMathieu Poirier (etmv4 * CS_ETMV4_PRIV_SIZE) + 561a818c563SMathieu Poirier (etmv3 * CS_ETMV3_PRIV_SIZE)); 562a818c563SMathieu Poirier } 563a818c563SMathieu Poirier 564a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu) 565a818c563SMathieu Poirier { 566a818c563SMathieu Poirier bool ret = false; 567a818c563SMathieu Poirier char path[PATH_MAX]; 568a818c563SMathieu Poirier int scan; 569a818c563SMathieu Poirier unsigned int val; 570a818c563SMathieu Poirier struct cs_etm_recording *ptr = 571a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 572a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 573a818c563SMathieu Poirier 574a818c563SMathieu Poirier /* Take any of the RO files for ETMv4 and see if it present */ 575a818c563SMathieu Poirier snprintf(path, PATH_MAX, "cpu%d/%s", 576a818c563SMathieu Poirier cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 577a818c563SMathieu Poirier scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 578a818c563SMathieu Poirier 579a818c563SMathieu Poirier /* The file was read successfully, we have a winner */ 580a818c563SMathieu Poirier if (scan == 1) 581a818c563SMathieu Poirier ret = true; 582a818c563SMathieu Poirier 583a818c563SMathieu Poirier return ret; 584a818c563SMathieu Poirier } 585a818c563SMathieu Poirier 586a818c563SMathieu Poirier static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path) 587a818c563SMathieu Poirier { 588a818c563SMathieu Poirier char pmu_path[PATH_MAX]; 589a818c563SMathieu Poirier int scan; 590a818c563SMathieu Poirier unsigned int val = 0; 591a818c563SMathieu Poirier 592a818c563SMathieu Poirier /* Get RO metadata from sysfs */ 593a818c563SMathieu Poirier snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 594a818c563SMathieu Poirier 595a818c563SMathieu Poirier scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val); 596a818c563SMathieu Poirier if (scan != 1) 597a818c563SMathieu Poirier pr_err("%s: error reading: %s\n", __func__, pmu_path); 598a818c563SMathieu Poirier 599a818c563SMathieu Poirier return val; 600a818c563SMathieu Poirier } 601a818c563SMathieu Poirier 6022e2f7ceeSGerman Gomez static int cs_etm_get_ro_signed(struct perf_pmu *pmu, int cpu, const char *path) 6032e2f7ceeSGerman Gomez { 6042e2f7ceeSGerman Gomez char pmu_path[PATH_MAX]; 6052e2f7ceeSGerman Gomez int scan; 6062e2f7ceeSGerman Gomez int val = 0; 6072e2f7ceeSGerman Gomez 6082e2f7ceeSGerman Gomez /* Get RO metadata from sysfs */ 6092e2f7ceeSGerman Gomez snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 6102e2f7ceeSGerman Gomez 6112e2f7ceeSGerman Gomez scan = perf_pmu__scan_file(pmu, pmu_path, "%d", &val); 6122e2f7ceeSGerman Gomez if (scan != 1) 6132e2f7ceeSGerman Gomez pr_err("%s: error reading: %s\n", __func__, pmu_path); 6142e2f7ceeSGerman Gomez 6152e2f7ceeSGerman Gomez return val; 6162e2f7ceeSGerman Gomez } 6172e2f7ceeSGerman Gomez 6182e2f7ceeSGerman Gomez static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, int cpu, const char *path) 6192e2f7ceeSGerman Gomez { 6202e2f7ceeSGerman Gomez char pmu_path[PATH_MAX]; 6212e2f7ceeSGerman Gomez 6222e2f7ceeSGerman Gomez /* Get RO metadata from sysfs */ 6232e2f7ceeSGerman Gomez snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 6242e2f7ceeSGerman Gomez 6252e2f7ceeSGerman Gomez return perf_pmu__file_exists(pmu, pmu_path); 6262e2f7ceeSGerman Gomez } 6272e2f7ceeSGerman Gomez 62851ba8811SJames Clark #define TRCDEVARCH_ARCHPART_SHIFT 0 62951ba8811SJames Clark #define TRCDEVARCH_ARCHPART_MASK GENMASK(11, 0) 63051ba8811SJames Clark #define TRCDEVARCH_ARCHPART(x) (((x) & TRCDEVARCH_ARCHPART_MASK) >> TRCDEVARCH_ARCHPART_SHIFT) 63151ba8811SJames Clark 63251ba8811SJames Clark #define TRCDEVARCH_ARCHVER_SHIFT 12 63351ba8811SJames Clark #define TRCDEVARCH_ARCHVER_MASK GENMASK(15, 12) 63451ba8811SJames Clark #define TRCDEVARCH_ARCHVER(x) (((x) & TRCDEVARCH_ARCHVER_MASK) >> TRCDEVARCH_ARCHVER_SHIFT) 63551ba8811SJames Clark 63651ba8811SJames Clark static bool cs_etm_is_ete(struct auxtrace_record *itr, int cpu) 63751ba8811SJames Clark { 63851ba8811SJames Clark struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); 63951ba8811SJames Clark struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 640e5af1397SJames Clark int trcdevarch; 64151ba8811SJames Clark 642e5af1397SJames Clark if (!cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH])) 643e5af1397SJames Clark return false; 644e5af1397SJames Clark 645e5af1397SJames Clark trcdevarch = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH]); 64651ba8811SJames Clark /* 64751ba8811SJames Clark * ETE if ARCHVER is 5 (ARCHVER is 4 for ETM) and ARCHPART is 0xA13. 64851ba8811SJames Clark * See ETM_DEVARCH_ETE_ARCH in coresight-etm4x.h 64951ba8811SJames Clark */ 65051ba8811SJames Clark return TRCDEVARCH_ARCHVER(trcdevarch) == 5 && TRCDEVARCH_ARCHPART(trcdevarch) == 0xA13; 65151ba8811SJames Clark } 65251ba8811SJames Clark 653c9ccc96bSJames Clark static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr, int cpu) 654c9ccc96bSJames Clark { 655c9ccc96bSJames Clark struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); 656c9ccc96bSJames Clark struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 657c9ccc96bSJames Clark 658c9ccc96bSJames Clark /* Get trace configuration register */ 659c9ccc96bSJames Clark data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_get_config(itr); 660e5fa5b41SMike Leach /* traceID set to legacy version, in case new perf running on older system */ 661e5fa5b41SMike Leach data[CS_ETMV4_TRCTRACEIDR] = 662e5fa5b41SMike Leach CORESIGHT_LEGACY_CPU_TRACE_ID(cpu) | CORESIGHT_TRACE_ID_UNUSED_FLAG; 663e5fa5b41SMike Leach 664c9ccc96bSJames Clark /* Get read-only information from sysFS */ 665c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR0] = cs_etm_get_ro(cs_etm_pmu, cpu, 666c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 667c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR1] = cs_etm_get_ro(cs_etm_pmu, cpu, 668c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR1]); 669c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR2] = cs_etm_get_ro(cs_etm_pmu, cpu, 670c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); 671c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR8] = cs_etm_get_ro(cs_etm_pmu, cpu, 672c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR8]); 673c9ccc96bSJames Clark data[CS_ETMV4_TRCAUTHSTATUS] = cs_etm_get_ro(cs_etm_pmu, cpu, 674c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCAUTHSTATUS]); 6752e2f7ceeSGerman Gomez 6762e2f7ceeSGerman Gomez /* Kernels older than 5.19 may not expose ts_source */ 6772e2f7ceeSGerman Gomez if (cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TS_SOURCE])) 6782e2f7ceeSGerman Gomez data[CS_ETMV4_TS_SOURCE] = (__u64) cs_etm_get_ro_signed(cs_etm_pmu, cpu, 6792e2f7ceeSGerman Gomez metadata_etmv4_ro[CS_ETMV4_TS_SOURCE]); 6802e2f7ceeSGerman Gomez else { 6815f968d28SJames Clark pr_debug3("[%03d] pmu file 'ts_source' not found. Fallback to safe value (-1)\n", 6822e2f7ceeSGerman Gomez cpu); 6832e2f7ceeSGerman Gomez data[CS_ETMV4_TS_SOURCE] = (__u64) -1; 6842e2f7ceeSGerman Gomez } 685c9ccc96bSJames Clark } 686c9ccc96bSJames Clark 687326163c5SGerman Gomez static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *itr, int cpu) 688326163c5SGerman Gomez { 689326163c5SGerman Gomez struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); 690326163c5SGerman Gomez struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 691326163c5SGerman Gomez 692326163c5SGerman Gomez /* Get trace configuration register */ 693326163c5SGerman Gomez data[CS_ETE_TRCCONFIGR] = cs_etmv4_get_config(itr); 694e5fa5b41SMike Leach /* traceID set to legacy version, in case new perf running on older system */ 695e5fa5b41SMike Leach data[CS_ETE_TRCTRACEIDR] = 696e5fa5b41SMike Leach CORESIGHT_LEGACY_CPU_TRACE_ID(cpu) | CORESIGHT_TRACE_ID_UNUSED_FLAG; 697e5fa5b41SMike Leach 698326163c5SGerman Gomez /* Get read-only information from sysFS */ 699326163c5SGerman Gomez data[CS_ETE_TRCIDR0] = cs_etm_get_ro(cs_etm_pmu, cpu, 700326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCIDR0]); 701326163c5SGerman Gomez data[CS_ETE_TRCIDR1] = cs_etm_get_ro(cs_etm_pmu, cpu, 702326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCIDR1]); 703326163c5SGerman Gomez data[CS_ETE_TRCIDR2] = cs_etm_get_ro(cs_etm_pmu, cpu, 704326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCIDR2]); 705326163c5SGerman Gomez data[CS_ETE_TRCIDR8] = cs_etm_get_ro(cs_etm_pmu, cpu, 706326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCIDR8]); 707326163c5SGerman Gomez data[CS_ETE_TRCAUTHSTATUS] = cs_etm_get_ro(cs_etm_pmu, cpu, 708326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCAUTHSTATUS]); 709326163c5SGerman Gomez /* ETE uses the same registers as ETMv4 plus TRCDEVARCH */ 710326163c5SGerman Gomez data[CS_ETE_TRCDEVARCH] = cs_etm_get_ro(cs_etm_pmu, cpu, 711326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCDEVARCH]); 7122e2f7ceeSGerman Gomez 7132e2f7ceeSGerman Gomez /* Kernels older than 5.19 may not expose ts_source */ 7142e2f7ceeSGerman Gomez if (cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TS_SOURCE])) 7152e2f7ceeSGerman Gomez data[CS_ETE_TS_SOURCE] = (__u64) cs_etm_get_ro_signed(cs_etm_pmu, cpu, 7162e2f7ceeSGerman Gomez metadata_ete_ro[CS_ETE_TS_SOURCE]); 7172e2f7ceeSGerman Gomez else { 7185f968d28SJames Clark pr_debug3("[%03d] pmu file 'ts_source' not found. Fallback to safe value (-1)\n", 7192e2f7ceeSGerman Gomez cpu); 7202e2f7ceeSGerman Gomez data[CS_ETE_TS_SOURCE] = (__u64) -1; 7212e2f7ceeSGerman Gomez } 722326163c5SGerman Gomez } 723326163c5SGerman Gomez 724a818c563SMathieu Poirier static void cs_etm_get_metadata(int cpu, u32 *offset, 725a818c563SMathieu Poirier struct auxtrace_record *itr, 72672932371SJiri Olsa struct perf_record_auxtrace_info *info) 727a818c563SMathieu Poirier { 72842b2b570SMike Leach u32 increment, nr_trc_params; 729a818c563SMathieu Poirier u64 magic; 730a818c563SMathieu Poirier struct cs_etm_recording *ptr = 731a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 732a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 733a818c563SMathieu Poirier 734a818c563SMathieu Poirier /* first see what kind of tracer this cpu is affined to */ 73551ba8811SJames Clark if (cs_etm_is_ete(itr, cpu)) { 73651ba8811SJames Clark magic = __perf_cs_ete_magic; 737326163c5SGerman Gomez cs_etm_save_ete_header(&info->priv[*offset], itr, cpu); 73851ba8811SJames Clark 73951ba8811SJames Clark /* How much space was used */ 74051ba8811SJames Clark increment = CS_ETE_PRIV_MAX; 74151ba8811SJames Clark nr_trc_params = CS_ETE_PRIV_MAX - CS_ETM_COMMON_BLK_MAX_V1; 74251ba8811SJames Clark } else if (cs_etm_is_etmv4(itr, cpu)) { 743a818c563SMathieu Poirier magic = __perf_cs_etmv4_magic; 744c9ccc96bSJames Clark cs_etm_save_etmv4_header(&info->priv[*offset], itr, cpu); 745a818c563SMathieu Poirier 746a818c563SMathieu Poirier /* How much space was used */ 747a818c563SMathieu Poirier increment = CS_ETMV4_PRIV_MAX; 74842b2b570SMike Leach nr_trc_params = CS_ETMV4_PRIV_MAX - CS_ETMV4_TRCCONFIGR; 749a818c563SMathieu Poirier } else { 750a818c563SMathieu Poirier magic = __perf_cs_etmv3_magic; 751a818c563SMathieu Poirier /* Get configuration register */ 752a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr); 753e5fa5b41SMike Leach /* traceID set to legacy value in case new perf running on old system */ 754a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMTRACEIDR] = 755e5fa5b41SMike Leach CORESIGHT_LEGACY_CPU_TRACE_ID(cpu) | CORESIGHT_TRACE_ID_UNUSED_FLAG; 756a818c563SMathieu Poirier /* Get read-only information from sysFS */ 757a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMCCER] = 758a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 759a818c563SMathieu Poirier metadata_etmv3_ro[CS_ETM_ETMCCER]); 760a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMIDR] = 761a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 762a818c563SMathieu Poirier metadata_etmv3_ro[CS_ETM_ETMIDR]); 763a818c563SMathieu Poirier 764a818c563SMathieu Poirier /* How much space was used */ 765a818c563SMathieu Poirier increment = CS_ETM_PRIV_MAX; 76642b2b570SMike Leach nr_trc_params = CS_ETM_PRIV_MAX - CS_ETM_ETMCR; 767a818c563SMathieu Poirier } 768a818c563SMathieu Poirier 769a818c563SMathieu Poirier /* Build generic header portion */ 770a818c563SMathieu Poirier info->priv[*offset + CS_ETM_MAGIC] = magic; 771a818c563SMathieu Poirier info->priv[*offset + CS_ETM_CPU] = cpu; 77242b2b570SMike Leach info->priv[*offset + CS_ETM_NR_TRC_PARAMS] = nr_trc_params; 773a818c563SMathieu Poirier /* Where the next CPU entry should start from */ 774a818c563SMathieu Poirier *offset += increment; 775a818c563SMathieu Poirier } 776a818c563SMathieu Poirier 777a818c563SMathieu Poirier static int cs_etm_info_fill(struct auxtrace_record *itr, 778a818c563SMathieu Poirier struct perf_session *session, 77972932371SJiri Olsa struct perf_record_auxtrace_info *info, 780a818c563SMathieu Poirier size_t priv_size) 781a818c563SMathieu Poirier { 782a818c563SMathieu Poirier int i; 783a818c563SMathieu Poirier u32 offset; 784a818c563SMathieu Poirier u64 nr_cpu, type; 785f854839bSJiri Olsa struct perf_cpu_map *cpu_map; 7860df6ade7SIan Rogers struct perf_cpu_map *event_cpus = session->evlist->core.user_requested_cpus; 7879c3516d1SJiri Olsa struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); 788a818c563SMathieu Poirier struct cs_etm_recording *ptr = 789a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 790a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 791a818c563SMathieu Poirier 792a818c563SMathieu Poirier if (priv_size != cs_etm_info_priv_size(itr, session->evlist)) 793a818c563SMathieu Poirier return -EINVAL; 794a818c563SMathieu Poirier 795c976ee11SJiri Olsa if (!session->evlist->core.nr_mmaps) 796a818c563SMathieu Poirier return -EINVAL; 797a818c563SMathieu Poirier 798796bfaddSMathieu Poirier /* If the cpu_map is empty all online CPUs are involved */ 799315c0a1fSJiri Olsa if (perf_cpu_map__empty(event_cpus)) { 800796bfaddSMathieu Poirier cpu_map = online_cpus; 801796bfaddSMathieu Poirier } else { 802796bfaddSMathieu Poirier /* Make sure all specified CPUs are online */ 8036549cd8fSJiri Olsa for (i = 0; i < perf_cpu_map__nr(event_cpus); i++) { 8046d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 8056d18804bSIan Rogers 8066d18804bSIan Rogers if (perf_cpu_map__has(event_cpus, cpu) && 8076d18804bSIan Rogers !perf_cpu_map__has(online_cpus, cpu)) 808796bfaddSMathieu Poirier return -EINVAL; 809796bfaddSMathieu Poirier } 810796bfaddSMathieu Poirier 811796bfaddSMathieu Poirier cpu_map = event_cpus; 812796bfaddSMathieu Poirier } 813796bfaddSMathieu Poirier 8146549cd8fSJiri Olsa nr_cpu = perf_cpu_map__nr(cpu_map); 815a818c563SMathieu Poirier /* Get PMU type as dynamically assigned by the core */ 816a818c563SMathieu Poirier type = cs_etm_pmu->type; 817a818c563SMathieu Poirier 818a818c563SMathieu Poirier /* First fill out the session header */ 819a818c563SMathieu Poirier info->type = PERF_AUXTRACE_CS_ETM; 82042b2b570SMike Leach info->priv[CS_HEADER_VERSION] = CS_HEADER_CURRENT_VERSION; 821a818c563SMathieu Poirier info->priv[CS_PMU_TYPE_CPUS] = type << 32; 822a818c563SMathieu Poirier info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu; 823a818c563SMathieu Poirier info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode; 824a818c563SMathieu Poirier 825a818c563SMathieu Poirier offset = CS_ETM_SNAPSHOT + 1; 826a818c563SMathieu Poirier 8276d18804bSIan Rogers for (i = 0; i < cpu__max_cpu().cpu && offset < priv_size; i++) { 8286d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 8296d18804bSIan Rogers 8306d18804bSIan Rogers if (perf_cpu_map__has(cpu_map, cpu)) 831a818c563SMathieu Poirier cs_etm_get_metadata(i, &offset, itr, info); 8326d18804bSIan Rogers } 833796bfaddSMathieu Poirier 83438f01d8dSJiri Olsa perf_cpu_map__put(online_cpus); 835a818c563SMathieu Poirier 836a818c563SMathieu Poirier return 0; 837a818c563SMathieu Poirier } 838a818c563SMathieu Poirier 839a818c563SMathieu Poirier static int cs_etm_snapshot_start(struct auxtrace_record *itr) 840a818c563SMathieu Poirier { 841a818c563SMathieu Poirier struct cs_etm_recording *ptr = 842a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 84332dcd021SJiri Olsa struct evsel *evsel; 844a818c563SMathieu Poirier 845a818c563SMathieu Poirier evlist__for_each_entry(ptr->evlist, evsel) { 8461fc632ceSJiri Olsa if (evsel->core.attr.type == ptr->cs_etm_pmu->type) 8479a10bb22SJiri Olsa return evsel__disable(evsel); 848a818c563SMathieu Poirier } 849a818c563SMathieu Poirier return -EINVAL; 850a818c563SMathieu Poirier } 851a818c563SMathieu Poirier 852a818c563SMathieu Poirier static int cs_etm_snapshot_finish(struct auxtrace_record *itr) 853a818c563SMathieu Poirier { 854a818c563SMathieu Poirier struct cs_etm_recording *ptr = 855a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 85632dcd021SJiri Olsa struct evsel *evsel; 857a818c563SMathieu Poirier 858a818c563SMathieu Poirier evlist__for_each_entry(ptr->evlist, evsel) { 8591fc632ceSJiri Olsa if (evsel->core.attr.type == ptr->cs_etm_pmu->type) 860ec7f24efSJiri Olsa return evsel__enable(evsel); 861a818c563SMathieu Poirier } 862a818c563SMathieu Poirier return -EINVAL; 863a818c563SMathieu Poirier } 864a818c563SMathieu Poirier 865a818c563SMathieu Poirier static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused) 866a818c563SMathieu Poirier { 867a818c563SMathieu Poirier return (((u64) rand() << 0) & 0x00000000FFFFFFFFull) | 868a818c563SMathieu Poirier (((u64) rand() << 32) & 0xFFFFFFFF00000000ull); 869a818c563SMathieu Poirier } 870a818c563SMathieu Poirier 871a818c563SMathieu Poirier static void cs_etm_recording_free(struct auxtrace_record *itr) 872a818c563SMathieu Poirier { 873a818c563SMathieu Poirier struct cs_etm_recording *ptr = 874a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 875e45c48a9SMathieu Poirier 876a818c563SMathieu Poirier free(ptr); 877a818c563SMathieu Poirier } 878a818c563SMathieu Poirier 879a818c563SMathieu Poirier struct auxtrace_record *cs_etm_record_init(int *err) 880a818c563SMathieu Poirier { 881a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu; 882a818c563SMathieu Poirier struct cs_etm_recording *ptr; 883a818c563SMathieu Poirier 8841eaf496eSIan Rogers cs_etm_pmu = perf_pmus__find(CORESIGHT_ETM_PMU_NAME); 885a818c563SMathieu Poirier 886a818c563SMathieu Poirier if (!cs_etm_pmu) { 887a818c563SMathieu Poirier *err = -EINVAL; 888a818c563SMathieu Poirier goto out; 889a818c563SMathieu Poirier } 890a818c563SMathieu Poirier 891a818c563SMathieu Poirier ptr = zalloc(sizeof(struct cs_etm_recording)); 892a818c563SMathieu Poirier if (!ptr) { 893a818c563SMathieu Poirier *err = -ENOMEM; 894a818c563SMathieu Poirier goto out; 895a818c563SMathieu Poirier } 896a818c563SMathieu Poirier 897a818c563SMathieu Poirier ptr->cs_etm_pmu = cs_etm_pmu; 898ad60ba0cSAdrian Hunter ptr->itr.pmu = cs_etm_pmu; 899a818c563SMathieu Poirier ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options; 900a818c563SMathieu Poirier ptr->itr.recording_options = cs_etm_recording_options; 901a818c563SMathieu Poirier ptr->itr.info_priv_size = cs_etm_info_priv_size; 902a818c563SMathieu Poirier ptr->itr.info_fill = cs_etm_info_fill; 903a818c563SMathieu Poirier ptr->itr.snapshot_start = cs_etm_snapshot_start; 904a818c563SMathieu Poirier ptr->itr.snapshot_finish = cs_etm_snapshot_finish; 905a818c563SMathieu Poirier ptr->itr.reference = cs_etm_reference; 906a818c563SMathieu Poirier ptr->itr.free = cs_etm_recording_free; 907ad60ba0cSAdrian Hunter ptr->itr.read_finish = auxtrace_record__read_finish; 908a818c563SMathieu Poirier 909a818c563SMathieu Poirier *err = 0; 910a818c563SMathieu Poirier return &ptr->itr; 911a818c563SMathieu Poirier out: 912a818c563SMathieu Poirier return NULL; 913a818c563SMathieu Poirier } 9147bfc1544SJames Clark 9157bfc1544SJames Clark /* 9167bfc1544SJames Clark * Set a default config to enable the user changed config tracking mechanism 9177bfc1544SJames Clark * (CFG_CHG and evsel__set_config_if_unset()). If no default is set then user 9187bfc1544SJames Clark * changes aren't tracked. 9197bfc1544SJames Clark */ 920*0197da7aSIan Rogers void 921*0197da7aSIan Rogers cs_etm_get_default_config(const struct perf_pmu *pmu __maybe_unused, 922*0197da7aSIan Rogers struct perf_event_attr *attr) 9237bfc1544SJames Clark { 9247bfc1544SJames Clark attr->sample_period = 1; 9257bfc1544SJames Clark } 926