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 an 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>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> # core, msm
Acked-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> # omapdrm
Acked-by: Patrik Jakobsson <patrik.r.jakobsson@gmail.com> # gma500
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Link: https://lore.kernel.org/r/20251009132006.45834-2-tzimmermann@suse.de
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 = {
* 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);
}
}
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,
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);
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 = {
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 = {
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 = {
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 = {
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 = {
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 = {
drm_framebuffer_remove(fb_helper->fb);
drm_client_release(&fb_helper->client);
- drm_fb_helper_unprepare(fb_helper);
- kfree(fb_helper);
}
__diag_push();
drm_framebuffer_remove(fb);
drm_client_release(&helper->client);
- drm_fb_helper_unprepare(helper);
- kfree(helper);
}
static const struct fb_ops msm_fb_ops = {
drm_framebuffer_remove(fb);
drm_client_release(&helper->client);
- drm_fb_helper_unprepare(helper);
- kfree(helper);
}
/*
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 = {
drm_framebuffer_remove(fb);
drm_client_release(&helper->client);
- drm_fb_helper_unprepare(helper);
- kfree(helper);
}
static const struct fb_ops tegra_fb_ops = {
*/
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:
*