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(¤t->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(¤t->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