[PATCH 48/72] imx-drm: hdmi: rework irq request/free

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>
Signed-off-by: Steve Longerbeam <steve_longerbeam@xxxxxxxxxx>
---
 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

_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/dri-devel





[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux