All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] drm: Reuse temporary memory for format conversion
@ 2023-09-20 11:10 Thomas Zimmermann
  2023-09-20 11:10 ` [PATCH 1/8] drm/format-helper: Add struct drm_xfrm_buf to cache " Thomas Zimmermann
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: Thomas Zimmermann @ 2023-09-20 11:10 UTC (permalink / raw)
  To: javierm, jfalempe, jose.exposito89, arthurgrillo, mairacanal,
	maarten.lankhorst, mripard, airlied, daniel, noralf
  Cc: Thomas Zimmermann, dri-devel

DRM's format-conversion helpers require temporary memory. Pass the
buffer from the caller and keep it allocated over several calls. Allow
the caller to preallocate the buffer memory.

The motivation for this patchset is the recent work on a DRM panic
handler. The panic handler requires format conversion to display an
error to the screen. But allocating memory during kernel panics is
fragile. The changes in this patchset enable the DRM panic handler to
preallocate buffer storage before the panic occurs.

As an additonal benefit, drivers can now keep the temporary storage
across multiple display updates. Avoiding memory allocation reduces
the CPU overhead of the format helpers.

Patch 1 adds struct drm_xfrm_buf, a simple interface to pass around
the buffer storage. Patch 2 moves the memory management from the format
helpers into their callers. Drivers release the temporary storage at
the end of their display-update functions.

Patches 3 to 8 update three drivers to keep the allocated memory for
all of a device's lifetime. Managed cleanup releases the buffer as part
of releaseing the device. As additional benefit, buffer allocation now
happens in atomic_check helpers. The driver thus detects OOM errors
before the display update begins.

Tested with simpledrm.

Thomas Zimmermann (8):
  drm/format-helper: Add struct drm_xfrm_buf to cache format conversion
  drm/format-helper: Pass xfrm buffer to format-conversion helpers
  drm/simpledrm: Store xfrm buffer in device instance
  drm/simpledrm: Preallocate xfrm buffer in plane's atomic_check
  drm/ofdrm: Store xfrm buffer in device instance
  drm/ofdrm: Preallocate xfrm buffer in plane's atomic_check
  drm/ssd130x: Store xfrm buffer in device instance
  drm/ssd130x: Preallocate xfrm buffer in plane's atomic_check

 drivers/gpu/drm/drm_format_helper.c           | 204 +++++++++++++-----
 drivers/gpu/drm/drm_mipi_dbi.c                |   7 +-
 drivers/gpu/drm/gud/gud_pipe.c                |  21 +-
 drivers/gpu/drm/solomon/ssd130x.c             |  31 ++-
 drivers/gpu/drm/solomon/ssd130x.h             |   3 +
 .../gpu/drm/tests/drm_format_helper_test.c    |  33 +--
 drivers/gpu/drm/tiny/cirrus.c                 |   5 +-
 drivers/gpu/drm/tiny/ofdrm.c                  |  18 +-
 drivers/gpu/drm/tiny/repaper.c                |   5 +-
 drivers/gpu/drm/tiny/simpledrm.c              |  45 +++-
 drivers/gpu/drm/tiny/st7586.c                 |   5 +-
 include/drm/drm_format_helper.h               |  74 +++++--
 12 files changed, 352 insertions(+), 99 deletions(-)

-- 
2.42.0


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

* [PATCH 1/8] drm/format-helper: Add struct drm_xfrm_buf to cache format conversion
  2023-09-20 11:10 [PATCH 0/8] drm: Reuse temporary memory for format conversion Thomas Zimmermann
@ 2023-09-20 11:10 ` Thomas Zimmermann
  2023-09-20 11:10 ` [PATCH 2/8] drm/format-helper: Pass xfrm buffer to format-conversion helpers Thomas Zimmermann
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Thomas Zimmermann @ 2023-09-20 11:10 UTC (permalink / raw)
  To: javierm, jfalempe, jose.exposito89, arthurgrillo, mairacanal,
	maarten.lankhorst, mripard, airlied, daniel, noralf
  Cc: Thomas Zimmermann, dri-devel

Hold temporary memory for format conversion in an instance of struct
drm_xfrm_buf. Update internal helpers of DRM's format-conversion code
accordingly. Drivers will later be able to keep this cache across
display updates.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_format_helper.c | 111 +++++++++++++++++++++++++---
 include/drm/drm_format_helper.h     |  46 ++++++++++++
 2 files changed, 146 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index f93a4efcee909..029ca7893260a 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -17,9 +17,93 @@
 #include <drm/drm_format_helper.h>
 #include <drm/drm_framebuffer.h>
 #include <drm/drm_fourcc.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_print.h>
 #include <drm/drm_rect.h>
 
+static void drm_xfrm_buf_init_release(struct drm_device *dev, void *res)
+{
+	struct drm_xfrm_buf *buf = res;
+
+	drm_xfrm_buf_release(buf);
+}
+
+/**
+ * drmm_xfrm_buf_init - Initialize xfrm buffer with managed cleanup
+ * @dev: The DRM device
+ * @buf: The xfrm buffer to initialize
+ *
+ * Clears all fields in struct drm_xfrm_buf and installs a DRM release
+ * action for the buffer. The buffer will be empty with no preallocated
+ * resources.
+ *
+ * Returns:
+ * 0 on success, or a negative errno code otherwise.
+ */
+int drmm_xfrm_buf_init(struct drm_device *dev, struct drm_xfrm_buf *buf)
+{
+	buf->mem = NULL;
+	buf->size = 0;
+	buf->preallocated = false;
+
+	return drmm_add_action_or_reset(dev, drm_xfrm_buf_init_release, buf);
+}
+EXPORT_SYMBOL(drmm_xfrm_buf_init);
+
+/**
+ * drm_xfrm_buf_reserve - Allocates storage in an xfrm buffer
+ * @buf: The xfrm buffer
+ * @new_size: The minimum allocation size
+ * @flags: Flags for kmalloc()
+ *
+ * Allocates at least @new_size bytes and returns a pointer to the memory
+ * range. After calling this function, previously returned memory blocks
+ * are invalid. It's best to collect all memory requirements of a format
+ * conversion and call this function once to allocate the range.
+ *
+ * Returns:
+ * A pointer to the allocated memory range, or a pointer-encoded errno code otherwise.
+ */
+void *drm_xfrm_buf_reserve(struct drm_xfrm_buf *buf, size_t new_size, gfp_t flags)
+{
+	void *mem;
+
+	if (new_size <= buf->size)
+		goto out;
+	else if (buf->preallocated)
+		return NULL;
+
+	mem = krealloc(buf->mem, new_size, flags);
+	if (!mem)
+		return NULL;
+
+	buf->mem = mem;
+	buf->size = new_size;
+
+out:
+	return buf->mem;
+}
+EXPORT_SYMBOL(drm_xfrm_buf_reserve);
+
+/**
+ * drm_xfrm_buf_release - Releases an xfrm buffer's storage
+ * @buf: The xfrm buffer
+ *
+ * Releases the memory range references by the xfrm buffer. After
+ * this call, all pointers to the memory are invalid. Prefer
+ * drmm_xfrm_buffer_init() for cleaning up and unloading a driver.
+ */
+void drm_xfrm_buf_release(struct drm_xfrm_buf *buf)
+{
+	if (buf->preallocated)
+		return;
+
+	kfree(buf->mem);
+	buf->mem = NULL;
+	buf->size = 0;
+}
+EXPORT_SYMBOL(drm_xfrm_buf_release);
+
 static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp)
 {
 	return clip->y1 * pitch + clip->x1 * cpp;
@@ -45,6 +129,7 @@ EXPORT_SYMBOL(drm_fb_clip_offset);
 static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize,
 			 const void *vaddr, const struct drm_framebuffer *fb,
 			 const struct drm_rect *clip, bool vaddr_cached_hint,
+			 struct drm_xfrm_buf *xfrm,
 			 void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
 {
 	unsigned long linepixels = drm_rect_width(clip);
@@ -60,7 +145,7 @@ static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_p
 	 * one line at a time.
 	 */
 	if (!vaddr_cached_hint) {
-		stmp = kmalloc(sbuf_len, GFP_KERNEL);
+		stmp = drm_xfrm_buf_reserve(xfrm, sbuf_len, GFP_KERNEL);
 		if (!stmp)
 			return -ENOMEM;
 	}
@@ -79,8 +164,6 @@ static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_p
 		dst += dst_pitch;
 	}
 
-	kfree(stmp);
-
 	return 0;
 }
 
@@ -88,6 +171,7 @@ static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_p
 static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize,
 			      const void *vaddr, const struct drm_framebuffer *fb,
 			      const struct drm_rect *clip, bool vaddr_cached_hint,
+			      struct drm_xfrm_buf *xfrm,
 			      void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
 {
 	unsigned long linepixels = drm_rect_width(clip);
@@ -101,9 +185,9 @@ static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsign
 	void *dbuf;
 
 	if (vaddr_cached_hint) {
-		dbuf = kmalloc(dbuf_len, GFP_KERNEL);
+		dbuf = drm_xfrm_buf_reserve(xfrm, dbuf_len, GFP_KERNEL);
 	} else {
-		dbuf = kmalloc(stmp_off + sbuf_len, GFP_KERNEL);
+		dbuf = drm_xfrm_buf_reserve(xfrm, stmp_off + sbuf_len, GFP_KERNEL);
 		stmp = dbuf + stmp_off;
 	}
 	if (!dbuf)
@@ -124,8 +208,6 @@ static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsign
 		dst += dst_pitch;
 	}
 
-	kfree(dbuf);
-
 	return 0;
 }
 
@@ -139,17 +221,24 @@ static int drm_fb_xfrm(struct iosys_map *dst,
 	static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
 		0, 0, 0, 0
 	};
+	struct drm_xfrm_buf tmp = DRM_XFRM_BUF_INIT;
+	int ret;
 
 	if (!dst_pitch)
 		dst_pitch = default_dst_pitch;
 
 	/* TODO: handle src in I/O memory here */
 	if (dst[0].is_iomem)
-		return __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0],
-					  src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm_line);
+		ret = __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0],
+					 src[0].vaddr, fb, clip, vaddr_cached_hint, &tmp,
+					 xfrm_line);
 	else
-		return __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0],
-				     src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm_line);
+		ret = __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0],
+				    src[0].vaddr, fb, clip, vaddr_cached_hint, &tmp,
+				    xfrm_line);
+	drm_xfrm_buf_release(&tmp);
+
+	return ret;
 }
 
 /**
diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
index 291deb09475bb..245a5edc4735a 100644
--- a/include/drm/drm_format_helper.h
+++ b/include/drm/drm_format_helper.h
@@ -15,6 +15,52 @@ struct drm_rect;
 
 struct iosys_map;
 
+/**
+ * struct drm_xfrm_buf - Stores transformation and conversion state
+ *
+ * DRM helpers for format conversion store temporary state in
+ * struct drm_xfrm_buf. The buffer's resources can be reused
+ * among multiple conversion operations.
+ *
+ * All fields are considered private.
+ */
+struct drm_xfrm_buf {
+	void *mem;
+	size_t size;
+	bool preallocated;
+};
+
+/**
+ * DRM_XFRM_BUF_INIT - Initializer for struct drm_xfrm_buf
+ *
+ * Initializes an instance of struct drm_xfrm_buf to default
+ * values.
+ */
+#define DRM_XFRM_BUF_INIT { \
+		.mem = NULL, \
+		.size = 0, \
+		.preallocated = false, \
+	}
+
+/**
+ * DRM_XFRM_BUF_INIT_PREALLOCATED - Initializer for struct drm_xfrm_buf
+ * @_mem: The preallocated memory area
+ * @_size: The number of bytes in _mem
+ *
+ * Initializes an instance of struct drm_xfrm_buf to preallocated
+ * storage. The caller is responsible for a releases the provided
+ * memory range.
+ */
+#define DRM_XFRM_BUF_INIT_PREALLOCATED(_mem, _size) { \
+		.mem = (_mem), \
+		.size = (_size), \
+		.preallocated = true, \
+	}
+
+int drmm_xfrm_buf_init(struct drm_device *dev, struct drm_xfrm_buf *buf);
+void *drm_xfrm_buf_reserve(struct drm_xfrm_buf *buf, size_t new_size, gfp_t flags);
+void drm_xfrm_buf_release(struct drm_xfrm_buf *buf);
+
 unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,
 				const struct drm_rect *clip);
 
-- 
2.42.0


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

* [PATCH 2/8] drm/format-helper: Pass xfrm buffer to format-conversion helpers
  2023-09-20 11:10 [PATCH 0/8] drm: Reuse temporary memory for format conversion Thomas Zimmermann
  2023-09-20 11:10 ` [PATCH 1/8] drm/format-helper: Add struct drm_xfrm_buf to cache " Thomas Zimmermann
