Skip to content

Commit

Permalink
[media] media: vb2: support userptr for PFN mappings
Browse files Browse the repository at this point in the history
Some video devices need to use contiguous memory which is
not backed by pages as it happens with vmalloc. This patch
provides USERPTR handling for those devices.

Signed-off-by: Javier Martin <javier.martin@vista-silicon.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Javier Martin authored and Mauro Carvalho Chehab committed Mar 8, 2012
1 parent a121216 commit 570d2a4
Showing 1 changed file with 47 additions and 23 deletions.
70 changes: 47 additions & 23 deletions drivers/media/video/videobuf2-vmalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* the Free Software Foundation.
*/

#include <linux/io.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/sched.h>
Expand All @@ -22,6 +23,7 @@
struct vb2_vmalloc_buf {
void *vaddr;
struct page **pages;
struct vm_area_struct *vma;
int write;
unsigned long size;
unsigned int n_pages;
Expand Down Expand Up @@ -71,6 +73,8 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr,
struct vb2_vmalloc_buf *buf;
unsigned long first, last;
int n_pages, offset;
struct vm_area_struct *vma;
dma_addr_t physp;

buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
Expand All @@ -80,23 +84,37 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr,
offset = vaddr & ~PAGE_MASK;
buf->size = size;

first = vaddr >> PAGE_SHIFT;
last = (vaddr + size - 1) >> PAGE_SHIFT;
buf->n_pages = last - first + 1;
buf->pages = kzalloc(buf->n_pages * sizeof(struct page *), GFP_KERNEL);
if (!buf->pages)
goto fail_pages_array_alloc;

/* current->mm->mmap_sem is taken by videobuf2 core */
n_pages = get_user_pages(current, current->mm, vaddr & PAGE_MASK,
buf->n_pages, write, 1, /* force */
buf->pages, NULL);
if (n_pages != buf->n_pages)
goto fail_get_user_pages;

buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1, PAGE_KERNEL);
if (!buf->vaddr)
goto fail_get_user_pages;
vma = find_vma(current->mm, vaddr);
if (vma && (vma->vm_flags & VM_PFNMAP) && (vma->vm_pgoff)) {
if (vb2_get_contig_userptr(vaddr, size, &vma, &physp))
goto fail_pages_array_alloc;
buf->vma = vma;
buf->vaddr = ioremap_nocache(physp, size);
if (!buf->vaddr)
goto fail_pages_array_alloc;
} else {
first = vaddr >> PAGE_SHIFT;
last = (vaddr + size - 1) >> PAGE_SHIFT;
buf->n_pages = last - first + 1;
buf->pages = kzalloc(buf->n_pages * sizeof(struct page *),
GFP_KERNEL);
if (!buf->pages)
goto fail_pages_array_alloc;

/* current->mm->mmap_sem is taken by videobuf2 core */
n_pages = get_user_pages(current, current->mm,
vaddr & PAGE_MASK, buf->n_pages,
write, 1, /* force */
buf->pages, NULL);
if (n_pages != buf->n_pages)
goto fail_get_user_pages;

buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1,
PAGE_KERNEL);
if (!buf->vaddr)
goto fail_get_user_pages;
}

buf->vaddr += offset;
return buf;
Expand All @@ -120,14 +138,20 @@ static void vb2_vmalloc_put_userptr(void *buf_priv)
unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK;
unsigned int i;

if (vaddr)
vm_unmap_ram((void *)vaddr, buf->n_pages);
for (i = 0; i < buf->n_pages; ++i) {
if (buf->write)
set_page_dirty_lock(buf->pages[i]);
put_page(buf->pages[i]);
if (buf->pages) {
if (vaddr)
vm_unmap_ram((void *)vaddr, buf->n_pages);
for (i = 0; i < buf->n_pages; ++i) {
if (buf->write)
set_page_dirty_lock(buf->pages[i]);
put_page(buf->pages[i]);
}
kfree(buf->pages);
} else {
if (buf->vma)
vb2_put_vma(buf->vma);
iounmap(buf->vaddr);
}
kfree(buf->pages);
kfree(buf);
}

Expand Down

0 comments on commit 570d2a4

Please sign in to comment.