950-0675-drm-vc4-hdmi-Drop-devm-interrupt-handler-for-CEC-int.patch 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. From 687a0fc86f37e0bc74c8382c0d89b0929fade1de Mon Sep 17 00:00:00 2001
  2. From: Maxime Ripard <[email protected]>
  3. Date: Mon, 5 Jul 2021 15:47:43 +0200
  4. Subject: [PATCH] drm/vc4: hdmi: Drop devm interrupt handler for CEC
  5. interrupts
  6. The CEC interrupt handlers are registered through the
  7. devm_request_threaded_irq function. However, while free_irq is indeed
  8. called properly when the device is unbound or bind fails, it's called
  9. after unbind or bind is done.
  10. In our particular case, it means that on failure it creates a window
  11. where our interrupt handler can be called, but we're freeing every
  12. resource (CEC adapter, DRM objects, etc.) it might need.
  13. In order to address this, let's switch to the non-devm variant to
  14. control better when the handler will be unregistered and allow us to
  15. make it safe.
  16. Fixes: 15b4511a4af6 ("drm/vc4: add HDMI CEC support")
  17. Signed-off-by: Maxime Ripard <[email protected]>
  18. ---
  19. drivers/gpu/drm/vc4/vc4_hdmi.c | 49 +++++++++++++++++++++++-----------
  20. 1 file changed, 33 insertions(+), 16 deletions(-)
  21. --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
  22. +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
  23. @@ -1896,25 +1896,23 @@ static int vc4_hdmi_cec_init(struct vc4_
  24. vc4_hdmi_cec_update_clk_div(vc4_hdmi);
  25. if (vc4_hdmi->variant->external_irq_controller) {
  26. - ret = devm_request_threaded_irq(&pdev->dev,
  27. - platform_get_irq_byname(pdev, "cec-rx"),
  28. + ret = request_threaded_irq(platform_get_irq_byname(pdev, "cec-rx"),
  29. vc4_cec_irq_handler_rx_bare,
  30. vc4_cec_irq_handler_rx_thread, 0,
  31. "vc4 hdmi cec rx", vc4_hdmi);
  32. if (ret)
  33. goto err_delete_cec_adap;
  34. - ret = devm_request_threaded_irq(&pdev->dev,
  35. - platform_get_irq_byname(pdev, "cec-tx"),
  36. + ret = request_threaded_irq(platform_get_irq_byname(pdev, "cec-tx"),
  37. vc4_cec_irq_handler_tx_bare,
  38. vc4_cec_irq_handler_tx_thread, 0,
  39. "vc4 hdmi cec tx", vc4_hdmi);
  40. if (ret)
  41. - goto err_delete_cec_adap;
  42. + goto err_remove_cec_rx_handler;
  43. } else {
  44. HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff);
  45. - ret = devm_request_threaded_irq(&pdev->dev, platform_get_irq(pdev, 0),
  46. + ret = request_threaded_irq(platform_get_irq(pdev, 0),
  47. vc4_cec_irq_handler,
  48. vc4_cec_irq_handler_thread, 0,
  49. "vc4 hdmi cec", vc4_hdmi);
  50. @@ -1924,10 +1922,20 @@ static int vc4_hdmi_cec_init(struct vc4_
  51. ret = cec_register_adapter(vc4_hdmi->cec_adap, &pdev->dev);
  52. if (ret < 0)
  53. - goto err_delete_cec_adap;
  54. + goto err_remove_handlers;
  55. return 0;
  56. +err_remove_handlers:
  57. + if (vc4_hdmi->variant->external_irq_controller)
  58. + free_irq(platform_get_irq_byname(pdev, "cec-tx"), vc4_hdmi);
  59. + else
  60. + free_irq(platform_get_irq(pdev, 0), vc4_hdmi);
  61. +
  62. +err_remove_cec_rx_handler:
  63. + if (vc4_hdmi->variant->external_irq_controller)
  64. + free_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_hdmi);
  65. +
  66. err_delete_cec_adap:
  67. cec_delete_adapter(vc4_hdmi->cec_adap);
  68. @@ -1936,6 +1944,15 @@ err_delete_cec_adap:
  69. static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi)
  70. {
  71. + struct platform_device *pdev = vc4_hdmi->pdev;
  72. +
  73. + if (vc4_hdmi->variant->external_irq_controller) {
  74. + free_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_hdmi);
  75. + free_irq(platform_get_irq_byname(pdev, "cec-tx"), vc4_hdmi);
  76. + } else {
  77. + free_irq(platform_get_irq(pdev, 0), vc4_hdmi);
  78. + }
  79. +
  80. cec_unregister_adapter(vc4_hdmi->cec_adap);
  81. }
  82. #else