Merge tag 'media/v4.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Sep 2015 23:42:39 +0000 (16:42 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Sep 2015 23:42:39 +0000 (16:42 -0700)
Pull media updates from Mauro Carvalho Chehab:
 "A series of patches that move part of the code used to allocate memory
  from the media subsystem to the mm subsystem"

[ The mm parts have been acked by VM people, and the series was
  apparently in -mm for a while   - Linus ]

* tag 'media/v4.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media:
  [media] drm/exynos: Convert g2d_userptr_get_dma_addr() to use get_vaddr_frames()
  [media] media: vb2: Remove unused functions
  [media] media: vb2: Convert vb2_dc_get_userptr() to use frame vector
  [media] media: vb2: Convert vb2_vmalloc_get_userptr() to use frame vector
  [media] media: vb2: Convert vb2_dma_sg_get_userptr() to use frame vector
  [media] vb2: Provide helpers for mapping virtual addresses
  [media] media: omap_vout: Convert omap_vout_uservirt_to_phys() to use get_vaddr_pfns()
  [media] mm: Provide new get_vaddr_frames() helper
  [media] vb2: Push mmap_sem down to memops

1  2 
drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_drm_gem.c
drivers/media/platform/omap/omap_vout.c
drivers/media/v4l2-core/videobuf2-core.c
include/linux/mm.h
include/media/videobuf2-memops.h
mm/Kconfig
mm/Makefile

index df0b61a60501c46ac6a58da5ae0ec993cbb7f9f4,b364562dc6c112c36945182feb105640c4d33152..bd1a4156f647b3b8cf3d26b97ee657c2b4b2bab6
@@@ -56,7 -56,7 +56,7 @@@ config DRM_EXYNOS_DS
  
  config DRM_EXYNOS_DP
        bool "EXYNOS DRM DP driver support"
 -      depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
 +      depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON)
        default DRM_EXYNOS
        select DRM_PANEL
        help
@@@ -77,6 -77,7 +77,7 @@@ config DRM_EXYNOS_VID
  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.
  
index 535b4ad6c4b14783a6ce099f81f4775759bd5ee6,7584834a53c9b62a0538dab1244f9d57b3bdda3b..3734c34aed16a22938509454cf794e5b4069ac35
  
  /* registers for base address */
  #define G2D_SRC_BASE_ADDR             0x0304
 +#define G2D_SRC_STRIDE_REG            0x0308
  #define G2D_SRC_COLOR_MODE            0x030C
  #define G2D_SRC_LEFT_TOP              0x0310
  #define G2D_SRC_RIGHT_BOTTOM          0x0314
  #define G2D_SRC_PLANE2_BASE_ADDR      0x0318
  #define G2D_DST_BASE_ADDR             0x0404
 +#define G2D_DST_STRIDE_REG            0x0408
  #define G2D_DST_COLOR_MODE            0x040C
  #define G2D_DST_LEFT_TOP              0x0410
  #define G2D_DST_RIGHT_BOTTOM          0x0414
