diff options
| author | Rob Clark <robdclark@gmail.com> | 2013-09-14 14:01:55 -0400 |
|---|---|---|
| committer | Rob Clark <robdclark@gmail.com> | 2013-11-01 12:39:45 -0400 |
| commit | edd4fc63a33eeeb922503b14e8040a3b028c76a5 (patch) | |
| tree | 6916bd23f5af0045c7fad9e0fb73eff5990e02aa /drivers/gpu | |
| parent | a862391871004bf8dea2299bb712aa93a512334a (diff) | |
drm/msm: rework inactive-work
Re-arrange things a bit so that we can get work requested after a bo
fence passes, like pageflip, done before retiring bo's. Without any
sort of bo cache in userspace, some games can trigger hundred's of
transient bo's, which can cause retire to take a long time (5-10ms).
Obviously we want a bo cache.. but this cleanup will make things a
bit easier for atomic as well and makes things a bit cleaner.
Signed-off-by: Rob Clark <robdclark@gmail.com>
Acked-by: David Brown <davidb@codeaurora.org>
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/msm/mdp4/mdp4_crtc.c | 11 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 30 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_drv.h | 21 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_gem.c | 35 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_gem.h | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_gpu.c | 4 |
6 files changed, 71 insertions, 33 deletions
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c index 5a68aab66fa2..1d52896dfa89 100644 --- a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c | |||
| @@ -51,7 +51,7 @@ struct mdp4_crtc { | |||
| 51 | 51 | ||
| 52 | /* if there is a pending flip, these will be non-null: */ | 52 | /* if there is a pending flip, these will be non-null: */ |
| 53 | struct drm_pending_vblank_event *event; | 53 | struct drm_pending_vblank_event *event; |
| 54 | struct work_struct pageflip_work; | 54 | struct msm_fence_cb pageflip_cb; |
| 55 | 55 | ||
| 56 | /* the fb that we currently hold a scanout ref to: */ | 56 | /* the fb that we currently hold a scanout ref to: */ |
| 57 | struct drm_framebuffer *fb; | 57 | struct drm_framebuffer *fb; |
| @@ -132,10 +132,10 @@ static void crtc_flush(struct drm_crtc *crtc) | |||
| 132 | mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush); | 132 | mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush); |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | static void pageflip_worker(struct work_struct *work) | 135 | static void pageflip_cb(struct msm_fence_cb *cb) |
| 136 | { | 136 | { |
| 137 | struct mdp4_crtc *mdp4_crtc = | 137 | struct mdp4_crtc *mdp4_crtc = |
| 138 | container_of(work, struct mdp4_crtc, pageflip_work); | 138 | container_of(cb, struct mdp4_crtc, pageflip_cb); |
| 139 | struct drm_crtc *crtc = &mdp4_crtc->base; | 139 | struct drm_crtc *crtc = &mdp4_crtc->base; |
| 140 | 140 | ||
| 141 | mdp4_plane_set_scanout(mdp4_crtc->plane, crtc->fb); | 141 | mdp4_plane_set_scanout(mdp4_crtc->plane, crtc->fb); |
| @@ -397,8 +397,7 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc, | |||
| 397 | mdp4_crtc->event = event; | 397 | mdp4_crtc->event = event; |
| 398 | update_fb(crtc, true, new_fb); | 398 | update_fb(crtc, true, new_fb); |
| 399 | 399 | ||
| 400 | return msm_gem_queue_inactive_work(obj, | 400 | return msm_gem_queue_inactive_cb(obj, &mdp4_crtc->pageflip_cb); |
| 401 | &mdp4_crtc->pageflip_work); | ||
| 402 | } | 401 | } |
| 403 | 402 | ||
| 404 | static int mdp4_crtc_set_property(struct drm_crtc *crtc, | 403 | static int mdp4_crtc_set_property(struct drm_crtc *crtc, |
| @@ -702,7 +701,7 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, | |||
| 702 | ret = drm_flip_work_init(&mdp4_crtc->unref_cursor_work, 64, | 701 | ret = drm_flip_work_init(&mdp4_crtc->unref_cursor_work, 64, |
| 703 | "unref cursor", unref_cursor_worker); | 702 | "unref cursor", unref_cursor_worker); |
| 704 | 703 | ||
| 705 | INIT_WORK(&mdp4_crtc->pageflip_work, pageflip_worker); | 704 | INIT_FENCE_CB(&mdp4_crtc->pageflip_cb, pageflip_cb); |
| 706 | 705 | ||
| 707 | drm_crtc_init(dev, crtc, &mdp4_crtc_funcs); | 706 | drm_crtc_init(dev, crtc, &mdp4_crtc_funcs); |
| 708 | drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs); | 707 | drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs); |
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index e7ac95a38725..86537692e45c 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c | |||
| @@ -187,6 +187,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags) | |||
| 187 | init_waitqueue_head(&priv->fence_event); | 187 | init_waitqueue_head(&priv->fence_event); |
| 188 | 188 | ||
| 189 | INIT_LIST_HEAD(&priv->inactive_list); | 189 | INIT_LIST_HEAD(&priv->inactive_list); |
| 190 | INIT_LIST_HEAD(&priv->fence_cbs); | ||
| 190 | 191 | ||
| 191 | drm_mode_config_init(dev); | 192 | drm_mode_config_init(dev); |
| 192 | 193 | ||
| @@ -539,15 +540,36 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence, | |||
| 539 | return ret; | 540 | return ret; |
| 540 | } | 541 | } |
| 541 | 542 | ||
| 542 | /* call under struct_mutex */ | 543 | /* called from workqueue */ |
| 543 | void msm_update_fence(struct drm_device *dev, uint32_t fence) | 544 | void msm_update_fence(struct drm_device *dev, uint32_t fence) |
| 544 | { | 545 | { |
| 545 | struct msm_drm_private *priv = dev->dev_private; | 546 | struct msm_drm_private *priv = dev->dev_private; |
| 546 | 547 | ||
| 547 | if (fence > priv->completed_fence) { | 548 | mutex_lock(&dev->struct_mutex); |
| 548 | priv->completed_fence = fence; | 549 | priv->completed_fence = max(fence, priv->completed_fence); |
| 549 | wake_up_all(&priv->fence_event); | 550 | |
| 551 | while (!list_empty(&priv->fence_cbs)) { | ||
| 552 | struct msm_fence_cb *cb; | ||
| 553 | |||
| 554 | cb = list_first_entry(&priv->fence_cbs, | ||
| 555 | struct msm_fence_cb, work.entry); | ||
| 556 | |||
| 557 | if (cb->fence > priv->completed_fence) | ||
| 558 | break; | ||
| 559 | |||
| 560 | list_del_init(&cb->work.entry); | ||
| 561 | queue_work(priv->wq, &cb->work); | ||
| 550 | } | 562 | } |
| 563 | |||
| 564 | mutex_unlock(&dev->struct_mutex); | ||
| 565 | |||
| 566 | wake_up_all(&priv->fence_event); | ||
| 567 | } | ||
| 568 | |||
| 569 | void __msm_fence_worker(struct work_struct *work) | ||
| 570 | { | ||
| 571 | struct msm_fence_cb *cb = container_of(work, struct msm_fence_cb, work); | ||
| 572 | cb->func(cb); | ||
| 551 | } | 573 | } |
| 552 | 574 | ||
| 553 | /* | 575 | /* |
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 2c6bad5905e8..d39f0862b19e 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h | |||
| @@ -73,6 +73,9 @@ struct msm_drm_private { | |||
| 73 | 73 | ||
| 74 | struct workqueue_struct *wq; | 74 | struct workqueue_struct *wq; |
| 75 | 75 | ||
| 76 | /* callbacks deferred until bo is inactive: */ | ||
| 77 | struct list_head fence_cbs; | ||
| 78 | |||
| 76 | /* registered IOMMU domains: */ | 79 | /* registered IOMMU domains: */ |
| 77 | unsigned int num_iommus; | 80 | unsigned int num_iommus; |
| 78 | struct iommu_domain *iommus[NUM_DOMAINS]; | 81 | struct iommu_domain *iommus[NUM_DOMAINS]; |
| @@ -97,6 +100,20 @@ struct msm_format { | |||
| 97 | uint32_t pixel_format; | 100 | uint32_t pixel_format; |
| 98 | }; | 101 | }; |
| 99 | 102 | ||
| 103 | /* callback from wq once fence has passed: */ | ||
| 104 | struct msm_fence_cb { | ||
| 105 | struct work_struct work; | ||
| 106 | uint32_t fence; | ||
| 107 | void (*func)(struct msm_fence_cb *cb); | ||
| 108 | }; | ||
| 109 | |||
| 110 | void __msm_fence_worker(struct work_struct *work); | ||
| 111 | |||
| 112 | #define INIT_FENCE_CB(_cb, _func) do { \ | ||
| 113 | INIT_WORK(&(_cb)->work, __msm_fence_worker); \ | ||
| 114 | (_cb)->func = _func; \ | ||
| 115 | } while (0) | ||
| 116 | |||
| 100 | /* As there are different display controller blocks depending on the | 117 | /* As there are different display controller blocks depending on the |
| 101 | * snapdragon version, the kms support is split out and the appropriate | 118 | * snapdragon version, the kms support is split out and the appropriate |
| 102 | * implementation is loaded at runtime. The kms module is responsible | 119 | * implementation is loaded at runtime. The kms module is responsible |
| @@ -160,8 +177,8 @@ int msm_gem_prime_pin(struct drm_gem_object *obj); | |||
| 160 | void msm_gem_prime_unpin(struct drm_gem_object *obj); | 177 | void msm_gem_prime_unpin(struct drm_gem_object *obj); |
| 161 | void *msm_gem_vaddr_locked(struct drm_gem_object *obj); | 178 | void *msm_gem_vaddr_locked(struct drm_gem_object *obj); |
| 162 | void *msm_gem_vaddr(struct drm_gem_object *obj); | 179 | void *msm_gem_vaddr(struct drm_gem_object *obj); |
| 163 | int msm_gem_queue_inactive_work(struct drm_gem_object *obj, | 180 | int msm_gem_queue_inactive_cb(struct drm_gem_object *obj, |
| 164 | struct work_struct *work); | 181 | struct msm_fence_cb *cb); |
| 165 | void msm_gem_move_to_active(struct drm_gem_object *obj, | 182 | void msm_gem_move_to_active(struct drm_gem_object *obj, |
| 166 | struct msm_gpu *gpu, bool write, uint32_t fence); | 183 | struct msm_gpu *gpu, bool write, uint32_t fence); |
| 167 | void msm_gem_move_to_inactive(struct drm_gem_object *obj); | 184 | void msm_gem_move_to_inactive(struct drm_gem_object *obj); |
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index ea2c96f9459b..291939de299e 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c | |||
| @@ -309,7 +309,17 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id, | |||
| 309 | 309 | ||
| 310 | int msm_gem_get_iova(struct drm_gem_object *obj, int id, uint32_t *iova) | 310 | int msm_gem_get_iova(struct drm_gem_object *obj, int id, uint32_t *iova) |
| 311 | { | 311 | { |
| 312 | struct msm_gem_object *msm_obj = to_msm_bo(obj); | ||
| 312 | int ret; | 313 | int ret; |
| 314 | |||
| 315 | /* this is safe right now because we don't unmap until the | ||
| 316 | * bo is deleted: | ||
| 317 | */ | ||
| 318 | if (msm_obj->domain[id].iova) { | ||
| 319 | *iova = msm_obj->domain[id].iova; | ||
| 320 | return 0; | ||
| 321 | } | ||
| 322 | |||
| 313 | mutex_lock(&obj->dev->struct_mutex); | 323 | mutex_lock(&obj->dev->struct_mutex); |
| 314 | ret = msm_gem_get_iova_locked(obj, id, iova); | 324 | ret = msm_gem_get_iova_locked(obj, id, iova); |
| 315 | mutex_unlock(&obj->dev->struct_mutex); | 325 | mutex_unlock(&obj->dev->struct_mutex); |
| @@ -379,8 +389,11 @@ void *msm_gem_vaddr(struct drm_gem_object *obj) | |||
| 379 | return ret; | 389 | return ret; |
| 380 | } | 390 | } |
| 381 | 391 | ||
| 382 | int msm_gem_queue_inactive_work(struct drm_gem_object *obj, | 392 | /* setup callback for when bo is no longer busy.. |
| 383 | struct work_struct *work) | 393 | * TODO probably want to differentiate read vs write.. |
| 394 | */ | ||
| 395 | int msm_gem_queue_inactive_cb(struct drm_gem_object *obj, | ||
| 396 | struct msm_fence_cb *cb) | ||
| 384 | { | 397 | { |
| 385 | struct drm_device *dev = obj->dev; | 398 | struct drm_device *dev = obj->dev; |
| 386 | struct msm_drm_private *priv = dev->dev_private; | 399 | struct msm_drm_private *priv = dev->dev_private; |
| @@ -388,12 +401,13 @@ int msm_gem_queue_inactive_work(struct drm_gem_object *obj, | |||
| 388 | int ret = 0; | 401 | int ret = 0; |
| 389 | 402 | ||
| 390 | mutex_lock(&dev->struct_mutex); | 403 | mutex_lock(&dev->struct_mutex); |
| 391 | if (!list_empty(&work->entry)) { | 404 | if (!list_empty(&cb->work.entry)) { |
| 392 | ret = -EINVAL; | 405 | ret = -EINVAL; |
| 393 | } else if (is_active(msm_obj)) { | 406 | } else if (is_active(msm_obj)) { |
| 394 | list_add_tail(&work->entry, &msm_obj->inactive_work); | 407 | cb->fence = max(msm_obj->read_fence, msm_obj->write_fence); |
| 408 | list_add_tail(&cb->work.entry, &priv->fence_cbs); | ||
| 395 | } else { | 409 | } else { |
| 396 | queue_work(priv->wq, work); | 410 | queue_work(priv->wq, &cb->work); |
| 397 | } | 411 | } |
| 398 | mutex_unlock(&dev->struct_mutex); | 412 | mutex_unlock(&dev->struct_mutex); |
| 399 | 413 | ||
| @@ -426,16 +440,6 @@ void msm_gem_move_to_inactive(struct drm_gem_object *obj) | |||
| 426 | msm_obj->write_fence = 0; | 440 | msm_obj->write_fence = 0; |
| 427 | list_del_init(&msm_obj->mm_list); | 441 | list_del_init(&msm_obj->mm_list); |
| 428 | list_add_tail(&msm_obj->mm_list, &priv->inactive_list); | 442 | list_add_tail(&msm_obj->mm_list, &priv->inactive_list); |
| 429 | |||
| 430 | while (!list_empty(&msm_obj->inactive_work)) { | ||
| 431 | struct work_struct *work; | ||
| 432 | |||
| 433 | work = list_first_entry(&msm_obj->inactive_work, | ||
| 434 | struct work_struct, entry); | ||
| 435 | |||
| 436 | list_del_init(&work->entry); | ||
| 437 | queue_work(priv->wq, work); | ||
| 438 | } | ||
| 439 | } | 443 | } |
| 440 | 444 | ||
| 441 | int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, | 445 | int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, |
| @@ -604,7 +608,6 @@ static int msm_gem_new_impl(struct drm_device *dev, | |||
| 604 | reservation_object_init(msm_obj->resv); | 608 | reservation_object_init(msm_obj->resv); |
| 605 | 609 | ||
| 606 | INIT_LIST_HEAD(&msm_obj->submit_entry); | 610 | INIT_LIST_HEAD(&msm_obj->submit_entry); |
| 607 | INIT_LIST_HEAD(&msm_obj->inactive_work); | ||
| 608 | list_add_tail(&msm_obj->mm_list, &priv->inactive_list); | 611 | list_add_tail(&msm_obj->mm_list, &priv->inactive_list); |
| 609 | 612 | ||
| 610 | *obj = &msm_obj->base; | 613 | *obj = &msm_obj->base; |
diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 0676f32e2c6a..f4f23a578d9d 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h | |||
| @@ -45,9 +45,6 @@ struct msm_gem_object { | |||
| 45 | */ | 45 | */ |
| 46 | struct list_head submit_entry; | 46 | struct list_head submit_entry; |
| 47 | 47 | ||
| 48 | /* work defered until bo is inactive: */ | ||
| 49 | struct list_head inactive_work; | ||
| 50 | |||
| 51 | struct page **pages; | 48 | struct page **pages; |
| 52 | struct sg_table *sgt; | 49 | struct sg_table *sgt; |
| 53 | void *vaddr; | 50 | void *vaddr; |
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 3bab937965d1..4583d61556f5 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c | |||
| @@ -268,6 +268,8 @@ static void retire_worker(struct work_struct *work) | |||
| 268 | struct drm_device *dev = gpu->dev; | 268 | struct drm_device *dev = gpu->dev; |
| 269 | uint32_t fence = gpu->funcs->last_fence(gpu); | 269 | uint32_t fence = gpu->funcs->last_fence(gpu); |
| 270 | 270 | ||
| 271 | msm_update_fence(gpu->dev, fence); | ||
| 272 | |||
| 271 | mutex_lock(&dev->struct_mutex); | 273 | mutex_lock(&dev->struct_mutex); |
| 272 | 274 | ||
| 273 | while (!list_empty(&gpu->active_list)) { | 275 | while (!list_empty(&gpu->active_list)) { |
| @@ -287,8 +289,6 @@ static void retire_worker(struct work_struct *work) | |||
| 287 | } | 289 | } |
| 288 | } | 290 | } |
| 289 | 291 | ||
| 290 | msm_update_fence(gpu->dev, fence); | ||
| 291 | |||
| 292 | mutex_unlock(&dev->struct_mutex); | 292 | mutex_unlock(&dev->struct_mutex); |
| 293 | } | 293 | } |
| 294 | 294 | ||
