mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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: 643231b283 ("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: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230216140620.17699-1-tzimmermann@suse.de
			
			
This commit is contained in:
		
							parent
							
								
									fb073aa27a
								
							
						
					
					
						commit
						3fb1f62f80
					
				
					 10 changed files with 17 additions and 3 deletions
				
			
		| 
						 | 
					@ -147,6 +147,7 @@ int armada_fbdev_init(struct drm_device *dev)
 | 
				
			||||||
 err_fb_setup:
 | 
					 err_fb_setup:
 | 
				
			||||||
	drm_fb_helper_fini(fbh);
 | 
						drm_fb_helper_fini(fbh);
 | 
				
			||||||
 err_fb_helper:
 | 
					 err_fb_helper:
 | 
				
			||||||
 | 
						drm_fb_helper_unprepare(fbh);
 | 
				
			||||||
	priv->fbdev = NULL;
 | 
						priv->fbdev = NULL;
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -164,6 +165,8 @@ void armada_fbdev_fini(struct drm_device *dev)
 | 
				
			||||||
		if (fbh->fb)
 | 
							if (fbh->fb)
 | 
				
			||||||
			fbh->fb->funcs->destroy(fbh->fb);
 | 
								fbh->fb->funcs->destroy(fbh->fb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							drm_fb_helper_unprepare(fbh);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		priv->fbdev = NULL;
 | 
							priv->fbdev = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -590,8 +590,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mutex_unlock(&kernel_fb_helper_lock);
 | 
						mutex_unlock(&kernel_fb_helper_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm_fb_helper_unprepare(fb_helper);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!fb_helper->client.funcs)
 | 
						if (!fb_helper->client.funcs)
 | 
				
			||||||
		drm_client_release(&fb_helper->client);
 | 
							drm_client_release(&fb_helper->client);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,6 +65,8 @@ static void drm_fbdev_fb_destroy(struct fb_info *info)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm_client_framebuffer_delete(fb_helper->buffer);
 | 
						drm_client_framebuffer_delete(fb_helper->buffer);
 | 
				
			||||||
	drm_client_release(&fb_helper->client);
 | 
						drm_client_release(&fb_helper->client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						drm_fb_helper_unprepare(fb_helper);
 | 
				
			||||||
	kfree(fb_helper);
 | 
						kfree(fb_helper);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -183,8 +183,8 @@ int exynos_drm_fbdev_init(struct drm_device *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_setup:
 | 
					err_setup:
 | 
				
			||||||
	drm_fb_helper_fini(helper);
 | 
						drm_fb_helper_fini(helper);
 | 
				
			||||||
 | 
					 | 
				
			||||||
err_init:
 | 
					err_init:
 | 
				
			||||||
 | 
						drm_fb_helper_unprepare(helper);
 | 
				
			||||||
	private->fb_helper = NULL;
 | 
						private->fb_helper = NULL;
 | 
				
			||||||
	kfree(fbdev);
 | 
						kfree(fbdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -219,6 +219,7 @@ void exynos_drm_fbdev_fini(struct drm_device *dev)
 | 
				
			||||||
	fbdev = to_exynos_fbdev(private->fb_helper);
 | 
						fbdev = to_exynos_fbdev(private->fb_helper);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	exynos_drm_fbdev_destroy(dev, private->fb_helper);
 | 
						exynos_drm_fbdev_destroy(dev, private->fb_helper);
 | 
				
			||||||
 | 
						drm_fb_helper_unprepare(private->fb_helper);
 | 
				
			||||||
	kfree(fbdev);
 | 
						kfree(fbdev);
 | 
				
			||||||
	private->fb_helper = NULL;
 | 
						private->fb_helper = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -427,6 +427,7 @@ int psb_fbdev_init(struct drm_device *dev)
 | 
				
			||||||
fini:
 | 
					fini:
 | 
				
			||||||
	drm_fb_helper_fini(fb_helper);
 | 
						drm_fb_helper_fini(fb_helper);
 | 
				
			||||||
free:
 | 
					free:
 | 
				
			||||||
 | 
						drm_fb_helper_unprepare(fb_helper);
 | 
				
			||||||
	kfree(fb_helper);
 | 
						kfree(fb_helper);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -439,6 +440,7 @@ static void psb_fbdev_fini(struct drm_device *dev)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	psb_fbdev_destroy(dev, dev_priv->fb_helper);
 | 
						psb_fbdev_destroy(dev, dev_priv->fb_helper);
 | 
				
			||||||
 | 
						drm_fb_helper_unprepare(dev_priv->fb_helper);
 | 
				
			||||||
	kfree(dev_priv->fb_helper);
 | 
						kfree(dev_priv->fb_helper);
 | 
				
			||||||
	dev_priv->fb_helper = NULL;
 | 
						dev_priv->fb_helper = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -340,6 +340,7 @@ static void intel_fbdev_destroy(struct intel_fbdev *ifbdev)
 | 
				
			||||||
	if (ifbdev->fb)
 | 
						if (ifbdev->fb)
 | 
				
			||||||
		drm_framebuffer_remove(&ifbdev->fb->base);
 | 
							drm_framebuffer_remove(&ifbdev->fb->base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						drm_fb_helper_unprepare(&ifbdev->helper);
 | 
				
			||||||
	kfree(ifbdev);
 | 
						kfree(ifbdev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -170,6 +170,7 @@ struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev)
 | 
				
			||||||
fini:
 | 
					fini:
 | 
				
			||||||
	drm_fb_helper_fini(helper);
 | 
						drm_fb_helper_fini(helper);
 | 
				
			||||||
fail:
 | 
					fail:
 | 
				
			||||||
 | 
						drm_fb_helper_unprepare(helper);
 | 
				
			||||||
	kfree(fbdev);
 | 
						kfree(fbdev);
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -196,6 +197,7 @@ void msm_fbdev_free(struct drm_device *dev)
 | 
				
			||||||
		drm_framebuffer_remove(fbdev->fb);
 | 
							drm_framebuffer_remove(fbdev->fb);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						drm_fb_helper_unprepare(helper);
 | 
				
			||||||
	kfree(fbdev);
 | 
						kfree(fbdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	priv->fbdev = NULL;
 | 
						priv->fbdev = NULL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -256,6 +256,7 @@ void omap_fbdev_init(struct drm_device *dev)
 | 
				
			||||||
fini:
 | 
					fini:
 | 
				
			||||||
	drm_fb_helper_fini(helper);
 | 
						drm_fb_helper_fini(helper);
 | 
				
			||||||
fail:
 | 
					fail:
 | 
				
			||||||
 | 
						drm_fb_helper_unprepare(helper);
 | 
				
			||||||
	kfree(fbdev);
 | 
						kfree(fbdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_warn(dev->dev, "omap_fbdev_init failed\n");
 | 
						dev_warn(dev->dev, "omap_fbdev_init failed\n");
 | 
				
			||||||
| 
						 | 
					@ -286,6 +287,7 @@ void omap_fbdev_fini(struct drm_device *dev)
 | 
				
			||||||
	if (fbdev->fb)
 | 
						if (fbdev->fb)
 | 
				
			||||||
		drm_framebuffer_remove(fbdev->fb);
 | 
							drm_framebuffer_remove(fbdev->fb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						drm_fb_helper_unprepare(helper);
 | 
				
			||||||
	kfree(fbdev);
 | 
						kfree(fbdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	priv->fbdev = NULL;
 | 
						priv->fbdev = NULL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -367,6 +367,7 @@ int radeon_fbdev_init(struct radeon_device *rdev)
 | 
				
			||||||
fini:
 | 
					fini:
 | 
				
			||||||
	drm_fb_helper_fini(&rfbdev->helper);
 | 
						drm_fb_helper_fini(&rfbdev->helper);
 | 
				
			||||||
free:
 | 
					free:
 | 
				
			||||||
 | 
						drm_fb_helper_unprepare(&rfbdev->helper);
 | 
				
			||||||
	kfree(rfbdev);
 | 
						kfree(rfbdev);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -377,6 +378,7 @@ void radeon_fbdev_fini(struct radeon_device *rdev)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev);
 | 
						radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev);
 | 
				
			||||||
 | 
						drm_fb_helper_unprepare(&rdev->mode_info.rfbdev->helper);
 | 
				
			||||||
	kfree(rdev->mode_info.rfbdev);
 | 
						kfree(rdev->mode_info.rfbdev);
 | 
				
			||||||
	rdev->mode_info.rfbdev = NULL;
 | 
						rdev->mode_info.rfbdev = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -315,6 +315,7 @@ static struct tegra_fbdev *tegra_fbdev_create(struct drm_device *drm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void tegra_fbdev_free(struct tegra_fbdev *fbdev)
 | 
					static void tegra_fbdev_free(struct tegra_fbdev *fbdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						drm_fb_helper_unprepare(&fbdev->base);
 | 
				
			||||||
	kfree(fbdev);
 | 
						kfree(fbdev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue