diff options
-rw-r--r-- | arch/s390/include/asm/kvm_host.h | 2 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 123 | ||||
-rw-r--r-- | arch/s390/kvm/trace-s390.h | 22 | ||||
-rw-r--r-- | include/linux/kvm_host.h | 2 |
4 files changed, 147 insertions, 2 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 0d45f6fe734f..f0a1dc5e5d1f 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h | |||
@@ -72,6 +72,7 @@ struct sca_block { | |||
72 | #define CPUSTAT_ZARCH 0x00000800 | 72 | #define CPUSTAT_ZARCH 0x00000800 |
73 | #define CPUSTAT_MCDS 0x00000100 | 73 | #define CPUSTAT_MCDS 0x00000100 |
74 | #define CPUSTAT_SM 0x00000080 | 74 | #define CPUSTAT_SM 0x00000080 |
75 | #define CPUSTAT_IBS 0x00000040 | ||
75 | #define CPUSTAT_G 0x00000008 | 76 | #define CPUSTAT_G 0x00000008 |
76 | #define CPUSTAT_GED 0x00000004 | 77 | #define CPUSTAT_GED 0x00000004 |
77 | #define CPUSTAT_J 0x00000002 | 78 | #define CPUSTAT_J 0x00000002 |
@@ -411,6 +412,7 @@ struct kvm_arch{ | |||
411 | int use_cmma; | 412 | int use_cmma; |
412 | struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS]; | 413 | struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS]; |
413 | wait_queue_head_t ipte_wq; | 414 | wait_queue_head_t ipte_wq; |
415 | spinlock_t start_stop_lock; | ||
414 | }; | 416 | }; |
415 | 417 | ||
416 | #define KVM_HVA_ERR_BAD (-1UL) | 418 | #define KVM_HVA_ERR_BAD (-1UL) |
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 6c972d229ace..0a01744cbdd9 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -458,6 +458,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) | |||
458 | kvm->arch.css_support = 0; | 458 | kvm->arch.css_support = 0; |
459 | kvm->arch.use_irqchip = 0; | 459 | kvm->arch.use_irqchip = 0; |
460 | 460 | ||
461 | spin_lock_init(&kvm->arch.start_stop_lock); | ||
462 | |||
461 | return 0; | 463 | return 0; |
462 | out_nogmap: | 464 | out_nogmap: |
463 | debug_unregister(kvm->arch.dbf); | 465 | debug_unregister(kvm->arch.dbf); |
@@ -996,8 +998,15 @@ bool kvm_s390_cmma_enabled(struct kvm *kvm) | |||
996 | return true; | 998 | return true; |
997 | } | 999 | } |
998 | 1000 | ||
1001 | static bool ibs_enabled(struct kvm_vcpu *vcpu) | ||
1002 | { | ||
1003 | return atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_IBS; | ||
1004 | } | ||
1005 | |||
999 | static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu) | 1006 | static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu) |
1000 | { | 1007 | { |
1008 | retry: | ||
1009 | s390_vcpu_unblock(vcpu); | ||
1001 | /* | 1010 | /* |
1002 | * We use MMU_RELOAD just to re-arm the ipte notifier for the | 1011 | * We use MMU_RELOAD just to re-arm the ipte notifier for the |
1003 | * guest prefix page. gmap_ipte_notify will wait on the ptl lock. | 1012 | * guest prefix page. gmap_ipte_notify will wait on the ptl lock. |
@@ -1005,15 +1014,34 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu) | |||
1005 | * already finished. We might race against a second unmapper that | 1014 | * already finished. We might race against a second unmapper that |
1006 | * wants to set the blocking bit. Lets just retry the request loop. | 1015 | * wants to set the blocking bit. Lets just retry the request loop. |
1007 | */ | 1016 | */ |
1008 | while (kvm_check_request(KVM_REQ_MMU_RELOAD, vcpu)) { | 1017 | if (kvm_check_request(KVM_REQ_MMU_RELOAD, vcpu)) { |
1009 | int rc; | 1018 | int rc; |
1010 | rc = gmap_ipte_notify(vcpu->arch.gmap, | 1019 | rc = gmap_ipte_notify(vcpu->arch.gmap, |
1011 | vcpu->arch.sie_block->prefix, | 1020 | vcpu->arch.sie_block->prefix, |
1012 | PAGE_SIZE * 2); | 1021 | PAGE_SIZE * 2); |
1013 | if (rc) | 1022 | if (rc) |
1014 | return rc; | 1023 | return rc; |
1015 | s390_vcpu_unblock(vcpu); | 1024 | goto retry; |
1025 | } | ||
1026 | |||
1027 | if (kvm_check_request(KVM_REQ_ENABLE_IBS, vcpu)) { | ||
1028 | if (!ibs_enabled(vcpu)) { | ||
1029 | trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 1); | ||
1030 | atomic_set_mask(CPUSTAT_IBS, | ||
1031 | &vcpu->arch.sie_block->cpuflags); | ||
1032 | } | ||
1033 | goto retry; | ||
1016 | } | 1034 | } |
1035 | |||
1036 | if (kvm_check_request(KVM_REQ_DISABLE_IBS, vcpu)) { | ||
1037 | if (ibs_enabled(vcpu)) { | ||
1038 | trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 0); | ||
1039 | atomic_clear_mask(CPUSTAT_IBS, | ||
1040 | &vcpu->arch.sie_block->cpuflags); | ||
1041 | } | ||
1042 | goto retry; | ||
1043 | } | ||
1044 | |||
1017 | return 0; | 1045 | return 0; |
1018 | } | 1046 | } |
1019 | 1047 | ||
@@ -1362,16 +1390,107 @@ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr) | |||
1362 | return kvm_s390_store_status_unloaded(vcpu, addr); | 1390 | return kvm_s390_store_status_unloaded(vcpu, addr); |
1363 | } | 1391 | } |
1364 | 1392 | ||
1393 | static inline int is_vcpu_stopped(struct kvm_vcpu *vcpu) | ||
1394 | { | ||
1395 | return atomic_read(&(vcpu)->arch.sie_block->cpuflags) & CPUSTAT_STOPPED; | ||
1396 | } | ||
1397 | |||
1398 | static void __disable_ibs_on_vcpu(struct kvm_vcpu *vcpu) | ||
1399 | { | ||
1400 | kvm_check_request(KVM_REQ_ENABLE_IBS, vcpu); | ||
1401 | kvm_make_request(KVM_REQ_DISABLE_IBS, vcpu); | ||
1402 | exit_sie_sync(vcpu); | ||
1403 | } | ||
1404 | |||
1405 | static void __disable_ibs_on_all_vcpus(struct kvm *kvm) | ||
1406 | { | ||
1407 | unsigned int i; | ||
1408 | struct kvm_vcpu *vcpu; | ||
1409 | |||
1410 | kvm_for_each_vcpu(i, vcpu, kvm) { | ||
1411 | __disable_ibs_on_vcpu(vcpu); | ||
1412 | } | ||
1413 | } | ||
1414 | |||
1415 | static void __enable_ibs_on_vcpu(struct kvm_vcpu *vcpu) | ||
1416 | { | ||
1417 | kvm_check_request(KVM_REQ_DISABLE_IBS, vcpu); | ||
1418 | kvm_make_request(KVM_REQ_ENABLE_IBS, vcpu); | ||
1419 | exit_sie_sync(vcpu); | ||
1420 | } | ||
1421 | |||
1365 | void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu) | 1422 | void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu) |
1366 | { | 1423 | { |
1424 | int i, online_vcpus, started_vcpus = 0; | ||
1425 | |||
1426 | if (!is_vcpu_stopped(vcpu)) | ||
1427 | return; | ||
1428 | |||
1367 | trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 1); | 1429 | trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 1); |
1430 | /* Only one cpu at a time may enter/leave the STOPPED state. */ | ||
1431 | spin_lock_bh(&vcpu->kvm->arch.start_stop_lock); | ||
1432 | online_vcpus = atomic_read(&vcpu->kvm->online_vcpus); | ||
1433 | |||
1434 | for (i = 0; i < online_vcpus; i++) { | ||
1435 | if (!is_vcpu_stopped(vcpu->kvm->vcpus[i])) | ||
1436 | started_vcpus++; | ||
1437 | } | ||
1438 | |||
1439 | if (started_vcpus == 0) { | ||
1440 | /* we're the only active VCPU -> speed it up */ | ||
1441 | __enable_ibs_on_vcpu(vcpu); | ||
1442 | } else if (started_vcpus == 1) { | ||
1443 | /* | ||
1444 | * As we are starting a second VCPU, we have to disable | ||
1445 | * the IBS facility on all VCPUs to remove potentially | ||
1446 | * oustanding ENABLE requests. | ||
1447 | */ | ||
1448 | __disable_ibs_on_all_vcpus(vcpu->kvm); | ||
1449 | } | ||
1450 | |||
1368 | atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); | 1451 | atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); |
1452 | /* | ||
1453 | * Another VCPU might have used IBS while we were offline. | ||
1454 | * Let's play safe and flush the VCPU at startup. | ||
1455 | */ | ||
1456 | vcpu->arch.sie_block->ihcpu = 0xffff; | ||
1457 | spin_unlock_bh(&vcpu->kvm->arch.start_stop_lock); | ||
1458 | return; | ||
1369 | } | 1459 | } |
1370 | 1460 | ||
1371 | void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu) | 1461 | void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu) |
1372 | { | 1462 | { |
1463 | int i, online_vcpus, started_vcpus = 0; | ||
1464 | struct kvm_vcpu *started_vcpu = NULL; | ||
1465 | |||
1466 | if (is_vcpu_stopped(vcpu)) | ||
1467 | return; | ||
1468 | |||
1373 | trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 0); | 1469 | trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 0); |
1470 | /* Only one cpu at a time may enter/leave the STOPPED state. */ | ||
1471 | spin_lock_bh(&vcpu->kvm->arch.start_stop_lock); | ||
1472 | online_vcpus = atomic_read(&vcpu->kvm->online_vcpus); | ||
1473 | |||
1374 | atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); | 1474 | atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); |
1475 | __disable_ibs_on_vcpu(vcpu); | ||
1476 | |||
1477 | for (i = 0; i < online_vcpus; i++) { | ||
1478 | if (!is_vcpu_stopped(vcpu->kvm->vcpus[i])) { | ||
1479 | started_vcpus++; | ||
1480 | started_vcpu = vcpu->kvm->vcpus[i]; | ||
1481 | } | ||
1482 | } | ||
1483 | |||
1484 | if (started_vcpus == 1) { | ||
1485 | /* | ||
1486 | * As we only have one VCPU left, we want to enable the | ||
1487 | * IBS facility for that VCPU to speed it up. | ||
1488 | */ | ||
1489 | __enable_ibs_on_vcpu(started_vcpu); | ||
1490 | } | ||
1491 | |||
1492 | spin_unlock_bh(&vcpu->kvm->arch.start_stop_lock); | ||
1493 | return; | ||
1375 | } | 1494 | } |
1376 | 1495 | ||
1377 | static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, | 1496 | static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, |
diff --git a/arch/s390/kvm/trace-s390.h b/arch/s390/kvm/trace-s390.h index 34d4f8af3a1d..647e9d6a4818 100644 --- a/arch/s390/kvm/trace-s390.h +++ b/arch/s390/kvm/trace-s390.h | |||
@@ -244,6 +244,28 @@ TRACE_EVENT(kvm_s390_enable_css, | |||
244 | __entry->kvm) | 244 | __entry->kvm) |
245 | ); | 245 | ); |
246 | 246 | ||
247 | /* | ||
248 | * Trace point for enabling and disabling interlocking-and-broadcasting | ||
249 | * suppression. | ||
250 | */ | ||
251 | TRACE_EVENT(kvm_s390_enable_disable_ibs, | ||
252 | TP_PROTO(unsigned int id, int state), | ||
253 | TP_ARGS(id, state), | ||
254 | |||
255 | TP_STRUCT__entry( | ||
256 | __field(unsigned int, id) | ||
257 | __field(int, state) | ||
258 | ), | ||
259 | |||
260 | TP_fast_assign( | ||
261 | __entry->id = id; | ||
262 | __entry->state = state; | ||
263 | ), | ||
264 | |||
265 | TP_printk("%s ibs on cpu %d", | ||
266 | __entry->state ? "enabling" : "disabling", __entry->id) | ||
267 | ); | ||
268 | |||
247 | 269 | ||
248 | #endif /* _TRACE_KVMS390_H */ | 270 | #endif /* _TRACE_KVMS390_H */ |
249 | 271 | ||
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 820fc2e1d9df..1e125b055327 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -134,6 +134,8 @@ static inline bool is_error_page(struct page *page) | |||
134 | #define KVM_REQ_EPR_EXIT 20 | 134 | #define KVM_REQ_EPR_EXIT 20 |
135 | #define KVM_REQ_SCAN_IOAPIC 21 | 135 | #define KVM_REQ_SCAN_IOAPIC 21 |
136 | #define KVM_REQ_GLOBAL_CLOCK_UPDATE 22 | 136 | #define KVM_REQ_GLOBAL_CLOCK_UPDATE 22 |
137 | #define KVM_REQ_ENABLE_IBS 23 | ||
138 | #define KVM_REQ_DISABLE_IBS 24 | ||
137 | 139 | ||
138 | #define KVM_USERSPACE_IRQ_SOURCE_ID 0 | 140 | #define KVM_USERSPACE_IRQ_SOURCE_ID 0 |
139 | #define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1 | 141 | #define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1 |