Skip to content

Commit

Permalink
KVM: s390: refactor interrupt injection code
Browse files Browse the repository at this point in the history
In preparation for the rework of the local interrupt injection code,
factor out injection routines from kvm_s390_inject_vcpu().

Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
  • Loading branch information
Jens Freimann authored and Christian Borntraeger committed Nov 28, 2014
1 parent 9fcf93b commit 0146a7b
Showing 1 changed file with 167 additions and 54 deletions.
221 changes: 167 additions & 54 deletions arch/s390/kvm/interrupt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}

Expand Down Expand Up @@ -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) {
inti->type = s390int->type;

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:
if (s390int->parm & 0xffff0000) {
kfree(inti);
return -EINVAL;
}
inti->type = s390int->type;
inti->pgm.code = s390int->parm;
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);
kvm_s390_vcpu_wakeup(vcpu);
return 0;
if (!rc)
kvm_s390_vcpu_wakeup(vcpu);
else
kfree(inti);
return rc;
}

void kvm_s390_clear_float_irqs(struct kvm *kvm)
Expand Down

0 comments on commit 0146a7b

Please sign in to comment.