| /* |
| <: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; |
| } |
| |