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

drm/meson: fix unbind path if HDMI fails to bind

If the case the HDMI controller fails to bind, we try to unbind
all components before calling drm_dev_put() which makes drm_bridge_detach()
crash because unbinding the HDMI controller frees the bridge memory.

The solution is the unbind all components at the end like in the remove
path.

Reviewed-by: Nicolas Belin <nbelin@baylibre.com>
Tested-by: Nicolas Belin <nbelin@baylibre.com>
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230512-amlogic-v6-4-upstream-dsi-ccf-vim3-v5-8-56eb7a4d5b8e@linaro.org

+14 -9
+14 -9
drivers/gpu/drm/meson/meson_drv.c
··· 316 316 goto exit_afbcd; 317 317 318 318 if (has_components) { 319 - ret = component_bind_all(drm->dev, drm); 319 + ret = component_bind_all(dev, drm); 320 320 if (ret) { 321 321 dev_err(drm->dev, "Couldn't bind all components\n"); 322 + /* Do not try to unbind */ 323 + has_components = false; 322 324 goto exit_afbcd; 323 325 } 324 326 } 325 327 326 328 ret = meson_encoder_hdmi_init(priv); 327 329 if (ret) 328 - goto unbind_all; 330 + goto exit_afbcd; 329 331 330 332 ret = meson_plane_create(priv); 331 333 if (ret) 332 - goto unbind_all; 334 + goto exit_afbcd; 333 335 334 336 ret = meson_overlay_create(priv); 335 337 if (ret) 336 - goto unbind_all; 338 + goto exit_afbcd; 337 339 338 340 ret = meson_crtc_create(priv); 339 341 if (ret) 340 - goto unbind_all; 342 + goto exit_afbcd; 341 343 342 344 ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm); 343 345 if (ret) 344 - goto unbind_all; 346 + goto exit_afbcd; 345 347 346 348 drm_mode_config_reset(drm); 347 349 ··· 361 359 362 360 uninstall_irq: 363 361 free_irq(priv->vsync_irq, drm); 364 - unbind_all: 365 - if (has_components) 366 - component_unbind_all(drm->dev, drm); 367 362 exit_afbcd: 368 363 if (priv->afbcd.ops) 369 364 priv->afbcd.ops->exit(priv); 370 365 free_drm: 371 366 drm_dev_put(drm); 367 + 368 + meson_encoder_hdmi_remove(priv); 369 + meson_encoder_cvbs_remove(priv); 370 + 371 + if (has_components) 372 + component_unbind_all(dev, drm); 372 373 373 374 return ret; 374 375 }