brintos

brintos / linux-shallow public Read only

0
0
Text · 4.8 KiB · 3b8eca0 Raw
220 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright(C) 2015 Linaro Limited. All rights reserved.4 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>5 */6 7#include <dirent.h>8#include <stdbool.h>9#include <linux/coresight-pmu.h>10#include <linux/zalloc.h>11#include <api/fs/fs.h>12 13#include "../../../util/auxtrace.h"14#include "../../../util/debug.h"15#include "../../../util/evlist.h"16#include "../../../util/pmu.h"17#include "../../../util/pmus.h"18#include "cs-etm.h"19#include "arm-spe.h"20#include "hisi-ptt.h"21 22static struct perf_pmu **find_all_arm_spe_pmus(int *nr_spes, int *err)23{24	struct perf_pmu **arm_spe_pmus = NULL;25	int ret, i, nr_cpus = sysconf(_SC_NPROCESSORS_CONF);26	/* arm_spe_xxxxxxxxx\0 */27	char arm_spe_pmu_name[sizeof(ARM_SPE_PMU_NAME) + 10];28 29	arm_spe_pmus = zalloc(sizeof(struct perf_pmu *) * nr_cpus);30	if (!arm_spe_pmus) {31		pr_err("spes alloc failed\n");32		*err = -ENOMEM;33		return NULL;34	}35 36	for (i = 0; i < nr_cpus; i++) {37		ret = sprintf(arm_spe_pmu_name, "%s%d", ARM_SPE_PMU_NAME, i);38		if (ret < 0) {39			pr_err("sprintf failed\n");40			*err = -ENOMEM;41			return NULL;42		}43 44		arm_spe_pmus[*nr_spes] = perf_pmus__find(arm_spe_pmu_name);45		if (arm_spe_pmus[*nr_spes]) {46			pr_debug2("%s %d: arm_spe_pmu %d type %d name %s\n",47				 __func__, __LINE__, *nr_spes,48				 arm_spe_pmus[*nr_spes]->type,49				 arm_spe_pmus[*nr_spes]->name);50			(*nr_spes)++;51		}52	}53 54	return arm_spe_pmus;55}56 57static struct perf_pmu **find_all_hisi_ptt_pmus(int *nr_ptts, int *err)58{59	struct perf_pmu **hisi_ptt_pmus = NULL;60	struct dirent *dent;61	char path[PATH_MAX];62	DIR *dir = NULL;63	int idx = 0;64 65	perf_pmu__event_source_devices_scnprintf(path, sizeof(path));66	dir = opendir(path);67	if (!dir) {68		pr_err("can't read directory '%s'\n", path);69		*err = -EINVAL;70		return NULL;71	}72 73	while ((dent = readdir(dir))) {74		if (strstr(dent->d_name, HISI_PTT_PMU_NAME))75			(*nr_ptts)++;76	}77 78	if (!(*nr_ptts))79		goto out;80 81	hisi_ptt_pmus = zalloc(sizeof(struct perf_pmu *) * (*nr_ptts));82	if (!hisi_ptt_pmus) {83		pr_err("hisi_ptt alloc failed\n");84		*err = -ENOMEM;85		goto out;86	}87 88	rewinddir(dir);89	while ((dent = readdir(dir))) {90		if (strstr(dent->d_name, HISI_PTT_PMU_NAME) && idx < *nr_ptts) {91			hisi_ptt_pmus[idx] = perf_pmus__find(dent->d_name);92			if (hisi_ptt_pmus[idx])93				idx++;94		}95	}96 97out:98	closedir(dir);99	return hisi_ptt_pmus;100}101 102static struct perf_pmu *find_pmu_for_event(struct perf_pmu **pmus,103					   int pmu_nr, struct evsel *evsel)104{105	int i;106 107	if (!pmus)108		return NULL;109 110	for (i = 0; i < pmu_nr; i++) {111		if (evsel->core.attr.type == pmus[i]->type)112			return pmus[i];113	}114 115	return NULL;116}117 118struct auxtrace_record119*auxtrace_record__init(struct evlist *evlist, int *err)120{121	struct perf_pmu	*cs_etm_pmu = NULL;122	struct perf_pmu **arm_spe_pmus = NULL;123	struct perf_pmu **hisi_ptt_pmus = NULL;124	struct evsel *evsel;125	struct perf_pmu *found_etm = NULL;126	struct perf_pmu *found_spe = NULL;127	struct perf_pmu *found_ptt = NULL;128	int auxtrace_event_cnt = 0;129	int nr_spes = 0;130	int nr_ptts = 0;131 132	if (!evlist)133		return NULL;134 135	cs_etm_pmu = perf_pmus__find(CORESIGHT_ETM_PMU_NAME);136	arm_spe_pmus = find_all_arm_spe_pmus(&nr_spes, err);137	hisi_ptt_pmus = find_all_hisi_ptt_pmus(&nr_ptts, err);138 139	evlist__for_each_entry(evlist, evsel) {140		if (cs_etm_pmu && !found_etm)141			found_etm = find_pmu_for_event(&cs_etm_pmu, 1, evsel);142 143		if (arm_spe_pmus && !found_spe)144			found_spe = find_pmu_for_event(arm_spe_pmus, nr_spes, evsel);145 146		if (hisi_ptt_pmus && !found_ptt)147			found_ptt = find_pmu_for_event(hisi_ptt_pmus, nr_ptts, evsel);148	}149 150	free(arm_spe_pmus);151	free(hisi_ptt_pmus);152 153	if (found_etm)154		auxtrace_event_cnt++;155 156	if (found_spe)157		auxtrace_event_cnt++;158 159	if (found_ptt)160		auxtrace_event_cnt++;161 162	if (auxtrace_event_cnt > 1) {163		pr_err("Concurrent AUX trace operation not currently supported\n");164		*err = -EOPNOTSUPP;165		return NULL;166	}167 168	if (found_etm)169		return cs_etm_record_init(err);170 171#if defined(__aarch64__)172	if (found_spe)173		return arm_spe_recording_init(err, found_spe);174 175	if (found_ptt)176		return hisi_ptt_recording_init(err, found_ptt);177#endif178 179	/*180	 * Clear 'err' even if we haven't found an event - that way perf181	 * record can still be used even if tracers aren't present.  The NULL182	 * return value will take care of telling the infrastructure HW tracing183	 * isn't available.184	 */185	*err = 0;186	return NULL;187}188 189#if defined(__arm__)190u64 compat_auxtrace_mmap__read_head(struct auxtrace_mmap *mm)191{192	struct perf_event_mmap_page *pc = mm->userpg;193	u64 result;194 195	__asm__ __volatile__(196"	ldrd    %0, %H0, [%1]"197	: "=&r" (result)198	: "r" (&pc->aux_head), "Qo" (pc->aux_head)199	);200 201	return result;202}203 204int compat_auxtrace_mmap__write_tail(struct auxtrace_mmap *mm, u64 tail)205{206	struct perf_event_mmap_page *pc = mm->userpg;207 208	/* Ensure all reads are done before we write the tail out */209	smp_mb();210 211	__asm__ __volatile__(212"	strd    %2, %H2, [%1]"213	: "=Qo" (pc->aux_tail)214	: "r" (&pc->aux_tail), "r" (tail)215	);216 217	return 0;218}219#endif220