@@@ -150,7 -148,6 +150,7 @@@ struct g2d_cmdlist 
   * A structure of buffer description
   *
   * @format: color format
 + * @stride: buffer stride/pitch in bytes
   * @left_x: the x coordinates of left top corner
   * @top_y: the y coordinates of left top corner
   * @right_x: the x coordinates of right bottom corner
   */
  struct g2d_buf_desc {
        unsigned int    format;
 +      unsigned int    stride;
        unsigned int    left_x;
        unsigned int    top_y;
        unsigned int    right_x;
@@@ -194,10 -190,8 +194,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;
@@@ -367,6 -361,7 +365,7 @@@ static void g2d_userptr_put_dma_addr(st
  {
        struct g2d_cmdlist_userptr *g2d_userptr =
                                        (struct g2d_cmdlist_userptr *)obj;
+       struct page **pages;
  
        if (!obj)
                return;
@@@ -386,19 -381,21 +385,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);
  }
  
@@@ -412,9 -409,7 +413,7 @@@ static dma_addr_t *g2d_userptr_get_dma_
        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;
                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");
+       g2d_userptr->vec = frame_vector_create(npages);
+       if (!g2d_userptr->vec) {
                ret = -ENOMEM;
                goto err_free;
        }
  
-       down_read(&current->mm->mmap_sem);
-       vma = find_vma(current->mm, userptr);
-       if (!vma) {
-               up_read(&current->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(&current->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(&current->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(&current->mm->mmap_sem);
-               DRM_ERROR("failed to get user pages from userptr.\n");
-               goto err_put_vma;
-       }
-       up_read(&current->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;
@@@ -553,16 -523,11 +527,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);
@@@ -593,7 -558,6 +562,7 @@@ static enum g2d_reg_type g2d_get_reg_ty
  
        switch (reg_offset) {
        case G2D_SRC_BASE_ADDR:
 +      case G2D_SRC_STRIDE_REG:
        case G2D_SRC_COLOR_MODE:
        case G2D_SRC_LEFT_TOP:
        case G2D_SRC_RIGHT_BOTTOM:
                reg_type = REG_TYPE_SRC_PLANE2;
                break;
        case G2D_DST_BASE_ADDR:
 +      case G2D_DST_STRIDE_REG:
        case G2D_DST_COLOR_MODE:
        case G2D_DST_LEFT_TOP:
        case G2D_DST_RIGHT_BOTTOM:
@@@ -658,8 -621,8 +627,8 @@@ static bool g2d_check_buf_desc_is_valid
                                                enum g2d_reg_type reg_type,
                                                unsigned long size)
  {
 -      unsigned int width, height;
 -      unsigned long area;
 +      int width, height;
 +      unsigned long bpp, last_pos;
  
        /*
         * check source and destination buffers only.
        if (reg_type != REG_TYPE_SRC && reg_type != REG_TYPE_DST)
                return true;
  
 -      width = buf_desc->right_x - buf_desc->left_x;
 +      /* This check also makes sure that right_x > left_x. */
 +      width = (int)buf_desc->right_x - (int)buf_desc->left_x;
        if (width < G2D_LEN_MIN || width > G2D_LEN_MAX) {
 -              DRM_ERROR("width[%u] is out of range!\n", width);
 +              DRM_ERROR("width[%d] is out of range!\n", width);
                return false;
        }
  
 -      height = buf_desc->bottom_y - buf_desc->top_y;
 +      /* This check also makes sure that bottom_y > top_y. */
 +      height = (int)buf_desc->bottom_y - (int)buf_desc->top_y;
        if (height < G2D_LEN_MIN || height > G2D_LEN_MAX) {
 -              DRM_ERROR("height[%u] is out of range!\n", height);
 +              DRM_ERROR("height[%d] is out of range!\n", height);
                return false;
        }
  
 -      area = (unsigned long)width * (unsigned long)height *
 -                                      g2d_get_buf_bpp(buf_desc->format);
 -      if (area > size) {
 -              DRM_ERROR("area[%lu] is out of range[%lu]!\n", area, size);
 +      bpp = g2d_get_buf_bpp(buf_desc->format);
 +
 +      /* Compute the position of the last byte that the engine accesses. */
 +      last_pos = ((unsigned long)buf_desc->bottom_y - 1) *
 +              (unsigned long)buf_desc->stride +
 +              (unsigned long)buf_desc->right_x * bpp - 1;
 +
 +      /*
 +       * Since right_x > left_x and bottom_y > top_y we already know
 +       * that the first_pos < last_pos (first_pos being the position
 +       * of the first byte the engine accesses), it just remains to
 +       * check if last_pos is smaller then the buffer size.
 +       */
 +
 +      if (last_pos >= size) {
 +              DRM_ERROR("last engine access position [%lu] "
 +                      "is out of range [%lu]!\n", last_pos, size);
                return false;
        }
  
@@@ -994,6 -942,8 +963,6 @@@ static int g2d_check_reg_offset(struct 
                                goto err;
  
                        reg_type = g2d_get_reg_type(reg_offset);
 -                      if (reg_type == REG_TYPE_NONE)
 -                              goto err;
  
                        /* check userptr buffer type. */
                        if ((cmdlist->data[index] & ~0x7fffffff) >> 31) {
                        } else
                                buf_info->types[reg_type] = BUF_TYPE_GEM;
                        break;
 +              case G2D_SRC_STRIDE_REG:
 +              case G2D_DST_STRIDE_REG:
 +                      if (for_addr)
 +                              goto err;
 +
 +                      reg_type = g2d_get_reg_type(reg_offset);
 +
 +                      buf_desc = &buf_info->descs[reg_type];
 +                      buf_desc->stride = cmdlist->data[index + 1];
 +                      break;
                case G2D_SRC_COLOR_MODE:
                case G2D_DST_COLOR_MODE:
                        if (for_addr)
                                goto err;
  
                        reg_type = g2d_get_reg_type(reg_offset);
 -                      if (reg_type == REG_TYPE_NONE)
 -                              goto err;
  
                        buf_desc = &buf_info->descs[reg_type];
                        value = cmdlist->data[index + 1];
                                goto err;
  
                        reg_type = g2d_get_reg_type(reg_offset);
 -                      if (reg_type == REG_TYPE_NONE)
 -                              goto err;
  
                        buf_desc = &buf_info->descs[reg_type];
                        value = cmdlist->data[index + 1];
                                goto err;
  
                        reg_type = g2d_get_reg_type(reg_offset);
 -                      if (reg_type == REG_TYPE_NONE)
 -                              goto err;
  
                        buf_desc = &buf_info->descs[reg_type];
                        value = cmdlist->data[index + 1];
@@@ -1342,6 -1288,9 +1311,6 @@@ static int g2d_subdrv_probe(struct drm_
                return ret;
        }
  
 -      if (!is_drm_iommu_supported(drm_dev))
 -              return 0;
 -
        ret = drm_iommu_attach_device(drm_dev, dev);
        if (ret < 0) {
                dev_err(dev, "failed to enable iommu.\n");
  
  static void g2d_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
  {
 -      if (!is_drm_iommu_supported(drm_dev))
 -              return;
 -
        drm_iommu_detach_device(drm_dev, dev);
  }
  
index 62b9ea1b07fb005c04da732490c06e91a2996e21,47068ae44ced3663d90f73e373c852df65d6a230..f12fbc36b120065902c50253a4e91e9cc8952df5
  #include <drm/drm_vma_manager.h>
  
  #include <linux/shmem_fs.h>
 +#include <linux/dma-buf.h>
  #include <drm/exynos_drm.h>
  
  #include "exynos_drm_drv.h"
  #include "exynos_drm_gem.h"
 -#include "exynos_drm_buf.h"
  #include "exynos_drm_iommu.h"
  
 -static unsigned int convert_to_vm_err_msg(int msg)
 +static int exynos_drm_alloc_buf(struct exynos_drm_gem_obj *obj)
  {
 -      unsigned int out_msg;
 +      struct drm_device *dev = obj->base.dev;
 +      enum dma_attr attr;
 +      unsigned int nr_pages;
  
 -      switch (msg) {
 -      case 0:
 -      case -ERESTARTSYS:
 -      case -EINTR:
 -              out_msg = VM_FAULT_NOPAGE;
 -              break;
 -
 -      case -ENOMEM:
 -              out_msg = VM_FAULT_OOM;
 -              break;
 -
 -      default:
 -              out_msg = VM_FAULT_SIGBUS;
 -              break;
 -      }
 -
 -      return out_msg;
 -}
 -
 -static int check_gem_flags(unsigned int flags)
 -{
 -      if (flags & ~(EXYNOS_BO_MASK)) {
 -              DRM_ERROR("invalid flags.\n");
 -              return -EINVAL;
 +      if (obj->dma_addr) {
 +              DRM_DEBUG_KMS("already allocated.\n");
 +              return 0;
        }
  
 -      return 0;
 -}
 +      init_dma_attrs(&obj->dma_attrs);
  
 -static void update_vm_cache_attr(struct exynos_drm_gem_obj *obj,
 -                                      struct vm_area_struct *vma)
 -{
 -      DRM_DEBUG_KMS("flags = 0x%x\n", obj->flags);
 +      /*
 +       * if EXYNOS_BO_CONTIG, fully physically contiguous memory
 +       * region will be allocated else physically contiguous
 +       * as possible.
 +       */
 +      if (!(obj->flags & EXYNOS_BO_NONCONTIG))
 +              dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &obj->dma_attrs);
  
 -      /* non-cachable as default. */
 -      if (obj->flags & EXYNOS_BO_CACHABLE)
 -              vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
 -      else if (obj->flags & EXYNOS_BO_WC)
 -              vma->vm_page_prot =
 -                      pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
 +      /*
 +       * if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping
 +       * else cachable mapping.
 +       */
 +      if (obj->flags & EXYNOS_BO_WC || !(obj->flags & EXYNOS_BO_CACHABLE))
 +              attr = DMA_ATTR_WRITE_COMBINE;
        else
 -              vma->vm_page_prot =
 -                      pgprot_noncached(vm_get_page_prot(vma->vm_flags));
 -}
 +              attr = DMA_ATTR_NON_CONSISTENT;
 +
 +      dma_set_attr(attr, &obj->dma_attrs);
 +      dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &obj->dma_attrs);
 +
 +      nr_pages = obj->size >> PAGE_SHIFT;
 +
 +      if (!is_drm_iommu_supported(dev)) {
 +              dma_addr_t start_addr;
 +              unsigned int i = 0;
 +
 +              obj->pages = drm_calloc_large(nr_pages, sizeof(struct page *));
 +              if (!obj->pages) {
 +                      DRM_ERROR("failed to allocate pages.\n");
 +                      return -ENOMEM;
 +              }
 +
 +              obj->cookie = dma_alloc_attrs(dev->dev,
 +                                      obj->size,
 +                                      &obj->dma_addr, GFP_KERNEL,
 +                                      &obj->dma_attrs);
 +              if (!obj->cookie) {
 +                      DRM_ERROR("failed to allocate buffer.\n");
 +                      drm_free_large(obj->pages);
 +                      return -ENOMEM;
 +              }
 +
 +              start_addr = obj->dma_addr;
 +              while (i < nr_pages) {
 +                      obj->pages[i] = phys_to_page(start_addr);
 +                      start_addr += PAGE_SIZE;
 +                      i++;
 +              }
 +      } else {
 +              obj->pages = dma_alloc_attrs(dev->dev, obj->size,
 +                                      &obj->dma_addr, GFP_KERNEL,
 +                                      &obj->dma_attrs);
 +              if (!obj->pages) {
 +                      DRM_ERROR("failed to allocate buffer.\n");
 +                      return -ENOMEM;
 +              }
 +      }
  
 -static unsigned long roundup_gem_size(unsigned long size, unsigned int flags)
 -{
 -      /* TODO */
 +      DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
 +                      (unsigned long)obj->dma_addr,
 +                      obj->size);
  
 -      return roundup(size, PAGE_SIZE);
 +      return 0;
  }
  
 -static int exynos_drm_gem_map_buf(struct drm_gem_object *obj,
 -                                      struct vm_area_struct *vma,
 -                                      unsigned long f_vaddr,
 -                                      pgoff_t page_offset)
 +static void exynos_drm_free_buf(struct exynos_drm_gem_obj *obj)
  {
 -      struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
 -      struct exynos_drm_gem_buf *buf = exynos_gem_obj->buffer;
 -      struct scatterlist *sgl;
 -      unsigned long pfn;
 -      int i;
 -
 -      if (!buf->sgt)
 -              return -EINTR;
 +      struct drm_device *dev = obj->base.dev;
  
 -      if (page_offset >= (buf->size >> PAGE_SHIFT)) {
 -              DRM_ERROR("invalid page offset\n");
 -              return -EINVAL;
 +      if (!obj->dma_addr) {
 +              DRM_DEBUG_KMS("dma_addr is invalid.\n");
 +              return;
        }
  
 -      sgl = buf->sgt->sgl;
 -      for_each_sg(buf->sgt->sgl, sgl, buf->sgt->nents, i) {
 -              if (page_offset < (sgl->length >> PAGE_SHIFT))
 -                      break;
 -              page_offset -=  (sgl->length >> PAGE_SHIFT);
 -      }
 +      DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
 +                      (unsigned long)obj->dma_addr, obj->size);
  
 -      pfn = __phys_to_pfn(sg_phys(sgl)) + page_offset;
 +      if (!is_drm_iommu_supported(dev)) {
 +              dma_free_attrs(dev->dev, obj->size, obj->cookie,
 +                              (dma_addr_t)obj->dma_addr, &obj->dma_attrs);
 +              drm_free_large(obj->pages);
 +      } else
 +              dma_free_attrs(dev->dev, obj->size, obj->pages,
 +                              (dma_addr_t)obj->dma_addr, &obj->dma_attrs);
  
 -      return vm_insert_mixed(vma, f_vaddr, pfn);
 +      obj->dma_addr = (dma_addr_t)NULL;
  }
  
  static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
  
  void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
  {
 -      struct drm_gem_object *obj;
 -      struct exynos_drm_gem_buf *buf;
 -
 -      obj = &exynos_gem_obj->base;
 -      buf = exynos_gem_obj->buffer;
 +      struct drm_gem_object *obj = &exynos_gem_obj->base;
  
        DRM_DEBUG_KMS("handle count = %d\n", obj->handle_count);
  
        if (obj->import_attach)
                goto out;
  
 -      exynos_drm_free_buf(obj->dev, exynos_gem_obj->flags, buf);
 +      exynos_drm_free_buf(exynos_gem_obj);
  
  out:
 -      exynos_drm_fini_buf(obj->dev, buf);
 -      exynos_gem_obj->buffer = NULL;
 -
        drm_gem_free_mmap_offset(obj);
  
        /* release file pointer to gem object. */
@@@ -187,7 -180,7 +187,7 @@@ unsigned long exynos_drm_gem_get_size(s
  
        drm_gem_object_unreference_unlocked(obj);
  
 -      return exynos_gem_obj->buffer->size;
 +      return exynos_gem_obj->size;
  }
  
  
@@@ -200,7 -193,7 +200,7 @@@ struct exynos_drm_gem_obj *exynos_drm_g
  
        exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL);
        if (!exynos_gem_obj)
 -              return NULL;
 +              return ERR_PTR(-ENOMEM);
  
        exynos_gem_obj->size = size;
        obj = &exynos_gem_obj->base;
        if (ret < 0) {
                DRM_ERROR("failed to initialize gem object\n");
                kfree(exynos_gem_obj);
 -              return NULL;
 +              return ERR_PTR(ret);
        }
  
        DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp);
@@@ -222,35 -215,47 +222,35 @@@ struct exynos_drm_gem_obj *exynos_drm_g
                                                unsigned long size)
  {
        struct exynos_drm_gem_obj *exynos_gem_obj;
 -      struct exynos_drm_gem_buf *buf;
        int ret;
  
 +      if (flags & ~(EXYNOS_BO_MASK)) {
 +              DRM_ERROR("invalid flags.\n");
 +              return ERR_PTR(-EINVAL);
 +      }
 +
        if (!size) {
                DRM_ERROR("invalid size.\n");
                return ERR_PTR(-EINVAL);
        }
  
 -      size = roundup_gem_size(size, flags);
 -
 -      ret = check_gem_flags(flags);
 -      if (ret)
 -              return ERR_PTR(ret);
 -
 -      buf = exynos_drm_init_buf(dev, size);
 -      if (!buf)
 -              return ERR_PTR(-ENOMEM);
 +      size = roundup(size, PAGE_SIZE);
  
        exynos_gem_obj = exynos_drm_gem_init(dev, size);
 -      if (!exynos_gem_obj) {
 -              ret = -ENOMEM;
 -              goto err_fini_buf;
 -      }
 -
 -      exynos_gem_obj->buffer = buf;
 +      if (IS_ERR(exynos_gem_obj))
 +              return exynos_gem_obj;
  
        /* set memory type and cache attribute from user side. */
        exynos_gem_obj->flags = flags;
  
 -      ret = exynos_drm_alloc_buf(dev, buf, flags);
 -      if (ret < 0)
 -              goto err_gem_fini;
 +      ret = exynos_drm_alloc_buf(exynos_gem_obj);
 +      if (ret < 0) {
 +              drm_gem_object_release(&exynos_gem_obj->base);
 +              kfree(exynos_gem_obj);
 +              return ERR_PTR(ret);
 +      }
  
        return exynos_gem_obj;
 -
 -err_gem_fini:
 -      drm_gem_object_release(&exynos_gem_obj->base);
 -      kfree(exynos_gem_obj);
 -err_fini_buf:
 -      exynos_drm_fini_buf(dev, buf);
 -      return ERR_PTR(ret);
  }
  
  int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
@@@ -289,7 -294,7 +289,7 @@@ dma_addr_t *exynos_drm_gem_get_dma_addr
  
        exynos_gem_obj = to_exynos_gem_obj(obj);
  
 -      return &exynos_gem_obj->buffer->dma_addr;
 +      return &exynos_gem_obj->dma_addr;
  }
  
  void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
@@@ -317,6 -322,7 +317,6 @@@ int exynos_drm_gem_mmap_buffer(struct e
                                      struct vm_area_struct *vma)
  {
        struct drm_device *drm_dev = exynos_gem_obj->base.dev;
 -      struct exynos_drm_gem_buf *buffer;
        unsigned long vm_size;
        int ret;
  
  
        vm_size = vma->vm_end - vma->vm_start;
  
 -      /*
 -       * a buffer contains information to physically continuous memory
 -       * allocated by user request or at framebuffer creation.
 -       */
 -      buffer = exynos_gem_obj->buffer;
 -
        /* check if user-requested size is valid. */
 -      if (vm_size > buffer->size)
 +      if (vm_size > exynos_gem_obj->size)
                return -EINVAL;
  
 -      ret = dma_mmap_attrs(drm_dev->dev, vma, buffer->pages,
 -                              buffer->dma_addr, buffer->size,
 -                              &buffer->dma_attrs);
 +      ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem_obj->pages,
 +                              exynos_gem_obj->dma_addr, exynos_gem_obj->size,
 +                              &exynos_gem_obj->dma_attrs);
        if (ret < 0) {
                DRM_ERROR("failed to mmap.\n");
                return ret;
@@@ -366,103 -378,6 +366,6 @@@ int exynos_drm_gem_get_ioctl(struct drm
        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)
@@@ -491,6 -406,15 +394,6 @@@ void exynos_gem_unmap_sgt_from_dma(stru
  
  void exynos_drm_gem_free_object(struct drm_gem_object *obj)
  {
 -      struct exynos_drm_gem_obj *exynos_gem_obj;
 -      struct exynos_drm_gem_buf *buf;
 -
 -      exynos_gem_obj = to_exynos_gem_obj(obj);
 -      buf = exynos_gem_obj->buffer;
 -
 -      if (obj->import_attach)
 -              drm_prime_gem_destroy(obj, buf->sgt);
 -
        exynos_drm_gem_destroy(to_exynos_gem_obj(obj));
  }
  
@@@ -574,34 -498,24 +477,34 @@@ unlock
  int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
  {
        struct drm_gem_object *obj = vma->vm_private_data;
 -      struct drm_device *dev = obj->dev;
 -      unsigned long f_vaddr;
 +      struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
 +      unsigned long pfn;
        pgoff_t page_offset;
        int ret;
  
        page_offset = ((unsigned long)vmf->virtual_address -
                        vma->vm_start) >> PAGE_SHIFT;
 -      f_vaddr = (unsigned long)vmf->virtual_address;
  
 -      mutex_lock(&dev->struct_mutex);
 +      if (page_offset >= (exynos_gem_obj->size >> PAGE_SHIFT)) {
 +              DRM_ERROR("invalid page offset\n");
 +              ret = -EINVAL;
 +              goto out;
 +      }
  
 -      ret = exynos_drm_gem_map_buf(obj, vma, f_vaddr, page_offset);
 -      if (ret < 0)
 -              DRM_ERROR("failed to map a buffer with user.\n");
 +      pfn = page_to_pfn(exynos_gem_obj->pages[page_offset]);
 +      ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
  
 -      mutex_unlock(&dev->struct_mutex);
 -
 -      return convert_to_vm_err_msg(ret);
 +out:
 +      switch (ret) {
 +      case 0:
 +      case -ERESTARTSYS:
 +      case -EINTR:
 +              return VM_FAULT_NOPAGE;
 +      case -ENOMEM:
 +              return VM_FAULT_OOM;
 +      default:
 +              return VM_FAULT_SIGBUS;
 +      }
  }
  
  int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
        obj = vma->vm_private_data;
        exynos_gem_obj = to_exynos_gem_obj(obj);
  
 -      ret = check_gem_flags(exynos_gem_obj->flags);
 -      if (ret)
 -              goto err_close_vm;
 +      DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem_obj->flags);
  
 -      update_vm_cache_attr(exynos_gem_obj, vma);
 +      /* non-cachable as default. */
 +      if (exynos_gem_obj->flags & EXYNOS_BO_CACHABLE)
 +              vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
 +      else if (exynos_gem_obj->flags & EXYNOS_BO_WC)
 +              vma->vm_page_prot =
 +                      pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
 +      else
 +              vma->vm_page_prot =
 +                      pgprot_noncached(vm_get_page_prot(vma->vm_flags));
  
        ret = exynos_drm_gem_mmap_buffer(exynos_gem_obj, vma);
        if (ret)
@@@ -644,76 -552,3 +547,76 @@@ err_close_vm
  
        return ret;
  }
 +
 +/* low-level interface prime helpers */
 +struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj)
 +{
 +      struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
 +      int npages;
 +
 +      npages = exynos_gem_obj->size >> PAGE_SHIFT;
 +
 +      return drm_prime_pages_to_sg(exynos_gem_obj->pages, npages);
 +}
 +
 +struct drm_gem_object *
 +exynos_drm_gem_prime_import_sg_table(struct drm_device *dev,
 +                                   struct dma_buf_attachment *attach,
 +                                   struct sg_table *sgt)
 +{
 +      struct exynos_drm_gem_obj *exynos_gem_obj;
 +      int npages;
 +      int ret;
 +
 +      exynos_gem_obj = exynos_drm_gem_init(dev, attach->dmabuf->size);
 +      if (IS_ERR(exynos_gem_obj)) {
 +              ret = PTR_ERR(exynos_gem_obj);
 +              return ERR_PTR(ret);
 +      }
 +
 +      exynos_gem_obj->dma_addr = sg_dma_address(sgt->sgl);
 +
 +      npages = exynos_gem_obj->size >> PAGE_SHIFT;
 +      exynos_gem_obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
 +      if (!exynos_gem_obj->pages) {
 +              ret = -ENOMEM;
 +              goto err;
 +      }
 +
 +      ret = drm_prime_sg_to_page_addr_arrays(sgt, exynos_gem_obj->pages, NULL,
 +                      npages);
 +      if (ret < 0)
 +              goto err_free_large;
 +
 +      if (sgt->nents == 1) {
 +              /* always physically continuous memory if sgt->nents is 1. */
 +              exynos_gem_obj->flags |= EXYNOS_BO_CONTIG;
 +      } else {
 +              /*
 +               * this case could be CONTIG or NONCONTIG type but for now
 +               * sets NONCONTIG.
 +               * TODO. we have to find a way that exporter can notify
 +               * the type of its own buffer to importer.
 +               */
 +              exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG;
 +      }
 +
 +      return &exynos_gem_obj->base;
 +
 +err_free_large:
 +      drm_free_large(exynos_gem_obj->pages);
 +err:
 +      drm_gem_object_release(&exynos_gem_obj->base);
 +      kfree(exynos_gem_obj);
 +      return ERR_PTR(ret);
 +}
 +
 +void *exynos_drm_gem_prime_vmap(struct drm_gem_object *obj)
 +{
 +      return NULL;
 +}
 +
 +void exynos_drm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
 +{
 +      /* Nothing to do */
 +}
index de2474e1132de486ae73f5581555f814a299b390,7feb6394f11139fc8e388623f7cb5e1d419d566e..70c28d19ea04c8a7cfa452a6c68d0452094d6fcb
@@@ -195,46 -195,34 +195,34 @@@ static int omap_vout_try_format(struct 
  }
  
  /*
-  * 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(&current->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(&current->mm->mmap_sem);
-       } else {
-               /* otherwise, use get_user_pages() for general userland pages */
-               int res, nr_pages = 1;
-               struct page *pages;
-               res = get_user_pages(current, current->mm, virtp, nr_pages, 1,
-                               0, &pages, NULL);
-               up_read(&current->mm->mmap_sem);
-               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;
-               }
+       if (virtp >= PAGE_OFFSET) {
+               *physp = virt_to_phys((void *)virtp);
+               return 0;
+       }
+       vec = frame_vector_create(1);
+       if (!vec)
+               return -ENOMEM;
+       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 +772,15 @@@ static int omap_vout_buffer_prepare(str
         * 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;
@@@ -834,12 -826,13 +826,13 @@@ static void omap_vout_buffer_queue(stru
  static void omap_vout_buffer_release(struct videobuf_queue *q,
                            struct videobuf_buffer *vb)
  {
-       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);
+       }
  }
  
  /*
@@@ -872,7 -865,7 +865,7 @@@ static void omap_vout_vm_close(struct v
        vout->mmap_count--;
  }
  
 -static struct vm_operations_struct omap_vout_vm_ops = {
 +static const struct vm_operations_struct omap_vout_vm_ops = {
        .open   = omap_vout_vm_open,
        .close  = omap_vout_vm_close,
  };
index f1022d810d2208f92057b3cf25eddabd5973aa90,243b28d073738daf605d75473eb57a4eddaf623b..4f59b7ec05d0fe7261312082d7ee2c2e17453b53
@@@ -717,7 -717,6 +717,7 @@@ static void __fill_v4l2_buffer(struct v
                break;
        case VB2_BUF_STATE_PREPARING:
        case VB2_BUF_STATE_DEQUEUED:
 +      case VB2_BUF_STATE_REQUEUEING:
                /* nothing */
                break;
        }
