root/kernel/power/suspend_test.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. suspend_test_start
  2. suspend_test_finish
  3. test_wakealarm
  4. has_wakealarm
  5. setup_test_suspend
  6. test_suspend

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

/* [<][>][^][v][top][bottom][index][help] */