aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@infradead.org>2007-01-25 03:00:01 -0500
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-02-21 10:34:55 -0500
commitb50e7fe99317c05b0bb8ba6338bc6aa7da3b918e (patch)
tree32124766d993a7d65b49555f6f65a04508ecc318
parent52ebc763d8e0c9f2ab48af89a75e90e2318bac86 (diff)
V4L/DVB (5147): Make vivi driver to use vmalloced pointers
Before this patch, vivi were simulating a scatter gather DMA transfer. While this is academic, showing how stuff really works on a real PCI device, this means a non-optimized code. There are only two memory models that vivi implements: 1) kernel alloced memory. This is also used by read() method. On this case, a vmalloc32 buffer is allocated at kernel; 2) userspace allocated memory. This is used by most userspace apps. video-buf will store this pointer. a simple copy_to_user is enough to transfer data. The third memory model scenario supported by video-buf is overlay mode. This model is not implemented on vivi and unlikely to be implemented on newer drivers, since now, most userspace apps do some post-processing (like de-interlacing). After this patch, some cleanups may be done at video-buf.c to avoid allocating pages, when the driver doesn't need a PCI buffer. This is the case of vivi and usb drivers. Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r--drivers/media/video/video-buf.c3
-rw-r--r--drivers/media/video/vivi.c83
-rw-r--r--include/media/video-buf.h3
3 files changed, 78 insertions, 11 deletions
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
index 6504a5866849..459786ff459a 100644
--- a/drivers/media/video/video-buf.c
+++ b/drivers/media/video/video-buf.c
@@ -148,6 +148,8 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
148 dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", 148 dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
149 data,size,dma->nr_pages); 149 data,size,dma->nr_pages);
150 150
151 dma->varea = (void *) data;
152
151 down_read(&current->mm->mmap_sem); 153 down_read(&current->mm->mmap_sem);
152 err = get_user_pages(current,current->mm, 154 err = get_user_pages(current,current->mm,
153 data & PAGE_MASK, dma->nr_pages, 155 data & PAGE_MASK, dma->nr_pages,
@@ -285,6 +287,7 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma)
285 287
286 vfree(dma->vmalloc); 288 vfree(dma->vmalloc);
287 dma->vmalloc = NULL; 289 dma->vmalloc = NULL;
290 dma->varea = NULL;
288 291
289 if (dma->bus_addr) { 292 if (dma->bus_addr) {
290 dma->bus_addr = 0; 293 dma->bus_addr = 0;
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 178441922738..0fb6d520d1d0 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -145,7 +145,9 @@ struct vivi_buffer {
145 145
146 struct vivi_fmt *fmt; 146 struct vivi_fmt *fmt;
147 147
148#ifdef CONFIG_VIVI_SCATTER
148 struct sg_to_addr *to_addr; 149 struct sg_to_addr *to_addr;
150#endif
149}; 151};
150 152
151struct vivi_dmaqueue { 153struct vivi_dmaqueue {
@@ -230,6 +232,7 @@ static u8 bars[8][3] = {
230#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15 232#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
231#define TSTAMP_MIN_X 64 233#define TSTAMP_MIN_X 64
232 234
235#ifdef CONFIG_VIVI_SCATTER
233static void prep_to_addr(struct sg_to_addr to_addr[], 236static void prep_to_addr(struct sg_to_addr to_addr[],
234 struct videobuf_buffer *vb) 237 struct videobuf_buffer *vb)
235{ 238{
@@ -262,14 +265,24 @@ static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
262 265
263 return (p1); 266 return (p1);
264} 267}
268#endif
265 269
270#ifdef CONFIG_VIVI_SCATTER
266static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, 271static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
267 int hmax, int line, char *timestr) 272 int hmax, int line, char *timestr)
273#else
274static void gen_line(char *basep,int inipos,int wmax,
275 int hmax, int line, char *timestr)
276#endif
268{ 277{
269 int w,i,j,pos=inipos,pgpos,oldpg,y; 278 int w,i,j,pos=inipos,y;
270 char *p,*s,*basep; 279 char *p,*s;
271 struct page *pg;
272 u8 chr,r,g,b,color; 280 u8 chr,r,g,b,color;
281#ifdef CONFIG_VIVI_SCATTER
282 int pgpos,oldpg;
283 char *basep;
284 struct page *pg;
285
273 unsigned long flags; 286 unsigned long flags;
274 spinlock_t spinlock; 287 spinlock_t spinlock;
275 288
@@ -280,6 +293,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
280 pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT); 293 pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT);
281 spin_lock_irqsave(&spinlock,flags); 294 spin_lock_irqsave(&spinlock,flags);
282 basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset; 295 basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
296#endif
283 297
284 /* We will just duplicate the second pixel at the packet */ 298 /* We will just duplicate the second pixel at the packet */
285 wmax/=2; 299 wmax/=2;
@@ -291,6 +305,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
291 b=bars[w*7/wmax][2]; 305 b=bars[w*7/wmax][2];
292 306
293 for (color=0;color<4;color++) { 307 for (color=0;color<4;color++) {
308#ifdef CONFIG_VIVI_SCATTER
294 pgpos=get_addr_pos(pos,pages,to_addr); 309 pgpos=get_addr_pos(pos,pages,to_addr);
295 if (pgpos!=oldpg) { 310 if (pgpos!=oldpg) {
296 pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT); 311 pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT);
@@ -299,6 +314,9 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
299 oldpg=pgpos; 314 oldpg=pgpos;
300 } 315 }
301 p=basep+pos-to_addr[pgpos].pos; 316 p=basep+pos-to_addr[pgpos].pos;
317#else
318 p=basep+pos;
319#endif
302 320
303 switch (color) { 321 switch (color) {
304 case 0: 322 case 0:
@@ -343,6 +361,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
343 361
344 pos=inipos+j*2; 362 pos=inipos+j*2;
345 for (color=0;color<4;color++) { 363 for (color=0;color<4;color++) {
364#ifdef CONFIG_VIVI_SCATTER
346 pgpos=get_addr_pos(pos,pages,to_addr); 365 pgpos=get_addr_pos(pos,pages,to_addr);
347 if (pgpos!=oldpg) { 366 if (pgpos!=oldpg) {
348 pg=pfn_to_page(sg_dma_address( 367 pg=pfn_to_page(sg_dma_address(
@@ -356,6 +375,9 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
356 oldpg=pgpos; 375 oldpg=pgpos;
357 } 376 }
358 p=basep+pos-to_addr[pgpos].pos; 377 p=basep+pos-to_addr[pgpos].pos;
378#else
379 p=basep+pos;
380#endif
359 381
360 y=TO_Y(r,g,b); 382 y=TO_Y(r,g,b);
361 383
@@ -380,19 +402,27 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
380 402
381 403
382end: 404end:
405#ifdef CONFIG_VIVI_SCATTER
383 kunmap_atomic(basep, KM_BOUNCE_READ); 406 kunmap_atomic(basep, KM_BOUNCE_READ);
384 spin_unlock_irqrestore(&spinlock,flags); 407 spin_unlock_irqrestore(&spinlock,flags);
385 408#else
409 return;
410#endif
386} 411}
387static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) 412static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
388{ 413{
389 int h,pos=0; 414 int h,pos=0;
390 int hmax = buf->vb.height; 415 int hmax = buf->vb.height;
391 int wmax = buf->vb.width; 416 int wmax = buf->vb.width;
392 struct videobuf_buffer *vb=&buf->vb;
393 struct sg_to_addr *to_addr=buf->to_addr;
394 struct timeval ts; 417 struct timeval ts;
418#ifdef CONFIG_VIVI_SCATTER
419 struct sg_to_addr *to_addr=buf->to_addr;
420 struct videobuf_buffer *vb=&buf->vb;
421#else
422 char *tmpbuf;
423#endif
395 424
425#ifdef CONFIG_VIVI_SCATTER
396 /* Test if DMA mapping is ready */ 426 /* Test if DMA mapping is ready */
397 if (!sg_dma_address(&vb->dma.sglist[0])) 427 if (!sg_dma_address(&vb->dma.sglist[0]))
398 return; 428 return;
@@ -401,9 +431,27 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
401 431
402 /* Check if there is enough memory */ 432 /* Check if there is enough memory */
403 BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2); 433 BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2);
434#else
435 if (buf->vb.dma.varea) {
436 tmpbuf=kmalloc (wmax*2, GFP_KERNEL);
437 } else {
438 tmpbuf=buf->vb.dma.vmalloc;
439 }
440
441#endif
404 442
405 for (h=0;h<hmax;h++) { 443 for (h=0;h<hmax;h++) {
444#ifdef CONFIG_VIVI_SCATTER
406 gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr); 445 gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr);
446#else
447 if (buf->vb.dma.varea) {
448 gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr);
449 /* FIXME: replacing to __copy_to_user */
450 copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2);
451 } else {
452 gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr);
453 }
454#endif
407 pos += wmax*2; 455 pos += wmax*2;
408 } 456 }
409 457
@@ -429,7 +477,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
429 dev->h,dev->m,dev->s,(dev->us+500)/1000); 477 dev->h,dev->m,dev->s,(dev->us+500)/1000);
430 478
431 dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, 479 dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr,
432 (unsigned long)buf->vb.dma.vmalloc,pos); 480 (unsigned long)buf->vb.dma.varea,pos);
433 481
434 /* Advice that buffer was filled */ 482 /* Advice that buffer was filled */
435 buf->vb.state = STATE_DONE; 483 buf->vb.state = STATE_DONE;
@@ -668,9 +716,11 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
668 if (in_interrupt()) 716 if (in_interrupt())
669 BUG(); 717 BUG();
670 718
719#ifdef CONFIG_VIVI_SCATTER
671 /*FIXME: Maybe a spinlock is required here */ 720 /*FIXME: Maybe a spinlock is required here */
672 kfree(buf->to_addr); 721 kfree(buf->to_addr);
673 buf->to_addr=NULL; 722 buf->to_addr=NULL;
723#endif
674 724
675 videobuf_waiton(&buf->vb,0,0); 725 videobuf_waiton(&buf->vb,0,0);
676 videobuf_dma_unmap(vq, &buf->vb.dma); 726 videobuf_dma_unmap(vq, &buf->vb.dma);
@@ -716,11 +766,12 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
716 766
717 buf->vb.state = STATE_PREPARED; 767 buf->vb.state = STATE_PREPARED;
718 768
769#ifdef CONFIG_VIVI_SCATTER
719 if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) { 770 if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) {
720 rc=-ENOMEM; 771 rc=-ENOMEM;
721 goto fail; 772 goto fail;
722 } 773 }
723 774#endif
724 return 0; 775 return 0;
725 776
726fail: 777fail:
@@ -785,6 +836,7 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb
785 free_buffer(vq,buf); 836 free_buffer(vq,buf);
786} 837}
787 838
839#ifdef CONFIG_VIVI_SCATTER
788static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents, 840static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
789 int direction) 841 int direction)
790{ 842{
@@ -817,6 +869,7 @@ static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
817// flush_write_buffers(); 869// flush_write_buffers();
818 return 0; 870 return 0;
819} 871}
872#endif
820 873
821static struct videobuf_queue_ops vivi_video_qops = { 874static struct videobuf_queue_ops vivi_video_qops = {
822 .buf_setup = buffer_setup, 875 .buf_setup = buffer_setup,
@@ -825,9 +878,9 @@ static struct videobuf_queue_ops vivi_video_qops = {
825 .buf_release = buffer_release, 878 .buf_release = buffer_release,
826 879
827 /* Non-pci handling routines */ 880 /* Non-pci handling routines */
828 .vb_map_sg = vivi_map_sg, 881// .vb_map_sg = vivi_map_sg,
829 .vb_dma_sync_sg = vivi_dma_sync_sg, 882// .vb_dma_sync_sg = vivi_dma_sync_sg,
830 .vb_unmap_sg = vivi_unmap_sg, 883// .vb_unmap_sg = vivi_unmap_sg,
831}; 884};
832 885
833/* ------------------------------------------------------------------ 886/* ------------------------------------------------------------------
@@ -1205,11 +1258,19 @@ static int vivi_open(struct inode *inode, struct file *file)
1205 sprintf(dev->timestr,"%02d:%02d:%02d:%03d", 1258 sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
1206 dev->h,dev->m,dev->s,(dev->us+500)/1000); 1259 dev->h,dev->m,dev->s,(dev->us+500)/1000);
1207 1260
1261#ifdef CONFIG_VIVI_SCATTER
1262 videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops,
1263 NULL, NULL,
1264 fh->type,
1265 V4L2_FIELD_INTERLACED,
1266 sizeof(struct vivi_buffer),fh);
1267#else
1208 videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops, 1268 videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops,
1209 NULL, NULL, 1269 NULL, NULL,
1210 fh->type, 1270 fh->type,
1211 V4L2_FIELD_INTERLACED, 1271 V4L2_FIELD_INTERLACED,
1212 sizeof(struct vivi_buffer),fh); 1272 sizeof(struct vivi_buffer),fh);
1273#endif
1213 1274
1214 return 0; 1275 return 0;
1215} 1276}
diff --git a/include/media/video-buf.h b/include/media/video-buf.h
index 1115a256969f..d6f079476db3 100644
--- a/include/media/video-buf.h
+++ b/include/media/video-buf.h
@@ -78,6 +78,9 @@ struct videobuf_dmabuf {
78 /* for kernel buffers */ 78 /* for kernel buffers */
79 void *vmalloc; 79 void *vmalloc;
80 80
81 /* Stores the userspace pointer to vmalloc area */
82 void *varea;
83
81 /* for overlay buffers (pci-pci dma) */ 84 /* for overlay buffers (pci-pci dma) */
82 dma_addr_t bus_addr; 85 dma_addr_t bus_addr;
83 86