Regards,
Oak

> -----Original Message-----
> From: Intel-gfx <intel-gfx-boun...@lists.freedesktop.org> On Behalf Of Thomas 
> Hellström
> Sent: January 3, 2022 7:00 AM
> To: intel-...@lists.freedesktop.org; dri-devel@lists.freedesktop.org
> Cc: Thomas Hellström <thomas.hellst...@linux.intel.com>; Auld, Matthew 
> <matthew.a...@intel.com>
> Subject: [Intel-gfx] [PATCH v4 2/4] drm/i915: Use the vma resource as 
> argument for gtt binding / unbinding
> 
> When introducing asynchronous unbinding, the vma itself may no longer
> be alive when the actual binding or unbinding takes place.

Can we take an extra reference counter of the vma to keep the vma alive, until 
the actual binding/unbinding takes place?

Regards,
Oak

> 
> Update the gtt i915_vma_ops accordingly to take a struct i915_vma_resource
> instead of a struct i915_vma for the bind_vma() and unbind_vma() ops.
> Similarly change the insert_entries() op for struct i915_address_space.
> 
> Replace a couple of i915_vma_snapshot members with their newly introduced
> i915_vma_resource counterparts, since they have the same lifetime.
> 
> Also make sure to avoid changing the struct i915_vma_flags (in particular
> the bind flags) async. That should now only be done sync under the
> vm mutex.
> 
> v2:
> - Update the vma_res::bound_flags when binding to the aliased ggtt
> 
> Signed-off-by: Thomas Hellström <thomas.hellst...@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_dpt.c      | 27 ++---
>  .../gpu/drm/i915/gem/i915_gem_object_types.h  | 27 +----
>  .../gpu/drm/i915/gem/selftests/huge_pages.c   | 37 +++----
>  drivers/gpu/drm/i915/gt/gen6_ppgtt.c          | 19 ++--
>  drivers/gpu/drm/i915/gt/gen8_ppgtt.c          | 37 +++----
>  drivers/gpu/drm/i915/gt/intel_engine_cs.c     |  4 +-
>  drivers/gpu/drm/i915/gt/intel_ggtt.c          | 70 ++++++-------
>  drivers/gpu/drm/i915/gt/intel_gtt.h           | 16 +--
>  drivers/gpu/drm/i915/gt/intel_ppgtt.c         | 22 +++--
>  drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c      | 13 ++-
>  drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h      |  2 +-
>  drivers/gpu/drm/i915/i915_debugfs.c           |  3 +-
>  drivers/gpu/drm/i915/i915_gpu_error.c         |  6 +-
>  drivers/gpu/drm/i915/i915_vma.c               | 24 ++++-
>  drivers/gpu/drm/i915/i915_vma.h               | 11 +--
>  drivers/gpu/drm/i915/i915_vma_resource.c      |  9 +-
>  drivers/gpu/drm/i915/i915_vma_resource.h      | 99 ++++++++++++++++++-
>  drivers/gpu/drm/i915/i915_vma_snapshot.c      |  4 -
>  drivers/gpu/drm/i915/i915_vma_snapshot.h      |  8 --
>  drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 64 ++++++++----
>  drivers/gpu/drm/i915/selftests/mock_gtt.c     | 12 +--
>  21 files changed, 308 insertions(+), 206 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c 
> b/drivers/gpu/drm/i915/display/intel_dpt.c
> index 8f674745e7e0..63a83d5f85a1 100644
> --- a/drivers/gpu/drm/i915/display/intel_dpt.c
> +++ b/drivers/gpu/drm/i915/display/intel_dpt.c
> @@ -48,7 +48,7 @@ static void dpt_insert_page(struct i915_address_space *vm,
>  }
> 
>  static void dpt_insert_entries(struct i915_address_space *vm,
> -                            struct i915_vma *vma,
> +                            struct i915_vma_resource *vma_res,
>                              enum i915_cache_level level,
>                              u32 flags)
>  {
> @@ -64,8 +64,8 @@ static void dpt_insert_entries(struct i915_address_space 
> *vm,
>        * not to allow the user to override access to a read only page.
>        */
> 
> -     i = vma->node.start / I915_GTT_PAGE_SIZE;
> -     for_each_sgt_daddr(addr, sgt_iter, vma->pages)
> +     i = vma_res->start / I915_GTT_PAGE_SIZE;
> +     for_each_sgt_daddr(addr, sgt_iter, vma_res->bi.pages)
>               gen8_set_pte(&base[i++], pte_encode | addr);
>  }
> 
> @@ -76,35 +76,38 @@ static void dpt_clear_range(struct i915_address_space *vm,
> 
>  static void dpt_bind_vma(struct i915_address_space *vm,
>                        struct i915_vm_pt_stash *stash,
> -                      struct i915_vma *vma,
> +                      struct i915_vma_resource *vma_res,
>                        enum i915_cache_level cache_level,
>                        u32 flags)
>  {
> -     struct drm_i915_gem_object *obj = vma->obj;
>       u32 pte_flags;
> 
> +     if (vma_res->bound_flags)
> +             return;
> +
>       /* Applicable to VLV (gen8+ do not support RO in the GGTT) */
>       pte_flags = 0;
> -     if (vma->vm->has_read_only && i915_gem_object_is_readonly(obj))
> +     if (vm->has_read_only && vma_res->bi.readonly)
>               pte_flags |= PTE_READ_ONLY;
> -     if (i915_gem_object_is_lmem(obj))
> +     if (vma_res->bi.lmem)
>               pte_flags |= PTE_LM;
> 
> -     vma->vm->insert_entries(vma->vm, vma, cache_level, pte_flags);
> +     vm->insert_entries(vm, vma_res, cache_level, pte_flags);
> 
> -     vma->page_sizes.gtt = I915_GTT_PAGE_SIZE;
> +     vma_res->page_sizes_gtt = I915_GTT_PAGE_SIZE;
> 
>       /*
>        * Without aliasing PPGTT there's no difference between
>        * GLOBAL/LOCAL_BIND, it's all the same ptes. Hence unconditionally
>        * upgrade to both bound if we bind either to avoid double-binding.
>        */
> -     atomic_or(I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND, &vma->flags);
> +     vma_res->bound_flags = I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND;
>  }
> 
> -static void dpt_unbind_vma(struct i915_address_space *vm, struct i915_vma 
> *vma)
> +static void dpt_unbind_vma(struct i915_address_space *vm,
> +                        struct i915_vma_resource *vma_res)
>  {
> -     vm->clear_range(vm, vma->node.start, vma->size);
> +     vm->clear_range(vm, vma_res->start, vma_res->vma_size);
>  }
> 
>  static void dpt_cleanup(struct i915_address_space *vm)
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h 
> b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
> index f9f7e44099fe..f99d260e0684 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
> @@ -15,6 +15,7 @@
> 
>  #include "i915_active.h"
>  #include "i915_selftest.h"
> +#include "i915_vma_resource.h"
> 
>  struct drm_i915_gem_object;
>  struct intel_fronbuffer;
> @@ -549,31 +550,7 @@ struct drm_i915_gem_object {
>               struct sg_table *pages;
>               void *mapping;
> 
> -             struct i915_page_sizes {
> -                     /**
> -                      * The sg mask of the pages sg_table. i.e the mask of
> -                      * of the lengths for each sg entry.
> -                      */
> -                     unsigned int phys;
> -
> -                     /**
> -                      * The gtt page sizes we are allowed to use given the
> -                      * sg mask and the supported page sizes. This will
> -                      * express the smallest unit we can use for the whole
> -                      * object, as well as the larger sizes we may be able
> -                      * to use opportunistically.
> -                      */
> -                     unsigned int sg;
> -
> -                     /**
> -                      * The actual gtt page size usage. Since we can have
> -                      * multiple vma associated with this object we need to
> -                      * prevent any trampling of state, hence a copy of this
> -                      * struct also lives in each vma, therefore the gtt
> -                      * value here should only be read/write through the vma.
> -                      */
> -                     unsigned int gtt;
> -             } page_sizes;
> +             struct i915_page_sizes page_sizes;
> 
>               I915_SELFTEST_DECLARE(unsigned int page_mask);
> 
> diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c 
> b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
> index 11f0aa65f8a3..26f997c376a2 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
> @@ -370,9 +370,9 @@ static int igt_check_page_sizes(struct i915_vma *vma)
>               err = -EINVAL;
>       }
> 
> -     if (!HAS_PAGE_SIZES(i915, vma->page_sizes.gtt)) {
> +     if (!HAS_PAGE_SIZES(i915, vma->resource->page_sizes_gtt)) {
>               pr_err("unsupported page_sizes.gtt=%u, supported=%u\n",
> -                    vma->page_sizes.gtt & ~supported, supported);
> +                    vma->resource->page_sizes_gtt & ~supported, supported);
>               err = -EINVAL;
>       }
> 
> @@ -403,15 +403,9 @@ static int igt_check_page_sizes(struct i915_vma *vma)
>       if (i915_gem_object_is_lmem(obj) &&
>           IS_ALIGNED(vma->node.start, SZ_2M) &&
>           vma->page_sizes.sg & SZ_2M &&
> -         vma->page_sizes.gtt < SZ_2M) {
> +         vma->resource->page_sizes_gtt < SZ_2M) {
>               pr_err("gtt pages mismatch for LMEM, expected 2M GTT pages, 
> sg(%u), gtt(%u)\n",
> -                    vma->page_sizes.sg, vma->page_sizes.gtt);
> -             err = -EINVAL;
> -     }
> -
> -     if (obj->mm.page_sizes.gtt) {
> -             pr_err("obj->page_sizes.gtt(%u) should never be set\n",
> -                    obj->mm.page_sizes.gtt);
> +                    vma->page_sizes.sg, vma->resource->page_sizes_gtt);
>               err = -EINVAL;
>       }
> 
> @@ -547,9 +541,9 @@ static int igt_mock_memory_region_huge_pages(void *arg)
>                               goto out_unpin;
>                       }
> 
> -                     if (vma->page_sizes.gtt != page_size) {
> +                     if (vma->resource->page_sizes_gtt != page_size) {
>                               pr_err("%s page_sizes.gtt=%u, expected=%u\n",
> -                                    __func__, vma->page_sizes.gtt,
> +                                    __func__, vma->resource->page_sizes_gtt,
>                                      page_size);
>                               err = -EINVAL;
>                               goto out_unpin;
> @@ -630,9 +624,9 @@ static int igt_mock_ppgtt_misaligned_dma(void *arg)
> 
>               err = igt_check_page_sizes(vma);
> 
> -             if (vma->page_sizes.gtt != page_size) {
> +             if (vma->resource->page_sizes_gtt != page_size) {
>                       pr_err("page_sizes.gtt=%u, expected %u\n",
> -                            vma->page_sizes.gtt, page_size);
> +                            vma->resource->page_sizes_gtt, page_size);
>                       err = -EINVAL;
>               }
> 
> @@ -657,9 +651,10 @@ static int igt_mock_ppgtt_misaligned_dma(void *arg)
> 
>                       err = igt_check_page_sizes(vma);
> 
> -                     if (vma->page_sizes.gtt != I915_GTT_PAGE_SIZE_4K) {
> +                     if (vma->resource->page_sizes_gtt != 
> I915_GTT_PAGE_SIZE_4K) {
>                               pr_err("page_sizes.gtt=%u, expected %llu\n",
> -                                    vma->page_sizes.gtt, 
> I915_GTT_PAGE_SIZE_4K);
> +                                    vma->resource->page_sizes_gtt,
> +                                    I915_GTT_PAGE_SIZE_4K);
>                               err = -EINVAL;
>                       }
> 
> @@ -805,9 +800,9 @@ static int igt_mock_ppgtt_huge_fill(void *arg)
>                       }
>               }
> 
> -             if (vma->page_sizes.gtt != expected_gtt) {
> +             if (vma->resource->page_sizes_gtt != expected_gtt) {
>                       pr_err("gtt=%u, expected=%u, size=%zd, single=%s\n",
> -                            vma->page_sizes.gtt, expected_gtt,
> +                            vma->resource->page_sizes_gtt, expected_gtt,
>                              obj->base.size, yesno(!!single));
>                       err = -EINVAL;
>                       break;
> @@ -961,10 +956,10 @@ static int igt_mock_ppgtt_64K(void *arg)
>                               }
>                       }
> 
> -                     if (vma->page_sizes.gtt != expected_gtt) {
> +                     if (vma->resource->page_sizes_gtt != expected_gtt) {
>                               pr_err("gtt=%u, expected=%u, i=%d, single=%s\n",
> -                                    vma->page_sizes.gtt, expected_gtt, i,
> -                                    yesno(!!single));
> +                                    vma->resource->page_sizes_gtt,
> +                                    expected_gtt, i, yesno(!!single));
>                               err = -EINVAL;
>                               goto out_vma_unpin;
>                       }
> diff --git a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c 
> b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
> index 6e9292918bfc..d657ffd6c86a 100644
> --- a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
> +++ b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c
> @@ -104,17 +104,17 @@ static void gen6_ppgtt_clear_range(struct 
> i915_address_space *vm,
>  }
> 
>  static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
> -                                   struct i915_vma *vma,
> +                                   struct i915_vma_resource *vma_res,
>                                     enum i915_cache_level cache_level,
>                                     u32 flags)
>  {
>       struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
>       struct i915_page_directory * const pd = ppgtt->pd;
> -     unsigned int first_entry = vma->node.start / I915_GTT_PAGE_SIZE;
> +     unsigned int first_entry = vma_res->start / I915_GTT_PAGE_SIZE;
>       unsigned int act_pt = first_entry / GEN6_PTES;
>       unsigned int act_pte = first_entry % GEN6_PTES;
>       const u32 pte_encode = vm->pte_encode(0, cache_level, flags);
> -     struct sgt_dma iter = sgt_dma(vma);
> +     struct sgt_dma iter = sgt_dma(vma_res);
>       gen6_pte_t *vaddr;
> 
>       GEM_BUG_ON(!pd->entry[act_pt]);
> @@ -140,7 +140,7 @@ static void gen6_ppgtt_insert_entries(struct 
> i915_address_space *vm,
>               }
>       } while (1);
> 
> -     vma->page_sizes.gtt = I915_GTT_PAGE_SIZE;
> +     vma_res->page_sizes_gtt = I915_GTT_PAGE_SIZE;
>  }
> 
>  static void gen6_flush_pd(struct gen6_ppgtt *ppgtt, u64 start, u64 end)
> @@ -271,13 +271,13 @@ static void gen6_ppgtt_cleanup(struct 
> i915_address_space *vm)
> 
>  static void pd_vma_bind(struct i915_address_space *vm,
>                       struct i915_vm_pt_stash *stash,
> -                     struct i915_vma *vma,
> +                     struct i915_vma_resource *vma_res,
>                       enum i915_cache_level cache_level,
>                       u32 unused)
>  {
>       struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
> -     struct gen6_ppgtt *ppgtt = vma->private;
> -     u32 ggtt_offset = i915_ggtt_offset(vma) / I915_GTT_PAGE_SIZE;
> +     struct gen6_ppgtt *ppgtt = vma_res->private;
> +     u32 ggtt_offset = vma_res->start / I915_GTT_PAGE_SIZE;
> 
>       ppgtt->pp_dir = ggtt_offset * sizeof(gen6_pte_t) << 10;
>       ppgtt->pd_addr = (gen6_pte_t __iomem *)ggtt->gsm + ggtt_offset;
> @@ -285,9 +285,10 @@ static void pd_vma_bind(struct i915_address_space *vm,
>       gen6_flush_pd(ppgtt, 0, ppgtt->base.vm.total);
>  }
> 
> -static void pd_vma_unbind(struct i915_address_space *vm, struct i915_vma 
> *vma)
> +static void pd_vma_unbind(struct i915_address_space *vm,
> +                       struct i915_vma_resource *vma_res)
>  {
> -     struct gen6_ppgtt *ppgtt = vma->private;
> +     struct gen6_ppgtt *ppgtt = vma_res->private;
>       struct i915_page_directory * const pd = ppgtt->base.pd;
>       struct i915_page_table *pt;
>       unsigned int pde;
> diff --git a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c 
> b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c
> index b012c50f7ce7..c43e724afa9f 100644
> --- a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c
> +++ b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c
> @@ -453,20 +453,21 @@ gen8_ppgtt_insert_pte(struct i915_ppgtt *ppgtt,
>       return idx;
>  }
> 
> -static void gen8_ppgtt_insert_huge(struct i915_vma *vma,
> +static void gen8_ppgtt_insert_huge(struct i915_address_space *vm,
> +                                struct i915_vma_resource *vma_res,
>                                  struct sgt_dma *iter,
>                                  enum i915_cache_level cache_level,
>                                  u32 flags)
>  {
>       const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level, flags);
>       unsigned int rem = sg_dma_len(iter->sg);
> -     u64 start = vma->node.start;
> +     u64 start = vma_res->start;
> 
> -     GEM_BUG_ON(!i915_vm_is_4lvl(vma->vm));
> +     GEM_BUG_ON(!i915_vm_is_4lvl(vm));
> 
>       do {
>               struct i915_page_directory * const pdp =
> -                     gen8_pdp_for_page_address(vma->vm, start);
> +                     gen8_pdp_for_page_address(vm, start);
>               struct i915_page_directory * const pd =
>                       i915_pd_entry(pdp, __gen8_pte_index(start, 2));
>               gen8_pte_t encode = pte_encode;
> @@ -475,7 +476,7 @@ static void gen8_ppgtt_insert_huge(struct i915_vma *vma,
>               gen8_pte_t *vaddr;
>               u16 index;
> 
> -             if (vma->page_sizes.sg & I915_GTT_PAGE_SIZE_2M &&
> +             if (vma_res->bi.page_sizes.sg & I915_GTT_PAGE_SIZE_2M &&
>                   IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_2M) &&
>                   rem >= I915_GTT_PAGE_SIZE_2M &&
>                   !__gen8_pte_index(start, 0)) {
> @@ -492,7 +493,7 @@ static void gen8_ppgtt_insert_huge(struct i915_vma *vma,
>                       page_size = I915_GTT_PAGE_SIZE;
> 
>                       if (!index &&
> -                         vma->page_sizes.sg & I915_GTT_PAGE_SIZE_64K &&
> +                         vma_res->bi.page_sizes.sg & I915_GTT_PAGE_SIZE_64K 
> &&
>                           IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) &&
>                           (IS_ALIGNED(rem, I915_GTT_PAGE_SIZE_64K) ||
>                            rem >= (I915_PDES - index) * I915_GTT_PAGE_SIZE))
> @@ -541,9 +542,9 @@ static void gen8_ppgtt_insert_huge(struct i915_vma *vma,
>                */
>               if (maybe_64K != -1 &&
>                   (index == I915_PDES ||
> -                  (i915_vm_has_scratch_64K(vma->vm) &&
> -                   !iter->sg && IS_ALIGNED(vma->node.start +
> -                                           vma->node.size,
> +                  (i915_vm_has_scratch_64K(vm) &&
> +                   !iter->sg && IS_ALIGNED(vma_res->start +
> +                                           vma_res->node_size,
>                                             I915_GTT_PAGE_SIZE_2M)))) {
>                       vaddr = px_vaddr(pd);
>                       vaddr[maybe_64K] |= GEN8_PDE_IPS_64K;
> @@ -559,10 +560,10 @@ static void gen8_ppgtt_insert_huge(struct i915_vma *vma,
>                        * instead - which we detect as missing results during
>                        * selftests.
>                        */
> -                     if (I915_SELFTEST_ONLY(vma->vm->scrub_64K)) {
> +                     if (I915_SELFTEST_ONLY(vm->scrub_64K)) {
>                               u16 i;
> 
> -                             encode = vma->vm->scratch[0]->encode;
> +                             encode = vm->scratch[0]->encode;
>                               vaddr = px_vaddr(i915_pt_entry(pd, maybe_64K));
> 
>                               for (i = 1; i < index; i += 16)
> @@ -572,22 +573,22 @@ static void gen8_ppgtt_insert_huge(struct i915_vma *vma,
>                       }
>               }
> 
> -             vma->page_sizes.gtt |= page_size;
> +             vma_res->page_sizes_gtt |= page_size;
>       } while (iter->sg && sg_dma_len(iter->sg));
>  }
> 
>  static void gen8_ppgtt_insert(struct i915_address_space *vm,
> -                           struct i915_vma *vma,
> +                           struct i915_vma_resource *vma_res,
>                             enum i915_cache_level cache_level,
>                             u32 flags)
>  {
>       struct i915_ppgtt * const ppgtt = i915_vm_to_ppgtt(vm);
> -     struct sgt_dma iter = sgt_dma(vma);
> +     struct sgt_dma iter = sgt_dma(vma_res);
> 
> -     if (vma->page_sizes.sg > I915_GTT_PAGE_SIZE) {
> -             gen8_ppgtt_insert_huge(vma, &iter, cache_level, flags);
> +     if (vma_res->bi.page_sizes.sg > I915_GTT_PAGE_SIZE) {
> +             gen8_ppgtt_insert_huge(vm, vma_res, &iter, cache_level, flags);
>       } else  {
> -             u64 idx = vma->node.start >> GEN8_PTE_SHIFT;
> +             u64 idx = vma_res->start >> GEN8_PTE_SHIFT;
> 
>               do {
>                       struct i915_page_directory * const pdp =
> @@ -597,7 +598,7 @@ static void gen8_ppgtt_insert(struct i915_address_space 
> *vm,
>                                                   cache_level, flags);
>               } while (idx);
> 
> -             vma->page_sizes.gtt = I915_GTT_PAGE_SIZE;
> +             vma_res->page_sizes_gtt = I915_GTT_PAGE_SIZE;
>       }
>  }
> 
> diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c 
> b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
> index 352254e001b4..74aa90587061 100644
> --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
> +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
> @@ -1718,8 +1718,8 @@ static void print_request_ring(struct drm_printer *m, 
> struct i915_request *rq)
>       drm_printf(m,
>                  "[head %04x, postfix %04x, tail %04x, batch 0x%08x_%08x]:\n",
>                  rq->head, rq->postfix, rq->tail,
> -                vsnap ? upper_32_bits(vsnap->gtt_offset) : ~0u,
> -                vsnap ? lower_32_bits(vsnap->gtt_offset) : ~0u);
> +                vsnap ? upper_32_bits(vsnap->vma_resource->start) : ~0u,
> +                vsnap ? lower_32_bits(vsnap->vma_resource->start) : ~0u);
> 
>       size = rq->tail - rq->head;
>       if (rq->tail < rq->head)
> diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c 
> b/drivers/gpu/drm/i915/gt/intel_ggtt.c
> index 5263dda7f8d5..0137b6af0973 100644
> --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c
> +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c
> @@ -235,7 +235,7 @@ static void gen8_ggtt_insert_page(struct 
> i915_address_space *vm,
>  }
> 
>  static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
> -                                  struct i915_vma *vma,
> +                                  struct i915_vma_resource *vma_res,
>                                    enum i915_cache_level level,
>                                    u32 flags)
>  {
> @@ -252,10 +252,10 @@ static void gen8_ggtt_insert_entries(struct 
> i915_address_space *vm,
>        */
> 
>       gte = (gen8_pte_t __iomem *)ggtt->gsm;
> -     gte += vma->node.start / I915_GTT_PAGE_SIZE;
> -     end = gte + vma->node.size / I915_GTT_PAGE_SIZE;
> +     gte += vma_res->start / I915_GTT_PAGE_SIZE;
> +     end = gte + vma_res->node_size / I915_GTT_PAGE_SIZE;
> 
> -     for_each_sgt_daddr(addr, iter, vma->pages)
> +     for_each_sgt_daddr(addr, iter, vma_res->bi.pages)
>               gen8_set_pte(gte++, pte_encode | addr);
>       GEM_BUG_ON(gte > end);
> 
> @@ -292,7 +292,7 @@ static void gen6_ggtt_insert_page(struct 
> i915_address_space *vm,
>   * through the GMADR mapped BAR (i915->mm.gtt->gtt).
>   */
>  static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
> -                                  struct i915_vma *vma,
> +                                  struct i915_vma_resource *vma_res,
>                                    enum i915_cache_level level,
>                                    u32 flags)
>  {
> @@ -303,10 +303,10 @@ static void gen6_ggtt_insert_entries(struct 
> i915_address_space *vm,
>       dma_addr_t addr;
> 
>       gte = (gen6_pte_t __iomem *)ggtt->gsm;
> -     gte += vma->node.start / I915_GTT_PAGE_SIZE;
> -     end = gte + vma->node.size / I915_GTT_PAGE_SIZE;
> +     gte += vma_res->start / I915_GTT_PAGE_SIZE;
> +     end = gte + vma_res->node_size / I915_GTT_PAGE_SIZE;
> 
> -     for_each_sgt_daddr(addr, iter, vma->pages)
> +     for_each_sgt_daddr(addr, iter, vma_res->bi.pages)
>               iowrite32(vm->pte_encode(addr, level, flags), gte++);
>       GEM_BUG_ON(gte > end);
> 
> @@ -389,7 +389,7 @@ static void bxt_vtd_ggtt_insert_page__BKL(struct 
> i915_address_space *vm,
> 
>  struct insert_entries {
>       struct i915_address_space *vm;
> -     struct i915_vma *vma;
> +     struct i915_vma_resource *vma_res;
>       enum i915_cache_level level;
>       u32 flags;
>  };
> @@ -398,18 +398,18 @@ static int bxt_vtd_ggtt_insert_entries__cb(void *_arg)
>  {
>       struct insert_entries *arg = _arg;
> 
> -     gen8_ggtt_insert_entries(arg->vm, arg->vma, arg->level, arg->flags);
> +     gen8_ggtt_insert_entries(arg->vm, arg->vma_res, arg->level, arg->flags);
>       bxt_vtd_ggtt_wa(arg->vm);
> 
>       return 0;
>  }
> 
>  static void bxt_vtd_ggtt_insert_entries__BKL(struct i915_address_space *vm,
> -                                          struct i915_vma *vma,
> +                                          struct i915_vma_resource *vma_res,
>                                            enum i915_cache_level level,
>                                            u32 flags)
>  {
> -     struct insert_entries arg = { vm, vma, level, flags };
> +     struct insert_entries arg = { vm, vma_res, level, flags };
> 
>       stop_machine(bxt_vtd_ggtt_insert_entries__cb, &arg, NULL);
>  }
> @@ -448,14 +448,14 @@ static void i915_ggtt_insert_page(struct 
> i915_address_space *vm,
>  }
> 
>  static void i915_ggtt_insert_entries(struct i915_address_space *vm,
> -                                  struct i915_vma *vma,
> +                                  struct i915_vma_resource *vma_res,
>                                    enum i915_cache_level cache_level,
>                                    u32 unused)
>  {
>       unsigned int flags = (cache_level == I915_CACHE_NONE) ?
>               AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY;
> 
> -     intel_gtt_insert_sg_entries(vma->pages, vma->node.start >> PAGE_SHIFT,
> +     intel_gtt_insert_sg_entries(vma_res->bi.pages, vma_res->start >> 
> PAGE_SHIFT,
>                                   flags);
>  }
> 
> @@ -467,30 +467,32 @@ static void i915_ggtt_clear_range(struct 
> i915_address_space *vm,
> 
>  static void ggtt_bind_vma(struct i915_address_space *vm,
>                         struct i915_vm_pt_stash *stash,
> -                       struct i915_vma *vma,
> +                       struct i915_vma_resource *vma_res,
>                         enum i915_cache_level cache_level,
>                         u32 flags)
>  {
> -     struct drm_i915_gem_object *obj = vma->obj;
>       u32 pte_flags;
> 
> -     if (i915_vma_is_bound(vma, ~flags & I915_VMA_BIND_MASK))
> +     if (vma_res->bound_flags & (~flags & I915_VMA_BIND_MASK))
>               return;
> 
> +     vma_res->bound_flags |= flags;
> +
>       /* Applicable to VLV (gen8+ do not support RO in the GGTT) */
>       pte_flags = 0;
> -     if (i915_gem_object_is_readonly(obj))
> +     if (vma_res->bi.readonly)
>               pte_flags |= PTE_READ_ONLY;
> -     if (i915_gem_object_is_lmem(obj))
> +     if (vma_res->bi.lmem)
>               pte_flags |= PTE_LM;
> 
> -     vm->insert_entries(vm, vma, cache_level, pte_flags);
> -     vma->page_sizes.gtt = I915_GTT_PAGE_SIZE;
> +     vm->insert_entries(vm, vma_res, cache_level, pte_flags);
> +     vma_res->page_sizes_gtt = I915_GTT_PAGE_SIZE;
>  }
> 
> -static void ggtt_unbind_vma(struct i915_address_space *vm, struct i915_vma 
> *vma)
> +static void ggtt_unbind_vma(struct i915_address_space *vm,
> +                         struct i915_vma_resource *vma_res)
>  {
> -     vm->clear_range(vm, vma->node.start, vma->size);
> +     vm->clear_range(vm, vma_res->start, vma_res->vma_size);
>  }
> 
>  static int ggtt_reserve_guc_top(struct i915_ggtt *ggtt)
> @@ -623,7 +625,7 @@ static int init_ggtt(struct i915_ggtt *ggtt)
> 
>  static void aliasing_gtt_bind_vma(struct i915_address_space *vm,
>                                 struct i915_vm_pt_stash *stash,
> -                               struct i915_vma *vma,
> +                               struct i915_vma_resource *vma_res,
>                                 enum i915_cache_level cache_level,
>                                 u32 flags)
>  {
> @@ -631,25 +633,27 @@ static void aliasing_gtt_bind_vma(struct 
> i915_address_space *vm,
> 
>       /* Currently applicable only to VLV */
>       pte_flags = 0;
> -     if (i915_gem_object_is_readonly(vma->obj))
> +     if (vma_res->bi.readonly)
>               pte_flags |= PTE_READ_ONLY;
> 
>       if (flags & I915_VMA_LOCAL_BIND)
>               ppgtt_bind_vma(&i915_vm_to_ggtt(vm)->alias->vm,
> -                            stash, vma, cache_level, flags);
> +                            stash, vma_res, cache_level, flags);
> 
>       if (flags & I915_VMA_GLOBAL_BIND)
> -             vm->insert_entries(vm, vma, cache_level, pte_flags);
> +             vm->insert_entries(vm, vma_res, cache_level, pte_flags);
> +
> +     vma_res->bound_flags |= flags;
>  }
> 
>  static void aliasing_gtt_unbind_vma(struct i915_address_space *vm,
> -                                 struct i915_vma *vma)
> +                                 struct i915_vma_resource *vma_res)
>  {
> -     if (i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND))
> -             vm->clear_range(vm, vma->node.start, vma->size);
> +     if (vma_res->bound_flags & I915_VMA_GLOBAL_BIND)
> +             vm->clear_range(vm, vma_res->start, vma_res->vma_size);
> 
> -     if (i915_vma_is_bound(vma, I915_VMA_LOCAL_BIND))
> -             ppgtt_unbind_vma(&i915_vm_to_ggtt(vm)->alias->vm, vma);
> +     if (vma_res->bound_flags & I915_VMA_LOCAL_BIND)
> +             ppgtt_unbind_vma(&i915_vm_to_ggtt(vm)->alias->vm, vma_res);
>  }
> 
>  static int init_aliasing_ppgtt(struct i915_ggtt *ggtt)
> @@ -1280,7 +1284,7 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm)
>                       atomic_read(&vma->flags) & I915_VMA_BIND_MASK;
> 
>               GEM_BUG_ON(!was_bound);
> -             vma->ops->bind_vma(vm, NULL, vma,
> +             vma->ops->bind_vma(vm, NULL, vma->resource,
>                                  obj ? obj->cache_level : 0,
>                                  was_bound);
>               if (obj) { /* only used during resume => exclusive access */
> diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h 
> b/drivers/gpu/drm/i915/gt/intel_gtt.h
> index 177b42b935a1..676b839d1a34 100644
> --- a/drivers/gpu/drm/i915/gt/intel_gtt.h
> +++ b/drivers/gpu/drm/i915/gt/intel_gtt.h
> @@ -27,6 +27,7 @@
> 
>  #include "gt/intel_reset.h"
>  #include "i915_selftest.h"
> +#include "i915_vma_resource.h"
>  #include "i915_vma_types.h"
> 
>  #define I915_GFP_ALLOW_FAIL (GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN)
> @@ -200,7 +201,7 @@ struct i915_vma_ops {
>       /* Map an object into an address space with the given cache flags. */
>       void (*bind_vma)(struct i915_address_space *vm,
>                        struct i915_vm_pt_stash *stash,
> -                      struct i915_vma *vma,
> +                      struct i915_vma_resource *vma_res,
>                        enum i915_cache_level cache_level,
>                        u32 flags);
>       /*
> @@ -208,7 +209,8 @@ struct i915_vma_ops {
>        * setting the valid PTE entries to a reserved scratch page.
>        */
>       void (*unbind_vma)(struct i915_address_space *vm,
> -                        struct i915_vma *vma);
> +                        struct i915_vma_resource *vma_res);
> +
>  };
> 
>  struct i915_address_space {
> @@ -285,7 +287,7 @@ struct i915_address_space {
>                           enum i915_cache_level cache_level,
>                           u32 flags);
>       void (*insert_entries)(struct i915_address_space *vm,
> -                            struct i915_vma *vma,
> +                            struct i915_vma_resource *vma_res,
>                              enum i915_cache_level cache_level,
>                              u32 flags);
>       void (*cleanup)(struct i915_address_space *vm);
> @@ -600,11 +602,11 @@ void gen6_ggtt_invalidate(struct i915_ggtt *ggtt);
> 
>  void ppgtt_bind_vma(struct i915_address_space *vm,
>                   struct i915_vm_pt_stash *stash,
> -                 struct i915_vma *vma,
> +                 struct i915_vma_resource *vma_res,
>                   enum i915_cache_level cache_level,
>                   u32 flags);
>  void ppgtt_unbind_vma(struct i915_address_space *vm,
> -                   struct i915_vma *vma);
> +                   struct i915_vma_resource *vma_res);
> 
>  void gtt_write_workarounds(struct intel_gt *gt);
> 
> @@ -627,8 +629,8 @@ __vm_create_scratch_for_read_pinned(struct 
> i915_address_space *vm, unsigned long
>  static inline struct sgt_dma {
>       struct scatterlist *sg;
>       dma_addr_t dma, max;
> -} sgt_dma(struct i915_vma *vma) {
> -     struct scatterlist *sg = vma->pages->sgl;
> +} sgt_dma(struct i915_vma_resource *vma_res) {
> +     struct scatterlist *sg = vma_res->bi.pages->sgl;
>       dma_addr_t addr = sg_dma_address(sg);
> 
>       return (struct sgt_dma){ sg, addr, addr + sg_dma_len(sg) };
> diff --git a/drivers/gpu/drm/i915/gt/intel_ppgtt.c 
> b/drivers/gpu/drm/i915/gt/intel_ppgtt.c
> index 083b3090c69c..48e6e2f87700 100644
> --- a/drivers/gpu/drm/i915/gt/intel_ppgtt.c
> +++ b/drivers/gpu/drm/i915/gt/intel_ppgtt.c
> @@ -179,32 +179,34 @@ struct i915_ppgtt *i915_ppgtt_create(struct intel_gt 
> *gt,
> 
>  void ppgtt_bind_vma(struct i915_address_space *vm,
>                   struct i915_vm_pt_stash *stash,
> -                 struct i915_vma *vma,
> +                 struct i915_vma_resource *vma_res,
>                   enum i915_cache_level cache_level,
>                   u32 flags)
>  {
>       u32 pte_flags;
> 
> -     if (!test_bit(I915_VMA_ALLOC_BIT, __i915_vma_flags(vma))) {
> -             vm->allocate_va_range(vm, stash, vma->node.start, vma->size);
> -             set_bit(I915_VMA_ALLOC_BIT, __i915_vma_flags(vma));
> +     if (!vma_res->allocated) {
> +             vm->allocate_va_range(vm, stash, vma_res->start,
> +                                   vma_res->vma_size);
> +             vma_res->allocated = true;
>       }
> 
>       /* Applicable to VLV, and gen8+ */
>       pte_flags = 0;
> -     if (i915_gem_object_is_readonly(vma->obj))
> +     if (vma_res->bi.readonly)
>               pte_flags |= PTE_READ_ONLY;
> -     if (i915_gem_object_is_lmem(vma->obj))
> +     if (vma_res->bi.lmem)
>               pte_flags |= PTE_LM;
> 
> -     vm->insert_entries(vm, vma, cache_level, pte_flags);
> +     vm->insert_entries(vm, vma_res, cache_level, pte_flags);
>       wmb();
>  }
> 
> -void ppgtt_unbind_vma(struct i915_address_space *vm, struct i915_vma *vma)
> +void ppgtt_unbind_vma(struct i915_address_space *vm,
> +                   struct i915_vma_resource *vma_res)
>  {
> -     if (test_and_clear_bit(I915_VMA_ALLOC_BIT, __i915_vma_flags(vma)))
> -             vm->clear_range(vm, vma->node.start, vma->size);
> +     if (vma_res->allocated)
> +             vm->clear_range(vm, vma_res->start, vma_res->vma_size);
>  }
> 
>  static unsigned long pd_count(u64 size, int shift)
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c 
> b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
> index a5af05bde6f2..777fc6f0ceff 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
> @@ -448,20 +448,19 @@ static void uc_fw_bind_ggtt(struct intel_uc_fw *uc_fw)
>  {
>       struct drm_i915_gem_object *obj = uc_fw->obj;
>       struct i915_ggtt *ggtt = __uc_fw_to_gt(uc_fw)->ggtt;
> -     struct i915_vma *dummy = &uc_fw->dummy;
> +     struct i915_vma_resource *dummy = &uc_fw->dummy;
>       u32 pte_flags = 0;
> 
> -     dummy->node.start = uc_fw_ggtt_offset(uc_fw);
> -     dummy->node.size = obj->base.size;
> -     dummy->pages = obj->mm.pages;
> -     dummy->vm = &ggtt->vm;
> +     dummy->start = uc_fw_ggtt_offset(uc_fw);
> +     dummy->node_size = obj->base.size;
> +     dummy->bi.pages = obj->mm.pages;
> 
>       GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
> -     GEM_BUG_ON(dummy->node.size > ggtt->uc_fw.size);
> +     GEM_BUG_ON(dummy->node_size > ggtt->uc_fw.size);
> 
>       /* uc_fw->obj cache domains were not controlled across suspend */
>       if (i915_gem_object_has_struct_page(obj))
> -             drm_clflush_sg(dummy->pages);
> +             drm_clflush_sg(dummy->bi.pages);
> 
>       if (i915_gem_object_is_lmem(obj))
>               pte_flags |= PTE_LM;
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h 
> b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
> index d9d1dc0b4cbb..3229018877d3 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
> @@ -85,7 +85,7 @@ struct intel_uc_fw {
>        * threaded as it done during driver load (inherently single threaded)
>        * or during a GT reset (mutex guarantees single threaded).
>        */
> -     struct i915_vma dummy;
> +     struct i915_vma_resource dummy;
>       struct i915_vma *rsa_data;
> 
>       /*
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c 
> b/drivers/gpu/drm/i915/i915_debugfs.c
> index e0e052cdf8b8..f7d1feba5aa4 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -170,7 +170,8 @@ i915_debugfs_describe_obj(struct seq_file *m, struct 
> drm_i915_gem_object *obj)
>               seq_printf(m, " (%s offset: %08llx, size: %08llx, pages: %s",
>                          stringify_vma_type(vma),
>                          vma->node.start, vma->node.size,
> -                        stringify_page_sizes(vma->page_sizes.gtt, NULL, 0));
> +                        stringify_page_sizes(vma->resource->page_sizes_gtt,
> +                                             NULL, 0));
>               if (i915_vma_is_ggtt(vma) || i915_vma_is_dpt(vma)) {
>                       switch (vma->ggtt_view.type) {
>                       case I915_GGTT_VIEW_NORMAL:
> diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c 
> b/drivers/gpu/drm/i915/i915_gpu_error.c
> index 5ae812d60abe..1af54ff374f9 100644
> --- a/drivers/gpu/drm/i915/i915_gpu_error.c
> +++ b/drivers/gpu/drm/i915/i915_gpu_error.c
> @@ -1040,9 +1040,9 @@ i915_vma_coredump_create(const struct intel_gt *gt,
>       strcpy(dst->name, vsnap->name);
>       dst->next = NULL;
> 
> -     dst->gtt_offset = vsnap->gtt_offset;
> -     dst->gtt_size = vsnap->gtt_size;
> -     dst->gtt_page_sizes = vsnap->page_sizes;
> +     dst->gtt_offset = vsnap->vma_resource->start;
> +     dst->gtt_size = vsnap->vma_resource->node_size;
> +     dst->gtt_page_sizes = vsnap->vma_resource->page_sizes_gtt;
>       dst->unused = 0;
> 
>       ret = -EINVAL;
> diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
> index 7097c5016431..1d4e448d22d9 100644
> --- a/drivers/gpu/drm/i915/i915_vma.c
> +++ b/drivers/gpu/drm/i915/i915_vma.c
> @@ -298,7 +298,7 @@ static void __vma_bind(struct dma_fence_work *work)
>       struct i915_vma *vma = vw->vma;
> 
>       vma->ops->bind_vma(vw->vm, &vw->stash,
> -                        vma, vw->cache_level, vw->flags);
> +                        vma->resource, vw->cache_level, vw->flags);
>  }
> 
>  static void __vma_release(struct dma_fence_work *work)
> @@ -375,6 +375,21 @@ static int i915_vma_verify_bind_complete(struct i915_vma 
> *vma)
>  #define i915_vma_verify_bind_complete(_vma) 0
>  #endif
> 
> +I915_SELFTEST_EXPORT void
> +i915_vma_resource_init_from_vma(struct i915_vma_resource *vma_res,
> +                             struct i915_vma *vma)
> +{
> +     struct drm_i915_gem_object *obj = vma->obj;
> +
> +     i915_vma_resource_init(vma_res, vma->pages, &vma->page_sizes,
> +                            i915_gem_object_is_readonly(obj),
> +                            i915_gem_object_is_lmem(obj),
> +                            vma->private,
> +                            vma->node.start,
> +                            vma->node.size,
> +                            vma->size);
> +}
> +
>  /**
>   * i915_vma_bind - Sets up PTEs for an VMA in it's corresponding address 
> space.
>   * @vma: VMA to map
> @@ -432,7 +447,7 @@ int i915_vma_bind(struct i915_vma *vma,
>               GEM_WARN_ON(!vma_flags);
>               kfree(vma_res);
>       } else {
> -             i915_vma_resource_init(vma_res);
> +             i915_vma_resource_init_from_vma(vma_res, vma);
>               vma->resource = vma_res;
>       }
>       trace_i915_vma_bind(vma, bind_flags);
> @@ -472,7 +487,8 @@ int i915_vma_bind(struct i915_vma *vma,
>                       if (ret)
>                               return ret;
>               }
> -             vma->ops->bind_vma(vma->vm, NULL, vma, cache_level, bind_flags);
> +             vma->ops->bind_vma(vma->vm, NULL, vma->resource, cache_level,
> +                                bind_flags);
>       }
> 
>       atomic_or(bind_flags, &vma->flags);
> @@ -1778,7 +1794,7 @@ void __i915_vma_evict(struct i915_vma *vma)
> 
>       if (likely(atomic_read(&vma->vm->open))) {
>               trace_i915_vma_unbind(vma);
> -             vma->ops->unbind_vma(vma->vm, vma);
> +             vma->ops->unbind_vma(vma->vm, vma->resource);
>       }
>       atomic_and(~(I915_VMA_BIND_MASK | I915_VMA_ERROR | I915_VMA_GGTT_WRITE),
>                  &vma->flags);
> diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h
> index de0f3e44cdfa..1df57ec832bd 100644
> --- a/drivers/gpu/drm/i915/i915_vma.h
> +++ b/drivers/gpu/drm/i915/i915_vma.h
> @@ -339,12 +339,6 @@ void __iomem *i915_vma_pin_iomap(struct i915_vma *vma);
>   */
>  void i915_vma_unpin_iomap(struct i915_vma *vma);
> 
> -static inline struct page *i915_vma_first_page(struct i915_vma *vma)
> -{
> -     GEM_BUG_ON(!vma->pages);
> -     return sg_page(vma->pages->sgl);
> -}
> -
>  /**
>   * i915_vma_pin_fence - pin fencing state
>   * @vma: vma to pin fencing for
> @@ -445,6 +439,11 @@ i915_vma_get_current_resource(struct i915_vma *vma)
>       return i915_vma_resource_get(vma->resource);
>  }
> 
> +#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
> +void i915_vma_resource_init_from_vma(struct i915_vma_resource *vma_res,
> +                                  struct i915_vma *vma);
> +#endif
> +
>  void i915_vma_module_exit(void);
>  int i915_vma_module_init(void);
> 
> diff --git a/drivers/gpu/drm/i915/i915_vma_resource.c 
> b/drivers/gpu/drm/i915/i915_vma_resource.c
> index 833e987bed2a..c86db89ab5d2 100644
> --- a/drivers/gpu/drm/i915/i915_vma_resource.c
> +++ b/drivers/gpu/drm/i915/i915_vma_resource.c
> @@ -23,15 +23,12 @@ static struct dma_fence_ops unbind_fence_ops = {
>  };
> 
>  /**
> - * i915_vma_resource_init - Initialize a vma resource.
> + * __i915_vma_resource_init - Initialize a vma resource.
>   * @vma_res: The vma resource to initialize
>   *
> - * Initializes a vma resource allocated using i915_vma_resource_alloc().
> - * The reason for having separate allocate and initialize function is that
> - * initialization may need to be performed from under a lock where
> - * allocation is not allowed.
> + * Initializes the private members of a vma resource.
>   */
> -void i915_vma_resource_init(struct i915_vma_resource *vma_res)
> +void __i915_vma_resource_init(struct i915_vma_resource *vma_res)
>  {
>       spin_lock_init(&vma_res->lock);
>       dma_fence_init(&vma_res->unbind_fence, &unbind_fence_ops,
> diff --git a/drivers/gpu/drm/i915/i915_vma_resource.h 
> b/drivers/gpu/drm/i915/i915_vma_resource.h
> index 34744da23072..9872de58268b 100644
> --- a/drivers/gpu/drm/i915/i915_vma_resource.h
> +++ b/drivers/gpu/drm/i915/i915_vma_resource.h
> @@ -9,6 +9,25 @@
>  #include <linux/dma-fence.h>
>  #include <linux/refcount.h>
> 
> +#include "i915_gem.h"
> +
> +struct i915_page_sizes {
> +     /**
> +      * The sg mask of the pages sg_table. i.e the mask of
> +      * the lengths for each sg entry.
> +      */
> +     unsigned int phys;
> +
> +     /**
> +      * The gtt page sizes we are allowed to use given the
> +      * sg mask and the supported page sizes. This will
> +      * express the smallest unit we can use for the whole
> +      * object, as well as the larger sizes we may be able
> +      * to use opportunistically.
> +      */
> +     unsigned int sg;
> +};
> +
>  /**
>   * struct i915_vma_resource - Snapshotted unbind information.
>   * @unbind_fence: Fence to mark unbinding complete. Note that this fence
> @@ -20,6 +39,13 @@
>   * @hold_count: Number of holders blocking the fence from finishing.
>   * The vma itself is keeping a hold, which is released when unbind
>   * is scheduled.
> + * @private: Bind backend private info.
> + * @start: Offset into the address space of bind range start.
> + * @node_size: Size of the allocated range manager node.
> + * @vma_size: Bind size.
> + * @page_sizes_gtt: Resulting page sizes from the bind operation.
> + * @bound_flags: Flags indicating binding status.
> + * @allocated: Backend private data. TODO: Should move into @private.
>   *
>   * The lifetime of a struct i915_vma_resource is from a binding request to
>   * the actual possible asynchronous unbind has completed.
> @@ -29,6 +55,32 @@ struct i915_vma_resource {
>       /* See above for description of the lock. */
>       spinlock_t lock;
>       refcount_t hold_count;
> +
> +     /**
> +      * struct i915_vma_bindinfo - Information needed for async bind
> +      * only but that can be dropped after the bind has taken place.
> +      * Consider making this a separate argument to the bind_vma
> +      * op, coalescing with other arguments like vm, stash, cache_level
> +      * and flags
> +      * @pages: The pages sg-table.
> +      * @page_sizes: Page sizes of the pages.
> +      * @readonly: Whether the vma should be bound read-only.
> +      * @lmem: Whether the vma points to lmem.
> +      */
> +     struct i915_vma_bindinfo {
> +             struct sg_table *pages;
> +             struct i915_page_sizes page_sizes;
> +             bool readonly:1;
> +             bool lmem:1;
> +     } bi;
> +
> +     void *private;
> +     unsigned long start;
> +     unsigned long node_size;
> +     unsigned long vma_size;
> +     u32 page_sizes_gtt;
> +     u32 bound_flags;
> +     bool allocated:1;
>  };
> 
>  bool i915_vma_resource_hold(struct i915_vma_resource *vma_res,
> @@ -41,6 +93,8 @@ struct i915_vma_resource *i915_vma_resource_alloc(void);
> 
>  struct dma_fence *i915_vma_resource_unbind(struct i915_vma_resource 
> *vma_res);
> 
> +void __i915_vma_resource_init(struct i915_vma_resource *vma_res);
> +
>  /**
>   * i915_vma_resource_get - Take a reference on a vma resource
>   * @vma_res: The vma resource on which to take a reference.
> @@ -63,8 +117,47 @@ static inline void i915_vma_resource_put(struct 
> i915_vma_resource *vma_res)
>       dma_fence_put(&vma_res->unbind_fence);
>  }
> 
> -#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
> -void i915_vma_resource_init(struct i915_vma_resource *vma_res);
> -#endif
> +/**
> + * i915_vma_resource_init - Initialize a vma resource.
> + * @vma_res: The vma resource to initialize
> + * @pages: The pages sg-table.
> + * @page_sizes: Page sizes of the pages.
> + * @readonly: Whether the vma should be bound read-only.
> + * @lmem: Whether the vma points to lmem.
> + * @private: Bind backend private info.
> + * @start: Offset into the address space of bind range start.
> + * @node_size: Size of the allocated range manager node.
> + * @size: Bind size.
> + *
> + * Initializes a vma resource allocated using i915_vma_resource_alloc().
> + * The reason for having separate allocate and initialize function is that
> + * initialization may need to be performed from under a lock where
> + * allocation is not allowed.
> + */
> +static inline void i915_vma_resource_init(struct i915_vma_resource *vma_res,
> +                                       struct sg_table *pages,
> +                                       const struct i915_page_sizes 
> *page_sizes,
> +                                       bool readonly,
> +                                       bool lmem,
> +                                       void *private,
> +                                       unsigned long start,
> +                                       unsigned long node_size,
> +                                       unsigned long size)
> +{
> +     __i915_vma_resource_init(vma_res);
> +     vma_res->bi.pages = pages;
> +     vma_res->bi.page_sizes = *page_sizes;
> +     vma_res->bi.readonly = readonly;
> +     vma_res->bi.lmem = lmem;
> +     vma_res->private = private;
> +     vma_res->start = start;
> +     vma_res->node_size = node_size;
> +     vma_res->vma_size = size;
> +}
> +
> +static inline void i915_vma_resource_fini(struct i915_vma_resource *vma_res)
> +{
> +     GEM_BUG_ON(refcount_read(&vma_res->hold_count) != 1);
> +}
> 
>  #endif
> diff --git a/drivers/gpu/drm/i915/i915_vma_snapshot.c 
> b/drivers/gpu/drm/i915/i915_vma_snapshot.c
> index f7333c7a2f5e..69f62c1ca967 100644
> --- a/drivers/gpu/drm/i915/i915_vma_snapshot.c
> +++ b/drivers/gpu/drm/i915/i915_vma_snapshot.c
> @@ -24,11 +24,7 @@ void i915_vma_snapshot_init(struct i915_vma_snapshot 
> *vsnap,
>               assert_object_held(vma->obj);
> 
>       vsnap->name = name;
> -     vsnap->size = vma->size;
>       vsnap->obj_size = vma->obj->base.size;
> -     vsnap->gtt_offset = vma->node.start;
> -     vsnap->gtt_size = vma->node.size;
> -     vsnap->page_sizes = vma->page_sizes.gtt;
>       vsnap->pages = vma->pages;
>       vsnap->pages_rsgt = NULL;
>       vsnap->mr = NULL;
> diff --git a/drivers/gpu/drm/i915/i915_vma_snapshot.h 
> b/drivers/gpu/drm/i915/i915_vma_snapshot.h
> index e74588dd676b..1b08ce9f8576 100644
> --- a/drivers/gpu/drm/i915/i915_vma_snapshot.h
> +++ b/drivers/gpu/drm/i915/i915_vma_snapshot.h
> @@ -23,31 +23,23 @@ struct sg_table;
> 
>  /**
>   * struct i915_vma_snapshot - Snapshot of vma metadata.
> - * @size: The vma size in bytes.
>   * @obj_size: The size of the underlying object in bytes.
> - * @gtt_offset: The gtt offset the vma is bound to.
> - * @gtt_size: The size in bytes allocated for the vma in the GTT.
>   * @pages: The struct sg_table pointing to the pages bound.
>   * @pages_rsgt: The refcounted sg_table holding the reference for @pages if 
> any.
>   * @mr: The memory region pointed for the pages bound.
>   * @kref: Reference for this structure.
>   * @vma_resource: Pointer to the vma resource representing the vma binding.
> - * @page_sizes: The vma GTT page sizes information.
>   * @onstack: Whether the structure shouldn't be freed on final put.
>   * @present: Whether the structure is present and initialized.
>   */
>  struct i915_vma_snapshot {
>       const char *name;
> -     size_t size;
>       size_t obj_size;
> -     size_t gtt_offset;
> -     size_t gtt_size;
>       struct sg_table *pages;
>       struct i915_refct_sgt *pages_rsgt;
>       struct intel_memory_region *mr;
>       struct kref kref;
>       struct i915_vma_resource *vma_resource;
> -     u32 page_sizes;
>       bool onstack:1;
>       bool present:1;
>  };
> diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c 
> b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
> index 54be880e55c3..70b5c47890b9 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
> +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
> @@ -239,11 +239,11 @@ static int lowlevel_hole(struct i915_address_space *vm,
>                        unsigned long end_time)
>  {
>       I915_RND_STATE(seed_prng);
> -     struct i915_vma *mock_vma;
> +     struct i915_vma_resource *mock_vma_res;
>       unsigned int size;
> 
> -     mock_vma = kzalloc(sizeof(*mock_vma), GFP_KERNEL);
> -     if (!mock_vma)
> +     mock_vma_res = kzalloc(sizeof(*mock_vma_res), GFP_KERNEL);
> +     if (!mock_vma_res)
>               return -ENOMEM;
> 
>       /* Keep creating larger objects until one cannot fit into the hole */
> @@ -269,7 +269,7 @@ static int lowlevel_hole(struct i915_address_space *vm,
>                               break;
>               } while (count >>= 1);
>               if (!count) {
> -                     kfree(mock_vma);
> +                     kfree(mock_vma_res);
>                       return -ENOMEM;
>               }
>               GEM_BUG_ON(!order);
> @@ -343,12 +343,12 @@ static int lowlevel_hole(struct i915_address_space *vm,
>                                       break;
>                       }
> 
> -                     mock_vma->pages = obj->mm.pages;
> -                     mock_vma->node.size = BIT_ULL(size);
> -                     mock_vma->node.start = addr;
> +                     mock_vma_res->bi.pages = obj->mm.pages;
> +                     mock_vma_res->node_size = BIT_ULL(size);
> +                     mock_vma_res->start = addr;
> 
>                       with_intel_runtime_pm(vm->gt->uncore->rpm, wakeref)
> -                             vm->insert_entries(vm, mock_vma,
> +                       vm->insert_entries(vm, mock_vma_res,
>                                                  I915_CACHE_NONE, 0);
>               }
>               count = n;
> @@ -371,7 +371,7 @@ static int lowlevel_hole(struct i915_address_space *vm,
>               cleanup_freed_objects(vm->i915);
>       }
> 
> -     kfree(mock_vma);
> +     kfree(mock_vma_res);
>       return 0;
>  }
> 
> @@ -1280,6 +1280,7 @@ static void track_vma_bind(struct i915_vma *vma)
>       atomic_set(&vma->pages_count, I915_VMA_PAGES_ACTIVE);
>       __i915_gem_object_pin_pages(obj);
>       vma->pages = obj->mm.pages;
> +     vma->resource->bi.pages = vma->pages;
> 
>       mutex_lock(&vma->vm->mutex);
>       list_add_tail(&vma->vm_link, &vma->vm->bound_list);
> @@ -1354,7 +1355,7 @@ static int reserve_gtt_with_resource(struct i915_vma 
> *vma, u64 offset)
>                                  obj->cache_level,
>                                  0);
>       if (!err) {
> -             i915_vma_resource_init(vma_res);
> +             i915_vma_resource_init_from_vma(vma_res, vma);
>               vma->resource = vma_res;
>       } else {
>               kfree(vma_res);
> @@ -1533,7 +1534,7 @@ static int insert_gtt_with_resource(struct i915_vma 
> *vma)
>       err = i915_gem_gtt_insert(vm, &vma->node, obj->base.size, 0,
>                                 obj->cache_level, 0, vm->total, 0);
>       if (!err) {
> -             i915_vma_resource_init(vma_res);
> +             i915_vma_resource_init_from_vma(vma_res, vma);
>               vma->resource = vma_res;
>       } else {
>               kfree(vma_res);
> @@ -1958,6 +1959,7 @@ static int igt_cs_tlb(void *arg)
>                       struct i915_vm_pt_stash stash = {};
>                       struct i915_request *rq;
>                       struct i915_gem_ww_ctx ww;
> +                     struct i915_vma_resource *vma_res;
>                       u64 offset;
> 
>                       offset = igt_random_offset(&prng,
> @@ -1978,6 +1980,13 @@ static int igt_cs_tlb(void *arg)
>                       if (err)
>                               goto end;
> 
> +                     vma_res = i915_vma_resource_alloc();
> +                     if (IS_ERR(vma_res)) {
> +                             i915_vma_put_pages(vma);
> +                             err = PTR_ERR(vma_res);
> +                             goto end;
> +                     }
> +
>                       i915_gem_ww_ctx_init(&ww, false);
>  retry:
>                       err = i915_vm_lock_objects(vm, &ww);
> @@ -1999,33 +2008,41 @@ static int igt_cs_tlb(void *arg)
>                                       goto retry;
>                       }
>                       i915_gem_ww_ctx_fini(&ww);
> -                     if (err)
> +                     if (err) {
> +                             kfree(vma_res);
>                               goto end;
> +                     }
> 
> +                     i915_vma_resource_init_from_vma(vma_res, vma);
>                       /* Prime the TLB with the dummy pages */
>                       for (i = 0; i < count; i++) {
> -                             vma->node.start = offset + i * PAGE_SIZE;
> -                             vm->insert_entries(vm, vma, I915_CACHE_NONE, 0);
> +                             vma_res->start = offset + i * PAGE_SIZE;
> +                             vm->insert_entries(vm, vma_res, I915_CACHE_NONE,
> +                                                0);
> 
> -                             rq = submit_batch(ce, vma->node.start);
> +                             rq = submit_batch(ce, vma_res->start);
>                               if (IS_ERR(rq)) {
>                                       err = PTR_ERR(rq);
> +                                     i915_vma_resource_fini(vma_res);
> +                                     kfree(vma_res);
>                                       goto end;
>                               }
>                               i915_request_put(rq);
>                       }
> -
> +                     i915_vma_resource_fini(vma_res);
>                       i915_vma_put_pages(vma);
> 
>                       err = context_sync(ce);
>                       if (err) {
>                               pr_err("%s: dummy setup timed out\n",
>                                      ce->engine->name);
> +                             kfree(vma_res);
>                               goto end;
>                       }
> 
>                       vma = i915_vma_instance(act, vm, NULL);
>                       if (IS_ERR(vma)) {
> +                             kfree(vma_res);
>                               err = PTR_ERR(vma);
>                               goto end;
>                       }
> @@ -2033,19 +2050,22 @@ static int igt_cs_tlb(void *arg)
>                       i915_gem_object_lock(act, NULL);
>                       err = i915_vma_get_pages(vma);
>                       i915_gem_object_unlock(act);
> -                     if (err)
> +                     if (err) {
> +                             kfree(vma_res);
>                               goto end;
> +                     }
> 
> +                     i915_vma_resource_init_from_vma(vma_res, vma);
>                       /* Replace the TLB with target batches */
>                       for (i = 0; i < count; i++) {
>                               struct i915_request *rq;
>                               u32 *cs = batch + i * 64 / sizeof(*cs);
>                               u64 addr;
> 
> -                             vma->node.start = offset + i * PAGE_SIZE;
> -                             vm->insert_entries(vm, vma, I915_CACHE_NONE, 0);
> +                             vma_res->start = offset + i * PAGE_SIZE;
> +                             vm->insert_entries(vm, vma_res, 
> I915_CACHE_NONE, 0);
> 
> -                             addr = vma->node.start + i * 64;
> +                             addr = vma_res->start + i * 64;
>                               cs[4] = MI_NOOP;
>                               cs[6] = lower_32_bits(addr);
>                               cs[7] = upper_32_bits(addr);
> @@ -2054,6 +2074,8 @@ static int igt_cs_tlb(void *arg)
>                               rq = submit_batch(ce, addr);
>                               if (IS_ERR(rq)) {
>                                       err = PTR_ERR(rq);
> +                                     i915_vma_resource_fini(vma_res);
> +                                     kfree(vma_res);
>                                       goto end;
>                               }
> 
> @@ -2070,6 +2092,8 @@ static int igt_cs_tlb(void *arg)
>                       }
>                       end_spin(batch, count - 1);
> 
> +                     i915_vma_resource_fini(vma_res);
> +                     kfree(vma_res);
>                       i915_vma_put_pages(vma);
> 
>                       err = context_sync(ce);
> diff --git a/drivers/gpu/drm/i915/selftests/mock_gtt.c 
> b/drivers/gpu/drm/i915/selftests/mock_gtt.c
> index 1802baf80a17..d40519e3ca38 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_gtt.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_gtt.c
> @@ -33,23 +33,23 @@ static void mock_insert_page(struct i915_address_space 
> *vm,
>  }
> 
>  static void mock_insert_entries(struct i915_address_space *vm,
> -                             struct i915_vma *vma,
> +                             struct i915_vma_resource *vma_res,
>                               enum i915_cache_level level, u32 flags)
>  {
>  }
> 
>  static void mock_bind_ppgtt(struct i915_address_space *vm,
>                           struct i915_vm_pt_stash *stash,
> -                         struct i915_vma *vma,
> +                         struct i915_vma_resource *vma_res,
>                           enum i915_cache_level cache_level,
>                           u32 flags)
>  {
>       GEM_BUG_ON(flags & I915_VMA_GLOBAL_BIND);
> -     set_bit(I915_VMA_LOCAL_BIND_BIT, __i915_vma_flags(vma));
> +     vma_res->bound_flags |= flags;
>  }
> 
>  static void mock_unbind_ppgtt(struct i915_address_space *vm,
> -                           struct i915_vma *vma)
> +                           struct i915_vma_resource *vma_res)
>  {
>  }
> 
> @@ -93,14 +93,14 @@ struct i915_ppgtt *mock_ppgtt(struct drm_i915_private 
> *i915, const char *name)
> 
>  static void mock_bind_ggtt(struct i915_address_space *vm,
>                          struct i915_vm_pt_stash *stash,
> -                        struct i915_vma *vma,
> +                        struct i915_vma_resource *vma_res,
>                          enum i915_cache_level cache_level,
>                          u32 flags)
>  {
>  }
> 
>  static void mock_unbind_ggtt(struct i915_address_space *vm,
> -                          struct i915_vma *vma)
> +                          struct i915_vma_resource *vma_res)
>  {
>  }
> 
> --
> 2.31.1

Reply via email to