@ 2023-09-20 11:10 ` Thomas Zimmermann
  2023-09-20 11:40   ` Jani Nikula
  2023-09-20 11:10 ` [PATCH 3/8] drm/simpledrm: Store xfrm buffer in device instance Thomas Zimmermann
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: Thomas Zimmermann @ 2023-09-20 11:10 UTC (permalink / raw)
  To: javierm, jfalempe, jose.exposito89, arthurgrillo, mairacanal,
	maarten.lankhorst, mripard, airlied, daniel, noralf
  Cc: David Lechner, Thomas Zimmermann, dri-devel, Gerd Hoffmann

Pass an instance of struct drm_xfrm_buf to DRM's format conversion
helpers. Update all callers. Drivers will later be able to keep this
cache across display updates.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Cc: Noralf Trønnes <noralf@tronnes.org>
Cc: Javier Martinez Canillas <javierm@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: David Lechner <david@lechnology.com>
---
 drivers/gpu/drm/drm_format_helper.c           | 119 ++++++++++--------
 drivers/gpu/drm/drm_mipi_dbi.c                |   7 +-
 drivers/gpu/drm/gud/gud_pipe.c                |  21 ++--
 drivers/gpu/drm/solomon/ssd130x.c             |   5 +-
 .../gpu/drm/tests/drm_format_helper_test.c    |  33 ++---
 drivers/gpu/drm/tiny/cirrus.c                 |   5 +-
 drivers/gpu/drm/tiny/ofdrm.c                  |   4 +-
 drivers/gpu/drm/tiny/repaper.c                |   5 +-
 drivers/gpu/drm/tiny/simpledrm.c              |   4 +-
 drivers/gpu/drm/tiny/st7586.c                 |   5 +-
 include/drm/drm_format_helper.h               |  28 +++--
 11 files changed, 139 insertions(+), 97 deletions(-)

diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index 029ca7893260a..70a717ee79d03 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -216,29 +216,25 @@ static int drm_fb_xfrm(struct iosys_map *dst,
 		       const unsigned int *dst_pitch, const u8 *dst_pixsize,
 		       const struct iosys_map *src, const struct drm_framebuffer *fb,
 		       const struct drm_rect *clip, bool vaddr_cached_hint,
+		       struct drm_xfrm_buf *xfrm,
 		       void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels))
 {
 	static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
 		0, 0, 0, 0
 	};
-	struct drm_xfrm_buf tmp = DRM_XFRM_BUF_INIT;
-	int ret;
 
 	if (!dst_pitch)
 		dst_pitch = default_dst_pitch;
 
 	/* TODO: handle src in I/O memory here */
 	if (dst[0].is_iomem)
-		ret = __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0],
-					 src[0].vaddr, fb, clip, vaddr_cached_hint, &tmp,
-					 xfrm_line);
+		return __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0],
+					  src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm,
+					  xfrm_line);
 	else
-		ret = __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0],
-				    src[0].vaddr, fb, clip, vaddr_cached_hint, &tmp,
-				    xfrm_line);
-	drm_xfrm_buf_release(&tmp);
-
-	return ret;
+		return __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0],
+				     src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm,
+				     xfrm_line);
 }
 
 /**
@@ -324,6 +320,7 @@ static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels
  * @fb: DRM framebuffer
  * @clip: Clip rectangle area to copy
  * @cached: Source buffer is mapped cached (eg. not write-combined)
+ * @xfrm: Transform and conversion state
  *
  * This function copies parts of a framebuffer to display memory and swaps per-pixel
  * bytes during the process. Destination and framebuffer formats must match. The
@@ -338,7 +335,8 @@ static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels
  */
 void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
 		 const struct iosys_map *src, const struct drm_framebuffer *fb,
-		 const struct drm_rect *clip, bool cached)
+		 const struct drm_rect *clip, bool cached,
+		 struct drm_xfrm_buf *xfrm)
 {
 	const struct drm_format_info *format = fb->format;
 	u8 cpp = DIV_ROUND_UP(drm_format_info_bpp(format, 0), 8);
@@ -357,7 +355,7 @@ void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
 		return;
 	}
 
-	drm_fb_xfrm(dst, dst_pitch, &cpp, src, fb, clip, cached, swab_line);
+	drm_fb_xfrm(dst, dst_pitch, &cpp, src, fb, clip, cached, xfrm, swab_line);
 }
 EXPORT_SYMBOL(drm_fb_swab);
 
@@ -384,6 +382,7 @@ static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigne
  * @src: Array of XRGB8888 source buffers
  * @fb: DRM framebuffer
  * @clip: Clip rectangle area to copy
+ * @xfrm: Transform and conversion state
  *
  * This function copies parts of a framebuffer to display memory and converts the
  * color format during the process. Destination and framebuffer formats must match. The
@@ -398,13 +397,13 @@ static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigne
  */
 void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch,
 			       const struct iosys_map *src, const struct drm_framebuffer *fb,
-			       const struct drm_rect *clip)
+			       const struct drm_rect *clip, struct drm_xfrm_buf *xfrm)
 {
 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
 		1,
 	};
 
-	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm,
 		    drm_fb_xrgb8888_to_rgb332_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332);
@@ -453,6 +452,7 @@ static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf,
  * @src: Array of XRGB8888 source buffer
  * @fb: DRM framebuffer
  * @clip: Clip rectangle area to copy
+ * @xfrm: Transform and conversion state
  * @swab: Swap bytes
  *
  * This function copies parts of a framebuffer to display memory and converts the
@@ -468,7 +468,8 @@ static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf,
  */
 void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch,
 			       const struct iosys_map *src, const struct drm_framebuffer *fb,
-			       const struct drm_rect *clip, bool swab)
+			       const struct drm_rect *clip, struct drm_xfrm_buf *xfrm,
+			       bool swab)
 {
 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
 		2,
@@ -481,7 +482,7 @@ void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pi
 	else
 		xfrm_line = drm_fb_xrgb8888_to_rgb565_line;
 
-	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm_line);
+	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm, xfrm_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
 
@@ -510,6 +511,7 @@ static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsig
  * @src: Array of XRGB8888 source buffer
  * @fb: DRM framebuffer
  * @clip: Clip rectangle area to copy
+ * @xfrm: Transform and conversion state
  *
  * This function copies parts of a framebuffer to display memory and converts
  * the color format during the process. The parameters @dst, @dst_pitch and
@@ -525,13 +527,13 @@ static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsig
  */
 void drm_fb_xrgb8888_to_xrgb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
 				 const struct iosys_map *src, const struct drm_framebuffer *fb,
-				 const struct drm_rect *clip)
+				 const struct drm_rect *clip, struct drm_xfrm_buf *xfrm)
 {
 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
 		2,
 	};
 
-	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm,
 		    drm_fb_xrgb8888_to_xrgb1555_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb1555);
@@ -562,6 +564,7 @@ static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsig
  * @src: Array of XRGB8888 source buffer
  * @fb: DRM framebuffer
  * @clip: Clip rectangle area to copy
+ * @xfrm: Transform and conversion state
  *
  * This function copies parts of a framebuffer to display memory and converts
  * the color format during the process. The parameters @dst, @dst_pitch and
@@ -577,13 +580,13 @@ static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsig
  */
 void drm_fb_xrgb8888_to_argb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
 				 const struct iosys_map *src, const struct drm_framebuffer *fb,
-				 const struct drm_rect *clip)
+				 const struct drm_rect *clip, struct drm_xfrm_buf *xfrm)
 {
 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
 		2,
 	};
 
-	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm,
 		    drm_fb_xrgb8888_to_argb1555_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb1555);
@@ -614,6 +617,7 @@ static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsig
  * @src: Array of XRGB8888 source buffer
  * @fb: DRM framebuffer
  * @clip: Clip rectangle area to copy
+ * @xfrm: Transform and conversion state
  *
  * This function copies parts of a framebuffer to display memory and converts
  * the color format during the process. The parameters @dst, @dst_pitch and
@@ -629,13 +633,13 @@ static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsig
  */
 void drm_fb_xrgb8888_to_rgba5551(struct iosys_map *dst, const unsigned int *dst_pitch,
 				 const struct iosys_map *src, const struct drm_framebuffer *fb,
-				 const struct drm_rect *clip)
+				 const struct drm_rect *clip, struct drm_xfrm_buf *xfrm)
 {
 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
 		2,
 	};
 
-	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm,
 		    drm_fb_xrgb8888_to_rgba5551_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgba5551);
@@ -664,6 +668,7 @@ static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigne
  * @src: Array of XRGB8888 source buffers
  * @fb: DRM framebuffer
  * @clip: Clip rectangle area to copy
+ * @xfrm: Transform and conversion state
  *
  * This function copies parts of a framebuffer to display memory and converts the
  * color format during the process. Destination and framebuffer formats must match. The
@@ -679,13 +684,13 @@ static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigne
  */
 void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch,
 			       const struct iosys_map *src, const struct drm_framebuffer *fb,
-			       const struct drm_rect *clip)
+			       const struct drm_rect *clip, struct drm_xfrm_buf *xfrm)
 {
 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
 		3,
 	};
 
-	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm,
 		    drm_fb_xrgb8888_to_rgb888_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888);
@@ -712,6 +717,7 @@ static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsig
  * @src: Array of XRGB8888 source buffer
  * @fb: DRM framebuffer
  * @clip: Clip rectangle area to copy
+ * @xfrm: Transform and conversion state
  *
  * This function copies parts of a framebuffer to display memory and converts the
  * color format during the process. The parameters @dst, @dst_pitch and @src refer
@@ -727,13 +733,13 @@ static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsig
  */
 void drm_fb_xrgb8888_to_argb8888(struct iosys_map *dst, const unsigned int *dst_pitch,
 				 const struct iosys_map *src, const struct drm_framebuffer *fb,
-				 const struct drm_rect *clip)
+				 const struct drm_rect *clip, struct drm_xfrm_buf *xfrm)
 {
 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
 		4,
 	};
 
-	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm,
 		    drm_fb_xrgb8888_to_argb8888_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb8888);
@@ -758,13 +764,13 @@ static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsig
 static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
 					const struct iosys_map *src,
 					const struct drm_framebuffer *fb,
-					const struct drm_rect *clip)
+					const struct drm_rect *clip, struct drm_xfrm_buf *xfrm)
 {
 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
 		4,
 	};
 
-	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm,
 		    drm_fb_xrgb8888_to_abgr8888_line);
 }
 
@@ -788,13 +794,13 @@ static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsig
 static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
 					const struct iosys_map *src,
 					const struct drm_framebuffer *fb,
-					const struct drm_rect *clip)
+					const struct drm_rect *clip, struct drm_xfrm_buf *xfrm)
 {
 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
 		4,
 	};
 
-	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm,
 		    drm_fb_xrgb8888_to_xbgr8888_line);
 }
 
@@ -824,6 +830,7 @@ static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, un
  * @src: Array of XRGB8888 source buffers
  * @fb: DRM framebuffer
  * @clip: Clip rectangle area to copy
+ * @xfrm: Transform and conversion state
  *
  * This function copies parts of a framebuffer to display memory and converts the
  * color format during the process. Destination and framebuffer formats must match. The
@@ -839,13 +846,13 @@ static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, un
  */
 void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,
 				    const struct iosys_map *src, const struct drm_framebuffer *fb,
-				    const struct drm_rect *clip)
+				    const struct drm_rect *clip, struct drm_xfrm_buf *xfrm)
 {
 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
 		4,
 	};
 
-	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm,
 		    drm_fb_xrgb8888_to_xrgb2101010_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010);
@@ -877,6 +884,7 @@ static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, un
  * @src: Array of XRGB8888 source buffers
  * @fb: DRM framebuffer
  * @clip: Clip rectangle area to copy
+ * @xfrm: Transform and conversion state
  *
  * This function copies parts of a framebuffer to display memory and converts
  * the color format during the process. The parameters @dst, @dst_pitch and
@@ -892,13 +900,13 @@ static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, un
  */
 void drm_fb_xrgb8888_to_argb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,
 				    const struct iosys_map *src, const struct drm_framebuffer *fb,
-				    const struct drm_rect *clip)
+				    const struct drm_rect *clip, struct drm_xfrm_buf *xfrm)
 {
 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
 		4,
 	};
 
-	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm,
 		    drm_fb_xrgb8888_to_argb2101010_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb2101010);
@@ -928,6 +936,7 @@ static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned
  * @src: Array of XRGB8888 source buffers
  * @fb: DRM framebuffer
  * @clip: Clip rectangle area to copy
+ * @xfrm: Transform and conversion state
  *
  * This function copies parts of a framebuffer to display memory and converts the
  * color format during the process. Destination and framebuffer formats must match. The
@@ -947,13 +956,13 @@ static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned
  */
 void drm_fb_xrgb8888_to_gray8(struct iosys_map *dst, const unsigned int *dst_pitch,
 			      const struct iosys_map *src, const struct drm_framebuffer *fb,
-			      const struct drm_rect *clip)
+			      const struct drm_rect *clip, struct drm_xfrm_buf *xfrm)
 {
 	static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
 		1,
 	};
 
-	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+	drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm,
 		    drm_fb_xrgb8888_to_gray8_line);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
@@ -967,6 +976,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
  * @src:	The framebuffer memory to copy from
  * @fb:		The framebuffer to copy from
  * @clip:	Clip rectangle area to copy
+ * @xfrm: Transform and conversion state
  *
  * This function copies parts of a framebuffer to display memory. If the
  * formats of the display and the framebuffer mismatch, the blit function
@@ -985,7 +995,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
  */
 int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t dst_format,
 		const struct iosys_map *src, const struct drm_framebuffer *fb,
-		const struct drm_rect *clip)
+		const struct drm_rect *clip, struct drm_xfrm_buf *xfrm)
 {
 	uint32_t fb_format = fb->format->format;
 
@@ -993,44 +1003,44 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d
 		drm_fb_memcpy(dst, dst_pitch, src, fb, clip);
 		return 0;
 	} else if (fb_format == (dst_format | DRM_FORMAT_BIG_ENDIAN)) {
-		drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
+		drm_fb_swab(dst, dst_pitch, src, fb, clip, false, xfrm);
 		return 0;
 	} else if (fb_format == (dst_format & ~DRM_FORMAT_BIG_ENDIAN)) {
-		drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
+		drm_fb_swab(dst, dst_pitch, src, fb, clip, false, xfrm);
 		return 0;
 	} else if (fb_format == DRM_FORMAT_XRGB8888) {
 		if (dst_format == DRM_FORMAT_RGB565) {
-			drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, false);
+			drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, xfrm, false);
 			return 0;
 		} else if (dst_format == DRM_FORMAT_XRGB1555) {
-			drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip);
+			drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip, xfrm);
 			return 0;
 		} else if (dst_format == DRM_FORMAT_ARGB1555) {
-			drm_fb_xrgb8888_to_argb1555(dst, dst_pitch, src, fb, clip);
+			drm_fb_xrgb8888_to_argb1555(dst, dst_pitch, src, fb, clip, xfrm);
 			return 0;
 		} else if (dst_format == DRM_FORMAT_RGBA5551) {
-			drm_fb_xrgb8888_to_rgba5551(dst, dst_pitch, src, fb, clip);
+			drm_fb_xrgb8888_to_rgba5551(dst, dst_pitch, src, fb, clip, xfrm);
 			return 0;
 		} else if (dst_format == DRM_FORMAT_RGB888) {
-			drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip);
+			drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip, xfrm);
 			return 0;
 		} else if (dst_format == DRM_FORMAT_ARGB8888) {
-			drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip);
+			drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip, xfrm);
 			return 0;
 		} else if (dst_format == DRM_FORMAT_XBGR8888) {
-			drm_fb_xrgb8888_to_xbgr8888(dst, dst_pitch, src, fb, clip);
+			drm_fb_xrgb8888_to_xbgr8888(dst, dst_pitch, src, fb, clip, xfrm);
 			return 0;
 		} else if (dst_format == DRM_FORMAT_ABGR8888) {
-			drm_fb_xrgb8888_to_abgr8888(dst, dst_pitch, src, fb, clip);
+			drm_fb_xrgb8888_to_abgr8888(dst, dst_pitch, src, fb, clip, xfrm);
 			return 0;
 		} else if (dst_format == DRM_FORMAT_XRGB2101010) {
-			drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip);
+			drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip, xfrm);
 			return 0;
 		} else if (dst_format == DRM_FORMAT_ARGB2101010) {
-			drm_fb_xrgb8888_to_argb2101010(dst, dst_pitch, src, fb, clip);
+			drm_fb_xrgb8888_to_argb2101010(dst, dst_pitch, src, fb, clip, xfrm);
 			return 0;
 		} else if (dst_format == DRM_FORMAT_BGRX8888) {
-			drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
+			drm_fb_swab(dst, dst_pitch, src, fb, clip, false, xfrm);
 			return 0;
 		}
 	}
@@ -1067,6 +1077,7 @@ static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int
  * @src: Array of XRGB8888 source buffers
  * @fb: DRM framebuffer
  * @clip: Clip rectangle area to copy
+ * @xfrm: Transform and conversion state
  *
  * This function copies parts of a framebuffer to display memory and converts the
  * color format during the process. Destination and framebuffer formats must match. The
@@ -1091,7 +1102,7 @@ static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int
  */
 void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitch,
 			     const struct iosys_map *src, const struct drm_framebuffer *fb,
-			     const struct drm_rect *clip)
+			     const struct drm_rect *clip, struct drm_xfrm_buf *xfrm)
 {
 	static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
 		0, 0, 0, 0
@@ -1131,7 +1142,7 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc
 	 * Allocate a buffer to be used for both copying from the cma
 	 * memory and to store the intermediate grayscale line pixels.
 	 */
-	src32 = kmalloc(len_src32 + linepixels, GFP_KERNEL);
+	src32 = drm_xfrm_buf_reserve(xfrm, len_src32 + linepixels, GFP_KERNEL);
 	if (!src32)
 		return;
 
@@ -1145,8 +1156,6 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc
 		vaddr += fb->pitches[0];
 		mono += dst_pitch_0;
 	}
-
-	kfree(src32);
 }
 EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono);
 
diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c
index e90f0bf895b33..b5f9ab9de1d08 100644
--- a/drivers/gpu/drm/drm_mipi_dbi.c
+++ b/drivers/gpu/drm/drm_mipi_dbi.c
@@ -206,6 +206,7 @@ int mipi_dbi_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer *
 {
 	struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
 	struct iosys_map dst_map = IOSYS_MAP_INIT_VADDR(dst);
+	struct drm_xfrm_buf xfrm = DRM_XFRM_BUF_INIT;
 	int ret;
 
 	ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
@@ -215,12 +216,12 @@ int mipi_dbi_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer *
 	switch (fb->format->format) {
 	case DRM_FORMAT_RGB565:
 		if (swap)
-			drm_fb_swab(&dst_map, NULL, src, fb, clip, !gem->import_attach);
+			drm_fb_swab(&dst_map, NULL, src, fb, clip, !gem->import_attach, &xfrm);
 		else
 			drm_fb_memcpy(&dst_map, NULL, src, fb, clip);
 		break;
 	case DRM_FORMAT_XRGB8888:
-		drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip, swap);
+		drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip, &xfrm, swap);
 		break;
 	default:
 		drm_err_once(fb->dev, "Format is not supported: %p4cc\n",
@@ -230,6 +231,8 @@ int mipi_dbi_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer *
 
 	drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
 
+	drm_xfrm_buf_release(&xfrm);
+
 	return ret;
 }
 EXPORT_SYMBOL(mipi_dbi_buf_copy);
diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c
index d2f199ea3c111..38d4a65c0204c 100644
--- a/drivers/gpu/drm/gud/gud_pipe.c
+++ b/drivers/gpu/drm/gud/gud_pipe.c
@@ -57,6 +57,7 @@ static size_t gud_xrgb8888_to_r124(u8 *dst, const struct drm_format_info *format
 	unsigned int bits_per_pixel = 8 / block_width;
 	unsigned int x, y, width, height;
 	u8 pix, *pix8, *block = dst; /* Assign to silence compiler warning */
+	struct drm_xfrm_buf xfrm = DRM_XFRM_BUF_INIT;
 	struct iosys_map dst_map, vmap;
 	size_t len;
 	void *buf;
@@ -75,7 +76,7 @@ static size_t gud_xrgb8888_to_r124(u8 *dst, const struct drm_format_info *format
 
 	iosys_map_set_vaddr(&dst_map, buf);
 	iosys_map_set_vaddr(&vmap, src);
-	drm_fb_xrgb8888_to_gray8(&dst_map, NULL, &vmap, fb, rect);
+	drm_fb_xrgb8888_to_gray8(&dst_map, NULL, &vmap, fb, rect, &xfrm);
 	pix8 = buf;
 
 	for (y = 0; y < height; y++) {
@@ -94,6 +95,7 @@ static size_t gud_xrgb8888_to_r124(u8 *dst, const struct drm_format_info *format
 	}
 
 	kfree(buf);
+	drm_xfrm_buf_release(&xfrm);
 
 	return len;
 }
@@ -154,6 +156,7 @@ static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb,
 			  const struct drm_format_info *format, struct drm_rect *rect,
 			  struct gud_set_buffer_req *req)
 {
+	struct drm_xfrm_buf xfrm = DRM_XFRM_BUF_INIT;
 	u8 compression = gdrm->compression;
 	struct iosys_map dst;
 	void *vaddr, *buf;
@@ -179,22 +182,24 @@ static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb,
 	if (format != fb->format) {
 		if (format->format == GUD_DRM_FORMAT_R1) {
 			len = gud_xrgb8888_to_r124(buf, format, vaddr, fb, rect);
-			if (!len)
+			if (!len) {
+				drm_xfrm_buf_release(&xfrm);
 				return -ENOMEM;
+			}
 		} else if (format->format == DRM_FORMAT_R8) {
-			drm_fb_xrgb8888_to_gray8(&dst, NULL, src, fb, rect);
+			drm_fb_xrgb8888_to_gray8(&dst, NULL, src, fb, rect, &xfrm);
 		} else if (format->format == DRM_FORMAT_RGB332) {
-			drm_fb_xrgb8888_to_rgb332(&dst, NULL, src, fb, rect);
+			drm_fb_xrgb8888_to_rgb332(&dst, NULL, src, fb, rect, &xfrm);
 		} else if (format->format == DRM_FORMAT_RGB565) {
-			drm_fb_xrgb8888_to_rgb565(&dst, NULL, src, fb, rect,
+			drm_fb_xrgb8888_to_rgb565(&dst, NULL, src, fb, rect, &xfrm,
 						  gud_is_big_endian());
 		} else if (format->format == DRM_FORMAT_RGB888) {
-			drm_fb_xrgb8888_to_rgb888(&dst, NULL, src, fb, rect);
+			drm_fb_xrgb8888_to_rgb888(&dst, NULL, src, fb, rect, &xfrm);
 		} else {
 			len = gud_xrgb8888_to_color(buf, format, vaddr, fb, rect);
 		}
 	} else if (gud_is_big_endian() && format->cpp[0] > 1) {
-		drm_fb_swab(&dst, NULL, src, fb, rect, cached_reads);
+		drm_fb_swab(&dst, NULL, src, fb, rect, cached_reads, &xfrm);
 	} else if (compression && cached_reads && pitch == fb->pitches[0]) {
 		/* can compress directly from the framebuffer */
 		buf = vaddr + rect->y1 * pitch;
@@ -222,6 +227,8 @@ static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb,
 		req->compressed_length = cpu_to_le32(complen);
 	}
 
+	drm_xfrm_buf_release(&xfrm);
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c
index 5a80b228d18ca..d11079733bc0e 100644
--- a/drivers/gpu/drm/solomon/ssd130x.c
+++ b/drivers/gpu/drm/solomon/ssd130x.c
@@ -571,6 +571,7 @@ static int ssd130x_fb_blit_rect(struct drm_plane_state *state,
 	struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev);
 	unsigned int page_height = ssd130x->device_info->page_height;
 	struct ssd130x_plane_state *ssd130x_state = to_ssd130x_plane_state(state);
+	struct drm_xfrm_buf xfrm = DRM_XFRM_BUF_INIT;
 	u8 *buf = ssd130x_state->buffer;
 	struct iosys_map dst;
 	unsigned int dst_pitch;
@@ -587,12 +588,14 @@ static int ssd130x_fb_blit_rect(struct drm_plane_state *state,
 		return ret;
 
 	iosys_map_set_vaddr(&dst, buf);
-	drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, vmap, fb, rect);
+	drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, vmap, fb, rect, &xfrm);
 
 	drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
 
 	ssd130x_update_rect(ssd130x, ssd130x_state, rect);
 
+	drm_xfrm_buf_release(&xfrm);
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c
index 1a6bd291345de..c6deabb6c64e5 100644
--- a/drivers/gpu/drm/tests/drm_format_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_format_helper_test.c
@@ -20,6 +20,10 @@
 
 #define TEST_USE_DEFAULT_PITCH 0
 
+static unsigned char conversion_buf_mem[PAGE_SIZE];
+static struct drm_xfrm_buf xfrm =
+	DRM_XFRM_BUF_INIT_PREALLOCATED(conversion_buf_mem, ARRAY_SIZE(conversion_buf_mem));
+
 struct convert_to_gray8_result {
 	unsigned int dst_pitch;
 	const u8 expected[TEST_BUF_SIZE];
@@ -568,8 +572,7 @@ static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test)
 	const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ?
 		NULL : &result->dst_pitch;
 
-	drm_fb_xrgb8888_to_gray8(&dst, dst_pitch, &src, &fb, &params->clip);
-
+	drm_fb_xrgb8888_to_gray8(&dst, dst_pitch, &src, &fb, &params->clip, &xfrm);
 	KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
 }
 
@@ -602,7 +605,7 @@ static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test)
 	const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ?
 		NULL : &result->dst_pitch;
 
-	drm_fb_xrgb8888_to_rgb332(&dst, dst_pitch, &src, &fb, &params->clip);
+	drm_fb_xrgb8888_to_rgb332(&dst, dst_pitch, &src, &fb, &params->clip, &xfrm);
 	KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
 }
 
@@ -635,12 +638,14 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test)
 	const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ?
 		NULL : &result->dst_pitch;
 
-	drm_fb_xrgb8888_to_rgb565(&dst, dst_pitch, &src, &fb, &params->clip, false);
+	drm_fb_xrgb8888_to_rgb565(&dst, dst_pitch, &src, &fb, &params->clip,
+				  &xfrm, false);
 	buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
 	KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
 
 	buf = dst.vaddr; /* restore original value of buf */
-	drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, &params->clip, true);
+	drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, &params->clip,
+				  &xfrm, true);
 	buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
 	KUNIT_EXPECT_MEMEQ(test, buf, result->expected_swab, dst_size);
 }
@@ -674,7 +679,7 @@ static void drm_test_fb_xrgb8888_to_xrgb1555(struct kunit *test)
 	const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ?
 		NULL : &result->dst_pitch;
 
-	drm_fb_xrgb8888_to_xrgb1555(&dst, dst_pitch, &src, &fb, &params->clip);
+	drm_fb_xrgb8888_to_xrgb1555(&dst, dst_pitch, &src, &fb, &params->clip, &xfrm);
 	buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
 	KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
 }
@@ -708,7 +713,7 @@ static void drm_test_fb_xrgb8888_to_argb1555(struct kunit *test)
 	const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ?
 		NULL : &result->dst_pitch;
 
-	drm_fb_xrgb8888_to_argb1555(&dst, dst_pitch, &src, &fb, &params->clip);
+	drm_fb_xrgb8888_to_argb1555(&dst, dst_pitch, &src, &fb, &params->clip, &xfrm);
 	buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
 	KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
 }
@@ -742,7 +747,7 @@ static void drm_test_fb_xrgb8888_to_rgba5551(struct kunit *test)
 	const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ?
 		NULL : &result->dst_pitch;
 
-	drm_fb_xrgb8888_to_rgba5551(&dst, dst_pitch, &src, &fb, &params->clip);
+	drm_fb_xrgb8888_to_rgba5551(&dst, dst_pitch, &src, &fb, &params->clip, &xfrm);
 	buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
 	KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
 }
@@ -780,7 +785,7 @@ static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test)
 	const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ?
 		NULL : &result->dst_pitch;
 
-	drm_fb_xrgb8888_to_rgb888(&dst, dst_pitch, &src, &fb, &params->clip);
+	drm_fb_xrgb8888_to_rgb888(&dst, dst_pitch, &src, &fb, &params->clip, &xfrm);
 	KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
 }
 
@@ -813,7 +818,7 @@ static void drm_test_fb_xrgb8888_to_argb8888(struct kunit *test)
 	const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ?
 		NULL : &result->dst_pitch;
 
-	drm_fb_xrgb8888_to_argb8888(&dst, dst_pitch, &src, &fb, &params->clip);
+	drm_fb_xrgb8888_to_argb8888(&dst, dst_pitch, &src, &fb, &params->clip, &xfrm);
 	buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32));
 	KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
 }
@@ -847,7 +852,7 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test)
 	const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ?
 		NULL : &result->dst_pitch;
 
-	drm_fb_xrgb8888_to_xrgb2101010(&dst, dst_pitch, &src, &fb, &params->clip);
+	drm_fb_xrgb8888_to_xrgb2101010(&dst, dst_pitch, &src, &fb, &params->clip, &xfrm);
 	buf = le32buf_to_cpu(test, buf, dst_size / sizeof(u32));
 	KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
 }
@@ -881,7 +886,7 @@ static void drm_test_fb_xrgb8888_to_argb2101010(struct kunit *test)
 	const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ?
 		NULL : &result->dst_pitch;
 
-	drm_fb_xrgb8888_to_argb2101010(&dst, dst_pitch, &src, &fb, &params->clip);
+	drm_fb_xrgb8888_to_argb2101010(&dst, dst_pitch, &src, &fb, &params->clip, &xfrm);
 	buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32));
 	KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
 }
@@ -915,7 +920,7 @@ static void drm_test_fb_xrgb8888_to_mono(struct kunit *test)
 	const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ?
 		NULL : &result->dst_pitch;
 
-	drm_fb_xrgb8888_to_mono(&dst, dst_pitch, &src, &fb, &params->clip);
+	drm_fb_xrgb8888_to_mono(&dst, dst_pitch, &src, &fb, &params->clip, &xfrm);
 	KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
 }
 
@@ -948,7 +953,7 @@ static void drm_test_fb_swab(struct kunit *test)
 	const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ?
 		NULL : &result->dst_pitch;
 
-	drm_fb_swab(&dst, dst_pitch, &src, &fb, &params->clip, false);
+	drm_fb_swab(&dst, dst_pitch, &src, &fb, &params->clip, false, &xfrm);
 	buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32));
 	KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
 }
diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c
index 594bc472862fe..74821d688daf5 100644
--- a/drivers/gpu/drm/tiny/cirrus.c
+++ b/drivers/gpu/drm/tiny/cirrus.c
@@ -391,6 +391,7 @@ static void cirrus_primary_plane_helper_atomic_update(struct drm_plane *plane,
 	struct cirrus_primary_plane_state *old_primary_plane_state =
 		to_cirrus_primary_plane_state(old_plane_state);
 	struct iosys_map vaddr = IOSYS_MAP_INIT_VADDR_IOMEM(cirrus->vram);
+	struct drm_xfrm_buf xfrm = DRM_XFRM_BUF_INIT;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect damage;
 	int idx;
@@ -411,10 +412,12 @@ static void cirrus_primary_plane_helper_atomic_update(struct drm_plane *plane,
 		unsigned int offset = drm_fb_clip_offset(pitch, format, &damage);
 		struct iosys_map dst = IOSYS_MAP_INIT_OFFSET(&vaddr, offset);
 
-		drm_fb_blit(&dst, &pitch, format->format, shadow_plane_state->data, fb, &damage);
+		drm_fb_blit(&dst, &pitch, format->format, shadow_plane_state->data, fb,
+			    &damage, &xfrm);
 	}
 
 	drm_dev_exit(idx);
+	drm_xfrm_buf_release(&xfrm);
 }
 
 static const struct drm_plane_helper_funcs cirrus_primary_plane_helper_funcs = {
diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c
index 2d999a0facdee..1add55c872670 100644
--- a/drivers/gpu/drm/tiny/ofdrm.c
+++ b/drivers/gpu/drm/tiny/ofdrm.c
@@ -796,6 +796,7 @@ static void ofdrm_primary_plane_helper_atomic_update(struct drm_plane *plane,
 	struct drm_framebuffer *fb = plane_state->fb;
 	unsigned int dst_pitch = odev->pitch;
 	const struct drm_format_info *dst_format = odev->format;
+	struct drm_xfrm_buf xfrm = DRM_XFRM_BUF_INIT;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect damage;
 	int ret, idx;
@@ -817,12 +818,13 @@ static void ofdrm_primary_plane_helper_atomic_update(struct drm_plane *plane,
 
 		iosys_map_incr(&dst, drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip));
 		drm_fb_blit(&dst, &dst_pitch, dst_format->format, shadow_plane_state->data, fb,
-			    &damage);
+			    &damage, &xfrm);
 	}
 
 	drm_dev_exit(idx);
 out_drm_gem_fb_end_cpu_access:
 	drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
+	drm_xfrm_buf_release(&xfrm);
 }
 
 static void ofdrm_primary_plane_helper_atomic_disable(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c
index 73dd4f4289c20..fddcaab78b92c 100644
--- a/drivers/gpu/drm/tiny/repaper.c
+++ b/drivers/gpu/drm/tiny/repaper.c
@@ -514,6 +514,7 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb)
 	struct drm_gem_dma_object *dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
 	struct repaper_epd *epd = drm_to_epd(fb->dev);
 	unsigned int dst_pitch = 0;
+	struct drm_xfrm_buf xfrm = DRM_XFRM_BUF_INIT;
 	struct iosys_map dst, vmap;
 	struct drm_rect clip;
 	int idx, ret = 0;
@@ -545,7 +546,7 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb)
 
 	iosys_map_set_vaddr(&dst, buf);
 	iosys_map_set_vaddr(&vmap, dma_obj->vaddr);
-	drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, &vmap, fb, &clip);
+	drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, &vmap, fb, &clip, &xfrm);
 
 	drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
 
@@ -601,6 +602,8 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb)
 out_exit:
 	drm_dev_exit(idx);
 
+	drm_xfrm_buf_release(&xfrm);
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index ff86ba1ae1b8b..8aceb7d378dea 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -486,6 +486,7 @@ static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane
 	struct drm_framebuffer *fb = plane_state->fb;
 	struct drm_device *dev = plane->dev;
 	struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
+	struct drm_xfrm_buf xfrm = DRM_XFRM_BUF_INIT;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect damage;
 	int ret, idx;
@@ -507,12 +508,13 @@ static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane
 
 		iosys_map_incr(&dst, drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip));
 		drm_fb_blit(&dst, &sdev->pitch, sdev->format->format, shadow_plane_state->data,
-			    fb, &damage);
+			    fb, &damage, &xfrm);
 	}
 
 	drm_dev_exit(idx);
 out_drm_gem_fb_end_cpu_access:
 	drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
+	drm_xfrm_buf_release(&xfrm);
 }
 
 static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/tiny/st7586.c b/drivers/gpu/drm/tiny/st7586.c
index 3cf4eec16a813..e4d1e071aae56 100644
--- a/drivers/gpu/drm/tiny/st7586.c
+++ b/drivers/gpu/drm/tiny/st7586.c
@@ -67,6 +67,7 @@ static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr,
 				       struct drm_rect *clip)
 {
 	size_t len = (clip->x2 - clip->x1) * (clip->y2 - clip->y1);
+	struct drm_xfrm_buf xfrm = DRM_XFRM_BUF_INIT;
 	unsigned int x, y;
 	u8 *src, *buf, val;
 	struct iosys_map dst_map, vmap;
@@ -77,7 +78,7 @@ static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr,
 
 	iosys_map_set_vaddr(&dst_map, buf);
 	iosys_map_set_vaddr(&vmap, vaddr);
-	drm_fb_xrgb8888_to_gray8(&dst_map, NULL, &vmap, fb, clip);
+	drm_fb_xrgb8888_to_gray8(&dst_map, NULL, &vmap, fb, clip, &xfrm);
 	src = buf;
 
 	for (y = clip->y1; y < clip->y2; y++) {
@@ -90,6 +91,8 @@ static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr,
 	}
 
 	kfree(buf);
+
+	drm_xfrm_buf_release(&xfrm);
 }
 
 static int st7586_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer *fb,
diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
index 245a5edc4735a..11bab88114e2d 100644
--- a/include/drm/drm_format_helper.h
+++ b/include/drm/drm_format_helper.h
@@ -69,45 +69,47 @@ void drm_fb_memcpy(struct iosys_map *dst, const unsigned int *dst_pitch,
 		   const struct drm_rect *clip);
 void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
 		 const struct iosys_map *src, const struct drm_framebuffer *fb,
-		 const struct drm_rect *clip, bool cached);
+		 const struct drm_rect *clip, bool cached,
+		 struct drm_xfrm_buf *xfrm);
 void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch,
 			       const struct iosys_map *src, const struct drm_framebuffer *fb,
-			       const struct drm_rect *clip);
+			       const struct drm_rect *clip, struct drm_xfrm_buf *xfrm);
 void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch,
 			       const struct iosys_map *src, const struct drm_framebuffer *fb,
-			       const struct drm_rect *clip, bool swab);
+			       const struct drm_rect *clip, struct drm_xfrm_buf *xfrm,
+			       bool swab);
 void drm_fb_xrgb8888_to_xrgb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
 				 const struct iosys_map *src, const struct drm_framebuffer *fb,
-				 const struct drm_rect *clip);
+				 const struct drm_rect *clip, struct drm_xfrm_buf *xfrm);
 void drm_fb_xrgb8888_to_argb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
 				 const struct iosys_map *src, const struct drm_framebuffer *fb,
-				 const struct drm_rect *clip);
+				 const struct drm_rect *clip, struct drm_xfrm_buf *xfrm);
 void drm_fb_xrgb8888_to_rgba5551(struct iosys_map *dst, const unsigned int *dst_pitch,
 				 const struct iosys_map *src, const struct drm_framebuffer *fb,
-				 const struct drm_rect *clip);
+				 const struct drm_rect *clip, struct drm_xfrm_buf *xfrm);
 void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch,
 			       const struct iosys_map *src, const struct drm_framebuffer *fb,
-			       const struct drm_rect *clip);
+			       const struct drm_rect *clip, struct drm_xfrm_buf *xfrm);
 void drm_fb_xrgb8888_to_argb8888(struct iosys_map *dst, const unsigned int *dst_pitch,
 				 const struct iosys_map *src, const struct drm_framebuffer *fb,
-				 const struct drm_rect *clip);
+				 const struct drm_rect *clip, struct drm_xfrm_buf *xfrm);
 void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,
 				    const struct iosys_map *src, const struct drm_framebuffer *fb,
-				    const struct drm_rect *clip);
+				    const struct drm_rect *clip, struct drm_xfrm_buf *xfrm);
 void drm_fb_xrgb8888_to_argb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,
 				    const struct iosys_map *src, const struct drm_framebuffer *fb,
-				    const struct drm_rect *clip);
+				    const struct drm_rect *clip, struct drm_xfrm_buf *xfrm);
 void drm_fb_xrgb8888_to_gray8(struct iosys_map *dst, const unsigned int *dst_pitch,
 			      const struct iosys_map *src, const struct drm_framebuffer *fb,
-			      const struct drm_rect *clip);
+			      const struct drm_rect *clip, struct drm_xfrm_buf *xfrm);
 
 int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t dst_format,
 		const struct iosys_map *src, const struct drm_framebuffer *fb,
-		const struct drm_rect *rect);
+		const struct drm_rect *clip, struct drm_xfrm_buf *xfrm);
 
 void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitch,
 			     const struct iosys_map *src, const struct drm_framebuffer *fb,
-			     const struct drm_rect *clip);
+			     const struct drm_rect *clip, struct drm_xfrm_buf *xfrm);
 
 size_t drm_fb_build_fourcc_list(struct drm_device *dev,
 				const u32 *native_fourccs, size_t native_nfourccs,
-- 
2.42.0


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

* [PATCH 3/8] drm/simpledrm: Store xfrm buffer in device instance
  2023-09-20 11:10 [PATCH 0/8] drm: Reuse temporary memory for format conversion Thomas Zimmermann
  2023-09-20 11:10 ` [PATCH 1/8] drm/format-helper: Add struct drm_xfrm_buf to cache " Thomas Zimmermann
  2023-09-20 11:10 ` [PATCH 2/8] drm/format-helper: Pass xfrm buffer to format-conversion helpers Thomas Zimmermann
@ 2023-09-20 11:10 ` Thomas Zimmermann
  2023-09-20 11:10 ` [PATCH 4/8] drm/simpledrm: Preallocate xfrm buffer in plane's atomic_check Thomas Zimmermann
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Thomas Zimmermann @ 2023-09-20 11:10 UTC (permalink / raw)
  To: javierm, jfalempe, jose.exposito89, arthurgrillo, mairacanal,
	maarten.lankhorst, mripard, airlied, daniel, noralf
  Cc: Thomas Zimmermann, dri-devel

Store and instance of struct drm_xfrm_buf in struct simpledrm_device
and keep the allocated memory allocated across display updates. Avoid
possibly reallocating temporary memory on each display update. Unloading
the DRM device also releases the xfrm buffer.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/tiny/simpledrm.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 8aceb7d378dea..31fc32a00d0a5 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -232,6 +232,7 @@ struct simpledrm_device {
 	struct drm_display_mode mode;
 	const struct drm_format_info *format;
 	unsigned int pitch;
+	struct drm_xfrm_buf xfrm;
 
 	/* memory management */
 	struct iosys_map screen_base;
@@ -486,7 +487,6 @@ static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane
 	struct drm_framebuffer *fb = plane_state->fb;
 	struct drm_device *dev = plane->dev;
 	struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
-	struct drm_xfrm_buf xfrm = DRM_XFRM_BUF_INIT;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect damage;
 	int ret, idx;
@@ -508,13 +508,12 @@ static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane
 
 		iosys_map_incr(&dst, drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip));
 		drm_fb_blit(&dst, &sdev->pitch, sdev->format->format, shadow_plane_state->data,
-			    fb, &damage, &xfrm);
+			    fb, &damage, &sdev->xfrm);
 	}
 
 	drm_dev_exit(idx);
 out_drm_gem_fb_end_cpu_access:
 	drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
-	drm_xfrm_buf_release(&xfrm);
 }
 
 static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plane,
@@ -714,6 +713,10 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
 	sdev->format = format;
 	sdev->pitch = stride;
 
+	ret = drmm_xfrm_buf_init(dev, &sdev->xfrm);
+	if (ret)
+		return ERR_PTR(ret);
+
 	drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&sdev->mode));
 	drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d byte\n",
 		&format->format, width, height, stride);
-- 
2.42.0


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

* [PATCH 4/8] drm/simpledrm: Preallocate xfrm buffer in plane's atomic_check
  2023-09-20 11:10 [PATCH 0/8] drm: Reuse temporary memory for format conversion Thomas Zimmermann
                   ` (2 preceding siblings ...)
  2023-09-20 11:10 ` [PATCH 3/8] drm/simpledrm: Store xfrm buffer in device instance Thomas Zimmermann
@ 2023-09-20 11:10 ` Thomas Zimmermann
  2023-09-20 11:10 ` [PATCH 5/8] drm/ofdrm: Store xfrm buffer in device instance Thomas Zimmermann
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Thomas Zimmermann @ 2023-09-20 11:10 UTC (permalink / raw)
  To: javierm, jfalempe, jose.exposito89, arthurgrillo, mairacanal,
	maarten.lankhorst, mripard, airlied, daniel, noralf
  Cc: Thomas Zimmermann, dri-devel

Preallocate the xfrm buffer's storage in the plane's atomic_check
function if a format conversion will be necessary. Allows the update
to fail if no memory is available. Avoids the same allocation within
atomic_update, which may not fail.

Also inline drm_plane_helper_atomic_check() into the driver and thus
return early for invisible planes. Avoids memory allocation entirely
in this case.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/tiny/simpledrm.c | 38 +++++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 31fc32a00d0a5..8ccd95795ecc8 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -18,6 +18,7 @@
 #include <drm/drm_drv.h>
 #include <drm/drm_fbdev_generic.h>
 #include <drm/drm_format_helper.h>
+#include <drm/drm_framebuffer.h>
 #include <drm/drm_gem_atomic_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_gem_shmem_helper.h>
@@ -478,6 +479,41 @@ static const uint64_t simpledrm_primary_plane_format_modifiers[] = {
 	DRM_FORMAT_MOD_INVALID
 };
 
+static int simpledrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
+						       struct drm_atomic_state *state)
+{
+	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
+	struct drm_framebuffer *new_fb = new_plane_state->fb;
+	struct drm_crtc *new_crtc = new_plane_state->crtc;
+	struct drm_crtc_state *new_crtc_state = NULL;
+	struct drm_device *dev = plane->dev;
+	struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
+	int ret;
+
+	if (new_crtc)
+		new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
+
+	ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
+						  DRM_PLANE_NO_SCALING,
+						  DRM_PLANE_NO_SCALING,
+						  false, false);
+	if (ret)
+		return ret;
+	else if (!new_plane_state->visible)
+		return 0;
+
+	if (new_fb->format != sdev->format) {
+		/* format conversion necessary; reserve buffer */
+		void *buf;
+
+		buf = drm_xfrm_buf_reserve(&sdev->xfrm, sdev->pitch, GFP_KERNEL);
+		if (!buf)
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
 static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane,
 							 struct drm_atomic_state *state)
 {
@@ -534,7 +570,7 @@ static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plan
 
 static const struct drm_plane_helper_funcs simpledrm_primary_plane_helper_funcs = {
 	DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
-	.atomic_check = drm_plane_helper_atomic_check,
+	.atomic_check = simpledrm_primary_plane_helper_atomic_check,
 	.atomic_update = simpledrm_primary_plane_helper_atomic_update,
 	.atomic_disable = simpledrm_primary_plane_helper_atomic_disable,
 };
-- 
2.42.0


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

* [PATCH 5/8] drm/ofdrm: Store xfrm buffer in device instance
  2023-09-20 11:10 [PATCH 0/8] drm: Reuse temporary memory for format conversion Thomas Zimmermann
                   ` (3 preceding siblings ...)
  2023-09-20 11:10 ` [PATCH 4/8] drm/simpledrm: Preallocate xfrm buffer in plane's atomic_check Thomas Zimmermann
@ 2023-09-20 11:10 ` Thomas Zimmermann
  2023-09-20 11:10 ` [PATCH 6/8] drm/ofdrm: Preallocate xfrm buffer in plane's atomic_check Thomas Zimmermann
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Thomas Zimmermann @ 2023-09-20 11:10 UTC (permalink / raw)
  To: javierm, jfalempe, jose.exposito89, arthurgrillo, mairacanal,
	maarten.lankhorst, mripard, airlied, daniel, noralf
  Cc: Thomas Zimmermann, dri-devel

Store and instance of struct drm_xfrm_buf in struct ofdrm_device and
keep the allocated memory allocated across display updates. Avoid
possibly reallocating temporary memory on each display update. Unloading
the DRM device also releases the xfrm buffer.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/tiny/ofdrm.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c
index 1add55c872670..08e4b04e0590e 100644
--- a/drivers/gpu/drm/tiny/ofdrm.c
+++ b/drivers/gpu/drm/tiny/ofdrm.c
@@ -301,6 +301,7 @@ struct ofdrm_device {
 	struct drm_display_mode mode;
 	const struct drm_format_info *format;
 	unsigned int pitch;
+	struct drm_xfrm_buf xfrm;
 
 	/* colormap */
 	void __iomem *cmap_base;
@@ -796,7 +797,6 @@ static void ofdrm_primary_plane_helper_atomic_update(struct drm_plane *plane,
 	struct drm_framebuffer *fb = plane_state->fb;
 	unsigned int dst_pitch = odev->pitch;
 	const struct drm_format_info *dst_format = odev->format;
-	struct drm_xfrm_buf xfrm = DRM_XFRM_BUF_INIT;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect damage;
 	int ret, idx;
@@ -818,13 +818,12 @@ static void ofdrm_primary_plane_helper_atomic_update(struct drm_plane *plane,
 
 		iosys_map_incr(&dst, drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip));
 		drm_fb_blit(&dst, &dst_pitch, dst_format->format, shadow_plane_state->data, fb,
-			    &damage, &xfrm);
+			    &damage, &odev->xfrm);
 	}
 
 	drm_dev_exit(idx);
 out_drm_gem_fb_end_cpu_access:
 	drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
-	drm_xfrm_buf_release(&xfrm);
 }
 
 static void ofdrm_primary_plane_helper_atomic_disable(struct drm_plane *plane,
@@ -1248,6 +1247,10 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
 	drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, linebytes=%d byte\n",
 		&format->format, width, height, linebytes);
 
+	ret = drmm_xfrm_buf_init(dev, &odev->xfrm);
+	if (ret)
+		return ERR_PTR(ret);
+
 	/*
 	 * Mode-setting pipeline
 	 */
-- 
2.42.0


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

* [PATCH 6/8] drm/ofdrm: Preallocate xfrm buffer in plane's atomic_check
  2023-09-20 11:10 [PATCH 0/8] drm: Reuse temporary memory for format conversion Thomas Zimmermann
                   ` (4 preceding siblings ...)
  2023-09-20 11:10 ` [PATCH 5/8] drm/ofdrm: Store xfrm buffer in device instance Thomas Zimmermann
@ 2023-09-20 11:10 ` Thomas Zimmermann
  2023-09-20 11:10 ` [PATCH 7/8] drm/ssd130x: Store xfrm buffer in device instance Thomas Zimmermann
  2023-09-20 11:10 ` [PATCH 8/8] drm/ssd130x: Preallocate xfrm buffer in plane's atomic_check Thomas Zimmermann
  7 siblings, 0 replies; 11+ messages in thread
