1*8a9fd832SMathieu 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> 8a818c563SMathieu Poirier #include <linux/bitops.h> 9afaed6d3SArnaldo Carvalho de Melo #include <linux/compiler.h> 10a818c563SMathieu Poirier #include <linux/coresight-pmu.h> 11a818c563SMathieu Poirier #include <linux/kernel.h> 12a818c563SMathieu Poirier #include <linux/log2.h> 13a818c563SMathieu Poirier #include <linux/types.h> 14a818c563SMathieu Poirier 15a818c563SMathieu Poirier #include "cs-etm.h" 16a818c563SMathieu Poirier #include "../../perf.h" 17a818c563SMathieu Poirier #include "../../util/auxtrace.h" 18a818c563SMathieu Poirier #include "../../util/cpumap.h" 19a818c563SMathieu Poirier #include "../../util/evlist.h" 203becf452SMathieu Poirier #include "../../util/evsel.h" 21a818c563SMathieu Poirier #include "../../util/pmu.h" 22a818c563SMathieu Poirier #include "../../util/thread_map.h" 23a818c563SMathieu Poirier #include "../../util/cs-etm.h" 24a818c563SMathieu Poirier 25a818c563SMathieu Poirier #include <stdlib.h> 267a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h> 27a818c563SMathieu Poirier 283becf452SMathieu Poirier #define ENABLE_SINK_MAX 128 293becf452SMathieu Poirier #define CS_BUS_DEVICE_PATH "/bus/coresight/devices/" 303becf452SMathieu Poirier 31a818c563SMathieu Poirier struct cs_etm_recording { 32a818c563SMathieu Poirier struct auxtrace_record itr; 33a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu; 34a818c563SMathieu Poirier struct perf_evlist *evlist; 35a818c563SMathieu Poirier bool snapshot_mode; 36a818c563SMathieu Poirier size_t snapshot_size; 37a818c563SMathieu Poirier }; 38a818c563SMathieu Poirier 39a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu); 40a818c563SMathieu Poirier 41a818c563SMathieu Poirier static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr, 42a818c563SMathieu Poirier struct record_opts *opts, 43a818c563SMathieu Poirier const char *str) 44a818c563SMathieu Poirier { 45a818c563SMathieu Poirier struct cs_etm_recording *ptr = 46a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 47a818c563SMathieu Poirier unsigned long long snapshot_size = 0; 48a818c563SMathieu Poirier char *endptr; 49a818c563SMathieu Poirier 50a818c563SMathieu Poirier if (str) { 51a818c563SMathieu Poirier snapshot_size = strtoull(str, &endptr, 0); 52a818c563SMathieu Poirier if (*endptr || snapshot_size > SIZE_MAX) 53a818c563SMathieu Poirier return -1; 54a818c563SMathieu Poirier } 55a818c563SMathieu Poirier 56a818c563SMathieu Poirier opts->auxtrace_snapshot_mode = true; 57a818c563SMathieu Poirier opts->auxtrace_snapshot_size = snapshot_size; 58a818c563SMathieu Poirier ptr->snapshot_size = snapshot_size; 59a818c563SMathieu Poirier 60a818c563SMathieu Poirier return 0; 61a818c563SMathieu Poirier } 62a818c563SMathieu Poirier 63a818c563SMathieu Poirier static int cs_etm_recording_options(struct auxtrace_record *itr, 64a818c563SMathieu Poirier struct perf_evlist *evlist, 65a818c563SMathieu Poirier struct record_opts *opts) 66a818c563SMathieu Poirier { 67a818c563SMathieu Poirier struct cs_etm_recording *ptr = 68a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 69a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 70a818c563SMathieu Poirier struct perf_evsel *evsel, *cs_etm_evsel = NULL; 71a818c563SMathieu Poirier const struct cpu_map *cpus = evlist->cpus; 72a818c563SMathieu Poirier bool privileged = (geteuid() == 0 || perf_event_paranoid() < 0); 73a818c563SMathieu Poirier 74a818c563SMathieu Poirier ptr->evlist = evlist; 75a818c563SMathieu Poirier ptr->snapshot_mode = opts->auxtrace_snapshot_mode; 76a818c563SMathieu Poirier 77a818c563SMathieu Poirier evlist__for_each_entry(evlist, evsel) { 78a818c563SMathieu Poirier if (evsel->attr.type == cs_etm_pmu->type) { 79a818c563SMathieu Poirier if (cs_etm_evsel) { 80a818c563SMathieu Poirier pr_err("There may be only one %s event\n", 81a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 82a818c563SMathieu Poirier return -EINVAL; 83a818c563SMathieu Poirier } 84a818c563SMathieu Poirier evsel->attr.freq = 0; 85a818c563SMathieu Poirier evsel->attr.sample_period = 1; 86a818c563SMathieu Poirier cs_etm_evsel = evsel; 87a818c563SMathieu Poirier opts->full_auxtrace = true; 88a818c563SMathieu Poirier } 89a818c563SMathieu Poirier } 90a818c563SMathieu Poirier 91a818c563SMathieu Poirier /* no need to continue if at least one event of interest was found */ 92a818c563SMathieu Poirier if (!cs_etm_evsel) 93a818c563SMathieu Poirier return 0; 94a818c563SMathieu Poirier 95a818c563SMathieu Poirier if (opts->use_clockid) { 96a818c563SMathieu Poirier pr_err("Cannot use clockid (-k option) with %s\n", 97a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 98a818c563SMathieu Poirier return -EINVAL; 99a818c563SMathieu Poirier } 100a818c563SMathieu Poirier 101a818c563SMathieu Poirier /* we are in snapshot mode */ 102a818c563SMathieu Poirier if (opts->auxtrace_snapshot_mode) { 103a818c563SMathieu Poirier /* 104a818c563SMathieu Poirier * No size were given to '-S' or '-m,', so go with 105a818c563SMathieu Poirier * the default 106a818c563SMathieu Poirier */ 107a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size && 108a818c563SMathieu Poirier !opts->auxtrace_mmap_pages) { 109a818c563SMathieu Poirier if (privileged) { 110a818c563SMathieu Poirier opts->auxtrace_mmap_pages = MiB(4) / page_size; 111a818c563SMathieu Poirier } else { 112a818c563SMathieu Poirier opts->auxtrace_mmap_pages = 113a818c563SMathieu Poirier KiB(128) / page_size; 114a818c563SMathieu Poirier if (opts->mmap_pages == UINT_MAX) 115a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 116a818c563SMathieu Poirier } 117a818c563SMathieu Poirier } else if (!opts->auxtrace_mmap_pages && !privileged && 118a818c563SMathieu Poirier opts->mmap_pages == UINT_MAX) { 119a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 120a818c563SMathieu Poirier } 121a818c563SMathieu Poirier 122a818c563SMathieu Poirier /* 123a818c563SMathieu Poirier * '-m,xyz' was specified but no snapshot size, so make the 124a818c563SMathieu Poirier * snapshot size as big as the auxtrace mmap area. 125a818c563SMathieu Poirier */ 126a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size) { 127a818c563SMathieu Poirier opts->auxtrace_snapshot_size = 128a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size; 129a818c563SMathieu Poirier } 130a818c563SMathieu Poirier 131a818c563SMathieu Poirier /* 132a818c563SMathieu Poirier * -Sxyz was specified but no auxtrace mmap area, so make the 133a818c563SMathieu Poirier * auxtrace mmap area big enough to fit the requested snapshot 134a818c563SMathieu Poirier * size. 135a818c563SMathieu Poirier */ 136a818c563SMathieu Poirier if (!opts->auxtrace_mmap_pages) { 137a818c563SMathieu Poirier size_t sz = opts->auxtrace_snapshot_size; 138a818c563SMathieu Poirier 139a818c563SMathieu Poirier sz = round_up(sz, page_size) / page_size; 140a818c563SMathieu Poirier opts->auxtrace_mmap_pages = roundup_pow_of_two(sz); 141a818c563SMathieu Poirier } 142a818c563SMathieu Poirier 143a818c563SMathieu Poirier /* Snapshost size can't be bigger than the auxtrace area */ 144a818c563SMathieu Poirier if (opts->auxtrace_snapshot_size > 145a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size) { 146a818c563SMathieu Poirier pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n", 147a818c563SMathieu Poirier opts->auxtrace_snapshot_size, 148a818c563SMathieu Poirier opts->auxtrace_mmap_pages * (size_t)page_size); 149a818c563SMathieu Poirier return -EINVAL; 150a818c563SMathieu Poirier } 151a818c563SMathieu Poirier 152a818c563SMathieu Poirier /* Something went wrong somewhere - this shouldn't happen */ 153a818c563SMathieu Poirier if (!opts->auxtrace_snapshot_size || 154a818c563SMathieu Poirier !opts->auxtrace_mmap_pages) { 155a818c563SMathieu Poirier pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n"); 156a818c563SMathieu Poirier return -EINVAL; 157a818c563SMathieu Poirier } 158a818c563SMathieu Poirier } 159a818c563SMathieu Poirier 160a818c563SMathieu Poirier /* We are in full trace mode but '-m,xyz' wasn't specified */ 161a818c563SMathieu Poirier if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) { 162a818c563SMathieu Poirier if (privileged) { 163a818c563SMathieu Poirier opts->auxtrace_mmap_pages = MiB(4) / page_size; 164a818c563SMathieu Poirier } else { 165a818c563SMathieu Poirier opts->auxtrace_mmap_pages = KiB(128) / page_size; 166a818c563SMathieu Poirier if (opts->mmap_pages == UINT_MAX) 167a818c563SMathieu Poirier opts->mmap_pages = KiB(256) / page_size; 168a818c563SMathieu Poirier } 169a818c563SMathieu Poirier 170a818c563SMathieu Poirier } 171a818c563SMathieu Poirier 172a818c563SMathieu Poirier /* Validate auxtrace_mmap_pages provided by user */ 173a818c563SMathieu Poirier if (opts->auxtrace_mmap_pages) { 174a818c563SMathieu Poirier unsigned int max_page = (KiB(128) / page_size); 175a818c563SMathieu Poirier size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size; 176a818c563SMathieu Poirier 177a818c563SMathieu Poirier if (!privileged && 178a818c563SMathieu Poirier opts->auxtrace_mmap_pages > max_page) { 179a818c563SMathieu Poirier opts->auxtrace_mmap_pages = max_page; 180a818c563SMathieu Poirier pr_err("auxtrace too big, truncating to %d\n", 181a818c563SMathieu Poirier max_page); 182a818c563SMathieu Poirier } 183a818c563SMathieu Poirier 184a818c563SMathieu Poirier if (!is_power_of_2(sz)) { 185a818c563SMathieu Poirier pr_err("Invalid mmap size for %s: must be a power of 2\n", 186a818c563SMathieu Poirier CORESIGHT_ETM_PMU_NAME); 187a818c563SMathieu Poirier return -EINVAL; 188a818c563SMathieu Poirier } 189a818c563SMathieu Poirier } 190a818c563SMathieu Poirier 191a818c563SMathieu Poirier if (opts->auxtrace_snapshot_mode) 192a818c563SMathieu Poirier pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME, 193a818c563SMathieu Poirier opts->auxtrace_snapshot_size); 194a818c563SMathieu Poirier 195a818c563SMathieu Poirier /* 196a818c563SMathieu Poirier * To obtain the auxtrace buffer file descriptor, the auxtrace 197a818c563SMathieu Poirier * event must come first. 198a818c563SMathieu Poirier */ 199a818c563SMathieu Poirier perf_evlist__to_front(evlist, cs_etm_evsel); 2000c788d47SKim Phillips 201a818c563SMathieu Poirier /* 202a818c563SMathieu Poirier * In the case of per-cpu mmaps, we need the CPU on the 203a818c563SMathieu Poirier * AUX event. 204a818c563SMathieu Poirier */ 205a818c563SMathieu Poirier if (!cpu_map__empty(cpus)) 206a818c563SMathieu Poirier perf_evsel__set_sample_bit(cs_etm_evsel, CPU); 207a818c563SMathieu Poirier 208a818c563SMathieu Poirier /* Add dummy event to keep tracking */ 209a818c563SMathieu Poirier if (opts->full_auxtrace) { 210a818c563SMathieu Poirier struct perf_evsel *tracking_evsel; 211a818c563SMathieu Poirier int err; 212a818c563SMathieu Poirier 213a818c563SMathieu Poirier err = parse_events(evlist, "dummy:u", NULL); 214a818c563SMathieu Poirier if (err) 215a818c563SMathieu Poirier return err; 216a818c563SMathieu Poirier 217a818c563SMathieu Poirier tracking_evsel = perf_evlist__last(evlist); 218a818c563SMathieu Poirier perf_evlist__set_tracking_event(evlist, tracking_evsel); 219a818c563SMathieu Poirier 220a818c563SMathieu Poirier tracking_evsel->attr.freq = 0; 221a818c563SMathieu Poirier tracking_evsel->attr.sample_period = 1; 222a818c563SMathieu Poirier 223a818c563SMathieu Poirier /* In per-cpu case, always need the time of mmap events etc */ 224a818c563SMathieu Poirier if (!cpu_map__empty(cpus)) 225a818c563SMathieu Poirier perf_evsel__set_sample_bit(tracking_evsel, TIME); 226a818c563SMathieu Poirier } 227a818c563SMathieu Poirier 228a818c563SMathieu Poirier return 0; 229a818c563SMathieu Poirier } 230a818c563SMathieu Poirier 231a818c563SMathieu Poirier static u64 cs_etm_get_config(struct auxtrace_record *itr) 232a818c563SMathieu Poirier { 233a818c563SMathieu Poirier u64 config = 0; 234a818c563SMathieu Poirier struct cs_etm_recording *ptr = 235a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 236a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 237a818c563SMathieu Poirier struct perf_evlist *evlist = ptr->evlist; 238a818c563SMathieu Poirier struct perf_evsel *evsel; 239a818c563SMathieu Poirier 240a818c563SMathieu Poirier evlist__for_each_entry(evlist, evsel) { 241a818c563SMathieu Poirier if (evsel->attr.type == cs_etm_pmu->type) { 242a818c563SMathieu Poirier /* 243a818c563SMathieu Poirier * Variable perf_event_attr::config is assigned to 244a818c563SMathieu Poirier * ETMv3/PTM. The bit fields have been made to match 245a818c563SMathieu Poirier * the ETMv3.5 ETRMCR register specification. See the 246a818c563SMathieu Poirier * PMU_FORMAT_ATTR() declarations in 247a818c563SMathieu Poirier * drivers/hwtracing/coresight/coresight-perf.c for 248a818c563SMathieu Poirier * details. 249a818c563SMathieu Poirier */ 250a818c563SMathieu Poirier config = evsel->attr.config; 251a818c563SMathieu Poirier break; 252a818c563SMathieu Poirier } 253a818c563SMathieu Poirier } 254a818c563SMathieu Poirier 255a818c563SMathieu Poirier return config; 256a818c563SMathieu Poirier } 257a818c563SMathieu Poirier 258df770ff0SMike Leach #ifndef BIT 259df770ff0SMike Leach #define BIT(N) (1UL << (N)) 260df770ff0SMike Leach #endif 261df770ff0SMike Leach 262df770ff0SMike Leach static u64 cs_etmv4_get_config(struct auxtrace_record *itr) 263df770ff0SMike Leach { 264df770ff0SMike Leach u64 config = 0; 265df770ff0SMike Leach u64 config_opts = 0; 266df770ff0SMike Leach 267df770ff0SMike Leach /* 268df770ff0SMike Leach * The perf event variable config bits represent both 269df770ff0SMike Leach * the command line options and register programming 270df770ff0SMike Leach * bits in ETMv3/PTM. For ETMv4 we must remap options 271df770ff0SMike Leach * to real bits 272df770ff0SMike Leach */ 273df770ff0SMike Leach config_opts = cs_etm_get_config(itr); 274df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_CYCACC)) 275df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_CYCACC); 276df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_TS)) 277df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_TS); 278df770ff0SMike Leach if (config_opts & BIT(ETM_OPT_RETSTK)) 279df770ff0SMike Leach config |= BIT(ETM4_CFG_BIT_RETSTK); 280df770ff0SMike Leach 281df770ff0SMike Leach return config; 282df770ff0SMike Leach } 283df770ff0SMike Leach 284a818c563SMathieu Poirier static size_t 285a818c563SMathieu Poirier cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, 286a818c563SMathieu Poirier struct perf_evlist *evlist __maybe_unused) 287a818c563SMathieu Poirier { 288a818c563SMathieu Poirier int i; 289a818c563SMathieu Poirier int etmv3 = 0, etmv4 = 0; 290796bfaddSMathieu Poirier struct cpu_map *event_cpus = evlist->cpus; 291796bfaddSMathieu Poirier struct cpu_map *online_cpus = cpu_map__new(NULL); 292a818c563SMathieu Poirier 293a818c563SMathieu Poirier /* cpu map is not empty, we have specific CPUs to work with */ 294796bfaddSMathieu Poirier if (!cpu_map__empty(event_cpus)) { 295796bfaddSMathieu Poirier for (i = 0; i < cpu__max_cpu(); i++) { 296796bfaddSMathieu Poirier if (!cpu_map__has(event_cpus, i) || 297796bfaddSMathieu Poirier !cpu_map__has(online_cpus, i)) 298796bfaddSMathieu Poirier continue; 299796bfaddSMathieu Poirier 300796bfaddSMathieu Poirier if (cs_etm_is_etmv4(itr, i)) 301a818c563SMathieu Poirier etmv4++; 302a818c563SMathieu Poirier else 303a818c563SMathieu Poirier etmv3++; 304a818c563SMathieu Poirier } 305a818c563SMathieu Poirier } else { 306a818c563SMathieu Poirier /* get configuration for all CPUs in the system */ 307a818c563SMathieu Poirier for (i = 0; i < cpu__max_cpu(); i++) { 308796bfaddSMathieu Poirier if (!cpu_map__has(online_cpus, i)) 309796bfaddSMathieu Poirier continue; 310796bfaddSMathieu Poirier 311a818c563SMathieu Poirier if (cs_etm_is_etmv4(itr, i)) 312a818c563SMathieu Poirier etmv4++; 313a818c563SMathieu Poirier else 314a818c563SMathieu Poirier etmv3++; 315a818c563SMathieu Poirier } 316a818c563SMathieu Poirier } 317a818c563SMathieu Poirier 318796bfaddSMathieu Poirier cpu_map__put(online_cpus); 319796bfaddSMathieu Poirier 320a818c563SMathieu Poirier return (CS_ETM_HEADER_SIZE + 321a818c563SMathieu Poirier (etmv4 * CS_ETMV4_PRIV_SIZE) + 322a818c563SMathieu Poirier (etmv3 * CS_ETMV3_PRIV_SIZE)); 323a818c563SMathieu Poirier } 324a818c563SMathieu Poirier 325a818c563SMathieu Poirier static const char *metadata_etmv3_ro[CS_ETM_PRIV_MAX] = { 326a818c563SMathieu Poirier [CS_ETM_ETMCCER] = "mgmt/etmccer", 327a818c563SMathieu Poirier [CS_ETM_ETMIDR] = "mgmt/etmidr", 328a818c563SMathieu Poirier }; 329a818c563SMathieu Poirier 330a818c563SMathieu Poirier static const char *metadata_etmv4_ro[CS_ETMV4_PRIV_MAX] = { 331a818c563SMathieu Poirier [CS_ETMV4_TRCIDR0] = "trcidr/trcidr0", 332a818c563SMathieu Poirier [CS_ETMV4_TRCIDR1] = "trcidr/trcidr1", 333a818c563SMathieu Poirier [CS_ETMV4_TRCIDR2] = "trcidr/trcidr2", 334a818c563SMathieu Poirier [CS_ETMV4_TRCIDR8] = "trcidr/trcidr8", 335a818c563SMathieu Poirier [CS_ETMV4_TRCAUTHSTATUS] = "mgmt/trcauthstatus", 336a818c563SMathieu Poirier }; 337a818c563SMathieu Poirier 338a818c563SMathieu Poirier static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu) 339a818c563SMathieu Poirier { 340a818c563SMathieu Poirier bool ret = false; 341a818c563SMathieu Poirier char path[PATH_MAX]; 342a818c563SMathieu Poirier int scan; 343a818c563SMathieu Poirier unsigned int val; 344a818c563SMathieu Poirier struct cs_etm_recording *ptr = 345a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 346a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 347a818c563SMathieu Poirier 348a818c563SMathieu Poirier /* Take any of the RO files for ETMv4 and see if it present */ 349a818c563SMathieu Poirier snprintf(path, PATH_MAX, "cpu%d/%s", 350a818c563SMathieu Poirier cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 351a818c563SMathieu Poirier scan = perf_pmu__scan_file(cs_etm_pmu, path, "%x", &val); 352a818c563SMathieu Poirier 353a818c563SMathieu Poirier /* The file was read successfully, we have a winner */ 354a818c563SMathieu Poirier if (scan == 1) 355a818c563SMathieu Poirier ret = true; 356a818c563SMathieu Poirier 357a818c563SMathieu Poirier return ret; 358a818c563SMathieu Poirier } 359a818c563SMathieu Poirier 360a818c563SMathieu Poirier static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu, const char *path) 361a818c563SMathieu Poirier { 362a818c563SMathieu Poirier char pmu_path[PATH_MAX]; 363a818c563SMathieu Poirier int scan; 364a818c563SMathieu Poirier unsigned int val = 0; 365a818c563SMathieu Poirier 366a818c563SMathieu Poirier /* Get RO metadata from sysfs */ 367a818c563SMathieu Poirier snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); 368a818c563SMathieu Poirier 369a818c563SMathieu Poirier scan = perf_pmu__scan_file(pmu, pmu_path, "%x", &val); 370a818c563SMathieu Poirier if (scan != 1) 371a818c563SMathieu Poirier pr_err("%s: error reading: %s\n", __func__, pmu_path); 372a818c563SMathieu Poirier 373a818c563SMathieu Poirier return val; 374a818c563SMathieu Poirier } 375a818c563SMathieu Poirier 376a818c563SMathieu Poirier static void cs_etm_get_metadata(int cpu, u32 *offset, 377a818c563SMathieu Poirier struct auxtrace_record *itr, 378a818c563SMathieu Poirier struct auxtrace_info_event *info) 379a818c563SMathieu Poirier { 380a818c563SMathieu Poirier u32 increment; 381a818c563SMathieu Poirier u64 magic; 382a818c563SMathieu Poirier struct cs_etm_recording *ptr = 383a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 384a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 385a818c563SMathieu Poirier 386a818c563SMathieu Poirier /* first see what kind of tracer this cpu is affined to */ 387a818c563SMathieu Poirier if (cs_etm_is_etmv4(itr, cpu)) { 388a818c563SMathieu Poirier magic = __perf_cs_etmv4_magic; 389a818c563SMathieu Poirier /* Get trace configuration register */ 390a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCCONFIGR] = 391df770ff0SMike Leach cs_etmv4_get_config(itr); 392a818c563SMathieu Poirier /* Get traceID from the framework */ 393a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCTRACEIDR] = 394a818c563SMathieu Poirier coresight_get_trace_id(cpu); 395a818c563SMathieu Poirier /* Get read-only information from sysFS */ 396a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCIDR0] = 397a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 398a818c563SMathieu Poirier metadata_etmv4_ro[CS_ETMV4_TRCIDR0]); 399a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCIDR1] = 400a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 401a818c563SMathieu Poirier metadata_etmv4_ro[CS_ETMV4_TRCIDR1]); 402a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCIDR2] = 403a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 404a818c563SMathieu Poirier metadata_etmv4_ro[CS_ETMV4_TRCIDR2]); 405a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCIDR8] = 406a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 407a818c563SMathieu Poirier metadata_etmv4_ro[CS_ETMV4_TRCIDR8]); 408a818c563SMathieu Poirier info->priv[*offset + CS_ETMV4_TRCAUTHSTATUS] = 409a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 410a818c563SMathieu Poirier metadata_etmv4_ro 411a818c563SMathieu Poirier [CS_ETMV4_TRCAUTHSTATUS]); 412a818c563SMathieu Poirier 413a818c563SMathieu Poirier /* How much space was used */ 414a818c563SMathieu Poirier increment = CS_ETMV4_PRIV_MAX; 415a818c563SMathieu Poirier } else { 416a818c563SMathieu Poirier magic = __perf_cs_etmv3_magic; 417a818c563SMathieu Poirier /* Get configuration register */ 418a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr); 419a818c563SMathieu Poirier /* Get traceID from the framework */ 420a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMTRACEIDR] = 421a818c563SMathieu Poirier coresight_get_trace_id(cpu); 422a818c563SMathieu Poirier /* Get read-only information from sysFS */ 423a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMCCER] = 424a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 425a818c563SMathieu Poirier metadata_etmv3_ro[CS_ETM_ETMCCER]); 426a818c563SMathieu Poirier info->priv[*offset + CS_ETM_ETMIDR] = 427a818c563SMathieu Poirier cs_etm_get_ro(cs_etm_pmu, cpu, 428a818c563SMathieu Poirier metadata_etmv3_ro[CS_ETM_ETMIDR]); 429a818c563SMathieu Poirier 430a818c563SMathieu Poirier /* How much space was used */ 431a818c563SMathieu Poirier increment = CS_ETM_PRIV_MAX; 432a818c563SMathieu Poirier } 433a818c563SMathieu Poirier 434a818c563SMathieu Poirier /* Build generic header portion */ 435a818c563SMathieu Poirier info->priv[*offset + CS_ETM_MAGIC] = magic; 436a818c563SMathieu Poirier info->priv[*offset + CS_ETM_CPU] = cpu; 437a818c563SMathieu Poirier /* Where the next CPU entry should start from */ 438a818c563SMathieu Poirier *offset += increment; 439a818c563SMathieu Poirier } 440a818c563SMathieu Poirier 441a818c563SMathieu Poirier static int cs_etm_info_fill(struct auxtrace_record *itr, 442a818c563SMathieu Poirier struct perf_session *session, 443a818c563SMathieu Poirier struct auxtrace_info_event *info, 444a818c563SMathieu Poirier size_t priv_size) 445a818c563SMathieu Poirier { 446a818c563SMathieu Poirier int i; 447a818c563SMathieu Poirier u32 offset; 448a818c563SMathieu Poirier u64 nr_cpu, type; 449796bfaddSMathieu Poirier struct cpu_map *cpu_map; 450796bfaddSMathieu Poirier struct cpu_map *event_cpus = session->evlist->cpus; 451796bfaddSMathieu Poirier struct cpu_map *online_cpus = cpu_map__new(NULL); 452a818c563SMathieu Poirier struct cs_etm_recording *ptr = 453a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 454a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; 455a818c563SMathieu Poirier 456a818c563SMathieu Poirier if (priv_size != cs_etm_info_priv_size(itr, session->evlist)) 457a818c563SMathieu Poirier return -EINVAL; 458a818c563SMathieu Poirier 459a818c563SMathieu Poirier if (!session->evlist->nr_mmaps) 460a818c563SMathieu Poirier return -EINVAL; 461a818c563SMathieu Poirier 462796bfaddSMathieu Poirier /* If the cpu_map is empty all online CPUs are involved */ 463796bfaddSMathieu Poirier if (cpu_map__empty(event_cpus)) { 464796bfaddSMathieu Poirier cpu_map = online_cpus; 465796bfaddSMathieu Poirier } else { 466796bfaddSMathieu Poirier /* Make sure all specified CPUs are online */ 467796bfaddSMathieu Poirier for (i = 0; i < cpu_map__nr(event_cpus); i++) { 468796bfaddSMathieu Poirier if (cpu_map__has(event_cpus, i) && 469796bfaddSMathieu Poirier !cpu_map__has(online_cpus, i)) 470796bfaddSMathieu Poirier return -EINVAL; 471796bfaddSMathieu Poirier } 472796bfaddSMathieu Poirier 473796bfaddSMathieu Poirier cpu_map = event_cpus; 474796bfaddSMathieu Poirier } 475796bfaddSMathieu Poirier 476796bfaddSMathieu Poirier nr_cpu = cpu_map__nr(cpu_map); 477a818c563SMathieu Poirier /* Get PMU type as dynamically assigned by the core */ 478a818c563SMathieu Poirier type = cs_etm_pmu->type; 479a818c563SMathieu Poirier 480a818c563SMathieu Poirier /* First fill out the session header */ 481a818c563SMathieu Poirier info->type = PERF_AUXTRACE_CS_ETM; 482a818c563SMathieu Poirier info->priv[CS_HEADER_VERSION_0] = 0; 483a818c563SMathieu Poirier info->priv[CS_PMU_TYPE_CPUS] = type << 32; 484a818c563SMathieu Poirier info->priv[CS_PMU_TYPE_CPUS] |= nr_cpu; 485a818c563SMathieu Poirier info->priv[CS_ETM_SNAPSHOT] = ptr->snapshot_mode; 486a818c563SMathieu Poirier 487a818c563SMathieu Poirier offset = CS_ETM_SNAPSHOT + 1; 488a818c563SMathieu Poirier 489796bfaddSMathieu Poirier for (i = 0; i < cpu__max_cpu() && offset < priv_size; i++) 490796bfaddSMathieu Poirier if (cpu_map__has(cpu_map, i)) 491a818c563SMathieu Poirier cs_etm_get_metadata(i, &offset, itr, info); 492796bfaddSMathieu Poirier 493796bfaddSMathieu Poirier cpu_map__put(online_cpus); 494a818c563SMathieu Poirier 495a818c563SMathieu Poirier return 0; 496a818c563SMathieu Poirier } 497a818c563SMathieu Poirier 498a818c563SMathieu Poirier static int cs_etm_find_snapshot(struct auxtrace_record *itr __maybe_unused, 499a818c563SMathieu Poirier int idx, struct auxtrace_mmap *mm, 500a818c563SMathieu Poirier unsigned char *data __maybe_unused, 501a818c563SMathieu Poirier u64 *head, u64 *old) 502a818c563SMathieu Poirier { 503a818c563SMathieu Poirier pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n", 504a818c563SMathieu Poirier __func__, idx, (size_t)*old, (size_t)*head, mm->len); 505a818c563SMathieu Poirier 506a818c563SMathieu Poirier *old = *head; 507a818c563SMathieu Poirier *head += mm->len; 508a818c563SMathieu Poirier 509a818c563SMathieu Poirier return 0; 510a818c563SMathieu Poirier } 511a818c563SMathieu Poirier 512a818c563SMathieu Poirier static int cs_etm_snapshot_start(struct auxtrace_record *itr) 513a818c563SMathieu Poirier { 514a818c563SMathieu Poirier struct cs_etm_recording *ptr = 515a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 516a818c563SMathieu Poirier struct perf_evsel *evsel; 517a818c563SMathieu Poirier 518a818c563SMathieu Poirier evlist__for_each_entry(ptr->evlist, evsel) { 519a818c563SMathieu Poirier if (evsel->attr.type == ptr->cs_etm_pmu->type) 520a818c563SMathieu Poirier return perf_evsel__disable(evsel); 521a818c563SMathieu Poirier } 522a818c563SMathieu Poirier return -EINVAL; 523a818c563SMathieu Poirier } 524a818c563SMathieu Poirier 525a818c563SMathieu Poirier static int cs_etm_snapshot_finish(struct auxtrace_record *itr) 526a818c563SMathieu Poirier { 527a818c563SMathieu Poirier struct cs_etm_recording *ptr = 528a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 529a818c563SMathieu Poirier struct perf_evsel *evsel; 530a818c563SMathieu Poirier 531a818c563SMathieu Poirier evlist__for_each_entry(ptr->evlist, evsel) { 532a818c563SMathieu Poirier if (evsel->attr.type == ptr->cs_etm_pmu->type) 533a818c563SMathieu Poirier return perf_evsel__enable(evsel); 534a818c563SMathieu Poirier } 535a818c563SMathieu Poirier return -EINVAL; 536a818c563SMathieu Poirier } 537a818c563SMathieu Poirier 538a818c563SMathieu Poirier static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused) 539a818c563SMathieu Poirier { 540a818c563SMathieu Poirier return (((u64) rand() << 0) & 0x00000000FFFFFFFFull) | 541a818c563SMathieu Poirier (((u64) rand() << 32) & 0xFFFFFFFF00000000ull); 542a818c563SMathieu Poirier } 543a818c563SMathieu Poirier 544a818c563SMathieu Poirier static void cs_etm_recording_free(struct auxtrace_record *itr) 545a818c563SMathieu Poirier { 546a818c563SMathieu Poirier struct cs_etm_recording *ptr = 547a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 548a818c563SMathieu Poirier free(ptr); 549a818c563SMathieu Poirier } 550a818c563SMathieu Poirier 551a818c563SMathieu Poirier static int cs_etm_read_finish(struct auxtrace_record *itr, int idx) 552a818c563SMathieu Poirier { 553a818c563SMathieu Poirier struct cs_etm_recording *ptr = 554a818c563SMathieu Poirier container_of(itr, struct cs_etm_recording, itr); 555a818c563SMathieu Poirier struct perf_evsel *evsel; 556a818c563SMathieu Poirier 557a818c563SMathieu Poirier evlist__for_each_entry(ptr->evlist, evsel) { 558a818c563SMathieu Poirier if (evsel->attr.type == ptr->cs_etm_pmu->type) 559a818c563SMathieu Poirier return perf_evlist__enable_event_idx(ptr->evlist, 560a818c563SMathieu Poirier evsel, idx); 561a818c563SMathieu Poirier } 562a818c563SMathieu Poirier 563a818c563SMathieu Poirier return -EINVAL; 564a818c563SMathieu Poirier } 565a818c563SMathieu Poirier 566a818c563SMathieu Poirier struct auxtrace_record *cs_etm_record_init(int *err) 567a818c563SMathieu Poirier { 568a818c563SMathieu Poirier struct perf_pmu *cs_etm_pmu; 569a818c563SMathieu Poirier struct cs_etm_recording *ptr; 570a818c563SMathieu Poirier 571a818c563SMathieu Poirier cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME); 572a818c563SMathieu Poirier 573a818c563SMathieu Poirier if (!cs_etm_pmu) { 574a818c563SMathieu Poirier *err = -EINVAL; 575a818c563SMathieu Poirier goto out; 576a818c563SMathieu Poirier } 577a818c563SMathieu Poirier 578a818c563SMathieu Poirier ptr = zalloc(sizeof(struct cs_etm_recording)); 579a818c563SMathieu Poirier if (!ptr) { 580a818c563SMathieu Poirier *err = -ENOMEM; 581a818c563SMathieu Poirier goto out; 582a818c563SMathieu Poirier } 583a818c563SMathieu Poirier 584a818c563SMathieu Poirier ptr->cs_etm_pmu = cs_etm_pmu; 585a818c563SMathieu Poirier ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options; 586a818c563SMathieu Poirier ptr->itr.recording_options = cs_etm_recording_options; 587a818c563SMathieu Poirier ptr->itr.info_priv_size = cs_etm_info_priv_size; 588a818c563SMathieu Poirier ptr->itr.info_fill = cs_etm_info_fill; 589a818c563SMathieu Poirier ptr->itr.find_snapshot = cs_etm_find_snapshot; 590a818c563SMathieu Poirier ptr->itr.snapshot_start = cs_etm_snapshot_start; 591a818c563SMathieu Poirier ptr->itr.snapshot_finish = cs_etm_snapshot_finish; 592a818c563SMathieu Poirier ptr->itr.reference = cs_etm_reference; 593a818c563SMathieu Poirier ptr->itr.free = cs_etm_recording_free; 594a818c563SMathieu Poirier ptr->itr.read_finish = cs_etm_read_finish; 595a818c563SMathieu Poirier 596a818c563SMathieu Poirier *err = 0; 597a818c563SMathieu Poirier return &ptr->itr; 598a818c563SMathieu Poirier out: 599a818c563SMathieu Poirier return NULL; 600a818c563SMathieu Poirier } 6013becf452SMathieu Poirier 6023becf452SMathieu Poirier static FILE *cs_device__open_file(const char *name) 6033becf452SMathieu Poirier { 6043becf452SMathieu Poirier struct stat st; 6053becf452SMathieu Poirier char path[PATH_MAX]; 6063becf452SMathieu Poirier const char *sysfs; 6073becf452SMathieu Poirier 6083becf452SMathieu Poirier sysfs = sysfs__mountpoint(); 6093becf452SMathieu Poirier if (!sysfs) 6103becf452SMathieu Poirier return NULL; 6113becf452SMathieu Poirier 6123becf452SMathieu Poirier snprintf(path, PATH_MAX, 6133becf452SMathieu Poirier "%s" CS_BUS_DEVICE_PATH "%s", sysfs, name); 6143becf452SMathieu Poirier 6153becf452SMathieu Poirier if (stat(path, &st) < 0) 6163becf452SMathieu Poirier return NULL; 6173becf452SMathieu Poirier 6183becf452SMathieu Poirier return fopen(path, "w"); 6193becf452SMathieu Poirier 6203becf452SMathieu Poirier } 6213becf452SMathieu Poirier 622afaed6d3SArnaldo Carvalho de Melo static int __printf(2, 3) cs_device__print_file(const char *name, const char *fmt, ...) 6233becf452SMathieu Poirier { 6243becf452SMathieu Poirier va_list args; 6253becf452SMathieu Poirier FILE *file; 6263becf452SMathieu Poirier int ret = -EINVAL; 6273becf452SMathieu Poirier 6283becf452SMathieu Poirier va_start(args, fmt); 6293becf452SMathieu Poirier file = cs_device__open_file(name); 6303becf452SMathieu Poirier if (file) { 6313becf452SMathieu Poirier ret = vfprintf(file, fmt, args); 6323becf452SMathieu Poirier fclose(file); 6333becf452SMathieu Poirier } 6343becf452SMathieu Poirier va_end(args); 6353becf452SMathieu Poirier return ret; 6363becf452SMathieu Poirier } 6373becf452SMathieu Poirier 6383becf452SMathieu Poirier int cs_etm_set_drv_config(struct perf_evsel_config_term *term) 6393becf452SMathieu Poirier { 6403becf452SMathieu Poirier int ret; 6413becf452SMathieu Poirier char enable_sink[ENABLE_SINK_MAX]; 6423becf452SMathieu Poirier 6433becf452SMathieu Poirier snprintf(enable_sink, ENABLE_SINK_MAX, "%s/%s", 6443becf452SMathieu Poirier term->val.drv_cfg, "enable_sink"); 6453becf452SMathieu Poirier 6463becf452SMathieu Poirier ret = cs_device__print_file(enable_sink, "%d", 1); 6473becf452SMathieu Poirier if (ret < 0) 6483becf452SMathieu Poirier return ret; 6493becf452SMathieu Poirier 6503becf452SMathieu Poirier return 0; 6513becf452SMathieu Poirier } 652