18c2ecf20Sopenharmony_ci#include <stdbool.h>
28c2ecf20Sopenharmony_ci#include <stdlib.h>
38c2ecf20Sopenharmony_ci#include <linux/kernel.h>
48c2ecf20Sopenharmony_ci#include <linux/types.h>
58c2ecf20Sopenharmony_ci#include <linux/bitops.h>
68c2ecf20Sopenharmony_ci#include <linux/log2.h>
78c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "../../util/evlist.h"
108c2ecf20Sopenharmony_ci#include "../../util/auxtrace.h"
118c2ecf20Sopenharmony_ci#include "../../util/evsel.h"
128c2ecf20Sopenharmony_ci#include "../../util/record.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define PERF_EVENT_CPUM_SF		0xB0000 /* Event: Basic-sampling */
158c2ecf20Sopenharmony_ci#define PERF_EVENT_CPUM_SF_DIAG		0xBD000 /* Event: Combined-sampling */
168c2ecf20Sopenharmony_ci#define DEFAULT_AUX_PAGES		128
178c2ecf20Sopenharmony_ci#define DEFAULT_FREQ			4000
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic void cpumsf_free(struct auxtrace_record *itr)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	free(itr);
228c2ecf20Sopenharmony_ci}
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic size_t cpumsf_info_priv_size(struct auxtrace_record *itr __maybe_unused,
258c2ecf20Sopenharmony_ci				    struct evlist *evlist __maybe_unused)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	return 0;
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic int
318c2ecf20Sopenharmony_cicpumsf_info_fill(struct auxtrace_record *itr __maybe_unused,
328c2ecf20Sopenharmony_ci		 struct perf_session *session __maybe_unused,
338c2ecf20Sopenharmony_ci		 struct perf_record_auxtrace_info *auxtrace_info __maybe_unused,
348c2ecf20Sopenharmony_ci		 size_t priv_size __maybe_unused)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	auxtrace_info->type = PERF_AUXTRACE_S390_CPUMSF;
378c2ecf20Sopenharmony_ci	return 0;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic unsigned long
418c2ecf20Sopenharmony_cicpumsf_reference(struct auxtrace_record *itr __maybe_unused)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	return 0;
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic int
478c2ecf20Sopenharmony_cicpumsf_recording_options(struct auxtrace_record *ar __maybe_unused,
488c2ecf20Sopenharmony_ci			 struct evlist *evlist __maybe_unused,
498c2ecf20Sopenharmony_ci			 struct record_opts *opts)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	unsigned int factor = 1;
528c2ecf20Sopenharmony_ci	unsigned int pages;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	opts->full_auxtrace = true;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	/*
578c2ecf20Sopenharmony_ci	 * The AUX buffer size should be set properly to avoid
588c2ecf20Sopenharmony_ci	 * overflow of samples if it is not set explicitly.
598c2ecf20Sopenharmony_ci	 * DEFAULT_AUX_PAGES is an proper size when sampling frequency
608c2ecf20Sopenharmony_ci	 * is DEFAULT_FREQ. It is expected to hold about 1/2 second
618c2ecf20Sopenharmony_ci	 * of sampling data. The size used for AUX buffer will scale
628c2ecf20Sopenharmony_ci	 * according to the specified frequency and DEFAULT_FREQ.
638c2ecf20Sopenharmony_ci	 */
648c2ecf20Sopenharmony_ci	if (!opts->auxtrace_mmap_pages) {
658c2ecf20Sopenharmony_ci		if (opts->user_freq != UINT_MAX)
668c2ecf20Sopenharmony_ci			factor = (opts->user_freq + DEFAULT_FREQ
678c2ecf20Sopenharmony_ci				  - 1) / DEFAULT_FREQ;
688c2ecf20Sopenharmony_ci		pages = DEFAULT_AUX_PAGES * factor;
698c2ecf20Sopenharmony_ci		opts->auxtrace_mmap_pages = roundup_pow_of_two(pages);
708c2ecf20Sopenharmony_ci	}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	return 0;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic int
768c2ecf20Sopenharmony_cicpumsf_parse_snapshot_options(struct auxtrace_record *itr __maybe_unused,
778c2ecf20Sopenharmony_ci			      struct record_opts *opts __maybe_unused,
788c2ecf20Sopenharmony_ci			      const char *str __maybe_unused)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	return 0;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/*
848c2ecf20Sopenharmony_ci * auxtrace_record__init is called when perf record
858c2ecf20Sopenharmony_ci * check if the event really need auxtrace
868c2ecf20Sopenharmony_ci */
878c2ecf20Sopenharmony_cistruct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
888c2ecf20Sopenharmony_ci					      int *err)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	struct auxtrace_record *aux;
918c2ecf20Sopenharmony_ci	struct evsel *pos;
928c2ecf20Sopenharmony_ci	int diagnose = 0;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	*err = 0;
958c2ecf20Sopenharmony_ci	if (evlist->core.nr_entries == 0)
968c2ecf20Sopenharmony_ci		return NULL;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
998c2ecf20Sopenharmony_ci		if (pos->core.attr.config == PERF_EVENT_CPUM_SF_DIAG) {
1008c2ecf20Sopenharmony_ci			diagnose = 1;
1018c2ecf20Sopenharmony_ci			break;
1028c2ecf20Sopenharmony_ci		}
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	if (!diagnose)
1068c2ecf20Sopenharmony_ci		return NULL;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	/* sampling in diagnose mode. alloc aux buffer */
1098c2ecf20Sopenharmony_ci	aux = zalloc(sizeof(*aux));
1108c2ecf20Sopenharmony_ci	if (aux == NULL) {
1118c2ecf20Sopenharmony_ci		*err = -ENOMEM;
1128c2ecf20Sopenharmony_ci		return NULL;
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	aux->parse_snapshot_options = cpumsf_parse_snapshot_options;
1168c2ecf20Sopenharmony_ci	aux->recording_options = cpumsf_recording_options;
1178c2ecf20Sopenharmony_ci	aux->info_priv_size = cpumsf_info_priv_size;
1188c2ecf20Sopenharmony_ci	aux->info_fill = cpumsf_info_fill;
1198c2ecf20Sopenharmony_ci	aux->free = cpumsf_free;
1208c2ecf20Sopenharmony_ci	aux->reference = cpumsf_reference;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	return aux;
1238c2ecf20Sopenharmony_ci}
124