aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.10/950-0676-drm-vc4-hdmi-Drop-devm-interrupt-handler-for-hotplug.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/bcm27xx/patches-5.10/950-0676-drm-vc4-hdmi-Drop-devm-interrupt-handler-for-hotplug.patch')
-rw-r--r--target/linux/bcm27xx/patches-5.10/950-0676-drm-vc4-hdmi-Drop-devm-interrupt-handler-for-hotplug.patch111
1 files changed, 111 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.10/950-0676-drm-vc4-hdmi-Drop-devm-interrupt-handler-for-hotplug.patch b/target/linux/bcm27xx/patches-5.10/950-0676-drm-vc4-hdmi-Drop-devm-interrupt-handler-for-hotplug.patch
new file mode 100644
index 0000000000..0594e35dbe
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.10/950-0676-drm-vc4-hdmi-Drop-devm-interrupt-handler-for-hotplug.patch
@@ -0,0 +1,111 @@
+From fda46a52e84a5160d7277e55e1c1be376b0ba579 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime@cerno.tech>
+Date: Mon, 5 Jul 2021 17:31:48 +0200
+Subject: [PATCH] drm/vc4: hdmi: Drop devm interrupt handler for
+ hotplug interrupts
+
+The hotplugs 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: f4790083c7c2 ("drm/vc4: hdmi: Rely on interrupts to handle hotplug")
+Signed-off-by: Maxime Ripard <maxime@cerno.tech>
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 41 +++++++++++++++++++++++-----------
+ 1 file changed, 28 insertions(+), 13 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -1611,26 +1611,28 @@ static irqreturn_t vc4_hdmi_hpd_irq_thre
+ static int vc4_hdmi_hotplug_init(struct vc4_hdmi *vc4_hdmi)
+ {
+ struct platform_device *pdev = vc4_hdmi->pdev;
+- struct device *dev = &pdev->dev;
+ struct drm_connector *connector = &vc4_hdmi->connector;
+ int ret;
+
+ if (vc4_hdmi->variant->external_irq_controller) {
+- ret = devm_request_threaded_irq(dev,
+- platform_get_irq_byname(pdev, "hpd-connected"),
+- NULL,
+- vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
+- "vc4 hdmi hpd connected", vc4_hdmi);
++ unsigned int hpd_con = platform_get_irq_byname(pdev, "hpd-connected");
++ unsigned int hpd_rm = platform_get_irq_byname(pdev, "hpd-removed");
++
++ ret = request_threaded_irq(hpd_con,
++ NULL,
++ vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
++ "vc4 hdmi hpd connected", vc4_hdmi);
+ if (ret)
+ return ret;
+
+- ret = devm_request_threaded_irq(dev,
+- platform_get_irq_byname(pdev, "hpd-removed"),
+- NULL,
+- vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
+- "vc4 hdmi hpd disconnected", vc4_hdmi);
+- if (ret)
++ ret = request_threaded_irq(hpd_rm,
++ NULL,
++ vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
++ "vc4 hdmi hpd disconnected", vc4_hdmi);
++ if (ret) {
++ free_irq(hpd_con, vc4_hdmi);
+ return ret;
++ }
+
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+ }
+@@ -1638,6 +1640,16 @@ static int vc4_hdmi_hotplug_init(struct
+ return 0;
+ }
+
++static void vc4_hdmi_hotplug_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, "hpd-connected"), vc4_hdmi);
++ free_irq(platform_get_irq_byname(pdev, "hpd-removed"), vc4_hdmi);
++ }
++}
++
+ #ifdef CONFIG_DRM_VC4_HDMI_CEC
+ static irqreturn_t vc4_cec_irq_handler_rx_thread(int irq, void *priv)
+ {
+@@ -2299,7 +2311,7 @@ static int vc4_hdmi_bind(struct device *
+
+ ret = vc4_hdmi_cec_init(vc4_hdmi);
+ if (ret)
+- goto err_destroy_conn;
++ goto err_free_hotplug;
+
+ ret = vc4_hdmi_audio_init(vc4_hdmi);
+ if (ret)
+@@ -2313,6 +2325,8 @@ static int vc4_hdmi_bind(struct device *
+
+ err_free_cec:
+ vc4_hdmi_cec_exit(vc4_hdmi);
++err_free_hotplug:
++ vc4_hdmi_hotplug_exit(vc4_hdmi);
+ err_destroy_conn:
+ vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
+ err_destroy_encoder:
+@@ -2354,6 +2368,7 @@ static void vc4_hdmi_unbind(struct devic
+ kfree(vc4_hdmi->hd_regset.regs);
+
+ vc4_hdmi_cec_exit(vc4_hdmi);
++ vc4_hdmi_hotplug_exit(vc4_hdmi);
+ vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
+ drm_encoder_cleanup(&vc4_hdmi->encoder.base.base);
+