Skip to content

Commit 32a19de

Browse files
committed
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: 15b4511 ("drm/vc4: add HDMI CEC support") Signed-off-by: Maxime Ripard <[email protected]> Reviewed-by: Dave Stevenson <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 9e5c772 commit 32a19de

File tree

1 file changed

+33
-16
lines changed

1 file changed

+33
-16
lines changed

drivers/gpu/drm/vc4/vc4_hdmi.c

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1857,38 +1857,46 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
18571857
vc4_hdmi_cec_update_clk_div(vc4_hdmi);
18581858

18591859
if (vc4_hdmi->variant->external_irq_controller) {
1860-
ret = devm_request_threaded_irq(&pdev->dev,
1861-
platform_get_irq_byname(pdev, "cec-rx"),
1862-
vc4_cec_irq_handler_rx_bare,
1863-
vc4_cec_irq_handler_rx_thread, 0,
1864-
"vc4 hdmi cec rx", vc4_hdmi);
1860+
ret = request_threaded_irq(platform_get_irq_byname(pdev, "cec-rx"),
1861+
vc4_cec_irq_handler_rx_bare,
1862+
vc4_cec_irq_handler_rx_thread, 0,
1863+
"vc4 hdmi cec rx", vc4_hdmi);
18651864
if (ret)
18661865
goto err_delete_cec_adap;
18671866

1868-
ret = devm_request_threaded_irq(&pdev->dev,
1869-
platform_get_irq_byname(pdev, "cec-tx"),
1870-
vc4_cec_irq_handler_tx_bare,
1871-
vc4_cec_irq_handler_tx_thread, 0,
1872-
"vc4 hdmi cec tx", vc4_hdmi);
1867+
ret = request_threaded_irq(platform_get_irq_byname(pdev, "cec-tx"),
1868+
vc4_cec_irq_handler_tx_bare,
1869+
vc4_cec_irq_handler_tx_thread, 0,
1870+
"vc4 hdmi cec tx", vc4_hdmi);
18731871
if (ret)
1874-
goto err_delete_cec_adap;
1872+
goto err_remove_cec_rx_handler;
18751873
} else {
18761874
HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff);
18771875

1878-
ret = devm_request_threaded_irq(&pdev->dev, platform_get_irq(pdev, 0),
1879-
vc4_cec_irq_handler,
1880-
vc4_cec_irq_handler_thread, 0,
1881-
"vc4 hdmi cec", vc4_hdmi);
1876+
ret = request_threaded_irq(platform_get_irq(pdev, 0),
1877+
vc4_cec_irq_handler,
1878+
vc4_cec_irq_handler_thread, 0,
1879+
"vc4 hdmi cec", vc4_hdmi);
18821880
if (ret)
18831881
goto err_delete_cec_adap;
18841882
}
18851883

18861884
ret = cec_register_adapter(vc4_hdmi->cec_adap, &pdev->dev);
18871885
if (ret < 0)
1888-
goto err_delete_cec_adap;
1886+
goto err_remove_handlers;
18891887

18901888
return 0;
18911889

1890+
err_remove_handlers:
1891+
if (vc4_hdmi->variant->external_irq_controller)
1892+
free_irq(platform_get_irq_byname(pdev, "cec-tx"), vc4_hdmi);
1893+
else
1894+
free_irq(platform_get_irq(pdev, 0), vc4_hdmi);
1895+
1896+
err_remove_cec_rx_handler:
1897+
if (vc4_hdmi->variant->external_irq_controller)
1898+
free_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_hdmi);
1899+
18921900
err_delete_cec_adap:
18931901
cec_delete_adapter(vc4_hdmi->cec_adap);
18941902

@@ -1897,6 +1905,15 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
18971905

18981906
static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi)
18991907
{
1908+
struct platform_device *pdev = vc4_hdmi->pdev;
1909+
1910+
if (vc4_hdmi->variant->external_irq_controller) {
1911+
free_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_hdmi);
1912+
free_irq(platform_get_irq_byname(pdev, "cec-tx"), vc4_hdmi);
1913+
} else {
1914+
free_irq(platform_get_irq(pdev, 0), vc4_hdmi);
1915+
}
1916+
19001917
cec_unregister_adapter(vc4_hdmi->cec_adap);
19011918
}
19021919
#else

0 commit comments

Comments
 (0)