Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/tilcdc: Fix removal actions in case of failed probe

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

authored by

Kory Maincent (TI.com) and committed by
Douglas Anderson
a585c7ef 491adc6a

+37 -20
+1 -1
drivers/gpu/drm/tilcdc/tilcdc_crtc.c
··· 586 586 drm_modeset_unlock(&crtc->mutex); 587 587 } 588 588 589 - static void tilcdc_crtc_destroy(struct drm_crtc *crtc) 589 + void tilcdc_crtc_destroy(struct drm_crtc *crtc) 590 590 { 591 591 struct tilcdc_drm_private *priv = crtc->dev->dev_private; 592 592
+35 -18
drivers/gpu/drm/tilcdc/tilcdc_drv.c
··· 172 172 if (priv->crtc) 173 173 tilcdc_crtc_shutdown(priv->crtc); 174 174 175 - if (priv->is_registered) 176 - drm_dev_unregister(dev); 175 + drm_dev_unregister(dev); 177 176 178 177 drm_kms_helper_poll_fini(dev); 179 178 drm_atomic_helper_shutdown(dev); ··· 219 220 priv->wq = alloc_ordered_workqueue("tilcdc", 0); 220 221 if (!priv->wq) { 221 222 ret = -ENOMEM; 222 - goto init_failed; 223 + goto put_drm; 223 224 } 224 225 225 226 priv->mmio = devm_platform_ioremap_resource(pdev, 0); 226 227 if (IS_ERR(priv->mmio)) { 227 228 dev_err(dev, "failed to request / ioremap\n"); 228 229 ret = PTR_ERR(priv->mmio); 229 - goto init_failed; 230 + goto free_wq; 230 231 } 231 232 232 233 priv->clk = clk_get(dev, "fck"); 233 234 if (IS_ERR(priv->clk)) { 234 235 dev_err(dev, "failed to get functional clock\n"); 235 236 ret = -ENODEV; 236 - goto init_failed; 237 + goto free_wq; 237 238 } 238 239 239 240 pm_runtime_enable(dev); ··· 312 313 ret = tilcdc_crtc_create(ddev); 313 314 if (ret < 0) { 314 315 dev_err(dev, "failed to create crtc\n"); 315 - goto init_failed; 316 + goto disable_pm; 316 317 } 317 318 modeset_init(ddev); 318 319 ··· 323 324 if (ret) { 324 325 dev_err(dev, "failed to register cpufreq notifier\n"); 325 326 priv->freq_transition.notifier_call = NULL; 326 - goto init_failed; 327 + goto destroy_crtc; 327 328 } 328 329 #endif 329 330 330 331 if (priv->is_componentized) { 331 332 ret = component_bind_all(dev, ddev); 332 333 if (ret < 0) 333 - goto init_failed; 334 + goto unregister_cpufreq_notif; 334 335 335 336 ret = tilcdc_add_component_encoder(ddev); 336 337 if (ret < 0) 337 - goto init_failed; 338 + goto unbind_component; 338 339 } else { 339 340 ret = tilcdc_attach_external_device(ddev); 340 341 if (ret) 341 - goto init_failed; 342 + goto unregister_cpufreq_notif; 342 343 } 343 344 344 345 if (!priv->external_connector && 345 346 ((priv->num_encoders == 0) || (priv->num_connectors == 0))) { 346 347 dev_err(dev, "no encoders/connectors found\n"); 347 348 ret = -EPROBE_DEFER; 348 - goto init_failed; 349 + goto unbind_component; 349 350 } 350 351 351 352 ret = drm_vblank_init(ddev, 1); 352 353 if (ret < 0) { 353 354 dev_err(dev, "failed to initialize vblank\n"); 354 - goto init_failed; 355 + goto unbind_component; 355 356 } 356 357 357 358 ret = platform_get_irq(pdev, 0); 358 359 if (ret < 0) 359 - goto init_failed; 360 + goto unbind_component; 360 361 priv->irq = ret; 361 362 362 363 ret = tilcdc_irq_install(ddev, priv->irq); 363 364 if (ret < 0) { 364 365 dev_err(dev, "failed to install IRQ handler\n"); 365 - goto init_failed; 366 + goto unbind_component; 366 367 } 367 368 368 369 drm_mode_config_reset(ddev); ··· 371 372 372 373 ret = drm_dev_register(ddev, 0); 373 374 if (ret) 374 - goto init_failed; 375 - priv->is_registered = true; 375 + goto stop_poll; 376 376 377 377 drm_client_setup_with_color_mode(ddev, bpp); 378 378 379 379 return 0; 380 380 381 - init_failed: 382 - tilcdc_fini(ddev); 381 + stop_poll: 382 + drm_kms_helper_poll_fini(ddev); 383 + tilcdc_irq_uninstall(ddev); 384 + unbind_component: 385 + if (priv->is_componentized) 386 + component_unbind_all(dev, ddev); 387 + unregister_cpufreq_notif: 388 + #ifdef CONFIG_CPU_FREQ 389 + cpufreq_unregister_notifier(&priv->freq_transition, 390 + CPUFREQ_TRANSITION_NOTIFIER); 391 + destroy_crtc: 392 + #endif 393 + tilcdc_crtc_destroy(priv->crtc); 394 + disable_pm: 395 + pm_runtime_disable(dev); 396 + clk_put(priv->clk); 397 + free_wq: 398 + destroy_workqueue(priv->wq); 399 + put_drm: 383 400 platform_set_drvdata(pdev, NULL); 401 + ddev->dev_private = NULL; 402 + drm_dev_put(ddev); 384 403 385 404 return ret; 386 405 }
+1 -1
drivers/gpu/drm/tilcdc/tilcdc_drv.h
··· 82 82 struct drm_encoder *external_encoder; 83 83 struct drm_connector *external_connector; 84 84 85 - bool is_registered; 86 85 bool is_componentized; 87 86 bool irq_enabled; 88 87 }; ··· 163 164 void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc, 164 165 bool simulate_vesa_sync); 165 166 void tilcdc_crtc_shutdown(struct drm_crtc *crtc); 167 + void tilcdc_crtc_destroy(struct drm_crtc *crtc); 166 168 int tilcdc_crtc_update_fb(struct drm_crtc *crtc, 167 169 struct drm_framebuffer *fb, 168 170 struct drm_pending_vblank_event *event);