Message ID | 20210518082701.997251-15-thomas.hellstrom@linux.intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | drm/i915: Move LMEM (VRAM) management over to TTM | expand |
On 5/18/21 10:27 AM, Thomas Hellström wrote: > From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> > > Use the ttm handlers for servicing page faults, and vm_access. > > Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> LGTM. Just need to make sure we don't forget about the caching. Reviewed-by: Thomas Hellström <thomas.hellstrom@linux.intel.com> > --- > drivers/gpu/drm/i915/gem/i915_gem_mman.c | 17 ++- > drivers/gpu/drm/i915/gem/i915_gem_mman.h | 2 + > .../gpu/drm/i915/gem/i915_gem_object_types.h | 1 + > drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 105 +++++++++++++++++- > 4 files changed, 118 insertions(+), 7 deletions(-) > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c > index 65db290efd16..2bf89349dde9 100644 > --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c > +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c > @@ -19,6 +19,7 @@ > #include "i915_gem_mman.h" > #include "i915_trace.h" > #include "i915_user_extensions.h" > +#include "i915_gem_ttm.h" > #include "i915_vma.h" > > static inline bool > @@ -789,7 +790,7 @@ i915_gem_mmap_offset_ioctl(struct drm_device *dev, void *data, > return __assign_mmap_offset(file, args->handle, type, &args->offset); > } > > -static void vm_open(struct vm_area_struct *vma) > +void i915_gem_mmap_vm_open(struct vm_area_struct *vma) > { > struct i915_mmap_offset *mmo = vma->vm_private_data; > struct drm_i915_gem_object *obj = mmo->obj; > @@ -798,7 +799,7 @@ static void vm_open(struct vm_area_struct *vma) > i915_gem_object_get(obj); > } > > -static void vm_close(struct vm_area_struct *vma) > +void i915_gem_mmap_vm_close(struct vm_area_struct *vma) > { > struct i915_mmap_offset *mmo = vma->vm_private_data; > struct drm_i915_gem_object *obj = mmo->obj; > @@ -810,15 +811,15 @@ static void vm_close(struct vm_area_struct *vma) > static const struct vm_operations_struct vm_ops_gtt = { > .fault = vm_fault_gtt, > .access = vm_access, > - .open = vm_open, > - .close = vm_close, > + .open = i915_gem_mmap_vm_open, > + .close = i915_gem_mmap_vm_close, > }; > > static const struct vm_operations_struct vm_ops_cpu = { > .fault = vm_fault_cpu, > .access = vm_access, > - .open = vm_open, > - .close = vm_close, > + .open = i915_gem_mmap_vm_open, > + .close = i915_gem_mmap_vm_close, > }; > > static int singleton_release(struct inode *inode, struct file *file) > @@ -953,6 +954,10 @@ int i915_gem_mmap(struct file *filp, struct vm_area_struct *vma) > } > vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); > > + /* override ops per-object if desired */ > + if (obj->ops->mmap_ops) > + vma->vm_ops = obj->ops->mmap_ops; > + > return 0; > } > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.h b/drivers/gpu/drm/i915/gem/i915_gem_mman.h > index efee9e0d2508..e5bd02a6db12 100644 > --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.h > +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.h > @@ -28,5 +28,7 @@ void __i915_gem_object_release_mmap_gtt(struct drm_i915_gem_object *obj); > void i915_gem_object_release_mmap_gtt(struct drm_i915_gem_object *obj); > > void i915_gem_object_release_mmap_offset(struct drm_i915_gem_object *obj); > +void i915_gem_mmap_vm_open(struct vm_area_struct *vma); > +void i915_gem_mmap_vm_close(struct vm_area_struct *vma); > > #endif > 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 b350765e1935..31d828e91cf4 100644 > --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h > +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h > @@ -79,6 +79,7 @@ struct drm_i915_gem_object_ops { > void (*delayed_free)(struct drm_i915_gem_object *obj); > void (*release)(struct drm_i915_gem_object *obj); > > + const struct vm_operations_struct *mmap_ops; > const char *name; /* friendly name for debug, e.g. lockdep classes */ > }; > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c > index 790f5ec45c4d..fe9ac50b2470 100644 > --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c > +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c > @@ -14,6 +14,7 @@ > #include "gem/i915_gem_region.h" > #include "gem/i915_gem_ttm.h" > #include "gem/i915_gem_ttm_bo_util.h" > +#include "gem/i915_gem_mman.h" > > #define I915_PL_LMEM0 TTM_PL_PRIV > #define I915_PL_SYSTEM TTM_PL_SYSTEM > @@ -345,6 +346,44 @@ static int i915_ttm_move(struct ttm_buffer_object *bo, bool evict, > return 0; > } > > +static int i915_ttm_io_mem_reserve(struct ttm_device *bdev, struct ttm_resource *mem) > +{ > + if (mem->mem_type < I915_PL_LMEM0) > + return 0; > + > + /* We may need to revisit this later, but this allows all caching to be used in mmap */ > + mem->bus.caching = ttm_cached; > + mem->bus.is_iomem = true; > + > + return 0; > +} > + > +static unsigned long i915_ttm_io_mem_pfn(struct ttm_buffer_object *bo, > + unsigned long page_offset) > +{ > + struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); > + struct sg_table *sgt = obj->ttm.cached_io_st; > + struct scatterlist *sg; > + unsigned int i; > + > + GEM_WARN_ON(bo->ttm); > + > + for_each_sgtable_dma_sg(sgt, sg, i) { > + unsigned long sg_max = sg->length >> PAGE_SHIFT; > + > + if (page_offset < sg_max) { > + unsigned long base = > + obj->mm.region->iomap.base - obj->mm.region->region.start; > + > + return ((base + sg_dma_address(sg)) >> PAGE_SHIFT) + page_offset; > + } > + > + page_offset -= sg_max; > + } > + GEM_BUG_ON(1); > + return 0; > +} > + > struct ttm_device_funcs i915_ttm_bo_driver = { > .ttm_tt_create = i915_ttm_tt_create, > .ttm_tt_unpopulate = i915_ttm_tt_unpopulate, > @@ -355,6 +394,8 @@ struct ttm_device_funcs i915_ttm_bo_driver = { > .verify_access = NULL, > .swap_notify = i915_ttm_swap_notify, > .delete_mem_notify = i915_ttm_delete_mem_notify, > + .io_mem_reserve = i915_ttm_io_mem_reserve, > + .io_mem_pfn = i915_ttm_io_mem_pfn, > }; > > static int i915_ttm_get_pages(struct drm_i915_gem_object *obj) > @@ -454,7 +495,68 @@ static void i915_ttm_delayed_free(struct drm_i915_gem_object *obj) > ttm_bo_put(i915_gem_to_ttm(obj)); > } > > -static const struct drm_i915_gem_object_ops i915_gem_ttm_obj_ops = { > +static vm_fault_t vm_fault_ttm(struct vm_fault *vmf) > +{ > + struct vm_area_struct *area = vmf->vma; > + struct i915_mmap_offset *mmo = area->vm_private_data; > + struct drm_i915_gem_object *obj = mmo->obj; > + vm_fault_t ret; > + > + /* Sanity check that we allow writing into this object */ > + if (unlikely(i915_gem_object_is_readonly(obj) && > + area->vm_flags & VM_WRITE)) > + return VM_FAULT_SIGBUS; > + > + ret = ttm_bo_vm_reserve(i915_gem_to_ttm(obj), vmf); > + if (ret) > + return ret; > + > + ret = ttm_bo_vm_fault_reserved(i915_gem_to_ttm(obj), vmf, > + drm_vma_node_start(&mmo->vma_node), > + vmf->vma->vm_page_prot, > + TTM_BO_VM_NUM_PREFAULT, 1); > + if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) > + return ret; > + > + dma_resv_unlock(obj->base.resv); > + > + return ret; > +} > + > +static int > +vm_access_ttm(struct vm_area_struct *area, unsigned long addr, > + void *buf, int len, int write) > +{ > + struct i915_mmap_offset *mmo = area->vm_private_data; > + struct drm_i915_gem_object *obj = mmo->obj; > + int err = 0; > + > + if (i915_gem_object_is_readonly(obj) && write) > + return -EACCES; > + > + addr -= area->vm_start; > + if (addr >= obj->base.size) > + return -EINVAL; > + > + err = i915_gem_object_lock_interruptible(obj, NULL); > + if (err) > + return err; > + > + len = ttm_bo_vm_access_reserved(i915_gem_to_ttm(obj), area, > + addr, buf, len, write); > + i915_gem_object_unlock(obj); > + > + return len; > +} > + > +static const struct vm_operations_struct vm_ops_ttm = { > + .fault = vm_fault_ttm, > + .access = vm_access_ttm, > + .open = i915_gem_mmap_vm_open, > + .close = i915_gem_mmap_vm_close, > +}; > + > +const struct drm_i915_gem_object_ops i915_gem_ttm_obj_ops = { > .name = "i915_gem_object_ttm", > .flags = I915_GEM_OBJECT_HAS_IOMEM, > > @@ -463,6 +565,7 @@ static const struct drm_i915_gem_object_ops i915_gem_ttm_obj_ops = { > .truncate = i915_ttm_purge, > .adjust_lru = i915_ttm_adjust_lru, > .delayed_free = i915_ttm_delayed_free, > + .mmap_ops = &vm_ops_ttm, > }; > > void i915_ttm_bo_destroy(struct ttm_buffer_object *bo)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c index 65db290efd16..2bf89349dde9 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c @@ -19,6 +19,7 @@ #include "i915_gem_mman.h" #include "i915_trace.h" #include "i915_user_extensions.h" +#include "i915_gem_ttm.h" #include "i915_vma.h" static inline bool @@ -789,7 +790,7 @@ i915_gem_mmap_offset_ioctl(struct drm_device *dev, void *data, return __assign_mmap_offset(file, args->handle, type, &args->offset); } -static void vm_open(struct vm_area_struct *vma) +void i915_gem_mmap_vm_open(struct vm_area_struct *vma) { struct i915_mmap_offset *mmo = vma->vm_private_data; struct drm_i915_gem_object *obj = mmo->obj; @@ -798,7 +799,7 @@ static void vm_open(struct vm_area_struct *vma) i915_gem_object_get(obj); } -static void vm_close(struct vm_area_struct *vma) +void i915_gem_mmap_vm_close(struct vm_area_struct *vma) { struct i915_mmap_offset *mmo = vma->vm_private_data; struct drm_i915_gem_object *obj = mmo->obj; @@ -810,15 +811,15 @@ static void vm_close(struct vm_area_struct *vma) static const struct vm_operations_struct vm_ops_gtt = { .fault = vm_fault_gtt, .access = vm_access, - .open = vm_open, - .close = vm_close, + .open = i915_gem_mmap_vm_open, + .close = i915_gem_mmap_vm_close, }; static const struct vm_operations_struct vm_ops_cpu = { .fault = vm_fault_cpu, .access = vm_access, - .open = vm_open, - .close = vm_close, + .open = i915_gem_mmap_vm_open, + .close = i915_gem_mmap_vm_close, }; static int singleton_release(struct inode *inode, struct file *file) @@ -953,6 +954,10 @@ int i915_gem_mmap(struct file *filp, struct vm_area_struct *vma) } vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + /* override ops per-object if desired */ + if (obj->ops->mmap_ops) + vma->vm_ops = obj->ops->mmap_ops; + return 0; } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.h b/drivers/gpu/drm/i915/gem/i915_gem_mman.h index efee9e0d2508..e5bd02a6db12 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_mman.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.h @@ -28,5 +28,7 @@ void __i915_gem_object_release_mmap_gtt(struct drm_i915_gem_object *obj); void i915_gem_object_release_mmap_gtt(struct drm_i915_gem_object *obj); void i915_gem_object_release_mmap_offset(struct drm_i915_gem_object *obj); +void i915_gem_mmap_vm_open(struct vm_area_struct *vma); +void i915_gem_mmap_vm_close(struct vm_area_struct *vma); #endif 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 b350765e1935..31d828e91cf4 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h @@ -79,6 +79,7 @@ struct drm_i915_gem_object_ops { void (*delayed_free)(struct drm_i915_gem_object *obj); void (*release)(struct drm_i915_gem_object *obj); + const struct vm_operations_struct *mmap_ops; const char *name; /* friendly name for debug, e.g. lockdep classes */ }; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 790f5ec45c4d..fe9ac50b2470 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -14,6 +14,7 @@ #include "gem/i915_gem_region.h" #include "gem/i915_gem_ttm.h" #include "gem/i915_gem_ttm_bo_util.h" +#include "gem/i915_gem_mman.h" #define I915_PL_LMEM0 TTM_PL_PRIV #define I915_PL_SYSTEM TTM_PL_SYSTEM @@ -345,6 +346,44 @@ static int i915_ttm_move(struct ttm_buffer_object *bo, bool evict, return 0; } +static int i915_ttm_io_mem_reserve(struct ttm_device *bdev, struct ttm_resource *mem) +{ + if (mem->mem_type < I915_PL_LMEM0) + return 0; + + /* We may need to revisit this later, but this allows all caching to be used in mmap */ + mem->bus.caching = ttm_cached; + mem->bus.is_iomem = true; + + return 0; +} + +static unsigned long i915_ttm_io_mem_pfn(struct ttm_buffer_object *bo, + unsigned long page_offset) +{ + struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); + struct sg_table *sgt = obj->ttm.cached_io_st; + struct scatterlist *sg; + unsigned int i; + + GEM_WARN_ON(bo->ttm); + + for_each_sgtable_dma_sg(sgt, sg, i) { + unsigned long sg_max = sg->length >> PAGE_SHIFT; + + if (page_offset < sg_max) { + unsigned long base = + obj->mm.region->iomap.base - obj->mm.region->region.start; + + return ((base + sg_dma_address(sg)) >> PAGE_SHIFT) + page_offset; + } + + page_offset -= sg_max; + } + GEM_BUG_ON(1); + return 0; +} + struct ttm_device_funcs i915_ttm_bo_driver = { .ttm_tt_create = i915_ttm_tt_create, .ttm_tt_unpopulate = i915_ttm_tt_unpopulate, @@ -355,6 +394,8 @@ struct ttm_device_funcs i915_ttm_bo_driver = { .verify_access = NULL, .swap_notify = i915_ttm_swap_notify, .delete_mem_notify = i915_ttm_delete_mem_notify, + .io_mem_reserve = i915_ttm_io_mem_reserve, + .io_mem_pfn = i915_ttm_io_mem_pfn, }; static int i915_ttm_get_pages(struct drm_i915_gem_object *obj) @@ -454,7 +495,68 @@ static void i915_ttm_delayed_free(struct drm_i915_gem_object *obj) ttm_bo_put(i915_gem_to_ttm(obj)); } -static const struct drm_i915_gem_object_ops i915_gem_ttm_obj_ops = { +static vm_fault_t vm_fault_ttm(struct vm_fault *vmf) +{ + struct vm_area_struct *area = vmf->vma; + struct i915_mmap_offset *mmo = area->vm_private_data; + struct drm_i915_gem_object *obj = mmo->obj; + vm_fault_t ret; + + /* Sanity check that we allow writing into this object */ + if (unlikely(i915_gem_object_is_readonly(obj) && + area->vm_flags & VM_WRITE)) + return VM_FAULT_SIGBUS; + + ret = ttm_bo_vm_reserve(i915_gem_to_ttm(obj), vmf); + if (ret) + return ret; + + ret = ttm_bo_vm_fault_reserved(i915_gem_to_ttm(obj), vmf, + drm_vma_node_start(&mmo->vma_node), + vmf->vma->vm_page_prot, + TTM_BO_VM_NUM_PREFAULT, 1); + if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) + return ret; + + dma_resv_unlock(obj->base.resv); + + return ret; +} + +static int +vm_access_ttm(struct vm_area_struct *area, unsigned long addr, + void *buf, int len, int write) +{ + struct i915_mmap_offset *mmo = area->vm_private_data; + struct drm_i915_gem_object *obj = mmo->obj; + int err = 0; + + if (i915_gem_object_is_readonly(obj) && write) + return -EACCES; + + addr -= area->vm_start; + if (addr >= obj->base.size) + return -EINVAL; + + err = i915_gem_object_lock_interruptible(obj, NULL); + if (err) + return err; + + len = ttm_bo_vm_access_reserved(i915_gem_to_ttm(obj), area, + addr, buf, len, write); + i915_gem_object_unlock(obj); + + return len; +} + +static const struct vm_operations_struct vm_ops_ttm = { + .fault = vm_fault_ttm, + .access = vm_access_ttm, + .open = i915_gem_mmap_vm_open, + .close = i915_gem_mmap_vm_close, +}; + +const struct drm_i915_gem_object_ops i915_gem_ttm_obj_ops = { .name = "i915_gem_object_ttm", .flags = I915_GEM_OBJECT_HAS_IOMEM, @@ -463,6 +565,7 @@ static const struct drm_i915_gem_object_ops i915_gem_ttm_obj_ops = { .truncate = i915_ttm_purge, .adjust_lru = i915_ttm_adjust_lru, .delayed_free = i915_ttm_delayed_free, + .mmap_ops = &vm_ops_ttm, }; void i915_ttm_bo_destroy(struct ttm_buffer_object *bo)