2007-08-03 06:31:33 +04:00
/*
* helper functions for vmalloc video4linux capture buffers
*
2008-07-17 04:27:49 +04:00
* The functions expect the hardware being able to scatter gather
2007-08-03 06:31:33 +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 >
*
* 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>
# include <linux/slab.h>
# include <linux/interrupt.h>
# include <linux/pci.h>
# include <linux/vmalloc.h>
# include <linux/pagemap.h>
# include <asm/page.h>
# include <asm/pgtable.h>
# include <media/videobuf-vmalloc.h>
# define MAGIC_DMABUF 0x17760309
# define MAGIC_VMAL_MEM 0x18221223
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-03 06:31:33 +04:00
2008-04-22 21:41:48 +04:00
static int debug ;
2007-08-03 06:31:33 +04:00
module_param ( debug , int , 0644 ) ;
MODULE_DESCRIPTION ( " helper module to manage video4linux vmalloc buffers " ) ;
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-vmalloc: " fmt , # # arg )
2007-08-03 06:31:33 +04:00
/***************************************************************************/
2010-03-17 10:01:04 +03:00
static void videobuf_vm_open ( struct vm_area_struct * vma )
2007-08-03 06:31:33 +04:00
{
struct videobuf_mapping * map = vma - > vm_private_data ;
2010-03-17 10:01:04 +03:00
dprintk ( 2 , " vm_open %p [count=%u,vma=%08lx-%08lx] \n " , map ,
map - > count , vma - > vm_start , vma - > vm_end ) ;
2007-08-03 06:31:33 +04:00
map - > count + + ;
}
2008-04-13 21:58:43 +04:00
static void videobuf_vm_close ( struct vm_area_struct * vma )
2007-08-03 06:31:33 +04:00
{
struct videobuf_mapping * map = vma - > vm_private_data ;
struct videobuf_queue * q = map - > q ;
int i ;
2010-03-17 10:01:04 +03:00
dprintk ( 2 , " vm_close %p [count=%u,vma=%08lx-%08lx] \n " , map ,
2008-04-13 21:58:43 +04:00
map - > count , vma - > vm_start , vma - > vm_end ) ;
2007-08-03 06:31:33 +04:00
2014-01-03 15:10:49 +04:00
map - > count - - ;
if ( 0 = = map - > count ) {
2008-04-13 21:58:43 +04:00
struct videobuf_vmalloc_memory * mem ;
dprintk ( 1 , " munmap %p q=%p \n " , map , q ) ;
2014-01-03 15:10:49 +04:00
videobuf_queue_lock ( q ) ;
2008-04-13 22:07:56 +04:00
/* We need first to cancel streams, before unmapping */
if ( q - > streaming )
videobuf_queue_cancel ( q ) ;
2007-08-03 06:31:33 +04:00
for ( i = 0 ; i < VIDEO_MAX_FRAME ; i + + ) {
if ( NULL = = q - > bufs [ i ] )
continue ;
2007-09-28 01:25:44 +04:00
if ( q - > bufs [ i ] - > map ! = map )
2007-08-03 06:31:33 +04:00
continue ;
2007-09-07 03:11:35 +04:00
2008-04-13 21:58:43 +04:00
mem = q - > bufs [ i ] - > priv ;
if ( mem ) {
/* This callback is called only if kernel has
allocated memory and this memory is mmapped .
In this case , memory should be freed ,
in order to do memory unmap .
*/
2008-04-13 22:07:56 +04:00
2008-04-13 21:58:43 +04:00
MAGIC_CHECK ( mem - > magic , MAGIC_VMAL_MEM ) ;
2008-04-13 22:07:56 +04:00
/* vfree is not atomic - can't be
called with IRQ ' s disabled
*/
dprintk ( 1 , " %s: buf[%d] freeing (%p) \n " ,
2010-05-11 17:36:34 +04:00
__func__ , i , mem - > vaddr ) ;
2008-04-13 22:07:56 +04:00
2010-05-11 17:36:34 +04:00
vfree ( mem - > vaddr ) ;
mem - > vaddr = NULL ;
2008-04-13 21:58:43 +04:00
}
2007-09-28 01:25:44 +04:00
q - > bufs [ i ] - > map = NULL ;
2007-08-03 06:31:33 +04:00
q - > bufs [ i ] - > baddr = 0 ;
}
2008-04-13 22:07:56 +04:00
2007-08-03 06:31:33 +04:00
kfree ( map ) ;
2008-04-13 22:07:56 +04:00
2014-01-03 15:10:49 +04:00
videobuf_queue_unlock ( q ) ;
2007-08-03 06:31:33 +04:00
}
2008-04-13 22:07:56 +04:00
2007-08-03 06:31:33 +04:00
return ;
}
2010-03-17 10:01:04 +03:00
static const struct vm_operations_struct videobuf_vm_ops = {
2007-08-03 06:31:33 +04:00
. open = videobuf_vm_open ,
. close = videobuf_vm_close ,
} ;
/* ---------------------------------------------------------------------
* vmalloc handlers for the generic methods
*/
/* 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-03 06:31:33 +04:00
*/
2010-05-11 17:36:28 +04:00
static struct videobuf_buffer * __videobuf_alloc_vb ( size_t size )
2007-08-03 06:31:33 +04:00
{
2008-02-05 02:52:21 +03:00
struct videobuf_vmalloc_memory * mem ;
2007-08-03 06:31:33 +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-03 06:31:33 +04:00
2010-03-17 10:01:04 +03:00
mem = vb - > priv = ( ( char * ) vb ) + size ;
mem - > magic = MAGIC_VMAL_MEM ;
2007-08-03 06:31:33 +04:00
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-03 06:31:33 +04:00
return vb ;
}
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-03 06:31:33 +04:00
{
2008-04-13 21:58:21 +04:00
struct videobuf_vmalloc_memory * mem = vb - > priv ;
2008-04-13 22:07:56 +04:00
int pages ;
2007-08-03 06:31:33 +04:00
BUG_ON ( ! mem ) ;
2008-04-13 21:58:21 +04:00
MAGIC_CHECK ( mem - > magic , MAGIC_VMAL_MEM ) ;
2007-08-03 06:31:33 +04:00
2008-04-13 21:58:21 +04:00
switch ( vb - > memory ) {
case V4L2_MEMORY_MMAP :
dprintk ( 1 , " %s memory method MMAP \n " , __func__ ) ;
2007-08-03 06:31:33 +04:00
2008-04-13 21:58:21 +04:00
/* All handling should be done by __videobuf_mmap_mapper() */
2010-05-11 17:36:34 +04:00
if ( ! mem - > vaddr ) {
2008-04-13 21:58:21 +04:00
printk ( KERN_ERR " memory is not alloced/mmapped. \n " ) ;
return - EINVAL ;
}
break ;
case V4L2_MEMORY_USERPTR :
2008-04-13 22:07:56 +04:00
pages = PAGE_ALIGN ( vb - > size ) ;
2007-08-03 06:31:33 +04:00
2008-04-13 21:58:21 +04:00
dprintk ( 1 , " %s memory method USERPTR \n " , __func__ ) ;
if ( vb - > baddr ) {
printk ( KERN_ERR " USERPTR is currently not supported \n " ) ;
return - EINVAL ;
}
2007-08-03 06:31:33 +04:00
2008-04-13 21:58:21 +04:00
/* The only USERPTR currently supported is the one needed for
2010-03-17 10:01:04 +03:00
* read ( ) method .
2008-04-13 21:58:21 +04:00
*/
2010-05-11 17:36:34 +04:00
mem - > vaddr = vmalloc_user ( pages ) ;
if ( ! mem - > vaddr ) {
2008-04-13 21:58:21 +04:00
printk ( KERN_ERR " vmalloc (%d pages) failed \n " , pages ) ;
return - ENOMEM ;
2007-08-03 06:31:33 +04:00
}
2008-04-13 21:58:21 +04:00
dprintk ( 1 , " vmalloc is at addr %p (%d pages) \n " ,
2010-05-11 17:36:34 +04:00
mem - > vaddr , pages ) ;
2008-04-13 21:58:21 +04:00
#if 0
int rc ;
/* Kernel userptr is used also by read() method. In this case,
there ' s no need to remap , since data will be copied to user
*/
if ( ! vb - > baddr )
return 0 ;
/* FIXME: to properly support USERPTR, remap should occur.
2008-07-26 15:37:58 +04:00
The code below won ' t work , since mem - > vma = NULL
2008-04-13 21:58:21 +04:00
*/
/* Try to remap memory */
rc = remap_vmalloc_range ( mem - > vma , ( void * ) vb - > baddr , 0 ) ;
if ( rc < 0 ) {
2010-03-17 10:01:04 +03:00
printk ( KERN_ERR " mmap: remap failed with error %d " , rc ) ;
2008-04-13 21:58:21 +04:00
return - ENOMEM ;
}
# endif
break ;
case V4L2_MEMORY_OVERLAY :
default :
dprintk ( 1 , " %s memory method OVERLAY/unknown \n " , __func__ ) ;
/* Currently, doesn't support V4L2_MEMORY_OVERLAY */
printk ( KERN_ERR " Memory method currently unsupported. \n " ) ;
return - EINVAL ;
2007-08-03 06:31:33 +04:00
}
return 0 ;
}
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-03 06:31:33 +04:00
{
2008-02-05 02:52:21 +03:00
struct videobuf_vmalloc_memory * mem ;
2007-08-03 06:31:33 +04:00
struct videobuf_mapping * map ;
2008-04-13 21:58:21 +04:00
int retval , pages ;
2007-08-03 06:31:33 +04:00
2008-04-13 21:58:21 +04:00
dprintk ( 1 , " %s \n " , __func__ ) ;
2007-08-03 06:31:33 +04:00
/* create mapping + update buffer list */
2008-04-13 21:58:21 +04:00
map = kzalloc ( sizeof ( struct videobuf_mapping ) , GFP_KERNEL ) ;
2007-08-03 06:31:33 +04:00
if ( NULL = = map )
return - ENOMEM ;
2010-03-28 16:09:05 +04:00
buf - > map = map ;
2007-08-03 06:31:33 +04:00
map - > q = q ;
2010-03-28 16:09:05 +04:00
buf - > baddr = vma - > vm_start ;
2007-08-03 06:31:33 +04:00
2010-03-28 16:09:05 +04:00
mem = buf - > priv ;
2008-04-13 21:58:21 +04:00
BUG_ON ( ! mem ) ;
MAGIC_CHECK ( mem - > magic , MAGIC_VMAL_MEM ) ;
2007-08-03 06:31:33 +04:00
2008-04-13 21:58:21 +04:00
pages = PAGE_ALIGN ( vma - > vm_end - vma - > vm_start ) ;
2010-05-11 17:36:34 +04:00
mem - > vaddr = vmalloc_user ( pages ) ;
if ( ! mem - > vaddr ) {
2008-04-13 21:58:21 +04:00
printk ( KERN_ERR " vmalloc (%d pages) failed \n " , pages ) ;
goto error ;
}
2010-05-11 17:36:34 +04:00
dprintk ( 1 , " vmalloc is at addr %p (%d pages) \n " , mem - > vaddr , pages ) ;
2007-09-28 01:25:44 +04:00
2007-08-03 06:31:33 +04:00
/* Try to remap memory */
2010-05-11 17:36:34 +04:00
retval = remap_vmalloc_range ( vma , mem - > vaddr , 0 ) ;
2008-04-13 21:58:21 +04:00
if ( retval < 0 ) {
printk ( KERN_ERR " mmap: remap failed with error %d. " , retval ) ;
2010-05-11 17:36:34 +04:00
vfree ( mem - > vaddr ) ;
2008-04-13 21:58:21 +04:00
goto error ;
2007-08-03 06:31:33 +04:00
}
2008-04-13 21:58:21 +04:00
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 ;
2008-04-13 21:58:21 +04:00
vma - > vm_private_data = map ;
2010-03-17 10:01:04 +03:00
dprintk ( 1 , " mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d \n " ,
2008-04-13 21:58:21 +04:00
map , q , vma - > vm_start , vma - > vm_end ,
2010-03-28 16:09:05 +04:00
( long int ) buf - > bsize ,
vma - > vm_pgoff , buf - > i ) ;
2007-08-03 06:31:33 +04:00
videobuf_vm_open ( vma ) ;
2008-04-13 21:58:21 +04:00
return 0 ;
error :
mem = NULL ;
kfree ( map ) ;
return - ENOMEM ;
2007-08-03 06:31:33 +04:00
}
static struct videobuf_qtype_ops qops = {
. magic = MAGIC_QTYPE_OPS ,
2010-05-11 17:36:28 +04:00
. alloc_vb = __videobuf_alloc_vb ,
2007-08-03 06:31:33 +04:00
. iolock = __videobuf_iolock ,
. mmap_mapper = __videobuf_mmap_mapper ,
2010-03-28 15:18:37 +04:00
. vaddr = videobuf_to_vmalloc ,
2007-08-03 06:31:33 +04:00
} ;
2010-03-17 10:01:04 +03:00
void videobuf_queue_vmalloc_init ( struct videobuf_queue * q ,
2009-11-18 01:43:41 +03:00
const struct videobuf_queue_ops * ops ,
2009-11-23 20:29:35 +03:00
struct device * dev ,
2007-08-03 06:31:33 +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-03 06:31:33 +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 , & qops , ext_lock ) ;
2007-08-03 06:31:33 +04:00
}
EXPORT_SYMBOL_GPL ( videobuf_queue_vmalloc_init ) ;
2010-03-17 10:01:04 +03:00
void * videobuf_to_vmalloc ( struct videobuf_buffer * buf )
2007-08-03 06:31:33 +04:00
{
2010-03-17 10:01:04 +03:00
struct videobuf_vmalloc_memory * mem = buf - > priv ;
BUG_ON ( ! mem ) ;
MAGIC_CHECK ( mem - > magic , MAGIC_VMAL_MEM ) ;
2007-08-03 06:31:33 +04:00
2010-05-11 17:36:34 +04:00
return mem - > vaddr ;
2007-08-03 06:31:33 +04:00
}
EXPORT_SYMBOL_GPL ( videobuf_to_vmalloc ) ;
2010-03-17 10:01:04 +03:00
void videobuf_vmalloc_free ( struct videobuf_buffer * buf )
2007-08-03 06:31:33 +04:00
{
2008-04-13 21:58:21 +04:00
struct videobuf_vmalloc_memory * mem = buf - > priv ;
2007-08-03 06:31:33 +04:00
2008-04-13 21:58:43 +04:00
/* mmapped memory can't be freed here, otherwise mmapped region
would be released , while still needed . In this case , the memory
release should happen inside videobuf_vm_close ( ) .
So , it should free memory only if the memory were allocated for
read ( ) operation .
*/
2009-01-24 03:35:12 +03:00
if ( ( buf - > memory ! = V4L2_MEMORY_USERPTR ) | | buf - > baddr )
2008-04-13 21:58:43 +04:00
return ;
2008-04-13 21:58:21 +04:00
if ( ! mem )
return ;
MAGIC_CHECK ( mem - > magic , MAGIC_VMAL_MEM ) ;
2007-08-03 06:31:33 +04:00
2010-05-11 17:36:34 +04:00
vfree ( mem - > vaddr ) ;
mem - > vaddr = NULL ;
2008-04-13 21:58:21 +04:00
2007-08-03 06:31:33 +04:00
return ;
}
EXPORT_SYMBOL_GPL ( videobuf_vmalloc_free ) ;