提交 570d2a48 编写于 作者: J Javier Martin 提交者: Mauro Carvalho Chehab

[media] media: vb2: support userptr for PFN mappings

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: NJavier Martin <javier.martin@vista-silicon.com>
Signed-off-by: NMarek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: NSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: NMauro Carvalho Chehab <mchehab@redhat.com>
上级 a1212162
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
* the Free Software Foundation. * the Free Software Foundation.
*/ */
#include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -22,6 +23,7 @@ ...@@ -22,6 +23,7 @@
struct vb2_vmalloc_buf { struct vb2_vmalloc_buf {
void *vaddr; void *vaddr;
struct page **pages; struct page **pages;
struct vm_area_struct *vma;
int write; int write;
unsigned long size; unsigned long size;
unsigned int n_pages; unsigned int n_pages;
...@@ -71,6 +73,8 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr, ...@@ -71,6 +73,8 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr,
struct vb2_vmalloc_buf *buf; struct vb2_vmalloc_buf *buf;
unsigned long first, last; unsigned long first, last;
int n_pages, offset; int n_pages, offset;
struct vm_area_struct *vma;
dma_addr_t physp;
buf = kzalloc(sizeof(*buf), GFP_KERNEL); buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf) if (!buf)
...@@ -80,23 +84,37 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr, ...@@ -80,23 +84,37 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr,
offset = vaddr & ~PAGE_MASK; offset = vaddr & ~PAGE_MASK;
buf->size = size; 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 */ vma = find_vma(current->mm, vaddr);
n_pages = get_user_pages(current, current->mm, vaddr & PAGE_MASK, if (vma && (vma->vm_flags & VM_PFNMAP) && (vma->vm_pgoff)) {
buf->n_pages, write, 1, /* force */ if (vb2_get_contig_userptr(vaddr, size, &vma, &physp))
buf->pages, NULL); goto fail_pages_array_alloc;
if (n_pages != buf->n_pages) buf->vma = vma;
goto fail_get_user_pages; buf->vaddr = ioremap_nocache(physp, size);
if (!buf->vaddr)
buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1, PAGE_KERNEL); goto fail_pages_array_alloc;
if (!buf->vaddr) } else {
goto fail_get_user_pages; 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; buf->vaddr += offset;
return buf; return buf;
...@@ -120,14 +138,20 @@ static void vb2_vmalloc_put_userptr(void *buf_priv) ...@@ -120,14 +138,20 @@ static void vb2_vmalloc_put_userptr(void *buf_priv)
unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK; unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK;
unsigned int i; unsigned int i;
if (vaddr) if (buf->pages) {
vm_unmap_ram((void *)vaddr, buf->n_pages); if (vaddr)
for (i = 0; i < buf->n_pages; ++i) { vm_unmap_ram((void *)vaddr, buf->n_pages);
if (buf->write) for (i = 0; i < buf->n_pages; ++i) {
set_page_dirty_lock(buf->pages[i]); if (buf->write)
put_page(buf->pages[i]); 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); kfree(buf);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册