From: Thomas Zimmermann @ 2023-09-20 11:10 UTC (permalink / raw)
  To: javierm, jfalempe, jose.exposito89, arthurgrillo, mairacanal,
	maarten.lankhorst, mripard, airlied, daniel, noralf
  Cc: Thomas Zimmermann, dri-devel

Preallocate the xfrm buffer's storage in the plane's atomic_check
function if a format conversion will be necessary. Allows the update
to fail if no memory is available. Avoids the same allocation within
atomic_update, which may not fail.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/tiny/ofdrm.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c
index 08e4b04e0590e..d81b986f5cbc6 100644
--- a/drivers/gpu/drm/tiny/ofdrm.c
+++ b/drivers/gpu/drm/tiny/ofdrm.c
@@ -759,6 +759,8 @@ static const uint64_t ofdrm_primary_plane_format_modifiers[] = {
 static int ofdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
 						   struct drm_atomic_state *new_state)
 {
+	struct drm_device *dev = plane->dev;
+	struct ofdrm_device *odev = ofdrm_device_of_dev(dev);
 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane);
 	struct drm_framebuffer *new_fb = new_plane_state->fb;
 	struct drm_crtc *new_crtc = new_plane_state->crtc;
@@ -778,6 +780,15 @@ static int ofdrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
 	else if (!new_plane_state->visible)
 		return 0;
 
