rx.c (10340B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: rx.c 8 * Purpose: BCMX RX API implementation 9 * Requires: 10 */ 11 12 #include <shared/bsl.h> 13 14 #include <shared/alloc.h> 15 #include <sal/core/libc.h> 16 #include <bcm/pkt.h> 17 #include <bcm/rx.h> 18 #include <bcm/error.h> 19 20 21 #include <bcm_int/control.h> 22 #include <bcm_int/common/rx.h> 23 24 #include <bcmx/rx.h> 25 #include <bcmx/bcmx.h> 26 27 #include "bcmx_int.h" 28 29 #define BCMX_RX_INIT_CHECK BCMX_READY_CHECK 30 31 #define BCMX_RX_SET_ERROR_CHECK(_unit, _check, _rv) \ 32 BCMX_SET_ERROR_CHECK(_unit, _check, _rv) 33 34 #define BCMX_RX_DELETE_ERROR_CHECK(_unit, _check, _rv) \ 35 BCMX_DELETE_ERROR_CHECK(_unit, _check, _rv) 36 37 #define BCMX_RX_GET_IS_VALID(_unit, _rv) \ 38 BCMX_ERROR_IS_VALID(_unit, _rv) 39 40 41 /* Exposed to BCMX internals */ 42 43 int _bcmx_rx_running = FALSE; 44 45 static rx_callout_t *bcmx_rco; 46 47 48 /* 49 * Function: 50 * bcmx_rx_running 51 * Purpose: 52 * Return status of whether BCMX RX is running 53 * Returns: 54 * TRUE if BCMX RX is running 55 * Notes: 56 * The _bcmx_rx_running variable is exported and visible. That 57 * can be checked as easily. 58 */ 59 60 int 61 bcmx_rx_running(void) { 62 return _bcmx_rx_running; 63 } 64 65 static INLINE rx_callout_t * 66 bcmx_rco_find(bcm_rx_cb_f fn, int priority, rx_callout_t **prev) 67 { 68 rx_callout_t *rco = bcmx_rco; 69 70 *prev = NULL; 71 while (rco != NULL) { 72 if (rco->rco_function == fn && rco->rco_priority == priority) { 73 return rco; 74 } 75 if (rco->rco_priority < priority) { 76 return NULL; 77 } 78 *prev = rco; 79 rco = (rx_callout_t *)rco->rco_next; 80 } 81 82 return NULL; 83 } 84 85 86 /* 87 * Function: 88 * bcmx_rx_register 89 * Purpose: 90 * Register with all BCM units to receive packets 91 * Parameters: 92 * name - char string identifier of callout 93 * fn - Callout function 94 * priority - Of callout 95 * cookie - Passed on callback 96 * flags - See BCM_RCO_F_... 97 * Returns: 98 * BCM_E_XXX 99 * Notes: 100 * Handlers registering in interrupt context will not receive 101 * tunnelled packets. 102 * 103 * The callback is registered with each available unit. 104 * 105 * The callbacks have to be maintained locally since addition/ 106 * removal of units results in making subsequent BCM layer 107 * register/unregister calls. 108 */ 109 110 int 111 bcmx_rx_register(const char *name, 112 bcm_rx_cb_f fn, 113 int priority, 114 void *cookie, 115 uint32 flags) 116 { 117 int unit, i; 118 int rv = BCM_E_NONE, tmp_rv; 119 rx_callout_t *rco, *prev, *next; 120 121 BCMX_RX_INIT_CHECK; 122 123 #if defined(BROADCOM_DEBUG) 124 if (flags & BCM_RCO_F_INTR) { 125 LOG_WARN(BSL_LS_BCMX_COMMON, 126 (BSL_META("BCMX RX: Intr RX handler will " 127 "not receive tunnelled pkts: %s\n"), 128 name)); 129 } 130 #endif /* BROADCOM_DEBUG */ 131 132 BCMX_CONFIG_LOCK; 133 rco = bcmx_rco_find(fn, priority, &prev); 134 if (rco != NULL) { 135 BCMX_CONFIG_UNLOCK; 136 return BCM_E_NONE; 137 } 138 139 rco = sal_alloc(sizeof(rx_callout_t), "bcmx_rx_reg"); 140 if (rco == NULL) { 141 BCMX_CONFIG_UNLOCK; 142 return BCM_E_MEMORY; 143 } 144 145 if (prev == NULL) { 146 next = bcmx_rco; 147 bcmx_rco = rco; 148 } else { 149 next = (rx_callout_t *)prev->rco_next; 150 prev->rco_next = rco; 151 } 152 SETUP_RCO(rco, name, fn, priority, cookie, next, flags); 153 for (i = 0; i < 16; i++) { 154 if ((flags & BCM_RCO_F_COS_ACCEPT_MASK) & BCM_RCO_F_COS_ACCEPT(i)) { 155 SETUP_RCO_COS_SET(rco, i); 156 } 157 } 158 BCMX_CONFIG_UNLOCK; 159 160 if (_bcmx_rx_running) { 161 rv = BCM_E_UNAVAIL; 162 BCMX_UNIT_ITER(unit, i) { 163 tmp_rv = bcm_rx_register(unit, name, fn, priority, cookie, flags); 164 BCM_IF_ERROR_RETURN(BCMX_RX_SET_ERROR_CHECK(unit, tmp_rv, &rv)); 165 } 166 } 167 168 return rv; 169 } 170 171 172 /* 173 * Function: 174 * bcmx_rx_unregister 175 * Purpose: 176 * Unregister the RX callback from all BCM units 177 * Parameters: 178 * fn - Callout function 179 * priority - Of callout 180 * Returns: 181 * BCM_E_XXX 182 */ 183 184 int 185 bcmx_rx_unregister(bcm_rx_cb_f fn, int priority) 186 { 187 int unit, i; 188 int rv = BCM_E_UNAVAIL, tmp_rv; 189 rx_callout_t *rco, *prev; 190 191 BCMX_RX_INIT_CHECK; 192 193 BCMX_CONFIG_LOCK; 194 rco = bcmx_rco_find(fn, priority, &prev); 195 if (rco == NULL) { 196 BCMX_CONFIG_UNLOCK; 197 return BCM_E_NONE; 198 } 199 200 if (prev == NULL) { 201 bcmx_rco = (rx_callout_t *)rco->rco_next; 202 } else { 203 prev->rco_next = rco->rco_next; 204 } 205 206 sal_free(rco); 207 BCMX_CONFIG_UNLOCK; 208 209 /* Now take care of any known remote units */ 210 BCMX_UNIT_ITER(unit, i) { 211 tmp_rv = bcm_rx_unregister(unit, fn, priority); 212 BCM_IF_ERROR_RETURN(BCMX_RX_DELETE_ERROR_CHECK(unit, tmp_rv, &rv)); 213 } 214 215 return rv; 216 } 217 218 219 220 /* 221 * Function: 222 * bcmx_rx_start 223 * Purpose: 224 * Start BCMX RX packet handling 225 * Returns: 226 * BCM_E_XXX 227 * Notes: 228 * Calls "add" on all the current units. 229 */ 230 231 int 232 bcmx_rx_start(void) 233 { 234 int unit, i; 235 int rv = BCM_E_UNAVAIL, tmp_rv; 236 237 BCMX_RX_INIT_CHECK; 238 239 if (_bcmx_rx_running) { 240 return BCM_E_NONE; 241 } 242 243 _bcmx_rx_running = TRUE; 244 245 BCMX_UNIT_ITER(unit, i) { 246 tmp_rv = bcmx_rx_device_add(unit); 247 if (BCM_FAILURE(BCMX_RX_SET_ERROR_CHECK(unit, tmp_rv, &rv))) { 248 LOG_WARN(BSL_LS_BCMX_COMMON, 249 (BSL_META_U(unit, 250 "BCMX RX: Unit %d add failed: %s\n"), 251 unit, bcm_errmsg(tmp_rv))); 252 break; 253 } 254 } 255 256 return rv; 257 } 258 259 260 261 /* 262 * Function: 263 * bcmx_rx_stop 264 * Purpose: 265 * Stop BCMX RX packet handling 266 * Returns: 267 * BCM_E_XXX 268 */ 269 270 int 271 bcmx_rx_stop(void) 272 { 273 int unit, i; 274 int rv = BCM_E_UNAVAIL, tmp_rv; 275 276 BCMX_RX_INIT_CHECK; 277 278 if (!_bcmx_rx_running) { 279 return BCM_E_NONE; 280 } 281 282 _bcmx_rx_running = FALSE; 283 284 BCMX_UNIT_ITER(unit, i) { 285 tmp_rv = bcmx_rx_device_remove(unit); 286 if (BCM_FAILURE(BCMX_RX_DELETE_ERROR_CHECK(unit, tmp_rv, &rv))) { 287 LOG_WARN(BSL_LS_BCMX_COMMON, 288 (BSL_META_U(unit, 289 "BCMX RX: Unit %d remove failed: %s\n"), 290 unit, bcm_errmsg(tmp_rv))); 291 break; 292 } 293 } 294 295 return rv; 296 } 297 298 299 /* 300 * Function: 301 * bcmx_rx_unit_add 302 * Purpose: 303 * Add a BCM unit to BCMX RX registration. 304 * Parameters: 305 * unit - The unit to add 306 * Returns: 307 * BCM_E_XXX 308 * Notes: 309 * May be called when a new BCM unit is added 310 */ 311 312 int 313 bcmx_rx_device_add(int unit) 314 { 315 rx_callout_t *rco = bcmx_rco; 316 int rv = BCM_E_NONE, tmp_rv; 317 318 BCMX_RX_INIT_CHECK; 319 320 if (!BCM_UNIT_VALID(unit)) { 321 return BCM_E_PARAM; 322 } 323 324 if (_bcmx_rx_running) { 325 rv = BCM_E_UNAVAIL; 326 while (rco != NULL) { 327 tmp_rv = bcm_rx_register(unit, 328 rco->rco_name, 329 rco->rco_function, 330 rco->rco_priority, 331 rco->rco_cookie, 332 rco->rco_flags); 333 if (BCM_FAILURE(BCMX_RX_SET_ERROR_CHECK(unit, tmp_rv, &rv))) { 334 LOG_WARN(BSL_LS_BCMX_COMMON, 335 (BSL_META_U(unit, 336 "BCMX RX: Unit %d register failed: %s\n"), 337 unit, bcm_errmsg(tmp_rv))); 338 } 339 rco = (rx_callout_t *)rco->rco_next; 340 } 341 342 /* Start RX */ 343 tmp_rv = bcm_rx_start(unit, NULL); 344 if (tmp_rv == BCM_E_BUSY) { 345 tmp_rv = BCM_E_NONE; 346 } 347 (void) BCMX_RX_SET_ERROR_CHECK(unit, tmp_rv, &rv); 348 } 349 350 return rv; 351 } 352 353 354 /* 355 * Function: 356 * bcmx_rx_unit_remove 357 * Purpose: 358 * Remove a BCM unit to BCMX RX registration. 359 * Parameters: 360 * unit - The unit to add 361 * Returns: 362 * BCM_E_XXX 363 * Notes: 364 * May be called when a BCM unit is removed 365 */ 366 367 int 368 bcmx_rx_device_remove(int unit) 369 { 370 rx_callout_t *rco = bcmx_rco; 371 int rv = BCM_E_NONE, tmp_rv; 372 373 BCMX_RX_INIT_CHECK; 374 375 if (!BCM_UNIT_VALID(unit)) { 376 return BCM_E_PARAM; 377 } 378 379 while (rco != NULL) { 380 tmp_rv = bcm_rx_unregister(unit, 381 rco->rco_function, 382 rco->rco_priority); 383 if (BCM_FAILURE(BCMX_RX_DELETE_ERROR_CHECK(unit, tmp_rv, &rv))) { 384 LOG_WARN(BSL_LS_BCMX_COMMON, 385 (BSL_META_U(unit, 386 "BCMX RX: Unit %d unregister failed: %s\n"), 387 unit, bcm_errmsg(tmp_rv))); 388 } 389 390 rco = (rx_callout_t *)rco->rco_next; 391 } 392 393 return rv; 394 } 395 396 /* 397 * Function: 398 * bcmx_rx_control_set(bcm_rx_control_t type, int value) 399 * Description: 400 * Enable/Disable specified RX feature. 401 * Parameters: 402 * type - RX control parameter 403 * value - new value of control parameter 404 * Return Value: 405 * BCM_E_NONE 406 * BCM_E_UNAVAIL - Functionality not available 407 */ 408 409 int 410 bcmx_rx_control_set(bcm_rx_control_t type, int arg) 411 { 412 int rv = BCM_E_UNAVAIL, tmp_rv; 413 int i, bcm_unit; 414 415 BCMX_RX_INIT_CHECK; 416 417 BCMX_UNIT_ITER(bcm_unit, i) { 418 tmp_rv = bcm_rx_control_set(bcm_unit, type, arg); 419 BCM_IF_ERROR_RETURN(BCMX_RX_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv)); 420 } 421 422 return rv; 423 } 424 425 /* 426 * Function: 427 * bcmx_rx_control_get(bcm_rx_control_t type, int *value) 428 * Description: 429 * Get the status of specified RX feature. 430 * Parameters: 431 * type - RX control parameter 432 * value - (OUT) Current value of control parameter 433 * Return Value: 434 * BCM_E_NONE 435 * BCM_E_UNAVAIL - Functionality not available 436 */ 437 438 int 439 bcmx_rx_control_get(bcm_rx_control_t type, int *arg) 440 { 441 int rv; 442 int i, bcm_unit; 443 444 BCMX_RX_INIT_CHECK; 445 446 BCMX_PARAM_NULL_CHECK(arg); 447 448 BCMX_UNIT_ITER(bcm_unit, i) { 449 rv = bcm_rx_control_get(bcm_unit, type, arg); 450 if (BCMX_RX_GET_IS_VALID(bcm_unit, rv)) { 451 return rv; 452 } 453 } 454 455 return BCM_E_UNAVAIL; 456 } 457