diff options
| author | Dave Airlie <airlied@redhat.com> | 2022-05-06 17:19:11 +1000 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2022-05-06 17:20:13 +1000 |
| commit | c67f84e97bafe73c47d5773105b114118ffb84df (patch) | |
| tree | d8e01ee364dda98fe99426ab62b4dd9fbd89c980 /drivers/video/fbdev | |
| parent | af3847a7472d2def8358b7ae94b14f1d20fd8661 (diff) | |
| parent | 6071c4c2a319da360b0bf2bc397d4fefad10b2c8 (diff) | |
| download | linux-c67f84e97bafe73c47d5773105b114118ffb84df.tar.bz2 | |
Merge tag 'drm-misc-next-2022-05-05' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for 5.19:
UAPI Changes:
Cross-subsystem Changes:
Core Changes:
- Add DRM-managed mutex initialisation
- edid: Doc improvements
- fbdev: deferred io improvements
- format-helper: consolidate format conversion helpers
- gem: Rework fence handling in drm_gem_plane_helper_prepare_fb
Driver Changes:
- ast: DisplayPort support, locking improvements
- exynos: Revert conversion to devm_drm_of_get_bridge for DSI
- mgag200: locking improvements
- mxsfb: LCDIF CRC support
- nouveau: switch to drm_gem_plane_helper_prepare_fb
- rockchip: Refactor IOMMU initialisation, make some structures
static, replace drm_detect_hdmi_monitor with
drm_display_info.is_hdmi, support swapped YUV formats,
clock improvements, rk3568 support, VOP2 support
- bridge:
- adv7511: Enable CEC for ADV7535
- it6505: Send DPCD SET_POWER to monitor at disable
- mcde_dsi: Revert conversion to devm_drm_of_get_bridge
- tc358767: Fix for eDP and DP DT endpoint parsing
- new bridge: i.MX8MP LDB
- panel:
- new panel: Startek KD070WVFPA043-C069A
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maxime Ripard <maxime@cerno.tech>
Link: https://patchwork.freedesktop.org/patch/msgid/20220505131127.lcqvsywo7qt3eywk@houat
Diffstat (limited to 'drivers/video/fbdev')
| -rw-r--r-- | drivers/video/fbdev/broadsheetfb.c | 27 | ||||
| -rw-r--r-- | drivers/video/fbdev/core/fb_defio.c | 212 | ||||
| -rw-r--r-- | drivers/video/fbdev/core/fbmem.c | 22 | ||||
| -rw-r--r-- | drivers/video/fbdev/hecubafb.c | 4 | ||||
| -rw-r--r-- | drivers/video/fbdev/hyperv_fb.c | 10 | ||||
| -rw-r--r-- | drivers/video/fbdev/metronomefb.c | 23 | ||||
| -rw-r--r-- | drivers/video/fbdev/sh_mobile_lcdcfb.c | 27 | ||||
| -rw-r--r-- | drivers/video/fbdev/smscufx.c | 13 | ||||
| -rw-r--r-- | drivers/video/fbdev/ssd1307fb.c | 4 | ||||
| -rw-r--r-- | drivers/video/fbdev/udlfb.c | 18 | ||||
| -rw-r--r-- | drivers/video/fbdev/xen-fbfront.c | 10 |
11 files changed, 226 insertions, 144 deletions
diff --git a/drivers/video/fbdev/broadsheetfb.c b/drivers/video/fbdev/broadsheetfb.c index b9054f658838..55e62dd96f9b 100644 --- a/drivers/video/fbdev/broadsheetfb.c +++ b/drivers/video/fbdev/broadsheetfb.c @@ -929,13 +929,11 @@ static void broadsheetfb_dpy_update(struct broadsheetfb_par *par) } /* this is called back from the deferred io workqueue */ -static void broadsheetfb_dpy_deferred_io(struct fb_info *info, - struct list_head *pagelist) +static void broadsheetfb_dpy_deferred_io(struct fb_info *info, struct list_head *pagereflist) { u16 y1 = 0, h = 0; - int prev_index = -1; - struct page *cur; - struct fb_deferred_io *fbdefio = info->fbdefio; + unsigned long prev_offset = ULONG_MAX; + struct fb_deferred_io_pageref *pageref; int h_inc; u16 yres = info->var.yres; u16 xres = info->var.xres; @@ -944,22 +942,22 @@ static void broadsheetfb_dpy_deferred_io(struct fb_info *info, h_inc = DIV_ROUND_UP(PAGE_SIZE , xres); /* walk the written page list and swizzle the data */ - list_for_each_entry(cur, &fbdefio->pagelist, lru) { - if (prev_index < 0) { + list_for_each_entry(pageref, pagereflist, list) { + if (prev_offset == ULONG_MAX) { /* just starting so assign first page */ - y1 = (cur->index << PAGE_SHIFT) / xres; + y1 = pageref->offset / xres; h = h_inc; - } else if ((prev_index + 1) == cur->index) { + } else if ((prev_offset + PAGE_SIZE) == pageref->offset) { /* this page is consecutive so increase our height */ h += h_inc; } else { /* page not consecutive, issue previous update first */ broadsheetfb_dpy_update_pages(info->par, y1, y1 + h); /* start over with our non consecutive page */ - y1 = (cur->index << PAGE_SHIFT) / xres; + y1 = pageref->offset / xres; h = h_inc; } - prev_index = cur->index; + prev_offset = pageref->offset; } /* if we still have any pages to update we do so now */ @@ -1055,12 +1053,13 @@ static const struct fb_ops broadsheetfb_ops = { .fb_fillrect = broadsheetfb_fillrect, .fb_copyarea = broadsheetfb_copyarea, .fb_imageblit = broadsheetfb_imageblit, + .fb_mmap = fb_deferred_io_mmap, }; static struct fb_deferred_io broadsheetfb_defio = { - .delay = HZ/4, - .sort_pagelist = true, - .deferred_io = broadsheetfb_dpy_deferred_io, + .delay = HZ/4, + .sort_pagereflist = true, + .deferred_io = broadsheetfb_dpy_deferred_io, }; static int broadsheetfb_probe(struct platform_device *dev) diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c index 6aaf6d0abf39..c730253ab85c 100644 --- a/drivers/video/fbdev/core/fb_defio.c +++ b/drivers/video/fbdev/core/fb_defio.c @@ -36,6 +36,60 @@ static struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs return page; } +static struct fb_deferred_io_pageref *fb_deferred_io_pageref_get(struct fb_info *info, + unsigned long offset, + struct page *page) +{ + struct fb_deferred_io *fbdefio = info->fbdefio; + struct list_head *pos = &fbdefio->pagereflist; + unsigned long pgoff = offset >> PAGE_SHIFT; + struct fb_deferred_io_pageref *pageref, *cur; + + if (WARN_ON_ONCE(pgoff >= info->npagerefs)) + return NULL; /* incorrect allocation size */ + + /* 1:1 mapping between pageref and page offset */ + pageref = &info->pagerefs[pgoff]; + + /* + * This check is to catch the case where a new process could start + * writing to the same page through a new PTE. This new access + * can cause a call to .page_mkwrite even if the original process' + * PTE is marked writable. + */ + if (!list_empty(&pageref->list)) + goto pageref_already_added; + + pageref->page = page; + pageref->offset = pgoff << PAGE_SHIFT; + + if (unlikely(fbdefio->sort_pagereflist)) { + /* + * We loop through the list of pagerefs before adding in + * order to keep the pagerefs sorted. This has significant + * overhead of O(n^2) with n being the number of written + * pages. If possible, drivers should try to work with + * unsorted page lists instead. + */ + list_for_each_entry(cur, &fbdefio->pagereflist, list) { + if (cur->offset > pageref->offset) + break; + } + pos = &cur->list; + } + + list_add_tail(&pageref->list, pos); + +pageref_already_added: + return pageref; +} + +static void fb_deferred_io_pageref_put(struct fb_deferred_io_pageref *pageref, + struct fb_info *info) +{ + list_del_init(&pageref->list); +} + /* this is to find and return the vmalloc-ed fb pages */ static vm_fault_t fb_deferred_io_fault(struct vm_fault *vmf) { @@ -59,7 +113,7 @@ static vm_fault_t fb_deferred_io_fault(struct vm_fault *vmf) printk(KERN_ERR "no mapping available\n"); BUG_ON(!page->mapping); - page->index = vmf->pgoff; + page->index = vmf->pgoff; /* for page_mkclean() */ vmf->page = page; return 0; @@ -89,29 +143,30 @@ int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasy } EXPORT_SYMBOL_GPL(fb_deferred_io_fsync); -/* vm_ops->page_mkwrite handler */ -static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) +/* + * Adds a page to the dirty list. Call this from struct + * vm_operations_struct.page_mkwrite. + */ +static vm_fault_t fb_deferred_io_track_page(struct fb_info *info, unsigned long offset, + struct page *page) { - struct page *page = vmf->page; - struct fb_info *info = vmf->vma->vm_private_data; struct fb_deferred_io *fbdefio = info->fbdefio; - struct list_head *pos = &fbdefio->pagelist; - - /* this is a callback we get when userspace first tries to - write to the page. we schedule a workqueue. that workqueue - will eventually mkclean the touched pages and execute the - deferred framebuffer IO. then if userspace touches a page - again, we repeat the same scheme */ - - file_update_time(vmf->vma->vm_file); + struct fb_deferred_io_pageref *pageref; + vm_fault_t ret; /* protect against the workqueue changing the page list */ mutex_lock(&fbdefio->lock); /* first write in this cycle, notify the driver */ - if (fbdefio->first_io && list_empty(&fbdefio->pagelist)) + if (fbdefio->first_io && list_empty(&fbdefio->pagereflist)) fbdefio->first_io(info); + pageref = fb_deferred_io_pageref_get(info, offset, page); + if (WARN_ON_ONCE(!pageref)) { + ret = VM_FAULT_OOM; + goto err_mutex_unlock; + } + /* * We want the page to remain locked from ->page_mkwrite until * the PTE is marked dirty to avoid page_mkclean() being called @@ -120,47 +175,49 @@ static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) * Do this by locking the page here and informing the caller * about it with VM_FAULT_LOCKED. */ - lock_page(page); - - /* - * This check is to catch the case where a new process could start - * writing to the same page through a new PTE. This new access - * can cause a call to .page_mkwrite even if the original process' - * PTE is marked writable. - * - * TODO: The lru field is owned by the page cache; hence the name. - * We dequeue in fb_deferred_io_work() after flushing the - * page's content into video memory. Instead of lru, fbdefio - * should have it's own field. - */ - if (!list_empty(&page->lru)) - goto page_already_added; - - if (unlikely(fbdefio->sort_pagelist)) { - /* - * We loop through the pagelist before adding in order to - * keep the pagelist sorted. This has significant overhead - * of O(n^2) with n being the number of written pages. If - * possible, drivers should try to work with unsorted page - * lists instead. - */ - struct page *cur; + lock_page(pageref->page); - list_for_each_entry(cur, &fbdefio->pagelist, lru) { - if (cur->index > page->index) - break; - } - pos = &cur->lru; - } - - list_add_tail(&page->lru, pos); - -page_already_added: mutex_unlock(&fbdefio->lock); /* come back after delay to process the deferred IO */ schedule_delayed_work(&info->deferred_work, fbdefio->delay); return VM_FAULT_LOCKED; + +err_mutex_unlock: + mutex_unlock(&fbdefio->lock); + return ret; +} + +/* + * fb_deferred_io_page_mkwrite - Mark a page as written for deferred I/O + * @fb_info: The fbdev info structure + * @vmf: The VM fault + * + * This is a callback we get when userspace first tries to + * write to the page. We schedule a workqueue. That workqueue + * will eventually mkclean the touched pages and execute the + * deferred framebuffer IO. Then if userspace touches a page + * again, we repeat the same scheme. + * + * Returns: + * VM_FAULT_LOCKED on success, or a VM_FAULT error otherwise. + */ +static vm_fault_t fb_deferred_io_page_mkwrite(struct fb_info *info, struct vm_fault *vmf) +{ + unsigned long offset = vmf->address - vmf->vma->vm_start; + struct page *page = vmf->page; + + file_update_time(vmf->vma->vm_file); + + return fb_deferred_io_track_page(info, offset, page); +} + +/* vm_ops->page_mkwrite handler */ +static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) +{ + struct fb_info *info = vmf->vma->vm_private_data; + + return fb_deferred_io_page_mkwrite(info, vmf); } static const struct vm_operations_struct fb_deferred_io_vm_ops = { @@ -181,52 +238,70 @@ int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma) vma->vm_private_data = info; return 0; } +EXPORT_SYMBOL_GPL(fb_deferred_io_mmap); /* workqueue callback */ static void fb_deferred_io_work(struct work_struct *work) { - struct fb_info *info = container_of(work, struct fb_info, - deferred_work.work); - struct list_head *node, *next; - struct page *cur; + struct fb_info *info = container_of(work, struct fb_info, deferred_work.work); + struct fb_deferred_io_pageref *pageref, *next; struct fb_deferred_io *fbdefio = info->fbdefio; /* here we mkclean the pages, then do all deferred IO */ mutex_lock(&fbdefio->lock); - list_for_each_entry(cur, &fbdefio->pagelist, lru) { + list_for_each_entry(pageref, &fbdefio->pagereflist, list) { + struct page *cur = pageref->page; lock_page(cur); page_mkclean(cur); unlock_page(cur); } - /* driver's callback with pagelist */ - fbdefio->deferred_io(info, &fbdefio->pagelist); + /* driver's callback with pagereflist */ + fbdefio->deferred_io(info, &fbdefio->pagereflist); /* clear the list */ - list_for_each_safe(node, next, &fbdefio->pagelist) { - list_del_init(node); - } + list_for_each_entry_safe(pageref, next, &fbdefio->pagereflist, list) + fb_deferred_io_pageref_put(pageref, info); + mutex_unlock(&fbdefio->lock); } -void fb_deferred_io_init(struct fb_info *info) +int fb_deferred_io_init(struct fb_info *info) { struct fb_deferred_io *fbdefio = info->fbdefio; - struct page *page; - unsigned int i; + struct fb_deferred_io_pageref *pagerefs; + unsigned long npagerefs, i; + int ret; BUG_ON(!fbdefio); + + if (WARN_ON(!info->fix.smem_len)) + return -EINVAL; + mutex_init(&fbdefio->lock); INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work); - INIT_LIST_HEAD(&fbdefio->pagelist); + INIT_LIST_HEAD(&fbdefio->pagereflist); if (fbdefio->delay == 0) /* set a default of 1 s */ fbdefio->delay = HZ; - /* initialize all the page lists one time */ - for (i = 0; i < info->fix.smem_len; i += PAGE_SIZE) { - page = fb_deferred_io_page(info, i); - INIT_LIST_HEAD(&page->lru); + npagerefs = DIV_ROUND_UP(info->fix.smem_len, PAGE_SIZE); + + /* alloc a page ref for each page of the display memory */ + pagerefs = kvcalloc(npagerefs, sizeof(*pagerefs), GFP_KERNEL); + if (!pagerefs) { + ret = -ENOMEM; + goto err; } + for (i = 0; i < npagerefs; ++i) + INIT_LIST_HEAD(&pagerefs[i].list); + info->npagerefs = npagerefs; + info->pagerefs = pagerefs; + + return 0; + +err: + mutex_destroy(&fbdefio->lock); + return ret; } EXPORT_SYMBOL_GPL(fb_deferred_io_init); @@ -253,6 +328,7 @@ void fb_deferred_io_cleanup(struct fb_info *info) page->mapping = NULL; } + kvfree(info->pagerefs); mutex_destroy(&fbdefio->lock); } EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup); diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 84427470367b..b445a7a00def 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1334,7 +1334,6 @@ static int fb_mmap(struct file *file, struct vm_area_struct * vma) { 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 start; u32 len; @@ -1343,14 +1342,7 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) return -ENODEV; mutex_lock(&info->mm_lock); - fb_mmap_fn = 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) { + if (info->fbops->fb_mmap) { int res; /* @@ -1358,9 +1350,19 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) * SME protection is removed ahead of the call */ 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); 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 } /* diff --git a/drivers/video/fbdev/hecubafb.c b/drivers/video/fbdev/hecubafb.c index 00d77105161a..eb1eaadc1bbb 100644 --- a/drivers/video/fbdev/hecubafb.c +++ b/drivers/video/fbdev/hecubafb.c @@ -115,8 +115,7 @@ static void hecubafb_dpy_update(struct hecubafb_par *par) } /* this is called back from the deferred io workqueue */ -static void hecubafb_dpy_deferred_io(struct fb_info *info, - struct list_head *pagelist) +static void hecubafb_dpy_deferred_io(struct fb_info *info, struct list_head *pagereflist) { hecubafb_dpy_update(info->par); } @@ -204,6 +203,7 @@ static const struct fb_ops hecubafb_ops = { .fb_fillrect = hecubafb_fillrect, .fb_copyarea = hecubafb_copyarea, .fb_imageblit = hecubafb_imageblit, + .fb_mmap = fb_deferred_io_mmap, }; static struct fb_deferred_io hecubafb_defio = { diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index c8e0ea27caf1..8359a513b600 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -420,11 +420,10 @@ static void hvfb_docopy(struct hvfb_par *par, } /* Deferred IO callback */ -static void synthvid_deferred_io(struct fb_info *p, - struct list_head *pagelist) +static void synthvid_deferred_io(struct fb_info *p, struct list_head *pagereflist) { struct hvfb_par *par = p->par; - struct page *page; + struct fb_deferred_io_pageref *pageref; unsigned long start, end; int y1, y2, miny, maxy; @@ -437,8 +436,8 @@ static void synthvid_deferred_io(struct fb_info *p, * in synthvid_update function by clamping the y2 * value to yres. */ - list_for_each_entry(page, pagelist, lru) { - start = page->index << PAGE_SHIFT; + list_for_each_entry(pageref, pagereflist, list) { + start = pageref->offset; end = start + PAGE_SIZE - 1; y1 = start / p->fix.line_length; y2 = end / p->fix.line_length; @@ -909,6 +908,7 @@ static const struct fb_ops hvfb_ops = { .fb_copyarea = hvfb_cfb_copyarea, .fb_imageblit = hvfb_cfb_imageblit, .fb_blank = hvfb_blank, + .fb_mmap = fb_deferred_io_mmap, }; diff --git a/drivers/video/fbdev/metronomefb.c b/drivers/video/fbdev/metronomefb.c index af858dd23ea6..9fd4bb85d735 100644 --- a/drivers/video/fbdev/metronomefb.c +++ b/drivers/video/fbdev/metronomefb.c @@ -465,20 +465,18 @@ static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index) } /* this is called back from the deferred io workqueue */ -static void metronomefb_dpy_deferred_io(struct fb_info *info, - struct list_head *pagelist) +static void metronomefb_dpy_deferred_io(struct fb_info *info, struct list_head *pagereflist) { u16 cksum; - struct page *cur; - struct fb_deferred_io *fbdefio = info->fbdefio; + struct fb_deferred_io_pageref *pageref; struct metronomefb_par *par = info->par; /* walk the written page list and swizzle the data */ - list_for_each_entry(cur, &fbdefio->pagelist, lru) { - cksum = metronomefb_dpy_update_page(par, - (cur->index << PAGE_SHIFT)); - par->metromem_img_csum -= par->csum_table[cur->index]; - par->csum_table[cur->index] = cksum; + list_for_each_entry(pageref, pagereflist, list) { + unsigned long pgoffset = pageref->offset >> PAGE_SHIFT; + cksum = metronomefb_dpy_update_page(par, pageref->offset); + par->metromem_img_csum -= par->csum_table[pgoffset]; + par->csum_table[pgoffset] = cksum; par->metromem_img_csum += cksum; } @@ -564,12 +562,13 @@ static const struct fb_ops metronomefb_ops = { .fb_fillrect = metronomefb_fillrect, .fb_copyarea = metronomefb_copyarea, .fb_imageblit = metronomefb_imageblit, + .fb_mmap = fb_deferred_io_mmap, }; static struct fb_deferred_io metronomefb_defio = { - .delay = HZ, - .sort_pagelist = true, - .deferred_io = metronomefb_dpy_deferred_io, + .delay = HZ, + .sort_pagereflist = true, + .deferred_io = metronomefb_dpy_deferred_io, }; static int metronomefb_probe(struct platform_device *dev) diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c index 9a4417430b4e..6d00893d41f4 100644 --- a/drivers/video/fbdev/sh_mobile_lcdcfb.c +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c @@ -435,24 +435,23 @@ static struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { .read_data = lcdc_sys_read_data, }; -static int sh_mobile_lcdc_sginit(struct fb_info *info, - struct list_head *pagelist) +static int sh_mobile_lcdc_sginit(struct fb_info *info, struct list_head *pagereflist) { struct sh_mobile_lcdc_chan *ch = info->par; unsigned int nr_pages_max = ch->fb_size >> PAGE_SHIFT; - struct page *page; + struct fb_deferred_io_pageref *pageref; int nr_pages = 0; sg_init_table(ch->sglist, nr_pages_max); - list_for_each_entry(page, pagelist, lru) - sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0); + list_for_each_entry(pageref, pagereflist, list) { + sg_set_page(&ch->sglist[nr_pages++], pageref->page, PAGE_SIZE, 0); + } return nr_pages; } -static void sh_mobile_lcdc_deferred_io(struct fb_info *info, - struct list_head *pagelist) +static void sh_mobile_lcdc_deferred_io(struct fb_info *info, struct list_head *pagereflist) { struct sh_mobile_lcdc_chan *ch = info->par; const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg; @@ -461,7 +460,7 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info, sh_mobile_lcdc_clk_on(ch->lcdc); /* - * It's possible to get here without anything on the pagelist via + * It's possible to get here without anything on the pagereflist via * sh_mobile_lcdc_deferred_io_touch() or via a userspace fsync() * invocation. In the former case, the acceleration routines are * stepped in to when using the framebuffer console causing the @@ -471,12 +470,12 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info, * acceleration routines have their own methods for writing in * that still need to be updated. * - * The fsync() and empty pagelist case could be optimized for, + * The fsync() and empty pagereflist case could be optimized for, * but we don't bother, as any application exhibiting such * behaviour is fundamentally broken anyways. */ - if (!list_empty(pagelist)) { - unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagelist); + if (!list_empty(pagereflist)) { + unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagereflist); /* trigger panel update */ dma_map_sg(ch->lcdc->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); @@ -1480,6 +1479,9 @@ sh_mobile_lcdc_overlay_mmap(struct fb_info *info, struct vm_area_struct *vma) { 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, ovl->dma_handle, ovl->fb_size); } @@ -1954,6 +1956,9 @@ sh_mobile_lcdc_mmap(struct fb_info *info, struct vm_area_struct *vma) { 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, ch->dma_handle, ch->fb_size); } diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c index 28768c272b73..d7aa5511c361 100644 --- a/drivers/video/fbdev/smscufx.c +++ b/drivers/video/fbdev/smscufx.c @@ -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 page, pos; + if (info->fbdefio) + return fb_deferred_io_mmap(info, vma); + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; if (size > info->fix.smem_len) @@ -952,12 +955,10 @@ static void ufx_ops_fillrect(struct fb_info *info, * Touching ANY framebuffer memory that triggers a page fault * in fb_defio will cause a deadlock, when it also tries to * grab the same mutex. */ -static void ufx_dpy_deferred_io(struct fb_info *info, - struct list_head *pagelist) +static void ufx_dpy_deferred_io(struct fb_info *info, struct list_head *pagereflist) { - struct page *cur; - struct fb_deferred_io *fbdefio = info->fbdefio; struct ufx_data *dev = info->par; + struct fb_deferred_io_pageref *pageref; if (!fb_defio) return; @@ -966,12 +967,12 @@ static void ufx_dpy_deferred_io(struct fb_info *info, return; /* walk the written page list and render each to device */ - list_for_each_entry(cur, &fbdefio->pagelist, lru) { + list_for_each_entry(pageref, pagereflist, list) { /* create a rectangle of full screen width that encloses the * entire dirty framebuffer page */ const int x = 0; const int width = dev->info->var.xres; - const int y = (cur->index << PAGE_SHIFT) / (width * 2); + const int y = pageref->offset / (width * 2); int height = (PAGE_SIZE / (width * 2)) + 1; height = min(height, (int)(dev->info->var.yres - y)); diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index c6d5df31111d..5c765655d000 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -368,10 +368,10 @@ static const struct fb_ops ssd1307fb_ops = { .fb_fillrect = ssd1307fb_fillrect, .fb_copyarea = ssd1307fb_copyarea, .fb_imageblit = ssd1307fb_imageblit, + .fb_mmap = fb_deferred_io_mmap, }; -static void ssd1307fb_deferred_io(struct fb_info *info, - struct list_head *pagelist) +static void ssd1307fb_deferred_io(struct fb_info *info, struct list_head *pagereflist) { ssd1307fb_update_display(info->par); } diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index d280733f283b..c863244ef12c 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -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 page, pos; + if (info->fbdefio) + return fb_deferred_io_mmap(info, vma); + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; if (size > info->fix.smem_len) @@ -778,11 +781,9 @@ static void dlfb_ops_fillrect(struct fb_info *info, * in fb_defio will cause a deadlock, when it also tries to * grab the same mutex. */ -static void dlfb_dpy_deferred_io(struct fb_info *info, - struct list_head *pagelist) +static void dlfb_dpy_deferred_io(struct fb_info *info, struct list_head *pagereflist) { - struct page *cur; - struct fb_deferred_io *fbdefio = info->fbdefio; + struct fb_deferred_io_pageref *pageref; struct dlfb_data *dlfb = info->par; struct urb *urb; char *cmd; @@ -808,11 +809,10 @@ static void dlfb_dpy_deferred_io(struct fb_info *info, cmd = urb->transfer_buffer; /* walk the written page list and render each to device */ - list_for_each_entry(cur, &fbdefio->pagelist, lru) { - + list_for_each_entry(pageref, pagereflist, list) { if (dlfb_render_hline(dlfb, &urb, (char *) info->fix.smem_start, - &cmd, cur->index << PAGE_SHIFT, - PAGE_SIZE, &bytes_identical, &bytes_sent)) + &cmd, pageref->offset, PAGE_SIZE, + &bytes_identical, &bytes_sent)) goto error; bytes_rendered += PAGE_SIZE; } @@ -980,7 +980,7 @@ static int dlfb_ops_open(struct fb_info *info, int user) if (fbdefio) { fbdefio->delay = DL_DEFIO_WRITE_DELAY; - fbdefio->sort_pagelist = true; + fbdefio->sort_pagereflist = true; fbdefio->deferred_io = dlfb_dpy_deferred_io; } diff --git a/drivers/video/fbdev/xen-fbfront.c b/drivers/video/fbdev/xen-fbfront.c index 6826f986da43..3bed357a9870 100644 --- a/drivers/video/fbdev/xen-fbfront.c +++ b/drivers/video/fbdev/xen-fbfront.c @@ -181,18 +181,17 @@ static void xenfb_refresh(struct xenfb_info *info, xenfb_do_update(info, x1, y1, x2 - x1 + 1, y2 - y1 + 1); } -static void xenfb_deferred_io(struct fb_info *fb_info, - struct list_head *pagelist) +static void xenfb_deferred_io(struct fb_info *fb_info, struct list_head *pagereflist) { struct xenfb_info *info = fb_info->par; - struct page *page; + struct fb_deferred_io_pageref *pageref; unsigned long beg, end; int y1, y2, miny, maxy; miny = INT_MAX; maxy = 0; - list_for_each_entry(page, pagelist, lru) { - beg = page->index << PAGE_SHIFT; + list_for_each_entry(pageref, pagereflist, list) { + beg = pageref->offset; end = beg + PAGE_SIZE - 1; y1 = beg / fb_info->fix.line_length; y2 = end / fb_info->fix.line_length; @@ -338,6 +337,7 @@ static const struct fb_ops xenfb_fb_ops = { .fb_imageblit = xenfb_imageblit, .fb_check_var = xenfb_check_var, .fb_set_par = xenfb_set_par, + .fb_mmap = fb_deferred_io_mmap, }; static irqreturn_t xenfb_event_handler(int rq, void *dev_id) |