+	if (new_fb->format != odev->format) {
+		void *buf;
+
+		/* format conversion necessary; reserve buffer */
+		buf = drm_xfrm_buf_reserve(&odev->xfrm, odev->pitch, GFP_KERNEL);
+		if (!buf)
+			return -ENOMEM;
+	}
+
 	new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc);
 
 	new_ofdrm_crtc_state = to_ofdrm_crtc_state(new_crtc_state);
-- 
2.42.0


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

* [PATCH 7/8] drm/ssd130x: Store xfrm buffer in device instance
  2023-09-20 11:10 [PATCH 0/8] drm: Reuse temporary memory for format conversion Thomas Zimmermann
                   ` (5 preceding siblings ...)
  2023-09-20 11:10 ` [PATCH 6/8] drm/ofdrm: Preallocate xfrm buffer in plane's atomic_check Thomas Zimmermann
@ 2023-09-20 11:10 ` Thomas Zimmermann
  2023-09-20 11:10 ` [PATCH 8/8] drm/ssd130x: Preallocate xfrm buffer in plane's atomic_check Thomas Zimmermann
  7 siblings, 0 replies; 11+ messages in thread
From: Thomas Zimmermann @ 2023-09-20 11:10 UTC (permalink / raw)
  To: javierm, jfalempe, jose.exposito89, arthurgrillo, mairacanal,
	maarten.lankhorst, mripard, airlied, daniel, noralf
  Cc: Thomas Zimmermann, dri-devel

