This is necessary for qemu to be able to pass the right information
to the guest, such as the supported page sizes and corresponding
encodings in the SLB and hash table, which can vary depending
on the processor type, the type of KVM used (PR vs HV) and the
version of KVM

Signed-off-by: Benjamin Herrenschmidt <b...@kernel.crashing.org>
---

Alex, can you sync with Avi ASAP on locking the ioctl & capability
numbers ? The patch itself can wait til the next merge window but
at least we want those locked in so we can push the qemu bits.

The qemu patch proper has fallbacks for when the kernel doesn't
support the ioctl (I'll post it separately)

For example I know the ioctl/caps already collide with Paulus other
patches so we need that sorted at Avi level.

 Documentation/virtual/kvm/api.txt  |   70 ++++++++++++++++++++++++++++++++++++
 arch/powerpc/include/asm/kvm_ppc.h |    3 +-
 arch/powerpc/kvm/book3s_hv.c       |   33 +++++++++++++++++
 arch/powerpc/kvm/book3s_pr.c       |   25 +++++++++++++
 arch/powerpc/kvm/powerpc.c         |   18 +++++++++-
 include/linux/kvm.h                |   27 ++++++++++++++
 6 files changed, 174 insertions(+), 2 deletions(-)

diff --git a/Documentation/virtual/kvm/api.txt 
b/Documentation/virtual/kvm/api.txt
index 81ff39f..e48b95d 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1689,6 +1689,76 @@ where the guest will clear the flag: when the soft 
lockup watchdog timer resets
 itself or when a soft lockup is detected.  This ioctl can be called any time
 after pausing the vcpu, but before it is resumed.
 
+4.71 KVM_PPC_GET_SMMU_INFO
+
+Capability: KVM_CAP_PPC_GET_SMMU_INFO
+Architectures: powerpc
+Type: vm ioctl
+Parameters: None
+Returns: 0 on success, -1 on error
+
+This populates and returns a structure describing the features of
+server "Server" class MMU emulation supported by KVM.
+This can in turn be used by userspace to generate the appropariate
+device-tree properties for the guest operating system.
+
+The structure contains some global informations, followed by an
+array of supported segment page sizes:
+
+      struct kvm_ppc_smmu_info {
+            __u64 flags;
+            __u32 slb_size;
+            __u32 pad;
+            struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ];
+      };
+
+The supported flags are:
+
+    - KVM_PPC_PAGE_SIZES_REAL:
+        When that flag is set, guest page sizes must "fit" the backing
+        store page sizes. When not set, any page size in the list can
+        be used regardless of how they are backed by userspace.
+
+    - KVM_PPC_1T_SEGMENTS
+        The emulated MMU supports 1T segments in addition to the
+        standard 256M ones.
+
+The "slb_size" field indicates how many SLB entries are supported
+
+The "sps" array contains 8 entries indicating the supported base
+page sizes for a segment in increasing order. Each entry is defined
+as follow:
+
+   struct kvm_ppc_one_seg_page_size {
+       __u32 page_shift;       /* Base page shift of segment (or 0) */
+       __u32 slb_enc;          /* SLB encoding for BookS */
+       struct kvm_ppc_one_page_size enc[KVM_PPC_PAGE_SIZES_MAX_SZ];
+   };
+
+An entry with a "page_shift" of 0 is unused. Because the array is
+organized in increasing order, a lookup can stop when encoutering
+such an entry.
+
+The "slb_enc" field provides the encoding to use in the SLB for the
+page size. The bits are in positions such as the value can directly
+be OR'ed into the "vsid" argument of the slbmte instruction.
+
+The "enc" array is a list which for each of those segment base page
+size provides the list of supported actual page sizes (which can be
+only larger or equal to the base page size), along with the
+corresponding encoding in the hash PTE. Similarily, the array is
+8 entries sorted by increasing sizes and an entry with a "0" shift
+is an empty entry and a terminator:
+
+   struct kvm_ppc_one_page_size {
+       __u32 page_shift;       /* Page shift (or 0) */
+       __u32 pte_enc;          /* Encoding in the HPTE (>>12) */
+   };
+
+The "pte_enc" field provides a value that can OR'ed into the hash
+PTE's RPN field (ie, it needs to be shifted left by 12 to OR it
+into the hash PTE second double word).
+
 5. The kvm_run structure
 
 Application code obtains a pointer to the kvm_run structure by
diff --git a/arch/powerpc/include/asm/kvm_ppc.h 
b/arch/powerpc/include/asm/kvm_ppc.h
index c1069f6..2a92327 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -140,7 +140,8 @@ extern int kvmppc_core_prepare_memory_region(struct kvm 
*kvm,
                                struct kvm_userspace_memory_region *mem);
 extern void kvmppc_core_commit_memory_region(struct kvm *kvm,
                                struct kvm_userspace_memory_region *mem);
-
+extern int kvm_vm_ioctl_get_smmu_info(struct kvm *kvm,
+                                     struct kvm_ppc_smmu_info *info);
 extern int kvmppc_bookehv_init(void);
 extern void kvmppc_bookehv_exit(void);
 
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 8ee46b9..7c6d267 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -1174,6 +1174,39 @@ long kvm_vm_ioctl_allocate_rma(struct kvm *kvm, struct 
kvm_allocate_rma *ret)
        return fd;
 }
 
