File Index
Files and directories
Sign in
FILE

header.c

File preview with syntax highlighting.

linux-6.19.14/tools/perf/arch/arm64/util/header.c 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 19
 14#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 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
 44int 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
 65char *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 */
 91int 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}
~/ Read-only file preview.