MSI-X MMIO support for KVM
Subsystems (4)
v9 cover MSI-X MMIO support for KVM
Sorry for the long delay, just come back from vacation...
Change from v8:
1. Update struct kvm_run to contain MSI-X routing update exit specific information.
2. Fix a mmio_nr counting bug.
Notice this patchset still based on 2.6.37 due to a block bug on assigned device in the upstream now.
Sheng Yang (4):
KVM: Move struct kvm_io_device to kvm_host.h
KVM: Add kvm_io_ext_data to IO handler
KVM: Emulate MSI-X table in kernel
KVM: Add documents for MSI-X MMIO API
Documentation/kvm/api.txt | 58 +++++++++ arch/x86/kvm/Makefile | 2 +- arch/x86/kvm/i8254.c | 6 +- arch/x86/kvm/i8259.c | 3 +- arch/x86/kvm/lapic.c | 3 +- arch/x86/kvm/x86.c | 40 +++++-- include/linux/kvm.h | 28 +++++ include/linux/kvm_host.h | 65 ++++++++++- virt/kvm/assigned-dev.c | 44 +++++++ virt/kvm/coalesced_mmio.c | 3 +- virt/kvm/eventfd.c | 2 +- virt/kvm/ioapic.c | 2 +- virt/kvm/iodev.h | 31 +---- virt/kvm/kvm_main.c | 40 ++++++- virt/kvm/msix_mmio.c | 293 +++++++++++++++++++++++++++++++++++++++++++++ virt/kvm/msix_mmio.h | 25 ++++ 16 files changed, 594 insertions(+), 51 deletions(-) create mode 100644 virt/kvm/msix_mmio.c create mode 100644 virt/kvm/msix_mmio.h
PATCH v9 1/4 KVM: Move struct kvm_io_device to kvm_host.h
Then it can be used by other struct in kvm_host.h
--- include/linux/kvm_host.h | 23 +++++++++++++++++++++++ virt/kvm/iodev.h | 25 +------------------------ 2 files changed, 24 insertions(+), 24 deletions(-)
include/linux/kvm_host.h +23 -0
@@ -98,6 +98,29 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn,int kvm_async_pf_wakeup_all (struct kvm_vcpu *vcpu);#endif +struct kvm_io_device ; + +/** +* kvm_io_device_ops are called under kvm slots_lock. +* read and write handlers return 0 if the transaction has been handled, +* or non-zero to have it passed to the next device. +**/ +struct kvm_io_device_ops { +int (*read)(struct kvm_io_device *this, +gpa_t addr, +int len, +void *val); +int (*write)(struct kvm_io_device *this, +gpa_t addr, +int len, +const void *val); +void (*destructor)(struct kvm_io_device *this); +}; + +struct kvm_io_device { +const struct kvm_io_device_ops *ops; +}; +struct kvm_vcpu {struct kvm *kvm;#ifdef CONFIG_PREEMPT_NOTIFIERS
virt/kvm/iodev.h +1 -24
@@ -17,32 +17,9 @@#define __KVM_IODEV_H__#include <linux/kvm_types.h> +#include <linux/kvm_host.h> #include <asm/errno.h> -struct kvm_io_device ; - -/** -* kvm_io_device_ops are called under kvm slots_lock. -* read and write handlers return 0 if the transaction has been handled, -* or non-zero to have it passed to the next device. -**/ -struct kvm_io_device_ops { -int (*read)(struct kvm_io_device *this, -gpa_t addr, -int len, -void *val); -int (*write)(struct kvm_io_device *this, -gpa_t addr, -int len, -const void *val); -void (*destructor)(struct kvm_io_device *this); -}; - - -struct kvm_io_device { -const struct kvm_io_device_ops *ops; -}; -static inline void kvm_iodevice_init (struct kvm_io_device *dev,const struct kvm_io_device_ops *ops) {
Signature · 1 line
1.7.0.1
PATCH v9 2/4 KVM: Add kvm_io_ext_data to IO handler
In reply to Sheng YangAdd a new parameter to IO writing handler, so that we can transfer information from IO handler to caller.
--- arch/x86/kvm/i8254.c | 6 ++++-- arch/x86/kvm/i8259.c | 3 ++- arch/x86/kvm/lapic.c | 3 ++- arch/x86/kvm/x86.c | 13 ++++++++----- include/linux/kvm_host.h | 12 ++++++++++-- virt/kvm/coalesced_mmio.c | 3 ++- virt/kvm/eventfd.c | 2 +- virt/kvm/ioapic.c | 2 +- virt/kvm/iodev.h | 6 ++++-- virt/kvm/kvm_main.c | 4 ++-- 10 files changed, 36 insertions(+), 18 deletions(-)
arch/x86/kvm/i8254.c +4 -2
@@ -439,7 +439,8 @@ static inline int pit_in_range(gpa_t addr) }static int pit_ioport_write (struct kvm_io_device *this, -gpa_t addr,int len,const void *data) +gpa_t addr,int len,const void *data, +struct kvm_io_ext_data *ext_data) {struct kvm_pit *pit =dev_to_pit (this);struct kvm_kpit_state *pit_state = &pit->pit_state;
@@ -585,7 +586,8 @@ static int pit_ioport_read(struct kvm_io_device *this, }static int speaker_ioport_write (struct kvm_io_device *this, -gpa_t addr,int len,const void *data) +gpa_t addr,int len,const void *data, +struct kvm_io_ext_data *ext_data) {struct kvm_pit *pit =speaker_to_pit (this);struct kvm_kpit_state *pit_state = &pit->pit_state;
arch/x86/kvm/i8259.c +2 -1
@@ -480,7 +480,8 @@ static inline struct kvm_pic *to_pic(struct kvm_io_device *dev) }static int picdev_write (struct kvm_io_device *this, -gpa_t addr,int len,const void *val) +gpa_t addr,int len,const void *val, +struct kvm_io_ext_data *ext_data) {struct kvm_pic *s =to_pic (this);unsigned char data = *(unsigned char *)val;
arch/x86/kvm/lapic.c +2 -1
@@ -836,7 +836,8 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) }static int apic_mmio_write (struct kvm_io_device *this, -gpa_t address,int len,const void *data) +gpa_t address,int len,const void *data, +struct kvm_io_ext_data *ext_data) {struct kvm_lapic *apic =to_lapic (this);unsigned int offset = address - apic->base_address;
arch/x86/kvm/x86.c +8 -5
@@ -3571,13 +3571,14 @@ static void kvm_init_msr_list(void) }static int vcpu_mmio_write (struct kvm_vcpu *vcpu,gpa_t addr,int len, -const void *v) +const void *v,struct kvm_io_ext_data *ext_data) {if (vcpu->arch.apic && - !kvm_iodevice_write (&vcpu->arch.apic->dev, addr, len, v)) + !kvm_iodevice_write (&vcpu->arch.apic->dev, addr, len, v, ext_data))return 0 ; -return kvm_io_bus_write (vcpu->kvm,KVM_MMIO_BUS , addr, len, v); +return kvm_io_bus_write (vcpu->kvm,KVM_MMIO_BUS , + addr, len, v, ext_data); }static int vcpu_mmio_read (struct kvm_vcpu *vcpu,gpa_t addr,int len,void *v)
@@ -3807,6 +3808,7 @@ static int emulator_write_emulated_onepage(unsigned long addr, struct kvm_vcpu *vcpu) {gpa_t gpa; +struct kvm_io_ext_data ext_data; gpa =kvm_mmu_gva_to_gpa_write (vcpu, addr, exception);
@@ -3825,7 +3827,7 @@ mmio:/* * Is this MMIO handled locally? */ -if (!vcpu_mmio_write (vcpu, gpa, bytes, val)) +if (!vcpu_mmio_write (vcpu, gpa, bytes, val, &ext_data))return X86EMUL_CONTINUE ; vcpu->mmio_needed =1 ;
@@ -3940,6 +3942,7 @@ static int kernel_pio(struct kvm_vcpu *vcpu, void *pd) {/* TODO: String I/O for in kernel device */ int r; +struct kvm_io_ext_data ext_data;if (vcpu->arch.pio.in) r = kvm_io_bus_read(vcpu->kvm, KVM_PIO_BUS, vcpu->arch.pio.port,
@@ -3947,7 +3950,7 @@ static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)else r =kvm_io_bus_write (vcpu->kvm,KVM_PIO_BUS , vcpu->arch.pio.port, vcpu->arch.pio.size, - pd); + pd, &ext_data);return r; }
include/linux/kvm_host.h +10 -2
@@ -68,8 +68,15 @@ enum kvm_bus {KVM_NR_BUSES }; +struct kvm_io_ext_data { +int type; +union { +char padding[256 ]; + }; +}; +int kvm_io_bus_write (struct kvm *kvm,enum kvm_bus bus_idx,gpa_t addr, -int len,const void *val); +int len,const void *val,struct kvm_io_ext_data *data);int kvm_io_bus_read (struct kvm *kvm,enum kvm_bus bus_idx,gpa_t addr,int len,void *val); int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx,
@@ -113,7 +120,8 @@ struct kvm_io_device_ops {int (*write)(struct kvm_io_device *this,gpa_t addr,int len, -const void *val); +const void *val, +struct kvm_io_ext_data *data);void (*destructor)(struct kvm_io_device *this); };
virt/kvm/coalesced_mmio.c +2 -1
@@ -59,7 +59,8 @@ static int coalesced_mmio_in_range(struct kvm_coalesced_mmio_dev *dev, }static int coalesced_mmio_write (struct kvm_io_device *this, -gpa_t addr,int len,const void *val) +gpa_t addr,int len,const void *val, +struct kvm_io_ext_data *ext_data) {struct kvm_coalesced_mmio_dev *dev =to_mmio (this);struct kvm_coalesced_mmio_ring *ring = dev->kvm->coalesced_mmio_ring;
virt/kvm/eventfd.c +1 -1
@@ -483,7 +483,7 @@ ioeventfd_in_range(struct _ioeventfd *p, gpa_t addr, int len, const void *val)/* MMIO/PIO writes trigger an event if the addr/val match */ static int ioeventfd_write (struct kvm_io_device *this,gpa_t addr,int len, -const void *val) +const void *val,struct kvm_io_ext_data *ext_data) {struct _ioeventfd *p =to_ioeventfd (this);
virt/kvm/ioapic.c +1 -1
@@ -321,7 +321,7 @@ static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len, }static int ioapic_mmio_write (struct kvm_io_device *this,gpa_t addr,int len, -const void *val) +const void *val,struct kvm_io_ext_data *ext_data) {struct kvm_ioapic *ioapic =to_ioapic (this);u32 data;
virt/kvm/iodev.h +4 -2
@@ -33,9 +33,11 @@ static inline int kvm_iodevice_read(struct kvm_io_device *dev, }static inline int kvm_iodevice_write (struct kvm_io_device *dev, -gpa_t addr,int l,const void *v) +gpa_t addr,int l,const void *v, +struct kvm_io_ext_data *data) { -return dev->ops->write ? dev->ops->write (dev, addr, l, v) : -EOPNOTSUPP ; +return dev->ops->write ? + dev->ops->write (dev, addr, l, v, data) : -EOPNOTSUPP ; }static inline void kvm_iodevice_destructor (struct kvm_io_device *dev)
virt/kvm/kvm_main.c +2 -2
@@ -2221,14 +2221,14 @@ static void kvm_io_bus_destroy(struct kvm_io_bus *bus)/* kvm_io_bus_write - called under kvm->slots_lock */ int kvm_io_bus_write (struct kvm *kvm,enum kvm_bus bus_idx,gpa_t addr, -int len,const void *val) +int len,const void *val,struct kvm_io_ext_data *ext_data) {int i;struct kvm_io_bus *bus; bus =srcu_dereference (kvm->buses[bus_idx], &kvm->srcu);for (i =0 ; i < bus->dev_count; i++) -if (!kvm_iodevice_write (bus->devs[i], addr, len, val)) +if (!kvm_iodevice_write (bus->devs[i], addr, len, val, ext_data))return 0 ;return -EOPNOTSUPP ; }
Signature · 1 line
1.7.0.1
PATCH v9 3/4 KVM: Emulate MSI-X table in kernel
In reply to Sheng YangThen we can support mask bit operation of assigned devices now.
--- arch/x86/kvm/Makefile | 2 +- arch/x86/kvm/x86.c | 29 ++++- include/linux/kvm.h | 28 +++++ include/linux/kvm_host.h | 32 +++++ virt/kvm/assigned-dev.c | 44 +++++++ virt/kvm/kvm_main.c | 38 ++++++- virt/kvm/msix_mmio.c | 293 ++++++++++++++++++++++++++++++++++++++++++++++ virt/kvm/msix_mmio.h | 25 ++++ 8 files changed, 479 insertions(+), 12 deletions(-) create mode 100644 virt/kvm/msix_mmio.c create mode 100644 virt/kvm/msix_mmio.h
arch/x86/kvm/Makefile +1 -1
@@ -7,7 +7,7 @@ CFLAGS_vmx.o := -I. kvm-y += $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \ coalesced_mmio.o irq_comm.o eventfd.o \ - assigned-dev.o) + assigned-dev.o msix_mmio.o) kvm-$(CONFIG_IOMMU_API) += $(addprefix ../../../virt/kvm/, iommu.o) kvm-$(CONFIG_KVM_ASYNC_PF) += $(addprefix ../../../virt/kvm/, async_pf.o)
arch/x86/kvm/x86.c +22 -7
@@ -1966,6 +1966,7 @@ int kvm_dev_ioctl_check_extension(long ext)case KVM_CAP_X86_ROBUST_SINGLESTEP :case KVM_CAP_XSAVE :case KVM_CAP_ASYNC_PF : +case KVM_CAP_MSIX_MMIO : r =1 ;break ;case KVM_CAP_COALESCED_MMIO :
@@ -3809,6 +3810,7 @@ static int emulator_write_emulated_onepage(unsigned long addr, {gpa_t gpa;struct kvm_io_ext_data ext_data; +int r; gpa =kvm_mmu_gva_to_gpa_write (vcpu, addr, exception);
@@ -3824,18 +3826,31 @@ static int emulator_write_emulated_onepage(unsigned long addr, mmio:trace_kvm_mmio (KVM_TRACE_MMIO_WRITE , bytes, gpa, *(u64 *)val); + r =vcpu_mmio_write (vcpu, gpa, bytes, val, &ext_data);/* * Is this MMIO handled locally? */ -if (!vcpu_mmio_write (vcpu, gpa, bytes, val, &ext_data)) +if (!r)return X86EMUL_CONTINUE ; - vcpu->mmio_needed =1 ; - vcpu->run->exit_reason =KVM_EXIT_MMIO ; - vcpu->run->mmio.phys_addr = vcpu->mmio_phys_addr = gpa; - vcpu->run->mmio.len = vcpu->mmio_size = bytes; - vcpu->run->mmio.is_write = vcpu->mmio_is_write =1 ; -memcpy (vcpu->run->mmio.data, val, bytes); +if (r == -ENOTSYNC ) { + vcpu->run->exit_reason =KVM_EXIT_MSIX_ROUTING_UPDATE ; + vcpu->run->msix_routing.dev_id = + ext_data.msix_routing.dev_id; + vcpu->run->msix_routing.type = + ext_data.msix_routing.type; + vcpu->run->msix_routing.entry_idx = + ext_data.msix_routing.entry_idx; + vcpu->run->msix_routing.flags = + ext_data.msix_routing.flags; + }else { + vcpu->mmio_needed =1 ; + vcpu->run->exit_reason =KVM_EXIT_MMIO ; + vcpu->run->mmio.phys_addr = vcpu->mmio_phys_addr = gpa; + vcpu->run->mmio.len = vcpu->mmio_size = bytes; + vcpu->run->mmio.is_write = vcpu->mmio_is_write =1 ; +memcpy (vcpu->run->mmio.data, val, bytes); + }return X86EMUL_CONTINUE ; }
include/linux/kvm.h +28 -0
@@ -161,6 +161,7 @@ struct kvm_pit_config {#define KVM_EXIT_NMI 16#define KVM_EXIT_INTERNAL_ERROR 17#define KVM_EXIT_OSI 18 +#define KVM_EXIT_MSIX_ROUTING_UPDATE 19/* For KVM_EXIT_INTERNAL_ERROR */ #define KVM_INTERNAL_ERROR_EMULATION 1
@@ -264,6 +265,13 @@ struct kvm_run {struct {__u64 gprs[32 ]; } osi; +/* KVM_EXIT_MSIX_ROUTING_UPDATE*/ +struct { +__u32 dev_id; +__u16 type; +__u16 entry_idx; +__u64 flags; + } msix_routing;/* Fix the size of the union. */ char padding[256 ]; };
@@ -541,6 +549,7 @@ struct kvm_ppc_pvinfo {#define KVM_CAP_PPC_GET_PVINFO 57#define KVM_CAP_PPC_IRQ_LEVEL 58#define KVM_CAP_ASYNC_PF 59 +#define KVM_CAP_MSIX_MMIO 60#ifdef KVM_CAP_IRQ_ROUTING
@@ -672,6 +681,9 @@ struct kvm_clock_data {#define KVM_XEN_HVM_CONFIG _IOW(KVMIO, 0x7a, struct kvm_xen_hvm_config)#define KVM_SET_CLOCK _IOW(KVMIO, 0x7b, struct kvm_clock_data)#define KVM_GET_CLOCK _IOR(KVMIO, 0x7c, struct kvm_clock_data) +/* Available with KVM_CAP_MSIX_MMIO */ +#define KVM_REGISTER_MSIX_MMIO _IOW(KVMIO, 0x7d, struct kvm_msix_mmio_user) +#define KVM_UNREGISTER_MSIX_MMIO _IOW(KVMIO, 0x7e, struct kvm_msix_mmio_user)/* Available with KVM_CAP_PIT_STATE2 */ #define KVM_GET_PIT2 _IOR(KVMIO, 0x9f, struct kvm_pit_state2)#define KVM_SET_PIT2 _IOW(KVMIO, 0xa0, struct kvm_pit_state2)
@@ -795,4 +807,20 @@ struct kvm_assigned_msix_entry { __u16 padding[3]; }; +#define KVM_MSIX_MMIO_TYPE_ASSIGNED_DEV (1 << 0) + +#define KVM_MSIX_MMIO_TYPE_BASE_TABLE (1 << 8) + +#define KVM_MSIX_MMIO_TYPE_DEV_MASK 0x00ff +#define KVM_MSIX_MMIO_TYPE_BASE_MASK 0xff00 +struct kvm_msix_mmio_user { +__u32 dev_id; +__u16 type; +__u16 max_entries_nr; +__u64 base_addr; +__u64 base_va; +__u64 flags; +__u64 reserved[4 ]; +}; +#endif /* __LINUX_KVM_H */
include/linux/kvm_host.h +32 -0
@@ -68,9 +68,16 @@ enum kvm_bus { KVM_NR_BUSES }; +#define KVM_IO_EXT_DATA_TYPE_MSIX_ROUTING 1struct kvm_io_ext_data {int type;union { +struct { +u32 dev_id; +u16 type; +u16 entry_idx; +u64 flags; + } msix_routing;char padding[256 ]; }; };
@@ -241,6 +248,27 @@ struct kvm_memslots { KVM_PRIVATE_MEM_SLOTS]; }; +#define KVM_MSIX_MMIO_MAX 32 + +struct kvm_msix_mmio { +u32 dev_id; +u16 type; +u16 max_entries_nr; +u64 flags; +gpa_t table_base_addr; +hva_t table_base_va; +gpa_t pba_base_addr; +hva_t pba_base_va; +}; + +struct kvm_msix_mmio_dev { +struct kvm *kvm; +struct kvm_io_device table_dev; +int mmio_nr; +struct kvm_msix_mmio mmio[KVM_MSIX_MMIO_MAX ]; +struct mutex lock; +}; +struct kvm {spinlock_t mmu_lock;raw_spinlock_t requests_lock;
@@ -289,6 +317,7 @@ struct kvm {long mmu_notifier_count;#endif long tlbs_dirty; +struct kvm_msix_mmio_dev msix_mmio_dev; };/* The guest did something we don't support. */
@@ -561,6 +590,9 @@ void kvm_unregister_irq_ack_notifier(struct kvm *kvm,int kvm_request_irq_source_id (struct kvm *kvm);void kvm_free_irq_source_id (struct kvm *kvm,int irq_source_id); +int kvm_assigned_device_update_msix_mask_bit (struct kvm *kvm, +int assigned_dev_id,int entry,bool mask); +/* For vcpu->arch.iommu_flags */ #define KVM_IOMMU_CACHE_COHERENCY 0x1
virt/kvm/assigned-dev.c +44 -0
65 lines not on this page · raw message
virt/kvm/kvm_main.c +34 -4
@@ -56,6 +56,7 @@#include "coalesced_mmio.h" #include "async_pf.h" +#include "msix_mmio.h" #define CREATE_TRACE_POINTS #include <trace/events/kvm.h>
@@ -509,6 +510,7 @@ static void kvm_destroy_vm(struct kvm *kvm)struct mm_struct *mm = kvm->mm;kvm_arch_sync_events (kvm); +kvm_unregister_msix_mmio_dev (kvm);spin_lock (&kvm_lock);list_del (&kvm->vm_list);spin_unlock (&kvm_lock);
@@ -1877,6 +1879,24 @@ static long kvm_vm_ioctl(struct file *filp,mutex_unlock (&kvm->lock);break ;#endif +case KVM_REGISTER_MSIX_MMIO : { +struct kvm_msix_mmio_user mmio_user; + + r = -EFAULT ; +if (copy_from_user (&mmio_user, argp,sizeof mmio_user)) + goto out; + r =kvm_vm_ioctl_register_msix_mmio (kvm, &mmio_user); +break ; + } +case KVM_UNREGISTER_MSIX_MMIO : { +struct kvm_msix_mmio_user mmio_user; + + r = -EFAULT ; +if (copy_from_user (&mmio_user, argp,sizeof mmio_user)) + goto out; + r =kvm_vm_ioctl_unregister_msix_mmio (kvm, &mmio_user); +break ; + }default : r =kvm_arch_vm_ioctl (filp, ioctl, arg);if (r == -ENOTTY )
@@ -1988,6 +2008,12 @@ static int kvm_dev_ioctl_create_vm(void) return r; }#endif + r =kvm_register_msix_mmio_dev (kvm); +if (r <0 ) { +kvm_put_kvm (kvm); +return r; + } + r =anon_inode_getfd ("kvm-vm" , &kvm_vm_fops, kvm,O_RDWR );if (r <0 )kvm_put_kvm (kvm);
@@ -2223,14 +2249,18 @@ static void kvm_io_bus_destroy(struct kvm_io_bus *bus)int kvm_io_bus_write (struct kvm *kvm,enum kvm_bus bus_idx,gpa_t addr,int len,const void *val,struct kvm_io_ext_data *ext_data) { -int i; +int i, r = -EOPNOTSUPP ;struct kvm_io_bus *bus; bus =srcu_dereference (kvm->buses[bus_idx], &kvm->srcu); -for (i =0 ; i < bus->dev_count; i++) -if (!kvm_iodevice_write (bus->devs[i], addr, len, val, ext_data)) +for (i =0 ; i < bus->dev_count; i++) { + r =kvm_iodevice_write (bus->devs[i], addr, len, val, ext_data); +if (r == -ENOTSYNC ) +break ; +else if (!r)return 0 ; -return -EOPNOTSUPP ; + } +return r; }/* kvm_io_bus_read - called under kvm->slots_lock */
virt/kvm/msix_mmio.c new file +293 -0
293 lines not on this page · raw message
virt/kvm/msix_mmio.h new file +25 -0
@@ -0,0 +1,25 @@ +#ifndef __KVM_MSIX_MMIO_H__ +#define __KVM_MSIX_MMIO_H__ +/* +* MSI-X MMIO emulation +* +* Copyright (c) 2010 Intel Corporation +* +* This work is licensed under the terms of the GNU GPL, version 2. See +* the COPYING file in the top-level directory. +* +* Author: +* Sheng Yang <[email protected]> +*/ + +#include <linux/pci.h> + +int kvm_register_msix_mmio_dev (struct kvm *kvm); +int kvm_unregister_msix_mmio_dev (struct kvm *kvm); +int kvm_vm_ioctl_register_msix_mmio (struct kvm *kvm, +struct kvm_msix_mmio_user *mmio_user); +int kvm_vm_ioctl_unregister_msix_mmio (struct kvm *kvm, +struct kvm_msix_mmio_user *mmio_user); +int kvm_free_msix_mmio (struct kvm *kvm,struct kvm_msix_mmio *mmio_user); + +#endif
Signature · 1 line
1.7.0.1
PATCH v9 4/4 KVM: Add documents for MSI-X MMIO API
In reply to Sheng Yang--- Documentation/kvm/api.txt | 58 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 58 insertions(+), 0 deletions(-)
Documentation/kvm/api.txt +58 -0
@@ -1263,6 +1263,53 @@ struct kvm_assigned_msix_entry { __u16 padding[3]; }; +4.54 KVM_REGISTER_MSIX_MMIO + +Capability: KVM_CAP_MSIX_MMIO +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_msix_mmio_user (in) +Returns: 0 on success, -1 on error + +This API indicates an MSI-X MMIO address of a guest device. Then all MMIO +operation would be handled by kernel. When necessary(e.g. MSI data/address +changed), KVM would exit to userspace using KVM_EXIT_MSIX_ROUTING_UPDATE to +indicate the MMIO modification and require userspace to update IRQ routing +table. + +NOTICE: Writing the MSI-X MMIO page after it was registered with this API may +be dangerous for userspace program. The writing during VM running may result +in synchronization issue therefore the assigned device can't work properly. +The writing is allowed when VM is not running and can be used as save/restore +mechanism. + +struct kvm_msix_mmio_user { + __u32 dev_id; + __u16 type; /* Device type and MMIO address type */ + __u16 max_entries_nr; /* Maximum entries supported */ + __u64 base_addr; /* Guest physical address of MMIO */ + __u64 base_va; /* Host virtual address of MMIO mapping */ + __u64 flags; /* Reserved for now */ + __u64 reserved[4]; +}; + +Current device type can be: +#define KVM_MSIX_MMIO_TYPE_ASSIGNED_DEV (1 << 0) + +Current MMIO type can be: +#define KVM_MSIX_MMIO_TYPE_BASE_TABLE (1 << 8) + +4.55 KVM_UNREGISTER_MSIX_MMIO + +Capability: KVM_CAP_MSIX_MMIO +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_msix_mmio_user (in) +Returns: 0 on success, -1 on error + +This API would unregister the specific MSI-X MMIO, indicated by dev_id and +type fields of struct kvm_msix_mmio_user. + 5. The kvm_run structure Application code obtains a pointer to the kvm_run structure by
@@ -1445,6 +1492,17 @@ Userspace can now handle the hypercall and when it's done modify the gprs as necessary. Upon guest entry all guest GPRs will then be replaced by the values in this struct. + /* KVM_EXIT_MSIX_ROUTING_UPDATE*/ + struct { + __u32 dev_id; + __u16 type; + __u16 entry_idx; + __u64 flags; + } msix_routing; + +KVM_EXIT_MSIX_ROUTING_UPDATE indicates one MSI-X entry has been modified, and +userspace need to update the correlated routing table. + /* Fix the size of the union. */ char padding[256]; };
Signature · 1 line
1.7.0.1
Quoted 7 lines · Sheng Yang
Sorry for the long delay, just come back from vacation...
Change from v8:
1. Update structkvm_runto contain MSI-X routing update exit specific information.
2. Fix ammio_nrcounting bug.
Quoted 8 lines
Notice this patchset still based on 2.6.37 due to a block bug on assigned device in the upstream now.
Sheng Yang (4):
KVM: Move structkvm_io_devicetokvm_host.h
KVM: Addkvm_io_ext_datato IO handler
KVM: Emulate MSI-X table in kernel
KVM: Add documents for MSI-X MMIO API
Looks good to me.
Quoted 11 lines · Marcelo Tosatti
Quoted 10 lines · Sheng Yang
Sorry for the long delay, just come back from vacation...
Change from v8:
1. Update structkvm_runto contain MSI-X routing update exit specific information.
2. Fix ammio_nrcounting bug.Notice this patchset still based on 2.6.37 due to a block bug on assigned device in the upstream now.
Quoted 7 lines
Quoted 5 lines
Sheng Yang (4):
KVM: Move structkvm_io_devicetokvm_host.h
KVM: Addkvm_io_ext_datato IO handler
KVM: Emulate MSI-X table in kernel
KVM: Add documents for MSI-X MMIO APILooks good to me.
What happened to this series and [1]? Forgotten because Sheng switched his job?
I just realized that MSI-X per-vector masking for assigned devices is not only slow (takes user space exits) but just simply broken (masking bit is not evaluated and applied to the device).
BTW, the same is also true for that optional per-vector masking of legacy MSI. Are there devices in the field that actually support this? I haven't found one so far and tend to consider this feature not worth implementing.
Jan
[1] http://thread.gmane.org/gmane.comp.emulators.kvm.devel/68144
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 18 lines · Jan Kiszka
Quoted 17 lines · Marcelo Tosatti
Quoted 15 lines · Sheng Yang
Sorry for the long delay, just come back from vacation...
Change from v8:
1. Update structkvm_runto contain MSI-X routing update exit specific information.
2. Fix ammio_nrcounting bug.Notice this patchset still based on 2.6.37 due to a block bug on assigned device in the upstream now.
Sheng Yang (4):
KVM: Move structkvm_io_devicetokvm_host.h
KVM: Addkvm_io_ext_datato IO handler
KVM: Emulate MSI-X table in kernel
KVM: Add documents for MSI-X MMIO API
Quoted 4 lines
Quoted 1 line
Looks good to me.
What happened to this series and [1]? Forgotten because Sheng switched his job?
I actually have guilty feelings about it now and then. It's just hard to merge such a complicated change with a non-trivial userspace interface.
Quoted 3 lines
I just realized that MSI-X per-vector masking for assigned devices is not only slow (takes user space exits) but just simply broken (masking bit is not evaluated and applied to the device).
Isn't that just a bug in qemu? Or something else?
Quoted 5 lines
BTW, the same is also true for that optional per-vector masking of legacy MSI. Are there devices in the field that actually support this? I haven't found one so far and tend to consider this feature not worth implementing.
Don't know. I don't like implementing features on the basis of bug reports, though. On the other hand we can't really test it without a real device.
Quoted 5 lines
Jan
[1] http://thread.gmane.org/gmane.comp.emulators.kvm.devel/68144
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 9 lines · Avi Kivity
Quoted 5 lines
BTW, the same is also true for that optional per-vector masking of legacy MSI. Are there devices in the field that actually support this? I haven't found one so far and tend to consider this feature not worth implementing.
Don't know. I don't like implementing features on the basis of bug reports, though. On the other hand we can't really test it without a real device.
Linux will use this capability if present. So
we could add support for an emulated device (e.g. e1000), then test with nested virt once iommu emulation lands :)
Signature · 1 line
MST
Quoted 7 lines · Michael S. Tsirkin
Quoted 6 lines · Avi Kivity
Quoted 5 lines
BTW, the same is also true for that optional per-vector masking of legacy MSI. Are there devices in the field that actually support this? I haven't found one so far and tend to consider this feature not worth implementing.
Quoted 7 lines
Quoted 3 lines
Don't know. I don't like implementing features on the basis of bug reports, though. On the other hand we can't really test it without a real device.
Linux will use this capability if present. So
we could add support for an emulated device (e.g. e1000), then test with nested virt once iommu emulation lands :)
Yeah, would be kind of cool. Still, I would feel better having it tested against a real silicon as well. Also to prove that there is a real need.
So, in case someone stumbles for such a device (bit 8 set in MSI control word), please let us know!
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 16 lines · Jan Kiszka
Quoted 7 lines · Michael S. Tsirkin
Quoted 6 lines · Avi Kivity
Quoted 5 lines
BTW, the same is also true for that optional per-vector masking of legacy MSI. Are there devices in the field that actually support this? I haven't found one so far and tend to consider this feature not worth implementing.
Quoted 7 lines
Quoted 3 lines
Don't know. I don't like implementing features on the basis of bug reports, though. On the other hand we can't really test it without a real device.
Linux will use this capability if present. So
we could add support for an emulated device (e.g. e1000), then test with nested virt once iommu emulation lands :)
Quoted 5 lines
Yeah, would be kind of cool. Still, I would feel better having it tested against a real silicon as well. Also to prove that there is a real need.
So, in case someone stumbles for such a device (bit 8 set in MSI control word), please let us know!
Doesn't any device that supports MSI-X supports per-vector masking?
Quoted 1 line
From the spec:
"MSI and MSI-X each support per-vector masking. Per-vector masking is an optional extension to MSI, and a standard feature with MSI-X"
Signature · 1 line
Sasha.
Quoted 23 lines · Sasha Levin
Quoted 16 lines · Jan Kiszka
Quoted 7 lines · Michael S. Tsirkin
Quoted 6 lines · Avi Kivity
Quoted 5 lines
BTW, the same is also true for that optional per-vector masking of legacy MSI. Are there devices in the field that actually support this? I haven't found one so far and tend to consider this feature not worth implementing.
Quoted 7 lines
Quoted 3 lines
Don't know. I don't like implementing features on the basis of bug reports, though. On the other hand we can't really test it without a real device.
Linux will use this capability if present. So
we could add support for an emulated device (e.g. e1000), then test with nested virt once iommu emulation lands :)Quoted 5 lines
Yeah, would be kind of cool. Still, I would feel better having it tested against a real silicon as well. Also to prove that there is a real need.
So, in case someone stumbles for such a device (bit 8 set in MSI control word), please let us know!
Quoted 6 lines
Doesn't any device that supports MSI-X supports per-vector masking?
Quoted 1 line
From the spec:
"MSI and MSI-X each support per-vector masking. Per-vector masking is an optional extension to MSI, and a standard feature with MSI-X"
Right, but the cap flag still has to be set.
Do you have any MSI-X device in reach?
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 24 lines · Jan Kiszka
Quoted 23 lines · Sasha Levin
Quoted 21 lines · Jan Kiszka
Quoted 7 lines · Michael S. Tsirkin
Quoted 6 lines · Avi Kivity
Quoted 5 lines
BTW, the same is also true for that optional per-vector masking of legacy MSI. Are there devices in the field that actually support this? I haven't found one so far and tend to consider this feature not worth implementing.
Quoted 7 lines
Quoted 3 lines
Don't know. I don't like implementing features on the basis of bug reports, though. On the other hand we can't really test it without a real device.
Linux will use this capability if present. So
we could add support for an emulated device (e.g. e1000), then test with nested virt once iommu emulation lands :)Yeah, would be kind of cool. Still, I would feel better having it tested against a real silicon as well. Also to prove that there is a real need.
So, in case someone stumbles for such a device (bit 8 set in MSI control word), please let us know!
Quoted 9 lines
Quoted 6 lines
Doesn't any device that supports MSI-X supports per-vector masking?
Quoted 1 line
From the spec:
"MSI and MSI-X each support per-vector masking. Per-vector masking is an optional extension to MSI, and a standard feature with MSI-X"
Right, but the cap flag still has to be set.
Are you sure? Take a look at the table in section 6.8.2.3 in the spec (pci v3). Unlike the message control for MSI, this table doesn't mention anything about bit 8 or the per-vector masking capability for MSI-X, it just assumes it's there.
Quoted 1 line
Do you have any MSI-X device in reach?
Don't think so, but I think it would be much easier to find a MSI-X device rather than a MSI with per-vector capability.
Signature · 1 line
Sasha.
Quoted 32 lines · Sasha Levin
Quoted 31 lines · Jan Kiszka
Quoted 29 lines · Sasha Levin
Quoted 16 lines · Jan Kiszka
Quoted 7 lines · Michael S. Tsirkin
Quoted 6 lines · Avi Kivity
Quoted 5 lines
BTW, the same is also true for that optional per-vector masking of legacy MSI. Are there devices in the field that actually support this? I haven't found one so far and tend to consider this feature not worth implementing.
Quoted 7 lines
Quoted 3 lines
Don't know. I don't like implementing features on the basis of bug reports, though. On the other hand we can't really test it without a real device.
Linux will use this capability if present. So
we could add support for an emulated device (e.g. e1000), then test with nested virt once iommu emulation lands :)Quoted 5 lines
Yeah, would be kind of cool. Still, I would feel better having it tested against a real silicon as well. Also to prove that there is a real need.
So, in case someone stumbles for such a device (bit 8 set in MSI control word), please let us know!
Doesn't any device that supports MSI-X supports per-vector masking?
Quoted 1 line
From the spec:
"MSI and MSI-X each support per-vector masking. Per-vector masking is an optional extension to MSI, and a standard feature with MSI-X"
Quoted 7 lines
Quoted 2 lines
Right, but the cap flag still has to be set.
Are you sure? Take a look at the table in section 6.8.2.3 in the spec (pci v3). Unlike the message control for MSI, this table doesn't mention anything about bit 8 or the per-vector masking capability for MSI-X, it just assumes it's there.
[Err, I should stop doing n things in parallel.]
Of course, MSI-X implies per-vector masking, but in a totally different way with different data structures etc. That's not interesting for the case in question: per-vector masking for legacy MSI.
Back to square #1: We need a device with MSI support and cap bit 8 set in its _MSI_ control word.
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 41 lines · Jan Kiszka
Quoted 32 lines · Sasha Levin
Quoted 31 lines · Jan Kiszka
Quoted 29 lines · Sasha Levin
Quoted 16 lines · Jan Kiszka
Quoted 7 lines · Michael S. Tsirkin
Quoted 6 lines · Avi Kivity
Quoted 5 lines
BTW, the same is also true for that optional per-vector masking of legacy MSI. Are there devices in the field that actually support this? I haven't found one so far and tend to consider this feature not worth implementing.
Quoted 7 lines
Quoted 3 lines
Don't know. I don't like implementing features on the basis of bug reports, though. On the other hand we can't really test it without a real device.
Linux will use this capability if present. So
we could add support for an emulated device (e.g. e1000), then test with nested virt once iommu emulation lands :)Quoted 5 lines
Yeah, would be kind of cool. Still, I would feel better having it tested against a real silicon as well. Also to prove that there is a real need.
So, in case someone stumbles for such a device (bit 8 set in MSI control word), please let us know!
Doesn't any device that supports MSI-X supports per-vector masking?
Quoted 1 line
From the spec:
"MSI and MSI-X each support per-vector masking. Per-vector masking is an optional extension to MSI, and a standard feature with MSI-X"
Quoted 7 lines
Quoted 2 lines
Right, but the cap flag still has to be set.
Are you sure? Take a look at the table in section 6.8.2.3 in the spec (pci v3). Unlike the message control for MSI, this table doesn't mention anything about bit 8 or the per-vector masking capability for MSI-X, it just assumes it's there.
Quoted 6 lines
[Err, I should stop doing n things in parallel.]
Of course, MSI-X implies per-vector masking, but in a totally different way with different data structures etc. That's not interesting for the case in question: per-vector masking for legacy MSI.
Ah, Okay.
Quoted 2 lines
Back to square #1: We need a device with MSI support and cap bit 8 set in its _MSI_ control word.
Alright, so I've looked at some of my servers, and one of them has both a bunch of MSI-X devices, and some MSI devices which show this:
Capabilities: [60] MSI: Enable+ Count=1/2 Maskable+ 64bit- Address: 00000020 Data: 0000 Masking: 00000000 Pending: 00000000
Which would suggest that the support per-vector masking, right?
Signature · 1 line
Sasha.
Quoted 11 lines · Sasha Levin
Quoted 2 lines
Back to square #1: We need a device with MSI support and cap bit 8 set in its _MSI_ control word.
Alright, so I've looked at some of my servers, and one of them has both a bunch of MSI-X devices, and some MSI devices which show this:
Capabilities: [60] MSI: Enable+ Count=1/2 Maskable+ 64bit- Address: 00000020 Data: 0000 Masking: 00000000 Pending: 00000000Which would suggest that the support per-vector masking, right?
pciutils has this:
cap = get_conf_word(d, where + PCI_CAP_FLAGS);
later
printf("MSI: Enable%c Count=%d/%d Maskable%c 64bit%c\n",
FLAG(cap, PCI_MSI_FLAGS_ENABLE),
1 << ((cap & PCI_MSI_FLAGS_QSIZE) >> 4),
1 << ((cap & PCI_MSI_FLAGS_QMASK) >> 1),
FLAG(cap, PCI_MSI_FLAGS_MASK_BIT),
FLAG(cap, PCI_MSI_FLAGS_64BIT));and
#define PCI_MSI_FLAGS_MASK_BIT 0x100 /* interrupt masking & reporting supported */
#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */
So yes, that's bit 8 in control word.
Quoted 3 lines
Signature · 1 line
Sasha.
Quoted 19 lines · Avi Kivity
Quoted 18 lines · Jan Kiszka
Quoted 17 lines · Marcelo Tosatti
Quoted 15 lines · Sheng Yang
Sorry for the long delay, just come back from vacation...
Change from v8:
1. Update structkvm_runto contain MSI-X routing update exit specific information.
2. Fix ammio_nrcounting bug.Notice this patchset still based on 2.6.37 due to a block bug on assigned device in the upstream now.
Sheng Yang (4):
KVM: Move structkvm_io_devicetokvm_host.h
KVM: Addkvm_io_ext_datato IO handler
KVM: Emulate MSI-X table in kernel
KVM: Add documents for MSI-X MMIO API
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
Looks good to me.
What happened to this series and [1]? Forgotten because Sheng switched his job?
I actually have guilty feelings about it now and then. It's just hard to merge such a complicated change with a non-trivial userspace interface.
I agree it's tricky. It will surely require rebasing anyway, thus also a proper re-review. I was also wondering (without locking into the dirty details yet) if that interface couldn't be made more generic to allow fast masking for virtio/vhost as well.
Quoted 6 lines
Quoted 4 lines
I just realized that MSI-X per-vector masking for assigned devices is not only slow (takes user space exits) but just simply broken (masking bit is not evaluated and applied to the device).
Isn't that just a bug in qemu? Or something else?
The fact the the per-vectors masks aren't evaluated indicates that it's simply not implemented yet.
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux