2008-07-29 22:34:04 -07: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 ) 2008 Silicon Graphics , Inc . All Rights Reserved .
*/
/*
* Cross Partition ( XP ) sn2 - based functions .
*
* Architecture specific implementation of common functions .
*/
# include <linux/device.h>
2008-07-29 22:34:05 -07:00
# include <asm/sn/bte.h>
2008-07-29 22:34:04 -07:00
# include <asm/sn/sn_sal.h>
# include "xp.h"
/*
* The export of xp_nofault_PIOR needs to happen here since it is defined
* in drivers / misc / sgi - xp / xp_nofault . S . The target of the nofault read is
* defined here .
*/
EXPORT_SYMBOL_GPL ( xp_nofault_PIOR ) ;
u64 xp_nofault_PIOR_target ;
EXPORT_SYMBOL_GPL ( xp_nofault_PIOR_target ) ;
/*
* Register a nofault code region which performs a cross - partition PIO read .
* If the PIO read times out , the MCA handler will consume the error and
* return to a kernel - provided instruction to indicate an error . This PIO read
* exists because it is guaranteed to timeout if the destination is down
2008-07-29 22:34:11 -07:00
* ( amo operations do not timeout on at least some CPUs on Shubs < = v1 .2 ,
2008-07-29 22:34:04 -07:00
* which unfortunately we have to work around ) .
*/
static enum xp_retval
xp_register_nofault_code_sn2 ( void )
{
int ret ;
u64 func_addr ;
u64 err_func_addr ;
func_addr = * ( u64 * ) xp_nofault_PIOR ;
err_func_addr = * ( u64 * ) xp_error_PIOR ;
ret = sn_register_nofault_code ( func_addr , err_func_addr , err_func_addr ,
1 , 1 ) ;
if ( ret ! = 0 ) {
dev_err ( xp , " can't register nofault code, error=%d \n " , ret ) ;
return xpSalError ;
}
/*
* Setup the nofault PIO read target . ( There is no special reason why
* SH_IPI_ACCESS was selected . )
*/
if ( is_shub1 ( ) )
xp_nofault_PIOR_target = SH1_IPI_ACCESS ;
else if ( is_shub2 ( ) )
xp_nofault_PIOR_target = SH2_IPI_ACCESS0 ;
return xpSuccess ;
}
void
xp_unregister_nofault_code_sn2 ( void )
{
u64 func_addr = * ( u64 * ) xp_nofault_PIOR ;
u64 err_func_addr = * ( u64 * ) xp_error_PIOR ;
/* unregister the PIO read nofault code region */
( void ) sn_register_nofault_code ( func_addr , err_func_addr ,
err_func_addr , 1 , 0 ) ;
}
2008-07-29 22:34:05 -07:00
/*
* Wrapper for bte_copy ( ) .
*
* vdst - virtual address of the destination of the transfer .
* psrc - physical address of the source of the transfer .
* len - number of bytes to transfer from source to destination .
*
* Note : xp_remote_memcpy_sn2 ( ) should never be called while holding a spinlock .
*/
static enum xp_retval
xp_remote_memcpy_sn2 ( void * vdst , const void * psrc , size_t len )
{
bte_result_t ret ;
u64 pdst = ia64_tpa ( vdst ) ;
/* >>> What are the rules governing the src and dst addresses passed in?
* > > > Currently we ' re assuming that dst is a virtual address and src
* > > > is a physical address , is this appropriate ? Can we allow them to
* > > > be whatever and we make the change here without damaging the
* > > > addresses ?
*/
/*
* Ensure that the physically mapped memory is contiguous .
*
* We do this by ensuring that the memory is from region 7 only .
* If the need should arise to use memory from one of the other
* regions , then modify the BUG_ON ( ) statement to ensure that the
* memory from that region is always physically contiguous .
*/
BUG_ON ( REGION_NUMBER ( vdst ) ! = RGN_KERNEL ) ;
ret = bte_copy ( ( u64 ) psrc , pdst , len , ( BTE_NOTIFY | BTE_WACQUIRE ) , NULL ) ;
if ( ret = = BTE_SUCCESS )
return xpSuccess ;
if ( is_shub2 ( ) )
dev_err ( xp , " bte_copy() on shub2 failed, error=0x%x \n " , ret ) ;
else
dev_err ( xp , " bte_copy() failed, error=%d \n " , ret ) ;
return xpBteCopyError ;
}
2008-07-29 22:34:04 -07:00
enum xp_retval
xp_init_sn2 ( void )
{
BUG_ON ( ! is_shub ( ) ) ;
xp_max_npartitions = XP_MAX_NPARTITIONS_SN2 ;
2008-07-29 22:34:05 -07:00
xp_remote_memcpy = xp_remote_memcpy_sn2 ;
2008-07-29 22:34:04 -07:00
return xp_register_nofault_code_sn2 ( ) ;
}
void
xp_exit_sn2 ( void )
{
BUG_ON ( ! is_shub ( ) ) ;
xp_unregister_nofault_code_sn2 ( ) ;
}