The platform devices registered in sysfb match with a firmware-based fbdev or DRM driver, that are used to have early graphics using framebuffers set up by the system firmware. Real DRM drivers later are probed and remove all conflicting framebuffers, leading to these platform devices for generic drivers to be unregistered. But the current solution has the problem that sysfb doesn't know when the device that registered is unregistered. This means that is not able to do any cleanup if needed since the device pointer may not be valid anymore. Not all platforms use sysfb to register the simple framebuffer devices, so an unregistration has to be forced by fbmem if sysfb_try_unregister() does not succeed at unregister the device. Suggested-by: Daniel Vetter <daniel.vetter@xxxxxxxx> Signed-off-by: Javier Martinez Canillas <javierm@xxxxxxxxxx> Reviewed-by: Daniel Vetter <daniel.vetter@xxxxxxxx> --- (no changes since v4) Changes in v4: - Drop call to sysfb_disable() in fbmem since is done in other places now. Changes in v2: - Explain in the commit message that fbmem has to unregister the device as fallback if a driver registered the device itself (Daniel Vetter). - Also explain that fallback in a comment in the code (Daniel Vetter). - Don't encode in fbmem the assumption that sysfb will always register platform devices (Daniel Vetter). - Add a FIXME comment about drivers registering devices (Daniel Vetter). drivers/video/fbdev/core/fbmem.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 2fda5917c212..9b035ef4d552 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/major.h> #include <linux/slab.h> +#include <linux/sysfb.h> #include <linux/mm.h> #include <linux/mman.h> #include <linux/vt.h> @@ -1587,18 +1588,35 @@ static void do_remove_conflicting_framebuffers(struct apertures_struct *a, if (!device) { pr_warn("fb%d: no device set\n", i); do_unregister_framebuffer(registered_fb[i]); - } else if (dev_is_platform(device)) { + } else { /* * Drop the lock because if the device is unregistered, its * driver will call to unregister_framebuffer(), that takes * this lock. */ mutex_unlock(®istration_lock); - platform_device_unregister(to_platform_device(device)); + /* + * First attempt the device to be unregistered by sysfb. + */ + if (!sysfb_try_unregister(device)) { + if (dev_is_platform(device)) { + /* + * FIXME: sysfb didn't register this device, the platform + * device was registered in other platform code. + */ + platform_device_unregister(to_platform_device(device)); + } else { + /* + * If is not a platform device, at least print a warning. A + * fix would add to make the code that registered the device + * to also unregister it. + */ + pr_warn("fb%d: cannot remove device\n", i); + /* call unregister_framebuffer() since the lock was dropped */ + unregister_framebuffer(registered_fb[i]); + } + } mutex_lock(®istration_lock); - } else { - pr_warn("fb%d: cannot remove device\n", i); - do_unregister_framebuffer(registered_fb[i]); } /* * Restart the removal loop now that the device has been -- 2.35.1