drivers/rtc/rtc-sirfsoc.c: fix kernel warning during wakeup
authorXianglong Du <Xianglong.Du@csr.com>
Wed, 11 Sep 2013 21:24:23 +0000 (14:24 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 11 Sep 2013 22:58:57 +0000 (15:58 -0700)
enable_irq_wake() might fail, if so, we will see kernel warning in resume
entries due to it always calls disable_irq_wake().

  WARNING: at kernel/irq/manage.c:529 irq_set_irq_wake+0xc4/0xf0()
  Unbalanced IRQ 52 wake disable
  Modules linked in: ipv6 libcomposite configfs
  CPU: 0 PID: 1591 Comm: ash Tainted: G        W    3.10.0-00854-gdbd86d4-dirty #100
    (unwind_backtrace+0x0/0xf8) from (show_stack+0x10/0x14)
    (show_stack+0x10/0x14) from (warn_slowpath_common+0x54/0x68)
    (warn_slowpath_common+0x54/0x68) from (warn_slowpath_fmt+0x30/0x40)
    (warn_slowpath_fmt+0x30/0x40) from (irq_set_irq_wake+0xc4/0xf0)
    (irq_set_irq_wake+0xc4/0xf0) from (sirfsoc_rtc_restore+0x30/0x38)
    (sirfsoc_rtc_restore+0x30/0x38) from (platform_pm_restore+0x2c/0x50)
    (platform_pm_restore+0x2c/0x50) from (dpm_run_callback.clone.6+0x30/0xb0)
    (dpm_run_callback.clone.6+0x30/0xb0) from (device_resume+0x88/0x134)
    (device_resume+0x88/0x134) from (dpm_resume+0x114/0x230)
    (dpm_resume+0x114/0x230) from (hibernation_snapshot+0x178/0x1d0)
    (hibernation_snapshot+0x178/0x1d0) from (hibernate+0x130/0x1dc)
    (hibernate+0x130/0x1dc) from (state_store+0xb4/0xc0)
    (state_store+0xb4/0xc0) from (kobj_attr_store+0x14/0x20)
    (kobj_attr_store+0x14/0x20) from (sysfs_write_file+0xfc/0x17c)
    (sysfs_write_file+0xfc/0x17c) from (vfs_write+0xc8/0x194)
    (vfs_write+0xc8/0x194) from (SyS_write+0x40/0x6c)
    (SyS_write+0x40/0x6c) from (ret_fast_syscall+0x0/0x30)

To avoid unbalanced "IRQ wake disable", ensure that disable_irq_wake() is
called only when enable_irq_wake() have been successfully enabled.

Signed-off-by: Xianglong Du <Xianglong.Du@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/rtc/rtc-sirfsoc.c

index aa7ed4b..63460cf 100644 (file)
@@ -44,6 +44,7 @@ struct sirfsoc_rtc_drv {
        struct rtc_device       *rtc;
        u32                     rtc_base;
        u32                     irq;
+       unsigned                irq_wake;
        /* Overflow for every 8 years extra time */
        u32                     overflow_rtc;
 #ifdef CONFIG_PM
@@ -355,8 +356,8 @@ static int sirfsoc_rtc_suspend(struct device *dev)
        rtcdrv->saved_counter =
                sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
        rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc;
-       if (device_may_wakeup(&pdev->dev))
-               enable_irq_wake(rtcdrv->irq);
+       if (device_may_wakeup(&pdev->dev) && !enable_irq_wake(rtcdrv->irq))
+               rtcdrv->irq_wake = 1;
 
        return 0;
 }
@@ -423,8 +424,10 @@ static int sirfsoc_rtc_resume(struct device *dev)
        struct platform_device *pdev = to_platform_device(dev);
        struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
        sirfsoc_rtc_thaw(dev);
-       if (device_may_wakeup(&pdev->dev))
+       if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) {
                disable_irq_wake(rtcdrv->irq);
+               rtcdrv->irq_wake = 0;
+       }
 
        return 0;
 }
@@ -434,8 +437,10 @@ static int sirfsoc_rtc_restore(struct device *dev)
        struct platform_device *pdev = to_platform_device(dev);
        struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
 
-       if (device_may_wakeup(&pdev->dev))
+       if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) {
                disable_irq_wake(rtcdrv->irq);
+               rtcdrv->irq_wake = 0;
+       }
        return 0;
 }