Re: [PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()

2015-07-21 Thread Jan Kara
On Sat 18-07-15 12:14:12, Inki Dae wrote:
> On 2015년 07월 17일 19:31, Hans Verkuil wrote:
> > On 07/17/2015 12:29 PM, Inki Dae wrote:
> >> On 2015년 07월 17일 19:20, Hans Verkuil wrote:
> >>> On 07/13/2015 04:55 PM, Jan Kara wrote:
> >>>> From: Jan Kara 
> >>>>
> >>>> Convert g2d_userptr_get_dma_addr() to pin pages using get_vaddr_frames().
> >>>> This removes the knowledge about vmas and mmap_sem locking from exynos
> >>>> driver. Also it fixes a problem that the function has been mapping user
> >>>> provided address without holding mmap_sem.
> >>>
> >>> I'd like to see an Ack from one of the exynos drm driver maintainers 
> >>> before
> >>> I merge this.
> >>>
> >>> Inki, Marek?
> >>
> >> I already gave Ack but it seems that Jan missed it while updating.
> >>
> >> Anyway,
> >> Acked-by: Inki Dae 
> > 
> > Thanks!
> 
> Oops, sorry. This patch would incur a build warning. Below is my comment.
> 
> >>>> @@ -456,65 +455,38 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
> >>>> drm_device *drm_dev,
> >>>>  return ERR_PTR(-ENOMEM);
> >>>>  
> >>>>  atomic_set(&g2d_userptr->refcount, 1);
> >>>> +g2d_userptr->size = size;
> >>>>  
> >>>>  start = userptr & PAGE_MASK;
> >>>>  offset = userptr & ~PAGE_MASK;
> >>>>  end = PAGE_ALIGN(userptr + size);
> >>>>  npages = (end - start) >> PAGE_SHIFT;
> >>>> -g2d_userptr->npages = npages;
> >>>> -
> >>>> -pages = drm_calloc_large(npages, sizeof(struct page *));
> >>>> -if (!pages) {
> >>>> -DRM_ERROR("failed to allocate pages.\n");
> >>>> -ret = -ENOMEM;
> >>>> +g2d_userptr->vec = frame_vector_create(npages);
> >>>> +if (!g2d_userptr->vec)
> 
> You would need ret = -EFAULT here. And below is a patch posted already,
>   http://www.spinics.net/lists/dri-devel/msg85321.html

The error should IMHO be -ENOMEM because frame_vector_create() fails only
if we fail to allocate the structure. Attached is the updated version of
the patch. Hans, can you please pick this one?
 
> ps. please, ignore the codes related to build error in the patch.
> 
> With the change, Acked-by: Inki Dae 

Thanks and sorry for making so many stupid mistakes in the Exynos driver.

        Honza
-- 
Jan Kara 
SUSE Labs, CR
>From e1ce3781eb0a3ffe045055f4145bc60ee7b2a6b5 Mon Sep 17 00:00:00 2001
From: Jan Kara 
Date: Wed, 4 Dec 2013 14:41:22 +0100
Subject: [PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use
 get_vaddr_frames()

Convert g2d_userptr_get_dma_addr() to pin pages using get_vaddr_frames().
This removes the knowledge about vmas and mmap_sem locking from exynos
driver. Also it fixes a problem that the function has been mapping user
provided address without holding mmap_sem.

Acked-by: Inki Dae 
Signed-off-by: Jan Kara 
---
 drivers/gpu/drm/exynos/Kconfig  |  1 +
 drivers/gpu/drm/exynos/exynos_drm_g2d.c | 89 ++
 drivers/gpu/drm/exynos/exynos_drm_gem.c | 97 -
 3 files changed, 30 insertions(+), 157 deletions(-)

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 43003c4ad80b..b364562dc6c1 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -77,6 +77,7 @@ config DRM_EXYNOS_VIDI
 config DRM_EXYNOS_G2D
 	bool "Exynos DRM G2D"
 	depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_G2D
+	select FRAME_VECTOR
 	help
 	  Choose this option if you want to use Exynos G2D for DRM.
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 81a250830808..7584834a53c9 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -190,10 +190,8 @@ struct g2d_cmdlist_userptr {
 	dma_addr_t		dma_addr;
 	unsigned long		userptr;
 	unsigned long		size;
-	struct page		**pages;
-	unsigned int		npages;
+	struct frame_vector	*vec;
 	struct sg_table		*sgt;
-	struct vm_area_struct	*vma;
 	atomic_t		refcount;
 	bool			in_pool;
 	bool			out_of_list;
@@ -363,6 +361,7 @@ static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev,
 {
 	struct g2d_cmdlist_userptr *g2d_userptr =
 	(struct g2d_cmdlist_userptr *)obj;
+	struct page **pages;
 
 	if (!obj)
 		return;
@@ -382,19 +381,21 @@ out:
 	

[PATCH 6/9] media: vb2: Convert vb2_vmalloc_get_userptr() to use frame vector

2015-07-13 Thread Jan Kara
From: Jan Kara 

Convert vb2_vmalloc_get_userptr() to use frame vector infrastructure.
When we are doing that there's no need to allocate page array and some
code can be simplified.

Acked-by: Marek Szyprowski 
Tested-by: Marek Szyprowski 
Signed-off-by: Jan Kara 
---
 drivers/media/v4l2-core/videobuf2-vmalloc.c | 92 +++--
 1 file changed, 36 insertions(+), 56 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c 
b/drivers/media/v4l2-core/videobuf2-vmalloc.c
index 63bef959623e..ecb8f0c7f025 100644
--- a/drivers/media/v4l2-core/videobuf2-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c
@@ -23,11 +23,9 @@
 
 struct vb2_vmalloc_buf {
void*vaddr;
-   struct page **pages;
-   struct vm_area_struct   *vma;
+   struct frame_vector *vec;
enum dma_data_direction dma_dir;
unsigned long   size;
-   unsigned intn_pages;
atomic_trefcount;
struct vb2_vmarea_handler   handler;
struct dma_buf  *dbuf;
@@ -76,10 +74,8 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
 enum dma_data_direction dma_dir)
 {
struct vb2_vmalloc_buf *buf;
-   unsigned long first, last;
-   int n_pages, offset;
-   struct vm_area_struct *vma;
-   dma_addr_t physp;
+   struct frame_vector *vec;
+   int n_pages, offset, i;
 
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
@@ -88,53 +84,36 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
buf->dma_dir = dma_dir;
offset = vaddr & ~PAGE_MASK;
buf->size = size;
-
-   down_read(¤t->mm->mmap_sem);
-   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 = (__force void *)ioremap_nocache(physp, size);
-   if (!buf->vaddr)
-   goto fail_pages_array_alloc;
+   vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE);
+   if (IS_ERR(vec))
+   goto fail_pfnvec_create;
+   buf->vec = vec;
+   n_pages = frame_vector_count(vec);
+   if (frame_vector_to_pages(vec) < 0) {
+   unsigned long *nums = frame_vector_pfns(vec);
+
+   /*
+* We cannot get page pointers for these pfns. Check memory is
+* physically contiguous and use direct mapping.
+*/
+   for (i = 1; i < n_pages; i++)
+   if (nums[i-1] + 1 != nums[i])
+   goto fail_map;
+   buf->vaddr = (__force void *)
+   ioremap_nocache(nums[0] << PAGE_SHIFT, size);
} 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,
-dma_dir == DMA_FROM_DEVICE,
-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,
+   buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1,
PAGE_KERNEL);
-   if (!buf->vaddr)
-   goto fail_get_user_pages;
}
-   up_read(¤t->mm->mmap_sem);
 
+   if (!buf->vaddr)
+   goto fail_map;
buf->vaddr += offset;
return buf;
 
-fail_get_user_pages:
-   pr_debug("get_user_pages requested/got: %d/%d]\n", n_pages,
-buf->n_pages);
-   while (--n_pages >= 0)
-   put_page(buf->pages[n_pages]);
-   kfree(buf->pages);
-
-fail_pages_array_alloc:
-   up_read(¤t->mm->mmap_sem);
+fail_map:
+   vb2_destroy_framevec(vec);
+fail_pfnvec_create:
kfree(buf);
 
return NULL;
@@ -145,20 +124,21 @@ stati

[PATCH 0/9 v7] Helper to abstract vma handling in media layer

2015-07-13 Thread Jan Kara
From: Jan Kara 

  Hello,

I'm sending the seventh version of my patch series to abstract vma handling
from the various media drivers. Since the previous version there are just
minor cleanups and fixes (see detailed changelog at the end of the email).

After this patch set drivers have to know much less details about vmas, their
types, and locking. Also quite some code is removed from them. As a bonus
drivers get automatically VM_FAULT_RETRY handling. The primary motivation for
this series is to remove knowledge about mmap_sem locking from as many places a
possible so that we can change it with reasonable effort.

The core of the series is the new helper get_vaddr_frames() which is given a
virtual address and it fills in PFNs / struct page pointers (depending on VMA
type) into the provided array. If PFNs correspond to normal pages it also grabs
references to these pages. The difference from get_user_pages() is that this
function can also deal with pfnmap, and io mappings which is what the media
drivers need.

I have tested the patches with vivid driver so at least vb2 code got some
exposure. Conversion of other drivers was just compile-tested (for x86 so e.g.
exynos driver which is only for Samsung platform is completely untested).

Hans, can you please pull the changes? Thanks!

Honza

Changes since v6:
* Fixed compilation error introduced into exynos driver
* Folded patch allowing get_vaddr_pfn() code to be selected by a config option
  into previous patches
* Rebased on top of linux-media tree

Changes since v5:
* Moved mm helper into a separate file and behind a config option
* Changed the first patch pushing mmap_sem down in videobuf2 core to avoid
  possible deadlock

Changes since v4:
* Minor cleanups and fixes pointed out by Mel and Vlasta
* Added Acked-by tags

Changes since v3:
* Added include  into mm/gup.c as it's needed for some archs
* Fixed error path for exynos driver

Changes since v2:
* Renamed functions and structures as Mel suggested
* Other minor changes suggested by Mel
* Rebased on top of 4.1-rc2
* Changed functions to get pointer to array of pages / pfns to perform
  conversion if necessary. This fixes possible issue in the omap I may have
  introduced in v2 and generally makes the API less errorprone.
--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/9] [media] vb2: Push mmap_sem down to memops

2015-07-13 Thread Jan Kara
From: Jan Kara 

Currently vb2 core acquires mmap_sem just around call to
__qbuf_userptr(). However since commit f035eb4e976ef5 (videobuf2: fix
lockdep warning) it isn't necessary to acquire it so early as we no
longer have to drop queue mutex before acquiring mmap_sem. So push
acquisition of mmap_sem down into .get_userptr memop so that the
semaphore is acquired for a shorter time and it is clearer what it is
needed for.

Note that we also need mmap_sem in .put_userptr memop since that ends up
calling vb2_put_vma() which calls vma->vm_ops->close() which should be
called with mmap_sem held. However we didn't hold mmap_sem in some code
paths anyway (e.g. when called via vb2_ioctl_reqbufs() ->
__vb2_queue_free() -> vb2_dma_sg_put_userptr()) and getting mmap_sem in
put_userptr() introduces a lock inversion with queue->mmap_lock in the
above mentioned call path.

Luckily this whole locking mess will get resolved once we convert
videobuf2 core to the new mm helper which avoids the need for mmap_sem
in .put_userptr memop altogether.

Signed-off-by: Jan Kara 
---
 drivers/media/v4l2-core/videobuf2-core.c   | 2 --
 drivers/media/v4l2-core/videobuf2-dma-contig.c | 5 +
 drivers/media/v4l2-core/videobuf2-dma-sg.c | 4 
 drivers/media/v4l2-core/videobuf2-vmalloc.c| 4 +++-
 4 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-core.c 
b/drivers/media/v4l2-core/videobuf2-core.c
index 93b315459098..4df6dfc47fc8 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -1675,9 +1675,7 @@ static int __buf_prepare(struct vb2_buffer *vb, const 
struct v4l2_buffer *b)
ret = __qbuf_mmap(vb, b);
break;
case V4L2_MEMORY_USERPTR:
-   down_read(¤t->mm->mmap_sem);
ret = __qbuf_userptr(vb, b);
-   up_read(¤t->mm->mmap_sem);
break;
case V4L2_MEMORY_DMABUF:
ret = __qbuf_dmabuf(vb, b);
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 94c1e6455d36..c548ce425701 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -616,6 +616,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
goto fail_buf;
}
 
+   down_read(¤t->mm->mmap_sem);
/* current->mm->mmap_sem is taken by videobuf2 core */
vma = find_vma(current->mm, vaddr);
if (!vma) {
@@ -642,6 +643,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
if (ret) {
unsigned long pfn;
if (vb2_dc_get_user_pfn(start, n_pages, vma, &pfn) == 0) {
+   up_read(¤t->mm->mmap_sem);
buf->dma_addr = vb2_dc_pfn_to_dma(buf->dev, pfn);
buf->size = size;
kfree(pages);
@@ -651,6 +653,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
pr_err("failed to get user pages\n");
goto fail_vma;
}
+   up_read(¤t->mm->mmap_sem);
 
sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
if (!sgt) {
@@ -713,10 +716,12 @@ fail_get_user_pages:
while (n_pages)
put_page(pages[--n_pages]);
 
+   down_read(¤t->mm->mmap_sem);
 fail_vma:
vb2_put_vma(buf->vma);
 
 fail_pages:
+   up_read(¤t->mm->mmap_sem);
kfree(pages); /* kfree is NULL-proof */
 
 fail_buf:
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c 
b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index 7289b81bd7b7..d2cf113d1933 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -264,6 +264,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
if (!buf->pages)
goto userptr_fail_alloc_pages;
 
+   down_read(¤t->mm->mmap_sem);
vma = find_vma(current->mm, vaddr);
if (!vma) {
dprintk(1, "no vma for address %lu\n", vaddr);
@@ -302,6 +303,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
 1, /* force */
 buf->pages,
 NULL);
+   up_read(¤t->mm->mmap_sem);
 
if (num_pages_from_user != buf->num_pages)
goto userptr_fail_get_user_pages;
@@ -331,8 +333,10 @@ userptr_fail_get_user_pages:
if (!vma_is_io(buf->vma))
while (--num_pages_from_user >= 0)
put_page(buf->pages[num_pages_from_user]);
+   down_read(¤t->mm->mmap_sem);
vb2_put_vma(buf-&

[PATCH 3/9] media: omap_vout: Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns()

2015-07-13 Thread Jan Kara
From: Jan Kara 

Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns() instead of
hand made mapping of virtual address to physical address. Also the
function leaked page reference from get_user_pages() so fix that by
properly release the reference when omap_vout_buffer_release() is
called.

Signed-off-by: Jan Kara 
---
 drivers/media/platform/omap/Kconfig |  1 +
 drivers/media/platform/omap/omap_vout.c | 67 +++--
 2 files changed, 32 insertions(+), 36 deletions(-)

diff --git a/drivers/media/platform/omap/Kconfig 
b/drivers/media/platform/omap/Kconfig
index dc2aaab54aef..217d613b0fe7 100644
--- a/drivers/media/platform/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
@@ -10,6 +10,7 @@ config VIDEO_OMAP2_VOUT
select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS
select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB
+   select FRAME_VECTOR
default n
---help---
  V4L2 Display driver support for OMAP2/3 based boards.
diff --git a/drivers/media/platform/omap/omap_vout.c 
b/drivers/media/platform/omap/omap_vout.c
index f09c5f17a42f..b0dad941f7cb 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -195,46 +195,34 @@ static int omap_vout_try_format(struct v4l2_pix_format 
*pix)
 }
 
 /*
- * omap_vout_uservirt_to_phys: This inline function is used to convert user
- * space virtual address to physical address.
+ * omap_vout_get_userptr: Convert user space virtual address to physical
+ * address.
  */
-static unsigned long omap_vout_uservirt_to_phys(unsigned long virtp)
+static int omap_vout_get_userptr(struct videobuf_buffer *vb, u32 virtp,
+u32 *physp)
 {
-   unsigned long physp = 0;
-   struct vm_area_struct *vma;
-   struct mm_struct *mm = current->mm;
+   struct frame_vector *vec;
+   int ret;
 
/* For kernel direct-mapped memory, take the easy way */
-   if (virtp >= PAGE_OFFSET)
-   return virt_to_phys((void *) virtp);
-
-   down_read(¤t->mm->mmap_sem);
-   vma = find_vma(mm, virtp);
-   if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) {
-   /* this will catch, kernel-allocated, mmaped-to-usermode
-  addresses */
-   physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
-   up_read(¤t->mm->mmap_sem);
-   } else {
-   /* otherwise, use get_user_pages() for general userland pages */
-   int res, nr_pages = 1;
-   struct page *pages;
+   if (virtp >= PAGE_OFFSET) {
+   *physp = virt_to_phys((void *)virtp);
+   return 0;
+   }
 
-   res = get_user_pages(current, current->mm, virtp, nr_pages, 1,
-   0, &pages, NULL);
-   up_read(¤t->mm->mmap_sem);
+   vec = frame_vector_create(1);
+   if (!vec)
+   return -ENOMEM;
 
-   if (res == nr_pages) {
-   physp =  __pa(page_address(&pages[0]) +
-   (virtp & ~PAGE_MASK));
-   } else {
-   printk(KERN_WARNING VOUT_NAME
-   "get_user_pages failed\n");
-   return 0;
-   }
+   ret = get_vaddr_frames(virtp, 1, true, false, vec);
+   if (ret != 1) {
+   frame_vector_destroy(vec);
+   return -EINVAL;
}
+   *physp = __pfn_to_phys(frame_vector_pfns(vec)[0]);
+   vb->priv = vec;
 
-   return physp;
+   return 0;
 }
 
 /*
@@ -784,11 +772,15 @@ static int omap_vout_buffer_prepare(struct videobuf_queue 
*q,
 * address of the buffer
 */
if (V4L2_MEMORY_USERPTR == vb->memory) {
+   int ret;
+
if (0 == vb->baddr)
return -EINVAL;
/* Physical address */
-   vout->queued_buf_addr[vb->i] = (u8 *)
-   omap_vout_uservirt_to_phys(vb->baddr);
+   ret = omap_vout_get_userptr(vb, vb->baddr,
+   (u32 *)&vout->queued_buf_addr[vb->i]);
+   if (ret < 0)
+   return ret;
} else {
unsigned long addr, dma_addr;
unsigned long size;
@@ -837,9 +829,12 @@ static void omap_vout_buffer_release(struct videobuf_queue 
*q,
struct omap_vout_device *vout = q->priv_data;
 
vb->state = VIDEOBUF_NEEDS_INIT;
+   if (vb->memory == V4L2_MEMORY_USERPTR && vb->priv) {
+   struct frame_vector *vec = vb->priv;
 
-   if (V4L2_MEMORY_MMAP != vout->memory)
-   return;
+   

[PATCH 7/9] media: vb2: Convert vb2_dc_get_userptr() to use frame vector

2015-07-13 Thread Jan Kara
From: Jan Kara 

Convert vb2_dc_get_userptr() to use frame vector infrastructure. When we
are doing that there's no need to allocate page array and some code can
be simplified.

Acked-by: Marek Szyprowski 
Tested-by: Marek Szyprowski 
Signed-off-by: Jan Kara 
---
 drivers/media/v4l2-core/videobuf2-dma-contig.c | 212 -
 1 file changed, 34 insertions(+), 178 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index c548ce425701..2397ceb1dc6b 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -32,15 +32,13 @@ struct vb2_dc_buf {
dma_addr_t  dma_addr;
enum dma_data_direction dma_dir;
struct sg_table *dma_sgt;
+   struct frame_vector *vec;
 
/* MMAP related */
struct vb2_vmarea_handler   handler;
atomic_trefcount;
struct sg_table *sgt_base;
 
-   /* USERPTR related */
-   struct vm_area_struct   *vma;
-
/* DMABUF related */
struct dma_buf_attachment   *db_attach;
 };
@@ -49,24 +47,6 @@ struct vb2_dc_buf {
 /*scatterlist table functions*/
 /*/
 
-
-static void vb2_dc_sgt_foreach_page(struct sg_table *sgt,
-   void (*cb)(struct page *pg))
-{
-   struct scatterlist *s;
-   unsigned int i;
-
-   for_each_sg(sgt->sgl, s, sgt->orig_nents, i) {
-   struct page *page = sg_page(s);
-   unsigned int n_pages = PAGE_ALIGN(s->offset + s->length)
-   >> PAGE_SHIFT;
-   unsigned int j;
-
-   for (j = 0; j < n_pages; ++j, ++page)
-   cb(page);
-   }
-}
-
 static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt)
 {
struct scatterlist *s;
@@ -429,92 +409,12 @@ static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, 
unsigned long flags)
 /*   callbacks for USERPTR buffers   */
 /*/
 
-static inline int vma_is_io(struct vm_area_struct *vma)
-{
-   return !!(vma->vm_flags & (VM_IO | VM_PFNMAP));
-}
-
-static int vb2_dc_get_user_pfn(unsigned long start, int n_pages,
-   struct vm_area_struct *vma, unsigned long *res)
-{
-   unsigned long pfn, start_pfn, prev_pfn;
-   unsigned int i;
-   int ret;
-
-   if (!vma_is_io(vma))
-   return -EFAULT;
-
-   ret = follow_pfn(vma, start, &pfn);
-   if (ret)
-   return ret;
-
-   start_pfn = pfn;
-   start += PAGE_SIZE;
-
-   for (i = 1; i < n_pages; ++i, start += PAGE_SIZE) {
-   prev_pfn = pfn;
-   ret = follow_pfn(vma, start, &pfn);
-
-   if (ret) {
-   pr_err("no page for address %lu\n", start);
-   return ret;
-   }
-   if (pfn != prev_pfn + 1)
-   return -EINVAL;
-   }
-
-   *res = start_pfn;
-   return 0;
-}
-
-static int vb2_dc_get_user_pages(unsigned long start, struct page **pages,
-   int n_pages, struct vm_area_struct *vma,
-   enum dma_data_direction dma_dir)
-{
-   if (vma_is_io(vma)) {
-   unsigned int i;
-
-   for (i = 0; i < n_pages; ++i, start += PAGE_SIZE) {
-   unsigned long pfn;
-   int ret = follow_pfn(vma, start, &pfn);
-
-   if (!pfn_valid(pfn))
-   return -EINVAL;
-
-   if (ret) {
-   pr_err("no page for address %lu\n", start);
-   return ret;
-   }
-   pages[i] = pfn_to_page(pfn);
-   }
-   } else {
-   int n;
-
-   n = get_user_pages(current, current->mm, start & PAGE_MASK,
-   n_pages, dma_dir == DMA_FROM_DEVICE, 1, pages, NULL);
-   /* negative error means that no page was pinned */
-   n = max(n, 0);
-   if (n != n_pages) {
-   pr_err("got only %d of %d user pages\n", n, n_pages);
-   while (n)
-   put_page(pages[--n]);
-   return -EFAULT;
-   }
-   }
-
-   return 0;
-}
-
-static void vb2_dc_put_dirty_page(struct page *page)
-{
-   set_page_dirty_lock(page);
-   put_page(page);
-}
-
 static void vb2_dc_put_userptr(void *buf_priv)
 {
struct vb2_dc_buf *buf = buf_priv;
struct sg_table *sgt = buf->dma_sgt;
+   int i;
+   struct page **pages;
 
if (sgt) {
D

[PATCH 4/9] vb2: Provide helpers for mapping virtual addresses

2015-07-13 Thread Jan Kara
From: Jan Kara 

Provide simple helper functions to map virtual address range into an
array of pfns / pages.

Acked-by: Marek Szyprowski 
Tested-by: Marek Szyprowski 
Signed-off-by: Jan Kara 
---
 drivers/media/v4l2-core/Kconfig|  1 +
 drivers/media/v4l2-core/videobuf2-memops.c | 58 ++
 include/media/videobuf2-memops.h   |  5 +++
 3 files changed, 64 insertions(+)

diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index b4b022933e29..82876a67f144 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -84,6 +84,7 @@ config VIDEOBUF2_CORE
 
 config VIDEOBUF2_MEMOPS
tristate
+   select FRAME_VECTOR
 
 config VIDEOBUF2_DMA_CONTIG
tristate
diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 81c1ad8b2cf1..0ec186d41b9b 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -137,6 +137,64 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned 
long size,
 EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
 
 /**
+ * vb2_create_framevec() - map virtual addresses to pfns
+ * @start: Virtual user address where we start mapping
+ * @length:Length of a range to map
+ * @write: Should we map for writing into the area
+ *
+ * This function allocates and fills in a vector with pfns corresponding to
+ * virtual address range passed in arguments. If pfns have corresponding pages,
+ * page references are also grabbed to pin pages in memory. The function
+ * returns pointer to the vector on success and error pointer in case of
+ * failure. Returned vector needs to be freed via vb2_destroy_pfnvec().
+ */
+struct frame_vector *vb2_create_framevec(unsigned long start,
+unsigned long length,
+bool write)
+{
+   int ret;
+   unsigned long first, last;
+   unsigned long nr;
+   struct frame_vector *vec;
+
+   first = start >> PAGE_SHIFT;
+   last = (start + length - 1) >> PAGE_SHIFT;
+   nr = last - first + 1;
+   vec = frame_vector_create(nr);
+   if (!vec)
+   return ERR_PTR(-ENOMEM);
+   ret = get_vaddr_frames(start, nr, write, 1, vec);
+   if (ret < 0)
+   goto out_destroy;
+   /* We accept only complete set of PFNs */
+   if (ret != nr) {
+   ret = -EFAULT;
+   goto out_release;
+   }
+   return vec;
+out_release:
+   put_vaddr_frames(vec);
+out_destroy:
+   frame_vector_destroy(vec);
+   return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(vb2_create_framevec);
+
+/**
+ * vb2_destroy_framevec() - release vector of mapped pfns
+ * @vec:   vector of pfns / pages to release
+ *
+ * This releases references to all pages in the vector @vec (if corresponding
+ * pfns are backed by pages) and frees the passed vector.
+ */
+void vb2_destroy_framevec(struct frame_vector *vec)
+{
+   put_vaddr_frames(vec);
+   frame_vector_destroy(vec);
+}
+EXPORT_SYMBOL(vb2_destroy_framevec);
+
+/**
  * vb2_common_vm_open() - increase refcount of the vma
  * @vma:   virtual memory region for the mapping
  *
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index f05444ca8c0c..2f0564ff5f31 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -15,6 +15,7 @@
 #define _MEDIA_VIDEOBUF2_MEMOPS_H
 
 #include 
+#include 
 
 /**
  * vb2_vmarea_handler - common vma refcount tracking handler
@@ -36,5 +37,9 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long 
size,
 struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
 void vb2_put_vma(struct vm_area_struct *vma);
 
+struct frame_vector *vb2_create_framevec(unsigned long start,
+unsigned long length,
+bool write);
+void vb2_destroy_framevec(struct frame_vector *vec);
 
 #endif
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 5/9] media: vb2: Convert vb2_dma_sg_get_userptr() to use frame vector

2015-07-13 Thread Jan Kara
From: Jan Kara 

Acked-by: Marek Szyprowski 
Tested-by: Marek Szyprowski 
Signed-off-by: Jan Kara 
---
 drivers/media/v4l2-core/videobuf2-dma-sg.c | 95 +-
 1 file changed, 15 insertions(+), 80 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c 
b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index d2cf113d1933..be7bd6535c9d 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -38,6 +38,7 @@ struct vb2_dma_sg_buf {
struct device   *dev;
void*vaddr;
struct page **pages;
+   struct frame_vector *vec;
int offset;
enum dma_data_direction dma_dir;
struct sg_table sg_table;
@@ -51,7 +52,6 @@ struct vb2_dma_sg_buf {
unsigned intnum_pages;
atomic_trefcount;
struct vb2_vmarea_handler   handler;
-   struct vm_area_struct   *vma;
 
struct dma_buf_attachment   *db_attach;
 };
@@ -225,25 +225,17 @@ static void vb2_dma_sg_finish(void *buf_priv)
dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
 }
 
-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,
unsigned long size,
enum dma_data_direction dma_dir)
 {
struct vb2_dma_sg_conf *conf = alloc_ctx;
struct vb2_dma_sg_buf *buf;
-   unsigned long first, last;
-   int num_pages_from_user;
-   struct vm_area_struct *vma;
struct sg_table *sgt;
DEFINE_DMA_ATTRS(attrs);
+   struct frame_vector *vec;
 
dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
-
buf = kzalloc(sizeof *buf, GFP_KERNEL);
if (!buf)
return NULL;
@@ -254,63 +246,19 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
buf->offset = vaddr & ~PAGE_MASK;
buf->size = size;
buf->dma_sgt = &buf->sg_table;
+   vec = vb2_create_framevec(vaddr, size, buf->dma_dir == DMA_FROM_DEVICE);
+   if (IS_ERR(vec))
+   goto userptr_fail_pfnvec;
+   buf->vec = vec;
 
-   first = (vaddr   & PAGE_MASK) >> PAGE_SHIFT;
-   last  = ((vaddr + size - 1) & PAGE_MASK) >> PAGE_SHIFT;
-   buf->num_pages = last - first + 1;
-
-   buf->pages = kzalloc(buf->num_pages * sizeof(struct page *),
-GFP_KERNEL);
-   if (!buf->pages)
-   goto userptr_fail_alloc_pages;
-
-   down_read(¤t->mm->mmap_sem);
-   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(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,
-buf->num_pages,
-buf->dma_dir == DMA_FROM_DEVICE,
-1, /* force */
-buf->pages,
-NULL);
-   up_read(¤t->mm->mmap_sem);
-
-   if (num_pages_from_user != buf->num_pages)
-   goto userptr_fail_get_user_pages;
+   buf->pages = frame_vector_pages(vec);
+   if (IS_ERR(buf->pages))
+   goto userptr_fail_sgtable;
+   buf->num_pages = frame_vector_count(vec);
 
if (sg_alloc_table_from_pages(buf->dma_sgt, buf->pages,
   

[PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()

2015-07-13 Thread Jan Kara
From: Jan Kara 

Convert g2d_userptr_get_dma_addr() to pin pages using get_vaddr_frames().
This removes the knowledge about vmas and mmap_sem locking from exynos
driver. Also it fixes a problem that the function has been mapping user
provided address without holding mmap_sem.

Signed-off-by: Jan Kara 
---
 drivers/gpu/drm/exynos/Kconfig  |  1 +
 drivers/gpu/drm/exynos/exynos_drm_g2d.c | 91 ++-
 drivers/gpu/drm/exynos/exynos_drm_gem.c | 97 -
 3 files changed, 30 insertions(+), 159 deletions(-)

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 43003c4ad80b..b364562dc6c1 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -77,6 +77,7 @@ config DRM_EXYNOS_VIDI
 config DRM_EXYNOS_G2D
bool "Exynos DRM G2D"
depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_G2D
+   select FRAME_VECTOR
help
  Choose this option if you want to use Exynos G2D for DRM.
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c 
b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 81a250830808..1d8d9a508373 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -190,10 +190,8 @@ struct g2d_cmdlist_userptr {
dma_addr_t  dma_addr;
unsigned long   userptr;
unsigned long   size;
-   struct page **pages;
-   unsigned intnpages;
+   struct frame_vector *vec;
struct sg_table *sgt;
-   struct vm_area_struct   *vma;
atomic_trefcount;
boolin_pool;
boolout_of_list;
@@ -363,6 +361,7 @@ static void g2d_userptr_put_dma_addr(struct drm_device 
*drm_dev,
 {
struct g2d_cmdlist_userptr *g2d_userptr =
(struct g2d_cmdlist_userptr *)obj;
+   struct page **pages;
 
if (!obj)
return;
@@ -382,19 +381,21 @@ out:
exynos_gem_unmap_sgt_from_dma(drm_dev, g2d_userptr->sgt,
DMA_BIDIRECTIONAL);
 
-   exynos_gem_put_pages_to_userptr(g2d_userptr->pages,
-   g2d_userptr->npages,
-   g2d_userptr->vma);
+   pages = frame_vector_pages(g2d_userptr->vec);
+   if (!IS_ERR(pages)) {
+   int i;
 
-   exynos_gem_put_vma(g2d_userptr->vma);
+   for (i = 0; i < frame_vector_count(g2d_userptr->vec); i++)
+   set_page_dirty_lock(pages[i]);
+   }
+   put_vaddr_frames(g2d_userptr->vec);
+   frame_vector_destroy(g2d_userptr->vec);
 
if (!g2d_userptr->out_of_list)
list_del_init(&g2d_userptr->list);
 
sg_free_table(g2d_userptr->sgt);
kfree(g2d_userptr->sgt);
-
-   drm_free_large(g2d_userptr->pages);
kfree(g2d_userptr);
 }
 
@@ -408,9 +409,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
drm_device *drm_dev,
struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
struct g2d_cmdlist_userptr *g2d_userptr;
struct g2d_data *g2d;
-   struct page **pages;
struct sg_table *sgt;
-   struct vm_area_struct *vma;
unsigned long start, end;
unsigned int npages, offset;
int ret;
@@ -456,65 +455,38 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
drm_device *drm_dev,
return ERR_PTR(-ENOMEM);
 
atomic_set(&g2d_userptr->refcount, 1);
+   g2d_userptr->size = size;
 
start = userptr & PAGE_MASK;
offset = userptr & ~PAGE_MASK;
end = PAGE_ALIGN(userptr + size);
npages = (end - start) >> PAGE_SHIFT;
-   g2d_userptr->npages = npages;
-
-   pages = drm_calloc_large(npages, sizeof(struct page *));
-   if (!pages) {
-   DRM_ERROR("failed to allocate pages.\n");
-   ret = -ENOMEM;
+   g2d_userptr->vec = frame_vector_create(npages);
+   if (!g2d_userptr->vec)
goto err_free;
-   }
 
-   down_read(¤t->mm->mmap_sem);
-   vma = find_vma(current->mm, userptr);
-   if (!vma) {
-   up_read(¤t->mm->mmap_sem);
-   DRM_ERROR("failed to get vm region.\n");
+   ret = get_vaddr_frames(start, npages, true, true, g2d_userptr->vec);
+   if (ret != npages) {
+   DRM_ERROR("failed to get user pages from userptr.\n");
+   if (ret < 0)
+   goto err_destroy_framevec;
ret = -EFAULT;
-   goto err_free_pages;
+   goto err_put_framevec;
}
-
-   if (vma->vm_end < userptr + size) {
-   up_read(¤t->mm->mmap_sem);
-

[PATCH 2/9] mm: Provide new get_vaddr_frames() helper

2015-07-13 Thread Jan Kara
From: Jan Kara 

Provide new function get_vaddr_frames().  This function maps virtual
addresses from given start and fills given array with page frame numbers of
the corresponding pages. If given start belongs to a normal vma, the function
grabs reference to each of the pages to pin them in memory. If start
belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
must make sure pfns aren't reused for anything else while he is using
them.

This function is created for various drivers to simplify handling of
their buffers.

Acked-by: Mel Gorman 
Acked-by: Vlastimil Babka 
Signed-off-by: Jan Kara 
---
 include/linux/mm.h |  44 ++
 mm/Kconfig |   3 +
 mm/Makefile|   1 +
 mm/frame_vector.c  | 231 +
 4 files changed, 279 insertions(+)
 create mode 100644 mm/frame_vector.c

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 2e872f92dbac..79ad29a8a60a 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -20,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct mempolicy;
 struct anon_vma;
@@ -1198,6 +1199,49 @@ long get_user_pages_unlocked(struct task_struct *tsk, 
struct mm_struct *mm,
int write, int force, struct page **pages);
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
struct page **pages);
+
+/* Container for pinned pfns / pages */
+struct frame_vector {
+   unsigned int nr_allocated;  /* Number of frames we have space for */
+   unsigned int nr_frames; /* Number of frames stored in ptrs array */
+   bool got_ref;   /* Did we pin pages by getting page ref? */
+   bool is_pfns;   /* Does array contain pages or pfns? */
+   void *ptrs[0];  /* Array of pinned pfns / pages. Use
+* pfns_vector_pages() or pfns_vector_pfns()
+* for access */
+};
+
+struct frame_vector *frame_vector_create(unsigned int nr_frames);
+void frame_vector_destroy(struct frame_vector *vec);
+int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
+bool write, bool force, struct frame_vector *vec);
+void put_vaddr_frames(struct frame_vector *vec);
+int frame_vector_to_pages(struct frame_vector *vec);
+void frame_vector_to_pfns(struct frame_vector *vec);
+
+static inline unsigned int frame_vector_count(struct frame_vector *vec)
+{
+   return vec->nr_frames;
+}
+
+static inline struct page **frame_vector_pages(struct frame_vector *vec)
+{
+   if (vec->is_pfns) {
+   int err = frame_vector_to_pages(vec);
+
+   if (err)
+   return ERR_PTR(err);
+   }
+   return (struct page **)(vec->ptrs);
+}
+
+static inline unsigned long *frame_vector_pfns(struct frame_vector *vec)
+{
+   if (!vec->is_pfns)
+   frame_vector_to_pfns(vec);
+   return (unsigned long *)(vec->ptrs);
+}
+
 struct kvec;
 int get_kernel_pages(const struct kvec *iov, int nr_pages, int write,
struct page **pages);
diff --git a/mm/Kconfig b/mm/Kconfig
index e79de2bd12cd..7f146dd32fc5 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -654,3 +654,6 @@ config DEFERRED_STRUCT_PAGE_INIT
  when kswapd starts. This has a potential performance impact on
  processes running early in the lifetime of the systemm until kswapd
  finishes the initialisation.
+
+config FRAME_VECTOR
+   bool
diff --git a/mm/Makefile b/mm/Makefile
index 98c4eaeabdcb..be5d5c866305 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -78,3 +78,4 @@ obj-$(CONFIG_CMA) += cma.o
 obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o
 obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o
 obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
+obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o
diff --git a/mm/frame_vector.c b/mm/frame_vector.c
new file mode 100644
index ..f76b579e46f1
--- /dev/null
+++ b/mm/frame_vector.c
@@ -0,0 +1,231 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/*
+ * get_vaddr_frames() - map virtual addresses to pfns
+ * @start: starting user address
+ * @nr_frames: number of pages / pfns from start to map
+ * @write: whether pages will be written to by the caller
+ * @force: whether to force write access even if user mapping is
+ * readonly. See description of the same argument of
+   get_user_pages().
+ * @vec:   structure which receives pages / pfns of the addresses mapped.
+ * It should have space for at least nr_frames entries.
+ *
+ * This function maps virtual addresses from @start and fills @vec structure
+ * with page frame numbers or page pointers to corresponding pages (choice
+ * depends on the type of the vma underlying the virtual address). If @start
+ * belongs to a normal vma, the function grabs reference to each of the pages
+ * to pin 

[PATCH 8/9] media: vb2: Remove unused functions

2015-07-13 Thread Jan Kara
From: Jan Kara 

Conversion to the use of pinned pfns made some functions unused. Remove
them. Also there's no need to lock mmap_sem in __buf_prepare() anymore.

Acked-by: Marek Szyprowski 
Tested-by: Marek Szyprowski 
Signed-off-by: Jan Kara 
---
 drivers/media/v4l2-core/videobuf2-memops.c | 114 -
 include/media/videobuf2-memops.h   |   6 --
 2 files changed, 120 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 0ec186d41b9b..48c6a49c4928 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -23,120 +23,6 @@
 #include 
 
 /**
- * vb2_get_vma() - acquire and lock the virtual memory area
- * @vma:   given virtual memory area
- *
- * This function attempts to acquire an area mapped in the userspace for
- * the duration of a hardware operation. The area is "locked" by performing
- * the same set of operation that are done when process calls fork() and
- * memory areas are duplicated.
- *
- * Returns a copy of a virtual memory region on success or NULL.
- */
-struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma)
-{
-   struct vm_area_struct *vma_copy;
-
-   vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
-   if (vma_copy == NULL)
-   return NULL;
-
-   if (vma->vm_ops && vma->vm_ops->open)
-   vma->vm_ops->open(vma);
-
-   if (vma->vm_file)
-   get_file(vma->vm_file);
-
-   memcpy(vma_copy, vma, sizeof(*vma));
-
-   vma_copy->vm_mm = NULL;
-   vma_copy->vm_next = NULL;
-   vma_copy->vm_prev = NULL;
-
-   return vma_copy;
-}
-EXPORT_SYMBOL_GPL(vb2_get_vma);
-
-/**
- * vb2_put_userptr() - release a userspace virtual memory area
- * @vma:   virtual memory region associated with the area to be released
- *
- * This function releases the previously acquired memory area after a hardware
- * operation.
- */
-void vb2_put_vma(struct vm_area_struct *vma)
-{
-   if (!vma)
-   return;
-
-   if (vma->vm_ops && vma->vm_ops->close)
-   vma->vm_ops->close(vma);
-
-   if (vma->vm_file)
-   fput(vma->vm_file);
-
-   kfree(vma);
-}
-EXPORT_SYMBOL_GPL(vb2_put_vma);
-
-/**
- * vb2_get_contig_userptr() - lock physically contiguous userspace mapped 
memory
- * @vaddr: starting virtual address of the area to be verified
- * @size:  size of the area
- * @res_paddr: will return physical address for the given vaddr
- * @res_vma:   will return locked copy of struct vm_area for the given area
- *
- * This function will go through memory area of size @size mapped at @vaddr and
- * verify that the underlying physical pages are contiguous. If they are
- * contiguous the virtual memory area is locked and a @res_vma is filled with
- * the copy and @res_pa set to the physical address of the buffer.
- *
- * Returns 0 on success.
- */
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa)
-{
-   struct mm_struct *mm = current->mm;
-   struct vm_area_struct *vma;
-   unsigned long offset, start, end;
-   unsigned long this_pfn, prev_pfn;
-   dma_addr_t pa = 0;
-
-   start = vaddr;
-   offset = start & ~PAGE_MASK;
-   end = start + size;
-
-   vma = find_vma(mm, start);
-
-   if (vma == NULL || vma->vm_end < end)
-   return -EFAULT;
-
-   for (prev_pfn = 0; start < end; start += PAGE_SIZE) {
-   int ret = follow_pfn(vma, start, &this_pfn);
-   if (ret)
-   return ret;
-
-   if (prev_pfn == 0)
-   pa = this_pfn << PAGE_SHIFT;
-   else if (this_pfn != prev_pfn + 1)
-   return -EFAULT;
-
-   prev_pfn = this_pfn;
-   }
-
-   /*
-* Memory is contigous, lock vma and return to the caller
-*/
-   *res_vma = vb2_get_vma(vma);
-   if (*res_vma == NULL)
-   return -ENOMEM;
-
-   *res_pa = pa + offset;
-   return 0;
-}
-EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
-
-/**
  * vb2_create_framevec() - map virtual addresses to pfns
  * @start: Virtual user address where we start mapping
  * @length:Length of a range to map
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index 2f0564ff5f31..830b5239fd8b 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -31,12 +31,6 @@ struct vb2_vmarea_handler {
 
 extern const struct vm_operations_struct vb2_common_vm_ops;
 
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa);
-
-struct vm_area_struct *vb

Re: [PATCH 0/10 v6] Helper to abstract vma handling in media layer

2015-07-13 Thread Jan Kara
On Mon 13-07-15 10:45:25, Hans Verkuil wrote:
> On 07/09/2015 02:12 PM, Hans Verkuil wrote:
> > On 07/09/2015 01:48 PM, Jan Kara wrote:
> >>   Hello,
> >>
> >>   Hans, did you have a chance to look at these patches? I have tested them
> >> with the vivid driver but it would be good if you could run them through
> >> your standard testing procedure as well. Andrew has updated the patches in
> >> his tree but some ack from you would be welcome...
> > 
> > I've planned a 'patch day' for Monday. So hopefully you'll see a pull 
> > request
> > by then.
> 
> OK, I'm confused. I thought the non-vb2 patches would go in for 4.2? That
> didn't happen, so I guess the plan is to merge the whole lot for 4.3 via
> our media tree? If that's the case, can you post a new patch series on

I guess Andrew wasn't sure what to push and what not so he just chose the
safe option to not push anything.

> top of the master branch of the media tree? I want to make sure I use the
> right patches. Also, if you do make a new patch series, then it would be
> better if patch 10/10 is folded into patch 2/10.

OK, I'll rebase patches on top of media tree.

Honza

> >> On Thu 18-06-15 16:08:30, Jan Kara wrote:
> >>>   Hello,
> >>>
> >>> I'm sending the sixth version of my patch series to abstract vma handling 
> >>> from
> >>> the various media drivers. Since the previous version I have added a 
> >>> patch to
> >>> move mm helpers into a separate file and behind a config option. I also
> >>> changed patch pushing mmap_sem down in videobuf2 core to avoid lockdep 
> >>> warning
> >>> and NULL dereference Hans found in his testing. I've also included small
> >>> fixups Andrew was carrying.
> >>>
> >>> After this patch set drivers have to know much less details about vmas, 
> >>> their
> >>> types, and locking. Also quite some code is removed from them. As a bonus
> >>> drivers get automatically VM_FAULT_RETRY handling. The primary motivation 
> >>> for
> >>> this series is to remove knowledge about mmap_sem locking from as many 
> >>> places a
> >>> possible so that we can change it with reasonable effort.
> >>>
> >>> The core of the series is the new helper get_vaddr_frames() which is 
> >>> given a
> >>> virtual address and it fills in PFNs / struct page pointers (depending on 
> >>> VMA
> >>> type) into the provided array. If PFNs correspond to normal pages it also 
> >>> grabs
> >>> references to these pages. The difference from get_user_pages() is that 
> >>> this
> >>> function can also deal with pfnmap, and io mappings which is what the 
> >>> media
> >>> drivers need.
> >>>
> >>> I have tested the patches with vivid driver so at least vb2 code got some
> >>> exposure. Conversion of other drivers was just compile-tested (for x86 so 
> >>> e.g.
> >>> exynos driver which is only for Samsung platform is completely untested).
> >>>
> >>> Andrew, can you please update the patches in mm three? Thanks!
> >>>
> >>>   Honza
> >>>
> >>> Changes since v5:
> >>> * Moved mm helper into a separate file and behind a config option
> >>> * Changed the first patch pushing mmap_sem down in videobuf2 core to avoid
> >>>   possible deadlock
> >>>
> >>> Changes since v4:
> >>> * Minor cleanups and fixes pointed out by Mel and Vlasta
> >>> * Added Acked-by tags
> >>>
> >>> Changes since v3:
> >>> * Added include  into mm/gup.c as it's needed for some 
> >>> archs
> >>> * Fixed error path for exynos driver
> >>>
> >>> Changes since v2:
> >>> * Renamed functions and structures as Mel suggested
> >>> * Other minor changes suggested by Mel
> >>> * Rebased on top of 4.1-rc2
> >>> * Changed functions to get pointer to array of pages / pfns to perform
> >>>   conversion if necessary. This fixes possible issue in the omap I may 
> >>> have
> >>>   introduced in v2 and generally makes the API less errorprone.
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-media" in
> > the body of a message to majord...@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > 
> 
-- 
Jan Kara 
SUSE Labs, CR
--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 0/10 v6] Helper to abstract vma handling in media layer

2015-07-09 Thread Jan Kara
  Hello,

  Hans, did you have a chance to look at these patches? I have tested them
with the vivid driver but it would be good if you could run them through
your standard testing procedure as well. Andrew has updated the patches in
his tree but some ack from you would be welcome...

Honza
On Thu 18-06-15 16:08:30, Jan Kara wrote:
>   Hello,
> 
> I'm sending the sixth version of my patch series to abstract vma handling from
> the various media drivers. Since the previous version I have added a patch to
> move mm helpers into a separate file and behind a config option. I also
> changed patch pushing mmap_sem down in videobuf2 core to avoid lockdep warning
> and NULL dereference Hans found in his testing. I've also included small
> fixups Andrew was carrying.
> 
> After this patch set drivers have to know much less details about vmas, their
> types, and locking. Also quite some code is removed from them. As a bonus
> drivers get automatically VM_FAULT_RETRY handling. The primary motivation for
> this series is to remove knowledge about mmap_sem locking from as many places 
> a
> possible so that we can change it with reasonable effort.
> 
> The core of the series is the new helper get_vaddr_frames() which is given a
> virtual address and it fills in PFNs / struct page pointers (depending on VMA
> type) into the provided array. If PFNs correspond to normal pages it also 
> grabs
> references to these pages. The difference from get_user_pages() is that this
> function can also deal with pfnmap, and io mappings which is what the media
> drivers need.
> 
> I have tested the patches with vivid driver so at least vb2 code got some
> exposure. Conversion of other drivers was just compile-tested (for x86 so e.g.
> exynos driver which is only for Samsung platform is completely untested).
> 
> Andrew, can you please update the patches in mm three? Thanks!
> 
>   Honza
> 
> Changes since v5:
> * Moved mm helper into a separate file and behind a config option
> * Changed the first patch pushing mmap_sem down in videobuf2 core to avoid
>   possible deadlock
> 
> Changes since v4:
> * Minor cleanups and fixes pointed out by Mel and Vlasta
> * Added Acked-by tags
> 
> Changes since v3:
> * Added include  into mm/gup.c as it's needed for some archs
> * Fixed error path for exynos driver
> 
> Changes since v2:
> * Renamed functions and structures as Mel suggested
> * Other minor changes suggested by Mel
> * Rebased on top of 4.1-rc2
> * Changed functions to get pointer to array of pages / pfns to perform
>   conversion if necessary. This fixes possible issue in the omap I may have
>   introduced in v2 and generally makes the API less errorprone.
-- 
Jan Kara 
SUSE Labs, CR
--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 5/10] media: vb2: Convert vb2_dma_sg_get_userptr() to use frame vector

2015-06-18 Thread Jan Kara
Acked-by: Marek Szyprowski 
Tested-by: Marek Szyprowski 
Signed-off-by: Jan Kara 
---
 drivers/media/v4l2-core/videobuf2-dma-sg.c | 95 +-
 1 file changed, 15 insertions(+), 80 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c 
b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index cdcf5ad79012..4ee1b3fbfe2a 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -38,6 +38,7 @@ struct vb2_dma_sg_buf {
struct device   *dev;
void*vaddr;
struct page **pages;
+   struct frame_vector *vec;
int offset;
enum dma_data_direction dma_dir;
struct sg_table sg_table;
@@ -51,7 +52,6 @@ struct vb2_dma_sg_buf {
unsigned intnum_pages;
atomic_trefcount;
struct vb2_vmarea_handler   handler;
-   struct vm_area_struct   *vma;
 
struct dma_buf_attachment   *db_attach;
 };
@@ -224,25 +224,17 @@ static void vb2_dma_sg_finish(void *buf_priv)
dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
 }
 
-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,
unsigned long size,
enum dma_data_direction dma_dir)
 {
struct vb2_dma_sg_conf *conf = alloc_ctx;
struct vb2_dma_sg_buf *buf;
-   unsigned long first, last;
-   int num_pages_from_user;
-   struct vm_area_struct *vma;
struct sg_table *sgt;
DEFINE_DMA_ATTRS(attrs);
+   struct frame_vector *vec;
 
dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
-
buf = kzalloc(sizeof *buf, GFP_KERNEL);
if (!buf)
return NULL;
@@ -253,63 +245,19 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
buf->offset = vaddr & ~PAGE_MASK;
buf->size = size;
buf->dma_sgt = &buf->sg_table;
+   vec = vb2_create_framevec(vaddr, size, buf->dma_dir == DMA_FROM_DEVICE);
+   if (IS_ERR(vec))
+   goto userptr_fail_pfnvec;
+   buf->vec = vec;
 
-   first = (vaddr   & PAGE_MASK) >> PAGE_SHIFT;
-   last  = ((vaddr + size - 1) & PAGE_MASK) >> PAGE_SHIFT;
-   buf->num_pages = last - first + 1;
-
-   buf->pages = kzalloc(buf->num_pages * sizeof(struct page *),
-GFP_KERNEL);
-   if (!buf->pages)
-   goto userptr_fail_alloc_pages;
-
-   down_read(¤t->mm->mmap_sem);
-   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(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,
-buf->num_pages,
-buf->dma_dir == DMA_FROM_DEVICE,
-1, /* force */
-buf->pages,
-NULL);
-   up_read(¤t->mm->mmap_sem);
-
-   if (num_pages_from_user != buf->num_pages)
-   goto userptr_fail_get_user_pages;
+   buf->pages = frame_vector_pages(vec);
+   if (IS_ERR(buf->pages))
+   goto userptr_fail_sgtable;
+   buf->num_pages = frame_vector_count(vec);
 
if (sg_alloc_table_from_pages(buf->dma_sgt, buf->pages,
buf->num_

[PATCH 8/10] media: vb2: Remove unused functions

2015-06-18 Thread Jan Kara
Conversion to the use of pinned pfns made some functions unused. Remove
them. Also there's no need to lock mmap_sem in __buf_prepare() anymore.

Acked-by: Marek Szyprowski 
Tested-by: Marek Szyprowski 
Signed-off-by: Jan Kara 
---
 drivers/media/v4l2-core/videobuf2-memops.c | 114 -
 include/media/videobuf2-memops.h   |   6 --
 2 files changed, 120 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 0ec186d41b9b..48c6a49c4928 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -23,120 +23,6 @@
 #include 
 
 /**
- * vb2_get_vma() - acquire and lock the virtual memory area
- * @vma:   given virtual memory area
- *
- * This function attempts to acquire an area mapped in the userspace for
- * the duration of a hardware operation. The area is "locked" by performing
- * the same set of operation that are done when process calls fork() and
- * memory areas are duplicated.
- *
- * Returns a copy of a virtual memory region on success or NULL.
- */
-struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma)
-{
-   struct vm_area_struct *vma_copy;
-
-   vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
-   if (vma_copy == NULL)
-   return NULL;
-
-   if (vma->vm_ops && vma->vm_ops->open)
-   vma->vm_ops->open(vma);
-
-   if (vma->vm_file)
-   get_file(vma->vm_file);
-
-   memcpy(vma_copy, vma, sizeof(*vma));
-
-   vma_copy->vm_mm = NULL;
-   vma_copy->vm_next = NULL;
-   vma_copy->vm_prev = NULL;
-
-   return vma_copy;
-}
-EXPORT_SYMBOL_GPL(vb2_get_vma);
-
-/**
- * vb2_put_userptr() - release a userspace virtual memory area
- * @vma:   virtual memory region associated with the area to be released
- *
- * This function releases the previously acquired memory area after a hardware
- * operation.
- */
-void vb2_put_vma(struct vm_area_struct *vma)
-{
-   if (!vma)
-   return;
-
-   if (vma->vm_ops && vma->vm_ops->close)
-   vma->vm_ops->close(vma);
-
-   if (vma->vm_file)
-   fput(vma->vm_file);
-
-   kfree(vma);
-}
-EXPORT_SYMBOL_GPL(vb2_put_vma);
-
-/**
- * vb2_get_contig_userptr() - lock physically contiguous userspace mapped 
memory
- * @vaddr: starting virtual address of the area to be verified
- * @size:  size of the area
- * @res_paddr: will return physical address for the given vaddr
- * @res_vma:   will return locked copy of struct vm_area for the given area
- *
- * This function will go through memory area of size @size mapped at @vaddr and
- * verify that the underlying physical pages are contiguous. If they are
- * contiguous the virtual memory area is locked and a @res_vma is filled with
- * the copy and @res_pa set to the physical address of the buffer.
- *
- * Returns 0 on success.
- */
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa)
-{
-   struct mm_struct *mm = current->mm;
-   struct vm_area_struct *vma;
-   unsigned long offset, start, end;
-   unsigned long this_pfn, prev_pfn;
-   dma_addr_t pa = 0;
-
-   start = vaddr;
-   offset = start & ~PAGE_MASK;
-   end = start + size;
-
-   vma = find_vma(mm, start);
-
-   if (vma == NULL || vma->vm_end < end)
-   return -EFAULT;
-
-   for (prev_pfn = 0; start < end; start += PAGE_SIZE) {
-   int ret = follow_pfn(vma, start, &this_pfn);
-   if (ret)
-   return ret;
-
-   if (prev_pfn == 0)
-   pa = this_pfn << PAGE_SHIFT;
-   else if (this_pfn != prev_pfn + 1)
-   return -EFAULT;
-
-   prev_pfn = this_pfn;
-   }
-
-   /*
-* Memory is contigous, lock vma and return to the caller
-*/
-   *res_vma = vb2_get_vma(vma);
-   if (*res_vma == NULL)
-   return -ENOMEM;
-
-   *res_pa = pa + offset;
-   return 0;
-}
-EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
-
-/**
  * vb2_create_framevec() - map virtual addresses to pfns
  * @start: Virtual user address where we start mapping
  * @length:Length of a range to map
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index 2f0564ff5f31..830b5239fd8b 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -31,12 +31,6 @@ struct vb2_vmarea_handler {
 
 extern const struct vm_operations_struct vb2_common_vm_ops;
 
-int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
-  struct vm_area_struct **res_vma, dma_addr_t *res_pa);
-
-struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vm

[PATCH 1/10] [media] vb2: Push mmap_sem down to memops

2015-06-18 Thread Jan Kara
Currently vb2 core acquires mmap_sem just around call to
__qbuf_userptr(). However since commit f035eb4e976ef5 (videobuf2: fix
lockdep warning) it isn't necessary to acquire it so early as we no
longer have to drop queue mutex before acquiring mmap_sem. So push
acquisition of mmap_sem down into .get_userptr memop so that the
semaphore is acquired for a shorter time and it is clearer what it is
needed for.

Note that we also need mmap_sem in .put_userptr memop since that ends up
calling vb2_put_vma() which calls vma->vm_ops->close() which should be
called with mmap_sem held. However we didn't hold mmap_sem in some code
paths anyway (e.g. when called via vb2_ioctl_reqbufs() ->
__vb2_queue_free() -> vb2_dma_sg_put_userptr()) and getting mmap_sem in
put_userptr() introduces a lock inversion with queue->mmap_lock in the
above mentioned call path.

Luckily this whole locking mess will get resolved once we convert
videobuf2 core to the new mm helper which avoids the need for mmap_sem
in .put_userptr memop altogether.

Signed-off-by: Jan Kara 
---
 drivers/media/v4l2-core/videobuf2-core.c   | 2 --
 drivers/media/v4l2-core/videobuf2-dma-contig.c | 5 +
 drivers/media/v4l2-core/videobuf2-dma-sg.c | 4 
 drivers/media/v4l2-core/videobuf2-vmalloc.c| 4 +++-
 4 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-core.c 
b/drivers/media/v4l2-core/videobuf2-core.c
index 66ada01c796c..20cdbc0900ea 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -1657,9 +1657,7 @@ static int __buf_prepare(struct vb2_buffer *vb, const 
struct v4l2_buffer *b)
ret = __qbuf_mmap(vb, b);
break;
case V4L2_MEMORY_USERPTR:
-   down_read(¤t->mm->mmap_sem);
ret = __qbuf_userptr(vb, b);
-   up_read(¤t->mm->mmap_sem);
break;
case V4L2_MEMORY_DMABUF:
ret = __qbuf_dmabuf(vb, b);
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 644dec73d220..8e660f033d3c 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -616,6 +616,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
goto fail_buf;
}
 
+   down_read(¤t->mm->mmap_sem);
/* current->mm->mmap_sem is taken by videobuf2 core */
vma = find_vma(current->mm, vaddr);
if (!vma) {
@@ -642,6 +643,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
if (ret) {
unsigned long pfn;
if (vb2_dc_get_user_pfn(start, n_pages, vma, &pfn) == 0) {
+   up_read(¤t->mm->mmap_sem);
buf->dma_addr = vb2_dc_pfn_to_dma(buf->dev, pfn);
buf->size = size;
kfree(pages);
@@ -651,6 +653,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned 
long vaddr,
pr_err("failed to get user pages\n");
goto fail_vma;
}
+   up_read(¤t->mm->mmap_sem);
 
sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
if (!sgt) {
@@ -713,10 +716,12 @@ fail_get_user_pages:
while (n_pages)
put_page(pages[--n_pages]);
 
+   down_read(¤t->mm->mmap_sem);
 fail_vma:
vb2_put_vma(buf->vma);
 
 fail_pages:
+   up_read(¤t->mm->mmap_sem);
kfree(pages); /* kfree is NULL-proof */
 
 fail_buf:
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c 
b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index 45c708e463b9..cdcf5ad79012 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -263,6 +263,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
if (!buf->pages)
goto userptr_fail_alloc_pages;
 
+   down_read(¤t->mm->mmap_sem);
vma = find_vma(current->mm, vaddr);
if (!vma) {
dprintk(1, "no vma for address %lu\n", vaddr);
@@ -301,6 +302,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
 1, /* force */
 buf->pages,
 NULL);
+   up_read(¤t->mm->mmap_sem);
 
if (num_pages_from_user != buf->num_pages)
goto userptr_fail_get_user_pages;
@@ -328,8 +330,10 @@ userptr_fail_get_user_pages:
if (!vma_is_io(buf->vma))
while (--num_pages_from_user >= 0)
put_page(buf->pages[num_pages_from_user]);
+   down_read(¤t->mm->mmap_sem);
vb2_put_vma(buf->vma);
 userptr_f

[PATCH 3/10] media: omap_vout: Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns()

2015-06-18 Thread Jan Kara
Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns() instead of
hand made mapping of virtual address to physical address. Also the
function leaked page reference from get_user_pages() so fix that by
properly release the reference when omap_vout_buffer_release() is
called.

Signed-off-by: Jan Kara 
---
 drivers/media/platform/omap/omap_vout.c | 67 +++--
 1 file changed, 31 insertions(+), 36 deletions(-)

diff --git a/drivers/media/platform/omap/omap_vout.c 
b/drivers/media/platform/omap/omap_vout.c
index 17b189a81ec5..0e4b3cfacc5d 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -195,46 +195,34 @@ static int omap_vout_try_format(struct v4l2_pix_format 
*pix)
 }
 
 /*
- * omap_vout_uservirt_to_phys: This inline function is used to convert user
- * space virtual address to physical address.
+ * omap_vout_get_userptr: Convert user space virtual address to physical
+ * address.
  */
-static unsigned long omap_vout_uservirt_to_phys(unsigned long virtp)
+static int omap_vout_get_userptr(struct videobuf_buffer *vb, u32 virtp,
+u32 *physp)
 {
-   unsigned long physp = 0;
-   struct vm_area_struct *vma;
-   struct mm_struct *mm = current->mm;
+   struct frame_vector *vec;
+   int ret;
 
/* For kernel direct-mapped memory, take the easy way */
-   if (virtp >= PAGE_OFFSET)
-   return virt_to_phys((void *) virtp);
-
-   down_read(¤t->mm->mmap_sem);
-   vma = find_vma(mm, virtp);
-   if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) {
-   /* this will catch, kernel-allocated, mmaped-to-usermode
-  addresses */
-   physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
-   up_read(¤t->mm->mmap_sem);
-   } else {
-   /* otherwise, use get_user_pages() for general userland pages */
-   int res, nr_pages = 1;
-   struct page *pages;
+   if (virtp >= PAGE_OFFSET) {
+   *physp = virt_to_phys((void *)virtp);
+   return 0;
+   }
 
-   res = get_user_pages(current, current->mm, virtp, nr_pages, 1,
-   0, &pages, NULL);
-   up_read(¤t->mm->mmap_sem);
+   vec = frame_vector_create(1);
+   if (!vec)
+   return -ENOMEM;
 
-   if (res == nr_pages) {
-   physp =  __pa(page_address(&pages[0]) +
-   (virtp & ~PAGE_MASK));
-   } else {
-   printk(KERN_WARNING VOUT_NAME
-   "get_user_pages failed\n");
-   return 0;
-   }
+   ret = get_vaddr_frames(virtp, 1, true, false, vec);
+   if (ret != 1) {
+   frame_vector_destroy(vec);
+   return -EINVAL;
}
+   *physp = __pfn_to_phys(frame_vector_pfns(vec)[0]);
+   vb->priv = vec;
 
-   return physp;
+   return 0;
 }
 
 /*
@@ -788,11 +776,15 @@ static int omap_vout_buffer_prepare(struct videobuf_queue 
*q,
 * address of the buffer
 */
if (V4L2_MEMORY_USERPTR == vb->memory) {
+   int ret;
+
if (0 == vb->baddr)
return -EINVAL;
/* Physical address */
-   vout->queued_buf_addr[vb->i] = (u8 *)
-   omap_vout_uservirt_to_phys(vb->baddr);
+   ret = omap_vout_get_userptr(vb, vb->baddr,
+   (u32 *)&vout->queued_buf_addr[vb->i]);
+   if (ret < 0)
+   return ret;
} else {
unsigned long addr, dma_addr;
unsigned long size;
@@ -841,9 +833,12 @@ static void omap_vout_buffer_release(struct videobuf_queue 
*q,
struct omap_vout_device *vout = q->priv_data;
 
vb->state = VIDEOBUF_NEEDS_INIT;
+   if (vb->memory == V4L2_MEMORY_USERPTR && vb->priv) {
+   struct frame_vector *vec = vb->priv;
 
-   if (V4L2_MEMORY_MMAP != vout->memory)
-   return;
+   put_vaddr_frames(vec);
+   frame_vector_destroy(vec);
+   }
 }
 
 /*
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 10/10] mm: Move get_vaddr_frames() behind a config option

2015-06-18 Thread Jan Kara
get_vaddr_frames() is used by relatively rare drivers so hide it and the
related functions behind a config option that is selected only by
drivers that need the infrastructure.

The saving are:
add/remove: 0/6 grow/shrink: 0/0 up/down: 0/-868 (-868)
function old new   delta
frame_vector_destroy  55   - -55
frame_vector_to_pfns  56   - -56
frame_vector_create   81   - -81
put_vaddr_frames  93   - -93
frame_vector_to_pages 98   - -98
get_vaddr_frames 485   --485

Suggested-by: Andrew Morton 
Signed-off-by: Jan Kara 
---
 drivers/gpu/drm/exynos/Kconfig  |   1 +
 drivers/media/platform/omap/Kconfig |   1 +
 drivers/media/v4l2-core/Kconfig |   1 +
 mm/Kconfig  |   3 +
 mm/Makefile |   1 +
 mm/frame_vector.c   | 231 
 mm/gup.c| 222 --
 7 files changed, 238 insertions(+), 222 deletions(-)
 create mode 100644 mm/frame_vector.c

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 0a6780367d28..fc678289cf79 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -71,6 +71,7 @@ config DRM_EXYNOS_VIDI
 config DRM_EXYNOS_G2D
bool "Exynos DRM G2D"
depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_G2D
+   select FRAME_VECTOR
help
  Choose this option if you want to use Exynos G2D for DRM.
 
diff --git a/drivers/media/platform/omap/Kconfig 
b/drivers/media/platform/omap/Kconfig
index dc2aaab54aef..217d613b0fe7 100644
--- a/drivers/media/platform/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
@@ -10,6 +10,7 @@ config VIDEO_OMAP2_VOUT
select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS
select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB
+   select FRAME_VECTOR
default n
---help---
  V4L2 Display driver support for OMAP2/3 based boards.
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index ba7e21a73023..0cb22add650b 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -73,6 +73,7 @@ config VIDEOBUF2_CORE
 
 config VIDEOBUF2_MEMOPS
tristate
+   select FRAME_VECTOR
 
 config VIDEOBUF2_DMA_CONTIG
tristate
diff --git a/mm/Kconfig b/mm/Kconfig
index 390214da4546..2ca52e9986f0 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -635,3 +635,6 @@ config MAX_STACK_SIZE_MB
  changed to a smaller value in which case that is used.
 
  A sane initial value is 80 MB.
+
+config FRAME_VECTOR
+   bool
diff --git a/mm/Makefile b/mm/Makefile
index 98c4eaeabdcb..be5d5c866305 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -78,3 +78,4 @@ obj-$(CONFIG_CMA) += cma.o
 obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o
 obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o
 obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
+obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o
diff --git a/mm/frame_vector.c b/mm/frame_vector.c
new file mode 100644
index ..f76b579e46f1
--- /dev/null
+++ b/mm/frame_vector.c
@@ -0,0 +1,231 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/*
+ * get_vaddr_frames() - map virtual addresses to pfns
+ * @start: starting user address
+ * @nr_frames: number of pages / pfns from start to map
+ * @write: whether pages will be written to by the caller
+ * @force: whether to force write access even if user mapping is
+ * readonly. See description of the same argument of
+   get_user_pages().
+ * @vec:   structure which receives pages / pfns of the addresses mapped.
+ * It should have space for at least nr_frames entries.
+ *
+ * This function maps virtual addresses from @start and fills @vec structure
+ * with page frame numbers or page pointers to corresponding pages (choice
+ * depends on the type of the vma underlying the virtual address). If @start
+ * belongs to a normal vma, the function grabs reference to each of the pages
+ * to pin them in memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't
+ * touch page structures and the caller must make sure pfns aren't reused for
+ * anything else while he is using them.
+ *
+ * The function returns number of pages mapped which may be less than
+ * @nr_frames. In particular we stop mapping if there are more vmas of
+ * different type underlying the specified range of virtual addresses.
+ * When the function isn't able to map a single page, it returns error.
+ *
+ * This function takes care of grabbing mmap_sem as necessary.
+ */
+int get_vaddr_f

[PATCH 9/10] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()

2015-06-18 Thread Jan Kara
Convert g2d_userptr_get_dma_addr() to pin pages using get_vaddr_frames().
This removes the knowledge about vmas and mmap_sem locking from exynos
driver. Also it fixes a problem that the function has been mapping user
provided address without holding mmap_sem.

Signed-off-by: Jan Kara 
---
 drivers/gpu/drm/exynos/exynos_drm_g2d.c | 91 ++-
 drivers/gpu/drm/exynos/exynos_drm_gem.c | 97 -
 2 files changed, 29 insertions(+), 159 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c 
b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 81a250830808..810e1ee7c07d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -190,10 +190,8 @@ struct g2d_cmdlist_userptr {
dma_addr_t  dma_addr;
unsigned long   userptr;
unsigned long   size;
-   struct page **pages;
-   unsigned intnpages;
+   struct frame_vector *vec;
struct sg_table *sgt;
-   struct vm_area_struct   *vma;
atomic_trefcount;
boolin_pool;
boolout_of_list;
@@ -363,6 +361,7 @@ static void g2d_userptr_put_dma_addr(struct drm_device 
*drm_dev,
 {
struct g2d_cmdlist_userptr *g2d_userptr =
(struct g2d_cmdlist_userptr *)obj;
+   struct page **pages;
 
if (!obj)
return;
@@ -382,19 +381,21 @@ out:
exynos_gem_unmap_sgt_from_dma(drm_dev, g2d_userptr->sgt,
DMA_BIDIRECTIONAL);
 
-   exynos_gem_put_pages_to_userptr(g2d_userptr->pages,
-   g2d_userptr->npages,
-   g2d_userptr->vma);
+   pages = frame_vector_pages(g2d_userptr->vec);
+   if (!IS_ERR(pages)) {
+   int i;
 
-   exynos_gem_put_vma(g2d_userptr->vma);
+   for (i = 0; i < frame_vector_count(g2d_userptr->vec); i++)
+   set_page_dirty_lock(pages[i]);
+   }
+   put_vaddr_frames(g2d_userptr->vec);
+   frame_vector_destroy(g2d_userptr->vec);
 
if (!g2d_userptr->out_of_list)
list_del_init(&g2d_userptr->list);
 
sg_free_table(g2d_userptr->sgt);
kfree(g2d_userptr->sgt);
-
-   drm_free_large(g2d_userptr->pages);
kfree(g2d_userptr);
 }
 
@@ -408,9 +409,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
drm_device *drm_dev,
struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
struct g2d_cmdlist_userptr *g2d_userptr;
struct g2d_data *g2d;
-   struct page **pages;
struct sg_table *sgt;
-   struct vm_area_struct *vma;
unsigned long start, end;
unsigned int npages, offset;
int ret;
@@ -456,65 +455,38 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct 
drm_device *drm_dev,
return ERR_PTR(-ENOMEM);
 
atomic_set(&g2d_userptr->refcount, 1);
+   g2d_userptr->size = size;
 
start = userptr & PAGE_MASK;
offset = userptr & ~PAGE_MASK;
end = PAGE_ALIGN(userptr + size);
npages = (end - start) >> PAGE_SHIFT;
-   g2d_userptr->npages = npages;
-
-   pages = drm_calloc_large(npages, sizeof(struct page *));
-   if (!pages) {
-   DRM_ERROR("failed to allocate pages.\n");
-   ret = -ENOMEM;
+   g2d_userptr->vec = frame_vector_create(npages);
+   if (!vec)
goto err_free;
-   }
 
-   down_read(¤t->mm->mmap_sem);
-   vma = find_vma(current->mm, userptr);
-   if (!vma) {
-   up_read(¤t->mm->mmap_sem);
-   DRM_ERROR("failed to get vm region.\n");
+   ret = get_vaddr_frames(start, npages, true, true, g2d_userptr->vec);
+   if (ret != npages) {
+   DRM_ERROR("failed to get user pages from userptr.\n");
+   if (ret < 0)
+   goto err_destroy_framevec;
ret = -EFAULT;
-   goto err_free_pages;
+   goto err_put_framevec;
}
-
-   if (vma->vm_end < userptr + size) {
-   up_read(¤t->mm->mmap_sem);
-   DRM_ERROR("vma is too small.\n");
+   if (frame_vector_to_pages(g2d_userptr->vec) < 0) {
ret = -EFAULT;
-   goto err_free_pages;
+   goto err_put_framevec;
}
 
-   g2d_userptr->vma = exynos_gem_get_vma(vma);
-   if (!g2d_userptr->vma) {
-   up_read(¤t->mm->mmap_sem);
-   DRM_ERROR("failed to copy vma.\n");
-   ret = -ENOMEM;
-   goto err_free_pages;
-   }
-
-   g2d_userptr->size = size;
-

[PATCH 6/10] media: vb2: Convert vb2_vmalloc_get_userptr() to use frame vector

2015-06-18 Thread Jan Kara
Convert vb2_vmalloc_get_userptr() to use frame vector infrastructure.
When we are doing that there's no need to allocate page array and some
code can be simplified.

Acked-by: Marek Szyprowski 
Tested-by: Marek Szyprowski 
Signed-off-by: Jan Kara 
---
 drivers/media/v4l2-core/videobuf2-vmalloc.c | 92 +++--
 1 file changed, 36 insertions(+), 56 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c 
b/drivers/media/v4l2-core/videobuf2-vmalloc.c
index 3199c379cd47..d2ce81fa2cdf 100644
--- a/drivers/media/v4l2-core/videobuf2-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c
@@ -23,11 +23,9 @@
 
 struct vb2_vmalloc_buf {
void*vaddr;
-   struct page **pages;
-   struct vm_area_struct   *vma;
+   struct frame_vector *vec;
enum dma_data_direction dma_dir;
unsigned long   size;
-   unsigned intn_pages;
atomic_trefcount;
struct vb2_vmarea_handler   handler;
struct dma_buf  *dbuf;
@@ -76,10 +74,8 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
 enum dma_data_direction dma_dir)
 {
struct vb2_vmalloc_buf *buf;
-   unsigned long first, last;
-   int n_pages, offset;
-   struct vm_area_struct *vma;
-   dma_addr_t physp;
+   struct frame_vector *vec;
+   int n_pages, offset, i;
 
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
@@ -88,53 +84,36 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, 
unsigned long vaddr,
buf->dma_dir = dma_dir;
offset = vaddr & ~PAGE_MASK;
buf->size = size;
-
-   down_read(¤t->mm->mmap_sem);
-   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 = (__force void *)ioremap_nocache(physp, size);
-   if (!buf->vaddr)
-   goto fail_pages_array_alloc;
+   vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE);
+   if (IS_ERR(vec))
+   goto fail_pfnvec_create;
+   buf->vec = vec;
+   n_pages = frame_vector_count(vec);
+   if (frame_vector_to_pages(vec) < 0) {
+   unsigned long *nums = frame_vector_pfns(vec);
+
+   /*
+* We cannot get page pointers for these pfns. Check memory is
+* physically contiguous and use direct mapping.
+*/
+   for (i = 1; i < n_pages; i++)
+   if (nums[i-1] + 1 != nums[i])
+   goto fail_map;
+   buf->vaddr = (__force void *)
+   ioremap_nocache(nums[0] << PAGE_SHIFT, size);
} 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,
-dma_dir == DMA_FROM_DEVICE,
-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,
+   buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1,
PAGE_KERNEL);
-   if (!buf->vaddr)
-   goto fail_get_user_pages;
}
-   up_read(¤t->mm->mmap_sem);
 
+   if (!buf->vaddr)
+   goto fail_map;
buf->vaddr += offset;
return buf;
 
-fail_get_user_pages:
-   pr_debug("get_user_pages requested/got: %d/%d]\n", n_pages,
-buf->n_pages);
-   while (--n_pages >= 0)
-   put_page(buf->pages[n_pages]);
-   kfree(buf->pages);
-
-fail_pages_array_alloc:
-   up_read(¤t->mm->mmap_sem);
+fail_map:
+   vb2_destroy_framevec(vec);
+fail_pfnvec_create:
kfree(buf);
 
return NULL;
@@ -145,20 +124,21 @@ static void vb2_vmalloc_pu

[PATCH 7/10] media: vb2: Convert vb2_dc_get_userptr() to use frame vector

2015-06-18 Thread Jan Kara
Convert vb2_dc_get_userptr() to use frame vector infrastructure. When we
are doing that there's no need to allocate page array and some code can
be simplified.

Acked-by: Marek Szyprowski 
Tested-by: Marek Szyprowski 
Signed-off-by: Jan Kara 
---
 drivers/media/v4l2-core/videobuf2-dma-contig.c | 212 -
 1 file changed, 34 insertions(+), 178 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c 
b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 8e660f033d3c..e6cea452302b 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -32,15 +32,13 @@ struct vb2_dc_buf {
dma_addr_t  dma_addr;
enum dma_data_direction dma_dir;
struct sg_table *dma_sgt;
+   struct frame_vector *vec;
 
/* MMAP related */
struct vb2_vmarea_handler   handler;
atomic_trefcount;
struct sg_table *sgt_base;
 
-   /* USERPTR related */
-   struct vm_area_struct   *vma;
-
/* DMABUF related */
struct dma_buf_attachment   *db_attach;
 };
@@ -49,24 +47,6 @@ struct vb2_dc_buf {
 /*scatterlist table functions*/
 /*/
 
-
-static void vb2_dc_sgt_foreach_page(struct sg_table *sgt,
-   void (*cb)(struct page *pg))
-{
-   struct scatterlist *s;
-   unsigned int i;
-
-   for_each_sg(sgt->sgl, s, sgt->orig_nents, i) {
-   struct page *page = sg_page(s);
-   unsigned int n_pages = PAGE_ALIGN(s->offset + s->length)
-   >> PAGE_SHIFT;
-   unsigned int j;
-
-   for (j = 0; j < n_pages; ++j, ++page)
-   cb(page);
-   }
-}
-
 static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt)
 {
struct scatterlist *s;
@@ -429,92 +409,12 @@ static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, 
unsigned long flags)
 /*   callbacks for USERPTR buffers   */
 /*/
 
-static inline int vma_is_io(struct vm_area_struct *vma)
-{
-   return !!(vma->vm_flags & (VM_IO | VM_PFNMAP));
-}
-
-static int vb2_dc_get_user_pfn(unsigned long start, int n_pages,
-   struct vm_area_struct *vma, unsigned long *res)
-{
-   unsigned long pfn, start_pfn, prev_pfn;
-   unsigned int i;
-   int ret;
-
-   if (!vma_is_io(vma))
-   return -EFAULT;
-
-   ret = follow_pfn(vma, start, &pfn);
-   if (ret)
-   return ret;
-
-   start_pfn = pfn;
-   start += PAGE_SIZE;
-
-   for (i = 1; i < n_pages; ++i, start += PAGE_SIZE) {
-   prev_pfn = pfn;
-   ret = follow_pfn(vma, start, &pfn);
-
-   if (ret) {
-   pr_err("no page for address %lu\n", start);
-   return ret;
-   }
-   if (pfn != prev_pfn + 1)
-   return -EINVAL;
-   }
-
-   *res = start_pfn;
-   return 0;
-}
-
-static int vb2_dc_get_user_pages(unsigned long start, struct page **pages,
-   int n_pages, struct vm_area_struct *vma,
-   enum dma_data_direction dma_dir)
-{
-   if (vma_is_io(vma)) {
-   unsigned int i;
-
-   for (i = 0; i < n_pages; ++i, start += PAGE_SIZE) {
-   unsigned long pfn;
-   int ret = follow_pfn(vma, start, &pfn);
-
-   if (!pfn_valid(pfn))
-   return -EINVAL;
-
-   if (ret) {
-   pr_err("no page for address %lu\n", start);
-   return ret;
-   }
-   pages[i] = pfn_to_page(pfn);
-   }
-   } else {
-   int n;
-
-   n = get_user_pages(current, current->mm, start & PAGE_MASK,
-   n_pages, dma_dir == DMA_FROM_DEVICE, 1, pages, NULL);
-   /* negative error means that no page was pinned */
-   n = max(n, 0);
-   if (n != n_pages) {
-   pr_err("got only %d of %d user pages\n", n, n_pages);
-   while (n)
-   put_page(pages[--n]);
-   return -EFAULT;
-   }
-   }
-
-   return 0;
-}
-
-static void vb2_dc_put_dirty_page(struct page *page)
-{
-   set_page_dirty_lock(page);
-   put_page(page);
-}
-
 static void vb2_dc_put_userptr(void *buf_priv)
 {
struct vb2_dc_buf *buf = buf_priv;
struct sg_table *sgt = buf->dma_sgt;
+   int i;
+   struct page **pages;
 
if (sgt) {
DEFINE_DMA_ATTRS(attrs);
@@ -526,13 +426,15 @@ static void vb2_dc_

[PATCH 0/10 v6] Helper to abstract vma handling in media layer

2015-06-18 Thread Jan Kara
  Hello,

I'm sending the sixth version of my patch series to abstract vma handling from
the various media drivers. Since the previous version I have added a patch to
move mm helpers into a separate file and behind a config option. I also
changed patch pushing mmap_sem down in videobuf2 core to avoid lockdep warning
and NULL dereference Hans found in his testing. I've also included small
fixups Andrew was carrying.

After this patch set drivers have to know much less details about vmas, their
types, and locking. Also quite some code is removed from them. As a bonus
drivers get automatically VM_FAULT_RETRY handling. The primary motivation for
this series is to remove knowledge about mmap_sem locking from as many places a
possible so that we can change it with reasonable effort.

The core of the series is the new helper get_vaddr_frames() which is given a
virtual address and it fills in PFNs / struct page pointers (depending on VMA
type) into the provided array. If PFNs correspond to normal pages it also grabs
references to these pages. The difference from get_user_pages() is that this
function can also deal with pfnmap, and io mappings which is what the media
drivers need.

I have tested the patches with vivid driver so at least vb2 code got some
exposure. Conversion of other drivers was just compile-tested (for x86 so e.g.
exynos driver which is only for Samsung platform is completely untested).

Andrew, can you please update the patches in mm three? Thanks!

Honza

Changes since v5:
* Moved mm helper into a separate file and behind a config option
* Changed the first patch pushing mmap_sem down in videobuf2 core to avoid
  possible deadlock

Changes since v4:
* Minor cleanups and fixes pointed out by Mel and Vlasta
* Added Acked-by tags

Changes since v3:
* Added include  into mm/gup.c as it's needed for some archs
* Fixed error path for exynos driver

Changes since v2:
* Renamed functions and structures as Mel suggested
* Other minor changes suggested by Mel
* Rebased on top of 4.1-rc2
* Changed functions to get pointer to array of pages / pfns to perform
  conversion if necessary. This fixes possible issue in the omap I may have
  introduced in v2 and generally makes the API less errorprone.
--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/10] mm: Provide new get_vaddr_frames() helper

2015-06-18 Thread Jan Kara
Provide new function get_vaddr_frames().  This function maps virtual
addresses from given start and fills given array with page frame numbers of
the corresponding pages. If given start belongs to a normal vma, the function
grabs reference to each of the pages to pin them in memory. If start
belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
must make sure pfns aren't reused for anything else while he is using
them.

This function is created for various drivers to simplify handling of
their buffers.

Acked-by: Mel Gorman 
Acked-by: Vlastimil Babka 
Signed-off-by: Jan Kara 
---
 include/linux/mm.h |  44 +++
 mm/gup.c   | 223 +
 2 files changed, 267 insertions(+)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 0755b9fd03a7..dcd1f02a78e9 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -20,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct mempolicy;
 struct anon_vma;
@@ -1197,6 +1198,49 @@ long get_user_pages_unlocked(struct task_struct *tsk, 
struct mm_struct *mm,
int write, int force, struct page **pages);
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
struct page **pages);
+
+/* Container for pinned pfns / pages */
+struct frame_vector {
+   unsigned int nr_allocated;  /* Number of frames we have space for */
+   unsigned int nr_frames; /* Number of frames stored in ptrs array */
+   bool got_ref;   /* Did we pin pages by getting page ref? */
+   bool is_pfns;   /* Does array contain pages or pfns? */
+   void *ptrs[0];  /* Array of pinned pfns / pages. Use
+* pfns_vector_pages() or pfns_vector_pfns()
+* for access */
+};
+
+struct frame_vector *frame_vector_create(unsigned int nr_frames);
+void frame_vector_destroy(struct frame_vector *vec);
+int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
+bool write, bool force, struct frame_vector *vec);
+void put_vaddr_frames(struct frame_vector *vec);
+int frame_vector_to_pages(struct frame_vector *vec);
+void frame_vector_to_pfns(struct frame_vector *vec);
+
+static inline unsigned int frame_vector_count(struct frame_vector *vec)
+{
+   return vec->nr_frames;
+}
+
+static inline struct page **frame_vector_pages(struct frame_vector *vec)
+{
+   if (vec->is_pfns) {
+   int err = frame_vector_to_pages(vec);
+
+   if (err)
+   return ERR_PTR(err);
+   }
+   return (struct page **)(vec->ptrs);
+}
+
+static inline unsigned long *frame_vector_pfns(struct frame_vector *vec)
+{
+   if (!vec->is_pfns)
+   frame_vector_to_pfns(vec);
+   return (unsigned long *)(vec->ptrs);
+}
+
 struct kvec;
 int get_kernel_pages(const struct kvec *iov, int nr_pages, int write,
struct page **pages);
diff --git a/mm/gup.c b/mm/gup.c
index 6297f6bccfb1..a7a4ac6ae9d0 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -8,6 +8,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -936,6 +937,228 @@ int __mm_populate(unsigned long start, unsigned long len, 
int ignore_errors)
return ret; /* 0 or negative error code */
 }
 
+/*
+ * get_vaddr_frames() - map virtual addresses to pfns
+ * @start: starting user address
+ * @nr_frames: number of pages / pfns from start to map
+ * @write: whether pages will be written to by the caller
+ * @force: whether to force write access even if user mapping is
+ * readonly. See description of the same argument of
+   get_user_pages().
+ * @vec:   structure which receives pages / pfns of the addresses mapped.
+ * It should have space for at least nr_frames entries.
+ *
+ * This function maps virtual addresses from @start and fills @vec structure
+ * with page frame numbers or page pointers to corresponding pages (choice
+ * depends on the type of the vma underlying the virtual address). If @start
+ * belongs to a normal vma, the function grabs reference to each of the pages
+ * to pin them in memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't
+ * touch page structures and the caller must make sure pfns aren't reused for
+ * anything else while he is using them.
+ *
+ * The function returns number of pages mapped which may be less than
+ * @nr_frames. In particular we stop mapping if there are more vmas of
+ * different type underlying the specified range of virtual addresses.
+ * When the function isn't able to map a single page, it returns error.
+ *
+ * This function takes care of grabbing mmap_sem as necessary.
+ */
+int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
+bool write, bool force, struct frame_vector *vec)
+{
+   struct mm_struct *mm = current

[PATCH 4/10] vb2: Provide helpers for mapping virtual addresses

2015-06-18 Thread Jan Kara
Provide simple helper functions to map virtual address range into an
array of pfns / pages.

Acked-by: Marek Szyprowski 
Tested-by: Marek Szyprowski 
Signed-off-by: Jan Kara 
---
 drivers/media/v4l2-core/videobuf2-memops.c | 58 ++
 include/media/videobuf2-memops.h   |  5 +++
 2 files changed, 63 insertions(+)

diff --git a/drivers/media/v4l2-core/videobuf2-memops.c 
b/drivers/media/v4l2-core/videobuf2-memops.c
index 81c1ad8b2cf1..0ec186d41b9b 100644
--- a/drivers/media/v4l2-core/videobuf2-memops.c
+++ b/drivers/media/v4l2-core/videobuf2-memops.c
@@ -137,6 +137,64 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned 
long size,
 EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
 
 /**
+ * vb2_create_framevec() - map virtual addresses to pfns
+ * @start: Virtual user address where we start mapping
+ * @length:Length of a range to map
+ * @write: Should we map for writing into the area
+ *
+ * This function allocates and fills in a vector with pfns corresponding to
+ * virtual address range passed in arguments. If pfns have corresponding pages,
+ * page references are also grabbed to pin pages in memory. The function
+ * returns pointer to the vector on success and error pointer in case of
+ * failure. Returned vector needs to be freed via vb2_destroy_pfnvec().
+ */
+struct frame_vector *vb2_create_framevec(unsigned long start,
+unsigned long length,
+bool write)
+{
+   int ret;
+   unsigned long first, last;
+   unsigned long nr;
+   struct frame_vector *vec;
+
+   first = start >> PAGE_SHIFT;
+   last = (start + length - 1) >> PAGE_SHIFT;
+   nr = last - first + 1;
+   vec = frame_vector_create(nr);
+   if (!vec)
+   return ERR_PTR(-ENOMEM);
+   ret = get_vaddr_frames(start, nr, write, 1, vec);
+   if (ret < 0)
+   goto out_destroy;
+   /* We accept only complete set of PFNs */
+   if (ret != nr) {
+   ret = -EFAULT;
+   goto out_release;
+   }
+   return vec;
+out_release:
+   put_vaddr_frames(vec);
+out_destroy:
+   frame_vector_destroy(vec);
+   return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(vb2_create_framevec);
+
+/**
+ * vb2_destroy_framevec() - release vector of mapped pfns
+ * @vec:   vector of pfns / pages to release
+ *
+ * This releases references to all pages in the vector @vec (if corresponding
+ * pfns are backed by pages) and frees the passed vector.
+ */
+void vb2_destroy_framevec(struct frame_vector *vec)
+{
+   put_vaddr_frames(vec);
+   frame_vector_destroy(vec);
+}
+EXPORT_SYMBOL(vb2_destroy_framevec);
+
+/**
  * vb2_common_vm_open() - increase refcount of the vma
  * @vma:   virtual memory region for the mapping
  *
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
index f05444ca8c0c..2f0564ff5f31 100644
--- a/include/media/videobuf2-memops.h
+++ b/include/media/videobuf2-memops.h
@@ -15,6 +15,7 @@
 #define _MEDIA_VIDEOBUF2_MEMOPS_H
 
 #include 
+#include 
 
 /**
  * vb2_vmarea_handler - common vma refcount tracking handler
@@ -36,5 +37,9 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long 
size,
 struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
 void vb2_put_vma(struct vm_area_struct *vma);
 
+struct frame_vector *vb2_create_framevec(unsigned long start,
+unsigned long length,
+bool write);
+void vb2_destroy_framevec(struct frame_vector *vec);
 
 #endif
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 9/9] [media] mm: Move get_vaddr_frames() behind a config option

2015-06-18 Thread Jan Kara
On Wed 10-06-15 09:37:20, Josh Triplett wrote:
> On Wed, Jun 10, 2015 at 06:20:52AM -0300, Mauro Carvalho Chehab wrote:
> > From: Jan Kara 
> > 
> > get_vaddr_frames() is used by relatively rare drivers so hide it and the
> > related functions behind a config option that is selected only by
> > drivers that need the infrastructure.
> > 
> > Suggested-by: Andrew Morton 
> > 
> > Signed-off-by: Jan Kara 
> > Signed-off-by: Hans Verkuil 
> > Signed-off-by: Mauro Carvalho Chehab 
> 
> Seems sensible to me.
> 
> Since this patch makes the kernel smaller, can you include the delta
> from bloat-o-meter between allnoconfig with and without this patch?

The results are:

add/remove: 0/6 grow/shrink: 0/0 up/down: 0/-868 (-868)
function old new   delta
frame_vector_destroy  55   - -55
frame_vector_to_pfns  56   - -56
frame_vector_create   81   - -81
put_vaddr_frames  93   - -93
frame_vector_to_pages 98   - -98
get_vaddr_frames 485   --485

I've added it to the changelog of the patch.

> Also, I assume you've compile-tested the kernel with allyesconfig minus
> the three options that now have "select FRAME_VECTOR", to make sure it
> builds?
  I did not because the config option VIDEOBUF2_MEMOPS is a virtual one
selected transitively by quite a few video drivers and I didn't bother with
tracking down all of them... But since that config option guards
compilation of the code I modified I'm pretty confident I got it right.

Honza

> >  create mode 100644 mm/frame_vector.c
> > 
> > diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
> > index 0a6780367d28..fc678289cf79 100644
> > --- a/drivers/gpu/drm/exynos/Kconfig
> > +++ b/drivers/gpu/drm/exynos/Kconfig
> > @@ -71,6 +71,7 @@ config DRM_EXYNOS_VIDI
> >  config DRM_EXYNOS_G2D
> > bool "Exynos DRM G2D"
> > depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_G2D
> > +   select FRAME_VECTOR
> > help
> >   Choose this option if you want to use Exynos G2D for DRM.
> >  
> > diff --git a/drivers/media/platform/omap/Kconfig 
> > b/drivers/media/platform/omap/Kconfig
> > index dc2aaab54aef..217d613b0fe7 100644
> > --- a/drivers/media/platform/omap/Kconfig
> > +++ b/drivers/media/platform/omap/Kconfig
> > @@ -10,6 +10,7 @@ config VIDEO_OMAP2_VOUT
> > select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS
> > select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
> > select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB
> > +   select FRAME_VECTOR
> > default n
> > ---help---
> >   V4L2 Display driver support for OMAP2/3 based boards.
> > diff --git a/drivers/media/v4l2-core/Kconfig 
> > b/drivers/media/v4l2-core/Kconfig
> > index f7a01a72eb9e..f38f6e387f04 100644
> > --- a/drivers/media/v4l2-core/Kconfig
> > +++ b/drivers/media/v4l2-core/Kconfig
> > @@ -73,6 +73,7 @@ config VIDEOBUF2_CORE
> >  
> >  config VIDEOBUF2_MEMOPS
> > tristate
> > +   select FRAME_VECTOR
> >  
> >  config VIDEOBUF2_DMA_CONTIG
> > tristate
> > diff --git a/mm/Kconfig b/mm/Kconfig
> > index 390214da4546..2ca52e9986f0 100644
> > --- a/mm/Kconfig
> > +++ b/mm/Kconfig
> > @@ -635,3 +635,6 @@ config MAX_STACK_SIZE_MB
> >   changed to a smaller value in which case that is used.
> >  
> >   A sane initial value is 80 MB.
> > +
> > +config FRAME_VECTOR
> > +   bool
> > diff --git a/mm/Makefile b/mm/Makefile
> > index 98c4eaeabdcb..be5d5c866305 100644
> > --- a/mm/Makefile
> > +++ b/mm/Makefile
> > @@ -78,3 +78,4 @@ obj-$(CONFIG_CMA) += cma.o
> >  obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o
> >  obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o
> >  obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
> > +obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o
> > diff --git a/mm/frame_vector.c b/mm/frame_vector.c
> > new file mode 100644
> > index ..31a2bd5f41d5
> > --- /dev/null
> > +++ b/mm/frame_vector.c
> > @@ -0,0 +1,232 @@
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +/*
> > + * get_vaddr_frames() - map virtual addresses to pfns
> > + * @start: starting user address
&

Re: [PATCH 2/9] mm: Provide new get_vaddr_frames() helper

2015-06-03 Thread Jan Kara
On Tue 02-06-15 15:29:12, Andrew Morton wrote:
> On Tue, 2 Jun 2015 17:23:00 +0200 Jan Kara  wrote:
> 
> > > That's a lump of new code which many kernels won't be needing.  Can we
> > > put all this in a new .c file and select it within drivers/media
> > > Kconfig?
> >   So the attached patch should do what you had in mind. OK?
> 
> lgtm.
> 
> >  drivers/gpu/drm/exynos/Kconfig  |   1 +
> >  drivers/media/platform/omap/Kconfig |   1 +
> >  drivers/media/v4l2-core/Kconfig |   1 +
> >  mm/Kconfig  |   3 +
> >  mm/Makefile |   1 +
> >  mm/frame-vec.c  | 233 
> > 
> 
> But frame_vector.c would be a more pleasing name.  For `struct frame_vector'.
  OK, makes sense. Updated patch attached.

Honza
-- 
Jan Kara 
SUSE Labs, CR
>From a129ecf637e75421d823d54eab885cd36e54c6ec Mon Sep 17 00:00:00 2001
From: Jan Kara 
Date: Tue, 2 Jun 2015 16:40:32 +0200
Subject: [PATCH] mm: Move get_vaddr_frames() behind a config option

get_vaddr_frames() is used by relatively rare drivers so hide it and the
related functions behind a config option that is selected only by
drivers that need the infrastructure.

Suggested-by: Andrew Morton 
Signed-off-by: Jan Kara 
---
 drivers/gpu/drm/exynos/Kconfig  |   1 +
 drivers/media/platform/omap/Kconfig |   1 +
 drivers/media/v4l2-core/Kconfig |   1 +
 mm/Kconfig  |   3 +
 mm/Makefile |   1 +
 mm/frame_vector.c   | 233 
 mm/gup.c| 225 --
 7 files changed, 240 insertions(+), 225 deletions(-)
 create mode 100644 mm/frame_vector.c

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 0a6780367d28..fc678289cf79 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -71,6 +71,7 @@ config DRM_EXYNOS_VIDI
 config DRM_EXYNOS_G2D
 	bool "Exynos DRM G2D"
 	depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_G2D
+	select FRAME_VECTOR
 	help
 	  Choose this option if you want to use Exynos G2D for DRM.
 
diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig
index dc2aaab54aef..217d613b0fe7 100644
--- a/drivers/media/platform/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
@@ -10,6 +10,7 @@ config VIDEO_OMAP2_VOUT
 	select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS
 	select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
 	select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB
+	select FRAME_VECTOR
 	default n
 	---help---
 	  V4L2 Display driver support for OMAP2/3 based boards.
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index ba7e21a73023..0cb22add650b 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -73,6 +73,7 @@ config VIDEOBUF2_CORE
 
 config VIDEOBUF2_MEMOPS
 	tristate
+	select FRAME_VECTOR
 
 config VIDEOBUF2_DMA_CONTIG
 	tristate
diff --git a/mm/Kconfig b/mm/Kconfig
index 390214da4546..2ca52e9986f0 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -635,3 +635,6 @@ config MAX_STACK_SIZE_MB
 	  changed to a smaller value in which case that is used.
 
 	  A sane initial value is 80 MB.
+
+config FRAME_VECTOR
+	bool
diff --git a/mm/Makefile b/mm/Makefile
index 98c4eaeabdcb..be5d5c866305 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -78,3 +78,4 @@ obj-$(CONFIG_CMA)	+= cma.o
 obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o
 obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o
 obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
+obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o
diff --git a/mm/frame_vector.c b/mm/frame_vector.c
new file mode 100644
index ..5d85bcd150ae
--- /dev/null
+++ b/mm/frame_vector.c
@@ -0,0 +1,233 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/*
+ * get_vaddr_frames() - map virtual addresses to pfns
+ * @start:	starting user address
+ * @nr_frames:	number of pages / pfns from start to map
+ * @write:	whether pages will be written to by the caller
+ * @force:	whether to force write access even if user mapping is
+ *		readonly. See description of the same argument of
+		get_user_pages().
+ * @vec:	structure which receives pages / pfns of the addresses mapped.
+ *		It should have space for at least nr_frames entries.
+ *
+ * This function maps virtual addresses from @start and fills @vec structure
+ * with page frame numbers or page pointers to corresponding pages (choice
+ * depends on the type of the vma underlying the virtual address). If @start
+ * belongs to a normal vma, the function grabs reference to each of the pages
+ * to pin them in memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't
+ * to

Re: [PATCH 2/9] mm: Provide new get_vaddr_frames() helper

2015-06-02 Thread Jan Kara
On Thu 28-05-15 16:24:02, Andrew Morton wrote:
> On Wed, 13 May 2015 15:08:08 +0200 Jan Kara  wrote:
> 
> > Provide new function get_vaddr_frames().  This function maps virtual
> > addresses from given start and fills given array with page frame numbers of
> > the corresponding pages. If given start belongs to a normal vma, the 
> > function
> > grabs reference to each of the pages to pin them in memory. If start
> > belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
> > must make sure pfns aren't reused for anything else while he is using
> > them.
> > 
> > This function is created for various drivers to simplify handling of
> > their buffers.
> > 
> > Acked-by: Mel Gorman 
> > Acked-by: Vlastimil Babka 
> > Signed-off-by: Jan Kara 
> > ---
> >  include/linux/mm.h |  44 +++
> >  mm/gup.c   | 226 
> > +
> 
> That's a lump of new code which many kernels won't be needing.  Can we
> put all this in a new .c file and select it within drivers/media
> Kconfig?
  So the attached patch should do what you had in mind. OK?

    Honza
-- 
Jan Kara 
SUSE Labs, CR
>From d18fc7863fc62d8ad0c1747b789a0dcf032ccf42 Mon Sep 17 00:00:00 2001
From: Jan Kara 
Date: Tue, 2 Jun 2015 16:40:32 +0200
Subject: [PATCH] mm: Move get_vaddr_frames() behind a config option

get_vaddr_frames() is used by relatively rare drivers so hide it and the
related functions behind a config option that is selected only by
drivers that need the infrastructure.

Suggested-by: Andrew Morton 
Signed-off-by: Jan Kara 
---
 drivers/gpu/drm/exynos/Kconfig  |   1 +
 drivers/media/platform/omap/Kconfig |   1 +
 drivers/media/v4l2-core/Kconfig |   1 +
 mm/Kconfig  |   3 +
 mm/Makefile |   1 +
 mm/frame-vec.c  | 233 
 mm/gup.c| 225 --
 7 files changed, 240 insertions(+), 225 deletions(-)
 create mode 100644 mm/frame-vec.c

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 0a6780367d28..b2fac87137c7 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -71,6 +71,7 @@ config DRM_EXYNOS_VIDI
 config DRM_EXYNOS_G2D
 	bool "Exynos DRM G2D"
 	depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_G2D
+	select FRAME_VEC
 	help
 	  Choose this option if you want to use Exynos G2D for DRM.
 
diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig
index dc2aaab54aef..7cceca7b184d 100644
--- a/drivers/media/platform/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
@@ -10,6 +10,7 @@ config VIDEO_OMAP2_VOUT
 	select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS
 	select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
 	select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB
+	select FRAME_VEC
 	default n
 	---help---
 	  V4L2 Display driver support for OMAP2/3 based boards.
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index ba7e21a73023..957e5a18b0ff 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -73,6 +73,7 @@ config VIDEOBUF2_CORE
 
 config VIDEOBUF2_MEMOPS
 	tristate
+	select FRAME_VEC
 
 config VIDEOBUF2_DMA_CONTIG
 	tristate
diff --git a/mm/Kconfig b/mm/Kconfig
index 390214da4546..d039615e8f82 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -635,3 +635,6 @@ config MAX_STACK_SIZE_MB
 	  changed to a smaller value in which case that is used.
 
 	  A sane initial value is 80 MB.
+
+config FRAME_VEC
+	bool
diff --git a/mm/Makefile b/mm/Makefile
index 98c4eaeabdcb..d38305462e17 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -78,3 +78,4 @@ obj-$(CONFIG_CMA)	+= cma.o
 obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o
 obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o
 obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
+obj-$(CONFIG_FRAME_VEC)	+= frame-vec.o
diff --git a/mm/frame-vec.c b/mm/frame-vec.c
new file mode 100644
index ..5d85bcd150ae
--- /dev/null
+++ b/mm/frame-vec.c
@@ -0,0 +1,233 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/*
+ * get_vaddr_frames() - map virtual addresses to pfns
+ * @start:	starting user address
+ * @nr_frames:	number of pages / pfns from start to map
+ * @write:	whether pages will be written to by the caller
+ * @force:	whether to force write access even if user mapping is
+ *		readonly. See description of the same argument of
+		get_user_pages().
+ * @vec:	structure which receives pages / pfns of the addresses mapped.
+ *		It should have space for at least nr_frames entries.
+ *
+ * This function maps virtual addresses from @start and fills @vec structu

Re: [PATCH 2/9] mm: Provide new get_vaddr_frames() helper

2015-06-01 Thread Jan Kara
On Thu 28-05-15 16:24:02, Andrew Morton wrote:
> On Wed, 13 May 2015 15:08:08 +0200 Jan Kara  wrote:
> 
> > Provide new function get_vaddr_frames().  This function maps virtual
> > addresses from given start and fills given array with page frame numbers of
> > the corresponding pages. If given start belongs to a normal vma, the 
> > function
> > grabs reference to each of the pages to pin them in memory. If start
> > belongs to VM_IO | VM_PFNMAP vma, we don't touch page structures. Caller
> > must make sure pfns aren't reused for anything else while he is using
> > them.
> > 
> > This function is created for various drivers to simplify handling of
> > their buffers.
> > 
> > Acked-by: Mel Gorman 
> > Acked-by: Vlastimil Babka 
> > Signed-off-by: Jan Kara 
> > ---
> >  include/linux/mm.h |  44 +++
> >  mm/gup.c   | 226 
> > +
> 
> That's a lump of new code which many kernels won't be needing.  Can we
> put all this in a new .c file and select it within drivers/media
> Kconfig?
  Yeah, makes sense. I'll write a patch. Hans, is it OK with you if I
just create a patch on top of the series you have in your tree?

Honza
-- 
Jan Kara 
SUSE Labs, CR
--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 0/9 v5] Helper to abstract vma handling in media layer

2015-05-25 Thread Jan Kara
On Mon 25-05-15 13:37:56, Hans Verkuil wrote:
> Hi Jan,
> 
> On 05/13/2015 03:08 PM, Jan Kara wrote:
> >   Hello,
> > 
> > I'm sending the fifth version of my patch series to abstract vma handling
> > from the various media drivers. The patches got some review from mm people 
> > and
> > testing from device driver guys so unless someone objects, patches will be
> > queued in media tree for the next merge window.
> 
> What is the current status? I saw one comment for patch 9, so I assume it is 
> not
> quite ready yet.
> 
> Let me know when you think it is time to merge.
  There was a minor comment to the exynos patch - I've sent updated version
of that patch as a reply to the comment. Do you want me to resend the whole
series? Otherwise I think you can just pick up the patches and merge them.
Thanks!

Honza

> > After this patch set drivers have to know much less details about vmas, 
> > their
> > types, and locking. Also quite some code is removed from them. As a bonus
> > drivers get automatically VM_FAULT_RETRY handling. The primary motivation 
> > for
> > this series is to remove knowledge about mmap_sem locking from as many 
> > places a
> > possible so that we can change it with reasonable effort.
> > 
> > The core of the series is the new helper get_vaddr_frames() which is given a
> > virtual address and it fills in PFNs / struct page pointers (depending on 
> > VMA
> > type) into the provided array. If PFNs correspond to normal pages it also 
> > grabs
> > references to these pages. The difference from get_user_pages() is that this
> > function can also deal with pfnmap, and io mappings which is what the media
> > drivers need.
> > 
> > I have tested the patches with vivid driver so at least vb2 code got some
> > exposure. Conversion of other drivers was just compile-tested (for x86 so 
> > e.g.
> > exynos driver which is only for Samsung platform is completely untested).
> > 
> > Honza
> > Changes since v4:
> > * Minor cleanups and fixes pointed out by Mel and Vlasta
> > * Added Acked-by tags
> > 
> > Changes since v3:
> > * Added include  into mm/gup.c as it's needed for some 
> > archs
> > * Fixed error path for exynos driver
> > 
> > Changes since v2:
> > * Renamed functions and structures as Mel suggested
> > * Other minor changes suggested by Mel
> > * Rebased on top of 4.1-rc2
> > * Changed functions to get pointer to array of pages / pfns to perform
> >   conversion if necessary. This fixes possible issue in the omap I may have
> >   introduced in v2 and generally makes the API less errorprone.
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-media" in
> > the body of a message to majord...@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > 
> 
-- 
Jan Kara 
SUSE Labs, CR
--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html