18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright(C) 2015 Linaro Limited. All rights reserved. 48c2ecf20Sopenharmony_ci * Author: Mathieu Poirier <mathieu.poirier@linaro.org> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <stdbool.h> 88c2ecf20Sopenharmony_ci#include <linux/coresight-pmu.h> 98c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "../../util/auxtrace.h" 128c2ecf20Sopenharmony_ci#include "../../util/debug.h" 138c2ecf20Sopenharmony_ci#include "../../util/evlist.h" 148c2ecf20Sopenharmony_ci#include "../../util/pmu.h" 158c2ecf20Sopenharmony_ci#include "cs-etm.h" 168c2ecf20Sopenharmony_ci#include "arm-spe.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic struct perf_pmu **find_all_arm_spe_pmus(int *nr_spes, int *err) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci struct perf_pmu **arm_spe_pmus = NULL; 218c2ecf20Sopenharmony_ci int ret, i, nr_cpus = sysconf(_SC_NPROCESSORS_CONF); 228c2ecf20Sopenharmony_ci /* arm_spe_xxxxxxxxx\0 */ 238c2ecf20Sopenharmony_ci char arm_spe_pmu_name[sizeof(ARM_SPE_PMU_NAME) + 10]; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci arm_spe_pmus = zalloc(sizeof(struct perf_pmu *) * nr_cpus); 268c2ecf20Sopenharmony_ci if (!arm_spe_pmus) { 278c2ecf20Sopenharmony_ci pr_err("spes alloc failed\n"); 288c2ecf20Sopenharmony_ci *err = -ENOMEM; 298c2ecf20Sopenharmony_ci return NULL; 308c2ecf20Sopenharmony_ci } 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci for (i = 0; i < nr_cpus; i++) { 338c2ecf20Sopenharmony_ci ret = sprintf(arm_spe_pmu_name, "%s%d", ARM_SPE_PMU_NAME, i); 348c2ecf20Sopenharmony_ci if (ret < 0) { 358c2ecf20Sopenharmony_ci pr_err("sprintf failed\n"); 368c2ecf20Sopenharmony_ci *err = -ENOMEM; 378c2ecf20Sopenharmony_ci return NULL; 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci arm_spe_pmus[*nr_spes] = perf_pmu__find(arm_spe_pmu_name); 418c2ecf20Sopenharmony_ci if (arm_spe_pmus[*nr_spes]) { 428c2ecf20Sopenharmony_ci pr_debug2("%s %d: arm_spe_pmu %d type %d name %s\n", 438c2ecf20Sopenharmony_ci __func__, __LINE__, *nr_spes, 448c2ecf20Sopenharmony_ci arm_spe_pmus[*nr_spes]->type, 458c2ecf20Sopenharmony_ci arm_spe_pmus[*nr_spes]->name); 468c2ecf20Sopenharmony_ci (*nr_spes)++; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci return arm_spe_pmus; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistruct auxtrace_record 548c2ecf20Sopenharmony_ci*auxtrace_record__init(struct evlist *evlist, int *err) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct perf_pmu *cs_etm_pmu; 578c2ecf20Sopenharmony_ci struct evsel *evsel; 588c2ecf20Sopenharmony_ci bool found_etm = false; 598c2ecf20Sopenharmony_ci struct perf_pmu *found_spe = NULL; 608c2ecf20Sopenharmony_ci struct perf_pmu **arm_spe_pmus = NULL; 618c2ecf20Sopenharmony_ci int nr_spes = 0; 628c2ecf20Sopenharmony_ci int i = 0; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (!evlist) 658c2ecf20Sopenharmony_ci return NULL; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME); 688c2ecf20Sopenharmony_ci arm_spe_pmus = find_all_arm_spe_pmus(&nr_spes, err); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 718c2ecf20Sopenharmony_ci if (cs_etm_pmu && 728c2ecf20Sopenharmony_ci evsel->core.attr.type == cs_etm_pmu->type) 738c2ecf20Sopenharmony_ci found_etm = true; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (!nr_spes || found_spe) 768c2ecf20Sopenharmony_ci continue; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci for (i = 0; i < nr_spes; i++) { 798c2ecf20Sopenharmony_ci if (evsel->core.attr.type == arm_spe_pmus[i]->type) { 808c2ecf20Sopenharmony_ci found_spe = arm_spe_pmus[i]; 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci free(arm_spe_pmus); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (found_etm && found_spe) { 888c2ecf20Sopenharmony_ci pr_err("Concurrent ARM Coresight ETM and SPE operation not currently supported\n"); 898c2ecf20Sopenharmony_ci *err = -EOPNOTSUPP; 908c2ecf20Sopenharmony_ci return NULL; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (found_etm) 948c2ecf20Sopenharmony_ci return cs_etm_record_init(err); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#if defined(__aarch64__) 978c2ecf20Sopenharmony_ci if (found_spe) 988c2ecf20Sopenharmony_ci return arm_spe_recording_init(err, found_spe); 998c2ecf20Sopenharmony_ci#endif 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* 1028c2ecf20Sopenharmony_ci * Clear 'err' even if we haven't found an event - that way perf 1038c2ecf20Sopenharmony_ci * record can still be used even if tracers aren't present. The NULL 1048c2ecf20Sopenharmony_ci * return value will take care of telling the infrastructure HW tracing 1058c2ecf20Sopenharmony_ci * isn't available. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci *err = 0; 1088c2ecf20Sopenharmony_ci return NULL; 1098c2ecf20Sopenharmony_ci} 110