Hi James, Geert, lkml and mm,
This patch adds support for the Hecuba/E-Ink display with deferred IO.
The changes from the previous version are to switch to using a mutex
and lock_page. I welcome your feedback and advice.
Signed-off-by: Jaya Kumar <redacted>
---
drivers/video/Kconfig | 13 +
drivers/video/Makefile | 1
drivers/video/hecubafb.c | 590 +++++++++++++++++++++++++++++++++++++++++++++++
mm/rmap.c | 1
4 files changed, 605 insertions(+)
---
@@ -0,0 +1,590 @@+/*+*linux/drivers/video/hecubafb.c--FBdriverforHecubacontroller+*+*Copyright(C)2006,JayaKumar+*ThisworkwassponsoredbyCIS(M)SdnBhd+*+*ThisfileissubjecttothetermsandconditionsoftheGNUGeneralPublic+*License.SeethefileCOPYINGinthemaindirectoryofthisarchivefor+*moredetails.+*+*Layoutisbasedonskeletonfb.cbyJamesSimmonsandGeertUytterhoeven.+*ThisworkwaspossiblebecauseofapollodisplaycodefromE-Ink'swebsite+*http://support.eink.com/community+*Allinformationusedtowritethiscodeisfrompublicmaterialmade+*availablebyE-Inkonitssupportsite.Somecommandssuchas0xA4+*werefoundbyloopingthroughcmd=0x00thru0xFFandsupplyingrandom+*values.Thereareothercommandsthatthedisplayiscapableof,+*beyondthe5usedherebuttheyaremorecomplex.+*+*ThisdriveriswrittentobeusedwiththeHecubadisplaycontroller+*board,andtestedwiththeEInk800x600displayin1bitmode.+*TheinterfacebetweenHecubaandthehostisTTLbasedGPIO.The+*GPIOrequirementsare8writabledatalinesand6linesforcontrol.+*Only4ofthecontrolsareactuallyusedherebut6forfutureuse.+*ThedriverrequirestheIOaddressesfordataandcontrolGPIOat+*loadtime.Itisalsopossibletousethisdisplaywithastandard+*PCparallelport.+*+*Generalnotes:+*-Usermustsethecubafb_enable=1toenableit+*-Usermustsetdio_addr=0xIOADDRcio_addr=0xIOADDRc2io_addr=0xIOADDR+*+*ExplainationfordeferredIO:+*-userspaceapplikeXfbdevmmapsframebuffer+*-driverhandlesandsetsupnopageandpage_mkwritehandlers+*-apptriestowritetommapedvaddress+*-getpagefaultandreachesdriver'snopagehandler+*-driver'snopagehandlerfindsandreturnsphysicalpage(no+*actualframebuffer)+*-writesogetpage_mkwritewhereweaddthispagetoalist+*-alsoschedulesaworkqueuetasktoberunafteradelay+*-appcontinueswritingtothatpagewithnoadditionalcost+*-theworkqueuetaskthendoespage_mkcleanforthepageson+*thelist,thencompletestheupdatingoftheframebuffer+*-apptriestowritetotheaddress(thatwasjustcleaned)+*-getpagefaultandtheabovesequenceoccursagain+*+*Thedesireisroughlytoallowburstyframebufferwritestooccur.+*Thenaftersometimewhenhopefullythingshavegonequiet,wegoand+*reallyupdatetheframebuffer.Forthistypeofnonvolatilehighlatency+*display,thedesiredimageisthefinalimageratherthanintermediate+*stageswhichiswhyit'sokaytonotupdateforeachwritethatis+*occuring.+*+*/++#include<asm/uaccess.h>+#include<linux/module.h>+#include<linux/kernel.h>+#include<linux/errno.h>+#include<linux/string.h>+#include<linux/mm.h>+#include<linux/slab.h>+#include<linux/vmalloc.h>+#include<linux/delay.h>+#include<linux/interrupt.h>+#include<linux/fb.h>+#include<linux/init.h>+#include<linux/platform_device.h>+#include<linux/list.h>++/* to support deferred IO */+#include<linux/rmap.h>+#include<linux/pagemap.h>++/* Apollo controller specific defines */+#define APOLLO_START_NEW_IMG 0xA0+#define APOLLO_STOP_IMG_DATA 0xA1+#define APOLLO_DISPLAY_IMG 0xA2+#define APOLLO_ERASE_DISPLAY 0xA3+#define APOLLO_INIT_DISPLAY 0xA4++/* Hecuba interface specific defines */+/* WUP is inverted, CD is inverted, DS is inverted */+#define HCB_NWUP_BIT 0x01+#define HCB_NDS_BIT 0x02+#define HCB_RW_BIT 0x04+#define HCB_NCD_BIT 0x08+#define HCB_ACK_BIT 0x80++/* Display specific information */+#define DPY_W 600+#define DPY_H 800++structhecubafb_par{+structdelayed_workdeferred_work;+unsignedlongdio_addr;+unsignedlongcio_addr;+unsignedlongc2io_addr;+unsignedcharctl;+atomic_tref_count;+atomic_tvma_count;+structfb_info*info;+unsignedintirq;+structmutexlock;+structlist_headpagelist;+};++structpage_list{+structlist_headlist;+structpage*page;+};++staticstructfb_fix_screeninfohecubafb_fix__initdata={+.id="hecubafb",+.type=FB_TYPE_PACKED_PIXELS,+.visual=FB_VISUAL_MONO01,+.xpanstep=0,+.ypanstep=0,+.ywrapstep=0,+.accel=FB_ACCEL_NONE,+};++staticstructfb_var_screeninfohecubafb_var__initdata={+.xres=DPY_W,+.yres=DPY_H,+.xres_virtual=DPY_W,+.yres_virtual=DPY_H,+.bits_per_pixel=1,+.nonstd=1,+};++staticunsignedlongdio_addr;+staticunsignedlongcio_addr;+staticunsignedlongc2io_addr;+staticunsignedlongsplashval;+staticunsignedintnosplash;+staticunsignedinthecubafb_enable;+staticunsignedintirq;++staticDECLARE_WAIT_QUEUE_HEAD(hecubafb_waitq);++staticvoidhcb_set_ctl(structhecubafb_par*par)+{+outb(par->ctl,par->cio_addr);+}++staticunsignedcharhcb_get_ctl(structhecubafb_par*par)+{+returninb(par->c2io_addr);+}++staticvoidhcb_set_data(structhecubafb_par*par,unsignedcharvalue)+{+outb(value,par->dio_addr);+}++staticint__devinitapollo_init_control(structhecubafb_par*par)+{+unsignedcharctl;+/* for init, we want the following setup to be set:+WUP=lo+ACK=hi+DS=hi+RW=hi+CD=lo+*/++/* write WUP to lo, DS to hi, RW to hi, CD to lo */+par->ctl=HCB_NWUP_BIT|HCB_RW_BIT|HCB_NCD_BIT;+par->ctl&=~HCB_NDS_BIT;+hcb_set_ctl(par);++/* check ACK is not lo */+ctl=hcb_get_ctl(par);+if((ctl&HCB_ACK_BIT)){+printk(KERN_ERR"Fail because ACK is already low\n");+return-ENXIO;+}++return0;+}++voidhcb_wait_for_ack(structhecubafb_par*par)+{++inttimeout;+unsignedcharctl;++timeout=500;+do{+ctl=hcb_get_ctl(par);+if((ctl&HCB_ACK_BIT))+return;+udelay(1);+}while(timeout--);+printk(KERN_ERR"timed out waiting for ack\n");+}++voidhcb_wait_for_ack_clear(structhecubafb_par*par)+{++inttimeout;+unsignedcharctl;++timeout=500;+do{+ctl=hcb_get_ctl(par);+if(!(ctl&HCB_ACK_BIT))+return;+udelay(1);+}while(timeout--);+printk(KERN_ERR"timed out waiting for clear\n");+}++voidapollo_send_data(structhecubafb_par*par,unsignedchardata)+{+/* set data */+hcb_set_data(par,data);++/* set DS low */+par->ctl|=HCB_NDS_BIT;+hcb_set_ctl(par);++hcb_wait_for_ack(par);++/* set DS hi */+par->ctl&=~(HCB_NDS_BIT);+hcb_set_ctl(par);++hcb_wait_for_ack_clear(par);+}++voidapollo_send_command(structhecubafb_par*par,unsignedchardata)+{+/* command so set CD to high */+par->ctl&=~(HCB_NCD_BIT);+hcb_set_ctl(par);++/* actually strobe with command */+apollo_send_data(par,data);++/* clear CD back to low */+par->ctl|=(HCB_NCD_BIT);+hcb_set_ctl(par);+}++/* main hecubafb functions */++staticvoidhecubafb_dpy_update(structhecubafb_par*par)+{+inti;+unsignedchar*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++));+}++apollo_send_command(par,0xA1);+apollo_send_command(par,0xA2);+}++staticvoidhecubafb_fillrect(structfb_info*info,+conststructfb_fillrect*rect)+{+structhecubafb_par*par=info->par;++cfb_fillrect(info,rect);++hecubafb_dpy_update(par);+}++staticvoidhecubafb_copyarea(structfb_info*info,+conststructfb_copyarea*area)+{+structhecubafb_par*par=info->par;++cfb_copyarea(info,area);++hecubafb_dpy_update(par);+}++staticvoidhecubafb_imageblit(structfb_info*info,+conststructfb_image*image)+{+structhecubafb_par*par=info->par;++cfb_imageblit(info,image);++hecubafb_dpy_update(par);+}++/*+*thisistheslowpathfromuserspace.theycanseekandwriteto+*thefb.it'sinefficienttodoanythinglessthanafullscreendraw+*/+staticssize_thecubafb_write(structfile*file,constchar__user*buf,+size_tcount,loff_t*ppos)+{+structinode*inode;+intfbidx;+structfb_info*info;+unsignedlongp;+interr=-EINVAL;+structhecubafb_par*par;+unsignedintxres;+unsignedintfbmemlength;++p=*ppos;+inode=file->f_dentry->d_inode;+fbidx=iminor(inode);+info=registered_fb[fbidx];++if(!info||!info->screen_base)+return-ENODEV;++par=info->par;+xres=info->var.xres;+fbmemlength=(xres*info->var.yres)/8;++if(p>fbmemlength)+return-ENOSPC;++err=0;+if((count+p)>fbmemlength){+count=fbmemlength-p;+err=-ENOSPC;+}++if(count){+char*base_addr;++base_addr=info->screen_base;+count-=copy_from_user(base_addr+p,buf,count);+*ppos+=count;+err=-EFAULT;+}++hecubafb_dpy_update(par);++if(count)+returncount;++returnerr;+}++/* this is to find and return the vmalloc-ed fb pages */+staticstructpage*hecubafb_vm_nopage(structvm_area_struct*vma,+unsignedlongvaddr,int*type)+{+unsignedlongoffset;+structpage*page;+structfb_info*info=vma->vm_private_data;++offset=(vaddr-vma->vm_start)+(vma->vm_pgoff<<PAGE_SHIFT);+if(offset>=(DPY_W*DPY_H)/8)+returnNOPAGE_SIGBUS;++page=vmalloc_to_page(info->screen_base+offset);+if(!page)+returnNOPAGE_OOM;++get_page(page);+if(type)+*type=VM_FAULT_MINOR;+returnpage;+}++staticvoidhecubafb_work(structwork_struct*work)+{+structhecubafb_par*par=container_of(work,structhecubafb_par,+deferred_work.work);+structlist_head*node,*next;+structpage_list*cur;++/* here we unmap the pages, then do all deferred IO */+mutex_lock(&par->lock);+list_for_each_safe(node,next,&par->pagelist){+cur=list_entry(node,structpage_list,list);+list_del(node);+lock_page(cur->page);+page_mkclean(cur->page);+unlock_page(cur->page);+kfree(cur);+}+mutex_unlock(&par->lock);+hecubafb_dpy_update(par);+}++staticinthecubafb_page_mkwrite(structvm_area_struct*vma,+structpage*page)+{+structfb_info*info=vma->vm_private_data;+structhecubafb_par*par=info->par;+structpage_list*new;++/* this is a callback we get when userspace first tries to +writetothepage.wescheduleaworkqueue.thatworkqueue+willeventuallyunmapthetouchedpagesandexecutethe+deferredframebufferIO.thenifuserspacetouchesapage+again,werepeatthesamescheme*/++new=kzalloc(sizeof(structpage_list),GFP_KERNEL);+if(!new)+return-ENOMEM;+new->page=page;++/* protect against the workqueue changing the page list */+mutex_lock(&par->lock);+list_add(&new->list,&par->pagelist);+mutex_unlock(&par->lock);++/* come back in 1s to process the deferred IO */+schedule_delayed_work(&par->deferred_work,HZ);+return0;+}++staticstructvm_operations_structhecubafb_vm_ops={+.nopage=hecubafb_vm_nopage,+.page_mkwrite=hecubafb_page_mkwrite,+};++staticinthecubafb_mmap(structfb_info*info,structvm_area_struct*vma)+{+vma->vm_ops=&hecubafb_vm_ops;+vma->vm_flags|=(VM_IO|VM_RESERVED|VM_DONTEXPAND);+vma->vm_private_data=info;+return0;+}++staticstructfb_opshecubafb_ops={+.owner=THIS_MODULE,+.fb_write=hecubafb_write,+.fb_fillrect=hecubafb_fillrect,+.fb_copyarea=hecubafb_copyarea,+.fb_imageblit=hecubafb_imageblit,+.fb_mmap=hecubafb_mmap,+};++staticint__devinithecubafb_probe(structplatform_device*dev)+{+structfb_info*info;+intretval=-ENOMEM;+intvideomemorysize;+unsignedchar*videomemory;+structhecubafb_par*par;++videomemorysize=(DPY_W*DPY_H)/8;++if(!(videomemory=vmalloc(videomemorysize)))+returnretval;++memset(videomemory,0,videomemorysize);++info=framebuffer_alloc(sizeof(structhecubafb_par),&dev->dev);+if(!info)+gotoerr;++info->screen_base=(char__iomem*)videomemory;+info->fbops=&hecubafb_ops;++info->var=hecubafb_var;+info->fix=hecubafb_fix;+par=info->par;+par->info=info;++if(!dio_addr||!cio_addr||!c2io_addr){+printk(KERN_WARNING"no IO addresses supplied\n");+gotoerr1;+}+par->dio_addr=dio_addr;+par->cio_addr=cio_addr;+par->c2io_addr=c2io_addr;+info->flags=FBINFO_FLAG_DEFAULT;+mutex_init(&par->lock);+INIT_DELAYED_WORK(&par->deferred_work,hecubafb_work);+INIT_LIST_HEAD(&par->pagelist);+retval=register_framebuffer(info);+if(retval<0)+gotoerr1;+platform_set_drvdata(dev,info);++printk(KERN_INFO+"fb%d: Hecuba frame buffer device, using %dK of video memory\n",+info->node,videomemorysize>>10);++/* this inits the dpy */+apollo_init_control(par);++apollo_send_command(par,APOLLO_INIT_DISPLAY);+apollo_send_data(par,0x81);++/* have to wait while display resets */+udelay(1000);++/* if we were told to splash the screen, we just clear it */+if(!nosplash){+apollo_send_command(par,APOLLO_ERASE_DISPLAY);+apollo_send_data(par,splashval);+}++return0;+err1:+framebuffer_release(info);+err:+vfree(videomemory);+returnretval;+}++staticint__devexithecubafb_remove(structplatform_device*dev)+{+structfb_info*info=platform_get_drvdata(dev);+structhecubafb_par*par;++if(info){+par=info->par;+cancel_delayed_work(&par->deferred_work);+flush_scheduled_work();+unregister_framebuffer(info);+vfree(info->screen_base);+framebuffer_release(info);+}+return0;+}++staticstructplatform_driverhecubafb_driver={+.probe=hecubafb_probe,+.remove=hecubafb_remove,+.driver={+.name="hecubafb",+},+};++staticstructplatform_device*hecubafb_device;++staticint__inithecubafb_init(void)+{+intret;++if(!hecubafb_enable){+printk(KERN_ERR"Use hecubafb_enable to enable the device\n");+return-ENXIO;+}++ret=platform_driver_register(&hecubafb_driver);+if(!ret){+hecubafb_device=platform_device_alloc("hecubafb",0);+if(hecubafb_device)+ret=platform_device_add(hecubafb_device);+else+ret=-ENOMEM;++if(ret){+platform_device_put(hecubafb_device);+platform_driver_unregister(&hecubafb_driver);+}+}+returnret;++}++staticvoid__exithecubafb_exit(void)+{+platform_device_unregister(hecubafb_device);+platform_driver_unregister(&hecubafb_driver);+}++module_param(nosplash,uint,0);+MODULE_PARM_DESC(nosplash,"Disable doing the splash screen");+module_param(hecubafb_enable,uint,0);+MODULE_PARM_DESC(hecubafb_enable,"Enable communication with Hecuba board");+module_param(dio_addr,ulong,0);+MODULE_PARM_DESC(dio_addr,"IO address for data, eg: 0x480");+module_param(cio_addr,ulong,0);+MODULE_PARM_DESC(cio_addr,"IO address for control, eg: 0x400");+module_param(c2io_addr,ulong,0);+MODULE_PARM_DESC(c2io_addr,"IO address for secondary control, eg: 0x408");+module_param(splashval,ulong,0);+MODULE_PARM_DESC(splashval,"Splash pattern: 0x00 is black, 0x01 is white");+module_param(irq,uint,0);+MODULE_PARM_DESC(irq,"IRQ for the Hecuba board");++module_init(hecubafb_init);+module_exit(hecubafb_exit);++MODULE_DESCRIPTION("fbdev driver for Hecuba board");+MODULE_AUTHOR("Jaya Kumar");+MODULE_LICENSE("GPL");
From: Peter Zijlstra <hidden> Date: 2007-02-17 12:34:18
On Sat, 2007-02-17 at 11:42 +0100, Jaya Kumar wrote:
Hi James, Geert, lkml and mm,
Hi Jaya,
This patch adds support for the Hecuba/E-Ink display with deferred IO.
The changes from the previous version are to switch to using a mutex
and lock_page. I welcome your feedback and advice.
This changelog ought to be a little more extensive; esp. because you're
using these fancy new functions ->page_mkwrite() and page_mkclean() in a
novel way.
Also, I'd still like to see a way to call msync() on the mmap'ed region
to force a flush. I think providing a fb_fsync() method in fbmem.c and a
hook down to the driver ought to work.
Also, you now seem to use a fixed 1 second delay, perhaps provide an
ioctl or something to customize this?
And, as Andrew suggested last time around, could you perhaps push this
fancy new idea into the FB layer so that more drivers can make us of it?
On Sat, 2007-02-17 at 11:42 +0100, Jaya Kumar wrote:
quoted
Hi James, Geert, lkml and mm,
Hi Jaya,
quoted
This patch adds support for the Hecuba/E-Ink display with deferred IO.
The changes from the previous version are to switch to using a mutex
and lock_page. I welcome your feedback and advice.
This changelog ought to be a little more extensive; esp. because you're
using these fancy new functions ->page_mkwrite() and page_mkclean() in a
novel way.
Hi Peter,
I had put the comment explaining the usage of mkwrite/mkclean in the
.c file. Oh, I see, in the changelog message. Ok, I'll update with a
changelog message mentioning mkwrite/mkclean.
Also, I'd still like to see a way to call msync() on the mmap'ed region
to force a flush. I think providing a fb_fsync() method in fbmem.c and a
hook down to the driver ought to work.
I'm hoping fbdev folk will give feedback if this is okay. James,
Geert, what do you think?
Also, you now seem to use a fixed 1 second delay, perhaps provide an
ioctl or something to customize this?
Ok. Will do.
And, as Andrew suggested last time around, could you perhaps push this
fancy new idea into the FB layer so that more drivers can make us of it?
I would like to do that very much. I have some ideas how it could work
for devices that support clean partial updates by tracking touched
pages. But I wonder if it is too early to try to abstract this out.
James, Geert, what do you think?
Thanks,
jaya
-------------------------------------------------------------------------
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
From: Paul Mundt <hidden> Date: 2007-02-17 14:01:37
On Sat, Feb 17, 2007 at 08:25:07AM -0500, Jaya Kumar wrote:
On 2/17/07, Peter Zijlstra [off-list ref] wrote:
quoted
And, as Andrew suggested last time around, could you perhaps push this
fancy new idea into the FB layer so that more drivers can make us of it?
I would like to do that very much. I have some ideas how it could work
for devices that support clean partial updates by tracking touched
pages. But I wonder if it is too early to try to abstract this out.
James, Geert, what do you think?
This would also provide an interesting hook for setting up chained DMA
for the real framebuffer updates when there's more than a couple of pages
that have been touched, which would also be nice to have. There's more
than a few drivers that could take advantage of that.
-------------------------------------------------------------------------
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
On Sat, Feb 17, 2007 at 08:25:07AM -0500, Jaya Kumar wrote:
quoted
On 2/17/07, Peter Zijlstra [off-list ref] wrote:
quoted
And, as Andrew suggested last time around, could you perhaps push this
fancy new idea into the FB layer so that more drivers can make us of it?
I would like to do that very much. I have some ideas how it could work
for devices that support clean partial updates by tracking touched
pages. But I wonder if it is too early to try to abstract this out.
James, Geert, what do you think?
This would also provide an interesting hook for setting up chained DMA
for the real framebuffer updates when there's more than a couple of pages
that have been touched, which would also be nice to have. There's more
than a few drivers that could take advantage of that.
Hi Paul,
I could benefit from knowing which driver and display device you are
considering to be applicable.
I was thinking the method used in hecubafb would only be useful to
devices with very slow update paths, where "losing" some of the
display activity is not an issue since the device would not have been
able to update fast enough to show that activity anyway.
What you described with chained DMA sounds different to this. I
suppose one could use this technique to coalesce framebuffer IO to get
better performance/utilization even for fast display devices. Sounds
interesting to try. Did I understand you correctly?
Thanks,
jaya
-------------------------------------------------------------------------
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
From: Paul Mundt <hidden> Date: 2007-02-18 23:59:59
On Sun, Feb 18, 2007 at 06:31:23AM -0500, Jaya Kumar wrote:
On 2/17/07, Paul Mundt [off-list ref] wrote:
quoted
This would also provide an interesting hook for setting up chained DMA
for the real framebuffer updates when there's more than a couple of pages
that have been touched, which would also be nice to have. There's more
than a few drivers that could take advantage of that.
I could benefit from knowing which driver and display device you are
considering to be applicable.
I was thinking the method used in hecubafb would only be useful to
devices with very slow update paths, where "losing" some of the
display activity is not an issue since the device would not have been
able to update fast enough to show that activity anyway.
What you described with chained DMA sounds different to this. I
suppose one could use this technique to coalesce framebuffer IO to get
better performance/utilization even for fast display devices. Sounds
interesting to try. Did I understand you correctly?
Yes, that's what I'm interested in trying. In the SH case we can
basically make use of the on-chip DMAC for any non-PCI device. Some of
these permit scatterlists and chained DMA in hardware, others do not. The
general problem is that since we have to go and poke at the dcache prior
to kicking off the DMA, it's rarely a win for a small number of pages,
memory bursts just end up being faster.
The other issue is that most of the "big" writers are doing so via mmap()
anyways, so it's futile to attempt to handle the DMA case in the
->write() path. Your approach seems like it might be an appropriate
interface for building something like this on top of.
Given that, this would have to be something that's dealt with at the
subsystem level rather than in individual drivers, hence the desire to
see something like this more generically visible.
-------------------------------------------------------------------------
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
Given that, this would have to be something that's dealt with at the
subsystem level rather than in individual drivers, hence the desire to
see something like this more generically visible.
Hi Peter, Paul, fbdev folk,
Ok. Here's what I'm thinking for abstracting this:
fbdev drivers would setup fb_mmap with their own_mmap as usual. In
own_mmap, they would do what they normally do and setup a vm_ops. They
are free to have their own nopage handler but would set the
page_mkwrite handler to be fbdev_deferred_io_mkwrite().
fbdev_deferred_io_mkwrite would build up the list of touched pages and
pass it to a delayed workqueue which would then mkclean on each page
and then pass a copy of that page list down to a driver's callback
function. The fbdev driver's callback function can then do the actual
IO to the framebuffer or coalesce DMA based on the provided page list.
I would like to add something like the following to struct fb_info:
#ifdef CONFIG_FB_DEFERRED_IO
struct fb_deferred_io *defio;
#endif
to store the mutex (to protect the page list), the touched page list,
and the driver's callback function.
I hope this sounds sufficiently generic to meet everyone's (the two of
us? :) needs.
Thanks,
jaya
ps: I've added James and Geert to the CC list. I would appreciate any
advice on whether this is a suitable approach.
-------------------------------------------------------------------------
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
From: Paul Mundt <hidden> Date: 2007-02-20 04:41:10
On Mon, Feb 19, 2007 at 11:13:04PM -0500, Jaya Kumar wrote:
On 2/18/07, Paul Mundt [off-list ref] wrote:
quoted
Given that, this would have to be something that's dealt with at the
subsystem level rather than in individual drivers, hence the desire to
see something like this more generically visible.
Hi Peter, Paul, fbdev folk,
Ok. Here's what I'm thinking for abstracting this:
fbdev drivers would setup fb_mmap with their own_mmap as usual. In
own_mmap, they would do what they normally do and setup a vm_ops. They
are free to have their own nopage handler but would set the
page_mkwrite handler to be fbdev_deferred_io_mkwrite().
The vast majority of drivers do not implement ->fb_mmap(), and with
proper abstraction, this should be something that's possible as a direct
alternative to drivers/video/fbmem.c:fb_mmap() for the people that want
it. Of course it's just as easy to do something like the sbuslib.c route
and then have drivers set their ->fb_mmap() from that too.
fbdev_deferred_io_mkwrite would build up the list of touched pages and
pass it to a delayed workqueue which would then mkclean on each page
and then pass a copy of that page list down to a driver's callback
function. The fbdev driver's callback function can then do the actual
IO to the framebuffer or coalesce DMA based on the provided page list.
That works for me, though I'd prefer for struct page_list to be done with
a scatterlist, then it's trivial to setup from the workqueue context
without having to shuffle things around.
-------------------------------------------------------------------------
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
On Mon, Feb 19, 2007 at 11:13:04PM -0500, Jaya Kumar wrote:
quoted
Ok. Here's what I'm thinking for abstracting this:
fbdev drivers would setup fb_mmap with their own_mmap as usual. In
own_mmap, they would do what they normally do and setup a vm_ops. They
are free to have their own nopage handler but would set the
page_mkwrite handler to be fbdev_deferred_io_mkwrite().
The vast majority of drivers do not implement ->fb_mmap(), and with
proper abstraction, this should be something that's possible as a direct
alternative to drivers/video/fbmem.c:fb_mmap() for the people that want
it. Of course it's just as easy to do something like the sbuslib.c route
and then have drivers set their ->fb_mmap() from that too.
I was thinking about having that fb_mmap replacement too. But then I
got worried because that generic implementation of nopage/etc would
need to handle whether the driver's fb memory was vmalloced, kmalloced
or a mixture if some do that. So I figured let's aim low and just pull
in the core part that does the setup and page tracking stuff. I hope
that's okay.
That works for me, though I'd prefer for struct page_list to be done with
a scatterlist, then it's trivial to setup from the workqueue context
without having to shuffle things around.
Ok. Will check out when implementing.
Thanks,
jaya
-------------------------------------------------------------------------
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
Given that, this would have to be something that's dealt with at the
subsystem level rather than in individual drivers, hence the desire to
see something like this more generically visible.
Hi Peter, Paul, fbdev folk,
Ok. Here's what I'm thinking for abstracting this:
fbdev drivers would setup fb_mmap with their own_mmap as usual. In
own_mmap, they would do what they normally do and setup a vm_ops. They
are free to have their own nopage handler but would set the
page_mkwrite handler to be fbdev_deferred_io_mkwrite().
fbdev_deferred_io_mkwrite would build up the list of touched pages and
pass it to a delayed workqueue which would then mkclean on each page
and then pass a copy of that page list down to a driver's callback
function. The fbdev driver's callback function can then do the actual
IO to the framebuffer or coalesce DMA based on the provided page list.
I would like to add something like the following to struct fb_info:
#ifdef CONFIG_FB_DEFERRED_IO
struct fb_deferred_io *defio;
#endif
Don't you need a way to specify the maximum deferral time? E.g. a field in
fb_info.
to store the mutex (to protect the page list), the touched page list,
and the driver's callback function.
I hope this sounds sufficiently generic to meet everyone's (the two of
us? :) needs.
Looks fine!
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
-------------------------------------------------------------------------
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
That works for me, though I'd prefer for struct page_list to be done with
a scatterlist, then it's trivial to setup from the workqueue context
without having to shuffle things around.
Ok. Will check out when implementing.
Took a quick look. If I used scatterlist, I'd still need to build a
list of scatterlist to pass to the driver callback. The alternative
being a preallocated array of scatterlist based on the page count of
the framebuffer, which seems expensive since scatterlist has page,
offset, dma and length.
On a separate note, Peter pointed out that it may be possible to reuse
page->lru instead of using a struct page_list. This would enable
something like:
in mkwrite:
mutex_lock
list_add(page->lru, defio->pagelist)
mutex_unlock
in deferred handler:
mutex_lock
for_each page {
lock_page
mkclean
unlock_page
}
callback(fb_info, pagelist)
for_each page {
list_del
}
mutex_unlock
The advantage of reusing page->lru is that avoids needing the struct
page_list and allocation in mkwrite. Is the above exploitation of
->lru ok with mm folk?
In above, we're iterating over the page list twice. I have to mkclean
before calling the callback to avoid the situation where a touched
page is missed by the callback. I don't see a way around that part.
Thanks,
jaya
-------------------------------------------------------------------------
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
On 2/20/07, Geert Uytterhoeven [off-list ref] wrote:
Don't you need a way to specify the maximum deferral time? E.g. a field in
fb_info.
You are right. I will need that. I could put that into struct
fb_deferred_io. So drivers would setup like:
static struct fb_deferred_io hecubafb_defio = {
.delay = HZ,
.deferred_io = hecubafb_dpy_update,
};
where that would be:
struct fb_deferred_io {
unsigned long delay; /* delay between mkwrite and deferred handler */
struct mutex lock; /* mutex that protects the page list */
struct list_head pagelist; /* list of touched pages */
struct delayed_work deferred_work;
void (*deferred_io)(struct fb_info *info, struct list_head
*pagelist); /* callback */
};
and the driver would do:
...
info->fbdefio = hecubafb_defio;
register_framebuffer...
When the driver calls register_framebuffer and unregister_framebuffer,
I can then do the init and destruction of the other members of that
struct. Does this sound okay?
Thanks,
jaya
From: James Simmons <hidden> Date: 2007-02-21 21:52:29
Could you make it work without the framebuffer. There are embedded LCD
displays that have internal memory that need data flushed to them.
On Wed, 21 Feb 2007, Jaya Kumar wrote:
On 2/20/07, Geert Uytterhoeven [off-list ref] wrote:
quoted
Don't you need a way to specify the maximum deferral time? E.g. a field in
fb_info.
You are right. I will need that. I could put that into struct
fb_deferred_io. So drivers would setup like:
static struct fb_deferred_io hecubafb_defio = {
.delay = HZ,
.deferred_io = hecubafb_dpy_update,
};
where that would be:
struct fb_deferred_io {
unsigned long delay; /* delay between mkwrite and deferred handler
*/
struct mutex lock; /* mutex that protects the page list */
struct list_head pagelist; /* list of touched pages */
struct delayed_work deferred_work;
void (*deferred_io)(struct fb_info *info, struct list_head
*pagelist); /* callback */
};
and the driver would do:
...
info->fbdefio = hecubafb_defio;
register_framebuffer...
When the driver calls register_framebuffer and unregister_framebuffer,
I can then do the init and destruction of the other members of that
struct. Does this sound okay?
Thanks,
jaya
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
-------------------------------------------------------------------------
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
Could you make it work without the framebuffer. There are embedded LCD
displays that have internal memory that need data flushed to them.
I'm not sure I understand. What the current implementation does is to
use host based framebuffer memory. Apps mmap that memory and draw to
that. Then after the delay, that framebuffer is written to the
device's memory. That's the scenario for hecubafb where the Apollo
controller maintains it's own internal framebuffer.
When you say without the framebuffer, if you meant without the host
memory, then this method doesn't work. If you mean without the
device's internal memory, then yes, I think we can do that, because it
would be up to the driver to use the touched pagelist to then perform
IO as suitable for its device.
Thanks,
jaya
-------------------------------------------------------------------------
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
From: "Antonino A. Daplas" <adaplas@gmail.com> Date: 2007-02-21 23:40:55
On Mon, 2007-02-19 at 23:13 -0500, Jaya Kumar wrote:
On 2/18/07, Paul Mundt [off-list ref] wrote:
quoted
Given that, this would have to be something that's dealt with at the
subsystem level rather than in individual drivers, hence the desire to
see something like this more generically visible.
Hi Peter, Paul, fbdev folk,
Ok. Here's what I'm thinking for abstracting this:
fbdev drivers would setup fb_mmap with their own_mmap as usual. In
own_mmap, they would do what they normally do and setup a vm_ops. They
are free to have their own nopage handler but would set the
page_mkwrite handler to be fbdev_deferred_io_mkwrite().
fbdev_deferred_io_mkwrite would build up the list of touched pages and
pass it to a delayed workqueue which would then mkclean on each page
Yes, this functionality is sorely needed by more than a few driver
writers.
and then pass a copy of that page list down to a driver's callback
function. The fbdev driver's callback function can then do the actual
IO to the framebuffer or coalesce DMA based on the provided page list.
I would like to add something like the following to struct fb_info:
#ifdef CONFIG_FB_DEFERRED_IO
struct fb_deferred_io *defio;
#endif
to store the mutex (to protect the page list), the touched page list,
and the driver's callback function.
I hope this sounds sufficiently generic to meet everyone's (the two of
us? :) needs.
There's definitely more than two :-). For the past several years,
various people have been asking for this functionality. So yes,
implementing this in a generic manner will be a big help.
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
From: "Antonino A. Daplas" <adaplas@gmail.com> Date: 2007-02-21 23:41:03
On Wed, 2007-02-21 at 11:55 -0500, Jaya Kumar wrote:
On 2/20/07, Geert Uytterhoeven [off-list ref] wrote:
quoted
Don't you need a way to specify the maximum deferral time? E.g. a field in
fb_info.
You are right. I will need that. I could put that into struct
fb_deferred_io. So drivers would setup like:
Is it also possible to let the drivers do the 'deferred_io'
themselves? Say, a driver that would flush the dirty pages on
every VBLANK interrupt.
static struct fb_deferred_io hecubafb_defio = {
.delay = HZ,
.deferred_io = hecubafb_dpy_update,
};
where that would be:
struct fb_deferred_io {
unsigned long delay; /* delay between mkwrite and deferred handler */
struct mutex lock; /* mutex that protects the page list */
struct list_head pagelist; /* list of touched pages */
struct delayed_work deferred_work;
void (*deferred_io)(struct fb_info *info, struct list_head
*pagelist); /* callback */
};
and the driver would do:
...
info->fbdefio = hecubafb_defio;
register_framebuffer...
When the driver calls register_framebuffer and unregister_framebuffer,
I can then do the init and destruction of the other members of that
struct. Does this sound okay?
It would be better if separate registering functions are created for
this functionality (ie deferred_io_register/unregister).
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
On 2/21/07, Antonino A. Daplas [off-list ref] wrote:
On Wed, 2007-02-21 at 11:55 -0500, Jaya Kumar wrote:
quoted
You are right. I will need that. I could put that into struct
fb_deferred_io. So drivers would setup like:
Is it also possible to let the drivers do the 'deferred_io'
themselves? Say, a driver that would flush the dirty pages on
every VBLANK interrupt.
Yes, I think so. The deferred_io callback that the driver would get
would be to provide them with the dirty pages list. Then, they could
use that to handle the on-vblank work.
quoted
When the driver calls register_framebuffer and unregister_framebuffer,
I can then do the init and destruction of the other members of that
struct. Does this sound okay?
It would be better if separate registering functions are created for
this functionality (ie deferred_io_register/unregister).
Ok. Will do it that way.
Thanks,
jaya
-------------------------------------------------------------------------
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
From: James Simmons <hidden> Date: 2007-02-28 16:50:36
I'm not sure I understand. What the current implementation does is to
use host based framebuffer memory. Apps mmap that memory and draw to
that. Then after the delay, that framebuffer is written to the
device's memory. That's the scenario for hecubafb where the Apollo
controller maintains it's own internal framebuffer.
When you say without the framebuffer, if you meant without the host
memory, then this method doesn't work. If you mean without the
device's internal memory, then yes, I think we can do that, because it
would be up to the driver to use the touched pagelist to then perform
IO as suitable for its device.
I meant for it to work for non framebuffer devices. I realized that not
such a great idea.