bcm-uk-rtrans.c (6576B)
1 /*********************************************************************** 2 * 3 * 4 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 5 * 6 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 7 * 8 * This provides a simple implementation of a BCM C2C/NH transport driver. 9 * This driver uses a User/Kernel Proxy service to transmit and receive the 10 * data. 11 * This driver is compiled for both the kernel and user space. 12 */ 13 14 #include "bcm-uk-trans.h" 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <assert.h> 19 20 #include <sal/core/alloc.h> 21 #include <sal/core/thread.h> 22 23 #include <bcm/error.h> 24 #include <soc/cm.h> 25 #include <linux-uk-proxy.h> 26 27 /* 28 * This is the name of the proxy service this module will use 29 */ 30 static char _input_proxy_service[] = "BCM UK PROXY REMOTE TRANSPORT"; 31 static char _output_proxy_service[] = "BCM UK PROXY REMOTE TRANSPORT"; 32 33 /* 34 * Simple Handler registration (emphasis on simple). 35 */ 36 #define MAX_CALLBACKS 5 37 static struct callback_ctrl_s { 38 bcm_rx_cb_f cb; 39 void* cookie; 40 } _callback_ctrl[MAX_CALLBACKS]; 41 42 /* 43 * Function: 44 * _rx_reg 45 * Purpose: 46 * Provides the transport's rx register function. Veru minimal. 47 */ 48 static int 49 _rx_reg(int unit, const char* name, bcm_rx_cb_f callback, uint8 priority, 50 void* cookie, uint32 flags) 51 { 52 int i; 53 for(i = 0; i < MAX_CALLBACKS; i++) { 54 if(_callback_ctrl[i].cb == NULL) { 55 _callback_ctrl[i].cb = callback; 56 _callback_ctrl[i].cookie = cookie; 57 return 0; 58 } 59 } 60 return -1; 61 } 62 63 /* 64 * Function: 65 * _rx_unreg 66 * Purpose: 67 * Provides the transport's rx unregister function. Very minimal. 68 */ 69 static int 70 _rx_unreg(int unit, bcm_rx_cb_f callback, uint8 priority) 71 { 72 int i; 73 for(i = 0; i < MAX_CALLBACKS; i++) { 74 if(_callback_ctrl[i].cb == callback) { 75 _callback_ctrl[i].cb = NULL; 76 _callback_ctrl[i].cookie = NULL; 77 } 78 } 79 return 0; 80 } 81 82 83 /* 84 * Function: 85 * _rx_handle 86 * Purpose: 87 * Processes a received frame for the transport 88 */ 89 static int 90 _rx_handle(unsigned char* data, int len) 91 { 92 int i; 93 bcm_pkt_t pkt; 94 95 /* pkt structure is at the beginning of the data */ 96 memcpy(&pkt, data, sizeof(pkt)); 97 len -= sizeof(pkt); 98 99 /* The data has to start at the beginning of this buffer or the data buffer won't be free-able if they own it */ 100 memmove(data, data+sizeof(pkt), len); 101 pkt.pkt_data = &pkt._pkt_data; 102 103 /* Fix the data block pointer */ 104 pkt.pkt_data->data = data; 105 pkt.pkt_data->len = len ; 106 107 assert(pkt.blk_count == 1); 108 109 /* Call everyone. This does not implement the priority scheme. */ 110 for(i = 0; i < MAX_CALLBACKS; i++) { 111 if(_callback_ctrl[i].cb) { 112 int rc = _callback_ctrl[i].cb(0, &pkt, _callback_ctrl[i].cookie); 113 switch(rc) 114 { 115 case BCM_RX_HANDLED: 116 { 117 /* We should try to reuse this */ 118 bcm_rx_free(0, data); 119 return 0; 120 } 121 case BCM_RX_HANDLED_OWNED: 122 { 123 return 0; 124 } 125 case BCM_RX_NOT_HANDLED: 126 { 127 /* Next handler */ 128 break; 129 } 130 default: 131 { 132 assert(0); 133 break; 134 } 135 } 136 } 137 } 138 bcm_rx_free(0, data); 139 return 0; 140 } 141 142 143 /* 144 * Function: 145 * _rx_thread 146 * Purpose: 147 * Receives and dispatches packets from the kernel proxy service. 148 */ 149 150 typedef struct rx_thread_ctrl_s { 151 const char* service; 152 int exit; 153 } rx_thread_ctrl_t; 154 155 static void 156 _rx_thread(rx_thread_ctrl_t* ctrl) 157 { 158 unsigned char* data = NULL; 159 160 for(;;) { 161 unsigned int len = LUK_MAX_DATA_SIZE; 162 if(!data) { 163 /* Transport client expects data to be allocated from the rx buffer pool */ 164 bcm_rx_alloc(0, LUK_MAX_DATA_SIZE, 0, (void*)&data); 165 assert(data); 166 } 167 memset(data, 0, LUK_MAX_DATA_SIZE); 168 169 if(linux_uk_proxy_recv(ctrl->service, data, &len) >= 0) { 170 _rx_handle(data, len); 171 172 data = NULL; 173 } 174 175 if(ctrl->exit) { 176 ctrl->exit = 0; 177 return; 178 } 179 } 180 } 181 182 183 /* 184 * Function: 185 * _setup_tx 186 * Purpose: 187 * setup_tx transport vector 188 */ 189 static int 190 _setup_tx(int unit, bcm_pkt_t* tx_pkt) 191 { 192 /* Nothing needed here */ 193 return BCM_E_NONE; 194 } 195 196 /* 197 * Function: 198 * _tx 199 * Purpose: 200 * tx transport vector 201 */ 202 static int 203 _tx(int unit, bcm_pkt_t* pkt, void* cookie) 204 { 205 int i; 206 unsigned char data[LUK_MAX_DATA_SIZE]; 207 unsigned char* p = data; 208 int len; 209 210 p += sizeof(bcm_pkt_t); 211 len = sizeof(bcm_pkt_t); 212 213 /* Collect data blocks into one buffer for transport */ 214 for(i = 0; i < pkt->blk_count; i++) { 215 memcpy(p, pkt->pkt_data[i].data, pkt->pkt_data[i].len); 216 p+=pkt->pkt_data[i].len; 217 len += pkt->pkt_data[i].len; 218 } 219 220 /* Put the bcm_pkt_t structure in front */ 221 memcpy(data, pkt, sizeof(*pkt)); 222 223 /* Send it */ 224 linux_uk_proxy_send(_output_proxy_service, data, len+4); 225 226 if(pkt->call_back) { 227 pkt->call_back(unit, pkt, cookie); 228 } 229 230 return 0; 231 } 232 233 /* 234 * Function: 235 * _tx_list 236 * Purpose: 237 * tx_list transport vector 238 */ 239 static int 240 _tx_list(int unit, bcm_pkt_t* pkt, bcm_pkt_cb_f all_done_cb, void* cookie) 241 { 242 bcm_pkt_t* p; 243 244 /* Just tx each one */ 245 for(p = pkt; p; p = p->next) { 246 _tx(unit, p, cookie); 247 } 248 249 if(all_done_cb) { 250 all_done_cb(unit, pkt, cookie); 251 } 252 253 return 0; 254 } 255 256 257 /* 258 * This is our transport structure 259 */ 260 static bcm_trans_ptr_t _trans_ptr = { 261 bcm_rx_alloc, /* All transports need to use bcm_rx_alloc() and bcm_rx_free() at the moment */ 262 bcm_rx_free, 263 bcm_pkt_rx_alloc, 264 bcm_pkt_rx_free, 265 _rx_reg, 266 _rx_unreg, 267 _setup_tx, 268 _tx, 269 _tx_list, 270 NULL, 271 NULL, 272 0 /* Default unit for alloc/free */ 273 }; 274 275 276 /* RX thread control */ 277 static rx_thread_ctrl_t _ctrl; 278 279 int 280 bcm_uk_rtrans_create(const char* service, bcm_trans_ptr_t** trans) 281 { 282 if(service) { 283 strcpy(_input_proxy_service, service); 284 strcpy(_output_proxy_service, service); 285 } 286 287 /* Need to open the proxy driver first. Not needed when running in the kernel */ 288 linux_uk_proxy_open(); 289 290 /* Special overrides */ 291 if(getenv("INPUT_PROXY_SERVICE")) { 292 strcpy(_input_proxy_service, getenv("INPUT_PROXY_SERVICE")); 293 } 294 if(getenv("OUTPUT_PROXY_SERVICE")) { 295 strcpy(_output_proxy_service, getenv("OUTPUT_PROXY_SERVICE")); 296 } 297 298 linux_uk_proxy_service_create(_input_proxy_service, 64, 0); 299 300 _ctrl.service = _input_proxy_service; 301 _ctrl.exit = 0; 302 303 sal_thread_create("BCM UK PROXY TRANSPORT RX", 0, 0, (void (*)(void*))_rx_thread, &_ctrl); 304 305 *trans = &_trans_ptr; 306 return 0; 307 } 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324