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

pm: boot time suspend selftest

Boot-time test for system suspend states (STR or standby). The generic
RTC framework triggers wakeup alarms, which are used to exit those states.

- Measures some aspects of suspend time ... this uses "jiffies" until
someone converts it to use a timebase that works properly even while
timer IRQs are disabled.

- Triggered by a command line parameter. By default nothing even
vaguely troublesome will happen, but "test_suspend=mem" will give
you a brief STR test during system boot. (Or you may need to use
"test_suspend=standby" instead, if your hardware needs that.)

This isn't without problems. It fires early enough during boot that for
example both PCMCIA and MMC stacks have misbehaved. The workaround in
those cases was to boot without such media cards inserted.

[matthltc@us.ibm.com: fix compile failure in boot time suspend selftest]
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Pavel Machek <pavel@suse.cz>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Signed-off-by: Matt Helsley <matthltc@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

David Brownell and committed by
Linus Torvalds
77437fd4 0d63081d

+212 -2
+8 -1
Documentation/kernel-parameters.txt
··· 87 87 SH SuperH architecture is enabled. 88 88 SMP The kernel is an SMP kernel. 89 89 SPARC Sparc architecture is enabled. 90 - SWSUSP Software suspend is enabled. 90 + SWSUSP Software suspend (hibernation) is enabled. 91 + SUSPEND System suspend states are enabled. 91 92 TS Appropriate touchscreen support is enabled. 92 93 USB USB support is enabled. 93 94 USBHID USB Human Interface Device support is enabled. ··· 2123 2122 See header of drivers/scsi/t128.c. 2124 2123 2125 2124 tdfx= [HW,DRM] 2125 + 2126 + test_suspend= [SUSPEND] 2127 + Specify "mem" (for Suspend-to-RAM) or "standby" (for 2128 + standby suspend) as the system sleep state to briefly 2129 + enter during system startup. The system is woken from 2130 + this state using a wakeup-capable RTC alarm. 2126 2131 2127 2132 thash_entries= [KNL,NET] 2128 2133 Set number of hash buckets for TCP connection
+11
kernel/power/Kconfig
··· 94 94 powered and thus its contents are preserved, such as the 95 95 suspend-to-RAM state (e.g. the ACPI S3 state). 96 96 97 + config PM_TEST_SUSPEND 98 + bool "Test suspend/resume and wakealarm during bootup" 99 + depends on SUSPEND && PM_DEBUG && RTC_LIB=y 100 + ---help--- 101 + This option will let you suspend your machine during bootup, and 102 + make it wake up a few seconds later using an RTC wakeup alarm. 103 + Enable this with a kernel parameter like "test_suspend=mem". 104 + 105 + You probably want to have your system's RTC driver statically 106 + linked, ensuring that it's available when this test runs. 107 + 97 108 config SUSPEND_FREEZER 98 109 bool "Enable freezer for suspend to RAM/standby" \ 99 110 if ARCH_WANTS_FREEZER_CONTROL || BROKEN
+193 -1
kernel/power/main.c
··· 132 132 133 133 #ifdef CONFIG_SUSPEND 134 134 135 + #ifdef CONFIG_PM_TEST_SUSPEND 136 + 137 + /* 138 + * We test the system suspend code by setting an RTC wakealarm a short 139 + * time in the future, then suspending. Suspending the devices won't 140 + * normally take long ... some systems only need a few milliseconds. 141 + * 142 + * The time it takes is system-specific though, so when we test this 143 + * during system bootup we allow a LOT of time. 144 + */ 145 + #define TEST_SUSPEND_SECONDS 5 146 + 147 + static unsigned long suspend_test_start_time; 148 + 149 + static void suspend_test_start(void) 150 + { 151 + /* FIXME Use better timebase than "jiffies", ideally a clocksource. 152 + * What we want is a hardware counter that will work correctly even 153 + * during the irqs-are-off stages of the suspend/resume cycle... 154 + */ 155 + suspend_test_start_time = jiffies; 156 + } 157 + 158 + static void suspend_test_finish(const char *label) 159 + { 160 + long nj = jiffies - suspend_test_start_time; 161 + unsigned msec; 162 + 163 + msec = jiffies_to_msecs(abs(nj)); 164 + pr_info("PM: %s took %d.%03d seconds\n", label, 165 + msec / 1000, msec % 1000); 166 + 167 + /* Warning on suspend means the RTC alarm period needs to be 168 + * larger -- the system was sooo slooowwww to suspend that the 169 + * alarm (should have) fired before the system went to sleep! 170 + * 171 + * Warning on either suspend or resume also means the system 172 + * has some performance issues. The stack dump of a WARN_ON 173 + * is more likely to get the right attention than a printk... 174 + */ 175 + WARN_ON(msec > (TEST_SUSPEND_SECONDS * 1000)); 176 + } 177 + 178 + #else 179 + 180 + static void suspend_test_start(void) 181 + { 182 + } 183 + 184 + static void suspend_test_finish(const char *label) 185 + { 186 + } 187 + 188 + #endif 189 + 135 190 /* This is just an arbitrary number */ 136 191 #define FREE_PAGE_NUMBER (100) 137 192 ··· 321 266 goto Close; 322 267 } 323 268 suspend_console(); 269 + suspend_test_start(); 324 270 error = device_suspend(PMSG_SUSPEND); 325 271 if (error) { 326 272 printk(KERN_ERR "PM: Some devices failed to suspend\n"); 327 273 goto Recover_platform; 328 274 } 329 - 275 + suspend_test_finish("suspend devices"); 330 276 if (suspend_test(TEST_DEVICES)) 331 277 goto Recover_platform; 332 278 ··· 349 293 if (suspend_ops->finish) 350 294 suspend_ops->finish(); 351 295 Resume_devices: 296 + suspend_test_start(); 352 297 device_resume(PMSG_RESUME); 298 + suspend_test_finish("resume devices"); 353 299 resume_console(); 354 300 Close: 355 301 if (suspend_ops->end) ··· 579 521 } 580 522 581 523 core_initcall(pm_init); 524 + 525 + 526 + #ifdef CONFIG_PM_TEST_SUSPEND 527 + 528 + #include <linux/rtc.h> 529 + 530 + /* 531 + * To test system suspend, we need a hands-off mechanism to resume the 532 + * system. RTCs wake alarms are a common self-contained mechanism. 533 + */ 534 + 535 + static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state) 536 + { 537 + static char err_readtime[] __initdata = 538 + KERN_ERR "PM: can't read %s time, err %d\n"; 539 + static char err_wakealarm [] __initdata = 540 + KERN_ERR "PM: can't set %s wakealarm, err %d\n"; 541 + static char err_suspend[] __initdata = 542 + KERN_ERR "PM: suspend test failed, error %d\n"; 543 + static char info_test[] __initdata = 544 + KERN_INFO "PM: test RTC wakeup from '%s' suspend\n"; 545 + 546 + unsigned long now; 547 + struct rtc_wkalrm alm; 548 + int status; 549 + 550 + /* this may fail if the RTC hasn't been initialized */ 551 + status = rtc_read_time(rtc, &alm.time); 552 + if (status < 0) { 553 + printk(err_readtime, rtc->dev.bus_id, status); 554 + return; 555 + } 556 + rtc_tm_to_time(&alm.time, &now); 557 + 558 + memset(&alm, 0, sizeof alm); 559 + rtc_time_to_tm(now + TEST_SUSPEND_SECONDS, &alm.time); 560 + alm.enabled = true; 561 + 562 + status = rtc_set_alarm(rtc, &alm); 563 + if (status < 0) { 564 + printk(err_wakealarm, rtc->dev.bus_id, status); 565 + return; 566 + } 567 + 568 + if (state == PM_SUSPEND_MEM) { 569 + printk(info_test, pm_states[state]); 570 + status = pm_suspend(state); 571 + if (status == -ENODEV) 572 + state = PM_SUSPEND_STANDBY; 573 + } 574 + if (state == PM_SUSPEND_STANDBY) { 575 + printk(info_test, pm_states[state]); 576 + status = pm_suspend(state); 577 + } 578 + if (status < 0) 579 + printk(err_suspend, status); 580 + } 581 + 582 + static int __init has_wakealarm(struct device *dev, void *name_ptr) 583 + { 584 + struct rtc_device *candidate = to_rtc_device(dev); 585 + 586 + if (!candidate->ops->set_alarm) 587 + return 0; 588 + if (!device_may_wakeup(candidate->dev.parent)) 589 + return 0; 590 + 591 + *(char **)name_ptr = dev->bus_id; 592 + return 1; 593 + } 594 + 595 + /* 596 + * Kernel options like "test_suspend=mem" force suspend/resume sanity tests 597 + * at startup time. They're normally disabled, for faster boot and because 598 + * we can't know which states really work on this particular system. 599 + */ 600 + static suspend_state_t test_state __initdata = PM_SUSPEND_ON; 601 + 602 + static char warn_bad_state[] __initdata = 603 + KERN_WARNING "PM: can't test '%s' suspend state\n"; 604 + 605 + static int __init setup_test_suspend(char *value) 606 + { 607 + unsigned i; 608 + 609 + /* "=mem" ==> "mem" */ 610 + value++; 611 + for (i = 0; i < PM_SUSPEND_MAX; i++) { 612 + if (!pm_states[i]) 613 + continue; 614 + if (strcmp(pm_states[i], value) != 0) 615 + continue; 616 + test_state = (__force suspend_state_t) i; 617 + return 0; 618 + } 619 + printk(warn_bad_state, value); 620 + return 0; 621 + } 622 + __setup("test_suspend", setup_test_suspend); 623 + 624 + static int __init test_suspend(void) 625 + { 626 + static char warn_no_rtc[] __initdata = 627 + KERN_WARNING "PM: no wakealarm-capable RTC driver is ready\n"; 628 + 629 + char *pony = NULL; 630 + struct rtc_device *rtc = NULL; 631 + 632 + /* PM is initialized by now; is that state testable? */ 633 + if (test_state == PM_SUSPEND_ON) 634 + goto done; 635 + if (!valid_state(test_state)) { 636 + printk(warn_bad_state, pm_states[test_state]); 637 + goto done; 638 + } 639 + 640 + /* RTCs have initialized by now too ... can we use one? */ 641 + class_find_device(rtc_class, NULL, &pony, has_wakealarm); 642 + if (pony) 643 + rtc = rtc_class_open(pony); 644 + if (!rtc) { 645 + printk(warn_no_rtc); 646 + goto done; 647 + } 648 + 649 + /* go for it */ 650 + test_wakealarm(rtc, test_state); 651 + rtc_class_close(rtc); 652 + done: 653 + return 0; 654 + } 655 + late_initcall(test_suspend); 656 + 657 + #endif /* CONFIG_PM_TEST_SUSPEND */