aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorMandeep Singh Baines <msb@chromium.org>2015-04-01 12:02:12 -0400
committerInki Dae <inki.dae@samsung.com>2015-04-12 22:39:40 -0400
commite752747b98ae64ff0d1484a3b1b812fd2cafed53 (patch)
tree96df2f45f0ade72739061e4ad5bff6254c169311 /drivers/gpu
parent5d09a67f1c102468ec8116c10bcd79bba6563508 (diff)
drm/exynos: track vblank events on a per crtc basis
The goal of the change is to make sure we send the vblank event on the current vblank. My hope is to fix any races that might be causing flicker. After this change I only see a flicker in the transition plymouth and X11. Simplified the code by tracking vblank events on a per-crtc basis. This allowed me to remove all error paths from the callback. It also allowed me to remove the vblank wait from the callback. Signed-off-by: Mandeep Singh Baines <msb@chromium.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk> Signed-off-by: Inki Dae <inki.dae@samsung.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c92
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c13
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h6
3 files changed, 44 insertions, 67 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 47dd2b0f4aa5..eb49195cec5c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -34,9 +34,8 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
34 if (mode > DRM_MODE_DPMS_ON) { 34 if (mode > DRM_MODE_DPMS_ON) {
35 /* wait for the completion of page flip. */ 35 /* wait for the completion of page flip. */
36 if (!wait_event_timeout(exynos_crtc->pending_flip_queue, 36 if (!wait_event_timeout(exynos_crtc->pending_flip_queue,
37 !atomic_read(&exynos_crtc->pending_flip), 37 (exynos_crtc->event == NULL), HZ/20))
38 HZ/20)) 38 exynos_crtc->event = NULL;
39 atomic_set(&exynos_crtc->pending_flip, 0);
40 drm_crtc_vblank_off(crtc); 39 drm_crtc_vblank_off(crtc);
41 } 40 }
42 41
@@ -164,11 +163,10 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
164 uint32_t page_flip_flags) 163 uint32_t page_flip_flags)
165{ 164{
166 struct drm_device *dev = crtc->dev; 165 struct drm_device *dev = crtc->dev;
167 struct exynos_drm_private *dev_priv = dev->dev_private;
168 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 166 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
169 struct drm_framebuffer *old_fb = crtc->primary->fb; 167 struct drm_framebuffer *old_fb = crtc->primary->fb;
170 unsigned int crtc_w, crtc_h; 168 unsigned int crtc_w, crtc_h;
171 int ret = -EINVAL; 169 int ret;
172 170
173 /* when the page flip is requested, crtc's dpms should be on */ 171 /* when the page flip is requested, crtc's dpms should be on */
174 if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { 172 if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) {
@@ -176,48 +174,49 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
176 return -EINVAL; 174 return -EINVAL;
177 } 175 }
178 176
179 mutex_lock(&dev->struct_mutex); 177 if (!event)
178 return -EINVAL;
180 179
181 if (event) { 180 spin_lock_irq(&dev->event_lock);
182 /* 181 if (exynos_crtc->event) {
183 * the pipe from user always is 0 so we can set pipe number 182 ret = -EBUSY;
184 * of current owner to event. 183 goto out;
185 */ 184 }
186 event->pipe = exynos_crtc->pipe;
187 185
188 ret = drm_vblank_get(dev, exynos_crtc->pipe); 186 ret = drm_vblank_get(dev, exynos_crtc->pipe);
189 if (ret) { 187 if (ret) {
190 DRM_DEBUG("failed to acquire vblank counter\n"); 188 DRM_DEBUG("failed to acquire vblank counter\n");
189 goto out;
190 }
191 191
192 goto out; 192 exynos_crtc->event = event;
193 } 193 spin_unlock_irq(&dev->event_lock);
194 194
195 /*
196 * the pipe from user always is 0 so we can set pipe number
197 * of current owner to event.
198 */
199 event->pipe = exynos_crtc->pipe;
200
201 crtc->primary->fb = fb;
202 crtc_w = fb->width - crtc->x;
203 crtc_h = fb->height - crtc->y;
204 ret = exynos_update_plane(crtc->primary, crtc, fb, 0, 0,
205 crtc_w, crtc_h, crtc->x, crtc->y,
206 crtc_w, crtc_h);
207 if (ret) {
208 crtc->primary->fb = old_fb;
195 spin_lock_irq(&dev->event_lock); 209 spin_lock_irq(&dev->event_lock);
196 list_add_tail(&event->base.link, 210 exynos_crtc->event = NULL;
197 &dev_priv->pageflip_event_list); 211 drm_vblank_put(dev, exynos_crtc->pipe);
198 atomic_set(&exynos_crtc->pending_flip, 1);
199 spin_unlock_irq(&dev->event_lock); 212 spin_unlock_irq(&dev->event_lock);
200 213 return ret;
201 crtc->primary->fb = fb;
202 crtc_w = fb->width - crtc->x;
203 crtc_h = fb->height - crtc->y;
204 ret = exynos_update_plane(crtc->primary, crtc, fb, 0, 0,
205 crtc_w, crtc_h, crtc->x, crtc->y,
206 crtc_w, crtc_h);
207 if (ret) {
208 crtc->primary->fb = old_fb;
209
210 spin_lock_irq(&dev->event_lock);
211 drm_vblank_put(dev, exynos_crtc->pipe);
212 list_del(&event->base.link);
213 atomic_set(&exynos_crtc->pending_flip, 0);
214 spin_unlock_irq(&dev->event_lock);
215
216 goto out;
217 }
218 } 214 }
215
216 return 0;
217
219out: 218out:
220 mutex_unlock(&dev->struct_mutex); 219 spin_unlock_irq(&dev->event_lock);
221 return ret; 220 return ret;
222} 221}
223 222
@@ -255,7 +254,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
255 return ERR_PTR(-ENOMEM); 254 return ERR_PTR(-ENOMEM);
256 255
257 init_waitqueue_head(&exynos_crtc->pending_flip_queue); 256 init_waitqueue_head(&exynos_crtc->pending_flip_queue);
258 atomic_set(&exynos_crtc->pending_flip, 0);
259 257
260 exynos_crtc->dpms = DRM_MODE_DPMS_OFF; 258 exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
261 exynos_crtc->pipe = pipe; 259 exynos_crtc->pipe = pipe;
@@ -313,26 +311,20 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
313void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe) 311void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
314{ 312{
315 struct exynos_drm_private *dev_priv = dev->dev_private; 313 struct exynos_drm_private *dev_priv = dev->dev_private;
316 struct drm_pending_vblank_event *e, *t;
317 struct drm_crtc *drm_crtc = dev_priv->crtc[pipe]; 314 struct drm_crtc *drm_crtc = dev_priv->crtc[pipe];
318 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc); 315 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
319 unsigned long flags; 316 unsigned long flags;
320 317
321 spin_lock_irqsave(&dev->event_lock, flags); 318 spin_lock_irqsave(&dev->event_lock, flags);
319 if (exynos_crtc->event) {
322 320
323 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list, 321 drm_send_vblank_event(dev, -1, exynos_crtc->event);
324 base.link) {
325 /* if event's pipe isn't same as crtc then ignore it. */
326 if (pipe != e->pipe)
327 continue;
328
329 list_del(&e->base.link);
330 drm_send_vblank_event(dev, -1, e);
331 drm_vblank_put(dev, pipe); 322 drm_vblank_put(dev, pipe);
332 atomic_set(&exynos_crtc->pending_flip, 0);
333 wake_up(&exynos_crtc->pending_flip_queue); 323 wake_up(&exynos_crtc->pending_flip_queue);
324
334 } 325 }
335 326
327 exynos_crtc->event = NULL;
336 spin_unlock_irqrestore(&dev->event_lock, flags); 328 spin_unlock_irqrestore(&dev->event_lock, flags);
337} 329}
338 330
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index bb6e7f72f9e0..8ac465208eae 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -60,7 +60,6 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
60 if (!private) 60 if (!private)
61 return -ENOMEM; 61 return -ENOMEM;
62 62
63 INIT_LIST_HEAD(&private->pageflip_event_list);
64 dev_set_drvdata(dev->dev, dev); 63 dev_set_drvdata(dev->dev, dev);
65 dev->dev_private = (void *)private; 64 dev->dev_private = (void *)private;
66 65
@@ -223,25 +222,13 @@ static void exynos_drm_preclose(struct drm_device *dev,
223 222
224static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) 223static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
225{ 224{
226 struct exynos_drm_private *private = dev->dev_private;
227 struct drm_pending_vblank_event *v, *vt;
228 struct drm_pending_event *e, *et; 225 struct drm_pending_event *e, *et;
229 unsigned long flags; 226 unsigned long flags;
230 227
231 if (!file->driver_priv) 228 if (!file->driver_priv)
232 return; 229 return;
233 230
234 /* Release all events not unhandled by page flip handler. */
235 spin_lock_irqsave(&dev->event_lock, flags); 231 spin_lock_irqsave(&dev->event_lock, flags);
236 list_for_each_entry_safe(v, vt, &private->pageflip_event_list,
237 base.link) {
238 if (v->base.file_priv == file) {
239 list_del(&v->base.link);
240 drm_vblank_put(dev, v->pipe);
241 v->base.destroy(&v->base);
242 }
243 }
244
245 /* Release all events handled by page flip handler but not freed. */ 232 /* Release all events handled by page flip handler but not freed. */
246 list_for_each_entry_safe(e, et, &file->event_list, link) { 233 list_for_each_entry_safe(e, et, &file->event_list, link) {
247 list_del(&e->link); 234 list_del(&e->link);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 26d6de1955dc..a1013aa8a900 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -206,6 +206,7 @@ struct exynos_drm_crtc_ops {
206 * we can refer to the crtc to current hardware interrupt occurred through 206 * we can refer to the crtc to current hardware interrupt occurred through
207 * this pipe value. 207 * this pipe value.
208 * @dpms: store the crtc dpms value 208 * @dpms: store the crtc dpms value
209 * @event: vblank event that is currently queued for flip
209 * @ops: pointer to callbacks for exynos drm specific functionality 210 * @ops: pointer to callbacks for exynos drm specific functionality
210 * @ctx: A pointer to the crtc's implementation specific context 211 * @ctx: A pointer to the crtc's implementation specific context
211 */ 212 */
@@ -215,7 +216,7 @@ struct exynos_drm_crtc {
215 unsigned int pipe; 216 unsigned int pipe;
216 unsigned int dpms; 217 unsigned int dpms;
217 wait_queue_head_t pending_flip_queue; 218 wait_queue_head_t pending_flip_queue;
218 atomic_t pending_flip; 219 struct drm_pending_vblank_event *event;
219 struct exynos_drm_crtc_ops *ops; 220 struct exynos_drm_crtc_ops *ops;
220 void *ctx; 221 void *ctx;
221}; 222};
@@ -245,9 +246,6 @@ struct drm_exynos_file_private {
245struct exynos_drm_private { 246struct exynos_drm_private {
246 struct drm_fb_helper *fb_helper; 247 struct drm_fb_helper *fb_helper;
247 248
248 /* list head for new event to be added. */
249 struct list_head pageflip_event_list;
250
251 /* 249 /*
252 * created crtc object would be contained at this array and 250 * created crtc object would be contained at this array and
253 * this array is used to be aware of which crtc did it request vblank. 251 * this array is used to be aware of which crtc did it request vblank.