---
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)