/* BEGIN_ICS_COPYRIGHT5 ****************************************
Copyright (c) 2015-2020, Intel Corporation
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
** END_ICS_COPYRIGHT5 ****************************************/
/****************************************************************************
* *
* FILE NAME VERSION *
* mai_config.c MAPI 0.05 *
* *
* DESCRIPTION *
* This file contains the code for initializing the mai subsystem *
* *
* *
* DATA STRUCTURES *
* None *
* *
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <ib_types.h>
#include <ib_status.h>
#include <mai_g.h> /* Global mai function definitions */
#include <cs_g.h> /* Global common services functions */
#include "mai_info.h" /* Statistics structures */
#include "mai_l.h" /* Local mai function definitions */
#include "vmai_stream.h" /* Streams conversion calls */
struct mai_dc *gMAI_DOWN_CHANNELS;
struct mai_fd *gMAI_UP_CHANNELS;
struct mai_data *gMAI_DATA_FREE;
struct mai_filter *gMAI_FILT_FREE;
struct mai_fd *gMAI_HANDLE_FREE;
struct mai_fd gMAI_CHANNELS[MAI_MAX_CHANNELS];
struct mai_data * gMAI_MAD_BUFFS = NULL;
struct mai_filter gMAI_FILTERS[MAI_MAX_FILTERS];
struct mai_dc gMAI_DOWN_CL[MAI_MAXDC_CHANNELS];
int gMAI_INITIALIZED = 0;
int gMAI_FILT_CNT,
gMAI_MAD_CNT,
gMAI_HDL_CNT;
MLock_t gmai_uplock;
MLock_t gmai_hlock,
gmai_mlock,
gmai_flock;
MLock_t gmai_dcthr_lock;
/* used to sync start of dedicated dc router thread */
Sema_t gMAI_DCTHREAD_SEMA;
int gMAI_USE_DEDICATED_DCTHREAD = MAI_DCTHREAD_OPTION;
int gMAI_DCTHREAD_HANDLE;
uint32_t gMAI_MAX_QUEUED = MAI_MAX_QUEUED_DEFAULT;
uint32_t gMAI_MAX_DATA = MAI_MAX_DATA_DEFAULT;
uint32_t gMAI_MADS_LOWWM = MAI_MADS_LOWWM_DEFAULT;
#ifdef MAI_STATS
mai_stats_t gMAI_STATS;
#endif
static Event_t ev_array[MAI_MAX_EVENTS];
extern int mai_dc_read_exit; // tells dc thread to shutdown
/*
* FUNCTION
* mai_set_num_end_ports
*
* DESCRIPTION
* This function can be called prior to calling mai_init. It will
* adjust the MAD buffer size and queue depths accordingly. If not
* called, they will be given reasonable defaults.
*
*
* INPUTS
* num_end_ports The required number of fabric end ports to scale to.
*
* OUTPUTS
*
*/
void mai_set_num_end_ports(uint32_t num_end_ports)
{
IB_ENTER(__func__, num_end_ports, 0, 0, 0);
if (gMAI_INITIALIZED)
{
IB_LOG_INFO("MAI already initialized; skipping...", 0);
return;
}
gMAI_MAX_QUEUED = num_end_ports;
gMAI_MAX_DATA = 5 * gMAI_MAX_QUEUED;
// see mai_l.h for other non-adjustable low watermarks
gMAI_MADS_LOWWM = gMAI_MAX_DATA / 10;
IB_EXIT(__func__, 0);
}
/*
* FUNCTION
* mai_init
*
* DESCRIPTION
* This function initializes the internal data areas used by the VIEO
* management API. It must be called exactly once, prior to using any
* other management API functions.
*
*
* INPUTS
* None
*
* OUTPUTS
*
* HISTORY
* NAME DATE REMARKS
* JMM 01/16/01 Initial entry
*/
static Threadname_t mai_init_pid=0;
void
mai_init()
{
int rc;
int i;
Threadname_t my_pid;
uint8_t name[16];
IB_ENTER(__func__, 0, 0, 0, 0);
/*
* Check to see if we have been gMAI_INITIALIZED yet. Since there can be a race
* condition when creating a lock, we can't do that here. What we do instead
* is have all 'N' contending processes write to a static variable and then go
* to sleep. After they wake up, only one will have the variable. That
* thread goes on.
*
* If the gMAI_INITIALIZED variable is zero, then there can be a thread in the
* process of initialization. In this case, we just wait here until the other
* thread finishes.
*/
(void) vs_thread_name(&my_pid);
if (gMAI_INITIALIZED == 0)
{
if (mai_init_pid == 0ull)
{
mai_init_pid = my_pid;
(void)vs_thread_sleep(VTIMER_1S);
}
i = 0;
if (mai_init_pid != my_pid)
{
while (gMAI_INITIALIZED == 0 && i < 30)
{
(void)vs_thread_sleep(VTIMER_1S);
i++;
}
if (gMAI_INITIALIZED == 0)
{
IB_LOG_ERROR0("failed to initialized");
}
return;
}
}
else
{
IB_LOG_INFO("Already initialized", 0);
return;
}
/*
* Make sure we belong here
*/
if (gMAI_INITIALIZED)
{
IB_LOG_INFO("Already initialized", 0);
return;
}
/*
* Reset these values
*/
gMAI_FILT_CNT = gMAI_MAD_CNT = gMAI_HDL_CNT = 0;
MSTATS_INIT();
/*
* Assume threads will not work - Unless changed later on
*/
/*
* Basic initialization
*/
gMAI_UP_CHANNELS = NULL;
gMAI_DATA_FREE = NULL;
gMAI_HANDLE_FREE = NULL;
gMAI_FILT_FREE = NULL;
gMAI_DCTHREAD_HANDLE = MAI_INVALID;
// initialize read semaphore
cs_sema_create (&gMAI_DCTHREAD_SEMA, 0);
mai_dc_read_exit = 0;
/*
* Initialize the one and only lock
*/
(void)memset(&gmai_uplock, 0, sizeof(MLock_t));
(void)memset(&gmai_hlock, 0, sizeof(MLock_t));
(void)memset(&gmai_flock, 0, sizeof(MLock_t));
(void)memset(&gmai_mlock, 0, sizeof(MLock_t));
(void)memset(&gmai_dcthr_lock, 0, sizeof(MLock_t));
rc = vs_lock_init(&gmai_uplock.lock, VLOCK_FREE, VLOCK_THREAD);
if (rc)
{
IB_LOG_ERRORRC("vs_lock_init rc:", rc);
IB_EXIT(__func__, VSTATUS_BAD);
return;
}
rc = vs_lock_init(&gmai_hlock.lock, VLOCK_FREE, VLOCK_THREAD);
if (rc)
{
IB_LOG_ERRORRC("vs_lock_init rc:", rc);
IB_EXIT(__func__, VSTATUS_BAD);
return;
}
rc = vs_lock_init(&gmai_flock.lock, VLOCK_FREE, VLOCK_THREAD);
if (rc)
{
IB_LOG_ERRORRC("vs_lock_init rc:", rc);
IB_EXIT(__func__, VSTATUS_BAD);
return;
}
rc = vs_lock_init(&gmai_mlock.lock, VLOCK_FREE, VLOCK_THREAD);
if (rc)
{
IB_LOG_ERRORRC("vs_lock_init rc:", rc);
IB_EXIT(__func__, VSTATUS_BAD);
return;
}
rc = vs_lock_init(&gmai_dcthr_lock.lock, VLOCK_FREE, VLOCK_THREAD);
if (rc)
{
IB_LOG_ERRORRC("gmai_dcthr_lock vs_lock_init rc:", rc);
IB_EXIT(__func__, VSTATUS_BAD);
return;
}
(void)memset(gMAI_DOWN_CL, 0, sizeof(gMAI_DOWN_CL));
/*
* Initialize the hardware channel control blocks
*/
for (i = 0; i < MAI_MAXDC_CHANNELS; i++)
{
struct mai_dc *p; /* To ease typing */
p = &gMAI_DOWN_CL[i];
p->next = NULL;
p->state = MAI_FREE;
p->ref = 0;
p->readt_state = QPS_DEAD;
rc = vs_lock_init(&p->lock.lock, VLOCK_FREE, VLOCK_THREAD);
if (rc)
{
IB_LOG_ERRORRC("vs_lock_init rc:", rc);
IB_EXIT(__func__, VSTATUS_BAD);
return;
}
}
(void)memset(ev_array, 0, sizeof(ev_array));
/*
* Initialize the events sets
*/
for (i = 0; i < MAI_MAX_EVENTS; i++)
{
sprintf((char *) name, "EVT_chan%d", i);
rc = vs_event_create(&ev_array[i], name, (Eventset_t) 0x00U);
if (rc)
{
IB_LOG_ERRORRC("vs_event_create failed rc:", rc);
IB_EXIT(__func__, VSTATUS_BAD);
return;
}
else
{
IB_LOG_VERBOSE("vs_event_created event ", i);
}
}
(void)memset(gMAI_CHANNELS, 0, sizeof(gMAI_CHANNELS));
/*
* Initialize all the channel control blocks
*/
for (i = 0; i < MAI_MAX_CHANNELS; i++)
{
struct mai_fd *p;
p = &gMAI_CHANNELS[i]; /* To ease typing */
p->state = MAI_FREE;
p->up_fd = i;
p->dev = MAI_INVALID;
p->port = MAI_INVALID;
p->qp = MAI_INVALID;
/*
* If threaded we will sleep on timeout or data arrived events.
* The event to wait on and the mask to signal with
*/
p->hdl_ehdl = ev_array[i/VEVENT_NUM_EVENTS].event_handle;
p->hdl_emask = (Eventset_t) (1 << (i%VEVENT_NUM_EVENTS));
rc = vs_lock_init(&p->lock.lock, VLOCK_FREE, VLOCK_THREAD);
if (rc)
{
IB_LOG_ERRORRC("vs_lock_init rc:", rc);
IB_EXIT(__func__, VSTATUS_BAD);
return;
}
/*
* So that free will work .. set stat to busy
*/
p->state = MAI_BUSY;
(void)mai_free_handle(p);
}
(void)memset(gMAI_FILTERS, 0, sizeof(gMAI_FILTERS));
/*
* Initialize all the filters
*/
for (i = 0; i < MAI_MAX_FILTERS; i++)
{
struct mai_filter *p;
p = &gMAI_FILTERS[i];
p->next = NULL;
p->next = NULL;
p->owner = NULL;
p->state = MAI_FREE;
p->qp = MAI_INVALID;
p->flags = 0;
p->hndl = i;
mai_free_filter(p);
}
IB_LOG_INFO("Allocating MAI MAD buffers", gMAI_MAX_DATA);
IB_LOG_INFO("Setting max queue depth to", gMAI_MAX_QUEUED);
IB_LOG_INFO("Total memory required is", gMAI_MAX_DATA * sizeof(struct mai_data));
gMAI_MAD_BUFFS = vs_malloc(gMAI_MAX_DATA * sizeof(struct mai_data));
if (!gMAI_MAD_BUFFS)
{
IB_LOG_ERROR("Failed to allocate MAI MAD buffers:", gMAI_MAX_DATA);
IB_LOG_ERROR("Total memory required was", gMAI_MAX_DATA * sizeof(struct mai_data));
IB_EXIT(__func__, VSTATUS_NOMEM);
return;
}
(void)memset(gMAI_MAD_BUFFS, 0, gMAI_MAX_DATA * sizeof(struct mai_data));
/*
* Initialize all the MAD mbufs
*/
for (i = 0; i < gMAI_MAX_DATA; i++)
{
struct mai_data *p;
p = &gMAI_MAD_BUFFS[i];
mai_free_mbuff(p);
}
/*
* Initialize filter subsysem
*/
maif_init();
rc = ib_init_sma(gMAI_MAX_DATA);
if (rc != VSTATUS_OK)
{
IB_LOG_ERRORRC("can't initialize sma rc:", rc);
IB_EXIT(__func__, VSTATUS_BAD);
return;
}
/*
* We are done and everything worked
*/
gMAI_INITIALIZED = 1;
IB_EXIT(__func__, 0);
return;
}
/*
* FUNCTION
* mai_shutdown
*
* DESCRIPTION
* This function marks the MAI library as un-initialized, forcing all
* applications fail and return from the library.
*
* INPUTS
* None
*
* OUTPUTS
*
*/
void
mai_shut_down(void)
{
int rc,i;
IB_ENTER(__func__, 0, 0, 0, 0);
mai_close_portinfo();
/*
* If we are using a dedicated down call thread, then
* terminate the send a message to wake the thread.
*/
if (gMAI_USE_DEDICATED_DCTHREAD)
{
if (gMAI_DCTHREAD_HANDLE != MAI_INVALID)
{
Mai_t mad;
struct mai_dc *p;
mad.type = MAI_TYPE_INTERNAL;
mad.active = MAI_ACT_TYPE;
p = &gMAI_DOWN_CL[0];
mai_dc_read_exit = 1;
rc = stl_send_sma(p->hndl, &mad, MAI_DEFAULT_SEND_TIMEOUT);
if (rc)
{
IB_LOG_ERRORRC("sending shutdown mad rc:", rc);
}
else
{
/*
* Sleep 1 second so that the MAI down call thread has time to run and
* terminate.
*/
(void)vs_thread_sleep(VTIMER_1S);
}
}
}
ib_shutdown_all();
/* mark MAI as not initialized to stop use */
gMAI_INITIALIZED = 0;
/*
* Free the events
*/
for (i = 0; i < MAI_MAX_EVENTS; i++)
{
rc = vs_event_delete(&ev_array[i]);
if (rc)
{
IB_LOG_ERRORRC("mai_shutdown: vs_event_create failed rc:", rc);
}
}
vs_free(gMAI_MAD_BUFFS);
IB_EXIT(__func__, 0);
}
#ifdef __VXWORKS__
extern Status_t ib_term_sma (void); /* to avoid implicit decl warning */
void
mai_deinit(){
int i=0;
vs_lock_delete(&gmai_uplock.lock);
vs_lock_delete(&gmai_hlock.lock);
vs_lock_delete(&gmai_mlock.lock);
vs_lock_delete(&gmai_flock.lock);
vs_lock_delete(&gmai_dcthr_lock.lock);
for (i = 0; i < MAI_MAXDC_CHANNELS; i++)
{
struct mai_dc *p; /* To ease typing */
p = &gMAI_DOWN_CL[i];
vs_lock_delete(&p->lock.lock);
}
for (i = 0; i < MAI_MAX_CHANNELS; i++)
{
struct mai_fd *p;
p = &gMAI_CHANNELS[i]; /* To ease typing */
vs_lock_delete(&p->lock.lock);
}
ib_term_sma();
gMAI_INITIALIZED = 0;
mai_init_pid = 0;
}
int maiBufferSize()
{
size_t size = sizeof(struct mai_data);
sysPrintf("An MAI buffer is %d bytes\n", size);
return size;
}
int maiBufferTotals()
{
size_t size = maiBufferSize();
size *= gMAI_MAX_DATA;
sysPrintf("There are %d MAI buffers that use %d bytes total\n", (unsigned)gMAI_MAX_DATA, size);
return size;
}
#endif