[media] videobuf2-dma-sg: Support io userptr operations on io memory
Memory exported via remap_pfn_range cannot be remapped via get_user_pages. Other videobuf2 methods (like the dma-contig) supports io memory. This patch adds support for this kind of memory. v2: Comments by Marek Szyprowski -Use vb2_get_vma and vb2_put_vma Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> Acked-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
This commit is contained in:
Родитель
1380f5754c
Коммит
50ac952d22
|
@ -40,6 +40,7 @@ struct vb2_dma_sg_buf {
|
||||||
unsigned int num_pages;
|
unsigned int num_pages;
|
||||||
atomic_t refcount;
|
atomic_t refcount;
|
||||||
struct vb2_vmarea_handler handler;
|
struct vb2_vmarea_handler handler;
|
||||||
|
struct vm_area_struct *vma;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void vb2_dma_sg_put(void *buf_priv);
|
static void vb2_dma_sg_put(void *buf_priv);
|
||||||
|
@ -155,12 +156,18 @@ static void vb2_dma_sg_put(void *buf_priv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int vma_is_io(struct vm_area_struct *vma)
|
||||||
|
{
|
||||||
|
return !!(vma->vm_flags & (VM_IO | VM_PFNMAP));
|
||||||
|
}
|
||||||
|
|
||||||
static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
|
static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
|
||||||
unsigned long size, int write)
|
unsigned long size, int write)
|
||||||
{
|
{
|
||||||
struct vb2_dma_sg_buf *buf;
|
struct vb2_dma_sg_buf *buf;
|
||||||
unsigned long first, last;
|
unsigned long first, last;
|
||||||
int num_pages_from_user;
|
int num_pages_from_user;
|
||||||
|
struct vm_area_struct *vma;
|
||||||
|
|
||||||
buf = kzalloc(sizeof *buf, GFP_KERNEL);
|
buf = kzalloc(sizeof *buf, GFP_KERNEL);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
|
@ -180,7 +187,38 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
|
||||||
if (!buf->pages)
|
if (!buf->pages)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
num_pages_from_user = get_user_pages(current, current->mm,
|
vma = find_vma(current->mm, vaddr);
|
||||||
|
if (!vma) {
|
||||||
|
dprintk(1, "no vma for address %lu\n", vaddr);
|
||||||
|
goto userptr_fail_find_vma;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vma->vm_end < vaddr + size) {
|
||||||
|
dprintk(1, "vma at %lu is too small for %lu bytes\n",
|
||||||
|
vaddr, size);
|
||||||
|
goto userptr_fail_find_vma;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf->vma = vb2_get_vma(vma);
|
||||||
|
if (!buf->vma) {
|
||||||
|
dprintk(1, "failed to copy vma\n");
|
||||||
|
goto userptr_fail_find_vma;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vma_is_io(buf->vma)) {
|
||||||
|
for (num_pages_from_user = 0;
|
||||||
|
num_pages_from_user < buf->num_pages;
|
||||||
|
++num_pages_from_user, vaddr += PAGE_SIZE) {
|
||||||
|
unsigned long pfn;
|
||||||
|
|
||||||
|
if (follow_pfn(buf->vma, vaddr, &pfn)) {
|
||||||
|
dprintk(1, "no page for address %lu\n", vaddr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf->pages[num_pages_from_user] = pfn_to_page(pfn);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
num_pages_from_user = get_user_pages(current, current->mm,
|
||||||
vaddr & PAGE_MASK,
|
vaddr & PAGE_MASK,
|
||||||
buf->num_pages,
|
buf->num_pages,
|
||||||
write,
|
write,
|
||||||
|
@ -201,8 +239,11 @@ userptr_fail_alloc_table_from_pages:
|
||||||
userptr_fail_get_user_pages:
|
userptr_fail_get_user_pages:
|
||||||
dprintk(1, "get_user_pages requested/got: %d/%d]\n",
|
dprintk(1, "get_user_pages requested/got: %d/%d]\n",
|
||||||
buf->num_pages, num_pages_from_user);
|
buf->num_pages, num_pages_from_user);
|
||||||
while (--num_pages_from_user >= 0)
|
if (!vma_is_io(buf->vma))
|
||||||
put_page(buf->pages[num_pages_from_user]);
|
while (--num_pages_from_user >= 0)
|
||||||
|
put_page(buf->pages[num_pages_from_user]);
|
||||||
|
vb2_put_vma(buf->vma);
|
||||||
|
userptr_fail_find_vma:
|
||||||
kfree(buf->pages);
|
kfree(buf->pages);
|
||||||
kfree(buf);
|
kfree(buf);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -225,9 +266,11 @@ static void vb2_dma_sg_put_userptr(void *buf_priv)
|
||||||
while (--i >= 0) {
|
while (--i >= 0) {
|
||||||
if (buf->write)
|
if (buf->write)
|
||||||
set_page_dirty_lock(buf->pages[i]);
|
set_page_dirty_lock(buf->pages[i]);
|
||||||
put_page(buf->pages[i]);
|
if (!vma_is_io(buf->vma))
|
||||||
|
put_page(buf->pages[i]);
|
||||||
}
|
}
|
||||||
kfree(buf->pages);
|
kfree(buf->pages);
|
||||||
|
vb2_put_vma(buf->vma);
|
||||||
kfree(buf);
|
kfree(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче