~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/perf/arch/arm/util/auxtrace.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 <dirent.h>
  8 #include <stdbool.h>
  9 #include <linux/coresight-pmu.h>
 10 #include <linux/zalloc.h>
 11 #include <api/fs/fs.h>
 12 
 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"
 18 #include "cs-etm.h"
 19 #include "arm-spe.h"
 20 #include "hisi-ptt.h"
 21 
 22 static struct perf_pmu **find_all_arm_spe_pmus(int *nr_spes, int *err)
 23 {
 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];
 28 
 29         arm_spe_pmus = zalloc(sizeof(struct perf_pmu *) * nr_cpus);
 30         if (!arm_spe_pmus) {
 31                 pr_err("spes alloc failed\n");
 32                 *err = -ENOMEM;
 33                 return NULL;
 34         }
 35 
 36         for (i = 0; i < nr_cpus; i++) {
 37                 ret = sprintf(arm_spe_pmu_name, "%s%d", ARM_SPE_PMU_NAME, i);
 38                 if (ret < 0) {
 39                         pr_err("sprintf failed\n");
 40                         *err = -ENOMEM;
 41                         return NULL;
 42                 }
 43 
 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);
 50                         (*nr_spes)++;
 51                 }
 52         }
 53 
 54         return arm_spe_pmus;
 55 }
 56 
 57 static struct perf_pmu **find_all_hisi_ptt_pmus(int *nr_ptts, int *err)
 58 {
 59         struct perf_pmu **hisi_ptt_pmus = NULL;
 60         struct dirent *dent;
 61         char path[PATH_MAX];
 62         DIR *dir = NULL;
 63         int idx = 0;
 64 
 65         perf_pmu__event_source_devices_scnprintf(path, sizeof(path));
 66         dir = opendir(path);
 67         if (!dir) {
 68                 pr_err("can't read directory '%s'\n", path);
 69                 *err = -EINVAL;
 70                 return NULL;
 71         }
 72 
 73         while ((dent = readdir(dir))) {
 74                 if (strstr(dent->d_name, HISI_PTT_PMU_NAME))
 75                         (*nr_ptts)++;
 76         }
 77 
 78         if (!(*nr_ptts))
 79                 goto out;
 80 
 81         hisi_ptt_pmus = zalloc(sizeof(struct perf_pmu *) * (*nr_ptts));
 82         if (!hisi_ptt_pmus) {
 83                 pr_err("hisi_ptt alloc failed\n");
 84                 *err = -ENOMEM;
 85                 goto out;
 86         }
 87 
 88         rewinddir(dir);
 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])
 93                                 idx++;
 94                 }
 95         }
 96 
 97 out:
 98         closedir(dir);
 99         return hisi_ptt_pmus;
100 }
101 
102 static struct perf_pmu *find_pmu_for_event(struct perf_pmu **pmus,
103                                            int pmu_nr, struct evsel *evsel)
104 {
105         int i;
106 
107         if (!pmus)
108                 return NULL;
109 
110         for (i = 0; i < pmu_nr; i++) {
111                 if (evsel->core.attr.type == pmus[i]->type)
112                         return pmus[i];
113         }
114 
115         return NULL;
116 }
117 
118 struct auxtrace_record
119 *auxtrace_record__init(struct evlist *evlist, int *err)
120 {
121         struct perf_pmu *cs_etm_pmu = NULL;
122         struct perf_pmu **arm_spe_pmus = NULL;
123         struct perf_pmu **hisi_ptt_pmus = NULL;
124         struct evsel *evsel;
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;
129         int nr_spes = 0;
130         int nr_ptts = 0;
131 
132         if (!evlist)
133                 return NULL;
134 
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);
138 
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);
142 
143                 if (arm_spe_pmus && !found_spe)
144                         found_spe = find_pmu_for_event(arm_spe_pmus, nr_spes, evsel);
145 
146                 if (hisi_ptt_pmus && !found_ptt)
147                         found_ptt = find_pmu_for_event(hisi_ptt_pmus, nr_ptts, evsel);
148         }
149 
150         free(arm_spe_pmus);
151         free(hisi_ptt_pmus);
152 
153         if (found_etm)
154                 auxtrace_event_cnt++;
155 
156         if (found_spe)
157                 auxtrace_event_cnt++;
158 
159         if (found_ptt)
160                 auxtrace_event_cnt++;
161 
162         if (auxtrace_event_cnt > 1) {
163                 pr_err("Concurrent AUX trace operation not currently supported\n");
164                 *err = -EOPNOTSUPP;
165                 return NULL;
166         }
167 
168         if (found_etm)
169                 return cs_etm_record_init(err);
170 
171 #if defined(__aarch64__)
172         if (found_spe)
173                 return arm_spe_recording_init(err, found_spe);
174 
175         if (found_ptt)
176                 return hisi_ptt_recording_init(err, found_ptt);
177 #endif
178 
179         /*
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
183          * isn't available.
184          */
185         *err = 0;
186         return NULL;
187 }
188 
189 #if defined(__arm__)
190 u64 compat_auxtrace_mmap__read_head(struct auxtrace_mmap *mm)
191 {
192         struct perf_event_mmap_page *pc = mm->userpg;
193         u64 result;
194 
195         __asm__ __volatile__(
196 "       ldrd    %0, %H0, [%1]"
197         : "=&r" (result)
198         : "r" (&pc->aux_head), "Qo" (pc->aux_head)
199         );
200 
201         return result;
202 }
203 
204 int compat_auxtrace_mmap__write_tail(struct auxtrace_mmap *mm, u64 tail)
205 {
206         struct perf_event_mmap_page *pc = mm->userpg;
207 
208         /* Ensure all reads are done before we write the tail out */
209         smp_mb();
210 
211         __asm__ __volatile__(
212 "       strd    %2, %H2, [%1]"
213         : "=Qo" (pc->aux_tail)
214         : "r" (&pc->aux_tail), "r" (tail)
215         );
216 
217         return 0;
218 }
219 #endif
220 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php