Commit 383d0b05 authored by Jens Freimann's avatar Jens Freimann Committed by Christian Borntraeger

KVM: s390: handle pending local interrupts via bitmap

This patch adapts handling of local interrupts to be more compliant with
the z/Architecture Principles of Operation and introduces a data
structure
which allows more efficient handling of interrupts.

* get rid of li->active flag, use bitmap instead
* Keep interrupts in a bitmap instead of a list
* Deliver interrupts in the order of their priority as defined in the
  PoP
* Use a second bitmap for sigp emergency requests, as a CPU can have
  one request pending from every other CPU in the system.
Signed-off-by: default avatarJens Freimann <jfrei@linux.vnet.ibm.com>
Reviewed-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: default avatarDavid Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
parent c0e6159d
...@@ -398,8 +398,6 @@ struct kvm_s390_irq_payload { ...@@ -398,8 +398,6 @@ struct kvm_s390_irq_payload {
struct kvm_s390_local_interrupt { struct kvm_s390_local_interrupt {
spinlock_t lock; spinlock_t lock;
struct list_head list;
atomic_t active;
struct kvm_s390_float_interrupt *float_int; struct kvm_s390_float_interrupt *float_int;
wait_queue_head_t *wq; wait_queue_head_t *wq;
atomic_t *cpuflags; atomic_t *cpuflags;
......
...@@ -257,7 +257,7 @@ static int handle_instruction_and_prog(struct kvm_vcpu *vcpu) ...@@ -257,7 +257,7 @@ static int handle_instruction_and_prog(struct kvm_vcpu *vcpu)
static int handle_external_interrupt(struct kvm_vcpu *vcpu) static int handle_external_interrupt(struct kvm_vcpu *vcpu)
{ {
u16 eic = vcpu->arch.sie_block->eic; u16 eic = vcpu->arch.sie_block->eic;
struct kvm_s390_interrupt irq; struct kvm_s390_irq irq;
psw_t newpsw; psw_t newpsw;
int rc; int rc;
...@@ -282,7 +282,7 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu) ...@@ -282,7 +282,7 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu)
if (kvm_s390_si_ext_call_pending(vcpu)) if (kvm_s390_si_ext_call_pending(vcpu))
return 0; return 0;
irq.type = KVM_S390_INT_EXTERNAL_CALL; irq.type = KVM_S390_INT_EXTERNAL_CALL;
irq.parm = vcpu->arch.sie_block->extcpuaddr; irq.u.extcall.code = vcpu->arch.sie_block->extcpuaddr;
break; break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
......
This diff is collapsed.
...@@ -719,7 +719,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, ...@@ -719,7 +719,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
} }
spin_lock_init(&vcpu->arch.local_int.lock); spin_lock_init(&vcpu->arch.local_int.lock);
INIT_LIST_HEAD(&vcpu->arch.local_int.list);
vcpu->arch.local_int.float_int = &kvm->arch.float_int; vcpu->arch.local_int.float_int = &kvm->arch.float_int;
vcpu->arch.local_int.wq = &vcpu->wq; vcpu->arch.local_int.wq = &vcpu->wq;
vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags; vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags;
...@@ -1122,13 +1121,15 @@ static void __kvm_inject_pfault_token(struct kvm_vcpu *vcpu, bool start_token, ...@@ -1122,13 +1121,15 @@ static void __kvm_inject_pfault_token(struct kvm_vcpu *vcpu, bool start_token,
unsigned long token) unsigned long token)
{ {
struct kvm_s390_interrupt inti; struct kvm_s390_interrupt inti;
inti.parm64 = token; struct kvm_s390_irq irq;
if (start_token) { if (start_token) {
inti.type = KVM_S390_INT_PFAULT_INIT; irq.u.ext.ext_params2 = token;
WARN_ON_ONCE(kvm_s390_inject_vcpu(vcpu, &inti)); irq.type = KVM_S390_INT_PFAULT_INIT;
WARN_ON_ONCE(kvm_s390_inject_vcpu(vcpu, &irq));
} else { } else {
inti.type = KVM_S390_INT_PFAULT_DONE; inti.type = KVM_S390_INT_PFAULT_DONE;
inti.parm64 = token;
WARN_ON_ONCE(kvm_s390_inject_vm(vcpu->kvm, &inti)); WARN_ON_ONCE(kvm_s390_inject_vm(vcpu->kvm, &inti));
} }
} }
...@@ -1622,11 +1623,14 @@ long kvm_arch_vcpu_ioctl(struct file *filp, ...@@ -1622,11 +1623,14 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
switch (ioctl) { switch (ioctl) {
case KVM_S390_INTERRUPT: { case KVM_S390_INTERRUPT: {
struct kvm_s390_interrupt s390int; struct kvm_s390_interrupt s390int;
struct kvm_s390_irq s390irq;
r = -EFAULT; r = -EFAULT;
if (copy_from_user(&s390int, argp, sizeof(s390int))) if (copy_from_user(&s390int, argp, sizeof(s390int)))
break; break;
r = kvm_s390_inject_vcpu(vcpu, &s390int); if (s390int_to_s390irq(&s390int, &s390irq))
return -EINVAL;
r = kvm_s390_inject_vcpu(vcpu, &s390irq);
break; break;
} }
case KVM_S390_STORE_STATUS: case KVM_S390_STORE_STATUS:
......
...@@ -142,7 +142,7 @@ void kvm_s390_clear_float_irqs(struct kvm *kvm); ...@@ -142,7 +142,7 @@ void kvm_s390_clear_float_irqs(struct kvm *kvm);
int __must_check kvm_s390_inject_vm(struct kvm *kvm, int __must_check kvm_s390_inject_vm(struct kvm *kvm,
struct kvm_s390_interrupt *s390int); struct kvm_s390_interrupt *s390int);
int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
struct kvm_s390_interrupt *s390int); struct kvm_s390_irq *irq);
int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm, struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
u64 cr6, u64 schid); u64 cr6, u64 schid);
...@@ -224,6 +224,9 @@ static inline int kvm_s390_inject_prog_cond(struct kvm_vcpu *vcpu, int rc) ...@@ -224,6 +224,9 @@ static inline int kvm_s390_inject_prog_cond(struct kvm_vcpu *vcpu, int rc)
return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm); return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
} }
int s390int_to_s390irq(struct kvm_s390_interrupt *s390int,
struct kvm_s390_irq *s390irq);
/* implemented in interrupt.c */ /* implemented in interrupt.c */
int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
int psw_extint_disabled(struct kvm_vcpu *vcpu); int psw_extint_disabled(struct kvm_vcpu *vcpu);
......
...@@ -49,13 +49,13 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu, ...@@ -49,13 +49,13 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
static int __inject_sigp_emergency(struct kvm_vcpu *vcpu, static int __inject_sigp_emergency(struct kvm_vcpu *vcpu,
struct kvm_vcpu *dst_vcpu) struct kvm_vcpu *dst_vcpu)
{ {
struct kvm_s390_interrupt s390int = { struct kvm_s390_irq irq = {
.type = KVM_S390_INT_EMERGENCY, .type = KVM_S390_INT_EMERGENCY,
.parm = vcpu->vcpu_id, .u.emerg.code = vcpu->vcpu_id,
}; };
int rc = 0; int rc = 0;
rc = kvm_s390_inject_vcpu(dst_vcpu, &s390int); rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
if (!rc) if (!rc)
VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x",
dst_vcpu->vcpu_id); dst_vcpu->vcpu_id);
...@@ -98,13 +98,13 @@ static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu, ...@@ -98,13 +98,13 @@ static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu,
static int __sigp_external_call(struct kvm_vcpu *vcpu, static int __sigp_external_call(struct kvm_vcpu *vcpu,
struct kvm_vcpu *dst_vcpu) struct kvm_vcpu *dst_vcpu)
{ {
struct kvm_s390_interrupt s390int = { struct kvm_s390_irq irq = {
.type = KVM_S390_INT_EXTERNAL_CALL, .type = KVM_S390_INT_EXTERNAL_CALL,
.parm = vcpu->vcpu_id, .u.extcall.code = vcpu->vcpu_id,
}; };
int rc; int rc;
rc = kvm_s390_inject_vcpu(dst_vcpu, &s390int); rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
if (!rc) if (!rc)
VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x", VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x",
dst_vcpu->vcpu_id); dst_vcpu->vcpu_id);
...@@ -115,29 +115,20 @@ static int __sigp_external_call(struct kvm_vcpu *vcpu, ...@@ -115,29 +115,20 @@ static int __sigp_external_call(struct kvm_vcpu *vcpu,
static int __inject_sigp_stop(struct kvm_vcpu *dst_vcpu, int action) static int __inject_sigp_stop(struct kvm_vcpu *dst_vcpu, int action)
{ {
struct kvm_s390_local_interrupt *li = &dst_vcpu->arch.local_int; struct kvm_s390_local_interrupt *li = &dst_vcpu->arch.local_int;
struct kvm_s390_interrupt_info *inti;
int rc = SIGP_CC_ORDER_CODE_ACCEPTED; int rc = SIGP_CC_ORDER_CODE_ACCEPTED;
inti = kzalloc(sizeof(*inti), GFP_ATOMIC);
if (!inti)
return -ENOMEM;
inti->type = KVM_S390_SIGP_STOP;
spin_lock(&li->lock); spin_lock(&li->lock);
if (li->action_bits & ACTION_STOP_ON_STOP) { if (li->action_bits & ACTION_STOP_ON_STOP) {
/* another SIGP STOP is pending */ /* another SIGP STOP is pending */
kfree(inti);
rc = SIGP_CC_BUSY; rc = SIGP_CC_BUSY;
goto out; goto out;
} }
if ((atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) { if ((atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
kfree(inti);
if ((action & ACTION_STORE_ON_STOP) != 0) if ((action & ACTION_STORE_ON_STOP) != 0)
rc = -ESHUTDOWN; rc = -ESHUTDOWN;
goto out; goto out;
} }
list_add_tail(&inti->list, &li->list); set_bit(IRQ_PEND_SIGP_STOP, &li->pending_irqs);
atomic_set(&li->active, 1);
li->action_bits |= action; li->action_bits |= action;
atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags); atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
kvm_s390_vcpu_wakeup(dst_vcpu); kvm_s390_vcpu_wakeup(dst_vcpu);
...@@ -207,7 +198,6 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu, ...@@ -207,7 +198,6 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
u32 address, u64 *reg) u32 address, u64 *reg)
{ {
struct kvm_s390_local_interrupt *li; struct kvm_s390_local_interrupt *li;
struct kvm_s390_interrupt_info *inti;
int rc; int rc;
li = &dst_vcpu->arch.local_int; li = &dst_vcpu->arch.local_int;
...@@ -224,25 +214,17 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu, ...@@ -224,25 +214,17 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
return SIGP_CC_STATUS_STORED; return SIGP_CC_STATUS_STORED;
} }
inti = kzalloc(sizeof(*inti), GFP_KERNEL);
if (!inti)
return SIGP_CC_BUSY;
spin_lock(&li->lock); spin_lock(&li->lock);
/* cpu must be in stopped state */ /* cpu must be in stopped state */
if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) { if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
*reg &= 0xffffffff00000000UL; *reg &= 0xffffffff00000000UL;
*reg |= SIGP_STATUS_INCORRECT_STATE; *reg |= SIGP_STATUS_INCORRECT_STATE;
rc = SIGP_CC_STATUS_STORED; rc = SIGP_CC_STATUS_STORED;
kfree(inti);
goto out_li; goto out_li;
} }
inti->type = KVM_S390_SIGP_SET_PREFIX; li->irq.prefix.address = address;
inti->prefix.address = address; set_bit(IRQ_PEND_SET_PREFIX, &li->pending_irqs);
list_add_tail(&inti->list, &li->list);
atomic_set(&li->active, 1);
kvm_s390_vcpu_wakeup(dst_vcpu); kvm_s390_vcpu_wakeup(dst_vcpu);
rc = SIGP_CC_ORDER_CODE_ACCEPTED; rc = SIGP_CC_ORDER_CODE_ACCEPTED;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment