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 evlist__for_each_entry(evlist, evsel) { 3231fc632ceSJiri Olsa if (evsel->core.attr.type == cs_etm_pmu->type) { 324a818c563SMathieu Poirier if (cs_etm_evsel) { 325a818c563SMathieu Poirier pr_err("There may be only one %s event\n", 326a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 327a818c563SMathieu Poirier return -EINVAL; 328a818c563SMathieu Poirier } 329a818c563SMathieu Poirier cs_etm_evsel = evsel; 330a818c563SMathieu Poirier } 331a818c563SMathieu Poirier } 332a818c563SMathieu Poirier 333a818c563SMathieu Poirier /* no need to continue if at least one event of interest was found */ 334a818c563SMathieu Poirier if (!cs_etm_evsel) 335a818c563SMathieu Poirier return 0; 336a818c563SMathieu Poirier 337*3963d84bSJames Clark ptr->evlist = evlist; 338*3963d84bSJames Clark ptr->snapshot_mode = opts->auxtrace_snapshot_mode; 339*3963d84bSJames Clark 340*3963d84bSJames Clark if (!record_opts__no_switch_events(opts) && 341*3963d84bSJames Clark perf_can_record_switch_events()) 342*3963d84bSJames Clark opts->record_switch_events = true; 343*3963d84bSJames Clark 344*3963d84bSJames Clark cs_etm_evsel->core.attr.freq = 0; 345*3963d84bSJames Clark cs_etm_evsel->core.attr.sample_period = 1; 346*3963d84bSJames Clark cs_etm_evsel->needs_auxtrace_mmap = true; 347*3963d84bSJames Clark opts->full_auxtrace = true; 348*3963d84bSJames Clark 349fa4e819bSMathieu Poirier ret = cs_etm_set_sink_attr(cs_etm_pmu, cs_etm_evsel); 350fa4e819bSMathieu Poirier if (ret) 351fa4e819bSMathieu Poirier return ret; 352fa4e819bSMathieu Poirier 353a818c563SMathieu Poirier if (opts->use_clockid) { 354a818c563SMathieu Poirier pr_err("Cannot use clockid (-k option) with %s\n", 355a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 356a818c563SMathieu Poirier return -EINVAL; 357a818c563SMathieu Poirier } 358a818c563SMathieu Poirier 359a818c563SMathieu Poirier /* we are in snapshot mode */ 360a818c563SMathieu Poirier if (opts->auxtrace_snapshot_mode) { 361a818c563SMathieu Poirier /* 362a818c563SMathieu Poirier * No size were given to '-S' or '-m,', so go with 363a818c563SMathieu Poirier * the default 364a818c563SMathieu Poirier */ 365a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size && 366a818c563SMathieu Poirier !opts->auxtrace_mmap_pages) { 367a818c563SMathieu Poirier if (privileged) { 368a818c563SMathieu Poirier opts->auxtrace_mmap_pages = MiB(4) / page_size; 369a818c563SMathieu Poirier } else { 370a818c563SMathieu Poirier opts->auxtrace_mmap_pages = 371a818c563SMathieu Poirier KiB(128) / page_size; 372a818c563SMathieu Poirier if (opts->mmap_pages == UINT_MAX) 373a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 374a818c563SMathieu Poirier } 375a818c563SMathieu Poirier } else if (!opts->auxtrace_mmap_pages && !privileged && 376a818c563SMathieu Poirier opts->mmap_pages == UINT_MAX) { 377a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 378a818c563SMathieu Poirier } 379a818c563SMathieu Poirier 380a818c563SMathieu Poirier /* 381a818c563SMathieu Poirier * '-m,xyz' was specified but no snapshot size, so make the 382a818c563SMathieu Poirier * snapshot size as big as the auxtrace mmap area. 383a818c563SMathieu Poirier */ 384a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size) { 385a818c563SMathieu Poirier opts->auxtrace_snapshot_size = 386a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size; 387a818c563SMathieu Poirier } 388a818c563SMathieu Poirier 389a818c563SMathieu Poirier /* 390a818c563SMathieu Poirier * -Sxyz was specified but no auxtrace mmap area, so make the 391a818c563SMathieu Poirier * auxtrace mmap area big enough to fit the requested snapshot 392a818c563SMathieu Poirier * size. 393a818c563SMathieu Poirier */ 394a818c563SMathieu Poirier if (!opts->auxtrace_mmap_pages) { 395a818c563SMathieu Poirier size_t sz = opts->auxtrace_snapshot_size; 396a818c563SMathieu Poirier 397a818c563SMathieu Poirier sz = round_up(sz, page_size) / page_size; 398a818c563SMathieu Poirier opts->auxtrace_mmap_pages = roundup_pow_of_two(sz); 399a818c563SMathieu Poirier } 400a818c563SMathieu Poirier 4014d39c89fSIngo Molnar /* Snapshot size can't be bigger than the auxtrace area */ 402a818c563SMathieu Poirier if (opts->auxtrace_snapshot_size > 403a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size) { 404a818c563SMathieu Poirier pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n", 405a818c563SMathieu Poirier opts->auxtrace_snapshot_size, 406a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size); 407a818c563SMathieu Poirier return -EINVAL; 408a818c563SMathieu Poirier } 409a818c563SMathieu Poirier 410a818c563SMathieu Poirier /* Something went wrong somewhere - this shouldn't happen */ 411a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size || 412a818c563SMathieu Poirier !opts->auxtrace_mmap_pages) { 413a818c563SMathieu Poirier pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n"); 414a818c563SMathieu Poirier return -EINVAL; 415a818c563SMathieu Poirier } 416a818c563SMathieu Poirier } 417a818c563SMathieu Poirier 418*3963d84bSJames Clark /* Buffer sizes weren't specified with '-m,xyz' so give some defaults */ 419*3963d84bSJames Clark if (!opts->auxtrace_mmap_pages) { 420a818c563SMathieu Poirier if (privileged) { 421a818c563SMathieu Poirier opts->auxtrace_mmap_pages = MiB(4) / page_size; 422a818c563SMathieu Poirier } else { 423a818c563SMathieu Poirier opts->auxtrace_mmap_pages = KiB(128) / page_size; 424a818c563SMathieu Poirier if (opts->mmap_pages == UINT_MAX) 425a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 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 /* 440e5fa5b41SMike Leach * get the CPU on the sample - need it to associate trace ID in the 441e5fa5b41SMike Leach * AUX_OUTPUT_HW_ID event, and the AUX event for per-cpu mmaps. 442e5fa5b41SMike Leach */ 443e5fa5b41SMike Leach evsel__set_sample_bit(cs_etm_evsel, CPU); 444e5fa5b41SMike Leach 445e5fa5b41SMike Leach /* 446e5fa5b41SMike Leach * Also the case of per-cpu mmaps, need the contextID in order to be notified 4473399ad9aSMathieu Poirier * when a context switch happened. 448a818c563SMathieu Poirier */ 449315c0a1fSJiri Olsa if (!perf_cpu_map__empty(cpus)) { 450374d910fSMathieu Poirier err = cs_etm_set_option(itr, cs_etm_evsel, 4518c559e8dSSuzuki K Poulose BIT(ETM_OPT_CTXTID) | BIT(ETM_OPT_TS)); 4521c839a5aSMathieu Poirier if (err) 4531c839a5aSMathieu Poirier goto out; 4543399ad9aSMathieu Poirier } 4553399ad9aSMathieu Poirier 456a818c563SMathieu Poirier /* Add dummy event to keep tracking */ 457806731a9SAdrian Hunter err = parse_event(evlist, "dummy:u"); 458a818c563SMathieu Poirier if (err) 4593399ad9aSMathieu Poirier goto out; 460*3963d84bSJames Clark evsel = evlist__last(evlist); 461*3963d84bSJames Clark evlist__set_tracking_event(evlist, evsel); 462*3963d84bSJames Clark evsel->core.attr.freq = 0; 463*3963d84bSJames Clark evsel->core.attr.sample_period = 1; 464a818c563SMathieu Poirier 465a818c563SMathieu Poirier /* In per-cpu case, always need the time of mmap events etc */ 466315c0a1fSJiri Olsa if (!perf_cpu_map__empty(cpus)) 467*3963d84bSJames Clark evsel__set_sample_bit(evsel, TIME); 468a818c563SMathieu Poirier 4693399ad9aSMathieu Poirier out: 4703399ad9aSMathieu Poirier return err; 471a818c563SMathieu Poirier } 472a818c563SMathieu Poirier 473a818c563SMathieu Poirier static u64 cs_etm_get_config(struct auxtrace_record *itr) 474a818c563SMathieu Poirier { 475a818c563SMathieu Poirier u64 config = 0; 476a818c563SMathieu Poirier struct cs_etm_recording *ptr = 477a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 478a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 47963503dbaSJiri Olsa struct evlist *evlist = ptr->evlist; 48032dcd021SJiri Olsa struct evsel *evsel; 481a818c563SMathieu Poirier 482a818c563SMathieu Poirier evlist__for_each_entry(evlist, evsel) { 4831fc632ceSJiri Olsa if (evsel->core.attr.type == cs_etm_pmu->type) { 484a818c563SMathieu Poirier /* 485a818c563SMathieu Poirier * Variable perf_event_attr::config is assigned to 486a818c563SMathieu Poirier * ETMv3/PTM. The bit fields have been made to match 487a818c563SMathieu Poirier * the ETMv3.5 ETRMCR register specification. See the 488a818c563SMathieu Poirier * PMU_FORMAT_ATTR() declarations in 489a818c563SMathieu Poirier * drivers/hwtracing/coresight/coresight-perf.c for 490a818c563SMathieu Poirier * details. 491a818c563SMathieu Poirier */ 4921fc632ceSJiri Olsa config = evsel->core.attr.config; 493a818c563SMathieu Poirier break; 494a818c563SMathieu Poirier } 495a818c563SMathieu Poirier } 496a818c563SMathieu Poirier 497a818c563SMathieu Poirier return config; 498a818c563SMathieu Poirier } 499a818c563SMathieu Poirier 500df770ff0SMike Leach #ifndef BIT 501df770ff0SMike Leach #define BIT(N) (1UL << (N)) 502df770ff0SMike Leach #endif 503df770ff0SMike Leach 504df770ff0SMike Leach static u64 cs_etmv4_get_config(struct auxtrace_record *itr) 505df770ff0SMike Leach { 506df770ff0SMike Leach u64 config = 0; 507df770ff0SMike Leach u64 config_opts = 0; 508df770ff0SMike Leach 509df770ff0SMike Leach /* 510df770ff0SMike Leach * The perf event variable config bits represent both 511df770ff0SMike Leach * the command line options and register programming 512df770ff0SMike Leach * bits in ETMv3/PTM. For ETMv4 we must remap options 513df770ff0SMike Leach * to real bits 514df770ff0SMike Leach */ 515df770ff0SMike Leach config_opts = cs_etm_get_config(itr); 516df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_CYCACC)) 517df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_CYCACC); 5183399ad9aSMathieu Poirier if (config_opts & BIT(ETM_OPT_CTXTID)) 5193399ad9aSMathieu Poirier config |= BIT(ETM4_CFG_BIT_CTXTID); 520df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_TS)) 521df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_TS); 522df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_RETSTK)) 523df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_RETSTK); 52430cb76aaSSuzuki K Poulose if (config_opts & BIT(ETM_OPT_CTXTID2)) 52530cb76aaSSuzuki K Poulose config |= BIT(ETM4_CFG_BIT_VMID) | 52630cb76aaSSuzuki K Poulose BIT(ETM4_CFG_BIT_VMID_OPT); 527aca8af3cSJames Clark if (config_opts & BIT(ETM_OPT_BRANCH_BROADCAST)) 528aca8af3cSJames Clark config |= BIT(ETM4_CFG_BIT_BB); 529aca8af3cSJames Clark 530df770ff0SMike Leach return config; 531df770ff0SMike Leach } 532df770ff0SMike Leach 533a818c563SMathieu Poirier static size_t 534a818c563SMathieu Poirier cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, 53563503dbaSJiri Olsa struct evlist *evlist __maybe_unused) 536a818c563SMathieu Poirier { 537a818c563SMathieu Poirier int i; 53851ba8811SJames Clark int etmv3 = 0, etmv4 = 0, ete = 0; 5390df6ade7SIan Rogers struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus; 5409c3516d1SJiri Olsa struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); 541a818c563SMathieu Poirier 542a818c563SMathieu Poirier /* cpu map is not empty, we have specific CPUs to work with */ 543315c0a1fSJiri Olsa if (!perf_cpu_map__empty(event_cpus)) { 5446d18804bSIan Rogers for (i = 0; i < cpu__max_cpu().cpu; i++) { 5456d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 5466d18804bSIan Rogers 5476d18804bSIan Rogers if (!perf_cpu_map__has(event_cpus, cpu) || 5486d18804bSIan Rogers !perf_cpu_map__has(online_cpus, cpu)) 549796bfaddSMathieu Poirier continue; 550796bfaddSMathieu Poirier 55151ba8811SJames Clark if (cs_etm_is_ete(itr, i)) 55251ba8811SJames Clark ete++; 55351ba8811SJames Clark else if (cs_etm_is_etmv4(itr, i)) 554a818c563SMathieu Poirier etmv4++; 555a818c563SMathieu Poirier else 556a818c563SMathieu Poirier etmv3++; 557a818c563SMathieu Poirier } 558a818c563SMathieu Poirier } else { 559a818c563SMathieu Poirier /* get configuration for all CPUs in the system */ 5606d18804bSIan Rogers for (i = 0; i < cpu__max_cpu().cpu; i++) { 5616d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 5626d18804bSIan Rogers 5636d18804bSIan Rogers if (!perf_cpu_map__has(online_cpus, cpu)) 564796bfaddSMathieu Poirier continue; 565796bfaddSMathieu Poirier 56651ba8811SJames Clark if (cs_etm_is_ete(itr, i)) 56751ba8811SJames Clark ete++; 56851ba8811SJames Clark else if (cs_etm_is_etmv4(itr, i)) 569a818c563SMathieu Poirier etmv4++; 570a818c563SMathieu Poirier else 571a818c563SMathieu Poirier etmv3++; 572a818c563SMathieu Poirier } 573a818c563SMathieu Poirier } 574a818c563SMathieu Poirier 57538f01d8dSJiri Olsa perf_cpu_map__put(online_cpus); 576796bfaddSMathieu Poirier 577a818c563SMathieu Poirier return (CS_ETM_HEADER_SIZE + 57851ba8811SJames Clark (ete * CS_ETE_PRIV_SIZE) + 579a818c563SMathieu Poirier (etmv4 * CS_ETMV4_PRIV_SIZE) + 580a818c563SMathieu Poirier (etmv3 * CS_ETMV3_PRIV_SIZE)); 581a818c563SMathieu Poirier } 582a818c563SMathieu Poirier 583a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu) 584a818c563SMathieu Poirier { 585a818c563SMathieu Poirier bool ret = false; 586a818c563SMathieu Poirier char path[PATH_MAX]; 587a818c563SMathieu Poirier int scan; 588a818c563SMathieu Poirier unsigned int val; 589a818c563SMathieu Poirier struct cs_etm_recording *ptr = 590a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 591a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 592a818c563SMathieu Poirier 593a818c563SMathieu Poirier /* Take any of the RO files for ETMv4 and see if it present */ 594a818c563SMathieu Poirier snprintf(path, PATH_MAX, "cpu%d/%s", 595a818c563SMathieu Poirier cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 596a818c563SMathieu Poirier scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 597a818c563SMathieu Poirier 598a818c563SMathieu Poirier /* The file was read successfully, we have a winner */ 599a818c563SMathieu Poirier if (scan == 1) 600a818c563SMathieu Poirier ret = true; 601a818c563SMathieu Poirier 602a818c563SMathieu Poirier return ret; 603a818c563SMathieu Poirier } 604a818c563SMathieu Poirier 605a818c563SMathieu Poirier static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path) 606a818c563SMathieu Poirier { 607a818c563SMathieu Poirier char pmu_path[PATH_MAX]; 608a818c563SMathieu Poirier int scan; 609a818c563SMathieu Poirier unsigned int val = 0; 610a818c563SMathieu Poirier 611a818c563SMathieu Poirier /* Get RO metadata from sysfs */ 612a818c563SMathieu Poirier snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 613a818c563SMathieu Poirier 614a818c563SMathieu Poirier scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val); 615a818c563SMathieu Poirier if (scan != 1) 616a818c563SMathieu Poirier pr_err("%s: error reading: %s\n", __func__, pmu_path); 617a818c563SMathieu Poirier 618a818c563SMathieu Poirier return val; 619a818c563SMathieu Poirier } 620a818c563SMathieu Poirier 6212e2f7ceeSGerman Gomez static int cs_etm_get_ro_signed(struct perf_pmu *pmu, int cpu, const char *path) 6222e2f7ceeSGerman Gomez { 6232e2f7ceeSGerman Gomez char pmu_path[PATH_MAX]; 6242e2f7ceeSGerman Gomez int scan; 6252e2f7ceeSGerman Gomez int val = 0; 6262e2f7ceeSGerman Gomez 6272e2f7ceeSGerman Gomez /* Get RO metadata from sysfs */ 6282e2f7ceeSGerman Gomez snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 6292e2f7ceeSGerman Gomez 6302e2f7ceeSGerman Gomez scan = perf_pmu__scan_file(pmu, pmu_path, "%d", &val); 6312e2f7ceeSGerman Gomez if (scan != 1) 6322e2f7ceeSGerman Gomez pr_err("%s: error reading: %s\n", __func__, pmu_path); 6332e2f7ceeSGerman Gomez 6342e2f7ceeSGerman Gomez return val; 6352e2f7ceeSGerman Gomez } 6362e2f7ceeSGerman Gomez 6372e2f7ceeSGerman Gomez static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, int cpu, const char *path) 6382e2f7ceeSGerman Gomez { 6392e2f7ceeSGerman Gomez char pmu_path[PATH_MAX]; 6402e2f7ceeSGerman Gomez 6412e2f7ceeSGerman Gomez /* Get RO metadata from sysfs */ 6422e2f7ceeSGerman Gomez snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 6432e2f7ceeSGerman Gomez 6442e2f7ceeSGerman Gomez return perf_pmu__file_exists(pmu, pmu_path); 6452e2f7ceeSGerman Gomez } 6462e2f7ceeSGerman Gomez 64751ba8811SJames Clark #define TRCDEVARCH_ARCHPART_SHIFT 0 64851ba8811SJames Clark #define TRCDEVARCH_ARCHPART_MASK GENMASK(11, 0) 64951ba8811SJames Clark #define TRCDEVARCH_ARCHPART(x) (((x) & TRCDEVARCH_ARCHPART_MASK) >> TRCDEVARCH_ARCHPART_SHIFT) 65051ba8811SJames Clark 65151ba8811SJames Clark #define TRCDEVARCH_ARCHVER_SHIFT 12 65251ba8811SJames Clark #define TRCDEVARCH_ARCHVER_MASK GENMASK(15, 12) 65351ba8811SJames Clark #define TRCDEVARCH_ARCHVER(x) (((x) & TRCDEVARCH_ARCHVER_MASK) >> TRCDEVARCH_ARCHVER_SHIFT) 65451ba8811SJames Clark 65551ba8811SJames Clark static bool cs_etm_is_ete(struct auxtrace_record *itr, int cpu) 65651ba8811SJames Clark { 65751ba8811SJames Clark struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); 65851ba8811SJames Clark struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 659e5af1397SJames Clark int trcdevarch; 66051ba8811SJames Clark 661e5af1397SJames Clark if (!cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH])) 662e5af1397SJames Clark return false; 663e5af1397SJames Clark 664e5af1397SJames Clark trcdevarch = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH]); 66551ba8811SJames Clark /* 66651ba8811SJames Clark * ETE if ARCHVER is 5 (ARCHVER is 4 for ETM) and ARCHPART is 0xA13. 66751ba8811SJames Clark * See ETM_DEVARCH_ETE_ARCH in coresight-etm4x.h 66851ba8811SJames Clark */ 66951ba8811SJames Clark return TRCDEVARCH_ARCHVER(trcdevarch) == 5 && TRCDEVARCH_ARCHPART(trcdevarch) == 0xA13; 67051ba8811SJames Clark } 67151ba8811SJames Clark 672c9ccc96bSJames Clark static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr, int cpu) 673c9ccc96bSJames Clark { 674c9ccc96bSJames Clark struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); 675c9ccc96bSJames Clark struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 676c9ccc96bSJames Clark 677c9ccc96bSJames Clark /* Get trace configuration register */ 678c9ccc96bSJames Clark data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_get_config(itr); 679e5fa5b41SMike Leach /* traceID set to legacy version, in case new perf running on older system */ 680e5fa5b41SMike Leach data[CS_ETMV4_TRCTRACEIDR] = 681e5fa5b41SMike Leach CORESIGHT_LEGACY_CPU_TRACE_ID(cpu) | CORESIGHT_TRACE_ID_UNUSED_FLAG; 682e5fa5b41SMike Leach 683c9ccc96bSJames Clark /* Get read-only information from sysFS */ 684c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR0] = cs_etm_get_ro(cs_etm_pmu, cpu, 685c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 686c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR1] = cs_etm_get_ro(cs_etm_pmu, cpu, 687c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR1]); 688c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR2] = cs_etm_get_ro(cs_etm_pmu, cpu, 689c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); 690c9ccc96bSJames Clark data[CS_ETMV4_TRCIDR8] = cs_etm_get_ro(cs_etm_pmu, cpu, 691c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCIDR8]); 692c9ccc96bSJames Clark data[CS_ETMV4_TRCAUTHSTATUS] = cs_etm_get_ro(cs_etm_pmu, cpu, 693c9ccc96bSJames Clark metadata_etmv4_ro[CS_ETMV4_TRCAUTHSTATUS]); 6942e2f7ceeSGerman Gomez 6952e2f7ceeSGerman Gomez /* Kernels older than 5.19 may not expose ts_source */ 6962e2f7ceeSGerman Gomez if (cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TS_SOURCE])) 6972e2f7ceeSGerman Gomez data[CS_ETMV4_TS_SOURCE] = (__u64) cs_etm_get_ro_signed(cs_etm_pmu, cpu, 6982e2f7ceeSGerman Gomez metadata_etmv4_ro[CS_ETMV4_TS_SOURCE]); 6992e2f7ceeSGerman Gomez else { 7005f968d28SJames Clark pr_debug3("[%03d] pmu file 'ts_source' not found. Fallback to safe value (-1)\n", 7012e2f7ceeSGerman Gomez cpu); 7022e2f7ceeSGerman Gomez data[CS_ETMV4_TS_SOURCE] = (__u64) -1; 7032e2f7ceeSGerman Gomez } 704c9ccc96bSJames Clark } 705c9ccc96bSJames Clark 706326163c5SGerman Gomez static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *itr, int cpu) 707326163c5SGerman Gomez { 708326163c5SGerman Gomez struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); 709326163c5SGerman Gomez struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 710326163c5SGerman Gomez 711326163c5SGerman Gomez /* Get trace configuration register */ 712326163c5SGerman Gomez data[CS_ETE_TRCCONFIGR] = cs_etmv4_get_config(itr); 713e5fa5b41SMike Leach /* traceID set to legacy version, in case new perf running on older system */ 714e5fa5b41SMike Leach data[CS_ETE_TRCTRACEIDR] = 715e5fa5b41SMike Leach CORESIGHT_LEGACY_CPU_TRACE_ID(cpu) | CORESIGHT_TRACE_ID_UNUSED_FLAG; 716e5fa5b41SMike Leach 717326163c5SGerman Gomez /* Get read-only information from sysFS */ 718326163c5SGerman Gomez data[CS_ETE_TRCIDR0] = cs_etm_get_ro(cs_etm_pmu, cpu, 719326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCIDR0]); 720326163c5SGerman Gomez data[CS_ETE_TRCIDR1] = cs_etm_get_ro(cs_etm_pmu, cpu, 721326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCIDR1]); 722326163c5SGerman Gomez data[CS_ETE_TRCIDR2] = cs_etm_get_ro(cs_etm_pmu, cpu, 723326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCIDR2]); 724326163c5SGerman Gomez data[CS_ETE_TRCIDR8] = cs_etm_get_ro(cs_etm_pmu, cpu, 725326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCIDR8]); 726326163c5SGerman Gomez data[CS_ETE_TRCAUTHSTATUS] = cs_etm_get_ro(cs_etm_pmu, cpu, 727326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCAUTHSTATUS]); 728326163c5SGerman Gomez /* ETE uses the same registers as ETMv4 plus TRCDEVARCH */ 729326163c5SGerman Gomez data[CS_ETE_TRCDEVARCH] = cs_etm_get_ro(cs_etm_pmu, cpu, 730326163c5SGerman Gomez metadata_ete_ro[CS_ETE_TRCDEVARCH]); 7312e2f7ceeSGerman Gomez 7322e2f7ceeSGerman Gomez /* Kernels older than 5.19 may not expose ts_source */ 7332e2f7ceeSGerman Gomez if (cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TS_SOURCE])) 7342e2f7ceeSGerman Gomez data[CS_ETE_TS_SOURCE] = (__u64) cs_etm_get_ro_signed(cs_etm_pmu, cpu, 7352e2f7ceeSGerman Gomez metadata_ete_ro[CS_ETE_TS_SOURCE]); 7362e2f7ceeSGerman Gomez else { 7375f968d28SJames Clark pr_debug3("[%03d] pmu file 'ts_source' not found. Fallback to safe value (-1)\n", 7382e2f7ceeSGerman Gomez cpu); 7392e2f7ceeSGerman Gomez data[CS_ETE_TS_SOURCE] = (__u64) -1; 7402e2f7ceeSGerman Gomez } 741326163c5SGerman Gomez } 742326163c5SGerman Gomez 743a818c563SMathieu Poirier static void cs_etm_get_metadata(int cpu, u32 *offset, 744a818c563SMathieu Poirier struct auxtrace_record *itr, 74572932371SJiri Olsa struct perf_record_auxtrace_info *info) 746a818c563SMathieu Poirier { 74742b2b570SMike Leach u32 increment, nr_trc_params; 748a818c563SMathieu Poirier u64 magic; 749a818c563SMathieu Poirier struct cs_etm_recording *ptr = 750a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 751a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 752a818c563SMathieu Poirier 753a818c563SMathieu Poirier /* first see what kind of tracer this cpu is affined to */ 75451ba8811SJames Clark if (cs_etm_is_ete(itr, cpu)) { 75551ba8811SJames Clark magic = __perf_cs_ete_magic; 756326163c5SGerman Gomez cs_etm_save_ete_header(&info->priv[*offset], itr, cpu); 75751ba8811SJames Clark 75851ba8811SJames Clark /* How much space was used */ 75951ba8811SJames Clark increment = CS_ETE_PRIV_MAX; 76051ba8811SJames Clark nr_trc_params = CS_ETE_PRIV_MAX - CS_ETM_COMMON_BLK_MAX_V1; 76151ba8811SJames Clark } else if (cs_etm_is_etmv4(itr, cpu)) { 762a818c563SMathieu Poirier magic = __perf_cs_etmv4_magic; 763c9ccc96bSJames Clark cs_etm_save_etmv4_header(&info->priv[*offset], itr, cpu); 764a818c563SMathieu Poirier 765a818c563SMathieu Poirier /* How much space was used */ 766a818c563SMathieu Poirier increment = CS_ETMV4_PRIV_MAX; 76742b2b570SMike Leach nr_trc_params = CS_ETMV4_PRIV_MAX - CS_ETMV4_TRCCONFIGR; 768a818c563SMathieu Poirier } else { 769a818c563SMathieu Poirier magic = __perf_cs_etmv3_magic; 770a818c563SMathieu Poirier /* Get configuration register */ 771a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr); 772e5fa5b41SMike Leach /* traceID set to legacy value in case new perf running on old system */ 773a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMTRACEIDR] = 774e5fa5b41SMike Leach CORESIGHT_LEGACY_CPU_TRACE_ID(cpu) | CORESIGHT_TRACE_ID_UNUSED_FLAG; 775a818c563SMathieu Poirier /* Get read-only information from sysFS */ 776a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMCCER] = 777a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 778a818c563SMathieu Poirier metadata_etmv3_ro[CS_ETM_ETMCCER]); 779a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMIDR] = 780a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 781a818c563SMathieu Poirier metadata_etmv3_ro[CS_ETM_ETMIDR]); 782a818c563SMathieu Poirier 783a818c563SMathieu Poirier /* How much space was used */ 784a818c563SMathieu Poirier increment = CS_ETM_PRIV_MAX; 78542b2b570SMike Leach nr_trc_params = CS_ETM_PRIV_MAX - CS_ETM_ETMCR; 786a818c563SMathieu Poirier } 787a818c563SMathieu Poirier 788a818c563SMathieu Poirier /* Build generic header portion */ 789a818c563SMathieu Poirier info->priv[*offset + CS_ETM_MAGIC] = magic; 790a818c563SMathieu Poirier info->priv[*offset + CS_ETM_CPU] = cpu; 79142b2b570SMike Leach info->priv[*offset + CS_ETM_NR_TRC_PARAMS] = nr_trc_params; 792a818c563SMathieu Poirier /* Where the next CPU entry should start from */ 793a818c563SMathieu Poirier *offset += increment; 794a818c563SMathieu Poirier } 795a818c563SMathieu Poirier 796a818c563SMathieu Poirier static int cs_etm_info_fill(struct auxtrace_record *itr, 797a818c563SMathieu Poirier struct perf_session *session, 79872932371SJiri Olsa struct perf_record_auxtrace_info *info, 799a818c563SMathieu Poirier size_t priv_size) 800a818c563SMathieu Poirier { 801a818c563SMathieu Poirier int i; 802a818c563SMathieu Poirier u32 offset; 803a818c563SMathieu Poirier u64 nr_cpu, type; 804f854839bSJiri Olsa struct perf_cpu_map *cpu_map; 8050df6ade7SIan Rogers struct perf_cpu_map *event_cpus = session->evlist->core.user_requested_cpus; 8069c3516d1SJiri Olsa struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); 807a818c563SMathieu Poirier struct cs_etm_recording *ptr = 808a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 809a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 810a818c563SMathieu Poirier 811a818c563SMathieu Poirier if (priv_size != cs_etm_info_priv_size(itr, session->evlist)) 812a818c563SMathieu Poirier return -EINVAL; 813a818c563SMathieu Poirier 814c976ee11SJiri Olsa if (!session->evlist->core.nr_mmaps) 815a818c563SMathieu Poirier return -EINVAL; 816a818c563SMathieu Poirier 817796bfaddSMathieu Poirier /* If the cpu_map is empty all online CPUs are involved */ 818315c0a1fSJiri Olsa if (perf_cpu_map__empty(event_cpus)) { 819796bfaddSMathieu Poirier cpu_map = online_cpus; 820796bfaddSMathieu Poirier } else { 821796bfaddSMathieu Poirier /* Make sure all specified CPUs are online */ 8226549cd8fSJiri Olsa for (i = 0; i < perf_cpu_map__nr(event_cpus); i++) { 8236d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 8246d18804bSIan Rogers 8256d18804bSIan Rogers if (perf_cpu_map__has(event_cpus, cpu) && 8266d18804bSIan Rogers !perf_cpu_map__has(online_cpus, cpu)) 827796bfaddSMathieu Poirier return -EINVAL; 828796bfaddSMathieu Poirier } 829796bfaddSMathieu Poirier 830796bfaddSMathieu Poirier cpu_map = event_cpus; 831796bfaddSMathieu Poirier } 832796bfaddSMathieu Poirier 8336549cd8fSJiri Olsa nr_cpu = perf_cpu_map__nr(cpu_map); 834a818c563SMathieu Poirier /* Get PMU type as dynamically assigned by the core */ 835a818c563SMathieu Poirier type = cs_etm_pmu->type; 836a818c563SMathieu Poirier 837a818c563SMathieu Poirier /* First fill out the session header */ 838a818c563SMathieu Poirier info->type = PERF_AUXTRACE_CS_ETM; 83942b2b570SMike Leach info->priv[CS_HEADER_VERSION] = CS_HEADER_CURRENT_VERSION; 840a818c563SMathieu Poirier info->priv[CS_PMU_TYPE_CPUS] = type << 32; 841a818c563SMathieu Poirier info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu; 842a818c563SMathieu Poirier info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode; 843a818c563SMathieu Poirier 844a818c563SMathieu Poirier offset = CS_ETM_SNAPSHOT + 1; 845a818c563SMathieu Poirier 8466d18804bSIan Rogers for (i = 0; i < cpu__max_cpu().cpu && offset < priv_size; i++) { 8476d18804bSIan Rogers struct perf_cpu cpu = { .cpu = i, }; 8486d18804bSIan Rogers 8496d18804bSIan Rogers if (perf_cpu_map__has(cpu_map, cpu)) 850a818c563SMathieu Poirier cs_etm_get_metadata(i, &offset, itr, info); 8516d18804bSIan Rogers } 852796bfaddSMathieu Poirier 85338f01d8dSJiri Olsa perf_cpu_map__put(online_cpus); 854a818c563SMathieu Poirier 855a818c563SMathieu Poirier return 0; 856a818c563SMathieu Poirier } 857a818c563SMathieu Poirier 858a818c563SMathieu Poirier static int cs_etm_snapshot_start(struct auxtrace_record *itr) 859a818c563SMathieu Poirier { 860a818c563SMathieu Poirier struct cs_etm_recording *ptr = 861a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 86232dcd021SJiri Olsa struct evsel *evsel; 863a818c563SMathieu Poirier 864a818c563SMathieu Poirier evlist__for_each_entry(ptr->evlist, evsel) { 8651fc632ceSJiri Olsa if (evsel->core.attr.type == ptr->cs_etm_pmu->type) 8669a10bb22SJiri Olsa return evsel__disable(evsel); 867a818c563SMathieu Poirier } 868a818c563SMathieu Poirier return -EINVAL; 869a818c563SMathieu Poirier } 870a818c563SMathieu Poirier 871a818c563SMathieu Poirier static int cs_etm_snapshot_finish(struct auxtrace_record *itr) 872a818c563SMathieu Poirier { 873a818c563SMathieu Poirier struct cs_etm_recording *ptr = 874a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 87532dcd021SJiri Olsa struct evsel *evsel; 876a818c563SMathieu Poirier 877a818c563SMathieu Poirier evlist__for_each_entry(ptr->evlist, evsel) { 8781fc632ceSJiri Olsa if (evsel->core.attr.type == ptr->cs_etm_pmu->type) 879ec7f24efSJiri Olsa return evsel__enable(evsel); 880a818c563SMathieu Poirier } 881a818c563SMathieu Poirier return -EINVAL; 882a818c563SMathieu Poirier } 883a818c563SMathieu Poirier 884a818c563SMathieu Poirier static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused) 885a818c563SMathieu Poirier { 886a818c563SMathieu Poirier return (((u64) rand() << 0) & 0x00000000FFFFFFFFull) | 887a818c563SMathieu Poirier (((u64) rand() << 32) & 0xFFFFFFFF00000000ull); 888a818c563SMathieu Poirier } 889a818c563SMathieu Poirier 890a818c563SMathieu Poirier static void cs_etm_recording_free(struct auxtrace_record *itr) 891a818c563SMathieu Poirier { 892a818c563SMathieu Poirier struct cs_etm_recording *ptr = 893a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 894e45c48a9SMathieu Poirier 895a818c563SMathieu Poirier free(ptr); 896a818c563SMathieu Poirier } 897a818c563SMathieu Poirier 898a818c563SMathieu Poirier struct auxtrace_record *cs_etm_record_init(int *err) 899a818c563SMathieu Poirier { 900a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu; 901a818c563SMathieu Poirier struct cs_etm_recording *ptr; 902a818c563SMathieu Poirier 903a818c563SMathieu Poirier cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME); 904a818c563SMathieu Poirier 905a818c563SMathieu Poirier if (!cs_etm_pmu) { 906a818c563SMathieu Poirier *err = -EINVAL; 907a818c563SMathieu Poirier goto out; 908a818c563SMathieu Poirier } 909a818c563SMathieu Poirier 910a818c563SMathieu Poirier ptr = zalloc(sizeof(struct cs_etm_recording)); 911a818c563SMathieu Poirier if (!ptr) { 912a818c563SMathieu Poirier *err = -ENOMEM; 913a818c563SMathieu Poirier goto out; 914a818c563SMathieu Poirier } 915a818c563SMathieu Poirier 916a818c563SMathieu Poirier ptr->cs_etm_pmu = cs_etm_pmu; 917ad60ba0cSAdrian Hunter ptr->itr.pmu = cs_etm_pmu; 918a818c563SMathieu Poirier ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options; 919a818c563SMathieu Poirier ptr->itr.recording_options = cs_etm_recording_options; 920a818c563SMathieu Poirier ptr->itr.info_priv_size = cs_etm_info_priv_size; 921a818c563SMathieu Poirier ptr->itr.info_fill = cs_etm_info_fill; 922a818c563SMathieu Poirier ptr->itr.snapshot_start = cs_etm_snapshot_start; 923a818c563SMathieu Poirier ptr->itr.snapshot_finish = cs_etm_snapshot_finish; 924a818c563SMathieu Poirier ptr->itr.reference = cs_etm_reference; 925a818c563SMathieu Poirier ptr->itr.free = cs_etm_recording_free; 926ad60ba0cSAdrian Hunter ptr->itr.read_finish = auxtrace_record__read_finish; 927a818c563SMathieu Poirier 928a818c563SMathieu Poirier *err = 0; 929a818c563SMathieu Poirier return &ptr->itr; 930a818c563SMathieu Poirier out: 931a818c563SMathieu Poirier return NULL; 932a818c563SMathieu Poirier } 933