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

drm/msm: introduce msm_fence_context

Better encapsulate the per-timeline stuff into fence-context. For now
there is just a single fence-context, but eventually we'll also have one
per-CRTC to enable fully explicit fencing.

Signed-off-by: Rob Clark <robdclark@gmail.com>

Rob Clark ca762a8a 340faef2

+108 -78
+3 -3
drivers/gpu/drm/msm/adreno/adreno_gpu.c
··· 121 121 gpu->rb->cur = gpu->rb->start; 122 122 123 123 /* reset completed fence seqno, just discard anything pending: */ 124 - adreno_gpu->memptrs->fence = gpu->submitted_fence; 124 + adreno_gpu->memptrs->fence = gpu->fctx->last_fence; 125 125 adreno_gpu->memptrs->rptr = 0; 126 126 adreno_gpu->memptrs->wptr = 0; 127 127 ··· 254 254 adreno_gpu->rev.patchid); 255 255 256 256 seq_printf(m, "fence: %d/%d\n", adreno_gpu->memptrs->fence, 257 - gpu->submitted_fence); 257 + gpu->fctx->last_fence); 258 258 seq_printf(m, "rptr: %d\n", get_rptr(adreno_gpu)); 259 259 seq_printf(m, "wptr: %d\n", adreno_gpu->memptrs->wptr); 260 260 seq_printf(m, "rb wptr: %d\n", get_wptr(gpu->rb)); ··· 295 295 adreno_gpu->rev.patchid); 296 296 297 297 printk("fence: %d/%d\n", adreno_gpu->memptrs->fence, 298 - gpu->submitted_fence); 298 + gpu->fctx->last_fence); 299 299 printk("rptr: %d\n", get_rptr(adreno_gpu)); 300 300 printk("wptr: %d\n", adreno_gpu->memptrs->wptr); 301 301 printk("rb wptr: %d\n", get_wptr(gpu->rb));
+6 -3
drivers/gpu/drm/msm/msm_atomic.c
··· 18 18 #include "msm_drv.h" 19 19 #include "msm_kms.h" 20 20 #include "msm_gem.h" 21 + #include "msm_gpu.h" /* temporary */ 21 22 #include "msm_fence.h" 22 23 23 24 struct msm_commit { ··· 203 202 int msm_atomic_commit(struct drm_device *dev, 204 203 struct drm_atomic_state *state, bool nonblock) 205 204 { 205 + struct msm_drm_private *priv = dev->dev_private; 206 206 int nplanes = dev->mode_config.num_total_plane; 207 207 int ncrtcs = dev->mode_config.num_crtc; 208 208 ktime_t timeout; ··· 278 276 * current layout. 279 277 */ 280 278 281 - if (nonblock) { 282 - msm_queue_fence_cb(dev, &c->fence_cb, c->fence); 279 + if (nonblock && priv->gpu) { 280 + msm_queue_fence_cb(priv->gpu->fctx, &c->fence_cb, c->fence); 283 281 return 0; 284 282 } 285 283 286 284 timeout = ktime_add_ms(ktime_get(), 1000); 287 285 288 286 /* uninterruptible wait */ 289 - msm_wait_fence(dev, c->fence, &timeout, false); 287 + if (priv->gpu) 288 + msm_wait_fence(priv->gpu->fctx, c->fence, &timeout, false); 290 289 291 290 complete_commit(c); 292 291
+5 -3
drivers/gpu/drm/msm/msm_drv.c
··· 339 339 dev->dev_private = priv; 340 340 341 341 priv->wq = alloc_ordered_workqueue("msm", 0); 342 - init_waitqueue_head(&priv->fence_event); 343 342 init_waitqueue_head(&priv->pending_crtcs_event); 344 343 345 344 INIT_LIST_HEAD(&priv->inactive_list); 346 - INIT_LIST_HEAD(&priv->fence_cbs); 347 345 INIT_LIST_HEAD(&priv->vblank_ctrl.event_list); 348 346 INIT_WORK(&priv->vblank_ctrl.work, vblank_ctrl_worker); 349 347 spin_lock_init(&priv->vblank_ctrl.lock); ··· 645 647 static int msm_ioctl_wait_fence(struct drm_device *dev, void *data, 646 648 struct drm_file *file) 647 649 { 650 + struct msm_drm_private *priv = dev->dev_private; 648 651 struct drm_msm_wait_fence *args = data; 649 652 ktime_t timeout = to_ktime(args->timeout); 650 653 ··· 654 655 return -EINVAL; 655 656 } 656 657 657 - return msm_wait_fence(dev, args->fence, &timeout, true); 658 + if (!priv->gpu) 659 + return 0; 660 + 661 + return msm_wait_fence(priv->gpu->fctx, args->fence, &timeout, true); 658 662 } 659 663 660 664 static const struct drm_ioctl_desc msm_ioctls[] = {
+1 -8
drivers/gpu/drm/msm/msm_drv.h
··· 49 49 struct msm_rd_state; 50 50 struct msm_perf_state; 51 51 struct msm_gem_submit; 52 + struct msm_fence_context; 52 53 struct msm_fence_cb; 53 54 54 55 #define NUM_DOMAINS 2 /* one for KMS, then one per gpu core (?) */ ··· 102 101 103 102 struct drm_fb_helper *fbdev; 104 103 105 - uint32_t next_fence, completed_fence; 106 - wait_queue_head_t fence_event; 107 - 108 104 struct msm_rd_state *rd; 109 105 struct msm_perf_state *perf; 110 106 ··· 109 111 struct list_head inactive_list; 110 112 111 113 struct workqueue_struct *wq; 112 - 113 - /* callbacks deferred until bo is inactive: */ 114 - struct list_head fence_cbs; 115 114 116 115 /* crtcs pending async atomic updates: */ 117 116 uint32_t pending_crtcs; ··· 189 194 void msm_gem_prime_unpin(struct drm_gem_object *obj); 190 195 void *msm_gem_vaddr_locked(struct drm_gem_object *obj); 191 196 void *msm_gem_vaddr(struct drm_gem_object *obj); 192 - int msm_gem_queue_inactive_cb(struct drm_gem_object *obj, 193 - struct msm_fence_cb *cb); 194 197 void msm_gem_move_to_active(struct drm_gem_object *obj, 195 198 struct msm_gpu *gpu, bool write, uint32_t fence); 196 199 void msm_gem_move_to_inactive(struct drm_gem_object *obj);
+53 -34
drivers/gpu/drm/msm/msm_fence.c
··· 15 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 16 */ 17 17 18 + #include <linux/fence.h> 19 + 18 20 #include "msm_drv.h" 19 21 #include "msm_fence.h" 20 - #include "msm_gpu.h" 21 22 22 - static inline bool fence_completed(struct drm_device *dev, uint32_t fence) 23 + 24 + struct msm_fence_context * 25 + msm_fence_context_alloc(struct drm_device *dev, const char *name) 23 26 { 24 - struct msm_drm_private *priv = dev->dev_private; 25 - return (int32_t)(priv->completed_fence - fence) >= 0; 27 + struct msm_fence_context *fctx; 28 + 29 + fctx = kzalloc(sizeof(*fctx), GFP_KERNEL); 30 + if (!fctx) 31 + return ERR_PTR(-ENOMEM); 32 + 33 + fctx->dev = dev; 34 + fctx->name = name; 35 + init_waitqueue_head(&fctx->event); 36 + INIT_LIST_HEAD(&fctx->fence_cbs); 37 + 38 + return fctx; 26 39 } 27 40 28 - int msm_wait_fence(struct drm_device *dev, uint32_t fence, 29 - ktime_t *timeout , bool interruptible) 41 + void msm_fence_context_free(struct msm_fence_context *fctx) 30 42 { 31 - struct msm_drm_private *priv = dev->dev_private; 43 + kfree(fctx); 44 + } 45 + 46 + static inline bool fence_completed(struct msm_fence_context *fctx, uint32_t fence) 47 + { 48 + return (int32_t)(fctx->completed_fence - fence) >= 0; 49 + } 50 + 51 + int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence, 52 + ktime_t *timeout, bool interruptible) 53 + { 32 54 int ret; 33 55 34 - if (!priv->gpu) 35 - return 0; 36 - 37 - if (fence > priv->gpu->submitted_fence) { 38 - DRM_ERROR("waiting on invalid fence: %u (of %u)\n", 39 - fence, priv->gpu->submitted_fence); 56 + if (fence > fctx->last_fence) { 57 + DRM_ERROR("%s: waiting on invalid fence: %u (of %u)\n", 58 + fctx->name, fence, fctx->last_fence); 40 59 return -EINVAL; 41 60 } 42 61 43 62 if (!timeout) { 44 63 /* no-wait: */ 45 - ret = fence_completed(dev, fence) ? 0 : -EBUSY; 64 + ret = fence_completed(fctx, fence) ? 0 : -EBUSY; 46 65 } else { 47 66 unsigned long remaining_jiffies = timeout_to_jiffies(timeout); 48 67 49 68 if (interruptible) 50 - ret = wait_event_interruptible_timeout(priv->fence_event, 51 - fence_completed(dev, fence), 69 + ret = wait_event_interruptible_timeout(fctx->event, 70 + fence_completed(fctx, fence), 52 71 remaining_jiffies); 53 72 else 54 - ret = wait_event_timeout(priv->fence_event, 55 - fence_completed(dev, fence), 73 + ret = wait_event_timeout(fctx->event, 74 + fence_completed(fctx, fence), 56 75 remaining_jiffies); 57 76 58 77 if (ret == 0) { 59 78 DBG("timeout waiting for fence: %u (completed: %u)", 60 - fence, priv->completed_fence); 79 + fence, fctx->completed_fence); 61 80 ret = -ETIMEDOUT; 62 81 } else if (ret != -ERESTARTSYS) { 63 82 ret = 0; ··· 86 67 return ret; 87 68 } 88 69 89 - int msm_queue_fence_cb(struct drm_device *dev, 70 + int msm_queue_fence_cb(struct msm_fence_context *fctx, 90 71 struct msm_fence_cb *cb, uint32_t fence) 91 72 { 92 - struct msm_drm_private *priv = dev->dev_private; 73 + struct msm_drm_private *priv = fctx->dev->dev_private; 93 74 int ret = 0; 94 75 95 - mutex_lock(&dev->struct_mutex); 76 + mutex_lock(&fctx->dev->struct_mutex); 96 77 if (!list_empty(&cb->work.entry)) { 97 78 ret = -EINVAL; 98 - } else if (fence > priv->completed_fence) { 79 + } else if (fence > fctx->completed_fence) { 99 80 cb->fence = fence; 100 - list_add_tail(&cb->work.entry, &priv->fence_cbs); 81 + list_add_tail(&cb->work.entry, &fctx->fence_cbs); 101 82 } else { 102 83 queue_work(priv->wq, &cb->work); 103 84 } 104 - mutex_unlock(&dev->struct_mutex); 85 + mutex_unlock(&fctx->dev->struct_mutex); 105 86 106 87 return ret; 107 88 } 108 89 109 90 /* called from workqueue */ 110 - void msm_update_fence(struct drm_device *dev, uint32_t fence) 91 + void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence) 111 92 { 112 - struct msm_drm_private *priv = dev->dev_private; 93 + struct msm_drm_private *priv = fctx->dev->dev_private; 113 94 114 - mutex_lock(&dev->struct_mutex); 115 - priv->completed_fence = max(fence, priv->completed_fence); 95 + mutex_lock(&fctx->dev->struct_mutex); 96 + fctx->completed_fence = max(fence, fctx->completed_fence); 116 97 117 - while (!list_empty(&priv->fence_cbs)) { 98 + while (!list_empty(&fctx->fence_cbs)) { 118 99 struct msm_fence_cb *cb; 119 100 120 - cb = list_first_entry(&priv->fence_cbs, 101 + cb = list_first_entry(&fctx->fence_cbs, 121 102 struct msm_fence_cb, work.entry); 122 103 123 - if (cb->fence > priv->completed_fence) 104 + if (cb->fence > fctx->completed_fence) 124 105 break; 125 106 126 107 list_del_init(&cb->work.entry); 127 108 queue_work(priv->wq, &cb->work); 128 109 } 129 110 130 - mutex_unlock(&dev->struct_mutex); 111 + mutex_unlock(&fctx->dev->struct_mutex); 131 112 132 - wake_up_all(&priv->fence_event); 113 + wake_up_all(&fctx->event); 133 114 } 134 115 135 116 void __msm_fence_worker(struct work_struct *work)
+18 -3
drivers/gpu/drm/msm/msm_fence.h
··· 20 20 21 21 #include "msm_drv.h" 22 22 23 + struct msm_fence_context { 24 + struct drm_device *dev; 25 + const char *name; 26 + /* last_fence == completed_fence --> no pending work */ 27 + uint32_t last_fence; /* last assigned fence */ 28 + uint32_t completed_fence; /* last completed fence */ 29 + wait_queue_head_t event; 30 + /* callbacks deferred until bo is inactive: */ 31 + struct list_head fence_cbs; 32 + }; 33 + 34 + struct msm_fence_context * msm_fence_context_alloc(struct drm_device *dev, 35 + const char *name); 36 + void msm_fence_context_free(struct msm_fence_context *fctx); 37 + 23 38 /* callback from wq once fence has passed: */ 24 39 struct msm_fence_cb { 25 40 struct work_struct work; ··· 49 34 (_cb)->func = _func; \ 50 35 } while (0) 51 36 52 - int msm_wait_fence(struct drm_device *dev, uint32_t fence, 37 + int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence, 53 38 ktime_t *timeout, bool interruptible); 54 - int msm_queue_fence_cb(struct drm_device *dev, 39 + int msm_queue_fence_cb(struct msm_fence_context *fctx, 55 40 struct msm_fence_cb *cb, uint32_t fence); 56 - void msm_update_fence(struct drm_device *dev, uint32_t fence); 41 + void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence); 57 42 58 43 #endif
+3 -13
drivers/gpu/drm/msm/msm_gem.c
··· 411 411 return ret; 412 412 } 413 413 414 - /* setup callback for when bo is no longer busy.. 415 - * TODO probably want to differentiate read vs write.. 416 - */ 417 - int msm_gem_queue_inactive_cb(struct drm_gem_object *obj, 418 - struct msm_fence_cb *cb) 419 - { 420 - struct msm_gem_object *msm_obj = to_msm_bo(obj); 421 - uint32_t fence = msm_gem_fence(msm_obj, 422 - MSM_PREP_READ | MSM_PREP_WRITE); 423 - return msm_queue_fence_cb(obj->dev, cb, fence); 424 - } 425 - 426 414 void msm_gem_move_to_active(struct drm_gem_object *obj, 427 415 struct msm_gpu *gpu, bool write, uint32_t fence) 428 416 { ··· 442 454 int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) 443 455 { 444 456 struct drm_device *dev = obj->dev; 457 + struct msm_drm_private *priv = dev->dev_private; 445 458 struct msm_gem_object *msm_obj = to_msm_bo(obj); 446 459 int ret = 0; 447 460 ··· 452 463 if (op & MSM_PREP_NOSYNC) 453 464 timeout = NULL; 454 465 455 - ret = msm_wait_fence(dev, fence, timeout, true); 466 + if (priv->gpu) 467 + ret = msm_wait_fence(priv->gpu->fctx, fence, timeout, true); 456 468 } 457 469 458 470 /* TODO cache maintenance */
+14 -9
drivers/gpu/drm/msm/msm_gpu.c
··· 313 313 if (fence != gpu->hangcheck_fence) { 314 314 /* some progress has been made.. ya! */ 315 315 gpu->hangcheck_fence = fence; 316 - } else if (fence < gpu->submitted_fence) { 316 + } else if (fence < gpu->fctx->last_fence) { 317 317 /* no progress and not done.. hung! */ 318 318 gpu->hangcheck_fence = fence; 319 319 dev_err(dev->dev, "%s: hangcheck detected gpu lockup!\n", ··· 321 321 dev_err(dev->dev, "%s: completed fence: %u\n", 322 322 gpu->name, fence); 323 323 dev_err(dev->dev, "%s: submitted fence: %u\n", 324 - gpu->name, gpu->submitted_fence); 324 + gpu->name, gpu->fctx->last_fence); 325 325 queue_work(priv->wq, &gpu->recover_work); 326 326 } 327 327 328 328 /* if still more pending work, reset the hangcheck timer: */ 329 - if (gpu->submitted_fence > gpu->hangcheck_fence) 329 + if (gpu->fctx->last_fence > gpu->hangcheck_fence) 330 330 hangcheck_timer_reset(gpu); 331 331 332 332 /* workaround for missing irq: */ ··· 474 474 struct drm_device *dev = gpu->dev; 475 475 uint32_t fence = gpu->funcs->last_fence(gpu); 476 476 477 - msm_update_fence(gpu->dev, fence); 477 + msm_update_fence(gpu->fctx, fence); 478 478 479 479 mutex_lock(&dev->struct_mutex); 480 480 retire_submits(gpu, fence); ··· 502 502 503 503 WARN_ON(!mutex_is_locked(&dev->struct_mutex)); 504 504 505 - submit->fence = ++priv->next_fence; 506 - 507 - gpu->submitted_fence = submit->fence; 505 + submit->fence = ++gpu->fctx->last_fence; 508 506 509 507 inactive_cancel(gpu); 510 508 511 509 list_add_tail(&submit->node, &gpu->submit_list); 512 510 513 511 msm_rd_dump_submit(submit); 514 - 515 - gpu->submitted_fence = submit->fence; 516 512 517 513 update_sw_cntrs(gpu); 518 514 ··· 570 574 gpu->funcs = funcs; 571 575 gpu->name = name; 572 576 gpu->inactive = true; 577 + gpu->fctx = msm_fence_context_alloc(drm, name); 578 + if (IS_ERR(gpu->fctx)) { 579 + ret = PTR_ERR(gpu->fctx); 580 + gpu->fctx = NULL; 581 + goto fail; 582 + } 573 583 574 584 INIT_LIST_HEAD(&gpu->active_list); 575 585 INIT_WORK(&gpu->retire_work, retire_worker); ··· 696 694 697 695 if (gpu->mmu) 698 696 gpu->mmu->funcs->destroy(gpu->mmu); 697 + 698 + if (gpu->fctx) 699 + msm_fence_context_free(gpu->fctx); 699 700 }
+5 -2
drivers/gpu/drm/msm/msm_gpu.h
··· 22 22 #include <linux/regulator/consumer.h> 23 23 24 24 #include "msm_drv.h" 25 + #include "msm_fence.h" 25 26 #include "msm_ringbuffer.h" 26 27 27 28 struct msm_gem_submit; ··· 78 77 const struct msm_gpu_perfcntr *perfcntrs; 79 78 uint32_t num_perfcntrs; 80 79 80 + /* ringbuffer: */ 81 81 struct msm_ringbuffer *rb; 82 82 uint32_t rb_iova; 83 83 84 84 /* list of GEM active objects: */ 85 85 struct list_head active_list; 86 86 87 - uint32_t submitted_fence; 87 + /* fencing: */ 88 + struct msm_fence_context *fctx; 88 89 89 90 /* is gpu powered/active? */ 90 91 int active_cnt; ··· 128 125 129 126 static inline bool msm_gpu_active(struct msm_gpu *gpu) 130 127 { 131 - return gpu->submitted_fence > gpu->funcs->last_fence(gpu); 128 + return gpu->fctx->last_fence > gpu->funcs->last_fence(gpu); 132 129 } 133 130 134 131 /* Perf-Counters: