diff options
author | Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> | 2011-10-18 06:27:15 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-10-30 06:24:05 -0400 |
commit | 7697e71f72b45a1bd0abe70918c383100fcc8514 (patch) | |
tree | afad6ff9dcd00a031de31b9cd34d2ae09484586a /arch/s390/kvm/sigp.c | |
parent | 7eef87dc99e419b1cc051e4417c37e4744d7b661 (diff) |
KVM: s390: implement sigp external call
Implement sigp external call, which might be required for guests that
issue an external call instead of an emergency signal for IPI.
This fixes an issue with "KVM: unknown SIGP: 0x02" when booting
such an SMP guest.
Signed-off-by: Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/s390/kvm/sigp.c')
-rw-r--r-- | arch/s390/kvm/sigp.c | 45 |
1 files changed, 44 insertions, 1 deletions
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index d6a50c1fb2e6..f815118835f3 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c | |||
@@ -87,6 +87,7 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr) | |||
87 | return -ENOMEM; | 87 | return -ENOMEM; |
88 | 88 | ||
89 | inti->type = KVM_S390_INT_EMERGENCY; | 89 | inti->type = KVM_S390_INT_EMERGENCY; |
90 | inti->emerg.code = vcpu->vcpu_id; | ||
90 | 91 | ||
91 | spin_lock(&fi->lock); | 92 | spin_lock(&fi->lock); |
92 | li = fi->local_int[cpu_addr]; | 93 | li = fi->local_int[cpu_addr]; |
@@ -103,9 +104,47 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr) | |||
103 | wake_up_interruptible(&li->wq); | 104 | wake_up_interruptible(&li->wq); |
104 | spin_unlock_bh(&li->lock); | 105 | spin_unlock_bh(&li->lock); |
105 | rc = 0; /* order accepted */ | 106 | rc = 0; /* order accepted */ |
107 | VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr); | ||
108 | unlock: | ||
109 | spin_unlock(&fi->lock); | ||
110 | return rc; | ||
111 | } | ||
112 | |||
113 | static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr) | ||
114 | { | ||
115 | struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; | ||
116 | struct kvm_s390_local_interrupt *li; | ||
117 | struct kvm_s390_interrupt_info *inti; | ||
118 | int rc; | ||
119 | |||
120 | if (cpu_addr >= KVM_MAX_VCPUS) | ||
121 | return 3; /* not operational */ | ||
122 | |||
123 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | ||
124 | if (!inti) | ||
125 | return -ENOMEM; | ||
126 | |||
127 | inti->type = KVM_S390_INT_EXTERNAL_CALL; | ||
128 | inti->extcall.code = vcpu->vcpu_id; | ||
129 | |||
130 | spin_lock(&fi->lock); | ||
131 | li = fi->local_int[cpu_addr]; | ||
132 | if (li == NULL) { | ||
133 | rc = 3; /* not operational */ | ||
134 | kfree(inti); | ||
135 | goto unlock; | ||
136 | } | ||
137 | spin_lock_bh(&li->lock); | ||
138 | list_add_tail(&inti->list, &li->list); | ||
139 | atomic_set(&li->active, 1); | ||
140 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | ||
141 | if (waitqueue_active(&li->wq)) | ||
142 | wake_up_interruptible(&li->wq); | ||
143 | spin_unlock_bh(&li->lock); | ||
144 | rc = 0; /* order accepted */ | ||
145 | VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x", cpu_addr); | ||
106 | unlock: | 146 | unlock: |
107 | spin_unlock(&fi->lock); | 147 | spin_unlock(&fi->lock); |
108 | VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr); | ||
109 | return rc; | 148 | return rc; |
110 | } | 149 | } |
111 | 150 | ||
@@ -267,6 +306,10 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu) | |||
267 | rc = __sigp_sense(vcpu, cpu_addr, | 306 | rc = __sigp_sense(vcpu, cpu_addr, |
268 | &vcpu->arch.guest_gprs[r1]); | 307 | &vcpu->arch.guest_gprs[r1]); |
269 | break; | 308 | break; |
309 | case SIGP_EXTERNAL_CALL: | ||
310 | vcpu->stat.instruction_sigp_external_call++; | ||
311 | rc = __sigp_external_call(vcpu, cpu_addr); | ||
312 | break; | ||
270 | case SIGP_EMERGENCY: | 313 | case SIGP_EMERGENCY: |
271 | vcpu->stat.instruction_sigp_emergency++; | 314 | vcpu->stat.instruction_sigp_emergency++; |
272 | rc = __sigp_emergency(vcpu, cpu_addr); | 315 | rc = __sigp_emergency(vcpu, cpu_addr); |