blob: c00c9baf72da897c2a5ca6c736d743ab677a1bd4 [file] [log] [blame]
/*
<:copyright-BRCM:2016:proprietary:standard
Broadcom Proprietary and Confidential.(c) 2016 Broadcom
All Rights Reserved
This program is the proprietary software of Broadcom Corporation and/or its
licensors, and may only be used, duplicated, modified or distributed pursuant
to the terms and conditions of a separate, written license agreement executed
between you and Broadcom (an "Authorized License"). Except as set forth in
an Authorized License, Broadcom grants no license (express or implied), right
to use, or waiver of any kind with respect to the Software, and Broadcom
expressly reserves all rights in and to the Software and all intellectual
property rights therein. IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE
NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY
BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE.
Except as expressly set forth in the Authorized License,
1. This program, including its structure, sequence and organization,
constitutes the valuable trade secrets of Broadcom, and you shall use
all reasonable efforts to protect the confidentiality thereof, and to
use this information only in connection with your use of Broadcom
integrated circuit products.
2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR
WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY DISCLAIMS ANY AND
ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, NONINFRINGEMENT,
FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR
COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR CORRESPONDENCE
TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF USE OR
PERFORMANCE OF THE SOFTWARE.
3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
ITS LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL,
INDIRECT, OR EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY
WAY RELATING TO YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN
IF BROADCOM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES;
OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE LIMITATIONS
SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF ANY
LIMITED REMEDY.
:>
*/
/*
* bcmtr_plugin_direct.c
*
* This plugin
* - TX: forwards messages to trmux
* - RX: waits on rx task's message queue
*/
#include <bcmos_system.h>
#include <bcmtr_plugin.h>
#include <bcm_config.h>
#include <bcmolt_tr_mux.h>
/* Receive OS message pool and queue */
static bcmos_msg_pool bcmtr_rx_msg_pool[BCMTR_MAX_OLTS];
static bcmos_msg_queue bcmtr_rxq[BCMTR_MAX_OLTS];
/* Flags indicating init progress */
static bcmos_bool rx_pool_created[BCMTR_MAX_OLTS];
static bcmos_bool rxq_created[BCMTR_MAX_OLTS];
static void _bcmtr_direct_rx_from_trmux(bcmolt_devid device, bcmos_buf *buf, bcmtrmux_channel channel, void *data);
/* To resolve symbols in user_appl in band not applicable for VXWorks*/
void using_inband_set(bcmos_bool using_inband){}
bcmos_bool using_inband_get(void)
{
return BCMOS_FALSE;
}
/* Transport IPC message data */
typedef struct bcmtr_ipc_data
{
bcmolt_buf buf; /* Rx buffer */
bcmolt_subchannel subch; /* rx channel */
} bcmtr_ipc_data;
/* System --> OLT buffer translation.
* system buffer is released in case of success
*/
static bcmos_errno bcmtr_sysbuf_to_oltbuf(bcmos_buf *sysb, bcmolt_buf *oltb)
{
bcmos_errno err;
err = bcmolt_buf_alloc(oltb, bcmos_buf_length(sysb), BCMTR_BUF_ENDIAN);
if (err)
return err;
bcmolt_buf_write(oltb, bcmos_buf_data(sysb), bcmos_buf_length(sysb));
bcmos_buf_free(sysb);
oltb->curr = oltb->start;
return BCM_ERR_OK;
}
/* OLT buffer --> system buffer translation.
* OLT buffer must have headroom for bcmos_buf header
*/
static bcmos_buf *bcmtr_oltbuf_to_sysbuf(bcmolt_buf *oltb)
{
bcmos_buf *sysb;
uint32_t len = bcmolt_buf_get_used(oltb);
sysb = bcmos_buf_alloc(len);
if (sysb == NULL)
return NULL;
memcpy(bcmos_buf_data(sysb), oltb->start, len);
bcmos_buf_length_set(sysb, len);
/* We don't release the original oltb because it is needed for retransmission.
* It will be released by the transport layer
*/
return sysb;
}
/* Release message data */
static void bcmtr_msg_data_release(bcmos_msg *msg)
{
bcmtr_ipc_data *data = msg->data;
bcmolt_buf_free(&data->buf);
}
/** Close communication channel */
static bcmos_errno bcmtr_direct_close(bcmtr_plugin_channel ch)
{
bcmolt_devid device = (bcmolt_devid)(ch >> 8);
bcmtrmux_channel muxch = (bcmtrmux_channel)(ch & 0xff);
/* Unregister from TRMUX */
bcmtrmux_channel_unregister(device, muxch);
/* Destroy rx message pool */
if (rx_pool_created[device])
{
bcmos_msg_pool_destroy(&bcmtr_rx_msg_pool[device]);
rx_pool_created[device] = BCMOS_FALSE;
}
/* Destroy RX message queue */
if (rxq_created[device])
{
bcmos_msg_queue_destroy(&bcmtr_rxq[device]);
rxq_created[device] = BCMOS_FALSE;
}
return BCM_ERR_OK;
}
/** Open communication channel */
static bcmos_errno bcmtr_direct_open(int device, bcmtr_plugin_cfg *cfg, bcmtr_plugin_channel *ch)
{
/* The following variables are declared static in order to protect name string */
static bcmos_msg_queue_parm msgq_parm = { .name = "tr_rxq"};
bcmos_msg_pool_parm msg_pool_parm = {};
bcmtrmux_channel mux_channel = BCMTRMUX_CHANNEL_AUTO_ASSIGN;
bcmos_errno err;
/* Direct plugin supports only 1 application instance */
if (device >= BCMTR_MAX_OLTS)
BCMOS_TRACE_RETURN(BCM_ERR_PARM, "Device %u is out of range\n", device);
if (rx_pool_created[device])
BCMOS_TRACE_RETURN(BCM_ERR_ALREADY, "Transport is already initialized for device %u\n", device);
/* Create RX msg pool */
msg_pool_parm.size = BCMTR_MAX_RXQ_SIZE; /* <-- Define parameter in bcmtr_config */
msg_pool_parm.data_size = sizeof(bcmtr_ipc_data);
msg_pool_parm.data_release = bcmtr_msg_data_release;
err = bcmos_msg_pool_create(&bcmtr_rx_msg_pool[device], &msg_pool_parm);
if (err)
BCMOS_TRACE_RETURN(err, "Can't create rx pool\n");
/* Create RX queue set */
err = bcmos_msg_queue_create(&bcmtr_rxq[device], &msgq_parm);
if (err)
{
bcmos_msg_pool_destroy(&bcmtr_rx_msg_pool[device]);
BCMOS_TRACE_RETURN(err, "Can't create rxq\n");
}
/* Register with trmux */
err = bcmtrmux_channel_register(device, &mux_channel, _bcmtr_direct_rx_from_trmux, (void *)NULL );
if (err)
{
bcmos_msg_pool_destroy(&bcmtr_rx_msg_pool[device]);
bcmos_msg_queue_destroy(&bcmtr_rxq[device]);
BCMOS_TRACE_RETURN(err, "Can't register with trmux\n");
}
rx_pool_created[device] = BCMOS_TRUE;
rxq_created[device] = BCMOS_TRUE;
*ch = (bcmtr_plugin_channel)((device << 8) | mux_channel);
return BCM_ERR_OK;
}
/** Send data */
static bcmos_errno bcmtr_direct_send(bcmtr_plugin_channel ch, bcmolt_subchannel subch, bcmolt_buf *buf,
bcmtr_send_flags flags)
{
bcmolt_devid device = (bcmolt_devid)(ch >> 8);
bcmtrmux_channel muxch = (bcmtrmux_channel)(ch & 0xff);
bcmos_buf *sysb;
/* Do zero-copy conversion from bcmolt_buf --> bcmos_buf. It is possible because room
* for bcmos_buf header is reserved in the beginning of bcmolt_buf
*/
sysb = bcmtr_oltbuf_to_sysbuf(buf);
if (!sysb)
return BCM_ERR_NOMEM;
bcmtrmux_rx_from_host(device, muxch, sysb);
return BCM_ERR_OK;
}
/* Receive from trmux. Called in trmux context */
static void _bcmtr_direct_rx_from_trmux(bcmolt_devid device, bcmos_buf *sysb, bcmtrmux_channel channel, void *data)
{
bcmos_msg *msg;
bcmtr_ipc_data *ipc_data;
bcmos_errno err;
msg = bcmos_msg_pool_alloc(&bcmtr_rx_msg_pool[device]);
if (!msg)
{
/* <-- add some statistic here */
bcmos_buf_free(sysb);
return;
}
ipc_data = msg->data;
err = bcmtr_sysbuf_to_oltbuf(sysb, &ipc_data->buf);
if (err)
{
/* <-- add some statistic here */
bcmos_buf_free(sysb);
bcmos_msg_free(msg);
return;
}
ipc_data->subch = channel;
err = bcmos_msg_send(&bcmtr_rxq[device], msg, BCMOS_MSG_SEND_AUTO_FREE);
if (err)
{
/* <-- add some statistic here */
}
}
/** Receive data */
static bcmos_errno bcmtr_direct_recv(bcmtr_plugin_channel ch, bcmolt_subchannel *subch, bcmolt_buf *buf)
{
bcmolt_devid device = (bcmolt_devid)(ch >> 8);
bcmos_msg *msg;
bcmtr_ipc_data *data;
bcmos_errno err;
err = bcmos_msg_recv(&bcmtr_rxq[device], BCMTR_MSG_TIMEOUT, &msg);
if (err)
{
if (err != BCM_ERR_TIMEOUT)
err = BCM_ERR_COMM_FAIL;
return err;
}
data = msg->data;
*buf = data->buf;
*subch = data->subch;
/* Prevent buffer release when releasing OS message */
data->buf.start = data->buf.curr = NULL;
bcmos_msg_free(msg);
return BCM_ERR_OK;
}
/** Initialize plugin callbacks
* \param[in,out] driver Transport plugin driver structure
* \return error code
*/
bcmos_errno bcmtr_plugin_init(bcmtr_plugin_cfg *cfg, bcmtr_driver *driver)
{
driver->open = bcmtr_direct_open;
driver->close = bcmtr_direct_close;
driver->recv = bcmtr_direct_recv;
driver->send = bcmtr_direct_send;
return BCM_ERR_OK;
}