OSDN Git Service

Merge tag 'perf-urgent-2023-09-10' of git://git.kernel.org/pub/scm/linux/kernel/git...
[tomoyo/tomoyo-test1.git] / tools / perf / arch / arm64 / util / header.c
1 #include <linux/kernel.h>
2 #include <linux/bits.h>
3 #include <linux/bitfield.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <perf/cpumap.h>
7 #include <util/cpumap.h>
8 #include <internal/cpumap.h>
9 #include <api/fs/fs.h>
10 #include <errno.h>
11 #include "debug.h"
12 #include "header.h"
13
14 #define MIDR "/regs/identification/midr_el1"
15 #define MIDR_SIZE 19
16 #define MIDR_REVISION_MASK      GENMASK(3, 0)
17 #define MIDR_VARIANT_MASK       GENMASK(23, 20)
18
19 static int _get_cpuid(char *buf, size_t sz, struct perf_cpu_map *cpus)
20 {
21         const char *sysfs = sysfs__mountpoint();
22         int cpu;
23         int ret = EINVAL;
24
25         if (!sysfs || sz < MIDR_SIZE)
26                 return EINVAL;
27
28         cpus = perf_cpu_map__get(cpus);
29
30         for (cpu = 0; cpu < perf_cpu_map__nr(cpus); cpu++) {
31                 char path[PATH_MAX];
32                 FILE *file;
33
34                 scnprintf(path, PATH_MAX, "%s/devices/system/cpu/cpu%d" MIDR,
35                           sysfs, RC_CHK_ACCESS(cpus)->map[cpu].cpu);
36
37                 file = fopen(path, "r");
38                 if (!file) {
39                         pr_debug("fopen failed for file %s\n", path);
40                         continue;
41                 }
42
43                 if (!fgets(buf, MIDR_SIZE, file)) {
44                         fclose(file);
45                         continue;
46                 }
47                 fclose(file);
48
49                 /* got midr break loop */
50                 ret = 0;
51                 break;
52         }
53
54         perf_cpu_map__put(cpus);
55         return ret;
56 }
57
58 int get_cpuid(char *buf, size_t sz)
59 {
60         struct perf_cpu_map *cpus = perf_cpu_map__new(NULL);
61         int ret;
62
63         if (!cpus)
64                 return EINVAL;
65
66         ret = _get_cpuid(buf, sz, cpus);
67
68         perf_cpu_map__put(cpus);
69
70         return ret;
71 }
72
73 char *get_cpuid_str(struct perf_pmu *pmu)
74 {
75         char *buf = NULL;
76         int res;
77
78         if (!pmu || !pmu->cpus)
79                 return NULL;
80
81         buf = malloc(MIDR_SIZE);
82         if (!buf)
83                 return NULL;
84
85         /* read midr from list of cpus mapped to this pmu */
86         res = _get_cpuid(buf, MIDR_SIZE, pmu->cpus);
87         if (res) {
88                 pr_err("failed to get cpuid string for PMU %s\n", pmu->name);
89                 free(buf);
90                 buf = NULL;
91         }
92
93         return buf;
94 }
95
96 /*
97  * Return 0 if idstr is a higher or equal to version of the same part as
98  * mapcpuid. Therefore, if mapcpuid has 0 for revision and variant then any
99  * version of idstr will match as long as it's the same CPU type.
100  *
101  * Return 1 if the CPU type is different or the version of idstr is lower.
102  */
103 int strcmp_cpuid_str(const char *mapcpuid, const char *idstr)
104 {
105         u64 map_id = strtoull(mapcpuid, NULL, 16);
106         char map_id_variant = FIELD_GET(MIDR_VARIANT_MASK, map_id);
107         char map_id_revision = FIELD_GET(MIDR_REVISION_MASK, map_id);
108         u64 id = strtoull(idstr, NULL, 16);
109         char id_variant = FIELD_GET(MIDR_VARIANT_MASK, id);
110         char id_revision = FIELD_GET(MIDR_REVISION_MASK, id);
111         u64 id_fields = ~(MIDR_VARIANT_MASK | MIDR_REVISION_MASK);
112
113         /* Compare without version first */
114         if ((map_id & id_fields) != (id & id_fields))
115                 return 1;
116
117         /*
118          * ID matches, now compare version.
119          *
120          * Arm revisions (like r0p0) are compared here like two digit semver
121          * values eg. 1.3 < 2.0 < 2.1 < 2.2.
122          *
123          *  r = high value = 'Variant' field in MIDR
124          *  p = low value  = 'Revision' field in MIDR
125          *
126          */
127         if (id_variant > map_id_variant)
128                 return 0;
129
130         if (id_variant == map_id_variant && id_revision >= map_id_revision)
131                 return 0;
132
133         /*
134          * variant is less than mapfile variant or variants are the same but
135          * the revision doesn't match. Return no match.
136          */
137         return 1;
138 }