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