From: Daniel Vetter <daniel@ffwll.ch>
To: "Noralf Trønnes" <noralf@tronnes.org>
Cc: linux-fbdev@vger.kernel.org, linux-kernel@vger.kernel.org,
dri-devel@lists.freedesktop.org, tomi.valkeinen@ti.com,
laurent.pinchart@ideasonboard.com
Subject: Re: [PATCH v3 3/7] drm/fb-helper: Add fb_deferred_io support
Date: Wed, 27 Apr 2016 19:20:52 +0000 [thread overview]
Message-ID: <20160427192052.GG2558@phenom.ffwll.local> (raw)
In-Reply-To: <1461780996-8612-4-git-send-email-noralf@tronnes.org>
On Wed, Apr 27, 2016 at 08:16:32PM +0200, Noralf Trønnes wrote:
> This adds deferred io support to drm_fb_helper.
> The fbdev framebuffer changes are flushed using the callback
> (struct drm_framebuffer *)->funcs->dirty() by a dedicated worker
> ensuring that it always runs in process context.
>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>
> Changes since v2:
> - FB_DEFERRED_IO is now always selected by DRM_KMS_FB_HELPER, ifdef removed
> - The drm_clip_rect utility functions are dropped, so open code it
> - docs: use & to denote structs
>
> Changes since v1:
> - Use a dedicated worker to run the framebuffer flushing like qxl does
> - Add parameter descriptions to drm_fb_helper_deferred_io
>
> drivers/gpu/drm/Kconfig | 1 +
> drivers/gpu/drm/drm_fb_helper.c | 109 +++++++++++++++++++++++++++++++++++++++-
> include/drm/drm_fb_helper.h | 15 ++++++
> 3 files changed, 124 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 9e4f2f1..8e6f34b 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -52,6 +52,7 @@ config DRM_KMS_FB_HELPER
> select FB_CFB_FILLRECT
> select FB_CFB_COPYAREA
> select FB_CFB_IMAGEBLIT
> + select FB_DEFERRED_IO
> help
> FBDEV helpers for KMS drivers.
>
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 855108e..5112b5d 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -48,6 +48,8 @@ MODULE_PARM_DESC(fbdev_emulation,
>
> static LIST_HEAD(kernel_fb_helper_list);
>
> +static void drm_fb_helper_dirty_init(struct drm_fb_helper *helper);
Instead of this forward decl just inline the few setup commands into
drm_fb_helper_prepare.
> +
> /**
> * DOC: fbdev helpers
> *
> @@ -84,6 +86,15 @@ static LIST_HEAD(kernel_fb_helper_list);
> * and set up an initial configuration using the detected hardware, drivers
> * should call drm_fb_helper_single_add_all_connectors() followed by
> * drm_fb_helper_initial_config().
> + *
> + * If CONFIG_FB_DEFERRED_IO is enabled and &drm_framebuffer_funcs ->dirty is
> + * set, the drm_fb_helper_{cfb,sys}_{write,fillrect,copyarea,imageblit}
> + * functions will accumulate changes and schedule &fb_helper .dirty_work to run
> + * right away. This worker then calls the dirty() function ensuring that it
> + * will always run in process context since the fb_*() function could be
> + * running in atomic context. If drm_fb_helper_deferred_io() is used as the
> + * deferred_io callback it will also schedule dirty_work with the damage
> + * collected from the mmap page writes.
> */
>
> /**
> @@ -650,6 +661,7 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
> const struct drm_fb_helper_funcs *funcs)
> {
> INIT_LIST_HEAD(&helper->kernel_fb_list);
> + drm_fb_helper_dirty_init(helper);
> helper->funcs = funcs;
> helper->dev = dev;
> }
> @@ -834,6 +846,82 @@ void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
> }
> EXPORT_SYMBOL(drm_fb_helper_unlink_fbi);
>
> +static void drm_fb_helper_dirty_work(struct work_struct *work)
> +{
> + struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
> + dirty_work);
> + struct drm_clip_rect *clip = &helper->dirty_clip;
> + struct drm_clip_rect clip_copy;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&helper->dirty_lock, flags);
> + clip_copy = *clip;
> + clip->x1 = clip->y1 = ~0;
> + clip->x2 = clip->y2 = 0;
> + spin_unlock_irqrestore(&helper->dirty_lock, flags);
> +
> + helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip_copy, 1);
> +}
> +
> +static void drm_fb_helper_dirty_init(struct drm_fb_helper *helper)
> +{
> + spin_lock_init(&helper->dirty_lock);
> + INIT_WORK(&helper->dirty_work, drm_fb_helper_dirty_work);
> + helper->dirty_clip.x1 = helper->dirty_clip.y1 = ~0;
> +}
> +
> +static void drm_fb_helper_dirty(struct fb_info *info, u32 x, u32 y,
> + u32 width, u32 height)
> +{
> + struct drm_fb_helper *helper = info->par;
> + struct drm_clip_rect *clip = &helper->dirty_clip;
> + unsigned long flags;
> +
> + if (!helper->fb->funcs->dirty)
> + return;
> +
> + spin_lock_irqsave(&helper->dirty_lock, flags);
> + clip->x1 = min_t(u32, clip->x1, x);
> + clip->y1 = min_t(u32, clip->y1, y);
> + clip->x2 = max_t(u32, clip->x2, x + width);
> + clip->y2 = max_t(u32, clip->y2, y + height);
> + spin_unlock_irqrestore(&helper->dirty_lock, flags);
> +
> + schedule_work(&helper->dirty_work);
> +}
> +
> +/**
> + * drm_fb_helper_deferred_io() - fbdev deferred_io callback function
> + * @info: fb_info struct pointer
> + * @pagelist: list of dirty mmap framebuffer pages
> + *
> + * This function is used as the &fb_deferred_io ->deferred_io
> + * callback function for flushing the fbdev mmap writes.
> + */
> +void drm_fb_helper_deferred_io(struct fb_info *info,
> + struct list_head *pagelist)
> +{
> + unsigned long start, end, min, max;
> + struct page *page;
> + u32 y1, y2;
> +
> + min = ULONG_MAX;
> + max = 0;
> + list_for_each_entry(page, pagelist, lru) {
> + start = page->index << PAGE_SHIFT;
> + end = start + PAGE_SIZE - 1;
> + min = min(min, start);
> + max = max(max, end);
> + }
> +
> + if (min < max) {
> + y1 = min / info->fix.line_length;
> + y2 = min_t(u32, max / info->fix.line_length, info->var.yres);
Needs a DIV_ROUND_UP here I think.
Besides these two nits nothing else I've spotted.
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> + drm_fb_helper_dirty(info, 0, y1, info->var.xres, y2 - y1);
> + }
> +}
> +EXPORT_SYMBOL(drm_fb_helper_deferred_io);
> +
> /**
> * drm_fb_helper_sys_read - wrapper around fb_sys_read
> * @info: fb_info struct pointer
> @@ -862,7 +950,14 @@ EXPORT_SYMBOL(drm_fb_helper_sys_read);
> ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
> size_t count, loff_t *ppos)
> {
> - return fb_sys_write(info, buf, count, ppos);
> + ssize_t ret;
> +
> + ret = fb_sys_write(info, buf, count, ppos);
> + if (ret > 0)
> + drm_fb_helper_dirty(info, 0, 0, info->var.xres,
> + info->var.yres);
> +
> + return ret;
> }
> EXPORT_SYMBOL(drm_fb_helper_sys_write);
>
> @@ -877,6 +972,8 @@ void drm_fb_helper_sys_fillrect(struct fb_info *info,
> const struct fb_fillrect *rect)
> {
> sys_fillrect(info, rect);
> + drm_fb_helper_dirty(info, rect->dx, rect->dy,
> + rect->width, rect->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_sys_fillrect);
>
> @@ -891,6 +988,8 @@ void drm_fb_helper_sys_copyarea(struct fb_info *info,
> const struct fb_copyarea *area)
> {
> sys_copyarea(info, area);
> + drm_fb_helper_dirty(info, area->dx, area->dy,
> + area->width, area->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_sys_copyarea);
>
> @@ -905,6 +1004,8 @@ void drm_fb_helper_sys_imageblit(struct fb_info *info,
> const struct fb_image *image)
> {
> sys_imageblit(info, image);
> + drm_fb_helper_dirty(info, image->dx, image->dy,
> + image->width, image->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_sys_imageblit);
>
> @@ -919,6 +1020,8 @@ void drm_fb_helper_cfb_fillrect(struct fb_info *info,
> const struct fb_fillrect *rect)
> {
> cfb_fillrect(info, rect);
> + drm_fb_helper_dirty(info, rect->dx, rect->dy,
> + rect->width, rect->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_cfb_fillrect);
>
> @@ -933,6 +1036,8 @@ void drm_fb_helper_cfb_copyarea(struct fb_info *info,
> const struct fb_copyarea *area)
> {
> cfb_copyarea(info, area);
> + drm_fb_helper_dirty(info, area->dx, area->dy,
> + area->width, area->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_cfb_copyarea);
>
> @@ -947,6 +1052,8 @@ void drm_fb_helper_cfb_imageblit(struct fb_info *info,
> const struct fb_image *image)
> {
> cfb_imageblit(info, image);
> + drm_fb_helper_dirty(info, image->dx, image->dy,
> + image->width, image->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit);
>
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index 062723b..5b4aa35 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -172,6 +172,10 @@ struct drm_fb_helper_connector {
> * @funcs: driver callbacks for fb helper
> * @fbdev: emulated fbdev device info struct
> * @pseudo_palette: fake palette of 16 colors
> + * @dirty_clip: clip rectangle used with deferred_io to accumulate damage to
> + * the screen buffer
> + * @dirty_lock: spinlock protecting @dirty_clip
> + * @dirty_work: worker used to flush the framebuffer
> *
> * This is the main structure used by the fbdev helpers. Drivers supporting
> * fbdev emulation should embedded this into their overall driver structure.
> @@ -189,6 +193,9 @@ struct drm_fb_helper {
> const struct drm_fb_helper_funcs *funcs;
> struct fb_info *fbdev;
> u32 pseudo_palette[17];
> + struct drm_clip_rect dirty_clip;
> + spinlock_t dirty_lock;
> + struct work_struct dirty_work;
>
> /**
> * @kernel_fb_list:
> @@ -245,6 +252,9 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
>
> void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper);
>
> +void drm_fb_helper_deferred_io(struct fb_info *info,
> + struct list_head *pagelist);
> +
> ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
> size_t count, loff_t *ppos);
> ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
> @@ -368,6 +378,11 @@ static inline void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
> {
> }
>
> +static inline void drm_fb_helper_deferred_io(struct fb_info *info,
> + struct list_head *pagelist)
> +{
> +}
> +
> static inline ssize_t drm_fb_helper_sys_read(struct fb_info *info,
> char __user *buf, size_t count,
> loff_t *ppos)
> --
> 2.2.2
>
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
WARNING: multiple messages have this Message-ID (diff)
From: Daniel Vetter <daniel@ffwll.ch>
To: "Noralf Trønnes" <noralf@tronnes.org>
Cc: linux-fbdev@vger.kernel.org, linux-kernel@vger.kernel.org,
dri-devel@lists.freedesktop.org, tomi.valkeinen@ti.com,
laurent.pinchart@ideasonboard.com
Subject: Re: [PATCH v3 3/7] drm/fb-helper: Add fb_deferred_io support
Date: Wed, 27 Apr 2016 21:20:52 +0200 [thread overview]
Message-ID: <20160427192052.GG2558@phenom.ffwll.local> (raw)
In-Reply-To: <1461780996-8612-4-git-send-email-noralf@tronnes.org>
On Wed, Apr 27, 2016 at 08:16:32PM +0200, Noralf Trønnes wrote:
> This adds deferred io support to drm_fb_helper.
> The fbdev framebuffer changes are flushed using the callback
> (struct drm_framebuffer *)->funcs->dirty() by a dedicated worker
> ensuring that it always runs in process context.
>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>
> Changes since v2:
> - FB_DEFERRED_IO is now always selected by DRM_KMS_FB_HELPER, ifdef removed
> - The drm_clip_rect utility functions are dropped, so open code it
> - docs: use & to denote structs
>
> Changes since v1:
> - Use a dedicated worker to run the framebuffer flushing like qxl does
> - Add parameter descriptions to drm_fb_helper_deferred_io
>
> drivers/gpu/drm/Kconfig | 1 +
> drivers/gpu/drm/drm_fb_helper.c | 109 +++++++++++++++++++++++++++++++++++++++-
> include/drm/drm_fb_helper.h | 15 ++++++
> 3 files changed, 124 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 9e4f2f1..8e6f34b 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -52,6 +52,7 @@ config DRM_KMS_FB_HELPER
> select FB_CFB_FILLRECT
> select FB_CFB_COPYAREA
> select FB_CFB_IMAGEBLIT
> + select FB_DEFERRED_IO
> help
> FBDEV helpers for KMS drivers.
>
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 855108e..5112b5d 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -48,6 +48,8 @@ MODULE_PARM_DESC(fbdev_emulation,
>
> static LIST_HEAD(kernel_fb_helper_list);
>
> +static void drm_fb_helper_dirty_init(struct drm_fb_helper *helper);
Instead of this forward decl just inline the few setup commands into
drm_fb_helper_prepare.
> +
> /**
> * DOC: fbdev helpers
> *
> @@ -84,6 +86,15 @@ static LIST_HEAD(kernel_fb_helper_list);
> * and set up an initial configuration using the detected hardware, drivers
> * should call drm_fb_helper_single_add_all_connectors() followed by
> * drm_fb_helper_initial_config().
> + *
> + * If CONFIG_FB_DEFERRED_IO is enabled and &drm_framebuffer_funcs ->dirty is
> + * set, the drm_fb_helper_{cfb,sys}_{write,fillrect,copyarea,imageblit}
> + * functions will accumulate changes and schedule &fb_helper .dirty_work to run
> + * right away. This worker then calls the dirty() function ensuring that it
> + * will always run in process context since the fb_*() function could be
> + * running in atomic context. If drm_fb_helper_deferred_io() is used as the
> + * deferred_io callback it will also schedule dirty_work with the damage
> + * collected from the mmap page writes.
> */
>
> /**
> @@ -650,6 +661,7 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
> const struct drm_fb_helper_funcs *funcs)
> {
> INIT_LIST_HEAD(&helper->kernel_fb_list);
> + drm_fb_helper_dirty_init(helper);
> helper->funcs = funcs;
> helper->dev = dev;
> }
> @@ -834,6 +846,82 @@ void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
> }
> EXPORT_SYMBOL(drm_fb_helper_unlink_fbi);
>
> +static void drm_fb_helper_dirty_work(struct work_struct *work)
> +{
> + struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
> + dirty_work);
> + struct drm_clip_rect *clip = &helper->dirty_clip;
> + struct drm_clip_rect clip_copy;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&helper->dirty_lock, flags);
> + clip_copy = *clip;
> + clip->x1 = clip->y1 = ~0;
> + clip->x2 = clip->y2 = 0;
> + spin_unlock_irqrestore(&helper->dirty_lock, flags);
> +
> + helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip_copy, 1);
> +}
> +
> +static void drm_fb_helper_dirty_init(struct drm_fb_helper *helper)
> +{
> + spin_lock_init(&helper->dirty_lock);
> + INIT_WORK(&helper->dirty_work, drm_fb_helper_dirty_work);
> + helper->dirty_clip.x1 = helper->dirty_clip.y1 = ~0;
> +}
> +
> +static void drm_fb_helper_dirty(struct fb_info *info, u32 x, u32 y,
> + u32 width, u32 height)
> +{
> + struct drm_fb_helper *helper = info->par;
> + struct drm_clip_rect *clip = &helper->dirty_clip;
> + unsigned long flags;
> +
> + if (!helper->fb->funcs->dirty)
> + return;
> +
> + spin_lock_irqsave(&helper->dirty_lock, flags);
> + clip->x1 = min_t(u32, clip->x1, x);
> + clip->y1 = min_t(u32, clip->y1, y);
> + clip->x2 = max_t(u32, clip->x2, x + width);
> + clip->y2 = max_t(u32, clip->y2, y + height);
> + spin_unlock_irqrestore(&helper->dirty_lock, flags);
> +
> + schedule_work(&helper->dirty_work);
> +}
> +
> +/**
> + * drm_fb_helper_deferred_io() - fbdev deferred_io callback function
> + * @info: fb_info struct pointer
> + * @pagelist: list of dirty mmap framebuffer pages
> + *
> + * This function is used as the &fb_deferred_io ->deferred_io
> + * callback function for flushing the fbdev mmap writes.
> + */
> +void drm_fb_helper_deferred_io(struct fb_info *info,
> + struct list_head *pagelist)
> +{
> + unsigned long start, end, min, max;
> + struct page *page;
> + u32 y1, y2;
> +
> + min = ULONG_MAX;
> + max = 0;
> + list_for_each_entry(page, pagelist, lru) {
> + start = page->index << PAGE_SHIFT;
> + end = start + PAGE_SIZE - 1;
> + min = min(min, start);
> + max = max(max, end);
> + }
> +
> + if (min < max) {
> + y1 = min / info->fix.line_length;
> + y2 = min_t(u32, max / info->fix.line_length, info->var.yres);
Needs a DIV_ROUND_UP here I think.
Besides these two nits nothing else I've spotted.
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> + drm_fb_helper_dirty(info, 0, y1, info->var.xres, y2 - y1);
> + }
> +}
> +EXPORT_SYMBOL(drm_fb_helper_deferred_io);
> +
> /**
> * drm_fb_helper_sys_read - wrapper around fb_sys_read
> * @info: fb_info struct pointer
> @@ -862,7 +950,14 @@ EXPORT_SYMBOL(drm_fb_helper_sys_read);
> ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
> size_t count, loff_t *ppos)
> {
> - return fb_sys_write(info, buf, count, ppos);
> + ssize_t ret;
> +
> + ret = fb_sys_write(info, buf, count, ppos);
> + if (ret > 0)
> + drm_fb_helper_dirty(info, 0, 0, info->var.xres,
> + info->var.yres);
> +
> + return ret;
> }
> EXPORT_SYMBOL(drm_fb_helper_sys_write);
>
> @@ -877,6 +972,8 @@ void drm_fb_helper_sys_fillrect(struct fb_info *info,
> const struct fb_fillrect *rect)
> {
> sys_fillrect(info, rect);
> + drm_fb_helper_dirty(info, rect->dx, rect->dy,
> + rect->width, rect->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_sys_fillrect);
>
> @@ -891,6 +988,8 @@ void drm_fb_helper_sys_copyarea(struct fb_info *info,
> const struct fb_copyarea *area)
> {
> sys_copyarea(info, area);
> + drm_fb_helper_dirty(info, area->dx, area->dy,
> + area->width, area->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_sys_copyarea);
>
> @@ -905,6 +1004,8 @@ void drm_fb_helper_sys_imageblit(struct fb_info *info,
> const struct fb_image *image)
> {
> sys_imageblit(info, image);
> + drm_fb_helper_dirty(info, image->dx, image->dy,
> + image->width, image->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_sys_imageblit);
>
> @@ -919,6 +1020,8 @@ void drm_fb_helper_cfb_fillrect(struct fb_info *info,
> const struct fb_fillrect *rect)
> {
> cfb_fillrect(info, rect);
> + drm_fb_helper_dirty(info, rect->dx, rect->dy,
> + rect->width, rect->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_cfb_fillrect);
>
> @@ -933,6 +1036,8 @@ void drm_fb_helper_cfb_copyarea(struct fb_info *info,
> const struct fb_copyarea *area)
> {
> cfb_copyarea(info, area);
> + drm_fb_helper_dirty(info, area->dx, area->dy,
> + area->width, area->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_cfb_copyarea);
>
> @@ -947,6 +1052,8 @@ void drm_fb_helper_cfb_imageblit(struct fb_info *info,
> const struct fb_image *image)
> {
> cfb_imageblit(info, image);
> + drm_fb_helper_dirty(info, image->dx, image->dy,
> + image->width, image->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit);
>
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index 062723b..5b4aa35 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -172,6 +172,10 @@ struct drm_fb_helper_connector {
> * @funcs: driver callbacks for fb helper
> * @fbdev: emulated fbdev device info struct
> * @pseudo_palette: fake palette of 16 colors
> + * @dirty_clip: clip rectangle used with deferred_io to accumulate damage to
> + * the screen buffer
> + * @dirty_lock: spinlock protecting @dirty_clip
> + * @dirty_work: worker used to flush the framebuffer
> *
> * This is the main structure used by the fbdev helpers. Drivers supporting
> * fbdev emulation should embedded this into their overall driver structure.
> @@ -189,6 +193,9 @@ struct drm_fb_helper {
> const struct drm_fb_helper_funcs *funcs;
> struct fb_info *fbdev;
> u32 pseudo_palette[17];
> + struct drm_clip_rect dirty_clip;
> + spinlock_t dirty_lock;
> + struct work_struct dirty_work;
>
> /**
> * @kernel_fb_list:
> @@ -245,6 +252,9 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
>
> void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper);
>
> +void drm_fb_helper_deferred_io(struct fb_info *info,
> + struct list_head *pagelist);
> +
> ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
> size_t count, loff_t *ppos);
> ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
> @@ -368,6 +378,11 @@ static inline void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
> {
> }
>
> +static inline void drm_fb_helper_deferred_io(struct fb_info *info,
> + struct list_head *pagelist)
> +{
> +}
> +
> static inline ssize_t drm_fb_helper_sys_read(struct fb_info *info,
> char __user *buf, size_t count,
> loff_t *ppos)
> --
> 2.2.2
>
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
WARNING: multiple messages have this Message-ID (diff)
From: Daniel Vetter <daniel@ffwll.ch>
To: "Noralf Trønnes" <noralf@tronnes.org>
Cc: dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org,
daniel@ffwll.ch, laurent.pinchart@ideasonboard.com,
tomi.valkeinen@ti.com, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v3 3/7] drm/fb-helper: Add fb_deferred_io support
Date: Wed, 27 Apr 2016 21:20:52 +0200 [thread overview]
Message-ID: <20160427192052.GG2558@phenom.ffwll.local> (raw)
In-Reply-To: <1461780996-8612-4-git-send-email-noralf@tronnes.org>
On Wed, Apr 27, 2016 at 08:16:32PM +0200, Noralf Trønnes wrote:
> This adds deferred io support to drm_fb_helper.
> The fbdev framebuffer changes are flushed using the callback
> (struct drm_framebuffer *)->funcs->dirty() by a dedicated worker
> ensuring that it always runs in process context.
>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>
> Changes since v2:
> - FB_DEFERRED_IO is now always selected by DRM_KMS_FB_HELPER, ifdef removed
> - The drm_clip_rect utility functions are dropped, so open code it
> - docs: use & to denote structs
>
> Changes since v1:
> - Use a dedicated worker to run the framebuffer flushing like qxl does
> - Add parameter descriptions to drm_fb_helper_deferred_io
>
> drivers/gpu/drm/Kconfig | 1 +
> drivers/gpu/drm/drm_fb_helper.c | 109 +++++++++++++++++++++++++++++++++++++++-
> include/drm/drm_fb_helper.h | 15 ++++++
> 3 files changed, 124 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 9e4f2f1..8e6f34b 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -52,6 +52,7 @@ config DRM_KMS_FB_HELPER
> select FB_CFB_FILLRECT
> select FB_CFB_COPYAREA
> select FB_CFB_IMAGEBLIT
> + select FB_DEFERRED_IO
> help
> FBDEV helpers for KMS drivers.
>
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 855108e..5112b5d 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -48,6 +48,8 @@ MODULE_PARM_DESC(fbdev_emulation,
>
> static LIST_HEAD(kernel_fb_helper_list);
>
> +static void drm_fb_helper_dirty_init(struct drm_fb_helper *helper);
Instead of this forward decl just inline the few setup commands into
drm_fb_helper_prepare.
> +
> /**
> * DOC: fbdev helpers
> *
> @@ -84,6 +86,15 @@ static LIST_HEAD(kernel_fb_helper_list);
> * and set up an initial configuration using the detected hardware, drivers
> * should call drm_fb_helper_single_add_all_connectors() followed by
> * drm_fb_helper_initial_config().
> + *
> + * If CONFIG_FB_DEFERRED_IO is enabled and &drm_framebuffer_funcs ->dirty is
> + * set, the drm_fb_helper_{cfb,sys}_{write,fillrect,copyarea,imageblit}
> + * functions will accumulate changes and schedule &fb_helper .dirty_work to run
> + * right away. This worker then calls the dirty() function ensuring that it
> + * will always run in process context since the fb_*() function could be
> + * running in atomic context. If drm_fb_helper_deferred_io() is used as the
> + * deferred_io callback it will also schedule dirty_work with the damage
> + * collected from the mmap page writes.
> */
>
> /**
> @@ -650,6 +661,7 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
> const struct drm_fb_helper_funcs *funcs)
> {
> INIT_LIST_HEAD(&helper->kernel_fb_list);
> + drm_fb_helper_dirty_init(helper);
> helper->funcs = funcs;
> helper->dev = dev;
> }
> @@ -834,6 +846,82 @@ void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
> }
> EXPORT_SYMBOL(drm_fb_helper_unlink_fbi);
>
> +static void drm_fb_helper_dirty_work(struct work_struct *work)
> +{
> + struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
> + dirty_work);
> + struct drm_clip_rect *clip = &helper->dirty_clip;
> + struct drm_clip_rect clip_copy;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&helper->dirty_lock, flags);
> + clip_copy = *clip;
> + clip->x1 = clip->y1 = ~0;
> + clip->x2 = clip->y2 = 0;
> + spin_unlock_irqrestore(&helper->dirty_lock, flags);
> +
> + helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip_copy, 1);
> +}
> +
> +static void drm_fb_helper_dirty_init(struct drm_fb_helper *helper)
> +{
> + spin_lock_init(&helper->dirty_lock);
> + INIT_WORK(&helper->dirty_work, drm_fb_helper_dirty_work);
> + helper->dirty_clip.x1 = helper->dirty_clip.y1 = ~0;
> +}
> +
> +static void drm_fb_helper_dirty(struct fb_info *info, u32 x, u32 y,
> + u32 width, u32 height)
> +{
> + struct drm_fb_helper *helper = info->par;
> + struct drm_clip_rect *clip = &helper->dirty_clip;
> + unsigned long flags;
> +
> + if (!helper->fb->funcs->dirty)
> + return;
> +
> + spin_lock_irqsave(&helper->dirty_lock, flags);
> + clip->x1 = min_t(u32, clip->x1, x);
> + clip->y1 = min_t(u32, clip->y1, y);
> + clip->x2 = max_t(u32, clip->x2, x + width);
> + clip->y2 = max_t(u32, clip->y2, y + height);
> + spin_unlock_irqrestore(&helper->dirty_lock, flags);
> +
> + schedule_work(&helper->dirty_work);
> +}
> +
> +/**
> + * drm_fb_helper_deferred_io() - fbdev deferred_io callback function
> + * @info: fb_info struct pointer
> + * @pagelist: list of dirty mmap framebuffer pages
> + *
> + * This function is used as the &fb_deferred_io ->deferred_io
> + * callback function for flushing the fbdev mmap writes.
> + */
> +void drm_fb_helper_deferred_io(struct fb_info *info,
> + struct list_head *pagelist)
> +{
> + unsigned long start, end, min, max;
> + struct page *page;
> + u32 y1, y2;
> +
> + min = ULONG_MAX;
> + max = 0;
> + list_for_each_entry(page, pagelist, lru) {
> + start = page->index << PAGE_SHIFT;
> + end = start + PAGE_SIZE - 1;
> + min = min(min, start);
> + max = max(max, end);
> + }
> +
> + if (min < max) {
> + y1 = min / info->fix.line_length;
> + y2 = min_t(u32, max / info->fix.line_length, info->var.yres);
Needs a DIV_ROUND_UP here I think.
Besides these two nits nothing else I've spotted.
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> + drm_fb_helper_dirty(info, 0, y1, info->var.xres, y2 - y1);
> + }
> +}
> +EXPORT_SYMBOL(drm_fb_helper_deferred_io);
> +
> /**
> * drm_fb_helper_sys_read - wrapper around fb_sys_read
> * @info: fb_info struct pointer
> @@ -862,7 +950,14 @@ EXPORT_SYMBOL(drm_fb_helper_sys_read);
> ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
> size_t count, loff_t *ppos)
> {
> - return fb_sys_write(info, buf, count, ppos);
> + ssize_t ret;
> +
> + ret = fb_sys_write(info, buf, count, ppos);
> + if (ret > 0)
> + drm_fb_helper_dirty(info, 0, 0, info->var.xres,
> + info->var.yres);
> +
> + return ret;
> }
> EXPORT_SYMBOL(drm_fb_helper_sys_write);
>
> @@ -877,6 +972,8 @@ void drm_fb_helper_sys_fillrect(struct fb_info *info,
> const struct fb_fillrect *rect)
> {
> sys_fillrect(info, rect);
> + drm_fb_helper_dirty(info, rect->dx, rect->dy,
> + rect->width, rect->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_sys_fillrect);
>
> @@ -891,6 +988,8 @@ void drm_fb_helper_sys_copyarea(struct fb_info *info,
> const struct fb_copyarea *area)
> {
> sys_copyarea(info, area);
> + drm_fb_helper_dirty(info, area->dx, area->dy,
> + area->width, area->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_sys_copyarea);
>
> @@ -905,6 +1004,8 @@ void drm_fb_helper_sys_imageblit(struct fb_info *info,
> const struct fb_image *image)
> {
> sys_imageblit(info, image);
> + drm_fb_helper_dirty(info, image->dx, image->dy,
> + image->width, image->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_sys_imageblit);
>
> @@ -919,6 +1020,8 @@ void drm_fb_helper_cfb_fillrect(struct fb_info *info,
> const struct fb_fillrect *rect)
> {
> cfb_fillrect(info, rect);
> + drm_fb_helper_dirty(info, rect->dx, rect->dy,
> + rect->width, rect->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_cfb_fillrect);
>
> @@ -933,6 +1036,8 @@ void drm_fb_helper_cfb_copyarea(struct fb_info *info,
> const struct fb_copyarea *area)
> {
> cfb_copyarea(info, area);
> + drm_fb_helper_dirty(info, area->dx, area->dy,
> + area->width, area->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_cfb_copyarea);
>
> @@ -947,6 +1052,8 @@ void drm_fb_helper_cfb_imageblit(struct fb_info *info,
> const struct fb_image *image)
> {
> cfb_imageblit(info, image);
> + drm_fb_helper_dirty(info, image->dx, image->dy,
> + image->width, image->height);
> }
> EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit);
>
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index 062723b..5b4aa35 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -172,6 +172,10 @@ struct drm_fb_helper_connector {
> * @funcs: driver callbacks for fb helper
> * @fbdev: emulated fbdev device info struct
> * @pseudo_palette: fake palette of 16 colors
> + * @dirty_clip: clip rectangle used with deferred_io to accumulate damage to
> + * the screen buffer
> + * @dirty_lock: spinlock protecting @dirty_clip
> + * @dirty_work: worker used to flush the framebuffer
> *
> * This is the main structure used by the fbdev helpers. Drivers supporting
> * fbdev emulation should embedded this into their overall driver structure.
> @@ -189,6 +193,9 @@ struct drm_fb_helper {
> const struct drm_fb_helper_funcs *funcs;
> struct fb_info *fbdev;
> u32 pseudo_palette[17];
> + struct drm_clip_rect dirty_clip;
> + spinlock_t dirty_lock;
> + struct work_struct dirty_work;
>
> /**
> * @kernel_fb_list:
> @@ -245,6 +252,9 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
>
> void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper);
>
> +void drm_fb_helper_deferred_io(struct fb_info *info,
> + struct list_head *pagelist);
> +
> ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
> size_t count, loff_t *ppos);
> ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
> @@ -368,6 +378,11 @@ static inline void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
> {
> }
>
> +static inline void drm_fb_helper_deferred_io(struct fb_info *info,
> + struct list_head *pagelist)
> +{
> +}
> +
> static inline ssize_t drm_fb_helper_sys_read(struct fb_info *info,
> char __user *buf, size_t count,
> loff_t *ppos)
> --
> 2.2.2
>
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
next prev parent reply other threads:[~2016-04-27 19:20 UTC|newest]
Thread overview: 47+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-04-27 18:16 [PATCH v3 0/7] drm: Add fbdev deferred io support to helpers Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 18:16 ` [PATCH v3 1/7] drm/udl: Change drm_fb_helper_sys_*() calls to sys_*() Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 18:16 ` [PATCH v3 2/7] drm/qxl: " Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 18:16 ` [PATCH v3 3/7] drm/fb-helper: Add fb_deferred_io support Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 19:20 ` Daniel Vetter [this message]
2016-04-27 19:20 ` Daniel Vetter
2016-04-27 19:20 ` Daniel Vetter
2016-04-27 19:24 ` Noralf Trønnes
2016-04-27 19:24 ` Noralf Trønnes
2016-04-28 7:17 ` Daniel Vetter
2016-04-28 7:17 ` Daniel Vetter
2016-04-28 7:17 ` Daniel Vetter
2016-04-27 18:16 ` [PATCH v3 4/7] fbdev: fb_defio: Export fb_deferred_io_mmap Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 18:16 ` [PATCH v3 5/7] drm/fb-cma-helper: Add fb_deferred_io support Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 18:16 ` [PATCH v3 6/7] drm/qxl: Use drm_fb_helper deferred_io support Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 19:22 ` Daniel Vetter
2016-04-27 19:22 ` Daniel Vetter
2016-04-27 19:22 ` Daniel Vetter
2016-04-27 18:16 ` [PATCH v3 7/7] drm/udl: " Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 18:16 ` Noralf Trønnes
2016-04-27 19:24 ` [PATCH v3 0/7] drm: Add fbdev deferred io support to helpers Daniel Vetter
2016-04-27 19:24 ` Daniel Vetter
2016-04-27 19:24 ` Daniel Vetter
2016-04-27 19:49 ` Noralf Trønnes
2016-04-27 19:49 ` Noralf Trønnes
2016-04-27 19:49 ` Noralf Trønnes
2016-04-28 7:20 ` Daniel Vetter
2016-04-28 7:20 ` Daniel Vetter
2016-04-28 7:20 ` Daniel Vetter
2016-04-29 8:02 ` Gerd Hoffmann
2016-04-29 8:02 ` Gerd Hoffmann
2016-04-29 8:02 ` Gerd Hoffmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20160427192052.GG2558@phenom.ffwll.local \
--to=daniel@ffwll.ch \
--cc=dri-devel@lists.freedesktop.org \
--cc=laurent.pinchart@ideasonboard.com \
--cc=linux-fbdev@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=noralf@tronnes.org \
--cc=tomi.valkeinen@ti.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.