Commit 59055851 authored by Thomas Zimmermann's avatar Thomas Zimmermann

fbdev: Put mmap for deferred I/O into drivers

The fbdev mmap function fb_mmap() unconditionally overrides the
driver's implementation if deferred I/O has been activated. This
makes it hard to implement mmap with anything but a vmalloc()'ed
software buffer. That is specifically a problem for DRM, where
video memory is maintained by a memory manager.

Leave the mmap handling to drivers and expect them to call the
helper for deferred I/O by thmeselves.

v4:
	* unlock mm_lock in fb_mmap() error path (Dan)
v3:
	* fix warning if fb_mmap is missing (kernel test robot)
v2:
	* print a helpful error message if the defio setup is
	  incorrect (Javier)
Signed-off-by: default avatarThomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: default avatarJavier Martinez Canillas <javierm@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220429100834.18898-2-tzimmermann@suse.de
parent 594e9c04
...@@ -2118,7 +2118,9 @@ static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) ...@@ -2118,7 +2118,9 @@ static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{ {
struct drm_fb_helper *fb_helper = info->par; struct drm_fb_helper *fb_helper = info->par;
if (fb_helper->dev->driver->gem_prime_mmap) if (drm_fbdev_use_shadow_fb(fb_helper))
return fb_deferred_io_mmap(info, vma);
else if (fb_helper->dev->driver->gem_prime_mmap)
return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma); return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma);
else else
return -ENODEV; return -ENODEV;
......
...@@ -619,6 +619,7 @@ static const struct fb_ops vmw_fb_ops = { ...@@ -619,6 +619,7 @@ static const struct fb_ops vmw_fb_ops = {
.fb_imageblit = vmw_fb_imageblit, .fb_imageblit = vmw_fb_imageblit,
.fb_pan_display = vmw_fb_pan_display, .fb_pan_display = vmw_fb_pan_display,
.fb_blank = vmw_fb_blank, .fb_blank = vmw_fb_blank,
.fb_mmap = fb_deferred_io_mmap,
}; };
int vmw_fb_init(struct vmw_private *vmw_priv) int vmw_fb_init(struct vmw_private *vmw_priv)
......
...@@ -428,6 +428,7 @@ static const struct fb_ops picolcdfb_ops = { ...@@ -428,6 +428,7 @@ static const struct fb_ops picolcdfb_ops = {
.fb_imageblit = picolcd_fb_imageblit, .fb_imageblit = picolcd_fb_imageblit,
.fb_check_var = picolcd_fb_check_var, .fb_check_var = picolcd_fb_check_var,
.fb_set_par = picolcd_set_par, .fb_set_par = picolcd_set_par,
.fb_mmap = fb_deferred_io_mmap,
}; };
......
...@@ -652,6 +652,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, ...@@ -652,6 +652,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
fbops->fb_imageblit = fbtft_fb_imageblit; fbops->fb_imageblit = fbtft_fb_imageblit;
fbops->fb_setcolreg = fbtft_fb_setcolreg; fbops->fb_setcolreg = fbtft_fb_setcolreg;
fbops->fb_blank = fbtft_fb_blank; fbops->fb_blank = fbtft_fb_blank;
fbops->fb_mmap = fb_deferred_io_mmap;
fbdefio->delay = HZ / fps; fbdefio->delay = HZ / fps;
fbdefio->sort_pagelist = true; fbdefio->sort_pagelist = true;
......
...@@ -1055,6 +1055,7 @@ static const struct fb_ops broadsheetfb_ops = { ...@@ -1055,6 +1055,7 @@ static const struct fb_ops broadsheetfb_ops = {
.fb_fillrect = broadsheetfb_fillrect, .fb_fillrect = broadsheetfb_fillrect,
.fb_copyarea = broadsheetfb_copyarea, .fb_copyarea = broadsheetfb_copyarea,
.fb_imageblit = broadsheetfb_imageblit, .fb_imageblit = broadsheetfb_imageblit,
.fb_mmap = fb_deferred_io_mmap,
}; };
static struct fb_deferred_io broadsheetfb_defio = { static struct fb_deferred_io broadsheetfb_defio = {
......
...@@ -181,6 +181,7 @@ int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma) ...@@ -181,6 +181,7 @@ int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
vma->vm_private_data = info; vma->vm_private_data = info;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(fb_deferred_io_mmap);
/* workqueue callback */ /* workqueue callback */
static void fb_deferred_io_work(struct work_struct *work) static void fb_deferred_io_work(struct work_struct *work)
......
...@@ -1334,7 +1334,6 @@ static int ...@@ -1334,7 +1334,6 @@ static int
fb_mmap(struct file *file, struct vm_area_struct * vma) fb_mmap(struct file *file, struct vm_area_struct * vma)
{ {
struct fb_info *info = file_fb_info(file); struct fb_info *info = file_fb_info(file);
int (*fb_mmap_fn)(struct fb_info *info, struct vm_area_struct *vma);
unsigned long mmio_pgoff; unsigned long mmio_pgoff;
unsigned long start; unsigned long start;
u32 len; u32 len;
...@@ -1343,14 +1342,7 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) ...@@ -1343,14 +1342,7 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
return -ENODEV; return -ENODEV;
mutex_lock(&info->mm_lock); mutex_lock(&info->mm_lock);
fb_mmap_fn = info->fbops->fb_mmap; if (info->fbops->fb_mmap) {
#if IS_ENABLED(CONFIG_FB_DEFERRED_IO)
if (info->fbdefio)
fb_mmap_fn = fb_deferred_io_mmap;
#endif
if (fb_mmap_fn) {
int res; int res;
/* /*
...@@ -1358,9 +1350,19 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) ...@@ -1358,9 +1350,19 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
* SME protection is removed ahead of the call * SME protection is removed ahead of the call
*/ */
vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
res = fb_mmap_fn(info, vma); res = info->fbops->fb_mmap(info, vma);
mutex_unlock(&info->mm_lock); mutex_unlock(&info->mm_lock);
return res; return res;
#if IS_ENABLED(CONFIG_FB_DEFERRED_IO)
} else if (info->fbdefio) {
/*
* FB deferred I/O wants you to handle mmap in your drivers. At a
* minimum, point struct fb_ops.fb_mmap to fb_deferred_io_mmap().
*/
dev_warn_once(info->dev, "fbdev mmap not set up for deferred I/O.\n");
mutex_unlock(&info->mm_lock);
return -ENODEV;
#endif
} }
/* /*
......
...@@ -204,6 +204,7 @@ static const struct fb_ops hecubafb_ops = { ...@@ -204,6 +204,7 @@ static const struct fb_ops hecubafb_ops = {
.fb_fillrect = hecubafb_fillrect, .fb_fillrect = hecubafb_fillrect,
.fb_copyarea = hecubafb_copyarea, .fb_copyarea = hecubafb_copyarea,
.fb_imageblit = hecubafb_imageblit, .fb_imageblit = hecubafb_imageblit,
.fb_mmap = fb_deferred_io_mmap,
}; };
static struct fb_deferred_io hecubafb_defio = { static struct fb_deferred_io hecubafb_defio = {
......
...@@ -909,6 +909,7 @@ static const struct fb_ops hvfb_ops = { ...@@ -909,6 +909,7 @@ static const struct fb_ops hvfb_ops = {
.fb_copyarea = hvfb_cfb_copyarea, .fb_copyarea = hvfb_cfb_copyarea,
.fb_imageblit = hvfb_cfb_imageblit, .fb_imageblit = hvfb_cfb_imageblit,
.fb_blank = hvfb_blank, .fb_blank = hvfb_blank,
.fb_mmap = fb_deferred_io_mmap,
}; };
......
...@@ -564,6 +564,7 @@ static const struct fb_ops metronomefb_ops = { ...@@ -564,6 +564,7 @@ static const struct fb_ops metronomefb_ops = {
.fb_fillrect = metronomefb_fillrect, .fb_fillrect = metronomefb_fillrect,
.fb_copyarea = metronomefb_copyarea, .fb_copyarea = metronomefb_copyarea,
.fb_imageblit = metronomefb_imageblit, .fb_imageblit = metronomefb_imageblit,
.fb_mmap = fb_deferred_io_mmap,
}; };
static struct fb_deferred_io metronomefb_defio = { static struct fb_deferred_io metronomefb_defio = {
......
...@@ -1480,6 +1480,9 @@ sh_mobile_lcdc_overlay_mmap(struct fb_info *info, struct vm_area_struct *vma) ...@@ -1480,6 +1480,9 @@ sh_mobile_lcdc_overlay_mmap(struct fb_info *info, struct vm_area_struct *vma)
{ {
struct sh_mobile_lcdc_overlay *ovl = info->par; struct sh_mobile_lcdc_overlay *ovl = info->par;
if (info->fbdefio)
return fb_deferred_io_mmap(info, vma);
return dma_mmap_coherent(ovl->channel->lcdc->dev, vma, ovl->fb_mem, return dma_mmap_coherent(ovl->channel->lcdc->dev, vma, ovl->fb_mem,
ovl->dma_handle, ovl->fb_size); ovl->dma_handle, ovl->fb_size);
} }
...@@ -1954,6 +1957,9 @@ sh_mobile_lcdc_mmap(struct fb_info *info, struct vm_area_struct *vma) ...@@ -1954,6 +1957,9 @@ sh_mobile_lcdc_mmap(struct fb_info *info, struct vm_area_struct *vma)
{ {
struct sh_mobile_lcdc_chan *ch = info->par; struct sh_mobile_lcdc_chan *ch = info->par;
if (info->fbdefio)
return fb_deferred_io_mmap(info, vma);
return dma_mmap_coherent(ch->lcdc->dev, vma, ch->fb_mem, return dma_mmap_coherent(ch->lcdc->dev, vma, ch->fb_mem,
ch->dma_handle, ch->fb_size); ch->dma_handle, ch->fb_size);
} }
......
...@@ -779,6 +779,9 @@ static int ufx_ops_mmap(struct fb_info *info, struct vm_area_struct *vma) ...@@ -779,6 +779,9 @@ static int ufx_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long page, pos; unsigned long page, pos;
if (info->fbdefio)
return fb_deferred_io_mmap(info, vma);
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
return -EINVAL; return -EINVAL;
if (size > info->fix.smem_len) if (size > info->fix.smem_len)
......
...@@ -368,6 +368,7 @@ static const struct fb_ops ssd1307fb_ops = { ...@@ -368,6 +368,7 @@ static const struct fb_ops ssd1307fb_ops = {
.fb_fillrect = ssd1307fb_fillrect, .fb_fillrect = ssd1307fb_fillrect,
.fb_copyarea = ssd1307fb_copyarea, .fb_copyarea = ssd1307fb_copyarea,
.fb_imageblit = ssd1307fb_imageblit, .fb_imageblit = ssd1307fb_imageblit,
.fb_mmap = fb_deferred_io_mmap,
}; };
static void ssd1307fb_deferred_io(struct fb_info *info, static void ssd1307fb_deferred_io(struct fb_info *info,
......
...@@ -326,6 +326,9 @@ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma) ...@@ -326,6 +326,9 @@ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long page, pos; unsigned long page, pos;
if (info->fbdefio)
return fb_deferred_io_mmap(info, vma);
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
return -EINVAL; return -EINVAL;
if (size > info->fix.smem_len) if (size > info->fix.smem_len)
......
...@@ -338,6 +338,7 @@ static const struct fb_ops xenfb_fb_ops = { ...@@ -338,6 +338,7 @@ static const struct fb_ops xenfb_fb_ops = {
.fb_imageblit = xenfb_imageblit, .fb_imageblit = xenfb_imageblit,
.fb_check_var = xenfb_check_var, .fb_check_var = xenfb_check_var,
.fb_set_par = xenfb_set_par, .fb_set_par = xenfb_set_par,
.fb_mmap = fb_deferred_io_mmap,
}; };
static irqreturn_t xenfb_event_handler(int rq, void *dev_id) static irqreturn_t xenfb_event_handler(int rq, void *dev_id)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment