18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/list.h>
38c2ecf20Sopenharmony_ci#include <linux/compiler.h>
48c2ecf20Sopenharmony_ci#include <linux/string.h>
58c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
68c2ecf20Sopenharmony_ci#include <subcmd/pager.h>
78c2ecf20Sopenharmony_ci#include <sys/types.h>
88c2ecf20Sopenharmony_ci#include <errno.h>
98c2ecf20Sopenharmony_ci#include <fcntl.h>
108c2ecf20Sopenharmony_ci#include <sys/stat.h>
118c2ecf20Sopenharmony_ci#include <unistd.h>
128c2ecf20Sopenharmony_ci#include <stdio.h>
138c2ecf20Sopenharmony_ci#include <stdbool.h>
148c2ecf20Sopenharmony_ci#include <stdarg.h>
158c2ecf20Sopenharmony_ci#include <dirent.h>
168c2ecf20Sopenharmony_ci#include <api/fs/fs.h>
178c2ecf20Sopenharmony_ci#include <locale.h>
188c2ecf20Sopenharmony_ci#include <regex.h>
198c2ecf20Sopenharmony_ci#include <perf/cpumap.h>
208c2ecf20Sopenharmony_ci#include "debug.h"
218c2ecf20Sopenharmony_ci#include "evsel.h"
228c2ecf20Sopenharmony_ci#include "pmu.h"
238c2ecf20Sopenharmony_ci#include "parse-events.h"
248c2ecf20Sopenharmony_ci#include "header.h"
258c2ecf20Sopenharmony_ci#include "string2.h"
268c2ecf20Sopenharmony_ci#include "strbuf.h"
278c2ecf20Sopenharmony_ci#include "fncache.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistruct perf_pmu perf_pmu__fake;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistruct perf_pmu_format {
328c2ecf20Sopenharmony_ci	char *name;
338c2ecf20Sopenharmony_ci	int value;
348c2ecf20Sopenharmony_ci	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
358c2ecf20Sopenharmony_ci	struct list_head list;
368c2ecf20Sopenharmony_ci};
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ciint perf_pmu_parse(struct list_head *list, char *name);
398c2ecf20Sopenharmony_ciextern FILE *perf_pmu_in;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic LIST_HEAD(pmus);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/*
448c2ecf20Sopenharmony_ci * Parse & process all the sysfs attributes located under
458c2ecf20Sopenharmony_ci * the directory specified in 'dir' parameter.
468c2ecf20Sopenharmony_ci */
478c2ecf20Sopenharmony_ciint perf_pmu__format_parse(char *dir, struct list_head *head)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	struct dirent *evt_ent;
508c2ecf20Sopenharmony_ci	DIR *format_dir;
518c2ecf20Sopenharmony_ci	int ret = 0;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	format_dir = opendir(dir);
548c2ecf20Sopenharmony_ci	if (!format_dir)
558c2ecf20Sopenharmony_ci		return -EINVAL;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	while (!ret && (evt_ent = readdir(format_dir))) {
588c2ecf20Sopenharmony_ci		char path[PATH_MAX];
598c2ecf20Sopenharmony_ci		char *name = evt_ent->d_name;
608c2ecf20Sopenharmony_ci		FILE *file;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci		if (!strcmp(name, ".") || !strcmp(name, ".."))
638c2ecf20Sopenharmony_ci			continue;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci		snprintf(path, PATH_MAX, "%s/%s", dir, name);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci		ret = -EINVAL;
688c2ecf20Sopenharmony_ci		file = fopen(path, "r");
698c2ecf20Sopenharmony_ci		if (!file)
708c2ecf20Sopenharmony_ci			break;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci		perf_pmu_in = file;
738c2ecf20Sopenharmony_ci		ret = perf_pmu_parse(head, name);
748c2ecf20Sopenharmony_ci		fclose(file);
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	closedir(format_dir);
788c2ecf20Sopenharmony_ci	return ret;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/*
828c2ecf20Sopenharmony_ci * Reading/parsing the default pmu format definition, which should be
838c2ecf20Sopenharmony_ci * located at:
848c2ecf20Sopenharmony_ci * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
858c2ecf20Sopenharmony_ci */
868c2ecf20Sopenharmony_cistatic int pmu_format(const char *name, struct list_head *format)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	char path[PATH_MAX];
898c2ecf20Sopenharmony_ci	const char *sysfs = sysfs__mountpoint();
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (!sysfs)
928c2ecf20Sopenharmony_ci		return -1;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	snprintf(path, PATH_MAX,
958c2ecf20Sopenharmony_ci		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	if (!file_available(path))
988c2ecf20Sopenharmony_ci		return 0;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	if (perf_pmu__format_parse(path, format))
1018c2ecf20Sopenharmony_ci		return -1;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return 0;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ciint perf_pmu__convert_scale(const char *scale, char **end, double *sval)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	char *lc;
1098c2ecf20Sopenharmony_ci	int ret = 0;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/*
1128c2ecf20Sopenharmony_ci	 * save current locale
1138c2ecf20Sopenharmony_ci	 */
1148c2ecf20Sopenharmony_ci	lc = setlocale(LC_NUMERIC, NULL);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	/*
1178c2ecf20Sopenharmony_ci	 * The lc string may be allocated in static storage,
1188c2ecf20Sopenharmony_ci	 * so get a dynamic copy to make it survive setlocale
1198c2ecf20Sopenharmony_ci	 * call below.
1208c2ecf20Sopenharmony_ci	 */
1218c2ecf20Sopenharmony_ci	lc = strdup(lc);
1228c2ecf20Sopenharmony_ci	if (!lc) {
1238c2ecf20Sopenharmony_ci		ret = -ENOMEM;
1248c2ecf20Sopenharmony_ci		goto out;
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	/*
1288c2ecf20Sopenharmony_ci	 * force to C locale to ensure kernel
1298c2ecf20Sopenharmony_ci	 * scale string is converted correctly.
1308c2ecf20Sopenharmony_ci	 * kernel uses default C locale.
1318c2ecf20Sopenharmony_ci	 */
1328c2ecf20Sopenharmony_ci	setlocale(LC_NUMERIC, "C");
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	*sval = strtod(scale, end);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ciout:
1378c2ecf20Sopenharmony_ci	/* restore locale */
1388c2ecf20Sopenharmony_ci	setlocale(LC_NUMERIC, lc);
1398c2ecf20Sopenharmony_ci	free(lc);
1408c2ecf20Sopenharmony_ci	return ret;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	struct stat st;
1468c2ecf20Sopenharmony_ci	ssize_t sret;
1478c2ecf20Sopenharmony_ci	char scale[128];
1488c2ecf20Sopenharmony_ci	int fd, ret = -1;
1498c2ecf20Sopenharmony_ci	char path[PATH_MAX];
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	scnprintf(path, PATH_MAX, "%s/%s.scale", dir, name);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	fd = open(path, O_RDONLY);
1548c2ecf20Sopenharmony_ci	if (fd == -1)
1558c2ecf20Sopenharmony_ci		return -1;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (fstat(fd, &st) < 0)
1588c2ecf20Sopenharmony_ci		goto error;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	sret = read(fd, scale, sizeof(scale)-1);
1618c2ecf20Sopenharmony_ci	if (sret < 0)
1628c2ecf20Sopenharmony_ci		goto error;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	if (scale[sret - 1] == '\n')
1658c2ecf20Sopenharmony_ci		scale[sret - 1] = '\0';
1668c2ecf20Sopenharmony_ci	else
1678c2ecf20Sopenharmony_ci		scale[sret] = '\0';
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	ret = perf_pmu__convert_scale(scale, NULL, &alias->scale);
1708c2ecf20Sopenharmony_cierror:
1718c2ecf20Sopenharmony_ci	close(fd);
1728c2ecf20Sopenharmony_ci	return ret;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	char path[PATH_MAX];
1788c2ecf20Sopenharmony_ci	ssize_t sret;
1798c2ecf20Sopenharmony_ci	int fd;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	scnprintf(path, PATH_MAX, "%s/%s.unit", dir, name);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	fd = open(path, O_RDONLY);
1848c2ecf20Sopenharmony_ci	if (fd == -1)
1858c2ecf20Sopenharmony_ci		return -1;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	sret = read(fd, alias->unit, UNIT_MAX_LEN);
1888c2ecf20Sopenharmony_ci	if (sret < 0)
1898c2ecf20Sopenharmony_ci		goto error;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	close(fd);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	if (alias->unit[sret - 1] == '\n')
1948c2ecf20Sopenharmony_ci		alias->unit[sret - 1] = '\0';
1958c2ecf20Sopenharmony_ci	else
1968c2ecf20Sopenharmony_ci		alias->unit[sret] = '\0';
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	return 0;
1998c2ecf20Sopenharmony_cierror:
2008c2ecf20Sopenharmony_ci	close(fd);
2018c2ecf20Sopenharmony_ci	alias->unit[0] = '\0';
2028c2ecf20Sopenharmony_ci	return -1;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic int
2068c2ecf20Sopenharmony_ciperf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	char path[PATH_MAX];
2098c2ecf20Sopenharmony_ci	int fd;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	scnprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	fd = open(path, O_RDONLY);
2148c2ecf20Sopenharmony_ci	if (fd == -1)
2158c2ecf20Sopenharmony_ci		return -1;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	close(fd);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	alias->per_pkg = true;
2208c2ecf20Sopenharmony_ci	return 0;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
2248c2ecf20Sopenharmony_ci				    char *dir, char *name)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	char path[PATH_MAX];
2278c2ecf20Sopenharmony_ci	int fd;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	scnprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	fd = open(path, O_RDONLY);
2328c2ecf20Sopenharmony_ci	if (fd == -1)
2338c2ecf20Sopenharmony_ci		return -1;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	alias->snapshot = true;
2368c2ecf20Sopenharmony_ci	close(fd);
2378c2ecf20Sopenharmony_ci	return 0;
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic void perf_pmu_assign_str(char *name, const char *field, char **old_str,
2418c2ecf20Sopenharmony_ci				char **new_str)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	if (!*old_str)
2448c2ecf20Sopenharmony_ci		goto set_new;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (*new_str) {	/* Have new string, check with old */
2478c2ecf20Sopenharmony_ci		if (strcasecmp(*old_str, *new_str))
2488c2ecf20Sopenharmony_ci			pr_debug("alias %s differs in field '%s'\n",
2498c2ecf20Sopenharmony_ci				 name, field);
2508c2ecf20Sopenharmony_ci		zfree(old_str);
2518c2ecf20Sopenharmony_ci	} else		/* Nothing new --> keep old string */
2528c2ecf20Sopenharmony_ci		return;
2538c2ecf20Sopenharmony_ciset_new:
2548c2ecf20Sopenharmony_ci	*old_str = *new_str;
2558c2ecf20Sopenharmony_ci	*new_str = NULL;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic void perf_pmu_update_alias(struct perf_pmu_alias *old,
2598c2ecf20Sopenharmony_ci				  struct perf_pmu_alias *newalias)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc);
2628c2ecf20Sopenharmony_ci	perf_pmu_assign_str(old->name, "long_desc", &old->long_desc,
2638c2ecf20Sopenharmony_ci			    &newalias->long_desc);
2648c2ecf20Sopenharmony_ci	perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic);
2658c2ecf20Sopenharmony_ci	perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr,
2668c2ecf20Sopenharmony_ci			    &newalias->metric_expr);
2678c2ecf20Sopenharmony_ci	perf_pmu_assign_str(old->name, "metric_name", &old->metric_name,
2688c2ecf20Sopenharmony_ci			    &newalias->metric_name);
2698c2ecf20Sopenharmony_ci	perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str);
2708c2ecf20Sopenharmony_ci	old->scale = newalias->scale;
2718c2ecf20Sopenharmony_ci	old->per_pkg = newalias->per_pkg;
2728c2ecf20Sopenharmony_ci	old->snapshot = newalias->snapshot;
2738c2ecf20Sopenharmony_ci	memcpy(old->unit, newalias->unit, sizeof(old->unit));
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci/* Delete an alias entry. */
2778c2ecf20Sopenharmony_civoid perf_pmu_free_alias(struct perf_pmu_alias *newalias)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	zfree(&newalias->name);
2808c2ecf20Sopenharmony_ci	zfree(&newalias->desc);
2818c2ecf20Sopenharmony_ci	zfree(&newalias->long_desc);
2828c2ecf20Sopenharmony_ci	zfree(&newalias->topic);
2838c2ecf20Sopenharmony_ci	zfree(&newalias->str);
2848c2ecf20Sopenharmony_ci	zfree(&newalias->metric_expr);
2858c2ecf20Sopenharmony_ci	zfree(&newalias->metric_name);
2868c2ecf20Sopenharmony_ci	parse_events_terms__purge(&newalias->terms);
2878c2ecf20Sopenharmony_ci	free(newalias);
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci/* Merge an alias, search in alias list. If this name is already
2918c2ecf20Sopenharmony_ci * present merge both of them to combine all information.
2928c2ecf20Sopenharmony_ci */
2938c2ecf20Sopenharmony_cistatic bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias,
2948c2ecf20Sopenharmony_ci				 struct list_head *alist)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	struct perf_pmu_alias *a;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	list_for_each_entry(a, alist, list) {
2998c2ecf20Sopenharmony_ci		if (!strcasecmp(newalias->name, a->name)) {
3008c2ecf20Sopenharmony_ci			perf_pmu_update_alias(a, newalias);
3018c2ecf20Sopenharmony_ci			perf_pmu_free_alias(newalias);
3028c2ecf20Sopenharmony_ci			return true;
3038c2ecf20Sopenharmony_ci		}
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ci	return false;
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
3098c2ecf20Sopenharmony_ci				 char *desc, char *val,
3108c2ecf20Sopenharmony_ci				 char *long_desc, char *topic,
3118c2ecf20Sopenharmony_ci				 char *unit, char *perpkg,
3128c2ecf20Sopenharmony_ci				 char *metric_expr,
3138c2ecf20Sopenharmony_ci				 char *metric_name,
3148c2ecf20Sopenharmony_ci				 char *deprecated)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	struct parse_events_term *term;
3178c2ecf20Sopenharmony_ci	struct perf_pmu_alias *alias;
3188c2ecf20Sopenharmony_ci	int ret;
3198c2ecf20Sopenharmony_ci	int num;
3208c2ecf20Sopenharmony_ci	char newval[256];
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	alias = malloc(sizeof(*alias));
3238c2ecf20Sopenharmony_ci	if (!alias)
3248c2ecf20Sopenharmony_ci		return -ENOMEM;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&alias->terms);
3278c2ecf20Sopenharmony_ci	alias->scale = 1.0;
3288c2ecf20Sopenharmony_ci	alias->unit[0] = '\0';
3298c2ecf20Sopenharmony_ci	alias->per_pkg = false;
3308c2ecf20Sopenharmony_ci	alias->snapshot = false;
3318c2ecf20Sopenharmony_ci	alias->deprecated = false;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	ret = parse_events_terms(&alias->terms, val);
3348c2ecf20Sopenharmony_ci	if (ret) {
3358c2ecf20Sopenharmony_ci		pr_err("Cannot parse alias %s: %d\n", val, ret);
3368c2ecf20Sopenharmony_ci		free(alias);
3378c2ecf20Sopenharmony_ci		return ret;
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	/* Scan event and remove leading zeroes, spaces, newlines, some
3418c2ecf20Sopenharmony_ci	 * platforms have terms specified as
3428c2ecf20Sopenharmony_ci	 * event=0x0091 (read from files ../<PMU>/events/<FILE>
3438c2ecf20Sopenharmony_ci	 * and terms specified as event=0x91 (read from JSON files).
3448c2ecf20Sopenharmony_ci	 *
3458c2ecf20Sopenharmony_ci	 * Rebuild string to make alias->str member comparable.
3468c2ecf20Sopenharmony_ci	 */
3478c2ecf20Sopenharmony_ci	memset(newval, 0, sizeof(newval));
3488c2ecf20Sopenharmony_ci	ret = 0;
3498c2ecf20Sopenharmony_ci	list_for_each_entry(term, &alias->terms, list) {
3508c2ecf20Sopenharmony_ci		if (ret)
3518c2ecf20Sopenharmony_ci			ret += scnprintf(newval + ret, sizeof(newval) - ret,
3528c2ecf20Sopenharmony_ci					 ",");
3538c2ecf20Sopenharmony_ci		if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM)
3548c2ecf20Sopenharmony_ci			ret += scnprintf(newval + ret, sizeof(newval) - ret,
3558c2ecf20Sopenharmony_ci					 "%s=%#x", term->config, term->val.num);
3568c2ecf20Sopenharmony_ci		else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
3578c2ecf20Sopenharmony_ci			ret += scnprintf(newval + ret, sizeof(newval) - ret,
3588c2ecf20Sopenharmony_ci					 "%s=%s", term->config, term->val.str);
3598c2ecf20Sopenharmony_ci	}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	alias->name = strdup(name);
3628c2ecf20Sopenharmony_ci	if (dir) {
3638c2ecf20Sopenharmony_ci		/*
3648c2ecf20Sopenharmony_ci		 * load unit name and scale if available
3658c2ecf20Sopenharmony_ci		 */
3668c2ecf20Sopenharmony_ci		perf_pmu__parse_unit(alias, dir, name);
3678c2ecf20Sopenharmony_ci		perf_pmu__parse_scale(alias, dir, name);
3688c2ecf20Sopenharmony_ci		perf_pmu__parse_per_pkg(alias, dir, name);
3698c2ecf20Sopenharmony_ci		perf_pmu__parse_snapshot(alias, dir, name);
3708c2ecf20Sopenharmony_ci	}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL;
3738c2ecf20Sopenharmony_ci	alias->metric_name = metric_name ? strdup(metric_name): NULL;
3748c2ecf20Sopenharmony_ci	alias->desc = desc ? strdup(desc) : NULL;
3758c2ecf20Sopenharmony_ci	alias->long_desc = long_desc ? strdup(long_desc) :
3768c2ecf20Sopenharmony_ci				desc ? strdup(desc) : NULL;
3778c2ecf20Sopenharmony_ci	alias->topic = topic ? strdup(topic) : NULL;
3788c2ecf20Sopenharmony_ci	if (unit) {
3798c2ecf20Sopenharmony_ci		if (perf_pmu__convert_scale(unit, &unit, &alias->scale) < 0)
3808c2ecf20Sopenharmony_ci			return -1;
3818c2ecf20Sopenharmony_ci		snprintf(alias->unit, sizeof(alias->unit), "%s", unit);
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci	alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1;
3848c2ecf20Sopenharmony_ci	alias->str = strdup(newval);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	if (deprecated)
3878c2ecf20Sopenharmony_ci		alias->deprecated = true;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (!perf_pmu_merge_alias(alias, list))
3908c2ecf20Sopenharmony_ci		list_add_tail(&alias->list, list);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	return 0;
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	char buf[256];
3988c2ecf20Sopenharmony_ci	int ret;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	ret = fread(buf, 1, sizeof(buf), file);
4018c2ecf20Sopenharmony_ci	if (ret == 0)
4028c2ecf20Sopenharmony_ci		return -EINVAL;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	buf[ret] = 0;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	/* Remove trailing newline from sysfs file */
4078c2ecf20Sopenharmony_ci	strim(buf);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL,
4108c2ecf20Sopenharmony_ci				     NULL, NULL, NULL, NULL);
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic inline bool pmu_alias_info_file(char *name)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	size_t len;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	len = strlen(name);
4188c2ecf20Sopenharmony_ci	if (len > 5 && !strcmp(name + len - 5, ".unit"))
4198c2ecf20Sopenharmony_ci		return true;
4208c2ecf20Sopenharmony_ci	if (len > 6 && !strcmp(name + len - 6, ".scale"))
4218c2ecf20Sopenharmony_ci		return true;
4228c2ecf20Sopenharmony_ci	if (len > 8 && !strcmp(name + len - 8, ".per-pkg"))
4238c2ecf20Sopenharmony_ci		return true;
4248c2ecf20Sopenharmony_ci	if (len > 9 && !strcmp(name + len - 9, ".snapshot"))
4258c2ecf20Sopenharmony_ci		return true;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	return false;
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci/*
4318c2ecf20Sopenharmony_ci * Process all the sysfs attributes located under the directory
4328c2ecf20Sopenharmony_ci * specified in 'dir' parameter.
4338c2ecf20Sopenharmony_ci */
4348c2ecf20Sopenharmony_cistatic int pmu_aliases_parse(char *dir, struct list_head *head)
4358c2ecf20Sopenharmony_ci{
4368c2ecf20Sopenharmony_ci	struct dirent *evt_ent;
4378c2ecf20Sopenharmony_ci	DIR *event_dir;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	event_dir = opendir(dir);
4408c2ecf20Sopenharmony_ci	if (!event_dir)
4418c2ecf20Sopenharmony_ci		return -EINVAL;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	while ((evt_ent = readdir(event_dir))) {
4448c2ecf20Sopenharmony_ci		char path[PATH_MAX];
4458c2ecf20Sopenharmony_ci		char *name = evt_ent->d_name;
4468c2ecf20Sopenharmony_ci		FILE *file;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci		if (!strcmp(name, ".") || !strcmp(name, ".."))
4498c2ecf20Sopenharmony_ci			continue;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci		/*
4528c2ecf20Sopenharmony_ci		 * skip info files parsed in perf_pmu__new_alias()
4538c2ecf20Sopenharmony_ci		 */
4548c2ecf20Sopenharmony_ci		if (pmu_alias_info_file(name))
4558c2ecf20Sopenharmony_ci			continue;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci		scnprintf(path, PATH_MAX, "%s/%s", dir, name);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci		file = fopen(path, "r");
4608c2ecf20Sopenharmony_ci		if (!file) {
4618c2ecf20Sopenharmony_ci			pr_debug("Cannot open %s\n", path);
4628c2ecf20Sopenharmony_ci			continue;
4638c2ecf20Sopenharmony_ci		}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci		if (perf_pmu__new_alias(head, dir, name, file) < 0)
4668c2ecf20Sopenharmony_ci			pr_debug("Cannot set up %s\n", name);
4678c2ecf20Sopenharmony_ci		fclose(file);
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	closedir(event_dir);
4718c2ecf20Sopenharmony_ci	return 0;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci/*
4758c2ecf20Sopenharmony_ci * Reading the pmu event aliases definition, which should be located at:
4768c2ecf20Sopenharmony_ci * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
4778c2ecf20Sopenharmony_ci */
4788c2ecf20Sopenharmony_cistatic int pmu_aliases(const char *name, struct list_head *head)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	char path[PATH_MAX];
4818c2ecf20Sopenharmony_ci	const char *sysfs = sysfs__mountpoint();
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	if (!sysfs)
4848c2ecf20Sopenharmony_ci		return -1;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	snprintf(path, PATH_MAX,
4878c2ecf20Sopenharmony_ci		 "%s/bus/event_source/devices/%s/events", sysfs, name);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	if (!file_available(path))
4908c2ecf20Sopenharmony_ci		return 0;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	if (pmu_aliases_parse(path, head))
4938c2ecf20Sopenharmony_ci		return -1;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	return 0;
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_cistatic int pmu_alias_terms(struct perf_pmu_alias *alias,
4998c2ecf20Sopenharmony_ci			   struct list_head *terms)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	struct parse_events_term *term, *cloned;
5028c2ecf20Sopenharmony_ci	LIST_HEAD(list);
5038c2ecf20Sopenharmony_ci	int ret;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	list_for_each_entry(term, &alias->terms, list) {
5068c2ecf20Sopenharmony_ci		ret = parse_events_term__clone(&cloned, term);
5078c2ecf20Sopenharmony_ci		if (ret) {
5088c2ecf20Sopenharmony_ci			parse_events_terms__purge(&list);
5098c2ecf20Sopenharmony_ci			return ret;
5108c2ecf20Sopenharmony_ci		}
5118c2ecf20Sopenharmony_ci		/*
5128c2ecf20Sopenharmony_ci		 * Weak terms don't override command line options,
5138c2ecf20Sopenharmony_ci		 * which we don't want for implicit terms in aliases.
5148c2ecf20Sopenharmony_ci		 */
5158c2ecf20Sopenharmony_ci		cloned->weak = true;
5168c2ecf20Sopenharmony_ci		list_add_tail(&cloned->list, &list);
5178c2ecf20Sopenharmony_ci	}
5188c2ecf20Sopenharmony_ci	list_splice(&list, terms);
5198c2ecf20Sopenharmony_ci	return 0;
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci/*
5238c2ecf20Sopenharmony_ci * Reading/parsing the default pmu type value, which should be
5248c2ecf20Sopenharmony_ci * located at:
5258c2ecf20Sopenharmony_ci * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
5268c2ecf20Sopenharmony_ci */
5278c2ecf20Sopenharmony_cistatic int pmu_type(const char *name, __u32 *type)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	char path[PATH_MAX];
5308c2ecf20Sopenharmony_ci	FILE *file;
5318c2ecf20Sopenharmony_ci	int ret = 0;
5328c2ecf20Sopenharmony_ci	const char *sysfs = sysfs__mountpoint();
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	if (!sysfs)
5358c2ecf20Sopenharmony_ci		return -1;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	snprintf(path, PATH_MAX,
5388c2ecf20Sopenharmony_ci		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	if (access(path, R_OK) < 0)
5418c2ecf20Sopenharmony_ci		return -1;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	file = fopen(path, "r");
5448c2ecf20Sopenharmony_ci	if (!file)
5458c2ecf20Sopenharmony_ci		return -EINVAL;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	if (1 != fscanf(file, "%u", type))
5488c2ecf20Sopenharmony_ci		ret = -1;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	fclose(file);
5518c2ecf20Sopenharmony_ci	return ret;
5528c2ecf20Sopenharmony_ci}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci/* Add all pmus in sysfs to pmu list: */
5558c2ecf20Sopenharmony_cistatic void pmu_read_sysfs(void)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	char path[PATH_MAX];
5588c2ecf20Sopenharmony_ci	DIR *dir;
5598c2ecf20Sopenharmony_ci	struct dirent *dent;
5608c2ecf20Sopenharmony_ci	const char *sysfs = sysfs__mountpoint();
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	if (!sysfs)
5638c2ecf20Sopenharmony_ci		return;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	snprintf(path, PATH_MAX,
5668c2ecf20Sopenharmony_ci		 "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	dir = opendir(path);
5698c2ecf20Sopenharmony_ci	if (!dir)
5708c2ecf20Sopenharmony_ci		return;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	while ((dent = readdir(dir))) {
5738c2ecf20Sopenharmony_ci		if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
5748c2ecf20Sopenharmony_ci			continue;
5758c2ecf20Sopenharmony_ci		/* add to static LIST_HEAD(pmus): */
5768c2ecf20Sopenharmony_ci		perf_pmu__find(dent->d_name);
5778c2ecf20Sopenharmony_ci	}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	closedir(dir);
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cistatic struct perf_cpu_map *__pmu_cpumask(const char *path)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci	FILE *file;
5858c2ecf20Sopenharmony_ci	struct perf_cpu_map *cpus;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	file = fopen(path, "r");
5888c2ecf20Sopenharmony_ci	if (!file)
5898c2ecf20Sopenharmony_ci		return NULL;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	cpus = perf_cpu_map__read(file);
5928c2ecf20Sopenharmony_ci	fclose(file);
5938c2ecf20Sopenharmony_ci	return cpus;
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci/*
5978c2ecf20Sopenharmony_ci * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64)
5988c2ecf20Sopenharmony_ci * may have a "cpus" file.
5998c2ecf20Sopenharmony_ci */
6008c2ecf20Sopenharmony_ci#define CPUS_TEMPLATE_UNCORE	"%s/bus/event_source/devices/%s/cpumask"
6018c2ecf20Sopenharmony_ci#define CPUS_TEMPLATE_CPU	"%s/bus/event_source/devices/%s/cpus"
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_cistatic struct perf_cpu_map *pmu_cpumask(const char *name)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	char path[PATH_MAX];
6068c2ecf20Sopenharmony_ci	struct perf_cpu_map *cpus;
6078c2ecf20Sopenharmony_ci	const char *sysfs = sysfs__mountpoint();
6088c2ecf20Sopenharmony_ci	const char *templates[] = {
6098c2ecf20Sopenharmony_ci		CPUS_TEMPLATE_UNCORE,
6108c2ecf20Sopenharmony_ci		CPUS_TEMPLATE_CPU,
6118c2ecf20Sopenharmony_ci		NULL
6128c2ecf20Sopenharmony_ci	};
6138c2ecf20Sopenharmony_ci	const char **template;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	if (!sysfs)
6168c2ecf20Sopenharmony_ci		return NULL;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	for (template = templates; *template; template++) {
6198c2ecf20Sopenharmony_ci		snprintf(path, PATH_MAX, *template, sysfs, name);
6208c2ecf20Sopenharmony_ci		cpus = __pmu_cpumask(path);
6218c2ecf20Sopenharmony_ci		if (cpus)
6228c2ecf20Sopenharmony_ci			return cpus;
6238c2ecf20Sopenharmony_ci	}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	return NULL;
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_cistatic bool pmu_is_uncore(const char *name)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	char path[PATH_MAX];
6318c2ecf20Sopenharmony_ci	const char *sysfs;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	sysfs = sysfs__mountpoint();
6348c2ecf20Sopenharmony_ci	snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name);
6358c2ecf20Sopenharmony_ci	return file_available(path);
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci/*
6398c2ecf20Sopenharmony_ci *  PMU CORE devices have different name other than cpu in sysfs on some
6408c2ecf20Sopenharmony_ci *  platforms.
6418c2ecf20Sopenharmony_ci *  Looking for possible sysfs files to identify the arm core device.
6428c2ecf20Sopenharmony_ci */
6438c2ecf20Sopenharmony_cistatic int is_arm_pmu_core(const char *name)
6448c2ecf20Sopenharmony_ci{
6458c2ecf20Sopenharmony_ci	char path[PATH_MAX];
6468c2ecf20Sopenharmony_ci	const char *sysfs = sysfs__mountpoint();
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	if (!sysfs)
6498c2ecf20Sopenharmony_ci		return 0;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	/* Look for cpu sysfs (specific to arm) */
6528c2ecf20Sopenharmony_ci	scnprintf(path, PATH_MAX, "%s/bus/event_source/devices/%s/cpus",
6538c2ecf20Sopenharmony_ci				sysfs, name);
6548c2ecf20Sopenharmony_ci	return file_available(path);
6558c2ecf20Sopenharmony_ci}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_cistatic char *perf_pmu__getcpuid(struct perf_pmu *pmu)
6588c2ecf20Sopenharmony_ci{
6598c2ecf20Sopenharmony_ci	char *cpuid;
6608c2ecf20Sopenharmony_ci	static bool printed;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	cpuid = getenv("PERF_CPUID");
6638c2ecf20Sopenharmony_ci	if (cpuid)
6648c2ecf20Sopenharmony_ci		cpuid = strdup(cpuid);
6658c2ecf20Sopenharmony_ci	if (!cpuid)
6668c2ecf20Sopenharmony_ci		cpuid = get_cpuid_str(pmu);
6678c2ecf20Sopenharmony_ci	if (!cpuid)
6688c2ecf20Sopenharmony_ci		return NULL;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	if (!printed) {
6718c2ecf20Sopenharmony_ci		pr_debug("Using CPUID %s\n", cpuid);
6728c2ecf20Sopenharmony_ci		printed = true;
6738c2ecf20Sopenharmony_ci	}
6748c2ecf20Sopenharmony_ci	return cpuid;
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_cistruct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
6788c2ecf20Sopenharmony_ci{
6798c2ecf20Sopenharmony_ci	struct pmu_events_map *map;
6808c2ecf20Sopenharmony_ci	char *cpuid = perf_pmu__getcpuid(pmu);
6818c2ecf20Sopenharmony_ci	int i;
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	/* on some platforms which uses cpus map, cpuid can be NULL for
6848c2ecf20Sopenharmony_ci	 * PMUs other than CORE PMUs.
6858c2ecf20Sopenharmony_ci	 */
6868c2ecf20Sopenharmony_ci	if (!cpuid)
6878c2ecf20Sopenharmony_ci		return NULL;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	i = 0;
6908c2ecf20Sopenharmony_ci	for (;;) {
6918c2ecf20Sopenharmony_ci		map = &pmu_events_map[i++];
6928c2ecf20Sopenharmony_ci		if (!map->table) {
6938c2ecf20Sopenharmony_ci			map = NULL;
6948c2ecf20Sopenharmony_ci			break;
6958c2ecf20Sopenharmony_ci		}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci		if (!strcmp_cpuid_str(map->cpuid, cpuid))
6988c2ecf20Sopenharmony_ci			break;
6998c2ecf20Sopenharmony_ci	}
7008c2ecf20Sopenharmony_ci	free(cpuid);
7018c2ecf20Sopenharmony_ci	return map;
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_cibool pmu_uncore_alias_match(const char *pmu_name, const char *name)
7058c2ecf20Sopenharmony_ci{
7068c2ecf20Sopenharmony_ci	char *tmp = NULL, *tok, *str;
7078c2ecf20Sopenharmony_ci	bool res;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	str = strdup(pmu_name);
7108c2ecf20Sopenharmony_ci	if (!str)
7118c2ecf20Sopenharmony_ci		return false;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	/*
7148c2ecf20Sopenharmony_ci	 * uncore alias may be from different PMU with common prefix
7158c2ecf20Sopenharmony_ci	 */
7168c2ecf20Sopenharmony_ci	tok = strtok_r(str, ",", &tmp);
7178c2ecf20Sopenharmony_ci	if (strncmp(pmu_name, tok, strlen(tok))) {
7188c2ecf20Sopenharmony_ci		res = false;
7198c2ecf20Sopenharmony_ci		goto out;
7208c2ecf20Sopenharmony_ci	}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	/*
7238c2ecf20Sopenharmony_ci	 * Match more complex aliases where the alias name is a comma-delimited
7248c2ecf20Sopenharmony_ci	 * list of tokens, orderly contained in the matching PMU name.
7258c2ecf20Sopenharmony_ci	 *
7268c2ecf20Sopenharmony_ci	 * Example: For alias "socket,pmuname" and PMU "socketX_pmunameY", we
7278c2ecf20Sopenharmony_ci	 *	    match "socket" in "socketX_pmunameY" and then "pmuname" in
7288c2ecf20Sopenharmony_ci	 *	    "pmunameY".
7298c2ecf20Sopenharmony_ci	 */
7308c2ecf20Sopenharmony_ci	for (; tok; name += strlen(tok), tok = strtok_r(NULL, ",", &tmp)) {
7318c2ecf20Sopenharmony_ci		name = strstr(name, tok);
7328c2ecf20Sopenharmony_ci		if (!name) {
7338c2ecf20Sopenharmony_ci			res = false;
7348c2ecf20Sopenharmony_ci			goto out;
7358c2ecf20Sopenharmony_ci		}
7368c2ecf20Sopenharmony_ci	}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	res = true;
7398c2ecf20Sopenharmony_ciout:
7408c2ecf20Sopenharmony_ci	free(str);
7418c2ecf20Sopenharmony_ci	return res;
7428c2ecf20Sopenharmony_ci}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci/*
7458c2ecf20Sopenharmony_ci * From the pmu_events_map, find the table of PMU events that corresponds
7468c2ecf20Sopenharmony_ci * to the current running CPU. Then, add all PMU events from that table
7478c2ecf20Sopenharmony_ci * as aliases.
7488c2ecf20Sopenharmony_ci */
7498c2ecf20Sopenharmony_civoid pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
7508c2ecf20Sopenharmony_ci			     struct pmu_events_map *map)
7518c2ecf20Sopenharmony_ci{
7528c2ecf20Sopenharmony_ci	int i;
7538c2ecf20Sopenharmony_ci	const char *name = pmu->name;
7548c2ecf20Sopenharmony_ci	/*
7558c2ecf20Sopenharmony_ci	 * Found a matching PMU events table. Create aliases
7568c2ecf20Sopenharmony_ci	 */
7578c2ecf20Sopenharmony_ci	i = 0;
7588c2ecf20Sopenharmony_ci	while (1) {
7598c2ecf20Sopenharmony_ci		const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
7608c2ecf20Sopenharmony_ci		struct pmu_event *pe = &map->table[i++];
7618c2ecf20Sopenharmony_ci		const char *pname = pe->pmu ? pe->pmu : cpu_name;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci		if (!pe->name) {
7648c2ecf20Sopenharmony_ci			if (pe->metric_group || pe->metric_name)
7658c2ecf20Sopenharmony_ci				continue;
7668c2ecf20Sopenharmony_ci			break;
7678c2ecf20Sopenharmony_ci		}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci		if (pmu_is_uncore(name) &&
7708c2ecf20Sopenharmony_ci		    pmu_uncore_alias_match(pname, name))
7718c2ecf20Sopenharmony_ci			goto new_alias;
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci		if (strcmp(pname, name))
7748c2ecf20Sopenharmony_ci			continue;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_cinew_alias:
7778c2ecf20Sopenharmony_ci		/* need type casts to override 'const' */
7788c2ecf20Sopenharmony_ci		__perf_pmu__new_alias(head, NULL, (char *)pe->name,
7798c2ecf20Sopenharmony_ci				(char *)pe->desc, (char *)pe->event,
7808c2ecf20Sopenharmony_ci				(char *)pe->long_desc, (char *)pe->topic,
7818c2ecf20Sopenharmony_ci				(char *)pe->unit, (char *)pe->perpkg,
7828c2ecf20Sopenharmony_ci				(char *)pe->metric_expr,
7838c2ecf20Sopenharmony_ci				(char *)pe->metric_name,
7848c2ecf20Sopenharmony_ci				(char *)pe->deprecated);
7858c2ecf20Sopenharmony_ci	}
7868c2ecf20Sopenharmony_ci}
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_cistatic void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
7898c2ecf20Sopenharmony_ci{
7908c2ecf20Sopenharmony_ci	struct pmu_events_map *map;
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	map = perf_pmu__find_map(pmu);
7938c2ecf20Sopenharmony_ci	if (!map)
7948c2ecf20Sopenharmony_ci		return;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	pmu_add_cpu_aliases_map(head, pmu, map);
7978c2ecf20Sopenharmony_ci}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_cistruct perf_event_attr * __weak
8008c2ecf20Sopenharmony_ciperf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	return NULL;
8038c2ecf20Sopenharmony_ci}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_cistatic int pmu_max_precise(const char *name)
8068c2ecf20Sopenharmony_ci{
8078c2ecf20Sopenharmony_ci	char path[PATH_MAX];
8088c2ecf20Sopenharmony_ci	int max_precise = -1;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	scnprintf(path, PATH_MAX,
8118c2ecf20Sopenharmony_ci		 "bus/event_source/devices/%s/caps/max_precise",
8128c2ecf20Sopenharmony_ci		 name);
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	sysfs__read_int(path, &max_precise);
8158c2ecf20Sopenharmony_ci	return max_precise;
8168c2ecf20Sopenharmony_ci}
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_cistatic struct perf_pmu *pmu_lookup(const char *name)
8198c2ecf20Sopenharmony_ci{
8208c2ecf20Sopenharmony_ci	struct perf_pmu *pmu;
8218c2ecf20Sopenharmony_ci	LIST_HEAD(format);
8228c2ecf20Sopenharmony_ci	LIST_HEAD(aliases);
8238c2ecf20Sopenharmony_ci	__u32 type;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	/*
8268c2ecf20Sopenharmony_ci	 * The pmu data we store & need consists of the pmu
8278c2ecf20Sopenharmony_ci	 * type value and format definitions. Load both right
8288c2ecf20Sopenharmony_ci	 * now.
8298c2ecf20Sopenharmony_ci	 */
8308c2ecf20Sopenharmony_ci	if (pmu_format(name, &format))
8318c2ecf20Sopenharmony_ci		return NULL;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	/*
8348c2ecf20Sopenharmony_ci	 * Check the type first to avoid unnecessary work.
8358c2ecf20Sopenharmony_ci	 */
8368c2ecf20Sopenharmony_ci	if (pmu_type(name, &type))
8378c2ecf20Sopenharmony_ci		return NULL;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	if (pmu_aliases(name, &aliases))
8408c2ecf20Sopenharmony_ci		return NULL;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	pmu = zalloc(sizeof(*pmu));
8438c2ecf20Sopenharmony_ci	if (!pmu)
8448c2ecf20Sopenharmony_ci		return NULL;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	pmu->cpus = pmu_cpumask(name);
8478c2ecf20Sopenharmony_ci	pmu->name = strdup(name);
8488c2ecf20Sopenharmony_ci	pmu->type = type;
8498c2ecf20Sopenharmony_ci	pmu->is_uncore = pmu_is_uncore(name);
8508c2ecf20Sopenharmony_ci	pmu->max_precise = pmu_max_precise(name);
8518c2ecf20Sopenharmony_ci	pmu_add_cpu_aliases(&aliases, pmu);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&pmu->format);
8548c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&pmu->aliases);
8558c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&pmu->caps);
8568c2ecf20Sopenharmony_ci	list_splice(&format, &pmu->format);
8578c2ecf20Sopenharmony_ci	list_splice(&aliases, &pmu->aliases);
8588c2ecf20Sopenharmony_ci	list_add_tail(&pmu->list, &pmus);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	pmu->default_config = perf_pmu__get_default_config(pmu);
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	return pmu;
8638c2ecf20Sopenharmony_ci}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_civoid perf_pmu__warn_invalid_formats(struct perf_pmu *pmu)
8668c2ecf20Sopenharmony_ci{
8678c2ecf20Sopenharmony_ci	struct perf_pmu_format *format;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	/* fake pmu doesn't have format list */
8708c2ecf20Sopenharmony_ci	if (pmu == &perf_pmu__fake)
8718c2ecf20Sopenharmony_ci		return;
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	list_for_each_entry(format, &pmu->format, list)
8748c2ecf20Sopenharmony_ci		if (format->value >= PERF_PMU_FORMAT_VALUE_CONFIG_END) {
8758c2ecf20Sopenharmony_ci			pr_warning("WARNING: '%s' format '%s' requires 'perf_event_attr::config%d'"
8768c2ecf20Sopenharmony_ci				   "which is not supported by this version of perf!\n",
8778c2ecf20Sopenharmony_ci				   pmu->name, format->name, format->value);
8788c2ecf20Sopenharmony_ci			return;
8798c2ecf20Sopenharmony_ci		}
8808c2ecf20Sopenharmony_ci}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_cistatic struct perf_pmu *pmu_find(const char *name)
8838c2ecf20Sopenharmony_ci{
8848c2ecf20Sopenharmony_ci	struct perf_pmu *pmu;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	list_for_each_entry(pmu, &pmus, list)
8878c2ecf20Sopenharmony_ci		if (!strcmp(pmu->name, name))
8888c2ecf20Sopenharmony_ci			return pmu;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	return NULL;
8918c2ecf20Sopenharmony_ci}
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_cistruct perf_pmu *perf_pmu__find_by_type(unsigned int type)
8948c2ecf20Sopenharmony_ci{
8958c2ecf20Sopenharmony_ci	struct perf_pmu *pmu;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	list_for_each_entry(pmu, &pmus, list)
8988c2ecf20Sopenharmony_ci		if (pmu->type == type)
8998c2ecf20Sopenharmony_ci			return pmu;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	return NULL;
9028c2ecf20Sopenharmony_ci}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_cistruct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
9058c2ecf20Sopenharmony_ci{
9068c2ecf20Sopenharmony_ci	/*
9078c2ecf20Sopenharmony_ci	 * pmu iterator: If pmu is NULL, we start at the begin,
9088c2ecf20Sopenharmony_ci	 * otherwise return the next pmu. Returns NULL on end.
9098c2ecf20Sopenharmony_ci	 */
9108c2ecf20Sopenharmony_ci	if (!pmu) {
9118c2ecf20Sopenharmony_ci		pmu_read_sysfs();
9128c2ecf20Sopenharmony_ci		pmu = list_prepare_entry(pmu, &pmus, list);
9138c2ecf20Sopenharmony_ci	}
9148c2ecf20Sopenharmony_ci	list_for_each_entry_continue(pmu, &pmus, list)
9158c2ecf20Sopenharmony_ci		return pmu;
9168c2ecf20Sopenharmony_ci	return NULL;
9178c2ecf20Sopenharmony_ci}
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_cistruct perf_pmu *evsel__find_pmu(struct evsel *evsel)
9208c2ecf20Sopenharmony_ci{
9218c2ecf20Sopenharmony_ci	struct perf_pmu *pmu = NULL;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	while ((pmu = perf_pmu__scan(pmu)) != NULL) {
9248c2ecf20Sopenharmony_ci		if (pmu->type == evsel->core.attr.type)
9258c2ecf20Sopenharmony_ci			break;
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	return pmu;
9298c2ecf20Sopenharmony_ci}
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_cibool evsel__is_aux_event(struct evsel *evsel)
9328c2ecf20Sopenharmony_ci{
9338c2ecf20Sopenharmony_ci	struct perf_pmu *pmu = evsel__find_pmu(evsel);
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	return pmu && pmu->auxtrace;
9368c2ecf20Sopenharmony_ci}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_cistruct perf_pmu *perf_pmu__find(const char *name)
9398c2ecf20Sopenharmony_ci{
9408c2ecf20Sopenharmony_ci	struct perf_pmu *pmu;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	/*
9438c2ecf20Sopenharmony_ci	 * Once PMU is loaded it stays in the list,
9448c2ecf20Sopenharmony_ci	 * so we keep us from multiple reading/parsing
9458c2ecf20Sopenharmony_ci	 * the pmu format definitions.
9468c2ecf20Sopenharmony_ci	 */
9478c2ecf20Sopenharmony_ci	pmu = pmu_find(name);
9488c2ecf20Sopenharmony_ci	if (pmu)
9498c2ecf20Sopenharmony_ci		return pmu;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	return pmu_lookup(name);
9528c2ecf20Sopenharmony_ci}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_cistatic struct perf_pmu_format *
9558c2ecf20Sopenharmony_cipmu_find_format(struct list_head *formats, const char *name)
9568c2ecf20Sopenharmony_ci{
9578c2ecf20Sopenharmony_ci	struct perf_pmu_format *format;
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	list_for_each_entry(format, formats, list)
9608c2ecf20Sopenharmony_ci		if (!strcmp(format->name, name))
9618c2ecf20Sopenharmony_ci			return format;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	return NULL;
9648c2ecf20Sopenharmony_ci}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci__u64 perf_pmu__format_bits(struct list_head *formats, const char *name)
9678c2ecf20Sopenharmony_ci{
9688c2ecf20Sopenharmony_ci	struct perf_pmu_format *format = pmu_find_format(formats, name);
9698c2ecf20Sopenharmony_ci	__u64 bits = 0;
9708c2ecf20Sopenharmony_ci	int fbit;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	if (!format)
9738c2ecf20Sopenharmony_ci		return 0;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS)
9768c2ecf20Sopenharmony_ci		bits |= 1ULL << fbit;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	return bits;
9798c2ecf20Sopenharmony_ci}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ciint perf_pmu__format_type(struct list_head *formats, const char *name)
9828c2ecf20Sopenharmony_ci{
9838c2ecf20Sopenharmony_ci	struct perf_pmu_format *format = pmu_find_format(formats, name);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	if (!format)
9868c2ecf20Sopenharmony_ci		return -1;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	return format->value;
9898c2ecf20Sopenharmony_ci}
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci/*
9928c2ecf20Sopenharmony_ci * Sets value based on the format definition (format parameter)
9938c2ecf20Sopenharmony_ci * and unformated value (value parameter).
9948c2ecf20Sopenharmony_ci */
9958c2ecf20Sopenharmony_cistatic void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
9968c2ecf20Sopenharmony_ci			     bool zero)
9978c2ecf20Sopenharmony_ci{
9988c2ecf20Sopenharmony_ci	unsigned long fbit, vbit;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci		if (!test_bit(fbit, format))
10038c2ecf20Sopenharmony_ci			continue;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci		if (value & (1llu << vbit++))
10068c2ecf20Sopenharmony_ci			*v |= (1llu << fbit);
10078c2ecf20Sopenharmony_ci		else if (zero)
10088c2ecf20Sopenharmony_ci			*v &= ~(1llu << fbit);
10098c2ecf20Sopenharmony_ci	}
10108c2ecf20Sopenharmony_ci}
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_cistatic __u64 pmu_format_max_value(const unsigned long *format)
10138c2ecf20Sopenharmony_ci{
10148c2ecf20Sopenharmony_ci	int w;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	w = bitmap_weight(format, PERF_PMU_FORMAT_BITS);
10178c2ecf20Sopenharmony_ci	if (!w)
10188c2ecf20Sopenharmony_ci		return 0;
10198c2ecf20Sopenharmony_ci	if (w < 64)
10208c2ecf20Sopenharmony_ci		return (1ULL << w) - 1;
10218c2ecf20Sopenharmony_ci	return -1;
10228c2ecf20Sopenharmony_ci}
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci/*
10258c2ecf20Sopenharmony_ci * Term is a string term, and might be a param-term. Try to look up it's value
10268c2ecf20Sopenharmony_ci * in the remaining terms.
10278c2ecf20Sopenharmony_ci * - We have a term like "base-or-format-term=param-term",
10288c2ecf20Sopenharmony_ci * - We need to find the value supplied for "param-term" (with param-term named
10298c2ecf20Sopenharmony_ci *   in a config string) later on in the term list.
10308c2ecf20Sopenharmony_ci */
10318c2ecf20Sopenharmony_cistatic int pmu_resolve_param_term(struct parse_events_term *term,
10328c2ecf20Sopenharmony_ci				  struct list_head *head_terms,
10338c2ecf20Sopenharmony_ci				  __u64 *value)
10348c2ecf20Sopenharmony_ci{
10358c2ecf20Sopenharmony_ci	struct parse_events_term *t;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	list_for_each_entry(t, head_terms, list) {
10388c2ecf20Sopenharmony_ci		if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM &&
10398c2ecf20Sopenharmony_ci		    t->config && !strcmp(t->config, term->config)) {
10408c2ecf20Sopenharmony_ci			t->used = true;
10418c2ecf20Sopenharmony_ci			*value = t->val.num;
10428c2ecf20Sopenharmony_ci			return 0;
10438c2ecf20Sopenharmony_ci		}
10448c2ecf20Sopenharmony_ci	}
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	if (verbose > 0)
10478c2ecf20Sopenharmony_ci		printf("Required parameter '%s' not specified\n", term->config);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	return -1;
10508c2ecf20Sopenharmony_ci}
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_cistatic char *pmu_formats_string(struct list_head *formats)
10538c2ecf20Sopenharmony_ci{
10548c2ecf20Sopenharmony_ci	struct perf_pmu_format *format;
10558c2ecf20Sopenharmony_ci	char *str = NULL;
10568c2ecf20Sopenharmony_ci	struct strbuf buf = STRBUF_INIT;
10578c2ecf20Sopenharmony_ci	unsigned i = 0;
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	if (!formats)
10608c2ecf20Sopenharmony_ci		return NULL;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	/* sysfs exported terms */
10638c2ecf20Sopenharmony_ci	list_for_each_entry(format, formats, list)
10648c2ecf20Sopenharmony_ci		if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0)
10658c2ecf20Sopenharmony_ci			goto error;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	str = strbuf_detach(&buf, NULL);
10688c2ecf20Sopenharmony_cierror:
10698c2ecf20Sopenharmony_ci	strbuf_release(&buf);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	return str;
10728c2ecf20Sopenharmony_ci}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci/*
10758c2ecf20Sopenharmony_ci * Setup one of config[12] attr members based on the
10768c2ecf20Sopenharmony_ci * user input data - term parameter.
10778c2ecf20Sopenharmony_ci */
10788c2ecf20Sopenharmony_cistatic int pmu_config_term(const char *pmu_name,
10798c2ecf20Sopenharmony_ci			   struct list_head *formats,
10808c2ecf20Sopenharmony_ci			   struct perf_event_attr *attr,
10818c2ecf20Sopenharmony_ci			   struct parse_events_term *term,
10828c2ecf20Sopenharmony_ci			   struct list_head *head_terms,
10838c2ecf20Sopenharmony_ci			   bool zero, struct parse_events_error *err)
10848c2ecf20Sopenharmony_ci{
10858c2ecf20Sopenharmony_ci	struct perf_pmu_format *format;
10868c2ecf20Sopenharmony_ci	__u64 *vp;
10878c2ecf20Sopenharmony_ci	__u64 val, max_val;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	/*
10908c2ecf20Sopenharmony_ci	 * If this is a parameter we've already used for parameterized-eval,
10918c2ecf20Sopenharmony_ci	 * skip it in normal eval.
10928c2ecf20Sopenharmony_ci	 */
10938c2ecf20Sopenharmony_ci	if (term->used)
10948c2ecf20Sopenharmony_ci		return 0;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	/*
10978c2ecf20Sopenharmony_ci	 * Hardcoded terms should be already in, so nothing
10988c2ecf20Sopenharmony_ci	 * to be done for them.
10998c2ecf20Sopenharmony_ci	 */
11008c2ecf20Sopenharmony_ci	if (parse_events__is_hardcoded_term(term))
11018c2ecf20Sopenharmony_ci		return 0;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	format = pmu_find_format(formats, term->config);
11048c2ecf20Sopenharmony_ci	if (!format) {
11058c2ecf20Sopenharmony_ci		char *pmu_term = pmu_formats_string(formats);
11068c2ecf20Sopenharmony_ci		char *unknown_term;
11078c2ecf20Sopenharmony_ci		char *help_msg;
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci		if (asprintf(&unknown_term,
11108c2ecf20Sopenharmony_ci				"unknown term '%s' for pmu '%s'",
11118c2ecf20Sopenharmony_ci				term->config, pmu_name) < 0)
11128c2ecf20Sopenharmony_ci			unknown_term = NULL;
11138c2ecf20Sopenharmony_ci		help_msg = parse_events_formats_error_string(pmu_term);
11148c2ecf20Sopenharmony_ci		if (err) {
11158c2ecf20Sopenharmony_ci			parse_events__handle_error(err, term->err_term,
11168c2ecf20Sopenharmony_ci						   unknown_term,
11178c2ecf20Sopenharmony_ci						   help_msg);
11188c2ecf20Sopenharmony_ci		} else {
11198c2ecf20Sopenharmony_ci			pr_debug("%s (%s)\n", unknown_term, help_msg);
11208c2ecf20Sopenharmony_ci			free(unknown_term);
11218c2ecf20Sopenharmony_ci		}
11228c2ecf20Sopenharmony_ci		free(pmu_term);
11238c2ecf20Sopenharmony_ci		return -EINVAL;
11248c2ecf20Sopenharmony_ci	}
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	switch (format->value) {
11278c2ecf20Sopenharmony_ci	case PERF_PMU_FORMAT_VALUE_CONFIG:
11288c2ecf20Sopenharmony_ci		vp = &attr->config;
11298c2ecf20Sopenharmony_ci		break;
11308c2ecf20Sopenharmony_ci	case PERF_PMU_FORMAT_VALUE_CONFIG1:
11318c2ecf20Sopenharmony_ci		vp = &attr->config1;
11328c2ecf20Sopenharmony_ci		break;
11338c2ecf20Sopenharmony_ci	case PERF_PMU_FORMAT_VALUE_CONFIG2:
11348c2ecf20Sopenharmony_ci		vp = &attr->config2;
11358c2ecf20Sopenharmony_ci		break;
11368c2ecf20Sopenharmony_ci	default:
11378c2ecf20Sopenharmony_ci		return -EINVAL;
11388c2ecf20Sopenharmony_ci	}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	/*
11418c2ecf20Sopenharmony_ci	 * Either directly use a numeric term, or try to translate string terms
11428c2ecf20Sopenharmony_ci	 * using event parameters.
11438c2ecf20Sopenharmony_ci	 */
11448c2ecf20Sopenharmony_ci	if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
11458c2ecf20Sopenharmony_ci		if (term->no_value &&
11468c2ecf20Sopenharmony_ci		    bitmap_weight(format->bits, PERF_PMU_FORMAT_BITS) > 1) {
11478c2ecf20Sopenharmony_ci			if (err) {
11488c2ecf20Sopenharmony_ci				parse_events__handle_error(err, term->err_val,
11498c2ecf20Sopenharmony_ci					   strdup("no value assigned for term"),
11508c2ecf20Sopenharmony_ci					   NULL);
11518c2ecf20Sopenharmony_ci			}
11528c2ecf20Sopenharmony_ci			return -EINVAL;
11538c2ecf20Sopenharmony_ci		}
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci		val = term->val.num;
11568c2ecf20Sopenharmony_ci	} else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
11578c2ecf20Sopenharmony_ci		if (strcmp(term->val.str, "?")) {
11588c2ecf20Sopenharmony_ci			if (verbose > 0) {
11598c2ecf20Sopenharmony_ci				pr_info("Invalid sysfs entry %s=%s\n",
11608c2ecf20Sopenharmony_ci						term->config, term->val.str);
11618c2ecf20Sopenharmony_ci			}
11628c2ecf20Sopenharmony_ci			if (err) {
11638c2ecf20Sopenharmony_ci				parse_events__handle_error(err, term->err_val,
11648c2ecf20Sopenharmony_ci					strdup("expected numeric value"),
11658c2ecf20Sopenharmony_ci					NULL);
11668c2ecf20Sopenharmony_ci			}
11678c2ecf20Sopenharmony_ci			return -EINVAL;
11688c2ecf20Sopenharmony_ci		}
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci		if (pmu_resolve_param_term(term, head_terms, &val))
11718c2ecf20Sopenharmony_ci			return -EINVAL;
11728c2ecf20Sopenharmony_ci	} else
11738c2ecf20Sopenharmony_ci		return -EINVAL;
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	max_val = pmu_format_max_value(format->bits);
11768c2ecf20Sopenharmony_ci	if (val > max_val) {
11778c2ecf20Sopenharmony_ci		if (err) {
11788c2ecf20Sopenharmony_ci			char *err_str;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci			parse_events__handle_error(err, term->err_val,
11818c2ecf20Sopenharmony_ci				asprintf(&err_str,
11828c2ecf20Sopenharmony_ci				    "value too big for format, maximum is %llu",
11838c2ecf20Sopenharmony_ci				    (unsigned long long)max_val) < 0
11848c2ecf20Sopenharmony_ci				    ? strdup("value too big for format")
11858c2ecf20Sopenharmony_ci				    : err_str,
11868c2ecf20Sopenharmony_ci				    NULL);
11878c2ecf20Sopenharmony_ci			return -EINVAL;
11888c2ecf20Sopenharmony_ci		}
11898c2ecf20Sopenharmony_ci		/*
11908c2ecf20Sopenharmony_ci		 * Assume we don't care if !err, in which case the value will be
11918c2ecf20Sopenharmony_ci		 * silently truncated.
11928c2ecf20Sopenharmony_ci		 */
11938c2ecf20Sopenharmony_ci	}
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	pmu_format_value(format->bits, val, vp, zero);
11968c2ecf20Sopenharmony_ci	return 0;
11978c2ecf20Sopenharmony_ci}
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ciint perf_pmu__config_terms(const char *pmu_name, struct list_head *formats,
12008c2ecf20Sopenharmony_ci			   struct perf_event_attr *attr,
12018c2ecf20Sopenharmony_ci			   struct list_head *head_terms,
12028c2ecf20Sopenharmony_ci			   bool zero, struct parse_events_error *err)
12038c2ecf20Sopenharmony_ci{
12048c2ecf20Sopenharmony_ci	struct parse_events_term *term;
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	list_for_each_entry(term, head_terms, list) {
12078c2ecf20Sopenharmony_ci		if (pmu_config_term(pmu_name, formats, attr, term, head_terms,
12088c2ecf20Sopenharmony_ci				    zero, err))
12098c2ecf20Sopenharmony_ci			return -EINVAL;
12108c2ecf20Sopenharmony_ci	}
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	return 0;
12138c2ecf20Sopenharmony_ci}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci/*
12168c2ecf20Sopenharmony_ci * Configures event's 'attr' parameter based on the:
12178c2ecf20Sopenharmony_ci * 1) users input - specified in terms parameter
12188c2ecf20Sopenharmony_ci * 2) pmu format definitions - specified by pmu parameter
12198c2ecf20Sopenharmony_ci */
12208c2ecf20Sopenharmony_ciint perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
12218c2ecf20Sopenharmony_ci		     struct list_head *head_terms,
12228c2ecf20Sopenharmony_ci		     struct parse_events_error *err)
12238c2ecf20Sopenharmony_ci{
12248c2ecf20Sopenharmony_ci	bool zero = !!pmu->default_config;
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	attr->type = pmu->type;
12278c2ecf20Sopenharmony_ci	return perf_pmu__config_terms(pmu->name, &pmu->format, attr,
12288c2ecf20Sopenharmony_ci				      head_terms, zero, err);
12298c2ecf20Sopenharmony_ci}
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_cistatic struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
12328c2ecf20Sopenharmony_ci					     struct parse_events_term *term)
12338c2ecf20Sopenharmony_ci{
12348c2ecf20Sopenharmony_ci	struct perf_pmu_alias *alias;
12358c2ecf20Sopenharmony_ci	char *name;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	if (parse_events__is_hardcoded_term(term))
12388c2ecf20Sopenharmony_ci		return NULL;
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
12418c2ecf20Sopenharmony_ci		if (term->val.num != 1)
12428c2ecf20Sopenharmony_ci			return NULL;
12438c2ecf20Sopenharmony_ci		if (pmu_find_format(&pmu->format, term->config))
12448c2ecf20Sopenharmony_ci			return NULL;
12458c2ecf20Sopenharmony_ci		name = term->config;
12468c2ecf20Sopenharmony_ci	} else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
12478c2ecf20Sopenharmony_ci		if (strcasecmp(term->config, "event"))
12488c2ecf20Sopenharmony_ci			return NULL;
12498c2ecf20Sopenharmony_ci		name = term->val.str;
12508c2ecf20Sopenharmony_ci	} else {
12518c2ecf20Sopenharmony_ci		return NULL;
12528c2ecf20Sopenharmony_ci	}
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	list_for_each_entry(alias, &pmu->aliases, list) {
12558c2ecf20Sopenharmony_ci		if (!strcasecmp(alias->name, name))
12568c2ecf20Sopenharmony_ci			return alias;
12578c2ecf20Sopenharmony_ci	}
12588c2ecf20Sopenharmony_ci	return NULL;
12598c2ecf20Sopenharmony_ci}
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_cistatic int check_info_data(struct perf_pmu_alias *alias,
12638c2ecf20Sopenharmony_ci			   struct perf_pmu_info *info)
12648c2ecf20Sopenharmony_ci{
12658c2ecf20Sopenharmony_ci	/*
12668c2ecf20Sopenharmony_ci	 * Only one term in event definition can
12678c2ecf20Sopenharmony_ci	 * define unit, scale and snapshot, fail
12688c2ecf20Sopenharmony_ci	 * if there's more than one.
12698c2ecf20Sopenharmony_ci	 */
12708c2ecf20Sopenharmony_ci	if ((info->unit && alias->unit[0]) ||
12718c2ecf20Sopenharmony_ci	    (info->scale && alias->scale) ||
12728c2ecf20Sopenharmony_ci	    (info->snapshot && alias->snapshot))
12738c2ecf20Sopenharmony_ci		return -EINVAL;
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	if (alias->unit[0])
12768c2ecf20Sopenharmony_ci		info->unit = alias->unit;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	if (alias->scale)
12798c2ecf20Sopenharmony_ci		info->scale = alias->scale;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	if (alias->snapshot)
12828c2ecf20Sopenharmony_ci		info->snapshot = alias->snapshot;
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	return 0;
12858c2ecf20Sopenharmony_ci}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci/*
12888c2ecf20Sopenharmony_ci * Find alias in the terms list and replace it with the terms
12898c2ecf20Sopenharmony_ci * defined for the alias
12908c2ecf20Sopenharmony_ci */
12918c2ecf20Sopenharmony_ciint perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
12928c2ecf20Sopenharmony_ci			  struct perf_pmu_info *info)
12938c2ecf20Sopenharmony_ci{
12948c2ecf20Sopenharmony_ci	struct parse_events_term *term, *h;
12958c2ecf20Sopenharmony_ci	struct perf_pmu_alias *alias;
12968c2ecf20Sopenharmony_ci	int ret;
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	info->per_pkg = false;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	/*
13018c2ecf20Sopenharmony_ci	 * Mark unit and scale as not set
13028c2ecf20Sopenharmony_ci	 * (different from default values, see below)
13038c2ecf20Sopenharmony_ci	 */
13048c2ecf20Sopenharmony_ci	info->unit     = NULL;
13058c2ecf20Sopenharmony_ci	info->scale    = 0.0;
13068c2ecf20Sopenharmony_ci	info->snapshot = false;
13078c2ecf20Sopenharmony_ci	info->metric_expr = NULL;
13088c2ecf20Sopenharmony_ci	info->metric_name = NULL;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	list_for_each_entry_safe(term, h, head_terms, list) {
13118c2ecf20Sopenharmony_ci		alias = pmu_find_alias(pmu, term);
13128c2ecf20Sopenharmony_ci		if (!alias)
13138c2ecf20Sopenharmony_ci			continue;
13148c2ecf20Sopenharmony_ci		ret = pmu_alias_terms(alias, &term->list);
13158c2ecf20Sopenharmony_ci		if (ret)
13168c2ecf20Sopenharmony_ci			return ret;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci		ret = check_info_data(alias, info);
13198c2ecf20Sopenharmony_ci		if (ret)
13208c2ecf20Sopenharmony_ci			return ret;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci		if (alias->per_pkg)
13238c2ecf20Sopenharmony_ci			info->per_pkg = true;
13248c2ecf20Sopenharmony_ci		info->metric_expr = alias->metric_expr;
13258c2ecf20Sopenharmony_ci		info->metric_name = alias->metric_name;
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci		list_del_init(&term->list);
13288c2ecf20Sopenharmony_ci		parse_events_term__delete(term);
13298c2ecf20Sopenharmony_ci	}
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	/*
13328c2ecf20Sopenharmony_ci	 * if no unit or scale foundin aliases, then
13338c2ecf20Sopenharmony_ci	 * set defaults as for evsel
13348c2ecf20Sopenharmony_ci	 * unit cannot left to NULL
13358c2ecf20Sopenharmony_ci	 */
13368c2ecf20Sopenharmony_ci	if (info->unit == NULL)
13378c2ecf20Sopenharmony_ci		info->unit   = "";
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	if (info->scale == 0.0)
13408c2ecf20Sopenharmony_ci		info->scale  = 1.0;
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	return 0;
13438c2ecf20Sopenharmony_ci}
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ciint perf_pmu__new_format(struct list_head *list, char *name,
13468c2ecf20Sopenharmony_ci			 int config, unsigned long *bits)
13478c2ecf20Sopenharmony_ci{
13488c2ecf20Sopenharmony_ci	struct perf_pmu_format *format;
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	format = zalloc(sizeof(*format));
13518c2ecf20Sopenharmony_ci	if (!format)
13528c2ecf20Sopenharmony_ci		return -ENOMEM;
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	format->name = strdup(name);
13558c2ecf20Sopenharmony_ci	format->value = config;
13568c2ecf20Sopenharmony_ci	memcpy(format->bits, bits, sizeof(format->bits));
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	list_add_tail(&format->list, list);
13598c2ecf20Sopenharmony_ci	return 0;
13608c2ecf20Sopenharmony_ci}
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_civoid perf_pmu__set_format(unsigned long *bits, long from, long to)
13638c2ecf20Sopenharmony_ci{
13648c2ecf20Sopenharmony_ci	long b;
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	if (!to)
13678c2ecf20Sopenharmony_ci		to = from;
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS));
13708c2ecf20Sopenharmony_ci	for (b = from; b <= to; b++)
13718c2ecf20Sopenharmony_ci		set_bit(b, bits);
13728c2ecf20Sopenharmony_ci}
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_civoid perf_pmu__del_formats(struct list_head *formats)
13758c2ecf20Sopenharmony_ci{
13768c2ecf20Sopenharmony_ci	struct perf_pmu_format *fmt, *tmp;
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	list_for_each_entry_safe(fmt, tmp, formats, list) {
13798c2ecf20Sopenharmony_ci		list_del(&fmt->list);
13808c2ecf20Sopenharmony_ci		free(fmt->name);
13818c2ecf20Sopenharmony_ci		free(fmt);
13828c2ecf20Sopenharmony_ci	}
13838c2ecf20Sopenharmony_ci}
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_cistatic int sub_non_neg(int a, int b)
13868c2ecf20Sopenharmony_ci{
13878c2ecf20Sopenharmony_ci	if (b > a)
13888c2ecf20Sopenharmony_ci		return 0;
13898c2ecf20Sopenharmony_ci	return a - b;
13908c2ecf20Sopenharmony_ci}
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_cistatic char *format_alias(char *buf, int len, struct perf_pmu *pmu,
13938c2ecf20Sopenharmony_ci			  struct perf_pmu_alias *alias)
13948c2ecf20Sopenharmony_ci{
13958c2ecf20Sopenharmony_ci	struct parse_events_term *term;
13968c2ecf20Sopenharmony_ci	int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name);
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	list_for_each_entry(term, &alias->terms, list) {
13998c2ecf20Sopenharmony_ci		if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
14008c2ecf20Sopenharmony_ci			used += snprintf(buf + used, sub_non_neg(len, used),
14018c2ecf20Sopenharmony_ci					",%s=%s", term->config,
14028c2ecf20Sopenharmony_ci					term->val.str);
14038c2ecf20Sopenharmony_ci	}
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	if (sub_non_neg(len, used) > 0) {
14068c2ecf20Sopenharmony_ci		buf[used] = '/';
14078c2ecf20Sopenharmony_ci		used++;
14088c2ecf20Sopenharmony_ci	}
14098c2ecf20Sopenharmony_ci	if (sub_non_neg(len, used) > 0) {
14108c2ecf20Sopenharmony_ci		buf[used] = '\0';
14118c2ecf20Sopenharmony_ci		used++;
14128c2ecf20Sopenharmony_ci	} else
14138c2ecf20Sopenharmony_ci		buf[len - 1] = '\0';
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	return buf;
14168c2ecf20Sopenharmony_ci}
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_cistatic char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
14198c2ecf20Sopenharmony_ci			     struct perf_pmu_alias *alias)
14208c2ecf20Sopenharmony_ci{
14218c2ecf20Sopenharmony_ci	snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name);
14228c2ecf20Sopenharmony_ci	return buf;
14238c2ecf20Sopenharmony_ci}
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_cistruct sevent {
14268c2ecf20Sopenharmony_ci	char *name;
14278c2ecf20Sopenharmony_ci	char *desc;
14288c2ecf20Sopenharmony_ci	char *topic;
14298c2ecf20Sopenharmony_ci	char *str;
14308c2ecf20Sopenharmony_ci	char *pmu;
14318c2ecf20Sopenharmony_ci	char *metric_expr;
14328c2ecf20Sopenharmony_ci	char *metric_name;
14338c2ecf20Sopenharmony_ci	int is_cpu;
14348c2ecf20Sopenharmony_ci};
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_cistatic int cmp_sevent(const void *a, const void *b)
14378c2ecf20Sopenharmony_ci{
14388c2ecf20Sopenharmony_ci	const struct sevent *as = a;
14398c2ecf20Sopenharmony_ci	const struct sevent *bs = b;
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	/* Put extra events last */
14428c2ecf20Sopenharmony_ci	if (!!as->desc != !!bs->desc)
14438c2ecf20Sopenharmony_ci		return !!as->desc - !!bs->desc;
14448c2ecf20Sopenharmony_ci	if (as->topic && bs->topic) {
14458c2ecf20Sopenharmony_ci		int n = strcmp(as->topic, bs->topic);
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci		if (n)
14488c2ecf20Sopenharmony_ci			return n;
14498c2ecf20Sopenharmony_ci	}
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	/* Order CPU core events to be first */
14528c2ecf20Sopenharmony_ci	if (as->is_cpu != bs->is_cpu)
14538c2ecf20Sopenharmony_ci		return bs->is_cpu - as->is_cpu;
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	return strcmp(as->name, bs->name);
14568c2ecf20Sopenharmony_ci}
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_cistatic void wordwrap(char *s, int start, int max, int corr)
14598c2ecf20Sopenharmony_ci{
14608c2ecf20Sopenharmony_ci	int column = start;
14618c2ecf20Sopenharmony_ci	int n;
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	while (*s) {
14648c2ecf20Sopenharmony_ci		int wlen = strcspn(s, " \t");
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci		if (column + wlen >= max && column > start) {
14678c2ecf20Sopenharmony_ci			printf("\n%*s", start, "");
14688c2ecf20Sopenharmony_ci			column = start + corr;
14698c2ecf20Sopenharmony_ci		}
14708c2ecf20Sopenharmony_ci		n = printf("%s%.*s", column > start ? " " : "", wlen, s);
14718c2ecf20Sopenharmony_ci		if (n <= 0)
14728c2ecf20Sopenharmony_ci			break;
14738c2ecf20Sopenharmony_ci		s += wlen;
14748c2ecf20Sopenharmony_ci		column += n;
14758c2ecf20Sopenharmony_ci		s = skip_spaces(s);
14768c2ecf20Sopenharmony_ci	}
14778c2ecf20Sopenharmony_ci}
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_cibool is_pmu_core(const char *name)
14808c2ecf20Sopenharmony_ci{
14818c2ecf20Sopenharmony_ci	return !strcmp(name, "cpu") || is_arm_pmu_core(name);
14828c2ecf20Sopenharmony_ci}
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_civoid print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
14858c2ecf20Sopenharmony_ci			bool long_desc, bool details_flag, bool deprecated)
14868c2ecf20Sopenharmony_ci{
14878c2ecf20Sopenharmony_ci	struct perf_pmu *pmu;
14888c2ecf20Sopenharmony_ci	struct perf_pmu_alias *alias;
14898c2ecf20Sopenharmony_ci	char buf[1024];
14908c2ecf20Sopenharmony_ci	int printed = 0;
14918c2ecf20Sopenharmony_ci	int len, j;
14928c2ecf20Sopenharmony_ci	struct sevent *aliases;
14938c2ecf20Sopenharmony_ci	int numdesc = 0;
14948c2ecf20Sopenharmony_ci	int columns = pager_get_columns();
14958c2ecf20Sopenharmony_ci	char *topic = NULL;
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	pmu = NULL;
14988c2ecf20Sopenharmony_ci	len = 0;
14998c2ecf20Sopenharmony_ci	while ((pmu = perf_pmu__scan(pmu)) != NULL) {
15008c2ecf20Sopenharmony_ci		list_for_each_entry(alias, &pmu->aliases, list)
15018c2ecf20Sopenharmony_ci			len++;
15028c2ecf20Sopenharmony_ci		if (pmu->selectable)
15038c2ecf20Sopenharmony_ci			len++;
15048c2ecf20Sopenharmony_ci	}
15058c2ecf20Sopenharmony_ci	aliases = zalloc(sizeof(struct sevent) * len);
15068c2ecf20Sopenharmony_ci	if (!aliases)
15078c2ecf20Sopenharmony_ci		goto out_enomem;
15088c2ecf20Sopenharmony_ci	pmu = NULL;
15098c2ecf20Sopenharmony_ci	j = 0;
15108c2ecf20Sopenharmony_ci	while ((pmu = perf_pmu__scan(pmu)) != NULL) {
15118c2ecf20Sopenharmony_ci		list_for_each_entry(alias, &pmu->aliases, list) {
15128c2ecf20Sopenharmony_ci			char *name = alias->desc ? alias->name :
15138c2ecf20Sopenharmony_ci				format_alias(buf, sizeof(buf), pmu, alias);
15148c2ecf20Sopenharmony_ci			bool is_cpu = is_pmu_core(pmu->name);
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci			if (alias->deprecated && !deprecated)
15178c2ecf20Sopenharmony_ci				continue;
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci			if (event_glob != NULL &&
15208c2ecf20Sopenharmony_ci			    !(strglobmatch_nocase(name, event_glob) ||
15218c2ecf20Sopenharmony_ci			      (!is_cpu && strglobmatch_nocase(alias->name,
15228c2ecf20Sopenharmony_ci						       event_glob)) ||
15238c2ecf20Sopenharmony_ci			      (alias->topic &&
15248c2ecf20Sopenharmony_ci			       strglobmatch_nocase(alias->topic, event_glob))))
15258c2ecf20Sopenharmony_ci				continue;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci			if (is_cpu && !name_only && !alias->desc)
15288c2ecf20Sopenharmony_ci				name = format_alias_or(buf, sizeof(buf), pmu, alias);
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci			aliases[j].name = name;
15318c2ecf20Sopenharmony_ci			if (is_cpu && !name_only && !alias->desc)
15328c2ecf20Sopenharmony_ci				aliases[j].name = format_alias_or(buf,
15338c2ecf20Sopenharmony_ci								  sizeof(buf),
15348c2ecf20Sopenharmony_ci								  pmu, alias);
15358c2ecf20Sopenharmony_ci			aliases[j].name = strdup(aliases[j].name);
15368c2ecf20Sopenharmony_ci			if (!aliases[j].name)
15378c2ecf20Sopenharmony_ci				goto out_enomem;
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci			aliases[j].desc = long_desc ? alias->long_desc :
15408c2ecf20Sopenharmony_ci						alias->desc;
15418c2ecf20Sopenharmony_ci			aliases[j].topic = alias->topic;
15428c2ecf20Sopenharmony_ci			aliases[j].str = alias->str;
15438c2ecf20Sopenharmony_ci			aliases[j].pmu = pmu->name;
15448c2ecf20Sopenharmony_ci			aliases[j].metric_expr = alias->metric_expr;
15458c2ecf20Sopenharmony_ci			aliases[j].metric_name = alias->metric_name;
15468c2ecf20Sopenharmony_ci			aliases[j].is_cpu = is_cpu;
15478c2ecf20Sopenharmony_ci			j++;
15488c2ecf20Sopenharmony_ci		}
15498c2ecf20Sopenharmony_ci		if (pmu->selectable &&
15508c2ecf20Sopenharmony_ci		    (event_glob == NULL || strglobmatch(pmu->name, event_glob))) {
15518c2ecf20Sopenharmony_ci			char *s;
15528c2ecf20Sopenharmony_ci			if (asprintf(&s, "%s//", pmu->name) < 0)
15538c2ecf20Sopenharmony_ci				goto out_enomem;
15548c2ecf20Sopenharmony_ci			aliases[j].name = s;
15558c2ecf20Sopenharmony_ci			j++;
15568c2ecf20Sopenharmony_ci		}
15578c2ecf20Sopenharmony_ci	}
15588c2ecf20Sopenharmony_ci	len = j;
15598c2ecf20Sopenharmony_ci	qsort(aliases, len, sizeof(struct sevent), cmp_sevent);
15608c2ecf20Sopenharmony_ci	for (j = 0; j < len; j++) {
15618c2ecf20Sopenharmony_ci		/* Skip duplicates */
15628c2ecf20Sopenharmony_ci		if (j > 0 && !strcmp(aliases[j].name, aliases[j - 1].name))
15638c2ecf20Sopenharmony_ci			continue;
15648c2ecf20Sopenharmony_ci		if (name_only) {
15658c2ecf20Sopenharmony_ci			printf("%s ", aliases[j].name);
15668c2ecf20Sopenharmony_ci			continue;
15678c2ecf20Sopenharmony_ci		}
15688c2ecf20Sopenharmony_ci		if (aliases[j].desc && !quiet_flag) {
15698c2ecf20Sopenharmony_ci			if (numdesc++ == 0)
15708c2ecf20Sopenharmony_ci				printf("\n");
15718c2ecf20Sopenharmony_ci			if (aliases[j].topic && (!topic ||
15728c2ecf20Sopenharmony_ci					strcmp(topic, aliases[j].topic))) {
15738c2ecf20Sopenharmony_ci				printf("%s%s:\n", topic ? "\n" : "",
15748c2ecf20Sopenharmony_ci						aliases[j].topic);
15758c2ecf20Sopenharmony_ci				topic = aliases[j].topic;
15768c2ecf20Sopenharmony_ci			}
15778c2ecf20Sopenharmony_ci			printf("  %-50s\n", aliases[j].name);
15788c2ecf20Sopenharmony_ci			printf("%*s", 8, "[");
15798c2ecf20Sopenharmony_ci			wordwrap(aliases[j].desc, 8, columns, 0);
15808c2ecf20Sopenharmony_ci			printf("]\n");
15818c2ecf20Sopenharmony_ci			if (details_flag) {
15828c2ecf20Sopenharmony_ci				printf("%*s%s/%s/ ", 8, "", aliases[j].pmu, aliases[j].str);
15838c2ecf20Sopenharmony_ci				if (aliases[j].metric_name)
15848c2ecf20Sopenharmony_ci					printf(" MetricName: %s", aliases[j].metric_name);
15858c2ecf20Sopenharmony_ci				if (aliases[j].metric_expr)
15868c2ecf20Sopenharmony_ci					printf(" MetricExpr: %s", aliases[j].metric_expr);
15878c2ecf20Sopenharmony_ci				putchar('\n');
15888c2ecf20Sopenharmony_ci			}
15898c2ecf20Sopenharmony_ci		} else
15908c2ecf20Sopenharmony_ci			printf("  %-50s [Kernel PMU event]\n", aliases[j].name);
15918c2ecf20Sopenharmony_ci		printed++;
15928c2ecf20Sopenharmony_ci	}
15938c2ecf20Sopenharmony_ci	if (printed && pager_in_use())
15948c2ecf20Sopenharmony_ci		printf("\n");
15958c2ecf20Sopenharmony_ciout_free:
15968c2ecf20Sopenharmony_ci	for (j = 0; j < len; j++)
15978c2ecf20Sopenharmony_ci		zfree(&aliases[j].name);
15988c2ecf20Sopenharmony_ci	zfree(&aliases);
15998c2ecf20Sopenharmony_ci	return;
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ciout_enomem:
16028c2ecf20Sopenharmony_ci	printf("FATAL: not enough memory to print PMU events\n");
16038c2ecf20Sopenharmony_ci	if (aliases)
16048c2ecf20Sopenharmony_ci		goto out_free;
16058c2ecf20Sopenharmony_ci}
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_cibool pmu_have_event(const char *pname, const char *name)
16088c2ecf20Sopenharmony_ci{
16098c2ecf20Sopenharmony_ci	struct perf_pmu *pmu;
16108c2ecf20Sopenharmony_ci	struct perf_pmu_alias *alias;
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	pmu = NULL;
16138c2ecf20Sopenharmony_ci	while ((pmu = perf_pmu__scan(pmu)) != NULL) {
16148c2ecf20Sopenharmony_ci		if (strcmp(pname, pmu->name))
16158c2ecf20Sopenharmony_ci			continue;
16168c2ecf20Sopenharmony_ci		list_for_each_entry(alias, &pmu->aliases, list)
16178c2ecf20Sopenharmony_ci			if (!strcmp(alias->name, name))
16188c2ecf20Sopenharmony_ci				return true;
16198c2ecf20Sopenharmony_ci	}
16208c2ecf20Sopenharmony_ci	return false;
16218c2ecf20Sopenharmony_ci}
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_cistatic FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
16248c2ecf20Sopenharmony_ci{
16258c2ecf20Sopenharmony_ci	char path[PATH_MAX];
16268c2ecf20Sopenharmony_ci	const char *sysfs;
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	sysfs = sysfs__mountpoint();
16298c2ecf20Sopenharmony_ci	if (!sysfs)
16308c2ecf20Sopenharmony_ci		return NULL;
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	snprintf(path, PATH_MAX,
16338c2ecf20Sopenharmony_ci		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name);
16348c2ecf20Sopenharmony_ci	if (!file_available(path))
16358c2ecf20Sopenharmony_ci		return NULL;
16368c2ecf20Sopenharmony_ci	return fopen(path, "r");
16378c2ecf20Sopenharmony_ci}
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ciint perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
16408c2ecf20Sopenharmony_ci			...)
16418c2ecf20Sopenharmony_ci{
16428c2ecf20Sopenharmony_ci	va_list args;
16438c2ecf20Sopenharmony_ci	FILE *file;
16448c2ecf20Sopenharmony_ci	int ret = EOF;
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	va_start(args, fmt);
16478c2ecf20Sopenharmony_ci	file = perf_pmu__open_file(pmu, name);
16488c2ecf20Sopenharmony_ci	if (file) {
16498c2ecf20Sopenharmony_ci		ret = vfscanf(file, fmt, args);
16508c2ecf20Sopenharmony_ci		fclose(file);
16518c2ecf20Sopenharmony_ci	}
16528c2ecf20Sopenharmony_ci	va_end(args);
16538c2ecf20Sopenharmony_ci	return ret;
16548c2ecf20Sopenharmony_ci}
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_cistatic int perf_pmu__new_caps(struct list_head *list, char *name, char *value)
16578c2ecf20Sopenharmony_ci{
16588c2ecf20Sopenharmony_ci	struct perf_pmu_caps *caps = zalloc(sizeof(*caps));
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	if (!caps)
16618c2ecf20Sopenharmony_ci		return -ENOMEM;
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci	caps->name = strdup(name);
16648c2ecf20Sopenharmony_ci	if (!caps->name)
16658c2ecf20Sopenharmony_ci		goto free_caps;
16668c2ecf20Sopenharmony_ci	caps->value = strndup(value, strlen(value) - 1);
16678c2ecf20Sopenharmony_ci	if (!caps->value)
16688c2ecf20Sopenharmony_ci		goto free_name;
16698c2ecf20Sopenharmony_ci	list_add_tail(&caps->list, list);
16708c2ecf20Sopenharmony_ci	return 0;
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_cifree_name:
16738c2ecf20Sopenharmony_ci	zfree(&caps->name);
16748c2ecf20Sopenharmony_cifree_caps:
16758c2ecf20Sopenharmony_ci	free(caps);
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci	return -ENOMEM;
16788c2ecf20Sopenharmony_ci}
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci/*
16818c2ecf20Sopenharmony_ci * Reading/parsing the given pmu capabilities, which should be located at:
16828c2ecf20Sopenharmony_ci * /sys/bus/event_source/devices/<dev>/caps as sysfs group attributes.
16838c2ecf20Sopenharmony_ci * Return the number of capabilities
16848c2ecf20Sopenharmony_ci */
16858c2ecf20Sopenharmony_ciint perf_pmu__caps_parse(struct perf_pmu *pmu)
16868c2ecf20Sopenharmony_ci{
16878c2ecf20Sopenharmony_ci	struct stat st;
16888c2ecf20Sopenharmony_ci	char caps_path[PATH_MAX];
16898c2ecf20Sopenharmony_ci	const char *sysfs = sysfs__mountpoint();
16908c2ecf20Sopenharmony_ci	DIR *caps_dir;
16918c2ecf20Sopenharmony_ci	struct dirent *evt_ent;
16928c2ecf20Sopenharmony_ci	int nr_caps = 0;
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	if (!sysfs)
16958c2ecf20Sopenharmony_ci		return -1;
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci	snprintf(caps_path, PATH_MAX,
16988c2ecf20Sopenharmony_ci		 "%s" EVENT_SOURCE_DEVICE_PATH "%s/caps", sysfs, pmu->name);
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci	if (stat(caps_path, &st) < 0)
17018c2ecf20Sopenharmony_ci		return 0;	/* no error if caps does not exist */
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	caps_dir = opendir(caps_path);
17048c2ecf20Sopenharmony_ci	if (!caps_dir)
17058c2ecf20Sopenharmony_ci		return -EINVAL;
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci	while ((evt_ent = readdir(caps_dir)) != NULL) {
17088c2ecf20Sopenharmony_ci		char path[PATH_MAX + NAME_MAX + 1];
17098c2ecf20Sopenharmony_ci		char *name = evt_ent->d_name;
17108c2ecf20Sopenharmony_ci		char value[128];
17118c2ecf20Sopenharmony_ci		FILE *file;
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci		if (!strcmp(name, ".") || !strcmp(name, ".."))
17148c2ecf20Sopenharmony_ci			continue;
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci		snprintf(path, sizeof(path), "%s/%s", caps_path, name);
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci		file = fopen(path, "r");
17198c2ecf20Sopenharmony_ci		if (!file)
17208c2ecf20Sopenharmony_ci			continue;
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci		if (!fgets(value, sizeof(value), file) ||
17238c2ecf20Sopenharmony_ci		    (perf_pmu__new_caps(&pmu->caps, name, value) < 0)) {
17248c2ecf20Sopenharmony_ci			fclose(file);
17258c2ecf20Sopenharmony_ci			continue;
17268c2ecf20Sopenharmony_ci		}
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci		nr_caps++;
17298c2ecf20Sopenharmony_ci		fclose(file);
17308c2ecf20Sopenharmony_ci	}
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci	closedir(caps_dir);
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	return nr_caps;
17358c2ecf20Sopenharmony_ci}
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_civoid perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
17388c2ecf20Sopenharmony_ci				   char *name)
17398c2ecf20Sopenharmony_ci{
17408c2ecf20Sopenharmony_ci	struct perf_pmu_format *format;
17418c2ecf20Sopenharmony_ci	__u64 masks = 0, bits;
17428c2ecf20Sopenharmony_ci	char buf[100];
17438c2ecf20Sopenharmony_ci	unsigned int i;
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	list_for_each_entry(format, &pmu->format, list)	{
17468c2ecf20Sopenharmony_ci		if (format->value != PERF_PMU_FORMAT_VALUE_CONFIG)
17478c2ecf20Sopenharmony_ci			continue;
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci		for_each_set_bit(i, format->bits, PERF_PMU_FORMAT_BITS)
17508c2ecf20Sopenharmony_ci			masks |= 1ULL << i;
17518c2ecf20Sopenharmony_ci	}
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	/*
17548c2ecf20Sopenharmony_ci	 * Kernel doesn't export any valid format bits.
17558c2ecf20Sopenharmony_ci	 */
17568c2ecf20Sopenharmony_ci	if (masks == 0)
17578c2ecf20Sopenharmony_ci		return;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	bits = config & ~masks;
17608c2ecf20Sopenharmony_ci	if (bits == 0)
17618c2ecf20Sopenharmony_ci		return;
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci	bitmap_scnprintf((unsigned long *)&bits, sizeof(bits) * 8, buf, sizeof(buf));
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	pr_warning("WARNING: event '%s' not valid (bits %s of config "
17668c2ecf20Sopenharmony_ci		   "'%llx' not supported by kernel)!\n",
17678c2ecf20Sopenharmony_ci		   name ?: "N/A", buf, config);
17688c2ecf20Sopenharmony_ci}
1769