All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/5] drm/imx: don't touch primary fb on pageflip
@ 2016-02-09 14:10 Lucas Stach
  2016-02-09 14:10 ` [PATCH 2/5] drm/imx: track flip state explicitly Lucas Stach
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Lucas Stach @ 2016-02-09 14:10 UTC (permalink / raw)
  To: Philipp Zabel; +Cc: kernel, dri-devel

The core already does the correct replacemet if the driver
page flip function returns without an error, so there is no
need to do it here.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/gpu/drm/imx/ipuv3-crtc.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index 13a6702f9f28..a78727d9683b 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -125,7 +125,6 @@ static int ipu_page_flip(struct drm_crtc *crtc,
 
 	ipu_crtc->newfb = fb;
 	ipu_crtc->page_flip_event = event;
-	crtc->primary->fb = fb;
 
 	return 0;
 }
-- 
2.7.0.rc3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/5] drm/imx: track flip state explicitly
  2016-02-09 14:10 [PATCH 1/5] drm/imx: don't touch primary fb on pageflip Lucas Stach
@ 2016-02-09 14:10 ` Lucas Stach
  2016-02-09 14:10 ` [PATCH 3/5] drm/imx: keep GEM object referenced as long as scanout is active Lucas Stach
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Lucas Stach @ 2016-02-09 14:10 UTC (permalink / raw)
  To: Philipp Zabel; +Cc: kernel, dri-devel

Start tracking the flip state explicitly, as opposed to inferring
it from the presence if a new FB. This is a preparatory step to
introduce an new immediate state, where we can wait for a fence to
signal.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/gpu/drm/imx/ipuv3-crtc.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index a78727d9683b..55619c3de069 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -31,6 +31,11 @@
 
 #define DRIVER_DESC		"i.MX IPUv3 Graphics"
 
+enum ipu_flip_status {
+	IPU_FLIP_NONE,
+	IPU_FLIP_PENDING,
+};
+
 struct ipu_crtc {
 	struct device		*dev;
 	struct drm_crtc		base;
@@ -42,8 +47,8 @@ struct ipu_crtc {
 	struct ipu_dc		*dc;
 	struct ipu_di		*di;
 	int			enabled;
+	enum ipu_flip_status	flip_state;
 	struct drm_pending_vblank_event *page_flip_event;
-	struct drm_framebuffer	*newfb;
 	int			irq;
 	u32			bus_format;
 	int			di_hsync_pin;
@@ -112,7 +117,7 @@ static int ipu_page_flip(struct drm_crtc *crtc,
 	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
 	int ret;
 
-	if (ipu_crtc->newfb)
+	if (ipu_crtc->flip_state != IPU_FLIP_NONE)
 		return -EBUSY;
 
 	ret = imx_drm_crtc_vblank_get(ipu_crtc->imx_crtc);
@@ -123,8 +128,8 @@ static int ipu_page_flip(struct drm_crtc *crtc,
 		return ret;
 	}
 
-	ipu_crtc->newfb = fb;
 	ipu_crtc->page_flip_event = event;
+	ipu_crtc->flip_state = IPU_FLIP_PENDING;
 
 	return 0;
 }
@@ -227,13 +232,13 @@ static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
 
 	imx_drm_handle_vblank(ipu_crtc->imx_crtc);
 
-	if (ipu_crtc->newfb) {
+	if (ipu_crtc->flip_state == IPU_FLIP_PENDING) {
 		struct ipu_plane *plane = ipu_crtc->plane[0];
 
-		ipu_crtc->newfb = NULL;
 		ipu_plane_set_base(plane, ipu_crtc->base.primary->fb,
 				   plane->x, plane->y);
 		ipu_crtc_handle_pageflip(ipu_crtc);
+		ipu_crtc->flip_state = IPU_FLIP_NONE;
 	}
 
 	return IRQ_HANDLED;
-- 
2.7.0.rc3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/5] drm/imx: keep GEM object referenced as long as scanout is active
  2016-02-09 14:10 [PATCH 1/5] drm/imx: don't touch primary fb on pageflip Lucas Stach
  2016-02-09 14:10 ` [PATCH 2/5] drm/imx: track flip state explicitly Lucas Stach
