]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/tilcdc: Fix removal actions in case of failed probe
authorKory Maincent (TI.com) <kory.maincent@bootlin.com>
Tue, 25 Nov 2025 09:05:44 +0000 (10:05 +0100)
committerDouglas Anderson <dianders@chromium.org>
Mon, 8 Dec 2025 21:54:25 +0000 (13:54 -0800)
The drm_kms_helper_poll_fini() and drm_atomic_helper_shutdown() helpers
should only be called when the device has been successfully registered.
Currently, these functions are called unconditionally in tilcdc_fini(),
which causes warnings during probe deferral scenarios.

[    7.972317] WARNING: CPU: 0 PID: 23 at drivers/gpu/drm/drm_atomic_state_helper.c:175 drm_atomic_helper_crtc_duplicate_state+0x60/0x68
...
[    8.005820]  drm_atomic_helper_crtc_duplicate_state from drm_atomic_get_crtc_state+0x68/0x108
[    8.005858]  drm_atomic_get_crtc_state from drm_atomic_helper_disable_all+0x90/0x1c8
[    8.005885]  drm_atomic_helper_disable_all from drm_atomic_helper_shutdown+0x90/0x144
[    8.005911]  drm_atomic_helper_shutdown from tilcdc_fini+0x68/0xf8 [tilcdc]
[    8.005957]  tilcdc_fini [tilcdc] from tilcdc_pdev_probe+0xb0/0x6d4 [tilcdc]

Fix this by rewriting the failed probe cleanup path using the standard
goto error handling pattern, which ensures that cleanup functions are
only called on successfully initialized resources. Additionally, remove
the now-unnecessary is_registered flag.

Cc: stable@vger.kernel.org
Fixes: 3c4babae3c4a ("drm: Call drm_atomic_helper_shutdown() at shutdown/remove time for misc drivers")
Signed-off-by: Kory Maincent (TI.com) <kory.maincent@bootlin.com>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Link: https://patch.msgid.link/20251125090546.137193-1-kory.maincent@bootlin.com
drivers/gpu/drm/tilcdc/tilcdc_crtc.c
drivers/gpu/drm/tilcdc/tilcdc_drv.c
drivers/gpu/drm/tilcdc/tilcdc_drv.h

index b5f60b2b2d0e72ae8ec0f3f4e5e85bc5004e6e5b..41802c9bd14759b22bce69902462bef38f1bb24b 100644 (file)
@@ -586,7 +586,7 @@ out:
        drm_modeset_unlock(&crtc->mutex);
 }
 
-static void tilcdc_crtc_destroy(struct drm_crtc *crtc)
+void tilcdc_crtc_destroy(struct drm_crtc *crtc)
 {
        struct tilcdc_drm_private *priv = crtc->dev->dev_private;
 
index 7caec4d38ddf0ce97b5806c585468530cc3e6a60..3dcbec312bacb4bc02494e8b7eb3eaf253ee8fea 100644 (file)
@@ -172,8 +172,7 @@ static void tilcdc_fini(struct drm_device *dev)
        if (priv->crtc)
                tilcdc_crtc_shutdown(priv->crtc);
 
-       if (priv->is_registered)
-               drm_dev_unregister(dev);
+       drm_dev_unregister(dev);
 
        drm_kms_helper_poll_fini(dev);
        drm_atomic_helper_shutdown(dev);
@@ -220,21 +219,21 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
        priv->wq = alloc_ordered_workqueue("tilcdc", 0);
        if (!priv->wq) {
                ret = -ENOMEM;
-               goto init_failed;
+               goto put_drm;
        }
 
        priv->mmio = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->mmio)) {
                dev_err(dev, "failed to request / ioremap\n");
                ret = PTR_ERR(priv->mmio);
-               goto init_failed;
+               goto free_wq;
        }
 
        priv->clk = clk_get(dev, "fck");
        if (IS_ERR(priv->clk)) {
                dev_err(dev, "failed to get functional clock\n");
                ret = -ENODEV;
-               goto init_failed;
+               goto free_wq;
        }
 
        pm_runtime_enable(dev);
