original files of m241
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
# Makefile - makefile for Multi-OS
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01d,01oct08,mze adding VSB configuration check before building
|
||||
# 01c,25sep08,ebh Adding in defs.docs reference for future proofing of docs
|
||||
# 01b,18sep08,jlk updated as per code review
|
||||
# 01a,19feb08,bwa written
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the multi-OS library.
|
||||
# If any OBJS are ever defined at this level only build them if
|
||||
#ifdef _WRS_CONFIG_COMPONENT_MIPC
|
||||
#OBJS = xxxx xx x
|
||||
#else
|
||||
#OBJS =
|
||||
#endif
|
||||
#
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
LIB_BASE_NAME=multios_ipc
|
||||
include $(TGT_DIR)/h/make/rules.library
|
||||
|
||||
# documentation specification for APIGEN
|
||||
include $(TGT_DIR)/h/make/config/comps/mipc/defs.docs
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# Makefile - makefile for MIPC and AF_MIPC kernel-space demos
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01b,05feb10,h_w add AF_MIPC kernel-space demos
|
||||
# 01a,03apr09,jlk written
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the MIPC demo
|
||||
#
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
|
||||
LIB_BASE_NAME=multios_ipc
|
||||
|
||||
# Including defs.library to see if _WRS_CONFIG_SMP is defined.
|
||||
# It must be after LIB_BASE_NAME
|
||||
include $(TGT_DIR)/h/make/defs.library
|
||||
|
||||
EXTRA_INCLUDE=-I$(WIND_BASE)/target/h/
|
||||
#EXTRA_DEFINE+=
|
||||
|
||||
ifdef _WRS_CONFIG_COMPONENT_MIPC
|
||||
OBJS= \
|
||||
mipcdemo.o \
|
||||
afmipcdemo.o
|
||||
else
|
||||
OBJS=
|
||||
endif
|
||||
|
||||
include $(TGT_DIR)/h/make/rules.library
|
||||
|
||||
# documentation specification for APIGEN
|
||||
include $(TGT_DIR)/h/make/config/comps/mipc/defs.docs
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
# Makefile - makefile for MIPC shared memory version
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01s,26may11,ebh Add af_mipc_lib.c for APIGEN output
|
||||
# 01r,25apr11,swg Include mipc_sm_show.c for APIGEN, fix WIND00268209
|
||||
# 01q,05feb10,h_w Add mipc_socket.c for AF_MIPC
|
||||
# 01p,24sep09,als Rename mipc_sm_api_events files to mipc_sm_event_pool
|
||||
# 01o,03sep09,als Remove references to more obsolete files
|
||||
# 01n,10aug09,als Stop building obsolete memory map file
|
||||
# 01m,02jul09,als Changes to reflect updated file names
|
||||
# 01l,23jun09,als Deletion of mipc_sm_api_defs.c
|
||||
# 01k,13feb09,ebh Fix typo
|
||||
# 01j,15dec08,apa Added MIPC 2.0 objects.
|
||||
# 01i,10nov08,jlk WIND00143103. Don't include rules.library twice.
|
||||
# 01h,02oct08,mze fix typo
|
||||
# 01g,01oct08,mze adding VSB configuration check
|
||||
# 01f,25sep08,ebh Add in defs.docs reference
|
||||
# 01e,18sep08,jlk Updated as per code review
|
||||
# 01d,04sep08,jlk Removed SMP limitation
|
||||
# 01c,08jul08,jpb Changed SMP conditional.
|
||||
# 01b,02jul08,ebh Change doc file to mipc_lib.c
|
||||
# 01a,19feb08,bwa written
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the Multi-OS IPC
|
||||
# shared-memory implementation.
|
||||
#
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
|
||||
DOC_FILES= af_mipc_lib.c mipc_lib.c mipc_sm_show.c
|
||||
|
||||
LIB_BASE_NAME=multios_ipc
|
||||
include $(TGT_DIR)/h/make/defs.library
|
||||
ifdef _WRS_CONFIG_COMPONENT_MIPC
|
||||
OBJS= \
|
||||
mipc_sm_api.o \
|
||||
mipc_sm_bus.o \
|
||||
mipc_sm_event_pool.o \
|
||||
mipc_sm_event_queue.o \
|
||||
mipc_sm_mem_region.o \
|
||||
mipc_sm_node.o \
|
||||
mipc_sm_port.o \
|
||||
mipc_sm_packet_pool.o \
|
||||
mipc_sm_show.o \
|
||||
mipc_sm_socket.o \
|
||||
mipc_sm_system.o \
|
||||
mipc_sm_vxworks.o \
|
||||
mipc_socket.o
|
||||
else
|
||||
OBJS=
|
||||
endif
|
||||
|
||||
include $(TGT_DIR)/h/make/rules.library
|
||||
|
||||
# documentation specification for APIGEN
|
||||
include $(TGT_DIR)/h/make/config/comps/mipc/defs.docs
|
||||
|
||||
@@ -0,0 +1,440 @@
|
||||
/* af_mipc_lib.c - Library for AF_MIPC socket communication */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01b,05aug11,zhw Add mipc_getstatsbybus() and mipc_clearstatsbybus()
|
||||
01a,24may11,als Initial version
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
The AF_MIPC API allows applications to communicate over MIPC buses using a
|
||||
standard Berkeley socket API, rather than the socket-like mipc_lib API.
|
||||
AF_MIPC provides access to some features not provided by mipc_lib
|
||||
(such as the ability to monitor multiple sockets using select()
|
||||
and to have multiple threads of control access a single socket),
|
||||
but it does not provide support for some specialized mipc_lib features
|
||||
(such as the ability to utilize zero-copy buffers or to communicate at
|
||||
interrupt-level).
|
||||
|
||||
AF_MIPC capabilities are currently available within the VxWorks kernel,
|
||||
VxWorks Real Time Processes (RTPs), and Linux user space processes.
|
||||
|
||||
AF_MIPC sockets belong to the address family 'AF_MIPC' and support
|
||||
the following Berkeley socket APIs:
|
||||
|
||||
\cs
|
||||
accept() listen() shutdown()
|
||||
bind() poll() socket()
|
||||
close() read() write()
|
||||
connect() select() recv()
|
||||
getpeername() send() recvfrom()
|
||||
getsockname() sendmsg() recvmsg()
|
||||
getsockopt() sendto()
|
||||
ioctl() setsockopt()
|
||||
\ce
|
||||
|
||||
These APIs operate conventionally, except as noted in the Wind River
|
||||
MIPC Programmer's Guide; consult that document for additional information.
|
||||
|
||||
Applications running within a VxWorks RTP or a Linux user space process
|
||||
may also utilize AF_MIPC versions of the following mipc_lib APIs:
|
||||
|
||||
\cs
|
||||
mipc_clearstatsbybus() mipc_getbusmaxnodes()
|
||||
mipc_getactivebusesl() mipc_getnamebybus()
|
||||
mipc_getactivenodesl() mipc_getnodebybus()
|
||||
mipc_getbusbyname() mipc_getstatsbybus()
|
||||
\ce
|
||||
|
||||
These APIs can be used in a similar fashion to their mipc_lib API counterparts;
|
||||
however, they do not have identical argument lists and return values.
|
||||
These differences are due to differences in the calling conventions
|
||||
used by kernel and non-kernel applications.
|
||||
|
||||
NOTE: Designers should carefully review the arguments and return values
|
||||
specified for each AF_MIPC API described below to ensure that their application
|
||||
handles them correctly.
|
||||
|
||||
INCLUDE FILES
|
||||
mipc.h
|
||||
|
||||
SEE ALSO
|
||||
\tb Wind River MIPC Programmer's Guide
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* mipc_clearstatsbybus - clears MIPC statistics for a bus
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* int mipc_clearstatsbybus
|
||||
* (
|
||||
* int busnum /@ number of the bus @/
|
||||
* )
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Clears MIPC statistics for the specified bus.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* \is
|
||||
* \i <busnum>
|
||||
* Bus number.
|
||||
* \ie
|
||||
*
|
||||
* NOTE: The statistics are only updated when MIPC is compiled with the
|
||||
* option MIPC_STATS_MODE = 1.
|
||||
*
|
||||
* RETURNS: 0 on success, -1 on failure.
|
||||
*
|
||||
* \is
|
||||
* \i ENETUNREACH
|
||||
* The specified bus is unreachable.
|
||||
* \ie
|
||||
*
|
||||
* ERRNO: N/A
|
||||
*
|
||||
* SEE ALSO: mipc_getstatsbybus()
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* mipc_getactivebusesl - get bitfield of the buses this node can utilize
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* int mipc_getactivebusesl
|
||||
* (
|
||||
* unsigned char * buses, /@ returned bitfield of the active buses @/
|
||||
* size_t buseslen /@ size of the bitfield array in bytes @/
|
||||
* )
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Gets a bitfield of the buses that are active.
|
||||
* Each active bus has its respective bit set to 1 in the returned array;
|
||||
* for example, the least significant bit of the first byte corresponds to bus 0,
|
||||
* while the most significant bit of the second byte corresponds to bus 15.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* \is
|
||||
* \i <buses>
|
||||
* Returned bitfield of the active buses.
|
||||
* \i <buseslen>
|
||||
* Size of the bitfield array in bytes.
|
||||
* \ie
|
||||
*
|
||||
* RETURNS: 0 on success, -1 on failure.
|
||||
*
|
||||
* ERRNO:
|
||||
*
|
||||
* \is
|
||||
* \i EINVAL
|
||||
* The buses parameter is invalid.
|
||||
* \i ENETUNREACH
|
||||
* The MIPC system has not been initialized yet.
|
||||
* \ie
|
||||
*
|
||||
* SEE ALSO:
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* mipc_getactivenodesl - get the bitfield of the active MIPC nodes on a bus
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* int mipc_getactivenodesl
|
||||
* (
|
||||
* int bus, /@ bus number @/
|
||||
* unsigned char * nodes, /@ returned array of the active nodes @/
|
||||
* size_t nodeslen /@ size of the active nodes array in bytes @/
|
||||
* )
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Gets a bitfield of the nodes that are active on a given bus.
|
||||
* Each active node has its respective bit set to 1 in the returned array;
|
||||
* for example, the least significant bit of the first byte corresponds to node 0,
|
||||
* while the most significant bit of the second byte corresponds to node 15.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* \is
|
||||
* \i <bus>
|
||||
* Bus number.
|
||||
* \i <nodes>
|
||||
* Returned array of the active nodes.
|
||||
* \i <nodeslen>
|
||||
* Size of the active nodes array in bytes.
|
||||
* \ie
|
||||
*
|
||||
* RETURNS: 0 on success, -1 on failure.
|
||||
*
|
||||
* ERRNO:
|
||||
*
|
||||
* \is
|
||||
* \i EINVAL
|
||||
* The nodes parameter is invalid.
|
||||
* \i ENETUNREACH
|
||||
* The specified bus is unreachable.
|
||||
* \ie
|
||||
*
|
||||
* SEE ALSO:
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* mipc_getbusbyname - get the number of a bus given its name
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* int mipc_getbusbyname
|
||||
* (
|
||||
* const char * name, /@ name of the bus @/
|
||||
* int * busnum /@ returned bus number @/
|
||||
* )
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Gets the number of a bus given its name.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* \is
|
||||
* \i <name>
|
||||
* Bus name.
|
||||
* \i <busnum>
|
||||
* Returned bus number.
|
||||
* \ie
|
||||
*
|
||||
* RETURNS: 0 on success, -1 on failure.
|
||||
*
|
||||
* ERRNO:
|
||||
*
|
||||
* \is
|
||||
* \i EINVAL
|
||||
* Unknown bus name.
|
||||
* \i ENETUNREACH
|
||||
* The MIPC system has not been initialized yet.
|
||||
* \ie
|
||||
*
|
||||
* SEE ALSO: mipc_getnamebybus()
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* mipc_getbusmaxnodes - get the configured maximum number of nodes on a bus
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* int mipc_getbusmaxnodes
|
||||
* (
|
||||
* int busnum /@ bus number @/
|
||||
* int * nodenum /@ returned maximum number of nodes @/
|
||||
* )
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Gets the configured maximum number of nodes on a specified bus.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* \is
|
||||
* \i <busnum>
|
||||
* Bus number.
|
||||
* \i <nodeid>
|
||||
* Returned maximum number of nodes.
|
||||
* \ie
|
||||
*
|
||||
* RETURNS: 0 on success, -1 on failure.
|
||||
*
|
||||
* ERRNO:
|
||||
*
|
||||
* \is
|
||||
* \i ENETUNREACH
|
||||
* The specified bus is unreachable.
|
||||
* \ie
|
||||
*
|
||||
* SEE ALSO:
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* mipc_getnamebybus - get the name of a MIPC bus given its number
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* int mipc_getnamebybus
|
||||
* (
|
||||
* int busnum, /@ number of the bus @/
|
||||
* char * name, /@ returned param for bus name @/
|
||||
* size_t namelen /@ buffer length of returned bus name @/
|
||||
* )
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Get the name of a MIPC bus given its number.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* \is
|
||||
* \i <busnum>
|
||||
* Bus number.
|
||||
* \i <name>
|
||||
* A pointer to a string buffer for returning the name of the bus.
|
||||
* \i <namelen>
|
||||
* The length of the string buffer for returing the bus name.
|
||||
* \ie
|
||||
*
|
||||
* RETURNS: 0 on success, -1 on failure.
|
||||
*
|
||||
* ERRNO:
|
||||
*
|
||||
* \is
|
||||
* \i EINVAL
|
||||
* The pointer to the return buffer is NULL.
|
||||
* \i ENETUNREACH
|
||||
* The specified bus is unreachable.
|
||||
* \i EOVERFLOW
|
||||
* The length of the string buffer for returing bus name is less than the
|
||||
* maximum length of a MIPC bus name.
|
||||
* \ie
|
||||
*
|
||||
* SEE ALSO: mipc_getbusbyname()
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* mipc_getnodebybus - get the node number of this node on a bus
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* int mipc_getnodebybus
|
||||
* (
|
||||
* int busnum, /@ number of the bus @/
|
||||
* int * nodenum /@ returned number of the node @/
|
||||
* )
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Get the node number of this node on a bus.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* \is
|
||||
* \i <busnum>
|
||||
* Bus number.
|
||||
* \i <nodenum>
|
||||
* Returned node number.
|
||||
* \ie
|
||||
*
|
||||
* RETURNS: 0 on success, -1 on failure.
|
||||
*
|
||||
* ERRNO:
|
||||
*
|
||||
* \is
|
||||
* \i ENETUNREACH
|
||||
* The specified bus is unreachable.
|
||||
* \ie
|
||||
*
|
||||
* SEE ALSO:
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* mipc_getstatsbybus - get MIPC statistics for a bus
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* int mipc_getstatsbybus
|
||||
* (
|
||||
* int busnum, /@ number of the bus @/
|
||||
* struct mipc_stats * buf /@ pointer to buffer receiving the statistics @/
|
||||
* )
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Get MIPC statistics for a bus.
|
||||
*
|
||||
* The definition of the MIPC statistics structre is as follows:
|
||||
* \cs
|
||||
* struct mipc_statistics
|
||||
* {
|
||||
* uint32_t bufs_sent; /@ number of buffers sent @/
|
||||
* uint32_t bufs_rcvd; /@ number of buffers received @/
|
||||
* uint32_t bytes_sent; /@ number of bytes sent @/
|
||||
* uint32_t bytes_rcvd; /@ number of bytes received @/
|
||||
* uint32_t bufs_allocated; /@ number of buffers allocated @/
|
||||
* uint32_t bufs_freed; /@ number of buffers freed @/
|
||||
* uint32_t bufs_cong_wait; /@ buffer congestion (blocking) @/
|
||||
* uint32_t bufs_cong_no_wait; /@ buffer congestion (non-blocking) @/
|
||||
* uint32_t buf_avail_sent; /@ buffer available events sent @/
|
||||
* uint32_t buf_avail_rcvd; /@ buffer available events received @/
|
||||
* uint32_t express_msgs_sent; /@ express messages sent @/
|
||||
* uint32_t express_msgs_rcvd; /@ express messages received @/
|
||||
* uint32_t buffer_not_avail; /@ could not get buffer from packet pool @/
|
||||
* uint32_t event_not_avail; /@ could not get event from event pool @/
|
||||
* uint32_t interrupts_sent; /@ number of interrupts sent @/
|
||||
* uint32_t interrupts_rcvd; /@ number of interrupts received @/
|
||||
* uint32_t interrupts_deferred; /@ invocations of deferred work thread @/
|
||||
* uint32_t sockets_bound; /@ number of sockets bound to bus @/
|
||||
* uint32_t sockets_closed; /@ number of sockets closed after binding to a bus @/
|
||||
* uint32_t socket_rx_queue_err; /@ number of times RX queue was full @/
|
||||
* }
|
||||
* \ce
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* \is
|
||||
* \i <busnum>
|
||||
* Bus number.
|
||||
* \i <buf>
|
||||
* A pointer to buffer receiving the statistics. This must be large enough to
|
||||
* hold the information in a 'mipc_statistics' structure.
|
||||
* \ie
|
||||
*
|
||||
* NOTE: The statistics are only available when MIPC is compiled with the
|
||||
* option MIPC_STATS_MODE = 1.
|
||||
*
|
||||
* RETURNS: 0 on success, -1 on failure.
|
||||
*
|
||||
* \is
|
||||
* \i ENETUNREACH
|
||||
* The specified bus is unreachable.
|
||||
* \ie
|
||||
*
|
||||
* ERRNO: N/A
|
||||
*
|
||||
* SEE ALSO: mipc_clearstatsbybus()
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,110 @@
|
||||
/* mipc_sm_bus.c - MIPC-SM buses */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011, 2013 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011, 2013 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01r,08may13,bbz clear the high impact warning from prevent.pl(WIND00416598)
|
||||
01q,07jan11,jlk Update license header
|
||||
01p,03mar10,als Add support for 64-bit memory addressing
|
||||
01o,29oct09,als Fix minor API issues (WIND00186193)
|
||||
01n,16sep09,als Enhance node restart capability
|
||||
01m,20aug09,als Add node restart support
|
||||
01l,19aug09,als Fix bug in bus initialization code (WIND00177423)
|
||||
01k,07aug09,ebh Remove unused routine and code inspection updates
|
||||
01j,04aug09,als Convert shared memory offsets to use MIPC_OFFSET type
|
||||
01i,21jul09,als Keep max buses info in local memory
|
||||
01h,02jul09,als Eliminate typedef for MipcSmBus
|
||||
01g,02jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01f,12may09,ebh Code review changes
|
||||
01e,30apr09,ebh Ensure that mipc.h is included first
|
||||
01d,27apr09,ebh Add mipc_sm_bus_ptr_valid() for faster lookup of valid buses
|
||||
01c,23mar09,ebh Fix portability issues in code
|
||||
01b,24feb09,ebh Change setting of lastNode on a bus
|
||||
01a,25nov08,apa Initial version.
|
||||
*/
|
||||
|
||||
#include "mipc_sm_core.h"
|
||||
#include "mipc_sm_system.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_bus_ptr - return pointer to a bus given its ID
|
||||
*/
|
||||
struct mipc_sm_bus *mipc_sm_bus_ptr(uint16_t busId)
|
||||
{
|
||||
if (mipc_sm_system_init_check() &&
|
||||
(busId < mipc_sm_max_buses) &&
|
||||
mipcSmLocalBusInfo[busId].activeOnBus) {
|
||||
return mipc_sm_bus_ptr_valid(busId);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_bus_init - initialize a MIPC-SM bus structure
|
||||
*/
|
||||
int mipc_sm_bus_init(struct mipc_sm_bus_config *config)
|
||||
{
|
||||
struct mipc_sm_bus *bus;
|
||||
struct mipc_sm_node *node;
|
||||
MIPC_OFFSET nodesOffset;
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
/* Allocate node array for bus */
|
||||
|
||||
rc = mipc_sm_mem_region_alloc(&mipcSmSystem->memPool,
|
||||
(MIPC_MEMSIZE)(config->maxNodes * sizeof(struct mipc_sm_node)),
|
||||
&nodesOffset);
|
||||
|
||||
if (rc != MIPC_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Initialize fields of SM bus */
|
||||
|
||||
bus = mipcSmBuses + config->number;
|
||||
strncpy(bus->name, config->name, MIPC_BUS_NAME_MAX_LEN-1);
|
||||
bus->maxNodes = MULTIOS_hton16(config->maxNodes);
|
||||
bus->nodesOffset = MULTIOS_hton32(nodesOffset);
|
||||
|
||||
/* Mark all node structures for bus as uninitialized */
|
||||
|
||||
node = (struct mipc_sm_node *)mipc_offset2addr(nodesOffset);
|
||||
|
||||
for (i = 0; i < config->maxNodes; i++) {
|
||||
node[i].state = 0;
|
||||
}
|
||||
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/* mipc_sm_bus.h - MIPC-SM bus */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01s,07jan11,jlk Update license header
|
||||
01r,03mar10,als Add support for 64-bit memory addressing
|
||||
01q,29oct09,als Fix minor API issues (WIND00186193)
|
||||
01p,02sep09,als Remove obsolete function declaration
|
||||
01o,20aug09,als Add node restart support
|
||||
01n,19aug09,als Fix bug in bus initialization code (WIND00177423)
|
||||
01m,07aug09,ebh Remove unused routine and code inspection updates
|
||||
01l,04aug09,als Convert shared memory offsets to use MIPC_OFFSET type
|
||||
01k,02jul09,als Eliminate typedef for MipcSmBus
|
||||
01j,02jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01i,04may09,ebh Try to increase performance
|
||||
01h,24apr09,ebh Remove unused variable
|
||||
01g,22apr09,ebh Remove unused variable and condense routines
|
||||
01f,21apr09,ebh Make sure all nodes are checked for heartbeats
|
||||
01e,24mar09,ebh Make inlines static and use MULTIOS_INLINE
|
||||
01d,17mar09,ebh Add information storage in local memory about node on buses
|
||||
01c,24feb09,ebh Ensure single access to the lastNode parameter
|
||||
01b,19feb09,ebh Adjust usage of the MIPC_SO_MTU information to validate on
|
||||
bind
|
||||
01a,25nov08,apa Initial version.
|
||||
*/
|
||||
|
||||
#ifndef __INC_mipc_sm_bus_h
|
||||
#define __INC_mipc_sm_bus_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct mipc_sm_bus /* structure resides in SM */
|
||||
{
|
||||
MIPC_OFFSET nodesOffset; /* offset to SM node structs */
|
||||
uint16_t maxNodes; /* maximum nodes on this bus */
|
||||
char name[MIPC_BUS_NAME_MAX_LEN]; /* name of bus */
|
||||
};
|
||||
|
||||
struct mipc_sm_bus *mipc_sm_bus_ptr(uint16_t busId);
|
||||
int mipc_sm_bus_init(struct mipc_sm_bus_config *config);
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_bus_ptr_valid - return pointer to a known valid bus
|
||||
*
|
||||
* Caller knows that the bus exists and does not want to do extra checks
|
||||
* to validate things that are known to be valid.
|
||||
*/
|
||||
static MULTIOS_INLINE struct mipc_sm_bus *mipc_sm_bus_ptr_valid(uint16_t busId)
|
||||
{
|
||||
return &mipcSmBuses[busId];
|
||||
}
|
||||
|
||||
static MULTIOS_INLINE uint16_t mipc_sm_bus_get_max_nodes(struct mipc_sm_bus *bus)
|
||||
{
|
||||
return MULTIOS_ntoh16(bus->maxNodes);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INC_mipc_sm_bus_h */
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
/* mipc_sm_core.h - main include file for MIPC-SM source files */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2009-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2009-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01y,07jan11,jlk Update license header
|
||||
01x,26aug10,jlk Make sure #ifdef __cplusplus starts after #includes
|
||||
01w,04mar10,als Add support for 64-bit memory addressing
|
||||
01v,29oct09,als Fix minor API issues (WIND00186193)
|
||||
01u,11sep09,als Enhance node restart capability
|
||||
01t,03sep09,als Display actual number of allocated buffers in show commands;
|
||||
remove obsolete semaphore
|
||||
01s,26aug09,als Cleanup issues with flow control rework
|
||||
01r,24aug09,bwa Add mipc_cpu_id global variable.
|
||||
01q,20aug09,als Add node restart support
|
||||
01p,14aug09,als Revise internals of event-based code
|
||||
01o,10aug09,als Eliminate unnecessary operations in receive datapath
|
||||
01n,07aug09,ebh Code inspection updates
|
||||
01m,05aug09,ebh Track number of sockets with TXBUFAVAIL callbacks registered
|
||||
01l,05aug09,als Move port's socket id out of shared memory
|
||||
01k,04aug09,als Convert shared memory offsets to use MIPC_OFFSET type
|
||||
01j,29jul09,als Add support for per-bus statistics collection
|
||||
01j,28jul09,ebh Update comments as per code inspection
|
||||
01i,28jul09,als Add/revise APIs to reflect feedback from HLD review
|
||||
01h,27jul09,als Event queue rework
|
||||
01g,24jul09,jlk Event Q re-work.
|
||||
01f,23jul09,als Move port allocation semaphore from SM to local memory
|
||||
01e,21jul09,als Keep max buses info in local memory
|
||||
01d,02jul09,als Use embedded semaphore in local bus info
|
||||
01c,25jun09,als Rework memory region code to fix WIND00167982
|
||||
01b,18jun09,als Enable selective use of MIPC debugging statements
|
||||
01a,09jun09,als Initial version.
|
||||
*/
|
||||
|
||||
#ifndef __INCmipc_sm_core_h
|
||||
#define __INCmipc_sm_core_h
|
||||
|
||||
#include <multios_ipc/mipc_sm_adapt.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* MIPC debug routines */
|
||||
|
||||
#define MIPC_DEBUG_LEVEL 0 /* redefine to non-zero where needed */
|
||||
/* (allows selective use of MIPCDBG/MIPCIDBG) */
|
||||
|
||||
/* can supply any number of items for "arg" */
|
||||
#define MIPCDBG(fmt, arg...) \
|
||||
do { if (MIPC_DEBUG_LEVEL) MULTIOS_PRINT(fmt, ##arg); } while (0)
|
||||
|
||||
/* must supply exactly 6 items for "arg", due to VxWorks logMsg() limitation */
|
||||
#define MIPCIDBG(fmt, arg...) \
|
||||
do { if (MIPC_DEBUG_LEVEL) MULTIOS_IPRINT(fmt, ##arg); } while (0)
|
||||
|
||||
/* MIPC reset request values */
|
||||
|
||||
#define MIPC_RESET_NONE 0
|
||||
#define MIPC_RESET_NODE 1
|
||||
#define MIPC_RESET_SYSTEM 2
|
||||
#define MIPC_RESET_IN_PROGRESS -1
|
||||
|
||||
/* MIPC reset log values */
|
||||
|
||||
#define MIPC_RESET_LOG_EMPTY 0x00
|
||||
#define MIPC_RESET_LOG_NODE 0x01
|
||||
#define MIPC_RESET_LOG_SYSTEM 0x02
|
||||
|
||||
/* MIPC configuration settings (in local memory; during initialization only) */
|
||||
|
||||
struct mipc_sm_sys_config
|
||||
{
|
||||
uint16_t nodeId; /* node's ID (on all buses) */
|
||||
uint16_t initMode; /* node's SM init permissions */
|
||||
uint16_t numBuses; /* # buses configured for node */
|
||||
uint16_t maxBuses; /* node's highest bus number + 1 */
|
||||
uint32_t maxSockets; /* node's maximum number of sockets */
|
||||
void *operRegionBaseAddr; /* base address of the operation region */
|
||||
MIPC_MEMSIZE operRegionSize; /* size in bytes of the operation region */
|
||||
uint16_t heartbeatPeriod; /* node's heartbeat period (in ms) */
|
||||
};
|
||||
|
||||
struct mipc_sm_bus_config
|
||||
{
|
||||
char name[MIPC_BUS_NAME_MAX_LEN]; /* name of this bus */
|
||||
uint16_t number; /* number of this bus */
|
||||
uint16_t maxNodes; /* max nodes on this bus */
|
||||
};
|
||||
|
||||
struct mipc_sm_node_config
|
||||
{
|
||||
int activeOnBus; /* set if node is active on the bus */
|
||||
int16_t qos; /* quality of service of the bus */
|
||||
uint16_t intId; /* interrupt number for the bus */
|
||||
uint16_t maxPorts; /* maximum ports */
|
||||
int16_t nEvents; /* number of basic events */
|
||||
uint32_t nBuffers; /* number of packet pool buffers */
|
||||
uint32_t mtu; /* size of packet pool buffers */
|
||||
uint16_t heartbeatPeriod; /* heartbeat period in milliseconds */
|
||||
};
|
||||
|
||||
/* MIPC system info global variables (in local memory) */
|
||||
|
||||
struct mipc_sm_local_peer_info { /* One entry per peer node on bus */
|
||||
MULTIOS_ATOMIC_VAL state;
|
||||
uint8_t is_up;
|
||||
};
|
||||
|
||||
struct mipc_sm_local_port_info { /* One entry per own port on bus */
|
||||
struct mipc_sm_socket *socket; /* Ptr to socket using port */
|
||||
MULTIOS_ATOMIC usage; /* bitmask indicating active operations */
|
||||
MULTIOS_SEM shutdownSem; /* used in socket shutdown code */
|
||||
uint32_t numBuffers; /* # buffers allocated to port */
|
||||
int allocated; /* Port has been allocated */
|
||||
};
|
||||
|
||||
struct mipc_sm_local_bus_info { /* One entry per bus in system */
|
||||
int activeOnBus; /* Is own node using bus? */
|
||||
struct mipc_sm_node *ownNode; /* Ptr to own node in SM */
|
||||
struct mipc_sm_port *ownPorts; /* Ptr to own ports in SM */
|
||||
uint16_t ownMaxPorts; /* Number of own ports in SM */
|
||||
uint16_t maxNodes; /* Maximum nodes on this bus */
|
||||
MULTIOS_SEM portAllocLock; /* Mutex for port allocation */
|
||||
struct mipc_sm_local_port_info *port_info; /* Ptr to own port info in LM */
|
||||
struct mipc_sm_local_peer_info *peer_info; /* Ptr to peer node info in LM */
|
||||
struct mipc_sm_socket *dummy_socket; /* Ptr to dummy socket for bus */
|
||||
MULTIOS_TIMER_ID heartbeatTimerId; /* Node heartbeating timer */
|
||||
int memAuditCountdown; /* Time until next memory audit */
|
||||
MULTIOS_ATOMIC stats[MIPC_NUM_STATS]; /* Bus statistics array */
|
||||
};
|
||||
|
||||
extern int mipc_sm_initialized; /* MIPC initialization flag */
|
||||
extern uint16_t mipc_cpu_id; /* CPU's ID (on all buses) */
|
||||
extern uint16_t mipc_node_id; /* Node's ID (on all buses) */
|
||||
extern uint16_t mipc_sm_max_buses; /* Maximum # of SM buses */
|
||||
extern uint16_t mipc_bus_default; /* Node's default bus number */
|
||||
extern struct mipc_sm_local_bus_info *mipcSmLocalBusInfo; /* Info on buses */
|
||||
extern struct mipc_sm_port dummy_port; /* Node's dummy port */
|
||||
extern uint8_t mipc_sm_sys_signature; /* MIPC system signature */
|
||||
|
||||
extern struct mipc_sm_system *mipcSmSystem; /* MIPC system info in SM */
|
||||
extern struct mipc_sm_bus *mipcSmBuses; /* MIPC bus array in SM */
|
||||
|
||||
extern int mipc_reset_state; /* Used in robustness testing */
|
||||
extern int mipc_reset_log; /* Used in robustness testing */
|
||||
|
||||
/* pointer/offset conversion routines that do network byte order conversion */
|
||||
|
||||
static MULTIOS_INLINE MIPC_OFFSET mipc_addr2offset_hton(void *address)
|
||||
{
|
||||
MIPC_OFFSET offset = mipc_addr2offset(address);
|
||||
|
||||
return MULTIOS_hton32(offset);
|
||||
}
|
||||
|
||||
static MULTIOS_INLINE void *mipc_offset2addr_ntoh(MIPC_OFFSET offset_nbo)
|
||||
{
|
||||
MIPC_OFFSET offset = MULTIOS_ntoh32(offset_nbo);
|
||||
|
||||
return mipc_offset2addr(offset);
|
||||
}
|
||||
|
||||
/* test if argument is a power of two */
|
||||
|
||||
static MULTIOS_INLINE int mipc_pwr2_check(uint32_t x)
|
||||
{
|
||||
return ((x != 0) && ((x & (x - 1)) == 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* round up a value to the nearest power of two
|
||||
*
|
||||
* This algorithm handles values less than 0x80000000; an input of 0 returns 0.
|
||||
* First the value is decremented, then the lower bits are systematically filled
|
||||
* with ones; adding one to the result gives the next highest power of two.
|
||||
* (Note: These 12 operations can be faster than a non-deterministic loop.)
|
||||
*/
|
||||
|
||||
static MULTIOS_INLINE uint32_t mipc_pwr2_roundup(uint32_t x)
|
||||
{
|
||||
x--; /* example: 1050 becomes 1049 (010000011001) */
|
||||
x |= (x >> 1); /* 010000011001 -> 011000011101 */
|
||||
x |= (x >> 2); /* 011000011101 -> 011110011111 */
|
||||
x |= (x >> 4); /* 011110011111 -> 011111111111 */
|
||||
x |= (x >> 8); /* 011111111111 -> 011111111111 */
|
||||
x |= (x >> 16); /* 011111111111 -> 011111111111 */
|
||||
return (x+1); /* 100000000000 */
|
||||
}
|
||||
|
||||
/* return pointer to statistics area for specified bus */
|
||||
|
||||
#if (MIPC_STATS_MODE > 0)
|
||||
|
||||
static MULTIOS_INLINE MULTIOS_ATOMIC *mipc_sm_stats_ptr(uint16_t busId) {
|
||||
return mipcSmLocalBusInfo[busId].stats;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INC_mipc_sm_core_h */
|
||||
|
||||
@@ -0,0 +1,302 @@
|
||||
/* mipc_sm_event_pool.c - MIPC-SM event pools */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
02w,07jan11,jlk Update license header
|
||||
02v,03mar10,als Add support for 64-bit memory addressing
|
||||
02u,28sep09,als Differentiate invalid event user from event on node's free list
|
||||
02t,24sep09,als Renamed from mipc_sm_api_events.c to mipc_sm_event_pool.c
|
||||
02s,23sep09,bwa add connection signature
|
||||
02r,17sep09,als Enhance node restart capability
|
||||
02q,26aug09,als Cleanup issues with flow control rework
|
||||
02p,25aug09,jlk WIND00178668 - MIPC flow control changes.
|
||||
02o,24aug09,als Fix up issues with asynchronous connect capability
|
||||
02n,20aug09,als Add node restart support
|
||||
02m,18aug09,jlk WIND00177194 - Remove deferred semaphore code.
|
||||
02l,14aug09,als Revise internals of event-based code
|
||||
02k,11aug09,als Revise event exchange code to improve robustness
|
||||
02j,10aug09,als Eliminate unnecessary operations in receive datapath
|
||||
02i,07aug09,ebh Code inspection updates
|
||||
02h,05aug09,ebh Allow TXBUFAVAIL callbacks on non-pending sockets
|
||||
02g,05aug09,als Move port's socket id out of shared memory
|
||||
02f,04aug09,als Convert shared memory offsets to use MIPC_OFFSET type
|
||||
02e,04aug09,als Remove unneeded argument from mipc_sm_api_buf_decr_free
|
||||
02d,29jul09,als Add support for per-bus statistics collection
|
||||
02c,27jul09,als Event queue rework
|
||||
02b,24jul09,jlk Event Q rework.
|
||||
02a,21jul09,als Keep max buses info in local memory
|
||||
01z,03jul09,h_w Fix WIND00166506 - avoid re-using sockets and ports have
|
||||
unreleased resources
|
||||
01y,02jul09,als Changes to reflect updated file names
|
||||
01x,02jul09,als Use embedded semaphore in local bus info
|
||||
01w,16jun09,ebh Code review changes
|
||||
01v,16jun09,als Elimination of obsolete files
|
||||
01u,13jun09,ebh Changes from performance review
|
||||
01t,03jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01v,03jun09,ebh Add support for a callback on a listening socket for incoming
|
||||
connect request
|
||||
01u,03jun09,h_w Fix WIND00166396 - embed semaphores into MipcSmSocket.
|
||||
01t,02jun09,zhw Add busId for mipc_sm_notify_node().
|
||||
01s,01jun09,als Revise configuration based on MIPC 2.0 HLD feedback
|
||||
01r,30may09,ebh A faster method to compute a set bit in processing RX events
|
||||
01q,29may09,ebh Speed up the process rx events routine
|
||||
01p,25may09,ebh Code Inspection Modifications
|
||||
01o,01may09,ebh Remove unused code
|
||||
01n,30apr09,ebh Ensure that mipc.h is included first
|
||||
01m,23apr09,ebh Adjust the TX buffer per bus usage
|
||||
01l,22apr09,ebh Add support for an ISR callable task to do deferred semGives
|
||||
01k,21apr09,ebh Separate out USERHANDLE from the socket structure
|
||||
01j,26mar09,ebh Fix assignment of grantedMyBufs in _cmd_txbufavail
|
||||
01i,24mar09,ebh Make inlines static and use MULTIOS_INLINE
|
||||
01h,24mar09,ebh Fix portability issues in code
|
||||
01g,24mar09,ebh Fix portability issues in code
|
||||
01f,23mar09,ebh Update "fix me" comments
|
||||
01e,16mar09,ebh Track number of buffers outstanding on a socket to prevent
|
||||
starvation
|
||||
01d,10mar09,ebh Update shutdown/close ordering
|
||||
01c,24feb09,ebh Make sure that an interrupt is sent even when an event cannot
|
||||
be queued after we incremented the trigger value
|
||||
01b,13feb09,ebh Update statistics
|
||||
01a,25nov08,apa Initial version.
|
||||
*/
|
||||
|
||||
#include "mipc_sm_core.h"
|
||||
#include "mipc_sm_event_pool.h"
|
||||
#include "mipc_sm_event_queue.h"
|
||||
#include "mipc_sm_socket.h"
|
||||
#include "mipc_sm_system.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_event_pool_init - Initialize a pool of events.
|
||||
*/
|
||||
int mipc_sm_event_pool_init(MipcSmEventPool *pool,
|
||||
uint16_t numEvents, uint16_t eventSize)
|
||||
{
|
||||
MIPC_OFFSET eventsOffset;
|
||||
MIPC_OFFSET poolOffsetNBO;
|
||||
MipcSmEvent *event;
|
||||
uint16_t eventIndex;
|
||||
uint16_t ownNodeIdNBO;
|
||||
int rc;
|
||||
|
||||
/* Allocate storage for event pool array */
|
||||
|
||||
eventSize = (uint16_t)ALIGN_UP((MIPC_OFFSET)eventSize);
|
||||
rc = mipc_sm_mem_region_alloc(&mipcSmSystem->memPool,
|
||||
(MIPC_MEMSIZE)(numEvents * eventSize),
|
||||
&eventsOffset);
|
||||
if (rc != MIPC_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Initialize event pool array; put all events in free list */
|
||||
|
||||
event = (MipcSmEvent *)mipc_offset2addr(eventsOffset);
|
||||
poolOffsetNBO = mipc_addr2offset_hton(pool);
|
||||
ownNodeIdNBO = MULTIOS_hton16(mipc_node_id);
|
||||
for (eventIndex = 0; eventIndex < numEvents; ) {
|
||||
event->poolOffset = poolOffsetNBO;
|
||||
event->ownIndex = MULTIOS_hton16(eventIndex);
|
||||
event->homeNode = ownNodeIdNBO;
|
||||
event->userNodeInfo = EVENT_FREELIST_USER_INFO;
|
||||
/* leave control/srcPort/srcPortSig/destPort fields unset */
|
||||
eventIndex++;
|
||||
event->nextFreeIndex = MULTIOS_hton16(eventIndex);
|
||||
event = (MipcSmEvent *)((char *)event + eventSize);
|
||||
}
|
||||
event = (MipcSmEvent *)((char *)event - eventSize);
|
||||
event->nextFreeIndex = MULTIOS_hton16(EVENT_INDEX_INVALID);
|
||||
|
||||
/* Initialize event pool structure */
|
||||
|
||||
pool->numEvents = MULTIOS_hton16(numEvents);
|
||||
pool->eventSize = MULTIOS_hton16(eventSize);
|
||||
pool->eventsOffset = MULTIOS_hton32(eventsOffset);
|
||||
MULTIOS_ATOMIC_SET(&pool->freeListState, 0);
|
||||
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_event_alloc - Allocate an event from a pool
|
||||
*/
|
||||
MipcSmEvent *mipc_sm_event_alloc(MipcSmEventPool *pool)
|
||||
{
|
||||
MULTIOS_ATOMIC_VAL origListState;
|
||||
MULTIOS_ATOMIC_VAL newListState;
|
||||
MipcSmEvent *eventsArray;
|
||||
MipcSmEvent *event;
|
||||
uint32_t headEventIndex;
|
||||
|
||||
eventsArray = (MipcSmEvent *)mipc_offset2addr_ntoh(pool->eventsOffset);
|
||||
|
||||
do {
|
||||
origListState = MULTIOS_ATOMIC_GET(&pool->freeListState);
|
||||
|
||||
headEventIndex = origListState & EVENT_INDEX_MASK;
|
||||
if (headEventIndex == EVENT_INDEX_INVALID) {
|
||||
/* No more free events */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
event = (MipcSmEvent *)((char *)eventsArray +
|
||||
headEventIndex * MULTIOS_ntoh16(pool->eventSize));
|
||||
newListState = origListState & ~EVENT_INDEX_MASK;
|
||||
newListState |= MULTIOS_ntoh16(event->nextFreeIndex);
|
||||
newListState += (1 << EVENT_INDEX_BITS);
|
||||
/* Don't need barrier here since only pool's state is changed */
|
||||
/* MULTIOS_MEM_BARRIER(); */
|
||||
} while (!MULTIOS_ATOMIC_CAS(&pool->freeListState,
|
||||
origListState, newListState));
|
||||
return event;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_event_free - Return an event to its pool
|
||||
*/
|
||||
void mipc_sm_event_free(MipcSmEvent *event)
|
||||
{
|
||||
MipcSmEventPool *pool;
|
||||
MULTIOS_ATOMIC_VAL origListState;
|
||||
MULTIOS_ATOMIC_VAL newListState;
|
||||
uint16_t headEventIndex;
|
||||
|
||||
event->userNodeInfo = EVENT_FREELIST_USER_INFO;
|
||||
pool = mipc_offset2addr_ntoh(event->poolOffset);
|
||||
|
||||
do {
|
||||
origListState = MULTIOS_ATOMIC_GET(&pool->freeListState);
|
||||
headEventIndex = (uint16_t)(origListState & EVENT_INDEX_MASK);
|
||||
event->nextFreeIndex = MULTIOS_hton16(headEventIndex);
|
||||
newListState = origListState & ~EVENT_INDEX_MASK;
|
||||
newListState |= MULTIOS_ntoh16(event->ownIndex);
|
||||
newListState += (1 << EVENT_INDEX_BITS);
|
||||
/* Ensure event's link is written before changing pool state */
|
||||
MULTIOS_MEM_BARRIER();
|
||||
} while (!MULTIOS_ATOMIC_CAS(&pool->freeListState,
|
||||
origListState, newListState));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_basic_event_alloc - Allocate a basic event from a socket's event pool
|
||||
*/
|
||||
MipcSmBasicEvent *mipc_sm_basic_event_alloc(MipcSmSocket *theSocket,
|
||||
uint32_t connectSig)
|
||||
{
|
||||
MipcSmEvent *event;
|
||||
uint32_t srcPortSig;
|
||||
|
||||
event = mipc_sm_event_alloc(&theSocket->nodeptr->eventPool);
|
||||
if (event) {
|
||||
event->userNodeInfo = theSocket->nodeptr->state;
|
||||
event->srcPort = MULTIOS_hton16(theSocket->addr.portNum);
|
||||
srcPortSig =
|
||||
(uint32_t)MULTIOS_ATOMIC_GET(&theSocket->port->state) &
|
||||
PORT_SIG_MASK;
|
||||
event->srcPortSig = MULTIOS_hton32(srcPortSig);
|
||||
event->connectSig = MULTIOS_hton32(connectSig);
|
||||
} else {
|
||||
MIPC_STATS_ADD(theSocket->statsPtr,
|
||||
MIPC_STATS_EVENT_NOT_AVAIL, 1);
|
||||
}
|
||||
return (MipcSmBasicEvent *)event;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_basic_event_send - Allocate and send a basic event
|
||||
*/
|
||||
int mipc_sm_basic_event_send(MipcSmSocket *theSocket, uint32_t connectSig,
|
||||
uint16_t destNode, uint16_t destPort,
|
||||
uint8_t cmd, uint64_t data)
|
||||
{
|
||||
struct mipc_sockaddr to;
|
||||
MipcSmBasicEvent *event;
|
||||
int rc;
|
||||
|
||||
event = mipc_sm_basic_event_alloc(theSocket, connectSig);
|
||||
if (!event) {
|
||||
return -MIPC_ENOMEM;
|
||||
}
|
||||
|
||||
to.busNum = theSocket->addr.busNum;
|
||||
to.nodeNum = destNode;
|
||||
to.portNum = destPort;
|
||||
event->data = MULTIOS_hton64(data);
|
||||
|
||||
rc = mipc_sm_event_send((MipcSmEvent *)event, &to, cmd);
|
||||
if (rc) {
|
||||
mipc_sm_basic_event_free(event);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void mipc_sm_event_pool_dump(int busId, int nodeId)
|
||||
{
|
||||
struct mipc_sm_node *node;
|
||||
MipcSmEventPool *evtPool;
|
||||
uint32_t *list;
|
||||
int i;
|
||||
MipcSmEvent *evt;
|
||||
MipcSmPacketPool *packPool;
|
||||
MipcSmPacketDesc *buf;
|
||||
|
||||
node = mipc_sm_node_ptr_valid(busId, nodeId);
|
||||
evtPool = &node->evtPool;
|
||||
|
||||
list = mipc_offset2addr_ntoh(evtPool->freeEvtIndexesOffset);
|
||||
|
||||
MIPC_PRINT("Event evtPool:\n");
|
||||
|
||||
evt = mipc_offset2addr_ntoh(evtPool->startOffset);
|
||||
|
||||
|
||||
for (i = 0; i < evtPool->nEvents; i++) {
|
||||
MIPC_PRINT("%d: %d: %p\n", i, list[i], evt+i);
|
||||
}
|
||||
|
||||
MIPC_PRINT("Events In Buffers:\n");
|
||||
|
||||
packPool = &node->packetPool;
|
||||
list = mipc_offset2addr_ntoh(packPool->freeBufIndexesOffset);
|
||||
buf = mipc_offset2addr_ntoh(packPool->bufferDescsOffset);
|
||||
|
||||
for (i = 0; i < packPool->nBuffers; i++) {
|
||||
MIPC_PRINT("%d: %d: %p\n", i, list[i], &buf->evt);
|
||||
buf++;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
/* mipc_sm_event_pool.h - MIPC-SM event pools */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01o,15dec11,swg Add a padding member for structure MipcSmBasicEvent
|
||||
(to fix WIND00320514)
|
||||
01n,07jan11,jlk Update license header
|
||||
01m,30mar10,als Initial changes in support of 64-bit memory addressing
|
||||
01l,28sep09,als Differentiate invalid event user from event on node's free list
|
||||
01k,24sep09,als Renamed from mipc_sm_api_events.h to mipc_sm_event_pool.h
|
||||
01j,23sep09,bwa add connection signature
|
||||
01i,17sep09,als Enhance node restart capability
|
||||
01h,02sep09,als Continue flow control rework
|
||||
01g,14aug09,als Revise internals of event-based code
|
||||
01f,07aug09,ebh Code inspection updates
|
||||
01e,24jul09,jlk Event Q rework.
|
||||
01d,02jul09,als Changes to reflect updated file names
|
||||
01c,11may09,ebh Changes from code inspections
|
||||
01b,12mar09,ebh Update function call name for consistency
|
||||
01a,25nov08,apa Initial version.
|
||||
*/
|
||||
|
||||
#ifndef __INC_mipc_sm_event_pool_h
|
||||
#define __INC_mipc_sm_event_pool_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* State indicator for an event pool's free buffer list is divided into 2 parts:
|
||||
*
|
||||
* - low order bits record array index of first free event
|
||||
* - upper bits record # of times free list has been changed
|
||||
* (either by event allocation or event freeing)
|
||||
*
|
||||
* By keeping both pieces of info in a single atomic variable, it is possible
|
||||
* for multiple threads to allocate or free items in a LIFO manner without
|
||||
* having to place a lock on the free list.
|
||||
*/
|
||||
|
||||
#define EVENT_INDEX_BITS 16
|
||||
#define EVENT_INDEX_MASK ((1U << EVENT_INDEX_BITS) - 1U)
|
||||
#define EVENT_INDEX_INVALID EVENT_INDEX_MASK
|
||||
|
||||
/*
|
||||
* Special event user indicators
|
||||
* - used when event/packet is on free list of home node's event/packet pool
|
||||
* or when it is in limbo because it could not be returned there
|
||||
* - are "illegal" because a node's state/signature can never be all 0s or 1s
|
||||
* - can ignore endianness when assigning these values or comparing to them
|
||||
*/
|
||||
|
||||
#define EVENT_INVALID_USER_INFO 0x00000000
|
||||
#define EVENT_FREELIST_USER_INFO 0xFFFFFFFF
|
||||
|
||||
typedef struct mipc_sm_event
|
||||
{
|
||||
MIPC_OFFSET poolOffset; /* offset of event's pool */
|
||||
MULTIOS_ATOMIC nextOffset; /* offset of next event in event queue */
|
||||
uint16_t ownIndex; /* event's index in event pool array */
|
||||
uint16_t nextFreeIndex; /* link to next event in free list */
|
||||
uint32_t control; /* event's command info */
|
||||
uint16_t homeNode; /* event owner (node id) */
|
||||
uint16_t srcPort; /* port that sent the event */
|
||||
uint32_t srcPortSig; /* signature of port that sent event */
|
||||
uint32_t userNodeInfo; /* event user info (node state) */
|
||||
uint16_t destPort; /* port that event was sent to */
|
||||
uint32_t connectSig; /* conn signature, explained below */
|
||||
} MipcSmEvent;
|
||||
|
||||
/* The connection signature is a 32-bit number that has different meanings
|
||||
* depending if used with a connection-oriented or connection-less socket.
|
||||
*
|
||||
* This signature is used to validate incoming packets and events on a
|
||||
* connection-oriented socket or a connection-less socket that has performed
|
||||
* a mipc_connect() operation.
|
||||
*
|
||||
* It is used along with the connectSig, peerConnectSig and sigCheckMask in
|
||||
* the socket structure. See mipc_sm_socket.h for more details.
|
||||
*/
|
||||
|
||||
typedef struct mipc_sm_event_pool
|
||||
{
|
||||
MULTIOS_ATOMIC freeListState; /* free list state indicator */
|
||||
MIPC_OFFSET eventsOffset; /* offset to array of events */
|
||||
uint16_t numEvents; /* number of events in pool */
|
||||
uint16_t eventSize; /* size of events in pool */
|
||||
} MipcSmEventPool;
|
||||
|
||||
|
||||
typedef struct mipc_sm_basic_event
|
||||
{
|
||||
MipcSmEvent evt; /* generic event -- MUST BE FIRST! */
|
||||
uint32_t padding; /* padding data to keep same offset
|
||||
of member 'data' in this structure
|
||||
between 32-bit OS and 64-bit OS */
|
||||
uint64_t data; /* data field for event */
|
||||
} MipcSmBasicEvent;
|
||||
|
||||
|
||||
/*
|
||||
* API's for manipulating a generic event pool
|
||||
* (i.e. pool of basic events or pool of packets)
|
||||
*/
|
||||
|
||||
int mipc_sm_event_pool_init(MipcSmEventPool *pool,
|
||||
uint16_t numEvents, uint16_t eventSize);
|
||||
|
||||
MipcSmEvent *mipc_sm_event_alloc(MipcSmEventPool *pool);
|
||||
void mipc_sm_event_free(MipcSmEvent *event);
|
||||
|
||||
/* indicate if event pool has a free item */
|
||||
static MULTIOS_INLINE int mipc_sm_event_avail(MipcSmEventPool *pool)
|
||||
{
|
||||
return (MULTIOS_ATOMIC_GET(&pool->freeListState) & EVENT_INDEX_MASK) !=
|
||||
EVENT_INDEX_INVALID;
|
||||
}
|
||||
|
||||
/*
|
||||
* API's for manipulating a socket's basic event pool
|
||||
* (note: this pool is simply the node's event pool)
|
||||
*/
|
||||
|
||||
MipcSmBasicEvent *mipc_sm_basic_event_alloc(struct mipc_sm_socket *theSocket,
|
||||
uint32_t connectSig);
|
||||
|
||||
static MULTIOS_INLINE void mipc_sm_basic_event_free(MipcSmBasicEvent *event)
|
||||
{
|
||||
mipc_sm_event_free((MipcSmEvent *)event);
|
||||
}
|
||||
|
||||
int mipc_sm_basic_event_send(struct mipc_sm_socket *theSocket,
|
||||
uint32_t connectSig,
|
||||
uint16_t destNode,
|
||||
uint16_t destPort,
|
||||
uint8_t cmd,
|
||||
uint64_t data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INC_mipc_sm_event_pool_h */
|
||||
|
||||
@@ -0,0 +1,710 @@
|
||||
/* mipc_sm_event_queue.c - MIPC-SM event queues */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
02a,16jun11,zhw Fix bug of buffer reclaiming (WIND00278985)
|
||||
01z,01feb11,ebh don't update queue state if couldn't notify node
|
||||
01y,07jan11,jlk Update license header
|
||||
01x,03mar10,als Add support for 64-bit memory addressing
|
||||
01w,27sep09,als Fix bugs in receive routines (WIND00183445, WIND00183399)
|
||||
01v,24sep09,als Rename mipc_sm_api_events files to mipc_sm_event_pool
|
||||
01u,23sep09,bwa add connection signature
|
||||
01t,17sep09,als Enhance node restart capability
|
||||
01s,11sep09,bwa replace sems by sync objects given only when requested
|
||||
01r,04sep09,als Enhance event enqueuing to better suppress unnecessary
|
||||
interrupts
|
||||
01q,26aug09,als Cleanup issues with flow control rework
|
||||
01p,26aug09,jlk Missing memory barriers. Assigned of port signature in event
|
||||
not done atomically.
|
||||
01o,25aug09,jlk WIND00178668 - MIPC flow control changes.
|
||||
01n,14aug09,als Revise internals of event-based code
|
||||
01m,10aug09,ebh Code inspection updates
|
||||
01l,04aug09,als Convert shared memory offsets to use MIPC_OFFSET type
|
||||
01k,02aug09,als Eliminate void pointer argument
|
||||
01j,30jul09,als Add support for per-bus statistics collection
|
||||
01i,27jul09,als Event queue rework
|
||||
01h,24jul09,als Remove purge of port's event queue during socket shutdown
|
||||
01g,24jul09,jlk Event Q rework.
|
||||
01f,25jun09,als Rework memory region code to fix WIND00167982
|
||||
01e,13jun09,ebh Changes from performance review
|
||||
01d,09jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01c,30apr09,ebh Ensure that mipc.h is included first
|
||||
01b,24feb09,ebh Rename event enqueue and dequeue routines
|
||||
01a,25nov08,apa Initial version
|
||||
*/
|
||||
|
||||
#include "mipc_sm_core.h"
|
||||
#include "mipc_sm_event_queue.h"
|
||||
#include "mipc_sm_socket.h"
|
||||
#include "mipc_sm_system.h"
|
||||
|
||||
/*
|
||||
* A node's event queue state is divided into 3 parts:
|
||||
*
|
||||
* bit 0 (new work added to event queue)
|
||||
* - indicates that at least one new event has been added to event queue
|
||||
* since the last time the receiver checked for new events
|
||||
* - set by senders; cleared by receiver
|
||||
*
|
||||
* bit 1 (event queue processing active)
|
||||
* - indicates that the receiver is currently processing the event queue
|
||||
* - set and cleared by receiver only
|
||||
*
|
||||
* remaining bits (event queue processing complete counter)
|
||||
* - indicates number of times receiver has checked event queue and then
|
||||
* become inactive
|
||||
* - incremented by receiver only
|
||||
*/
|
||||
|
||||
#define EVENT_QUEUE_NEW_WORK 0x01
|
||||
#define EVENT_QUEUE_RUNNING 0x02
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* _is_sig_invalid - detect if an event signature does not match a socket's
|
||||
*/
|
||||
static MULTIOS_INLINE int _is_sig_invalid(MipcSmSocket *s, MipcSmEvent *e)
|
||||
{
|
||||
uint32_t event_signature = MULTIOS_ntoh32(e->connectSig);
|
||||
|
||||
return (int)((event_signature ^ s->peerConnectSig) & s->sigCheckMask);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _cmd_packet - Process an incoming packet.
|
||||
*
|
||||
* Process an event sent as MIPC_SM_CMD_PACKET
|
||||
*/
|
||||
static void _cmd_packet(MipcSmSocket *theSocket, MipcSmEvent *event)
|
||||
{
|
||||
MipcSmPacketDesc *bufDesc = (MipcSmPacketDesc *)event;
|
||||
int action;
|
||||
int rc;
|
||||
|
||||
if (_is_sig_invalid(theSocket, event)) {
|
||||
mipc_sm_packet_free(theSocket, bufDesc);
|
||||
return;
|
||||
}
|
||||
|
||||
MIPC_STATS_ADD(theSocket->statsPtr, MIPC_STATS_BUFS_RCVD, 1);
|
||||
MIPC_STATS_ADD(theSocket->statsPtr, MIPC_STATS_BYTES_RCVD,
|
||||
MULTIOS_ntoh32(bufDesc->bufLen));
|
||||
|
||||
/* invoke callback (which must exist for every socket) */
|
||||
action = theSocket->options.optRxCallback(
|
||||
mipc_sm_sock2sd(theSocket),
|
||||
mipc_sm_packet_data_ptr(bufDesc),
|
||||
MULTIOS_ntoh32(bufDesc->bufLen),
|
||||
MULTIOS_ntoh16(event->homeNode),
|
||||
MULTIOS_ntoh16(event->srcPort),
|
||||
(MIPC_ZBUFFER)bufDesc);
|
||||
|
||||
switch (action) {
|
||||
case MIPC_RX_QUEUEBUF:
|
||||
break;
|
||||
|
||||
case MIPC_RX_KEEPBUF:
|
||||
return;
|
||||
|
||||
default:
|
||||
mipc_sm_packet_free(theSocket, bufDesc);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = mipc_sm_socket_packet_queue(theSocket, bufDesc);
|
||||
|
||||
/* buffer could not be placed on receive queue and has been free'd */
|
||||
if (rc < 0) {
|
||||
/* break connection (if it exists), since there is data loss */
|
||||
if (theSocket->connRequired &&
|
||||
(theSocket->connState == MIPC_SM_CONN_UP))
|
||||
{
|
||||
theSocket->connState = MIPC_SM_CONN_SELF_RST;
|
||||
mipc_sm_basic_event_send(
|
||||
theSocket, theSocket->connectSig,
|
||||
theSocket->peer.nodeNum, theSocket->peer.portNum,
|
||||
MIPC_SM_CMD_CONNECT_FIN, 1);
|
||||
}
|
||||
|
||||
MIPC_STATS_ADD(theSocket->statsPtr,
|
||||
MIPC_STATS_SOCKET_RX_QUEUE_ERR, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* let application known a buffer has been queued */
|
||||
if (theSocket->options.optRxQueuedCallback) {
|
||||
theSocket->options.optRxQueuedCallback(
|
||||
mipc_sm_sock2sd(theSocket));
|
||||
}
|
||||
mipc_sm_socket_do_sync(&theSocket->rxWait);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _cmd_txbufavail - Process a returned packet.
|
||||
*
|
||||
* A MIPC_SM_CMD_TXBUFAVAIL event indicates that a packet has been returned
|
||||
* to its originating port because the port's packet list was empty.
|
||||
* The port needs to free the packet and notify any waiting application(s).
|
||||
*
|
||||
* If a port never depletes its packet list this routine will never be invoked.
|
||||
*
|
||||
* Note: Normal connection signture validation is not done here since it is
|
||||
* not applicable. (i.e. We rely on the port signature to ensure that
|
||||
* the packet actually belongs to this port instance.)
|
||||
*/
|
||||
static void _cmd_txbufavail(MipcSmSocket *theSocket, MipcSmEvent *event)
|
||||
{
|
||||
MipcSmPacketDesc *bufDesc = (MipcSmPacketDesc *)event;
|
||||
uint16_t busId;
|
||||
MipcSmPort *port;
|
||||
MULTIOS_ATOMIC_VAL portState;
|
||||
uint32_t portSig;
|
||||
|
||||
struct mipc_sm_local_bus_info *busInfo; /* ptr to local info for bus */
|
||||
|
||||
MIPC_STATS_ADD(theSocket->statsPtr, MIPC_STATS_BUF_AVAIL_RCVD, 1);
|
||||
|
||||
MIPCDBG(MIPC_INFO "Received notification of free tx buffer.\n");
|
||||
|
||||
busId = theSocket->addr.busNum;
|
||||
busInfo = &mipcSmLocalBusInfo[busId];
|
||||
port = theSocket->port;
|
||||
|
||||
/* decide what to do with packet */
|
||||
restart:
|
||||
portSig = MULTIOS_ntoh32(bufDesc->event.srcPortSig);
|
||||
portState = MULTIOS_ATOMIC_GET(&port->state);
|
||||
|
||||
/* if port signatures don't match, return packet to node's pool */
|
||||
if (portSig != (portState & PORT_SIG_MASK)) {
|
||||
MIPCDBG("port %d: freed obsolete packet indirectly\n",
|
||||
theSocket->addr.portNum);
|
||||
mipc_sm_event_free((MipcSmEvent *)bufDesc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* put packet back in port's packet list */
|
||||
if (!mipc_sm_port_packet_put(port, portState, bufDesc)) {
|
||||
/*
|
||||
* a port state change prevented packet from being returned,
|
||||
* start decision process from the beginning
|
||||
*/
|
||||
goto restart;
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify socket if buffer list has gone from empty to non-empty;
|
||||
* also tell any application blocked waiting for a transmit buffer
|
||||
*/
|
||||
if ((portState & EVENT_INDEX_MASK) == EVENT_INDEX_INVALID) {
|
||||
if (theSocket->options.optTxBufAvailCallback) {
|
||||
theSocket->options.optTxBufAvailCallback(
|
||||
mipc_sm_sock2sd(theSocket));
|
||||
}
|
||||
mipc_sm_socket_do_sync(&theSocket->txWait);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _cmd_connect_syn - Process a connection request.
|
||||
*
|
||||
* Process an event sent as MIPC_SM_CMD_CONNECT_SYN
|
||||
*/
|
||||
static void _cmd_connect_syn(MipcSmSocket *theSocket, MipcSmEvent *event)
|
||||
{
|
||||
MipcSmBasicEvent *fullEvent = (MipcSmBasicEvent *)event;
|
||||
uint32_t event_sig = MULTIOS_ntoh32(event->connectSig);
|
||||
uint16_t srcNode = MULTIOS_ntoh16(event->homeNode);
|
||||
uint16_t srcPort = MULTIOS_ntoh16(event->srcPort);
|
||||
|
||||
if (theSocket->connectQueue && !_is_sig_invalid(theSocket, event)) {
|
||||
uint16_t nextHead = (uint16_t)
|
||||
((theSocket->connectQueueHead + 1U) %
|
||||
theSocket->connectQueueSize);
|
||||
|
||||
/* store the request in the queue if there is still space */
|
||||
if (nextHead != theSocket->connectQueueTail) {
|
||||
struct mipc_sm_conn_request *request =
|
||||
theSocket->connectQueue +
|
||||
theSocket->connectQueueHead;
|
||||
|
||||
request->srcNode = srcNode;
|
||||
request->srcPort = srcPort;
|
||||
request->connectSig = event_sig;
|
||||
theSocket->connectQueueHead = nextHead;
|
||||
|
||||
/* let application know the request came in */
|
||||
|
||||
if (theSocket->options.optConnectRequestCallback) {
|
||||
theSocket->options.optConnectRequestCallback(
|
||||
mipc_sm_sock2sd(theSocket));
|
||||
}
|
||||
mipc_sm_socket_do_sync(&theSocket->rxWait);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
mipc_sm_basic_event_send(theSocket, event_sig, srcNode, srcPort,
|
||||
MIPC_SM_CMD_CONNECT_NAK, 0);
|
||||
MIPCDBG(MIPC_INFO "Connection request rejected.\n");
|
||||
exit:
|
||||
mipc_sm_basic_event_free(fullEvent);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _cmd_connect_ack - Process a connection acknowledge.
|
||||
*
|
||||
* Process an event sent as MIPC_SM_CMD_CONNECT_ACK
|
||||
*/
|
||||
static void _cmd_connect_ack(MipcSmSocket *theSocket, MipcSmEvent *event)
|
||||
{
|
||||
MipcSmBasicEvent *fullEvent = (MipcSmBasicEvent *)event;
|
||||
|
||||
MIPCDBG(MIPC_INFO "Received connect ACK.\n");
|
||||
|
||||
if ((theSocket->connState == MIPC_SM_CONN_SENT_SYN) &&
|
||||
!_is_sig_invalid(theSocket, event)) {
|
||||
theSocket->peer.portNum = MULTIOS_ntoh16(event->srcPort);
|
||||
theSocket->connState = MIPC_SM_CONN_UP;
|
||||
if (theSocket->options.optConnectedCallback) {
|
||||
theSocket->options.optConnectedCallback(
|
||||
mipc_sm_sock2sd(theSocket));
|
||||
}
|
||||
mipc_sm_socket_do_sync(&theSocket->rxWait);
|
||||
} else {
|
||||
MIPCDBG(MIPC_INFO "Connect ACK bounced back.\n");
|
||||
mipc_sm_basic_event_send(
|
||||
theSocket, MULTIOS_ntoh32(event->connectSig),
|
||||
MULTIOS_ntoh16(event->homeNode),
|
||||
MULTIOS_ntoh16(event->srcPort),
|
||||
MIPC_SM_CMD_CONNECT_FIN, 1);
|
||||
}
|
||||
mipc_sm_basic_event_free(fullEvent);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _cmd_connect_nak - Process a connection refusal.
|
||||
*
|
||||
* Process an event sent as MIPC_SM_CMD_CONNECT_NAK
|
||||
*/
|
||||
static void _cmd_connect_nak(MipcSmSocket *theSocket, MipcSmEvent *event)
|
||||
{
|
||||
MipcSmBasicEvent *fullEvent = (MipcSmBasicEvent *)event;
|
||||
|
||||
if ((theSocket->connState == MIPC_SM_CONN_SENT_SYN) &&
|
||||
!_is_sig_invalid(theSocket, event)) {
|
||||
theSocket->connState = MIPC_SM_CONN_PEER_NAK;
|
||||
if (theSocket->options.optConnectRefusedCallback) {
|
||||
theSocket->options.optConnectRefusedCallback(
|
||||
mipc_sm_sock2sd(theSocket));
|
||||
}
|
||||
mipc_sm_socket_do_sync(&theSocket->rxWait);
|
||||
} else {
|
||||
MIPCDBG(MIPC_INFO "Connect NACK discarded.\n");
|
||||
}
|
||||
|
||||
mipc_sm_basic_event_free(fullEvent);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _cmd_disconnect_req - Process a connection termination event.
|
||||
*
|
||||
* Process an event sent as MIPC_SM_CMD_CONNECT_FIN
|
||||
*/
|
||||
static void _cmd_connect_fin(MipcSmSocket *theSocket, MipcSmEvent *event)
|
||||
{
|
||||
MipcSmBasicEvent *fullEvent = (MipcSmBasicEvent *)event;
|
||||
|
||||
if ((theSocket->connState == MIPC_SM_CONN_UP) &&
|
||||
!_is_sig_invalid(theSocket, event)) {
|
||||
/*
|
||||
* Switch port event processing from real socket to dummy socket
|
||||
* to prevent socket from having to handle any future events
|
||||
*/
|
||||
theSocket->portInfo->socket =
|
||||
mipcSmLocalBusInfo[theSocket->addr.busNum].dummy_socket;
|
||||
|
||||
/* Record reason for connection termination */
|
||||
theSocket->connState = (uint8_t)
|
||||
((MULTIOS_ntoh64(fullEvent->data) & 1U)
|
||||
? MIPC_SM_CONN_PEER_RST : MIPC_SM_CONN_PEER_FIN);
|
||||
|
||||
/* Let application know about disconnection */
|
||||
if (theSocket->options.optDisconnectedCallback) {
|
||||
theSocket->options.optDisconnectedCallback(
|
||||
mipc_sm_sock2sd(theSocket));
|
||||
}
|
||||
mipc_sm_socket_do_sync(&theSocket->rxWait);
|
||||
mipc_sm_socket_do_sync(&theSocket->txWait);
|
||||
} else {
|
||||
MIPCDBG(MIPC_INFO "Disconnect request discarded.\n");
|
||||
}
|
||||
|
||||
mipc_sm_basic_event_free(fullEvent);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _cmd_express_data - Process incoming 64-bit express data.
|
||||
*
|
||||
* Process an event sent as MIPC_SM_CMD_EXPRESS
|
||||
*
|
||||
* Note: Normal connection signture validation is not done here since it is
|
||||
* not applicable (i.e. express data can be sent from anyone to anyone
|
||||
* else at any time).
|
||||
*/
|
||||
static void _cmd_express_data(MipcSmSocket *theSocket, MipcSmEvent *event)
|
||||
{
|
||||
MipcSmBasicEvent *fullEvent = (MipcSmBasicEvent *)event;
|
||||
uint64_t data = MULTIOS_ntoh64(fullEvent->data);
|
||||
|
||||
MIPC_STATS_ADD(theSocket->statsPtr, MIPC_STATS_EXPRESS_MSGS_RCVD, 1);
|
||||
|
||||
/* invoke callback (which must exist for every socket) */
|
||||
theSocket->options.optExpressCallback(
|
||||
mipc_sm_sock2sd(theSocket),
|
||||
MULTIOS_ntoh16(event->homeNode),
|
||||
MULTIOS_ntoh16(event->srcPort),
|
||||
data);
|
||||
|
||||
mipc_sm_basic_event_free(fullEvent);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _cmd_mem_audit - Recover lost shared memory resources.
|
||||
*
|
||||
* Process an event sent as MIPC_SM_CMD_MEM_AUDIT
|
||||
*
|
||||
* Note: Normal connection signture validation is not done here since it is
|
||||
* not applicable (i.e. this is an internal housekeeping event).
|
||||
*/
|
||||
static void _cmd_mem_audit(MipcSmSocket *theSocket, MipcSmEvent *event)
|
||||
{
|
||||
uint16_t busId = theSocket->addr.busNum;
|
||||
struct mipc_sm_local_bus_info *busInfo = &mipcSmLocalBusInfo[busId];
|
||||
|
||||
mipc_sm_basic_event_free((MipcSmBasicEvent *)event);
|
||||
|
||||
mipc_sm_node_pool_audit(busId, &busInfo->ownNode->eventPool, 0);
|
||||
mipc_sm_node_pool_audit(busId, &busInfo->ownNode->packetPool.eventPool, 1);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _cmd_node_status - Handle change in peer node status.
|
||||
*
|
||||
* Process an event sent as MIPC_SM_CMD_NODE_STATUS
|
||||
*
|
||||
* Note: Normal connection signture validation is not done here since it is
|
||||
* not applicable (i.e. this is an internal housekeeping event).
|
||||
*/
|
||||
static void _cmd_node_status(MipcSmSocket *theSocket, MipcSmEvent *event)
|
||||
{
|
||||
MipcSmBasicEvent *fullEvent = (MipcSmBasicEvent *)event;
|
||||
uint64_t data = MULTIOS_ntoh64(fullEvent->data);
|
||||
uint16_t nodeId = (uint16_t)data;
|
||||
uint16_t busId = theSocket->addr.busNum;
|
||||
|
||||
if (data >> 16) {
|
||||
mipc_sm_node_up(busId, nodeId);
|
||||
} else {
|
||||
mipc_sm_node_down(busId, nodeId);
|
||||
}
|
||||
|
||||
mipc_sm_basic_event_free(fullEvent);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _cmd_unknown - Process unrecognized event
|
||||
*
|
||||
* Ignore event (assumed to be unsupported feature of a future version of MIPC)
|
||||
*/
|
||||
static void _cmd_unknown(MipcSmSocket *theSocket, MipcSmEvent *event)
|
||||
{
|
||||
MIPCDBG(MIPC_ALERT "Received unknown command %u\n",
|
||||
MULTIOS_ntoh32(event->control));
|
||||
mipc_sm_event_free(event);
|
||||
}
|
||||
|
||||
/* Table of event processing functions */
|
||||
|
||||
typedef void (*MIPC_SM_CMD_FUNC)(MipcSmSocket *theSocket, MipcSmEvent *theEvent);
|
||||
|
||||
static MIPC_SM_CMD_FUNC _cmd_demux_table[16] =
|
||||
{
|
||||
_cmd_packet, /* MIPC_SM_CMD_PACKET */
|
||||
_cmd_txbufavail, /* MIPC_SM_CMD_TXBUFAVAIL */
|
||||
_cmd_connect_syn, /* MIPC_SM_CMD_CONNECT_SYN */
|
||||
_cmd_connect_ack, /* MIPC_SM_CMD_CONNECT_ACK */
|
||||
_cmd_connect_nak, /* MIPC_SM_CMD_CONNECT_NAK */
|
||||
_cmd_connect_fin, /* MIPC_SM_CMD_CONNECT_FIN */
|
||||
_cmd_express_data, /* MIPC_SM_CMD_EXPRESS_DATA */
|
||||
_cmd_mem_audit, /* MIPC_SM_CMD_MEM_AUDIT */
|
||||
_cmd_node_status, /* MIPC_SM_CMD_NODE_STATUS */
|
||||
_cmd_unknown, /* reserved for future use */
|
||||
_cmd_unknown, /* reserved for future use */
|
||||
_cmd_unknown, /* reserved for future use */
|
||||
_cmd_unknown, /* reserved for future use */
|
||||
_cmd_unknown, /* reserved for future use */
|
||||
_cmd_unknown, /* reserved for future use */
|
||||
_cmd_unknown /* reserved for future use */
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* _process_event - process an event received on the node's event queue
|
||||
*/
|
||||
static MULTIOS_INLINE void _process_event
|
||||
(
|
||||
uint16_t busId,
|
||||
MipcSmEvent *event
|
||||
)
|
||||
{
|
||||
MULTIOS_ATOMIC_VAL portUsage;
|
||||
struct mipc_sm_local_port_info *port_info;
|
||||
|
||||
/* set port's "event processing active" indicator */
|
||||
port_info = &mipcSmLocalBusInfo[busId].port_info[event->destPort];
|
||||
MULTIOS_ATOMIC_ADD(&port_info->usage, PORT_EVENT_ACTIVE);
|
||||
|
||||
/* pass event to socket (note: may be a dummy socket) */
|
||||
_cmd_demux_table[MULTIOS_ntoh32(event->control) & 0xf](
|
||||
port_info->socket, event);
|
||||
|
||||
/*
|
||||
* clear port's "event processing active" indicator;
|
||||
* if port can now complete a socket shutdown, wake it up
|
||||
*/
|
||||
portUsage = MULTIOS_ATOMIC_SUB(&port_info->usage, PORT_EVENT_ACTIVE);
|
||||
if (portUsage == (PORT_EVENT_ACTIVE | PORT_SHUTDOWN_ACTIVE)) {
|
||||
MULTIOS_SEM_UP(&port_info->shutdownSem);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _capture_events - capture events from node's event queue
|
||||
*
|
||||
* Note that elements of event queue end up in FIFO order.
|
||||
*/
|
||||
static MIPC_OFFSET _capture_events(MULTIOS_ATOMIC *eventTailOffset)
|
||||
{
|
||||
MIPC_OFFSET currOffset;
|
||||
MIPC_OFFSET nextOffset;
|
||||
MIPC_OFFSET tempOffset;
|
||||
MipcSmEvent *event;
|
||||
|
||||
/* grab all elements in event queue; set queue back to empty */
|
||||
currOffset = MULTIOS_ATOMIC_SET(eventTailOffset, 0);
|
||||
nextOffset = 0;
|
||||
|
||||
/* invert the order of the elements in the queue */
|
||||
while (currOffset != 0) {
|
||||
event = (MipcSmEvent *)mipc_offset2addr(currOffset);
|
||||
tempOffset = currOffset;
|
||||
currOffset = MULTIOS_ATOMIC_SET(&event->nextOffset, nextOffset);
|
||||
nextOffset = tempOffset;
|
||||
}
|
||||
|
||||
return nextOffset;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_api_process_rx_events - process all events in node's event queue
|
||||
*/
|
||||
void mipc_sm_api_process_rx_events(uint16_t busId)
|
||||
{
|
||||
struct mipc_sm_node *node; /* ptr to own node in SM */
|
||||
MULTIOS_ATOMIC_VAL origEventState; /* event state on entry */
|
||||
MULTIOS_ATOMIC_VAL newEventState; /* updated event state */
|
||||
MIPC_OFFSET headEventOffset; /* offset to 1st event to process */
|
||||
MipcSmEvent *event; /* ptr to event to process */
|
||||
|
||||
node = mipcSmLocalBusInfo[busId].ownNode;
|
||||
|
||||
do {
|
||||
/*
|
||||
* update event queue state:
|
||||
* - set "event queue processing active" indicator
|
||||
* - clear "new work added to event queue" indicator
|
||||
*/
|
||||
origEventState = MULTIOS_ATOMIC_GET(&node->eventQueueState);
|
||||
newEventState = (origEventState & ~EVENT_QUEUE_NEW_WORK)
|
||||
| EVENT_QUEUE_RUNNING;
|
||||
MULTIOS_ATOMIC_SET(&node->eventQueueState, newEventState);
|
||||
|
||||
/* grab all events from event queue (in FIFO order) */
|
||||
headEventOffset = _capture_events(&node->eventTailOffset);
|
||||
|
||||
/* process all captured events */
|
||||
while (headEventOffset != 0) {
|
||||
event = mipc_offset2addr(headEventOffset);
|
||||
headEventOffset = MULTIOS_ATOMIC_GET(&event->nextOffset);
|
||||
_process_event(busId, event);
|
||||
}
|
||||
|
||||
/*
|
||||
* try to update event queue state:
|
||||
* - clear "event queue processing active" indicator
|
||||
* - increment "event queue processing complete counter"
|
||||
*
|
||||
* if update fails because "new work" indicator was set
|
||||
* by a sender, start event queue processing all over again
|
||||
*/
|
||||
} while (!MULTIOS_ATOMIC_CAS(&node->eventQueueState, newEventState,
|
||||
newEventState + EVENT_QUEUE_RUNNING));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _event_enqueue - enqueue event onto node's event queue
|
||||
*
|
||||
* Note that elements of event queue are actually kept in LIFO order.
|
||||
*/
|
||||
static void _event_enqueue(MULTIOS_ATOMIC *eventTailOffset, MipcSmEvent *newEvt)
|
||||
{
|
||||
MIPC_OFFSET newTailOffset;
|
||||
MIPC_OFFSET oldTailOffset;
|
||||
|
||||
/* Compute offset of new tail element for list */
|
||||
newTailOffset = mipc_addr2offset(newEvt);
|
||||
|
||||
/* Add new element to tail of list */
|
||||
do {
|
||||
oldTailOffset = MULTIOS_ATOMIC_GET(eventTailOffset);
|
||||
MULTIOS_ATOMIC_SET(&newEvt->nextOffset, oldTailOffset);
|
||||
/* Ensure event's link is written before changing queue state */
|
||||
MULTIOS_MEM_BARRIER();
|
||||
} while (!MULTIOS_ATOMIC_CAS(eventTailOffset,
|
||||
oldTailOffset, newTailOffset));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_event_send - send event to a port
|
||||
*
|
||||
* On entry, it is assumed that MIPC is initialized, and that the destination
|
||||
* bus, node, and port structures exist. (There is no guarantee that the node
|
||||
* is currently up or that the port is active, though.)
|
||||
*/
|
||||
int mipc_sm_event_send(MipcSmEvent *event, const struct mipc_sockaddr *to,
|
||||
uint16_t cmd)
|
||||
{
|
||||
struct mipc_sm_local_bus_info *busInfo;
|
||||
struct mipc_sm_node *node;
|
||||
MULTIOS_ATOMIC_VAL origEventState;
|
||||
MULTIOS_ATOMIC_VAL newEventState;
|
||||
|
||||
/* Locate destination node & ensure it is currently active */
|
||||
busInfo = &mipcSmLocalBusInfo[to->busNum];
|
||||
if (!busInfo->peer_info[to->nodeNum].is_up) {
|
||||
return -MIPC_ENETUNREACH;
|
||||
}
|
||||
node = mipc_sm_node_ptr_valid(to->busNum, to->nodeNum);
|
||||
|
||||
/* Finish initializing the event (source info is already set) */
|
||||
event->control = MULTIOS_hton32(cmd);
|
||||
event->destPort = MULTIOS_hton16(to->portNum);
|
||||
event->userNodeInfo = node->state;
|
||||
|
||||
/* Enqueue event (does a Mem Barrier and can't fail) */
|
||||
_event_enqueue(&node->eventTailOffset, event);
|
||||
|
||||
/* Notify receiver that a new event needs to be processed */
|
||||
restart:
|
||||
/* Capture current state of event queue */
|
||||
origEventState = MULTIOS_ATOMIC_GET(&node->eventQueueState);
|
||||
|
||||
/*
|
||||
* If receiver is already aware unprocessed events exist
|
||||
* there's nothing more we need to do ...
|
||||
*/
|
||||
if (origEventState & EVENT_QUEUE_NEW_WORK) {
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* If receiver is currently processing event queue, update the
|
||||
* event queue state to let receiver know there is more work to do
|
||||
*/
|
||||
if (origEventState & EVENT_QUEUE_RUNNING) {
|
||||
if (MULTIOS_ATOMIC_CAS(&node->eventQueueState, origEventState,
|
||||
origEventState | EVENT_QUEUE_NEW_WORK)) {
|
||||
return MIPC_OK;
|
||||
}
|
||||
/*
|
||||
* Update failed, either because another sender indicated
|
||||
* new work or because the receiver became inactive before
|
||||
* we could tell it about the new work;
|
||||
* restart notification processing from the beginning
|
||||
*/
|
||||
goto restart;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we reach this point, receiver is currently inactive and no one
|
||||
* else has notified it of new work, so we need to do the notification
|
||||
*/
|
||||
|
||||
/*
|
||||
* Send interrupt if receiver is running in ISR or ISR-deferred mode
|
||||
* (this *must* be done before the event queue state that follows)
|
||||
*/
|
||||
if (MULTIOS_ntoh16(node->qos) >= 0) {
|
||||
if (mipc_sm_adapt_notify_node(to->busNum,
|
||||
MULTIOS_ntoh16(node->cpuId),
|
||||
MULTIOS_ntoh16(node->intId)) != MIPC_OK) {
|
||||
/* can't return a failure since packet was enqueued
|
||||
* properly
|
||||
*/
|
||||
return MIPC_OK;
|
||||
}
|
||||
MIPC_STATS_ADD(mipc_sm_stats_ptr(to->busNum),
|
||||
MIPC_STATS_INTERRUPTS_SENT, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update event queue state to indicate that new work has been added;
|
||||
* this prevents other senders from also trying to notify the receiver
|
||||
* about new work, avoiding unnecessary interrupts
|
||||
*
|
||||
* Note: If the update fails, this indicates that:
|
||||
* a) another sender has already indicated new work, or
|
||||
* b) receiver has started processing the event queue since our event
|
||||
* was added and is still active, or
|
||||
* c) receiver started processing the event queue since our event
|
||||
* was added and is now inactive, or
|
||||
* d) a) and b), or
|
||||
* e) a) and c)
|
||||
* In any of these scenarios, our update is no longer required ...
|
||||
*/
|
||||
newEventState = origEventState | EVENT_QUEUE_NEW_WORK;
|
||||
(void)MULTIOS_ATOMIC_CAS(&node->eventQueueState,
|
||||
origEventState, newEventState);
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/* mipc_sm_event_queue.h - MIPC-SM event queues */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01u,07jan11,jlk Update license header
|
||||
01t,26aug10,jlk Make sure #ifdef __cplusplus starts after #includes
|
||||
01s,27sep09,als Fix bugs in receive routines (WIND00183445, WIND00183399)
|
||||
01r,24sep09,als Rename mipc_sm_api_events files to mipc_sm_event_pool
|
||||
01q,23sep09,bwa add connection signature
|
||||
01p,22sep09,als Enhance node restart capability
|
||||
01o,26aug09,als Cleanup issues with flow control rework
|
||||
01n,25aug09,jlk WIND00178668 - MIPC flow control changes.
|
||||
01m,14aug09,als Revise internals of event-based code
|
||||
01l,05aug09,als Move port's socket id out of shared memory
|
||||
01k,04aug09,als Convert shared memory offsets to use MIPC_OFFSET type
|
||||
01j,02aug09,als Eliminate void pointer argument
|
||||
01i,30jul09,als Add support for per-bus statistics collection
|
||||
01h,27jul09,als Event queue rework
|
||||
01g,24jul09,als Remove purge of port's event queue during socket shutdown
|
||||
01f,24jul09,jlk Event Q rework.
|
||||
01e,25jun09,als Rework memory region code to fix WIND00167982
|
||||
01d,13jun09,ebh Add mipc_sm_event_enqueue_all
|
||||
01c,24mar09,ebh Make inlines static and use MULTIOS_INLINE
|
||||
01b,24feb09,ebh Rename event enqueue and dequeue routines
|
||||
01a,25nov08,apa Initial version
|
||||
*/
|
||||
|
||||
#ifndef __INC_mipc_sm_event_queue_h
|
||||
#define __INC_mipc_sm_event_queue_h
|
||||
|
||||
#include "mipc_sm_event_pool.h"
|
||||
#include "mipc_sm_socket.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Event commands (maximum of 16 can be defined) */
|
||||
|
||||
#define MIPC_SM_CMD_PACKET 0
|
||||
#define MIPC_SM_CMD_TXBUFAVAIL 1
|
||||
#define MIPC_SM_CMD_CONNECT_SYN 2
|
||||
#define MIPC_SM_CMD_CONNECT_ACK 3
|
||||
#define MIPC_SM_CMD_CONNECT_NAK 4
|
||||
#define MIPC_SM_CMD_CONNECT_FIN 5
|
||||
#define MIPC_SM_CMD_EXPRESS_DATA 6
|
||||
#define MIPC_SM_CMD_MEM_AUDIT 7
|
||||
#define MIPC_SM_CMD_NODE_STATUS 8
|
||||
|
||||
int mipc_sm_event_send(MipcSmEvent *event, const struct mipc_sockaddr *to,
|
||||
uint16_t cmd);
|
||||
|
||||
void mipc_sm_api_process_rx_events(uint16_t busId);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INC_mipc_sm_event_queue_h */
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/* mipc_sm_mem_region.c - MIPC memory region */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01m,07jan11,jlk Update license header
|
||||
01l,02mar10,als Add support for 64-bit memory addressing
|
||||
01k,13aug09,als Improve robustness of packet pool
|
||||
01j,07aug09,ebh Code inspection updates
|
||||
01i,04aug09,als Convert shared memory offsets to use MIPC_OFFSET type
|
||||
01h,07jul09,h_x Add some comments to fix WIND00168361.
|
||||
01g,25jun09,als Rework memory region code to fix WIND00167982
|
||||
01f,18jun09,als Fix alignment bugs in memory region handling code
|
||||
01e,15jun09,ebh Change MULTIOS_CAS to MULTIOS_ATOMIC_CAS
|
||||
01d,09jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01c,30apr09,ebh Ensure that mipc.h is included first
|
||||
01b,23mar09,ebh Fix portability issues in code
|
||||
01a,25nov08,apa Initial version
|
||||
*/
|
||||
|
||||
#include "mipc_sm_core.h"
|
||||
#include "mipc_sm_mem_region.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_mem_region_init - initialize a shared memory pool
|
||||
*
|
||||
* Note: start/end offset is rounded up/down to provide required alignment
|
||||
*/
|
||||
void mipc_sm_mem_region_init(struct mipc_sm_mem_region *region,
|
||||
MIPC_MEMSIZE nBytes, MIPC_OFFSET startOffset)
|
||||
{
|
||||
MIPC_OFFSET endOffset;
|
||||
|
||||
endOffset = ALIGN_DOWN(startOffset + nBytes);
|
||||
startOffset = ALIGN_UP(startOffset);
|
||||
|
||||
region->startOffset = MULTIOS_hton32(startOffset);
|
||||
region->endOffset = MULTIOS_hton32(endOffset);
|
||||
|
||||
MULTIOS_ATOMIC_SET(®ion->nextFreeOffset, startOffset);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_mem_region_alloc - allocate storage from a shared memory pool
|
||||
*
|
||||
* Note: allocation musn't go past end of pool (or wrap around!);
|
||||
* must also protect against simultaneous allocations by other nodes
|
||||
*
|
||||
* Returns: MIPC_OK if successful ("offset" set to offset of allocated area)
|
||||
* MIPC_ENOMEM if allocation of nBytes fails
|
||||
*/
|
||||
int mipc_sm_mem_region_alloc(struct mipc_sm_mem_region *region,
|
||||
MIPC_MEMSIZE nBytes, MIPC_OFFSET *offset)
|
||||
{
|
||||
MIPC_OFFSET currentOffset;
|
||||
MIPC_OFFSET nextFreeOffset;
|
||||
|
||||
do {
|
||||
currentOffset = MULTIOS_ATOMIC_GET(®ion->nextFreeOffset);
|
||||
nextFreeOffset = ALIGN_UP(currentOffset + nBytes);
|
||||
|
||||
if ((nextFreeOffset > MULTIOS_ntoh32(region->endOffset)) ||
|
||||
(nextFreeOffset < currentOffset)) {
|
||||
|
||||
/* Memory exhaustion */
|
||||
return -MIPC_ENOMEM;
|
||||
}
|
||||
} while (!MULTIOS_ATOMIC_CAS(®ion->nextFreeOffset, currentOffset,
|
||||
nextFreeOffset));
|
||||
|
||||
*offset = currentOffset;
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/* mipc_sm_mem_region.h - MIPC memory region */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01h,07jan11,jlk Update license header
|
||||
01g,02mar10,als Add support for 64-bit memory addressing
|
||||
01f,13aug09,als Improve robustness of packet pool
|
||||
01e,07aug09,ebh Code inspection updates
|
||||
01d,04aug09,als Convert shared memory offsets to use MIPC_OFFSET type
|
||||
01c,25jun09,als Rework memory region code to fix WIND00167982
|
||||
01b,09jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01a,25nov08,apa Initial version
|
||||
*/
|
||||
|
||||
#ifndef __INC_mipc_sm_mem_region_h
|
||||
#define __INC_mipc_sm_mem_region_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* specify byte alignment used by shared memory regions; must be power of 2! */
|
||||
|
||||
#define MIPC_SM_MEM_REGION_ALIGNMENT 8U /* enforce 64 bit alignment */
|
||||
|
||||
/* macros used to for desired byte alignment */
|
||||
|
||||
#define ALIGNMENT_MASK (~(MIPC_OFFSET)(MIPC_SM_MEM_REGION_ALIGNMENT - 1U))
|
||||
|
||||
static MULTIOS_INLINE MIPC_OFFSET ALIGN_UP(MIPC_OFFSET offset)
|
||||
{
|
||||
return (offset + (MIPC_SM_MEM_REGION_ALIGNMENT - 1U)) & ALIGNMENT_MASK;
|
||||
}
|
||||
|
||||
static MULTIOS_INLINE MIPC_OFFSET ALIGN_DOWN(MIPC_OFFSET offset)
|
||||
{
|
||||
return offset & ALIGNMENT_MASK;
|
||||
}
|
||||
|
||||
struct mipc_sm_mem_region
|
||||
{
|
||||
MIPC_OFFSET startOffset;
|
||||
MIPC_OFFSET endOffset;
|
||||
MULTIOS_ATOMIC nextFreeOffset;
|
||||
};
|
||||
|
||||
/* Initialize a memory region of size 'nBytes' */
|
||||
void mipc_sm_mem_region_init(struct mipc_sm_mem_region *region,
|
||||
MIPC_MEMSIZE nBytes, MIPC_OFFSET startOffset);
|
||||
|
||||
/* Allocate a memory block of size 'nBytes' from a memory region */
|
||||
int mipc_sm_mem_region_alloc(struct mipc_sm_mem_region *region,
|
||||
MIPC_MEMSIZE nBytes, MIPC_OFFSET *offset);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INC_mipc_sm_mem_region_h */
|
||||
|
||||
@@ -0,0 +1,736 @@
|
||||
/* mipc_sm_node.c - MIPC-SM nodes */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
02y,12dec12,zhw Move define of MIPC_HB_PROBE_INTERVAL to mipc_sm_node.h
|
||||
02x,16jun11,zhw Fix bug of buffer reclaiming (WIND00278985)
|
||||
02w,04apr11,ste typo in function header
|
||||
02v,14jan11,ste Use new functions to allocate/free memory
|
||||
02u,07jan11,jlk Update license header
|
||||
02t,23nov10,gjj WIND00241399 - eliminate compiling warnings
|
||||
02s,14sep10,jlk Add debug mode support
|
||||
02r,07aug10,wy1 add the call to MULTIOS_TIMER_START in the end of
|
||||
func mipc_sm_init (fix WIND00226071)
|
||||
02q,04aug10,h_w Remove compile warning(WIND00189507)
|
||||
02p,18mar10,jag Add Linux procfs framework calls
|
||||
02o,02mar10,als Add support for 64-bit memory addressing
|
||||
02n,29oct09,als Fix connection signature duplication (WIND00185284)
|
||||
02m,27sep09,als Fix bugs in receive routines (WIND00183445, WIND00183399)
|
||||
02l,23sep09,bwa add connection signature
|
||||
02k,11sep09,als Enhance node restart capability
|
||||
02j,11sep09,bwa replace sems by sync objects given only when requested
|
||||
02i,03sep09,als Remove reference to obsolete semaphore
|
||||
02h,26aug09,als Cleanup issues with flow control rework
|
||||
02g,25aug09,bwa Differentiate between CPU ID and Node ID.
|
||||
02f,25aug09,jlk WIND00178668 - MIPC flow control changes.
|
||||
02e,25aug09,als Fix issues with node restart capability
|
||||
02d,20aug09,als Add node restart support
|
||||
02c,19aug09,als Fix bug in bus initialization code (WIND00177423)
|
||||
02b,14aug09,als Revise internals of event-based code
|
||||
02a,11aug09,als Revise event exchange code to improve robustness
|
||||
01z,10aug09,als Eliminate unnecessary operations in receive datapath
|
||||
01y,07aug09,ebh Remove unused routine and code inspection updates
|
||||
01x,07aug09,als Convert return value of routine to void
|
||||
01w,05aug09,als Move port's socket id out of shared memory
|
||||
01v,04aug09,als Convert shared memory offsets to use MIPC_OFFSET type
|
||||
01u,29jul09,als Add support for per-bus statistics collection
|
||||
01t,27jul09,als Event queue rework
|
||||
01s,24jul09,jlk Event Q rework.
|
||||
01r,23jul09,als Move port allocation semaphore from SM to local memory
|
||||
01q,22jul09,als Allow adaptation code to handle fatal errors detected by
|
||||
common code
|
||||
01p,02jul09,als Changes to reflect updated file names
|
||||
01o,01jul09,als Handle failure to allocate data structures during node init
|
||||
01n,16jun09,als Elimination of obsolete files
|
||||
01m,02jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01l,29may09,als Revise configuration based on MIPC 2.0 HLD feedback
|
||||
01k,26may09,ebh Code Inspection Modifications
|
||||
01j,01may09,ebh Add routine to return port and node information
|
||||
01i,30apr09,ebh Ensure that mipc.h is included first
|
||||
01h,24apr09,ebh Add in txEventsCount
|
||||
01g,22apr09,ebh Get all nodes for heartbeating, not just known nodes
|
||||
01f,21apr09,ebh Remove FUNCPTR usage
|
||||
01e,25mar09,ebh Remove unused variable
|
||||
01d,16mar09,ebh Track number of buffers outstanding on a socket to prevent
|
||||
starvation
|
||||
01c,19feb09,ebh Adjust usage of the MIPC_SO_MTU information to validate on
|
||||
bind
|
||||
01b,13feb09,ebh Update statistics
|
||||
01a,25nov08,apa Initial version.
|
||||
*/
|
||||
|
||||
#include "mipc_sm_core.h"
|
||||
#include "mipc_sm_system.h"
|
||||
#include "mipc_sm_port.h"
|
||||
#include "mipc_sm_socket.h"
|
||||
#include "mipc_sm_event_queue.h"
|
||||
|
||||
extern void mipc_sock_init(MipcSmSocket *theSocket, int type);
|
||||
|
||||
static int _dummy_show_update(uint16_t bus_unused, uint16_t node_unused)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int(*mipc_sm_node_show_up_update)(uint16_t, uint16_t) = _dummy_show_update;
|
||||
int(*mipc_sm_node_show_down_update)(uint16_t, uint16_t) = _dummy_show_update;
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_node_ptr_valid - Return a pointer to a known valid node given its ID.
|
||||
*
|
||||
* Caller knows that the node exists on the specified bus and does not want to
|
||||
* do extra checks to validate things that are known to be valid.
|
||||
*/
|
||||
struct mipc_sm_node *mipc_sm_node_ptr_valid(uint16_t busId, uint16_t nodeId)
|
||||
{
|
||||
struct mipc_sm_bus *bus = mipc_sm_bus_ptr_valid(busId);
|
||||
|
||||
return(struct mipc_sm_node *)mipc_offset2addr_ntoh(
|
||||
bus->nodesOffset) + nodeId;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_node_ptr - Return a pointer to a node given its ID.
|
||||
*/
|
||||
struct mipc_sm_node *mipc_sm_node_ptr(uint16_t busId, uint16_t nodeId)
|
||||
{
|
||||
struct mipc_sm_bus *bus = mipc_sm_bus_ptr(busId);
|
||||
struct mipc_sm_node *node;
|
||||
|
||||
if (bus && (nodeId < MULTIOS_ntoh16(bus->maxNodes))) {
|
||||
node = (struct mipc_sm_node *)mipc_offset2addr_ntoh(
|
||||
bus->nodesOffset) + nodeId;
|
||||
if ((MULTIOS_ntoh32(node->state) & SYSTEM_SIG_MASK) ==
|
||||
mipc_sm_sys_signature) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_node_pool_audit - Reclaim event pool items sent to non-operational nodes
|
||||
*
|
||||
* Note: This routine is called during processing of MIPC events.
|
||||
*/
|
||||
void mipc_sm_node_pool_audit(uint16_t busId, MipcSmEventPool *pool, int isBuf)
|
||||
{
|
||||
struct mipc_sm_local_peer_info *peerInfo;
|
||||
struct mipc_sm_local_port_info *portInfo;
|
||||
MipcSmEvent *event;
|
||||
uint16_t numEvents = MULTIOS_ntoh16(pool->numEvents);
|
||||
uint16_t eventSize = MULTIOS_ntoh16(pool->eventSize);
|
||||
uint16_t userNodeId;
|
||||
int eventIndex;
|
||||
|
||||
int nodeOk = 0;
|
||||
int alreadyFree = 0;
|
||||
int reclaimed = 0;
|
||||
|
||||
peerInfo = mipcSmLocalBusInfo[busId].peer_info;
|
||||
portInfo = mipcSmLocalBusInfo[busId].port_info;
|
||||
|
||||
event = (MipcSmEvent *)mipc_offset2addr_ntoh(pool->eventsOffset);
|
||||
eventIndex = 0;
|
||||
while (eventIndex < numEvents) {
|
||||
if (event->userNodeInfo == EVENT_FREELIST_USER_INFO) {
|
||||
/* event already in pool's free list */
|
||||
alreadyFree++;
|
||||
} else {
|
||||
userNodeId = (uint16_t)
|
||||
((MULTIOS_ntoh32(event->userNodeInfo) &
|
||||
NODE_ID_MASK) >> 16);
|
||||
if (!peerInfo[userNodeId].is_up) {
|
||||
/* event sent to a now-failed node -- reclaim */
|
||||
if (isBuf) {
|
||||
mipc_sm_packet_free(
|
||||
(MipcSmSocket *)portInfo[event->srcPort].socket,
|
||||
(MipcSmPacketDesc *)event);
|
||||
} else {
|
||||
mipc_sm_event_free(event);
|
||||
}
|
||||
reclaimed++;
|
||||
} else if ((peerInfo[userNodeId].state ^
|
||||
MULTIOS_ntoh32(event->userNodeInfo)) &
|
||||
NODE_SIG_MASK) {
|
||||
/* event sent to a now-restarted node -- reclaim */
|
||||
if (isBuf) {
|
||||
mipc_sm_packet_free(
|
||||
(MipcSmSocket *)portInfo[event->srcPort].socket,
|
||||
(MipcSmPacketDesc *)event);
|
||||
} else {
|
||||
mipc_sm_event_free(event);
|
||||
}
|
||||
reclaimed++;
|
||||
} else {
|
||||
/* event sent to an operational node */
|
||||
nodeOk++;
|
||||
}
|
||||
}
|
||||
event = (MipcSmEvent *)((char *)event + eventSize);
|
||||
eventIndex++;
|
||||
}
|
||||
|
||||
MIPCDBG("Auditing pool %p: %u events, %u ok, %u free, %u reclaimed\n",
|
||||
pool, numEvents, nodeOk, alreadyFree, reclaimed);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_node_up - react to a node joining a bus
|
||||
*
|
||||
* Note: This routine is called during processing of MIPC events.
|
||||
*/
|
||||
void mipc_sm_node_up(uint16_t busId, uint16_t nodeId)
|
||||
{
|
||||
struct mipc_sm_local_bus_info *busInfo = &mipcSmLocalBusInfo[busId];
|
||||
struct mipc_sm_local_port_info *portInfo;
|
||||
struct mipc_sm_socket *theSocket;
|
||||
MULTIOS_ATOMIC_VAL portUsage;
|
||||
uint16_t portIndex;
|
||||
|
||||
MIPCDBG("Detected node %u.%u up\n", busId, nodeId);
|
||||
|
||||
/* Examine all ports > 0 to see if any are affected by new node */
|
||||
|
||||
portInfo = &busInfo->port_info[1];
|
||||
for (portIndex = 1; portIndex < busInfo->ownMaxPorts; portIndex++) {
|
||||
|
||||
/* set "node change active" indicator */
|
||||
MULTIOS_ATOMIC_ADD(&portInfo->usage, PORT_NODE_CHANGE_ACTIVE);
|
||||
|
||||
/* perform "node joined" callback on port's socket */
|
||||
theSocket = portInfo->socket;
|
||||
if (theSocket->options.optNodeJoinCallback) {
|
||||
theSocket->options.optNodeJoinCallback(
|
||||
mipc_sm_sock2sd(theSocket), nodeId);
|
||||
}
|
||||
|
||||
/*
|
||||
* clear "node change active" indicator;
|
||||
* if port can now complete a socket shutdown, wake it up
|
||||
*/
|
||||
portUsage = MULTIOS_ATOMIC_SUB(&portInfo->usage,
|
||||
PORT_NODE_CHANGE_ACTIVE);
|
||||
if (portUsage ==
|
||||
(PORT_NODE_CHANGE_ACTIVE | PORT_SHUTDOWN_ACTIVE)) {
|
||||
MULTIOS_SEM_UP(&portInfo->shutdownSem);
|
||||
}
|
||||
|
||||
portInfo++;
|
||||
}
|
||||
|
||||
(void)mipc_sm_node_show_up_update(busId, nodeId);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_node_down - react to a node leaving a bus
|
||||
*
|
||||
* Note: This routine is called during processing of MIPC events.
|
||||
*/
|
||||
void mipc_sm_node_down(uint16_t busId, uint16_t nodeId)
|
||||
{
|
||||
struct mipc_sm_local_bus_info *busInfo = &mipcSmLocalBusInfo[busId];
|
||||
struct mipc_sm_local_port_info *portInfo;
|
||||
struct mipc_sm_socket *theSocket;
|
||||
MULTIOS_ATOMIC_VAL portUsage;
|
||||
uint16_t portIndex;
|
||||
|
||||
MIPCDBG("Detected node %u.%u down\n", busId, nodeId);
|
||||
|
||||
(void)mipc_sm_node_show_down_update(busId, nodeId);
|
||||
|
||||
/* Examine all ports > 0 to see if any are affected by failed node */
|
||||
|
||||
portInfo = &busInfo->port_info[1];
|
||||
for (portIndex = 1; portIndex < busInfo->ownMaxPorts; portIndex++) {
|
||||
|
||||
/* set "node change active" indicator */
|
||||
MULTIOS_ATOMIC_ADD(&portInfo->usage, PORT_NODE_CHANGE_ACTIVE);
|
||||
|
||||
/* perform "node left" callback on port's socket */
|
||||
theSocket = portInfo->socket;
|
||||
if (theSocket->options.optNodeLeftCallback) {
|
||||
theSocket->options.optNodeLeftCallback(
|
||||
mipc_sm_sock2sd(theSocket), nodeId);
|
||||
}
|
||||
|
||||
/* handle severing of connection to port's socket */
|
||||
if (theSocket->connRequired &&
|
||||
(theSocket->peer.nodeNum == nodeId)) {
|
||||
if (theSocket->connState == MIPC_SM_CONN_UP) {
|
||||
/* let socket know connection has failed */
|
||||
theSocket->connState = MIPC_SM_CONN_PEER_RST;
|
||||
if (theSocket->options.optDisconnectedCallback) {
|
||||
theSocket->options.optDisconnectedCallback(
|
||||
mipc_sm_sock2sd(theSocket));
|
||||
}
|
||||
mipc_sm_socket_do_sync(&theSocket->rxWait);
|
||||
mipc_sm_socket_do_sync(&theSocket->txWait);
|
||||
}
|
||||
else if (theSocket->connState == MIPC_SM_CONN_SENT_SYN) {
|
||||
/* let socket know connection attempt has failed */
|
||||
theSocket->connState = MIPC_SM_CONN_PEER_NAK;
|
||||
if (theSocket->options.optConnectRefusedCallback) {
|
||||
theSocket->options.optConnectRefusedCallback(
|
||||
mipc_sm_sock2sd(theSocket));
|
||||
}
|
||||
mipc_sm_socket_do_sync(&theSocket->rxWait);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* clear "node change active" indicator;
|
||||
* if port can now complete a socket shutdown, wake it up
|
||||
*/
|
||||
portUsage = MULTIOS_ATOMIC_SUB(&portInfo->usage,
|
||||
PORT_NODE_CHANGE_ACTIVE);
|
||||
if (portUsage ==
|
||||
(PORT_NODE_CHANGE_ACTIVE | PORT_SHUTDOWN_ACTIVE)) {
|
||||
MULTIOS_SEM_UP(&portInfo->shutdownSem);
|
||||
}
|
||||
|
||||
portInfo++;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _node_send_internal_event - send an internal event to port 0 on a bus
|
||||
*
|
||||
* This routine runs at interrupt level and should do only lightweight work.
|
||||
*/
|
||||
static int _node_send_internal_event(uint16_t busId, uint16_t cmd,
|
||||
uint64_t data)
|
||||
{
|
||||
struct mipc_sm_local_bus_info *busInfo = &mipcSmLocalBusInfo[busId];
|
||||
MipcSmBasicEvent *event;
|
||||
struct mipc_sockaddr addr;
|
||||
int rc;
|
||||
|
||||
event = mipc_sm_basic_event_alloc(busInfo->dummy_socket,
|
||||
MIPC_SM_CONN_SIG_TYPE_INVALID);
|
||||
if (event) {
|
||||
event->data = MULTIOS_hton64(data);
|
||||
addr.busNum = busId;
|
||||
addr.nodeNum = mipc_node_id;
|
||||
addr.portNum = 0;
|
||||
(void) mipc_sm_event_send((MipcSmEvent *)event, &addr, cmd);
|
||||
rc = MIPC_OK;
|
||||
} else {
|
||||
rc = -MIPC_ENOMEM;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _node_peer_audit - check status of peer nodes on a bus
|
||||
*
|
||||
* This routine runs at interrupt level and should do only lightweight work.
|
||||
*/
|
||||
static void _node_peer_audit(uint16_t busId)
|
||||
{
|
||||
struct mipc_sm_bus *bus = mipc_sm_bus_ptr_valid(busId);
|
||||
struct mipc_sm_local_bus_info *busInfo = &mipcSmLocalBusInfo[busId];
|
||||
struct mipc_sm_node *peerNode;
|
||||
struct mipc_sm_local_peer_info *peerInfo;
|
||||
MULTIOS_ATOMIC_VAL newState;
|
||||
uint16_t nodeId;
|
||||
uint16_t lastNode;
|
||||
|
||||
peerNode = mipc_sm_node_ptr_valid(busId, 0);
|
||||
peerInfo = busInfo->peer_info;
|
||||
lastNode = mipc_sm_bus_get_max_nodes(bus);
|
||||
|
||||
for (nodeId = 0; nodeId < lastNode; nodeId++, peerNode++, peerInfo++) {
|
||||
newState = MULTIOS_ntoh32(peerNode->state);
|
||||
|
||||
if (peerInfo->is_up) {
|
||||
if (((newState == peerInfo->state) &&
|
||||
!(mipcSmSystem->sysOpts & MIPC_SYSOPT_DEBUG_FLG)) ||
|
||||
((newState ^ peerInfo->state) & ~NODE_HB_MASK)) {
|
||||
if (_node_send_internal_event(
|
||||
busId, MIPC_SM_CMD_NODE_STATUS,
|
||||
nodeId) == MIPC_OK) {
|
||||
peerInfo->is_up = 0;
|
||||
peerInfo->state = newState;
|
||||
|
||||
/*
|
||||
* Request memory audit to recover
|
||||
* lost buffers and events
|
||||
*
|
||||
* Note: Do audit on 2nd upcoming tick,
|
||||
* not first one; this helps prevent a
|
||||
* 2nd audit request if multiple nodes
|
||||
* fail simultaneously, but with a skew
|
||||
* in their heartbeat updates
|
||||
*/
|
||||
|
||||
if (!busInfo->memAuditCountdown) {
|
||||
busInfo->memAuditCountdown = 2;
|
||||
}
|
||||
} else {
|
||||
/* Re-detect node down on next audit */
|
||||
}
|
||||
} else {
|
||||
/* Node is still up */
|
||||
peerInfo->state = newState;
|
||||
}
|
||||
} else {
|
||||
if ((newState != peerInfo->state) &&
|
||||
!((newState ^ peerInfo->state) & ~NODE_HB_MASK)) {
|
||||
if (_node_send_internal_event(
|
||||
busId, MIPC_SM_CMD_NODE_STATUS,
|
||||
nodeId | (1U << 16)) == MIPC_OK) {
|
||||
peerInfo->is_up = 1;
|
||||
peerInfo->state = newState;
|
||||
} else {
|
||||
/* Re-detect node up on next audit */
|
||||
}
|
||||
} else {
|
||||
/* Node is still down */
|
||||
peerInfo->state = newState;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _node_heartbeat_timer - node heartbeat routine
|
||||
*
|
||||
* This routine runs at interrupt level and should do only lightweight work.
|
||||
*/
|
||||
static void _node_heartbeat_timer(MULTIOS_TIMER_ARG arg)
|
||||
{
|
||||
uint16_t busId = (uint16_t)arg;
|
||||
struct mipc_sm_local_bus_info *busInfo = &mipcSmLocalBusInfo[busId];
|
||||
struct mipc_sm_node *node = mipc_sm_node_ptr_valid(busId, mipc_node_id);
|
||||
MULTIOS_ATOMIC_VAL nodeState;
|
||||
|
||||
/* Handle a user-initiated MIPC reset request */
|
||||
|
||||
switch (mipc_reset_state) {
|
||||
case MIPC_RESET_NONE:
|
||||
break;
|
||||
case MIPC_RESET_NODE:
|
||||
/* leave SM intact & simply restart node */
|
||||
mipc_reset_state = MIPC_RESET_IN_PROGRESS;
|
||||
mipc_sm_adapt_fatal_error("MIPC node reset forced");
|
||||
return;
|
||||
case MIPC_RESET_SYSTEM:
|
||||
/* invalidate system struct (forces system re-initialization) */
|
||||
mipc_reset_state = MIPC_RESET_IN_PROGRESS;
|
||||
MULTIOS_ATOMIC_SET(&mipcSmSystem->state,
|
||||
MULTIOS_ATOMIC_GET(&mipcSmSystem->state) |
|
||||
SYSTEM_MEM_STATE_MASK);
|
||||
break;
|
||||
case MIPC_RESET_IN_PROGRESS:
|
||||
/* reset in progress -- wait for it to complete */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check that MIPC's SM area hasn't been re-initialized */
|
||||
|
||||
if ((MULTIOS_ATOMIC_GET(&mipcSmSystem->state) & SYSTEM_SIG_MASK) !=
|
||||
mipc_sm_sys_signature) {
|
||||
mipc_sm_adapt_fatal_error("MIPC SM state change detected");
|
||||
}
|
||||
|
||||
/* Update node's heartbeat on bus to indicate it is (still) alive */
|
||||
|
||||
nodeState = MULTIOS_ntoh32(node->state);
|
||||
nodeState += NODE_HB_INCREMENT;
|
||||
node->state = MULTIOS_hton32(nodeState);
|
||||
|
||||
/* Request a memory audit, if it is time for one */
|
||||
|
||||
if (busInfo->memAuditCountdown) {
|
||||
busInfo->memAuditCountdown--;
|
||||
if (busInfo->memAuditCountdown == 0) {
|
||||
if (_node_send_internal_event(
|
||||
busId, MIPC_SM_CMD_MEM_AUDIT, 0)) {
|
||||
busInfo->memAuditCountdown = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check status of the other nodes on bus every N-th heartbeat */
|
||||
|
||||
if ((((nodeState >> NODE_HB_SHIFT) + busId) &
|
||||
(MIPC_HB_PROBE_INTERVAL - 1)) == 0) {
|
||||
_node_peer_audit(busId);
|
||||
}
|
||||
|
||||
/* Restart the heartbeat timer */
|
||||
|
||||
MULTIOS_TIMER_START(busInfo->heartbeatTimerId,
|
||||
MULTIOS_ntoh16(mipcSmSystem->heartbeatPeriod),
|
||||
_node_heartbeat_timer,
|
||||
(MULTIOS_TIMER_ARG)arg);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_node_init - initialize a MIPC-SM node on a bus
|
||||
*/
|
||||
|
||||
int mipc_sm_node_init(struct mipc_sm_sys_config *sysConfig,
|
||||
struct mipc_sm_bus_config *busConfig,
|
||||
struct mipc_sm_node_config *nodeConfig)
|
||||
{
|
||||
MULTIOS_ATOMIC_VAL origNodeState;
|
||||
MULTIOS_ATOMIC_VAL newNodeState;
|
||||
struct mipc_sm_node *node;
|
||||
struct mipc_sm_node *peerNode;
|
||||
struct mipc_sm_local_bus_info *busInfo;
|
||||
MipcSmPort *portArray;
|
||||
uint16_t busId;
|
||||
uint16_t nodeId;
|
||||
uint16_t cpuId;
|
||||
uint16_t portId;
|
||||
uint16_t peerNodeId;
|
||||
size_t numPortBytes;
|
||||
int memAuditDelay;
|
||||
int rc;
|
||||
|
||||
busId = busConfig->number;
|
||||
nodeId = mipc_node_id;
|
||||
cpuId = mipc_cpu_id;
|
||||
node = mipc_sm_node_ptr_valid(busId, nodeId);
|
||||
|
||||
/*
|
||||
* Update node state to reflect new incarnation of node
|
||||
*
|
||||
* Heartbeat is set to 0xFC; this ensures that peer nodes on bus 0
|
||||
* will be audited on the first tick of the node's heartbeat timer.
|
||||
*
|
||||
* Also note that there is no risk that other nodes will attempt to
|
||||
* interact with this node while it is still initializing itself,
|
||||
* since they won't see this node as "alive" until after that first
|
||||
* timer tick changes this node's heartbeat.
|
||||
*/
|
||||
|
||||
origNodeState = MULTIOS_ntoh32(node->state);
|
||||
newNodeState = origNodeState + NODE_INCARN_INCREMENT;
|
||||
newNodeState = (newNodeState & NODE_INCARN_MASK) |
|
||||
(NODE_HB_MASK | (nodeId << 16) | mipc_sm_sys_signature);
|
||||
node->state = MULTIOS_hton32(newNodeState);
|
||||
|
||||
/* Establish shared memory data structures used for this bus */
|
||||
|
||||
if ((origNodeState & SYSTEM_SIG_MASK) != mipc_sm_sys_signature) {
|
||||
|
||||
/* Node has never existed during this incarnation of system */
|
||||
MIPCDBG("Initializing SM for node %u on bus %u\n",
|
||||
nodeId, busId);
|
||||
|
||||
node->versionMajor = MIPC_VERSION_MAJOR;
|
||||
node->versionMinor = MIPC_VERSION_MINOR;
|
||||
|
||||
node->reserved = 0;
|
||||
|
||||
/* Allocate node's packet pool (and initialize it) */
|
||||
|
||||
rc = mipc_sm_packet_pool_init(&node->packetPool,
|
||||
nodeConfig->nBuffers,
|
||||
nodeConfig->mtu);
|
||||
if (rc != MIPC_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Allocate node's event pool (and initialize it) */
|
||||
|
||||
rc = mipc_sm_event_pool_init(&node->eventPool,
|
||||
(uint16_t)nodeConfig->nEvents,
|
||||
(uint16_t)sizeof(MipcSmBasicEvent));
|
||||
if (rc != MIPC_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Allocate node's port array (but don't initialize them yet) */
|
||||
|
||||
rc = mipc_sm_mem_region_alloc(&mipcSmSystem->memPool,
|
||||
(MIPC_MEMSIZE)(nodeConfig->maxPorts * sizeof(MipcSmPort)),
|
||||
&node->portsOffset);
|
||||
if (rc != MIPC_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
node->maxPorts = MULTIOS_hton16(nodeConfig->maxPorts);
|
||||
node->portsOffset = MULTIOS_hton32(node->portsOffset);
|
||||
|
||||
/* Set up node's statistics area */
|
||||
|
||||
node->statsOffset = MULTIOS_hton32(0);
|
||||
node->reservedOffset = 0;
|
||||
|
||||
/* No memory audit required */
|
||||
|
||||
memAuditDelay = 0;
|
||||
|
||||
if (busId == mipc_bus_default) {
|
||||
mipc_reset_log |= MIPC_RESET_LOG_NODE;
|
||||
}
|
||||
} else {
|
||||
/* Node has previously existed in this incarnation of system */
|
||||
MIPCDBG("Re-using SM for node %u on bus %u\n",
|
||||
nodeId, busId);
|
||||
|
||||
/* Memory audit is needed once status of all nodes is known */
|
||||
|
||||
memAuditDelay = MIPC_HB_PROBE_INTERVAL + 1;
|
||||
}
|
||||
|
||||
/* Allocate local memory data structures needed for this bus */
|
||||
|
||||
busInfo = &mipcSmLocalBusInfo[busId];
|
||||
|
||||
numPortBytes =
|
||||
nodeConfig->maxPorts * sizeof(struct mipc_sm_local_port_info);
|
||||
busInfo->port_info = mipc_alloc_local_port_info(busId, nodeConfig->maxPorts);
|
||||
if (!busInfo->port_info)
|
||||
goto no_port;
|
||||
|
||||
busInfo->peer_info = mipc_alloc_local_peer_info(busId, busConfig->maxNodes);
|
||||
if (!busInfo->peer_info)
|
||||
goto no_peer;
|
||||
|
||||
busInfo->dummy_socket = mipc_alloc_socket(1);
|
||||
if (!busInfo->dummy_socket)
|
||||
goto no_sock;
|
||||
|
||||
busInfo->heartbeatTimerId = MULTIOS_TIMER_CREATE();
|
||||
if (!busInfo->heartbeatTimerId)
|
||||
goto no_timer;
|
||||
|
||||
/* Initialize local memory data structures used for this bus */
|
||||
|
||||
busInfo->ownNode = node;
|
||||
|
||||
busInfo->ownPorts =
|
||||
(MipcSmPort *)mipc_offset2addr_ntoh(node->portsOffset);
|
||||
memset(busInfo->port_info, 0, numPortBytes);
|
||||
busInfo->ownMaxPorts = nodeConfig->maxPorts;
|
||||
busInfo->maxNodes = busConfig->maxNodes;
|
||||
MULTIOS_SEM_INIT_FULL(&busInfo->portAllocLock);
|
||||
busInfo->memAuditCountdown = memAuditDelay;
|
||||
|
||||
/* Initialize dummy port */
|
||||
|
||||
MULTIOS_ATOMIC_SET(&dummy_port.state, EVENT_INDEX_INVALID);
|
||||
|
||||
/* Initialize dummy socket */
|
||||
|
||||
mipc_sock_init(busInfo->dummy_socket, MIPC_SOCK_RDM);
|
||||
busInfo->dummy_socket->addr.busNum = busId;
|
||||
busInfo->dummy_socket->addr.nodeNum = nodeId;
|
||||
busInfo->dummy_socket->addr.portNum = MIPC_SM_PORT_INVALID_SOCKET;
|
||||
busInfo->dummy_socket->nodeptr = node;
|
||||
busInfo->dummy_socket->port = &dummy_port;
|
||||
/* note: "portInfo" field is left NULL */
|
||||
busInfo->dummy_socket->statsPtr = mipcSmLocalBusInfo[busId].stats;
|
||||
|
||||
/* Initialize all ports (both SM and local memory portions) */
|
||||
|
||||
portArray = mipc_offset2addr_ntoh(node->portsOffset);
|
||||
|
||||
for (portId = 0; portId < nodeConfig->maxPorts; portId++) {
|
||||
/* Reset port back to virgin state */
|
||||
mipc_sm_port_init(portArray + portId);
|
||||
/* Associate port with dummy socket */
|
||||
busInfo->port_info[portId].socket = busInfo->dummy_socket;
|
||||
/* Initialize fields used during socket shutdown */
|
||||
MULTIOS_SEM_INIT(&busInfo->port_info[portId].shutdownSem);
|
||||
/* port_info[portId].usage is already 0 -- no need to init it */
|
||||
}
|
||||
|
||||
/* Reserve port 0 for use by MIPC */
|
||||
|
||||
busInfo->port_info[0].allocated = 1;
|
||||
busInfo->port_info[0].socket = busInfo->dummy_socket;
|
||||
|
||||
/* Now initialize rest of node structure on bus */
|
||||
|
||||
node->qos = MULTIOS_hton16(nodeConfig->qos);
|
||||
node->cpuId = MULTIOS_hton16(cpuId);
|
||||
node->intId = MULTIOS_hton16(nodeConfig->intId);
|
||||
|
||||
MULTIOS_ATOMIC_SET(&node->eventQueueState, 0);
|
||||
MULTIOS_ATOMIC_SET(&node->eventTailOffset, 0);
|
||||
|
||||
/* Capture current state of all nodes on the bus */
|
||||
|
||||
for (peerNodeId = 0; peerNodeId < busConfig->maxNodes; peerNodeId++) {
|
||||
peerNode = mipc_sm_node_ptr_valid(busId, peerNodeId);
|
||||
busInfo->peer_info[peerNodeId].state =
|
||||
MULTIOS_ntoh32(peerNode->state);
|
||||
busInfo->peer_info[peerNodeId].is_up = 0;
|
||||
}
|
||||
busInfo->peer_info[nodeId].is_up = 1;
|
||||
|
||||
return MIPC_OK;
|
||||
|
||||
/* Abnormal exit points used when unable to alloc from local memory */
|
||||
no_timer:
|
||||
mipc_free_socket(busInfo->dummy_socket);
|
||||
no_sock:
|
||||
mipc_free_local_peer_info(busInfo->peer_info);
|
||||
no_peer:
|
||||
mipc_free_local_port_info(busInfo->port_info);
|
||||
no_port:
|
||||
return -MIPC_ENOMEM;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_node_heartbeat_start - start the heartbeart timer of a given bus
|
||||
*/
|
||||
|
||||
void mipc_sm_node_heartbeat_start(struct mipc_sm_sys_config *sysConfig,
|
||||
struct mipc_sm_bus_config *currBusConfig)
|
||||
{
|
||||
struct mipc_sm_local_bus_info *busInfo;
|
||||
uint16_t busId;
|
||||
|
||||
busId = currBusConfig->number;
|
||||
busInfo = &mipcSmLocalBusInfo[busId];
|
||||
|
||||
if(mipcSmLocalBusInfo[busId].activeOnBus != 1)
|
||||
return;
|
||||
|
||||
MIPCDBG("mipc start timer timerid=%p bus=%u\n", busInfo->heartbeatTimerId,
|
||||
busId);
|
||||
MULTIOS_TIMER_START(busInfo->heartbeatTimerId,
|
||||
sysConfig->heartbeatPeriod,
|
||||
_node_heartbeat_timer,
|
||||
(MULTIOS_TIMER_ARG)busId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
/* mipc_sm_node.h - MIPC-SM nodes */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
02f,12dec12,zhw Move define of MIPC_HB_PROBE_INTERVAL to here
|
||||
02e,16jun11,zhw Fix bug of buffer reclaiming (WIND00278985)
|
||||
02d,07jan11,jlk Update license header
|
||||
02c,07aug10,wy1 add the api mipc_sm_node_heartbeat_start (fix WIND00226071)
|
||||
02f,26aug10,jlk Make sure #ifdef __cplusplus starts after #includes
|
||||
02e,10aug10,wy1 add mipc_sm_node_heartbeat_start calls
|
||||
02d,18mar10,jag add Linux procfs framework calls
|
||||
02c,30mar10,als Initial changes in support of 64-bit memory addressing
|
||||
02b,01oct09,als Finalize versioning info in shared memory
|
||||
02a,14sep09,als Enhance node restart capability
|
||||
01z,26aug09,als Cleanup issues with flow control rework
|
||||
01y,25aug09,jlk WIND00178668 - MIPC flow control changes.
|
||||
01x,20aug09,als Add node restart support
|
||||
01w,19aug09,als Fix bug in bus initialization code (WIND00177423)
|
||||
01v,14aug09,als Revise internals of event-based code
|
||||
01u,11aug09,als Revise event exchange code to improve robustness
|
||||
01t,07aug09,ebh Remove unused routine and code inspection updates
|
||||
01s,07aug09,als Convert return value of routine to void
|
||||
01r,06aug09,als Move port's socket id out of shared memory
|
||||
01q,04aug09,als Convert shared memory offsets to use MIPC_OFFSET type
|
||||
01p,29jul09,als Add support for per-bus statistics collection
|
||||
01o,27jul09,als Event queue rework
|
||||
01n,24jul09,jlk Event Q rework.
|
||||
01m,23jul09,als Move port allocation semaphore from SM to local memory
|
||||
01l,02jul09,als Changes to reflect updated file names
|
||||
01k,02jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01j,29may09,als Revise configuration based on MIPC 2.0 HLD feedback
|
||||
01i,26may09,ebh Code Inspection Modifications
|
||||
01h,01may09,ebh Add routine to return port and node information
|
||||
01g,24apr09,ebh Add in txEventsCount
|
||||
01f,25mar09,ebh Remove unused variable
|
||||
01e,24mar09,ebh Make inlines static and use MULTIOS_INLINE
|
||||
01d,16mar09,ebh Track number of buffers outstanding on a socket to prevent
|
||||
starvation
|
||||
01c,19feb09,ebh Adjust usage of the MIPC_SO_MTU information to validate on
|
||||
bind
|
||||
01b,13feb09,ebh Update statistics
|
||||
01a,25nov08,apa Initial version
|
||||
*/
|
||||
|
||||
#ifndef __INC_mipc_sm_node_h
|
||||
#define __INC_mipc_sm_node_h
|
||||
|
||||
#include "mipc_sm_packet_pool.h"
|
||||
#include "mipc_sm_port.h"
|
||||
#include "mipc_sm_system.h"
|
||||
#include "mipc_sm_bus.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct mipc_sm_node_config;
|
||||
struct mipc_sm_bus_config;
|
||||
|
||||
/* MIPC node structure (resides in SM) */
|
||||
|
||||
struct mipc_sm_node
|
||||
{
|
||||
MULTIOS_ATOMIC_VAL state; /* node state */
|
||||
uint8_t versionMajor; /* X digit of MIPC X.Y */
|
||||
uint8_t versionMinor; /* Y digit of MIPC X.Y */
|
||||
uint16_t reserved; /* currently unused */
|
||||
int16_t qos; /* event processing QOS */
|
||||
uint16_t cpuId; /* event processing CPU */
|
||||
uint16_t intId; /* event processing interrupt */
|
||||
uint16_t maxPorts; /* # ports in SM port array */
|
||||
MIPC_OFFSET portsOffset; /* offset of SM port array*/
|
||||
MIPC_OFFSET statsOffset; /* reserved for future use */
|
||||
MULTIOS_ATOMIC_VAL reservedOffset; /* reserved for future use */
|
||||
MULTIOS_ATOMIC eventQueueState; /* state of event queue */
|
||||
MULTIOS_ATOMIC eventTailOffset; /* offset of tail event in queue */
|
||||
MipcSmEventPool eventPool; /* pool of basic events */
|
||||
MipcSmPacketPool packetPool; /* pool of buffers */
|
||||
};
|
||||
|
||||
/*
|
||||
* Node state info is held in a non-atomic variable with the following format:
|
||||
*
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | heartbeat | node id |node incarnation | sys signature |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
*
|
||||
* |--------- node signature ----------|
|
||||
*
|
||||
* System signature records the MIPC system signature that existed at the time
|
||||
* the node structure was initialized.
|
||||
*
|
||||
* Node incarnation is a counter that is incremented every time the node is
|
||||
* (re)started.
|
||||
*
|
||||
* Together, the low order 16 bits form a "node signature", which is different
|
||||
* for each incarnation of the node and is constant during its lifetime. The
|
||||
* signature allows a node determine if it needs to (re)initialize its node
|
||||
* structure upon startup.
|
||||
*
|
||||
* Node id records the node's own id. Together with the node signature, it is
|
||||
* used in recovering lost buffers and events following a restart of the node.
|
||||
*
|
||||
* Hearbeat is a counter that is regularly incremented while the node is
|
||||
* operational. The changing count allows other nodes to detect if a node
|
||||
* becomes non-operational.
|
||||
*
|
||||
* Note: Unlike the MIPC system and port states, this field is non-atomic
|
||||
* because it is altered by the node itself (in a single-threaded manner),
|
||||
* and not by other nodes.
|
||||
*/
|
||||
|
||||
#define NODE_SIG_MASK 0x0000FFFFU
|
||||
#define NODE_INCARN_MASK 0x0000FF00U
|
||||
#define NODE_INCARN_INCREMENT 0x00000100U
|
||||
#define NODE_ID_MASK 0x03FF0000U
|
||||
#define NODE_HB_MASK 0xFC000000U
|
||||
#define NODE_HB_INCREMENT 0x04000000U
|
||||
#define NODE_HB_SHIFT 26
|
||||
|
||||
#define MIPC_SM_NODE_MAX_PORTS 1024
|
||||
|
||||
#define MIPC_INVALID_NODE 0xffff
|
||||
|
||||
/* # of heartbeats between checks of peer node status (must be a power of 2) */
|
||||
|
||||
#define MIPC_HB_PROBE_INTERVAL 4
|
||||
|
||||
struct mipc_sm_node *mipc_sm_node_ptr(uint16_t busId, uint16_t nodeId);
|
||||
struct mipc_sm_node *mipc_sm_node_ptr_valid(uint16_t busId, uint16_t nodeId);
|
||||
|
||||
static MULTIOS_INLINE int mipc_sm_node_is_up(uint16_t busId, uint16_t nodeId)
|
||||
{
|
||||
return (mipc_sm_node_ptr(busId, nodeId) &&
|
||||
mipcSmLocalBusInfo[busId].peer_info[nodeId].is_up);
|
||||
}
|
||||
|
||||
void mipc_sm_node_pool_audit(uint16_t busId, MipcSmEventPool *pool, int isBuf);
|
||||
void mipc_sm_node_up(uint16_t busId, uint16_t nodeId);
|
||||
void mipc_sm_node_down(uint16_t busId, uint16_t nodeId);
|
||||
|
||||
int mipc_sm_node_init(struct mipc_sm_sys_config *sysConfig,
|
||||
struct mipc_sm_bus_config *busConfig,
|
||||
struct mipc_sm_node_config *nodeConfig);
|
||||
|
||||
/* show routine hooks (needed for Linux procfs handling) */
|
||||
|
||||
extern int(*mipc_sm_node_show_up_update)(uint16_t, uint16_t);
|
||||
extern int(*mipc_sm_node_show_down_update)(uint16_t, uint16_t);
|
||||
|
||||
extern void mipc_sm_node_heartbeat_start(struct mipc_sm_sys_config *sysConfig,
|
||||
struct mipc_sm_bus_config *currBusConfig);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INC_mipc_sm_node_h */
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
/* mipc_sm_packet_pool.c - MIPC-SM packet pools */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
02a,07jan11,jlk Update license header
|
||||
01z,03mar10,als Add support for 64-bit memory addressing
|
||||
01y,27sep09,als Fix bugs in receive routines (WIND00183445, WIND00183399)
|
||||
01x,17sep09,als Enhance node restart capability
|
||||
01w,11sep09,bwa replace sems by sync objects given only when requested
|
||||
01v,09sep09,als Correct minor statistics collection issues
|
||||
01u,03sep09,als Display actual number of allocated buffers in show commands
|
||||
01t,26aug09,als Cleanup issues with flow control rework
|
||||
01s,25aug09,jlk WIND00178668 - MIPC flow control changes and clean-up.
|
||||
01r,20aug09,als Fix bug in creation of packet pool
|
||||
01q,14aug09,als Revise internals of event-based code
|
||||
01p,12aug09,als Improve robustness of packet pool
|
||||
01o,10aug09,ebh Make mipc_sm_packet_pool_buffer_ptr() an inline routine
|
||||
01n,04aug09,als Convert shared memory offsets to use MIPC_OFFSET type
|
||||
01m,24jul09,jlk Event Q rework.
|
||||
01l,25jun09,als Rework memory region code to fix WIND00167982
|
||||
01k,16jun09,ebh Fix extra freeing of buffer
|
||||
01j,13jun09,ebh Changes from performance review
|
||||
01i,09jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01h,26may09,ebh Code Inspection Modifications
|
||||
01g,14may09,dcc moved MIPC_SM_PACKET_POOL_NO_BUFFER_OWNER declaration to
|
||||
mipc_sm_packet_pool.h. Added buffer reclamation support.
|
||||
01f,30apr09,ebh Ensure that mipc.h is included first
|
||||
01e,16apr09,ebh Ensure that mipc_zalloc() does not block on out of range
|
||||
buffer size
|
||||
01d,24mar09,ebh Keep packetSize in host byte order, but store a network byte
|
||||
order version for sexternal use
|
||||
01c,16mar09,ebh Track number of buffers outstanding on a socket to prevent
|
||||
starvation
|
||||
01b,18feb09,ebh Collapse 3 packet pools into a single pool per bus
|
||||
01a,25nov08,apa Initial version.
|
||||
*/
|
||||
|
||||
#include "mipc_sm_core.h"
|
||||
#include "mipc_sm_event_queue.h"
|
||||
#include "mipc_sm_packet_pool.h"
|
||||
#include "mipc_sm_system.h"
|
||||
#include "mipc_sm_socket.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_packet_pool_init - Initialize a pool of buffers.
|
||||
*/
|
||||
int mipc_sm_packet_pool_init(MipcSmPacketPool *pool,
|
||||
uint32_t numBuffers, uint32_t mtu)
|
||||
{
|
||||
MIPC_OFFSET bufsOffset;
|
||||
MipcSmPacketDesc *desc;
|
||||
uint32_t bufferIndex;
|
||||
MIPC_MEMSIZE bufDataSize;
|
||||
int rc;
|
||||
|
||||
/* Allocate array of (aligned) buffer data areas */
|
||||
bufDataSize = ALIGN_UP((MIPC_OFFSET)mtu);
|
||||
rc = mipc_sm_mem_region_alloc(&mipcSmSystem->memPool,
|
||||
numBuffers * bufDataSize,
|
||||
&bufsOffset);
|
||||
if (rc != MIPC_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Allocate pool of buffer descriptors */
|
||||
rc = mipc_sm_event_pool_init(&pool->eventPool,
|
||||
(uint16_t)numBuffers,
|
||||
(uint16_t)sizeof(MipcSmPacketDesc));
|
||||
if (rc != MIPC_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Initialize rest of packet pool structure */
|
||||
pool->bufsOffset = MULTIOS_hton32(bufsOffset);
|
||||
pool->packetSize = MULTIOS_hton32(mtu);
|
||||
|
||||
/* Finish initializing buffer descriptors (event field already done) */
|
||||
desc = (MipcSmPacketDesc *)mipc_offset2addr_ntoh(
|
||||
pool->eventPool.eventsOffset);
|
||||
for (bufferIndex = 0; bufferIndex < numBuffers; bufferIndex++) {
|
||||
desc->bufOffset = MULTIOS_hton32(bufsOffset);
|
||||
/* leave "bufLen" field unset */
|
||||
bufsOffset += bufDataSize;
|
||||
desc = (MipcSmPacketDesc *)((char *)desc +
|
||||
MULTIOS_ntoh16(pool->eventPool.eventSize));
|
||||
}
|
||||
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* _txbuf_avail_condition_met - test if there is an available tx buffer
|
||||
*
|
||||
* For use as mipc_sm_socket_wait() fourth parameter
|
||||
*/
|
||||
static int _txbuf_avail_condition_met(MipcSmSocket *s)
|
||||
{
|
||||
MULTIOS_ATOMIC_VAL portState = MULTIOS_ATOMIC_GET(&s->port->state);
|
||||
|
||||
return ((portState & EVENT_INDEX_MASK) != EVENT_INDEX_INVALID);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_api_packet_alloc - Allocate a buffer from port's private list
|
||||
*
|
||||
* Note that theSocket->port must be valid before calling this routine
|
||||
*/
|
||||
int mipc_sm_packet_alloc(MipcSmSocket *theSocket, int flags,
|
||||
MipcSmPacketDesc **bufDesc, uint8_t **buffer)
|
||||
{
|
||||
MipcSmPacketDesc *desc; /* packet descriptor pointer */
|
||||
int rc; /* return code from function calls */
|
||||
|
||||
/* try to grab a packet from port's private list */
|
||||
desc = mipc_sm_port_packet_get(theSocket->port,
|
||||
&theSocket->nodeptr->packetPool.eventPool);
|
||||
if (desc) {
|
||||
MIPC_STATS_ADD(theSocket->statsPtr, MIPC_STATS_BUFS_ALLOCATED, 1);
|
||||
*bufDesc = desc;
|
||||
*buffer = mipc_sm_packet_data_ptr(desc);
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/* no packets available -- quit if we don't want to wait for it */
|
||||
if ((!theSocket->options.optBlocking) || (flags & MIPC_MSG_DONTWAIT)) {
|
||||
MIPC_STATS_ADD(theSocket->statsPtr,
|
||||
MIPC_STATS_BUF_CONG_NO_WAIT, 1);
|
||||
return -MIPC_EWOULDBLOCK;
|
||||
}
|
||||
|
||||
/* wait for packet to arrive */
|
||||
MIPC_STATS_ADD(theSocket->statsPtr, MIPC_STATS_BUF_CONG_WAIT, 1);
|
||||
rc = mipc_sm_socket_wait(theSocket, &theSocket->txWait,
|
||||
theSocket->options.optSendTimeout,
|
||||
_txbuf_avail_condition_met);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* see if a packet is now available */
|
||||
desc = mipc_sm_port_packet_get(theSocket->port,
|
||||
&theSocket->nodeptr->packetPool.eventPool);
|
||||
if (desc) {
|
||||
MIPC_STATS_ADD(theSocket->statsPtr, MIPC_STATS_BUFS_ALLOCATED, 1);
|
||||
*bufDesc = desc;
|
||||
*buffer = mipc_sm_packet_data_ptr(desc);
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle cases where semaphore was given for reasons other than
|
||||
* the packet list becoming non-empty
|
||||
*
|
||||
* (currently, the only way this happens is if a socket's connection
|
||||
* is broken while we are waiting for a buffer to send to peer)
|
||||
*/
|
||||
return -MIPC_ECONNABORTED;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_packet_free - Return a buffer to port's private list
|
||||
*/
|
||||
void mipc_sm_packet_free(MipcSmSocket *theSocket, MipcSmPacketDesc *bufDesc)
|
||||
{
|
||||
uint16_t busId;
|
||||
uint16_t srcNodeId;
|
||||
uint16_t srcPortId;
|
||||
struct mipc_sm_node *srcNode; /* source node structure */
|
||||
MipcSmPort *srcPort; /* source port structure */
|
||||
uint32_t portSig;
|
||||
MULTIOS_ATOMIC_VAL portState;
|
||||
struct mipc_sockaddr to; /* destination address */
|
||||
|
||||
MIPC_STATS_ADD(theSocket->statsPtr, MIPC_STATS_BUFS_FREED, 1);
|
||||
|
||||
/* locate port that sent packet */
|
||||
busId = theSocket->addr.busNum;
|
||||
|
||||
srcNodeId = MULTIOS_ntoh16(bufDesc->event.homeNode);
|
||||
srcNode = (struct mipc_sm_node *)mipc_offset2addr_ntoh(
|
||||
mipcSmBuses[busId].nodesOffset) + srcNodeId;
|
||||
|
||||
srcPortId = MULTIOS_ntoh16(bufDesc->event.srcPort);
|
||||
srcPort = (MipcSmPort *)mipc_offset2addr_ntoh(srcNode->portsOffset) +
|
||||
srcPortId;
|
||||
|
||||
portSig = MULTIOS_ntoh32(bufDesc->event.srcPortSig);
|
||||
|
||||
/* decide what to do with packet */
|
||||
restart:
|
||||
portState = MULTIOS_ATOMIC_GET(&srcPort->state);
|
||||
|
||||
/* if port signatures don't match, return packet to node's pool */
|
||||
if (portSig != (portState & PORT_SIG_MASK)) {
|
||||
MIPCDBG("port %u: freed obsolete packet directly\n", srcPortId);
|
||||
mipc_sm_event_free((MipcSmEvent *)bufDesc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if port's packet list is non-empty, give packet back to port */
|
||||
if ((portState & EVENT_INDEX_MASK) != EVENT_INDEX_INVALID) {
|
||||
bufDesc->event.userNodeInfo = srcNode->state;
|
||||
if (mipc_sm_port_packet_put(srcPort, portState, bufDesc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* a port state change prevented packet from being freed,
|
||||
* start decision process from the beginning
|
||||
*/
|
||||
goto restart;
|
||||
}
|
||||
|
||||
/*
|
||||
* port's packet list is empty, so send packet back to port
|
||||
* and let it free the packet & notify any waiting applications
|
||||
*/
|
||||
to.busNum = busId;
|
||||
to.nodeNum = srcNodeId;
|
||||
to.portNum = srcPortId;
|
||||
if (mipc_sm_event_send((MipcSmEvent *)bufDesc, &to,
|
||||
MIPC_SM_CMD_TXBUFAVAIL)) {
|
||||
/*
|
||||
* couldn't notify port because node is no longer active;
|
||||
* mark packet so node can reclaim it during restart
|
||||
*/
|
||||
bufDesc->event.userNodeInfo = EVENT_INVALID_USER_INFO;
|
||||
return;
|
||||
}
|
||||
MIPC_STATS_ADD(theSocket->statsPtr, MIPC_STATS_BUF_AVAIL_SENT, 1);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_packet_free_all - Free all packets owned by socket's port
|
||||
*/
|
||||
void mipc_sm_packet_free_all(MipcSmSocket *theSocket)
|
||||
{
|
||||
mipc_sm_port_packets_free(theSocket->addr.busNum,
|
||||
theSocket->addr.portNum,
|
||||
&theSocket->nodeptr->packetPool.eventPool);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/* mipc_sm_packet_pool.h - MIPC-SM packet pools */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01t,07jan11,jlk Update license header
|
||||
01s,26aug10,jlk Make sure #ifdef __cplusplus starts after #includes
|
||||
01r,24sep09,als Rename mipc_sm_api_events files to mipc_sm_event_pool
|
||||
01q,26aug09,als Cleanup issues with flow control rework
|
||||
01p,25aug09,jlk WIND00178668 - MIPC flow control changes and clean-up.
|
||||
01o,14aug09,als Revise internals of event-based code
|
||||
01n,12aug09,als Improve robustness of packet pool
|
||||
01m,10aug09,ebh Fix typo and make mipc_sm_packet_pool_buffer_ptr() an inline
|
||||
routine
|
||||
01l,04aug09,als Convert shared memory offsets to use MIPC_OFFSET type
|
||||
01k,02aug09,als Ensure buffer descriptor ownerport field is in network order
|
||||
01j,24jul09,jlk Event Q rework.
|
||||
01i,15jun09,ebh Change type of ownerport to uint16_t
|
||||
01h,09jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01g,26may09,ebh Code Inspection Modifications
|
||||
01f,13may09,dcc added buffer reclamation support
|
||||
01f,11may09,ebh Remove unused field in MipcSmPacketDesc
|
||||
01e,16apr09,ebh Remove size from the allocation of a zero-copy buffer
|
||||
01d,24mar09,ebh Keep packetSize in host byte order, but store a network byte
|
||||
order version for sexternal use
|
||||
01c,16mar09,ebh Track number of buffers outstanding on a socket to prevent
|
||||
starvation
|
||||
01b,18feb09,ebh Collapse 3 packet pools into a single pool per bus
|
||||
01a,25nov08,apa Initial version
|
||||
*/
|
||||
|
||||
#ifndef __INC_mipc_sm_packet_pool_h
|
||||
#define __INC_mipc_sm_packet_pool_h
|
||||
|
||||
#include "mipc_sm_event_pool.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct mipc_sm_packet_desc
|
||||
{
|
||||
MipcSmEvent event; /* buffer's event - MUST BE FIRST! */
|
||||
MIPC_OFFSET bufOffset; /* offset of buffer data area */
|
||||
uint32_t bufLen; /* # bytes used in buffer data area */
|
||||
} MipcSmPacketDesc;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MipcSmEventPool eventPool; /* pool of buffer descriptors */
|
||||
MIPC_OFFSET bufsOffset; /* offset of buffer array */
|
||||
uint32_t packetSize; /* buffer MTU */
|
||||
} MipcSmPacketPool;
|
||||
|
||||
|
||||
/* Initialize a packet pool */
|
||||
int mipc_sm_packet_pool_init(MipcSmPacketPool *pool,
|
||||
uint32_t numBuffers, uint32_t mtu);
|
||||
|
||||
/* Indicate if packet pool has a free oacket */
|
||||
static MULTIOS_INLINE int mipc_sm_packet_avail(MipcSmPacketPool *pool)
|
||||
{
|
||||
return mipc_sm_event_avail(&pool->eventPool);
|
||||
}
|
||||
|
||||
/*
|
||||
* Alloc/free packets from a socket's packet pool [= its private list]
|
||||
*/
|
||||
|
||||
int mipc_sm_packet_alloc(struct mipc_sm_socket *theSocket, int flags,
|
||||
MipcSmPacketDesc **bufDesc, uint8_t **buffer);
|
||||
|
||||
void mipc_sm_packet_free(struct mipc_sm_socket *theSocket,
|
||||
MipcSmPacketDesc *bufDesc);
|
||||
|
||||
void mipc_sm_packet_free_all(struct mipc_sm_socket *theSocket);
|
||||
|
||||
/* Return pointer to a packet's data area */
|
||||
|
||||
static MULTIOS_INLINE uint8_t *mipc_sm_packet_data_ptr(MipcSmPacketDesc *desc)
|
||||
{
|
||||
return mipc_offset2addr_ntoh(desc->bufOffset);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INC_mipc_sm_packet_pool_h */
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
/* mipc_sm_port.c - MIPC-SM ports */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011, 2013 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01v,30oct13,f_f Fixed the issue of checking return value (WIND00439645)
|
||||
01u,09aug13,f_f Fixed some coverity issues (WIND00429907)
|
||||
01t,07jan11,jlk Update license header
|
||||
01s,03mar10,als Add support for 64-bit memory addressing
|
||||
01r,23sep09,bwa add connection signature
|
||||
01q,11sep09,als Enhance node restart capability
|
||||
01p,09sep09,als Correct minor statistics collection issues
|
||||
01o,03sep09,als Init port packet list to empty; show actual # packets allocated
|
||||
01n,26aug09,als Cleanup issues with flow control rework
|
||||
01m,25aug09,jlk WIND00178668 - MIPC flow control changes and clean-up.
|
||||
01l,20aug09,als Add node restart support
|
||||
01k,17aug09,als Revise internals of event-based code
|
||||
01j,05aug09,als Move port's socket id out of shared memory
|
||||
01i,04aug09,als Convert shared memory offsets to use MIPC_OFFSET type
|
||||
01h,27jul09,als Event queue rework
|
||||
01g,24jul09,jlk Event Q rework.
|
||||
01f,25jun09,als Rework memory region code to fix WIND00167982
|
||||
01e,15jun09,ebh Change MULTIOS_CAS to MULTIOS_ATOMIC_CAS
|
||||
01d,08jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01c,01may09,ebh Add routine to return port and node information
|
||||
01b,30apr09,ebh Ensure that mipc.h is included first
|
||||
01a,25nov08,apa Initial version.
|
||||
*/
|
||||
|
||||
#include "mipc_sm_core.h"
|
||||
#include "mipc_sm_system.h"
|
||||
|
||||
/*
|
||||
* Dummy port. Dummy sockets point to this port, which is configured
|
||||
* to have a signature that doesn't match a valid (i.e. allocated) port
|
||||
* and has an empty packet list.
|
||||
*/
|
||||
struct mipc_sm_port dummy_port;
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_port_ptr - Return a pointer to a port given its ID
|
||||
*/
|
||||
MipcSmPort *mipc_sm_port_ptr(uint16_t busId, uint16_t nodeId, uint16_t portId)
|
||||
{
|
||||
struct mipc_sm_node *node = mipc_sm_node_ptr(busId, nodeId);
|
||||
|
||||
if (node && (portId < MULTIOS_ntoh16(node->maxPorts))) {
|
||||
return (MipcSmPort *)mipc_offset2addr_ntoh(node->portsOffset) +
|
||||
portId;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_port_init - Initialize a port
|
||||
*
|
||||
* This routine marks the port as unused by giving it a new signature (with a
|
||||
* low bit of 0), an empty packet list, and a state count of 0.
|
||||
*
|
||||
* Note: The new signature prevents other nodes from returning packets to the
|
||||
* port. The signature is not set to a specific initial value -- we simply
|
||||
* bump up whatever random signature the port had previously.
|
||||
*/
|
||||
void mipc_sm_port_init(MipcSmPort *port)
|
||||
{
|
||||
MULTIOS_ATOMIC_VAL newPortState;
|
||||
|
||||
newPortState = MULTIOS_ATOMIC_GET(&port->state);
|
||||
newPortState |= (PORT_SIG_INCREMENT | EVENT_INDEX_INVALID);
|
||||
newPortState += PORT_SIG_INCREMENT;
|
||||
newPortState &= (PORT_SIG_MASK | EVENT_INDEX_MASK);
|
||||
(void)MULTIOS_ATOMIC_SET(&port->state, newPortState);
|
||||
|
||||
port->reserved = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_port_alloc - Allocate an unused port
|
||||
*
|
||||
* This routine attempts to allocate an available port for use by a socket.
|
||||
* (The caller can request a specific port number or any available port.)
|
||||
*
|
||||
* The routine passes back the id of the port allocated (and its location in SM),
|
||||
* if allocation is successful.
|
||||
*/
|
||||
int mipc_sm_port_alloc(uint16_t busId, uint16_t portId, MipcSmPort **foundPort)
|
||||
{
|
||||
struct mipc_sm_local_bus_info *busInfo = &mipcSmLocalBusInfo[busId];
|
||||
struct mipc_sm_local_port_info *portInfo = busInfo->port_info;
|
||||
MipcSmPort *port;
|
||||
MULTIOS_ATOMIC_VAL origState;
|
||||
MULTIOS_ATOMIC_VAL newState;
|
||||
MULTIOS_ATOMIC_VAL newSig;
|
||||
uint16_t numPortsToTry;
|
||||
int rc;
|
||||
|
||||
/* Allocate desired port */
|
||||
rc = MULTIOS_SEM_DOWN(&busInfo->portAllocLock);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (portId == MIPC_PORT_ANY || portId == 0) {
|
||||
portId = (uint16_t)(busInfo->ownMaxPorts - 1U);
|
||||
numPortsToTry = portId;
|
||||
rc = -MIPC_EADDRNOTAVAIL;
|
||||
} else {
|
||||
/* Leave portId "as is" */
|
||||
numPortsToTry = 1;
|
||||
rc = -MIPC_EADDRINUSE;
|
||||
}
|
||||
|
||||
do {
|
||||
if (!portInfo[portId].allocated) {
|
||||
portInfo[portId].allocated = 1;
|
||||
rc = MIPC_OK;
|
||||
break;
|
||||
}
|
||||
portId--;
|
||||
numPortsToTry--;
|
||||
} while (numPortsToTry > 0);
|
||||
|
||||
MULTIOS_SEM_UP(&busInfo->portAllocLock);
|
||||
|
||||
/* Abort if unable to get desired port */
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Increment port signature to indicate new incarnation is active;
|
||||
* reset port's packet list to empty; state count is set to 0
|
||||
*/
|
||||
port = busInfo->ownPorts + portId;
|
||||
|
||||
origState = MULTIOS_ATOMIC_GET(&port->state);
|
||||
newSig = (origState + PORT_SIG_INCREMENT) & PORT_SIG_MASK;
|
||||
newState = newSig | EVENT_INDEX_INVALID;
|
||||
(void)MULTIOS_ATOMIC_SET(&port->state, newState);
|
||||
|
||||
*foundPort = port;
|
||||
return portId;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_port_bufs_alloc - Allocate buffers for a port
|
||||
*
|
||||
* Reserve the specified # of packets from the node's packet pool.
|
||||
*/
|
||||
int mipc_sm_port_bufs_alloc(uint16_t busId, uint16_t portId, uint16_t txBufs,
|
||||
uint32_t connectSig)
|
||||
{
|
||||
struct mipc_sm_local_bus_info *busInfo = &mipcSmLocalBusInfo[busId];
|
||||
struct mipc_sm_local_port_info *portInfo = busInfo->port_info;
|
||||
MipcSmEvent *event;
|
||||
MipcSmEventPool *pool;
|
||||
MipcSmPort *port;
|
||||
MULTIOS_ATOMIC_VAL state;
|
||||
MULTIOS_ATOMIC_VAL portSig;
|
||||
|
||||
port = busInfo->ownPorts + portId;
|
||||
state = MULTIOS_ATOMIC_GET(&port->state);
|
||||
portSig = state & PORT_SIG_MASK;
|
||||
|
||||
/* Create private list of packets for port's exclusive use */
|
||||
portInfo[portId].numBuffers = txBufs;
|
||||
pool = &busInfo->ownNode->packetPool.eventPool;
|
||||
|
||||
MIPCDBG("port %u: allocating %u packets\n", portId, txBufs);
|
||||
while (txBufs--) {
|
||||
event = mipc_sm_event_alloc(pool);
|
||||
if (!event) {
|
||||
MIPCDBG("port %u: unable to allocate all packets\n",
|
||||
portId);
|
||||
MIPC_STATS_ADD(mipc_sm_stats_ptr(busId),
|
||||
MIPC_STATS_BUFFER_NOT_AVAIL, 1);
|
||||
mipc_sm_port_free(busId, portId);
|
||||
return -MIPC_ENOMEM;
|
||||
}
|
||||
event->userNodeInfo = (uint32_t)busInfo->ownNode->state;
|
||||
event->srcPort = MULTIOS_hton16(portId);
|
||||
event->srcPortSig = MULTIOS_hton32(portSig);
|
||||
event->connectSig = MULTIOS_hton32(connectSig);
|
||||
(void)mipc_sm_port_packet_put(port, state,
|
||||
(struct mipc_sm_packet_desc *)event);
|
||||
state = MULTIOS_ATOMIC_GET(&port->state);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_port_free - Free an allocated port
|
||||
*
|
||||
* This routine marks a previously allocated port as free, and returns any
|
||||
* free packets it has to the node's packet pool.
|
||||
*/
|
||||
void mipc_sm_port_free(uint16_t busId, uint16_t portId)
|
||||
{
|
||||
struct mipc_sm_local_bus_info *busInfo = &mipcSmLocalBusInfo[busId];
|
||||
struct mipc_sm_node *node = busInfo->ownNode;
|
||||
MipcSmPort *port = busInfo->ownPorts + portId;
|
||||
MULTIOS_ATOMIC_VAL origState;
|
||||
MULTIOS_ATOMIC_VAL newState;
|
||||
MULTIOS_ATOMIC_VAL newSig;
|
||||
MipcSmEventPool *pool = &node->packetPool.eventPool;
|
||||
MipcSmEvent *eventsArray;
|
||||
MipcSmEvent *event;
|
||||
uint32_t headEventIndex;
|
||||
int count = 0;
|
||||
|
||||
/*
|
||||
* Increment port signature to ensure any unreturned packets from port
|
||||
* are given back to node's pool; resets port's packet list to empty;
|
||||
* state count is set to 0
|
||||
*/
|
||||
do {
|
||||
origState = MULTIOS_ATOMIC_GET(&port->state);
|
||||
newSig = (origState + PORT_SIG_INCREMENT) & PORT_SIG_MASK;
|
||||
newState = newSig | EVENT_INDEX_INVALID;
|
||||
} while (!MULTIOS_ATOMIC_CAS(&port->state, origState, newState));
|
||||
|
||||
/*
|
||||
* Return all packets in port's private list to node's pool
|
||||
* (Can manipulate packet list items without locks because
|
||||
* they are no longer visible to anyone else)
|
||||
*/
|
||||
eventsArray = (MipcSmEvent *)mipc_offset2addr_ntoh(pool->eventsOffset);
|
||||
headEventIndex = (uint32_t)origState & EVENT_INDEX_MASK;
|
||||
while (headEventIndex != EVENT_INDEX_INVALID) {
|
||||
event = (MipcSmEvent *)((char *)eventsArray +
|
||||
headEventIndex * MULTIOS_ntoh16(pool->eventSize));
|
||||
headEventIndex = event->nextFreeIndex;
|
||||
mipc_sm_event_free(event);
|
||||
count++;
|
||||
}
|
||||
MIPCDBG("port %u: freed %d packets\n", portId, count);
|
||||
busInfo->port_info[portId].numBuffers = 0;
|
||||
|
||||
/*
|
||||
* Mark port as unused
|
||||
* (Don't need to take "portAllocLock" since there is no possibility
|
||||
* that multiple threads will try to free the same port)
|
||||
*/
|
||||
busInfo->port_info[portId].allocated = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_port_packets_free - Free all packets in a port's private list
|
||||
*/
|
||||
void mipc_sm_port_packets_free(uint16_t busId, uint16_t portId,
|
||||
MipcSmEventPool *pool)
|
||||
{
|
||||
struct mipc_sm_local_bus_info *busInfo = &mipcSmLocalBusInfo[busId];
|
||||
MipcSmPort *port = busInfo->ownPorts + portId;
|
||||
MULTIOS_ATOMIC_VAL origState;
|
||||
MULTIOS_ATOMIC_VAL newState;
|
||||
MipcSmEvent *eventsArray;
|
||||
MipcSmEvent *event;
|
||||
uint32_t headEventIndex;
|
||||
int count = 0;
|
||||
|
||||
/* Reset port's packet list to empty (leave signature unchanged) */
|
||||
do {
|
||||
origState = MULTIOS_ATOMIC_GET(&port->state);
|
||||
newState = origState | EVENT_INDEX_INVALID;
|
||||
newState = newState + PORT_UPDATE_INCREMENT;
|
||||
} while (!MULTIOS_ATOMIC_CAS(&port->state, origState, newState));
|
||||
|
||||
/*
|
||||
* Return all packets in port's private list to node's pool
|
||||
* (Can manipulate packet list items without locks because
|
||||
* they are no longer visible to anyone else)
|
||||
*/
|
||||
eventsArray = (MipcSmEvent *)mipc_offset2addr_ntoh(pool->eventsOffset);
|
||||
headEventIndex = (uint32_t)origState & EVENT_INDEX_MASK;
|
||||
while (headEventIndex != EVENT_INDEX_INVALID) {
|
||||
event = (MipcSmEvent *)((char *)eventsArray +
|
||||
headEventIndex * MULTIOS_ntoh16(pool->eventSize));
|
||||
headEventIndex = event->nextFreeIndex;
|
||||
mipc_sm_event_free(event);
|
||||
count++;
|
||||
}
|
||||
MIPCDBG("port %u: freed %d packets\n", portId, count);
|
||||
busInfo->port_info[portId].numBuffers = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_port_packet_get - Obtain a packet from a port's private list
|
||||
*/
|
||||
MipcSmPacketDesc *mipc_sm_port_packet_get(MipcSmPort *port,
|
||||
MipcSmEventPool *pool)
|
||||
{
|
||||
MULTIOS_ATOMIC_VAL origState;
|
||||
MULTIOS_ATOMIC_VAL newState;
|
||||
MipcSmEvent *eventsArray;
|
||||
MipcSmEvent *event;
|
||||
uint32_t headEventIndex;
|
||||
|
||||
eventsArray = (MipcSmEvent *)mipc_offset2addr_ntoh(pool->eventsOffset);
|
||||
|
||||
do {
|
||||
origState = MULTIOS_ATOMIC_GET(&port->state);
|
||||
|
||||
/* Quit if port's private list is empty */
|
||||
headEventIndex = (uint32_t)origState & EVENT_INDEX_MASK;
|
||||
if (headEventIndex == EVENT_INDEX_INVALID) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Locate new head of private list */
|
||||
event = (MipcSmEvent *)((char *)eventsArray +
|
||||
headEventIndex * MULTIOS_ntoh16(pool->eventSize));
|
||||
headEventIndex = MULTIOS_ntoh16(event->nextFreeIndex);
|
||||
|
||||
/* Update list head & increment state change counter */
|
||||
newState = origState & (~EVENT_INDEX_MASK);
|
||||
newState += (PORT_UPDATE_INCREMENT | headEventIndex);
|
||||
|
||||
/* Don't need barrier here since only port's state is changed */
|
||||
/* MULTIOS_MEM_BARRIER(); */
|
||||
} while (!MULTIOS_ATOMIC_CAS(&port->state, origState, newState));
|
||||
|
||||
return (MipcSmPacketDesc *)event;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_port_packet_put - Try to return a packet to a port's private list
|
||||
*
|
||||
* Returns: non-zero if successful, zero if port state change prevented return
|
||||
*/
|
||||
int mipc_sm_port_packet_put(MipcSmPort *port, MULTIOS_ATOMIC_VAL origState,
|
||||
struct mipc_sm_packet_desc *bufDesc)
|
||||
{
|
||||
MULTIOS_ATOMIC_VAL newState;
|
||||
uint16_t headEventIndex;
|
||||
|
||||
/* Link packet to current list head */
|
||||
headEventIndex = (uint16_t)((uint32_t)origState & EVENT_INDEX_MASK);
|
||||
bufDesc->event.nextFreeIndex = MULTIOS_hton16(headEventIndex);
|
||||
|
||||
/* Make packet new list head & increment state change counter */
|
||||
newState = origState & (~EVENT_INDEX_MASK);
|
||||
newState += (PORT_UPDATE_INCREMENT |
|
||||
MULTIOS_ntoh16(bufDesc->event.ownIndex));
|
||||
|
||||
/* Ensure event's link is written before changing port state */
|
||||
MULTIOS_MEM_BARRIER();
|
||||
|
||||
return MULTIOS_ATOMIC_CAS(&port->state, origState, newState);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_port_pool_buffer_avail - Indicate if port pool has a free buffer
|
||||
*/
|
||||
int mipc_sm_port_pool_buffer_avail(MipcSmPort *port)
|
||||
{
|
||||
return (MULTIOS_ATOMIC_GET(&port->state) & EVENT_INDEX_MASK) !=
|
||||
EVENT_INDEX_INVALID;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/* mipc_sm_port.h - MIPC-SM ports */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01r,07jan11,jlk Update license header
|
||||
01q,30mar10,als Initial changes in support of 64-bit memory addressing
|
||||
01p,23sep09,bwa add connection signature
|
||||
01o,11sep09,als Enhance node restart capability
|
||||
01n,03sep09,als Display actual number of allocated buffers in show commands
|
||||
01m,26aug09,als Cleanup issues with flow control rework
|
||||
01l,25aug09,jlk WIND00178668 - MIPC flow control changes and clean-up.
|
||||
01k,24aug09,als Fix issues with simultaneous node up/down and socket shutdown
|
||||
01j,15aug09,als Fix race condition in socket shutdown code
|
||||
01i,05aug09,als Move port's socket id out of shared memory
|
||||
01h,27jul09,als Event queue rework
|
||||
01g,01may09,ebh Add routine to return port and node information
|
||||
01f,24mar09,ebh Make inlines static and use MULTIOS_INLINE
|
||||
01e,24mar09,ebh Fix portability issues in code
|
||||
01d,24mar09,ebh Fix portability issues in code
|
||||
01c,16mar09,ebh Track number of buffers outstanding on a socket to prevent
|
||||
starvation
|
||||
01b,11mar09,ebh Define the socketId as a volatile entity
|
||||
01a,25nov08,apa Initial version
|
||||
*/
|
||||
|
||||
#ifndef __INC_mipc_sm_port_h
|
||||
#define __INC_mipc_sm_port_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct mipc_sm_event_pool;
|
||||
struct mipc_sm_packet_desc;
|
||||
|
||||
/* MIPC port structure (resides in SM) */
|
||||
|
||||
typedef struct mipc_sm_port
|
||||
{
|
||||
MULTIOS_ATOMIC state; /* port state */
|
||||
MULTIOS_ATOMIC_VAL reserved; /* reserved for future use */
|
||||
} MipcSmPort;
|
||||
|
||||
/*
|
||||
* Port state info is held in an atomic variable with the following format:
|
||||
*
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | update count |port incarnation | packet list head index |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
*
|
||||
* |-port signature -|
|
||||
*
|
||||
* Packet list head index indicates first free packet in port's private
|
||||
* collection of packets.
|
||||
*
|
||||
* Port incarnation is a counter that is incremented every time the port is
|
||||
* allocated, and again when it is freed. (The incarnation counter is also
|
||||
* incremented each time the port is initialized during node start up.) The
|
||||
* low bit of the count is set if the port is allocated and clear if it is free.
|
||||
*
|
||||
* The port incarnation bits form a "port signature", which is different for
|
||||
* each incarnation of the port and is constant during its lifetime. A change
|
||||
* in the port signature allows nodes to detect when packets cannot be returned
|
||||
* to their original port because it no longer exists.
|
||||
*
|
||||
* Update count is incremented each time the packet list head is updated,
|
||||
* and is reset to zero when the port signature is changed. This ensures that
|
||||
* anyone trying to change the port state can tell if someone else has altered
|
||||
* the port while they were preparing their change.
|
||||
*/
|
||||
|
||||
#define PORT_UPDATE_MASK 0xFF000000U
|
||||
#define PORT_UPDATE_INCREMENT 0x01000000U
|
||||
#define PORT_SIG_MASK 0x00FF0000U
|
||||
#define PORT_SIG_INCREMENT 0x00010000U
|
||||
|
||||
#define MIPC_SM_PORT_INVALID_SOCKET 0xffff
|
||||
|
||||
#define PORT_SHUTDOWN_ACTIVE 0x01
|
||||
#define PORT_EVENT_ACTIVE 0x02
|
||||
#define PORT_NODE_CHANGE_ACTIVE 0x04
|
||||
|
||||
MipcSmPort *mipc_sm_port_ptr(uint16_t busId, uint16_t nodeId, uint16_t portId);
|
||||
|
||||
void mipc_sm_port_init(MipcSmPort *port);
|
||||
|
||||
int mipc_sm_port_alloc(uint16_t busId, uint16_t portId, MipcSmPort **foundPort);
|
||||
int mipc_sm_port_bufs_alloc(uint16_t busId, uint16_t portId, uint16_t txBufs,
|
||||
uint32_t connectSig);
|
||||
void mipc_sm_port_free(uint16_t busId, uint16_t portId);
|
||||
|
||||
void mipc_sm_port_packets_free(uint16_t busId, uint16_t portId,
|
||||
struct mipc_sm_event_pool *pool);
|
||||
|
||||
struct mipc_sm_packet_desc *mipc_sm_port_packet_get(MipcSmPort *port,
|
||||
struct mipc_sm_event_pool *pool);
|
||||
int mipc_sm_port_packet_put(MipcSmPort *port, MULTIOS_ATOMIC_VAL portState,
|
||||
struct mipc_sm_packet_desc *bufDesc);
|
||||
|
||||
int mipc_sm_port_pool_buffer_avail(MipcSmPort *port);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INC_mipc_sm_port_h */
|
||||
|
||||
@@ -0,0 +1,737 @@
|
||||
/* mipc_sm_show.c - MIPC show routines */
|
||||
|
||||
/* (comment line split to allow apigen processing)
|
||||
*********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
02r,20may11,als Enhance show command descriptions for MIPC 2.2
|
||||
02q,22apr11,swg Add necessary comments to cover VxWorks show commands
|
||||
in APIGEN output, fix WIND00268209
|
||||
02p,07jan11,jlk Update license header
|
||||
02o,24sep10,jlk Add displaying of debug mode and system options
|
||||
02n,02mar10,als Add support for 64-bit memory addressing
|
||||
02m,30sep09,als Fix potential null pointer dereference in mipcShow()
|
||||
02l,23sep09,bwa add connection signature
|
||||
02k,14sep09,als Enhance node restart capability
|
||||
02j,09sep09,als Correct minor statistics collection issues
|
||||
02i,03sep09,als Display actual # buffers allocated; enhance debug output
|
||||
02h,27aug09,als Cleanup issues with flow control rework
|
||||
02g,25aug09,jlk WIND00178668 - MIPC flow control changes and clean-up.
|
||||
02f,20aug09,als Add node restart support
|
||||
02e,19aug09,als Suppress display of non-configured buses
|
||||
02d,14aug09,als Revise internals of event-based code
|
||||
02c,12aug09,als Improve robustness of packet pool
|
||||
02b,11aug09,als Revise event exchange code to improve robustness
|
||||
02a,10aug09,ebh Fix comment line describing file
|
||||
01z,05aug09,als Move port's socket id out of shared memory
|
||||
01y,04aug09,als Convert shared memory offsets to use MIPC_OFFSET type
|
||||
01x,29jul09,als Add support for per-bus statistics collection
|
||||
01x,27jul09,ebh Update output format for used and unused bytes
|
||||
01w,27jul09,als Event queue rework
|
||||
01v,24jul09,jlk Event Q rework. Add some event q info.
|
||||
01u,02jul09,als Changes to reflect updated file names
|
||||
01t,30jun09,als Eliminate obsolete user data socket option
|
||||
01s,25jun09,als Rework memory region code to fix WIND00167982
|
||||
01r,22jun09,als Fix issues with handling of timers
|
||||
01q,16jun09,ebh Prevent out of bounds access and allow for post-mortem
|
||||
viewing
|
||||
01p,03jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01p,03jun09,ebh Fix output for mipcShowNode that shows ports existing after
|
||||
they have been closed
|
||||
01o,29may09,als Revise configuration based on MIPC 2.0 HLD feedback
|
||||
01n,26may09,ebh Code Inspection Modifications
|
||||
01m,10may09,ebh Change txBufferAvailCount to txBufferAvailEvents
|
||||
01l,30apr09,ebh Ensure that mipc.h is included first
|
||||
01k,24apr09,ebh Add in txEventsCount
|
||||
01j,22apr09,ebh Add in default bus display
|
||||
01i,25mar09,ebh Update show routines
|
||||
01h,24mar09,ebh Keep packetSize in host byte order, but store a network byte
|
||||
order version for external use
|
||||
01g,24mar09,ebh Fix portability issues in code
|
||||
01f,19mar09,ebh Add new information for show routines
|
||||
01e,24feb09,ebh Update lastNode display
|
||||
01d,19feb09,ebh Adjust usage of the MIPC_SO_MTU information to validate on
|
||||
bind
|
||||
01c,19feb09,ebh Collapse 3 packet pools into a single pool per bus
|
||||
01b,13feb09,ebh Update show output
|
||||
01a,25nov08,apa Initial version.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
The MIPC show routines display information about the current status
|
||||
of a system containing MIPC.
|
||||
This information can be used to confirm that MIPC is operating normally
|
||||
or to assist in troubleshooting communication problems involving MIPC.
|
||||
|
||||
These routines are currently available only from the VxWorks shell,
|
||||
or to kernel tasks running within VxWorks.
|
||||
|
||||
INCLUDE FILES
|
||||
N/A
|
||||
|
||||
SEE ALSO
|
||||
\tb Wind River MIPC Programmer's Guide
|
||||
|
||||
INTERNAL
|
||||
|
||||
The mipcShowDebugOn(), mipcShowDebugOff(), and mipcReset() routines
|
||||
are for internal use only and are not advertised to customers.
|
||||
*/
|
||||
|
||||
#include "mipc_sm_core.h"
|
||||
#include "mipc_sm_show.h"
|
||||
#include "mipc_sm_system.h"
|
||||
#include "mipc_sm_socket.h"
|
||||
|
||||
static int mipc_show_debug_flag = 0; /* if set, provide further show info */
|
||||
|
||||
/*****************************************************************************
|
||||
* mipcShowDebugOn - Enable debugging output for MIPC show commands
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* void mipcShowDebugOn(void)
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Causes MIPC show commands to display both standard information and
|
||||
* debugging information that may be useful during troubleshooting
|
||||
* of hardware or software problems. Interpretation of debugging information
|
||||
* typically requires a detailed understanding of the implementation of MIPC.
|
||||
*
|
||||
* RETURNS: void
|
||||
*
|
||||
* ERRNO: N/A
|
||||
*
|
||||
* SEE ALSO:
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
void mipcShowDebugOn(void)
|
||||
{
|
||||
mipc_show_debug_flag = 1;
|
||||
MULTIOS_PRINT("\nMIPC Show Commands extra debug output: ON\n");
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipcShowDebugOff - Disable debugging output for MIPC show commands
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* void mipcShowDebugOff(void)
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Causes MIPC show commands to display standard information information only.
|
||||
*
|
||||
* RETURNS: void
|
||||
*
|
||||
* ERRNO: N/A
|
||||
*
|
||||
* SEE ALSO:
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
void mipcShowDebugOff(void)
|
||||
{
|
||||
mipc_show_debug_flag = 0;
|
||||
MULTIOS_PRINT("\nMIPC Show Commands extra debug output: OFF\n");
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* mipcHelp - Display information about MIPC show commands
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* int mipcHelp(void)
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Displays information about the currently installed version of MIPC
|
||||
* and the set of available show commands.
|
||||
*
|
||||
* RETURNS: 'MIPC_OK'
|
||||
*
|
||||
* ERRNO: N/A
|
||||
*
|
||||
* SEE ALSO:
|
||||
*/
|
||||
int mipcHelp(void)
|
||||
{
|
||||
MULTIOS_PRINT("\nMIPC\n{\n");
|
||||
MULTIOS_PRINT(" installed version: %d.%d\n",
|
||||
MIPC_VERSION_MAJOR, MIPC_VERSION_MINOR);
|
||||
MULTIOS_PRINT(" available show commands:\n");
|
||||
MULTIOS_PRINT(" mipcHelp - this command\n");
|
||||
MULTIOS_PRINT(" mipcShow - basic information about the system and buses\n");
|
||||
MULTIOS_PRINT(" mipcShowBus <busNum> - bus information\n");
|
||||
MULTIOS_PRINT(" mipcShowNode <busNum>,<nodeNum> - node information on the bus\n");
|
||||
MULTIOS_PRINT(" mipcShowPort <busNum>,<nodeNum>,<portNum> - port information\n"
|
||||
" on specified node on the bus\n");
|
||||
MULTIOS_PRINT("}\n\n");
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* mipcShow - Display MIPC system information
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* int mipcShow(void)
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Displays general information about MIPC's shared memory region,
|
||||
* the MIPC buses that exist in the system, and the MIPC id of the node
|
||||
* displaying the information.
|
||||
*
|
||||
* This routine does not take any parameters.
|
||||
*
|
||||
* RETURNS: 'MIPC_OK' on success, -1 on failure.
|
||||
*
|
||||
* ERRNO: N/A
|
||||
*
|
||||
* SEE ALSO:
|
||||
*/
|
||||
int mipcShow(void)
|
||||
{
|
||||
struct mipc_sm_bus *bus;
|
||||
uint16_t busId;
|
||||
uint16_t maxBuses;
|
||||
int listEmpty;
|
||||
|
||||
/* Once more bus types are available, will need to do more than just SM */
|
||||
|
||||
if (!mipc_sm_system_init_check()) {
|
||||
MULTIOS_PRINT("MIPC-SM has not been initialized\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
maxBuses = MULTIOS_ntoh16(mipcSmSystem->maxBuses);
|
||||
|
||||
MULTIOS_PRINT("\nMIPC-SM SYSTEM\n{\n");
|
||||
if (mipcSmSystem->sysOpts & MIPC_SYSOPT_DEBUG_FLG) {
|
||||
MULTIOS_PRINT(" DEBUG MODE IS ON\n");
|
||||
}
|
||||
MULTIOS_PRINT(" base address of SM: %p\n", mipcSmStartAddr);
|
||||
MULTIOS_PRINT(" SM memory pool region: size=0x%x used=0x%x unused=0x%x bytes\n",
|
||||
MULTIOS_ntoh32(mipcSmSystem->memPool.endOffset) -
|
||||
MULTIOS_ntoh32(mipcSmSystem->memPool.startOffset),
|
||||
MULTIOS_ATOMIC_GET(&mipcSmSystem->memPool.nextFreeOffset) -
|
||||
MULTIOS_ntoh32(mipcSmSystem->memPool.startOffset),
|
||||
MULTIOS_ntoh32(mipcSmSystem->memPool.endOffset) -
|
||||
MULTIOS_ATOMIC_GET(&mipcSmSystem->memPool.nextFreeOffset));
|
||||
MULTIOS_PRINT(" maximum buses: %u\n", maxBuses);
|
||||
|
||||
MULTIOS_PRINT(" buses: ");
|
||||
bus = mipc_sm_bus_ptr_valid(0);
|
||||
|
||||
listEmpty = 1;
|
||||
for (busId = 0; busId < maxBuses; busId++, bus++) {
|
||||
if (bus->maxNodes > 0) {
|
||||
MULTIOS_PRINT("%c %u-%c%s%c", listEmpty ? '{' : ',',
|
||||
busId, '"', bus->name, '"');
|
||||
listEmpty = 0;
|
||||
}
|
||||
}
|
||||
if (listEmpty) {
|
||||
MULTIOS_PRINT("{ (none)");
|
||||
}
|
||||
MULTIOS_PRINT(" }\n");
|
||||
if (mipc_bus_default != MIPC_BUS_ANY) {
|
||||
MULTIOS_PRINT(" default bus: %d\n", mipc_bus_default);
|
||||
} else {
|
||||
MULTIOS_PRINT(" default bus: <none>\n");
|
||||
}
|
||||
MULTIOS_PRINT(" my node: %u\n", mipc_node_id);
|
||||
|
||||
#ifdef MIPC_CHECK_ARGS
|
||||
MULTIOS_PRINT(" MIPC_CHECK_ARGS is ON\n");
|
||||
#endif
|
||||
#if (MIPC_STATS_MODE > 0)
|
||||
MULTIOS_PRINT(" MIPC_STATS_MODE is ON\n");
|
||||
#endif
|
||||
|
||||
/* print out any extra debugging information */
|
||||
if (mipc_show_debug_flag) {
|
||||
MULTIOS_PRINT("\nEXTRA DEBUG OUTPUT:\n");
|
||||
MULTIOS_PRINT(" system options: 0x%x\n",
|
||||
mipcSmSystem->sysOpts);
|
||||
MULTIOS_PRINT(" system state: 0x%08x\n",
|
||||
MULTIOS_ATOMIC_GET(&mipcSmSystem->state));
|
||||
MULTIOS_PRINT(" next ID to be generated: %u\n",
|
||||
MULTIOS_ATOMIC_GET(&mipcSmSystem->id_generator));
|
||||
MULTIOS_PRINT(" busesOffset: 0x%x\n",
|
||||
MULTIOS_ntoh32(mipcSmSystem->busesOffset));
|
||||
MULTIOS_PRINT(" SM memory pool region: start=0x%x next=0x%x end=0x%x\n",
|
||||
MULTIOS_ntoh32(mipcSmSystem->memPool.startOffset),
|
||||
MULTIOS_ATOMIC_GET(&mipcSmSystem->memPool.nextFreeOffset),
|
||||
MULTIOS_ntoh32(mipcSmSystem->memPool.endOffset));
|
||||
}
|
||||
|
||||
MULTIOS_PRINT("}\n\n");
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* mipcShowBus - Display MIPC bus information
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* int mipcShowBus(int busId)
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Displays information about a MIPC bus, including its name,
|
||||
* the number of nodes it can support, and which nodes are currently
|
||||
* operational on the bus.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* \is
|
||||
* \i <busId>
|
||||
* Bus number.
|
||||
* \ie
|
||||
*
|
||||
* RETURNS: 'MIPC_OK' on success, -1 if unable to access the desired bus.
|
||||
*
|
||||
* ERRNO: N/A
|
||||
*
|
||||
* SEE ALSO: mipcShow()
|
||||
*/
|
||||
|
||||
int mipcShowBus(int busId)
|
||||
{
|
||||
uint16_t nodeId;
|
||||
uint16_t maxNodes;
|
||||
struct mipc_sm_bus *bus;
|
||||
int listEmpty;
|
||||
#if (MIPC_STATS_MODE > 0)
|
||||
struct mipc_stats bus_stats;
|
||||
#endif
|
||||
|
||||
if (!mipc_sm_system_init_check()) {
|
||||
MULTIOS_PRINT("MIPC-SM has not been initialized\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bus = mipc_sm_bus_ptr((uint16_t)busId);
|
||||
if (!bus) {
|
||||
MULTIOS_PRINT("Bus %d cannot be found\n", busId);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bus->maxNodes == 0) {
|
||||
MULTIOS_PRINT("Bus %d is not configured\n", busId);
|
||||
return -1;
|
||||
}
|
||||
|
||||
MULTIOS_PRINT("\nMIPC-SM BUS %d\n{\n", busId);
|
||||
MULTIOS_PRINT(" bus name: %c%s%c\n", '"', bus->name, '"');
|
||||
MULTIOS_PRINT(" maximum nodes: %u\n", MULTIOS_ntoh16(bus->maxNodes));
|
||||
MULTIOS_PRINT(" my node number: %u\n", mipc_node_id);
|
||||
|
||||
MULTIOS_PRINT(" active nodes: ");
|
||||
maxNodes = MULTIOS_ntoh16(bus->maxNodes);
|
||||
|
||||
listEmpty = 1;
|
||||
for (nodeId = 0; nodeId < maxNodes; nodeId++) {
|
||||
if (mipc_sm_node_is_up((uint16_t)busId, nodeId)) {
|
||||
MULTIOS_PRINT("%c %u", listEmpty ? '{' : ',', nodeId);
|
||||
listEmpty = 0;
|
||||
}
|
||||
}
|
||||
if (listEmpty) {
|
||||
MULTIOS_PRINT("{ (none)");
|
||||
}
|
||||
MULTIOS_PRINT(" }\n");
|
||||
|
||||
#if (MIPC_STATS_MODE > 0)
|
||||
mipc_getstatsbybus(busId, &bus_stats);
|
||||
MULTIOS_PRINT("\n node %u statistics mode: local\n", mipc_node_id);
|
||||
MULTIOS_PRINT(" buffer messages: sent=%u received=%u\n",
|
||||
bus_stats.bufs_sent, bus_stats.bufs_rcvd);
|
||||
MULTIOS_PRINT(" buffer bytes: sent=%u received=%u\n",
|
||||
bus_stats.bytes_sent, bus_stats.bytes_rcvd);
|
||||
MULTIOS_PRINT(" buffer tracking: allocated=%u freed=%u\n",
|
||||
bus_stats.bufs_allocated, bus_stats.bufs_freed);
|
||||
MULTIOS_PRINT(" buffer congestion: blocking=%u non-blocking=%u\n",
|
||||
bus_stats.buf_cong_wait, bus_stats.buf_cong_no_wait);
|
||||
MULTIOS_PRINT(" buffer available events: sent=%u received=%u\n",
|
||||
bus_stats.buf_avail_sent, bus_stats.buf_avail_rcvd);
|
||||
MULTIOS_PRINT(" express messages: sent=%u received=%u\n",
|
||||
bus_stats.express_msgs_sent, bus_stats.express_msgs_rcvd);
|
||||
MULTIOS_PRINT(" buffer exceptions: unavailable=%u\n",
|
||||
bus_stats.buffer_not_avail);
|
||||
MULTIOS_PRINT(" event exceptions: unavailable=%u\n",
|
||||
bus_stats.event_not_avail);
|
||||
MULTIOS_PRINT(" interrupts: sent=%u received=%u deferred=%u\n",
|
||||
bus_stats.interrupts_sent, bus_stats.interrupts_rcvd,
|
||||
bus_stats.interrupts_deferred);
|
||||
MULTIOS_PRINT(" socket usage: bound=%u closed=%u\n",
|
||||
bus_stats.sockets_bound, bus_stats.sockets_closed);
|
||||
MULTIOS_PRINT(" socket exceptions: rx queue full=%u\n",
|
||||
bus_stats.socket_rx_queue_err);
|
||||
#else
|
||||
MULTIOS_PRINT("\n node %u statistics mode: none\n", mipc_node_id);
|
||||
#endif
|
||||
|
||||
if (mipc_show_debug_flag) {
|
||||
MULTIOS_PRINT("\nEXTRA DEBUG OUTPUT:\n");
|
||||
MULTIOS_PRINT(" bus area address: %p\n", bus);
|
||||
MULTIOS_PRINT(" nodes offset: 0x%x\n",
|
||||
MULTIOS_ntoh32(bus->nodesOffset));
|
||||
}
|
||||
|
||||
MULTIOS_PRINT("}\n\n");
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* mipcShowNode - Display MIPC node information
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* int mipcShowNode
|
||||
* (
|
||||
* int busId,
|
||||
* int nodeId
|
||||
* )
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Displays information about a node on a MIPC bus, including its current status
|
||||
* and resource utilization, the number of ports it can support,
|
||||
* and which ports are currently operational on the node.
|
||||
*
|
||||
* Parameters:
|
||||
* \is
|
||||
* \i <busId>
|
||||
* Bus number.
|
||||
* \i <nodeId>
|
||||
* Node number.
|
||||
* \ie
|
||||
*
|
||||
* RETURNS: 'MIPC_OK' on success, -1 if unable to access the desired node.
|
||||
*
|
||||
* ERRNO: N/A
|
||||
*
|
||||
* SEE ALSO: mipcShow()
|
||||
*/
|
||||
int mipcShowNode(int busId, int nodeId)
|
||||
{
|
||||
uint16_t portId;
|
||||
uint16_t maxPorts;
|
||||
MipcSmPacketPool *pktPool;
|
||||
MipcSmEventPool *evtPool;
|
||||
MipcSmPort *port;
|
||||
struct mipc_sm_node *node;
|
||||
MULTIOS_ATOMIC_VAL nodeState;
|
||||
int listEmpty;
|
||||
|
||||
if (!mipc_sm_system_init_check()) {
|
||||
MULTIOS_PRINT("MIPC-SM has not been initialized\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
node = mipc_sm_node_ptr((uint16_t)busId, (uint16_t)nodeId);
|
||||
if (!node) {
|
||||
MULTIOS_PRINT("Node %d.%d cannot be found\n", busId, nodeId);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nodeState = MULTIOS_ntoh32(node->state);
|
||||
|
||||
MULTIOS_PRINT("\nMIPC-SM NODE %d.%d\n{\n", busId, nodeId);
|
||||
MULTIOS_PRINT(" current state: %s (signature=%d, heartbeat=%u)\n",
|
||||
mipc_sm_node_is_up((uint16_t)busId, (uint16_t)nodeId) ?
|
||||
"active" : "not active",
|
||||
(uint32_t)nodeState & NODE_SIG_MASK,
|
||||
(uint32_t)nodeState >> NODE_HB_SHIFT);
|
||||
MULTIOS_PRINT(" number of ports: %u\n", MULTIOS_ntoh16(node->maxPorts));
|
||||
MULTIOS_PRINT(" qos: %d (%s)\n", MULTIOS_ntoh16(node->qos),
|
||||
(MULTIOS_ntoh16(node->qos) > 0) ? "ISR deferred mode" :
|
||||
(MULTIOS_ntoh16(node->qos) == 0) ? "ISR mode" : "user mode");
|
||||
|
||||
pktPool = &node->packetPool;
|
||||
|
||||
MULTIOS_PRINT(" packet pool\n");
|
||||
MULTIOS_PRINT(" packet size: %u\n",
|
||||
MULTIOS_ntoh32(pktPool->packetSize));
|
||||
MULTIOS_PRINT(" number of buffers: %u\n",
|
||||
MULTIOS_ntoh16(pktPool->eventPool.numEvents));
|
||||
MULTIOS_PRINT(" available buffers: %s\n",
|
||||
mipc_sm_packet_avail(pktPool) ? "yes" : "no");
|
||||
|
||||
evtPool = &node->eventPool;
|
||||
|
||||
MULTIOS_PRINT(" event pool\n");
|
||||
MULTIOS_PRINT(" number of events: %u\n",
|
||||
MULTIOS_ntoh16(evtPool->numEvents));
|
||||
MULTIOS_PRINT(" available events: %s\n",
|
||||
mipc_sm_event_avail(evtPool) ? "yes" : "no");
|
||||
|
||||
MULTIOS_PRINT(" active ports: ");
|
||||
port = mipc_sm_port_ptr((uint16_t)busId, (uint16_t)nodeId, 0);
|
||||
maxPorts = MULTIOS_ntoh16(node->maxPorts);
|
||||
|
||||
listEmpty = 1;
|
||||
for (portId = 0; portId < maxPorts; portId++, port++) {
|
||||
if (MULTIOS_ATOMIC_GET(&port->state) & 0x10000) {
|
||||
MULTIOS_PRINT("%c %u", listEmpty ? '{' : ',', portId);
|
||||
listEmpty = 0;
|
||||
}
|
||||
}
|
||||
if (listEmpty) {
|
||||
MULTIOS_PRINT("{ (none)");
|
||||
}
|
||||
MULTIOS_PRINT(" }\n");
|
||||
|
||||
if (mipc_show_debug_flag) {
|
||||
MULTIOS_PRINT("\nEXTRA DEBUG OUTPUT:\n");
|
||||
MULTIOS_PRINT(" node area address: %p\n", node);
|
||||
MULTIOS_PRINT(" event queue state: 0x%08x\n",
|
||||
MULTIOS_ATOMIC_GET(&node->eventQueueState));
|
||||
MULTIOS_PRINT(" event queue tail offset: 0x%x\n",
|
||||
MULTIOS_ATOMIC_GET(&node->eventTailOffset));
|
||||
MULTIOS_PRINT(" portsOffset: 0x%x\n",
|
||||
MULTIOS_ntoh32(node->portsOffset));
|
||||
MULTIOS_PRINT(" cpuId: %u\n", MULTIOS_ntoh16(node->cpuId));
|
||||
MULTIOS_PRINT(" intId: %u\n", MULTIOS_ntoh16(node->intId));
|
||||
MULTIOS_PRINT(" packet pool\n");
|
||||
MULTIOS_PRINT(" pool address: %p\n", pktPool);
|
||||
MULTIOS_PRINT(" bufsOffset: 0x%x\n",
|
||||
MULTIOS_ntoh32(pktPool->bufsOffset));
|
||||
MULTIOS_PRINT(" eventsOffset: 0x%x\n",
|
||||
MULTIOS_ntoh32(pktPool->eventPool.eventsOffset));
|
||||
MULTIOS_PRINT(" eventSize: %u\n",
|
||||
MULTIOS_ntoh16(pktPool->eventPool.eventSize));
|
||||
MULTIOS_PRINT(" freeListState: 0x%08x\n",
|
||||
MULTIOS_ATOMIC_GET(&pktPool->eventPool.freeListState));
|
||||
MULTIOS_PRINT(" event pool\n");
|
||||
MULTIOS_PRINT(" pool address: %p\n", evtPool);
|
||||
MULTIOS_PRINT(" eventsOffset: 0x%x\n",
|
||||
MULTIOS_ntoh32(evtPool->eventsOffset));
|
||||
MULTIOS_PRINT(" eventSize: %u\n",
|
||||
MULTIOS_ntoh16(evtPool->eventSize));
|
||||
MULTIOS_PRINT(" freeListState: 0x%08x\n",
|
||||
MULTIOS_ATOMIC_GET(&evtPool->freeListState));
|
||||
}
|
||||
|
||||
MULTIOS_PRINT("}\n\n");
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* mipcShowPort - Display MIPC port information
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* int mipcShowPort
|
||||
* (
|
||||
* int busId,
|
||||
* int nodeId,
|
||||
* int portId
|
||||
* )
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Displays information about a port on a node on a MIPC bus,
|
||||
* including its current status and resource utilization.
|
||||
*
|
||||
* Parameters:
|
||||
* \is
|
||||
* \i <busId>
|
||||
* Bus number.
|
||||
* \i <nodeId>
|
||||
* Node number.
|
||||
* \i <portId>
|
||||
* Port number.
|
||||
* \ie
|
||||
*
|
||||
* RETURNS: 'MIPC_OK' on success, -1 if unable to access the desired port.
|
||||
*
|
||||
* ERRNO: N/A
|
||||
*
|
||||
* SEE ALSO: mipcShow()
|
||||
*/
|
||||
int mipcShowPort(int busId, int nodeId, int portId)
|
||||
{
|
||||
MipcSmPort *port;
|
||||
struct mipc_sm_local_port_info *portInfo;
|
||||
MipcSmSocket *theSocket;
|
||||
|
||||
if (!mipc_sm_system_init_check()) {
|
||||
MULTIOS_PRINT("MIPC-SM has not been initialized\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
port = mipc_sm_port_ptr((uint16_t)busId, (uint16_t)nodeId,
|
||||
(uint16_t)portId);
|
||||
if (!port) {
|
||||
MULTIOS_PRINT("Port %d.%d.%d cannot be found\n",
|
||||
busId, nodeId, portId);
|
||||
return -1;
|
||||
}
|
||||
|
||||
MULTIOS_PRINT("\nMIPC-SM PORT %d.%d.%d\n{\n", busId, nodeId, portId);
|
||||
MULTIOS_PRINT(" port active: %s\n",
|
||||
(MULTIOS_ATOMIC_GET(&port->state) & 0x10000) ? "yes" : "no");
|
||||
MULTIOS_PRINT(" available buffers: %s\n",
|
||||
mipc_sm_port_pool_buffer_avail(port) ? "yes" : "no");
|
||||
|
||||
if (nodeId != mipc_node_id) {
|
||||
MULTIOS_PRINT(" additional info: none\n");
|
||||
theSocket = NULL;
|
||||
goto debug;
|
||||
}
|
||||
|
||||
portInfo = &mipcSmLocalBusInfo[busId].port_info[portId];
|
||||
theSocket = portInfo->socket;
|
||||
if (theSocket == mipcSmLocalBusInfo[busId].dummy_socket) {
|
||||
theSocket = NULL;
|
||||
}
|
||||
|
||||
if (theSocket) {
|
||||
MULTIOS_PRINT(" buffer allocation: %u\n", portInfo->numBuffers);
|
||||
/* may display additional socket info in the future ... */
|
||||
}
|
||||
debug:
|
||||
if (!mipc_show_debug_flag) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
MULTIOS_PRINT("\nEXTRA DEBUG OUTPUT:\n");
|
||||
MULTIOS_PRINT(" port area address: %p\n", port);
|
||||
MULTIOS_PRINT(" port state: 0x%08x\n",
|
||||
MULTIOS_ATOMIC_GET(&port->state));
|
||||
|
||||
if (theSocket) {
|
||||
MULTIOS_PRINT(" socket address: %p\n", theSocket);
|
||||
MULTIOS_PRINT(" socket options:\n");
|
||||
MULTIOS_PRINT(" blocking socket: %s\n",
|
||||
theSocket->options.optBlocking ? "yes" : "no");
|
||||
MULTIOS_PRINT(" connection timeout (ms): %d\n",
|
||||
theSocket->options.optConnectionTimeout);
|
||||
MULTIOS_PRINT(" send timeout (ms): %d\n",
|
||||
theSocket->options.optSendTimeout);
|
||||
MULTIOS_PRINT(" receive timeout (ms): %d\n",
|
||||
theSocket->options.optReceiveTimeout);
|
||||
MULTIOS_PRINT(" tx buffer size: %u\n",
|
||||
theSocket->options.optMtu);
|
||||
MULTIOS_PRINT(" tx buffers: %u\n",
|
||||
theSocket->options.optTxBuffers);
|
||||
MULTIOS_PRINT(" rx buffers: %u\n",
|
||||
theSocket->options.optRxBuffers);
|
||||
}
|
||||
exit:
|
||||
MULTIOS_PRINT("}\n\n");
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipcReset - Request a MIPC reset (or display results of most recent reset)
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* \cs
|
||||
* int mipcReset(int type)
|
||||
* \ce
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* This is an undocumented API that is for testing/debugging purposes only.
|
||||
* Specifying reset command 2 instructs all nodes in the system to reboot,
|
||||
* while reset command 1 instructs only the node itself to reboot. Issuing
|
||||
* reset command 0 displays whether the node initialized the entire MIPC
|
||||
* shared memory region when it started up and whether the node initialized
|
||||
* its own area(s) of the MIPC shared memory region when it started up.
|
||||
*
|
||||
* Parameters:
|
||||
* \is
|
||||
* \i <type>
|
||||
* reset command.
|
||||
* \ie
|
||||
*
|
||||
* RETURNS: 'MIPC_OK' on success, -1 on failure.
|
||||
*
|
||||
* ERRNO: N/A
|
||||
*
|
||||
* SEE ALSO:
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
int mipcReset(int type)
|
||||
{
|
||||
if (!mipc_sm_system_init_check()) {
|
||||
MULTIOS_PRINT("MIPC-SM has not been initialized\n");
|
||||
return -1;
|
||||
}
|
||||
else if (type == MIPC_RESET_NONE) {
|
||||
MULTIOS_PRINT("MIPC-SM reset log: "
|
||||
"system init done=%s, node %u.%u init done=%s\n",
|
||||
(mipc_reset_log & MIPC_RESET_LOG_SYSTEM) ? "yes" : "no",
|
||||
mipc_bus_default, mipc_node_id,
|
||||
(mipc_reset_log & MIPC_RESET_LOG_NODE) ? "yes" : "no");
|
||||
}
|
||||
else if ((type >= MIPC_RESET_NODE) && (type <= MIPC_RESET_SYSTEM)) {
|
||||
mipc_reset_state = type;
|
||||
}
|
||||
else {
|
||||
MULTIOS_PRINT("Invalid reset request\n");
|
||||
return -1;
|
||||
}
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/* mipc_sm_show.h - MIPC-SM show functions */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01h,07jan11,jlk Update license header
|
||||
01g,30mar10,als Initial changes in support of 64-bit memory addressing
|
||||
01f,17sep09,als Enhance node restart capability
|
||||
01e,21aug09,als Add node restart support
|
||||
01d,10aug09,ebh Fix comment line describing file
|
||||
01c,27mar09,ebh Update show command names
|
||||
01b,23mar09,ebh Fix portability issues in code
|
||||
01a,25nov08,apa Initial version
|
||||
*/
|
||||
|
||||
#ifndef __INC_mipc_sm_show_h
|
||||
#define __INC_mipc_sm_show_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int mipcHelp(void);
|
||||
int mipcShow(void);
|
||||
int mipcShowBus(int busId);
|
||||
int mipcShowNode(int busId, int nodeId);
|
||||
int mipcShowPort(int busId, int nodeId, int portId);
|
||||
|
||||
/* undocumented APIs */
|
||||
|
||||
void mipcShowDebugOn(void);
|
||||
void mipcShowDebugOff(void);
|
||||
int mipcReset(int type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INC_mipc_sm_show_h */
|
||||
|
||||
@@ -0,0 +1,349 @@
|
||||
/* mipc_sm_socket.c - MIPC-SM sockets */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01w,14jan11,ste Use new functions to allocate/free memory
|
||||
01v,07jan11,jlk Update license header
|
||||
01u,23dec10,zhw Fix bug in packet queue (WIND00247240)
|
||||
01t,22mar10,jlk WIND00201354 - fix race condition on queueing packets for SMP
|
||||
01s,02mar10,als Add support for 64-bit memory addressing
|
||||
01r,10nov09,pad Temporary workaround allowing this file to compile for 64-bit
|
||||
build.
|
||||
01q,27sep09,als Fix bugs in receive routines (WIND00183445, WIND00183399)
|
||||
01p,15sep09,als Fix bug in revised semaphore handling
|
||||
01o,11sep09,bwa replace sems by sync objects given only when requested
|
||||
01n,02sep09,als Continue flow control rework
|
||||
01m,15aug09,als Fix race condition in socket shutdown code
|
||||
01l,11aug09,als Change name of socket pointer to descriptor conversion routine
|
||||
01k,07aug09,als Make socket descriptors simple positive integers
|
||||
01j,30jun09,als Convert free list protection from spinlock to semaphore
|
||||
01i,17jun09,ebh Use fixed sized (power-of-2) socket structures
|
||||
01h,13jun09,ebh Modify socket descriptors to be offsets
|
||||
01g,09jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01f,12may09,ebh Fix bug in initializing the socket structures
|
||||
01e,30apr09,ebh Ensure that mipc.h is included first
|
||||
01d,28apr09,ebh Update userhandle type
|
||||
01c,21apr09,ebh Separate out USERHANDLE from the socket structure
|
||||
01b,10mar09,ebh Update parameter passing of mipc_sm_socket_free
|
||||
01a,25nov08,apa Initial version
|
||||
*/
|
||||
|
||||
#include "mipc_sm_core.h"
|
||||
#include "mipc_sm_socket.h"
|
||||
|
||||
uint32_t mipcSmMaxSockets = 0; /* max sockets on node */
|
||||
MipcSmSocket *mipcSmAllSockets = NULL;
|
||||
unsigned long * mipcUserHandles = NULL;
|
||||
static MipcSmSocket *mipcSmFreeSockets = NULL;
|
||||
static MULTIOS_SEM freeListLock;
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_socket_init - Initialize the pool of socket descriptors.
|
||||
*/
|
||||
int mipc_sm_socket_init(unsigned int maxSockets)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned long n;
|
||||
MipcSmSocket *theSocket;
|
||||
|
||||
/*
|
||||
* Perform compile-time verification that the array of socket structures
|
||||
* used by MIPC is sized correctly.
|
||||
*
|
||||
* If the array entry size specified by MIPC_SD_BITS is not big enough
|
||||
* to hold one MipcSmSocket structure, increase MIPC_SD_BITS; likewise,
|
||||
* if the array entry size specified by MIPC_SD_BITS is big enough to
|
||||
* hold more than one MipcSmSocket structure, decrease MIPC_SD_BITS.
|
||||
* Finally, MIPC_SD_BITS cannot exceed 12 because this would result in
|
||||
* socket array offsets exceeding 32 bits if the maximum permitted
|
||||
* number of sockets is used; among other things, this would mean that
|
||||
* the resulting MIPC socket decriptor wouldn't fit in an "int" type.
|
||||
*
|
||||
* Note: Some of these errors cannot be caught using #if's because the
|
||||
* C preprocessor cannot resolve sizeof() to a numeric value. It is
|
||||
* likewise impossible to avoid the need for this checking by having
|
||||
* MIPC automatically generate a #define with the desired value of
|
||||
* MIPC_SD_BITS.
|
||||
*/
|
||||
|
||||
if (0) {
|
||||
char MIPC_SD_BITS_too_small_error[
|
||||
(sizeof(MipcSmSocket) <= (1<<MIPC_SD_BITS)) - 1];
|
||||
char MIPC_SD_BITS_too_large_error[
|
||||
(sizeof(MipcSmSocket)*2 > (1<<MIPC_SD_BITS)) - 1];
|
||||
char MIPC_SD_BITS_range_error[(MIPC_SD_BITS <= 12) - 1];
|
||||
|
||||
MIPC_SD_BITS_too_small_error[0] = '\0';
|
||||
MIPC_SD_BITS_too_large_error[0] = '\0';
|
||||
MIPC_SD_BITS_range_error[0] = '\0';
|
||||
}
|
||||
|
||||
MIPCDBG(MIPC_INFO "Initializing the sockets...\n");
|
||||
|
||||
MULTIOS_SEM_INIT_FULL(&freeListLock);
|
||||
|
||||
/* Allocate array of sockets */
|
||||
MIPCDBG(MIPC_INFO "Allocating %u sockets of %u bytes each (require at least %lu bytes)...\n",
|
||||
maxSockets, (1 << MIPC_SD_BITS),
|
||||
(unsigned long)sizeof(MipcSmSocket));
|
||||
|
||||
n = maxSockets * (1 << MIPC_SD_BITS);
|
||||
|
||||
mipcSmAllSockets = mipc_alloc_socket(maxSockets);
|
||||
if (!mipcSmAllSockets) {
|
||||
MIPCDBG(MIPC_ALERT "Failed to allocate the sockets.\n");
|
||||
return -MIPC_ENOMEM;
|
||||
}
|
||||
memset(mipcSmAllSockets, 0, n);
|
||||
|
||||
/* Allocate array of user handles */
|
||||
n = maxSockets * sizeof(unsigned long);
|
||||
|
||||
mipcUserHandles = mipc_alloc_sock_user_handle(maxSockets);
|
||||
if (!mipcUserHandles) {
|
||||
MIPCDBG(MIPC_ALERT "Failed to allocate the socket user handles.\n");
|
||||
mipc_free_socket(mipcSmAllSockets);
|
||||
return -MIPC_ENOMEM;
|
||||
}
|
||||
|
||||
MIPCDBG(MIPC_INFO "Initializing the list of free sockets...\n");
|
||||
|
||||
mipcSmMaxSockets = maxSockets;
|
||||
mipcSmFreeSockets = mipcSmAllSockets;
|
||||
|
||||
/* Create list of free sockets - last entry points 'next' to NULL */
|
||||
n = maxSockets - 1;
|
||||
|
||||
theSocket = mipcSmAllSockets;
|
||||
for (i = 0; i < n; i++) {
|
||||
theSocket->sd = mipc_index2sd(i);
|
||||
theSocket->next = (MipcSmSocket *)((char *)theSocket +
|
||||
(1 << MIPC_SD_BITS));
|
||||
theSocket = theSocket->next;
|
||||
}
|
||||
theSocket->sd = mipc_index2sd(i);
|
||||
|
||||
MIPCDBG(MIPC_INFO "Initialization of the sockets is completed.\n");
|
||||
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_socket_alloc - Allocate a socket descriptor.
|
||||
*/
|
||||
int mipc_sm_socket_alloc(MipcSmSocket **theSocket)
|
||||
{
|
||||
int rc;
|
||||
int sd;
|
||||
|
||||
rc = MULTIOS_SEM_DOWN(&freeListLock);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (mipcSmFreeSockets) {
|
||||
sd = mipc_sm_sock2sd(mipcSmFreeSockets);
|
||||
*theSocket = mipcSmFreeSockets;
|
||||
mipcSmFreeSockets->allocated = TRUE;
|
||||
mipcSmFreeSockets = mipcSmFreeSockets->next;
|
||||
MIPCDBG(MIPC_INFO "Socket %d has been allocated.\n", sd);
|
||||
} else {
|
||||
sd = -MIPC_ENFILE;
|
||||
MIPCDBG(MIPC_INFO "Failed to allocate a socket.\n");
|
||||
}
|
||||
|
||||
MULTIOS_SEM_UP(&freeListLock);
|
||||
return sd;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_socket_free - Return a socket descriptor to the pool of free descriptors.
|
||||
*/
|
||||
int mipc_sm_socket_free(MipcSmSocket *theSocket)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = MULTIOS_SEM_DOWN(&freeListLock);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
MIPCDBG(MIPC_INFO "Socket %d has been freed.\n", theSocket->sd);
|
||||
theSocket->allocated = FALSE;
|
||||
theSocket->next = mipcSmFreeSockets;
|
||||
mipcSmFreeSockets = theSocket;
|
||||
|
||||
MULTIOS_SEM_UP(&freeListLock);
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_socket_packet_queue - Queue a received buffer descriptor.
|
||||
*
|
||||
* The queue has a list of free slots with a head and tail (unsigned) value.
|
||||
* Enqueued data goes to the tail, dequeued data come from the head.
|
||||
* mask - this is the value queueLimit-1
|
||||
* (Head & mask) - points to first queued slot (location to dequeue data)
|
||||
* (Tail & mask) - points one past last queued slot
|
||||
* NOTE that Head and Tail have double duty:
|
||||
* (Head & mask) - points to one past last unused slot
|
||||
* (Tail & mask) - points to first unused slot (location to enqueue data)
|
||||
*
|
||||
* When Head == Tail, then there is no data on the queue.
|
||||
* When (Tail - Head) == queueLimit, then the queue is full.
|
||||
* (NOTE that the queue size is optimized to have a queueLimit that is power
|
||||
* of 2.)
|
||||
*
|
||||
* To enqueue something, add at tail location and increment tail. When
|
||||
* (Tail & mask) catches the (Head & mask) then we have used all of the
|
||||
* slots and the queue is full.
|
||||
*
|
||||
* The head and tail values keep incrementing without end and we only mask
|
||||
* the values when we need to (wrapping of these unsigned values is
|
||||
* acceptable and expected). The Head and Tail both start at the same value
|
||||
* (0 by convention). When (Head==Tail) there is nothing on the queue.
|
||||
*
|
||||
* To enqueue an item, we just verify that (Tail-Head != queueLimit). Then we
|
||||
* add the item to the tail and increment Tail.
|
||||
*
|
||||
* To dequeue an item, we verify that (Tail != Head) and use the item at the
|
||||
* head location. The Head value is then incremented.
|
||||
*
|
||||
* The following table with a queueLimit of 4 shows how this works.
|
||||
* Modulo 4 values in braces.
|
||||
*
|
||||
* Tail (mod) Head (mod)
|
||||
* List of 4 elements with all spots allocatable: 0 (0) 0 (0)
|
||||
* After allocating one spot: 1 (1) 0 (0)
|
||||
* After allocating second spot: 2 (2) 0 (0)
|
||||
* After allocating third spot: 3 (3) 0 (0)
|
||||
* After freeing one spot: 3 (3) 1 (1)
|
||||
* After allocating fourth spot: 4 (0) 1 (1)
|
||||
* After allocating fifth spot: 5 (1) 1 (1)
|
||||
* Next allocation attempt would fail since ('Tail' - 'Head' == queueLimit)
|
||||
*
|
||||
* Note that operations at this level are single threaded so we do not need
|
||||
* to use atomic variables for Tail and Head.
|
||||
*/
|
||||
int mipc_sm_socket_packet_queue(MipcSmSocket *theSocket,
|
||||
MipcSmPacketDesc *bufDesc)
|
||||
{
|
||||
struct mipc_sm_rx_buffer *rxbuf;
|
||||
uint16_t indexMask = theSocket->rxqIndexMask;
|
||||
int queueLimit = theSocket->options.optRxBuffers;
|
||||
|
||||
if ((uint16_t)(theSocket->rxqTail - theSocket->rxqHead) == queueLimit) {
|
||||
MIPCDBG(MIPC_ALERT "Failed to queue descriptor.");
|
||||
mipc_sm_packet_free(theSocket, bufDesc);
|
||||
return -MIPC_ENOMEM;
|
||||
}
|
||||
|
||||
rxbuf = &theSocket->rxq[theSocket->rxqTail & indexMask];
|
||||
rxbuf->desc = bufDesc;
|
||||
rxbuf->buffer = mipc_sm_packet_data_ptr(bufDesc);
|
||||
rxbuf->nBytesLeft = MULTIOS_ntoh32(bufDesc->bufLen);
|
||||
|
||||
theSocket->rxqTail++;
|
||||
|
||||
/*
|
||||
* Ensure rx buffer updates are written before telling socket that more
|
||||
* data is available
|
||||
*/
|
||||
MULTIOS_MEM_BARRIER();
|
||||
|
||||
MULTIOS_ATOMIC_ADD(&theSocket->rxqBytes,
|
||||
(MULTIOS_ATOMIC_VAL)rxbuf->nBytesLeft);
|
||||
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_socket_wait - wait for a sync event on an empty queue
|
||||
*
|
||||
* Instead of using a straight semaphore to wait for events, we use a flag/sem
|
||||
* combo. This has two advantages: a) it solves the problem of Linux only
|
||||
* having an implementation of counting semaphores without a ceiling, and b)
|
||||
* the CAS operation in the case no task is waiting is very fast.
|
||||
*
|
||||
* The task triggering the event will clear the flag and atomically check if
|
||||
* it was raised. If so, it will give the semaphore, waking up the task that
|
||||
* requested it. This is performed in mipc_sm_socket_do_sync().
|
||||
*
|
||||
* The burden of the more clever work is done by the task that requests the
|
||||
* sync. First, the flag is set to indicate the sync is requested. Then, the
|
||||
* condition of satisfaction must be checked to ensure that it did not occur
|
||||
* while the flag was being set. If it did occur, we have to try reverting it
|
||||
* in case it was not cleared by the task performing the sync: if we succeed
|
||||
* in reverting it, it means that the other task did not see it as set and
|
||||
* will not have given the semaphore, and we should thus not sleep on it.
|
||||
*
|
||||
* If neither of these cases are true, we sleep on the semaphore. If we
|
||||
* obtain it, everything is fine. If we don't, we have to handle the case
|
||||
* where we time out. In that case, the flag might have been cleared and
|
||||
* the semaphore given too late. To handle this, we clear the flag and
|
||||
* atomically check if it was already cleared: if it was, we take the
|
||||
* semaphore since it will be given and we do not want to leave it in the
|
||||
* available state.
|
||||
*
|
||||
* Again, most of the burden is placed on the task that will request the
|
||||
* sync, but it is done in the failure path, where an event, most probably
|
||||
* an incoming packet or a transmit buffer, is not available.
|
||||
*
|
||||
* Returns: time remaining if semaphore is taken
|
||||
* (is >= 0 if timeout >= 0; is 0 if timeout == MULTIOS_WAIT_FOREVER);
|
||||
* <0 on error
|
||||
*/
|
||||
int mipc_sm_socket_wait(MipcSmSocket *theSocket,
|
||||
struct mipc_sm_socket_sync *wait,
|
||||
int timeout,
|
||||
int (*condition_met)(MipcSmSocket *))
|
||||
{
|
||||
MULTIOS_ATOMIC *flag = &wait->flag;
|
||||
int rc;
|
||||
|
||||
MULTIOS_ATOMIC_SET(flag, 1);
|
||||
if (condition_met(theSocket)) {
|
||||
if (MULTIOS_ATOMIC_CAS(flag, 1, 0)) {
|
||||
return (timeout < 0) ? 0 : timeout;
|
||||
}
|
||||
}
|
||||
|
||||
rc = MULTIOS_SEM_DOWN_WITH_TIMEOUT(&wait->sem, timeout);
|
||||
|
||||
if (rc < 0) {
|
||||
if(!MULTIOS_ATOMIC_CAS(flag, 1, 0)) {
|
||||
MULTIOS_SEM_DOWN(&wait->sem);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,334 @@
|
||||
/* mipc_sm_socket.h - MIPC-SM sockets */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
02l,29dec11,swg Add new fields "connStartTime" and "connDestAddr"
|
||||
to struct mipc_sm_socket. (WIND00261229)
|
||||
02k,07jan11,jlk Update license header
|
||||
02j,08sep10,h_w Add a new field "rxqFlags" to struct mipc_sm_socket
|
||||
02i,26aug10,jlk Make sure #ifdef __cplusplus starts after #includes
|
||||
02h,02jun10,als Remove code for deprecated MIPC 1.0 APIs
|
||||
02g,17mar10,als Add support for 64-bit memory addressing
|
||||
02f,29oct09,als Fix connection signature duplication (WIND00185284)
|
||||
02e,27sep09,als Fix bugs in receive routines (WIND00183445, WIND00183399)
|
||||
02d,23sep09,bwa add connection signature
|
||||
02c,15sep09,als Fix bug in revised semaphore handling
|
||||
02b,11sep09,bwa replace sems by sync objects given only when requested
|
||||
02a,01sep09,als Continue flow control rework
|
||||
01z,24aug09,als Fix up issues with asynchronous connect capability
|
||||
01y,21aug09,als Eliminate unused semaphore from socket structure
|
||||
01x,15aug09,als Fix race condition in socket shutdown code
|
||||
01w,11aug09,als Change name of socket pointer to descriptor conversion routine
|
||||
01v,07aug09,ebh Code inspection updates
|
||||
01u,07aug09,als Make socket descriptors simple positive integers
|
||||
01t,06aug09,ebh Add a pending flag into the socket structure
|
||||
01s,06aug09,als Move port's socket id out of shared memory
|
||||
01r,02aug09,als Eliminate void pointer argument
|
||||
01q,30jul09,als Add support for per-bus statistics collection
|
||||
01p,03jul09,als Remove socket option default symbols
|
||||
01o,03jul09,h_w Fix WIND00166506 - avoid re-using sockets and ports have
|
||||
unreleased resources
|
||||
01n,30jun09,als Use template to speed initialization of new socket
|
||||
01m,17jun09,ebh Add macros for socket offset to sd conversions
|
||||
01l,13jun09,ebh Remove unused socket_end routine
|
||||
01k,08jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01j,03jun09,ebh Add support for a callback on a listening socket for incoming
|
||||
connect request
|
||||
01i,03jun09,h_w Fix WIND00166396 - embed semaphores into MipcSmSocket
|
||||
01h,28may09,ebh Store the node ptr in the socket structure for fast path
|
||||
01g,10may09,ebh Move externs from .c files to here
|
||||
01f,21apr09,ebh Separate out USERHANDLE from the socket structure
|
||||
01e,24mar09,ebh Make inlines static and use MULTIOS_INLINE
|
||||
01d,16mar09,ebh Track number of buffers outstanding on a socket to prevent
|
||||
starvation
|
||||
01c,10mar09,ebh Update parameter passing of mipc_sm_socket_free
|
||||
01b,18feb09,ebh Update obsolete socket options
|
||||
01a,25nov08,apa Initial version.
|
||||
*/
|
||||
|
||||
#ifndef __INC_mipc_sm_socket_h
|
||||
#define __INC_mipc_sm_socket_h
|
||||
|
||||
#include "mipc_sm_packet_pool.h"
|
||||
#include "mipc_sm_system.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* NOTE: any changes to the MIPC socket structure must also be propogated
|
||||
* to the socket_template used during socket initialization
|
||||
*/
|
||||
|
||||
struct mipc_sm_socket_options
|
||||
{
|
||||
uint16_t optBlocking; /* true if socket is blocking */
|
||||
uint16_t optTxBuffers; /* max TX buffer allocation */
|
||||
uint16_t optRxBuffers; /* size of RX queue */
|
||||
uint32_t optMtu; /* MTU in-use or requested */
|
||||
int optConnectionTimeout;
|
||||
int optSendTimeout;
|
||||
int optReceiveTimeout;
|
||||
|
||||
/* Callback function pointers */
|
||||
|
||||
MIPC_RX_CALLBACK optRxCallback;
|
||||
MIPC_RXQUEUED_CALLBACK optRxQueuedCallback;
|
||||
MIPC_EXPRESS_CALLBACK optExpressCallback;
|
||||
MIPC_TXBUFAVAIL_CALLBACK optTxBufAvailCallback;
|
||||
MIPC_CONNECTREQUEST_CALLBACK optConnectRequestCallback;
|
||||
MIPC_CONNECTED_CALLBACK optConnectedCallback;
|
||||
MIPC_CONNECTREFUSED_CALLBACK optConnectRefusedCallback;
|
||||
MIPC_DISCONNECTED_CALLBACK optDisconnectedCallback;
|
||||
MIPC_NODEJOIN_CALLBACK optNodeJoinCallback;
|
||||
MIPC_NODELEFT_CALLBACK optNodeLeftCallback;
|
||||
};
|
||||
|
||||
struct mipc_sm_rx_buffer
|
||||
{
|
||||
MipcSmPacketDesc *desc; /* ptr to received buffer */
|
||||
uint8_t *buffer; /* ptr to next byte of data */
|
||||
uint32_t nBytesLeft; /* amount of un-received data */
|
||||
};
|
||||
|
||||
struct mipc_sm_conn_request
|
||||
{
|
||||
uint16_t srcNode; /* These fields are stored in */
|
||||
uint16_t srcPort; /* the backlog queue to be */
|
||||
uint32_t connectSig; /* processed by a listening */
|
||||
}; /* socket */
|
||||
|
||||
struct mipc_sm_socket_sync {
|
||||
MULTIOS_SEM sem; /* sync semaphore */
|
||||
MULTIOS_ATOMIC flag; /* currently waiting on a sync */
|
||||
};
|
||||
|
||||
typedef struct mipc_sm_socket
|
||||
{
|
||||
/* Fields initialized by socket template when socket is allocated */
|
||||
|
||||
/* State */
|
||||
uint8_t type; /* socket type (eg. MIPC_SOCK_RDM) */
|
||||
uint8_t allocated; /* socket is allocated */
|
||||
uint8_t bound; /* socket has been bound */
|
||||
uint8_t shutdown; /* socket has been shut down */
|
||||
uint8_t connRequired; /* socket is connection-based */
|
||||
uint8_t connState; /* connection state (see below) */
|
||||
|
||||
/* Associated data structures */
|
||||
struct mipc_sm_port *port; /* ptr to port info in SM */
|
||||
struct mipc_sm_local_port_info *portInfo; /* ptr to port info in LM */
|
||||
struct mipc_sm_node *nodeptr; /* ptr to node structure, if bound */
|
||||
MULTIOS_ATOMIC *statsPtr; /* ptr to bus stats array, if bound */
|
||||
|
||||
/* Socket options */
|
||||
struct mipc_sm_socket_options options;
|
||||
|
||||
/* Socket addresses */
|
||||
struct mipc_sockaddr addr; /* own socket address */
|
||||
struct mipc_sockaddr peer; /* peer socket address */
|
||||
struct mipc_sockaddr connDestAddr; /* connection destination */
|
||||
|
||||
/* Receive queue */
|
||||
uint16_t rxqHead;
|
||||
uint16_t rxqTail;
|
||||
uint16_t rxqIndexMask;
|
||||
uint16_t rxqFlags;
|
||||
struct mipc_sm_rx_buffer *rxq;
|
||||
|
||||
/* Connection signature */
|
||||
uint32_t connectSig; /* own port's connection signature */
|
||||
uint32_t peerConnectSig; /* peer port's connection signature */
|
||||
uint32_t sigCheckMask; /* signature checking mask */
|
||||
|
||||
/* Connection request queue */
|
||||
struct mipc_sm_conn_request *connectQueue; /* connection request queue */
|
||||
uint16_t connectQueueSize; /* size of connection request queue */
|
||||
uint16_t connectQueueHead; /* head of connection request queue */
|
||||
uint16_t connectQueueTail; /* tail of connection request queue */
|
||||
|
||||
/* Simple-linked list of sockets */
|
||||
struct mipc_sm_socket *next;
|
||||
|
||||
/*
|
||||
* Fields not initialized by socket template
|
||||
* (i.e. constant and/or OS-specific type fields)
|
||||
*/
|
||||
|
||||
int sd; /* socket descriptor (constant) */
|
||||
uint32_t connStartTime; /* initialized by mipc_connect() */
|
||||
struct mipc_sm_socket_sync rxWait;
|
||||
struct mipc_sm_socket_sync txWait;
|
||||
MULTIOS_ATOMIC rxqBytes; /* number of bytes in RX queue */
|
||||
} MipcSmSocket;
|
||||
|
||||
/*
|
||||
* connection state values
|
||||
* - connection-based sockets can assume any of these values
|
||||
* - connectionless sockets can only use MIPC_SM_CONN_NONE & MIPC_SM_CONN_UP
|
||||
*/
|
||||
#define MIPC_SM_CONN_NONE 0 /* unconnected */
|
||||
#define MIPC_SM_CONN_SENT_SYN 1 /* connecting */
|
||||
#define MIPC_SM_CONN_UP 2 /* connected */
|
||||
#define MIPC_SM_CONN_SHUTDOWN 3 /* normal self termination */
|
||||
#define MIPC_SM_CONN_PEER_FIN 4 /* normal peer termination */
|
||||
#define MIPC_SM_CONN_PEER_RST 5 /* abnormal peer termination */
|
||||
#define MIPC_SM_CONN_SELF_RST 6 /* abnormal self-termination */
|
||||
#define MIPC_SM_CONN_PEER_NAK 7 /* peer refused connection */
|
||||
|
||||
/*
|
||||
* MIPC connection signatures
|
||||
*
|
||||
* Each MIPC socket has an associated connection signature that is present
|
||||
* in every event it sends. A MIPC socket that receives an event validates the
|
||||
* connection signature to ensure the event has arrived from an expected source.
|
||||
* Unexpected events receive special handling to ensure they do not interfere
|
||||
* with the normal flow of events arriving from expected sources.
|
||||
*
|
||||
* A MIPC connection signature has the form:
|
||||
*
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | type | node id | port id | port signature |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
*
|
||||
* where "type" indicates the class of socket that sent the event (connection-
|
||||
* based or connectionless) and the remaining fields form an identifier that is
|
||||
* unique within the system (on the associated bus).
|
||||
*
|
||||
* A socket is issued its signature when the socket is bound to a bus. In most
|
||||
* cases the socket utilizes its own node id, port id, and port signature to
|
||||
* generate its connection signature; however, a socket that is created by a
|
||||
* listening socket uses the signature of the socket that issued the connection
|
||||
* request, meaning that both ends of the connection share the same signature.
|
||||
* Once a socket's connection signature is established, it is used in all events
|
||||
* sent by the socket until the socket is closed.
|
||||
*
|
||||
* When a socket is bound to a bus it also sets up a peer signature and
|
||||
* signature mask, which together indicate the expected signature of events
|
||||
* arriving at the socket. Validation is done by checking only the portion
|
||||
* of the peer signature that the socket needs to validate.
|
||||
*
|
||||
* - A connection-based socket normally validates the entire signature to ensure
|
||||
* it is communicating with its peer. A listening socket only validates the
|
||||
* type field, since it can receive SYNs from any connection-based port.
|
||||
*
|
||||
* - A connectionless socket normally validates only the type field, since
|
||||
* it can receive from any connectionless port. However, if the socket has
|
||||
* been assigned a specific peer (via mipc_connect()), it validates the node
|
||||
* id and port id fields (but not the port signature) to ensure it receives
|
||||
* events from any instance of the specified socket address.
|
||||
*
|
||||
* Unlike the socket's connection signature, its peer signature and signature
|
||||
* mask can change after the socket has been bound to a bus (for example,
|
||||
* by calling mipc_connect()).
|
||||
*/
|
||||
|
||||
/* connection signature values */
|
||||
|
||||
#define MIPC_SM_CONN_SIG_TYPE_INVALID 0x00000000U /* invalid signature */
|
||||
#define MIPC_SM_CONN_SIG_TYPE_REALCONN 0x10000000U /* connection-based */
|
||||
#define MIPC_SM_CONN_SIG_TYPE_CONNLESS 0x20000000U /* connectionless */
|
||||
/* note: types 0x3 through 0xF are also invalid */
|
||||
|
||||
#define MIPC_SM_CONN_SIG_CHECK_TYPE 0xF0000000U /* check type only */
|
||||
#define MIPC_SM_CONN_SIG_CHECK_PORTID 0xFFFFFF00U /* check type & portid */
|
||||
#define MIPC_SM_CONN_SIG_CHECK_ALL 0xFFFFFFFFU /* check full signature */
|
||||
|
||||
/* # leading bytes of socket that are initialized using socket template */
|
||||
#define SOCK_INIT_SIZE MULTIOS_STRUCT_MEMBER_OFFSET(MipcSmSocket, sd)
|
||||
|
||||
extern uint32_t mipcSmMaxSockets; /* maximum sockets on node */
|
||||
extern MipcSmSocket *mipcSmAllSockets; /* pointer to array of sockets */
|
||||
|
||||
/* Initialize the pool of socket descriptors */
|
||||
int mipc_sm_socket_init(unsigned int maxSockets);
|
||||
|
||||
/* Allocate a socket descriptor */
|
||||
int mipc_sm_socket_alloc(MipcSmSocket **theSocket);
|
||||
|
||||
/* Return a socket descriptor to the pool of free descriptors */
|
||||
int mipc_sm_socket_free(MipcSmSocket *theSocket);
|
||||
|
||||
|
||||
/* Return socket descriptor given a socket pointer */
|
||||
static MULTIOS_INLINE int mipc_sm_sock2sd(MipcSmSocket *theSocket) {
|
||||
return theSocket->sd;
|
||||
}
|
||||
|
||||
/* Return a socket pointer given a socket descriptor */
|
||||
static MULTIOS_INLINE MipcSmSocket *mipc_sm_socket_ptr_valid(int sd)
|
||||
{
|
||||
return (MipcSmSocket *)((char *)mipcSmAllSockets + mipc_sd2offset(sd));
|
||||
}
|
||||
|
||||
/* Return socket pointer given a socket descriptor */
|
||||
static MULTIOS_INLINE MipcSmSocket *mipc_sm_socket_ptr(int sd)
|
||||
{
|
||||
#ifdef MIPC_CHECK_ARGS
|
||||
if (mipc_sm_system_init_check() && mipc_sd_legal(sd)) {
|
||||
MipcSmSocket *theSocket = mipc_sm_socket_ptr_valid(sd);
|
||||
if (theSocket->allocated) {
|
||||
return theSocket;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
#else
|
||||
return mipc_sm_socket_ptr_valid(sd);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Wait for synchronization condition to occur */
|
||||
int mipc_sm_socket_wait(MipcSmSocket *theSocket,
|
||||
struct mipc_sm_socket_sync *wait, int timeout,
|
||||
int(*condition_met)(MipcSmSocket *));
|
||||
|
||||
/* Wake up any thread waiting for synchronization condition */
|
||||
static MULTIOS_INLINE void mipc_sm_socket_do_sync(
|
||||
struct mipc_sm_socket_sync *wait)
|
||||
{
|
||||
if (MULTIOS_ATOMIC_CAS(&wait->flag, 1, 0)) {
|
||||
MULTIOS_SEM_UP(&wait->sem);
|
||||
}
|
||||
}
|
||||
|
||||
/* Enqueue packet on a socket's receive queue */
|
||||
int mipc_sm_socket_packet_queue(MipcSmSocket *theSocket,
|
||||
MipcSmPacketDesc *bufDesc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INC_mipc_sm_socket_h */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,149 @@
|
||||
/* mipc_sm_system.h - MIPC-SM system */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01s,07jan11,jlk Update license header
|
||||
01r,14sep10,jlk Add system option support including debug mode
|
||||
01q,26aug10,jlk Make sure #ifdef __cplusplus starts after #includes
|
||||
01p,01oct09,als Finalize versioning info in shared memory
|
||||
01o,23sep09,bwa add connection signature
|
||||
01n,14sep09,als Enhance node restart capability
|
||||
01m,20aug09,als Add node restart support
|
||||
01l,04aug09,als Convert shared memory offsets to use MIPC_OFFSET type
|
||||
01k,27jul09,als Make bus heartbeat period a system critical setting
|
||||
01j,02jul09,als Changes to reflect updated file names
|
||||
01i,02jul09,als Move mipcSmBuses to be with other system global variables
|
||||
01h,25jun09,als Rework memory region code to fix WIND00167982
|
||||
01g,18jun09,als Fix bug in memory region alignment handling
|
||||
01g,17jun09,ebh Fix comment spacing
|
||||
01f,02jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01e,26may09,ebh Code Inspection Modifications
|
||||
01d,13may09,ebh Move macros from api_defs.h
|
||||
01c,24mar09,ebh Make inlines static and use MULTIOS_INLINE
|
||||
01b,23mar09,ebh Fix portability issues in code
|
||||
01a,25nov08,apa Initial version.
|
||||
*/
|
||||
|
||||
#ifndef __INC_mipc_sm_system_h
|
||||
#define __INC_mipc_sm_system_h
|
||||
|
||||
#include "mipc_sm_bus.h"
|
||||
#include "mipc_sm_node.h"
|
||||
#include "mipc_sm_port.h"
|
||||
#include "mipc_sm_mem_region.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* MIPC system structure (resides in SM) */
|
||||
|
||||
struct mipc_sm_system
|
||||
{
|
||||
MULTIOS_ATOMIC state; /* system state */
|
||||
uint8_t versionMajor; /* X digit of MIPC X.Y */
|
||||
uint8_t versionMinor; /* Y digit of MIPC X.Y */
|
||||
uint8_t sysOpts; /* system options */
|
||||
uint8_t reserved; /* currently unused */
|
||||
uint16_t maxBuses; /* # buses in SM bus descriptor array */
|
||||
uint16_t heartbeatPeriod; /* heartbeat period (in ms) */
|
||||
MULTIOS_ATOMIC id_generator; /* generates 32-bit IDs */
|
||||
MIPC_OFFSET maxOffset; /* total size of SM area */
|
||||
struct mipc_sm_mem_region memPool; /* SM memory pool descriptor */
|
||||
MIPC_OFFSET busesOffset; /* offset of SM bus descriptor array */
|
||||
MIPC_OFFSET reservedOffset; /* currently unused */
|
||||
};
|
||||
|
||||
/*
|
||||
* System state info is held in an atomic variable with the following format:
|
||||
*
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | flags | initializing node id |s-incarn|memstate|
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
*
|
||||
* |- sys signature -|
|
||||
*
|
||||
* Memory state indicates the state of shared memory (either initialized,
|
||||
* initializing, or uninitialized).
|
||||
*
|
||||
* System incarnation is a counter that is incremented every time shared memory
|
||||
* is (re)initialized.
|
||||
*
|
||||
* Together, the low order 8 bits form a "system signature", which is different
|
||||
* for each incarnation of the system and is constant during its lifetime.
|
||||
* A change in the system signature allows nodes to detect when shared memory
|
||||
* is about to be re-initialized.
|
||||
*
|
||||
* The initializing node id records which node initialized shared memory
|
||||
* during the most recent incarnation of the system. This info is not used
|
||||
* by MIPC itself, but it may come in handy for debugging system initialization
|
||||
* problems.
|
||||
*
|
||||
* Flags are currently unused. They are set to zero, so they can be more
|
||||
* easily utilized for new purposes in the future.
|
||||
*/
|
||||
|
||||
#define SYSTEM_MEM_STATE_MASK 0x0000000F
|
||||
#define SYSTEM_MEM_INITIALIZING 0x00000001 /* SM currently being set up */
|
||||
#define SYSTEM_MEM_INITIALIZED 0x00000002 /* SM has been fully set up */
|
||||
/* Note: any other value for memory state means "uninitialized" */
|
||||
|
||||
#define SYSTEM_SIG_MASK 0x000000FF
|
||||
#define SYSTEM_INCARN_MASK 0x000000F0
|
||||
#define SYSTEM_INCARN_INCREMENT 0x00000010
|
||||
|
||||
|
||||
/*
|
||||
* System option flags.
|
||||
* These are the actual bit values that go into the sysOpts field
|
||||
*/
|
||||
#define MIPC_SYSOPT_DEBUG_FLG 0x1U
|
||||
|
||||
/* Check if the MIPC-SM system has been initialized on this host */
|
||||
static MULTIOS_INLINE int mipc_sm_system_init_check(void)
|
||||
{
|
||||
return mipc_sm_initialized;
|
||||
}
|
||||
|
||||
/* Return a MIPC-SM auto-generated ID */
|
||||
uint32_t mipc_sm_system_generate_id(void);
|
||||
|
||||
/* Return the maximum number of buses and a pointer to the buses */
|
||||
struct mipc_sm_bus *mipc_sm_system_get_buses(uint16_t *numBuses);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INC_mipc_sm_system_h */
|
||||
|
||||
@@ -0,0 +1,963 @@
|
||||
/* mipc_sm_vxworks.c - VxWorks adaptation code for MIPC-SM (main part) */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2012, 2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
02y,26jun13,h_l fix coverity issue.(WIND00423763)
|
||||
02x,09jul12,zhw Removal of warnings (WIND00357525)
|
||||
02w,18feb11,ebh Fix warning about ambiguous else clause
|
||||
02w,05jan11,wy1 Add a new function multios_down_timeout (WIND00246398)
|
||||
02v,18oct10,swg fix WIND00235791, change the type of intId and outIntId in struct
|
||||
mipc_vx_bus_dev into int32_t, and check the parameter when calling
|
||||
vbiVioapicIntSend() in function mipc_sm_adapt_notify_node()
|
||||
02u,10dec10,rab fix args in polled mode MIPC_PRINT
|
||||
02t,09sep10,jlk Cleanup: Remove unused mipc_sm_semtask_priority global
|
||||
02s,23Aug10,jlk WIND00229705 - Make mipc_sm_adapt_config_done() consistent
|
||||
with version in WR Linux.
|
||||
02r,30mar10,als Initial changes in support of 64-bit memory addressing
|
||||
02q,18mar10,wy1 fix WIND00199391,WIND00203299, fill the outIntId field in
|
||||
func-mipc_sm_adapt_config_done, when running in wrhv.
|
||||
02p,05feb10,j_y change vxIpiEmit() to vxIpiPhysEmit()
|
||||
for mipc smp m-n adatption
|
||||
02o,02feb10,d_c SMP M-N Updates: change prototype for vxCpuIdGet()
|
||||
02n,15jan10,j_y change the return value of mipc_sm_adapt_get_cpu_id()
|
||||
for mipc smp m-n adatption
|
||||
02m,29oct09,als Finish conversion to VBI 2.0 (WIND185734)
|
||||
02l,03sep09,dcc fix merge issue
|
||||
02k,01sep09,als Simplify logic in deferred interrupt handling
|
||||
02j,21aug09,dcc added support for WRHV 1.1
|
||||
02i,17aug09,d_c Add VBI2.0 support
|
||||
Defect WIND00177074 Fix WIND00177093
|
||||
02h,26aug09,bwa Optimized behaviour of mipcIsrDeferFunc().
|
||||
02g,24aug09,bwa Use sysProcNumXXX for node numbers.
|
||||
02f,21aug09,bwa removed mipcIsrDemuxFunc() from hypervisor guest builds.
|
||||
02e,20aug09,bwa Fixed uninitialized variable in mipcIsrDeferFunc().
|
||||
Removed mipcIsrGiveTask() prototype.
|
||||
02d,19aug09,bwa Fixed deferral mode race condition between work task and ISR
|
||||
where both were reading/writing 'working' state and 'new work
|
||||
arrival' flag non-atomically.
|
||||
02c,19aug09,bwa Replaced useless QOS prio by bus num in tMipcQos task name
|
||||
(prio can be obtained via 'i', bus number cannot).
|
||||
02b,19aug09,bwa Fixed possible buffer overflow when creating the task name.
|
||||
02a,19aug09,bwa Fixed possible buffer overflow when creating the bus name.
|
||||
01z,19aug09,bwa Fixed function header alignment for documentation tool.
|
||||
01y,18aug09,jlk WIND00177194 - Remove deferred semaphore code.
|
||||
01x,10aug09,ebh Fix sizing of the deferred semaphore table
|
||||
01w,07aug09,ebh Code inspection updates
|
||||
01v,07aug09,als Make socket descriptors simple positive integers
|
||||
01u,06aug09,als Move port's socket id out of shared memory
|
||||
01t,30jul09,ebh Further code inspection changes
|
||||
01s,29jul09,als Add support for per-bus statistics collection
|
||||
01r,24jul09,ebh Updates as per code inspection
|
||||
01q,22jul09,als Allow adaptation code to handle fatal errors detected by
|
||||
common code
|
||||
01p,09jul09,dcc set up node's intId for correct show routines display.
|
||||
01o,02jul09,als Created from mipc_sm_notify_vxworks.c
|
||||
01n,02jul09,als Use embedded semaphore in local bus info
|
||||
01m,24jun09,dcc added support for WRHV Guest OS
|
||||
01l,16jun09,als Enhance error path code during initialization
|
||||
01l,16jun09,ebh Fixes for ISR-processed mode
|
||||
01k,15jun09,ebh Change socket offsets to socket values in bitmapped
|
||||
notifications
|
||||
01j,03jun09,als Rework system configuration/initialization as per HLD and CI
|
||||
01l,03jun09,ebh Fix gnu compiler warnings
|
||||
01k,03jun09,h_w Fix WIND00166396 - embed semaphores into MipcSmSocket
|
||||
01j,02jun09,zhw Add busId for mipc_sm_notify_node()
|
||||
01i,29may09,als Revise configuration based on MIPC 2.0 HLD feedback
|
||||
01h,04may09,ebh Updates deferred gives and debugging routines
|
||||
01g,30apr09,ebh Ensure that mipc.h is included first
|
||||
01f,23apr09,ebh Continued work on preventing work queue panics and add in
|
||||
support for the txbufferSem for ANY socket
|
||||
01e,21apr09,ebh Add capability to give all semaphores at task level
|
||||
01d,21apr09,ebh Add return values to ISR registration functions
|
||||
01c,23mar09,ebh Remove unused variables
|
||||
01b,24feb09,ebh Modify parameter of mipc_sm_notify_node to be the node struct
|
||||
01a,25nov08,apa Initial version.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This file implements the bulk of the VxWorks adaptation support for MIPC-SM.
|
||||
This includes:
|
||||
- implementing the adaptation routines called by MIPC-SM
|
||||
- implementing the interrupt handlers and tasks required to detect incoming
|
||||
events on buses that run in ISR mode or ISR deferred mode
|
||||
|
||||
The routines in this file are divided into two sections. The first section
|
||||
provides the routines that must be present because they are called by the
|
||||
common code. The second section contains routines only used in the VxWorks
|
||||
adaptation code and not called directly by name by any common code (some
|
||||
routines may be called by reference).
|
||||
*/
|
||||
|
||||
#include <multios_ipc/mipc_sm_adapt.h>
|
||||
#include "mipc_sm_core.h"
|
||||
#include "mipc_sm_socket.h"
|
||||
#include <edrLib.h>
|
||||
#include <jobQueueLib.h>
|
||||
#include <string.h>
|
||||
#include <vxIpiLib.h>
|
||||
|
||||
#if defined (_WRS_CONFIG_WRHV_GUEST)
|
||||
#include <wrhv/vbi.h>
|
||||
#include "mipc_sm_node.h"
|
||||
#else
|
||||
#include <vxCpuLib.h>
|
||||
#endif
|
||||
|
||||
/* Symbols defined by MIPC-SM configlette */
|
||||
|
||||
IMPORT int mipc_sm_rxtask_stack;
|
||||
|
||||
/*
|
||||
* Definitions used to support basic operation of MIPC buses
|
||||
*/
|
||||
|
||||
#define MIPC_WORK_RUNNING 0x01 /* work task is handling events */
|
||||
#define MIPC_WORK_ADDED 0x02 /* new event have arrived */
|
||||
|
||||
/* MIPC ISR deferred bus worker task job item */
|
||||
|
||||
struct mipc_job_item
|
||||
{
|
||||
QJOB qjob; /* job control info [must be first field!] */
|
||||
void *arg; /* job argument (i.e. busId)*/
|
||||
};
|
||||
|
||||
/* MIPC bus device descriptor */
|
||||
|
||||
struct mipc_vx_bus_dev
|
||||
{
|
||||
int qos; /* bus QOS */
|
||||
MULTIOS_ATOMIC *stats; /* ptr to bus statistics array */
|
||||
|
||||
/* The following fields are only used by buses with QOS >= 0 */
|
||||
|
||||
#ifdef _WRS_CONFIG_WRHV_GUEST
|
||||
int32_t outIntId; /* output interrupt number */
|
||||
#endif
|
||||
|
||||
int32_t intId; /* interrupt number */
|
||||
MIPC_ISR_FUNC func; /* ISR handler to call */
|
||||
void * arg; /* ISR handler arg */
|
||||
|
||||
/* The following fields are only used by buses with QOS > 0 */
|
||||
|
||||
TASK_ID workTaskId; /* task id of worker task */
|
||||
JOB_QUEUE_ID jobQueueId; /* work job queue ID */
|
||||
struct mipc_job_item workTaskJob; /* worker task job */
|
||||
atomic_t workState; /* state of task work */
|
||||
};
|
||||
|
||||
LOCAL struct mipc_vx_bus_dev *bus_dev; /* ptr to array of bus devices */
|
||||
LOCAL int mipc_saved_isr_busId;
|
||||
LOCAL unsigned int mipc_saved_max_buses;
|
||||
LOCAL int mipc_num_isr_work_buses;
|
||||
LOCAL int mipc_num_isr_defer_buses;
|
||||
|
||||
/* function prototypes */
|
||||
|
||||
LOCAL void mipcTaskWorkFunc(QJOB *pJob);
|
||||
LOCAL void mipcIsrDeferFunc(void *arg);
|
||||
LOCAL void mipcIsrWorkFunc(void *arg);
|
||||
|
||||
#ifndef _WRS_CONFIG_WRHV_GUEST
|
||||
LOCAL void mipcIsrDemuxFunc(void *arg);
|
||||
#endif
|
||||
|
||||
/***********************************************************
|
||||
* API Adaptation routines called by the MIPC common code
|
||||
* (these must be provided by any OS supporting MIPC)
|
||||
**********************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_adapt_validate_settings - validate settings against MIPC configuration
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
int mipc_sm_adapt_validate_settings(uint16_t num_buses,
|
||||
struct mipc_sm_sys_config *sys,
|
||||
struct mipc_sm_node_config *nodes,
|
||||
struct mipc_sm_bus_config *buses)
|
||||
{
|
||||
/* nothing to do for vxWorks */
|
||||
(void) num_buses;
|
||||
(void) sys;
|
||||
(void) nodes;
|
||||
(void) buses;
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_alloc_sock_user_handle - allocate an array of long used as socket user handle
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
unsigned long *mipc_alloc_sock_user_handle(uint32_t number)
|
||||
{
|
||||
return (unsigned long *)MULTIOS_KALLOC(number * sizeof(unsigned long));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_free_sock_user_handle - free array of long used as socket user handle
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
void mipc_free_sock_user_handle(unsigned long *ptr)
|
||||
{
|
||||
MULTIOS_KFREE(ptr);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_alloc_socket - allocate an array of mipc_sm_socket
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
struct mipc_sm_socket *mipc_alloc_socket(uint32_t number)
|
||||
{
|
||||
/* Note: size of one MipcSmSocket is rounded up to (1 << MIPC_SD_BITS) */
|
||||
/* coverity[incorrect_multiplication] */
|
||||
return (struct mipc_sm_socket *)MULTIOS_KALLOC(number * (1 << MIPC_SD_BITS));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_free_socket - free array of mipc_sm_socket
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
void mipc_free_socket(struct mipc_sm_socket *ptr)
|
||||
{
|
||||
MULTIOS_KFREE(ptr);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_alloc_rx_buffer - allocate an array of mipc_sm_rx_buffer
|
||||
* for socket descriptor 'sd'
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
struct mipc_sm_rx_buffer *mipc_alloc_rx_buffer(int sd, uint32_t number)
|
||||
{
|
||||
/* unused parameter */
|
||||
(void) sd;
|
||||
|
||||
return (struct mipc_sm_rx_buffer *)MULTIOS_KALLOC(number *
|
||||
sizeof(struct mipc_sm_rx_buffer));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_free_rx_buffer - free mipc_sm_rx_buffer array for socket 'sd'
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
void mipc_free_rx_buffer(int sd, struct mipc_sm_rx_buffer *ptr)
|
||||
{
|
||||
/* unused parameter */
|
||||
(void) sd;
|
||||
|
||||
MULTIOS_KFREE(ptr);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_alloc_conn_request - allocate an array of mipc_sm_conn_request
|
||||
* for socket descriptor 'sd'
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
struct mipc_sm_conn_request *mipc_alloc_conn_request(int sd, uint32_t number)
|
||||
{
|
||||
/* unused parameter */
|
||||
(void) sd;
|
||||
|
||||
return (struct mipc_sm_conn_request *)MULTIOS_KALLOC(number *
|
||||
sizeof(struct mipc_sm_conn_request));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_free_conn_request - free array of mipc_sm_conn_request for socket 'sd'
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
void mipc_free_conn_request(int sd, struct mipc_sm_conn_request *ptr)
|
||||
{
|
||||
/* unused parameter */
|
||||
(void) sd;
|
||||
|
||||
MULTIOS_KFREE(ptr);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_alloc_local_port_info - allocate an array of mipc_alloc_local_port_info
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
struct mipc_sm_local_port_info *mipc_alloc_local_port_info(int busId, uint32_t number)
|
||||
{
|
||||
/* unused parameter */
|
||||
(void) busId;
|
||||
|
||||
return (struct mipc_sm_local_port_info *)MULTIOS_KALLOC(number *
|
||||
sizeof(struct mipc_sm_local_port_info));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_free_local_port_info - free array of mipc_alloc_local_port_info
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
void mipc_free_local_port_info(struct mipc_sm_local_port_info *ptr)
|
||||
{
|
||||
MULTIOS_KFREE(ptr);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_alloc_local_peer_info - allocate an array of mipc_sm_local_peer_info
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
struct mipc_sm_local_peer_info *mipc_alloc_local_peer_info(int busId, uint32_t number)
|
||||
{
|
||||
return (struct mipc_sm_local_peer_info *)MULTIOS_KALLOC(number *
|
||||
sizeof(struct mipc_sm_local_peer_info));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_free_local_peer_info - free array of mipc_sm_local_peer_info
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
void mipc_free_local_peer_info(struct mipc_sm_local_peer_info *ptr)
|
||||
{
|
||||
MULTIOS_KFREE(ptr);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_alloc_local_bus_info - allocate an array of mipc_sm_local_bus_info
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
struct mipc_sm_local_bus_info *mipc_alloc_local_bus_info(uint32_t number)
|
||||
{
|
||||
return (struct mipc_sm_local_bus_info *)MULTIOS_KALLOC(number *
|
||||
sizeof(struct mipc_sm_local_bus_info));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_free_local_bus_info - free array of mipc_sm_local_bus_info
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
void mipc_free_local_bus_info(struct mipc_sm_local_bus_info *ptr)
|
||||
{
|
||||
MULTIOS_KFREE(ptr);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_alloc_bus_config - allocate an array of mipc_sm_bus_config
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
struct mipc_sm_bus_config *mipc_alloc_bus_config(uint32_t number)
|
||||
{
|
||||
return (struct mipc_sm_bus_config *)MULTIOS_KALLOC(number *
|
||||
sizeof(struct mipc_sm_bus_config));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_free_bus_config - free array of mipc_sm_bus_config
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
void mipc_free_bus_config(struct mipc_sm_bus_config *ptr)
|
||||
{
|
||||
MULTIOS_KFREE(ptr);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_alloc_node_config - allocate an array of mipc_sm_node_config
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
struct mipc_sm_node_config *mipc_alloc_node_config(uint32_t number)
|
||||
{
|
||||
return (struct mipc_sm_node_config *)MULTIOS_KALLOC(number *
|
||||
sizeof(struct mipc_sm_node_config));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_free_node_config - free array of mipc_sm_node_config
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
void mipc_free_node_config(struct mipc_sm_node_config *ptr)
|
||||
{
|
||||
MULTIOS_KFREE(ptr);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_alloc_sys_config - allocate an array of mipc_sm_sys_config structure
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
struct mipc_sm_sys_config *mipc_alloc_sys_config(void)
|
||||
{
|
||||
return (struct mipc_sm_sys_config *)MULTIOS_KALLOC(
|
||||
sizeof(struct mipc_sm_sys_config));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_free_sys_config - free a mipc_sm_sys_config structure
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
void mipc_free_sys_config(struct mipc_sm_sys_config *ptr)
|
||||
{
|
||||
MULTIOS_KFREE(ptr);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_adapt_get_cpu_id - return the CPU ID.
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
int mipc_sm_adapt_get_cpu_id(void)
|
||||
{
|
||||
#if defined (_WRS_CONFIG_WRHV_GUEST)
|
||||
return (VBI_BOARD_ID_GET() - 1);
|
||||
#else
|
||||
return CPU_LOGICAL_TO_PHYS(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_adapt_get_node_id - return the node ID
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
int mipc_sm_adapt_get_node_id(void)
|
||||
{
|
||||
#if defined (_WRS_CONFIG_WRHV_GUEST)
|
||||
return (VBI_BOARD_ID_GET() - 1);
|
||||
#else
|
||||
return sysProcNumGet();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_adapt_config_init - prepare for registration of buses
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
int mipc_sm_adapt_config_init(uint32_t maxBuses)
|
||||
{
|
||||
bus_dev = (struct mipc_vx_bus_dev *)
|
||||
MULTIOS_KALLOC(maxBuses * sizeof(struct mipc_vx_bus_dev));
|
||||
if (!bus_dev)
|
||||
{
|
||||
MIPC_PRINT(MIPC_ALERT "unable to create bus devices\n");
|
||||
return -MIPC_ENOMEM;
|
||||
}
|
||||
|
||||
/* Assume all buses will operate in user mode */
|
||||
|
||||
memset(bus_dev, 0xff, maxBuses * sizeof(struct mipc_vx_bus_dev));
|
||||
mipc_num_isr_work_buses = 0;
|
||||
mipc_num_isr_defer_buses = 0;
|
||||
mipc_saved_max_buses = maxBuses;
|
||||
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_adapt_config_bus - register a bus
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
int mipc_sm_adapt_config_bus(uint16_t busId, uint16_t nodeId, int qos,
|
||||
uint16_t intId, MULTIOS_ATOMIC *stats)
|
||||
{
|
||||
bus_dev[busId].qos = qos;
|
||||
bus_dev[busId].stats = stats;
|
||||
|
||||
if (qos < 0)
|
||||
{
|
||||
/* Nothing else to do for bus running in user mode ... */
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
if (qos == 0)
|
||||
{
|
||||
bus_dev[busId].func = mipcIsrWorkFunc;
|
||||
mipc_num_isr_work_buses++;
|
||||
}
|
||||
else
|
||||
{
|
||||
bus_dev[busId].func = mipcIsrDeferFunc;
|
||||
mipc_num_isr_defer_buses++;
|
||||
}
|
||||
bus_dev[busId].arg = (void *)(unsigned long)busId;
|
||||
bus_dev[busId].intId = intId;
|
||||
|
||||
mipc_saved_isr_busId = busId;
|
||||
|
||||
/* Note: nodeId is unused since it's the same on all buses ... */
|
||||
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_adapt_config_done - complete registration of buses
|
||||
*
|
||||
* This routine completes any registration needed for ISRs.
|
||||
*
|
||||
* NOTE: If errors occur during this routine, it does *not* attempt to free up
|
||||
* any resources it has allocated since they may be needed by the subset
|
||||
* of MIPC's buses (if any) that *were* successfully registered.
|
||||
* NOTE: mipcMaxSockets is assumed to be valid before calling this routine
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
int mipc_sm_adapt_config_done(uint32_t maxBuses)
|
||||
{
|
||||
int num_isr_buses;
|
||||
unsigned int busId;
|
||||
int rc = MIPC_OK;
|
||||
|
||||
/* Register ISR to handle interrupt-driven bus (or buses), if any */
|
||||
|
||||
num_isr_buses = mipc_num_isr_work_buses + mipc_num_isr_defer_buses;
|
||||
|
||||
#ifndef _WRS_CONFIG_WRHV_GUEST
|
||||
if (num_isr_buses == 1)
|
||||
{
|
||||
rc = mipc_sm_isr_set((uint16_t)bus_dev[mipc_saved_isr_busId].intId,
|
||||
bus_dev[mipc_saved_isr_busId].func,
|
||||
bus_dev[mipc_saved_isr_busId].arg);
|
||||
}
|
||||
else if (num_isr_buses > 1)
|
||||
{
|
||||
|
||||
/* VXWORKS AMP SYSTEMS USE A SINGLE INTERRUPT FOR ALL BUSES */
|
||||
/* Note: all buses shared the same interrupt ... */
|
||||
rc = mipc_sm_isr_set((uint16_t)bus_dev[mipc_saved_isr_busId].intId,
|
||||
mipcIsrDemuxFunc,
|
||||
NULL);
|
||||
}
|
||||
#else /* VXWORKS GUEST SYSTEMS USE A DIFFERENT INTERRUPT FOR EACH BUS */
|
||||
rc = -MIPC_EINVAL;
|
||||
for (busId = 0; busId < maxBuses ; busId++)
|
||||
{
|
||||
char bus_name[12];
|
||||
struct mipc_sm_node *node;
|
||||
|
||||
sprintf(bus_name, "mipcbus%u", busId);
|
||||
|
||||
/* Set up interrupt we use to interrupt other nodes */
|
||||
|
||||
bus_dev[busId].outIntId = vbiIntVecFind (bus_name, VB_OUTPUT_INT);
|
||||
if (bus_dev[busId].outIntId < 0)
|
||||
{
|
||||
if (bus_dev[busId].qos >= 0)
|
||||
{
|
||||
/*
|
||||
* issue message if a non-polled bus has no
|
||||
* output interrupt; this is OK if all other
|
||||
* nodes are running in polled mode,
|
||||
* but it is definitely unusual ...
|
||||
*/
|
||||
MIPC_PRINT(MIPC_INFO "%s can't find its output interrupt "
|
||||
"-- other nodes must use polling\n",
|
||||
bus_name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up interrupt that other nodes use to interrupt us
|
||||
*
|
||||
* We also update the intId field in shared memory to reflect
|
||||
* the interrupt actually being used -- this value is ignored
|
||||
* by all guest OS's, but can still be seen using show routines
|
||||
*/
|
||||
bus_dev[busId].intId = vbiIntVecFind (bus_name, VB_INPUT_INT);
|
||||
node = mipc_sm_node_ptr_valid(busId, mipc_node_id);
|
||||
node->intId = MULTIOS_hton16(bus_dev[busId].intId);
|
||||
|
||||
if (bus_dev[busId].intId < 0)
|
||||
{
|
||||
if (bus_dev[busId].qos >= 0)
|
||||
{
|
||||
/*
|
||||
* non-polled bus is missing its interrupt
|
||||
* -- issue warning & treat bus as not "OK"
|
||||
*/
|
||||
MIPC_PRINT(MIPC_ALERT
|
||||
"%s can't find its input interrupt "
|
||||
"-- bus is non-operational\n",
|
||||
bus_name);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* polled bus doesn't need an interrupt
|
||||
* so it's always "OK"
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bus_dev[busId].qos < 0)
|
||||
{
|
||||
/*
|
||||
* polled bus has an interrupt defined
|
||||
* -- issue message, but consider bus as "OK"
|
||||
*/
|
||||
mipc_sm_isr_set (bus_dev[busId].intId,
|
||||
bus_dev[busId].func,
|
||||
bus_dev[busId].arg);
|
||||
|
||||
MIPC_PRINT(MIPC_INFO
|
||||
"%s uses polling "
|
||||
"-- input interrupt %u is not used\n",
|
||||
bus_name, bus_dev[busId].intId);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* non-polled bus needs an interrupt
|
||||
* -- issue warning & treat bus as not "OK"
|
||||
* if unable to enable it
|
||||
*/
|
||||
|
||||
if (mipc_sm_isr_set (bus_dev[busId].intId,
|
||||
bus_dev[busId].func,
|
||||
bus_dev[busId].arg))
|
||||
{
|
||||
MIPC_PRINT(MIPC_ALERT
|
||||
"%s can't register input interrupt %u "
|
||||
"-- bus is non-operational\n",
|
||||
bus_name, bus_dev[busId].intId);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rc = MIPC_OK;
|
||||
|
||||
} /* for (busId = ... */
|
||||
|
||||
/* We continue if at least one bus was OK.*/
|
||||
|
||||
#endif
|
||||
|
||||
if (rc)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Create a worker task for every bus running in ISR deferred mode */
|
||||
|
||||
for (busId = 0; busId < maxBuses; busId++)
|
||||
{
|
||||
char taskName[12];
|
||||
|
||||
if (bus_dev[busId].qos <= 0)
|
||||
continue;
|
||||
|
||||
bus_dev[busId].workTaskJob.qjob.func = (QJOB_FUNC)mipcTaskWorkFunc;
|
||||
bus_dev[busId].workTaskJob.qjob.pNext = NULL;
|
||||
bus_dev[busId].workTaskJob.qjob.priInfo = 0;
|
||||
bus_dev[busId].workTaskJob.arg = (void *)(unsigned long)busId;
|
||||
vxAtomicSet(&bus_dev[busId].workState, 0);
|
||||
|
||||
bus_dev[busId].jobQueueId = jobQueueCreate(NULL);
|
||||
if (!bus_dev[busId].jobQueueId)
|
||||
{
|
||||
return -MIPC_ENOMEM;
|
||||
}
|
||||
|
||||
snprintf(taskName, 12, "tMipcBus%d", busId);
|
||||
bus_dev[busId].workTaskId = taskSpawn(taskName, bus_dev[busId].qos,
|
||||
0, (size_t)mipc_sm_rxtask_stack,
|
||||
(FUNCPTR)jobQueueProcess,
|
||||
(_Vx_usr_arg_t)bus_dev[busId].jobQueueId,
|
||||
(_Vx_usr_arg_t)0,
|
||||
(_Vx_usr_arg_t)0,
|
||||
(_Vx_usr_arg_t)0,
|
||||
(_Vx_usr_arg_t)0,
|
||||
(_Vx_usr_arg_t)0,
|
||||
(_Vx_usr_arg_t)0,
|
||||
(_Vx_usr_arg_t)0,
|
||||
(_Vx_usr_arg_t)0,
|
||||
(_Vx_usr_arg_t)0);
|
||||
if (bus_dev[busId].workTaskId == TASK_ID_ERROR)
|
||||
{
|
||||
return -MIPC_ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
return MIPC_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_adapt_config_abort - abort startup prior to registration of buses
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
void mipc_sm_adapt_config_abort(void)
|
||||
{
|
||||
/* Destroy array of bus devices */
|
||||
|
||||
MULTIOS_KFREE(bus_dev);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_adapt_notify_node - send an event notification to a node
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
int mipc_sm_adapt_notify_node(uint16_t busId, uint16_t cpuId, uint16_t intId)
|
||||
{
|
||||
int retVal;
|
||||
#ifndef _WRS_CONFIG_WRHV_GUEST
|
||||
return vxIpiPhysEmit(intId, (1U << cpuId));
|
||||
#else
|
||||
if (bus_dev[busId].outIntId < 0) {
|
||||
MIPC_PRINT(MIPC_ALERT
|
||||
"notify node error: bus %u outIntId invalid\n",
|
||||
busId);
|
||||
return -MIPC_EINVAL;
|
||||
}
|
||||
|
||||
retVal = vbiVioapicIntSend ((vbiIrq_t) bus_dev[busId].outIntId,
|
||||
VBI_IOAPICSEND_UNICAST, cpuId + 1);
|
||||
if (retVal) {
|
||||
MIPC_PRINT(MIPC_ALERT
|
||||
"notify node error: IntSend %d bus %u outInt %u\n",
|
||||
retVal, busId, bus_dev[busId].outIntId);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
return MIPC_OK;
|
||||
#endif /* _WRS_CONFIG_WRHV_GUEST */
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mipc_sm_adapt_fatal_error - respond to fatal error reported by MIPC
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
void mipc_sm_adapt_fatal_error(char *reason)
|
||||
{
|
||||
/* generate a kernel panic */
|
||||
|
||||
if (INT_CONTEXT()) {
|
||||
EDR_INTERRUPT_FATAL_INJECT(NULL, NULL, NULL, NULL, reason);
|
||||
} else {
|
||||
EDR_KERNEL_FATAL_INJECT(NULL, NULL, NULL, NULL, reason);
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
* Adaptation routines strictly used in VxWorks adaptation
|
||||
* (not called directly by the MIPC common code)
|
||||
**********************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* mipcTaskWorkFunc - worker task routine for bus running in ISR deferred mode
|
||||
*
|
||||
* This routine tells MIPC to process events for the associated bus.
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
LOCAL void mipcTaskWorkFunc(QJOB *pJob)
|
||||
{
|
||||
uint16_t busId = (uint16_t)
|
||||
(((unsigned long)((struct mipc_job_item *)pJob)->arg) & 0xffffUL);
|
||||
atomic_t *pWorkState;
|
||||
|
||||
MIPC_STATS_ADD(bus_dev[busId].stats, MIPC_STATS_INTERRUPTS_DEFERRED, 1);
|
||||
|
||||
pWorkState = &bus_dev[busId].workState;
|
||||
do
|
||||
{
|
||||
vxAtomicSet(pWorkState, MIPC_WORK_RUNNING);
|
||||
mipc_sm_api_process_rx_events(busId);
|
||||
}
|
||||
while (!vxAtomicCas(pWorkState, MIPC_WORK_RUNNING, 0));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* mipcIsrDeferFunc - ISR for bus running in ISR deferred mode
|
||||
*
|
||||
* This routine schedules the work task for this bus to process bus events.
|
||||
* If the task is already running, the routine just tells it to keep going.
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
LOCAL void mipcIsrDeferFunc(void *arg)
|
||||
{
|
||||
int busId = (uint16_t)((unsigned long)arg & 0xffffUL);
|
||||
atomic_t *pWorkState;
|
||||
atomicVal_t workState;
|
||||
|
||||
MIPC_STATS_ADD(bus_dev[busId].stats, MIPC_STATS_INTERRUPTS_RCVD, 1);
|
||||
|
||||
/* check state of deferred work task */
|
||||
pWorkState = &bus_dev[busId].workState;
|
||||
workState = vxAtomicGet(pWorkState);
|
||||
|
||||
/* do nothing if task is already aware that new work is available */
|
||||
if (workState & MIPC_WORK_ADDED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* inform task of new work if task is currently running */
|
||||
if (workState & MIPC_WORK_RUNNING)
|
||||
{
|
||||
if (vxAtomicCas(pWorkState, MIPC_WORK_RUNNING,
|
||||
MIPC_WORK_RUNNING | MIPC_WORK_ADDED))
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* task stopped running while we were trying to inform it */
|
||||
}
|
||||
|
||||
/* task is idle, so wake it up (no need to use CAS here ...) */
|
||||
|
||||
vxAtomicSet(pWorkState, MIPC_WORK_ADDED);
|
||||
jobQueuePost(bus_dev[busId].jobQueueId,
|
||||
&bus_dev[busId].workTaskJob.qjob);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* mipcIsrWorkFunc - ISR for bus running in ISR mode
|
||||
*
|
||||
* This routine basically calls the processing call for the specified bus that
|
||||
* runs at ISR level.
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
LOCAL void mipcIsrWorkFunc(void *arg)
|
||||
{
|
||||
uint16_t busId = (uint16_t)((unsigned long)arg & 0xffffUL);
|
||||
|
||||
MIPC_STATS_ADD(bus_dev[busId].stats, MIPC_STATS_INTERRUPTS_RCVD, 1);
|
||||
|
||||
mipc_sm_api_process_rx_events(busId);
|
||||
}
|
||||
|
||||
#ifndef _WRS_CONFIG_WRHV_GUEST
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* mipcIsrDemuxFunc - ISR used when multiple buses share one interrupt line
|
||||
*
|
||||
* This routine is not needed for hypervisor guests since the hypervisor is
|
||||
* capable of handing out a different interrupt for each bus.
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
LOCAL void mipcIsrDemuxFunc(void *arg)
|
||||
{
|
||||
uint16_t busId;
|
||||
|
||||
for (busId = 0; busId < mipc_saved_max_buses; busId++)
|
||||
{
|
||||
if (bus_dev[busId].qos >= 0)
|
||||
{
|
||||
bus_dev[busId].func(bus_dev[busId].arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _WRS_CONFIG_WRHV_GUEST */
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* multios_down_timeout - get a multi-OS semaphore within a time limit
|
||||
*
|
||||
* This code assumes that only a single thread can wait on a semaphore.
|
||||
*
|
||||
* Returns: time remaining if semaphore is taken
|
||||
* (is >= 0 if timeout >= 0; is 0 if timeout == MULTIOS_WAIT_FOREVER);
|
||||
* -ETIMEDOUT if time limit expired without getting semaphore;
|
||||
* -EINVAL if any other condition prevented getting semaphore
|
||||
*/
|
||||
int multios_down_timeout(MULTIOS_SEM_ID sem, int timeout)
|
||||
{
|
||||
ULONG waitTicks;
|
||||
ULONG startTicks;
|
||||
ULONG elapsedTicks;
|
||||
int res;
|
||||
|
||||
if (timeout == MULTIOS_WAIT_FOREVER)
|
||||
return MULTIOS_SEM_DOWN(sem);
|
||||
|
||||
/* start timer & then try to take semaphore */
|
||||
|
||||
waitTicks = (timeout * sysClkRateGet() + 999UL) / 1000UL;
|
||||
startTicks = tickGet();
|
||||
res = semTake(sem, (_Vx_ticks_t)waitTicks);
|
||||
elapsedTicks = tickGet() - startTicks;
|
||||
|
||||
/* handle cases where semaphore was taken */
|
||||
|
||||
if (res == OK)
|
||||
return (elapsedTicks >= waitTicks) ? 0 :
|
||||
(int)(((waitTicks - elapsedTicks) * 1000UL) / sysClkRateGet());
|
||||
|
||||
/* handle cases where semaphore wasn't taken */
|
||||
|
||||
res = errnoGet();
|
||||
return ((res == S_objLib_OBJ_TIMEOUT) || (res == S_objLib_OBJ_UNAVAILABLE)) ?
|
||||
-ETIMEDOUT : -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
||||
# Makefile - makefile for MIPC Network Device
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01a,20may09,spw written
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the Multi-OS IPC network
|
||||
# driver
|
||||
#
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
|
||||
#DOC_FILES= mipcnetEnd.c
|
||||
|
||||
LIB_BASE_NAME=multios_ipc
|
||||
include $(TGT_DIR)/h/make/defs.library
|
||||
|
||||
ifdef _WRS_CONFIG_COMPONENT_MIPC
|
||||
OBJS= mipcnetEnd.o mipcnetIpc.o mnd_vx.o
|
||||
else
|
||||
OBJS=
|
||||
endif
|
||||
|
||||
include $(TGT_DIR)/h/make/rules.library
|
||||
|
||||
# documentation specification for APIGEN
|
||||
include $(TGT_DIR)/h/make/config/comps/mipc/defs.docs
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,57 @@
|
||||
/* mnd_vx.c - MIPC Network Device driver: VxWorks specific routines. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 -2010 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute or otherwise make use of this software
|
||||
* may be licensed only pursuant to the terms of an applicable Wind River
|
||||
* license agreement. No license to Wind River intellectual property rights
|
||||
* is granted herein. All rights not licensed by Wind River are reserved
|
||||
* by Wind River.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01b,24jun10,h_w upgrade to MND 2.1
|
||||
01a,06jul09,spw written.
|
||||
*/
|
||||
|
||||
#include <multios_ipc/mnd_adapt.h>
|
||||
#include <taskLib.h>
|
||||
|
||||
/* Priority of bus ctrl tasks. Should be higher number than MIPC QOS */
|
||||
|
||||
#define MIPCNET_TASK_PRI 80
|
||||
|
||||
/* mipcnet control task stack size */
|
||||
|
||||
#define MIPCNET_TASK_SSIZE 2000
|
||||
|
||||
|
||||
int mnd_proc_create
|
||||
(
|
||||
const char *name,
|
||||
int (*entry)(void *data),
|
||||
void *arg,
|
||||
MULTIOS_PROC_ID *ppid
|
||||
)
|
||||
{
|
||||
MULTIOS_PROC_ID tid = taskSpawn ((char *) name, MIPCNET_TASK_PRI, 0,
|
||||
MIPCNET_TASK_SSIZE, (FUNCPTR) entry,
|
||||
(_Vx_usr_arg_t) arg, 0,0,0,0,0,0,0,0,0);
|
||||
if (tid == TASK_ID_ERROR)
|
||||
return (-1);
|
||||
|
||||
*ppid = tid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mnd_proc_delete
|
||||
(
|
||||
MULTIOS_PROC_ID pid
|
||||
)
|
||||
{
|
||||
return (taskDelete (pid));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Makefile - makefile for MIPC Serial Device
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01f,09apr10,wy1 WIND00206195. Don't ship MSD apigen output
|
||||
# 01e,10nov08,jlk WIND00143103. Don't include rules.library twice.
|
||||
# 01d,01oct08,mze add VSB configuration check
|
||||
# 01c,25sep08,ebh Adding in defs.docs reference for future proofing of docs
|
||||
# 01b,25aug08,jlk Updated as per code review.
|
||||
# 01a,17apr08,jlk written
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the Multi-OS IPC serial
|
||||
# driver
|
||||
#
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
|
||||
DOC_FILES=
|
||||
|
||||
LIB_BASE_NAME=multios_ipc
|
||||
include $(TGT_DIR)/h/make/defs.library
|
||||
|
||||
ifdef _WRS_CONFIG_COMPONENT_MIPC
|
||||
OBJS= msdLib.o msd_common.o
|
||||
else
|
||||
OBJS=
|
||||
endif
|
||||
|
||||
include $(TGT_DIR)/h/make/rules.library
|
||||
|
||||
# documentation specification for APIGEN
|
||||
include $(TGT_DIR)/h/make/config/comps/mipc/defs.docs
|
||||
|
||||
@@ -0,0 +1,600 @@
|
||||
/* msdLib.c - MIPC serial driver */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2010, 2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01k,08may13,bbz clear the high impact warning from prevent.pl(WIND00416598)
|
||||
01j,24jan11,zhw Use binary semaphore rather than taskSuspend()/taskResume()
|
||||
to wake up and put to sleep the MSD TX task (WIND00251291)
|
||||
01i,01apr10,als Initial changes in support of 64-bit memory addressing
|
||||
01h,05nov09,ebh Add socket locks to single thread access to MIPC
|
||||
01g,07jul09,jlk Code inspection changes
|
||||
01f,10jun09,jlk WIND00169759: Tx task can stall due to a race condition.
|
||||
01e,22may09,jlk Updated to accommodate changes to common MIPC code.
|
||||
01d,25aug08,jlk Updated as per code review.
|
||||
01c,08aug08,jlk Updated as per HLD review.
|
||||
01b,07jul08,jlk MSD conversion.
|
||||
01a,22apr08,jlk written.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This is a MIPC serial driver. It is used to provide TTY functionality
|
||||
over MIPC. This then enables services such as the shell to be used over MIPC.
|
||||
|
||||
INCLUDES
|
||||
multios_ipc/msdLib.h sioLib.h
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <errnoLib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <semLib.h>
|
||||
|
||||
/* Max 8 levels 0-7 */
|
||||
#define MSD_DEBUG_LEVEL 0
|
||||
#include <multios_ipc/msdLib.h>
|
||||
|
||||
/* device and channel structures */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* SIO_CHAN *MUST* be first */
|
||||
|
||||
SIO_CHAN sio; /* standard SIO_CHAN element */
|
||||
|
||||
/* callbacks */
|
||||
|
||||
STATUS (*getTxChar) (void *, char *);
|
||||
STATUS (*putRcvChar) (void *, char);
|
||||
void (*errorRtn) (void *, int, void *, int);
|
||||
void * getTxArg;
|
||||
void * putRcvArg;
|
||||
void * errorArg;
|
||||
|
||||
/* mipc stuff */
|
||||
struct msd_device *msdDev;
|
||||
|
||||
/* transmit task id */
|
||||
TASK_ID txTask;
|
||||
|
||||
SEMAPHORE txSync;
|
||||
|
||||
} MSD_CHAN;
|
||||
|
||||
|
||||
/* forward static declarations */
|
||||
|
||||
LOCAL int msdTxStartup (SIO_CHAN * pSioChan);
|
||||
LOCAL int msdCallbackInstall (SIO_CHAN *pSioChan, int callbackType,
|
||||
STATUS (*callback)(void *,...), void *callbackArg);
|
||||
LOCAL int msdIoctl (SIO_CHAN *pSioChan, int request, void *arg);
|
||||
LOCAL STATUS dummyTxCallback (void *, char *);
|
||||
LOCAL STATUS dummyRxCallback (void *, char);
|
||||
LOCAL void dummyErrCallback (void *, int, void *, int);
|
||||
LOCAL void msdTxTask (MSD_CHAN * pChan);
|
||||
LOCAL void msdHandleRxDataCb(struct msd_device *, struct msd_hdr *, int);
|
||||
LOCAL void msdTxStartCb(struct msd_device *);
|
||||
|
||||
/* global variables */
|
||||
|
||||
/* local variables */
|
||||
|
||||
LOCAL SIO_DRV_FUNCS msdSioDrvFuncs =
|
||||
{
|
||||
msdIoctl,
|
||||
msdTxStartup,
|
||||
msdCallbackInstall,
|
||||
/* MSD doesn't support polled mode */
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
LOCAL int msdInitialized = 0;
|
||||
LOCAL int msdTxBufs;
|
||||
LOCAL int msdTxPrio;
|
||||
LOCAL int msdTxOpts;
|
||||
LOCAL int msdMtu;
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* msdLibInit - initialize the MSD component
|
||||
*
|
||||
* This routine initializes the MSD component.
|
||||
*
|
||||
* RETURNS: OK on success. ERROR on failure.
|
||||
*/
|
||||
|
||||
STATUS msdLibInit
|
||||
(
|
||||
int txBufs, /* Number of MIPC tx buffers. Must be greater than 0 */
|
||||
int txPrio, /* Priority of the transmit task */
|
||||
int txOpts, /* Options for the transmit task. Typically 0 */
|
||||
int mtu /* Size of the MSD payload. */
|
||||
)
|
||||
{
|
||||
if (msdInitialized)
|
||||
return OK;
|
||||
|
||||
if (txBufs <= 0)
|
||||
{
|
||||
errnoSet (EINVAL);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
msdTxBufs = txBufs;
|
||||
msdTxPrio = txPrio;
|
||||
msdTxOpts = txOpts;
|
||||
msdMtu = mtu;
|
||||
|
||||
if (msd_init (msdHandleRxDataCb, msdTxStartCb) == NULL)
|
||||
{
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
msdInitialized = TRUE;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* msdCreate - create an MSD device
|
||||
*
|
||||
* This routine creates an MSD device
|
||||
*
|
||||
* RETURNS: A SIO channel object on success. ERROR otherwise.
|
||||
*/
|
||||
|
||||
SIO_CHAN * msdCreate
|
||||
(
|
||||
void
|
||||
)
|
||||
{
|
||||
MSD_CHAN * pChan;
|
||||
struct msd_device *msdDev;
|
||||
uint8_t instance;
|
||||
char taskName[8]; /* "tMsdxxx" */
|
||||
|
||||
if (!msdInitialized)
|
||||
return (SIO_CHAN *)ERROR;
|
||||
|
||||
MSD_DBG1(printf ("MSD: Creating MSD device.\n");)
|
||||
|
||||
/* Find an available msd device */
|
||||
msdDev = msd_find_free_dev (&instance);
|
||||
if (msdDev == NULL)
|
||||
{
|
||||
MSD_DBG1(printf ("MSD: Max devices reached.\n");)
|
||||
errnoSet (ENOMEM);
|
||||
return (SIO_CHAN *)ERROR;
|
||||
}
|
||||
|
||||
pChan = (MSD_CHAN *) malloc (sizeof (MSD_CHAN));
|
||||
if (pChan == NULL)
|
||||
{
|
||||
MSD_DBG1(printf ("MSD: Out of memory.\n");)
|
||||
MSD_FREE_DEV (msdDev);
|
||||
return (SIO_CHAN *)ERROR;
|
||||
}
|
||||
|
||||
pChan->txTask = TASK_ID_ERROR;
|
||||
|
||||
pChan->sio.pDrvFuncs = &msdSioDrvFuncs;
|
||||
|
||||
/* install dummy driver callbacks */
|
||||
pChan->getTxChar = dummyTxCallback;
|
||||
pChan->putRcvChar = dummyRxCallback;
|
||||
pChan->errorRtn = dummyErrCallback;
|
||||
|
||||
pChan->msdDev = msdDev;
|
||||
msdDev->tx_bufs = msdTxBufs;
|
||||
msdDev->mtu = msdMtu;
|
||||
msdDev->os_data = pChan;
|
||||
msdDev->mipc_socket = -1;
|
||||
|
||||
if (semBInit (&pChan->txSync, SEM_Q_FIFO, SEM_EMPTY) < 0)
|
||||
{
|
||||
MSD_DBG1(printf ("MSD: Failed to initialize semaphore (txSync).\n");)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
msdDev->local_addr.mipc_addr.busNum = MIPC_BUS_ANY;
|
||||
msdDev->local_addr.mipc_addr.nodeNum = MIPC_NODE_ANY;
|
||||
msdDev->local_addr.mipc_addr.portNum = MSD_PORT_NUM;
|
||||
msdDev->local_addr.instance = instance;
|
||||
|
||||
msdDev->remote_addr.mipc_addr.busNum = MIPC_BUS_ANY;
|
||||
msdDev->remote_addr.mipc_addr.nodeNum = MIPC_NODE_ANY;
|
||||
msdDev->remote_addr.mipc_addr.portNum = MSD_PORT_NUM;
|
||||
msdDev->remote_addr.instance = 0xFFU;
|
||||
|
||||
/* Finally create the tx task */
|
||||
sprintf (taskName, "tMsd%d", instance);
|
||||
pChan->txTask = taskSpawn (taskName, msdTxPrio, msdTxOpts, 4096,
|
||||
(FUNCPTR)msdTxTask, (_Vx_usr_arg_t)pChan, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
if (pChan->txTask == TASK_ID_ERROR)
|
||||
goto fail;
|
||||
|
||||
return &pChan->sio;
|
||||
|
||||
fail:
|
||||
msdDestroy (&pChan->sio);
|
||||
return (SIO_CHAN *)ERROR;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* msdDestroy - destroy a MSD_CHAN instance
|
||||
*
|
||||
* This function is used to destroy an instance of a MSD_CHAN object.
|
||||
*
|
||||
* RETURNS: Always returns OK.
|
||||
*/
|
||||
|
||||
STATUS msdDestroy
|
||||
(
|
||||
SIO_CHAN * pSioChan
|
||||
)
|
||||
{
|
||||
MSD_CHAN * pChan = (MSD_CHAN *)pSioChan;
|
||||
|
||||
if (pChan->txTask != TASK_ID_ERROR)
|
||||
taskDelete (pChan->txTask);
|
||||
|
||||
semDestroy (&pChan->txSync, FALSE);
|
||||
|
||||
if (pChan->msdDev->mipc_socket != -1)
|
||||
msd_close_socket (pChan->msdDev);
|
||||
|
||||
MSD_FREE_DEV (pChan->msdDev);
|
||||
|
||||
free (pChan);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* msdHandleRxDataCb - receive data handler call back
|
||||
*
|
||||
* This function handles packets received from the MIPC socket. It forwards
|
||||
* them to the TTY layer using the callbacks. It is installed into the MSD
|
||||
* common code as a callback.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* NOMANUAL
|
||||
*
|
||||
*/
|
||||
|
||||
LOCAL void msdHandleRxDataCb
|
||||
(
|
||||
struct msd_device *dev,
|
||||
struct msd_hdr *hdr,
|
||||
int nbytes
|
||||
)
|
||||
{
|
||||
MSD_CHAN * pChan;
|
||||
int i;
|
||||
|
||||
pChan = (MSD_CHAN *)dev->os_data;
|
||||
|
||||
for (i = 0; i < nbytes; i++)
|
||||
{
|
||||
if ((*pChan->putRcvChar) (pChan->putRcvArg, hdr->data[i]) != 0)
|
||||
/* No point in feeding the rest as ring is full */
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* msdTxTask - task to handle transmitting over MIPC
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
LOCAL void msdTxTask
|
||||
(
|
||||
MSD_CHAN * pChan /* channel requiring service */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
struct msd_hdr * header;
|
||||
MIPC_ZBUFFER zbuf;
|
||||
char c;
|
||||
struct msd_socket_lock * msd_lock;
|
||||
|
||||
semTake (&pChan->txSync, WAIT_FOREVER);
|
||||
|
||||
mipc_getuserhandle(pChan->msdDev->mipc_socket, (unsigned long *)&msd_lock);
|
||||
while (TRUE)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
if ((*pChan->getTxChar) (pChan->getTxArg, &c) == ERROR)
|
||||
break;
|
||||
|
||||
MULTIOS_SEM_DOWN(&msd_lock->sem);
|
||||
mipc_zalloc (pChan->msdDev->mipc_socket, 0, (uint8_t **)(&header),
|
||||
&zbuf, 0);
|
||||
|
||||
/*
|
||||
* Grab characters to the maximum of the MTU or until there are no
|
||||
* more to transmit
|
||||
*/
|
||||
header->data[0] = c;
|
||||
for (i = 1; i < pChan->msdDev->mtu; i++)
|
||||
{
|
||||
if ((*pChan->getTxChar) (pChan->getTxArg, &header->data[i]) == ERROR)
|
||||
break;
|
||||
}
|
||||
|
||||
msd_send (pChan->msdDev, header, zbuf, i, MSD_OP_SEND);
|
||||
MULTIOS_SEM_UP(&msd_lock->sem);
|
||||
}
|
||||
/* Ran out of characters to process. */
|
||||
/* Sleep until we have something to transmit */
|
||||
MSD_DBG7(printf ("MSD: Tx Task sleep...\n");)
|
||||
semTake (&pChan->txSync, WAIT_FOREVER);
|
||||
MSD_DBG7(printf ("MSD: Tx Task running...\n");)
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* msdTxStartup - start the transmitter task
|
||||
*
|
||||
* This routine kicks off the transmit task that does the actual transmit.
|
||||
* The actual data will be obtained by calling the TxCharGet callback routine.
|
||||
*
|
||||
* RETURNS: OK on success, ERROR otherwise.
|
||||
*/
|
||||
|
||||
LOCAL int msdTxStartup
|
||||
(
|
||||
SIO_CHAN * pSioChan /* channel to start */
|
||||
)
|
||||
{
|
||||
MSD_CHAN * pChan = (MSD_CHAN *)pSioChan;
|
||||
|
||||
if ((pChan->msdDev->mipc_socket < 0) || (pChan->msdDev->bound == 0) ||
|
||||
(!pChan->msdDev->up))
|
||||
{
|
||||
pChan->msdDev->tx_start = TRUE;
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
semGive (&pChan->txSync);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* msdTxStartCb - start the transmitter task.
|
||||
*
|
||||
* This callback is called from the MSD common code when it determines
|
||||
* that conditions are met to complete an outstanding write request.
|
||||
* Theses conditions include connected endpoint node coming up or
|
||||
* the remote endpoint is connected (and the node on the remote is up).
|
||||
*
|
||||
* NOMANUAL
|
||||
*
|
||||
*/
|
||||
|
||||
LOCAL void msdTxStartCb
|
||||
(
|
||||
struct msd_device *dev
|
||||
)
|
||||
{
|
||||
MSD_CHAN * pChan;
|
||||
|
||||
pChan = (MSD_CHAN *)dev->os_data;
|
||||
|
||||
dev->tx_start = FALSE;
|
||||
|
||||
semGive (&pChan->txSync);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* msdCallbackInstall - install ISR callbacks to get/put chars
|
||||
*
|
||||
* This driver allows interrupt callbacks for transmitting characters
|
||||
* and receiving characters. In general, drivers may support other
|
||||
* types of callbacks too.
|
||||
*
|
||||
* RETURNS: OK on success, or ENOSYS for an unsupported callback type.
|
||||
*/
|
||||
|
||||
LOCAL int msdCallbackInstall
|
||||
(
|
||||
SIO_CHAN * pSioChan, /* channel */
|
||||
int callbackType, /* type of callback */
|
||||
STATUS (*callback)(void *,...), /* callback */
|
||||
void * callbackArg /* parameter to callback */
|
||||
)
|
||||
{
|
||||
MSD_CHAN * pChan = (MSD_CHAN *)pSioChan;
|
||||
|
||||
switch (callbackType)
|
||||
{
|
||||
case SIO_CALLBACK_GET_TX_CHAR:
|
||||
pChan->getTxChar = (STATUS (*)(void *, char *))callback;
|
||||
pChan->getTxArg = callbackArg;
|
||||
return OK;
|
||||
|
||||
case SIO_CALLBACK_PUT_RCV_CHAR:
|
||||
pChan->putRcvChar = (STATUS (*)(void *, char))callback;
|
||||
pChan->putRcvArg = callbackArg;
|
||||
return OK;
|
||||
|
||||
case SIO_CALLBACK_ERROR:
|
||||
pChan->errorRtn = (void (*)(void *, int, void *, int))callback;
|
||||
pChan->errorArg = callbackArg;
|
||||
return OK;
|
||||
|
||||
default:
|
||||
return ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* msdIoctl - special device control
|
||||
*
|
||||
* RETURNS: OK on success, ENOSYS on unsupported request, or errno on other
|
||||
* failures.
|
||||
*/
|
||||
|
||||
LOCAL int msdIoctl
|
||||
(
|
||||
SIO_CHAN * pSioChan, /* device to control */
|
||||
int request, /* request code */
|
||||
void * arg /* some argument */
|
||||
)
|
||||
{
|
||||
MSD_CHAN *pChan = (MSD_CHAN *) pSioChan;
|
||||
struct msd_endpoint_get *endp;
|
||||
int result;
|
||||
|
||||
MSD_DBG2(printf ("MSD: ioctl 0x%x. arg %p\n", request, arg);)
|
||||
|
||||
switch (request)
|
||||
{
|
||||
case SIO_MODE_GET:
|
||||
case SIO_AVAIL_MODES_GET:
|
||||
/* MSD only supports interrupt mode */
|
||||
*(int *)arg = SIO_MODE_INT;
|
||||
return OK;
|
||||
|
||||
case SIO_OPEN:
|
||||
case SIO_HUP:
|
||||
return OK;
|
||||
|
||||
case MSD_SET_ENDPOINT:
|
||||
if (arg == NULL)
|
||||
return EINVAL;
|
||||
|
||||
result = msd_connect_endpoint(pChan->msdDev,
|
||||
(struct msd_endpoint_set *)arg);
|
||||
if (result != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
MSD_DBG4(printf ("MSD Remote endpoint connected.\n");)
|
||||
return OK;
|
||||
|
||||
case MSD_GET_ENDPOINT:
|
||||
if (arg == NULL)
|
||||
return EINVAL;
|
||||
|
||||
endp = (struct msd_endpoint_get *)arg;
|
||||
|
||||
strncpy (endp->bus_name, pChan->msdDev->bus_name, MSD_BUS_NAME_LEN-1);
|
||||
endp->node = pChan->msdDev->remote_addr.mipc_addr.nodeNum;
|
||||
endp->instance = pChan->msdDev->remote_addr.instance;
|
||||
endp->up = (unsigned char)pChan->msdDev->up;
|
||||
return OK;
|
||||
|
||||
default:
|
||||
MSD_DBG2(printf ("MSD: Got unhandled ioctl: 0x%x\n", request);)
|
||||
return ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* dummyTxCallback - dummy Tx callback routine
|
||||
*
|
||||
* RETURNS: ERROR.
|
||||
*/
|
||||
|
||||
LOCAL STATUS dummyTxCallback
|
||||
(
|
||||
void * callbackArg, /* argument registered with callback */
|
||||
char * pChar /* ptr to data location */
|
||||
)
|
||||
{
|
||||
static BOOL doit = TRUE;
|
||||
|
||||
if (doit)
|
||||
{
|
||||
MSD_DBG7(printf ("Dummy txCallback: %p %p\n", callbackArg, pChar);)
|
||||
doit = FALSE;
|
||||
}
|
||||
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* dummyRxCallback - dummy Rx callback routine
|
||||
*
|
||||
* RETURNS: N/A.
|
||||
* ARGSUSED
|
||||
*/
|
||||
|
||||
LOCAL STATUS dummyRxCallback
|
||||
(
|
||||
void * callbackArg, /* argument registered with callback */
|
||||
char data /* receive data */
|
||||
)
|
||||
{
|
||||
static BOOL doit = TRUE;
|
||||
|
||||
if (doit)
|
||||
{
|
||||
MSD_DBG7(printf ("Dummy rxCallback: %p 0x%x\n", callbackArg,
|
||||
(int)data);)
|
||||
doit = FALSE;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* dummyErrCallback - dummy Error callback routine
|
||||
*
|
||||
* RETURNS: N/A.
|
||||
*/
|
||||
|
||||
LOCAL void dummyErrCallback
|
||||
(
|
||||
void * callbackArg, /* argument registered with callback */
|
||||
int errorCode, /* error code */
|
||||
void * pData, /* ptr to device specific data */
|
||||
int size /* size of device specific data */
|
||||
)
|
||||
{
|
||||
static BOOL doit = TRUE;
|
||||
|
||||
if (doit)
|
||||
{
|
||||
MSD_DBG7(printf ("Dummy errorCallback: %p 0x%x %p %d\n",
|
||||
callbackArg, errorCode, pData, size);)
|
||||
doit = FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,518 @@
|
||||
/* msd_common.c - MSD common code. */
|
||||
|
||||
/********************************************************************
|
||||
The following file is dual licensed and is available under either
|
||||
the GPL version 2 or a Wind River commercial license.
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011, 2013 Wind River Systems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*********************************************************************
|
||||
Copyright (c) 2008-2011, 2013 Wind River Systems, Inc.
|
||||
|
||||
The right to copy, distribute, modify, or otherwise make use
|
||||
of this software may be licensed pursuant to the terms
|
||||
of an applicable Wind River license agreement.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01q,30oct13,f_f Fixed the issue of checking return value (WIND00439645)
|
||||
01p,09aug13,f_f Fixed some coverity issues (WIND00429907)
|
||||
01o,08may13,bbz clear the high impact warning from prevent.pl(WIND00416598)
|
||||
01n,07jan11,jlk Update license header
|
||||
01m,23Jun10,wy1 Fix for WIND00190477, add a sem for msd_devs array
|
||||
01l,16mar10,als Add support for 64-bit memory addressing
|
||||
01k,18nov09,als Revise MSD single threading to work with Linux (WIND00190478)
|
||||
01j,10nov09,h_x Fix for WIND00187415
|
||||
01i,05nov09,ebh Add socket locks to single thread access to MIPC
|
||||
01h,23jun09,jlk Code inspection changes
|
||||
01g,22may09,jlk Updated to accommodate Linux.
|
||||
01f,22apr09,ebh Add in extra fields for mipc_bind call
|
||||
01e,27aug08,apa Sync with latest MIPC API.
|
||||
01d,25aug08,jlk Updated as per code review.
|
||||
01c,08aug08,jlk Updated as per HLD review.
|
||||
01b,07jul08,jlk TTY conversion.
|
||||
01a,26jun08,jlk Initial version.
|
||||
*/
|
||||
|
||||
/* Max 8 levels 0-7 */
|
||||
#define MSD_DEBUG_LEVEL 0
|
||||
|
||||
#include <multios_ipc/msd.h>
|
||||
|
||||
struct msd_device msd_devs[MSD_MAX_DEVS];
|
||||
|
||||
struct msd_socket_lock msd_locks[MSD_MAX_DEVS];
|
||||
MULTIOS_SEM msd_lock_array_sem;
|
||||
MULTIOS_SEM msd_devs_array_sem;
|
||||
|
||||
/*
|
||||
* The OS specific code supplies functions to process received data and to kick
|
||||
* start transmission.
|
||||
*/
|
||||
static msd_handle_rx_data_func msd_os_handle_rx_data;
|
||||
static msd_tx_start_func msd_os_tx_start;
|
||||
|
||||
/*
|
||||
* This routine searches through the array of MSD dev objects looking for an
|
||||
* unused one, then claims it.
|
||||
*/
|
||||
struct msd_device * msd_find_free_dev (uint8_t *instance)
|
||||
{
|
||||
uint8_t i;
|
||||
struct msd_device *dev;
|
||||
|
||||
dev = &msd_devs[0];
|
||||
|
||||
MULTIOS_SEM_DOWN(&msd_devs_array_sem);
|
||||
for (i = 0; i < MSD_MAX_DEVS; i++, dev++) {
|
||||
if (!dev->in_use) {
|
||||
dev->in_use = 1;
|
||||
MULTIOS_SEM_UP(&msd_devs_array_sem);
|
||||
*instance = i;
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
MULTIOS_SEM_UP(&msd_devs_array_sem);
|
||||
*instance = 0xFF;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine searches the msd dev array for a socket that corresponds to the
|
||||
* given bus number.
|
||||
*/
|
||||
static int msd_find_socket (unsigned short bus)
|
||||
{
|
||||
int i;
|
||||
struct msd_device *dev;
|
||||
|
||||
dev = msd_devs;
|
||||
MULTIOS_SEM_DOWN(&msd_devs_array_sem);
|
||||
for (i = 0; i < MSD_MAX_DEVS; i++, dev++) {
|
||||
if ((dev->local_addr.mipc_addr.busNum == bus) &&
|
||||
(dev->mipc_socket >= 0))
|
||||
{
|
||||
MULTIOS_SEM_UP(&msd_devs_array_sem);
|
||||
MSD_DBG2 (MULTIOS_PRINT ("MSD: Socket %d found for bus "
|
||||
"%u\n", dev->mipc_socket, bus);)
|
||||
return dev->mipc_socket;
|
||||
}
|
||||
}
|
||||
MULTIOS_SEM_UP(&msd_devs_array_sem);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends an MSD packet over MIPC
|
||||
*/
|
||||
void msd_send (struct msd_device *dev, struct msd_hdr *hdr, MIPC_ZBUFFER zbuf,
|
||||
int size, uint8_t op)
|
||||
{
|
||||
ssize_t result;
|
||||
|
||||
hdr->dev_id = dev->remote_addr.instance;
|
||||
hdr->op = op;
|
||||
hdr->ver_maj = MSD_PROTO_MAJOR_VER;
|
||||
hdr->ver_min = MSD_PROTO_MINOR_VER;
|
||||
/*
|
||||
* Adjust the size to account for the MSD header. Note that the MSD hdr
|
||||
* structure already contains MSD_HDR_DATA_SZ bytes of data.
|
||||
*/
|
||||
size += ((int)sizeof (struct msd_hdr) - MSD_HDR_DATA_SZ);
|
||||
|
||||
MSD_DBG2 (MULTIOS_PRINT ("MSD: Send on socket %d. Dst node %u. "
|
||||
"Total size %d. zbuf %p\n", dev->mipc_socket,
|
||||
dev->remote_addr.mipc_addr.nodeNum, size, zbuf);)
|
||||
|
||||
result = mipc_zsendto (dev->mipc_socket, zbuf, (size_t)size, 0,
|
||||
&(dev->remote_addr.mipc_addr),
|
||||
(socklen_t)sizeof (struct mipc_sockaddr));
|
||||
if (result < 0) {
|
||||
MSD_DBG1 (MULTIOS_PRINT ("MSD: Send failed. Returned %d\n",
|
||||
(int)result);)
|
||||
mipc_zfree (dev->mipc_socket, zbuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Validate the message version
|
||||
*/
|
||||
static int msd_ver_valid (struct msd_hdr *hdr)
|
||||
{
|
||||
if ((hdr->ver_maj != MSD_PROTO_MAJOR_VER) ||
|
||||
(hdr->ver_min > MSD_PROTO_MAJOR_VER))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is the receive callback installed on the MIPC socket. It is
|
||||
* called every time the socket receives a packet. Once validated, the packet
|
||||
* is passed off to the OS specific routine for processing.
|
||||
* This function can be called at interrupt level.
|
||||
*/
|
||||
static int msd_rx_cb (int fd, char *buf, size_t nbytes, unsigned short src_node,
|
||||
unsigned short src_port, MIPC_ZBUFFER zbuf)
|
||||
{
|
||||
struct msd_hdr *hdr;
|
||||
struct msd_device *dev;
|
||||
|
||||
MSD_DBG7 (MULTIOS_PRINT ("MSD: Rx callback. src node %u, src port %u, size %lu\n",
|
||||
src_node, src_port, nbytes));
|
||||
|
||||
hdr = (struct msd_hdr *)buf;
|
||||
|
||||
if (!msd_ver_valid (hdr))
|
||||
return MIPC_RX_RELEASEBUF;
|
||||
|
||||
if (hdr->dev_id >= MSD_MAX_DEVS)
|
||||
return MIPC_RX_RELEASEBUF;
|
||||
|
||||
dev = &msd_devs[hdr->dev_id];
|
||||
|
||||
/* socket is guaranteed to be valid in this callback by MIPC and should still be
|
||||
* in msd_devs table; must not take a semaphore since this routine may be invoked
|
||||
* at interrupt level */
|
||||
|
||||
/* Check to see if the message is from the expected node */
|
||||
if ((dev->mipc_socket != fd) ||
|
||||
(dev->remote_addr.mipc_addr.nodeNum != src_node))
|
||||
{
|
||||
return MIPC_RX_RELEASEBUF;
|
||||
}
|
||||
|
||||
switch (hdr->op) {
|
||||
case MSD_OP_SEND:
|
||||
msd_os_handle_rx_data (dev, hdr, (int)
|
||||
(nbytes - sizeof (struct msd_hdr) + MSD_HDR_DATA_SZ));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return MIPC_RX_RELEASEBUF;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is the transmit callback installed on the MIPC socket. It is
|
||||
* called every time the socket's list of available transmit buffers goes from
|
||||
* empty to non-empty.
|
||||
*/
|
||||
static void msd_tx_cb (int fd)
|
||||
{
|
||||
MSD_DBG7 (MULTIOS_PRINT ("MSD: Tx callback.\n");)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function sets the state of the remote node. It is called from the node
|
||||
* up/down callbacks. If the node is up and a transmission is outstanding, the
|
||||
* transmission is kicked off.
|
||||
*/
|
||||
static void msd_state_set (int fd, unsigned short node, uint8_t state)
|
||||
{
|
||||
struct msd_device *dev = msd_devs;
|
||||
int i;
|
||||
|
||||
MULTIOS_SEM_DOWN(&msd_devs_array_sem);
|
||||
for (i = 0; i < MSD_MAX_DEVS; i++, dev++) {
|
||||
if ((dev->mipc_socket == fd) &&
|
||||
(dev->remote_addr.mipc_addr.nodeNum == node))
|
||||
{
|
||||
dev->up = state;
|
||||
if (state && dev->tx_start)
|
||||
msd_os_tx_start (dev);
|
||||
/* add break, because it seemed no need to continue the loop here
|
||||
* */
|
||||
break;
|
||||
}
|
||||
}
|
||||
MULTIOS_SEM_UP(&msd_devs_array_sem);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is the node join callback installed on the MIPC socket. It is
|
||||
* called every time a node comes up and joins the network.
|
||||
*/
|
||||
static void msd_up_cb (int fd, unsigned short node)
|
||||
{
|
||||
msd_state_set (fd, node, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is the node leave callback installed on the MIPC socket. It is
|
||||
* called every time a node goes down and leaves the network.
|
||||
*/
|
||||
static void msd_down_cb (int fd, unsigned short node)
|
||||
{
|
||||
msd_state_set (fd, node, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called whenever an MSD device is no longer needed or is
|
||||
* being re-directed to a different bus. It checks the msd dev array to see
|
||||
* if it is the last one using the socket. If so, the socket is closed. In
|
||||
* addition, the msd dev object is reset.
|
||||
*/
|
||||
void msd_close_socket (struct msd_device *dev)
|
||||
{
|
||||
int i, count;
|
||||
struct msd_device *cur_dev;
|
||||
|
||||
count = 0;
|
||||
MULTIOS_SEM_DOWN(&msd_devs_array_sem);
|
||||
cur_dev = &msd_devs[0];
|
||||
for (i = 0; i < MSD_MAX_DEVS; i++) {
|
||||
if (cur_dev->mipc_socket == dev->mipc_socket) {
|
||||
count++;
|
||||
}
|
||||
cur_dev++;
|
||||
}
|
||||
if (count <= 1) {
|
||||
struct msd_socket_lock * msd_lock;
|
||||
if (mipc_getuserhandle(dev->mipc_socket,
|
||||
(unsigned long *)&msd_lock) == MIPC_OK) {
|
||||
/* MULTIOS_SEM_DOWN(&msd_lock_array_sem); */
|
||||
msd_lock->in_use = 0;
|
||||
/* MULTIOS_SEM_UP(&msd_lock_array_sem); */
|
||||
}
|
||||
mipc_close (dev->mipc_socket);
|
||||
}
|
||||
|
||||
dev->mipc_socket = -1;
|
||||
dev->local_addr.mipc_addr.busNum = MIPC_BUS_ANY;
|
||||
|
||||
MULTIOS_SEM_UP(&msd_devs_array_sem);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This routine "connects" the local endpoint to the specified remote endpoint.
|
||||
* No actual message is sent to do the connect. A similar operation must be
|
||||
* done on the remote node to properly configure the msd channel.
|
||||
*/
|
||||
int msd_connect_endpoint (struct msd_device *dev, struct msd_endpoint_set *endp)
|
||||
{
|
||||
socklen_t addrlen;
|
||||
int result, bus, s, opt;
|
||||
unsigned short busNum;
|
||||
socklen_t optlen;
|
||||
unsigned char act_nodes[128] = {0}; /* support 1024(128*8) nodes */
|
||||
unsigned int remainder,quotient;
|
||||
|
||||
result = mipc_getbusbyname (endp->bus_name, &bus);
|
||||
if (result < 0) {
|
||||
MSD_DBG1 (MIPC_PRINT ("MSD: Failed to get bus for %s\n",
|
||||
endp->bus_name);)
|
||||
return result;
|
||||
}
|
||||
busNum = (unsigned short)bus;
|
||||
|
||||
if (dev->mipc_socket != -1) {
|
||||
/* Already connected. Moving connection? */
|
||||
MSD_DBG2 (MIPC_PRINT ("MSD: Moving connection on socket %d\n", dev->mipc_socket);)
|
||||
if (dev->remote_addr.mipc_addr.busNum == busNum) {
|
||||
dev->remote_addr.mipc_addr.nodeNum = endp->node;
|
||||
dev->remote_addr.instance = endp->instance;
|
||||
goto detect_up;
|
||||
}
|
||||
|
||||
/* Replacing socket */
|
||||
msd_close_socket (dev);
|
||||
}
|
||||
|
||||
dev->bound = 0;
|
||||
/*
|
||||
* Setup remote address. Note we don't need to set the family since
|
||||
* this was done during initialization and doesn't change
|
||||
*/
|
||||
dev->remote_addr.mipc_addr.busNum = busNum;
|
||||
dev->remote_addr.mipc_addr.nodeNum = endp->node;
|
||||
dev->remote_addr.instance = endp->instance;
|
||||
strncpy (dev->bus_name, endp->bus_name, MSD_BUS_NAME_LEN-1); /* Cache the name */
|
||||
|
||||
/* See if there's an msd socket already for opened for this bus */
|
||||
s = msd_find_socket (busNum);
|
||||
MSD_DBG7 (MIPC_PRINT ("MSD: Socket %d found.\n", s);)
|
||||
|
||||
if (s == -1) {
|
||||
int i;
|
||||
|
||||
/* No socket yet for this bus */
|
||||
MSD_DBG2 (MIPC_PRINT ("MSD: Creating socket for bus %u\n", busNum);)
|
||||
|
||||
/*
|
||||
* Setup local address. Note we don't need to set the family
|
||||
* since this was done during initialization and doesn't change
|
||||
*/
|
||||
dev->local_addr.mipc_addr.busNum = busNum;
|
||||
dev->local_addr.mipc_addr.nodeNum = MIPC_NODE_ANY;
|
||||
|
||||
s = mipc_socket (MSD_DOMAIN, MIPC_SOCK_DGRAM, MSD_PROTOCOL);
|
||||
if (s < 0) {
|
||||
MSD_DBG1 (MIPC_PRINT ("MSD: Failed to create socket\n");)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
MSD_DBG7 (MIPC_PRINT ("MSD: Got socket %d\n", s);)
|
||||
|
||||
/* find an entry in the msd_locks[] array to track socket */
|
||||
|
||||
MULTIOS_SEM_DOWN(&msd_lock_array_sem);
|
||||
for (i = 0; msd_locks[i].in_use; i++) {
|
||||
/* keep looking for an unused lock entry */
|
||||
}
|
||||
msd_locks[i].in_use = 1;
|
||||
mipc_setuserhandle(s,(unsigned long)&msd_locks[i]);
|
||||
MULTIOS_SEM_UP(&msd_lock_array_sem);
|
||||
|
||||
dev->mipc_socket = s;
|
||||
opt = 0;
|
||||
(void)mipc_setsockopt (s, 0, MIPC_SO_NBIO, &opt,
|
||||
(socklen_t)sizeof (opt));
|
||||
(void)mipc_setsockopt (s, 0, MIPC_SO_TXBUFS, &dev->tx_bufs,
|
||||
(socklen_t)sizeof(dev->tx_bufs));
|
||||
if (dev->mtu > 0) {
|
||||
/* Custom MTU */
|
||||
opt = dev->mtu +
|
||||
(int)sizeof (struct msd_hdr) - MSD_HDR_DATA_SZ;
|
||||
/* Round up nearest power of 2 */
|
||||
opt--;
|
||||
opt |= opt >> 1;
|
||||
opt |= opt >> 2;
|
||||
opt |= opt >> 4;
|
||||
opt |= opt >> 8;
|
||||
opt |= opt >> 16;
|
||||
opt++;
|
||||
(void)mipc_setsockopt (s, 0, MIPC_SO_MTU, &opt,
|
||||
(socklen_t)sizeof (opt));
|
||||
}
|
||||
|
||||
(void)mipc_setsockopt (s, 0, MIPC_SO_RX_CALLBACK, msd_rx_cb,
|
||||
(socklen_t)sizeof (void *));
|
||||
(void)mipc_setsockopt (s, 0, MIPC_SO_NODEJOIN_CALLBACK, msd_up_cb,
|
||||
(socklen_t)sizeof (void *));
|
||||
(void)mipc_setsockopt (s, 0, MIPC_SO_NODELEFT_CALLBACK, msd_down_cb,
|
||||
(socklen_t)sizeof (void *));
|
||||
(void)mipc_setsockopt (s, 0, MIPC_SO_TXBUFAVAIL_CALLBACK, msd_tx_cb,
|
||||
(socklen_t)sizeof (void *));
|
||||
|
||||
MSD_DBG7 (MIPC_PRINT ("MSD: Binding socket. node %u bus %u port %u\n",
|
||||
dev->local_addr.mipc_addr.nodeNum,
|
||||
dev->local_addr.mipc_addr.busNum,
|
||||
dev->local_addr.mipc_addr.portNum);)
|
||||
result = mipc_bind (s, &dev->local_addr.mipc_addr,
|
||||
(socklen_t)sizeof (dev->local_addr.mipc_addr));
|
||||
if (result != 0) {
|
||||
MSD_DBG1 (MIPC_PRINT ("MSD: Bind failed: %d\n", result);)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Determine the actual mtu */
|
||||
optlen = (socklen_t)sizeof (opt);
|
||||
(void)mipc_getsockopt (s, 0, MIPC_SO_MTU, &opt, &optlen);
|
||||
dev->mtu = opt - (int)sizeof (struct msd_hdr) + MSD_HDR_DATA_SZ;
|
||||
|
||||
MSD_DBG7 (MIPC_PRINT ("MSD: Bind completed successfully.\n");)
|
||||
|
||||
} else {
|
||||
dev->mipc_socket = s;
|
||||
}
|
||||
|
||||
dev->bound = 1;
|
||||
|
||||
addrlen = (socklen_t)sizeof (dev->local_addr.mipc_addr);
|
||||
(void)mipc_getsockname (dev->mipc_socket, &dev->local_addr.mipc_addr,
|
||||
&addrlen);
|
||||
|
||||
detect_up:
|
||||
result = mipc_getactivenodesl(dev->local_addr.mipc_addr.busNum,
|
||||
act_nodes, 128);
|
||||
|
||||
quotient = endp->node / 8U;
|
||||
remainder = endp->node & 0x7U;
|
||||
|
||||
if((result == MIPC_OK) && (act_nodes[quotient] & (1 << remainder)))
|
||||
{
|
||||
dev->up = 1;
|
||||
if (dev->tx_start)
|
||||
msd_os_tx_start (dev);
|
||||
}
|
||||
|
||||
|
||||
MSD_DBG7 (MIPC_PRINT ("MSD: Connect done. Remote node %u. Remote inst %u. Bus %u.\n",
|
||||
dev->remote_addr.mipc_addr.nodeNum,
|
||||
dev->remote_addr.instance,
|
||||
dev->remote_addr.mipc_addr.busNum);)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This routine must be called by the OS specific init. code. It installs the
|
||||
* call backs for the receive and transmit start functions. It also does some
|
||||
* pre-initilization of some global data structures.
|
||||
*/
|
||||
struct msd_device * msd_init (msd_handle_rx_data_func rx_func,
|
||||
msd_tx_start_func tx_func)
|
||||
{
|
||||
uint8_t i;
|
||||
struct msd_device *dev;
|
||||
|
||||
if ((rx_func == NULL) || (tx_func == NULL))
|
||||
return NULL;
|
||||
|
||||
msd_os_handle_rx_data = rx_func;
|
||||
msd_os_tx_start = tx_func;
|
||||
|
||||
dev = &msd_devs[0];
|
||||
for (i = 0; i < MSD_MAX_DEVS; i++, dev++) {
|
||||
dev->mipc_socket = -1;
|
||||
dev->mtu = -1;
|
||||
dev->bound = 0;
|
||||
dev->up = 0;
|
||||
dev->tx_start = 0;
|
||||
dev->remote_addr.mipc_addr.nodeNum = MIPC_NODE_ANY;
|
||||
dev->remote_addr.mipc_addr.family = MIPC_AF;
|
||||
dev->remote_addr.mipc_addr.portNum = MIPC_PORT_ANY;
|
||||
dev->remote_addr.mipc_addr.busNum = MIPC_BUS_ANY;
|
||||
dev->remote_addr.mipc_addr.portNum = MSD_PORT_NUM;
|
||||
dev->local_addr.mipc_addr.nodeNum = MIPC_NODE_ANY;
|
||||
dev->local_addr.mipc_addr.family = MIPC_AF;
|
||||
dev->local_addr.mipc_addr.portNum = MIPC_PORT_ANY;
|
||||
dev->local_addr.mipc_addr.busNum = MIPC_BUS_ANY;
|
||||
dev->local_addr.mipc_addr.portNum = MSD_PORT_NUM;
|
||||
|
||||
MULTIOS_SEM_INIT_FULL(&msd_locks[i].sem);
|
||||
msd_locks[i].in_use = 0;
|
||||
}
|
||||
|
||||
MULTIOS_SEM_INIT_FULL(&msd_lock_array_sem);
|
||||
MULTIOS_SEM_INIT_FULL(&msd_devs_array_sem);
|
||||
|
||||
return &msd_devs[0];
|
||||
}
|
||||
Reference in New Issue
Block a user