rtc/mc13783: protect rtc {,un}registration by mc13783 lock
authorUwe Kleine-König <[email protected]>
Fri, 5 Mar 2010 21:44:30 +0000 (13:44 -0800)
committerLinus Torvalds <[email protected]>
Sat, 6 Mar 2010 19:26:47 +0000 (11:26 -0800)
This is to protect from interrupt handlers using an unregistered rtc
device.

To assert that the reset irq is considered now before the rtc is
registered the corresponding status is checked before.

Signed-off-by: Uwe Kleine-König <[email protected]>
Cc: Alessandro Zummo <[email protected]>
Cc: Paul Gortmaker <[email protected]>
Cc: Valentin Longchamp <[email protected]>
Cc: Sascha Hauer <[email protected]>
Cc: Samuel Ortiz <[email protected]>
Cc: Dmitry Torokhov <[email protected]>
Cc: Luotao Fu <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
drivers/rtc/rtc-mc13783.c

index 0a978a0e40fce6dcf65bdc3ecf6b9b54b61707d4..6a36201178a865cbf3fcf568a4b07d8883d5d0f8 100644 (file)
@@ -169,6 +169,7 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev)
 {
        int ret;
        struct mc13783_rtc *priv;
+       int rtcrst_pending;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -177,8 +178,6 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev)
        priv->mc13783 = dev_get_drvdata(pdev->dev.parent);
        platform_set_drvdata(pdev, priv);
 
-       priv->valid = 1;
-
        mc13783_lock(priv->mc13783);
 
        ret = mc13783_irq_request(priv->mc13783, MC13783_IRQ_RTCRST,
@@ -186,33 +185,37 @@ static int __devinit mc13783_rtc_probe(struct platform_device *pdev)
        if (ret)
                goto err_reset_irq_request;
 
+       ret = mc13783_irq_status(priv->mc13783, MC13783_IRQ_RTCRST,
+                       NULL, &rtcrst_pending);
+       if (ret)
+               goto err_reset_irq_status;
+
+       priv->valid = !rtcrst_pending;
+
        ret = mc13783_irq_request_nounmask(priv->mc13783, MC13783_IRQ_1HZ,
                        mc13783_rtc_update_handler, DRIVER_NAME, priv);
        if (ret)
                goto err_update_irq_request;
 
-       mc13783_unlock(priv->mc13783);
-
        priv->rtc = rtc_device_register(pdev->name,
                        &pdev->dev, &mc13783_rtc_ops, THIS_MODULE);
-
        if (IS_ERR(priv->rtc)) {
                ret = PTR_ERR(priv->rtc);
 
-               mc13783_lock(priv->mc13783);
-
                mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv);
 err_update_irq_request:
 
+err_reset_irq_status:
+
                mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv);
 err_reset_irq_request:
 
-               mc13783_unlock(priv->mc13783);
-
                platform_set_drvdata(pdev, NULL);
                kfree(priv);
        }
 
+       mc13783_unlock(priv->mc13783);
+
        return ret;
 }
 
@@ -220,10 +223,10 @@ static int __devexit mc13783_rtc_remove(struct platform_device *pdev)
 {
        struct mc13783_rtc *priv = platform_get_drvdata(pdev);
 
-       rtc_device_unregister(priv->rtc);
-
        mc13783_lock(priv->mc13783);
 
+       rtc_device_unregister(priv->rtc);
+
        mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv);
        mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv);