18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * handling kvm guest interrupts 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2008, 2020 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author(s): Carsten Otte <cotte@de.ibm.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "kvm-s390" 118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 148c2ecf20Sopenharmony_ci#include <linux/kvm_host.h> 158c2ecf20Sopenharmony_ci#include <linux/hrtimer.h> 168c2ecf20Sopenharmony_ci#include <linux/mmu_context.h> 178c2ecf20Sopenharmony_ci#include <linux/nospec.h> 188c2ecf20Sopenharmony_ci#include <linux/signal.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 218c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 228c2ecf20Sopenharmony_ci#include <asm/asm-offsets.h> 238c2ecf20Sopenharmony_ci#include <asm/dis.h> 248c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 258c2ecf20Sopenharmony_ci#include <asm/sclp.h> 268c2ecf20Sopenharmony_ci#include <asm/isc.h> 278c2ecf20Sopenharmony_ci#include <asm/gmap.h> 288c2ecf20Sopenharmony_ci#include <asm/switch_to.h> 298c2ecf20Sopenharmony_ci#include <asm/nmi.h> 308c2ecf20Sopenharmony_ci#include <asm/airq.h> 318c2ecf20Sopenharmony_ci#include "kvm-s390.h" 328c2ecf20Sopenharmony_ci#include "gaccess.h" 338c2ecf20Sopenharmony_ci#include "trace-s390.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define PFAULT_INIT 0x0600 368c2ecf20Sopenharmony_ci#define PFAULT_DONE 0x0680 378c2ecf20Sopenharmony_ci#define VIRTIO_PARAM 0x0d00 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic struct kvm_s390_gib *gib; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* handle external calls via sigp interpretation facility */ 428c2ecf20Sopenharmony_cistatic int sca_ext_call_pending(struct kvm_vcpu *vcpu, int *src_id) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci int c, scn; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (!kvm_s390_test_cpuflags(vcpu, CPUSTAT_ECALL_PEND)) 478c2ecf20Sopenharmony_ci return 0; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci BUG_ON(!kvm_s390_use_sca_entries()); 508c2ecf20Sopenharmony_ci read_lock(&vcpu->kvm->arch.sca_lock); 518c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.use_esca) { 528c2ecf20Sopenharmony_ci struct esca_block *sca = vcpu->kvm->arch.sca; 538c2ecf20Sopenharmony_ci union esca_sigp_ctrl sigp_ctrl = 548c2ecf20Sopenharmony_ci sca->cpu[vcpu->vcpu_id].sigp_ctrl; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci c = sigp_ctrl.c; 578c2ecf20Sopenharmony_ci scn = sigp_ctrl.scn; 588c2ecf20Sopenharmony_ci } else { 598c2ecf20Sopenharmony_ci struct bsca_block *sca = vcpu->kvm->arch.sca; 608c2ecf20Sopenharmony_ci union bsca_sigp_ctrl sigp_ctrl = 618c2ecf20Sopenharmony_ci sca->cpu[vcpu->vcpu_id].sigp_ctrl; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci c = sigp_ctrl.c; 648c2ecf20Sopenharmony_ci scn = sigp_ctrl.scn; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci read_unlock(&vcpu->kvm->arch.sca_lock); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (src_id) 698c2ecf20Sopenharmony_ci *src_id = scn; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return c; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci int expect, rc; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci BUG_ON(!kvm_s390_use_sca_entries()); 798c2ecf20Sopenharmony_ci read_lock(&vcpu->kvm->arch.sca_lock); 808c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.use_esca) { 818c2ecf20Sopenharmony_ci struct esca_block *sca = vcpu->kvm->arch.sca; 828c2ecf20Sopenharmony_ci union esca_sigp_ctrl *sigp_ctrl = 838c2ecf20Sopenharmony_ci &(sca->cpu[vcpu->vcpu_id].sigp_ctrl); 848c2ecf20Sopenharmony_ci union esca_sigp_ctrl new_val = {0}, old_val; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci old_val = READ_ONCE(*sigp_ctrl); 878c2ecf20Sopenharmony_ci new_val.scn = src_id; 888c2ecf20Sopenharmony_ci new_val.c = 1; 898c2ecf20Sopenharmony_ci old_val.c = 0; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci expect = old_val.value; 928c2ecf20Sopenharmony_ci rc = cmpxchg(&sigp_ctrl->value, old_val.value, new_val.value); 938c2ecf20Sopenharmony_ci } else { 948c2ecf20Sopenharmony_ci struct bsca_block *sca = vcpu->kvm->arch.sca; 958c2ecf20Sopenharmony_ci union bsca_sigp_ctrl *sigp_ctrl = 968c2ecf20Sopenharmony_ci &(sca->cpu[vcpu->vcpu_id].sigp_ctrl); 978c2ecf20Sopenharmony_ci union bsca_sigp_ctrl new_val = {0}, old_val; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci old_val = READ_ONCE(*sigp_ctrl); 1008c2ecf20Sopenharmony_ci new_val.scn = src_id; 1018c2ecf20Sopenharmony_ci new_val.c = 1; 1028c2ecf20Sopenharmony_ci old_val.c = 0; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci expect = old_val.value; 1058c2ecf20Sopenharmony_ci rc = cmpxchg(&sigp_ctrl->value, old_val.value, new_val.value); 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci read_unlock(&vcpu->kvm->arch.sca_lock); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (rc != expect) { 1108c2ecf20Sopenharmony_ci /* another external call is pending */ 1118c2ecf20Sopenharmony_ci return -EBUSY; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_ECALL_PEND); 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic void sca_clear_ext_call(struct kvm_vcpu *vcpu) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci int rc, expect; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (!kvm_s390_use_sca_entries()) 1228c2ecf20Sopenharmony_ci return; 1238c2ecf20Sopenharmony_ci kvm_s390_clear_cpuflags(vcpu, CPUSTAT_ECALL_PEND); 1248c2ecf20Sopenharmony_ci read_lock(&vcpu->kvm->arch.sca_lock); 1258c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.use_esca) { 1268c2ecf20Sopenharmony_ci struct esca_block *sca = vcpu->kvm->arch.sca; 1278c2ecf20Sopenharmony_ci union esca_sigp_ctrl *sigp_ctrl = 1288c2ecf20Sopenharmony_ci &(sca->cpu[vcpu->vcpu_id].sigp_ctrl); 1298c2ecf20Sopenharmony_ci union esca_sigp_ctrl old; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci old = READ_ONCE(*sigp_ctrl); 1328c2ecf20Sopenharmony_ci expect = old.value; 1338c2ecf20Sopenharmony_ci rc = cmpxchg(&sigp_ctrl->value, old.value, 0); 1348c2ecf20Sopenharmony_ci } else { 1358c2ecf20Sopenharmony_ci struct bsca_block *sca = vcpu->kvm->arch.sca; 1368c2ecf20Sopenharmony_ci union bsca_sigp_ctrl *sigp_ctrl = 1378c2ecf20Sopenharmony_ci &(sca->cpu[vcpu->vcpu_id].sigp_ctrl); 1388c2ecf20Sopenharmony_ci union bsca_sigp_ctrl old; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci old = READ_ONCE(*sigp_ctrl); 1418c2ecf20Sopenharmony_ci expect = old.value; 1428c2ecf20Sopenharmony_ci rc = cmpxchg(&sigp_ctrl->value, old.value, 0); 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci read_unlock(&vcpu->kvm->arch.sca_lock); 1458c2ecf20Sopenharmony_ci WARN_ON(rc != expect); /* cannot clear? */ 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ciint psw_extint_disabled(struct kvm_vcpu *vcpu) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT); 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic int psw_ioint_disabled(struct kvm_vcpu *vcpu) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic int psw_mchk_disabled(struct kvm_vcpu *vcpu) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_MCHECK); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int psw_interrupts_disabled(struct kvm_vcpu *vcpu) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci return psw_extint_disabled(vcpu) && 1668c2ecf20Sopenharmony_ci psw_ioint_disabled(vcpu) && 1678c2ecf20Sopenharmony_ci psw_mchk_disabled(vcpu); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int ckc_interrupts_enabled(struct kvm_vcpu *vcpu) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci if (psw_extint_disabled(vcpu) || 1738c2ecf20Sopenharmony_ci !(vcpu->arch.sie_block->gcr[0] & CR0_CLOCK_COMPARATOR_SUBMASK)) 1748c2ecf20Sopenharmony_ci return 0; 1758c2ecf20Sopenharmony_ci if (guestdbg_enabled(vcpu) && guestdbg_sstep_enabled(vcpu)) 1768c2ecf20Sopenharmony_ci /* No timer interrupts when single stepping */ 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci return 1; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int ckc_irq_pending(struct kvm_vcpu *vcpu) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci const u64 now = kvm_s390_get_tod_clock_fast(vcpu->kvm); 1848c2ecf20Sopenharmony_ci const u64 ckc = vcpu->arch.sie_block->ckc; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gcr[0] & CR0_CLOCK_COMPARATOR_SIGN) { 1878c2ecf20Sopenharmony_ci if ((s64)ckc >= (s64)now) 1888c2ecf20Sopenharmony_ci return 0; 1898c2ecf20Sopenharmony_ci } else if (ckc >= now) { 1908c2ecf20Sopenharmony_ci return 0; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci return ckc_interrupts_enabled(vcpu); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int cpu_timer_interrupts_enabled(struct kvm_vcpu *vcpu) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci return !psw_extint_disabled(vcpu) && 1988c2ecf20Sopenharmony_ci (vcpu->arch.sie_block->gcr[0] & CR0_CPU_TIMER_SUBMASK); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic int cpu_timer_irq_pending(struct kvm_vcpu *vcpu) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci if (!cpu_timer_interrupts_enabled(vcpu)) 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci return kvm_s390_get_cpu_timer(vcpu) >> 63; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic uint64_t isc_to_isc_bits(int isc) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci return (0x80 >> isc) << 24; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic inline u32 isc_to_int_word(u8 isc) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci return ((u32)isc << 27) | 0x80000000; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic inline u8 int_word_to_isc(u32 int_word) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci return (int_word & 0x38000000) >> 27; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* 2248c2ecf20Sopenharmony_ci * To use atomic bitmap functions, we have to provide a bitmap address 2258c2ecf20Sopenharmony_ci * that is u64 aligned. However, the ipm might be u32 aligned. 2268c2ecf20Sopenharmony_ci * Therefore, we logically start the bitmap at the very beginning of the 2278c2ecf20Sopenharmony_ci * struct and fixup the bit number. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci#define IPM_BIT_OFFSET (offsetof(struct kvm_s390_gisa, ipm) * BITS_PER_BYTE) 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/** 2328c2ecf20Sopenharmony_ci * gisa_set_iam - change the GISA interruption alert mask 2338c2ecf20Sopenharmony_ci * 2348c2ecf20Sopenharmony_ci * @gisa: gisa to operate on 2358c2ecf20Sopenharmony_ci * @iam: new IAM value to use 2368c2ecf20Sopenharmony_ci * 2378c2ecf20Sopenharmony_ci * Change the IAM atomically with the next alert address and the IPM 2388c2ecf20Sopenharmony_ci * of the GISA if the GISA is not part of the GIB alert list. All three 2398c2ecf20Sopenharmony_ci * fields are located in the first long word of the GISA. 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * Returns: 0 on success 2428c2ecf20Sopenharmony_ci * -EBUSY in case the gisa is part of the alert list 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cistatic inline int gisa_set_iam(struct kvm_s390_gisa *gisa, u8 iam) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci u64 word, _word; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci do { 2498c2ecf20Sopenharmony_ci word = READ_ONCE(gisa->u64.word[0]); 2508c2ecf20Sopenharmony_ci if ((u64)gisa != word >> 32) 2518c2ecf20Sopenharmony_ci return -EBUSY; 2528c2ecf20Sopenharmony_ci _word = (word & ~0xffUL) | iam; 2538c2ecf20Sopenharmony_ci } while (cmpxchg(&gisa->u64.word[0], word, _word) != word); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci return 0; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci/** 2598c2ecf20Sopenharmony_ci * gisa_clear_ipm - clear the GISA interruption pending mask 2608c2ecf20Sopenharmony_ci * 2618c2ecf20Sopenharmony_ci * @gisa: gisa to operate on 2628c2ecf20Sopenharmony_ci * 2638c2ecf20Sopenharmony_ci * Clear the IPM atomically with the next alert address and the IAM 2648c2ecf20Sopenharmony_ci * of the GISA unconditionally. All three fields are located in the 2658c2ecf20Sopenharmony_ci * first long word of the GISA. 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_cistatic inline void gisa_clear_ipm(struct kvm_s390_gisa *gisa) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci u64 word, _word; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci do { 2728c2ecf20Sopenharmony_ci word = READ_ONCE(gisa->u64.word[0]); 2738c2ecf20Sopenharmony_ci _word = word & ~(0xffUL << 24); 2748c2ecf20Sopenharmony_ci } while (cmpxchg(&gisa->u64.word[0], word, _word) != word); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci/** 2788c2ecf20Sopenharmony_ci * gisa_get_ipm_or_restore_iam - return IPM or restore GISA IAM 2798c2ecf20Sopenharmony_ci * 2808c2ecf20Sopenharmony_ci * @gi: gisa interrupt struct to work on 2818c2ecf20Sopenharmony_ci * 2828c2ecf20Sopenharmony_ci * Atomically restores the interruption alert mask if none of the 2838c2ecf20Sopenharmony_ci * relevant ISCs are pending and return the IPM. 2848c2ecf20Sopenharmony_ci * 2858c2ecf20Sopenharmony_ci * Returns: the relevant pending ISCs 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_cistatic inline u8 gisa_get_ipm_or_restore_iam(struct kvm_s390_gisa_interrupt *gi) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci u8 pending_mask, alert_mask; 2908c2ecf20Sopenharmony_ci u64 word, _word; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci do { 2938c2ecf20Sopenharmony_ci word = READ_ONCE(gi->origin->u64.word[0]); 2948c2ecf20Sopenharmony_ci alert_mask = READ_ONCE(gi->alert.mask); 2958c2ecf20Sopenharmony_ci pending_mask = (u8)(word >> 24) & alert_mask; 2968c2ecf20Sopenharmony_ci if (pending_mask) 2978c2ecf20Sopenharmony_ci return pending_mask; 2988c2ecf20Sopenharmony_ci _word = (word & ~0xffUL) | alert_mask; 2998c2ecf20Sopenharmony_ci } while (cmpxchg(&gi->origin->u64.word[0], word, _word) != word); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci return 0; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic inline int gisa_in_alert_list(struct kvm_s390_gisa *gisa) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci return READ_ONCE(gisa->next_alert) != (u32)(u64)gisa; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic inline void gisa_set_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci set_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic inline u8 gisa_get_ipm(struct kvm_s390_gisa *gisa) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci return READ_ONCE(gisa->ipm); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic inline void gisa_clear_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci clear_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa); 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic inline int gisa_tac_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gisc) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci return test_and_clear_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic inline unsigned long pending_irqs_no_gisa(struct kvm_vcpu *vcpu) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci unsigned long pending = vcpu->kvm->arch.float_int.pending_irqs | 3328c2ecf20Sopenharmony_ci vcpu->arch.local_int.pending_irqs; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci pending &= ~vcpu->kvm->arch.float_int.masked_irqs; 3358c2ecf20Sopenharmony_ci return pending; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic inline unsigned long pending_irqs(struct kvm_vcpu *vcpu) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct kvm_s390_gisa_interrupt *gi = &vcpu->kvm->arch.gisa_int; 3418c2ecf20Sopenharmony_ci unsigned long pending_mask; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci pending_mask = pending_irqs_no_gisa(vcpu); 3448c2ecf20Sopenharmony_ci if (gi->origin) 3458c2ecf20Sopenharmony_ci pending_mask |= gisa_get_ipm(gi->origin) << IRQ_PEND_IO_ISC_7; 3468c2ecf20Sopenharmony_ci return pending_mask; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic inline int isc_to_irq_type(unsigned long isc) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci return IRQ_PEND_IO_ISC_0 - isc; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic inline int irq_type_to_isc(unsigned long irq_type) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci return IRQ_PEND_IO_ISC_0 - irq_type; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic unsigned long disable_iscs(struct kvm_vcpu *vcpu, 3608c2ecf20Sopenharmony_ci unsigned long active_mask) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci int i; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci for (i = 0; i <= MAX_ISC; i++) 3658c2ecf20Sopenharmony_ci if (!(vcpu->arch.sie_block->gcr[6] & isc_to_isc_bits(i))) 3668c2ecf20Sopenharmony_ci active_mask &= ~(1UL << (isc_to_irq_type(i))); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci return active_mask; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic unsigned long deliverable_irqs(struct kvm_vcpu *vcpu) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci unsigned long active_mask; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci active_mask = pending_irqs(vcpu); 3768c2ecf20Sopenharmony_ci if (!active_mask) 3778c2ecf20Sopenharmony_ci return 0; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (psw_extint_disabled(vcpu)) 3808c2ecf20Sopenharmony_ci active_mask &= ~IRQ_PEND_EXT_MASK; 3818c2ecf20Sopenharmony_ci if (psw_ioint_disabled(vcpu)) 3828c2ecf20Sopenharmony_ci active_mask &= ~IRQ_PEND_IO_MASK; 3838c2ecf20Sopenharmony_ci else 3848c2ecf20Sopenharmony_ci active_mask = disable_iscs(vcpu, active_mask); 3858c2ecf20Sopenharmony_ci if (!(vcpu->arch.sie_block->gcr[0] & CR0_EXTERNAL_CALL_SUBMASK)) 3868c2ecf20Sopenharmony_ci __clear_bit(IRQ_PEND_EXT_EXTERNAL, &active_mask); 3878c2ecf20Sopenharmony_ci if (!(vcpu->arch.sie_block->gcr[0] & CR0_EMERGENCY_SIGNAL_SUBMASK)) 3888c2ecf20Sopenharmony_ci __clear_bit(IRQ_PEND_EXT_EMERGENCY, &active_mask); 3898c2ecf20Sopenharmony_ci if (!(vcpu->arch.sie_block->gcr[0] & CR0_CLOCK_COMPARATOR_SUBMASK)) 3908c2ecf20Sopenharmony_ci __clear_bit(IRQ_PEND_EXT_CLOCK_COMP, &active_mask); 3918c2ecf20Sopenharmony_ci if (!(vcpu->arch.sie_block->gcr[0] & CR0_CPU_TIMER_SUBMASK)) 3928c2ecf20Sopenharmony_ci __clear_bit(IRQ_PEND_EXT_CPU_TIMER, &active_mask); 3938c2ecf20Sopenharmony_ci if (!(vcpu->arch.sie_block->gcr[0] & CR0_SERVICE_SIGNAL_SUBMASK)) { 3948c2ecf20Sopenharmony_ci __clear_bit(IRQ_PEND_EXT_SERVICE, &active_mask); 3958c2ecf20Sopenharmony_ci __clear_bit(IRQ_PEND_EXT_SERVICE_EV, &active_mask); 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci if (psw_mchk_disabled(vcpu)) 3988c2ecf20Sopenharmony_ci active_mask &= ~IRQ_PEND_MCHK_MASK; 3998c2ecf20Sopenharmony_ci /* PV guest cpus can have a single interruption injected at a time. */ 4008c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_get_handle(vcpu) && 4018c2ecf20Sopenharmony_ci vcpu->arch.sie_block->iictl != IICTL_CODE_NONE) 4028c2ecf20Sopenharmony_ci active_mask &= ~(IRQ_PEND_EXT_II_MASK | 4038c2ecf20Sopenharmony_ci IRQ_PEND_IO_MASK | 4048c2ecf20Sopenharmony_ci IRQ_PEND_MCHK_MASK); 4058c2ecf20Sopenharmony_ci /* 4068c2ecf20Sopenharmony_ci * Check both floating and local interrupt's cr14 because 4078c2ecf20Sopenharmony_ci * bit IRQ_PEND_MCHK_REP could be set in both cases. 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_ci if (!(vcpu->arch.sie_block->gcr[14] & 4108c2ecf20Sopenharmony_ci (vcpu->kvm->arch.float_int.mchk.cr14 | 4118c2ecf20Sopenharmony_ci vcpu->arch.local_int.irq.mchk.cr14))) 4128c2ecf20Sopenharmony_ci __clear_bit(IRQ_PEND_MCHK_REP, &active_mask); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci /* 4158c2ecf20Sopenharmony_ci * STOP irqs will never be actively delivered. They are triggered via 4168c2ecf20Sopenharmony_ci * intercept requests and cleared when the stop intercept is performed. 4178c2ecf20Sopenharmony_ci */ 4188c2ecf20Sopenharmony_ci __clear_bit(IRQ_PEND_SIGP_STOP, &active_mask); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return active_mask; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic void __set_cpu_idle(struct kvm_vcpu *vcpu) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_WAIT); 4268c2ecf20Sopenharmony_ci set_bit(kvm_vcpu_get_idx(vcpu), vcpu->kvm->arch.idle_mask); 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic void __unset_cpu_idle(struct kvm_vcpu *vcpu) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci kvm_s390_clear_cpuflags(vcpu, CPUSTAT_WAIT); 4328c2ecf20Sopenharmony_ci clear_bit(kvm_vcpu_get_idx(vcpu), vcpu->kvm->arch.idle_mask); 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic void __reset_intercept_indicators(struct kvm_vcpu *vcpu) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci kvm_s390_clear_cpuflags(vcpu, CPUSTAT_IO_INT | CPUSTAT_EXT_INT | 4388c2ecf20Sopenharmony_ci CPUSTAT_STOP_INT); 4398c2ecf20Sopenharmony_ci vcpu->arch.sie_block->lctl = 0x0000; 4408c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ictl &= ~(ICTL_LPSW | ICTL_STCTL | ICTL_PINT); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (guestdbg_enabled(vcpu)) { 4438c2ecf20Sopenharmony_ci vcpu->arch.sie_block->lctl |= (LCTL_CR0 | LCTL_CR9 | 4448c2ecf20Sopenharmony_ci LCTL_CR10 | LCTL_CR11); 4458c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ictl |= (ICTL_STCTL | ICTL_PINT); 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic void set_intercept_indicators_io(struct kvm_vcpu *vcpu) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci if (!(pending_irqs_no_gisa(vcpu) & IRQ_PEND_IO_MASK)) 4528c2ecf20Sopenharmony_ci return; 4538c2ecf20Sopenharmony_ci if (psw_ioint_disabled(vcpu)) 4548c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_IO_INT); 4558c2ecf20Sopenharmony_ci else 4568c2ecf20Sopenharmony_ci vcpu->arch.sie_block->lctl |= LCTL_CR6; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic void set_intercept_indicators_ext(struct kvm_vcpu *vcpu) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci if (!(pending_irqs_no_gisa(vcpu) & IRQ_PEND_EXT_MASK)) 4628c2ecf20Sopenharmony_ci return; 4638c2ecf20Sopenharmony_ci if (psw_extint_disabled(vcpu)) 4648c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_EXT_INT); 4658c2ecf20Sopenharmony_ci else 4668c2ecf20Sopenharmony_ci vcpu->arch.sie_block->lctl |= LCTL_CR0; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic void set_intercept_indicators_mchk(struct kvm_vcpu *vcpu) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci if (!(pending_irqs_no_gisa(vcpu) & IRQ_PEND_MCHK_MASK)) 4728c2ecf20Sopenharmony_ci return; 4738c2ecf20Sopenharmony_ci if (psw_mchk_disabled(vcpu)) 4748c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ictl |= ICTL_LPSW; 4758c2ecf20Sopenharmony_ci else 4768c2ecf20Sopenharmony_ci vcpu->arch.sie_block->lctl |= LCTL_CR14; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic void set_intercept_indicators_stop(struct kvm_vcpu *vcpu) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci if (kvm_s390_is_stop_irq_pending(vcpu)) 4828c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_STOP_INT); 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci/* Set interception request for non-deliverable interrupts */ 4868c2ecf20Sopenharmony_cistatic void set_intercept_indicators(struct kvm_vcpu *vcpu) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci set_intercept_indicators_io(vcpu); 4898c2ecf20Sopenharmony_ci set_intercept_indicators_ext(vcpu); 4908c2ecf20Sopenharmony_ci set_intercept_indicators_mchk(vcpu); 4918c2ecf20Sopenharmony_ci set_intercept_indicators_stop(vcpu); 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic int __must_check __deliver_cpu_timer(struct kvm_vcpu *vcpu) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 4978c2ecf20Sopenharmony_ci int rc = 0; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci vcpu->stat.deliver_cputm++; 5008c2ecf20Sopenharmony_ci trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_CPU_TIMER, 5018c2ecf20Sopenharmony_ci 0, 0); 5028c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 5038c2ecf20Sopenharmony_ci vcpu->arch.sie_block->iictl = IICTL_CODE_EXT; 5048c2ecf20Sopenharmony_ci vcpu->arch.sie_block->eic = EXT_IRQ_CPU_TIMER; 5058c2ecf20Sopenharmony_ci } else { 5068c2ecf20Sopenharmony_ci rc = put_guest_lc(vcpu, EXT_IRQ_CPU_TIMER, 5078c2ecf20Sopenharmony_ci (u16 *)__LC_EXT_INT_CODE); 5088c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, 0, (u16 *)__LC_EXT_CPU_ADDR); 5098c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, 5108c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 5118c2ecf20Sopenharmony_ci rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, 5128c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs); 5158c2ecf20Sopenharmony_ci return rc ? -EFAULT : 0; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic int __must_check __deliver_ckc(struct kvm_vcpu *vcpu) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 5218c2ecf20Sopenharmony_ci int rc = 0; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci vcpu->stat.deliver_ckc++; 5248c2ecf20Sopenharmony_ci trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_CLOCK_COMP, 5258c2ecf20Sopenharmony_ci 0, 0); 5268c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 5278c2ecf20Sopenharmony_ci vcpu->arch.sie_block->iictl = IICTL_CODE_EXT; 5288c2ecf20Sopenharmony_ci vcpu->arch.sie_block->eic = EXT_IRQ_CLK_COMP; 5298c2ecf20Sopenharmony_ci } else { 5308c2ecf20Sopenharmony_ci rc = put_guest_lc(vcpu, EXT_IRQ_CLK_COMP, 5318c2ecf20Sopenharmony_ci (u16 __user *)__LC_EXT_INT_CODE); 5328c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, 0, (u16 *)__LC_EXT_CPU_ADDR); 5338c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, 5348c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 5358c2ecf20Sopenharmony_ci rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, 5368c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_EXT_CLOCK_COMP, &li->pending_irqs); 5398c2ecf20Sopenharmony_ci return rc ? -EFAULT : 0; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic int __must_check __deliver_pfault_init(struct kvm_vcpu *vcpu) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 5458c2ecf20Sopenharmony_ci struct kvm_s390_ext_info ext; 5468c2ecf20Sopenharmony_ci int rc; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci spin_lock(&li->lock); 5498c2ecf20Sopenharmony_ci ext = li->irq.ext; 5508c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_PFAULT_INIT, &li->pending_irqs); 5518c2ecf20Sopenharmony_ci li->irq.ext.ext_params2 = 0; 5528c2ecf20Sopenharmony_ci spin_unlock(&li->lock); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "deliver: pfault init token 0x%llx", 5558c2ecf20Sopenharmony_ci ext.ext_params2); 5568c2ecf20Sopenharmony_ci trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, 5578c2ecf20Sopenharmony_ci KVM_S390_INT_PFAULT_INIT, 5588c2ecf20Sopenharmony_ci 0, ext.ext_params2); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci rc = put_guest_lc(vcpu, EXT_IRQ_CP_SERVICE, (u16 *) __LC_EXT_INT_CODE); 5618c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, PFAULT_INIT, (u16 *) __LC_EXT_CPU_ADDR); 5628c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, 5638c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 5648c2ecf20Sopenharmony_ci rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, 5658c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 5668c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, ext.ext_params2, (u64 *) __LC_EXT_PARAMS2); 5678c2ecf20Sopenharmony_ci return rc ? -EFAULT : 0; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic int __write_machine_check(struct kvm_vcpu *vcpu, 5718c2ecf20Sopenharmony_ci struct kvm_s390_mchk_info *mchk) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci unsigned long ext_sa_addr; 5748c2ecf20Sopenharmony_ci unsigned long lc; 5758c2ecf20Sopenharmony_ci freg_t fprs[NUM_FPRS]; 5768c2ecf20Sopenharmony_ci union mci mci; 5778c2ecf20Sopenharmony_ci int rc; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* 5808c2ecf20Sopenharmony_ci * All other possible payload for a machine check (e.g. the register 5818c2ecf20Sopenharmony_ci * contents in the save area) will be handled by the ultravisor, as 5828c2ecf20Sopenharmony_ci * the hypervisor does not not have the needed information for 5838c2ecf20Sopenharmony_ci * protected guests. 5848c2ecf20Sopenharmony_ci */ 5858c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 5868c2ecf20Sopenharmony_ci vcpu->arch.sie_block->iictl = IICTL_CODE_MCHK; 5878c2ecf20Sopenharmony_ci vcpu->arch.sie_block->mcic = mchk->mcic; 5888c2ecf20Sopenharmony_ci vcpu->arch.sie_block->faddr = mchk->failing_storage_address; 5898c2ecf20Sopenharmony_ci vcpu->arch.sie_block->edc = mchk->ext_damage_code; 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci mci.val = mchk->mcic; 5948c2ecf20Sopenharmony_ci /* take care of lazy register loading */ 5958c2ecf20Sopenharmony_ci save_fpu_regs(); 5968c2ecf20Sopenharmony_ci save_access_regs(vcpu->run->s.regs.acrs); 5978c2ecf20Sopenharmony_ci if (MACHINE_HAS_GS && vcpu->arch.gs_enabled) 5988c2ecf20Sopenharmony_ci save_gs_cb(current->thread.gs_cb); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* Extended save area */ 6018c2ecf20Sopenharmony_ci rc = read_guest_lc(vcpu, __LC_MCESAD, &ext_sa_addr, 6028c2ecf20Sopenharmony_ci sizeof(unsigned long)); 6038c2ecf20Sopenharmony_ci /* Only bits 0 through 63-LC are used for address formation */ 6048c2ecf20Sopenharmony_ci lc = ext_sa_addr & MCESA_LC_MASK; 6058c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 133)) { 6068c2ecf20Sopenharmony_ci switch (lc) { 6078c2ecf20Sopenharmony_ci case 0: 6088c2ecf20Sopenharmony_ci case 10: 6098c2ecf20Sopenharmony_ci ext_sa_addr &= ~0x3ffUL; 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci case 11: 6128c2ecf20Sopenharmony_ci ext_sa_addr &= ~0x7ffUL; 6138c2ecf20Sopenharmony_ci break; 6148c2ecf20Sopenharmony_ci case 12: 6158c2ecf20Sopenharmony_ci ext_sa_addr &= ~0xfffUL; 6168c2ecf20Sopenharmony_ci break; 6178c2ecf20Sopenharmony_ci default: 6188c2ecf20Sopenharmony_ci ext_sa_addr = 0; 6198c2ecf20Sopenharmony_ci break; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci } else { 6228c2ecf20Sopenharmony_ci ext_sa_addr &= ~0x3ffUL; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (!rc && mci.vr && ext_sa_addr && test_kvm_facility(vcpu->kvm, 129)) { 6268c2ecf20Sopenharmony_ci if (write_guest_abs(vcpu, ext_sa_addr, vcpu->run->s.regs.vrs, 6278c2ecf20Sopenharmony_ci 512)) 6288c2ecf20Sopenharmony_ci mci.vr = 0; 6298c2ecf20Sopenharmony_ci } else { 6308c2ecf20Sopenharmony_ci mci.vr = 0; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci if (!rc && mci.gs && ext_sa_addr && test_kvm_facility(vcpu->kvm, 133) 6338c2ecf20Sopenharmony_ci && (lc == 11 || lc == 12)) { 6348c2ecf20Sopenharmony_ci if (write_guest_abs(vcpu, ext_sa_addr + 1024, 6358c2ecf20Sopenharmony_ci &vcpu->run->s.regs.gscb, 32)) 6368c2ecf20Sopenharmony_ci mci.gs = 0; 6378c2ecf20Sopenharmony_ci } else { 6388c2ecf20Sopenharmony_ci mci.gs = 0; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci /* General interruption information */ 6428c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, 1, (u8 __user *) __LC_AR_MODE_ID); 6438c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_MCK_OLD_PSW, 6448c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 6458c2ecf20Sopenharmony_ci rc |= read_guest_lc(vcpu, __LC_MCK_NEW_PSW, 6468c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 6478c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, mci.val, (u64 __user *) __LC_MCCK_CODE); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* Register-save areas */ 6508c2ecf20Sopenharmony_ci if (MACHINE_HAS_VX) { 6518c2ecf20Sopenharmony_ci convert_vx_to_fp(fprs, (__vector128 *) vcpu->run->s.regs.vrs); 6528c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_FPREGS_SAVE_AREA, fprs, 128); 6538c2ecf20Sopenharmony_ci } else { 6548c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_FPREGS_SAVE_AREA, 6558c2ecf20Sopenharmony_ci vcpu->run->s.regs.fprs, 128); 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_GPREGS_SAVE_AREA, 6588c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs, 128); 6598c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, current->thread.fpu.fpc, 6608c2ecf20Sopenharmony_ci (u32 __user *) __LC_FP_CREG_SAVE_AREA); 6618c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, vcpu->arch.sie_block->todpr, 6628c2ecf20Sopenharmony_ci (u32 __user *) __LC_TOD_PROGREG_SAVE_AREA); 6638c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, kvm_s390_get_cpu_timer(vcpu), 6648c2ecf20Sopenharmony_ci (u64 __user *) __LC_CPU_TIMER_SAVE_AREA); 6658c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, vcpu->arch.sie_block->ckc >> 8, 6668c2ecf20Sopenharmony_ci (u64 __user *) __LC_CLOCK_COMP_SAVE_AREA); 6678c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_AREGS_SAVE_AREA, 6688c2ecf20Sopenharmony_ci &vcpu->run->s.regs.acrs, 64); 6698c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_CREGS_SAVE_AREA, 6708c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gcr, 128); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* Extended interruption information */ 6738c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, mchk->ext_damage_code, 6748c2ecf20Sopenharmony_ci (u32 __user *) __LC_EXT_DAMAGE_CODE); 6758c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, mchk->failing_storage_address, 6768c2ecf20Sopenharmony_ci (u64 __user *) __LC_MCCK_FAIL_STOR_ADDR); 6778c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_PSW_SAVE_AREA, &mchk->fixed_logout, 6788c2ecf20Sopenharmony_ci sizeof(mchk->fixed_logout)); 6798c2ecf20Sopenharmony_ci return rc ? -EFAULT : 0; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic int __must_check __deliver_machine_check(struct kvm_vcpu *vcpu) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; 6858c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 6868c2ecf20Sopenharmony_ci struct kvm_s390_mchk_info mchk = {}; 6878c2ecf20Sopenharmony_ci int deliver = 0; 6888c2ecf20Sopenharmony_ci int rc = 0; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 6918c2ecf20Sopenharmony_ci spin_lock(&li->lock); 6928c2ecf20Sopenharmony_ci if (test_bit(IRQ_PEND_MCHK_EX, &li->pending_irqs) || 6938c2ecf20Sopenharmony_ci test_bit(IRQ_PEND_MCHK_REP, &li->pending_irqs)) { 6948c2ecf20Sopenharmony_ci /* 6958c2ecf20Sopenharmony_ci * If there was an exigent machine check pending, then any 6968c2ecf20Sopenharmony_ci * repressible machine checks that might have been pending 6978c2ecf20Sopenharmony_ci * are indicated along with it, so always clear bits for 6988c2ecf20Sopenharmony_ci * repressible and exigent interrupts 6998c2ecf20Sopenharmony_ci */ 7008c2ecf20Sopenharmony_ci mchk = li->irq.mchk; 7018c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_MCHK_EX, &li->pending_irqs); 7028c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_MCHK_REP, &li->pending_irqs); 7038c2ecf20Sopenharmony_ci memset(&li->irq.mchk, 0, sizeof(mchk)); 7048c2ecf20Sopenharmony_ci deliver = 1; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci /* 7078c2ecf20Sopenharmony_ci * We indicate floating repressible conditions along with 7088c2ecf20Sopenharmony_ci * other pending conditions. Channel Report Pending and Channel 7098c2ecf20Sopenharmony_ci * Subsystem damage are the only two and and are indicated by 7108c2ecf20Sopenharmony_ci * bits in mcic and masked in cr14. 7118c2ecf20Sopenharmony_ci */ 7128c2ecf20Sopenharmony_ci if (test_and_clear_bit(IRQ_PEND_MCHK_REP, &fi->pending_irqs)) { 7138c2ecf20Sopenharmony_ci mchk.mcic |= fi->mchk.mcic; 7148c2ecf20Sopenharmony_ci mchk.cr14 |= fi->mchk.cr14; 7158c2ecf20Sopenharmony_ci memset(&fi->mchk, 0, sizeof(mchk)); 7168c2ecf20Sopenharmony_ci deliver = 1; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci spin_unlock(&li->lock); 7198c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (deliver) { 7228c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "deliver: machine check mcic 0x%llx", 7238c2ecf20Sopenharmony_ci mchk.mcic); 7248c2ecf20Sopenharmony_ci trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, 7258c2ecf20Sopenharmony_ci KVM_S390_MCHK, 7268c2ecf20Sopenharmony_ci mchk.cr14, mchk.mcic); 7278c2ecf20Sopenharmony_ci vcpu->stat.deliver_machine_check++; 7288c2ecf20Sopenharmony_ci rc = __write_machine_check(vcpu, &mchk); 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci return rc; 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic int __must_check __deliver_restart(struct kvm_vcpu *vcpu) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 7368c2ecf20Sopenharmony_ci int rc = 0; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "%s", "deliver: cpu restart"); 7398c2ecf20Sopenharmony_ci vcpu->stat.deliver_restart_signal++; 7408c2ecf20Sopenharmony_ci trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_RESTART, 0, 0); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 7438c2ecf20Sopenharmony_ci vcpu->arch.sie_block->iictl = IICTL_CODE_RESTART; 7448c2ecf20Sopenharmony_ci } else { 7458c2ecf20Sopenharmony_ci rc = write_guest_lc(vcpu, 7468c2ecf20Sopenharmony_ci offsetof(struct lowcore, restart_old_psw), 7478c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 7488c2ecf20Sopenharmony_ci rc |= read_guest_lc(vcpu, offsetof(struct lowcore, restart_psw), 7498c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_RESTART, &li->pending_irqs); 7528c2ecf20Sopenharmony_ci return rc ? -EFAULT : 0; 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic int __must_check __deliver_set_prefix(struct kvm_vcpu *vcpu) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 7588c2ecf20Sopenharmony_ci struct kvm_s390_prefix_info prefix; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci spin_lock(&li->lock); 7618c2ecf20Sopenharmony_ci prefix = li->irq.prefix; 7628c2ecf20Sopenharmony_ci li->irq.prefix.address = 0; 7638c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_SET_PREFIX, &li->pending_irqs); 7648c2ecf20Sopenharmony_ci spin_unlock(&li->lock); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci vcpu->stat.deliver_prefix_signal++; 7678c2ecf20Sopenharmony_ci trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, 7688c2ecf20Sopenharmony_ci KVM_S390_SIGP_SET_PREFIX, 7698c2ecf20Sopenharmony_ci prefix.address, 0); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci kvm_s390_set_prefix(vcpu, prefix.address); 7728c2ecf20Sopenharmony_ci return 0; 7738c2ecf20Sopenharmony_ci} 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_cistatic int __must_check __deliver_emergency_signal(struct kvm_vcpu *vcpu) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 7788c2ecf20Sopenharmony_ci int rc; 7798c2ecf20Sopenharmony_ci int cpu_addr; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci spin_lock(&li->lock); 7828c2ecf20Sopenharmony_ci cpu_addr = find_first_bit(li->sigp_emerg_pending, KVM_MAX_VCPUS); 7838c2ecf20Sopenharmony_ci clear_bit(cpu_addr, li->sigp_emerg_pending); 7848c2ecf20Sopenharmony_ci if (bitmap_empty(li->sigp_emerg_pending, KVM_MAX_VCPUS)) 7858c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_EXT_EMERGENCY, &li->pending_irqs); 7868c2ecf20Sopenharmony_ci spin_unlock(&li->lock); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "%s", "deliver: sigp emerg"); 7898c2ecf20Sopenharmony_ci vcpu->stat.deliver_emergency_signal++; 7908c2ecf20Sopenharmony_ci trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_EMERGENCY, 7918c2ecf20Sopenharmony_ci cpu_addr, 0); 7928c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 7938c2ecf20Sopenharmony_ci vcpu->arch.sie_block->iictl = IICTL_CODE_EXT; 7948c2ecf20Sopenharmony_ci vcpu->arch.sie_block->eic = EXT_IRQ_EMERGENCY_SIG; 7958c2ecf20Sopenharmony_ci vcpu->arch.sie_block->extcpuaddr = cpu_addr; 7968c2ecf20Sopenharmony_ci return 0; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci rc = put_guest_lc(vcpu, EXT_IRQ_EMERGENCY_SIG, 8008c2ecf20Sopenharmony_ci (u16 *)__LC_EXT_INT_CODE); 8018c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, cpu_addr, (u16 *)__LC_EXT_CPU_ADDR); 8028c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, 8038c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 8048c2ecf20Sopenharmony_ci rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, 8058c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 8068c2ecf20Sopenharmony_ci return rc ? -EFAULT : 0; 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_cistatic int __must_check __deliver_external_call(struct kvm_vcpu *vcpu) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 8128c2ecf20Sopenharmony_ci struct kvm_s390_extcall_info extcall; 8138c2ecf20Sopenharmony_ci int rc; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci spin_lock(&li->lock); 8168c2ecf20Sopenharmony_ci extcall = li->irq.extcall; 8178c2ecf20Sopenharmony_ci li->irq.extcall.code = 0; 8188c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs); 8198c2ecf20Sopenharmony_ci spin_unlock(&li->lock); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "%s", "deliver: sigp ext call"); 8228c2ecf20Sopenharmony_ci vcpu->stat.deliver_external_call++; 8238c2ecf20Sopenharmony_ci trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, 8248c2ecf20Sopenharmony_ci KVM_S390_INT_EXTERNAL_CALL, 8258c2ecf20Sopenharmony_ci extcall.code, 0); 8268c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 8278c2ecf20Sopenharmony_ci vcpu->arch.sie_block->iictl = IICTL_CODE_EXT; 8288c2ecf20Sopenharmony_ci vcpu->arch.sie_block->eic = EXT_IRQ_EXTERNAL_CALL; 8298c2ecf20Sopenharmony_ci vcpu->arch.sie_block->extcpuaddr = extcall.code; 8308c2ecf20Sopenharmony_ci return 0; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci rc = put_guest_lc(vcpu, EXT_IRQ_EXTERNAL_CALL, 8348c2ecf20Sopenharmony_ci (u16 *)__LC_EXT_INT_CODE); 8358c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, extcall.code, (u16 *)__LC_EXT_CPU_ADDR); 8368c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, 8378c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 8388c2ecf20Sopenharmony_ci rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &vcpu->arch.sie_block->gpsw, 8398c2ecf20Sopenharmony_ci sizeof(psw_t)); 8408c2ecf20Sopenharmony_ci return rc ? -EFAULT : 0; 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic int __deliver_prog_pv(struct kvm_vcpu *vcpu, u16 code) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci switch (code) { 8468c2ecf20Sopenharmony_ci case PGM_SPECIFICATION: 8478c2ecf20Sopenharmony_ci vcpu->arch.sie_block->iictl = IICTL_CODE_SPECIFICATION; 8488c2ecf20Sopenharmony_ci break; 8498c2ecf20Sopenharmony_ci case PGM_OPERAND: 8508c2ecf20Sopenharmony_ci vcpu->arch.sie_block->iictl = IICTL_CODE_OPERAND; 8518c2ecf20Sopenharmony_ci break; 8528c2ecf20Sopenharmony_ci default: 8538c2ecf20Sopenharmony_ci return -EINVAL; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci return 0; 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_cistatic int __must_check __deliver_prog(struct kvm_vcpu *vcpu) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 8618c2ecf20Sopenharmony_ci struct kvm_s390_pgm_info pgm_info; 8628c2ecf20Sopenharmony_ci int rc = 0, nullifying = false; 8638c2ecf20Sopenharmony_ci u16 ilen; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci spin_lock(&li->lock); 8668c2ecf20Sopenharmony_ci pgm_info = li->irq.pgm; 8678c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_PROG, &li->pending_irqs); 8688c2ecf20Sopenharmony_ci memset(&li->irq.pgm, 0, sizeof(pgm_info)); 8698c2ecf20Sopenharmony_ci spin_unlock(&li->lock); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci ilen = pgm_info.flags & KVM_S390_PGM_FLAGS_ILC_MASK; 8728c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "deliver: program irq code 0x%x, ilen:%d", 8738c2ecf20Sopenharmony_ci pgm_info.code, ilen); 8748c2ecf20Sopenharmony_ci vcpu->stat.deliver_program++; 8758c2ecf20Sopenharmony_ci trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_PROGRAM_INT, 8768c2ecf20Sopenharmony_ci pgm_info.code, 0); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci /* PER is handled by the ultravisor */ 8798c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) 8808c2ecf20Sopenharmony_ci return __deliver_prog_pv(vcpu, pgm_info.code & ~PGM_PER); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci switch (pgm_info.code & ~PGM_PER) { 8838c2ecf20Sopenharmony_ci case PGM_AFX_TRANSLATION: 8848c2ecf20Sopenharmony_ci case PGM_ASX_TRANSLATION: 8858c2ecf20Sopenharmony_ci case PGM_EX_TRANSLATION: 8868c2ecf20Sopenharmony_ci case PGM_LFX_TRANSLATION: 8878c2ecf20Sopenharmony_ci case PGM_LSTE_SEQUENCE: 8888c2ecf20Sopenharmony_ci case PGM_LSX_TRANSLATION: 8898c2ecf20Sopenharmony_ci case PGM_LX_TRANSLATION: 8908c2ecf20Sopenharmony_ci case PGM_PRIMARY_AUTHORITY: 8918c2ecf20Sopenharmony_ci case PGM_SECONDARY_AUTHORITY: 8928c2ecf20Sopenharmony_ci nullifying = true; 8938c2ecf20Sopenharmony_ci fallthrough; 8948c2ecf20Sopenharmony_ci case PGM_SPACE_SWITCH: 8958c2ecf20Sopenharmony_ci rc = put_guest_lc(vcpu, pgm_info.trans_exc_code, 8968c2ecf20Sopenharmony_ci (u64 *)__LC_TRANS_EXC_CODE); 8978c2ecf20Sopenharmony_ci break; 8988c2ecf20Sopenharmony_ci case PGM_ALEN_TRANSLATION: 8998c2ecf20Sopenharmony_ci case PGM_ALE_SEQUENCE: 9008c2ecf20Sopenharmony_ci case PGM_ASTE_INSTANCE: 9018c2ecf20Sopenharmony_ci case PGM_ASTE_SEQUENCE: 9028c2ecf20Sopenharmony_ci case PGM_ASTE_VALIDITY: 9038c2ecf20Sopenharmony_ci case PGM_EXTENDED_AUTHORITY: 9048c2ecf20Sopenharmony_ci rc = put_guest_lc(vcpu, pgm_info.exc_access_id, 9058c2ecf20Sopenharmony_ci (u8 *)__LC_EXC_ACCESS_ID); 9068c2ecf20Sopenharmony_ci nullifying = true; 9078c2ecf20Sopenharmony_ci break; 9088c2ecf20Sopenharmony_ci case PGM_ASCE_TYPE: 9098c2ecf20Sopenharmony_ci case PGM_PAGE_TRANSLATION: 9108c2ecf20Sopenharmony_ci case PGM_REGION_FIRST_TRANS: 9118c2ecf20Sopenharmony_ci case PGM_REGION_SECOND_TRANS: 9128c2ecf20Sopenharmony_ci case PGM_REGION_THIRD_TRANS: 9138c2ecf20Sopenharmony_ci case PGM_SEGMENT_TRANSLATION: 9148c2ecf20Sopenharmony_ci rc = put_guest_lc(vcpu, pgm_info.trans_exc_code, 9158c2ecf20Sopenharmony_ci (u64 *)__LC_TRANS_EXC_CODE); 9168c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, pgm_info.exc_access_id, 9178c2ecf20Sopenharmony_ci (u8 *)__LC_EXC_ACCESS_ID); 9188c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, pgm_info.op_access_id, 9198c2ecf20Sopenharmony_ci (u8 *)__LC_OP_ACCESS_ID); 9208c2ecf20Sopenharmony_ci nullifying = true; 9218c2ecf20Sopenharmony_ci break; 9228c2ecf20Sopenharmony_ci case PGM_MONITOR: 9238c2ecf20Sopenharmony_ci rc = put_guest_lc(vcpu, pgm_info.mon_class_nr, 9248c2ecf20Sopenharmony_ci (u16 *)__LC_MON_CLASS_NR); 9258c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, pgm_info.mon_code, 9268c2ecf20Sopenharmony_ci (u64 *)__LC_MON_CODE); 9278c2ecf20Sopenharmony_ci break; 9288c2ecf20Sopenharmony_ci case PGM_VECTOR_PROCESSING: 9298c2ecf20Sopenharmony_ci case PGM_DATA: 9308c2ecf20Sopenharmony_ci rc = put_guest_lc(vcpu, pgm_info.data_exc_code, 9318c2ecf20Sopenharmony_ci (u32 *)__LC_DATA_EXC_CODE); 9328c2ecf20Sopenharmony_ci break; 9338c2ecf20Sopenharmony_ci case PGM_PROTECTION: 9348c2ecf20Sopenharmony_ci rc = put_guest_lc(vcpu, pgm_info.trans_exc_code, 9358c2ecf20Sopenharmony_ci (u64 *)__LC_TRANS_EXC_CODE); 9368c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, pgm_info.exc_access_id, 9378c2ecf20Sopenharmony_ci (u8 *)__LC_EXC_ACCESS_ID); 9388c2ecf20Sopenharmony_ci break; 9398c2ecf20Sopenharmony_ci case PGM_STACK_FULL: 9408c2ecf20Sopenharmony_ci case PGM_STACK_EMPTY: 9418c2ecf20Sopenharmony_ci case PGM_STACK_SPECIFICATION: 9428c2ecf20Sopenharmony_ci case PGM_STACK_TYPE: 9438c2ecf20Sopenharmony_ci case PGM_STACK_OPERATION: 9448c2ecf20Sopenharmony_ci case PGM_TRACE_TABEL: 9458c2ecf20Sopenharmony_ci case PGM_CRYPTO_OPERATION: 9468c2ecf20Sopenharmony_ci nullifying = true; 9478c2ecf20Sopenharmony_ci break; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci if (pgm_info.code & PGM_PER) { 9518c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, pgm_info.per_code, 9528c2ecf20Sopenharmony_ci (u8 *) __LC_PER_CODE); 9538c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, pgm_info.per_atmid, 9548c2ecf20Sopenharmony_ci (u8 *)__LC_PER_ATMID); 9558c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, pgm_info.per_address, 9568c2ecf20Sopenharmony_ci (u64 *) __LC_PER_ADDRESS); 9578c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, pgm_info.per_access_id, 9588c2ecf20Sopenharmony_ci (u8 *) __LC_PER_ACCESS_ID); 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (nullifying && !(pgm_info.flags & KVM_S390_PGM_FLAGS_NO_REWIND)) 9628c2ecf20Sopenharmony_ci kvm_s390_rewind_psw(vcpu, ilen); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci /* bit 1+2 of the target are the ilc, so we can directly use ilen */ 9658c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, ilen, (u16 *) __LC_PGM_ILC); 9668c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, vcpu->arch.sie_block->gbea, 9678c2ecf20Sopenharmony_ci (u64 *) __LC_LAST_BREAK); 9688c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, pgm_info.code, 9698c2ecf20Sopenharmony_ci (u16 *)__LC_PGM_INT_CODE); 9708c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_PGM_OLD_PSW, 9718c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 9728c2ecf20Sopenharmony_ci rc |= read_guest_lc(vcpu, __LC_PGM_NEW_PSW, 9738c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 9748c2ecf20Sopenharmony_ci return rc ? -EFAULT : 0; 9758c2ecf20Sopenharmony_ci} 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci#define SCCB_MASK 0xFFFFFFF8 9788c2ecf20Sopenharmony_ci#define SCCB_EVENT_PENDING 0x3 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_cistatic int write_sclp(struct kvm_vcpu *vcpu, u32 parm) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci int rc; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_get_handle(vcpu)) { 9858c2ecf20Sopenharmony_ci vcpu->arch.sie_block->iictl = IICTL_CODE_EXT; 9868c2ecf20Sopenharmony_ci vcpu->arch.sie_block->eic = EXT_IRQ_SERVICE_SIG; 9878c2ecf20Sopenharmony_ci vcpu->arch.sie_block->eiparams = parm; 9888c2ecf20Sopenharmony_ci return 0; 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci rc = put_guest_lc(vcpu, EXT_IRQ_SERVICE_SIG, (u16 *)__LC_EXT_INT_CODE); 9928c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, 0, (u16 *)__LC_EXT_CPU_ADDR); 9938c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, 9948c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 9958c2ecf20Sopenharmony_ci rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, 9968c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); 9978c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, parm, 9988c2ecf20Sopenharmony_ci (u32 *)__LC_EXT_PARAMS); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci return rc ? -EFAULT : 0; 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_cistatic int __must_check __deliver_service(struct kvm_vcpu *vcpu) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; 10068c2ecf20Sopenharmony_ci struct kvm_s390_ext_info ext; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 10098c2ecf20Sopenharmony_ci if (test_bit(IRQ_PEND_EXT_SERVICE, &fi->masked_irqs) || 10108c2ecf20Sopenharmony_ci !(test_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs))) { 10118c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 10128c2ecf20Sopenharmony_ci return 0; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci ext = fi->srv_signal; 10158c2ecf20Sopenharmony_ci memset(&fi->srv_signal, 0, sizeof(ext)); 10168c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs); 10178c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs); 10188c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) 10198c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_EXT_SERVICE, &fi->masked_irqs); 10208c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "deliver: sclp parameter 0x%x", 10238c2ecf20Sopenharmony_ci ext.ext_params); 10248c2ecf20Sopenharmony_ci vcpu->stat.deliver_service_signal++; 10258c2ecf20Sopenharmony_ci trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_SERVICE, 10268c2ecf20Sopenharmony_ci ext.ext_params, 0); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci return write_sclp(vcpu, ext.ext_params); 10298c2ecf20Sopenharmony_ci} 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_cistatic int __must_check __deliver_service_ev(struct kvm_vcpu *vcpu) 10328c2ecf20Sopenharmony_ci{ 10338c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; 10348c2ecf20Sopenharmony_ci struct kvm_s390_ext_info ext; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 10378c2ecf20Sopenharmony_ci if (!(test_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs))) { 10388c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 10398c2ecf20Sopenharmony_ci return 0; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci ext = fi->srv_signal; 10428c2ecf20Sopenharmony_ci /* only clear the event bit */ 10438c2ecf20Sopenharmony_ci fi->srv_signal.ext_params &= ~SCCB_EVENT_PENDING; 10448c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs); 10458c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "%s", "deliver: sclp parameter event"); 10488c2ecf20Sopenharmony_ci vcpu->stat.deliver_service_signal++; 10498c2ecf20Sopenharmony_ci trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_SERVICE, 10508c2ecf20Sopenharmony_ci ext.ext_params, 0); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci return write_sclp(vcpu, SCCB_EVENT_PENDING); 10538c2ecf20Sopenharmony_ci} 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_cistatic int __must_check __deliver_pfault_done(struct kvm_vcpu *vcpu) 10568c2ecf20Sopenharmony_ci{ 10578c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; 10588c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti; 10598c2ecf20Sopenharmony_ci int rc = 0; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 10628c2ecf20Sopenharmony_ci inti = list_first_entry_or_null(&fi->lists[FIRQ_LIST_PFAULT], 10638c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info, 10648c2ecf20Sopenharmony_ci list); 10658c2ecf20Sopenharmony_ci if (inti) { 10668c2ecf20Sopenharmony_ci list_del(&inti->list); 10678c2ecf20Sopenharmony_ci fi->counters[FIRQ_CNTR_PFAULT] -= 1; 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci if (list_empty(&fi->lists[FIRQ_LIST_PFAULT])) 10708c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_PFAULT_DONE, &fi->pending_irqs); 10718c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (inti) { 10748c2ecf20Sopenharmony_ci trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, 10758c2ecf20Sopenharmony_ci KVM_S390_INT_PFAULT_DONE, 0, 10768c2ecf20Sopenharmony_ci inti->ext.ext_params2); 10778c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "deliver: pfault done token 0x%llx", 10788c2ecf20Sopenharmony_ci inti->ext.ext_params2); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci rc = put_guest_lc(vcpu, EXT_IRQ_CP_SERVICE, 10818c2ecf20Sopenharmony_ci (u16 *)__LC_EXT_INT_CODE); 10828c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, PFAULT_DONE, 10838c2ecf20Sopenharmony_ci (u16 *)__LC_EXT_CPU_ADDR); 10848c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, 10858c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, 10868c2ecf20Sopenharmony_ci sizeof(psw_t)); 10878c2ecf20Sopenharmony_ci rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, 10888c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, 10898c2ecf20Sopenharmony_ci sizeof(psw_t)); 10908c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, inti->ext.ext_params2, 10918c2ecf20Sopenharmony_ci (u64 *)__LC_EXT_PARAMS2); 10928c2ecf20Sopenharmony_ci kfree(inti); 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci return rc ? -EFAULT : 0; 10958c2ecf20Sopenharmony_ci} 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_cistatic int __must_check __deliver_virtio(struct kvm_vcpu *vcpu) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; 11008c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti; 11018c2ecf20Sopenharmony_ci int rc = 0; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 11048c2ecf20Sopenharmony_ci inti = list_first_entry_or_null(&fi->lists[FIRQ_LIST_VIRTIO], 11058c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info, 11068c2ecf20Sopenharmony_ci list); 11078c2ecf20Sopenharmony_ci if (inti) { 11088c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, 11098c2ecf20Sopenharmony_ci "deliver: virtio parm: 0x%x,parm64: 0x%llx", 11108c2ecf20Sopenharmony_ci inti->ext.ext_params, inti->ext.ext_params2); 11118c2ecf20Sopenharmony_ci vcpu->stat.deliver_virtio++; 11128c2ecf20Sopenharmony_ci trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, 11138c2ecf20Sopenharmony_ci inti->type, 11148c2ecf20Sopenharmony_ci inti->ext.ext_params, 11158c2ecf20Sopenharmony_ci inti->ext.ext_params2); 11168c2ecf20Sopenharmony_ci list_del(&inti->list); 11178c2ecf20Sopenharmony_ci fi->counters[FIRQ_CNTR_VIRTIO] -= 1; 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci if (list_empty(&fi->lists[FIRQ_LIST_VIRTIO])) 11208c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_VIRTIO, &fi->pending_irqs); 11218c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci if (inti) { 11248c2ecf20Sopenharmony_ci rc = put_guest_lc(vcpu, EXT_IRQ_CP_SERVICE, 11258c2ecf20Sopenharmony_ci (u16 *)__LC_EXT_INT_CODE); 11268c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, VIRTIO_PARAM, 11278c2ecf20Sopenharmony_ci (u16 *)__LC_EXT_CPU_ADDR); 11288c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW, 11298c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, 11308c2ecf20Sopenharmony_ci sizeof(psw_t)); 11318c2ecf20Sopenharmony_ci rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, 11328c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, 11338c2ecf20Sopenharmony_ci sizeof(psw_t)); 11348c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, inti->ext.ext_params, 11358c2ecf20Sopenharmony_ci (u32 *)__LC_EXT_PARAMS); 11368c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, inti->ext.ext_params2, 11378c2ecf20Sopenharmony_ci (u64 *)__LC_EXT_PARAMS2); 11388c2ecf20Sopenharmony_ci kfree(inti); 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci return rc ? -EFAULT : 0; 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic int __do_deliver_io(struct kvm_vcpu *vcpu, struct kvm_s390_io_info *io) 11448c2ecf20Sopenharmony_ci{ 11458c2ecf20Sopenharmony_ci int rc; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 11488c2ecf20Sopenharmony_ci vcpu->arch.sie_block->iictl = IICTL_CODE_IO; 11498c2ecf20Sopenharmony_ci vcpu->arch.sie_block->subchannel_id = io->subchannel_id; 11508c2ecf20Sopenharmony_ci vcpu->arch.sie_block->subchannel_nr = io->subchannel_nr; 11518c2ecf20Sopenharmony_ci vcpu->arch.sie_block->io_int_parm = io->io_int_parm; 11528c2ecf20Sopenharmony_ci vcpu->arch.sie_block->io_int_word = io->io_int_word; 11538c2ecf20Sopenharmony_ci return 0; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci rc = put_guest_lc(vcpu, io->subchannel_id, (u16 *)__LC_SUBCHANNEL_ID); 11578c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, io->subchannel_nr, (u16 *)__LC_SUBCHANNEL_NR); 11588c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, io->io_int_parm, (u32 *)__LC_IO_INT_PARM); 11598c2ecf20Sopenharmony_ci rc |= put_guest_lc(vcpu, io->io_int_word, (u32 *)__LC_IO_INT_WORD); 11608c2ecf20Sopenharmony_ci rc |= write_guest_lc(vcpu, __LC_IO_OLD_PSW, 11618c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, 11628c2ecf20Sopenharmony_ci sizeof(psw_t)); 11638c2ecf20Sopenharmony_ci rc |= read_guest_lc(vcpu, __LC_IO_NEW_PSW, 11648c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, 11658c2ecf20Sopenharmony_ci sizeof(psw_t)); 11668c2ecf20Sopenharmony_ci return rc ? -EFAULT : 0; 11678c2ecf20Sopenharmony_ci} 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_cistatic int __must_check __deliver_io(struct kvm_vcpu *vcpu, 11708c2ecf20Sopenharmony_ci unsigned long irq_type) 11718c2ecf20Sopenharmony_ci{ 11728c2ecf20Sopenharmony_ci struct list_head *isc_list; 11738c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi; 11748c2ecf20Sopenharmony_ci struct kvm_s390_gisa_interrupt *gi = &vcpu->kvm->arch.gisa_int; 11758c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti = NULL; 11768c2ecf20Sopenharmony_ci struct kvm_s390_io_info io; 11778c2ecf20Sopenharmony_ci u32 isc; 11788c2ecf20Sopenharmony_ci int rc = 0; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci fi = &vcpu->kvm->arch.float_int; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 11838c2ecf20Sopenharmony_ci isc = irq_type_to_isc(irq_type); 11848c2ecf20Sopenharmony_ci isc_list = &fi->lists[isc]; 11858c2ecf20Sopenharmony_ci inti = list_first_entry_or_null(isc_list, 11868c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info, 11878c2ecf20Sopenharmony_ci list); 11888c2ecf20Sopenharmony_ci if (inti) { 11898c2ecf20Sopenharmony_ci if (inti->type & KVM_S390_INT_IO_AI_MASK) 11908c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "%s", "deliver: I/O (AI)"); 11918c2ecf20Sopenharmony_ci else 11928c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "deliver: I/O %x ss %x schid %04x", 11938c2ecf20Sopenharmony_ci inti->io.subchannel_id >> 8, 11948c2ecf20Sopenharmony_ci inti->io.subchannel_id >> 1 & 0x3, 11958c2ecf20Sopenharmony_ci inti->io.subchannel_nr); 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci vcpu->stat.deliver_io++; 11988c2ecf20Sopenharmony_ci trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, 11998c2ecf20Sopenharmony_ci inti->type, 12008c2ecf20Sopenharmony_ci ((__u32)inti->io.subchannel_id << 16) | 12018c2ecf20Sopenharmony_ci inti->io.subchannel_nr, 12028c2ecf20Sopenharmony_ci ((__u64)inti->io.io_int_parm << 32) | 12038c2ecf20Sopenharmony_ci inti->io.io_int_word); 12048c2ecf20Sopenharmony_ci list_del(&inti->list); 12058c2ecf20Sopenharmony_ci fi->counters[FIRQ_CNTR_IO] -= 1; 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci if (list_empty(isc_list)) 12088c2ecf20Sopenharmony_ci clear_bit(irq_type, &fi->pending_irqs); 12098c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci if (inti) { 12128c2ecf20Sopenharmony_ci rc = __do_deliver_io(vcpu, &(inti->io)); 12138c2ecf20Sopenharmony_ci kfree(inti); 12148c2ecf20Sopenharmony_ci goto out; 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci if (gi->origin && gisa_tac_ipm_gisc(gi->origin, isc)) { 12188c2ecf20Sopenharmony_ci /* 12198c2ecf20Sopenharmony_ci * in case an adapter interrupt was not delivered 12208c2ecf20Sopenharmony_ci * in SIE context KVM will handle the delivery 12218c2ecf20Sopenharmony_ci */ 12228c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "%s isc %u", "deliver: I/O (AI/gisa)", isc); 12238c2ecf20Sopenharmony_ci memset(&io, 0, sizeof(io)); 12248c2ecf20Sopenharmony_ci io.io_int_word = isc_to_int_word(isc); 12258c2ecf20Sopenharmony_ci vcpu->stat.deliver_io++; 12268c2ecf20Sopenharmony_ci trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, 12278c2ecf20Sopenharmony_ci KVM_S390_INT_IO(1, 0, 0, 0), 12288c2ecf20Sopenharmony_ci ((__u32)io.subchannel_id << 16) | 12298c2ecf20Sopenharmony_ci io.subchannel_nr, 12308c2ecf20Sopenharmony_ci ((__u64)io.io_int_parm << 32) | 12318c2ecf20Sopenharmony_ci io.io_int_word); 12328c2ecf20Sopenharmony_ci rc = __do_deliver_io(vcpu, &io); 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ciout: 12358c2ecf20Sopenharmony_ci return rc; 12368c2ecf20Sopenharmony_ci} 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci/* Check whether an external call is pending (deliverable or not) */ 12398c2ecf20Sopenharmony_ciint kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu) 12408c2ecf20Sopenharmony_ci{ 12418c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci if (!sclp.has_sigpif) 12448c2ecf20Sopenharmony_ci return test_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs); 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci return sca_ext_call_pending(vcpu, NULL); 12478c2ecf20Sopenharmony_ci} 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ciint kvm_s390_vcpu_has_irq(struct kvm_vcpu *vcpu, int exclude_stop) 12508c2ecf20Sopenharmony_ci{ 12518c2ecf20Sopenharmony_ci if (deliverable_irqs(vcpu)) 12528c2ecf20Sopenharmony_ci return 1; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci if (kvm_cpu_has_pending_timer(vcpu)) 12558c2ecf20Sopenharmony_ci return 1; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci /* external call pending and deliverable */ 12588c2ecf20Sopenharmony_ci if (kvm_s390_ext_call_pending(vcpu) && 12598c2ecf20Sopenharmony_ci !psw_extint_disabled(vcpu) && 12608c2ecf20Sopenharmony_ci (vcpu->arch.sie_block->gcr[0] & CR0_EXTERNAL_CALL_SUBMASK)) 12618c2ecf20Sopenharmony_ci return 1; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci if (!exclude_stop && kvm_s390_is_stop_irq_pending(vcpu)) 12648c2ecf20Sopenharmony_ci return 1; 12658c2ecf20Sopenharmony_ci return 0; 12668c2ecf20Sopenharmony_ci} 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ciint kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) 12698c2ecf20Sopenharmony_ci{ 12708c2ecf20Sopenharmony_ci return ckc_irq_pending(vcpu) || cpu_timer_irq_pending(vcpu); 12718c2ecf20Sopenharmony_ci} 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_cistatic u64 __calculate_sltime(struct kvm_vcpu *vcpu) 12748c2ecf20Sopenharmony_ci{ 12758c2ecf20Sopenharmony_ci const u64 now = kvm_s390_get_tod_clock_fast(vcpu->kvm); 12768c2ecf20Sopenharmony_ci const u64 ckc = vcpu->arch.sie_block->ckc; 12778c2ecf20Sopenharmony_ci u64 cputm, sltime = 0; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if (ckc_interrupts_enabled(vcpu)) { 12808c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gcr[0] & CR0_CLOCK_COMPARATOR_SIGN) { 12818c2ecf20Sopenharmony_ci if ((s64)now < (s64)ckc) 12828c2ecf20Sopenharmony_ci sltime = tod_to_ns((s64)ckc - (s64)now); 12838c2ecf20Sopenharmony_ci } else if (now < ckc) { 12848c2ecf20Sopenharmony_ci sltime = tod_to_ns(ckc - now); 12858c2ecf20Sopenharmony_ci } 12868c2ecf20Sopenharmony_ci /* already expired */ 12878c2ecf20Sopenharmony_ci if (!sltime) 12888c2ecf20Sopenharmony_ci return 0; 12898c2ecf20Sopenharmony_ci if (cpu_timer_interrupts_enabled(vcpu)) { 12908c2ecf20Sopenharmony_ci cputm = kvm_s390_get_cpu_timer(vcpu); 12918c2ecf20Sopenharmony_ci /* already expired? */ 12928c2ecf20Sopenharmony_ci if (cputm >> 63) 12938c2ecf20Sopenharmony_ci return 0; 12948c2ecf20Sopenharmony_ci return min(sltime, tod_to_ns(cputm)); 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci } else if (cpu_timer_interrupts_enabled(vcpu)) { 12978c2ecf20Sopenharmony_ci sltime = kvm_s390_get_cpu_timer(vcpu); 12988c2ecf20Sopenharmony_ci /* already expired? */ 12998c2ecf20Sopenharmony_ci if (sltime >> 63) 13008c2ecf20Sopenharmony_ci return 0; 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci return sltime; 13038c2ecf20Sopenharmony_ci} 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ciint kvm_s390_handle_wait(struct kvm_vcpu *vcpu) 13068c2ecf20Sopenharmony_ci{ 13078c2ecf20Sopenharmony_ci struct kvm_s390_gisa_interrupt *gi = &vcpu->kvm->arch.gisa_int; 13088c2ecf20Sopenharmony_ci u64 sltime; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci vcpu->stat.exit_wait_state++; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci /* fast path */ 13138c2ecf20Sopenharmony_ci if (kvm_arch_vcpu_runnable(vcpu)) 13148c2ecf20Sopenharmony_ci return 0; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci if (psw_interrupts_disabled(vcpu)) { 13178c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "%s", "disabled wait"); 13188c2ecf20Sopenharmony_ci return -EOPNOTSUPP; /* disabled wait */ 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci if (gi->origin && 13228c2ecf20Sopenharmony_ci (gisa_get_ipm_or_restore_iam(gi) & 13238c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gcr[6] >> 24)) 13248c2ecf20Sopenharmony_ci return 0; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci if (!ckc_interrupts_enabled(vcpu) && 13278c2ecf20Sopenharmony_ci !cpu_timer_interrupts_enabled(vcpu)) { 13288c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "%s", "enabled wait w/o timer"); 13298c2ecf20Sopenharmony_ci __set_cpu_idle(vcpu); 13308c2ecf20Sopenharmony_ci goto no_timer; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci sltime = __calculate_sltime(vcpu); 13348c2ecf20Sopenharmony_ci if (!sltime) 13358c2ecf20Sopenharmony_ci return 0; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci __set_cpu_idle(vcpu); 13388c2ecf20Sopenharmony_ci hrtimer_start(&vcpu->arch.ckc_timer, sltime, HRTIMER_MODE_REL); 13398c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "enabled wait: %llu ns", sltime); 13408c2ecf20Sopenharmony_cino_timer: 13418c2ecf20Sopenharmony_ci srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); 13428c2ecf20Sopenharmony_ci kvm_vcpu_block(vcpu); 13438c2ecf20Sopenharmony_ci __unset_cpu_idle(vcpu); 13448c2ecf20Sopenharmony_ci vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci hrtimer_cancel(&vcpu->arch.ckc_timer); 13478c2ecf20Sopenharmony_ci return 0; 13488c2ecf20Sopenharmony_ci} 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_civoid kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu) 13518c2ecf20Sopenharmony_ci{ 13528c2ecf20Sopenharmony_ci vcpu->valid_wakeup = true; 13538c2ecf20Sopenharmony_ci kvm_vcpu_wake_up(vcpu); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci /* 13568c2ecf20Sopenharmony_ci * The VCPU might not be sleeping but rather executing VSIE. Let's 13578c2ecf20Sopenharmony_ci * kick it, so it leaves the SIE to process the request. 13588c2ecf20Sopenharmony_ci */ 13598c2ecf20Sopenharmony_ci kvm_s390_vsie_kick(vcpu); 13608c2ecf20Sopenharmony_ci} 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_cienum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer) 13638c2ecf20Sopenharmony_ci{ 13648c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 13658c2ecf20Sopenharmony_ci u64 sltime; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci vcpu = container_of(timer, struct kvm_vcpu, arch.ckc_timer); 13688c2ecf20Sopenharmony_ci sltime = __calculate_sltime(vcpu); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci /* 13718c2ecf20Sopenharmony_ci * If the monotonic clock runs faster than the tod clock we might be 13728c2ecf20Sopenharmony_ci * woken up too early and have to go back to sleep to avoid deadlocks. 13738c2ecf20Sopenharmony_ci */ 13748c2ecf20Sopenharmony_ci if (sltime && hrtimer_forward_now(timer, ns_to_ktime(sltime))) 13758c2ecf20Sopenharmony_ci return HRTIMER_RESTART; 13768c2ecf20Sopenharmony_ci kvm_s390_vcpu_wakeup(vcpu); 13778c2ecf20Sopenharmony_ci return HRTIMER_NORESTART; 13788c2ecf20Sopenharmony_ci} 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_civoid kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu) 13818c2ecf20Sopenharmony_ci{ 13828c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci spin_lock(&li->lock); 13858c2ecf20Sopenharmony_ci li->pending_irqs = 0; 13868c2ecf20Sopenharmony_ci bitmap_zero(li->sigp_emerg_pending, KVM_MAX_VCPUS); 13878c2ecf20Sopenharmony_ci memset(&li->irq, 0, sizeof(li->irq)); 13888c2ecf20Sopenharmony_ci spin_unlock(&li->lock); 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci sca_clear_ext_call(vcpu); 13918c2ecf20Sopenharmony_ci} 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ciint __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) 13948c2ecf20Sopenharmony_ci{ 13958c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 13968c2ecf20Sopenharmony_ci int rc = 0; 13978c2ecf20Sopenharmony_ci unsigned long irq_type; 13988c2ecf20Sopenharmony_ci unsigned long irqs; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci __reset_intercept_indicators(vcpu); 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci /* pending ckc conditions might have been invalidated */ 14038c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_EXT_CLOCK_COMP, &li->pending_irqs); 14048c2ecf20Sopenharmony_ci if (ckc_irq_pending(vcpu)) 14058c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_EXT_CLOCK_COMP, &li->pending_irqs); 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci /* pending cpu timer conditions might have been invalidated */ 14088c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs); 14098c2ecf20Sopenharmony_ci if (cpu_timer_irq_pending(vcpu)) 14108c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci while ((irqs = deliverable_irqs(vcpu)) && !rc) { 14138c2ecf20Sopenharmony_ci /* bits are in the reverse order of interrupt priority */ 14148c2ecf20Sopenharmony_ci irq_type = find_last_bit(&irqs, IRQ_PEND_COUNT); 14158c2ecf20Sopenharmony_ci switch (irq_type) { 14168c2ecf20Sopenharmony_ci case IRQ_PEND_IO_ISC_0: 14178c2ecf20Sopenharmony_ci case IRQ_PEND_IO_ISC_1: 14188c2ecf20Sopenharmony_ci case IRQ_PEND_IO_ISC_2: 14198c2ecf20Sopenharmony_ci case IRQ_PEND_IO_ISC_3: 14208c2ecf20Sopenharmony_ci case IRQ_PEND_IO_ISC_4: 14218c2ecf20Sopenharmony_ci case IRQ_PEND_IO_ISC_5: 14228c2ecf20Sopenharmony_ci case IRQ_PEND_IO_ISC_6: 14238c2ecf20Sopenharmony_ci case IRQ_PEND_IO_ISC_7: 14248c2ecf20Sopenharmony_ci rc = __deliver_io(vcpu, irq_type); 14258c2ecf20Sopenharmony_ci break; 14268c2ecf20Sopenharmony_ci case IRQ_PEND_MCHK_EX: 14278c2ecf20Sopenharmony_ci case IRQ_PEND_MCHK_REP: 14288c2ecf20Sopenharmony_ci rc = __deliver_machine_check(vcpu); 14298c2ecf20Sopenharmony_ci break; 14308c2ecf20Sopenharmony_ci case IRQ_PEND_PROG: 14318c2ecf20Sopenharmony_ci rc = __deliver_prog(vcpu); 14328c2ecf20Sopenharmony_ci break; 14338c2ecf20Sopenharmony_ci case IRQ_PEND_EXT_EMERGENCY: 14348c2ecf20Sopenharmony_ci rc = __deliver_emergency_signal(vcpu); 14358c2ecf20Sopenharmony_ci break; 14368c2ecf20Sopenharmony_ci case IRQ_PEND_EXT_EXTERNAL: 14378c2ecf20Sopenharmony_ci rc = __deliver_external_call(vcpu); 14388c2ecf20Sopenharmony_ci break; 14398c2ecf20Sopenharmony_ci case IRQ_PEND_EXT_CLOCK_COMP: 14408c2ecf20Sopenharmony_ci rc = __deliver_ckc(vcpu); 14418c2ecf20Sopenharmony_ci break; 14428c2ecf20Sopenharmony_ci case IRQ_PEND_EXT_CPU_TIMER: 14438c2ecf20Sopenharmony_ci rc = __deliver_cpu_timer(vcpu); 14448c2ecf20Sopenharmony_ci break; 14458c2ecf20Sopenharmony_ci case IRQ_PEND_RESTART: 14468c2ecf20Sopenharmony_ci rc = __deliver_restart(vcpu); 14478c2ecf20Sopenharmony_ci break; 14488c2ecf20Sopenharmony_ci case IRQ_PEND_SET_PREFIX: 14498c2ecf20Sopenharmony_ci rc = __deliver_set_prefix(vcpu); 14508c2ecf20Sopenharmony_ci break; 14518c2ecf20Sopenharmony_ci case IRQ_PEND_PFAULT_INIT: 14528c2ecf20Sopenharmony_ci rc = __deliver_pfault_init(vcpu); 14538c2ecf20Sopenharmony_ci break; 14548c2ecf20Sopenharmony_ci case IRQ_PEND_EXT_SERVICE: 14558c2ecf20Sopenharmony_ci rc = __deliver_service(vcpu); 14568c2ecf20Sopenharmony_ci break; 14578c2ecf20Sopenharmony_ci case IRQ_PEND_EXT_SERVICE_EV: 14588c2ecf20Sopenharmony_ci rc = __deliver_service_ev(vcpu); 14598c2ecf20Sopenharmony_ci break; 14608c2ecf20Sopenharmony_ci case IRQ_PEND_PFAULT_DONE: 14618c2ecf20Sopenharmony_ci rc = __deliver_pfault_done(vcpu); 14628c2ecf20Sopenharmony_ci break; 14638c2ecf20Sopenharmony_ci case IRQ_PEND_VIRTIO: 14648c2ecf20Sopenharmony_ci rc = __deliver_virtio(vcpu); 14658c2ecf20Sopenharmony_ci break; 14668c2ecf20Sopenharmony_ci default: 14678c2ecf20Sopenharmony_ci WARN_ONCE(1, "Unknown pending irq type %ld", irq_type); 14688c2ecf20Sopenharmony_ci clear_bit(irq_type, &li->pending_irqs); 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci } 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci set_intercept_indicators(vcpu); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci return rc; 14758c2ecf20Sopenharmony_ci} 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_cistatic int __inject_prog(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) 14788c2ecf20Sopenharmony_ci{ 14798c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci vcpu->stat.inject_program++; 14828c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "inject: program irq code 0x%x", irq->u.pgm.code); 14838c2ecf20Sopenharmony_ci trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_PROGRAM_INT, 14848c2ecf20Sopenharmony_ci irq->u.pgm.code, 0); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci if (!(irq->u.pgm.flags & KVM_S390_PGM_FLAGS_ILC_VALID)) { 14878c2ecf20Sopenharmony_ci /* auto detection if no valid ILC was given */ 14888c2ecf20Sopenharmony_ci irq->u.pgm.flags &= ~KVM_S390_PGM_FLAGS_ILC_MASK; 14898c2ecf20Sopenharmony_ci irq->u.pgm.flags |= kvm_s390_get_ilen(vcpu); 14908c2ecf20Sopenharmony_ci irq->u.pgm.flags |= KVM_S390_PGM_FLAGS_ILC_VALID; 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci if (irq->u.pgm.code == PGM_PER) { 14948c2ecf20Sopenharmony_ci li->irq.pgm.code |= PGM_PER; 14958c2ecf20Sopenharmony_ci li->irq.pgm.flags = irq->u.pgm.flags; 14968c2ecf20Sopenharmony_ci /* only modify PER related information */ 14978c2ecf20Sopenharmony_ci li->irq.pgm.per_address = irq->u.pgm.per_address; 14988c2ecf20Sopenharmony_ci li->irq.pgm.per_code = irq->u.pgm.per_code; 14998c2ecf20Sopenharmony_ci li->irq.pgm.per_atmid = irq->u.pgm.per_atmid; 15008c2ecf20Sopenharmony_ci li->irq.pgm.per_access_id = irq->u.pgm.per_access_id; 15018c2ecf20Sopenharmony_ci } else if (!(irq->u.pgm.code & PGM_PER)) { 15028c2ecf20Sopenharmony_ci li->irq.pgm.code = (li->irq.pgm.code & PGM_PER) | 15038c2ecf20Sopenharmony_ci irq->u.pgm.code; 15048c2ecf20Sopenharmony_ci li->irq.pgm.flags = irq->u.pgm.flags; 15058c2ecf20Sopenharmony_ci /* only modify non-PER information */ 15068c2ecf20Sopenharmony_ci li->irq.pgm.trans_exc_code = irq->u.pgm.trans_exc_code; 15078c2ecf20Sopenharmony_ci li->irq.pgm.mon_code = irq->u.pgm.mon_code; 15088c2ecf20Sopenharmony_ci li->irq.pgm.data_exc_code = irq->u.pgm.data_exc_code; 15098c2ecf20Sopenharmony_ci li->irq.pgm.mon_class_nr = irq->u.pgm.mon_class_nr; 15108c2ecf20Sopenharmony_ci li->irq.pgm.exc_access_id = irq->u.pgm.exc_access_id; 15118c2ecf20Sopenharmony_ci li->irq.pgm.op_access_id = irq->u.pgm.op_access_id; 15128c2ecf20Sopenharmony_ci } else { 15138c2ecf20Sopenharmony_ci li->irq.pgm = irq->u.pgm; 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_PROG, &li->pending_irqs); 15168c2ecf20Sopenharmony_ci return 0; 15178c2ecf20Sopenharmony_ci} 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_cistatic int __inject_pfault_init(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) 15208c2ecf20Sopenharmony_ci{ 15218c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci vcpu->stat.inject_pfault_init++; 15248c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "inject: pfault init parameter block at 0x%llx", 15258c2ecf20Sopenharmony_ci irq->u.ext.ext_params2); 15268c2ecf20Sopenharmony_ci trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_PFAULT_INIT, 15278c2ecf20Sopenharmony_ci irq->u.ext.ext_params, 15288c2ecf20Sopenharmony_ci irq->u.ext.ext_params2); 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci li->irq.ext = irq->u.ext; 15318c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_PFAULT_INIT, &li->pending_irqs); 15328c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_EXT_INT); 15338c2ecf20Sopenharmony_ci return 0; 15348c2ecf20Sopenharmony_ci} 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_cistatic int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) 15378c2ecf20Sopenharmony_ci{ 15388c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 15398c2ecf20Sopenharmony_ci struct kvm_s390_extcall_info *extcall = &li->irq.extcall; 15408c2ecf20Sopenharmony_ci uint16_t src_id = irq->u.extcall.code; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci vcpu->stat.inject_external_call++; 15438c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "inject: external call source-cpu:%u", 15448c2ecf20Sopenharmony_ci src_id); 15458c2ecf20Sopenharmony_ci trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_EXTERNAL_CALL, 15468c2ecf20Sopenharmony_ci src_id, 0); 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci /* sending vcpu invalid */ 15498c2ecf20Sopenharmony_ci if (kvm_get_vcpu_by_id(vcpu->kvm, src_id) == NULL) 15508c2ecf20Sopenharmony_ci return -EINVAL; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci if (sclp.has_sigpif && !kvm_s390_pv_cpu_get_handle(vcpu)) 15538c2ecf20Sopenharmony_ci return sca_inject_ext_call(vcpu, src_id); 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci if (test_and_set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs)) 15568c2ecf20Sopenharmony_ci return -EBUSY; 15578c2ecf20Sopenharmony_ci *extcall = irq->u.extcall; 15588c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_EXT_INT); 15598c2ecf20Sopenharmony_ci return 0; 15608c2ecf20Sopenharmony_ci} 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_cistatic int __inject_set_prefix(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) 15638c2ecf20Sopenharmony_ci{ 15648c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 15658c2ecf20Sopenharmony_ci struct kvm_s390_prefix_info *prefix = &li->irq.prefix; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci vcpu->stat.inject_set_prefix++; 15688c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "inject: set prefix to %x", 15698c2ecf20Sopenharmony_ci irq->u.prefix.address); 15708c2ecf20Sopenharmony_ci trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_SIGP_SET_PREFIX, 15718c2ecf20Sopenharmony_ci irq->u.prefix.address, 0); 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci if (!is_vcpu_stopped(vcpu)) 15748c2ecf20Sopenharmony_ci return -EBUSY; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci *prefix = irq->u.prefix; 15778c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_SET_PREFIX, &li->pending_irqs); 15788c2ecf20Sopenharmony_ci return 0; 15798c2ecf20Sopenharmony_ci} 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci#define KVM_S390_STOP_SUPP_FLAGS (KVM_S390_STOP_FLAG_STORE_STATUS) 15828c2ecf20Sopenharmony_cistatic int __inject_sigp_stop(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) 15838c2ecf20Sopenharmony_ci{ 15848c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 15858c2ecf20Sopenharmony_ci struct kvm_s390_stop_info *stop = &li->irq.stop; 15868c2ecf20Sopenharmony_ci int rc = 0; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci vcpu->stat.inject_stop_signal++; 15898c2ecf20Sopenharmony_ci trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_SIGP_STOP, 0, 0); 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci if (irq->u.stop.flags & ~KVM_S390_STOP_SUPP_FLAGS) 15928c2ecf20Sopenharmony_ci return -EINVAL; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci if (is_vcpu_stopped(vcpu)) { 15958c2ecf20Sopenharmony_ci if (irq->u.stop.flags & KVM_S390_STOP_FLAG_STORE_STATUS) 15968c2ecf20Sopenharmony_ci rc = kvm_s390_store_status_unloaded(vcpu, 15978c2ecf20Sopenharmony_ci KVM_S390_STORE_STATUS_NOADDR); 15988c2ecf20Sopenharmony_ci return rc; 15998c2ecf20Sopenharmony_ci } 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci if (test_and_set_bit(IRQ_PEND_SIGP_STOP, &li->pending_irqs)) 16028c2ecf20Sopenharmony_ci return -EBUSY; 16038c2ecf20Sopenharmony_ci stop->flags = irq->u.stop.flags; 16048c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_STOP_INT); 16058c2ecf20Sopenharmony_ci return 0; 16068c2ecf20Sopenharmony_ci} 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_cistatic int __inject_sigp_restart(struct kvm_vcpu *vcpu) 16098c2ecf20Sopenharmony_ci{ 16108c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci vcpu->stat.inject_restart++; 16138c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "%s", "inject: restart int"); 16148c2ecf20Sopenharmony_ci trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_RESTART, 0, 0); 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_RESTART, &li->pending_irqs); 16178c2ecf20Sopenharmony_ci return 0; 16188c2ecf20Sopenharmony_ci} 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_cistatic int __inject_sigp_emergency(struct kvm_vcpu *vcpu, 16218c2ecf20Sopenharmony_ci struct kvm_s390_irq *irq) 16228c2ecf20Sopenharmony_ci{ 16238c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci vcpu->stat.inject_emergency_signal++; 16268c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "inject: emergency from cpu %u", 16278c2ecf20Sopenharmony_ci irq->u.emerg.code); 16288c2ecf20Sopenharmony_ci trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_EMERGENCY, 16298c2ecf20Sopenharmony_ci irq->u.emerg.code, 0); 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci /* sending vcpu invalid */ 16328c2ecf20Sopenharmony_ci if (kvm_get_vcpu_by_id(vcpu->kvm, irq->u.emerg.code) == NULL) 16338c2ecf20Sopenharmony_ci return -EINVAL; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci set_bit(irq->u.emerg.code, li->sigp_emerg_pending); 16368c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_EXT_EMERGENCY, &li->pending_irqs); 16378c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_EXT_INT); 16388c2ecf20Sopenharmony_ci return 0; 16398c2ecf20Sopenharmony_ci} 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_cistatic int __inject_mchk(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) 16428c2ecf20Sopenharmony_ci{ 16438c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 16448c2ecf20Sopenharmony_ci struct kvm_s390_mchk_info *mchk = &li->irq.mchk; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci vcpu->stat.inject_mchk++; 16478c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "inject: machine check mcic 0x%llx", 16488c2ecf20Sopenharmony_ci irq->u.mchk.mcic); 16498c2ecf20Sopenharmony_ci trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_MCHK, 0, 16508c2ecf20Sopenharmony_ci irq->u.mchk.mcic); 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci /* 16538c2ecf20Sopenharmony_ci * Because repressible machine checks can be indicated along with 16548c2ecf20Sopenharmony_ci * exigent machine checks (PoP, Chapter 11, Interruption action) 16558c2ecf20Sopenharmony_ci * we need to combine cr14, mcic and external damage code. 16568c2ecf20Sopenharmony_ci * Failing storage address and the logout area should not be or'ed 16578c2ecf20Sopenharmony_ci * together, we just indicate the last occurrence of the corresponding 16588c2ecf20Sopenharmony_ci * machine check 16598c2ecf20Sopenharmony_ci */ 16608c2ecf20Sopenharmony_ci mchk->cr14 |= irq->u.mchk.cr14; 16618c2ecf20Sopenharmony_ci mchk->mcic |= irq->u.mchk.mcic; 16628c2ecf20Sopenharmony_ci mchk->ext_damage_code |= irq->u.mchk.ext_damage_code; 16638c2ecf20Sopenharmony_ci mchk->failing_storage_address = irq->u.mchk.failing_storage_address; 16648c2ecf20Sopenharmony_ci memcpy(&mchk->fixed_logout, &irq->u.mchk.fixed_logout, 16658c2ecf20Sopenharmony_ci sizeof(mchk->fixed_logout)); 16668c2ecf20Sopenharmony_ci if (mchk->mcic & MCHK_EX_MASK) 16678c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_MCHK_EX, &li->pending_irqs); 16688c2ecf20Sopenharmony_ci else if (mchk->mcic & MCHK_REP_MASK) 16698c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_MCHK_REP, &li->pending_irqs); 16708c2ecf20Sopenharmony_ci return 0; 16718c2ecf20Sopenharmony_ci} 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_cistatic int __inject_ckc(struct kvm_vcpu *vcpu) 16748c2ecf20Sopenharmony_ci{ 16758c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci vcpu->stat.inject_ckc++; 16788c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "%s", "inject: clock comparator external"); 16798c2ecf20Sopenharmony_ci trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_CLOCK_COMP, 16808c2ecf20Sopenharmony_ci 0, 0); 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_EXT_CLOCK_COMP, &li->pending_irqs); 16838c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_EXT_INT); 16848c2ecf20Sopenharmony_ci return 0; 16858c2ecf20Sopenharmony_ci} 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_cistatic int __inject_cpu_timer(struct kvm_vcpu *vcpu) 16888c2ecf20Sopenharmony_ci{ 16898c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci vcpu->stat.inject_cputm++; 16928c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "%s", "inject: cpu timer external"); 16938c2ecf20Sopenharmony_ci trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_CPU_TIMER, 16948c2ecf20Sopenharmony_ci 0, 0); 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs); 16978c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_EXT_INT); 16988c2ecf20Sopenharmony_ci return 0; 16998c2ecf20Sopenharmony_ci} 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_cistatic struct kvm_s390_interrupt_info *get_io_int(struct kvm *kvm, 17028c2ecf20Sopenharmony_ci int isc, u32 schid) 17038c2ecf20Sopenharmony_ci{ 17048c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int; 17058c2ecf20Sopenharmony_ci struct list_head *isc_list = &fi->lists[FIRQ_LIST_IO_ISC_0 + isc]; 17068c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *iter; 17078c2ecf20Sopenharmony_ci u16 id = (schid & 0xffff0000U) >> 16; 17088c2ecf20Sopenharmony_ci u16 nr = schid & 0x0000ffffU; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 17118c2ecf20Sopenharmony_ci list_for_each_entry(iter, isc_list, list) { 17128c2ecf20Sopenharmony_ci if (schid && (id != iter->io.subchannel_id || 17138c2ecf20Sopenharmony_ci nr != iter->io.subchannel_nr)) 17148c2ecf20Sopenharmony_ci continue; 17158c2ecf20Sopenharmony_ci /* found an appropriate entry */ 17168c2ecf20Sopenharmony_ci list_del_init(&iter->list); 17178c2ecf20Sopenharmony_ci fi->counters[FIRQ_CNTR_IO] -= 1; 17188c2ecf20Sopenharmony_ci if (list_empty(isc_list)) 17198c2ecf20Sopenharmony_ci clear_bit(isc_to_irq_type(isc), &fi->pending_irqs); 17208c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 17218c2ecf20Sopenharmony_ci return iter; 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 17248c2ecf20Sopenharmony_ci return NULL; 17258c2ecf20Sopenharmony_ci} 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_cistatic struct kvm_s390_interrupt_info *get_top_io_int(struct kvm *kvm, 17288c2ecf20Sopenharmony_ci u64 isc_mask, u32 schid) 17298c2ecf20Sopenharmony_ci{ 17308c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti = NULL; 17318c2ecf20Sopenharmony_ci int isc; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci for (isc = 0; isc <= MAX_ISC && !inti; isc++) { 17348c2ecf20Sopenharmony_ci if (isc_mask & isc_to_isc_bits(isc)) 17358c2ecf20Sopenharmony_ci inti = get_io_int(kvm, isc, schid); 17368c2ecf20Sopenharmony_ci } 17378c2ecf20Sopenharmony_ci return inti; 17388c2ecf20Sopenharmony_ci} 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_cistatic int get_top_gisa_isc(struct kvm *kvm, u64 isc_mask, u32 schid) 17418c2ecf20Sopenharmony_ci{ 17428c2ecf20Sopenharmony_ci struct kvm_s390_gisa_interrupt *gi = &kvm->arch.gisa_int; 17438c2ecf20Sopenharmony_ci unsigned long active_mask; 17448c2ecf20Sopenharmony_ci int isc; 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci if (schid) 17478c2ecf20Sopenharmony_ci goto out; 17488c2ecf20Sopenharmony_ci if (!gi->origin) 17498c2ecf20Sopenharmony_ci goto out; 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci active_mask = (isc_mask & gisa_get_ipm(gi->origin) << 24) << 32; 17528c2ecf20Sopenharmony_ci while (active_mask) { 17538c2ecf20Sopenharmony_ci isc = __fls(active_mask) ^ (BITS_PER_LONG - 1); 17548c2ecf20Sopenharmony_ci if (gisa_tac_ipm_gisc(gi->origin, isc)) 17558c2ecf20Sopenharmony_ci return isc; 17568c2ecf20Sopenharmony_ci clear_bit_inv(isc, &active_mask); 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ciout: 17598c2ecf20Sopenharmony_ci return -EINVAL; 17608c2ecf20Sopenharmony_ci} 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci/* 17638c2ecf20Sopenharmony_ci * Dequeue and return an I/O interrupt matching any of the interruption 17648c2ecf20Sopenharmony_ci * subclasses as designated by the isc mask in cr6 and the schid (if != 0). 17658c2ecf20Sopenharmony_ci * Take into account the interrupts pending in the interrupt list and in GISA. 17668c2ecf20Sopenharmony_ci * 17678c2ecf20Sopenharmony_ci * Note that for a guest that does not enable I/O interrupts 17688c2ecf20Sopenharmony_ci * but relies on TPI, a flood of classic interrupts may starve 17698c2ecf20Sopenharmony_ci * out adapter interrupts on the same isc. Linux does not do 17708c2ecf20Sopenharmony_ci * that, and it is possible to work around the issue by configuring 17718c2ecf20Sopenharmony_ci * different iscs for classic and adapter interrupts in the guest, 17728c2ecf20Sopenharmony_ci * but we may want to revisit this in the future. 17738c2ecf20Sopenharmony_ci */ 17748c2ecf20Sopenharmony_cistruct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm, 17758c2ecf20Sopenharmony_ci u64 isc_mask, u32 schid) 17768c2ecf20Sopenharmony_ci{ 17778c2ecf20Sopenharmony_ci struct kvm_s390_gisa_interrupt *gi = &kvm->arch.gisa_int; 17788c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti, *tmp_inti; 17798c2ecf20Sopenharmony_ci int isc; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci inti = get_top_io_int(kvm, isc_mask, schid); 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci isc = get_top_gisa_isc(kvm, isc_mask, schid); 17848c2ecf20Sopenharmony_ci if (isc < 0) 17858c2ecf20Sopenharmony_ci /* no AI in GISA */ 17868c2ecf20Sopenharmony_ci goto out; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci if (!inti) 17898c2ecf20Sopenharmony_ci /* AI in GISA but no classical IO int */ 17908c2ecf20Sopenharmony_ci goto gisa_out; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci /* both types of interrupts present */ 17938c2ecf20Sopenharmony_ci if (int_word_to_isc(inti->io.io_int_word) <= isc) { 17948c2ecf20Sopenharmony_ci /* classical IO int with higher priority */ 17958c2ecf20Sopenharmony_ci gisa_set_ipm_gisc(gi->origin, isc); 17968c2ecf20Sopenharmony_ci goto out; 17978c2ecf20Sopenharmony_ci } 17988c2ecf20Sopenharmony_cigisa_out: 17998c2ecf20Sopenharmony_ci tmp_inti = kzalloc(sizeof(*inti), GFP_KERNEL); 18008c2ecf20Sopenharmony_ci if (tmp_inti) { 18018c2ecf20Sopenharmony_ci tmp_inti->type = KVM_S390_INT_IO(1, 0, 0, 0); 18028c2ecf20Sopenharmony_ci tmp_inti->io.io_int_word = isc_to_int_word(isc); 18038c2ecf20Sopenharmony_ci if (inti) 18048c2ecf20Sopenharmony_ci kvm_s390_reinject_io_int(kvm, inti); 18058c2ecf20Sopenharmony_ci inti = tmp_inti; 18068c2ecf20Sopenharmony_ci } else 18078c2ecf20Sopenharmony_ci gisa_set_ipm_gisc(gi->origin, isc); 18088c2ecf20Sopenharmony_ciout: 18098c2ecf20Sopenharmony_ci return inti; 18108c2ecf20Sopenharmony_ci} 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_cistatic int __inject_service(struct kvm *kvm, 18138c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti) 18148c2ecf20Sopenharmony_ci{ 18158c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci kvm->stat.inject_service_signal++; 18188c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 18198c2ecf20Sopenharmony_ci fi->srv_signal.ext_params |= inti->ext.ext_params & SCCB_EVENT_PENDING; 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci /* We always allow events, track them separately from the sccb ints */ 18228c2ecf20Sopenharmony_ci if (fi->srv_signal.ext_params & SCCB_EVENT_PENDING) 18238c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs); 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci /* 18268c2ecf20Sopenharmony_ci * Early versions of the QEMU s390 bios will inject several 18278c2ecf20Sopenharmony_ci * service interrupts after another without handling a 18288c2ecf20Sopenharmony_ci * condition code indicating busy. 18298c2ecf20Sopenharmony_ci * We will silently ignore those superfluous sccb values. 18308c2ecf20Sopenharmony_ci * A future version of QEMU will take care of serialization 18318c2ecf20Sopenharmony_ci * of servc requests 18328c2ecf20Sopenharmony_ci */ 18338c2ecf20Sopenharmony_ci if (fi->srv_signal.ext_params & SCCB_MASK) 18348c2ecf20Sopenharmony_ci goto out; 18358c2ecf20Sopenharmony_ci fi->srv_signal.ext_params |= inti->ext.ext_params & SCCB_MASK; 18368c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs); 18378c2ecf20Sopenharmony_ciout: 18388c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 18398c2ecf20Sopenharmony_ci kfree(inti); 18408c2ecf20Sopenharmony_ci return 0; 18418c2ecf20Sopenharmony_ci} 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_cistatic int __inject_virtio(struct kvm *kvm, 18448c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti) 18458c2ecf20Sopenharmony_ci{ 18468c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci kvm->stat.inject_virtio++; 18498c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 18508c2ecf20Sopenharmony_ci if (fi->counters[FIRQ_CNTR_VIRTIO] >= KVM_S390_MAX_VIRTIO_IRQS) { 18518c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 18528c2ecf20Sopenharmony_ci return -EBUSY; 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci fi->counters[FIRQ_CNTR_VIRTIO] += 1; 18558c2ecf20Sopenharmony_ci list_add_tail(&inti->list, &fi->lists[FIRQ_LIST_VIRTIO]); 18568c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_VIRTIO, &fi->pending_irqs); 18578c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 18588c2ecf20Sopenharmony_ci return 0; 18598c2ecf20Sopenharmony_ci} 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_cistatic int __inject_pfault_done(struct kvm *kvm, 18628c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti) 18638c2ecf20Sopenharmony_ci{ 18648c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int; 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci kvm->stat.inject_pfault_done++; 18678c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 18688c2ecf20Sopenharmony_ci if (fi->counters[FIRQ_CNTR_PFAULT] >= 18698c2ecf20Sopenharmony_ci (ASYNC_PF_PER_VCPU * KVM_MAX_VCPUS)) { 18708c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 18718c2ecf20Sopenharmony_ci return -EBUSY; 18728c2ecf20Sopenharmony_ci } 18738c2ecf20Sopenharmony_ci fi->counters[FIRQ_CNTR_PFAULT] += 1; 18748c2ecf20Sopenharmony_ci list_add_tail(&inti->list, &fi->lists[FIRQ_LIST_PFAULT]); 18758c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_PFAULT_DONE, &fi->pending_irqs); 18768c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 18778c2ecf20Sopenharmony_ci return 0; 18788c2ecf20Sopenharmony_ci} 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci#define CR_PENDING_SUBCLASS 28 18818c2ecf20Sopenharmony_cistatic int __inject_float_mchk(struct kvm *kvm, 18828c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti) 18838c2ecf20Sopenharmony_ci{ 18848c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci kvm->stat.inject_float_mchk++; 18878c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 18888c2ecf20Sopenharmony_ci fi->mchk.cr14 |= inti->mchk.cr14 & (1UL << CR_PENDING_SUBCLASS); 18898c2ecf20Sopenharmony_ci fi->mchk.mcic |= inti->mchk.mcic; 18908c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_MCHK_REP, &fi->pending_irqs); 18918c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 18928c2ecf20Sopenharmony_ci kfree(inti); 18938c2ecf20Sopenharmony_ci return 0; 18948c2ecf20Sopenharmony_ci} 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_cistatic int __inject_io(struct kvm *kvm, struct kvm_s390_interrupt_info *inti) 18978c2ecf20Sopenharmony_ci{ 18988c2ecf20Sopenharmony_ci struct kvm_s390_gisa_interrupt *gi = &kvm->arch.gisa_int; 18998c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi; 19008c2ecf20Sopenharmony_ci struct list_head *list; 19018c2ecf20Sopenharmony_ci int isc; 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci kvm->stat.inject_io++; 19048c2ecf20Sopenharmony_ci isc = int_word_to_isc(inti->io.io_int_word); 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci /* 19078c2ecf20Sopenharmony_ci * Do not make use of gisa in protected mode. We do not use the lock 19088c2ecf20Sopenharmony_ci * checking variant as this is just a performance optimization and we 19098c2ecf20Sopenharmony_ci * do not hold the lock here. This is ok as the code will pick 19108c2ecf20Sopenharmony_ci * interrupts from both "lists" for delivery. 19118c2ecf20Sopenharmony_ci */ 19128c2ecf20Sopenharmony_ci if (!kvm_s390_pv_get_handle(kvm) && 19138c2ecf20Sopenharmony_ci gi->origin && inti->type & KVM_S390_INT_IO_AI_MASK) { 19148c2ecf20Sopenharmony_ci VM_EVENT(kvm, 4, "%s isc %1u", "inject: I/O (AI/gisa)", isc); 19158c2ecf20Sopenharmony_ci gisa_set_ipm_gisc(gi->origin, isc); 19168c2ecf20Sopenharmony_ci kfree(inti); 19178c2ecf20Sopenharmony_ci return 0; 19188c2ecf20Sopenharmony_ci } 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci fi = &kvm->arch.float_int; 19218c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 19228c2ecf20Sopenharmony_ci if (fi->counters[FIRQ_CNTR_IO] >= KVM_S390_MAX_FLOAT_IRQS) { 19238c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 19248c2ecf20Sopenharmony_ci return -EBUSY; 19258c2ecf20Sopenharmony_ci } 19268c2ecf20Sopenharmony_ci fi->counters[FIRQ_CNTR_IO] += 1; 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci if (inti->type & KVM_S390_INT_IO_AI_MASK) 19298c2ecf20Sopenharmony_ci VM_EVENT(kvm, 4, "%s", "inject: I/O (AI)"); 19308c2ecf20Sopenharmony_ci else 19318c2ecf20Sopenharmony_ci VM_EVENT(kvm, 4, "inject: I/O %x ss %x schid %04x", 19328c2ecf20Sopenharmony_ci inti->io.subchannel_id >> 8, 19338c2ecf20Sopenharmony_ci inti->io.subchannel_id >> 1 & 0x3, 19348c2ecf20Sopenharmony_ci inti->io.subchannel_nr); 19358c2ecf20Sopenharmony_ci list = &fi->lists[FIRQ_LIST_IO_ISC_0 + isc]; 19368c2ecf20Sopenharmony_ci list_add_tail(&inti->list, list); 19378c2ecf20Sopenharmony_ci set_bit(isc_to_irq_type(isc), &fi->pending_irqs); 19388c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 19398c2ecf20Sopenharmony_ci return 0; 19408c2ecf20Sopenharmony_ci} 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci/* 19438c2ecf20Sopenharmony_ci * Find a destination VCPU for a floating irq and kick it. 19448c2ecf20Sopenharmony_ci */ 19458c2ecf20Sopenharmony_cistatic void __floating_irq_kick(struct kvm *kvm, u64 type) 19468c2ecf20Sopenharmony_ci{ 19478c2ecf20Sopenharmony_ci struct kvm_vcpu *dst_vcpu; 19488c2ecf20Sopenharmony_ci int sigcpu, online_vcpus, nr_tries = 0; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci online_vcpus = atomic_read(&kvm->online_vcpus); 19518c2ecf20Sopenharmony_ci if (!online_vcpus) 19528c2ecf20Sopenharmony_ci return; 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci /* find idle VCPUs first, then round robin */ 19558c2ecf20Sopenharmony_ci sigcpu = find_first_bit(kvm->arch.idle_mask, online_vcpus); 19568c2ecf20Sopenharmony_ci if (sigcpu == online_vcpus) { 19578c2ecf20Sopenharmony_ci do { 19588c2ecf20Sopenharmony_ci sigcpu = kvm->arch.float_int.next_rr_cpu++; 19598c2ecf20Sopenharmony_ci kvm->arch.float_int.next_rr_cpu %= online_vcpus; 19608c2ecf20Sopenharmony_ci /* avoid endless loops if all vcpus are stopped */ 19618c2ecf20Sopenharmony_ci if (nr_tries++ >= online_vcpus) 19628c2ecf20Sopenharmony_ci return; 19638c2ecf20Sopenharmony_ci } while (is_vcpu_stopped(kvm_get_vcpu(kvm, sigcpu))); 19648c2ecf20Sopenharmony_ci } 19658c2ecf20Sopenharmony_ci dst_vcpu = kvm_get_vcpu(kvm, sigcpu); 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci /* make the VCPU drop out of the SIE, or wake it up if sleeping */ 19688c2ecf20Sopenharmony_ci switch (type) { 19698c2ecf20Sopenharmony_ci case KVM_S390_MCHK: 19708c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_STOP_INT); 19718c2ecf20Sopenharmony_ci break; 19728c2ecf20Sopenharmony_ci case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: 19738c2ecf20Sopenharmony_ci if (!(type & KVM_S390_INT_IO_AI_MASK && 19748c2ecf20Sopenharmony_ci kvm->arch.gisa_int.origin) || 19758c2ecf20Sopenharmony_ci kvm_s390_pv_cpu_get_handle(dst_vcpu)) 19768c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_IO_INT); 19778c2ecf20Sopenharmony_ci break; 19788c2ecf20Sopenharmony_ci default: 19798c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_EXT_INT); 19808c2ecf20Sopenharmony_ci break; 19818c2ecf20Sopenharmony_ci } 19828c2ecf20Sopenharmony_ci kvm_s390_vcpu_wakeup(dst_vcpu); 19838c2ecf20Sopenharmony_ci} 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_cistatic int __inject_vm(struct kvm *kvm, struct kvm_s390_interrupt_info *inti) 19868c2ecf20Sopenharmony_ci{ 19878c2ecf20Sopenharmony_ci u64 type = READ_ONCE(inti->type); 19888c2ecf20Sopenharmony_ci int rc; 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci switch (type) { 19918c2ecf20Sopenharmony_ci case KVM_S390_MCHK: 19928c2ecf20Sopenharmony_ci rc = __inject_float_mchk(kvm, inti); 19938c2ecf20Sopenharmony_ci break; 19948c2ecf20Sopenharmony_ci case KVM_S390_INT_VIRTIO: 19958c2ecf20Sopenharmony_ci rc = __inject_virtio(kvm, inti); 19968c2ecf20Sopenharmony_ci break; 19978c2ecf20Sopenharmony_ci case KVM_S390_INT_SERVICE: 19988c2ecf20Sopenharmony_ci rc = __inject_service(kvm, inti); 19998c2ecf20Sopenharmony_ci break; 20008c2ecf20Sopenharmony_ci case KVM_S390_INT_PFAULT_DONE: 20018c2ecf20Sopenharmony_ci rc = __inject_pfault_done(kvm, inti); 20028c2ecf20Sopenharmony_ci break; 20038c2ecf20Sopenharmony_ci case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: 20048c2ecf20Sopenharmony_ci rc = __inject_io(kvm, inti); 20058c2ecf20Sopenharmony_ci break; 20068c2ecf20Sopenharmony_ci default: 20078c2ecf20Sopenharmony_ci rc = -EINVAL; 20088c2ecf20Sopenharmony_ci } 20098c2ecf20Sopenharmony_ci if (rc) 20108c2ecf20Sopenharmony_ci return rc; 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci __floating_irq_kick(kvm, type); 20138c2ecf20Sopenharmony_ci return 0; 20148c2ecf20Sopenharmony_ci} 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ciint kvm_s390_inject_vm(struct kvm *kvm, 20178c2ecf20Sopenharmony_ci struct kvm_s390_interrupt *s390int) 20188c2ecf20Sopenharmony_ci{ 20198c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti; 20208c2ecf20Sopenharmony_ci int rc; 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci inti = kzalloc(sizeof(*inti), GFP_KERNEL); 20238c2ecf20Sopenharmony_ci if (!inti) 20248c2ecf20Sopenharmony_ci return -ENOMEM; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci inti->type = s390int->type; 20278c2ecf20Sopenharmony_ci switch (inti->type) { 20288c2ecf20Sopenharmony_ci case KVM_S390_INT_VIRTIO: 20298c2ecf20Sopenharmony_ci VM_EVENT(kvm, 5, "inject: virtio parm:%x,parm64:%llx", 20308c2ecf20Sopenharmony_ci s390int->parm, s390int->parm64); 20318c2ecf20Sopenharmony_ci inti->ext.ext_params = s390int->parm; 20328c2ecf20Sopenharmony_ci inti->ext.ext_params2 = s390int->parm64; 20338c2ecf20Sopenharmony_ci break; 20348c2ecf20Sopenharmony_ci case KVM_S390_INT_SERVICE: 20358c2ecf20Sopenharmony_ci VM_EVENT(kvm, 4, "inject: sclp parm:%x", s390int->parm); 20368c2ecf20Sopenharmony_ci inti->ext.ext_params = s390int->parm; 20378c2ecf20Sopenharmony_ci break; 20388c2ecf20Sopenharmony_ci case KVM_S390_INT_PFAULT_DONE: 20398c2ecf20Sopenharmony_ci inti->ext.ext_params2 = s390int->parm64; 20408c2ecf20Sopenharmony_ci break; 20418c2ecf20Sopenharmony_ci case KVM_S390_MCHK: 20428c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "inject: machine check mcic 0x%llx", 20438c2ecf20Sopenharmony_ci s390int->parm64); 20448c2ecf20Sopenharmony_ci inti->mchk.cr14 = s390int->parm; /* upper bits are not used */ 20458c2ecf20Sopenharmony_ci inti->mchk.mcic = s390int->parm64; 20468c2ecf20Sopenharmony_ci break; 20478c2ecf20Sopenharmony_ci case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: 20488c2ecf20Sopenharmony_ci inti->io.subchannel_id = s390int->parm >> 16; 20498c2ecf20Sopenharmony_ci inti->io.subchannel_nr = s390int->parm & 0x0000ffffu; 20508c2ecf20Sopenharmony_ci inti->io.io_int_parm = s390int->parm64 >> 32; 20518c2ecf20Sopenharmony_ci inti->io.io_int_word = s390int->parm64 & 0x00000000ffffffffull; 20528c2ecf20Sopenharmony_ci break; 20538c2ecf20Sopenharmony_ci default: 20548c2ecf20Sopenharmony_ci kfree(inti); 20558c2ecf20Sopenharmony_ci return -EINVAL; 20568c2ecf20Sopenharmony_ci } 20578c2ecf20Sopenharmony_ci trace_kvm_s390_inject_vm(s390int->type, s390int->parm, s390int->parm64, 20588c2ecf20Sopenharmony_ci 2); 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci rc = __inject_vm(kvm, inti); 20618c2ecf20Sopenharmony_ci if (rc) 20628c2ecf20Sopenharmony_ci kfree(inti); 20638c2ecf20Sopenharmony_ci return rc; 20648c2ecf20Sopenharmony_ci} 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ciint kvm_s390_reinject_io_int(struct kvm *kvm, 20678c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti) 20688c2ecf20Sopenharmony_ci{ 20698c2ecf20Sopenharmony_ci return __inject_vm(kvm, inti); 20708c2ecf20Sopenharmony_ci} 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ciint s390int_to_s390irq(struct kvm_s390_interrupt *s390int, 20738c2ecf20Sopenharmony_ci struct kvm_s390_irq *irq) 20748c2ecf20Sopenharmony_ci{ 20758c2ecf20Sopenharmony_ci irq->type = s390int->type; 20768c2ecf20Sopenharmony_ci switch (irq->type) { 20778c2ecf20Sopenharmony_ci case KVM_S390_PROGRAM_INT: 20788c2ecf20Sopenharmony_ci if (s390int->parm & 0xffff0000) 20798c2ecf20Sopenharmony_ci return -EINVAL; 20808c2ecf20Sopenharmony_ci irq->u.pgm.code = s390int->parm; 20818c2ecf20Sopenharmony_ci break; 20828c2ecf20Sopenharmony_ci case KVM_S390_SIGP_SET_PREFIX: 20838c2ecf20Sopenharmony_ci irq->u.prefix.address = s390int->parm; 20848c2ecf20Sopenharmony_ci break; 20858c2ecf20Sopenharmony_ci case KVM_S390_SIGP_STOP: 20868c2ecf20Sopenharmony_ci irq->u.stop.flags = s390int->parm; 20878c2ecf20Sopenharmony_ci break; 20888c2ecf20Sopenharmony_ci case KVM_S390_INT_EXTERNAL_CALL: 20898c2ecf20Sopenharmony_ci if (s390int->parm & 0xffff0000) 20908c2ecf20Sopenharmony_ci return -EINVAL; 20918c2ecf20Sopenharmony_ci irq->u.extcall.code = s390int->parm; 20928c2ecf20Sopenharmony_ci break; 20938c2ecf20Sopenharmony_ci case KVM_S390_INT_EMERGENCY: 20948c2ecf20Sopenharmony_ci if (s390int->parm & 0xffff0000) 20958c2ecf20Sopenharmony_ci return -EINVAL; 20968c2ecf20Sopenharmony_ci irq->u.emerg.code = s390int->parm; 20978c2ecf20Sopenharmony_ci break; 20988c2ecf20Sopenharmony_ci case KVM_S390_MCHK: 20998c2ecf20Sopenharmony_ci irq->u.mchk.mcic = s390int->parm64; 21008c2ecf20Sopenharmony_ci break; 21018c2ecf20Sopenharmony_ci case KVM_S390_INT_PFAULT_INIT: 21028c2ecf20Sopenharmony_ci irq->u.ext.ext_params = s390int->parm; 21038c2ecf20Sopenharmony_ci irq->u.ext.ext_params2 = s390int->parm64; 21048c2ecf20Sopenharmony_ci break; 21058c2ecf20Sopenharmony_ci case KVM_S390_RESTART: 21068c2ecf20Sopenharmony_ci case KVM_S390_INT_CLOCK_COMP: 21078c2ecf20Sopenharmony_ci case KVM_S390_INT_CPU_TIMER: 21088c2ecf20Sopenharmony_ci break; 21098c2ecf20Sopenharmony_ci default: 21108c2ecf20Sopenharmony_ci return -EINVAL; 21118c2ecf20Sopenharmony_ci } 21128c2ecf20Sopenharmony_ci return 0; 21138c2ecf20Sopenharmony_ci} 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ciint kvm_s390_is_stop_irq_pending(struct kvm_vcpu *vcpu) 21168c2ecf20Sopenharmony_ci{ 21178c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci return test_bit(IRQ_PEND_SIGP_STOP, &li->pending_irqs); 21208c2ecf20Sopenharmony_ci} 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ciint kvm_s390_is_restart_irq_pending(struct kvm_vcpu *vcpu) 21238c2ecf20Sopenharmony_ci{ 21248c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci return test_bit(IRQ_PEND_RESTART, &li->pending_irqs); 21278c2ecf20Sopenharmony_ci} 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_civoid kvm_s390_clear_stop_irq(struct kvm_vcpu *vcpu) 21308c2ecf20Sopenharmony_ci{ 21318c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci spin_lock(&li->lock); 21348c2ecf20Sopenharmony_ci li->irq.stop.flags = 0; 21358c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_SIGP_STOP, &li->pending_irqs); 21368c2ecf20Sopenharmony_ci spin_unlock(&li->lock); 21378c2ecf20Sopenharmony_ci} 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_cistatic int do_inject_vcpu(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) 21408c2ecf20Sopenharmony_ci{ 21418c2ecf20Sopenharmony_ci int rc; 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci switch (irq->type) { 21448c2ecf20Sopenharmony_ci case KVM_S390_PROGRAM_INT: 21458c2ecf20Sopenharmony_ci rc = __inject_prog(vcpu, irq); 21468c2ecf20Sopenharmony_ci break; 21478c2ecf20Sopenharmony_ci case KVM_S390_SIGP_SET_PREFIX: 21488c2ecf20Sopenharmony_ci rc = __inject_set_prefix(vcpu, irq); 21498c2ecf20Sopenharmony_ci break; 21508c2ecf20Sopenharmony_ci case KVM_S390_SIGP_STOP: 21518c2ecf20Sopenharmony_ci rc = __inject_sigp_stop(vcpu, irq); 21528c2ecf20Sopenharmony_ci break; 21538c2ecf20Sopenharmony_ci case KVM_S390_RESTART: 21548c2ecf20Sopenharmony_ci rc = __inject_sigp_restart(vcpu); 21558c2ecf20Sopenharmony_ci break; 21568c2ecf20Sopenharmony_ci case KVM_S390_INT_CLOCK_COMP: 21578c2ecf20Sopenharmony_ci rc = __inject_ckc(vcpu); 21588c2ecf20Sopenharmony_ci break; 21598c2ecf20Sopenharmony_ci case KVM_S390_INT_CPU_TIMER: 21608c2ecf20Sopenharmony_ci rc = __inject_cpu_timer(vcpu); 21618c2ecf20Sopenharmony_ci break; 21628c2ecf20Sopenharmony_ci case KVM_S390_INT_EXTERNAL_CALL: 21638c2ecf20Sopenharmony_ci rc = __inject_extcall(vcpu, irq); 21648c2ecf20Sopenharmony_ci break; 21658c2ecf20Sopenharmony_ci case KVM_S390_INT_EMERGENCY: 21668c2ecf20Sopenharmony_ci rc = __inject_sigp_emergency(vcpu, irq); 21678c2ecf20Sopenharmony_ci break; 21688c2ecf20Sopenharmony_ci case KVM_S390_MCHK: 21698c2ecf20Sopenharmony_ci rc = __inject_mchk(vcpu, irq); 21708c2ecf20Sopenharmony_ci break; 21718c2ecf20Sopenharmony_ci case KVM_S390_INT_PFAULT_INIT: 21728c2ecf20Sopenharmony_ci rc = __inject_pfault_init(vcpu, irq); 21738c2ecf20Sopenharmony_ci break; 21748c2ecf20Sopenharmony_ci case KVM_S390_INT_VIRTIO: 21758c2ecf20Sopenharmony_ci case KVM_S390_INT_SERVICE: 21768c2ecf20Sopenharmony_ci case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: 21778c2ecf20Sopenharmony_ci default: 21788c2ecf20Sopenharmony_ci rc = -EINVAL; 21798c2ecf20Sopenharmony_ci } 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci return rc; 21828c2ecf20Sopenharmony_ci} 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ciint kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) 21858c2ecf20Sopenharmony_ci{ 21868c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 21878c2ecf20Sopenharmony_ci int rc; 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci spin_lock(&li->lock); 21908c2ecf20Sopenharmony_ci rc = do_inject_vcpu(vcpu, irq); 21918c2ecf20Sopenharmony_ci spin_unlock(&li->lock); 21928c2ecf20Sopenharmony_ci if (!rc) 21938c2ecf20Sopenharmony_ci kvm_s390_vcpu_wakeup(vcpu); 21948c2ecf20Sopenharmony_ci return rc; 21958c2ecf20Sopenharmony_ci} 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_cistatic inline void clear_irq_list(struct list_head *_list) 21988c2ecf20Sopenharmony_ci{ 21998c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti, *n; 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci list_for_each_entry_safe(inti, n, _list, list) { 22028c2ecf20Sopenharmony_ci list_del(&inti->list); 22038c2ecf20Sopenharmony_ci kfree(inti); 22048c2ecf20Sopenharmony_ci } 22058c2ecf20Sopenharmony_ci} 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_cistatic void inti_to_irq(struct kvm_s390_interrupt_info *inti, 22088c2ecf20Sopenharmony_ci struct kvm_s390_irq *irq) 22098c2ecf20Sopenharmony_ci{ 22108c2ecf20Sopenharmony_ci irq->type = inti->type; 22118c2ecf20Sopenharmony_ci switch (inti->type) { 22128c2ecf20Sopenharmony_ci case KVM_S390_INT_PFAULT_INIT: 22138c2ecf20Sopenharmony_ci case KVM_S390_INT_PFAULT_DONE: 22148c2ecf20Sopenharmony_ci case KVM_S390_INT_VIRTIO: 22158c2ecf20Sopenharmony_ci irq->u.ext = inti->ext; 22168c2ecf20Sopenharmony_ci break; 22178c2ecf20Sopenharmony_ci case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: 22188c2ecf20Sopenharmony_ci irq->u.io = inti->io; 22198c2ecf20Sopenharmony_ci break; 22208c2ecf20Sopenharmony_ci } 22218c2ecf20Sopenharmony_ci} 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_civoid kvm_s390_clear_float_irqs(struct kvm *kvm) 22248c2ecf20Sopenharmony_ci{ 22258c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int; 22268c2ecf20Sopenharmony_ci int i; 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 22298c2ecf20Sopenharmony_ci if (!kvm_s390_pv_is_protected(kvm)) 22308c2ecf20Sopenharmony_ci fi->masked_irqs = 0; 22318c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 22328c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 22338c2ecf20Sopenharmony_ci fi->pending_irqs = 0; 22348c2ecf20Sopenharmony_ci memset(&fi->srv_signal, 0, sizeof(fi->srv_signal)); 22358c2ecf20Sopenharmony_ci memset(&fi->mchk, 0, sizeof(fi->mchk)); 22368c2ecf20Sopenharmony_ci for (i = 0; i < FIRQ_LIST_COUNT; i++) 22378c2ecf20Sopenharmony_ci clear_irq_list(&fi->lists[i]); 22388c2ecf20Sopenharmony_ci for (i = 0; i < FIRQ_MAX_COUNT; i++) 22398c2ecf20Sopenharmony_ci fi->counters[i] = 0; 22408c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 22418c2ecf20Sopenharmony_ci kvm_s390_gisa_clear(kvm); 22428c2ecf20Sopenharmony_ci}; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_cistatic int get_all_floating_irqs(struct kvm *kvm, u8 __user *usrbuf, u64 len) 22458c2ecf20Sopenharmony_ci{ 22468c2ecf20Sopenharmony_ci struct kvm_s390_gisa_interrupt *gi = &kvm->arch.gisa_int; 22478c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti; 22488c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi; 22498c2ecf20Sopenharmony_ci struct kvm_s390_irq *buf; 22508c2ecf20Sopenharmony_ci struct kvm_s390_irq *irq; 22518c2ecf20Sopenharmony_ci int max_irqs; 22528c2ecf20Sopenharmony_ci int ret = 0; 22538c2ecf20Sopenharmony_ci int n = 0; 22548c2ecf20Sopenharmony_ci int i; 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci if (len > KVM_S390_FLIC_MAX_BUFFER || len == 0) 22578c2ecf20Sopenharmony_ci return -EINVAL; 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci /* 22608c2ecf20Sopenharmony_ci * We are already using -ENOMEM to signal 22618c2ecf20Sopenharmony_ci * userspace it may retry with a bigger buffer, 22628c2ecf20Sopenharmony_ci * so we need to use something else for this case 22638c2ecf20Sopenharmony_ci */ 22648c2ecf20Sopenharmony_ci buf = vzalloc(len); 22658c2ecf20Sopenharmony_ci if (!buf) 22668c2ecf20Sopenharmony_ci return -ENOBUFS; 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci max_irqs = len / sizeof(struct kvm_s390_irq); 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci if (gi->origin && gisa_get_ipm(gi->origin)) { 22718c2ecf20Sopenharmony_ci for (i = 0; i <= MAX_ISC; i++) { 22728c2ecf20Sopenharmony_ci if (n == max_irqs) { 22738c2ecf20Sopenharmony_ci /* signal userspace to try again */ 22748c2ecf20Sopenharmony_ci ret = -ENOMEM; 22758c2ecf20Sopenharmony_ci goto out_nolock; 22768c2ecf20Sopenharmony_ci } 22778c2ecf20Sopenharmony_ci if (gisa_tac_ipm_gisc(gi->origin, i)) { 22788c2ecf20Sopenharmony_ci irq = (struct kvm_s390_irq *) &buf[n]; 22798c2ecf20Sopenharmony_ci irq->type = KVM_S390_INT_IO(1, 0, 0, 0); 22808c2ecf20Sopenharmony_ci irq->u.io.io_int_word = isc_to_int_word(i); 22818c2ecf20Sopenharmony_ci n++; 22828c2ecf20Sopenharmony_ci } 22838c2ecf20Sopenharmony_ci } 22848c2ecf20Sopenharmony_ci } 22858c2ecf20Sopenharmony_ci fi = &kvm->arch.float_int; 22868c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 22878c2ecf20Sopenharmony_ci for (i = 0; i < FIRQ_LIST_COUNT; i++) { 22888c2ecf20Sopenharmony_ci list_for_each_entry(inti, &fi->lists[i], list) { 22898c2ecf20Sopenharmony_ci if (n == max_irqs) { 22908c2ecf20Sopenharmony_ci /* signal userspace to try again */ 22918c2ecf20Sopenharmony_ci ret = -ENOMEM; 22928c2ecf20Sopenharmony_ci goto out; 22938c2ecf20Sopenharmony_ci } 22948c2ecf20Sopenharmony_ci inti_to_irq(inti, &buf[n]); 22958c2ecf20Sopenharmony_ci n++; 22968c2ecf20Sopenharmony_ci } 22978c2ecf20Sopenharmony_ci } 22988c2ecf20Sopenharmony_ci if (test_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs) || 22998c2ecf20Sopenharmony_ci test_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs)) { 23008c2ecf20Sopenharmony_ci if (n == max_irqs) { 23018c2ecf20Sopenharmony_ci /* signal userspace to try again */ 23028c2ecf20Sopenharmony_ci ret = -ENOMEM; 23038c2ecf20Sopenharmony_ci goto out; 23048c2ecf20Sopenharmony_ci } 23058c2ecf20Sopenharmony_ci irq = (struct kvm_s390_irq *) &buf[n]; 23068c2ecf20Sopenharmony_ci irq->type = KVM_S390_INT_SERVICE; 23078c2ecf20Sopenharmony_ci irq->u.ext = fi->srv_signal; 23088c2ecf20Sopenharmony_ci n++; 23098c2ecf20Sopenharmony_ci } 23108c2ecf20Sopenharmony_ci if (test_bit(IRQ_PEND_MCHK_REP, &fi->pending_irqs)) { 23118c2ecf20Sopenharmony_ci if (n == max_irqs) { 23128c2ecf20Sopenharmony_ci /* signal userspace to try again */ 23138c2ecf20Sopenharmony_ci ret = -ENOMEM; 23148c2ecf20Sopenharmony_ci goto out; 23158c2ecf20Sopenharmony_ci } 23168c2ecf20Sopenharmony_ci irq = (struct kvm_s390_irq *) &buf[n]; 23178c2ecf20Sopenharmony_ci irq->type = KVM_S390_MCHK; 23188c2ecf20Sopenharmony_ci irq->u.mchk = fi->mchk; 23198c2ecf20Sopenharmony_ci n++; 23208c2ecf20Sopenharmony_ci} 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ciout: 23238c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 23248c2ecf20Sopenharmony_ciout_nolock: 23258c2ecf20Sopenharmony_ci if (!ret && n > 0) { 23268c2ecf20Sopenharmony_ci if (copy_to_user(usrbuf, buf, sizeof(struct kvm_s390_irq) * n)) 23278c2ecf20Sopenharmony_ci ret = -EFAULT; 23288c2ecf20Sopenharmony_ci } 23298c2ecf20Sopenharmony_ci vfree(buf); 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci return ret < 0 ? ret : n; 23328c2ecf20Sopenharmony_ci} 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_cistatic int flic_ais_mode_get_all(struct kvm *kvm, struct kvm_device_attr *attr) 23358c2ecf20Sopenharmony_ci{ 23368c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int; 23378c2ecf20Sopenharmony_ci struct kvm_s390_ais_all ais; 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci if (attr->attr < sizeof(ais)) 23408c2ecf20Sopenharmony_ci return -EINVAL; 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci if (!test_kvm_facility(kvm, 72)) 23438c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci mutex_lock(&fi->ais_lock); 23468c2ecf20Sopenharmony_ci ais.simm = fi->simm; 23478c2ecf20Sopenharmony_ci ais.nimm = fi->nimm; 23488c2ecf20Sopenharmony_ci mutex_unlock(&fi->ais_lock); 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)attr->addr, &ais, sizeof(ais))) 23518c2ecf20Sopenharmony_ci return -EFAULT; 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci return 0; 23548c2ecf20Sopenharmony_ci} 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_cistatic int flic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) 23578c2ecf20Sopenharmony_ci{ 23588c2ecf20Sopenharmony_ci int r; 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci switch (attr->group) { 23618c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_GET_ALL_IRQS: 23628c2ecf20Sopenharmony_ci r = get_all_floating_irqs(dev->kvm, (u8 __user *) attr->addr, 23638c2ecf20Sopenharmony_ci attr->attr); 23648c2ecf20Sopenharmony_ci break; 23658c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_AISM_ALL: 23668c2ecf20Sopenharmony_ci r = flic_ais_mode_get_all(dev->kvm, attr); 23678c2ecf20Sopenharmony_ci break; 23688c2ecf20Sopenharmony_ci default: 23698c2ecf20Sopenharmony_ci r = -EINVAL; 23708c2ecf20Sopenharmony_ci } 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci return r; 23738c2ecf20Sopenharmony_ci} 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_cistatic inline int copy_irq_from_user(struct kvm_s390_interrupt_info *inti, 23768c2ecf20Sopenharmony_ci u64 addr) 23778c2ecf20Sopenharmony_ci{ 23788c2ecf20Sopenharmony_ci struct kvm_s390_irq __user *uptr = (struct kvm_s390_irq __user *) addr; 23798c2ecf20Sopenharmony_ci void *target = NULL; 23808c2ecf20Sopenharmony_ci void __user *source; 23818c2ecf20Sopenharmony_ci u64 size; 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci if (get_user(inti->type, (u64 __user *)addr)) 23848c2ecf20Sopenharmony_ci return -EFAULT; 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci switch (inti->type) { 23878c2ecf20Sopenharmony_ci case KVM_S390_INT_PFAULT_INIT: 23888c2ecf20Sopenharmony_ci case KVM_S390_INT_PFAULT_DONE: 23898c2ecf20Sopenharmony_ci case KVM_S390_INT_VIRTIO: 23908c2ecf20Sopenharmony_ci case KVM_S390_INT_SERVICE: 23918c2ecf20Sopenharmony_ci target = (void *) &inti->ext; 23928c2ecf20Sopenharmony_ci source = &uptr->u.ext; 23938c2ecf20Sopenharmony_ci size = sizeof(inti->ext); 23948c2ecf20Sopenharmony_ci break; 23958c2ecf20Sopenharmony_ci case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: 23968c2ecf20Sopenharmony_ci target = (void *) &inti->io; 23978c2ecf20Sopenharmony_ci source = &uptr->u.io; 23988c2ecf20Sopenharmony_ci size = sizeof(inti->io); 23998c2ecf20Sopenharmony_ci break; 24008c2ecf20Sopenharmony_ci case KVM_S390_MCHK: 24018c2ecf20Sopenharmony_ci target = (void *) &inti->mchk; 24028c2ecf20Sopenharmony_ci source = &uptr->u.mchk; 24038c2ecf20Sopenharmony_ci size = sizeof(inti->mchk); 24048c2ecf20Sopenharmony_ci break; 24058c2ecf20Sopenharmony_ci default: 24068c2ecf20Sopenharmony_ci return -EINVAL; 24078c2ecf20Sopenharmony_ci } 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci if (copy_from_user(target, source, size)) 24108c2ecf20Sopenharmony_ci return -EFAULT; 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci return 0; 24138c2ecf20Sopenharmony_ci} 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_cistatic int enqueue_floating_irq(struct kvm_device *dev, 24168c2ecf20Sopenharmony_ci struct kvm_device_attr *attr) 24178c2ecf20Sopenharmony_ci{ 24188c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti = NULL; 24198c2ecf20Sopenharmony_ci int r = 0; 24208c2ecf20Sopenharmony_ci int len = attr->attr; 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci if (len % sizeof(struct kvm_s390_irq) != 0) 24238c2ecf20Sopenharmony_ci return -EINVAL; 24248c2ecf20Sopenharmony_ci else if (len > KVM_S390_FLIC_MAX_BUFFER) 24258c2ecf20Sopenharmony_ci return -EINVAL; 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci while (len >= sizeof(struct kvm_s390_irq)) { 24288c2ecf20Sopenharmony_ci inti = kzalloc(sizeof(*inti), GFP_KERNEL); 24298c2ecf20Sopenharmony_ci if (!inti) 24308c2ecf20Sopenharmony_ci return -ENOMEM; 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci r = copy_irq_from_user(inti, attr->addr); 24338c2ecf20Sopenharmony_ci if (r) { 24348c2ecf20Sopenharmony_ci kfree(inti); 24358c2ecf20Sopenharmony_ci return r; 24368c2ecf20Sopenharmony_ci } 24378c2ecf20Sopenharmony_ci r = __inject_vm(dev->kvm, inti); 24388c2ecf20Sopenharmony_ci if (r) { 24398c2ecf20Sopenharmony_ci kfree(inti); 24408c2ecf20Sopenharmony_ci return r; 24418c2ecf20Sopenharmony_ci } 24428c2ecf20Sopenharmony_ci len -= sizeof(struct kvm_s390_irq); 24438c2ecf20Sopenharmony_ci attr->addr += sizeof(struct kvm_s390_irq); 24448c2ecf20Sopenharmony_ci } 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci return r; 24478c2ecf20Sopenharmony_ci} 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_cistatic struct s390_io_adapter *get_io_adapter(struct kvm *kvm, unsigned int id) 24508c2ecf20Sopenharmony_ci{ 24518c2ecf20Sopenharmony_ci if (id >= MAX_S390_IO_ADAPTERS) 24528c2ecf20Sopenharmony_ci return NULL; 24538c2ecf20Sopenharmony_ci id = array_index_nospec(id, MAX_S390_IO_ADAPTERS); 24548c2ecf20Sopenharmony_ci return kvm->arch.adapters[id]; 24558c2ecf20Sopenharmony_ci} 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_cistatic int register_io_adapter(struct kvm_device *dev, 24588c2ecf20Sopenharmony_ci struct kvm_device_attr *attr) 24598c2ecf20Sopenharmony_ci{ 24608c2ecf20Sopenharmony_ci struct s390_io_adapter *adapter; 24618c2ecf20Sopenharmony_ci struct kvm_s390_io_adapter adapter_info; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci if (copy_from_user(&adapter_info, 24648c2ecf20Sopenharmony_ci (void __user *)attr->addr, sizeof(adapter_info))) 24658c2ecf20Sopenharmony_ci return -EFAULT; 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_ci if (adapter_info.id >= MAX_S390_IO_ADAPTERS) 24688c2ecf20Sopenharmony_ci return -EINVAL; 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci adapter_info.id = array_index_nospec(adapter_info.id, 24718c2ecf20Sopenharmony_ci MAX_S390_IO_ADAPTERS); 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci if (dev->kvm->arch.adapters[adapter_info.id] != NULL) 24748c2ecf20Sopenharmony_ci return -EINVAL; 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); 24778c2ecf20Sopenharmony_ci if (!adapter) 24788c2ecf20Sopenharmony_ci return -ENOMEM; 24798c2ecf20Sopenharmony_ci 24808c2ecf20Sopenharmony_ci adapter->id = adapter_info.id; 24818c2ecf20Sopenharmony_ci adapter->isc = adapter_info.isc; 24828c2ecf20Sopenharmony_ci adapter->maskable = adapter_info.maskable; 24838c2ecf20Sopenharmony_ci adapter->masked = false; 24848c2ecf20Sopenharmony_ci adapter->swap = adapter_info.swap; 24858c2ecf20Sopenharmony_ci adapter->suppressible = (adapter_info.flags) & 24868c2ecf20Sopenharmony_ci KVM_S390_ADAPTER_SUPPRESSIBLE; 24878c2ecf20Sopenharmony_ci dev->kvm->arch.adapters[adapter->id] = adapter; 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci return 0; 24908c2ecf20Sopenharmony_ci} 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ciint kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked) 24938c2ecf20Sopenharmony_ci{ 24948c2ecf20Sopenharmony_ci int ret; 24958c2ecf20Sopenharmony_ci struct s390_io_adapter *adapter = get_io_adapter(kvm, id); 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci if (!adapter || !adapter->maskable) 24988c2ecf20Sopenharmony_ci return -EINVAL; 24998c2ecf20Sopenharmony_ci ret = adapter->masked; 25008c2ecf20Sopenharmony_ci adapter->masked = masked; 25018c2ecf20Sopenharmony_ci return ret; 25028c2ecf20Sopenharmony_ci} 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_civoid kvm_s390_destroy_adapters(struct kvm *kvm) 25058c2ecf20Sopenharmony_ci{ 25068c2ecf20Sopenharmony_ci int i; 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci for (i = 0; i < MAX_S390_IO_ADAPTERS; i++) 25098c2ecf20Sopenharmony_ci kfree(kvm->arch.adapters[i]); 25108c2ecf20Sopenharmony_ci} 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_cistatic int modify_io_adapter(struct kvm_device *dev, 25138c2ecf20Sopenharmony_ci struct kvm_device_attr *attr) 25148c2ecf20Sopenharmony_ci{ 25158c2ecf20Sopenharmony_ci struct kvm_s390_io_adapter_req req; 25168c2ecf20Sopenharmony_ci struct s390_io_adapter *adapter; 25178c2ecf20Sopenharmony_ci int ret; 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci if (copy_from_user(&req, (void __user *)attr->addr, sizeof(req))) 25208c2ecf20Sopenharmony_ci return -EFAULT; 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_ci adapter = get_io_adapter(dev->kvm, req.id); 25238c2ecf20Sopenharmony_ci if (!adapter) 25248c2ecf20Sopenharmony_ci return -EINVAL; 25258c2ecf20Sopenharmony_ci switch (req.type) { 25268c2ecf20Sopenharmony_ci case KVM_S390_IO_ADAPTER_MASK: 25278c2ecf20Sopenharmony_ci ret = kvm_s390_mask_adapter(dev->kvm, req.id, req.mask); 25288c2ecf20Sopenharmony_ci if (ret > 0) 25298c2ecf20Sopenharmony_ci ret = 0; 25308c2ecf20Sopenharmony_ci break; 25318c2ecf20Sopenharmony_ci /* 25328c2ecf20Sopenharmony_ci * The following operations are no longer needed and therefore no-ops. 25338c2ecf20Sopenharmony_ci * The gpa to hva translation is done when an IRQ route is set up. The 25348c2ecf20Sopenharmony_ci * set_irq code uses get_user_pages_remote() to do the actual write. 25358c2ecf20Sopenharmony_ci */ 25368c2ecf20Sopenharmony_ci case KVM_S390_IO_ADAPTER_MAP: 25378c2ecf20Sopenharmony_ci case KVM_S390_IO_ADAPTER_UNMAP: 25388c2ecf20Sopenharmony_ci ret = 0; 25398c2ecf20Sopenharmony_ci break; 25408c2ecf20Sopenharmony_ci default: 25418c2ecf20Sopenharmony_ci ret = -EINVAL; 25428c2ecf20Sopenharmony_ci } 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci return ret; 25458c2ecf20Sopenharmony_ci} 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_cistatic int clear_io_irq(struct kvm *kvm, struct kvm_device_attr *attr) 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci{ 25508c2ecf20Sopenharmony_ci const u64 isc_mask = 0xffUL << 24; /* all iscs set */ 25518c2ecf20Sopenharmony_ci u32 schid; 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci if (attr->flags) 25548c2ecf20Sopenharmony_ci return -EINVAL; 25558c2ecf20Sopenharmony_ci if (attr->attr != sizeof(schid)) 25568c2ecf20Sopenharmony_ci return -EINVAL; 25578c2ecf20Sopenharmony_ci if (copy_from_user(&schid, (void __user *) attr->addr, sizeof(schid))) 25588c2ecf20Sopenharmony_ci return -EFAULT; 25598c2ecf20Sopenharmony_ci if (!schid) 25608c2ecf20Sopenharmony_ci return -EINVAL; 25618c2ecf20Sopenharmony_ci kfree(kvm_s390_get_io_int(kvm, isc_mask, schid)); 25628c2ecf20Sopenharmony_ci /* 25638c2ecf20Sopenharmony_ci * If userspace is conforming to the architecture, we can have at most 25648c2ecf20Sopenharmony_ci * one pending I/O interrupt per subchannel, so this is effectively a 25658c2ecf20Sopenharmony_ci * clear all. 25668c2ecf20Sopenharmony_ci */ 25678c2ecf20Sopenharmony_ci return 0; 25688c2ecf20Sopenharmony_ci} 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_cistatic int modify_ais_mode(struct kvm *kvm, struct kvm_device_attr *attr) 25718c2ecf20Sopenharmony_ci{ 25728c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int; 25738c2ecf20Sopenharmony_ci struct kvm_s390_ais_req req; 25748c2ecf20Sopenharmony_ci int ret = 0; 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_ci if (!test_kvm_facility(kvm, 72)) 25778c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci if (copy_from_user(&req, (void __user *)attr->addr, sizeof(req))) 25808c2ecf20Sopenharmony_ci return -EFAULT; 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_ci if (req.isc > MAX_ISC) 25838c2ecf20Sopenharmony_ci return -EINVAL; 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci trace_kvm_s390_modify_ais_mode(req.isc, 25868c2ecf20Sopenharmony_ci (fi->simm & AIS_MODE_MASK(req.isc)) ? 25878c2ecf20Sopenharmony_ci (fi->nimm & AIS_MODE_MASK(req.isc)) ? 25888c2ecf20Sopenharmony_ci 2 : KVM_S390_AIS_MODE_SINGLE : 25898c2ecf20Sopenharmony_ci KVM_S390_AIS_MODE_ALL, req.mode); 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci mutex_lock(&fi->ais_lock); 25928c2ecf20Sopenharmony_ci switch (req.mode) { 25938c2ecf20Sopenharmony_ci case KVM_S390_AIS_MODE_ALL: 25948c2ecf20Sopenharmony_ci fi->simm &= ~AIS_MODE_MASK(req.isc); 25958c2ecf20Sopenharmony_ci fi->nimm &= ~AIS_MODE_MASK(req.isc); 25968c2ecf20Sopenharmony_ci break; 25978c2ecf20Sopenharmony_ci case KVM_S390_AIS_MODE_SINGLE: 25988c2ecf20Sopenharmony_ci fi->simm |= AIS_MODE_MASK(req.isc); 25998c2ecf20Sopenharmony_ci fi->nimm &= ~AIS_MODE_MASK(req.isc); 26008c2ecf20Sopenharmony_ci break; 26018c2ecf20Sopenharmony_ci default: 26028c2ecf20Sopenharmony_ci ret = -EINVAL; 26038c2ecf20Sopenharmony_ci } 26048c2ecf20Sopenharmony_ci mutex_unlock(&fi->ais_lock); 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci return ret; 26078c2ecf20Sopenharmony_ci} 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_cistatic int kvm_s390_inject_airq(struct kvm *kvm, 26108c2ecf20Sopenharmony_ci struct s390_io_adapter *adapter) 26118c2ecf20Sopenharmony_ci{ 26128c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int; 26138c2ecf20Sopenharmony_ci struct kvm_s390_interrupt s390int = { 26148c2ecf20Sopenharmony_ci .type = KVM_S390_INT_IO(1, 0, 0, 0), 26158c2ecf20Sopenharmony_ci .parm = 0, 26168c2ecf20Sopenharmony_ci .parm64 = isc_to_int_word(adapter->isc), 26178c2ecf20Sopenharmony_ci }; 26188c2ecf20Sopenharmony_ci int ret = 0; 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci if (!test_kvm_facility(kvm, 72) || !adapter->suppressible) 26218c2ecf20Sopenharmony_ci return kvm_s390_inject_vm(kvm, &s390int); 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci mutex_lock(&fi->ais_lock); 26248c2ecf20Sopenharmony_ci if (fi->nimm & AIS_MODE_MASK(adapter->isc)) { 26258c2ecf20Sopenharmony_ci trace_kvm_s390_airq_suppressed(adapter->id, adapter->isc); 26268c2ecf20Sopenharmony_ci goto out; 26278c2ecf20Sopenharmony_ci } 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci ret = kvm_s390_inject_vm(kvm, &s390int); 26308c2ecf20Sopenharmony_ci if (!ret && (fi->simm & AIS_MODE_MASK(adapter->isc))) { 26318c2ecf20Sopenharmony_ci fi->nimm |= AIS_MODE_MASK(adapter->isc); 26328c2ecf20Sopenharmony_ci trace_kvm_s390_modify_ais_mode(adapter->isc, 26338c2ecf20Sopenharmony_ci KVM_S390_AIS_MODE_SINGLE, 2); 26348c2ecf20Sopenharmony_ci } 26358c2ecf20Sopenharmony_ciout: 26368c2ecf20Sopenharmony_ci mutex_unlock(&fi->ais_lock); 26378c2ecf20Sopenharmony_ci return ret; 26388c2ecf20Sopenharmony_ci} 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_cistatic int flic_inject_airq(struct kvm *kvm, struct kvm_device_attr *attr) 26418c2ecf20Sopenharmony_ci{ 26428c2ecf20Sopenharmony_ci unsigned int id = attr->attr; 26438c2ecf20Sopenharmony_ci struct s390_io_adapter *adapter = get_io_adapter(kvm, id); 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci if (!adapter) 26468c2ecf20Sopenharmony_ci return -EINVAL; 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci return kvm_s390_inject_airq(kvm, adapter); 26498c2ecf20Sopenharmony_ci} 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_cistatic int flic_ais_mode_set_all(struct kvm *kvm, struct kvm_device_attr *attr) 26528c2ecf20Sopenharmony_ci{ 26538c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int; 26548c2ecf20Sopenharmony_ci struct kvm_s390_ais_all ais; 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_ci if (!test_kvm_facility(kvm, 72)) 26578c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci if (copy_from_user(&ais, (void __user *)attr->addr, sizeof(ais))) 26608c2ecf20Sopenharmony_ci return -EFAULT; 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci mutex_lock(&fi->ais_lock); 26638c2ecf20Sopenharmony_ci fi->simm = ais.simm; 26648c2ecf20Sopenharmony_ci fi->nimm = ais.nimm; 26658c2ecf20Sopenharmony_ci mutex_unlock(&fi->ais_lock); 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci return 0; 26688c2ecf20Sopenharmony_ci} 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_cistatic int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) 26718c2ecf20Sopenharmony_ci{ 26728c2ecf20Sopenharmony_ci int r = 0; 26738c2ecf20Sopenharmony_ci unsigned int i; 26748c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci switch (attr->group) { 26778c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_ENQUEUE: 26788c2ecf20Sopenharmony_ci r = enqueue_floating_irq(dev, attr); 26798c2ecf20Sopenharmony_ci break; 26808c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_CLEAR_IRQS: 26818c2ecf20Sopenharmony_ci kvm_s390_clear_float_irqs(dev->kvm); 26828c2ecf20Sopenharmony_ci break; 26838c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_APF_ENABLE: 26848c2ecf20Sopenharmony_ci dev->kvm->arch.gmap->pfault_enabled = 1; 26858c2ecf20Sopenharmony_ci break; 26868c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_APF_DISABLE_WAIT: 26878c2ecf20Sopenharmony_ci dev->kvm->arch.gmap->pfault_enabled = 0; 26888c2ecf20Sopenharmony_ci /* 26898c2ecf20Sopenharmony_ci * Make sure no async faults are in transition when 26908c2ecf20Sopenharmony_ci * clearing the queues. So we don't need to worry 26918c2ecf20Sopenharmony_ci * about late coming workers. 26928c2ecf20Sopenharmony_ci */ 26938c2ecf20Sopenharmony_ci synchronize_srcu(&dev->kvm->srcu); 26948c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, vcpu, dev->kvm) 26958c2ecf20Sopenharmony_ci kvm_clear_async_pf_completion_queue(vcpu); 26968c2ecf20Sopenharmony_ci break; 26978c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_ADAPTER_REGISTER: 26988c2ecf20Sopenharmony_ci r = register_io_adapter(dev, attr); 26998c2ecf20Sopenharmony_ci break; 27008c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_ADAPTER_MODIFY: 27018c2ecf20Sopenharmony_ci r = modify_io_adapter(dev, attr); 27028c2ecf20Sopenharmony_ci break; 27038c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_CLEAR_IO_IRQ: 27048c2ecf20Sopenharmony_ci r = clear_io_irq(dev->kvm, attr); 27058c2ecf20Sopenharmony_ci break; 27068c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_AISM: 27078c2ecf20Sopenharmony_ci r = modify_ais_mode(dev->kvm, attr); 27088c2ecf20Sopenharmony_ci break; 27098c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_AIRQ_INJECT: 27108c2ecf20Sopenharmony_ci r = flic_inject_airq(dev->kvm, attr); 27118c2ecf20Sopenharmony_ci break; 27128c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_AISM_ALL: 27138c2ecf20Sopenharmony_ci r = flic_ais_mode_set_all(dev->kvm, attr); 27148c2ecf20Sopenharmony_ci break; 27158c2ecf20Sopenharmony_ci default: 27168c2ecf20Sopenharmony_ci r = -EINVAL; 27178c2ecf20Sopenharmony_ci } 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci return r; 27208c2ecf20Sopenharmony_ci} 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_cistatic int flic_has_attr(struct kvm_device *dev, 27238c2ecf20Sopenharmony_ci struct kvm_device_attr *attr) 27248c2ecf20Sopenharmony_ci{ 27258c2ecf20Sopenharmony_ci switch (attr->group) { 27268c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_GET_ALL_IRQS: 27278c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_ENQUEUE: 27288c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_CLEAR_IRQS: 27298c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_APF_ENABLE: 27308c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_APF_DISABLE_WAIT: 27318c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_ADAPTER_REGISTER: 27328c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_ADAPTER_MODIFY: 27338c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_CLEAR_IO_IRQ: 27348c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_AISM: 27358c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_AIRQ_INJECT: 27368c2ecf20Sopenharmony_ci case KVM_DEV_FLIC_AISM_ALL: 27378c2ecf20Sopenharmony_ci return 0; 27388c2ecf20Sopenharmony_ci } 27398c2ecf20Sopenharmony_ci return -ENXIO; 27408c2ecf20Sopenharmony_ci} 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_cistatic int flic_create(struct kvm_device *dev, u32 type) 27438c2ecf20Sopenharmony_ci{ 27448c2ecf20Sopenharmony_ci if (!dev) 27458c2ecf20Sopenharmony_ci return -EINVAL; 27468c2ecf20Sopenharmony_ci if (dev->kvm->arch.flic) 27478c2ecf20Sopenharmony_ci return -EINVAL; 27488c2ecf20Sopenharmony_ci dev->kvm->arch.flic = dev; 27498c2ecf20Sopenharmony_ci return 0; 27508c2ecf20Sopenharmony_ci} 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_cistatic void flic_destroy(struct kvm_device *dev) 27538c2ecf20Sopenharmony_ci{ 27548c2ecf20Sopenharmony_ci dev->kvm->arch.flic = NULL; 27558c2ecf20Sopenharmony_ci kfree(dev); 27568c2ecf20Sopenharmony_ci} 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_ci/* s390 floating irq controller (flic) */ 27598c2ecf20Sopenharmony_cistruct kvm_device_ops kvm_flic_ops = { 27608c2ecf20Sopenharmony_ci .name = "kvm-flic", 27618c2ecf20Sopenharmony_ci .get_attr = flic_get_attr, 27628c2ecf20Sopenharmony_ci .set_attr = flic_set_attr, 27638c2ecf20Sopenharmony_ci .has_attr = flic_has_attr, 27648c2ecf20Sopenharmony_ci .create = flic_create, 27658c2ecf20Sopenharmony_ci .destroy = flic_destroy, 27668c2ecf20Sopenharmony_ci}; 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_cistatic unsigned long get_ind_bit(__u64 addr, unsigned long bit_nr, bool swap) 27698c2ecf20Sopenharmony_ci{ 27708c2ecf20Sopenharmony_ci unsigned long bit; 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci bit = bit_nr + (addr % PAGE_SIZE) * 8; 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci return swap ? (bit ^ (BITS_PER_LONG - 1)) : bit; 27758c2ecf20Sopenharmony_ci} 27768c2ecf20Sopenharmony_ci 27778c2ecf20Sopenharmony_cistatic struct page *get_map_page(struct kvm *kvm, u64 uaddr) 27788c2ecf20Sopenharmony_ci{ 27798c2ecf20Sopenharmony_ci struct page *page = NULL; 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci mmap_read_lock(kvm->mm); 27828c2ecf20Sopenharmony_ci get_user_pages_remote(kvm->mm, uaddr, 1, FOLL_WRITE, 27838c2ecf20Sopenharmony_ci &page, NULL, NULL); 27848c2ecf20Sopenharmony_ci mmap_read_unlock(kvm->mm); 27858c2ecf20Sopenharmony_ci return page; 27868c2ecf20Sopenharmony_ci} 27878c2ecf20Sopenharmony_ci 27888c2ecf20Sopenharmony_cistatic int adapter_indicators_set(struct kvm *kvm, 27898c2ecf20Sopenharmony_ci struct s390_io_adapter *adapter, 27908c2ecf20Sopenharmony_ci struct kvm_s390_adapter_int *adapter_int) 27918c2ecf20Sopenharmony_ci{ 27928c2ecf20Sopenharmony_ci unsigned long bit; 27938c2ecf20Sopenharmony_ci int summary_set, idx; 27948c2ecf20Sopenharmony_ci struct page *ind_page, *summary_page; 27958c2ecf20Sopenharmony_ci void *map; 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci ind_page = get_map_page(kvm, adapter_int->ind_addr); 27988c2ecf20Sopenharmony_ci if (!ind_page) 27998c2ecf20Sopenharmony_ci return -1; 28008c2ecf20Sopenharmony_ci summary_page = get_map_page(kvm, adapter_int->summary_addr); 28018c2ecf20Sopenharmony_ci if (!summary_page) { 28028c2ecf20Sopenharmony_ci put_page(ind_page); 28038c2ecf20Sopenharmony_ci return -1; 28048c2ecf20Sopenharmony_ci } 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci idx = srcu_read_lock(&kvm->srcu); 28078c2ecf20Sopenharmony_ci map = page_address(ind_page); 28088c2ecf20Sopenharmony_ci bit = get_ind_bit(adapter_int->ind_addr, 28098c2ecf20Sopenharmony_ci adapter_int->ind_offset, adapter->swap); 28108c2ecf20Sopenharmony_ci set_bit(bit, map); 28118c2ecf20Sopenharmony_ci mark_page_dirty(kvm, adapter_int->ind_addr >> PAGE_SHIFT); 28128c2ecf20Sopenharmony_ci set_page_dirty_lock(ind_page); 28138c2ecf20Sopenharmony_ci map = page_address(summary_page); 28148c2ecf20Sopenharmony_ci bit = get_ind_bit(adapter_int->summary_addr, 28158c2ecf20Sopenharmony_ci adapter_int->summary_offset, adapter->swap); 28168c2ecf20Sopenharmony_ci summary_set = test_and_set_bit(bit, map); 28178c2ecf20Sopenharmony_ci mark_page_dirty(kvm, adapter_int->summary_addr >> PAGE_SHIFT); 28188c2ecf20Sopenharmony_ci set_page_dirty_lock(summary_page); 28198c2ecf20Sopenharmony_ci srcu_read_unlock(&kvm->srcu, idx); 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ci put_page(ind_page); 28228c2ecf20Sopenharmony_ci put_page(summary_page); 28238c2ecf20Sopenharmony_ci return summary_set ? 0 : 1; 28248c2ecf20Sopenharmony_ci} 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci/* 28278c2ecf20Sopenharmony_ci * < 0 - not injected due to error 28288c2ecf20Sopenharmony_ci * = 0 - coalesced, summary indicator already active 28298c2ecf20Sopenharmony_ci * > 0 - injected interrupt 28308c2ecf20Sopenharmony_ci */ 28318c2ecf20Sopenharmony_cistatic int set_adapter_int(struct kvm_kernel_irq_routing_entry *e, 28328c2ecf20Sopenharmony_ci struct kvm *kvm, int irq_source_id, int level, 28338c2ecf20Sopenharmony_ci bool line_status) 28348c2ecf20Sopenharmony_ci{ 28358c2ecf20Sopenharmony_ci int ret; 28368c2ecf20Sopenharmony_ci struct s390_io_adapter *adapter; 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci /* We're only interested in the 0->1 transition. */ 28398c2ecf20Sopenharmony_ci if (!level) 28408c2ecf20Sopenharmony_ci return 0; 28418c2ecf20Sopenharmony_ci adapter = get_io_adapter(kvm, e->adapter.adapter_id); 28428c2ecf20Sopenharmony_ci if (!adapter) 28438c2ecf20Sopenharmony_ci return -1; 28448c2ecf20Sopenharmony_ci ret = adapter_indicators_set(kvm, adapter, &e->adapter); 28458c2ecf20Sopenharmony_ci if ((ret > 0) && !adapter->masked) { 28468c2ecf20Sopenharmony_ci ret = kvm_s390_inject_airq(kvm, adapter); 28478c2ecf20Sopenharmony_ci if (ret == 0) 28488c2ecf20Sopenharmony_ci ret = 1; 28498c2ecf20Sopenharmony_ci } 28508c2ecf20Sopenharmony_ci return ret; 28518c2ecf20Sopenharmony_ci} 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci/* 28548c2ecf20Sopenharmony_ci * Inject the machine check to the guest. 28558c2ecf20Sopenharmony_ci */ 28568c2ecf20Sopenharmony_civoid kvm_s390_reinject_machine_check(struct kvm_vcpu *vcpu, 28578c2ecf20Sopenharmony_ci struct mcck_volatile_info *mcck_info) 28588c2ecf20Sopenharmony_ci{ 28598c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info inti; 28608c2ecf20Sopenharmony_ci struct kvm_s390_irq irq; 28618c2ecf20Sopenharmony_ci struct kvm_s390_mchk_info *mchk; 28628c2ecf20Sopenharmony_ci union mci mci; 28638c2ecf20Sopenharmony_ci __u64 cr14 = 0; /* upper bits are not used */ 28648c2ecf20Sopenharmony_ci int rc; 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci mci.val = mcck_info->mcic; 28678c2ecf20Sopenharmony_ci if (mci.sr) 28688c2ecf20Sopenharmony_ci cr14 |= CR14_RECOVERY_SUBMASK; 28698c2ecf20Sopenharmony_ci if (mci.dg) 28708c2ecf20Sopenharmony_ci cr14 |= CR14_DEGRADATION_SUBMASK; 28718c2ecf20Sopenharmony_ci if (mci.w) 28728c2ecf20Sopenharmony_ci cr14 |= CR14_WARNING_SUBMASK; 28738c2ecf20Sopenharmony_ci 28748c2ecf20Sopenharmony_ci mchk = mci.ck ? &inti.mchk : &irq.u.mchk; 28758c2ecf20Sopenharmony_ci mchk->cr14 = cr14; 28768c2ecf20Sopenharmony_ci mchk->mcic = mcck_info->mcic; 28778c2ecf20Sopenharmony_ci mchk->ext_damage_code = mcck_info->ext_damage_code; 28788c2ecf20Sopenharmony_ci mchk->failing_storage_address = mcck_info->failing_storage_address; 28798c2ecf20Sopenharmony_ci if (mci.ck) { 28808c2ecf20Sopenharmony_ci /* Inject the floating machine check */ 28818c2ecf20Sopenharmony_ci inti.type = KVM_S390_MCHK; 28828c2ecf20Sopenharmony_ci rc = __inject_vm(vcpu->kvm, &inti); 28838c2ecf20Sopenharmony_ci } else { 28848c2ecf20Sopenharmony_ci /* Inject the machine check to specified vcpu */ 28858c2ecf20Sopenharmony_ci irq.type = KVM_S390_MCHK; 28868c2ecf20Sopenharmony_ci rc = kvm_s390_inject_vcpu(vcpu, &irq); 28878c2ecf20Sopenharmony_ci } 28888c2ecf20Sopenharmony_ci WARN_ON_ONCE(rc); 28898c2ecf20Sopenharmony_ci} 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_ciint kvm_set_routing_entry(struct kvm *kvm, 28928c2ecf20Sopenharmony_ci struct kvm_kernel_irq_routing_entry *e, 28938c2ecf20Sopenharmony_ci const struct kvm_irq_routing_entry *ue) 28948c2ecf20Sopenharmony_ci{ 28958c2ecf20Sopenharmony_ci u64 uaddr; 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci switch (ue->type) { 28988c2ecf20Sopenharmony_ci /* we store the userspace addresses instead of the guest addresses */ 28998c2ecf20Sopenharmony_ci case KVM_IRQ_ROUTING_S390_ADAPTER: 29008c2ecf20Sopenharmony_ci e->set = set_adapter_int; 29018c2ecf20Sopenharmony_ci uaddr = gmap_translate(kvm->arch.gmap, ue->u.adapter.summary_addr); 29028c2ecf20Sopenharmony_ci if (uaddr == -EFAULT) 29038c2ecf20Sopenharmony_ci return -EFAULT; 29048c2ecf20Sopenharmony_ci e->adapter.summary_addr = uaddr; 29058c2ecf20Sopenharmony_ci uaddr = gmap_translate(kvm->arch.gmap, ue->u.adapter.ind_addr); 29068c2ecf20Sopenharmony_ci if (uaddr == -EFAULT) 29078c2ecf20Sopenharmony_ci return -EFAULT; 29088c2ecf20Sopenharmony_ci e->adapter.ind_addr = uaddr; 29098c2ecf20Sopenharmony_ci e->adapter.summary_offset = ue->u.adapter.summary_offset; 29108c2ecf20Sopenharmony_ci e->adapter.ind_offset = ue->u.adapter.ind_offset; 29118c2ecf20Sopenharmony_ci e->adapter.adapter_id = ue->u.adapter.adapter_id; 29128c2ecf20Sopenharmony_ci return 0; 29138c2ecf20Sopenharmony_ci default: 29148c2ecf20Sopenharmony_ci return -EINVAL; 29158c2ecf20Sopenharmony_ci } 29168c2ecf20Sopenharmony_ci} 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ciint kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, 29198c2ecf20Sopenharmony_ci int irq_source_id, int level, bool line_status) 29208c2ecf20Sopenharmony_ci{ 29218c2ecf20Sopenharmony_ci return -EINVAL; 29228c2ecf20Sopenharmony_ci} 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_ciint kvm_s390_set_irq_state(struct kvm_vcpu *vcpu, void __user *irqstate, int len) 29258c2ecf20Sopenharmony_ci{ 29268c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 29278c2ecf20Sopenharmony_ci struct kvm_s390_irq *buf; 29288c2ecf20Sopenharmony_ci int r = 0; 29298c2ecf20Sopenharmony_ci int n; 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci buf = vmalloc(len); 29328c2ecf20Sopenharmony_ci if (!buf) 29338c2ecf20Sopenharmony_ci return -ENOMEM; 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_ci if (copy_from_user((void *) buf, irqstate, len)) { 29368c2ecf20Sopenharmony_ci r = -EFAULT; 29378c2ecf20Sopenharmony_ci goto out_free; 29388c2ecf20Sopenharmony_ci } 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci /* 29418c2ecf20Sopenharmony_ci * Don't allow setting the interrupt state 29428c2ecf20Sopenharmony_ci * when there are already interrupts pending 29438c2ecf20Sopenharmony_ci */ 29448c2ecf20Sopenharmony_ci spin_lock(&li->lock); 29458c2ecf20Sopenharmony_ci if (li->pending_irqs) { 29468c2ecf20Sopenharmony_ci r = -EBUSY; 29478c2ecf20Sopenharmony_ci goto out_unlock; 29488c2ecf20Sopenharmony_ci } 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_ci for (n = 0; n < len / sizeof(*buf); n++) { 29518c2ecf20Sopenharmony_ci r = do_inject_vcpu(vcpu, &buf[n]); 29528c2ecf20Sopenharmony_ci if (r) 29538c2ecf20Sopenharmony_ci break; 29548c2ecf20Sopenharmony_ci } 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ciout_unlock: 29578c2ecf20Sopenharmony_ci spin_unlock(&li->lock); 29588c2ecf20Sopenharmony_ciout_free: 29598c2ecf20Sopenharmony_ci vfree(buf); 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci return r; 29628c2ecf20Sopenharmony_ci} 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_cistatic void store_local_irq(struct kvm_s390_local_interrupt *li, 29658c2ecf20Sopenharmony_ci struct kvm_s390_irq *irq, 29668c2ecf20Sopenharmony_ci unsigned long irq_type) 29678c2ecf20Sopenharmony_ci{ 29688c2ecf20Sopenharmony_ci switch (irq_type) { 29698c2ecf20Sopenharmony_ci case IRQ_PEND_MCHK_EX: 29708c2ecf20Sopenharmony_ci case IRQ_PEND_MCHK_REP: 29718c2ecf20Sopenharmony_ci irq->type = KVM_S390_MCHK; 29728c2ecf20Sopenharmony_ci irq->u.mchk = li->irq.mchk; 29738c2ecf20Sopenharmony_ci break; 29748c2ecf20Sopenharmony_ci case IRQ_PEND_PROG: 29758c2ecf20Sopenharmony_ci irq->type = KVM_S390_PROGRAM_INT; 29768c2ecf20Sopenharmony_ci irq->u.pgm = li->irq.pgm; 29778c2ecf20Sopenharmony_ci break; 29788c2ecf20Sopenharmony_ci case IRQ_PEND_PFAULT_INIT: 29798c2ecf20Sopenharmony_ci irq->type = KVM_S390_INT_PFAULT_INIT; 29808c2ecf20Sopenharmony_ci irq->u.ext = li->irq.ext; 29818c2ecf20Sopenharmony_ci break; 29828c2ecf20Sopenharmony_ci case IRQ_PEND_EXT_EXTERNAL: 29838c2ecf20Sopenharmony_ci irq->type = KVM_S390_INT_EXTERNAL_CALL; 29848c2ecf20Sopenharmony_ci irq->u.extcall = li->irq.extcall; 29858c2ecf20Sopenharmony_ci break; 29868c2ecf20Sopenharmony_ci case IRQ_PEND_EXT_CLOCK_COMP: 29878c2ecf20Sopenharmony_ci irq->type = KVM_S390_INT_CLOCK_COMP; 29888c2ecf20Sopenharmony_ci break; 29898c2ecf20Sopenharmony_ci case IRQ_PEND_EXT_CPU_TIMER: 29908c2ecf20Sopenharmony_ci irq->type = KVM_S390_INT_CPU_TIMER; 29918c2ecf20Sopenharmony_ci break; 29928c2ecf20Sopenharmony_ci case IRQ_PEND_SIGP_STOP: 29938c2ecf20Sopenharmony_ci irq->type = KVM_S390_SIGP_STOP; 29948c2ecf20Sopenharmony_ci irq->u.stop = li->irq.stop; 29958c2ecf20Sopenharmony_ci break; 29968c2ecf20Sopenharmony_ci case IRQ_PEND_RESTART: 29978c2ecf20Sopenharmony_ci irq->type = KVM_S390_RESTART; 29988c2ecf20Sopenharmony_ci break; 29998c2ecf20Sopenharmony_ci case IRQ_PEND_SET_PREFIX: 30008c2ecf20Sopenharmony_ci irq->type = KVM_S390_SIGP_SET_PREFIX; 30018c2ecf20Sopenharmony_ci irq->u.prefix = li->irq.prefix; 30028c2ecf20Sopenharmony_ci break; 30038c2ecf20Sopenharmony_ci } 30048c2ecf20Sopenharmony_ci} 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ciint kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, __u8 __user *buf, int len) 30078c2ecf20Sopenharmony_ci{ 30088c2ecf20Sopenharmony_ci int scn; 30098c2ecf20Sopenharmony_ci DECLARE_BITMAP(sigp_emerg_pending, KVM_MAX_VCPUS); 30108c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 30118c2ecf20Sopenharmony_ci unsigned long pending_irqs; 30128c2ecf20Sopenharmony_ci struct kvm_s390_irq irq; 30138c2ecf20Sopenharmony_ci unsigned long irq_type; 30148c2ecf20Sopenharmony_ci int cpuaddr; 30158c2ecf20Sopenharmony_ci int n = 0; 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci spin_lock(&li->lock); 30188c2ecf20Sopenharmony_ci pending_irqs = li->pending_irqs; 30198c2ecf20Sopenharmony_ci memcpy(&sigp_emerg_pending, &li->sigp_emerg_pending, 30208c2ecf20Sopenharmony_ci sizeof(sigp_emerg_pending)); 30218c2ecf20Sopenharmony_ci spin_unlock(&li->lock); 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ci for_each_set_bit(irq_type, &pending_irqs, IRQ_PEND_COUNT) { 30248c2ecf20Sopenharmony_ci memset(&irq, 0, sizeof(irq)); 30258c2ecf20Sopenharmony_ci if (irq_type == IRQ_PEND_EXT_EMERGENCY) 30268c2ecf20Sopenharmony_ci continue; 30278c2ecf20Sopenharmony_ci if (n + sizeof(irq) > len) 30288c2ecf20Sopenharmony_ci return -ENOBUFS; 30298c2ecf20Sopenharmony_ci store_local_irq(&vcpu->arch.local_int, &irq, irq_type); 30308c2ecf20Sopenharmony_ci if (copy_to_user(&buf[n], &irq, sizeof(irq))) 30318c2ecf20Sopenharmony_ci return -EFAULT; 30328c2ecf20Sopenharmony_ci n += sizeof(irq); 30338c2ecf20Sopenharmony_ci } 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_ci if (test_bit(IRQ_PEND_EXT_EMERGENCY, &pending_irqs)) { 30368c2ecf20Sopenharmony_ci for_each_set_bit(cpuaddr, sigp_emerg_pending, KVM_MAX_VCPUS) { 30378c2ecf20Sopenharmony_ci memset(&irq, 0, sizeof(irq)); 30388c2ecf20Sopenharmony_ci if (n + sizeof(irq) > len) 30398c2ecf20Sopenharmony_ci return -ENOBUFS; 30408c2ecf20Sopenharmony_ci irq.type = KVM_S390_INT_EMERGENCY; 30418c2ecf20Sopenharmony_ci irq.u.emerg.code = cpuaddr; 30428c2ecf20Sopenharmony_ci if (copy_to_user(&buf[n], &irq, sizeof(irq))) 30438c2ecf20Sopenharmony_ci return -EFAULT; 30448c2ecf20Sopenharmony_ci n += sizeof(irq); 30458c2ecf20Sopenharmony_ci } 30468c2ecf20Sopenharmony_ci } 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci if (sca_ext_call_pending(vcpu, &scn)) { 30498c2ecf20Sopenharmony_ci if (n + sizeof(irq) > len) 30508c2ecf20Sopenharmony_ci return -ENOBUFS; 30518c2ecf20Sopenharmony_ci memset(&irq, 0, sizeof(irq)); 30528c2ecf20Sopenharmony_ci irq.type = KVM_S390_INT_EXTERNAL_CALL; 30538c2ecf20Sopenharmony_ci irq.u.extcall.code = scn; 30548c2ecf20Sopenharmony_ci if (copy_to_user(&buf[n], &irq, sizeof(irq))) 30558c2ecf20Sopenharmony_ci return -EFAULT; 30568c2ecf20Sopenharmony_ci n += sizeof(irq); 30578c2ecf20Sopenharmony_ci } 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_ci return n; 30608c2ecf20Sopenharmony_ci} 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_cistatic void __airqs_kick_single_vcpu(struct kvm *kvm, u8 deliverable_mask) 30638c2ecf20Sopenharmony_ci{ 30648c2ecf20Sopenharmony_ci int vcpu_idx, online_vcpus = atomic_read(&kvm->online_vcpus); 30658c2ecf20Sopenharmony_ci struct kvm_s390_gisa_interrupt *gi = &kvm->arch.gisa_int; 30668c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 30678c2ecf20Sopenharmony_ci u8 vcpu_isc_mask; 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci for_each_set_bit(vcpu_idx, kvm->arch.idle_mask, online_vcpus) { 30708c2ecf20Sopenharmony_ci vcpu = kvm_get_vcpu(kvm, vcpu_idx); 30718c2ecf20Sopenharmony_ci if (psw_ioint_disabled(vcpu)) 30728c2ecf20Sopenharmony_ci continue; 30738c2ecf20Sopenharmony_ci vcpu_isc_mask = (u8)(vcpu->arch.sie_block->gcr[6] >> 24); 30748c2ecf20Sopenharmony_ci if (deliverable_mask & vcpu_isc_mask) { 30758c2ecf20Sopenharmony_ci /* lately kicked but not yet running */ 30768c2ecf20Sopenharmony_ci if (test_and_set_bit(vcpu_idx, gi->kicked_mask)) 30778c2ecf20Sopenharmony_ci return; 30788c2ecf20Sopenharmony_ci kvm_s390_vcpu_wakeup(vcpu); 30798c2ecf20Sopenharmony_ci return; 30808c2ecf20Sopenharmony_ci } 30818c2ecf20Sopenharmony_ci } 30828c2ecf20Sopenharmony_ci} 30838c2ecf20Sopenharmony_ci 30848c2ecf20Sopenharmony_cistatic enum hrtimer_restart gisa_vcpu_kicker(struct hrtimer *timer) 30858c2ecf20Sopenharmony_ci{ 30868c2ecf20Sopenharmony_ci struct kvm_s390_gisa_interrupt *gi = 30878c2ecf20Sopenharmony_ci container_of(timer, struct kvm_s390_gisa_interrupt, timer); 30888c2ecf20Sopenharmony_ci struct kvm *kvm = 30898c2ecf20Sopenharmony_ci container_of(gi->origin, struct sie_page2, gisa)->kvm; 30908c2ecf20Sopenharmony_ci u8 pending_mask; 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ci pending_mask = gisa_get_ipm_or_restore_iam(gi); 30938c2ecf20Sopenharmony_ci if (pending_mask) { 30948c2ecf20Sopenharmony_ci __airqs_kick_single_vcpu(kvm, pending_mask); 30958c2ecf20Sopenharmony_ci hrtimer_forward_now(timer, ns_to_ktime(gi->expires)); 30968c2ecf20Sopenharmony_ci return HRTIMER_RESTART; 30978c2ecf20Sopenharmony_ci } 30988c2ecf20Sopenharmony_ci 30998c2ecf20Sopenharmony_ci return HRTIMER_NORESTART; 31008c2ecf20Sopenharmony_ci} 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_ci#define NULL_GISA_ADDR 0x00000000UL 31038c2ecf20Sopenharmony_ci#define NONE_GISA_ADDR 0x00000001UL 31048c2ecf20Sopenharmony_ci#define GISA_ADDR_MASK 0xfffff000UL 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_cistatic void process_gib_alert_list(void) 31078c2ecf20Sopenharmony_ci{ 31088c2ecf20Sopenharmony_ci struct kvm_s390_gisa_interrupt *gi; 31098c2ecf20Sopenharmony_ci struct kvm_s390_gisa *gisa; 31108c2ecf20Sopenharmony_ci struct kvm *kvm; 31118c2ecf20Sopenharmony_ci u32 final, origin = 0UL; 31128c2ecf20Sopenharmony_ci 31138c2ecf20Sopenharmony_ci do { 31148c2ecf20Sopenharmony_ci /* 31158c2ecf20Sopenharmony_ci * If the NONE_GISA_ADDR is still stored in the alert list 31168c2ecf20Sopenharmony_ci * origin, we will leave the outer loop. No further GISA has 31178c2ecf20Sopenharmony_ci * been added to the alert list by millicode while processing 31188c2ecf20Sopenharmony_ci * the current alert list. 31198c2ecf20Sopenharmony_ci */ 31208c2ecf20Sopenharmony_ci final = (origin & NONE_GISA_ADDR); 31218c2ecf20Sopenharmony_ci /* 31228c2ecf20Sopenharmony_ci * Cut off the alert list and store the NONE_GISA_ADDR in the 31238c2ecf20Sopenharmony_ci * alert list origin to avoid further GAL interruptions. 31248c2ecf20Sopenharmony_ci * A new alert list can be build up by millicode in parallel 31258c2ecf20Sopenharmony_ci * for guests not in the yet cut-off alert list. When in the 31268c2ecf20Sopenharmony_ci * final loop, store the NULL_GISA_ADDR instead. This will re- 31278c2ecf20Sopenharmony_ci * enable GAL interruptions on the host again. 31288c2ecf20Sopenharmony_ci */ 31298c2ecf20Sopenharmony_ci origin = xchg(&gib->alert_list_origin, 31308c2ecf20Sopenharmony_ci (!final) ? NONE_GISA_ADDR : NULL_GISA_ADDR); 31318c2ecf20Sopenharmony_ci /* 31328c2ecf20Sopenharmony_ci * Loop through the just cut-off alert list and start the 31338c2ecf20Sopenharmony_ci * gisa timers to kick idle vcpus to consume the pending 31348c2ecf20Sopenharmony_ci * interruptions asap. 31358c2ecf20Sopenharmony_ci */ 31368c2ecf20Sopenharmony_ci while (origin & GISA_ADDR_MASK) { 31378c2ecf20Sopenharmony_ci gisa = (struct kvm_s390_gisa *)(u64)origin; 31388c2ecf20Sopenharmony_ci origin = gisa->next_alert; 31398c2ecf20Sopenharmony_ci gisa->next_alert = (u32)(u64)gisa; 31408c2ecf20Sopenharmony_ci kvm = container_of(gisa, struct sie_page2, gisa)->kvm; 31418c2ecf20Sopenharmony_ci gi = &kvm->arch.gisa_int; 31428c2ecf20Sopenharmony_ci if (hrtimer_active(&gi->timer)) 31438c2ecf20Sopenharmony_ci hrtimer_cancel(&gi->timer); 31448c2ecf20Sopenharmony_ci hrtimer_start(&gi->timer, 0, HRTIMER_MODE_REL); 31458c2ecf20Sopenharmony_ci } 31468c2ecf20Sopenharmony_ci } while (!final); 31478c2ecf20Sopenharmony_ci 31488c2ecf20Sopenharmony_ci} 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_civoid kvm_s390_gisa_clear(struct kvm *kvm) 31518c2ecf20Sopenharmony_ci{ 31528c2ecf20Sopenharmony_ci struct kvm_s390_gisa_interrupt *gi = &kvm->arch.gisa_int; 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci if (!gi->origin) 31558c2ecf20Sopenharmony_ci return; 31568c2ecf20Sopenharmony_ci gisa_clear_ipm(gi->origin); 31578c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "gisa 0x%pK cleared", gi->origin); 31588c2ecf20Sopenharmony_ci} 31598c2ecf20Sopenharmony_ci 31608c2ecf20Sopenharmony_civoid kvm_s390_gisa_init(struct kvm *kvm) 31618c2ecf20Sopenharmony_ci{ 31628c2ecf20Sopenharmony_ci struct kvm_s390_gisa_interrupt *gi = &kvm->arch.gisa_int; 31638c2ecf20Sopenharmony_ci 31648c2ecf20Sopenharmony_ci if (!css_general_characteristics.aiv) 31658c2ecf20Sopenharmony_ci return; 31668c2ecf20Sopenharmony_ci gi->origin = &kvm->arch.sie_page2->gisa; 31678c2ecf20Sopenharmony_ci gi->alert.mask = 0; 31688c2ecf20Sopenharmony_ci spin_lock_init(&gi->alert.ref_lock); 31698c2ecf20Sopenharmony_ci gi->expires = 50 * 1000; /* 50 usec */ 31708c2ecf20Sopenharmony_ci hrtimer_init(&gi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 31718c2ecf20Sopenharmony_ci gi->timer.function = gisa_vcpu_kicker; 31728c2ecf20Sopenharmony_ci memset(gi->origin, 0, sizeof(struct kvm_s390_gisa)); 31738c2ecf20Sopenharmony_ci gi->origin->next_alert = (u32)(u64)gi->origin; 31748c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "gisa 0x%pK initialized", gi->origin); 31758c2ecf20Sopenharmony_ci} 31768c2ecf20Sopenharmony_ci 31778c2ecf20Sopenharmony_civoid kvm_s390_gisa_destroy(struct kvm *kvm) 31788c2ecf20Sopenharmony_ci{ 31798c2ecf20Sopenharmony_ci struct kvm_s390_gisa_interrupt *gi = &kvm->arch.gisa_int; 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci if (!gi->origin) 31828c2ecf20Sopenharmony_ci return; 31838c2ecf20Sopenharmony_ci if (gi->alert.mask) 31848c2ecf20Sopenharmony_ci KVM_EVENT(3, "vm 0x%pK has unexpected iam 0x%02x", 31858c2ecf20Sopenharmony_ci kvm, gi->alert.mask); 31868c2ecf20Sopenharmony_ci while (gisa_in_alert_list(gi->origin)) 31878c2ecf20Sopenharmony_ci cpu_relax(); 31888c2ecf20Sopenharmony_ci hrtimer_cancel(&gi->timer); 31898c2ecf20Sopenharmony_ci gi->origin = NULL; 31908c2ecf20Sopenharmony_ci} 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_ci/** 31938c2ecf20Sopenharmony_ci * kvm_s390_gisc_register - register a guest ISC 31948c2ecf20Sopenharmony_ci * 31958c2ecf20Sopenharmony_ci * @kvm: the kernel vm to work with 31968c2ecf20Sopenharmony_ci * @gisc: the guest interruption sub class to register 31978c2ecf20Sopenharmony_ci * 31988c2ecf20Sopenharmony_ci * The function extends the vm specific alert mask to use. 31998c2ecf20Sopenharmony_ci * The effective IAM mask in the GISA is updated as well 32008c2ecf20Sopenharmony_ci * in case the GISA is not part of the GIB alert list. 32018c2ecf20Sopenharmony_ci * It will be updated latest when the IAM gets restored 32028c2ecf20Sopenharmony_ci * by gisa_get_ipm_or_restore_iam(). 32038c2ecf20Sopenharmony_ci * 32048c2ecf20Sopenharmony_ci * Returns: the nonspecific ISC (NISC) the gib alert mechanism 32058c2ecf20Sopenharmony_ci * has registered with the channel subsystem. 32068c2ecf20Sopenharmony_ci * -ENODEV in case the vm uses no GISA 32078c2ecf20Sopenharmony_ci * -ERANGE in case the guest ISC is invalid 32088c2ecf20Sopenharmony_ci */ 32098c2ecf20Sopenharmony_ciint kvm_s390_gisc_register(struct kvm *kvm, u32 gisc) 32108c2ecf20Sopenharmony_ci{ 32118c2ecf20Sopenharmony_ci struct kvm_s390_gisa_interrupt *gi = &kvm->arch.gisa_int; 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci if (!gi->origin) 32148c2ecf20Sopenharmony_ci return -ENODEV; 32158c2ecf20Sopenharmony_ci if (gisc > MAX_ISC) 32168c2ecf20Sopenharmony_ci return -ERANGE; 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci spin_lock(&gi->alert.ref_lock); 32198c2ecf20Sopenharmony_ci gi->alert.ref_count[gisc]++; 32208c2ecf20Sopenharmony_ci if (gi->alert.ref_count[gisc] == 1) { 32218c2ecf20Sopenharmony_ci gi->alert.mask |= 0x80 >> gisc; 32228c2ecf20Sopenharmony_ci gisa_set_iam(gi->origin, gi->alert.mask); 32238c2ecf20Sopenharmony_ci } 32248c2ecf20Sopenharmony_ci spin_unlock(&gi->alert.ref_lock); 32258c2ecf20Sopenharmony_ci 32268c2ecf20Sopenharmony_ci return gib->nisc; 32278c2ecf20Sopenharmony_ci} 32288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvm_s390_gisc_register); 32298c2ecf20Sopenharmony_ci 32308c2ecf20Sopenharmony_ci/** 32318c2ecf20Sopenharmony_ci * kvm_s390_gisc_unregister - unregister a guest ISC 32328c2ecf20Sopenharmony_ci * 32338c2ecf20Sopenharmony_ci * @kvm: the kernel vm to work with 32348c2ecf20Sopenharmony_ci * @gisc: the guest interruption sub class to register 32358c2ecf20Sopenharmony_ci * 32368c2ecf20Sopenharmony_ci * The function reduces the vm specific alert mask to use. 32378c2ecf20Sopenharmony_ci * The effective IAM mask in the GISA is updated as well 32388c2ecf20Sopenharmony_ci * in case the GISA is not part of the GIB alert list. 32398c2ecf20Sopenharmony_ci * It will be updated latest when the IAM gets restored 32408c2ecf20Sopenharmony_ci * by gisa_get_ipm_or_restore_iam(). 32418c2ecf20Sopenharmony_ci * 32428c2ecf20Sopenharmony_ci * Returns: the nonspecific ISC (NISC) the gib alert mechanism 32438c2ecf20Sopenharmony_ci * has registered with the channel subsystem. 32448c2ecf20Sopenharmony_ci * -ENODEV in case the vm uses no GISA 32458c2ecf20Sopenharmony_ci * -ERANGE in case the guest ISC is invalid 32468c2ecf20Sopenharmony_ci * -EINVAL in case the guest ISC is not registered 32478c2ecf20Sopenharmony_ci */ 32488c2ecf20Sopenharmony_ciint kvm_s390_gisc_unregister(struct kvm *kvm, u32 gisc) 32498c2ecf20Sopenharmony_ci{ 32508c2ecf20Sopenharmony_ci struct kvm_s390_gisa_interrupt *gi = &kvm->arch.gisa_int; 32518c2ecf20Sopenharmony_ci int rc = 0; 32528c2ecf20Sopenharmony_ci 32538c2ecf20Sopenharmony_ci if (!gi->origin) 32548c2ecf20Sopenharmony_ci return -ENODEV; 32558c2ecf20Sopenharmony_ci if (gisc > MAX_ISC) 32568c2ecf20Sopenharmony_ci return -ERANGE; 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_ci spin_lock(&gi->alert.ref_lock); 32598c2ecf20Sopenharmony_ci if (gi->alert.ref_count[gisc] == 0) { 32608c2ecf20Sopenharmony_ci rc = -EINVAL; 32618c2ecf20Sopenharmony_ci goto out; 32628c2ecf20Sopenharmony_ci } 32638c2ecf20Sopenharmony_ci gi->alert.ref_count[gisc]--; 32648c2ecf20Sopenharmony_ci if (gi->alert.ref_count[gisc] == 0) { 32658c2ecf20Sopenharmony_ci gi->alert.mask &= ~(0x80 >> gisc); 32668c2ecf20Sopenharmony_ci gisa_set_iam(gi->origin, gi->alert.mask); 32678c2ecf20Sopenharmony_ci } 32688c2ecf20Sopenharmony_ciout: 32698c2ecf20Sopenharmony_ci spin_unlock(&gi->alert.ref_lock); 32708c2ecf20Sopenharmony_ci 32718c2ecf20Sopenharmony_ci return rc; 32728c2ecf20Sopenharmony_ci} 32738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvm_s390_gisc_unregister); 32748c2ecf20Sopenharmony_ci 32758c2ecf20Sopenharmony_cistatic void gib_alert_irq_handler(struct airq_struct *airq, bool floating) 32768c2ecf20Sopenharmony_ci{ 32778c2ecf20Sopenharmony_ci inc_irq_stat(IRQIO_GAL); 32788c2ecf20Sopenharmony_ci process_gib_alert_list(); 32798c2ecf20Sopenharmony_ci} 32808c2ecf20Sopenharmony_ci 32818c2ecf20Sopenharmony_cistatic struct airq_struct gib_alert_irq = { 32828c2ecf20Sopenharmony_ci .handler = gib_alert_irq_handler, 32838c2ecf20Sopenharmony_ci .lsi_ptr = &gib_alert_irq.lsi_mask, 32848c2ecf20Sopenharmony_ci}; 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_civoid kvm_s390_gib_destroy(void) 32878c2ecf20Sopenharmony_ci{ 32888c2ecf20Sopenharmony_ci if (!gib) 32898c2ecf20Sopenharmony_ci return; 32908c2ecf20Sopenharmony_ci chsc_sgib(0); 32918c2ecf20Sopenharmony_ci unregister_adapter_interrupt(&gib_alert_irq); 32928c2ecf20Sopenharmony_ci free_page((unsigned long)gib); 32938c2ecf20Sopenharmony_ci gib = NULL; 32948c2ecf20Sopenharmony_ci} 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_ciint kvm_s390_gib_init(u8 nisc) 32978c2ecf20Sopenharmony_ci{ 32988c2ecf20Sopenharmony_ci int rc = 0; 32998c2ecf20Sopenharmony_ci 33008c2ecf20Sopenharmony_ci if (!css_general_characteristics.aiv) { 33018c2ecf20Sopenharmony_ci KVM_EVENT(3, "%s", "gib not initialized, no AIV facility"); 33028c2ecf20Sopenharmony_ci goto out; 33038c2ecf20Sopenharmony_ci } 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_ci gib = (struct kvm_s390_gib *)get_zeroed_page(GFP_KERNEL | GFP_DMA); 33068c2ecf20Sopenharmony_ci if (!gib) { 33078c2ecf20Sopenharmony_ci rc = -ENOMEM; 33088c2ecf20Sopenharmony_ci goto out; 33098c2ecf20Sopenharmony_ci } 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci gib_alert_irq.isc = nisc; 33128c2ecf20Sopenharmony_ci if (register_adapter_interrupt(&gib_alert_irq)) { 33138c2ecf20Sopenharmony_ci pr_err("Registering the GIB alert interruption handler failed\n"); 33148c2ecf20Sopenharmony_ci rc = -EIO; 33158c2ecf20Sopenharmony_ci goto out_free_gib; 33168c2ecf20Sopenharmony_ci } 33178c2ecf20Sopenharmony_ci 33188c2ecf20Sopenharmony_ci gib->nisc = nisc; 33198c2ecf20Sopenharmony_ci if (chsc_sgib((u32)(u64)gib)) { 33208c2ecf20Sopenharmony_ci pr_err("Associating the GIB with the AIV facility failed\n"); 33218c2ecf20Sopenharmony_ci free_page((unsigned long)gib); 33228c2ecf20Sopenharmony_ci gib = NULL; 33238c2ecf20Sopenharmony_ci rc = -EIO; 33248c2ecf20Sopenharmony_ci goto out_unreg_gal; 33258c2ecf20Sopenharmony_ci } 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_ci KVM_EVENT(3, "gib 0x%pK (nisc=%d) initialized", gib, gib->nisc); 33288c2ecf20Sopenharmony_ci goto out; 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_ciout_unreg_gal: 33318c2ecf20Sopenharmony_ci unregister_adapter_interrupt(&gib_alert_irq); 33328c2ecf20Sopenharmony_ciout_free_gib: 33338c2ecf20Sopenharmony_ci free_page((unsigned long)gib); 33348c2ecf20Sopenharmony_ci gib = NULL; 33358c2ecf20Sopenharmony_ciout: 33368c2ecf20Sopenharmony_ci return rc; 33378c2ecf20Sopenharmony_ci} 3338