summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/staging/fbtft/fbtft-core.c1
-rw-r--r--drivers/video/fbdev/broadsheetfb.c1
-rw-r--r--drivers/video/fbdev/core/fb_defio.c24
-rw-r--r--drivers/video/fbdev/metronomefb.c1
-rw-r--r--drivers/video/fbdev/udlfb.c1
-rw-r--r--include/linux/fb.h1
6 files changed, 22 insertions, 7 deletions
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 */