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