aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2014-01-10 08:33:28 -0500
committerChristian Borntraeger <borntraeger@de.ibm.com>2014-04-22 07:24:39 -0400
commit8a242234b4bfed37f7fbd9b0b16f8088f31ca140 (patch)
treeb7dbea23f97a08e2e45512f20d546521dfcd6fb9
parent217a440683b51463f53e397cfdda27d7e92bf275 (diff)
KVM: s390: make use of ipte lock
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Reviewed-by: Thomas Huth <thuth@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
-rw-r--r--arch/s390/include/asm/kvm_host.h12
-rw-r--r--arch/s390/kvm/gaccess.c109
-rw-r--r--arch/s390/kvm/gaccess.h2
-rw-r--r--arch/s390/kvm/kvm-s390.c2
-rw-r--r--arch/s390/kvm/priv.c18
5 files changed, 142 insertions, 1 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index c290d443d2c1..f1ed7bdba733 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -39,9 +39,17 @@ struct sca_entry {
39 __u64 reserved2[2]; 39 __u64 reserved2[2];
40} __attribute__((packed)); 40} __attribute__((packed));
41 41
42union ipte_control {
43 unsigned long val;
44 struct {
45 unsigned long k : 1;
46 unsigned long kh : 31;
47 unsigned long kg : 32;
48 };
49};
42 50
43struct sca_block { 51struct sca_block {
44 __u64 ipte_control; 52 union ipte_control ipte_control;
45 __u64 reserved[5]; 53 __u64 reserved[5];
46 __u64 mcn; 54 __u64 mcn;
47 __u64 reserved2; 55 __u64 reserved2;
@@ -167,6 +175,7 @@ struct kvm_vcpu_stat {
167 u32 instruction_stpx; 175 u32 instruction_stpx;
168 u32 instruction_stap; 176 u32 instruction_stap;
169 u32 instruction_storage_key; 177 u32 instruction_storage_key;
178 u32 instruction_ipte_interlock;
170 u32 instruction_stsch; 179 u32 instruction_stsch;
171 u32 instruction_chsc; 180 u32 instruction_chsc;
172 u32 instruction_stsi; 181 u32 instruction_stsi;
@@ -336,6 +345,7 @@ struct kvm_arch{
336 int use_irqchip; 345 int use_irqchip;
337 int use_cmma; 346 int use_cmma;
338 struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS]; 347 struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];
348 wait_queue_head_t ipte_wq;
339}; 349};
340 350
341#define KVM_HVA_ERR_BAD (-1UL) 351#define KVM_HVA_ERR_BAD (-1UL)
diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c
index 916e1ee1f8c9..691fdb776c90 100644
--- a/arch/s390/kvm/gaccess.c
+++ b/arch/s390/kvm/gaccess.c
@@ -207,6 +207,107 @@ union raddress {
207 unsigned long pfra : 52; /* Page-Frame Real Address */ 207 unsigned long pfra : 52; /* Page-Frame Real Address */
208}; 208};
209 209
210static int ipte_lock_count;
211static DEFINE_MUTEX(ipte_mutex);
212
213int ipte_lock_held(struct kvm_vcpu *vcpu)
214{
215 union ipte_control *ic = &vcpu->kvm->arch.sca->ipte_control;
216
217 if (vcpu->arch.sie_block->eca & 1)
218 return ic->kh != 0;
219 return ipte_lock_count != 0;
220}
221
222static void ipte_lock_simple(struct kvm_vcpu *vcpu)
223{
224 union ipte_control old, new, *ic;
225
226 mutex_lock(&ipte_mutex);
227 ipte_lock_count++;
228 if (ipte_lock_count > 1)
229 goto out;
230 ic = &vcpu->kvm->arch.sca->ipte_control;
231 do {
232 old = ACCESS_ONCE(*ic);
233 while (old.k) {
234 cond_resched();
235 old = ACCESS_ONCE(*ic);
236 }
237 new = old;
238 new.k = 1;
239 } while (cmpxchg(&ic->val, old.val, new.val) != old.val);
240out:
241 mutex_unlock(&ipte_mutex);
242}
243
244static void ipte_unlock_simple(struct kvm_vcpu *vcpu)
245{
246 union ipte_control old, new, *ic;
247
248 mutex_lock(&ipte_mutex);
249 ipte_lock_count--;
250 if (ipte_lock_count)
251 goto out;
252 ic = &vcpu->kvm->arch.sca->ipte_control;
253 do {
254 new = old = ACCESS_ONCE(*ic);
255 new.k = 0;
256 } while (cmpxchg(&ic->val, old.val, new.val) != old.val);
257 if (!ipte_lock_count)
258 wake_up(&vcpu->kvm->arch.ipte_wq);
259out:
260 mutex_unlock(&ipte_mutex);
261}
262
263static void ipte_lock_siif(struct kvm_vcpu *vcpu)
264{
265 union ipte_control old, new, *ic;
266
267 ic = &vcpu->kvm->arch.sca->ipte_control;
268 do {
269 old = ACCESS_ONCE(*ic);
270 while (old.kg) {
271 cond_resched();
272 old = ACCESS_ONCE(*ic);
273 }
274 new = old;
275 new.k = 1;
276 new.kh++;
277 } while (cmpxchg(&ic->val, old.val, new.val) != old.val);
278}
279
280static void ipte_unlock_siif(struct kvm_vcpu *vcpu)
281{
282 union ipte_control old, new, *ic;
283
284 ic = &vcpu->kvm->arch.sca->ipte_control;
285 do {
286 new = old = ACCESS_ONCE(*ic);
287 new.kh--;
288 if (!new.kh)
289 new.k = 0;
290 } while (cmpxchg(&ic->val, old.val, new.val) != old.val);
291 if (!new.kh)
292 wake_up(&vcpu->kvm->arch.ipte_wq);
293}
294
295static void ipte_lock(struct kvm_vcpu *vcpu)
296{
297 if (vcpu->arch.sie_block->eca & 1)
298 ipte_lock_siif(vcpu);
299 else
300 ipte_lock_simple(vcpu);
301}
302
303static void ipte_unlock(struct kvm_vcpu *vcpu)
304{
305 if (vcpu->arch.sie_block->eca & 1)
306 ipte_unlock_siif(vcpu);
307 else
308 ipte_unlock_simple(vcpu);
309}
310
210static unsigned long get_vcpu_asce(struct kvm_vcpu *vcpu) 311static unsigned long get_vcpu_asce(struct kvm_vcpu *vcpu)
211{ 312{
212 switch (psw_bits(vcpu->arch.sie_block->gpsw).as) { 313 switch (psw_bits(vcpu->arch.sie_block->gpsw).as) {
@@ -485,6 +586,8 @@ int access_guest(struct kvm_vcpu *vcpu, unsigned long ga, void *data,
485 unsigned long _len, nr_pages, gpa, idx; 586 unsigned long _len, nr_pages, gpa, idx;
486 unsigned long pages_array[2]; 587 unsigned long pages_array[2];
487 unsigned long *pages; 588 unsigned long *pages;
589 int need_ipte_lock;
590 union asce asce;
488 int rc; 591 int rc;
489 592
490 if (!len) 593 if (!len)
@@ -498,6 +601,10 @@ int access_guest(struct kvm_vcpu *vcpu, unsigned long ga, void *data,
498 pages = vmalloc(nr_pages * sizeof(unsigned long)); 601 pages = vmalloc(nr_pages * sizeof(unsigned long));
499 if (!pages) 602 if (!pages)
500 return -ENOMEM; 603 return -ENOMEM;
604 asce.val = get_vcpu_asce(vcpu);
605 need_ipte_lock = psw_bits(*psw).t && !asce.r;
606 if (need_ipte_lock)
607 ipte_lock(vcpu);
501 rc = guest_page_range(vcpu, ga, pages, nr_pages, write); 608 rc = guest_page_range(vcpu, ga, pages, nr_pages, write);
502 for (idx = 0; idx < nr_pages && !rc; idx++) { 609 for (idx = 0; idx < nr_pages && !rc; idx++) {
503 gpa = *(pages + idx) + (ga & ~PAGE_MASK); 610 gpa = *(pages + idx) + (ga & ~PAGE_MASK);
@@ -510,6 +617,8 @@ int access_guest(struct kvm_vcpu *vcpu, unsigned long ga, void *data,
510 ga += _len; 617 ga += _len;
511 data += _len; 618 data += _len;
512 } 619 }
620 if (need_ipte_lock)
621 ipte_unlock(vcpu);
513 if (nr_pages > ARRAY_SIZE(pages_array)) 622 if (nr_pages > ARRAY_SIZE(pages_array))
514 vfree(pages); 623 vfree(pages);
515 return rc; 624 return rc;
diff --git a/arch/s390/kvm/gaccess.h b/arch/s390/kvm/gaccess.h
index 21ee62cd948e..f46e764c5b43 100644
--- a/arch/s390/kvm/gaccess.h
+++ b/arch/s390/kvm/gaccess.h
@@ -397,4 +397,6 @@ int read_guest_real(struct kvm_vcpu *vcpu, unsigned long gra, void *data,
397 return access_guest_real(vcpu, gra, data, len, 0); 397 return access_guest_real(vcpu, gra, data, len, 0);
398} 398}
399 399
400int ipte_lock_held(struct kvm_vcpu *vcpu);
401
400#endif /* __KVM_S390_GACCESS_H */ 402#endif /* __KVM_S390_GACCESS_H */
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 927ba7361da9..e1dfe2461d4b 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -67,6 +67,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
67 { "instruction_stpx", VCPU_STAT(instruction_stpx) }, 67 { "instruction_stpx", VCPU_STAT(instruction_stpx) },
68 { "instruction_stap", VCPU_STAT(instruction_stap) }, 68 { "instruction_stap", VCPU_STAT(instruction_stap) },
69 { "instruction_storage_key", VCPU_STAT(instruction_storage_key) }, 69 { "instruction_storage_key", VCPU_STAT(instruction_storage_key) },
70 { "instruction_ipte_interlock", VCPU_STAT(instruction_ipte_interlock) },
70 { "instruction_stsch", VCPU_STAT(instruction_stsch) }, 71 { "instruction_stsch", VCPU_STAT(instruction_stsch) },
71 { "instruction_chsc", VCPU_STAT(instruction_chsc) }, 72 { "instruction_chsc", VCPU_STAT(instruction_chsc) },
72 { "instruction_essa", VCPU_STAT(instruction_essa) }, 73 { "instruction_essa", VCPU_STAT(instruction_essa) },
@@ -437,6 +438,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
437 438
438 spin_lock_init(&kvm->arch.float_int.lock); 439 spin_lock_init(&kvm->arch.float_int.lock);
439 INIT_LIST_HEAD(&kvm->arch.float_int.list); 440 INIT_LIST_HEAD(&kvm->arch.float_int.list);
441 init_waitqueue_head(&kvm->arch.ipte_wq);
440 442
441 debug_register_view(kvm->arch.dbf, &debug_sprintf_view); 443 debug_register_view(kvm->arch.dbf, &debug_sprintf_view);
442 VM_EVENT(kvm, 3, "%s", "vm created"); 444 VM_EVENT(kvm, 3, "%s", "vm created");
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 9a04d74c5fb4..4792f1df921a 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -173,6 +173,19 @@ static int handle_skey(struct kvm_vcpu *vcpu)
173 return 0; 173 return 0;
174} 174}
175 175
176static int handle_ipte_interlock(struct kvm_vcpu *vcpu)
177{
178 psw_t *psw = &vcpu->arch.sie_block->gpsw;
179
180 vcpu->stat.instruction_ipte_interlock++;
181 if (psw_bits(*psw).p)
182 return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
183 wait_event(vcpu->kvm->arch.ipte_wq, !ipte_lock_held(vcpu));
184 psw->addr = __rewind_psw(*psw, 4);
185 VCPU_EVENT(vcpu, 4, "%s", "retrying ipte interlock operation");
186 return 0;
187}
188
176static int handle_test_block(struct kvm_vcpu *vcpu) 189static int handle_test_block(struct kvm_vcpu *vcpu)
177{ 190{
178 unsigned long hva; 191 unsigned long hva;
@@ -509,6 +522,7 @@ static const intercept_handler_t b2_handlers[256] = {
509 [0x10] = handle_set_prefix, 522 [0x10] = handle_set_prefix,
510 [0x11] = handle_store_prefix, 523 [0x11] = handle_store_prefix,
511 [0x12] = handle_store_cpu_address, 524 [0x12] = handle_store_cpu_address,
525 [0x21] = handle_ipte_interlock,
512 [0x29] = handle_skey, 526 [0x29] = handle_skey,
513 [0x2a] = handle_skey, 527 [0x2a] = handle_skey,
514 [0x2b] = handle_skey, 528 [0x2b] = handle_skey,
@@ -526,6 +540,7 @@ static const intercept_handler_t b2_handlers[256] = {
526 [0x3a] = handle_io_inst, 540 [0x3a] = handle_io_inst,
527 [0x3b] = handle_io_inst, 541 [0x3b] = handle_io_inst,
528 [0x3c] = handle_io_inst, 542 [0x3c] = handle_io_inst,
543 [0x50] = handle_ipte_interlock,
529 [0x5f] = handle_io_inst, 544 [0x5f] = handle_io_inst,
530 [0x74] = handle_io_inst, 545 [0x74] = handle_io_inst,
531 [0x76] = handle_io_inst, 546 [0x76] = handle_io_inst,
@@ -686,7 +701,10 @@ static int handle_essa(struct kvm_vcpu *vcpu)
686} 701}
687 702
688static const intercept_handler_t b9_handlers[256] = { 703static const intercept_handler_t b9_handlers[256] = {
704 [0x8a] = handle_ipte_interlock,
689 [0x8d] = handle_epsw, 705 [0x8d] = handle_epsw,
706 [0x8e] = handle_ipte_interlock,
707 [0x8f] = handle_ipte_interlock,
690 [0xab] = handle_essa, 708 [0xab] = handle_essa,
691 [0xaf] = handle_pfmf, 709 [0xaf] = handle_pfmf,
692}; 710};