diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 72139ddcede6087ad9ef9d590ee18007b302b8a9..229d4974067758d63dc4737cdb3dc0bad429d2ec 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -259,13 +259,24 @@ static int msm_drm_uninit(struct device *dev) struct msm_mdss *mdss = priv->mdss; int i; + /* + * Shutdown the hw if we're far enough along where things might be on. + * If we run this too early, we'll end up panicking in any variety of + * places. Since we don't register the drm device until late in + * msm_drm_init, drm_dev->registered is used as an indicator that the + * shutdown will be successful. + */ + if (ddev->registered) { + drm_dev_unregister(ddev); + drm_atomic_helper_shutdown(ddev); + } + /* We must cancel and cleanup any pending vblank enable/disable * work before drm_irq_uninstall() to avoid work re-enabling an * irq after uninstall has disabled it. */ flush_workqueue(priv->wq); - destroy_workqueue(priv->wq); /* clean up event worker threads */ for (i = 0; i < priv->num_crtcs; i++) { @@ -279,8 +290,6 @@ static int msm_drm_uninit(struct device *dev) drm_kms_helper_poll_fini(ddev); - drm_dev_unregister(ddev); - msm_perf_debugfs_cleanup(priv); msm_rd_debugfs_cleanup(priv); @@ -288,7 +297,7 @@ static int msm_drm_uninit(struct device *dev) if (fbdev && priv->fbdev) msm_fbdev_free(ddev); #endif - drm_atomic_helper_shutdown(ddev); + drm_mode_config_cleanup(ddev); pm_runtime_get_sync(dev); @@ -313,6 +322,7 @@ static int msm_drm_uninit(struct device *dev) ddev->dev_private = NULL; drm_dev_put(ddev); + destroy_workqueue(priv->wq); kfree(priv); return 0;