aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2014-03-31 14:50:44 -0400
committerMarcelo Tosatti <mtosatti@redhat.com>2014-04-17 13:01:43 -0400
commit68c3b4d1676d870f0453c31d5a52e7e65c7448ae (patch)
tree7e0cc2b79df3a1c772d3aa19ffa879759e3ffe3c
parentf848a5a8dcb655553423f77cc98909a04e64173d (diff)
KVM: VMX: speed up wildcard MMIO EVENTFD
With KVM, MMIO is much slower than PIO, due to the need to do page walk and emulation. But with EPT, it does not have to be: we know the address from the VMCS so if the address is unique, we can look up the eventfd directly, bypassing emulation. Unfortunately, this only works if userspace does not need to match on access length and data. The implementation adds a separate FAST_MMIO bus internally. This serves two purposes: - minimize overhead for old userspace that does not use eventfd with lengtth = 0 - minimize disruption in other code (since we don't know the length, devices on the MMIO bus only get a valid address in write, this way we don't need to touch all devices to teach them to handle an invalid length) At the moment, this optimization only has effect for EPT on x86. It will be possible to speed up MMIO for NPT and MMU using the same idea in the future. With this patch applied, on VMX MMIO EVENTFD is essentially as fast as PIO. I was unable to detect any measureable slowdown to non-eventfd MMIO. Making MMIO faster is important for the upcoming virtio 1.0 which includes an MMIO signalling capability. The idea was suggested by Peter Anvin. Lots of thanks to Gleb for pre-review and suggestions. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r--arch/x86/kvm/vmx.c4
-rw-r--r--include/linux/kvm_host.h1
-rw-r--r--include/uapi/linux/kvm.h1
-rw-r--r--virt/kvm/eventfd.c16
-rw-r--r--virt/kvm/kvm_main.c1
5 files changed, 23 insertions, 0 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 1f68c5831924..eb3f2b1b764c 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -5528,6 +5528,10 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu)
5528 gpa_t gpa; 5528 gpa_t gpa;
5529 5529
5530 gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS); 5530 gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
5531 if (!kvm_io_bus_write(vcpu->kvm, KVM_FAST_MMIO_BUS, gpa, 0, NULL)) {
5532 skip_emulated_instruction(vcpu);
5533 return 1;
5534 }
5531 5535
5532 ret = handle_mmio_page_fault_common(vcpu, gpa, true); 5536 ret = handle_mmio_page_fault_common(vcpu, gpa, true);
5533 if (likely(ret == RET_MMIO_PF_EMULATE)) 5537 if (likely(ret == RET_MMIO_PF_EMULATE))
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 7d21cf9f4380..6c3c2eb96d06 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -163,6 +163,7 @@ enum kvm_bus {
163 KVM_MMIO_BUS, 163 KVM_MMIO_BUS,
164 KVM_PIO_BUS, 164 KVM_PIO_BUS,
165 KVM_VIRTIO_CCW_NOTIFY_BUS, 165 KVM_VIRTIO_CCW_NOTIFY_BUS,
166 KVM_FAST_MMIO_BUS,
166 KVM_NR_BUSES 167 KVM_NR_BUSES
167}; 168};
168 169
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 39098a61f41c..d8a6ce4c2a83 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -515,6 +515,7 @@ enum {
515 kvm_ioeventfd_flag_nr_pio, 515 kvm_ioeventfd_flag_nr_pio,
516 kvm_ioeventfd_flag_nr_deassign, 516 kvm_ioeventfd_flag_nr_deassign,
517 kvm_ioeventfd_flag_nr_virtio_ccw_notify, 517 kvm_ioeventfd_flag_nr_virtio_ccw_notify,
518 kvm_ioeventfd_flag_nr_fast_mmio,
518 kvm_ioeventfd_flag_nr_max, 519 kvm_ioeventfd_flag_nr_max,
519}; 520};
520 521
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c
index 2721996bb9c2..912ec5a95e2c 100644
--- a/virt/kvm/eventfd.c
+++ b/virt/kvm/eventfd.c
@@ -770,6 +770,16 @@ kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
770 if (ret < 0) 770 if (ret < 0)
771 goto unlock_fail; 771 goto unlock_fail;
772 772
773 /* When length is ignored, MMIO is also put on a separate bus, for
774 * faster lookups.
775 */
776 if (!args->len && !(args->flags & KVM_IOEVENTFD_FLAG_PIO)) {
777 ret = kvm_io_bus_register_dev(kvm, KVM_FAST_MMIO_BUS,
778 p->addr, 0, &p->dev);
779 if (ret < 0)
780 goto register_fail;
781 }
782
773 kvm->buses[bus_idx]->ioeventfd_count++; 783 kvm->buses[bus_idx]->ioeventfd_count++;
774 list_add_tail(&p->list, &kvm->ioeventfds); 784 list_add_tail(&p->list, &kvm->ioeventfds);
775 785
@@ -777,6 +787,8 @@ kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
777 787
778 return 0; 788 return 0;
779 789
790register_fail:
791 kvm_io_bus_unregister_dev(kvm, bus_idx, &p->dev);
780unlock_fail: 792unlock_fail:
781 mutex_unlock(&kvm->slots_lock); 793 mutex_unlock(&kvm->slots_lock);
782 794
@@ -816,6 +828,10 @@ kvm_deassign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
816 continue; 828 continue;
817 829
818 kvm_io_bus_unregister_dev(kvm, bus_idx, &p->dev); 830 kvm_io_bus_unregister_dev(kvm, bus_idx, &p->dev);
831 if (!p->length) {
832 kvm_io_bus_unregister_dev(kvm, KVM_FAST_MMIO_BUS,
833 &p->dev);
834 }
819 kvm->buses[bus_idx]->ioeventfd_count--; 835 kvm->buses[bus_idx]->ioeventfd_count--;
820 ioeventfd_release(p); 836 ioeventfd_release(p);
821 ret = 0; 837 ret = 0;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 56baae8c2f56..96456ac888ba 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2922,6 +2922,7 @@ static int __kvm_io_bus_read(struct kvm_io_bus *bus, struct kvm_io_range *range,
2922 2922
2923 return -EOPNOTSUPP; 2923 return -EOPNOTSUPP;
2924} 2924}
2925EXPORT_SYMBOL_GPL(kvm_io_bus_write);
2925 2926
2926/* kvm_io_bus_read - called under kvm->slots_lock */ 2927/* kvm_io_bus_read - called under kvm->slots_lock */
2927int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, 2928int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,