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" 19b4209025SArnaldo Carvalho de Melo #include "../../util/debug.h" 20aeb00b1aSArnaldo Carvalho de Melo #include "../../util/record.h" 21a818c563SMathieu Poirier #include "../../util/auxtrace.h" 22a818c563SMathieu Poirier #include "../../util/cpumap.h" 23dda1bf8eSIgor Lubashev #include "../../util/event.h" 24a818c563SMathieu Poirier #include "../../util/evlist.h" 253becf452SMathieu Poirier #include "../../util/evsel.h" 2640c7d246SArnaldo Carvalho de Melo #include "../../util/perf_api_probe.h" 2795be9d19SArnaldo Carvalho de Melo #include "../../util/evsel_config.h" 28a818c563SMathieu Poirier #include "../../util/pmu.h" 29a818c563SMathieu Poirier #include "../../util/cs-etm.h" 3020f2be1dSJiri Olsa #include <internal/lib.h> // page_size 31f2a39fe8SArnaldo Carvalho de Melo #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; 41e45c48a9SMathieu Poirier int wrapped_cnt; 42e45c48a9SMathieu Poirier bool *wrapped; 43a818c563SMathieu Poirier bool snapshot_mode; 44a818c563SMathieu Poirier size_t snapshot_size; 45a818c563SMathieu Poirier }; 46a818c563SMathieu Poirier 473399ad9aSMathieu Poirier static const char *metadata_etmv3_ro[CS_ETM_PRIV_MAX] = { 483399ad9aSMathieu Poirier [CS_ETM_ETMCCER] = "mgmt/etmccer", 493399ad9aSMathieu Poirier [CS_ETM_ETMIDR] = "mgmt/etmidr", 503399ad9aSMathieu Poirier }; 513399ad9aSMathieu Poirier 523399ad9aSMathieu Poirier static const char *metadata_etmv4_ro[CS_ETMV4_PRIV_MAX] = { 533399ad9aSMathieu Poirier [CS_ETMV4_TRCIDR0] = "trcidr/trcidr0", 543399ad9aSMathieu Poirier [CS_ETMV4_TRCIDR1] = "trcidr/trcidr1", 553399ad9aSMathieu Poirier [CS_ETMV4_TRCIDR2] = "trcidr/trcidr2", 563399ad9aSMathieu Poirier [CS_ETMV4_TRCIDR8] = "trcidr/trcidr8", 573399ad9aSMathieu Poirier [CS_ETMV4_TRCAUTHSTATUS] = "mgmt/trcauthstatus", 583399ad9aSMathieu Poirier }; 593399ad9aSMathieu Poirier 60a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu); 61a818c563SMathieu Poirier 623399ad9aSMathieu Poirier static int cs_etm_set_context_id(struct auxtrace_record *itr, 6332dcd021SJiri Olsa struct evsel *evsel, int cpu) 643399ad9aSMathieu Poirier { 653399ad9aSMathieu Poirier struct cs_etm_recording *ptr; 663399ad9aSMathieu Poirier struct perf_pmu *cs_etm_pmu; 673399ad9aSMathieu Poirier char path[PATH_MAX]; 683399ad9aSMathieu Poirier int err = -EINVAL; 693399ad9aSMathieu Poirier u32 val; 703399ad9aSMathieu Poirier 713399ad9aSMathieu Poirier ptr = container_of(itr, struct cs_etm_recording, itr); 723399ad9aSMathieu Poirier cs_etm_pmu = ptr->cs_etm_pmu; 733399ad9aSMathieu Poirier 743399ad9aSMathieu Poirier if (!cs_etm_is_etmv4(itr, cpu)) 753399ad9aSMathieu Poirier goto out; 763399ad9aSMathieu Poirier 773399ad9aSMathieu Poirier /* Get a handle on TRCIRD2 */ 783399ad9aSMathieu Poirier snprintf(path, PATH_MAX, "cpu%d/%s", 793399ad9aSMathieu Poirier cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); 803399ad9aSMathieu Poirier err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 813399ad9aSMathieu Poirier 823399ad9aSMathieu Poirier /* There was a problem reading the file, bailing out */ 833399ad9aSMathieu Poirier if (err != 1) { 843399ad9aSMathieu Poirier pr_err("%s: can't read file %s\n", 853399ad9aSMathieu Poirier CORESIGHT_ETM_PMU_NAME, path); 863399ad9aSMathieu Poirier goto out; 873399ad9aSMathieu Poirier } 883399ad9aSMathieu Poirier 893399ad9aSMathieu Poirier /* 903399ad9aSMathieu Poirier * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID tracing 913399ad9aSMathieu Poirier * is supported: 923399ad9aSMathieu Poirier * 0b00000 Context ID tracing is not supported. 933399ad9aSMathieu Poirier * 0b00100 Maximum of 32-bit Context ID size. 943399ad9aSMathieu Poirier * All other values are reserved. 953399ad9aSMathieu Poirier */ 963399ad9aSMathieu Poirier val = BMVAL(val, 5, 9); 973399ad9aSMathieu Poirier if (!val || val != 0x4) { 983399ad9aSMathieu Poirier err = -EINVAL; 993399ad9aSMathieu Poirier goto out; 1003399ad9aSMathieu Poirier } 1013399ad9aSMathieu Poirier 1023399ad9aSMathieu Poirier /* All good, let the kernel know */ 1031fc632ceSJiri Olsa evsel->core.attr.config |= (1 << ETM_OPT_CTXTID); 1043399ad9aSMathieu Poirier err = 0; 1053399ad9aSMathieu Poirier 1063399ad9aSMathieu Poirier out: 1073399ad9aSMathieu Poirier 1083399ad9aSMathieu Poirier return err; 1093399ad9aSMathieu Poirier } 1103399ad9aSMathieu Poirier 1111c839a5aSMathieu Poirier static int cs_etm_set_timestamp(struct auxtrace_record *itr, 11232dcd021SJiri Olsa struct evsel *evsel, int cpu) 1131c839a5aSMathieu Poirier { 1141c839a5aSMathieu Poirier struct cs_etm_recording *ptr; 1151c839a5aSMathieu Poirier struct perf_pmu *cs_etm_pmu; 1161c839a5aSMathieu Poirier char path[PATH_MAX]; 1171c839a5aSMathieu Poirier int err = -EINVAL; 1181c839a5aSMathieu Poirier u32 val; 1191c839a5aSMathieu Poirier 1201c839a5aSMathieu Poirier ptr = container_of(itr, struct cs_etm_recording, itr); 1211c839a5aSMathieu Poirier cs_etm_pmu = ptr->cs_etm_pmu; 1221c839a5aSMathieu Poirier 1231c839a5aSMathieu Poirier if (!cs_etm_is_etmv4(itr, cpu)) 1241c839a5aSMathieu Poirier goto out; 1251c839a5aSMathieu Poirier 1261c839a5aSMathieu Poirier /* Get a handle on TRCIRD0 */ 1271c839a5aSMathieu Poirier snprintf(path, PATH_MAX, "cpu%d/%s", 1281c839a5aSMathieu Poirier cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 1291c839a5aSMathieu Poirier err = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 1301c839a5aSMathieu Poirier 1311c839a5aSMathieu Poirier /* There was a problem reading the file, bailing out */ 1321c839a5aSMathieu Poirier if (err != 1) { 1331c839a5aSMathieu Poirier pr_err("%s: can't read file %s\n", 1341c839a5aSMathieu Poirier CORESIGHT_ETM_PMU_NAME, path); 1351c839a5aSMathieu Poirier goto out; 1361c839a5aSMathieu Poirier } 1371c839a5aSMathieu Poirier 1381c839a5aSMathieu Poirier /* 1391c839a5aSMathieu Poirier * TRCIDR0.TSSIZE, bit [28-24], indicates whether global timestamping 1401c839a5aSMathieu Poirier * is supported: 1411c839a5aSMathieu Poirier * 0b00000 Global timestamping is not implemented 1421c839a5aSMathieu Poirier * 0b00110 Implementation supports a maximum timestamp of 48bits. 1431c839a5aSMathieu Poirier * 0b01000 Implementation supports a maximum timestamp of 64bits. 1441c839a5aSMathieu Poirier */ 1451c839a5aSMathieu Poirier val &= GENMASK(28, 24); 1461c839a5aSMathieu Poirier if (!val) { 1471c839a5aSMathieu Poirier err = -EINVAL; 1481c839a5aSMathieu Poirier goto out; 1491c839a5aSMathieu Poirier } 1501c839a5aSMathieu Poirier 1511c839a5aSMathieu Poirier /* All good, let the kernel know */ 1521fc632ceSJiri Olsa evsel->core.attr.config |= (1 << ETM_OPT_TS); 1531c839a5aSMathieu Poirier err = 0; 1541c839a5aSMathieu Poirier 1551c839a5aSMathieu Poirier out: 1561c839a5aSMathieu Poirier return err; 1571c839a5aSMathieu Poirier } 1581c839a5aSMathieu Poirier 1593399ad9aSMathieu Poirier static int cs_etm_set_option(struct auxtrace_record *itr, 16032dcd021SJiri Olsa struct evsel *evsel, u32 option) 1613399ad9aSMathieu Poirier { 1623399ad9aSMathieu Poirier int i, err = -EINVAL; 163f72f901dSJiri Olsa struct perf_cpu_map *event_cpus = evsel->evlist->core.cpus; 1649c3516d1SJiri Olsa struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); 1653399ad9aSMathieu Poirier 1663399ad9aSMathieu Poirier /* Set option of each CPU we have */ 1673399ad9aSMathieu Poirier for (i = 0; i < cpu__max_cpu(); i++) { 1683399ad9aSMathieu Poirier if (!cpu_map__has(event_cpus, i) || 1693399ad9aSMathieu Poirier !cpu_map__has(online_cpus, i)) 1703399ad9aSMathieu Poirier continue; 1713399ad9aSMathieu Poirier 172374d910fSMathieu Poirier if (option & ETM_OPT_CTXTID) { 1733399ad9aSMathieu Poirier err = cs_etm_set_context_id(itr, evsel, i); 1743399ad9aSMathieu Poirier if (err) 1753399ad9aSMathieu Poirier goto out; 176374d910fSMathieu Poirier } 177374d910fSMathieu Poirier if (option & ETM_OPT_TS) { 1781c839a5aSMathieu Poirier err = cs_etm_set_timestamp(itr, evsel, i); 1791c839a5aSMathieu Poirier if (err) 1801c839a5aSMathieu Poirier goto out; 1813399ad9aSMathieu Poirier } 182374d910fSMathieu Poirier if (option & ~(ETM_OPT_CTXTID | ETM_OPT_TS)) 183374d910fSMathieu Poirier /* Nothing else is currently supported */ 184374d910fSMathieu Poirier goto out; 1853399ad9aSMathieu Poirier } 1863399ad9aSMathieu Poirier 1873399ad9aSMathieu Poirier err = 0; 1883399ad9aSMathieu Poirier out: 18938f01d8dSJiri Olsa perf_cpu_map__put(online_cpus); 1903399ad9aSMathieu Poirier return err; 1913399ad9aSMathieu Poirier } 1923399ad9aSMathieu Poirier 193a818c563SMathieu Poirier static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr, 194a818c563SMathieu Poirier struct record_opts *opts, 195a818c563SMathieu Poirier const char *str) 196a818c563SMathieu Poirier { 197a818c563SMathieu Poirier struct cs_etm_recording *ptr = 198a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 199a818c563SMathieu Poirier unsigned long long snapshot_size = 0; 200a818c563SMathieu Poirier char *endptr; 201a818c563SMathieu Poirier 202a818c563SMathieu Poirier if (str) { 203a818c563SMathieu Poirier snapshot_size = strtoull(str, &endptr, 0); 204a818c563SMathieu Poirier if (*endptr || snapshot_size > SIZE_MAX) 205a818c563SMathieu Poirier return -1; 206a818c563SMathieu Poirier } 207a818c563SMathieu Poirier 208a818c563SMathieu Poirier opts->auxtrace_snapshot_mode = true; 209a818c563SMathieu Poirier opts->auxtrace_snapshot_size = snapshot_size; 210a818c563SMathieu Poirier ptr->snapshot_size = snapshot_size; 211a818c563SMathieu Poirier 212a818c563SMathieu Poirier return 0; 213a818c563SMathieu Poirier } 214a818c563SMathieu Poirier 215fa4e819bSMathieu Poirier static int cs_etm_set_sink_attr(struct perf_pmu *pmu, 21632dcd021SJiri Olsa struct evsel *evsel) 217fa4e819bSMathieu Poirier { 218fa4e819bSMathieu Poirier char msg[BUFSIZ], path[PATH_MAX], *sink; 21935ac0cadSArnaldo Carvalho de Melo struct evsel_config_term *term; 220fa4e819bSMathieu Poirier int ret = -EINVAL; 221fa4e819bSMathieu Poirier u32 hash; 222fa4e819bSMathieu Poirier 2231fc632ceSJiri Olsa if (evsel->core.attr.config2 & GENMASK(31, 0)) 224fa4e819bSMathieu Poirier return 0; 225fa4e819bSMathieu Poirier 226fa4e819bSMathieu Poirier list_for_each_entry(term, &evsel->config_terms, list) { 22735ac0cadSArnaldo Carvalho de Melo if (term->type != EVSEL__CONFIG_TERM_DRV_CFG) 228fa4e819bSMathieu Poirier continue; 229fa4e819bSMathieu Poirier 230e884602bSLeo Yan sink = term->val.str; 231fa4e819bSMathieu Poirier snprintf(path, PATH_MAX, "sinks/%s", sink); 232fa4e819bSMathieu Poirier 233fa4e819bSMathieu Poirier ret = perf_pmu__scan_file(pmu, path, "%x", &hash); 234fa4e819bSMathieu Poirier if (ret != 1) { 235fa4e819bSMathieu Poirier pr_err("failed to set sink \"%s\" on event %s with %d (%s)\n", 2368ab2e96dSArnaldo Carvalho de Melo sink, evsel__name(evsel), errno, 237fa4e819bSMathieu Poirier str_error_r(errno, msg, sizeof(msg))); 238fa4e819bSMathieu Poirier return ret; 239fa4e819bSMathieu Poirier } 240fa4e819bSMathieu Poirier 2411fc632ceSJiri Olsa evsel->core.attr.config2 |= hash; 242fa4e819bSMathieu Poirier return 0; 243fa4e819bSMathieu Poirier } 244fa4e819bSMathieu Poirier 245fa4e819bSMathieu Poirier /* 24647446212SMike Leach * No sink was provided on the command line - allow the CoreSight 24747446212SMike Leach * system to look for a default 248fa4e819bSMathieu Poirier */ 24947446212SMike Leach return 0; 250fa4e819bSMathieu Poirier } 251fa4e819bSMathieu Poirier 252a818c563SMathieu Poirier static int cs_etm_recording_options(struct auxtrace_record *itr, 25363503dbaSJiri Olsa struct evlist *evlist, 254a818c563SMathieu Poirier struct record_opts *opts) 255a818c563SMathieu Poirier { 256fa4e819bSMathieu Poirier int ret; 257a818c563SMathieu Poirier struct cs_etm_recording *ptr = 258a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 259a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 26032dcd021SJiri Olsa struct evsel *evsel, *cs_etm_evsel = NULL; 261f72f901dSJiri Olsa struct perf_cpu_map *cpus = evlist->core.cpus; 262dda1bf8eSIgor Lubashev bool privileged = perf_event_paranoid_check(-1); 2633399ad9aSMathieu Poirier int err = 0; 264a818c563SMathieu Poirier 265a818c563SMathieu Poirier ptr->evlist = evlist; 266a818c563SMathieu Poirier ptr->snapshot_mode = opts->auxtrace_snapshot_mode; 267a818c563SMathieu Poirier 26816b4b4e1SAdrian Hunter if (!record_opts__no_switch_events(opts) && 26916b4b4e1SAdrian Hunter perf_can_record_switch_events()) 270e5993c42SMathieu Poirier opts->record_switch_events = true; 271e5993c42SMathieu Poirier 272a818c563SMathieu Poirier evlist__for_each_entry(evlist, evsel) { 2731fc632ceSJiri Olsa if (evsel->core.attr.type == cs_etm_pmu->type) { 274a818c563SMathieu Poirier if (cs_etm_evsel) { 275a818c563SMathieu Poirier pr_err("There may be only one %s event\n", 276a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 277a818c563SMathieu Poirier return -EINVAL; 278a818c563SMathieu Poirier } 2791fc632ceSJiri Olsa evsel->core.attr.freq = 0; 2801fc632ceSJiri Olsa evsel->core.attr.sample_period = 1; 281a818c563SMathieu Poirier cs_etm_evsel = evsel; 282a818c563SMathieu Poirier opts->full_auxtrace = true; 283a818c563SMathieu Poirier } 284a818c563SMathieu Poirier } 285a818c563SMathieu Poirier 286a818c563SMathieu Poirier /* no need to continue if at least one event of interest was found */ 287a818c563SMathieu Poirier if (!cs_etm_evsel) 288a818c563SMathieu Poirier return 0; 289a818c563SMathieu Poirier 290fa4e819bSMathieu Poirier ret = cs_etm_set_sink_attr(cs_etm_pmu, cs_etm_evsel); 291fa4e819bSMathieu Poirier if (ret) 292fa4e819bSMathieu Poirier return ret; 293fa4e819bSMathieu Poirier 294a818c563SMathieu Poirier if (opts->use_clockid) { 295a818c563SMathieu Poirier pr_err("Cannot use clockid (-k option) with %s\n", 296a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 297a818c563SMathieu Poirier return -EINVAL; 298a818c563SMathieu Poirier } 299a818c563SMathieu Poirier 300a818c563SMathieu Poirier /* we are in snapshot mode */ 301a818c563SMathieu Poirier if (opts->auxtrace_snapshot_mode) { 302a818c563SMathieu Poirier /* 303a818c563SMathieu Poirier * No size were given to '-S' or '-m,', so go with 304a818c563SMathieu Poirier * the default 305a818c563SMathieu Poirier */ 306a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size && 307a818c563SMathieu Poirier !opts->auxtrace_mmap_pages) { 308a818c563SMathieu Poirier if (privileged) { 309a818c563SMathieu Poirier opts->auxtrace_mmap_pages = MiB(4) / page_size; 310a818c563SMathieu Poirier } else { 311a818c563SMathieu Poirier opts->auxtrace_mmap_pages = 312a818c563SMathieu Poirier KiB(128) / page_size; 313a818c563SMathieu Poirier if (opts->mmap_pages == UINT_MAX) 314a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 315a818c563SMathieu Poirier } 316a818c563SMathieu Poirier } else if (!opts->auxtrace_mmap_pages && !privileged && 317a818c563SMathieu Poirier opts->mmap_pages == UINT_MAX) { 318a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 319a818c563SMathieu Poirier } 320a818c563SMathieu Poirier 321a818c563SMathieu Poirier /* 322a818c563SMathieu Poirier * '-m,xyz' was specified but no snapshot size, so make the 323a818c563SMathieu Poirier * snapshot size as big as the auxtrace mmap area. 324a818c563SMathieu Poirier */ 325a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size) { 326a818c563SMathieu Poirier opts->auxtrace_snapshot_size = 327a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size; 328a818c563SMathieu Poirier } 329a818c563SMathieu Poirier 330a818c563SMathieu Poirier /* 331a818c563SMathieu Poirier * -Sxyz was specified but no auxtrace mmap area, so make the 332a818c563SMathieu Poirier * auxtrace mmap area big enough to fit the requested snapshot 333a818c563SMathieu Poirier * size. 334a818c563SMathieu Poirier */ 335a818c563SMathieu Poirier if (!opts->auxtrace_mmap_pages) { 336a818c563SMathieu Poirier size_t sz = opts->auxtrace_snapshot_size; 337a818c563SMathieu Poirier 338a818c563SMathieu Poirier sz = round_up(sz, page_size) / page_size; 339a818c563SMathieu Poirier opts->auxtrace_mmap_pages = roundup_pow_of_two(sz); 340a818c563SMathieu Poirier } 341a818c563SMathieu Poirier 342a818c563SMathieu Poirier /* Snapshost size can't be bigger than the auxtrace area */ 343a818c563SMathieu Poirier if (opts->auxtrace_snapshot_size > 344a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size) { 345a818c563SMathieu Poirier pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n", 346a818c563SMathieu Poirier opts->auxtrace_snapshot_size, 347a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size); 348a818c563SMathieu Poirier return -EINVAL; 349a818c563SMathieu Poirier } 350a818c563SMathieu Poirier 351a818c563SMathieu Poirier /* Something went wrong somewhere - this shouldn't happen */ 352a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size || 353a818c563SMathieu Poirier !opts->auxtrace_mmap_pages) { 354a818c563SMathieu Poirier pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n"); 355a818c563SMathieu Poirier return -EINVAL; 356a818c563SMathieu Poirier } 357a818c563SMathieu Poirier } 358a818c563SMathieu Poirier 359a818c563SMathieu Poirier /* We are in full trace mode but '-m,xyz' wasn't specified */ 360a818c563SMathieu Poirier if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) { 361a818c563SMathieu Poirier if (privileged) { 362a818c563SMathieu Poirier opts->auxtrace_mmap_pages = MiB(4) / page_size; 363a818c563SMathieu Poirier } else { 364a818c563SMathieu Poirier opts->auxtrace_mmap_pages = KiB(128) / page_size; 365a818c563SMathieu Poirier if (opts->mmap_pages == UINT_MAX) 366a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 367a818c563SMathieu Poirier } 368a818c563SMathieu Poirier 369a818c563SMathieu Poirier } 370a818c563SMathieu Poirier 371a818c563SMathieu Poirier /* Validate auxtrace_mmap_pages provided by user */ 372a818c563SMathieu Poirier if (opts->auxtrace_mmap_pages) { 373a818c563SMathieu Poirier unsigned int max_page = (KiB(128) / page_size); 374a818c563SMathieu Poirier size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size; 375a818c563SMathieu Poirier 376a818c563SMathieu Poirier if (!privileged && 377a818c563SMathieu Poirier opts->auxtrace_mmap_pages > max_page) { 378a818c563SMathieu Poirier opts->auxtrace_mmap_pages = max_page; 379a818c563SMathieu Poirier pr_err("auxtrace too big, truncating to %d\n", 380a818c563SMathieu Poirier max_page); 381a818c563SMathieu Poirier } 382a818c563SMathieu Poirier 383a818c563SMathieu Poirier if (!is_power_of_2(sz)) { 384a818c563SMathieu Poirier pr_err("Invalid mmap size for %s: must be a power of 2\n", 385a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 386a818c563SMathieu Poirier return -EINVAL; 387a818c563SMathieu Poirier } 388a818c563SMathieu Poirier } 389a818c563SMathieu Poirier 390a818c563SMathieu Poirier if (opts->auxtrace_snapshot_mode) 391a818c563SMathieu Poirier pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME, 392a818c563SMathieu Poirier opts->auxtrace_snapshot_size); 393a818c563SMathieu Poirier 394a818c563SMathieu Poirier /* 395a818c563SMathieu Poirier * To obtain the auxtrace buffer file descriptor, the auxtrace 396a818c563SMathieu Poirier * event must come first. 397a818c563SMathieu Poirier */ 398e414fd1aSArnaldo Carvalho de Melo evlist__to_front(evlist, cs_etm_evsel); 3990c788d47SKim Phillips 400a818c563SMathieu Poirier /* 401a818c563SMathieu Poirier * In the case of per-cpu mmaps, we need the CPU on the 4023399ad9aSMathieu Poirier * AUX event. We also need the contextID in order to be notified 4033399ad9aSMathieu Poirier * when a context switch happened. 404a818c563SMathieu Poirier */ 405315c0a1fSJiri Olsa if (!perf_cpu_map__empty(cpus)) { 406862b2f8fSArnaldo Carvalho de Melo evsel__set_sample_bit(cs_etm_evsel, CPU); 407a818c563SMathieu Poirier 408374d910fSMathieu Poirier err = cs_etm_set_option(itr, cs_etm_evsel, 409374d910fSMathieu Poirier ETM_OPT_CTXTID | ETM_OPT_TS); 4101c839a5aSMathieu Poirier if (err) 4111c839a5aSMathieu Poirier goto out; 4123399ad9aSMathieu Poirier } 4133399ad9aSMathieu Poirier 414a818c563SMathieu Poirier /* Add dummy event to keep tracking */ 415a818c563SMathieu Poirier if (opts->full_auxtrace) { 41632dcd021SJiri Olsa struct evsel *tracking_evsel; 417a818c563SMathieu Poirier 418a818c563SMathieu Poirier err = parse_events(evlist, "dummy:u", NULL); 419a818c563SMathieu Poirier if (err) 4203399ad9aSMathieu Poirier goto out; 421a818c563SMathieu Poirier 422515dbe48SJiri Olsa tracking_evsel = evlist__last(evlist); 423e80db255SArnaldo Carvalho de Melo evlist__set_tracking_event(evlist, tracking_evsel); 424a818c563SMathieu Poirier 4251fc632ceSJiri Olsa tracking_evsel->core.attr.freq = 0; 4261fc632ceSJiri Olsa tracking_evsel->core.attr.sample_period = 1; 427a818c563SMathieu Poirier 428a818c563SMathieu Poirier /* In per-cpu case, always need the time of mmap events etc */ 429315c0a1fSJiri Olsa if (!perf_cpu_map__empty(cpus)) 430862b2f8fSArnaldo Carvalho de Melo evsel__set_sample_bit(tracking_evsel, TIME); 431a818c563SMathieu Poirier } 432a818c563SMathieu Poirier 4333399ad9aSMathieu Poirier out: 4343399ad9aSMathieu Poirier return err; 435a818c563SMathieu Poirier } 436a818c563SMathieu Poirier 437a818c563SMathieu Poirier static u64 cs_etm_get_config(struct auxtrace_record *itr) 438a818c563SMathieu Poirier { 439a818c563SMathieu Poirier u64 config = 0; 440a818c563SMathieu Poirier struct cs_etm_recording *ptr = 441a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 442a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 44363503dbaSJiri Olsa struct evlist *evlist = ptr->evlist; 44432dcd021SJiri Olsa struct evsel *evsel; 445a818c563SMathieu Poirier 446a818c563SMathieu Poirier evlist__for_each_entry(evlist, evsel) { 4471fc632ceSJiri Olsa if (evsel->core.attr.type == cs_etm_pmu->type) { 448a818c563SMathieu Poirier /* 449a818c563SMathieu Poirier * Variable perf_event_attr::config is assigned to 450a818c563SMathieu Poirier * ETMv3/PTM. The bit fields have been made to match 451a818c563SMathieu Poirier * the ETMv3.5 ETRMCR register specification. See the 452a818c563SMathieu Poirier * PMU_FORMAT_ATTR() declarations in 453a818c563SMathieu Poirier * drivers/hwtracing/coresight/coresight-perf.c for 454a818c563SMathieu Poirier * details. 455a818c563SMathieu Poirier */ 4561fc632ceSJiri Olsa config = evsel->core.attr.config; 457a818c563SMathieu Poirier break; 458a818c563SMathieu Poirier } 459a818c563SMathieu Poirier } 460a818c563SMathieu Poirier 461a818c563SMathieu Poirier return config; 462a818c563SMathieu Poirier } 463a818c563SMathieu Poirier 464df770ff0SMike Leach #ifndef BIT 465df770ff0SMike Leach #define BIT(N) (1UL << (N)) 466df770ff0SMike Leach #endif 467df770ff0SMike Leach 468df770ff0SMike Leach static u64 cs_etmv4_get_config(struct auxtrace_record *itr) 469df770ff0SMike Leach { 470df770ff0SMike Leach u64 config = 0; 471df770ff0SMike Leach u64 config_opts = 0; 472df770ff0SMike Leach 473df770ff0SMike Leach /* 474df770ff0SMike Leach * The perf event variable config bits represent both 475df770ff0SMike Leach * the command line options and register programming 476df770ff0SMike Leach * bits in ETMv3/PTM. For ETMv4 we must remap options 477df770ff0SMike Leach * to real bits 478df770ff0SMike Leach */ 479df770ff0SMike Leach config_opts = cs_etm_get_config(itr); 480df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_CYCACC)) 481df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_CYCACC); 4823399ad9aSMathieu Poirier if (config_opts & BIT(ETM_OPT_CTXTID)) 4833399ad9aSMathieu Poirier config |= BIT(ETM4_CFG_BIT_CTXTID); 484df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_TS)) 485df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_TS); 486df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_RETSTK)) 487df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_RETSTK); 488df770ff0SMike Leach 489df770ff0SMike Leach return config; 490df770ff0SMike Leach } 491df770ff0SMike Leach 492a818c563SMathieu Poirier static size_t 493a818c563SMathieu Poirier cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, 49463503dbaSJiri Olsa struct evlist *evlist __maybe_unused) 495a818c563SMathieu Poirier { 496a818c563SMathieu Poirier int i; 497a818c563SMathieu Poirier int etmv3 = 0, etmv4 = 0; 498f72f901dSJiri Olsa struct perf_cpu_map *event_cpus = evlist->core.cpus; 4999c3516d1SJiri Olsa struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); 500a818c563SMathieu Poirier 501a818c563SMathieu Poirier /* cpu map is not empty, we have specific CPUs to work with */ 502315c0a1fSJiri Olsa if (!perf_cpu_map__empty(event_cpus)) { 503796bfaddSMathieu Poirier for (i = 0; i < cpu__max_cpu(); i++) { 504796bfaddSMathieu Poirier if (!cpu_map__has(event_cpus, i) || 505796bfaddSMathieu Poirier !cpu_map__has(online_cpus, i)) 506796bfaddSMathieu Poirier continue; 507796bfaddSMathieu Poirier 508796bfaddSMathieu Poirier if (cs_etm_is_etmv4(itr, i)) 509a818c563SMathieu Poirier etmv4++; 510a818c563SMathieu Poirier else 511a818c563SMathieu Poirier etmv3++; 512a818c563SMathieu Poirier } 513a818c563SMathieu Poirier } else { 514a818c563SMathieu Poirier /* get configuration for all CPUs in the system */ 515a818c563SMathieu Poirier for (i = 0; i < cpu__max_cpu(); i++) { 516796bfaddSMathieu Poirier if (!cpu_map__has(online_cpus, i)) 517796bfaddSMathieu Poirier continue; 518796bfaddSMathieu Poirier 519a818c563SMathieu Poirier if (cs_etm_is_etmv4(itr, i)) 520a818c563SMathieu Poirier etmv4++; 521a818c563SMathieu Poirier else 522a818c563SMathieu Poirier etmv3++; 523a818c563SMathieu Poirier } 524a818c563SMathieu Poirier } 525a818c563SMathieu Poirier 52638f01d8dSJiri Olsa perf_cpu_map__put(online_cpus); 527796bfaddSMathieu Poirier 528a818c563SMathieu Poirier return (CS_ETM_HEADER_SIZE + 529a818c563SMathieu Poirier (etmv4 * CS_ETMV4_PRIV_SIZE) + 530a818c563SMathieu Poirier (etmv3 * CS_ETMV3_PRIV_SIZE)); 531a818c563SMathieu Poirier } 532a818c563SMathieu Poirier 533a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu) 534a818c563SMathieu Poirier { 535a818c563SMathieu Poirier bool ret = false; 536a818c563SMathieu Poirier char path[PATH_MAX]; 537a818c563SMathieu Poirier int scan; 538a818c563SMathieu Poirier unsigned int val; 539a818c563SMathieu Poirier struct cs_etm_recording *ptr = 540a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 541a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 542a818c563SMathieu Poirier 543a818c563SMathieu Poirier /* Take any of the RO files for ETMv4 and see if it present */ 544a818c563SMathieu Poirier snprintf(path, PATH_MAX, "cpu%d/%s", 545a818c563SMathieu Poirier cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 546a818c563SMathieu Poirier scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 547a818c563SMathieu Poirier 548a818c563SMathieu Poirier /* The file was read successfully, we have a winner */ 549a818c563SMathieu Poirier if (scan == 1) 550a818c563SMathieu Poirier ret = true; 551a818c563SMathieu Poirier 552a818c563SMathieu Poirier return ret; 553a818c563SMathieu Poirier } 554a818c563SMathieu Poirier 555a818c563SMathieu Poirier static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path) 556a818c563SMathieu Poirier { 557a818c563SMathieu Poirier char pmu_path[PATH_MAX]; 558a818c563SMathieu Poirier int scan; 559a818c563SMathieu Poirier unsigned int val = 0; 560a818c563SMathieu Poirier 561a818c563SMathieu Poirier /* Get RO metadata from sysfs */ 562a818c563SMathieu Poirier snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 563a818c563SMathieu Poirier 564a818c563SMathieu Poirier scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val); 565a818c563SMathieu Poirier if (scan != 1) 566a818c563SMathieu Poirier pr_err("%s: error reading: %s\n", __func__, pmu_path); 567a818c563SMathieu Poirier 568a818c563SMathieu Poirier return val; 569a818c563SMathieu Poirier } 570a818c563SMathieu Poirier 571a818c563SMathieu Poirier static void cs_etm_get_metadata(int cpu, u32 *offset, 572a818c563SMathieu Poirier struct auxtrace_record *itr, 57372932371SJiri Olsa struct perf_record_auxtrace_info *info) 574a818c563SMathieu Poirier { 575*42b2b570SMike Leach u32 increment, nr_trc_params; 576a818c563SMathieu Poirier u64 magic; 577a818c563SMathieu Poirier struct cs_etm_recording *ptr = 578a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 579a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 580a818c563SMathieu Poirier 581a818c563SMathieu Poirier /* first see what kind of tracer this cpu is affined to */ 582a818c563SMathieu Poirier if (cs_etm_is_etmv4(itr, cpu)) { 583a818c563SMathieu Poirier magic = __perf_cs_etmv4_magic; 584a818c563SMathieu Poirier /* Get trace configuration register */ 585a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCCONFIGR] = 586df770ff0SMike Leach cs_etmv4_get_config(itr); 587a818c563SMathieu Poirier /* Get traceID from the framework */ 588a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCTRACEIDR] = 589a818c563SMathieu Poirier coresight_get_trace_id(cpu); 590a818c563SMathieu Poirier /* Get read-only information from sysFS */ 591a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCIDR0] = 592a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 593a818c563SMathieu Poirier metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 594a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCIDR1] = 595a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 596a818c563SMathieu Poirier metadata_etmv4_ro[CS_ETMV4_TRCIDR1]); 597a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCIDR2] = 598a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 599a818c563SMathieu Poirier metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); 600a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCIDR8] = 601a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 602a818c563SMathieu Poirier metadata_etmv4_ro[CS_ETMV4_TRCIDR8]); 603a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCAUTHSTATUS] = 604a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 605a818c563SMathieu Poirier metadata_etmv4_ro 606a818c563SMathieu Poirier [CS_ETMV4_TRCAUTHSTATUS]); 607a818c563SMathieu Poirier 608a818c563SMathieu Poirier /* How much space was used */ 609a818c563SMathieu Poirier increment = CS_ETMV4_PRIV_MAX; 610*42b2b570SMike Leach nr_trc_params = CS_ETMV4_PRIV_MAX - CS_ETMV4_TRCCONFIGR; 611a818c563SMathieu Poirier } else { 612a818c563SMathieu Poirier magic = __perf_cs_etmv3_magic; 613a818c563SMathieu Poirier /* Get configuration register */ 614a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr); 615a818c563SMathieu Poirier /* Get traceID from the framework */ 616a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMTRACEIDR] = 617a818c563SMathieu Poirier coresight_get_trace_id(cpu); 618a818c563SMathieu Poirier /* Get read-only information from sysFS */ 619a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMCCER] = 620a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 621a818c563SMathieu Poirier metadata_etmv3_ro[CS_ETM_ETMCCER]); 622a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMIDR] = 623a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 624a818c563SMathieu Poirier metadata_etmv3_ro[CS_ETM_ETMIDR]); 625a818c563SMathieu Poirier 626a818c563SMathieu Poirier /* How much space was used */ 627a818c563SMathieu Poirier increment = CS_ETM_PRIV_MAX; 628*42b2b570SMike Leach nr_trc_params = CS_ETM_PRIV_MAX - CS_ETM_ETMCR; 629a818c563SMathieu Poirier } 630a818c563SMathieu Poirier 631a818c563SMathieu Poirier /* Build generic header portion */ 632a818c563SMathieu Poirier info->priv[*offset + CS_ETM_MAGIC] = magic; 633a818c563SMathieu Poirier info->priv[*offset + CS_ETM_CPU] = cpu; 634*42b2b570SMike Leach info->priv[*offset + CS_ETM_NR_TRC_PARAMS] = nr_trc_params; 635a818c563SMathieu Poirier /* Where the next CPU entry should start from */ 636a818c563SMathieu Poirier *offset += increment; 637a818c563SMathieu Poirier } 638a818c563SMathieu Poirier 639a818c563SMathieu Poirier static int cs_etm_info_fill(struct auxtrace_record *itr, 640a818c563SMathieu Poirier struct perf_session *session, 64172932371SJiri Olsa struct perf_record_auxtrace_info *info, 642a818c563SMathieu Poirier size_t priv_size) 643a818c563SMathieu Poirier { 644a818c563SMathieu Poirier int i; 645a818c563SMathieu Poirier u32 offset; 646a818c563SMathieu Poirier u64 nr_cpu, type; 647f854839bSJiri Olsa struct perf_cpu_map *cpu_map; 648f72f901dSJiri Olsa struct perf_cpu_map *event_cpus = session->evlist->core.cpus; 6499c3516d1SJiri Olsa struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL); 650a818c563SMathieu Poirier struct cs_etm_recording *ptr = 651a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 652a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 653a818c563SMathieu Poirier 654a818c563SMathieu Poirier if (priv_size != cs_etm_info_priv_size(itr, session->evlist)) 655a818c563SMathieu Poirier return -EINVAL; 656a818c563SMathieu Poirier 657c976ee11SJiri Olsa if (!session->evlist->core.nr_mmaps) 658a818c563SMathieu Poirier return -EINVAL; 659a818c563SMathieu Poirier 660796bfaddSMathieu Poirier /* If the cpu_map is empty all online CPUs are involved */ 661315c0a1fSJiri Olsa if (perf_cpu_map__empty(event_cpus)) { 662796bfaddSMathieu Poirier cpu_map = online_cpus; 663796bfaddSMathieu Poirier } else { 664796bfaddSMathieu Poirier /* Make sure all specified CPUs are online */ 6656549cd8fSJiri Olsa for (i = 0; i < perf_cpu_map__nr(event_cpus); i++) { 666796bfaddSMathieu Poirier if (cpu_map__has(event_cpus, i) && 667796bfaddSMathieu Poirier !cpu_map__has(online_cpus, i)) 668796bfaddSMathieu Poirier return -EINVAL; 669796bfaddSMathieu Poirier } 670796bfaddSMathieu Poirier 671796bfaddSMathieu Poirier cpu_map = event_cpus; 672796bfaddSMathieu Poirier } 673796bfaddSMathieu Poirier 6746549cd8fSJiri Olsa nr_cpu = perf_cpu_map__nr(cpu_map); 675a818c563SMathieu Poirier /* Get PMU type as dynamically assigned by the core */ 676a818c563SMathieu Poirier type = cs_etm_pmu->type; 677a818c563SMathieu Poirier 678a818c563SMathieu Poirier /* First fill out the session header */ 679a818c563SMathieu Poirier info->type = PERF_AUXTRACE_CS_ETM; 680*42b2b570SMike Leach info->priv[CS_HEADER_VERSION] = CS_HEADER_CURRENT_VERSION; 681a818c563SMathieu Poirier info->priv[CS_PMU_TYPE_CPUS] = type << 32; 682a818c563SMathieu Poirier info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu; 683a818c563SMathieu Poirier info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode; 684a818c563SMathieu Poirier 685a818c563SMathieu Poirier offset = CS_ETM_SNAPSHOT + 1; 686a818c563SMathieu Poirier 687796bfaddSMathieu Poirier for (i = 0; i < cpu__max_cpu() && offset < priv_size; i++) 688796bfaddSMathieu Poirier if (cpu_map__has(cpu_map, i)) 689a818c563SMathieu Poirier cs_etm_get_metadata(i, &offset, itr, info); 690796bfaddSMathieu Poirier 69138f01d8dSJiri Olsa perf_cpu_map__put(online_cpus); 692a818c563SMathieu Poirier 693a818c563SMathieu Poirier return 0; 694a818c563SMathieu Poirier } 695a818c563SMathieu Poirier 696e45c48a9SMathieu Poirier static int cs_etm_alloc_wrapped_array(struct cs_etm_recording *ptr, int idx) 697e45c48a9SMathieu Poirier { 698e45c48a9SMathieu Poirier bool *wrapped; 699e45c48a9SMathieu Poirier int cnt = ptr->wrapped_cnt; 700e45c48a9SMathieu Poirier 701e45c48a9SMathieu Poirier /* Make @ptr->wrapped as big as @idx */ 702e45c48a9SMathieu Poirier while (cnt <= idx) 703e45c48a9SMathieu Poirier cnt++; 704e45c48a9SMathieu Poirier 705e45c48a9SMathieu Poirier /* 706e45c48a9SMathieu Poirier * Free'ed in cs_etm_recording_free(). Using realloc() to avoid 707e45c48a9SMathieu Poirier * cross compilation problems where the host's system supports 708e45c48a9SMathieu Poirier * reallocarray() but not the target. 709e45c48a9SMathieu Poirier */ 710e45c48a9SMathieu Poirier wrapped = realloc(ptr->wrapped, cnt * sizeof(bool)); 711e45c48a9SMathieu Poirier if (!wrapped) 712e45c48a9SMathieu Poirier return -ENOMEM; 713e45c48a9SMathieu Poirier 714e45c48a9SMathieu Poirier wrapped[cnt - 1] = false; 715e45c48a9SMathieu Poirier ptr->wrapped_cnt = cnt; 716e45c48a9SMathieu Poirier ptr->wrapped = wrapped; 717e45c48a9SMathieu Poirier 718e45c48a9SMathieu Poirier return 0; 719e45c48a9SMathieu Poirier } 720e45c48a9SMathieu Poirier 721e45c48a9SMathieu Poirier static bool cs_etm_buffer_has_wrapped(unsigned char *buffer, 722e45c48a9SMathieu Poirier size_t buffer_size, u64 head) 723e45c48a9SMathieu Poirier { 724e45c48a9SMathieu Poirier u64 i, watermark; 725e45c48a9SMathieu Poirier u64 *buf = (u64 *)buffer; 726e45c48a9SMathieu Poirier size_t buf_size = buffer_size; 727e45c48a9SMathieu Poirier 728e45c48a9SMathieu Poirier /* 729e45c48a9SMathieu Poirier * We want to look the very last 512 byte (chosen arbitrarily) in 730e45c48a9SMathieu Poirier * the ring buffer. 731e45c48a9SMathieu Poirier */ 732e45c48a9SMathieu Poirier watermark = buf_size - 512; 733e45c48a9SMathieu Poirier 734e45c48a9SMathieu Poirier /* 735e45c48a9SMathieu Poirier * @head is continuously increasing - if its value is equal or greater 736e45c48a9SMathieu Poirier * than the size of the ring buffer, it has wrapped around. 737e45c48a9SMathieu Poirier */ 738e45c48a9SMathieu Poirier if (head >= buffer_size) 739e45c48a9SMathieu Poirier return true; 740e45c48a9SMathieu Poirier 741e45c48a9SMathieu Poirier /* 742e45c48a9SMathieu Poirier * The value of @head is somewhere within the size of the ring buffer. 743e45c48a9SMathieu Poirier * This can be that there hasn't been enough data to fill the ring 744e45c48a9SMathieu Poirier * buffer yet or the trace time was so long that @head has numerically 745e45c48a9SMathieu Poirier * wrapped around. To find we need to check if we have data at the very 746e45c48a9SMathieu Poirier * end of the ring buffer. We can reliably do this because mmap'ed 747e45c48a9SMathieu Poirier * pages are zeroed out and there is a fresh mapping with every new 748e45c48a9SMathieu Poirier * session. 749e45c48a9SMathieu Poirier */ 750e45c48a9SMathieu Poirier 751e45c48a9SMathieu Poirier /* @head is less than 512 byte from the end of the ring buffer */ 752e45c48a9SMathieu Poirier if (head > watermark) 753e45c48a9SMathieu Poirier watermark = head; 754e45c48a9SMathieu Poirier 755e45c48a9SMathieu Poirier /* 756e45c48a9SMathieu Poirier * Speed things up by using 64 bit transactions (see "u64 *buf" above) 757e45c48a9SMathieu Poirier */ 758e45c48a9SMathieu Poirier watermark >>= 3; 759e45c48a9SMathieu Poirier buf_size >>= 3; 760e45c48a9SMathieu Poirier 761e45c48a9SMathieu Poirier /* 762e45c48a9SMathieu Poirier * If we find trace data at the end of the ring buffer, @head has 763e45c48a9SMathieu Poirier * been there and has numerically wrapped around at least once. 764e45c48a9SMathieu Poirier */ 765e45c48a9SMathieu Poirier for (i = watermark; i < buf_size; i++) 766e45c48a9SMathieu Poirier if (buf[i]) 767e45c48a9SMathieu Poirier return true; 768e45c48a9SMathieu Poirier 769e45c48a9SMathieu Poirier return false; 770e45c48a9SMathieu Poirier } 771e45c48a9SMathieu Poirier 772e45c48a9SMathieu Poirier static int cs_etm_find_snapshot(struct auxtrace_record *itr, 773a818c563SMathieu Poirier int idx, struct auxtrace_mmap *mm, 774e45c48a9SMathieu Poirier unsigned char *data, 775a818c563SMathieu Poirier u64 *head, u64 *old) 776a818c563SMathieu Poirier { 777e45c48a9SMathieu Poirier int err; 778e45c48a9SMathieu Poirier bool wrapped; 779e45c48a9SMathieu Poirier struct cs_etm_recording *ptr = 780e45c48a9SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 781e45c48a9SMathieu Poirier 782e45c48a9SMathieu Poirier /* 783e45c48a9SMathieu Poirier * Allocate memory to keep track of wrapping if this is the first 784e45c48a9SMathieu Poirier * time we deal with this *mm. 785e45c48a9SMathieu Poirier */ 786e45c48a9SMathieu Poirier if (idx >= ptr->wrapped_cnt) { 787e45c48a9SMathieu Poirier err = cs_etm_alloc_wrapped_array(ptr, idx); 788e45c48a9SMathieu Poirier if (err) 789e45c48a9SMathieu Poirier return err; 790e45c48a9SMathieu Poirier } 791e45c48a9SMathieu Poirier 792e45c48a9SMathieu Poirier /* 793e45c48a9SMathieu Poirier * Check to see if *head has wrapped around. If it hasn't only the 794e45c48a9SMathieu Poirier * amount of data between *head and *old is snapshot'ed to avoid 795e45c48a9SMathieu Poirier * bloating the perf.data file with zeros. But as soon as *head has 796e45c48a9SMathieu Poirier * wrapped around the entire size of the AUX ring buffer it taken. 797e45c48a9SMathieu Poirier */ 798e45c48a9SMathieu Poirier wrapped = ptr->wrapped[idx]; 799e45c48a9SMathieu Poirier if (!wrapped && cs_etm_buffer_has_wrapped(data, mm->len, *head)) { 800e45c48a9SMathieu Poirier wrapped = true; 801e45c48a9SMathieu Poirier ptr->wrapped[idx] = true; 802e45c48a9SMathieu Poirier } 803e45c48a9SMathieu Poirier 804a818c563SMathieu Poirier pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n", 805a818c563SMathieu Poirier __func__, idx, (size_t)*old, (size_t)*head, mm->len); 806a818c563SMathieu Poirier 807e45c48a9SMathieu Poirier /* No wrap has occurred, we can just use *head and *old. */ 808e45c48a9SMathieu Poirier if (!wrapped) 809e45c48a9SMathieu Poirier return 0; 810e45c48a9SMathieu Poirier 811e45c48a9SMathieu Poirier /* 812e45c48a9SMathieu Poirier * *head has wrapped around - adjust *head and *old to pickup the 813e45c48a9SMathieu Poirier * entire content of the AUX buffer. 814e45c48a9SMathieu Poirier */ 815e45c48a9SMathieu Poirier if (*head >= mm->len) { 816e45c48a9SMathieu Poirier *old = *head - mm->len; 817e45c48a9SMathieu Poirier } else { 818a818c563SMathieu Poirier *head += mm->len; 819e45c48a9SMathieu Poirier *old = *head - mm->len; 820e45c48a9SMathieu Poirier } 821a818c563SMathieu Poirier 822a818c563SMathieu Poirier return 0; 823a818c563SMathieu Poirier } 824a818c563SMathieu Poirier 825a818c563SMathieu Poirier static int cs_etm_snapshot_start(struct auxtrace_record *itr) 826a818c563SMathieu Poirier { 827a818c563SMathieu Poirier struct cs_etm_recording *ptr = 828a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 82932dcd021SJiri Olsa struct evsel *evsel; 830a818c563SMathieu Poirier 831a818c563SMathieu Poirier evlist__for_each_entry(ptr->evlist, evsel) { 8321fc632ceSJiri Olsa if (evsel->core.attr.type == ptr->cs_etm_pmu->type) 8339a10bb22SJiri Olsa return evsel__disable(evsel); 834a818c563SMathieu Poirier } 835a818c563SMathieu Poirier return -EINVAL; 836a818c563SMathieu Poirier } 837a818c563SMathieu Poirier 838a818c563SMathieu Poirier static int cs_etm_snapshot_finish(struct auxtrace_record *itr) 839a818c563SMathieu Poirier { 840a818c563SMathieu Poirier struct cs_etm_recording *ptr = 841a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 84232dcd021SJiri Olsa struct evsel *evsel; 843a818c563SMathieu Poirier 844a818c563SMathieu Poirier evlist__for_each_entry(ptr->evlist, evsel) { 8451fc632ceSJiri Olsa if (evsel->core.attr.type == ptr->cs_etm_pmu->type) 846ec7f24efSJiri Olsa return evsel__enable(evsel); 847a818c563SMathieu Poirier } 848a818c563SMathieu Poirier return -EINVAL; 849a818c563SMathieu Poirier } 850a818c563SMathieu Poirier 851a818c563SMathieu Poirier static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused) 852a818c563SMathieu Poirier { 853a818c563SMathieu Poirier return (((u64) rand() << 0) & 0x00000000FFFFFFFFull) | 854a818c563SMathieu Poirier (((u64) rand() << 32) & 0xFFFFFFFF00000000ull); 855a818c563SMathieu Poirier } 856a818c563SMathieu Poirier 857a818c563SMathieu Poirier static void cs_etm_recording_free(struct auxtrace_record *itr) 858a818c563SMathieu Poirier { 859a818c563SMathieu Poirier struct cs_etm_recording *ptr = 860a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 861e45c48a9SMathieu Poirier 862e45c48a9SMathieu Poirier zfree(&ptr->wrapped); 863a818c563SMathieu Poirier free(ptr); 864a818c563SMathieu Poirier } 865a818c563SMathieu Poirier 866a818c563SMathieu Poirier struct auxtrace_record *cs_etm_record_init(int *err) 867a818c563SMathieu Poirier { 868a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu; 869a818c563SMathieu Poirier struct cs_etm_recording *ptr; 870a818c563SMathieu Poirier 871a818c563SMathieu Poirier cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME); 872a818c563SMathieu Poirier 873a818c563SMathieu Poirier if (!cs_etm_pmu) { 874a818c563SMathieu Poirier *err = -EINVAL; 875a818c563SMathieu Poirier goto out; 876a818c563SMathieu Poirier } 877a818c563SMathieu Poirier 878a818c563SMathieu Poirier ptr = zalloc(sizeof(struct cs_etm_recording)); 879a818c563SMathieu Poirier if (!ptr) { 880a818c563SMathieu Poirier *err = -ENOMEM; 881a818c563SMathieu Poirier goto out; 882a818c563SMathieu Poirier } 883a818c563SMathieu Poirier 884a818c563SMathieu Poirier ptr->cs_etm_pmu = cs_etm_pmu; 885ad60ba0cSAdrian Hunter ptr->itr.pmu = cs_etm_pmu; 886a818c563SMathieu Poirier ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options; 887a818c563SMathieu Poirier ptr->itr.recording_options = cs_etm_recording_options; 888a818c563SMathieu Poirier ptr->itr.info_priv_size = cs_etm_info_priv_size; 889a818c563SMathieu Poirier ptr->itr.info_fill = cs_etm_info_fill; 890a818c563SMathieu Poirier ptr->itr.find_snapshot = cs_etm_find_snapshot; 891a818c563SMathieu Poirier ptr->itr.snapshot_start = cs_etm_snapshot_start; 892a818c563SMathieu Poirier ptr->itr.snapshot_finish = cs_etm_snapshot_finish; 893a818c563SMathieu Poirier ptr->itr.reference = cs_etm_reference; 894a818c563SMathieu Poirier ptr->itr.free = cs_etm_recording_free; 895ad60ba0cSAdrian Hunter ptr->itr.read_finish = auxtrace_record__read_finish; 896a818c563SMathieu Poirier 897a818c563SMathieu Poirier *err = 0; 898a818c563SMathieu Poirier return &ptr->itr; 899a818c563SMathieu Poirier out: 900a818c563SMathieu Poirier return NULL; 901a818c563SMathieu Poirier } 902