All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Noralf Trønnes" <noralf@tronnes.org>
To: dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org,
	laurent.pinchart@ideasonboard.com, tomi.valkeinen@ti.com,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 4/8] drm/fb-helper: Add fb_deferred_io support
Date: Tue, 26 Apr 2016 16:24:54 +0000	[thread overview]
Message-ID: <571F9656.1090506@tronnes.org> (raw)
In-Reply-To: <20160425090957.GQ2510@phenom.ffwll.local>


Den 25.04.2016 11:09, skrev Daniel Vetter:
> On Sun, Apr 24, 2016 at 10:48:58PM +0200, Noralf Trønnes wrote:
>> This adds deferred io support if CONFIG_FB_DEFERRED_IO is enabled.
>> 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 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/drm_fb_helper.c | 127 +++++++++++++++++++++++++++++++++++++++-
>>   include/drm/drm_fb_helper.h     |  17 ++++++
>>   2 files changed, 143 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
>> index 855108e..46ee6f8 100644
>> --- a/drivers/gpu/drm/drm_fb_helper.c
>> +++ b/drivers/gpu/drm/drm_fb_helper.c
>> @@ -40,6 +40,7 @@
>>   #include <drm/drm_crtc_helper.h>
>>   #include <drm/drm_atomic.h>
>>   #include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_rect.h>
>>
>>   static bool drm_fbdev_emulation = true;
>>   module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
>> @@ -48,6 +49,10 @@ MODULE_PARM_DESC(fbdev_emulation,
>>
>>   static LIST_HEAD(kernel_fb_helper_list);
>>
>> +static void drm_fb_helper_dirty_init(struct drm_fb_helper *helper);
>> +static void drm_fb_helper_dirty(struct fb_info *info, u32 x, u32 y,
>> +				u32 width, u32 height);
>> +
>>   /**
>>    * DOC: fbdev helpers
>>    *
>> @@ -84,6 +89,16 @@ 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
>> + * (struct drm_framebuffer *)->funcs->dirty is set, the
>> + * drm_fb_helper_{cfb,sys}_{write,fillrect,copyarea,imageblit} functions
>> + * will accumulate changes and schedule (struct 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.
> One thing to consider (and personally I don't care either way) is whether
> we shouldn't just select CONFIG_FB_DEFERRED_IO if the fbdev helpers are
> enabled. Pushing that out to drivers is imo a bit fragile.
>
> But like I said I'm ok with either way.

My concern was adding code and data that only a few drivers would
actually use. But of course there's the tradeoff with complexity.
I use this to enable it:
         select FB_DEFERRED_IO if DRM_KMS_FB_HELPER

I guess the maintainer has to make this choice between size and 
complexity :-)
I can enable it by default if you want, drm is both huge and complex so I
don't know what's best.

As a sidenote, I have also put all the fbdev code in a file of it's own to
make it simple with regards to the DRM_FBDEV_EMULATION user option:
tinydrm-$(CONFIG_DRM_KMS_FB_HELPER)     += tinydrm-fbdev.o

>>    */
>>
>>   /**
>> @@ -401,11 +416,14 @@ backoff:
>>   static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
>>   {
>>   	struct drm_device *dev = fb_helper->dev;
>> +	struct fb_info *info = fb_helper->fbdev;
>>   	struct drm_plane *plane;
>>   	int i;
>>
>>   	drm_warn_on_modeset_not_all_locked(dev);
>>
>> +	drm_fb_helper_dirty(info, 0, 0, info->var.xres, info->var.yres);
> Why is this needed? If you do a modeset (or pageflip or whatever) drivers
> are supposed to re-upload the entire screen. We've talked about adding a
> dirty rectangle to atomic to allow userspace to optimize this, but there
> should _never_ be a need to do a dirtyfb call around a modeset. Probably
> just a driver bug in your panel drm drivers?

Ok, in tinydrm I now set a flag in &drm_simple_display_pipe_funcs
->plane_update to indicate that the next dirty() should do the whole
framebuffer which seems to work fine.
Should I actually perform the update as well?
If so I would need to add a worker in tinydrm to do that.


Noralf.

> With the above line removed:
>
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>
>> +
>>   	if (fb_helper->atomic)
>>   		return restore_fbdev_mode_atomic(fb_helper);
>>
>> @@ -650,6 +668,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 +853,93 @@ void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
>>   }
>>   EXPORT_SYMBOL(drm_fb_helper_unlink_fbi);
>>
>> +#ifdef CONFIG_FB_DEFERRED_IO
>> +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;
>> +	unsigned long flags;
>> +
>> +	spin_lock_irqsave(&helper->dirty_lock, flags);
>> +	clip = helper->dirty_clip;
>> +	drm_clip_rect_reset(&helper->dirty_clip);
>> +	spin_unlock_irqrestore(&helper->dirty_lock, flags);
>> +
>> +	helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip, 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);
>> +}
>> +
>> +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;
>> +	unsigned long flags;
>> +
>> +	if (!helper->fb->funcs->dirty)
>> +		return;
>> +
>> +	clip.x1 = x;
>> +	clip.x2 = x + width;
>> +	clip.y1 = y;
>> +	clip.y2 = y + height;
>> +
>> +	spin_lock_irqsave(&helper->dirty_lock, flags);
>> +	drm_clip_rect_merge(&helper->dirty_clip, &clip, 1, 0, 0, 0);
>> +	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 (struct 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);
>> +		drm_fb_helper_dirty(info, 0, y1, info->var.xres, y2 - y1);
>> +	}
>> +}
>> +EXPORT_SYMBOL(drm_fb_helper_deferred_io);
>> +
>> +#else
>> +static void drm_fb_helper_dirty_init(struct drm_fb_helper *helper)
>> +{
>> +}
>> +
>> +static void drm_fb_helper_dirty(struct fb_info *info, u32 x, u32 y,
>> +				u32 width, u32 height)
>> +{
>> +}
>> +#endif /* CONFIG_FB_DEFERRED_IO */
>> +
>>   /**
>>    * drm_fb_helper_sys_read - wrapper around fb_sys_read
>>    * @info: fb_info struct pointer
>> @@ -862,7 +968,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 +990,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 +1006,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 +1022,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 +1038,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 +1054,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 +1070,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..dde825c 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,11 @@ struct drm_fb_helper {
>>   	const struct drm_fb_helper_funcs *funcs;
>>   	struct fb_info *fbdev;
>>   	u32 pseudo_palette[17];
>> +#ifdef CONFIG_FB_DEFERRED_IO
>> +	struct drm_clip_rect dirty_clip;
>> +	spinlock_t dirty_lock;
>> +	struct work_struct dirty_work;
>> +#endif
>>
>>   	/**
>>   	 * @kernel_fb_list:
>> @@ -245,6 +254,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 +380,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
>>


WARNING: multiple messages have this Message-ID (diff)
From: "Noralf Trønnes" <noralf@tronnes.org>
To: dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org,
	laurent.pinchart@ideasonboard.com, tomi.valkeinen@ti.com,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 4/8] drm/fb-helper: Add fb_deferred_io support
Date: Tue, 26 Apr 2016 18:24:54 +0200	[thread overview]
Message-ID: <571F9656.1090506@tronnes.org> (raw)
In-Reply-To: <20160425090957.GQ2510@phenom.ffwll.local>


Den 25.04.2016 11:09, skrev Daniel Vetter:
> On Sun, Apr 24, 2016 at 10:48:58PM +0200, Noralf Trønnes wrote:
>> This adds deferred io support if CONFIG_FB_DEFERRED_IO is enabled.
>> 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 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/drm_fb_helper.c | 127 +++++++++++++++++++++++++++++++++++++++-
>>   include/drm/drm_fb_helper.h     |  17 ++++++
>>   2 files changed, 143 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
>> index 855108e..46ee6f8 100644
>> --- a/drivers/gpu/drm/drm_fb_helper.c
>> +++ b/drivers/gpu/drm/drm_fb_helper.c
>> @@ -40,6 +40,7 @@
>>   #include <drm/drm_crtc_helper.h>
>>   #include <drm/drm_atomic.h>
>>   #include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_rect.h>
>>
>>   static bool drm_fbdev_emulation = true;
>>   module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
>> @@ -48,6 +49,10 @@ MODULE_PARM_DESC(fbdev_emulation,
>>
>>   static LIST_HEAD(kernel_fb_helper_list);
>>
>> +static void drm_fb_helper_dirty_init(struct drm_fb_helper *helper);
>> +static void drm_fb_helper_dirty(struct fb_info *info, u32 x, u32 y,
>> +				u32 width, u32 height);
>> +
>>   /**
>>    * DOC: fbdev helpers
>>    *
>> @@ -84,6 +89,16 @@ 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
>> + * (struct drm_framebuffer *)->funcs->dirty is set, the
>> + * drm_fb_helper_{cfb,sys}_{write,fillrect,copyarea,imageblit} functions
>> + * will accumulate changes and schedule (struct 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.
> One thing to consider (and personally I don't care either way) is whether
> we shouldn't just select CONFIG_FB_DEFERRED_IO if the fbdev helpers are
> enabled. Pushing that out to drivers is imo a bit fragile.
>
> But like I said I'm ok with either way.

My concern was adding code and data that only a few drivers would
actually use. But of course there's the tradeoff with complexity.
I use this to enable it:
         select FB_DEFERRED_IO if DRM_KMS_FB_HELPER

I guess the maintainer has to make this choice between size and 
complexity :-)
I can enable it by default if you want, drm is both huge and complex so I
don't know what's best.

As a sidenote, I have also put all the fbdev code in a file of it's own to
make it simple with regards to the DRM_FBDEV_EMULATION user option:
tinydrm-$(CONFIG_DRM_KMS_FB_HELPER)     += tinydrm-fbdev.o

>>    */
>>
>>   /**
>> @@ -401,11 +416,14 @@ backoff:
>>   static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
>>   {
>>   	struct drm_device *dev = fb_helper->dev;
>> +	struct fb_info *info = fb_helper->fbdev;
>>   	struct drm_plane *plane;
>>   	int i;
>>
>>   	drm_warn_on_modeset_not_all_locked(dev);
>>
>> +	drm_fb_helper_dirty(info, 0, 0, info->var.xres, info->var.yres);
> Why is this needed? If you do a modeset (or pageflip or whatever) drivers
> are supposed to re-upload the entire screen. We've talked about adding a
> dirty rectangle to atomic to allow userspace to optimize this, but there
> should _never_ be a need to do a dirtyfb call around a modeset. Probably
> just a driver bug in your panel drm drivers?

Ok, in tinydrm I now set a flag in &drm_simple_display_pipe_funcs
->plane_update to indicate that the next dirty() should do the whole
framebuffer which seems to work fine.
Should I actually perform the update as well?
If so I would need to add a worker in tinydrm to do that.


Noralf.

> With the above line removed:
>
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>
>> +
>>   	if (fb_helper->atomic)
>>   		return restore_fbdev_mode_atomic(fb_helper);
>>
>> @@ -650,6 +668,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 +853,93 @@ void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
>>   }
>>   EXPORT_SYMBOL(drm_fb_helper_unlink_fbi);
>>
>> +#ifdef CONFIG_FB_DEFERRED_IO
>> +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;
>> +	unsigned long flags;
>> +
>> +	spin_lock_irqsave(&helper->dirty_lock, flags);
>> +	clip = helper->dirty_clip;
>> +	drm_clip_rect_reset(&helper->dirty_clip);
>> +	spin_unlock_irqrestore(&helper->dirty_lock, flags);
>> +
>> +	helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip, 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);
>> +}
>> +
>> +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;
>> +	unsigned long flags;
>> +
>> +	if (!helper->fb->funcs->dirty)
>> +		return;
>> +
>> +	clip.x1 = x;
>> +	clip.x2 = x + width;
>> +	clip.y1 = y;
>> +	clip.y2 = y + height;
>> +
>> +	spin_lock_irqsave(&helper->dirty_lock, flags);
>> +	drm_clip_rect_merge(&helper->dirty_clip, &clip, 1, 0, 0, 0);
>> +	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 (struct 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);
>> +		drm_fb_helper_dirty(info, 0, y1, info->var.xres, y2 - y1);
>> +	}
>> +}
>> +EXPORT_SYMBOL(drm_fb_helper_deferred_io);
>> +
>> +#else
>> +static void drm_fb_helper_dirty_init(struct drm_fb_helper *helper)
>> +{
>> +}
>> +
>> +static void drm_fb_helper_dirty(struct fb_info *info, u32 x, u32 y,
>> +				u32 width, u32 height)
>> +{
>> +}
>> +#endif /* CONFIG_FB_DEFERRED_IO */
>> +
>>   /**
>>    * drm_fb_helper_sys_read - wrapper around fb_sys_read
>>    * @info: fb_info struct pointer
>> @@ -862,7 +968,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 +990,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 +1006,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 +1022,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 +1038,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 +1054,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 +1070,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..dde825c 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,11 @@ struct drm_fb_helper {
>>   	const struct drm_fb_helper_funcs *funcs;
>>   	struct fb_info *fbdev;
>>   	u32 pseudo_palette[17];
>> +#ifdef CONFIG_FB_DEFERRED_IO
>> +	struct drm_clip_rect dirty_clip;
>> +	spinlock_t dirty_lock;
>> +	struct work_struct dirty_work;
>> +#endif
>>
>>   	/**
>>   	 * @kernel_fb_list:
>> @@ -245,6 +254,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 +380,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
>>

_______________________________________________
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: "Noralf Trønnes" <noralf@tronnes.org>
To: dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org,
	laurent.pinchart@ideasonboard.com, tomi.valkeinen@ti.com,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 4/8] drm/fb-helper: Add fb_deferred_io support
Date: Tue, 26 Apr 2016 18:24:54 +0200	[thread overview]
Message-ID: <571F9656.1090506@tronnes.org> (raw)
In-Reply-To: <20160425090957.GQ2510@phenom.ffwll.local>


Den 25.04.2016 11:09, skrev Daniel Vetter:
> On Sun, Apr 24, 2016 at 10:48:58PM +0200, Noralf Trønnes wrote:
>> This adds deferred io support if CONFIG_FB_DEFERRED_IO is enabled.
>> 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 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/drm_fb_helper.c | 127 +++++++++++++++++++++++++++++++++++++++-
>>   include/drm/drm_fb_helper.h     |  17 ++++++
>>   2 files changed, 143 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
>> index 855108e..46ee6f8 100644
>> --- a/drivers/gpu/drm/drm_fb_helper.c
>> +++ b/drivers/gpu/drm/drm_fb_helper.c
>> @@ -40,6 +40,7 @@
>>   #include <drm/drm_crtc_helper.h>
>>   #include <drm/drm_atomic.h>
>>   #include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_rect.h>
>>
>>   static bool drm_fbdev_emulation = true;
>>   module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
>> @@ -48,6 +49,10 @@ MODULE_PARM_DESC(fbdev_emulation,
>>
>>   static LIST_HEAD(kernel_fb_helper_list);
>>
>> +static void drm_fb_helper_dirty_init(struct drm_fb_helper *helper);
>> +static void drm_fb_helper_dirty(struct fb_info *info, u32 x, u32 y,
>> +				u32 width, u32 height);
>> +
>>   /**
>>    * DOC: fbdev helpers
>>    *
>> @@ -84,6 +89,16 @@ 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
>> + * (struct drm_framebuffer *)->funcs->dirty is set, the
>> + * drm_fb_helper_{cfb,sys}_{write,fillrect,copyarea,imageblit} functions
>> + * will accumulate changes and schedule (struct 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.
> One thing to consider (and personally I don't care either way) is whether
> we shouldn't just select CONFIG_FB_DEFERRED_IO if the fbdev helpers are
> enabled. Pushing that out to drivers is imo a bit fragile.
>
> But like I said I'm ok with either way.

My concern was adding code and data that only a few drivers would
actually use. But of course there's the tradeoff with complexity.
I use this to enable it:
         select FB_DEFERRED_IO if DRM_KMS_FB_HELPER

I guess the maintainer has to make this choice between size and 
complexity :-)
I can enable it by default if you want, drm is both huge and complex so I
don't know what's best.

As a sidenote, I have also put all the fbdev code in a file of it's own to
make it simple with regards to the DRM_FBDEV_EMULATION user option:
tinydrm-$(CONFIG_DRM_KMS_FB_HELPER)     += tinydrm-fbdev.o

>>    */
>>
>>   /**
>> @@ -401,11 +416,14 @@ backoff:
>>   static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
>>   {
>>   	struct drm_device *dev = fb_helper->dev;
>> +	struct fb_info *info = fb_helper->fbdev;
>>   	struct drm_plane *plane;
>>   	int i;
>>
>>   	drm_warn_on_modeset_not_all_locked(dev);
>>
>> +	drm_fb_helper_dirty(info, 0, 0, info->var.xres, info->var.yres);
> Why is this needed? If you do a modeset (or pageflip or whatever) drivers
> are supposed to re-upload the entire screen. We've talked about adding a
> dirty rectangle to atomic to allow userspace to optimize this, but there
> should _never_ be a need to do a dirtyfb call around a modeset. Probably
> just a driver bug in your panel drm drivers?

Ok, in tinydrm I now set a flag in &drm_simple_display_pipe_funcs
->plane_update to indicate that the next dirty() should do the whole
framebuffer which seems to work fine.
Should I actually perform the update as well?
If so I would need to add a worker in tinydrm to do that.


Noralf.

> With the above line removed:
>
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>
>> +
>>   	if (fb_helper->atomic)
>>   		return restore_fbdev_mode_atomic(fb_helper);
>>
>> @@ -650,6 +668,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 +853,93 @@ void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
>>   }
>>   EXPORT_SYMBOL(drm_fb_helper_unlink_fbi);
>>
>> +#ifdef CONFIG_FB_DEFERRED_IO
>> +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;
>> +	unsigned long flags;
>> +
>> +	spin_lock_irqsave(&helper->dirty_lock, flags);
>> +	clip = helper->dirty_clip;
>> +	drm_clip_rect_reset(&helper->dirty_clip);
>> +	spin_unlock_irqrestore(&helper->dirty_lock, flags);
>> +
>> +	helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip, 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);
>> +}
>> +
>> +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;
>> +	unsigned long flags;
>> +
>> +	if (!helper->fb->funcs->dirty)
>> +		return;
>> +
>> +	clip.x1 = x;
>> +	clip.x2 = x + width;
>> +	clip.y1 = y;
>> +	clip.y2 = y + height;
>> +
>> +	spin_lock_irqsave(&helper->dirty_lock, flags);
>> +	drm_clip_rect_merge(&helper->dirty_clip, &clip, 1, 0, 0, 0);
>> +	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 (struct 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);
>> +		drm_fb_helper_dirty(info, 0, y1, info->var.xres, y2 - y1);
>> +	}
>> +}
>> +EXPORT_SYMBOL(drm_fb_helper_deferred_io);
>> +
>> +#else
>> +static void drm_fb_helper_dirty_init(struct drm_fb_helper *helper)
>> +{
>> +}
>> +
>> +static void drm_fb_helper_dirty(struct fb_info *info, u32 x, u32 y,
>> +				u32 width, u32 height)
>> +{
>> +}
>> +#endif /* CONFIG_FB_DEFERRED_IO */
>> +
>>   /**
>>    * drm_fb_helper_sys_read - wrapper around fb_sys_read
>>    * @info: fb_info struct pointer
>> @@ -862,7 +968,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 +990,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 +1006,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 +1022,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 +1038,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 +1054,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 +1070,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..dde825c 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,11 @@ struct drm_fb_helper {
>>   	const struct drm_fb_helper_funcs *funcs;
>>   	struct fb_info *fbdev;
>>   	u32 pseudo_palette[17];
>> +#ifdef CONFIG_FB_DEFERRED_IO
>> +	struct drm_clip_rect dirty_clip;
>> +	spinlock_t dirty_lock;
>> +	struct work_struct dirty_work;
>> +#endif
>>
>>   	/**
>>   	 * @kernel_fb_list:
>> @@ -245,6 +254,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 +380,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
>>

  reply	other threads:[~2016-04-26 16:24 UTC|newest]

Thread overview: 87+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-04-24 20:48 [PATCH v2 0/8] drm: Add fbdev deferred io support to helpers Noralf Trønnes
2016-04-24 20:48 ` Noralf Trønnes
2016-04-24 20:48 ` Noralf Trønnes
2016-04-24 20:48 ` [PATCH v2 1/8] drm/rect: Add some drm_clip_rect utility functions Noralf Trønnes
2016-04-24 20:48   ` Noralf Trønnes
2016-04-24 20:48   ` Noralf Trønnes
2016-04-25  9:02   ` Daniel Vetter
2016-04-25  9:02     ` Daniel Vetter
2016-04-25  9:02     ` Daniel Vetter
2016-04-25 12:39   ` Ville Syrjälä
2016-04-25 12:39     ` Ville Syrjälä
2016-04-25 12:39     ` Ville Syrjälä
2016-04-25 12:55     ` Noralf Trønnes
2016-04-25 12:55       ` Noralf Trønnes
2016-04-25 12:55       ` Noralf Trønnes
2016-04-25 13:02       ` Ville Syrjälä
2016-04-25 13:02         ` Ville Syrjälä
2016-04-25 14:03         ` Noralf Trønnes
2016-04-25 14:03           ` Noralf Trønnes
2016-04-25 14:03           ` Noralf Trønnes
2016-04-25 15:09           ` Ville Syrjälä
2016-04-25 15:09             ` Ville Syrjälä
2016-04-25 15:09             ` Ville Syrjälä
2016-04-25 16:05             ` Daniel Vetter
2016-04-25 16:05               ` Daniel Vetter
2016-04-25 16:05               ` Daniel Vetter
2016-04-25 16:38               ` Ville Syrjälä
2016-04-25 16:38                 ` Ville Syrjälä
2016-04-25 16:38                 ` Ville Syrjälä
2016-04-25 18:35                 ` Noralf Trønnes
2016-04-25 18:35                   ` Noralf Trønnes
2016-04-25 18:35                   ` Noralf Trønnes
2016-04-25 19:03                   ` Daniel Vetter
2016-04-25 19:03                     ` Daniel Vetter
2016-04-25 19:03                     ` Daniel Vetter
2016-04-25 21:13                   ` Laurent Pinchart
2016-04-25 21:13                     ` Laurent Pinchart
2016-04-26 16:26                     ` Noralf Trønnes
2016-04-26 16:26                       ` Noralf Trønnes
2016-04-24 20:48 ` [PATCH v2 2/8] drm/udl: Change drm_fb_helper_sys_*() calls to sys_*() Noralf Trønnes
2016-04-24 20:48   ` Noralf Trønnes
2016-04-24 20:48 ` [PATCH v2 3/8] drm/qxl: " Noralf Trønnes
2016-04-24 20:48   ` Noralf Trønnes
2016-04-24 20:48   ` Noralf Trønnes
2016-04-25  9:03   ` Daniel Vetter
2016-04-25  9:03     ` Daniel Vetter
2016-04-25  9:03     ` Daniel Vetter
2016-04-24 20:48 ` [PATCH v2 4/8] drm/fb-helper: Add fb_deferred_io support Noralf Trønnes
2016-04-24 20:48   ` Noralf Trønnes
2016-04-24 20:48   ` Noralf Trønnes
2016-04-25  9:09   ` Daniel Vetter
2016-04-25  9:09     ` Daniel Vetter
2016-04-26 16:24     ` Noralf Trønnes [this message]
2016-04-26 16:24       ` Noralf Trønnes
2016-04-26 16:24       ` Noralf Trønnes
2016-04-26 17:19       ` Daniel Vetter
2016-04-26 17:19         ` Daniel Vetter
2016-04-26 17:19         ` Daniel Vetter
2016-04-27  9:45         ` Noralf Trønnes
2016-04-27  9:45           ` Noralf Trønnes
2016-04-27  9:45           ` Noralf Trønnes
2016-04-27 11:14           ` Daniel Vetter
2016-04-27 11:14             ` Daniel Vetter
2016-04-27 11:14             ` Daniel Vetter
2016-04-24 20:48 ` [PATCH v2 5/8] fbdev: fb_defio: Export fb_deferred_io_mmap Noralf Trønnes
2016-04-24 20:48   ` Noralf Trønnes
2016-04-24 20:48   ` Noralf Trønnes
2016-04-25  9:11   ` Daniel Vetter
2016-04-25  9:11     ` Daniel Vetter
2016-04-25  9:11     ` Daniel Vetter
2016-04-24 20:49 ` [PATCH v2 6/8] drm/fb-cma-helper: Add fb_deferred_io support Noralf Trønnes
2016-04-24 20:49   ` Noralf Trønnes
2016-04-24 20:49   ` Noralf Trønnes
2016-04-25  9:15   ` Daniel Vetter
2016-04-25  9:15     ` Daniel Vetter
2016-04-25  9:15     ` Daniel Vetter
2016-04-24 20:49 ` [PATCH v2 7/8] drm/qxl: Use drm_fb_helper deferred_io support Noralf Trønnes
2016-04-24 20:49   ` Noralf Trønnes
2016-04-24 20:49   ` Noralf Trønnes
2016-04-25  9:16   ` Daniel Vetter
2016-04-25  9:16     ` Daniel Vetter
2016-04-24 20:49 ` [PATCH v2 8/8] drm/udl: " Noralf Trønnes
2016-04-24 20:49   ` Noralf Trønnes
2016-04-24 20:49   ` Noralf Trønnes
2016-04-25  9:17   ` Daniel Vetter
2016-04-25  9:17     ` Daniel Vetter
2016-04-25  9:17     ` Daniel Vetter

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=571F9656.1090506@tronnes.org \
    --to=noralf@tronnes.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-fbdev@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.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.