Merge tag 'defconfig-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / drivers / gpu / drm / drm_gem_framebuffer_helper.c
index e2c6882..3c75d79 100644 (file)
@@ -15,6 +15,8 @@
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_modeset_helper.h>
 
+#include "drm_internal.h"
+
 #define AFBC_HEADER_SIZE               16
 #define AFBC_TH_LAYOUT_ALIGNMENT       8
 #define AFBC_HDR_ALIGN                 64
@@ -48,7 +50,7 @@
 struct drm_gem_object *drm_gem_fb_get_obj(struct drm_framebuffer *fb,
                                          unsigned int plane)
 {
-       if (plane >= 4)
+       if (plane >= ARRAY_SIZE(fb->obj))
                return NULL;
 
        return fb->obj[plane];
@@ -62,7 +64,8 @@ drm_gem_fb_init(struct drm_device *dev,
                 struct drm_gem_object **obj, unsigned int num_planes,
                 const struct drm_framebuffer_funcs *funcs)
 {
-       int ret, i;
+       unsigned int i;
+       int ret;
 
        drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
 
@@ -86,9 +89,9 @@ drm_gem_fb_init(struct drm_device *dev,
  */
 void drm_gem_fb_destroy(struct drm_framebuffer *fb)
 {
-       int i;
+       size_t i;
 
-       for (i = 0; i < 4; i++)
+       for (i = 0; i < ARRAY_SIZE(fb->obj); i++)
                drm_gem_object_put(fb->obj[i]);
 
        drm_framebuffer_cleanup(fb);
@@ -145,8 +148,9 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
                               const struct drm_framebuffer_funcs *funcs)
 {
        const struct drm_format_info *info;
-       struct drm_gem_object *objs[4];
-       int ret, i;
+       struct drm_gem_object *objs[DRM_FORMAT_MAX_PLANES];
+       unsigned int i;
+       int ret;
 
        info = drm_get_format_info(dev, mode_cmd);
        if (!info) {
@@ -187,9 +191,10 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
        return 0;
 
 err_gem_object_put:
-       for (i--; i >= 0; i--)
+       while (i > 0) {
+               --i;
                drm_gem_object_put(objs[i]);
-
+       }
        return ret;
 }
 EXPORT_SYMBOL_GPL(drm_gem_fb_init_with_funcs);
@@ -306,6 +311,184 @@ 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_vmap - maps all framebuffer BOs into kernel address space
+ * @fb: the framebuffer
+ * @map: returns the mapping's address for each BO
+ * @data: returns the data address for each BO, can be NULL
+ *
+ * This function maps all buffer objects of the given framebuffer into
+ * kernel address space and stores them in struct dma_buf_map. If the
+ * mapping operation fails for one of the BOs, the function unmaps the
+ * already established mappings automatically.
+ *
+ * Callers that want to access a BO's stored data should pass @data.
+ * The argument returns the addresses of the data stored in each BO. This
+ * is different from @map if the framebuffer's offsets field is non-zero.
+ *
+ * See drm_gem_fb_vunmap() for unmapping.
+ *
+ * Returns:
+ * 0 on success, or a negative errno code otherwise.
+ */
+int drm_gem_fb_vmap(struct drm_framebuffer *fb,
+                   struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES],
+                   struct dma_buf_map data[DRM_FORMAT_MAX_PLANES])
+{
+       struct drm_gem_object *obj;
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < DRM_FORMAT_MAX_PLANES; ++i) {
+               obj = drm_gem_fb_get_obj(fb, i);
+               if (!obj) {
+                       dma_buf_map_clear(&map[i]);
+                       continue;
+               }
+               ret = drm_gem_vmap(obj, &map[i]);
+               if (ret)
+                       goto err_drm_gem_vunmap;
+       }
+
+       if (data) {
+               for (i = 0; i < DRM_FORMAT_MAX_PLANES; ++i) {
+                       memcpy(&data[i], &map[i], sizeof(data[i]));
+                       if (dma_buf_map_is_null(&data[i]))
+                               continue;
+                       dma_buf_map_incr(&data[i], fb->offsets[i]);
+               }
+       }
+
+       return 0;
+
+err_drm_gem_vunmap:
+       while (i) {
+               --i;
+               obj = drm_gem_fb_get_obj(fb, i);
+               if (!obj)
+                       continue;
+               drm_gem_vunmap(obj, &map[i]);
+       }
+       return ret;
+}
+EXPORT_SYMBOL(drm_gem_fb_vmap);
+
+/**
+ * drm_gem_fb_vunmap - unmaps framebuffer BOs from kernel address space
+ * @fb: the framebuffer
+ * @map: mapping addresses as returned by drm_gem_fb_vmap()
+ *
+ * This function unmaps all buffer objects of the given framebuffer.
+ *
+ * See drm_gem_fb_vmap() for more information.
+ */
+void drm_gem_fb_vunmap(struct drm_framebuffer *fb,
+                      struct dma_buf_map map[static DRM_FORMAT_MAX_PLANES])
+{
+       unsigned int i = DRM_FORMAT_MAX_PLANES;
+       struct drm_gem_object *obj;
+
+       while (i) {
+               --i;
+               obj = drm_gem_fb_get_obj(fb, i);
+               if (!obj)
+                       continue;
+               if (dma_buf_map_is_null(&map[i]))
+                       continue;
+               drm_gem_vunmap(obj, &map[i]);
+       }
+}
+EXPORT_SYMBOL(drm_gem_fb_vunmap);
+
+/**
+ * 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)
 {