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