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/string.h> 12 #include <linux/zalloc.h> 13 #include <errno.h> 14 #include <time.h> 15 16 #include "../../../util/cpumap.h" 17 #include "../../../util/event.h" 18 #include "../../../util/evsel.h" 19 #include "../../../util/evsel_config.h" 20 #include "../../../util/evlist.h" 21 #include "../../../util/session.h" 22 #include <internal/lib.h> // page_size 23 #include "../../../util/pmu.h" 24 #include "../../../util/debug.h" 25 #include "../../../util/auxtrace.h" 26 #include "../../../util/record.h" 27 #include "../../../util/header.h" 28 #include "../../../util/arm-spe.h" 29 #include <tools/libc_compat.h> // reallocarray 30 31 #define ARM_SPE_CPU_MAGIC 0x1010101010101010ULL 32 33 #define KiB(x) ((x) * 1024) 34 #define MiB(x) ((x) * 1024 * 1024) 35 36 struct arm_spe_recording { 37 struct auxtrace_record itr; 38 struct perf_pmu *arm_spe_pmu; 39 struct evlist *evlist; 40 int wrapped_cnt; 41 bool *wrapped; 42 }; 43 44 /* Iterate config list to detect if the "freq" parameter is set */ 45 static bool arm_spe_is_set_freq(struct evsel *evsel) 46 { 47 struct evsel_config_term *term; 48 49 list_for_each_entry(term, &evsel->config_terms, list) { 50 if (term->type == EVSEL__CONFIG_TERM_FREQ) 51 return true; 52 } 53 54 return false; 55 } 56 57 /* 58 * arm_spe_find_cpus() returns a new cpu map, and the caller should invoke 59 * perf_cpu_map__put() to release the map after use. 60 */ 61 static struct perf_cpu_map *arm_spe_find_cpus(struct evlist *evlist) 62 { 63 struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus; 64 struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus(); 65 struct perf_cpu_map *intersect_cpus; 66 67 /* cpu map is not "any" CPU , we have specific CPUs to work with */ 68 if (!perf_cpu_map__has_any_cpu(event_cpus)) { 69 intersect_cpus = perf_cpu_map__intersect(event_cpus, online_cpus); 70 perf_cpu_map__put(online_cpus); 71 /* Event can be "any" CPU so count all CPUs. */ 72 } else { 73 intersect_cpus = online_cpus; 74 } 75 76 return intersect_cpus; 77 } 78 79 static size_t 80 arm_spe_info_priv_size(struct auxtrace_record *itr __maybe_unused, 81 struct evlist *evlist) 82 { 83 struct perf_cpu_map *cpu_map = arm_spe_find_cpus(evlist); 84 size_t size; 85 86 if (!cpu_map) 87 return 0; 88 89 size = ARM_SPE_AUXTRACE_PRIV_MAX + 90 ARM_SPE_CPU_PRIV_MAX * perf_cpu_map__nr(cpu_map); 91 size *= sizeof(u64); 92 93 perf_cpu_map__put(cpu_map); 94 return size; 95 } 96 97 static int arm_spe_save_cpu_header(struct auxtrace_record *itr, 98 struct perf_cpu cpu, __u64 data[]) 99 { 100 struct arm_spe_recording *sper = 101 container_of(itr, struct arm_spe_recording, itr); 102 struct perf_pmu *pmu = NULL; 103 char *cpuid = NULL; 104 u64 val; 105 106 /* Read CPU MIDR */ 107 cpuid = get_cpuid_allow_env_override(cpu); 108 if (!cpuid) 109 return -ENOMEM; 110 val = strtol(cpuid, NULL, 16); 111 112 data[ARM_SPE_MAGIC] = ARM_SPE_CPU_MAGIC; 113 data[ARM_SPE_CPU] = cpu.cpu; 114 data[ARM_SPE_CPU_NR_PARAMS] = ARM_SPE_CPU_PRIV_MAX - ARM_SPE_CPU_MIDR; 115 data[ARM_SPE_CPU_MIDR] = val; 116 117 /* Find the associate Arm SPE PMU for the CPU */ 118 if (perf_cpu_map__has(sper->arm_spe_pmu->cpus, cpu)) 119 pmu = sper->arm_spe_pmu; 120 121 if (!pmu) { 122 /* No Arm SPE PMU is found */ 123 data[ARM_SPE_CPU_PMU_TYPE] = ULLONG_MAX; 124 data[ARM_SPE_CAP_MIN_IVAL] = 0; 125 data[ARM_SPE_CAP_EVENT_FILTER] = 0; 126 } else { 127 data[ARM_SPE_CPU_PMU_TYPE] = pmu->type; 128 129 if (perf_pmu__scan_file(pmu, "caps/min_interval", "%lu", &val) != 1) 130 val = 0; 131 data[ARM_SPE_CAP_MIN_IVAL] = val; 132 133 if (perf_pmu__scan_file(pmu, "caps/event_filter", "%lx", &val) != 1) 134 val = 0; 135 data[ARM_SPE_CAP_EVENT_FILTER] = val; 136 } 137 138 free(cpuid); 139 return ARM_SPE_CPU_PRIV_MAX; 140 } 141 142 static int arm_spe_info_fill(struct auxtrace_record *itr, 143 struct perf_session *session, 144 struct perf_record_auxtrace_info *auxtrace_info, 145 size_t priv_size) 146 { 147 unsigned int i; 148 int ret; 149 size_t offset; 150 struct arm_spe_recording *sper = 151 container_of(itr, struct arm_spe_recording, itr); 152 struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu; 153 struct perf_cpu_map *cpu_map; 154 struct perf_cpu cpu; 155 __u64 *data; 156 157 if (priv_size != arm_spe_info_priv_size(itr, session->evlist)) 158 return -EINVAL; 159 160 if (!session->evlist->core.nr_mmaps) 161 return -EINVAL; 162 163 cpu_map = arm_spe_find_cpus(session->evlist); 164 if (!cpu_map) 165 return -EINVAL; 166 167 auxtrace_info->type = PERF_AUXTRACE_ARM_SPE; 168 auxtrace_info->priv[ARM_SPE_HEADER_VERSION] = ARM_SPE_HEADER_CURRENT_VERSION; 169 auxtrace_info->priv[ARM_SPE_HEADER_SIZE] = 170 ARM_SPE_AUXTRACE_PRIV_MAX - ARM_SPE_HEADER_VERSION; 171 auxtrace_info->priv[ARM_SPE_PMU_TYPE_V2] = arm_spe_pmu->type; 172 auxtrace_info->priv[ARM_SPE_CPUS_NUM] = perf_cpu_map__nr(cpu_map); 173 174 offset = ARM_SPE_AUXTRACE_PRIV_MAX; 175 perf_cpu_map__for_each_cpu(cpu, i, cpu_map) { 176 assert(offset < priv_size); 177 data = &auxtrace_info->priv[offset]; 178 ret = arm_spe_save_cpu_header(itr, cpu, data); 179 if (ret < 0) 180 goto out; 181 offset += ret; 182 } 183 184 ret = 0; 185 out: 186 perf_cpu_map__put(cpu_map); 187 return ret; 188 } 189 190 static void 191 arm_spe_snapshot_resolve_auxtrace_defaults(struct record_opts *opts, 192 bool privileged) 193 { 194 /* 195 * The default snapshot size is the auxtrace mmap size. If neither auxtrace mmap size nor 196 * snapshot size is specified, then the default is 4MiB for privileged users, 128KiB for 197 * unprivileged users. 198 * 199 * The default auxtrace mmap size is 4MiB/page_size for privileged users, 128KiB for 200 * unprivileged users. If an unprivileged user does not specify mmap pages, the mmap pages 201 * will be reduced from the default 512KiB/page_size to 256KiB/page_size, otherwise the 202 * user is likely to get an error as they exceed their mlock limmit. 203 */ 204 205 /* 206 * No size were given to '-S' or '-m,', so go with the default 207 */ 208 if (!opts->auxtrace_snapshot_size && !opts->auxtrace_mmap_pages) { 209 if (privileged) { 210 opts->auxtrace_mmap_pages = MiB(4) / page_size; 211 } else { 212 opts->auxtrace_mmap_pages = KiB(128) / page_size; 213 if (opts->mmap_pages == UINT_MAX) 214 opts->mmap_pages = KiB(256) / page_size; 215 } 216 } else if (!opts->auxtrace_mmap_pages && !privileged && opts->mmap_pages == UINT_MAX) { 217 opts->mmap_pages = KiB(256) / page_size; 218 } 219 220 /* 221 * '-m,xyz' was specified but no snapshot size, so make the snapshot size as big as the 222 * auxtrace mmap area. 223 */ 224 if (!opts->auxtrace_snapshot_size) 225 opts->auxtrace_snapshot_size = opts->auxtrace_mmap_pages * (size_t)page_size; 226 227 /* 228 * '-Sxyz' was specified but no auxtrace mmap area, so make the auxtrace mmap area big 229 * enough to fit the requested snapshot size. 230 */ 231 if (!opts->auxtrace_mmap_pages) { 232 size_t sz = opts->auxtrace_snapshot_size; 233 234 sz = round_up(sz, page_size) / page_size; 235 opts->auxtrace_mmap_pages = roundup_pow_of_two(sz); 236 } 237 } 238 239 static __u64 arm_spe_pmu__sample_period(const struct perf_pmu *arm_spe_pmu) 240 { 241 static __u64 sample_period; 242 243 if (sample_period) 244 return sample_period; 245 246 /* 247 * If kernel driver doesn't advertise a minimum, 248 * use max allowable by PMSIDR_EL1.INTERVAL 249 */ 250 if (perf_pmu__scan_file(arm_spe_pmu, "caps/min_interval", "%llu", 251 &sample_period) != 1) { 252 pr_debug("arm_spe driver doesn't advertise a min. interval. Using 4096\n"); 253 sample_period = 4096; 254 } 255 return sample_period; 256 } 257 258 static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus) 259 { 260 u64 pa_enable_bit; 261 262 evsel->core.attr.freq = 0; 263 evsel->core.attr.sample_period = arm_spe_pmu__sample_period(evsel->pmu); 264 evsel->needs_auxtrace_mmap = true; 265 266 /* 267 * To obtain the auxtrace buffer file descriptor, the auxtrace event 268 * must come first. 269 */ 270 evlist__to_front(evsel->evlist, evsel); 271 272 /* 273 * In the case of per-cpu mmaps, sample CPU for AUX event; 274 * also enable the timestamp tracing for samples correlation. 275 */ 276 if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) { 277 evsel__set_sample_bit(evsel, CPU); 278 evsel__set_config_if_unset(evsel, "ts_enable", 1); 279 } 280 281 /* 282 * Set this only so that perf report knows that SPE generates memory info. It has no effect 283 * on the opening of the event or the SPE data produced. 284 */ 285 evsel__set_sample_bit(evsel, DATA_SRC); 286 287 /* 288 * The PHYS_ADDR flag does not affect the driver behaviour, it is used to 289 * inform that the resulting output's SPE samples contain physical addresses 290 * where applicable. 291 */ 292 293 if (!evsel__get_config_val(evsel, "pa_enable", &pa_enable_bit)) 294 if (pa_enable_bit) 295 evsel__set_sample_bit(evsel, PHYS_ADDR); 296 } 297 298 static int arm_spe_setup_aux_buffer(struct record_opts *opts) 299 { 300 bool privileged = perf_event_paranoid_check(-1); 301 302 /* 303 * we are in snapshot mode. 304 */ 305 if (opts->auxtrace_snapshot_mode) { 306 /* 307 * Command arguments '-Sxyz' and/or '-m,xyz' are missing, so fill those in with 308 * default values. 309 */ 310 if (!opts->auxtrace_snapshot_size || !opts->auxtrace_mmap_pages) 311 arm_spe_snapshot_resolve_auxtrace_defaults(opts, privileged); 312 313 /* 314 * Snapshot size can't be bigger than the auxtrace area. 315 */ 316 if (opts->auxtrace_snapshot_size > opts->auxtrace_mmap_pages * (size_t)page_size) { 317 pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n", 318 opts->auxtrace_snapshot_size, 319 opts->auxtrace_mmap_pages * (size_t)page_size); 320 return -EINVAL; 321 } 322 323 /* 324 * Something went wrong somewhere - this shouldn't happen. 325 */ 326 if (!opts->auxtrace_snapshot_size || !opts->auxtrace_mmap_pages) { 327 pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n"); 328 return -EINVAL; 329 } 330 331 pr_debug2("%sx snapshot size: %zu\n", ARM_SPE_PMU_NAME, 332 opts->auxtrace_snapshot_size); 333 } 334 335 /* We are in full trace mode but '-m,xyz' wasn't specified */ 336 if (!opts->auxtrace_mmap_pages) { 337 if (privileged) { 338 opts->auxtrace_mmap_pages = MiB(4) / page_size; 339 } else { 340 opts->auxtrace_mmap_pages = KiB(128) / page_size; 341 if (opts->mmap_pages == UINT_MAX) 342 opts->mmap_pages = KiB(256) / page_size; 343 } 344 } 345 346 /* Validate auxtrace_mmap_pages */ 347 if (opts->auxtrace_mmap_pages) { 348 size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size; 349 size_t min_sz = KiB(8); 350 351 if (sz < min_sz || !is_power_of_2(sz)) { 352 pr_err("Invalid mmap size for ARM SPE: must be at least %zuKiB and a power of 2\n", 353 min_sz / 1024); 354 return -EINVAL; 355 } 356 } 357 358 return 0; 359 } 360 361 static int arm_spe_setup_tracking_event(struct evlist *evlist, 362 struct record_opts *opts) 363 { 364 int err; 365 struct evsel *tracking_evsel; 366 struct perf_cpu_map *cpus = evlist->core.user_requested_cpus; 367 368 /* Add dummy event to keep tracking */ 369 err = parse_event(evlist, "dummy:u"); 370 if (err) 371 return err; 372 373 tracking_evsel = evlist__last(evlist); 374 evlist__set_tracking_event(evlist, tracking_evsel); 375 376 tracking_evsel->core.attr.freq = 0; 377 tracking_evsel->core.attr.sample_period = 1; 378 379 /* In per-cpu case, always need the time of mmap events etc */ 380 if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) { 381 evsel__set_sample_bit(tracking_evsel, TIME); 382 evsel__set_sample_bit(tracking_evsel, CPU); 383 384 /* also track task context switch */ 385 if (!record_opts__no_switch_events(opts)) 386 tracking_evsel->core.attr.context_switch = 1; 387 } 388 389 return 0; 390 } 391 392 static int arm_spe_recording_options(struct auxtrace_record *itr, 393 struct evlist *evlist, 394 struct record_opts *opts) 395 { 396 struct arm_spe_recording *sper = 397 container_of(itr, struct arm_spe_recording, itr); 398 struct evsel *evsel, *tmp; 399 struct perf_cpu_map *cpus = evlist->core.user_requested_cpus; 400 bool discard = false; 401 int err; 402 u64 discard_bit; 403 404 sper->evlist = evlist; 405 406 evlist__for_each_entry(evlist, evsel) { 407 if (evsel__is_aux_event(evsel)) { 408 if (!strstarts(evsel->pmu->name, ARM_SPE_PMU_NAME)) { 409 pr_err("Found unexpected auxtrace event: %s\n", 410 evsel->pmu->name); 411 return -EINVAL; 412 } 413 opts->full_auxtrace = true; 414 415 if (opts->user_freq != UINT_MAX || 416 arm_spe_is_set_freq(evsel)) { 417 pr_err("Arm SPE: Frequency is not supported. " 418 "Set period with -c option or PMU parameter (-e %s/period=NUM/).\n", 419 evsel->pmu->name); 420 return -EINVAL; 421 } 422 } 423 } 424 425 if (!opts->full_auxtrace) 426 return 0; 427 428 evlist__for_each_entry_safe(evlist, tmp, evsel) { 429 if (evsel__is_aux_event(evsel)) { 430 arm_spe_setup_evsel(evsel, cpus); 431 if (!evsel__get_config_val(evsel, "discard", &discard_bit)) 432 discard = !!discard_bit; 433 } 434 } 435 436 if (discard) 437 return 0; 438 439 err = arm_spe_setup_aux_buffer(opts); 440 if (err) 441 return err; 442 443 return arm_spe_setup_tracking_event(evlist, opts); 444 } 445 446 static int arm_spe_parse_snapshot_options(struct auxtrace_record *itr __maybe_unused, 447 struct record_opts *opts, 448 const char *str) 449 { 450 unsigned long long snapshot_size = 0; 451 char *endptr; 452 453 if (str) { 454 snapshot_size = strtoull(str, &endptr, 0); 455 if (*endptr || snapshot_size > SIZE_MAX) 456 return -1; 457 } 458 459 opts->auxtrace_snapshot_mode = true; 460 opts->auxtrace_snapshot_size = snapshot_size; 461 462 return 0; 463 } 464 465 static int arm_spe_snapshot_start(struct auxtrace_record *itr) 466 { 467 struct arm_spe_recording *ptr = 468 container_of(itr, struct arm_spe_recording, itr); 469 struct evsel *evsel; 470 int ret = -EINVAL; 471 472 evlist__for_each_entry(ptr->evlist, evsel) { 473 if (evsel__is_aux_event(evsel)) { 474 ret = evsel__disable(evsel); 475 if (ret < 0) 476 return ret; 477 } 478 } 479 return ret; 480 } 481 482 static int arm_spe_snapshot_finish(struct auxtrace_record *itr) 483 { 484 struct arm_spe_recording *ptr = 485 container_of(itr, struct arm_spe_recording, itr); 486 struct evsel *evsel; 487 int ret = -EINVAL; 488 489 evlist__for_each_entry(ptr->evlist, evsel) { 490 if (evsel__is_aux_event(evsel)) { 491 ret = evsel__enable(evsel); 492 if (ret < 0) 493 return ret; 494 } 495 } 496 return ret; 497 } 498 499 static int arm_spe_alloc_wrapped_array(struct arm_spe_recording *ptr, int idx) 500 { 501 bool *wrapped; 502 int cnt = ptr->wrapped_cnt, new_cnt, i; 503 504 /* 505 * No need to allocate, so return early. 506 */ 507 if (idx < cnt) 508 return 0; 509 510 /* 511 * Make ptr->wrapped as big as idx. 512 */ 513 new_cnt = idx + 1; 514 515 /* 516 * Free'ed in arm_spe_recording_free(). 517 */ 518 wrapped = reallocarray(ptr->wrapped, new_cnt, sizeof(bool)); 519 if (!wrapped) 520 return -ENOMEM; 521 522 /* 523 * init new allocated values. 524 */ 525 for (i = cnt; i < new_cnt; i++) 526 wrapped[i] = false; 527 528 ptr->wrapped_cnt = new_cnt; 529 ptr->wrapped = wrapped; 530 531 return 0; 532 } 533 534 static bool arm_spe_buffer_has_wrapped(unsigned char *buffer, 535 size_t buffer_size, u64 head) 536 { 537 u64 i, watermark; 538 u64 *buf = (u64 *)buffer; 539 size_t buf_size = buffer_size; 540 541 /* 542 * Defensively handle the case where head might be continually increasing - if its value is 543 * equal or greater than the size of the ring buffer, then we can safely determine it has 544 * wrapped around. Otherwise, continue to detect if head might have wrapped. 545 */ 546 if (head >= buffer_size) 547 return true; 548 549 /* 550 * We want to look the very last 512 byte (chosen arbitrarily) in the ring buffer. 551 */ 552 watermark = buf_size - 512; 553 554 /* 555 * The value of head is somewhere within the size of the ring buffer. This can be that there 556 * hasn't been enough data to fill the ring buffer yet or the trace time was so long that 557 * head has numerically wrapped around. To find we need to check if we have data at the 558 * very end of the ring buffer. We can reliably do this because mmap'ed pages are zeroed 559 * out and there is a fresh mapping with every new session. 560 */ 561 562 /* 563 * head is less than 512 byte from the end of the ring buffer. 564 */ 565 if (head > watermark) 566 watermark = head; 567 568 /* 569 * Speed things up by using 64 bit transactions (see "u64 *buf" above) 570 */ 571 watermark /= sizeof(u64); 572 buf_size /= sizeof(u64); 573 574 /* 575 * If we find trace data at the end of the ring buffer, head has been there and has 576 * numerically wrapped around at least once. 577 */ 578 for (i = watermark; i < buf_size; i++) 579 if (buf[i]) 580 return true; 581 582 return false; 583 } 584 585 static int arm_spe_find_snapshot(struct auxtrace_record *itr, int idx, 586 struct auxtrace_mmap *mm, unsigned char *data, 587 u64 *head, u64 *old) 588 { 589 int err; 590 bool wrapped; 591 struct arm_spe_recording *ptr = 592 container_of(itr, struct arm_spe_recording, itr); 593 594 /* 595 * Allocate memory to keep track of wrapping if this is the first 596 * time we deal with this *mm. 597 */ 598 if (idx >= ptr->wrapped_cnt) { 599 err = arm_spe_alloc_wrapped_array(ptr, idx); 600 if (err) 601 return err; 602 } 603 604 /* 605 * Check to see if *head has wrapped around. If it hasn't only the 606 * amount of data between *head and *old is snapshot'ed to avoid 607 * bloating the perf.data file with zeros. But as soon as *head has 608 * wrapped around the entire size of the AUX ring buffer it taken. 609 */ 610 wrapped = ptr->wrapped[idx]; 611 if (!wrapped && arm_spe_buffer_has_wrapped(data, mm->len, *head)) { 612 wrapped = true; 613 ptr->wrapped[idx] = true; 614 } 615 616 pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n", 617 __func__, idx, (size_t)*old, (size_t)*head, mm->len); 618 619 /* 620 * No wrap has occurred, we can just use *head and *old. 621 */ 622 if (!wrapped) 623 return 0; 624 625 /* 626 * *head has wrapped around - adjust *head and *old to pickup the 627 * entire content of the AUX buffer. 628 */ 629 if (*head >= mm->len) { 630 *old = *head - mm->len; 631 } else { 632 *head += mm->len; 633 *old = *head - mm->len; 634 } 635 636 return 0; 637 } 638 639 static u64 arm_spe_reference(struct auxtrace_record *itr __maybe_unused) 640 { 641 struct timespec ts; 642 643 clock_gettime(CLOCK_MONOTONIC_RAW, &ts); 644 645 return ts.tv_sec ^ ts.tv_nsec; 646 } 647 648 static void arm_spe_recording_free(struct auxtrace_record *itr) 649 { 650 struct arm_spe_recording *sper = 651 container_of(itr, struct arm_spe_recording, itr); 652 653 zfree(&sper->wrapped); 654 free(sper); 655 } 656 657 struct auxtrace_record *arm_spe_recording_init(int *err, 658 struct perf_pmu *arm_spe_pmu) 659 { 660 struct arm_spe_recording *sper; 661 662 if (!arm_spe_pmu) { 663 *err = -ENODEV; 664 return NULL; 665 } 666 667 sper = zalloc(sizeof(struct arm_spe_recording)); 668 if (!sper) { 669 *err = -ENOMEM; 670 return NULL; 671 } 672 673 sper->arm_spe_pmu = arm_spe_pmu; 674 sper->itr.snapshot_start = arm_spe_snapshot_start; 675 sper->itr.snapshot_finish = arm_spe_snapshot_finish; 676 sper->itr.find_snapshot = arm_spe_find_snapshot; 677 sper->itr.parse_snapshot_options = arm_spe_parse_snapshot_options; 678 sper->itr.recording_options = arm_spe_recording_options; 679 sper->itr.info_priv_size = arm_spe_info_priv_size; 680 sper->itr.info_fill = arm_spe_info_fill; 681 sper->itr.free = arm_spe_recording_free; 682 sper->itr.reference = arm_spe_reference; 683 sper->itr.read_finish = auxtrace_record__read_finish; 684 sper->itr.alignment = 0; 685 686 *err = 0; 687 return &sper->itr; 688 } 689 690 void 691 arm_spe_pmu_default_config(const struct perf_pmu *arm_spe_pmu, struct perf_event_attr *attr) 692 { 693 attr->sample_period = arm_spe_pmu__sample_period(arm_spe_pmu); 694 } 695