Thread (5 messages) 5 messages, 3 authors, 2007-02-24

Re: [RFC 2.6.20 1/1] fbdev, mm: Deferred IO and hecubafb driver

From: "Antonino A. Daplas" <adaplas@gmail.com>
Date: 2007-02-24 06:49:25
Also in: linux-mm, lkml

On Fri, 2007-02-23 at 07:32 +0100, Jaya Kumar wrote:
Hi Tony, Paul, Peter, fbdev, lkml, and mm,

This is a first pass at abstracting deferred IO out from hecubafb and
into fbdev as was discussed before: 
http://marc.theaimsgroup.com/?l=linux-fbdev-devel&m=117187443327466&w=2

Please let me know your feedback and if it looks okay so far.
Can you create 2 separate patches, one for the deferred_io and another
for the driver that uses it?
+Another one may be if one has a device framebuffer that is in an usual format,
+say diagonally shifting RGB, this may then be a mechanism for you to allow
+apps to pretend to have a normal framebuffer but reswizzle for the device
+framebuffer at vsync time based on the touched pagelist.
Hmm, yes, it can be used to implement a shadow framebuffer :-)
+
+How to use it: (for applications)
+---------------------------------
+No changes needed. mmap the framebuffer like normal and just use it.
+
+How to use it: (for fbdev drivers)
+----------------------------------
+The following example may be helpful.
+
+1. Setup your mmap and vm_ops structures. Eg:
+
+
+The delay is the minimum delay between when the page_mkwrite trigger occurs
+and when the deferred_io callback is called. The deferred_io callback is
+explained below.
+
+static struct vm_operations_struct hecubafb_vm_ops = {
+	.nopage   	= hecubafb_vm_nopage,
+	.page_mkwrite	= fb_deferred_io_mkwrite,
+};
+
It would seem to me that the above can be made generic, so we have this
instead:

static struct vm_operations_struct fb_deferred_vm_ops = {
	.nopage   	= fb_deferred_io_vm_nopage,
	.page_mkwrite	= fb_deferred_io_mkwrite,
};
+You will need a nopage routine to find and retrive the struct page for your
+framebuffer pages. You must set page_mkwrite to fb_deferred_io_mkwrite.
+Here's the example nopage for hecubafb where it is a vmalloced framebuffer. 
+
+static int hecubafb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	vma->vm_ops = &hecubafb_vm_ops;
+	vma->vm_flags |= ( VM_IO | VM_RESERVED | VM_DONTEXPAND );
+	vma->vm_private_data = info;
+	return 0;
+}
And this too as fb_deferred_io_mmap.
+
+static struct page* hecubafb_vm_nopage(struct vm_area_struct *vma, 
+					unsigned long vaddr, int *type)
+{
+	unsigned long offset;
+	struct page *page;
+	struct fb_info *info = vma->vm_private_data;
+
+	offset = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+	if (offset >= (DPY_W*DPY_H)/8)
+		return NOPAGE_SIGBUS;
+
To make it generic, this can simply be:

	if (offset >= info->fix.smem_len)
		return NOPAGE_SIGBUS.
+	page = vmalloc_to_page(info->screen_base + offset);
+	if (!page)
+		return NOPAGE_OOM;
+
+	get_page(page);
+	if (type)
+		*type = VM_FAULT_MINOR;
+	return page;
+}
+
+static struct fb_deferred_io hecubafb_defio = {
+	.delay		= HZ,
+	.deferred_io	= hecubafb_dpy_deferred_io,
+};
Leaving the drivers to just fill up the above. This would result in a
decrease of code duplication and it will be easier for driver writers.

quoted hunk ↗ jump to hunk
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 2822526..863126a 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1325,6 +1325,7 @@ register_framebuffer(struct fb_info *fb_info)
 
 	event.info = fb_info;
 	fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
+	fb_deferred_io_init(fb_info);
 	return 0;
 }
 
@@ -1355,6 +1356,7 @@ unregister_framebuffer(struct fb_info *fb_info)
 	fb_destroy_modelist(&fb_info->modelist);
 	registered_fb[i]=NULL;
 	num_registered_fb--;
+	fb_deferred_io_cleanup(fb_info);
 	fb_cleanup_device(fb_info);
 	device_destroy(fb_class, MKDEV(FB_MAJOR, i));
 	event.info = fb_info;
I would prefer to have the init and cleanup functions called by the
driver themselves, instead of piggy-backing them to the
framebuffer_register/unregister.

+static void hecubafb_dpy_update(struct hecubafb_par *par)
+{
+	int i;
+	unsigned char *buf = par->info->screen_base;
+
+	apollo_send_command(par, 0xA0);
+
+	for (i=0; i < (DPY_W*DPY_H/8); i++) {
+		apollo_send_data(par, *(buf++));
+	}
+
This basically dumps the entire framebuffer to the hardware, doesn't it?
This framebuffer has only 2 pages at the most, so it doesn't matter. But
for hardware with MB's of RAM, I don't think this is feasible.

Is there a way to selectively update only the touched pages, ie from the
fbdevio->pagelist? struct page has a field (pgoff_t index), is this
usable? If not, can we just create a bit array, just to tell the driver
which are the dirty pages?

Tony


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help