Commit 2bd1337a authored by Andrew Donnellan's avatar Andrew Donnellan Committed by Janosch Frank
Browse files

KVM: s390: Use generic VIRT_XFER_TO_GUEST_WORK functions



Switch to using the generic infrastructure to check for and handle pending
work before transitioning into guest mode.

xfer_to_guest_mode_handle_work() does a few more things than the current
code does when deciding whether or not to exit the __vcpu_run() loop. The
exittime tests from kvm-unit-tests, in my tests, were within a few percent
compared to before this series, which is within noise tolerance.

Co-developed-by: default avatarHeiko Carstens <hca@linux.ibm.com>
Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
Signed-off-by: default avatarAndrew Donnellan <ajd@linux.ibm.com>
Acked-by: default avatarJanosch Frank <frankja@linux.ibm.com>
[frankja@linux.ibm.com: Removed semicolon]
Signed-off-by: default avatarJanosch Frank <frankja@linux.ibm.com>
parent d0139059
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ config KVM
	select HAVE_KVM_NO_POLL
	select KVM_VFIO
	select MMU_NOTIFIER
	select VIRT_XFER_TO_GUEST_WORK
	help
	  Support hosting paravirtualized guest machines using the SIE
	  virtualization capability on the mainframe. This should work
+18 −7
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt

#include <linux/compiler.h>
#include <linux/entry-virt.h>
#include <linux/export.h>
#include <linux/err.h>
#include <linux/fs.h>
@@ -4675,9 +4676,6 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu)
	vcpu->arch.sie_block->gg14 = vcpu->run->s.regs.gprs[14];
	vcpu->arch.sie_block->gg15 = vcpu->run->s.regs.gprs[15];

	if (need_resched())
		schedule();

	if (!kvm_is_ucontrol(vcpu->kvm)) {
		rc = kvm_s390_deliver_pending_interrupts(vcpu);
		if (rc || guestdbg_exit_pending(vcpu))
@@ -4982,12 +4980,12 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
	 */
	kvm_vcpu_srcu_read_lock(vcpu);

	do {
	while (true) {
		rc = vcpu_pre_run(vcpu);
		kvm_vcpu_srcu_read_unlock(vcpu);
		if (rc || guestdbg_exit_pending(vcpu))
			break;

		kvm_vcpu_srcu_read_unlock(vcpu);
		/*
		 * As PF_VCPU will be used in fault handler, between
		 * guest_timing_enter_irqoff and guest_timing_exit_irqoff
@@ -4999,7 +4997,17 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
			       sizeof(sie_page->pv_grregs));
		}

xfer_to_guest_mode_check:
		local_irq_disable();
		xfer_to_guest_mode_prepare();
		if (xfer_to_guest_mode_work_pending()) {
			local_irq_enable();
			rc = kvm_xfer_to_guest_mode_handle_work(vcpu);
			if (rc)
				break;
			goto xfer_to_guest_mode_check;
		}

		guest_timing_enter_irqoff();
		__disable_cpu_timer_accounting(vcpu);

@@ -5029,9 +5037,12 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
		kvm_vcpu_srcu_read_lock(vcpu);

		rc = vcpu_post_run(vcpu, exit_reason);
	} while (!signal_pending(current) && !guestdbg_exit_pending(vcpu) && !rc);

		if (rc || guestdbg_exit_pending(vcpu)) {
			kvm_vcpu_srcu_read_unlock(vcpu);
			break;
		}
	}

	return rc;
}

+13 −5
Original line number Diff line number Diff line
@@ -1180,12 +1180,23 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
	current->thread.gmap_int_code = 0;
	barrier();
	if (!kvm_s390_vcpu_sie_inhibited(vcpu)) {
xfer_to_guest_mode_check:
		local_irq_disable();
		xfer_to_guest_mode_prepare();
		if (xfer_to_guest_mode_work_pending()) {
			local_irq_enable();
			rc = kvm_xfer_to_guest_mode_handle_work(vcpu);
			if (rc)
				goto skip_sie;
			goto xfer_to_guest_mode_check;
		}
		guest_timing_enter_irqoff();
		rc = kvm_s390_enter_exit_sie(scb_s, vcpu->run->s.regs.gprs, vsie_page->gmap->asce);
		guest_timing_exit_irqoff();
		local_irq_enable();
	}

skip_sie:
	barrier();
	vcpu->arch.sie_block->prog0c &= ~PROG_IN_SIE;

@@ -1345,13 +1356,11 @@ static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
		 * but rewind the PSW to re-enter SIE once that's completed
		 * instead of passing a "no action" intercept to the guest.
		 */
		if (signal_pending(current) ||
		    kvm_s390_vcpu_has_irq(vcpu, 0) ||
		if (kvm_s390_vcpu_has_irq(vcpu, 0) ||
		    kvm_s390_vcpu_sie_inhibited(vcpu)) {
			kvm_s390_rewind_psw(vcpu, 4);
			break;
		}
		cond_resched();
	}

	if (rc == -EFAULT) {
@@ -1483,8 +1492,7 @@ int kvm_s390_handle_vsie(struct kvm_vcpu *vcpu)
	if (unlikely(scb_addr & 0x1ffUL))
		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);

	if (signal_pending(current) || kvm_s390_vcpu_has_irq(vcpu, 0) ||
	    kvm_s390_vcpu_sie_inhibited(vcpu)) {
	if (kvm_s390_vcpu_has_irq(vcpu, 0) || kvm_s390_vcpu_sie_inhibited(vcpu)) {
		kvm_s390_rewind_psw(vcpu, 4);
		return 0;
	}