--------
 - add IPTE to trace event decoder
 - document and advertise KVM_CAP_S390_IRQCHIP
 
 Cleanups
 --------
 - Reuse kvm_vcpu_block for s390
 - Get rid of tasklet for wakup processing
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABAgAGBQJTzRsBAAoJEBF7vIC1phx8gf4P/0TlwS6YoLsWJ2VFOwLyjsbZ
 SU3WVPKgWwAlEE1XyTHpnKIainpUUp7qc227/QZDt7plONfZHir/kmkAeZlfqVD/
 tVogeYXBHFvLIvBJVLOhcGnSqK6WaHiUFJtv9Goz3wD6GCe+qzFgV15gXlR9Nw7E
 mOISwpFOoa8lDWj0XTF5sfchdwyVY3Nj49W2quNmpp8vKkwHSyHzyu5MKd7wBmI2
 9LV25/DzDKW8uslEXINgUFpoUT/LQ4regWjhHPXaoA7+zBvttD/33zdXzeR8qBxm
 FnV1Pypzxd69YfHg8CVTRoLS3knKdWNAReCGC8LX1XyF17cOhuU3FlkQRln8dGLP
 B2M3p1sMUR+fiXkaEZdRdFVkBtxEvmAzyAcBd7jklGpM2/RTHOcYfzQl66UO4EK4
 dfKvK5NuCz+t4q6C6rUgjLDKv2GxZulzARVMlI99bBFc1g57HHDD+trt0yXTAX81
 GqLIkrAT0H+RX1IrQNvhgEg2j8wME2tCmw/BXFYuLLlREoDniMKPZwteBSLZMjy5
 6BstgWYarOdul59XWNjogSlPkyaqh0fxDul00X+/sTxEwxgJfApOmpcU7XekD5FP
 4EHC8BHG3TBEjAoMD71La7a4P6vh8F54KLPta8YrtP3pe1d4Ez/15Mi2Wf/sdAVQ
 0Ym0Q9y1QMeH/s/CPDkB
 =8McL
 -----END PGP SIGNATURE-----

Merge tag 'kvm-s390-20140721' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into kvm-next

Bugfixes
--------
- add IPTE to trace event decoder
- document and advertise KVM_CAP_S390_IRQCHIP

Cleanups
--------
- Reuse kvm_vcpu_block for s390
- Get rid of tasklet for wakup processing
This commit is contained in:
Paolo Bonzini 2014-07-22 10:22:53 +02:00
commit c756ad036f
7 changed files with 82 additions and 104 deletions

View File