@ 2016-02-09 14:10 ` Lucas Stach
  2016-02-09 14:10 ` [PATCH 4/5] drm/imx: implement fence sync Lucas Stach
  2016-02-09 14:10 ` [PATCH 5/5] drm/imx: only enable vblank IRQs when needed Lucas Stach
  3 siblings, 0 replies; 5+ messages in thread
From: Lucas Stach @ 2016-02-09 14:10 UTC (permalink / raw)
  To: Philipp Zabel; +Cc: kernel, dri-devel

The DRM core only references the currently queued/active framebuffer.
So there is a period of time where the flip is not completed, but
the GEM object backing the FB is already unreferenced and could be
destroyed if userspace closes its handle.

Make sure to keep a reference to the GEM object until the flip is
actually executed clean things up in a worker running behind the
flip execution.

Also move the page flip event into the context of this worker, so
it gets cleaned up automatically.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/gpu/drm/imx/ipuv3-crtc.c | 49 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 44 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index 55619c3de069..a07e656e9a32 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -36,6 +36,12 @@ enum ipu_flip_status {
 	IPU_FLIP_PENDING,
 };
 
+struct ipu_flip_work {
+	struct work_struct		unref_work;
+	struct drm_gem_object		*bo;
+	struct drm_pending_vblank_event *page_flip_event;
+};
+
 struct ipu_crtc {
 	struct device		*dev;
 	struct drm_crtc		base;
@@ -48,7 +54,8 @@ struct ipu_crtc {
 	struct ipu_di		*di;
 	int			enabled;
 	enum ipu_flip_status	flip_state;
-	struct drm_pending_vblank_event *page_flip_event;
+	struct workqueue_struct *flip_queue;
+	struct ipu_flip_work	*flip_work;
 	int			irq;
 	u32			bus_format;
 	int			di_hsync_pin;
@@ -109,12 +116,22 @@ static void ipu_crtc_dpms(struct drm_crtc *crtc, int mode)
 	}
 }
 
+static void ipu_flip_unref_work_func(struct work_struct *__work)
+{
+	struct ipu_flip_work *work =
+			container_of(__work, struct ipu_flip_work, unref_work);
+
+	drm_gem_object_unreference_unlocked(work->bo);
+	kfree(work);
+}
+
 static int ipu_page_flip(struct drm_crtc *crtc,
 		struct drm_framebuffer *fb,
 		struct drm_pending_vblank_event *event,
 		uint32_t page_flip_flags)
 {
 	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+	struct ipu_flip_work *flip_work;
 	int ret;
 
 	if (ipu_crtc->flip_state != IPU_FLIP_NONE)
@@ -128,10 +145,27 @@ static int ipu_page_flip(struct drm_crtc *crtc,
 		return ret;
 	}
 
-	ipu_crtc->page_flip_event = event;
+	flip_work = kzalloc(sizeof *flip_work, GFP_KERNEL);
+	if (!flip_work) {
+		ret = -ENOMEM;
+		goto put_vblank;
+	}
+	INIT_WORK(&flip_work->unref_work, ipu_flip_unref_work_func);
+	flip_work->page_flip_event = event;
+
+	/* get BO backing the old framebuffer and take a reference */
+	flip_work->bo = &drm_fb_cma_get_gem_obj(crtc->primary->fb, 0)->base;
+	drm_gem_object_reference(flip_work->bo);
+
+	ipu_crtc->flip_work = flip_work;
 	ipu_crtc->flip_state = IPU_FLIP_PENDING;
 
 	return 0;
+
+put_vblank:
+	imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc);
+
+	return ret;
 }
 
 static const struct drm_crtc_funcs ipu_crtc_funcs = {
@@ -216,12 +250,12 @@ static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
 {
 	unsigned long flags;
 	struct drm_device *drm = ipu_crtc->base.dev;
+	struct ipu_flip_work *work = ipu_crtc->flip_work;
 
 	spin_lock_irqsave(&drm->event_lock, flags);
-	if (ipu_crtc->page_flip_event)
+	if (work->page_flip_event)
 		drm_crtc_send_vblank_event(&ipu_crtc->base,
-					   ipu_crtc->page_flip_event);
-	ipu_crtc->page_flip_event = NULL;
+					   work->page_flip_event);
 	imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc);
 	spin_unlock_irqrestore(&drm->event_lock, flags);
 }
@@ -238,6 +272,8 @@ static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
 		ipu_plane_set_base(plane, ipu_crtc->base.primary->fb,
 				   plane->x, plane->y);
 		ipu_crtc_handle_pageflip(ipu_crtc);
+		queue_work(ipu_crtc->flip_queue,
+			   &ipu_crtc->flip_work->unref_work);
 		ipu_crtc->flip_state = IPU_FLIP_NONE;
 	}
 
@@ -403,6 +439,8 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 		goto err_put_plane_res;
 	}
 
+	ipu_crtc->flip_queue = create_singlethread_workqueue("ipu-crtc-flip");
+
 	return 0;
 
 err_put_plane_res:
@@ -444,6 +482,7 @@ static void ipu_drm_unbind(struct device *dev, struct device *master,
 
 	imx_drm_remove_crtc(ipu_crtc->imx_crtc);
 
+	destroy_workqueue(ipu_crtc->flip_queue);
 	ipu_plane_put_resources(ipu_crtc->plane[0]);
 	ipu_put_resources(ipu_crtc);
 }
-- 
2.7.0.rc3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 4/5] drm/imx: implement fence sync
  2016-02-09 14:10 [PATCH 1/5] drm/imx: don't touch primary fb on pageflip Lucas Stach
  2016-02-09 14:10 ` [PATCH 2/5] drm/imx: track flip state explicitly Lucas Stach
  2016-02-09 14:10 ` [PATCH 3/5] drm/imx: keep GEM object referenced as long as scanout is active Lucas Stach
@ 2016-02-09 14:10 ` Lucas Stach
  2016-02-09 14:10 ` [PATCH 5/5] drm/imx: only enable vblank IRQs when needed Lucas Stach
  3 siblings, 0 replies; 5+ messages in thread
From: Lucas Stach @ 2016-02-09 14:10 UTC (permalink / raw)
  To: Philipp Zabel; +Cc: kernel, dri-devel

If the FB is backed by a GEM object with an dma-buf attached
we need to wait for any pending fences to signal before executing
the page flip.

The implementation is straight forward by deferring the flip to
a workqueue in that case.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/gpu/drm/imx/ipuv3-crtc.c | 63 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 61 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index a07e656e9a32..30214c0e7d93 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -22,6 +22,8 @@
 #include <linux/fb.h>
 #include <linux/clk.h>
 #include <linux/errno.h>
+#include <linux/reservation.h>
+#include <linux/dma-buf.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 
@@ -34,12 +36,18 @@
 enum ipu_flip_status {
 	IPU_FLIP_NONE,
 	IPU_FLIP_PENDING,
+	IPU_FLIP_SUBMITTED,
 };
 
 struct ipu_flip_work {
 	struct work_struct		unref_work;
 	struct drm_gem_object		*bo;
 	struct drm_pending_vblank_event *page_flip_event;
+	struct work_struct		fence_work;
+	struct ipu_crtc			*crtc;
+	struct fence			*excl;
+	unsigned			shared_count;
+	struct fence			**shared;
 };
 
 struct ipu_crtc {
@@ -125,11 +133,31 @@ static void ipu_flip_unref_work_func(struct work_struct *__work)
 	kfree(work);
 }
 
+static void ipu_flip_fence_work_func(struct work_struct *__work)
+{
+	struct ipu_flip_work *work =
+			container_of(__work, struct ipu_flip_work, fence_work);
+	int i;
+
+	/* wait for all fences attached to the FB obj to signal */
+	if (work->excl) {
+		fence_wait(work->excl, false);
+		fence_put(work->excl);
+	}
+	for (i = 0; i < work->shared_count; i++) {
+		fence_wait(work->shared[i], false);
+		fence_put(work->shared[i]);
+	}
+
+	work->crtc->flip_state = IPU_FLIP_SUBMITTED;
+}
+
 static int ipu_page_flip(struct drm_crtc *crtc,
 		struct drm_framebuffer *fb,
 		struct drm_pending_vblank_event *event,
 		uint32_t page_flip_flags)
 {
+	struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
 	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
 	struct ipu_flip_work *flip_work;
 	int ret;
@@ -158,10 +186,41 @@ static int ipu_page_flip(struct drm_crtc *crtc,
 	drm_gem_object_reference(flip_work->bo);
 
 	ipu_crtc->flip_work = flip_work;
-	ipu_crtc->flip_state = IPU_FLIP_PENDING;
+	/*
+	 * If the object has a DMABUF attached, we need to wait on its fences
+	 * if there are any.
+	 */
+	if (cma_obj->base.dma_buf) {
+		INIT_WORK(&flip_work->fence_work, ipu_flip_fence_work_func);
+		flip_work->crtc = ipu_crtc;
+
+		ret = reservation_object_get_fences_rcu(
+				cma_obj->base.dma_buf->resv, &flip_work->excl,
+				&flip_work->shared_count, &flip_work->shared);
+
+		if (unlikely(ret)) {
+			DRM_ERROR("failed to get fences for buffer\n");
+			goto free_flip_work;
+		}
+
+		/* No need to queue the worker if the are no fences */
+		if (!flip_work->excl && !flip_work->shared_count) {
+			ipu_crtc->flip_state = IPU_FLIP_SUBMITTED;
+		} else {
+			ipu_crtc->flip_state = IPU_FLIP_PENDING;
+			queue_work(ipu_crtc->flip_queue,
+				   &flip_work->fence_work);
+		}
+	} else {
+		ipu_crtc->flip_state = IPU_FLIP_SUBMITTED;
+	}
 
 	return 0;
 
+free_flip_work:
+	drm_gem_object_unreference_unlocked(flip_work->bo);
+	kfree(flip_work);
+	ipu_crtc->flip_work = NULL;
 put_vblank:
 	imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc);
 
@@ -266,7 +325,7 @@ static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
 
 	imx_drm_handle_vblank(ipu_crtc->imx_crtc);
 
-	if (ipu_crtc->flip_state == IPU_FLIP_PENDING) {
+	if (ipu_crtc->flip_state == IPU_FLIP_SUBMITTED) {
 		struct ipu_plane *plane = ipu_crtc->plane[0];
 
 		ipu_plane_set_base(plane, ipu_crtc->base.primary->fb,
-- 
2.7.0.rc3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 5/5] drm/imx: only enable vblank IRQs when needed
  2016-02-09 14:10 [PATCH 1/5] drm/imx: don't touch primary fb on pageflip Lucas Stach
                   ` (2 preceding siblings ...)
  2016-02-09 14:10 ` [PATCH 4/5] drm/imx: implement fence sync Lucas Stach
@ 2016-02-09 14:10 ` Lucas Stach
  3 siblings, 0 replies; 5+ messages in thread
