lib/scatterlist: sg_page_iter: support sg lists w/o backing pages
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / gpu / drm / i915 / i915_gem.c
index 8413ffc..911bd40 100644 (file)
@@ -411,10 +411,9 @@ i915_gem_shmem_pread(struct drm_device *dev,
        int obj_do_bit17_swizzling, page_do_bit17_swizzling;
        int prefaulted = 0;
        int needs_clflush = 0;
-       struct scatterlist *sg;
-       int i;
+       struct sg_page_iter sg_iter;
 
-       user_data = (char __user *) (uintptr_t) args->data_ptr;
+       user_data = to_user_ptr(args->data_ptr);
        remain = args->size;
 
        obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
@@ -441,11 +440,9 @@ i915_gem_shmem_pread(struct drm_device *dev,
 
        offset = args->offset;
 
-       for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) {
-               struct page *page;
-
-               if (i < offset >> PAGE_SHIFT)
-                       continue;
+       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents,
+                        offset >> PAGE_SHIFT) {
+               struct page *page = sg_page_iter_page(&sg_iter);
 
                if (remain <= 0)
                        break;
@@ -460,7 +457,6 @@ i915_gem_shmem_pread(struct drm_device *dev,
                if ((shmem_page_offset + page_length) > PAGE_SIZE)
                        page_length = PAGE_SIZE - shmem_page_offset;
 
-               page = sg_page(sg);
                page_do_bit17_swizzling = obj_do_bit17_swizzling &&
                        (page_to_phys(page) & (1 << 17)) != 0;
 
@@ -522,7 +518,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
                return 0;
 
        if (!access_ok(VERIFY_WRITE,
-                      (char __user *)(uintptr_t)args->data_ptr,
+                      to_user_ptr(args->data_ptr),
                       args->size))
                return -EFAULT;
 
@@ -613,7 +609,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
        if (ret)
                goto out_unpin;
 
-       user_data = (char __user *) (uintptr_t) args->data_ptr;
+       user_data = to_user_ptr(args->data_ptr);
        remain = args->size;
 
        offset = obj->gtt_offset + args->offset;
@@ -732,10 +728,9 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
        int hit_slowpath = 0;
        int needs_clflush_after = 0;
        int needs_clflush_before = 0;
-       int i;
-       struct scatterlist *sg;
+       struct sg_page_iter sg_iter;
 
-       user_data = (char __user *) (uintptr_t) args->data_ptr;
+       user_data = to_user_ptr(args->data_ptr);
        remain = args->size;
 
        obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
@@ -768,13 +763,11 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
        offset = args->offset;
        obj->dirty = 1;
 
-       for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) {
-               struct page *page;
+       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents,
+                        offset >> PAGE_SHIFT) {
+               struct page *page = sg_page_iter_page(&sg_iter);
                int partial_cacheline_write;
 
-               if (i < offset >> PAGE_SHIFT)
-                       continue;
-
                if (remain <= 0)
                        break;
 
@@ -796,7 +789,6 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
                        ((shmem_page_offset | page_length)
                                & (boot_cpu_data.x86_clflush_size - 1));
 
-               page = sg_page(sg);
                page_do_bit17_swizzling = obj_do_bit17_swizzling &&
                        (page_to_phys(page) & (1 << 17)) != 0;
 
@@ -867,11 +859,11 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
                return 0;
 
        if (!access_ok(VERIFY_READ,
-                      (char __user *)(uintptr_t)args->data_ptr,
+                      to_user_ptr(args->data_ptr),
                       args->size))
                return -EFAULT;
 
-       ret = fault_in_multipages_readable((char __user *)(uintptr_t)args->data_ptr,
+       ret = fault_in_multipages_readable(to_user_ptr(args->data_ptr),
                                           args->size);
        if (ret)
                return -EFAULT;
@@ -1618,7 +1610,7 @@ i915_gem_object_truncate(struct drm_i915_gem_object *obj)
         * To do this we must instruct the shmfs to drop all of its
         * backing pages, *now*.
         */
-       inode = obj->base.filp->f_path.dentry->d_inode;
+       inode = file_inode(obj->base.filp);
        shmem_truncate_range(inode, 0, (loff_t)-1);
 
        obj->madv = __I915_MADV_PURGED;
@@ -1633,9 +1625,8 @@ i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj)
 static void
 i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
 {
-       int page_count = obj->base.size / PAGE_SIZE;
-       struct scatterlist *sg;
-       int ret, i;
+       struct sg_page_iter sg_iter;
+       int ret;
 
        BUG_ON(obj->madv == __I915_MADV_PURGED);
 
@@ -1655,8 +1646,8 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
        if (obj->madv == I915_MADV_DONTNEED)
                obj->dirty = 0;
 
-       for_each_sg(obj->pages->sgl, sg, page_count, i) {
-               struct page *page = sg_page(sg);
+       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
+               struct page *page = sg_page_iter_page(&sg_iter);
 
                if (obj->dirty)
                        set_page_dirty(page);
@@ -1757,7 +1748,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
        struct address_space *mapping;
        struct sg_table *st;
        struct scatterlist *sg;
+       struct sg_page_iter sg_iter;
        struct page *page;
+       unsigned long last_pfn = 0;     /* suppress gcc warning */
        gfp_t gfp;
 
        /* Assert that the object is not currently in any GPU domain. As it
@@ -1783,11 +1776,13 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
         *
         * Fail silently without starting the shrinker
         */
-       mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
+       mapping = file_inode(obj->base.filp)->i_mapping;
        gfp = mapping_gfp_mask(mapping);
        gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD;
        gfp &= ~(__GFP_IO | __GFP_WAIT);
-       for_each_sg(st->sgl, sg, page_count, i) {
+       sg = st->sgl;
+       st->nents = 0;
+       for (i = 0; i < page_count; i++) {
                page = shmem_read_mapping_page_gfp(mapping, i, gfp);
                if (IS_ERR(page)) {
                        i915_gem_purge(dev_priv, page_count);
@@ -1810,9 +1805,18 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
                        gfp &= ~(__GFP_IO | __GFP_WAIT);
                }
 
-               sg_set_page(sg, page, PAGE_SIZE, 0);
+               if (!i || page_to_pfn(page) != last_pfn + 1) {
+                       if (i)
+                               sg = sg_next(sg);
+                       st->nents++;
+                       sg_set_page(sg, page, PAGE_SIZE, 0);
+               } else {
+                       sg->length += PAGE_SIZE;
+               }
+               last_pfn = page_to_pfn(page);
        }
 
+       sg_mark_end(sg);
        obj->pages = st;
 
        if (i915_gem_object_needs_bit17_swizzle(obj))
@@ -1821,8 +1825,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
        return 0;
 
 err_pages:
-       for_each_sg(st->sgl, sg, i, page_count)
-               page_cache_release(sg_page(sg));
+       sg_mark_end(sg);
+       for_each_sg_page(st->sgl, &sg_iter, st->nents, 0)
+               page_cache_release(sg_page_iter_page(&sg_iter));
        sg_free_table(st);
        kfree(st);
        return PTR_ERR(page);
@@ -2123,11 +2128,11 @@ static void i915_gem_reset_fences(struct drm_device *dev)
        for (i = 0; i < dev_priv->num_fence_regs; i++) {
                struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i];
 
-               i915_gem_write_fence(dev, i, NULL);
-
                if (reg->obj)
                        i915_gem_object_fence_lost(reg->obj);
 
+               i915_gem_write_fence(dev, i, NULL);
+
                reg->pin_count = 0;
                reg->obj = NULL;
                INIT_LIST_HEAD(&reg->lru_list);
@@ -2717,6 +2722,7 @@ int
 i915_gem_object_put_fence(struct drm_i915_gem_object *obj)
 {
        struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+       struct drm_i915_fence_reg *fence;
        int ret;
 
        ret = i915_gem_object_wait_fence(obj);
@@ -2726,10 +2732,10 @@ i915_gem_object_put_fence(struct drm_i915_gem_object *obj)
        if (obj->fence_reg == I915_FENCE_REG_NONE)
                return 0;
 
-       i915_gem_object_update_fence(obj,
-                                    &dev_priv->fence_regs[obj->fence_reg],
-                                    false);
+       fence = &dev_priv->fence_regs[obj->fence_reg];
+
        i915_gem_object_fence_lost(obj);
+       i915_gem_object_update_fence(obj, fence, false);
 
        return 0;
 }
@@ -3747,7 +3753,7 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
                mask |= __GFP_DMA32;
        }
 
-       mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
+       mapping = file_inode(obj->base.filp)->i_mapping;
        mapping_set_gfp_mask(mapping, mask);
 
        i915_gem_object_init(obj, &i915_gem_object_ops);
@@ -4010,7 +4016,16 @@ int i915_gem_init(struct drm_device *dev)
        int ret;
 
        mutex_lock(&dev->struct_mutex);
+
+       if (IS_VALLEYVIEW(dev)) {
+               /* VLVA0 (potential hack), BIOS isn't actually waking us */
+               I915_WRITE(VLV_GTLC_WAKE_CTRL, 1);
+               if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) & 1) == 1, 10))
+                       DRM_DEBUG_DRIVER("allow wake ack timed out\n");
+       }
+
        i915_gem_init_global_gtt(dev);
+
        ret = i915_gem_init_hw(dev);
        mutex_unlock(&dev->struct_mutex);
        if (ret) {
@@ -4232,7 +4247,7 @@ void i915_gem_free_all_phys_object(struct drm_device *dev)
 void i915_gem_detach_phys_object(struct drm_device *dev,
                                 struct drm_i915_gem_object *obj)
 {
-       struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
+       struct address_space *mapping = file_inode(obj->base.filp)->i_mapping;
        char *vaddr;
        int i;
        int page_count;
@@ -4268,7 +4283,7 @@ i915_gem_attach_phys_object(struct drm_device *dev,
                            int id,
                            int align)
 {
-       struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
+       struct address_space *mapping = file_inode(obj->base.filp)->i_mapping;
        drm_i915_private_t *dev_priv = dev->dev_private;
        int ret = 0;
        int page_count;
@@ -4327,7 +4342,7 @@ i915_gem_phys_pwrite(struct drm_device *dev,
                     struct drm_file *file_priv)
 {
        void *vaddr = obj->phys_obj->handle->vaddr + args->offset;
-       char __user *user_data = (char __user *) (uintptr_t) args->data_ptr;
+       char __user *user_data = to_user_ptr(args->data_ptr);
 
        if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) {
                unsigned long unwritten;