@@ -313,7 +312,7 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
        ret = tilcdc_crtc_create(ddev);
        if (ret < 0) {
                dev_err(dev, "failed to create crtc\n");
-               goto init_failed;
+               goto disable_pm;
        }
        modeset_init(ddev);
 
@@ -324,46 +323,46 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
        if (ret) {
                dev_err(dev, "failed to register cpufreq notifier\n");
                priv->freq_transition.notifier_call = NULL;
-               goto init_failed;
+               goto destroy_crtc;
        }
 #endif
 
        if (priv->is_componentized) {
                ret = component_bind_all(dev, ddev);
                if (ret < 0)
-                       goto init_failed;
+                       goto unregister_cpufreq_notif;
 
                ret = tilcdc_add_component_encoder(ddev);
                if (ret < 0)
-                       goto init_failed;
+                       goto unbind_component;
        } else {
                ret = tilcdc_attach_external_device(ddev);
                if (ret)
-                       goto init_failed;
+                       goto unregister_cpufreq_notif;
        }
 
        if (!priv->external_connector &&
            ((priv->num_encoders == 0) || (priv->num_connectors == 0))) {
                dev_err(dev, "no encoders/connectors found\n");
                ret = -EPROBE_DEFER;
-               goto init_failed;
+               goto unbind_component;
        }
 
        ret = drm_vblank_init(ddev, 1);
        if (ret < 0) {
                dev_err(dev, "failed to initialize vblank\n");
-               goto init_failed;
+               goto unbind_component;
        }
 
        ret = platform_get_irq(pdev, 0);
        if (ret < 0)
-               goto init_failed;
+               goto unbind_component;
        priv->irq = ret;
 
        ret = tilcdc_irq_install(ddev, priv->irq);
        if (ret < 0) {
                dev_err(dev, "failed to install IRQ handler\n");
-               goto init_failed;
+               goto unbind_component;
        }
 
        drm_mode_config_reset(ddev);
@@ -372,16 +371,34 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev)
 
        ret = drm_dev_register(ddev, 0);
        if (ret)
-               goto init_failed;
-       priv->is_registered = true;
+               goto stop_poll;
 
        drm_client_setup_with_color_mode(ddev, bpp);
 
        return 0;
 
-init_failed:
-       tilcdc_fini(ddev);
+stop_poll:
+       drm_kms_helper_poll_fini(ddev);
+       tilcdc_irq_uninstall(ddev);
+unbind_component:
+       if (priv->is_componentized)
+               component_unbind_all(dev, ddev);
+unregister_cpufreq_notif:
+#ifdef CONFIG_CPU_FREQ
+       cpufreq_unregister_notifier(&priv->freq_transition,
+                                   CPUFREQ_TRANSITION_NOTIFIER);
+destroy_crtc:
+#endif
+       tilcdc_crtc_destroy(priv->crtc);
+disable_pm:
+       pm_runtime_disable(dev);
+       clk_put(priv->clk);
+free_wq:
+       destroy_workqueue(priv->wq);
+put_drm:
        platform_set_drvdata(pdev, NULL);
+       ddev->dev_private = NULL;
+       drm_dev_put(ddev);
 
        return ret;
 }
index b818448c83f612b03f0eba000e3b9a278454647a..58b276f82a669a0d32fcebb6f4024960195b6f26 100644 (file)
@@ -82,7 +82,6 @@ struct tilcdc_drm_private {
        struct drm_encoder *external_encoder;
        struct drm_connector *external_connector;
 
-       bool is_registered;
        bool is_componentized;
        bool irq_enabled;
 };
@@ -164,6 +163,7 @@ void tilcdc_crtc_set_panel_info(struct drm_crtc *crtc,
 void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc,
                                        bool simulate_vesa_sync);
 void tilcdc_crtc_shutdown(struct drm_crtc *crtc);
+void tilcdc_crtc_destroy(struct drm_crtc *crtc);
 int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
                struct drm_framebuffer *fb,
                struct drm_pending_vblank_event *event);