original files of m241

This commit is contained in:
neelimap
2026-07-30 11:19:44 +05:30
parent 170c2b3f3a
commit afc7070c1f
12254 changed files with 7655111 additions and 0 deletions
@@ -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(&region->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(&region->nextFreeOffset);
nextFreeOffset = ALIGN_UP(currentOffset + nBytes);
if ((nextFreeOffset > MULTIOS_ntoh32(region->endOffset)) ||
(nextFreeOffset < currentOffset)) {
/* Memory exhaustion */
return -MIPC_ENOMEM;
}
} while (!MULTIOS_ATOMIC_CAS(&region->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];
}