From: Lucas Stach @ 2016-02-09 14:10 UTC (permalink / raw)
  To: Philipp Zabel; +Cc: kernel, dri-devel

The vblank IRQ is only needed to trigger page flip work, so we
might as well disable it when there is no work to do.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/gpu/drm/imx/ipuv3-crtc.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index 30214c0e7d93..3d842715755d 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -382,11 +382,18 @@ static const struct drm_crtc_helper_funcs ipu_helper_funcs = {
 
 static int ipu_enable_vblank(struct drm_crtc *crtc)
 {
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+	enable_irq(ipu_crtc->irq);
+
 	return 0;
 }
 
 static void ipu_disable_vblank(struct drm_crtc *crtc)
 {
+	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+
+	disable_irq_nosync(ipu_crtc->irq);
 }
 
 static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc,
@@ -497,6 +504,8 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 		dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret);
 		goto err_put_plane_res;
 	}
+	/* Only enable IRQ when we actually need it to trigger work. */
+	disable_irq(ipu_crtc->irq);
 
 	ipu_crtc->flip_queue = create_singlethread_workqueue("ipu-crtc-flip");
 
-- 
2.7.0.rc3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-02-09 14:11 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-09 14:10 [PATCH 1/5] drm/imx: don't touch primary fb on pageflip Lucas Stach
2016-02-09 14:10 ` [PATCH 2/5] drm/imx: track flip state explicitly Lucas Stach
2016-02-09 14:10 ` [PATCH 3/5] drm/imx: keep GEM object referenced as long as scanout is active Lucas Stach
2016-02-09 14:10 ` [PATCH 4/5] drm/imx: implement fence sync Lucas Stach
2016-02-09 14:10 ` [PATCH 5/5] drm/imx: only enable vblank IRQs when needed Lucas Stach

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.