Re: [RFC 2.6.20 1/1] fbdev, mm: Deferred IO and hecubafb driver
flat view
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?
quoted hunk ↗ jump to hunk
+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 :-)
quoted hunk ↗ jump to hunk
+ +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,
};
quoted hunk ↗ jump to hunk
+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.
quoted hunk ↗ jump to hunk
+ +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.
quoted hunk ↗ jump to hunk
+ page = vmalloc_to_page(info->screen_base + offset); + if (!page) + return NOPAGE_OOM; + + get_page(page); + if (type) + *type = VM_FAULT_MINOR; + return page; +} +
quoted hunk ↗ jump to hunk
+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.
quoted hunk ↗ jump to hunk
+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