Signed-off-by: Alexey Kardashevskiy <a...@ozlabs.ru>
---

Changes:
v2:
* it does not try to introduce a realmode search function.
Instead, liobn-to-iommu-group lookup is done by VFIO KVM device
in virtual mode and the result (iommu_group pointer) is cached
in kvm_arch so the realmode handlers do not use VFIO KVM device for that.
And the iommu groups get released on KVM termination.

I tried this, seems viable.

Did not I miss anything? Thanks.


---
 arch/powerpc/include/asm/kvm_host.h |  3 ++
 arch/powerpc/kvm/Kconfig            |  1 +
 arch/powerpc/kvm/Makefile           |  3 ++
 include/linux/vfio.h                |  3 ++
 include/uapi/linux/kvm.h            |  1 +
 virt/kvm/vfio.c                     | 74 +++++++++++++++++++++++++++++++++++++
 6 files changed, 85 insertions(+)

diff --git a/arch/powerpc/include/asm/kvm_host.h 
b/arch/powerpc/include/asm/kvm_host.h
index 48dbe8b..e1163d7 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -293,6 +293,9 @@ struct kvm_arch {
 #ifdef CONFIG_KVM_XICS
        struct kvmppc_xics *xics;
 #endif
+#ifdef CONFIG_KVM_VFIO
+       struct kvm_vfio *vfio;
+#endif
 };
 
 /*
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index 61b3535..d1b7f64 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -60,6 +60,7 @@ config KVM_BOOK3S_64
        select KVM_BOOK3S_64_HANDLER
        select KVM
        select SPAPR_TCE_IOMMU
+       select KVM_VFIO
        ---help---
          Support running unmodified book3s_64 and book3s_32 guest kernels
          in virtual machines on book3s_64 host processors.
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index 6646c95..2438d2e 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -87,6 +87,9 @@ kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \
 kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \
        book3s_xics.o
 
+kvm-book3s_64-objs-$(CONFIG_KVM_VFIO) += \
+       $(KVM)/vfio.o \
+
 kvm-book3s_64-module-objs := \
        $(KVM)/kvm_main.o \
        $(KVM)/eventfd.o \
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index 24579a0..681e19b 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -97,4 +97,7 @@ extern struct vfio_group *vfio_group_get_external_user(struct 
file *filep);
 extern void vfio_group_put_external_user(struct vfio_group *group);
 extern int vfio_external_user_iommu_id(struct vfio_group *group);
 
+extern struct iommu_group *vfio_find_group_by_liobn(struct kvm *kvm,
+               unsigned long liobn);
+
 #endif /* VFIO_H */
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 7c1a349..a74ad16 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -847,6 +847,7 @@ struct kvm_device_attr {
 #define  KVM_DEV_VFIO_GROUP                    1
 #define   KVM_DEV_VFIO_GROUP_ADD                       1
 #define   KVM_DEV_VFIO_GROUP_DEL                       2
+#define  KVM_DEV_VFIO_SPAPR_TCE_LIOBN          2
 
 /*
  * ioctls for VM fds
diff --git a/virt/kvm/vfio.c b/virt/kvm/vfio.c
index ca4260e..f9271d5 100644
--- a/virt/kvm/vfio.c
+++ b/virt/kvm/vfio.c
@@ -22,6 +22,9 @@
 struct kvm_vfio_group {
        struct list_head node;
        struct vfio_group *vfio_group;
+#ifdef CONFIG_SPAPR_TCE_IOMMU
+       uint64_t liobn;
+#endif
 };
 
 struct kvm_vfio {
@@ -188,12 +191,76 @@ static int kvm_vfio_set_group(struct kvm_device *dev, 
long attr, u64 arg)
        return -ENXIO;
 }
 
+#ifdef CONFIG_SPAPR_TCE_IOMMU
+static int kvm_vfio_set_spapr_tce_liobn(struct kvm_device *dev,
+               long attr, u64 arg)
+{
+       struct kvm_vfio *kv = dev->private;
+       struct vfio_group *vfio_group;
+       struct kvm_vfio_group *kvg;
+       void __user *argp = (void __user *)arg;
+       struct fd f;
+       int32_t fd;
+       uint64_t liobn = attr;
+
+       if (get_user(fd, (int32_t __user *)argp))
+               return -EFAULT;
+
+       f = fdget(fd);
+       if (!f.file)
+               return -EBADF;
+
+       vfio_group = kvm_vfio_group_get_external_user(f.file);
+       fdput(f);
+
+       list_for_each_entry(kvg, &kv->group_list, node) {
+               if (kvg->vfio_group == vfio_group) {
+                       WARN_ON(kvg->liobn);
+                       kvg->liobn = liobn;
+                       kvm_vfio_group_put_external_user(vfio_group);
+                       return 0;
+               }
+       }
+
+       kvm_vfio_group_put_external_user(vfio_group);
+
+       return -ENXIO;
+}
+
+struct iommu_group *vfio_find_group_by_liobn(struct kvm *kvm,
+               unsigned long liobn)
+{
+       struct kvm_vfio_group *kvg;
+
+       if (!kvm->arch.vfio)
+               return NULL;
+
+       list_for_each_entry(kvg, &kvm->arch.vfio->group_list, node) {
+               if (kvg->liobn == liobn) {
+                       int group_id = vfio_external_user_iommu_id(
+                                       kvg->vfio_group);
+                       struct iommu_group *grp =
+                                       iommu_group_get_by_id(group_id);
+                       return grp;
+               }
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(vfio_find_group_by_liobn);
+#endif
+
 static int kvm_vfio_set_attr(struct kvm_device *dev,
                             struct kvm_device_attr *attr)
 {
        switch (attr->group) {
        case KVM_DEV_VFIO_GROUP:
                return kvm_vfio_set_group(dev, attr->attr, attr->addr);
+#ifdef CONFIG_SPAPR_TCE_IOMMU
+       case KVM_DEV_VFIO_SPAPR_TCE_LIOBN:
+               return kvm_vfio_set_spapr_tce_liobn(dev, attr->attr,
+                               attr->addr);
+#endif
        }
 
        return -ENXIO;
@@ -211,6 +278,10 @@ static int kvm_vfio_has_attr(struct kvm_device *dev,
                }
 
                break;
+#ifdef CONFIG_SPAPR_TCE_IOMMU
+       case KVM_DEV_VFIO_SPAPR_TCE_LIOBN:
+               return 0;
+#endif
        }
 
        return -ENXIO;
@@ -251,6 +322,9 @@ static int kvm_vfio_create(struct kvm_device *dev, u32 type)
        mutex_init(&kv->lock);
 
        dev->private = kv;
+#ifdef CONFIG_SPAPR_TCE_IOMMU
+       dev->kvm->arch.vfio = kv;
+#endif
 
        return 0;
 }
-- 
1.8.4.rc4

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to