2005-04-25 20:36:23 +04:00
/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 2005 Thiemo Seufer
* Copyright ( C ) 2005 MIPS Technologies , Inc . All rights reserved .
* Author : Maciej W . Rozycki < macro @ mips . com >
*/
# include <linux/init.h>
# include <asm/addrspace.h>
# include <asm/bug.h>
2007-07-11 19:55:40 +04:00
# include <asm/cacheflush.h>
2005-04-25 20:36:23 +04:00
# ifndef CKSEG2
# define CKSEG2 CKSSEG
# endif
# ifndef TO_PHYS_MASK
# define TO_PHYS_MASK -1
# endif
/*
* FUNC is executed in one of the uncached segments , depending on its
* original address as follows :
*
* 1. If the original address is in CKSEG0 or CKSEG1 , then the uncached
* segment used is CKSEG1 .
* 2. If the original address is in XKPHYS , then the uncached segment
* used is XKPHYS ( 2 ) .
* 3. Otherwise it ' s a bug .
*
* The same remapping is done with the stack pointer . Stack handling
* works because we don ' t handle stack arguments or more complex return
* values , so we can avoid sharing the same stack area between a cached
* and the uncached mode .
*/
unsigned long __init run_uncached ( void * func )
{
register long sp __asm__ ( " $sp " ) ;
register long ret __asm__ ( " $2 " ) ;
long lfunc = ( long ) func , ufunc ;
long usp ;
if ( sp > = ( long ) CKSEG0 & & sp < ( long ) CKSEG2 )
usp = CKSEG1ADDR ( sp ) ;
2007-02-06 04:59:22 +03:00
# ifdef CONFIG_64BIT
2007-11-01 00:11:24 +03:00
else if ( ( long long ) sp > = ( long long ) PHYS_TO_XKPHYS ( 0 , 0 ) & &
( long long ) sp < ( long long ) PHYS_TO_XKPHYS ( 8 , 0 ) )
usp = PHYS_TO_XKPHYS ( K_CALG_UNCACHED ,
2005-04-25 20:36:23 +04:00
XKPHYS_TO_PHYS ( ( long long ) sp ) ) ;
2007-02-06 04:59:22 +03:00
# endif
2005-04-25 20:36:23 +04:00
else {
BUG ( ) ;
usp = sp ;
}
if ( lfunc > = ( long ) CKSEG0 & & lfunc < ( long ) CKSEG2 )
ufunc = CKSEG1ADDR ( lfunc ) ;
2007-02-06 04:59:22 +03:00
# ifdef CONFIG_64BIT
2007-11-01 00:11:24 +03:00
else if ( ( long long ) lfunc > = ( long long ) PHYS_TO_XKPHYS ( 0 , 0 ) & &
( long long ) lfunc < ( long long ) PHYS_TO_XKPHYS ( 8 , 0 ) )
ufunc = PHYS_TO_XKPHYS ( K_CALG_UNCACHED ,
2005-04-25 20:36:23 +04:00
XKPHYS_TO_PHYS ( ( long long ) lfunc ) ) ;
2007-02-06 04:59:22 +03:00
# endif
2005-04-25 20:36:23 +04:00
else {
BUG ( ) ;
ufunc = lfunc ;
}
__asm__ __volatile__ (
" move $16, $sp \n "
" move $sp, %1 \n "
" jalr %2 \n "
" move $sp, $16 "
: " =r " ( ret )
: " r " ( usp ) , " r " ( ufunc )
: " $16 " , " $31 " ) ;
return ret ;
}