On Tue, May 24, 2016 at 7:11 PM, Daniel Vetter <daniel@xxxxxxxx> wrote: > On Tue, May 24, 2016 at 06:10:52PM +0800, Liu Ying wrote: >> To support generic atomic page flip, this patch customizes ->atomic_commit >> for async commits. > > It's now called nonblocking instead of async. Please run s/async/nonblock/ > over this patch. Ok. Will do. Regards, Liu Ying > -Daniel > >> >> Signed-off-by: Liu Ying <gnuiyl@xxxxxxxxx> >> --- >> drivers/gpu/drm/imx/imx-drm-core.c | 137 +++++++++++++++++++++++++++++++- >> drivers/gpu/drm/imx/ipuv3-crtc.c | 156 ++----------------------------------- >> 2 files changed, 144 insertions(+), 149 deletions(-) >> >> diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c >> index 2fa04a0..cb521cb 100644 >> --- a/drivers/gpu/drm/imx/imx-drm-core.c >> +++ b/drivers/gpu/drm/imx/imx-drm-core.c >> @@ -15,10 +15,14 @@ >> */ >> #include <linux/component.h> >> #include <linux/device.h> >> +#include <linux/dma-buf.h> >> #include <linux/fb.h> >> #include <linux/module.h> >> #include <linux/platform_device.h> >> +#include <linux/reservation.h> >> +#include <linux/wait.h> >> #include <drm/drmP.h> >> +#include <drm/drm_atomic.h> >> #include <drm/drm_atomic_helper.h> >> #include <drm/drm_fb_helper.h> >> #include <drm/drm_crtc_helper.h> >> @@ -48,6 +52,14 @@ struct imx_drm_device { >> struct imx_drm_crtc { >> struct drm_crtc *crtc; >> struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs; >> + wait_queue_head_t commit_wait; >> + bool commit_pending; >> +}; >> + >> +struct imx_drm_commit { >> + struct work_struct work; >> + struct drm_device *dev; >> + struct drm_atomic_state *state; >> }; >> >> #if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) >> @@ -168,11 +180,132 @@ static void imx_drm_output_poll_changed(struct drm_device *drm) >> drm_fbdev_cma_hotplug_event(imxdrm->fbhelper); >> } >> >> +static void imx_drm_atomic_complete(struct imx_drm_commit *commit, bool async) >> +{ >> + struct drm_device *dev = commit->dev; >> + struct imx_drm_device *imxdrm = dev->dev_private; >> + struct imx_drm_crtc *imx_crtc; >> + struct drm_atomic_state *old_state = commit->state; >> + struct drm_crtc *crtc; >> + struct drm_crtc_state *old_crtc_state; >> + struct drm_plane_state *plane_state; >> + struct drm_gem_cma_object *cma_obj; >> + struct fence *excl; >> + unsigned shared_count; >> + struct fence **shared; >> + unsigned int i, j; >> + int ret; >> + >> + /* Wait for fences. */ >> + for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { >> + if (crtc->state->event) { >> + plane_state = crtc->primary->state; >> + cma_obj = drm_fb_cma_get_gem_obj(plane_state->fb, 0); >> + if (cma_obj->base.dma_buf) { >> + ret = reservation_object_get_fences_rcu( >> + cma_obj->base.dma_buf->resv, &excl, >> + &shared_count, &shared); >> + if (unlikely(ret)) >> + DRM_ERROR("failed to get fences " >> + "for buffer\n"); >> + >> + if (excl) { >> + fence_wait(excl, false); >> + fence_put(excl); >> + } >> + for (j = 0; j < shared_count; i++) { >> + fence_wait(shared[j], false); >> + fence_put(shared[j]); >> + } >> + } >> + } >> + } >> + >> + /* Apply the atomic update. */ >> + drm_atomic_helper_commit_modeset_disables(dev, old_state); >> + drm_atomic_helper_commit_modeset_enables(dev, old_state); >> + drm_atomic_helper_commit_planes(dev, old_state, false); >> + drm_atomic_helper_wait_for_vblanks(dev, old_state); >> + drm_atomic_helper_cleanup_planes(dev, old_state); >> + >> + if (async) >> + for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { >> + imx_crtc = imxdrm->crtc[i]; >> + >> + /* Complete the commit, wake up any waiter. */ >> + spin_lock(&imx_crtc->commit_wait.lock); >> + imx_crtc->commit_pending = false; >> + wake_up_all_locked(&imx_crtc->commit_wait); >> + spin_unlock(&imx_crtc->commit_wait.lock); >> + } >> + >> + drm_atomic_state_free(old_state); >> + >> + kfree(commit); >> +} >> + >> +static void imx_drm_atomic_work(struct work_struct *work) >> +{ >> + struct imx_drm_commit *commit = >> + container_of(work, struct imx_drm_commit, work); >> + >> + imx_drm_atomic_complete(commit, true); >> +} >> + >> +static int imx_drm_atomic_commit(struct drm_device *dev, >> + struct drm_atomic_state *state, bool async) >> +{ >> + struct imx_drm_device *imxdrm = dev->dev_private; >> + struct imx_drm_crtc *imx_crtc; >> + struct imx_drm_commit *commit; >> + struct drm_crtc *crtc; >> + struct drm_crtc_state *crtc_state; >> + unsigned int i; >> + int ret; >> + >> + commit = kzalloc(sizeof(*commit), GFP_KERNEL); >> + if (commit == NULL) >> + return -ENOMEM; >> + >> + commit->dev = dev; >> + commit->state = state; >> + >> + if (async) { >> + for_each_crtc_in_state(state, crtc, crtc_state, i) { >> + imx_crtc = imxdrm->crtc[i]; >> + >> + spin_lock(&imx_crtc->commit_wait.lock); >> + ret = wait_event_interruptible_locked( >> + imx_crtc->commit_wait, >> + !imx_crtc->commit_pending); >> + if (ret == 0) >> + imx_crtc->commit_pending = true; >> + spin_unlock(&imx_crtc->commit_wait.lock); >> + >> + if (ret) { >> + kfree(commit); >> + return ret; >> + } >> + } >> + >> + INIT_WORK(&commit->work, imx_drm_atomic_work); >> + } >> + >> + drm_atomic_helper_swap_state(dev, state); >> + >> + if (async) >> + schedule_work(&commit->work); >> + else >> + imx_drm_atomic_complete(commit, async); >> + >> + return 0; >> +} >> + >> static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = { >> .fb_create = drm_fb_cma_create, >> .output_poll_changed = imx_drm_output_poll_changed, >> .atomic_check = drm_atomic_helper_check, >> - .atomic_commit = drm_atomic_helper_commit, >> + .atomic_commit = imx_drm_atomic_commit, >> }; >> >> /* >> @@ -315,6 +448,8 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, >> imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs; >> imx_drm_crtc->crtc = crtc; >> >> + init_waitqueue_head(&imx_drm_crtc->commit_wait); >> + >> crtc->port = port; >> >> imxdrm->crtc[imxdrm->pipes++] = imx_drm_crtc; >> diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c >> index 4d1b911..dcbeb56 100644 >> --- a/drivers/gpu/drm/imx/ipuv3-crtc.c >> +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c >> @@ -24,8 +24,6 @@ >> #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> >> >> @@ -35,23 +33,6 @@ >> >> #define DRIVER_DESC "i.MX IPUv3 Graphics" >> >> -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 { >> struct device *dev; >> struct drm_crtc base; >> @@ -62,9 +43,6 @@ struct ipu_crtc { >> >> struct ipu_dc *dc; >> struct ipu_di *di; >> - enum ipu_flip_status flip_state; >> - struct workqueue_struct *flip_queue; >> - struct ipu_flip_work *flip_work; >> int irq; >> }; >> >> @@ -94,150 +72,35 @@ static void ipu_crtc_disable(struct drm_crtc *crtc) >> drm_crtc_vblank_off(&ipu_crtc->base); >> } >> >> -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 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; >> - >> - if (ipu_crtc->flip_state != IPU_FLIP_NONE) >> - return -EBUSY; >> - >> - ret = imx_drm_crtc_vblank_get(ipu_crtc->imx_crtc); >> - if (ret) { >> - dev_dbg(ipu_crtc->dev, "failed to acquire vblank counter\n"); >> - list_del(&event->base.link); >> - >> - return ret; >> - } >> - >> - 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; >> - /* >> - * 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; >> - } >> - >> - if (crtc->primary->state) >> - drm_atomic_set_fb_for_plane(crtc->primary->state, fb); >> - >> - 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); >> - >> - return ret; >> -} >> - >> static const struct drm_crtc_funcs ipu_crtc_funcs = { >> .set_config = drm_atomic_helper_set_config, >> .destroy = drm_crtc_cleanup, >> - .page_flip = ipu_page_flip, >> + .page_flip = drm_atomic_helper_page_flip, >> .reset = drm_atomic_helper_crtc_reset, >> .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, >> .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, >> }; >> >> -static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc) >> +static void ipu_crtc_handle_pageflip(struct drm_crtc *crtc) >> { >> + struct drm_device *drm = crtc->dev; >> 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 (work->page_flip_event) >> - drm_crtc_send_vblank_event(&ipu_crtc->base, >> - work->page_flip_event); >> - imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc); >> + drm_crtc_send_vblank_event(crtc, crtc->state->event); >> + crtc->state->event = NULL; >> spin_unlock_irqrestore(&drm->event_lock, flags); >> } >> >> static irqreturn_t ipu_irq_handler(int irq, void *dev_id) >> { >> struct ipu_crtc *ipu_crtc = dev_id; >> + struct drm_crtc *crtc = &ipu_crtc->base; >> >> imx_drm_handle_vblank(ipu_crtc->imx_crtc); >> >> - 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); >> - 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; >> - } >> + if (crtc->state->event) >> + ipu_crtc_handle_pageflip(crtc); >> >> return IRQ_HANDLED; >> } >> @@ -452,8 +315,6 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, >> >> ipu_plane_put_resources(ipu_crtc->plane[0]); >> >> - ipu_crtc->flip_queue = create_singlethread_workqueue("ipu-crtc-flip"); >> - >> return 0; >> >> err_put_plane_res: >> @@ -495,7 +356,6 @@ 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_put_resources(ipu_crtc); >> } >> >> -- >> 2.7.4 >> >> _______________________________________________ >> dri-devel mailing list >> dri-devel@xxxxxxxxxxxxxxxxxxxxx >> https://lists.freedesktop.org/mailman/listinfo/dri-devel > > -- > Daniel Vetter > Software Engineer, Intel Corporation > http://blog.ffwll.ch _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel