Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers/rtc/rtc-sirfsoc.c: fix kernel panic of backing from hibernation

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:

rtc rtc0: **** DPM device timeout ****
Stack trace:
unwind_backtrace+0x0/0xf4
show_stack+0x10/0x14
dpm_wd_handler+0x24/0x28
call_timer_fn.isra.33+0x24/0x88
run_timer_softirq+0x178/0x1f0
__do_softirq+0x120/0x200
do_softirq+0x54/0x5c
irq_exit+0x9c/0xd0
handle_IRQ+0x44/0x90
__irq_svc+0x40/0x70
_raw_spin_unlock_irqrestore+0x10/0x48
sirfsoc_rtc_iobrg_readl+0x34/0x3c
sirfsoc_rtc_read_time+0x24/0x48
__rtc_read_time.isra.3+0x48/0x5c
rtc_read_time+0x30/0x44
rtc_resume.part.9+0x20/0x104
rtc_resume+0x5c/0x64
dpm_run_callback.isra.4+0x2c/0x74
device_resume+0x9c/0x144
dpm_resume+0x100/0x224
hibernation_snapshot+0x170/0x398
hibernate+0x13c/0x1d8
state_store+0xb4/0xb8
kobj_attr_store+0x14/0x20
sysfs_write_file+0x160/0x190
vfs_write+0xb4/0x194
SyS_write+0x3c/0x78

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@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Cc: Grant Likely <grant.likely@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Xianglong Du and committed by
Linus Torvalds
3916b09e c2c0eed7

+9 -53
+9 -53
drivers/rtc/rtc-sirfsoc.c
··· 331 331 return 0; 332 332 } 333 333 334 - #ifdef CONFIG_PM 335 - 334 + #ifdef CONFIG_PM_SLEEP 336 335 static int sirfsoc_rtc_suspend(struct device *dev) 337 336 { 338 - struct platform_device *pdev = to_platform_device(dev); 339 - struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev); 337 + struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev); 340 338 rtcdrv->overflow_rtc = 341 339 sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE); 342 340 343 341 rtcdrv->saved_counter = 344 342 sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); 345 343 rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc; 346 - if (device_may_wakeup(&pdev->dev) && !enable_irq_wake(rtcdrv->irq)) 344 + if (device_may_wakeup(dev) && !enable_irq_wake(rtcdrv->irq)) 347 345 rtcdrv->irq_wake = 1; 348 346 349 347 return 0; 350 348 } 351 349 352 - static int sirfsoc_rtc_freeze(struct device *dev) 353 - { 354 - sirfsoc_rtc_suspend(dev); 355 - 356 - return 0; 357 - } 358 - 359 - static int sirfsoc_rtc_thaw(struct device *dev) 350 + static int sirfsoc_rtc_resume(struct device *dev) 360 351 { 361 352 u32 tmp; 362 - struct sirfsoc_rtc_drv *rtcdrv; 363 - rtcdrv = dev_get_drvdata(dev); 353 + struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev); 364 354 365 355 /* 366 - * if resume from snapshot and the rtc power is losed, 356 + * if resume from snapshot and the rtc power is lost, 367 357 * restroe the rtc settings 368 358 */ 369 359 if (SIRFSOC_RTC_CLK != sirfsoc_rtc_iobrg_readl( ··· 393 403 sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc, 394 404 rtcdrv->rtc_base + RTC_SW_VALUE); 395 405 396 - return 0; 397 - } 398 - 399 - static int sirfsoc_rtc_resume(struct device *dev) 400 - { 401 - struct platform_device *pdev = to_platform_device(dev); 402 - struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev); 403 - sirfsoc_rtc_thaw(dev); 404 - if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) { 406 + if (device_may_wakeup(dev) && rtcdrv->irq_wake) { 405 407 disable_irq_wake(rtcdrv->irq); 406 408 rtcdrv->irq_wake = 0; 407 409 } 408 410 409 411 return 0; 410 412 } 411 - 412 - static int sirfsoc_rtc_restore(struct device *dev) 413 - { 414 - struct platform_device *pdev = to_platform_device(dev); 415 - struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev); 416 - 417 - if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) { 418 - disable_irq_wake(rtcdrv->irq); 419 - rtcdrv->irq_wake = 0; 420 - } 421 - return 0; 422 - } 423 - 424 - #else 425 - #define sirfsoc_rtc_suspend NULL 426 - #define sirfsoc_rtc_resume NULL 427 - #define sirfsoc_rtc_freeze NULL 428 - #define sirfsoc_rtc_thaw NULL 429 - #define sirfsoc_rtc_restore NULL 430 413 #endif 431 414 432 - static const struct dev_pm_ops sirfsoc_rtc_pm_ops = { 433 - .suspend = sirfsoc_rtc_suspend, 434 - .resume = sirfsoc_rtc_resume, 435 - .freeze = sirfsoc_rtc_freeze, 436 - .thaw = sirfsoc_rtc_thaw, 437 - .restore = sirfsoc_rtc_restore, 438 - }; 415 + static SIMPLE_DEV_PM_OPS(sirfsoc_rtc_pm_ops, 416 + sirfsoc_rtc_suspend, sirfsoc_rtc_resume); 439 417 440 418 static struct platform_driver sirfsoc_rtc_driver = { 441 419 .driver = { 442 420 .name = "sirfsoc-rtc", 443 421 .owner = THIS_MODULE, 444 - #ifdef CONFIG_PM 445 422 .pm = &sirfsoc_rtc_pm_ops, 446 - #endif 447 423 .of_match_table = sirfsoc_rtc_of_match, 448 424 }, 449 425 .probe = sirfsoc_rtc_probe,