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