Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/msm: Separate locking of buffer resources from struct_mutex

Buffer object specific resources like pages, domains, sg list
need not be protected with struct_mutex. They can be protected
with a buffer object level lock. This simplifies locking and
makes it easier to avoid potential recursive locking scenarios
for SVM involving mmap_sem and struct_mutex. This also removes
unnecessary serialization when creating buffer objects, and also
between buffer object creation and GPU command submission.

Signed-off-by: Sushmita Susheelendra <ssusheel@codeaurora.org>
[robclark: squash in handling new locking for shrinker]
Signed-off-by: Rob Clark <robdclark@gmail.com>

authored by

Sushmita Susheelendra and committed by
Rob Clark
0e08270a 816fa34c

+245 -151
+4 -4
drivers/gpu/drm/msm/adreno/a5xx_gpu.c
··· 297 297 struct drm_gem_object *bo; 298 298 void *ptr; 299 299 300 - bo = msm_gem_new(drm, fw->size - 4, MSM_BO_UNCACHED); 300 + bo = msm_gem_new_locked(drm, fw->size - 4, MSM_BO_UNCACHED); 301 301 if (IS_ERR(bo)) 302 302 return bo; 303 303 304 - ptr = msm_gem_get_vaddr_locked(bo); 304 + ptr = msm_gem_get_vaddr(bo); 305 305 if (!ptr) { 306 306 drm_gem_object_unreference(bo); 307 307 return ERR_PTR(-ENOMEM); 308 308 } 309 309 310 310 if (iova) { 311 - int ret = msm_gem_get_iova_locked(bo, gpu->aspace, iova); 311 + int ret = msm_gem_get_iova(bo, gpu->aspace, iova); 312 312 313 313 if (ret) { 314 314 drm_gem_object_unreference(bo); ··· 318 318 319 319 memcpy(ptr, &fw->data[4], fw->size - 4); 320 320 321 - msm_gem_put_vaddr_locked(bo); 321 + msm_gem_put_vaddr(bo); 322 322 return bo; 323 323 } 324 324
+4 -4
drivers/gpu/drm/msm/adreno/a5xx_power.c
··· 294 294 */ 295 295 bosize = (cmds_size + (cmds_size / TYPE4_MAX_PAYLOAD) + 1) << 2; 296 296 297 - a5xx_gpu->gpmu_bo = msm_gem_new(drm, bosize, MSM_BO_UNCACHED); 297 + a5xx_gpu->gpmu_bo = msm_gem_new_locked(drm, bosize, MSM_BO_UNCACHED); 298 298 if (IS_ERR(a5xx_gpu->gpmu_bo)) 299 299 goto err; 300 300 301 - if (msm_gem_get_iova_locked(a5xx_gpu->gpmu_bo, gpu->aspace, 301 + if (msm_gem_get_iova(a5xx_gpu->gpmu_bo, gpu->aspace, 302 302 &a5xx_gpu->gpmu_iova)) 303 303 goto err; 304 304 305 - ptr = msm_gem_get_vaddr_locked(a5xx_gpu->gpmu_bo); 305 + ptr = msm_gem_get_vaddr(a5xx_gpu->gpmu_bo); 306 306 if (!ptr) 307 307 goto err; 308 308 ··· 321 321 cmds_size -= _size; 322 322 } 323 323 324 - msm_gem_put_vaddr_locked(a5xx_gpu->gpmu_bo); 324 + msm_gem_put_vaddr(a5xx_gpu->gpmu_bo); 325 325 a5xx_gpu->gpmu_dwords = dwords; 326 326 327 327 goto out;
+1 -3
drivers/gpu/drm/msm/adreno/adreno_gpu.c
··· 64 64 65 65 DBG("%s", gpu->name); 66 66 67 - ret = msm_gem_get_iova_locked(gpu->rb->bo, gpu->aspace, &gpu->rb_iova); 67 + ret = msm_gem_get_iova(gpu->rb->bo, gpu->aspace, &gpu->rb_iova); 68 68 if (ret) { 69 69 gpu->rb_iova = 0; 70 70 dev_err(gpu->dev->dev, "could not map ringbuffer: %d\n", ret); ··· 397 397 return ret; 398 398 } 399 399 400 - mutex_lock(&drm->struct_mutex); 401 400 adreno_gpu->memptrs_bo = msm_gem_new(drm, sizeof(*adreno_gpu->memptrs), 402 401 MSM_BO_UNCACHED); 403 - mutex_unlock(&drm->struct_mutex); 404 402 if (IS_ERR(adreno_gpu->memptrs_bo)) { 405 403 ret = PTR_ERR(adreno_gpu->memptrs_bo); 406 404 adreno_gpu->memptrs_bo = NULL;
+1 -3
drivers/gpu/drm/msm/dsi/dsi_host.c
··· 982 982 uint64_t iova; 983 983 984 984 if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) { 985 - mutex_lock(&dev->struct_mutex); 986 985 msm_host->tx_gem_obj = msm_gem_new(dev, size, MSM_BO_UNCACHED); 987 986 if (IS_ERR(msm_host->tx_gem_obj)) { 988 987 ret = PTR_ERR(msm_host->tx_gem_obj); 989 988 pr_err("%s: failed to allocate gem, %d\n", 990 989 __func__, ret); 991 990 msm_host->tx_gem_obj = NULL; 992 - mutex_unlock(&dev->struct_mutex); 993 991 return ret; 994 992 } 995 993 996 - ret = msm_gem_get_iova_locked(msm_host->tx_gem_obj, 994 + ret = msm_gem_get_iova(msm_host->tx_gem_obj, 997 995 priv->kms->aspace, &iova); 998 996 mutex_unlock(&dev->struct_mutex); 999 997 if (ret) {
+1 -1
drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
··· 374 374 if (next_bo) { 375 375 /* take a obj ref + iova ref when we start scanning out: */ 376 376 drm_gem_object_reference(next_bo); 377 - msm_gem_get_iova_locked(next_bo, kms->aspace, &iova); 377 + msm_gem_get_iova(next_bo, kms->aspace, &iova); 378 378 379 379 /* enable cursor: */ 380 380 mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_SIZE(dma),
-2
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
··· 528 528 goto fail; 529 529 } 530 530 531 - mutex_lock(&dev->struct_mutex); 532 531 mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC); 533 - mutex_unlock(&dev->struct_mutex); 534 532 if (IS_ERR(mdp4_kms->blank_cursor_bo)) { 535 533 ret = PTR_ERR(mdp4_kms->blank_cursor_bo); 536 534 dev_err(dev->dev, "could not allocate blank-cursor bo: %d\n", ret);
+1
drivers/gpu/drm/msm/msm_drv.c
··· 336 336 priv->vram.size = size; 337 337 338 338 drm_mm_init(&priv->vram.mm, 0, (size >> PAGE_SHIFT) - 1); 339 + spin_lock_init(&priv->vram.lock); 339 340 340 341 attrs |= DMA_ATTR_NO_KERNEL_MAPPING; 341 342 attrs |= DMA_ATTR_WRITE_COMBINE;
+3 -6
drivers/gpu/drm/msm/msm_drv.h
··· 149 149 * and position mm_node->start is in # of pages: 150 150 */ 151 151 struct drm_mm mm; 152 + spinlock_t lock; /* Protects drm_mm node allocation/removal */ 152 153 } vram; 153 154 154 155 struct notifier_block vmap_notifier; ··· 199 198 int msm_gem_mmap(struct file *filp, struct vm_area_struct *vma); 200 199 int msm_gem_fault(struct vm_fault *vmf); 201 200 uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj); 202 - int msm_gem_get_iova_locked(struct drm_gem_object *obj, 203 - struct msm_gem_address_space *aspace, uint64_t *iova); 204 201 int msm_gem_get_iova(struct drm_gem_object *obj, 205 202 struct msm_gem_address_space *aspace, uint64_t *iova); 206 203 uint64_t msm_gem_iova(struct drm_gem_object *obj, ··· 220 221 struct dma_buf_attachment *attach, struct sg_table *sg); 221 222 int msm_gem_prime_pin(struct drm_gem_object *obj); 222 223 void msm_gem_prime_unpin(struct drm_gem_object *obj); 223 - void *msm_gem_get_vaddr_locked(struct drm_gem_object *obj); 224 224 void *msm_gem_get_vaddr(struct drm_gem_object *obj); 225 - void msm_gem_put_vaddr_locked(struct drm_gem_object *obj); 226 225 void msm_gem_put_vaddr(struct drm_gem_object *obj); 227 226 int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv); 228 - void msm_gem_purge(struct drm_gem_object *obj); 229 - void msm_gem_vunmap(struct drm_gem_object *obj); 230 227 int msm_gem_sync_object(struct drm_gem_object *obj, 231 228 struct msm_fence_context *fctx, bool exclusive); 232 229 void msm_gem_move_to_active(struct drm_gem_object *obj, ··· 234 239 int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, 235 240 uint32_t size, uint32_t flags, uint32_t *handle); 236 241 struct drm_gem_object *msm_gem_new(struct drm_device *dev, 242 + uint32_t size, uint32_t flags); 243 + struct drm_gem_object *msm_gem_new_locked(struct drm_device *dev, 237 244 uint32_t size, uint32_t flags); 238 245 struct drm_gem_object *msm_gem_import(struct drm_device *dev, 239 246 struct dma_buf *dmabuf, struct sg_table *sgt);
+2 -4
drivers/gpu/drm/msm/msm_fbdev.c
··· 97 97 /* allocate backing bo */ 98 98 size = mode_cmd.pitches[0] * mode_cmd.height; 99 99 DBG("allocating %d bytes for fb %d", size, dev->primary->index); 100 - mutex_lock(&dev->struct_mutex); 101 100 fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | 102 101 MSM_BO_WC | MSM_BO_STOLEN); 103 - mutex_unlock(&dev->struct_mutex); 104 102 if (IS_ERR(fbdev->bo)) { 105 103 ret = PTR_ERR(fbdev->bo); 106 104 fbdev->bo = NULL; ··· 124 126 * in panic (ie. lock-safe, etc) we could avoid pinning the 125 127 * buffer now: 126 128 */ 127 - ret = msm_gem_get_iova_locked(fbdev->bo, priv->kms->aspace, &paddr); 129 + ret = msm_gem_get_iova(fbdev->bo, priv->kms->aspace, &paddr); 128 130 if (ret) { 129 131 dev_err(dev->dev, "failed to get buffer obj iova: %d\n", ret); 130 132 goto fail_unlock; ··· 153 155 154 156 dev->mode_config.fb_base = paddr; 155 157 156 - fbi->screen_base = msm_gem_get_vaddr_locked(fbdev->bo); 158 + fbi->screen_base = msm_gem_get_vaddr(fbdev->bo); 157 159 if (IS_ERR(fbi->screen_base)) { 158 160 ret = PTR_ERR(fbi->screen_base); 159 161 goto fail_unlock;
+176 -112
drivers/gpu/drm/msm/msm_gem.c
··· 26 26 #include "msm_gpu.h" 27 27 #include "msm_mmu.h" 28 28 29 + static void msm_gem_vunmap_locked(struct drm_gem_object *obj); 30 + 31 + 29 32 static dma_addr_t physaddr(struct drm_gem_object *obj) 30 33 { 31 34 struct msm_gem_object *msm_obj = to_msm_bo(obj); ··· 44 41 } 45 42 46 43 /* allocate pages from VRAM carveout, used when no IOMMU: */ 47 - static struct page **get_pages_vram(struct drm_gem_object *obj, 48 - int npages) 44 + static struct page **get_pages_vram(struct drm_gem_object *obj, int npages) 49 45 { 50 46 struct msm_gem_object *msm_obj = to_msm_bo(obj); 51 47 struct msm_drm_private *priv = obj->dev->dev_private; ··· 56 54 if (!p) 57 55 return ERR_PTR(-ENOMEM); 58 56 57 + spin_lock(&priv->vram.lock); 59 58 ret = drm_mm_insert_node(&priv->vram.mm, msm_obj->vram_node, npages); 59 + spin_unlock(&priv->vram.lock); 60 60 if (ret) { 61 61 kvfree(p); 62 62 return ERR_PTR(ret); ··· 73 69 return p; 74 70 } 75 71 76 - /* called with dev->struct_mutex held */ 77 72 static struct page **get_pages(struct drm_gem_object *obj) 78 73 { 79 74 struct msm_gem_object *msm_obj = to_msm_bo(obj); ··· 112 109 return msm_obj->pages; 113 110 } 114 111 112 + static void put_pages_vram(struct drm_gem_object *obj) 113 + { 114 + struct msm_gem_object *msm_obj = to_msm_bo(obj); 115 + struct msm_drm_private *priv = obj->dev->dev_private; 116 + 117 + spin_lock(&priv->vram.lock); 118 + drm_mm_remove_node(msm_obj->vram_node); 119 + spin_unlock(&priv->vram.lock); 120 + 121 + kvfree(msm_obj->pages); 122 + } 123 + 115 124 static void put_pages(struct drm_gem_object *obj) 116 125 { 117 126 struct msm_gem_object *msm_obj = to_msm_bo(obj); ··· 140 125 141 126 if (use_pages(obj)) 142 127 drm_gem_put_pages(obj, msm_obj->pages, true, false); 143 - else { 144 - drm_mm_remove_node(msm_obj->vram_node); 145 - kvfree(msm_obj->pages); 146 - } 128 + else 129 + put_pages_vram(obj); 147 130 148 131 msm_obj->pages = NULL; 149 132 } ··· 149 136 150 137 struct page **msm_gem_get_pages(struct drm_gem_object *obj) 151 138 { 152 - struct drm_device *dev = obj->dev; 139 + struct msm_gem_object *msm_obj = to_msm_bo(obj); 153 140 struct page **p; 154 - mutex_lock(&dev->struct_mutex); 141 + 142 + mutex_lock(&msm_obj->lock); 143 + 144 + if (WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED)) { 145 + mutex_unlock(&msm_obj->lock); 146 + return ERR_PTR(-EBUSY); 147 + } 148 + 155 149 p = get_pages(obj); 156 - mutex_unlock(&dev->struct_mutex); 150 + mutex_unlock(&msm_obj->lock); 157 151 return p; 158 152 } 159 153 ··· 215 195 { 216 196 struct vm_area_struct *vma = vmf->vma; 217 197 struct drm_gem_object *obj = vma->vm_private_data; 218 - struct drm_device *dev = obj->dev; 219 - struct msm_drm_private *priv = dev->dev_private; 198 + struct msm_gem_object *msm_obj = to_msm_bo(obj); 220 199 struct page **pages; 221 200 unsigned long pfn; 222 201 pgoff_t pgoff; 223 202 int ret; 224 203 225 - /* This should only happen if userspace tries to pass a mmap'd 226 - * but unfaulted gem bo vaddr into submit ioctl, triggering 227 - * a page fault while struct_mutex is already held. This is 228 - * not a valid use-case so just bail. 204 + /* 205 + * vm_ops.open/drm_gem_mmap_obj and close get and put 206 + * a reference on obj. So, we dont need to hold one here. 229 207 */ 230 - if (priv->struct_mutex_task == current) 231 - return VM_FAULT_SIGBUS; 232 - 233 - /* Make sure we don't parallel update on a fault, nor move or remove 234 - * something from beneath our feet 235 - */ 236 - ret = mutex_lock_interruptible(&dev->struct_mutex); 208 + ret = mutex_lock_interruptible(&msm_obj->lock); 237 209 if (ret) 238 210 goto out; 211 + 212 + if (WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED)) { 213 + mutex_unlock(&msm_obj->lock); 214 + return VM_FAULT_SIGBUS; 215 + } 239 216 240 217 /* make sure we have pages attached now */ 241 218 pages = get_pages(obj); ··· 252 235 ret = vm_insert_mixed(vma, vmf->address, __pfn_to_pfn_t(pfn, PFN_DEV)); 253 236 254 237 out_unlock: 255 - mutex_unlock(&dev->struct_mutex); 238 + mutex_unlock(&msm_obj->lock); 256 239 out: 257 240 switch (ret) { 258 241 case -EAGAIN: ··· 276 259 static uint64_t mmap_offset(struct drm_gem_object *obj) 277 260 { 278 261 struct drm_device *dev = obj->dev; 262 + struct msm_gem_object *msm_obj = to_msm_bo(obj); 279 263 int ret; 280 264 281 - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); 265 + WARN_ON(!mutex_is_locked(&msm_obj->lock)); 282 266 283 267 /* Make it mmapable */ 284 268 ret = drm_gem_create_mmap_offset(obj); ··· 295 277 uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj) 296 278 { 297 279 uint64_t offset; 298 - mutex_lock(&obj->dev->struct_mutex); 280 + struct msm_gem_object *msm_obj = to_msm_bo(obj); 281 + 282 + mutex_lock(&msm_obj->lock); 299 283 offset = mmap_offset(obj); 300 - mutex_unlock(&obj->dev->struct_mutex); 284 + mutex_unlock(&msm_obj->lock); 301 285 return offset; 302 286 } 303 287 ··· 308 288 { 309 289 struct msm_gem_object *msm_obj = to_msm_bo(obj); 310 290 struct msm_gem_vma *vma; 291 + 292 + WARN_ON(!mutex_is_locked(&msm_obj->lock)); 311 293 312 294 vma = kzalloc(sizeof(*vma), GFP_KERNEL); 313 295 if (!vma) ··· 328 306 struct msm_gem_object *msm_obj = to_msm_bo(obj); 329 307 struct msm_gem_vma *vma; 330 308 331 - WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); 309 + WARN_ON(!mutex_is_locked(&msm_obj->lock)); 332 310 333 311 list_for_each_entry(vma, &msm_obj->vmas, list) { 334 312 if (vma->aspace == aspace) ··· 347 325 kfree(vma); 348 326 } 349 327 328 + /* Called with msm_obj->lock locked */ 350 329 static void 351 330 put_iova(struct drm_gem_object *obj) 352 331 { 353 332 struct msm_gem_object *msm_obj = to_msm_bo(obj); 354 333 struct msm_gem_vma *vma, *tmp; 355 334 356 - WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); 335 + WARN_ON(!mutex_is_locked(&msm_obj->lock)); 357 336 358 337 list_for_each_entry_safe(vma, tmp, &msm_obj->vmas, list) { 359 338 msm_gem_unmap_vma(vma->aspace, vma, msm_obj->sgt); ··· 362 339 } 363 340 } 364 341 365 - /* should be called under struct_mutex.. although it can be called 366 - * from atomic context without struct_mutex to acquire an extra 367 - * iova ref if you know one is already held. 368 - * 369 - * That means when I do eventually need to add support for unpinning 370 - * the refcnt counter needs to be atomic_t. 371 - */ 372 - int msm_gem_get_iova_locked(struct drm_gem_object *obj, 342 + /* get iova, taking a reference. Should have a matching put */ 343 + int msm_gem_get_iova(struct drm_gem_object *obj, 373 344 struct msm_gem_address_space *aspace, uint64_t *iova) 374 345 { 375 346 struct msm_gem_object *msm_obj = to_msm_bo(obj); 376 347 struct msm_gem_vma *vma; 377 348 int ret = 0; 378 349 379 - WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); 350 + mutex_lock(&msm_obj->lock); 351 + 352 + if (WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED)) { 353 + mutex_unlock(&msm_obj->lock); 354 + return -EBUSY; 355 + } 380 356 381 357 vma = lookup_vma(obj, aspace); 382 358 ··· 399 377 } 400 378 401 379 *iova = vma->iova; 380 + 381 + mutex_unlock(&msm_obj->lock); 402 382 return 0; 403 383 404 384 fail: 405 385 del_vma(vma); 406 386 407 - return ret; 408 - } 409 - 410 - /* get iova, taking a reference. Should have a matching put */ 411 - int msm_gem_get_iova(struct drm_gem_object *obj, 412 - struct msm_gem_address_space *aspace, uint64_t *iova) 413 - { 414 - int ret; 415 - 416 - mutex_lock(&obj->dev->struct_mutex); 417 - ret = msm_gem_get_iova_locked(obj, aspace, iova); 418 - mutex_unlock(&obj->dev->struct_mutex); 419 - 387 + mutex_unlock(&msm_obj->lock); 420 388 return ret; 421 389 } 422 390 ··· 416 404 uint64_t msm_gem_iova(struct drm_gem_object *obj, 417 405 struct msm_gem_address_space *aspace) 418 406 { 407 + struct msm_gem_object *msm_obj = to_msm_bo(obj); 419 408 struct msm_gem_vma *vma; 420 409 421 - mutex_lock(&obj->dev->struct_mutex); 410 + mutex_lock(&msm_obj->lock); 422 411 vma = lookup_vma(obj, aspace); 423 - mutex_unlock(&obj->dev->struct_mutex); 412 + mutex_unlock(&msm_obj->lock); 424 413 WARN_ON(!vma); 425 414 426 415 return vma ? vma->iova : 0; ··· 468 455 return ret; 469 456 } 470 457 471 - void *msm_gem_get_vaddr_locked(struct drm_gem_object *obj) 472 - { 473 - struct msm_gem_object *msm_obj = to_msm_bo(obj); 474 - WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); 475 - if (!msm_obj->vaddr) { 476 - struct page **pages = get_pages(obj); 477 - if (IS_ERR(pages)) 478 - return ERR_CAST(pages); 479 - msm_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT, 480 - VM_MAP, pgprot_writecombine(PAGE_KERNEL)); 481 - if (msm_obj->vaddr == NULL) 482 - return ERR_PTR(-ENOMEM); 483 - } 484 - msm_obj->vmap_count++; 485 - return msm_obj->vaddr; 486 - } 487 - 488 458 void *msm_gem_get_vaddr(struct drm_gem_object *obj) 489 459 { 490 - void *ret; 491 - mutex_lock(&obj->dev->struct_mutex); 492 - ret = msm_gem_get_vaddr_locked(obj); 493 - mutex_unlock(&obj->dev->struct_mutex); 494 - return ret; 495 - } 496 - 497 - void msm_gem_put_vaddr_locked(struct drm_gem_object *obj) 498 - { 499 460 struct msm_gem_object *msm_obj = to_msm_bo(obj); 500 - WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); 501 - WARN_ON(msm_obj->vmap_count < 1); 461 + int ret = 0; 462 + 463 + mutex_lock(&msm_obj->lock); 464 + 465 + if (WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED)) { 466 + mutex_unlock(&msm_obj->lock); 467 + return ERR_PTR(-EBUSY); 468 + } 469 + 470 + /* increment vmap_count *before* vmap() call, so shrinker can 471 + * check vmap_count (is_vunmapable()) outside of msm_obj->lock. 472 + * This guarantees that we won't try to msm_gem_vunmap() this 473 + * same object from within the vmap() call (while we already 474 + * hold msm_obj->lock) 475 + */ 476 + msm_obj->vmap_count++; 477 + 478 + if (!msm_obj->vaddr) { 479 + struct page **pages = get_pages(obj); 480 + if (IS_ERR(pages)) { 481 + ret = PTR_ERR(pages); 482 + goto fail; 483 + } 484 + msm_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT, 485 + VM_MAP, pgprot_writecombine(PAGE_KERNEL)); 486 + if (msm_obj->vaddr == NULL) { 487 + ret = -ENOMEM; 488 + goto fail; 489 + } 490 + } 491 + 492 + mutex_unlock(&msm_obj->lock); 493 + return msm_obj->vaddr; 494 + 495 + fail: 502 496 msm_obj->vmap_count--; 497 + mutex_unlock(&msm_obj->lock); 498 + return ERR_PTR(ret); 503 499 } 504 500 505 501 void msm_gem_put_vaddr(struct drm_gem_object *obj) 506 502 { 507 - mutex_lock(&obj->dev->struct_mutex); 508 - msm_gem_put_vaddr_locked(obj); 509 - mutex_unlock(&obj->dev->struct_mutex); 503 + struct msm_gem_object *msm_obj = to_msm_bo(obj); 504 + 505 + mutex_lock(&msm_obj->lock); 506 + WARN_ON(msm_obj->vmap_count < 1); 507 + msm_obj->vmap_count--; 508 + mutex_unlock(&msm_obj->lock); 510 509 } 511 510 512 511 /* Update madvise status, returns true if not purged, else ··· 528 503 { 529 504 struct msm_gem_object *msm_obj = to_msm_bo(obj); 530 505 506 + mutex_lock(&msm_obj->lock); 507 + 531 508 WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); 532 509 533 510 if (msm_obj->madv != __MSM_MADV_PURGED) 534 511 msm_obj->madv = madv; 535 512 536 - return (msm_obj->madv != __MSM_MADV_PURGED); 513 + madv = msm_obj->madv; 514 + 515 + mutex_unlock(&msm_obj->lock); 516 + 517 + return (madv != __MSM_MADV_PURGED); 537 518 } 538 519 539 - void msm_gem_purge(struct drm_gem_object *obj) 520 + void msm_gem_purge(struct drm_gem_object *obj, enum msm_gem_lock subclass) 540 521 { 541 522 struct drm_device *dev = obj->dev; 542 523 struct msm_gem_object *msm_obj = to_msm_bo(obj); ··· 551 520 WARN_ON(!is_purgeable(msm_obj)); 552 521 WARN_ON(obj->import_attach); 553 522 523 + mutex_lock_nested(&msm_obj->lock, subclass); 524 + 554 525 put_iova(obj); 555 526 556 - msm_gem_vunmap(obj); 527 + msm_gem_vunmap_locked(obj); 557 528 558 529 put_pages(obj); 559 530 ··· 573 540 574 541 invalidate_mapping_pages(file_inode(obj->filp)->i_mapping, 575 542 0, (loff_t)-1); 543 + 544 + mutex_unlock(&msm_obj->lock); 576 545 } 577 546 578 - void msm_gem_vunmap(struct drm_gem_object *obj) 547 + static void msm_gem_vunmap_locked(struct drm_gem_object *obj) 579 548 { 580 549 struct msm_gem_object *msm_obj = to_msm_bo(obj); 550 + 551 + WARN_ON(!mutex_is_locked(&msm_obj->lock)); 581 552 582 553 if (!msm_obj->vaddr || WARN_ON(!is_vunmapable(msm_obj))) 583 554 return; 584 555 585 556 vunmap(msm_obj->vaddr); 586 557 msm_obj->vaddr = NULL; 558 + } 559 + 560 + void msm_gem_vunmap(struct drm_gem_object *obj, enum msm_gem_lock subclass) 561 + { 562 + struct msm_gem_object *msm_obj = to_msm_bo(obj); 563 + 564 + mutex_lock_nested(&msm_obj->lock, subclass); 565 + msm_gem_vunmap_locked(obj); 566 + mutex_unlock(&msm_obj->lock); 587 567 } 588 568 589 569 /* must be called before _move_to_active().. */ ··· 720 674 uint64_t off = drm_vma_node_start(&obj->vma_node); 721 675 const char *madv; 722 676 723 - WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); 677 + mutex_lock(&msm_obj->lock); 724 678 725 679 switch (msm_obj->madv) { 726 680 case __MSM_MADV_PURGED: ··· 761 715 if (fence) 762 716 describe_fence(fence, "Exclusive", m); 763 717 rcu_read_unlock(); 718 + 719 + mutex_unlock(&msm_obj->lock); 764 720 } 765 721 766 722 void msm_gem_describe_objects(struct list_head *list, struct seq_file *m) ··· 795 747 796 748 list_del(&msm_obj->mm_list); 797 749 750 + mutex_lock(&msm_obj->lock); 751 + 798 752 put_iova(obj); 799 753 800 754 if (obj->import_attach) { ··· 811 761 812 762 drm_prime_gem_destroy(obj, msm_obj->sgt); 813 763 } else { 814 - msm_gem_vunmap(obj); 764 + msm_gem_vunmap_locked(obj); 815 765 put_pages(obj); 816 766 } 817 767 ··· 820 770 821 771 drm_gem_object_release(obj); 822 772 773 + mutex_unlock(&msm_obj->lock); 823 774 kfree(msm_obj); 824 775 } 825 776 ··· 831 780 struct drm_gem_object *obj; 832 781 int ret; 833 782 834 - ret = mutex_lock_interruptible(&dev->struct_mutex); 835 - if (ret) 836 - return ret; 837 - 838 783 obj = msm_gem_new(dev, size, flags); 839 - 840 - mutex_unlock(&dev->struct_mutex); 841 784 842 785 if (IS_ERR(obj)) 843 786 return PTR_ERR(obj); ··· 847 802 static int msm_gem_new_impl(struct drm_device *dev, 848 803 uint32_t size, uint32_t flags, 849 804 struct reservation_object *resv, 850 - struct drm_gem_object **obj) 805 + struct drm_gem_object **obj, 806 + bool struct_mutex_locked) 851 807 { 852 808 struct msm_drm_private *priv = dev->dev_private; 853 809 struct msm_gem_object *msm_obj; 854 - 855 - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); 856 810 857 811 switch (flags & MSM_BO_CACHE_MASK) { 858 812 case MSM_BO_UNCACHED: ··· 868 824 if (!msm_obj) 869 825 return -ENOMEM; 870 826 827 + mutex_init(&msm_obj->lock); 828 + 871 829 msm_obj->flags = flags; 872 830 msm_obj->madv = MSM_MADV_WILLNEED; 873 831 ··· 883 837 INIT_LIST_HEAD(&msm_obj->submit_entry); 884 838 INIT_LIST_HEAD(&msm_obj->vmas); 885 839 886 - list_add_tail(&msm_obj->mm_list, &priv->inactive_list); 840 + if (struct_mutex_locked) { 841 + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); 842 + list_add_tail(&msm_obj->mm_list, &priv->inactive_list); 843 + } else { 844 + mutex_lock(&dev->struct_mutex); 845 + list_add_tail(&msm_obj->mm_list, &priv->inactive_list); 846 + mutex_unlock(&dev->struct_mutex); 847 + } 887 848 888 849 *obj = &msm_obj->base; 889 850 890 851 return 0; 891 852 } 892 853 893 - struct drm_gem_object *msm_gem_new(struct drm_device *dev, 894 - uint32_t size, uint32_t flags) 854 + static struct drm_gem_object *_msm_gem_new(struct drm_device *dev, 855 + uint32_t size, uint32_t flags, bool struct_mutex_locked) 895 856 { 896 857 struct msm_drm_private *priv = dev->dev_private; 897 858 struct drm_gem_object *obj = NULL; 898 859 bool use_vram = false; 899 860 int ret; 900 - 901 - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); 902 861 903 862 size = PAGE_ALIGN(size); 904 863 ··· 921 870 if (size == 0) 922 871 return ERR_PTR(-EINVAL); 923 872 924 - ret = msm_gem_new_impl(dev, size, flags, NULL, &obj); 873 + ret = msm_gem_new_impl(dev, size, flags, NULL, &obj, struct_mutex_locked); 925 874 if (ret) 926 875 goto fail; 927 876 ··· 955 904 return obj; 956 905 957 906 fail: 958 - drm_gem_object_unreference(obj); 907 + drm_gem_object_unreference_unlocked(obj); 959 908 return ERR_PTR(ret); 909 + } 910 + 911 + struct drm_gem_object *msm_gem_new_locked(struct drm_device *dev, 912 + uint32_t size, uint32_t flags) 913 + { 914 + return _msm_gem_new(dev, size, flags, true); 915 + } 916 + 917 + struct drm_gem_object *msm_gem_new(struct drm_device *dev, 918 + uint32_t size, uint32_t flags) 919 + { 920 + return _msm_gem_new(dev, size, flags, false); 960 921 } 961 922 962 923 struct drm_gem_object *msm_gem_import(struct drm_device *dev, ··· 987 924 988 925 size = PAGE_ALIGN(dmabuf->size); 989 926 990 - /* Take mutex so we can modify the inactive list in msm_gem_new_impl */ 991 - mutex_lock(&dev->struct_mutex); 992 - ret = msm_gem_new_impl(dev, size, MSM_BO_WC, dmabuf->resv, &obj); 993 - mutex_unlock(&dev->struct_mutex); 994 - 927 + ret = msm_gem_new_impl(dev, size, MSM_BO_WC, dmabuf->resv, &obj, false); 995 928 if (ret) 996 929 goto fail; 997 930 ··· 996 937 npages = size / PAGE_SIZE; 997 938 998 939 msm_obj = to_msm_bo(obj); 940 + mutex_lock(&msm_obj->lock); 999 941 msm_obj->sgt = sgt; 1000 942 msm_obj->pages = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); 1001 943 if (!msm_obj->pages) { 944 + mutex_unlock(&msm_obj->lock); 1002 945 ret = -ENOMEM; 1003 946 goto fail; 1004 947 } 1005 948 1006 949 ret = drm_prime_sg_to_page_addr_arrays(sgt, msm_obj->pages, NULL, npages); 1007 - if (ret) 950 + if (ret) { 951 + mutex_unlock(&msm_obj->lock); 1008 952 goto fail; 953 + } 1009 954 955 + mutex_unlock(&msm_obj->lock); 1010 956 return obj; 1011 957 1012 958 fail:
+22
drivers/gpu/drm/msm/msm_gem.h
··· 31 31 * and position mm_node->start is in # of pages: 32 32 */ 33 33 struct drm_mm mm; 34 + spinlock_t lock; /* Protects drm_mm node allocation/removal */ 34 35 struct msm_mmu *mmu; 35 36 struct kref kref; 36 37 }; ··· 90 89 * an IOMMU. Also used for stolen/splashscreen buffer. 91 90 */ 92 91 struct drm_mm_node *vram_node; 92 + struct mutex lock; /* Protects resources associated with bo */ 93 93 }; 94 94 #define to_msm_bo(x) container_of(x, struct msm_gem_object, base) 95 95 ··· 101 99 102 100 static inline bool is_purgeable(struct msm_gem_object *msm_obj) 103 101 { 102 + WARN_ON(!mutex_is_locked(&msm_obj->base.dev->struct_mutex)); 104 103 return (msm_obj->madv == MSM_MADV_DONTNEED) && msm_obj->sgt && 105 104 !msm_obj->base.dma_buf && !msm_obj->base.import_attach; 106 105 } ··· 110 107 { 111 108 return (msm_obj->vmap_count == 0) && msm_obj->vaddr; 112 109 } 110 + 111 + /* The shrinker can be triggered while we hold objA->lock, and need 112 + * to grab objB->lock to purge it. Lockdep just sees these as a single 113 + * class of lock, so we use subclasses to teach it the difference. 114 + * 115 + * OBJ_LOCK_NORMAL is implicit (ie. normal mutex_lock() call), and 116 + * OBJ_LOCK_SHRINKER is used by shrinker. 117 + * 118 + * It is *essential* that we never go down paths that could trigger the 119 + * shrinker for a purgable object. This is ensured by checking that 120 + * msm_obj->madv == MSM_MADV_WILLNEED. 121 + */ 122 + enum msm_gem_lock { 123 + OBJ_LOCK_NORMAL, 124 + OBJ_LOCK_SHRINKER, 125 + }; 126 + 127 + void msm_gem_purge(struct drm_gem_object *obj, enum msm_gem_lock subclass); 128 + void msm_gem_vunmap(struct drm_gem_object *obj, enum msm_gem_lock subclass); 113 129 114 130 /* Created per submit-ioctl, to track bo's and cmdstream bufs, etc, 115 131 * associated with the cmdstream submission for synchronization (and
+14 -2
drivers/gpu/drm/msm/msm_gem_shrinker.c
··· 20 20 21 21 static bool msm_gem_shrinker_lock(struct drm_device *dev, bool *unlock) 22 22 { 23 + /* NOTE: we are *closer* to being able to get rid of 24 + * mutex_trylock_recursive().. the msm_gem code itself does 25 + * not need struct_mutex, although codepaths that can trigger 26 + * shrinker are still called in code-paths that hold the 27 + * struct_mutex. 28 + * 29 + * Also, msm_obj->madv is protected by struct_mutex. 30 + * 31 + * The next step is probably split out a seperate lock for 32 + * protecting inactive_list, so that shrinker does not need 33 + * struct_mutex. 34 + */ 23 35 switch (mutex_trylock_recursive(&dev->struct_mutex)) { 24 36 case MUTEX_TRYLOCK_FAILED: 25 37 return false; ··· 89 77 if (freed >= sc->nr_to_scan) 90 78 break; 91 79 if (is_purgeable(msm_obj)) { 92 - msm_gem_purge(&msm_obj->base); 80 + msm_gem_purge(&msm_obj->base, OBJ_LOCK_SHRINKER); 93 81 freed += msm_obj->base.size >> PAGE_SHIFT; 94 82 } 95 83 } ··· 118 106 119 107 list_for_each_entry(msm_obj, &priv->inactive_list, mm_list) { 120 108 if (is_vunmapable(msm_obj)) { 121 - msm_gem_vunmap(&msm_obj->base); 109 + msm_gem_vunmap(&msm_obj->base, OBJ_LOCK_SHRINKER); 122 110 /* since we don't know any better, lets bail after a few 123 111 * and if necessary the shrinker will be invoked again. 124 112 * Seems better than unmapping *everything*
+3 -3
drivers/gpu/drm/msm/msm_gem_submit.c
··· 245 245 uint64_t iova; 246 246 247 247 /* if locking succeeded, pin bo: */ 248 - ret = msm_gem_get_iova_locked(&msm_obj->base, 248 + ret = msm_gem_get_iova(&msm_obj->base, 249 249 submit->gpu->aspace, &iova); 250 250 251 251 if (ret) ··· 301 301 /* For now, just map the entire thing. Eventually we probably 302 302 * to do it page-by-page, w/ kmap() if not vmap()d.. 303 303 */ 304 - ptr = msm_gem_get_vaddr_locked(&obj->base); 304 + ptr = msm_gem_get_vaddr(&obj->base); 305 305 306 306 if (IS_ERR(ptr)) { 307 307 ret = PTR_ERR(ptr); ··· 359 359 } 360 360 361 361 out: 362 - msm_gem_put_vaddr_locked(&obj->base); 362 + msm_gem_put_vaddr(&obj->base); 363 363 364 364 return ret; 365 365 }
+9 -1
drivers/gpu/drm/msm/msm_gem_vma.c
··· 50 50 aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt, size); 51 51 } 52 52 53 + spin_lock(&aspace->lock); 53 54 drm_mm_remove_node(&vma->node); 55 + spin_unlock(&aspace->lock); 54 56 55 57 vma->iova = 0; 56 58 ··· 65 63 { 66 64 int ret; 67 65 68 - if (WARN_ON(drm_mm_node_allocated(&vma->node))) 66 + spin_lock(&aspace->lock); 67 + if (WARN_ON(drm_mm_node_allocated(&vma->node))) { 68 + spin_unlock(&aspace->lock); 69 69 return 0; 70 + } 70 71 71 72 ret = drm_mm_insert_node(&aspace->mm, &vma->node, npages); 73 + spin_unlock(&aspace->lock); 74 + 72 75 if (ret) 73 76 return ret; 74 77 ··· 101 94 if (!aspace) 102 95 return ERR_PTR(-ENOMEM); 103 96 97 + spin_lock_init(&aspace->lock); 104 98 aspace->name = name; 105 99 aspace->mmu = msm_iommu_new(dev, domain); 106 100
+1 -3
drivers/gpu/drm/msm/msm_gpu.c
··· 497 497 498 498 /* submit takes a reference to the bo and iova until retired: */ 499 499 drm_gem_object_reference(&msm_obj->base); 500 - msm_gem_get_iova_locked(&msm_obj->base, 500 + msm_gem_get_iova(&msm_obj->base, 501 501 submit->gpu->aspace, &iova); 502 502 503 503 if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE) ··· 661 661 } 662 662 663 663 /* Create ringbuffer: */ 664 - mutex_lock(&drm->struct_mutex); 665 664 gpu->rb = msm_ringbuffer_new(gpu, config->ringsz); 666 - mutex_unlock(&drm->struct_mutex); 667 665 if (IS_ERR(gpu->rb)) { 668 666 ret = PTR_ERR(gpu->rb); 669 667 gpu->rb = NULL;
+2 -2
drivers/gpu/drm/msm/msm_rd.c
··· 268 268 struct msm_gem_object *obj = submit->bos[idx].obj; 269 269 const char *buf; 270 270 271 - buf = msm_gem_get_vaddr_locked(&obj->base); 271 + buf = msm_gem_get_vaddr(&obj->base); 272 272 if (IS_ERR(buf)) 273 273 return; 274 274 ··· 283 283 (uint32_t[3]){ iova, size, iova >> 32 }, 12); 284 284 rd_write_section(rd, RD_BUFFER_CONTENTS, buf, size); 285 285 286 - msm_gem_put_vaddr_locked(&obj->base); 286 + msm_gem_put_vaddr(&obj->base); 287 287 } 288 288 289 289 /* called under struct_mutex */
+1 -1
drivers/gpu/drm/msm/msm_ringbuffer.c
··· 40 40 goto fail; 41 41 } 42 42 43 - ring->start = msm_gem_get_vaddr_locked(ring->bo); 43 + ring->start = msm_gem_get_vaddr(ring->bo); 44 44 if (IS_ERR(ring->start)) { 45 45 ret = PTR_ERR(ring->start); 46 46 goto fail;