Shad Ansari | 2f7f9be | 2017-06-07 13:34:53 -0700 | [diff] [blame^] | 1 | /* |
| 2 | <:copyright-BRCM:2016:proprietary:standard |
| 3 | |
| 4 | Broadcom Proprietary and Confidential.(c) 2016 Broadcom |
| 5 | All Rights Reserved |
| 6 | |
| 7 | This program is the proprietary software of Broadcom Corporation and/or its |
| 8 | licensors, and may only be used, duplicated, modified or distributed pursuant |
| 9 | to the terms and conditions of a separate, written license agreement executed |
| 10 | between you and Broadcom (an "Authorized License"). Except as set forth in |
| 11 | an Authorized License, Broadcom grants no license (express or implied), right |
| 12 | to use, or waiver of any kind with respect to the Software, and Broadcom |
| 13 | expressly reserves all rights in and to the Software and all intellectual |
| 14 | property rights therein. IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE |
| 15 | NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY |
| 16 | BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE. |
| 17 | |
| 18 | Except as expressly set forth in the Authorized License, |
| 19 | |
| 20 | 1. This program, including its structure, sequence and organization, |
| 21 | constitutes the valuable trade secrets of Broadcom, and you shall use |
| 22 | all reasonable efforts to protect the confidentiality thereof, and to |
| 23 | use this information only in connection with your use of Broadcom |
| 24 | integrated circuit products. |
| 25 | |
| 26 | 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" |
| 27 | AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR |
| 28 | WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH |
| 29 | RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY DISCLAIMS ANY AND |
| 30 | ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, |
| 31 | FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR |
| 32 | COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR CORRESPONDENCE |
| 33 | TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF USE OR |
| 34 | PERFORMANCE OF THE SOFTWARE. |
| 35 | |
| 36 | 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR |
| 37 | ITS LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, |
| 38 | INDIRECT, OR EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY |
| 39 | WAY RELATING TO YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN |
| 40 | IF BROADCOM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; |
| 41 | OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE |
| 42 | SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE LIMITATIONS |
| 43 | SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF ANY |
| 44 | LIMITED REMEDY. |
| 45 | :> |
| 46 | */ |
| 47 | /* |
| 48 | * bcmtr_plugin_direct.c |
| 49 | * |
| 50 | * This plugin |
| 51 | * - TX: forwards messages to trmux |
| 52 | * - RX: waits on rx task's message queue |
| 53 | */ |
| 54 | |
| 55 | #include <bcmos_system.h> |
| 56 | |
| 57 | #include <bcmtr_plugin.h> |
| 58 | #include <bcm_config.h> |
| 59 | #include <bcmolt_tr_mux.h> |
| 60 | |
| 61 | /* Receive OS message pool and queue */ |
| 62 | static bcmos_msg_pool bcmtr_rx_msg_pool[BCMTR_MAX_OLTS]; |
| 63 | static bcmos_msg_queue bcmtr_rxq[BCMTR_MAX_OLTS]; |
| 64 | |
| 65 | /* Flags indicating init progress */ |
| 66 | static bcmos_bool rx_pool_created[BCMTR_MAX_OLTS]; |
| 67 | static bcmos_bool rxq_created[BCMTR_MAX_OLTS]; |
| 68 | static void _bcmtr_direct_rx_from_trmux(bcmolt_devid device, bcmos_buf *buf, bcmtrmux_channel channel, void *data); |
| 69 | |
| 70 | /* To resolve symbols in user_appl in band not applicable for VXWorks*/ |
| 71 | void using_inband_set(bcmos_bool using_inband){} |
| 72 | bcmos_bool using_inband_get(void) |
| 73 | { |
| 74 | return BCMOS_FALSE; |
| 75 | } |
| 76 | |
| 77 | |
| 78 | /* Transport IPC message data */ |
| 79 | typedef struct bcmtr_ipc_data |
| 80 | { |
| 81 | bcmolt_buf buf; /* Rx buffer */ |
| 82 | bcmolt_subchannel subch; /* rx channel */ |
| 83 | } bcmtr_ipc_data; |
| 84 | |
| 85 | |
| 86 | /* System --> OLT buffer translation. |
| 87 | * system buffer is released in case of success |
| 88 | */ |
| 89 | static bcmos_errno bcmtr_sysbuf_to_oltbuf(bcmos_buf *sysb, bcmolt_buf *oltb) |
| 90 | { |
| 91 | bcmos_errno err; |
| 92 | |
| 93 | err = bcmolt_buf_alloc(oltb, bcmos_buf_length(sysb), BCMTR_BUF_ENDIAN); |
| 94 | if (err) |
| 95 | return err; |
| 96 | bcmolt_buf_write(oltb, bcmos_buf_data(sysb), bcmos_buf_length(sysb)); |
| 97 | bcmos_buf_free(sysb); |
| 98 | oltb->curr = oltb->start; |
| 99 | return BCM_ERR_OK; |
| 100 | } |
| 101 | |
| 102 | /* OLT buffer --> system buffer translation. |
| 103 | * OLT buffer must have headroom for bcmos_buf header |
| 104 | */ |
| 105 | static bcmos_buf *bcmtr_oltbuf_to_sysbuf(bcmolt_buf *oltb) |
| 106 | { |
| 107 | bcmos_buf *sysb; |
| 108 | uint32_t len = bcmolt_buf_get_used(oltb); |
| 109 | |
| 110 | sysb = bcmos_buf_alloc(len); |
| 111 | if (sysb == NULL) |
| 112 | return NULL; |
| 113 | memcpy(bcmos_buf_data(sysb), oltb->start, len); |
| 114 | bcmos_buf_length_set(sysb, len); |
| 115 | /* We don't release the original oltb because it is needed for retransmission. |
| 116 | * It will be released by the transport layer |
| 117 | */ |
| 118 | return sysb; |
| 119 | } |
| 120 | |
| 121 | /* Release message data */ |
| 122 | static void bcmtr_msg_data_release(bcmos_msg *msg) |
| 123 | { |
| 124 | bcmtr_ipc_data *data = msg->data; |
| 125 | bcmolt_buf_free(&data->buf); |
| 126 | } |
| 127 | |
| 128 | /** Close communication channel */ |
| 129 | static bcmos_errno bcmtr_direct_close(bcmtr_plugin_channel ch) |
| 130 | { |
| 131 | bcmolt_devid device = (bcmolt_devid)(ch >> 8); |
| 132 | bcmtrmux_channel muxch = (bcmtrmux_channel)(ch & 0xff); |
| 133 | |
| 134 | /* Unregister from TRMUX */ |
| 135 | bcmtrmux_channel_unregister(device, muxch); |
| 136 | |
| 137 | /* Destroy rx message pool */ |
| 138 | if (rx_pool_created[device]) |
| 139 | { |
| 140 | bcmos_msg_pool_destroy(&bcmtr_rx_msg_pool[device]); |
| 141 | rx_pool_created[device] = BCMOS_FALSE; |
| 142 | } |
| 143 | |
| 144 | /* Destroy RX message queue */ |
| 145 | if (rxq_created[device]) |
| 146 | { |
| 147 | bcmos_msg_queue_destroy(&bcmtr_rxq[device]); |
| 148 | rxq_created[device] = BCMOS_FALSE; |
| 149 | } |
| 150 | |
| 151 | return BCM_ERR_OK; |
| 152 | } |
| 153 | |
| 154 | /** Open communication channel */ |
| 155 | static bcmos_errno bcmtr_direct_open(int device, bcmtr_plugin_cfg *cfg, bcmtr_plugin_channel *ch) |
| 156 | { |
| 157 | /* The following variables are declared static in order to protect name string */ |
| 158 | static bcmos_msg_queue_parm msgq_parm = { .name = "tr_rxq"}; |
| 159 | bcmos_msg_pool_parm msg_pool_parm = {}; |
| 160 | bcmtrmux_channel mux_channel = BCMTRMUX_CHANNEL_AUTO_ASSIGN; |
| 161 | bcmos_errno err; |
| 162 | |
| 163 | /* Direct plugin supports only 1 application instance */ |
| 164 | if (device >= BCMTR_MAX_OLTS) |
| 165 | BCMOS_TRACE_RETURN(BCM_ERR_PARM, "Device %u is out of range\n", device); |
| 166 | if (rx_pool_created[device]) |
| 167 | BCMOS_TRACE_RETURN(BCM_ERR_ALREADY, "Transport is already initialized for device %u\n", device); |
| 168 | |
| 169 | /* Create RX msg pool */ |
| 170 | msg_pool_parm.size = BCMTR_MAX_RXQ_SIZE; /* <-- Define parameter in bcmtr_config */ |
| 171 | msg_pool_parm.data_size = sizeof(bcmtr_ipc_data); |
| 172 | msg_pool_parm.data_release = bcmtr_msg_data_release; |
| 173 | err = bcmos_msg_pool_create(&bcmtr_rx_msg_pool[device], &msg_pool_parm); |
| 174 | if (err) |
| 175 | BCMOS_TRACE_RETURN(err, "Can't create rx pool\n"); |
| 176 | |
| 177 | /* Create RX queue set */ |
| 178 | err = bcmos_msg_queue_create(&bcmtr_rxq[device], &msgq_parm); |
| 179 | if (err) |
| 180 | { |
| 181 | bcmos_msg_pool_destroy(&bcmtr_rx_msg_pool[device]); |
| 182 | BCMOS_TRACE_RETURN(err, "Can't create rxq\n"); |
| 183 | } |
| 184 | |
| 185 | /* Register with trmux */ |
| 186 | err = bcmtrmux_channel_register(device, &mux_channel, _bcmtr_direct_rx_from_trmux, (void *)NULL ); |
| 187 | if (err) |
| 188 | { |
| 189 | bcmos_msg_pool_destroy(&bcmtr_rx_msg_pool[device]); |
| 190 | bcmos_msg_queue_destroy(&bcmtr_rxq[device]); |
| 191 | BCMOS_TRACE_RETURN(err, "Can't register with trmux\n"); |
| 192 | } |
| 193 | |
| 194 | rx_pool_created[device] = BCMOS_TRUE; |
| 195 | rxq_created[device] = BCMOS_TRUE; |
| 196 | *ch = (bcmtr_plugin_channel)((device << 8) | mux_channel); |
| 197 | |
| 198 | return BCM_ERR_OK; |
| 199 | } |
| 200 | |
| 201 | /** Send data */ |
| 202 | static bcmos_errno bcmtr_direct_send(bcmtr_plugin_channel ch, bcmolt_subchannel subch, bcmolt_buf *buf, |
| 203 | bcmtr_send_flags flags) |
| 204 | { |
| 205 | bcmolt_devid device = (bcmolt_devid)(ch >> 8); |
| 206 | bcmtrmux_channel muxch = (bcmtrmux_channel)(ch & 0xff); |
| 207 | bcmos_buf *sysb; |
| 208 | |
| 209 | /* Do zero-copy conversion from bcmolt_buf --> bcmos_buf. It is possible because room |
| 210 | * for bcmos_buf header is reserved in the beginning of bcmolt_buf |
| 211 | */ |
| 212 | sysb = bcmtr_oltbuf_to_sysbuf(buf); |
| 213 | if (!sysb) |
| 214 | return BCM_ERR_NOMEM; |
| 215 | bcmtrmux_rx_from_host(device, muxch, sysb); |
| 216 | |
| 217 | return BCM_ERR_OK; |
| 218 | } |
| 219 | |
| 220 | /* Receive from trmux. Called in trmux context */ |
| 221 | static void _bcmtr_direct_rx_from_trmux(bcmolt_devid device, bcmos_buf *sysb, bcmtrmux_channel channel, void *data) |
| 222 | { |
| 223 | bcmos_msg *msg; |
| 224 | bcmtr_ipc_data *ipc_data; |
| 225 | bcmos_errno err; |
| 226 | |
| 227 | msg = bcmos_msg_pool_alloc(&bcmtr_rx_msg_pool[device]); |
| 228 | if (!msg) |
| 229 | { |
| 230 | /* <-- add some statistic here */ |
| 231 | bcmos_buf_free(sysb); |
| 232 | return; |
| 233 | } |
| 234 | ipc_data = msg->data; |
| 235 | err = bcmtr_sysbuf_to_oltbuf(sysb, &ipc_data->buf); |
| 236 | if (err) |
| 237 | { |
| 238 | /* <-- add some statistic here */ |
| 239 | bcmos_buf_free(sysb); |
| 240 | bcmos_msg_free(msg); |
| 241 | return; |
| 242 | } |
| 243 | ipc_data->subch = channel; |
| 244 | err = bcmos_msg_send(&bcmtr_rxq[device], msg, BCMOS_MSG_SEND_AUTO_FREE); |
| 245 | if (err) |
| 246 | { |
| 247 | /* <-- add some statistic here */ |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | /** Receive data */ |
| 252 | static bcmos_errno bcmtr_direct_recv(bcmtr_plugin_channel ch, bcmolt_subchannel *subch, bcmolt_buf *buf) |
| 253 | { |
| 254 | bcmolt_devid device = (bcmolt_devid)(ch >> 8); |
| 255 | bcmos_msg *msg; |
| 256 | bcmtr_ipc_data *data; |
| 257 | bcmos_errno err; |
| 258 | |
| 259 | err = bcmos_msg_recv(&bcmtr_rxq[device], BCMTR_MSG_TIMEOUT, &msg); |
| 260 | if (err) |
| 261 | { |
| 262 | if (err != BCM_ERR_TIMEOUT) |
| 263 | err = BCM_ERR_COMM_FAIL; |
| 264 | return err; |
| 265 | } |
| 266 | |
| 267 | data = msg->data; |
| 268 | *buf = data->buf; |
| 269 | *subch = data->subch; |
| 270 | /* Prevent buffer release when releasing OS message */ |
| 271 | data->buf.start = data->buf.curr = NULL; |
| 272 | bcmos_msg_free(msg); |
| 273 | |
| 274 | return BCM_ERR_OK; |
| 275 | } |
| 276 | |
| 277 | /** Initialize plugin callbacks |
| 278 | * \param[in,out] driver Transport plugin driver structure |
| 279 | * \return error code |
| 280 | */ |
| 281 | bcmos_errno bcmtr_plugin_init(bcmtr_plugin_cfg *cfg, bcmtr_driver *driver) |
| 282 | { |
| 283 | driver->open = bcmtr_direct_open; |
| 284 | driver->close = bcmtr_direct_close; |
| 285 | driver->recv = bcmtr_direct_recv; |
| 286 | driver->send = bcmtr_direct_send; |
| 287 | |
| 288 | return BCM_ERR_OK; |
| 289 | } |
| 290 | |