Merge tag 'drm-intel-gt-next-2023-04-06' of git://anongit.freedesktop.org/drm/drm...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / i915 / gem / i915_gem_ttm_move.c
index 6e3de0f33add9bd21b766a0384f74c5be6ff0b30..dd188dfcc423e463f5d275299300ffd5bb623002 100644 (file)
@@ -103,7 +103,27 @@ void i915_ttm_adjust_gem_after_move(struct drm_i915_gem_object *obj)
 {
        struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
        unsigned int cache_level;
+       unsigned int mem_flags;
        unsigned int i;
+       int mem_type;
+
+       /*
+        * We might have been purged (or swapped out) if the resource is NULL,
+        * in which case the SYSTEM placement is the closest match to describe
+        * the current domain. If the object is ever used in this state then we
+        * will require moving it again.
+        */
+       if (!bo->resource) {
+               mem_flags = I915_BO_FLAG_STRUCT_PAGE;
+               mem_type = I915_PL_SYSTEM;
+               cache_level = I915_CACHE_NONE;
+       } else {
+               mem_flags = i915_ttm_cpu_maps_iomem(bo->resource) ? I915_BO_FLAG_IOMEM :
+                       I915_BO_FLAG_STRUCT_PAGE;
+               mem_type = bo->resource->mem_type;
+               cache_level = i915_ttm_cache_level(to_i915(bo->base.dev), bo->resource,
+                                                  bo->ttm);
+       }
 
        /*
         * If object was moved to an allowable region, update the object
@@ -111,11 +131,11 @@ void i915_ttm_adjust_gem_after_move(struct drm_i915_gem_object *obj)
         * in an allowable region, it's evicted and we don't update the
         * object region.
         */
-       if (intel_region_to_ttm_type(obj->mm.region) != bo->resource->mem_type) {
+       if (intel_region_to_ttm_type(obj->mm.region) != mem_type) {
                for (i = 0; i < obj->mm.n_placements; ++i) {
                        struct intel_memory_region *mr = obj->mm.placements[i];
 
-                       if (intel_region_to_ttm_type(mr) == bo->resource->mem_type &&
+                       if (intel_region_to_ttm_type(mr) == mem_type &&
                            mr != obj->mm.region) {
                                i915_gem_object_release_memory_region(obj);
                                i915_gem_object_init_memory_region(obj, mr);
@@ -125,12 +145,8 @@ void i915_ttm_adjust_gem_after_move(struct drm_i915_gem_object *obj)
        }
 
        obj->mem_flags &= ~(I915_BO_FLAG_STRUCT_PAGE | I915_BO_FLAG_IOMEM);
+       obj->mem_flags |= mem_flags;
 
-       obj->mem_flags |= i915_ttm_cpu_maps_iomem(bo->resource) ? I915_BO_FLAG_IOMEM :
-               I915_BO_FLAG_STRUCT_PAGE;
-
-       cache_level = i915_ttm_cache_level(to_i915(bo->base.dev), bo->resource,
-                                          bo->ttm);
        i915_gem_object_set_cache_coherency(obj, cache_level);
 }
 
@@ -568,6 +584,32 @@ int i915_ttm_move(struct ttm_buffer_object *bo, bool evict,
                return 0;
        }
 
+       if (!bo->resource) {
+               if (dst_mem->mem_type != TTM_PL_SYSTEM) {
+                       hop->mem_type = TTM_PL_SYSTEM;
+                       hop->flags = TTM_PL_FLAG_TEMPORARY;
+                       return -EMULTIHOP;
+               }
+
+               /*
+                * This is only reached when first creating the object, or if
+                * the object was purged or swapped out (pipeline-gutting). For
+                * the former we can safely skip all of the below since we are
+                * only using a dummy SYSTEM placement here. And with the latter
+                * we will always re-enter here with bo->resource set correctly
+                * (as per the above), since this is part of a multi-hop
+                * sequence, where at the end we can do the move for real.
+                *
+                * The special case here is when the dst_mem is TTM_PL_SYSTEM,
+                * which doens't require any kind of move, so it should be safe
+                * to skip all the below and call ttm_bo_move_null() here, where
+                * the caller in __i915_ttm_get_pages() will take care of the
+                * rest, since we should have a valid ttm_tt.
+                */
+               ttm_bo_move_null(bo, dst_mem);
+               return 0;
+       }
+
        ret = i915_ttm_move_notify(bo);
        if (ret)
                return ret;
@@ -672,6 +714,10 @@ int i915_gem_obj_copy_ttm(struct drm_i915_gem_object *dst,
 
        assert_object_held(dst);
        assert_object_held(src);
+
+       if (GEM_WARN_ON(!src_bo->resource || !dst_bo->resource))
+               return -EINVAL;
+
        i915_deps_init(&deps, GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN);
 
        ret = dma_resv_reserve_fences(src_bo->base.resv, 1);