+static void kvmppc_add_seg_page_size(struct kvm_ppc_one_seg_page_size **sps,
+                                    int linux_psize)
+{
+       struct mmu_psize_def *def = &mmu_psize_defs[linux_psize];
+
+       if (!def->shift)
+               return;
+       *sps->page_shift = def->shift;
+       *sps->slb_enc = def->sllp;
+       *sps->enc[0].page_shift = def->shift;
+       *sps->enc[0].pte_enc = def->penc;
+       *sps++;
+}
+
+int kvm_vm_ioctl_get_smmu_info(struct kvm *kvm, struct kvm_ppc_smmu_info *info)
+{
+       struct kvm_ppc_one_seg_page_size *sps;
+       int i;
+
+       info->flags = KVM_PPC_PAGE_SIZES_REAL;
+       if (mmu_has_feature(MMU_FTR_1T_SEGMENT))
+               info->flags |= KVM_PPC_1T_SEGMENTS;
+       info->slb_size = mmu_slb_size;
+
+       /* We only support these sizes for now, and no muti-size segments */
+       sps = &sinfo->sps[0];
+       kvmppc_add_seg_page_size(&sps, MMU_PAGE_4K);
+       kvmppc_add_seg_page_size(&sps, MMU_PAGE_64K);
+       kvmppc_add_seg_page_size(&sps, MMU_PAGE_16M);
+
+       return 0;
+}
+
 /*
  * Get (and clear) the dirty memory log for a memory slot.
  */
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index 5f0ee48..70d9ee6 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -1154,6 +1154,31 @@ out:
        return r;
 }
 
+#ifdef CONFIG_PPC64
+int kvm_vm_ioctl_get_smmu_info(struct kvm *kvm, struct kvm_ppc_smmu_info *info)
+{
+       /* No flags */
+       info->flags = 0;
+
+       /* SLB is always 64 entries */
+       info->slb_size = 64;
+
+       /* Standard 4k base page size segment */
+       info->sps[0].page_shift = 12;
+       info->sps[0].slb_enc = 0;
+       info->sps[0].enc[0].page_shift = 12;
+       info->sps[0].enc[0].pte_enc = 0;
+
+       /* Standard 16M large page size segment */
+       info->sps[1].page_shift = 24;
+       info->sps[1].slb_enc = SLB_VSID_L;
+       info->sps[1].enc[0].page_shift = 24;
+       info->sps[1].enc[0].pte_enc = 0;
+
+       return 0;
+}
+#endif /* CONFIG_PPC64 */
+
 int kvmppc_core_prepare_memory_region(struct kvm *kvm,
                                      struct kvm_userspace_memory_region *mem)
 {
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 6ac3115..1493c8d 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -279,6 +279,11 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_MAX_VCPUS:
                r = KVM_MAX_VCPUS;
                break;
+#ifdef CONFIG_PPC_BOOK3S_64
+       case KVM_CAP_PPC_GET_SMMU_INFO:
+               r = 1;
+               break;
+#endif
        default:
                r = 0;
                break;
@@ -718,7 +723,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                break;
        }
 #endif
-
        default:
                r = -EINVAL;
        }
@@ -800,6 +804,18 @@ long kvm_arch_vm_ioctl(struct file *filp,
        }
 #endif /* CONFIG_KVM_BOOK3S_64_HV */
 
+#ifdef CONFIG_PPC_BOOK3S_64
+       case KVM_PPC_GET_SMMU_INFO: {
+               struct kvm *kvm = filp->private_data;
+               struct kvm_ppc_smmu_info info;
+
+               memset(&info, 0, sizeof(info));
+               r = kvm_vm_ioctl_get_smmu_info(kvm, &info);
+               if (r >= 0 && copy_to_user(argp, &info, sizeof(info)))
+                       r = -EFAULT;
+               break;
+       }
+#endif /* CONFIG_PPC_BOOK3S_64 */
        default:
                r = -ENOTTY;
        }
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 7a9dd4b..aa60473 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -449,6 +449,30 @@ struct kvm_ppc_pvinfo {
        __u8  pad[108];
 };
 
+/* for KVM_PPC_GET_SMMU_INFO */
+#define KVM_PPC_PAGE_SIZES_MAX_SZ      8
+
+struct kvm_ppc_one_page_size {
+       __u32 page_shift;       /* Page shift (or 0) */
+       __u32 pte_enc;          /* Encoding in the HPTE (>>12) */
+};
+
+struct kvm_ppc_one_seg_page_size {
+       __u32 page_shift;       /* Base page shift of segment (or 0) */
+       __u32 slb_enc;          /* SLB encoding for BookS */
+       struct kvm_ppc_one_page_size enc[KVM_PPC_PAGE_SIZES_MAX_SZ];
+};
+
+#define KVM_PPC_PAGE_SIZES_REAL                0x00000001
+#define KVM_PPC_1T_SEGMENTS            0x00000002
+
+struct kvm_ppc_smmu_info {
+       __u64 flags;
+       __u32 slb_size;
+       __u32 pad;
+       struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ];
+};
+
 #define KVMIO 0xAE
 
 /* machine type bits, to be used as argument to KVM_CREATE_VM */
@@ -590,6 +614,7 @@ struct kvm_ppc_pvinfo {
 #define KVM_CAP_SYNC_REGS 74
 #define KVM_CAP_PCI_2_3 75
 #define KVM_CAP_KVMCLOCK_CTRL 76
+#define KVM_CAP_PPC_GET_SMMU_INFO 77
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -789,6 +814,8 @@ struct kvm_s390_ucas_mapping {
 /* Available with KVM_CAP_PCI_2_3 */
 #define KVM_ASSIGN_SET_INTX_MASK  _IOW(KVMIO,  0xa4, \
                                       struct kvm_assigned_pci_dev)
+/* Available with KVM_CAP_PPC_GET_SMMU_INFO */
+#define KVM_PPC_GET_SMMU_INFO    _IOR(KVMIO,  0xa5, struct kvm_ppc_smmu_info)
 
 /*
  * ioctls for vcpu fds


--
To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to