All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/5] drm: Add shmem GEM library
@ 2018-10-17 13:04 Noralf Trønnes
  2018-10-17 13:04 ` [PATCH v5 1/5] drm/driver: Add defaults for .gem_prime_export/import callbacks Noralf Trønnes
                   ` (7 more replies)
  0 siblings, 8 replies; 35+ messages in thread
From: Noralf Trønnes @ 2018-10-17 13:04 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, sam, david

This patchset adds a library for shmem backed GEM objects and makes use
of it in tinydrm.

Daniel suggested that I make a generic mmap function for GEM PRIME.
I wondered if I could make it the default for drm_driver->gem_prime_mmap
so I looked at all the drivers that don't set that callback:
- armada, i915, omap and udl has their own dmabuf implementations.
- nouveau and radeon use drm_gem_prime_export(), but don't set the
  ->gem_prime_mmap callback.

Making it default would change the behaviour of those last two so I let
it be.

I'm cc'ing intel-gfx to have the CI look at the core changes I've made.
I can't exercise all the codepaths using vc4 and tinydrm.

Noralf.

Changes since version 4:
- Add drm_gem_prime_mmap() (Daniel Vetter)
- Drop drm_gem_object_funcs->prime_mmap
- drm_gem_shmem_mmap(): Subtract drm_vma_node_start() to get the real
  vma->vm_pgoff
- drm_gem_shmem_fault(): Use vmf->pgoff now that vma->vm_pgoff is
  correct

Changes since version 3:
- Drop cache modes (Thomas Hellstrom)
- Add a GEM object attached vtable

Changes since version 2:
- Grammar (Sam Ravnborg)
- s/drm_gem_shmem_put_pages_unlocked/drm_gem_shmem_put_pages_locked/
  (Sam Ravnborg)
- Add debug ouput in error path (Sam Ravnborg)

Changes since version 1:
- Fix missing argument in docs (kbuild test robot)
- Fix: sparse: expression using sizeof(void) (kbuild test robot)
- Rebasing gave a new checkpatch warning, so I changed to bitfields:
CHECK: Avoid using bool structure members because of possible alignment
issues - see: https://lkml.org/lkml/2017/11/21/384
#834: FILE: include/drm/drm_gem_shmem_helper.h:84:
+       bool pages_mark_dirty_on_put;
#841: FILE: include/drm/drm_gem_shmem_helper.h:91:
+       bool pages_mark_accessed_on_put;

Noralf Trønnes (5):
  drm/driver: Add defaults for .gem_prime_export/import callbacks
  drm/prime: Add drm_gem_prime_mmap()
  drm/gem: Add drm_gem_object_funcs
  drm: Add library for shmem backed GEM objects
  drm/tinydrm: Switch from CMA to shmem buffers

 Documentation/gpu/drm-kms-helpers.rst          |  12 +
 Documentation/gpu/todo.rst                     |   7 +
 drivers/gpu/drm/Kconfig                        |   6 +
 drivers/gpu/drm/Makefile                       |   1 +
 drivers/gpu/drm/drm_client.c                   |  12 +-
 drivers/gpu/drm/drm_gem.c                      | 109 ++++-
 drivers/gpu/drm/drm_gem_shmem_helper.c         | 551 +++++++++++++++++++++++++
 drivers/gpu/drm/drm_prime.c                    |  79 +++-
 drivers/gpu/drm/tinydrm/Kconfig                |   2 +-
 drivers/gpu/drm/tinydrm/core/tinydrm-core.c    |  92 ++---
 drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c |   5 +
 drivers/gpu/drm/tinydrm/ili9225.c              |  14 +-
 drivers/gpu/drm/tinydrm/ili9341.c              |   6 +-
 drivers/gpu/drm/tinydrm/mi0283qt.c             |   6 +-
 drivers/gpu/drm/tinydrm/mipi-dbi.c             |  38 +-
 drivers/gpu/drm/tinydrm/repaper.c              |  24 +-
 drivers/gpu/drm/tinydrm/st7586.c               |  15 +-
 drivers/gpu/drm/tinydrm/st7735r.c              |   6 +-
 include/drm/drm_drv.h                          |   4 +
 include/drm/drm_gem.h                          | 131 ++++++
 include/drm/drm_gem_shmem_helper.h             | 153 +++++++
 include/drm/drm_prime.h                        |   1 +
 include/drm/tinydrm/tinydrm.h                  |  36 +-
 23 files changed, 1122 insertions(+), 188 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_gem_shmem_helper.c
 create mode 100644 include/drm/drm_gem_shmem_helper.h

-- 
2.15.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v5 1/5] drm/driver: Add defaults for .gem_prime_export/import callbacks
  2018-10-17 13:04 [PATCH v5 0/5] drm: Add shmem GEM library Noralf Trønnes
@ 2018-10-17 13:04 ` Noralf Trønnes
  2018-10-17 13:04 ` [PATCH v5 2/5] drm/prime: Add drm_gem_prime_mmap() Noralf Trønnes
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 35+ messages in thread
From: Noralf Trønnes @ 2018-10-17 13:04 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, sam, david

The majority of drivers use drm_gem_prime_export() and
drm_gem_prime_import() for these callbacks so let's make them the
default.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 Documentation/gpu/todo.rst  |  7 +++++++
 drivers/gpu/drm/drm_prime.c | 10 ++++++++--
 include/drm/drm_drv.h       |  4 ++++
 3 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index 5c9d86c962af..abc31956ef15 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -234,6 +234,13 @@ efficient.
 
 Contact: Daniel Vetter
 
+Defaults for .gem_prime_import and export
+-----------------------------------------
+
+Most drivers don't need to set drm_driver->gem_prime_import and
+->gem_prime_export now that drm_gem_prime_import() and drm_gem_prime_export()
+are the default.
+
 Core refactorings
 =================
 
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 8d54d51a6b6b..ba6c7e02a2ae 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -529,7 +529,10 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev,
 		return dmabuf;
 	}
 
-	dmabuf = dev->driver->gem_prime_export(dev, obj, flags);
+	if (dev->driver->gem_prime_export)
+		dmabuf = dev->driver->gem_prime_export(dev, obj, flags);
+	else
+		dmabuf = drm_gem_prime_export(dev, obj, flags);
 	if (IS_ERR(dmabuf)) {
 		/* normally the created dma-buf takes ownership of the ref,
 		 * but if that fails then drop the ref
@@ -762,7 +765,10 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev,
 
 	/* never seen this one, need to import */
 	mutex_lock(&dev->object_name_lock);
-	obj = dev->driver->gem_prime_import(dev, dma_buf);
+	if (dev->driver->gem_prime_import)
+		obj = dev->driver->gem_prime_import(dev, dma_buf);
+	else
+		obj = drm_gem_prime_import(dev, dma_buf);
 	if (IS_ERR(obj)) {
 		ret = PTR_ERR(obj);
 		goto out_unlock;
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
index 3199ef70c007..dbb2f6ad184a 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -471,6 +471,8 @@ struct drm_driver {
 	 * @gem_prime_export:
 	 *
 	 * export GEM -> dmabuf
+	 *
+	 * This defaults to drm_gem_prime_export() if not set.
 	 */
 	struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
 				struct drm_gem_object *obj, int flags);
@@ -478,6 +480,8 @@ struct drm_driver {
 	 * @gem_prime_import:
 	 *
 	 * import dmabuf -> GEM
+	 *
+	 * This defaults to drm_gem_prime_import() if not set.
 	 */
 	struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
 				struct dma_buf *dma_buf);
-- 
2.15.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 2/5] drm/prime: Add drm_gem_prime_mmap()
  2018-10-17 13:04 [PATCH v5 0/5] drm: Add shmem GEM library Noralf Trønnes
  2018-10-17 13:04 ` [PATCH v5 1/5] drm/driver: Add defaults for .gem_prime_export/import callbacks Noralf Trønnes
@ 2018-10-17 13:04 ` Noralf Trønnes
  2018-10-17 15:22   ` Daniel Vetter
  2018-10-17 13:04 ` [PATCH v5 3/5] drm/gem: Add drm_gem_object_funcs Noralf Trønnes
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 35+ messages in thread
From: Noralf Trønnes @ 2018-10-17 13:04 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, sam, david

Add a generic PRIME GEM mmap function.

Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_prime.c | 37 +++++++++++++++++++++++++++++++++++++
 include/drm/drm_prime.h     |  1 +
 2 files changed, 38 insertions(+)

diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index ba6c7e02a2ae..42abf98c1d4a 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -651,6 +651,43 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);
 
+/**
+ * drm_gem_prime_mmap - PRIME mmap function for GEM drivers
+ * @obj: GEM object
+ * @vma: Virtual address range
+ *
+ * This function sets up a userspace mapping for PRIME exported buffers using
+ * the same codepath that is used for regular GEM buffer mapping on the DRM fd.
+ * The fake GEM offset is added to vma->vm_pgoff and &drm_driver->fops->mmap is
+ * called to set up the mapping.
+ *
+ * Drivers can use this as their &drm_driver->gem_prime_mmap callback.
+ */
+int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
+{
+	/* Used by drm_gem_mmap() to lookup the GEM object */
+	struct drm_file priv = {
+		.minor = obj->dev->primary,
+	};
+	struct file fil = {
+		.private_data = &priv,
+	};
+	int ret;
+
+	ret = drm_vma_node_allow(&obj->vma_node, &priv);
+	if (ret)
+		return ret;
+
+	vma->vm_pgoff += drm_vma_node_start(&obj->vma_node);
+
+	ret = obj->dev->driver->fops->mmap(&fil, vma);
+
+	drm_vma_node_revoke(&obj->vma_node, &priv);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_gem_prime_mmap);
+
 /**
  * drm_gem_prime_import_dev - core implementation of the import callback
  * @dev: drm_device to import into
diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h
index e2032fbc0f08..b03731a3f079 100644
--- a/include/drm/drm_prime.h
+++ b/include/drm/drm_prime.h
@@ -70,6 +70,7 @@ struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
 int drm_gem_prime_handle_to_fd(struct drm_device *dev,
 			       struct drm_file *file_priv, uint32_t handle, uint32_t flags,
 			       int *prime_fd);
+int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
 struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
 					    struct dma_buf *dma_buf);
 
-- 
2.15.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 3/5] drm/gem: Add drm_gem_object_funcs
  2018-10-17 13:04 [PATCH v5 0/5] drm: Add shmem GEM library Noralf Trønnes
  2018-10-17 13:04 ` [PATCH v5 1/5] drm/driver: Add defaults for .gem_prime_export/import callbacks Noralf Trønnes
  2018-10-17 13:04 ` [PATCH v5 2/5] drm/prime: Add drm_gem_prime_mmap() Noralf Trønnes
@ 2018-10-17 13:04 ` Noralf Trønnes
  2018-10-22 12:57   ` Christian König
  2018-10-31 23:37   ` Noralf Trønnes
  2018-10-17 13:04 ` [PATCH v5 4/5] drm: Add library for shmem backed GEM objects Noralf Trønnes
                   ` (4 subsequent siblings)
  7 siblings, 2 replies; 35+ messages in thread
From: Noralf Trønnes @ 2018-10-17 13:04 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, sam, david

This adds an optional function table on GEM objects.
The main benefit is for drivers that support more than one type of
memory (shmem,vram,cma) for their buffers depending on the hardware it
runs on. With the callbacks attached to the GEM object itself, it is
easier to have core helpers for the the various buffer types. The driver
only has to make the decision about buffer type on GEM object creation
and all other callbacks can be handled by the chosen helper.

drm_driver->gem_prime_res_obj has not been added since there's a todo to
put a reservation_object into drm_gem_object.

v2: Drop drm_gem_object_funcs->prime_mmap in favour of
drm_gem_prime_mmap() (Daniel Vetter)

v1:
- drm_gem_object_funcs.map -> .prime_map let it only do PRIME mmap like
  the function it superseeds (Daniel Vetter)
- Flip around the if ladders and make obj->funcs the first choice
  highlighting the fact that this the new default way of doing it
  (Daniel Vetter)

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_client.c |  12 ++--
 drivers/gpu/drm/drm_gem.c    | 109 ++++++++++++++++++++++++++++++++---
 drivers/gpu/drm/drm_prime.c  |  34 ++++++-----
 include/drm/drm_gem.h        | 131 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 252 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 17d9a64e885e..eca7331762e4 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -80,8 +80,7 @@ int drm_client_new(struct drm_device *dev, struct drm_client_dev *client,
 {
 	int ret;
 
-	if (!drm_core_check_feature(dev, DRIVER_MODESET) ||
-	    !dev->driver->dumb_create || !dev->driver->gem_prime_vmap)
+	if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create)
 		return -EOPNOTSUPP;
 
 	if (funcs && !try_module_get(funcs->owner))
@@ -212,8 +211,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
 {
 	struct drm_device *dev = buffer->client->dev;
 
-	if (buffer->vaddr && dev->driver->gem_prime_vunmap)
-		dev->driver->gem_prime_vunmap(buffer->gem, buffer->vaddr);
+	drm_gem_vunmap(buffer->gem, buffer->vaddr);
 
 	if (buffer->gem)
 		drm_gem_object_put_unlocked(buffer->gem);
@@ -266,9 +264,9 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u
 	 * fd_install step out of the driver backend hooks, to make that
 	 * final step optional for internal users.
 	 */
-	vaddr = dev->driver->gem_prime_vmap(obj);
-	if (!vaddr) {
-		ret = -ENOMEM;
+	vaddr = drm_gem_vmap(obj);
+	if (IS_ERR(vaddr)) {
+		ret = PTR_ERR(vaddr);
 		goto err_delete;
 	}
 
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 512078ebd97b..8b55ece97967 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -257,7 +257,9 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
 	struct drm_gem_object *obj = ptr;
 	struct drm_device *dev = obj->dev;
 
-	if (dev->driver->gem_close_object)
+	if (obj->funcs && obj->funcs->close)
+		obj->funcs->close(obj, file_priv);
+	else if (dev->driver->gem_close_object)
 		dev->driver->gem_close_object(obj, file_priv);
 
 	if (drm_core_check_feature(dev, DRIVER_PRIME))
@@ -410,7 +412,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
 	if (ret)
 		goto err_remove;
 
-	if (dev->driver->gem_open_object) {
+	if (obj->funcs && obj->funcs->open) {
+		ret = obj->funcs->open(obj, file_priv);
+		if (ret)
+			goto err_revoke;
+	} else if (dev->driver->gem_open_object) {
 		ret = dev->driver->gem_open_object(obj, file_priv);
 		if (ret)
 			goto err_revoke;
@@ -835,7 +841,9 @@ drm_gem_object_free(struct kref *kref)
 		container_of(kref, struct drm_gem_object, refcount);
 	struct drm_device *dev = obj->dev;
 
-	if (dev->driver->gem_free_object_unlocked) {
+	if (obj->funcs) {
+		obj->funcs->free(obj);
+	} else if (dev->driver->gem_free_object_unlocked) {
 		dev->driver->gem_free_object_unlocked(obj);
 	} else if (dev->driver->gem_free_object) {
 		WARN_ON(!mutex_is_locked(&dev->struct_mutex));
@@ -864,13 +872,13 @@ drm_gem_object_put_unlocked(struct drm_gem_object *obj)
 
 	dev = obj->dev;
 
-	if (dev->driver->gem_free_object_unlocked) {
-		kref_put(&obj->refcount, drm_gem_object_free);
-	} else {
+	if (dev->driver->gem_free_object) {
 		might_lock(&dev->struct_mutex);
 		if (kref_put_mutex(&obj->refcount, drm_gem_object_free,
 				&dev->struct_mutex))
 			mutex_unlock(&dev->struct_mutex);
+	} else {
+		kref_put(&obj->refcount, drm_gem_object_free);
 	}
 }
 EXPORT_SYMBOL(drm_gem_object_put_unlocked);
@@ -960,11 +968,14 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
 	if (obj_size < vma->vm_end - vma->vm_start)
 		return -EINVAL;
 
-	if (!dev->driver->gem_vm_ops)
+	if (obj->funcs && obj->funcs->vm_ops)
+		vma->vm_ops = obj->funcs->vm_ops;
+	else if (dev->driver->gem_vm_ops)
+		vma->vm_ops = dev->driver->gem_vm_ops;
+	else
 		return -EINVAL;
 
 	vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
-	vma->vm_ops = dev->driver->gem_vm_ops;
 	vma->vm_private_data = obj;
 	vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
 	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
@@ -1066,6 +1077,86 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent,
 	drm_printf_indent(p, indent, "imported=%s\n",
 			  obj->import_attach ? "yes" : "no");
 
-	if (obj->dev->driver->gem_print_info)
+	if (obj->funcs && obj->funcs->print_info)
+		obj->funcs->print_info(p, indent, obj);
+	else if (obj->dev->driver->gem_print_info)
 		obj->dev->driver->gem_print_info(p, indent, obj);
 }
+
+/**
+ * drm_gem_pin - Pin backing buffer in memory
+ * @obj: GEM object
+ *
+ * Make sure the backing buffer is pinned in memory.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int drm_gem_pin(struct drm_gem_object *obj)
+{
+	if (obj->funcs && obj->funcs->pin)
+		return obj->funcs->pin(obj);
+	else if (obj->dev->driver->gem_prime_pin)
+		return obj->dev->driver->gem_prime_pin(obj);
+	else
+		return 0;
+}
+EXPORT_SYMBOL(drm_gem_pin);
+
+/**
+ * drm_gem_unpin - Unpin backing buffer from memory
+ * @obj: GEM object
+ *
+ * Relax the requirement that the backing buffer is pinned in memory.
+ */
+void drm_gem_unpin(struct drm_gem_object *obj)
+{
+	if (obj->funcs && obj->funcs->unpin)
+		obj->funcs->unpin(obj);
+	else if (obj->dev->driver->gem_prime_unpin)
+		obj->dev->driver->gem_prime_unpin(obj);
+}
+EXPORT_SYMBOL(drm_gem_unpin);
+
+/**
+ * drm_gem_vmap - Map buffer into kernel virtual address space
+ * @obj: GEM object
+ *
+ * Returns:
+ * A virtual pointer to a newly created GEM object or an ERR_PTR-encoded negative
+ * error code on failure.
+ */
+void *drm_gem_vmap(struct drm_gem_object *obj)
+{
+	void *vaddr;
+
+	if (obj->funcs && obj->funcs->vmap)
+		vaddr = obj->funcs->vmap(obj);
+	else if (obj->dev->driver->gem_prime_vmap)
+		vaddr = obj->dev->driver->gem_prime_vmap(obj);
+	else
+		vaddr = ERR_PTR(-EOPNOTSUPP);
+
+	if (!vaddr)
+		vaddr = ERR_PTR(-ENOMEM);
+
+	return vaddr;
+}
+EXPORT_SYMBOL(drm_gem_vmap);
+
+/**
+ * drm_gem_vunmap - Remove buffer mapping from kernel virtual address space
+ * @obj: GEM object
+ * @vaddr: Virtual address (can be NULL)
+ */
+void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+	if (!vaddr)
+		return;
+
+	if (obj->funcs && obj->funcs->vunmap)
+		obj->funcs->vunmap(obj, vaddr);
+	else if (obj->dev->driver->gem_prime_vunmap)
+		obj->dev->driver->gem_prime_vunmap(obj, vaddr);
+}
+EXPORT_SYMBOL(drm_gem_vunmap);
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 42abf98c1d4a..e0ab5213efa7 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -199,7 +199,6 @@ int drm_gem_map_attach(struct dma_buf *dma_buf,
 {
 	struct drm_prime_attachment *prime_attach;
 	struct drm_gem_object *obj = dma_buf->priv;
-	struct drm_device *dev = obj->dev;
 
 	prime_attach = kzalloc(sizeof(*prime_attach), GFP_KERNEL);
 	if (!prime_attach)
@@ -208,10 +207,7 @@ int drm_gem_map_attach(struct dma_buf *dma_buf,
 	prime_attach->dir = DMA_NONE;
 	attach->priv = prime_attach;
 
-	if (!dev->driver->gem_prime_pin)
-		return 0;
-
-	return dev->driver->gem_prime_pin(obj);
+	return drm_gem_pin(obj);
 }
 EXPORT_SYMBOL(drm_gem_map_attach);
 
@@ -228,7 +224,6 @@ void drm_gem_map_detach(struct dma_buf *dma_buf,
 {
 	struct drm_prime_attachment *prime_attach = attach->priv;
 	struct drm_gem_object *obj = dma_buf->priv;
-	struct drm_device *dev = obj->dev;
 
 	if (prime_attach) {
 		struct sg_table *sgt = prime_attach->sgt;
@@ -247,8 +242,7 @@ void drm_gem_map_detach(struct dma_buf *dma_buf,
 		attach->priv = NULL;
 	}
 
-	if (dev->driver->gem_prime_unpin)
-		dev->driver->gem_prime_unpin(obj);
+	drm_gem_unpin(obj);
 }
 EXPORT_SYMBOL(drm_gem_map_detach);
 
@@ -310,7 +304,10 @@ struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
 	if (WARN_ON(prime_attach->dir != DMA_NONE))
 		return ERR_PTR(-EBUSY);
 
-	sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
+	if (obj->funcs)
+		sgt = obj->funcs->get_sg_table(obj);
+	else
+		sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
 
 	if (!IS_ERR(sgt)) {
 		if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
@@ -406,12 +403,13 @@ EXPORT_SYMBOL(drm_gem_dmabuf_release);
 void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
 {
 	struct drm_gem_object *obj = dma_buf->priv;
-	struct drm_device *dev = obj->dev;
+	void *vaddr;
 
-	if (dev->driver->gem_prime_vmap)
-		return dev->driver->gem_prime_vmap(obj);
-	else
-		return NULL;
+	vaddr = drm_gem_vmap(obj);
+	if (IS_ERR(vaddr))
+		vaddr = NULL;
+
+	return vaddr;
 }
 EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
 
@@ -426,10 +424,8 @@ EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
 void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
 {
 	struct drm_gem_object *obj = dma_buf->priv;
-	struct drm_device *dev = obj->dev;
 
-	if (dev->driver->gem_prime_vunmap)
-		dev->driver->gem_prime_vunmap(obj, vaddr);
+	drm_gem_vunmap(obj, vaddr);
 }
 EXPORT_SYMBOL(drm_gem_dmabuf_vunmap);
 
@@ -529,7 +525,9 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev,
 		return dmabuf;
 	}
 
-	if (dev->driver->gem_prime_export)
+	if (obj->funcs && obj->funcs->export)
+		dmabuf = obj->funcs->export(obj, flags);
+	else if (dev->driver->gem_prime_export)
 		dmabuf = dev->driver->gem_prime_export(dev, obj, flags);
 	else
 		dmabuf = drm_gem_prime_export(dev, obj, flags);
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index 3583b98a1718..f466ce5bde0e 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -38,6 +38,121 @@
 
 #include <drm/drm_vma_manager.h>
 
+struct drm_gem_object;
+
+/**
+ * struct drm_gem_object_funcs - GEM object functions
+ */
+struct drm_gem_object_funcs {
+	/**
+	 * @free:
+	 *
+	 * Deconstructor for drm_gem_objects.
+	 *
+	 * This callback is mandatory.
+	 */
+	void (*free)(struct drm_gem_object *obj);
+
+	/**
+	 * @open:
+	 *
+	 * Called upon GEM handle creation.
+	 *
+	 * This callback is optional.
+	 */
+	int (*open)(struct drm_gem_object *obj, struct drm_file *file);
+
+	/**
+	 * @close:
+	 *
+	 * Called upon GEM handle release.
+	 *
+	 * This callback is optional.
+	 */
+	void (*close)(struct drm_gem_object *obj, struct drm_file *file);
+
+	/**
+	 * @print_info:
+	 *
+	 * If driver subclasses struct &drm_gem_object, it can implement this
+	 * optional hook for printing additional driver specific info.
+	 *
+	 * drm_printf_indent() should be used in the callback passing it the
+	 * indent argument.
+	 *
+	 * This callback is called from drm_gem_print_info().
+	 *
+	 * This callback is optional.
+	 */
+	void (*print_info)(struct drm_printer *p, unsigned int indent,
+			   const struct drm_gem_object *obj);
+
+	/**
+	 * @export:
+	 *
+	 * Export backing buffer as a &dma_buf.
+	 * If this is not set drm_gem_prime_export() is used.
+	 *
+	 * This callback is optional.
+	 */
+	struct dma_buf *(*export)(struct drm_gem_object *obj, int flags);
+
+	/**
+	 * @pin:
+	 *
+	 * Pin backing buffer in memory.
+	 *
+	 * This callback is optional.
+	 */
+	int (*pin)(struct drm_gem_object *obj);
+
+	/**
+	 * @unpin:
+	 *
+	 * Unpin backing buffer.
+	 *
+	 * This callback is optional.
+	 */
+	void (*unpin)(struct drm_gem_object *obj);
+
+	/**
+	 * @get_sg_table:
+	 *
+	 * Returns a Scatter-Gather table representation of the buffer.
+	 * Used when exporting a buffer.
+	 *
+	 * This callback is mandatory if buffer export is supported.
+	 */
+	struct sg_table *(*get_sg_table)(struct drm_gem_object *obj);
+
+	/**
+	 * @vmap:
+	 *
+	 * Returns a virtual address for the buffer.
+	 *
+	 * This callback is optional.
+	 */
+	void *(*vmap)(struct drm_gem_object *obj);
+
+	/**
+	 * @vunmap:
+	 *
+	 * Releases the the address previously returned by @vmap.
+	 *
+	 * This callback is optional.
+	 */
+	void (*vunmap)(struct drm_gem_object *obj, void *vaddr);
+
+	/**
+	 * @vm_ops:
+	 *
+	 * Virtual memory operations used with mmap.
+	 *
+	 * This is optional but necessary for mmap support.
+	 */
+	const struct vm_operations_struct *vm_ops;
+};
+
 /**
  * struct drm_gem_object - GEM buffer object
  *
@@ -146,6 +261,17 @@ struct drm_gem_object {
 	 * simply leave it as NULL.
 	 */
 	struct dma_buf_attachment *import_attach;
+
+	/**
+	 * @funcs:
+	 *
+	 * Optional GEM object functions. If this is set, it will be used instead of the
+	 * corresponding &drm_driver GEM callbacks.
+	 *
+	 * New drivers should use this.
+	 *
+	 */
+	const struct drm_gem_object_funcs *funcs;
 };
 
 /**
@@ -293,4 +419,9 @@ int drm_gem_dumb_destroy(struct drm_file *file,
 			 struct drm_device *dev,
 			 uint32_t handle);
 
+int drm_gem_pin(struct drm_gem_object *obj);
+void drm_gem_unpin(struct drm_gem_object *obj);
+void *drm_gem_vmap(struct drm_gem_object *obj);
+void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr);
+
 #endif /* __DRM_GEM_H__ */
-- 
2.15.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2018-10-17 13:04 [PATCH v5 0/5] drm: Add shmem GEM library Noralf Trønnes
                   ` (2 preceding siblings ...)
  2018-10-17 13:04 ` [PATCH v5 3/5] drm/gem: Add drm_gem_object_funcs Noralf Trønnes
@ 2018-10-17 13:04 ` Noralf Trønnes
  2018-10-17 15:46   ` Daniel Vetter
  2018-11-27  0:36   ` Eric Anholt
  2018-10-17 13:04 ` [PATCH v5 5/5] drm/tinydrm: Switch from CMA to shmem buffers Noralf Trønnes
                   ` (3 subsequent siblings)
  7 siblings, 2 replies; 35+ messages in thread
From: Noralf Trønnes @ 2018-10-17 13:04 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, sam, david

This adds a library for shmem backed GEM objects.

v5:
- Drop drm_gem_shmem_prime_mmap() (Daniel Vetter)
- drm_gem_shmem_mmap(): Subtract drm_vma_node_start() to get the real
  vma->vm_pgoff
- drm_gem_shmem_fault(): Use vmf->pgoff now that vma->vm_pgoff is correct

v4:
- Drop cache modes (Thomas Hellstrom)
- Add a GEM attached vtable

v3:
- Grammar (Sam Ravnborg)
- s/drm_gem_shmem_put_pages_unlocked/drm_gem_shmem_put_pages_locked/
  (Sam Ravnborg)
- Add debug output in error path (Sam Ravnborg)

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 Documentation/gpu/drm-kms-helpers.rst  |  12 +
 drivers/gpu/drm/Kconfig                |   6 +
 drivers/gpu/drm/Makefile               |   1 +
 drivers/gpu/drm/drm_gem_shmem_helper.c | 551 +++++++++++++++++++++++++++++++++
 include/drm/drm_gem_shmem_helper.h     | 153 +++++++++
 5 files changed, 723 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_gem_shmem_helper.c
 create mode 100644 include/drm/drm_gem_shmem_helper.h

diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst
index 4b4dc236ef6f..8305d3566928 100644
--- a/Documentation/gpu/drm-kms-helpers.rst
+++ b/Documentation/gpu/drm-kms-helpers.rst
@@ -335,3 +335,15 @@ Legacy CRTC/Modeset Helper Functions Reference
 
 .. kernel-doc:: drivers/gpu/drm/drm_crtc_helper.c
    :export:
+
+SHMEM GEM Helper Reference
+==========================
+
+.. kernel-doc:: drivers/gpu/drm/drm_gem_shmem_helper.c
+   :doc: overview
+
+.. kernel-doc:: include/drm/drm_gem_shmem_helper.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/drm_gem_shmem_helper.c
+   :export:
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 736b7e67e4ec..46090a36f52e 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -157,6 +157,12 @@ config DRM_KMS_CMA_HELPER
 	help
 	  Choose this if you need the KMS CMA helper functions
 
+config DRM_GEM_SHMEM_HELPER
+	bool
+	depends on DRM
+	help
+	  Choose this if you need the GEM shmem helper functions
+
 config DRM_VM
 	bool
 	depends on DRM && MMU
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 576ba985e138..8733ceb41292 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -25,6 +25,7 @@ drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
 drm-$(CONFIG_DRM_VM) += drm_vm.o
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
+drm-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_gem_shmem_helper.o
 drm-$(CONFIG_PCI) += ati_pcigart.o
 drm-$(CONFIG_DRM_PANEL) += drm_panel.o
 drm-$(CONFIG_OF) += drm_of.o
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
new file mode 100644
index 000000000000..c4eec51d3282
--- /dev/null
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -0,0 +1,551 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018 Noralf Trønnes
+ */
+
+#include <linux/dma-buf.h>
+#include <linux/export.h>
+#include <linux/mutex.h>
+#include <linux/shmem_fs.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <drm/drm_device.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_prime.h>
+#include <drm/drm_print.h>
+
+/**
+ * DOC: overview
+ *
+ * This library provides helpers for GEM objects backed by shmem buffers
+ * allocated using anonymous pageable memory.
+ */
+
+static const struct drm_gem_object_funcs drm_gem_shmem_funcs = {
+	.free = drm_gem_shmem_free_object,
+	.print_info = drm_gem_shmem_print_info,
+	.pin = drm_gem_shmem_pin,
+	.unpin = drm_gem_shmem_unpin,
+	.get_sg_table = drm_gem_shmem_get_sg_table,
+	.vmap = drm_gem_shmem_vmap,
+	.vunmap = drm_gem_shmem_vunmap,
+	.vm_ops = &drm_gem_shmem_vm_ops,
+};
+
+/**
+ * drm_gem_shmem_create - Allocate an object with the given size
+ * @dev: DRM device
+ * @size: Size of the object to allocate
+ *
+ * This function creates a shmem GEM object.
+ *
+ * Returns:
+ * A struct drm_gem_shmem_object * on success or an ERR_PTR()-encoded negative
+ * error code on failure.
+ */
+struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size)
+{
+	struct drm_gem_shmem_object *shmem;
+	struct drm_gem_object *obj;
+	int ret;
+
+	size = PAGE_ALIGN(size);
+
+	if (dev->driver->gem_create_object)
+		obj = dev->driver->gem_create_object(dev, size);
+	else
+		obj = kzalloc(sizeof(*shmem), GFP_KERNEL);
+	if (!obj)
+		return ERR_PTR(-ENOMEM);
+
+	if (!obj->funcs)
+		obj->funcs = &drm_gem_shmem_funcs;
+
+	ret = drm_gem_object_init(dev, obj, size);
+	if (ret)
+		goto err_free;
+
+	ret = drm_gem_create_mmap_offset(obj);
+	if (ret)
+		goto err_release;
+
+	shmem = to_drm_gem_shmem_obj(obj);
+	mutex_init(&shmem->pages_lock);
+	mutex_init(&shmem->vmap_lock);
+
+	return shmem;
+
+err_release:
+	drm_gem_object_release(obj);
+err_free:
+	kfree(shmem);
+
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(drm_gem_shmem_create);
+
+/**
+ * drm_gem_shmem_free_object - Free resources associated with a shmem GEM object
+ * @obj: GEM object to free
+ *
+ * This function cleans up the GEM object state and frees the memory used to
+ * store the object itself.
+ */
+void drm_gem_shmem_free_object(struct drm_gem_object *obj)
+{
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+
+	WARN_ON(shmem->vmap_use_count);
+
+	if (obj->import_attach) {
+		shmem->pages_use_count--;
+		drm_prime_gem_destroy(obj, shmem->sgt);
+		kvfree(shmem->pages);
+	}
+
+	WARN_ON(shmem->pages_use_count);
+
+	drm_gem_object_release(obj);
+	mutex_destroy(&shmem->pages_lock);
+	mutex_destroy(&shmem->vmap_lock);
+	kfree(shmem);
+}
+EXPORT_SYMBOL_GPL(drm_gem_shmem_free_object);
+
+static int drm_gem_shmem_get_pages_locked(struct drm_gem_shmem_object *shmem)
+{
+	struct drm_gem_object *obj = &shmem->base;
+	struct page **pages;
+
+	if (shmem->pages_use_count++ > 0)
+		return 0;
+
+	pages = drm_gem_get_pages(obj);
+	if (IS_ERR(pages)) {
+		DRM_DEBUG_KMS("Failed to get pages (%ld)\n", PTR_ERR(pages));
+		shmem->pages_use_count = 0;
+		return PTR_ERR(pages);
+	}
+
+	shmem->pages = pages;
+
+	return 0;
+}
+
+/*
+ * drm_gem_shmem_get_pages - Allocate backing pages for a shmem GEM object
+ * @shmem: shmem GEM object
+ *
+ * This function makes sure that backing pages exists for the shmem GEM object
+ * and increases the use count.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem)
+{
+	int ret;
+
+	ret = mutex_lock_interruptible(&shmem->pages_lock);
+	if (ret)
+		return ret;
+	ret = drm_gem_shmem_get_pages_locked(shmem);
+	mutex_unlock(&shmem->pages_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_gem_shmem_get_pages);
+
+static void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem)
+{
+	struct drm_gem_object *obj = &shmem->base;
+
+	if (WARN_ON_ONCE(!shmem->pages_use_count))
+		return;
+
+	if (--shmem->pages_use_count > 0)
+		return;
+
+	drm_gem_put_pages(obj, shmem->pages,
+			  shmem->pages_mark_dirty_on_put,
+			  shmem->pages_mark_accessed_on_put);
+	shmem->pages = NULL;
+}
+
+/*
+ * drm_gem_shmem_put_pages - Decrease use count on the backing pages for a shmem GEM object
+ * @shmem: shmem GEM object
+ *
+ * This function decreases the use count and puts the backing pages when use drops to zero.
+ */
+void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem)
+{
+	mutex_lock(&shmem->pages_lock);
+	drm_gem_shmem_put_pages_locked(shmem);
+	mutex_unlock(&shmem->pages_lock);
+}
+EXPORT_SYMBOL(drm_gem_shmem_put_pages);
+
+/**
+ * drm_gem_shmem_pin - Pin backing pages for a shmem GEM object
+ * @obj: GEM object
+ *
+ * This function makes sure the backing pages are pinned in memory while the
+ * buffer is exported.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int drm_gem_shmem_pin(struct drm_gem_object *obj)
+{
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+
+	return drm_gem_shmem_get_pages(shmem);
+}
+EXPORT_SYMBOL(drm_gem_shmem_pin);
+
+/**
+ * drm_gem_shmem_unpin - Unpin backing pages for a shmem GEM object
+ * @obj: GEM object
+ *
+ * This function removes the requirement that the backing pages are pinned in
+ * memory.
+ */
+void drm_gem_shmem_unpin(struct drm_gem_object *obj)
+{
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+
+	drm_gem_shmem_put_pages(shmem);
+}
+EXPORT_SYMBOL(drm_gem_shmem_unpin);
+
+static void *drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem)
+{
+	struct drm_gem_object *obj = &shmem->base;
+	int ret;
+
+	if (shmem->vmap_use_count++ > 0)
+		return shmem->vaddr;
+
+	ret = drm_gem_shmem_get_pages(shmem);
+	if (ret)
+		goto err_zero_use;
+
+	if (obj->import_attach)
+		shmem->vaddr = dma_buf_vmap(obj->import_attach->dmabuf);
+	else
+		shmem->vaddr = vmap(shmem->pages, obj->size >> PAGE_SHIFT, VM_MAP, PAGE_KERNEL);
+
+	if (!shmem->vaddr) {
+		DRM_DEBUG_KMS("Failed to vmap pages\n");
+		ret = -ENOMEM;
+		goto err_put_pages;
+	}
+
+	return shmem->vaddr;
+
+err_put_pages:
+	drm_gem_shmem_put_pages(shmem);
+err_zero_use:
+	shmem->vmap_use_count = 0;
+
+	return ERR_PTR(ret);
+}
+
+/*
+ * drm_gem_shmem_vmap - Create a virtual mapping for a shmem GEM object
+ * @shmem: shmem GEM object
+ *
+ * This function makes sure that a virtual address exists for the buffer backing
+ * the shmem GEM object.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+void *drm_gem_shmem_vmap(struct drm_gem_object *obj)
+{
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+	void *vaddr;
+	int ret;
+
+	ret = mutex_lock_interruptible(&shmem->vmap_lock);
+	if (ret)
+		return ERR_PTR(ret);
+	vaddr = drm_gem_shmem_vmap_locked(shmem);
+	mutex_unlock(&shmem->vmap_lock);
+
+	return vaddr;
+}
+EXPORT_SYMBOL(drm_gem_shmem_vmap);
+
+static void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem)
+{
+	struct drm_gem_object *obj = &shmem->base;
+
+	if (WARN_ON_ONCE(!shmem->vmap_use_count))
+		return;
+
+	if (--shmem->vmap_use_count > 0)
+		return;
+
+	if (obj->import_attach)
+		dma_buf_vunmap(obj->import_attach->dmabuf, shmem->vaddr);
+	else
+		vunmap(shmem->vaddr);
+
+	shmem->vaddr = NULL;
+	drm_gem_shmem_put_pages(shmem);
+}
+
+/*
+ * drm_gem_shmem_vunmap - Unmap a virtual mapping fo a shmem GEM object
+ * @shmem: shmem GEM object
+ *
+ * This function removes the virtual address when use count drops to zero.
+ */
+void drm_gem_shmem_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+
+	mutex_lock(&shmem->vmap_lock);
+	drm_gem_shmem_vunmap_locked(shmem);
+	mutex_unlock(&shmem->vmap_lock);
+}
+EXPORT_SYMBOL(drm_gem_shmem_vunmap);
+
+static struct drm_gem_shmem_object *
+drm_gem_shmem_create_with_handle(struct drm_file *file_priv,
+				 struct drm_device *dev, size_t size,
+				 uint32_t *handle)
+{
+	struct drm_gem_shmem_object *shmem;
+	int ret;
+
+	shmem = drm_gem_shmem_create(dev, size);
+	if (IS_ERR(shmem))
+		return shmem;
+
+	/*
+	 * Allocate an id of idr table where the obj is registered
+	 * and handle has the id what user can see.
+	 */
+	ret = drm_gem_handle_create(file_priv, &shmem->base, handle);
+	/* drop reference from allocate - handle holds it now. */
+	drm_gem_object_put_unlocked(&shmem->base);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return shmem;
+}
+
+/**
+ * drm_gem_shmem_dumb_create - Create a dumb shmem buffer object
+ * @file: DRM file structure to create the dumb buffer for
+ * @dev: DRM device
+ * @args: IOCTL data
+ *
+ * This function computes the pitch of the dumb buffer and rounds it up to an
+ * integer number of bytes per pixel. Drivers for hardware that doesn't have
+ * any additional restrictions on the pitch can directly use this function as
+ * their &drm_driver.dumb_create callback.
+ *
+ * For hardware with additional restrictions, drivers can adjust the fields
+ * set up by userspace before calling into this function.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
+			      struct drm_mode_create_dumb *args)
+{
+	u32 min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+	struct drm_gem_shmem_object *shmem;
+
+	if (!args->pitch || !args->size) {
+		args->pitch = min_pitch;
+		args->size = args->pitch * args->height;
+	} else {
+		/* ensure sane minimum values */
+		if (args->pitch < min_pitch)
+			args->pitch = min_pitch;
+		if (args->size < args->pitch * args->height)
+			args->size = args->pitch * args->height;
+	}
+
+	shmem = drm_gem_shmem_create_with_handle(file, dev, args->size, &args->handle);
+
+	return PTR_ERR_OR_ZERO(shmem);
+}
+EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create);
+
+static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
+{
+	struct vm_area_struct *vma = vmf->vma;
+	struct drm_gem_object *obj = vma->vm_private_data;
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+	loff_t num_pages = obj->size >> PAGE_SHIFT;
+	struct page *page;
+
+	if (vmf->pgoff > num_pages || WARN_ON_ONCE(!shmem->pages))
+		return VM_FAULT_SIGBUS;
+
+	page = shmem->pages[vmf->pgoff];
+
+	return vmf_insert_page(vma, vmf->address, page);
+}
+
+static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
+{
+	struct drm_gem_object *obj = vma->vm_private_data;
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+
+	drm_gem_shmem_put_pages(shmem);
+	drm_gem_vm_close(vma);
+}
+
+const struct vm_operations_struct drm_gem_shmem_vm_ops = {
+	.fault = drm_gem_shmem_fault,
+	.open = drm_gem_vm_open,
+	.close = drm_gem_shmem_vm_close,
+};
+EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
+
+/**
+ * drm_gem_shmem_mmap - Memory-map a shmem GEM object
+ * @filp: File object
+ * @vma: VMA for the area to be mapped
+ *
+ * This function implements an augmented version of the GEM DRM file mmap
+ * operation for shmem objects. Drivers which employ the shmem helpers should
+ * use this function as their &file_operations.mmap handler in the DRM device file's
+ * file_operations structure.
+ *
+ * Instead of directly referencing this function, drivers should use the
+ * DEFINE_DRM_GEM_SHMEM_FOPS() macro.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct drm_gem_shmem_object *shmem;
+	int ret;
+
+	ret = drm_gem_mmap(filp, vma);
+	if (ret)
+		return ret;
+
+	shmem = to_drm_gem_shmem_obj(vma->vm_private_data);
+
+	ret = drm_gem_shmem_get_pages(shmem);
+	if (ret) {
+		drm_gem_vm_close(vma);
+		return ret;
+	}
+
+	/* VM_PFNMAP was set by drm_gem_mmap() */
+	vma->vm_flags &= ~VM_PFNMAP;
+	vma->vm_flags |= VM_MIXEDMAP;
+	vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+
+	fput(vma->vm_file);
+	vma->vm_file = get_file(shmem->base.filp);
+	/* Remove the fake offset */
+	vma->vm_pgoff -= drm_vma_node_start(&shmem->base.vma_node);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap);
+
+/**
+ * drm_gem_shmem_print_info() - Print &drm_gem_shmem_object info for debugfs
+ * @p: DRM printer
+ * @indent: Tab indentation level
+ * @obj: GEM object
+ */
+void drm_gem_shmem_print_info(struct drm_printer *p, unsigned int indent,
+			      const struct drm_gem_object *obj)
+{
+	const struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+
+	drm_printf_indent(p, indent, "pages_use_count=%u\n", shmem->pages_use_count);
+	drm_printf_indent(p, indent, "vmap_use_count=%u\n", shmem->vmap_use_count);
+	drm_printf_indent(p, indent, "vaddr=%p\n", shmem->vaddr);
+}
+EXPORT_SYMBOL(drm_gem_shmem_print_info);
+
+/**
+ * drm_gem_shmem_get_sg_table - Provide a scatter/gather table of pinned
+ *                              pages for a shmem GEM object
+ * @obj: GEM object
+ *
+ * This function exports a scatter/gather table suitable for PRIME usage by
+ * calling the standard DMA mapping API.
+ *
+ * Returns:
+ * A pointer to the scatter/gather table of pinned pages or NULL on failure.
+ */
+struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_object *obj)
+{
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+
+	return drm_prime_pages_to_sg(shmem->pages, obj->size >> PAGE_SHIFT);
+}
+EXPORT_SYMBOL_GPL(drm_gem_shmem_get_sg_table);
+
+/**
+ * drm_gem_shmem_prime_import_sg_table - Produce a shmem GEM object from
+ *                 another driver's scatter/gather table of pinned pages
+ * @dev: Device to import into
+ * @attach: DMA-BUF attachment
+ * @sgt: Scatter/gather table of pinned pages
+ *
+ * This function imports a scatter/gather table exported via DMA-BUF by
+ * another driver. Drivers that use the shmem helpers should set this as their
+ * &drm_driver.gem_prime_import_sg_table callback.
+ *
+ * Returns:
+ * A pointer to a newly created GEM object or an ERR_PTR-encoded negative
+ * error code on failure.
+ */
+struct drm_gem_object *
+drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
+				    struct dma_buf_attachment *attach,
+				    struct sg_table *sgt)
+{
+	size_t size = PAGE_ALIGN(attach->dmabuf->size);
+	size_t npages = size >> PAGE_SHIFT;
+	struct drm_gem_shmem_object *shmem;
+	int ret;
+
+	shmem = drm_gem_shmem_create(dev, size);
+	if (IS_ERR(shmem))
+		return ERR_CAST(shmem);
+
+	shmem->pages = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
+	if (!shmem->pages) {
+		ret = -ENOMEM;
+		goto err_free_gem;
+	}
+
+	ret = drm_prime_sg_to_page_addr_arrays(sgt, shmem->pages, NULL, npages);
+	if (ret < 0)
+		goto err_free_array;
+
+	shmem->sgt = sgt;
+	shmem->pages_use_count = 1; /* Permanently pinned from our point of view */
+
+	DRM_DEBUG_PRIME("size = %zu\n", size);
+
+	return &shmem->base;
+
+err_free_array:
+	kvfree(shmem->pages);
+err_free_gem:
+	drm_gem_object_put_unlocked(&shmem->base);
+
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(drm_gem_shmem_prime_import_sg_table);
diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
new file mode 100644
index 000000000000..26b05e06407d
--- /dev/null
+++ b/include/drm/drm_gem_shmem_helper.h
@@ -0,0 +1,153 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __DRM_GEM_SHMEM_HELPER_H__
+#define __DRM_GEM_SHMEM_HELPER_H__
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+
+#include <drm/drm_file.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_ioctl.h>
+#include <drm/drm_prime.h>
+
+struct dma_buf_attachment;
+struct drm_mode_create_dumb;
+struct drm_printer;
+struct sg_table;
+
+/**
+ * struct drm_gem_shmem_object - GEM object backed by shmem
+ */
+struct drm_gem_shmem_object {
+	/**
+	 * @base: Base GEM object
+	 */
+	struct drm_gem_object base;
+
+	/**
+	 * @pages_lock: Protects the page table and use count
+	 */
+	struct mutex pages_lock;
+
+	/**
+	 * @pages: Page table
+	 */
+	struct page **pages;
+
+	/**
+	 * @pages_use_count:
+	 *
+	 * Reference count on the pages table.
+	 * The pages are put when the count reaches zero.
+	 */
+	unsigned int pages_use_count;
+
+	/**
+	 * @pages_mark_dirty_on_put:
+	 *
+	 * Mark pages as dirty when they are put.
+	 */
+	unsigned int pages_mark_dirty_on_put    : 1;
+
+	/**
+	 * @pages_mark_accessed_on_put:
+	 *
+	 * Mark pages as accessed when they are put.
+	 */
+	unsigned int pages_mark_accessed_on_put : 1;
+
+	/**
+	 * @sgt: Scatter/gather table for imported PRIME buffers
+	 */
+	struct sg_table *sgt;
+
+	/**
+	 * @vmap_lock: Protects the vmap address and use count
+	 */
+	struct mutex vmap_lock;
+
+	/**
+	 * @vaddr: Kernel virtual address of the backing memory
+	 */
+	void *vaddr;
+
+	/**
+	 * @vmap_use_count:
+	 *
+	 * Reference count on the virtual address.
+	 * The address are un-mapped when the count reaches zero.
+	 */
+	unsigned int vmap_use_count;
+};
+
+#define to_drm_gem_shmem_obj(obj) \
+	container_of(obj, struct drm_gem_shmem_object, base)
+
+/**
+ * DEFINE_DRM_GEM_SHMEM_FOPS() - Macro to generate file operations for shmem drivers
+ * @name: name for the generated structure
+ *
+ * This macro autogenerates a suitable &struct file_operations for shmem based
+ * drivers, which can be assigned to &drm_driver.fops. Note that this structure
+ * cannot be shared between drivers, because it contains a reference to the
+ * current module using THIS_MODULE.
+ *
+ * Note that the declaration is already marked as static - if you need a
+ * non-static version of this you're probably doing it wrong and will break the
+ * THIS_MODULE reference by accident.
+ */
+#define DEFINE_DRM_GEM_SHMEM_FOPS(name) \
+	static const struct file_operations name = {\
+		.owner		= THIS_MODULE,\
+		.open		= drm_open,\
+		.release	= drm_release,\
+		.unlocked_ioctl	= drm_ioctl,\
+		.compat_ioctl	= drm_compat_ioctl,\
+		.poll		= drm_poll,\
+		.read		= drm_read,\
+		.llseek		= noop_llseek,\
+		.mmap		= drm_gem_shmem_mmap, \
+	}
+
+struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size);
+void drm_gem_shmem_free_object(struct drm_gem_object *obj);
+
+int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem);
+void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem);
+int drm_gem_shmem_pin(struct drm_gem_object *obj);
+void drm_gem_shmem_unpin(struct drm_gem_object *obj);
+void *drm_gem_shmem_vmap(struct drm_gem_object *obj);
+void drm_gem_shmem_vunmap(struct drm_gem_object *obj, void *vaddr);
+
+int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
+			      struct drm_mode_create_dumb *args);
+
+int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma);
+
+extern const struct vm_operations_struct drm_gem_shmem_vm_ops;
+
+void drm_gem_shmem_print_info(struct drm_printer *p, unsigned int indent,
+			      const struct drm_gem_object *obj);
+
+struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_object *obj);
+struct drm_gem_object *
+drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
+				    struct dma_buf_attachment *attach,
+				    struct sg_table *sgt);
+
+/**
+ * DRM_GEM_SHMEM_DRIVER_OPS - Default shmem GEM operations
+ *
+ * This macro provides a shortcut for setting the shmem GEM operations in
+ * the &drm_driver structure.
+ */
+#define DRM_GEM_SHMEM_DRIVER_OPS \
+	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd, \
+	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle, \
+	.gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, \
+	.gem_prime_mmap		= drm_gem_prime_mmap, \
+	.dumb_create		= drm_gem_shmem_dumb_create
+
+#endif /* __DRM_GEM_SHMEM_HELPER_H__ */
-- 
2.15.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 5/5] drm/tinydrm: Switch from CMA to shmem buffers
  2018-10-17 13:04 [PATCH v5 0/5] drm: Add shmem GEM library Noralf Trønnes
                   ` (3 preceding siblings ...)
  2018-10-17 13:04 ` [PATCH v5 4/5] drm: Add library for shmem backed GEM objects Noralf Trønnes
@ 2018-10-17 13:04 ` Noralf Trønnes
  2018-10-26 22:38   ` Noralf Trønnes
  2018-10-17 13:43 ` ✗ Fi.CI.CHECKPATCH: warning for drm: Add shmem GEM library Patchwork
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 35+ messages in thread
From: Noralf Trønnes @ 2018-10-17 13:04 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, sam, david

This move makes tinydrm useful for more drivers. tinydrm doesn't need
continuous memory, but at the time it was convenient to use the CMA
library. The spi core can do dma on is_vmalloc() addresses making this
possible.

Cc: David Lechner <david@lechnology.com>
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Acked-by: David Lechner <david@lechnology.com>
Tested-by: David Lechner <david@lechnology.com>
---
 drivers/gpu/drm/tinydrm/Kconfig                |  2 +-
 drivers/gpu/drm/tinydrm/core/tinydrm-core.c    | 92 +++++++-------------------
 drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c |  5 ++
 drivers/gpu/drm/tinydrm/ili9225.c              | 14 ++--
 drivers/gpu/drm/tinydrm/ili9341.c              |  6 +-
 drivers/gpu/drm/tinydrm/mi0283qt.c             |  6 +-
 drivers/gpu/drm/tinydrm/mipi-dbi.c             | 38 ++++-------
 drivers/gpu/drm/tinydrm/repaper.c              | 24 +++----
 drivers/gpu/drm/tinydrm/st7586.c               | 15 +++--
 drivers/gpu/drm/tinydrm/st7735r.c              |  6 +-
 include/drm/tinydrm/tinydrm.h                  | 36 +++-------
 11 files changed, 91 insertions(+), 153 deletions(-)

diff --git a/drivers/gpu/drm/tinydrm/Kconfig b/drivers/gpu/drm/tinydrm/Kconfig
index 16f4b5c91f1b..aa0cabba5ace 100644
--- a/drivers/gpu/drm/tinydrm/Kconfig
+++ b/drivers/gpu/drm/tinydrm/Kconfig
@@ -2,7 +2,7 @@ menuconfig DRM_TINYDRM
 	tristate "Support for simple displays"
 	depends on DRM
 	select DRM_KMS_HELPER
-	select DRM_KMS_CMA_HELPER
+	select DRM_GEM_SHMEM_HELPER
 	help
 	  Choose this option if you have a tinydrm supported display.
 	  If M is selected the module will be called tinydrm.
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
index 255341ee4eb9..38ba361d1af2 100644
--- a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
+++ b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
@@ -12,6 +12,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
 #include <drm/tinydrm/tinydrm.h>
 #include <linux/device.h>
 #include <linux/dma-buf.h>
@@ -23,7 +24,7 @@
  *
  * It is based on &drm_simple_display_pipe coupled with a &drm_connector which
  * has only one fixed &drm_display_mode. The framebuffers are backed by the
- * cma helper and have support for framebuffer flushing (dirty).
+ * shmem buffers and have support for framebuffer flushing (dirty).
  * fbdev support is also included.
  *
  */
@@ -37,84 +38,41 @@
  */
 
 /**
- * tinydrm_gem_cma_prime_import_sg_table - Produce a CMA GEM object from
- *     another driver's scatter/gather table of pinned pages
- * @drm: DRM device to import into
- * @attach: DMA-BUF attachment
- * @sgt: Scatter/gather table of pinned pages
+ * tinydrm_fb_destroy - Destroy framebuffer
+ * @fb: Framebuffer
  *
- * This function imports a scatter/gather table exported via DMA-BUF by
- * another driver using drm_gem_cma_prime_import_sg_table(). It sets the
- * kernel virtual address on the CMA object. Drivers should use this as their
- * &drm_driver->gem_prime_import_sg_table callback if they need the virtual
- * address. tinydrm_gem_cma_free_object() should be used in combination with
- * this function.
- *
- * Returns:
- * A pointer to a newly created GEM object or an ERR_PTR-encoded negative
- * error code on failure.
+ * This function unmaps the virtual address on the backing buffer and destroys the framebuffer.
+ * Drivers should use this as their &drm_framebuffer_funcs->destroy callback.
  */
-struct drm_gem_object *
-tinydrm_gem_cma_prime_import_sg_table(struct drm_device *drm,
-				      struct dma_buf_attachment *attach,
-				      struct sg_table *sgt)
+void tinydrm_fb_destroy(struct drm_framebuffer *fb)
 {
-	struct drm_gem_cma_object *cma_obj;
-	struct drm_gem_object *obj;
-	void *vaddr;
+	struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(gem);
 
-	vaddr = dma_buf_vmap(attach->dmabuf);
-	if (!vaddr) {
-		DRM_ERROR("Failed to vmap PRIME buffer\n");
-		return ERR_PTR(-ENOMEM);
-	}
-
-	obj = drm_gem_cma_prime_import_sg_table(drm, attach, sgt);
-	if (IS_ERR(obj)) {
-		dma_buf_vunmap(attach->dmabuf, vaddr);
-		return obj;
-	}
-
-	cma_obj = to_drm_gem_cma_obj(obj);
-	cma_obj->vaddr = vaddr;
-
-	return obj;
+	drm_gem_vunmap(gem, shmem->vaddr);
+	drm_gem_fb_destroy(fb);
 }
-EXPORT_SYMBOL(tinydrm_gem_cma_prime_import_sg_table);
-
-/**
- * tinydrm_gem_cma_free_object - Free resources associated with a CMA GEM
- *                               object
- * @gem_obj: GEM object to free
- *
- * This function frees the backing memory of the CMA GEM object, cleans up the
- * GEM object state and frees the memory used to store the object itself using
- * drm_gem_cma_free_object(). It also handles PRIME buffers which has the kernel
- * virtual address set by tinydrm_gem_cma_prime_import_sg_table(). Drivers
- * can use this as their &drm_driver->gem_free_object_unlocked callback.
- */
-void tinydrm_gem_cma_free_object(struct drm_gem_object *gem_obj)
-{
-	if (gem_obj->import_attach) {
-		struct drm_gem_cma_object *cma_obj;
-
-		cma_obj = to_drm_gem_cma_obj(gem_obj);
-		dma_buf_vunmap(gem_obj->import_attach->dmabuf, cma_obj->vaddr);
-		cma_obj->vaddr = NULL;
-	}
-
-	drm_gem_cma_free_object(gem_obj);
-}
-EXPORT_SYMBOL_GPL(tinydrm_gem_cma_free_object);
+EXPORT_SYMBOL(tinydrm_fb_destroy);
 
 static struct drm_framebuffer *
 tinydrm_fb_create(struct drm_device *drm, struct drm_file *file_priv,
 		  const struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	struct tinydrm_device *tdev = drm->dev_private;
+	struct drm_framebuffer *fb;
+	void *vaddr;
 
-	return drm_gem_fb_create_with_funcs(drm, file_priv, mode_cmd,
-					    tdev->fb_funcs);
+	fb = drm_gem_fb_create_with_funcs(drm, file_priv, mode_cmd, tdev->fb_funcs);
+	if (IS_ERR(fb))
+		return fb;
+
+	vaddr = drm_gem_vmap(drm_gem_fb_get_obj(fb, 0));
+	if (IS_ERR(vaddr)) {
+		drm_gem_fb_destroy(fb);
+		return ERR_CAST(vaddr);
+	}
+
+	return fb;
 }
 
 static const struct drm_mode_config_funcs tinydrm_mode_config_funcs = {
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c b/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c
index dcd390163a4a..f9d35acff23d 100644
--- a/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c
+++ b/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c
@@ -9,12 +9,17 @@
 
 #include <linux/backlight.h>
 #include <linux/dma-buf.h>
+#include <linux/module.h>
 #include <linux/pm.h>
 #include <linux/spi/spi.h>
 #include <linux/swab.h>
 
+#include <drm/drm_device.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fourcc.h>
 #include <drm/tinydrm/tinydrm.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
+#include <drm/drm_print.h>
 
 static unsigned int spi_max;
 module_param(spi_max, uint, 0400);
diff --git a/drivers/gpu/drm/tinydrm/ili9225.c b/drivers/gpu/drm/tinydrm/ili9225.c
index 455fefe012f5..c24d6e4c834b 100644
--- a/drivers/gpu/drm/tinydrm/ili9225.c
+++ b/drivers/gpu/drm/tinydrm/ili9225.c
@@ -20,8 +20,11 @@
 #include <linux/spi/spi.h>
 #include <video/mipi_display.h>
 
+#include <drm/drm_drv.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_fourcc.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
 
@@ -77,7 +80,8 @@ static int ili9225_fb_dirty(struct drm_framebuffer *fb,
 			    unsigned int color, struct drm_clip_rect *clips,
 			    unsigned int num_clips)
 {
-	struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+	struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(gem);
 	struct tinydrm_device *tdev = fb->dev->dev_private;
 	struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
 	bool swap = mipi->swap_bytes;
@@ -104,7 +108,7 @@ static int ili9225_fb_dirty(struct drm_framebuffer *fb,
 		if (ret)
 			return ret;
 	} else {
-		tr = cma_obj->vaddr;
+		tr = shmem->vaddr;
 	}
 
 	switch (mipi->rotation) {
@@ -157,7 +161,7 @@ static int ili9225_fb_dirty(struct drm_framebuffer *fb,
 }
 
 static const struct drm_framebuffer_funcs ili9225_fb_funcs = {
-	.destroy	= drm_gem_fb_destroy,
+	.destroy	= tinydrm_fb_destroy,
 	.create_handle	= drm_gem_fb_create_handle,
 	.dirty		= tinydrm_fb_dirty,
 };
@@ -361,13 +365,13 @@ static const struct drm_display_mode ili9225_mode = {
 	TINYDRM_MODE(176, 220, 35, 44),
 };
 
-DEFINE_DRM_GEM_CMA_FOPS(ili9225_fops);
+DEFINE_DRM_GEM_SHMEM_FOPS(ili9225_fops);
 
 static struct drm_driver ili9225_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
 				  DRIVER_ATOMIC,
 	.fops			= &ili9225_fops,
-	TINYDRM_GEM_DRIVER_OPS,
+	DRM_GEM_SHMEM_DRIVER_OPS,
 	.name			= "ili9225",
 	.desc			= "Ilitek ILI9225",
 	.date			= "20171106",
diff --git a/drivers/gpu/drm/tinydrm/ili9341.c b/drivers/gpu/drm/tinydrm/ili9341.c
index 6701037749a7..7a80f8e6d6f3 100644
--- a/drivers/gpu/drm/tinydrm/ili9341.c
+++ b/drivers/gpu/drm/tinydrm/ili9341.c
@@ -15,8 +15,10 @@
 #include <linux/property.h>
 #include <linux/spi/spi.h>
 
+#include <drm/drm_drv.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
 #include <drm/drm_modeset_helper.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
@@ -139,12 +141,12 @@ static const struct drm_display_mode yx240qv29_mode = {
 	TINYDRM_MODE(240, 320, 37, 49),
 };
 
-DEFINE_DRM_GEM_CMA_FOPS(ili9341_fops);
+DEFINE_DRM_GEM_SHMEM_FOPS(ili9341_fops);
 
 static struct drm_driver ili9341_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
 	.fops			= &ili9341_fops,
-	TINYDRM_GEM_DRIVER_OPS,
+	DRM_GEM_SHMEM_DRIVER_OPS,
 	.debugfs_init		= mipi_dbi_debugfs_init,
 	.name			= "ili9341",
 	.desc			= "Ilitek ILI9341",
diff --git a/drivers/gpu/drm/tinydrm/mi0283qt.c b/drivers/gpu/drm/tinydrm/mi0283qt.c
index d7bb4c5e6657..b5837a6b3633 100644
--- a/drivers/gpu/drm/tinydrm/mi0283qt.c
+++ b/drivers/gpu/drm/tinydrm/mi0283qt.c
@@ -17,9 +17,11 @@
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 
+#include <drm/drm_drv.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_modeset_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
 #include <video/mipi_display.h>
@@ -147,13 +149,13 @@ static const struct drm_display_mode mi0283qt_mode = {
 	TINYDRM_MODE(320, 240, 58, 43),
 };
 
-DEFINE_DRM_GEM_CMA_FOPS(mi0283qt_fops);
+DEFINE_DRM_GEM_SHMEM_FOPS(mi0283qt_fops);
 
 static struct drm_driver mi0283qt_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
 				  DRIVER_ATOMIC,
 	.fops			= &mi0283qt_fops,
-	TINYDRM_GEM_DRIVER_OPS,
+	DRM_GEM_SHMEM_DRIVER_OPS,
 	.debugfs_init		= mipi_dbi_debugfs_init,
 	.name			= "mi0283qt",
 	.desc			= "Multi-Inno MI0283QT",
diff --git a/drivers/gpu/drm/tinydrm/mipi-dbi.c b/drivers/gpu/drm/tinydrm/mipi-dbi.c
index cb3441e51d5f..e0f59177c2ef 100644
--- a/drivers/gpu/drm/tinydrm/mipi-dbi.c
+++ b/drivers/gpu/drm/tinydrm/mipi-dbi.c
@@ -9,10 +9,15 @@
  * (at your option) any later version.
  */
 
+#include <drm/drm_device.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fourcc.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
 #include <linux/debugfs.h>
+#include <linux/delay.h>
 #include <linux/dma-buf.h>
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
@@ -167,10 +172,11 @@ EXPORT_SYMBOL(mipi_dbi_command_buf);
 int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
 		      struct drm_clip_rect *clip, bool swap)
 {
-	struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
-	struct dma_buf_attachment *import_attach = cma_obj->base.import_attach;
+	struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(gem);
+	struct dma_buf_attachment *import_attach = gem->import_attach;
 	struct drm_format_name_buf format_name;
-	void *src = cma_obj->vaddr;
+	void *src = shmem->vaddr;
 	int ret = 0;
 
 	if (import_attach) {
@@ -210,7 +216,8 @@ static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
 			     struct drm_clip_rect *clips,
 			     unsigned int num_clips)
 {
-	struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+	struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(gem);
 	struct tinydrm_device *tdev = fb->dev->dev_private;
 	struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
 	bool swap = mipi->swap_bytes;
@@ -235,7 +242,7 @@ static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
 		if (ret)
 			return ret;
 	} else {
-		tr = cma_obj->vaddr;
+		tr = shmem->vaddr;
 	}
 
 	mipi_dbi_command(mipi, MIPI_DCS_SET_COLUMN_ADDRESS,
@@ -252,7 +259,7 @@ static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
 }
 
 static const struct drm_framebuffer_funcs mipi_dbi_fb_funcs = {
-	.destroy	= drm_gem_fb_destroy,
+	.destroy	= tinydrm_fb_destroy,
 	.create_handle	= drm_gem_fb_create_handle,
 	.dirty		= tinydrm_fb_dirty,
 };
@@ -882,31 +889,12 @@ int mipi_dbi_spi_init(struct spi_device *spi, struct mipi_dbi *mipi,
 {
 	size_t tx_size = tinydrm_spi_max_transfer_size(spi, 0);
 	struct device *dev = &spi->dev;
-	int ret;
 
 	if (tx_size < 16) {
 		DRM_ERROR("SPI transmit buffer too small: %zu\n", tx_size);
 		return -EINVAL;
 	}
 
-	/*
-	 * Even though it's not the SPI device that does DMA (the master does),
-	 * the dma mask is necessary for the dma_alloc_wc() in
-	 * drm_gem_cma_create(). The dma_addr returned will be a physical
-	 * adddress which might be different from the bus address, but this is
-	 * not a problem since the address will not be used.
-	 * The virtual address is used in the transfer and the SPI core
-	 * re-maps it on the SPI master device using the DMA streaming API
-	 * (spi_map_buf()).
-	 */
-	if (!dev->coherent_dma_mask) {
-		ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
-		if (ret) {
-			dev_warn(dev, "Failed to set dma mask %d\n", ret);
-			return ret;
-		}
-	}
-
 	mipi->spi = spi;
 	mipi->read_commands = mipi_dbi_dcs_read_commands;
 
diff --git a/drivers/gpu/drm/tinydrm/repaper.c b/drivers/gpu/drm/tinydrm/repaper.c
index 50a1d4216ce7..82d8c6bf0c91 100644
--- a/drivers/gpu/drm/tinydrm/repaper.c
+++ b/drivers/gpu/drm/tinydrm/repaper.c
@@ -26,7 +26,9 @@
 #include <linux/spi/spi.h>
 #include <linux/thermal.h>
 
+#include <drm/drm_drv.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
 #include <drm/tinydrm/tinydrm.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
 
@@ -526,8 +528,9 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb,
 			    struct drm_clip_rect *clips,
 			    unsigned int num_clips)
 {
-	struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
-	struct dma_buf_attachment *import_attach = cma_obj->base.import_attach;
+	struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(gem);
+	struct dma_buf_attachment *import_attach = gem->import_attach;
 	struct tinydrm_device *tdev = fb->dev->dev_private;
 	struct repaper_epd *epd = epd_from_tinydrm(tdev);
 	struct drm_clip_rect clip;
@@ -559,7 +562,7 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb,
 			goto out_free;
 	}
 
-	tinydrm_xrgb8888_to_gray8(buf, cma_obj->vaddr, fb, &clip);
+	tinydrm_xrgb8888_to_gray8(buf, shmem->vaddr, fb, &clip);
 
 	if (import_attach) {
 		ret = dma_buf_end_cpu_access(import_attach->dmabuf,
@@ -624,7 +627,7 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb,
 }
 
 static const struct drm_framebuffer_funcs repaper_fb_funcs = {
-	.destroy	= drm_gem_fb_destroy,
+	.destroy	= tinydrm_fb_destroy,
 	.create_handle	= drm_gem_fb_create_handle,
 	.dirty		= tinydrm_fb_dirty,
 };
@@ -876,13 +879,13 @@ static const struct drm_display_mode repaper_e2271cs021_mode = {
 static const u8 repaper_e2271cs021_cs[] = { 0x00, 0x00, 0x00, 0x7f,
 					    0xff, 0xfe, 0x00, 0x00 };
 
-DEFINE_DRM_GEM_CMA_FOPS(repaper_fops);
+DEFINE_DRM_GEM_SHMEM_FOPS(repaper_fops);
 
 static struct drm_driver repaper_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
 				  DRIVER_ATOMIC,
 	.fops			= &repaper_fops,
-	TINYDRM_GEM_DRIVER_OPS,
+	DRM_GEM_SHMEM_DRIVER_OPS,
 	.name			= "repaper",
 	.desc			= "Pervasive Displays RePaper e-ink panels",
 	.date			= "20170405",
@@ -929,15 +932,6 @@ static int repaper_probe(struct spi_device *spi)
 		model = spi_id->driver_data;
 	}
 
-	/* The SPI device is used to allocate dma memory */
-	if (!dev->coherent_dma_mask) {
-		ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
-		if (ret) {
-			dev_warn(dev, "Failed to set dma mask %d\n", ret);
-			return ret;
-		}
-	}
-
 	epd = devm_kzalloc(dev, sizeof(*epd), GFP_KERNEL);
 	if (!epd)
 		return -ENOMEM;
diff --git a/drivers/gpu/drm/tinydrm/st7586.c b/drivers/gpu/drm/tinydrm/st7586.c
index 2fcbc3067d71..340c9be2613b 100644
--- a/drivers/gpu/drm/tinydrm/st7586.c
+++ b/drivers/gpu/drm/tinydrm/st7586.c
@@ -17,8 +17,10 @@
 #include <linux/spi/spi.h>
 #include <video/mipi_display.h>
 
+#include <drm/drm_drv.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
 
@@ -88,9 +90,10 @@ static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr,
 static int st7586_buf_copy(void *dst, struct drm_framebuffer *fb,
 			   struct drm_clip_rect *clip)
 {
-	struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
-	struct dma_buf_attachment *import_attach = cma_obj->base.import_attach;
-	void *src = cma_obj->vaddr;
+	struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
+	struct dma_buf_attachment *import_attach = gem->import_attach;
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(gem);
+	void *src = shmem->vaddr;
 	int ret = 0;
 
 	if (import_attach) {
@@ -156,7 +159,7 @@ static int st7586_fb_dirty(struct drm_framebuffer *fb,
 }
 
 static const struct drm_framebuffer_funcs st7586_fb_funcs = {
-	.destroy	= drm_gem_fb_destroy,
+	.destroy	= tinydrm_fb_destroy,
 	.create_handle	= drm_gem_fb_create_handle,
 	.dirty		= tinydrm_fb_dirty,
 };
@@ -297,13 +300,13 @@ static const struct drm_display_mode st7586_mode = {
 	TINYDRM_MODE(178, 128, 37, 27),
 };
 
-DEFINE_DRM_GEM_CMA_FOPS(st7586_fops);
+DEFINE_DRM_GEM_SHMEM_FOPS(st7586_fops);
 
 static struct drm_driver st7586_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
 				  DRIVER_ATOMIC,
 	.fops			= &st7586_fops,
-	TINYDRM_GEM_DRIVER_OPS,
+	DRM_GEM_SHMEM_DRIVER_OPS,
 	.debugfs_init		= mipi_dbi_debugfs_init,
 	.name			= "st7586",
 	.desc			= "Sitronix ST7586",
diff --git a/drivers/gpu/drm/tinydrm/st7735r.c b/drivers/gpu/drm/tinydrm/st7735r.c
index 3081bc57c116..1108088a1a03 100644
--- a/drivers/gpu/drm/tinydrm/st7735r.c
+++ b/drivers/gpu/drm/tinydrm/st7735r.c
@@ -14,8 +14,10 @@
 #include <linux/spi/spi.h>
 #include <video/mipi_display.h>
 
+#include <drm/drm_drv.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
 
@@ -113,13 +115,13 @@ static const struct drm_display_mode jd_t18003_t01_mode = {
 	TINYDRM_MODE(128, 160, 28, 35),
 };
 
-DEFINE_DRM_GEM_CMA_FOPS(st7735r_fops);
+DEFINE_DRM_GEM_SHMEM_FOPS(st7735r_fops);
 
 static struct drm_driver st7735r_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
 				  DRIVER_ATOMIC,
 	.fops			= &st7735r_fops,
-	TINYDRM_GEM_DRIVER_OPS,
+	DRM_GEM_SHMEM_DRIVER_OPS,
 	.debugfs_init		= mipi_dbi_debugfs_init,
 	.name			= "st7735r",
 	.desc			= "Sitronix ST7735R",
diff --git a/include/drm/tinydrm/tinydrm.h b/include/drm/tinydrm/tinydrm.h
index fe9827d0ca8a..e2cb254125c5 100644
--- a/include/drm/tinydrm/tinydrm.h
+++ b/include/drm/tinydrm/tinydrm.h
@@ -10,10 +10,15 @@
 #ifndef __LINUX_TINYDRM_H
 #define __LINUX_TINYDRM_H
 
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_fb_cma_helper.h>
+#include <linux/mutex.h>
 #include <drm/drm_simple_kms_helper.h>
 
+struct drm_driver;
+struct drm_framebuffer;
+struct drm_file;
+struct drm_clip_rect;
+struct drm_framebuffer_funcs;
+
 /**
  * struct tinydrm_device - tinydrm device
  */
@@ -53,27 +58,6 @@ pipe_to_tinydrm(struct drm_simple_display_pipe *pipe)
 	return container_of(pipe, struct tinydrm_device, pipe);
 }
 
-/**
- * TINYDRM_GEM_DRIVER_OPS - default tinydrm gem operations
- *
- * This macro provides a shortcut for setting the tinydrm GEM operations in
- * the &drm_driver structure.
- */
-#define TINYDRM_GEM_DRIVER_OPS \
-	.gem_free_object_unlocked = tinydrm_gem_cma_free_object, \
-	.gem_print_info		= drm_gem_cma_print_info, \
-	.gem_vm_ops		= &drm_gem_cma_vm_ops, \
-	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd, \
-	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle, \
-	.gem_prime_import	= drm_gem_prime_import, \
-	.gem_prime_export	= drm_gem_prime_export, \
-	.gem_prime_get_sg_table	= drm_gem_cma_prime_get_sg_table, \
-	.gem_prime_import_sg_table = tinydrm_gem_cma_prime_import_sg_table, \
-	.gem_prime_vmap		= drm_gem_cma_prime_vmap, \
-	.gem_prime_vunmap	= drm_gem_cma_prime_vunmap, \
-	.gem_prime_mmap		= drm_gem_cma_prime_mmap, \
-	.dumb_create		= drm_gem_cma_dumb_create
-
 /**
  * TINYDRM_MODE - tinydrm display mode
  * @hd: Horizontal resolution, width
@@ -97,11 +81,7 @@ pipe_to_tinydrm(struct drm_simple_display_pipe *pipe)
 	.type = DRM_MODE_TYPE_DRIVER, \
 	.clock = 1 /* pass validation */
 
-void tinydrm_gem_cma_free_object(struct drm_gem_object *gem_obj);
-struct drm_gem_object *
-tinydrm_gem_cma_prime_import_sg_table(struct drm_device *drm,
-				      struct dma_buf_attachment *attach,
-				      struct sg_table *sgt);
+void tinydrm_fb_destroy(struct drm_framebuffer *fb);
 int devm_tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
 		      const struct drm_framebuffer_funcs *fb_funcs,
 		      struct drm_driver *driver);
-- 
2.15.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* ✗ Fi.CI.CHECKPATCH: warning for drm: Add shmem GEM library
  2018-10-17 13:04 [PATCH v5 0/5] drm: Add shmem GEM library Noralf Trønnes
                   ` (4 preceding siblings ...)
  2018-10-17 13:04 ` [PATCH v5 5/5] drm/tinydrm: Switch from CMA to shmem buffers Noralf Trønnes
@ 2018-10-17 13:43 ` Patchwork
  2018-10-17 14:02 ` ✓ Fi.CI.BAT: success " Patchwork
  2018-10-17 17:37 ` ✓ Fi.CI.IGT: " Patchwork
  7 siblings, 0 replies; 35+ messages in thread
From: Patchwork @ 2018-10-17 13:43 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx

== Series Details ==

Series: drm: Add shmem GEM library
URL   : https://patchwork.freedesktop.org/series/51120/
State : warning

== Summary ==

$ dim checkpatch origin/drm-tip
fe745f1947c0 drm/driver: Add defaults for .gem_prime_export/import callbacks
26dcb4c0c861 drm/prime: Add drm_gem_prime_mmap()
cebeed8e2a08 drm/gem: Add drm_gem_object_funcs
d2ed5244c5f6 drm: Add library for shmem backed GEM objects
-:79: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#79: 
new file mode 100644

total: 0 errors, 1 warnings, 0 checks, 738 lines checked
593b702cf1af drm/tinydrm: Switch from CMA to shmem buffers

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* ✓ Fi.CI.BAT: success for drm: Add shmem GEM library
  2018-10-17 13:04 [PATCH v5 0/5] drm: Add shmem GEM library Noralf Trønnes
                   ` (5 preceding siblings ...)
  2018-10-17 13:43 ` ✗ Fi.CI.CHECKPATCH: warning for drm: Add shmem GEM library Patchwork
@ 2018-10-17 14:02 ` Patchwork
  2018-10-17 17:37 ` ✓ Fi.CI.IGT: " Patchwork
  7 siblings, 0 replies; 35+ messages in thread
From: Patchwork @ 2018-10-17 14:02 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx

== Series Details ==

Series: drm: Add shmem GEM library
URL   : https://patchwork.freedesktop.org/series/51120/
State : success

== Summary ==

= CI Bug Log - changes from CI_DRM_4998 -> Patchwork_10490 =

== Summary - SUCCESS ==

  No regressions found.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/51120/revisions/1/mbox/

== Known issues ==

  Here are the changes found in Patchwork_10490 that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@gem_exec_suspend@basic-s3:
      fi-kbl-soraka:      NOTRUN -> INCOMPLETE (fdo#107859, fdo#107774, fdo#107556)

    igt@kms_pipe_crc_basic@hang-read-crc-pipe-b:
      fi-byt-clapper:     PASS -> FAIL (fdo#103191, fdo#107362)

    igt@pm_rpm@module-reload:
      fi-glk-j4005:       PASS -> DMESG-WARN (fdo#106000)

    igt@prime_vgem@basic-fence-flip:
      fi-cfl-8700k:       PASS -> FAIL (fdo#104008)

    
    ==== Possible fixes ====

    igt@drv_selftest@live_objects:
      fi-cfl-8109u:       INCOMPLETE -> PASS

    igt@gem_exec_suspend@basic-s3:
      fi-cfl-8109u:       DMESG-WARN (fdo#107345) -> PASS +1

    igt@kms_flip@basic-flip-vs-modeset:
      fi-skl-6700hq:      DMESG-WARN (fdo#105998) -> PASS

    igt@kms_pipe_crc_basic@nonblocking-crc-pipe-b-frame-sequence:
      fi-byt-clapper:     FAIL (fdo#103191, fdo#107362) -> PASS

    igt@kms_pipe_crc_basic@suspend-read-crc-pipe-b:
      fi-blb-e6850:       INCOMPLETE (fdo#107718) -> PASS

    
  fdo#103191 https://bugs.freedesktop.org/show_bug.cgi?id=103191
  fdo#104008 https://bugs.freedesktop.org/show_bug.cgi?id=104008
  fdo#105998 https://bugs.freedesktop.org/show_bug.cgi?id=105998
  fdo#106000 https://bugs.freedesktop.org/show_bug.cgi?id=106000
  fdo#107345 https://bugs.freedesktop.org/show_bug.cgi?id=107345
  fdo#107362 https://bugs.freedesktop.org/show_bug.cgi?id=107362
  fdo#107556 https://bugs.freedesktop.org/show_bug.cgi?id=107556
  fdo#107718 https://bugs.freedesktop.org/show_bug.cgi?id=107718
  fdo#107774 https://bugs.freedesktop.org/show_bug.cgi?id=107774
  fdo#107859 https://bugs.freedesktop.org/show_bug.cgi?id=107859


== Participating hosts (45 -> 42) ==

  Additional (1): fi-kbl-soraka 
  Missing    (4): fi-ilk-m540 fi-byt-squawks fi-bsw-cyan fi-hsw-4200u 


== Build changes ==

    * Linux: CI_DRM_4998 -> Patchwork_10490

  CI_DRM_4998: a44032bf63ec3acf03e451105d90ee66a7d7f867 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4683: 7766b1e2348b32cc8ed58a972c6fd53b20279549 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_10490: 593b702cf1af25accdb63a18d1b7c70e1e6ebc71 @ git://anongit.freedesktop.org/gfx-ci/linux


== Linux commits ==

593b702cf1af drm/tinydrm: Switch from CMA to shmem buffers
d2ed5244c5f6 drm: Add library for shmem backed GEM objects
cebeed8e2a08 drm/gem: Add drm_gem_object_funcs
26dcb4c0c861 drm/prime: Add drm_gem_prime_mmap()
fe745f1947c0 drm/driver: Add defaults for .gem_prime_export/import callbacks

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_10490/issues.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 2/5] drm/prime: Add drm_gem_prime_mmap()
  2018-10-17 13:04 ` [PATCH v5 2/5] drm/prime: Add drm_gem_prime_mmap() Noralf Trønnes
@ 2018-10-17 15:22   ` Daniel Vetter
  0 siblings, 0 replies; 35+ messages in thread
From: Daniel Vetter @ 2018-10-17 15:22 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, sam, david, dri-devel

On Wed, Oct 17, 2018 at 03:04:51PM +0200, Noralf Trønnes wrote:
> Add a generic PRIME GEM mmap function.
> 
> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>  drivers/gpu/drm/drm_prime.c | 37 +++++++++++++++++++++++++++++++++++++
>  include/drm/drm_prime.h     |  1 +
>  2 files changed, 38 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
> index ba6c7e02a2ae..42abf98c1d4a 100644
> --- a/drivers/gpu/drm/drm_prime.c
> +++ b/drivers/gpu/drm/drm_prime.c
> @@ -651,6 +651,43 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev,
>  }
>  EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);
>  
> +/**
> + * drm_gem_prime_mmap - PRIME mmap function for GEM drivers
> + * @obj: GEM object
> + * @vma: Virtual address range
> + *
> + * This function sets up a userspace mapping for PRIME exported buffers using
> + * the same codepath that is used for regular GEM buffer mapping on the DRM fd.
> + * The fake GEM offset is added to vma->vm_pgoff and &drm_driver->fops->mmap is
> + * called to set up the mapping.
> + *
> + * Drivers can use this as their &drm_driver->gem_prime_mmap callback.

s/->/./ for the kerneldoc.

Otherwise looks good to me, Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

We indeed can't make this the default because only dumb buffers are
guaranteed to be coherent, other mmap implementations might not be. And
for those the driver must provide the right begin/end_cpu_access callbacks
in the dma_buf_ops structure.

Also, would be neat if we could slightly demidlayer the helpers here, so
that it's less of an all-or-nothing decisions. But that's for another
time.
-Daniel


> + */
> +int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
> +{
> +	/* Used by drm_gem_mmap() to lookup the GEM object */
> +	struct drm_file priv = {
> +		.minor = obj->dev->primary,
> +	};
> +	struct file fil = {
> +		.private_data = &priv,
> +	};
> +	int ret;
> +
> +	ret = drm_vma_node_allow(&obj->vma_node, &priv);
> +	if (ret)
> +		return ret;
> +
> +	vma->vm_pgoff += drm_vma_node_start(&obj->vma_node);
> +
> +	ret = obj->dev->driver->fops->mmap(&fil, vma);
> +
> +	drm_vma_node_revoke(&obj->vma_node, &priv);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(drm_gem_prime_mmap);
> +
>  /**
>   * drm_gem_prime_import_dev - core implementation of the import callback
>   * @dev: drm_device to import into
> diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h
> index e2032fbc0f08..b03731a3f079 100644
> --- a/include/drm/drm_prime.h
> +++ b/include/drm/drm_prime.h
> @@ -70,6 +70,7 @@ struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
>  int drm_gem_prime_handle_to_fd(struct drm_device *dev,
>  			       struct drm_file *file_priv, uint32_t handle, uint32_t flags,
>  			       int *prime_fd);
> +int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
>  struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
>  					    struct dma_buf *dma_buf);
>  
> -- 
> 2.15.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2018-10-17 13:04 ` [PATCH v5 4/5] drm: Add library for shmem backed GEM objects Noralf Trønnes
@ 2018-10-17 15:46   ` Daniel Vetter
  2018-10-22 14:15     ` Noralf Trønnes
  2018-11-27  0:36   ` Eric Anholt
  1 sibling, 1 reply; 35+ messages in thread
From: Daniel Vetter @ 2018-10-17 15:46 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, sam, david, dri-devel

On Wed, Oct 17, 2018 at 03:04:53PM +0200, Noralf Trønnes wrote:
> This adds a library for shmem backed GEM objects.
> 
> v5:
> - Drop drm_gem_shmem_prime_mmap() (Daniel Vetter)
> - drm_gem_shmem_mmap(): Subtract drm_vma_node_start() to get the real
>   vma->vm_pgoff
> - drm_gem_shmem_fault(): Use vmf->pgoff now that vma->vm_pgoff is correct
> 
> v4:
> - Drop cache modes (Thomas Hellstrom)
> - Add a GEM attached vtable
> 
> v3:
> - Grammar (Sam Ravnborg)
> - s/drm_gem_shmem_put_pages_unlocked/drm_gem_shmem_put_pages_locked/
>   (Sam Ravnborg)
> - Add debug output in error path (Sam Ravnborg)
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>  Documentation/gpu/drm-kms-helpers.rst  |  12 +
>  drivers/gpu/drm/Kconfig                |   6 +
>  drivers/gpu/drm/Makefile               |   1 +
>  drivers/gpu/drm/drm_gem_shmem_helper.c | 551 +++++++++++++++++++++++++++++++++
>  include/drm/drm_gem_shmem_helper.h     | 153 +++++++++
>  5 files changed, 723 insertions(+)
>  create mode 100644 drivers/gpu/drm/drm_gem_shmem_helper.c
>  create mode 100644 include/drm/drm_gem_shmem_helper.h
> 
> diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst
> index 4b4dc236ef6f..8305d3566928 100644
> --- a/Documentation/gpu/drm-kms-helpers.rst
> +++ b/Documentation/gpu/drm-kms-helpers.rst
> @@ -335,3 +335,15 @@ Legacy CRTC/Modeset Helper Functions Reference
>  
>  .. kernel-doc:: drivers/gpu/drm/drm_crtc_helper.c
>     :export:
> +
> +SHMEM GEM Helper Reference
> +==========================
> +
> +.. kernel-doc:: drivers/gpu/drm/drm_gem_shmem_helper.c
> +   :doc: overview
> +
> +.. kernel-doc:: include/drm/drm_gem_shmem_helper.h
> +   :internal:
> +
> +.. kernel-doc:: drivers/gpu/drm/drm_gem_shmem_helper.c
> +   :export:

This doesn't make sense here imo - put them right next to the cma helpers
in drm-mm.rst instead?

> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 736b7e67e4ec..46090a36f52e 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -157,6 +157,12 @@ config DRM_KMS_CMA_HELPER
>  	help
>  	  Choose this if you need the KMS CMA helper functions
>  
> +config DRM_GEM_SHMEM_HELPER
> +	bool
> +	depends on DRM
> +	help
> +	  Choose this if you need the GEM shmem helper functions
> +
>  config DRM_VM
>  	bool
>  	depends on DRM && MMU
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 576ba985e138..8733ceb41292 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -25,6 +25,7 @@ drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
>  drm-$(CONFIG_DRM_VM) += drm_vm.o
>  drm-$(CONFIG_COMPAT) += drm_ioc32.o
>  drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
> +drm-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_gem_shmem_helper.o
>  drm-$(CONFIG_PCI) += ati_pcigart.o
>  drm-$(CONFIG_DRM_PANEL) += drm_panel.o
>  drm-$(CONFIG_OF) += drm_of.o
> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> new file mode 100644
> index 000000000000..c4eec51d3282
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> @@ -0,0 +1,551 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2018 Noralf Trønnes
> + */
> +
> +#include <linux/dma-buf.h>
> +#include <linux/export.h>
> +#include <linux/mutex.h>
> +#include <linux/shmem_fs.h>
> +#include <linux/slab.h>
> +#include <linux/vmalloc.h>
> +
> +#include <drm/drm_device.h>
> +#include <drm/drm_drv.h>
> +#include <drm/drm_gem_shmem_helper.h>
> +#include <drm/drm_prime.h>
> +#include <drm/drm_print.h>
> +
> +/**
> + * DOC: overview
> + *
> + * This library provides helpers for GEM objects backed by shmem buffers
> + * allocated using anonymous pageable memory.

Would be neat to insert a link to the cma version here (and to the gem
version in the cma helpers) and spend a few words on when to use each.

> + */
> +
> +static const struct drm_gem_object_funcs drm_gem_shmem_funcs = {
> +	.free = drm_gem_shmem_free_object,
> +	.print_info = drm_gem_shmem_print_info,
> +	.pin = drm_gem_shmem_pin,
> +	.unpin = drm_gem_shmem_unpin,
> +	.get_sg_table = drm_gem_shmem_get_sg_table,
> +	.vmap = drm_gem_shmem_vmap,
> +	.vunmap = drm_gem_shmem_vunmap,
> +	.vm_ops = &drm_gem_shmem_vm_ops,
> +};
> +
> +/**
> + * drm_gem_shmem_create - Allocate an object with the given size
> + * @dev: DRM device
> + * @size: Size of the object to allocate
> + *
> + * This function creates a shmem GEM object.
> + *
> + * Returns:
> + * A struct drm_gem_shmem_object * on success or an ERR_PTR()-encoded negative
> + * error code on failure.
> + */
> +struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size)
> +{
> +	struct drm_gem_shmem_object *shmem;
> +	struct drm_gem_object *obj;
> +	int ret;
> +
> +	size = PAGE_ALIGN(size);
> +
> +	if (dev->driver->gem_create_object)
> +		obj = dev->driver->gem_create_object(dev, size);
> +	else
> +		obj = kzalloc(sizeof(*shmem), GFP_KERNEL);
> +	if (!obj)
> +		return ERR_PTR(-ENOMEM);
> +
> +	if (!obj->funcs)
> +		obj->funcs = &drm_gem_shmem_funcs;
> +
> +	ret = drm_gem_object_init(dev, obj, size);
> +	if (ret)
> +		goto err_free;
> +
> +	ret = drm_gem_create_mmap_offset(obj);
> +	if (ret)
> +		goto err_release;
> +
> +	shmem = to_drm_gem_shmem_obj(obj);
> +	mutex_init(&shmem->pages_lock);
> +	mutex_init(&shmem->vmap_lock);
> +
> +	return shmem;
> +
> +err_release:
> +	drm_gem_object_release(obj);
> +err_free:
> +	kfree(shmem);
> +
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(drm_gem_shmem_create);
> +
> +/**
> + * drm_gem_shmem_free_object - Free resources associated with a shmem GEM object
> + * @obj: GEM object to free
> + *
> + * This function cleans up the GEM object state and frees the memory used to
> + * store the object itself.
> + */
> +void drm_gem_shmem_free_object(struct drm_gem_object *obj)
> +{
> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> +
> +	WARN_ON(shmem->vmap_use_count);
> +
> +	if (obj->import_attach) {
> +		shmem->pages_use_count--;
> +		drm_prime_gem_destroy(obj, shmem->sgt);
> +		kvfree(shmem->pages);
> +	}
> +
> +	WARN_ON(shmem->pages_use_count);
> +
> +	drm_gem_object_release(obj);
> +	mutex_destroy(&shmem->pages_lock);
> +	mutex_destroy(&shmem->vmap_lock);
> +	kfree(shmem);
> +}
> +EXPORT_SYMBOL_GPL(drm_gem_shmem_free_object);
> +
> +static int drm_gem_shmem_get_pages_locked(struct drm_gem_shmem_object *shmem)
> +{
> +	struct drm_gem_object *obj = &shmem->base;
> +	struct page **pages;
> +
> +	if (shmem->pages_use_count++ > 0)
> +		return 0;
> +
> +	pages = drm_gem_get_pages(obj);

I think moving the drm_gem_get/put_pages into the shmem helper here would
be a good cleanup. Plus aligning the prefix to drm_gem_shmem - they really
only work with shmem, not cma gem bo.

> +	if (IS_ERR(pages)) {
> +		DRM_DEBUG_KMS("Failed to get pages (%ld)\n", PTR_ERR(pages));
> +		shmem->pages_use_count = 0;
> +		return PTR_ERR(pages);
> +	}
> +
> +	shmem->pages = pages;
> +
> +	return 0;
> +}
> +
> +/*
> + * drm_gem_shmem_get_pages - Allocate backing pages for a shmem GEM object
> + * @shmem: shmem GEM object
> + *
> + * This function makes sure that backing pages exists for the shmem GEM object
> + * and increases the use count.
> + *
> + * Returns:
> + * 0 on success or a negative error code on failure.
> + */
> +int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem)
> +{
> +	int ret;
> +
> +	ret = mutex_lock_interruptible(&shmem->pages_lock);
> +	if (ret)
> +		return ret;
> +	ret = drm_gem_shmem_get_pages_locked(shmem);
> +	mutex_unlock(&shmem->pages_lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(drm_gem_shmem_get_pages);
> +
> +static void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem)
> +{
> +	struct drm_gem_object *obj = &shmem->base;
> +
> +	if (WARN_ON_ONCE(!shmem->pages_use_count))
> +		return;
> +
> +	if (--shmem->pages_use_count > 0)
> +		return;
> +
> +	drm_gem_put_pages(obj, shmem->pages,
> +			  shmem->pages_mark_dirty_on_put,
> +			  shmem->pages_mark_accessed_on_put);
> +	shmem->pages = NULL;
> +}
> +
> +/*
> + * drm_gem_shmem_put_pages - Decrease use count on the backing pages for a shmem GEM object
> + * @shmem: shmem GEM object
> + *
> + * This function decreases the use count and puts the backing pages when use drops to zero.
> + */
> +void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem)
> +{
> +	mutex_lock(&shmem->pages_lock);
> +	drm_gem_shmem_put_pages_locked(shmem);
> +	mutex_unlock(&shmem->pages_lock);
> +}
> +EXPORT_SYMBOL(drm_gem_shmem_put_pages);
> +
> +/**
> + * drm_gem_shmem_pin - Pin backing pages for a shmem GEM object
> + * @obj: GEM object
> + *
> + * This function makes sure the backing pages are pinned in memory while the
> + * buffer is exported.
> + *
> + * Returns:
> + * 0 on success or a negative error code on failure.
> + */
> +int drm_gem_shmem_pin(struct drm_gem_object *obj)
> +{
> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> +
> +	return drm_gem_shmem_get_pages(shmem);
> +}
> +EXPORT_SYMBOL(drm_gem_shmem_pin);
> +
> +/**
> + * drm_gem_shmem_unpin - Unpin backing pages for a shmem GEM object
> + * @obj: GEM object
> + *
> + * This function removes the requirement that the backing pages are pinned in
> + * memory.
> + */
> +void drm_gem_shmem_unpin(struct drm_gem_object *obj)
> +{
> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> +
> +	drm_gem_shmem_put_pages(shmem);
> +}
> +EXPORT_SYMBOL(drm_gem_shmem_unpin);
> +
> +static void *drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem)
> +{
> +	struct drm_gem_object *obj = &shmem->base;
> +	int ret;
> +
> +	if (shmem->vmap_use_count++ > 0)
> +		return shmem->vaddr;
> +
> +	ret = drm_gem_shmem_get_pages(shmem);
> +	if (ret)
> +		goto err_zero_use;
> +
> +	if (obj->import_attach)
> +		shmem->vaddr = dma_buf_vmap(obj->import_attach->dmabuf);
> +	else
> +		shmem->vaddr = vmap(shmem->pages, obj->size >> PAGE_SHIFT, VM_MAP, PAGE_KERNEL);
> +
> +	if (!shmem->vaddr) {
> +		DRM_DEBUG_KMS("Failed to vmap pages\n");
> +		ret = -ENOMEM;
> +		goto err_put_pages;
> +	}
> +
> +	return shmem->vaddr;
> +
> +err_put_pages:
> +	drm_gem_shmem_put_pages(shmem);
> +err_zero_use:
> +	shmem->vmap_use_count = 0;
> +
> +	return ERR_PTR(ret);
> +}
> +
> +/*
> + * drm_gem_shmem_vmap - Create a virtual mapping for a shmem GEM object
> + * @shmem: shmem GEM object
> + *
> + * This function makes sure that a virtual address exists for the buffer backing
> + * the shmem GEM object.
> + *
> + * Returns:
> + * 0 on success or a negative error code on failure.
> + */
> +void *drm_gem_shmem_vmap(struct drm_gem_object *obj)
> +{
> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> +	void *vaddr;
> +	int ret;
> +
> +	ret = mutex_lock_interruptible(&shmem->vmap_lock);
> +	if (ret)
> +		return ERR_PTR(ret);
> +	vaddr = drm_gem_shmem_vmap_locked(shmem);
> +	mutex_unlock(&shmem->vmap_lock);
> +
> +	return vaddr;
> +}
> +EXPORT_SYMBOL(drm_gem_shmem_vmap);
> +
> +static void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem)
> +{
> +	struct drm_gem_object *obj = &shmem->base;
> +
> +	if (WARN_ON_ONCE(!shmem->vmap_use_count))
> +		return;
> +
> +	if (--shmem->vmap_use_count > 0)
> +		return;
> +
> +	if (obj->import_attach)
> +		dma_buf_vunmap(obj->import_attach->dmabuf, shmem->vaddr);
> +	else
> +		vunmap(shmem->vaddr);
> +
> +	shmem->vaddr = NULL;
> +	drm_gem_shmem_put_pages(shmem);
> +}
> +
> +/*
> + * drm_gem_shmem_vunmap - Unmap a virtual mapping fo a shmem GEM object
> + * @shmem: shmem GEM object
> + *
> + * This function removes the virtual address when use count drops to zero.
> + */
> +void drm_gem_shmem_vunmap(struct drm_gem_object *obj, void *vaddr)
> +{
> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> +
> +	mutex_lock(&shmem->vmap_lock);
> +	drm_gem_shmem_vunmap_locked(shmem);
> +	mutex_unlock(&shmem->vmap_lock);
> +}
> +EXPORT_SYMBOL(drm_gem_shmem_vunmap);
> +
> +static struct drm_gem_shmem_object *
> +drm_gem_shmem_create_with_handle(struct drm_file *file_priv,
> +				 struct drm_device *dev, size_t size,
> +				 uint32_t *handle)
> +{
> +	struct drm_gem_shmem_object *shmem;
> +	int ret;
> +
> +	shmem = drm_gem_shmem_create(dev, size);
> +	if (IS_ERR(shmem))
> +		return shmem;
> +
> +	/*
> +	 * Allocate an id of idr table where the obj is registered
> +	 * and handle has the id what user can see.
> +	 */
> +	ret = drm_gem_handle_create(file_priv, &shmem->base, handle);
> +	/* drop reference from allocate - handle holds it now. */
> +	drm_gem_object_put_unlocked(&shmem->base);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	return shmem;
> +}
> +
> +/**
> + * drm_gem_shmem_dumb_create - Create a dumb shmem buffer object
> + * @file: DRM file structure to create the dumb buffer for
> + * @dev: DRM device
> + * @args: IOCTL data
> + *
> + * This function computes the pitch of the dumb buffer and rounds it up to an
> + * integer number of bytes per pixel. Drivers for hardware that doesn't have
> + * any additional restrictions on the pitch can directly use this function as
> + * their &drm_driver.dumb_create callback.
> + *
> + * For hardware with additional restrictions, drivers can adjust the fields
> + * set up by userspace before calling into this function.
> + *
> + * Returns:
> + * 0 on success or a negative error code on failure.
> + */
> +int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
> +			      struct drm_mode_create_dumb *args)
> +{
> +	u32 min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
> +	struct drm_gem_shmem_object *shmem;
> +
> +	if (!args->pitch || !args->size) {
> +		args->pitch = min_pitch;
> +		args->size = args->pitch * args->height;
> +	} else {
> +		/* ensure sane minimum values */
> +		if (args->pitch < min_pitch)
> +			args->pitch = min_pitch;
> +		if (args->size < args->pitch * args->height)
> +			args->size = args->pitch * args->height;
> +	}
> +
> +	shmem = drm_gem_shmem_create_with_handle(file, dev, args->size, &args->handle);
> +
> +	return PTR_ERR_OR_ZERO(shmem);
> +}
> +EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create);
> +
> +static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
> +{
> +	struct vm_area_struct *vma = vmf->vma;
> +	struct drm_gem_object *obj = vma->vm_private_data;
> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> +	loff_t num_pages = obj->size >> PAGE_SHIFT;
> +	struct page *page;
> +
> +	if (vmf->pgoff > num_pages || WARN_ON_ONCE(!shmem->pages))
> +		return VM_FAULT_SIGBUS;
> +
> +	page = shmem->pages[vmf->pgoff];
> +
> +	return vmf_insert_page(vma, vmf->address, page);
> +}
> +
> +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
> +{
> +	struct drm_gem_object *obj = vma->vm_private_data;
> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> +
> +	drm_gem_shmem_put_pages(shmem);

Imbalance get/put_pages here, if someone forks (which is what calls
vm_ops->open on an existing vma).

> +	drm_gem_vm_close(vma);
> +}
> +
> +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
> +	.fault = drm_gem_shmem_fault,
> +	.open = drm_gem_vm_open,
> +	.close = drm_gem_shmem_vm_close,
> +};
> +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
> +
> +/**
> + * drm_gem_shmem_mmap - Memory-map a shmem GEM object
> + * @filp: File object
> + * @vma: VMA for the area to be mapped
> + *
> + * This function implements an augmented version of the GEM DRM file mmap
> + * operation for shmem objects. Drivers which employ the shmem helpers should
> + * use this function as their &file_operations.mmap handler in the DRM device file's
> + * file_operations structure.
> + *
> + * Instead of directly referencing this function, drivers should use the
> + * DEFINE_DRM_GEM_SHMEM_FOPS() macro.
> + *
> + * Returns:
> + * 0 on success or a negative error code on failure.
> + */

Between cma helpers, gem shmem helpers and the drm_gem_mmap we now have
quite a bit a confusion of mmap functions. I think it'd be good to update
the kerneldoc for drm_gem_mmap() to point at these here (both the shmem
and cma version), so that people prefer to use these helpers here. Direct
call to drm_gem_mmap would only be needed if you want to use your own
vm_ops.

> +int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma)
> +{
> +	struct drm_gem_shmem_object *shmem;
> +	int ret;
> +
> +	ret = drm_gem_mmap(filp, vma);
> +	if (ret)
> +		return ret;
> +
> +	shmem = to_drm_gem_shmem_obj(vma->vm_private_data);
> +
> +	ret = drm_gem_shmem_get_pages(shmem);
> +	if (ret) {
> +		drm_gem_vm_close(vma);
> +		return ret;
> +	}
> +
> +	/* VM_PFNMAP was set by drm_gem_mmap() */
> +	vma->vm_flags &= ~VM_PFNMAP;
> +	vma->vm_flags |= VM_MIXEDMAP;
> +	vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
> +
> +	fput(vma->vm_file);
> +	vma->vm_file = get_file(shmem->base.filp);
> +	/* Remove the fake offset */
> +	vma->vm_pgoff -= drm_vma_node_start(&shmem->base.vma_node);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap);

Looking through your mmap code there's 2 bits:
- shmem isn't coherent, if you try to actually buffer share this with
  prime I expect it'll fail badly. We'd need begin/end_cpu_access
  callbacks in dma_buf_ops to make this work. So not entirely sure how
  much value there is in implementing the prime mmap stuff (but doesn't
  hurt to have it).

- shmem already has an mmap implemtation, you can just use that. Needs a
  similar mmap forwarding trick as you've done for prime mmap, but instead
  you forward to obj->base.filp. That allows you to cut away all the
  vm_ops and everything. I guess we could clean this up in a follow-up,
  since it doesn't have an effect on the interfaces exposed to drivers. At
  least not a big one, drm_gem_shmem_vm_ops would disappear.

> +
> +/**
> + * drm_gem_shmem_print_info() - Print &drm_gem_shmem_object info for debugfs
> + * @p: DRM printer
> + * @indent: Tab indentation level
> + * @obj: GEM object

Would be good to reference the hook this is meant for:
&drm_gem_object_funcs.print_info, same for all the others. For those
drivers that want to pick&choose.

Cheers, Daniel

> + */
> +void drm_gem_shmem_print_info(struct drm_printer *p, unsigned int indent,
> +			      const struct drm_gem_object *obj)
> +{
> +	const struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> +
> +	drm_printf_indent(p, indent, "pages_use_count=%u\n", shmem->pages_use_count);
> +	drm_printf_indent(p, indent, "vmap_use_count=%u\n", shmem->vmap_use_count);
> +	drm_printf_indent(p, indent, "vaddr=%p\n", shmem->vaddr);
> +}
> +EXPORT_SYMBOL(drm_gem_shmem_print_info);
> +
> +/**
> + * drm_gem_shmem_get_sg_table - Provide a scatter/gather table of pinned
> + *                              pages for a shmem GEM object
> + * @obj: GEM object
> + *
> + * This function exports a scatter/gather table suitable for PRIME usage by
> + * calling the standard DMA mapping API.
> + *
> + * Returns:
> + * A pointer to the scatter/gather table of pinned pages or NULL on failure.
> + */
> +struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_object *obj)
> +{
> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> +
> +	return drm_prime_pages_to_sg(shmem->pages, obj->size >> PAGE_SHIFT);
> +}
> +EXPORT_SYMBOL_GPL(drm_gem_shmem_get_sg_table);
> +
> +/**
> + * drm_gem_shmem_prime_import_sg_table - Produce a shmem GEM object from
> + *                 another driver's scatter/gather table of pinned pages
> + * @dev: Device to import into
> + * @attach: DMA-BUF attachment
> + * @sgt: Scatter/gather table of pinned pages
> + *
> + * This function imports a scatter/gather table exported via DMA-BUF by
> + * another driver. Drivers that use the shmem helpers should set this as their
> + * &drm_driver.gem_prime_import_sg_table callback.
> + *
> + * Returns:
> + * A pointer to a newly created GEM object or an ERR_PTR-encoded negative
> + * error code on failure.
> + */
> +struct drm_gem_object *
> +drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
> +				    struct dma_buf_attachment *attach,
> +				    struct sg_table *sgt)
> +{
> +	size_t size = PAGE_ALIGN(attach->dmabuf->size);
> +	size_t npages = size >> PAGE_SHIFT;
> +	struct drm_gem_shmem_object *shmem;
> +	int ret;
> +
> +	shmem = drm_gem_shmem_create(dev, size);
> +	if (IS_ERR(shmem))
> +		return ERR_CAST(shmem);
> +
> +	shmem->pages = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
> +	if (!shmem->pages) {
> +		ret = -ENOMEM;
> +		goto err_free_gem;
> +	}
> +
> +	ret = drm_prime_sg_to_page_addr_arrays(sgt, shmem->pages, NULL, npages);
> +	if (ret < 0)
> +		goto err_free_array;
> +
> +	shmem->sgt = sgt;
> +	shmem->pages_use_count = 1; /* Permanently pinned from our point of view */
> +
> +	DRM_DEBUG_PRIME("size = %zu\n", size);
> +
> +	return &shmem->base;
> +
> +err_free_array:
> +	kvfree(shmem->pages);
> +err_free_gem:
> +	drm_gem_object_put_unlocked(&shmem->base);
> +
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(drm_gem_shmem_prime_import_sg_table);
> diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
> new file mode 100644
> index 000000000000..26b05e06407d
> --- /dev/null
> +++ b/include/drm/drm_gem_shmem_helper.h
> @@ -0,0 +1,153 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef __DRM_GEM_SHMEM_HELPER_H__
> +#define __DRM_GEM_SHMEM_HELPER_H__
> +
> +#include <linux/fs.h>
> +#include <linux/mm.h>
> +#include <linux/mutex.h>
> +
> +#include <drm/drm_file.h>
> +#include <drm/drm_gem.h>
> +#include <drm/drm_ioctl.h>
> +#include <drm/drm_prime.h>
> +
> +struct dma_buf_attachment;
> +struct drm_mode_create_dumb;
> +struct drm_printer;
> +struct sg_table;
> +
> +/**
> + * struct drm_gem_shmem_object - GEM object backed by shmem
> + */
> +struct drm_gem_shmem_object {
> +	/**
> +	 * @base: Base GEM object
> +	 */
> +	struct drm_gem_object base;
> +
> +	/**
> +	 * @pages_lock: Protects the page table and use count
> +	 */
> +	struct mutex pages_lock;
> +
> +	/**
> +	 * @pages: Page table
> +	 */
> +	struct page **pages;
> +
> +	/**
> +	 * @pages_use_count:
> +	 *
> +	 * Reference count on the pages table.
> +	 * The pages are put when the count reaches zero.
> +	 */
> +	unsigned int pages_use_count;
> +
> +	/**
> +	 * @pages_mark_dirty_on_put:
> +	 *
> +	 * Mark pages as dirty when they are put.
> +	 */
> +	unsigned int pages_mark_dirty_on_put    : 1;
> +
> +	/**
> +	 * @pages_mark_accessed_on_put:
> +	 *
> +	 * Mark pages as accessed when they are put.
> +	 */
> +	unsigned int pages_mark_accessed_on_put : 1;
> +
> +	/**
> +	 * @sgt: Scatter/gather table for imported PRIME buffers
> +	 */
> +	struct sg_table *sgt;
> +
> +	/**
> +	 * @vmap_lock: Protects the vmap address and use count
> +	 */
> +	struct mutex vmap_lock;
> +
> +	/**
> +	 * @vaddr: Kernel virtual address of the backing memory
> +	 */
> +	void *vaddr;
> +
> +	/**
> +	 * @vmap_use_count:
> +	 *
> +	 * Reference count on the virtual address.
> +	 * The address are un-mapped when the count reaches zero.
> +	 */
> +	unsigned int vmap_use_count;
> +};
> +
> +#define to_drm_gem_shmem_obj(obj) \
> +	container_of(obj, struct drm_gem_shmem_object, base)
> +
> +/**
> + * DEFINE_DRM_GEM_SHMEM_FOPS() - Macro to generate file operations for shmem drivers
> + * @name: name for the generated structure
> + *
> + * This macro autogenerates a suitable &struct file_operations for shmem based
> + * drivers, which can be assigned to &drm_driver.fops. Note that this structure
> + * cannot be shared between drivers, because it contains a reference to the
> + * current module using THIS_MODULE.
> + *
> + * Note that the declaration is already marked as static - if you need a
> + * non-static version of this you're probably doing it wrong and will break the
> + * THIS_MODULE reference by accident.
> + */
> +#define DEFINE_DRM_GEM_SHMEM_FOPS(name) \
> +	static const struct file_operations name = {\
> +		.owner		= THIS_MODULE,\
> +		.open		= drm_open,\
> +		.release	= drm_release,\
> +		.unlocked_ioctl	= drm_ioctl,\
> +		.compat_ioctl	= drm_compat_ioctl,\
> +		.poll		= drm_poll,\
> +		.read		= drm_read,\
> +		.llseek		= noop_llseek,\
> +		.mmap		= drm_gem_shmem_mmap, \
> +	}
> +
> +struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size);
> +void drm_gem_shmem_free_object(struct drm_gem_object *obj);
> +
> +int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem);
> +void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem);
> +int drm_gem_shmem_pin(struct drm_gem_object *obj);
> +void drm_gem_shmem_unpin(struct drm_gem_object *obj);
> +void *drm_gem_shmem_vmap(struct drm_gem_object *obj);
> +void drm_gem_shmem_vunmap(struct drm_gem_object *obj, void *vaddr);
> +
> +int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
> +			      struct drm_mode_create_dumb *args);
> +
> +int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma);
> +
> +extern const struct vm_operations_struct drm_gem_shmem_vm_ops;
> +
> +void drm_gem_shmem_print_info(struct drm_printer *p, unsigned int indent,
> +			      const struct drm_gem_object *obj);
> +
> +struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_object *obj);
> +struct drm_gem_object *
> +drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
> +				    struct dma_buf_attachment *attach,
> +				    struct sg_table *sgt);
> +
> +/**
> + * DRM_GEM_SHMEM_DRIVER_OPS - Default shmem GEM operations
> + *
> + * This macro provides a shortcut for setting the shmem GEM operations in
> + * the &drm_driver structure.
> + */
> +#define DRM_GEM_SHMEM_DRIVER_OPS \
> +	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd, \
> +	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle, \
> +	.gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, \
> +	.gem_prime_mmap		= drm_gem_prime_mmap, \
> +	.dumb_create		= drm_gem_shmem_dumb_create
> +
> +#endif /* __DRM_GEM_SHMEM_HELPER_H__ */
> -- 
> 2.15.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* ✓ Fi.CI.IGT: success for drm: Add shmem GEM library
  2018-10-17 13:04 [PATCH v5 0/5] drm: Add shmem GEM library Noralf Trønnes
                   ` (6 preceding siblings ...)
  2018-10-17 14:02 ` ✓ Fi.CI.BAT: success " Patchwork
@ 2018-10-17 17:37 ` Patchwork
  7 siblings, 0 replies; 35+ messages in thread
From: Patchwork @ 2018-10-17 17:37 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx

== Series Details ==

Series: drm: Add shmem GEM library
URL   : https://patchwork.freedesktop.org/series/51120/
State : success

== Summary ==

= CI Bug Log - changes from CI_DRM_4998_full -> Patchwork_10490_full =

== Summary - WARNING ==

  Minor unknown changes coming with Patchwork_10490_full need to be verified
  manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in Patchwork_10490_full, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  

== Possible new issues ==

  Here are the unknown changes that may have been introduced in Patchwork_10490_full:

  === IGT changes ===

    ==== Warnings ====

    igt@perf_pmu@rc6:
      shard-kbl:          SKIP -> PASS

    
== Known issues ==

  Here are the changes found in Patchwork_10490_full that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@debugfs_test@read_all_entries_display_off:
      shard-skl:          PASS -> INCOMPLETE (fdo#104108) +1

    igt@drv_suspend@fence-restore-untiled:
      shard-kbl:          PASS -> INCOMPLETE (fdo#103665)

    igt@gem_exec_await@wide-contexts:
      shard-glk:          PASS -> FAIL (fdo#106680)

    igt@gem_exec_schedule@pi-ringfull-blt:
      shard-skl:          NOTRUN -> FAIL (fdo#103158)

    igt@kms_atomic_transition@1x-modeset-transitions:
      shard-skl:          NOTRUN -> FAIL (fdo#108470) +1

    igt@kms_available_modes_crc@available_mode_test_crc:
      shard-apl:          PASS -> FAIL (fdo#106641)

    igt@kms_busy@extended-modeset-hang-newfb-render-c:
      shard-glk:          NOTRUN -> DMESG-WARN (fdo#107956)

    igt@kms_busy@extended-modeset-hang-newfb-with-reset-render-b:
      shard-skl:          NOTRUN -> DMESG-WARN (fdo#107956) +1

    igt@kms_busy@extended-pageflip-modeset-hang-oldfb-render-b:
      shard-skl:          PASS -> DMESG-WARN (fdo#107956)

    igt@kms_color@pipe-a-ctm-blue-to-red:
      shard-skl:          NOTRUN -> FAIL (fdo#107201)

    igt@kms_cursor_crc@cursor-256x256-suspend:
      shard-skl:          NOTRUN -> FAIL (fdo#103232, fdo#103191)

    igt@kms_draw_crc@draw-method-rgb565-mmap-gtt-ytiled:
      shard-skl:          NOTRUN -> FAIL (fdo#103184)

    igt@kms_draw_crc@draw-method-xrgb8888-pwrite-untiled:
      shard-skl:          NOTRUN -> FAIL (fdo#108472)

    igt@kms_flip@2x-flip-vs-expired-vblank-interruptible:
      shard-glk:          PASS -> FAIL (fdo#105363)

    igt@kms_frontbuffer_tracking@fbcpsr-stridechange:
      shard-skl:          NOTRUN -> FAIL (fdo#105683)

    igt@kms_frontbuffer_tracking@psr-1p-offscren-pri-indfb-draw-mmap-gtt:
      shard-skl:          NOTRUN -> FAIL (fdo#103167) +3

    igt@kms_plane@plane-position-covered-pipe-b-planes:
      shard-apl:          PASS -> FAIL (fdo#103166)

    igt@kms_plane_alpha_blend@pipe-a-alpha-7efc:
      shard-skl:          NOTRUN -> FAIL (fdo#107815, fdo#108145) +1

    igt@kms_plane_alpha_blend@pipe-a-constant-alpha-max:
      shard-apl:          NOTRUN -> FAIL (fdo#108145)

    igt@kms_plane_multiple@atomic-pipe-b-tiling-x:
      shard-glk:          PASS -> FAIL (fdo#103166)

    
    ==== Possible fixes ====

    igt@gem_pwrite_pread@uncached-pwrite-blt-gtt_mmap-performance:
      shard-apl:          INCOMPLETE (fdo#103927) -> PASS

    igt@kms_busy@extended-modeset-hang-newfb-with-reset-render-c:
      shard-kbl:          DMESG-WARN (fdo#107956) -> PASS

    igt@kms_cursor_legacy@flip-vs-cursor-atomic-transitions-varying-size:
      shard-glk:          INCOMPLETE (fdo#103359, k.org#198133) -> PASS

    igt@kms_flip@flip-vs-expired-vblank:
      shard-skl:          FAIL (fdo#105363) -> PASS +1

    igt@kms_flip@flip-vs-modeset-interruptible:
      shard-kbl:          DMESG-WARN (fdo#103558, fdo#105602) -> PASS +3

    igt@kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-draw-mmap-cpu:
      shard-glk:          FAIL (fdo#103167) -> PASS

    igt@kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-indfb-draw-render:
      shard-glk:          DMESG-FAIL (fdo#106538) -> PASS

    igt@kms_plane@plane-panning-bottom-right-suspend-pipe-a-planes:
      shard-skl:          INCOMPLETE (fdo#104108, fdo#107773) -> PASS

    igt@kms_plane@plane-position-covered-pipe-a-planes:
      shard-glk:          FAIL (fdo#103166) -> PASS

    igt@kms_setmode@basic:
      shard-kbl:          FAIL (fdo#99912) -> PASS

    igt@kms_vblank@pipe-b-ts-continuation-idle-hang:
      shard-glk:          DMESG-WARN (fdo#105763, fdo#106538) -> PASS +1

    
  fdo#103158 https://bugs.freedesktop.org/show_bug.cgi?id=103158
  fdo#103166 https://bugs.freedesktop.org/show_bug.cgi?id=103166
  fdo#103167 https://bugs.freedesktop.org/show_bug.cgi?id=103167
  fdo#103184 https://bugs.freedesktop.org/show_bug.cgi?id=103184
  fdo#103191 https://bugs.freedesktop.org/show_bug.cgi?id=103191
  fdo#103232 https://bugs.freedesktop.org/show_bug.cgi?id=103232
  fdo#103359 https://bugs.freedesktop.org/show_bug.cgi?id=103359
  fdo#103558 https://bugs.freedesktop.org/show_bug.cgi?id=103558
  fdo#103665 https://bugs.freedesktop.org/show_bug.cgi?id=103665
  fdo#103927 https://bugs.freedesktop.org/show_bug.cgi?id=103927
  fdo#104108 https://bugs.freedesktop.org/show_bug.cgi?id=104108
  fdo#105363 https://bugs.freedesktop.org/show_bug.cgi?id=105363
  fdo#105602 https://bugs.freedesktop.org/show_bug.cgi?id=105602
  fdo#105683 https://bugs.freedesktop.org/show_bug.cgi?id=105683
  fdo#105763 https://bugs.freedesktop.org/show_bug.cgi?id=105763
  fdo#106538 https://bugs.freedesktop.org/show_bug.cgi?id=106538
  fdo#106641 https://bugs.freedesktop.org/show_bug.cgi?id=106641
  fdo#106680 https://bugs.freedesktop.org/show_bug.cgi?id=106680
  fdo#107201 https://bugs.freedesktop.org/show_bug.cgi?id=107201
  fdo#107773 https://bugs.freedesktop.org/show_bug.cgi?id=107773
  fdo#107815 https://bugs.freedesktop.org/show_bug.cgi?id=107815
  fdo#107956 https://bugs.freedesktop.org/show_bug.cgi?id=107956
  fdo#108145 https://bugs.freedesktop.org/show_bug.cgi?id=108145
  fdo#108470 https://bugs.freedesktop.org/show_bug.cgi?id=108470
  fdo#108472 https://bugs.freedesktop.org/show_bug.cgi?id=108472
  fdo#99912 https://bugs.freedesktop.org/show_bug.cgi?id=99912
  k.org#198133 https://bugzilla.kernel.org/show_bug.cgi?id=198133


== Participating hosts (6 -> 6) ==

  No changes in participating hosts


== Build changes ==

    * Linux: CI_DRM_4998 -> Patchwork_10490

  CI_DRM_4998: a44032bf63ec3acf03e451105d90ee66a7d7f867 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4683: 7766b1e2348b32cc8ed58a972c6fd53b20279549 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_10490: 593b702cf1af25accdb63a18d1b7c70e1e6ebc71 @ git://anongit.freedesktop.org/gfx-ci/linux
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_10490/shards.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 3/5] drm/gem: Add drm_gem_object_funcs
  2018-10-17 13:04 ` [PATCH v5 3/5] drm/gem: Add drm_gem_object_funcs Noralf Trønnes
@ 2018-10-22 12:57   ` Christian König
  2018-10-23 13:46     ` Daniel Vetter
  2018-10-31 23:37   ` Noralf Trønnes
  1 sibling, 1 reply; 35+ messages in thread
From: Christian König @ 2018-10-22 12:57 UTC (permalink / raw)
  To: Noralf Trønnes, dri-devel; +Cc: intel-gfx, sam, david

Am 17.10.18 um 15:04 schrieb Noralf Trønnes:
> This adds an optional function table on GEM objects.
> The main benefit is for drivers that support more than one type of
> memory (shmem,vram,cma) for their buffers depending on the hardware it
> runs on. With the callbacks attached to the GEM object itself, it is
> easier to have core helpers for the the various buffer types. The driver
> only has to make the decision about buffer type on GEM object creation
> and all other callbacks can be handled by the chosen helper.
>
> drm_driver->gem_prime_res_obj has not been added since there's a todo to
> put a reservation_object into drm_gem_object.
>
> v2: Drop drm_gem_object_funcs->prime_mmap in favour of
> drm_gem_prime_mmap() (Daniel Vetter)
>
> v1:
> - drm_gem_object_funcs.map -> .prime_map let it only do PRIME mmap like
>    the function it superseeds (Daniel Vetter)
> - Flip around the if ladders and make obj->funcs the first choice
>    highlighting the fact that this the new default way of doing it
>    (Daniel Vetter)

Well could we please make this mandatory and convert drivers bit by bit?

Christian.

>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>   drivers/gpu/drm/drm_client.c |  12 ++--
>   drivers/gpu/drm/drm_gem.c    | 109 ++++++++++++++++++++++++++++++++---
>   drivers/gpu/drm/drm_prime.c  |  34 ++++++-----
>   include/drm/drm_gem.h        | 131 +++++++++++++++++++++++++++++++++++++++++++
>   4 files changed, 252 insertions(+), 34 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
> index 17d9a64e885e..eca7331762e4 100644
> --- a/drivers/gpu/drm/drm_client.c
> +++ b/drivers/gpu/drm/drm_client.c
> @@ -80,8 +80,7 @@ int drm_client_new(struct drm_device *dev, struct drm_client_dev *client,
>   {
>   	int ret;
>   
> -	if (!drm_core_check_feature(dev, DRIVER_MODESET) ||
> -	    !dev->driver->dumb_create || !dev->driver->gem_prime_vmap)
> +	if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create)
>   		return -EOPNOTSUPP;
>   
>   	if (funcs && !try_module_get(funcs->owner))
> @@ -212,8 +211,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
>   {
>   	struct drm_device *dev = buffer->client->dev;
>   
> -	if (buffer->vaddr && dev->driver->gem_prime_vunmap)
> -		dev->driver->gem_prime_vunmap(buffer->gem, buffer->vaddr);
> +	drm_gem_vunmap(buffer->gem, buffer->vaddr);
>   
>   	if (buffer->gem)
>   		drm_gem_object_put_unlocked(buffer->gem);
> @@ -266,9 +264,9 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u
>   	 * fd_install step out of the driver backend hooks, to make that
>   	 * final step optional for internal users.
>   	 */
> -	vaddr = dev->driver->gem_prime_vmap(obj);
> -	if (!vaddr) {
> -		ret = -ENOMEM;
> +	vaddr = drm_gem_vmap(obj);
> +	if (IS_ERR(vaddr)) {
> +		ret = PTR_ERR(vaddr);
>   		goto err_delete;
>   	}
>   
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index 512078ebd97b..8b55ece97967 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -257,7 +257,9 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
>   	struct drm_gem_object *obj = ptr;
>   	struct drm_device *dev = obj->dev;
>   
> -	if (dev->driver->gem_close_object)
> +	if (obj->funcs && obj->funcs->close)
> +		obj->funcs->close(obj, file_priv);
> +	else if (dev->driver->gem_close_object)
>   		dev->driver->gem_close_object(obj, file_priv);
>   
>   	if (drm_core_check_feature(dev, DRIVER_PRIME))
> @@ -410,7 +412,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
>   	if (ret)
>   		goto err_remove;
>   
> -	if (dev->driver->gem_open_object) {
> +	if (obj->funcs && obj->funcs->open) {
> +		ret = obj->funcs->open(obj, file_priv);
> +		if (ret)
> +			goto err_revoke;
> +	} else if (dev->driver->gem_open_object) {
>   		ret = dev->driver->gem_open_object(obj, file_priv);
>   		if (ret)
>   			goto err_revoke;
> @@ -835,7 +841,9 @@ drm_gem_object_free(struct kref *kref)
>   		container_of(kref, struct drm_gem_object, refcount);
>   	struct drm_device *dev = obj->dev;
>   
> -	if (dev->driver->gem_free_object_unlocked) {
> +	if (obj->funcs) {
> +		obj->funcs->free(obj);
> +	} else if (dev->driver->gem_free_object_unlocked) {
>   		dev->driver->gem_free_object_unlocked(obj);
>   	} else if (dev->driver->gem_free_object) {
>   		WARN_ON(!mutex_is_locked(&dev->struct_mutex));
> @@ -864,13 +872,13 @@ drm_gem_object_put_unlocked(struct drm_gem_object *obj)
>   
>   	dev = obj->dev;
>   
> -	if (dev->driver->gem_free_object_unlocked) {
> -		kref_put(&obj->refcount, drm_gem_object_free);
> -	} else {
> +	if (dev->driver->gem_free_object) {
>   		might_lock(&dev->struct_mutex);
>   		if (kref_put_mutex(&obj->refcount, drm_gem_object_free,
>   				&dev->struct_mutex))
>   			mutex_unlock(&dev->struct_mutex);
> +	} else {
> +		kref_put(&obj->refcount, drm_gem_object_free);
>   	}
>   }
>   EXPORT_SYMBOL(drm_gem_object_put_unlocked);
> @@ -960,11 +968,14 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
>   	if (obj_size < vma->vm_end - vma->vm_start)
>   		return -EINVAL;
>   
> -	if (!dev->driver->gem_vm_ops)
> +	if (obj->funcs && obj->funcs->vm_ops)
> +		vma->vm_ops = obj->funcs->vm_ops;
> +	else if (dev->driver->gem_vm_ops)
> +		vma->vm_ops = dev->driver->gem_vm_ops;
> +	else
>   		return -EINVAL;
>   
>   	vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
> -	vma->vm_ops = dev->driver->gem_vm_ops;
>   	vma->vm_private_data = obj;
>   	vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
>   	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
> @@ -1066,6 +1077,86 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent,
>   	drm_printf_indent(p, indent, "imported=%s\n",
>   			  obj->import_attach ? "yes" : "no");
>   
> -	if (obj->dev->driver->gem_print_info)
> +	if (obj->funcs && obj->funcs->print_info)
> +		obj->funcs->print_info(p, indent, obj);
> +	else if (obj->dev->driver->gem_print_info)
>   		obj->dev->driver->gem_print_info(p, indent, obj);
>   }
> +
> +/**
> + * drm_gem_pin - Pin backing buffer in memory
> + * @obj: GEM object
> + *
> + * Make sure the backing buffer is pinned in memory.
> + *
> + * Returns:
> + * 0 on success or a negative error code on failure.
> + */
> +int drm_gem_pin(struct drm_gem_object *obj)
> +{
> +	if (obj->funcs && obj->funcs->pin)
> +		return obj->funcs->pin(obj);
> +	else if (obj->dev->driver->gem_prime_pin)
> +		return obj->dev->driver->gem_prime_pin(obj);
> +	else
> +		return 0;
> +}
> +EXPORT_SYMBOL(drm_gem_pin);
> +
> +/**
> + * drm_gem_unpin - Unpin backing buffer from memory
> + * @obj: GEM object
> + *
> + * Relax the requirement that the backing buffer is pinned in memory.
> + */
> +void drm_gem_unpin(struct drm_gem_object *obj)
> +{
> +	if (obj->funcs && obj->funcs->unpin)
> +		obj->funcs->unpin(obj);
> +	else if (obj->dev->driver->gem_prime_unpin)
> +		obj->dev->driver->gem_prime_unpin(obj);
> +}
> +EXPORT_SYMBOL(drm_gem_unpin);
> +
> +/**
> + * drm_gem_vmap - Map buffer into kernel virtual address space
> + * @obj: GEM object
> + *
> + * Returns:
> + * A virtual pointer to a newly created GEM object or an ERR_PTR-encoded negative
> + * error code on failure.
> + */
> +void *drm_gem_vmap(struct drm_gem_object *obj)
> +{
> +	void *vaddr;
> +
> +	if (obj->funcs && obj->funcs->vmap)
> +		vaddr = obj->funcs->vmap(obj);
> +	else if (obj->dev->driver->gem_prime_vmap)
> +		vaddr = obj->dev->driver->gem_prime_vmap(obj);
> +	else
> +		vaddr = ERR_PTR(-EOPNOTSUPP);
> +
> +	if (!vaddr)
> +		vaddr = ERR_PTR(-ENOMEM);
> +
> +	return vaddr;
> +}
> +EXPORT_SYMBOL(drm_gem_vmap);
> +
> +/**
> + * drm_gem_vunmap - Remove buffer mapping from kernel virtual address space
> + * @obj: GEM object
> + * @vaddr: Virtual address (can be NULL)
> + */
> +void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr)
> +{
> +	if (!vaddr)
> +		return;
> +
> +	if (obj->funcs && obj->funcs->vunmap)
> +		obj->funcs->vunmap(obj, vaddr);
> +	else if (obj->dev->driver->gem_prime_vunmap)
> +		obj->dev->driver->gem_prime_vunmap(obj, vaddr);
> +}
> +EXPORT_SYMBOL(drm_gem_vunmap);
> diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
> index 42abf98c1d4a..e0ab5213efa7 100644
> --- a/drivers/gpu/drm/drm_prime.c
> +++ b/drivers/gpu/drm/drm_prime.c
> @@ -199,7 +199,6 @@ int drm_gem_map_attach(struct dma_buf *dma_buf,
>   {
>   	struct drm_prime_attachment *prime_attach;
>   	struct drm_gem_object *obj = dma_buf->priv;
> -	struct drm_device *dev = obj->dev;
>   
>   	prime_attach = kzalloc(sizeof(*prime_attach), GFP_KERNEL);
>   	if (!prime_attach)
> @@ -208,10 +207,7 @@ int drm_gem_map_attach(struct dma_buf *dma_buf,
>   	prime_attach->dir = DMA_NONE;
>   	attach->priv = prime_attach;
>   
> -	if (!dev->driver->gem_prime_pin)
> -		return 0;
> -
> -	return dev->driver->gem_prime_pin(obj);
> +	return drm_gem_pin(obj);
>   }
>   EXPORT_SYMBOL(drm_gem_map_attach);
>   
> @@ -228,7 +224,6 @@ void drm_gem_map_detach(struct dma_buf *dma_buf,
>   {
>   	struct drm_prime_attachment *prime_attach = attach->priv;
>   	struct drm_gem_object *obj = dma_buf->priv;
> -	struct drm_device *dev = obj->dev;
>   
>   	if (prime_attach) {
>   		struct sg_table *sgt = prime_attach->sgt;
> @@ -247,8 +242,7 @@ void drm_gem_map_detach(struct dma_buf *dma_buf,
>   		attach->priv = NULL;
>   	}
>   
> -	if (dev->driver->gem_prime_unpin)
> -		dev->driver->gem_prime_unpin(obj);
> +	drm_gem_unpin(obj);
>   }
>   EXPORT_SYMBOL(drm_gem_map_detach);
>   
> @@ -310,7 +304,10 @@ struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
>   	if (WARN_ON(prime_attach->dir != DMA_NONE))
>   		return ERR_PTR(-EBUSY);
>   
> -	sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
> +	if (obj->funcs)
> +		sgt = obj->funcs->get_sg_table(obj);
> +	else
> +		sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
>   
>   	if (!IS_ERR(sgt)) {
>   		if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
> @@ -406,12 +403,13 @@ EXPORT_SYMBOL(drm_gem_dmabuf_release);
>   void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
>   {
>   	struct drm_gem_object *obj = dma_buf->priv;
> -	struct drm_device *dev = obj->dev;
> +	void *vaddr;
>   
> -	if (dev->driver->gem_prime_vmap)
> -		return dev->driver->gem_prime_vmap(obj);
> -	else
> -		return NULL;
> +	vaddr = drm_gem_vmap(obj);
> +	if (IS_ERR(vaddr))
> +		vaddr = NULL;
> +
> +	return vaddr;
>   }
>   EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
>   
> @@ -426,10 +424,8 @@ EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
>   void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
>   {
>   	struct drm_gem_object *obj = dma_buf->priv;
> -	struct drm_device *dev = obj->dev;
>   
> -	if (dev->driver->gem_prime_vunmap)
> -		dev->driver->gem_prime_vunmap(obj, vaddr);
> +	drm_gem_vunmap(obj, vaddr);
>   }
>   EXPORT_SYMBOL(drm_gem_dmabuf_vunmap);
>   
> @@ -529,7 +525,9 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev,
>   		return dmabuf;
>   	}
>   
> -	if (dev->driver->gem_prime_export)
> +	if (obj->funcs && obj->funcs->export)
> +		dmabuf = obj->funcs->export(obj, flags);
> +	else if (dev->driver->gem_prime_export)
>   		dmabuf = dev->driver->gem_prime_export(dev, obj, flags);
>   	else
>   		dmabuf = drm_gem_prime_export(dev, obj, flags);
> diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
> index 3583b98a1718..f466ce5bde0e 100644
> --- a/include/drm/drm_gem.h
> +++ b/include/drm/drm_gem.h
> @@ -38,6 +38,121 @@
>   
>   #include <drm/drm_vma_manager.h>
>   
> +struct drm_gem_object;
> +
> +/**
> + * struct drm_gem_object_funcs - GEM object functions
> + */
> +struct drm_gem_object_funcs {
> +	/**
> +	 * @free:
> +	 *
> +	 * Deconstructor for drm_gem_objects.
> +	 *
> +	 * This callback is mandatory.
> +	 */
> +	void (*free)(struct drm_gem_object *obj);
> +
> +	/**
> +	 * @open:
> +	 *
> +	 * Called upon GEM handle creation.
> +	 *
> +	 * This callback is optional.
> +	 */
> +	int (*open)(struct drm_gem_object *obj, struct drm_file *file);
> +
> +	/**
> +	 * @close:
> +	 *
> +	 * Called upon GEM handle release.
> +	 *
> +	 * This callback is optional.
> +	 */
> +	void (*close)(struct drm_gem_object *obj, struct drm_file *file);
> +
> +	/**
> +	 * @print_info:
> +	 *
> +	 * If driver subclasses struct &drm_gem_object, it can implement this
> +	 * optional hook for printing additional driver specific info.
> +	 *
> +	 * drm_printf_indent() should be used in the callback passing it the
> +	 * indent argument.
> +	 *
> +	 * This callback is called from drm_gem_print_info().
> +	 *
> +	 * This callback is optional.
> +	 */
> +	void (*print_info)(struct drm_printer *p, unsigned int indent,
> +			   const struct drm_gem_object *obj);
> +
> +	/**
> +	 * @export:
> +	 *
> +	 * Export backing buffer as a &dma_buf.
> +	 * If this is not set drm_gem_prime_export() is used.
> +	 *
> +	 * This callback is optional.
> +	 */
> +	struct dma_buf *(*export)(struct drm_gem_object *obj, int flags);
> +
> +	/**
> +	 * @pin:
> +	 *
> +	 * Pin backing buffer in memory.
> +	 *
> +	 * This callback is optional.
> +	 */
> +	int (*pin)(struct drm_gem_object *obj);
> +
> +	/**
> +	 * @unpin:
> +	 *
> +	 * Unpin backing buffer.
> +	 *
> +	 * This callback is optional.
> +	 */
> +	void (*unpin)(struct drm_gem_object *obj);
> +
> +	/**
> +	 * @get_sg_table:
> +	 *
> +	 * Returns a Scatter-Gather table representation of the buffer.
> +	 * Used when exporting a buffer.
> +	 *
> +	 * This callback is mandatory if buffer export is supported.
> +	 */
> +	struct sg_table *(*get_sg_table)(struct drm_gem_object *obj);
> +
> +	/**
> +	 * @vmap:
> +	 *
> +	 * Returns a virtual address for the buffer.
> +	 *
> +	 * This callback is optional.
> +	 */
> +	void *(*vmap)(struct drm_gem_object *obj);
> +
> +	/**
> +	 * @vunmap:
> +	 *
> +	 * Releases the the address previously returned by @vmap.
> +	 *
> +	 * This callback is optional.
> +	 */
> +	void (*vunmap)(struct drm_gem_object *obj, void *vaddr);
> +
> +	/**
> +	 * @vm_ops:
> +	 *
> +	 * Virtual memory operations used with mmap.
> +	 *
> +	 * This is optional but necessary for mmap support.
> +	 */
> +	const struct vm_operations_struct *vm_ops;
> +};
> +
>   /**
>    * struct drm_gem_object - GEM buffer object
>    *
> @@ -146,6 +261,17 @@ struct drm_gem_object {
>   	 * simply leave it as NULL.
>   	 */
>   	struct dma_buf_attachment *import_attach;
> +
> +	/**
> +	 * @funcs:
> +	 *
> +	 * Optional GEM object functions. If this is set, it will be used instead of the
> +	 * corresponding &drm_driver GEM callbacks.
> +	 *
> +	 * New drivers should use this.
> +	 *
> +	 */
> +	const struct drm_gem_object_funcs *funcs;
>   };
>   
>   /**
> @@ -293,4 +419,9 @@ int drm_gem_dumb_destroy(struct drm_file *file,
>   			 struct drm_device *dev,
>   			 uint32_t handle);
>   
> +int drm_gem_pin(struct drm_gem_object *obj);
> +void drm_gem_unpin(struct drm_gem_object *obj);
> +void *drm_gem_vmap(struct drm_gem_object *obj);
> +void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr);
> +
>   #endif /* __DRM_GEM_H__ */

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2018-10-17 15:46   ` Daniel Vetter
@ 2018-10-22 14:15     ` Noralf Trønnes
  2018-10-23 13:50       ` Daniel Vetter
  0 siblings, 1 reply; 35+ messages in thread
From: Noralf Trønnes @ 2018-10-22 14:15 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, sam, david, dri-devel


Den 17.10.2018 17.46, skrev Daniel Vetter:
> On Wed, Oct 17, 2018 at 03:04:53PM +0200, Noralf Trønnes wrote:
>> This adds a library for shmem backed GEM objects.
>>
>> v5:
>> - Drop drm_gem_shmem_prime_mmap() (Daniel Vetter)
>> - drm_gem_shmem_mmap(): Subtract drm_vma_node_start() to get the real
>>    vma->vm_pgoff
>> - drm_gem_shmem_fault(): Use vmf->pgoff now that vma->vm_pgoff is correct
>>
>> v4:
>> - Drop cache modes (Thomas Hellstrom)
>> - Add a GEM attached vtable
>>
>> v3:
>> - Grammar (Sam Ravnborg)
>> - s/drm_gem_shmem_put_pages_unlocked/drm_gem_shmem_put_pages_locked/
>>    (Sam Ravnborg)
>> - Add debug output in error path (Sam Ravnborg)
>>
>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
>> ---
>>   Documentation/gpu/drm-kms-helpers.rst  |  12 +
>>   drivers/gpu/drm/Kconfig                |   6 +
>>   drivers/gpu/drm/Makefile               |   1 +
>>   drivers/gpu/drm/drm_gem_shmem_helper.c | 551 +++++++++++++++++++++++++++++++++
>>   include/drm/drm_gem_shmem_helper.h     | 153 +++++++++
>>   5 files changed, 723 insertions(+)
>>   create mode 100644 drivers/gpu/drm/drm_gem_shmem_helper.c
>>   create mode 100644 include/drm/drm_gem_shmem_helper.h
>>

<snip>

>> +static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
>> +{
>> +	struct vm_area_struct *vma = vmf->vma;
>> +	struct drm_gem_object *obj = vma->vm_private_data;
>> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
>> +	loff_t num_pages = obj->size >> PAGE_SHIFT;
>> +	struct page *page;
>> +
>> +	if (vmf->pgoff > num_pages || WARN_ON_ONCE(!shmem->pages))
>> +		return VM_FAULT_SIGBUS;
>> +
>> +	page = shmem->pages[vmf->pgoff];
>> +
>> +	return vmf_insert_page(vma, vmf->address, page);
>> +}
>> +
>> +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
>> +{
>> +	struct drm_gem_object *obj = vma->vm_private_data;
>> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
>> +
>> +	drm_gem_shmem_put_pages(shmem);
> Imbalance get/put_pages here, if someone forks (which is what calls
> vm_ops->open on an existing vma).
>
>> +	drm_gem_vm_close(vma);
>> +}
>> +
>> +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
>> +	.fault = drm_gem_shmem_fault,
>> +	.open = drm_gem_vm_open,
>> +	.close = drm_gem_shmem_vm_close,
>> +};
>> +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
>> +
>> +/**
>> + * drm_gem_shmem_mmap - Memory-map a shmem GEM object
>> + * @filp: File object
>> + * @vma: VMA for the area to be mapped
>> + *
>> + * This function implements an augmented version of the GEM DRM file mmap
>> + * operation for shmem objects. Drivers which employ the shmem helpers should
>> + * use this function as their &file_operations.mmap handler in the DRM device file's
>> + * file_operations structure.
>> + *
>> + * Instead of directly referencing this function, drivers should use the
>> + * DEFINE_DRM_GEM_SHMEM_FOPS() macro.
>> + *
>> + * Returns:
>> + * 0 on success or a negative error code on failure.
>> + */
> Between cma helpers, gem shmem helpers and the drm_gem_mmap we now have
> quite a bit a confusion of mmap functions. I think it'd be good to update
> the kerneldoc for drm_gem_mmap() to point at these here (both the shmem
> and cma version), so that people prefer to use these helpers here. Direct
> call to drm_gem_mmap would only be needed if you want to use your own
> vm_ops.
>
>> +int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma)
>> +{
>> +	struct drm_gem_shmem_object *shmem;
>> +	int ret;
>> +
>> +	ret = drm_gem_mmap(filp, vma);
>> +	if (ret)
>> +		return ret;
>> +
>> +	shmem = to_drm_gem_shmem_obj(vma->vm_private_data);
>> +
>> +	ret = drm_gem_shmem_get_pages(shmem);
>> +	if (ret) {
>> +		drm_gem_vm_close(vma);
>> +		return ret;
>> +	}
>> +
>> +	/* VM_PFNMAP was set by drm_gem_mmap() */
>> +	vma->vm_flags &= ~VM_PFNMAP;
>> +	vma->vm_flags |= VM_MIXEDMAP;
>> +	vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
>> +
>> +	fput(vma->vm_file);
>> +	vma->vm_file = get_file(shmem->base.filp);
>> +	/* Remove the fake offset */
>> +	vma->vm_pgoff -= drm_vma_node_start(&shmem->base.vma_node);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap);
> Looking through your mmap code there's 2 bits:
> - shmem isn't coherent,

You saved me in the last minute with that comment Daniel.

I just remembered that on the Raspberry Pi I need to swap the bytes 
(RGB565,
SPI big endian) before transfer because its SPI can't do 16-bit transfers.
So I removed the swapping and sent the shmem buffer straight through to SPI.
This resulted in fbcon looking erratic and "distorted", so it didn't work
with the generic fbdev emulation shadow buffer being copied by the cpu to
the shmem buffer which is DMA'ed out over SPI. Even though the SPI core is
using the streaming DMA API.
(apparently I've worked so much on DRM helper refactoring that I've
forgotten how the tinydrm drivers work...)

So it looks like I can't use shmem for the current tinydrm drivers, which
all use SPI. Unless there's a solution to my problem, I guess I'll I have
to postpone this shmem work until I can use it in a driver that I'm 
planning
to do further down the road. It will compress the framebuffer before
transfer over USB so no DMA on the shmem buffer.

Do you want me to apply the first 3 patches anyway, even though the shmem
stuff has to wait?

> if you try to actually buffer share this with
>    prime I expect it'll fail badly. We'd need begin/end_cpu_access
>    callbacks in dma_buf_ops to make this work. So not entirely sure how
>    much value there is in implementing the prime mmap stuff (but doesn't
>    hurt to have it).

The generic fbdev emulation uses PRIME mmap.

>
> - shmem already has an mmap implemtation, you can just use that. Needs a
>    similar mmap forwarding trick as you've done for prime mmap, but instead
>    you forward to obj->base.filp. That allows you to cut away all the
>    vm_ops and everything. I guess we could clean this up in a follow-up,
>    since it doesn't have an effect on the interfaces exposed to drivers. At
>    least not a big one, drm_gem_shmem_vm_ops would disappear.

This approach using the shmem mmap seemed to work, not sure if the vm_flags
needs to be touched though.
(I'm putting it up here for the record, increases the chance of me finding
it when I pick up the shmem helper further down the road)

int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma)
{
     struct drm_gem_object *obj;
     int ret;

     ret = drm_gem_mmap(filp, vma);
     if (ret)
         return ret;

     obj = vma->vm_private_data;

     /* Remove the fake offset */
     vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);

     /* VM_PFNMAP was set by drm_gem_mmap() */
     vma->vm_flags &= ~VM_PFNMAP;
     vma->vm_flags |= VM_MIXEDMAP;
     vma->vm_page_prot = pgprot_decrypted(vm_get_page_prot(vma->vm_flags));

     fput(vma->vm_file);
     vma->vm_file = get_file(obj->filp);

     drm_gem_object_put_unlocked(obj);

     return call_mmap(vma->vm_file, vma);
}


Noralf.


>> +
>> +/**
>> + * drm_gem_shmem_print_info() - Print &drm_gem_shmem_object info for debugfs
>> + * @p: DRM printer
>> + * @indent: Tab indentation level
>> + * @obj: GEM object
> Would be good to reference the hook this is meant for:
> &drm_gem_object_funcs.print_info, same for all the others. For those
> drivers that want to pick&choose.
>
> Cheers, Daniel
>
>> + */
>> +void drm_gem_shmem_print_info(struct drm_printer *p, unsigned int indent,
>> +			      const struct drm_gem_object *obj)
>> +{
>> +	const struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
>> +
>> +	drm_printf_indent(p, indent, "pages_use_count=%u\n", shmem->pages_use_count);
>> +	drm_printf_indent(p, indent, "vmap_use_count=%u\n", shmem->vmap_use_count);
>> +	drm_printf_indent(p, indent, "vaddr=%p\n", shmem->vaddr);
>> +}
>> +EXPORT_SYMBOL(drm_gem_shmem_print_info);
>> +
>> +/**
>> + * drm_gem_shmem_get_sg_table - Provide a scatter/gather table of pinned
>> + *                              pages for a shmem GEM object
>> + * @obj: GEM object
>> + *
>> + * This function exports a scatter/gather table suitable for PRIME usage by
>> + * calling the standard DMA mapping API.
>> + *
>> + * Returns:
>> + * A pointer to the scatter/gather table of pinned pages or NULL on failure.
>> + */
>> +struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_object *obj)
>> +{
>> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
>> +
>> +	return drm_prime_pages_to_sg(shmem->pages, obj->size >> PAGE_SHIFT);
>> +}
>> +EXPORT_SYMBOL_GPL(drm_gem_shmem_get_sg_table);
>> +
>> +/**
>> + * drm_gem_shmem_prime_import_sg_table - Produce a shmem GEM object from
>> + *                 another driver's scatter/gather table of pinned pages
>> + * @dev: Device to import into
>> + * @attach: DMA-BUF attachment
>> + * @sgt: Scatter/gather table of pinned pages
>> + *
>> + * This function imports a scatter/gather table exported via DMA-BUF by
>> + * another driver. Drivers that use the shmem helpers should set this as their
>> + * &drm_driver.gem_prime_import_sg_table callback.
>> + *
>> + * Returns:
>> + * A pointer to a newly created GEM object or an ERR_PTR-encoded negative
>> + * error code on failure.
>> + */
>> +struct drm_gem_object *
>> +drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
>> +				    struct dma_buf_attachment *attach,
>> +				    struct sg_table *sgt)
>> +{
>> +	size_t size = PAGE_ALIGN(attach->dmabuf->size);
>> +	size_t npages = size >> PAGE_SHIFT;
>> +	struct drm_gem_shmem_object *shmem;
>> +	int ret;
>> +
>> +	shmem = drm_gem_shmem_create(dev, size);
>> +	if (IS_ERR(shmem))
>> +		return ERR_CAST(shmem);
>> +
>> +	shmem->pages = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
>> +	if (!shmem->pages) {
>> +		ret = -ENOMEM;
>> +		goto err_free_gem;
>> +	}
>> +
>> +	ret = drm_prime_sg_to_page_addr_arrays(sgt, shmem->pages, NULL, npages);
>> +	if (ret < 0)
>> +		goto err_free_array;
>> +
>> +	shmem->sgt = sgt;
>> +	shmem->pages_use_count = 1; /* Permanently pinned from our point of view */
>> +
>> +	DRM_DEBUG_PRIME("size = %zu\n", size);
>> +
>> +	return &shmem->base;
>> +
>> +err_free_array:
>> +	kvfree(shmem->pages);
>> +err_free_gem:
>> +	drm_gem_object_put_unlocked(&shmem->base);
>> +
>> +	return ERR_PTR(ret);
>> +}
>> +EXPORT_SYMBOL_GPL(drm_gem_shmem_prime_import_sg_table);
>> diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
>> new file mode 100644
>> index 000000000000..26b05e06407d
>> --- /dev/null
>> +++ b/include/drm/drm_gem_shmem_helper.h
>> @@ -0,0 +1,153 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +
>> +#ifndef __DRM_GEM_SHMEM_HELPER_H__
>> +#define __DRM_GEM_SHMEM_HELPER_H__
>> +
>> +#include <linux/fs.h>
>> +#include <linux/mm.h>
>> +#include <linux/mutex.h>
>> +
>> +#include <drm/drm_file.h>
>> +#include <drm/drm_gem.h>
>> +#include <drm/drm_ioctl.h>
>> +#include <drm/drm_prime.h>
>> +
>> +struct dma_buf_attachment;
>> +struct drm_mode_create_dumb;
>> +struct drm_printer;
>> +struct sg_table;
>> +
>> +/**
>> + * struct drm_gem_shmem_object - GEM object backed by shmem
>> + */
>> +struct drm_gem_shmem_object {
>> +	/**
>> +	 * @base: Base GEM object
>> +	 */
>> +	struct drm_gem_object base;
>> +
>> +	/**
>> +	 * @pages_lock: Protects the page table and use count
>> +	 */
>> +	struct mutex pages_lock;
>> +
>> +	/**
>> +	 * @pages: Page table
>> +	 */
>> +	struct page **pages;
>> +
>> +	/**
>> +	 * @pages_use_count:
>> +	 *
>> +	 * Reference count on the pages table.
>> +	 * The pages are put when the count reaches zero.
>> +	 */
>> +	unsigned int pages_use_count;
>> +
>> +	/**
>> +	 * @pages_mark_dirty_on_put:
>> +	 *
>> +	 * Mark pages as dirty when they are put.
>> +	 */
>> +	unsigned int pages_mark_dirty_on_put    : 1;
>> +
>> +	/**
>> +	 * @pages_mark_accessed_on_put:
>> +	 *
>> +	 * Mark pages as accessed when they are put.
>> +	 */
>> +	unsigned int pages_mark_accessed_on_put : 1;
>> +
>> +	/**
>> +	 * @sgt: Scatter/gather table for imported PRIME buffers
>> +	 */
>> +	struct sg_table *sgt;
>> +
>> +	/**
>> +	 * @vmap_lock: Protects the vmap address and use count
>> +	 */
>> +	struct mutex vmap_lock;
>> +
>> +	/**
>> +	 * @vaddr: Kernel virtual address of the backing memory
>> +	 */
>> +	void *vaddr;
>> +
>> +	/**
>> +	 * @vmap_use_count:
>> +	 *
>> +	 * Reference count on the virtual address.
>> +	 * The address are un-mapped when the count reaches zero.
>> +	 */
>> +	unsigned int vmap_use_count;
>> +};
>> +
>> +#define to_drm_gem_shmem_obj(obj) \
>> +	container_of(obj, struct drm_gem_shmem_object, base)
>> +
>> +/**
>> + * DEFINE_DRM_GEM_SHMEM_FOPS() - Macro to generate file operations for shmem drivers
>> + * @name: name for the generated structure
>> + *
>> + * This macro autogenerates a suitable &struct file_operations for shmem based
>> + * drivers, which can be assigned to &drm_driver.fops. Note that this structure
>> + * cannot be shared between drivers, because it contains a reference to the
>> + * current module using THIS_MODULE.
>> + *
>> + * Note that the declaration is already marked as static - if you need a
>> + * non-static version of this you're probably doing it wrong and will break the
>> + * THIS_MODULE reference by accident.
>> + */
>> +#define DEFINE_DRM_GEM_SHMEM_FOPS(name) \
>> +	static const struct file_operations name = {\
>> +		.owner		= THIS_MODULE,\
>> +		.open		= drm_open,\
>> +		.release	= drm_release,\
>> +		.unlocked_ioctl	= drm_ioctl,\
>> +		.compat_ioctl	= drm_compat_ioctl,\
>> +		.poll		= drm_poll,\
>> +		.read		= drm_read,\
>> +		.llseek		= noop_llseek,\
>> +		.mmap		= drm_gem_shmem_mmap, \
>> +	}
>> +
>> +struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size);
>> +void drm_gem_shmem_free_object(struct drm_gem_object *obj);
>> +
>> +int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem);
>> +void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem);
>> +int drm_gem_shmem_pin(struct drm_gem_object *obj);
>> +void drm_gem_shmem_unpin(struct drm_gem_object *obj);
>> +void *drm_gem_shmem_vmap(struct drm_gem_object *obj);
>> +void drm_gem_shmem_vunmap(struct drm_gem_object *obj, void *vaddr);
>> +
>> +int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
>> +			      struct drm_mode_create_dumb *args);
>> +
>> +int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma);
>> +
>> +extern const struct vm_operations_struct drm_gem_shmem_vm_ops;
>> +
>> +void drm_gem_shmem_print_info(struct drm_printer *p, unsigned int indent,
>> +			      const struct drm_gem_object *obj);
>> +
>> +struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_object *obj);
>> +struct drm_gem_object *
>> +drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
>> +				    struct dma_buf_attachment *attach,
>> +				    struct sg_table *sgt);
>> +
>> +/**
>> + * DRM_GEM_SHMEM_DRIVER_OPS - Default shmem GEM operations
>> + *
>> + * This macro provides a shortcut for setting the shmem GEM operations in
>> + * the &drm_driver structure.
>> + */
>> +#define DRM_GEM_SHMEM_DRIVER_OPS \
>> +	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd, \
>> +	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle, \
>> +	.gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, \
>> +	.gem_prime_mmap		= drm_gem_prime_mmap, \
>> +	.dumb_create		= drm_gem_shmem_dumb_create
>> +
>> +#endif /* __DRM_GEM_SHMEM_HELPER_H__ */
>> -- 
>> 2.15.1
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/dri-devel

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 3/5] drm/gem: Add drm_gem_object_funcs
  2018-10-22 12:57   ` Christian König
@ 2018-10-23 13:46     ` Daniel Vetter
  0 siblings, 0 replies; 35+ messages in thread
From: Daniel Vetter @ 2018-10-23 13:46 UTC (permalink / raw)
  To: christian.koenig; +Cc: intel-gfx, Noralf Trønnes, sam, david, dri-devel

On Mon, Oct 22, 2018 at 02:57:28PM +0200, Christian König wrote:
> Am 17.10.18 um 15:04 schrieb Noralf Trønnes:
> > This adds an optional function table on GEM objects.
> > The main benefit is for drivers that support more than one type of
> > memory (shmem,vram,cma) for their buffers depending on the hardware it
> > runs on. With the callbacks attached to the GEM object itself, it is
> > easier to have core helpers for the the various buffer types. The driver
> > only has to make the decision about buffer type on GEM object creation
> > and all other callbacks can be handled by the chosen helper.
> > 
> > drm_driver->gem_prime_res_obj has not been added since there's a todo to
> > put a reservation_object into drm_gem_object.
> > 
> > v2: Drop drm_gem_object_funcs->prime_mmap in favour of
> > drm_gem_prime_mmap() (Daniel Vetter)
> > 
> > v1:
> > - drm_gem_object_funcs.map -> .prime_map let it only do PRIME mmap like
> >    the function it superseeds (Daniel Vetter)
> > - Flip around the if ladders and make obj->funcs the first choice
> >    highlighting the fact that this the new default way of doing it
> >    (Daniel Vetter)
> 
> Well could we please make this mandatory and convert drivers bit by bit?

Yeah I'm all for adding a new entry to todo.rst and getting this rolling.
If there's support (which seems so).
-Daniel

> 
> Christian.
> 
> > 
> > Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> > Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > ---
> >   drivers/gpu/drm/drm_client.c |  12 ++--
> >   drivers/gpu/drm/drm_gem.c    | 109 ++++++++++++++++++++++++++++++++---
> >   drivers/gpu/drm/drm_prime.c  |  34 ++++++-----
> >   include/drm/drm_gem.h        | 131 +++++++++++++++++++++++++++++++++++++++++++
> >   4 files changed, 252 insertions(+), 34 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
> > index 17d9a64e885e..eca7331762e4 100644
> > --- a/drivers/gpu/drm/drm_client.c
> > +++ b/drivers/gpu/drm/drm_client.c
> > @@ -80,8 +80,7 @@ int drm_client_new(struct drm_device *dev, struct drm_client_dev *client,
> >   {
> >   	int ret;
> > -	if (!drm_core_check_feature(dev, DRIVER_MODESET) ||
> > -	    !dev->driver->dumb_create || !dev->driver->gem_prime_vmap)
> > +	if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create)
> >   		return -EOPNOTSUPP;
> >   	if (funcs && !try_module_get(funcs->owner))
> > @@ -212,8 +211,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
> >   {
> >   	struct drm_device *dev = buffer->client->dev;
> > -	if (buffer->vaddr && dev->driver->gem_prime_vunmap)
> > -		dev->driver->gem_prime_vunmap(buffer->gem, buffer->vaddr);
> > +	drm_gem_vunmap(buffer->gem, buffer->vaddr);
> >   	if (buffer->gem)
> >   		drm_gem_object_put_unlocked(buffer->gem);
> > @@ -266,9 +264,9 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u
> >   	 * fd_install step out of the driver backend hooks, to make that
> >   	 * final step optional for internal users.
> >   	 */
> > -	vaddr = dev->driver->gem_prime_vmap(obj);
> > -	if (!vaddr) {
> > -		ret = -ENOMEM;
> > +	vaddr = drm_gem_vmap(obj);
> > +	if (IS_ERR(vaddr)) {
> > +		ret = PTR_ERR(vaddr);
> >   		goto err_delete;
> >   	}
> > diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> > index 512078ebd97b..8b55ece97967 100644
> > --- a/drivers/gpu/drm/drm_gem.c
> > +++ b/drivers/gpu/drm/drm_gem.c
> > @@ -257,7 +257,9 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
> >   	struct drm_gem_object *obj = ptr;
> >   	struct drm_device *dev = obj->dev;
> > -	if (dev->driver->gem_close_object)
> > +	if (obj->funcs && obj->funcs->close)
> > +		obj->funcs->close(obj, file_priv);
> > +	else if (dev->driver->gem_close_object)
> >   		dev->driver->gem_close_object(obj, file_priv);
> >   	if (drm_core_check_feature(dev, DRIVER_PRIME))
> > @@ -410,7 +412,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
> >   	if (ret)
> >   		goto err_remove;
> > -	if (dev->driver->gem_open_object) {
> > +	if (obj->funcs && obj->funcs->open) {
> > +		ret = obj->funcs->open(obj, file_priv);
> > +		if (ret)
> > +			goto err_revoke;
> > +	} else if (dev->driver->gem_open_object) {
> >   		ret = dev->driver->gem_open_object(obj, file_priv);
> >   		if (ret)
> >   			goto err_revoke;
> > @@ -835,7 +841,9 @@ drm_gem_object_free(struct kref *kref)
> >   		container_of(kref, struct drm_gem_object, refcount);
> >   	struct drm_device *dev = obj->dev;
> > -	if (dev->driver->gem_free_object_unlocked) {
> > +	if (obj->funcs) {
> > +		obj->funcs->free(obj);
> > +	} else if (dev->driver->gem_free_object_unlocked) {
> >   		dev->driver->gem_free_object_unlocked(obj);
> >   	} else if (dev->driver->gem_free_object) {
> >   		WARN_ON(!mutex_is_locked(&dev->struct_mutex));
> > @@ -864,13 +872,13 @@ drm_gem_object_put_unlocked(struct drm_gem_object *obj)
> >   	dev = obj->dev;
> > -	if (dev->driver->gem_free_object_unlocked) {
> > -		kref_put(&obj->refcount, drm_gem_object_free);
> > -	} else {
> > +	if (dev->driver->gem_free_object) {
> >   		might_lock(&dev->struct_mutex);
> >   		if (kref_put_mutex(&obj->refcount, drm_gem_object_free,
> >   				&dev->struct_mutex))
> >   			mutex_unlock(&dev->struct_mutex);
> > +	} else {
> > +		kref_put(&obj->refcount, drm_gem_object_free);
> >   	}
> >   }
> >   EXPORT_SYMBOL(drm_gem_object_put_unlocked);
> > @@ -960,11 +968,14 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
> >   	if (obj_size < vma->vm_end - vma->vm_start)
> >   		return -EINVAL;
> > -	if (!dev->driver->gem_vm_ops)
> > +	if (obj->funcs && obj->funcs->vm_ops)
> > +		vma->vm_ops = obj->funcs->vm_ops;
> > +	else if (dev->driver->gem_vm_ops)
> > +		vma->vm_ops = dev->driver->gem_vm_ops;
> > +	else
> >   		return -EINVAL;
> >   	vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
> > -	vma->vm_ops = dev->driver->gem_vm_ops;
> >   	vma->vm_private_data = obj;
> >   	vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
> >   	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
> > @@ -1066,6 +1077,86 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent,
> >   	drm_printf_indent(p, indent, "imported=%s\n",
> >   			  obj->import_attach ? "yes" : "no");
> > -	if (obj->dev->driver->gem_print_info)
> > +	if (obj->funcs && obj->funcs->print_info)
> > +		obj->funcs->print_info(p, indent, obj);
> > +	else if (obj->dev->driver->gem_print_info)
> >   		obj->dev->driver->gem_print_info(p, indent, obj);
> >   }
> > +
> > +/**
> > + * drm_gem_pin - Pin backing buffer in memory
> > + * @obj: GEM object
> > + *
> > + * Make sure the backing buffer is pinned in memory.
> > + *
> > + * Returns:
> > + * 0 on success or a negative error code on failure.
> > + */
> > +int drm_gem_pin(struct drm_gem_object *obj)
> > +{
> > +	if (obj->funcs && obj->funcs->pin)
> > +		return obj->funcs->pin(obj);
> > +	else if (obj->dev->driver->gem_prime_pin)
> > +		return obj->dev->driver->gem_prime_pin(obj);
> > +	else
> > +		return 0;
> > +}
> > +EXPORT_SYMBOL(drm_gem_pin);
> > +
> > +/**
> > + * drm_gem_unpin - Unpin backing buffer from memory
> > + * @obj: GEM object
> > + *
> > + * Relax the requirement that the backing buffer is pinned in memory.
> > + */
> > +void drm_gem_unpin(struct drm_gem_object *obj)
> > +{
> > +	if (obj->funcs && obj->funcs->unpin)
> > +		obj->funcs->unpin(obj);
> > +	else if (obj->dev->driver->gem_prime_unpin)
> > +		obj->dev->driver->gem_prime_unpin(obj);
> > +}
> > +EXPORT_SYMBOL(drm_gem_unpin);
> > +
> > +/**
> > + * drm_gem_vmap - Map buffer into kernel virtual address space
> > + * @obj: GEM object
> > + *
> > + * Returns:
> > + * A virtual pointer to a newly created GEM object or an ERR_PTR-encoded negative
> > + * error code on failure.
> > + */
> > +void *drm_gem_vmap(struct drm_gem_object *obj)
> > +{
> > +	void *vaddr;
> > +
> > +	if (obj->funcs && obj->funcs->vmap)
> > +		vaddr = obj->funcs->vmap(obj);
> > +	else if (obj->dev->driver->gem_prime_vmap)
> > +		vaddr = obj->dev->driver->gem_prime_vmap(obj);
> > +	else
> > +		vaddr = ERR_PTR(-EOPNOTSUPP);
> > +
> > +	if (!vaddr)
> > +		vaddr = ERR_PTR(-ENOMEM);
> > +
> > +	return vaddr;
> > +}
> > +EXPORT_SYMBOL(drm_gem_vmap);
> > +
> > +/**
> > + * drm_gem_vunmap - Remove buffer mapping from kernel virtual address space
> > + * @obj: GEM object
> > + * @vaddr: Virtual address (can be NULL)
> > + */
> > +void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr)
> > +{
> > +	if (!vaddr)
> > +		return;
> > +
> > +	if (obj->funcs && obj->funcs->vunmap)
> > +		obj->funcs->vunmap(obj, vaddr);
> > +	else if (obj->dev->driver->gem_prime_vunmap)
> > +		obj->dev->driver->gem_prime_vunmap(obj, vaddr);
> > +}
> > +EXPORT_SYMBOL(drm_gem_vunmap);
> > diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
> > index 42abf98c1d4a..e0ab5213efa7 100644
> > --- a/drivers/gpu/drm/drm_prime.c
> > +++ b/drivers/gpu/drm/drm_prime.c
> > @@ -199,7 +199,6 @@ int drm_gem_map_attach(struct dma_buf *dma_buf,
> >   {
> >   	struct drm_prime_attachment *prime_attach;
> >   	struct drm_gem_object *obj = dma_buf->priv;
> > -	struct drm_device *dev = obj->dev;
> >   	prime_attach = kzalloc(sizeof(*prime_attach), GFP_KERNEL);
> >   	if (!prime_attach)
> > @@ -208,10 +207,7 @@ int drm_gem_map_attach(struct dma_buf *dma_buf,
> >   	prime_attach->dir = DMA_NONE;
> >   	attach->priv = prime_attach;
> > -	if (!dev->driver->gem_prime_pin)
> > -		return 0;
> > -
> > -	return dev->driver->gem_prime_pin(obj);
> > +	return drm_gem_pin(obj);
> >   }
> >   EXPORT_SYMBOL(drm_gem_map_attach);
> > @@ -228,7 +224,6 @@ void drm_gem_map_detach(struct dma_buf *dma_buf,
> >   {
> >   	struct drm_prime_attachment *prime_attach = attach->priv;
> >   	struct drm_gem_object *obj = dma_buf->priv;
> > -	struct drm_device *dev = obj->dev;
> >   	if (prime_attach) {
> >   		struct sg_table *sgt = prime_attach->sgt;
> > @@ -247,8 +242,7 @@ void drm_gem_map_detach(struct dma_buf *dma_buf,
> >   		attach->priv = NULL;
> >   	}
> > -	if (dev->driver->gem_prime_unpin)
> > -		dev->driver->gem_prime_unpin(obj);
> > +	drm_gem_unpin(obj);
> >   }
> >   EXPORT_SYMBOL(drm_gem_map_detach);
> > @@ -310,7 +304,10 @@ struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
> >   	if (WARN_ON(prime_attach->dir != DMA_NONE))
> >   		return ERR_PTR(-EBUSY);
> > -	sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
> > +	if (obj->funcs)
> > +		sgt = obj->funcs->get_sg_table(obj);
> > +	else
> > +		sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
> >   	if (!IS_ERR(sgt)) {
> >   		if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
> > @@ -406,12 +403,13 @@ EXPORT_SYMBOL(drm_gem_dmabuf_release);
> >   void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
> >   {
> >   	struct drm_gem_object *obj = dma_buf->priv;
> > -	struct drm_device *dev = obj->dev;
> > +	void *vaddr;
> > -	if (dev->driver->gem_prime_vmap)
> > -		return dev->driver->gem_prime_vmap(obj);
> > -	else
> > -		return NULL;
> > +	vaddr = drm_gem_vmap(obj);
> > +	if (IS_ERR(vaddr))
> > +		vaddr = NULL;
> > +
> > +	return vaddr;
> >   }
> >   EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
> > @@ -426,10 +424,8 @@ EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
> >   void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
> >   {
> >   	struct drm_gem_object *obj = dma_buf->priv;
> > -	struct drm_device *dev = obj->dev;
> > -	if (dev->driver->gem_prime_vunmap)
> > -		dev->driver->gem_prime_vunmap(obj, vaddr);
> > +	drm_gem_vunmap(obj, vaddr);
> >   }
> >   EXPORT_SYMBOL(drm_gem_dmabuf_vunmap);
> > @@ -529,7 +525,9 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev,
> >   		return dmabuf;
> >   	}
> > -	if (dev->driver->gem_prime_export)
> > +	if (obj->funcs && obj->funcs->export)
> > +		dmabuf = obj->funcs->export(obj, flags);
> > +	else if (dev->driver->gem_prime_export)
> >   		dmabuf = dev->driver->gem_prime_export(dev, obj, flags);
> >   	else
> >   		dmabuf = drm_gem_prime_export(dev, obj, flags);
> > diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
> > index 3583b98a1718..f466ce5bde0e 100644
> > --- a/include/drm/drm_gem.h
> > +++ b/include/drm/drm_gem.h
> > @@ -38,6 +38,121 @@
> >   #include <drm/drm_vma_manager.h>
> > +struct drm_gem_object;
> > +
> > +/**
> > + * struct drm_gem_object_funcs - GEM object functions
> > + */
> > +struct drm_gem_object_funcs {
> > +	/**
> > +	 * @free:
> > +	 *
> > +	 * Deconstructor for drm_gem_objects.
> > +	 *
> > +	 * This callback is mandatory.
> > +	 */
> > +	void (*free)(struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @open:
> > +	 *
> > +	 * Called upon GEM handle creation.
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	int (*open)(struct drm_gem_object *obj, struct drm_file *file);
> > +
> > +	/**
> > +	 * @close:
> > +	 *
> > +	 * Called upon GEM handle release.
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	void (*close)(struct drm_gem_object *obj, struct drm_file *file);
> > +
> > +	/**
> > +	 * @print_info:
> > +	 *
> > +	 * If driver subclasses struct &drm_gem_object, it can implement this
> > +	 * optional hook for printing additional driver specific info.
> > +	 *
> > +	 * drm_printf_indent() should be used in the callback passing it the
> > +	 * indent argument.
> > +	 *
> > +	 * This callback is called from drm_gem_print_info().
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	void (*print_info)(struct drm_printer *p, unsigned int indent,
> > +			   const struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @export:
> > +	 *
> > +	 * Export backing buffer as a &dma_buf.
> > +	 * If this is not set drm_gem_prime_export() is used.
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	struct dma_buf *(*export)(struct drm_gem_object *obj, int flags);
> > +
> > +	/**
> > +	 * @pin:
> > +	 *
> > +	 * Pin backing buffer in memory.
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	int (*pin)(struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @unpin:
> > +	 *
> > +	 * Unpin backing buffer.
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	void (*unpin)(struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @get_sg_table:
> > +	 *
> > +	 * Returns a Scatter-Gather table representation of the buffer.
> > +	 * Used when exporting a buffer.
> > +	 *
> > +	 * This callback is mandatory if buffer export is supported.
> > +	 */
> > +	struct sg_table *(*get_sg_table)(struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @vmap:
> > +	 *
> > +	 * Returns a virtual address for the buffer.
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	void *(*vmap)(struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @vunmap:
> > +	 *
> > +	 * Releases the the address previously returned by @vmap.
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	void (*vunmap)(struct drm_gem_object *obj, void *vaddr);
> > +
> > +	/**
> > +	 * @vm_ops:
> > +	 *
> > +	 * Virtual memory operations used with mmap.
> > +	 *
> > +	 * This is optional but necessary for mmap support.
> > +	 */
> > +	const struct vm_operations_struct *vm_ops;
> > +};
> > +
> >   /**
> >    * struct drm_gem_object - GEM buffer object
> >    *
> > @@ -146,6 +261,17 @@ struct drm_gem_object {
> >   	 * simply leave it as NULL.
> >   	 */
> >   	struct dma_buf_attachment *import_attach;
> > +
> > +	/**
> > +	 * @funcs:
> > +	 *
> > +	 * Optional GEM object functions. If this is set, it will be used instead of the
> > +	 * corresponding &drm_driver GEM callbacks.
> > +	 *
> > +	 * New drivers should use this.
> > +	 *
> > +	 */
> > +	const struct drm_gem_object_funcs *funcs;
> >   };
> >   /**
> > @@ -293,4 +419,9 @@ int drm_gem_dumb_destroy(struct drm_file *file,
> >   			 struct drm_device *dev,
> >   			 uint32_t handle);
> > +int drm_gem_pin(struct drm_gem_object *obj);
> > +void drm_gem_unpin(struct drm_gem_object *obj);
> > +void *drm_gem_vmap(struct drm_gem_object *obj);
> > +void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr);
> > +
> >   #endif /* __DRM_GEM_H__ */
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2018-10-22 14:15     ` Noralf Trønnes
@ 2018-10-23 13:50       ` Daniel Vetter
  0 siblings, 0 replies; 35+ messages in thread
From: Daniel Vetter @ 2018-10-23 13:50 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, sam, dri-devel, david

On Mon, Oct 22, 2018 at 04:15:48PM +0200, Noralf Trønnes wrote:
> 
> Den 17.10.2018 17.46, skrev Daniel Vetter:
> > On Wed, Oct 17, 2018 at 03:04:53PM +0200, Noralf Trønnes wrote:
> > > This adds a library for shmem backed GEM objects.
> > > 
> > > v5:
> > > - Drop drm_gem_shmem_prime_mmap() (Daniel Vetter)
> > > - drm_gem_shmem_mmap(): Subtract drm_vma_node_start() to get the real
> > >    vma->vm_pgoff
> > > - drm_gem_shmem_fault(): Use vmf->pgoff now that vma->vm_pgoff is correct
> > > 
> > > v4:
> > > - Drop cache modes (Thomas Hellstrom)
> > > - Add a GEM attached vtable
> > > 
> > > v3:
> > > - Grammar (Sam Ravnborg)
> > > - s/drm_gem_shmem_put_pages_unlocked/drm_gem_shmem_put_pages_locked/
> > >    (Sam Ravnborg)
> > > - Add debug output in error path (Sam Ravnborg)
> > > 
> > > Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> > > ---
> > >   Documentation/gpu/drm-kms-helpers.rst  |  12 +
> > >   drivers/gpu/drm/Kconfig                |   6 +
> > >   drivers/gpu/drm/Makefile               |   1 +
> > >   drivers/gpu/drm/drm_gem_shmem_helper.c | 551 +++++++++++++++++++++++++++++++++
> > >   include/drm/drm_gem_shmem_helper.h     | 153 +++++++++
> > >   5 files changed, 723 insertions(+)
> > >   create mode 100644 drivers/gpu/drm/drm_gem_shmem_helper.c
> > >   create mode 100644 include/drm/drm_gem_shmem_helper.h
> > > 
> 
> <snip>
> 
> > > +static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
> > > +{
> > > +	struct vm_area_struct *vma = vmf->vma;
> > > +	struct drm_gem_object *obj = vma->vm_private_data;
> > > +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> > > +	loff_t num_pages = obj->size >> PAGE_SHIFT;
> > > +	struct page *page;
> > > +
> > > +	if (vmf->pgoff > num_pages || WARN_ON_ONCE(!shmem->pages))
> > > +		return VM_FAULT_SIGBUS;
> > > +
> > > +	page = shmem->pages[vmf->pgoff];
> > > +
> > > +	return vmf_insert_page(vma, vmf->address, page);
> > > +}
> > > +
> > > +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
> > > +{
> > > +	struct drm_gem_object *obj = vma->vm_private_data;
> > > +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> > > +
> > > +	drm_gem_shmem_put_pages(shmem);
> > Imbalance get/put_pages here, if someone forks (which is what calls
> > vm_ops->open on an existing vma).
> > 
> > > +	drm_gem_vm_close(vma);
> > > +}
> > > +
> > > +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
> > > +	.fault = drm_gem_shmem_fault,
> > > +	.open = drm_gem_vm_open,
> > > +	.close = drm_gem_shmem_vm_close,
> > > +};
> > > +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
> > > +
> > > +/**
> > > + * drm_gem_shmem_mmap - Memory-map a shmem GEM object
> > > + * @filp: File object
> > > + * @vma: VMA for the area to be mapped
> > > + *
> > > + * This function implements an augmented version of the GEM DRM file mmap
> > > + * operation for shmem objects. Drivers which employ the shmem helpers should
> > > + * use this function as their &file_operations.mmap handler in the DRM device file's
> > > + * file_operations structure.
> > > + *
> > > + * Instead of directly referencing this function, drivers should use the
> > > + * DEFINE_DRM_GEM_SHMEM_FOPS() macro.
> > > + *
> > > + * Returns:
> > > + * 0 on success or a negative error code on failure.
> > > + */
> > Between cma helpers, gem shmem helpers and the drm_gem_mmap we now have
> > quite a bit a confusion of mmap functions. I think it'd be good to update
> > the kerneldoc for drm_gem_mmap() to point at these here (both the shmem
> > and cma version), so that people prefer to use these helpers here. Direct
> > call to drm_gem_mmap would only be needed if you want to use your own
> > vm_ops.
> > 
> > > +int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma)
> > > +{
> > > +	struct drm_gem_shmem_object *shmem;
> > > +	int ret;
> > > +
> > > +	ret = drm_gem_mmap(filp, vma);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	shmem = to_drm_gem_shmem_obj(vma->vm_private_data);
> > > +
> > > +	ret = drm_gem_shmem_get_pages(shmem);
> > > +	if (ret) {
> > > +		drm_gem_vm_close(vma);
> > > +		return ret;
> > > +	}
> > > +
> > > +	/* VM_PFNMAP was set by drm_gem_mmap() */
> > > +	vma->vm_flags &= ~VM_PFNMAP;
> > > +	vma->vm_flags |= VM_MIXEDMAP;
> > > +	vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
> > > +
> > > +	fput(vma->vm_file);
> > > +	vma->vm_file = get_file(shmem->base.filp);
> > > +	/* Remove the fake offset */
> > > +	vma->vm_pgoff -= drm_vma_node_start(&shmem->base.vma_node);
> > > +
> > > +	return 0;
> > > +}
> > > +EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap);
> > Looking through your mmap code there's 2 bits:
> > - shmem isn't coherent,
> 
> You saved me in the last minute with that comment Daniel.
> 
> I just remembered that on the Raspberry Pi I need to swap the bytes (RGB565,
> SPI big endian) before transfer because its SPI can't do 16-bit transfers.
> So I removed the swapping and sent the shmem buffer straight through to SPI.
> This resulted in fbcon looking erratic and "distorted", so it didn't work
> with the generic fbdev emulation shadow buffer being copied by the cpu to
> the shmem buffer which is DMA'ed out over SPI. Even though the SPI core is
> using the streaming DMA API.
> (apparently I've worked so much on DRM helper refactoring that I've
> forgotten how the tinydrm drivers work...)
> 
> So it looks like I can't use shmem for the current tinydrm drivers, which
> all use SPI. Unless there's a solution to my problem, I guess I'll I have
> to postpone this shmem work until I can use it in a driver that I'm planning
> to do further down the road. It will compress the framebuffer before
> transfer over USB so no DMA on the shmem buffer.
> 
> Do you want me to apply the first 3 patches anyway, even though the shmem
> stuff has to wait?

Yeah I guess back to drawing board.

It looks like there's interests from others (Christian from AMD) on the
vtables stuff. So just pushing that, including a todo.rst entry to convert
drivers over, sounds like a good idea.

> 
> > if you try to actually buffer share this with
> >    prime I expect it'll fail badly. We'd need begin/end_cpu_access
> >    callbacks in dma_buf_ops to make this work. So not entirely sure how
> >    much value there is in implementing the prime mmap stuff (but doesn't
> >    hurt to have it).
> 
> The generic fbdev emulation uses PRIME mmap.

Oops. Works for CMA, doesn't work so well for shmem (assuming we have
non-coherent dma somewhere).

Maybe we can assume that all shmem using drivers will employ some kind of
manual upload (i.e. dirty), and then we could call the flush functions
from there?

> > - shmem already has an mmap implemtation, you can just use that. Needs a
> >    similar mmap forwarding trick as you've done for prime mmap, but instead
> >    you forward to obj->base.filp. That allows you to cut away all the
> >    vm_ops and everything. I guess we could clean this up in a follow-up,
> >    since it doesn't have an effect on the interfaces exposed to drivers. At
> >    least not a big one, drm_gem_shmem_vm_ops would disappear.
> 
> This approach using the shmem mmap seemed to work, not sure if the vm_flags
> needs to be touched though.
> (I'm putting it up here for the record, increases the chance of me finding
> it when I pick up the shmem helper further down the road)

vm_flags touching shouldn't be necessary anymore, you don't use
vm_insert_pfn. Which is what requires the VM_PFNMAP/MIXEDMAP stuff,
depending upon which vm_insert* function you're using. Afaiui at least,
not a core -mm expert at all.

But yes, this is what I had in mind.
-Daniel

> 
> int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma)
> {
>     struct drm_gem_object *obj;
>     int ret;
> 
>     ret = drm_gem_mmap(filp, vma);
>     if (ret)
>         return ret;
> 
>     obj = vma->vm_private_data;
> 
>     /* Remove the fake offset */
>     vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
> 
>     /* VM_PFNMAP was set by drm_gem_mmap() */
>     vma->vm_flags &= ~VM_PFNMAP;
>     vma->vm_flags |= VM_MIXEDMAP;
>     vma->vm_page_prot = pgprot_decrypted(vm_get_page_prot(vma->vm_flags));
> 
>     fput(vma->vm_file);
>     vma->vm_file = get_file(obj->filp);
> 
>     drm_gem_object_put_unlocked(obj);
> 
>     return call_mmap(vma->vm_file, vma);
> }
> 
> 
> Noralf.
> 
> 
> > > +
> > > +/**
> > > + * drm_gem_shmem_print_info() - Print &drm_gem_shmem_object info for debugfs
> > > + * @p: DRM printer
> > > + * @indent: Tab indentation level
> > > + * @obj: GEM object
> > Would be good to reference the hook this is meant for:
> > &drm_gem_object_funcs.print_info, same for all the others. For those
> > drivers that want to pick&choose.
> > 
> > Cheers, Daniel
> > 
> > > + */
> > > +void drm_gem_shmem_print_info(struct drm_printer *p, unsigned int indent,
> > > +			      const struct drm_gem_object *obj)
> > > +{
> > > +	const struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> > > +
> > > +	drm_printf_indent(p, indent, "pages_use_count=%u\n", shmem->pages_use_count);
> > > +	drm_printf_indent(p, indent, "vmap_use_count=%u\n", shmem->vmap_use_count);
> > > +	drm_printf_indent(p, indent, "vaddr=%p\n", shmem->vaddr);
> > > +}
> > > +EXPORT_SYMBOL(drm_gem_shmem_print_info);
> > > +
> > > +/**
> > > + * drm_gem_shmem_get_sg_table - Provide a scatter/gather table of pinned
> > > + *                              pages for a shmem GEM object
> > > + * @obj: GEM object
> > > + *
> > > + * This function exports a scatter/gather table suitable for PRIME usage by
> > > + * calling the standard DMA mapping API.
> > > + *
> > > + * Returns:
> > > + * A pointer to the scatter/gather table of pinned pages or NULL on failure.
> > > + */
> > > +struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_object *obj)
> > > +{
> > > +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> > > +
> > > +	return drm_prime_pages_to_sg(shmem->pages, obj->size >> PAGE_SHIFT);
> > > +}
> > > +EXPORT_SYMBOL_GPL(drm_gem_shmem_get_sg_table);
> > > +
> > > +/**
> > > + * drm_gem_shmem_prime_import_sg_table - Produce a shmem GEM object from
> > > + *                 another driver's scatter/gather table of pinned pages
> > > + * @dev: Device to import into
> > > + * @attach: DMA-BUF attachment
> > > + * @sgt: Scatter/gather table of pinned pages
> > > + *
> > > + * This function imports a scatter/gather table exported via DMA-BUF by
> > > + * another driver. Drivers that use the shmem helpers should set this as their
> > > + * &drm_driver.gem_prime_import_sg_table callback.
> > > + *
> > > + * Returns:
> > > + * A pointer to a newly created GEM object or an ERR_PTR-encoded negative
> > > + * error code on failure.
> > > + */
> > > +struct drm_gem_object *
> > > +drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
> > > +				    struct dma_buf_attachment *attach,
> > > +				    struct sg_table *sgt)
> > > +{
> > > +	size_t size = PAGE_ALIGN(attach->dmabuf->size);
> > > +	size_t npages = size >> PAGE_SHIFT;
> > > +	struct drm_gem_shmem_object *shmem;
> > > +	int ret;
> > > +
> > > +	shmem = drm_gem_shmem_create(dev, size);
> > > +	if (IS_ERR(shmem))
> > > +		return ERR_CAST(shmem);
> > > +
> > > +	shmem->pages = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
> > > +	if (!shmem->pages) {
> > > +		ret = -ENOMEM;
> > > +		goto err_free_gem;
> > > +	}
> > > +
> > > +	ret = drm_prime_sg_to_page_addr_arrays(sgt, shmem->pages, NULL, npages);
> > > +	if (ret < 0)
> > > +		goto err_free_array;
> > > +
> > > +	shmem->sgt = sgt;
> > > +	shmem->pages_use_count = 1; /* Permanently pinned from our point of view */
> > > +
> > > +	DRM_DEBUG_PRIME("size = %zu\n", size);
> > > +
> > > +	return &shmem->base;
> > > +
> > > +err_free_array:
> > > +	kvfree(shmem->pages);
> > > +err_free_gem:
> > > +	drm_gem_object_put_unlocked(&shmem->base);
> > > +
> > > +	return ERR_PTR(ret);
> > > +}
> > > +EXPORT_SYMBOL_GPL(drm_gem_shmem_prime_import_sg_table);
> > > diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
> > > new file mode 100644
> > > index 000000000000..26b05e06407d
> > > --- /dev/null
> > > +++ b/include/drm/drm_gem_shmem_helper.h
> > > @@ -0,0 +1,153 @@
> > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > +
> > > +#ifndef __DRM_GEM_SHMEM_HELPER_H__
> > > +#define __DRM_GEM_SHMEM_HELPER_H__
> > > +
> > > +#include <linux/fs.h>
> > > +#include <linux/mm.h>
> > > +#include <linux/mutex.h>
> > > +
> > > +#include <drm/drm_file.h>
> > > +#include <drm/drm_gem.h>
> > > +#include <drm/drm_ioctl.h>
> > > +#include <drm/drm_prime.h>
> > > +
> > > +struct dma_buf_attachment;
> > > +struct drm_mode_create_dumb;
> > > +struct drm_printer;
> > > +struct sg_table;
> > > +
> > > +/**
> > > + * struct drm_gem_shmem_object - GEM object backed by shmem
> > > + */
> > > +struct drm_gem_shmem_object {
> > > +	/**
> > > +	 * @base: Base GEM object
> > > +	 */
> > > +	struct drm_gem_object base;
> > > +
> > > +	/**
> > > +	 * @pages_lock: Protects the page table and use count
> > > +	 */
> > > +	struct mutex pages_lock;
> > > +
> > > +	/**
> > > +	 * @pages: Page table
> > > +	 */
> > > +	struct page **pages;
> > > +
> > > +	/**
> > > +	 * @pages_use_count:
> > > +	 *
> > > +	 * Reference count on the pages table.
> > > +	 * The pages are put when the count reaches zero.
> > > +	 */
> > > +	unsigned int pages_use_count;
> > > +
> > > +	/**
> > > +	 * @pages_mark_dirty_on_put:
> > > +	 *
> > > +	 * Mark pages as dirty when they are put.
> > > +	 */
> > > +	unsigned int pages_mark_dirty_on_put    : 1;
> > > +
> > > +	/**
> > > +	 * @pages_mark_accessed_on_put:
> > > +	 *
> > > +	 * Mark pages as accessed when they are put.
> > > +	 */
> > > +	unsigned int pages_mark_accessed_on_put : 1;
> > > +
> > > +	/**
> > > +	 * @sgt: Scatter/gather table for imported PRIME buffers
> > > +	 */
> > > +	struct sg_table *sgt;
> > > +
> > > +	/**
> > > +	 * @vmap_lock: Protects the vmap address and use count
> > > +	 */
> > > +	struct mutex vmap_lock;
> > > +
> > > +	/**
> > > +	 * @vaddr: Kernel virtual address of the backing memory
> > > +	 */
> > > +	void *vaddr;
> > > +
> > > +	/**
> > > +	 * @vmap_use_count:
> > > +	 *
> > > +	 * Reference count on the virtual address.
> > > +	 * The address are un-mapped when the count reaches zero.
> > > +	 */
> > > +	unsigned int vmap_use_count;
> > > +};
> > > +
> > > +#define to_drm_gem_shmem_obj(obj) \
> > > +	container_of(obj, struct drm_gem_shmem_object, base)
> > > +
> > > +/**
> > > + * DEFINE_DRM_GEM_SHMEM_FOPS() - Macro to generate file operations for shmem drivers
> > > + * @name: name for the generated structure
> > > + *
> > > + * This macro autogenerates a suitable &struct file_operations for shmem based
> > > + * drivers, which can be assigned to &drm_driver.fops. Note that this structure
> > > + * cannot be shared between drivers, because it contains a reference to the
> > > + * current module using THIS_MODULE.
> > > + *
> > > + * Note that the declaration is already marked as static - if you need a
> > > + * non-static version of this you're probably doing it wrong and will break the
> > > + * THIS_MODULE reference by accident.
> > > + */
> > > +#define DEFINE_DRM_GEM_SHMEM_FOPS(name) \
> > > +	static const struct file_operations name = {\
> > > +		.owner		= THIS_MODULE,\
> > > +		.open		= drm_open,\
> > > +		.release	= drm_release,\
> > > +		.unlocked_ioctl	= drm_ioctl,\
> > > +		.compat_ioctl	= drm_compat_ioctl,\
> > > +		.poll		= drm_poll,\
> > > +		.read		= drm_read,\
> > > +		.llseek		= noop_llseek,\
> > > +		.mmap		= drm_gem_shmem_mmap, \
> > > +	}
> > > +
> > > +struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size);
> > > +void drm_gem_shmem_free_object(struct drm_gem_object *obj);
> > > +
> > > +int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem);
> > > +void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem);
> > > +int drm_gem_shmem_pin(struct drm_gem_object *obj);
> > > +void drm_gem_shmem_unpin(struct drm_gem_object *obj);
> > > +void *drm_gem_shmem_vmap(struct drm_gem_object *obj);
> > > +void drm_gem_shmem_vunmap(struct drm_gem_object *obj, void *vaddr);
> > > +
> > > +int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
> > > +			      struct drm_mode_create_dumb *args);
> > > +
> > > +int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma);
> > > +
> > > +extern const struct vm_operations_struct drm_gem_shmem_vm_ops;
> > > +
> > > +void drm_gem_shmem_print_info(struct drm_printer *p, unsigned int indent,
> > > +			      const struct drm_gem_object *obj);
> > > +
> > > +struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_object *obj);
> > > +struct drm_gem_object *
> > > +drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
> > > +				    struct dma_buf_attachment *attach,
> > > +				    struct sg_table *sgt);
> > > +
> > > +/**
> > > + * DRM_GEM_SHMEM_DRIVER_OPS - Default shmem GEM operations
> > > + *
> > > + * This macro provides a shortcut for setting the shmem GEM operations in
> > > + * the &drm_driver structure.
> > > + */
> > > +#define DRM_GEM_SHMEM_DRIVER_OPS \
> > > +	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd, \
> > > +	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle, \
> > > +	.gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, \
> > > +	.gem_prime_mmap		= drm_gem_prime_mmap, \
> > > +	.dumb_create		= drm_gem_shmem_dumb_create
> > > +
> > > +#endif /* __DRM_GEM_SHMEM_HELPER_H__ */
> > > -- 
> > > 2.15.1
> > > 
> > > _______________________________________________
> > > dri-devel mailing list
> > > dri-devel@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 5/5] drm/tinydrm: Switch from CMA to shmem buffers
  2018-10-17 13:04 ` [PATCH v5 5/5] drm/tinydrm: Switch from CMA to shmem buffers Noralf Trønnes
@ 2018-10-26 22:38   ` Noralf Trønnes
  2018-10-28 20:21     ` David Lechner
  0 siblings, 1 reply; 35+ messages in thread
From: Noralf Trønnes @ 2018-10-26 22:38 UTC (permalink / raw)
  To: dri-devel; +Cc: thomas, intel-gfx, sam, david


Den 17.10.2018 15.04, skrev Noralf Trønnes:
> This move makes tinydrm useful for more drivers. tinydrm doesn't need
> continuous memory, but at the time it was convenient to use the CMA
> library. The spi core can do dma on is_vmalloc() addresses making this
> possible.
>
> Cc: David Lechner <david@lechnology.com>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> Acked-by: David Lechner <david@lechnology.com>
> Tested-by: David Lechner <david@lechnology.com>
> ---

David,
FYI This series is scratched.
See the shmem helper patch thread for details.

Noralf.

>   drivers/gpu/drm/tinydrm/Kconfig                |  2 +-
>   drivers/gpu/drm/tinydrm/core/tinydrm-core.c    | 92 +++++++-------------------
>   drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c |  5 ++
>   drivers/gpu/drm/tinydrm/ili9225.c              | 14 ++--
>   drivers/gpu/drm/tinydrm/ili9341.c              |  6 +-
>   drivers/gpu/drm/tinydrm/mi0283qt.c             |  6 +-
>   drivers/gpu/drm/tinydrm/mipi-dbi.c             | 38 ++++-------
>   drivers/gpu/drm/tinydrm/repaper.c              | 24 +++----
>   drivers/gpu/drm/tinydrm/st7586.c               | 15 +++--
>   drivers/gpu/drm/tinydrm/st7735r.c              |  6 +-
>   include/drm/tinydrm/tinydrm.h                  | 36 +++-------
>   11 files changed, 91 insertions(+), 153 deletions(-)
>
> diff --git a/drivers/gpu/drm/tinydrm/Kconfig b/drivers/gpu/drm/tinydrm/Kconfig
> index 16f4b5c91f1b..aa0cabba5ace 100644
> --- a/drivers/gpu/drm/tinydrm/Kconfig
> +++ b/drivers/gpu/drm/tinydrm/Kconfig
> @@ -2,7 +2,7 @@ menuconfig DRM_TINYDRM
>   	tristate "Support for simple displays"
>   	depends on DRM
>   	select DRM_KMS_HELPER
> -	select DRM_KMS_CMA_HELPER
> +	select DRM_GEM_SHMEM_HELPER
>   	help
>   	  Choose this option if you have a tinydrm supported display.
>   	  If M is selected the module will be called tinydrm.
> diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
> index 255341ee4eb9..38ba361d1af2 100644
> --- a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
> +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c
> @@ -12,6 +12,7 @@
>   #include <drm/drm_crtc_helper.h>
>   #include <drm/drm_fb_helper.h>
>   #include <drm/drm_gem_framebuffer_helper.h>
> +#include <drm/drm_gem_shmem_helper.h>
>   #include <drm/tinydrm/tinydrm.h>
>   #include <linux/device.h>
>   #include <linux/dma-buf.h>
> @@ -23,7 +24,7 @@
>    *
>    * It is based on &drm_simple_display_pipe coupled with a &drm_connector which
>    * has only one fixed &drm_display_mode. The framebuffers are backed by the
> - * cma helper and have support for framebuffer flushing (dirty).
> + * shmem buffers and have support for framebuffer flushing (dirty).
>    * fbdev support is also included.
>    *
>    */
> @@ -37,84 +38,41 @@
>    */
>   
>   /**
> - * tinydrm_gem_cma_prime_import_sg_table - Produce a CMA GEM object from
> - *     another driver's scatter/gather table of pinned pages
> - * @drm: DRM device to import into
> - * @attach: DMA-BUF attachment
> - * @sgt: Scatter/gather table of pinned pages
> + * tinydrm_fb_destroy - Destroy framebuffer
> + * @fb: Framebuffer
>    *
> - * This function imports a scatter/gather table exported via DMA-BUF by
> - * another driver using drm_gem_cma_prime_import_sg_table(). It sets the
> - * kernel virtual address on the CMA object. Drivers should use this as their
> - * &drm_driver->gem_prime_import_sg_table callback if they need the virtual
> - * address. tinydrm_gem_cma_free_object() should be used in combination with
> - * this function.
> - *
> - * Returns:
> - * A pointer to a newly created GEM object or an ERR_PTR-encoded negative
> - * error code on failure.
> + * This function unmaps the virtual address on the backing buffer and destroys the framebuffer.
> + * Drivers should use this as their &drm_framebuffer_funcs->destroy callback.
>    */
> -struct drm_gem_object *
> -tinydrm_gem_cma_prime_import_sg_table(struct drm_device *drm,
> -				      struct dma_buf_attachment *attach,
> -				      struct sg_table *sgt)
> +void tinydrm_fb_destroy(struct drm_framebuffer *fb)
>   {
> -	struct drm_gem_cma_object *cma_obj;
> -	struct drm_gem_object *obj;
> -	void *vaddr;
> +	struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(gem);
>   
> -	vaddr = dma_buf_vmap(attach->dmabuf);
> -	if (!vaddr) {
> -		DRM_ERROR("Failed to vmap PRIME buffer\n");
> -		return ERR_PTR(-ENOMEM);
> -	}
> -
> -	obj = drm_gem_cma_prime_import_sg_table(drm, attach, sgt);
> -	if (IS_ERR(obj)) {
> -		dma_buf_vunmap(attach->dmabuf, vaddr);
> -		return obj;
> -	}
> -
> -	cma_obj = to_drm_gem_cma_obj(obj);
> -	cma_obj->vaddr = vaddr;
> -
> -	return obj;
> +	drm_gem_vunmap(gem, shmem->vaddr);
> +	drm_gem_fb_destroy(fb);
>   }
> -EXPORT_SYMBOL(tinydrm_gem_cma_prime_import_sg_table);
> -
> -/**
> - * tinydrm_gem_cma_free_object - Free resources associated with a CMA GEM
> - *                               object
> - * @gem_obj: GEM object to free
> - *
> - * This function frees the backing memory of the CMA GEM object, cleans up the
> - * GEM object state and frees the memory used to store the object itself using
> - * drm_gem_cma_free_object(). It also handles PRIME buffers which has the kernel
> - * virtual address set by tinydrm_gem_cma_prime_import_sg_table(). Drivers
> - * can use this as their &drm_driver->gem_free_object_unlocked callback.
> - */
> -void tinydrm_gem_cma_free_object(struct drm_gem_object *gem_obj)
> -{
> -	if (gem_obj->import_attach) {
> -		struct drm_gem_cma_object *cma_obj;
> -
> -		cma_obj = to_drm_gem_cma_obj(gem_obj);
> -		dma_buf_vunmap(gem_obj->import_attach->dmabuf, cma_obj->vaddr);
> -		cma_obj->vaddr = NULL;
> -	}
> -
> -	drm_gem_cma_free_object(gem_obj);
> -}
> -EXPORT_SYMBOL_GPL(tinydrm_gem_cma_free_object);
> +EXPORT_SYMBOL(tinydrm_fb_destroy);
>   
>   static struct drm_framebuffer *
>   tinydrm_fb_create(struct drm_device *drm, struct drm_file *file_priv,
>   		  const struct drm_mode_fb_cmd2 *mode_cmd)
>   {
>   	struct tinydrm_device *tdev = drm->dev_private;
> +	struct drm_framebuffer *fb;
> +	void *vaddr;
>   
> -	return drm_gem_fb_create_with_funcs(drm, file_priv, mode_cmd,
> -					    tdev->fb_funcs);
> +	fb = drm_gem_fb_create_with_funcs(drm, file_priv, mode_cmd, tdev->fb_funcs);
> +	if (IS_ERR(fb))
> +		return fb;
> +
> +	vaddr = drm_gem_vmap(drm_gem_fb_get_obj(fb, 0));
> +	if (IS_ERR(vaddr)) {
> +		drm_gem_fb_destroy(fb);
> +		return ERR_CAST(vaddr);
> +	}
> +
> +	return fb;
>   }
>   
>   static const struct drm_mode_config_funcs tinydrm_mode_config_funcs = {
> diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c b/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c
> index dcd390163a4a..f9d35acff23d 100644
> --- a/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c
> +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c
> @@ -9,12 +9,17 @@
>   
>   #include <linux/backlight.h>
>   #include <linux/dma-buf.h>
> +#include <linux/module.h>
>   #include <linux/pm.h>
>   #include <linux/spi/spi.h>
>   #include <linux/swab.h>
>   
> +#include <drm/drm_device.h>
> +#include <drm/drm_drv.h>
> +#include <drm/drm_fourcc.h>
>   #include <drm/tinydrm/tinydrm.h>
>   #include <drm/tinydrm/tinydrm-helpers.h>
> +#include <drm/drm_print.h>
>   
>   static unsigned int spi_max;
>   module_param(spi_max, uint, 0400);
> diff --git a/drivers/gpu/drm/tinydrm/ili9225.c b/drivers/gpu/drm/tinydrm/ili9225.c
> index 455fefe012f5..c24d6e4c834b 100644
> --- a/drivers/gpu/drm/tinydrm/ili9225.c
> +++ b/drivers/gpu/drm/tinydrm/ili9225.c
> @@ -20,8 +20,11 @@
>   #include <linux/spi/spi.h>
>   #include <video/mipi_display.h>
>   
> +#include <drm/drm_drv.h>
>   #include <drm/drm_fb_helper.h>
> +#include <drm/drm_fourcc.h>
>   #include <drm/drm_gem_framebuffer_helper.h>
> +#include <drm/drm_gem_shmem_helper.h>
>   #include <drm/tinydrm/mipi-dbi.h>
>   #include <drm/tinydrm/tinydrm-helpers.h>
>   
> @@ -77,7 +80,8 @@ static int ili9225_fb_dirty(struct drm_framebuffer *fb,
>   			    unsigned int color, struct drm_clip_rect *clips,
>   			    unsigned int num_clips)
>   {
> -	struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
> +	struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(gem);
>   	struct tinydrm_device *tdev = fb->dev->dev_private;
>   	struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
>   	bool swap = mipi->swap_bytes;
> @@ -104,7 +108,7 @@ static int ili9225_fb_dirty(struct drm_framebuffer *fb,
>   		if (ret)
>   			return ret;
>   	} else {
> -		tr = cma_obj->vaddr;
> +		tr = shmem->vaddr;
>   	}
>   
>   	switch (mipi->rotation) {
> @@ -157,7 +161,7 @@ static int ili9225_fb_dirty(struct drm_framebuffer *fb,
>   }
>   
>   static const struct drm_framebuffer_funcs ili9225_fb_funcs = {
> -	.destroy	= drm_gem_fb_destroy,
> +	.destroy	= tinydrm_fb_destroy,
>   	.create_handle	= drm_gem_fb_create_handle,
>   	.dirty		= tinydrm_fb_dirty,
>   };
> @@ -361,13 +365,13 @@ static const struct drm_display_mode ili9225_mode = {
>   	TINYDRM_MODE(176, 220, 35, 44),
>   };
>   
> -DEFINE_DRM_GEM_CMA_FOPS(ili9225_fops);
> +DEFINE_DRM_GEM_SHMEM_FOPS(ili9225_fops);
>   
>   static struct drm_driver ili9225_driver = {
>   	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
>   				  DRIVER_ATOMIC,
>   	.fops			= &ili9225_fops,
> -	TINYDRM_GEM_DRIVER_OPS,
> +	DRM_GEM_SHMEM_DRIVER_OPS,
>   	.name			= "ili9225",
>   	.desc			= "Ilitek ILI9225",
>   	.date			= "20171106",
> diff --git a/drivers/gpu/drm/tinydrm/ili9341.c b/drivers/gpu/drm/tinydrm/ili9341.c
> index 6701037749a7..7a80f8e6d6f3 100644
> --- a/drivers/gpu/drm/tinydrm/ili9341.c
> +++ b/drivers/gpu/drm/tinydrm/ili9341.c
> @@ -15,8 +15,10 @@
>   #include <linux/property.h>
>   #include <linux/spi/spi.h>
>   
> +#include <drm/drm_drv.h>
>   #include <drm/drm_fb_helper.h>
>   #include <drm/drm_gem_framebuffer_helper.h>
> +#include <drm/drm_gem_shmem_helper.h>
>   #include <drm/drm_modeset_helper.h>
>   #include <drm/tinydrm/mipi-dbi.h>
>   #include <drm/tinydrm/tinydrm-helpers.h>
> @@ -139,12 +141,12 @@ static const struct drm_display_mode yx240qv29_mode = {
>   	TINYDRM_MODE(240, 320, 37, 49),
>   };
>   
> -DEFINE_DRM_GEM_CMA_FOPS(ili9341_fops);
> +DEFINE_DRM_GEM_SHMEM_FOPS(ili9341_fops);
>   
>   static struct drm_driver ili9341_driver = {
>   	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
>   	.fops			= &ili9341_fops,
> -	TINYDRM_GEM_DRIVER_OPS,
> +	DRM_GEM_SHMEM_DRIVER_OPS,
>   	.debugfs_init		= mipi_dbi_debugfs_init,
>   	.name			= "ili9341",
>   	.desc			= "Ilitek ILI9341",
> diff --git a/drivers/gpu/drm/tinydrm/mi0283qt.c b/drivers/gpu/drm/tinydrm/mi0283qt.c
> index d7bb4c5e6657..b5837a6b3633 100644
> --- a/drivers/gpu/drm/tinydrm/mi0283qt.c
> +++ b/drivers/gpu/drm/tinydrm/mi0283qt.c
> @@ -17,9 +17,11 @@
>   #include <linux/regulator/consumer.h>
>   #include <linux/spi/spi.h>
>   
> +#include <drm/drm_drv.h>
>   #include <drm/drm_fb_helper.h>
>   #include <drm/drm_modeset_helper.h>
>   #include <drm/drm_gem_framebuffer_helper.h>
> +#include <drm/drm_gem_shmem_helper.h>
>   #include <drm/tinydrm/mipi-dbi.h>
>   #include <drm/tinydrm/tinydrm-helpers.h>
>   #include <video/mipi_display.h>
> @@ -147,13 +149,13 @@ static const struct drm_display_mode mi0283qt_mode = {
>   	TINYDRM_MODE(320, 240, 58, 43),
>   };
>   
> -DEFINE_DRM_GEM_CMA_FOPS(mi0283qt_fops);
> +DEFINE_DRM_GEM_SHMEM_FOPS(mi0283qt_fops);
>   
>   static struct drm_driver mi0283qt_driver = {
>   	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
>   				  DRIVER_ATOMIC,
>   	.fops			= &mi0283qt_fops,
> -	TINYDRM_GEM_DRIVER_OPS,
> +	DRM_GEM_SHMEM_DRIVER_OPS,
>   	.debugfs_init		= mipi_dbi_debugfs_init,
>   	.name			= "mi0283qt",
>   	.desc			= "Multi-Inno MI0283QT",
> diff --git a/drivers/gpu/drm/tinydrm/mipi-dbi.c b/drivers/gpu/drm/tinydrm/mipi-dbi.c
> index cb3441e51d5f..e0f59177c2ef 100644
> --- a/drivers/gpu/drm/tinydrm/mipi-dbi.c
> +++ b/drivers/gpu/drm/tinydrm/mipi-dbi.c
> @@ -9,10 +9,15 @@
>    * (at your option) any later version.
>    */
>   
> +#include <drm/drm_device.h>
> +#include <drm/drm_drv.h>
> +#include <drm/drm_fourcc.h>
>   #include <drm/drm_gem_framebuffer_helper.h>
> +#include <drm/drm_gem_shmem_helper.h>
>   #include <drm/tinydrm/mipi-dbi.h>
>   #include <drm/tinydrm/tinydrm-helpers.h>
>   #include <linux/debugfs.h>
> +#include <linux/delay.h>
>   #include <linux/dma-buf.h>
>   #include <linux/gpio/consumer.h>
>   #include <linux/module.h>
> @@ -167,10 +172,11 @@ EXPORT_SYMBOL(mipi_dbi_command_buf);
>   int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
>   		      struct drm_clip_rect *clip, bool swap)
>   {
> -	struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
> -	struct dma_buf_attachment *import_attach = cma_obj->base.import_attach;
> +	struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(gem);
> +	struct dma_buf_attachment *import_attach = gem->import_attach;
>   	struct drm_format_name_buf format_name;
> -	void *src = cma_obj->vaddr;
> +	void *src = shmem->vaddr;
>   	int ret = 0;
>   
>   	if (import_attach) {
> @@ -210,7 +216,8 @@ static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
>   			     struct drm_clip_rect *clips,
>   			     unsigned int num_clips)
>   {
> -	struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
> +	struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(gem);
>   	struct tinydrm_device *tdev = fb->dev->dev_private;
>   	struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
>   	bool swap = mipi->swap_bytes;
> @@ -235,7 +242,7 @@ static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
>   		if (ret)
>   			return ret;
>   	} else {
> -		tr = cma_obj->vaddr;
> +		tr = shmem->vaddr;
>   	}
>   
>   	mipi_dbi_command(mipi, MIPI_DCS_SET_COLUMN_ADDRESS,
> @@ -252,7 +259,7 @@ static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
>   }
>   
>   static const struct drm_framebuffer_funcs mipi_dbi_fb_funcs = {
> -	.destroy	= drm_gem_fb_destroy,
> +	.destroy	= tinydrm_fb_destroy,
>   	.create_handle	= drm_gem_fb_create_handle,
>   	.dirty		= tinydrm_fb_dirty,
>   };
> @@ -882,31 +889,12 @@ int mipi_dbi_spi_init(struct spi_device *spi, struct mipi_dbi *mipi,
>   {
>   	size_t tx_size = tinydrm_spi_max_transfer_size(spi, 0);
>   	struct device *dev = &spi->dev;
> -	int ret;
>   
>   	if (tx_size < 16) {
>   		DRM_ERROR("SPI transmit buffer too small: %zu\n", tx_size);
>   		return -EINVAL;
>   	}
>   
> -	/*
> -	 * Even though it's not the SPI device that does DMA (the master does),
> -	 * the dma mask is necessary for the dma_alloc_wc() in
> -	 * drm_gem_cma_create(). The dma_addr returned will be a physical
> -	 * adddress which might be different from the bus address, but this is
> -	 * not a problem since the address will not be used.
> -	 * The virtual address is used in the transfer and the SPI core
> -	 * re-maps it on the SPI master device using the DMA streaming API
> -	 * (spi_map_buf()).
> -	 */
> -	if (!dev->coherent_dma_mask) {
> -		ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
> -		if (ret) {
> -			dev_warn(dev, "Failed to set dma mask %d\n", ret);
> -			return ret;
> -		}
> -	}
> -
>   	mipi->spi = spi;
>   	mipi->read_commands = mipi_dbi_dcs_read_commands;
>   
> diff --git a/drivers/gpu/drm/tinydrm/repaper.c b/drivers/gpu/drm/tinydrm/repaper.c
> index 50a1d4216ce7..82d8c6bf0c91 100644
> --- a/drivers/gpu/drm/tinydrm/repaper.c
> +++ b/drivers/gpu/drm/tinydrm/repaper.c
> @@ -26,7 +26,9 @@
>   #include <linux/spi/spi.h>
>   #include <linux/thermal.h>
>   
> +#include <drm/drm_drv.h>
>   #include <drm/drm_gem_framebuffer_helper.h>
> +#include <drm/drm_gem_shmem_helper.h>
>   #include <drm/tinydrm/tinydrm.h>
>   #include <drm/tinydrm/tinydrm-helpers.h>
>   
> @@ -526,8 +528,9 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb,
>   			    struct drm_clip_rect *clips,
>   			    unsigned int num_clips)
>   {
> -	struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
> -	struct dma_buf_attachment *import_attach = cma_obj->base.import_attach;
> +	struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(gem);
> +	struct dma_buf_attachment *import_attach = gem->import_attach;
>   	struct tinydrm_device *tdev = fb->dev->dev_private;
>   	struct repaper_epd *epd = epd_from_tinydrm(tdev);
>   	struct drm_clip_rect clip;
> @@ -559,7 +562,7 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb,
>   			goto out_free;
>   	}
>   
> -	tinydrm_xrgb8888_to_gray8(buf, cma_obj->vaddr, fb, &clip);
> +	tinydrm_xrgb8888_to_gray8(buf, shmem->vaddr, fb, &clip);
>   
>   	if (import_attach) {
>   		ret = dma_buf_end_cpu_access(import_attach->dmabuf,
> @@ -624,7 +627,7 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb,
>   }
>   
>   static const struct drm_framebuffer_funcs repaper_fb_funcs = {
> -	.destroy	= drm_gem_fb_destroy,
> +	.destroy	= tinydrm_fb_destroy,
>   	.create_handle	= drm_gem_fb_create_handle,
>   	.dirty		= tinydrm_fb_dirty,
>   };
> @@ -876,13 +879,13 @@ static const struct drm_display_mode repaper_e2271cs021_mode = {
>   static const u8 repaper_e2271cs021_cs[] = { 0x00, 0x00, 0x00, 0x7f,
>   					    0xff, 0xfe, 0x00, 0x00 };
>   
> -DEFINE_DRM_GEM_CMA_FOPS(repaper_fops);
> +DEFINE_DRM_GEM_SHMEM_FOPS(repaper_fops);
>   
>   static struct drm_driver repaper_driver = {
>   	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
>   				  DRIVER_ATOMIC,
>   	.fops			= &repaper_fops,
> -	TINYDRM_GEM_DRIVER_OPS,
> +	DRM_GEM_SHMEM_DRIVER_OPS,
>   	.name			= "repaper",
>   	.desc			= "Pervasive Displays RePaper e-ink panels",
>   	.date			= "20170405",
> @@ -929,15 +932,6 @@ static int repaper_probe(struct spi_device *spi)
>   		model = spi_id->driver_data;
>   	}
>   
> -	/* The SPI device is used to allocate dma memory */
> -	if (!dev->coherent_dma_mask) {
> -		ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
> -		if (ret) {
> -			dev_warn(dev, "Failed to set dma mask %d\n", ret);
> -			return ret;
> -		}
> -	}
> -
>   	epd = devm_kzalloc(dev, sizeof(*epd), GFP_KERNEL);
>   	if (!epd)
>   		return -ENOMEM;
> diff --git a/drivers/gpu/drm/tinydrm/st7586.c b/drivers/gpu/drm/tinydrm/st7586.c
> index 2fcbc3067d71..340c9be2613b 100644
> --- a/drivers/gpu/drm/tinydrm/st7586.c
> +++ b/drivers/gpu/drm/tinydrm/st7586.c
> @@ -17,8 +17,10 @@
>   #include <linux/spi/spi.h>
>   #include <video/mipi_display.h>
>   
> +#include <drm/drm_drv.h>
>   #include <drm/drm_fb_helper.h>
>   #include <drm/drm_gem_framebuffer_helper.h>
> +#include <drm/drm_gem_shmem_helper.h>
>   #include <drm/tinydrm/mipi-dbi.h>
>   #include <drm/tinydrm/tinydrm-helpers.h>
>   
> @@ -88,9 +90,10 @@ static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr,
>   static int st7586_buf_copy(void *dst, struct drm_framebuffer *fb,
>   			   struct drm_clip_rect *clip)
>   {
> -	struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
> -	struct dma_buf_attachment *import_attach = cma_obj->base.import_attach;
> -	void *src = cma_obj->vaddr;
> +	struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
> +	struct dma_buf_attachment *import_attach = gem->import_attach;
> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(gem);
> +	void *src = shmem->vaddr;
>   	int ret = 0;
>   
>   	if (import_attach) {
> @@ -156,7 +159,7 @@ static int st7586_fb_dirty(struct drm_framebuffer *fb,
>   }
>   
>   static const struct drm_framebuffer_funcs st7586_fb_funcs = {
> -	.destroy	= drm_gem_fb_destroy,
> +	.destroy	= tinydrm_fb_destroy,
>   	.create_handle	= drm_gem_fb_create_handle,
>   	.dirty		= tinydrm_fb_dirty,
>   };
> @@ -297,13 +300,13 @@ static const struct drm_display_mode st7586_mode = {
>   	TINYDRM_MODE(178, 128, 37, 27),
>   };
>   
> -DEFINE_DRM_GEM_CMA_FOPS(st7586_fops);
> +DEFINE_DRM_GEM_SHMEM_FOPS(st7586_fops);
>   
>   static struct drm_driver st7586_driver = {
>   	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
>   				  DRIVER_ATOMIC,
>   	.fops			= &st7586_fops,
> -	TINYDRM_GEM_DRIVER_OPS,
> +	DRM_GEM_SHMEM_DRIVER_OPS,
>   	.debugfs_init		= mipi_dbi_debugfs_init,
>   	.name			= "st7586",
>   	.desc			= "Sitronix ST7586",
> diff --git a/drivers/gpu/drm/tinydrm/st7735r.c b/drivers/gpu/drm/tinydrm/st7735r.c
> index 3081bc57c116..1108088a1a03 100644
> --- a/drivers/gpu/drm/tinydrm/st7735r.c
> +++ b/drivers/gpu/drm/tinydrm/st7735r.c
> @@ -14,8 +14,10 @@
>   #include <linux/spi/spi.h>
>   #include <video/mipi_display.h>
>   
> +#include <drm/drm_drv.h>
>   #include <drm/drm_fb_helper.h>
>   #include <drm/drm_gem_framebuffer_helper.h>
> +#include <drm/drm_gem_shmem_helper.h>
>   #include <drm/tinydrm/mipi-dbi.h>
>   #include <drm/tinydrm/tinydrm-helpers.h>
>   
> @@ -113,13 +115,13 @@ static const struct drm_display_mode jd_t18003_t01_mode = {
>   	TINYDRM_MODE(128, 160, 28, 35),
>   };
>   
> -DEFINE_DRM_GEM_CMA_FOPS(st7735r_fops);
> +DEFINE_DRM_GEM_SHMEM_FOPS(st7735r_fops);
>   
>   static struct drm_driver st7735r_driver = {
>   	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
>   				  DRIVER_ATOMIC,
>   	.fops			= &st7735r_fops,
> -	TINYDRM_GEM_DRIVER_OPS,
> +	DRM_GEM_SHMEM_DRIVER_OPS,
>   	.debugfs_init		= mipi_dbi_debugfs_init,
>   	.name			= "st7735r",
>   	.desc			= "Sitronix ST7735R",
> diff --git a/include/drm/tinydrm/tinydrm.h b/include/drm/tinydrm/tinydrm.h
> index fe9827d0ca8a..e2cb254125c5 100644
> --- a/include/drm/tinydrm/tinydrm.h
> +++ b/include/drm/tinydrm/tinydrm.h
> @@ -10,10 +10,15 @@
>   #ifndef __LINUX_TINYDRM_H
>   #define __LINUX_TINYDRM_H
>   
> -#include <drm/drm_gem_cma_helper.h>
> -#include <drm/drm_fb_cma_helper.h>
> +#include <linux/mutex.h>
>   #include <drm/drm_simple_kms_helper.h>
>   
> +struct drm_driver;
> +struct drm_framebuffer;
> +struct drm_file;
> +struct drm_clip_rect;
> +struct drm_framebuffer_funcs;
> +
>   /**
>    * struct tinydrm_device - tinydrm device
>    */
> @@ -53,27 +58,6 @@ pipe_to_tinydrm(struct drm_simple_display_pipe *pipe)
>   	return container_of(pipe, struct tinydrm_device, pipe);
>   }
>   
> -/**
> - * TINYDRM_GEM_DRIVER_OPS - default tinydrm gem operations
> - *
> - * This macro provides a shortcut for setting the tinydrm GEM operations in
> - * the &drm_driver structure.
> - */
> -#define TINYDRM_GEM_DRIVER_OPS \
> -	.gem_free_object_unlocked = tinydrm_gem_cma_free_object, \
> -	.gem_print_info		= drm_gem_cma_print_info, \
> -	.gem_vm_ops		= &drm_gem_cma_vm_ops, \
> -	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd, \
> -	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle, \
> -	.gem_prime_import	= drm_gem_prime_import, \
> -	.gem_prime_export	= drm_gem_prime_export, \
> -	.gem_prime_get_sg_table	= drm_gem_cma_prime_get_sg_table, \
> -	.gem_prime_import_sg_table = tinydrm_gem_cma_prime_import_sg_table, \
> -	.gem_prime_vmap		= drm_gem_cma_prime_vmap, \
> -	.gem_prime_vunmap	= drm_gem_cma_prime_vunmap, \
> -	.gem_prime_mmap		= drm_gem_cma_prime_mmap, \
> -	.dumb_create		= drm_gem_cma_dumb_create
> -
>   /**
>    * TINYDRM_MODE - tinydrm display mode
>    * @hd: Horizontal resolution, width
> @@ -97,11 +81,7 @@ pipe_to_tinydrm(struct drm_simple_display_pipe *pipe)
>   	.type = DRM_MODE_TYPE_DRIVER, \
>   	.clock = 1 /* pass validation */
>   
> -void tinydrm_gem_cma_free_object(struct drm_gem_object *gem_obj);
> -struct drm_gem_object *
> -tinydrm_gem_cma_prime_import_sg_table(struct drm_device *drm,
> -				      struct dma_buf_attachment *attach,
> -				      struct sg_table *sgt);
> +void tinydrm_fb_destroy(struct drm_framebuffer *fb);
>   int devm_tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
>   		      const struct drm_framebuffer_funcs *fb_funcs,
>   		      struct drm_driver *driver);

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 5/5] drm/tinydrm: Switch from CMA to shmem buffers
  2018-10-26 22:38   ` Noralf Trønnes
@ 2018-10-28 20:21     ` David Lechner
  2018-10-28 20:46       ` Noralf Trønnes
  0 siblings, 1 reply; 35+ messages in thread
From: David Lechner @ 2018-10-28 20:21 UTC (permalink / raw)
  To: Noralf Trønnes, dri-devel; +Cc: thomas, intel-gfx, sam

On 10/26/2018 05:38 PM, Noralf Trønnes wrote:
> 
> Den 17.10.2018 15.04, skrev Noralf Trønnes:
>> This move makes tinydrm useful for more drivers. tinydrm doesn't need
>> continuous memory, but at the time it was convenient to use the CMA
>> library. The spi core can do dma on is_vmalloc() addresses making this
>> possible.
>>
>> Cc: David Lechner <david@lechnology.com>
>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
>> Acked-by: David Lechner <david@lechnology.com>
>> Tested-by: David Lechner <david@lechnology.com>
>> ---
> 
> David,
> FYI This series is scratched.
> See the shmem helper patch thread for details.
> 

Yes, I saw that. Thank you.

I don't suppose there is a way to configure the DMA controller to do
the byte swapping?

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 5/5] drm/tinydrm: Switch from CMA to shmem buffers
  2018-10-28 20:21     ` David Lechner
@ 2018-10-28 20:46       ` Noralf Trønnes
  2018-10-29  9:07         ` Daniel Vetter
  0 siblings, 1 reply; 35+ messages in thread
From: Noralf Trønnes @ 2018-10-28 20:46 UTC (permalink / raw)
  To: David Lechner, dri-devel; +Cc: thomas, intel-gfx, sam


Den 28.10.2018 21.21, skrev David Lechner:
> On 10/26/2018 05:38 PM, Noralf Trønnes wrote:
>> Den 17.10.2018 15.04, skrev Noralf Trønnes:
>>> This move makes tinydrm useful for more drivers. tinydrm doesn't need
>>> continuous memory, but at the time it was convenient to use the CMA
>>> library. The spi core can do dma on is_vmalloc() addresses making this
>>> possible.
>>>
>>> Cc: David Lechner <david@lechnology.com>
>>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
>>> Acked-by: David Lechner <david@lechnology.com>
>>> Tested-by: David Lechner <david@lechnology.com>
>>> ---
>> David,
>> FYI This series is scratched.
>> See the shmem helper patch thread for details.
>>
> Yes, I saw that. Thank you.
>
> I don't suppose there is a way to configure the DMA controller to do
> the byte swapping?
>

Not that I know of.
"Proper" SPI hw can do 16-bit transfers and for them there's no problem.
The DMA capable SPI block on the Pi can only do 8-bit, hence the swapping.

But that wasn't the problem, the byteswapping actually papered over the
problem. I'm no -mm expert so I don't know why the problem onyl showed
up when using the virtual address of the buffer used by fbcon and not on
mmap'ed fbdev as Daniel suggested would happen.
Either way shmem not being coherent is a problem on the Pi, even though
I expected the DMA streaming API called by the spi core to flush "things".

The solution I'm aiming for is to make it easy for tinydrm drivers to 
use the
buffer type they want, instead of having one type they all have to use.

Noralf.
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 5/5] drm/tinydrm: Switch from CMA to shmem buffers
  2018-10-28 20:46       ` Noralf Trønnes
@ 2018-10-29  9:07         ` Daniel Vetter
  2018-10-31 18:41           ` Noralf Trønnes
  0 siblings, 1 reply; 35+ messages in thread
From: Daniel Vetter @ 2018-10-29  9:07 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: sam, intel-gfx, thomas, David Lechner, dri-devel

On Sun, Oct 28, 2018 at 09:46:43PM +0100, Noralf Trønnes wrote:
> 
> Den 28.10.2018 21.21, skrev David Lechner:
> > On 10/26/2018 05:38 PM, Noralf Trønnes wrote:
> > > Den 17.10.2018 15.04, skrev Noralf Trønnes:
> > > > This move makes tinydrm useful for more drivers. tinydrm doesn't need
> > > > continuous memory, but at the time it was convenient to use the CMA
> > > > library. The spi core can do dma on is_vmalloc() addresses making this
> > > > possible.
> > > > 
> > > > Cc: David Lechner <david@lechnology.com>
> > > > Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> > > > Acked-by: David Lechner <david@lechnology.com>
> > > > Tested-by: David Lechner <david@lechnology.com>
> > > > ---
> > > David,
> > > FYI This series is scratched.
> > > See the shmem helper patch thread for details.
> > > 
> > Yes, I saw that. Thank you.
> > 
> > I don't suppose there is a way to configure the DMA controller to do
> > the byte swapping?
> > 
> 
> Not that I know of.
> "Proper" SPI hw can do 16-bit transfers and for them there's no problem.
> The DMA capable SPI block on the Pi can only do 8-bit, hence the swapping.
> 
> But that wasn't the problem, the byteswapping actually papered over the
> problem. I'm no -mm expert so I don't know why the problem onyl showed
> up when using the virtual address of the buffer used by fbcon and not on
> mmap'ed fbdev as Daniel suggested would happen.

Hm, I missed that detail. This sounds like one of the mappings ended up
being write-combining (which avoids all the issues with dirty cpu cache
lines), while the broken one was not.

Or we ended up with a flush somewhere by accident.

> Either way shmem not being coherent is a problem on the Pi, even though
> I expected the DMA streaming API called by the spi core to flush "things".

It should do that for you. At least if it's using dma_map/unmap_sg and
friends.

> The solution I'm aiming for is to make it easy for tinydrm drivers to use
> the
> buffer type they want, instead of having one type they all have to use.

General recommendation for this is "less midlayer, more helper". Which was
the goal of all this ... Oh well :-/ Maybe we can progress in other areas
meanwhile.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 5/5] drm/tinydrm: Switch from CMA to shmem buffers
  2018-10-29  9:07         ` Daniel Vetter
@ 2018-10-31 18:41           ` Noralf Trønnes
  0 siblings, 0 replies; 35+ messages in thread
From: Noralf Trønnes @ 2018-10-31 18:41 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: sam, intel-gfx, thomas, David Lechner, dri-devel


Den 29.10.2018 10.07, skrev Daniel Vetter:
> On Sun, Oct 28, 2018 at 09:46:43PM +0100, Noralf Trønnes wrote:
>> Den 28.10.2018 21.21, skrev David Lechner:
>>> On 10/26/2018 05:38 PM, Noralf Trønnes wrote:
>>>> Den 17.10.2018 15.04, skrev Noralf Trønnes:
>>>>> This move makes tinydrm useful for more drivers. tinydrm doesn't need
>>>>> continuous memory, but at the time it was convenient to use the CMA
>>>>> library. The spi core can do dma on is_vmalloc() addresses making this
>>>>> possible.
>>>>>
>>>>> Cc: David Lechner <david@lechnology.com>
>>>>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
>>>>> Acked-by: David Lechner <david@lechnology.com>
>>>>> Tested-by: David Lechner <david@lechnology.com>
>>>>> ---
>>>> David,
>>>> FYI This series is scratched.
>>>> See the shmem helper patch thread for details.
>>>>
>>> Yes, I saw that. Thank you.
>>>
>>> I don't suppose there is a way to configure the DMA controller to do
>>> the byte swapping?
>>>
>> Not that I know of.
>> "Proper" SPI hw can do 16-bit transfers and for them there's no problem.
>> The DMA capable SPI block on the Pi can only do 8-bit, hence the swapping.
>>
>> But that wasn't the problem, the byteswapping actually papered over the
>> problem. I'm no -mm expert so I don't know why the problem onyl showed
>> up when using the virtual address of the buffer used by fbcon and not on
>> mmap'ed fbdev as Daniel suggested would happen.
> Hm, I missed that detail. This sounds like one of the mappings ended up
> being write-combining (which avoids all the issues with dirty cpu cache
> lines), while the broken one was not.
>
> Or we ended up with a flush somewhere by accident.
>
>> Either way shmem not being coherent is a problem on the Pi, even though
>> I expected the DMA streaming API called by the spi core to flush "things".
> It should do that for you. At least if it's using dma_map/unmap_sg and
> friends.

I just watched a talk by the i2c maintainer about his challenges with
supporting DMA buffers and DMA only host controllers:

   DMA Safety in Buffers for Linux Kernel Device Drivers - Wolfram Sang
   https://www.youtube.com/watch?v=JDwaMClvV-s

In passing he mentions this from Documentation/spi/spi-summary:

   - I/O buffers use the usual Linux rules, and must be DMA-safe.
     You'd normally allocate them from the heap or free page pool.

So how can the SPI core ensure DMA safety for its DMA mapping of the
underlying pages of virtual addresses? This is what I relied on when
doing the shmem helper.

Doing further digging I came across these:

Vignesh R says:
https://www.spinics.net/lists/kernel/msg2687381.html

   SPI core does try to DMA into underlying physical pages of vmalloc'd
   buffer. But this has two problems:

   1. Does not work well with VIVT caches[1].
   2. On ARM LPAE systems, vmalloc'd buffers can be from highmem region
   that are not addressable using 32 bit addresses and is backed by LPAE.
   So, a 32 bit DMA cannot access these buffers.

   Both these issues lead to random crashes and errors with UBIFS and JFFS2
   flash file systems which this patch series tries to address using bounce
   buffer

   [1] https://patchwork.kernel.org/patch/9579553/


Russel King provides some more info:
https://patchwork.kernel.org/patch/9579553/#20139929

   SPI is rather another special case - rather than SPI following the
   established mechanism of passing data references via scatterlists or
   similar, it also passes them via virtual addresses, which means SPI
   can directly access the vmalloc area when performing PIO.  This
   really makes the problem more complex, because it means that if you
   do have a SPI driver that does that, it's going to be reading/writing
   direct from vmalloc space.

   That's not a problem as long as the data is only accessed via vmalloc
   space, but it will definitely go totally wrong if the data is
   subsequently mapped into userspace.


So even if I could make the shmem helper work on the Raspberry Pi with
tinydrm and SPI, it probably wouldn't work on all systems.


I also learned that using devm_kmalloc, which tinydrm does for a tx buffer,
is not DMA safe because it prepends a devres struct to the buffer making
the buffer itself not cache line aligned.

[Question] devm_kmalloc() for DMA ?
https://linux-arm-kernel.infradead.narkive.com/vyJqy0RQ/question-devm-kmalloc-for-dma

I'll turn this into a plain kmalloc when I return to my work on supporting
device unplug which will deal with device resource lifetime issues.

Noralf.

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 3/5] drm/gem: Add drm_gem_object_funcs
  2018-10-17 13:04 ` [PATCH v5 3/5] drm/gem: Add drm_gem_object_funcs Noralf Trønnes
  2018-10-22 12:57   ` Christian König
@ 2018-10-31 23:37   ` Noralf Trønnes
  2018-11-01  8:36     ` [Intel-gfx] " Daniel Vetter
  1 sibling, 1 reply; 35+ messages in thread
From: Noralf Trønnes @ 2018-10-31 23:37 UTC (permalink / raw)
  To: dri-devel; +Cc: thomas, intel-gfx, sam, david


Den 17.10.2018 15.04, skrev Noralf Trønnes:
> This adds an optional function table on GEM objects.
> The main benefit is for drivers that support more than one type of
> memory (shmem,vram,cma) for their buffers depending on the hardware it
> runs on. With the callbacks attached to the GEM object itself, it is
> easier to have core helpers for the the various buffer types. The driver
> only has to make the decision about buffer type on GEM object creation
> and all other callbacks can be handled by the chosen helper.
>
> drm_driver->gem_prime_res_obj has not been added since there's a todo to
> put a reservation_object into drm_gem_object.
>
> v2: Drop drm_gem_object_funcs->prime_mmap in favour of
> drm_gem_prime_mmap() (Daniel Vetter)
>
> v1:
> - drm_gem_object_funcs.map -> .prime_map let it only do PRIME mmap like
>    the function it superseeds (Daniel Vetter)
> - Flip around the if ladders and make obj->funcs the first choice
>    highlighting the fact that this the new default way of doing it
>    (Daniel Vetter)
>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---

Now that the shmem helper has now been postponed to the future I'm
thinking about doing some prep work in tinydrm to loosen the coupling to
the cma helper (longterm goal is try and get rid of tinydrm.ko altogether).

First step could be to add a drm_driver->gem_create_object function for
the cma helper that gives the default gem functions:

static const struct drm_gem_object_funcs drm_cma_gem_funcs = {
     .free = drm_gem_cma_free_object,
     .print_info = drm_gem_cma_print_info,
     .get_sg_table = drm_gem_cma_prime_get_sg_table,
     .vmap = drm_gem_cma_prime_vmap,
     .vm_ops = &drm_gem_cma_vm_ops,
};

struct drm_gem_object *
drm_cma_gem_create_object_default_funcs(struct drm_device *dev, size_t size)
{
     struct drm_gem_cma_object *cma_obj;

     cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
     if (!cma_obj)
         return NULL;

     cma_obj->base.funcs = &drm_cma_gem_funcs;

     return cma_obj;
}

tinydrm drivers relies on the buffer always having a virtual address, so
for imported buffers there's currently a custom .gem_prime_import_sg_table
that vmaps the buffer. In order to use the default cma helper gem
functions I plan to do the vmapping on framebuffer creation instead.

I could create a pair of functions (fb_create/destroy) in the cma helper
to achieve that:

struct drm_framebuffer *
drm_cma_fb_create_vmap_with_funcs(struct drm_device *dev, struct 
drm_file *file,
                   const struct drm_mode_fb_cmd2 *mode_cmd,
                   const struct drm_framebuffer_funcs *funcs)
{
     struct drm_gem_cma_object *cma;
     struct drm_framebuffer *fb;
     struct drm_gem_object *gem;

     fb = drm_gem_fb_create_with_funcs(dev, file, mode_cmd, funcs);
     if (IS_ERR(fb))
         return fb;

     gem = drm_gem_fb_get_obj(fb, 0);
     cma = to_drm_gem_cma_obj(gem);

     if (gem->import_attach)
         cma->vaddr = dma_buf_vmap(gem->import_attach->dmabuf);

     if (!cma->vaddr) {
         DRM_DEV_DEBUG(dev->dev, "Failed to vmap buffer\n");
         drm_gem_fb_destroy(fb);
         return ERR_PTR(-ENOMEM);
     }

     return fb;
}

void drm_cma_fb_destroy_vunmap(struct drm_framebuffer *fb)
{
     struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
     struct drm_gem_cma_object *cma = to_drm_gem_cma_obj(gem);

     if (gem->import_attach) {
         dma_buf_vmap(gem->import_attach->dmabuf, cma->vaddr);
         cma->vaddr = NULL;
     }
     drm_gem_fb_destroy(fb);
}


This approach means that I would have to do the same for the future shmem
helper as well. If I add a vaddr to the gem object, I could create a
common pair of functions in the gem fb helper that can be used regardless
of the underlying buffer:

struct drm_gem_object {
     void *vaddr;
};

struct drm_framebuffer *
drm_gem_fb_create_vmap_with_funcs(struct drm_device *dev, struct 
drm_file *file,
                   const struct drm_mode_fb_cmd2 *mode_cmd,
                   const struct drm_framebuffer_funcs *funcs)
{
     struct drm_framebuffer *fb;
     struct drm_gem_object *obj;
     void *vaddr;

     fb = drm_gem_fb_create_with_funcs(dev, file, mode_cmd, funcs);
     if (IS_ERR(fb))
         return fb;

     if (obj->import_attach)
         vaddr = dma_buf_vmap(obj->import_attach->dmabuf);
     else
         vaddr = drm_gem_vmap(obj);

     if (!vaddr || IS_ERR(vaddr)) {
         DRM_DEV_DEBUG(dev->dev, "Failed to vmap buffer\n");
         drm_gem_fb_destroy(fb);
         return ERR_PTR(-ENOMEM);
     }

     obj->vaddr = vaddr;

     return fb;
}

void drm_gem_fb_destroy_vunmap(struct drm_framebuffer *fb)
{
     struct drm_gem_object *obj = drm_gem_fb_get_obj(fb, 0);

     if (obj->import_attach) {
         dma_buf_vmap(obj->import_attach->dmabuf, obj->vaddr);
         obj->vaddr = NULL;
     } else {
         drm_gem_vunmap(obj, obj->vaddr);
     }
     drm_gem_fb_destroy(fb);
}


It is also possible to take this a bit further and move the dma_buf_vmap()
call into drm_gem_vmap() and let it provide an address for imported
buffers as well:

struct drm_gem_object {
     struct mutex vmap_lock;
     unsigned int vmap_use_count;
     void *vaddr;
};

void *drm_gem_vmap(struct drm_gem_object *obj)
{
     void *vaddr;
     int ret;

     ret = mutex_lock_interruptible(&obj->vmap_lock);
     if (ret)
         return ERR_PTR(ret);

     if (obj->vmap_use_count++ > 0) {
         vaddr = obj->vaddr;
         goto out_unlock;
     }

     if (obj->import_attach)
         vaddr = dma_buf_vmap(obj->import_attach->dmabuf);
     else if (obj->funcs && obj->funcs->vmap)
         vaddr = obj->funcs->vmap(obj);
     else if (obj->dev->driver->gem_prime_vmap)
         vaddr = obj->dev->driver->gem_prime_vmap(obj);
     else
         vaddr = ERR_PTR(-EOPNOTSUPP);

     if (!vaddr)
         vaddr = ERR_PTR(-ENOMEM);
     if (IS_ERR(vaddr)) {
         obj->vmap_use_count = 0;
         goto out_unlock;
     }

     obj->vaddr = vaddr;
out_unlock:
     mutex_unlock(&obj->vmap_lock);

     return vaddr;
}

void drm_gem_vunmap(struct drm_gem_object *obj)
{
     mutex_lock(&obj->vmap_lock);

     if (WARN_ON_ONCE(!obj->vmap_use_count))
         goto out_unlock;

     if (--obj->vmap_use_count > 0)
         goto out_unlock;

     if (obj->import_attach)
         dma_buf_vunmap(obj->import_attach->dmabuf, obj->vaddr);
     else if (obj->funcs && obj->funcs->vunmap)
         obj->funcs->vunmap(obj, obj->vaddr);
     else if (obj->dev->driver->gem_prime_vunmap)
         obj->dev->driver->gem_prime_vunmap(obj, obj->vaddr);
out_unlock:
     mutex_unlock(&obj->vmap_lock);
}


What do you think?

Noralf.

>   drivers/gpu/drm/drm_client.c |  12 ++--
>   drivers/gpu/drm/drm_gem.c    | 109 ++++++++++++++++++++++++++++++++---
>   drivers/gpu/drm/drm_prime.c  |  34 ++++++-----
>   include/drm/drm_gem.h        | 131 +++++++++++++++++++++++++++++++++++++++++++
>   4 files changed, 252 insertions(+), 34 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
> index 17d9a64e885e..eca7331762e4 100644
> --- a/drivers/gpu/drm/drm_client.c
> +++ b/drivers/gpu/drm/drm_client.c
> @@ -80,8 +80,7 @@ int drm_client_new(struct drm_device *dev, struct drm_client_dev *client,
>   {
>   	int ret;
>   
> -	if (!drm_core_check_feature(dev, DRIVER_MODESET) ||
> -	    !dev->driver->dumb_create || !dev->driver->gem_prime_vmap)
> +	if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create)
>   		return -EOPNOTSUPP;
>   
>   	if (funcs && !try_module_get(funcs->owner))
> @@ -212,8 +211,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
>   {
>   	struct drm_device *dev = buffer->client->dev;
>   
> -	if (buffer->vaddr && dev->driver->gem_prime_vunmap)
> -		dev->driver->gem_prime_vunmap(buffer->gem, buffer->vaddr);
> +	drm_gem_vunmap(buffer->gem, buffer->vaddr);
>   
>   	if (buffer->gem)
>   		drm_gem_object_put_unlocked(buffer->gem);
> @@ -266,9 +264,9 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u
>   	 * fd_install step out of the driver backend hooks, to make that
>   	 * final step optional for internal users.
>   	 */
> -	vaddr = dev->driver->gem_prime_vmap(obj);
> -	if (!vaddr) {
> -		ret = -ENOMEM;
> +	vaddr = drm_gem_vmap(obj);
> +	if (IS_ERR(vaddr)) {
> +		ret = PTR_ERR(vaddr);
>   		goto err_delete;
>   	}
>   
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index 512078ebd97b..8b55ece97967 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -257,7 +257,9 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
>   	struct drm_gem_object *obj = ptr;
>   	struct drm_device *dev = obj->dev;
>   
> -	if (dev->driver->gem_close_object)
> +	if (obj->funcs && obj->funcs->close)
> +		obj->funcs->close(obj, file_priv);
> +	else if (dev->driver->gem_close_object)
>   		dev->driver->gem_close_object(obj, file_priv);
>   
>   	if (drm_core_check_feature(dev, DRIVER_PRIME))
> @@ -410,7 +412,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
>   	if (ret)
>   		goto err_remove;
>   
> -	if (dev->driver->gem_open_object) {
> +	if (obj->funcs && obj->funcs->open) {
> +		ret = obj->funcs->open(obj, file_priv);
> +		if (ret)
> +			goto err_revoke;
> +	} else if (dev->driver->gem_open_object) {
>   		ret = dev->driver->gem_open_object(obj, file_priv);
>   		if (ret)
>   			goto err_revoke;
> @@ -835,7 +841,9 @@ drm_gem_object_free(struct kref *kref)
>   		container_of(kref, struct drm_gem_object, refcount);
>   	struct drm_device *dev = obj->dev;
>   
> -	if (dev->driver->gem_free_object_unlocked) {
> +	if (obj->funcs) {
> +		obj->funcs->free(obj);
> +	} else if (dev->driver->gem_free_object_unlocked) {
>   		dev->driver->gem_free_object_unlocked(obj);
>   	} else if (dev->driver->gem_free_object) {
>   		WARN_ON(!mutex_is_locked(&dev->struct_mutex));
> @@ -864,13 +872,13 @@ drm_gem_object_put_unlocked(struct drm_gem_object *obj)
>   
>   	dev = obj->dev;
>   
> -	if (dev->driver->gem_free_object_unlocked) {
> -		kref_put(&obj->refcount, drm_gem_object_free);
> -	} else {
> +	if (dev->driver->gem_free_object) {
>   		might_lock(&dev->struct_mutex);
>   		if (kref_put_mutex(&obj->refcount, drm_gem_object_free,
>   				&dev->struct_mutex))
>   			mutex_unlock(&dev->struct_mutex);
> +	} else {
> +		kref_put(&obj->refcount, drm_gem_object_free);
>   	}
>   }
>   EXPORT_SYMBOL(drm_gem_object_put_unlocked);
> @@ -960,11 +968,14 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
>   	if (obj_size < vma->vm_end - vma->vm_start)
>   		return -EINVAL;
>   
> -	if (!dev->driver->gem_vm_ops)
> +	if (obj->funcs && obj->funcs->vm_ops)
> +		vma->vm_ops = obj->funcs->vm_ops;
> +	else if (dev->driver->gem_vm_ops)
> +		vma->vm_ops = dev->driver->gem_vm_ops;
> +	else
>   		return -EINVAL;
>   
>   	vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
> -	vma->vm_ops = dev->driver->gem_vm_ops;
>   	vma->vm_private_data = obj;
>   	vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
>   	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
> @@ -1066,6 +1077,86 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent,
>   	drm_printf_indent(p, indent, "imported=%s\n",
>   			  obj->import_attach ? "yes" : "no");
>   
> -	if (obj->dev->driver->gem_print_info)
> +	if (obj->funcs && obj->funcs->print_info)
> +		obj->funcs->print_info(p, indent, obj);
> +	else if (obj->dev->driver->gem_print_info)
>   		obj->dev->driver->gem_print_info(p, indent, obj);
>   }
> +
> +/**
> + * drm_gem_pin - Pin backing buffer in memory
> + * @obj: GEM object
> + *
> + * Make sure the backing buffer is pinned in memory.
> + *
> + * Returns:
> + * 0 on success or a negative error code on failure.
> + */
> +int drm_gem_pin(struct drm_gem_object *obj)
> +{
> +	if (obj->funcs && obj->funcs->pin)
> +		return obj->funcs->pin(obj);
> +	else if (obj->dev->driver->gem_prime_pin)
> +		return obj->dev->driver->gem_prime_pin(obj);
> +	else
> +		return 0;
> +}
> +EXPORT_SYMBOL(drm_gem_pin);
> +
> +/**
> + * drm_gem_unpin - Unpin backing buffer from memory
> + * @obj: GEM object
> + *
> + * Relax the requirement that the backing buffer is pinned in memory.
> + */
> +void drm_gem_unpin(struct drm_gem_object *obj)
> +{
> +	if (obj->funcs && obj->funcs->unpin)
> +		obj->funcs->unpin(obj);
> +	else if (obj->dev->driver->gem_prime_unpin)
> +		obj->dev->driver->gem_prime_unpin(obj);
> +}
> +EXPORT_SYMBOL(drm_gem_unpin);
> +
> +/**
> + * drm_gem_vmap - Map buffer into kernel virtual address space
> + * @obj: GEM object
> + *
> + * Returns:
> + * A virtual pointer to a newly created GEM object or an ERR_PTR-encoded negative
> + * error code on failure.
> + */
> +void *drm_gem_vmap(struct drm_gem_object *obj)
> +{
> +	void *vaddr;
> +
> +	if (obj->funcs && obj->funcs->vmap)
> +		vaddr = obj->funcs->vmap(obj);
> +	else if (obj->dev->driver->gem_prime_vmap)
> +		vaddr = obj->dev->driver->gem_prime_vmap(obj);
> +	else
> +		vaddr = ERR_PTR(-EOPNOTSUPP);
> +
> +	if (!vaddr)
> +		vaddr = ERR_PTR(-ENOMEM);
> +
> +	return vaddr;
> +}
> +EXPORT_SYMBOL(drm_gem_vmap);
> +
> +/**
> + * drm_gem_vunmap - Remove buffer mapping from kernel virtual address space
> + * @obj: GEM object
> + * @vaddr: Virtual address (can be NULL)
> + */
> +void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr)
> +{
> +	if (!vaddr)
> +		return;
> +
> +	if (obj->funcs && obj->funcs->vunmap)
> +		obj->funcs->vunmap(obj, vaddr);
> +	else if (obj->dev->driver->gem_prime_vunmap)
> +		obj->dev->driver->gem_prime_vunmap(obj, vaddr);
> +}
> +EXPORT_SYMBOL(drm_gem_vunmap);
> diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
> index 42abf98c1d4a..e0ab5213efa7 100644
> --- a/drivers/gpu/drm/drm_prime.c
> +++ b/drivers/gpu/drm/drm_prime.c
> @@ -199,7 +199,6 @@ int drm_gem_map_attach(struct dma_buf *dma_buf,
>   {
>   	struct drm_prime_attachment *prime_attach;
>   	struct drm_gem_object *obj = dma_buf->priv;
> -	struct drm_device *dev = obj->dev;
>   
>   	prime_attach = kzalloc(sizeof(*prime_attach), GFP_KERNEL);
>   	if (!prime_attach)
> @@ -208,10 +207,7 @@ int drm_gem_map_attach(struct dma_buf *dma_buf,
>   	prime_attach->dir = DMA_NONE;
>   	attach->priv = prime_attach;
>   
> -	if (!dev->driver->gem_prime_pin)
> -		return 0;
> -
> -	return dev->driver->gem_prime_pin(obj);
> +	return drm_gem_pin(obj);
>   }
>   EXPORT_SYMBOL(drm_gem_map_attach);
>   
> @@ -228,7 +224,6 @@ void drm_gem_map_detach(struct dma_buf *dma_buf,
>   {
>   	struct drm_prime_attachment *prime_attach = attach->priv;
>   	struct drm_gem_object *obj = dma_buf->priv;
> -	struct drm_device *dev = obj->dev;
>   
>   	if (prime_attach) {
>   		struct sg_table *sgt = prime_attach->sgt;
> @@ -247,8 +242,7 @@ void drm_gem_map_detach(struct dma_buf *dma_buf,
>   		attach->priv = NULL;
>   	}
>   
> -	if (dev->driver->gem_prime_unpin)
> -		dev->driver->gem_prime_unpin(obj);
> +	drm_gem_unpin(obj);
>   }
>   EXPORT_SYMBOL(drm_gem_map_detach);
>   
> @@ -310,7 +304,10 @@ struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
>   	if (WARN_ON(prime_attach->dir != DMA_NONE))
>   		return ERR_PTR(-EBUSY);
>   
> -	sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
> +	if (obj->funcs)
> +		sgt = obj->funcs->get_sg_table(obj);
> +	else
> +		sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
>   
>   	if (!IS_ERR(sgt)) {
>   		if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
> @@ -406,12 +403,13 @@ EXPORT_SYMBOL(drm_gem_dmabuf_release);
>   void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
>   {
>   	struct drm_gem_object *obj = dma_buf->priv;
> -	struct drm_device *dev = obj->dev;
> +	void *vaddr;
>   
> -	if (dev->driver->gem_prime_vmap)
> -		return dev->driver->gem_prime_vmap(obj);
> -	else
> -		return NULL;
> +	vaddr = drm_gem_vmap(obj);
> +	if (IS_ERR(vaddr))
> +		vaddr = NULL;
> +
> +	return vaddr;
>   }
>   EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
>   
> @@ -426,10 +424,8 @@ EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
>   void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
>   {
>   	struct drm_gem_object *obj = dma_buf->priv;
> -	struct drm_device *dev = obj->dev;
>   
> -	if (dev->driver->gem_prime_vunmap)
> -		dev->driver->gem_prime_vunmap(obj, vaddr);
> +	drm_gem_vunmap(obj, vaddr);
>   }
>   EXPORT_SYMBOL(drm_gem_dmabuf_vunmap);
>   
> @@ -529,7 +525,9 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev,
>   		return dmabuf;
>   	}
>   
> -	if (dev->driver->gem_prime_export)
> +	if (obj->funcs && obj->funcs->export)
> +		dmabuf = obj->funcs->export(obj, flags);
> +	else if (dev->driver->gem_prime_export)
>   		dmabuf = dev->driver->gem_prime_export(dev, obj, flags);
>   	else
>   		dmabuf = drm_gem_prime_export(dev, obj, flags);
> diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
> index 3583b98a1718..f466ce5bde0e 100644
> --- a/include/drm/drm_gem.h
> +++ b/include/drm/drm_gem.h
> @@ -38,6 +38,121 @@
>   
>   #include <drm/drm_vma_manager.h>
>   
> +struct drm_gem_object;
> +
> +/**
> + * struct drm_gem_object_funcs - GEM object functions
> + */
> +struct drm_gem_object_funcs {
> +	/**
> +	 * @free:
> +	 *
> +	 * Deconstructor for drm_gem_objects.
> +	 *
> +	 * This callback is mandatory.
> +	 */
> +	void (*free)(struct drm_gem_object *obj);
> +
> +	/**
> +	 * @open:
> +	 *
> +	 * Called upon GEM handle creation.
> +	 *
> +	 * This callback is optional.
> +	 */
> +	int (*open)(struct drm_gem_object *obj, struct drm_file *file);
> +
> +	/**
> +	 * @close:
> +	 *
> +	 * Called upon GEM handle release.
> +	 *
> +	 * This callback is optional.
> +	 */
> +	void (*close)(struct drm_gem_object *obj, struct drm_file *file);
> +
> +	/**
> +	 * @print_info:
> +	 *
> +	 * If driver subclasses struct &drm_gem_object, it can implement this
> +	 * optional hook for printing additional driver specific info.
> +	 *
> +	 * drm_printf_indent() should be used in the callback passing it the
> +	 * indent argument.
> +	 *
> +	 * This callback is called from drm_gem_print_info().
> +	 *
> +	 * This callback is optional.
> +	 */
> +	void (*print_info)(struct drm_printer *p, unsigned int indent,
> +			   const struct drm_gem_object *obj);
> +
> +	/**
> +	 * @export:
> +	 *
> +	 * Export backing buffer as a &dma_buf.
> +	 * If this is not set drm_gem_prime_export() is used.
> +	 *
> +	 * This callback is optional.
> +	 */
> +	struct dma_buf *(*export)(struct drm_gem_object *obj, int flags);
> +
> +	/**
> +	 * @pin:
> +	 *
> +	 * Pin backing buffer in memory.
> +	 *
> +	 * This callback is optional.
> +	 */
> +	int (*pin)(struct drm_gem_object *obj);
> +
> +	/**
> +	 * @unpin:
> +	 *
> +	 * Unpin backing buffer.
> +	 *
> +	 * This callback is optional.
> +	 */
> +	void (*unpin)(struct drm_gem_object *obj);
> +
> +	/**
> +	 * @get_sg_table:
> +	 *
> +	 * Returns a Scatter-Gather table representation of the buffer.
> +	 * Used when exporting a buffer.
> +	 *
> +	 * This callback is mandatory if buffer export is supported.
> +	 */
> +	struct sg_table *(*get_sg_table)(struct drm_gem_object *obj);
> +
> +	/**
> +	 * @vmap:
> +	 *
> +	 * Returns a virtual address for the buffer.
> +	 *
> +	 * This callback is optional.
> +	 */
> +	void *(*vmap)(struct drm_gem_object *obj);
> +
> +	/**
> +	 * @vunmap:
> +	 *
> +	 * Releases the the address previously returned by @vmap.
> +	 *
> +	 * This callback is optional.
> +	 */
> +	void (*vunmap)(struct drm_gem_object *obj, void *vaddr);
> +
> +	/**
> +	 * @vm_ops:
> +	 *
> +	 * Virtual memory operations used with mmap.
> +	 *
> +	 * This is optional but necessary for mmap support.
> +	 */
> +	const struct vm_operations_struct *vm_ops;
> +};
> +
>   /**
>    * struct drm_gem_object - GEM buffer object
>    *
> @@ -146,6 +261,17 @@ struct drm_gem_object {
>   	 * simply leave it as NULL.
>   	 */
>   	struct dma_buf_attachment *import_attach;
> +
> +	/**
> +	 * @funcs:
> +	 *
> +	 * Optional GEM object functions. If this is set, it will be used instead of the
> +	 * corresponding &drm_driver GEM callbacks.
> +	 *
> +	 * New drivers should use this.
> +	 *
> +	 */
> +	const struct drm_gem_object_funcs *funcs;
>   };
>   
>   /**
> @@ -293,4 +419,9 @@ int drm_gem_dumb_destroy(struct drm_file *file,
>   			 struct drm_device *dev,
>   			 uint32_t handle);
>   
> +int drm_gem_pin(struct drm_gem_object *obj);
> +void drm_gem_unpin(struct drm_gem_object *obj);
> +void *drm_gem_vmap(struct drm_gem_object *obj);
> +void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr);
> +
>   #endif /* __DRM_GEM_H__ */

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Intel-gfx] [PATCH v5 3/5] drm/gem: Add drm_gem_object_funcs
  2018-10-31 23:37   ` Noralf Trønnes
@ 2018-11-01  8:36     ` Daniel Vetter
  0 siblings, 0 replies; 35+ messages in thread
From: Daniel Vetter @ 2018-11-01  8:36 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: sam, intel-gfx, david, dri-devel

On Thu, Nov 01, 2018 at 12:37:14AM +0100, Noralf Trønnes wrote:
> 
> Den 17.10.2018 15.04, skrev Noralf Trønnes:
> > This adds an optional function table on GEM objects.
> > The main benefit is for drivers that support more than one type of
> > memory (shmem,vram,cma) for their buffers depending on the hardware it
> > runs on. With the callbacks attached to the GEM object itself, it is
> > easier to have core helpers for the the various buffer types. The driver
> > only has to make the decision about buffer type on GEM object creation
> > and all other callbacks can be handled by the chosen helper.
> > 
> > drm_driver->gem_prime_res_obj has not been added since there's a todo to
> > put a reservation_object into drm_gem_object.
> > 
> > v2: Drop drm_gem_object_funcs->prime_mmap in favour of
> > drm_gem_prime_mmap() (Daniel Vetter)
> > 
> > v1:
> > - drm_gem_object_funcs.map -> .prime_map let it only do PRIME mmap like
> >    the function it superseeds (Daniel Vetter)
> > - Flip around the if ladders and make obj->funcs the first choice
> >    highlighting the fact that this the new default way of doing it
> >    (Daniel Vetter)
> > 
> > Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> > Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > ---
> 
> Now that the shmem helper has now been postponed to the future I'm
> thinking about doing some prep work in tinydrm to loosen the coupling to
> the cma helper (longterm goal is try and get rid of tinydrm.ko altogether).
> 
> First step could be to add a drm_driver->gem_create_object function for
> the cma helper that gives the default gem functions:
> 
> static const struct drm_gem_object_funcs drm_cma_gem_funcs = {
>     .free = drm_gem_cma_free_object,
>     .print_info = drm_gem_cma_print_info,
>     .get_sg_table = drm_gem_cma_prime_get_sg_table,
>     .vmap = drm_gem_cma_prime_vmap,
>     .vm_ops = &drm_gem_cma_vm_ops,
> };
> 
> struct drm_gem_object *
> drm_cma_gem_create_object_default_funcs(struct drm_device *dev, size_t size)
> {
>     struct drm_gem_cma_object *cma_obj;
> 
>     cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
>     if (!cma_obj)
>         return NULL;
> 
>     cma_obj->base.funcs = &drm_cma_gem_funcs;
> 
>     return cma_obj;
> }
> 
> tinydrm drivers relies on the buffer always having a virtual address, so
> for imported buffers there's currently a custom .gem_prime_import_sg_table
> that vmaps the buffer. In order to use the default cma helper gem
> functions I plan to do the vmapping on framebuffer creation instead.
> 
> I could create a pair of functions (fb_create/destroy) in the cma helper
> to achieve that:
> 
> struct drm_framebuffer *
> drm_cma_fb_create_vmap_with_funcs(struct drm_device *dev, struct drm_file
> *file,
>                   const struct drm_mode_fb_cmd2 *mode_cmd,
>                   const struct drm_framebuffer_funcs *funcs)
> {
>     struct drm_gem_cma_object *cma;
>     struct drm_framebuffer *fb;
>     struct drm_gem_object *gem;
> 
>     fb = drm_gem_fb_create_with_funcs(dev, file, mode_cmd, funcs);
>     if (IS_ERR(fb))
>         return fb;
> 
>     gem = drm_gem_fb_get_obj(fb, 0);
>     cma = to_drm_gem_cma_obj(gem);
> 
>     if (gem->import_attach)
>         cma->vaddr = dma_buf_vmap(gem->import_attach->dmabuf);
> 
>     if (!cma->vaddr) {
>         DRM_DEV_DEBUG(dev->dev, "Failed to vmap buffer\n");
>         drm_gem_fb_destroy(fb);
>         return ERR_PTR(-ENOMEM);
>     }
> 
>     return fb;
> }
> 
> void drm_cma_fb_destroy_vunmap(struct drm_framebuffer *fb)
> {
>     struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
>     struct drm_gem_cma_object *cma = to_drm_gem_cma_obj(gem);
> 
>     if (gem->import_attach) {
>         dma_buf_vmap(gem->import_attach->dmabuf, cma->vaddr);
>         cma->vaddr = NULL;
>     }
>     drm_gem_fb_destroy(fb);
> }
> 
> 
> This approach means that I would have to do the same for the future shmem
> helper as well. If I add a vaddr to the gem object, I could create a
> common pair of functions in the gem fb helper that can be used regardless
> of the underlying buffer:
> 
> struct drm_gem_object {
>     void *vaddr;
> };
> 
> struct drm_framebuffer *
> drm_gem_fb_create_vmap_with_funcs(struct drm_device *dev, struct drm_file
> *file,
>                   const struct drm_mode_fb_cmd2 *mode_cmd,
>                   const struct drm_framebuffer_funcs *funcs)
> {
>     struct drm_framebuffer *fb;
>     struct drm_gem_object *obj;
>     void *vaddr;
> 
>     fb = drm_gem_fb_create_with_funcs(dev, file, mode_cmd, funcs);
>     if (IS_ERR(fb))
>         return fb;
> 
>     if (obj->import_attach)
>         vaddr = dma_buf_vmap(obj->import_attach->dmabuf);
>     else
>         vaddr = drm_gem_vmap(obj);
> 
>     if (!vaddr || IS_ERR(vaddr)) {
>         DRM_DEV_DEBUG(dev->dev, "Failed to vmap buffer\n");
>         drm_gem_fb_destroy(fb);
>         return ERR_PTR(-ENOMEM);
>     }
> 
>     obj->vaddr = vaddr;
> 
>     return fb;
> }
> 
> void drm_gem_fb_destroy_vunmap(struct drm_framebuffer *fb)
> {
>     struct drm_gem_object *obj = drm_gem_fb_get_obj(fb, 0);
> 
>     if (obj->import_attach) {
>         dma_buf_vmap(obj->import_attach->dmabuf, obj->vaddr);
>         obj->vaddr = NULL;
>     } else {
>         drm_gem_vunmap(obj, obj->vaddr);
>     }
>     drm_gem_fb_destroy(fb);
> }
> 
> 
> It is also possible to take this a bit further and move the dma_buf_vmap()
> call into drm_gem_vmap() and let it provide an address for imported
> buffers as well:
> 
> struct drm_gem_object {
>     struct mutex vmap_lock;
>     unsigned int vmap_use_count;
>     void *vaddr;
> };
> 
> void *drm_gem_vmap(struct drm_gem_object *obj)
> {
>     void *vaddr;
>     int ret;
> 
>     ret = mutex_lock_interruptible(&obj->vmap_lock);
>     if (ret)
>         return ERR_PTR(ret);
> 
>     if (obj->vmap_use_count++ > 0) {
>         vaddr = obj->vaddr;
>         goto out_unlock;
>     }
> 
>     if (obj->import_attach)
>         vaddr = dma_buf_vmap(obj->import_attach->dmabuf);
>     else if (obj->funcs && obj->funcs->vmap)
>         vaddr = obj->funcs->vmap(obj);
>     else if (obj->dev->driver->gem_prime_vmap)
>         vaddr = obj->dev->driver->gem_prime_vmap(obj);
>     else
>         vaddr = ERR_PTR(-EOPNOTSUPP);
> 
>     if (!vaddr)
>         vaddr = ERR_PTR(-ENOMEM);
>     if (IS_ERR(vaddr)) {
>         obj->vmap_use_count = 0;
>         goto out_unlock;
>     }
> 
>     obj->vaddr = vaddr;
> out_unlock:
>     mutex_unlock(&obj->vmap_lock);
> 
>     return vaddr;
> }
> 
> void drm_gem_vunmap(struct drm_gem_object *obj)
> {
>     mutex_lock(&obj->vmap_lock);
> 
>     if (WARN_ON_ONCE(!obj->vmap_use_count))
>         goto out_unlock;
> 
>     if (--obj->vmap_use_count > 0)
>         goto out_unlock;
> 
>     if (obj->import_attach)
>         dma_buf_vunmap(obj->import_attach->dmabuf, obj->vaddr);
>     else if (obj->funcs && obj->funcs->vunmap)
>         obj->funcs->vunmap(obj, obj->vaddr);
>     else if (obj->dev->driver->gem_prime_vunmap)
>         obj->dev->driver->gem_prime_vunmap(obj, obj->vaddr);
> out_unlock:
>     mutex_unlock(&obj->vmap_lock);
> }
> 
> 
> What do you think?

For the reasons you've pointed out in your other mail, vmap is
complicated. Even more complicated when you want to mix it with buffer
sharing. On reasonable modern architectures (anything ppc, x86 and arm8+)
it just amounts to getting the cache flushing right, but on older arm you
have all that fun rmk laid out with incompatible mappings and stuff.

On top we have subsystems that kinda muddle on, like spi, so no clear
indication what would be best from those either.

I honestly have no idea what's the best approach.

Your draft should work, but we might encode vmap expectatins that just
don't really work in general.
-Daniel

> 
> Noralf.
> 
> >   drivers/gpu/drm/drm_client.c |  12 ++--
> >   drivers/gpu/drm/drm_gem.c    | 109 ++++++++++++++++++++++++++++++++---
> >   drivers/gpu/drm/drm_prime.c  |  34 ++++++-----
> >   include/drm/drm_gem.h        | 131 +++++++++++++++++++++++++++++++++++++++++++
> >   4 files changed, 252 insertions(+), 34 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
> > index 17d9a64e885e..eca7331762e4 100644
> > --- a/drivers/gpu/drm/drm_client.c
> > +++ b/drivers/gpu/drm/drm_client.c
> > @@ -80,8 +80,7 @@ int drm_client_new(struct drm_device *dev, struct drm_client_dev *client,
> >   {
> >   	int ret;
> > -	if (!drm_core_check_feature(dev, DRIVER_MODESET) ||
> > -	    !dev->driver->dumb_create || !dev->driver->gem_prime_vmap)
> > +	if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create)
> >   		return -EOPNOTSUPP;
> >   	if (funcs && !try_module_get(funcs->owner))
> > @@ -212,8 +211,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
> >   {
> >   	struct drm_device *dev = buffer->client->dev;
> > -	if (buffer->vaddr && dev->driver->gem_prime_vunmap)
> > -		dev->driver->gem_prime_vunmap(buffer->gem, buffer->vaddr);
> > +	drm_gem_vunmap(buffer->gem, buffer->vaddr);
> >   	if (buffer->gem)
> >   		drm_gem_object_put_unlocked(buffer->gem);
> > @@ -266,9 +264,9 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u
> >   	 * fd_install step out of the driver backend hooks, to make that
> >   	 * final step optional for internal users.
> >   	 */
> > -	vaddr = dev->driver->gem_prime_vmap(obj);
> > -	if (!vaddr) {
> > -		ret = -ENOMEM;
> > +	vaddr = drm_gem_vmap(obj);
> > +	if (IS_ERR(vaddr)) {
> > +		ret = PTR_ERR(vaddr);
> >   		goto err_delete;
> >   	}
> > diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> > index 512078ebd97b..8b55ece97967 100644
> > --- a/drivers/gpu/drm/drm_gem.c
> > +++ b/drivers/gpu/drm/drm_gem.c
> > @@ -257,7 +257,9 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
> >   	struct drm_gem_object *obj = ptr;
> >   	struct drm_device *dev = obj->dev;
> > -	if (dev->driver->gem_close_object)
> > +	if (obj->funcs && obj->funcs->close)
> > +		obj->funcs->close(obj, file_priv);
> > +	else if (dev->driver->gem_close_object)
> >   		dev->driver->gem_close_object(obj, file_priv);
> >   	if (drm_core_check_feature(dev, DRIVER_PRIME))
> > @@ -410,7 +412,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
> >   	if (ret)
> >   		goto err_remove;
> > -	if (dev->driver->gem_open_object) {
> > +	if (obj->funcs && obj->funcs->open) {
> > +		ret = obj->funcs->open(obj, file_priv);
> > +		if (ret)
> > +			goto err_revoke;
> > +	} else if (dev->driver->gem_open_object) {
> >   		ret = dev->driver->gem_open_object(obj, file_priv);
> >   		if (ret)
> >   			goto err_revoke;
> > @@ -835,7 +841,9 @@ drm_gem_object_free(struct kref *kref)
> >   		container_of(kref, struct drm_gem_object, refcount);
> >   	struct drm_device *dev = obj->dev;
> > -	if (dev->driver->gem_free_object_unlocked) {
> > +	if (obj->funcs) {
> > +		obj->funcs->free(obj);
> > +	} else if (dev->driver->gem_free_object_unlocked) {
> >   		dev->driver->gem_free_object_unlocked(obj);
> >   	} else if (dev->driver->gem_free_object) {
> >   		WARN_ON(!mutex_is_locked(&dev->struct_mutex));
> > @@ -864,13 +872,13 @@ drm_gem_object_put_unlocked(struct drm_gem_object *obj)
> >   	dev = obj->dev;
> > -	if (dev->driver->gem_free_object_unlocked) {
> > -		kref_put(&obj->refcount, drm_gem_object_free);
> > -	} else {
> > +	if (dev->driver->gem_free_object) {
> >   		might_lock(&dev->struct_mutex);
> >   		if (kref_put_mutex(&obj->refcount, drm_gem_object_free,
> >   				&dev->struct_mutex))
> >   			mutex_unlock(&dev->struct_mutex);
> > +	} else {
> > +		kref_put(&obj->refcount, drm_gem_object_free);
> >   	}
> >   }
> >   EXPORT_SYMBOL(drm_gem_object_put_unlocked);
> > @@ -960,11 +968,14 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
> >   	if (obj_size < vma->vm_end - vma->vm_start)
> >   		return -EINVAL;
> > -	if (!dev->driver->gem_vm_ops)
> > +	if (obj->funcs && obj->funcs->vm_ops)
> > +		vma->vm_ops = obj->funcs->vm_ops;
> > +	else if (dev->driver->gem_vm_ops)
> > +		vma->vm_ops = dev->driver->gem_vm_ops;
> > +	else
> >   		return -EINVAL;
> >   	vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
> > -	vma->vm_ops = dev->driver->gem_vm_ops;
> >   	vma->vm_private_data = obj;
> >   	vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
> >   	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
> > @@ -1066,6 +1077,86 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent,
> >   	drm_printf_indent(p, indent, "imported=%s\n",
> >   			  obj->import_attach ? "yes" : "no");
> > -	if (obj->dev->driver->gem_print_info)
> > +	if (obj->funcs && obj->funcs->print_info)
> > +		obj->funcs->print_info(p, indent, obj);
> > +	else if (obj->dev->driver->gem_print_info)
> >   		obj->dev->driver->gem_print_info(p, indent, obj);
> >   }
> > +
> > +/**
> > + * drm_gem_pin - Pin backing buffer in memory
> > + * @obj: GEM object
> > + *
> > + * Make sure the backing buffer is pinned in memory.
> > + *
> > + * Returns:
> > + * 0 on success or a negative error code on failure.
> > + */
> > +int drm_gem_pin(struct drm_gem_object *obj)
> > +{
> > +	if (obj->funcs && obj->funcs->pin)
> > +		return obj->funcs->pin(obj);
> > +	else if (obj->dev->driver->gem_prime_pin)
> > +		return obj->dev->driver->gem_prime_pin(obj);
> > +	else
> > +		return 0;
> > +}
> > +EXPORT_SYMBOL(drm_gem_pin);
> > +
> > +/**
> > + * drm_gem_unpin - Unpin backing buffer from memory
> > + * @obj: GEM object
> > + *
> > + * Relax the requirement that the backing buffer is pinned in memory.
> > + */
> > +void drm_gem_unpin(struct drm_gem_object *obj)
> > +{
> > +	if (obj->funcs && obj->funcs->unpin)
> > +		obj->funcs->unpin(obj);
> > +	else if (obj->dev->driver->gem_prime_unpin)
> > +		obj->dev->driver->gem_prime_unpin(obj);
> > +}
> > +EXPORT_SYMBOL(drm_gem_unpin);
> > +
> > +/**
> > + * drm_gem_vmap - Map buffer into kernel virtual address space
> > + * @obj: GEM object
> > + *
> > + * Returns:
> > + * A virtual pointer to a newly created GEM object or an ERR_PTR-encoded negative
> > + * error code on failure.
> > + */
> > +void *drm_gem_vmap(struct drm_gem_object *obj)
> > +{
> > +	void *vaddr;
> > +
> > +	if (obj->funcs && obj->funcs->vmap)
> > +		vaddr = obj->funcs->vmap(obj);
> > +	else if (obj->dev->driver->gem_prime_vmap)
> > +		vaddr = obj->dev->driver->gem_prime_vmap(obj);
> > +	else
> > +		vaddr = ERR_PTR(-EOPNOTSUPP);
> > +
> > +	if (!vaddr)
> > +		vaddr = ERR_PTR(-ENOMEM);
> > +
> > +	return vaddr;
> > +}
> > +EXPORT_SYMBOL(drm_gem_vmap);
> > +
> > +/**
> > + * drm_gem_vunmap - Remove buffer mapping from kernel virtual address space
> > + * @obj: GEM object
> > + * @vaddr: Virtual address (can be NULL)
> > + */
> > +void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr)
> > +{
> > +	if (!vaddr)
> > +		return;
> > +
> > +	if (obj->funcs && obj->funcs->vunmap)
> > +		obj->funcs->vunmap(obj, vaddr);
> > +	else if (obj->dev->driver->gem_prime_vunmap)
> > +		obj->dev->driver->gem_prime_vunmap(obj, vaddr);
> > +}
> > +EXPORT_SYMBOL(drm_gem_vunmap);
> > diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
> > index 42abf98c1d4a..e0ab5213efa7 100644
> > --- a/drivers/gpu/drm/drm_prime.c
> > +++ b/drivers/gpu/drm/drm_prime.c
> > @@ -199,7 +199,6 @@ int drm_gem_map_attach(struct dma_buf *dma_buf,
> >   {
> >   	struct drm_prime_attachment *prime_attach;
> >   	struct drm_gem_object *obj = dma_buf->priv;
> > -	struct drm_device *dev = obj->dev;
> >   	prime_attach = kzalloc(sizeof(*prime_attach), GFP_KERNEL);
> >   	if (!prime_attach)
> > @@ -208,10 +207,7 @@ int drm_gem_map_attach(struct dma_buf *dma_buf,
> >   	prime_attach->dir = DMA_NONE;
> >   	attach->priv = prime_attach;
> > -	if (!dev->driver->gem_prime_pin)
> > -		return 0;
> > -
> > -	return dev->driver->gem_prime_pin(obj);
> > +	return drm_gem_pin(obj);
> >   }
> >   EXPORT_SYMBOL(drm_gem_map_attach);
> > @@ -228,7 +224,6 @@ void drm_gem_map_detach(struct dma_buf *dma_buf,
> >   {
> >   	struct drm_prime_attachment *prime_attach = attach->priv;
> >   	struct drm_gem_object *obj = dma_buf->priv;
> > -	struct drm_device *dev = obj->dev;
> >   	if (prime_attach) {
> >   		struct sg_table *sgt = prime_attach->sgt;
> > @@ -247,8 +242,7 @@ void drm_gem_map_detach(struct dma_buf *dma_buf,
> >   		attach->priv = NULL;
> >   	}
> > -	if (dev->driver->gem_prime_unpin)
> > -		dev->driver->gem_prime_unpin(obj);
> > +	drm_gem_unpin(obj);
> >   }
> >   EXPORT_SYMBOL(drm_gem_map_detach);
> > @@ -310,7 +304,10 @@ struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
> >   	if (WARN_ON(prime_attach->dir != DMA_NONE))
> >   		return ERR_PTR(-EBUSY);
> > -	sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
> > +	if (obj->funcs)
> > +		sgt = obj->funcs->get_sg_table(obj);
> > +	else
> > +		sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
> >   	if (!IS_ERR(sgt)) {
> >   		if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir,
> > @@ -406,12 +403,13 @@ EXPORT_SYMBOL(drm_gem_dmabuf_release);
> >   void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf)
> >   {
> >   	struct drm_gem_object *obj = dma_buf->priv;
> > -	struct drm_device *dev = obj->dev;
> > +	void *vaddr;
> > -	if (dev->driver->gem_prime_vmap)
> > -		return dev->driver->gem_prime_vmap(obj);
> > -	else
> > -		return NULL;
> > +	vaddr = drm_gem_vmap(obj);
> > +	if (IS_ERR(vaddr))
> > +		vaddr = NULL;
> > +
> > +	return vaddr;
> >   }
> >   EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
> > @@ -426,10 +424,8 @@ EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
> >   void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
> >   {
> >   	struct drm_gem_object *obj = dma_buf->priv;
> > -	struct drm_device *dev = obj->dev;
> > -	if (dev->driver->gem_prime_vunmap)
> > -		dev->driver->gem_prime_vunmap(obj, vaddr);
> > +	drm_gem_vunmap(obj, vaddr);
> >   }
> >   EXPORT_SYMBOL(drm_gem_dmabuf_vunmap);
> > @@ -529,7 +525,9 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev,
> >   		return dmabuf;
> >   	}
> > -	if (dev->driver->gem_prime_export)
> > +	if (obj->funcs && obj->funcs->export)
> > +		dmabuf = obj->funcs->export(obj, flags);
> > +	else if (dev->driver->gem_prime_export)
> >   		dmabuf = dev->driver->gem_prime_export(dev, obj, flags);
> >   	else
> >   		dmabuf = drm_gem_prime_export(dev, obj, flags);
> > diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
> > index 3583b98a1718..f466ce5bde0e 100644
> > --- a/include/drm/drm_gem.h
> > +++ b/include/drm/drm_gem.h
> > @@ -38,6 +38,121 @@
> >   #include <drm/drm_vma_manager.h>
> > +struct drm_gem_object;
> > +
> > +/**
> > + * struct drm_gem_object_funcs - GEM object functions
> > + */
> > +struct drm_gem_object_funcs {
> > +	/**
> > +	 * @free:
> > +	 *
> > +	 * Deconstructor for drm_gem_objects.
> > +	 *
> > +	 * This callback is mandatory.
> > +	 */
> > +	void (*free)(struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @open:
> > +	 *
> > +	 * Called upon GEM handle creation.
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	int (*open)(struct drm_gem_object *obj, struct drm_file *file);
> > +
> > +	/**
> > +	 * @close:
> > +	 *
> > +	 * Called upon GEM handle release.
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	void (*close)(struct drm_gem_object *obj, struct drm_file *file);
> > +
> > +	/**
> > +	 * @print_info:
> > +	 *
> > +	 * If driver subclasses struct &drm_gem_object, it can implement this
> > +	 * optional hook for printing additional driver specific info.
> > +	 *
> > +	 * drm_printf_indent() should be used in the callback passing it the
> > +	 * indent argument.
> > +	 *
> > +	 * This callback is called from drm_gem_print_info().
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	void (*print_info)(struct drm_printer *p, unsigned int indent,
> > +			   const struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @export:
> > +	 *
> > +	 * Export backing buffer as a &dma_buf.
> > +	 * If this is not set drm_gem_prime_export() is used.
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	struct dma_buf *(*export)(struct drm_gem_object *obj, int flags);
> > +
> > +	/**
> > +	 * @pin:
> > +	 *
> > +	 * Pin backing buffer in memory.
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	int (*pin)(struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @unpin:
> > +	 *
> > +	 * Unpin backing buffer.
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	void (*unpin)(struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @get_sg_table:
> > +	 *
> > +	 * Returns a Scatter-Gather table representation of the buffer.
> > +	 * Used when exporting a buffer.
> > +	 *
> > +	 * This callback is mandatory if buffer export is supported.
> > +	 */
> > +	struct sg_table *(*get_sg_table)(struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @vmap:
> > +	 *
> > +	 * Returns a virtual address for the buffer.
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	void *(*vmap)(struct drm_gem_object *obj);
> > +
> > +	/**
> > +	 * @vunmap:
> > +	 *
> > +	 * Releases the the address previously returned by @vmap.
> > +	 *
> > +	 * This callback is optional.
> > +	 */
> > +	void (*vunmap)(struct drm_gem_object *obj, void *vaddr);
> > +
> > +	/**
> > +	 * @vm_ops:
> > +	 *
> > +	 * Virtual memory operations used with mmap.
> > +	 *
> > +	 * This is optional but necessary for mmap support.
> > +	 */
> > +	const struct vm_operations_struct *vm_ops;
> > +};
> > +
> >   /**
> >    * struct drm_gem_object - GEM buffer object
> >    *
> > @@ -146,6 +261,17 @@ struct drm_gem_object {
> >   	 * simply leave it as NULL.
> >   	 */
> >   	struct dma_buf_attachment *import_attach;
> > +
> > +	/**
> > +	 * @funcs:
> > +	 *
> > +	 * Optional GEM object functions. If this is set, it will be used instead of the
> > +	 * corresponding &drm_driver GEM callbacks.
> > +	 *
> > +	 * New drivers should use this.
> > +	 *
> > +	 */
> > +	const struct drm_gem_object_funcs *funcs;
> >   };
> >   /**
> > @@ -293,4 +419,9 @@ int drm_gem_dumb_destroy(struct drm_file *file,
> >   			 struct drm_device *dev,
> >   			 uint32_t handle);
> > +int drm_gem_pin(struct drm_gem_object *obj);
> > +void drm_gem_unpin(struct drm_gem_object *obj);
> > +void *drm_gem_vmap(struct drm_gem_object *obj);
> > +void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr);
> > +
> >   #endif /* __DRM_GEM_H__ */
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2018-10-17 13:04 ` [PATCH v5 4/5] drm: Add library for shmem backed GEM objects Noralf Trønnes
  2018-10-17 15:46   ` Daniel Vetter
@ 2018-11-27  0:36   ` Eric Anholt
  2018-11-27  8:58     ` [Intel-gfx] " Daniel Vetter
  1 sibling, 1 reply; 35+ messages in thread
From: Eric Anholt @ 2018-11-27  0:36 UTC (permalink / raw)
  To: Noralf Trønnes, dri-devel; +Cc: intel-gfx, sam, david


[-- Attachment #1.1: Type: text/plain, Size: 693 bytes --]

Noralf Trønnes <noralf@tronnes.org> writes:
> +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
> +{
> +	struct drm_gem_object *obj = vma->vm_private_data;
> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> +
> +	drm_gem_shmem_put_pages(shmem);
> +	drm_gem_vm_close(vma);
> +}
> +
> +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
> +	.fault = drm_gem_shmem_fault,
> +	.open = drm_gem_vm_open,
> +	.close = drm_gem_shmem_vm_close,
> +};
> +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);

I just saw a warning from drm_gem_shmem_put_pages() for
!shmem->pages_use_count -- I think drm_gem_vm_open() needs to
drm_gem_shmem_get_pages().

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Intel-gfx] [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2018-11-27  0:36   ` Eric Anholt
@ 2018-11-27  8:58     ` Daniel Vetter
  2018-11-27 20:38       ` Eric Anholt
  0 siblings, 1 reply; 35+ messages in thread
From: Daniel Vetter @ 2018-11-27  8:58 UTC (permalink / raw)
  To: Eric Anholt; +Cc: intel-gfx, sam, david, dri-devel

On Mon, Nov 26, 2018 at 04:36:21PM -0800, Eric Anholt wrote:
> Noralf Trønnes <noralf@tronnes.org> writes:
> > +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
> > +{
> > +	struct drm_gem_object *obj = vma->vm_private_data;
> > +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> > +
> > +	drm_gem_shmem_put_pages(shmem);
> > +	drm_gem_vm_close(vma);
> > +}
> > +
> > +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
> > +	.fault = drm_gem_shmem_fault,
> > +	.open = drm_gem_vm_open,
> > +	.close = drm_gem_shmem_vm_close,
> > +};
> > +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
> 
> I just saw a warning from drm_gem_shmem_put_pages() for
> !shmem->pages_use_count -- I think drm_gem_vm_open() needs to
> drm_gem_shmem_get_pages().

Yeah we need a drm_gem_shmem_vm_open here.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2018-11-27  8:58     ` [Intel-gfx] " Daniel Vetter
@ 2018-11-27 20:38       ` Eric Anholt
  2018-11-28  8:22         ` [Intel-gfx] " Daniel Vetter
  0 siblings, 1 reply; 35+ messages in thread
From: Eric Anholt @ 2018-11-27 20:38 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, Noralf Trønnes, sam, david, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 993 bytes --]

Daniel Vetter <daniel@ffwll.ch> writes:

> On Mon, Nov 26, 2018 at 04:36:21PM -0800, Eric Anholt wrote:
>> Noralf Trønnes <noralf@tronnes.org> writes:
>> > +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
>> > +{
>> > +	struct drm_gem_object *obj = vma->vm_private_data;
>> > +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
>> > +
>> > +	drm_gem_shmem_put_pages(shmem);
>> > +	drm_gem_vm_close(vma);
>> > +}
>> > +
>> > +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
>> > +	.fault = drm_gem_shmem_fault,
>> > +	.open = drm_gem_vm_open,
>> > +	.close = drm_gem_shmem_vm_close,
>> > +};
>> > +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
>> 
>> I just saw a warning from drm_gem_shmem_put_pages() for
>> !shmem->pages_use_count -- I think drm_gem_vm_open() needs to
>> drm_gem_shmem_get_pages().
>
> Yeah we need a drm_gem_shmem_vm_open here.

Adding one of those fixed my refcounting issues, so I've sent out a v6
with it.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Intel-gfx] [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2018-11-27 20:38       ` Eric Anholt
@ 2018-11-28  8:22         ` Daniel Vetter
  2018-11-28 21:52           ` Eric Anholt
  0 siblings, 1 reply; 35+ messages in thread
From: Daniel Vetter @ 2018-11-28  8:22 UTC (permalink / raw)
  To: Eric Anholt; +Cc: david, intel-gfx, dri-devel, sam

On Tue, Nov 27, 2018 at 12:38:44PM -0800, Eric Anholt wrote:
> Daniel Vetter <daniel@ffwll.ch> writes:
> 
> > On Mon, Nov 26, 2018 at 04:36:21PM -0800, Eric Anholt wrote:
> >> Noralf Trønnes <noralf@tronnes.org> writes:
> >> > +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
> >> > +{
> >> > +	struct drm_gem_object *obj = vma->vm_private_data;
> >> > +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> >> > +
> >> > +	drm_gem_shmem_put_pages(shmem);
> >> > +	drm_gem_vm_close(vma);
> >> > +}
> >> > +
> >> > +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
> >> > +	.fault = drm_gem_shmem_fault,
> >> > +	.open = drm_gem_vm_open,
> >> > +	.close = drm_gem_shmem_vm_close,
> >> > +};
> >> > +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
> >> 
> >> I just saw a warning from drm_gem_shmem_put_pages() for
> >> !shmem->pages_use_count -- I think drm_gem_vm_open() needs to
> >> drm_gem_shmem_get_pages().
> >
> > Yeah we need a drm_gem_shmem_vm_open here.
> 
> Adding one of those fixed my refcounting issues, so I've sent out a v6
> with it.

Just realized that I've reviewed this patch already, spotted that vma
management issue there too. Plus a pile of other things. From reading that
other thread discussion with Noralf concluded with "not yet ready for
prime time" unfortunately :-/
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Intel-gfx] [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2018-11-28  8:22         ` [Intel-gfx] " Daniel Vetter
@ 2018-11-28 21:52           ` Eric Anholt
  2018-11-29  9:17             ` Daniel Vetter
  0 siblings, 1 reply; 35+ messages in thread
From: Eric Anholt @ 2018-11-28 21:52 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: david, intel-gfx, dri-devel, sam


[-- Attachment #1.1: Type: text/plain, Size: 1570 bytes --]

Daniel Vetter <daniel@ffwll.ch> writes:

> On Tue, Nov 27, 2018 at 12:38:44PM -0800, Eric Anholt wrote:
>> Daniel Vetter <daniel@ffwll.ch> writes:
>> 
>> > On Mon, Nov 26, 2018 at 04:36:21PM -0800, Eric Anholt wrote:
>> >> Noralf Trønnes <noralf@tronnes.org> writes:
>> >> > +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
>> >> > +{
>> >> > +	struct drm_gem_object *obj = vma->vm_private_data;
>> >> > +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
>> >> > +
>> >> > +	drm_gem_shmem_put_pages(shmem);
>> >> > +	drm_gem_vm_close(vma);
>> >> > +}
>> >> > +
>> >> > +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
>> >> > +	.fault = drm_gem_shmem_fault,
>> >> > +	.open = drm_gem_vm_open,
>> >> > +	.close = drm_gem_shmem_vm_close,
>> >> > +};
>> >> > +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
>> >> 
>> >> I just saw a warning from drm_gem_shmem_put_pages() for
>> >> !shmem->pages_use_count -- I think drm_gem_vm_open() needs to
>> >> drm_gem_shmem_get_pages().
>> >
>> > Yeah we need a drm_gem_shmem_vm_open here.
>> 
>> Adding one of those fixed my refcounting issues, so I've sent out a v6
>> with it.
>
> Just realized that I've reviewed this patch already, spotted that vma
> management issue there too. Plus a pile of other things. From reading that
> other thread discussion with Noralf concluded with "not yet ready for
> prime time" unfortunately :-/

I saw stuff about how it wasn't usable for SPI because SPI does weird
things with DMA mapping.  Was there something else?

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Intel-gfx] [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2018-11-28 21:52           ` Eric Anholt
@ 2018-11-29  9:17             ` Daniel Vetter
  2018-11-29 23:58               ` Eric Anholt
  0 siblings, 1 reply; 35+ messages in thread
From: Daniel Vetter @ 2018-11-29  9:17 UTC (permalink / raw)
  To: Eric Anholt; +Cc: david, intel-gfx, dri-devel, sam

On Wed, Nov 28, 2018 at 01:52:56PM -0800, Eric Anholt wrote:
> Daniel Vetter <daniel@ffwll.ch> writes:
> 
> > On Tue, Nov 27, 2018 at 12:38:44PM -0800, Eric Anholt wrote:
> >> Daniel Vetter <daniel@ffwll.ch> writes:
> >> 
> >> > On Mon, Nov 26, 2018 at 04:36:21PM -0800, Eric Anholt wrote:
> >> >> Noralf Trønnes <noralf@tronnes.org> writes:
> >> >> > +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
> >> >> > +{
> >> >> > +	struct drm_gem_object *obj = vma->vm_private_data;
> >> >> > +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> >> >> > +
> >> >> > +	drm_gem_shmem_put_pages(shmem);
> >> >> > +	drm_gem_vm_close(vma);
> >> >> > +}
> >> >> > +
> >> >> > +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
> >> >> > +	.fault = drm_gem_shmem_fault,
> >> >> > +	.open = drm_gem_vm_open,
> >> >> > +	.close = drm_gem_shmem_vm_close,
> >> >> > +};
> >> >> > +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
> >> >> 
> >> >> I just saw a warning from drm_gem_shmem_put_pages() for
> >> >> !shmem->pages_use_count -- I think drm_gem_vm_open() needs to
> >> >> drm_gem_shmem_get_pages().
> >> >
> >> > Yeah we need a drm_gem_shmem_vm_open here.
> >> 
> >> Adding one of those fixed my refcounting issues, so I've sent out a v6
> >> with it.
> >
> > Just realized that I've reviewed this patch already, spotted that vma
> > management issue there too. Plus a pile of other things. From reading that
> > other thread discussion with Noralf concluded with "not yet ready for
> > prime time" unfortunately :-/
> 
> I saw stuff about how it wasn't usable for SPI because SPI does weird
> things with DMA mapping.  Was there something else?

Looking through that mail it was a bunch of comments to improve the
kerneldoc. Plus a note that buffer sharing/mmap is going to be all
incoherent and horrible (but I guess for vkms we don't care that much).
I'm just kinda vary of generic buffer handling that turns out to not be
actually all that useful. We have lots of deadends and kinda-midlayers in
this area already (but this one here definitely smells plenty better than
lots of older ones).
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2018-11-29  9:17             ` Daniel Vetter
@ 2018-11-29 23:58               ` Eric Anholt
  2018-12-02 15:58                 ` Noralf Trønnes
  0 siblings, 1 reply; 35+ messages in thread
From: Eric Anholt @ 2018-11-29 23:58 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: david, intel-gfx, dri-devel, Noralf Trønnes, sam


[-- Attachment #1.1: Type: text/plain, Size: 2421 bytes --]

Daniel Vetter <daniel@ffwll.ch> writes:

> On Wed, Nov 28, 2018 at 01:52:56PM -0800, Eric Anholt wrote:
>> Daniel Vetter <daniel@ffwll.ch> writes:
>> 
>> > On Tue, Nov 27, 2018 at 12:38:44PM -0800, Eric Anholt wrote:
>> >> Daniel Vetter <daniel@ffwll.ch> writes:
>> >> 
>> >> > On Mon, Nov 26, 2018 at 04:36:21PM -0800, Eric Anholt wrote:
>> >> >> Noralf Trønnes <noralf@tronnes.org> writes:
>> >> >> > +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
>> >> >> > +{
>> >> >> > +	struct drm_gem_object *obj = vma->vm_private_data;
>> >> >> > +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
>> >> >> > +
>> >> >> > +	drm_gem_shmem_put_pages(shmem);
>> >> >> > +	drm_gem_vm_close(vma);
>> >> >> > +}
>> >> >> > +
>> >> >> > +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
>> >> >> > +	.fault = drm_gem_shmem_fault,
>> >> >> > +	.open = drm_gem_vm_open,
>> >> >> > +	.close = drm_gem_shmem_vm_close,
>> >> >> > +};
>> >> >> > +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
>> >> >> 
>> >> >> I just saw a warning from drm_gem_shmem_put_pages() for
>> >> >> !shmem->pages_use_count -- I think drm_gem_vm_open() needs to
>> >> >> drm_gem_shmem_get_pages().
>> >> >
>> >> > Yeah we need a drm_gem_shmem_vm_open here.
>> >> 
>> >> Adding one of those fixed my refcounting issues, so I've sent out a v6
>> >> with it.
>> >
>> > Just realized that I've reviewed this patch already, spotted that vma
>> > management issue there too. Plus a pile of other things. From reading that
>> > other thread discussion with Noralf concluded with "not yet ready for
>> > prime time" unfortunately :-/
>> 
>> I saw stuff about how it wasn't usable for SPI because SPI does weird
>> things with DMA mapping.  Was there something else?
>
> Looking through that mail it was a bunch of comments to improve the
> kerneldoc. Plus a note that buffer sharing/mmap is going to be all
> incoherent and horrible (but I guess for vkms we don't care that much).
> I'm just kinda vary of generic buffer handling that turns out to not be
> actually all that useful. We have lots of deadends and kinda-midlayers in
> this area already (but this one here definitely smells plenty better than
> lots of older ones).

FWIW, I really want shmem helpers for v3d.  The fault handling in
particular has magic I don't understand, and this is not my first fault
handler. :/

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2018-11-29 23:58               ` Eric Anholt
@ 2018-12-02 15:58                 ` Noralf Trønnes
  2019-01-28 20:57                   ` [Intel-gfx] " Rob Herring
  0 siblings, 1 reply; 35+ messages in thread
From: Noralf Trønnes @ 2018-12-02 15:58 UTC (permalink / raw)
  To: Eric Anholt, Daniel Vetter; +Cc: intel-gfx, sam, david, dri-devel


Den 30.11.2018 00.58, skrev Eric Anholt:
> Daniel Vetter <daniel@ffwll.ch> writes:
>
>> On Wed, Nov 28, 2018 at 01:52:56PM -0800, Eric Anholt wrote:
>>> Daniel Vetter <daniel@ffwll.ch> writes:
>>>
>>>> On Tue, Nov 27, 2018 at 12:38:44PM -0800, Eric Anholt wrote:
>>>>> Daniel Vetter <daniel@ffwll.ch> writes:
>>>>>
>>>>>> On Mon, Nov 26, 2018 at 04:36:21PM -0800, Eric Anholt wrote:
>>>>>>> Noralf Trønnes <noralf@tronnes.org> writes:
>>>>>>>> +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
>>>>>>>> +{
>>>>>>>> +	struct drm_gem_object *obj = vma->vm_private_data;
>>>>>>>> +	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
>>>>>>>> +
>>>>>>>> +	drm_gem_shmem_put_pages(shmem);
>>>>>>>> +	drm_gem_vm_close(vma);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
>>>>>>>> +	.fault = drm_gem_shmem_fault,
>>>>>>>> +	.open = drm_gem_vm_open,
>>>>>>>> +	.close = drm_gem_shmem_vm_close,
>>>>>>>> +};
>>>>>>>> +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
>>>>>>> I just saw a warning from drm_gem_shmem_put_pages() for
>>>>>>> !shmem->pages_use_count -- I think drm_gem_vm_open() needs to
>>>>>>> drm_gem_shmem_get_pages().
>>>>>> Yeah we need a drm_gem_shmem_vm_open here.
>>>>> Adding one of those fixed my refcounting issues, so I've sent out a v6
>>>>> with it.
>>>> Just realized that I've reviewed this patch already, spotted that vma
>>>> management issue there too. Plus a pile of other things. From reading that
>>>> other thread discussion with Noralf concluded with "not yet ready for
>>>> prime time" unfortunately :-/
>>> I saw stuff about how it wasn't usable for SPI because SPI does weird
>>> things with DMA mapping.  Was there something else?
>> Looking through that mail it was a bunch of comments to improve the
>> kerneldoc. Plus a note that buffer sharing/mmap is going to be all
>> incoherent and horrible (but I guess for vkms we don't care that much).
>> I'm just kinda vary of generic buffer handling that turns out to not be
>> actually all that useful. We have lots of deadends and kinda-midlayers in
>> this area already (but this one here definitely smells plenty better than
>> lots of older ones).
> FWIW, I really want shmem helpers for v3d.  The fault handling in
> particular has magic I don't understand, and this is not my first fault
> handler. :/


If you can use it for a "real" hw driver like v3d, I think it makes a lot
sense to have it as a helper. I believe udl and a future simpledrm can
also make use of it.

I have an idea about a usb driver that I hope to work on somewhere down
the line that will need this kind of code. So my plan was to resurrect
this code when I got there.

I agree that fault handling looks a bit like magic. I looked at all the
drivers that uses shmem buffers to see what they where doing. When Daniel
put me on the right track with the fake offsets, the fault handler ended
up being quite small.

Having a helper like this that can actually be used for real hw drivers
(if it can, that is), increases the chance of getting this -mm stuff
right. And hopefully someone down the line having domain knowledge can
audit this code. It's less likely that this will happen with code tucked
away in a driver, especially the smaller ones.

Initially I hoped that I could make the helper compatible with vgem, so I
could convert vgem to use this helper. That would give the helper a lot
of testing, making it and keeping it solid. However vgem can get pages
one by one in the fault handler if all pages hasn't been fetched. I
didn't see an easy way to handle that together with page use counting.
The main reason for having page counting was to make it easy to bolt on a
shrinker, but I have no experience nor any knowledge about that, so I
don't know if it can be easily done.

Noralf.

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Intel-gfx] [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2018-12-02 15:58                 ` Noralf Trønnes
@ 2019-01-28 20:57                   ` Rob Herring
  2019-01-28 21:22                     ` Noralf Trønnes
  0 siblings, 1 reply; 35+ messages in thread
From: Rob Herring @ 2019-01-28 20:57 UTC (permalink / raw)
  To: Noralf Trønnes
  Cc: David Lechner, Tomeu Vizoso, intel-gfx, dri-devel, Sam Ravnborg

On Sun, Dec 2, 2018 at 9:59 AM Noralf Trønnes <noralf@tronnes.org> wrote:
>
>
> Den 30.11.2018 00.58, skrev Eric Anholt:
> > Daniel Vetter <daniel@ffwll.ch> writes:
> >
> >> On Wed, Nov 28, 2018 at 01:52:56PM -0800, Eric Anholt wrote:
> >>> Daniel Vetter <daniel@ffwll.ch> writes:
> >>>
> >>>> On Tue, Nov 27, 2018 at 12:38:44PM -0800, Eric Anholt wrote:
> >>>>> Daniel Vetter <daniel@ffwll.ch> writes:
> >>>>>
> >>>>>> On Mon, Nov 26, 2018 at 04:36:21PM -0800, Eric Anholt wrote:
> >>>>>>> Noralf Trønnes <noralf@tronnes.org> writes:
> >>>>>>>> +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
> >>>>>>>> +{
> >>>>>>>> +      struct drm_gem_object *obj = vma->vm_private_data;
> >>>>>>>> +      struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> >>>>>>>> +
> >>>>>>>> +      drm_gem_shmem_put_pages(shmem);
> >>>>>>>> +      drm_gem_vm_close(vma);
> >>>>>>>> +}
> >>>>>>>> +
> >>>>>>>> +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
> >>>>>>>> +      .fault = drm_gem_shmem_fault,
> >>>>>>>> +      .open = drm_gem_vm_open,
> >>>>>>>> +      .close = drm_gem_shmem_vm_close,
> >>>>>>>> +};
> >>>>>>>> +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
> >>>>>>> I just saw a warning from drm_gem_shmem_put_pages() for
> >>>>>>> !shmem->pages_use_count -- I think drm_gem_vm_open() needs to
> >>>>>>> drm_gem_shmem_get_pages().
> >>>>>> Yeah we need a drm_gem_shmem_vm_open here.
> >>>>> Adding one of those fixed my refcounting issues, so I've sent out a v6
> >>>>> with it.
> >>>> Just realized that I've reviewed this patch already, spotted that vma
> >>>> management issue there too. Plus a pile of other things. From reading that
> >>>> other thread discussion with Noralf concluded with "not yet ready for
> >>>> prime time" unfortunately :-/
> >>> I saw stuff about how it wasn't usable for SPI because SPI does weird
> >>> things with DMA mapping.  Was there something else?
> >> Looking through that mail it was a bunch of comments to improve the
> >> kerneldoc. Plus a note that buffer sharing/mmap is going to be all
> >> incoherent and horrible (but I guess for vkms we don't care that much).
> >> I'm just kinda vary of generic buffer handling that turns out to not be
> >> actually all that useful. We have lots of deadends and kinda-midlayers in
> >> this area already (but this one here definitely smells plenty better than
> >> lots of older ones).
> > FWIW, I really want shmem helpers for v3d.  The fault handling in
> > particular has magic I don't understand, and this is not my first fault
> > handler. :/
>
>
> If you can use it for a "real" hw driver like v3d, I think it makes a lot
> sense to have it as a helper. I believe udl and a future simpledrm can
> also make use of it.

FWIW, I think etnaviv at least could use this too.

I'm starting to look at panfrost and lima drivers and was trying to
figure out where to start with the GEM code. So I've been comparing
etnaviv, freedreno, and vgem implementations. They are all pretty
similar from what I see. The per driver GEM obj structs certainly are.
I can't bring myself to just copy etnaviv code over and do a
s/etnaviv/panfrost/. So searching around a bit, I ended up on this
thread. This seems to be what I need for panfrost (based on my brief
study).

Rob
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Intel-gfx] [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2019-01-28 20:57                   ` [Intel-gfx] " Rob Herring
@ 2019-01-28 21:22                     ` Noralf Trønnes
  2019-01-28 22:01                       ` Rob Herring
  2019-01-29  0:19                       ` Eric Anholt
  0 siblings, 2 replies; 35+ messages in thread
From: Noralf Trønnes @ 2019-01-28 21:22 UTC (permalink / raw)
  To: Rob Herring
  Cc: David Lechner, Tomeu Vizoso, intel-gfx, dri-devel, Sam Ravnborg



Den 28.01.2019 21.57, skrev Rob Herring:
> On Sun, Dec 2, 2018 at 9:59 AM Noralf Trønnes <noralf@tronnes.org> wrote:
>>
>>
>> Den 30.11.2018 00.58, skrev Eric Anholt:
>>> Daniel Vetter <daniel@ffwll.ch> writes:
>>>
>>>> On Wed, Nov 28, 2018 at 01:52:56PM -0800, Eric Anholt wrote:
>>>>> Daniel Vetter <daniel@ffwll.ch> writes:
>>>>>
>>>>>> On Tue, Nov 27, 2018 at 12:38:44PM -0800, Eric Anholt wrote:
>>>>>>> Daniel Vetter <daniel@ffwll.ch> writes:
>>>>>>>
>>>>>>>> On Mon, Nov 26, 2018 at 04:36:21PM -0800, Eric Anholt wrote:
>>>>>>>>> Noralf Trønnes <noralf@tronnes.org> writes:
>>>>>>>>>> +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
>>>>>>>>>> +{
>>>>>>>>>> +      struct drm_gem_object *obj = vma->vm_private_data;
>>>>>>>>>> +      struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
>>>>>>>>>> +
>>>>>>>>>> +      drm_gem_shmem_put_pages(shmem);
>>>>>>>>>> +      drm_gem_vm_close(vma);
>>>>>>>>>> +}
>>>>>>>>>> +
>>>>>>>>>> +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
>>>>>>>>>> +      .fault = drm_gem_shmem_fault,
>>>>>>>>>> +      .open = drm_gem_vm_open,
>>>>>>>>>> +      .close = drm_gem_shmem_vm_close,
>>>>>>>>>> +};
>>>>>>>>>> +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
>>>>>>>>> I just saw a warning from drm_gem_shmem_put_pages() for
>>>>>>>>> !shmem->pages_use_count -- I think drm_gem_vm_open() needs to
>>>>>>>>> drm_gem_shmem_get_pages().
>>>>>>>> Yeah we need a drm_gem_shmem_vm_open here.
>>>>>>> Adding one of those fixed my refcounting issues, so I've sent out a v6
>>>>>>> with it.
>>>>>> Just realized that I've reviewed this patch already, spotted that vma
>>>>>> management issue there too. Plus a pile of other things. From reading that
>>>>>> other thread discussion with Noralf concluded with "not yet ready for
>>>>>> prime time" unfortunately :-/
>>>>> I saw stuff about how it wasn't usable for SPI because SPI does weird
>>>>> things with DMA mapping.  Was there something else?
>>>> Looking through that mail it was a bunch of comments to improve the
>>>> kerneldoc. Plus a note that buffer sharing/mmap is going to be all
>>>> incoherent and horrible (but I guess for vkms we don't care that much).
>>>> I'm just kinda vary of generic buffer handling that turns out to not be
>>>> actually all that useful. We have lots of deadends and kinda-midlayers in
>>>> this area already (but this one here definitely smells plenty better than
>>>> lots of older ones).
>>> FWIW, I really want shmem helpers for v3d.  The fault handling in
>>> particular has magic I don't understand, and this is not my first fault
>>> handler. :/
>>
>>
>> If you can use it for a "real" hw driver like v3d, I think it makes a lot
>> sense to have it as a helper. I believe udl and a future simpledrm can
>> also make use of it.
> 
> FWIW, I think etnaviv at least could use this too.
> 
> I'm starting to look at panfrost and lima drivers and was trying to
> figure out where to start with the GEM code. So I've been comparing
> etnaviv, freedreno, and vgem implementations. They are all pretty
> similar from what I see. The per driver GEM obj structs certainly are.
> I can't bring myself to just copy etnaviv code over and do a
> s/etnaviv/panfrost/. So searching around a bit, I ended up on this
> thread. This seems to be what I need for panfrost (based on my brief
> study).
> 

I gave up on this due to problems with SPI DMA.
Eric tried to use it with vkms, but it failed. On his blog he speculates
that it might be due to cached CPU mappings:
https://anholt.github.io/twivc4/2018/12/03/twiv/

For tinydrm I wanted cached mappings, but it might not work that well
with shmem. Maybe that's why I had problems with SPI DMA.

Maybe this change to drm_gem_shmem_mmap() is all it takes:

-	vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+	vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));

The memory subsystem is really complicated and I have kind of given up
on trying to decipher it.

Noralf.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2019-01-28 21:22                     ` Noralf Trønnes
@ 2019-01-28 22:01                       ` Rob Herring
  2019-01-29  0:19                       ` Eric Anholt
  1 sibling, 0 replies; 35+ messages in thread
From: Rob Herring @ 2019-01-28 22:01 UTC (permalink / raw)
  To: Noralf Trønnes
  Cc: David Lechner, Tomeu Vizoso, intel-gfx, dri-devel, Sam Ravnborg

On Mon, Jan 28, 2019 at 3:26 PM Noralf Trønnes <noralf@tronnes.org> wrote:
>
>
>
> Den 28.01.2019 21.57, skrev Rob Herring:
> > On Sun, Dec 2, 2018 at 9:59 AM Noralf Trønnes <noralf@tronnes.org> wrote:
> >>
> >>
> >> Den 30.11.2018 00.58, skrev Eric Anholt:
> >>> Daniel Vetter <daniel@ffwll.ch> writes:
> >>>
> >>>> On Wed, Nov 28, 2018 at 01:52:56PM -0800, Eric Anholt wrote:
> >>>>> Daniel Vetter <daniel@ffwll.ch> writes:
> >>>>>
> >>>>>> On Tue, Nov 27, 2018 at 12:38:44PM -0800, Eric Anholt wrote:
> >>>>>>> Daniel Vetter <daniel@ffwll.ch> writes:
> >>>>>>>
> >>>>>>>> On Mon, Nov 26, 2018 at 04:36:21PM -0800, Eric Anholt wrote:
> >>>>>>>>> Noralf Trønnes <noralf@tronnes.org> writes:
> >>>>>>>>>> +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
> >>>>>>>>>> +{
> >>>>>>>>>> +      struct drm_gem_object *obj = vma->vm_private_data;
> >>>>>>>>>> +      struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
> >>>>>>>>>> +
> >>>>>>>>>> +      drm_gem_shmem_put_pages(shmem);
> >>>>>>>>>> +      drm_gem_vm_close(vma);
> >>>>>>>>>> +}
> >>>>>>>>>> +
> >>>>>>>>>> +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
> >>>>>>>>>> +      .fault = drm_gem_shmem_fault,
> >>>>>>>>>> +      .open = drm_gem_vm_open,
> >>>>>>>>>> +      .close = drm_gem_shmem_vm_close,
> >>>>>>>>>> +};
> >>>>>>>>>> +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
> >>>>>>>>> I just saw a warning from drm_gem_shmem_put_pages() for
> >>>>>>>>> !shmem->pages_use_count -- I think drm_gem_vm_open() needs to
> >>>>>>>>> drm_gem_shmem_get_pages().
> >>>>>>>> Yeah we need a drm_gem_shmem_vm_open here.
> >>>>>>> Adding one of those fixed my refcounting issues, so I've sent out a v6
> >>>>>>> with it.
> >>>>>> Just realized that I've reviewed this patch already, spotted that vma
> >>>>>> management issue there too. Plus a pile of other things. From reading that
> >>>>>> other thread discussion with Noralf concluded with "not yet ready for
> >>>>>> prime time" unfortunately :-/
> >>>>> I saw stuff about how it wasn't usable for SPI because SPI does weird
> >>>>> things with DMA mapping.  Was there something else?
> >>>> Looking through that mail it was a bunch of comments to improve the
> >>>> kerneldoc. Plus a note that buffer sharing/mmap is going to be all
> >>>> incoherent and horrible (but I guess for vkms we don't care that much).
> >>>> I'm just kinda vary of generic buffer handling that turns out to not be
> >>>> actually all that useful. We have lots of deadends and kinda-midlayers in
> >>>> this area already (but this one here definitely smells plenty better than
> >>>> lots of older ones).
> >>> FWIW, I really want shmem helpers for v3d.  The fault handling in
> >>> particular has magic I don't understand, and this is not my first fault
> >>> handler. :/
> >>
> >>
> >> If you can use it for a "real" hw driver like v3d, I think it makes a lot
> >> sense to have it as a helper. I believe udl and a future simpledrm can
> >> also make use of it.
> >
> > FWIW, I think etnaviv at least could use this too.
> >
> > I'm starting to look at panfrost and lima drivers and was trying to
> > figure out where to start with the GEM code. So I've been comparing
> > etnaviv, freedreno, and vgem implementations. They are all pretty
> > similar from what I see. The per driver GEM obj structs certainly are.
> > I can't bring myself to just copy etnaviv code over and do a
> > s/etnaviv/panfrost/. So searching around a bit, I ended up on this
> > thread. This seems to be what I need for panfrost (based on my brief
> > study).
> >
>
> I gave up on this due to problems with SPI DMA.
> Eric tried to use it with vkms, but it failed. On his blog he speculates
> that it might be due to cached CPU mappings:
> https://anholt.github.io/twivc4/2018/12/03/twiv/
>
> For tinydrm I wanted cached mappings, but it might not work that well
> with shmem. Maybe that's why I had problems with SPI DMA.

I think for most ARM systems, a cached mapping is not coherent. So
there will need to be cache flushes using the dma API. I see there's
been some discussion around that too.

> Maybe this change to drm_gem_shmem_mmap() is all it takes:
>
> -       vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
> +       vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));

Seems like at least this part needs some flexibility. etnaviv,
freedreno, and omap at least all appear to support cached, uncached,
and writecombined based on flags in the GEM object.

> The memory subsystem is really complicated and I have kind of given up
> on trying to decipher it.

Yes. All the more reason to not let each driver figure out what to do.

Rob
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2019-01-28 21:22                     ` Noralf Trønnes
  2019-01-28 22:01                       ` Rob Herring
@ 2019-01-29  0:19                       ` Eric Anholt
  2019-01-29  8:44                         ` [Intel-gfx] " Noralf Trønnes
  1 sibling, 1 reply; 35+ messages in thread
From: Eric Anholt @ 2019-01-29  0:19 UTC (permalink / raw)
  To: Noralf Trønnes, Rob Herring
  Cc: David Lechner, Tomeu Vizoso, intel-gfx, dri-devel, Sam Ravnborg


[-- Attachment #1.1: Type: text/plain, Size: 4095 bytes --]

Noralf Trønnes <noralf@tronnes.org> writes:

> Den 28.01.2019 21.57, skrev Rob Herring:
>> On Sun, Dec 2, 2018 at 9:59 AM Noralf Trønnes <noralf@tronnes.org> wrote:
>>>
>>>
>>> Den 30.11.2018 00.58, skrev Eric Anholt:
>>>> Daniel Vetter <daniel@ffwll.ch> writes:
>>>>
>>>>> On Wed, Nov 28, 2018 at 01:52:56PM -0800, Eric Anholt wrote:
>>>>>> Daniel Vetter <daniel@ffwll.ch> writes:
>>>>>>
>>>>>>> On Tue, Nov 27, 2018 at 12:38:44PM -0800, Eric Anholt wrote:
>>>>>>>> Daniel Vetter <daniel@ffwll.ch> writes:
>>>>>>>>
>>>>>>>>> On Mon, Nov 26, 2018 at 04:36:21PM -0800, Eric Anholt wrote:
>>>>>>>>>> Noralf Trønnes <noralf@tronnes.org> writes:
>>>>>>>>>>> +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
>>>>>>>>>>> +{
>>>>>>>>>>> +      struct drm_gem_object *obj = vma->vm_private_data;
>>>>>>>>>>> +      struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
>>>>>>>>>>> +
>>>>>>>>>>> +      drm_gem_shmem_put_pages(shmem);
>>>>>>>>>>> +      drm_gem_vm_close(vma);
>>>>>>>>>>> +}
>>>>>>>>>>> +
>>>>>>>>>>> +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
>>>>>>>>>>> +      .fault = drm_gem_shmem_fault,
>>>>>>>>>>> +      .open = drm_gem_vm_open,
>>>>>>>>>>> +      .close = drm_gem_shmem_vm_close,
>>>>>>>>>>> +};
>>>>>>>>>>> +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
>>>>>>>>>> I just saw a warning from drm_gem_shmem_put_pages() for
>>>>>>>>>> !shmem->pages_use_count -- I think drm_gem_vm_open() needs to
>>>>>>>>>> drm_gem_shmem_get_pages().
>>>>>>>>> Yeah we need a drm_gem_shmem_vm_open here.
>>>>>>>> Adding one of those fixed my refcounting issues, so I've sent out a v6
>>>>>>>> with it.
>>>>>>> Just realized that I've reviewed this patch already, spotted that vma
>>>>>>> management issue there too. Plus a pile of other things. From reading that
>>>>>>> other thread discussion with Noralf concluded with "not yet ready for
>>>>>>> prime time" unfortunately :-/
>>>>>> I saw stuff about how it wasn't usable for SPI because SPI does weird
>>>>>> things with DMA mapping.  Was there something else?
>>>>> Looking through that mail it was a bunch of comments to improve the
>>>>> kerneldoc. Plus a note that buffer sharing/mmap is going to be all
>>>>> incoherent and horrible (but I guess for vkms we don't care that much).
>>>>> I'm just kinda vary of generic buffer handling that turns out to not be
>>>>> actually all that useful. We have lots of deadends and kinda-midlayers in
>>>>> this area already (but this one here definitely smells plenty better than
>>>>> lots of older ones).
>>>> FWIW, I really want shmem helpers for v3d.  The fault handling in
>>>> particular has magic I don't understand, and this is not my first fault
>>>> handler. :/
>>>
>>>
>>> If you can use it for a "real" hw driver like v3d, I think it makes a lot
>>> sense to have it as a helper. I believe udl and a future simpledrm can
>>> also make use of it.
>> 
>> FWIW, I think etnaviv at least could use this too.
>> 
>> I'm starting to look at panfrost and lima drivers and was trying to
>> figure out where to start with the GEM code. So I've been comparing
>> etnaviv, freedreno, and vgem implementations. They are all pretty
>> similar from what I see. The per driver GEM obj structs certainly are.
>> I can't bring myself to just copy etnaviv code over and do a
>> s/etnaviv/panfrost/. So searching around a bit, I ended up on this
>> thread. This seems to be what I need for panfrost (based on my brief
>> study).
>> 
>
> I gave up on this due to problems with SPI DMA.
> Eric tried to use it with vkms, but it failed. On his blog he speculates
> that it might be due to cached CPU mappings:
> https://anholt.github.io/twivc4/2018/12/03/twiv/
>
> For tinydrm I wanted cached mappings, but it might not work that well
> with shmem. Maybe that's why I had problems with SPI DMA.

Actually, for tinydrm buffers that are dma-buf exported through prime, I
really want tinydrm using WC mappings so that vc4 or v3d rendering (now
supported on Mesa master with kmsro) works.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Intel-gfx] [PATCH v5 4/5] drm: Add library for shmem backed GEM objects
  2019-01-29  0:19                       ` Eric Anholt
@ 2019-01-29  8:44                         ` Noralf Trønnes
  0 siblings, 0 replies; 35+ messages in thread
From: Noralf Trønnes @ 2019-01-29  8:44 UTC (permalink / raw)
  To: Eric Anholt, Rob Herring
  Cc: David Lechner, Tomeu Vizoso, intel-gfx, dri-devel, Sam Ravnborg



Den 29.01.2019 01.19, skrev Eric Anholt:
> Noralf Trønnes <noralf@tronnes.org> writes:
> 
>> Den 28.01.2019 21.57, skrev Rob Herring:
>>> On Sun, Dec 2, 2018 at 9:59 AM Noralf Trønnes <noralf@tronnes.org> wrote:
>>>>
>>>>
>>>> Den 30.11.2018 00.58, skrev Eric Anholt:
>>>>> Daniel Vetter <daniel@ffwll.ch> writes:
>>>>>
>>>>>> On Wed, Nov 28, 2018 at 01:52:56PM -0800, Eric Anholt wrote:
>>>>>>> Daniel Vetter <daniel@ffwll.ch> writes:
>>>>>>>
>>>>>>>> On Tue, Nov 27, 2018 at 12:38:44PM -0800, Eric Anholt wrote:
>>>>>>>>> Daniel Vetter <daniel@ffwll.ch> writes:
>>>>>>>>>
>>>>>>>>>> On Mon, Nov 26, 2018 at 04:36:21PM -0800, Eric Anholt wrote:
>>>>>>>>>>> Noralf Trønnes <noralf@tronnes.org> writes:
>>>>>>>>>>>> +static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
>>>>>>>>>>>> +{
>>>>>>>>>>>> +      struct drm_gem_object *obj = vma->vm_private_data;
>>>>>>>>>>>> +      struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
>>>>>>>>>>>> +
>>>>>>>>>>>> +      drm_gem_shmem_put_pages(shmem);
>>>>>>>>>>>> +      drm_gem_vm_close(vma);
>>>>>>>>>>>> +}
>>>>>>>>>>>> +
>>>>>>>>>>>> +const struct vm_operations_struct drm_gem_shmem_vm_ops = {
>>>>>>>>>>>> +      .fault = drm_gem_shmem_fault,
>>>>>>>>>>>> +      .open = drm_gem_vm_open,
>>>>>>>>>>>> +      .close = drm_gem_shmem_vm_close,
>>>>>>>>>>>> +};
>>>>>>>>>>>> +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops);
>>>>>>>>>>> I just saw a warning from drm_gem_shmem_put_pages() for
>>>>>>>>>>> !shmem->pages_use_count -- I think drm_gem_vm_open() needs to
>>>>>>>>>>> drm_gem_shmem_get_pages().
>>>>>>>>>> Yeah we need a drm_gem_shmem_vm_open here.
>>>>>>>>> Adding one of those fixed my refcounting issues, so I've sent out a v6
>>>>>>>>> with it.
>>>>>>>> Just realized that I've reviewed this patch already, spotted that vma
>>>>>>>> management issue there too. Plus a pile of other things. From reading that
>>>>>>>> other thread discussion with Noralf concluded with "not yet ready for
>>>>>>>> prime time" unfortunately :-/
>>>>>>> I saw stuff about how it wasn't usable for SPI because SPI does weird
>>>>>>> things with DMA mapping.  Was there something else?
>>>>>> Looking through that mail it was a bunch of comments to improve the
>>>>>> kerneldoc. Plus a note that buffer sharing/mmap is going to be all
>>>>>> incoherent and horrible (but I guess for vkms we don't care that much).
>>>>>> I'm just kinda vary of generic buffer handling that turns out to not be
>>>>>> actually all that useful. We have lots of deadends and kinda-midlayers in
>>>>>> this area already (but this one here definitely smells plenty better than
>>>>>> lots of older ones).
>>>>> FWIW, I really want shmem helpers for v3d.  The fault handling in
>>>>> particular has magic I don't understand, and this is not my first fault
>>>>> handler. :/
>>>>
>>>>
>>>> If you can use it for a "real" hw driver like v3d, I think it makes a lot
>>>> sense to have it as a helper. I believe udl and a future simpledrm can
>>>> also make use of it.
>>>
>>> FWIW, I think etnaviv at least could use this too.
>>>
>>> I'm starting to look at panfrost and lima drivers and was trying to
>>> figure out where to start with the GEM code. So I've been comparing
>>> etnaviv, freedreno, and vgem implementations. They are all pretty
>>> similar from what I see. The per driver GEM obj structs certainly are.
>>> I can't bring myself to just copy etnaviv code over and do a
>>> s/etnaviv/panfrost/. So searching around a bit, I ended up on this
>>> thread. This seems to be what I need for panfrost (based on my brief
>>> study).
>>>
>>
>> I gave up on this due to problems with SPI DMA.
>> Eric tried to use it with vkms, but it failed. On his blog he speculates
>> that it might be due to cached CPU mappings:
>> https://anholt.github.io/twivc4/2018/12/03/twiv/
>>
>> For tinydrm I wanted cached mappings, but it might not work that well
>> with shmem. Maybe that's why I had problems with SPI DMA.
> 
> Actually, for tinydrm buffers that are dma-buf exported through prime, I
> really want tinydrm using WC mappings so that vc4 or v3d rendering (now
> supported on Mesa master with kmsro) works.
> 

I thought that the buffer is created by the GPU driver when using PRIME?
And them imported into the tinydrm driver. In which case it doesn't
matter how tinydrm creates it's dumb buffers.

That said, I will stay with CMA buffers for the SPI drivers. It just
works. The reason I looked into shmem, is that tindyrm would then be
able to import buffers that isn't contiguous in memory, thus making it
work with more GPU's. And the reason for cached buffers is that with
partial flushing the rectangle is copied to a separate buffer for
transfer and CPU acccess to WC memory is quite slow. But ofc for these
small buffers it's not that big a deal.

Noralf.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2019-01-29  8:44 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-17 13:04 [PATCH v5 0/5] drm: Add shmem GEM library Noralf Trønnes
2018-10-17 13:04 ` [PATCH v5 1/5] drm/driver: Add defaults for .gem_prime_export/import callbacks Noralf Trønnes
2018-10-17 13:04 ` [PATCH v5 2/5] drm/prime: Add drm_gem_prime_mmap() Noralf Trønnes
2018-10-17 15:22   ` Daniel Vetter
2018-10-17 13:04 ` [PATCH v5 3/5] drm/gem: Add drm_gem_object_funcs Noralf Trønnes
2018-10-22 12:57   ` Christian König
2018-10-23 13:46     ` Daniel Vetter
2018-10-31 23:37   ` Noralf Trønnes
2018-11-01  8:36     ` [Intel-gfx] " Daniel Vetter
2018-10-17 13:04 ` [PATCH v5 4/5] drm: Add library for shmem backed GEM objects Noralf Trønnes
2018-10-17 15:46   ` Daniel Vetter
2018-10-22 14:15     ` Noralf Trønnes
2018-10-23 13:50       ` Daniel Vetter
2018-11-27  0:36   ` Eric Anholt
2018-11-27  8:58     ` [Intel-gfx] " Daniel Vetter
2018-11-27 20:38       ` Eric Anholt
2018-11-28  8:22         ` [Intel-gfx] " Daniel Vetter
2018-11-28 21:52           ` Eric Anholt
2018-11-29  9:17             ` Daniel Vetter
2018-11-29 23:58               ` Eric Anholt
2018-12-02 15:58                 ` Noralf Trønnes
2019-01-28 20:57                   ` [Intel-gfx] " Rob Herring
2019-01-28 21:22                     ` Noralf Trønnes
2019-01-28 22:01                       ` Rob Herring
2019-01-29  0:19                       ` Eric Anholt
2019-01-29  8:44                         ` [Intel-gfx] " Noralf Trønnes
2018-10-17 13:04 ` [PATCH v5 5/5] drm/tinydrm: Switch from CMA to shmem buffers Noralf Trønnes
2018-10-26 22:38   ` Noralf Trønnes
2018-10-28 20:21     ` David Lechner
2018-10-28 20:46       ` Noralf Trønnes
2018-10-29  9:07         ` Daniel Vetter
2018-10-31 18:41           ` Noralf Trønnes
2018-10-17 13:43 ` ✗ Fi.CI.CHECKPATCH: warning for drm: Add shmem GEM library Patchwork
2018-10-17 14:02 ` ✓ Fi.CI.BAT: success " Patchwork
2018-10-17 17:37 ` ✓ Fi.CI.IGT: " Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.