Merge tag 'drm-next-2018-10-24' of git://anongit.freedesktop.org/drm/drm
[platform/kernel/linux-starfive.git] / drivers / gpu / drm / i915 / i915_gem.c
index fcc73a6..0c8aa57 100644 (file)
@@ -802,6 +802,11 @@ void i915_gem_flush_ggtt_writes(struct drm_i915_private *dev_priv)
         * that was!).
         */
 
+       wmb();
+
+       if (INTEL_INFO(dev_priv)->has_coherent_ggtt)
+               return;
+
        i915_gem_chipset_flush(dev_priv);
 
        intel_runtime_pm_get(dev_priv);
@@ -1122,11 +1127,7 @@ i915_gem_shmem_pread(struct drm_i915_gem_object *obj,
        offset = offset_in_page(args->offset);
        for (idx = args->offset >> PAGE_SHIFT; remain; idx++) {
                struct page *page = i915_gem_object_get_page(obj, idx);
-               int length;
-
-               length = remain;
-               if (offset + length > PAGE_SIZE)
-                       length = PAGE_SIZE - offset;
+               unsigned int length = min_t(u64, remain, PAGE_SIZE - offset);
 
                ret = shmem_pread(page, offset, length, user_data,
                                  page_to_phys(page) & obj_do_bit17_swizzling,
@@ -1570,11 +1571,7 @@ i915_gem_shmem_pwrite(struct drm_i915_gem_object *obj,
        offset = offset_in_page(args->offset);
        for (idx = args->offset >> PAGE_SHIFT; remain; idx++) {
                struct page *page = i915_gem_object_get_page(obj, idx);
-               int length;
-
-               length = remain;
-               if (offset + length > PAGE_SIZE)
-                       length = PAGE_SIZE - offset;
+               unsigned int length = min_t(u64, remain, PAGE_SIZE - offset);
 
                ret = shmem_pwrite(page, offset, length, user_data,
                                   page_to_phys(page) & obj_do_bit17_swizzling,
@@ -1906,7 +1903,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
        return 0;
 }
 
-static unsigned int tile_row_pages(struct drm_i915_gem_object *obj)
+static unsigned int tile_row_pages(const struct drm_i915_gem_object *obj)
 {
        return i915_gem_object_get_tile_row_size(obj) >> PAGE_SHIFT;
 }
@@ -1965,7 +1962,7 @@ int i915_gem_mmap_gtt_version(void)
 }
 
 static inline struct i915_ggtt_view
-compute_partial_view(struct drm_i915_gem_object *obj,
+compute_partial_view(const struct drm_i915_gem_object *obj,
                     pgoff_t page_offset,
                     unsigned int chunk)
 {
@@ -2013,7 +2010,7 @@ vm_fault_t i915_gem_fault(struct vm_fault *vmf)
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       bool write = !!(vmf->flags & FAULT_FLAG_WRITE);
+       bool write = area->vm_flags & VM_WRITE;
        struct i915_vma *vma;
        pgoff_t page_offset;
        int ret;
@@ -2501,7 +2498,9 @@ static bool i915_sg_trim(struct sg_table *orig_st)
        new_sg = new_st.sgl;
        for_each_sg(orig_st->sgl, sg, orig_st->nents, i) {
                sg_set_page(new_sg, sg_page(sg), sg->length, 0);
-               /* called before being DMA mapped, no need to copy sg->dma_* */
+               sg_dma_address(new_sg) = sg_dma_address(sg);
+               sg_dma_len(new_sg) = sg_dma_len(sg);
+
                new_sg = sg_next(new_sg);
        }
        GEM_BUG_ON(new_sg); /* Should walk exactly nents and hit the end */
@@ -2528,13 +2527,21 @@ static int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
        gfp_t noreclaim;
        int ret;
 
-       /* Assert that the object is not currently in any GPU domain. As it
+       /*
+        * Assert that the object is not currently in any GPU domain. As it
         * wasn't in the GTT, there shouldn't be any way it could have been in
         * a GPU cache
         */
        GEM_BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS);
        GEM_BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS);
 
+       /*
+        * If there's no chance of allocating enough pages for the whole
+        * object, bail early.
+        */
+       if (page_count > totalram_pages)
+               return -ENOMEM;
+
        st = kmalloc(sizeof(*st), GFP_KERNEL);
        if (st == NULL)
                return -ENOMEM;
@@ -2545,7 +2552,8 @@ rebuild_st:
                return -ENOMEM;
        }
 
-       /* Get the list of pages out of our struct file.  They'll be pinned
+       /*
+        * Get the list of pages out of our struct file.  They'll be pinned
         * at this point until we release them.
         *
         * Fail silently without starting the shrinker
@@ -2577,7 +2585,8 @@ rebuild_st:
                        i915_gem_shrink(dev_priv, 2 * page_count, NULL, *s++);
                        cond_resched();
 
-                       /* We've tried hard to allocate the memory by reaping
+                       /*
+                        * We've tried hard to allocate the memory by reaping
                         * our own buffer, now let the real VM do its job and
                         * go down in flames if truly OOM.
                         *
@@ -2589,7 +2598,8 @@ rebuild_st:
                                /* reclaim and warn, but no oom */
                                gfp = mapping_gfp_mask(mapping);
 
-                               /* Our bo are always dirty and so we require
+                               /*
+                                * Our bo are always dirty and so we require
                                 * kswapd to reclaim our pages (direct reclaim
                                 * does not effectively begin pageout of our
                                 * buffers on its own). However, direct reclaim
@@ -2633,7 +2643,8 @@ rebuild_st:
 
        ret = i915_gem_gtt_prepare_pages(obj, st);
        if (ret) {
-               /* DMA remapping failed? One possible cause is that
+               /*
+                * DMA remapping failed? One possible cause is that
                 * it could not reserve enough large entries, asking
                 * for PAGE_SIZE chunks instead may be helpful.
                 */
@@ -2667,7 +2678,8 @@ err_pages:
        sg_free_table(st);
        kfree(st);
 
-       /* shmemfs first checks if there is enough memory to allocate the page
+       /*
+        * shmemfs first checks if there is enough memory to allocate the page
         * and reports ENOSPC should there be insufficient, along with the usual
         * ENOMEM for a genuine allocation failure.
         *
@@ -3307,8 +3319,8 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
                        intel_engine_dump(engine, &p, "%s\n", engine->name);
        }
 
-       set_bit(I915_WEDGED, &i915->gpu_error.flags);
-       smp_mb__after_atomic();
+       if (test_and_set_bit(I915_WEDGED, &i915->gpu_error.flags))
+               goto out;
 
        /*
         * First, stop submission to hw, but do not yet complete requests by
@@ -3324,7 +3336,8 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
        i915->caps.scheduler = 0;
 
        /* Even if the GPU reset fails, it should still stop the engines */
-       intel_gpu_reset(i915, ALL_ENGINES);
+       if (INTEL_GEN(i915) >= 5)
+               intel_gpu_reset(i915, ALL_ENGINES);
 
        /*
         * Make sure no one is running the old callback before we proceed with
@@ -3367,6 +3380,7 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
                i915_gem_reset_finish_engine(engine);
        }
 
+out:
        GEM_TRACE("end\n");
 
        wake_up_all(&i915->gpu_error.reset_queue);
@@ -3418,6 +3432,9 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915)
        i915_retire_requests(i915);
        GEM_BUG_ON(i915->gt.active_requests);
 
+       if (!intel_gpu_reset(i915, ALL_ENGINES))
+               intel_engines_sanitize(i915);
+
        /*
         * Undo nop_submit_request. We prevent all new i915 requests from
         * being queued (by disallowing execbuf whilst wedged) so having
@@ -3816,6 +3833,12 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915,
                        if (timeout < 0)
                                return timeout;
                }
+               if (GEM_SHOW_DEBUG() && !timeout) {
+                       /* Presume that timeout was non-zero to begin with! */
+                       dev_warn(&i915->drm.pdev->dev,
+                                "Missed idle-completion interrupt!\n");
+                       GEM_TRACE_DUMP();
+               }
 
                err = wait_for_engines(i915);
                if (err)
@@ -5388,8 +5411,19 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915)
 
        assert_kernel_context_is_current(i915);
 
+       /*
+        * Immediately park the GPU so that we enable powersaving and
+        * treat it as idle. The next time we issue a request, we will
+        * unpark and start using the engine->pinned_default_state, otherwise
+        * it is in limbo and an early reset may fail.
+        */
+       __i915_gem_park(i915);
+
        for_each_engine(engine, i915, id) {
                struct i915_vma *state;
+               void *vaddr;
+
+               GEM_BUG_ON(to_intel_context(ctx, engine)->pin_count);
 
                state = to_intel_context(ctx, engine)->state;
                if (!state)
@@ -5412,6 +5446,16 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915)
                        goto err_active;
 
                engine->default_state = i915_gem_object_get(state->obj);
+
+               /* Check we can acquire the image of the context state */
+               vaddr = i915_gem_object_pin_map(engine->default_state,
+                                               I915_MAP_FORCE_WB);
+               if (IS_ERR(vaddr)) {
+                       err = PTR_ERR(vaddr);
+                       goto err_active;
+               }
+
+               i915_gem_object_unpin_map(engine->default_state);
        }
 
        if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) {
@@ -5592,6 +5636,8 @@ err_uc_misc:
                i915_gem_cleanup_userptr(dev_priv);
 
        if (ret == -EIO) {
+               mutex_lock(&dev_priv->drm.struct_mutex);
+
                /*
                 * Allow engine initialisation to fail by marking the GPU as
                 * wedged. But we only want to do this where the GPU is angry,
@@ -5602,7 +5648,14 @@ err_uc_misc:
                                        "Failed to initialize GPU, declaring it wedged!\n");
                        i915_gem_set_wedged(dev_priv);
                }
-               ret = 0;
+
+               /* Minimal basic recovery for KMS */
+               ret = i915_ggtt_enable_hw(dev_priv);
+               i915_gem_restore_gtt_mappings(dev_priv);
+               i915_gem_restore_fences(dev_priv);
+               intel_init_clock_gating(dev_priv);
+
+               mutex_unlock(&dev_priv->drm.struct_mutex);
        }
 
        i915_gem_drain_freed_objects(dev_priv);
@@ -5612,6 +5665,7 @@ err_uc_misc:
 void i915_gem_fini(struct drm_i915_private *dev_priv)
 {
        i915_gem_suspend_late(dev_priv);
+       intel_disable_gt_powersave(dev_priv);
 
        /* Flush any outstanding unpin_work. */
        i915_gem_drain_workqueue(dev_priv);
@@ -5623,6 +5677,8 @@ void i915_gem_fini(struct drm_i915_private *dev_priv)
        i915_gem_contexts_fini(dev_priv);
        mutex_unlock(&dev_priv->drm.struct_mutex);
 
+       intel_cleanup_gt_powersave(dev_priv);
+
        intel_uc_fini_misc(dev_priv);
        i915_gem_cleanup_userptr(dev_priv);
 
@@ -5996,7 +6052,8 @@ i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
        count = __sg_page_count(sg);
 
        while (idx + count <= n) {
-               unsigned long exception, i;
+               void *entry;
+               unsigned long i;
                int ret;
 
                /* If we cannot allocate and insert this entry, or the
@@ -6011,12 +6068,9 @@ i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
                if (ret && ret != -EEXIST)
                        goto scan;
 
-               exception =
-                       RADIX_TREE_EXCEPTIONAL_ENTRY |
-                       idx << RADIX_TREE_EXCEPTIONAL_SHIFT;
+               entry = xa_mk_value(idx);
                for (i = 1; i < count; i++) {
-                       ret = radix_tree_insert(&iter->radix, idx + i,
-                                               (void *)exception);
+                       ret = radix_tree_insert(&iter->radix, idx + i, entry);
                        if (ret && ret != -EEXIST)
                                goto scan;
                }
@@ -6054,15 +6108,14 @@ lookup:
        GEM_BUG_ON(!sg);
 
        /* If this index is in the middle of multi-page sg entry,
-        * the radixtree will contain an exceptional entry that points
+        * the radix tree will contain a value entry that points
         * to the start of that range. We will return the pointer to
         * the base page and the offset of this page within the
         * sg entry's range.
         */
        *offset = 0;
-       if (unlikely(radix_tree_exception(sg))) {
-               unsigned long base =
-                       (unsigned long)sg >> RADIX_TREE_EXCEPTIONAL_SHIFT;
+       if (unlikely(xa_is_value(sg))) {
+               unsigned long base = xa_to_value(sg);
 
                sg = radix_tree_lookup(&iter->radix, base);
                GEM_BUG_ON(!sg);
@@ -6182,4 +6235,5 @@ err_unlock:
 #include "selftests/huge_pages.c"
 #include "selftests/i915_gem_object.c"
 #include "selftests/i915_gem_coherency.c"
+#include "selftests/i915_gem.c"
 #endif