@@@ -1185,8 -1184,7 +1185,8 @@@ void vb2_buffer_done(struct vb2_buffer 
  
        if (WARN_ON(state != VB2_BUF_STATE_DONE &&
                    state != VB2_BUF_STATE_ERROR &&
 -                  state != VB2_BUF_STATE_QUEUED))
 +                  state != VB2_BUF_STATE_QUEUED &&
 +                  state != VB2_BUF_STATE_REQUEUEING))
                state = VB2_BUF_STATE_ERROR;
  
  #ifdef CONFIG_VIDEO_ADV_DEBUG
        for (plane = 0; plane < vb->num_planes; ++plane)
                call_void_memop(vb, finish, vb->planes[plane].mem_priv);
  
 -      /* Add the buffer to the done buffers list */
        spin_lock_irqsave(&q->done_lock, flags);
 -      vb->state = state;
 -      if (state != VB2_BUF_STATE_QUEUED)
 +      if (state == VB2_BUF_STATE_QUEUED ||
 +          state == VB2_BUF_STATE_REQUEUEING) {
 +              vb->state = VB2_BUF_STATE_QUEUED;
 +      } else {
 +              /* Add the buffer to the done buffers list */
                list_add_tail(&vb->done_entry, &q->done_list);
 +              vb->state = state;
 +      }
        atomic_dec(&q->owned_by_drv_count);
        spin_unlock_irqrestore(&q->done_lock, flags);
  
        trace_vb2_buf_done(q, vb);
  
 -      if (state == VB2_BUF_STATE_QUEUED) {
 +      switch (state) {
 +      case VB2_BUF_STATE_QUEUED:
 +              return;
 +      case VB2_BUF_STATE_REQUEUEING:
                if (q->start_streaming_called)
                        __enqueue_in_driver(vb);
                return;
 +      default:
 +              /* Inform any processes that may be waiting for buffers */
 +              wake_up(&q->done_wq);
 +              break;
        }
 -
 -      /* Inform any processes that may be waiting for buffers */
 -      wake_up(&q->done_wq);
  }
  EXPORT_SYMBOL_GPL(vb2_buffer_done);
  
