rtc/mc13783: protect rtc {,un}registration by mc13783 lock
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 <u.kleine-koenig@pengutronix.de>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Paul Gortmaker <p_gortmaker@yahoo.com>
Cc: Valentin Longchamp <valentin.longchamp@epfl.ch>
Cc: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Samuel Ortiz <sameo@linux.intel.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Luotao Fu <l.fu@pengutronix.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/drivers/rtc/rtc-mc13783.c b/drivers/rtc/rtc-mc13783.c
index 0a978a0..6a36201 100644
--- a/drivers/rtc/rtc-mc13783.c
+++ b/drivers/rtc/rtc-mc13783.c
@@ -169,6 +169,7 @@
{
int ret;
struct mc13783_rtc *priv;
+ int rtcrst_pending;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -177,8 +178,6 @@
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 @@
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 @@
{
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);