2007-08-23 23:26:14 +04:00
/*
2008-04-22 21:42:13 +04:00
* helper functions for SG DMA video4linux capture buffers
2007-08-23 23:26:14 +04:00
*
2008-07-17 04:27:49 +04:00
* The functions expect the hardware being able to scatter gather
2007-08-23 23:26:14 +04:00
* ( i . e . the buffers are not linear in physical memory , but fragmented
* into PAGE_SIZE chunks ) . They also assume the driver does not need
* to touch the video data .
*
* ( c ) 2007 Mauro Carvalho Chehab , < mchehab @ infradead . org >
*
* Highly based on video - buf written originally by :
* ( c ) 2001 , 02 Gerd Knorr < kraxel @ bytesex . org >
* ( c ) 2006 Mauro Carvalho Chehab , < mchehab @ infradead . org >
* ( c ) 2006 Ted Walther and John Sokol
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
2009-10-07 17:09:06 +04:00
# include <linux/sched.h>
2007-08-23 23:26:14 +04:00
# include <linux/slab.h>
# include <linux/interrupt.h>
2008-04-22 21:42:13 +04:00
# include <linux/dma-mapping.h>
2007-08-23 23:26:14 +04:00
# include <linux/vmalloc.h>
# include <linux/pagemap.h>
2007-10-23 22:42:11 +04:00
# include <linux/scatterlist.h>
2007-08-23 23:26:14 +04:00
# include <asm/page.h>
# include <asm/pgtable.h>
# include <media/videobuf-dma-sg.h>
# define MAGIC_DMABUF 0x19721112
# define MAGIC_SG_MEM 0x17890714
2010-03-17 10:01:04 +03:00
# define MAGIC_CHECK(is, should) \
if ( unlikely ( ( is ) ! = ( should ) ) ) { \
printk ( KERN_ERR " magic mismatch: %x (expected %x) \n " , \
is , should ) ; \
BUG ( ) ; \
}
2007-08-23 23:26:14 +04:00
2008-04-22 21:41:48 +04:00
static int debug ;
2007-08-23 23:26:14 +04:00
module_param ( debug , int , 0644 ) ;
2008-04-22 21:42:13 +04:00
MODULE_DESCRIPTION ( " helper module to manage video4linux dma sg buffers " ) ;
2007-08-23 23:26:14 +04:00
MODULE_AUTHOR ( " Mauro Carvalho Chehab <mchehab@infradead.org> " ) ;
MODULE_LICENSE ( " GPL " ) ;
2010-03-17 10:01:04 +03:00
# define dprintk(level, fmt, arg...) \
if ( debug > = level ) \
printk ( KERN_DEBUG " vbuf-sg: " fmt , # # arg )
2007-08-23 23:26:14 +04:00
/* --------------------------------------------------------------------- */
2010-05-11 17:36:32 +04:00
/*
* Return a scatterlist for some page - aligned vmalloc ( ) ' ed memory
* block ( NULL on errors ) . Memory for the scatterlist is allocated
* using kmalloc . The caller must free the memory .
*/
static struct scatterlist * videobuf_vmalloc_to_sg ( unsigned char * virt ,
int nr_pages )
2007-08-23 23:26:14 +04:00
{
struct scatterlist * sglist ;
struct page * pg ;
int i ;
2010-11-05 06:07:39 +03:00
sglist = vzalloc ( nr_pages * sizeof ( * sglist ) ) ;
2007-08-23 23:26:14 +04:00
if ( NULL = = sglist )
return NULL ;
2007-10-22 23:19:53 +04:00
sg_init_table ( sglist , nr_pages ) ;
2007-08-23 23:26:14 +04:00
for ( i = 0 ; i < nr_pages ; i + + , virt + = PAGE_SIZE ) {
pg = vmalloc_to_page ( virt ) ;
if ( NULL = = pg )
goto err ;
BUG_ON ( PageHighMem ( pg ) ) ;
2007-10-24 13:20:47 +04:00
sg_set_page ( & sglist [ i ] , pg , PAGE_SIZE , 0 ) ;
2007-08-23 23:26:14 +04:00
}
return sglist ;
2010-03-17 10:01:04 +03:00
err :
2009-05-11 18:00:20 +04:00
vfree ( sglist ) ;
2007-08-23 23:26:14 +04:00
return NULL ;
}
2010-05-11 17:36:32 +04:00
/*
* Return a scatterlist for a an array of userpages ( NULL on errors ) .
* Memory for the scatterlist is allocated using kmalloc . The caller
* must free the memory .
*/
static struct scatterlist * videobuf_pages_to_sg ( struct page * * pages ,
2010-09-07 13:10:45 +04:00
int nr_pages , int offset , size_t size )
2007-08-23 23:26:14 +04:00
{
struct scatterlist * sglist ;
2008-07-04 13:33:22 +04:00
int i ;
2007-08-23 23:26:14 +04:00
if ( NULL = = pages [ 0 ] )
return NULL ;
2009-05-11 18:00:20 +04:00
sglist = vmalloc ( nr_pages * sizeof ( * sglist ) ) ;
2007-08-23 23:26:14 +04:00
if ( NULL = = sglist )
return NULL ;
2007-10-22 23:19:53 +04:00
sg_init_table ( sglist , nr_pages ) ;
2007-08-23 23:26:14 +04:00
if ( PageHighMem ( pages [ 0 ] ) )
/* DMA to highmem pages might not work */
goto highmem ;
2011-04-19 18:54:54 +04:00
sg_set_page ( & sglist [ 0 ] , pages [ 0 ] ,
min_t ( size_t , PAGE_SIZE - offset , size ) , offset ) ;
size - = min_t ( size_t , PAGE_SIZE - offset , size ) ;
2007-08-23 23:26:14 +04:00
for ( i = 1 ; i < nr_pages ; i + + ) {
if ( NULL = = pages [ i ] )
goto nopage ;
if ( PageHighMem ( pages [ i ] ) )
goto highmem ;
2010-10-07 16:31:33 +04:00
sg_set_page ( & sglist [ i ] , pages [ i ] , min_t ( size_t , PAGE_SIZE , size ) , 0 ) ;
size - = min_t ( size_t , PAGE_SIZE , size ) ;
2007-08-23 23:26:14 +04:00
}
return sglist ;
2010-03-17 10:01:04 +03:00
nopage :
dprintk ( 2 , " sgl: oops - no page \n " ) ;
2009-05-11 18:00:20 +04:00
vfree ( sglist ) ;
2007-08-23 23:26:14 +04:00
return NULL ;
2010-03-17 10:01:04 +03:00
highmem :
dprintk ( 2 , " sgl: oops - highmem page \n " ) ;
2009-05-11 18:00:20 +04:00
vfree ( sglist ) ;
2007-08-23 23:26:14 +04:00
return NULL ;
}
/* --------------------------------------------------------------------- */
2010-03-17 10:01:04 +03:00
struct videobuf_dmabuf * videobuf_to_dma ( struct videobuf_buffer * buf )
2007-08-23 23:26:14 +04:00
{
2008-04-22 21:42:13 +04:00
struct videobuf_dma_sg_memory * mem = buf - > priv ;
BUG_ON ( ! mem ) ;
2007-08-23 23:26:14 +04:00
2008-04-22 21:42:13 +04:00
MAGIC_CHECK ( mem - > magic , MAGIC_SG_MEM ) ;
2007-08-23 23:26:14 +04:00
return & mem - > dma ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_to_dma ) ;
2007-08-23 23:26:14 +04:00
void videobuf_dma_init ( struct videobuf_dmabuf * dma )
{
2010-03-17 10:01:04 +03:00
memset ( dma , 0 , sizeof ( * dma ) ) ;
2007-08-23 23:26:14 +04:00
dma - > magic = MAGIC_DMABUF ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_dma_init ) ;
2007-08-23 23:26:14 +04:00
2007-09-28 03:34:09 +04:00
static int videobuf_dma_init_user_locked ( struct videobuf_dmabuf * dma ,
int direction , unsigned long data , unsigned long size )
2007-08-23 23:26:14 +04:00
{
2010-03-17 10:01:04 +03:00
unsigned long first , last ;
2007-08-23 23:26:14 +04:00
int err , rw = 0 ;
dma - > direction = direction ;
switch ( dma - > direction ) {
2008-04-22 21:42:13 +04:00
case DMA_FROM_DEVICE :
rw = READ ;
break ;
case DMA_TO_DEVICE :
rw = WRITE ;
break ;
default :
BUG ( ) ;
2007-08-23 23:26:14 +04:00
}
first = ( data & PAGE_MASK ) > > PAGE_SHIFT ;
last = ( ( data + size - 1 ) & PAGE_MASK ) > > PAGE_SHIFT ;
2010-09-07 13:10:45 +04:00
dma - > offset = data & ~ PAGE_MASK ;
dma - > size = size ;
2007-08-23 23:26:14 +04:00
dma - > nr_pages = last - first + 1 ;
2010-03-17 10:01:04 +03:00
dma - > pages = kmalloc ( dma - > nr_pages * sizeof ( struct page * ) , GFP_KERNEL ) ;
2007-08-23 23:26:14 +04:00
if ( NULL = = dma - > pages )
return - ENOMEM ;
2010-03-17 10:01:04 +03:00
dprintk ( 1 , " init user [0x%lx+0x%lx => %d pages] \n " ,
data , size , dma - > nr_pages ) ;
err = get_user_pages ( current , current - > mm ,
2007-08-23 23:26:14 +04:00
data & PAGE_MASK , dma - > nr_pages ,
rw = = READ , 1 , /* force */
dma - > pages , NULL ) ;
2007-09-28 03:34:09 +04:00
2007-08-23 23:26:14 +04:00
if ( err ! = dma - > nr_pages ) {
dma - > nr_pages = ( err > = 0 ) ? err : 0 ;
2010-03-17 10:01:04 +03:00
dprintk ( 1 , " get_user_pages: err=%d [%d] \n " , err , dma - > nr_pages ) ;
2007-08-23 23:26:14 +04:00
return err < 0 ? err : - EINVAL ;
}
return 0 ;
}
2007-09-28 03:34:09 +04:00
int videobuf_dma_init_user ( struct videobuf_dmabuf * dma , int direction ,
unsigned long data , unsigned long size )
{
int ret ;
2010-03-17 10:01:04 +03:00
2007-09-28 03:34:09 +04:00
down_read ( & current - > mm - > mmap_sem ) ;
ret = videobuf_dma_init_user_locked ( dma , direction , data , size ) ;
up_read ( & current - > mm - > mmap_sem ) ;
return ret ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_dma_init_user ) ;
2007-09-28 03:34:09 +04:00
2007-08-23 23:26:14 +04:00
int videobuf_dma_init_kernel ( struct videobuf_dmabuf * dma , int direction ,
int nr_pages )
{
2010-03-17 10:01:04 +03:00
dprintk ( 1 , " init kernel [%d pages] \n " , nr_pages ) ;
2007-08-23 23:26:14 +04:00
dma - > direction = direction ;
2010-05-11 17:36:34 +04:00
dma - > vaddr = vmalloc_32 ( nr_pages < < PAGE_SHIFT ) ;
if ( NULL = = dma - > vaddr ) {
2010-03-17 10:01:04 +03:00
dprintk ( 1 , " vmalloc_32(%d pages) failed \n " , nr_pages ) ;
2007-08-23 23:26:14 +04:00
return - ENOMEM ;
}
2010-03-17 10:01:04 +03:00
dprintk ( 1 , " vmalloc is at addr 0x%08lx, size=%d \n " ,
2010-05-11 17:36:34 +04:00
( unsigned long ) dma - > vaddr ,
2007-08-23 23:26:14 +04:00
nr_pages < < PAGE_SHIFT ) ;
2010-03-17 10:01:04 +03:00
2010-05-11 17:36:34 +04:00
memset ( dma - > vaddr , 0 , nr_pages < < PAGE_SHIFT ) ;
2007-08-23 23:26:14 +04:00
dma - > nr_pages = nr_pages ;
2010-03-17 10:01:04 +03:00
2007-08-23 23:26:14 +04:00
return 0 ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_dma_init_kernel ) ;
2007-08-23 23:26:14 +04:00
int videobuf_dma_init_overlay ( struct videobuf_dmabuf * dma , int direction ,
dma_addr_t addr , int nr_pages )
{
2010-03-17 10:01:04 +03:00
dprintk ( 1 , " init overlay [%d pages @ bus 0x%lx] \n " ,
nr_pages , ( unsigned long ) addr ) ;
2007-08-23 23:26:14 +04:00
dma - > direction = direction ;
2010-03-17 10:01:04 +03:00
2007-08-23 23:26:14 +04:00
if ( 0 = = addr )
return - EINVAL ;
dma - > bus_addr = addr ;
dma - > nr_pages = nr_pages ;
2010-03-17 10:01:04 +03:00
2007-08-23 23:26:14 +04:00
return 0 ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_dma_init_overlay ) ;
2007-08-23 23:26:14 +04:00
2010-05-11 17:36:30 +04:00
int videobuf_dma_map ( struct device * dev , struct videobuf_dmabuf * dma )
2007-08-23 23:26:14 +04:00
{
2010-03-17 10:01:04 +03:00
MAGIC_CHECK ( dma - > magic , MAGIC_DMABUF ) ;
2007-08-23 23:26:14 +04:00
BUG_ON ( 0 = = dma - > nr_pages ) ;
if ( dma - > pages ) {
dma - > sglist = videobuf_pages_to_sg ( dma - > pages , dma - > nr_pages ,
2010-09-07 13:10:45 +04:00
dma - > offset , dma - > size ) ;
2007-08-23 23:26:14 +04:00
}
2010-05-11 17:36:34 +04:00
if ( dma - > vaddr ) {
dma - > sglist = videobuf_vmalloc_to_sg ( dma - > vaddr ,
2010-03-17 10:01:04 +03:00
dma - > nr_pages ) ;
2007-08-23 23:26:14 +04:00
}
if ( dma - > bus_addr ) {
2009-05-11 18:00:20 +04:00
dma - > sglist = vmalloc ( sizeof ( * dma - > sglist ) ) ;
2007-08-23 23:26:14 +04:00
if ( NULL ! = dma - > sglist ) {
2010-03-17 10:01:04 +03:00
dma - > sglen = 1 ;
sg_dma_address ( & dma - > sglist [ 0 ] ) = dma - > bus_addr
& PAGE_MASK ;
dma - > sglist [ 0 ] . offset = dma - > bus_addr & ~ PAGE_MASK ;
sg_dma_len ( & dma - > sglist [ 0 ] ) = dma - > nr_pages * PAGE_SIZE ;
2007-08-23 23:26:14 +04:00
}
}
if ( NULL = = dma - > sglist ) {
2010-03-17 10:01:04 +03:00
dprintk ( 1 , " scatterlist is NULL \n " ) ;
2007-08-23 23:26:14 +04:00
return - ENOMEM ;
}
if ( ! dma - > bus_addr ) {
2010-05-11 17:36:30 +04:00
dma - > sglen = dma_map_sg ( dev , dma - > sglist ,
2007-08-23 23:26:14 +04:00
dma - > nr_pages , dma - > direction ) ;
if ( 0 = = dma - > sglen ) {
printk ( KERN_WARNING
2010-03-17 10:01:04 +03:00
" %s: videobuf_map_sg failed \n " , __func__ ) ;
2009-05-11 18:00:20 +04:00
vfree ( dma - > sglist ) ;
2007-08-23 23:26:14 +04:00
dma - > sglist = NULL ;
dma - > sglen = 0 ;
2009-06-11 06:17:27 +04:00
return - ENOMEM ;
2007-08-23 23:26:14 +04:00
}
}
2010-03-17 10:01:04 +03:00
2007-08-23 23:26:14 +04:00
return 0 ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_dma_map ) ;
2007-08-23 23:26:14 +04:00
2010-05-11 17:36:30 +04:00
int videobuf_dma_unmap ( struct device * dev , struct videobuf_dmabuf * dma )
2007-08-23 23:26:14 +04:00
{
2008-04-22 21:42:13 +04:00
MAGIC_CHECK ( dma - > magic , MAGIC_DMABUF ) ;
2010-03-17 10:01:04 +03:00
2007-08-23 23:26:14 +04:00
if ( ! dma - > sglen )
return 0 ;
2010-05-11 17:36:30 +04:00
dma_unmap_sg ( dev , dma - > sglist , dma - > sglen , dma - > direction ) ;
2007-10-08 18:43:49 +04:00
2009-05-11 18:00:20 +04:00
vfree ( dma - > sglist ) ;
2007-08-23 23:26:14 +04:00
dma - > sglist = NULL ;
dma - > sglen = 0 ;
2010-03-17 10:01:04 +03:00
2007-08-23 23:26:14 +04:00
return 0 ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_dma_unmap ) ;
2007-08-23 23:26:14 +04:00
int videobuf_dma_free ( struct videobuf_dmabuf * dma )
{
2010-03-17 10:01:04 +03:00
int i ;
MAGIC_CHECK ( dma - > magic , MAGIC_DMABUF ) ;
2007-08-23 23:26:14 +04:00
BUG_ON ( dma - > sglen ) ;
if ( dma - > pages ) {
2010-03-17 10:01:04 +03:00
for ( i = 0 ; i < dma - > nr_pages ; i + + )
2007-08-23 23:26:14 +04:00
page_cache_release ( dma - > pages [ i ] ) ;
kfree ( dma - > pages ) ;
dma - > pages = NULL ;
}
2010-05-11 17:36:34 +04:00
vfree ( dma - > vaddr ) ;
dma - > vaddr = NULL ;
2007-08-23 23:26:14 +04:00
2010-03-17 10:01:04 +03:00
if ( dma - > bus_addr )
2007-08-23 23:26:14 +04:00
dma - > bus_addr = 0 ;
2008-04-22 21:42:13 +04:00
dma - > direction = DMA_NONE ;
2010-03-17 10:01:04 +03:00
2007-08-23 23:26:14 +04:00
return 0 ;
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_dma_free ) ;
2007-08-23 23:26:14 +04:00
/* --------------------------------------------------------------------- */
2010-03-17 10:01:04 +03:00
static void videobuf_vm_open ( struct vm_area_struct * vma )
2007-08-23 23:26:14 +04:00
{
struct videobuf_mapping * map = vma - > vm_private_data ;
2013-05-09 22:03:33 +04:00
struct videobuf_queue * q = map - > q ;
2007-08-23 23:26:14 +04:00
2010-03-17 10:01:04 +03:00
dprintk ( 2 , " vm_open %p [count=%d,vma=%08lx-%08lx] \n " , map ,
map - > count , vma - > vm_start , vma - > vm_end ) ;
2013-05-09 22:03:33 +04:00
videobuf_queue_lock ( q ) ;
2007-08-23 23:26:14 +04:00
map - > count + + ;
2013-05-09 22:03:33 +04:00
videobuf_queue_unlock ( q ) ;
2007-08-23 23:26:14 +04:00
}
2010-03-17 10:01:04 +03:00
static void videobuf_vm_close ( struct vm_area_struct * vma )
2007-08-23 23:26:14 +04:00
{
struct videobuf_mapping * map = vma - > vm_private_data ;
struct videobuf_queue * q = map - > q ;
2008-04-22 21:42:13 +04:00
struct videobuf_dma_sg_memory * mem ;
2007-08-23 23:26:14 +04:00
int i ;
2010-03-17 10:01:04 +03:00
dprintk ( 2 , " vm_close %p [count=%d,vma=%08lx-%08lx] \n " , map ,
map - > count , vma - > vm_start , vma - > vm_end ) ;
2007-08-23 23:26:14 +04:00
2013-05-09 22:03:33 +04:00
videobuf_queue_lock ( q ) ;
if ( ! - - map - > count ) {
2010-03-17 10:01:04 +03:00
dprintk ( 1 , " munmap %p q=%p \n " , map , q ) ;
2007-08-23 23:26:14 +04:00
for ( i = 0 ; i < VIDEO_MAX_FRAME ; i + + ) {
if ( NULL = = q - > bufs [ i ] )
continue ;
2010-03-17 10:01:04 +03:00
mem = q - > bufs [ i ] - > priv ;
2007-08-23 23:26:14 +04:00
if ( ! mem )
continue ;
2010-03-17 10:01:04 +03:00
MAGIC_CHECK ( mem - > magic , MAGIC_SG_MEM ) ;
2007-08-23 23:26:14 +04:00
2007-09-28 01:25:44 +04:00
if ( q - > bufs [ i ] - > map ! = map )
2007-08-23 23:26:14 +04:00
continue ;
2007-09-28 01:25:44 +04:00
q - > bufs [ i ] - > map = NULL ;
2007-08-23 23:26:14 +04:00
q - > bufs [ i ] - > baddr = 0 ;
2010-03-17 10:01:04 +03:00
q - > ops - > buf_release ( q , q - > bufs [ i ] ) ;
2007-08-23 23:26:14 +04:00
}
kfree ( map ) ;
}
2013-05-09 22:03:33 +04:00
videobuf_queue_unlock ( q ) ;
2007-08-23 23:26:14 +04:00
return ;
}
/*
* Get a anonymous page for the mapping . Make sure we can DMA to that
* memory location with 32 bit PCI devices ( i . e . don ' t use highmem for
* now . . . ) . Bounce buffers don ' t work very well for the data rates
* video capture has .
*/
2010-03-17 10:01:04 +03:00
static int videobuf_vm_fault ( struct vm_area_struct * vma , struct vm_fault * vmf )
2007-08-23 23:26:14 +04:00
{
struct page * page ;
2010-03-17 10:01:04 +03:00
dprintk ( 3 , " fault: fault @ %08lx [vma %08lx-%08lx] \n " ,
( unsigned long ) vmf - > virtual_address ,
vma - > vm_start , vma - > vm_end ) ;
2007-08-23 23:26:14 +04:00
page = alloc_page ( GFP_USER | __GFP_DMA32 ) ;
if ( ! page )
2007-12-07 23:57:38 +03:00
return VM_FAULT_OOM ;
2009-01-04 00:20:04 +03:00
clear_user_highpage ( page , ( unsigned long ) vmf - > virtual_address ) ;
2007-12-07 23:57:38 +03:00
vmf - > page = page ;
2010-03-17 10:01:04 +03:00
2007-12-07 23:57:38 +03:00
return 0 ;
2007-08-23 23:26:14 +04:00
}
2010-03-17 10:01:04 +03:00
static const struct vm_operations_struct videobuf_vm_ops = {
. open = videobuf_vm_open ,
. close = videobuf_vm_close ,
. fault = videobuf_vm_fault ,
2007-08-23 23:26:14 +04:00
} ;
/* ---------------------------------------------------------------------
2008-04-22 21:42:13 +04:00
* SG handlers for the generic methods
2007-08-23 23:26:14 +04:00
*/
/* Allocated area consists on 3 parts:
struct video_buffer
struct < driver > _buffer ( cx88_buffer , saa7134_buf , . . . )
2008-04-22 21:42:13 +04:00
struct videobuf_dma_sg_memory
2007-08-23 23:26:14 +04:00
*/
2010-05-11 17:36:28 +04:00
static struct videobuf_buffer * __videobuf_alloc_vb ( size_t size )
2007-08-23 23:26:14 +04:00
{
2008-04-22 21:42:13 +04:00
struct videobuf_dma_sg_memory * mem ;
2007-08-23 23:26:14 +04:00
struct videobuf_buffer * vb ;
2010-03-17 10:01:04 +03:00
vb = kzalloc ( size + sizeof ( * mem ) , GFP_KERNEL ) ;
2010-02-22 19:10:06 +03:00
if ( ! vb )
return vb ;
2007-08-23 23:26:14 +04:00
2010-03-17 10:01:04 +03:00
mem = vb - > priv = ( ( char * ) vb ) + size ;
mem - > magic = MAGIC_SG_MEM ;
2007-08-23 23:26:14 +04:00
videobuf_dma_init ( & mem - > dma ) ;
2010-03-17 10:01:04 +03:00
dprintk ( 1 , " %s: allocated at %p(%ld+%ld) & %p(%ld) \n " ,
__func__ , vb , ( long ) sizeof ( * vb ) , ( long ) size - sizeof ( * vb ) ,
mem , ( long ) sizeof ( * mem ) ) ;
2007-08-23 23:26:14 +04:00
return vb ;
}
2010-03-28 15:18:37 +04:00
static void * __videobuf_to_vaddr ( struct videobuf_buffer * buf )
2008-04-13 22:10:00 +04:00
{
struct videobuf_dma_sg_memory * mem = buf - > priv ;
BUG_ON ( ! mem ) ;
MAGIC_CHECK ( mem - > magic , MAGIC_SG_MEM ) ;
2010-05-11 17:36:34 +04:00
return mem - > dma . vaddr ;
2008-04-13 22:10:00 +04:00
}
2010-03-17 10:01:04 +03:00
static int __videobuf_iolock ( struct videobuf_queue * q ,
struct videobuf_buffer * vb ,
struct v4l2_framebuffer * fbuf )
2007-08-23 23:26:14 +04:00
{
2010-03-17 10:01:04 +03:00
int err , pages ;
2007-08-23 23:26:14 +04:00
dma_addr_t bus ;
2008-04-22 21:42:13 +04:00
struct videobuf_dma_sg_memory * mem = vb - > priv ;
2007-08-23 23:26:14 +04:00
BUG_ON ( ! mem ) ;
2008-04-22 21:42:13 +04:00
MAGIC_CHECK ( mem - > magic , MAGIC_SG_MEM ) ;
2007-08-23 23:26:14 +04:00
switch ( vb - > memory ) {
case V4L2_MEMORY_MMAP :
case V4L2_MEMORY_USERPTR :
if ( 0 = = vb - > baddr ) {
/* no userspace addr -- kernel bounce buffer */
pages = PAGE_ALIGN ( vb - > size ) > > PAGE_SHIFT ;
2010-03-17 10:01:04 +03:00
err = videobuf_dma_init_kernel ( & mem - > dma ,
DMA_FROM_DEVICE ,
pages ) ;
2007-08-23 23:26:14 +04:00
if ( 0 ! = err )
return err ;
2007-09-28 03:34:09 +04:00
} else if ( vb - > memory = = V4L2_MEMORY_USERPTR ) {
2007-08-23 23:26:14 +04:00
/* dma directly to userspace */
2010-03-17 10:01:04 +03:00
err = videobuf_dma_init_user ( & mem - > dma ,
DMA_FROM_DEVICE ,
vb - > baddr , vb - > bsize ) ;
2007-08-23 23:26:14 +04:00
if ( 0 ! = err )
return err ;
2007-09-28 03:34:09 +04:00
} else {
/* NOTE: HACK: videobuf_iolock on V4L2_MEMORY_MMAP
buffers can only be called from videobuf_qbuf
we take current - > mm - > mmap_sem there , to prevent
locking inversion , so don ' t take it here */
err = videobuf_dma_init_user_locked ( & mem - > dma ,
2008-04-22 21:42:13 +04:00
DMA_FROM_DEVICE ,
2007-09-28 03:34:09 +04:00
vb - > baddr , vb - > bsize ) ;
if ( 0 ! = err )
return err ;
2007-08-23 23:26:14 +04:00
}
break ;
case V4L2_MEMORY_OVERLAY :
if ( NULL = = fbuf )
return - EINVAL ;
/* FIXME: need sanity checks for vb->boff */
/*
* Using a double cast to avoid compiler warnings when
* building for PAE . Compiler doesn ' t like direct casting
* of a 32 bit ptr to 64 bit integer .
*/
bus = ( dma_addr_t ) ( unsigned long ) fbuf - > base + vb - > boff ;
pages = PAGE_ALIGN ( vb - > size ) > > PAGE_SHIFT ;
2008-04-22 21:42:13 +04:00
err = videobuf_dma_init_overlay ( & mem - > dma , DMA_FROM_DEVICE ,
2007-08-23 23:26:14 +04:00
bus , pages ) ;
if ( 0 ! = err )
return err ;
break ;
default :
BUG ( ) ;
}
2010-05-11 17:36:30 +04:00
err = videobuf_dma_map ( q - > dev , & mem - > dma ) ;
2007-08-23 23:26:14 +04:00
if ( 0 ! = err )
return err ;
return 0 ;
}
static int __videobuf_sync ( struct videobuf_queue * q ,
struct videobuf_buffer * buf )
{
2008-04-22 21:42:13 +04:00
struct videobuf_dma_sg_memory * mem = buf - > priv ;
2010-05-05 23:23:09 +04:00
BUG_ON ( ! mem | | ! mem - > dma . sglen ) ;
2010-03-17 10:01:04 +03:00
MAGIC_CHECK ( mem - > magic , MAGIC_SG_MEM ) ;
2010-05-05 23:23:09 +04:00
MAGIC_CHECK ( mem - > dma . magic , MAGIC_DMABUF ) ;
2007-08-23 23:26:14 +04:00
2010-05-05 23:23:09 +04:00
dma_sync_sg_for_cpu ( q - > dev , mem - > dma . sglist ,
2010-03-18 01:53:04 +03:00
mem - > dma . sglen , mem - > dma . direction ) ;
2010-05-05 23:23:09 +04:00
return 0 ;
2007-08-23 23:26:14 +04:00
}
static int __videobuf_mmap_mapper ( struct videobuf_queue * q ,
2010-03-28 16:09:05 +04:00
struct videobuf_buffer * buf ,
struct vm_area_struct * vma )
2007-08-23 23:26:14 +04:00
{
2010-03-28 16:09:05 +04:00
struct videobuf_dma_sg_memory * mem = buf - > priv ;
2007-08-23 23:26:14 +04:00
struct videobuf_mapping * map ;
2010-04-25 18:23:52 +04:00
unsigned int first , last , size = 0 , i ;
2007-08-23 23:26:14 +04:00
int retval ;
retval = - EINVAL ;
2010-03-28 16:09:05 +04:00
BUG_ON ( ! mem ) ;
MAGIC_CHECK ( mem - > magic , MAGIC_SG_MEM ) ;
2007-08-23 23:26:14 +04:00
/* look for first buffer to map */
for ( first = 0 ; first < VIDEO_MAX_FRAME ; first + + ) {
2010-03-28 16:09:05 +04:00
if ( buf = = q - > bufs [ first ] ) {
size = PAGE_ALIGN ( q - > bufs [ first ] - > bsize ) ;
2007-08-23 23:26:14 +04:00
break ;
2010-03-28 16:09:05 +04:00
}
2007-08-23 23:26:14 +04:00
}
2010-03-28 16:09:05 +04:00
/* paranoia, should never happen since buf is always valid. */
2010-04-25 18:23:52 +04:00
if ( ! size ) {
2010-03-17 10:01:04 +03:00
dprintk ( 1 , " mmap app bug: offset invalid [offset=0x%lx] \n " ,
2010-03-28 16:09:05 +04:00
( vma - > vm_pgoff < < PAGE_SHIFT ) ) ;
2007-08-23 23:26:14 +04:00
goto done ;
}
2010-03-28 16:09:05 +04:00
last = first ;
2007-08-23 23:26:14 +04:00
/* create mapping + update buffer list */
retval = - ENOMEM ;
2010-03-17 10:01:04 +03:00
map = kmalloc ( sizeof ( struct videobuf_mapping ) , GFP_KERNEL ) ;
2007-08-23 23:26:14 +04:00
if ( NULL = = map )
goto done ;
2008-04-03 01:10:59 +04:00
size = 0 ;
for ( i = first ; i < = last ; i + + ) {
if ( NULL = = q - > bufs [ i ] )
continue ;
2007-09-28 01:25:44 +04:00
q - > bufs [ i ] - > map = map ;
2007-08-23 23:26:14 +04:00
q - > bufs [ i ] - > baddr = vma - > vm_start + size ;
2009-07-23 17:56:25 +04:00
size + = PAGE_ALIGN ( q - > bufs [ i ] - > bsize ) ;
2007-08-23 23:26:14 +04:00
}
2008-04-03 01:10:59 +04:00
2007-08-23 23:26:14 +04:00
map - > count = 1 ;
map - > q = q ;
vma - > vm_ops = & videobuf_vm_ops ;
mm: kill vma flag VM_RESERVED and mm->reserved_vm counter
A long time ago, in v2.4, VM_RESERVED kept swapout process off VMA,
currently it lost original meaning but still has some effects:
| effect | alternative flags
-+------------------------+---------------------------------------------
1| account as reserved_vm | VM_IO
2| skip in core dump | VM_IO, VM_DONTDUMP
3| do not merge or expand | VM_IO, VM_DONTEXPAND, VM_HUGETLB, VM_PFNMAP
4| do not mlock | VM_IO, VM_DONTEXPAND, VM_HUGETLB, VM_PFNMAP
This patch removes reserved_vm counter from mm_struct. Seems like nobody
cares about it, it does not exported into userspace directly, it only
reduces total_vm showed in proc.
Thus VM_RESERVED can be replaced with VM_IO or pair VM_DONTEXPAND | VM_DONTDUMP.
remap_pfn_range() and io_remap_pfn_range() set VM_IO|VM_DONTEXPAND|VM_DONTDUMP.
remap_vmalloc_range() set VM_DONTEXPAND | VM_DONTDUMP.
[akpm@linux-foundation.org: drivers/vfio/pci/vfio_pci.c fixup]
Signed-off-by: Konstantin Khlebnikov <khlebnikov@openvz.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Carsten Otte <cotte@de.ibm.com>
Cc: Chris Metcalf <cmetcalf@tilera.com>
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Cc: Eric Paris <eparis@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Morris <james.l.morris@oracle.com>
Cc: Jason Baron <jbaron@redhat.com>
Cc: Kentaro Takeda <takedakn@nttdata.co.jp>
Cc: Matt Helsley <matthltc@us.ibm.com>
Cc: Nick Piggin <npiggin@kernel.dk>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Robert Richter <robert.richter@amd.com>
Cc: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Cc: Venkatesh Pallipadi <venki@google.com>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2012-10-09 03:29:02 +04:00
vma - > vm_flags | = VM_DONTEXPAND | VM_DONTDUMP ;
2007-08-23 23:26:14 +04:00
vma - > vm_flags & = ~ VM_IO ; /* using shared anonymous pages */
vma - > vm_private_data = map ;
2010-03-17 10:01:04 +03:00
dprintk ( 1 , " mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d \n " ,
map , q , vma - > vm_start , vma - > vm_end , vma - > vm_pgoff , first , last ) ;
2007-08-23 23:26:14 +04:00
retval = 0 ;
2010-03-17 10:01:04 +03:00
done :
2007-08-23 23:26:14 +04:00
return retval ;
}
2008-04-22 21:42:13 +04:00
static struct videobuf_qtype_ops sg_ops = {
2007-08-23 23:26:14 +04:00
. magic = MAGIC_QTYPE_OPS ,
2010-05-11 17:36:28 +04:00
. alloc_vb = __videobuf_alloc_vb ,
2007-08-23 23:26:14 +04:00
. iolock = __videobuf_iolock ,
. sync = __videobuf_sync ,
. mmap_mapper = __videobuf_mmap_mapper ,
2010-03-28 15:18:37 +04:00
. vaddr = __videobuf_to_vaddr ,
2007-08-23 23:26:14 +04:00
} ;
2008-04-22 21:42:13 +04:00
void * videobuf_sg_alloc ( size_t size )
2007-08-23 23:26:14 +04:00
{
struct videobuf_queue q ;
/* Required to make generic handler to call __videobuf_alloc */
2008-04-22 21:42:13 +04:00
q . int_ops = & sg_ops ;
2007-08-23 23:26:14 +04:00
2008-04-22 21:42:13 +04:00
q . msize = size ;
2007-08-23 23:26:14 +04:00
2010-05-11 17:36:28 +04:00
return videobuf_alloc_vb ( & q ) ;
2007-08-23 23:26:14 +04:00
}
2010-03-17 10:01:04 +03:00
EXPORT_SYMBOL_GPL ( videobuf_sg_alloc ) ;
2007-08-23 23:26:14 +04:00
2010-03-17 10:01:04 +03:00
void videobuf_queue_sg_init ( struct videobuf_queue * q ,
2009-11-18 01:43:41 +03:00
const struct videobuf_queue_ops * ops ,
2008-04-22 21:42:13 +04:00
struct device * dev ,
2007-08-23 23:26:14 +04:00
spinlock_t * irqlock ,
enum v4l2_buf_type type ,
enum v4l2_field field ,
unsigned int msize ,
2010-09-21 00:39:46 +04:00
void * priv ,
struct mutex * ext_lock )
2007-08-23 23:26:14 +04:00
{
2007-10-08 19:20:02 +04:00
videobuf_queue_core_init ( q , ops , dev , irqlock , type , field , msize ,
2010-09-21 00:39:46 +04:00
priv , & sg_ops , ext_lock ) ;
2007-08-23 23:26:14 +04:00
}
2008-04-22 21:42:13 +04:00
EXPORT_SYMBOL_GPL ( videobuf_queue_sg_init ) ;
2007-08-23 23:26:14 +04:00