From 27599aacbaefcbf2af7b06b0029459bbf682000d Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 25 Jan 2022 10:12:18 +0100 Subject: fbdev: Hot-unplug firmware fb devices on forced removal Hot-unplug all firmware-framebuffer devices as part of removing them via remove_conflicting_framebuffers() et al. Releases all memory regions to be acquired by native drivers. Firmware, such as EFI, install a framebuffer while posting the computer. After removing the firmware-framebuffer device from fbdev, a native driver takes over the hardware and the firmware framebuffer becomes invalid. Firmware-framebuffer drivers, specifically simplefb, don't release their device from Linux' device hierarchy. It still owns the firmware framebuffer and blocks the native drivers from loading. This has been observed in the vmwgfx driver. [1] Initiating a device removal (i.e., hot unplug) as part of remove_conflicting_framebuffers() removes the underlying device and returns the memory range to the system. [1] https://lore.kernel.org/dri-devel/20220117180359.18114-1-zack@kde.org/ v2: * rename variable 'dev' to 'device' (Javier) Signed-off-by: Thomas Zimmermann Reported-by: Zack Rusin Reviewed-by: Javier Martinez Canillas Reviewed-by: Zack Rusin Reviewed-by: Hans de Goede CC: stable@vger.kernel.org # v5.11+ Link: https://patchwork.freedesktop.org/patch/msgid/20220125091222.21457-2-tzimmermann@suse.de --- include/linux/fb.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux/fb.h') diff --git a/include/linux/fb.h b/include/linux/fb.h index 6f3db99ab990..ac294fc4c07b 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -502,6 +502,7 @@ struct fb_info { } *apertures; bool skip_vt_switch; /* no VT switch on suspend/resume required */ + bool forced_out; /* set when being removed by another driver */ }; static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { -- cgit v1.2.3 From 8c30e2d81bfddc5ab9f6b04db1c0f7d6ca7bdf46 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 11 Feb 2022 10:46:40 +0100 Subject: fbdev: Don't sort deferred-I/O pages by default Fbdev's deferred I/O sorts all dirty pages by default, which incurs a significant overhead. Make the sorting step optional and update the few drivers that require it. Use a FIFO list by default. Most fbdev drivers with deferred I/O build a bounding rectangle around the dirty pages or simply flush the whole screen. The only two affected DRM drivers, generic fbdev and vmwgfx, both use a bounding rectangle. In those cases, the exact order of the pages doesn't matter. The other drivers look at the page index or handle pages one-by-one. The patch sets the sort_pagelist flag for those, even though some of them would probably work correctly without sorting. Driver maintainers should update their driver accordingly. Sorting pages by memory offset for deferred I/O performs an implicit bubble-sort step on the list of dirty pages. The algorithm goes through the list of dirty pages and inserts each new page according to its index field. Even worse, list traversal always starts at the first entry. As video memory is most likely updated scanline by scanline, the algorithm traverses through the complete list for each updated page. For example, with 1024x768x32bpp each page covers exactly one scanline. Writing a single screen update from top to bottom requires updating 768 pages. With an average list length of 384 entries, a screen update creates (768 * 384 =) 294912 compare operation. Fix this by making the sorting step opt-in and update the few drivers that require it. All other drivers work with unsorted page lists. Pages are appended to the list. Therefore, in the common case of writing the framebuffer top to bottom, pages are still sorted by offset, which may have a positive effect on performance. Playing a video [1] in mplayer's benchmark mode shows the difference (i7-4790, FullHD, simpledrm, kernel with debugging). mplayer -benchmark -nosound -vo fbdev ./big_buck_bunny_720p_stereo.ogg With sorted page lists: BENCHMARKs: VC: 32.960s VO: 73.068s A: 0.000s Sys: 2.413s = 108.441s BENCHMARK%: VC: 30.3947% VO: 67.3802% A: 0.0000% Sys: 2.2251% = 100.0000% With unsorted page lists: BENCHMARKs: VC: 31.005s VO: 42.889s A: 0.000s Sys: 2.256s = 76.150s BENCHMARK%: VC: 40.7156% VO: 56.3219% A: 0.0000% Sys: 2.9625% = 100.0000% VC shows the overhead of video decoding, VO shows the overhead of the video output. Using unsorted page lists reduces the benchmark's run time by ~32s/~25%. v2: * Make sorted pagelists the special case (Sam) * Comment on drivers' use of pagelist (Sam) * Warn about the overhead in comment Signed-off-by: Thomas Zimmermann Acked-by: Sam Ravnborg Acked-by: Andy Shevchenko Link: https://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_720p_stereo.ogg # [1] Link: https://patchwork.freedesktop.org/patch/msgid/20220211094640.21632-3-tzimmermann@suse.de --- drivers/staging/fbtft/fbtft-core.c | 1 + drivers/video/fbdev/broadsheetfb.c | 1 + drivers/video/fbdev/core/fb_defio.c | 24 +++++++++++++++++------- drivers/video/fbdev/metronomefb.c | 1 + drivers/video/fbdev/udlfb.c | 1 + include/linux/fb.h | 1 + 6 files changed, 22 insertions(+), 7 deletions(-) (limited to 'include/linux/fb.h') diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index f2684d2d6851..4a35347b3020 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -654,6 +654,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, fbops->fb_blank = fbtft_fb_blank; fbdefio->delay = HZ / fps; + fbdefio->sort_pagelist = true; fbdefio->deferred_io = fbtft_deferred_io; fb_deferred_io_init(info); diff --git a/drivers/video/fbdev/broadsheetfb.c b/drivers/video/fbdev/broadsheetfb.c index fd66f4d4a621..b9054f658838 100644 --- a/drivers/video/fbdev/broadsheetfb.c +++ b/drivers/video/fbdev/broadsheetfb.c @@ -1059,6 +1059,7 @@ static const struct fb_ops broadsheetfb_ops = { static struct fb_deferred_io broadsheetfb_defio = { .delay = HZ/4, + .sort_pagelist = true, .deferred_io = broadsheetfb_dpy_deferred_io, }; diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c index 169a81c8172b..98b0f23bf5e2 100644 --- a/drivers/video/fbdev/core/fb_defio.c +++ b/drivers/video/fbdev/core/fb_defio.c @@ -96,7 +96,7 @@ static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) struct page *page = vmf->page; struct fb_info *info = vmf->vma->vm_private_data; struct fb_deferred_io *fbdefio = info->fbdefio; - struct page *cur; + 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 @@ -137,14 +137,24 @@ static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) if (!list_empty(&page->lru)) goto page_already_added; - /* we loop through the pagelist before adding in order - to keep the pagelist sorted */ - list_for_each_entry(cur, &fbdefio->pagelist, lru) { - if (cur->index > page->index) - break; + 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; + + list_for_each_entry(cur, &fbdefio->pagelist, lru) { + if (cur->index > page->index) + break; + } + pos = &cur->lru; } - list_add_tail(&page->lru, &cur->lru); + list_add_tail(&page->lru, pos); page_already_added: mutex_unlock(&fbdefio->lock); diff --git a/drivers/video/fbdev/metronomefb.c b/drivers/video/fbdev/metronomefb.c index 952826557a0c..af858dd23ea6 100644 --- a/drivers/video/fbdev/metronomefb.c +++ b/drivers/video/fbdev/metronomefb.c @@ -568,6 +568,7 @@ static const struct fb_ops metronomefb_ops = { static struct fb_deferred_io metronomefb_defio = { .delay = HZ, + .sort_pagelist = true, .deferred_io = metronomefb_dpy_deferred_io, }; diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index b9cdd02c1000..184bb8433b78 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -980,6 +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->deferred_io = dlfb_dpy_deferred_io; } diff --git a/include/linux/fb.h b/include/linux/fb.h index 9a14f3f8a329..39baa9a70779 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -204,6 +204,7 @@ struct fb_pixmap { struct fb_deferred_io { /* delay between mkwrite and deferred handler */ unsigned long delay; + bool sort_pagelist; /* sort pagelist by offset */ struct mutex lock; /* mutex that protects the page list */ struct list_head pagelist; /* list of touched pages */ /* callback */ -- cgit v1.2.3 From 6b2060cf9138a2cd5f3468a949d3869abed049ef Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 5 Apr 2022 23:03:26 +0200 Subject: fb: Delete fb_info->queue It was only used by fbcon, and that now switched to its own, private work. Acked-by: Sam Ravnborg Acked-by: Thomas Zimmermann Signed-off-by: Daniel Vetter Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Link: https://patchwork.freedesktop.org/patch/msgid/20220405210335.3434130-9-daniel.vetter@ffwll.ch --- include/linux/fb.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux/fb.h') diff --git a/include/linux/fb.h b/include/linux/fb.h index 9a77ab615c36..f95da1af9ff6 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -450,7 +450,6 @@ struct fb_info { struct fb_var_screeninfo var; /* Current var */ struct fb_fix_screeninfo fix; /* Current fix */ struct fb_monspecs monspecs; /* Current Monitor specs */ - struct work_struct queue; /* Framebuffer event queue */ struct fb_pixmap pixmap; /* Image hardware mapper */ struct fb_pixmap sprite; /* Cursor hardware mapper */ struct fb_cmap cmap; /* Current cmap */ -- cgit v1.2.3 From 56c134f7f1b58be08bdb0ca8372474a4a5165f31 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 29 Apr 2022 12:08:31 +0200 Subject: fbdev: Track deferred-I/O pages in pageref struct Store the per-page state for fbdev's deferred I/O in struct fb_deferred_io_pageref. Maintain a list of pagerefs for the pages that have to be written back to video memory. Update all affected drivers. As with pages before, fbdev acquires a pageref when an mmaped page of the framebuffer is being written to. It holds the pageref in a list of all currently written pagerefs until it flushes the written pages to video memory. Writeback occurs periodically. After writeback fbdev releases all pagerefs and builds up a new dirty list until the next writeback occurs. Using pagerefs has a number of benefits. For pages of the framebuffer, the deferred I/O code used struct page.lru as an entry into the list of dirty pages. The lru field is owned by the page cache, which makes deferred I/O incompatible with some memory pages (e.g., most notably DRM's GEM SHMEM allocator). struct fb_deferred_io_pageref now provides an entry into a list of dirty framebuffer pages, freeing lru for use with the page cache. Drivers also assumed that struct page.index is the page offset into the framebuffer. This is not true for DRM buffers, which are located at various offset within a mapped area. struct fb_deferred_io_pageref explicitly stores an offset into the framebuffer. struct page.index is now only the page offset into the mapped area. These changes will allow DRM to use fbdev deferred I/O without an intermediate shadow buffer. v3: * use pageref->offset for sorting * fix grammar in comment v2: * minor fixes in commit message Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20220429100834.18898-3-tzimmermann@suse.de --- drivers/gpu/drm/drm_fb_helper.c | 6 +- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 5 +- drivers/staging/fbtft/fbtft-core.c | 5 +- drivers/video/fbdev/broadsheetfb.c | 5 +- drivers/video/fbdev/core/fb_defio.c | 156 ++++++++++++++++++++++----------- drivers/video/fbdev/hyperv_fb.c | 5 +- drivers/video/fbdev/metronomefb.c | 5 +- drivers/video/fbdev/sh_mobile_lcdcfb.c | 6 +- drivers/video/fbdev/smscufx.c | 5 +- drivers/video/fbdev/udlfb.c | 5 +- drivers/video/fbdev/xen-fbfront.c | 5 +- include/linux/fb.h | 11 ++- 12 files changed, 145 insertions(+), 74 deletions(-) (limited to 'include/linux/fb.h') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index d06ce0e92d66..dd1d72d58b35 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -717,13 +717,13 @@ void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagelist) { unsigned long start, end, min, max; - struct page *page; + struct fb_deferred_io_pageref *pageref; struct drm_rect damage_area; min = ULONG_MAX; max = 0; - list_for_each_entry(page, pagelist, lru) { - start = page->index << PAGE_SHIFT; + list_for_each_entry(pageref, pagelist, list) { + start = pageref->offset; end = start + PAGE_SIZE; min = min(min, start); max = max(max, end); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 02a4a4fa3da3..db02e17e12b6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -322,12 +322,13 @@ static void vmw_deferred_io(struct fb_info *info, struct vmw_fb_par *par = info->par; unsigned long start, end, min, max; unsigned long flags; - struct page *page; + struct fb_deferred_io_pageref *pageref; int y1, y2; min = ULONG_MAX; max = 0; - list_for_each_entry(page, pagelist, lru) { + list_for_each_entry(pageref, pagelist, list) { + struct page *page = pageref->page; start = page->index << PAGE_SHIFT; end = start + PAGE_SIZE - 1; min = min(min, start); diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index d4e14f7c9d57..e9662822e1ef 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -326,7 +326,7 @@ static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist) { struct fbtft_par *par = info->par; unsigned int dirty_lines_start, dirty_lines_end; - struct page *page; + struct fb_deferred_io_pageref *pageref; unsigned long index; unsigned int y_low = 0, y_high = 0; int count = 0; @@ -340,7 +340,8 @@ static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist) spin_unlock(&par->dirty_lock); /* Mark display lines as dirty */ - list_for_each_entry(page, pagelist, lru) { + list_for_each_entry(pageref, pagelist, list) { + struct page *page = pageref->page; count++; index = page->index << PAGE_SHIFT; y_low = index / info->fix.line_length; diff --git a/drivers/video/fbdev/broadsheetfb.c b/drivers/video/fbdev/broadsheetfb.c index 528bc0902338..6afc6ef4cb5e 100644 --- a/drivers/video/fbdev/broadsheetfb.c +++ b/drivers/video/fbdev/broadsheetfb.c @@ -934,7 +934,7 @@ static void broadsheetfb_dpy_deferred_io(struct fb_info *info, { u16 y1 = 0, h = 0; int prev_index = -1; - struct page *cur; + struct fb_deferred_io_pageref *pageref; struct fb_deferred_io *fbdefio = info->fbdefio; int h_inc; u16 yres = info->var.yres; @@ -944,7 +944,8 @@ 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) { + list_for_each_entry(pageref, &fbdefio->pagelist, list) { + struct page *cur = pageref->page; if (prev_index < 0) { /* just starting so assign first page */ y1 = (cur->index << PAGE_SHIFT) / xres; diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c index 6924d489a289..1bdef5c241f7 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->pagelist; + 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_pagelist)) { + /* + * 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, &info->fbdefio->pagelist, 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; @@ -95,7 +149,11 @@ static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) 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; + struct fb_deferred_io_pageref *pageref; + unsigned long offset; + vm_fault_t ret; + + offset = (vmf->address - vmf->vma->vm_start); /* this is a callback we get when userspace first tries to write to the page. we schedule a workqueue. that workqueue @@ -112,6 +170,12 @@ static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) if (fbdefio->first_io && list_empty(&fbdefio->pagelist)) 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 +184,17 @@ 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; - - list_for_each_entry(cur, &fbdefio->pagelist, lru) { - if (cur->index > page->index) - break; - } - pos = &cur->lru; - } - - list_add_tail(&page->lru, pos); + lock_page(pageref->page); -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; } static const struct vm_operations_struct fb_deferred_io_vm_ops = { @@ -186,15 +220,14 @@ 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->pagelist, list) { + struct page *cur = pageref->page; lock_page(cur); page_mkclean(cur); unlock_page(cur); @@ -204,30 +237,48 @@ static void fb_deferred_io_work(struct work_struct *work) fbdefio->deferred_io(info, &fbdefio->pagelist); /* clear the list */ - list_for_each_safe(node, next, &fbdefio->pagelist) { - list_del_init(node); - } + list_for_each_entry_safe(pageref, next, &fbdefio->pagelist, 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); 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); @@ -254,6 +305,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/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index d7f6abf827b9..51eb57ea68f7 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -424,7 +424,7 @@ static void synthvid_deferred_io(struct fb_info *p, struct list_head *pagelist) { 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,7 +437,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) { + list_for_each_entry(pageref, pagelist, list) { + struct page *page = pageref->page; start = page->index << PAGE_SHIFT; end = start + PAGE_SIZE - 1; y1 = start / p->fix.line_length; diff --git a/drivers/video/fbdev/metronomefb.c b/drivers/video/fbdev/metronomefb.c index 2541f2fe065b..8352fa3f4cef 100644 --- a/drivers/video/fbdev/metronomefb.c +++ b/drivers/video/fbdev/metronomefb.c @@ -469,12 +469,13 @@ static void metronomefb_dpy_deferred_io(struct fb_info *info, struct list_head *pagelist) { u16 cksum; - struct page *cur; + struct fb_deferred_io_pageref *pageref; struct fb_deferred_io *fbdefio = info->fbdefio; struct metronomefb_par *par = info->par; /* walk the written page list and swizzle the data */ - list_for_each_entry(cur, &fbdefio->pagelist, lru) { + list_for_each_entry(pageref, &fbdefio->pagelist, list) { + struct page *cur = pageref->page; cksum = metronomefb_dpy_update_page(par, (cur->index << PAGE_SHIFT)); par->metromem_img_csum -= par->csum_table[cur->index]; diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c index ad034eb0e7a0..aea0660ba0c3 100644 --- a/drivers/video/fbdev/sh_mobile_lcdcfb.c +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c @@ -440,13 +440,15 @@ static int sh_mobile_lcdc_sginit(struct fb_info *info, { 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) + list_for_each_entry(pageref, pagelist, list) { + struct page *page = pageref->page; sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0); + } return nr_pages; } diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c index 9383f8d0914c..eb108f56ea04 100644 --- a/drivers/video/fbdev/smscufx.c +++ b/drivers/video/fbdev/smscufx.c @@ -958,7 +958,7 @@ static void ufx_ops_fillrect(struct fb_info *info, static void ufx_dpy_deferred_io(struct fb_info *info, struct list_head *pagelist) { - struct page *cur; + struct fb_deferred_io_pageref *pageref; struct fb_deferred_io *fbdefio = info->fbdefio; struct ufx_data *dev = info->par; @@ -969,9 +969,10 @@ 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, &fbdefio->pagelist, list) { /* create a rectangle of full screen width that encloses the * entire dirty framebuffer page */ + struct page *cur = pageref->page; const int x = 0; const int width = dev->info->var.xres; const int y = (cur->index << PAGE_SHIFT) / (width * 2); diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index 179b30ba09f5..f70b9cc8e855 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -784,7 +784,7 @@ static void dlfb_ops_fillrect(struct fb_info *info, static void dlfb_dpy_deferred_io(struct fb_info *info, struct list_head *pagelist) { - struct page *cur; + struct fb_deferred_io_pageref *pageref; struct fb_deferred_io *fbdefio = info->fbdefio; struct dlfb_data *dlfb = info->par; struct urb *urb; @@ -811,7 +811,8 @@ 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, &fbdefio->pagelist, list) { + struct page *cur = pageref->page; if (dlfb_render_hline(dlfb, &urb, (char *) info->fix.smem_start, &cmd, cur->index << PAGE_SHIFT, diff --git a/drivers/video/fbdev/xen-fbfront.c b/drivers/video/fbdev/xen-fbfront.c index 6c8846eba2fb..608fcde767d3 100644 --- a/drivers/video/fbdev/xen-fbfront.c +++ b/drivers/video/fbdev/xen-fbfront.c @@ -185,13 +185,14 @@ static void xenfb_deferred_io(struct fb_info *fb_info, struct list_head *pagelist) { 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) { + list_for_each_entry(pageref, pagelist, list) { + struct page *page = pageref->page; beg = page->index << PAGE_SHIFT; end = beg + PAGE_SIZE - 1; y1 = beg / fb_info->fix.line_length; diff --git a/include/linux/fb.h b/include/linux/fb.h index f95da1af9ff6..a332590c0fae 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -201,6 +201,13 @@ struct fb_pixmap { }; #ifdef CONFIG_FB_DEFERRED_IO +struct fb_deferred_io_pageref { + struct page *page; + unsigned long offset; + /* private */ + struct list_head list; +}; + struct fb_deferred_io { /* delay between mkwrite and deferred handler */ unsigned long delay; @@ -468,6 +475,8 @@ struct fb_info { #endif #ifdef CONFIG_FB_DEFERRED_IO struct delayed_work deferred_work; + unsigned long npagerefs; + struct fb_deferred_io_pageref *pagerefs; struct fb_deferred_io *fbdefio; #endif @@ -661,7 +670,7 @@ static inline void __fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, /* drivers/video/fb_defio.c */ int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma); -extern void fb_deferred_io_init(struct fb_info *info); +extern int fb_deferred_io_init(struct fb_info *info); extern void fb_deferred_io_open(struct fb_info *info, struct inode *inode, struct file *file); -- cgit v1.2.3 From e80eec1b871a2acb8f5c92db4c237e9ae6dd322b Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 29 Apr 2022 12:08:33 +0200 Subject: fbdev: Rename pagelist to pagereflist for deferred I/O Rename various instances of pagelist to pagereflist. The list now stores pageref structures, so the new name is more appropriate. In their write-back helpers, several fbdev drivers refer to the pageref list in struct fb_deferred_io instead of using the one supplied as argument to the function. Convert them over to the supplied one. It's the same instance, so no change of behavior occurs. v4: * fix commit message (Javier) Suggested-by: Sam Ravnborg Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20220429100834.18898-5-tzimmermann@suse.de --- drivers/gpu/drm/drm_fb_helper.c | 7 +++---- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 5 ++--- drivers/hid/hid-picolcd_fb.c | 2 +- drivers/staging/fbtft/fbtft-core.c | 10 +++++----- drivers/video/fbdev/broadsheetfb.c | 12 +++++------- drivers/video/fbdev/core/fb_defio.c | 18 +++++++++--------- drivers/video/fbdev/hecubafb.c | 3 +-- drivers/video/fbdev/hyperv_fb.c | 5 ++--- drivers/video/fbdev/metronomefb.c | 12 +++++------- drivers/video/fbdev/sh_mobile_lcdcfb.c | 16 +++++++--------- drivers/video/fbdev/smscufx.c | 8 +++----- drivers/video/fbdev/ssd1307fb.c | 3 +-- drivers/video/fbdev/udlfb.c | 8 +++----- drivers/video/fbdev/xen-fbfront.c | 5 ++--- include/drm/drm_fb_helper.h | 3 +-- include/linux/fb.h | 6 +++--- 16 files changed, 53 insertions(+), 70 deletions(-) (limited to 'include/linux/fb.h') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index dd1d72d58b35..5ad2b6a2778c 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -708,13 +708,12 @@ static void drm_fb_helper_memory_range_to_clip(struct fb_info *info, off_t off, /** * drm_fb_helper_deferred_io() - fbdev deferred_io callback function * @info: fb_info struct pointer - * @pagelist: list of mmap framebuffer pages that have to be flushed + * @pagereflist: list of mmap framebuffer pages that have to be flushed * * 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) +void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagereflist) { unsigned long start, end, min, max; struct fb_deferred_io_pageref *pageref; @@ -722,7 +721,7 @@ void drm_fb_helper_deferred_io(struct fb_info *info, min = ULONG_MAX; max = 0; - list_for_each_entry(pageref, pagelist, list) { + list_for_each_entry(pageref, pagereflist, list) { start = pageref->offset; end = start + PAGE_SIZE; min = min(min, start); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index db02e17e12b6..9a3dc5c4eec8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -316,8 +316,7 @@ static int vmw_fb_pan_display(struct fb_var_screeninfo *var, return 0; } -static void vmw_deferred_io(struct fb_info *info, - struct list_head *pagelist) +static void vmw_deferred_io(struct fb_info *info, struct list_head *pagereflist) { struct vmw_fb_par *par = info->par; unsigned long start, end, min, max; @@ -327,7 +326,7 @@ static void vmw_deferred_io(struct fb_info *info, min = ULONG_MAX; max = 0; - list_for_each_entry(pageref, pagelist, list) { + list_for_each_entry(pageref, pagereflist, list) { struct page *page = pageref->page; start = page->index << PAGE_SHIFT; end = start + PAGE_SIZE - 1; diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c index 78515e6bacf0..de61c08fabea 100644 --- a/drivers/hid/hid-picolcd_fb.c +++ b/drivers/hid/hid-picolcd_fb.c @@ -433,7 +433,7 @@ static const struct fb_ops picolcdfb_ops = { /* Callback from deferred IO workqueue */ -static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagelist) +static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagereflist) { picolcd_fb_update(info); } diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index e9662822e1ef..8774bffe94cc 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -322,7 +322,7 @@ static void fbtft_mkdirty(struct fb_info *info, int y, int height) schedule_delayed_work(&info->deferred_work, fbdefio->delay); } -static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist) +static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagereflist) { struct fbtft_par *par = info->par; unsigned int dirty_lines_start, dirty_lines_end; @@ -340,7 +340,7 @@ static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist) spin_unlock(&par->dirty_lock); /* Mark display lines as dirty */ - list_for_each_entry(pageref, pagelist, list) { + list_for_each_entry(pageref, pagereflist, list) { struct page *page = pageref->page; count++; index = page->index << PAGE_SHIFT; @@ -655,9 +655,9 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, fbops->fb_blank = fbtft_fb_blank; fbops->fb_mmap = fb_deferred_io_mmap; - fbdefio->delay = HZ / fps; - fbdefio->sort_pagelist = true; - fbdefio->deferred_io = fbtft_deferred_io; + fbdefio->delay = HZ / fps; + fbdefio->sort_pagereflist = true; + fbdefio->deferred_io = fbtft_deferred_io; fb_deferred_io_init(info); snprintf(info->fix.id, sizeof(info->fix.id), "%s", dev->driver->name); diff --git a/drivers/video/fbdev/broadsheetfb.c b/drivers/video/fbdev/broadsheetfb.c index 6afc6ef4cb5e..883a3ac03189 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 fb_deferred_io_pageref *pageref; - struct fb_deferred_io *fbdefio = info->fbdefio; int h_inc; u16 yres = info->var.yres; u16 xres = info->var.xres; @@ -944,7 +942,7 @@ 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(pageref, &fbdefio->pagelist, list) { + list_for_each_entry(pageref, pagereflist, list) { struct page *cur = pageref->page; if (prev_index < 0) { /* just starting so assign first page */ @@ -1060,9 +1058,9 @@ static const struct fb_ops broadsheetfb_ops = { }; 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 3f9bb4725119..c730253ab85c 100644 --- a/drivers/video/fbdev/core/fb_defio.c +++ b/drivers/video/fbdev/core/fb_defio.c @@ -41,7 +41,7 @@ static struct fb_deferred_io_pageref *fb_deferred_io_pageref_get(struct fb_info struct page *page) { struct fb_deferred_io *fbdefio = info->fbdefio; - struct list_head *pos = &fbdefio->pagelist; + struct list_head *pos = &fbdefio->pagereflist; unsigned long pgoff = offset >> PAGE_SHIFT; struct fb_deferred_io_pageref *pageref, *cur; @@ -63,7 +63,7 @@ static struct fb_deferred_io_pageref *fb_deferred_io_pageref_get(struct fb_info pageref->page = page; pageref->offset = pgoff << PAGE_SHIFT; - if (unlikely(fbdefio->sort_pagelist)) { + if (unlikely(fbdefio->sort_pagereflist)) { /* * We loop through the list of pagerefs before adding in * order to keep the pagerefs sorted. This has significant @@ -71,7 +71,7 @@ static struct fb_deferred_io_pageref *fb_deferred_io_pageref_get(struct fb_info * pages. If possible, drivers should try to work with * unsorted page lists instead. */ - list_for_each_entry(cur, &info->fbdefio->pagelist, list) { + list_for_each_entry(cur, &fbdefio->pagereflist, list) { if (cur->offset > pageref->offset) break; } @@ -158,7 +158,7 @@ static vm_fault_t fb_deferred_io_track_page(struct fb_info *info, unsigned long 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); @@ -249,18 +249,18 @@ static void fb_deferred_io_work(struct work_struct *work) /* here we mkclean the pages, then do all deferred IO */ mutex_lock(&fbdefio->lock); - list_for_each_entry(pageref, &fbdefio->pagelist, list) { + 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_entry_safe(pageref, next, &fbdefio->pagelist, list) + list_for_each_entry_safe(pageref, next, &fbdefio->pagereflist, list) fb_deferred_io_pageref_put(pageref, info); mutex_unlock(&fbdefio->lock); @@ -280,7 +280,7 @@ int fb_deferred_io_init(struct fb_info *info) 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; diff --git a/drivers/video/fbdev/hecubafb.c b/drivers/video/fbdev/hecubafb.c index 2c483e2cf9ec..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); } diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index 51eb57ea68f7..550cf0990070 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -420,8 +420,7 @@ 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 fb_deferred_io_pageref *pageref; @@ -437,7 +436,7 @@ static void synthvid_deferred_io(struct fb_info *p, * in synthvid_update function by clamping the y2 * value to yres. */ - list_for_each_entry(pageref, pagelist, list) { + list_for_each_entry(pageref, pagereflist, list) { struct page *page = pageref->page; start = page->index << PAGE_SHIFT; end = start + PAGE_SIZE - 1; diff --git a/drivers/video/fbdev/metronomefb.c b/drivers/video/fbdev/metronomefb.c index 8352fa3f4cef..f581c73d39df 100644 --- a/drivers/video/fbdev/metronomefb.c +++ b/drivers/video/fbdev/metronomefb.c @@ -465,16 +465,14 @@ 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 fb_deferred_io_pageref *pageref; - struct fb_deferred_io *fbdefio = info->fbdefio; struct metronomefb_par *par = info->par; /* walk the written page list and swizzle the data */ - list_for_each_entry(pageref, &fbdefio->pagelist, list) { + list_for_each_entry(pageref, pagereflist, list) { struct page *cur = pageref->page; cksum = metronomefb_dpy_update_page(par, (cur->index << PAGE_SHIFT)); @@ -569,9 +567,9 @@ static const struct fb_ops metronomefb_ops = { }; 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 aea0660ba0c3..2b060eca4360 100644 --- a/drivers/video/fbdev/sh_mobile_lcdcfb.c +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c @@ -435,8 +435,7 @@ 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; @@ -445,7 +444,7 @@ static int sh_mobile_lcdc_sginit(struct fb_info *info, sg_init_table(ch->sglist, nr_pages_max); - list_for_each_entry(pageref, pagelist, list) { + list_for_each_entry(pageref, pagereflist, list) { struct page *page = pageref->page; sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0); } @@ -453,8 +452,7 @@ static int sh_mobile_lcdc_sginit(struct fb_info *info, 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; @@ -463,7 +461,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 @@ -473,12 +471,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); diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c index eb108f56ea04..7f00605bc0d1 100644 --- a/drivers/video/fbdev/smscufx.c +++ b/drivers/video/fbdev/smscufx.c @@ -955,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 fb_deferred_io_pageref *pageref; - struct fb_deferred_io *fbdefio = info->fbdefio; struct ufx_data *dev = info->par; + struct fb_deferred_io_pageref *pageref; if (!fb_defio) return; @@ -969,7 +967,7 @@ 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(pageref, &fbdefio->pagelist, list) { + list_for_each_entry(pageref, pagereflist, list) { /* create a rectangle of full screen width that encloses the * entire dirty framebuffer page */ struct page *cur = pageref->page; diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index 7547b4628afc..5c765655d000 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -371,8 +371,7 @@ static const struct fb_ops ssd1307fb_ops = { .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 f70b9cc8e855..66eefd317431 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -781,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 fb_deferred_io_pageref *pageref; - struct fb_deferred_io *fbdefio = info->fbdefio; struct dlfb_data *dlfb = info->par; struct urb *urb; char *cmd; @@ -811,7 +809,7 @@ 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(pageref, &fbdefio->pagelist, list) { + list_for_each_entry(pageref, pagereflist, list) { struct page *cur = pageref->page; if (dlfb_render_hline(dlfb, &urb, (char *) info->fix.smem_start, @@ -984,7 +982,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 608fcde767d3..bc8244b9ce03 100644 --- a/drivers/video/fbdev/xen-fbfront.c +++ b/drivers/video/fbdev/xen-fbfront.c @@ -181,8 +181,7 @@ 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 fb_deferred_io_pageref *pageref; @@ -191,7 +190,7 @@ static void xenfb_deferred_io(struct fb_info *fb_info, miny = INT_MAX; maxy = 0; - list_for_each_entry(pageref, pagelist, list) { + list_for_each_entry(pageref, pagereflist, list) { struct page *page = pageref->page; beg = page->index << PAGE_SHIFT; end = beg + PAGE_SIZE - 1; diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 3af4624368d8..329607ca65c0 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -229,8 +229,7 @@ void drm_fb_helper_fill_info(struct fb_info *info, struct drm_fb_helper *fb_helper, struct drm_fb_helper_surface_size *sizes); -void drm_fb_helper_deferred_io(struct fb_info *info, - struct list_head *pagelist); +void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagereflist); ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, size_t count, loff_t *ppos); diff --git a/include/linux/fb.h b/include/linux/fb.h index a332590c0fae..69c67c70fa78 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -211,9 +211,9 @@ struct fb_deferred_io_pageref { struct fb_deferred_io { /* delay between mkwrite and deferred handler */ unsigned long delay; - bool sort_pagelist; /* sort pagelist by offset */ - struct mutex lock; /* mutex that protects the page list */ - struct list_head pagelist; /* list of touched pages */ + bool sort_pagereflist; /* sort pagelist by offset */ + struct mutex lock; /* mutex that protects the pageref list */ + struct list_head pagereflist; /* list of pagerefs for touched pages */ /* callback */ void (*first_io)(struct fb_info *info); void (*deferred_io)(struct fb_info *info, struct list_head *pagelist); -- cgit v1.2.3 From 26817fb7b066b21c66cd41d75ed2137e046045be Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 4 May 2022 09:27:10 -0400 Subject: Revert "fbdev: fbmem: add a helper to determine if an aperture is used by a fw fb" This reverts commit 9a45ac2320d0a6ae01880a30d4b86025fce4061b. This was added a helper for amdgpu to workaround a runtime pm regression caused by a runtime pm fix in efifb. We now have a better workaround in amdgpu in commit f95af4a9236695 ("drm/amdgpu: don't runtime suspend if there are displays attached (v3)") so this workaround is no longer necessary. Since amdgpu was the only user of this interface, we can remove it. Reviewed-by: Javier Martinez Canillas Acked-by: Daniel Vetter Signed-off-by: Alex Deucher --- drivers/video/fbdev/core/fbmem.c | 47 ---------------------------------------- include/linux/fb.h | 1 - 2 files changed, 48 deletions(-) (limited to 'include/linux/fb.h') diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index ad9aac06427a..700ac4a83329 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1783,53 +1783,6 @@ int remove_conflicting_framebuffers(struct apertures_struct *a, } EXPORT_SYMBOL(remove_conflicting_framebuffers); -/** - * is_firmware_framebuffer - detect if firmware-configured framebuffer matches - * @a: memory range, users of which are to be checked - * - * This function checks framebuffer devices (initialized by firmware/bootloader) - * which use memory range described by @a. If @a matchesm the function returns - * true, otherwise false. - */ -bool is_firmware_framebuffer(struct apertures_struct *a) -{ - bool do_free = false; - bool found = false; - int i; - - if (!a) { - a = alloc_apertures(1); - if (!a) - return false; - - a->ranges[0].base = 0; - a->ranges[0].size = ~0; - do_free = true; - } - - mutex_lock(®istration_lock); - /* check all firmware fbs and kick off if the base addr overlaps */ - for_each_registered_fb(i) { - struct apertures_struct *gen_aper; - - if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) - continue; - - gen_aper = registered_fb[i]->apertures; - if (fb_do_apertures_overlap(gen_aper, a)) { - found = true; - break; - } - } - mutex_unlock(®istration_lock); - - if (do_free) - kfree(a); - - return found; -} -EXPORT_SYMBOL(is_firmware_framebuffer); - /** * remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices * @pdev: PCI device diff --git a/include/linux/fb.h b/include/linux/fb.h index 9a77ab615c36..147d582dab41 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -612,7 +612,6 @@ extern int remove_conflicting_pci_framebuffers(struct pci_dev *pdev, const char *name); extern int remove_conflicting_framebuffers(struct apertures_struct *a, const char *name, bool primary); -extern bool is_firmware_framebuffer(struct apertures_struct *a); extern int fb_prepare_logo(struct fb_info *fb_info, int rotate); extern int fb_show_logo(struct fb_info *fb_info, int rotate); extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size); -- cgit v1.2.3