Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0146a7b0 authored by Jens Freimann's avatar Jens Freimann Committed by Christian Borntraeger
Browse files

KVM: s390: refactor interrupt injection code



In preparation for the rework of the local interrupt injection code,
factor out injection routines from kvm_s390_inject_vcpu().

Signed-off-by: default avatarJens Freimann <jfrei@linux.vnet.ibm.com>
Reviewed-by: default avatarDavid Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
parent 9fcf93b5
Loading
Loading
Loading
Loading
+167 −54
Original line number Diff line number Diff line
@@ -719,6 +719,16 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
	return rc;
}

static int __inject_prog_irq(struct kvm_vcpu *vcpu,
			     struct kvm_s390_interrupt_info *inti)
{
	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;

	list_add(&inti->list, &li->list);
	atomic_set(&li->active, 1);
	return 0;
}

int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
{
	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
@@ -746,6 +756,7 @@ int kvm_s390_inject_prog_irq(struct kvm_vcpu *vcpu,
{
	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
	struct kvm_s390_interrupt_info *inti;
	int rc;

	inti = kzalloc(sizeof(*inti), GFP_KERNEL);
	if (!inti)
@@ -759,10 +770,133 @@ int kvm_s390_inject_prog_irq(struct kvm_vcpu *vcpu,
	inti->type = KVM_S390_PROGRAM_INT;
	memcpy(&inti->pgm, pgm_info, sizeof(inti->pgm));
	spin_lock(&li->lock);
	list_add(&inti->list, &li->list);
	atomic_set(&li->active, 1);
	rc = __inject_prog_irq(vcpu, inti);
	BUG_ON(waitqueue_active(li->wq));
	spin_unlock(&li->lock);
	return rc;
}

static int __inject_pfault_init(struct kvm_vcpu *vcpu,
				struct kvm_s390_interrupt *s390int,
				struct kvm_s390_interrupt_info *inti)
{
	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;

	inti->ext.ext_params2 = s390int->parm64;
	list_add_tail(&inti->list, &li->list);
	atomic_set(&li->active, 1);
	atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
	return 0;
}

static int __inject_extcall(struct kvm_vcpu *vcpu,
			    struct kvm_s390_interrupt *s390int,
			    struct kvm_s390_interrupt_info *inti)
{
	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;

	VCPU_EVENT(vcpu, 3, "inject: external call source-cpu:%u",
		   s390int->parm);
	if (s390int->parm & 0xffff0000)
		return -EINVAL;
	inti->extcall.code = s390int->parm;
	list_add_tail(&inti->list, &li->list);
	atomic_set(&li->active, 1);
	atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
	return 0;
}

static int __inject_set_prefix(struct kvm_vcpu *vcpu,
			       struct kvm_s390_interrupt *s390int,
			       struct kvm_s390_interrupt_info *inti)
{
	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;

	VCPU_EVENT(vcpu, 3, "inject: set prefix to %x (from user)",
		   s390int->parm);
	inti->prefix.address = s390int->parm;
	list_add_tail(&inti->list, &li->list);
	atomic_set(&li->active, 1);
	return 0;
}

static int __inject_sigp_stop(struct kvm_vcpu *vcpu,
			      struct kvm_s390_interrupt *s390int,
			      struct kvm_s390_interrupt_info *inti)
{
	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;

	list_add_tail(&inti->list, &li->list);
	atomic_set(&li->active, 1);
	li->action_bits |= ACTION_STOP_ON_STOP;
	return 0;
}

static int __inject_sigp_restart(struct kvm_vcpu *vcpu,
				 struct kvm_s390_interrupt *s390int,
				 struct kvm_s390_interrupt_info *inti)
{
	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;

	VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
	list_add_tail(&inti->list, &li->list);
	atomic_set(&li->active, 1);
	return 0;
}

static int __inject_sigp_emergency(struct kvm_vcpu *vcpu,
				   struct kvm_s390_interrupt *s390int,
				   struct kvm_s390_interrupt_info *inti)
{
	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;

	VCPU_EVENT(vcpu, 3, "inject: emergency %u\n", s390int->parm);
	if (s390int->parm & 0xffff0000)
		return -EINVAL;
	inti->emerg.code = s390int->parm;
	list_add_tail(&inti->list, &li->list);
	atomic_set(&li->active, 1);
	atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
	return 0;
}

static int __inject_mchk(struct kvm_vcpu *vcpu,
			 struct kvm_s390_interrupt *s390int,
			 struct kvm_s390_interrupt_info *inti)
{
	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;

	VCPU_EVENT(vcpu, 5, "inject: machine check parm64:%llx",
		   s390int->parm64);
	inti->mchk.mcic = s390int->parm64;
	list_add_tail(&inti->list, &li->list);
	atomic_set(&li->active, 1);
	return 0;
}

static int __inject_ckc(struct kvm_vcpu *vcpu,
			struct kvm_s390_interrupt *s390int,
			struct kvm_s390_interrupt_info *inti)
{
	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;

	VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
	list_add_tail(&inti->list, &li->list);
	atomic_set(&li->active, 1);
	atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
	return 0;
}

static int __inject_cpu_timer(struct kvm_vcpu *vcpu,
			      struct kvm_s390_interrupt *s390int,
			      struct kvm_s390_interrupt_info *inti)
{
	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;

	VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
	list_add_tail(&inti->list, &li->list);
	atomic_set(&li->active, 1);
	atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
	return 0;
}

@@ -933,89 +1067,68 @@ void kvm_s390_reinject_io_int(struct kvm *kvm,
int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
			 struct kvm_s390_interrupt *s390int)
{
	struct kvm_s390_local_interrupt *li;
	struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
	struct kvm_s390_interrupt_info *inti;
	int rc;

	inti = kzalloc(sizeof(*inti), GFP_KERNEL);
	if (!inti)
		return -ENOMEM;

	switch (s390int->type) {
	case KVM_S390_PROGRAM_INT:
		if (s390int->parm & 0xffff0000) {
			kfree(inti);
			return -EINVAL;
		}
	inti->type = s390int->type;
		inti->pgm.code = s390int->parm;

	trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, s390int->type,
				   s390int->parm, 0, 2);
	spin_lock(&li->lock);
	switch (inti->type) {
	case KVM_S390_PROGRAM_INT:
		VCPU_EVENT(vcpu, 3, "inject: program check %d (from user)",
			   s390int->parm);
		inti->pgm.code = s390int->parm;
		if (s390int->parm & 0xffff0000)
			rc = -EINVAL;
		else
			rc = __inject_prog_irq(vcpu, inti);
		break;
	case KVM_S390_SIGP_SET_PREFIX:
		inti->prefix.address = s390int->parm;
		inti->type = s390int->type;
		VCPU_EVENT(vcpu, 3, "inject: set prefix to %x (from user)",
			   s390int->parm);
		rc = __inject_set_prefix(vcpu, s390int, inti);
		break;
	case KVM_S390_SIGP_STOP:
		rc = __inject_sigp_stop(vcpu, s390int, inti);
		break;
	case KVM_S390_RESTART:
		rc = __inject_sigp_restart(vcpu, s390int, inti);
		break;
	case KVM_S390_INT_CLOCK_COMP:
		rc = __inject_ckc(vcpu, s390int, inti);
		break;
	case KVM_S390_INT_CPU_TIMER:
		VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
		inti->type = s390int->type;
		rc = __inject_cpu_timer(vcpu, s390int, inti);
		break;
	case KVM_S390_INT_EXTERNAL_CALL:
		if (s390int->parm & 0xffff0000) {
			kfree(inti);
			return -EINVAL;
		}
		VCPU_EVENT(vcpu, 3, "inject: external call source-cpu:%u",
			   s390int->parm);
		inti->type = s390int->type;
		inti->extcall.code = s390int->parm;
		rc = __inject_extcall(vcpu, s390int, inti);
		break;
	case KVM_S390_INT_EMERGENCY:
		if (s390int->parm & 0xffff0000) {
			kfree(inti);
			return -EINVAL;
		}
		VCPU_EVENT(vcpu, 3, "inject: emergency %u\n", s390int->parm);
		inti->type = s390int->type;
		inti->emerg.code = s390int->parm;
		rc = __inject_sigp_emergency(vcpu, s390int, inti);
		break;
	case KVM_S390_MCHK:
		VCPU_EVENT(vcpu, 5, "inject: machine check parm64:%llx",
			   s390int->parm64);
		inti->type = s390int->type;
		inti->mchk.mcic = s390int->parm64;
		rc = __inject_mchk(vcpu, s390int, inti);
		break;
	case KVM_S390_INT_PFAULT_INIT:
		inti->type = s390int->type;
		inti->ext.ext_params2 = s390int->parm64;
		rc = __inject_pfault_init(vcpu, s390int, inti);
		break;
	case KVM_S390_INT_VIRTIO:
	case KVM_S390_INT_SERVICE:
	case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
	default:
		kfree(inti);
		return -EINVAL;
		rc = -EINVAL;
	}
	trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, s390int->type, s390int->parm,
				   s390int->parm64, 2);

	li = &vcpu->arch.local_int;
	spin_lock(&li->lock);
	if (inti->type == KVM_S390_PROGRAM_INT)
		list_add(&inti->list, &li->list);
	else
		list_add_tail(&inti->list, &li->list);
	atomic_set(&li->active, 1);
	if (inti->type == KVM_S390_SIGP_STOP)
		li->action_bits |= ACTION_STOP_ON_STOP;
	atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
	spin_unlock(&li->lock);
	if (!rc)
		kvm_s390_vcpu_wakeup(vcpu);
	return 0;
	else
		kfree(inti);
	return rc;
}

void kvm_s390_clear_float_irqs(struct kvm *kvm)