/* * Do not allocate memory (or fail in any way) in machine_kexec(). * We are past the point of no return, committed to rebooting now. */ void machine_kexec(struct kimage *image) { unsigned long page_list[PAGES_NR]; void *control_page; int save_ftrace_enabled; asmlinkage unsigned long (*relocate_kernel_ptr)(unsigned long indirection_page, unsigned long control_page, unsigned long start_address, unsigned int has_pae, unsigned int preserve_context); #ifdef CONFIG_KEXEC_JUMP if (image->preserve_context) save_processor_state(); #endif save_ftrace_enabled = __ftrace_enabled_save(); /* Interrupts aren't acceptable while we reboot */ local_irq_disable(); if (image->preserve_context) { #ifdef CONFIG_X86_IO_APIC /* * We need to put APICs in legacy mode so that we can * get timer interrupts in second kernel. kexec/kdump * paths already have calls to disable_IO_APIC() in * one form or other. kexec jump path also need * one. */ disable_IO_APIC(); #endif } control_page = page_address(image->control_code_page); memcpy(control_page, relocate_kernel, KEXEC_CONTROL_CODE_MAX_SIZE); relocate_kernel_ptr = control_page; page_list[PA_CONTROL_PAGE] = __pa(control_page); page_list[VA_CONTROL_PAGE] = (unsigned long)control_page; page_list[PA_PGD] = __pa(image->arch.pgd); if (image->type == KEXEC_TYPE_DEFAULT) page_list[PA_SWAP_PAGE] = (page_to_pfn(image->swap_page) << PAGE_SHIFT); /* now call it */ image->start = relocate_kernel_ptr((unsigned long)image->head, (unsigned long)page_list, image->start, cpu_has_pae, image->preserve_context); #ifdef CONFIG_KEXEC_JUMP if (image->preserve_context) restore_processor_state(); #endif __ftrace_enabled_restore(save_ftrace_enabled); }
int swsusp_suspend(void) { int error; if ((error = arch_prepare_suspend())) return error; local_irq_disable(); /* At this point, device_suspend() has been called, but *not* * device_power_down(). We *must* 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. */ if ((error = device_power_down(PMSG_FREEZE))) { printk(KERN_ERR "Some devices failed to power down, aborting suspend\n"); goto Enable_irqs; } if ((error = save_highmem())) { printk(KERN_ERR "swsusp: Not enough free pages for highmem\n"); goto Restore_highmem; } save_processor_state(); if ((error = swsusp_arch_suspend())) printk(KERN_ERR "Error %d suspending\n", error); /* Restore control flow magically appears here */ restore_processor_state(); Restore_highmem: restore_highmem(); device_power_up(); Enable_irqs: local_irq_enable(); return error; }
int swsusp_resume(void) { int error; local_irq_disable(); /* NOTE: device_power_down() is just a suspend() with irqs off; * it has no special "power things down" semantics */ if (device_power_down(PMSG_PRETHAW)) printk(KERN_ERR "Some devices failed to power down, very bad\n"); /* 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(); device_power_up(); local_irq_enable(); return error; }
int swsusp_resume(void) { int error; local_irq_disable(); if (device_power_down(PMSG_FREEZE)) printk(KERN_ERR "Some devices failed to power down, very bad\n"); /* We'll ignore saved state, but this gets preempt count (etc) right */ save_processor_state(); error = swsusp_arch_resume(); /* Code below is only ever reached in case of failure. Otherwise * execution continues at place where swsusp_arch_suspend was called */ BUG_ON(!error); /* 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(); restore_highmem(); touch_softlockup_watchdog(); device_power_up(); local_irq_enable(); return error; }
int swsusp_suspend(void) { int error; if ((error = arch_prepare_suspend())) return error; local_irq_disable(); /* At this point, device_suspend() has been called, but *not* * device_power_down(). We *must* 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. */ if ((error = device_power_down(PMSG_FREEZE))) { local_irq_enable(); return error; } save_processor_state(); error = swsusp_arch_suspend(); /* Restore control flow magically appears here */ restore_processor_state(); restore_highmem(); device_power_up(); local_irq_enable(); return error; }
int __init pmdisk_restore(void) { int error; local_irq_disable(); save_processor_state(); error = pmdisk_arch_suspend(1); restore_processor_state(); local_irq_enable(); return error; }
static int create_image(int platform_mode) { int error; error = arch_prepare_suspend(); if (error) return error; device_pm_lock(); 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 "PM: Some devices failed to power down, " "aborting hibernation\n"); goto Enable_irqs; } if (hibernation_test(TEST_CORE)) 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) platform_leave(platform_mode); Power_up: /* NOTE: device_power_up() is just a resume() for devices * that suspended with irqs off ... no overall powerup. */ device_power_up(in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); Enable_irqs: local_irq_enable(); device_pm_unlock(); return error; }
int pmdisk_save(void) { int error; #if defined (CONFIG_HIGHMEM) || defined (CONFIG_DISCONTIGMEM) pr_debug("pmdisk: not supported with high- or discontig-mem.\n"); return -EPERM; #endif if ((error = arch_prepare_suspend())) return error; local_irq_disable(); save_processor_state(); error = pmdisk_arch_suspend(0); restore_processor_state(); local_irq_enable(); return error; }
int swsusp_resume(void) { int error; local_irq_disable(); device_power_down(PMSG_FREEZE); /* We'll ignore saved state, but this gets preempt count (etc) right */ save_processor_state(); error = swsusp_arch_resume(); /* Code below is only ever reached in case of failure. Otherwise * execution continues at place where swsusp_arch_suspend was called */ BUG_ON(!error); restore_processor_state(); restore_highmem(); device_power_up(); local_irq_enable(); return error; }
/** * toi_atomic_restore - prepare to do the atomic restore * * Get ready to do the atomic restore. This part gets us into the same * state we are in prior to do calling do_toi_lowlevel while * hibernating: hot-unplugging secondary cpus and freeze processes, * before starting the thread that will do the restore. **/ int toi_atomic_restore(void) { int error; toi_running = 1; toi_prepare_status(DONT_CLEAR_BAR, "Atomic restore."); memcpy(&toi_bkd.toi_nosave_commandline, saved_command_line, strlen(saved_command_line)); toi_pre_atomic_restore_modules(&toi_bkd); if (add_boot_kernel_data_pbe()) goto Failed; toi_prepare_status(DONT_CLEAR_BAR, "Doing atomic copy/restore."); if (toi_go_atomic(PMSG_QUIESCE, 0)) goto Failed; /* We'll ignore saved state, but this gets preempt count (etc) right */ save_processor_state(); error = swsusp_arch_resume(); /* * Code below is only ever reached in case of failure. Otherwise * execution continues at place where swsusp_arch_suspend was called. * * We don't know whether it's safe to continue (this shouldn't happen), * so lets err on the side of caution. */ BUG(); Failed: free_pbe_list(&restore_pblist, 0); #ifdef CONFIG_HIGHMEM pr_warn("[%s] 0x%p 0x%p 0x%p\n", __func__, restore_highmem_pblist->address, restore_highmem_pblist->orig_address, restore_highmem_pblist->next); if (restore_highmem_pblist->next != NULL) free_pbe_list(&restore_highmem_pblist, 1); #endif toi_running = 0; return 1; }
static int resume_target_kernel(void) { int error; device_pm_lock(); local_irq_disable(); error = device_power_down(PMSG_QUIESCE); if (error) { printk(KERN_ERR "PM: Some devices failed to power down, " "aborting resume\n"); 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(); device_power_up(PMSG_RECOVER); Enable_irqs: local_irq_enable(); device_pm_unlock(); return error; }
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; }
/** * resume_target_kernel - Restore system state from a hibernation image. * @platform_mode: Whether or not to use the platform driver. * * Execute device drivers' "noirq" and "late" freeze callbacks, restore the * contents of highmem that have not been restored yet from the image and run * the low-level code that will restore the remaining contents of memory and * switch to the just restored target kernel. */ static int resume_target_kernel(bool platform_mode) { int error; error = dpm_suspend_end(PMSG_QUIESCE); if (error) { pr_err("Some devices failed to power down, aborting resume\n"); return error; } error = platform_pre_restore(platform_mode); if (error) goto Cleanup; error = hibernate_resume_nonboot_cpu_disable(); if (error) goto Enable_cpus; local_irq_disable(); error = syscore_suspend(); if (error) goto Enable_irqs; 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 the place where * swsusp_arch_suspend() was called. */ BUG_ON(!error); /* * This call to restore_highmem() reverts the changes made by * 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(); syscore_resume(); Enable_irqs: local_irq_enable(); Enable_cpus: enable_nonboot_cpus(); Cleanup: platform_restore_cleanup(platform_mode); dpm_resume_start(PMSG_RECOVER); return error; }
/** * 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) { pr_err("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) { pr_err("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(); trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, true); error = swsusp_arch_suspend(); /* Restore control flow magically appears here */ restore_processor_state(); trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, false); if (error) pr_err("Error %d creating hibernation image\n", error); if (!in_suspend) { events_check_enabled = false; clear_free_pages(); } 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 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; }
/* ********************************************************************************************************* * aw_early_suspend * *Description: prepare necessary info for suspend&resume; * *Return : return 0 is process successed; * *Notes : -1: data is ok; * -2: data has been destory. ********************************************************************************************************* */ static int aw_early_suspend(void) { #define MAX_RETRY_TIMES (5) __s32 retry = MAX_RETRY_TIMES; //backup device state mem_ccu_save((__ccmu_reg_list_t *)(SW_VA_CCM_IO_BASE)); mem_gpio_save(&(saved_gpio_state)); mem_tmr_save(&(saved_tmr_state)); mem_twi_save(&(saved_twi_state)); mem_sram_save(&(saved_sram_state)); if (likely(mem_para_info.axp_enable)) { //backup volt and freq state, after backup device state mem_twi_init(AXP_IICBUS); /* backup voltages */ while(-1 == (mem_para_info.suspend_dcdc2 = mem_get_voltage(POWER_VOL_DCDC2)) && --retry){ ; } if(0 == retry){ print_call_info(); return -1; }else{ retry = MAX_RETRY_TIMES; } while(-1 == (mem_para_info.suspend_dcdc3 = mem_get_voltage(POWER_VOL_DCDC3)) && --retry){ ; } if(0 == retry){ print_call_info(); return -1; }else{ retry = MAX_RETRY_TIMES; } } else { mem_para_info.suspend_dcdc2 = -1; mem_para_info.suspend_dcdc3 = -1; } printk("dcdc2:%d, dcdc3:%d\n", mem_para_info.suspend_dcdc2, mem_para_info.suspend_dcdc3); /*backup bus ratio*/ mem_clk_getdiv(&mem_para_info.clk_div); /*backup pll ratio*/ mem_clk_get_pll_factor(&mem_para_info.pll_factor); //backup mmu save_mmu_state(&(mem_para_info.saved_mmu_state)); //backup cpu state // __save_processor_state(&(mem_para_info.saved_cpu_context)); //backup 0x0000,0000 page entry, size? // save_mapping(MEM_SW_VA_SRAM_BASE); // mem_para_info.saved_cpu_context.ttb_1r = DRAM_STANDBY_PGD_PA; memcpy((void*)(DRAM_STANDBY_PGD_ADDR + 0x3000), (void*)0xc0007000, 0x1000); __cpuc_coherent_kern_range(DRAM_STANDBY_PGD_ADDR + 0x3000, DRAM_STANDBY_PGD_ADDR + 0x4000 - 1); mem_para_info.saved_mmu_state.ttb_1r = DRAM_STANDBY_PGD_PA; //prepare resume0 code for resume if((DRAM_BACKUP_SIZE1) < sizeof(mem_para_info)){ //judge the reserved space for mem para is enough or not. print_call_info(); return -1; } //clean all the data into dram memcpy((void *)DRAM_BACKUP_BASE_ADDR1, (void *)&mem_para_info, sizeof(mem_para_info)); dmac_flush_range((void *)DRAM_BACKUP_BASE_ADDR1, (void *)(DRAM_BACKUP_BASE_ADDR1 + DRAM_BACKUP_SIZE1 - 1)); //prepare dram training area data memcpy((void *)DRAM_BACKUP_BASE_ADDR2, (void *)DRAM_BASE_ADDR, DRAM_TRANING_SIZE); dmac_flush_range((void *)DRAM_BACKUP_BASE_ADDR2, (void *)(DRAM_BACKUP_BASE_ADDR2 + DRAM_BACKUP_SIZE2 - 1)); mem_arch_suspend(); save_processor_state(); //before creating mapping, build the coherent between cache and memory __cpuc_flush_kern_all(); __cpuc_coherent_kern_range(0xc0000000, 0xffffffff-1); //create 0x0000,0000 mapping table: 0x0000,0000 -> 0x0000,0000 //create_mapping(); //clean and flush mem_flush_tlb(); #ifdef PRE_DISABLE_MMU //jump to sram: dram enter selfresh, and power off. mem = (super_standby_func)SRAM_FUNC_START_PA; #else //jump to sram: dram enter selfresh, and power off. mem = (super_standby_func)SRAM_FUNC_START; #endif //move standby code to sram memcpy((void *)SRAM_FUNC_START, (void *)&suspend_bin_start, (int)&suspend_bin_end - (int)&suspend_bin_start); #ifdef CONFIG_AW_FPGA_PLATFORM *(unsigned int *)(0xf0007000 - 0x4) = 0x12345678; printk("%s,%d:%d\n",__FILE__,__LINE__, *(unsigned int *)(0xf0007000 - 0x4)); #endif #ifdef PRE_DISABLE_MMU //enable the mapping and jump //invalidate tlb? maybe, but now, at this situation, 0x0000 <--> 0x0000 mapping never stay in tlb before this. //busy_waiting(); jump_to_suspend(mem_para_info.saved_mmu_state.ttb_1r, mem); #else mem(); #endif return -2; }
/** * create_image - Create a hibernation image. * @platform_mode: Whether or not to use the platform driver. * * Execute device drivers' .freeze_noirq() callbacks, create a hibernation image * and execute the drivers' .thaw_noirq() callbacks. * * Control reappears in this routine after the subsequent restore. */ static int create_image(int platform_mode) { int error; 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 = 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_noirq(in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); return error; }