Store and instance of struct drm_xfrm_buf in struct ssd130x_device and
keep the allocated memory allocated across display updates. Avoid
possibly reallocating temporary memory on each display update. Unloading
the DRM device also releases the xfrm buffer.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/solomon/ssd130x.c | 9 +++++----
 drivers/gpu/drm/solomon/ssd130x.h | 3 +++
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c
index d11079733bc0e..508588bd2d565 100644
--- a/drivers/gpu/drm/solomon/ssd130x.c
+++ b/drivers/gpu/drm/solomon/ssd130x.c
@@ -571,7 +571,6 @@ static int ssd130x_fb_blit_rect(struct drm_plane_state *state,
 	struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev);
 	unsigned int page_height = ssd130x->device_info->page_height;
 	struct ssd130x_plane_state *ssd130x_state = to_ssd130x_plane_state(state);
-	struct drm_xfrm_buf xfrm = DRM_XFRM_BUF_INIT;
 	u8 *buf = ssd130x_state->buffer;
 	struct iosys_map dst;
 	unsigned int dst_pitch;
@@ -588,14 +587,12 @@ static int ssd130x_fb_blit_rect(struct drm_plane_state *state,
 		return ret;
 
 	iosys_map_set_vaddr(&dst, buf);
-	drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, vmap, fb, rect, &xfrm);
+	drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, vmap, fb, rect, &ssd130x->xfrm);
 
 	drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
 
 	ssd130x_update_rect(ssd130x, ssd130x_state, rect);
 
