📄 disk.c
字号:
/* * kernel/power/disk.c - Suspend-to-disk support. * * Copyright (c) 2003 Patrick Mochel * Copyright (c) 2003 Open Source Development Lab * Copyright (c) 2004 Pavel Machek <pavel@suse.cz> * * This file is released under the GPLv2. * */#include <linux/suspend.h>#include <linux/syscalls.h>#include <linux/reboot.h>#include <linux/string.h>#include <linux/device.h>#include <linux/delay.h>#include <linux/fs.h>#include <linux/mount.h>#include <linux/pm.h>#include <linux/console.h>#include <linux/cpu.h>#include <linux/freezer.h>#include "power.h"static int noresume = 0;char resume_file[256] = CONFIG_PM_STD_PARTITION;dev_t swsusp_resume_device;sector_t swsusp_resume_block;enum { HIBERNATION_INVALID, HIBERNATION_PLATFORM, HIBERNATION_TEST, HIBERNATION_TESTPROC, HIBERNATION_SHUTDOWN, HIBERNATION_REBOOT, /* keep last */ __HIBERNATION_AFTER_LAST};#define HIBERNATION_MAX (__HIBERNATION_AFTER_LAST-1)#define HIBERNATION_FIRST (HIBERNATION_INVALID + 1)static int hibernation_mode = HIBERNATION_SHUTDOWN;static struct platform_hibernation_ops *hibernation_ops;/** * hibernation_set_ops - set the global hibernate operations * @ops: the hibernation operations to use in subsequent hibernation transitions */void hibernation_set_ops(struct platform_hibernation_ops *ops){ if (ops && !(ops->start && ops->pre_snapshot && ops->finish && ops->prepare && ops->enter && ops->pre_restore && ops->restore_cleanup)) { WARN_ON(1); return; } mutex_lock(&pm_mutex); hibernation_ops = ops; if (ops) hibernation_mode = HIBERNATION_PLATFORM; else if (hibernation_mode == HIBERNATION_PLATFORM) hibernation_mode = HIBERNATION_SHUTDOWN; mutex_unlock(&pm_mutex);}/** * platform_start - tell the platform driver that we're starting * hibernation */static int platform_start(int platform_mode){ return (platform_mode && hibernation_ops) ? hibernation_ops->start() : 0;}/** * platform_pre_snapshot - prepare the machine for hibernation using the * platform driver if so configured and return an error code if it fails */static int platform_pre_snapshot(int platform_mode){ return (platform_mode && hibernation_ops) ? hibernation_ops->pre_snapshot() : 0;}/** * platform_leave - prepare the machine for switching to the normal mode * of operation using the platform driver (called with interrupts disabled) */static void platform_leave(int platform_mode){ if (platform_mode && hibernation_ops) hibernation_ops->leave();}/** * platform_finish - switch the machine to the normal mode of operation * using the platform driver (must be called after platform_prepare()) */static void platform_finish(int platform_mode){ if (platform_mode && hibernation_ops) hibernation_ops->finish();}/** * platform_pre_restore - prepare the platform for the restoration from a * hibernation image. If the restore fails after this function has been * called, platform_restore_cleanup() must be called. */static int platform_pre_restore(int platform_mode){ return (platform_mode && hibernation_ops) ? hibernation_ops->pre_restore() : 0;}/** * platform_restore_cleanup - switch the platform to the normal mode of * operation after a failing restore. If platform_pre_restore() has been * called before the failing restore, this function must be called too, * regardless of the result of platform_pre_restore(). */static void platform_restore_cleanup(int platform_mode){ if (platform_mode && hibernation_ops) hibernation_ops->restore_cleanup();}/** * create_image - freeze devices that need to be frozen with interrupts * off, create the hibernation image and thaw those devices. Control * reappears in this routine after a restore. */int create_image(int platform_mode){ int error; error = arch_prepare_suspend(); if (error) return error; local_irq_disable(); /* At this point, device_suspend() has been called, but *not* * device_power_down(). We *must* call device_power_down() now. * Otherwise, drivers for some devices (e.g. interrupt controllers) * become desynchronized with the actual state of the hardware * at resume time, and evil weirdness ensues. */ error = device_power_down(PMSG_FREEZE); if (error) { printk(KERN_ERR "Some devices failed to power down, " KERN_ERR "aborting suspend\n"); goto Enable_irqs; } save_processor_state(); error = swsusp_arch_suspend(); if (error) printk(KERN_ERR "Error %d while creating the image\n", error); /* Restore control flow magically appears here */ restore_processor_state(); if (!in_suspend) platform_leave(platform_mode); /* NOTE: device_power_up() is just a resume() for devices * that suspended with irqs off ... no overall powerup. */ device_power_up(); Enable_irqs: local_irq_enable(); return error;}/** * hibernation_snapshot - quiesce devices and create the hibernation * snapshot image. * @platform_mode - if set, use the platform driver, if available, to * prepare the platform frimware for the power transition. * * Must be called with pm_mutex held */int hibernation_snapshot(int platform_mode){ int error; /* Free memory before shutting down devices. */ error = swsusp_shrink_memory(); if (error) return error; error = platform_start(platform_mode); if (error) return error; suspend_console(); error = device_suspend(PMSG_FREEZE); if (error) goto Resume_console; error = platform_pre_snapshot(platform_mode); if (error) goto Resume_devices; error = disable_nonboot_cpus(); if (!error) { if (hibernation_mode != HIBERNATION_TEST) { in_suspend = 1; error = create_image(platform_mode); /* Control returns here after successful restore */ } else { printk("swsusp debug: Waiting for 5 seconds.\n"); mdelay(5000); } } enable_nonboot_cpus(); Resume_devices: platform_finish(platform_mode); device_resume(); Resume_console: resume_console(); return error;}/** * hibernation_restore - quiesce devices and restore the hibernation * snapshot image. If successful, control returns in hibernation_snaphot() * @platform_mode - if set, use the platform driver, if available, to * prepare the platform frimware for the transition. * * Must be called with pm_mutex held */int hibernation_restore(int platform_mode){ int error; pm_prepare_console(); suspend_console(); error = device_suspend(PMSG_PRETHAW); if (error) goto Finish; error = platform_pre_restore(platform_mode); if (!error) { error = disable_nonboot_cpus(); if (!error) error = swsusp_resume(); enable_nonboot_cpus(); } platform_restore_cleanup(platform_mode); device_resume(); Finish: resume_console(); pm_restore_console(); return error;}/** * hibernation_platform_enter - enter the hibernation state using the * platform driver (if available) */int hibernation_platform_enter(void){ int error; if (!hibernation_ops) return -ENOSYS; /* * We have cancelled the power transition by running * hibernation_ops->finish() before saving the image, so we should let * the firmware know that we're going to enter the sleep state after all */ error = hibernation_ops->start(); if (error) return error; suspend_console(); error = device_suspend(PMSG_SUSPEND); if (error) goto Resume_console; error = hibernation_ops->prepare(); if (error) goto Resume_devices; error = disable_nonboot_cpus(); if (error) goto Finish; local_irq_disable(); error = device_power_down(PMSG_SUSPEND); if (!error) { hibernation_ops->enter(); /* We should never get here */ while (1); } local_irq_enable(); /* * We don't need to reenable the nonboot CPUs or resume consoles, since * the system is going to be halted anyway. */ Finish: hibernation_ops->finish(); Resume_devices: device_resume(); Resume_console: resume_console(); return error;}/** * power_down - Shut the machine down for hibernation. * * Use the platform driver, if configured so; otherwise try * to power off or reboot. */static void power_down(void){ switch (hibernation_mode) { case HIBERNATION_TEST: case HIBERNATION_TESTPROC: break; case HIBERNATION_REBOOT: kernel_restart(NULL); break; case HIBERNATION_PLATFORM: hibernation_platform_enter(); case HIBERNATION_SHUTDOWN: kernel_power_off(); break; } kernel_halt(); /* * Valid image is on the disk, if we continue we risk serious data * corruption after resume. */ printk(KERN_CRIT "Please power me down manually\n"); while(1);}static void unprepare_processes(void){ thaw_processes(); pm_restore_console();}static int prepare_processes(void){ int error = 0; pm_prepare_console(); if (freeze_processes()) { error = -EBUSY; unprepare_processes(); } return error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -