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 5cf6140..911bd40 100644 (file)
@@ -442,7 +442,7 @@ i915_gem_shmem_pread(struct drm_device *dev,
 
        for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents,
                         offset >> PAGE_SHIFT) {
-               struct page *page = sg_iter.page;
+               struct page *page = sg_page_iter_page(&sg_iter);
 
                if (remain <= 0)
                        break;
@@ -765,7 +765,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
 
        for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents,
                         offset >> PAGE_SHIFT) {
-               struct page *page = sg_iter.page;
+               struct page *page = sg_page_iter_page(&sg_iter);
                int partial_cacheline_write;
 
                if (remain <= 0)
@@ -1625,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);
 
@@ -1647,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);
@@ -1749,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
@@ -1779,7 +1780,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
        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);
@@ -1802,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))
@@ -1813,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);
@@ -2115,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);
@@ -2709,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);
@@ -2718,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;
 }