[PATCH 1/4] drm/client: Add client free callback to unprepare fb_helper
From: Thomas Zimmermann <tzimmermann@suse.de>
Date: 2025-10-09 13:23:03
Also in:
amd-gfx, dri-devel, intel-gfx, linux-arm-kernel, linux-arm-msm, linux-samsung-soc, linux-tegra
Subsystem:
drm driver for qualcomm display hardware, drm drivers, drm drivers and misc gpu patches, drm drivers for exynos, drm drivers for gma500 (poulsbo, moorestown and derivative chipsets), drm drivers for nvidia tegra, drm drivers for ti omap, intel drm display for xe and i915 drivers, intel drm i915 driver (meteor lake, dg2 and older excluding poulsbo, moorestown and derivative), marvell armada drm support, radeon and amdgpu drm drivers, the rest · Maintainers:
Rob Clark, Dmitry Baryshkov, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Inki Dae, Seung-Woo Kim, Kyungmin Park, Patrik Jakobsson, Thierry Reding, Mikko Perttunen, Tomi Valkeinen, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin, Russell King, Alex Deucher, Christian König, Linus Torvalds
Add free callback to struct drm_client_funcs. Invoke function to free the client memory as part of the release process. Implement free for fbdev emulation. Fbdev emulation allocates and prepares client memory in drm_fbdev_client_setup(). The release happens in fb_destroy from struct fb_ops. Multiple implementations of this callback exist in the various drivers that provide fbdev implementation. Each of them needs to follow the implementation details of the fbdev setup code. Adding a free callback for the client puts the unprepare and release of the fbdev client in a single place. Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> --- drivers/gpu/drm/armada/armada_fbdev.c | 2 -- drivers/gpu/drm/clients/drm_fbdev_client.c | 17 +++++++++++++++-- drivers/gpu/drm/drm_client.c | 4 ++++ drivers/gpu/drm/drm_fbdev_dma.c | 4 ---- drivers/gpu/drm/drm_fbdev_shmem.c | 2 -- drivers/gpu/drm/drm_fbdev_ttm.c | 2 -- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 2 -- drivers/gpu/drm/gma500/fbdev.c | 3 --- drivers/gpu/drm/i915/display/intel_fbdev.c | 2 -- drivers/gpu/drm/msm/msm_fbdev.c | 2 -- drivers/gpu/drm/omapdrm/omap_fbdev.c | 2 -- drivers/gpu/drm/radeon/radeon_fbdev.c | 2 -- drivers/gpu/drm/tegra/fbdev.c | 2 -- include/drm/drm_client.h | 10 ++++++++++ 14 files changed, 29 insertions(+), 27 deletions(-)
diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c
index cb53cc91bafb..22e2081bfa04 100644
--- a/drivers/gpu/drm/armada/armada_fbdev.c
+++ b/drivers/gpu/drm/armada/armada_fbdev.c@@ -28,8 +28,6 @@ static void armada_fbdev_fb_destroy(struct fb_info *info) fbh->fb->funcs->destroy(fbh->fb); drm_client_release(&fbh->client); - drm_fb_helper_unprepare(fbh); - kfree(fbh); } static const struct fb_ops armada_fb_ops = {
diff --git a/drivers/gpu/drm/clients/drm_fbdev_client.c b/drivers/gpu/drm/clients/drm_fbdev_client.c
index f894ba52bdb5..5336accab1b6 100644
--- a/drivers/gpu/drm/clients/drm_fbdev_client.c
+++ b/drivers/gpu/drm/clients/drm_fbdev_client.c@@ -13,16 +13,28 @@ * struct drm_client_funcs */ +static void drm_fbdev_client_free(struct drm_client_dev *client) +{ + struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); + + drm_fb_helper_unprepare(fb_helper); + kfree(fb_helper); +} + static void drm_fbdev_client_unregister(struct drm_client_dev *client) { struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); if (fb_helper->info) { + /* + * Fully probed framebuffer device + */ drm_fb_helper_unregister_info(fb_helper); } else { + /* + * Partially initialized client, no framebuffer device yet + */ drm_client_release(&fb_helper->client); - drm_fb_helper_unprepare(fb_helper); - kfree(fb_helper); } }
@@ -88,6 +100,7 @@ static int drm_fbdev_client_resume(struct drm_client_dev *client, bool holds_con static const struct drm_client_funcs drm_fbdev_client_funcs = { .owner = THIS_MODULE, + .free = drm_fbdev_client_free, .unregister = drm_fbdev_client_unregister, .restore = drm_fbdev_client_restore, .hotplug = drm_fbdev_client_hotplug,
diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 3fa38d4ac70b..fe9c6d7083ea 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c@@ -168,6 +168,10 @@ void drm_client_release(struct drm_client_dev *client) drm_client_modeset_free(client); drm_client_close(client); + + if (client->funcs && client->funcs->free) + client->funcs->free(client); + drm_dev_put(dev); } EXPORT_SYMBOL(drm_client_release);
diff --git a/drivers/gpu/drm/drm_fbdev_dma.c b/drivers/gpu/drm/drm_fbdev_dma.c
index 8bd626ef16c7..c6196293e424 100644
--- a/drivers/gpu/drm/drm_fbdev_dma.c
+++ b/drivers/gpu/drm/drm_fbdev_dma.c@@ -57,8 +57,6 @@ static void drm_fbdev_dma_fb_destroy(struct fb_info *info) drm_client_buffer_vunmap(fb_helper->buffer); drm_client_framebuffer_delete(fb_helper->buffer); drm_client_release(&fb_helper->client); - drm_fb_helper_unprepare(fb_helper); - kfree(fb_helper); } static const struct fb_ops drm_fbdev_dma_fb_ops = {
@@ -92,8 +90,6 @@ static void drm_fbdev_dma_shadowed_fb_destroy(struct fb_info *info) drm_client_buffer_vunmap(fb_helper->buffer); drm_client_framebuffer_delete(fb_helper->buffer); drm_client_release(&fb_helper->client); - drm_fb_helper_unprepare(fb_helper); - kfree(fb_helper); } static const struct fb_ops drm_fbdev_dma_shadowed_fb_ops = {
diff --git a/drivers/gpu/drm/drm_fbdev_shmem.c b/drivers/gpu/drm/drm_fbdev_shmem.c
index 1e827bf8b815..51573058df6f 100644
--- a/drivers/gpu/drm/drm_fbdev_shmem.c
+++ b/drivers/gpu/drm/drm_fbdev_shmem.c@@ -65,8 +65,6 @@ static void drm_fbdev_shmem_fb_destroy(struct fb_info *info) drm_client_buffer_vunmap(fb_helper->buffer); drm_client_framebuffer_delete(fb_helper->buffer); drm_client_release(&fb_helper->client); - drm_fb_helper_unprepare(fb_helper); - kfree(fb_helper); } static const struct fb_ops drm_fbdev_shmem_fb_ops = {
diff --git a/drivers/gpu/drm/drm_fbdev_ttm.c b/drivers/gpu/drm/drm_fbdev_ttm.c
index 85feb55bba11..ccf460fbc1f0 100644
--- a/drivers/gpu/drm/drm_fbdev_ttm.c
+++ b/drivers/gpu/drm/drm_fbdev_ttm.c@@ -53,8 +53,6 @@ static void drm_fbdev_ttm_fb_destroy(struct fb_info *info) drm_client_framebuffer_delete(fb_helper->buffer); drm_client_release(&fb_helper->client); - drm_fb_helper_unprepare(fb_helper); - kfree(fb_helper); } static const struct fb_ops drm_fbdev_ttm_fb_ops = {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 93de25b77e68..a3bd21a827ad 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c@@ -42,8 +42,6 @@ static void exynos_drm_fb_destroy(struct fb_info *info) drm_framebuffer_remove(fb); drm_client_release(&fb_helper->client); - drm_fb_helper_unprepare(fb_helper); - kfree(fb_helper); } static const struct fb_ops exynos_drm_fb_ops = {
diff --git a/drivers/gpu/drm/gma500/fbdev.c b/drivers/gpu/drm/gma500/fbdev.c
index a6af21514cff..bc92fa24a1e2 100644
--- a/drivers/gpu/drm/gma500/fbdev.c
+++ b/drivers/gpu/drm/gma500/fbdev.c@@ -84,9 +84,6 @@ static void psb_fbdev_fb_destroy(struct fb_info *info) drm_gem_object_put(obj); drm_client_release(&fb_helper->client); - - drm_fb_helper_unprepare(fb_helper); - kfree(fb_helper); } static const struct fb_ops psb_fbdev_fb_ops = {
diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c
index 3fbdf75415cc..d5f26c8bb102 100644
--- a/drivers/gpu/drm/i915/display/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/display/intel_fbdev.c@@ -146,8 +146,6 @@ static void intel_fbdev_fb_destroy(struct fb_info *info) drm_framebuffer_remove(fb_helper->fb); drm_client_release(&fb_helper->client); - drm_fb_helper_unprepare(fb_helper); - kfree(fb_helper); } __diag_push();
diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c
index b5969374d53f..aad6fb77f0de 100644
--- a/drivers/gpu/drm/msm/msm_fbdev.c
+++ b/drivers/gpu/drm/msm/msm_fbdev.c@@ -52,8 +52,6 @@ static void msm_fbdev_fb_destroy(struct fb_info *info) drm_framebuffer_remove(fb); drm_client_release(&helper->client); - drm_fb_helper_unprepare(helper); - kfree(helper); } static const struct fb_ops msm_fb_ops = {
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index 948af7ec1130..b5df2923d2a6 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c@@ -103,8 +103,6 @@ static void omap_fbdev_fb_destroy(struct fb_info *info) drm_framebuffer_remove(fb); drm_client_release(&helper->client); - drm_fb_helper_unprepare(helper); - kfree(helper); } /*
diff --git a/drivers/gpu/drm/radeon/radeon_fbdev.c b/drivers/gpu/drm/radeon/radeon_fbdev.c
index dc81b0c2dbff..4df6c9167bf0 100644
--- a/drivers/gpu/drm/radeon/radeon_fbdev.c
+++ b/drivers/gpu/drm/radeon/radeon_fbdev.c@@ -184,8 +184,6 @@ static void radeon_fbdev_fb_destroy(struct fb_info *info) radeon_fbdev_destroy_pinned_object(gobj); drm_client_release(&fb_helper->client); - drm_fb_helper_unprepare(fb_helper); - kfree(fb_helper); } static const struct fb_ops radeon_fbdev_fb_ops = {
diff --git a/drivers/gpu/drm/tegra/fbdev.c b/drivers/gpu/drm/tegra/fbdev.c
index 1b70f5e164af..91aece6f34e0 100644
--- a/drivers/gpu/drm/tegra/fbdev.c
+++ b/drivers/gpu/drm/tegra/fbdev.c@@ -53,8 +53,6 @@ static void tegra_fbdev_fb_destroy(struct fb_info *info) drm_framebuffer_remove(fb); drm_client_release(&helper->client); - drm_fb_helper_unprepare(helper); - kfree(helper); } static const struct fb_ops tegra_fb_ops = {
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index bdd845e383ef..eecb8d6e15c7 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h@@ -28,6 +28,16 @@ struct drm_client_funcs { */ struct module *owner; + /** + * @free: + * + * Called when the client gets unregistered. Implementations should + * release all client-specific data and free the memory. + * + * This callback is optional. + */ + void (*free)(struct drm_client_dev *client); + /** * @unregister: *
--
2.51.0