(iommu_tce_check_ioba((stt)->page_shift, (stt)->offset, \
                                (stt)->size, (ioba), (npages)) ?        \
                                H_PARAMETER : H_SUCCESS)
-extern long kvmppc_tce_validate(struct kvmppc_spapr_tce_table *tt,
-               unsigned long tce);
 extern long kvmppc_gpa_to_ua(struct kvm *kvm, unsigned long gpa,
                unsigned long *ua, unsigned long **prmap);
 extern void kvmppc_tce_put(struct kvmppc_spapr_tce_table *tt,
 
        return ret;
 }
 
+static long kvmppc_tce_validate(struct kvmppc_spapr_tce_table *stt,
+               unsigned long tce)
+{
+       unsigned long gpa = tce & ~(TCE_PCI_READ | TCE_PCI_WRITE);
+       enum dma_data_direction dir = iommu_tce_direction(tce);
+       struct kvmppc_spapr_tce_iommu_table *stit;
+       unsigned long ua = 0;
+
+       /* Allow userspace to poison TCE table */
+       if (dir == DMA_NONE)
+               return H_SUCCESS;
+
+       if (iommu_tce_check_gpa(stt->page_shift, gpa))
+               return H_TOO_HARD;
+
+       if (kvmppc_gpa_to_ua(stt->kvm, tce & ~(TCE_PCI_READ | TCE_PCI_WRITE),
+                               &ua, NULL))
+               return H_TOO_HARD;
+
+       list_for_each_entry_rcu(stit, &stt->iommu_tables, next) {
+               unsigned long hpa = 0;
+               struct mm_iommu_table_group_mem_t *mem;
+               long shift = stit->tbl->it_page_shift;
+
+               mem = mm_iommu_lookup(stt->kvm->mm, ua, 1ULL << shift);
+               if (!mem)
+                       return H_TOO_HARD;
+
+               if (mm_iommu_ua_to_hpa(mem, ua, shift, &hpa))
+                       return H_TOO_HARD;
+       }
+
+       return H_SUCCESS;
+}
+
 static void kvmppc_clear_tce(struct iommu_table *tbl, unsigned long entry)
 {
        unsigned long hpa = 0;
 
 }
 EXPORT_SYMBOL_GPL(kvmppc_find_table);
 
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
 /*
  * Validates TCE address.
  * At the moment flags and page mask are validated.
  * to the table and user space is supposed to process them), we can skip
  * checking other things (such as TCE is a guest RAM address or the page
  * was actually allocated).
- *
- * WARNING: This will be called in real-mode on HV KVM and virtual
- *          mode on PR KVM
  */
-long kvmppc_tce_validate(struct kvmppc_spapr_tce_table *stt, unsigned long tce)
+static long kvmppc_rm_tce_validate(struct kvmppc_spapr_tce_table *stt,
+               unsigned long tce)
 {
        unsigned long gpa = tce & ~(TCE_PCI_READ | TCE_PCI_WRITE);
        enum dma_data_direction dir = iommu_tce_direction(tce);
+       struct kvmppc_spapr_tce_iommu_table *stit;
+       unsigned long ua = 0;
 
        /* Allow userspace to poison TCE table */
        if (dir == DMA_NONE)
        if (iommu_tce_check_gpa(stt->page_shift, gpa))
                return H_PARAMETER;
 
+       if (kvmppc_gpa_to_ua(stt->kvm, tce & ~(TCE_PCI_READ | TCE_PCI_WRITE),
+                               &ua, NULL))
+               return H_TOO_HARD;
+
+       list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
+               unsigned long hpa = 0;
+               struct mm_iommu_table_group_mem_t *mem;
+               long shift = stit->tbl->it_page_shift;
+
+               mem = mm_iommu_lookup_rm(stt->kvm->mm, ua, 1ULL << shift);
+               if (!mem)
+                       return H_TOO_HARD;
+
+               if (mm_iommu_ua_to_hpa_rm(mem, ua, shift, &hpa))
+                       return H_TOO_HARD;
+       }
+
        return H_SUCCESS;
 }
-EXPORT_SYMBOL_GPL(kvmppc_tce_validate);
+#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
 
 /* Note on the use of page_address() in real mode,
  *
        if (ret != H_SUCCESS)
                return ret;
 
-       ret = kvmppc_tce_validate(stt, tce);
+       ret = kvmppc_rm_tce_validate(stt, tce);
        if (ret != H_SUCCESS)
                return ret;
 
        for (i = 0; i < npages; ++i) {
                unsigned long tce = be64_to_cpu(((u64 *)tces)[i]);
 
-               ret = kvmppc_tce_validate(stt, tce);
+               ret = kvmppc_rm_tce_validate(stt, tce);
                if (ret != H_SUCCESS)
                        goto unlock_exit;
        }