linux/kernel/power/suspend_test.c
<<
>>
Prefs
   1/*
   2 * kernel/power/suspend_test.c - Suspend to RAM and standby test facility.
   3 *
   4 * Copyright (c) 2009 Pavel Machek <pavel@ucw.cz>
   5 *
   6 * This file is released under the GPLv2.
   7 */
   8
   9#include <linux/init.h>
  10#include <linux/rtc.h>
  11
  12#include "power.h"
  13
  14/*
  15 * We test the system suspend code by setting an RTC wakealarm a short
  16 * time in the future, then suspending.  Suspending the devices won't
  17 * normally take long ... some systems only need a few milliseconds.
  18 *
  19 * The time it takes is system-specific though, so when we test this
  20 * during system bootup we allow a LOT of time.
  21 */
  22#define TEST_SUSPEND_SECONDS    10
  23
  24static unsigned long suspend_test_start_time;
  25
  26void suspend_test_start(void)
  27{
  28        /* FIXME Use better timebase than "jiffies", ideally a clocksource.
  29         * What we want is a hardware counter that will work correctly even
  30         * during the irqs-are-off stages of the suspend/resume cycle...
  31         */
  32        suspend_test_start_time = jiffies;
  33}
  34
  35void suspend_test_finish(const char *label)
  36{
  37        long nj = jiffies - suspend_test_start_time;
  38        unsigned msec;
  39
  40        msec = jiffies_to_msecs(abs(nj));
  41        pr_info("PM: %s took %d.%03d seconds\n", label,
  42                        msec / 1000, msec % 1000);
  43
  44        /* Warning on suspend means the RTC alarm period needs to be
  45         * larger -- the system was sooo slooowwww to suspend that the
  46         * alarm (should have) fired before the system went to sleep!
  47         *
  48         * Warning on either suspend or resume also means the system
  49         * has some performance issues.  The stack dump of a WARN_ON
  50         * is more likely to get the right attention than a printk...
  51         */
  52        WARN(msec > (TEST_SUSPEND_SECONDS * 1000),
  53             "Component: %s, time: %u\n", label, msec);
  54}
  55
  56/*
  57 * To test system suspend, we need a hands-off mechanism to resume the
  58 * system.  RTCs wake alarms are a common self-contained mechanism.
  59 */
  60
  61static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state)
  62{
  63        static char err_readtime[] __initdata =
  64                KERN_ERR "PM: can't read %s time, err %d\n";
  65        static char err_wakealarm [] __initdata =
  66                KERN_ERR "PM: can't set %s wakealarm, err %d\n";
  67        static char err_suspend[] __initdata =
  68                KERN_ERR "PM: suspend test failed, error %d\n";
  69        static char info_test[] __initdata =
  70                KERN_INFO "PM: test RTC wakeup from '%s' suspend\n";
  71
  72        unsigned long           now;
  73        struct rtc_wkalrm       alm;
  74        int                     status;
  75
  76        /* this may fail if the RTC hasn't been initialized */
  77        status = rtc_read_time(rtc, &alm.time);
  78        if (status < 0) {
  79                printk(err_readtime, dev_name(&rtc->dev), status);
  80                return;
  81        }
  82        rtc_tm_to_time(&alm.time, &now);
  83
  84        memset(&alm, 0, sizeof alm);
  85        rtc_time_to_tm(now + TEST_SUSPEND_SECONDS, &alm.time);
  86        alm.enabled = true;
  87
  88        status = rtc_set_alarm(rtc, &alm);
  89        if (status < 0) {
  90                printk(err_wakealarm, dev_name(&rtc->dev), status);
  91                return;
  92        }
  93
  94        if (state == PM_SUSPEND_MEM) {
  95                printk(info_test, pm_states[state]);
  96                status = pm_suspend(state);
  97                if (status == -ENODEV)
  98                        state = PM_SUSPEND_STANDBY;
  99        }
 100        if (state == PM_SUSPEND_STANDBY) {
 101                printk(info_test, pm_states[state]);
 102                status = pm_suspend(state);
 103        }
 104        if (status < 0)
 105                printk(err_suspend, status);
 106
 107        /* Some platforms can't detect that the alarm triggered the
 108         * wakeup, or (accordingly) disable it after it afterwards.
 109         * It's supposed to give oneshot behavior; cope.
 110         */
 111        alm.enabled = false;
 112        rtc_set_alarm(rtc, &alm);
 113}
 114
 115static int __init has_wakealarm(struct device *dev, void *name_ptr)
 116{
 117        struct rtc_device *candidate = to_rtc_device(dev);
 118
 119        if (!candidate->ops->set_alarm)
 120                return 0;
 121        if (!device_may_wakeup(candidate->dev.parent))
 122                return 0;
 123
 124        *(const char **)name_ptr = dev_name(dev);
 125        return 1;
 126}
 127
 128/*
 129 * Kernel options like "test_suspend=mem" force suspend/resume sanity tests
 130 * at startup time.  They're normally disabled, for faster boot and because
 131 * we can't know which states really work on this particular system.
 132 */
 133static suspend_state_t test_state __initdata = PM_SUSPEND_ON;
 134
 135static char warn_bad_state[] __initdata =
 136        KERN_WARNING "PM: can't test '%s' suspend state\n";
 137
 138static int __init setup_test_suspend(char *value)
 139{
 140        unsigned i;
 141
 142        /* "=mem" ==> "mem" */
 143        value++;
 144        for (i = 0; i < PM_SUSPEND_MAX; i++) {
 145                if (!pm_states[i])
 146                        continue;
 147                if (strcmp(pm_states[i], value) != 0)
 148                        continue;
 149                test_state = (__force suspend_state_t) i;
 150                return 0;
 151        }
 152        printk(warn_bad_state, value);
 153        return 0;
 154}
 155__setup("test_suspend", setup_test_suspend);
 156
 157static int __init test_suspend(void)
 158{
 159        static char             warn_no_rtc[] __initdata =
 160                KERN_WARNING "PM: no wakealarm-capable RTC driver is ready\n";
 161
 162        char                    *pony = NULL;
 163        struct rtc_device       *rtc = NULL;
 164
 165        /* PM is initialized by now; is that state testable? */
 166        if (test_state == PM_SUSPEND_ON)
 167                goto done;
 168        if (!valid_state(test_state)) {
 169                printk(warn_bad_state, pm_states[test_state]);
 170                goto done;
 171        }
 172
 173        /* RTCs have initialized by now too ... can we use one? */
 174        class_find_device(rtc_class, NULL, &pony, has_wakealarm);
 175        if (pony)
 176                rtc = rtc_class_open(pony);
 177        if (!rtc) {
 178                printk(warn_no_rtc);
 179                goto done;
 180        }
 181
 182        /* go for it */
 183        test_wakealarm(rtc, test_state);
 184        rtc_class_close(rtc);
 185done:
 186        return 0;
 187}
 188late_initcall(test_suspend);
 189
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.