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