2005-03-24 05:50:00 +03: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 .
*
2008-04-22 23:46:56 +04:00
* Copyright ( c ) 2004 - 2008 Silicon Graphics , Inc . All Rights Reserved .
2005-03-24 05:50:00 +03:00
*/
/*
* Cross Partition Communication ( XPC ) partition support .
*
* This is the part of XPC that detects the presence / absence of
* other partitions . It provides a heartbeat and monitors the
* heartbeats of other partitions .
*
*/
2008-07-30 09:34:16 +04:00
# include <linux/device.h>
# include <linux/hardirq.h>
2008-04-22 23:46:56 +04:00
# include "xpc.h"
2009-12-16 03:47:56 +03:00
# include <asm/uv/uv_hub.h>
2005-03-24 05:50:00 +03:00
/* XPC is exiting flag */
int xpc_exiting ;
2005-10-25 23:09:51 +04:00
/* this partition's reserved page pointers */
2005-03-24 05:50:00 +03:00
struct xpc_rsvd_page * xpc_rsvd_page ;
2008-07-30 09:34:14 +04:00
static unsigned long * xpc_part_nasids ;
unsigned long * xpc_mach_nasids ;
2005-03-24 05:50:00 +03:00
2008-07-30 09:34:14 +04:00
static int xpc_nasid_mask_nbytes ; /* #of bytes in nasid mask */
int xpc_nasid_mask_nlongs ; /* #of longs in nasid mask */
2005-10-25 23:09:51 +04:00
2008-07-30 09:34:04 +04:00
struct xpc_partition * xpc_partitions ;
2005-03-24 05:50:00 +03:00
2006-02-17 13:18:43 +03:00
/*
* Guarantee that the kmalloc ' d memory is cacheline aligned .
*/
2006-08-09 00:03:29 +04:00
void *
2006-02-17 13:18:43 +03:00
xpc_kmalloc_cacheline_aligned ( size_t size , gfp_t flags , void * * base )
{
/* see if kmalloc will give us cachline aligned memory by default */
* base = kmalloc ( size , flags ) ;
2008-04-22 23:50:17 +04:00
if ( * base = = NULL )
2006-02-17 13:18:43 +03:00
return NULL ;
2008-04-22 23:50:17 +04:00
if ( ( u64 ) * base = = L1_CACHE_ALIGN ( ( u64 ) * base ) )
2006-02-17 13:18:43 +03:00
return * base ;
2008-04-22 23:50:17 +04:00
2006-02-17 13:18:43 +03:00
kfree ( * base ) ;
/* nope, we'll have to do it ourselves */
* base = kmalloc ( size + L1_CACHE_BYTES , flags ) ;
2008-04-22 23:50:17 +04:00
if ( * base = = NULL )
2006-02-17 13:18:43 +03:00
return NULL ;
2008-04-22 23:50:17 +04:00
2008-04-22 23:48:01 +04:00
return ( void * ) L1_CACHE_ALIGN ( ( u64 ) * base ) ;
2006-02-17 13:18:43 +03:00
}
2005-03-24 05:50:00 +03:00
/*
* Given a nasid , get the physical address of the partition ' s reserved page
* for that nasid . This function returns 0 on any error .
*/
2008-07-30 09:34:16 +04:00
static unsigned long
2005-10-25 23:11:53 +04:00
xpc_get_rsvd_page_pa ( int nasid )
2005-03-24 05:50:00 +03:00
{
2008-07-30 09:34:05 +04:00
enum xp_retval ret ;
2005-03-24 05:50:00 +03:00
u64 cookie = 0 ;
2008-07-30 09:34:16 +04:00
unsigned long rp_pa = nasid ; /* seed with nasid */
2008-07-30 09:34:16 +04:00
size_t len = 0 ;
2008-07-30 09:34:16 +04:00
size_t buf_len = 0 ;
void * buf = buf ;
2005-10-25 23:11:53 +04:00
void * buf_base = NULL ;
2009-04-14 01:40:19 +04:00
enum xp_retval ( * get_partition_rsvd_page_pa )
( void * , u64 * , unsigned long * , size_t * ) =
xpc_arch_ops . get_partition_rsvd_page_pa ;
2005-03-24 05:50:00 +03:00
while ( 1 ) {
2008-07-30 09:34:18 +04:00
/* !!! rp_pa will need to be _gpa on UV.
* ? ? ? So do we save it into the architecture specific parts
* ? ? ? of the xpc_partition structure ? Do we rename this
* ? ? ? function or have two versions ? Rename rp_pa for UV to
* ? ? ? rp_gpa ?
*/
2009-04-14 01:40:19 +04:00
ret = get_partition_rsvd_page_pa ( buf , & cookie , & rp_pa , & len ) ;
2005-03-24 05:50:00 +03:00
2008-07-30 09:34:16 +04:00
dev_dbg ( xpc_part , " SAL returned with ret=%d, cookie=0x%016lx, "
" address=0x%016lx, len=0x%016lx \n " , ret ,
2008-07-30 09:34:16 +04:00
( unsigned long ) cookie , rp_pa , len ) ;
2005-03-24 05:50:00 +03:00
2008-07-30 09:34:16 +04:00
if ( ret ! = xpNeedMoreInfo )
2005-03-24 05:50:00 +03:00
break ;
2008-07-30 09:34:14 +04:00
/* !!! L1_CACHE_ALIGN() is only a sn2-bte_copy requirement */
2009-12-16 03:47:56 +03:00
if ( is_shub ( ) )
len = L1_CACHE_ALIGN ( len ) ;
if ( len > buf_len ) {
if ( buf_base ! = NULL )
kfree ( buf_base ) ;
2005-10-25 23:11:53 +04:00
buf_len = L1_CACHE_ALIGN ( len ) ;
2008-07-30 09:34:16 +04:00
buf = xpc_kmalloc_cacheline_aligned ( buf_len , GFP_KERNEL ,
& buf_base ) ;
2005-10-25 23:11:53 +04:00
if ( buf_base = = NULL ) {
dev_err ( xpc_part , " unable to kmalloc "
2008-07-30 09:34:16 +04:00
" len=0x%016lx \n " , buf_len ) ;
2008-07-30 09:34:16 +04:00
ret = xpNoMemory ;
2005-10-25 23:11:53 +04:00
break ;
}
2005-03-24 05:50:00 +03:00
}
2009-12-16 03:47:56 +03:00
ret = xp_remote_memcpy ( xp_pa ( buf ) , rp_pa , len ) ;
2008-07-30 09:34:05 +04:00
if ( ret ! = xpSuccess ) {
dev_dbg ( xpc_part , " xp_remote_memcpy failed %d \n " , ret ) ;
2005-03-24 05:50:00 +03:00
break ;
}
}
2006-04-20 21:11:09 +04:00
kfree ( buf_base ) ;
2005-10-25 23:11:53 +04:00
2008-07-30 09:34:16 +04:00
if ( ret ! = xpSuccess )
2005-03-24 05:50:00 +03:00
rp_pa = 0 ;
2008-04-22 23:50:17 +04:00
2008-07-30 09:34:16 +04:00
dev_dbg ( xpc_part , " reserved page at phys address 0x%016lx \n " , rp_pa ) ;
2005-03-24 05:50:00 +03:00
return rp_pa ;
}
/*
* Fill the partition reserved page with the information needed by
* other partitions to discover we are alive and establish initial
* communications .
*/
2008-07-30 09:34:18 +04:00
int
2008-07-30 09:34:05 +04:00
xpc_setup_rsvd_page ( void )
2005-03-24 05:50:00 +03:00
{
2008-07-30 09:34:18 +04:00
int ret ;
2005-03-24 05:50:00 +03:00
struct xpc_rsvd_page * rp ;
2008-07-30 09:34:16 +04:00
unsigned long rp_pa ;
2008-07-30 09:34:15 +04:00
unsigned long new_ts_jiffies ;
2005-03-24 05:50:00 +03:00
/* get the local reserved page's address */
2005-10-25 23:11:53 +04:00
preempt_disable ( ) ;
2008-07-30 09:34:16 +04:00
rp_pa = xpc_get_rsvd_page_pa ( xp_cpu_to_nasid ( smp_processor_id ( ) ) ) ;
2005-10-25 23:11:53 +04:00
preempt_enable ( ) ;
2005-03-24 05:50:00 +03:00
if ( rp_pa = = 0 ) {
dev_err ( xpc_part , " SAL failed to locate the reserved page \n " ) ;
2008-07-30 09:34:18 +04:00
return - ESRCH ;
2005-03-24 05:50:00 +03:00
}
2009-12-16 03:47:56 +03:00
rp = ( struct xpc_rsvd_page * ) __va ( xp_socket_pa ( rp_pa ) ) ;
2005-03-24 05:50:00 +03:00
2008-07-30 09:34:05 +04:00
if ( rp - > SAL_version < 3 ) {
/* SAL_versions < 3 had a SAL_partid defined as a u8 */
rp - > SAL_partid & = 0xff ;
}
2008-07-30 09:34:16 +04:00
BUG_ON ( rp - > SAL_partid ! = xp_partition_id ) ;
2008-07-30 09:34:05 +04:00
if ( rp - > SAL_partid < 0 | | rp - > SAL_partid > = xp_max_npartitions ) {
dev_err ( xpc_part , " the reserved page's partid of %d is outside "
" supported range (< 0 || >= %d) \n " , rp - > SAL_partid ,
xp_max_npartitions ) ;
2008-07-30 09:34:18 +04:00
return - EINVAL ;
2005-03-24 05:50:00 +03:00
}
rp - > version = XPC_RP_VERSION ;
2008-07-30 09:34:05 +04:00
rp - > max_npartitions = xp_max_npartitions ;
2005-03-24 05:50:00 +03:00
2005-10-25 23:09:51 +04:00
/* establish the actual sizes of the nasid masks */
if ( rp - > SAL_version = = 1 ) {
/* SAL_version 1 didn't set the nasids_size field */
2008-07-30 09:34:05 +04:00
rp - > SAL_nasids_size = 128 ;
2005-10-25 23:09:51 +04:00
}
2008-07-30 09:34:14 +04:00
xpc_nasid_mask_nbytes = rp - > SAL_nasids_size ;
xpc_nasid_mask_nlongs = BITS_TO_LONGS ( rp - > SAL_nasids_size *
BITS_PER_BYTE ) ;
2005-10-25 23:09:51 +04:00
/* setup the pointers to the various items in the reserved page */
xpc_part_nasids = XPC_RP_PART_NASIDS ( rp ) ;
xpc_mach_nasids = XPC_RP_MACH_NASIDS ( rp ) ;
2005-03-24 05:50:00 +03:00
2009-04-14 01:40:19 +04:00
ret = xpc_arch_ops . setup_rsvd_page ( rp ) ;
2008-07-30 09:34:18 +04:00
if ( ret ! = 0 )
return ret ;
2005-03-24 05:50:00 +03:00
/*
2008-07-30 09:34:05 +04:00
* Set timestamp of when reserved page was setup by XPC .
2005-03-24 05:50:00 +03:00
* This signifies to the remote partition that our reserved
* page is initialized .
*/
2008-07-30 09:34:15 +04:00
new_ts_jiffies = jiffies ;
if ( new_ts_jiffies = = 0 | | new_ts_jiffies = = rp - > ts_jiffies )
new_ts_jiffies + + ;
rp - > ts_jiffies = new_ts_jiffies ;
2005-03-24 05:50:00 +03:00
2008-07-30 09:34:18 +04:00
xpc_rsvd_page = rp ;
return 0 ;
}
void
xpc_teardown_rsvd_page ( void )
{
/* a zero timestamp indicates our rsvd page is not initialized */
xpc_rsvd_page - > ts_jiffies = 0 ;
2005-03-24 05:50:00 +03:00
}
/*
2005-10-25 23:09:51 +04:00
* Get a copy of a portion of the remote partition ' s rsvd page .
2005-03-24 05:50:00 +03:00
*
* remote_rp points to a buffer that is cacheline aligned for BTE copies and
2005-10-25 23:09:51 +04:00
* is large enough to contain a copy of their reserved page header and
* part_nasids mask .
2005-03-24 05:50:00 +03:00
*/
2008-07-30 09:34:07 +04:00
enum xp_retval
2008-07-30 09:34:14 +04:00
xpc_get_remote_rp ( int nasid , unsigned long * discovered_nasids ,
2008-07-30 09:34:16 +04:00
struct xpc_rsvd_page * remote_rp , unsigned long * remote_rp_pa )
2005-03-24 05:50:00 +03:00
{
2008-07-30 09:34:14 +04:00
int l ;
2008-07-30 09:34:05 +04:00
enum xp_retval ret ;
2005-03-24 05:50:00 +03:00
/* get the reserved page's physical address */
2005-10-25 23:11:53 +04:00
* remote_rp_pa = xpc_get_rsvd_page_pa ( nasid ) ;
2008-04-22 23:50:17 +04:00
if ( * remote_rp_pa = = 0 )
2008-05-13 01:02:02 +04:00
return xpNoRsvdPageAddr ;
2005-03-24 05:50:00 +03:00
2005-10-25 23:09:51 +04:00
/* pull over the reserved page header and part_nasids mask */
2008-07-30 09:34:16 +04:00
ret = xp_remote_memcpy ( xp_pa ( remote_rp ) , * remote_rp_pa ,
2008-07-30 09:34:14 +04:00
XPC_RP_HEADER_SIZE + xpc_nasid_mask_nbytes ) ;
2008-07-30 09:34:05 +04:00
if ( ret ! = xpSuccess )
return ret ;
2005-03-24 05:50:00 +03:00
if ( discovered_nasids ! = NULL ) {
2008-07-30 09:34:14 +04:00
unsigned long * remote_part_nasids =
XPC_RP_PART_NASIDS ( remote_rp ) ;
2005-10-25 23:09:51 +04:00
2008-07-30 09:34:14 +04:00
for ( l = 0 ; l < xpc_nasid_mask_nlongs ; l + + )
discovered_nasids [ l ] | = remote_part_nasids [ l ] ;
2005-03-24 05:50:00 +03:00
}
2008-07-30 09:34:15 +04:00
/* zero timestamp indicates the reserved page has not been setup */
if ( remote_rp - > ts_jiffies = = 0 )
2008-07-30 09:34:05 +04:00
return xpRsvdPageNotSet ;
2005-03-24 05:50:00 +03:00
if ( XPC_VERSION_MAJOR ( remote_rp - > version ) ! =
2008-04-22 23:48:01 +04:00
XPC_VERSION_MAJOR ( XPC_RP_VERSION ) ) {
2008-05-13 01:02:02 +04:00
return xpBadVersion ;
2005-03-24 05:50:00 +03:00
}
2008-07-30 09:34:09 +04:00
/* check that both remote and local partids are valid for each side */
2008-07-30 09:34:07 +04:00
if ( remote_rp - > SAL_partid < 0 | |
remote_rp - > SAL_partid > = xp_max_npartitions | |
2008-07-30 09:34:16 +04:00
remote_rp - > max_npartitions < = xp_partition_id ) {
2008-07-30 09:34:05 +04:00
return xpInvalidPartid ;
2008-07-30 09:34:07 +04:00
}
2008-07-30 09:34:16 +04:00
if ( remote_rp - > SAL_partid = = xp_partition_id )
2008-07-30 09:34:07 +04:00
return xpLocalPartid ;
2008-07-30 09:34:05 +04:00
2008-05-13 01:02:02 +04:00
return xpSuccess ;
2005-03-24 05:50:00 +03:00
}
2005-09-01 23:01:37 +04:00
/*
2008-07-30 09:34:09 +04:00
* See if the other side has responded to a partition deactivate request
* from us . Though we requested the remote partition to deactivate with regard
* to us , we really only need to wait for the other side to disengage from us .
2005-09-01 23:01:37 +04:00
*/
int
xpc_partition_disengaged ( struct xpc_partition * part )
{
2008-05-13 01:02:03 +04:00
short partid = XPC_PARTID ( part ) ;
2005-09-01 23:01:37 +04:00
int disengaged ;
2009-04-14 01:40:19 +04:00
disengaged = ! xpc_arch_ops . partition_engaged ( partid ) ;
2008-07-30 09:34:09 +04:00
if ( part - > disengage_timeout ) {
2005-09-01 23:01:37 +04:00
if ( ! disengaged ) {
2008-07-30 09:34:09 +04:00
if ( time_is_after_jiffies ( part - > disengage_timeout ) ) {
2005-09-01 23:01:37 +04:00
/* timelimit hasn't been reached yet */
return 0 ;
}
/*
2008-07-30 09:34:09 +04:00
* Other side hasn ' t responded to our deactivate
2005-09-01 23:01:37 +04:00
* request in a timely fashion , so assume it ' s dead .
*/
2008-07-30 09:34:09 +04:00
dev_info ( xpc_part , " deactivate request to remote "
" partition %d timed out \n " , partid ) ;
xpc_disengage_timedout = 1 ;
2009-04-14 01:40:19 +04:00
xpc_arch_ops . assume_partition_disengaged ( partid ) ;
2005-09-01 23:01:37 +04:00
disengaged = 1 ;
}
2008-07-30 09:34:09 +04:00
part - > disengage_timeout = 0 ;
2005-09-01 23:01:37 +04:00
/* cancel the timer function, provided it's not us */
2008-07-30 09:34:09 +04:00
if ( ! in_interrupt ( ) )
del_singleshot_timer_sync ( & part - > disengage_timer ) ;
2005-09-01 23:01:37 +04:00
2008-07-30 09:34:18 +04:00
DBUG_ON ( part - > act_state ! = XPC_P_AS_DEACTIVATING & &
part - > act_state ! = XPC_P_AS_INACTIVE ) ;
if ( part - > act_state ! = XPC_P_AS_INACTIVE )
2005-09-01 23:01:37 +04:00
xpc_wakeup_channel_mgr ( part ) ;
2009-04-14 01:40:19 +04:00
xpc_arch_ops . cancel_partition_deactivation_request ( part ) ;
2005-09-01 23:01:37 +04:00
}
return disengaged ;
}
2005-03-24 05:50:00 +03:00
/*
* Mark specified partition as active .
*/
2008-05-13 01:02:02 +04:00
enum xp_retval
2005-03-24 05:50:00 +03:00
xpc_mark_partition_active ( struct xpc_partition * part )
{
unsigned long irq_flags ;
2008-05-13 01:02:02 +04:00
enum xp_retval ret ;
2005-03-24 05:50:00 +03:00
dev_dbg ( xpc_part , " setting partition %d to ACTIVE \n " , XPC_PARTID ( part ) ) ;
spin_lock_irqsave ( & part - > act_lock , irq_flags ) ;
2008-07-30 09:34:18 +04:00
if ( part - > act_state = = XPC_P_AS_ACTIVATING ) {
part - > act_state = XPC_P_AS_ACTIVE ;
2008-05-13 01:02:02 +04:00
ret = xpSuccess ;
2005-03-24 05:50:00 +03:00
} else {
2008-05-13 01:02:02 +04:00
DBUG_ON ( part - > reason = = xpSuccess ) ;
2005-03-24 05:50:00 +03:00
ret = part - > reason ;
}
spin_unlock_irqrestore ( & part - > act_lock , irq_flags ) ;
return ret ;
}
/*
2008-07-30 09:34:09 +04:00
* Start the process of deactivating the specified partition .
2005-03-24 05:50:00 +03:00
*/
void
xpc_deactivate_partition ( const int line , struct xpc_partition * part ,
2008-05-13 01:02:02 +04:00
enum xp_retval reason )
2005-03-24 05:50:00 +03:00
{
unsigned long irq_flags ;
spin_lock_irqsave ( & part - > act_lock , irq_flags ) ;
2008-07-30 09:34:18 +04:00
if ( part - > act_state = = XPC_P_AS_INACTIVE ) {
2005-03-24 05:50:00 +03:00
XPC_SET_REASON ( part , reason , line ) ;
spin_unlock_irqrestore ( & part - > act_lock , irq_flags ) ;
2008-05-13 01:02:02 +04:00
if ( reason = = xpReactivating ) {
2005-03-24 05:50:00 +03:00
/* we interrupt ourselves to reactivate partition */
2009-04-14 01:40:19 +04:00
xpc_arch_ops . request_partition_reactivation ( part ) ;
2005-03-24 05:50:00 +03:00
}
return ;
}
2008-07-30 09:34:18 +04:00
if ( part - > act_state = = XPC_P_AS_DEACTIVATING ) {
2008-05-13 01:02:02 +04:00
if ( ( part - > reason = = xpUnloading & & reason ! = xpUnloading ) | |
reason = = xpReactivating ) {
2005-03-24 05:50:00 +03:00
XPC_SET_REASON ( part , reason , line ) ;
}
spin_unlock_irqrestore ( & part - > act_lock , irq_flags ) ;
return ;
}
2008-07-30 09:34:18 +04:00
part - > act_state = XPC_P_AS_DEACTIVATING ;
2005-03-24 05:50:00 +03:00
XPC_SET_REASON ( part , reason , line ) ;
spin_unlock_irqrestore ( & part - > act_lock , irq_flags ) ;
2008-07-30 09:34:09 +04:00
/* ask remote partition to deactivate with regard to us */
2009-04-14 01:40:19 +04:00
xpc_arch_ops . request_partition_deactivation ( part ) ;
2005-03-24 05:50:00 +03:00
2008-07-30 09:34:09 +04:00
/* set a timelimit on the disengage phase of the deactivation request */
part - > disengage_timeout = jiffies + ( xpc_disengage_timelimit * HZ ) ;
part - > disengage_timer . expires = part - > disengage_timeout ;
add_timer ( & part - > disengage_timer ) ;
2005-03-24 05:50:00 +03:00
2005-10-25 23:07:43 +04:00
dev_dbg ( xpc_part , " bringing partition %d down, reason = %d \n " ,
XPC_PARTID ( part ) , reason ) ;
2005-03-24 05:50:00 +03:00
2005-09-01 23:01:37 +04:00
xpc_partition_going_down ( part , reason ) ;
2005-03-24 05:50:00 +03:00
}
/*
2005-09-01 23:01:37 +04:00
* Mark specified partition as inactive .
2005-03-24 05:50:00 +03:00
*/
void
xpc_mark_partition_inactive ( struct xpc_partition * part )
{
unsigned long irq_flags ;
dev_dbg ( xpc_part , " setting partition %d to INACTIVE \n " ,
XPC_PARTID ( part ) ) ;
spin_lock_irqsave ( & part - > act_lock , irq_flags ) ;
2008-07-30 09:34:18 +04:00
part - > act_state = XPC_P_AS_INACTIVE ;
2005-03-24 05:50:00 +03:00
spin_unlock_irqrestore ( & part - > act_lock , irq_flags ) ;
part - > remote_rp_pa = 0 ;
}
/*
* SAL has provided a partition and machine mask . The partition mask
* contains a bit for each even nasid in our partition . The machine
* mask contains a bit for each even nasid in the entire machine .
*
* Using those two bit arrays , we can determine which nasids are
* known in the machine . Each should also have a reserved page
* initialized if they are available for partitioning .
*/
void
xpc_discovery ( void )
{
void * remote_rp_base ;
struct xpc_rsvd_page * remote_rp ;
2008-07-30 09:34:16 +04:00
unsigned long remote_rp_pa ;
2005-03-24 05:50:00 +03:00
int region ;
2005-10-25 23:09:51 +04:00
int region_size ;
2005-03-24 05:50:00 +03:00
int max_regions ;
int nasid ;
struct xpc_rsvd_page * rp ;
2008-07-30 09:34:14 +04:00
unsigned long * discovered_nasids ;
2008-05-13 01:02:02 +04:00
enum xp_retval ret ;
2005-03-24 05:50:00 +03:00
2005-10-25 23:09:51 +04:00
remote_rp = xpc_kmalloc_cacheline_aligned ( XPC_RP_HEADER_SIZE +
2008-07-30 09:34:14 +04:00
xpc_nasid_mask_nbytes ,
2008-04-22 23:48:01 +04:00
GFP_KERNEL , & remote_rp_base ) ;
2008-04-22 23:50:17 +04:00
if ( remote_rp = = NULL )
2005-03-24 05:50:00 +03:00
return ;
2008-04-22 23:50:17 +04:00
2008-07-30 09:34:14 +04:00
discovered_nasids = kzalloc ( sizeof ( long ) * xpc_nasid_mask_nlongs ,
2008-04-22 23:48:01 +04:00
GFP_KERNEL ) ;
2005-03-24 05:50:00 +03:00
if ( discovered_nasids = = NULL ) {
kfree ( remote_rp_base ) ;
return ;
}
2008-04-22 23:48:01 +04:00
rp = ( struct xpc_rsvd_page * ) xpc_rsvd_page ;
2005-03-24 05:50:00 +03:00
/*
* The term ' region ' in this context refers to the minimum number of
* nodes that can comprise an access protection grouping . The access
* protection is in regards to memory , IOI and IPI .
*/
2005-10-25 23:09:51 +04:00
max_regions = 64 ;
2008-07-30 09:34:16 +04:00
region_size = xp_region_size ;
2005-10-25 23:09:51 +04:00
switch ( region_size ) {
case 128 :
max_regions * = 2 ;
case 64 :
max_regions * = 2 ;
case 32 :
max_regions * = 2 ;
region_size = 16 ;
DBUG_ON ( ! is_shub2 ( ) ) ;
}
2005-03-24 05:50:00 +03:00
for ( region = 0 ; region < max_regions ; region + + ) {
2008-04-22 23:50:17 +04:00
if ( xpc_exiting )
2005-03-24 05:50:00 +03:00
break ;
dev_dbg ( xpc_part , " searching region %d \n " , region ) ;
2005-10-25 23:09:51 +04:00
for ( nasid = ( region * region_size * 2 ) ;
2008-04-22 23:48:01 +04:00
nasid < ( ( region + 1 ) * region_size * 2 ) ; nasid + = 2 ) {
2005-03-24 05:50:00 +03:00
2008-04-22 23:50:17 +04:00
if ( xpc_exiting )
2005-03-24 05:50:00 +03:00
break ;
dev_dbg ( xpc_part , " checking nasid %d \n " , nasid ) ;
2008-07-30 09:34:14 +04:00
if ( test_bit ( nasid / 2 , xpc_part_nasids ) ) {
2005-03-24 05:50:00 +03:00
dev_dbg ( xpc_part , " PROM indicates Nasid %d is "
" part of the local partition; skipping "
" region \n " , nasid ) ;
break ;
}
2008-07-30 09:34:14 +04:00
if ( ! ( test_bit ( nasid / 2 , xpc_mach_nasids ) ) ) {
2005-03-24 05:50:00 +03:00
dev_dbg ( xpc_part , " PROM indicates Nasid %d was "
" not on Numa-Link network at reset \n " ,
nasid ) ;
continue ;
}
2008-07-30 09:34:14 +04:00
if ( test_bit ( nasid / 2 , discovered_nasids ) ) {
2005-03-24 05:50:00 +03:00
dev_dbg ( xpc_part , " Nasid %d is part of a "
" partition which was previously "
" discovered \n " , nasid ) ;
continue ;
}
2008-07-30 09:34:07 +04:00
/* pull over the rsvd page header & part_nasids mask */
2005-03-24 05:50:00 +03:00
ret = xpc_get_remote_rp ( nasid , discovered_nasids ,
2008-04-22 23:48:01 +04:00
remote_rp , & remote_rp_pa ) ;
2008-05-13 01:02:02 +04:00
if ( ret ! = xpSuccess ) {
2005-03-24 05:50:00 +03:00
dev_dbg ( xpc_part , " unable to get reserved page "
" from nasid %d, reason=%d \n " , nasid ,
ret ) ;
2008-05-13 01:02:02 +04:00
if ( ret = = xpLocalPartid )
2005-03-24 05:50:00 +03:00
break ;
2008-04-22 23:50:17 +04:00
2005-03-24 05:50:00 +03:00
continue ;
}
2009-04-14 01:40:19 +04:00
xpc_arch_ops . request_partition_activation ( remote_rp ,
2008-07-30 09:34:09 +04:00
remote_rp_pa , nasid ) ;
2005-03-24 05:50:00 +03:00
}
}
kfree ( discovered_nasids ) ;
kfree ( remote_rp_base ) ;
}
/*
* Given a partid , get the nasids owned by that partition from the
2005-04-05 00:14:00 +04:00
* remote partition ' s reserved page .
2005-03-24 05:50:00 +03:00
*/
2008-05-13 01:02:02 +04:00
enum xp_retval
2008-05-13 01:02:03 +04:00
xpc_initiate_partid_to_nasids ( short partid , void * nasid_mask )
2005-03-24 05:50:00 +03:00
{
struct xpc_partition * part ;
2008-07-30 09:34:16 +04:00
unsigned long part_nasid_pa ;
2005-03-24 05:50:00 +03:00
part = & xpc_partitions [ partid ] ;
2008-04-22 23:50:17 +04:00
if ( part - > remote_rp_pa = = 0 )
2008-05-13 01:02:02 +04:00
return xpPartitionDown ;
2005-03-24 05:50:00 +03:00
2008-07-30 09:34:14 +04:00
memset ( nasid_mask , 0 , xpc_nasid_mask_nbytes ) ;
2005-10-25 23:09:51 +04:00
2008-07-30 09:34:16 +04:00
part_nasid_pa = ( unsigned long ) XPC_RP_PART_NASIDS ( part - > remote_rp_pa ) ;
2005-03-24 05:50:00 +03:00
2008-07-30 09:34:16 +04:00
return xp_remote_memcpy ( xp_pa ( nasid_mask ) , part_nasid_pa ,
2008-07-30 09:34:14 +04:00
xpc_nasid_mask_nbytes ) ;
2005-03-24 05:50:00 +03:00
}