diff mbox

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

Message ID 1414796095-10107-49-git-send-email-steve_longerbeam@mentor.com (mailing list archive)
State New, archived
Headers show

Commit Message

Steve Longerbeam Oct. 31, 2014, 10:54 p.m. UTC
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@mentor.com>
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/imx-hdmi.c |   33 +++++++++++++++++++--------------
 1 file changed, 19 insertions(+), 14 deletions(-)
diff mbox

Patch

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);