perf auxtrace arm: Refactor event list iteration in auxtrace_record__init()
[platform/kernel/linux-starfive.git] / tools / perf / arch / arm / util / auxtrace.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright(C) 2015 Linaro Limited. All rights reserved.
4  * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
5  */
6
7 #include <stdbool.h>
8 #include <linux/coresight-pmu.h>
9 #include <linux/zalloc.h>
10
11 #include "../../../util/auxtrace.h"
12 #include "../../../util/debug.h"
13 #include "../../../util/evlist.h"
14 #include "../../../util/pmu.h"
15 #include "cs-etm.h"
16 #include "arm-spe.h"
17
18 static struct perf_pmu **find_all_arm_spe_pmus(int *nr_spes, int *err)
19 {
20         struct perf_pmu **arm_spe_pmus = NULL;
21         int ret, i, nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
22         /* arm_spe_xxxxxxxxx\0 */
23         char arm_spe_pmu_name[sizeof(ARM_SPE_PMU_NAME) + 10];
24
25         arm_spe_pmus = zalloc(sizeof(struct perf_pmu *) * nr_cpus);
26         if (!arm_spe_pmus) {
27                 pr_err("spes alloc failed\n");
28                 *err = -ENOMEM;
29                 return NULL;
30         }
31
32         for (i = 0; i < nr_cpus; i++) {
33                 ret = sprintf(arm_spe_pmu_name, "%s%d", ARM_SPE_PMU_NAME, i);
34                 if (ret < 0) {
35                         pr_err("sprintf failed\n");
36                         *err = -ENOMEM;
37                         return NULL;
38                 }
39
40                 arm_spe_pmus[*nr_spes] = perf_pmu__find(arm_spe_pmu_name);
41                 if (arm_spe_pmus[*nr_spes]) {
42                         pr_debug2("%s %d: arm_spe_pmu %d type %d name %s\n",
43                                  __func__, __LINE__, *nr_spes,
44                                  arm_spe_pmus[*nr_spes]->type,
45                                  arm_spe_pmus[*nr_spes]->name);
46                         (*nr_spes)++;
47                 }
48         }
49
50         return arm_spe_pmus;
51 }
52
53 static struct perf_pmu *find_pmu_for_event(struct perf_pmu **pmus,
54                                            int pmu_nr, struct evsel *evsel)
55 {
56         int i;
57
58         if (!pmus)
59                 return NULL;
60
61         for (i = 0; i < pmu_nr; i++) {
62                 if (evsel->core.attr.type == pmus[i]->type)
63                         return pmus[i];
64         }
65
66         return NULL;
67 }
68
69 struct auxtrace_record
70 *auxtrace_record__init(struct evlist *evlist, int *err)
71 {
72         struct perf_pmu *cs_etm_pmu = NULL;
73         struct perf_pmu **arm_spe_pmus = NULL;
74         struct evsel *evsel;
75         struct perf_pmu *found_etm = NULL;
76         struct perf_pmu *found_spe = NULL;
77         int auxtrace_event_cnt = 0;
78         int nr_spes = 0;
79
80         if (!evlist)
81                 return NULL;
82
83         cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
84         arm_spe_pmus = find_all_arm_spe_pmus(&nr_spes, err);
85
86         evlist__for_each_entry(evlist, evsel) {
87                 if (cs_etm_pmu && !found_etm)
88                         found_etm = find_pmu_for_event(&cs_etm_pmu, 1, evsel);
89
90                 if (arm_spe_pmus && !found_spe)
91                         found_spe = find_pmu_for_event(arm_spe_pmus, nr_spes, evsel);
92         }
93
94         free(arm_spe_pmus);
95
96         if (found_etm)
97                 auxtrace_event_cnt++;
98
99         if (found_spe)
100                 auxtrace_event_cnt++;
101
102         if (auxtrace_event_cnt > 1) {
103                 pr_err("Concurrent AUX trace operation not currently supported\n");
104                 *err = -EOPNOTSUPP;
105                 return NULL;
106         }
107
108         if (found_etm)
109                 return cs_etm_record_init(err);
110
111 #if defined(__aarch64__)
112         if (found_spe)
113                 return arm_spe_recording_init(err, found_spe);
114 #endif
115
116         /*
117          * Clear 'err' even if we haven't found an event - that way perf
118          * record can still be used even if tracers aren't present.  The NULL
119          * return value will take care of telling the infrastructure HW tracing
120          * isn't available.
121          */
122         *err = 0;
123         return NULL;
124 }
125
126 #if defined(__arm__)
127 u64 compat_auxtrace_mmap__read_head(struct auxtrace_mmap *mm)
128 {
129         struct perf_event_mmap_page *pc = mm->userpg;
130         u64 result;
131
132         __asm__ __volatile__(
133 "       ldrd    %0, %H0, [%1]"
134         : "=&r" (result)
135         : "r" (&pc->aux_head), "Qo" (pc->aux_head)
136         );
137
138         return result;
139 }
140
141 int compat_auxtrace_mmap__write_tail(struct auxtrace_mmap *mm, u64 tail)
142 {
143         struct perf_event_mmap_page *pc = mm->userpg;
144
145         /* Ensure all reads are done before we write the tail out */
146         smp_mb();
147
148         __asm__ __volatile__(
149 "       strd    %2, %H2, [%1]"
150         : "=Qo" (pc->aux_tail)
151         : "r" (&pc->aux_tail), "r" (tail)
152         );
153
154         return 0;
155 }
156 #endif