162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Arch specific functions for perf kvm stat.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2014 IBM Corp.
662306a36Sopenharmony_ci * Author(s): Alexander Yarygin <yarygin@linux.vnet.ibm.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <errno.h>
1062306a36Sopenharmony_ci#include <string.h>
1162306a36Sopenharmony_ci#include "../../util/kvm-stat.h"
1262306a36Sopenharmony_ci#include "../../util/evsel.h"
1362306a36Sopenharmony_ci#include <asm/sie.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cidefine_exit_reasons_table(sie_exit_reasons, sie_intercept_code);
1662306a36Sopenharmony_cidefine_exit_reasons_table(sie_icpt_insn_codes, icpt_insn_codes);
1762306a36Sopenharmony_cidefine_exit_reasons_table(sie_sigp_order_codes, sigp_order_codes);
1862306a36Sopenharmony_cidefine_exit_reasons_table(sie_diagnose_codes, diagnose_codes);
1962306a36Sopenharmony_cidefine_exit_reasons_table(sie_icpt_prog_codes, icpt_prog_codes);
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciconst char *vcpu_id_str = "id";
2262306a36Sopenharmony_ciconst char *kvm_exit_reason = "icptcode";
2362306a36Sopenharmony_ciconst char *kvm_entry_trace = "kvm:kvm_s390_sie_enter";
2462306a36Sopenharmony_ciconst char *kvm_exit_trace = "kvm:kvm_s390_sie_exit";
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic void event_icpt_insn_get_key(struct evsel *evsel,
2762306a36Sopenharmony_ci				    struct perf_sample *sample,
2862306a36Sopenharmony_ci				    struct event_key *key)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	unsigned long insn;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	insn = evsel__intval(evsel, sample, "instruction");
3362306a36Sopenharmony_ci	key->key = icpt_insn_decoder(insn);
3462306a36Sopenharmony_ci	key->exit_reasons = sie_icpt_insn_codes;
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic void event_sigp_get_key(struct evsel *evsel,
3862306a36Sopenharmony_ci			       struct perf_sample *sample,
3962306a36Sopenharmony_ci			       struct event_key *key)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	key->key = evsel__intval(evsel, sample, "order_code");
4262306a36Sopenharmony_ci	key->exit_reasons = sie_sigp_order_codes;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic void event_diag_get_key(struct evsel *evsel,
4662306a36Sopenharmony_ci			       struct perf_sample *sample,
4762306a36Sopenharmony_ci			       struct event_key *key)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	key->key = evsel__intval(evsel, sample, "code");
5062306a36Sopenharmony_ci	key->exit_reasons = sie_diagnose_codes;
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic void event_icpt_prog_get_key(struct evsel *evsel,
5462306a36Sopenharmony_ci				    struct perf_sample *sample,
5562306a36Sopenharmony_ci				    struct event_key *key)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	key->key = evsel__intval(evsel, sample, "code");
5862306a36Sopenharmony_ci	key->exit_reasons = sie_icpt_prog_codes;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic struct child_event_ops child_events[] = {
6262306a36Sopenharmony_ci	{ .name = "kvm:kvm_s390_intercept_instruction",
6362306a36Sopenharmony_ci	  .get_key = event_icpt_insn_get_key },
6462306a36Sopenharmony_ci	{ .name = "kvm:kvm_s390_handle_sigp",
6562306a36Sopenharmony_ci	  .get_key = event_sigp_get_key },
6662306a36Sopenharmony_ci	{ .name = "kvm:kvm_s390_handle_diag",
6762306a36Sopenharmony_ci	  .get_key = event_diag_get_key },
6862306a36Sopenharmony_ci	{ .name = "kvm:kvm_s390_intercept_prog",
6962306a36Sopenharmony_ci	  .get_key = event_icpt_prog_get_key },
7062306a36Sopenharmony_ci	{ NULL, NULL },
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic struct kvm_events_ops exit_events = {
7462306a36Sopenharmony_ci	.is_begin_event = exit_event_begin,
7562306a36Sopenharmony_ci	.is_end_event = exit_event_end,
7662306a36Sopenharmony_ci	.child_ops = child_events,
7762306a36Sopenharmony_ci	.decode_key = exit_event_decode_key,
7862306a36Sopenharmony_ci	.name = "VM-EXIT"
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ciconst char *kvm_events_tp[] = {
8262306a36Sopenharmony_ci	"kvm:kvm_s390_sie_enter",
8362306a36Sopenharmony_ci	"kvm:kvm_s390_sie_exit",
8462306a36Sopenharmony_ci	"kvm:kvm_s390_intercept_instruction",
8562306a36Sopenharmony_ci	"kvm:kvm_s390_handle_sigp",
8662306a36Sopenharmony_ci	"kvm:kvm_s390_handle_diag",
8762306a36Sopenharmony_ci	"kvm:kvm_s390_intercept_prog",
8862306a36Sopenharmony_ci	NULL,
8962306a36Sopenharmony_ci};
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistruct kvm_reg_events_ops kvm_reg_events_ops[] = {
9262306a36Sopenharmony_ci	{ .name = "vmexit", .ops = &exit_events },
9362306a36Sopenharmony_ci	{ NULL, NULL },
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ciconst char * const kvm_skip_events[] = {
9762306a36Sopenharmony_ci	"Wait state",
9862306a36Sopenharmony_ci	NULL,
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ciint cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	if (strstr(cpuid, "IBM")) {
10462306a36Sopenharmony_ci		kvm->exit_reasons = sie_exit_reasons;
10562306a36Sopenharmony_ci		kvm->exit_reasons_isa = "SIE";
10662306a36Sopenharmony_ci	} else
10762306a36Sopenharmony_ci		return -ENOTSUP;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	return 0;
11062306a36Sopenharmony_ci}
111