xref: /linux/arch/powerpc/kvm/book3s_64_vio.c (revision 3762d45aa71d546cc0afa29da2f1cd360c099484)
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>
31f31e65e1SBenjamin Herrenschmidt 
32f31e65e1SBenjamin Herrenschmidt #include <asm/tlbflush.h>
33f31e65e1SBenjamin Herrenschmidt #include <asm/kvm_ppc.h>
34f31e65e1SBenjamin Herrenschmidt #include <asm/kvm_book3s.h>
35f64e8084SAneesh Kumar K.V #include <asm/book3s/64/mmu-hash.h>
36f31e65e1SBenjamin Herrenschmidt #include <asm/hvcall.h>
37f31e65e1SBenjamin Herrenschmidt #include <asm/synch.h>
38f31e65e1SBenjamin Herrenschmidt #include <asm/ppc-opcode.h>
39f31e65e1SBenjamin Herrenschmidt #include <asm/kvm_host.h>
40f31e65e1SBenjamin Herrenschmidt #include <asm/udbg.h>
41462ee11eSAlexey Kardashevskiy #include <asm/iommu.h>
42d3695aa4SAlexey Kardashevskiy #include <asm/tce.h>
43f31e65e1SBenjamin Herrenschmidt 
44fe26e527SAlexey Kardashevskiy static unsigned long kvmppc_tce_pages(unsigned long iommu_pages)
45f31e65e1SBenjamin Herrenschmidt {
46fe26e527SAlexey Kardashevskiy 	return ALIGN(iommu_pages * sizeof(u64), PAGE_SIZE) / PAGE_SIZE;
47f31e65e1SBenjamin Herrenschmidt }
48f31e65e1SBenjamin Herrenschmidt 
49f8626985SAlexey Kardashevskiy static unsigned long kvmppc_stt_pages(unsigned long tce_pages)
50f8626985SAlexey Kardashevskiy {
51f8626985SAlexey Kardashevskiy 	unsigned long stt_bytes = sizeof(struct kvmppc_spapr_tce_table) +
52f8626985SAlexey Kardashevskiy 			(tce_pages * sizeof(struct page *));
53f8626985SAlexey Kardashevskiy 
54f8626985SAlexey Kardashevskiy 	return tce_pages + ALIGN(stt_bytes, PAGE_SIZE) / PAGE_SIZE;
55f8626985SAlexey Kardashevskiy }
56f8626985SAlexey Kardashevskiy 
57f8626985SAlexey Kardashevskiy static long kvmppc_account_memlimit(unsigned long stt_pages, bool inc)
58f8626985SAlexey Kardashevskiy {
59f8626985SAlexey Kardashevskiy 	long ret = 0;
60f8626985SAlexey Kardashevskiy 
61f8626985SAlexey Kardashevskiy 	if (!current || !current->mm)
62f8626985SAlexey Kardashevskiy 		return ret; /* process exited */
63f8626985SAlexey Kardashevskiy 
64f8626985SAlexey Kardashevskiy 	down_write(&current->mm->mmap_sem);
65f8626985SAlexey Kardashevskiy 
66f8626985SAlexey Kardashevskiy 	if (inc) {
67f8626985SAlexey Kardashevskiy 		unsigned long locked, lock_limit;
68f8626985SAlexey Kardashevskiy 
69f8626985SAlexey Kardashevskiy 		locked = current->mm->locked_vm + stt_pages;
70f8626985SAlexey Kardashevskiy 		lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
71f8626985SAlexey Kardashevskiy 		if (locked > lock_limit && !capable(CAP_IPC_LOCK))
72f8626985SAlexey Kardashevskiy 			ret = -ENOMEM;
73f8626985SAlexey Kardashevskiy 		else
74f8626985SAlexey Kardashevskiy 			current->mm->locked_vm += stt_pages;
75f8626985SAlexey Kardashevskiy 	} else {
76f8626985SAlexey Kardashevskiy 		if (WARN_ON_ONCE(stt_pages > current->mm->locked_vm))
77f8626985SAlexey Kardashevskiy 			stt_pages = current->mm->locked_vm;
78f8626985SAlexey Kardashevskiy 
79f8626985SAlexey Kardashevskiy 		current->mm->locked_vm -= stt_pages;
80f8626985SAlexey Kardashevskiy 	}
81f8626985SAlexey Kardashevskiy 
82f8626985SAlexey Kardashevskiy 	pr_debug("[%d] RLIMIT_MEMLOCK KVM %c%ld %ld/%ld%s\n", current->pid,
83f8626985SAlexey Kardashevskiy 			inc ? '+' : '-',
84f8626985SAlexey Kardashevskiy 			stt_pages << PAGE_SHIFT,
85f8626985SAlexey Kardashevskiy 			current->mm->locked_vm << PAGE_SHIFT,
86f8626985SAlexey Kardashevskiy 			rlimit(RLIMIT_MEMLOCK),
87f8626985SAlexey Kardashevskiy 			ret ? " - exceeded" : "");
88f8626985SAlexey Kardashevskiy 
89f8626985SAlexey Kardashevskiy 	up_write(&current->mm->mmap_sem);
90f8626985SAlexey Kardashevskiy 
91f8626985SAlexey Kardashevskiy 	return ret;
92f8626985SAlexey Kardashevskiy }
93f8626985SAlexey Kardashevskiy 
94366baf28SAlexey Kardashevskiy static void release_spapr_tce_table(struct rcu_head *head)
95f31e65e1SBenjamin Herrenschmidt {
96366baf28SAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt = container_of(head,
97366baf28SAlexey Kardashevskiy 			struct kvmppc_spapr_tce_table, rcu);
98fe26e527SAlexey Kardashevskiy 	unsigned long i, npages = kvmppc_tce_pages(stt->size);
99f31e65e1SBenjamin Herrenschmidt 
100f8626985SAlexey Kardashevskiy 	for (i = 0; i < npages; i++)
101f31e65e1SBenjamin Herrenschmidt 		__free_page(stt->pages[i]);
102f31e65e1SBenjamin Herrenschmidt 
103366baf28SAlexey Kardashevskiy 	kfree(stt);
104f31e65e1SBenjamin Herrenschmidt }
105f31e65e1SBenjamin Herrenschmidt 
10611bac800SDave Jiang static int kvm_spapr_tce_fault(struct vm_fault *vmf)
107f31e65e1SBenjamin Herrenschmidt {
10811bac800SDave Jiang 	struct kvmppc_spapr_tce_table *stt = vmf->vma->vm_file->private_data;
109f31e65e1SBenjamin Herrenschmidt 	struct page *page;
110f31e65e1SBenjamin Herrenschmidt 
111fe26e527SAlexey Kardashevskiy 	if (vmf->pgoff >= kvmppc_tce_pages(stt->size))
112f31e65e1SBenjamin Herrenschmidt 		return VM_FAULT_SIGBUS;
113f31e65e1SBenjamin Herrenschmidt 
114f31e65e1SBenjamin Herrenschmidt 	page = stt->pages[vmf->pgoff];
115f31e65e1SBenjamin Herrenschmidt 	get_page(page);
116f31e65e1SBenjamin Herrenschmidt 	vmf->page = page;
117f31e65e1SBenjamin Herrenschmidt 	return 0;
118f31e65e1SBenjamin Herrenschmidt }
119f31e65e1SBenjamin Herrenschmidt 
120f31e65e1SBenjamin Herrenschmidt static const struct vm_operations_struct kvm_spapr_tce_vm_ops = {
121f31e65e1SBenjamin Herrenschmidt 	.fault = kvm_spapr_tce_fault,
122f31e65e1SBenjamin Herrenschmidt };
123f31e65e1SBenjamin Herrenschmidt 
124f31e65e1SBenjamin Herrenschmidt static int kvm_spapr_tce_mmap(struct file *file, struct vm_area_struct *vma)
125f31e65e1SBenjamin Herrenschmidt {
126f31e65e1SBenjamin Herrenschmidt 	vma->vm_ops = &kvm_spapr_tce_vm_ops;
127f31e65e1SBenjamin Herrenschmidt 	return 0;
128f31e65e1SBenjamin Herrenschmidt }
129f31e65e1SBenjamin Herrenschmidt 
130f31e65e1SBenjamin Herrenschmidt static int kvm_spapr_tce_release(struct inode *inode, struct file *filp)
131f31e65e1SBenjamin Herrenschmidt {
132f31e65e1SBenjamin Herrenschmidt 	struct kvmppc_spapr_tce_table *stt = filp->private_data;
133f31e65e1SBenjamin Herrenschmidt 
134366baf28SAlexey Kardashevskiy 	list_del_rcu(&stt->list);
135366baf28SAlexey Kardashevskiy 
136366baf28SAlexey Kardashevskiy 	kvm_put_kvm(stt->kvm);
137366baf28SAlexey Kardashevskiy 
138f8626985SAlexey Kardashevskiy 	kvmppc_account_memlimit(
139fe26e527SAlexey Kardashevskiy 		kvmppc_stt_pages(kvmppc_tce_pages(stt->size)), false);
140366baf28SAlexey Kardashevskiy 	call_rcu(&stt->rcu, release_spapr_tce_table);
141366baf28SAlexey Kardashevskiy 
142f31e65e1SBenjamin Herrenschmidt 	return 0;
143f31e65e1SBenjamin Herrenschmidt }
144f31e65e1SBenjamin Herrenschmidt 
14575ef9de1SAl Viro static const struct file_operations kvm_spapr_tce_fops = {
146f31e65e1SBenjamin Herrenschmidt 	.mmap           = kvm_spapr_tce_mmap,
147f31e65e1SBenjamin Herrenschmidt 	.release	= kvm_spapr_tce_release,
148f31e65e1SBenjamin Herrenschmidt };
149f31e65e1SBenjamin Herrenschmidt 
150f31e65e1SBenjamin Herrenschmidt long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
15158ded420SAlexey Kardashevskiy 				   struct kvm_create_spapr_tce_64 *args)
152f31e65e1SBenjamin Herrenschmidt {
153f31e65e1SBenjamin Herrenschmidt 	struct kvmppc_spapr_tce_table *stt = NULL;
154fe26e527SAlexey Kardashevskiy 	unsigned long npages, size;
155f31e65e1SBenjamin Herrenschmidt 	int ret = -ENOMEM;
156f31e65e1SBenjamin Herrenschmidt 	int i;
157f31e65e1SBenjamin Herrenschmidt 
15858ded420SAlexey Kardashevskiy 	if (!args->size)
15958ded420SAlexey Kardashevskiy 		return -EINVAL;
16058ded420SAlexey Kardashevskiy 
161f31e65e1SBenjamin Herrenschmidt 	/* Check this LIOBN hasn't been previously allocated */
162f31e65e1SBenjamin Herrenschmidt 	list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) {
163f31e65e1SBenjamin Herrenschmidt 		if (stt->liobn == args->liobn)
164f31e65e1SBenjamin Herrenschmidt 			return -EBUSY;
165f31e65e1SBenjamin Herrenschmidt 	}
166f31e65e1SBenjamin Herrenschmidt 
167*3762d45aSAlexey Kardashevskiy 	size = _ALIGN_UP(args->size, PAGE_SIZE >> 3);
168fe26e527SAlexey Kardashevskiy 	npages = kvmppc_tce_pages(size);
169f8626985SAlexey Kardashevskiy 	ret = kvmppc_account_memlimit(kvmppc_stt_pages(npages), true);
170f8626985SAlexey Kardashevskiy 	if (ret) {
171f8626985SAlexey Kardashevskiy 		stt = NULL;
172f8626985SAlexey Kardashevskiy 		goto fail;
173f8626985SAlexey Kardashevskiy 	}
174f31e65e1SBenjamin Herrenschmidt 
1755982f084SWei Yongjun 	ret = -ENOMEM;
176f31e65e1SBenjamin Herrenschmidt 	stt = kzalloc(sizeof(*stt) + npages * sizeof(struct page *),
177f31e65e1SBenjamin Herrenschmidt 		      GFP_KERNEL);
178f31e65e1SBenjamin Herrenschmidt 	if (!stt)
179f31e65e1SBenjamin Herrenschmidt 		goto fail;
180f31e65e1SBenjamin Herrenschmidt 
181f31e65e1SBenjamin Herrenschmidt 	stt->liobn = args->liobn;
18258ded420SAlexey Kardashevskiy 	stt->page_shift = args->page_shift;
18358ded420SAlexey Kardashevskiy 	stt->offset = args->offset;
184fe26e527SAlexey Kardashevskiy 	stt->size = size;
185f31e65e1SBenjamin Herrenschmidt 	stt->kvm = kvm;
186f31e65e1SBenjamin Herrenschmidt 
187f31e65e1SBenjamin Herrenschmidt 	for (i = 0; i < npages; i++) {
188f31e65e1SBenjamin Herrenschmidt 		stt->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
189f31e65e1SBenjamin Herrenschmidt 		if (!stt->pages[i])
190f31e65e1SBenjamin Herrenschmidt 			goto fail;
191f31e65e1SBenjamin Herrenschmidt 	}
192f31e65e1SBenjamin Herrenschmidt 
193f31e65e1SBenjamin Herrenschmidt 	kvm_get_kvm(kvm);
194f31e65e1SBenjamin Herrenschmidt 
195f31e65e1SBenjamin Herrenschmidt 	mutex_lock(&kvm->lock);
196366baf28SAlexey Kardashevskiy 	list_add_rcu(&stt->list, &kvm->arch.spapr_tce_tables);
197f31e65e1SBenjamin Herrenschmidt 
198f31e65e1SBenjamin Herrenschmidt 	mutex_unlock(&kvm->lock);
199f31e65e1SBenjamin Herrenschmidt 
200f31e65e1SBenjamin Herrenschmidt 	return anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops,
2012f84d5eaSYann Droneaud 				stt, O_RDWR | O_CLOEXEC);
202f31e65e1SBenjamin Herrenschmidt 
203f31e65e1SBenjamin Herrenschmidt fail:
204f31e65e1SBenjamin Herrenschmidt 	if (stt) {
205f31e65e1SBenjamin Herrenschmidt 		for (i = 0; i < npages; i++)
206f31e65e1SBenjamin Herrenschmidt 			if (stt->pages[i])
207f31e65e1SBenjamin Herrenschmidt 				__free_page(stt->pages[i]);
208f31e65e1SBenjamin Herrenschmidt 
209f31e65e1SBenjamin Herrenschmidt 		kfree(stt);
210f31e65e1SBenjamin Herrenschmidt 	}
211f31e65e1SBenjamin Herrenschmidt 	return ret;
212f31e65e1SBenjamin Herrenschmidt }
213d3695aa4SAlexey Kardashevskiy 
21431217db7SAlexey Kardashevskiy long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
21531217db7SAlexey Kardashevskiy 		      unsigned long ioba, unsigned long tce)
21631217db7SAlexey Kardashevskiy {
21731217db7SAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt = kvmppc_find_table(vcpu, liobn);
21831217db7SAlexey Kardashevskiy 	long ret;
21931217db7SAlexey Kardashevskiy 
22031217db7SAlexey Kardashevskiy 	/* udbg_printf("H_PUT_TCE(): liobn=0x%lx ioba=0x%lx, tce=0x%lx\n", */
22131217db7SAlexey Kardashevskiy 	/* 	    liobn, ioba, tce); */
22231217db7SAlexey Kardashevskiy 
22331217db7SAlexey Kardashevskiy 	if (!stt)
22431217db7SAlexey Kardashevskiy 		return H_TOO_HARD;
22531217db7SAlexey Kardashevskiy 
22631217db7SAlexey Kardashevskiy 	ret = kvmppc_ioba_validate(stt, ioba, 1);
22731217db7SAlexey Kardashevskiy 	if (ret != H_SUCCESS)
22831217db7SAlexey Kardashevskiy 		return ret;
22931217db7SAlexey Kardashevskiy 
23031217db7SAlexey Kardashevskiy 	ret = kvmppc_tce_validate(stt, tce);
23131217db7SAlexey Kardashevskiy 	if (ret != H_SUCCESS)
23231217db7SAlexey Kardashevskiy 		return ret;
23331217db7SAlexey Kardashevskiy 
23431217db7SAlexey Kardashevskiy 	kvmppc_tce_put(stt, ioba >> stt->page_shift, tce);
23531217db7SAlexey Kardashevskiy 
23631217db7SAlexey Kardashevskiy 	return H_SUCCESS;
23731217db7SAlexey Kardashevskiy }
23831217db7SAlexey Kardashevskiy EXPORT_SYMBOL_GPL(kvmppc_h_put_tce);
23931217db7SAlexey Kardashevskiy 
240d3695aa4SAlexey Kardashevskiy long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu,
241d3695aa4SAlexey Kardashevskiy 		unsigned long liobn, unsigned long ioba,
242d3695aa4SAlexey Kardashevskiy 		unsigned long tce_list, unsigned long npages)
243d3695aa4SAlexey Kardashevskiy {
244d3695aa4SAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt;
245d3695aa4SAlexey Kardashevskiy 	long i, ret = H_SUCCESS, idx;
246d3695aa4SAlexey Kardashevskiy 	unsigned long entry, ua = 0;
247f8750513SDaniel Axtens 	u64 __user *tces;
248f8750513SDaniel Axtens 	u64 tce;
249d3695aa4SAlexey Kardashevskiy 
250d3695aa4SAlexey Kardashevskiy 	stt = kvmppc_find_table(vcpu, liobn);
251d3695aa4SAlexey Kardashevskiy 	if (!stt)
252d3695aa4SAlexey Kardashevskiy 		return H_TOO_HARD;
253d3695aa4SAlexey Kardashevskiy 
254fe26e527SAlexey Kardashevskiy 	entry = ioba >> stt->page_shift;
255d3695aa4SAlexey Kardashevskiy 	/*
256d3695aa4SAlexey Kardashevskiy 	 * SPAPR spec says that the maximum size of the list is 512 TCEs
257d3695aa4SAlexey Kardashevskiy 	 * so the whole table fits in 4K page
258d3695aa4SAlexey Kardashevskiy 	 */
259d3695aa4SAlexey Kardashevskiy 	if (npages > 512)
260d3695aa4SAlexey Kardashevskiy 		return H_PARAMETER;
261d3695aa4SAlexey Kardashevskiy 
262d3695aa4SAlexey Kardashevskiy 	if (tce_list & (SZ_4K - 1))
263d3695aa4SAlexey Kardashevskiy 		return H_PARAMETER;
264d3695aa4SAlexey Kardashevskiy 
265d3695aa4SAlexey Kardashevskiy 	ret = kvmppc_ioba_validate(stt, ioba, npages);
266d3695aa4SAlexey Kardashevskiy 	if (ret != H_SUCCESS)
267d3695aa4SAlexey Kardashevskiy 		return ret;
268d3695aa4SAlexey Kardashevskiy 
269d3695aa4SAlexey Kardashevskiy 	idx = srcu_read_lock(&vcpu->kvm->srcu);
270d3695aa4SAlexey Kardashevskiy 	if (kvmppc_gpa_to_ua(vcpu->kvm, tce_list, &ua, NULL)) {
271d3695aa4SAlexey Kardashevskiy 		ret = H_TOO_HARD;
272d3695aa4SAlexey Kardashevskiy 		goto unlock_exit;
273d3695aa4SAlexey Kardashevskiy 	}
274d3695aa4SAlexey Kardashevskiy 	tces = (u64 __user *) ua;
275d3695aa4SAlexey Kardashevskiy 
276d3695aa4SAlexey Kardashevskiy 	for (i = 0; i < npages; ++i) {
277d3695aa4SAlexey Kardashevskiy 		if (get_user(tce, tces + i)) {
278d3695aa4SAlexey Kardashevskiy 			ret = H_TOO_HARD;
279d3695aa4SAlexey Kardashevskiy 			goto unlock_exit;
280d3695aa4SAlexey Kardashevskiy 		}
281d3695aa4SAlexey Kardashevskiy 		tce = be64_to_cpu(tce);
282d3695aa4SAlexey Kardashevskiy 
283d3695aa4SAlexey Kardashevskiy 		ret = kvmppc_tce_validate(stt, tce);
284d3695aa4SAlexey Kardashevskiy 		if (ret != H_SUCCESS)
285d3695aa4SAlexey Kardashevskiy 			goto unlock_exit;
286d3695aa4SAlexey Kardashevskiy 
287d3695aa4SAlexey Kardashevskiy 		kvmppc_tce_put(stt, entry + i, tce);
288d3695aa4SAlexey Kardashevskiy 	}
289d3695aa4SAlexey Kardashevskiy 
290d3695aa4SAlexey Kardashevskiy unlock_exit:
291d3695aa4SAlexey Kardashevskiy 	srcu_read_unlock(&vcpu->kvm->srcu, idx);
292d3695aa4SAlexey Kardashevskiy 
293d3695aa4SAlexey Kardashevskiy 	return ret;
294d3695aa4SAlexey Kardashevskiy }
295d3695aa4SAlexey Kardashevskiy EXPORT_SYMBOL_GPL(kvmppc_h_put_tce_indirect);
29631217db7SAlexey Kardashevskiy 
29731217db7SAlexey Kardashevskiy long kvmppc_h_stuff_tce(struct kvm_vcpu *vcpu,
29831217db7SAlexey Kardashevskiy 		unsigned long liobn, unsigned long ioba,
29931217db7SAlexey Kardashevskiy 		unsigned long tce_value, unsigned long npages)
30031217db7SAlexey Kardashevskiy {
30131217db7SAlexey Kardashevskiy 	struct kvmppc_spapr_tce_table *stt;
30231217db7SAlexey Kardashevskiy 	long i, ret;
30331217db7SAlexey Kardashevskiy 
30431217db7SAlexey Kardashevskiy 	stt = kvmppc_find_table(vcpu, liobn);
30531217db7SAlexey Kardashevskiy 	if (!stt)
30631217db7SAlexey Kardashevskiy 		return H_TOO_HARD;
30731217db7SAlexey Kardashevskiy 
30831217db7SAlexey Kardashevskiy 	ret = kvmppc_ioba_validate(stt, ioba, npages);
30931217db7SAlexey Kardashevskiy 	if (ret != H_SUCCESS)
31031217db7SAlexey Kardashevskiy 		return ret;
31131217db7SAlexey Kardashevskiy 
31231217db7SAlexey Kardashevskiy 	/* Check permission bits only to allow userspace poison TCE for debug */
31331217db7SAlexey Kardashevskiy 	if (tce_value & (TCE_PCI_WRITE | TCE_PCI_READ))
31431217db7SAlexey Kardashevskiy 		return H_PARAMETER;
31531217db7SAlexey Kardashevskiy 
31631217db7SAlexey Kardashevskiy 	for (i = 0; i < npages; ++i, ioba += (1ULL << stt->page_shift))
31731217db7SAlexey Kardashevskiy 		kvmppc_tce_put(stt, ioba >> stt->page_shift, tce_value);
31831217db7SAlexey Kardashevskiy 
31931217db7SAlexey Kardashevskiy 	return H_SUCCESS;
32031217db7SAlexey Kardashevskiy }
32131217db7SAlexey Kardashevskiy EXPORT_SYMBOL_GPL(kvmppc_h_stuff_tce);
322