/** * hibernation_platform_enter - Power off the system using the platform driver. */ 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->begin(); if (error) goto Close; entering_platform_hibernation = true; suspend_console(); ftrace_stop(); error = dpm_suspend_start(PMSG_HIBERNATE); if (error) { if (hibernation_ops->recover) hibernation_ops->recover(); goto Resume_devices; } error = dpm_suspend_end(PMSG_HIBERNATE); if (error) goto Resume_devices; error = hibernation_ops->prepare(); if (error) goto Platform_finish; error = disable_nonboot_cpus(); if (error) goto Platform_finish; local_irq_disable(); syscore_suspend(); if (pm_wakeup_pending()) { error = -EAGAIN; goto Power_up; } hibernation_ops->enter(); /* We should never get here */ while (1); Power_up: syscore_resume(); local_irq_enable(); enable_nonboot_cpus(); Platform_finish: hibernation_ops->finish(); dpm_resume_start(PMSG_RESTORE); Resume_devices: entering_platform_hibernation = false; dpm_resume_end(PMSG_RESTORE); ftrace_start(); resume_console(); Close: hibernation_ops->end(); return error; }
/** * hibernation_snapshot - Quiesce devices and create a hibernation image. * @platform_mode: If set, use platform driver to prepare for the transition. * * This routine must be called with pm_mutex held. */ int hibernation_snapshot(int platform_mode) { pm_message_t msg; int error; error = platform_begin(platform_mode); if (error) goto Close; /* Preallocate image memory before shutting down devices. */ error = hibernate_preallocate_memory(); if (error) goto Close; error = freeze_kernel_threads(); if (error) goto Cleanup; if (hibernation_test(TEST_FREEZER)) { /* * Indicate to the caller that we are returning due to a * successful freezer test. */ freezer_test_done = true; goto Thaw; } error = dpm_prepare(PMSG_FREEZE); if (error) { dpm_complete(PMSG_RECOVER); goto Thaw; } suspend_console(); ftrace_stop(); pm_restrict_gfp_mask(); error = dpm_suspend(PMSG_FREEZE); if (error || hibernation_test(TEST_DEVICES)) platform_recover(platform_mode); else error = create_image(platform_mode); /* * In the case that we call create_image() above, the control * returns here (1) after the image has been created or the * image creation has failed and (2) after a successful restore. */ /* We may need to release the preallocated image pages here. */ if (error || !in_suspend) swsusp_free(); msg = in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE; dpm_resume(msg); if (error || !in_suspend) pm_restore_gfp_mask(); ftrace_start(); resume_console(); dpm_complete(msg); Close: platform_end(platform_mode); return error; Thaw: thaw_kernel_threads(); Cleanup: swsusp_free(); goto Close; }
static int software_resume(void) { int error; down(&pm_sem); if (!swsusp_resume_device) { if (!strlen(resume_file)) { up(&pm_sem); return -ENOENT; } swsusp_resume_device = name_to_dev_t(resume_file); pr_debug("swsusp: Resume From Partition %s\n", resume_file); } else { pr_debug("swsusp: Resume From Partition %d:%d\n", MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device)); } if (noresume) { /** * FIXME: If noresume is specified, we need to find the partition * and reset it back to normal swap space. */ up(&pm_sem); return 0; } pr_debug("PM: Checking swsusp image.\n"); if ((error = swsusp_check())) goto Done; pr_debug("PM: Preparing processes for restore.\n"); if ((error = prepare_processes())) { swsusp_close(); goto Done; } pr_debug("PM: Reading swsusp image.\n"); if ((error = swsusp_read())) { swsusp_free(); goto Thaw; } pr_debug("PM: Preparing devices for restore.\n"); suspend_console(); if ((error = device_suspend(PMSG_PRETHAW))) { resume_console(); printk("Some devices failed to suspend\n"); swsusp_free(); goto Thaw; } mb(); pr_debug("PM: Restoring saved image.\n"); swsusp_resume(); pr_debug("PM: Restore failed, recovering.n"); device_resume(); resume_console(); Thaw: unprepare_processes(); Done: /* For success case, the suspend path will release the lock */ up(&pm_sem); pr_debug("PM: Resume from disk failed.\n"); return 0; }
int hibernation_platform_enter(void) { int error; gfp_t saved_mask; 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->begin(); if (error) goto Close; entering_platform_hibernation = true; suspend_console(); saved_mask = clear_gfp_allowed_mask(GFP_IOFS); error = dpm_suspend_start(PMSG_HIBERNATE); if (error) { if (hibernation_ops->recover) hibernation_ops->recover(); goto Resume_devices; } error = dpm_suspend_noirq(PMSG_HIBERNATE); if (error) goto Resume_devices; error = hibernation_ops->prepare(); if (error) goto Platform_finish; error = disable_nonboot_cpus(); if (error) goto Platform_finish; local_irq_disable(); sysdev_suspend(PMSG_HIBERNATE); hibernation_ops->enter(); /* We should never get here */ while (1); /* * We don't need to reenable the nonboot CPUs or resume consoles, since * the system is going to be halted anyway. */ Platform_finish: hibernation_ops->finish(); dpm_suspend_noirq(PMSG_RESTORE); Resume_devices: entering_platform_hibernation = false; dpm_resume_end(PMSG_RESTORE); set_gfp_allowed_mask(saved_mask); resume_console(); Close: hibernation_ops->end(); return error; }
static int snapshot_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { int error = 0; struct snapshot_data *data; loff_t avail; sector_t offset; if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR) return -ENOTTY; if (!capable(CAP_SYS_ADMIN)) return -EPERM; data = filp->private_data; switch (cmd) { case SNAPSHOT_FREEZE: if (data->frozen) break; mutex_lock(&pm_mutex); if (freeze_processes()) { thaw_processes(); error = -EBUSY; } mutex_unlock(&pm_mutex); if (!error) data->frozen = 1; break; case SNAPSHOT_UNFREEZE: if (!data->frozen) break; mutex_lock(&pm_mutex); thaw_processes(); mutex_unlock(&pm_mutex); data->frozen = 0; break; case SNAPSHOT_ATOMIC_SNAPSHOT: if (data->mode != O_RDONLY || !data->frozen || data->ready) { error = -EPERM; break; } error = snapshot_suspend(data->platform_suspend); if (!error) error = put_user(in_suspend, (unsigned int __user *)arg); if (!error) data->ready = 1; break; case SNAPSHOT_ATOMIC_RESTORE: snapshot_write_finalize(&data->handle); if (data->mode != O_WRONLY || !data->frozen || !snapshot_image_loaded(&data->handle)) { error = -EPERM; break; } error = snapshot_restore(data->platform_suspend); break; case SNAPSHOT_FREE: swsusp_free(); memset(&data->handle, 0, sizeof(struct snapshot_handle)); data->ready = 0; break; case SNAPSHOT_SET_IMAGE_SIZE: image_size = arg; break; case SNAPSHOT_AVAIL_SWAP: avail = count_swap_pages(data->swap, 1); avail <<= PAGE_SHIFT; error = put_user(avail, (loff_t __user *)arg); break; case SNAPSHOT_GET_SWAP_PAGE: if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { error = -ENODEV; break; } if (!data->bitmap) { data->bitmap = alloc_bitmap(count_swap_pages(data->swap, 0)); if (!data->bitmap) { error = -ENOMEM; break; } } offset = alloc_swapdev_block(data->swap, data->bitmap); if (offset) { offset <<= PAGE_SHIFT; error = put_user(offset, (sector_t __user *)arg); } else { error = -ENOSPC; } break; case SNAPSHOT_FREE_SWAP_PAGES: if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { error = -ENODEV; break; } free_all_swap_pages(data->swap, data->bitmap); free_bitmap(data->bitmap); data->bitmap = NULL; break; case SNAPSHOT_SET_SWAP_FILE: if (!data->bitmap) { /* * User space encodes device types as two-byte values, * so we need to recode them */ if (old_decode_dev(arg)) { data->swap = swap_type_of(old_decode_dev(arg), 0, NULL); if (data->swap < 0) error = -ENODEV; } else { data->swap = -1; error = -EINVAL; } } else { error = -EPERM; } break; case SNAPSHOT_S2RAM: if (!pm_ops) { error = -ENOSYS; break; } if (!data->frozen) { error = -EPERM; break; } if (!mutex_trylock(&pm_mutex)) { error = -EBUSY; break; } if (pm_ops->prepare) { error = pm_ops->prepare(PM_SUSPEND_MEM); if (error) goto OutS3; } /* Put devices to sleep */ suspend_console(); error = device_suspend(PMSG_SUSPEND); if (error) { printk(KERN_ERR "Failed to suspend some devices.\n"); } else { /* Enter S3, system is already frozen */ suspend_enter(PM_SUSPEND_MEM); /* Wake up devices */ device_resume(); } resume_console(); if (pm_ops->finish) pm_ops->finish(PM_SUSPEND_MEM); OutS3: mutex_unlock(&pm_mutex); break; case SNAPSHOT_PMOPS: error = -EINVAL; switch (arg) { case PMOPS_PREPARE: if (pm_ops && pm_ops->enter) { data->platform_suspend = 1; error = 0; } else { error = -ENOSYS; } break; case PMOPS_ENTER: if (data->platform_suspend) { disable_nonboot_cpus(); kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); error = pm_ops->enter(PM_SUSPEND_DISK); enable_nonboot_cpus(); } break; case PMOPS_FINISH: if (data->platform_suspend) error = 0; break; default: printk(KERN_ERR "SNAPSHOT_PMOPS: invalid argument %ld\n", arg); } break; case SNAPSHOT_SET_SWAP_AREA: if (data->bitmap) { error = -EPERM; } else { struct resume_swap_area swap_area; dev_t swdev; error = copy_from_user(&swap_area, (void __user *)arg, sizeof(struct resume_swap_area)); if (error) { error = -EFAULT; break; } /* * User space encodes device types as two-byte values, * so we need to recode them */ swdev = old_decode_dev(swap_area.dev); if (swdev) { offset = swap_area.offset; data->swap = swap_type_of(swdev, offset, NULL); if (data->swap < 0) error = -ENODEV; } else { data->swap = -1; error = -EINVAL; } } break; default: error = -ENOTTY; } return error; }
/** * hom_freeze_devices_and_enter - * freeze devices and enter in hibernation on memory */ static int hibernation_on_memory_enter(void) { int error = 0; unsigned long pe_counter; if (!hom_ops) return -ENOSYS; pr_debug("[STM]:[PM]: platform_begin\n"); error = platform_begin(); if (error) goto Close; suspend_console(); pr_debug("[STM]:[PM]: Suspend devices\n"); error = dpm_suspend_start(PMSG_FREEZE); if (error) goto Resume_devices; pr_debug("[STM]:[PM]: Suspend devices (noirq)\n"); error = dpm_suspend_noirq(PMSG_FREEZE); if (error) goto Resume_devices_noirq; error = disable_nonboot_cpus(); if (error) goto Enable_cpus; local_irq_disable(); pr_debug("[STM]:[PM]: Suspend sysdevices\n"); error = sysdev_suspend(PMSG_FREEZE); if (error) goto Enable_irqs; pr_debug("[STM]:[PM]: platform_prepare\n"); error = platform_prepare(); if (error) { pr_err("[STM]:[PM]: platform_prepare has refused the HoM\n"); goto Skip_enter; } pr_debug("[STM]:[PM]: platform_enter\n"); pe_counter = preempt_count(); platform_enter(); BUG_ON(pe_counter != preempt_count()); Skip_enter: pr_debug("[STM]:[PM]: platform_complete\n"); platform_complete(); pr_debug("[STM]:[PM]: Resumed sysdevices\n"); sysdev_resume(); Enable_irqs: local_irq_enable(); Enable_cpus: enable_nonboot_cpus(); Resume_devices_noirq: pr_debug("[STM]:[PM]: Resume devices (noirq)\n"); dpm_resume_noirq(PMSG_RESTORE); Resume_devices: pr_debug("[STM]:[PM]: Resume devices\n"); dpm_resume_end(PMSG_RESTORE); resume_console(); Close: pr_debug("[STM]:[PM]: platform_end\n"); platform_end(); pr_debug("[STM]:[PM]: exit\n"); return error; }