diff options
author | David Hildenbrand <dahi@linux.vnet.ibm.com> | 2014-03-14 06:00:21 -0400 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2014-04-29 09:01:54 -0400 |
commit | 8ad357551797b1edc184fb9f6a4f80a6fa626459 (patch) | |
tree | 3700cdc96803f5be483cd79453b240c73b522f3a /arch/s390/kvm/kvm-s390.c | |
parent | 6852d7b69b4949234c3a8ae1f279f6a4c6563662 (diff) |
KVM: s390: enable IBS for single running VCPUs
This patch enables the IBS facility when a single VCPU is running.
The facility is dynamically turned on/off as soon as other VCPUs
enter/leave the stopped state.
When this facility is operating, some instructions can be executed
faster for single-cpu guests.
Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Reviewed-by: Dominik Dingel <dingel@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Diffstat (limited to 'arch/s390/kvm/kvm-s390.c')
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 123 |
1 files changed, 121 insertions, 2 deletions
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, |