Commit 3fb1f62f authored by Thomas Zimmermann's avatar Thomas Zimmermann
Browse files

drm/fb-helper: Remove drm_fb_helper_unprepare() from drm_fb_helper_fini()



Move drm_fb_helper_unprepare() from drm_fb_helper_fini() into the
calling fbdev implementation. Avoids a possible stale mutex with
generic fbdev code.

As indicated by its name, drm_fb_helper_prepare() prepares struct
drm_fb_helper before setting up the fbdev support with a call to
drm_fb_helper_init(). In legacy fbdev emulation, this happens next
to each other. If successful, drm_fb_helper_fini() later tear down
the fbdev device and also unprepare via drm_fb_helper_unprepare().

Generic fbdev emulation prepares struct drm_fb_helper immediately
after allocating the instance. It only calls drm_fb_helper_init()
as part of processing a hotplug event. If the hotplug-handling fails,
it runs drm_fb_helper_fini(). This unprepares the fb-helper instance
and the next hotplug event runs on stale data.

Solve this by moving drm_fb_helper_unprepare() from drm_fb_helper_fini()
into the fbdev implementations. Call it right before freeing the
fb-helper instance.

Fixes: 643231b2 ("drm/fbdev-generic: Minimize hotplug error handling")
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: Javier Martinez Canillas <javierm@redhat.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Maxime Ripard <mripard@kernel.org>
Cc: David Airlie <airlied@gmail.com>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: dri-devel@lists.freedesktop.org
Signed-off-by: default avatarThomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: default avatarJavier Martinez Canillas <javierm@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230216140620.17699-1-tzimmermann@suse.de
parent fb073aa2
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -147,6 +147,7 @@ int armada_fbdev_init(struct drm_device *dev)
 err_fb_setup:
	drm_fb_helper_fini(fbh);
 err_fb_helper:
	drm_fb_helper_unprepare(fbh);
	priv->fbdev = NULL;
	return ret;
}
@@ -164,6 +165,8 @@ void armada_fbdev_fini(struct drm_device *dev)
		if (fbh->fb)
			fbh->fb->funcs->destroy(fbh->fb);

		drm_fb_helper_unprepare(fbh);

		priv->fbdev = NULL;
	}
}
+0 −2
Original line number Diff line number Diff line
@@ -590,8 +590,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
	}
	mutex_unlock(&kernel_fb_helper_lock);

	drm_fb_helper_unprepare(fb_helper);

	if (!fb_helper->client.funcs)
		drm_client_release(&fb_helper->client);
}
+2 −0
Original line number Diff line number Diff line
@@ -65,6 +65,8 @@ static void drm_fbdev_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);
}

+2 −1
Original line number Diff line number Diff line
@@ -183,8 +183,8 @@ int exynos_drm_fbdev_init(struct drm_device *dev)

err_setup:
	drm_fb_helper_fini(helper);

err_init:
	drm_fb_helper_unprepare(helper);
	private->fb_helper = NULL;
	kfree(fbdev);

@@ -219,6 +219,7 @@ void exynos_drm_fbdev_fini(struct drm_device *dev)
	fbdev = to_exynos_fbdev(private->fb_helper);

	exynos_drm_fbdev_destroy(dev, private->fb_helper);
	drm_fb_helper_unprepare(private->fb_helper);
	kfree(fbdev);
	private->fb_helper = NULL;
}
+2 −0
Original line number Diff line number Diff line
@@ -427,6 +427,7 @@ int psb_fbdev_init(struct drm_device *dev)
fini:
	drm_fb_helper_fini(fb_helper);
free:
	drm_fb_helper_unprepare(fb_helper);
	kfree(fb_helper);
	return ret;
}
@@ -439,6 +440,7 @@ static void psb_fbdev_fini(struct drm_device *dev)
		return;

	psb_fbdev_destroy(dev, dev_priv->fb_helper);
	drm_fb_helper_unprepare(dev_priv->fb_helper);
	kfree(dev_priv->fb_helper);
	dev_priv->fb_helper = NULL;
}
Loading