rtc: da9053: fix access ordering error during RTC interrupt at system power on
authorSteve Twiss <stwiss.opensource@diasemi.com>
Thu, 14 Apr 2016 11:04:54 +0000 (12:04 +0100)
committerAlexandre Belloni <alexandre.belloni@free-electrons.com>
Fri, 20 May 2016 10:33:51 +0000 (12:33 +0200)
This fix alters the ordering of the IRQ and device registrations in the RTC
driver probe function. This change will apply to the RTC driver that supports
both DA9052 and DA9053 PMICs.

A problem could occur with the existing RTC driver if:

A system is started from a cold boot using the PMIC RTC IRQ to initiate a
power on operation. For instance, if an RTC alarm is used to start a
platform from power off.
The existing driver IRQ is requested before the device has been properly
registered.

i.e.
ret = da9052_request_irq()
comes before
rtc->rtc = devm_rtc_device_register();

In this case, an interrupt exists before the device has been registered and
the IRQ handler can be called immediately: this can happen be before the
memory for rtc->rtc has been allocated. The IRQ handler da9052_rtc_irq()
contains the function call:

rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);

which in turn tries to access the unavailable rtc->rtc.

The fix is to reorder the functions inside the RTC probe. The IRQ is
requested after the RTC device resource has been registered so that
da9052_request_irq() is the last thing to happen.

Signed-off-by: Steve Twiss <stwiss.opensource@diasemi.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
drivers/rtc/rtc-da9052.c

index 1ba4371cbc2d7868ebee5dd3136f3ee88b6143f3..a20bcf0e33cd10a1c0f43918c759f4d52856a07a 100644 (file)
@@ -302,6 +302,13 @@ static int da9052_rtc_probe(struct platform_device *pdev)
        if (ret != 0)
                rtc_err(rtc, "Failed to disable TICKS: %d\n", ret);
 
+       device_init_wakeup(&pdev->dev, true);
+       rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+                                      &da9052_rtc_ops, THIS_MODULE);
+
+       if (IS_ERR(rtc->rtc))
+               return PTR_ERR(rtc->rtc);
+
        ret = da9052_request_irq(rtc->da9052, DA9052_IRQ_ALARM, "ALM",
                                da9052_rtc_irq, rtc);
        if (ret != 0) {
@@ -309,11 +316,7 @@ static int da9052_rtc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       device_init_wakeup(&pdev->dev, true);
-
-       rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
-                                      &da9052_rtc_ops, THIS_MODULE);
-       return PTR_ERR_OR_ZERO(rtc->rtc);
+       return 0;
 }
 
 static struct platform_driver da9052_rtc_driver = {