On Thu, 21 Oct 2021 at 18:30, Matthew Auld <matthew.william.auld@xxxxxxxxx> wrote: > > On Thu, 21 Oct 2021 at 11:36, Maarten Lankhorst > <maarten.lankhorst@xxxxxxxxxxxxxxx> wrote: > > > > Big delta, but boils down to moving set_pages to i915_vma.c, and removing > > the special handling, all callers use the defaults anyway. We only remap > > in ggtt, so default case will fall through. > > > > Because we still don't require locking in i915_vma_unpin(), handle this by > > using xchg in get_pages(), as it's locked with obj->mutex, and cmpxchg in > > unpin, which only fails if we race a against a new pin. > > > > Signed-off-by: Maarten Lankhorst <maarten.lankhorst@xxxxxxxxxxxxxxx> > > --- > > drivers/gpu/drm/i915/display/intel_dpt.c | 2 - > > drivers/gpu/drm/i915/gt/gen6_ppgtt.c | 15 - > > drivers/gpu/drm/i915/gt/intel_ggtt.c | 345 ---------------- > > drivers/gpu/drm/i915/gt/intel_gtt.c | 13 - > > drivers/gpu/drm/i915/gt/intel_gtt.h | 7 - > > drivers/gpu/drm/i915/gt/intel_ppgtt.c | 12 - > > drivers/gpu/drm/i915/i915_vma.c | 388 ++++++++++++++++-- > > drivers/gpu/drm/i915/i915_vma.h | 3 + > > drivers/gpu/drm/i915/i915_vma_types.h | 1 - > > drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 12 +- > > drivers/gpu/drm/i915/selftests/mock_gtt.c | 4 - > > 11 files changed, 368 insertions(+), 434 deletions(-) > > > > diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c > > index 8f7b1f7534a4..ef428f3fc538 100644 > > --- a/drivers/gpu/drm/i915/display/intel_dpt.c > > +++ b/drivers/gpu/drm/i915/display/intel_dpt.c > > @@ -221,8 +221,6 @@ intel_dpt_create(struct intel_framebuffer *fb) > > > > vm->vma_ops.bind_vma = dpt_bind_vma; > > vm->vma_ops.unbind_vma = dpt_unbind_vma; > > - vm->vma_ops.set_pages = ggtt_set_pages; > > - vm->vma_ops.clear_pages = clear_pages; > > > > vm->pte_encode = gen8_ggtt_pte_encode; > > > > diff --git a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c > > index 5caa1703716e..5c048b4ccd4d 100644 > > --- a/drivers/gpu/drm/i915/gt/gen6_ppgtt.c > > +++ b/drivers/gpu/drm/i915/gt/gen6_ppgtt.c > > @@ -270,19 +270,6 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) > > free_pd(&ppgtt->base.vm, ppgtt->base.pd); > > } > > > > -static int pd_vma_set_pages(struct i915_vma *vma) > > -{ > > - vma->pages = ERR_PTR(-ENODEV); > > - return 0; > > -} > > - > > -static void pd_vma_clear_pages(struct i915_vma *vma) > > -{ > > - GEM_BUG_ON(!vma->pages); > > - > > - vma->pages = NULL; > > -} > > - > > static void pd_vma_bind(struct i915_address_space *vm, > > struct i915_vm_pt_stash *stash, > > struct i915_vma *vma, > > @@ -322,8 +309,6 @@ static void pd_vma_unbind(struct i915_address_space *vm, struct i915_vma *vma) > > } > > > > static const struct i915_vma_ops pd_vma_ops = { > > - .set_pages = pd_vma_set_pages, > > - .clear_pages = pd_vma_clear_pages, > > .bind_vma = pd_vma_bind, > > .unbind_vma = pd_vma_unbind, > > }; > > diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c > > index f17383e76eb7..6da57199bb33 100644 > > --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c > > +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c > > @@ -20,9 +20,6 @@ > > #include "intel_gtt.h" > > #include "gen8_ppgtt.h" > > > > -static int > > -i915_get_ggtt_vma_pages(struct i915_vma *vma); > > - > > static void i915_ggtt_color_adjust(const struct drm_mm_node *node, > > unsigned long color, > > u64 *start, > > @@ -875,21 +872,6 @@ static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size) > > return 0; > > } > > > > -int ggtt_set_pages(struct i915_vma *vma) > > -{ > > - int ret; > > - > > - GEM_BUG_ON(vma->pages); > > - > > - ret = i915_get_ggtt_vma_pages(vma); > > - if (ret) > > - return ret; > > - > > - vma->page_sizes = vma->obj->mm.page_sizes; > > - > > - return 0; > > -} > > - > > static void gen6_gmch_remove(struct i915_address_space *vm) > > { > > struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); > > @@ -950,8 +932,6 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) > > > > ggtt->vm.vma_ops.bind_vma = ggtt_bind_vma; > > ggtt->vm.vma_ops.unbind_vma = ggtt_unbind_vma; > > - ggtt->vm.vma_ops.set_pages = ggtt_set_pages; > > - ggtt->vm.vma_ops.clear_pages = clear_pages; > > > > ggtt->vm.pte_encode = gen8_ggtt_pte_encode; > > > > @@ -1100,8 +1080,6 @@ static int gen6_gmch_probe(struct i915_ggtt *ggtt) > > > > ggtt->vm.vma_ops.bind_vma = ggtt_bind_vma; > > ggtt->vm.vma_ops.unbind_vma = ggtt_unbind_vma; > > - ggtt->vm.vma_ops.set_pages = ggtt_set_pages; > > - ggtt->vm.vma_ops.clear_pages = clear_pages; > > > > return ggtt_probe_common(ggtt, size); > > } > > @@ -1145,8 +1123,6 @@ static int i915_gmch_probe(struct i915_ggtt *ggtt) > > > > ggtt->vm.vma_ops.bind_vma = ggtt_bind_vma; > > ggtt->vm.vma_ops.unbind_vma = ggtt_unbind_vma; > > - ggtt->vm.vma_ops.set_pages = ggtt_set_pages; > > - ggtt->vm.vma_ops.clear_pages = clear_pages; > > > > if (unlikely(ggtt->do_idle_maps)) > > drm_notice(&i915->drm, > > @@ -1294,324 +1270,3 @@ void i915_ggtt_resume(struct i915_ggtt *ggtt) > > > > intel_ggtt_restore_fences(ggtt); > > } > > - > > -static struct scatterlist * > > -rotate_pages(struct drm_i915_gem_object *obj, unsigned int offset, > > - unsigned int width, unsigned int height, > > - unsigned int src_stride, unsigned int dst_stride, > > - struct sg_table *st, struct scatterlist *sg) > > -{ > > - unsigned int column, row; > > - unsigned int src_idx; > > - > > - for (column = 0; column < width; column++) { > > - unsigned int left; > > - > > - src_idx = src_stride * (height - 1) + column + offset; > > - for (row = 0; row < height; row++) { > > - st->nents++; > > - /* > > - * We don't need the pages, but need to initialize > > - * the entries so the sg list can be happily traversed. > > - * The only thing we need are DMA addresses. > > - */ > > - sg_set_page(sg, NULL, I915_GTT_PAGE_SIZE, 0); > > - sg_dma_address(sg) = > > - i915_gem_object_get_dma_address(obj, src_idx); > > - sg_dma_len(sg) = I915_GTT_PAGE_SIZE; > > - sg = sg_next(sg); > > - src_idx -= src_stride; > > - } > > - > > - left = (dst_stride - height) * I915_GTT_PAGE_SIZE; > > - > > - if (!left) > > - continue; > > - > > - st->nents++; > > - > > - /* > > - * The DE ignores the PTEs for the padding tiles, the sg entry > > - * here is just a conenience to indicate how many padding PTEs > > - * to insert at this spot. > > - */ > > - sg_set_page(sg, NULL, left, 0); > > - sg_dma_address(sg) = 0; > > - sg_dma_len(sg) = left; > > - sg = sg_next(sg); > > - } > > - > > - return sg; > > -} > > - > > -static noinline struct sg_table * > > -intel_rotate_pages(struct intel_rotation_info *rot_info, > > - struct drm_i915_gem_object *obj) > > -{ > > - unsigned int size = intel_rotation_info_size(rot_info); > > - struct drm_i915_private *i915 = to_i915(obj->base.dev); > > - struct sg_table *st; > > - struct scatterlist *sg; > > - int ret = -ENOMEM; > > - int i; > > - > > - /* Allocate target SG list. */ > > - st = kmalloc(sizeof(*st), GFP_KERNEL); > > - if (!st) > > - goto err_st_alloc; > > - > > - ret = sg_alloc_table(st, size, GFP_KERNEL); > > - if (ret) > > - goto err_sg_alloc; > > - > > - st->nents = 0; > > - sg = st->sgl; > > - > > - for (i = 0 ; i < ARRAY_SIZE(rot_info->plane); i++) > > - sg = rotate_pages(obj, rot_info->plane[i].offset, > > - rot_info->plane[i].width, rot_info->plane[i].height, > > - rot_info->plane[i].src_stride, > > - rot_info->plane[i].dst_stride, > > - st, sg); > > - > > - return st; > > - > > -err_sg_alloc: > > - kfree(st); > > -err_st_alloc: > > - > > - drm_dbg(&i915->drm, "Failed to create rotated mapping for object size %zu! (%ux%u tiles, %u pages)\n", > > - obj->base.size, rot_info->plane[0].width, > > - rot_info->plane[0].height, size); > > - > > - return ERR_PTR(ret); > > -} > > - > > -static struct scatterlist * > > -remap_pages(struct drm_i915_gem_object *obj, > > - unsigned int offset, unsigned int alignment_pad, > > - unsigned int width, unsigned int height, > > - unsigned int src_stride, unsigned int dst_stride, > > - struct sg_table *st, struct scatterlist *sg) > > -{ > > - unsigned int row; > > - > > - if (alignment_pad) { > > - st->nents++; > > - > > - /* > > - * The DE ignores the PTEs for the padding tiles, the sg entry > > - * here is just a convenience to indicate how many padding PTEs > > - * to insert at this spot. > > - */ > > - sg_set_page(sg, NULL, alignment_pad * 4096, 0); > > - sg_dma_address(sg) = 0; > > - sg_dma_len(sg) = alignment_pad * 4096; > > - sg = sg_next(sg); > > - } > > - > > - for (row = 0; row < height; row++) { > > - unsigned int left = width * I915_GTT_PAGE_SIZE; > > - > > - while (left) { > > - dma_addr_t addr; > > - unsigned int length; > > - > > - /* > > - * We don't need the pages, but need to initialize > > - * the entries so the sg list can be happily traversed. > > - * The only thing we need are DMA addresses. > > - */ > > - > > - addr = i915_gem_object_get_dma_address_len(obj, offset, &length); > > - > > - length = min(left, length); > > - > > - st->nents++; > > - > > - sg_set_page(sg, NULL, length, 0); > > - sg_dma_address(sg) = addr; > > - sg_dma_len(sg) = length; > > - sg = sg_next(sg); > > - > > - offset += length / I915_GTT_PAGE_SIZE; > > - left -= length; > > - } > > - > > - offset += src_stride - width; > > - > > - left = (dst_stride - width) * I915_GTT_PAGE_SIZE; > > - > > - if (!left) > > - continue; > > - > > - st->nents++; > > - > > - /* > > - * The DE ignores the PTEs for the padding tiles, the sg entry > > - * here is just a conenience to indicate how many padding PTEs > > - * to insert at this spot. > > - */ > > - sg_set_page(sg, NULL, left, 0); > > - sg_dma_address(sg) = 0; > > - sg_dma_len(sg) = left; > > - sg = sg_next(sg); > > - } > > - > > - return sg; > > -} > > - > > -static noinline struct sg_table * > > -intel_remap_pages(struct intel_remapped_info *rem_info, > > - struct drm_i915_gem_object *obj) > > -{ > > - unsigned int size = intel_remapped_info_size(rem_info); > > - struct drm_i915_private *i915 = to_i915(obj->base.dev); > > - struct sg_table *st; > > - struct scatterlist *sg; > > - unsigned int gtt_offset = 0; > > - int ret = -ENOMEM; > > - int i; > > - > > - /* Allocate target SG list. */ > > - st = kmalloc(sizeof(*st), GFP_KERNEL); > > - if (!st) > > - goto err_st_alloc; > > - > > - ret = sg_alloc_table(st, size, GFP_KERNEL); > > - if (ret) > > - goto err_sg_alloc; > > - > > - st->nents = 0; > > - sg = st->sgl; > > - > > - for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++) { > > - unsigned int alignment_pad = 0; > > - > > - if (rem_info->plane_alignment) > > - alignment_pad = ALIGN(gtt_offset, rem_info->plane_alignment) - gtt_offset; > > - > > - sg = remap_pages(obj, > > - rem_info->plane[i].offset, alignment_pad, > > - rem_info->plane[i].width, rem_info->plane[i].height, > > - rem_info->plane[i].src_stride, rem_info->plane[i].dst_stride, > > - st, sg); > > - > > - gtt_offset += alignment_pad + > > - rem_info->plane[i].dst_stride * rem_info->plane[i].height; > > - } > > - > > - i915_sg_trim(st); > > - > > - return st; > > - > > -err_sg_alloc: > > - kfree(st); > > -err_st_alloc: > > - > > - drm_dbg(&i915->drm, "Failed to create remapped mapping for object size %zu! (%ux%u tiles, %u pages)\n", > > - obj->base.size, rem_info->plane[0].width, > > - rem_info->plane[0].height, size); > > - > > - return ERR_PTR(ret); > > -} > > - > > -static noinline struct sg_table * > > -intel_partial_pages(const struct i915_ggtt_view *view, > > - struct drm_i915_gem_object *obj) > > -{ > > - struct sg_table *st; > > - struct scatterlist *sg, *iter; > > - unsigned int count = view->partial.size; > > - unsigned int offset; > > - int ret = -ENOMEM; > > - > > - st = kmalloc(sizeof(*st), GFP_KERNEL); > > - if (!st) > > - goto err_st_alloc; > > - > > - ret = sg_alloc_table(st, count, GFP_KERNEL); > > - if (ret) > > - goto err_sg_alloc; > > - > > - iter = i915_gem_object_get_sg_dma(obj, view->partial.offset, &offset); > > - GEM_BUG_ON(!iter); > > - > > - sg = st->sgl; > > - st->nents = 0; > > - do { > > - unsigned int len; > > - > > - len = min(sg_dma_len(iter) - (offset << PAGE_SHIFT), > > - count << PAGE_SHIFT); > > - sg_set_page(sg, NULL, len, 0); > > - sg_dma_address(sg) = > > - sg_dma_address(iter) + (offset << PAGE_SHIFT); > > - sg_dma_len(sg) = len; > > - > > - st->nents++; > > - count -= len >> PAGE_SHIFT; > > - if (count == 0) { > > - sg_mark_end(sg); > > - i915_sg_trim(st); /* Drop any unused tail entries. */ > > - > > - return st; > > - } > > - > > - sg = __sg_next(sg); > > - iter = __sg_next(iter); > > - offset = 0; > > - } while (1); > > - > > -err_sg_alloc: > > - kfree(st); > > -err_st_alloc: > > - return ERR_PTR(ret); > > -} > > - > > -static int > > -i915_get_ggtt_vma_pages(struct i915_vma *vma) > > -{ > > - int ret; > > - > > - /* > > - * The vma->pages are only valid within the lifespan of the borrowed > > - * obj->mm.pages. When the obj->mm.pages sg_table is regenerated, so > > - * must be the vma->pages. A simple rule is that vma->pages must only > > - * be accessed when the obj->mm.pages are pinned. > > - */ > > - GEM_BUG_ON(!i915_gem_object_has_pinned_pages(vma->obj)); > > - > > - switch (vma->ggtt_view.type) { > > - default: > > - GEM_BUG_ON(vma->ggtt_view.type); > > - fallthrough; > > - case I915_GGTT_VIEW_NORMAL: > > - vma->pages = vma->obj->mm.pages; > > - return 0; > > - > > - case I915_GGTT_VIEW_ROTATED: > > - vma->pages = > > - intel_rotate_pages(&vma->ggtt_view.rotated, vma->obj); > > - break; > > - > > - case I915_GGTT_VIEW_REMAPPED: > > - vma->pages = > > - intel_remap_pages(&vma->ggtt_view.remapped, vma->obj); > > - break; > > - > > - case I915_GGTT_VIEW_PARTIAL: > > - vma->pages = intel_partial_pages(&vma->ggtt_view, vma->obj); > > - break; > > - } > > - > > - ret = 0; > > - if (IS_ERR(vma->pages)) { > > - ret = PTR_ERR(vma->pages); > > - vma->pages = NULL; > > - drm_err(&vma->vm->i915->drm, > > - "Failed to get pages for VMA view type %u (%d)!\n", > > - vma->ggtt_view.type, ret); > > - } > > - return ret; > > -} > > diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c > > index 67d14afa6623..12eed5fcb17a 100644 > > --- a/drivers/gpu/drm/i915/gt/intel_gtt.c > > +++ b/drivers/gpu/drm/i915/gt/intel_gtt.c > > @@ -221,19 +221,6 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass) > > INIT_LIST_HEAD(&vm->bound_list); > > } > > > > -void clear_pages(struct i915_vma *vma) > > -{ > > - GEM_BUG_ON(!vma->pages); > > - > > - if (vma->pages != vma->obj->mm.pages) { > > - sg_free_table(vma->pages); > > - kfree(vma->pages); > > - } > > - vma->pages = NULL; > > - > > - memset(&vma->page_sizes, 0, sizeof(vma->page_sizes)); > > -} > > - > > void *__px_vaddr(struct drm_i915_gem_object *p) > > { > > enum i915_map_type type; > > diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h > > index bc6750263359..306e7645fdc5 100644 > > --- a/drivers/gpu/drm/i915/gt/intel_gtt.h > > +++ b/drivers/gpu/drm/i915/gt/intel_gtt.h > > @@ -206,9 +206,6 @@ struct i915_vma_ops { > > */ > > void (*unbind_vma)(struct i915_address_space *vm, > > struct i915_vma *vma); > > - > > - int (*set_pages)(struct i915_vma *vma); > > - void (*clear_pages)(struct i915_vma *vma); > > }; > > > > struct i915_address_space { > > @@ -594,10 +591,6 @@ release_pd_entry(struct i915_page_directory * const pd, > > const struct drm_i915_gem_object * const scratch); > > void gen6_ggtt_invalidate(struct i915_ggtt *ggtt); > > > > -int ggtt_set_pages(struct i915_vma *vma); > > -int ppgtt_set_pages(struct i915_vma *vma); > > -void clear_pages(struct i915_vma *vma); > > - > > void ppgtt_bind_vma(struct i915_address_space *vm, > > struct i915_vm_pt_stash *stash, > > struct i915_vma *vma, > > diff --git a/drivers/gpu/drm/i915/gt/intel_ppgtt.c b/drivers/gpu/drm/i915/gt/intel_ppgtt.c > > index 4396bfd630d8..083b3090c69c 100644 > > --- a/drivers/gpu/drm/i915/gt/intel_ppgtt.c > > +++ b/drivers/gpu/drm/i915/gt/intel_ppgtt.c > > @@ -289,16 +289,6 @@ void i915_vm_free_pt_stash(struct i915_address_space *vm, > > } > > } > > > > -int ppgtt_set_pages(struct i915_vma *vma) > > -{ > > - GEM_BUG_ON(vma->pages); > > - > > - vma->pages = vma->obj->mm.pages; > > - vma->page_sizes = vma->obj->mm.page_sizes; > > - > > - return 0; > > -} > > - > > void ppgtt_init(struct i915_ppgtt *ppgtt, struct intel_gt *gt, > > unsigned long lmem_pt_obj_flags) > > { > > @@ -315,6 +305,4 @@ void ppgtt_init(struct i915_ppgtt *ppgtt, struct intel_gt *gt, > > > > ppgtt->vm.vma_ops.bind_vma = ppgtt_bind_vma; > > ppgtt->vm.vma_ops.unbind_vma = ppgtt_unbind_vma; > > - ppgtt->vm.vma_ops.set_pages = ppgtt_set_pages; > > - ppgtt->vm.vma_ops.clear_pages = clear_pages; > > } > > diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c > > index ac09b685678a..bacc8d68e495 100644 > > --- a/drivers/gpu/drm/i915/i915_vma.c > > +++ b/drivers/gpu/drm/i915/i915_vma.c > > @@ -112,7 +112,6 @@ vma_create(struct drm_i915_gem_object *obj, > > return ERR_PTR(-ENOMEM); > > > > kref_init(&vma->ref); > > - mutex_init(&vma->pages_mutex); > > vma->vm = i915_vm_get(vm); > > vma->ops = &vm->vma_ops; > > vma->obj = obj; > > @@ -789,10 +788,343 @@ static bool try_qad_pin(struct i915_vma *vma, unsigned int flags) > > return pinned; > > } > > > > -static int vma_get_pages(struct i915_vma *vma) > > + > > + > > +static struct scatterlist * > > +rotate_pages(struct drm_i915_gem_object *obj, unsigned int offset, > > + unsigned int width, unsigned int height, > > + unsigned int src_stride, unsigned int dst_stride, > > + struct sg_table *st, struct scatterlist *sg) > > { > > - int err = 0; > > - bool pinned_pages = true; > > + unsigned int column, row; > > + unsigned int src_idx; > > + > > + for (column = 0; column < width; column++) { > > + unsigned int left; > > + > > + src_idx = src_stride * (height - 1) + column + offset; > > + for (row = 0; row < height; row++) { > > + st->nents++; > > + /* > > + * We don't need the pages, but need to initialize > > + * the entries so the sg list can be happily traversed. > > + * The only thing we need are DMA addresses. > > + */ > > + sg_set_page(sg, NULL, I915_GTT_PAGE_SIZE, 0); > > + sg_dma_address(sg) = > > + i915_gem_object_get_dma_address(obj, src_idx); > > + sg_dma_len(sg) = I915_GTT_PAGE_SIZE; > > + sg = sg_next(sg); > > + src_idx -= src_stride; > > + } > > + > > + left = (dst_stride - height) * I915_GTT_PAGE_SIZE; > > + > > + if (!left) > > + continue; > > + > > + st->nents++; > > + > > + /* > > + * The DE ignores the PTEs for the padding tiles, the sg entry > > + * here is just a conenience to indicate how many padding PTEs > > + * to insert at this spot. > > + */ > > + sg_set_page(sg, NULL, left, 0); > > + sg_dma_address(sg) = 0; > > + sg_dma_len(sg) = left; > > + sg = sg_next(sg); > > + } > > + > > + return sg; > > +} > > + > > +static noinline struct sg_table * > > +intel_rotate_pages(struct intel_rotation_info *rot_info, > > + struct drm_i915_gem_object *obj) > > +{ > > + unsigned int size = intel_rotation_info_size(rot_info); > > + struct drm_i915_private *i915 = to_i915(obj->base.dev); > > + struct sg_table *st; > > + struct scatterlist *sg; > > + int ret = -ENOMEM; > > + int i; > > + > > + /* Allocate target SG list. */ > > + st = kmalloc(sizeof(*st), GFP_KERNEL); > > + if (!st) > > + goto err_st_alloc; > > + > > + ret = sg_alloc_table(st, size, GFP_KERNEL); > > + if (ret) > > + goto err_sg_alloc; > > + > > + st->nents = 0; > > + sg = st->sgl; > > + > > + for (i = 0 ; i < ARRAY_SIZE(rot_info->plane); i++) > > + sg = rotate_pages(obj, rot_info->plane[i].offset, > > + rot_info->plane[i].width, rot_info->plane[i].height, > > + rot_info->plane[i].src_stride, > > + rot_info->plane[i].dst_stride, > > + st, sg); > > + > > + return st; > > + > > +err_sg_alloc: > > + kfree(st); > > +err_st_alloc: > > + > > + drm_dbg(&i915->drm, "Failed to create rotated mapping for object size %zu! (%ux%u tiles, %u pages)\n", > > + obj->base.size, rot_info->plane[0].width, > > + rot_info->plane[0].height, size); > > + > > + return ERR_PTR(ret); > > +} > > + > > +static struct scatterlist * > > +remap_pages(struct drm_i915_gem_object *obj, > > + unsigned int offset, unsigned int alignment_pad, > > + unsigned int width, unsigned int height, > > + unsigned int src_stride, unsigned int dst_stride, > > + struct sg_table *st, struct scatterlist *sg) > > +{ > > + unsigned int row; > > + > > + if (alignment_pad) { > > + st->nents++; > > + > > + /* > > + * The DE ignores the PTEs for the padding tiles, the sg entry > > + * here is just a convenience to indicate how many padding PTEs > > + * to insert at this spot. > > + */ > > + sg_set_page(sg, NULL, alignment_pad * 4096, 0); > > + sg_dma_address(sg) = 0; > > + sg_dma_len(sg) = alignment_pad * 4096; > > + sg = sg_next(sg); > > + } > > + > > + for (row = 0; row < height; row++) { > > + unsigned int left = width * I915_GTT_PAGE_SIZE; > > + > > + while (left) { > > + dma_addr_t addr; > > + unsigned int length; > > + > > + /* > > + * We don't need the pages, but need to initialize > > + * the entries so the sg list can be happily traversed. > > + * The only thing we need are DMA addresses. > > + */ > > + > > + addr = i915_gem_object_get_dma_address_len(obj, offset, &length); > > + > > + length = min(left, length); > > + > > + st->nents++; > > + > > + sg_set_page(sg, NULL, length, 0); > > + sg_dma_address(sg) = addr; > > + sg_dma_len(sg) = length; > > + sg = sg_next(sg); > > + > > + offset += length / I915_GTT_PAGE_SIZE; > > + left -= length; > > + } > > + > > + offset += src_stride - width; > > + > > + left = (dst_stride - width) * I915_GTT_PAGE_SIZE; > > + > > + if (!left) > > + continue; > > + > > + st->nents++; > > + > > + /* > > + * The DE ignores the PTEs for the padding tiles, the sg entry > > + * here is just a conenience to indicate how many padding PTEs > > + * to insert at this spot. > > + */ > > + sg_set_page(sg, NULL, left, 0); > > + sg_dma_address(sg) = 0; > > + sg_dma_len(sg) = left; > > + sg = sg_next(sg); > > + } > > + > > + return sg; > > +} > > + > > +static noinline struct sg_table * > > +intel_remap_pages(struct intel_remapped_info *rem_info, > > + struct drm_i915_gem_object *obj) > > +{ > > + unsigned int size = intel_remapped_info_size(rem_info); > > + struct drm_i915_private *i915 = to_i915(obj->base.dev); > > + struct sg_table *st; > > + struct scatterlist *sg; > > + unsigned int gtt_offset = 0; > > + int ret = -ENOMEM; > > + int i; > > + > > + /* Allocate target SG list. */ > > + st = kmalloc(sizeof(*st), GFP_KERNEL); > > + if (!st) > > + goto err_st_alloc; > > + > > + ret = sg_alloc_table(st, size, GFP_KERNEL); > > + if (ret) > > + goto err_sg_alloc; > > + > > + st->nents = 0; > > + sg = st->sgl; > > + > > + for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++) { > > + unsigned int alignment_pad = 0; > > + > > + if (rem_info->plane_alignment) > > + alignment_pad = ALIGN(gtt_offset, rem_info->plane_alignment) - gtt_offset; > > + > > + sg = remap_pages(obj, > > + rem_info->plane[i].offset, alignment_pad, > > + rem_info->plane[i].width, rem_info->plane[i].height, > > + rem_info->plane[i].src_stride, rem_info->plane[i].dst_stride, > > + st, sg); > > + > > + gtt_offset += alignment_pad + > > + rem_info->plane[i].dst_stride * rem_info->plane[i].height; > > + } > > + > > + i915_sg_trim(st); > > + > > + return st; > > + > > +err_sg_alloc: > > + kfree(st); > > +err_st_alloc: > > + > > + drm_dbg(&i915->drm, "Failed to create remapped mapping for object size %zu! (%ux%u tiles, %u pages)\n", > > + obj->base.size, rem_info->plane[0].width, > > + rem_info->plane[0].height, size); > > + > > + return ERR_PTR(ret); > > +} > > + > > +static noinline struct sg_table * > > +intel_partial_pages(const struct i915_ggtt_view *view, > > + struct drm_i915_gem_object *obj) > > +{ > > + struct sg_table *st; > > + struct scatterlist *sg, *iter; > > + unsigned int count = view->partial.size; > > + unsigned int offset; > > + int ret = -ENOMEM; > > + > > + st = kmalloc(sizeof(*st), GFP_KERNEL); > > + if (!st) > > + goto err_st_alloc; > > + > > + ret = sg_alloc_table(st, count, GFP_KERNEL); > > + if (ret) > > + goto err_sg_alloc; > > + > > + iter = i915_gem_object_get_sg_dma(obj, view->partial.offset, &offset); > > + GEM_BUG_ON(!iter); > > + > > + sg = st->sgl; > > + st->nents = 0; > > + do { > > + unsigned int len; > > + > > + len = min(sg_dma_len(iter) - (offset << PAGE_SHIFT), > > + count << PAGE_SHIFT); > > + sg_set_page(sg, NULL, len, 0); > > + sg_dma_address(sg) = > > + sg_dma_address(iter) + (offset << PAGE_SHIFT); > > + sg_dma_len(sg) = len; > > + > > + st->nents++; > > + count -= len >> PAGE_SHIFT; > > + if (count == 0) { > > + sg_mark_end(sg); > > + i915_sg_trim(st); /* Drop any unused tail entries. */ > > + > > + return st; > > + } > > + > > + sg = __sg_next(sg); > > + iter = __sg_next(iter); > > + offset = 0; > > + } while (1); > > + > > +err_sg_alloc: > > + kfree(st); > > +err_st_alloc: > > + return ERR_PTR(ret); > > +} > > + > > +static int > > +__i915_vma_get_pages(struct i915_vma *vma) > > +{ > > + struct sg_table *pages; > > + int ret; > > + > > + /* > > + * The vma->pages are only valid within the lifespan of the borrowed > > + * obj->mm.pages. When the obj->mm.pages sg_table is regenerated, so > > + * must be the vma->pages. A simple rule is that vma->pages must only > > + * be accessed when the obj->mm.pages are pinned. > > + */ > > + GEM_BUG_ON(!i915_gem_object_has_pinned_pages(vma->obj)); > > + > > + switch (vma->ggtt_view.type) { > > + default: > > + GEM_BUG_ON(vma->ggtt_view.type); > > + fallthrough; > > + case I915_GGTT_VIEW_NORMAL: > > + pages = vma->obj->mm.pages; > > + break; > > + > > + case I915_GGTT_VIEW_ROTATED: > > + pages = > > + intel_rotate_pages(&vma->ggtt_view.rotated, vma->obj); > > + break; > > + > > + case I915_GGTT_VIEW_REMAPPED: > > + pages = > > + intel_remap_pages(&vma->ggtt_view.remapped, vma->obj); > > + break; > > + > > + case I915_GGTT_VIEW_PARTIAL: > > + pages = intel_partial_pages(&vma->ggtt_view, vma->obj); > > + break; > > + } > > + > > + ret = 0; > > + /* gen6 ppgtt doesn't have backing pages, special-case it */ > > + if (IS_ERR(pages) && pages != ERR_PTR(-ENODEV)) { > > Where does this -ENODEV come from? AFAIK for the gen6 thing mm.pages = > ZERO_SIZE_PTR. Also, just checking, I assume we always hit the > VIEW_NORMAL for that? > > > + ret = PTR_ERR(pages); > > + pages = NULL; > > + drm_err(&vma->vm->i915->drm, > > + "Failed to get pages for VMA view type %u (%d)!\n", > > + vma->ggtt_view.type, ret); > > Can we just return here? > > > + } > > + > > + pages = xchg(&vma->pages, pages); > > + > > + /* did we race against a put_pages? */ > > + if (pages && pages != vma->obj->mm.pages) { > > + sg_free_table(vma->pages); > > + kfree(vma->pages); > > + } > > What is this race exactly, can we add some more details here please? > So we can more easily evaluate the lockless trickery here. Ok, the lockless stuff just gets removed by the end of the series.