Helper to abstract vma handling in media layer
Subsystems (7)
v7 cover Helper to abstract vma handling in media layer
From: Jan Kara <[email protected]>
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 <linux/vmalloc.h> 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.
PATCH v7 1/9 vb2: Push mmap_sem down to memops
From: Jan Kara <[email protected]>
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.
--- 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(-)
drivers/media/v4l2-core/videobuf2-core.c +0 -2
@@ -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);
drivers/media/v4l2-core/videobuf2-dma-contig.c +5 -0
@@ -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:
drivers/media/v4l2-core/videobuf2-dma-sg.c +4 -0
@@ -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->vma); userptr_fail_find_vma: +up_read (¤t->mm->mmap_sem);kfree (buf->pages); userptr_fail_alloc_pages:kfree (buf);
drivers/media/v4l2-core/videobuf2-vmalloc.c +3 -1
@@ -89,7 +89,7 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr, 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))
@@ -121,6 +121,7 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr,if (!buf->vaddr) goto fail_get_user_pages; } +up_read (¤t->mm->mmap_sem); buf->vaddr += offset;return buf;
@@ -133,6 +134,7 @@ fail_get_user_pages:kfree (buf->pages); fail_pages_array_alloc: +up_read (¤t->mm->mmap_sem);kfree (buf);return NULL ;
Signature · 7 lines
2.1.4 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v7 2/9 mm: Provide new get_vaddr_frames() helper
In reply to Jan KaraFrom: Jan Kara <[email protected]>
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.
--- 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
include/linux/mm.h +44 -0
@@ -20,6 +20,7 @@#include <linux/shrinker.h> #include <linux/resource.h> #include <linux/page_ext.h> +#include <linux/err.h> 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);
mm/Kconfig +3 -0
@@ -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
mm/Makefile +1 -0
@@ -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
mm/frame_vector.c new file +231 -0
231 lines not on this page · raw message
Signature · 1 line
2.1.4
Re: [PATCH 2/9] mm: Provide new get_vaddr_frames() helper
Quoted 10 lines · Jan Kara
From: Jan Kara <[email protected]>
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 toVM_IO|VM_PFNMAPvma, we don't touch page structures. Caller must make sure pfns aren't reused for anything else while he is using them.
Quoted 6 lines
This function is created for various drivers to simplify handling of their buffers.
Acked-by Mel Gorman <[email protected]>Acked-by Vlastimil Babka <[email protected]>Signed-off-by Jan Kara <[email protected]>
I'd like to see an Acked-by from Andrew or mm-maintainers before I merge this.
Anyone?
Regards,
Hans
Quoted 328 lines
--- 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.cinclude/linux/mm.h +44
-0@@ -20,6 +20,7 @@#include <linux/shrinker.h> #include <linux/resource.h> #include <linux/page_ext.h> +#include <linux/err.h> 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);mm/Kconfig +3
-0@@ -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 + boolmm/Makefile +1
-0@@ -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.omm/frame_vector.c new file +231
-0@@ -0,0 +1,231 @@ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/pagemap.h> +#include <linux/sched.h> + +/* +* 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->mm; +struct vm_area_struct *vma; +int ret =0 ; +int err; +int locked; + +if (nr_frames ==0 ) +return 0 ; + +if (WARN_ON_ONCE (nr_frames > vec->nr_allocated)) + nr_frames = vec->nr_allocated; + +down_read (&mm->mmap_sem); + locked =1 ; + vma =find_vma_intersection (mm, start, start +1 ); +if (!vma) { + ret = -EFAULT ; + goto out; + } +if (!(vma->vm_flags & (VM_IO |VM_PFNMAP ))) { + vec->got_ref = true; + vec->is_pfns = false; + ret =get_user_pages_locked (current, mm, start, nr_frames, + write, force, (struct page **)(vec->ptrs), &locked); + goto out; + } + + vec->got_ref = false; + vec->is_pfns = true; +do { +unsigned long *nums =frame_vector_pfns (vec); + +while (ret < nr_frames && start +PAGE_SIZE <= vma->vm_end) { + err =follow_pfn (vma, start, &nums[ret]); +if (err) { +if (ret ==0 ) + ret = err; + goto out; + } + start +=PAGE_SIZE ; + ret++; + } +/* +* We stop if we have enough pages or if VMA doesn't completely +* cover the tail page. +*/ +if (ret >= nr_frames || start < vma->vm_end) +break ; + vma =find_vma_intersection (mm, start, start +1 ); + }while (vma && vma->vm_flags & (VM_IO |VM_PFNMAP )); +out: +if (locked) +up_read (&mm->mmap_sem); +if (!ret) + ret = -EFAULT ; +if (ret >0 ) + vec->nr_frames = ret; +return ret; +} +EXPORT_SYMBOL (get_vaddr_frames); + +/** +* put_vaddr_frames() - drop references to pages if get_vaddr_frames() acquired +* them +* @vec: frame vector to put +* +* Drop references to pages if get_vaddr_frames() acquired them. We also +* invalidate the frame vector so that it is prepared for the next call into +* get_vaddr_frames(). +*/ +void put_vaddr_frames (struct frame_vector *vec) +{ +int i; +struct page **pages; + +if (!vec->got_ref) + goto out; + pages =frame_vector_pages (vec); +/* +* frame_vector_pages() might needed to do a conversion when +* get_vaddr_frames() got pages but vec was later converted to pfns. +* But it shouldn't really fail to convert pfns back... +*/ +if (WARN_ON (IS_ERR (pages))) + goto out; +for (i =0 ; i < vec->nr_frames; i++) +put_page (pages[i]); + vec->got_ref = false; +out: + vec->nr_frames =0 ; +} +EXPORT_SYMBOL (put_vaddr_frames); + +/** +* frame_vector_to_pages - convert frame vector to contain page pointers +* @vec: frame vector to convert +* +* Convert @vec to contain array of page pointers. If the conversion is +* successful, return 0. Otherwise return an error. Note that we do not grab +* page references for the page structures. +*/ +int frame_vector_to_pages (struct frame_vector *vec) +{ +int i; +unsigned long *nums; +struct page **pages; + +if (!vec->is_pfns) +return 0 ; + nums =frame_vector_pfns (vec); +for (i =0 ; i < vec->nr_frames; i++) +if (!pfn_valid (nums[i])) +return -EINVAL ; + pages = (struct page **)nums; +for (i =0 ; i < vec->nr_frames; i++) + pages[i] =pfn_to_page (nums[i]); + vec->is_pfns = false; +return 0 ; +} +EXPORT_SYMBOL (frame_vector_to_pages); + +/** +* frame_vector_to_pfns - convert frame vector to contain pfns +* @vec: frame vector to convert +* +* Convert @vec to contain array of pfns. +*/ +void frame_vector_to_pfns (struct frame_vector *vec) +{ +int i; +unsigned long *nums; +struct page **pages; + +if (vec->is_pfns) +return ; + pages = (struct page **)(vec->ptrs); + nums = (unsigned long *)pages; +for (i =0 ; i < vec->nr_frames; i++) + nums[i] =page_to_pfn (pages[i]); + vec->is_pfns = true; +} +EXPORT_SYMBOL (frame_vector_to_pfns); + +/** +* frame_vector_create() - allocate & initialize structure for pinned pfns +* @nr_frames: number of pfns slots we should reserve +* +* Allocate and initialize struct pinned_pfns to be able to hold @nr_pfns +* pfns. +*/ +struct frame_vector *frame_vector_create (unsigned int nr_frames) +{ +struct frame_vector *vec; +int size =sizeof (struct frame_vector ) +sizeof (void *) * nr_frames; + +if (WARN_ON_ONCE (nr_frames ==0 )) +return NULL ; +/* +* This is absurdly high. It's here just to avoid strange effects when +* arithmetics overflows. +*/ +if (WARN_ON_ONCE (nr_frames >INT_MAX /sizeof (void *) /2 )) +return NULL ; +/* +* Avoid higher order allocations, use vmalloc instead. It should +* be rare anyway. +*/ +if (size <=PAGE_SIZE ) + vec =kmalloc (size,GFP_KERNEL ); +else + vec =vmalloc (size); +if (!vec) +return NULL ; + vec->nr_allocated = nr_frames; + vec->nr_frames =0 ; +return vec; +} +EXPORT_SYMBOL (frame_vector_create); + +/** +* frame_vector_destroy() - free memory allocated to carry frame vector +* @vec: Frame vector to free +* +* Free structure allocated by frame_vector_create() to carry frames. +*/ +void frame_vector_destroy (struct frame_vector *vec) +{ +/* Make sure put_vaddr_frames() got called properly... */ +VM_BUG_ON (vec->nr_frames >0 ); +kvfree (vec); +} +EXPORT_SYMBOL (frame_vector_destroy); +
Re: [PATCH 2/9] mm: Provide new get_vaddr_frames() helper
Quoted 11 lines · On Fri, 17 Jul 2015 12:23:40 +0200 Hans Verkuil <[email protected]> wrote:
Quoted 10 lines · Jan Kara
From: Jan Kara <[email protected]>
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 toVM_IO|VM_PFNMAPvma, we don't touch page structures. Caller must make sure pfns aren't reused for anything else while he is using them.
Quoted 8 lines
Quoted 6 lines
This function is created for various drivers to simplify handling of their buffers.
Acked-by Mel Gorman <[email protected]>Acked-by Vlastimil Babka <[email protected]>Signed-off-by Jan Kara <[email protected]>I'd like to see an Acked-by from Andrew or mm-maintainers before I merge this.
I think I already acked this but it got lost.
PATCH v7 3/9 media: omap_vout: Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns()
In reply to Jan KaraFrom: Jan Kara <[email protected]>
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.
--- drivers/media/platform/omap/Kconfig | 1 + drivers/media/platform/omap/omap_vout.c | 67 +++++++++++++++------------------ 2 files changed, 32 insertions(+), 36 deletions(-)
drivers/media/platform/omap/Kconfig +1 -0
@@ -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.
drivers/media/platform/omap/omap_vout.c +31 -36
97 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v7 4/9 vb2: Provide helpers for mapping virtual addresses
In reply to Jan KaraFrom: Jan Kara <[email protected]>
Provide simple helper functions to map virtual address range into an array of pfns / pages.
--- 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(+)
drivers/media/v4l2-core/Kconfig +1 -0
@@ -84,6 +84,7 @@ config VIDEOBUF2_CORE config VIDEOBUF2_MEMOPS tristate + select FRAME_VECTOR config VIDEOBUF2_DMA_CONTIG tristate
drivers/media/v4l2-core/videobuf2-memops.c +58 -0
64 lines not on this page · raw message
include/media/videobuf2-memops.h +5 -0
@@ -15,6 +15,7 @@#define _MEDIA_VIDEOBUF2_MEMOPS_H#include <media/videobuf2-core.h> +#include <linux/mm.h> /** * 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
Signature · 1 line
2.1.4
PATCH v7 5/9 media: vb2: Convert vb2_dma_sg_get_userptr() to use frame vector
In reply to Jan KaraFrom: Jan Kara <[email protected]>
--- drivers/media/v4l2-core/videobuf2-dma-sg.c | 95 +++++------------------------- 1 file changed, 15 insertions(+), 80 deletions(-)
drivers/media/v4l2-core/videobuf2-dma-sg.c +15 -80
@@ -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 int num_pages;atomic_t refcount;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, buf->num_pages, buf->offset, size,0 )) - goto userptr_fail_alloc_table_from_pages; + goto userptr_fail_sgtable; sgt = &buf->sg_table;/*
@@ -326,19 +274,9 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, userptr_fail_map:sg_free_table (&buf->sg_table); -userptr_fail_alloc_table_from_pages: -userptr_fail_get_user_pages: -dprintk (1 ,"get_user_pages requested/got: %d/%d]\n" , - buf->num_pages, num_pages_from_user); -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_fail_find_vma: -up_read (¤t->mm->mmap_sem); -kfree (buf->pages); -userptr_fail_alloc_pages: +userptr_fail_sgtable: +vb2_destroy_framevec (vec); +userptr_fail_pfnvec:kfree (buf);return NULL ; }
@@ -366,11 +304,8 @@ static void vb2_dma_sg_put_userptr(void *buf_priv)while (--i >=0 ) {if (buf->dma_dir ==DMA_FROM_DEVICE )set_page_dirty_lock (buf->pages[i]); -if (!vma_is_io (buf->vma)) -put_page (buf->pages[i]); } -kfree (buf->pages); -vb2_put_vma (buf->vma); +vb2_destroy_framevec (buf->vec);kfree (buf); }
Signature · 1 line
2.1.4
PATCH v7 6/9 media: vb2: Convert vb2_vmalloc_get_userptr() to use frame vector
In reply to Jan KaraFrom: Jan Kara <[email protected]>
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.
--- drivers/media/v4l2-core/videobuf2-vmalloc.c | 92 +++++++++++------------------ 1 file changed, 36 insertions(+), 56 deletions(-)
drivers/media/v4l2-core/videobuf2-vmalloc.c +36 -56
@@ -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 int n_pages;atomic_t refcount;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_put_userptr(void *buf_priv)struct vb2_vmalloc_buf *buf = buf_priv;unsigned long vaddr = (unsigned long )buf->vaddr &PAGE_MASK ;unsigned int i; +struct page **pages; +unsigned int n_pages; -if (buf->pages) { +if (!buf->vec->is_pfns) { + n_pages =frame_vector_count (buf->vec); + pages =frame_vector_pages (buf->vec);if (vaddr) -vm_unmap_ram ((void *)vaddr, buf->n_pages); -for (i =0 ; i < buf->n_pages; ++i) { -if (buf->dma_dir ==DMA_FROM_DEVICE ) -set_page_dirty_lock (buf->pages[i]); -put_page (buf->pages[i]); - } -kfree (buf->pages); +vm_unmap_ram ((void *)vaddr, n_pages); +if (buf->dma_dir ==DMA_FROM_DEVICE ) +for (i =0 ; i < n_pages; i++) +set_page_dirty_lock (pages[i]); }else { -vb2_put_vma (buf->vma);iounmap ((__force void __iomem *)buf->vaddr); } +vb2_destroy_framevec (buf->vec);kfree (buf); }
Signature · 7 lines
2.1.4 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v7 7/9 media: vb2: Convert vb2_dc_get_userptr() to use frame vector
In reply to Jan KaraFrom: Jan Kara <[email protected]>
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.
--- drivers/media/v4l2-core/videobuf2-dma-contig.c | 212 ++++--------------------- 1 file changed, 34 insertions(+), 178 deletions(-)
drivers/media/v4l2-core/videobuf2-dma-contig.c +34 -178
@@ -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_t refcount;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_put_userptr(void *buf_priv)*/ dma_unmap_sg_attrs (buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir, &attrs); -if (!vma_is_io (buf->vma)) -vb2_dc_sgt_foreach_page (sgt, vb2_dc_put_dirty_page); - + pages =frame_vector_pages (buf->vec); +/* sgt should exist only if vector contains pages... */ +BUG_ON (IS_ERR (pages)); +for (i =0 ; i <frame_vector_count (buf->vec); i++) +set_page_dirty_lock (pages[i]);sg_free_table (sgt);kfree (sgt); } -vb2_put_vma (buf->vma); +vb2_destroy_framevec (buf->vec);kfree (buf); }
@@ -572,13 +474,10 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr, {struct vb2_dc_conf *conf = alloc_ctx;struct vb2_dc_buf *buf; -unsigned long start; -unsigned long end; +struct frame_vector *vec;unsigned long offset; -struct page **pages; -int n_pages; +int n_pages, i;int ret =0 ; -struct vm_area_struct *vma;struct sg_table *sgt;unsigned long contig_size;unsigned long dma_align =dma_get_cache_alignment ();
@@ -604,75 +503,43 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr, buf->dev = conf->dev; buf->dma_dir = dma_dir; - start = vaddr &PAGE_MASK ; offset = vaddr & ~PAGE_MASK ; - end =PAGE_ALIGN (vaddr + size); - n_pages = (end - start) >>PAGE_SHIFT ; - - pages =kmalloc (n_pages *sizeof (pages[0 ]),GFP_KERNEL ); -if (!pages) { - ret = -ENOMEM ; -pr_err ("failed to allocate pages table\n" ); + vec =vb2_create_framevec (vaddr, size, dma_dir ==DMA_FROM_DEVICE ); +if (IS_ERR (vec)) { + ret =PTR_ERR (vec); goto fail_buf; } + buf->vec = vec; + n_pages =frame_vector_count (vec); + ret =frame_vector_to_pages (vec); +if (ret <0 ) { +unsigned long *nums =frame_vector_pfns (vec); -down_read (¤t->mm->mmap_sem); -/* current->mm->mmap_sem is taken by videobuf2 core */ - vma =find_vma (current->mm, vaddr); -if (!vma) { -pr_err ("no vma for address %lu\n" , vaddr); - ret = -EFAULT ; - goto fail_pages; - } - -if (vma->vm_end < vaddr + size) { -pr_err ("vma at %lu is too small for %lu bytes\n" , vaddr, size); - ret = -EFAULT ; - goto fail_pages; - } - - buf->vma =vb2_get_vma (vma); -if (!buf->vma) { -pr_err ("failed to copy vma\n" ); - ret = -ENOMEM ; - goto fail_pages; - } - -/* extract page list from userspace mapping */ - ret =vb2_dc_get_user_pages (start, pages, n_pages, vma, dma_dir); -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); -return buf; - } - -pr_err ("failed to get user pages\n" ); - goto fail_vma; +/* +* Failed to convert to pages... Check the memory is physically +* contiguous and use direct mapping +*/ +for (i =1 ; i < n_pages; i++) +if (nums[i-1 ] +1 != nums[i]) + goto fail_pfnvec; + buf->dma_addr =vb2_dc_pfn_to_dma (buf->dev, nums[0 ]); + goto out; } -up_read (¤t->mm->mmap_sem); sgt =kzalloc (sizeof (*sgt),GFP_KERNEL );if (!sgt) {pr_err ("failed to allocate sg table\n" ); ret = -ENOMEM ; - goto fail_get_user_pages; + goto fail_pfnvec; } - ret =sg_alloc_table_from_pages (sgt, pages, n_pages, + ret =sg_alloc_table_from_pages (sgt,frame_vector_pages (vec), n_pages, offset, size,GFP_KERNEL );if (ret) {pr_err ("failed to initialize sg table\n" ); goto fail_sgt; } -/* pages are no longer needed */ -kfree (pages); - pages =NULL ; -/* * No need to sync to the device, this will happen later when the * prepare() memop is called.
@@ -694,8 +561,9 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr, } buf->dma_addr =sg_dma_address (sgt->sgl); - buf->size = size; buf->dma_sgt = sgt; +out: + buf->size = size;return buf;
@@ -704,25 +572,13 @@ fail_map_sg: buf->dma_dir, &attrs); fail_sgt_init: -if (!vma_is_io (buf->vma)) -vb2_dc_sgt_foreach_page (sgt, put_page);sg_free_table (sgt); fail_sgt:kfree (sgt); -fail_get_user_pages: -if (pages && !vma_is_io (buf->vma)) -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_pfnvec: +vb2_destroy_framevec (vec); fail_buf:kfree (buf);
Signature · 1 line
2.1.4
PATCH v7 8/9 media: vb2: Remove unused functions
In reply to Jan KaraFrom: Jan Kara <[email protected]>
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.
--- drivers/media/v4l2-core/videobuf2-memops.c | 114 ----------------------------- include/media/videobuf2-memops.h | 6 -- 2 files changed, 120 deletions(-)
drivers/media/v4l2-core/videobuf2-memops.c +0 -114
@@ -23,120 +23,6 @@#include <media/videobuf2-memops.h> /** -* 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
include/media/videobuf2-memops.h +0 -6
@@ -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 *vma); -void vb2_put_vma (struct vm_area_struct *vma); -struct frame_vector *vb2_create_framevec (unsigned long start,unsigned long length,bool write);
Signature · 1 line
2.1.4
PATCH v7 9/9 drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()
In reply to Jan KaraFrom: Jan Kara <[email protected]>
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.
--- 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(-)
drivers/gpu/drm/exynos/Kconfig +1 -0
@@ -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.
drivers/gpu/drm/exynos/exynos_drm_g2d.c +29 -62
154 lines not on this page · raw message
drivers/gpu/drm/exynos/exynos_drm_gem.c +0 -97
103 lines not on this page · raw message
Signature · 1 line
2.1.4
Re: [PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()
Quoted 6 lines · Jan Kara
From: Jan Kara <[email protected]>
Convert
g2d_userptr_get_dma_addr()to pin pages usingget_vaddr_frames(). This removes the knowledge about vmas andmmap_semlocking from exynos driver. Also it fixes a problem that the function has been mapping user provided address without holdingmmap_sem.
I'd like to see an Ack from one of the exynos drm driver maintainers before I merge this.
Inki, Marek?
Regards,
Hans
Quoted 293 lines
Signed-off-by Jan Kara <[email protected]>--- 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(-)drivers/gpu/drm/exynos/Kconfig +1
-0@@ -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.drivers/gpu/drm/exynos/exynos_drm_g2d.c +29
-62@@ -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: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); -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; - - ret =exynos_gem_get_pages_from_userptr (start &PAGE_MASK , - npages, pages, vma); -if (ret <0 ) { -up_read (¤t->mm->mmap_sem); -DRM_ERROR ("failed to get user pages from userptr.\n" ); - goto err_put_vma; - } - -up_read (¤t->mm->mmap_sem); - g2d_userptr->pages = pages; - sgt =kzalloc (sizeof (*sgt),GFP_KERNEL );if (!sgt) { ret = -ENOMEM ; - goto err_free_userptr; + goto err_put_framevec; } - ret =sg_alloc_table_from_pages (sgt, pages, npages, offset, - size,GFP_KERNEL ); + ret =sg_alloc_table_from_pages (sgt, +frame_vector_pages (g2d_userptr->vec), + npages, offset, size,GFP_KERNEL );if (ret <0 ) {DRM_ERROR ("failed to get sgt from pages.\n" ); goto err_free_sgt;@@ -549,16 +521,11 @@ err_sg_free_table: err_free_sgt:kfree (sgt); -err_free_userptr: -exynos_gem_put_pages_to_userptr (g2d_userptr->pages, - g2d_userptr->npages, - g2d_userptr->vma); - -err_put_vma: -exynos_gem_put_vma (g2d_userptr->vma); +err_put_framevec: +put_vaddr_frames (g2d_userptr->vec); -err_free_pages: -drm_free_large (pages); +err_destroy_framevec: +frame_vector_destroy (g2d_userptr->vec); err_free:kfree (g2d_userptr);drivers/gpu/drm/exynos/exynos_drm_gem.c +0
-97@@ -378,103 +378,6 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,return 0 ; } -struct vm_area_struct *exynos_gem_get_vma (struct vm_area_struct *vma) -{ -struct vm_area_struct *vma_copy; - - vma_copy =kmalloc (sizeof (*vma_copy),GFP_KERNEL ); -if (!vma_copy) -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; -} - -void exynos_gem_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); -} - -int exynos_gem_get_pages_from_userptr (unsigned long start, -unsigned int npages, -struct page **pages, -struct vm_area_struct *vma) -{ -int get_npages; - -/* the memory region mmaped with VM_PFNMAP. */ -if (vma_is_io (vma)) { -unsigned int i; - -for (i =0 ; i < npages; ++i, start +=PAGE_SIZE ) { -unsigned long pfn; -int ret =follow_pfn (vma, start, &pfn); -if (ret) -return ret; - - pages[i] =pfn_to_page (pfn); - } - -if (i != npages) { -DRM_ERROR ("failed to get user_pages.\n" ); -return -EINVAL ; - } - -return 0 ; - } - - get_npages =get_user_pages (current, current->mm, start, - npages,1 ,1 , pages,NULL ); - get_npages =max (get_npages,0 ); -if (get_npages != npages) { -DRM_ERROR ("failed to get user_pages.\n" ); -while (get_npages) -put_page (pages[--get_npages]); -return -EFAULT ; - } - -return 0 ; -} - -void exynos_gem_put_pages_to_userptr (struct page **pages, -unsigned int npages, -struct vm_area_struct *vma) -{ -if (!vma_is_io (vma)) { -unsigned int i; - -for (i =0 ; i < npages; i++) { -set_page_dirty_lock (pages[i]); - -/* -* undo the reference we took when populating -* the table. -*/ -put_page (pages[i]); - } - } -} -int exynos_gem_map_sgt_with_dma (struct drm_device *drm_dev,struct sg_table *sgt,enum dma_data_direction dir)
Re: [PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()
Quoted 8 lines · Hans Verkuil
Quoted 6 lines · Jan Kara
From: Jan Kara <[email protected]>
Convert
g2d_userptr_get_dma_addr()to pin pages usingget_vaddr_frames(). This removes the knowledge about vmas andmmap_semlocking from exynos driver. Also it fixes a problem that the function has been mapping user provided address without holdingmmap_sem.
Quoted 4 lines
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,
Thanks,
Inki Dae
Quoted 304 lines
Regards,
Hans
Quoted 283 lines
Signed-off-by Jan Kara <[email protected]>--- 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(-)drivers/gpu/drm/exynos/Kconfig +1
-0@@ -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.drivers/gpu/drm/exynos/exynos_drm_g2d.c +29
-62@@ -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: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); -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; - - ret =exynos_gem_get_pages_from_userptr (start &PAGE_MASK , - npages, pages, vma); -if (ret <0 ) { -up_read (¤t->mm->mmap_sem); -DRM_ERROR ("failed to get user pages from userptr.\n" ); - goto err_put_vma; - } - -up_read (¤t->mm->mmap_sem); - g2d_userptr->pages = pages; - sgt =kzalloc (sizeof (*sgt),GFP_KERNEL );if (!sgt) { ret = -ENOMEM ; - goto err_free_userptr; + goto err_put_framevec; } - ret =sg_alloc_table_from_pages (sgt, pages, npages, offset, - size,GFP_KERNEL ); + ret =sg_alloc_table_from_pages (sgt, +frame_vector_pages (g2d_userptr->vec), + npages, offset, size,GFP_KERNEL );if (ret <0 ) {DRM_ERROR ("failed to get sgt from pages.\n" ); goto err_free_sgt;@@ -549,16 +521,11 @@ err_sg_free_table: err_free_sgt:kfree (sgt); -err_free_userptr: -exynos_gem_put_pages_to_userptr (g2d_userptr->pages, - g2d_userptr->npages, - g2d_userptr->vma); - -err_put_vma: -exynos_gem_put_vma (g2d_userptr->vma); +err_put_framevec: +put_vaddr_frames (g2d_userptr->vec); -err_free_pages: -drm_free_large (pages); +err_destroy_framevec: +frame_vector_destroy (g2d_userptr->vec); err_free:kfree (g2d_userptr);drivers/gpu/drm/exynos/exynos_drm_gem.c +0
-90@@ -378,103 +378,6 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,return 0 ; } -struct vm_area_struct *exynos_gem_get_vma (struct vm_area_struct *vma) -{ -struct vm_area_struct *vma_copy; - - vma_copy =kmalloc (sizeof (*vma_copy),GFP_KERNEL ); -if (!vma_copy) -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; -} - -void exynos_gem_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); -} - -int exynos_gem_get_pages_from_userptr (unsigned long start, -unsigned int npages, -struct page **pages, -struct vm_area_struct *vma) -{ -int get_npages; - -/* the memory region mmaped with VM_PFNMAP. */ -if (vma_is_io (vma)) { -unsigned int i; - -for (i =0 ; i < npages; ++i, start +=PAGE_SIZE ) { -unsigned long pfn; -int ret =follow_pfn (vma, start, &pfn); -if (ret) -return ret; - - pages[i] =pfn_to_page (pfn); - } - -if (i != npages) { -DRM_ERROR ("failed to get user_pages.\n" ); -return -EINVAL ; - } - -return 0 ; - } - - get_npages =get_user_pages (current, current->mm, start, - npages,1 ,1 , pages,NULL ); - get_npages =max (get_npages,0 ); -if (get_npages != npages) { -DRM_ERROR ("failed to get user_pages.\n" ); -while (get_npages) -put_page (pages[--get_npages]); -return -EFAULT ; - } - -return 0 ; -} - -void exynos_gem_put_pages_to_userptr (struct page **pages, -unsigned int npages, -struct vm_area_struct *vma) -{ -if (!vma_is_io (vma)) { -unsigned int i; - -for (i =0 ; i < npages; i++) { -set_page_dirty_lock (pages[i]); - -/* -* undo the reference we took when populating drivers/gpu/drm/exynos/exynos_drm_gem.c int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, · line 383
Quoted 10 lines
drivers/gpu/drm/exynos/exynos_drm_gem.c +0
-7-* the table. -*/ -put_page (pages[i]); - } - } -} -int exynos_gem_map_sgt_with_dma (struct drm_device *drm_dev,struct sg_table *sgt,enum dma_data_direction dir)--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()
Quoted 12 lines · Inki Dae
Quoted 11 lines · Hans Verkuil
Quoted 6 lines · Jan Kara
From: Jan Kara <[email protected]>
Convert
g2d_userptr_get_dma_addr()to pin pages usingget_vaddr_frames(). This removes the knowledge about vmas andmmap_semlocking from exynos driver. Also it fixes a problem that the function has been mapping user provided address without holdingmmap_sem.I'd like to see an Ack from one of the exynos drm driver maintainers before I merge this.
Quoted 6 lines
Quoted 1 line
Inki, Marek?
I already gave Ack but it seems that Jan missed it while updating.
Anyway,
Acked-by Inki Dae <[email protected]>
Thanks!
BTW, I didn't see your earlier Ack either. Was it posted to the linux-media list as well? It didn't turn up there.
Regards,
Hans
Quoted 314 lines
Thanks,
Inki DaeQuoted 295 lines
Regards,
Hans
Quoted 290 lines
Signed-off-by Jan Kara <[email protected]>--- 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(-)drivers/gpu/drm/exynos/Kconfig +1
-0@@ -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.drivers/gpu/drm/exynos/exynos_drm_g2d.c +29
-62@@ -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: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); -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; - - ret =exynos_gem_get_pages_from_userptr (start &PAGE_MASK , - npages, pages, vma); -if (ret <0 ) { -up_read (¤t->mm->mmap_sem); -DRM_ERROR ("failed to get user pages from userptr.\n" ); - goto err_put_vma; - } - -up_read (¤t->mm->mmap_sem); - g2d_userptr->pages = pages; - sgt =kzalloc (sizeof (*sgt),GFP_KERNEL );if (!sgt) { ret = -ENOMEM ; - goto err_free_userptr; + goto err_put_framevec; } - ret =sg_alloc_table_from_pages (sgt, pages, npages, offset, - size,GFP_KERNEL ); + ret =sg_alloc_table_from_pages (sgt, +frame_vector_pages (g2d_userptr->vec), + npages, offset, size,GFP_KERNEL );if (ret <0 ) {DRM_ERROR ("failed to get sgt from pages.\n" ); goto err_free_sgt;@@ -549,16 +521,11 @@ err_sg_free_table: err_free_sgt:kfree (sgt); -err_free_userptr: -exynos_gem_put_pages_to_userptr (g2d_userptr->pages, - g2d_userptr->npages, - g2d_userptr->vma); - -err_put_vma: -exynos_gem_put_vma (g2d_userptr->vma); +err_put_framevec: +put_vaddr_frames (g2d_userptr->vec); -err_free_pages: -drm_free_large (pages); +err_destroy_framevec: +frame_vector_destroy (g2d_userptr->vec); err_free:kfree (g2d_userptr);drivers/gpu/drm/exynos/exynos_drm_gem.c +0
-97@@ -378,103 +378,6 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,return 0 ; } -struct vm_area_struct *exynos_gem_get_vma (struct vm_area_struct *vma) -{ -struct vm_area_struct *vma_copy; - - vma_copy =kmalloc (sizeof (*vma_copy),GFP_KERNEL ); -if (!vma_copy) -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; -} - -void exynos_gem_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); -} - -int exynos_gem_get_pages_from_userptr (unsigned long start, -unsigned int npages, -struct page **pages, -struct vm_area_struct *vma) -{ -int get_npages; - -/* the memory region mmaped with VM_PFNMAP. */ -if (vma_is_io (vma)) { -unsigned int i; - -for (i =0 ; i < npages; ++i, start +=PAGE_SIZE ) { -unsigned long pfn; -int ret =follow_pfn (vma, start, &pfn); -if (ret) -return ret; - - pages[i] =pfn_to_page (pfn); - } - -if (i != npages) { -DRM_ERROR ("failed to get user_pages.\n" ); -return -EINVAL ; - } - -return 0 ; - } - - get_npages =get_user_pages (current, current->mm, start, - npages,1 ,1 , pages,NULL ); - get_npages =max (get_npages,0 ); -if (get_npages != npages) { -DRM_ERROR ("failed to get user_pages.\n" ); -while (get_npages) -put_page (pages[--get_npages]); -return -EFAULT ; - } - -return 0 ; -} - -void exynos_gem_put_pages_to_userptr (struct page **pages, -unsigned int npages, -struct vm_area_struct *vma) -{ -if (!vma_is_io (vma)) { -unsigned int i; - -for (i =0 ; i < npages; i++) { -set_page_dirty_lock (pages[i]); - -/* -* undo the reference we took when populating -* the table. -*/ -put_page (pages[i]); - } - } -} - int exynos_gem_map_sgt_with_dma(struct drm_device *drm_dev,Quoted 9 lines
drivers/gpu/drm/exynos/exynos_drm_gem.c int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, · line 383
Quoted 3 lines
drivers/gpu/drm/exynos/exynos_drm_gem.c +0
-0struct sg_table *sgt, enum dma_data_direction dir)--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Inki Dae
maintainerRe: [PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()
Quoted 13 lines · Hans Verkuil
Quoted 12 lines · Inki Dae
Quoted 11 lines · Hans Verkuil
Quoted 6 lines · Jan Kara
From: Jan Kara <[email protected]>
Convert
g2d_userptr_get_dma_addr()to pin pages usingget_vaddr_frames(). This removes the knowledge about vmas andmmap_semlocking from exynos driver. Also it fixes a problem that the function has been mapping user provided address without holdingmmap_sem.I'd like to see an Ack from one of the exynos drm driver maintainers before I merge this.
Quoted 8 lines
Quoted 6 lines
Quoted 1 line
Inki, Marek?
I already gave Ack but it seems that Jan missed it while updating.
Anyway,
Acked-by Inki Dae <[email protected]>Thanks!
Oops, sorry. This patch would incur a build warning. Below is my comment.
Quoted 3 lines
BTW, I didn't see your earlier Ack either. Was it posted to the linux-media list as well? It didn't turn up there.
I thought posted but I couldn't find the email in my mailbox so I may mistake.
Quoted 102 lines
Regards,
Hans
Quoted 97 lines
Thanks,
Inki DaeQuoted 93 lines
Regards,
Hans
Quoted 88 lines
Signed-off-by Jan Kara <[email protected]>--- 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(-)drivers/gpu/drm/exynos/Kconfig +1
-0@@ -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.drivers/gpu/drm/exynos/exynos_drm_g2d.c +11
-11@@ -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: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;
Quoted 12 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/gpu/drm/exynos/exynos_drm_g2d.c +0
-0start = userptr &PAGE_MASK ; offset = userptr & ~PAGE_MASK ; end =PAGE_ALIGN (userptr + size); npages = (end - start) >>PAGE_SHIFT ;Quoted 8 lines
Quoted 8 lines
drivers/gpu/drm/exynos/exynos_drm_g2d.c static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, · line 465
Quoted 8 lines
drivers/gpu/drm/exynos/exynos_drm_g2d.c +2
-6- 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
ps. please, ignore the codes related to build error in the patch.
With the change, Acked-by: Inki Dae <[email protected]>
Thanks,
Inki Dae
Quoted 207 lines
Quoted 205 lines
Quoted 190 lines
Quoted 190 lines
drivers/gpu/drm/exynos/exynos_drm_g2d.c +16
-45goto 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; - - ret =exynos_gem_get_pages_from_userptr (start &PAGE_MASK , - npages, pages, vma); -if (ret <0 ) { -up_read (¤t->mm->mmap_sem); -DRM_ERROR ("failed to get user pages from userptr.\n" ); - goto err_put_vma; - } - -up_read (¤t->mm->mmap_sem); - g2d_userptr->pages = pages; - sgt =kzalloc (sizeof (*sgt),GFP_KERNEL );if (!sgt) { ret = -ENOMEM ; - goto err_free_userptr; + goto err_put_framevec; } - ret =sg_alloc_table_from_pages (sgt, pages, npages, offset, - size,GFP_KERNEL ); + ret =sg_alloc_table_from_pages (sgt, +frame_vector_pages (g2d_userptr->vec), + npages, offset, size,GFP_KERNEL );if (ret <0 ) {DRM_ERROR ("failed to get sgt from pages.\n" ); goto err_free_sgt;@@ -549,16 +521,11 @@ err_sg_free_table: err_free_sgt:kfree (sgt); -err_free_userptr: -exynos_gem_put_pages_to_userptr (g2d_userptr->pages, - g2d_userptr->npages, - g2d_userptr->vma); - -err_put_vma: -exynos_gem_put_vma (g2d_userptr->vma); +err_put_framevec: +put_vaddr_frames (g2d_userptr->vec); -err_free_pages: -drm_free_large (pages); +err_destroy_framevec: +frame_vector_destroy (g2d_userptr->vec); err_free:kfree (g2d_userptr);drivers/gpu/drm/exynos/exynos_drm_gem.c +0
-97@@ -378,103 +378,6 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,return 0 ; } -struct vm_area_struct *exynos_gem_get_vma (struct vm_area_struct *vma) -{ -struct vm_area_struct *vma_copy; - - vma_copy =kmalloc (sizeof (*vma_copy),GFP_KERNEL ); -if (!vma_copy) -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; -} - -void exynos_gem_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); -} - -int exynos_gem_get_pages_from_userptr (unsigned long start, -unsigned int npages, -struct page **pages, -struct vm_area_struct *vma) -{ -int get_npages; - -/* the memory region mmaped with VM_PFNMAP. */ -if (vma_is_io (vma)) { -unsigned int i; - -for (i =0 ; i < npages; ++i, start +=PAGE_SIZE ) { -unsigned long pfn; -int ret =follow_pfn (vma, start, &pfn); -if (ret) -return ret; - - pages[i] =pfn_to_page (pfn); - } - -if (i != npages) { -DRM_ERROR ("failed to get user_pages.\n" ); -return -EINVAL ; - } - -return 0 ; - } - - get_npages =get_user_pages (current, current->mm, start, - npages,1 ,1 , pages,NULL ); - get_npages =max (get_npages,0 ); -if (get_npages != npages) { -DRM_ERROR ("failed to get user_pages.\n" ); -while (get_npages) -put_page (pages[--get_npages]); -return -EFAULT ; - } - -return 0 ; -} - -void exynos_gem_put_pages_to_userptr (struct page **pages, -unsigned int npages, -struct vm_area_struct *vma) -{ -if (!vma_is_io (vma)) { -unsigned int i; - -for (i =0 ; i < npages; i++) { -set_page_dirty_lock (pages[i]); - -/* -* undo the reference we took when populating -* the table. -*/ -put_page (pages[i]); - } - } -} - int exynos_gem_map_sgt_with_dma(struct drm_device *drm_dev,Quoted 9 lines
drivers/gpu/drm/exynos/exynos_drm_gem.c int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, · line 383
Quoted 3 lines
drivers/gpu/drm/exynos/exynos_drm_gem.c +0
-0struct sg_table *sgt, enum dma_data_direction dir)--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 9/9] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()
Quoted 45 lines · Inki Dae
Quoted 13 lines · Hans Verkuil
Quoted 12 lines · Inki Dae
Quoted 11 lines · Hans Verkuil
Quoted 6 lines · Jan Kara
From: Jan Kara <[email protected]>
Convert
g2d_userptr_get_dma_addr()to pin pages usingget_vaddr_frames(). This removes the knowledge about vmas andmmap_semlocking from exynos driver. Also it fixes a problem that the function has been mapping user provided address without holdingmmap_sem.I'd like to see an Ack from one of the exynos drm driver maintainers before I merge this.
Quoted 8 lines
Quoted 6 lines
Quoted 1 line
Inki, Marek?
I already gave Ack but it seems that Jan missed it while updating.
Anyway,
Acked-by Inki Dae <[email protected]>Thanks!
Oops, sorry. This patch would incur a build warning. Below is my comment.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
drivers/gpu/drm/exynos/exynos_drm_g2d.c +1
-0@@ -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;Quoted 12 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/gpu/drm/exynos/exynos_drm_g2d.c +0
-0start = userptr &PAGE_MASK ; offset = userptr & ~PAGE_MASK ; end =PAGE_ALIGN (userptr + size); npages = (end - start) >>PAGE_SHIFT ;Quoted 8 lines
Quoted 8 lines
drivers/gpu/drm/exynos/exynos_drm_g2d.c static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, · line 465
Quoted 8 lines
drivers/gpu/drm/exynos/exynos_drm_g2d.c +2
-6- 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 =
-EFAULThere. And below is a patch posted already,
Quoted 1 line
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?
Quoted 3 lines
ps. please, ignore the codes related to build error in the patch.
With the change, Acked-by: Inki Dae <[email protected]>
Thanks and sorry for making so many stupid mistakes in the Exynos driver.
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Quoted 1 line
From
e1ce3781eb0a3ffe045055f4145bc60ee7b2a6b5Mon Sep 17 00:00:00 2001
From: Jan Kara <[email protected]>
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.
--- 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(-)
drivers/gpu/drm/exynos/Kconfig +1 -0
@@ -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.
drivers/gpu/drm/exynos/exynos_drm_g2d.c +29 -60
154 lines not on this page · raw message
drivers/gpu/drm/exynos/exynos_drm_gem.c +0 -97
103 lines not on this page · raw message
Signature · 1 line
2.1.4
Quoted 21 lines · Jan Kara
From: Jan Kara <[email protected]>
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_RETRYhandling. The primary motivation for this series is to remove knowledge aboutmmap_semlocking 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 fromget_user_pages()is that this function can also deal with pfnmap, and io mappings which is what the media drivers need.
Quoted 5 lines
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!
Scheduled for Friday or the following Monday!
Thanks,
Hans
Quoted 34 lines
Honza
Changes since v6:
* Fixed compilation error introduced into exynos driver
* Folded patch allowingget_vaddr_pfn()code to be selected by a config option into previous patches
* Rebased on top of linux-media treeChanges since v5:
* Moved mm helper into a separate file and behind a config option
* Changed the first patch pushingmmap_semdown in videobuf2 core to avoid possible deadlockChanges since v4:
* Minor cleanups and fixes pointed out by Mel and Vlasta
* Added Acked-by tagsChanges since v3:
* Added include <linux/vmalloc.h> intomm/gup.cas it's needed for some archs
* Fixed error path for exynos driverChanges 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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Jan,
Quoted 21 lines · Jan Kara
From: Jan Kara <[email protected]>
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_RETRYhandling. The primary motivation for this series is to remove knowledge aboutmmap_semlocking 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 fromget_user_pages()is that this function can also deal with pfnmap, and io mappings which is what the media drivers need.
Quoted 5 lines
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!
I've done some testing myself and it all looks fine to me. All I need is an additional Ack for the mm patch from Andrew or other mm maintainers.
Regards,
Hans
Quoted 34 lines
Honza
Changes since v6:
* Fixed compilation error introduced into exynos driver
* Folded patch allowingget_vaddr_pfn()code to be selected by a config option into previous patches
* Rebased on top of linux-media treeChanges since v5:
* Moved mm helper into a separate file and behind a config option
* Changed the first patch pushingmmap_semdown in videobuf2 core to avoid possible deadlockChanges since v4:
* Minor cleanups and fixes pointed out by Mel and Vlasta
* Added Acked-by tagsChanges since v3:
* Added include <linux/vmalloc.h> intomm/gup.cas it's needed for some archs
* Fixed error path for exynos driverChanges 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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html