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