@ -2934,15 +2934,18 @@ The fields in each entry are defined as follows:
6. Capabilities that can be enabled 6. Capabilities that can be enabled
----------------------------------- -----------------------------------
There are certain capabilities that change the behavior of the virtual CPU when There are certain capabilities that change the behavior of the virtual CPU or
enabled. To enable them, please see section 4.37. Below you can find a list of the virtual machine when enabled. To enable them, please see section 4.37.
capabilities and what their effect on the vCPU is when enabling them. Below you can find a list of capabilities and what their effect on the vCPU or
the virtual machine is when enabling them.
The following information is provided along with the description: The following information is provided along with the description:
Architectures: which instruction set architectures provide this ioctl. Architectures: which instruction set architectures provide this ioctl.
x86 includes both i386 and x86_64. x86 includes both i386 and x86_64.
Target: whether this is a per-vcpu or per-vm capability.
Parameters: what parameters are accepted by the capability. Parameters: what parameters are accepted by the capability.
Returns: the return value. General error numbers (EBADF, ENOMEM, EINVAL) Returns: the return value. General error numbers (EBADF, ENOMEM, EINVAL)
@ -2952,6 +2955,7 @@ The following information is provided along with the description:
6.1 KVM_CAP_PPC_OSI 6.1 KVM_CAP_PPC_OSI
Architectures: ppc Architectures: ppc
Target: vcpu
Parameters: none Parameters: none
Returns: 0 on success; -1 on error Returns: 0 on success; -1 on error
@ -2966,6 +2970,7 @@ When this capability is enabled, KVM_EXIT_OSI can occur.
6.2 KVM_CAP_PPC_PAPR 6.2 KVM_CAP_PPC_PAPR
Architectures: ppc Architectures: ppc
Target: vcpu
Parameters: none Parameters: none
Returns: 0 on success; -1 on error Returns: 0 on success; -1 on error
@ -2985,6 +2990,7 @@ When this capability is enabled, KVM_EXIT_PAPR_HCALL can occur.
6.3 KVM_CAP_SW_TLB 6.3 KVM_CAP_SW_TLB
Architectures: ppc Architectures: ppc
Target: vcpu
Parameters: args[0] is the address of a struct kvm_config_tlb Parameters: args[0] is the address of a struct kvm_config_tlb
Returns: 0 on success; -1 on error Returns: 0 on success; -1 on error
@ -3027,6 +3033,7 @@ For mmu types KVM_MMU_FSL_BOOKE_NOHV and KVM_MMU_FSL_BOOKE_HV:
6.4 KVM_CAP_S390_CSS_SUPPORT 6.4 KVM_CAP_S390_CSS_SUPPORT
Architectures: s390 Architectures: s390
Target: vcpu
Parameters: none Parameters: none
Returns: 0 on success; -1 on error Returns: 0 on success; -1 on error
@ -3038,9 +3045,13 @@ handled in-kernel, while the other I/O instructions are passed to userspace.
When this capability is enabled, KVM_EXIT_S390_TSCH will occur on TEST When this capability is enabled, KVM_EXIT_S390_TSCH will occur on TEST
SUBCHANNEL intercepts. SUBCHANNEL intercepts.
Note that even though this capability is enabled per-vcpu, the complete
virtual machine is affected.
6.5 KVM_CAP_PPC_EPR 6.5 KVM_CAP_PPC_EPR
Architectures: ppc Architectures: ppc
Target: vcpu
Parameters: args[0] defines whether the proxy facility is active Parameters: args[0] defines whether the proxy facility is active
Returns: 0 on success; -1 on error Returns: 0 on success; -1 on error
@ -3066,7 +3077,17 @@ This capability connects the vcpu to an in-kernel MPIC device.
6.7 KVM_CAP_IRQ_XICS 6.7 KVM_CAP_IRQ_XICS
Architectures: ppc Architectures: ppc
Target: vcpu
Parameters: args[0] is the XICS device fd Parameters: args[0] is the XICS device fd
args[1] is the XICS CPU number (server ID) for this vcpu args[1] is the XICS CPU number (server ID) for this vcpu
This capability connects the vcpu to an in-kernel XICS device. This capability connects the vcpu to an in-kernel XICS device.
6.8 KVM_CAP_S390_IRQCHIP
Architectures: s390
Target: vm
Parameters: none
This capability enables the in-kernel irqchip for s390. Please refer to
"4.24 KVM_CREATE_IRQCHIP" for details.

View File