@@@ -1258,19 -1248,19 +1258,19 @@@ EXPORT_SYMBOL_GPL(vb2_discard_done)
  
  static void vb2_warn_zero_bytesused(struct vb2_buffer *vb)
  {
 -      static bool __check_once __read_mostly;
 +      static bool check_once;
  
 -      if (__check_once)
 +      if (check_once)
                return;
  
 -      __check_once = true;
 -      __WARN();
 +      check_once = true;
 +      WARN_ON(1);
  
 -      pr_warn_once("use of bytesused == 0 is deprecated and will be removed in the future,\n");
 +      pr_warn("use of bytesused == 0 is deprecated and will be removed in the future,\n");
        if (vb->vb2_queue->allow_zero_bytesused)
 -              pr_warn_once("use VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP) instead.\n");
 +              pr_warn("use VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP) instead.\n");
        else
 -              pr_warn_once("use the actual size instead.\n");
 +              pr_warn("use the actual size instead.\n");
  }
  
  /**
@@@ -1691,9 -1681,7 +1691,7 @@@ static int __buf_prepare(struct vb2_buf
                ret = __qbuf_mmap(vb, b);
                break;
        case V4L2_MEMORY_USERPTR:
-               down_read(&current->mm->mmap_sem);
                ret = __qbuf_userptr(vb, b);
-               up_read(&current->mm->mmap_sem);
                break;
        case V4L2_MEMORY_DMABUF:
                ret = __qbuf_dmabuf(vb, b);
diff --combined include/linux/mm.h
index fda728e3c27d000d952bfccc8c0850dcd649aa68,79ad29a8a60a9a6a4ff61bc237e83b843e5e1513..91c08f6f0dc96dbb7474d3349f62b5d3f723fe80
@@@ -20,6 -20,7 +20,7 @@@
  #include <linux/shrinker.h>
  #include <linux/resource.h>
  #include <linux/page_ext.h>
+ #include <linux/err.h>
  
  struct mempolicy;
  struct anon_vma;
@@@ -124,10 -125,8 +125,10 @@@ extern unsigned int kobjsize(const voi
  #define VM_MAYSHARE   0x00000080
  
  #define VM_GROWSDOWN  0x00000100      /* general info on the segment */
 +#define VM_UFFD_MISSING       0x00000200      /* missing pages tracking */
  #define VM_PFNMAP     0x00000400      /* Page-ranges managed without "struct page", just pure PFN */
  #define VM_DENYWRITE  0x00000800      /* ETXTBSY on write attempts.. */
 +#define VM_UFFD_WP    0x00001000      /* wrprotect pages tracking */
  
  #define VM_LOCKED     0x00002000
  #define VM_IO           0x00004000    /* Memory mapped I/O or similar */