-	drm_xfrm_buf_release(&xfrm);
-
 	return ret;
 }
 
@@ -1117,6 +1114,10 @@ struct ssd130x_device *ssd130x_probe(struct device *dev, struct regmap *regmap)
 	bl->props.max_brightness = MAX_CONTRAST;
 	ssd130x->bl_dev = bl;
 
+	ret = drmm_xfrm_buf_init(drm, &ssd130x->xfrm);
+	if (ret)
+		return ERR_PTR(ret);
+
 	ret = ssd130x_init_modeset(ssd130x);
 	if (ret)
 		return ERR_PTR(ret);
diff --git a/drivers/gpu/drm/solomon/ssd130x.h b/drivers/gpu/drm/solomon/ssd130x.h
index 87968b3e7fb82..f4e525feb2188 100644
--- a/drivers/gpu/drm/solomon/ssd130x.h
+++ b/drivers/gpu/drm/solomon/ssd130x.h
@@ -17,6 +17,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_encoder.h>
+#include <drm/drm_format_helper.h>
 #include <drm/drm_plane_helper.h>
 
 #include <linux/regmap.h>
@@ -55,6 +56,8 @@ struct ssd130x_device {
 	struct drm_connector connector;
 	struct i2c_client *client;
 
+	struct drm_xfrm_buf xfrm;
+
 	struct regmap *regmap;
 
 	const struct ssd130x_deviceinfo *device_info;
-- 
2.42.0


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

* [PATCH 8/8] drm/ssd130x: Preallocate xfrm buffer in plane's atomic_check
  2023-09-20 11:10 [PATCH 0/8] drm: Reuse temporary memory for format conversion Thomas Zimmermann
                   ` (6 preceding siblings ...)
  2023-09-20 11:10 ` [PATCH 7/8] drm/ssd130x: Store xfrm buffer in device instance Thomas Zimmermann
@ 2023-09-20 11:10 ` Thomas Zimmermann
  2023-09-20 11:30   ` Thomas Zimmermann
  7 siblings, 1 reply; 11+ messages in thread
From: Thomas Zimmermann @ 2023-09-20 11:10 UTC (permalink / raw)
  To: javierm, jfalempe, jose.exposito89, arthurgrillo, mairacanal,
	maarten.lankhorst, mripard, airlied, daniel, noralf
  Cc: Thomas Zimmermann, dri-devel

Preallocate the xfrm buffer's storage in the plane's atomic_check
function if a format conversion will be necessary. Allows the update
to fail if no memory is available. Avoids the same allocation within
atomic_update, which may not fail.

Also inline drm_plane_helper_atomic_check() into the driver and thus
return early for invisible planes. Avoids memory allocation entirely
in this case.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/solomon/ssd130x.c | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c
index 508588bd2d565..3788d847e50ff 100644
--- a/drivers/gpu/drm/solomon/ssd130x.c
+++ b/drivers/gpu/drm/solomon/ssd130x.c
@@ -601,17 +601,27 @@ static int ssd130x_primary_plane_helper_atomic_check(struct drm_plane *plane,
 {
 	struct drm_device *drm = plane->dev;
 	struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);
-	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
-	struct ssd130x_plane_state *ssd130x_state = to_ssd130x_plane_state(plane_state);
+	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
+	struct ssd130x_plane_state *ssd130x_state = to_ssd130x_plane_state(new_plane_state);
+	struct drm_crtc *new_crtc = new_plane_state->crtc;
+	struct drm_crtc_state *new_crtc_state = NULL;
 	unsigned int page_height = ssd130x->device_info->page_height;
 	unsigned int pages = DIV_ROUND_UP(ssd130x->height, page_height);
 	const struct drm_format_info *fi;
 	unsigned int pitch;
 	int ret;
 
-	ret = drm_plane_helper_atomic_check(plane, state);
+	if (new_crtc)
+		new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
+
+	ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
+						  DRM_PLANE_NO_SCALING,
+						  DRM_PLANE_NO_SCALING,
+						  false, false);
 	if (ret)
 		return ret;
+	else if (!new_plane_state->visible)
+		return 0;
 
 	fi = drm_format_info(DRM_FORMAT_R1);
 	if (!fi)
@@ -619,6 +629,15 @@ static int ssd130x_primary_plane_helper_atomic_check(struct drm_plane *plane,
 
 	pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width);
 
+	if (new_plane_state->fb->format != fi) {
+		void *buf;
+
+		/* format conversion necessary; reserve buffer */
+		buf = drm_xfrm_buf_reserve(&ssd130x->xfrm, pitch, GFP_KERNEL);
+		if (!buf)
+			return -ENOMEM;
+	}
+
 	ssd130x_state->buffer = kcalloc(pitch, ssd130x->height, GFP_KERNEL);
 	if (!ssd130x_state->buffer)
 		return -ENOMEM;
-- 
2.42.0


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

* Re: [PATCH 8/8] drm/ssd130x: Preallocate xfrm buffer in plane's atomic_check
  2023-09-20 11:10 ` [PATCH 8/8] drm/ssd130x: Preallocate xfrm buffer in plane's atomic_check Thomas Zimmermann
@ 2023-09-20 11:30   ` Thomas Zimmermann
  0 siblings, 0 replies; 11+ messages in thread
From: Thomas Zimmermann @ 2023-09-20 11:30 UTC (permalink / raw)
  To: javierm, jfalempe, jose.exposito89, arthurgrillo, mairacanal,
	maarten.lankhorst, mripard, airlied, daniel, noralf
  Cc: dri-devel


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



Am 20.09.23 um 13:10 schrieb Thomas Zimmermann:
[...]
>   	if (!fi)
> @@ -619,6 +629,15 @@ static int ssd130x_primary_plane_helper_atomic_check(struct drm_plane *plane,
>   
>   	pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width);
>   
> +	if (new_plane_state->fb->format != fi) {
> +		void *buf;
> +
> +		/* format conversion necessary; reserve buffer */
> +		buf = drm_xfrm_buf_reserve(&ssd130x->xfrm, pitch, GFP_KERNEL);
> +		if (!buf)
> +			return -ENOMEM;
> +	}

Grrr! Right in the moment I sent this patch, I realized that this code 
would run concurrently with atomic_update. Hence, it cannot realloc the 
temporary buffer.

I think drivers could also pre-allocate in the device's probe function 
after calling drmm_xfrm_buf_init(). It's just enough memory for a single 
scanline.


> +
>   	ssd130x_state->buffer = kcalloc(pitch, ssd130x->height, GFP_KERNEL);
>   	if (!ssd130x_state->buffer)
>   		return -ENOMEM;

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

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

* Re: [PATCH 2/8] drm/format-helper: Pass xfrm buffer to format-conversion helpers
  2023-09-20 11:10 ` [PATCH 2/8] drm/format-helper: Pass xfrm buffer to format-conversion helpers Thomas Zimmermann
@ 2023-09-20 11:40   ` Jani Nikula
  0 siblings, 0 replies; 11+ messages in thread
From: Jani Nikula @ 2023-09-20 11:40 UTC (permalink / raw)
  To: Thomas Zimmermann, javierm, jfalempe, jose.exposito89,
	arthurgrillo, mairacanal, maarten.lankhorst, mripard, airlied,
	daniel, noralf
  Cc: dri-devel, David Lechner, Thomas Zimmermann, Gerd Hoffmann

On Wed, 20 Sep 2023, Thomas Zimmermann <tzimmermann@suse.de> wrote:
> diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c
> index 1a6bd291345de..c6deabb6c64e5 100644
> --- a/drivers/gpu/drm/tests/drm_format_helper_test.c
> +++ b/drivers/gpu/drm/tests/drm_format_helper_test.c
> @@ -20,6 +20,10 @@
>  
>  #define TEST_USE_DEFAULT_PITCH 0
>  
> +static unsigned char conversion_buf_mem[PAGE_SIZE];
> +static struct drm_xfrm_buf xfrm =
> +	DRM_XFRM_BUF_INIT_PREALLOCATED(conversion_buf_mem, ARRAY_SIZE(conversion_buf_mem));
> +

Just something that caught my eye, that should be sizeof() instead of
ARRAY_SIZE(), I think, even though makes no difference for unsigned
char.

BR,
Jani.


-- 
Jani Nikula, Intel

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

end of thread, other threads:[~2023-09-20 11:40 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-09-20 11:10 [PATCH 0/8] drm: Reuse temporary memory for format conversion Thomas Zimmermann
2023-09-20 11:10 ` [PATCH 1/8] drm/format-helper: Add struct drm_xfrm_buf to cache " Thomas Zimmermann
2023-09-20 11:10 ` [PATCH 2/8] drm/format-helper: Pass xfrm buffer to format-conversion helpers Thomas Zimmermann
2023-09-20 11:40   ` Jani Nikula
2023-09-20 11:10 ` [PATCH 3/8] drm/simpledrm: Store xfrm buffer in device instance Thomas Zimmermann
2023-09-20 11:10 ` [PATCH 4/8] drm/simpledrm: Preallocate xfrm buffer in plane's atomic_check Thomas Zimmermann
2023-09-20 11:10 ` [PATCH 5/8] drm/ofdrm: Store xfrm buffer in device instance Thomas Zimmermann
2023-09-20 11:10 ` [PATCH 6/8] drm/ofdrm: Preallocate xfrm buffer in plane's atomic_check Thomas Zimmermann
2023-09-20 11:10 ` [PATCH 7/8] drm/ssd130x: Store xfrm buffer in device instance Thomas Zimmermann
2023-09-20 11:10 ` [PATCH 8/8] drm/ssd130x: Preallocate xfrm buffer in plane's atomic_check Thomas Zimmermann
2023-09-20 11:30   ` Thomas Zimmermann

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.