2 #include <linux/suspend.h>
3 #include <asm/cacheflush.h>
4 #include <asm/system_misc.h>
6 #include <asm/suspend.h>
8 extern void cpu_resume(void);
9 typedef void (*phys_reset_t
)(unsigned long);
10 static int swsusp_saved
= 0;
14 * Snapshot kernel memory and reset the system.
15 * After resume, the hibernation snapshot is written out.
17 static int notrace
__swsusp_arch_save_image(unsigned long unused
)
19 extern int swsusp_save(void);
23 swsusp_saved
= (ret
== 0) ? 1 : 0;
28 * Save the current CPU state before suspend / poweroff.
30 int notrace
swsusp_arch_suspend(void)
34 retval
= cpu_suspend(0, __swsusp_arch_save_image
);
42 * The framework loads the hibernation image into a linked list anchored
43 * at restore_pblist, for swsusp_arch_resume() to copy back to the proper
46 * To make this work if resume is triggered from initramfs, the
47 * pagetables need to be switched to allow writes to kernel mem.
49 static void notrace
__swsusp_arch_restore_image(void *unused
)
51 extern struct pbe
*restore_pblist
;
52 phys_reset_t phys_reset
;
55 for (pbe
= restore_pblist
; pbe
; pbe
= pbe
->next
)
56 copy_page(pbe
->orig_address
, pbe
->address
);
58 /* Clean and invalidate caches */
61 /* Turn off caching */
64 /* Push out any further dirty data, and ensure cache is empty */
67 /* Take out a flat memory mapping. */
68 setup_mm_for_reboot();
70 phys_reset
= (phys_reset_t
)(unsigned long)virt_to_phys(cpu_reset
);
72 /* Return from cpu_suspend/swsusp_arch_suspend */
73 phys_reset((unsigned long)virt_to_phys(cpu_resume
));
75 /* Should never get here. */
79 static u8 __swsusp_resume_stk
[PAGE_SIZE
/2] __nosavedata
;
82 * Resume from the hibernation image.
83 * Due to the kernel heap / data restore, stack contents change underneath
84 * and that would make function calls impossible; switch to a temporary
85 * stack within the nosave region to avoid that problem.
87 int __naked
swsusp_arch_resume(void)
89 extern void call_with_stack(void (*fn
)(void *), void *arg
, void *sp
);
90 cpu_init(); /* get a clean PSR */
91 call_with_stack(__swsusp_arch_restore_image
, 0,
92 __swsusp_resume_stk
+ ARRAY_SIZE(__swsusp_resume_stk
));