[PATCH 48/72] imx-drm: hdmi: rework irq request/free
Steve Longerbeam
slongerbeam at gmail.com
Fri Oct 31 15:54:31 PDT 2014
Rearrange how HDMI driver requests and frees irq. Currently the driver
has two problems:
1) if imx_hdmi_register() fails, irq still can trigger and cause oops
2) irq is enabled too early, before all fields are initialized, so
triggered irq can cause oops.
Fix by moving irq request and activation to very end of imx_hdmi_bind(),
especially after imx_hdmi_register(). Then there's no possible way there
could be a (spurious) interrupt after a failed imx_hdmi_register() but
before the irq is freed.
Signed-off-by: Dmitry Eremin-Solenikov <dmitry_eremin at mentor.com>
Signed-off-by: Steve Longerbeam <steve_longerbeam at mentor.com>
---
drivers/staging/imx-drm/imx-hdmi.c | 33 +++++++++++++++++++--------------
1 file changed, 19 insertions(+), 14 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 801a3eb..db3906f 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -122,6 +122,7 @@ struct imx_hdmi {
struct hdmi_data_info hdmi_data;
int vic;
+ int irq;
u8 edid[HDMI_EDID_LEN];
bool cable_plugin;
@@ -1593,7 +1594,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
struct device_node *ddc_node;
struct imx_hdmi *hdmi;
struct resource *iores;
- int ret, irq;
+ int ret;
hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
@@ -1620,16 +1621,6 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
dev_dbg(hdmi->dev, "no ddc property found\n");
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
- imx_hdmi_irq, IRQF_SHARED,
- dev_name(dev), hdmi);
- if (ret)
- return ret;
-
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hdmi->regs = devm_ioremap_resource(dev, iores);
if (IS_ERR(hdmi->regs))
@@ -1685,6 +1676,10 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
*/
hdmi_init_clk_regenerator(hdmi);
+ ret = imx_hdmi_register(drm, hdmi);
+ if (ret)
+ goto err_isfr;
+
/*
* Configure registers related to HDMI interrupt
* generation before registering IRQ.
@@ -1694,14 +1689,21 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
/* Clear Hotplug interrupts */
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
- ret = imx_hdmi_fb_registered(hdmi);
- if (ret)
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
goto err_iahb;
+ hdmi->irq = ret;
- ret = imx_hdmi_register(drm, hdmi);
+ ret = devm_request_threaded_irq(dev, hdmi->irq, imx_hdmi_hardirq,
+ imx_hdmi_irq, IRQF_SHARED,
+ dev_name(dev), hdmi);
if (ret)
goto err_iahb;
+ ret = imx_hdmi_fb_registered(hdmi);
+ if (ret)
+ goto err_irq;
+
/* Unmute interrupts */
hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
@@ -1709,6 +1711,8 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
return 0;
+err_irq:
+ devm_free_irq(dev, hdmi->irq, hdmi);
err_iahb:
clk_disable_unprepare(hdmi->iahb_clk);
err_isfr:
@@ -1724,6 +1728,7 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
/* Disable all interrupts */
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+ devm_free_irq(dev, hdmi->irq, hdmi);
hdmi->connector.funcs->destroy(&hdmi->connector);
hdmi->encoder.funcs->destroy(&hdmi->encoder);
--
1.7.9.5
More information about the dri-devel
mailing list