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


Reply via email to