1 /************************************************************************** 2 * 3 * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 * USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 /* 28 * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> 29 */ 30 31 #define pr_fmt(fmt) "[TTM] " fmt 32 33 #include <ttm/ttm_module.h> 34 #include <ttm/ttm_bo_driver.h> 35 #include <ttm/ttm_placement.h> 36 #include <drm/drm_vma_manager.h> 37 #include <linux/mm.h> 38 #include <linux/pfn_t.h> 39 #include <linux/rbtree.h> 40 #include <linux/module.h> 41 #include <linux/uaccess.h> 42 43 #define TTM_BO_VM_NUM_PREFAULT 16 44 45 static int ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo, 46 struct vm_area_struct *vma, 47 struct vm_fault *vmf) 48 { 49 int ret = 0; 50 51 if (likely(!test_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags))) 52 goto out_unlock; 53 54 /* 55 * Quick non-stalling check for idle. 56 */ 57 ret = ttm_bo_wait(bo, false, true); 58 if (likely(ret == 0)) 59 goto out_unlock; 60 61 /* 62 * If possible, avoid waiting for GPU with mmap_sem 63 * held. 64 */ 65 if (vmf->flags & FAULT_FLAG_ALLOW_RETRY) { 66 ret = VM_FAULT_RETRY; 67 if (vmf->flags & FAULT_FLAG_RETRY_NOWAIT) 68 goto out_unlock; 69 70 up_read(&vma->vm_mm->mmap_sem); 71 (void) ttm_bo_wait(bo, true, false); 72 goto out_unlock; 73 } 74 75 /* 76 * Ordinary wait. 77 */ 78 ret = ttm_bo_wait(bo, true, false); 79 if (unlikely(ret != 0)) 80 ret = (ret != -ERESTARTSYS) ? VM_FAULT_SIGBUS : 81 VM_FAULT_NOPAGE; 82 83 out_unlock: 84 return ret; 85 } 86 87 static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 88 { 89 struct ttm_buffer_object *bo = (struct ttm_buffer_object *) 90 vma->vm_private_data; 91 struct ttm_bo_device *bdev = bo->bdev; 92 unsigned long page_offset; 93 unsigned long page_last; 94 unsigned long pfn; 95 struct ttm_tt *ttm = NULL; 96 struct page *page; 97 int ret; 98 int i; 99 unsigned long address = (unsigned long)vmf->virtual_address; 100 int retval = VM_FAULT_NOPAGE; 101 struct ttm_mem_type_manager *man = 102 &bdev->man[bo->mem.mem_type]; 103 struct vm_area_struct cvma; 104 105 /* 106 * Work around locking order reversal in fault / nopfn 107 * between mmap_sem and bo_reserve: Perform a trylock operation 108 * for reserve, and if it fails, retry the fault after waiting 109 * for the buffer to become unreserved. 110 */ 111 ret = ttm_bo_reserve(bo, true, true, NULL); 112 if (unlikely(ret != 0)) { 113 if (ret != -EBUSY) 114 return VM_FAULT_NOPAGE; 115 116 if (vmf->flags & FAULT_FLAG_ALLOW_RETRY) { 117 if (!(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) { 118 up_read(&vma->vm_mm->mmap_sem); 119 (void) ttm_bo_wait_unreserved(bo); 120 } 121 122 return VM_FAULT_RETRY; 123 } 124 125 /* 126 * If we'd want to change locking order to 127 * mmap_sem -> bo::reserve, we'd use a blocking reserve here 128 * instead of retrying the fault... 129 */ 130 return VM_FAULT_NOPAGE; 131 } 132 133 /* 134 * Refuse to fault imported pages. This should be handled 135 * (if at all) by redirecting mmap to the exporter. 136 */ 137 if (bo->ttm && (bo->ttm->page_flags & TTM_PAGE_FLAG_SG)) { 138 retval = VM_FAULT_SIGBUS; 139 goto out_unlock; 140 } 141 142 if (bdev->driver->fault_reserve_notify) { 143 ret = bdev->driver->fault_reserve_notify(bo); 144 switch (ret) { 145 case 0: 146 break; 147 case -EBUSY: 148 case -ERESTARTSYS: 149 retval = VM_FAULT_NOPAGE; 150 goto out_unlock; 151 default: 152 retval = VM_FAULT_SIGBUS; 153 goto out_unlock; 154 } 155 } 156 157 /* 158 * Wait for buffer data in transit, due to a pipelined 159 * move. 160 */ 161 ret = ttm_bo_vm_fault_idle(bo, vma, vmf); 162 if (unlikely(ret != 0)) { 163 retval = ret; 164 goto out_unlock; 165 } 166 167 ret = ttm_mem_io_lock(man, true); 168 if (unlikely(ret != 0)) { 169 retval = VM_FAULT_NOPAGE; 170 goto out_unlock; 171 } 172 ret = ttm_mem_io_reserve_vm(bo); 173 if (unlikely(ret != 0)) { 174 retval = VM_FAULT_SIGBUS; 175 goto out_io_unlock; 176 } 177 178 page_offset = ((address - vma->vm_start) >> PAGE_SHIFT) + 179 vma->vm_pgoff - drm_vma_node_start(&bo->vma_node); 180 page_last = vma_pages(vma) + vma->vm_pgoff - 181 drm_vma_node_start(&bo->vma_node); 182 183 if (unlikely(page_offset >= bo->num_pages)) { 184 retval = VM_FAULT_SIGBUS; 185 goto out_io_unlock; 186 } 187 188 /* 189 * Make a local vma copy to modify the page_prot member 190 * and vm_flags if necessary. The vma parameter is protected 191 * by mmap_sem in write mode. 192 */ 193 cvma = *vma; 194 cvma.vm_page_prot = vm_get_page_prot(cvma.vm_flags); 195 196 if (bo->mem.bus.is_iomem) { 197 cvma.vm_page_prot = ttm_io_prot(bo->mem.placement, 198 cvma.vm_page_prot); 199 } else { 200 ttm = bo->ttm; 201 cvma.vm_page_prot = ttm_io_prot(bo->mem.placement, 202 cvma.vm_page_prot); 203 204 /* Allocate all page at once, most common usage */ 205 if (ttm->bdev->driver->ttm_tt_populate(ttm)) { 206 retval = VM_FAULT_OOM; 207 goto out_io_unlock; 208 } 209 } 210 211 /* 212 * Speculatively prefault a number of pages. Only error on 213 * first page. 214 */ 215 for (i = 0; i < TTM_BO_VM_NUM_PREFAULT; ++i) { 216 if (bo->mem.bus.is_iomem) 217 pfn = ((bo->mem.bus.base + bo->mem.bus.offset) >> PAGE_SHIFT) + page_offset; 218 else { 219 page = ttm->pages[page_offset]; 220 if (unlikely(!page && i == 0)) { 221 retval = VM_FAULT_OOM; 222 goto out_io_unlock; 223 } else if (unlikely(!page)) { 224 break; 225 } 226 page->mapping = vma->vm_file->f_mapping; 227 page->index = drm_vma_node_start(&bo->vma_node) + 228 page_offset; 229 pfn = page_to_pfn(page); 230 } 231 232 if (vma->vm_flags & VM_MIXEDMAP) 233 ret = vm_insert_mixed(&cvma, address, 234 __pfn_to_pfn_t(pfn, PFN_DEV)); 235 else 236 ret = vm_insert_pfn(&cvma, address, pfn); 237 238 /* 239 * Somebody beat us to this PTE or prefaulting to 240 * an already populated PTE, or prefaulting error. 241 */ 242 243 if (unlikely((ret == -EBUSY) || (ret != 0 && i > 0))) 244 break; 245 else if (unlikely(ret != 0)) { 246 retval = 247 (ret == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS; 248 goto out_io_unlock; 249 } 250 251 address += PAGE_SIZE; 252 if (unlikely(++page_offset >= page_last)) 253 break; 254 } 255 out_io_unlock: 256 ttm_mem_io_unlock(man); 257 out_unlock: 258 ttm_bo_unreserve(bo); 259 return retval; 260 } 261 262 static void ttm_bo_vm_open(struct vm_area_struct *vma) 263 { 264 struct ttm_buffer_object *bo = 265 (struct ttm_buffer_object *)vma->vm_private_data; 266 267 WARN_ON(bo->bdev->dev_mapping != vma->vm_file->f_mapping); 268 269 (void)ttm_bo_reference(bo); 270 } 271 272 static void ttm_bo_vm_close(struct vm_area_struct *vma) 273 { 274 struct ttm_buffer_object *bo = (struct ttm_buffer_object *)vma->vm_private_data; 275 276 ttm_bo_unref(&bo); 277 vma->vm_private_data = NULL; 278 } 279 280 static const struct vm_operations_struct ttm_bo_vm_ops = { 281 .fault = ttm_bo_vm_fault, 282 .open = ttm_bo_vm_open, 283 .close = ttm_bo_vm_close 284 }; 285 286 static struct ttm_buffer_object *ttm_bo_vm_lookup(struct ttm_bo_device *bdev, 287 unsigned long offset, 288 unsigned long pages) 289 { 290 struct drm_vma_offset_node *node; 291 struct ttm_buffer_object *bo = NULL; 292 293 drm_vma_offset_lock_lookup(&bdev->vma_manager); 294 295 node = drm_vma_offset_lookup_locked(&bdev->vma_manager, offset, pages); 296 if (likely(node)) { 297 bo = container_of(node, struct ttm_buffer_object, vma_node); 298 if (!kref_get_unless_zero(&bo->kref)) 299 bo = NULL; 300 } 301 302 drm_vma_offset_unlock_lookup(&bdev->vma_manager); 303 304 if (!bo) 305 pr_err("Could not find buffer object to map\n"); 306 307 return bo; 308 } 309 310 int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma, 311 struct ttm_bo_device *bdev) 312 { 313 struct ttm_bo_driver *driver; 314 struct ttm_buffer_object *bo; 315 int ret; 316 317 bo = ttm_bo_vm_lookup(bdev, vma->vm_pgoff, vma_pages(vma)); 318 if (unlikely(!bo)) 319 return -EINVAL; 320 321 driver = bo->bdev->driver; 322 if (unlikely(!driver->verify_access)) { 323 ret = -EPERM; 324 goto out_unref; 325 } 326 ret = driver->verify_access(bo, filp); 327 if (unlikely(ret != 0)) 328 goto out_unref; 329 330 vma->vm_ops = &ttm_bo_vm_ops; 331 332 /* 333 * Note: We're transferring the bo reference to 334 * vma->vm_private_data here. 335 */ 336 337 vma->vm_private_data = bo; 338 339 /* 340 * We'd like to use VM_PFNMAP on shared mappings, where 341 * (vma->vm_flags & VM_SHARED) != 0, for performance reasons, 342 * but for some reason VM_PFNMAP + x86 PAT + write-combine is very 343 * bad for performance. Until that has been sorted out, use 344 * VM_MIXEDMAP on all mappings. See freedesktop.org bug #75719 345 */ 346 vma->vm_flags |= VM_MIXEDMAP; 347 vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; 348 return 0; 349 out_unref: 350 ttm_bo_unref(&bo); 351 return ret; 352 } 353 EXPORT_SYMBOL(ttm_bo_mmap); 354 355 int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo) 356 { 357 if (vma->vm_pgoff != 0) 358 return -EACCES; 359 360 vma->vm_ops = &ttm_bo_vm_ops; 361 vma->vm_private_data = ttm_bo_reference(bo); 362 vma->vm_flags |= VM_MIXEDMAP; 363 vma->vm_flags |= VM_IO | VM_DONTEXPAND; 364 return 0; 365 } 366 EXPORT_SYMBOL(ttm_fbdev_mmap); 367