1#include <stdio.h>
2#include <stdlib.h>
3#include <perf/cpumap.h>
4#include <util/cpumap.h>
5#include <internal/cpumap.h>
6#include <api/fs/fs.h>
7#include <errno.h>
8#include "debug.h"
9#include "header.h"
10
11#define MIDR "/regs/identification/midr_el1"
12#define MIDR_SIZE 19
13#define MIDR_REVISION_MASK      0xf
14#define MIDR_VARIANT_SHIFT      20
15#define MIDR_VARIANT_MASK       (0xf << MIDR_VARIANT_SHIFT)
16
17static int _get_cpuid(char *buf, size_t sz, struct perf_cpu_map *cpus)
18{
19	const char *sysfs = sysfs__mountpoint();
20	u64 midr = 0;
21	int cpu;
22
23	if (!sysfs || sz < MIDR_SIZE)
24		return EINVAL;
25
26	cpus = perf_cpu_map__get(cpus);
27
28	for (cpu = 0; cpu < perf_cpu_map__nr(cpus); cpu++) {
29		char path[PATH_MAX];
30		FILE *file;
31
32		scnprintf(path, PATH_MAX, "%s/devices/system/cpu/cpu%d"MIDR,
33				sysfs, cpus->map[cpu]);
34
35		file = fopen(path, "r");
36		if (!file) {
37			pr_debug("fopen failed for file %s\n", path);
38			continue;
39		}
40
41		if (!fgets(buf, MIDR_SIZE, file)) {
42			fclose(file);
43			continue;
44		}
45		fclose(file);
46
47		/* Ignore/clear Variant[23:20] and
48		 * Revision[3:0] of MIDR
49		 */
50		midr = strtoul(buf, NULL, 16);
51		midr &= (~(MIDR_VARIANT_MASK | MIDR_REVISION_MASK));
52		scnprintf(buf, MIDR_SIZE, "0x%016lx", midr);
53		/* got midr break loop */
54		break;
55	}
56
57	perf_cpu_map__put(cpus);
58
59	if (!midr)
60		return EINVAL;
61
62	return 0;
63}
64
65int get_cpuid(char *buf, size_t sz)
66{
67	struct perf_cpu_map *cpus = perf_cpu_map__new(NULL);
68	int ret;
69
70	if (!cpus)
71		return EINVAL;
72
73	ret = _get_cpuid(buf, sz, cpus);
74
75	perf_cpu_map__put(cpus);
76
77	return ret;
78}
79
80char *get_cpuid_str(struct perf_pmu *pmu)
81{
82	char *buf = NULL;
83	int res;
84
85	if (!pmu || !pmu->cpus)
86		return NULL;
87
88	buf = malloc(MIDR_SIZE);
89	if (!buf)
90		return NULL;
91
92	/* read midr from list of cpus mapped to this pmu */
93	res = _get_cpuid(buf, MIDR_SIZE, pmu->cpus);
94	if (res) {
95		pr_err("failed to get cpuid string for PMU %s\n", pmu->name);
96		free(buf);
97		buf = NULL;
98	}
99
100	return buf;
101}
102