xref: /linux/arch/powerpc/kvm/book3s_64_vio.c (revision e1a1ef84cd07f72ce12f139eb9a37d3f9028e7a7)
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/kvm_ppc.h>
35f31e65e1SBenjamin Herrenschmidt #include <asm/kvm_book3s.h>
36f64e8084SAneesh Kumar K.V #include <asm/book3s/64/mmu-hash.h>
37f31e65e1SBenjamin Herrenschmidt #include <asm/hvcall.h>
38f31e65e1SBenjamin Herrenschmidt #include <asm/synch.h>
39f31e65e1SBenjamin Herrenschmidt #include <asm/ppc-opcode.h>
40f31e65e1SBenjamin Herrenschmidt #include <asm/kvm_host.h>
41f31e65e1SBenjamin Herrenschmidt #include <asm/udbg.h>
42462ee11eSAlexey Kardashevskiy #include <asm/iommu.h>
43d3695aa4SAlexey Kardashevskiy #include <asm/tce.h>
44121f80baSAlexey Kardashevskiy #include <asm/mmu_context.h>
45f31e65e1SBenjamin Herrenschmidt 
46fe26e527SAlexey Kardashevskiy static unsigned long kvmppc_tce_pages(unsigned long iommu_pages)
47f31e65e1SBenjamin Herrenschmidt {
48fe26e527SAlexey Kardashevskiy 	return ALIGN(iommu_pages * sizeof(u64), PAGE_SIZE) / PAGE_SIZE;
49f31e65e1SBenjamin Herrenschmidt }
50f31e65e1SBenjamin Herrenschmidt 
51f8626985SAlexey Kardashevskiy static unsigned long kvmppc_stt_pages(unsigned long tce_pages)
52f8626985SAlexey Kardashevskiy {
53f8626985SAlexey Kardashevskiy 	unsigned long stt_bytes = sizeof(struct kvmppc_spapr_tce_table) +
54f8626985SAlexey Kardashevskiy 			(tce_pages * sizeof(struct page *));
55f8626985SAlexey Kardashevskiy 
56f8626985SAlexey Kardashevskiy 	return tce_pages + ALIGN(stt_bytes, PAGE_SIZE) / PAGE_SIZE;
57f8626985SAlexey Kardashevskiy }
58f8626985SAlexey Kardashevskiy 
59f8626985SAlexey Kardashevskiy static long kvmppc_account_memlimit(unsigned long stt_pages, bool inc)
60f8626985SAlexey Kardashevskiy {
61f8626985SAlexey Kardashevskiy 	long ret = 0;
62f8626985SAlexey Kardashevskiy 
63f8626985SAlexey Kardashevskiy 	if (!current || !current->mm)
64f8626985SAlexey Kardashevskiy 		return ret; /* process exited */
65f8626985SAlexey Kardashevskiy 
66f8626985SAlexey Kardashevskiy 	down_write(&current->mm->mmap_sem);
67f8626985SAlexey Kardashevskiy 
68f8626985SAlexey Kardashevskiy 	if (inc) {
69f8626985SAlexey Kardashevskiy 		unsigned long locked, lock_limit;
70f8626985SAlexey Kardashevskiy 
71f8626985SAlexey Kardashevskiy 		locked = current->mm->locked_vm + stt_pages;
72f8626985SAlexey Kardashevskiy 		lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
73f8626985SAlexey Kardashevskiy 		if (locked > lock_limit && !capable(CAP_IPC_LOCK))
74f8626985SAlexey Kardashevskiy 			ret = -ENOMEM;
75f8626985SAlexey Kardashevskiy 		else
76f8626985SAlexey Kardashevskiy 			current->mm->locked_vm += stt_pages;
77f8626985SAlexey Kardashevskiy 	} else {
78f8626985SAlexey Kardashevskiy 		if (WARN_ON_ONCE(stt_pages > current->mm->locked_vm))
79f8626985SAlexey Kardashevskiy 			stt_pages = current->mm->locked_vm;
80f8626985SAlexey Kardashevskiy 
81f8626985SAlexey Kardashevskiy 		current->mm->locked_vm -= stt_pages;
82f8626985SAlexey Kardashevskiy 	}
83f8626985SAlexey Kardashevskiy 
84f8626985SAlexey Kardashevskiy 	pr_debug("[%d] RLIMIT_MEMLOCK KVM %c%ld %ld/%ld%s\n", current->pid,
85f8626985SAlexey Kardashevskiy 			inc ? '+' : '-',
86f8626985SAlexey Kardashevskiy 			stt_pages << PAGE_SHIFT,
87f8626985SAlexey Kardashevskiy 			current->mm->locked_vm << PAGE_SHIFT,
88f8626985SAlexey Kardashevskiy 			rlimit(RLIMIT_MEMLOCK),
89f8626985SAlexey Kardashevskiy 			ret ? " - exceeded" : "");
90f8626985SAlexey Kardashevskiy 
91f8626985SAlexey Kardashevskiy 	up_write(&current->mm->mmap_sem);
92f8626985SAlexey Kardashevskiy 
93f8626985SAlexey Kardashevskiy 	return ret;
94f8626985SAlexey Kardashevskiy }
95f8626985SAlexey Kardashevskiy 
96121f80baSAlexey Kardashevskiy static void kvm_spapr_tce_iommu_table_free(struct rcu_head *head)
97121f80baSAlexey Kardashevskiy {
98121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit = container_of(head,
99121f80baSAlexey Kardashevskiy 			struct kvmppc_spapr_tce_iommu_table, rcu);
100121f80baSAlexey Kardashevskiy 
101121f80baSAlexey Kardashevskiy 	iommu_tce_table_put(stit->tbl);
102121f80baSAlexey Kardashevskiy 
103121f80baSAlexey Kardashevskiy 	kfree(stit);
104121f80baSAlexey Kardashevskiy }
105121f80baSAlexey Kardashevskiy 
106121f80baSAlexey Kardashevskiy static void kvm_spapr_tce_liobn_put(struct kref *kref)
107121f80baSAlexey Kardashevskiy {
108121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit = container_of(kref,
109121f80baSAlexey Kardashevskiy 			struct kvmppc_spapr_tce_iommu_table, kref);
110121f80baSAlexey Kardashevskiy 
111121f80baSAlexey Kardashevskiy 	list_del_rcu(&stit->next);
112121f80baSAlexey Kardashevskiy 
113121f80baSAlexey Kardashevskiy 	call_rcu(&stit->rcu, kvm_spapr_tce_iommu_table_free);
114121f80baSAlexey Kardashevskiy }
115121f80baSAlexey Kardashevskiy 
116121f80baSAlexey Kardashevskiy extern void kvm_spapr_tce_release_iommu_group(struct kvm *kvm,
117121f80baSAlexey Kardashevskiy 		struct iommu_group *grp)
118121f80baSAlexey Kardashevskiy {
119121f80baSAlexey Kardashevskiy 	int i;
120121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt;
121121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit, *tmp;
122121f80baSAlexey Kardashevskiy 	struct iommu_table_group *table_group = NULL;
123121f80baSAlexey Kardashevskiy 
124121f80baSAlexey Kardashevskiy 	list_for_each_entry_rcu(stt, &kvm->arch.spapr_tce_tables, list) {
125121f80baSAlexey Kardashevskiy 
126121f80baSAlexey Kardashevskiy 		table_group = iommu_group_get_iommudata(grp);
127121f80baSAlexey Kardashevskiy 		if (WARN_ON(!table_group))
128121f80baSAlexey Kardashevskiy 			continue;
129121f80baSAlexey Kardashevskiy 
130121f80baSAlexey Kardashevskiy 		list_for_each_entry_safe(stit, tmp, &stt->iommu_tables, next) {
131121f80baSAlexey Kardashevskiy 			for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
132121f80baSAlexey Kardashevskiy 				if (table_group->tables[i] != stit->tbl)
133121f80baSAlexey Kardashevskiy 					continue;
134121f80baSAlexey Kardashevskiy 
135121f80baSAlexey Kardashevskiy 				kref_put(&stit->kref, kvm_spapr_tce_liobn_put);
136121f80baSAlexey Kardashevskiy 			}
137121f80baSAlexey Kardashevskiy 		}
138121f80baSAlexey Kardashevskiy 	}
139121f80baSAlexey Kardashevskiy }
140121f80baSAlexey Kardashevskiy 
141121f80baSAlexey Kardashevskiy extern long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd,
142121f80baSAlexey Kardashevskiy 		struct iommu_group *grp)
143121f80baSAlexey Kardashevskiy {
144121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt = NULL;
145121f80baSAlexey Kardashevskiy 	bool found = false;
146121f80baSAlexey Kardashevskiy 	struct iommu_table *tbl = NULL;
147121f80baSAlexey Kardashevskiy 	struct iommu_table_group *table_group;
148121f80baSAlexey Kardashevskiy 	long i;
149121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit;
150121f80baSAlexey Kardashevskiy 	struct fd f;
151121f80baSAlexey Kardashevskiy 
152121f80baSAlexey Kardashevskiy 	f = fdget(tablefd);
153121f80baSAlexey Kardashevskiy 	if (!f.file)
154121f80baSAlexey Kardashevskiy 		return -EBADF;
155121f80baSAlexey Kardashevskiy 
156121f80baSAlexey Kardashevskiy 	list_for_each_entry_rcu(stt, &kvm->arch.spapr_tce_tables, list) {
157121f80baSAlexey Kardashevskiy 		if (stt == f.file->private_data) {
158121f80baSAlexey Kardashevskiy 			found = true;
159121f80baSAlexey Kardashevskiy 			break;
160121f80baSAlexey Kardashevskiy 		}
161121f80baSAlexey Kardashevskiy 	}
162121f80baSAlexey Kardashevskiy 
163121f80baSAlexey Kardashevskiy 	fdput(f);
164121f80baSAlexey Kardashevskiy 
165121f80baSAlexey Kardashevskiy 	if (!found)
166121f80baSAlexey Kardashevskiy 		return -EINVAL;
167121f80baSAlexey Kardashevskiy 
168121f80baSAlexey Kardashevskiy 	table_group = iommu_group_get_iommudata(grp);
169121f80baSAlexey Kardashevskiy 	if (WARN_ON(!table_group))
170121f80baSAlexey Kardashevskiy 		return -EFAULT;
171121f80baSAlexey Kardashevskiy 
172121f80baSAlexey Kardashevskiy 	for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
173121f80baSAlexey Kardashevskiy 		struct iommu_table *tbltmp = table_group->tables[i];
174121f80baSAlexey Kardashevskiy 
175121f80baSAlexey Kardashevskiy 		if (!tbltmp)
176121f80baSAlexey Kardashevskiy 			continue;
177ca1fc489SAlexey Kardashevskiy 		/* Make sure hardware table parameters are compatible */
178ca1fc489SAlexey Kardashevskiy 		if ((tbltmp->it_page_shift <= stt->page_shift) &&
179ca1fc489SAlexey Kardashevskiy 				(tbltmp->it_offset << tbltmp->it_page_shift ==
180ca1fc489SAlexey Kardashevskiy 				 stt->offset << stt->page_shift) &&
18176346cd9SAlexey Kardashevskiy 				(tbltmp->it_size << tbltmp->it_page_shift >=
182ca1fc489SAlexey Kardashevskiy 				 stt->size << stt->page_shift)) {
183121f80baSAlexey Kardashevskiy 			/*
184121f80baSAlexey Kardashevskiy 			 * Reference the table to avoid races with
185121f80baSAlexey Kardashevskiy 			 * add/remove DMA windows.
186121f80baSAlexey Kardashevskiy 			 */
187121f80baSAlexey Kardashevskiy 			tbl = iommu_tce_table_get(tbltmp);
188121f80baSAlexey Kardashevskiy 			break;
189121f80baSAlexey Kardashevskiy 		}
190121f80baSAlexey Kardashevskiy 	}
191121f80baSAlexey Kardashevskiy 	if (!tbl)
192121f80baSAlexey Kardashevskiy 		return -EINVAL;
193121f80baSAlexey Kardashevskiy 
194121f80baSAlexey Kardashevskiy 	list_for_each_entry_rcu(stit, &stt->iommu_tables, next) {
195121f80baSAlexey Kardashevskiy 		if (tbl != stit->tbl)
196121f80baSAlexey Kardashevskiy 			continue;
197121f80baSAlexey Kardashevskiy 
198121f80baSAlexey Kardashevskiy 		if (!kref_get_unless_zero(&stit->kref)) {
199121f80baSAlexey Kardashevskiy 			/* stit is being destroyed */
200121f80baSAlexey Kardashevskiy 			iommu_tce_table_put(tbl);
201121f80baSAlexey Kardashevskiy 			return -ENOTTY;
202121f80baSAlexey Kardashevskiy 		}
203121f80baSAlexey Kardashevskiy 		/*
204121f80baSAlexey Kardashevskiy 		 * The table is already known to this KVM, we just increased
205121f80baSAlexey Kardashevskiy 		 * its KVM reference counter and can return.
206121f80baSAlexey Kardashevskiy 		 */
207121f80baSAlexey Kardashevskiy 		return 0;
208121f80baSAlexey Kardashevskiy 	}
209121f80baSAlexey Kardashevskiy 
210121f80baSAlexey Kardashevskiy 	stit = kzalloc(sizeof(*stit), GFP_KERNEL);
211121f80baSAlexey Kardashevskiy 	if (!stit) {
212121f80baSAlexey Kardashevskiy 		iommu_tce_table_put(tbl);
213121f80baSAlexey Kardashevskiy 		return -ENOMEM;
214121f80baSAlexey Kardashevskiy 	}
215121f80baSAlexey Kardashevskiy 
216121f80baSAlexey Kardashevskiy 	stit->tbl = tbl;
217121f80baSAlexey Kardashevskiy 	kref_init(&stit->kref);
218121f80baSAlexey Kardashevskiy 
219121f80baSAlexey Kardashevskiy 	list_add_rcu(&stit->next, &stt->iommu_tables);
220121f80baSAlexey Kardashevskiy 
221121f80baSAlexey Kardashevskiy 	return 0;
222121f80baSAlexey Kardashevskiy }
223121f80baSAlexey Kardashevskiy 
224366baf28SAlexey Kardashevskiy static void release_spapr_tce_table(struct rcu_head *head)
225f31e65e1SBenjamin Herrenschmidt {
226366baf28SAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt = container_of(head,
227366baf28SAlexey Kardashevskiy 			struct kvmppc_spapr_tce_table, rcu);
228fe26e527SAlexey Kardashevskiy 	unsigned long i, npages = kvmppc_tce_pages(stt->size);
229f31e65e1SBenjamin Herrenschmidt 
230f8626985SAlexey Kardashevskiy 	for (i = 0; i < npages; i++)
231*e1a1ef84SAlexey Kardashevskiy 		if (stt->pages[i])
232f31e65e1SBenjamin Herrenschmidt 			__free_page(stt->pages[i]);
233f31e65e1SBenjamin Herrenschmidt 
234366baf28SAlexey Kardashevskiy 	kfree(stt);
235f31e65e1SBenjamin Herrenschmidt }
236f31e65e1SBenjamin Herrenschmidt 
237*e1a1ef84SAlexey Kardashevskiy static struct page *kvm_spapr_get_tce_page(struct kvmppc_spapr_tce_table *stt,
238*e1a1ef84SAlexey Kardashevskiy 		unsigned long sttpage)
239*e1a1ef84SAlexey Kardashevskiy {
240*e1a1ef84SAlexey Kardashevskiy 	struct page *page = stt->pages[sttpage];
241*e1a1ef84SAlexey Kardashevskiy 
242*e1a1ef84SAlexey Kardashevskiy 	if (page)
243*e1a1ef84SAlexey Kardashevskiy 		return page;
244*e1a1ef84SAlexey Kardashevskiy 
245*e1a1ef84SAlexey Kardashevskiy 	mutex_lock(&stt->alloc_lock);
246*e1a1ef84SAlexey Kardashevskiy 	page = stt->pages[sttpage];
247*e1a1ef84SAlexey Kardashevskiy 	if (!page) {
248*e1a1ef84SAlexey Kardashevskiy 		page = alloc_page(GFP_KERNEL | __GFP_ZERO);
249*e1a1ef84SAlexey Kardashevskiy 		WARN_ON_ONCE(!page);
250*e1a1ef84SAlexey Kardashevskiy 		if (page)
251*e1a1ef84SAlexey Kardashevskiy 			stt->pages[sttpage] = page;
252*e1a1ef84SAlexey Kardashevskiy 	}
253*e1a1ef84SAlexey Kardashevskiy 	mutex_unlock(&stt->alloc_lock);
254*e1a1ef84SAlexey Kardashevskiy 
255*e1a1ef84SAlexey Kardashevskiy 	return page;
256*e1a1ef84SAlexey Kardashevskiy }
257*e1a1ef84SAlexey Kardashevskiy 
25816d5c39dSSouptick Joarder static vm_fault_t kvm_spapr_tce_fault(struct vm_fault *vmf)
259f31e65e1SBenjamin Herrenschmidt {
26011bac800SDave Jiang 	struct kvmppc_spapr_tce_table *stt = vmf->vma->vm_file->private_data;
261f31e65e1SBenjamin Herrenschmidt 	struct page *page;
262f31e65e1SBenjamin Herrenschmidt 
263fe26e527SAlexey Kardashevskiy 	if (vmf->pgoff >= kvmppc_tce_pages(stt->size))
264f31e65e1SBenjamin Herrenschmidt 		return VM_FAULT_SIGBUS;
265f31e65e1SBenjamin Herrenschmidt 
266*e1a1ef84SAlexey Kardashevskiy 	page = kvm_spapr_get_tce_page(stt, vmf->pgoff);
267*e1a1ef84SAlexey Kardashevskiy 	if (!page)
268*e1a1ef84SAlexey Kardashevskiy 		return VM_FAULT_OOM;
269*e1a1ef84SAlexey Kardashevskiy 
270f31e65e1SBenjamin Herrenschmidt 	get_page(page);
271f31e65e1SBenjamin Herrenschmidt 	vmf->page = page;
272f31e65e1SBenjamin Herrenschmidt 	return 0;
273f31e65e1SBenjamin Herrenschmidt }
274f31e65e1SBenjamin Herrenschmidt 
275f31e65e1SBenjamin Herrenschmidt static const struct vm_operations_struct kvm_spapr_tce_vm_ops = {
276f31e65e1SBenjamin Herrenschmidt 	.fault = kvm_spapr_tce_fault,
277f31e65e1SBenjamin Herrenschmidt };
278f31e65e1SBenjamin Herrenschmidt 
279f31e65e1SBenjamin Herrenschmidt static int kvm_spapr_tce_mmap(struct file *file, struct vm_area_struct *vma)
280f31e65e1SBenjamin Herrenschmidt {
281f31e65e1SBenjamin Herrenschmidt 	vma->vm_ops = &kvm_spapr_tce_vm_ops;
282f31e65e1SBenjamin Herrenschmidt 	return 0;
283f31e65e1SBenjamin Herrenschmidt }
284f31e65e1SBenjamin Herrenschmidt 
285f31e65e1SBenjamin Herrenschmidt static int kvm_spapr_tce_release(struct inode *inode, struct file *filp)
286f31e65e1SBenjamin Herrenschmidt {
287f31e65e1SBenjamin Herrenschmidt 	struct kvmppc_spapr_tce_table *stt = filp->private_data;
288121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit, *tmp;
289edd03602SPaul Mackerras 	struct kvm *kvm = stt->kvm;
290f31e65e1SBenjamin Herrenschmidt 
291edd03602SPaul Mackerras 	mutex_lock(&kvm->lock);
292366baf28SAlexey Kardashevskiy 	list_del_rcu(&stt->list);
293edd03602SPaul Mackerras 	mutex_unlock(&kvm->lock);
294366baf28SAlexey Kardashevskiy 
295121f80baSAlexey Kardashevskiy 	list_for_each_entry_safe(stit, tmp, &stt->iommu_tables, next) {
296121f80baSAlexey Kardashevskiy 		WARN_ON(!kref_read(&stit->kref));
297121f80baSAlexey Kardashevskiy 		while (1) {
298121f80baSAlexey Kardashevskiy 			if (kref_put(&stit->kref, kvm_spapr_tce_liobn_put))
299121f80baSAlexey Kardashevskiy 				break;
300121f80baSAlexey Kardashevskiy 		}
301121f80baSAlexey Kardashevskiy 	}
302121f80baSAlexey Kardashevskiy 
303366baf28SAlexey Kardashevskiy 	kvm_put_kvm(stt->kvm);
304366baf28SAlexey Kardashevskiy 
305f8626985SAlexey Kardashevskiy 	kvmppc_account_memlimit(
306fe26e527SAlexey Kardashevskiy 		kvmppc_stt_pages(kvmppc_tce_pages(stt->size)), false);
307366baf28SAlexey Kardashevskiy 	call_rcu(&stt->rcu, release_spapr_tce_table);
308366baf28SAlexey Kardashevskiy 
309f31e65e1SBenjamin Herrenschmidt 	return 0;
310f31e65e1SBenjamin Herrenschmidt }
311f31e65e1SBenjamin Herrenschmidt 
31275ef9de1SAl Viro static const struct file_operations kvm_spapr_tce_fops = {
313f31e65e1SBenjamin Herrenschmidt 	.mmap           = kvm_spapr_tce_mmap,
314f31e65e1SBenjamin Herrenschmidt 	.release	= kvm_spapr_tce_release,
315f31e65e1SBenjamin Herrenschmidt };
316f31e65e1SBenjamin Herrenschmidt 
317f31e65e1SBenjamin Herrenschmidt long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
31858ded420SAlexey Kardashevskiy 				   struct kvm_create_spapr_tce_64 *args)
319f31e65e1SBenjamin Herrenschmidt {
320f31e65e1SBenjamin Herrenschmidt 	struct kvmppc_spapr_tce_table *stt = NULL;
32147c5310aSPaul Mackerras 	struct kvmppc_spapr_tce_table *siter;
32276346cd9SAlexey Kardashevskiy 	unsigned long npages, size = args->size;
323f31e65e1SBenjamin Herrenschmidt 	int ret = -ENOMEM;
324f31e65e1SBenjamin Herrenschmidt 
325e45719afSAlexey Kardashevskiy 	if (!args->size || args->page_shift < 12 || args->page_shift > 34 ||
326e45719afSAlexey Kardashevskiy 		(args->offset + args->size > (ULLONG_MAX >> args->page_shift)))
32758ded420SAlexey Kardashevskiy 		return -EINVAL;
32858ded420SAlexey Kardashevskiy 
329fe26e527SAlexey Kardashevskiy 	npages = kvmppc_tce_pages(size);
330f8626985SAlexey Kardashevskiy 	ret = kvmppc_account_memlimit(kvmppc_stt_pages(npages), true);
33147c5310aSPaul Mackerras 	if (ret)
33247c5310aSPaul Mackerras 		return ret;
333f31e65e1SBenjamin Herrenschmidt 
3345982f084SWei Yongjun 	ret = -ENOMEM;
335f31e65e1SBenjamin Herrenschmidt 	stt = kzalloc(sizeof(*stt) + npages * sizeof(struct page *),
336f31e65e1SBenjamin Herrenschmidt 		      GFP_KERNEL);
337f31e65e1SBenjamin Herrenschmidt 	if (!stt)
33847c5310aSPaul Mackerras 		goto fail_acct;
339f31e65e1SBenjamin Herrenschmidt 
340f31e65e1SBenjamin Herrenschmidt 	stt->liobn = args->liobn;
34158ded420SAlexey Kardashevskiy 	stt->page_shift = args->page_shift;
34258ded420SAlexey Kardashevskiy 	stt->offset = args->offset;
343fe26e527SAlexey Kardashevskiy 	stt->size = size;
344f31e65e1SBenjamin Herrenschmidt 	stt->kvm = kvm;
345*e1a1ef84SAlexey Kardashevskiy 	mutex_init(&stt->alloc_lock);
346121f80baSAlexey Kardashevskiy 	INIT_LIST_HEAD_RCU(&stt->iommu_tables);
347f31e65e1SBenjamin Herrenschmidt 
348f31e65e1SBenjamin Herrenschmidt 	mutex_lock(&kvm->lock);
34947c5310aSPaul Mackerras 
35047c5310aSPaul Mackerras 	/* Check this LIOBN hasn't been previously allocated */
35147c5310aSPaul Mackerras 	ret = 0;
35247c5310aSPaul Mackerras 	list_for_each_entry(siter, &kvm->arch.spapr_tce_tables, list) {
35347c5310aSPaul Mackerras 		if (siter->liobn == args->liobn) {
35447c5310aSPaul Mackerras 			ret = -EBUSY;
35547c5310aSPaul Mackerras 			break;
35647c5310aSPaul Mackerras 		}
35747c5310aSPaul Mackerras 	}
35847c5310aSPaul Mackerras 
359716cb116SAlexey Kardashevskiy 	kvm_get_kvm(kvm);
360edd03602SPaul Mackerras 	if (!ret)
361edd03602SPaul Mackerras 		ret = anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops,
362edd03602SPaul Mackerras 				       stt, O_RDWR | O_CLOEXEC);
363edd03602SPaul Mackerras 
364716cb116SAlexey Kardashevskiy 	if (ret >= 0)
365366baf28SAlexey Kardashevskiy 		list_add_rcu(&stt->list, &kvm->arch.spapr_tce_tables);
366716cb116SAlexey Kardashevskiy 	else
367716cb116SAlexey Kardashevskiy 		kvm_put_kvm(kvm);
368f31e65e1SBenjamin Herrenschmidt 
369f31e65e1SBenjamin Herrenschmidt 	mutex_unlock(&kvm->lock);
370f31e65e1SBenjamin Herrenschmidt 
371edd03602SPaul Mackerras 	if (ret >= 0)
372edd03602SPaul Mackerras 		return ret;
373f31e65e1SBenjamin Herrenschmidt 
374f31e65e1SBenjamin Herrenschmidt 	kfree(stt);
37547c5310aSPaul Mackerras  fail_acct:
37647c5310aSPaul Mackerras 	kvmppc_account_memlimit(kvmppc_stt_pages(npages), false);
377f31e65e1SBenjamin Herrenschmidt 	return ret;
378f31e65e1SBenjamin Herrenschmidt }
379d3695aa4SAlexey Kardashevskiy 
3802001825eSAlexey Kardashevskiy static long kvmppc_tce_to_ua(struct kvm *kvm, unsigned long tce,
3812001825eSAlexey Kardashevskiy 		unsigned long *ua)
3822001825eSAlexey Kardashevskiy {
3832001825eSAlexey Kardashevskiy 	unsigned long gfn = tce >> PAGE_SHIFT;
3842001825eSAlexey Kardashevskiy 	struct kvm_memory_slot *memslot;
3852001825eSAlexey Kardashevskiy 
3862001825eSAlexey Kardashevskiy 	memslot = search_memslots(kvm_memslots(kvm), gfn);
3872001825eSAlexey Kardashevskiy 	if (!memslot)
3882001825eSAlexey Kardashevskiy 		return -EINVAL;
3892001825eSAlexey Kardashevskiy 
3902001825eSAlexey Kardashevskiy 	*ua = __gfn_to_hva_memslot(memslot, gfn) |
3912001825eSAlexey Kardashevskiy 		(tce & ~(PAGE_MASK | TCE_PCI_READ | TCE_PCI_WRITE));
3922001825eSAlexey Kardashevskiy 
3932001825eSAlexey Kardashevskiy 	return 0;
3942001825eSAlexey Kardashevskiy }
3952001825eSAlexey Kardashevskiy 
39642de7b9eSAlexey Kardashevskiy static long kvmppc_tce_validate(struct kvmppc_spapr_tce_table *stt,
39742de7b9eSAlexey Kardashevskiy 		unsigned long tce)
39842de7b9eSAlexey Kardashevskiy {
39942de7b9eSAlexey Kardashevskiy 	unsigned long gpa = tce & ~(TCE_PCI_READ | TCE_PCI_WRITE);
40042de7b9eSAlexey Kardashevskiy 	enum dma_data_direction dir = iommu_tce_direction(tce);
40142de7b9eSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit;
40242de7b9eSAlexey Kardashevskiy 	unsigned long ua = 0;
40342de7b9eSAlexey Kardashevskiy 
40442de7b9eSAlexey Kardashevskiy 	/* Allow userspace to poison TCE table */
40542de7b9eSAlexey Kardashevskiy 	if (dir == DMA_NONE)
40642de7b9eSAlexey Kardashevskiy 		return H_SUCCESS;
40742de7b9eSAlexey Kardashevskiy 
40842de7b9eSAlexey Kardashevskiy 	if (iommu_tce_check_gpa(stt->page_shift, gpa))
40942de7b9eSAlexey Kardashevskiy 		return H_TOO_HARD;
41042de7b9eSAlexey Kardashevskiy 
4112001825eSAlexey Kardashevskiy 	if (kvmppc_tce_to_ua(stt->kvm, tce, &ua))
41242de7b9eSAlexey Kardashevskiy 		return H_TOO_HARD;
41342de7b9eSAlexey Kardashevskiy 
41442de7b9eSAlexey Kardashevskiy 	list_for_each_entry_rcu(stit, &stt->iommu_tables, next) {
41542de7b9eSAlexey Kardashevskiy 		unsigned long hpa = 0;
41642de7b9eSAlexey Kardashevskiy 		struct mm_iommu_table_group_mem_t *mem;
41742de7b9eSAlexey Kardashevskiy 		long shift = stit->tbl->it_page_shift;
41842de7b9eSAlexey Kardashevskiy 
41942de7b9eSAlexey Kardashevskiy 		mem = mm_iommu_lookup(stt->kvm->mm, ua, 1ULL << shift);
42042de7b9eSAlexey Kardashevskiy 		if (!mem)
42142de7b9eSAlexey Kardashevskiy 			return H_TOO_HARD;
42242de7b9eSAlexey Kardashevskiy 
42342de7b9eSAlexey Kardashevskiy 		if (mm_iommu_ua_to_hpa(mem, ua, shift, &hpa))
42442de7b9eSAlexey Kardashevskiy 			return H_TOO_HARD;
42542de7b9eSAlexey Kardashevskiy 	}
42642de7b9eSAlexey Kardashevskiy 
42742de7b9eSAlexey Kardashevskiy 	return H_SUCCESS;
42842de7b9eSAlexey Kardashevskiy }
42942de7b9eSAlexey Kardashevskiy 
430*e1a1ef84SAlexey Kardashevskiy /*
431*e1a1ef84SAlexey Kardashevskiy  * Handles TCE requests for emulated devices.
432*e1a1ef84SAlexey Kardashevskiy  * Puts guest TCE values to the table and expects user space to convert them.
433*e1a1ef84SAlexey Kardashevskiy  * Cannot fail so kvmppc_tce_validate must be called before it.
434*e1a1ef84SAlexey Kardashevskiy  */
435*e1a1ef84SAlexey Kardashevskiy static void kvmppc_tce_put(struct kvmppc_spapr_tce_table *stt,
436*e1a1ef84SAlexey Kardashevskiy 		unsigned long idx, unsigned long tce)
437*e1a1ef84SAlexey Kardashevskiy {
438*e1a1ef84SAlexey Kardashevskiy 	struct page *page;
439*e1a1ef84SAlexey Kardashevskiy 	u64 *tbl;
440*e1a1ef84SAlexey Kardashevskiy 	unsigned long sttpage;
441*e1a1ef84SAlexey Kardashevskiy 
442*e1a1ef84SAlexey Kardashevskiy 	idx -= stt->offset;
443*e1a1ef84SAlexey Kardashevskiy 	sttpage = idx / TCES_PER_PAGE;
444*e1a1ef84SAlexey Kardashevskiy 	page = stt->pages[sttpage];
445*e1a1ef84SAlexey Kardashevskiy 
446*e1a1ef84SAlexey Kardashevskiy 	if (!page) {
447*e1a1ef84SAlexey Kardashevskiy 		/* We allow any TCE, not just with read|write permissions */
448*e1a1ef84SAlexey Kardashevskiy 		if (!tce)
449*e1a1ef84SAlexey Kardashevskiy 			return;
450*e1a1ef84SAlexey Kardashevskiy 
451*e1a1ef84SAlexey Kardashevskiy 		page = kvm_spapr_get_tce_page(stt, sttpage);
452*e1a1ef84SAlexey Kardashevskiy 		if (!page)
453*e1a1ef84SAlexey Kardashevskiy 			return;
454*e1a1ef84SAlexey Kardashevskiy 	}
455*e1a1ef84SAlexey Kardashevskiy 	tbl = page_to_virt(page);
456*e1a1ef84SAlexey Kardashevskiy 
457*e1a1ef84SAlexey Kardashevskiy 	tbl[idx % TCES_PER_PAGE] = tce;
458*e1a1ef84SAlexey Kardashevskiy }
459*e1a1ef84SAlexey Kardashevskiy 
460c10c21efSAlexey Kardashevskiy static void kvmppc_clear_tce(struct mm_struct *mm, struct iommu_table *tbl,
461c10c21efSAlexey Kardashevskiy 		unsigned long entry)
462121f80baSAlexey Kardashevskiy {
463121f80baSAlexey Kardashevskiy 	unsigned long hpa = 0;
464121f80baSAlexey Kardashevskiy 	enum dma_data_direction dir = DMA_NONE;
465121f80baSAlexey Kardashevskiy 
466c10c21efSAlexey Kardashevskiy 	iommu_tce_xchg(mm, tbl, entry, &hpa, &dir);
467121f80baSAlexey Kardashevskiy }
468121f80baSAlexey Kardashevskiy 
469121f80baSAlexey Kardashevskiy static long kvmppc_tce_iommu_mapped_dec(struct kvm *kvm,
470121f80baSAlexey Kardashevskiy 		struct iommu_table *tbl, unsigned long entry)
471121f80baSAlexey Kardashevskiy {
472121f80baSAlexey Kardashevskiy 	struct mm_iommu_table_group_mem_t *mem = NULL;
473121f80baSAlexey Kardashevskiy 	const unsigned long pgsize = 1ULL << tbl->it_page_shift;
4746e301a8eSAlexey Kardashevskiy 	__be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY_RO(tbl, entry);
475121f80baSAlexey Kardashevskiy 
476121f80baSAlexey Kardashevskiy 	if (!pua)
4776e301a8eSAlexey Kardashevskiy 		return H_SUCCESS;
478121f80baSAlexey Kardashevskiy 
47900a5c58dSAlexey Kardashevskiy 	mem = mm_iommu_lookup(kvm->mm, be64_to_cpu(*pua), pgsize);
480121f80baSAlexey Kardashevskiy 	if (!mem)
481121f80baSAlexey Kardashevskiy 		return H_TOO_HARD;
482121f80baSAlexey Kardashevskiy 
483121f80baSAlexey Kardashevskiy 	mm_iommu_mapped_dec(mem);
484121f80baSAlexey Kardashevskiy 
48500a5c58dSAlexey Kardashevskiy 	*pua = cpu_to_be64(0);
486121f80baSAlexey Kardashevskiy 
487121f80baSAlexey Kardashevskiy 	return H_SUCCESS;
488121f80baSAlexey Kardashevskiy }
489121f80baSAlexey Kardashevskiy 
490ca1fc489SAlexey Kardashevskiy static long kvmppc_tce_iommu_do_unmap(struct kvm *kvm,
491121f80baSAlexey Kardashevskiy 		struct iommu_table *tbl, unsigned long entry)
492121f80baSAlexey Kardashevskiy {
493121f80baSAlexey Kardashevskiy 	enum dma_data_direction dir = DMA_NONE;
494121f80baSAlexey Kardashevskiy 	unsigned long hpa = 0;
495121f80baSAlexey Kardashevskiy 	long ret;
496121f80baSAlexey Kardashevskiy 
497c10c21efSAlexey Kardashevskiy 	if (WARN_ON_ONCE(iommu_tce_xchg(kvm->mm, tbl, entry, &hpa, &dir)))
498f7960e29SAlexey Kardashevskiy 		return H_TOO_HARD;
499121f80baSAlexey Kardashevskiy 
500121f80baSAlexey Kardashevskiy 	if (dir == DMA_NONE)
501121f80baSAlexey Kardashevskiy 		return H_SUCCESS;
502121f80baSAlexey Kardashevskiy 
503121f80baSAlexey Kardashevskiy 	ret = kvmppc_tce_iommu_mapped_dec(kvm, tbl, entry);
504121f80baSAlexey Kardashevskiy 	if (ret != H_SUCCESS)
505c10c21efSAlexey Kardashevskiy 		iommu_tce_xchg(kvm->mm, tbl, entry, &hpa, &dir);
506121f80baSAlexey Kardashevskiy 
507121f80baSAlexey Kardashevskiy 	return ret;
508121f80baSAlexey Kardashevskiy }
509121f80baSAlexey Kardashevskiy 
510ca1fc489SAlexey Kardashevskiy static long kvmppc_tce_iommu_unmap(struct kvm *kvm,
511ca1fc489SAlexey Kardashevskiy 		struct kvmppc_spapr_tce_table *stt, struct iommu_table *tbl,
512ca1fc489SAlexey Kardashevskiy 		unsigned long entry)
513ca1fc489SAlexey Kardashevskiy {
514ca1fc489SAlexey Kardashevskiy 	unsigned long i, ret = H_SUCCESS;
515ca1fc489SAlexey Kardashevskiy 	unsigned long subpages = 1ULL << (stt->page_shift - tbl->it_page_shift);
516ca1fc489SAlexey Kardashevskiy 	unsigned long io_entry = entry * subpages;
517ca1fc489SAlexey Kardashevskiy 
518ca1fc489SAlexey Kardashevskiy 	for (i = 0; i < subpages; ++i) {
519ca1fc489SAlexey Kardashevskiy 		ret = kvmppc_tce_iommu_do_unmap(kvm, tbl, io_entry + i);
520ca1fc489SAlexey Kardashevskiy 		if (ret != H_SUCCESS)
521ca1fc489SAlexey Kardashevskiy 			break;
522ca1fc489SAlexey Kardashevskiy 	}
523ca1fc489SAlexey Kardashevskiy 
524ca1fc489SAlexey Kardashevskiy 	return ret;
525ca1fc489SAlexey Kardashevskiy }
526ca1fc489SAlexey Kardashevskiy 
527ca1fc489SAlexey Kardashevskiy long kvmppc_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl,
528121f80baSAlexey Kardashevskiy 		unsigned long entry, unsigned long ua,
529121f80baSAlexey Kardashevskiy 		enum dma_data_direction dir)
530121f80baSAlexey Kardashevskiy {
531121f80baSAlexey Kardashevskiy 	long ret;
53200a5c58dSAlexey Kardashevskiy 	unsigned long hpa;
53300a5c58dSAlexey Kardashevskiy 	__be64 *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry);
534121f80baSAlexey Kardashevskiy 	struct mm_iommu_table_group_mem_t *mem;
535121f80baSAlexey Kardashevskiy 
536121f80baSAlexey Kardashevskiy 	if (!pua)
537121f80baSAlexey Kardashevskiy 		/* it_userspace allocation might be delayed */
538121f80baSAlexey Kardashevskiy 		return H_TOO_HARD;
539121f80baSAlexey Kardashevskiy 
540121f80baSAlexey Kardashevskiy 	mem = mm_iommu_lookup(kvm->mm, ua, 1ULL << tbl->it_page_shift);
541121f80baSAlexey Kardashevskiy 	if (!mem)
542121f80baSAlexey Kardashevskiy 		/* This only handles v2 IOMMU type, v1 is handled via ioctl() */
543121f80baSAlexey Kardashevskiy 		return H_TOO_HARD;
544121f80baSAlexey Kardashevskiy 
54576fa4975SAlexey Kardashevskiy 	if (WARN_ON_ONCE(mm_iommu_ua_to_hpa(mem, ua, tbl->it_page_shift, &hpa)))
546f7960e29SAlexey Kardashevskiy 		return H_TOO_HARD;
547121f80baSAlexey Kardashevskiy 
548121f80baSAlexey Kardashevskiy 	if (mm_iommu_mapped_inc(mem))
549f7960e29SAlexey Kardashevskiy 		return H_TOO_HARD;
550121f80baSAlexey Kardashevskiy 
551c10c21efSAlexey Kardashevskiy 	ret = iommu_tce_xchg(kvm->mm, tbl, entry, &hpa, &dir);
552121f80baSAlexey Kardashevskiy 	if (WARN_ON_ONCE(ret)) {
553121f80baSAlexey Kardashevskiy 		mm_iommu_mapped_dec(mem);
554f7960e29SAlexey Kardashevskiy 		return H_TOO_HARD;
555121f80baSAlexey Kardashevskiy 	}
556121f80baSAlexey Kardashevskiy 
557121f80baSAlexey Kardashevskiy 	if (dir != DMA_NONE)
558121f80baSAlexey Kardashevskiy 		kvmppc_tce_iommu_mapped_dec(kvm, tbl, entry);
559121f80baSAlexey Kardashevskiy 
56000a5c58dSAlexey Kardashevskiy 	*pua = cpu_to_be64(ua);
561121f80baSAlexey Kardashevskiy 
562121f80baSAlexey Kardashevskiy 	return 0;
563121f80baSAlexey Kardashevskiy }
564121f80baSAlexey Kardashevskiy 
565ca1fc489SAlexey Kardashevskiy static long kvmppc_tce_iommu_map(struct kvm *kvm,
566ca1fc489SAlexey Kardashevskiy 		struct kvmppc_spapr_tce_table *stt, struct iommu_table *tbl,
567ca1fc489SAlexey Kardashevskiy 		unsigned long entry, unsigned long ua,
568ca1fc489SAlexey Kardashevskiy 		enum dma_data_direction dir)
569ca1fc489SAlexey Kardashevskiy {
570ca1fc489SAlexey Kardashevskiy 	unsigned long i, pgoff, ret = H_SUCCESS;
571ca1fc489SAlexey Kardashevskiy 	unsigned long subpages = 1ULL << (stt->page_shift - tbl->it_page_shift);
572ca1fc489SAlexey Kardashevskiy 	unsigned long io_entry = entry * subpages;
573ca1fc489SAlexey Kardashevskiy 
574ca1fc489SAlexey Kardashevskiy 	for (i = 0, pgoff = 0; i < subpages;
575ca1fc489SAlexey Kardashevskiy 			++i, pgoff += IOMMU_PAGE_SIZE(tbl)) {
576ca1fc489SAlexey Kardashevskiy 
577ca1fc489SAlexey Kardashevskiy 		ret = kvmppc_tce_iommu_do_map(kvm, tbl,
578ca1fc489SAlexey Kardashevskiy 				io_entry + i, ua + pgoff, dir);
579ca1fc489SAlexey Kardashevskiy 		if (ret != H_SUCCESS)
580ca1fc489SAlexey Kardashevskiy 			break;
581ca1fc489SAlexey Kardashevskiy 	}
582ca1fc489SAlexey Kardashevskiy 
583ca1fc489SAlexey Kardashevskiy 	return ret;
584ca1fc489SAlexey Kardashevskiy }
585ca1fc489SAlexey Kardashevskiy 
58631217db7SAlexey Kardashevskiy long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
58731217db7SAlexey Kardashevskiy 		      unsigned long ioba, unsigned long tce)
58831217db7SAlexey Kardashevskiy {
589503bfcbeSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt;
590121f80baSAlexey Kardashevskiy 	long ret, idx;
591121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit;
592121f80baSAlexey Kardashevskiy 	unsigned long entry, ua = 0;
593121f80baSAlexey Kardashevskiy 	enum dma_data_direction dir;
59431217db7SAlexey Kardashevskiy 
59531217db7SAlexey Kardashevskiy 	/* udbg_printf("H_PUT_TCE(): liobn=0x%lx ioba=0x%lx, tce=0x%lx\n", */
59631217db7SAlexey Kardashevskiy 	/* 	    liobn, ioba, tce); */
59731217db7SAlexey Kardashevskiy 
598503bfcbeSAlexey Kardashevskiy 	stt = kvmppc_find_table(vcpu->kvm, liobn);
59931217db7SAlexey Kardashevskiy 	if (!stt)
60031217db7SAlexey Kardashevskiy 		return H_TOO_HARD;
60131217db7SAlexey Kardashevskiy 
60231217db7SAlexey Kardashevskiy 	ret = kvmppc_ioba_validate(stt, ioba, 1);
60331217db7SAlexey Kardashevskiy 	if (ret != H_SUCCESS)
60431217db7SAlexey Kardashevskiy 		return ret;
60531217db7SAlexey Kardashevskiy 
606345077c8SAlexey Kardashevskiy 	idx = srcu_read_lock(&vcpu->kvm->srcu);
607345077c8SAlexey Kardashevskiy 
60831217db7SAlexey Kardashevskiy 	ret = kvmppc_tce_validate(stt, tce);
60931217db7SAlexey Kardashevskiy 	if (ret != H_SUCCESS)
610345077c8SAlexey Kardashevskiy 		goto unlock_exit;
61131217db7SAlexey Kardashevskiy 
612121f80baSAlexey Kardashevskiy 	dir = iommu_tce_direction(tce);
6138f6a9f0dSAlexey Kardashevskiy 
6142001825eSAlexey Kardashevskiy 	if ((dir != DMA_NONE) && kvmppc_tce_to_ua(vcpu->kvm, tce, &ua)) {
6158f6a9f0dSAlexey Kardashevskiy 		ret = H_PARAMETER;
6168f6a9f0dSAlexey Kardashevskiy 		goto unlock_exit;
6178f6a9f0dSAlexey Kardashevskiy 	}
618121f80baSAlexey Kardashevskiy 
619121f80baSAlexey Kardashevskiy 	entry = ioba >> stt->page_shift;
620121f80baSAlexey Kardashevskiy 
621121f80baSAlexey Kardashevskiy 	list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
6228f6a9f0dSAlexey Kardashevskiy 		if (dir == DMA_NONE)
623ca1fc489SAlexey Kardashevskiy 			ret = kvmppc_tce_iommu_unmap(vcpu->kvm, stt,
624121f80baSAlexey Kardashevskiy 					stit->tbl, entry);
6258f6a9f0dSAlexey Kardashevskiy 		else
626ca1fc489SAlexey Kardashevskiy 			ret = kvmppc_tce_iommu_map(vcpu->kvm, stt, stit->tbl,
627121f80baSAlexey Kardashevskiy 					entry, ua, dir);
628121f80baSAlexey Kardashevskiy 
6292691f0ffSAlexey Kardashevskiy 		if (ret != H_SUCCESS) {
630c10c21efSAlexey Kardashevskiy 			kvmppc_clear_tce(vcpu->kvm->mm, stit->tbl, entry);
6312691f0ffSAlexey Kardashevskiy 			goto unlock_exit;
6322691f0ffSAlexey Kardashevskiy 		}
633121f80baSAlexey Kardashevskiy 	}
634121f80baSAlexey Kardashevskiy 
635121f80baSAlexey Kardashevskiy 	kvmppc_tce_put(stt, entry, tce);
63631217db7SAlexey Kardashevskiy 
6378f6a9f0dSAlexey Kardashevskiy unlock_exit:
6388f6a9f0dSAlexey Kardashevskiy 	srcu_read_unlock(&vcpu->kvm->srcu, idx);
6398f6a9f0dSAlexey Kardashevskiy 
6408f6a9f0dSAlexey Kardashevskiy 	return ret;
64131217db7SAlexey Kardashevskiy }
64231217db7SAlexey Kardashevskiy EXPORT_SYMBOL_GPL(kvmppc_h_put_tce);
64331217db7SAlexey Kardashevskiy 
644d3695aa4SAlexey Kardashevskiy long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu,
645d3695aa4SAlexey Kardashevskiy 		unsigned long liobn, unsigned long ioba,
646d3695aa4SAlexey Kardashevskiy 		unsigned long tce_list, unsigned long npages)
647d3695aa4SAlexey Kardashevskiy {
648d3695aa4SAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt;
649d3695aa4SAlexey Kardashevskiy 	long i, ret = H_SUCCESS, idx;
650d3695aa4SAlexey Kardashevskiy 	unsigned long entry, ua = 0;
651f8750513SDaniel Axtens 	u64 __user *tces;
652f8750513SDaniel Axtens 	u64 tce;
653121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit;
654d3695aa4SAlexey Kardashevskiy 
655503bfcbeSAlexey Kardashevskiy 	stt = kvmppc_find_table(vcpu->kvm, liobn);
656d3695aa4SAlexey Kardashevskiy 	if (!stt)
657d3695aa4SAlexey Kardashevskiy 		return H_TOO_HARD;
658d3695aa4SAlexey Kardashevskiy 
659fe26e527SAlexey Kardashevskiy 	entry = ioba >> stt->page_shift;
660d3695aa4SAlexey Kardashevskiy 	/*
661d3695aa4SAlexey Kardashevskiy 	 * SPAPR spec says that the maximum size of the list is 512 TCEs
662d3695aa4SAlexey Kardashevskiy 	 * so the whole table fits in 4K page
663d3695aa4SAlexey Kardashevskiy 	 */
664d3695aa4SAlexey Kardashevskiy 	if (npages > 512)
665d3695aa4SAlexey Kardashevskiy 		return H_PARAMETER;
666d3695aa4SAlexey Kardashevskiy 
667d3695aa4SAlexey Kardashevskiy 	if (tce_list & (SZ_4K - 1))
668d3695aa4SAlexey Kardashevskiy 		return H_PARAMETER;
669d3695aa4SAlexey Kardashevskiy 
670d3695aa4SAlexey Kardashevskiy 	ret = kvmppc_ioba_validate(stt, ioba, npages);
671d3695aa4SAlexey Kardashevskiy 	if (ret != H_SUCCESS)
672d3695aa4SAlexey Kardashevskiy 		return ret;
673d3695aa4SAlexey Kardashevskiy 
674d3695aa4SAlexey Kardashevskiy 	idx = srcu_read_lock(&vcpu->kvm->srcu);
6752001825eSAlexey Kardashevskiy 	if (kvmppc_tce_to_ua(vcpu->kvm, tce_list, &ua)) {
676d3695aa4SAlexey Kardashevskiy 		ret = H_TOO_HARD;
677d3695aa4SAlexey Kardashevskiy 		goto unlock_exit;
678d3695aa4SAlexey Kardashevskiy 	}
679d3695aa4SAlexey Kardashevskiy 	tces = (u64 __user *) ua;
680d3695aa4SAlexey Kardashevskiy 
681d3695aa4SAlexey Kardashevskiy 	for (i = 0; i < npages; ++i) {
682d3695aa4SAlexey Kardashevskiy 		if (get_user(tce, tces + i)) {
683d3695aa4SAlexey Kardashevskiy 			ret = H_TOO_HARD;
684d3695aa4SAlexey Kardashevskiy 			goto unlock_exit;
685d3695aa4SAlexey Kardashevskiy 		}
686d3695aa4SAlexey Kardashevskiy 		tce = be64_to_cpu(tce);
687d3695aa4SAlexey Kardashevskiy 
688d3695aa4SAlexey Kardashevskiy 		ret = kvmppc_tce_validate(stt, tce);
689d3695aa4SAlexey Kardashevskiy 		if (ret != H_SUCCESS)
690d3695aa4SAlexey Kardashevskiy 			goto unlock_exit;
691e199ad2bSAlexey Kardashevskiy 	}
692e199ad2bSAlexey Kardashevskiy 
693e199ad2bSAlexey Kardashevskiy 	for (i = 0; i < npages; ++i) {
694e199ad2bSAlexey Kardashevskiy 		/*
695e199ad2bSAlexey Kardashevskiy 		 * This looks unsafe, because we validate, then regrab
696e199ad2bSAlexey Kardashevskiy 		 * the TCE from userspace which could have been changed by
697e199ad2bSAlexey Kardashevskiy 		 * another thread.
698e199ad2bSAlexey Kardashevskiy 		 *
699e199ad2bSAlexey Kardashevskiy 		 * But it actually is safe, because the relevant checks will be
700e199ad2bSAlexey Kardashevskiy 		 * re-executed in the following code.  If userspace tries to
701e199ad2bSAlexey Kardashevskiy 		 * change this dodgily it will result in a messier failure mode
702e199ad2bSAlexey Kardashevskiy 		 * but won't threaten the host.
703e199ad2bSAlexey Kardashevskiy 		 */
704e199ad2bSAlexey Kardashevskiy 		if (get_user(tce, tces + i)) {
705e199ad2bSAlexey Kardashevskiy 			ret = H_TOO_HARD;
706e199ad2bSAlexey Kardashevskiy 			goto unlock_exit;
707e199ad2bSAlexey Kardashevskiy 		}
708e199ad2bSAlexey Kardashevskiy 		tce = be64_to_cpu(tce);
709d3695aa4SAlexey Kardashevskiy 
7102001825eSAlexey Kardashevskiy 		if (kvmppc_tce_to_ua(vcpu->kvm, tce, &ua))
711121f80baSAlexey Kardashevskiy 			return H_PARAMETER;
712121f80baSAlexey Kardashevskiy 
713121f80baSAlexey Kardashevskiy 		list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
714ca1fc489SAlexey Kardashevskiy 			ret = kvmppc_tce_iommu_map(vcpu->kvm, stt,
715121f80baSAlexey Kardashevskiy 					stit->tbl, entry + i, ua,
716121f80baSAlexey Kardashevskiy 					iommu_tce_direction(tce));
717121f80baSAlexey Kardashevskiy 
7182691f0ffSAlexey Kardashevskiy 			if (ret != H_SUCCESS) {
719c10c21efSAlexey Kardashevskiy 				kvmppc_clear_tce(vcpu->kvm->mm, stit->tbl,
720c10c21efSAlexey Kardashevskiy 						entry);
7212691f0ffSAlexey Kardashevskiy 				goto unlock_exit;
7222691f0ffSAlexey Kardashevskiy 			}
723121f80baSAlexey Kardashevskiy 		}
724121f80baSAlexey Kardashevskiy 
725d3695aa4SAlexey Kardashevskiy 		kvmppc_tce_put(stt, entry + i, tce);
726d3695aa4SAlexey Kardashevskiy 	}
727d3695aa4SAlexey Kardashevskiy 
728d3695aa4SAlexey Kardashevskiy unlock_exit:
729d3695aa4SAlexey Kardashevskiy 	srcu_read_unlock(&vcpu->kvm->srcu, idx);
730d3695aa4SAlexey Kardashevskiy 
731d3695aa4SAlexey Kardashevskiy 	return ret;
732d3695aa4SAlexey Kardashevskiy }
733d3695aa4SAlexey Kardashevskiy EXPORT_SYMBOL_GPL(kvmppc_h_put_tce_indirect);
73431217db7SAlexey Kardashevskiy 
73531217db7SAlexey Kardashevskiy long kvmppc_h_stuff_tce(struct kvm_vcpu *vcpu,
73631217db7SAlexey Kardashevskiy 		unsigned long liobn, unsigned long ioba,
73731217db7SAlexey Kardashevskiy 		unsigned long tce_value, unsigned long npages)
73831217db7SAlexey Kardashevskiy {
73931217db7SAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt;
74031217db7SAlexey Kardashevskiy 	long i, ret;
741121f80baSAlexey Kardashevskiy 	struct kvmppc_spapr_tce_iommu_table *stit;
74231217db7SAlexey Kardashevskiy 
743503bfcbeSAlexey Kardashevskiy 	stt = kvmppc_find_table(vcpu->kvm, liobn);
74431217db7SAlexey Kardashevskiy 	if (!stt)
74531217db7SAlexey Kardashevskiy 		return H_TOO_HARD;
74631217db7SAlexey Kardashevskiy 
74731217db7SAlexey Kardashevskiy 	ret = kvmppc_ioba_validate(stt, ioba, npages);
74831217db7SAlexey Kardashevskiy 	if (ret != H_SUCCESS)
74931217db7SAlexey Kardashevskiy 		return ret;
75031217db7SAlexey Kardashevskiy 
75131217db7SAlexey Kardashevskiy 	/* Check permission bits only to allow userspace poison TCE for debug */
75231217db7SAlexey Kardashevskiy 	if (tce_value & (TCE_PCI_WRITE | TCE_PCI_READ))
75331217db7SAlexey Kardashevskiy 		return H_PARAMETER;
75431217db7SAlexey Kardashevskiy 
755121f80baSAlexey Kardashevskiy 	list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
756c6b61661SAlexey Kardashevskiy 		unsigned long entry = ioba >> stt->page_shift;
757121f80baSAlexey Kardashevskiy 
758121f80baSAlexey Kardashevskiy 		for (i = 0; i < npages; ++i) {
759ca1fc489SAlexey Kardashevskiy 			ret = kvmppc_tce_iommu_unmap(vcpu->kvm, stt,
760121f80baSAlexey Kardashevskiy 					stit->tbl, entry + i);
761121f80baSAlexey Kardashevskiy 
762121f80baSAlexey Kardashevskiy 			if (ret == H_SUCCESS)
763121f80baSAlexey Kardashevskiy 				continue;
764121f80baSAlexey Kardashevskiy 
765121f80baSAlexey Kardashevskiy 			if (ret == H_TOO_HARD)
766121f80baSAlexey Kardashevskiy 				return ret;
767121f80baSAlexey Kardashevskiy 
768121f80baSAlexey Kardashevskiy 			WARN_ON_ONCE(1);
769c10c21efSAlexey Kardashevskiy 			kvmppc_clear_tce(vcpu->kvm->mm, stit->tbl, entry);
770121f80baSAlexey Kardashevskiy 		}
771121f80baSAlexey Kardashevskiy 	}
772121f80baSAlexey Kardashevskiy 
77331217db7SAlexey Kardashevskiy 	for (i = 0; i < npages; ++i, ioba += (1ULL << stt->page_shift))
77431217db7SAlexey Kardashevskiy 		kvmppc_tce_put(stt, ioba >> stt->page_shift, tce_value);
77531217db7SAlexey Kardashevskiy 
77631217db7SAlexey Kardashevskiy 	return H_SUCCESS;
77731217db7SAlexey Kardashevskiy }
77831217db7SAlexey Kardashevskiy EXPORT_SYMBOL_GPL(kvmppc_h_stuff_tce);
779