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