]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/powerpc/kvm/book3s_64_vio.c
KVM: PPC: Add support for multiple-TCE hcalls
[karo-tx-linux.git] / arch / powerpc / kvm / book3s_64_vio.c
index 1a1e14f8572f98c8dcfb45ba75f6a1e63c5ea3c9..94c8e7e9b58cdfc32cf164a84113515c5daa6a4d 100644 (file)
@@ -14,6 +14,7 @@
  *
  * Copyright 2010 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
  * Copyright 2011 David Gibson, IBM Corporation <dwg@au1.ibm.com>
+ * Copyright 2016 Alexey Kardashevskiy, IBM Corporation <aik@au1.ibm.com>
  */
 
 #include <linux/types.h>
 #include <asm/ppc-opcode.h>
 #include <asm/kvm_host.h>
 #include <asm/udbg.h>
-
-#define TCES_PER_PAGE  (PAGE_SIZE / sizeof(u64))
+#include <asm/iommu.h>
+#include <asm/tce.h>
 
 static unsigned long kvmppc_tce_pages(unsigned long window_size)
 {
-       return ALIGN((window_size >> SPAPR_TCE_SHIFT)
+       return ALIGN((window_size >> IOMMU_PAGE_SHIFT_4K)
                     * sizeof(u64), PAGE_SIZE) / PAGE_SIZE;
 }
 
@@ -203,3 +204,59 @@ fail:
        }
        return ret;
 }
+
+long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu,
+               unsigned long liobn, unsigned long ioba,
+               unsigned long tce_list, unsigned long npages)
+{
+       struct kvmppc_spapr_tce_table *stt;
+       long i, ret = H_SUCCESS, idx;
+       unsigned long entry, ua = 0;
+       u64 __user *tces, tce;
+
+       stt = kvmppc_find_table(vcpu, liobn);
+       if (!stt)
+               return H_TOO_HARD;
+
+       entry = ioba >> IOMMU_PAGE_SHIFT_4K;
+       /*
+        * SPAPR spec says that the maximum size of the list is 512 TCEs
+        * so the whole table fits in 4K page
+        */
+       if (npages > 512)
+               return H_PARAMETER;
+
+       if (tce_list & (SZ_4K - 1))
+               return H_PARAMETER;
+
+       ret = kvmppc_ioba_validate(stt, ioba, npages);
+       if (ret != H_SUCCESS)
+               return ret;
+
+       idx = srcu_read_lock(&vcpu->kvm->srcu);
+       if (kvmppc_gpa_to_ua(vcpu->kvm, tce_list, &ua, NULL)) {
+               ret = H_TOO_HARD;
+               goto unlock_exit;
+       }
+       tces = (u64 __user *) ua;
+
+       for (i = 0; i < npages; ++i) {
+               if (get_user(tce, tces + i)) {
+                       ret = H_TOO_HARD;
+                       goto unlock_exit;
+               }
+               tce = be64_to_cpu(tce);
+
+               ret = kvmppc_tce_validate(stt, tce);
+               if (ret != H_SUCCESS)
+                       goto unlock_exit;
+
+               kvmppc_tce_put(stt, entry + i, tce);
+       }
+
+unlock_exit:
+       srcu_read_unlock(&vcpu->kvm->srcu, idx);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(kvmppc_h_put_tce_indirect);