Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+78 -11
+3
drivers/media/video/video-buf.c
··· 148 148 dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", 149 149 data,size,dma->nr_pages); 150 150 151 + dma->varea = (void *) data; 152 + 151 153 down_read(&current->mm->mmap_sem); 152 154 err = get_user_pages(current,current->mm, 153 155 data & PAGE_MASK, dma->nr_pages, ··· 287 285 288 286 vfree(dma->vmalloc); 289 287 dma->vmalloc = NULL; 288 + dma->varea = NULL; 290 289 291 290 if (dma->bus_addr) { 292 291 dma->bus_addr = 0;
+72 -11
drivers/media/video/vivi.c
··· 145 145 146 146 struct vivi_fmt *fmt; 147 147 148 + #ifdef CONFIG_VIVI_SCATTER 148 149 struct sg_to_addr *to_addr; 150 + #endif 149 151 }; 150 152 151 153 struct vivi_dmaqueue { ··· 232 230 #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15 233 231 #define TSTAMP_MIN_X 64 234 232 233 + #ifdef CONFIG_VIVI_SCATTER 235 234 static void prep_to_addr(struct sg_to_addr to_addr[], 236 235 struct videobuf_buffer *vb) 237 236 { ··· 265 262 266 263 return (p1); 267 264 } 265 + #endif 268 266 267 + #ifdef CONFIG_VIVI_SCATTER 269 268 static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, 270 269 int hmax, int line, char *timestr) 270 + #else 271 + static void gen_line(char *basep,int inipos,int wmax, 272 + int hmax, int line, char *timestr) 273 + #endif 271 274 { 272 - int w,i,j,pos=inipos,pgpos,oldpg,y; 273 - char *p,*s,*basep; 274 - struct page *pg; 275 + int w,i,j,pos=inipos,y; 276 + char *p,*s; 275 277 u8 chr,r,g,b,color; 278 + #ifdef CONFIG_VIVI_SCATTER 279 + int pgpos,oldpg; 280 + char *basep; 281 + struct page *pg; 282 + 276 283 unsigned long flags; 277 284 spinlock_t spinlock; 278 285 ··· 293 280 pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT); 294 281 spin_lock_irqsave(&spinlock,flags); 295 282 basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset; 283 + #endif 296 284 297 285 /* We will just duplicate the second pixel at the packet */ 298 286 wmax/=2; ··· 305 291 b=bars[w*7/wmax][2]; 306 292 307 293 for (color=0;color<4;color++) { 294 + #ifdef CONFIG_VIVI_SCATTER 308 295 pgpos=get_addr_pos(pos,pages,to_addr); 309 296 if (pgpos!=oldpg) { 310 297 pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT); ··· 314 299 oldpg=pgpos; 315 300 } 316 301 p=basep+pos-to_addr[pgpos].pos; 302 + #else 303 + p=basep+pos; 304 + #endif 317 305 318 306 switch (color) { 319 307 case 0: ··· 361 343 362 344 pos=inipos+j*2; 363 345 for (color=0;color<4;color++) { 346 + #ifdef CONFIG_VIVI_SCATTER 364 347 pgpos=get_addr_pos(pos,pages,to_addr); 365 348 if (pgpos!=oldpg) { 366 349 pg=pfn_to_page(sg_dma_address( ··· 375 356 oldpg=pgpos; 376 357 } 377 358 p=basep+pos-to_addr[pgpos].pos; 359 + #else 360 + p=basep+pos; 361 + #endif 378 362 379 363 y=TO_Y(r,g,b); 380 364 ··· 402 380 403 381 404 382 end: 383 + #ifdef CONFIG_VIVI_SCATTER 405 384 kunmap_atomic(basep, KM_BOUNCE_READ); 406 385 spin_unlock_irqrestore(&spinlock,flags); 407 - 386 + #else 387 + return; 388 + #endif 408 389 } 409 390 static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) 410 391 { 411 392 int h,pos=0; 412 393 int hmax = buf->vb.height; 413 394 int wmax = buf->vb.width; 414 - struct videobuf_buffer *vb=&buf->vb; 415 - struct sg_to_addr *to_addr=buf->to_addr; 416 395 struct timeval ts; 396 + #ifdef CONFIG_VIVI_SCATTER 397 + struct sg_to_addr *to_addr=buf->to_addr; 398 + struct videobuf_buffer *vb=&buf->vb; 399 + #else 400 + char *tmpbuf; 401 + #endif 417 402 403 + #ifdef CONFIG_VIVI_SCATTER 418 404 /* Test if DMA mapping is ready */ 419 405 if (!sg_dma_address(&vb->dma.sglist[0])) 420 406 return; ··· 431 401 432 402 /* Check if there is enough memory */ 433 403 BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2); 404 + #else 405 + if (buf->vb.dma.varea) { 406 + tmpbuf=kmalloc (wmax*2, GFP_KERNEL); 407 + } else { 408 + tmpbuf=buf->vb.dma.vmalloc; 409 + } 410 + 411 + #endif 434 412 435 413 for (h=0;h<hmax;h++) { 414 + #ifdef CONFIG_VIVI_SCATTER 436 415 gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr); 416 + #else 417 + if (buf->vb.dma.varea) { 418 + gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr); 419 + /* FIXME: replacing to __copy_to_user */ 420 + copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2); 421 + } else { 422 + gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr); 423 + } 424 + #endif 437 425 pos += wmax*2; 438 426 } 439 427 ··· 477 429 dev->h,dev->m,dev->s,(dev->us+500)/1000); 478 430 479 431 dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, 480 - (unsigned long)buf->vb.dma.vmalloc,pos); 432 + (unsigned long)buf->vb.dma.varea,pos); 481 433 482 434 /* Advice that buffer was filled */ 483 435 buf->vb.state = STATE_DONE; ··· 716 668 if (in_interrupt()) 717 669 BUG(); 718 670 671 + #ifdef CONFIG_VIVI_SCATTER 719 672 /*FIXME: Maybe a spinlock is required here */ 720 673 kfree(buf->to_addr); 721 674 buf->to_addr=NULL; 675 + #endif 722 676 723 677 videobuf_waiton(&buf->vb,0,0); 724 678 videobuf_dma_unmap(vq, &buf->vb.dma); ··· 766 716 767 717 buf->vb.state = STATE_PREPARED; 768 718 719 + #ifdef CONFIG_VIVI_SCATTER 769 720 if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) { 770 721 rc=-ENOMEM; 771 722 goto fail; 772 723 } 773 - 724 + #endif 774 725 return 0; 775 726 776 727 fail: ··· 836 785 free_buffer(vq,buf); 837 786 } 838 787 788 + #ifdef CONFIG_VIVI_SCATTER 839 789 static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents, 840 790 int direction) 841 791 { ··· 869 817 // flush_write_buffers(); 870 818 return 0; 871 819 } 820 + #endif 872 821 873 822 static struct videobuf_queue_ops vivi_video_qops = { 874 823 .buf_setup = buffer_setup, ··· 878 825 .buf_release = buffer_release, 879 826 880 827 /* Non-pci handling routines */ 881 - .vb_map_sg = vivi_map_sg, 882 - .vb_dma_sync_sg = vivi_dma_sync_sg, 883 - .vb_unmap_sg = vivi_unmap_sg, 828 + // .vb_map_sg = vivi_map_sg, 829 + // .vb_dma_sync_sg = vivi_dma_sync_sg, 830 + // .vb_unmap_sg = vivi_unmap_sg, 884 831 }; 885 832 886 833 /* ------------------------------------------------------------------ ··· 1258 1205 sprintf(dev->timestr,"%02d:%02d:%02d:%03d", 1259 1206 dev->h,dev->m,dev->s,(dev->us+500)/1000); 1260 1207 1208 + #ifdef CONFIG_VIVI_SCATTER 1209 + videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops, 1210 + NULL, NULL, 1211 + fh->type, 1212 + V4L2_FIELD_INTERLACED, 1213 + sizeof(struct vivi_buffer),fh); 1214 + #else 1261 1215 videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops, 1262 1216 NULL, NULL, 1263 1217 fh->type, 1264 1218 V4L2_FIELD_INTERLACED, 1265 1219 sizeof(struct vivi_buffer),fh); 1220 + #endif 1266 1221 1267 1222 return 0; 1268 1223 }
+3
include/media/video-buf.h
··· 78 78 /* for kernel buffers */ 79 79 void *vmalloc; 80 80 81 + /* Stores the userspace pointer to vmalloc area */ 82 + void *varea; 83 + 81 84 /* for overlay buffers (pci-pci dma) */ 82 85 dma_addr_t bus_addr; 83 86