From 5833bd2fe1c7d9e2650a11a8785b848bbd0d0188 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 7 Aug 2013 13:41:21 -0400 Subject: [PATCH] drm/omap: use flip-work helper And simplify how we hold a ref+pin to what is being scanned out by using fb refcnt'ing. The previous logic pre-dated fb refcnt, and as a result was less straightforward than it could have been. By holding a ref to the fb, we don't have to care about how many plane's there are and holding a ref to each color plane's bo. Signed-off-by: Rob Clark Signed-off-by: Dave Airlie --- drivers/gpu/drm/omapdrm/omap_drv.h | 5 +- drivers/gpu/drm/omapdrm/omap_fb.c | 80 +++++++++++++--------------- drivers/gpu/drm/omapdrm/omap_plane.c | 51 ++++++++---------- 3 files changed, 61 insertions(+), 75 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index f2ba425d80dd..30b95b736658 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -203,9 +203,8 @@ struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos); struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p); -int omap_framebuffer_replace(struct drm_framebuffer *a, - struct drm_framebuffer *b, void *arg, - void (*unpin)(void *arg, struct drm_gem_object *bo)); +int omap_framebuffer_pin(struct drm_framebuffer *fb); +int omap_framebuffer_unpin(struct drm_framebuffer *fb); void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, struct omap_drm_window *win, struct omap_overlay_info *info); struct drm_connector *omap_framebuffer_get_next_connector( diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index 8031402e7951..f2b8f0668c0c 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -237,58 +237,52 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, } } -/* Call for unpin 'a' (if not NULL), and pin 'b' (if not NULL). Although - * buffers to unpin are just pushed to the unpin fifo so that the - * caller can defer unpin until vblank. - * - * Note if this fails (ie. something went very wrong!), all buffers are - * unpinned, and the caller disables the overlay. We could have tried - * to revert back to the previous set of pinned buffers but if things are - * hosed there is no guarantee that would succeed. - */ -int omap_framebuffer_replace(struct drm_framebuffer *a, - struct drm_framebuffer *b, void *arg, - void (*unpin)(void *arg, struct drm_gem_object *bo)) +/* pin, prepare for scanout: */ +int omap_framebuffer_pin(struct drm_framebuffer *fb) { - int ret = 0, i, na, nb; - struct omap_framebuffer *ofba = to_omap_framebuffer(a); - struct omap_framebuffer *ofbb = to_omap_framebuffer(b); - uint32_t pinned_mask = 0; + struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); + int ret, i, n = drm_format_num_planes(fb->pixel_format); - na = a ? drm_format_num_planes(a->pixel_format) : 0; - nb = b ? drm_format_num_planes(b->pixel_format) : 0; - - for (i = 0; i < max(na, nb); i++) { - struct plane *pa, *pb; - - pa = (i < na) ? &ofba->planes[i] : NULL; - pb = (i < nb) ? &ofbb->planes[i] : NULL; - - if (pa) - unpin(arg, pa->bo); - - if (pb && !ret) { - ret = omap_gem_get_paddr(pb->bo, &pb->paddr, true); - if (!ret) { - omap_gem_dma_sync(pb->bo, DMA_TO_DEVICE); - pinned_mask |= (1 << i); - } - } + for (i = 0; i < n; i++) { + struct plane *plane = &omap_fb->planes[i]; + ret = omap_gem_get_paddr(plane->bo, &plane->paddr, true); + if (ret) + goto fail; + omap_gem_dma_sync(plane->bo, DMA_TO_DEVICE); } - if (ret) { - /* something went wrong.. unpin what has been pinned */ - for (i = 0; i < nb; i++) { - if (pinned_mask & (1 << i)) { - struct plane *pb = &ofba->planes[i]; - unpin(arg, pb->bo); - } - } + return 0; + +fail: + for (i--; i >= 0; i--) { + struct plane *plane = &omap_fb->planes[i]; + omap_gem_put_paddr(plane->bo); + plane->paddr = 0; } return ret; } +/* unpin, no longer being scanned out: */ +int omap_framebuffer_unpin(struct drm_framebuffer *fb) +{ + struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); + int ret, i, n = drm_format_num_planes(fb->pixel_format); + + for (i = 0; i < n; i++) { + struct plane *plane = &omap_fb->planes[i]; + ret = omap_gem_put_paddr(plane->bo); + if (ret) + goto fail; + plane->paddr = 0; + } + + return 0; + +fail: + return ret; +} + struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p) { struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 8d225d7ff4e3..046d5e660c04 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -17,7 +17,7 @@ * this program. If not, see . */ -#include +#include "drm_flip_work.h" #include "omap_drv.h" #include "omap_dmm_tiler.h" @@ -58,26 +58,23 @@ struct omap_plane { struct omap_drm_irq error_irq; - /* set of bo's pending unpin until next post_apply() */ - DECLARE_KFIFO_PTR(unpin_fifo, struct drm_gem_object *); + /* for deferring bo unpin's until next post_apply(): */ + struct drm_flip_work unpin_work; // XXX maybe get rid of this and handle vblank in crtc too? struct callback apply_done_cb; }; -static void unpin(void *arg, struct drm_gem_object *bo) +static void unpin_worker(struct drm_flip_work *work, void *val) { - struct drm_plane *plane = arg; - struct omap_plane *omap_plane = to_omap_plane(plane); + struct omap_plane *omap_plane = + container_of(work, struct omap_plane, unpin_work); + struct drm_device *dev = omap_plane->base.dev; - if (kfifo_put(&omap_plane->unpin_fifo, - (const struct drm_gem_object **)&bo)) { - /* also hold a ref so it isn't free'd while pinned */ - drm_gem_object_reference(bo); - } else { - dev_err(plane->dev->dev, "unpin fifo full!\n"); - omap_gem_put_paddr(bo); - } + omap_framebuffer_unpin(val); + mutex_lock(&dev->mode_config.mutex); + drm_framebuffer_unreference(val); + mutex_unlock(&dev->mode_config.mutex); } /* update which fb (if any) is pinned for scanout */ @@ -87,23 +84,22 @@ static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb) struct drm_framebuffer *pinned_fb = omap_plane->pinned_fb; if (pinned_fb != fb) { - int ret; + int ret = 0; DBG("%p -> %p", pinned_fb, fb); - if (fb) + if (fb) { drm_framebuffer_reference(fb); - - ret = omap_framebuffer_replace(pinned_fb, fb, plane, unpin); + ret = omap_framebuffer_pin(fb); + } if (pinned_fb) - drm_framebuffer_unreference(pinned_fb); + drm_flip_work_queue(&omap_plane->unpin_work, pinned_fb); if (ret) { dev_err(plane->dev->dev, "could not swap %p -> %p\n", omap_plane->pinned_fb, fb); - if (fb) - drm_framebuffer_unreference(fb); + drm_framebuffer_unreference(fb); omap_plane->pinned_fb = NULL; return ret; } @@ -170,17 +166,14 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply) struct omap_plane *omap_plane = container_of(apply, struct omap_plane, apply); struct drm_plane *plane = &omap_plane->base; + struct omap_drm_private *priv = plane->dev->dev_private; struct omap_overlay_info *info = &omap_plane->info; - struct drm_gem_object *bo = NULL; struct callback cb; cb = omap_plane->apply_done_cb; omap_plane->apply_done_cb.fxn = NULL; - while (kfifo_get(&omap_plane->unpin_fifo, &bo)) { - omap_gem_put_paddr(bo); - drm_gem_object_unreference_unlocked(bo); - } + drm_flip_work_commit(&omap_plane->unpin_work, priv->wq); if (cb.fxn) cb.fxn(cb.arg); @@ -277,8 +270,7 @@ static void omap_plane_destroy(struct drm_plane *plane) omap_plane_disable(plane); drm_plane_cleanup(plane); - WARN_ON(!kfifo_is_empty(&omap_plane->unpin_fifo)); - kfifo_free(&omap_plane->unpin_fifo); + drm_flip_work_cleanup(&omap_plane->unpin_work); kfree(omap_plane); } @@ -399,7 +391,8 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, if (!omap_plane) goto fail; - ret = kfifo_alloc(&omap_plane->unpin_fifo, 16, GFP_KERNEL); + ret = drm_flip_work_init(&omap_plane->unpin_work, 16, + "unpin", unpin_worker); if (ret) { dev_err(dev->dev, "could not allocate unpin FIFO\n"); goto fail;