1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright(C) 2015 Linaro Limited. All rights reserved.
4 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
9 #include <linux/coresight-pmu.h>
10 #include <linux/zalloc.h>
11 #include <api/fs/fs.h>
13 #include "../../../util/auxtrace.h"
14 #include "../../../util/debug.h"
15 #include "../../../util/evlist.h"
16 #include "../../../util/pmu.h"
17 #include "../../../util/pmus.h"
22 static struct perf_pmu
**find_all_arm_spe_pmus(int *nr_spes
, int *err
)
24 struct perf_pmu
**arm_spe_pmus
= NULL
;
25 int ret
, i
, nr_cpus
= sysconf(_SC_NPROCESSORS_CONF
);
26 /* arm_spe_xxxxxxxxx\0 */
27 char arm_spe_pmu_name
[sizeof(ARM_SPE_PMU_NAME
) + 10];
29 arm_spe_pmus
= zalloc(sizeof(struct perf_pmu
*) * nr_cpus
);
31 pr_err("spes alloc failed\n");
36 for (i
= 0; i
< nr_cpus
; i
++) {
37 ret
= sprintf(arm_spe_pmu_name
, "%s%d", ARM_SPE_PMU_NAME
, i
);
39 pr_err("sprintf failed\n");
44 arm_spe_pmus
[*nr_spes
] = perf_pmus__find(arm_spe_pmu_name
);
45 if (arm_spe_pmus
[*nr_spes
]) {
46 pr_debug2("%s %d: arm_spe_pmu %d type %d name %s\n",
47 __func__
, __LINE__
, *nr_spes
,
48 arm_spe_pmus
[*nr_spes
]->type
,
49 arm_spe_pmus
[*nr_spes
]->name
);
57 static struct perf_pmu
**find_all_hisi_ptt_pmus(int *nr_ptts
, int *err
)
59 struct perf_pmu
**hisi_ptt_pmus
= NULL
;
65 perf_pmu__event_source_devices_scnprintf(path
, sizeof(path
));
68 pr_err("can't read directory '%s'\n", path
);
73 while ((dent
= readdir(dir
))) {
74 if (strstr(dent
->d_name
, HISI_PTT_PMU_NAME
))
81 hisi_ptt_pmus
= zalloc(sizeof(struct perf_pmu
*) * (*nr_ptts
));
83 pr_err("hisi_ptt alloc failed\n");
89 while ((dent
= readdir(dir
))) {
90 if (strstr(dent
->d_name
, HISI_PTT_PMU_NAME
) && idx
< *nr_ptts
) {
91 hisi_ptt_pmus
[idx
] = perf_pmus__find(dent
->d_name
);
92 if (hisi_ptt_pmus
[idx
])
102 static struct perf_pmu
*find_pmu_for_event(struct perf_pmu
**pmus
,
103 int pmu_nr
, struct evsel
*evsel
)
110 for (i
= 0; i
< pmu_nr
; i
++) {
111 if (evsel
->core
.attr
.type
== pmus
[i
]->type
)
118 struct auxtrace_record
119 *auxtrace_record__init(struct evlist
*evlist
, int *err
)
121 struct perf_pmu
*cs_etm_pmu
= NULL
;
122 struct perf_pmu
**arm_spe_pmus
= NULL
;
123 struct perf_pmu
**hisi_ptt_pmus
= NULL
;
125 struct perf_pmu
*found_etm
= NULL
;
126 struct perf_pmu
*found_spe
= NULL
;
127 struct perf_pmu
*found_ptt
= NULL
;
128 int auxtrace_event_cnt
= 0;
135 cs_etm_pmu
= perf_pmus__find(CORESIGHT_ETM_PMU_NAME
);
136 arm_spe_pmus
= find_all_arm_spe_pmus(&nr_spes
, err
);
137 hisi_ptt_pmus
= find_all_hisi_ptt_pmus(&nr_ptts
, err
);
139 evlist__for_each_entry(evlist
, evsel
) {
140 if (cs_etm_pmu
&& !found_etm
)
141 found_etm
= find_pmu_for_event(&cs_etm_pmu
, 1, evsel
);
143 if (arm_spe_pmus
&& !found_spe
)
144 found_spe
= find_pmu_for_event(arm_spe_pmus
, nr_spes
, evsel
);
146 if (hisi_ptt_pmus
&& !found_ptt
)
147 found_ptt
= find_pmu_for_event(hisi_ptt_pmus
, nr_ptts
, evsel
);
154 auxtrace_event_cnt
++;
157 auxtrace_event_cnt
++;
160 auxtrace_event_cnt
++;
162 if (auxtrace_event_cnt
> 1) {
163 pr_err("Concurrent AUX trace operation not currently supported\n");
169 return cs_etm_record_init(err
);
171 #if defined(__aarch64__)
173 return arm_spe_recording_init(err
, found_spe
);
176 return hisi_ptt_recording_init(err
, found_ptt
);
180 * Clear 'err' even if we haven't found an event - that way perf
181 * record can still be used even if tracers aren't present. The NULL
182 * return value will take care of telling the infrastructure HW tracing
190 u64
compat_auxtrace_mmap__read_head(struct auxtrace_mmap
*mm
)
192 struct perf_event_mmap_page
*pc
= mm
->userpg
;
195 __asm__
__volatile__(
196 " ldrd %0, %H0, [%1]"
198 : "r" (&pc
->aux_head
), "Qo" (pc
->aux_head
)
204 int compat_auxtrace_mmap__write_tail(struct auxtrace_mmap
*mm
, u64 tail
)
206 struct perf_event_mmap_page
*pc
= mm
->userpg
;
208 /* Ensure all reads are done before we write the tail out */
211 __asm__
__volatile__(
212 " strd %2, %H2, [%1]"
213 : "=Qo" (pc
->aux_tail
)
214 : "r" (&pc
->aux_tail
), "r" (tail
)