1 #include <linux/kernel.h>
2 #include <linux/bits.h>
3 #include <linux/bitfield.h>
6 #include <perf/cpumap.h>
7 #include <util/cpumap.h>
8 #include <internal/cpumap.h>
14 #define MIDR "/regs/identification/midr_el1"
16 #define MIDR_REVISION_MASK GENMASK(3, 0)
17 #define MIDR_VARIANT_MASK GENMASK(23, 20)
19 static int _get_cpuid(char *buf, size_t sz, struct perf_cpu_map *cpus)
21 const char *sysfs = sysfs__mountpoint();
25 if (!sysfs || sz < MIDR_SIZE)
28 cpus = perf_cpu_map__get(cpus);
30 for (cpu = 0; cpu < perf_cpu_map__nr(cpus); cpu++) {
34 scnprintf(path, PATH_MAX, "%s/devices/system/cpu/cpu%d" MIDR,
35 sysfs, RC_CHK_ACCESS(cpus)->map[cpu].cpu);
37 file = fopen(path, "r");
39 pr_debug("fopen failed for file %s\n", path);
43 if (!fgets(buf, MIDR_SIZE, file)) {
49 /* got midr break loop */
54 perf_cpu_map__put(cpus);
58 int get_cpuid(char *buf, size_t sz)
60 struct perf_cpu_map *cpus = perf_cpu_map__new(NULL);
66 ret = _get_cpuid(buf, sz, cpus);
68 perf_cpu_map__put(cpus);
73 char *get_cpuid_str(struct perf_pmu *pmu)
78 if (!pmu || !pmu->cpus)
81 buf = malloc(MIDR_SIZE);
85 /* read midr from list of cpus mapped to this pmu */
86 res = _get_cpuid(buf, MIDR_SIZE, pmu->cpus);
88 pr_err("failed to get cpuid string for PMU %s\n", pmu->name);
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.
101 * Return 1 if the CPU type is different or the version of idstr is lower.
103 int strcmp_cpuid_str(const char *mapcpuid, const char *idstr)
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);
113 /* Compare without version first */
114 if ((map_id & id_fields) != (id & id_fields))
118 * ID matches, now compare version.
120 * Arm revisions (like r0p0) are compared here like two digit semver
121 * values eg. 1.3 < 2.0 < 2.1 < 2.2.
123 * r = high value = 'Variant' field in MIDR
124 * p = low value = 'Revision' field in MIDR
127 if (id_variant > map_id_variant)
130 if (id_variant == map_id_variant && id_revision >= map_id_revision)
134 * variant is less than mapfile variant or variants are the same but
135 * the revision doesn't match. Return no match.