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/rbtree.h> 39 #include <linux/module.h> 40 #include <linux/uaccess.h> 41 42 #define TTM_BO_VM_NUM_PREFAULT 16 43 44 static int ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo, 45 struct vm_area_struct *vma, 46 struct vm_fault *vmf) 47 { 48 struct ttm_bo_device *bdev = bo->bdev; 49 int ret = 0; 50 51 spin_lock(&bdev->fence_lock); 52 if (likely(!test_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags))) 53 goto out_unlock; 54 55 /* 56 * Quick non-stalling check for idle. 57 */ 58 ret = ttm_bo_wait(bo, false, false, true); 59 if (likely(ret == 0)) 60 goto out_unlock; 61 62 /* 63 * If possible, avoid waiting for GPU with mmap_sem 64 * held. 65 */ 66 if (vmf->flags & FAULT_FLAG_ALLOW_RETRY) { 67 ret = VM_FAULT_RETRY; 68 if (vmf->flags & FAULT_FLAG_RETRY_NOWAIT) 69 goto out_unlock; 70 71 up_read(&vma->vm_mm->mmap_sem); 72 (void) ttm_bo_wait(bo, false, true, false); 73 goto out_unlock; 74 } 75 76 /* 77 * Ordinary wait. 78 */ 79 ret = ttm_bo_wait(bo, false, true, false); 80 if (unlikely(ret != 0)) 81 ret = (ret != -ERESTARTSYS) ? VM_FAULT_SIGBUS : 82 VM_FAULT_NOPAGE; 83 84 out_unlock: 85 spin_unlock(&bdev->fence_lock); 86 return ret; 87 } 88 89 static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 90 { 91 struct ttm_buffer_object *bo = (struct ttm_buffer_object *) 92 vma->vm_private_data; 93 struct ttm_bo_device *bdev = bo->bdev; 94 unsigned long page_offset; 95 unsigned long page_last; 96 unsigned long pfn; 97 struct ttm_tt *ttm = NULL; 98 struct page *page; 99 int ret; 100 int i; 101 unsigned long address = (unsigned long)vmf->virtual_address; 102 int retval = VM_FAULT_NOPAGE; 103 struct ttm_mem_type_manager *man = 104 &bdev->man[bo->mem.mem_type]; 105 struct vm_area_struct cvma; 106 107 /* 108 * Work around locking order reversal in fault / nopfn 109 * between mmap_sem and bo_reserve: Perform a trylock operation 110 * for reserve, and if it fails, retry the fault after waiting 111 * for the buffer to become unreserved. 112 */ 113 ret = ttm_bo_reserve(bo, true, true, false, NULL); 114 if (unlikely(ret != 0)) { 115 if (ret != -EBUSY) 116 return VM_FAULT_NOPAGE; 117 118 if (vmf->flags & FAULT_FLAG_ALLOW_RETRY) { 119 if (!(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) { 120 up_read(&vma->vm_mm->mmap_sem); 121 (void) ttm_bo_wait_unreserved(bo); 122 } 123 124 return VM_FAULT_RETRY; 125 } 126 127 /* 128 * If we'd want to change locking order to 129 * mmap_sem -> bo::reserve, we'd use a blocking reserve here 130 * instead of retrying the fault... 131 */ 132 return VM_FAULT_NOPAGE; 133 } 134 135 /* 136 * Refuse to fault imported pages. This should be handled 137 * (if at all) by redirecting mmap to the exporter. 138 */ 139 if (bo->ttm && (bo->ttm->page_flags & TTM_PAGE_FLAG_SG)) { 140 retval = VM_FAULT_SIGBUS; 141 goto out_unlock; 142 } 143 144 if (bdev->driver->fault_reserve_notify) { 145 ret = bdev->driver->fault_reserve_notify(bo); 146 switch (ret) { 147 case 0: 148 break; 149 case -EBUSY: 150 case -ERESTARTSYS: 151 retval = VM_FAULT_NOPAGE; 152 goto out_unlock; 153 default: 154 retval = VM_FAULT_SIGBUS; 155 goto out_unlock; 156 } 157 } 158 159 /* 160 * Wait for buffer data in transit, due to a pipelined 161 * move. 162 */ 163 ret = ttm_bo_vm_fault_idle(bo, vma, vmf); 164 if (unlikely(ret != 0)) { 165 retval = ret; 166 goto out_unlock; 167 } 168 169 ret = ttm_mem_io_lock(man, true); 170 if (unlikely(ret != 0)) { 171 retval = VM_FAULT_NOPAGE; 172 goto out_unlock; 173 } 174 ret = ttm_mem_io_reserve_vm(bo); 175 if (unlikely(ret != 0)) { 176 retval = VM_FAULT_SIGBUS; 177 goto out_io_unlock; 178 } 179 180 page_offset = ((address - vma->vm_start) >> PAGE_SHIFT) + 181 vma->vm_pgoff - drm_vma_node_start(&bo->vma_node); 182 page_last = vma_pages(vma) + vma->vm_pgoff - 183 drm_vma_node_start(&bo->vma_node); 184 185 if (unlikely(page_offset >= bo->num_pages)) { 186 retval = VM_FAULT_SIGBUS; 187 goto out_io_unlock; 188 } 189 190 /* 191 * Make a local vma copy to modify the page_prot member 192 * and vm_flags if necessary. The vma parameter is protected 193 * by mmap_sem in write mode. 194 */ 195 cvma = *vma; 196 cvma.vm_page_prot = vm_get_page_prot(cvma.vm_flags); 197 198 if (bo->mem.bus.is_iomem) { 199 cvma.vm_page_prot = ttm_io_prot(bo->mem.placement, 200 cvma.vm_page_prot); 201 } else { 202 ttm = bo->ttm; 203 if (!(bo->mem.placement & TTM_PL_FLAG_CACHED)) 204 cvma.vm_page_prot = ttm_io_prot(bo->mem.placement, 205 cvma.vm_page_prot); 206 207 /* Allocate all page at once, most common usage */ 208 if (ttm->bdev->driver->ttm_tt_populate(ttm)) { 209 retval = VM_FAULT_OOM; 210 goto out_io_unlock; 211 } 212 } 213 214 /* 215 * Speculatively prefault a number of pages. Only error on 216 * first page. 217 */ 218 for (i = 0; i < TTM_BO_VM_NUM_PREFAULT; ++i) { 219 if (bo->mem.bus.is_iomem) 220 pfn = ((bo->mem.bus.base + bo->mem.bus.offset) >> PAGE_SHIFT) + page_offset; 221 else { 222 page = ttm->pages[page_offset]; 223 if (unlikely(!page && i == 0)) { 224 retval = VM_FAULT_OOM; 225 goto out_io_unlock; 226 } else if (unlikely(!page)) { 227 break; 228 } 229 page->mapping = vma->vm_file->f_mapping; 230 page->index = drm_vma_node_start(&bo->vma_node) + 231 page_offset; 232 pfn = page_to_pfn(page); 233 } 234 235 if (vma->vm_flags & VM_MIXEDMAP) 236 ret = vm_insert_mixed(&cvma, address, pfn); 237 else 238 ret = vm_insert_pfn(&cvma, address, pfn); 239 240 /* 241 * Somebody beat us to this PTE or prefaulting to 242 * an already populated PTE, or prefaulting error. 243 */ 244 245 if (unlikely((ret == -EBUSY) || (ret != 0 && i > 0))) 246 break; 247 else if (unlikely(ret != 0)) { 248 retval = 249 (ret == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS; 250 goto out_io_unlock; 251 } 252 253 address += PAGE_SIZE; 254 if (unlikely(++page_offset >= page_last)) 255 break; 256 } 257 out_io_unlock: 258 ttm_mem_io_unlock(man); 259 out_unlock: 260 ttm_bo_unreserve(bo); 261 return retval; 262 } 263 264 static void ttm_bo_vm_open(struct vm_area_struct *vma) 265 { 266 struct ttm_buffer_object *bo = 267 (struct ttm_buffer_object *)vma->vm_private_data; 268 269 WARN_ON(bo->bdev->dev_mapping != vma->vm_file->f_mapping); 270 271 (void)ttm_bo_reference(bo); 272 } 273 274 static void ttm_bo_vm_close(struct vm_area_struct *vma) 275 { 276 struct ttm_buffer_object *bo = (struct ttm_buffer_object *)vma->vm_private_data; 277 278 ttm_bo_unref(&bo); 279 vma->vm_private_data = NULL; 280 } 281 282 static const struct vm_operations_struct ttm_bo_vm_ops = { 283 .fault = ttm_bo_vm_fault, 284 .open = ttm_bo_vm_open, 285 .close = ttm_bo_vm_close 286 }; 287 288 static struct ttm_buffer_object *ttm_bo_vm_lookup(struct ttm_bo_device *bdev, 289 unsigned long offset, 290 unsigned long pages) 291 { 292 struct drm_vma_offset_node *node; 293 struct ttm_buffer_object *bo = NULL; 294 295 drm_vma_offset_lock_lookup(&bdev->vma_manager); 296 297 node = drm_vma_offset_lookup_locked(&bdev->vma_manager, offset, pages); 298 if (likely(node)) { 299 bo = container_of(node, struct ttm_buffer_object, vma_node); 300 if (!kref_get_unless_zero(&bo->kref)) 301 bo = NULL; 302 } 303 304 drm_vma_offset_unlock_lookup(&bdev->vma_manager); 305 306 if (!bo) 307 pr_err("Could not find buffer object to map\n"); 308 309 return bo; 310 } 311 312 int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma, 313 struct ttm_bo_device *bdev) 314 { 315 struct ttm_bo_driver *driver; 316 struct ttm_buffer_object *bo; 317 int ret; 318 319 bo = ttm_bo_vm_lookup(bdev, vma->vm_pgoff, vma_pages(vma)); 320 if (unlikely(!bo)) 321 return -EINVAL; 322 323 driver = bo->bdev->driver; 324 if (unlikely(!driver->verify_access)) { 325 ret = -EPERM; 326 goto out_unref; 327 } 328 ret = driver->verify_access(bo, filp); 329 if (unlikely(ret != 0)) 330 goto out_unref; 331 332 vma->vm_ops = &ttm_bo_vm_ops; 333 334 /* 335 * Note: We're transferring the bo reference to 336 * vma->vm_private_data here. 337 */ 338 339 vma->vm_private_data = bo; 340 341 /* 342 * We'd like to use VM_PFNMAP on shared mappings, where 343 * (vma->vm_flags & VM_SHARED) != 0, for performance reasons, 344 * but for some reason VM_PFNMAP + x86 PAT + write-combine is very 345 * bad for performance. Until that has been sorted out, use 346 * VM_MIXEDMAP on all mappings. See freedesktop.org bug #75719 347 */ 348 vma->vm_flags |= VM_MIXEDMAP; 349 vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; 350 return 0; 351 out_unref: 352 ttm_bo_unref(&bo); 353 return ret; 354 } 355 EXPORT_SYMBOL(ttm_bo_mmap); 356 357 int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo) 358 { 359 if (vma->vm_pgoff != 0) 360 return -EACCES; 361 362 vma->vm_ops = &ttm_bo_vm_ops; 363 vma->vm_private_data = ttm_bo_reference(bo); 364 vma->vm_flags |= VM_MIXEDMAP; 365 vma->vm_flags |= VM_IO | VM_DONTEXPAND; 366 return 0; 367 } 368 EXPORT_SYMBOL(ttm_fbdev_mmap); 369