diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index f621cd6..2039767 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2127,6 +2127,34 @@ written, then `n_invalid' invalid entries, invalidating any previously
 valid entries found.
 
 
+4.79 KVM_CREATE_SPAPR_TCE_IOMMU
+
+Capability: KVM_CAP_SPAPR_TCE_IOMMU
+Architectures: powerpc
+Type: vm ioctl
+Parameters: struct kvm_create_spapr_tce_iommu (in)
+Returns: 0 on success, -1 on error
+
+This creates a link between IOMMU group and a hardware TCE (translation
+control entry) table. This link lets the host kernel know what IOMMU
+group (i.e. TCE table) to use for the LIOBN number passed with
+H_PUT_TCE, H_PUT_TCE_INDIRECT, H_STUFF_TCE hypercalls.
+
+/* for KVM_CAP_SPAPR_TCE_IOMMU */
+struct kvm_create_spapr_tce_iommu {
+	__u64 liobn;
+	__u32 iommu_id;
+	__u32 flags;
+};
+
+No flag is supported at the moment.
+
+When the guest issues TCE call on a liobn for which a TCE table has been
+registered, the kernel will handle it in real mode, updating the hardware
+TCE table. TCE table calls for other liobns will cause a vm exit and must
+be handled by userspace.
+
+
 5. The kvm_run structure
 ------------------------
 
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 36ceb0d..2b70cbc 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -178,6 +178,8 @@ struct kvmppc_spapr_tce_table {
 	struct kvm *kvm;
 	u64 liobn;
 	u32 window_size;
+	bool virtmode_only;
+	struct iommu_group *grp;    /* used for IOMMU groups */
 	struct page *pages[0];
 };
 
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index d501246..bdfa140 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -139,6 +139,8 @@ extern void kvmppc_xics_free(struct kvm *kvm);
 
 extern long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
 				struct kvm_create_spapr_tce *args);
+extern long kvm_vm_ioctl_create_spapr_tce_iommu(struct kvm *kvm,
+				struct kvm_create_spapr_tce_iommu *args);
 extern struct kvmppc_spapr_tce_table *kvmppc_find_tce_table(
 		struct kvm_vcpu *vcpu, unsigned long liobn);
 extern long kvmppc_emulated_h_put_tce(struct kvmppc_spapr_tce_table *stt,
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index 681b314..b67d44b 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -291,6 +291,13 @@ 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;
+	__u32 flags;
+};
+
 /* for KVM_ALLOCATE_RMA */
 struct kvm_allocate_rma {
 	__u64 rma_size;
diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c
index 643ac1e..98cf949 100644
--- a/arch/powerpc/kvm/book3s_64_vio.c
+++ b/arch/powerpc/kvm/book3s_64_vio.c
@@ -27,6 +27,9 @@
 #include <linux/hugetlb.h>
 #include <linux/list.h>
 #include <linux/anon_inodes.h>
+#include <linux/pci.h>
+#include <linux/iommu.h>
+#include <linux/module.h>
 
 #include <asm/tlbflush.h>
 #include <asm/kvm_ppc.h>
@@ -38,10 +41,19 @@
 #include <asm/kvm_host.h>
 #include <asm/udbg.h>
 #include <asm/iommu.h>
+#include <asm/tce.h>
+
+#define DRIVER_VERSION	"0.1"
+#define DRIVER_AUTHOR	"Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>"
+#define DRIVER_DESC	"POWERPC KVM driver"
 
 #define TCES_PER_PAGE	(PAGE_SIZE / sizeof(u64))
 #define ERROR_ADDR      (~(unsigned long)0x0)
 
+static bool kvmppc_tce_virt_only = false;
+module_param_named(virt_only, kvmppc_tce_virt_only, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(virt_only, "Disable realmode handling of IOMMU map/unmap");
+
 /*
  * TCE tables handlers.
  */
@@ -58,8 +70,13 @@ static void release_spapr_tce_table(struct kvmppc_spapr_tce_table *stt)
 
 	mutex_lock(&kvm->lock);
 	list_del(&stt->list);
-	for (i = 0; i < kvmppc_stt_npages(stt->window_size); i++)
-		__free_page(stt->pages[i]);
+#ifdef CONFIG_IOMMU_API
+	if (stt->grp) {
+		iommu_group_put(stt->grp);
+	} else
+#endif
+		for (i = 0; i < kvmppc_stt_npages(stt->window_size); i++)
+			__free_page(stt->pages[i]);
 	kfree(stt);
 	mutex_unlock(&kvm->lock);
 
@@ -155,9 +172,127 @@ fail:
 	return ret;
 }
 
+#ifdef CONFIG_IOMMU_API
+static const struct file_operations kvm_spapr_tce_iommu_fops = {
+	.release	= kvm_spapr_tce_release,
+};
+
+long kvm_vm_ioctl_create_spapr_tce_iommu(struct kvm *kvm,
+		struct kvm_create_spapr_tce_iommu *args)
+{
+	struct kvmppc_spapr_tce_table *tt = NULL;
+	struct iommu_group *grp;
+	struct iommu_table *tbl;
+
+	/* Find an IOMMU table for the given ID */
+	grp = iommu_group_get_by_id(args->iommu_id);
+	if (!grp)
+		return -ENXIO;
+
+	tbl = iommu_group_get_iommudata(grp);
+	if (!tbl)
+		return -ENXIO;
+
+	/* Check this LIOBN hasn't been previously allocated */
+	list_for_each_entry(tt, &kvm->arch.spapr_tce_tables, list) {
+		if (tt->liobn == args->liobn)
+			return -EBUSY;
+	}
+
+	tt = kzalloc(sizeof(*tt), GFP_KERNEL);
+	if (!tt)
+		return -ENOMEM;
+
+	tt->liobn = args->liobn;
+	tt->kvm = kvm;
+	tt->virtmode_only = kvmppc_tce_virt_only;
+	tt->grp = grp;
+
+	kvm_get_kvm(kvm);
+
+	mutex_lock(&kvm->lock);
+	list_add(&tt->list, &kvm->arch.spapr_tce_tables);
+
+	mutex_unlock(&kvm->lock);
+
+	pr_debug("LIOBN=%llX hooked to IOMMU %d, flags=%u\n",
+			args->liobn, args->iommu_id, args->flags);
+
+	return anon_inode_getfd("kvm-spapr-tce-iommu",
+			&kvm_spapr_tce_iommu_fops, tt, O_RDWR);
+}
+#else
+long kvm_vm_ioctl_create_spapr_tce_iommu(struct kvm *kvm,
+		struct kvm_create_spapr_tce_iommu *args)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_IOMMU_API */
+
+#ifdef CONFIG_IOMMU_API
 /*
  * Virtual mode handling of IOMMU map/unmap.
  */
+static int clear_tce_virt_mode(struct iommu_table *tbl,
+		unsigned long ioba, unsigned long tce_value,
+		unsigned long npages)
+{
+	int ret;
+	unsigned long entry = ioba >> IOMMU_PAGE_SHIFT;
+
+	ret = iommu_tce_clear_param_check(tbl, ioba, tce_value, npages);
+	if (ret)
+		return ret;
+
+	ret = iommu_clear_tces_and_put_pages(tbl, entry, npages);
+	if (ret < 0)
+		pr_err("iommu_tce: %s failed ioba=%lx, tce_value=%lx ret=%d\n",
+				__func__, ioba, tce_value, ret);
+
+	return ret;
+}
+
+static int put_tce_virt_mode(struct kvmppc_spapr_tce_table *tt,
+		struct iommu_table *tbl,
+		unsigned long ioba, unsigned long tce,
+		pte_t pte, unsigned long pg_size)
+{
+	int ret;
+	unsigned long entry = ioba >> IOMMU_PAGE_SHIFT;
+
+	ret = iommu_tce_put_param_check(tbl, ioba, tce);
+	if (ret)
+		return ret;
+
+	/* System page size case, easy to handle */
+	if (pg_size == PAGE_SIZE)
+		return iommu_put_tce_user_mode(tbl, entry, tce);
+
+	return -EAGAIN;
+}
+
+static pte_t va_to_linux_pte(struct kvm_vcpu *vcpu,
+		unsigned long hva, bool writing, unsigned long *pg_sizep)
+{
+#ifdef CONFIG_KVM_BOOK3S_64_HV
+	/* Find out the page pte and size if requested */
+	pte_t pte;
+	unsigned long pg_size = 0;
+
+	pte = lookup_linux_pte(vcpu->arch.pgdir, hva,
+			writing, &pg_size);
+	if (!pte_present(pte))
+		return 0;
+
+	*pg_sizep = pg_size;
+
+	return pte;
+#else
+	return 0;
+#endif
+}
+#endif /* CONFIG_IOMMU_API */
+
 /* Converts guest physical address into host virtual */
 static unsigned long get_virt_address(struct kvm_vcpu *vcpu,
 		unsigned long gpa)
@@ -188,6 +323,43 @@ long kvmppc_virtmode_h_put_tce(struct kvm_vcpu *vcpu,
 	if (!tt)
 		return H_TOO_HARD;
 
+#ifdef CONFIG_IOMMU_API
+	if (tt->grp) {
+		long ret;
+		struct iommu_table *tbl = iommu_group_get_iommudata(tt->grp);
+
+		/* Return error if the group is being destroyed */
+		if (!tbl)
+			return H_RESCINDED;
+
+		if (tce & (TCE_PCI_READ | TCE_PCI_WRITE)) {
+			unsigned long hpa, pg_size = 0;
+			pte_t pte;
+
+			hpa = get_virt_address(vcpu, tce);
+			if (hpa == ERROR_ADDR)
+				return -EFAULT;
+
+			pte = va_to_linux_pte(vcpu, hpa, tce & TCE_PCI_WRITE,
+					&pg_size);
+			if (!pte)
+				return -EFAULT;
+
+			ret = put_tce_virt_mode(tt, tbl, ioba, hpa,
+					pte, pg_size);
+		} else {
+			ret = clear_tce_virt_mode(tbl, ioba, 0, 1);
+		}
+		iommu_flush_tce(tbl);
+
+		WARN_ON(ret == -EAGAIN);
+		if (ret < 0)
+			return H_PARAMETER;
+
+		return H_SUCCESS;
+	}
+#endif
+
 	/* Emulated IO */
 	return kvmppc_emulated_h_put_tce(tt, ioba, tce);
 }
@@ -213,6 +385,52 @@ long kvmppc_virtmode_h_put_tce_indirect(struct kvm_vcpu *vcpu,
 	if (tces == ERROR_ADDR)
 		return H_TOO_HARD;
 
+#ifdef CONFIG_IOMMU_API
+	if (tt->grp) {
+		long ret = 0;
+		struct iommu_table *tbl = iommu_group_get_iommudata(tt->grp);
+
+		/* Return error if the group is being destroyed */
+		if (!tbl)
+			return H_RESCINDED;
+
+		for (i = 0; i < npages; ++i) {
+			unsigned long hpa, pg_size = 0;
+			pte_t pte = 0;
+			unsigned long tce;
+			unsigned long ptce = tces + i * sizeof(unsigned long);
+
+			if (get_user(tce, (unsigned long __user *)ptce))
+				break;
+
+			hpa = get_virt_address(vcpu, tce);
+			if (hpa == ERROR_ADDR)
+				return -EFAULT;
+
+			pte = va_to_linux_pte(vcpu, hpa,
+					tce & TCE_PCI_WRITE, &pg_size);
+			if (!pte)
+				return -EFAULT;
+
+			ret = put_tce_virt_mode(tt, tbl,
+					ioba + (i << IOMMU_PAGE_SHIFT),
+					hpa, pte, pg_size);
+			if (ret)
+				break;
+		}
+		if (ret)
+			clear_tce_virt_mode(tbl, ioba, 0, i);
+
+		iommu_flush_tce(tbl);
+
+		WARN_ON(ret == -EAGAIN);
+		if (ret < 0)
+			return H_PARAMETER;
+
+		return H_SUCCESS;
+	}
+#endif
+
 	/* Emulated IO */
 	if ((ioba + (npages << IOMMU_PAGE_SHIFT)) > tt->window_size)
 		return H_PARAMETER;
@@ -253,6 +471,26 @@ long kvmppc_virtmode_h_stuff_tce(struct kvm_vcpu *vcpu,
 	if (!tt)
 		return H_TOO_HARD;
 
+#ifdef CONFIG_IOMMU_API
+	if (tt->grp) {
+		long ret;
+		struct iommu_table *tbl = iommu_group_get_iommudata(tt->grp);
+
+		/* Return error if the group is being destroyed */
+		if (!tbl)
+			return H_RESCINDED;
+
+		ret = clear_tce_virt_mode(tbl, ioba,
+				tce_value, npages);
+
+		WARN_ON(ret == -EAGAIN);
+		if (ret < 0)
+			return H_PARAMETER;
+
+		return H_SUCCESS;
+	}
+#endif
+
 	/* Emulated IO */
 	if ((ioba + (npages << IOMMU_PAGE_SHIFT)) > tt->window_size)
 		return H_PARAMETER;
diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c
index 55fdf7a..c5e5905 100644
--- a/arch/powerpc/kvm/book3s_64_vio_hv.c
+++ b/arch/powerpc/kvm/book3s_64_vio_hv.c
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <linux/hugetlb.h>
 #include <linux/list.h>
+#include <linux/iommu.h>
 
 #include <asm/tlbflush.h>
 #include <asm/kvm_ppc.h>
@@ -161,6 +162,85 @@ static unsigned long get_real_address(struct kvm_vcpu *vcpu,
 	return hwaddr;
 }
 
+#ifdef CONFIG_IOMMU_API
+static int clear_tce_real_mode(struct iommu_table *tbl,
+		unsigned long ioba,
+		unsigned long tce_value, unsigned long npages)
+{
+	int ret;
+	unsigned long entry = ioba >> IOMMU_PAGE_SHIFT;
+
+	ret = iommu_tce_clear_param_check(tbl, ioba, tce_value, npages);
+	if (ret)
+		return ret;
+
+	for ( ; npages; --npages, ++entry) {
+		struct page *page;
+		unsigned long oldtce;
+
+		oldtce = iommu_clear_tce(tbl, entry);
+		if (!oldtce)
+			continue;
+
+		page = realmode_pfn_to_page(oldtce >> PAGE_SHIFT);
+		if (!page) {
+			ret = -EAGAIN;
+			break;
+		}
+
+		if (oldtce & TCE_PCI_WRITE)
+			SetPageDirty(page);
+
+		ret = realmode_put_page(page);
+		if (ret)
+			break;
+	}
+	/* if (ret < 0)
+		pr_err("iommu_tce: %s failed ioba=%lx, tce_value=%lx ret=%d\n",
+				__func__, ioba, tce_value, ret); */
+
+	return ret;
+}
+
+static int put_tce_real_mode(struct kvmppc_spapr_tce_table *tt,
+		struct iommu_table *tbl,
+		unsigned long ioba, unsigned long tce,
+		pte_t pte, unsigned long pg_size)
+{
+	int ret;
+	unsigned long entry = ioba >> IOMMU_PAGE_SHIFT;
+	struct page *page = NULL;
+	enum dma_data_direction direction = iommu_tce_direction(tce);
+
+	ret = iommu_tce_put_param_check(tbl, ioba, tce);
+	if (ret)
+		return ret;
+
+	if (pg_size != PAGE_SIZE)
+		return -EAGAIN;
+
+	/* Small page case, find page struct to increment a counter */
+	page = realmode_pfn_to_page(tce >> PAGE_SHIFT);
+	if (!page)
+		return -EAGAIN;
+
+	ret = realmode_get_page(page);
+	if (ret)
+		return ret;
+
+	/* tce_build accepts virtual addresses */
+	ret = iommu_tce_build(tbl, entry, (unsigned long) __va(tce), direction);
+	if (ret)
+		realmode_put_page(page);
+
+	/* if (ret < 0)
+		pr_err("iommu_tce: %s failed ioba=%lx, tce=%lx, ret=%d\n",
+				__func__, ioba, tce, ret); */
+
+	return ret;
+}
+#endif /* CONFIG_IOMMU_API */
+
 long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
 		      unsigned long ioba, unsigned long tce)
 {
@@ -171,6 +251,44 @@ long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
 	if (!tt)
 		return H_TOO_HARD;
 
+	if (tt->virtmode_only)
+		return H_TOO_HARD;
+
+#ifdef CONFIG_IOMMU_API
+	if (tt->grp) {
+		long ret;
+		struct iommu_table *tbl = iommu_group_get_iommudata(tt->grp);
+
+		/* Return error if the group is being destroyed */
+		if (!tbl)
+			return H_RESCINDED;
+
+		if (tce & (TCE_PCI_READ | TCE_PCI_WRITE)) {
+			unsigned long hpa, pg_size = 0;
+			pte_t pte = 0;
+
+			hpa = get_real_address(vcpu, tce, tce & TCE_PCI_WRITE,
+					&pte, &pg_size);
+			if (hpa == ERROR_ADDR)
+				return H_TOO_HARD;
+
+			ret = put_tce_real_mode(tt, tbl, ioba,
+					hpa, pte, pg_size);
+		} else {
+			ret = clear_tce_real_mode(tbl, ioba, 0, 1);
+		}
+		iommu_flush_tce(tbl);
+
+		if (ret == -EAGAIN)
+			return H_TOO_HARD;
+
+		if (ret < 0)
+			return H_PARAMETER;
+
+		return H_SUCCESS;
+	}
+#endif
+
 	/* Emulated IO */
 	return kvmppc_emulated_h_put_tce(tt, ioba, tce);
 }
@@ -192,10 +310,58 @@ long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu,
 	if (!tt)
 		return H_TOO_HARD;
 
+	if (tt->virtmode_only)
+		return H_TOO_HARD;
+
 	tces = get_real_address(vcpu, tce_list, false, NULL, NULL);
 	if (tces == ERROR_ADDR)
 		return H_TOO_HARD;
 
+#ifdef CONFIG_IOMMU_API
+	if (tt->grp) {
+		long ret = 0;
+		struct iommu_table *tbl = iommu_group_get_iommudata(tt->grp);
+
+		/* Return error if the group is being destroyed */
+		if (!tbl)
+			return H_RESCINDED;
+
+		for (i = 0; i < npages; ++i) {
+			unsigned long hpa, pg_size = 0;
+			pte_t pte = 0;
+			unsigned long tce;
+			unsigned long ptce = tces + i * sizeof(unsigned long);
+
+			if (get_user(tce, (unsigned long __user *)ptce))
+				break;
+
+			hpa = get_real_address(vcpu, tce,
+					tce & TCE_PCI_WRITE,
+					&pte, &pg_size);
+			if (hpa == ERROR_ADDR)
+				ret = -EAGAIN;
+			else
+				ret = put_tce_real_mode(tt, tbl,
+						ioba + (i << IOMMU_PAGE_SHIFT),
+						hpa, pte, pg_size);
+			if (ret)
+				break;
+		}
+		if (ret)
+			clear_tce_real_mode(tbl, ioba, 0, i);
+
+		iommu_flush_tce(tbl);
+
+		if (ret == -EAGAIN)
+			return H_TOO_HARD;
+
+		if (ret < 0)
+			return H_PARAMETER;
+
+		return H_SUCCESS;
+	}
+#endif
+
 	/* Emulated IO */
 	if ((ioba + (npages << IOMMU_PAGE_SHIFT)) > tt->window_size)
 		return H_PARAMETER;
@@ -236,6 +402,32 @@ long kvmppc_h_stuff_tce(struct kvm_vcpu *vcpu,
 	if (!tt)
 		return H_TOO_HARD;
 
+	if (tt->virtmode_only)
+		return H_TOO_HARD;
+
+#ifdef CONFIG_IOMMU_API
+	if (tt->grp) {
+		long ret;
+		struct iommu_table *tbl = iommu_group_get_iommudata(tt->grp);
+
+		/* Return error if the group is being destroyed */
+		if (!tbl)
+			return H_RESCINDED;
+
+		ret = clear_tce_real_mode(tbl, ioba,
+				tce_value, npages);
+		iommu_flush_tce(tbl);
+
+		if (ret == -EAGAIN)
+			return H_TOO_HARD;
+
+		if (ret < 0)
+			return H_PARAMETER;
+
+		return H_SUCCESS;
+	}
+#endif
+
 	/* Emulated IO */
 	if ((ioba + (npages << IOMMU_PAGE_SHIFT)) > tt->window_size)
 		return H_PARAMETER;
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index b7ad589..269b0f6 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -385,6 +385,7 @@ int kvm_dev_ioctl_check_extension(long ext)
 		break;
 #endif
 	case KVM_CAP_SPAPR_MULTITCE:
+	case KVM_CAP_SPAPR_TCE_IOMMU:
 		r = 1;
 		break;
 	default:
@@ -935,6 +936,17 @@ long kvm_arch_vm_ioctl(struct file *filp,
 		r = kvm_vm_ioctl_create_spapr_tce(kvm, &create_tce);
 		goto out;
 	}
+	case KVM_CREATE_SPAPR_TCE_IOMMU: {
+		struct kvm_create_spapr_tce_iommu create_tce_iommu;
+		struct kvm *kvm = filp->private_data;
+
+		r = -EFAULT;
+		if (copy_from_user(&create_tce_iommu, argp,
+				sizeof(create_tce_iommu)))
+			goto out;
+		r = kvm_vm_ioctl_create_spapr_tce_iommu(kvm, &create_tce_iommu);
+		goto out;
+	}
 #endif /* CONFIG_PPC_BOOK3S_64 */
 
 #ifdef CONFIG_KVM_BOOK3S_64_HV
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 6c04da1..161e1d3 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -641,6 +641,7 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_PPC_RTAS (0x100000 + 87)
 #define KVM_CAP_SPAPR_XICS (0x100000 + 88)
 #define KVM_CAP_SPAPR_MULTITCE (0x110000 + 89)
+#define KVM_CAP_SPAPR_TCE_IOMMU (0x110000 + 90)
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -885,6 +886,7 @@ struct kvm_s390_ucas_mapping {
 #define KVM_PPC_GET_HTAB_FD	  _IOW(KVMIO,  0xaa, struct kvm_get_htab_fd)
 /* Available with KVM_CAP_PPC_RTAS */
 #define KVM_PPC_RTAS_DEFINE_TOKEN _IOW(KVMIO,  0xdc, struct kvm_rtas_token_args)
+#define KVM_CREATE_SPAPR_TCE_IOMMU _IOW(KVMIO,  0xaf, struct kvm_create_spapr_tce_iommu)
 
 /*
  * ioctls for vcpu fds