@ -305,7 +305,6 @@ struct kvm_s390_local_interrupt {
struct list_head list; struct list_head list;
atomic_t active; atomic_t active;
struct kvm_s390_float_interrupt *float_int; struct kvm_s390_float_interrupt *float_int;
int timer_due; /* event indicator for waitqueue below */
wait_queue_head_t *wq; wait_queue_head_t *wq;
atomic_t *cpuflags; atomic_t *cpuflags;
unsigned int action_bits; unsigned int action_bits;
@ -367,7 +366,6 @@ struct kvm_vcpu_arch {
s390_fp_regs guest_fpregs; s390_fp_regs guest_fpregs;
struct kvm_s390_local_interrupt local_int; struct kvm_s390_local_interrupt local_int;
struct hrtimer ckc_timer; struct hrtimer ckc_timer;
struct tasklet_struct tasklet;
struct kvm_s390_pgm_info pgm; struct kvm_s390_pgm_info pgm;
union { union {
struct cpuid cpu_id; struct cpuid cpu_id;

View File

@ -108,6 +108,7 @@
exit_code_ipa0(0xB2, 0x17, "STETR"), \ exit_code_ipa0(0xB2, 0x17, "STETR"), \
exit_code_ipa0(0xB2, 0x18, "PC"), \ exit_code_ipa0(0xB2, 0x18, "PC"), \
exit_code_ipa0(0xB2, 0x20, "SERVC"), \ exit_code_ipa0(0xB2, 0x20, "SERVC"), \
exit_code_ipa0(0xB2, 0x21, "IPTE"), \
exit_code_ipa0(0xB2, 0x28, "PT"), \ exit_code_ipa0(0xB2, 0x28, "PT"), \
exit_code_ipa0(0xB2, 0x29, "ISKE"), \ exit_code_ipa0(0xB2, 0x29, "ISKE"), \
exit_code_ipa0(0xB2, 0x2a, "RRBE"), \ exit_code_ipa0(0xB2, 0x2a, "RRBE"), \

View File

@ -544,13 +544,13 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
int rc = 0; int rc = 0;
if (atomic_read(&li->active)) { if (atomic_read(&li->active)) {
spin_lock_bh(&li->lock); spin_lock(&li->lock);
list_for_each_entry(inti, &li->list, list) list_for_each_entry(inti, &li->list, list)
if (__interrupt_is_deliverable(vcpu, inti)) { if (__interrupt_is_deliverable(vcpu, inti)) {
rc = 1; rc = 1;
break; break;
} }
spin_unlock_bh(&li->lock); spin_unlock(&li->lock);
} }
if ((!rc) && atomic_read(&fi->active)) { if ((!rc) && atomic_read(&fi->active)) {
@ -585,88 +585,56 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
int kvm_s390_handle_wait(struct kvm_vcpu *vcpu) int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
{ {
u64 now, sltime; u64 now, sltime;
DECLARE_WAITQUEUE(wait, current);
vcpu->stat.exit_wait_state++; vcpu->stat.exit_wait_state++;
if (kvm_cpu_has_interrupt(vcpu))
return 0;
__set_cpu_idle(vcpu); /* fast path */
spin_lock_bh(&vcpu->arch.local_int.lock); if (kvm_cpu_has_pending_timer(vcpu) || kvm_arch_vcpu_runnable(vcpu))
vcpu->arch.local_int.timer_due = 0; return 0;
spin_unlock_bh(&vcpu->arch.local_int.lock);
if (psw_interrupts_disabled(vcpu)) { if (psw_interrupts_disabled(vcpu)) {
VCPU_EVENT(vcpu, 3, "%s", "disabled wait"); VCPU_EVENT(vcpu, 3, "%s", "disabled wait");
__unset_cpu_idle(vcpu);
return -EOPNOTSUPP; /* disabled wait */ return -EOPNOTSUPP; /* disabled wait */
} }
__set_cpu_idle(vcpu);
if (!ckc_interrupts_enabled(vcpu)) { if (!ckc_interrupts_enabled(vcpu)) {
VCPU_EVENT(vcpu, 3, "%s", "enabled wait w/o timer"); VCPU_EVENT(vcpu, 3, "%s", "enabled wait w/o timer");
goto no_timer; goto no_timer;
} }
now = get_tod_clock_fast() + vcpu->arch.sie_block->epoch; now = get_tod_clock_fast() + vcpu->arch.sie_block->epoch;
if (vcpu->arch.sie_block->ckc < now) {
__unset_cpu_idle(vcpu);
return 0;
}
sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now); sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now);
hrtimer_start(&vcpu->arch.ckc_timer, ktime_set (0, sltime) , HRTIMER_MODE_REL); hrtimer_start(&vcpu->arch.ckc_timer, ktime_set (0, sltime) , HRTIMER_MODE_REL);
VCPU_EVENT(vcpu, 5, "enabled wait via clock comparator: %llx ns", sltime); VCPU_EVENT(vcpu, 5, "enabled wait via clock comparator: %llx ns", sltime);
no_timer: no_timer:
srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
spin_lock(&vcpu->arch.local_int.float_int->lock); kvm_vcpu_block(vcpu);
spin_lock_bh(&vcpu->arch.local_int.lock);
add_wait_queue(&vcpu->wq, &wait);
while (list_empty(&vcpu->arch.local_int.list) &&
list_empty(&vcpu->arch.local_int.float_int->list) &&
(!vcpu->arch.local_int.timer_due) &&
!signal_pending(current) &&
!kvm_s390_si_ext_call_pending(vcpu)) {
set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_bh(&vcpu->arch.local_int.lock);
spin_unlock(&vcpu->arch.local_int.float_int->lock);
schedule();
spin_lock(&vcpu->arch.local_int.float_int->lock);
spin_lock_bh(&vcpu->arch.local_int.lock);
}
__unset_cpu_idle(vcpu); __unset_cpu_idle(vcpu);
__set_current_state(TASK_RUNNING);
remove_wait_queue(&vcpu->wq, &wait);
spin_unlock_bh(&vcpu->arch.local_int.lock);
spin_unlock(&vcpu->arch.local_int.float_int->lock);
vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
hrtimer_try_to_cancel(&vcpu->arch.ckc_timer); hrtimer_try_to_cancel(&vcpu->arch.ckc_timer);
return 0; return 0;
} }
void kvm_s390_tasklet(unsigned long parm) void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu)
{ {
struct kvm_vcpu *vcpu = (struct kvm_vcpu *) parm; if (waitqueue_active(&vcpu->wq)) {
/*
spin_lock(&vcpu->arch.local_int.lock); * The vcpu gave up the cpu voluntarily, mark it as a good
vcpu->arch.local_int.timer_due = 1; * yield-candidate.
if (waitqueue_active(&vcpu->wq)) */
vcpu->preempted = true;
wake_up_interruptible(&vcpu->wq); wake_up_interruptible(&vcpu->wq);
spin_unlock(&vcpu->arch.local_int.lock); }
} }
/*
* low level hrtimer wake routine. Because this runs in hardirq context
* we schedule a tasklet to do the real work.
*/
enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer) enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer)
{ {
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
vcpu = container_of(timer, struct kvm_vcpu, arch.ckc_timer); vcpu = container_of(timer, struct kvm_vcpu, arch.ckc_timer);
vcpu->preempted = true; kvm_s390_vcpu_wakeup(vcpu);
tasklet_schedule(&vcpu->arch.tasklet);
return HRTIMER_NORESTART; return HRTIMER_NORESTART;
} }
@ -676,13 +644,13 @@ void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu)
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
struct kvm_s390_interrupt_info *n, *inti = NULL; struct kvm_s390_interrupt_info *n, *inti = NULL;
spin_lock_bh(&li->lock); spin_lock(&li->lock);
list_for_each_entry_safe(inti, n, &li->list, list) { list_for_each_entry_safe(inti, n, &li->list, list) {
list_del(&inti->list); list_del(&inti->list);
kfree(inti); kfree(inti);
} }
atomic_set(&li->active, 0); atomic_set(&li->active, 0);
spin_unlock_bh(&li->lock); spin_unlock(&li->lock);
/* clear pending external calls set by sigp interpretation facility */ /* clear pending external calls set by sigp interpretation facility */
atomic_clear_mask(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags); atomic_clear_mask(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags);
@ -701,7 +669,7 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
if (atomic_read(&li->active)) { if (atomic_read(&li->active)) {
do { do {
deliver = 0; deliver = 0;
spin_lock_bh(&li->lock); spin_lock(&li->lock);
list_for_each_entry_safe(inti, n, &li->list, list) { list_for_each_entry_safe(inti, n, &li->list, list) {
if (__interrupt_is_deliverable(vcpu, inti)) { if (__interrupt_is_deliverable(vcpu, inti)) {
list_del(&inti->list); list_del(&inti->list);
@ -712,7 +680,7 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
} }
if (list_empty(&li->list)) if (list_empty(&li->list))
atomic_set(&li->active, 0); atomic_set(&li->active, 0);
spin_unlock_bh(&li->lock); spin_unlock(&li->lock);
if (deliver) { if (deliver) {
__do_deliver_interrupt(vcpu, inti); __do_deliver_interrupt(vcpu, inti);
kfree(inti); kfree(inti);
@ -758,7 +726,7 @@ void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu)
if (atomic_read(&li->active)) { if (atomic_read(&li->active)) {
do { do {
deliver = 0; deliver = 0;
spin_lock_bh(&li->lock); spin_lock(&li->lock);
list_for_each_entry_safe(inti, n, &li->list, list) { list_for_each_entry_safe(inti, n, &li->list, list) {
if ((inti->type == KVM_S390_MCHK) && if ((inti->type == KVM_S390_MCHK) &&
__interrupt_is_deliverable(vcpu, inti)) { __interrupt_is_deliverable(vcpu, inti)) {
@ -770,7 +738,7 @@ void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu)
} }
if (list_empty(&li->list)) if (list_empty(&li->list))
atomic_set(&li->active, 0); atomic_set(&li->active, 0);
spin_unlock_bh(&li->lock); spin_unlock(&li->lock);
if (deliver) { if (deliver) {
__do_deliver_interrupt(vcpu, inti); __do_deliver_interrupt(vcpu, inti);
kfree(inti); kfree(inti);
@ -817,11 +785,11 @@ int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
VCPU_EVENT(vcpu, 3, "inject: program check %d (from kernel)", code); VCPU_EVENT(vcpu, 3, "inject: program check %d (from kernel)", code);
trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, inti->type, code, 0, 1); trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, inti->type, code, 0, 1);
spin_lock_bh(&li->lock); spin_lock(&li->lock);
list_add(&inti->list, &li->list); list_add(&inti->list, &li->list);
atomic_set(&li->active, 1); atomic_set(&li->active, 1);
BUG_ON(waitqueue_active(li->wq)); BUG_ON(waitqueue_active(li->wq));
spin_unlock_bh(&li->lock); spin_unlock(&li->lock);
return 0; return 0;
} }
@ -842,11 +810,11 @@ int kvm_s390_inject_prog_irq(struct kvm_vcpu *vcpu,
inti->type = KVM_S390_PROGRAM_INT; inti->type = KVM_S390_PROGRAM_INT;
memcpy(&inti->pgm, pgm_info, sizeof(inti->pgm)); memcpy(&inti->pgm, pgm_info, sizeof(inti->pgm));
spin_lock_bh(&li->lock); spin_lock(&li->lock);
list_add(&inti->list, &li->list); list_add(&inti->list, &li->list);
atomic_set(&li->active, 1); atomic_set(&li->active, 1);
BUG_ON(waitqueue_active(li->wq)); BUG_ON(waitqueue_active(li->wq));
spin_unlock_bh(&li->lock); spin_unlock(&li->lock);
return 0; return 0;
} }
@ -934,12 +902,10 @@ static int __inject_vm(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
} }
dst_vcpu = kvm_get_vcpu(kvm, sigcpu); dst_vcpu = kvm_get_vcpu(kvm, sigcpu);
li = &dst_vcpu->arch.local_int; li = &dst_vcpu->arch.local_int;
spin_lock_bh(&li->lock); spin_lock(&li->lock);
atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
if (waitqueue_active(li->wq)) spin_unlock(&li->lock);
wake_up_interruptible(li->wq); kvm_s390_vcpu_wakeup(kvm_get_vcpu(kvm, sigcpu));
kvm_get_vcpu(kvm, sigcpu)->preempted = true;
spin_unlock_bh(&li->lock);
unlock_fi: unlock_fi:
spin_unlock(&fi->lock); spin_unlock(&fi->lock);
mutex_unlock(&kvm->lock); mutex_unlock(&kvm->lock);
@ -1081,7 +1047,7 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
mutex_lock(&vcpu->kvm->lock); mutex_lock(&vcpu->kvm->lock);
li = &vcpu->arch.local_int; li = &vcpu->arch.local_int;
spin_lock_bh(&li->lock); spin_lock(&li->lock);
if (inti->type == KVM_S390_PROGRAM_INT) if (inti->type == KVM_S390_PROGRAM_INT)
list_add(&inti->list, &li->list); list_add(&inti->list, &li->list);
else else
@ -1090,11 +1056,9 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
if (inti->type == KVM_S390_SIGP_STOP) if (inti->type == KVM_S390_SIGP_STOP)
li->action_bits |= ACTION_STOP_ON_STOP; li->action_bits |= ACTION_STOP_ON_STOP;
atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
if (waitqueue_active(&vcpu->wq)) spin_unlock(&li->lock);
wake_up_interruptible(&vcpu->wq);
vcpu->preempted = true;
spin_unlock_bh(&li->lock);
mutex_unlock(&vcpu->kvm->lock); mutex_unlock(&vcpu->kvm->lock);
kvm_s390_vcpu_wakeup(vcpu);
return 0; return 0;
} }

View File

@ -166,6 +166,7 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_IOEVENTFD: case KVM_CAP_IOEVENTFD:
case KVM_CAP_DEVICE_CTRL: case KVM_CAP_DEVICE_CTRL:
case KVM_CAP_ENABLE_CAP_VM: case KVM_CAP_ENABLE_CAP_VM:
case KVM_CAP_S390_IRQCHIP:
case KVM_CAP_VM_ATTRIBUTES: case KVM_CAP_VM_ATTRIBUTES:
case KVM_CAP_MP_STATE: case KVM_CAP_MP_STATE:
r = 1; r = 1;
@ -649,8 +650,6 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
return rc; return rc;
} }
hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet,
(unsigned long) vcpu);
vcpu->arch.ckc_timer.function = kvm_s390_idle_wakeup; vcpu->arch.ckc_timer.function = kvm_s390_idle_wakeup;
get_cpu_id(&vcpu->arch.cpu_id); get_cpu_id(&vcpu->arch.cpu_id);
vcpu->arch.cpu_id.version = 0xff; vcpu->arch.cpu_id.version = 0xff;
@ -1068,6 +1067,9 @@ retry:
goto retry; goto retry;
} }
/* nothing to do, just clear the request */
clear_bit(KVM_REQ_UNHALT, &vcpu->requests);
return 0; return 0;
} }
@ -1475,7 +1477,7 @@ void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu)
trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 1); trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 1);
/* Only one cpu at a time may enter/leave the STOPPED state. */ /* Only one cpu at a time may enter/leave the STOPPED state. */
spin_lock_bh(&vcpu->kvm->arch.start_stop_lock); spin_lock(&vcpu->kvm->arch.start_stop_lock);
online_vcpus = atomic_read(&vcpu->kvm->online_vcpus); online_vcpus = atomic_read(&vcpu->kvm->online_vcpus);
for (i = 0; i < online_vcpus; i++) { for (i = 0; i < online_vcpus; i++) {
@ -1501,7 +1503,7 @@ void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu)
* Let's play safe and flush the VCPU at startup. * Let's play safe and flush the VCPU at startup.
*/ */
vcpu->arch.sie_block->ihcpu = 0xffff; vcpu->arch.sie_block->ihcpu = 0xffff;
spin_unlock_bh(&vcpu->kvm->arch.start_stop_lock); spin_unlock(&vcpu->kvm->arch.start_stop_lock);
return; return;
} }
@ -1515,17 +1517,17 @@ void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu)
trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 0); trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 0);
/* Only one cpu at a time may enter/leave the STOPPED state. */ /* Only one cpu at a time may enter/leave the STOPPED state. */
spin_lock_bh(&vcpu->kvm->arch.start_stop_lock); spin_lock(&vcpu->kvm->arch.start_stop_lock);
online_vcpus = atomic_read(&vcpu->kvm->online_vcpus); online_vcpus = atomic_read(&vcpu->kvm->online_vcpus);
/* Need to lock access to action_bits to avoid a SIGP race condition */ /* Need to lock access to action_bits to avoid a SIGP race condition */
spin_lock_bh(&vcpu->arch.local_int.lock); spin_lock(&vcpu->arch.local_int.lock);
atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
/* SIGP STOP and SIGP STOP AND STORE STATUS has been fully processed */ /* SIGP STOP and SIGP STOP AND STORE STATUS has been fully processed */
vcpu->arch.local_int.action_bits &= vcpu->arch.local_int.action_bits &=
~(ACTION_STOP_ON_STOP | ACTION_STORE_ON_STOP); ~(ACTION_STOP_ON_STOP | ACTION_STORE_ON_STOP);
spin_unlock_bh(&vcpu->arch.local_int.lock); spin_unlock(&vcpu->arch.local_int.lock);
__disable_ibs_on_vcpu(vcpu); __disable_ibs_on_vcpu(vcpu);
@ -1544,7 +1546,7 @@ void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu)
__enable_ibs_on_vcpu(started_vcpu); __enable_ibs_on_vcpu(started_vcpu);
} }
spin_unlock_bh(&vcpu->kvm->arch.start_stop_lock); spin_unlock(&vcpu->kvm->arch.start_stop_lock);
return; return;
} }

