2011-08-26 20:28:52 +01:00
# include <linux/init.h>
2011-11-15 11:11:19 +00:00
# include <asm/idmap.h>
2011-08-26 20:28:52 +01:00
# include <asm/pgalloc.h>
# include <asm/pgtable.h>
# include <asm/memory.h>
# include <asm/suspend.h>
# include <asm/tlbflush.h>
2011-09-01 11:52:33 +01:00
extern int __cpu_suspend ( unsigned long , int ( * ) ( unsigned long ) ) ;
2011-08-31 23:26:18 +01:00
extern void cpu_resume_mmu ( void ) ;
2011-08-26 20:28:52 +01:00
2011-09-01 11:52:33 +01:00
/*
* This is called by __cpu_suspend ( ) to save the state , and do whatever
* flushing is required to ensure that when the CPU goes to sleep we have
* the necessary data available when the caches are not searched .
*/
void __cpu_suspend_save ( u32 * ptr , u32 ptrsz , u32 sp , u32 * save_ptr )
{
* save_ptr = virt_to_phys ( ptr ) ;
/* This must correspond to the LDM in cpu_resume() assembly */
2011-11-15 11:11:19 +00:00
* ptr + + = virt_to_phys ( idmap_pgd ) ;
2011-09-01 11:52:33 +01:00
* ptr + + = sp ;
* ptr + + = virt_to_phys ( cpu_do_resume ) ;
cpu_do_suspend ( ptr ) ;
flush_cache_all ( ) ;
2011-09-01 11:57:59 +01:00
outer_clean_range ( * save_ptr , * save_ptr + ptrsz ) ;
outer_clean_range ( virt_to_phys ( save_ptr ) ,
virt_to_phys ( save_ptr ) + sizeof ( * save_ptr ) ) ;
2011-09-01 11:52:33 +01:00
}
2011-08-26 20:28:52 +01:00
/*
* Hide the first two arguments to __cpu_suspend - these are an implementation
* detail which platform code shouldn ' t have to know about .
*/
int cpu_suspend ( unsigned long arg , int ( * fn ) ( unsigned long ) )
{
struct mm_struct * mm = current - > active_mm ;
int ret ;
2011-11-15 11:11:19 +00:00
if ( ! idmap_pgd )
2011-08-26 20:28:52 +01:00
return - EINVAL ;
/*
2011-08-27 22:39:09 +01:00
* Provide a temporary page table with an identity mapping for
* the MMU - enable code , required for resuming . On successful
* resume ( indicated by a zero return code ) , we need to switch
* back to the correct page tables .
2011-08-26 20:28:52 +01:00
*/
2011-09-01 11:52:33 +01:00
ret = __cpu_suspend ( arg , fn ) ;
2011-08-27 22:39:09 +01:00
if ( ret = = 0 ) {
cpu_switch_mm ( mm - > pgd , mm ) ;
local_flush_tlb_all ( ) ;
}
2011-08-26 20:28:52 +01:00
return ret ;
}