xref: /linux/arch/powerpc/kvm/book3s_64_vio.c (revision 8f6a9f0d0604817f7c8d4376fd51718f1bf192ee)
1f31e65e1SBenjamin Herrenschmidt /*
2f31e65e1SBenjamin Herrenschmidt  * This program is free software; you can redistribute it and/or modify
3f31e65e1SBenjamin Herrenschmidt  * it under the terms of the GNU General Public License, version 2, as
4f31e65e1SBenjamin Herrenschmidt  * published by the Free Software Foundation.
5f31e65e1SBenjamin Herrenschmidt  *
6f31e65e1SBenjamin Herrenschmidt  * This program is distributed in the hope that it will be useful,
7f31e65e1SBenjamin Herrenschmidt  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8f31e65e1SBenjamin Herrenschmidt  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9f31e65e1SBenjamin Herrenschmidt  * GNU General Public License for more details.
10f31e65e1SBenjamin Herrenschmidt  *
11f31e65e1SBenjamin Herrenschmidt  * You should have received a copy of the GNU General Public License
12f31e65e1SBenjamin Herrenschmidt  * along with this program; if not, write to the Free Software
13f31e65e1SBenjamin Herrenschmidt  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
14f31e65e1SBenjamin Herrenschmidt  *
15f31e65e1SBenjamin Herrenschmidt  * Copyright 2010 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
16f31e65e1SBenjamin Herrenschmidt  * Copyright 2011 David Gibson, IBM Corporation <dwg@au1.ibm.com>
17d3695aa4SAlexey Kardashevskiy  * Copyright 2016 Alexey Kardashevskiy, IBM Corporation <aik@au1.ibm.com>
18f31e65e1SBenjamin Herrenschmidt  */
19f31e65e1SBenjamin Herrenschmidt 
20f31e65e1SBenjamin Herrenschmidt #include <linux/types.h>
21f31e65e1SBenjamin Herrenschmidt #include <linux/string.h>
22f31e65e1SBenjamin Herrenschmidt #include <linux/kvm.h>
23f31e65e1SBenjamin Herrenschmidt #include <linux/kvm_host.h>
24f31e65e1SBenjamin Herrenschmidt #include <linux/highmem.h>
25f31e65e1SBenjamin Herrenschmidt #include <linux/gfp.h>
26f31e65e1SBenjamin Herrenschmidt #include <linux/slab.h>
273f07c014SIngo Molnar #include <linux/sched/signal.h>
28f31e65e1SBenjamin Herrenschmidt #include <linux/hugetlb.h>
29f31e65e1SBenjamin Herrenschmidt #include <linux/list.h>
30f31e65e1SBenjamin Herrenschmidt #include <linux/anon_inodes.h>
31121f80baSAlexey Kardashevskiy #include <linux/iommu.h>
32121f80baSAlexey Kardashevskiy #include <linux/file.h>
33f31e65e1SBenjamin Herrenschmidt 
34f31e65e1SBenjamin Herrenschmidt #include <asm/tlbflush.h>
35f31e65e1SBenjamin Herrenschmidt #include <asm/kvm_ppc.h>
36f31e65e1SBenjamin Herrenschmidt #include <asm/kvm_book3s.h>
37f64e8084SAneesh Kumar K.V #include <asm/book3s/64/mmu-hash.h>
38f31e65e1SBenjamin Herrenschmidt #include <asm/hvcall.h>
39f31e65e1SBenjamin Herrenschmidt #include <asm/synch.h>
40f31e65e1SBenjamin Herrenschmidt #include <asm/ppc-opcode.h>
41f31e65e1SBenjamin Herrenschmidt #include <asm/kvm_host.h>
42f31e65e1SBenjamin Herrenschmidt #include <asm/udbg.h>
43462ee11eSAlexey Kardashevskiy #include <asm/iommu.h>
44d3695aa4SAlexey Kardashevskiy #include <asm/tce.h>
45121f80baSAlexey Kardashevskiy #include <asm/mmu_context.h>
46f31e65e1SBenjamin Herrenschmidt 
47fe26e527SAlexey Kardashevskiy static unsigned long kvmppc_tce_pages(unsigned long iommu_pages)
48f31e65e1SBenjamin Herrenschmidt {
49fe26e527SAlexey Kardashevskiy 	return ALIGN(iommu_pages * sizeof(u64), PAGE_SIZE) / PAGE_SIZE;
50f31e65e1SBenjamin Herrenschmidt }
51f31e65e1SBenjamin Herrenschmidt 
52f8626985SAlexey Kardashevskiy static unsigned long kvmppc_stt_pages(unsigned long tce_pages)
53f8626985SAlexey Kardashevskiy {
54f8626985SAlexey Kardashevskiy 	unsigned long stt_bytes = sizeof(struct kvmppc_spapr_tce_table) +
55f8626985SAlexey Kardashevskiy 			(tce_pages * sizeof(struct page *));
56f8626985SAlexey Kardashevskiy 
57f8626985SAlexey Kardashevskiy 	return tce_pages + ALIGN(stt_bytes, PAGE_SIZE) / PAGE_SIZE;
58f8626985SAlexey Kardashevskiy }
59f8626985SAlexey Kardashevskiy 
60f8626985SAlexey Kardashevskiy static long kvmppc_account_memlimit(unsigned long stt_pages, bool inc)
61f8626985SAlexey Kardashevskiy {
62f8626985SAlexey Kardashevskiy 	long ret = 0;
63f8626985SAlexey Kardashevskiy 
64f8626985SAlexey Kardashevskiy 	if (!current || !current->mm)
65f8626985SAlexey Kardashevskiy 		return ret; /* process exited */
66f8626985SAlexey Kardashevskiy 
67f8626985SAlexey Kardashevskiy 	down_write(&current->mm->mmap_sem);
68f8626985SAlexey Kardashevskiy 
69f8626985SAlexey Kardashevskiy 	if (inc) {
70f8626985SAlexey Kardashevskiy 		unsigned long locked, lock_limit;
71f8626985SAlexey Kardashevskiy 
72f8626985SAlexey Kardashevskiy 		locked = current->mm->locked_vm + stt_pages;
73f8626985SAlexey Kardashevskiy 		lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
74f8626985SAlexey Kardashevskiy 		if (locked > lock_limit && !capable(CAP_IPC_LOCK))
75f8626985SAlexey Kardashevskiy 			ret = -ENOMEM;
76f8626985SAlexey Kardashevskiy 		else
77f8626985SAlexey Kardashevskiy 			current->mm->locked_vm += stt_pages;
78f8626985SAlexey Kardashevskiy 	} else {
79f8626985SAlexey Kardashevskiy 		if (WARN_ON_ONCE(stt_pages > current->mm->locked_vm))
80f8626985SAlexey Kardashevskiy 			stt_pages = current->mm->locked_vm;
81f8626985SAlexey Kardashevskiy 
82f8626985SAlexey Kardashevskiy 		current->mm->locked_vm -= stt_pages;
83f8626985SAlexey Kardashevskiy 	}
84f8626985SAlexey Kardashevskiy 
85f8626985SAlexey Kardashevskiy 	pr_debug("[%d] RLIMIT_MEMLOCK KVM %c%ld %ld/%ld%s\n", current->pid,
86f8626985SAlexey Kardashevskiy 			inc ? '+' : '-',
87f8626985SAlexey Kardashevskiy 			stt_pages << PAGE_SHIFT,
88f8626985SAlexey Kardashevskiy 			current->mm->locked_vm << PAGE_SHIFT,
89f8626985SAlexey Kardashevskiy 			rlimit(RLIMIT_MEMLOCK),
90f8626985SAlexey Kardashevskiy 			ret ? " - exceeded" : "");
91f8626985SAlexey Kardashevskiy 
92f8626985SAlexey Kardashevskiy 	up_write(&current->mm->mmap_sem);
93f8626985SAlexey Kardashevskiy 
94f8626985SAlexey Kardashevskiy 	return ret;
95f8626985SAlexey Kardashevskiy }
96f8626985SAlexey Kardashevskiy 
97121f80baSAlexey Kardashevskiy static void kvm_spapr_tce_iommu_table_free(struct rcu_head *head)
98121f80baSAlexey Kardashevskiy {
99121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit = container_of(head,
100121f80baSAlexey Kardashevskiy 			struct kvmppc_spapr_tce_iommu_table, rcu);
101121f80baSAlexey Kardashevskiy 
102121f80baSAlexey Kardashevskiy 	iommu_tce_table_put(stit->tbl);
103121f80baSAlexey Kardashevskiy 
104121f80baSAlexey Kardashevskiy 	kfree(stit);
105121f80baSAlexey Kardashevskiy }
106121f80baSAlexey Kardashevskiy 
107121f80baSAlexey Kardashevskiy static void kvm_spapr_tce_liobn_put(struct kref *kref)
108121f80baSAlexey Kardashevskiy {
109121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit = container_of(kref,
110121f80baSAlexey Kardashevskiy 			struct kvmppc_spapr_tce_iommu_table, kref);
111121f80baSAlexey Kardashevskiy 
112121f80baSAlexey Kardashevskiy 	list_del_rcu(&stit->next);
113121f80baSAlexey Kardashevskiy 
114121f80baSAlexey Kardashevskiy 	call_rcu(&stit->rcu, kvm_spapr_tce_iommu_table_free);
115121f80baSAlexey Kardashevskiy }
116121f80baSAlexey Kardashevskiy 
117121f80baSAlexey Kardashevskiy extern void kvm_spapr_tce_release_iommu_group(struct kvm *kvm,
118121f80baSAlexey Kardashevskiy 		struct iommu_group *grp)
119121f80baSAlexey Kardashevskiy {
120121f80baSAlexey Kardashevskiy 	int i;
121121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt;
122121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit, *tmp;
123121f80baSAlexey Kardashevskiy 	struct iommu_table_group *table_group = NULL;
124121f80baSAlexey Kardashevskiy 
125121f80baSAlexey Kardashevskiy 	list_for_each_entry_rcu(stt, &kvm->arch.spapr_tce_tables, list) {
126121f80baSAlexey Kardashevskiy 
127121f80baSAlexey Kardashevskiy 		table_group = iommu_group_get_iommudata(grp);
128121f80baSAlexey Kardashevskiy 		if (WARN_ON(!table_group))
129121f80baSAlexey Kardashevskiy 			continue;
130121f80baSAlexey Kardashevskiy 
131121f80baSAlexey Kardashevskiy 		list_for_each_entry_safe(stit, tmp, &stt->iommu_tables, next) {
132121f80baSAlexey Kardashevskiy 			for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
133121f80baSAlexey Kardashevskiy 				if (table_group->tables[i] != stit->tbl)
134121f80baSAlexey Kardashevskiy 					continue;
135121f80baSAlexey Kardashevskiy 
136121f80baSAlexey Kardashevskiy 				kref_put(&stit->kref, kvm_spapr_tce_liobn_put);
137121f80baSAlexey Kardashevskiy 				return;
138121f80baSAlexey Kardashevskiy 			}
139121f80baSAlexey Kardashevskiy 		}
140121f80baSAlexey Kardashevskiy 	}
141121f80baSAlexey Kardashevskiy }
142121f80baSAlexey Kardashevskiy 
143121f80baSAlexey Kardashevskiy extern long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd,
144121f80baSAlexey Kardashevskiy 		struct iommu_group *grp)
145121f80baSAlexey Kardashevskiy {
146121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt = NULL;
147121f80baSAlexey Kardashevskiy 	bool found = false;
148121f80baSAlexey Kardashevskiy 	struct iommu_table *tbl = NULL;
149121f80baSAlexey Kardashevskiy 	struct iommu_table_group *table_group;
150121f80baSAlexey Kardashevskiy 	long i;
151121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit;
152121f80baSAlexey Kardashevskiy 	struct fd f;
153121f80baSAlexey Kardashevskiy 
154121f80baSAlexey Kardashevskiy 	f = fdget(tablefd);
155121f80baSAlexey Kardashevskiy 	if (!f.file)
156121f80baSAlexey Kardashevskiy 		return -EBADF;
157121f80baSAlexey Kardashevskiy 
158121f80baSAlexey Kardashevskiy 	list_for_each_entry_rcu(stt, &kvm->arch.spapr_tce_tables, list) {
159121f80baSAlexey Kardashevskiy 		if (stt == f.file->private_data) {
160121f80baSAlexey Kardashevskiy 			found = true;
161121f80baSAlexey Kardashevskiy 			break;
162121f80baSAlexey Kardashevskiy 		}
163121f80baSAlexey Kardashevskiy 	}
164121f80baSAlexey Kardashevskiy 
165121f80baSAlexey Kardashevskiy 	fdput(f);
166121f80baSAlexey Kardashevskiy 
167121f80baSAlexey Kardashevskiy 	if (!found)
168121f80baSAlexey Kardashevskiy 		return -EINVAL;
169121f80baSAlexey Kardashevskiy 
170121f80baSAlexey Kardashevskiy 	table_group = iommu_group_get_iommudata(grp);
171121f80baSAlexey Kardashevskiy 	if (WARN_ON(!table_group))
172121f80baSAlexey Kardashevskiy 		return -EFAULT;
173121f80baSAlexey Kardashevskiy 
174121f80baSAlexey Kardashevskiy 	for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
175121f80baSAlexey Kardashevskiy 		struct iommu_table *tbltmp = table_group->tables[i];
176121f80baSAlexey Kardashevskiy 
177121f80baSAlexey Kardashevskiy 		if (!tbltmp)
178121f80baSAlexey Kardashevskiy 			continue;
179121f80baSAlexey Kardashevskiy 		/*
180121f80baSAlexey Kardashevskiy 		 * Make sure hardware table parameters are exactly the same;
181121f80baSAlexey Kardashevskiy 		 * this is used in the TCE handlers where boundary checks
182121f80baSAlexey Kardashevskiy 		 * use only the first attached table.
183121f80baSAlexey Kardashevskiy 		 */
184121f80baSAlexey Kardashevskiy 		if ((tbltmp->it_page_shift == stt->page_shift) &&
185121f80baSAlexey Kardashevskiy 				(tbltmp->it_offset == stt->offset) &&
186121f80baSAlexey Kardashevskiy 				(tbltmp->it_size == stt->size)) {
187121f80baSAlexey Kardashevskiy 			/*
188121f80baSAlexey Kardashevskiy 			 * Reference the table to avoid races with
189121f80baSAlexey Kardashevskiy 			 * add/remove DMA windows.
190121f80baSAlexey Kardashevskiy 			 */
191121f80baSAlexey Kardashevskiy 			tbl = iommu_tce_table_get(tbltmp);
192121f80baSAlexey Kardashevskiy 			break;
193121f80baSAlexey Kardashevskiy 		}
194121f80baSAlexey Kardashevskiy 	}
195121f80baSAlexey Kardashevskiy 	if (!tbl)
196121f80baSAlexey Kardashevskiy 		return -EINVAL;
197121f80baSAlexey Kardashevskiy 
198121f80baSAlexey Kardashevskiy 	list_for_each_entry_rcu(stit, &stt->iommu_tables, next) {
199121f80baSAlexey Kardashevskiy 		if (tbl != stit->tbl)
200121f80baSAlexey Kardashevskiy 			continue;
201121f80baSAlexey Kardashevskiy 
202121f80baSAlexey Kardashevskiy 		if (!kref_get_unless_zero(&stit->kref)) {
203121f80baSAlexey Kardashevskiy 			/* stit is being destroyed */
204121f80baSAlexey Kardashevskiy 			iommu_tce_table_put(tbl);
205121f80baSAlexey Kardashevskiy 			return -ENOTTY;
206121f80baSAlexey Kardashevskiy 		}
207121f80baSAlexey Kardashevskiy 		/*
208121f80baSAlexey Kardashevskiy 		 * The table is already known to this KVM, we just increased
209121f80baSAlexey Kardashevskiy 		 * its KVM reference counter and can return.
210121f80baSAlexey Kardashevskiy 		 */
211121f80baSAlexey Kardashevskiy 		return 0;
212121f80baSAlexey Kardashevskiy 	}
213121f80baSAlexey Kardashevskiy 
214121f80baSAlexey Kardashevskiy 	stit = kzalloc(sizeof(*stit), GFP_KERNEL);
215121f80baSAlexey Kardashevskiy 	if (!stit) {
216121f80baSAlexey Kardashevskiy 		iommu_tce_table_put(tbl);
217121f80baSAlexey Kardashevskiy 		return -ENOMEM;
218121f80baSAlexey Kardashevskiy 	}
219121f80baSAlexey Kardashevskiy 
220121f80baSAlexey Kardashevskiy 	stit->tbl = tbl;
221121f80baSAlexey Kardashevskiy 	kref_init(&stit->kref);
222121f80baSAlexey Kardashevskiy 
223121f80baSAlexey Kardashevskiy 	list_add_rcu(&stit->next, &stt->iommu_tables);
224121f80baSAlexey Kardashevskiy 
225121f80baSAlexey Kardashevskiy 	return 0;
226121f80baSAlexey Kardashevskiy }
227121f80baSAlexey Kardashevskiy 
228366baf28SAlexey Kardashevskiy static void release_spapr_tce_table(struct rcu_head *head)
229f31e65e1SBenjamin Herrenschmidt {
230366baf28SAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt = container_of(head,
231366baf28SAlexey Kardashevskiy 			struct kvmppc_spapr_tce_table, rcu);
232fe26e527SAlexey Kardashevskiy 	unsigned long i, npages = kvmppc_tce_pages(stt->size);
233f31e65e1SBenjamin Herrenschmidt 
234f8626985SAlexey Kardashevskiy 	for (i = 0; i < npages; i++)
235f31e65e1SBenjamin Herrenschmidt 		__free_page(stt->pages[i]);
236f31e65e1SBenjamin Herrenschmidt 
237366baf28SAlexey Kardashevskiy 	kfree(stt);
238f31e65e1SBenjamin Herrenschmidt }
239f31e65e1SBenjamin Herrenschmidt 
24011bac800SDave Jiang static int kvm_spapr_tce_fault(struct vm_fault *vmf)
241f31e65e1SBenjamin Herrenschmidt {
24211bac800SDave Jiang 	struct kvmppc_spapr_tce_table *stt = vmf->vma->vm_file->private_data;
243f31e65e1SBenjamin Herrenschmidt 	struct page *page;
244f31e65e1SBenjamin Herrenschmidt 
245fe26e527SAlexey Kardashevskiy 	if (vmf->pgoff >= kvmppc_tce_pages(stt->size))
246f31e65e1SBenjamin Herrenschmidt 		return VM_FAULT_SIGBUS;
247f31e65e1SBenjamin Herrenschmidt 
248f31e65e1SBenjamin Herrenschmidt 	page = stt->pages[vmf->pgoff];
249f31e65e1SBenjamin Herrenschmidt 	get_page(page);
250f31e65e1SBenjamin Herrenschmidt 	vmf->page = page;
251f31e65e1SBenjamin Herrenschmidt 	return 0;
252f31e65e1SBenjamin Herrenschmidt }
253f31e65e1SBenjamin Herrenschmidt 
254f31e65e1SBenjamin Herrenschmidt static const struct vm_operations_struct kvm_spapr_tce_vm_ops = {
255f31e65e1SBenjamin Herrenschmidt 	.fault = kvm_spapr_tce_fault,
256f31e65e1SBenjamin Herrenschmidt };
257f31e65e1SBenjamin Herrenschmidt 
258f31e65e1SBenjamin Herrenschmidt static int kvm_spapr_tce_mmap(struct file *file, struct vm_area_struct *vma)
259f31e65e1SBenjamin Herrenschmidt {
260f31e65e1SBenjamin Herrenschmidt 	vma->vm_ops = &kvm_spapr_tce_vm_ops;
261f31e65e1SBenjamin Herrenschmidt 	return 0;
262f31e65e1SBenjamin Herrenschmidt }
263f31e65e1SBenjamin Herrenschmidt 
264f31e65e1SBenjamin Herrenschmidt static int kvm_spapr_tce_release(struct inode *inode, struct file *filp)
265f31e65e1SBenjamin Herrenschmidt {
266f31e65e1SBenjamin Herrenschmidt 	struct kvmppc_spapr_tce_table *stt = filp->private_data;
267121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit, *tmp;
268edd03602SPaul Mackerras 	struct kvm *kvm = stt->kvm;
269f31e65e1SBenjamin Herrenschmidt 
270edd03602SPaul Mackerras 	mutex_lock(&kvm->lock);
271366baf28SAlexey Kardashevskiy 	list_del_rcu(&stt->list);
272edd03602SPaul Mackerras 	mutex_unlock(&kvm->lock);
273366baf28SAlexey Kardashevskiy 
274121f80baSAlexey Kardashevskiy 	list_for_each_entry_safe(stit, tmp, &stt->iommu_tables, next) {
275121f80baSAlexey Kardashevskiy 		WARN_ON(!kref_read(&stit->kref));
276121f80baSAlexey Kardashevskiy 		while (1) {
277121f80baSAlexey Kardashevskiy 			if (kref_put(&stit->kref, kvm_spapr_tce_liobn_put))
278121f80baSAlexey Kardashevskiy 				break;
279121f80baSAlexey Kardashevskiy 		}
280121f80baSAlexey Kardashevskiy 	}
281121f80baSAlexey Kardashevskiy 
282366baf28SAlexey Kardashevskiy 	kvm_put_kvm(stt->kvm);
283366baf28SAlexey Kardashevskiy 
284f8626985SAlexey Kardashevskiy 	kvmppc_account_memlimit(
285fe26e527SAlexey Kardashevskiy 		kvmppc_stt_pages(kvmppc_tce_pages(stt->size)), false);
286366baf28SAlexey Kardashevskiy 	call_rcu(&stt->rcu, release_spapr_tce_table);
287366baf28SAlexey Kardashevskiy 
288f31e65e1SBenjamin Herrenschmidt 	return 0;
289f31e65e1SBenjamin Herrenschmidt }
290f31e65e1SBenjamin Herrenschmidt 
29175ef9de1SAl Viro static const struct file_operations kvm_spapr_tce_fops = {
292f31e65e1SBenjamin Herrenschmidt 	.mmap           = kvm_spapr_tce_mmap,
293f31e65e1SBenjamin Herrenschmidt 	.release	= kvm_spapr_tce_release,
294f31e65e1SBenjamin Herrenschmidt };
295f31e65e1SBenjamin Herrenschmidt 
296f31e65e1SBenjamin Herrenschmidt long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
29758ded420SAlexey Kardashevskiy 				   struct kvm_create_spapr_tce_64 *args)
298f31e65e1SBenjamin Herrenschmidt {
299f31e65e1SBenjamin Herrenschmidt 	struct kvmppc_spapr_tce_table *stt = NULL;
30047c5310aSPaul Mackerras 	struct kvmppc_spapr_tce_table *siter;
301fe26e527SAlexey Kardashevskiy 	unsigned long npages, size;
302f31e65e1SBenjamin Herrenschmidt 	int ret = -ENOMEM;
303f31e65e1SBenjamin Herrenschmidt 	int i;
304f31e65e1SBenjamin Herrenschmidt 
30558ded420SAlexey Kardashevskiy 	if (!args->size)
30658ded420SAlexey Kardashevskiy 		return -EINVAL;
30758ded420SAlexey Kardashevskiy 
3083762d45aSAlexey Kardashevskiy 	size = _ALIGN_UP(args->size, PAGE_SIZE >> 3);
309fe26e527SAlexey Kardashevskiy 	npages = kvmppc_tce_pages(size);
310f8626985SAlexey Kardashevskiy 	ret = kvmppc_account_memlimit(kvmppc_stt_pages(npages), true);
31147c5310aSPaul Mackerras 	if (ret)
31247c5310aSPaul Mackerras 		return ret;
313f31e65e1SBenjamin Herrenschmidt 
3145982f084SWei Yongjun 	ret = -ENOMEM;
315f31e65e1SBenjamin Herrenschmidt 	stt = kzalloc(sizeof(*stt) + npages * sizeof(struct page *),
316f31e65e1SBenjamin Herrenschmidt 		      GFP_KERNEL);
317f31e65e1SBenjamin Herrenschmidt 	if (!stt)
31847c5310aSPaul Mackerras 		goto fail_acct;
319f31e65e1SBenjamin Herrenschmidt 
320f31e65e1SBenjamin Herrenschmidt 	stt->liobn = args->liobn;
32158ded420SAlexey Kardashevskiy 	stt->page_shift = args->page_shift;
32258ded420SAlexey Kardashevskiy 	stt->offset = args->offset;
323fe26e527SAlexey Kardashevskiy 	stt->size = size;
324f31e65e1SBenjamin Herrenschmidt 	stt->kvm = kvm;
325121f80baSAlexey Kardashevskiy 	INIT_LIST_HEAD_RCU(&stt->iommu_tables);
326f31e65e1SBenjamin Herrenschmidt 
327f31e65e1SBenjamin Herrenschmidt 	for (i = 0; i < npages; i++) {
328f31e65e1SBenjamin Herrenschmidt 		stt->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
329f31e65e1SBenjamin Herrenschmidt 		if (!stt->pages[i])
330f31e65e1SBenjamin Herrenschmidt 			goto fail;
331f31e65e1SBenjamin Herrenschmidt 	}
332f31e65e1SBenjamin Herrenschmidt 
333f31e65e1SBenjamin Herrenschmidt 	mutex_lock(&kvm->lock);
33447c5310aSPaul Mackerras 
33547c5310aSPaul Mackerras 	/* Check this LIOBN hasn't been previously allocated */
33647c5310aSPaul Mackerras 	ret = 0;
33747c5310aSPaul Mackerras 	list_for_each_entry(siter, &kvm->arch.spapr_tce_tables, list) {
33847c5310aSPaul Mackerras 		if (siter->liobn == args->liobn) {
33947c5310aSPaul Mackerras 			ret = -EBUSY;
34047c5310aSPaul Mackerras 			break;
34147c5310aSPaul Mackerras 		}
34247c5310aSPaul Mackerras 	}
34347c5310aSPaul Mackerras 
344edd03602SPaul Mackerras 	if (!ret)
345edd03602SPaul Mackerras 		ret = anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops,
346edd03602SPaul Mackerras 				       stt, O_RDWR | O_CLOEXEC);
347edd03602SPaul Mackerras 
348edd03602SPaul Mackerras 	if (ret >= 0) {
349366baf28SAlexey Kardashevskiy 		list_add_rcu(&stt->list, &kvm->arch.spapr_tce_tables);
35047c5310aSPaul Mackerras 		kvm_get_kvm(kvm);
35147c5310aSPaul Mackerras 	}
352f31e65e1SBenjamin Herrenschmidt 
353f31e65e1SBenjamin Herrenschmidt 	mutex_unlock(&kvm->lock);
354f31e65e1SBenjamin Herrenschmidt 
355edd03602SPaul Mackerras 	if (ret >= 0)
356edd03602SPaul Mackerras 		return ret;
357f31e65e1SBenjamin Herrenschmidt 
358f31e65e1SBenjamin Herrenschmidt  fail:
359f31e65e1SBenjamin Herrenschmidt 	for (i = 0; i < npages; i++)
360f31e65e1SBenjamin Herrenschmidt 		if (stt->pages[i])
361f31e65e1SBenjamin Herrenschmidt 			__free_page(stt->pages[i]);
362f31e65e1SBenjamin Herrenschmidt 
363f31e65e1SBenjamin Herrenschmidt 	kfree(stt);
36447c5310aSPaul Mackerras  fail_acct:
36547c5310aSPaul Mackerras 	kvmppc_account_memlimit(kvmppc_stt_pages(npages), false);
366f31e65e1SBenjamin Herrenschmidt 	return ret;
367f31e65e1SBenjamin Herrenschmidt }
368d3695aa4SAlexey Kardashevskiy 
369121f80baSAlexey Kardashevskiy static void kvmppc_clear_tce(struct iommu_table *tbl, unsigned long entry)
370121f80baSAlexey Kardashevskiy {
371121f80baSAlexey Kardashevskiy 	unsigned long hpa = 0;
372121f80baSAlexey Kardashevskiy 	enum dma_data_direction dir = DMA_NONE;
373121f80baSAlexey Kardashevskiy 
374121f80baSAlexey Kardashevskiy 	iommu_tce_xchg(tbl, entry, &hpa, &dir);
375121f80baSAlexey Kardashevskiy }
376121f80baSAlexey Kardashevskiy 
377121f80baSAlexey Kardashevskiy static long kvmppc_tce_iommu_mapped_dec(struct kvm *kvm,
378121f80baSAlexey Kardashevskiy 		struct iommu_table *tbl, unsigned long entry)
379121f80baSAlexey Kardashevskiy {
380121f80baSAlexey Kardashevskiy 	struct mm_iommu_table_group_mem_t *mem = NULL;
381121f80baSAlexey Kardashevskiy 	const unsigned long pgsize = 1ULL << tbl->it_page_shift;
382121f80baSAlexey Kardashevskiy 	unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry);
383121f80baSAlexey Kardashevskiy 
384121f80baSAlexey Kardashevskiy 	if (!pua)
385121f80baSAlexey Kardashevskiy 		/* it_userspace allocation might be delayed */
386121f80baSAlexey Kardashevskiy 		return H_TOO_HARD;
387121f80baSAlexey Kardashevskiy 
388121f80baSAlexey Kardashevskiy 	mem = mm_iommu_lookup(kvm->mm, *pua, pgsize);
389121f80baSAlexey Kardashevskiy 	if (!mem)
390121f80baSAlexey Kardashevskiy 		return H_TOO_HARD;
391121f80baSAlexey Kardashevskiy 
392121f80baSAlexey Kardashevskiy 	mm_iommu_mapped_dec(mem);
393121f80baSAlexey Kardashevskiy 
394121f80baSAlexey Kardashevskiy 	*pua = 0;
395121f80baSAlexey Kardashevskiy 
396121f80baSAlexey Kardashevskiy 	return H_SUCCESS;
397121f80baSAlexey Kardashevskiy }
398121f80baSAlexey Kardashevskiy 
399121f80baSAlexey Kardashevskiy static long kvmppc_tce_iommu_unmap(struct kvm *kvm,
400121f80baSAlexey Kardashevskiy 		struct iommu_table *tbl, unsigned long entry)
401121f80baSAlexey Kardashevskiy {
402121f80baSAlexey Kardashevskiy 	enum dma_data_direction dir = DMA_NONE;
403121f80baSAlexey Kardashevskiy 	unsigned long hpa = 0;
404121f80baSAlexey Kardashevskiy 	long ret;
405121f80baSAlexey Kardashevskiy 
406121f80baSAlexey Kardashevskiy 	if (WARN_ON_ONCE(iommu_tce_xchg(tbl, entry, &hpa, &dir)))
407121f80baSAlexey Kardashevskiy 		return H_HARDWARE;
408121f80baSAlexey Kardashevskiy 
409121f80baSAlexey Kardashevskiy 	if (dir == DMA_NONE)
410121f80baSAlexey Kardashevskiy 		return H_SUCCESS;
411121f80baSAlexey Kardashevskiy 
412121f80baSAlexey Kardashevskiy 	ret = kvmppc_tce_iommu_mapped_dec(kvm, tbl, entry);
413121f80baSAlexey Kardashevskiy 	if (ret != H_SUCCESS)
414121f80baSAlexey Kardashevskiy 		iommu_tce_xchg(tbl, entry, &hpa, &dir);
415121f80baSAlexey Kardashevskiy 
416121f80baSAlexey Kardashevskiy 	return ret;
417121f80baSAlexey Kardashevskiy }
418121f80baSAlexey Kardashevskiy 
419121f80baSAlexey Kardashevskiy long kvmppc_tce_iommu_map(struct kvm *kvm, struct iommu_table *tbl,
420121f80baSAlexey Kardashevskiy 		unsigned long entry, unsigned long ua,
421121f80baSAlexey Kardashevskiy 		enum dma_data_direction dir)
422121f80baSAlexey Kardashevskiy {
423121f80baSAlexey Kardashevskiy 	long ret;
424121f80baSAlexey Kardashevskiy 	unsigned long hpa, *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry);
425121f80baSAlexey Kardashevskiy 	struct mm_iommu_table_group_mem_t *mem;
426121f80baSAlexey Kardashevskiy 
427121f80baSAlexey Kardashevskiy 	if (!pua)
428121f80baSAlexey Kardashevskiy 		/* it_userspace allocation might be delayed */
429121f80baSAlexey Kardashevskiy 		return H_TOO_HARD;
430121f80baSAlexey Kardashevskiy 
431121f80baSAlexey Kardashevskiy 	mem = mm_iommu_lookup(kvm->mm, ua, 1ULL << tbl->it_page_shift);
432121f80baSAlexey Kardashevskiy 	if (!mem)
433121f80baSAlexey Kardashevskiy 		/* This only handles v2 IOMMU type, v1 is handled via ioctl() */
434121f80baSAlexey Kardashevskiy 		return H_TOO_HARD;
435121f80baSAlexey Kardashevskiy 
436121f80baSAlexey Kardashevskiy 	if (WARN_ON_ONCE(mm_iommu_ua_to_hpa(mem, ua, &hpa)))
437121f80baSAlexey Kardashevskiy 		return H_HARDWARE;
438121f80baSAlexey Kardashevskiy 
439121f80baSAlexey Kardashevskiy 	if (mm_iommu_mapped_inc(mem))
440121f80baSAlexey Kardashevskiy 		return H_CLOSED;
441121f80baSAlexey Kardashevskiy 
442121f80baSAlexey Kardashevskiy 	ret = iommu_tce_xchg(tbl, entry, &hpa, &dir);
443121f80baSAlexey Kardashevskiy 	if (WARN_ON_ONCE(ret)) {
444121f80baSAlexey Kardashevskiy 		mm_iommu_mapped_dec(mem);
445121f80baSAlexey Kardashevskiy 		return H_HARDWARE;
446121f80baSAlexey Kardashevskiy 	}
447121f80baSAlexey Kardashevskiy 
448121f80baSAlexey Kardashevskiy 	if (dir != DMA_NONE)
449121f80baSAlexey Kardashevskiy 		kvmppc_tce_iommu_mapped_dec(kvm, tbl, entry);
450121f80baSAlexey Kardashevskiy 
451121f80baSAlexey Kardashevskiy 	*pua = ua;
452121f80baSAlexey Kardashevskiy 
453121f80baSAlexey Kardashevskiy 	return 0;
454121f80baSAlexey Kardashevskiy }
455121f80baSAlexey Kardashevskiy 
45631217db7SAlexey Kardashevskiy long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
45731217db7SAlexey Kardashevskiy 		      unsigned long ioba, unsigned long tce)
45831217db7SAlexey Kardashevskiy {
459503bfcbeSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt;
460121f80baSAlexey Kardashevskiy 	long ret, idx;
461121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit;
462121f80baSAlexey Kardashevskiy 	unsigned long entry, ua = 0;
463121f80baSAlexey Kardashevskiy 	enum dma_data_direction dir;
46431217db7SAlexey Kardashevskiy 
46531217db7SAlexey Kardashevskiy 	/* udbg_printf("H_PUT_TCE(): liobn=0x%lx ioba=0x%lx, tce=0x%lx\n", */
46631217db7SAlexey Kardashevskiy 	/* 	    liobn, ioba, tce); */
46731217db7SAlexey Kardashevskiy 
468503bfcbeSAlexey Kardashevskiy 	stt = kvmppc_find_table(vcpu->kvm, liobn);
46931217db7SAlexey Kardashevskiy 	if (!stt)
47031217db7SAlexey Kardashevskiy 		return H_TOO_HARD;
47131217db7SAlexey Kardashevskiy 
47231217db7SAlexey Kardashevskiy 	ret = kvmppc_ioba_validate(stt, ioba, 1);
47331217db7SAlexey Kardashevskiy 	if (ret != H_SUCCESS)
47431217db7SAlexey Kardashevskiy 		return ret;
47531217db7SAlexey Kardashevskiy 
47631217db7SAlexey Kardashevskiy 	ret = kvmppc_tce_validate(stt, tce);
47731217db7SAlexey Kardashevskiy 	if (ret != H_SUCCESS)
47831217db7SAlexey Kardashevskiy 		return ret;
47931217db7SAlexey Kardashevskiy 
480121f80baSAlexey Kardashevskiy 	dir = iommu_tce_direction(tce);
481*8f6a9f0dSAlexey Kardashevskiy 
482*8f6a9f0dSAlexey Kardashevskiy 	idx = srcu_read_lock(&vcpu->kvm->srcu);
483*8f6a9f0dSAlexey Kardashevskiy 
484121f80baSAlexey Kardashevskiy 	if ((dir != DMA_NONE) && kvmppc_gpa_to_ua(vcpu->kvm,
485*8f6a9f0dSAlexey Kardashevskiy 			tce & ~(TCE_PCI_READ | TCE_PCI_WRITE), &ua, NULL)) {
486*8f6a9f0dSAlexey Kardashevskiy 		ret = H_PARAMETER;
487*8f6a9f0dSAlexey Kardashevskiy 		goto unlock_exit;
488*8f6a9f0dSAlexey Kardashevskiy 	}
489121f80baSAlexey Kardashevskiy 
490121f80baSAlexey Kardashevskiy 	entry = ioba >> stt->page_shift;
491121f80baSAlexey Kardashevskiy 
492121f80baSAlexey Kardashevskiy 	list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
493*8f6a9f0dSAlexey Kardashevskiy 		if (dir == DMA_NONE)
494121f80baSAlexey Kardashevskiy 			ret = kvmppc_tce_iommu_unmap(vcpu->kvm,
495121f80baSAlexey Kardashevskiy 					stit->tbl, entry);
496*8f6a9f0dSAlexey Kardashevskiy 		else
497121f80baSAlexey Kardashevskiy 			ret = kvmppc_tce_iommu_map(vcpu->kvm, stit->tbl,
498121f80baSAlexey Kardashevskiy 					entry, ua, dir);
499121f80baSAlexey Kardashevskiy 
500121f80baSAlexey Kardashevskiy 		if (ret == H_SUCCESS)
501121f80baSAlexey Kardashevskiy 			continue;
502121f80baSAlexey Kardashevskiy 
503121f80baSAlexey Kardashevskiy 		if (ret == H_TOO_HARD)
504*8f6a9f0dSAlexey Kardashevskiy 			goto unlock_exit;
505121f80baSAlexey Kardashevskiy 
506121f80baSAlexey Kardashevskiy 		WARN_ON_ONCE(1);
507121f80baSAlexey Kardashevskiy 		kvmppc_clear_tce(stit->tbl, entry);
508121f80baSAlexey Kardashevskiy 	}
509121f80baSAlexey Kardashevskiy 
510121f80baSAlexey Kardashevskiy 	kvmppc_tce_put(stt, entry, tce);
51131217db7SAlexey Kardashevskiy 
512*8f6a9f0dSAlexey Kardashevskiy unlock_exit:
513*8f6a9f0dSAlexey Kardashevskiy 	srcu_read_unlock(&vcpu->kvm->srcu, idx);
514*8f6a9f0dSAlexey Kardashevskiy 
515*8f6a9f0dSAlexey Kardashevskiy 	return ret;
51631217db7SAlexey Kardashevskiy }
51731217db7SAlexey Kardashevskiy EXPORT_SYMBOL_GPL(kvmppc_h_put_tce);
51831217db7SAlexey Kardashevskiy 
519d3695aa4SAlexey Kardashevskiy long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu,
520d3695aa4SAlexey Kardashevskiy 		unsigned long liobn, unsigned long ioba,
521d3695aa4SAlexey Kardashevskiy 		unsigned long tce_list, unsigned long npages)
522d3695aa4SAlexey Kardashevskiy {
523d3695aa4SAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt;
524d3695aa4SAlexey Kardashevskiy 	long i, ret = H_SUCCESS, idx;
525d3695aa4SAlexey Kardashevskiy 	unsigned long entry, ua = 0;
526f8750513SDaniel Axtens 	u64 __user *tces;
527f8750513SDaniel Axtens 	u64 tce;
528121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit;
529d3695aa4SAlexey Kardashevskiy 
530503bfcbeSAlexey Kardashevskiy 	stt = kvmppc_find_table(vcpu->kvm, liobn);
531d3695aa4SAlexey Kardashevskiy 	if (!stt)
532d3695aa4SAlexey Kardashevskiy 		return H_TOO_HARD;
533d3695aa4SAlexey Kardashevskiy 
534fe26e527SAlexey Kardashevskiy 	entry = ioba >> stt->page_shift;
535d3695aa4SAlexey Kardashevskiy 	/*
536d3695aa4SAlexey Kardashevskiy 	 * SPAPR spec says that the maximum size of the list is 512 TCEs
537d3695aa4SAlexey Kardashevskiy 	 * so the whole table fits in 4K page
538d3695aa4SAlexey Kardashevskiy 	 */
539d3695aa4SAlexey Kardashevskiy 	if (npages > 512)
540d3695aa4SAlexey Kardashevskiy 		return H_PARAMETER;
541d3695aa4SAlexey Kardashevskiy 
542d3695aa4SAlexey Kardashevskiy 	if (tce_list & (SZ_4K - 1))
543d3695aa4SAlexey Kardashevskiy 		return H_PARAMETER;
544d3695aa4SAlexey Kardashevskiy 
545d3695aa4SAlexey Kardashevskiy 	ret = kvmppc_ioba_validate(stt, ioba, npages);
546d3695aa4SAlexey Kardashevskiy 	if (ret != H_SUCCESS)
547d3695aa4SAlexey Kardashevskiy 		return ret;
548d3695aa4SAlexey Kardashevskiy 
549d3695aa4SAlexey Kardashevskiy 	idx = srcu_read_lock(&vcpu->kvm->srcu);
550d3695aa4SAlexey Kardashevskiy 	if (kvmppc_gpa_to_ua(vcpu->kvm, tce_list, &ua, NULL)) {
551d3695aa4SAlexey Kardashevskiy 		ret = H_TOO_HARD;
552d3695aa4SAlexey Kardashevskiy 		goto unlock_exit;
553d3695aa4SAlexey Kardashevskiy 	}
554d3695aa4SAlexey Kardashevskiy 	tces = (u64 __user *) ua;
555d3695aa4SAlexey Kardashevskiy 
556d3695aa4SAlexey Kardashevskiy 	for (i = 0; i < npages; ++i) {
557d3695aa4SAlexey Kardashevskiy 		if (get_user(tce, tces + i)) {
558d3695aa4SAlexey Kardashevskiy 			ret = H_TOO_HARD;
559d3695aa4SAlexey Kardashevskiy 			goto unlock_exit;
560d3695aa4SAlexey Kardashevskiy 		}
561d3695aa4SAlexey Kardashevskiy 		tce = be64_to_cpu(tce);
562d3695aa4SAlexey Kardashevskiy 
563d3695aa4SAlexey Kardashevskiy 		ret = kvmppc_tce_validate(stt, tce);
564d3695aa4SAlexey Kardashevskiy 		if (ret != H_SUCCESS)
565d3695aa4SAlexey Kardashevskiy 			goto unlock_exit;
566d3695aa4SAlexey Kardashevskiy 
567121f80baSAlexey Kardashevskiy 		if (kvmppc_gpa_to_ua(vcpu->kvm,
568121f80baSAlexey Kardashevskiy 				tce & ~(TCE_PCI_READ | TCE_PCI_WRITE),
569121f80baSAlexey Kardashevskiy 				&ua, NULL))
570121f80baSAlexey Kardashevskiy 			return H_PARAMETER;
571121f80baSAlexey Kardashevskiy 
572121f80baSAlexey Kardashevskiy 		list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
573121f80baSAlexey Kardashevskiy 			ret = kvmppc_tce_iommu_map(vcpu->kvm,
574121f80baSAlexey Kardashevskiy 					stit->tbl, entry + i, ua,
575121f80baSAlexey Kardashevskiy 					iommu_tce_direction(tce));
576121f80baSAlexey Kardashevskiy 
577121f80baSAlexey Kardashevskiy 			if (ret == H_SUCCESS)
578121f80baSAlexey Kardashevskiy 				continue;
579121f80baSAlexey Kardashevskiy 
580121f80baSAlexey Kardashevskiy 			if (ret == H_TOO_HARD)
581121f80baSAlexey Kardashevskiy 				goto unlock_exit;
582121f80baSAlexey Kardashevskiy 
583121f80baSAlexey Kardashevskiy 			WARN_ON_ONCE(1);
584121f80baSAlexey Kardashevskiy 			kvmppc_clear_tce(stit->tbl, entry);
585121f80baSAlexey Kardashevskiy 		}
586121f80baSAlexey Kardashevskiy 
587d3695aa4SAlexey Kardashevskiy 		kvmppc_tce_put(stt, entry + i, tce);
588d3695aa4SAlexey Kardashevskiy 	}
589d3695aa4SAlexey Kardashevskiy 
590d3695aa4SAlexey Kardashevskiy unlock_exit:
591d3695aa4SAlexey Kardashevskiy 	srcu_read_unlock(&vcpu->kvm->srcu, idx);
592d3695aa4SAlexey Kardashevskiy 
593d3695aa4SAlexey Kardashevskiy 	return ret;
594d3695aa4SAlexey Kardashevskiy }
595d3695aa4SAlexey Kardashevskiy EXPORT_SYMBOL_GPL(kvmppc_h_put_tce_indirect);
59631217db7SAlexey Kardashevskiy 
59731217db7SAlexey Kardashevskiy long kvmppc_h_stuff_tce(struct kvm_vcpu *vcpu,
59831217db7SAlexey Kardashevskiy 		unsigned long liobn, unsigned long ioba,
59931217db7SAlexey Kardashevskiy 		unsigned long tce_value, unsigned long npages)
60031217db7SAlexey Kardashevskiy {
60131217db7SAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt;
60231217db7SAlexey Kardashevskiy 	long i, ret;
603121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit;
60431217db7SAlexey Kardashevskiy 
605503bfcbeSAlexey Kardashevskiy 	stt = kvmppc_find_table(vcpu->kvm, liobn);
60631217db7SAlexey Kardashevskiy 	if (!stt)
60731217db7SAlexey Kardashevskiy 		return H_TOO_HARD;
60831217db7SAlexey Kardashevskiy 
60931217db7SAlexey Kardashevskiy 	ret = kvmppc_ioba_validate(stt, ioba, npages);
61031217db7SAlexey Kardashevskiy 	if (ret != H_SUCCESS)
61131217db7SAlexey Kardashevskiy 		return ret;
61231217db7SAlexey Kardashevskiy 
61331217db7SAlexey Kardashevskiy 	/* Check permission bits only to allow userspace poison TCE for debug */
61431217db7SAlexey Kardashevskiy 	if (tce_value & (TCE_PCI_WRITE | TCE_PCI_READ))
61531217db7SAlexey Kardashevskiy 		return H_PARAMETER;
61631217db7SAlexey Kardashevskiy 
617121f80baSAlexey Kardashevskiy 	list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
618121f80baSAlexey Kardashevskiy 		unsigned long entry = ioba >> stit->tbl->it_page_shift;
619121f80baSAlexey Kardashevskiy 
620121f80baSAlexey Kardashevskiy 		for (i = 0; i < npages; ++i) {
621121f80baSAlexey Kardashevskiy 			ret = kvmppc_tce_iommu_unmap(vcpu->kvm,
622121f80baSAlexey Kardashevskiy 					stit->tbl, entry + i);
623121f80baSAlexey Kardashevskiy 
624121f80baSAlexey Kardashevskiy 			if (ret == H_SUCCESS)
625121f80baSAlexey Kardashevskiy 				continue;
626121f80baSAlexey Kardashevskiy 
627121f80baSAlexey Kardashevskiy 			if (ret == H_TOO_HARD)
628121f80baSAlexey Kardashevskiy 				return ret;
629121f80baSAlexey Kardashevskiy 
630121f80baSAlexey Kardashevskiy 			WARN_ON_ONCE(1);
631121f80baSAlexey Kardashevskiy 			kvmppc_clear_tce(stit->tbl, entry);
632121f80baSAlexey Kardashevskiy 		}
633121f80baSAlexey Kardashevskiy 	}
634121f80baSAlexey Kardashevskiy 
63531217db7SAlexey Kardashevskiy 	for (i = 0; i < npages; ++i, ioba += (1ULL << stt->page_shift))
63631217db7SAlexey Kardashevskiy 		kvmppc_tce_put(stt, ioba >> stt->page_shift, tce_value);
63731217db7SAlexey Kardashevskiy 
63831217db7SAlexey Kardashevskiy 	return H_SUCCESS;
63931217db7SAlexey Kardashevskiy }
64031217db7SAlexey Kardashevskiy EXPORT_SYMBOL_GPL(kvmppc_h_stuff_tce);
641