[PATCH] drivers/rtc/rtc-sirfsoc.c: fix kernel panic of backing from hibernation
Barry Song
21cnbao at gmail.com
Sun Jan 5 21:14:30 EST 2014
From: Xianglong Du <Xianglong.Du at csr.com>
RTC settings will be lost if power supply is cut off after hibernation finished,
but the current "restore" function does not restore RTC related settings, this
causes rtc_read_time failure and kernel panic:
[ 72.873363] rtc rtc0: **** DPM device timeout ****
[ 72.875332] [<c00154e4>] (unwind_backtrace+0x0/0xf4) from [<c00120b4>] (show_stack+0x10/0x14)
[ 72.883862] [<c00120b4>] (show_stack+0x10/0x14) from [<c02179b4>] (dpm_wd_handler+0x24/0x28)
[ 72.892288] [<c02179b4>] (dpm_wd_handler+0x24/0x28) from [<c002d6f0>] (call_timer_fn.isra.33+0x24/0x88)
[ 72.901663] [<c002d6f0>] (call_timer_fn.isra.33+0x24/0x88) from [<c002d8cc>] (run_timer_softirq+0x178/0x1f0)
[ 72.911463] [<c002d8cc>] (run_timer_softirq+0x178/0x1f0) from [<c0027c8c>] (__do_softirq+0x120/0x200)
[ 72.920658] [<c0027c8c>] (__do_softirq+0x120/0x200) from [<c0027e1c>] (do_softirq+0x54/0x5c)
[ 72.929075] [<c0027e1c>] (do_softirq+0x54/0x5c) from [<c00280c4>] (irq_exit+0x9c/0xd0)
[ 72.936971] [<c00280c4>] (irq_exit+0x9c/0xd0) from [<c000ef84>] (handle_IRQ+0x44/0x90)
[ 72.944876] [<c000ef84>] (handle_IRQ+0x44/0x90) from [<c000dc80>] (__irq_svc+0x40/0x70)
[ 72.952841] [<c000dc80>] (__irq_svc+0x40/0x70) from [<c03864b4>] (_raw_spin_unlock_irqrestore+0x10/0x48)
[ 72.962325] [<c03864b4>] (_raw_spin_unlock_irqrestore+0x10/0x48) from [<c001ddc0>] (sirfsoc_rtc_iobrg_readl+0x34/0x3c)
[ 72.973007] [<c001ddc0>] (sirfsoc_rtc_iobrg_readl+0x34/0x3c) from [<c027caf8>] (sirfsoc_rtc_read_time+0x24/0x48)
[ 72.983147] [<c027caf8>] (sirfsoc_rtc_read_time+0x24/0x48) from [<c027a930>] (__rtc_read_time.isra.3+0x48/0x5c)
[ 72.993229] [<c027a930>] (__rtc_read_time.isra.3+0x48/0x5c) from [<c027a974>] (rtc_read_time+0x30/0x44)
[ 73.002592] [<c027a974>] (rtc_read_time+0x30/0x44) from [<c027a2f0>] (rtc_resume.part.9+0x20/0x104)
[ 73.011620] [<c027a2f0>] (rtc_resume.part.9+0x20/0x104) from [<c027a430>] (rtc_resume+0x5c/0x64)
[ 73.020388] [<c027a430>] (rtc_resume+0x5c/0x64) from [<c0217a4c>] (dpm_run_callback.isra.4+0x2c/0x74)
[ 73.029597] [<c0217a4c>] (dpm_run_callback.isra.4+0x2c/0x74) from [<c0217f80>] (device_resume+0x9c/0x144)
[ 73.039134] [<c0217f80>] (device_resume+0x9c/0x144) from [<c0218aec>] (dpm_resume+0x100/0x224)
[ 73.047734] [<c0218aec>] (dpm_resume+0x100/0x224) from [<c0056f4c>] (hibernation_snapshot+0x170/0x398)
[ 73.057019] [<c0056f4c>] (hibernation_snapshot+0x170/0x398) from [<c00575b4>] (hibernate+0x13c/0x1d8)
[ 73.066212] [<c00575b4>] (hibernate+0x13c/0x1d8) from [<c00556f4>] (state_store+0xb4/0xb8)
[ 73.074474] [<c00556f4>] (state_store+0xb4/0xb8) from [<c0197d50>] (kobj_attr_store+0x14/0x20)
[ 73.083033] [<c0197d50>] (kobj_attr_store+0x14/0x20) from [<c0118c04>] (sysfs_write_file+0x160/0x190)
[ 73.092271] [<c0118c04>] (sysfs_write_file+0x160/0x190) from [<c00c2b08>] (vfs_write+0xb4/0x194)
[ 73.101027] [<c00c2b08>] (vfs_write+0xb4/0x194) from [<c00c3088>] (SyS_write+0x3c/0x78)
[ 73.109016] [<c00c3088>] (SyS_write+0x3c/0x78) from [<c000e080>] (ret_fast_syscall+0x0/0x30)
this patch uses SIMPLE_DEV_PM_OPS() to make restore() execute the existing resume()
function which will restore the set of RTC.
Signed-off-by: Xianglong Du <Xianglong.Du at csr.com>
Signed-off-by: Barry Song <Baohua.Song at csr.com>
---
drivers/rtc/rtc-sirfsoc.c | 62 ++++++--------------------------------------
1 files changed, 9 insertions(+), 53 deletions(-)
diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c
index 3eb3642..14f6179 100644
--- a/drivers/rtc/rtc-sirfsoc.c
+++ b/drivers/rtc/rtc-sirfsoc.c
@@ -335,39 +335,29 @@ static int sirfsoc_rtc_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-
+#ifdef CONFIG_PM_SLEEP
static int sirfsoc_rtc_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
+ struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev);
rtcdrv->overflow_rtc =
sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE);
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(dev) && !enable_irq_wake(rtcdrv->irq))
rtcdrv->irq_wake = 1;
return 0;
}
-static int sirfsoc_rtc_freeze(struct device *dev)
-{
- sirfsoc_rtc_suspend(dev);
-
- return 0;
-}
-
-static int sirfsoc_rtc_thaw(struct device *dev)
+static int sirfsoc_rtc_resume(struct device *dev)
{
u32 tmp;
- struct sirfsoc_rtc_drv *rtcdrv;
- rtcdrv = dev_get_drvdata(dev);
+ struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev);
/*
- * if resume from snapshot and the rtc power is losed,
+ * if resume from snapshot and the rtc power is lost,
* restroe the rtc settings
*/
if (SIRFSOC_RTC_CLK != sirfsoc_rtc_iobrg_readl(
@@ -407,57 +397,23 @@ static int sirfsoc_rtc_thaw(struct device *dev)
sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc,
rtcdrv->rtc_base + RTC_SW_VALUE);
- return 0;
-}
-
-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) && rtcdrv->irq_wake) {
+ if (device_may_wakeup(dev) && rtcdrv->irq_wake) {
disable_irq_wake(rtcdrv->irq);
rtcdrv->irq_wake = 0;
}
return 0;
}
-
-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) && rtcdrv->irq_wake) {
- disable_irq_wake(rtcdrv->irq);
- rtcdrv->irq_wake = 0;
- }
- return 0;
-}
-
-#else
-#define sirfsoc_rtc_suspend NULL
-#define sirfsoc_rtc_resume NULL
-#define sirfsoc_rtc_freeze NULL
-#define sirfsoc_rtc_thaw NULL
-#define sirfsoc_rtc_restore NULL
#endif
-static const struct dev_pm_ops sirfsoc_rtc_pm_ops = {
- .suspend = sirfsoc_rtc_suspend,
- .resume = sirfsoc_rtc_resume,
- .freeze = sirfsoc_rtc_freeze,
- .thaw = sirfsoc_rtc_thaw,
- .restore = sirfsoc_rtc_restore,
-};
+static SIMPLE_DEV_PM_OPS(sirfsoc_rtc_pm_ops,
+ sirfsoc_rtc_suspend, sirfsoc_rtc_resume);
static struct platform_driver sirfsoc_rtc_driver = {
.driver = {
.name = "sirfsoc-rtc",
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &sirfsoc_rtc_pm_ops,
-#endif
.of_match_table = sirfsoc_rtc_of_match,
},
.probe = sirfsoc_rtc_probe,
--
1.7.5.4
More information about the linux-arm-kernel
mailing list