brintos

brintos / linux-shallow public Read only

0
0
Text · 2.9 KiB · 741df36 Raw
134 lines · c
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 1914#define MIDR_REVISION_MASK      GENMASK(3, 0)15#define MIDR_VARIANT_MASK	GENMASK(23, 20)16 17static int _get_cpuid(char *buf, size_t sz, struct perf_cpu_map *cpus)18{19	const char *sysfs = sysfs__mountpoint();20	struct perf_cpu cpu;21	int idx, ret = EINVAL;22 23	if (!sysfs || sz < MIDR_SIZE)24		return EINVAL;25 26	perf_cpu_map__for_each_cpu(cpu, idx, cpus) {27		char path[PATH_MAX];28		FILE *file;29 30		scnprintf(path, PATH_MAX, "%s/devices/system/cpu/cpu%d" MIDR,31			  sysfs, cpu.cpu);32 33		file = fopen(path, "r");34		if (!file) {35			pr_debug("fopen failed for file %s\n", path);36			continue;37		}38 39		if (!fgets(buf, MIDR_SIZE, file)) {40			fclose(file);41			continue;42		}43		fclose(file);44 45		/* got midr break loop */46		ret = 0;47		break;48	}49 50	return ret;51}52 53int get_cpuid(char *buf, size_t sz)54{55	struct perf_cpu_map *cpus = perf_cpu_map__new_online_cpus();56	int ret;57 58	if (!cpus)59		return EINVAL;60 61	ret = _get_cpuid(buf, sz, cpus);62 63	perf_cpu_map__put(cpus);64 65	return ret;66}67 68char *get_cpuid_str(struct perf_pmu *pmu)69{70	char *buf = NULL;71	int res;72 73	if (!pmu || !pmu->cpus)74		return NULL;75 76	buf = malloc(MIDR_SIZE);77	if (!buf)78		return NULL;79 80	/* read midr from list of cpus mapped to this pmu */81	res = _get_cpuid(buf, MIDR_SIZE, pmu->cpus);82	if (res) {83		pr_err("failed to get cpuid string for PMU %s\n", pmu->name);84		free(buf);85		buf = NULL;86	}87 88	return buf;89}90 91/*92 * Return 0 if idstr is a higher or equal to version of the same part as93 * mapcpuid. Therefore, if mapcpuid has 0 for revision and variant then any94 * version of idstr will match as long as it's the same CPU type.95 *96 * Return 1 if the CPU type is different or the version of idstr is lower.97 */98int strcmp_cpuid_str(const char *mapcpuid, const char *idstr)99{100	u64 map_id = strtoull(mapcpuid, NULL, 16);101	char map_id_variant = FIELD_GET(MIDR_VARIANT_MASK, map_id);102	char map_id_revision = FIELD_GET(MIDR_REVISION_MASK, map_id);103	u64 id = strtoull(idstr, NULL, 16);104	char id_variant = FIELD_GET(MIDR_VARIANT_MASK, id);105	char id_revision = FIELD_GET(MIDR_REVISION_MASK, id);106	u64 id_fields = ~(MIDR_VARIANT_MASK | MIDR_REVISION_MASK);107 108	/* Compare without version first */109	if ((map_id & id_fields) != (id & id_fields))110		return 1;111 112	/*113	 * ID matches, now compare version.114	 *115	 * Arm revisions (like r0p0) are compared here like two digit semver116	 * values eg. 1.3 < 2.0 < 2.1 < 2.2.117	 *118	 *  r = high value = 'Variant' field in MIDR119	 *  p = low value  = 'Revision' field in MIDR120	 *121	 */122	if (id_variant > map_id_variant)123		return 0;124 125	if (id_variant == map_id_variant && id_revision >= map_id_revision)126		return 0;127 128	/*129	 * variant is less than mapfile variant or variants are the same but130	 * the revision doesn't match. Return no match.131	 */132	return 1;133}134