@@@ -247,10 -246,7 +248,10 @@@ struct vm_fault 
  struct vm_operations_struct {
        void (*open)(struct vm_area_struct * area);
        void (*close)(struct vm_area_struct * area);
 +      int (*mremap)(struct vm_area_struct * area);
        int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf);
 +      int (*pmd_fault)(struct vm_area_struct *, unsigned long address,
 +                                              pmd_t *, unsigned int flags);
        void (*map_pages)(struct vm_area_struct *vma, struct vm_fault *vmf);
  
        /* notification that a previously read-only page is about to become
@@@ -309,6 -305,18 +310,6 @@@ struct inode
  #define page_private(page)            ((page)->private)
  #define set_page_private(page, v)     ((page)->private = (v))
  
 -/* It's valid only if the page is free path or free_list */
 -static inline void set_freepage_migratetype(struct page *page, int migratetype)
 -{
 -      page->index = migratetype;
 -}
 -
 -/* It's valid only if the page is free path or free_list */
 -static inline int get_freepage_migratetype(struct page *page)
 -{
 -      return page->index;
 -}
 -
  /*
   * FIXME: take this include out, include page-flags.h in
   * files which need it (119 of them)
@@@ -349,15 -357,20 +350,15 @@@ static inline int get_page_unless_zero(
        return atomic_inc_not_zero(&page->_count);
  }
  
 -/*
 - * Try to drop a ref unless the page has a refcount of one, return false if
 - * that is the case.
 - * This is to make sure that the refcount won't become zero after this drop.
 - * This can be called when MMU is off so it must not access
 - * any of the virtual mappings.
 - */
 -static inline int put_page_unless_one(struct page *page)
 -{
 -      return atomic_add_unless(&page->_count, -1, 1);
 -}
 -
  extern int page_is_ram(unsigned long pfn);
 -extern int region_is_ram(resource_size_t phys_addr, unsigned long size);
 +
 +enum {
 +      REGION_INTERSECTS,
 +      REGION_DISJOINT,
 +      REGION_MIXED,
 +};
 +
 +int region_intersects(resource_size_t offset, size_t size, const char *type);
  
  /* Support for virtually mapped pages */
  struct page *vmalloc_to_page(const void *addr);
