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" 28c6613bd4SIan Rogers #include "../../../util/pmu.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 723399ad9aSMathieu Poirier static int cs_etm_set_context_id(struct auxtrace_record *itr, 7332dcd021SJiri Olsa struct evsel *evsel, int cpu) 743399ad9aSMathieu Poirier { 753399ad9aSMathieu Poirier struct cs_etm_recording *ptr; 763399ad9aSMathieu Poirier struct perf_pmu *cs_etm_pmu; 773399ad9aSMathieu Poirier char path[PATH_MAX]; 783399ad9aSMathieu Poirier int err = -EINVAL; 793399ad9aSMathieu Poirier u32 val; 8030cb76aaSSuzuki K Poulose u64 contextid; 813399ad9aSMathieu Poirier 823399ad9aSMathieu Poirier ptr = container_of(itr, struct cs_etm_recording, itr); 833399ad9aSMathieu Poirier cs_etm_pmu = ptr->cs_etm_pmu; 843399ad9aSMathieu Poirier 853399ad9aSMathieu Poirier if (!cs_etm_is_etmv4(itr, cpu)) 863399ad9aSMathieu Poirier goto out; 873399ad9aSMathieu Poirier 88050a0fc4SJames Clark /* Get a handle on TRCIDR2 */ 893399ad9aSMathieu Poirier snprintf(path, PATH_MAX, "cpu%d/%s", 903399ad9aSMathieu Poirier cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); 913399ad9aSMathieu Poirier err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 923399ad9aSMathieu Poirier 933399ad9aSMathieu Poirier /* There was a problem reading the file, bailing out */ 943399ad9aSMathieu Poirier if (err != 1) { 953399ad9aSMathieu Poirier pr_err("%s: can't read file %s\n", 963399ad9aSMathieu Poirier CORESIGHT_ETM_PMU_NAME, path); 973399ad9aSMathieu Poirier goto out; 983399ad9aSMathieu Poirier } 993399ad9aSMathieu Poirier 10030cb76aaSSuzuki K Poulose /* User has configured for PID tracing, respects it. */ 10130cb76aaSSuzuki K Poulose contextid = evsel->core.attr.config & 10230cb76aaSSuzuki K Poulose (BIT(ETM_OPT_CTXTID) | BIT(ETM_OPT_CTXTID2)); 10330cb76aaSSuzuki K Poulose 1043399ad9aSMathieu Poirier /* 10530cb76aaSSuzuki K Poulose * If user doesn't configure the contextid format, parse PMU format and 10630cb76aaSSuzuki K Poulose * enable PID tracing according to the "contextid" format bits: 10730cb76aaSSuzuki K Poulose * 10830cb76aaSSuzuki K Poulose * If bit ETM_OPT_CTXTID is set, trace CONTEXTIDR_EL1; 10930cb76aaSSuzuki K Poulose * If bit ETM_OPT_CTXTID2 is set, trace CONTEXTIDR_EL2. 11030cb76aaSSuzuki K Poulose */ 11130cb76aaSSuzuki K Poulose if (!contextid) 11230cb76aaSSuzuki K Poulose contextid = perf_pmu__format_bits(&cs_etm_pmu->format, 11330cb76aaSSuzuki K Poulose "contextid"); 11430cb76aaSSuzuki K Poulose 11530cb76aaSSuzuki K Poulose if (contextid & BIT(ETM_OPT_CTXTID)) { 11630cb76aaSSuzuki K Poulose /* 11730cb76aaSSuzuki K Poulose * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID 11830cb76aaSSuzuki K Poulose * tracing is supported: 1193399ad9aSMathieu Poirier * 0b00000 Context ID tracing is not supported. 1203399ad9aSMathieu Poirier * 0b00100 Maximum of 32-bit Context ID size. 1213399ad9aSMathieu Poirier * All other values are reserved. 1223399ad9aSMathieu Poirier */ 1233399ad9aSMathieu Poirier val = BMVAL(val, 5, 9); 1243399ad9aSMathieu Poirier if (!val || val != 0x4) { 12530cb76aaSSuzuki K Poulose pr_err("%s: CONTEXTIDR_EL1 isn't supported\n", 12630cb76aaSSuzuki K Poulose CORESIGHT_ETM_PMU_NAME); 1273399ad9aSMathieu Poirier err = -EINVAL; 1283399ad9aSMathieu Poirier goto out; 1293399ad9aSMathieu Poirier } 13030cb76aaSSuzuki K Poulose } 13130cb76aaSSuzuki K Poulose 13230cb76aaSSuzuki K Poulose if (contextid & BIT(ETM_OPT_CTXTID2)) { 13330cb76aaSSuzuki K Poulose /* 13430cb76aaSSuzuki K Poulose * TRCIDR2.VMIDOPT[30:29] != 0 and 13530cb76aaSSuzuki K Poulose * TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid) 13630cb76aaSSuzuki K Poulose * We can't support CONTEXTIDR in VMID if the size of the 13730cb76aaSSuzuki K Poulose * virtual context id is < 32bit. 13830cb76aaSSuzuki K Poulose * Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us. 13930cb76aaSSuzuki K Poulose */ 14030cb76aaSSuzuki K Poulose if (!BMVAL(val, 29, 30) || BMVAL(val, 10, 14) < 4) { 14130cb76aaSSuzuki K Poulose pr_err("%s: CONTEXTIDR_EL2 isn't supported\n", 14230cb76aaSSuzuki K Poulose CORESIGHT_ETM_PMU_NAME); 14330cb76aaSSuzuki K Poulose err = -EINVAL; 14430cb76aaSSuzuki K Poulose goto out; 14530cb76aaSSuzuki K Poulose } 14630cb76aaSSuzuki K Poulose } 1473399ad9aSMathieu Poirier 1483399ad9aSMathieu Poirier /* All good, let the kernel know */ 14930cb76aaSSuzuki K Poulose evsel->core.attr.config |= contextid; 1503399ad9aSMathieu Poirier err = 0; 1513399ad9aSMathieu Poirier 1523399ad9aSMathieu Poirier out: 1533399ad9aSMathieu Poirier return err; 1543399ad9aSMathieu Poirier } 1553399ad9aSMathieu Poirier 1561c839a5aSMathieu Poirier static int cs_etm_set_timestamp(struct auxtrace_record *itr, 15732dcd021SJiri Olsa struct evsel *evsel, int cpu) 1581c839a5aSMathieu Poirier { 1591c839a5aSMathieu Poirier struct cs_etm_recording *ptr; 1601c839a5aSMathieu Poirier struct perf_pmu *cs_etm_pmu; 1611c839a5aSMathieu Poirier char path[PATH_MAX]; 1621c839a5aSMathieu Poirier int err = -EINVAL; 1631c839a5aSMathieu Poirier u32 val; 1641c839a5aSMathieu Poirier 1651c839a5aSMathieu Poirier ptr = container_of(itr, struct cs_etm_recording, itr); 1661c839a5aSMathieu Poirier cs_etm_pmu = ptr->cs_etm_pmu; 1671c839a5aSMathieu Poirier 1681c839a5aSMathieu Poirier if (!cs_etm_is_etmv4(itr, cpu)) 1691c839a5aSMathieu Poirier goto out; 1701c839a5aSMathieu Poirier 1711c839a5aSMathieu Poirier /* Get a handle on TRCIRD0 */ 1721c839a5aSMathieu Poirier snprintf(path, PATH_MAX, "cpu%d/%s", 1731c839a5aSMathieu Poirier cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 1741c839a5aSMathieu Poirier err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 1751c839a5aSMathieu Poirier 1761c839a5aSMathieu Poirier /* There was a problem reading the file, bailing out */ 1771c839a5aSMathieu Poirier if (err != 1) { 1781c839a5aSMathieu Poirier pr_err("%s: can't read file %s\n", 1791c839a5aSMathieu Poirier CORESIGHT_ETM_PMU_NAME, path); 1801c839a5aSMathieu Poirier goto out; 1811c839a5aSMathieu Poirier } 1821c839a5aSMathieu Poirier 1831c839a5aSMathieu Poirier /* 1841c839a5aSMathieu Poirier * TRCIDR0.TSSIZE, bit [28-24], indicates whether global timestamping 1851c839a5aSMathieu Poirier * is supported: 1861c839a5aSMathieu Poirier * 0b00000 Global timestamping is not implemented 1871c839a5aSMathieu Poirier * 0b00110 Implementation supports a maximum timestamp of 48bits. 1881c839a5aSMathieu Poirier * 0b01000 Implementation supports a maximum timestamp of 64bits. 1891c839a5aSMathieu Poirier */ 1901c839a5aSMathieu Poirier val &= GENMASK(28, 24); 1911c839a5aSMathieu Poirier if (!val) { 1921c839a5aSMathieu Poirier err = -EINVAL; 1931c839a5aSMathieu Poirier goto out; 1941c839a5aSMathieu Poirier } 1951c839a5aSMathieu Poirier 1961c839a5aSMathieu Poirier /* All good, let the kernel know */ 1971fc632ceSJiri Olsa evsel->core.attr.config |= (1 << ETM_OPT_TS); 1981c839a5aSMathieu Poirier err = 0; 1991c839a5aSMathieu Poirier 2001c839a5aSMathieu Poirier out: 2011c839a5aSMathieu Poirier return err; 2021c839a5aSMathieu Poirier } 2031c839a5aSMathieu Poirier 2046fc5baf5SSuzuki K Poulose #define ETM_SET_OPT_CTXTID (1 << 0) 2056fc5baf5SSuzuki K Poulose #define ETM_SET_OPT_TS (1 << 1) 2066fc5baf5SSuzuki K Poulose #define ETM_SET_OPT_MASK (ETM_SET_OPT_CTXTID | ETM_SET_OPT_TS) 2076fc5baf5SSuzuki K Poulose 2083399ad9aSMathieu Poirier static int cs_etm_set_option(struct auxtrace_record *itr, 20932dcd021SJiri Olsa struct evsel *evsel, u32 option) 2103399ad9aSMathieu Poirier { 2113399ad9aSMathieu Poirier int i, err = -EINVAL; 2120df6ade7SIan Rogers struct perf_cpu_map *event_cpus = evsel->evlist->core.user_requested_cpus; 2139c3516d1SJiri Olsa struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); 2143399ad9aSMathieu Poirier 2153399ad9aSMathieu Poirier /* Set option of each CPU we have */ 2166d18804bSIan Rogers for (i = 0; i < cpu__max_cpu().cpu; i++) { 2176d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 2186d18804bSIan Rogers 2196d18804bSIan Rogers if (!perf_cpu_map__has(event_cpus, cpu) || 2206d18804bSIan Rogers !perf_cpu_map__has(online_cpus, cpu)) 2213399ad9aSMathieu Poirier continue; 2223399ad9aSMathieu Poirier 2238c559e8dSSuzuki K Poulose if (option & BIT(ETM_OPT_CTXTID)) { 2243399ad9aSMathieu Poirier err = cs_etm_set_context_id(itr, evsel, i); 2253399ad9aSMathieu Poirier if (err) 2263399ad9aSMathieu Poirier goto out; 227374d910fSMathieu Poirier } 2288c559e8dSSuzuki K Poulose if (option & BIT(ETM_OPT_TS)) { 2291c839a5aSMathieu Poirier err = cs_etm_set_timestamp(itr, evsel, i); 2301c839a5aSMathieu Poirier if (err) 2311c839a5aSMathieu Poirier goto out; 2323399ad9aSMathieu Poirier } 2338c559e8dSSuzuki K Poulose if (option & ~(BIT(ETM_OPT_CTXTID) | BIT(ETM_OPT_TS))) 234374d910fSMathieu Poirier /* Nothing else is currently supported */ 235374d910fSMathieu Poirier goto out; 2363399ad9aSMathieu Poirier } 2373399ad9aSMathieu Poirier 2383399ad9aSMathieu Poirier err = 0; 2393399ad9aSMathieu Poirier out: 24038f01d8dSJiri Olsa perf_cpu_map__put(online_cpus); 2413399ad9aSMathieu Poirier return err; 2423399ad9aSMathieu Poirier } 2433399ad9aSMathieu Poirier 244a818c563SMathieu Poirier static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr, 245a818c563SMathieu Poirier struct record_opts *opts, 246a818c563SMathieu Poirier const char *str) 247a818c563SMathieu Poirier { 248a818c563SMathieu Poirier struct cs_etm_recording *ptr = 249a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 250a818c563SMathieu Poirier unsigned long long snapshot_size = 0; 251a818c563SMathieu Poirier char *endptr; 252a818c563SMathieu Poirier 253a818c563SMathieu Poirier if (str) { 254a818c563SMathieu Poirier snapshot_size = strtoull(str, &endptr, 0); 255a818c563SMathieu Poirier if (*endptr || snapshot_size > SIZE_MAX) 256a818c563SMathieu Poirier return -1; 257a818c563SMathieu Poirier } 258a818c563SMathieu Poirier 259a818c563SMathieu Poirier opts->auxtrace_snapshot_mode = true; 260a818c563SMathieu Poirier opts->auxtrace_snapshot_size = snapshot_size; 261a818c563SMathieu Poirier ptr->snapshot_size = snapshot_size; 262a818c563SMathieu Poirier 263a818c563SMathieu Poirier return 0; 264a818c563SMathieu Poirier } 265a818c563SMathieu Poirier 266fa4e819bSMathieu Poirier static int cs_etm_set_sink_attr(struct perf_pmu *pmu, 26732dcd021SJiri Olsa struct evsel *evsel) 268fa4e819bSMathieu Poirier { 269fa4e819bSMathieu Poirier char msg[BUFSIZ], path[PATH_MAX], *sink; 27035ac0cadSArnaldo Carvalho de Melo struct evsel_config_term *term; 271fa4e819bSMathieu Poirier int ret = -EINVAL; 272fa4e819bSMathieu Poirier u32 hash; 273fa4e819bSMathieu Poirier 2741fc632ceSJiri Olsa if (evsel->core.attr.config2 & GENMASK(31, 0)) 275fa4e819bSMathieu Poirier return 0; 276fa4e819bSMathieu Poirier 277fa4e819bSMathieu Poirier list_for_each_entry(term, &evsel->config_terms, list) { 27835ac0cadSArnaldo Carvalho de Melo if (term->type != EVSEL__CONFIG_TERM_DRV_CFG) 279fa4e819bSMathieu Poirier continue; 280fa4e819bSMathieu Poirier 281e884602bSLeo Yan sink = term->val.str; 282fa4e819bSMathieu Poirier snprintf(path, PATH_MAX, "sinks/%s", sink); 283fa4e819bSMathieu Poirier 284fa4e819bSMathieu Poirier ret = perf_pmu__scan_file(pmu, path, "%x", &hash); 285fa4e819bSMathieu Poirier if (ret != 1) { 2866bc75b4cSJames Clark if (errno == ENOENT) 2876bc75b4cSJames Clark pr_err("Couldn't find sink \"%s\" on event %s\n" 2886bc75b4cSJames Clark "Missing kernel or device support?\n\n" 2896bc75b4cSJames Clark "Hint: An appropriate sink will be picked automatically if one isn't specified.\n", 2906bc75b4cSJames Clark sink, evsel__name(evsel)); 2916bc75b4cSJames Clark else 2926bc75b4cSJames Clark pr_err("Failed to set sink \"%s\" on event %s with %d (%s)\n", 2938ab2e96dSArnaldo Carvalho de Melo sink, evsel__name(evsel), errno, 294fa4e819bSMathieu Poirier str_error_r(errno, msg, sizeof(msg))); 295fa4e819bSMathieu Poirier return ret; 296fa4e819bSMathieu Poirier } 297fa4e819bSMathieu Poirier 2981fc632ceSJiri Olsa evsel->core.attr.config2 |= hash; 299fa4e819bSMathieu Poirier return 0; 300fa4e819bSMathieu Poirier } 301fa4e819bSMathieu Poirier 302fa4e819bSMathieu Poirier /* 30347446212SMike Leach * No sink was provided on the command line - allow the CoreSight 30447446212SMike Leach * system to look for a default 305fa4e819bSMathieu Poirier */ 30647446212SMike Leach return 0; 307fa4e819bSMathieu Poirier } 308fa4e819bSMathieu Poirier 309a818c563SMathieu Poirier static int cs_etm_recording_options(struct auxtrace_record *itr, 31063503dbaSJiri Olsa struct evlist *evlist, 311a818c563SMathieu Poirier struct record_opts *opts) 312a818c563SMathieu Poirier { 313fa4e819bSMathieu Poirier int ret; 314a818c563SMathieu Poirier struct cs_etm_recording *ptr = 315a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 316a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 31732dcd021SJiri Olsa struct evsel *evsel, *cs_etm_evsel = NULL; 3180df6ade7SIan Rogers struct perf_cpu_map *cpus = evlist->core.user_requested_cpus; 319dda1bf8eSIgor Lubashev bool privileged = perf_event_paranoid_check(-1); 3203399ad9aSMathieu Poirier int err = 0; 321a818c563SMathieu Poirier 322a818c563SMathieu Poirier ptr->evlist = evlist; 323a818c563SMathieu Poirier ptr->snapshot_mode = opts->auxtrace_snapshot_mode; 324a818c563SMathieu Poirier 32516b4b4e1SAdrian Hunter if (!record_opts__no_switch_events(opts) && 32616b4b4e1SAdrian Hunter perf_can_record_switch_events()) 327e5993c42SMathieu Poirier opts->record_switch_events = true; 328e5993c42SMathieu Poirier 329a818c563SMathieu Poirier evlist__for_each_entry(evlist, evsel) { 3301fc632ceSJiri Olsa if (evsel->core.attr.type == cs_etm_pmu->type) { 331a818c563SMathieu Poirier if (cs_etm_evsel) { 332a818c563SMathieu Poirier pr_err("There may be only one %s event\n", 333a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 334a818c563SMathieu Poirier return -EINVAL; 335a818c563SMathieu Poirier } 3361fc632ceSJiri Olsa evsel->core.attr.freq = 0; 3371fc632ceSJiri Olsa evsel->core.attr.sample_period = 1; 3387df319e5SAdrian Hunter evsel->needs_auxtrace_mmap = true; 339a818c563SMathieu Poirier cs_etm_evsel = evsel; 340a818c563SMathieu Poirier opts->full_auxtrace = true; 341a818c563SMathieu Poirier } 342a818c563SMathieu Poirier } 343a818c563SMathieu Poirier 344a818c563SMathieu Poirier /* no need to continue if at least one event of interest was found */ 345a818c563SMathieu Poirier if (!cs_etm_evsel) 346a818c563SMathieu Poirier return 0; 347a818c563SMathieu Poirier 348fa4e819bSMathieu Poirier ret = cs_etm_set_sink_attr(cs_etm_pmu, cs_etm_evsel); 349fa4e819bSMathieu Poirier if (ret) 350fa4e819bSMathieu Poirier return ret; 351fa4e819bSMathieu Poirier 352a818c563SMathieu Poirier if (opts->use_clockid) { 353a818c563SMathieu Poirier pr_err("Cannot use clockid (-k option) with %s\n", 354a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 355a818c563SMathieu Poirier return -EINVAL; 356a818c563SMathieu Poirier } 357a818c563SMathieu Poirier 358a818c563SMathieu Poirier /* we are in snapshot mode */ 359a818c563SMathieu Poirier if (opts->auxtrace_snapshot_mode) { 360a818c563SMathieu Poirier /* 361a818c563SMathieu Poirier * No size were given to '-S' or '-m,', so go with 362a818c563SMathieu Poirier * the default 363a818c563SMathieu Poirier */ 364a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size && 365a818c563SMathieu Poirier !opts->auxtrace_mmap_pages) { 366a818c563SMathieu Poirier if (privileged) { 367a818c563SMathieu Poirier opts->auxtrace_mmap_pages = MiB(4) / page_size; 368a818c563SMathieu Poirier } else { 369a818c563SMathieu Poirier opts->auxtrace_mmap_pages = 370a818c563SMathieu Poirier KiB(128) / page_size; 371a818c563SMathieu Poirier if (opts->mmap_pages == UINT_MAX) 372a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 373a818c563SMathieu Poirier } 374a818c563SMathieu Poirier } else if (!opts->auxtrace_mmap_pages && !privileged && 375a818c563SMathieu Poirier opts->mmap_pages == UINT_MAX) { 376a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 377a818c563SMathieu Poirier } 378a818c563SMathieu Poirier 379a818c563SMathieu Poirier /* 380a818c563SMathieu Poirier * '-m,xyz' was specified but no snapshot size, so make the 381a818c563SMathieu Poirier * snapshot size as big as the auxtrace mmap area. 382a818c563SMathieu Poirier */ 383a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size) { 384a818c563SMathieu Poirier opts->auxtrace_snapshot_size = 385a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size; 386a818c563SMathieu Poirier } 387a818c563SMathieu Poirier 388a818c563SMathieu Poirier /* 389a818c563SMathieu Poirier * -Sxyz was specified but no auxtrace mmap area, so make the 390a818c563SMathieu Poirier * auxtrace mmap area big enough to fit the requested snapshot 391a818c563SMathieu Poirier * size. 392a818c563SMathieu Poirier */ 393a818c563SMathieu Poirier if (!opts->auxtrace_mmap_pages) { 394a818c563SMathieu Poirier size_t sz = opts->auxtrace_snapshot_size; 395a818c563SMathieu Poirier 396a818c563SMathieu Poirier sz = round_up(sz, page_size) / page_size; 397a818c563SMathieu Poirier opts->auxtrace_mmap_pages = roundup_pow_of_two(sz); 398a818c563SMathieu Poirier } 399a818c563SMathieu Poirier 4004d39c89fSIngo Molnar /* Snapshot size can't be bigger than the auxtrace area */ 401a818c563SMathieu Poirier if (opts->auxtrace_snapshot_size > 402a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size) { 403a818c563SMathieu Poirier pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n", 404a818c563SMathieu Poirier opts->auxtrace_snapshot_size, 405a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size); 406a818c563SMathieu Poirier return -EINVAL; 407a818c563SMathieu Poirier } 408a818c563SMathieu Poirier 409a818c563SMathieu Poirier /* Something went wrong somewhere - this shouldn't happen */ 410a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size || 411a818c563SMathieu Poirier !opts->auxtrace_mmap_pages) { 412a818c563SMathieu Poirier pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n"); 413a818c563SMathieu Poirier return -EINVAL; 414a818c563SMathieu Poirier } 415a818c563SMathieu Poirier } 416a818c563SMathieu Poirier 417a818c563SMathieu Poirier /* We are in full trace mode but '-m,xyz' wasn't specified */ 418a818c563SMathieu Poirier if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) { 419a818c563SMathieu Poirier if (privileged) { 420a818c563SMathieu Poirier opts->auxtrace_mmap_pages = MiB(4) / page_size; 421a818c563SMathieu Poirier } else { 422a818c563SMathieu Poirier opts->auxtrace_mmap_pages = KiB(128) / page_size; 423a818c563SMathieu Poirier if (opts->mmap_pages == UINT_MAX) 424a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 425a818c563SMathieu Poirier } 426a818c563SMathieu Poirier 427a818c563SMathieu Poirier } 428a818c563SMathieu Poirier 429a818c563SMathieu Poirier if (opts->auxtrace_snapshot_mode) 430a818c563SMathieu Poirier pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME, 431a818c563SMathieu Poirier opts->auxtrace_snapshot_size); 432a818c563SMathieu Poirier 433a818c563SMathieu Poirier /* 434a818c563SMathieu Poirier * To obtain the auxtrace buffer file descriptor, the auxtrace 435a818c563SMathieu Poirier * event must come first. 436a818c563SMathieu Poirier */ 437e414fd1aSArnaldo Carvalho de Melo evlist__to_front(evlist, cs_etm_evsel); 4380c788d47SKim Phillips 439a818c563SMathieu Poirier /* 440a818c563SMathieu Poirier * In the case of per-cpu mmaps, we need the CPU on the 4413399ad9aSMathieu Poirier * AUX event. We also need the contextID in order to be notified 4423399ad9aSMathieu Poirier * when a context switch happened. 443a818c563SMathieu Poirier */ 444315c0a1fSJiri Olsa if (!perf_cpu_map__empty(cpus)) { 445862b2f8fSArnaldo Carvalho de Melo evsel__set_sample_bit(cs_etm_evsel, CPU); 446a818c563SMathieu Poirier 447374d910fSMathieu Poirier err = cs_etm_set_option(itr, cs_etm_evsel, 4488c559e8dSSuzuki K Poulose BIT(ETM_OPT_CTXTID) | BIT(ETM_OPT_TS)); 4491c839a5aSMathieu Poirier if (err) 4501c839a5aSMathieu Poirier goto out; 4513399ad9aSMathieu Poirier } 4523399ad9aSMathieu Poirier 453a818c563SMathieu Poirier /* Add dummy event to keep tracking */ 454a818c563SMathieu Poirier if (opts->full_auxtrace) { 45532dcd021SJiri Olsa struct evsel *tracking_evsel; 456a818c563SMathieu Poirier 457806731a9SAdrian Hunter err = parse_event(evlist, "dummy:u"); 458a818c563SMathieu Poirier if (err) 4593399ad9aSMathieu Poirier goto out; 460a818c563SMathieu Poirier 461515dbe48SJiri Olsa tracking_evsel = evlist__last(evlist); 462e80db255SArnaldo Carvalho de Melo evlist__set_tracking_event(evlist, tracking_evsel); 463a818c563SMathieu Poirier 4641fc632ceSJiri Olsa tracking_evsel->core.attr.freq = 0; 4651fc632ceSJiri Olsa tracking_evsel->core.attr.sample_period = 1; 466a818c563SMathieu Poirier 467a818c563SMathieu Poirier /* In per-cpu case, always need the time of mmap events etc */ 468315c0a1fSJiri Olsa if (!perf_cpu_map__empty(cpus)) 469862b2f8fSArnaldo Carvalho de Melo evsel__set_sample_bit(tracking_evsel, TIME); 470a818c563SMathieu Poirier } 471a818c563SMathieu Poirier 4723399ad9aSMathieu Poirier out: 4733399ad9aSMathieu Poirier return err; 474a818c563SMathieu Poirier } 475a818c563SMathieu Poirier 476a818c563SMathieu Poirier static u64 cs_etm_get_config(struct auxtrace_record *itr) 477a818c563SMathieu Poirier { 478a818c563SMathieu Poirier u64 config = 0; 479a818c563SMathieu Poirier struct cs_etm_recording *ptr = 480a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 481a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 48263503dbaSJiri Olsa struct evlist *evlist = ptr->evlist; 48332dcd021SJiri Olsa struct evsel *evsel; 484a818c563SMathieu Poirier 485a818c563SMathieu Poirier evlist__for_each_entry(evlist, evsel) { 4861fc632ceSJiri Olsa if (evsel->core.attr.type == cs_etm_pmu->type) { 487a818c563SMathieu Poirier /* 488a818c563SMathieu Poirier * Variable perf_event_attr::config is assigned to 489a818c563SMathieu Poirier * ETMv3/PTM. The bit fields have been made to match 490a818c563SMathieu Poirier * the ETMv3.5 ETRMCR register specification. See the 491a818c563SMathieu Poirier * PMU_FORMAT_ATTR() declarations in 492a818c563SMathieu Poirier * drivers/hwtracing/coresight/coresight-perf.c for 493a818c563SMathieu Poirier * details. 494a818c563SMathieu Poirier */ 4951fc632ceSJiri Olsa config = evsel->core.attr.config; 496a818c563SMathieu Poirier break; 497a818c563SMathieu Poirier } 498a818c563SMathieu Poirier } 499a818c563SMathieu Poirier 500a818c563SMathieu Poirier return config; 501a818c563SMathieu Poirier } 502a818c563SMathieu Poirier 503df770ff0SMike Leach #ifndef BIT 504df770ff0SMike Leach #define BIT(N) (1UL << (N)) 505df770ff0SMike Leach #endif 506df770ff0SMike Leach 507df770ff0SMike Leach static u64 cs_etmv4_get_config(struct auxtrace_record *itr) 508df770ff0SMike Leach { 509df770ff0SMike Leach u64 config = 0; 510df770ff0SMike Leach u64 config_opts = 0; 511df770ff0SMike Leach 512df770ff0SMike Leach /* 513df770ff0SMike Leach * The perf event variable config bits represent both 514df770ff0SMike Leach * the command line options and register programming 515df770ff0SMike Leach * bits in ETMv3/PTM. For ETMv4 we must remap options 516df770ff0SMike Leach * to real bits 517df770ff0SMike Leach */ 518df770ff0SMike Leach config_opts = cs_etm_get_config(itr); 519df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_CYCACC)) 520df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_CYCACC); 5213399ad9aSMathieu Poirier if (config_opts & BIT(ETM_OPT_CTXTID)) 5223399ad9aSMathieu Poirier config |= BIT(ETM4_CFG_BIT_CTXTID); 523df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_TS)) 524df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_TS); 525df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_RETSTK)) 526df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_RETSTK); 52730cb76aaSSuzuki K Poulose if (config_opts & BIT(ETM_OPT_CTXTID2)) 52830cb76aaSSuzuki K Poulose config |= BIT(ETM4_CFG_BIT_VMID) | 52930cb76aaSSuzuki K Poulose BIT(ETM4_CFG_BIT_VMID_OPT); 530aca8af3cSJames Clark if (config_opts & BIT(ETM_OPT_BRANCH_BROADCAST)) 531aca8af3cSJames Clark config |= BIT(ETM4_CFG_BIT_BB); 532aca8af3cSJames Clark 533df770ff0SMike Leach return config; 534df770ff0SMike Leach } 535df770ff0SMike Leach 536a818c563SMathieu Poirier static size_t 537a818c563SMathieu Poirier cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, 53863503dbaSJiri Olsa struct evlist *evlist __maybe_unused) 539a818c563SMathieu Poirier { 540a818c563SMathieu Poirier int i; 54151ba8811SJames Clark int etmv3 = 0, etmv4 = 0, ete = 0; 5420df6ade7SIan Rogers struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus; 5439c3516d1SJiri Olsa struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); 544a818c563SMathieu Poirier 545a818c563SMathieu Poirier /* cpu map is not empty, we have specific CPUs to work with */ 546315c0a1fSJiri Olsa if (!perf_cpu_map__empty(event_cpus)) { 5476d18804bSIan Rogers for (i = 0; i < cpu__max_cpu().cpu; i++) { 5486d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 5496d18804bSIan Rogers 5506d18804bSIan Rogers if (!perf_cpu_map__has(event_cpus, cpu) || 5516d18804bSIan Rogers !perf_cpu_map__has(online_cpus, cpu)) 552796bfaddSMathieu Poirier continue; 553796bfaddSMathieu Poirier 55451ba8811SJames Clark if (cs_etm_is_ete(itr, i)) 55551ba8811SJames Clark ete++; 55651ba8811SJames Clark else if (cs_etm_is_etmv4(itr, i)) 557a818c563SMathieu Poirier etmv4++; 558a818c563SMathieu Poirier else 559a818c563SMathieu Poirier etmv3++; 560a818c563SMathieu Poirier } 561a818c563SMathieu Poirier } else { 562a818c563SMathieu Poirier /* get configuration for all CPUs in the system */ 5636d18804bSIan Rogers for (i = 0; i < cpu__max_cpu().cpu; i++) { 5646d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 5656d18804bSIan Rogers 5666d18804bSIan Rogers if (!perf_cpu_map__has(online_cpus, cpu)) 567796bfaddSMathieu Poirier continue; 568796bfaddSMathieu Poirier 56951ba8811SJames Clark if (cs_etm_is_ete(itr, i)) 57051ba8811SJames Clark ete++; 57151ba8811SJames Clark else if (cs_etm_is_etmv4(itr, i)) 572a818c563SMathieu Poirier etmv4++; 573a818c563SMathieu Poirier else 574a818c563SMathieu Poirier etmv3++; 575a818c563SMathieu Poirier } 576a818c563SMathieu Poirier } 577a818c563SMathieu Poirier 57838f01d8dSJiri Olsa perf_cpu_map__put(online_cpus); 579796bfaddSMathieu Poirier 580a818c563SMathieu Poirier return (CS_ETM_HEADER_SIZE + 58151ba8811SJames Clark (ete * CS_ETE_PRIV_SIZE) + 582a818c563SMathieu Poirier (etmv4 * CS_ETMV4_PRIV_SIZE) + 583a818c563SMathieu Poirier (etmv3 * CS_ETMV3_PRIV_SIZE)); 584a818c563SMathieu Poirier } 585a818c563SMathieu Poirier 586a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu) 587a818c563SMathieu Poirier { 588a818c563SMathieu Poirier bool ret = false; 589a818c563SMathieu Poirier char path[PATH_MAX]; 590a818c563SMathieu Poirier int scan; 591a818c563SMathieu Poirier unsigned int val; 592a818c563SMathieu Poirier struct cs_etm_recording *ptr = 593a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 594a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 595a818c563SMathieu Poirier 596a818c563SMathieu Poirier /* Take any of the RO files for ETMv4 and see if it present */ 597a818c563SMathieu Poirier snprintf(path, PATH_MAX, "cpu%d/%s", 598a818c563SMathieu Poirier cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 599a818c563SMathieu Poirier scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 600a818c563SMathieu Poirier 601a818c563SMathieu Poirier /* The file was read successfully, we have a winner */ 602a818c563SMathieu Poirier if (scan == 1) 603a818c563SMathieu Poirier ret = true; 604a818c563SMathieu Poirier 605a818c563SMathieu Poirier return ret; 606a818c563SMathieu Poirier } 607a818c563SMathieu Poirier 608a818c563SMathieu Poirier static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path) 609a818c563SMathieu Poirier { 610a818c563SMathieu Poirier char pmu_path[PATH_MAX]; 611a818c563SMathieu Poirier int scan; 612a818c563SMathieu Poirier unsigned int val = 0; 613a818c563SMathieu Poirier 614a818c563SMathieu Poirier /* Get RO metadata from sysfs */ 615a818c563SMathieu Poirier snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 616a818c563SMathieu Poirier 617a818c563SMathieu Poirier scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val); 618a818c563SMathieu Poirier if (scan != 1) 619a818c563SMathieu Poirier pr_err("%s: error reading: %s\n", __func__, pmu_path); 620a818c563SMathieu Poirier 621a818c563SMathieu Poirier return val; 622a818c563SMathieu Poirier } 623a818c563SMathieu Poirier 6242e2f7ceeSGerman Gomez static int cs_etm_get_ro_signed(struct perf_pmu *pmu, int cpu, const char *path) 6252e2f7ceeSGerman Gomez { 6262e2f7ceeSGerman Gomez char pmu_path[PATH_MAX]; 6272e2f7ceeSGerman Gomez int scan; 6282e2f7ceeSGerman Gomez int val = 0; 6292e2f7ceeSGerman Gomez 6302e2f7ceeSGerman Gomez /* Get RO metadata from sysfs */ 6312e2f7ceeSGerman Gomez snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 6322e2f7ceeSGerman Gomez 6332e2f7ceeSGerman Gomez scan = perf_pmu__scan_file(pmu, pmu_path, "%d", &val); 6342e2f7ceeSGerman Gomez if (scan != 1) 6352e2f7ceeSGerman Gomez pr_err("%s: error reading: %s\n", __func__, pmu_path); 6362e2f7ceeSGerman Gomez 6372e2f7ceeSGerman Gomez return val; 6382e2f7ceeSGerman Gomez } 6392e2f7ceeSGerman Gomez 6402e2f7ceeSGerman Gomez static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, int cpu, const char *path) 6412e2f7ceeSGerman Gomez { 6422e2f7ceeSGerman Gomez char pmu_path[PATH_MAX]; 6432e2f7ceeSGerman Gomez 6442e2f7ceeSGerman Gomez /* Get RO metadata from sysfs */ 6452e2f7ceeSGerman Gomez snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 6462e2f7ceeSGerman Gomez 6472e2f7ceeSGerman Gomez return perf_pmu__file_exists(pmu, pmu_path); 6482e2f7ceeSGerman Gomez } 6492e2f7ceeSGerman Gomez 65051ba8811SJames Clark #define TRCDEVARCH_ARCHPART_SHIFT 0 65151ba8811SJames Clark #define TRCDEVARCH_ARCHPART_MASK GENMASK(11, 0) 65251ba8811SJames Clark #define TRCDEVARCH_ARCHPART(x) (((x) & TRCDEVARCH_ARCHPART_MASK) >> TRCDEVARCH_ARCHPART_SHIFT) 65351ba8811SJames Clark 65451ba8811SJames Clark #define TRCDEVARCH_ARCHVER_SHIFT 12 65551ba8811SJames Clark #define TRCDEVARCH_ARCHVER_MASK GENMASK(15, 12) 65651ba8811SJames Clark #define TRCDEVARCH_ARCHVER(x) (((x) & TRCDEVARCH_ARCHVER_MASK) >> TRCDEVARCH_ARCHVER_SHIFT) 65751ba8811SJames Clark 65851ba8811SJames Clark static bool cs_etm_is_ete(struct auxtrace_record *itr, int cpu) 65951ba8811SJames Clark { 66051ba8811SJames Clark struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); 66151ba8811SJames Clark struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 662*e5af1397SJames Clark int trcdevarch; 66351ba8811SJames Clark 664*e5af1397SJames Clark if (!cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH])) 665*e5af1397SJames Clark return false; 666*e5af1397SJames Clark 667*e5af1397SJames Clark trcdevarch = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH]); 66851ba8811SJames Clark /* 66951ba8811SJames Clark * ETE if ARCHVER is 5 (ARCHVER is 4 for ETM) and ARCHPART is 0xA13. 67051ba8811SJames Clark * See ETM_DEVARCH_ETE_ARCH in coresight-etm4x.h 67151ba8811SJames Clark */ 67251ba8811SJames Clark return TRCDEVARCH_ARCHVER(trcdevarch) == 5 && TRCDEVARCH_ARCHPART(trcdevarch) == 0xA13; 67351ba8811SJames Clark } 67451ba8811SJames Clark 675c9ccc96bSJames Clark static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr, int cpu) 676c9ccc96bSJames Clark { 677c9ccc96bSJames Clark struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); 678c9ccc96bSJames Clark struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 679c9ccc96bSJames Clark 680c9ccc96bSJames Clark /* Get trace configuration register */ 681c9ccc96bSJames Clark data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_get_config(itr); 682c9ccc96bSJames Clark /* Get traceID from the framework */ 683c9ccc96bSJames Clark data[CS_ETMV4_TRCTRACEIDR] = coresight_get_trace_id(cpu); 684c9ccc96bSJames Clark /* Get read-only information from sysFS */ 685c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR0] = cs_etm_get_ro(cs_etm_pmu, cpu, 686c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 687c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR1] = cs_etm_get_ro(cs_etm_pmu, cpu, 688c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR1]); 689c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR2] = cs_etm_get_ro(cs_etm_pmu, cpu, 690c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); 691c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR8] = cs_etm_get_ro(cs_etm_pmu, cpu, 692c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR8]); 693c9ccc96bSJames Clark data[CS_ETMV4_TRCAUTHSTATUS] = cs_etm_get_ro(cs_etm_pmu, cpu, 694c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCAUTHSTATUS]); 6952e2f7ceeSGerman Gomez 6962e2f7ceeSGerman Gomez /* Kernels older than 5.19 may not expose ts_source */ 6972e2f7ceeSGerman Gomez if (cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TS_SOURCE])) 6982e2f7ceeSGerman Gomez data[CS_ETMV4_TS_SOURCE] = (__u64) cs_etm_get_ro_signed(cs_etm_pmu, cpu, 6992e2f7ceeSGerman Gomez metadata_etmv4_ro[CS_ETMV4_TS_SOURCE]); 7002e2f7ceeSGerman Gomez else { 7015f968d28SJames Clark pr_debug3("[%03d] pmu file 'ts_source' not found. Fallback to safe value (-1)\n", 7022e2f7ceeSGerman Gomez cpu); 7032e2f7ceeSGerman Gomez data[CS_ETMV4_TS_SOURCE] = (__u64) -1; 7042e2f7ceeSGerman Gomez } 705c9ccc96bSJames Clark } 706c9ccc96bSJames Clark 707326163c5SGerman Gomez static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *itr, int cpu) 708326163c5SGerman Gomez { 709326163c5SGerman Gomez struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); 710326163c5SGerman Gomez struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 711326163c5SGerman Gomez 712326163c5SGerman Gomez /* Get trace configuration register */ 713326163c5SGerman Gomez data[CS_ETE_TRCCONFIGR] = cs_etmv4_get_config(itr); 714326163c5SGerman Gomez /* Get traceID from the framework */ 715326163c5SGerman Gomez data[CS_ETE_TRCTRACEIDR] = coresight_get_trace_id(cpu); 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); 771a818c563SMathieu Poirier /* Get traceID from the framework */ 772a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMTRACEIDR] = 773a818c563SMathieu Poirier coresight_get_trace_id(cpu); 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; 8059c3516d1SJiri Olsa struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); 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 */ 817315c0a1fSJiri Olsa if (perf_cpu_map__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 902a818c563SMathieu Poirier cs_etm_pmu = perf_pmu__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 } 932