/** * create_image - Create a hibernation image. * @platform_mode: Whether or not to use the platform driver. * * Execute device drivers' "late" and "noirq" freeze callbacks, create a * hibernation image and run the drivers' "noirq" and "early" thaw callbacks. * * Control reappears in this routine after the subsequent restore. */ static int create_image(int platform_mode) { int error; error = dpm_suspend_end(PMSG_FREEZE); if (error) { printk(KERN_ERR "PM: Some devices failed to power down, " "aborting hibernation\n"); return error; } error = platform_pre_snapshot(platform_mode); if (error || hibernation_test(TEST_PLATFORM)) goto Platform_finish; error = disable_nonboot_cpus(); if (error || hibernation_test(TEST_CPUS)) goto Enable_cpus; local_irq_disable(); error = syscore_suspend(); if (error) { printk(KERN_ERR "PM: Some system devices failed to power down, " "aborting hibernation\n"); goto Enable_irqs; } if (hibernation_test(TEST_CORE) || pm_wakeup_pending()) goto Power_up; in_suspend = 1; save_processor_state(); error = swsusp_arch_suspend(); if (error) printk(KERN_ERR "PM: Error %d creating hibernation image\n", error); /* Restore control flow magically appears here */ restore_processor_state(); if (!in_suspend) { events_check_enabled = false; platform_leave(platform_mode); } Power_up: syscore_resume(); Enable_irqs: local_irq_enable(); Enable_cpus: enable_nonboot_cpus(); Platform_finish: platform_finish(platform_mode); dpm_resume_start(in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); return error; }
static int resume_target_kernel(bool platform_mode) { int error; error = dpm_suspend_noirq(PMSG_QUIESCE); if (error) { printk(KERN_ERR "PM: Some devices failed to power down, " "aborting resume\n"); return error; } error = platform_pre_restore(platform_mode); if (error) goto Cleanup; error = disable_nonboot_cpus(); if (error) goto Enable_cpus; local_irq_disable(); error = sysdev_suspend(PMSG_QUIESCE); if (error) goto Enable_irqs; /* We'll ignore saved state, but this gets preempt count (etc) right */ save_processor_state(); error = restore_highmem(); if (!error) { error = swsusp_arch_resume(); /* * The code below is only ever reached in case of a failure. * Otherwise execution continues at place where * swsusp_arch_suspend() was called */ BUG_ON(!error); /* This call to restore_highmem() undos the previous one */ restore_highmem(); } /* * The only reason why swsusp_arch_resume() can fail is memory being * very tight, so we have to free it as soon as we can to avoid * subsequent failures */ swsusp_free(); restore_processor_state(); touch_softlockup_watchdog(); sysdev_resume(); Enable_irqs: local_irq_enable(); Enable_cpus: enable_nonboot_cpus(); Cleanup: platform_restore_cleanup(platform_mode); dpm_resume_noirq(PMSG_RECOVER); return error; }
/* ********************************************************************************************************* * aw_early_suspend * *Description: prepare necessary info for suspend&resume; * *Return : return 0 is process successed; * *Notes : ********************************************************************************************************* */ static int aw_super_standby(suspend_state_t state) { int result = 0; suspend_status_flag = 0; mem_para_info.axp_enable = standby_axp_enable; mem_enter: if( 1 == mem_para_info.mem_flag){ invalidate_branch_predictor(); //must be called to invalidate I-cache inner shareable? // I+BTB cache invalidate __cpuc_flush_icache_all(); //disable 0x0000 <---> 0x0000 mapping restore_processor_state(); mem_flush_tlb(); //destroy 0x0000 <---> 0x0000 mapping //restore_mapping(MEM_SW_VA_SRAM_BASE); mem_arch_resume(); goto resume; } save_runtime_context(mem_para_info.saved_runtime_context_svc); mem_para_info.mem_flag = 1; standby_level = STANDBY_WITH_POWER_OFF; mem_para_info.resume_pointer = (void *)&&mem_enter; mem_para_info.debug_mask = debug_mask; mem_para_info.suspend_delay_ms = suspend_delay_ms; //busy_waiting(); if(unlikely(debug_mask&PM_STANDBY_PRINT_STANDBY)){ pr_info("resume_pointer = 0x%x. \n", (unsigned int)(mem_para_info.resume_pointer)); } #if 1 /* config system wakeup evetn type */ if(PM_SUSPEND_MEM == state || PM_SUSPEND_STANDBY == state){ mem_para_info.axp_event = AXP_MEM_WAKEUP | AXP_WAKEUP_PIO_ANY; }else if(PM_SUSPEND_BOOTFAST == state){ mem_para_info.axp_event = AXP_BOOTFAST_WAKEUP; } #endif result = aw_early_suspend(); if(-2 == result){ //mem_para_info.mem_flag = 1; //busy_waiting(); suspend_status_flag = 2; goto mem_enter; }else if(-1 == result){ suspend_status_flag = 1; mem_para_info.mem_flag = 0; goto suspend_err; } resume: aw_late_resume(); //have been disable dcache in resume1 //enable_cache(); suspend_err: if(unlikely(debug_mask&PM_STANDBY_PRINT_RESUME)){ pr_info("suspend_status_flag = %d. \n", suspend_status_flag); } return 0; }
static int create_image(int platform_mode) { int error; error = arch_prepare_suspend(); if (error) return error; /* At this point, dpm_suspend_start() has been called, but *not* * dpm_suspend_noirq(). We *must* call dpm_suspend_noirq() 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 = dpm_suspend_noirq(PMSG_FREEZE); if (error) { printk(KERN_ERR "PM: Some devices failed to power down, " "aborting hibernation\n"); return error; } error = platform_pre_snapshot(platform_mode); if (error || hibernation_test(TEST_PLATFORM)) goto Platform_finish; error = disable_nonboot_cpus(); if (error || hibernation_test(TEST_CPUS) || hibernation_testmode(HIBERNATION_TEST)) goto Enable_cpus; local_irq_disable(); error = sysdev_suspend(PMSG_FREEZE); if (error) { printk(KERN_ERR "PM: Some system devices failed to power down, " "aborting hibernation\n"); goto Enable_irqs; } if (hibernation_test(TEST_CORE) || !pm_check_wakeup_events()) goto Power_up; in_suspend = 1; save_processor_state(); error = swsusp_arch_suspend(); if (error) printk(KERN_ERR "PM: Error %d creating hibernation image\n", error); /* Restore control flow magically appears here */ restore_processor_state(); if (!in_suspend) { events_check_enabled = false; platform_leave(platform_mode); } Power_up: sysdev_resume(); /* NOTE: dpm_resume_noirq() is just a resume() for devices * that suspended with irqs off ... no overall powerup. */ Enable_irqs: local_irq_enable(); Enable_cpus: enable_nonboot_cpus(); Platform_finish: platform_finish(platform_mode); dpm_resume_noirq(in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); return error; }