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> 8*fa4e819bSMathieu 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> 14a818c563SMathieu Poirier #include <linux/types.h> 15a818c563SMathieu Poirier 16a818c563SMathieu Poirier #include "cs-etm.h" 17a818c563SMathieu Poirier #include "../../perf.h" 18a818c563SMathieu Poirier #include "../../util/auxtrace.h" 19a818c563SMathieu Poirier #include "../../util/cpumap.h" 20a818c563SMathieu Poirier #include "../../util/evlist.h" 213becf452SMathieu Poirier #include "../../util/evsel.h" 22a818c563SMathieu Poirier #include "../../util/pmu.h" 23a818c563SMathieu Poirier #include "../../util/thread_map.h" 24a818c563SMathieu Poirier #include "../../util/cs-etm.h" 25a818c563SMathieu Poirier 26*fa4e819bSMathieu Poirier #include <errno.h> 27a818c563SMathieu Poirier #include <stdlib.h> 287a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h> 29a818c563SMathieu Poirier 303becf452SMathieu Poirier #define ENABLE_SINK_MAX 128 313becf452SMathieu Poirier #define CS_BUS_DEVICE_PATH "/bus/coresight/devices/" 323becf452SMathieu Poirier 33a818c563SMathieu Poirier struct cs_etm_recording { 34a818c563SMathieu Poirier struct auxtrace_record itr; 35a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu; 36a818c563SMathieu Poirier struct perf_evlist *evlist; 37a818c563SMathieu Poirier bool snapshot_mode; 38a818c563SMathieu Poirier size_t snapshot_size; 39a818c563SMathieu Poirier }; 40a818c563SMathieu Poirier 41a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu); 42a818c563SMathieu Poirier 43a818c563SMathieu Poirier static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr, 44a818c563SMathieu Poirier struct record_opts *opts, 45a818c563SMathieu Poirier const char *str) 46a818c563SMathieu Poirier { 47a818c563SMathieu Poirier struct cs_etm_recording *ptr = 48a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 49a818c563SMathieu Poirier unsigned long long snapshot_size = 0; 50a818c563SMathieu Poirier char *endptr; 51a818c563SMathieu Poirier 52a818c563SMathieu Poirier if (str) { 53a818c563SMathieu Poirier snapshot_size = strtoull(str, &endptr, 0); 54a818c563SMathieu Poirier if (*endptr || snapshot_size > SIZE_MAX) 55a818c563SMathieu Poirier return -1; 56a818c563SMathieu Poirier } 57a818c563SMathieu Poirier 58a818c563SMathieu Poirier opts->auxtrace_snapshot_mode = true; 59a818c563SMathieu Poirier opts->auxtrace_snapshot_size = snapshot_size; 60a818c563SMathieu Poirier ptr->snapshot_size = snapshot_size; 61a818c563SMathieu Poirier 62a818c563SMathieu Poirier return 0; 63a818c563SMathieu Poirier } 64a818c563SMathieu Poirier 65*fa4e819bSMathieu Poirier static int cs_etm_set_sink_attr(struct perf_pmu *pmu, 66*fa4e819bSMathieu Poirier struct perf_evsel *evsel) 67*fa4e819bSMathieu Poirier { 68*fa4e819bSMathieu Poirier char msg[BUFSIZ], path[PATH_MAX], *sink; 69*fa4e819bSMathieu Poirier struct perf_evsel_config_term *term; 70*fa4e819bSMathieu Poirier int ret = -EINVAL; 71*fa4e819bSMathieu Poirier u32 hash; 72*fa4e819bSMathieu Poirier 73*fa4e819bSMathieu Poirier if (evsel->attr.config2 & GENMASK(31, 0)) 74*fa4e819bSMathieu Poirier return 0; 75*fa4e819bSMathieu Poirier 76*fa4e819bSMathieu Poirier list_for_each_entry(term, &evsel->config_terms, list) { 77*fa4e819bSMathieu Poirier if (term->type != PERF_EVSEL__CONFIG_TERM_DRV_CFG) 78*fa4e819bSMathieu Poirier continue; 79*fa4e819bSMathieu Poirier 80*fa4e819bSMathieu Poirier sink = term->val.drv_cfg; 81*fa4e819bSMathieu Poirier snprintf(path, PATH_MAX, "sinks/%s", sink); 82*fa4e819bSMathieu Poirier 83*fa4e819bSMathieu Poirier ret = perf_pmu__scan_file(pmu, path, "%x", &hash); 84*fa4e819bSMathieu Poirier if (ret != 1) { 85*fa4e819bSMathieu Poirier pr_err("failed to set sink \"%s\" on event %s with %d (%s)\n", 86*fa4e819bSMathieu Poirier sink, perf_evsel__name(evsel), errno, 87*fa4e819bSMathieu Poirier str_error_r(errno, msg, sizeof(msg))); 88*fa4e819bSMathieu Poirier return ret; 89*fa4e819bSMathieu Poirier } 90*fa4e819bSMathieu Poirier 91*fa4e819bSMathieu Poirier evsel->attr.config2 |= hash; 92*fa4e819bSMathieu Poirier return 0; 93*fa4e819bSMathieu Poirier } 94*fa4e819bSMathieu Poirier 95*fa4e819bSMathieu Poirier /* 96*fa4e819bSMathieu Poirier * No sink was provided on the command line - for _now_ treat 97*fa4e819bSMathieu Poirier * this as an error. 98*fa4e819bSMathieu Poirier */ 99*fa4e819bSMathieu Poirier return ret; 100*fa4e819bSMathieu Poirier } 101*fa4e819bSMathieu Poirier 102a818c563SMathieu Poirier static int cs_etm_recording_options(struct auxtrace_record *itr, 103a818c563SMathieu Poirier struct perf_evlist *evlist, 104a818c563SMathieu Poirier struct record_opts *opts) 105a818c563SMathieu Poirier { 106*fa4e819bSMathieu Poirier int ret; 107a818c563SMathieu Poirier struct cs_etm_recording *ptr = 108a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 109a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 110a818c563SMathieu Poirier struct perf_evsel *evsel, *cs_etm_evsel = NULL; 111a818c563SMathieu Poirier const struct cpu_map *cpus = evlist->cpus; 112a818c563SMathieu Poirier bool privileged = (geteuid() == 0 || perf_event_paranoid() < 0); 113a818c563SMathieu Poirier 114a818c563SMathieu Poirier ptr->evlist = evlist; 115a818c563SMathieu Poirier ptr->snapshot_mode = opts->auxtrace_snapshot_mode; 116a818c563SMathieu Poirier 117a818c563SMathieu Poirier evlist__for_each_entry(evlist, evsel) { 118a818c563SMathieu Poirier if (evsel->attr.type == cs_etm_pmu->type) { 119a818c563SMathieu Poirier if (cs_etm_evsel) { 120a818c563SMathieu Poirier pr_err("There may be only one %s event\n", 121a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 122a818c563SMathieu Poirier return -EINVAL; 123a818c563SMathieu Poirier } 124a818c563SMathieu Poirier evsel->attr.freq = 0; 125a818c563SMathieu Poirier evsel->attr.sample_period = 1; 126a818c563SMathieu Poirier cs_etm_evsel = evsel; 127a818c563SMathieu Poirier opts->full_auxtrace = true; 128a818c563SMathieu Poirier } 129a818c563SMathieu Poirier } 130a818c563SMathieu Poirier 131a818c563SMathieu Poirier /* no need to continue if at least one event of interest was found */ 132a818c563SMathieu Poirier if (!cs_etm_evsel) 133a818c563SMathieu Poirier return 0; 134a818c563SMathieu Poirier 135*fa4e819bSMathieu Poirier ret = cs_etm_set_sink_attr(cs_etm_pmu, cs_etm_evsel); 136*fa4e819bSMathieu Poirier if (ret) 137*fa4e819bSMathieu Poirier return ret; 138*fa4e819bSMathieu Poirier 139a818c563SMathieu Poirier if (opts->use_clockid) { 140a818c563SMathieu Poirier pr_err("Cannot use clockid (-k option) with %s\n", 141a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 142a818c563SMathieu Poirier return -EINVAL; 143a818c563SMathieu Poirier } 144a818c563SMathieu Poirier 145a818c563SMathieu Poirier /* we are in snapshot mode */ 146a818c563SMathieu Poirier if (opts->auxtrace_snapshot_mode) { 147a818c563SMathieu Poirier /* 148a818c563SMathieu Poirier * No size were given to '-S' or '-m,', so go with 149a818c563SMathieu Poirier * the default 150a818c563SMathieu Poirier */ 151a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size && 152a818c563SMathieu Poirier !opts->auxtrace_mmap_pages) { 153a818c563SMathieu Poirier if (privileged) { 154a818c563SMathieu Poirier opts->auxtrace_mmap_pages = MiB(4) / page_size; 155a818c563SMathieu Poirier } else { 156a818c563SMathieu Poirier opts->auxtrace_mmap_pages = 157a818c563SMathieu Poirier KiB(128) / page_size; 158a818c563SMathieu Poirier if (opts->mmap_pages == UINT_MAX) 159a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 160a818c563SMathieu Poirier } 161a818c563SMathieu Poirier } else if (!opts->auxtrace_mmap_pages && !privileged && 162a818c563SMathieu Poirier opts->mmap_pages == UINT_MAX) { 163a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 164a818c563SMathieu Poirier } 165a818c563SMathieu Poirier 166a818c563SMathieu Poirier /* 167a818c563SMathieu Poirier * '-m,xyz' was specified but no snapshot size, so make the 168a818c563SMathieu Poirier * snapshot size as big as the auxtrace mmap area. 169a818c563SMathieu Poirier */ 170a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size) { 171a818c563SMathieu Poirier opts->auxtrace_snapshot_size = 172a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size; 173a818c563SMathieu Poirier } 174a818c563SMathieu Poirier 175a818c563SMathieu Poirier /* 176a818c563SMathieu Poirier * -Sxyz was specified but no auxtrace mmap area, so make the 177a818c563SMathieu Poirier * auxtrace mmap area big enough to fit the requested snapshot 178a818c563SMathieu Poirier * size. 179a818c563SMathieu Poirier */ 180a818c563SMathieu Poirier if (!opts->auxtrace_mmap_pages) { 181a818c563SMathieu Poirier size_t sz = opts->auxtrace_snapshot_size; 182a818c563SMathieu Poirier 183a818c563SMathieu Poirier sz = round_up(sz, page_size) / page_size; 184a818c563SMathieu Poirier opts->auxtrace_mmap_pages = roundup_pow_of_two(sz); 185a818c563SMathieu Poirier } 186a818c563SMathieu Poirier 187a818c563SMathieu Poirier /* Snapshost size can't be bigger than the auxtrace area */ 188a818c563SMathieu Poirier if (opts->auxtrace_snapshot_size > 189a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size) { 190a818c563SMathieu Poirier pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n", 191a818c563SMathieu Poirier opts->auxtrace_snapshot_size, 192a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size); 193a818c563SMathieu Poirier return -EINVAL; 194a818c563SMathieu Poirier } 195a818c563SMathieu Poirier 196a818c563SMathieu Poirier /* Something went wrong somewhere - this shouldn't happen */ 197a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size || 198a818c563SMathieu Poirier !opts->auxtrace_mmap_pages) { 199a818c563SMathieu Poirier pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n"); 200a818c563SMathieu Poirier return -EINVAL; 201a818c563SMathieu Poirier } 202a818c563SMathieu Poirier } 203a818c563SMathieu Poirier 204a818c563SMathieu Poirier /* We are in full trace mode but '-m,xyz' wasn't specified */ 205a818c563SMathieu Poirier if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) { 206a818c563SMathieu Poirier if (privileged) { 207a818c563SMathieu Poirier opts->auxtrace_mmap_pages = MiB(4) / page_size; 208a818c563SMathieu Poirier } else { 209a818c563SMathieu Poirier opts->auxtrace_mmap_pages = KiB(128) / page_size; 210a818c563SMathieu Poirier if (opts->mmap_pages == UINT_MAX) 211a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 212a818c563SMathieu Poirier } 213a818c563SMathieu Poirier 214a818c563SMathieu Poirier } 215a818c563SMathieu Poirier 216a818c563SMathieu Poirier /* Validate auxtrace_mmap_pages provided by user */ 217a818c563SMathieu Poirier if (opts->auxtrace_mmap_pages) { 218a818c563SMathieu Poirier unsigned int max_page = (KiB(128) / page_size); 219a818c563SMathieu Poirier size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size; 220a818c563SMathieu Poirier 221a818c563SMathieu Poirier if (!privileged && 222a818c563SMathieu Poirier opts->auxtrace_mmap_pages > max_page) { 223a818c563SMathieu Poirier opts->auxtrace_mmap_pages = max_page; 224a818c563SMathieu Poirier pr_err("auxtrace too big, truncating to %d\n", 225a818c563SMathieu Poirier max_page); 226a818c563SMathieu Poirier } 227a818c563SMathieu Poirier 228a818c563SMathieu Poirier if (!is_power_of_2(sz)) { 229a818c563SMathieu Poirier pr_err("Invalid mmap size for %s: must be a power of 2\n", 230a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 231a818c563SMathieu Poirier return -EINVAL; 232a818c563SMathieu Poirier } 233a818c563SMathieu Poirier } 234a818c563SMathieu Poirier 235a818c563SMathieu Poirier if (opts->auxtrace_snapshot_mode) 236a818c563SMathieu Poirier pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME, 237a818c563SMathieu Poirier opts->auxtrace_snapshot_size); 238a818c563SMathieu Poirier 239a818c563SMathieu Poirier /* 240a818c563SMathieu Poirier * To obtain the auxtrace buffer file descriptor, the auxtrace 241a818c563SMathieu Poirier * event must come first. 242a818c563SMathieu Poirier */ 243a818c563SMathieu Poirier perf_evlist__to_front(evlist, cs_etm_evsel); 2440c788d47SKim Phillips 245a818c563SMathieu Poirier /* 246a818c563SMathieu Poirier * In the case of per-cpu mmaps, we need the CPU on the 247a818c563SMathieu Poirier * AUX event. 248a818c563SMathieu Poirier */ 249a818c563SMathieu Poirier if (!cpu_map__empty(cpus)) 250a818c563SMathieu Poirier perf_evsel__set_sample_bit(cs_etm_evsel, CPU); 251a818c563SMathieu Poirier 252a818c563SMathieu Poirier /* Add dummy event to keep tracking */ 253a818c563SMathieu Poirier if (opts->full_auxtrace) { 254a818c563SMathieu Poirier struct perf_evsel *tracking_evsel; 255a818c563SMathieu Poirier int err; 256a818c563SMathieu Poirier 257a818c563SMathieu Poirier err = parse_events(evlist, "dummy:u", NULL); 258a818c563SMathieu Poirier if (err) 259a818c563SMathieu Poirier return err; 260a818c563SMathieu Poirier 261a818c563SMathieu Poirier tracking_evsel = perf_evlist__last(evlist); 262a818c563SMathieu Poirier perf_evlist__set_tracking_event(evlist, tracking_evsel); 263a818c563SMathieu Poirier 264a818c563SMathieu Poirier tracking_evsel->attr.freq = 0; 265a818c563SMathieu Poirier tracking_evsel->attr.sample_period = 1; 266a818c563SMathieu Poirier 267a818c563SMathieu Poirier /* In per-cpu case, always need the time of mmap events etc */ 268a818c563SMathieu Poirier if (!cpu_map__empty(cpus)) 269a818c563SMathieu Poirier perf_evsel__set_sample_bit(tracking_evsel, TIME); 270a818c563SMathieu Poirier } 271a818c563SMathieu Poirier 272a818c563SMathieu Poirier return 0; 273a818c563SMathieu Poirier } 274a818c563SMathieu Poirier 275a818c563SMathieu Poirier static u64 cs_etm_get_config(struct auxtrace_record *itr) 276a818c563SMathieu Poirier { 277a818c563SMathieu Poirier u64 config = 0; 278a818c563SMathieu Poirier struct cs_etm_recording *ptr = 279a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 280a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 281a818c563SMathieu Poirier struct perf_evlist *evlist = ptr->evlist; 282a818c563SMathieu Poirier struct perf_evsel *evsel; 283a818c563SMathieu Poirier 284a818c563SMathieu Poirier evlist__for_each_entry(evlist, evsel) { 285a818c563SMathieu Poirier if (evsel->attr.type == cs_etm_pmu->type) { 286a818c563SMathieu Poirier /* 287a818c563SMathieu Poirier * Variable perf_event_attr::config is assigned to 288a818c563SMathieu Poirier * ETMv3/PTM. The bit fields have been made to match 289a818c563SMathieu Poirier * the ETMv3.5 ETRMCR register specification. See the 290a818c563SMathieu Poirier * PMU_FORMAT_ATTR() declarations in 291a818c563SMathieu Poirier * drivers/hwtracing/coresight/coresight-perf.c for 292a818c563SMathieu Poirier * details. 293a818c563SMathieu Poirier */ 294a818c563SMathieu Poirier config = evsel->attr.config; 295a818c563SMathieu Poirier break; 296a818c563SMathieu Poirier } 297a818c563SMathieu Poirier } 298a818c563SMathieu Poirier 299a818c563SMathieu Poirier return config; 300a818c563SMathieu Poirier } 301a818c563SMathieu Poirier 302df770ff0SMike Leach #ifndef BIT 303df770ff0SMike Leach #define BIT(N) (1UL << (N)) 304df770ff0SMike Leach #endif 305df770ff0SMike Leach 306df770ff0SMike Leach static u64 cs_etmv4_get_config(struct auxtrace_record *itr) 307df770ff0SMike Leach { 308df770ff0SMike Leach u64 config = 0; 309df770ff0SMike Leach u64 config_opts = 0; 310df770ff0SMike Leach 311df770ff0SMike Leach /* 312df770ff0SMike Leach * The perf event variable config bits represent both 313df770ff0SMike Leach * the command line options and register programming 314df770ff0SMike Leach * bits in ETMv3/PTM. For ETMv4 we must remap options 315df770ff0SMike Leach * to real bits 316df770ff0SMike Leach */ 317df770ff0SMike Leach config_opts = cs_etm_get_config(itr); 318df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_CYCACC)) 319df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_CYCACC); 320df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_TS)) 321df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_TS); 322df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_RETSTK)) 323df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_RETSTK); 324df770ff0SMike Leach 325df770ff0SMike Leach return config; 326df770ff0SMike Leach } 327df770ff0SMike Leach 328a818c563SMathieu Poirier static size_t 329a818c563SMathieu Poirier cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, 330a818c563SMathieu Poirier struct perf_evlist *evlist __maybe_unused) 331a818c563SMathieu Poirier { 332a818c563SMathieu Poirier int i; 333a818c563SMathieu Poirier int etmv3 = 0, etmv4 = 0; 334796bfaddSMathieu Poirier struct cpu_map *event_cpus = evlist->cpus; 335796bfaddSMathieu Poirier struct cpu_map *online_cpus = cpu_map__new(NULL); 336a818c563SMathieu Poirier 337a818c563SMathieu Poirier /* cpu map is not empty, we have specific CPUs to work with */ 338796bfaddSMathieu Poirier if (!cpu_map__empty(event_cpus)) { 339796bfaddSMathieu Poirier for (i = 0; i < cpu__max_cpu(); i++) { 340796bfaddSMathieu Poirier if (!cpu_map__has(event_cpus, i) || 341796bfaddSMathieu Poirier !cpu_map__has(online_cpus, i)) 342796bfaddSMathieu Poirier continue; 343796bfaddSMathieu Poirier 344796bfaddSMathieu Poirier if (cs_etm_is_etmv4(itr, i)) 345a818c563SMathieu Poirier etmv4++; 346a818c563SMathieu Poirier else 347a818c563SMathieu Poirier etmv3++; 348a818c563SMathieu Poirier } 349a818c563SMathieu Poirier } else { 350a818c563SMathieu Poirier /* get configuration for all CPUs in the system */ 351a818c563SMathieu Poirier for (i = 0; i < cpu__max_cpu(); i++) { 352796bfaddSMathieu Poirier if (!cpu_map__has(online_cpus, i)) 353796bfaddSMathieu Poirier continue; 354796bfaddSMathieu Poirier 355a818c563SMathieu Poirier if (cs_etm_is_etmv4(itr, i)) 356a818c563SMathieu Poirier etmv4++; 357a818c563SMathieu Poirier else 358a818c563SMathieu Poirier etmv3++; 359a818c563SMathieu Poirier } 360a818c563SMathieu Poirier } 361a818c563SMathieu Poirier 362796bfaddSMathieu Poirier cpu_map__put(online_cpus); 363796bfaddSMathieu Poirier 364a818c563SMathieu Poirier return (CS_ETM_HEADER_SIZE + 365a818c563SMathieu Poirier (etmv4 * CS_ETMV4_PRIV_SIZE) + 366a818c563SMathieu Poirier (etmv3 * CS_ETMV3_PRIV_SIZE)); 367a818c563SMathieu Poirier } 368a818c563SMathieu Poirier 369a818c563SMathieu Poirier static const char *metadata_etmv3_ro[CS_ETM_PRIV_MAX] = { 370a818c563SMathieu Poirier [CS_ETM_ETMCCER] = "mgmt/etmccer", 371a818c563SMathieu Poirier [CS_ETM_ETMIDR] = "mgmt/etmidr", 372a818c563SMathieu Poirier }; 373a818c563SMathieu Poirier 374a818c563SMathieu Poirier static const char *metadata_etmv4_ro[CS_ETMV4_PRIV_MAX] = { 375a818c563SMathieu Poirier [CS_ETMV4_TRCIDR0] = "trcidr/trcidr0", 376a818c563SMathieu Poirier [CS_ETMV4_TRCIDR1] = "trcidr/trcidr1", 377a818c563SMathieu Poirier [CS_ETMV4_TRCIDR2] = "trcidr/trcidr2", 378a818c563SMathieu Poirier [CS_ETMV4_TRCIDR8] = "trcidr/trcidr8", 379a818c563SMathieu Poirier [CS_ETMV4_TRCAUTHSTATUS] = "mgmt/trcauthstatus", 380a818c563SMathieu Poirier }; 381a818c563SMathieu Poirier 382a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu) 383a818c563SMathieu Poirier { 384a818c563SMathieu Poirier bool ret = false; 385a818c563SMathieu Poirier char path[PATH_MAX]; 386a818c563SMathieu Poirier int scan; 387a818c563SMathieu Poirier unsigned int val; 388a818c563SMathieu Poirier struct cs_etm_recording *ptr = 389a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 390a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 391a818c563SMathieu Poirier 392a818c563SMathieu Poirier /* Take any of the RO files for ETMv4 and see if it present */ 393a818c563SMathieu Poirier snprintf(path, PATH_MAX, "cpu%d/%s", 394a818c563SMathieu Poirier cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 395a818c563SMathieu Poirier scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 396a818c563SMathieu Poirier 397a818c563SMathieu Poirier /* The file was read successfully, we have a winner */ 398a818c563SMathieu Poirier if (scan == 1) 399a818c563SMathieu Poirier ret = true; 400a818c563SMathieu Poirier 401a818c563SMathieu Poirier return ret; 402a818c563SMathieu Poirier } 403a818c563SMathieu Poirier 404a818c563SMathieu Poirier static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path) 405a818c563SMathieu Poirier { 406a818c563SMathieu Poirier char pmu_path[PATH_MAX]; 407a818c563SMathieu Poirier int scan; 408a818c563SMathieu Poirier unsigned int val = 0; 409a818c563SMathieu Poirier 410a818c563SMathieu Poirier /* Get RO metadata from sysfs */ 411a818c563SMathieu Poirier snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 412a818c563SMathieu Poirier 413a818c563SMathieu Poirier scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val); 414a818c563SMathieu Poirier if (scan != 1) 415a818c563SMathieu Poirier pr_err("%s: error reading: %s\n", __func__, pmu_path); 416a818c563SMathieu Poirier 417a818c563SMathieu Poirier return val; 418a818c563SMathieu Poirier } 419a818c563SMathieu Poirier 420a818c563SMathieu Poirier static void cs_etm_get_metadata(int cpu, u32 *offset, 421a818c563SMathieu Poirier struct auxtrace_record *itr, 422a818c563SMathieu Poirier struct auxtrace_info_event *info) 423a818c563SMathieu Poirier { 424a818c563SMathieu Poirier u32 increment; 425a818c563SMathieu Poirier u64 magic; 426a818c563SMathieu Poirier struct cs_etm_recording *ptr = 427a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 428a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 429a818c563SMathieu Poirier 430a818c563SMathieu Poirier /* first see what kind of tracer this cpu is affined to */ 431a818c563SMathieu Poirier if (cs_etm_is_etmv4(itr, cpu)) { 432a818c563SMathieu Poirier magic = __perf_cs_etmv4_magic; 433a818c563SMathieu Poirier /* Get trace configuration register */ 434a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCCONFIGR] = 435df770ff0SMike Leach cs_etmv4_get_config(itr); 436a818c563SMathieu Poirier /* Get traceID from the framework */ 437a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCTRACEIDR] = 438a818c563SMathieu Poirier coresight_get_trace_id(cpu); 439a818c563SMathieu Poirier /* Get read-only information from sysFS */ 440a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCIDR0] = 441a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 442a818c563SMathieu Poirier metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 443a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCIDR1] = 444a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 445a818c563SMathieu Poirier metadata_etmv4_ro[CS_ETMV4_TRCIDR1]); 446a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCIDR2] = 447a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 448a818c563SMathieu Poirier metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); 449a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCIDR8] = 450a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 451a818c563SMathieu Poirier metadata_etmv4_ro[CS_ETMV4_TRCIDR8]); 452a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCAUTHSTATUS] = 453a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 454a818c563SMathieu Poirier metadata_etmv4_ro 455a818c563SMathieu Poirier [CS_ETMV4_TRCAUTHSTATUS]); 456a818c563SMathieu Poirier 457a818c563SMathieu Poirier /* How much space was used */ 458a818c563SMathieu Poirier increment = CS_ETMV4_PRIV_MAX; 459a818c563SMathieu Poirier } else { 460a818c563SMathieu Poirier magic = __perf_cs_etmv3_magic; 461a818c563SMathieu Poirier /* Get configuration register */ 462a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr); 463a818c563SMathieu Poirier /* Get traceID from the framework */ 464a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMTRACEIDR] = 465a818c563SMathieu Poirier coresight_get_trace_id(cpu); 466a818c563SMathieu Poirier /* Get read-only information from sysFS */ 467a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMCCER] = 468a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 469a818c563SMathieu Poirier metadata_etmv3_ro[CS_ETM_ETMCCER]); 470a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMIDR] = 471a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 472a818c563SMathieu Poirier metadata_etmv3_ro[CS_ETM_ETMIDR]); 473a818c563SMathieu Poirier 474a818c563SMathieu Poirier /* How much space was used */ 475a818c563SMathieu Poirier increment = CS_ETM_PRIV_MAX; 476a818c563SMathieu Poirier } 477a818c563SMathieu Poirier 478a818c563SMathieu Poirier /* Build generic header portion */ 479a818c563SMathieu Poirier info->priv[*offset + CS_ETM_MAGIC] = magic; 480a818c563SMathieu Poirier info->priv[*offset + CS_ETM_CPU] = cpu; 481a818c563SMathieu Poirier /* Where the next CPU entry should start from */ 482a818c563SMathieu Poirier *offset += increment; 483a818c563SMathieu Poirier } 484a818c563SMathieu Poirier 485a818c563SMathieu Poirier static int cs_etm_info_fill(struct auxtrace_record *itr, 486a818c563SMathieu Poirier struct perf_session *session, 487a818c563SMathieu Poirier struct auxtrace_info_event *info, 488a818c563SMathieu Poirier size_t priv_size) 489a818c563SMathieu Poirier { 490a818c563SMathieu Poirier int i; 491a818c563SMathieu Poirier u32 offset; 492a818c563SMathieu Poirier u64 nr_cpu, type; 493796bfaddSMathieu Poirier struct cpu_map *cpu_map; 494796bfaddSMathieu Poirier struct cpu_map *event_cpus = session->evlist->cpus; 495796bfaddSMathieu Poirier struct cpu_map *online_cpus = cpu_map__new(NULL); 496a818c563SMathieu Poirier struct cs_etm_recording *ptr = 497a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 498a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 499a818c563SMathieu Poirier 500a818c563SMathieu Poirier if (priv_size != cs_etm_info_priv_size(itr, session->evlist)) 501a818c563SMathieu Poirier return -EINVAL; 502a818c563SMathieu Poirier 503a818c563SMathieu Poirier if (!session->evlist->nr_mmaps) 504a818c563SMathieu Poirier return -EINVAL; 505a818c563SMathieu Poirier 506796bfaddSMathieu Poirier /* If the cpu_map is empty all online CPUs are involved */ 507796bfaddSMathieu Poirier if (cpu_map__empty(event_cpus)) { 508796bfaddSMathieu Poirier cpu_map = online_cpus; 509796bfaddSMathieu Poirier } else { 510796bfaddSMathieu Poirier /* Make sure all specified CPUs are online */ 511796bfaddSMathieu Poirier for (i = 0; i < cpu_map__nr(event_cpus); i++) { 512796bfaddSMathieu Poirier if (cpu_map__has(event_cpus, i) && 513796bfaddSMathieu Poirier !cpu_map__has(online_cpus, i)) 514796bfaddSMathieu Poirier return -EINVAL; 515796bfaddSMathieu Poirier } 516796bfaddSMathieu Poirier 517796bfaddSMathieu Poirier cpu_map = event_cpus; 518796bfaddSMathieu Poirier } 519796bfaddSMathieu Poirier 520796bfaddSMathieu Poirier nr_cpu = cpu_map__nr(cpu_map); 521a818c563SMathieu Poirier /* Get PMU type as dynamically assigned by the core */ 522a818c563SMathieu Poirier type = cs_etm_pmu->type; 523a818c563SMathieu Poirier 524a818c563SMathieu Poirier /* First fill out the session header */ 525a818c563SMathieu Poirier info->type = PERF_AUXTRACE_CS_ETM; 526a818c563SMathieu Poirier info->priv[CS_HEADER_VERSION_0] = 0; 527a818c563SMathieu Poirier info->priv[CS_PMU_TYPE_CPUS] = type << 32; 528a818c563SMathieu Poirier info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu; 529a818c563SMathieu Poirier info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode; 530a818c563SMathieu Poirier 531a818c563SMathieu Poirier offset = CS_ETM_SNAPSHOT + 1; 532a818c563SMathieu Poirier 533796bfaddSMathieu Poirier for (i = 0; i < cpu__max_cpu() && offset < priv_size; i++) 534796bfaddSMathieu Poirier if (cpu_map__has(cpu_map, i)) 535a818c563SMathieu Poirier cs_etm_get_metadata(i, &offset, itr, info); 536796bfaddSMathieu Poirier 537796bfaddSMathieu Poirier cpu_map__put(online_cpus); 538a818c563SMathieu Poirier 539a818c563SMathieu Poirier return 0; 540a818c563SMathieu Poirier } 541a818c563SMathieu Poirier 542a818c563SMathieu Poirier static int cs_etm_find_snapshot(struct auxtrace_record *itr __maybe_unused, 543a818c563SMathieu Poirier int idx, struct auxtrace_mmap *mm, 544a818c563SMathieu Poirier unsigned char *data __maybe_unused, 545a818c563SMathieu Poirier u64 *head, u64 *old) 546a818c563SMathieu Poirier { 547a818c563SMathieu Poirier pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n", 548a818c563SMathieu Poirier __func__, idx, (size_t)*old, (size_t)*head, mm->len); 549a818c563SMathieu Poirier 550a818c563SMathieu Poirier *old = *head; 551a818c563SMathieu Poirier *head += mm->len; 552a818c563SMathieu Poirier 553a818c563SMathieu Poirier return 0; 554a818c563SMathieu Poirier } 555a818c563SMathieu Poirier 556a818c563SMathieu Poirier static int cs_etm_snapshot_start(struct auxtrace_record *itr) 557a818c563SMathieu Poirier { 558a818c563SMathieu Poirier struct cs_etm_recording *ptr = 559a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 560a818c563SMathieu Poirier struct perf_evsel *evsel; 561a818c563SMathieu Poirier 562a818c563SMathieu Poirier evlist__for_each_entry(ptr->evlist, evsel) { 563a818c563SMathieu Poirier if (evsel->attr.type == ptr->cs_etm_pmu->type) 564a818c563SMathieu Poirier return perf_evsel__disable(evsel); 565a818c563SMathieu Poirier } 566a818c563SMathieu Poirier return -EINVAL; 567a818c563SMathieu Poirier } 568a818c563SMathieu Poirier 569a818c563SMathieu Poirier static int cs_etm_snapshot_finish(struct auxtrace_record *itr) 570a818c563SMathieu Poirier { 571a818c563SMathieu Poirier struct cs_etm_recording *ptr = 572a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 573a818c563SMathieu Poirier struct perf_evsel *evsel; 574a818c563SMathieu Poirier 575a818c563SMathieu Poirier evlist__for_each_entry(ptr->evlist, evsel) { 576a818c563SMathieu Poirier if (evsel->attr.type == ptr->cs_etm_pmu->type) 577a818c563SMathieu Poirier return perf_evsel__enable(evsel); 578a818c563SMathieu Poirier } 579a818c563SMathieu Poirier return -EINVAL; 580a818c563SMathieu Poirier } 581a818c563SMathieu Poirier 582a818c563SMathieu Poirier static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused) 583a818c563SMathieu Poirier { 584a818c563SMathieu Poirier return (((u64) rand() << 0) & 0x00000000FFFFFFFFull) | 585a818c563SMathieu Poirier (((u64) rand() << 32) & 0xFFFFFFFF00000000ull); 586a818c563SMathieu Poirier } 587a818c563SMathieu Poirier 588a818c563SMathieu Poirier static void cs_etm_recording_free(struct auxtrace_record *itr) 589a818c563SMathieu Poirier { 590a818c563SMathieu Poirier struct cs_etm_recording *ptr = 591a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 592a818c563SMathieu Poirier free(ptr); 593a818c563SMathieu Poirier } 594a818c563SMathieu Poirier 595a818c563SMathieu Poirier static int cs_etm_read_finish(struct auxtrace_record *itr, int idx) 596a818c563SMathieu Poirier { 597a818c563SMathieu Poirier struct cs_etm_recording *ptr = 598a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 599a818c563SMathieu Poirier struct perf_evsel *evsel; 600a818c563SMathieu Poirier 601a818c563SMathieu Poirier evlist__for_each_entry(ptr->evlist, evsel) { 602a818c563SMathieu Poirier if (evsel->attr.type == ptr->cs_etm_pmu->type) 603a818c563SMathieu Poirier return perf_evlist__enable_event_idx(ptr->evlist, 604a818c563SMathieu Poirier evsel, idx); 605a818c563SMathieu Poirier } 606a818c563SMathieu Poirier 607a818c563SMathieu Poirier return -EINVAL; 608a818c563SMathieu Poirier } 609a818c563SMathieu Poirier 610a818c563SMathieu Poirier struct auxtrace_record *cs_etm_record_init(int *err) 611a818c563SMathieu Poirier { 612a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu; 613a818c563SMathieu Poirier struct cs_etm_recording *ptr; 614a818c563SMathieu Poirier 615a818c563SMathieu Poirier cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME); 616a818c563SMathieu Poirier 617a818c563SMathieu Poirier if (!cs_etm_pmu) { 618a818c563SMathieu Poirier *err = -EINVAL; 619a818c563SMathieu Poirier goto out; 620a818c563SMathieu Poirier } 621a818c563SMathieu Poirier 622a818c563SMathieu Poirier ptr = zalloc(sizeof(struct cs_etm_recording)); 623a818c563SMathieu Poirier if (!ptr) { 624a818c563SMathieu Poirier *err = -ENOMEM; 625a818c563SMathieu Poirier goto out; 626a818c563SMathieu Poirier } 627a818c563SMathieu Poirier 628a818c563SMathieu Poirier ptr->cs_etm_pmu = cs_etm_pmu; 629a818c563SMathieu Poirier ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options; 630a818c563SMathieu Poirier ptr->itr.recording_options = cs_etm_recording_options; 631a818c563SMathieu Poirier ptr->itr.info_priv_size = cs_etm_info_priv_size; 632a818c563SMathieu Poirier ptr->itr.info_fill = cs_etm_info_fill; 633a818c563SMathieu Poirier ptr->itr.find_snapshot = cs_etm_find_snapshot; 634a818c563SMathieu Poirier ptr->itr.snapshot_start = cs_etm_snapshot_start; 635a818c563SMathieu Poirier ptr->itr.snapshot_finish = cs_etm_snapshot_finish; 636a818c563SMathieu Poirier ptr->itr.reference = cs_etm_reference; 637a818c563SMathieu Poirier ptr->itr.free = cs_etm_recording_free; 638a818c563SMathieu Poirier ptr->itr.read_finish = cs_etm_read_finish; 639a818c563SMathieu Poirier 640a818c563SMathieu Poirier *err = 0; 641a818c563SMathieu Poirier return &ptr->itr; 642a818c563SMathieu Poirier out: 643a818c563SMathieu Poirier return NULL; 644a818c563SMathieu Poirier } 6453becf452SMathieu Poirier 6463becf452SMathieu Poirier static FILE *cs_device__open_file(const char *name) 6473becf452SMathieu Poirier { 6483becf452SMathieu Poirier struct stat st; 6493becf452SMathieu Poirier char path[PATH_MAX]; 6503becf452SMathieu Poirier const char *sysfs; 6513becf452SMathieu Poirier 6523becf452SMathieu Poirier sysfs = sysfs__mountpoint(); 6533becf452SMathieu Poirier if (!sysfs) 6543becf452SMathieu Poirier return NULL; 6553becf452SMathieu Poirier 6563becf452SMathieu Poirier snprintf(path, PATH_MAX, 6573becf452SMathieu Poirier "%s" CS_BUS_DEVICE_PATH "%s", sysfs, name); 6583becf452SMathieu Poirier 6593becf452SMathieu Poirier if (stat(path, &st) < 0) 6603becf452SMathieu Poirier return NULL; 6613becf452SMathieu Poirier 6623becf452SMathieu Poirier return fopen(path, "w"); 6633becf452SMathieu Poirier 6643becf452SMathieu Poirier } 6653becf452SMathieu Poirier 666afaed6d3SArnaldo Carvalho de Melo static int __printf(2, 3) cs_device__print_file(const char *name, const char *fmt, ...) 6673becf452SMathieu Poirier { 6683becf452SMathieu Poirier va_list args; 6693becf452SMathieu Poirier FILE *file; 6703becf452SMathieu Poirier int ret = -EINVAL; 6713becf452SMathieu Poirier 6723becf452SMathieu Poirier va_start(args, fmt); 6733becf452SMathieu Poirier file = cs_device__open_file(name); 6743becf452SMathieu Poirier if (file) { 6753becf452SMathieu Poirier ret = vfprintf(file, fmt, args); 6763becf452SMathieu Poirier fclose(file); 6773becf452SMathieu Poirier } 6783becf452SMathieu Poirier va_end(args); 6793becf452SMathieu Poirier return ret; 6803becf452SMathieu Poirier } 6813becf452SMathieu Poirier 6823becf452SMathieu Poirier int cs_etm_set_drv_config(struct perf_evsel_config_term *term) 6833becf452SMathieu Poirier { 6843becf452SMathieu Poirier int ret; 6853becf452SMathieu Poirier char enable_sink[ENABLE_SINK_MAX]; 6863becf452SMathieu Poirier 6873becf452SMathieu Poirier snprintf(enable_sink, ENABLE_SINK_MAX, "%s/%s", 6883becf452SMathieu Poirier term->val.drv_cfg, "enable_sink"); 6893becf452SMathieu Poirier 6903becf452SMathieu Poirier ret = cs_device__print_file(enable_sink, "%d", 1); 6913becf452SMathieu Poirier if (ret < 0) 6923becf452SMathieu Poirier return ret; 6933becf452SMathieu Poirier 6943becf452SMathieu Poirier return 0; 6953becf452SMathieu Poirier } 696