drm/gem: Provide drm_gem_fb_{begin,end}_cpu_access() helpers
authorThomas Zimmermann <tzimmermann@suse.de>
Fri, 16 Jul 2021 14:07:55 +0000 (16:07 +0200)
committerThomas Zimmermann <tzimmermann@suse.de>
Fri, 23 Jul 2021 18:17:13 +0000 (20:17 +0200)
Implement helpers drm_gem_fb_begin_cpu_access() and _end_cpu_access(),
which call the rsp dma-buf functions for all GEM BOs of the given
framebuffer.

Calls to dma_buf_end_cpu_access() can return an error code on failure,
while drm_gem_fb_end_cpu_access() does not. The latter runs during DRM's
atomic commit or during cleanup. Both cases don't allow for errors, so
leave out the return value.

v2:
* fix typo in docs (Daniel)

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210716140801.1215-2-tzimmermann@suse.de
drivers/gpu/drm/drm_gem_framebuffer_helper.c
include/drm/drm_gem_framebuffer_helper.h

index e2c6882..67bc9ed 100644 (file)
@@ -306,6 +306,95 @@ drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file,
 }
 EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty);
 
+/**
+ * drm_gem_fb_begin_cpu_access - prepares GEM buffer objects for CPU access
+ * @fb: the framebuffer
+ * @dir: access mode
+ *
+ * Prepares a framebuffer's GEM buffer objects for CPU access. This function
+ * must be called before accessing the BO data within the kernel. For imported
+ * BOs, the function calls dma_buf_begin_cpu_access().
+ *
+ * See drm_gem_fb_end_cpu_access() for signalling the end of CPU access.
+ *
+ * Returns:
+ * 0 on success, or a negative errno code otherwise.
+ */
+int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir)
+{
+       struct dma_buf_attachment *import_attach;
+       struct drm_gem_object *obj;
+       size_t i;
+       int ret, ret2;
+
+       for (i = 0; i < ARRAY_SIZE(fb->obj); ++i) {
+               obj = drm_gem_fb_get_obj(fb, i);
+               if (!obj)
+                       continue;
+               import_attach = obj->import_attach;
+               if (!import_attach)
+                       continue;
+               ret = dma_buf_begin_cpu_access(import_attach->dmabuf, dir);
+               if (ret)
+                       goto err_dma_buf_end_cpu_access;
+       }
+
+       return 0;
+
+err_dma_buf_end_cpu_access:
+       while (i) {
+               --i;
+               obj = drm_gem_fb_get_obj(fb, i);
+               if (!obj)
+                       continue;
+               import_attach = obj->import_attach;
+               if (!import_attach)
+                       continue;
+               ret2 = dma_buf_end_cpu_access(import_attach->dmabuf, dir);
+               if (ret2) {
+                       drm_err(fb->dev,
+                               "dma_buf_end_cpu_access() failed during error handling: %d\n",
+                               ret2);
+               }
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_gem_fb_begin_cpu_access);
+
+/**
+ * drm_gem_fb_end_cpu_access - signals end of CPU access to GEM buffer objects
+ * @fb: the framebuffer
+ * @dir: access mode
+ *
+ * Signals the end of CPU access to the given framebuffer's GEM buffer objects. This
+ * function must be paired with a corresponding call to drm_gem_fb_begin_cpu_access().
+ * For imported BOs, the function calls dma_buf_end_cpu_access().
+ *
+ * See also drm_gem_fb_begin_cpu_access().
+ */
+void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir)
+{
+       size_t i = ARRAY_SIZE(fb->obj);
+       struct dma_buf_attachment *import_attach;
+       struct drm_gem_object *obj;
+       int ret;
+
+       while (i) {
+               --i;
+               obj = drm_gem_fb_get_obj(fb, i);
+               if (!obj)
+                       continue;
+               import_attach = obj->import_attach;
+               if (!import_attach)
+                       continue;
+               ret = dma_buf_end_cpu_access(import_attach->dmabuf, dir);
+               if (ret)
+                       drm_err(fb->dev, "dma_buf_end_cpu_access() failed: %d\n", ret);
+       }
+}
+EXPORT_SYMBOL(drm_gem_fb_end_cpu_access);
+
 static __u32 drm_gem_afbc_get_bpp(struct drm_device *dev,
                                  const struct drm_mode_fb_cmd2 *mode_cmd)
 {
index 6bdffc7..5705722 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef __DRM_GEM_FB_HELPER_H__
 #define __DRM_GEM_FB_HELPER_H__
 
+#include <linux/dma-buf.h>
+#include <linux/dma-buf-map.h>
+
 struct drm_afbc_framebuffer;
 struct drm_device;
 struct drm_fb_helper_surface_size;
@@ -34,6 +37,9 @@ struct drm_framebuffer *
 drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file,
                             const struct drm_mode_fb_cmd2 *mode_cmd);
 
+int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir);
+void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir);
+
 #define drm_is_afbc(modifier) \
        (((modifier) & AFBC_VENDOR_AND_TYPE_MASK) == DRM_FORMAT_MOD_ARM_AFBC(0))