diff options
author | Rob Clark <robdclark@gmail.com> | 2013-10-29 12:05:20 -0400 |
---|---|---|
committer | Rob Clark <robdclark@gmail.com> | 2013-11-01 12:39:45 -0400 |
commit | 2a2b8fa628a5069db1cc984d21a3048ffd485346 (patch) | |
tree | be51f04a9f18b69288277bd2b47faf57c85cffab | |
parent | 505886d50633385f57e8e2b14fbb636cecb50297 (diff) |
drm/msm/mdp4: page_flip cleanups/fixes
There were a few potential problems with the original page_flip/vblank
code in mdp4_crtc.
1) We need vblank irq for a couple things, both completing flips and
updating cursor. We need to keep track of what work is pending so
that (for example) a cursor update while we are still waiting for
pageflip_cb (ie. pageflip requested from userspace, but still
waiting for rendering to complete) would not prematurely trigger
event to userspace.
2) A preclose -> pageflip-cancel should not cancel a pageflip that
was requested on a different file (ie. non-master closing should
not cancel a pending pageflip).
With these fixes, we no longer have problems w/ cursor not updating and
with occasional hangs with userspace waiting for a pageflip that had
been cancelled (launching XBMC from gnome-shell overview mode was a good
way to trigger this, but now works reliably).
Signed-off-by: Rob Clark <robdclark@gmail.com>
-rw-r--r-- | drivers/gpu/drm/msm/mdp4/mdp4_crtc.c | 61 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp4/mdp4_kms.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp4/mdp4_kms.h | 2 |
3 files changed, 50 insertions, 15 deletions
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c index 1d52896dfa89..019d530187ff 100644 --- a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c | |||
@@ -53,6 +53,10 @@ struct mdp4_crtc { | |||
53 | struct drm_pending_vblank_event *event; | 53 | struct drm_pending_vblank_event *event; |
54 | struct msm_fence_cb pageflip_cb; | 54 | struct msm_fence_cb pageflip_cb; |
55 | 55 | ||
56 | #define PENDING_CURSOR 0x1 | ||
57 | #define PENDING_FLIP 0x2 | ||
58 | atomic_t pending; | ||
59 | |||
56 | /* the fb that we currently hold a scanout ref to: */ | 60 | /* the fb that we currently hold a scanout ref to: */ |
57 | struct drm_framebuffer *fb; | 61 | struct drm_framebuffer *fb; |
58 | 62 | ||
@@ -93,7 +97,8 @@ static void update_fb(struct drm_crtc *crtc, bool async, | |||
93 | } | 97 | } |
94 | } | 98 | } |
95 | 99 | ||
96 | static void complete_flip(struct drm_crtc *crtc, bool canceled) | 100 | /* if file!=NULL, this is preclose potential cancel-flip path */ |
101 | static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) | ||
97 | { | 102 | { |
98 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | 103 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); |
99 | struct drm_device *dev = crtc->dev; | 104 | struct drm_device *dev = crtc->dev; |
@@ -103,11 +108,14 @@ static void complete_flip(struct drm_crtc *crtc, bool canceled) | |||
103 | spin_lock_irqsave(&dev->event_lock, flags); | 108 | spin_lock_irqsave(&dev->event_lock, flags); |
104 | event = mdp4_crtc->event; | 109 | event = mdp4_crtc->event; |
105 | if (event) { | 110 | if (event) { |
106 | mdp4_crtc->event = NULL; | 111 | /* if regular vblank case (!file) or if cancel-flip from |
107 | if (canceled) | 112 | * preclose on file that requested flip, then send the |
108 | event->base.destroy(&event->base); | 113 | * event: |
109 | else | 114 | */ |
115 | if (!file || (event->base.file_priv == file)) { | ||
116 | mdp4_crtc->event = NULL; | ||
110 | drm_send_vblank_event(dev, mdp4_crtc->id, event); | 117 | drm_send_vblank_event(dev, mdp4_crtc->id, event); |
118 | } | ||
111 | } | 119 | } |
112 | spin_unlock_irqrestore(&dev->event_lock, flags); | 120 | spin_unlock_irqrestore(&dev->event_lock, flags); |
113 | } | 121 | } |
@@ -132,17 +140,29 @@ static void crtc_flush(struct drm_crtc *crtc) | |||
132 | mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush); | 140 | mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush); |
133 | } | 141 | } |
134 | 142 | ||
143 | static void request_pending(struct drm_crtc *crtc, uint32_t pending) | ||
144 | { | ||
145 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | ||
146 | |||
147 | atomic_or(pending, &mdp4_crtc->pending); | ||
148 | mdp4_irq_register(get_kms(crtc), &mdp4_crtc->vblank); | ||
149 | } | ||
150 | |||
135 | static void pageflip_cb(struct msm_fence_cb *cb) | 151 | static void pageflip_cb(struct msm_fence_cb *cb) |
136 | { | 152 | { |
137 | struct mdp4_crtc *mdp4_crtc = | 153 | struct mdp4_crtc *mdp4_crtc = |
138 | container_of(cb, struct mdp4_crtc, pageflip_cb); | 154 | container_of(cb, struct mdp4_crtc, pageflip_cb); |
139 | struct drm_crtc *crtc = &mdp4_crtc->base; | 155 | struct drm_crtc *crtc = &mdp4_crtc->base; |
156 | struct drm_framebuffer *fb = crtc->fb; | ||
157 | |||
158 | if (!fb) | ||
159 | return; | ||
140 | 160 | ||
141 | mdp4_plane_set_scanout(mdp4_crtc->plane, crtc->fb); | 161 | mdp4_plane_set_scanout(mdp4_crtc->plane, fb); |
142 | crtc_flush(crtc); | 162 | crtc_flush(crtc); |
143 | 163 | ||
144 | /* enable vblank to complete flip: */ | 164 | /* enable vblank to complete flip: */ |
145 | mdp4_irq_register(get_kms(crtc), &mdp4_crtc->vblank); | 165 | request_pending(crtc, PENDING_FLIP); |
146 | } | 166 | } |
147 | 167 | ||
148 | static void unref_fb_worker(struct drm_flip_work *work, void *val) | 168 | static void unref_fb_worker(struct drm_flip_work *work, void *val) |
@@ -386,6 +406,7 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc, | |||
386 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | 406 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); |
387 | struct drm_device *dev = crtc->dev; | 407 | struct drm_device *dev = crtc->dev; |
388 | struct drm_gem_object *obj; | 408 | struct drm_gem_object *obj; |
409 | unsigned long flags; | ||
389 | 410 | ||
390 | if (mdp4_crtc->event) { | 411 | if (mdp4_crtc->event) { |
391 | dev_err(dev->dev, "already pending flip!\n"); | 412 | dev_err(dev->dev, "already pending flip!\n"); |
@@ -394,7 +415,10 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc, | |||
394 | 415 | ||
395 | obj = msm_framebuffer_bo(new_fb, 0); | 416 | obj = msm_framebuffer_bo(new_fb, 0); |
396 | 417 | ||
418 | spin_lock_irqsave(&dev->event_lock, flags); | ||
397 | mdp4_crtc->event = event; | 419 | mdp4_crtc->event = event; |
420 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
421 | |||
398 | update_fb(crtc, true, new_fb); | 422 | update_fb(crtc, true, new_fb); |
399 | 423 | ||
400 | return msm_gem_queue_inactive_cb(obj, &mdp4_crtc->pageflip_cb); | 424 | return msm_gem_queue_inactive_cb(obj, &mdp4_crtc->pageflip_cb); |
@@ -506,6 +530,8 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc, | |||
506 | drm_gem_object_unreference_unlocked(old_bo); | 530 | drm_gem_object_unreference_unlocked(old_bo); |
507 | } | 531 | } |
508 | 532 | ||
533 | request_pending(crtc, PENDING_CURSOR); | ||
534 | |||
509 | return 0; | 535 | return 0; |
510 | 536 | ||
511 | fail: | 537 | fail: |
@@ -550,13 +576,21 @@ static void mdp4_crtc_vblank_irq(struct mdp4_irq *irq, uint32_t irqstatus) | |||
550 | struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, vblank); | 576 | struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, vblank); |
551 | struct drm_crtc *crtc = &mdp4_crtc->base; | 577 | struct drm_crtc *crtc = &mdp4_crtc->base; |
552 | struct msm_drm_private *priv = crtc->dev->dev_private; | 578 | struct msm_drm_private *priv = crtc->dev->dev_private; |
579 | unsigned pending; | ||
553 | 580 | ||
554 | update_cursor(crtc); | ||
555 | complete_flip(crtc, false); | ||
556 | mdp4_irq_unregister(get_kms(crtc), &mdp4_crtc->vblank); | 581 | mdp4_irq_unregister(get_kms(crtc), &mdp4_crtc->vblank); |
557 | 582 | ||
558 | drm_flip_work_commit(&mdp4_crtc->unref_fb_work, priv->wq); | 583 | pending = atomic_xchg(&mdp4_crtc->pending, 0); |
559 | drm_flip_work_commit(&mdp4_crtc->unref_cursor_work, priv->wq); | 584 | |
585 | if (pending & PENDING_FLIP) { | ||
586 | complete_flip(crtc, NULL); | ||
587 | drm_flip_work_commit(&mdp4_crtc->unref_fb_work, priv->wq); | ||
588 | } | ||
589 | |||
590 | if (pending & PENDING_CURSOR) { | ||
591 | update_cursor(crtc); | ||
592 | drm_flip_work_commit(&mdp4_crtc->unref_cursor_work, priv->wq); | ||
593 | } | ||
560 | } | 594 | } |
561 | 595 | ||
562 | static void mdp4_crtc_err_irq(struct mdp4_irq *irq, uint32_t irqstatus) | 596 | static void mdp4_crtc_err_irq(struct mdp4_irq *irq, uint32_t irqstatus) |
@@ -573,9 +607,10 @@ uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc) | |||
573 | return mdp4_crtc->vblank.irqmask; | 607 | return mdp4_crtc->vblank.irqmask; |
574 | } | 608 | } |
575 | 609 | ||
576 | void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc) | 610 | void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file) |
577 | { | 611 | { |
578 | complete_flip(crtc, true); | 612 | DBG("cancel: %p", file); |
613 | complete_flip(crtc, file); | ||
579 | } | 614 | } |
580 | 615 | ||
581 | /* set dma config, ie. the format the encoder wants. */ | 616 | /* set dma config, ie. the format the encoder wants. */ |
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp4/mdp4_kms.c index c2485a71faa8..8972ac35a43d 100644 --- a/drivers/gpu/drm/msm/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp4/mdp4_kms.c | |||
@@ -135,7 +135,7 @@ static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file) | |||
135 | unsigned i; | 135 | unsigned i; |
136 | 136 | ||
137 | for (i = 0; i < priv->num_crtcs; i++) | 137 | for (i = 0; i < priv->num_crtcs; i++) |
138 | mdp4_crtc_cancel_pending_flip(priv->crtcs[i]); | 138 | mdp4_crtc_cancel_pending_flip(priv->crtcs[i], file); |
139 | } | 139 | } |
140 | 140 | ||
141 | static void mdp4_destroy(struct msm_kms *kms) | 141 | static void mdp4_destroy(struct msm_kms *kms) |
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp4/mdp4_kms.h index 11c34387aeb6..eb015c834087 100644 --- a/drivers/gpu/drm/msm/mdp4/mdp4_kms.h +++ b/drivers/gpu/drm/msm/mdp4/mdp4_kms.h | |||
@@ -207,7 +207,7 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev, | |||
207 | enum mdp4_pipe pipe_id, bool private_plane); | 207 | enum mdp4_pipe pipe_id, bool private_plane); |
208 | 208 | ||
209 | uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc); | 209 | uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc); |
210 | void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc); | 210 | void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file); |
211 | void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config); | 211 | void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config); |
212 | void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf); | 212 | void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf); |
213 | void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane); | 213 | void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane); |