linux/kernel/power/suspend.c
<<
>>
Prefs
   1/*
   2 * kernel/power/suspend.c - Suspend to RAM and standby functionality.
   3 *
   4 * Copyright (c) 2003 Patrick Mochel
   5 * Copyright (c) 2003 Open Source Development Lab
   6 * Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
   7 *
   8 * This file is released under the GPLv2.
   9 */
  10
  11#include <linux/string.h>
  12#include <linux/delay.h>
  13#include <linux/errno.h>
  14#include <linux/init.h>
  15#include <linux/console.h>
  16#include <linux/cpu.h>
  17#include <linux/syscalls.h>
  18#include <linux/gfp.h>
  19#include <linux/io.h>
  20#include <linux/kernel.h>
  21#include <linux/list.h>
  22#include <linux/mm.h>
  23#include <linux/slab.h>
  24#include <linux/export.h>
  25#include <linux/suspend.h>
  26#include <linux/syscore_ops.h>
  27#include <linux/ftrace.h>
  28#include <trace/events/power.h>
  29
  30#include "power.h"
  31
  32const char *const pm_states[PM_SUSPEND_MAX] = {
  33        [PM_SUSPEND_STANDBY]    = "standby",
  34        [PM_SUSPEND_MEM]        = "mem",
  35};
  36
  37static const struct platform_suspend_ops *suspend_ops;
  38
  39/**
  40 * suspend_set_ops - Set the global suspend method table.
  41 * @ops: Suspend operations to use.
  42 */
  43void suspend_set_ops(const struct platform_suspend_ops *ops)
  44{
  45        lock_system_sleep();
  46        suspend_ops = ops;
  47        unlock_system_sleep();
  48}
  49EXPORT_SYMBOL_GPL(suspend_set_ops);
  50
  51bool valid_state(suspend_state_t state)
  52{
  53        /*
  54         * All states need lowlevel support and need to be valid to the lowlevel
  55         * implementation, no valid callback implies that none are valid.
  56         */
  57        return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);
  58}
  59
  60/**
  61 * suspend_valid_only_mem - Generic memory-only valid callback.
  62 *
  63 * Platform drivers that implement mem suspend only and only need to check for
  64 * that in their .valid() callback can use this instead of rolling their own
  65 * .valid() callback.
  66 */
  67int suspend_valid_only_mem(suspend_state_t state)
  68{
  69        return state == PM_SUSPEND_MEM;
  70}
  71EXPORT_SYMBOL_GPL(suspend_valid_only_mem);
  72
  73static int suspend_test(int level)
  74{
  75#ifdef CONFIG_PM_DEBUG
  76        if (pm_test_level == level) {
  77                printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
  78                mdelay(5000);
  79                return 1;
  80        }
  81#endif /* !CONFIG_PM_DEBUG */
  82        return 0;
  83}
  84
  85/**
  86 * suspend_prepare - Prepare for entering system sleep state.
  87 *
  88 * Common code run for every system sleep state that can be entered (except for
  89 * hibernation).  Run suspend notifiers, allocate the "suspend" console and
  90 * freeze processes.
  91 */
  92static int suspend_prepare(void)
  93{
  94        int error;
  95
  96        if (!suspend_ops || !suspend_ops->enter)
  97                return -EPERM;
  98
  99        pm_prepare_console();
 100
 101        error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
 102        if (error)
 103                goto Finish;
 104
 105        error = suspend_freeze_processes();
 106        if (!error)
 107                return 0;
 108
 109        suspend_stats.failed_freeze++;
 110        dpm_save_failed_step(SUSPEND_FREEZE);
 111 Finish:
 112        pm_notifier_call_chain(PM_POST_SUSPEND);
 113        pm_restore_console();
 114        return error;
 115}
 116
 117/* default implementation */
 118void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
 119{
 120        local_irq_disable();
 121}
 122
 123/* default implementation */
 124void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
 125{
 126        local_irq_enable();
 127}
 128
 129/**
 130 * suspend_enter - Make the system enter the given sleep state.
 131 * @state: System sleep state to enter.
 132 * @wakeup: Returns information that the sleep state should not be re-entered.
 133 *
 134 * This function should be called after devices have been suspended.
 135 */
 136static int suspend_enter(suspend_state_t state, bool *wakeup)
 137{
 138        int error;
 139
 140        if (suspend_ops->prepare) {
 141                error = suspend_ops->prepare();
 142                if (error)
 143                        goto Platform_finish;
 144        }
 145
 146        error = dpm_suspend_end(PMSG_SUSPEND);
 147        if (error) {
 148                printk(KERN_ERR "PM: Some devices failed to power down\n");
 149                goto Platform_finish;
 150        }
 151
 152        if (suspend_ops->prepare_late) {
 153                error = suspend_ops->prepare_late();
 154                if (error)
 155                        goto Platform_wake;
 156        }
 157
 158        if (suspend_test(TEST_PLATFORM))
 159                goto Platform_wake;
 160
 161        error = disable_nonboot_cpus();
 162        if (error || suspend_test(TEST_CPUS))
 163                goto Enable_cpus;
 164
 165        arch_suspend_disable_irqs();
 166        BUG_ON(!irqs_disabled());
 167
 168        error = syscore_suspend();
 169        if (!error) {
 170                *wakeup = pm_wakeup_pending();
 171                if (!(suspend_test(TEST_CORE) || *wakeup)) {
 172                        error = suspend_ops->enter(state);
 173                        events_check_enabled = false;
 174                }
 175                syscore_resume();
 176        }
 177
 178        arch_suspend_enable_irqs();
 179        BUG_ON(irqs_disabled());
 180
 181 Enable_cpus:
 182        enable_nonboot_cpus();
 183
 184 Platform_wake:
 185        if (suspend_ops->wake)
 186                suspend_ops->wake();
 187
 188        dpm_resume_start(PMSG_RESUME);
 189
 190 Platform_finish:
 191        if (suspend_ops->finish)
 192                suspend_ops->finish();
 193
 194        return error;
 195}
 196
 197/**
 198 * suspend_devices_and_enter - Suspend devices and enter system sleep state.
 199 * @state: System sleep state to enter.
 200 */
 201int suspend_devices_and_enter(suspend_state_t state)
 202{
 203        int error;
 204        bool wakeup = false;
 205
 206        if (!suspend_ops)
 207                return -ENOSYS;
 208
 209        trace_machine_suspend(state);
 210        if (suspend_ops->begin) {
 211                error = suspend_ops->begin(state);
 212                if (error)
 213                        goto Close;
 214        }
 215        suspend_console();
 216        ftrace_stop();
 217        suspend_test_start();
 218        error = dpm_suspend_start(PMSG_SUSPEND);
 219        if (error) {
 220                printk(KERN_ERR "PM: Some devices failed to suspend\n");
 221                goto Recover_platform;
 222        }
 223        suspend_test_finish("suspend devices");
 224        if (suspend_test(TEST_DEVICES))
 225                goto Recover_platform;
 226
 227        do {
 228                error = suspend_enter(state, &wakeup);
 229        } while (!error && !wakeup
 230                && suspend_ops->suspend_again && suspend_ops->suspend_again());
 231
 232 Resume_devices:
 233        suspend_test_start();
 234        dpm_resume_end(PMSG_RESUME);
 235        suspend_test_finish("resume devices");
 236        ftrace_start();
 237        resume_console();
 238 Close:
 239        if (suspend_ops->end)
 240                suspend_ops->end();
 241        trace_machine_suspend(PWR_EVENT_EXIT);
 242        return error;
 243
 244 Recover_platform:
 245        if (suspend_ops->recover)
 246                suspend_ops->recover();
 247        goto Resume_devices;
 248}
 249
 250/**
 251 * suspend_finish - Clean up before finishing the suspend sequence.
 252 *
 253 * Call platform code to clean up, restart processes, and free the console that
 254 * we've allocated. This routine is not called for hibernation.
 255 */
 256static void suspend_finish(void)
 257{
 258        suspend_thaw_processes();
 259        pm_notifier_call_chain(PM_POST_SUSPEND);
 260        pm_restore_console();
 261}
 262
 263/**
 264 * enter_state - Do common work needed to enter system sleep state.
 265 * @state: System sleep state to enter.
 266 *
 267 * Make sure that no one else is trying to put the system into a sleep state.
 268 * Fail if that's not the case.  Otherwise, prepare for system suspend, make the
 269 * system enter the given sleep state and clean up after wakeup.
 270 */
 271static int enter_state(suspend_state_t state)
 272{
 273        int error;
 274
 275        if (!valid_state(state))
 276                return -ENODEV;
 277
 278        if (!mutex_trylock(&pm_mutex))
 279                return -EBUSY;
 280
 281        printk(KERN_INFO "PM: Syncing filesystems ... ");
 282        sys_sync();
 283        printk("done.\n");
 284
 285        pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
 286        error = suspend_prepare();
 287        if (error)
 288                goto Unlock;
 289
 290        if (suspend_test(TEST_FREEZER))
 291                goto Finish;
 292
 293        pr_debug("PM: Entering %s sleep\n", pm_states[state]);
 294        pm_restrict_gfp_mask();
 295        error = suspend_devices_and_enter(state);
 296        pm_restore_gfp_mask();
 297
 298 Finish:
 299        pr_debug("PM: Finishing wakeup.\n");
 300        suspend_finish();
 301 Unlock:
 302        mutex_unlock(&pm_mutex);
 303        return error;
 304}
 305
 306/**
 307 * pm_suspend - Externally visible function for suspending the system.
 308 * @state: System sleep state to enter.
 309 *
 310 * Check if the value of @state represents one of the supported states,
 311 * execute enter_state() and update system suspend statistics.
 312 */
 313int pm_suspend(suspend_state_t state)
 314{
 315        int error;
 316
 317        if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX)
 318                return -EINVAL;
 319
 320        error = enter_state(state);
 321        if (error) {
 322                suspend_stats.fail++;
 323                dpm_save_failed_errno(error);
 324        } else {
 325                suspend_stats.success++;
 326        }
 327        return error;
 328}
 329EXPORT_SYMBOL(pm_suspend);
 330
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.