Skip to content

Commit

Permalink
rtc/mc13783: protect rtc {,un}registration by mc13783 lock
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Uwe Kleine-König authored and torvalds committed Mar 6, 2010
1 parent 86c3400 commit 4c014e8
Showing 1 changed file with 14 additions and 11 deletions.
25 changes: 14 additions & 11 deletions drivers/rtc/rtc-mc13783.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -177,53 +178,55 @@ 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,
mc13783_rtc_reset_handler, DRIVER_NAME, priv);
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;
}

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

Expand Down

0 comments on commit 4c014e8

Please sign in to comment.