aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Clark <robdclark@gmail.com>2013-09-14 14:01:55 -0400
committerRob Clark <robdclark@gmail.com>2013-11-01 12:39:45 -0400
commitedd4fc63a33eeeb922503b14e8040a3b028c76a5 (patch)
tree6916bd23f5af0045c7fad9e0fb73eff5990e02aa
parenta862391871004bf8dea2299bb712aa93a512334a (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>
-rw-r--r--drivers/gpu/drm/msm/mdp4/mdp4_crtc.c11
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c30
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h21
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c35
-rw-r--r--drivers/gpu/drm/msm/msm_gem.h3
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.c4
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
135static void pageflip_worker(struct work_struct *work) 135static 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
404static int mdp4_crtc_set_property(struct drm_crtc *crtc, 403static 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 */
543void msm_update_fence(struct drm_device *dev, uint32_t fence) 544void 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
569void __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: */
104struct msm_fence_cb {
105 struct work_struct work;
106 uint32_t fence;
107 void (*func)(struct msm_fence_cb *cb);
108};
109
110void __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);
160void msm_gem_prime_unpin(struct drm_gem_object *obj); 177void msm_gem_prime_unpin(struct drm_gem_object *obj);
161void *msm_gem_vaddr_locked(struct drm_gem_object *obj); 178void *msm_gem_vaddr_locked(struct drm_gem_object *obj);
162void *msm_gem_vaddr(struct drm_gem_object *obj); 179void *msm_gem_vaddr(struct drm_gem_object *obj);
163int msm_gem_queue_inactive_work(struct drm_gem_object *obj, 180int msm_gem_queue_inactive_cb(struct drm_gem_object *obj,
164 struct work_struct *work); 181 struct msm_fence_cb *cb);
165void msm_gem_move_to_active(struct drm_gem_object *obj, 182void 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);
167void msm_gem_move_to_inactive(struct drm_gem_object *obj); 184void 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
310int msm_gem_get_iova(struct drm_gem_object *obj, int id, uint32_t *iova) 310int 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
382int 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 */
395int 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
441int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, 445int 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