View File

@ -136,8 +136,8 @@ static inline int kvm_s390_user_cpu_state_ctrl(struct kvm *kvm)
} }
int kvm_s390_handle_wait(struct kvm_vcpu *vcpu); int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu);
enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer); enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer);
void kvm_s390_tasklet(unsigned long parm);
void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu); void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu);
void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu); void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu);
void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu); void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu);

View File

@ -125,8 +125,9 @@ static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr)
return rc ? rc : SIGP_CC_ORDER_CODE_ACCEPTED; return rc ? rc : SIGP_CC_ORDER_CODE_ACCEPTED;
} }
static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, 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_interrupt_info *inti; struct kvm_s390_interrupt_info *inti;
int rc = SIGP_CC_ORDER_CODE_ACCEPTED; int rc = SIGP_CC_ORDER_CODE_ACCEPTED;
@ -135,7 +136,7 @@ static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action)
return -ENOMEM; return -ENOMEM;
inti->type = KVM_S390_SIGP_STOP; inti->type = KVM_S390_SIGP_STOP;
spin_lock_bh(&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 */
rc = SIGP_CC_BUSY; rc = SIGP_CC_BUSY;
@ -151,17 +152,15 @@ static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action)
atomic_set(&li->active, 1); 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);
if (waitqueue_active(li->wq)) kvm_s390_vcpu_wakeup(dst_vcpu);
wake_up_interruptible(li->wq);
out: out:
spin_unlock_bh(&li->lock); spin_unlock(&li->lock);
return rc; return rc;
} }
static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int action) static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int action)
{ {
struct kvm_s390_local_interrupt *li;
struct kvm_vcpu *dst_vcpu = NULL; struct kvm_vcpu *dst_vcpu = NULL;
int rc; int rc;
@ -171,9 +170,8 @@ static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int action)
dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr); dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
if (!dst_vcpu) if (!dst_vcpu)
return SIGP_CC_NOT_OPERATIONAL; return SIGP_CC_NOT_OPERATIONAL;
li = &dst_vcpu->arch.local_int;
rc = __inject_sigp_stop(li, action); rc = __inject_sigp_stop(dst_vcpu, action);
VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr); VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr);
@ -243,7 +241,7 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
if (!inti) if (!inti)
return SIGP_CC_BUSY; return SIGP_CC_BUSY;
spin_lock_bh(&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;
@ -258,13 +256,12 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
list_add_tail(&inti->list, &li->list); list_add_tail(&inti->list, &li->list);
atomic_set(&li->active, 1); atomic_set(&li->active, 1);
if (waitqueue_active(li->wq)) kvm_s390_vcpu_wakeup(dst_vcpu);
wake_up_interruptible(li->wq);
rc = SIGP_CC_ORDER_CODE_ACCEPTED; rc = SIGP_CC_ORDER_CODE_ACCEPTED;
VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address); VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address);
out_li: out_li:
spin_unlock_bh(&li->lock); spin_unlock(&li->lock);
return rc; return rc;
} }
@ -280,9 +277,9 @@ static int __sigp_store_status_at_addr(struct kvm_vcpu *vcpu, u16 cpu_id,
if (!dst_vcpu) if (!dst_vcpu)
return SIGP_CC_NOT_OPERATIONAL; return SIGP_CC_NOT_OPERATIONAL;
spin_lock_bh(&dst_vcpu->arch.local_int.lock); spin_lock(&dst_vcpu->arch.local_int.lock);
flags = atomic_read(dst_vcpu->arch.local_int.cpuflags); flags = atomic_read(dst_vcpu->arch.local_int.cpuflags);
spin_unlock_bh(&dst_vcpu->arch.local_int.lock); spin_unlock(&dst_vcpu->arch.local_int.lock);
if (!(flags & CPUSTAT_STOPPED)) { if (!(flags & CPUSTAT_STOPPED)) {
*reg &= 0xffffffff00000000UL; *reg &= 0xffffffff00000000UL;
*reg |= SIGP_STATUS_INCORRECT_STATE; *reg |= SIGP_STATUS_INCORRECT_STATE;
@ -343,10 +340,10 @@ static int sigp_check_callable(struct kvm_vcpu *vcpu, u16 cpu_addr)
if (!dst_vcpu) if (!dst_vcpu)
return SIGP_CC_NOT_OPERATIONAL; return SIGP_CC_NOT_OPERATIONAL;
li = &dst_vcpu->arch.local_int; li = &dst_vcpu->arch.local_int;
spin_lock_bh(&li->lock); spin_lock(&li->lock);
if (li->action_bits & ACTION_STOP_ON_STOP) if (li->action_bits & ACTION_STOP_ON_STOP)
rc = SIGP_CC_BUSY; rc = SIGP_CC_BUSY;
spin_unlock_bh(&li->lock); spin_unlock(&li->lock);
return rc; return rc;
} }
@ -466,12 +463,7 @@ int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu)
dest_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr); dest_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
BUG_ON(dest_vcpu == NULL); BUG_ON(dest_vcpu == NULL);
spin_lock_bh(&dest_vcpu->arch.local_int.lock); kvm_s390_vcpu_wakeup(dest_vcpu);
if (waitqueue_active(&dest_vcpu->wq))
wake_up_interruptible(&dest_vcpu->wq);
dest_vcpu->preempted = true;
spin_unlock_bh(&dest_vcpu->arch.local_int.lock);
kvm_s390_set_psw_cc(vcpu, SIGP_CC_ORDER_CODE_ACCEPTED); kvm_s390_set_psw_cc(vcpu, SIGP_CC_ORDER_CODE_ACCEPTED);
return 0; return 0;
} }