2005-03-23 19:50:00 -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 .
*
2009-04-13 14:40:19 -07:00
* Copyright ( c ) 2004 - 2009 Silicon Graphics , Inc . All Rights Reserved .
2005-03-23 19:50:00 -07:00
*/
/*
* Cross Partition Communication ( XPC ) channel support .
*
* This is the part of XPC that manages the channels and
* sends / receives messages across them to / from other partitions .
*
*/
2008-07-29 22:34:16 -07:00
# include <linux/device.h>
2008-04-22 14:46:56 -05:00
# include "xpc.h"
2005-03-23 19:50:00 -07:00
/*
* Process a connect message from a remote partition .
*
* Note : xpc_process_connect ( ) is expecting to be called with the
* spin_lock_irqsave held and will leave it locked upon return .
*/
static void
xpc_process_connect ( struct xpc_channel * ch , unsigned long * irq_flags )
{
2008-05-12 14:02:02 -07:00
enum xp_retval ret ;
2005-03-23 19:50:00 -07:00
DBUG_ON ( ! spin_is_locked ( & ch - > lock ) ) ;
if ( ! ( ch - > flags & XPC_C_OPENREQUEST ) | |
2008-04-22 14:48:55 -05:00
! ( ch - > flags & XPC_C_ROPENREQUEST ) ) {
2005-03-23 19:50:00 -07:00
/* nothing more to do for now */
return ;
}
DBUG_ON ( ! ( ch - > flags & XPC_C_CONNECTING ) ) ;
if ( ! ( ch - > flags & XPC_C_SETUP ) ) {
spin_unlock_irqrestore ( & ch - > lock , * irq_flags ) ;
2009-04-13 14:40:19 -07:00
ret = xpc_arch_ops . setup_msg_structures ( ch ) ;
2005-03-23 19:50:00 -07:00
spin_lock_irqsave ( & ch - > lock , * irq_flags ) ;
2008-05-12 14:02:02 -07:00
if ( ret ! = xpSuccess )
2005-03-23 19:50:00 -07:00
XPC_DISCONNECT_CHANNEL ( ch , ret , irq_flags ) ;
2009-04-13 14:40:19 -07:00
else
ch - > flags | = XPC_C_SETUP ;
2008-04-22 14:50:17 -05:00
2009-04-13 14:40:19 -07:00
if ( ch - > flags & XPC_C_DISCONNECTING )
2005-03-23 19:50:00 -07:00
return ;
}
if ( ! ( ch - > flags & XPC_C_OPENREPLY ) ) {
ch - > flags | = XPC_C_OPENREPLY ;
2009-04-13 14:40:19 -07:00
xpc_arch_ops . send_chctl_openreply ( ch , irq_flags ) ;
2005-03-23 19:50:00 -07:00
}
2008-04-22 14:50:17 -05:00
if ( ! ( ch - > flags & XPC_C_ROPENREPLY ) )
2005-03-23 19:50:00 -07:00
return ;
2009-04-13 14:40:19 -07:00
if ( ! ( ch - > flags & XPC_C_OPENCOMPLETE ) ) {
ch - > flags | = ( XPC_C_OPENCOMPLETE | XPC_C_CONNECTED ) ;
2009-04-13 14:40:19 -07:00
xpc_arch_ops . send_chctl_opencomplete ( ch , irq_flags ) ;
2009-04-13 14:40:19 -07:00
}
if ( ! ( ch - > flags & XPC_C_ROPENCOMPLETE ) )
return ;
2005-03-23 19:50:00 -07:00
dev_info ( xpc_chan , " channel %d to partition %d connected \n " ,
2008-04-22 14:48:55 -05:00
ch - > number , ch - > partid ) ;
2005-03-23 19:50:00 -07:00
2009-04-13 14:40:19 -07:00
ch - > flags = ( XPC_C_CONNECTED | XPC_C_SETUP ) ; /* clear all else */
2005-03-23 19:50:00 -07:00
}
/*
* spin_lock_irqsave ( ) is expected to be held on entry .
*/
static void
xpc_process_disconnect ( struct xpc_channel * ch , unsigned long * irq_flags )
{
struct xpc_partition * part = & xpc_partitions [ ch - > partid ] ;
2005-09-01 14:01:37 -05:00
u32 channel_was_connected = ( ch - > flags & XPC_C_WASCONNECTED ) ;
2005-03-23 19:50:00 -07:00
DBUG_ON ( ! spin_is_locked ( & ch - > lock ) ) ;
2008-04-22 14:50:17 -05:00
if ( ! ( ch - > flags & XPC_C_DISCONNECTING ) )
2005-03-23 19:50:00 -07:00
return ;
DBUG_ON ( ! ( ch - > flags & XPC_C_CLOSEREQUEST ) ) ;
/* make sure all activity has settled down first */
2006-11-22 08:25:00 -06:00
if ( atomic_read ( & ch - > kthreads_assigned ) > 0 | |
2008-04-22 14:48:55 -05:00
atomic_read ( & ch - > references ) > 0 ) {
2005-03-23 19:50:00 -07:00
return ;
}
2006-11-22 08:25:00 -06:00
DBUG_ON ( ( ch - > flags & XPC_C_CONNECTEDCALLOUT_MADE ) & &
2008-04-22 14:48:55 -05:00
! ( ch - > flags & XPC_C_DISCONNECTINGCALLOUT_MADE ) ) ;
2005-03-23 19:50:00 -07:00
2008-07-29 22:34:18 -07:00
if ( part - > act_state = = XPC_P_AS_DEACTIVATING ) {
2005-09-01 14:01:37 -05:00
/* can't proceed until the other side disengages from us */
2009-04-13 14:40:19 -07:00
if ( xpc_arch_ops . partition_engaged ( ch - > partid ) )
2005-09-01 14:01:37 -05:00
return ;
2005-03-23 19:50:00 -07:00
2005-09-01 14:01:37 -05:00
} else {
2005-03-23 19:50:00 -07:00
/* as long as the other side is up do the full protocol */
2008-04-22 14:50:17 -05:00
if ( ! ( ch - > flags & XPC_C_RCLOSEREQUEST ) )
2005-03-23 19:50:00 -07:00
return ;
if ( ! ( ch - > flags & XPC_C_CLOSEREPLY ) ) {
ch - > flags | = XPC_C_CLOSEREPLY ;
2009-04-13 14:40:19 -07:00
xpc_arch_ops . send_chctl_closereply ( ch , irq_flags ) ;
2005-03-23 19:50:00 -07:00
}
2008-04-22 14:50:17 -05:00
if ( ! ( ch - > flags & XPC_C_RCLOSEREPLY ) )
2005-03-23 19:50:00 -07:00
return ;
}
2005-09-01 14:01:37 -05:00
/* wake those waiting for notify completion */
if ( atomic_read ( & ch - > n_to_notify ) > 0 ) {
2008-07-29 22:34:14 -07:00
/* we do callout while holding ch->lock, callout can't block */
2009-04-13 14:40:19 -07:00
xpc_arch_ops . notify_senders_of_disconnect ( ch ) ;
2005-09-01 14:01:37 -05:00
}
2005-03-23 19:50:00 -07:00
/* both sides are disconnected now */
2006-02-15 08:02:21 -06:00
if ( ch - > flags & XPC_C_DISCONNECTINGCALLOUT_MADE ) {
2005-12-22 14:32:56 -06:00
spin_unlock_irqrestore ( & ch - > lock , * irq_flags ) ;
2008-05-12 14:02:02 -07:00
xpc_disconnect_callout ( ch , xpDisconnected ) ;
2005-12-22 14:32:56 -06:00
spin_lock_irqsave ( & ch - > lock , * irq_flags ) ;
}
2008-07-29 22:34:18 -07:00
DBUG_ON ( atomic_read ( & ch - > n_to_notify ) ! = 0 ) ;
2005-09-01 14:01:37 -05:00
/* it's now safe to free the channel's message queues */
2009-04-13 14:40:19 -07:00
xpc_arch_ops . teardown_msg_structures ( ch ) ;
2008-07-29 22:34:18 -07:00
ch - > func = NULL ;
ch - > key = NULL ;
2008-07-29 22:34:19 -07:00
ch - > entry_size = 0 ;
2008-07-29 22:34:18 -07:00
ch - > local_nentries = 0 ;
ch - > remote_nentries = 0 ;
ch - > kthreads_assigned_limit = 0 ;
ch - > kthreads_idle_limit = 0 ;
2005-09-01 14:01:37 -05:00
2008-07-29 22:34:11 -07:00
/*
* Mark the channel disconnected and clear all other flags , including
2009-04-13 14:40:19 -07:00
* XPC_C_SETUP ( because of call to
* xpc_arch_ops . teardown_msg_structures ( ) ) but not including
* XPC_C_WDISCONNECT ( if it was set ) .
2008-07-29 22:34:11 -07:00
*/
2005-09-01 14:01:37 -05:00
ch - > flags = ( XPC_C_DISCONNECTED | ( ch - > flags & XPC_C_WDISCONNECT ) ) ;
2005-03-23 19:50:00 -07:00
atomic_dec ( & part - > nchannels_active ) ;
2005-09-01 14:01:37 -05:00
if ( channel_was_connected ) {
2005-03-23 19:50:00 -07:00
dev_info ( xpc_chan , " channel %d to partition %d disconnected, "
2008-04-22 14:48:55 -05:00
" reason=%d \n " , ch - > number , ch - > partid , ch - > reason ) ;
2005-03-23 19:50:00 -07:00
}
2005-09-01 14:01:37 -05:00
if ( ch - > flags & XPC_C_WDISCONNECT ) {
2006-01-17 12:52:21 -05:00
/* we won't lose the CPU since we're holding ch->lock */
complete ( & ch - > wdisconnect_wait ) ;
2008-07-29 22:34:10 -07:00
} else if ( ch - > delayed_chctl_flags ) {
2008-07-29 22:34:18 -07:00
if ( part - > act_state ! = XPC_P_AS_DEACTIVATING ) {
2008-07-29 22:34:10 -07:00
/* time to take action on any delayed chctl flags */
spin_lock ( & part - > chctl_lock ) ;
part - > chctl . flags [ ch - > number ] | =
ch - > delayed_chctl_flags ;
spin_unlock ( & part - > chctl_lock ) ;
2005-10-25 14:07:43 -05:00
}
2008-07-29 22:34:10 -07:00
ch - > delayed_chctl_flags = 0 ;
2005-09-01 14:01:37 -05:00
}
2005-03-23 19:50:00 -07:00
}
/*
* Process a change in the channel ' s remote connection state .
*/
static void
2008-07-29 22:34:10 -07:00
xpc_process_openclose_chctl_flags ( struct xpc_partition * part , int ch_number ,
u8 chctl_flags )
2005-03-23 19:50:00 -07:00
{
unsigned long irq_flags ;
struct xpc_openclose_args * args =
2008-04-22 14:48:55 -05:00
& part - > remote_openclose_args [ ch_number ] ;
2005-03-23 19:50:00 -07:00
struct xpc_channel * ch = & part - > channels [ ch_number ] ;
2008-05-12 14:02:02 -07:00
enum xp_retval reason ;
2009-04-02 16:59:10 -07:00
enum xp_retval ret ;
2009-04-13 14:40:19 -07:00
int create_kthread = 0 ;
2005-03-23 19:50:00 -07:00
spin_lock_irqsave ( & ch - > lock , irq_flags ) ;
2008-04-22 14:50:17 -05:00
again :
2005-10-25 14:07:43 -05:00
2008-04-22 14:50:17 -05:00
if ( ( ch - > flags & XPC_C_DISCONNECTED ) & &
( ch - > flags & XPC_C_WDISCONNECT ) ) {
2005-10-25 14:07:43 -05:00
/*
2008-07-29 22:34:10 -07:00
* Delay processing chctl flags until thread waiting disconnect
2005-10-25 14:07:43 -05:00
* has had a chance to see that the channel is disconnected .
*/
2008-07-29 22:34:10 -07:00
ch - > delayed_chctl_flags | = chctl_flags ;
2009-04-13 14:40:19 -07:00
goto out ;
2005-10-25 14:07:43 -05:00
}
2008-07-29 22:34:10 -07:00
if ( chctl_flags & XPC_CHCTL_CLOSEREQUEST ) {
2005-03-23 19:50:00 -07:00
2008-07-29 22:34:10 -07:00
dev_dbg ( xpc_chan , " XPC_CHCTL_CLOSEREQUEST (reason=%d) received "
2005-03-23 19:50:00 -07:00
" from partid=%d, channel=%d \n " , args - > reason ,
ch - > partid , ch - > number ) ;
/*
* If RCLOSEREQUEST is set , we ' re probably waiting for
* RCLOSEREPLY . We should find it and a ROPENREQUEST packed
2008-07-29 22:34:10 -07:00
* with this RCLOSEREQUEST in the chctl_flags .
2005-03-23 19:50:00 -07:00
*/
if ( ch - > flags & XPC_C_RCLOSEREQUEST ) {
DBUG_ON ( ! ( ch - > flags & XPC_C_DISCONNECTING ) ) ;
DBUG_ON ( ! ( ch - > flags & XPC_C_CLOSEREQUEST ) ) ;
DBUG_ON ( ! ( ch - > flags & XPC_C_CLOSEREPLY ) ) ;
DBUG_ON ( ch - > flags & XPC_C_RCLOSEREPLY ) ;
2008-07-29 22:34:10 -07:00
DBUG_ON ( ! ( chctl_flags & XPC_CHCTL_CLOSEREPLY ) ) ;
chctl_flags & = ~ XPC_CHCTL_CLOSEREPLY ;
2005-03-23 19:50:00 -07:00
ch - > flags | = XPC_C_RCLOSEREPLY ;
/* both sides have finished disconnecting */
xpc_process_disconnect ( ch , & irq_flags ) ;
2005-10-25 14:07:43 -05:00
DBUG_ON ( ! ( ch - > flags & XPC_C_DISCONNECTED ) ) ;
goto again ;
2005-03-23 19:50:00 -07:00
}
if ( ch - > flags & XPC_C_DISCONNECTED ) {
2008-07-29 22:34:10 -07:00
if ( ! ( chctl_flags & XPC_CHCTL_OPENREQUEST ) ) {
if ( part - > chctl . flags [ ch_number ] &
XPC_CHCTL_OPENREQUEST ) {
DBUG_ON ( ch - > delayed_chctl_flags ! = 0 ) ;
spin_lock ( & part - > chctl_lock ) ;
part - > chctl . flags [ ch_number ] | =
XPC_CHCTL_CLOSEREQUEST ;
spin_unlock ( & part - > chctl_lock ) ;
2005-10-25 14:07:43 -05:00
}
2009-04-13 14:40:19 -07:00
goto out ;
2005-03-23 19:50:00 -07:00
}
XPC_SET_REASON ( ch , 0 , 0 ) ;
ch - > flags & = ~ XPC_C_DISCONNECTED ;
atomic_inc ( & part - > nchannels_active ) ;
ch - > flags | = ( XPC_C_CONNECTING | XPC_C_ROPENREQUEST ) ;
}
2009-04-13 14:40:19 -07:00
chctl_flags & = ~ ( XPC_CHCTL_OPENREQUEST | XPC_CHCTL_OPENREPLY |
XPC_CHCTL_OPENCOMPLETE ) ;
2005-03-23 19:50:00 -07:00
/*
* The meaningful CLOSEREQUEST connection state fields are :
* reason = reason connection is to be closed
*/
ch - > flags | = XPC_C_RCLOSEREQUEST ;
if ( ! ( ch - > flags & XPC_C_DISCONNECTING ) ) {
reason = args - > reason ;
2008-05-12 14:02:02 -07:00
if ( reason < = xpSuccess | | reason > xpUnknownReason )
reason = xpUnknownReason ;
else if ( reason = = xpUnregistering )
reason = xpOtherUnregistering ;
2005-03-23 19:50:00 -07:00
XPC_DISCONNECT_CHANNEL ( ch , reason , & irq_flags ) ;
2005-10-25 14:07:43 -05:00
2008-07-29 22:34:10 -07:00
DBUG_ON ( chctl_flags & XPC_CHCTL_CLOSEREPLY ) ;
2009-04-13 14:40:19 -07:00
goto out ;
2005-03-23 19:50:00 -07:00
}
2005-10-25 14:07:43 -05:00
xpc_process_disconnect ( ch , & irq_flags ) ;
2005-03-23 19:50:00 -07:00
}
2008-07-29 22:34:10 -07:00
if ( chctl_flags & XPC_CHCTL_CLOSEREPLY ) {
2005-03-23 19:50:00 -07:00
2008-07-29 22:34:10 -07:00
dev_dbg ( xpc_chan , " XPC_CHCTL_CLOSEREPLY received from partid= "
" %d, channel=%d \n " , ch - > partid , ch - > number ) ;
2005-03-23 19:50:00 -07:00
if ( ch - > flags & XPC_C_DISCONNECTED ) {
2008-07-29 22:34:18 -07:00
DBUG_ON ( part - > act_state ! = XPC_P_AS_DEACTIVATING ) ;
2009-04-13 14:40:19 -07:00
goto out ;
2005-03-23 19:50:00 -07:00
}
DBUG_ON ( ! ( ch - > flags & XPC_C_CLOSEREQUEST ) ) ;
2005-10-25 14:07:43 -05:00
if ( ! ( ch - > flags & XPC_C_RCLOSEREQUEST ) ) {
2008-07-29 22:34:10 -07:00
if ( part - > chctl . flags [ ch_number ] &
XPC_CHCTL_CLOSEREQUEST ) {
DBUG_ON ( ch - > delayed_chctl_flags ! = 0 ) ;
spin_lock ( & part - > chctl_lock ) ;
part - > chctl . flags [ ch_number ] | =
XPC_CHCTL_CLOSEREPLY ;
spin_unlock ( & part - > chctl_lock ) ;
2005-10-25 14:07:43 -05:00
}
2009-04-13 14:40:19 -07:00
goto out ;
2005-10-25 14:07:43 -05:00
}
2005-03-23 19:50:00 -07:00
ch - > flags | = XPC_C_RCLOSEREPLY ;
if ( ch - > flags & XPC_C_CLOSEREPLY ) {
/* both sides have finished disconnecting */
xpc_process_disconnect ( ch , & irq_flags ) ;
}
}
2008-07-29 22:34:10 -07:00
if ( chctl_flags & XPC_CHCTL_OPENREQUEST ) {
2005-03-23 19:50:00 -07:00
2008-07-29 22:34:19 -07:00
dev_dbg ( xpc_chan , " XPC_CHCTL_OPENREQUEST (entry_size=%d, "
2005-03-23 19:50:00 -07:00
" local_nentries=%d) received from partid=%d, "
2008-07-29 22:34:19 -07:00
" channel=%d \n " , args - > entry_size , args - > local_nentries ,
2005-03-23 19:50:00 -07:00
ch - > partid , ch - > number ) ;
2008-07-29 22:34:18 -07:00
if ( part - > act_state = = XPC_P_AS_DEACTIVATING | |
2008-04-22 14:48:55 -05:00
( ch - > flags & XPC_C_ROPENREQUEST ) ) {
2009-04-13 14:40:19 -07:00
goto out ;
2005-10-25 14:07:43 -05:00
}
if ( ch - > flags & ( XPC_C_DISCONNECTING | XPC_C_WDISCONNECT ) ) {
2008-07-29 22:34:10 -07:00
ch - > delayed_chctl_flags | = XPC_CHCTL_OPENREQUEST ;
2009-04-13 14:40:19 -07:00
goto out ;
2005-03-23 19:50:00 -07:00
}
DBUG_ON ( ! ( ch - > flags & ( XPC_C_DISCONNECTED |
2008-04-22 14:48:55 -05:00
XPC_C_OPENREQUEST ) ) ) ;
2005-03-23 19:50:00 -07:00
DBUG_ON ( ch - > flags & ( XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY |
2008-04-22 14:48:55 -05:00
XPC_C_OPENREPLY | XPC_C_CONNECTED ) ) ;
2005-03-23 19:50:00 -07:00
/*
* The meaningful OPENREQUEST connection state fields are :
2008-07-29 22:34:19 -07:00
* entry_size = size of channel ' s messages in bytes
2005-03-23 19:50:00 -07:00
* local_nentries = remote partition ' s local_nentries
*/
2008-07-29 22:34:19 -07:00
if ( args - > entry_size = = 0 | | args - > local_nentries = = 0 ) {
2005-10-25 14:07:43 -05:00
/* assume OPENREQUEST was delayed by mistake */
2009-04-13 14:40:19 -07:00
goto out ;
2005-10-25 14:07:43 -05:00
}
2005-03-23 19:50:00 -07:00
ch - > flags | = ( XPC_C_ROPENREQUEST | XPC_C_CONNECTING ) ;
ch - > remote_nentries = args - > local_nentries ;
if ( ch - > flags & XPC_C_OPENREQUEST ) {
2008-07-29 22:34:19 -07:00
if ( args - > entry_size ! = ch - > entry_size ) {
2008-05-12 14:02:02 -07:00
XPC_DISCONNECT_CHANNEL ( ch , xpUnequalMsgSizes ,
2008-04-22 14:48:55 -05:00
& irq_flags ) ;
2009-04-13 14:40:19 -07:00
goto out ;
2005-03-23 19:50:00 -07:00
}
} else {
2008-07-29 22:34:19 -07:00
ch - > entry_size = args - > entry_size ;
2005-03-23 19:50:00 -07:00
XPC_SET_REASON ( ch , 0 , 0 ) ;
ch - > flags & = ~ XPC_C_DISCONNECTED ;
atomic_inc ( & part - > nchannels_active ) ;
}
xpc_process_connect ( ch , & irq_flags ) ;
}
2008-07-29 22:34:10 -07:00
if ( chctl_flags & XPC_CHCTL_OPENREPLY ) {
2005-03-23 19:50:00 -07:00
2008-07-29 22:34:10 -07:00
dev_dbg ( xpc_chan , " XPC_CHCTL_OPENREPLY (local_msgqueue_pa= "
" 0x%lx, local_nentries=%d, remote_nentries=%d) "
" received from partid=%d, channel=%d \n " ,
2008-07-29 22:34:16 -07:00
args - > local_msgqueue_pa , args - > local_nentries ,
args - > remote_nentries , ch - > partid , ch - > number ) ;
2005-03-23 19:50:00 -07:00
2009-04-13 14:40:19 -07:00
if ( ch - > flags & ( XPC_C_DISCONNECTING | XPC_C_DISCONNECTED ) )
goto out ;
2005-10-25 14:07:43 -05:00
if ( ! ( ch - > flags & XPC_C_OPENREQUEST ) ) {
2008-05-12 14:02:02 -07:00
XPC_DISCONNECT_CHANNEL ( ch , xpOpenCloseError ,
2008-04-22 14:48:55 -05:00
& irq_flags ) ;
2009-04-13 14:40:19 -07:00
goto out ;
2005-10-25 14:07:43 -05:00
}
2005-03-23 19:50:00 -07:00
DBUG_ON ( ! ( ch - > flags & XPC_C_ROPENREQUEST ) ) ;
DBUG_ON ( ch - > flags & XPC_C_CONNECTED ) ;
/*
* The meaningful OPENREPLY connection state fields are :
* local_msgqueue_pa = physical address of remote
2008-04-22 14:48:55 -05:00
* partition ' s local_msgqueue
2005-03-23 19:50:00 -07:00
* local_nentries = remote partition ' s local_nentries
* remote_nentries = remote partition ' s remote_nentries
*/
DBUG_ON ( args - > local_msgqueue_pa = = 0 ) ;
DBUG_ON ( args - > local_nentries = = 0 ) ;
DBUG_ON ( args - > remote_nentries = = 0 ) ;
2009-04-13 14:40:19 -07:00
ret = xpc_arch_ops . save_remote_msgqueue_pa ( ch ,
args - > local_msgqueue_pa ) ;
2009-04-02 16:59:10 -07:00
if ( ret ! = xpSuccess ) {
XPC_DISCONNECT_CHANNEL ( ch , ret , & irq_flags ) ;
2009-04-13 14:40:19 -07:00
goto out ;
2009-04-02 16:59:10 -07:00
}
2005-03-23 19:50:00 -07:00
ch - > flags | = XPC_C_ROPENREPLY ;
if ( args - > local_nentries < ch - > remote_nentries ) {
2008-07-29 22:34:10 -07:00
dev_dbg ( xpc_chan , " XPC_CHCTL_OPENREPLY: new "
2005-03-23 19:50:00 -07:00
" remote_nentries=%d, old remote_nentries=%d, "
" partid=%d, channel=%d \n " ,
args - > local_nentries , ch - > remote_nentries ,
ch - > partid , ch - > number ) ;
ch - > remote_nentries = args - > local_nentries ;
}
if ( args - > remote_nentries < ch - > local_nentries ) {
2008-07-29 22:34:10 -07:00
dev_dbg ( xpc_chan , " XPC_CHCTL_OPENREPLY: new "
2005-03-23 19:50:00 -07:00
" local_nentries=%d, old local_nentries=%d, "
" partid=%d, channel=%d \n " ,
args - > remote_nentries , ch - > local_nentries ,
ch - > partid , ch - > number ) ;
ch - > local_nentries = args - > remote_nentries ;
}
xpc_process_connect ( ch , & irq_flags ) ;
}
2009-04-13 14:40:19 -07:00
if ( chctl_flags & XPC_CHCTL_OPENCOMPLETE ) {
dev_dbg ( xpc_chan , " XPC_CHCTL_OPENCOMPLETE received from "
" partid=%d, channel=%d \n " , ch - > partid , ch - > number ) ;
if ( ch - > flags & ( XPC_C_DISCONNECTING | XPC_C_DISCONNECTED ) )
goto out ;
if ( ! ( ch - > flags & XPC_C_OPENREQUEST ) | |
! ( ch - > flags & XPC_C_OPENREPLY ) ) {
XPC_DISCONNECT_CHANNEL ( ch , xpOpenCloseError ,
& irq_flags ) ;
goto out ;
}
DBUG_ON ( ! ( ch - > flags & XPC_C_ROPENREQUEST ) ) ;
DBUG_ON ( ! ( ch - > flags & XPC_C_ROPENREPLY ) ) ;
DBUG_ON ( ! ( ch - > flags & XPC_C_CONNECTED ) ) ;
ch - > flags | = XPC_C_ROPENCOMPLETE ;
xpc_process_connect ( ch , & irq_flags ) ;
create_kthread = 1 ;
}
out :
2005-03-23 19:50:00 -07:00
spin_unlock_irqrestore ( & ch - > lock , irq_flags ) ;
2009-04-13 14:40:19 -07:00
if ( create_kthread )
xpc_create_kthreads ( ch , 1 , 0 ) ;
2005-03-23 19:50:00 -07:00
}
/*
* Attempt to establish a channel connection to a remote partition .
*/
2008-05-12 14:02:02 -07:00
static enum xp_retval
2005-03-23 19:50:00 -07:00
xpc_connect_channel ( struct xpc_channel * ch )
{
unsigned long irq_flags ;
struct xpc_registration * registration = & xpc_registrations [ ch - > number ] ;
2008-04-22 14:50:17 -05:00
if ( mutex_trylock ( & registration - > mutex ) = = 0 )
2008-05-12 14:02:02 -07:00
return xpRetry ;
2005-03-23 19:50:00 -07:00
if ( ! XPC_CHANNEL_REGISTERED ( ch - > number ) ) {
2006-01-17 12:52:21 -05:00
mutex_unlock ( & registration - > mutex ) ;
2008-05-12 14:02:02 -07:00
return xpUnregistered ;
2005-03-23 19:50:00 -07:00
}
spin_lock_irqsave ( & ch - > lock , irq_flags ) ;
DBUG_ON ( ch - > flags & XPC_C_CONNECTED ) ;
DBUG_ON ( ch - > flags & XPC_C_OPENREQUEST ) ;
if ( ch - > flags & XPC_C_DISCONNECTING ) {
spin_unlock_irqrestore ( & ch - > lock , irq_flags ) ;
2006-01-17 12:52:21 -05:00
mutex_unlock ( & registration - > mutex ) ;
2005-03-23 19:50:00 -07:00
return ch - > reason ;
}
/* add info from the channel connect registration to the channel */
ch - > kthreads_assigned_limit = registration - > assigned_limit ;
ch - > kthreads_idle_limit = registration - > idle_limit ;
DBUG_ON ( atomic_read ( & ch - > kthreads_assigned ) ! = 0 ) ;
DBUG_ON ( atomic_read ( & ch - > kthreads_idle ) ! = 0 ) ;
DBUG_ON ( atomic_read ( & ch - > kthreads_active ) ! = 0 ) ;
ch - > func = registration - > func ;
DBUG_ON ( registration - > func = = NULL ) ;
ch - > key = registration - > key ;
ch - > local_nentries = registration - > nentries ;
if ( ch - > flags & XPC_C_ROPENREQUEST ) {
2008-07-29 22:34:19 -07:00
if ( registration - > entry_size ! = ch - > entry_size ) {
2005-03-23 19:50:00 -07:00
/* the local and remote sides aren't the same */
/*
* Because XPC_DISCONNECT_CHANNEL ( ) can block we ' re
* forced to up the registration sema before we unlock
* the channel lock . But that ' s okay here because we ' re
* done with the part that required the registration
* sema . XPC_DISCONNECT_CHANNEL ( ) requires that the
* channel lock be locked and will unlock and relock
* the channel lock as needed .
*/
2006-01-17 12:52:21 -05:00
mutex_unlock ( & registration - > mutex ) ;
2008-05-12 14:02:02 -07:00
XPC_DISCONNECT_CHANNEL ( ch , xpUnequalMsgSizes ,
2008-04-22 14:48:55 -05:00
& irq_flags ) ;
2005-03-23 19:50:00 -07:00
spin_unlock_irqrestore ( & ch - > lock , irq_flags ) ;
2008-05-12 14:02:02 -07:00
return xpUnequalMsgSizes ;
2005-03-23 19:50:00 -07:00
}
} else {
2008-07-29 22:34:19 -07:00
ch - > entry_size = registration - > entry_size ;
2005-03-23 19:50:00 -07:00
XPC_SET_REASON ( ch , 0 , 0 ) ;
ch - > flags & = ~ XPC_C_DISCONNECTED ;
atomic_inc ( & xpc_partitions [ ch - > partid ] . nchannels_active ) ;
}
2006-01-17 12:52:21 -05:00
mutex_unlock ( & registration - > mutex ) ;
2005-03-23 19:50:00 -07:00
/* initiate the connection */
ch - > flags | = ( XPC_C_OPENREQUEST | XPC_C_CONNECTING ) ;
2009-04-13 14:40:19 -07:00
xpc_arch_ops . send_chctl_openrequest ( ch , & irq_flags ) ;
2005-03-23 19:50:00 -07:00
xpc_process_connect ( ch , & irq_flags ) ;
spin_unlock_irqrestore ( & ch - > lock , irq_flags ) ;
2008-05-12 14:02:02 -07:00
return xpSuccess ;
2005-03-23 19:50:00 -07:00
}
void
2008-07-29 22:34:10 -07:00
xpc_process_sent_chctl_flags ( struct xpc_partition * part )
2005-03-23 19:50:00 -07:00
{
unsigned long irq_flags ;
2008-07-29 22:34:10 -07:00
union xpc_channel_ctl_flags chctl ;
2005-03-23 19:50:00 -07:00
struct xpc_channel * ch ;
int ch_number ;
2005-09-01 14:01:37 -05:00
u32 ch_flags ;
2005-03-23 19:50:00 -07:00
2009-04-13 14:40:19 -07:00
chctl . all_flags = xpc_arch_ops . get_chctl_all_flags ( part ) ;
2005-03-23 19:50:00 -07:00
/*
* Initiate channel connections for registered channels .
*
* For each connected channel that has pending messages activate idle
* kthreads and / or create new kthreads as needed .
*/
for ( ch_number = 0 ; ch_number < part - > nchannels ; ch_number + + ) {
ch = & part - > channels [ ch_number ] ;
/*
2008-07-29 22:34:10 -07:00
* Process any open or close related chctl flags , and then deal
2005-03-23 19:50:00 -07:00
* with connecting or disconnecting the channel as required .
*/
2008-07-29 22:34:10 -07:00
if ( chctl . flags [ ch_number ] & XPC_OPENCLOSE_CHCTL_FLAGS ) {
xpc_process_openclose_chctl_flags ( part , ch_number ,
chctl . flags [ ch_number ] ) ;
}
2005-03-23 19:50:00 -07:00
2005-09-01 14:01:37 -05:00
ch_flags = ch - > flags ; /* need an atomic snapshot of flags */
2005-03-23 19:50:00 -07:00
2005-09-01 14:01:37 -05:00
if ( ch_flags & XPC_C_DISCONNECTING ) {
2005-03-23 19:50:00 -07:00
spin_lock_irqsave ( & ch - > lock , irq_flags ) ;
xpc_process_disconnect ( ch , & irq_flags ) ;
spin_unlock_irqrestore ( & ch - > lock , irq_flags ) ;
continue ;
}
2008-07-29 22:34:18 -07:00
if ( part - > act_state = = XPC_P_AS_DEACTIVATING )
2005-03-23 19:50:00 -07:00
continue ;
2005-09-01 14:01:37 -05:00
if ( ! ( ch_flags & XPC_C_CONNECTED ) ) {
if ( ! ( ch_flags & XPC_C_OPENREQUEST ) ) {
DBUG_ON ( ch_flags & XPC_C_SETUP ) ;
2008-04-22 14:48:55 -05:00
( void ) xpc_connect_channel ( ch ) ;
2005-03-23 19:50:00 -07:00
}
continue ;
}
/*
2008-07-29 22:34:10 -07:00
* Process any message related chctl flags , this may involve
* the activation of kthreads to deliver any pending messages
* sent from the other partition .
2005-03-23 19:50:00 -07:00
*/
2008-07-29 22:34:10 -07:00
if ( chctl . flags [ ch_number ] & XPC_MSG_CHCTL_FLAGS )
2009-04-13 14:40:19 -07:00
xpc_arch_ops . process_msg_chctl_flags ( part , ch_number ) ;
2005-03-23 19:50:00 -07:00
}
}
/*
2005-09-01 14:01:37 -05:00
* XPC ' s heartbeat code calls this function to inform XPC that a partition is
* going down . XPC responds by tearing down the XPartition Communication
2005-03-23 19:50:00 -07:00
* infrastructure used for the just downed partition .
*
* XPC ' s heartbeat code will never call this function and xpc_partition_up ( )
* at the same time . Nor will it ever make multiple calls to either function
* at the same time .
*/
void
2008-05-12 14:02:02 -07:00
xpc_partition_going_down ( struct xpc_partition * part , enum xp_retval reason )
2005-03-23 19:50:00 -07:00
{
unsigned long irq_flags ;
int ch_number ;
struct xpc_channel * ch ;
dev_dbg ( xpc_chan , " deactivating partition %d, reason=%d \n " ,
XPC_PARTID ( part ) , reason ) ;
if ( ! xpc_part_ref ( part ) ) {
/* infrastructure for this partition isn't currently set up */
return ;
}
2005-09-01 14:01:37 -05:00
/* disconnect channels associated with the partition going down */
2005-03-23 19:50:00 -07:00
for ( ch_number = 0 ; ch_number < part - > nchannels ; ch_number + + ) {
ch = & part - > channels [ ch_number ] ;
xpc_msgqueue_ref ( ch ) ;
spin_lock_irqsave ( & ch - > lock , irq_flags ) ;
XPC_DISCONNECT_CHANNEL ( ch , reason , & irq_flags ) ;
spin_unlock_irqrestore ( & ch - > lock , irq_flags ) ;
xpc_msgqueue_deref ( ch ) ;
}
xpc_wakeup_channel_mgr ( part ) ;
xpc_part_deref ( part ) ;
}
/*
* Called by XP at the time of channel connection registration to cause
* XPC to establish connections to all currently active partitions .
*/
void
xpc_initiate_connect ( int ch_number )
{
2008-05-12 14:02:03 -07:00
short partid ;
2005-03-23 19:50:00 -07:00
struct xpc_partition * part ;
struct xpc_channel * ch ;
2008-07-29 22:34:04 -07:00
DBUG_ON ( ch_number < 0 | | ch_number > = XPC_MAX_NCHANNELS ) ;
2005-03-23 19:50:00 -07:00
2008-07-29 22:34:04 -07:00
for ( partid = 0 ; partid < xp_max_npartitions ; partid + + ) {
2005-03-23 19:50:00 -07:00
part = & xpc_partitions [ partid ] ;
if ( xpc_part_ref ( part ) ) {
ch = & part - > channels [ ch_number ] ;
2005-10-25 14:07:43 -05:00
/*
* Initiate the establishment of a connection on the
* newly registered channel to the remote partition .
*/
xpc_wakeup_channel_mgr ( part ) ;
2005-03-23 19:50:00 -07:00
xpc_part_deref ( part ) ;
}
}
}
void
xpc_connected_callout ( struct xpc_channel * ch )
{
/* let the registerer know that a connection has been established */
if ( ch - > func ! = NULL ) {
2008-05-12 14:02:02 -07:00
dev_dbg ( xpc_chan , " ch->func() called, reason=xpConnected, "
2005-03-23 19:50:00 -07:00
" partid=%d, channel=%d \n " , ch - > partid , ch - > number ) ;
2008-05-12 14:02:02 -07:00
ch - > func ( xpConnected , ch - > partid , ch - > number ,
2008-04-22 14:48:55 -05:00
( void * ) ( u64 ) ch - > local_nentries , ch - > key ) ;
2005-03-23 19:50:00 -07:00
2008-05-12 14:02:02 -07:00
dev_dbg ( xpc_chan , " ch->func() returned, reason=xpConnected, "
2005-03-23 19:50:00 -07:00
" partid=%d, channel=%d \n " , ch - > partid , ch - > number ) ;
}
}
/*
* Called by XP at the time of channel connection unregistration to cause
* XPC to teardown all current connections for the specified channel .
*
* Before returning xpc_initiate_disconnect ( ) will wait until all connections
* on the specified channel have been closed / torndown . So the caller can be
* assured that they will not be receiving any more callouts from XPC to the
* function they registered via xpc_connect ( ) .
*
* Arguments :
*
* ch_number - channel # to unregister .
*/
void
xpc_initiate_disconnect ( int ch_number )
{
unsigned long irq_flags ;
2008-05-12 14:02:03 -07:00
short partid ;
2005-03-23 19:50:00 -07:00
struct xpc_partition * part ;
struct xpc_channel * ch ;
2008-07-29 22:34:04 -07:00
DBUG_ON ( ch_number < 0 | | ch_number > = XPC_MAX_NCHANNELS ) ;
2005-03-23 19:50:00 -07:00
/* initiate the channel disconnect for every active partition */
2008-07-29 22:34:04 -07:00
for ( partid = 0 ; partid < xp_max_npartitions ; partid + + ) {
2005-03-23 19:50:00 -07:00
part = & xpc_partitions [ partid ] ;
if ( xpc_part_ref ( part ) ) {
ch = & part - > channels [ ch_number ] ;
xpc_msgqueue_ref ( ch ) ;
spin_lock_irqsave ( & ch - > lock , irq_flags ) ;
2005-09-01 14:01:37 -05:00
if ( ! ( ch - > flags & XPC_C_DISCONNECTED ) ) {
ch - > flags | = XPC_C_WDISCONNECT ;
2008-05-12 14:02:02 -07:00
XPC_DISCONNECT_CHANNEL ( ch , xpUnregistering ,
2008-04-22 14:48:55 -05:00
& irq_flags ) ;
2005-09-01 14:01:37 -05:00
}
2005-03-23 19:50:00 -07:00
spin_unlock_irqrestore ( & ch - > lock , irq_flags ) ;
xpc_msgqueue_deref ( ch ) ;
xpc_part_deref ( part ) ;
}
}
xpc_disconnect_wait ( ch_number ) ;
}
/*
* To disconnect a channel , and reflect it back to all who may be waiting .
*
2005-09-01 14:01:37 -05:00
* An OPEN is not allowed until XPC_C_DISCONNECTING is cleared by
* xpc_process_disconnect ( ) , and if set , XPC_C_WDISCONNECT is cleared by
* xpc_disconnect_wait ( ) .
2005-03-23 19:50:00 -07:00
*
* THE CHANNEL IS TO BE LOCKED BY THE CALLER AND WILL REMAIN LOCKED UPON RETURN .
*/
void
xpc_disconnect_channel ( const int line , struct xpc_channel * ch ,
2008-05-12 14:02:02 -07:00
enum xp_retval reason , unsigned long * irq_flags )
2005-03-23 19:50:00 -07:00
{
2005-09-01 14:01:37 -05:00
u32 channel_was_connected = ( ch - > flags & XPC_C_CONNECTED ) ;
2005-03-23 19:50:00 -07:00
DBUG_ON ( ! spin_is_locked ( & ch - > lock ) ) ;
2008-04-22 14:50:17 -05:00
if ( ch - > flags & ( XPC_C_DISCONNECTING | XPC_C_DISCONNECTED ) )
2005-03-23 19:50:00 -07:00
return ;
2008-04-22 14:50:17 -05:00
2005-03-23 19:50:00 -07:00
DBUG_ON ( ! ( ch - > flags & ( XPC_C_CONNECTING | XPC_C_CONNECTED ) ) ) ;
dev_dbg ( xpc_chan , " reason=%d, line=%d, partid=%d, channel=%d \n " ,
reason , line , ch - > partid , ch - > number ) ;
XPC_SET_REASON ( ch , reason , line ) ;
2005-09-01 14:01:37 -05:00
ch - > flags | = ( XPC_C_CLOSEREQUEST | XPC_C_DISCONNECTING ) ;
2005-03-23 19:50:00 -07:00
/* some of these may not have been set */
ch - > flags & = ~ ( XPC_C_OPENREQUEST | XPC_C_OPENREPLY |
2008-04-22 14:48:55 -05:00
XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY |
XPC_C_CONNECTING | XPC_C_CONNECTED ) ;
2005-03-23 19:50:00 -07:00
2009-04-13 14:40:19 -07:00
xpc_arch_ops . send_chctl_closerequest ( ch , irq_flags ) ;
2005-03-23 19:50:00 -07:00
2008-04-22 14:50:17 -05:00
if ( channel_was_connected )
2005-03-23 19:50:00 -07:00
ch - > flags | = XPC_C_WASCONNECTED ;
2005-09-01 14:01:37 -05:00
spin_unlock_irqrestore ( & ch - > lock , * irq_flags ) ;
/* wake all idle kthreads so they can exit */
2005-03-23 19:50:00 -07:00
if ( atomic_read ( & ch - > kthreads_idle ) > 0 ) {
wake_up_all ( & ch - > idle_wq ) ;
2006-11-22 08:25:00 -06:00
} else if ( ( ch - > flags & XPC_C_CONNECTEDCALLOUT_MADE ) & &
2008-04-22 14:48:55 -05:00
! ( ch - > flags & XPC_C_DISCONNECTINGCALLOUT ) ) {
2008-05-12 14:02:02 -07:00
/* start a kthread that will do the xpDisconnecting callout */
2006-11-22 08:25:00 -06:00
xpc_create_kthreads ( ch , 1 , 1 ) ;
2005-03-23 19:50:00 -07:00
}
/* wake those waiting to allocate an entry from the local msg queue */
2008-04-22 14:50:17 -05:00
if ( atomic_read ( & ch - > n_on_msg_allocate_wq ) > 0 )
2005-03-23 19:50:00 -07:00
wake_up ( & ch - > msg_allocate_wq ) ;
spin_lock_irqsave ( & ch - > lock , * irq_flags ) ;
}
void
2008-05-12 14:02:02 -07:00
xpc_disconnect_callout ( struct xpc_channel * ch , enum xp_retval reason )
2005-03-23 19:50:00 -07:00
{
/*
2005-09-01 14:01:37 -05:00
* Let the channel ' s registerer know that the channel is being
2005-03-23 19:50:00 -07:00
* disconnected . We don ' t want to do this if the registerer was never
2005-09-01 14:01:37 -05:00
* informed of a connection being made .
2005-03-23 19:50:00 -07:00
*/
if ( ch - > func ! = NULL ) {
2005-12-22 14:32:56 -06:00
dev_dbg ( xpc_chan , " ch->func() called, reason=%d, partid=%d, "
" channel=%d \n " , reason , ch - > partid , ch - > number ) ;
2005-03-23 19:50:00 -07:00
2005-12-22 14:32:56 -06:00
ch - > func ( reason , ch - > partid , ch - > number , NULL , ch - > key ) ;
2005-03-23 19:50:00 -07:00
2005-12-22 14:32:56 -06:00
dev_dbg ( xpc_chan , " ch->func() returned, reason=%d, partid=%d, "
" channel=%d \n " , reason , ch - > partid , ch - > number ) ;
2005-03-23 19:50:00 -07:00
}
}
/*
* Wait for a message entry to become available for the specified channel ,
* but don ' t wait any longer than 1 jiffy .
*/
2008-07-29 22:34:07 -07:00
enum xp_retval
2005-03-23 19:50:00 -07:00
xpc_allocate_msg_wait ( struct xpc_channel * ch )
{
2008-05-12 14:02:02 -07:00
enum xp_retval ret ;
2005-03-23 19:50:00 -07:00
if ( ch - > flags & XPC_C_DISCONNECTING ) {
2008-05-12 14:02:02 -07:00
DBUG_ON ( ch - > reason = = xpInterrupted ) ;
2005-03-23 19:50:00 -07:00
return ch - > reason ;
}
atomic_inc ( & ch - > n_on_msg_allocate_wq ) ;
ret = interruptible_sleep_on_timeout ( & ch - > msg_allocate_wq , 1 ) ;
atomic_dec ( & ch - > n_on_msg_allocate_wq ) ;
if ( ch - > flags & XPC_C_DISCONNECTING ) {
ret = ch - > reason ;
2008-05-12 14:02:02 -07:00
DBUG_ON ( ch - > reason = = xpInterrupted ) ;
2005-03-23 19:50:00 -07:00
} else if ( ret = = 0 ) {
2008-05-12 14:02:02 -07:00
ret = xpTimeout ;
2005-03-23 19:50:00 -07:00
} else {
2008-05-12 14:02:02 -07:00
ret = xpInterrupted ;
2005-03-23 19:50:00 -07:00
}
return ret ;
}
/*
2008-07-29 22:34:08 -07:00
* Send a message that contains the user ' s payload on the specified channel
* connected to the specified partition .
2005-03-23 19:50:00 -07:00
*
2008-07-29 22:34:08 -07:00
* NOTE that this routine can sleep waiting for a message entry to become
* available . To not sleep , pass in the XPC_NOWAIT flag .
2005-03-23 19:50:00 -07:00
*
2008-07-29 22:34:08 -07:00
* Once sent , this routine will not wait for the message to be received , nor
* will notification be given when it does happen .
2005-03-23 19:50:00 -07:00
*
* Arguments :
*
* partid - ID of partition to which the channel is connected .
* ch_number - channel # to send message on .
2008-07-29 22:34:08 -07:00
* flags - see xp . h for valid flags .
* payload - pointer to the payload which is to be sent .
* payload_size - size of the payload in bytes .
2005-03-23 19:50:00 -07:00
*/
2008-05-12 14:02:02 -07:00
enum xp_retval
2008-07-29 22:34:08 -07:00
xpc_initiate_send ( short partid , int ch_number , u32 flags , void * payload ,
u16 payload_size )
2005-03-23 19:50:00 -07:00
{
struct xpc_partition * part = & xpc_partitions [ partid ] ;
2008-07-29 22:34:08 -07:00
enum xp_retval ret = xpUnknownReason ;
2005-03-23 19:50:00 -07:00
2008-07-29 22:34:08 -07:00
dev_dbg ( xpc_chan , " payload=0x%p, partid=%d, channel=%d \n " , payload ,
2005-03-23 19:50:00 -07:00
partid , ch_number ) ;
2008-07-29 22:34:04 -07:00
DBUG_ON ( partid < 0 | | partid > = xp_max_npartitions ) ;
2005-03-23 19:50:00 -07:00
DBUG_ON ( ch_number < 0 | | ch_number > = part - > nchannels ) ;
2008-07-29 22:34:08 -07:00
DBUG_ON ( payload = = NULL ) ;
2005-03-23 19:50:00 -07:00
2008-07-29 22:34:08 -07:00
if ( xpc_part_ref ( part ) ) {
2009-04-13 14:40:19 -07:00
ret = xpc_arch_ops . send_payload ( & part - > channels [ ch_number ] ,
flags , payload , payload_size , 0 , NULL , NULL ) ;
2008-07-29 22:34:08 -07:00
xpc_part_deref ( part ) ;
}
2005-03-23 19:50:00 -07:00
return ret ;
}
/*
2008-07-29 22:34:08 -07:00
* Send a message that contains the user ' s payload on the specified channel
* connected to the specified partition .
2005-03-23 19:50:00 -07:00
*
2008-07-29 22:34:08 -07:00
* NOTE that this routine can sleep waiting for a message entry to become
* available . To not sleep , pass in the XPC_NOWAIT flag .
*
* This routine will not wait for the message to be sent or received .
2005-03-23 19:50:00 -07:00
*
* Once the remote end of the channel has received the message , the function
* passed as an argument to xpc_initiate_send_notify ( ) will be called . This
* allows the sender to free up or re - use any buffers referenced by the
* message , but does NOT mean the message has been processed at the remote
* end by a receiver .
*
* If this routine returns an error , the caller ' s function will NOT be called .
*
* Arguments :
*
* partid - ID of partition to which the channel is connected .
* ch_number - channel # to send message on .
2008-07-29 22:34:08 -07:00
* flags - see xp . h for valid flags .
* payload - pointer to the payload which is to be sent .
* payload_size - size of the payload in bytes .
2005-03-23 19:50:00 -07:00
* func - function to call with asynchronous notification of message
* receipt . THIS FUNCTION MUST BE NON - BLOCKING .
* key - user - defined key to be passed to the function when it ' s called .
*/
2008-05-12 14:02:02 -07:00
enum xp_retval
2008-07-29 22:34:08 -07:00
xpc_initiate_send_notify ( short partid , int ch_number , u32 flags , void * payload ,
u16 payload_size , xpc_notify_func func , void * key )
2005-03-23 19:50:00 -07:00
{
struct xpc_partition * part = & xpc_partitions [ partid ] ;
2008-07-29 22:34:08 -07:00
enum xp_retval ret = xpUnknownReason ;
2005-03-23 19:50:00 -07:00
2008-07-29 22:34:08 -07:00
dev_dbg ( xpc_chan , " payload=0x%p, partid=%d, channel=%d \n " , payload ,
2005-03-23 19:50:00 -07:00
partid , ch_number ) ;
2008-07-29 22:34:04 -07:00
DBUG_ON ( partid < 0 | | partid > = xp_max_npartitions ) ;
2005-03-23 19:50:00 -07:00
DBUG_ON ( ch_number < 0 | | ch_number > = part - > nchannels ) ;
2008-07-29 22:34:08 -07:00
DBUG_ON ( payload = = NULL ) ;
2005-03-23 19:50:00 -07:00
DBUG_ON ( func = = NULL ) ;
2008-07-29 22:34:08 -07:00
if ( xpc_part_ref ( part ) ) {
2009-04-13 14:40:19 -07:00
ret = xpc_arch_ops . send_payload ( & part - > channels [ ch_number ] ,
flags , payload , payload_size , XPC_N_CALL , func , key ) ;
2008-07-29 22:34:08 -07:00
xpc_part_deref ( part ) ;
}
2005-03-23 19:50:00 -07:00
return ret ;
}
/*
2008-07-29 22:34:19 -07:00
* Deliver a message ' s payload to its intended recipient .
2005-03-23 19:50:00 -07:00
*/
void
2008-07-29 22:34:19 -07:00
xpc_deliver_payload ( struct xpc_channel * ch )
2005-03-23 19:50:00 -07:00
{
2008-07-29 22:34:19 -07:00
void * payload ;
2005-03-23 19:50:00 -07:00
2009-04-13 14:40:19 -07:00
payload = xpc_arch_ops . get_deliverable_payload ( ch ) ;
2008-07-29 22:34:19 -07:00
if ( payload ! = NULL ) {
2005-03-23 19:50:00 -07:00
/*
* This ref is taken to protect the payload itself from being
* freed before the user is finished with it , which the user
* indicates by calling xpc_initiate_received ( ) .
*/
xpc_msgqueue_ref ( ch ) ;
atomic_inc ( & ch - > kthreads_active ) ;
if ( ch - > func ! = NULL ) {
2008-07-29 22:34:19 -07:00
dev_dbg ( xpc_chan , " ch->func() called, payload=0x%p "
" partid=%d channel=%d \n " , payload , ch - > partid ,
2005-03-23 19:50:00 -07:00
ch - > number ) ;
/* deliver the message to its intended recipient */
2008-07-29 22:34:19 -07:00
ch - > func ( xpMsgReceived , ch - > partid , ch - > number , payload ,
ch - > key ) ;
2005-03-23 19:50:00 -07:00
2008-07-29 22:34:19 -07:00
dev_dbg ( xpc_chan , " ch->func() returned, payload=0x%p "
" partid=%d channel=%d \n " , payload , ch - > partid ,
2005-03-23 19:50:00 -07:00
ch - > number ) ;
}
atomic_dec ( & ch - > kthreads_active ) ;
}
}
/*
2008-07-29 22:34:19 -07:00
* Acknowledge receipt of a delivered message ' s payload .
2005-03-23 19:50:00 -07:00
*
* This function , although called by users , does not call xpc_part_ref ( ) to
* ensure that the partition infrastructure is in place . It relies on the
2008-07-29 22:34:19 -07:00
* fact that we called xpc_msgqueue_ref ( ) in xpc_deliver_payload ( ) .
2005-03-23 19:50:00 -07:00
*
* Arguments :
*
* partid - ID of partition to which the channel is connected .
* ch_number - channel # message received on .
* payload - pointer to the payload area allocated via
2008-07-29 22:34:08 -07:00
* xpc_initiate_send ( ) or xpc_initiate_send_notify ( ) .
2005-03-23 19:50:00 -07:00
*/
void
2008-05-12 14:02:03 -07:00
xpc_initiate_received ( short partid , int ch_number , void * payload )
2005-03-23 19:50:00 -07:00
{
struct xpc_partition * part = & xpc_partitions [ partid ] ;
struct xpc_channel * ch ;
2008-07-29 22:34:04 -07:00
DBUG_ON ( partid < 0 | | partid > = xp_max_npartitions ) ;
2005-03-23 19:50:00 -07:00
DBUG_ON ( ch_number < 0 | | ch_number > = part - > nchannels ) ;
ch = & part - > channels [ ch_number ] ;
2009-04-13 14:40:19 -07:00
xpc_arch_ops . received_payload ( ch , payload ) ;
2005-03-23 19:50:00 -07:00
2008-07-29 22:34:19 -07:00
/* the call to xpc_msgqueue_ref() was done by xpc_deliver_payload() */
2005-03-23 19:50:00 -07:00
xpc_msgqueue_deref ( ch ) ;
}