aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJaya Kumar <jayakumar.lkml@gmail.com>2007-05-08 03:37:37 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-08 14:15:26 -0400
commit60b59beafba875aef6d378078bce0baf2287ae14 (patch)
treebb599c0e2ad43ee8f515a9f9af009442931b6a37 /drivers
parent3a2842480bbef42c3c90e14c1f378360d8c20a0c (diff)
fbdev: mm: Deferred IO support
This implements deferred IO support in fbdev. Deferred IO is a way to delay and repurpose IO. This implementation is done using mm's page_mkwrite and page_mkclean hooks in order to detect, delay and then rewrite IO. This functionality is used by hecubafb. [adaplas] This is useful for graphics hardware with no directly addressable/mappable framebuffer. Implementing this will allow the "framebuffer" to be accesible from user space via mmap(). Signed-off-by: Jaya Kumar <jayakumar.lkml@gmail.com> Signed-off-by: Antonino Daplas <adaplas@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/Kconfig5
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/fb_defio.c137
3 files changed, 143 insertions, 0 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 8dfa88a68ae9..61c0a03d33f2 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -91,6 +91,11 @@ config FB_CFB_IMAGEBLIT
91 blitting. This is used by drivers that don't provide their own 91 blitting. This is used by drivers that don't provide their own
92 (accelerated) version. 92 (accelerated) version.
93 93
94config FB_DEFERRED_IO
95 bool
96 depends on FB
97 default y
98
94config FB_SVGALIB 99config FB_SVGALIB
95 tristate 100 tristate
96 depends on FB 101 depends on FB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 281462414930..deb5fa55f783 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
20obj-$(CONFIG_FB_SVGALIB) += svgalib.o 20obj-$(CONFIG_FB_SVGALIB) += svgalib.o
21obj-$(CONFIG_FB_MACMODES) += macmodes.o 21obj-$(CONFIG_FB_MACMODES) += macmodes.o
22obj-$(CONFIG_FB_DDC) += fb_ddc.o 22obj-$(CONFIG_FB_DDC) += fb_ddc.o
23obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o
23 24
24# Hardware specific drivers go first 25# Hardware specific drivers go first
25obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o 26obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
new file mode 100644
index 000000000000..cc780f4e183d
--- /dev/null
+++ b/drivers/video/fb_defio.c
@@ -0,0 +1,137 @@
1/*
2 * linux/drivers/video/fb_defio.c
3 *
4 * Copyright (C) 2006 Jaya Kumar
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/errno.h>
14#include <linux/string.h>
15#include <linux/mm.h>
16#include <linux/slab.h>
17#include <linux/vmalloc.h>
18#include <linux/delay.h>
19#include <linux/interrupt.h>
20#include <linux/fb.h>
21#include <linux/list.h>
22#include <asm/uaccess.h>
23
24/* to support deferred IO */
25#include <linux/rmap.h>
26#include <linux/pagemap.h>
27
28/* this is to find and return the vmalloc-ed fb pages */
29static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma,
30 unsigned long vaddr, int *type)
31{
32 unsigned long offset;
33 struct page *page;
34 struct fb_info *info = vma->vm_private_data;
35
36 offset = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
37 if (offset >= info->fix.smem_len)
38 return NOPAGE_SIGBUS;
39
40 page = vmalloc_to_page(info->screen_base + offset);
41 if (!page)
42 return NOPAGE_OOM;
43
44 get_page(page);
45 if (type)
46 *type = VM_FAULT_MINOR;
47 return page;
48}
49
50/* vm_ops->page_mkwrite handler */
51int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
52 struct page *page)
53{
54 struct fb_info *info = vma->vm_private_data;
55 struct fb_deferred_io *fbdefio = info->fbdefio;
56
57 /* this is a callback we get when userspace first tries to
58 write to the page. we schedule a workqueue. that workqueue
59 will eventually mkclean the touched pages and execute the
60 deferred framebuffer IO. then if userspace touches a page
61 again, we repeat the same scheme */
62
63 /* protect against the workqueue changing the page list */
64 mutex_lock(&fbdefio->lock);
65 list_add(&page->lru, &fbdefio->pagelist);
66 mutex_unlock(&fbdefio->lock);
67
68 /* come back after delay to process the deferred IO */
69 schedule_delayed_work(&info->deferred_work, fbdefio->delay);
70 return 0;
71}
72
73static struct vm_operations_struct fb_deferred_io_vm_ops = {
74 .nopage = fb_deferred_io_nopage,
75 .page_mkwrite = fb_deferred_io_mkwrite,
76};
77
78static int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
79{
80 vma->vm_ops = &fb_deferred_io_vm_ops;
81 vma->vm_flags |= ( VM_IO | VM_RESERVED | VM_DONTEXPAND );
82 vma->vm_private_data = info;
83 return 0;
84}
85
86/* workqueue callback */
87static void fb_deferred_io_work(struct work_struct *work)
88{
89 struct fb_info *info = container_of(work, struct fb_info,
90 deferred_work.work);
91 struct list_head *node, *next;
92 struct page *cur;
93 struct fb_deferred_io *fbdefio = info->fbdefio;
94
95 /* here we mkclean the pages, then do all deferred IO */
96 mutex_lock(&fbdefio->lock);
97 list_for_each_entry(cur, &fbdefio->pagelist, lru) {
98 lock_page(cur);
99 page_mkclean(cur);
100 unlock_page(cur);
101 }
102
103 /* driver's callback with pagelist */
104 fbdefio->deferred_io(info, &fbdefio->pagelist);
105
106 /* clear the list */
107 list_for_each_safe(node, next, &fbdefio->pagelist) {
108 list_del(node);
109 }
110 mutex_unlock(&fbdefio->lock);
111}
112
113void fb_deferred_io_init(struct fb_info *info)
114{
115 struct fb_deferred_io *fbdefio = info->fbdefio;
116
117 BUG_ON(!fbdefio);
118 mutex_init(&fbdefio->lock);
119 info->fbops->fb_mmap = fb_deferred_io_mmap;
120 INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work);
121 INIT_LIST_HEAD(&fbdefio->pagelist);
122 if (fbdefio->delay == 0) /* set a default of 1 s */
123 fbdefio->delay = HZ;
124}
125EXPORT_SYMBOL_GPL(fb_deferred_io_init);
126
127void fb_deferred_io_cleanup(struct fb_info *info)
128{
129 struct fb_deferred_io *fbdefio = info->fbdefio;
130
131 BUG_ON(!fbdefio);
132 cancel_delayed_work(&info->deferred_work);
133 flush_scheduled_work();
134}
135EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup);
136
137MODULE_LICENSE("GPL");