1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Arm Statistical Profiling Extensions (SPE) support 4 * Copyright (c) 2017-2018, Arm Ltd. 5 */ 6 7 #include <linux/kernel.h> 8 #include <linux/types.h> 9 #include <linux/bitops.h> 10 #include <linux/log2.h> 11 #include <linux/zalloc.h> 12 #include <time.h> 13 14 #include "../../../util/cpumap.h" 15 #include "../../../util/event.h" 16 #include "../../../util/evsel.h" 17 #include "../../../util/evsel_config.h" 18 #include "../../../util/evlist.h" 19 #include "../../../util/session.h" 20 #include <internal/lib.h> // page_size 21 #include "../../../util/pmu.h" 22 #include "../../../util/debug.h" 23 #include "../../../util/auxtrace.h" 24 #include "../../../util/record.h" 25 #include "../../../util/arm-spe.h" 26 27 #define KiB(x) ((x) * 1024) 28 #define MiB(x) ((x) * 1024 * 1024) 29 30 struct arm_spe_recording { 31 struct auxtrace_record itr; 32 struct perf_pmu *arm_spe_pmu; 33 struct evlist *evlist; 34 }; 35 36 static void arm_spe_set_timestamp(struct auxtrace_record *itr, 37 struct evsel *evsel) 38 { 39 struct arm_spe_recording *ptr; 40 struct perf_pmu *arm_spe_pmu; 41 struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG); 42 u64 user_bits = 0, bit; 43 44 ptr = container_of(itr, struct arm_spe_recording, itr); 45 arm_spe_pmu = ptr->arm_spe_pmu; 46 47 if (term) 48 user_bits = term->val.cfg_chg; 49 50 bit = perf_pmu__format_bits(&arm_spe_pmu->format, "ts_enable"); 51 52 /* Skip if user has set it */ 53 if (bit & user_bits) 54 return; 55 56 evsel->core.attr.config |= bit; 57 } 58 59 static size_t 60 arm_spe_info_priv_size(struct auxtrace_record *itr __maybe_unused, 61 struct evlist *evlist __maybe_unused) 62 { 63 return ARM_SPE_AUXTRACE_PRIV_SIZE; 64 } 65 66 static int arm_spe_info_fill(struct auxtrace_record *itr, 67 struct perf_session *session, 68 struct perf_record_auxtrace_info *auxtrace_info, 69 size_t priv_size) 70 { 71 struct arm_spe_recording *sper = 72 container_of(itr, struct arm_spe_recording, itr); 73 struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu; 74 75 if (priv_size != ARM_SPE_AUXTRACE_PRIV_SIZE) 76 return -EINVAL; 77 78 if (!session->evlist->core.nr_mmaps) 79 return -EINVAL; 80 81 auxtrace_info->type = PERF_AUXTRACE_ARM_SPE; 82 auxtrace_info->priv[ARM_SPE_PMU_TYPE] = arm_spe_pmu->type; 83 84 return 0; 85 } 86 87 static int arm_spe_recording_options(struct auxtrace_record *itr, 88 struct evlist *evlist, 89 struct record_opts *opts) 90 { 91 struct arm_spe_recording *sper = 92 container_of(itr, struct arm_spe_recording, itr); 93 struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu; 94 struct evsel *evsel, *arm_spe_evsel = NULL; 95 struct perf_cpu_map *cpus = evlist->core.cpus; 96 bool privileged = perf_event_paranoid_check(-1); 97 struct evsel *tracking_evsel; 98 int err; 99 100 sper->evlist = evlist; 101 102 evlist__for_each_entry(evlist, evsel) { 103 if (evsel->core.attr.type == arm_spe_pmu->type) { 104 if (arm_spe_evsel) { 105 pr_err("There may be only one " ARM_SPE_PMU_NAME "x event\n"); 106 return -EINVAL; 107 } 108 evsel->core.attr.freq = 0; 109 evsel->core.attr.sample_period = 1; 110 arm_spe_evsel = evsel; 111 opts->full_auxtrace = true; 112 } 113 } 114 115 if (!opts->full_auxtrace) 116 return 0; 117 118 /* We are in full trace mode but '-m,xyz' wasn't specified */ 119 if (!opts->auxtrace_mmap_pages) { 120 if (privileged) { 121 opts->auxtrace_mmap_pages = MiB(4) / page_size; 122 } else { 123 opts->auxtrace_mmap_pages = KiB(128) / page_size; 124 if (opts->mmap_pages == UINT_MAX) 125 opts->mmap_pages = KiB(256) / page_size; 126 } 127 } 128 129 /* Validate auxtrace_mmap_pages */ 130 if (opts->auxtrace_mmap_pages) { 131 size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size; 132 size_t min_sz = KiB(8); 133 134 if (sz < min_sz || !is_power_of_2(sz)) { 135 pr_err("Invalid mmap size for ARM SPE: must be at least %zuKiB and a power of 2\n", 136 min_sz / 1024); 137 return -EINVAL; 138 } 139 } 140 141 142 /* 143 * To obtain the auxtrace buffer file descriptor, the auxtrace event 144 * must come first. 145 */ 146 evlist__to_front(evlist, arm_spe_evsel); 147 148 /* 149 * In the case of per-cpu mmaps, sample CPU for AUX event; 150 * also enable the timestamp tracing for samples correlation. 151 */ 152 if (!perf_cpu_map__empty(cpus)) { 153 evsel__set_sample_bit(arm_spe_evsel, CPU); 154 arm_spe_set_timestamp(itr, arm_spe_evsel); 155 } 156 157 /* Add dummy event to keep tracking */ 158 err = parse_events(evlist, "dummy:u", NULL); 159 if (err) 160 return err; 161 162 tracking_evsel = evlist__last(evlist); 163 evlist__set_tracking_event(evlist, tracking_evsel); 164 165 tracking_evsel->core.attr.freq = 0; 166 tracking_evsel->core.attr.sample_period = 1; 167 168 /* In per-cpu case, always need the time of mmap events etc */ 169 if (!perf_cpu_map__empty(cpus)) 170 evsel__set_sample_bit(tracking_evsel, TIME); 171 172 return 0; 173 } 174 175 static u64 arm_spe_reference(struct auxtrace_record *itr __maybe_unused) 176 { 177 struct timespec ts; 178 179 clock_gettime(CLOCK_MONOTONIC_RAW, &ts); 180 181 return ts.tv_sec ^ ts.tv_nsec; 182 } 183 184 static void arm_spe_recording_free(struct auxtrace_record *itr) 185 { 186 struct arm_spe_recording *sper = 187 container_of(itr, struct arm_spe_recording, itr); 188 189 free(sper); 190 } 191 192 struct auxtrace_record *arm_spe_recording_init(int *err, 193 struct perf_pmu *arm_spe_pmu) 194 { 195 struct arm_spe_recording *sper; 196 197 if (!arm_spe_pmu) { 198 *err = -ENODEV; 199 return NULL; 200 } 201 202 sper = zalloc(sizeof(struct arm_spe_recording)); 203 if (!sper) { 204 *err = -ENOMEM; 205 return NULL; 206 } 207 208 sper->arm_spe_pmu = arm_spe_pmu; 209 sper->itr.pmu = arm_spe_pmu; 210 sper->itr.recording_options = arm_spe_recording_options; 211 sper->itr.info_priv_size = arm_spe_info_priv_size; 212 sper->itr.info_fill = arm_spe_info_fill; 213 sper->itr.free = arm_spe_recording_free; 214 sper->itr.reference = arm_spe_reference; 215 sper->itr.read_finish = auxtrace_record__read_finish; 216 sper->itr.alignment = 0; 217 218 *err = 0; 219 return &sper->itr; 220 } 221 222 struct perf_event_attr 223 *arm_spe_pmu_default_config(struct perf_pmu *arm_spe_pmu) 224 { 225 struct perf_event_attr *attr; 226 227 attr = zalloc(sizeof(struct perf_event_attr)); 228 if (!attr) { 229 pr_err("arm_spe default config cannot allocate a perf_event_attr\n"); 230 return NULL; 231 } 232 233 /* 234 * If kernel driver doesn't advertise a minimum, 235 * use max allowable by PMSIDR_EL1.INTERVAL 236 */ 237 if (perf_pmu__scan_file(arm_spe_pmu, "caps/min_interval", "%llu", 238 &attr->sample_period) != 1) { 239 pr_debug("arm_spe driver doesn't advertise a min. interval. Using 4096\n"); 240 attr->sample_period = 4096; 241 } 242 243 arm_spe_pmu->selectable = true; 244 arm_spe_pmu->is_uncore = false; 245 246 return attr; 247 } 248