@@@ -990,34 -1003,6 +991,34 @@@ static inline int page_mapped(struct pa
        return atomic_read(&(page)->_mapcount) >= 0;
  }
  
 +/*
 + * Return true only if the page has been allocated with
 + * ALLOC_NO_WATERMARKS and the low watermark was not
 + * met implying that the system is under some pressure.
 + */
 +static inline bool page_is_pfmemalloc(struct page *page)
 +{
 +      /*
 +       * Page index cannot be this large so this must be
 +       * a pfmemalloc page.
 +       */
 +      return page->index == -1UL;
 +}
 +
 +/*
 + * Only to be called by the page allocator on a freshly allocated
 + * page.
 + */
 +static inline void set_page_pfmemalloc(struct page *page)
 +{
 +      page->index = -1UL;
 +}
 +
 +static inline void clear_page_pfmemalloc(struct page *page)
 +{
 +      page->index = 0;
 +}
 +
  /*
   * Different kinds of faults, as returned by handle_mm_fault().
   * Used to decide whether a process gets delivered SIGBUS or
@@@ -1214,6 -1199,49 +1215,49 @@@ long get_user_pages_unlocked(struct tas
                    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);
@@@ -1245,11 -1273,6 +1289,11 @@@ static inline int vma_growsdown(struct 
        return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN);
  }
  
 +static inline bool vma_is_anonymous(struct vm_area_struct *vma)
 +{
 +      return !vma->vm_ops;
 +}
 +
  static inline int stack_guard_page_start(struct vm_area_struct *vma,
                                             unsigned long addr)
  {
@@@ -1826,7 -1849,7 +1870,7 @@@ extern int vma_adjust(struct vm_area_st
  extern struct vm_area_struct *vma_merge(struct mm_struct *,
        struct vm_area_struct *prev, unsigned long addr, unsigned long end,
        unsigned long vm_flags, struct anon_vma *, struct file *, pgoff_t,
 -      struct mempolicy *);
 +      struct mempolicy *, struct vm_userfaultfd_ctx);
  extern struct anon_vma *find_mergeable_anon_vma(struct vm_area_struct *);
  extern int split_vma(struct mm_struct *,
        struct vm_area_struct *, unsigned long addr, int new_below);
@@@ -1873,19 -1896,11 +1917,19 @@@ extern unsigned long get_unmapped_area(
  
  extern unsigned long mmap_region(struct file *file, unsigned long addr,
        unsigned long len, vm_flags_t vm_flags, unsigned long pgoff);
 -extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
 +extern unsigned long do_mmap(struct file *file, unsigned long addr,
        unsigned long len, unsigned long prot, unsigned long flags,
 -      unsigned long pgoff, unsigned long *populate);
 +      vm_flags_t vm_flags, unsigned long pgoff, unsigned long *populate);
  extern int do_munmap(struct mm_struct *, unsigned long, size_t);
  
 +static inline unsigned long
 +do_mmap_pgoff(struct file *file, unsigned long addr,
 +      unsigned long len, unsigned long prot, unsigned long flags,
 +      unsigned long pgoff, unsigned long *populate)
 +{
 +      return do_mmap(file, addr, len, prot, flags, 0, pgoff, populate);
 +}
 +
  #ifdef CONFIG_MMU
  extern int __mm_populate(unsigned long addr, unsigned long len,
                         int ignore_errors);
@@@ -2184,7 -2199,6 +2228,7 @@@ extern int memory_failure(unsigned lon
  extern void memory_failure_queue(unsigned long pfn, int trapno, int flags);
  extern int unpoison_memory(unsigned long pfn);
  extern int get_hwpoison_page(struct page *page);
 +extern void put_hwpoison_page(struct page *page);
  extern int sysctl_memory_failure_early_kill;
  extern int sysctl_memory_failure_recovery;
  extern void shake_page(struct page *p, int access);
index 9f36641a67810f80a4387b2a706d61318841e2af,830b5239fd8b1e5d300b3a19bad60ade4243f1e1..6513c7ec3116f1722f490fac8abf9d1f39d39ceb
  #define _MEDIA_VIDEOBUF2_MEMOPS_H
  
  #include <media/videobuf2-core.h>
+ #include <linux/mm.h>
  
  /**
 - * vb2_vmarea_handler - common vma refcount tracking handler
 + * struct vb2_vmarea_handler - common vma refcount tracking handler
 + *
   * @refcount: pointer to refcount entry in the buffer
   * @put:      callback to function that decreases buffer refcount
   * @arg:      argument for @put callback
@@@ -31,11 -31,9 +32,9 @@@ 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);
+ void vb2_destroy_framevec(struct frame_vector *vec);
  
  #endif
diff --combined mm/Kconfig
index 6413d027c0b2ea18acb3c9c1a35149ce7af4bd2c,7f146dd32fc5c77a090523c68dc782cd1dae0ae7..0d9fdcd01e479d87a45cb487db54e8c1fff27883
@@@ -299,9 -299,15 +299,9 @@@ config BOUNC
  # On the 'tile' arch, USB OHCI needs the bounce pool since tilegx will often
  # have more than 4GB of memory, but we don't currently use the IOTLB to present
  # a 32-bit address to OHCI.  So we need to use a bounce pool instead.
 -#
 -# We also use the bounce pool to provide stable page writes for jbd.  jbd
 -# initiates buffer writeback without locking the page or setting PG_writeback,
 -# and fixing that behavior (a second time; jbd2 doesn't have this problem) is
 -# a major rework effort.  Instead, use the bounce buffer to snapshot pages
 -# (until jbd goes away).  The only jbd user is ext3.
  config NEED_BOUNCE_POOL
        bool
 -      default y if (TILE && USB_OHCI_HCD) || (BLK_DEV_INTEGRITY && JBD)
 +      default y if TILE && USB_OHCI_HCD
  
  config NR_QUICK
        int
@@@ -649,31 -655,5 +649,34 @@@ config DEFERRED_STRUCT_PAGE_INI
          processes running early in the lifetime of the systemm until kswapd
          finishes the initialisation.
  
 +config IDLE_PAGE_TRACKING
 +      bool "Enable idle page tracking"
 +      depends on SYSFS && MMU
 +      select PAGE_EXTENSION if !64BIT
 +      help
 +        This feature allows to estimate the amount of user pages that have
 +        not been touched during a given period of time. This information can
 +        be useful to tune memory cgroup limits and/or for job placement
 +        within a compute cluster.
 +
 +        See Documentation/vm/idle_page_tracking.txt for more details.
 +
 +config ZONE_DEVICE
 +      bool "Device memory (pmem, etc...) hotplug support" if EXPERT
 +      default !ZONE_DMA
 +      depends on !ZONE_DMA
 +      depends on MEMORY_HOTPLUG
 +      depends on MEMORY_HOTREMOVE
 +      depends on X86_64 #arch_add_memory() comprehends device memory
 +
 +      help
 +        Device memory hotplug support allows for establishing pmem,
 +        or other device driver discovered memory regions, in the
 +        memmap. This allows pfn_to_page() lookups of otherwise
 +        "device-physical" addresses which is needed for using a DAX
 +        mapping in an O_DIRECT operation, among other things.
 +
 +        If FS_DAX is enabled, then say Y.
++
+ config FRAME_VECTOR
+       bool
diff --combined mm/Makefile
index 56f8eed73f1a6f658d90d156b5b4f2ddd0030eae,be5d5c866305170dffc105b36c7fdcd833bac87c..2ed43191fc3bf78f46f111e88fa9d5a01b8c661a
@@@ -78,5 -78,4 +78,6 @@@ obj-$(CONFIG_CMA)     += cma.
  obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o
  obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o
  obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o
 +obj-$(CONFIG_USERFAULTFD) += userfaultfd.o
 +obj-$(CONFIG_IDLE_PAGE_TRACKING) += page_idle.o
+ obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o
This page took 0.048944 seconds and 5 git commands to generate.