drm/vc4: hdmi: Drop devm interrupt handler for CEC interrupts
The CEC interrupt handlers are registered through the devm_request_threaded_irq function. However, while free_irq is indeed called properly when the device is unbound or bind fails, it's called after unbind or bind is done. In our particular case, it means that on failure it creates a window where our interrupt handler can be called, but we're freeing every resource (CEC adapter, DRM objects, etc.) it might need. In order to address this, let's switch to the non-devm variant to control better when the handler will be unregistered and allow us to make it safe. Fixes: 15b4511a4af6 ("drm/vc4: add HDMI CEC support") Signed-off-by: Maxime Ripard <maxime@cerno.tech> Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com> Link: https://patchwork.freedesktop.org/patch/msgid/20210707095112.1469670-2-maxime@cerno.tech
This commit is contained in:
parent
9e5c772954
commit
32a19de21a
@ -1857,38 +1857,46 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
|
||||
vc4_hdmi_cec_update_clk_div(vc4_hdmi);
|
||||
|
||||
if (vc4_hdmi->variant->external_irq_controller) {
|
||||
ret = devm_request_threaded_irq(&pdev->dev,
|
||||
platform_get_irq_byname(pdev, "cec-rx"),
|
||||
vc4_cec_irq_handler_rx_bare,
|
||||
vc4_cec_irq_handler_rx_thread, 0,
|
||||
"vc4 hdmi cec rx", vc4_hdmi);
|
||||
ret = request_threaded_irq(platform_get_irq_byname(pdev, "cec-rx"),
|
||||
vc4_cec_irq_handler_rx_bare,
|
||||
vc4_cec_irq_handler_rx_thread, 0,
|
||||
"vc4 hdmi cec rx", vc4_hdmi);
|
||||
if (ret)
|
||||
goto err_delete_cec_adap;
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev,
|
||||
platform_get_irq_byname(pdev, "cec-tx"),
|
||||
vc4_cec_irq_handler_tx_bare,
|
||||
vc4_cec_irq_handler_tx_thread, 0,
|
||||
"vc4 hdmi cec tx", vc4_hdmi);
|
||||
ret = request_threaded_irq(platform_get_irq_byname(pdev, "cec-tx"),
|
||||
vc4_cec_irq_handler_tx_bare,
|
||||
vc4_cec_irq_handler_tx_thread, 0,
|
||||
"vc4 hdmi cec tx", vc4_hdmi);
|
||||
if (ret)
|
||||
goto err_delete_cec_adap;
|
||||
goto err_remove_cec_rx_handler;
|
||||
} else {
|
||||
HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff);
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, platform_get_irq(pdev, 0),
|
||||
vc4_cec_irq_handler,
|
||||
vc4_cec_irq_handler_thread, 0,
|
||||
"vc4 hdmi cec", vc4_hdmi);
|
||||
ret = request_threaded_irq(platform_get_irq(pdev, 0),
|
||||
vc4_cec_irq_handler,
|
||||
vc4_cec_irq_handler_thread, 0,
|
||||
"vc4 hdmi cec", vc4_hdmi);
|
||||
if (ret)
|
||||
goto err_delete_cec_adap;
|
||||
}
|
||||
|
||||
ret = cec_register_adapter(vc4_hdmi->cec_adap, &pdev->dev);
|
||||
if (ret < 0)
|
||||
goto err_delete_cec_adap;
|
||||
goto err_remove_handlers;
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_handlers:
|
||||
if (vc4_hdmi->variant->external_irq_controller)
|
||||
free_irq(platform_get_irq_byname(pdev, "cec-tx"), vc4_hdmi);
|
||||
else
|
||||
free_irq(platform_get_irq(pdev, 0), vc4_hdmi);
|
||||
|
||||
err_remove_cec_rx_handler:
|
||||
if (vc4_hdmi->variant->external_irq_controller)
|
||||
free_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_hdmi);
|
||||
|
||||
err_delete_cec_adap:
|
||||
cec_delete_adapter(vc4_hdmi->cec_adap);
|
||||
|
||||
@ -1897,6 +1905,15 @@ err_delete_cec_adap:
|
||||
|
||||
static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
struct platform_device *pdev = vc4_hdmi->pdev;
|
||||
|
||||
if (vc4_hdmi->variant->external_irq_controller) {
|
||||
free_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_hdmi);
|
||||
free_irq(platform_get_irq_byname(pdev, "cec-tx"), vc4_hdmi);
|
||||
} else {
|
||||
free_irq(platform_get_irq(pdev, 0), vc4_hdmi);
|
||||
}
|
||||
|
||||
cec_unregister_adapter(vc4_hdmi->cec_adap);
|
||||
}
|
||||
#else
|
||||
|
Loading…
x
Reference in New Issue
Block a user