Normally TCE request coming from the guest are routed to QEMU by the host kernel. Since this way slows DMA operations, the host kernel may support a real mode acceleration.
In order to use it, the host kernel supports new KVM_CAP_SPAPR_TCE_IOMMU capability and KVM_CREATE_SPAPR_TCE_IOMMU ioctl which lets QEMU tell the host what LIOBN is used for an IOMMU group. Signed-off-by: Alexey Kardashevskiy <a...@ozlabs.ru> --- linux-headers/asm-powerpc/kvm.h | 8 ++++++++ linux-headers/linux/kvm.h | 2 ++ target-ppc/kvm.c | 24 ++++++++++++++++++++++++ target-ppc/kvm_ppc.h | 1 + 4 files changed, 35 insertions(+) diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index 3c1bfb3..d53c8f2 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/linux-headers/asm-powerpc/kvm.h @@ -291,6 +291,14 @@ struct kvm_create_spapr_tce { __u32 window_size; }; +/* for KVM_CAP_SPAPR_TCE_IOMMU */ +struct kvm_create_spapr_tce_iommu { + __u64 liobn; + __u32 iommu_id; +#define SPAPR_TCE_PUT_TCE_VIRTMODE_ONLY 1 /* for debug purposes */ + __u32 flags; +}; + /* for KVM_ALLOCATE_RMA */ struct kvm_allocate_rma { __u64 rma_size; diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 8aff3b0..a665fc7 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -634,6 +634,7 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_SPAPR_XICS 85 #define KVM_CAP_PPC_HTAB_FD 86 #define KVM_CAP_PPC_MULTITCE 87 +#define KVM_CAP_SPAPR_TCE_IOMMU 88 #ifdef KVM_CAP_IRQ_ROUTING @@ -883,6 +884,7 @@ struct kvm_s390_ucas_mapping { #endif #define KVM_IRQCHIP_GET_SOURCES _IOW(KVMIO, 0xad, struct kvm_irq_sources) #define KVM_IRQCHIP_SET_SOURCES _IOW(KVMIO, 0xae, struct kvm_irq_sources) +#define KVM_CREATE_SPAPR_TCE_IOMMU _IOW(KVMIO, 0xaf, struct kvm_create_spapr_tce_iommu) /* * ioctls for vcpu fds diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 11c2689..3cfa770 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -60,6 +60,7 @@ static int cap_booke_sregs; static int cap_ppc_smt; static int cap_ppc_rma; static int cap_spapr_tce; +static int cap_spapr_tce_iommu; static int cap_one_reg; static int cap_htab_fd; @@ -90,6 +91,7 @@ int kvm_arch_init(KVMState *s) cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT); cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA); cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); + cap_spapr_tce_iommu = kvm_check_extension(s, KVM_CAP_SPAPR_TCE_IOMMU); /* This capability is misnamed - it was introduced with the * KVM_SET_ONE_REG ioctl(), which at the time only supported the * HIOR. We don't want a different capability for every register @@ -1478,6 +1480,28 @@ int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size) return 0; } +int kvmppc_create_spapr_tce_iommu(uint32_t liobn, uint32_t iommu_id) +{ + int ret = 0; + struct kvm_create_spapr_tce_iommu args = { + .liobn = liobn, + .iommu_id = iommu_id, + /* .flags = SPAPR_TCE_PUT_TCE_VIRTMODE_ONLY */ + }; + + if (!cap_spapr_tce_iommu) { + fprintf(stderr, "KVM VFIO: TCE IOMMU capability is not present, DMA may be slow\n"); + return -1; + } + + ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_SPAPR_TCE_IOMMU, &args); + if (ret < 0) + fprintf(stderr, "KVM VFIO: Failed to create TCE table for liobn 0x%x, ret = %d, DMA may be slow\n", + liobn, ret); + + return ret; +} + int kvmppc_reset_htab(int shift_hint) { uint32_t shift = shift_hint; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 63a438a..225a173 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -29,6 +29,7 @@ int kvmppc_smt_threads(void); off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd); int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); +int kvmppc_create_spapr_tce_iommu(uint32_t liobn, uint32_t iommu_id); int kvmppc_reset_htab(int shift_hint); uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift); #endif /* !CONFIG_USER_ONLY */ -- 1.7.10.4