rx.c (245309B)
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: Receive packet mechanism 9 * Requires: 10 * 11 * See sdk/doc/txrx.txt and pkt.txt for 12 * information on the RX API and implementation. 13 * 14 * Quick overview: 15 * 16 * Packet buffer allocation/deallocation is user configurable. 17 * This expects to be given monolithic (single block) buffers. 18 * When "HANDLED_OWNED" is returned by a handler, that means 19 * that the data buffer is stolen, not the packet structure. 20 * 21 * Callback functions may be registered in interrupt or non- 22 * interrupt mode. Non-interrupt is preferred. 23 * 24 * Interrupt load is limited by setting overall rate limit 25 * (bcm_rx_rate_burst_set/get). 26 * 27 * If a packet is not serviced in interrupt mode, it is queued 28 * based on its COS. 29 * 30 * Each queue has a rate limit (bcm_rx_cos_rate_set/get) which 31 * controls the number of callbacks that will be made for the queue. 32 * The non-interrupt thread services these queues from highest to 33 * lowest and will discard packets in the queue when they exceed 34 * the queue's rate limit. 35 * 36 * Packets handled at interrupt level are still accounted for in 37 * the COS rate limiting. 38 * 39 * A channel is: 40 * Physically: A separate hardware DMA process 41 * Logically: A collection of COS bundled together. 42 * Rate limiting per channel is no longer supported (replaced 43 * by COS queue rate limiting). 44 * 45 * Channels may be enabled and disabled separately from starting RX 46 * running. However, stopping RX disables all channels. 47 * 48 * Packets are started in groups called "chains", each of which 49 * is controlled by a "DV" (DMA-descriptor vector). 50 * 51 * Updates to the handler linked list need to be synchronized 52 * both with thread packet processing (mutex) and interrupt 53 * packet processing (spl). 54 * 55 * If no real callouts are registered (other than internal discard) 56 * don't bother starting DVs, nor queuing input pkts into cos queues. 57 */ 58 59 #include <shared/bsl.h> 60 61 #include <shared/alloc.h> 62 #include <sal/core/libc.h> 63 #include <soc/dma.h> 64 #include <soc/drv.h> 65 #include <soc/higig.h> 66 #include <soc/iproc.h> 67 #if defined(BCM_BRADLEY_SUPPORT) 68 #include <soc/bradley.h> 69 #endif 70 71 #include <bcm_int/common/multicast.h> 72 #include <bcm_int/common/rx.h> 73 74 #ifdef BCM_ESW_SUPPORT 75 #ifdef BCM_OLP_SUPPORT 76 #include <soc/shared/olp_pkt.h> 77 #include <soc/shared/olp_pack.h> 78 #endif /* BCM_OLP_SUPPORT */ 79 #ifdef BCM_XGS3_SWITCH_SUPPORT 80 #include <bcm_int/esw/port.h> 81 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 82 #if defined(INCLUDE_L3) && defined(BCM_XGS3_SWITCH_SUPPORT) 83 #include <bcm_int/esw/firebolt.h> 84 #endif /* INCLUDE_L3 && BCM_XGS3_SWITCH_SUPPORT */ 85 #include <bcm_int/esw/trunk.h> 86 #if defined(INCLUDE_L3) && defined(BCM_TRX_SUPPORT) 87 #include <bcm_int/esw/mpls.h> 88 #include <bcm_int/esw/mim.h> 89 #include <bcm_int/esw/multicast.h> 90 #include <bcm_int/esw/virtual.h> 91 #include <bcm_int/esw/vpn.h> 92 #include <bcm_int/esw/triumph.h> 93 #endif /* INCLUDE_L3 && BCM_TRX_SUPPORT */ 94 #if defined(INCLUDE_RCPU) && defined(BCM_XGS3_SWITCH_SUPPORT) 95 #include <bcm_int/esw/rcpu.h> 96 #endif 97 #ifdef BCM_TRX_SUPPORT 98 #include <bcm_int/esw/trx.h> 99 #endif /* BCM_TRX_SUPPORT */ 100 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 101 #include <bcm_int/esw/trident2plus.h> 102 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 103 #if defined(BCM_TOMAHAWK3_SUPPORT) 104 #include <bcm_int/esw/tomahawk3.h> 105 #endif /* BCM_TOMAHAWK3_SUPPORT */ 106 #if defined(BCM_TOMAHAWK_SUPPORT) 107 #include <bcm_int/esw/tomahawk.h> 108 #endif /* BCM_TOMAHAWK_SUPPORT */ 109 #if defined(BCM_TRIDENT3_SUPPORT) 110 #include <soc/trident3.h> 111 #include <bcm_int/esw/trident3.h> 112 #endif /* BCM_TRIDENT3_SUPPORT */ 113 #if defined(BCM_HELIX5_SUPPORT) 114 #include <bcm_int/esw/helix5.h> 115 #endif /* BCM_HELIX5_SUPPORT */ 116 #endif /* BCM_ESW_SUPPORT */ 117 118 #ifdef BCM_DPP_SUPPORT 119 #include <soc/dpp/PPD/ppd_api_trap_mgmt.h> 120 #include <bcm_int/dpp/utils.h> 121 #include <bcm_int/dpp/rx.h> 122 #include <sal/core/libc.h> 123 #include <sal/appl/io.h> 124 #endif /*BCM_DPP_SUPPORT*/ 125 126 #ifdef BCM_DNX_SUPPORT 127 #include <bcm_int/dnx/rx/rx.h> 128 #include <bcm_int/dnx/algo/port/algo_port_mgmt.h> 129 #include <soc/dnx/dnx_err_recovery_manager_utils.h> 130 #endif 131 132 #include <bcm_int/control.h> 133 #include <bcm/error.h> 134 #include <bcm/rx.h> 135 #include <bcm/stack.h> 136 #include <bcm_int/api_xlate_port.h> 137 138 #ifdef BCM_CMICM_SUPPORT 139 #include <soc/cmicm.h> 140 #endif 141 142 #ifdef BCM_RPC_SUPPORT 143 #include <bcm_int/rpc/rlink.h> 144 #endif 145 146 #ifdef ADAPTER_SERVER_MODE 147 #include <errno.h> 148 #include <unistd.h> 149 #include <stdlib.h> 150 #include <stdio.h> 151 #include <bde/pli/verinet.h> 152 #endif /* ADAPTER_SERVER_MODE */ 153 154 #ifdef BCM_SAND_SUPPORT 155 #define BCM_RX_COS_ARAD (64) 156 #endif 157 158 #if defined(BROADCOM_DEBUG) 159 #define RX_ERROR(message_) LOG_ERROR(BSL_LS_BCM_RX, message_) 160 #define RX_WARN(message_) LOG_WARN(BSL_LS_BCM_RX, message_) 161 #define RX_INFO(message_) LOG_INFO(BSL_LS_BCM_RX, message_) 162 #define RX_VERBOSE(message_) LOG_VERBOSE(BSL_LS_BCM_RX, message_) 163 #define RX_PRINT(message_) bsl_printf message_ 164 #else 165 166 #define RX_ERROR(message_) 167 #define RX_WARN(message_) 168 #define RX_INFO(message_) 169 #define RX_VERBOSE(message_) 170 #define RX_PRINT(message_) 171 #endif /* defined(BROADCOM_DEBUG) */ 172 173 174 /* The main control structure for RX subsystem. */ 175 rx_ctl_t *rx_ctl[BCM_CONTROL_MAX]; 176 int rx_spl; 177 178 rx_control_t rx_control; 179 180 #ifdef ADAPTER_SERVER_MODE 181 int pipe_fds[2]; 182 #endif /* ADAPTER_SERVER_MODE */ 183 184 #if defined(BCM_RPC_SUPPORT) || defined(BCM_RCPU_SUPPORT) 185 /* { */ 186 static int rx_common_spl; 187 #define RX_COMMON_INTR_LOCK rx_common_spl = sal_splhi() 188 #define RX_COMMON_INTR_UNLOCK sal_spl(rx_common_spl) 189 190 bcm_pkt_t *pkt_freelist; 191 /* ONLY modify pktlist_count BEFORE starting RX */ 192 int bcm_rx_pktlist_count = BCM_RX_PKTLIST_COUNT_DEFAULT; 193 194 int 195 bcm_rx_remote_pkt_alloc(int len, bcm_pkt_t **pkt) 196 { 197 uint8 *data; 198 int rv; 199 200 RX_COMMON_INTR_LOCK; 201 if (pkt_freelist != NULL) { 202 *pkt = pkt_freelist; 203 pkt_freelist = (*pkt)->next; 204 } 205 RX_COMMON_INTR_UNLOCK; 206 if (*pkt == NULL) { 207 return BCM_E_MEMORY; 208 } 209 sal_memset(*pkt, 0, sizeof(**pkt)); 210 211 data = NULL; 212 rv = bcm_rx_pool_alloc(-1, len, 0, (void*)&data); 213 if (BCM_E_NONE != rv) { 214 bcm_rx_remote_pkt_free(*pkt); 215 *pkt = NULL; 216 return rv; 217 } 218 BCM_PKT_ONE_BUF_SETUP(*pkt, data, len); 219 (*pkt)->alloc_ptr = data; 220 return BCM_E_NONE; 221 } 222 223 int 224 bcm_rx_remote_pkt_free(bcm_pkt_t *pkt) 225 { 226 if (pkt == NULL) { 227 return BCM_E_INTERNAL; 228 } 229 if (pkt->alloc_ptr != NULL) { 230 bcm_rx_pool_free(-1, pkt->alloc_ptr); 231 pkt->alloc_ptr = NULL; 232 } 233 RX_COMMON_INTR_LOCK; 234 pkt->next = pkt_freelist; 235 pkt_freelist = pkt; 236 RX_COMMON_INTR_UNLOCK; 237 238 return BCM_E_NONE; 239 } 240 /* } */ 241 #endif /* BCM_RPC_SUPPORT */ 242 243 /* Standard BCM transport pointer structure */ 244 bcm_trans_ptr_t bcm_trans_ptr = { 245 bcm_rx_alloc, 246 bcm_rx_free, 247 bcm_pkt_rx_alloc, 248 bcm_pkt_rx_free, 249 bcm_rx_register, 250 bcm_rx_unregister, 251 bcm_tx_pkt_setup, 252 bcm_tx, 253 bcm_tx_list, 254 bcm_tx_array, 255 bcm_tx_pkt_l2_map, /* Not yet fully implemented */ 256 0 /* Default unit for alloc/free */ 257 }; 258 259 #if (defined(BCM_ESW_SUPPORT) || defined (BCM_SAND_SUPPORT)) 260 /* { */ 261 #if defined (BCM_OLP_SUPPORT) 262 /* { */ 263 264 #ifdef BCM_TRIDENT2PLUS_SUPPORT 265 /* { */ 266 #define BCM_PKT_RX_DCB_OLP(pkt,dcb) \ 267 (SOC_DCB_RX_MATCHRULE_GET((pkt)->unit, dcb) == \ 268 rx_ctl[(pkt)->unit]->olp_match_rule) 269 270 #define BCM_PKT_RX_OLP(unit,pkt) \ 271 ((pkt)->rx_matched == rx_ctl[unit]->olp_match_rule) 272 /* } */ 273 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 274 275 #define OLP_HDR_TYPE_MAX 1 276 #define OLP_HDR_STYPE_MAX 0x16 277 278 uint8 olp_oam_hdr_map[OLP_HDR_TYPE_MAX][OLP_HDR_STYPE_MAX] = { 279 { 280 bcmPktRxOamTypeNone, /*0*/ 281 bcmPktRxOamTypeEthOamCcm, 282 bcmPktRxOamTypeEthOamLm, 283 bcmPktRxOamTypeEthOamDm, 284 bcmPktRxOamTypeEthOamOther, 285 bcmPktRxOamTypeBhhOamCcm, /*5*/ 286 bcmPktRxOamTypeBhhOamLm, 287 bcmPktRxOamTypeBhhOamDm, 288 bcmPktRxOamTypeBhhOamOther, 289 bcmPktRxOamTypeBfdOam, /*9*/ 290 bcmPktRxOamTypeRfc6374Dlm, 291 bcmPktRxOamTypeRfc6374Dm, 292 bcmPktRxOamTypeRfc6374DlmPlusDm, 293 bcmPktRxOamTypeRfc6374Ilm, 294 bcmPktRxOamTypeRfc6374IlmPlusDm, /*14*/ 295 bcmPktRxOamTypeSat, /*15*/ 296 bcmPktRxOamTypeOtherAch, 297 298 bcmPktRxOamTypeEthOamUpMepCcm, 299 bcmPktRxOamTypeEthOamUpMepLm, 300 bcmPktRxOamTypeEthOamUpMepDm, 301 bcmPktRxOamTypeEthOamUpMepOther, /*20*/ 302 bcmPktRxOamTypeUpSat, /*21*/ 303 } 304 }; 305 306 #define SOC_OLP_OAM_TYPE_MAP(hdt,hdst) \ 307 (((hdt > OLP_HDR_TYPE_MAX) || (hdst >= OLP_HDR_STYPE_MAX ) || \ 308 (hdt <= 0) || (hdst <= 0)) ? bcmPktRxOamTypeNone : olp_oam_hdr_map[hdt-1][hdst]) 309 310 #if defined (BCM_SABER2_SUPPORT) 311 /* { */ 312 uint8 olp_rx_timestamp_map[] = { 313 BCM_PKT_TIMESTAMP_MODE_NONE, /* None */ 314 BCM_PKT_TIMESTAMP_MODE_NONE, /* LM counter */ 315 BCM_PKT_TIMESTAMP_MODE_PTP, /* DM PTP */ 316 BCM_PKT_TIMESTAMP_MODE_NTP, /* DM NTP */ 317 BCM_PKT_TIMESTAMP_MODE_NTP, /* LM + DM NTP */ 318 BCM_PKT_TIMESTAMP_MODE_PTP, /* LM + DM PTP */ 319 BCM_PKT_TIMESTAMP_MODE_NONE, /* Reserved */ 320 BCM_PKT_TIMESTAMP_MODE_NONE, /* Reserved */ 321 }; 322 #define SB2_SOC_OLP_INVALID_SAMPLE_TYPE(smpl_type) \ 323 (smpl_type > 3) 324 #define SB2_SOC_OLP_INVALID_SAMPLE_EXT_TYPE(smpl_ext_type) \ 325 (smpl_ext_type > 1) 326 327 #define SB2_SOC_OLP_RX_TIMESTAMP_MODE_GET(smpl_type, smpl_ext_type) \ 328 (((SB2_SOC_OLP_INVALID_SAMPLE_TYPE(smpl_type)) || \ 329 (SB2_SOC_OLP_INVALID_SAMPLE_EXT_TYPE(smpl_ext_type)))?\ 330 BCM_PKT_TIMESTAMP_MODE_NONE:\ 331 olp_rx_timestamp_map[smpl_ext_type << 2 | smpl_type]) 332 /* } */ 333 #endif /* BCM_SABER2_SUPPORT */ 334 335 /* } */ 336 #endif /* BCM_OLP_SUPPORT */ 337 338 STATIC int 339 _bcm_rx_default_scheduler(int unit, int *sched_unit, 340 bcm_cos_queue_t *sched_cosq, int *sched_count); 341 342 #define _Q_DEC_TOKENS(q) if ((q)->pps > 0) ((q)->tokens)--; 343 344 /* 345 * This should be called each time a packet is handled, owned, etc. 346 * It counts when all packets for a DV are processed; it 347 * changes the DV state and notifies the thread at that point. 348 */ 349 #define MARK_PKT_PROCESSED(_pkt, unit, chan, dv) \ 350 do { \ 351 if (RX_IS_LOCAL(unit) || RX_IS_RCPU(unit)) { \ 352 MARK_PKT_PROCESSED_LOCAL(unit, chan, dv); \ 353 } else { \ 354 bcm_rx_remote_pkt_free(_pkt); \ 355 } \ 356 } while (0) 357 358 /* 359 * As above, no local checking 360 */ 361 362 #define MARK_PKT_PROCESSED_LOCAL(unit, chan, dv) \ 363 do { \ 364 int pkts_processed; \ 365 RX_INTR_LOCK; \ 366 pkts_processed = ++DV_PKTS_PROCESSED(dv); \ 367 if ((SOC_DMA_MODE(unit) != SOC_DMA_MODE_CONTINUOUS) ) { \ 368 if (pkts_processed == RX_PPC(unit)) { \ 369 DV_STATE(dv) = DV_S_NEEDS_FILL; \ 370 RX_THREAD_NOTIFY(unit); \ 371 } \ 372 } else { \ 373 if ((pkts_processed == RX_PPC(unit)) && \ 374 (DV_STATE(dv) == DV_S_RLD_DONE)) { \ 375 DV_STATE(dv) = DV_S_NEEDS_FILL; \ 376 RX_THREAD_NOTIFY(unit); \ 377 } \ 378 } \ 379 RX_INTR_UNLOCK; \ 380 } while (0) 381 382 #ifndef BCM_RPC_SUPPORT 383 /* { */ 384 #undef MARK_PKT_PROCESSED 385 #define MARK_PKT_PROCESSED(_pkt, unit, chan, dv) \ 386 MARK_PKT_PROCESSED_LOCAL(unit, chan, dv) 387 /* } */ 388 #endif /* BCM_RPC_SUPPORT */ 389 390 /* Sleep .5 seconds when not running. */ 391 #define NON_RUNNING_SLEEP 500000 392 393 static int _rx_chan_run_count; 394 395 int bcm_rx_token_check_us = BCM_RX_TOKEN_CHECK_US_DEFAULT; 396 397 /* Check if given quantity is < cur sleep secs; set to that value if so */ 398 #define BASE_SLEEP_VAL \ 399 ((_rx_chan_run_count > 0) ? bcm_rx_token_check_us : NON_RUNNING_SLEEP) 400 401 /* Set sleep to base value */ 402 #define INIT_SLEEP rx_control.sleep_cur = BASE_SLEEP_VAL 403 404 /* Lower sleep time if val is < current */ 405 #define SLEEP_MIN_SET(val) \ 406 (rx_control.sleep_cur = ((val) < rx_control.sleep_cur) ? \ 407 (val) : rx_control.sleep_cur) 408 409 /* 410 * Boolean: 411 * Is discard the only callout registered? 412 */ 413 #define INTR_CALLOUTS(unit) \ 414 (rx_ctl[unit]->hndlr_intr_cnt != 0) 415 #define NON_INTR_CALLOUTS(unit) \ 416 (rx_ctl[unit]->hndlr_cnt != 0) 417 #define NO_REAL_CALLOUTS(unit) \ 418 (rx_ctl[unit]->hndlr_intr_cnt == 0 && rx_ctl[unit]->hndlr_cnt == 0) 419 420 /* Number of packets allocated for a channel */ 421 #define RX_CHAN_PKT_COUNT(unit, chan) (RX_PPC(unit) * RX_CHAINS(unit, chan)) 422 423 #define RX_DEFAULT_ALLOC bcm_rx_pool_alloc 424 #define RX_DEFAULT_FREE bcm_rx_pool_free 425 426 static int rx_dv_count; /* Debug: count number of DVs used */ 427 428 /* Forward declarations */ 429 STATIC INLINE void rx_done_chain(int unit, dv_t *dv); 430 STATIC INLINE void rx_done_reload(int unit, dv_t *dv); 431 STATIC void rx_pkt_thread(void *param); 432 STATIC int rx_thread_start(int unit); 433 STATIC void rx_process_packet(int unit, bcm_pkt_t *pkt); 434 #ifdef BCM_RCPU_SUPPORT 435 /* { */ 436 STATIC void rx_rcpu_process_packet(int unit, bcm_pkt_t *pkt); 437 /* } */ 438 #endif /* BCM_RCPU_SUPPORT */ 439 STATIC INLINE void rx_intr_process_packet(int unit, dv_t *dv, 440 dcb_t *dcb, bcm_pkt_t *pkt); 441 STATIC bcm_rx_t rx_discard_packet(int unit, bcm_pkt_t *pkt, 442 void *cookie); 443 444 STATIC int rx_channel_dv_setup(int unit, int chan); 445 STATIC void rx_channel_shutdown(int unit, int chan); 446 STATIC void rx_user_cfg_check(int unit); 447 STATIC void rx_dcb_per_pkt_init(int unit); 448 STATIC int rx_discard_handler_setup(int unit, rx_ctl_t *rx_ctrl_ptr); 449 450 static INLINE void rx_dv_fill(int unit, int chan, dv_t *dv); 451 static INLINE dv_t *rx_dv_alloc(int unit, int chan, int dv_idx); 452 STATIC INLINE void rx_dv_dealloc(int unit, int chan, int dv_idx); 453 STATIC int rx_queue_init(int unit, rx_ctl_t *rx_ctrl_ptr); 454 STATIC void rx_queue_cleanup(int unit, rx_ctl_t *rx_ctrl_ptr); 455 456 STATIC void rx_init_all_tokens(int unit); 457 STATIC void rx_cleanup(int unit); 458 459 STATIC void rx_default_parser(int unit, bcm_pkt_t *pkt); 460 STATIC void cmicx_rx_default_parser(int unit, bcm_pkt_t *pkt); 461 462 /* Default data for configuring RX system in cmice/m/d devices */ 463 static bcm_rx_cfg_t _rx_dflt_cfg = { 464 RX_PKT_SIZE_DFLT, /* packet alloc size */ 465 RX_PPC_DFLT, /* Packets per chain */ 466 RX_PPS_DFLT, /* Default pkt rate, global (all COS, one unit) */ 467 0, /* Burst */ 468 { /* Just configure channel 1 */ 469 {0}, /* Channel 0 is usually TX */ 470 { /* Channel 1, default RX */ 471 RX_CHAINS_DFLT, /* DV count (number of chains) */ 472 1000, /* Default pkt rate, DEPRECATED */ 473 0, /* No flags */ 474 0xff /* COS bitmap channel to receive */ 475 } 476 }, 477 RX_DEFAULT_ALLOC, /* alloc function */ 478 RX_DEFAULT_FREE, /* free function */ 479 0 /* flags */ 480 }; 481 482 /* Default data for configuring RX system in cmicx devices */ 483 static bcm_rx_cfg_t _cmicx_rx_dflt_cfg = { 484 RX_PKT_SIZE_DFLT, /* packet alloc size */ 485 RX_CMICX_PPC_DFLT, /* Packets per chain */ 486 RX_PPS_DFLT, /* Default pkt rate, global (all COS, one unit) */ 487 0, /* Burst */ 488 { /* Just configure channel 1 */ 489 {0}, /* Channel 0 is usually TX */ 490 { /* Channel 1, default RX */ 491 RX_CHAINS_DFLT, /* DV count (number of chains) */ 492 1000, /* Default pkt rate, DEPRECATED */ 493 0, /* No flags */ 494 0xff /* COS bitmap channel to receive */ 495 } 496 }, 497 RX_DEFAULT_ALLOC, /* alloc function */ 498 RX_DEFAULT_FREE, /* free function */ 499 0 /* flags */ 500 }; 501 502 #if defined(BCM_RPC_SUPPORT) || defined(BCM_RCPU_SUPPORT) 503 /* { */ 504 static bcm_pkt_t *pktlist_alloc; 505 /* } */ 506 #endif 507 508 /**************************************************************** 509 * 510 * User visible API routines: 511 * bcm_rx_init Init, 512 * bcm_rx_start Setup, 513 * bcm_rx_stop teardown, 514 * bcm_rx_cfg_get get configuration 515 * bcm_rx_cfg_init Reinitial user configuration 516 * bcm_rx_register Register/unregister handlers 517 * bcm_rx_unregister 518 * bcm_rx_queue_register 519 * bcm_rx_queue_unregister 520 * bcm_rx_cosq_mapping_size_get 521 * bcm_rx_cosq_mapping_set 522 * bcm_rx_cosq_mapping_get 523 * bcm_rx_cosq_mapping_delete 524 * bcm_rx_channels_running 525 * bcm_rx_alloc Gateways to packet alloc/free a buffer 526 * bcm_rx_free 527 * bcm_rx_rate_get/set Get/set interrupt load rate limits 528 * bcm_rx_cos_rate_get/set Get/set COS rate limits 529 * bcm_rx_cos_burst_get/set Get/set burst rate limits 530 * bcm_rx_cos_max_len_get/set Get/set max q len limits 531 * 532 * Since we demand doing an RX stop to change some parts of the 533 * configuration (like pkts/chain setting), the DVs must be 534 * aborted and deallocated on stop. 535 */ 536 537 538 /* 539 * Function: 540 * _bcm_rx_ctrl_lock 541 * Purpose: 542 * Lock rx control structures for all units. 543 * Parameters: 544 * None. 545 * Returns: 546 * BCM_E_XXX 547 */ 548 549 STATIC int 550 _bcm_rx_ctrl_lock(void) 551 { 552 int unit; /* Unit iterator. */ 553 554 _BCM_RX_SYSTEM_LOCK; 555 556 for (unit = 0; unit < BCM_CONTROL_MAX; unit++) { 557 /* Skip rx uninitialized units. */ 558 if (!RX_IS_SETUP(unit)) { 559 continue; 560 } 561 RX_LOCK(unit); 562 } 563 return (BCM_E_NONE); 564 } 565 566 /* 567 * Function: 568 * _bcm_rx_ctrl_unlock 569 * Purpose: 570 * Unlock rx control structures for all units. 571 * Parameters: 572 * None. 573 * Returns: 574 * BCM_E_XXX 575 */ 576 577 STATIC int 578 _bcm_rx_ctrl_unlock(void) 579 { 580 int unit; /* Unit iterator. */ 581 582 for (unit = 0; unit < BCM_CONTROL_MAX; unit++) { 583 /* Skip rx uninitialized units. */ 584 if (!RX_IS_SETUP(unit)) { 585 continue; 586 } 587 RX_UNLOCK(unit); 588 } 589 590 _BCM_RX_SYSTEM_UNLOCK; 591 592 return (BCM_E_NONE); 593 } 594 595 /* 596 * Function: 597 * _bcm_rx_unit_list_update 598 * Purpose: 599 * Update list of units with rx started. 600 * Parameters: 601 * None. 602 * Returns: 603 * BCM_E_XXX 604 */ 605 606 STATIC int 607 _bcm_rx_unit_list_update(void) 608 { 609 int unit; /* Unit iterator. */ 610 int prev_unit; /* Last unit with rx initialized. */ 611 int rv = BCM_E_NONE; /* Operation return status. */ 612 613 /* Lock all units rx control structure. */ 614 _bcm_rx_ctrl_lock(); 615 616 /* Reset first unit in the list & max cos queue number. */ 617 rx_control.rx_unit_first = prev_unit = -1; 618 rx_control.system_cosq_max = -1; 619 620 for (unit = 0; unit < BCM_CONTROL_MAX; unit++) { 621 /* Reset next unit on initialized units. */ 622 if (RX_IS_SETUP(unit)) { 623 rx_ctl[unit]->next_unit = -1; 624 } 625 626 /* Skip rx not started units. */ 627 if (!RX_UNIT_STARTED(unit)) { 628 continue; 629 } 630 631 /* Fill rx started units into a linked list .*/ 632 if (-1 == prev_unit) { 633 rx_control.rx_unit_first = unit; 634 } else { 635 rx_ctl[prev_unit]->next_unit = unit; 636 } 637 prev_unit = unit; 638 rx_ctl[unit]->next_unit = -1; 639 640 if (RX_QUEUE_MAX(unit) > rx_control.system_cosq_max) { 641 rx_control.system_cosq_max = RX_QUEUE_MAX(unit); 642 } 643 } 644 645 /* Unlock all units rx control structure. */ 646 _bcm_rx_ctrl_unlock(); 647 return (rv); 648 } 649 650 651 /* 652 * Function: 653 * bcm_common_rx_sched_register 654 * Purpose: 655 * Rx scheduler registration function. 656 * Parameters: 657 * unit - (IN) Unused. 658 * sched_cb - (IN) Rx scheduler routine. 659 * Returns: 660 * BCM_E_XXX 661 */ 662 int 663 _bcm_common_rx_sched_register(int unit, bcm_rx_sched_cb sched_cb) 664 { 665 /* Input parameters check. */ 666 if (NULL == sched_cb) { 667 return (BCM_E_PARAM); 668 } 669 670 _bcm_rx_ctrl_lock(); 671 672 rx_control.rx_sched_cb = sched_cb; 673 674 _bcm_rx_ctrl_unlock(); 675 676 return (BCM_E_NONE); 677 } 678 679 /* 680 * Function: 681 * bcm_common_rx_sched_unregister 682 * Purpose: 683 * Rx scheduler de-registration function. 684 * Parameters: 685 * unit - (IN) Unused. 686 * Returns: 687 * BCM_E_XXX 688 */ 689 int 690 _bcm_common_rx_sched_unregister(int unit) 691 { 692 _bcm_rx_ctrl_lock(); 693 694 rx_control.rx_sched_cb = _BCM_RX_SCHED_DEFAULT_CB; 695 696 _bcm_rx_ctrl_unlock(); 697 return (BCM_E_NONE); 698 } 699 700 /* 701 * Function: 702 * bcm_common_rx_unit_next_get 703 * Purpose: 704 * Rx started units iteration routine. 705 * Parameters: 706 * unit - (IN) BCM device number. 707 * unit_next - (OUT) Next attached unit with started rx. 708 * Returns: 709 * BCM_E_XXX 710 */ 711 int 712 _bcm_common_rx_unit_next_get(int unit, int *unit_next) 713 { 714 /* Input parameters check. */ 715 if (NULL == unit_next) { 716 return (BCM_E_PARAM); 717 } 718 719 if (!RX_IS_SETUP(unit)) { 720 *unit_next = -1; 721 } else { 722 RX_LOCK(unit); 723 if (!RX_UNIT_STARTED(unit)) { 724 *unit_next = -1; 725 } else { 726 *unit_next = rx_ctl[unit]->next_unit; 727 } 728 RX_UNLOCK(unit); 729 } 730 return (BCM_E_NONE); 731 } 732 733 734 /* 735 * Function: 736 * bcm_common_rx_queue_max_get 737 * Purpose: 738 * Get maximum cos queue number for the device. 739 * Parameters: 740 * unit - (IN) BCM device number. 741 * cosq - (OUT) Maximum queue priority. 742 * Returns: 743 * BCM_E_XXX 744 */ 745 int 746 _bcm_common_rx_queue_max_get(int unit, bcm_cos_queue_t *cosq) 747 { 748 /* Input parameters check. */ 749 if (NULL == cosq) { 750 return (BCM_E_PARAM); 751 } 752 753 if (!SOC_UNIT_VALID(unit)) { 754 *cosq = NUM_CPU_COSQ_DEF; 755 } else { 756 757 *cosq = NUM_CPU_COSQ(unit) - 1; 758 } 759 760 return (BCM_E_NONE); 761 } 762 763 /* 764 * Function: 765 * bcm_common_rx_queue_packet_count_get 766 * Purpose: 767 * Get number of packets awaiting processing in the specific device/queue. 768 * Parameters: 769 * unit - (IN) BCM device number. 770 * cosq - (IN) Queue priority. 771 * packet_count - (OUT) Number of packets awaiting processing. 772 * Returns: 773 * BCM_E_XXX 774 */ 775 int 776 _bcm_common_rx_queue_packet_count_get(int unit, bcm_cos_queue_t cosq, int *packet_count) 777 { 778 /* Input parameters check. */ 779 if (NULL == packet_count) { 780 return (BCM_E_PARAM); 781 } 782 783 if (0 == RX_IS_SETUP(unit)) { 784 return (BCM_E_INIT); 785 } 786 787 if (cosq > RX_QUEUE_MAX(unit)) { 788 return (BCM_E_PARAM); 789 } 790 791 RX_LOCK(unit); 792 if (RX_UNIT_STARTED(unit)) { 793 *packet_count = RX_QUEUE(unit, cosq)->count; 794 } else { 795 *packet_count = 0; 796 } 797 RX_UNLOCK(unit); 798 return (BCM_E_NONE); 799 } 800 /* 801 * Function: 802 * bcm_common_rx_queue_rate_limit_status 803 * Purpose: 804 * Get number of packet that can be rx scheduled 805 * until system hits queue rx rate limit. 806 * Parameters: 807 * unit - (IN) BCM device number. 808 * cosq - (IN) Queue priority. 809 * packet_tokens - (OUT)Maximum number of packets that can be scheduled. 810 * Returns: 811 * BCM_E_XXX 812 */ 813 int 814 _bcm_common_rx_queue_rate_limit_status_get(int unit, bcm_cos_queue_t cosq, 815 int *packet_tokens) 816 { 817 /* Input parameters check. */ 818 if (NULL == packet_tokens) { 819 return (BCM_E_PARAM); 820 } 821 822 if (0 == RX_IS_SETUP(unit)) { 823 return (BCM_E_INIT); 824 } 825 826 if (cosq > RX_QUEUE_MAX(unit)) { 827 return (BCM_E_PARAM); 828 } 829 830 RX_LOCK(unit); 831 if (RX_UNIT_STARTED(unit)) { 832 if (RX_QUEUE(unit, cosq)->pps > 0) { 833 *packet_tokens = RX_QUEUE(unit, cosq)->tokens; 834 } else { 835 *packet_tokens = BCM_RX_SCHED_ALL_PACKETS; 836 } 837 } else { 838 /* Don't schedule anything for this device. */ 839 *packet_tokens = 0; 840 } 841 RX_UNLOCK(unit); 842 return (BCM_E_NONE); 843 } 844 845 #ifdef BCM_RPC_SUPPORT 846 /* { */ 847 /* 848 * Function: 849 * _bcm_rx_sl_mode_update 850 * Purpose: 851 * Update packet structures for SL mode 852 * Returns: 853 * BCM_E_XXX 854 * Notes: 855 * Right now, affects all packet structures. This will be a 856 * problem if packets are "on the fly". 857 */ 858 859 int 860 _bcm_rx_sl_mode_update(int unit) { 861 int sl_mode; 862 int i; 863 864 if (unit < 0 || unit >= BCM_CONTROL_MAX) { /* Bad unit number */ 865 return BCM_E_PARAM; 866 } 867 868 if (rx_ctl[unit] == NULL) { /* Init not yet done */ 869 return BCM_E_NONE; 870 } 871 872 sl_mode = (SOC_UNIT_VALID(unit) && SOC_SL_MODE(unit)) 873 && !RX_IGNORE_SL(unit); 874 875 for (i = 0; i < bcm_rx_pktlist_count; i++) { 876 if (sl_mode) { 877 pktlist_alloc[i].flags |= BCM_PKT_F_SLTAG; 878 } else { 879 pktlist_alloc[i].flags &= ~BCM_PKT_F_SLTAG; 880 } 881 } 882 883 return BCM_E_NONE; 884 } 885 /* } */ 886 #endif /* BCM_RPC_SUPPORT */ 887 888 /* 889 * Function: 890 * bcm_rx_init 891 * Purpose: 892 * Software initialization for RX API 893 * Parameters: 894 * unit - Unit to init 895 * Returns: 896 * BCM_E_XXX 897 * Notes: 898 * Allocates rx control structure 899 * Copies default config into active config 900 * Adds discard handler 901 */ 902 903 int 904 _bcm_common_rx_init(int unit) 905 { 906 int rv, i; 907 int chan; 908 rx_ctl_t *rx_ctrl_ptr = NULL; 909 int number_of_packets; 910 911 if (rx_ctl[unit] != NULL) { 912 if (_bcm_common_rx_active(unit)) { 913 if ((rv = _bcm_common_rx_stop(unit, NULL)) < 0) { 914 RX_ERROR((BSL_META_U 915 (unit, "Error in RX Init: RX Stop returned %s\n"), 916 bcm_errmsg(rv))); 917 return rv; 918 } 919 } 920 rx_ctl[unit]->tot_pkts = 0; 921 FOREACH_SETUP_CHANNEL(unit, chan) { 922 RX_CHAN_CTL(unit, chan).rpkt = 0; 923 RX_CHAN_CTL(unit, chan).rbyte = 0; 924 RX_CHAN_CTL(unit, chan).dpkt = 0; 925 RX_CHAN_CTL(unit, chan).dbyte = 0; 926 RX_CHAN_CTL(unit, chan).mem_fail = 0; 927 } 928 for (i = 0; i <= RX_QUEUE_MAX(unit); i++) { 929 RX_QUEUE(unit, i)->tot_pkts = 0; 930 } 931 932 return BCM_E_NONE; 933 } 934 935 #if defined(BCM_RPC_SUPPORT) || defined(BCM_RCPU_SUPPORT) 936 /* { */ 937 if (pktlist_alloc == NULL) { /* Set up remote packet free list */ 938 int i; 939 int len = bcm_rx_pktlist_count * sizeof(bcm_pkt_t); 940 941 pktlist_alloc = sal_alloc(len, "RX pkt list"); 942 if (pktlist_alloc == NULL) { 943 return BCM_E_MEMORY; 944 } 945 sal_memset(pktlist_alloc, 0, len); 946 947 for (i = 0; i < bcm_rx_pktlist_count; i++) { 948 sal_memset(&pktlist_alloc[i], 0, sizeof(bcm_pkt_t)); 949 pktlist_alloc[i].next = &pktlist_alloc[i + 1]; 950 } 951 pktlist_alloc[bcm_rx_pktlist_count - 1].next = NULL; 952 pkt_freelist = pktlist_alloc; 953 } 954 /* } */ 955 #endif 956 957 rx_ctrl_ptr = sal_alloc(sizeof(rx_ctl_t), "rx_ctl"); 958 if (rx_ctrl_ptr == NULL) { 959 return BCM_E_MEMORY; 960 } 961 sal_memset(rx_ctrl_ptr, 0, sizeof(rx_ctl_t)); 962 963 if (soc_feature(unit, soc_feature_cmicx)) { 964 sal_memcpy(&rx_ctrl_ptr->user_cfg, &_cmicx_rx_dflt_cfg, sizeof(bcm_rx_cfg_t)); 965 } else { 966 sal_memcpy(&rx_ctrl_ptr->user_cfg, &_rx_dflt_cfg, sizeof(bcm_rx_cfg_t)); 967 } 968 969 rv = _bcm_common_rx_queue_max_get(unit, &rx_ctrl_ptr->queue_max); 970 if (BCM_FAILURE(rv)) { 971 sal_free(rx_ctrl_ptr); 972 return (rv); 973 } 974 975 if((rx_ctrl_ptr->queue_max+1) > BCM_RX_COS){ 976 sal_free(rx_ctrl_ptr); 977 return BCM_E_INTERNAL; 978 } 979 980 rv = rx_queue_init(unit, rx_ctrl_ptr); 981 if (BCM_FAILURE(rv)) { 982 sal_free(rx_ctrl_ptr); 983 return (rv); 984 } 985 986 /* Set Default Olp Match Rule */ 987 rx_ctrl_ptr->olp_match_rule = BCM_DEFAULT_OLP_MATCH_RULE; 988 989 rx_ctrl_ptr->rx_mutex = sal_mutex_create("RX_MUTEX"); 990 rv = rx_discard_handler_setup(unit, rx_ctrl_ptr); 991 if (BCM_FAILURE(rv)) { 992 sal_mutex_destroy(rx_ctrl_ptr->rx_mutex); 993 rx_queue_cleanup(unit, rx_ctrl_ptr); 994 sal_free(rx_ctrl_ptr); 995 return (rv); 996 } 997 998 if (!bcm_rx_pool_setup_done()) { 999 number_of_packets = soc_property_get(unit, spn_RX_POOL_NOF_PKTS, BCM_RX_POOL_COUNT_DEFAULT); 1000 1001 RX_INFO((BSL_META_U(unit, "RX: Starting rx pool with pkt count %d, packet size %d\n"), 1002 number_of_packets, rx_ctrl_ptr->user_cfg.pkt_size)); 1003 1004 rv = (bcm_rx_pool_setup(number_of_packets, 1005 rx_ctrl_ptr->user_cfg.pkt_size + sizeof(void *))); 1006 if (BCM_FAILURE(rv)) { 1007 sal_free((void *)rx_ctrl_ptr->rc_callout); 1008 sal_mutex_destroy(rx_ctrl_ptr->rx_mutex); 1009 rx_queue_cleanup(unit, rx_ctrl_ptr); 1010 sal_free(rx_ctrl_ptr); 1011 return (rv); 1012 } 1013 } 1014 1015 if (NULL == rx_control.system_lock) { 1016 rx_control.system_lock = sal_mutex_create("RX system lock"); 1017 if (NULL == rx_control.system_lock) { 1018 bcm_rx_pool_cleanup(); 1019 sal_free((void *)rx_ctrl_ptr->rc_callout); 1020 sal_mutex_destroy(rx_ctrl_ptr->rx_mutex); 1021 rx_queue_cleanup(unit, rx_ctrl_ptr); 1022 sal_free(rx_ctrl_ptr); 1023 return (BCM_E_MEMORY); 1024 } 1025 } 1026 1027 if (NULL == rx_control.start_lock) { 1028 rx_control.start_lock = sal_mutex_create("RX start lock"); 1029 if (NULL == rx_control.start_lock) { 1030 bcm_rx_pool_cleanup(); 1031 sal_free((void *)rx_ctrl_ptr->rc_callout); 1032 sal_mutex_destroy(rx_ctrl_ptr->rx_mutex); 1033 sal_mutex_destroy(rx_control.system_lock); 1034 rx_queue_cleanup(unit, rx_ctrl_ptr); 1035 sal_free(rx_ctrl_ptr); 1036 return (BCM_E_MEMORY); 1037 } 1038 } 1039 1040 rx_ctrl_ptr->cpu_port_priorities = soc_property_suffix_num_get(unit, -1, spn_CUSTOM_FEATURE, "cpu_port_priorities", 0); 1041 1042 rx_ctrl_ptr->next_unit = -1; 1043 _BCM_RX_SYSTEM_LOCK; 1044 rx_ctl[unit] = rx_ctrl_ptr; 1045 _BCM_RX_SYSTEM_UNLOCK; 1046 RX_INFO((BSL_META_U(unit, "RX: Initialized unit %d\n"), unit)); 1047 1048 return BCM_E_NONE; 1049 } 1050 1051 /* 1052 * Function: 1053 * _bcm_rx_shutdown 1054 * Purpose: 1055 * Shutdown threads, free up resources without touching 1056 * hardware 1057 * Parameters: 1058 * unit - StrataXGS unit number 1059 * Returns: 1060 * BCM_E_XXX 1061 */ 1062 int _bcm_rx_shutdown(int unit) 1063 { 1064 rx_callout_t *callout_p; 1065 rx_callout_t *next_callout_p; 1066 int i; 1067 1068 if (0 == RX_IS_SETUP(unit)) { 1069 return (BCM_E_NONE); 1070 } 1071 1072 _BCM_RX_START_LOCK; 1073 _BCM_RX_SYSTEM_LOCK; 1074 1075 if (RX_UNIT_STARTED(unit)) 1076 { 1077 int rv; 1078 rv = bcm_rx_stop(unit, NULL); 1079 if (BCM_FAILURE(rv)) { 1080 _BCM_RX_SYSTEM_UNLOCK; 1081 _BCM_RX_START_UNLOCK; 1082 return rv; 1083 } 1084 } 1085 #ifndef PLISIM 1086 rx_cleanup(unit); 1087 #endif 1088 /* 1089 * Check if this is the last unit being detached 1090 */ 1091 for (i = 0; i < BCM_CONTROL_MAX; i++) { 1092 if (i == unit) { 1093 continue; 1094 } else if (rx_ctl[i] != NULL) { 1095 break; 1096 } 1097 } 1098 /* 1099 * This is the last unit. Cleanup rx pool 1100 */ 1101 if (i == BCM_CONTROL_MAX) { 1102 int rv = BCM_E_NONE; 1103 rv = bcm_rx_pool_cleanup(); 1104 if (BCM_FAILURE(rv)) { 1105 if (BCM_E_BUSY == rv) { 1106 RX_WARN((BSL_META_U(unit, "RX pool cleanup failed, " 1107 "still in use. Continuing ...\n"))); 1108 } else { 1109 return rv; 1110 } 1111 } 1112 } 1113 1114 for (callout_p = (void *) (rx_ctl[unit]->rc_callout); callout_p != NULL;) 1115 { 1116 next_callout_p = (void *) callout_p->rco_next; 1117 1118 sal_free(callout_p); 1119 1120 callout_p = next_callout_p; 1121 } 1122 1123 rx_ctl[unit]->rc_callout = NULL; 1124 1125 sal_mutex_destroy(rx_ctl[unit]->rx_mutex); 1126 1127 rx_queue_cleanup(unit, rx_ctl[unit]); 1128 sal_free(rx_ctl[unit]); 1129 rx_ctl[unit] = NULL; 1130 1131 #if defined(BCM_RPC_SUPPORT) || defined(BCM_RCPU_SUPPORT) 1132 /* { */ 1133 if (pktlist_alloc != NULL) { 1134 bcm_pkt_t *pkt, *next_pkt; 1135 1136 pkt = pkt_freelist; 1137 while (pkt != NULL) { 1138 next_pkt = pkt->next; 1139 if (pkt->alloc_ptr != NULL) { 1140 bcm_rx_remote_pkt_free(pkt); 1141 pkt->alloc_ptr = NULL; 1142 } 1143 pkt = next_pkt; 1144 } 1145 sal_free(pktlist_alloc); 1146 pktlist_alloc = NULL; 1147 } 1148 pkt_freelist = NULL; 1149 /* } */ 1150 #endif 1151 1152 1153 rx_control.system_flags |= BCM_RX_CTRL_ACTIVE_UNITS_UPDATE; 1154 1155 _BCM_RX_SYSTEM_UNLOCK; 1156 _BCM_RX_START_UNLOCK; 1157 1158 return BCM_E_NONE; 1159 } 1160 1161 /* 1162 * Function: 1163 * bcm_rx_cfg_init 1164 * Purpose: 1165 * Re-initialize the user level configuration 1166 * Parameters: 1167 * unit - StrataXGS unit number 1168 * Returns: 1169 * BCM_E_XXX 1170 * Notes: 1171 * Can't use if currently running. Should be called before 1172 * doing a simple modification of the RX configuration in case 1173 * the previous user has left it in a strange state. 1174 */ 1175 1176 int 1177 _bcm_common_rx_cfg_init(int unit) 1178 { 1179 RX_INIT_CHECK(unit); 1180 1181 if (RX_UNIT_STARTED(unit)) { 1182 return BCM_E_BUSY; 1183 } 1184 1185 /* 1186 * If unit is not within the permissible limit of 0 to 127, 1187 * then we exit from RX_INIT_CHECK itself. 1188 */ 1189 /* coverity[overrun-local] */ 1190 if (soc_feature(unit, soc_feature_cmicx)) { 1191 sal_memcpy(&rx_ctl[unit]->user_cfg, &_cmicx_rx_dflt_cfg, sizeof(bcm_rx_cfg_t)); 1192 } else { 1193 sal_memcpy(&rx_ctl[unit]->user_cfg, &_rx_dflt_cfg, sizeof(bcm_rx_cfg_t)); 1194 } 1195 1196 return BCM_E_NONE; 1197 } 1198 1199 /* 1200 * Function: 1201 * bcm_rx_start 1202 * Purpose: 1203 * Initialize and configure the RX subsystem for a given unit 1204 * Parameters: 1205 * unit - Unit to configure 1206 * cfg - Configuration to use. See include/bcm/rx.h 1207 * Returns: 1208 * BCM_E_XXX 1209 * Notes: 1210 * Starts the packet receive thread if not already running. 1211 * cfg may be null: Use default config. 1212 * alloc/free in cfg may be null: Use default alloc/free functions 1213 */ 1214 1215 int 1216 _bcm_common_rx_start(int unit, bcm_rx_cfg_t *cfg) 1217 { 1218 1219 int rv = BCM_E_NONE; 1220 int chan; 1221 1222 RX_INIT_CHECK(unit); 1223 1224 if (RX_UNIT_STARTED(unit)) { 1225 RX_INFO((BSL_META_U(unit, "RX start %d: Already started\n"), unit)); 1226 return BCM_E_BUSY; 1227 } 1228 1229 _BCM_RX_START_LOCK; 1230 1231 if (cfg) { /* Use default if config not specified. */ 1232 if ((cfg->pkt_size == 0) || (cfg->pkts_per_chain == 0)) { 1233 _BCM_RX_START_UNLOCK; 1234 return BCM_E_PARAM; 1235 } 1236 sal_memcpy(&rx_ctl[unit]->user_cfg, cfg, sizeof(bcm_rx_cfg_t)); 1237 if (cfg->rx_alloc == NULL) { 1238 rx_ctl[unit]->user_cfg.rx_alloc = RX_DEFAULT_ALLOC; 1239 } 1240 if (cfg->rx_free == NULL) { 1241 rx_ctl[unit]->user_cfg.rx_free = RX_DEFAULT_FREE; 1242 } 1243 rx_user_cfg_check(unit); 1244 } 1245 1246 RX_INFO((BSL_META_U(unit, "RX: Starting unit %d\n"), unit)); 1247 1248 if (rx_ctl[unit]->rx_parser == NULL) { 1249 if (soc_feature(unit, soc_feature_cmicx)) { 1250 RX_INFO((BSL_META_U(unit, "RX: Using cmicx default parser\n"))); 1251 rx_ctl[unit]->rx_parser = cmicx_rx_default_parser; 1252 } else { 1253 rx_ctl[unit]->rx_parser = rx_default_parser; 1254 } 1255 } 1256 1257 #if defined(BCM_RPC_SUPPORT) || defined(BCM_RCPU_SUPPORT) 1258 /* { */ 1259 if (rx_ctl[unit]->user_cfg.rx_alloc != RX_DEFAULT_ALLOC || 1260 rx_ctl[unit]->user_cfg.rx_free != RX_DEFAULT_FREE) { 1261 LOG_WARN(BSL_LS_BCM_RX, 1262 (BSL_META_U(unit, 1263 BSL_META_U 1264 (unit, "RX WARNING: Not using rx_pool alloc/free with %s.\n")), 1265 RX_IS_RCPU(unit)? "RCPU" : "RPC")); 1266 } 1267 /* } */ 1268 #endif 1269 1270 if (RX_IS_LOCAL(unit)) { 1271 rx_dcb_per_pkt_init(unit); 1272 } 1273 1274 rx_init_all_tokens(unit); 1275 rx_ctl[unit]->pkts_since_start = 0; 1276 rx_ctl[unit]->pkts_owned = 0; 1277 1278 if (RX_IS_LOCAL(unit) && SOC_UNIT_VALID(unit)) { 1279 int first_rx_chan = -1; 1280 1281 /* Set up each channel */ 1282 FOREACH_SETUP_CHANNEL(unit, chan) { 1283 rv = rx_channel_dv_setup(unit, chan); 1284 if (rv < 0) { 1285 RX_ERROR((BSL_META_U 1286 (unit, "RX: Error on setup unit %d, chan %d\n"), 1287 unit, chan)); 1288 rx_cleanup(unit); 1289 return rv; 1290 } 1291 1292 rx_ctl[unit]->chan_running |= (1 << chan); 1293 ++_rx_chan_run_count; 1294 /* get the first RX channel */ 1295 if (first_rx_chan == -1) { 1296 first_rx_chan = chan; 1297 } 1298 } 1299 1300 /* 1301 * RX cos based DMA 1302 */ 1303 if (soc_feature(unit, soc_feature_cos_rx_dma) 1304 && first_rx_chan != -1 1305 /* 1306 * nof_rx_chan is only for DNX 1307 * If there is only one rx channel, enable all cosq on this channel 1308 */ 1309 && (!SOC_IS_DNX(unit) || (_rx_chan_run_count == 1)) 1310 ) { 1311 /* enable all cosq on the first Rx channel */ 1312 rv = _bcm_common_rx_queue_channel_set(unit, -1, first_rx_chan); 1313 if (BCM_FAILURE(rv)) { 1314 _BCM_RX_START_UNLOCK; 1315 return rv; 1316 } 1317 if(!soc_feature(unit, soc_feature_cmicm) && 1318 !soc_feature(unit, soc_feature_cmicx)) { 1319 soc_pci_write(unit, CMIC_CONFIG, 1320 (soc_pci_read(unit, CMIC_CONFIG) | 1321 CC_COS_QUALIFIED_DMA_RX_EN)); 1322 } 1323 } 1324 } 1325 1326 RX_INTR_LOCK; 1327 1328 if (!rx_control.thread_running) { 1329 rx_control.rx_unit_first = -1; 1330 rx_control.system_cosq_max = -1; 1331 rx_control.thread_running = TRUE; 1332 RX_INTR_UNLOCK; 1333 /* Start up the thread */ 1334 1335 if ((rv = rx_thread_start(unit)) < 0) { 1336 rx_control.thread_running = FALSE; 1337 rx_cleanup(unit); 1338 _BCM_RX_START_UNLOCK; 1339 return rv; 1340 } 1341 1342 } else { 1343 RX_INTR_UNLOCK; 1344 } 1345 1346 rx_ctl[unit]->flags |= BCM_RX_F_STARTED; 1347 1348 #if defined(INCLUDE_RCPU) && defined(BCM_ESW_SUPPORT) && defined(BCM_XGS3_SWITCH_SUPPORT) 1349 /* { */ 1350 if (RX_IS_RCPU(unit)) { 1351 soc_rcpu_tocpu_cb_register(unit, _bcm_esw_rcpu_tocpu_rx); 1352 } 1353 /* } */ 1354 #endif 1355 /* 1356 * Make sure to update the list after 1357 * new unit was marked active. 1358 */ 1359 _BCM_RX_SYSTEM_LOCK; 1360 rx_control.system_flags |= BCM_RX_CTRL_ACTIVE_UNITS_UPDATE; 1361 _BCM_RX_SYSTEM_UNLOCK; 1362 _BCM_RX_START_UNLOCK; 1363 1364 #if defined(INCLUDE_PTP) 1365 /* { */ 1366 #if defined(BCM_HURRICANE2_SUPPORT) 1367 { 1368 uint32 flags; 1369 /* coverity: unit already initialized */ 1370 /* coverity[overrun-local] */ 1371 bcm_stk_mode_get(unit, &flags); 1372 if (flags == BCM_STK_NONE) { 1373 if (SOC_IS_HURRICANE2(unit) || SOC_IS_GREYHOUND(unit)) { 1374 int i; 1375 int ptp_app = 0; 1376 1377 for (i = 0; i < SOC_CMCS_NUM(unit); i++) { 1378 if (i == SOC_PCI_CMC(unit)) { 1379 /* Skip CPU queue */ 1380 continue; 1381 } 1382 if (NUM_CPU_ARM_COSQ(unit, i)) { 1383 /* uC application exists */ 1384 ptp_app = 1; 1385 break; 1386 } 1387 } 1388 1389 if (ptp_app) { 1390 rv = bcm_field_entry_remove(unit, 0); 1391 if ((rv != BCM_E_NONE) && (rv != BCM_E_NOT_FOUND)) { 1392 return rv; 1393 } 1394 } 1395 } 1396 } 1397 } 1398 #endif /* BCM_HURRICANE2_SUPPORT */ 1399 /* } */ 1400 #endif /* INCLUDE_PTP */ 1401 1402 /* Disable flow control assertion from CMIC to MMU. */ 1403 rv = soc_cpu_flow_ctrl(unit, FALSE); 1404 return rv; 1405 } 1406 1407 /* 1408 * Function: 1409 * bcm_rx_stop 1410 * Purpose: 1411 * Stop RX for the given unit; saves current configuration 1412 * Parameters: 1413 * unit - The unit to stop 1414 * cfg - OUT Configuration copied to this parameter 1415 * Returns: 1416 * BCM_E_XXX 1417 * Notes: 1418 * This signals the thread to exit. 1419 */ 1420 1421 int 1422 _bcm_common_rx_stop(int unit, bcm_rx_cfg_t *cfg) 1423 { 1424 int i; 1425 1426 RX_INIT_CHECK(unit); 1427 1428 _BCM_RX_START_LOCK; 1429 RX_INFO((BSL_META_U(unit, "RX: Stopping unit %d\n"), unit)); 1430 1431 if (cfg != NULL) { /* Save configuration */ 1432 sal_memcpy(cfg, &rx_ctl[unit]->user_cfg, sizeof(bcm_rx_cfg_t)); 1433 } 1434 1435 #if defined(INCLUDE_RCPU) && defined(BCM_ESW_SUPPORT) && defined(BCM_XGS3_SWITCH_SUPPORT) 1436 /* { */ 1437 if (RX_IS_RCPU(unit)) { 1438 soc_rcpu_tocpu_cb_unregister(unit); 1439 } 1440 /* } */ 1441 #endif /* INCLUDE_RCPU */ 1442 1443 /* 1444 * If no units are active, signal thread to stop and wait to 1445 * see it exit; simple semaphore 1446 */ 1447 RX_INTR_LOCK; 1448 for (i = 0; i < BCM_CONTROL_MAX; i++) { 1449 if (!RX_IS_SETUP(i) || i == unit) { 1450 continue; 1451 } 1452 if (rx_ctl[i]->flags & BCM_RX_F_STARTED) { 1453 /* Some other unit is active */ 1454 rx_ctl[unit]->flags &= ~BCM_RX_F_STARTED; 1455 RX_INTR_UNLOCK; 1456 _BCM_RX_SYSTEM_LOCK; 1457 rx_control.system_flags |= BCM_RX_CTRL_ACTIVE_UNITS_UPDATE; 1458 _BCM_RX_SYSTEM_UNLOCK; 1459 _BCM_RX_START_UNLOCK; 1460 #ifdef BCM_SAND_SUPPORT 1461 rx_cleanup(unit); 1462 #endif 1463 return BCM_E_NONE; 1464 } 1465 } 1466 1467 /* Okay, no one else is running. Kill thread */ 1468 if (rx_control.thread_running) { 1469 rx_control.thread_exit_complete = FALSE; 1470 rx_control.thread_running = FALSE; 1471 1472 #ifdef ADAPTER_SERVER_MODE 1473 /* { */ 1474 /* Alert rx thread that it needs to exit */ 1475 if (writen(pipe_fds[1], "x", 1) == -1 && errno != EAGAIN) { 1476 return errno; 1477 } 1478 /* } */ 1479 #endif /* ADAPTER_SERVER_MODE */ 1480 1481 RX_INTR_UNLOCK; 1482 RX_THREAD_NOTIFY(unit); 1483 for (i = 0; i < 10; i++) { 1484 if (rx_control.thread_exit_complete) { 1485 break; 1486 } 1487 /* Sleep a bit to allow thread to stop */ 1488 sal_usleep(500000); 1489 } 1490 if (!rx_control.thread_exit_complete) { 1491 LOG_WARN(BSL_LS_BCM_RX, 1492 (BSL_META_U(unit, 1493 BSL_META_U 1494 (unit, "RX %d: Thread %p running after signaled " 1495 "to stop; \nDVs may not be cleaned up.\n")), 1496 unit, (void *)rx_control.rx_tid)); 1497 } else { 1498 rx_control.rx_tid = NULL; 1499 } 1500 } else { 1501 RX_INTR_UNLOCK; 1502 } 1503 1504 rx_ctl[unit]->flags &= ~BCM_RX_F_STARTED; 1505 _BCM_RX_SYSTEM_LOCK; 1506 rx_control.system_flags |= BCM_RX_CTRL_ACTIVE_UNITS_UPDATE; 1507 _BCM_RX_SYSTEM_UNLOCK; 1508 _BCM_RX_START_UNLOCK; 1509 1510 /* Enable flow control assertion from CMIC to MMU. */ 1511 (void)soc_cpu_flow_ctrl(unit, TRUE); 1512 1513 return BCM_E_NONE; 1514 } 1515 1516 /* 1517 * Function: 1518 * _bcm_common_rx_clear 1519 * Purpose: 1520 * Clear all RX info 1521 * Returns: 1522 * BCM_E_NONE 1523 */ 1524 1525 int 1526 _bcm_common_rx_clear(int unit) 1527 { 1528 for (unit = 0; unit < BCM_CONTROL_MAX; unit++) 1529 { 1530 BCM_IF_ERROR_RETURN(_bcm_rx_shutdown(unit)); 1531 } 1532 1533 return BCM_E_NONE; 1534 } 1535 1536 1537 /* 1538 * Function: 1539 * bcm_rx_cfg_get 1540 * Purpose: 1541 * Check if init done; get the current RX configuration 1542 * Parameters: 1543 * unit - Strata device ID 1544 * cfg - OUT Configuration copied to this parameter. May be NULL 1545 * Returns: 1546 * BCM_E_INIT if not running on unit 1547 * BCM_E_NONE if running on unit 1548 * < 0 BCM_E_XXX error code 1549 * Notes: 1550 */ 1551 1552 int 1553 _bcm_common_rx_cfg_get(int unit, bcm_rx_cfg_t *cfg) 1554 { 1555 RX_INIT_CHECK(unit); 1556 1557 /* Copy config */ 1558 if (cfg != NULL) { 1559 sal_memcpy(cfg, &rx_ctl[unit]->user_cfg, sizeof(bcm_rx_cfg_t)); 1560 } 1561 1562 return (RX_UNIT_STARTED(unit)) ? BCM_E_NONE : BCM_E_INIT; 1563 } 1564 1565 /* Install callback handle */ 1566 static int 1567 _bcm_common_rx_callback_install(int unit, const char * name, rx_callout_t *rco, 1568 uint8 priority, uint32 flags) 1569 { 1570 volatile rx_callout_t *list_rco, *prev_rco; 1571 int i; 1572 1573 RX_LOCK(unit); 1574 RX_INTR_LOCK; 1575 1576 /* Need to double check duplicate callback */ 1577 for (list_rco = rx_ctl[unit]->rc_callout; list_rco; 1578 list_rco = list_rco->rco_next) { 1579 if (list_rco->rco_function == rco->rco_function && 1580 list_rco->rco_priority == rco->rco_priority) { 1581 if (((list_rco->rco_flags & BCM_RCO_F_INTR) == 1582 (rco->rco_flags & BCM_RCO_F_INTR)) && 1583 (list_rco->rco_cookie == rco->rco_cookie)) { 1584 /* get duplicate handle, update cosq */ 1585 for (i = 0; i <= RX_QUEUE_MAX(unit); i++) { 1586 if (SHR_BITGET(rco->rco_cos, i)) { 1587 SHR_BITSET(list_rco->rco_cos, i); 1588 } 1589 } 1590 RX_INTR_UNLOCK; 1591 RX_UNLOCK(unit); 1592 sal_free ((void *)rco); 1593 return BCM_E_NONE; 1594 } 1595 LOG_VERBOSE(BSL_LS_BCM_RX, 1596 (BSL_META_U(unit, 1597 BSL_META_U 1598 (unit, "RX: %s registered with diff params\n")), 1599 name)); 1600 1601 RX_INTR_UNLOCK; 1602 RX_UNLOCK(unit); 1603 sal_free((void *)rco); 1604 return BCM_E_PARAM; 1605 } 1606 } 1607 1608 /* 1609 * Find correct place to insert handler, this code assumes that 1610 * the discard handler has been registered on init. Handlers 1611 * of the same priority are placed in the list in the order 1612 * they are registered 1613 */ 1614 1615 prev_rco = NULL; 1616 for (list_rco = rx_ctl[unit]->rc_callout; list_rco; 1617 list_rco = list_rco->rco_next) { 1618 if (list_rco->rco_priority < priority) { 1619 break; 1620 } 1621 1622 prev_rco = list_rco; 1623 } 1624 1625 if (prev_rco) { /* Insert after prev_rco */ 1626 rco->rco_next = prev_rco->rco_next; 1627 prev_rco->rco_next = rco; 1628 } else { /* Insert first */ 1629 rco->rco_next = list_rco; 1630 rx_ctl[unit]->rc_callout = rco; 1631 } 1632 1633 if (flags & BCM_RCO_F_INTR) { 1634 rx_ctl[unit]->hndlr_intr_cnt++; 1635 } else { 1636 rx_ctl[unit]->hndlr_cnt++; 1637 } 1638 RX_INTR_UNLOCK; 1639 RX_UNLOCK(unit); 1640 1641 LOG_VERBOSE(BSL_LS_BCM_RX, 1642 (BSL_META_U(unit, 1643 BSL_META_U(unit, "RX: %s registered %s%s.\n")), 1644 name, 1645 prev_rco ? "after " : "first", 1646 prev_rco ? prev_rco->rco_name : "")); 1647 return BCM_E_NONE; 1648 } 1649 1650 /* 1651 * Function: 1652 * bcm_rx_queue_register 1653 * Purpose: 1654 * Register an application callback for the specified CPU queue 1655 * Parameters: 1656 * unit - StrataSwitch unit number. 1657 * name - constant character string for debug purposes. 1658 * cosq - CPU cos queue 1659 * callback - callback function pointer. 1660 * priority - priority of handler in list (0 is lowest priority). 1661 * cookie - cookie passed to driver when packet arrives. 1662 * flags - Register for interrupt or non-interrupt callback 1663 * Returns: 1664 * BCM_E_NONE - callout registered. 1665 * BCM_E_MEMORY - memory allocation failed. 1666 */ 1667 1668 int 1669 _bcm_common_rx_queue_register(int unit, const char *name, bcm_cos_queue_t cosq, 1670 bcm_rx_cb_f callback, uint8 priority, void *cookie, 1671 uint32 flags) 1672 { 1673 volatile rx_callout_t *rco; 1674 volatile rx_callout_t *list_rco; 1675 int i; 1676 1677 /* 1678 * If the caller wants to use the same callback function for different 1679 * queues, they have to call multiple times. Note that in the driver, 1680 * we keep track of the queues using a bitmap so that only one RCO entry 1681 * is needed for each callback. 1682 */ 1683 if (callback == NULL) { 1684 return BCM_E_PARAM; 1685 } 1686 1687 /* Check unit */ 1688 RX_INIT_CHECK(unit); 1689 1690 /* Check cosq number */ 1691 if ((cosq != BCM_RX_COS_ALL) && 1692 (cosq < 0 || cosq > RX_QUEUE_MAX(unit))) { 1693 return BCM_E_PARAM; 1694 } 1695 1696 RX_INFO((BSL_META_U 1697 (unit, "RX: Registering %s on %d, cosq 0x%x flags 0x%x%s\n"), 1698 name, unit, cosq, flags, flags & BCM_RCO_F_INTR ? "(intr)" : "")); 1699 1700 #if defined(BCM_RPC_SUPPORT) 1701 /* { */ 1702 if (RX_IS_REMOTE(unit) && !RX_IS_RCPU(unit)) { 1703 int rv; 1704 1705 /* Always try to set up tunnel connection; multiple connects okay. */ 1706 rv = bcm_rlink_rx_connect(unit); 1707 if (rv < 0) { 1708 LOG_WARN(BSL_LS_BCM_RX, 1709 (BSL_META_U(unit, 1710 BSL_META_U 1711 (unit, "RX: rlink connect unit %d returned %d: %s\n")), 1712 unit, rv, bcm_errmsg(rv))); 1713 } 1714 } 1715 /* } */ 1716 #endif 1717 /* 1718 * In the case of re-installing a callback with the same priority, 1719 * unlike _bcm_common_rx_register(), this API will just update the cosq 1720 * bitmap for the callback if other parameters are the same. This allows 1721 * multiple cosq to be added to same callback via calling 1722 * _bcm_common_rx_queue_register() multiple times. 1723 */ 1724 1725 RX_LOCK(unit); 1726 RX_INTR_LOCK; 1727 for (list_rco = rx_ctl[unit]->rc_callout; list_rco; 1728 list_rco = list_rco->rco_next) { 1729 uint32 flag_int = flags & BCM_RCO_F_INTR; 1730 1731 if (list_rco->rco_function == callback && 1732 list_rco->rco_priority == priority) { 1733 if ((list_rco->rco_flags & BCM_RCO_F_INTR) == flag_int && 1734 list_rco->rco_cookie == cookie) { 1735 if (cosq == BCM_RX_COS_ALL) { 1736 for (i = 0; i <= RX_QUEUE_MAX(unit); i++) { 1737 SHR_BITSET(list_rco->rco_cos, i); 1738 } 1739 } else { 1740 SHR_BITSET(list_rco->rco_cos, cosq); 1741 1742 /* Support legacy cosq input via flags */ 1743 if (flags & BCM_RCO_F_ALL_COS) { 1744 for (i = 0; i <= RX_QUEUE_MAX(unit); i++) { 1745 SHR_BITSET(list_rco->rco_cos, i); 1746 } 1747 } else { 1748 for (i = 0; i < 16; i++) { 1749 if ((flags & BCM_RCO_F_COS_ACCEPT_MASK) & 1750 BCM_RCO_F_COS_ACCEPT(i)) { 1751 SHR_BITSET(list_rco->rco_cos, i); 1752 } 1753 } 1754 } 1755 } 1756 1757 RX_INTR_UNLOCK; 1758 RX_UNLOCK(unit); 1759 return BCM_E_NONE; 1760 } 1761 LOG_VERBOSE(BSL_LS_BCM_RX, 1762 (BSL_META_U(unit, 1763 BSL_META_U 1764 (unit, "RX: %s registered with diff params\n")), 1765 name)); 1766 1767 RX_INTR_UNLOCK; 1768 RX_UNLOCK(unit); 1769 return BCM_E_PARAM; 1770 } 1771 } 1772 1773 RX_INTR_UNLOCK; 1774 RX_UNLOCK(unit); 1775 1776 /* Alloc a callback struct */ 1777 if ((rco = sal_alloc(sizeof(*rco), "rx_callout")) == NULL) { 1778 return(BCM_E_MEMORY); 1779 } 1780 1781 /* Init the callback struct */ 1782 SETUP_RCO(rco, name, callback, priority, cookie, NULL, flags); 1783 1784 if (cosq == BCM_RX_COS_ALL) { 1785 for (i = 0; i <= RX_QUEUE_MAX(unit); i++) { 1786 SHR_BITSET(rco->rco_cos, i); 1787 } 1788 } else { 1789 SHR_BITSET(rco->rco_cos, cosq); 1790 1791 /* Support legacy cosq input via flags */ 1792 if (flags & BCM_RCO_F_ALL_COS) { 1793 for (i = 0; i <= RX_QUEUE_MAX(unit); i++) { 1794 SHR_BITSET(rco->rco_cos, i); 1795 } 1796 } else { 1797 for (i = 0; i < 16; i++) { 1798 if ((flags & BCM_RCO_F_COS_ACCEPT_MASK) & 1799 BCM_RCO_F_COS_ACCEPT(i)) { 1800 SHR_BITSET(rco->rco_cos, i); 1801 } 1802 } 1803 } 1804 } 1805 1806 return _bcm_common_rx_callback_install(unit, name, (rx_callout_t *)rco, 1807 priority, flags); 1808 } 1809 1810 /* 1811 * Function: 1812 * bcm_rx_register 1813 * Purpose: 1814 * Register an upper layer driver 1815 * Parameters: 1816 * unit - StrataSwitch unit number. 1817 * chan - DMA channel number 1818 * name - constant character string for debug purposes. 1819 * priority - priority of handler in list (0 is lowest priority). 1820 * f - function to call for that driver. 1821 * cookie - cookie passed to driver when packet arrives. 1822 * flags - Register for interrupt or non-interrupt callback 1823 * Returns: 1824 * BCM_E_NONE - callout registered. 1825 * BCM_E_MEMORY - memory allocation failed. 1826 * Notes: 1827 * Refer bcm_rx_queue_register() if cosq is bigger than 16. 1828 */ 1829 1830 int 1831 _bcm_common_rx_register(int unit, const char *name, bcm_rx_cb_f callback, 1832 uint8 priority, void *cookie, uint32 flags) 1833 { 1834 volatile rx_callout_t *rco, *list_rco; 1835 int i; 1836 1837 RX_INIT_CHECK(unit); 1838 1839 if (NULL == callback) { 1840 return BCM_E_PARAM; 1841 } 1842 1843 RX_INFO((BSL_META_U 1844 (unit, "RX: Registering %s on %d, flags 0x%x%s\n"), 1845 name, unit, flags, flags & BCM_RCO_F_INTR ? "(intr)" : "")); 1846 1847 if (!(flags & BCM_RCO_F_COS_ACCEPT_MASK) && 1848 !(flags & BCM_RCO_F_ALL_COS)) { 1849 LOG_WARN(BSL_LS_BCM_RX, 1850 (BSL_META_U(unit, 1851 BSL_META_U 1852 (unit, 1853 "RX unit %d: Registering callback with no COS accepted.\n")), 1854 unit)); 1855 LOG_WARN(BSL_LS_BCM_RX, 1856 (BSL_META_U(unit, 1857 BSL_META_U(unit, " Callbacks will not occur to %s\n")), 1858 name)); 1859 } 1860 1861 #if defined(BCM_RPC_SUPPORT) 1862 /* { */ 1863 if (RX_IS_REMOTE(unit) && !RX_IS_RCPU(unit)) { 1864 int rv; 1865 1866 /* Always try to set up tunnel connection; multiple connects okay. */ 1867 rv = bcm_rlink_rx_connect(unit); 1868 if (rv < 0) { 1869 LOG_WARN(BSL_LS_BCM_RX, 1870 (BSL_META_U(unit, 1871 BSL_META_U 1872 (unit, "RX: rlink connect unit %d returned %d: %s\n")), 1873 unit, rv, bcm_errmsg(rv))); 1874 } 1875 } 1876 /* } */ 1877 #endif 1878 1879 RX_LOCK(unit); 1880 RX_INTR_LOCK; 1881 /* First check if already registered */ 1882 for (list_rco = rx_ctl[unit]->rc_callout; list_rco; 1883 list_rco = list_rco->rco_next) { 1884 if (list_rco->rco_function == callback && 1885 list_rco->rco_priority == priority) { 1886 if (list_rco->rco_flags == flags && 1887 list_rco->rco_cookie == cookie) { 1888 RX_INTR_UNLOCK; 1889 RX_UNLOCK(unit); 1890 return BCM_E_NONE; 1891 } 1892 LOG_VERBOSE(BSL_LS_BCM_RX, 1893 (BSL_META_U(unit, 1894 BSL_META_U 1895 (unit, "RX: %s registered with diff params\n")), 1896 name)); 1897 1898 RX_INTR_UNLOCK; 1899 RX_UNLOCK(unit); 1900 return BCM_E_PARAM; 1901 } 1902 } 1903 1904 RX_INTR_UNLOCK; 1905 RX_UNLOCK(unit); 1906 1907 if ((rco = sal_alloc(sizeof(*rco), "rx_callout")) == NULL) { 1908 return(BCM_E_MEMORY); 1909 } 1910 SETUP_RCO(rco, name, callback, priority, cookie, NULL, flags); 1911 /* Older implementation used only rco_flags field to carry 1912 * cos information. Since there are now devices which support > 32 1913 * cos queues, rco_cos bitmap has been added. Add the specified 1914 * cos to rco_cos here. 1915 */ 1916 if (flags & BCM_RCO_F_ALL_COS) { 1917 for (i = 0; i <= RX_QUEUE_MAX(unit); i++) { 1918 SETUP_RCO_COS_SET(rco, i); 1919 } 1920 } else { 1921 for (i = 0; i < 16; i++) { 1922 if ((flags & BCM_RCO_F_COS_ACCEPT_MASK) & BCM_RCO_F_COS_ACCEPT(i)) { 1923 SETUP_RCO_COS_SET(rco, i); 1924 } 1925 } 1926 } 1927 1928 return _bcm_common_rx_callback_install(unit, name, (rx_callout_t *)rco, 1929 priority, flags); 1930 } 1931 1932 /* Common function for bcm_rx_unregister and bcm_rx_queue_unregister */ 1933 static int 1934 _bcm_common_rx_callback_unregister(int unit, bcm_rx_cb_f callback, 1935 uint8 priority, bcm_cos_queue_t cosq) 1936 { 1937 volatile rx_callout_t *rco; 1938 volatile rx_callout_t *prev_rco = NULL; 1939 #if defined(BROADCOM_DEBUG) 1940 /* { */ 1941 const char *name; 1942 /* } */ 1943 #endif 1944 uint32 flags; 1945 int i; 1946 1947 RX_INIT_CHECK(unit); 1948 1949 if ((cosq != BCM_RX_COS_ALL) && 1950 (cosq < 0 || cosq > RX_QUEUE_MAX(unit))) { 1951 return BCM_E_PARAM; 1952 } 1953 1954 RX_LOCK(unit); 1955 RX_INTR_LOCK; 1956 for (rco = rx_ctl[unit]->rc_callout; rco; rco = rco->rco_next) { 1957 if (rco->rco_function == callback && rco->rco_priority == priority) { 1958 break; 1959 } 1960 prev_rco = rco; 1961 } 1962 1963 if (!rco) { 1964 RX_INTR_UNLOCK; 1965 RX_UNLOCK(unit); 1966 return BCM_E_NOT_FOUND; 1967 } 1968 1969 if (cosq != BCM_RX_COS_ALL) { 1970 SHR_BITCLR(rco->rco_cos, cosq); 1971 for (i = 0; i <= RX_QUEUE_MAX(unit); i++) { 1972 if (SHR_BITGET(rco->rco_cos, i)) { 1973 /* Don't delete callback if any cosq still associated */ 1974 RX_INTR_UNLOCK; 1975 RX_UNLOCK(unit); 1976 return BCM_E_NONE; 1977 } 1978 } 1979 } 1980 #if defined(BROADCOM_DEBUG) 1981 /* { */ 1982 name = rco->rco_name; 1983 /* } */ 1984 #endif 1985 flags = rco->rco_flags; 1986 1987 if (!prev_rco) { /* First elt on list */ 1988 rx_ctl[unit]->rc_callout = rco->rco_next; 1989 } else { /* skip current */ 1990 prev_rco->rco_next = rco->rco_next; 1991 } 1992 1993 if (flags & BCM_RCO_F_INTR) { 1994 rx_ctl[unit]->hndlr_intr_cnt--; 1995 } else { 1996 rx_ctl[unit]->hndlr_cnt--; 1997 } 1998 RX_INTR_UNLOCK; 1999 RX_UNLOCK(unit); 2000 2001 #if defined(BCM_RPC_SUPPORT) 2002 /* { */ 2003 if (RX_IS_REMOTE(unit) && !RX_IS_RCPU(unit)) { 2004 /* Check if time to unregister */ 2005 int rv; 2006 2007 if (rx_ctl[unit]->rc_callout == NULL) { /* No callouts, disconnect */ 2008 rv = bcm_rlink_rx_disconnect(unit); 2009 if (rv < 0) { 2010 LOG_WARN(BSL_LS_BCM_RX, 2011 (BSL_META_U(unit, 2012 BSL_META_U 2013 (unit, 2014 "RX: rlink disconnect unit %d returned %d: %s\n")), 2015 unit, rv, bcm_errmsg(rv))); 2016 } 2017 } 2018 } 2019 /* } */ 2020 #endif 2021 2022 RX_INFO((BSL_META_U(unit, "RX: Unregistered %s on %d\n"), name, unit)); 2023 sal_free((void *)rco); 2024 2025 return BCM_E_NONE; 2026 } 2027 2028 /* 2029 * Function: 2030 * bcm_rx_unregister 2031 * Purpose: 2032 * De-register a callback function 2033 * Parameters: 2034 * unit - Unit reference 2035 * priority - Priority of registered callback 2036 * callback - The function being registered 2037 * Returns: 2038 * BCM_E_XXX 2039 * Notes: 2040 * Run through linked list looking for match of function and priority 2041 */ 2042 2043 int 2044 _bcm_common_rx_unregister(int unit, bcm_rx_cb_f callback, uint8 priority) 2045 { 2046 return _bcm_common_rx_callback_unregister(unit, callback, priority, 2047 BCM_RX_COS_ALL); 2048 } 2049 2050 /* 2051 * Function: 2052 * bcm_rx_queue_unregister 2053 * Purpose: 2054 * Unregister a callback function 2055 * Parameters: 2056 * unit - Unit reference 2057 * cosq - CPU cos queue 2058 * priority - Priority of registered callback 2059 * callback - The function being registered 2060 * Returns: 2061 * BCM_E_XXX 2062 */ 2063 2064 int 2065 _bcm_common_rx_queue_unregister(int unit, bcm_cos_queue_t cosq, 2066 bcm_rx_cb_f callback, uint8 priority) 2067 { 2068 return _bcm_common_rx_callback_unregister (unit, callback, priority, cosq); 2069 } 2070 2071 /* 2072 * Function: 2073 * bcm_rx_reasons_get 2074 * Purpose: 2075 * Get all supported reasons for rx packets 2076 * Parameters: 2077 * unit - Unit reference 2078 * reasons - rx packet "reasons" bitmap 2079 * Returns: 2080 * BCM_E_XXX 2081 */ 2082 int 2083 _bcm_common_rx_reasons_get(int unit, bcm_rx_reasons_t *reasons) 2084 { 2085 uint32 ix; 2086 uint32 max_index = 32; 2087 soc_rx_reason_t *map; 2088 soc_rx_reason_t **map_array; 2089 int maps_index = 0; 2090 2091 if (!SOC_UNIT_VALID(unit)) { 2092 2093 return BCM_E_INTERNAL; 2094 } 2095 2096 BCM_RX_REASON_CLEAR_ALL(*reasons); 2097 2098 if (soc_feature(unit, soc_feature_dcb_reason_hi)) { 2099 max_index = 64; 2100 } 2101 2102 map_array = SOC_DCB_RX_REASON_MAPS(unit); 2103 while ((map = map_array[maps_index++]) != NULL) { 2104 for (ix = 0; ix < max_index ; ix++) { 2105 /* coverity [mixed_enums] */ 2106 if ((map[ix] >= (soc_rx_reason_t)socRxReasonInvalid) && 2107 (map[ix] <= (soc_rx_reason_t)socRxReasonCount)) { 2108 BCM_RX_REASON_SET(*reasons, (bcm_rx_reason_t)map[ix]); 2109 } 2110 } 2111 } 2112 2113 #ifdef BCM_XGS3_SWITCH_SUPPORT 2114 /* { */ 2115 if (SOC_IS_XGS3_SWITCH(unit)) { 2116 /* BPDU is a separate bit in the DCB, so it is pasted in */ 2117 BCM_RX_REASON_SET(*reasons, bcmRxReasonBpdu); 2118 } 2119 /* } */ 2120 #endif 2121 return BCM_E_NONE; 2122 } 2123 2124 /* 2125 * Function: 2126 * _bcm_common_rx_queue_channel_set_helper 2127 * Purpose: 2128 * Helper function to program CMIC. 2129 * Refactored the code to put common code 2130 * in a single function. 2131 * Parameters: 2132 * unit - Unit reference 2133 * queue_id - CPU cos queue index (0 - (max cosq - 1)) 2134 * doesn't handle queue_id -1 2135 * chan_id - channel index (0 - (BCM_RX_CHANNELS-1)) 2136 * doesn't handle chan_id -1 2137 * cmc - cmc number 2138 * Returns: 2139 * BCM_E_XXX 2140 */ 2141 int 2142 _bcm_common_rx_queue_channel_set_helper(int unit, bcm_cos_queue_t queue_id, 2143 bcm_rx_chan_t chan_id, 2144 int cmc) 2145 { 2146 #ifdef BCM_CMICM_SUPPORT 2147 /* { */ 2148 uint32 ix; 2149 int endq; 2150 int start_chan_id; 2151 int startq = 0; 2152 uint32 chan_off; 2153 int pci_cmc = SOC_PCI_CMC(unit); 2154 uint32 reg_addr, reg_val; 2155 2156 if (cmc != pci_cmc) { 2157 /* compute start queue number for any CMC */ 2158 startq = NUM_CPU_ARM_COSQ(unit, pci_cmc); 2159 for (ix = 0; ix < cmc; ix++) { 2160 startq += (ix != pci_cmc) ? NUM_CPU_ARM_COSQ(unit, ix) : 0; 2161 } 2162 } 2163 2164 start_chan_id = (cmc != pci_cmc) ? cmc * BCM_RX_CHANNELS : 0; 2165 2166 endq = startq + NUM_CPU_ARM_COSQ(unit, cmc); 2167 if (queue_id < startq || queue_id >= endq) { 2168 return BCM_E_PARAM; 2169 } 2170 2171 if (!SHR_BITGET(CPU_ARM_QUEUE_BITMAP(unit, cmc), queue_id)) { 2172 return BCM_E_PARAM; 2173 } 2174 2175 for (ix = start_chan_id; 2176 ix < (start_chan_id + BCM_RX_CHANNELS); ix++) { 2177 chan_off = ix % BCM_RX_CHANNELS; 2178 if (!SOC_IS_TD2P_TT2P(unit)) { 2179 reg_addr = (queue_id < 32) ? 2180 CMIC_CMCx_CHy_COS_CTRL_RX_0_OFFSET(cmc, chan_off) : 2181 CMIC_CMCx_CHy_COS_CTRL_RX_1_OFFSET(cmc, chan_off); 2182 reg_val = soc_pci_read(unit, reg_addr); 2183 2184 if (ix == (uint32)chan_id) { 2185 reg_val |= ((uint32)1 << (queue_id % 32)); 2186 } else { /* Clear for all other channels */ 2187 reg_val &= ~((uint32)1 << (queue_id % 32)); 2188 } 2189 /* Incoporate the reserved queues (if any on this device) 2190 * into the CMIC programming, */ 2191 reg_val |= 2192 CPU_ARM_RSVD_QUEUE_BITMAP(unit,cmc)[queue_id / 32]; 2193 soc_pci_write(unit, reg_addr, reg_val); 2194 } 2195 else { 2196 reg_addr = (queue_id < 32) ? 2197 CMIC_CMCx_CHy_COS_CTRL_RX_0_OFFSET(cmc, chan_off) : 2198 CMIC_CMCx_CHy_COS_CTRL_RX_1_OFFSET(cmc, chan_off); 2199 reg_val = soc_pci_read(unit, reg_addr); 2200 2201 if (ix == (uint32)chan_id) { 2202 reg_val |= ((uint32)1 << (queue_id % 32)); 2203 } else { /* Clear for all other channels */ 2204 reg_val &= ~((uint32)1 << (queue_id % 32)); 2205 } 2206 soc_pci_write(unit, reg_addr, reg_val); 2207 2208 reg_addr = CMIC_CMCx_CHy_COS_CTRL_RX_1_OFFSET(cmc, chan_off); 2209 reg_val = soc_pci_read(unit, reg_addr); 2210 if (ix == (uint32)chan_id) { 2211 reg_val |= 2212 CPU_ARM_RSVD_QUEUE_BITMAP(unit,cmc)[1]; 2213 } else { /* Clear for all other channels */ 2214 reg_val &= 2215 ~(CPU_ARM_RSVD_QUEUE_BITMAP(unit,cmc)[1]); 2216 } 2217 soc_pci_write(unit, reg_addr, reg_val); 2218 } 2219 } 2220 2221 #if defined(BCM_KATANA_SUPPORT) 2222 /* { */ 2223 if (SOC_IS_KATANAX(unit)) { 2224 /* 2225 * Katana queues have been disabled to prevent packets 2226 * that cannot egress from reaching the CMIC. At this 2227 * point those queues can be enabled. 2228 */ 2229 reg_val = 0; 2230 soc_reg_field_set(unit, THDO_QUEUE_DISABLE_CFG2r, ®_val, 2231 QUEUE_NUMf, queue_id); 2232 SOC_IF_ERROR_RETURN( 2233 WRITE_THDO_QUEUE_DISABLE_CFG2r(unit, reg_val)); 2234 reg_val = 0; 2235 soc_reg_field_set(unit, THDO_QUEUE_DISABLE_CFG1r, ®_val, 2236 QUEUE_WRf, 1); 2237 SOC_IF_ERROR_RETURN( 2238 WRITE_THDO_QUEUE_DISABLE_CFG1r(unit, reg_val)); 2239 } 2240 /* } */ 2241 #endif /*BCM_KATANA_SUPPORT */ 2242 /* } */ 2243 #endif /* CMICM Support */ 2244 return BCM_E_NONE; 2245 } 2246 2247 /* 2248 * Function: 2249 * bcm_rx_queue_channel_set 2250 * Purpose: 2251 * Assign a RX channel to a cosq 2252 * Parameters: 2253 * unit - Unit reference 2254 * queue_id - CPU cos queue index (0 - (max cosq - 1)) 2255 * (Negative for all) 2256 * chan_id - channel index (0 - (BCM_RX_CHANNELS-1)), -1 for no channel 2257 * Returns: 2258 * BCM_E_XXX 2259 */ 2260 int 2261 _bcm_common_rx_queue_channel_set(int unit, bcm_cos_queue_t queue_id, 2262 bcm_rx_chan_t chan_id) 2263 { 2264 uint32 ix, bit; 2265 uint32 chan_id_max = BCM_RX_CHANNELS; 2266 uint32 reg_index,reg_base, reg_addr, reg_val; 2267 #if defined(BCM_CMICM_SUPPORT) 2268 /* { */ 2269 uint32 chan_off; 2270 int numq, endq, countq; 2271 int start_chan_id; 2272 #endif 2273 #if defined(BCM_CMICM_SUPPORT) || defined(BCM_CMICX_SUPPORT) 2274 int cmc; 2275 int pci_cmc = SOC_PCI_CMC(unit); 2276 int startq = 0; 2277 #ifdef BCM_KATANA_SUPPORT 2278 /* { */ 2279 uint32 i = 0; 2280 /* } */ 2281 #endif 2282 2283 soc_dma_max_rx_channels_get(unit, &chan_id_max); 2284 2285 if (0 != SOC_CMCS_NUM(unit)) { 2286 chan_id_max *= SOC_CMCS_NUM(unit); 2287 } 2288 /* } */ 2289 #endif 2290 2291 if (SOC_WARM_BOOT(unit)) { 2292 return BCM_E_NONE; 2293 } 2294 if (!soc_feature(unit, soc_feature_cos_rx_dma)) { 2295 /* not DMA set up */ 2296 return BCM_E_CONFIG; 2297 } else if (-1 == chan_id) { 2298 if (-1 == queue_id) { 2299 /* May not disable all queues */ 2300 return BCM_E_PARAM; 2301 } else if (soc_feature(unit, soc_feature_cmicm)) { 2302 /* May not disable queues on CMICm devices */ 2303 return BCM_E_PARAM; 2304 } else if (soc_feature(unit, soc_feature_cmicx)) { 2305 /* May not disable queues on CMICx devices */ 2306 return BCM_E_PARAM; 2307 } /* Else, OK to disable queue */ 2308 } else if ((chan_id < 0) || (chan_id >= chan_id_max)) { 2309 /* Verify the chan id */ 2310 return BCM_E_PARAM; 2311 } else if (queue_id >= NUM_CPU_COSQ(unit)) { 2312 return BCM_E_PARAM; 2313 } 2314 2315 #ifdef BCM_CMICM_SUPPORT /* For now, we also have to support CMICe */ 2316 /* { */ 2317 if(soc_feature(unit, soc_feature_cmicm)) { 2318 /* We institute the normalizing assumption that the 2319 * channels are numbered first in the PCI CMC, then in order of the 2320 * ARM CMCs. This is why we have the shuffling steps below. 2321 */ 2322 if (chan_id < BCM_RX_CHANNELS) { 2323 cmc = pci_cmc; 2324 } else { 2325 cmc = SOC_ARM_CMC(unit, ((chan_id / BCM_RX_CHANNELS) - 1)); 2326 /* compute start queue number for any CMC */ 2327 startq = NUM_CPU_ARM_COSQ(unit, pci_cmc); 2328 for (ix = 0; ix < cmc; ix++) { 2329 startq += (ix != pci_cmc) ? NUM_CPU_ARM_COSQ(unit, ix) : 0; 2330 } 2331 } 2332 2333 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 2334 /* { */ 2335 /* Only for host CPU PCI CMC. 2336 * Only if custom LLS hierarchy is being built 2337 * Only for Trident2Plus */ 2338 if (SOC_IS_TD2P_TT2P(unit) && 2339 bcm_td2p_cosq_ets_mode(unit) && 2340 (cmc == pci_cmc)) { 2341 BCM_IF_ERROR_RETURN(bcm_td2p_rx_queue_channel_set(unit, queue_id, chan_id)); 2342 } 2343 else 2344 /* } */ 2345 #endif 2346 #if defined(BCM_TOMAHAWK_SUPPORT) 2347 /* { */ 2348 /* Only for host CPU PCI CMC. 2349 * Only for Tomahawk */ 2350 if (SOC_IS_TOMAHAWKX(unit) && 2351 (cmc == pci_cmc)) { 2352 BCM_IF_ERROR_RETURN(bcm_th_rx_queue_channel_set_test(unit, 2353 queue_id, chan_id)); 2354 } 2355 else 2356 /* } */ 2357 #endif 2358 { 2359 numq = NUM_CPU_ARM_COSQ(unit, cmc); 2360 start_chan_id = (cmc != pci_cmc) ? cmc * BCM_RX_CHANNELS : 0; 2361 2362 if (queue_id < 0) { /* All COS Queues */ 2363 /* validate the queue range of CMC is in the valid range 2364 * for this CMC 2365 */ 2366 SHR_BITCOUNT_RANGE(CPU_ARM_QUEUE_BITMAP(unit, cmc), 2367 countq, startq, numq); 2368 if (numq != countq) { 2369 return BCM_E_PARAM; 2370 } 2371 2372 /* We know chan_id != -1 from the parameter check at the 2373 * start of the function */ 2374 endq = startq + NUM_CPU_ARM_COSQ(unit, cmc); 2375 for (ix = start_chan_id; ix < (start_chan_id + BCM_RX_CHANNELS); ix++) { 2376 /* set CMIC_CMCx_CHy_COS_CTRL_RX_0/1 based on CMC's start 2377 * and end queue number 2378 */ 2379 chan_off = ix % BCM_RX_CHANNELS; 2380 reg_val = 0; 2381 if (ix == (uint32)chan_id) { 2382 reg_val |= (endq < 32) ? 2383 ((uint32)1 << endq) - 1 : 0xffffffff; 2384 reg_val &= (startq < 32) ? 2385 ~(((uint32)1 << startq) - 1) : 0; 2386 } 2387 2388 reg_addr = CMIC_CMCx_CHy_COS_CTRL_RX_0_OFFSET(cmc, chan_off); 2389 /* Incoporate the reserved queues (if any on this device) 2390 * into the CMIC programming, */ 2391 reg_val |= CPU_ARM_RSVD_QUEUE_BITMAP(unit,cmc)[0]; 2392 soc_pci_write(unit, reg_addr, reg_val); 2393 reg_addr = CMIC_CMCx_CHy_COS_CTRL_RX_1_OFFSET(cmc, chan_off); 2394 2395 reg_val = 0; 2396 /* Incoporate the reserved queues (if any on this device) 2397 * into the CMIC programming, */ 2398 reg_val |= CPU_ARM_RSVD_QUEUE_BITMAP(unit,cmc)[1]; 2399 2400 if (ix == (uint32)chan_id) { 2401 reg_val |= ((endq >= 32) && (endq < 64)) ? 2402 (((uint32)1 << (endq % 32)) - 1) : 2403 ((endq < 32) ? 0 : 0xffffffff); 2404 reg_val &= (startq >= 32) ? 2405 ~(((uint32)1 << (startq % 32)) - 1) : 0xffffffff; 2406 2407 if (SOC_IS_TD2P_TT2P(unit)) { 2408 soc_pci_write(unit, reg_addr, reg_val); 2409 } 2410 } 2411 2412 #ifdef BCM_KATANA2_SUPPORT 2413 /* { */ 2414 if (SOC_IS_KATANA2(unit)) { 2415 if ((reg_addr == soc_reg_addr(unit, 2416 CMIC_CMC0_CH1_COS_CTRL_RX_1r, REG_PORT_ANY, 0)) || 2417 (reg_addr == soc_reg_addr(unit, 2418 CMIC_CMC0_CH2_COS_CTRL_RX_1r, REG_PORT_ANY, 0)) || 2419 (reg_addr == soc_reg_addr(unit, 2420 CMIC_CMC0_CH3_COS_CTRL_RX_1r, REG_PORT_ANY, 0)) || 2421 (reg_addr == soc_reg_addr(unit, 2422 CMIC_CMC1_CH1_COS_CTRL_RX_1r, REG_PORT_ANY, 0)) || 2423 (reg_addr == soc_reg_addr(unit, 2424 CMIC_CMC2_CH1_COS_CTRL_RX_1r, REG_PORT_ANY, 0))) { 2425 reg_val |= (1 << (15 + chan_id)); 2426 } 2427 } 2428 2429 if (SOC_IS_SABER2(unit)) { 2430 if (reg_addr == soc_reg_addr(unit, 2431 CMIC_CMC2_CH3_COS_CTRL_RX_1r, REG_PORT_ANY, 0)) { 2432 reg_val |= (1 << (15 + chan_id)); 2433 } 2434 } 2435 /* } */ 2436 #endif 2437 if (!SOC_IS_TD2P_TT2P(unit)) { 2438 soc_pci_write(unit, reg_addr, reg_val); 2439 } 2440 } 2441 #if defined(BCM_KATANA_SUPPORT) 2442 /* { */ 2443 if (SOC_IS_KATANAX(unit)) { 2444 /* 2445 * Katana queues have been disabled to prevent packets 2446 * that cannot egress from reaching the CMIC. At this 2447 * point those queues can be enabled. 2448 */ 2449 for (i = startq; i < endq; i++) { 2450 reg_val = 0; 2451 soc_reg_field_set(unit, 2452 THDO_QUEUE_DISABLE_CFG2r, ®_val, QUEUE_NUMf, i); 2453 SOC_IF_ERROR_RETURN( 2454 WRITE_THDO_QUEUE_DISABLE_CFG2r(unit, reg_val)); 2455 reg_val = 0; 2456 soc_reg_field_set(unit, 2457 THDO_QUEUE_DISABLE_CFG1r, ®_val, QUEUE_WRf, 1); 2458 SOC_IF_ERROR_RETURN( 2459 WRITE_THDO_QUEUE_DISABLE_CFG1r(unit, reg_val)); 2460 } 2461 } 2462 /* } */ 2463 #endif /*BCM_KATANA_SUPPORT */ 2464 } else { 2465 BCM_IF_ERROR_RETURN(_bcm_common_rx_queue_channel_set_helper(unit, 2466 queue_id, 2467 chan_id, cmc)); 2468 } 2469 } 2470 } else 2471 /* } */ 2472 #endif /* CMICM Support */ 2473 #ifdef BCM_CMICX_SUPPORT 2474 if (soc_feature(unit, soc_feature_cmicx)) { 2475 uint32 max_rx_channels = 0; 2476 2477 soc_dma_max_rx_channels_get(unit, &max_rx_channels); 2478 2479 if (chan_id < max_rx_channels) { 2480 cmc = pci_cmc; 2481 } else { 2482 cmc = SOC_ARM_CMC(unit, ((chan_id / max_rx_channels) - 1)); 2483 /* compute start queue number for any CMC */ 2484 startq = NUM_CPU_ARM_COSQ(unit, pci_cmc); 2485 for (ix = 0; ix < cmc; ix++) { 2486 startq += (ix != pci_cmc) ? NUM_CPU_ARM_COSQ(unit, ix) : 0; 2487 } 2488 } 2489 2490 #if defined(BCM_TOMAHAWK3_SUPPORT) 2491 /* Only for host CPU PCI CMC. 2492 * Only for Tomahawk3 */ 2493 if (SOC_IS_TOMAHAWK3(unit)) { 2494 if (cmc == pci_cmc) { 2495 BCM_IF_ERROR_RETURN(bcm_th3_rx_queue_channel_set_test(unit, 2496 queue_id, chan_id)); 2497 } else { 2498 uint32 cfg = 0; 2499 uint32 cos_ctrl = 0; 2500 uint32 queue_mask = 0; 2501 dma_chan_t vchan = 0; 2502 dma_chan_t vchan_start = 0; 2503 dma_chan_t vchan_end = 0; 2504 2505 vchan_start = max_rx_channels*cmc; 2506 vchan_end = max_rx_channels*(cmc + 1); 2507 2508 if (chan_id < vchan_start || chan_id >= vchan_end) { 2509 return BCM_E_PARAM; 2510 } 2511 2512 if (queue_id > SOC_TH3_NUM_CPU_QUEUES) { 2513 return BCM_E_PARAM; 2514 } 2515 2516 cfg = (queue_id < 32) ? 0x1:0x2; 2517 queue_mask = (uint32)(1 << (queue_id % 32)); 2518 2519 for (vchan = vchan_start; vchan < vchan_end; vchan++) { 2520 BCM_IF_ERROR_RETURN(soc_dma_chan_cos_ctrl_get(unit, vchan, 2521 cfg, &cos_ctrl)); 2522 if (vchan == chan_id) { 2523 cos_ctrl |= queue_mask; 2524 } else { 2525 cos_ctrl &= ~queue_mask; 2526 } 2527 BCM_IF_ERROR_RETURN(soc_dma_chan_cos_ctrl_set(unit, vchan, 2528 cfg, cos_ctrl)); 2529 } 2530 } 2531 } else 2532 #endif 2533 #if defined(BCM_TRIDENT3_SUPPORT) 2534 /* Only for host CPU PCI CMC. 2535 * Only for Trident3 */ 2536 if (SOC_IS_TRIDENT3X(unit) && 2537 (cmc == pci_cmc)) { 2538 #if defined(BCM_HELIX5_SUPPORT) 2539 if (SOC_IS_HELIX5(unit)) { 2540 BCM_IF_ERROR_RETURN(bcm_hx5_rx_queue_channel_set_test(unit, 2541 queue_id, chan_id)); 2542 } else 2543 #endif 2544 { 2545 BCM_IF_ERROR_RETURN(bcm_td3_rx_queue_channel_set_test(unit, 2546 queue_id, chan_id)); 2547 } 2548 } else { 2549 uint32 cfg = 0; 2550 uint32 cos_ctrl = 0; 2551 uint32 queue_mask = 0; 2552 dma_chan_t vchan = 0; 2553 dma_chan_t vchan_start = 0; 2554 dma_chan_t vchan_end = 0; 2555 2556 vchan_start = max_rx_channels*cmc; 2557 vchan_end = max_rx_channels*(cmc + 1); 2558 2559 if (chan_id < vchan_start || chan_id >= vchan_end) { 2560 return BCM_E_PARAM; 2561 } 2562 if (queue_id < startq || queue_id > SOC_TD3_NUM_CPU_QUEUES) { 2563 return BCM_E_PARAM; 2564 } 2565 2566 cfg = (queue_id < 32) ? 0x1:0x2; 2567 queue_mask = (uint32)(1 << (queue_id % 32)); 2568 2569 for (vchan = vchan_start; vchan < vchan_end; vchan++) { 2570 BCM_IF_ERROR_RETURN(soc_dma_chan_cos_ctrl_get(unit, vchan, 2571 cfg, &cos_ctrl)); 2572 if (vchan == chan_id) { 2573 cos_ctrl |= queue_mask; 2574 } else { 2575 cos_ctrl &= ~queue_mask; 2576 } 2577 BCM_IF_ERROR_RETURN(soc_dma_chan_cos_ctrl_set(unit, vchan, 2578 cfg, cos_ctrl)); 2579 } 2580 } 2581 #endif 2582 if (SOC_IS_DNX(unit)) { 2583 uint32 cfg = 0; 2584 uint32 cos_ctrl = 0; 2585 uint32 queue_mask = 0; 2586 dma_chan_t vchan = 0; 2587 dma_chan_t vchan_start = 0; 2588 dma_chan_t vchan_end = 0; 2589 2590 vchan_start = max_rx_channels*cmc; 2591 vchan_end = max_rx_channels*(cmc + 1); 2592 2593 /** All COS Queues */ 2594 if (queue_id < 0) 2595 { 2596 for (queue_id = 0; queue_id < 48; queue_id++) 2597 { 2598 cfg = (queue_id < 32) ? 0x1:0x2; 2599 queue_mask = (uint32)(1 << (queue_id % 32)); 2600 2601 for (vchan = vchan_start; vchan < vchan_end; vchan++) 2602 { 2603 BCM_IF_ERROR_RETURN(soc_dma_chan_cos_ctrl_get(unit, vchan, 2604 cfg, &cos_ctrl)); 2605 if (vchan == chan_id) { 2606 cos_ctrl |= queue_mask; 2607 } else { 2608 cos_ctrl &= ~queue_mask; 2609 } 2610 BCM_IF_ERROR_RETURN(soc_dma_chan_cos_ctrl_set(unit, vchan, 2611 cfg, cos_ctrl)); 2612 } 2613 } 2614 } 2615 else 2616 { 2617 cfg = (queue_id < 32) ? 0x1:0x2; 2618 queue_mask = (uint32)(1 << (queue_id % 32)); 2619 for (vchan = vchan_start; vchan < vchan_end; vchan++) 2620 { 2621 BCM_IF_ERROR_RETURN(soc_dma_chan_cos_ctrl_get(unit, vchan, 2622 cfg, &cos_ctrl)); 2623 if (vchan == chan_id) { 2624 cos_ctrl |= queue_mask; 2625 } else { 2626 cos_ctrl &= ~queue_mask; 2627 } 2628 BCM_IF_ERROR_RETURN(soc_dma_chan_cos_ctrl_set(unit, vchan, 2629 cfg, cos_ctrl)); 2630 } 2631 } 2632 } 2633 } else 2634 #endif /* CMICX Support */ 2635 { 2636 if (chan_id >= 0) { 2637 if (SOC_KNET_MODE(unit)) { 2638 /* Accept all DMA channels configured for Rx */ 2639 reg_val = soc_pci_read(unit, CMIC_DMA_CTRL); 2640 reg_val &= DC_DIRECTION_MASK(chan_id); 2641 if (reg_val == DC_MEM_TO_SOC(chan_id)) { 2642 return BCM_E_NOT_FOUND; 2643 } 2644 } else if (!RX_CHAN_USED(unit, chan_id)) { 2645 return BCM_E_NOT_FOUND; 2646 } 2647 } 2648 if (SOC_IS_TRX(unit)) { 2649 reg_base = CMIC_RX_COS_CONTROL_0; 2650 } else { 2651 reg_base = CMIC_RX_COS_CONTROL; 2652 } 2653 reg_index = NUM_CPU_COSQ(unit) / 8; 2654 2655 /* Negative queue_id represents all COS queue */ 2656 if (queue_id < 0) { 2657 /* We know chan_id != -1 from the parameter check at the 2658 * start of the function */ 2659 if (chan_id < 0) 2660 return BCM_E_PARAM; 2661 for (ix = 0; ix < reg_index; ix++) { 2662 reg_addr = reg_base + (4 * ix); 2663 reg_val = (0xff << RCC_COS_MAP_SHFT(chan_id)); 2664 soc_pci_write(unit, reg_addr, reg_val); 2665 } 2666 } else { 2667 reg_addr = reg_base + (4 * (queue_id / 8)); 2668 reg_val = soc_pci_read(unit, reg_addr); 2669 bit = 1 << (queue_id % 8); 2670 for (ix = 0; ix < BCM_RX_CHANNELS; ix++) { 2671 if (ix == (uint32)chan_id) { 2672 reg_val |= (bit << RCC_COS_MAP_SHFT(ix)); 2673 } else { 2674 /* a cosq can associate with exact one channel */ 2675 reg_val &= ~(bit << RCC_COS_MAP_SHFT(ix)); 2676 } 2677 } 2678 soc_pci_write(unit, reg_addr, reg_val); 2679 } 2680 } 2681 return BCM_E_NONE; 2682 } 2683 2684 /* 2685 * Function: 2686 * bcm_rx_queue_channel_get 2687 * Purpose: 2688 * Get the associated rx channel with a given cosq 2689 * Parameters: 2690 * unit - Unit reference 2691 * queue_id - CPU cos queue index (0 - (max cosq - 1)) 2692 * chan_id - channel index (0 - (BCM_RX_CHANNELS-1)) 2693 * Returns: 2694 * BCM_E_XXX 2695 */ 2696 int 2697 _bcm_common_rx_queue_channel_get(int unit, bcm_cos_queue_t queue_id, 2698 bcm_rx_chan_t *chan_id) 2699 { 2700 uint32 reg_base, reg_addr, reg_val; 2701 uint32 ix, bit; 2702 #if defined(BCM_CMICM_SUPPORT) || defined(BCM_CMICX_SUPPORT) 2703 /* { */ 2704 int cmc; 2705 int chan_offset; 2706 int pci_cmc = SOC_PCI_CMC(unit); 2707 uint32 chan_id_max; 2708 2709 soc_dma_max_rx_channels_get(unit, &chan_id_max); 2710 chan_id_max *= SOC_CMCS_NUM(unit); 2711 /* } */ 2712 #endif 2713 2714 if (!SOC_UNIT_VALID(unit)) { 2715 2716 return BCM_E_INTERNAL; 2717 } 2718 if (!RX_INIT_DONE(unit)) { 2719 return BCM_E_INIT; 2720 } 2721 2722 *chan_id = -1; 2723 if (!soc_feature(unit, soc_feature_cos_rx_dma)) { 2724 /* not DMA set up */ 2725 return BCM_E_CONFIG; 2726 } else if (queue_id < 0 || queue_id >= NUM_CPU_COSQ(unit)) { 2727 return BCM_E_PARAM; 2728 } 2729 2730 #ifdef BCM_CMICM_SUPPORT /* For now, we also have to support CMICe */ 2731 /* { */ 2732 if(soc_feature(unit, soc_feature_cmicm)) { 2733 for (ix = 0; ix < chan_id_max; ix++) { 2734 if (ix < BCM_RX_CHANNELS) { 2735 cmc = pci_cmc; 2736 } else { 2737 cmc = SOC_ARM_CMC(unit, ((ix / BCM_RX_CHANNELS) - 1)); 2738 } 2739 chan_offset = ix % BCM_RX_CHANNELS; 2740 reg_addr = (queue_id < 32) ? 2741 CMIC_CMCx_CHy_COS_CTRL_RX_0_OFFSET(cmc,chan_offset) : 2742 CMIC_CMCx_CHy_COS_CTRL_RX_1_OFFSET(cmc,chan_offset); 2743 bit = 1 << (queue_id % 32); 2744 reg_val = soc_pci_read(unit, reg_addr); 2745 if (reg_val & bit) { 2746 if (*chan_id == -1) { 2747 *chan_id = ix; 2748 } else { 2749 LOG_WARN(BSL_LS_BCM_RX, 2750 (BSL_META_U(unit, 2751 BSL_META_U 2752 (unit, 2753 "rx_queue_channel_get: Warning: " 2754 "Multiple channels assigned to the " 2755 "COS 0x%x for unit %d\n")), 2756 queue_id, unit)); 2757 return BCM_E_INTERNAL; 2758 } 2759 } 2760 } 2761 } else 2762 /* } */ 2763 #endif /* CMICM Support */ 2764 #ifdef BCM_CMICX_SUPPORT 2765 if(soc_feature(unit, soc_feature_cmicx)) { 2766 uint32 max_rx_channels = 0; 2767 /* In the case of cmicx devices the value of max_rx_channels will 2768 * be equal to 8. It will never be zero. 2769 * Coverity thinks this can be zero and this is a case that cannot happen 2770 */ 2771 soc_dma_max_rx_channels_get(unit, &max_rx_channels); 2772 2773 for (ix = 0; ix < chan_id_max; ix++) { 2774 if (ix < max_rx_channels) { 2775 cmc = pci_cmc; 2776 } else { 2777 /* coverity[overflow] */ 2778 /* coverity[divide_by_zero] */ 2779 cmc = SOC_ARM_CMC(unit, ((ix / max_rx_channels) - 1)); 2780 } 2781 /* coverity[divide_by_zero] */ 2782 chan_offset = ix % max_rx_channels; 2783 bit = 1 << (queue_id % 32); 2784 reg_val = soc_cmicx_pktdma_cos_ctrl_queue_id_get(unit, cmc, 2785 chan_offset, queue_id); 2786 if (reg_val & bit) { 2787 if (*chan_id == -1) { 2788 *chan_id = ix; 2789 } else { 2790 LOG_WARN(BSL_LS_BCM_RX, 2791 (BSL_META_U(unit, 2792 BSL_META_U 2793 (unit, 2794 "rx_queue_channel_get: Warning: " 2795 "Multiple channels assigned to the " 2796 "COS 0x%x for unit %d\n")), 2797 queue_id, unit)); 2798 return BCM_E_INTERNAL; 2799 } 2800 } 2801 } 2802 } else 2803 #endif /* CMICX Support */ 2804 { 2805 if (SOC_IS_TRX(unit)) { 2806 reg_base = CMIC_RX_COS_CONTROL_0; 2807 } else { 2808 reg_base = CMIC_RX_COS_CONTROL; 2809 } 2810 2811 reg_addr = reg_base + (4 * (queue_id / 8)); 2812 reg_val = soc_pci_read(unit, reg_addr); 2813 2814 bit = 1 << (queue_id % 8); 2815 for (ix = 0; ix < BCM_RX_CHANNELS; ix++) { 2816 if (reg_val & (bit << RCC_COS_MAP_SHFT(ix))) { 2817 if (*chan_id == -1) { 2818 *chan_id = ix; 2819 } else { 2820 LOG_WARN(BSL_LS_BCM_RX, 2821 (BSL_META_U(unit, 2822 BSL_META_U 2823 (unit, 2824 "rx_queue_channel_get: Warning: " 2825 "Multiple channels assigned to " 2826 "the COS 0x%x for unit %d\n")), 2827 queue_id, unit)); 2828 return BCM_E_INTERNAL; 2829 } 2830 } 2831 } 2832 } 2833 return ((*chan_id == -1)? BCM_E_NOT_FOUND : BCM_E_NONE); 2834 } 2835 2836 /* 2837 * Function: 2838 * bcm_rx_active 2839 * Purpose: 2840 * Return boolean as to whether unit is running 2841 * Parameters: 2842 * unit - StrataXGS to check 2843 * Returns: 2844 * Boolean: TRUE if unit is running. 2845 * Notes: 2846 */ 2847 2848 int 2849 _bcm_common_rx_active(int unit) 2850 { 2851 return (RX_UNIT_STARTED(unit)) != 0; 2852 } 2853 2854 2855 /* 2856 * Function: 2857 * bcm_rx_running_channels_get 2858 * Purpose: 2859 * Returns a bitmap indicating which channels are active 2860 * Parameters: 2861 * unit - Which unit to operate on 2862 * Returns: 2863 * Bitmap of active channels 2864 * Notes: 2865 */ 2866 2867 int 2868 _bcm_common_rx_channels_running(int unit, uint32 *channels) 2869 { 2870 if (!RX_INIT_DONE(unit)) { 2871 return BCM_E_INIT; 2872 } 2873 *channels = rx_ctl[unit]->chan_running; 2874 return BCM_E_NONE; 2875 } 2876 2877 /* 2878 * Function: 2879 * bcm_rx_alloc 2880 * Purpose: 2881 * Gateway to configured RX allocation function 2882 * Parameters: 2883 * unit - Unit reference 2884 * pkt_size - Packet size, see notes. 2885 * flags - Used to set up packet flags 2886 * Returns: 2887 * Pointer to new packet buffer or NULL if cannot alloc memory 2888 * Notes: 2889 * Although the packet size is normally configured per unit, 2890 * the option of using a different size is given here. If 2891 * pkt_size <= 0, then the default packet size for the unit 2892 * is used. 2893 */ 2894 2895 int 2896 _bcm_common_rx_alloc(int unit, int pkt_size, uint32 flags, void **buf) 2897 { 2898 if (!RX_INIT_DONE(unit)) { 2899 *buf = NULL; 2900 return BCM_E_INIT; 2901 } 2902 2903 if (pkt_size <= 0) { 2904 pkt_size = rx_ctl[unit]->user_cfg.pkt_size; 2905 } 2906 2907 return rx_ctl[unit]->user_cfg.rx_alloc(unit, pkt_size, flags, buf); 2908 } 2909 2910 2911 /* 2912 * Function: 2913 * bcm_rx_free 2914 * Purpose: 2915 * Gateway to configured RX free function. Generally, packet 2916 * buffer was allocated with bcm_rx_alloc. 2917 * Parameters: 2918 * unit - Unit reference 2919 * pkt - Packet to free 2920 * Returns: 2921 * Notes: 2922 * In particular, packets stolen from RX with BCM_RX_HANDLED_OWNED 2923 * should use this to free packets. 2924 */ 2925 2926 int 2927 _bcm_common_rx_free(int unit, void *pkt_data) 2928 { 2929 #if defined(BROADCOM_DEBUG) 2930 /* { */ 2931 if (rx_ctl[unit] == NULL || !rx_ctl[unit]->user_cfg.rx_free) { 2932 return BCM_E_MEMORY; 2933 } 2934 /* } */ 2935 #endif /* BROADCOM_DEBUG */ 2936 2937 if (pkt_data != NULL) { 2938 rx_ctl[unit]->user_cfg.rx_free(unit, pkt_data); 2939 } 2940 2941 return BCM_E_NONE; 2942 } 2943 2944 2945 /* 2946 * Function: 2947 * bcm_rx_free_enqueue 2948 * Purpose: 2949 * Queue a packet to be freed by the RX thread. 2950 * Parameters: 2951 * unit - Unit reference 2952 * pkt - Packet to free 2953 * Returns: 2954 * Notes: 2955 * This may be called in interrupt context to queue 2956 * a packet to be freed. 2957 * 2958 * Assumes pkt_data is 32-bit aligned. 2959 * Uses the first word of the freed data as a "next" pointer 2960 * for the free list. 2961 */ 2962 2963 #define PKT_TO_FREE_NEXT(data) (((void **)data)[0]) 2964 int 2965 _bcm_common_rx_free_enqueue(int unit, void *pkt_data) 2966 { 2967 if (pkt_data == NULL) { 2968 return BCM_E_PARAM; 2969 } 2970 2971 if (!RX_INIT_DONE(unit) || rx_control.rx_tid == NULL) { 2972 return BCM_E_INIT; 2973 } 2974 2975 RX_INTR_LOCK; 2976 PKT_TO_FREE_NEXT(pkt_data) = (void *)(rx_ctl[unit]->free_list); 2977 rx_ctl[unit]->free_list = pkt_data; 2978 RX_INTR_UNLOCK; 2979 2980 RX_THREAD_NOTIFY(unit); 2981 2982 return BCM_E_NONE; 2983 } 2984 2985 /* 2986 * Function: 2987 * _bcm_common_rx_olp_match_rule_set 2988 * Purpose: 2989 * Set Olp Match Rule value in rx_ctl 2990 * Parameters: 2991 * unit - StrataSwitch unit number. 2992 * olp_match_rule - Olp Match Rule Value. 2993 * Returns: 2994 * BCM_E_XXX 2995 */ 2996 int 2997 _bcm_common_rx_olp_match_rule_set (int unit, int olp_match_rule) 2998 { 2999 if (!RX_INIT_DONE(unit)) { 3000 return BCM_E_INIT; 3001 } 3002 RX_LOCK(unit); 3003 rx_ctl[unit]->olp_match_rule = olp_match_rule; 3004 RX_UNLOCK(unit); 3005 3006 return BCM_E_NONE; 3007 } 3008 3009 /* 3010 * Function: 3011 * _bcm_common_rx_olp_match_rule_get 3012 * Purpose: 3013 * Get Olp Match Rule value in rx_ctl 3014 * Parameters: 3015 * unit - StrataSwitch unit number. 3016 * olp_match_rule - Olp Match Rule Value. 3017 * Returns: 3018 * BCM_E_XXX 3019 */ 3020 int 3021 _bcm_common_rx_olp_match_rule_get (int unit, int *olp_match_rule) 3022 { 3023 if (!RX_INIT_DONE(unit)) { 3024 return BCM_E_INIT; 3025 } 3026 if (olp_match_rule == NULL) { 3027 return BCM_E_PARAM; 3028 } 3029 *olp_match_rule = rx_ctl[unit]->olp_match_rule; 3030 3031 return BCM_E_NONE; 3032 } 3033 3034 /**************************************************************** 3035 * 3036 * Global (all COS) and per COS rate limiting configuration 3037 */ 3038 3039 3040 /* 3041 * Functions: 3042 * bcm_rx_burst_set, get; bcm_rx_rate_set, get 3043 * bcm_rx_cos_burst_set, get; bcm_rx_cos_rate_set, get; 3044 * bcm_rx_cos_max_len_set, get 3045 * Purpose: 3046 * Get/Set the global and per COS limits: 3047 * rate: Packets/second 3048 * burst: Packets (max tokens in bucket) 3049 * max_len: Packets (max permitted in queue). 3050 * Parameters: 3051 * unit - Unit reference 3052 * cos - For per COS functions, which COS queue affected 3053 * pps - Rate in packets per second (OUT for get functions) 3054 * burst - Burst rate for the system in packets (OUT for get functions) 3055 * max_q_len - Burst rate for the system in packets (OUT for get functions) 3056 * Returns: 3057 * BCM_E_XXX 3058 * Notes: 3059 * PPS must be >= 0 and 3060 * Max queue length must be >= 0; 3061 * otherwise param error. 3062 * 3063 * PPS == 0 -> rate limiting disabled. 3064 * max_q_len == 0 -> no limit on queue length (not recommended) 3065 */ 3066 3067 int 3068 _bcm_common_rx_rate_set(int unit, int pps) 3069 { 3070 RX_INIT_CHECK(unit); 3071 3072 if (pps < 0) { 3073 return BCM_E_PARAM; 3074 } 3075 RX_PPS(unit) = pps; 3076 3077 return BCM_E_NONE; 3078 } 3079 3080 int 3081 _bcm_common_rx_rate_get(int unit, int *pps) 3082 { 3083 RX_INIT_CHECK(unit); 3084 3085 if (pps) { 3086 *pps = RX_PPS(unit); 3087 } 3088 3089 return BCM_E_NONE; 3090 } 3091 3092 int 3093 _bcm_common_rx_cpu_rate_set(int unit, int pps) 3094 { 3095 if (pps < 0) { 3096 return BCM_E_PARAM; 3097 } 3098 rx_control.system_pps = pps; 3099 3100 return BCM_E_NONE; 3101 } 3102 3103 int 3104 _bcm_common_rx_cpu_rate_get(int unit, int *pps) 3105 { 3106 if (pps) { 3107 *pps = rx_control.system_pps; 3108 } 3109 return BCM_E_NONE; 3110 } 3111 3112 3113 int 3114 _bcm_common_rx_burst_set(int unit, int burst) 3115 { 3116 RX_INIT_CHECK(unit); 3117 3118 RX_BURST(unit) = burst; 3119 RX_TOKENS(unit) = burst; 3120 3121 return BCM_E_NONE; 3122 } 3123 3124 int 3125 _bcm_common_rx_burst_get(int unit, int *burst) 3126 { 3127 RX_INIT_CHECK(unit); 3128 3129 if (burst) { 3130 *burst = RX_BURST(unit); 3131 } 3132 return BCM_E_NONE; 3133 } 3134 3135 int 3136 _bcm_common_rx_cos_rate_set(int unit, int cos, int pps) 3137 { 3138 int i; 3139 3140 if (!LEGAL_COS(cos) || pps < 0) { 3141 return BCM_E_PARAM; 3142 } 3143 3144 RX_INIT_CHECK(unit); 3145 if (cos == BCM_RX_COS_ALL) { 3146 for (i = 0; i <= RX_QUEUE_MAX(unit); i++) { 3147 RX_COS_PPS(unit, i) = pps; 3148 } 3149 } else { 3150 RX_COS_PPS(unit, cos) = pps; 3151 } 3152 3153 return BCM_E_NONE; 3154 } 3155 3156 int 3157 _bcm_common_rx_cos_rate_get(int unit, int cos, int *pps) 3158 { 3159 RX_INIT_CHECK(unit); 3160 if (pps) { 3161 *pps = RX_COS_PPS(unit, cos); 3162 } 3163 3164 return BCM_E_NONE; 3165 } 3166 3167 int 3168 _bcm_common_rx_cos_burst_set(int unit, int cos, int burst) 3169 { 3170 rx_queue_t *queue; 3171 int i; 3172 3173 if (!LEGAL_COS(cos)) { 3174 return BCM_E_PARAM; 3175 } 3176 3177 RX_INIT_CHECK(unit); 3178 if (cos == BCM_RX_COS_ALL) { 3179 for (i = 0; i <= RX_QUEUE_MAX(unit); i++) { 3180 queue = RX_QUEUE(unit, i); 3181 queue->burst = burst; 3182 queue->tokens = burst; 3183 } 3184 } else { 3185 queue = RX_QUEUE(unit, cos); 3186 queue->burst = burst; 3187 queue->tokens = burst; 3188 } 3189 3190 return BCM_E_NONE; 3191 } 3192 3193 int 3194 _bcm_common_rx_cos_burst_get(int unit, int cos, int *burst) 3195 { 3196 RX_INIT_CHECK(unit); 3197 if (burst) { 3198 *burst = RX_COS_BURST(unit, cos); 3199 } 3200 3201 return BCM_E_NONE; 3202 } 3203 3204 int 3205 _bcm_common_rx_cos_max_len_set(int unit, int cos, int max_q_len) 3206 { 3207 if (!LEGAL_COS(cos) || max_q_len < 0) { 3208 return BCM_E_PARAM; 3209 } 3210 3211 RX_INIT_CHECK(unit); 3212 if (cos == BCM_RX_COS_ALL) { 3213 for (cos = 0; cos <= RX_QUEUE_MAX(unit); cos++) { 3214 RX_COS_MAX_LEN(unit, cos) = max_q_len; 3215 } 3216 } else { 3217 RX_COS_MAX_LEN(unit, cos) = max_q_len; 3218 } 3219 3220 return BCM_E_NONE; 3221 } 3222 3223 int 3224 _bcm_common_rx_cos_max_len_get(int unit, int cos, int *max_q_len) 3225 { 3226 RX_INIT_CHECK(unit); 3227 if (max_q_len) { 3228 *max_q_len = RX_COS_MAX_LEN(unit, cos); 3229 } 3230 3231 return BCM_E_NONE; 3232 } 3233 3234 /**************************************************************** 3235 * 3236 * The non-interrupt thread 3237 */ 3238 3239 STATIC int 3240 rx_thread_start(int unit) 3241 { 3242 int priority; 3243 3244 /* Timer/Event semaphore thread sleeping on. */ 3245 if (NULL == rx_control.pkt_notify) { 3246 rx_control.pkt_notify = sal_sem_create("RX pkt ntfy", sal_sem_BINARY, 0); 3247 if (NULL == rx_control.pkt_notify) { 3248 return (BCM_E_MEMORY); 3249 } 3250 rx_control.pkt_notify_given = FALSE; 3251 } 3252 3253 /* RX start/stop on one of the units protection mutex. */ 3254 if (NULL == rx_control.system_lock) { 3255 rx_control.system_lock = sal_mutex_create("RX system lock"); 3256 if (NULL == rx_control.system_lock) { 3257 sal_sem_destroy(rx_control.pkt_notify); 3258 return (BCM_E_MEMORY); 3259 } 3260 } 3261 3262 if (SOC_UNIT_VALID(unit)) { 3263 priority = soc_property_get(unit, 3264 spn_BCM_RX_THREAD_PRI, 3265 RX_THREAD_PRI_DFLT); 3266 } else { 3267 priority = RX_THREAD_PRI_DFLT; 3268 } 3269 3270 if (NULL == rx_control.rx_sched_cb) { 3271 rx_control.rx_sched_cb = _BCM_RX_SCHED_DEFAULT_CB; 3272 } 3273 3274 /* Start rx thread. */ 3275 rx_control.rx_tid = sal_thread_create("bcmRX", 3276 SAL_THREAD_STKSZ, 3277 priority, 3278 rx_pkt_thread, NULL); 3279 3280 /* Thread creation error handling. */ 3281 if (NULL == rx_control.rx_tid) { 3282 sal_sem_destroy(rx_control.pkt_notify); 3283 sal_mutex_destroy(rx_control.system_lock); 3284 sal_mutex_destroy(rx_control.start_lock); 3285 rx_control.pkt_notify = NULL; 3286 rx_control.system_lock = NULL; 3287 return BCM_E_MEMORY; 3288 } 3289 3290 return BCM_E_NONE; 3291 } 3292 3293 3294 /* 3295 * Calculate number of tokens that should be added to a bucket 3296 * 3297 * Add pps tokens per second to the bucket (up to max_burst). 3298 * Find the number of us per token (assuming pps is much less than 1M). 3299 * 3300 * (us per token) = 1000000 us/sec / (pps tokens/sec) 3301 * 3302 * For example, for 2000 pps, add one token every 500 us. We then 3303 * check the elapsed time since the last addition and divide that 3304 * by us per token. 3305 * 3306 * That is: 3307 * 3308 * (tokens to add) = (elapsed us since last add) / (us per token) 3309 * = (cur - last) / (1000000 / pps) 3310 * = ((cur - last) * pps) / 1000000 3311 * 3312 * Note: When pps > 10000, there can be an integer overflow from 3313 * the multiplication. We fix this by changing order of the calculation 3314 * depending on the size of pps. 3315 */ 3316 3317 #define us_PER_TOKEN(pps) (1000000 / (pps)) 3318 3319 static sal_usecs_t last_fill_check = 0; /* Last time tokens checked */ 3320 3321 /* 3322 * Function: 3323 * _token_update 3324 * Purpose: 3325 * Update the tokens for one bucket 3326 * Parameters: 3327 * cur_time - current time in us 3328 * pps - rate limit for bucket; 0 means disabled 3329 * burst - burst limit for bucket 3330 * token_bucket - (IN/OUT) bucket to be updated 3331 * last_fill - (IN/OUT) last time this bucket was updated 3332 * Returns: 3333 * BCM_E_XXX 3334 */ 3335 3336 STATIC INLINE void 3337 _token_update(sal_usecs_t cur_time, int pps, int burst, 3338 volatile int *token_bucket, sal_usecs_t *last_fill) 3339 { 3340 int new_tokens; 3341 int max_add; 3342 int bucket_top; 3343 int time_diff; 3344 3345 max_add = bucket_top = pps > burst ? pps : burst; 3346 3347 time_diff = SAL_USECS_SUB(cur_time, *last_fill); 3348 if (time_diff < 0) { 3349 /* In case the clock has changed, update last fill to cur_time */ 3350 *last_fill = cur_time; 3351 return; 3352 } 3353 if (time_diff == 0) { 3354 return; 3355 } 3356 3357 /* Cap the number of additions by the fraction of a second refreshed */ 3358 if (time_diff < 1000000) { 3359 max_add = pps / (1000000/time_diff); 3360 } 3361 3362 /* Not enough time passed to add tokens at this rate */ 3363 if (max_add == 0) { 3364 return; 3365 } 3366 3367 /* We use commutative multiplication law to avoid integer 3368 overflow for the following calculation 3369 time_diff * pps / 1000000 3370 If time gap is bigger than two regular refill times 3371 (2 * BCM_RX_TOKEN_CHECK_US_DEFAULT) = 200000 micro 3372 we use (time_diff / 10000) 3373 For high rate flows (over 1000 pps) we use pps / 100 3374 */ 3375 if (*token_bucket < bucket_top) { 3376 new_tokens = ((time_diff > (BCM_RX_TOKEN_CHECK_US_DEFAULT << 1)) ? \ 3377 ((pps < 1000) ? (((time_diff / 10000) * pps) / 100) : \ 3378 ((time_diff / 10000) * (pps / 100))) : \ 3379 ((pps < 1000) ? ((time_diff * pps) / 1000000) : \ 3380 ((time_diff * (pps / 100)) / 10000))); 3381 3382 if (new_tokens > max_add) { 3383 new_tokens = max_add; 3384 } 3385 if (new_tokens > 0) { 3386 *token_bucket += new_tokens; 3387 if (*token_bucket > bucket_top) { 3388 *token_bucket = bucket_top; 3389 } 3390 *last_fill = cur_time; 3391 } 3392 } 3393 } 3394 3395 /* Add tokens to all active token buckets */ 3396 static INLINE void 3397 _all_tokens_update(sal_usecs_t cur_time) 3398 { 3399 int cos, unit; 3400 rx_queue_t *queue; 3401 3402 for (unit = 0; unit < BCM_CONTROL_MAX; unit++) { 3403 if (RX_IS_SETUP(unit)) { 3404 for (cos = 0; cos <= RX_QUEUE_MAX(unit); cos++) { 3405 queue = RX_QUEUE(unit, cos); 3406 if (queue->pps > 0) { 3407 _token_update(cur_time, queue->pps, queue->burst, 3408 &queue->tokens, &queue->last_fill); 3409 } 3410 } 3411 if (RX_PPS(unit) > 0) { 3412 _token_update(cur_time, RX_PPS(unit), RX_BURST(unit), 3413 &rx_ctl[unit]->tokens, &rx_ctl[unit]->last_fill); 3414 } 3415 } 3416 } 3417 3418 /* Check system wide rate limiting */ 3419 if (rx_control.system_pps > 0) { 3420 _token_update(cur_time, rx_control.system_pps, 0, 3421 &rx_control.system_tokens, 3422 &rx_control.system_last_fill); 3423 } 3424 3425 last_fill_check = cur_time; 3426 } 3427 3428 STATIC void 3429 rx_update_tokens(void) 3430 { 3431 sal_usecs_t cur_time; 3432 3433 /* Get current time. */ 3434 cur_time = sal_time_usecs(); 3435 3436 RX_INTR_LOCK; 3437 3438 /* Protection agains clock moving back. */ 3439 if (SAL_USECS_SUB(cur_time, last_fill_check) < 0) { 3440 last_fill_check = cur_time; 3441 } 3442 3443 /* Time based tokens refill check. */ 3444 if (SAL_USECS_SUB(cur_time, last_fill_check) >= bcm_rx_token_check_us) { 3445 _all_tokens_update(cur_time); 3446 } 3447 3448 RX_INTR_UNLOCK; 3449 } 3450 3451 /* Free all buffers listed in pending free list */ 3452 STATIC void 3453 rx_free_queued(int unit) 3454 { 3455 void *free_list, *next_free; 3456 3457 /* Steal list of pkts to be freed for unit */ 3458 RX_INTR_LOCK; 3459 free_list = (bcm_pkt_t *)rx_ctl[unit]->free_list; 3460 rx_ctl[unit]->free_list = NULL; 3461 RX_INTR_UNLOCK; 3462 3463 while (free_list) { 3464 next_free = PKT_TO_FREE_NEXT(free_list); 3465 bcm_rx_free(unit, free_list); 3466 free_list = next_free; 3467 } 3468 } 3469 3470 /* 3471 * Thread support functions 3472 */ 3473 3474 /* Start a chain and update the tokens */ 3475 STATIC INLINE int 3476 rx_chain_start(int unit, int chan, dv_t *dv) 3477 { 3478 int rv = BCM_E_NONE; 3479 3480 LOG_VERBOSE(BSL_LS_BCM_RX, 3481 (BSL_META_U(unit, 3482 BSL_META_U(unit, "RX: Starting %d/%d/%d\n")), 3483 unit, chan, DV_INDEX(dv))); 3484 3485 if (!RX_INIT_DONE(unit) || !rx_control.thread_running) { 3486 /* Revert state in case scheduled */ 3487 DV_STATE(dv) = DV_S_FILLED; 3488 return BCM_E_NONE; 3489 } 3490 3491 if (!SOC_UNIT_VALID(unit)) { 3492 3493 return BCM_E_INTERNAL; 3494 } 3495 3496 /* Start the DV */ 3497 DV_STATE(dv) = DV_S_ACTIVE; 3498 DV_ABORT_CLEANUP(dv) = soc_feature(unit, soc_feature_rxdma_cleanup); 3499 3500 if ((rv = soc_dma_start(unit, chan, dv)) < 0) { 3501 DV_STATE(dv) = DV_S_ERROR; 3502 RX_ERROR((BSL_META_U(unit, "RX: Could not start dv, u %d, chan %d\n"), 3503 unit, chan)); 3504 } 3505 3506 return rv; 3507 } 3508 3509 /* 3510 * The DV (chain) given is ready 3511 * to go. If rate limiting allows that, start the chain. If 3512 * not, schedule the chain in the future. 3513 * 3514 * This is implemented by: First updating the global (all COS) and 3515 * per channel token buckets. If a bucket is negative, this 3516 * indicates a time in the future when the DV can be scheduled, 3517 * based on the pkts/sec of the limit. 3518 * 3519 * Calculate both (global and channel) start times and take the 3520 * later one. 3521 * 3522 * NOTE: This routine should only be called from inside of 3523 * the rx thread b/c it affects variables that that thread 3524 * depends on for timing. 3525 */ 3526 #define USEC_DELAY(tokens, ppc, pps) \ 3527 ((-(tokens) + (ppc)) * us_PER_TOKEN(pps)) 3528 STATIC INLINE int 3529 rx_chain_start_or_sched(int unit, int chan, dv_t *dv) 3530 { 3531 int global_usecs = 0; 3532 int system_usecs = 0; 3533 sal_usecs_t cur_time; 3534 3535 LOG_VERBOSE(BSL_LS_BCM_RX, 3536 (BSL_META_U(unit, 3537 BSL_META_U(unit, "RX: Chain. glob tok %d.\n")), 3538 RX_TOKENS(unit))); 3539 3540 RX_INTR_LOCK; 3541 3542 /* 3543 * Decrement the token buckets for global limits. 3544 * If negative, we must schedule the packet in the 3545 * future. The time to schedule is based on the number of usecs 3546 * needed to get the bucket up to pkts/chain again. 3547 */ 3548 if (rx_control.system_pps > 0) { /* System rate limiting */ 3549 rx_control.system_tokens -= RX_PPC(unit); 3550 if (rx_control.system_tokens < 0) { 3551 system_usecs = USEC_DELAY(rx_control.system_tokens, 3552 RX_PPC(unit), rx_control.system_pps); 3553 } 3554 } 3555 if (RX_PPS(unit)) { /* Global rate limiting is on */ 3556 RX_TOKENS(unit) -= RX_PPC(unit); 3557 if (RX_TOKENS(unit) < 0) { 3558 global_usecs = USEC_DELAY(rx_ctl[unit]->tokens, 3559 RX_PPC(unit), RX_PPS(unit)); 3560 } 3561 } 3562 3563 RX_INTR_UNLOCK; 3564 3565 /* Use the maximum delay */ 3566 if (global_usecs < system_usecs) { 3567 global_usecs = system_usecs; 3568 } 3569 3570 if (!global_usecs) { /* Can start immediately */ 3571 return rx_chain_start(unit, chan, dv); 3572 } else { 3573 3574 /***** The DV must be scheduled into the future *****/ 3575 3576 DV_STATE(dv) = DV_S_SCHEDULED; 3577 cur_time = sal_time_usecs(); 3578 DV_SCHED_TIME(dv) = cur_time; 3579 DV_TIME_DIFF(dv) = global_usecs; 3580 SLEEP_MIN_SET(global_usecs); 3581 RX_INFO((BSL_META_U 3582 (unit, "RX: Scheduling %d/%d/%d in %d us; " 3583 "cur %u; sleep %u\n"), unit, chan, DV_INDEX(dv), 3584 global_usecs, cur_time, rx_control.sleep_cur)); 3585 } 3586 3587 return BCM_E_NONE; 3588 } 3589 3590 /* 3591 * Based on the state of the DV, carry out an action. 3592 * If it is scheduled, check if it may be started. 3593 * 3594 * NOTE: This routine should only be called from inside of 3595 * the rx thread b/c it affects variables that that thread 3596 * depends on for timing. 3597 */ 3598 3599 static INLINE int 3600 rx_update_dv(int unit, int chan, dv_t *dv) 3601 { 3602 sal_usecs_t cur_usecs; 3603 int sched_usecs; 3604 int rv = BCM_E_NONE; 3605 3606 /* If no real callouts, don't bother starting DVs */ 3607 if (!SOC_KNET_MODE(unit) && 3608 (!rx_control.thread_running || NO_REAL_CALLOUTS(unit))) { 3609 if (DV_STATE(dv) == DV_S_SCHEDULED) { 3610 DV_STATE(dv) = DV_S_FILLED; 3611 } 3612 return BCM_E_NONE; 3613 } 3614 3615 assert(dv); 3616 3617 switch (DV_STATE(dv)) { 3618 case DV_S_NEEDS_FILL: 3619 rx_dv_fill(unit, chan, dv); 3620 3621 /* If fill succeeded, try to schedule/start; otherwise break. */ 3622 if (DV_STATE(dv) != DV_S_FILLED) { 3623 break; 3624 } 3625 /* Fall thru: Ready to be scheduled/started */ 3626 case DV_S_FILLED: /* See if we can start or schedule this DV */ 3627 rv = rx_chain_start_or_sched(unit, chan, dv); 3628 3629 break; 3630 case DV_S_SCHEDULED: 3631 cur_usecs = sal_time_usecs(); 3632 3633 /* How much time before next schedule? */ 3634 sched_usecs = DV_FUTURE_US(dv, cur_usecs); 3635 3636 if (sched_usecs <= 0) { 3637 /* Start the dv */ 3638 RX_INFO((BSL_META_U 3639 (unit, "RX: Starting scheduled %d/%d/%d, diff %d " 3640 "@ %u\n"), unit, chan, DV_INDEX(dv), 3641 sched_usecs, cur_usecs)); 3642 rv = rx_chain_start(unit, chan, dv); 3643 } else { 3644 /* Still not ready to be started; set sleep min time */ 3645 RX_INFO((BSL_META_U 3646 (unit, "RX: %d/%d/%d not ready at %u, diff %d\n"), 3647 unit, chan, DV_INDEX(dv), cur_usecs, sched_usecs)); 3648 SLEEP_MIN_SET(sched_usecs); 3649 } 3650 break; 3651 default: /* Don't worry about other states here. */ 3652 break; 3653 } 3654 3655 return rv; 3656 } 3657 3658 /* 3659 * Function: 3660 * rx_thread_dv_check 3661 * Purpose: 3662 * Check if any DVs need refilling, starting or scheduling 3663 * Parameters: 3664 * unit - unit to examine 3665 * Returns: 3666 * BCM_E_XXX 3667 * Notes: 3668 * To avoid starvation, a "current" channel is maintained that 3669 * rotates through the possible channels. 3670 * 3671 * Does nothing for remote units, but safe to call on them. 3672 */ 3673 #define _CUR_CHAN(unit) (rx_ctl[unit]->cur_chan) 3674 3675 STATIC void 3676 rx_thread_dv_check(int unit) 3677 { 3678 int chan; 3679 int i, j; 3680 uint32 dma_chan; 3681 3682 if (RX_IS_REMOTE(unit) || !SOC_UNIT_VALID(unit)) { 3683 return; 3684 } 3685 3686 soc_dma_max_rx_channels_get(unit, &dma_chan); 3687 3688 chan = _CUR_CHAN(unit); 3689 3690 for (j = 0; j < dma_chan; j++) { 3691 if (RX_CHAN_RUNNING(unit, chan)) { 3692 for (i = 0; i < RX_CHAINS(unit, chan); i++) { 3693 rx_update_dv(unit, chan, RX_DV(unit, chan, i)); 3694 } 3695 } 3696 chan = (chan + 1) % dma_chan; 3697 } 3698 3699 _CUR_CHAN(unit) = (_CUR_CHAN(unit) + 1) % dma_chan; 3700 3701 } 3702 3703 #undef _CUR_CHAN 3704 /* 3705 * Function: 3706 * rx_thread_pkts_process 3707 * Purpose: 3708 * Process all pending packets for a particular COS 3709 * Parameters: 3710 * unit - (IN) BCM device number. 3711 * cos - (IN) Queue to read packets from. 3712 * count - (IN) 3713 * Returns: 3714 * BCM_E_XXX 3715 */ 3716 3717 STATIC int 3718 rx_thread_pkts_process(int unit, int cos, int count) 3719 { 3720 bcm_pkt_t *pkt_list = NULL; 3721 bcm_pkt_t *next_pkt; 3722 rx_queue_t *queue; 3723 int drop_all = FALSE; /* Drop all flag. */ 3724 int rv = BCM_E_NONE; /* Operation return status. */ 3725 3726 /* 3727 * Steal the queue's packets; if rate limiting on, just take as many 3728 * as can be handled. 3729 */ 3730 queue = RX_QUEUE(unit, cos); 3731 3732 if ((count > queue->count) || (count < 0)) { 3733 count = queue->count; 3734 } 3735 3736 if (0 == count) { 3737 return (BCM_E_NONE); 3738 } 3739 3740 if ((queue->pps > 0) && (count > queue->tokens)) { 3741 3742 _Q_STEAL_ALL(queue, pkt_list); 3743 drop_all = TRUE; 3744 /* count = queue->tokens; */ 3745 } else { 3746 _Q_STEAL(queue, pkt_list, count); 3747 } 3748 3749 if (pkt_list == NULL) { 3750 return (BCM_E_NONE); /* Strange but Queue is empty.*/ 3751 } 3752 3753 /* Process packets */ 3754 while (pkt_list) { 3755 #if defined(BCM_RXP_DEBUG) 3756 /* { */ 3757 bcm_rx_pool_own(pkt_list->alloc_ptr, "rx_dequeue"); 3758 /* } */ 3759 #endif 3760 next_pkt = pkt_list->_next; 3761 3762 /* Make sure scheduler properly enforces queue rate limiting. */ 3763 if (queue->pps > 0 && (FALSE == drop_all)) { 3764 if (queue->tokens > 0) { 3765 queue->tokens--; 3766 } 3767 } 3768 3769 /* Process 1 packet from the queue. */ 3770 3771 if (drop_all) { 3772 if (RX_IS_RCPU(unit)) { 3773 bcm_pkt_rx_free(unit, pkt_list); /* Free the packet */ 3774 } else { 3775 /* 3776 * Unit boundaries are checked before entering this function. 3777 * No need to recheck. 3778 */ 3779 /* coverity[overrun-local] */ 3780 MARK_PKT_PROCESSED(pkt_list, unit, 3781 pkt_list->dma_channel, pkt_list->_dv); 3782 } 3783 queue->rate_disc++; 3784 } else { 3785 #ifdef BCM_RCPU_SUPPORT 3786 /* { */ 3787 if (RX_IS_RCPU(unit)) { 3788 rx_rcpu_process_packet(unit, pkt_list); 3789 } else 3790 /* } */ 3791 #endif /* BCM_RCPU_SUPPORT */ 3792 { 3793 rx_process_packet(unit, pkt_list); 3794 } 3795 } 3796 3797 pkt_list = next_pkt; 3798 3799 _BCM_RX_CHECK_THREAD_DONE; 3800 } 3801 3802 LOG_DEBUG(BSL_LS_BCM_RX, 3803 (BSL_META_U(unit, 3804 "RX COS (%d) Processed (%d) packets\n"), 3805 cos, count)); 3806 return rv; 3807 } 3808 3809 /* 3810 * Clean up Queues for a RCPU unit. 3811 */ 3812 STATIC INLINE void 3813 rx_rcpu_cleanup_queues(int unit) 3814 { 3815 int i; 3816 bcm_pkt_t *pkt_list = NULL; 3817 bcm_pkt_t *next_pkt; 3818 rx_queue_t *queue; 3819 3820 rx_free_queued(unit); 3821 for (i = 0; i <= RX_QUEUE_MAX(unit); i++) { 3822 queue = RX_QUEUE(unit, i); 3823 _Q_STEAL_ALL(queue, pkt_list); 3824 while (pkt_list) { 3825 next_pkt = pkt_list->_next; 3826 bcm_pkt_free(unit, pkt_list); 3827 pkt_list = next_pkt; 3828 } 3829 } 3830 } 3831 3832 /* 3833 * Clean up queues on thread exit. The queued packets still belong 3834 * to DVs, so they'll be freed when rx_dv_dealloc is called. 3835 */ 3836 STATIC INLINE void 3837 rx_cleanup_queues(int unit) 3838 { 3839 int i; 3840 rx_queue_t *queue; 3841 3842 rx_free_queued(unit); 3843 for (i = 0; i <= RX_QUEUE_MAX(unit); i++) { 3844 queue = RX_QUEUE(unit, i); 3845 if (!_Q_EMPTY(queue)) { 3846 queue->count = 0; 3847 queue->head = NULL; 3848 queue->tail = NULL; 3849 } 3850 } 3851 } 3852 3853 /* Called on error or thread exit to clean up DMA, etc. */ 3854 STATIC void 3855 rx_cleanup(int unit) 3856 { 3857 int chan; 3858 3859 if (RX_IS_RCPU(unit)) { 3860 rx_rcpu_cleanup_queues(unit); 3861 return; 3862 } 3863 3864 if (rx_ctl[unit] != NULL) { 3865 if (SOC_UNIT_VALID(unit)) { 3866 /* For each RX channel, abort running DVs, dealloc DVs, 3867 * and mark not running */ 3868 FOREACH_SETUP_CHANNEL(unit, chan) { 3869 /* Abort running DVs on this RX channel*/ 3870 if (soc_dma_abort_channel_total(unit, chan) < 0) { 3871 LOG_WARN(BSL_LS_BCM_RX, 3872 (BSL_META_U(unit, 3873 BSL_META_U 3874 (unit, "RX: Error aborting DMA channel %d\n")), 3875 chan)); 3876 } 3877 /* Sleep .1 sec to allow abort to complete and 3878 * pending pkts thru */ 3879 sal_usleep(100000); 3880 rx_channel_shutdown(unit, chan); 3881 if (rx_ctl[unit] == NULL) { 3882 return; 3883 } 3884 } 3885 } 3886 3887 rx_cleanup_queues(unit); 3888 } 3889 } 3890 3891 /* 3892 * Function: 3893 * _bcm_rx_default_scheduler 3894 * Purpose: 3895 * Schedule number of packets to be processed 3896 * on a specific unit, queue pair. 3897 * Parameters: 3898 * unit - (IN) BCM device number. 3899 * sched_unit - (OUT) Device to process packets. 3900 * sched_cosq - (OUT) Queue to process packets. 3901 * sched_count - (OUT) Number of packets to process. 3902 * Returns: 3903 * BCM_E_XXX 3904 */ 3905 3906 STATIC int 3907 _bcm_rx_default_scheduler(int unit, int *sched_unit, 3908 bcm_cos_queue_t *sched_cosq, int *sched_count) 3909 { 3910 int pkt_in_queue; /* Number of packets waiting. */ 3911 int pkt_limit; /* Max packets to schedule due */ 3912 /* to rate limiting. */ 3913 static bcm_cos_queue_t cosq_idx = -1; /* Queue iterator. */ 3914 static int unit_next = -1;/* Bcm device iterator. */ 3915 3916 3917 /* Get maximum cosq supported by the system. */ 3918 if ((-1 == unit_next) && 3919 (cosq_idx == -1)) { 3920 /* Queues & units iteration initialization. */ 3921 cosq_idx = rx_control.system_cosq_max; 3922 unit_next = unit; 3923 } else { 3924 /* Proceed to the next unit. */ 3925 BCM_IF_ERROR_RETURN(_bcm_common_rx_unit_next_get(unit_next, &unit_next)); 3926 /* If no other unit found proceed to the next queue.*/ 3927 if (-1 == unit_next) { 3928 unit_next = unit; 3929 cosq_idx--; 3930 } 3931 } 3932 3933 for (; cosq_idx >= 0; cosq_idx--) { 3934 /* Check if thread exit request was issued. */ 3935 _BCM_RX_CHECK_THREAD_DONE; 3936 3937 /* Check if queue is supported by the system. */ 3938 for(;unit_next != -1;) { 3939 /* Check if thread exit request was issued. */ 3940 _BCM_RX_CHECK_THREAD_DONE; 3941 3942 /* Check if queue is supported by the device. */ 3943 if (cosq_idx > RX_QUEUE_MAX(unit_next)) { 3944 BCM_IF_ERROR_RETURN(_bcm_common_rx_unit_next_get(unit_next, &unit_next)); 3945 continue; 3946 } 3947 3948 /* Get number of packets awaiting processing. */ 3949 BCM_IF_ERROR_RETURN 3950 (_bcm_common_rx_queue_packet_count_get(unit_next, 3951 cosq_idx, &pkt_in_queue)); 3952 3953 /* Queue rate limiting enforcement. */ 3954 if (pkt_in_queue) { 3955 BCM_IF_ERROR_RETURN 3956 (_bcm_common_rx_queue_rate_limit_status_get(unit_next, cosq_idx, 3957 &pkt_limit)); 3958 *sched_unit = unit_next; 3959 *sched_cosq = cosq_idx; 3960 3961 if (BCM_RX_SCHED_ALL_PACKETS == pkt_limit) { 3962 *sched_count = pkt_in_queue; 3963 } else if (pkt_limit < pkt_in_queue) { 3964 *sched_count = pkt_limit;; 3965 } else { 3966 *sched_count = pkt_in_queue; 3967 } 3968 return (BCM_E_NONE); 3969 } 3970 BCM_IF_ERROR_RETURN(_bcm_common_rx_unit_next_get(unit_next, &unit_next)); 3971 } 3972 unit_next = unit; 3973 } 3974 3975 /* Prep for the next scheduling cycle. */ 3976 cosq_idx = -1; 3977 unit_next = -1; 3978 /* Done indicator. */ 3979 *sched_count = 0; 3980 3981 return (BCM_E_NONE); 3982 } 3983 3984 /* 3985 * Function: 3986 * rx_pkt_thread 3987 * Purpose: 3988 * User level thread that handles packets and DV refills 3989 * Parameters: 3990 * param - Unit number for this thread 3991 * Notes: 3992 * This can get awoken for one or more of the following reasons: 3993 * 1. Descriptor(s) are done (packets ready to process) 3994 * 2. RX stop is called ending processing 3995 * 3. Interrupt processing has handled packets and DV may be 3996 * ready for refill. 3997 * 4. Periodic check in case memory has freed up. 3998 * 3999 * When a DV is scheduled to start, it may change the 4000 * next waking time of this thread by setting sleep_cur. 4001 */ 4002 4003 4004 STATIC void 4005 rx_pkt_thread(void *param) 4006 { 4007 int unit = 0; 4008 int unit_update_idx; 4009 bcm_cos_queue_t cosq; 4010 int count; 4011 4012 /* coverity : unit is already initialised in rx_pkt_thread */ 4013 /* coverity[uninit_use_in_call] */ 4014 RX_INFO((BSL_META_U(unit, "RX: Packet thread starting\n"))); 4015 4016 #ifdef BCM_DNX_SUPPORT 4017 DNX_ERR_RECOVERY_UTILS_EXCLUDED_THREADS_ADD_ALL_UNITS(); 4018 #endif 4019 4020 INIT_SLEEP; 4021 /* Sleep on semaphore. */ 4022 while (rx_control.thread_running) { 4023 4024 /* Refill buckets */ 4025 rx_update_tokens(); 4026 4027 /* Make sure scheduler callback was registered. */ 4028 if (NULL == rx_control.rx_sched_cb) { 4029 break; 4030 } 4031 4032 /* Lock system rx start/stop mechanism. */ 4033 _BCM_RX_SYSTEM_LOCK; 4034 4035 /* Check if system active units list update is required. */ 4036 if (rx_control.system_flags & BCM_RX_CTRL_ACTIVE_UNITS_UPDATE) { 4037 _bcm_rx_unit_list_update(); 4038 rx_control.system_flags &= ~BCM_RX_CTRL_ACTIVE_UNITS_UPDATE; 4039 } 4040 4041 unit_update_idx = rx_control.rx_unit_first; 4042 4043 /* Schedule number of packets to be processed. */ 4044 while (BCM_SUCCESS(rx_control.rx_sched_cb(rx_control.rx_unit_first, 4045 &unit, &cosq, &count))) { 4046 4047 /* Check for completion. */ 4048 if (!count) { 4049 break; 4050 } 4051 /* check unit */ 4052 if (unit < 0 || unit >= BCM_CONTROL_MAX) { 4053 break; 4054 } 4055 4056 /* Process packets based on scheduler allocation. */ 4057 if (BCM_FAILURE(rx_thread_pkts_process(unit, cosq, count))) { 4058 RX_WARN((BSL_META_U 4059 (unit, "Packet rx failed - check the scheduler.\n"))); 4060 } 4061 /* 4062 * Free queued packets and check DVs for all units 4063 * in rx started list before the scheduled one. 4064 */ 4065 for (;-1 != unit_update_idx;) { 4066 rx_free_queued(unit_update_idx); 4067 rx_thread_dv_check(unit_update_idx); 4068 if (unit_update_idx == unit) { 4069 break; 4070 } 4071 _bcm_common_rx_unit_next_get(unit_update_idx, &unit_update_idx); 4072 } 4073 _BCM_RX_CHECK_THREAD_DONE; 4074 4075 if (rx_control.system_flags & BCM_RX_CTRL_ACTIVE_UNITS_UPDATE) { 4076 _bcm_rx_unit_list_update(); 4077 rx_control.system_flags &= ~BCM_RX_CTRL_ACTIVE_UNITS_UPDATE; 4078 } 4079 } 4080 4081 /* 4082 * Free queued packets and check DVs for all units 4083 * in rx started list after last scheduled unit. 4084 */ 4085 for (;-1 != unit_update_idx;) { 4086 /* Free queued packets and check DVs */ 4087 rx_free_queued(unit_update_idx); 4088 rx_thread_dv_check(unit_update_idx); 4089 _bcm_common_rx_unit_next_get(unit_update_idx, &unit_update_idx); 4090 } 4091 4092 /* Unlock system rx start/stop mechanism. */ 4093 _BCM_RX_SYSTEM_UNLOCK; 4094 4095 _BCM_RX_CHECK_THREAD_DONE; 4096 4097 SLEEP_MIN_SET(BASE_SLEEP_VAL); 4098 4099 sal_sem_take(rx_control.pkt_notify, rx_control.sleep_cur); 4100 rx_control.pkt_notify_given = FALSE; 4101 4102 INIT_SLEEP; 4103 } 4104 4105 for (unit = 0; unit < BCM_CONTROL_MAX; unit++) { 4106 if (RX_IS_LOCAL(unit) || RX_IS_RCPU(unit)) { 4107 rx_cleanup(unit); 4108 } 4109 } 4110 rx_control.thread_exit_complete = TRUE; 4111 RX_INFO((BSL_META_U(unit, "RX: Packet thread exitting\n"))); 4112 4113 #ifdef BCM_DNX_SUPPORT 4114 DNX_ERR_RECOVERY_UTILS_EXCLUDED_THREADS_REMOVE_ALL_UNITS(); 4115 #endif 4116 4117 sal_thread_exit(0); 4118 } 4119 4120 /**************************************************************** 4121 * 4122 * Interrupt handling routines: 4123 * Packet done 4124 * Chain done 4125 */ 4126 4127 4128 /* Multiple DCB DMA fillin routine */ 4129 4130 STATIC INLINE void 4131 multi_dcb_fillin(int unit, bcm_pkt_t *pkt, dv_t *dv, int idx) 4132 { 4133 #ifdef BCM_XGS_SUPPORT 4134 /* { */ 4135 uint8 *vlan_store; 4136 uint16 vlan_ctl_tag; 4137 4138 if (SOC_IS_XGS12_FABRIC(unit)) { /* Handle HiGig header and VLAN tag */ 4139 4140 /* Put XGS hdr into pkt->_higig */ 4141 sal_memcpy(pkt->_higig, SOC_DV_HG_HDR(dv, idx), 4142 sizeof(soc_higig_hdr_t)); 4143 4144 /* Put the VLAN info either into pkt or pkt->_vtag as per flags */ 4145 vlan_ctl_tag = soc_higig_field_get(unit, 4146 (soc_higig_hdr_t *)pkt->_higig, 4147 HG_vlan_tag); 4148 vlan_store = BCM_PKT_VLAN_PTR(pkt); 4149 vlan_store[0] = 0x81; 4150 vlan_store[1] = 0x00; 4151 vlan_store[2] = vlan_ctl_tag >> 8; 4152 vlan_store[3] = vlan_ctl_tag & 0xff; 4153 4154 return; 4155 } 4156 /* } */ 4157 #endif /* BCM_XGS_SUPPORT */ 4158 4159 if (BCM_PKT_HAS_SLTAG(pkt)) { 4160 /* SL tag was DMA'd to DV buffer; copy to pkt->_sltag */ 4161 sal_memcpy(pkt->_sltag, SOC_DV_SL_TAG(dv, idx), sizeof(uint32)); 4162 } 4163 4164 if (BCM_PKT_RX_VLAN_TAG_STRIP(pkt)) { 4165 /* VLAN tag was DMA'd to DV buffer; copy to pkt->_vtag */ 4166 sal_memcpy(pkt->_vtag, SOC_DV_VLAN_TAG(dv, idx), sizeof(uint32)); 4167 } 4168 } 4169 4170 /* Move data around if it was DMA'd in a single data buffer */ 4171 4172 STATIC INLINE void 4173 single_dcb_fillin(int unit, bcm_pkt_t *pkt) 4174 { 4175 uint8 tmp_buf[20]; 4176 4177 /* Single buffer was used for packet; move data as necessary */ 4178 #ifdef BCM_XGS_SUPPORT 4179 /* { */ 4180 uint16 vlan_ctl_tag; 4181 uint8 *pkt_ptr; 4182 4183 if (SOC_IS_XGS12_FABRIC(unit)) { /* Handle HiGig header and VLAN tag */ 4184 sal_memcpy(pkt->_higig, pkt->_pkt_data.data, 12); 4185 pkt->_pkt_data.data += 12; /* 12 hg hdr */ 4186 if (!BCM_PKT_RX_VLAN_TAG_STRIP(pkt)) { 4187 /* Move L2 addrs back 4 bytes; add VLAN data into pkt */ 4188 sal_memcpy(tmp_buf, pkt->_pkt_data.data, 12); 4189 pkt->_pkt_data.data -= 4; /* Add space back for vlan */ 4190 sal_memcpy(pkt->_pkt_data.data, tmp_buf, 12); 4191 pkt_ptr = pkt->_pkt_data.data; 4192 pkt_ptr[12] = 0x81; 4193 pkt_ptr[13] = 0x00; 4194 vlan_ctl_tag = soc_higig_field_get(unit, 4195 (soc_higig_hdr_t *)pkt->_higig, 4196 HG_vlan_tag); 4197 4198 pkt_ptr[14] = vlan_ctl_tag >> 8; 4199 pkt_ptr[15] = vlan_ctl_tag & 0xff; 4200 } 4201 4202 /* Note: XGS and SL combinations not currently supported. */ 4203 return; 4204 } 4205 /* } */ 4206 #endif 4207 4208 /* No HG header */ 4209 if (BCM_PKT_HAS_SLTAG(pkt)) { /* Strip SL tag */ 4210 sal_memcpy(pkt->_sltag, &pkt->_pkt_data.data[16], 4); 4211 sal_memcpy(tmp_buf, pkt->_pkt_data.data, 16); 4212 pkt->_pkt_data.data += 4; /* Eliminated 4 byte SL tag */ 4213 sal_memcpy(pkt->_pkt_data.data, tmp_buf, 16); 4214 } 4215 4216 if (BCM_PKT_RX_VLAN_TAG_STRIP(pkt)) { /* Strip VLAN tag */ 4217 sal_memcpy(pkt->_vtag, &pkt->_pkt_data.data[12], 4); 4218 sal_memcpy(tmp_buf, pkt->_pkt_data.data, 12); 4219 pkt->_pkt_data.data += 4; /* Eliminated 4 byte VLAN tag */ 4220 sal_memcpy(pkt->_pkt_data.data, tmp_buf, 12); 4221 } 4222 } 4223 4224 4225 /* 4226 * Function: 4227 * rx_done_packet 4228 * Purpose: 4229 * Process a packet done done notification. 4230 * Parameters: 4231 * unit - StrataSwitch unit number. 4232 * dv - pointer to dv structure active 4233 * dcb - pointer to dcb completed. 4234 * Returns: 4235 * Nothing. 4236 * Notes: 4237 * This routine is called in interrupt context 4238 * 4239 * We count on the non-interrupt thread to update 4240 * the tokens for each queue. 4241 * 4242 * Only called for local units. 4243 */ 4244 4245 STATIC void 4246 rx_done_packet(int unit, dv_t *dv, dcb_t *dcb) 4247 { 4248 volatile bcm_pkt_t *pkt; 4249 int pkt_dcb_idx; 4250 int flags, chan; 4251 uint32 count; 4252 4253 chan = DV_CHANNEL(dv); 4254 pkt_dcb_idx = SOC_DCB_PTR2IDX(unit, dcb, dv->dv_dcb) / 4255 RX_DCB_PER_PKT(unit, chan); 4256 pkt = DV_PKT(dv, pkt_dcb_idx); 4257 assert(pkt_dcb_idx == pkt->_idx); 4258 4259 /* for jumbo packet */ 4260 flags = SOC_DCB_INTRINFO(unit, dcb, 0, &count); 4261 if (0 == (flags & SOC_DCB_INFO_PKTEND)) { 4262 if (RX_CHAN_FLAGS(unit, chan) & BCM_RX_F_OVERSIZED_OK) { 4263 /* Accept truncated packet */ 4264 pkt->flags |= BCM_RX_TRUNCATED; 4265 } else { 4266 /* No matter DCB mode is multi or single mode, the DV of packet 4267 will be free if the packet is !end & pkt_size > dma_len */ 4268 rx_ctl[unit]->dcb_errs++; 4269 MARK_PKT_PROCESSED_LOCAL(unit, chan, dv); 4270 return; 4271 } 4272 } 4273 #ifdef INCLUDE_KNET 4274 /* { */ 4275 /* Mask off indicator for kernel processing done */ 4276 count &= ~SOC_DCB_KNET_DONE; 4277 if (count == 0) { 4278 MARK_PKT_PROCESSED_LOCAL(unit, chan, dv); 4279 return; 4280 } 4281 /* } */ 4282 #endif 4283 4284 rx_ctl[unit]->tot_pkts++; 4285 rx_ctl[unit]->pkts_since_start++; 4286 if (!rx_control.thread_running) { 4287 /* Thread is not running; Ignore packet */ 4288 rx_ctl[unit]->thrd_not_running++; 4289 if (++DV_PKTS_PROCESSED(dv) == RX_PPC(unit)) { 4290 DV_STATE(dv) = DV_S_NEEDS_FILL; 4291 } 4292 return; 4293 } 4294 4295 if (RX_CHAN_RUNNING(unit, chan)) { 4296 /* Do not process packet if an error is noticed. */ 4297 #ifdef BCM_XGS3_SWITCH_SUPPORT 4298 /* { */ 4299 /* 4300 * XGS 3 RX error as a result of previously aborting RX DMA 4301 * First DCB in the RX packet must have Start bit set 4302 */ 4303 int abort_cleanup_done; 4304 4305 if (DV_ABORT_CLEANUP(dv)) { 4306 dcb_t *sop_dcb; 4307 4308 DV_ABORT_CLEANUP(dv) = 0; 4309 4310 sop_dcb = SOC_DCB_IDX2PTR(unit, 4311 dv->dv_dcb, 4312 pkt_dcb_idx * RX_DCB_PER_PKT(unit, chan)); 4313 if (SOC_DCB_RX_START_GET(unit, sop_dcb)) { 4314 abort_cleanup_done = 1; 4315 } else { 4316 abort_cleanup_done = 0; 4317 } 4318 } else { 4319 abort_cleanup_done = 1; 4320 } 4321 #else 4322 #define abort_cleanup_done 1 4323 /* } */ 4324 #endif 4325 if (!SOC_DCB_RX_ERROR_GET(unit, dcb) && abort_cleanup_done) { 4326 #ifdef BCM_DNX_SUPPORT 4327 /* 4328 * For DNX, there is dedicated rx channel per cpu port 4329 * Convert rx channel to dst port 4330 */ 4331 if (SOC_IS_DNX(unit)) 4332 { 4333 bcm_gport_t logical_port; 4334 int channel_index = 1; 4335 int rv = BCM_E_NONE; 4336 4337 /** Convert rx channel to rx port in the case of dedicated rx channel per cpu port */ 4338 BCM_PBMP_ITER(PBMP_CMIC(unit), logical_port) 4339 { 4340 if (channel_index == chan) 4341 { 4342 int base_q_pair = 0; 4343 BCM_GPORT_LOCAL_SET(pkt->dst_gport, logical_port); 4344 /** set queue_base to rx_port*/ 4345 rv = dnx_algo_port_base_q_pair_get(unit, logical_port, &base_q_pair); 4346 if (rv == BCM_E_NONE) 4347 { 4348 pkt->rx_port = base_q_pair; 4349 } 4350 /* 4351 * customer_feature_cpu_port_priorities = 1/2/8/64 4352 * in case of 1/2/8, cos = egq - queue_base, SOC port_properties should be consistent with customer_cpu_port_priorities 4353 * in case of 64, cos = egq - 192, SOC port_properties should be 8, EGQ 192 to 254 are mapped to 63 CoS in the ascending order 4354 * such that 192 to CoS0, 193 to CoS1, .., 254 to CoS62. 4355 */ 4356 if (rx_ctl[unit]->cpu_port_priorities == 64) 4357 { 4358 pkt->cos = pkt->rx_port - 192; 4359 } 4360 else 4361 { 4362 pkt->cos = 0; 4363 } 4364 break; 4365 } 4366 channel_index++; 4367 } 4368 } 4369 #endif 4370 rx_intr_process_packet(unit, dv, dcb, (bcm_pkt_t *)pkt); 4371 } else { 4372 rx_ctl[unit]->dcb_errs++; 4373 MARK_PKT_PROCESSED_LOCAL(unit, chan, dv); 4374 } 4375 } else {/* If not active, mark the packet as handled */ 4376 rx_ctl[unit]->not_running++; 4377 MARK_PKT_PROCESSED_LOCAL(unit, chan, dv); 4378 } 4379 } 4380 4381 /* 4382 * Function: 4383 * rx_done_chain 4384 * Purpose: 4385 * Handle chain done interrupt 4386 * Parameters: 4387 * unit - StrataSwitch unit number. 4388 * dv - pointer to dv completed. 4389 * Returns: 4390 * Nothing 4391 * Notes: 4392 */ 4393 4394 STATIC void 4395 rx_done_chain(int unit, dv_t *dv) 4396 { 4397 if (DV_STATE(dv) == DV_S_ACTIVE) { 4398 DV_STATE(dv) = DV_S_CHN_DONE; 4399 } 4400 4401 LOG_INFO(BSL_LS_BCM_RX, 4402 (BSL_META_U(unit, 4403 "RX Chain Done for c=%d, dv=%p\n"), 4404 dv->dv_channel, (void *)dv)); 4405 4406 if (DV_STATE(dv) == DV_S_NEEDS_FILL) { 4407 int chan = DV_CHANNEL(dv); 4408 rx_update_tokens(); 4409 rx_dv_fill(unit, chan, dv); 4410 if (DV_STATE(dv) != DV_S_FILLED) { 4411 RX_THREAD_NOTIFY(unit); 4412 } else { 4413 (void)rx_chain_start_or_sched(unit, chan, dv); 4414 } 4415 } 4416 4417 /* Might implement stall here */ 4418 } 4419 4420 /* 4421 * Function: 4422 * rx_done_reload 4423 * Purpose: 4424 * Handle reload done interrupt 4425 * Parameters: 4426 * unit - StrataSwitch unit number. 4427 * dv - pointer to dv completed. 4428 * Returns: 4429 * Nothing 4430 * Notes: 4431 */ 4432 4433 STATIC void 4434 rx_done_reload(int unit, dv_t *dv) 4435 { 4436 int pkts_processed = DV_PKTS_PROCESSED(dv); 4437 4438 LOG_DEBUG(BSL_LS_BCM_RX, 4439 (BSL_META_U(unit, 4440 "RX Reload Done for c=%d, dv=%p\n"), 4441 dv->dv_channel, (void *)dv)); 4442 4443 /* Make sure all packets are drained before sending DV for refill */ 4444 if (pkts_processed < RX_PPC(unit)) { 4445 DV_STATE(dv) = DV_S_RLD_DONE; 4446 } else if (pkts_processed == RX_PPC(unit)) { 4447 /* Let RX thread fill and concat DV */ 4448 DV_STATE(dv) = DV_S_NEEDS_FILL; 4449 RX_THREAD_NOTIFY(unit); 4450 } 4451 } 4452 4453 STATIC INLINE void 4454 pkt_len_get(int unit, int chan, bcm_pkt_t *pkt, dv_t *dv) 4455 { 4456 int len = 0; 4457 int i; 4458 4459 for (i = (pkt->_idx * RX_DCB_PER_PKT(unit, chan)); 4460 i < (pkt->_idx + 1) * RX_DCB_PER_PKT(unit, chan); i++) { 4461 len += SOC_DCB_XFERCOUNT_GET(unit, 4462 SOC_DCB_IDX2PTR(unit, dv->dv_dcb, i)); 4463 } 4464 pkt->tot_len = len; 4465 pkt->pkt_len = len; 4466 4467 /* Don't include some tags in "pkt_len" */ 4468 #ifdef BCM_XGS_SUPPORT 4469 /* { */ 4470 if (BCM_PKT_HAS_HGHDR(pkt)) { 4471 /* 4472 * HiGig pkts (Hercules only): Do not include header length; 4473 * but, VLAN is inserted into the packet, so need to add that 4474 * back in. 4475 */ 4476 pkt->pkt_len -= (sizeof(soc_higig_hdr_t) - sizeof(uint32)); 4477 } 4478 /* } */ 4479 #endif /* BCM_XGS_SUPPORT */ 4480 if (BCM_PKT_HAS_SLTAG(pkt)) { 4481 pkt->pkt_len -= sizeof(uint32); 4482 } 4483 if (BCM_PKT_RX_CRC_STRIP(pkt)) { 4484 pkt->pkt_len -= sizeof(uint32); 4485 } 4486 if (BCM_PKT_RX_VLAN_TAG_STRIP(pkt)) { 4487 pkt->pkt_len -= sizeof(uint32); 4488 } 4489 } 4490 4491 #ifdef BCM_XGS3_SWITCH_SUPPORT 4492 /* { */ 4493 #ifdef BCM_HIGIG2_SUPPORT 4494 /* { */ 4495 4496 STATIC INLINE void 4497 rx_higig2_gport_resolve(int unit, bcm_gport_t vp, int physical, 4498 bcm_gport_t *gport) 4499 { 4500 bcm_gport_t l_gport = BCM_GPORT_INVALID; 4501 4502 if (!physical) { 4503 #if defined(INCLUDE_L3) && defined(BCM_TRX_SUPPORT) 4504 /* { */ 4505 /* MPLS/MiM virtual port unicast */ 4506 #if defined(BCM_SCORPION_SUPPORT) 4507 /* { */ 4508 if (SOC_IS_SC_CQ(unit) && 4509 soc_feature(unit, soc_feature_subport)){ 4510 int grp; 4511 if (BCM_SUCCESS(_bcm_tr_subport_group_find(unit, 4512 vp, &grp))) { 4513 if (grp != -1) { 4514 BCM_GPORT_SUBPORT_PORT_SET(l_gport, vp); 4515 } 4516 } 4517 } else 4518 /* } */ 4519 #endif /* BCM_SCORPION_SUPPORT */ 4520 if (SOC_IS_TR_VL(unit)) { 4521 if (_bcm_vp_used_get(unit, vp, _bcmVpTypeMpls)) { 4522 BCM_GPORT_MPLS_PORT_ID_SET(l_gport, vp); 4523 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeMim)) { 4524 BCM_GPORT_MIM_PORT_ID_SET(l_gport, vp); 4525 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeSubport)) { 4526 BCM_GPORT_SUBPORT_PORT_SET(l_gport, vp); 4527 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeWlan)) { 4528 BCM_GPORT_WLAN_PORT_ID_SET(l_gport, vp); 4529 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) { 4530 BCM_GPORT_VLAN_PORT_ID_SET(l_gport, vp); 4531 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVxlan)) { 4532 BCM_GPORT_VXLAN_PORT_ID_SET(l_gport, vp); 4533 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeL2Gre)) { 4534 BCM_GPORT_L2GRE_PORT_ID_SET(l_gport, vp); 4535 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeTrill)) { 4536 BCM_GPORT_TRILL_PORT_ID_SET(l_gport, vp); 4537 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) { 4538 BCM_GPORT_NIV_PORT_ID_SET(l_gport, vp); 4539 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeExtender)) { 4540 BCM_GPORT_EXTENDER_PORT_ID_SET(l_gport, vp); 4541 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeFlow)) { 4542 BCM_GPORT_FLOW_PORT_ID_SET(l_gport, vp); 4543 } 4544 } 4545 /* } */ 4546 #endif /* INCLUDE_L3 && BCM_TRX_SUPPORT */ 4547 } else { 4548 BCM_GPORT_MODPORT_SET(l_gport, (vp >> 8) & 0xff, vp & 0xff); 4549 } 4550 4551 *gport = l_gport; 4552 } 4553 4554 #if defined(INCLUDE_L3) && defined(BCM_TRX_SUPPORT) 4555 /* { */ 4556 STATIC INLINE void 4557 rx_higig2_vpn_resolve(int unit, bcm_vlan_t vni, bcm_vlan_t *vpn) 4558 { 4559 if (SOC_IS_TR_VL(unit)) { 4560 if (_bcm_vfi_used_get(unit, vni, _bcmVfiTypeMpls)) { 4561 _BCM_VPN_SET(*vpn, _BCM_VPN_TYPE_VFI, vni); 4562 } else if (_bcm_vfi_used_get(unit, vni, _bcmVfiTypeMim)) { 4563 _BCM_VPN_SET(*vpn, _BCM_VPN_TYPE_VFI, vni); 4564 } else if (_bcm_vfi_used_get(unit, vni, _bcmVfiTypeL2Gre)) { 4565 _BCM_VPN_SET(*vpn, _BCM_VPN_TYPE_VFI, vni); 4566 } else if (_bcm_vfi_used_get(unit, vni, _bcmVfiTypeVxlan)) { 4567 _BCM_VPN_SET(*vpn, _BCM_VPN_TYPE_VFI, vni); 4568 } 4569 } 4570 } 4571 /* } */ 4572 4573 STATIC INLINE void 4574 rx_svp_vpn_resolve(int unit, int vp, bcm_vlan_t *vpn) 4575 { 4576 *vpn = _bcm_vp_vfi_get(unit, vp); 4577 } 4578 #endif /* INCLUDE_L3 && BCM_TRX_SUPPORT */ 4579 4580 #if defined(INCLUDE_L3) && defined(BCM_XGS3_SWITCH_SUPPORT) 4581 /* { */ 4582 STATIC INLINE void 4583 rx_higig2_encap_resolve(int unit, uint32 repl_id, bcm_if_t *encap) 4584 { 4585 4586 if (soc_feature(unit, soc_feature_remote_encap)) { 4587 /* TR3 only has next hop encoding */ 4588 *encap = repl_id + BCM_XGS3_EGRESS_IDX_MIN(unit); 4589 } else if (SOC_IS_TRIUMPH2(unit) || SOC_IS_VALKYRIE2(unit) || 4590 SOC_IS_APOLLO(unit) || SOC_IS_TD_TT(unit) || 4591 SOC_IS_KATANA(unit)) { 4592 if (0 != (repl_id & (1 << 14))) { 4593 *encap = (repl_id & ((1 << 14) - 1)) + 4594 BCM_XGS3_EGRESS_IDX_MIN(unit); 4595 } else { 4596 /* Just an L3 interface */ 4597 *encap = repl_id; 4598 } 4599 } else { 4600 /* Legacy devices only have L3 interfaces */ 4601 *encap = repl_id; 4602 } 4603 } 4604 /* } */ 4605 #endif /* INCLUDE_L3 && BCM_XGS3_SWITCH_SUPPORT */ 4606 /* } */ 4607 #endif /* BCM_HIGIG2_SUPPORT */ 4608 4609 4610 /* 4611 * Function: 4612 * rx_higig_info_decode 4613 * Purpose: 4614 * Decomposes the info in Higig headers and puts them into the 4615 * bmc_pkt_t informational members. 4616 * Parameters: 4617 * unit - StrataSwitch unit number. 4618 * pkt - pointer to completed DCB. 4619 * Returns: 4620 * Nothing. 4621 */ 4622 void 4623 rx_higig_info_decode(int unit, bcm_pkt_t *pkt) 4624 { 4625 soc_higig_hdr_t *xgh; 4626 xgh = (soc_higig_hdr_t *)(pkt->_higig); 4627 4628 #ifdef BCM_HIGIG2_SUPPORT 4629 /* { */ 4630 if (soc_feature(unit, soc_feature_higig2) || 4631 soc_feature(unit, soc_feature_rx_pkt_hdr_format_higig2)) { 4632 /* CMIC RX packets are in HiGig2 format if the device supports it */ 4633 soc_higig2_hdr_t *xgh2; 4634 bcm_gport_t raw_port, gport; 4635 int physical = FALSE; 4636 int remote_encap = FALSE; 4637 #if defined(BCM_BRADLEY_SUPPORT) 4638 /* { */ 4639 int mc_index; 4640 int bcast_size, mcast_size, ipmc_size; 4641 /* } */ 4642 #endif /* BCM_BRADLEY_SUPPORT */ 4643 #if defined(INCLUDE_L3) && defined(BCM_TRX_SUPPORT) 4644 /* { */ 4645 bcm_vlan_t vni = 0, vpn=0; 4646 /* } */ 4647 #endif /* INCLUDE_L3 && BCM_TRX_SUPPORT */ 4648 #if defined(INCLUDE_L3) && defined(BCM_XGS3_SWITCH_SUPPORT) 4649 /* { */ 4650 uint32 repl_id; 4651 /* } */ 4652 #endif /* INCLUDE_L3 && BCM_XGS3_SWITCH_SUPPORT */ 4653 4654 if (SOC_REMOTE_ENCAP(unit) && 4655 soc_feature(unit, soc_feature_remote_encap)) { 4656 remote_encap = TRUE; 4657 } 4658 4659 xgh2 = (soc_higig2_hdr_t *)(pkt->_higig); 4660 4661 /* Start with the FRC fields */ 4662 pkt->prio_int = soc_higig2_field_get(unit, xgh2, HG_tc); 4663 pkt->multicast_group = soc_higig2_field_get(unit, xgh2, HG_mgid); 4664 pkt->stk_load_balancing_number = 4665 soc_higig2_field_get(unit, xgh2, HG_lbid); 4666 switch (soc_higig2_field_get(unit, xgh2, HG_dp)) { 4667 case 0: 4668 pkt->color = bcmColorGreen; 4669 break; 4670 case 3: 4671 pkt->color = bcmColorYellow; 4672 break; 4673 case 1: 4674 pkt->color = bcmColorRed; 4675 break; 4676 default: 4677 pkt->color = bcmColorBlack; 4678 break; 4679 } 4680 /* Other FRC fields come from DCB values, so don't overwrite them */ 4681 4682 switch (soc_higig2_field_get(unit, xgh2, HG_ppd_type)) { 4683 case 0: /* PPD0 */ 4684 if (soc_higig2_field_get(unit, xgh2, HG_ingress_tagged)) { 4685 pkt->rx_untagged &= ~BCM_PKT_OUTER_UNTAGGED; 4686 } else { 4687 pkt->rx_untagged |= BCM_PKT_OUTER_UNTAGGED; 4688 } 4689 if (soc_higig2_field_get(unit, xgh2, HG_mirror)) { 4690 pkt->stk_flags |= BCM_PKT_STK_F_MIRROR; 4691 } 4692 if (soc_higig2_field_get(unit, xgh2, HG_l3)) { 4693 pkt->flags |= BCM_PKT_F_ROUTED; 4694 } 4695 pkt->vlan = soc_higig2_field_get(unit, xgh2, HG_vlan_id); 4696 pkt->vlan_pri = soc_higig2_field_get(unit, xgh2, HG_vlan_pri); 4697 pkt->vlan_cfi = soc_higig2_field_get(unit, xgh2, HG_vlan_cfi); 4698 pkt->pfm = soc_higig2_field_get(unit, xgh2, HG_pfm); 4699 if (soc_higig2_field_get(unit, xgh2, HG_preserve_dscp)) { 4700 pkt->stk_flags |= BCM_PKT_STK_F_PRESERVE_DSCP; 4701 } 4702 if (soc_higig2_field_get(unit, xgh2, HG_preserve_dot1p)) { 4703 pkt->stk_flags |= BCM_PKT_STK_F_PRESERVE_PKT_PRIO; 4704 } 4705 #if defined(INCLUDE_L3) && defined(BCM_XGS3_SWITCH_SUPPORT) 4706 /* { */ 4707 if (remote_encap) { 4708 pkt->stk_flags |= BCM_PKT_STK_F_ENCAP_ID; 4709 repl_id = 4710 soc_higig2_field_get(unit, xgh2, HG_replication_id); 4711 rx_higig2_encap_resolve(unit, repl_id, &(pkt->stk_encap_id)); 4712 } 4713 /* } */ 4714 #endif /* INCLUDE_L3 && BCM_XGS3_SWITCH_SUPPORT */ 4715 break; 4716 case 1: /* PPD1 */ 4717 pkt->stk_classification_tag = 4718 soc_higig2_field_get(unit, xgh2, HG_ctag); 4719 pkt->stk_flags |= BCM_PKT_STK_F_CLASSIFICATION_TAG; 4720 pkt->vlan = soc_higig2_field_get(unit, xgh2, HG_vlan_id); 4721 pkt->vlan_pri = soc_higig2_field_get(unit, xgh2, HG_vlan_pri); 4722 pkt->vlan_cfi = soc_higig2_field_get(unit, xgh2, HG_vlan_cfi); 4723 pkt->pfm = soc_higig2_field_get(unit, xgh2, HG_pfm); 4724 break; 4725 case 2: /* PPD2 */ 4726 #if defined(INCLUDE_L3) && defined(BCM_TRX_SUPPORT) 4727 /* { */ 4728 vni = soc_higig2_field_get(unit, xgh2, HG_vni); 4729 rx_higig2_vpn_resolve(unit, vni, &vpn); 4730 if (_BCM_VPN_IS_SET(vpn)) { 4731 pkt->vlan = vpn; 4732 } 4733 /* } */ 4734 #endif /* INCLUDE_L3 && BCM_TRX_SUPPORT */ 4735 #if defined(INCLUDE_L3) && defined(BCM_XGS3_SWITCH_SUPPORT) 4736 /* { */ 4737 if (remote_encap) { 4738 pkt->stk_flags |= BCM_PKT_STK_F_ENCAP_ID; 4739 repl_id = 4740 soc_higig2_field_get(unit, xgh2, HG_replication_id); 4741 rx_higig2_encap_resolve(unit, repl_id, &(pkt->stk_encap_id)); 4742 } 4743 /* } */ 4744 #endif /* INCLUDE_L3 && BCM_XGS3_SWITCH_SUPPORT */ 4745 if (soc_higig2_field_get(unit, xgh2, HG_multipoint)) { 4746 switch (soc_higig2_field_get(unit, xgh2, HG_fwd_type)) { 4747 case 4: 4748 pkt->stk_forward = BCM_PKT_STK_FORWARD_L2_MULTICAST; 4749 break; 4750 case 5: 4751 pkt->stk_forward = 4752 BCM_PKT_STK_FORWARD_L2_MULTICAST_UNKNOWN; 4753 break; 4754 case 2: 4755 pkt->stk_forward = BCM_PKT_STK_FORWARD_L3_MULTICAST; 4756 break; 4757 case 3: 4758 pkt->stk_forward = 4759 BCM_PKT_STK_FORWARD_L3_MULTICAST_UNKNOWN; 4760 break; 4761 case 6: 4762 pkt->stk_forward = 4763 BCM_PKT_STK_FORWARD_L2_UNICAST_UNKNOWN; 4764 break; 4765 case 7: 4766 pkt->stk_forward = BCM_PKT_STK_FORWARD_BROADCAST; 4767 break; 4768 default: 4769 pkt->stk_forward = BCM_PKT_STK_FORWARD_COUNT; 4770 break; 4771 } 4772 if (!remote_encap) { 4773 pkt->multicast_group = 4774 soc_higig2_field_get(unit, xgh2, HG_dst_vp); 4775 } 4776 } else { 4777 switch (soc_higig2_field_get(unit, xgh2, HG_fwd_type)) { 4778 case 0: 4779 pkt->stk_forward = BCM_PKT_STK_FORWARD_CPU; 4780 break; 4781 case 4: 4782 pkt->stk_forward = BCM_PKT_STK_FORWARD_L2_UNICAST; 4783 break; 4784 case 2: 4785 pkt->stk_forward = BCM_PKT_STK_FORWARD_L3_UNICAST; 4786 break; 4787 default: 4788 pkt->stk_forward = BCM_PKT_STK_FORWARD_COUNT; 4789 break; 4790 } 4791 if (!remote_encap) { 4792 raw_port = soc_higig2_field_get(unit, xgh2, HG_dst_vp); 4793 physical = 4794 soc_higig2_field_get(unit, xgh2, HG_dst_type) != 0; 4795 rx_higig2_gport_resolve(unit, raw_port, 4796 physical, &gport); 4797 if (gport != BCM_GPORT_INVALID) { 4798 pkt->dst_gport = gport; 4799 pkt->stk_flags |= BCM_PKT_STK_F_DST_PORT; 4800 } 4801 } 4802 } 4803 raw_port = soc_higig2_field_get(unit, xgh2, HG_src_vp); 4804 physical = soc_higig2_field_get(unit, xgh2, HG_src_type) != 0; 4805 rx_higig2_gport_resolve(unit, raw_port, physical, &gport); 4806 if (gport != BCM_GPORT_INVALID) { 4807 pkt->src_gport = gport; 4808 pkt->stk_flags |= BCM_PKT_STK_F_SRC_PORT; 4809 } 4810 if (soc_higig2_field_get(unit, xgh2, HG_mirror)) { 4811 pkt->stk_flags |= BCM_PKT_STK_F_MIRROR; 4812 } 4813 if (soc_higig2_field_get(unit, xgh2, HG_donot_modify)) { 4814 pkt->stk_flags |= BCM_PKT_STK_F_DO_NOT_MODIFY; 4815 } 4816 if (soc_higig2_field_get(unit, xgh2, HG_donot_learn)) { 4817 pkt->stk_flags |= BCM_PKT_STK_F_DO_NOT_LEARN; 4818 } 4819 if (soc_higig2_field_get(unit, xgh2, HG_lag_failover)) { 4820 pkt->stk_flags |= BCM_PKT_STK_F_TRUNK_FAILOVER; 4821 } 4822 if (soc_higig2_field_get(unit, xgh2, HG_protection_status)) { 4823 pkt->stk_flags |= BCM_PKT_STK_F_FAILOVER; 4824 } 4825 if (soc_higig2_field_get(unit, xgh2, HG_preserve_dscp)) { 4826 pkt->stk_flags |= BCM_PKT_STK_F_PRESERVE_DSCP; 4827 } 4828 if (soc_higig2_field_get(unit, xgh2, HG_preserve_dot1p)) { 4829 pkt->stk_flags |= BCM_PKT_STK_F_PRESERVE_PKT_PRIO; 4830 } 4831 break; 4832 case 3: /* PPD3 */ 4833 raw_port = soc_higig2_field_get(unit, xgh2, HG_src_vp); 4834 physical = soc_higig2_field_get(unit, xgh2, HG_src_type) != 0; 4835 rx_higig2_gport_resolve(unit, raw_port, physical, &gport); 4836 if (gport != BCM_GPORT_INVALID) { 4837 pkt->src_gport = gport; 4838 pkt->stk_flags |= BCM_PKT_STK_F_SRC_PORT; 4839 } 4840 if (soc_higig2_field_get(unit, xgh2, HG_preserve_dscp)) { 4841 pkt->stk_flags |= BCM_PKT_STK_F_PRESERVE_DSCP; 4842 } 4843 if (soc_higig2_field_get(unit, xgh2, HG_preserve_dot1p)) { 4844 pkt->stk_flags |= BCM_PKT_STK_F_PRESERVE_PKT_PRIO; 4845 } 4846 if (soc_higig2_field_get(unit, xgh2, HG_donot_learn)) { 4847 pkt->stk_flags |= BCM_PKT_STK_F_DO_NOT_LEARN; 4848 } 4849 if (soc_higig2_field_get(unit, xgh2, 4850 HG_data_container_type) == 1) { 4851 /* Offload overlay */ 4852 pkt->stk_classification_tag = 4853 soc_higig2_field_get(unit, xgh2, HG_ctag); 4854 pkt->stk_flags |= BCM_PKT_STK_F_CLASSIFICATION_TAG; 4855 if (soc_higig2_field_get(unit, xgh2, HG_deferred_drop)) { 4856 pkt->stk_flags |= BCM_PKT_STK_F_DEFERRED_DROP; 4857 } 4858 if (soc_higig2_field_get(unit, xgh2, 4859 HG_deferred_change_pkt_pri)) { 4860 pkt->stk_flags |= BCM_PKT_STK_F_DEFERRED_CHANGE_PKT_PRIO; 4861 pkt->stk_pkt_prio = 4862 soc_higig2_field_get(unit, xgh2, HG_new_pkt_pri); 4863 } 4864 if (soc_higig2_field_get(unit, xgh2, 4865 HG_deferred_change_dscp)) { 4866 pkt->stk_flags |= BCM_PKT_STK_F_DEFERRED_CHANGE_DSCP; 4867 pkt->stk_dscp = 4868 soc_higig2_field_get(unit, xgh2, HG_new_dscp); 4869 } 4870 switch (soc_higig2_field_get(unit, xgh2, HG_vxlt_done)) { 4871 case 0: 4872 pkt->stk_flags |= BCM_PKT_STK_F_VLAN_TRANSLATE_NONE; 4873 break; 4874 case 1: 4875 pkt->stk_flags |= BCM_PKT_STK_F_VLAN_TRANSLATE_UNCHANGED; 4876 break; 4877 case 3: 4878 pkt->stk_flags |= BCM_PKT_STK_F_VLAN_TRANSLATE_CHANGED; 4879 break; 4880 default: 4881 /* Unknown type, no change */ 4882 break; 4883 } 4884 } /* Else unknown overlay, nothing to parse */ 4885 break; 4886 default: 4887 /* Unknown type, nothing to parse */ 4888 break; 4889 } 4890 4891 #if defined(INCLUDE_L3) && defined(BCM_TRX_SUPPORT) 4892 if (SOC_IS_TRIDENT2PLUS(unit) && 4893 BCM_GPORT_IS_MPLS_PORT(pkt->src_gport) && 4894 !_BCM_VPN_IS_SET(pkt->vlan)) { 4895 rx_svp_vpn_resolve(unit, BCM_GPORT_MPLS_PORT_ID_GET(pkt->src_gport), 4896 &pkt->vlan); 4897 } 4898 #endif 4899 #if defined(BCM_BRADLEY_SUPPORT) 4900 /* { */ 4901 if ((SOC_HIGIG_OP_IPMC == pkt->opcode) || 4902 (SOC_HIGIG_OP_MC == pkt->opcode)) { 4903 /* Resolve multicast group */ 4904 /* We can ignore the following return code because it connot 4905 * return anything but SOC_E_NONE */ 4906 (void) soc_hbx_higig2_mcast_sizes_get(unit, &bcast_size, 4907 &mcast_size, &ipmc_size); 4908 4909 mc_index = pkt->multicast_group; 4910 if (SOC_HIGIG_OP_IPMC == pkt->opcode) { 4911 mc_index -= mcast_size + bcast_size; 4912 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3) 4913 /* { */ 4914 if (SOC_IS_TRX(unit)) { 4915 bcm_multicast_t group; 4916 int rv; 4917 rv = _bcm_tr_multicast_ipmc_group_type_get(unit, 4918 mc_index, 4919 &group); 4920 if (BCM_E_NONE == rv) { 4921 pkt->multicast_group = group; 4922 } else { 4923 /* Default to L3 IPMC type */ 4924 _BCM_MULTICAST_GROUP_SET(pkt->multicast_group, 4925 _BCM_MULTICAST_TYPE_L3, 4926 mc_index); 4927 } 4928 } else 4929 /* } */ 4930 #endif /* BCM_TRIUMPH_SUPPORT && INCLUDE_L3 */ 4931 { 4932 _BCM_MULTICAST_GROUP_SET(pkt->multicast_group, 4933 _BCM_MULTICAST_TYPE_L3, 4934 mc_index); 4935 } 4936 } else { /* SOC_HIGIG_OP_MC */ 4937 mc_index -= bcast_size; 4938 _BCM_MULTICAST_GROUP_SET(pkt->multicast_group, 4939 _BCM_MULTICAST_TYPE_L2, mc_index); 4940 } 4941 } 4942 /* } */ 4943 #endif /* BCM_BRADLEY_SUPPORT */ 4944 } else 4945 /* } */ 4946 #endif /* BCM_HIGIG2_SUPPORT */ 4947 { 4948 /* Higig decoding */ 4949 pkt->prio_int = soc_higig_field_get(unit, xgh, HG_cos); 4950 pkt->pfm = soc_higig_field_get(unit, xgh, HG_pfm); 4951 switch (soc_higig_field_get(unit, xgh, HG_cng)) { 4952 case 0: 4953 pkt->color = bcmColorGreen; 4954 break; 4955 case 3: 4956 pkt->color = bcmColorYellow; 4957 break; 4958 case 1: 4959 pkt->color = bcmColorRed; 4960 break; 4961 default: 4962 pkt->color = bcmColorBlack; 4963 break; 4964 } 4965 if (soc_higig_field_get(unit, xgh, HG_hdr_format) == 0) { 4966 /* Overlay 1 */ 4967 if (SOC_IS_HB_GW(unit)) { 4968 if (soc_higig_field_get(unit, xgh, HG_donot_modify)) { 4969 pkt->stk_flags |= BCM_PKT_STK_F_DO_NOT_MODIFY; 4970 } 4971 if (soc_higig_field_get(unit, xgh, HG_donot_learn)) { 4972 pkt->stk_flags |= BCM_PKT_STK_F_DO_NOT_LEARN; 4973 } 4974 if (soc_higig_field_get(unit, xgh, HG_lag_failover)) { 4975 pkt->stk_flags |= BCM_PKT_STK_F_TRUNK_FAILOVER; 4976 } 4977 } 4978 if (soc_higig_field_get(unit, xgh, HG_mirror)) { 4979 pkt->stk_flags |= BCM_PKT_STK_F_MIRROR; 4980 } 4981 if (soc_higig_field_get(unit, xgh, HG_l3)) { 4982 pkt->flags |= BCM_PKT_F_ROUTED; 4983 } 4984 } else if (soc_higig_field_get(unit, xgh, HG_hdr_format) == 1) { 4985 /* Overlay 2 */ 4986 pkt->stk_classification_tag = 4987 soc_higig_field_get(unit, xgh, HG_ctag); 4988 pkt->stk_flags |= BCM_PKT_STK_F_CLASSIFICATION_TAG; 4989 } /* Else reserved format */ 4990 4991 if ((pkt->rx_untagged) && (pkt->flags & BCM_RX_MIRRORED)) { 4992 pkt->vlan = soc_higig_field_get(unit, xgh, HG_vlan_id); 4993 pkt->vlan_pri = soc_higig_field_get(unit, xgh, HG_vlan_pri); 4994 pkt->vlan_cfi = soc_higig_field_get(unit, xgh, HG_vlan_cfi); 4995 } 4996 } 4997 } 4998 4999 #if defined(BCM_MONTEREY_SUPPORT) 5000 void 5001 rx_timestamp_convert(int unit, bcm_pkt_t *pkt) 5002 { 5003 if (SOC_IS_MONTEREY(unit)) { 5004 /* uint32 lower, upper; */ 5005 uint64 T1; /* Current timestamper value */ 5006 uint64 T2; /* RX packet timestamp */ 5007 5008 COMPILER_64_ZERO( T1 ); 5009 COMPILER_64_ZERO( T2 ); 5010 /* Read the current timestamper */ 5011 READ_NS_TIMESYNC_TS1_TIMESTAMP_UPPER_STATUSr(unit, &u64_H(T1)/*&upper*/); 5012 READ_NS_TIMESYNC_TS1_TIMESTAMP_LOWER_STATUSr(unit, &u64_L(T1)/*&lower*/); 5013 5014 /* Construct T2, 52b */ 5015 u64_L(T2) = pkt->rx_timestamp; 5016 COMPILER_64_SHL(T2, 4); 5017 u64_L(T2) = u64_L(T2) | (pkt->rx_timestamp_upper & 0xF); 5018 5019 if (COMPILER_64_BITTEST(T1, 35) == COMPILER_64_BITTEST(T2, 35)) { 5020 /* T2[51..36] = T1[51..36] */ 5021 u64_H(T2) = (u64_H(T2) & 0xF) | (u64_H(T1) & 0xFFFF0); 5022 } 5023 5024 if ((COMPILER_64_BITTEST(T1,35)==1) && (COMPILER_64_BITTEST(T2,35)==0)) { 5025 /* T2[51..36] = T1[51..36] */ 5026 u64_H(T2) = (u64_H(T2) & 0xF) | (u64_H(T1) & 0xFFFF0); 5027 } 5028 5029 if ((COMPILER_64_BITTEST(T1,35)==0) && (COMPILER_64_BITTEST(T2,35)==1)) { 5030 /* T2[51..36] = T1[51..36] - 1 */ 5031 u64_H(T2) = (u64_H(T2) & 0xF) | ((u64_H(T1) & 0xFFFF0) - 0x10); 5032 } 5033 5034 pkt->rx_timestamp_upper = u64_H(T2); 5035 pkt->rx_timestamp = u64_L(T2); 5036 } 5037 } 5038 #endif /* BCM_MONTEREY_SUPPORT */ 5039 5040 /* 5041 * Function: 5042 * rx_olp_info_decode 5043 * Purpose: 5044 * Decomposes the info in olp header and puts them into the 5045 * bcm_pkt_t informational members. 5046 * Parameters: 5047 * unit - StrataSwitch unit number. 5048 * pkt - pointer to completed DCB. 5049 * Returns: 5050 * Nothing. 5051 */ 5052 #if defined (BCM_TRIDENT2PLUS_SUPPORT) || defined (BCM_SABER2_SUPPORT) 5053 /* { */ 5054 void 5055 rx_olp_info_decode(int unit, bcm_pkt_t *pkt) 5056 { 5057 soc_olp_rx_hdr_t oh; 5058 uint8 *hdr = pkt->_olp_hdr; 5059 #if defined (BCM_SABER2_SUPPORT) 5060 /* { */ 5061 int is_lmplusdm_pkt = 0; 5062 /* } */ 5063 #endif 5064 5065 shr_olp_rx_header_unpack(hdr, &oh); 5066 5067 pkt->rx_oam_pkt_type = SOC_OLP_OAM_TYPE_MAP(SOC_OLP_RX_HDR_TYPE_GET(&oh), 5068 SOC_OLP_RX_HDR_STYPE_GET(&oh)); 5069 pkt->src_port = SOC_OLP_RX_PORT_GET(&oh); 5070 pkt->src_mod = SOC_OLP_RX_MODID_GET(&oh); 5071 5072 #if defined (BCM_SABER2_SUPPORT) 5073 /* { */ 5074 /* Check for LM + DM. It is supported only on SB2 */ 5075 if (SOC_IS_SABER2(unit)) { 5076 is_lmplusdm_pkt = SOC_OLP_RX_OAM_SAMPLE_TYPE_EXT_GET(&oh); 5077 /* coverity[result_independent_of_operands] */ 5078 pkt->timestamp_mode = SB2_SOC_OLP_RX_TIMESTAMP_MODE_GET( 5079 SOC_OLP_RX_SAMPLE_TYPE_GET(&oh), 5080 is_lmplusdm_pkt); 5081 } 5082 /* } */ 5083 #endif 5084 5085 #if defined (BCM_TRIDENT2PLUS_SUPPORT) 5086 /* { */ 5087 if (SOC_IS_TRIDENT2PLUS(unit) || SOC_IS_APACHE(unit)) { 5088 pkt->timestamp_mode = SOC_OLP_RX_SAMPLE_TYPE_GET(&oh); 5089 if(pkt->timestamp_mode != BCM_PKT_TIMESTAMP_MODE_NONE){ 5090 pkt->timestamp_mode--; 5091 } 5092 } 5093 /* } */ 5094 #endif 5095 5096 #if defined (BCM_APACHE_SUPPORT) 5097 /* { */ 5098 if (SOC_IS_APACHE(unit)) { 5099 /* Derive resolved LM counter index from session_id */ 5100 pkt->oam_counter_size = 1; 5101 pkt->oam_counter[0].counter_object_id = SOC_OLP_RX_SESSION_ID_GET(&oh); 5102 } 5103 /* } */ 5104 #endif 5105 5106 #if defined (BCM_SABER2_SUPPORT) 5107 /* { */ 5108 if (is_lmplusdm_pkt) { /* LM + DM case only available for Saber2 */ 5109 /* Only 32 bit counter is available in case of LM + DM */ 5110 pkt->oam_counter[0].counter_value_lower = SOC_OLP_RX_SAMPLE_VALUE_EXT_GET(&oh); 5111 pkt->oam_counter_size = 1; 5112 } 5113 /* } */ 5114 #endif 5115 if(pkt->timestamp_mode == BCM_PKT_TIMESTAMP_MODE_NONE) { /* LM only case */ 5116 pkt->oam_counter[0].counter_value_lower = SOC_OLP_RX_TIMESTAMP_GET(&oh); 5117 pkt->oam_counter[0].counter_value_upper = SOC_OLP_RX_TIMESTAMP_UPPER_GET(&oh); 5118 pkt->oam_counter_size = 1; 5119 } else { /* DM only case */ 5120 if (soc_feature(unit, soc_feature_rx_timestamp)) { 5121 pkt->rx_timestamp = SOC_OLP_RX_TIMESTAMP_GET(&oh); 5122 } 5123 if (soc_feature(unit, soc_feature_rx_timestamp_upper)) { 5124 pkt->rx_timestamp_upper = SOC_OLP_RX_TIMESTAMP_UPPER_GET(&oh); 5125 } 5126 } 5127 pkt->oam_hdr_offset = SOC_OLP_RX_OAM_PDU_OFFSET_GET(&oh) + sizeof(soc_olp_rx_pkt_t); 5128 5129 RX_INFO((BSL_META_U(unit,"%s,h1 0x%x, h2 0x%x, h3 0x%x, h4 0x%x, not filled reason 0x%x" 5130 "hdrT 0x%x,hdrst 0x%x,modid %d,srcP %d," 5131 "oamType %d,timeMod %d,tu 0x%x, tl 0x%x,oamOff 0x%x,matchRule 0x%x " 5132 "oamCouterSz %u, oam_counter0.lwr %u, oam_counter0.upr %u, counter_object_id0 %u" 5133 "\n"), 5134 __FUNCTION__,oh.u1.h1,oh.u2.h2,oh.u3.h3,oh.u4.h4,pkt->rx_reason, 5135 SOC_OLP_RX_HDR_TYPE_GET(&oh),SOC_OLP_RX_HDR_STYPE_GET(&oh),pkt->src_mod,pkt->src_port, 5136 pkt->rx_oam_pkt_type,pkt->timestamp_mode,pkt->rx_timestamp_upper,pkt->rx_timestamp, 5137 pkt->oam_hdr_offset, pkt->rx_matched, pkt->oam_counter_size, 5138 pkt->oam_counter[0].counter_value_lower, pkt->oam_counter[0].counter_value_upper, 5139 pkt->oam_counter[0].counter_object_id)); 5140 } 5141 /* } */ 5142 #endif /* BCM_TRIDENT2PLUS_SUPPORT || BCM_SABER2_SUPPORT*/ 5143 5144 /* } */ 5145 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 5146 5147 #if defined(INCLUDE_RCPU) && defined(BCM_ESW_SUPPORT) && defined(BCM_XGS3_SWITCH_SUPPORT) 5148 /* { */ 5149 extern int rx_rcpu_base_info_parse(bcm_pkt_t *rx_pkt); 5150 extern int rx_rcpu_intr_process_packet(bcm_pkt_t *pkt, int *runit); 5151 /* } */ 5152 #endif 5153 5154 STATIC void 5155 rx_default_parser(int unit, bcm_pkt_t *pkt) 5156 { 5157 bcm_dma_chan_t chan; 5158 int idx, runit; 5159 dv_t *dv ; 5160 dcb_t *dcb ; 5161 #if defined (BCM_ESW_SUPPORT) 5162 /* { */ 5163 int olp_encap_oam_pkt = 0; 5164 /* } */ 5165 #endif 5166 5167 dv = pkt->_dv; 5168 dcb = pkt->_dcb; 5169 idx = pkt->_idx; 5170 chan = DV_CHANNEL(dv); 5171 5172 /* If single buffer used to DMA packet, may need cleanup */ 5173 if (RX_CHAN_FLAGS(unit, chan) & BCM_RX_F_MULTI_DCB) { 5174 multi_dcb_fillin(unit, pkt, dv, idx); 5175 } else if (!SOC_IS_RCPU_UNIT(unit)) { 5176 single_dcb_fillin(unit, pkt); 5177 } 5178 5179 runit = unit; 5180 5181 if (SOC_IS_RCPU_UNIT(unit)) { 5182 #if defined(INCLUDE_RCPU) && defined(BCM_ESW_SUPPORT) && defined(BCM_XGS3_SWITCH_SUPPORT) 5183 /* { */ 5184 rx_rcpu_intr_process_packet(pkt, &runit); 5185 /* } */ 5186 #endif 5187 } else if (SOC_IS_XGS_SWITCH(unit)) { /* Get XGS HiGig info from DMA desc */ 5188 #ifdef BCM_ESW_SUPPORT 5189 /* { */ 5190 #ifdef BCM_XGS_SUPPORT 5191 /* { */ 5192 int src_port_tgid; 5193 5194 pkt->rx_matched = SOC_DCB_RX_MATCHRULE_GET(unit, dcb); 5195 #if defined (BCM_TRIDENT2PLUS_SUPPORT) || defined (BCM_SABER2_SUPPORT) 5196 /* { */ 5197 if(soc_feature(unit, soc_feature_cpu_as_olp)) { 5198 #ifdef BCM_TRIDENT2PLUS_SUPPORT 5199 /* { */ 5200 if(SOC_IS_TRIDENT2PLUS(unit)) { 5201 olp_encap_oam_pkt = BCM_PKT_RX_OLP(unit,pkt); 5202 } else 5203 /* } */ 5204 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 5205 { 5206 olp_encap_oam_pkt = SOC_DCB_OLP_ENCAP_OAM_PKT_GET(unit, dcb); 5207 #if defined(BCM_TOMAHAWK_SUPPORT) 5208 /* { */ 5209 if (SOC_INFO(unit).th_ctc_replace_enabled) { 5210 pkt->rx_matched = SOC_DCB_RX_HG2_EXT_EH_TYPE_GET(unit, dcb); 5211 } else 5212 /* } */ 5213 #endif /* BCM_TOMAHAWK_SUPPORT */ 5214 { 5215 pkt->rx_matched = SOC_DCB_RX_MATCHRULE_GET(unit, dcb); 5216 } 5217 } 5218 } 5219 5220 if(olp_encap_oam_pkt) { 5221 sal_memcpy(pkt->_olp_hdr, (pkt->pkt_data->data + sizeof(soc_olp_l2_hdr_t)), 5222 sizeof(soc_olp_rx_hdr_t)); 5223 rx_olp_info_decode(unit, pkt); 5224 src_port_tgid = pkt->src_port; 5225 } else 5226 /* } */ 5227 #endif /* BCM_OLP_SUPPORT */ 5228 { 5229 pkt->src_mod = SOC_DCB_RX_SRCMOD_GET(unit, dcb); 5230 src_port_tgid = SOC_DCB_RX_SRCPORT_GET(unit, dcb); 5231 } 5232 pkt->opcode = SOC_DCB_RX_OPCODE_GET(unit, dcb); 5233 pkt->dest_mod = SOC_DCB_RX_DESTMOD_GET(unit, dcb); 5234 pkt->dest_port = SOC_DCB_RX_DESTPORT_GET(unit, dcb); 5235 pkt->rx_decap_tunnel = 5236 (bcm_rx_decap_tunnel_t)SOC_DCB_RX_DECAP_TUNNEL_GET(unit, dcb); 5237 if (!soc_feature(unit, soc_feature_trunk_group_overlay) && 5238 (src_port_tgid & BCM_TGID_TRUNK_INDICATOR(unit))) { 5239 pkt->src_trunk = src_port_tgid & BCM_TGID_PORT_TRUNK_MASK(unit); 5240 pkt->flags |= BCM_PKT_F_TRUNK; 5241 pkt->src_port = -1; 5242 } else { 5243 pkt->src_port = src_port_tgid; 5244 pkt->src_trunk = -1; 5245 pkt->flags &= ~BCM_PKT_F_TRUNK; 5246 #ifdef BCM_XGS3_SWITCH_SUPPORT 5247 /* { */ 5248 /* 5249 * bcm_attach_early_txrx can be used to initialise tx and rx modules before 5250 * other modules. However processing various packet fields needes to be 5251 * avoided until the warmboot is complete, because related structures are yet 5252 * to be initialised in the corresponding modules. 5253 */ 5254 if (soc_feature(unit, soc_feature_trunk_extended) 5255 && !SOC_WARM_BOOT(unit)) { 5256 int rv = BCM_E_NONE; 5257 bcm_trunk_t tid; 5258 5259 tid = -1; 5260 rv = _bcm_esw_trunk_port_property_get(unit, pkt->src_mod, 5261 src_port_tgid, &tid); 5262 if (BCM_SUCCESS(rv) && (tid != -1)) { 5263 pkt->src_trunk = tid; 5264 pkt->flags |= BCM_PKT_F_TRUNK; 5265 } 5266 } 5267 /* } */ 5268 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 5269 } 5270 pkt->src_gport = BCM_GPORT_INVALID; 5271 pkt->dst_gport = BCM_GPORT_INVALID; 5272 pkt->cos = SOC_DCB_RX_COS_GET(unit, dcb); 5273 pkt->prio_int = BCM_PKT_VLAN_PRI(pkt); 5274 pkt->vlan = BCM_PKT_VLAN_ID(pkt); 5275 5276 #ifdef BCM_XGS3_SWITCH_SUPPORT 5277 /* { */ 5278 if (SOC_IS_XGS3_SWITCH(unit)) { 5279 bcm_vlan_t outer_vid; 5280 int hg_hdr_size; 5281 int rv = BCM_E_NONE; 5282 _bcm_gport_dest_t dest; 5283 5284 if (SOC_DCB_RX_MIRROR_GET(unit, dcb)) { 5285 pkt->flags |= BCM_RX_MIRRORED; 5286 } 5287 pkt->rx_classification_tag = SOC_DCB_RX_CLASSTAG_GET(unit, dcb); 5288 outer_vid = SOC_DCB_RX_OUTER_VID_GET(unit, dcb); 5289 if (outer_vid) { 5290 /* Don't overwrite if we don't have info */ 5291 pkt->vlan = outer_vid; 5292 } 5293 pkt->vlan_pri = SOC_DCB_RX_OUTER_PRI_GET(unit, dcb); 5294 pkt->vlan_cfi = SOC_DCB_RX_OUTER_CFI_GET(unit, dcb); 5295 pkt->inner_vlan = SOC_DCB_RX_INNER_VID_GET(unit, dcb); 5296 pkt->inner_vlan_pri = SOC_DCB_RX_INNER_PRI_GET(unit, dcb); 5297 pkt->inner_vlan_cfi = SOC_DCB_RX_INNER_CFI_GET(unit, dcb); 5298 #ifdef BCM_TRX_SUPPORT 5299 /* { */ 5300 pkt->rx_outer_tag_action = 5301 _BCM_TRX_TAG_ACTION_DECODE(SOC_DCB_RX_OUTER_TAG_ACTION_GET(unit, dcb)); 5302 pkt->rx_inner_tag_action = 5303 _BCM_TRX_TAG_ACTION_DECODE(SOC_DCB_RX_INNER_TAG_ACTION_GET(unit, dcb)); 5304 pkt->rx_l3_intf = SOC_DCB_RX_L3_INTF_GET(unit, dcb); 5305 /* } */ 5306 #endif /* BCM_TRX_SUPPORT */ 5307 5308 #ifdef BCM_HIGIG2_SUPPORT 5309 /* { */ 5310 if (soc_feature(unit, soc_feature_higig2) || 5311 soc_feature(unit, soc_feature_rx_pkt_hdr_format_higig2)) { 5312 hg_hdr_size = sizeof(soc_higig2_hdr_t); 5313 } else 5314 /* } */ 5315 #endif /* BCM_HIGIG2_SUPPORT */ 5316 { 5317 hg_hdr_size = sizeof(soc_higig_hdr_t); 5318 } 5319 /* Put XGS hdr into pkt->_higig */ 5320 sal_memcpy(pkt->_higig, SOC_DCB_MHP_GET(unit, dcb), 5321 hg_hdr_size); 5322 #ifdef LE_HOST 5323 /* { */ 5324 { 5325 /* Higig field accessors expect network byte ordering, 5326 * so we must reverse the bytes on LE hosts */ 5327 int word; 5328 uint32 *hg_data = (uint32 *) pkt->_higig; 5329 for (word = 0; word < BYTES2WORDS(hg_hdr_size); word++) { 5330 hg_data[word] = _shr_swap32(hg_data[word]); 5331 } 5332 } 5333 /* } */ 5334 #endif 5335 rx_higig_info_decode(unit, pkt); 5336 5337 if (BCM_GPORT_INVALID == pkt->src_gport) { 5338 /* Not set by the Higig2 logic */ 5339 _bcm_gport_dest_t_init(&dest); 5340 if (-1 != pkt->src_trunk) { 5341 dest.gport_type = _SHR_GPORT_TYPE_TRUNK; 5342 dest.tgid = pkt->src_trunk; 5343 } else { 5344 dest.gport_type = _SHR_GPORT_TYPE_MODPORT; 5345 dest.modid = pkt->src_mod; 5346 dest.port = pkt->src_port; 5347 } 5348 rv = _bcm_esw_gport_construct(unit, &dest, &(pkt->src_gport)); 5349 if (BCM_FAILURE(rv)) { 5350 pkt->src_gport = BCM_GPORT_INVALID; 5351 } 5352 } 5353 5354 if (BCM_GPORT_INVALID == pkt->dst_gport) { 5355 /* Not set by the Higig2 logic */ 5356 _bcm_gport_dest_t_init(&dest); 5357 dest.gport_type = _SHR_GPORT_TYPE_MODPORT; 5358 dest.modid = pkt->dest_mod; 5359 dest.port = pkt->dest_port; 5360 rv = _bcm_esw_gport_construct(unit, &dest, 5361 &(pkt->dst_gport)); 5362 if (BCM_FAILURE(rv)) { 5363 pkt->dst_gport = BCM_GPORT_INVALID; 5364 } 5365 } 5366 } 5367 /* } */ 5368 #endif 5369 5370 if (soc_feature(unit, soc_feature_rx_timestamp) && !olp_encap_oam_pkt) { 5371 /* Get time stamp value for TS protocol packets or OAM DM */ 5372 pkt->rx_timestamp = SOC_DCB_RX_TIMESTAMP_GET(unit, dcb); 5373 } 5374 5375 if (soc_feature(unit, soc_feature_rx_timestamp_upper) && 5376 !olp_encap_oam_pkt) { 5377 /* Get upper 32-bit of time stamp value for OAM DM */ 5378 pkt->rx_timestamp_upper = SOC_DCB_RX_TIMESTAMP_UPPER_GET(unit, dcb); 5379 } 5380 5381 #if defined(BCM_MONTEREY_SUPPORT) 5382 rx_timestamp_convert(unit, pkt); 5383 #endif 5384 } else if (SOC_IS_XGS12_FABRIC(unit)) { 5385 soc_higig_hdr_t *xgh; 5386 5387 xgh = (soc_higig_hdr_t *)(pkt->_higig); 5388 pkt->opcode = xgh->overlay1.opcode; 5389 pkt->dest_mod = xgh->overlay1.dst_mod | 5390 (xgh->hgp_overlay1.dst_mod_5 << 5) | 5391 (xgh->hgp_overlay1.dst_mod_6 << 6); 5392 pkt->dest_port = xgh->overlay1.dst_port; 5393 pkt->src_mod = xgh->overlay1.src_mod | 5394 (xgh->hgp_overlay1.src_mod_5 << 5) | 5395 (xgh->hgp_overlay1.src_mod_6 << 6); 5396 pkt->src_port = xgh->overlay1.src_port; 5397 pkt->cos = SOC_DCB_RX_COS_GET(unit, dcb); 5398 pkt->prio_int = xgh->overlay1.cos; 5399 pkt->rx_untagged = !xgh->hgp_overlay1.ingress_tagged; 5400 pkt->vlan = xgh->overlay1.vlan_id_lo | (xgh->overlay1.vlan_id_hi << 8); 5401 /* } */ 5402 #endif 5403 /* } */ 5404 #endif /* BCM_ESW_SUPPORT */ 5405 5406 } else if (SOC_UNIT_VALID(unit)) { 5407 /* All Strata and Strata 2 devices report src port as ing port */ 5408 pkt->src_port = SOC_DCB_RX_SRCPORT_GET(unit, dcb); 5409 #ifndef BCM_SAND_SUPPORT 5410 pkt->cos = SOC_DCB_RX_COS_GET(unit, dcb); 5411 #endif 5412 pkt->prio_int = BCM_PKT_VLAN_PRI(pkt); 5413 pkt->vlan = BCM_PKT_VLAN_ID(pkt); 5414 } 5415 5416 pkt->rx_unit = runit; 5417 5418 #ifdef BCM_ESW_SUPPORT 5419 /* { */ 5420 if ((SOC_UNIT_VALID(unit)) && !SOC_IS_RCPU_UNIT(unit)) { 5421 pkt->rx_reason = SOC_DCB_RX_REASON_GET(unit, dcb); 5422 SOC_DCB_RX_REASONS_GET(unit, dcb, &pkt->rx_reasons); 5423 if (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonMirror)) { 5424 pkt->rx_path |= BCM_RX_PATH_MIRRORED; 5425 BCM_RX_REASON_CLEAR(pkt->rx_reasons, bcmRxReasonMirror); 5426 if (!BCM_RX_REASON_IS_NULL(pkt->rx_reasons)) { 5427 if (SOC_DCB_RX_SWITCH_DROP_GET(unit, dcb)) { 5428 pkt->rx_path |= BCM_RX_PATH_COPY_TO_CPU; 5429 } else { 5430 pkt->rx_path |= BCM_RX_PATH_SWITCHED | BCM_RX_PATH_COPY_TO_CPU; 5431 } 5432 } 5433 BCM_RX_REASON_SET(pkt->rx_reasons, bcmRxReasonMirror); 5434 } else if (BCM_RX_REASON_IS_NULL(pkt->rx_reasons)) { 5435 pkt->rx_path |= BCM_RX_PATH_SWITCHED; 5436 } else if (SOC_DCB_RX_SWITCH_DROP_GET(unit, dcb)) { 5437 pkt->rx_path |= BCM_RX_PATH_COPY_TO_CPU; 5438 } else if (olp_encap_oam_pkt) { 5439 pkt->rx_path |= BCM_RX_PATH_COPY_TO_CPU; 5440 } else { 5441 pkt->rx_path |= BCM_RX_PATH_SWITCHED | BCM_RX_PATH_COPY_TO_CPU; 5442 } 5443 #ifdef BCM_TRIDENT2PLUS_SUPPORT 5444 /* { */ 5445 if(olp_encap_oam_pkt && SOC_IS_TRIDENT2PLUS(unit)) { 5446 BCM_RX_REASON_SET(pkt->rx_reasons, bcmRxReasonOAMSlowpath); 5447 } 5448 /* } */ 5449 #endif 5450 } 5451 /* } */ 5452 #endif 5453 5454 #ifdef BCM_DPP_SUPPORT 5455 /* { */ 5456 #ifdef BCM_ARAD_PARSE_PACKET_IN_INTERRUPT_CONTEXT 5457 /* { */ 5458 if (SOC_IS_ARAD(unit)) { 5459 _bcm_dpp_rx_packet_parse(unit, pkt, 0); 5460 } 5461 /* } */ 5462 #endif /*BCM_ARAD_PARSE_PACKET_IN_INTERRUPT_CONTEXT*/ 5463 /* } */ 5464 #endif /*BCM_SAND_SUPPORT*/ 5465 5466 } 5467 5468 /* 5469 * cmicx rx default parser routine 5470 * The entire EP_2_CPU_HDR is parsed 5471 */ 5472 STATIC void 5473 cmicx_rx_default_parser(int unit, bcm_pkt_t *pkt) 5474 { 5475 bcm_dma_chan_t chan; 5476 int idx, runit; 5477 dv_t *dv ; 5478 uint32 hdr[24]; 5479 5480 dv = pkt->_dv; 5481 idx = pkt->_idx; 5482 chan = DV_CHANNEL(dv); 5483 5484 #ifdef BCM_ARAD_PARSE_PACKET_IN_INTERRUPT_CONTEXT 5485 #ifdef BCM_DNX_SUPPORT 5486 if (SOC_IS_DNX(unit)) { 5487 dnx_rx_packet_parse(unit, pkt, FALSE); 5488 } 5489 return; 5490 #endif 5491 #endif 5492 5493 if (pkt->_pkt_data.data) 5494 { 5495 sal_memcpy(hdr, pkt->_pkt_data.data - pkt->egress_to_cpu_hdr_size, pkt->egress_to_cpu_hdr_size); 5496 } 5497 5498 if (bsl_check(bslLayerSoc, bslSourceRx, bslSeverityVerbose, unit)) { 5499 soc_dma_ep_to_cpu_hdr_dump(unit, "EP_2_CPU ", pkt->_pkt_data.data - pkt->egress_to_cpu_hdr_size, pkt->egress_to_cpu_hdr_size, 0); 5500 } 5501 5502 /* If single buffer used to DMA packet, may need cleanup */ 5503 if (RX_CHAN_FLAGS(unit, chan) & BCM_RX_F_MULTI_DCB) { 5504 multi_dcb_fillin(unit, pkt, dv, idx); 5505 } else if (!SOC_IS_RCPU_UNIT(unit)) { 5506 single_dcb_fillin(unit, pkt); 5507 } 5508 5509 runit = unit; 5510 if (SOC_IS_XGS_SWITCH(unit)) { /* Get XGS HiGig info from DMA desc */ 5511 #ifdef BCM_ESW_SUPPORT 5512 #ifdef BCM_XGS_SUPPORT 5513 int src_port_tgid; 5514 5515 pkt->rx_matched = SOC_DCB_RX_MATCHRULE_GET(unit, hdr); 5516 pkt->src_mod = SOC_DCB_RX_SRCMOD_GET(unit, hdr); 5517 src_port_tgid = SOC_DCB_RX_SRCPORT_GET(unit, hdr); 5518 pkt->opcode = SOC_DCB_RX_OPCODE_GET(unit, hdr); 5519 pkt->dest_mod = SOC_DCB_RX_DESTMOD_GET(unit, hdr); 5520 pkt->dest_port = SOC_DCB_RX_DESTPORT_GET(unit, hdr); 5521 5522 pkt->rx_decap_tunnel = SOC_DCB_RX_DECAP_TUNNEL_GET(unit, hdr); 5523 5524 RX_INFO((BSL_META_U(unit, 5525 "rx matched (%d) src mod (%d) dest mod (%d) dest port (%d) decap tunnel (%d)\n"), 5526 pkt->rx_matched, pkt->src_mod, pkt->dest_mod, pkt->dest_port, pkt->rx_decap_tunnel)); 5527 5528 #if defined(BCM_TRIDENT3_SUPPORT) 5529 if (SOC_IS_TRIDENT3X(unit)) { 5530 pkt->match_id[0] = SOC_DCB_MATCH_ID_LO_GET(unit, hdr); 5531 pkt->match_id[1] = SOC_DCB_MATCH_ID_HI_GET(unit, hdr); 5532 5533 RX_INFO((BSL_META_U(unit, "match id low (0x%x) match id high (0x%x)\n"), 5534 pkt->match_id[0], pkt->match_id[1])); 5535 5536 pkt->forwarding_type = SOC_DCB_FORWARDING_TYPE_GET(unit, hdr); 5537 pkt->forwarding_zone_id = SOC_DCB_FORWARDING_ZONE_ID_GET(unit, hdr); 5538 5539 if (pkt->forwarding_type == BCM_PKT_L3UC) { 5540 pkt->flags |= BCM_PKT_F_ROUTED; 5541 } 5542 5543 RX_INFO((BSL_META_U(unit, "forwarding type (0x%x) forwarding zone id (0x%x)\n"), 5544 pkt->forwarding_type, pkt->forwarding_zone_id)); 5545 } 5546 #endif 5547 if (!soc_feature(unit, soc_feature_trunk_group_overlay) && 5548 (src_port_tgid & BCM_TGID_TRUNK_INDICATOR(unit))) { 5549 pkt->src_trunk = src_port_tgid & BCM_TGID_PORT_TRUNK_MASK(unit); 5550 pkt->flags |= BCM_PKT_F_TRUNK; 5551 pkt->src_port = -1; 5552 } else { 5553 pkt->src_port = src_port_tgid; 5554 pkt->src_trunk = -1; 5555 pkt->flags &= ~BCM_PKT_F_TRUNK; 5556 #ifdef BCM_XGS3_SWITCH_SUPPORT 5557 /* 5558 * bcm_attach_early_txrx can be used to initialise tx and rx modules before 5559 * other modules. However processing various packet fields needes to be 5560 * avoided until the warmboot is complete, because related structures are yet 5561 * to be initialised in the corresponding modules. 5562 */ 5563 if (soc_feature(unit, soc_feature_trunk_extended) 5564 && !SOC_WARM_BOOT(unit)) { 5565 int rv = BCM_E_NONE; 5566 bcm_trunk_t tid; 5567 5568 tid = -1; 5569 rv = _bcm_esw_trunk_port_property_get(unit, pkt->src_mod, 5570 src_port_tgid, &tid); 5571 if (BCM_SUCCESS(rv) && (tid != -1)) { 5572 pkt->src_trunk = tid; 5573 pkt->flags |= BCM_PKT_F_TRUNK; 5574 } 5575 } 5576 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 5577 } 5578 5579 pkt->src_gport = BCM_GPORT_INVALID; 5580 pkt->dst_gport = BCM_GPORT_INVALID; 5581 pkt->cos = SOC_DCB_RX_COS_GET(unit,hdr); 5582 pkt->prio_int = BCM_PKT_VLAN_PRI(pkt); 5583 pkt->vlan = BCM_PKT_VLAN_ID(pkt); 5584 5585 RX_INFO((BSL_META_U(unit, 5586 "src gport (%d) dst gport (%d) cos (%d) prio (%d) vlan (%d)\n"), 5587 pkt->src_gport, pkt->dst_gport, pkt->cos, pkt->prio_int, pkt->vlan)); 5588 #ifdef BCM_XGS3_SWITCH_SUPPORT 5589 if (SOC_IS_XGS3_SWITCH(unit)) { 5590 bcm_vlan_t outer_vid; 5591 int hg_hdr_size; 5592 int rv = BCM_E_NONE; 5593 _bcm_gport_dest_t dest; 5594 5595 if (SOC_DCB_RX_MIRROR_GET(unit, hdr)) { 5596 pkt->flags |= BCM_RX_MIRRORED; 5597 } 5598 pkt->rx_classification_tag = SOC_DCB_RX_CLASSTAG_GET(unit, hdr); 5599 outer_vid = SOC_DCB_RX_OUTER_VID_GET(unit, hdr); 5600 if (outer_vid) { 5601 /* Don't overwrite if we don't have info */ 5602 pkt->vlan = outer_vid; 5603 RX_INFO((BSL_META_U(unit, "outer_vid (%d) vlan (%d)\n"), outer_vid, pkt->vlan)); 5604 } else { 5605 #if defined(BCM_TRIDENT3_SUPPORT) 5606 5607 #define BCM_PKT_VID_OFFSET(pkt, os) \ 5608 ((uint16)((BCM_PKT_VLAN_PTR(pkt)[2+os]<<8) | (BCM_PKT_VLAN_PTR(pkt)[3+os]))) 5609 5610 if (SOC_IS_TRIDENT3X(unit) && !BCM_PKT_RX_VLAN_TAG_STRIP(pkt)) { 5611 int pkt_ethertype; 5612 pkt_ethertype = BCM_PKT_TAG_PROTOCOL(pkt); 5613 if (soc_td3_rx_etype_niv[unit] && 5614 soc_td3_rx_etype_niv[unit] == pkt_ethertype) { 5615 /* Skip 6 bytes VNTAG */ 5616 pkt->vlan = 5617 BCM_VLAN_CTRL_ID(BCM_PKT_VID_OFFSET(pkt, 6)); 5618 pkt->prio_int = 5619 BCM_VLAN_CTRL_PRIO(BCM_PKT_VID_OFFSET(pkt, 6)); 5620 RX_INFO((BSL_META_U(unit, "outer_vid (%d) vlan (%d)\n"), 5621 outer_vid, pkt->vlan)); 5622 } 5623 5624 if (soc_td3_rx_etype_pe[unit] && 5625 soc_td3_rx_etype_pe[unit] == pkt_ethertype) { 5626 /* Skip 8 bytes ETAG */ 5627 pkt->vlan = 5628 BCM_VLAN_CTRL_ID(BCM_PKT_VID_OFFSET(pkt, 8)); 5629 pkt->prio_int = 5630 BCM_VLAN_CTRL_PRIO(BCM_PKT_VID_OFFSET(pkt, 8)); 5631 RX_INFO((BSL_META_U(unit, "outer_vid (%d) vlan (%d)\n"), 5632 outer_vid, pkt->vlan)); 5633 } 5634 } 5635 #endif 5636 } 5637 pkt->vlan_pri = SOC_DCB_RX_OUTER_PRI_GET(unit, hdr); 5638 pkt->vlan_cfi = SOC_DCB_RX_OUTER_CFI_GET(unit, hdr); 5639 pkt->inner_vlan = SOC_DCB_RX_INNER_VID_GET(unit, hdr); 5640 pkt->inner_vlan_pri = SOC_DCB_RX_INNER_PRI_GET(unit, hdr); 5641 pkt->inner_vlan_cfi = SOC_DCB_RX_INNER_CFI_GET(unit, hdr); 5642 5643 #ifdef BCM_TRX_SUPPORT 5644 pkt->rx_outer_tag_action = 5645 _BCM_TRX_TAG_ACTION_DECODE(SOC_DCB_RX_OUTER_TAG_ACTION_GET(unit, hdr)); 5646 pkt->rx_inner_tag_action = 5647 _BCM_TRX_TAG_ACTION_DECODE(SOC_DCB_RX_INNER_TAG_ACTION_GET(unit, hdr)); 5648 pkt->rx_l3_intf = SOC_DCB_RX_L3_INTF_GET(unit, hdr); 5649 5650 RX_INFO((BSL_META_U(unit, 5651 "rx outer tag action (%d) rx inner tag action (%d) rx l3 intf (%d)\n"), 5652 pkt->rx_outer_tag_action, pkt->rx_inner_tag_action, pkt->rx_l3_intf)); 5653 #endif 5654 RX_INFO((BSL_META_U(unit, 5655 "vlan (%d) vlan pri (%d) vlan cfi (%d) inner vlan (%d) inner vlan pri (%d) inner vlan cfi (%d)\n"), 5656 pkt->vlan, pkt->vlan_pri, pkt->vlan_cfi, pkt->inner_vlan, pkt->inner_vlan_pri, pkt->inner_vlan_cfi)); 5657 5658 #ifdef BCM_HIGIG2_SUPPORT 5659 if (soc_feature(unit, soc_feature_higig2) || 5660 soc_feature(unit, soc_feature_rx_pkt_hdr_format_higig2)) { 5661 hg_hdr_size = sizeof(soc_higig2_hdr_t); 5662 } else 5663 #endif /* BCM_HIGIG2_SUPPORT */ 5664 { 5665 hg_hdr_size = sizeof(soc_higig_hdr_t); 5666 } 5667 5668 /* Put XGS hdr into pkt->_higig */ 5669 sal_memcpy(pkt->_higig, hdr, hg_hdr_size); 5670 5671 RX_INFO((BSL_META_U(unit, "high gig header size = %d\n"), hg_hdr_size)); 5672 #ifdef LE_HOST 5673 { 5674 /* Higig field accessors expect network byte ordering, 5675 * so we must reverse the bytes on LE hosts */ 5676 int word; 5677 uint32 *hg_data = (uint32 *) pkt->_higig; 5678 for (word = 0; word < BYTES2WORDS(hg_hdr_size); word++) { 5679 hg_data[word] = _shr_swap32(hg_data[word]); 5680 RX_INFO((BSL_META_U(unit, "high gig data = %x\n"), hg_data[word])); 5681 } 5682 } 5683 #endif 5684 5685 rx_higig_info_decode(unit, pkt); 5686 5687 RX_INFO((BSL_META_U(unit, "vlan after decode (%d)\n"), pkt->vlan)); 5688 5689 if (SOC_IS_TRIDENT3X(unit)) { 5690 #ifdef BCM_HIGIG2_SUPPORT 5691 if (soc_feature(unit, soc_feature_higig2) || 5692 soc_feature(unit, soc_feature_rx_pkt_hdr_format_higig2)) { 5693 /* CMIC RX packets are in HiGig2 format if the device supports it */ 5694 soc_higig2_hdr_t *xgh2; 5695 xgh2 = (soc_higig2_hdr_t *)(pkt->_higig); 5696 5697 if (soc_higig2_field_get(unit, xgh2, HG_ehv)) { 5698 /* 5699 * The Extended Higig data is found from byte 56 of the EP_2_CPU_HDR in TD3 devices. 5700 * Since we have already advanced the pointer to point to the start of data, 5701 * in the below code we go back by 8 bytes. 5702 */ 5703 sal_memcpy(pkt->_ext_higig, pkt->_pkt_data.data - 8, sizeof(pkt->_ext_higig)); 5704 #ifdef LE_HOST 5705 { 5706 uint32 *ext_hg_data = (uint32 *) pkt->_ext_higig; 5707 5708 /* 5709 * From Spec, there are only 4 bytes and hence 1 word of 5710 * Extended Higig data. 5711 */ 5712 ext_hg_data[0] = _shr_swap32(ext_hg_data[0]); 5713 RX_INFO((BSL_META_U(unit, "ext_high gig data = %x\n"), ext_hg_data[0])); 5714 } 5715 #endif 5716 } 5717 } 5718 #endif 5719 } 5720 5721 if (BCM_GPORT_INVALID == pkt->src_gport) { 5722 /* Not set by the Higig2 logic */ 5723 _bcm_gport_dest_t_init(&dest); 5724 if (-1 != pkt->src_trunk) { 5725 dest.gport_type = _SHR_GPORT_TYPE_TRUNK; 5726 dest.tgid = pkt->src_trunk; 5727 } else { 5728 dest.gport_type = _SHR_GPORT_TYPE_MODPORT; 5729 dest.modid = pkt->src_mod; 5730 dest.port = pkt->src_port; 5731 } 5732 rv = _bcm_esw_gport_construct(unit, &dest, &(pkt->src_gport)); 5733 if (BCM_FAILURE(rv)) { 5734 pkt->src_gport = BCM_GPORT_INVALID; 5735 } 5736 } 5737 5738 if (BCM_GPORT_INVALID == pkt->dst_gport) { 5739 /* Not set by the Higig2 logic */ 5740 _bcm_gport_dest_t_init(&dest); 5741 dest.gport_type = _SHR_GPORT_TYPE_MODPORT; 5742 dest.modid = pkt->dest_mod; 5743 dest.port = pkt->dest_port; 5744 rv = _bcm_esw_gport_construct(unit, &dest, 5745 &(pkt->dst_gport)); 5746 if (BCM_FAILURE(rv)) { 5747 pkt->dst_gport = BCM_GPORT_INVALID; 5748 } 5749 } 5750 5751 } 5752 #endif 5753 5754 if (soc_feature(unit, soc_feature_rx_timestamp)) { 5755 /* Get time stamp value for TS protocol packets or OAM DM */ 5756 pkt->rx_timestamp = SOC_DCB_RX_TIMESTAMP_GET(unit, hdr); 5757 } 5758 5759 if (soc_feature(unit, soc_feature_rx_timestamp_upper)) { 5760 /* Get upper 32-bit of time stamp value for OAM DM */ 5761 pkt->rx_timestamp_upper = SOC_DCB_RX_TIMESTAMP_UPPER_GET(unit, hdr); 5762 } 5763 } else if (SOC_IS_XGS12_FABRIC(unit)) { 5764 soc_higig_hdr_t *xgh; 5765 5766 xgh = (soc_higig_hdr_t *)(pkt->_higig); 5767 pkt->opcode = xgh->overlay1.opcode; 5768 pkt->dest_mod = xgh->overlay1.dst_mod | 5769 (xgh->hgp_overlay1.dst_mod_5 << 5) | 5770 (xgh->hgp_overlay1.dst_mod_6 << 6); 5771 pkt->dest_port = xgh->overlay1.dst_port; 5772 pkt->src_mod = xgh->overlay1.src_mod | 5773 (xgh->hgp_overlay1.src_mod_5 << 5) | 5774 (xgh->hgp_overlay1.src_mod_6 << 6); 5775 pkt->src_port = xgh->overlay1.src_port; 5776 pkt->cos = SOC_DCB_RX_COS_GET(unit, hdr); 5777 pkt->prio_int = xgh->overlay1.cos; 5778 pkt->rx_untagged = !xgh->hgp_overlay1.ingress_tagged; 5779 pkt->vlan = xgh->overlay1.vlan_id_lo | (xgh->overlay1.vlan_id_hi << 8); 5780 5781 RX_INFO((BSL_META_U(unit, 5782 "src port (%d) dst port (%d) cos (%d) prio int (%d) vlan (%d)\n"), 5783 pkt->src_port, pkt->dest_port, pkt->cos, pkt->prio_int, pkt->vlan)); 5784 5785 #endif 5786 #endif /* BCM_ESW_SUPPORT */ 5787 } 5788 5789 pkt->rx_unit = runit; 5790 #ifdef BCM_ESW_SUPPORT 5791 if ((SOC_UNIT_VALID(unit)) && !SOC_IS_RCPU_UNIT(unit)) { 5792 pkt->rx_reason = SOC_DCB_RX_REASON_GET(unit, hdr); 5793 SOC_DCB_RX_REASONS_GET(unit, hdr, &pkt->rx_reasons); 5794 if (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonMirror)) { 5795 pkt->rx_path |= BCM_RX_PATH_MIRRORED; 5796 BCM_RX_REASON_CLEAR(pkt->rx_reasons, bcmRxReasonMirror); 5797 if (!BCM_RX_REASON_IS_NULL(pkt->rx_reasons)) { 5798 if (SOC_DCB_RX_SWITCH_DROP_GET(unit, hdr)) { 5799 pkt->rx_path |= BCM_RX_PATH_COPY_TO_CPU; 5800 } else { 5801 pkt->rx_path |= BCM_RX_PATH_SWITCHED | BCM_RX_PATH_COPY_TO_CPU; 5802 } 5803 } 5804 BCM_RX_REASON_SET(pkt->rx_reasons, bcmRxReasonMirror); 5805 } else if (BCM_RX_REASON_IS_NULL(pkt->rx_reasons)) { 5806 pkt->rx_path |= BCM_RX_PATH_SWITCHED; 5807 } else if (SOC_DCB_RX_SWITCH_DROP_GET(unit, hdr)) { 5808 pkt->rx_path |= BCM_RX_PATH_COPY_TO_CPU; 5809 } else { 5810 pkt->rx_path |= BCM_RX_PATH_SWITCHED | BCM_RX_PATH_COPY_TO_CPU; 5811 } 5812 } 5813 #endif 5814 5815 RX_INFO((BSL_META_U(unit, 5816 "exit point: src port (%d) dst port (%d) cos (%d) prio int (%d) vlan (%d)\n"), 5817 pkt->src_port, pkt->dest_port, pkt->cos, pkt->prio_int, pkt->vlan)); 5818 } 5819 5820 /* 5821 * Function: 5822 * rx_intr_process_packet 5823 * Purpose: 5824 * Processes a received packet in interrupt context 5825 * calling out to the handlers until 5826 * the packet is consumed. 5827 * Parameters: 5828 * unit - StrataSwitch unit number. 5829 * dcb - pointer to completed DCB. 5830 * Returns: 5831 * Nothing. 5832 * Notes: 5833 * THIS ROUTINE IS CALLED AT INTERRUPT LEVEL. 5834 */ 5835 5836 STATIC INLINE void 5837 rx_intr_process_packet(int unit, dv_t *dv, dcb_t *dcb, bcm_pkt_t *pkt) 5838 { 5839 volatile rx_callout_t *rco; 5840 bcm_rx_t handler_rc; 5841 bcm_dma_chan_t chan; 5842 rx_queue_t *queue; 5843 int handled = FALSE; 5844 5845 pkt->_dcb = (void *)dcb; 5846 chan = DV_CHANNEL(dv); 5847 5848 pkt_len_get(unit, chan, (bcm_pkt_t *)pkt, dv); 5849 5850 /** for DNX devices, rx_port is not from EP_TO_CPU header */ 5851 if (soc_feature(unit, soc_feature_cmicx)) 5852 { 5853 if (!soc_feature(unit, soc_feature_no_ep_to_cpu)) 5854 { 5855 pkt->rx_port = SOC_DCB_RX_INGPORT_GET(unit, pkt->_pkt_data.data); 5856 } 5857 } 5858 else 5859 { 5860 pkt->rx_port = SOC_DCB_RX_INGPORT_GET(unit, dcb); 5861 } 5862 5863 pkt->dma_channel = chan; 5864 pkt->rx_unit = pkt->unit = unit; 5865 5866 if (!SOC_IS_XGS12_FABRIC(unit)) { 5867 if (soc_feature(unit, soc_feature_cmicx)) { 5868 if (!soc_feature(unit, soc_feature_no_ep_to_cpu)) 5869 { 5870 pkt->rx_untagged = SOC_DCB_RX_UNTAGGED_GET(unit, pkt->_pkt_data.data); 5871 } 5872 else 5873 { 5874 pkt->rx_untagged = 0; 5875 } 5876 } else { 5877 pkt->rx_untagged = SOC_DCB_RX_UNTAGGED_GET(unit, dcb); 5878 } 5879 } 5880 5881 /* to get correct cos */ 5882 if (SOC_IS_RCPU_UNIT(unit)) { 5883 #if defined(INCLUDE_RCPU) && defined(BCM_ESW_SUPPORT) && defined(BCM_XGS3_SWITCH_SUPPORT) 5884 /* { */ 5885 if (!(RX_CHAN_FLAGS(unit, chan) & BCM_RX_F_MULTI_DCB)) { 5886 single_dcb_fillin(unit, pkt); 5887 } 5888 if (BCM_SUCCESS(rx_rcpu_base_info_parse(pkt))) { 5889 if (soc_feature(unit, soc_feature_cmicx)) { 5890 pkt->cos = SOC_DCB_RX_COS_GET(unit, pkt->_pkt_data.data); 5891 } else { 5892 pkt->cos = SOC_DCB_RX_COS_GET(unit, (dcb_t *)(pkt->_dcb)); 5893 } 5894 } 5895 /* } */ 5896 #endif 5897 #ifdef BCM_DPP_SUPPORT 5898 /* { */ 5899 } else if (SOC_IS_ARAD(unit)) { 5900 _bcm_dpp_rx_packet_cos_parse(unit, pkt); 5901 /* } */ 5902 #endif 5903 } else { 5904 if (soc_feature(unit, soc_feature_cmicx)) { 5905 /** for DNX devices, cos is not from EP_TO_CPU header */ 5906 if (!soc_feature(unit, soc_feature_no_ep_to_cpu)) 5907 { 5908 pkt->cos = SOC_DCB_RX_COS_GET(unit, pkt->_pkt_data.data); 5909 } 5910 } else { 5911 pkt->cos = SOC_DCB_RX_COS_GET(unit, dcb); 5912 } 5913 } 5914 /** Dune devices on CMICx without ep_to_cpu header */ 5915 if ((!soc_feature(unit, soc_feature_no_ep_to_cpu)) && soc_feature(unit, soc_feature_cmicx)) { 5916 uint32 hdr_size = 0; 5917 soc_stat_t *stat = &SOC_CONTROL(unit)->stat; 5918 5919 soc_dma_header_size_get(unit, &hdr_size); 5920 pkt->egress_to_cpu_hdr_size = hdr_size; 5921 pkt->pkt_len -= hdr_size; 5922 pkt->tot_len -= hdr_size; 5923 stat->dma_rbyt -= hdr_size; 5924 pkt->_pkt_data.data = pkt->_pkt_data.data + hdr_size; 5925 } 5926 RX_CHAN_CTL(unit, chan).rpkt++; 5927 RX_CHAN_CTL(unit, chan).rbyte += pkt->tot_len; 5928 5929 queue = RX_QUEUE(unit, pkt->cos); 5930 5931 5932 if (INTR_CALLOUTS(unit)) { 5933 /* Check if bandwidth available for this pkt */ 5934 if (queue->pps > 0 && queue->tokens <= 0) { 5935 /* Rate limiting on and not enough tokens */ 5936 queue->rate_disc++; 5937 MARK_PKT_PROCESSED_LOCAL(unit, chan, dv); 5938 return; 5939 } 5940 5941 if ((rx_ctl[unit]->user_cfg.flags & BCM_RX_F_PKT_UNPARSED) != 5942 BCM_RX_F_PKT_UNPARSED) { 5943 if (rx_ctl[unit]->rx_parser != NULL) { 5944 rx_ctl[unit]->rx_parser(unit, pkt); 5945 } 5946 } 5947 5948 /* Loop through registered drivers looking for intr handlers. */ 5949 for (rco = rx_ctl[unit]->rc_callout; rco; rco = rco->rco_next) { 5950 BCM_API_XLATE_PORT_DECL(rx_port); 5951 BCM_API_XLATE_PORT_DECL(rx_port_orig); 5952 5953 if (!(rco->rco_flags & BCM_RCO_F_INTR)) { 5954 continue; 5955 } 5956 if (!(SHR_BITGET(rco->rco_cos, pkt->cos))) { 5957 /* callback is not interested in this COS */ 5958 continue; 5959 } 5960 5961 /* Since pkt->rx_port is an int8, it cannot be passed directly */ 5962 BCM_API_XLATE_PORT_SAVE(rx_port_orig, pkt->rx_port); 5963 BCM_API_XLATE_PORT_ASSIGN(rx_port, rx_port_orig); 5964 BCM_API_XLATE_PORT_P2A(unit, &rx_port); 5965 BCM_API_XLATE_PORT_ASSIGN(pkt->rx_port, rx_port); 5966 5967 handler_rc = rco->rco_function(unit, pkt, rco->rco_cookie); 5968 5969 BCM_API_XLATE_PORT_RESTORE(pkt->rx_port, rx_port_orig); 5970 5971 switch (handler_rc) { 5972 case BCM_RX_NOT_HANDLED: 5973 break; /* Next callout */ 5974 case BCM_RX_HANDLED: /* Account for the packet */ 5975 _Q_DEC_TOKENS(queue); 5976 MARK_PKT_PROCESSED_LOCAL(unit, chan, dv); 5977 handled = TRUE; 5978 rco->rco_pkts_handled++; 5979 break; 5980 case BCM_RX_HANDLED_OWNED: /* Packet stolen */ 5981 _Q_DEC_TOKENS(queue); 5982 pkt->_pkt_data.data = NULL; /* Mark as stolen */ 5983 pkt->alloc_ptr = NULL; /* Mark as stolen */ 5984 MARK_PKT_PROCESSED_LOCAL(unit, chan, dv); 5985 handled = TRUE; 5986 rx_ctl[unit]->pkts_owned++; 5987 rco->rco_pkts_owned++; 5988 break; 5989 default: /* Treated as NOT_HANDLED */ 5990 rx_ctl[unit]->bad_hndlr_rv++; 5991 break; 5992 } 5993 5994 if (handled) { 5995 break; 5996 } 5997 } 5998 } 5999 6000 if (!handled) { /* Not processed, enqueue for non-interrupt handling */ 6001 if ((queue->max_len > 0) && (queue->count < queue->max_len)) { 6002 if (NON_INTR_CALLOUTS(unit)) { 6003 if ((rx_ctl[unit]->user_cfg.flags & BCM_RX_F_PKT_UNPARSED) != 6004 BCM_RX_F_PKT_UNPARSED) { 6005 if (rx_ctl[unit]->rx_parser != NULL) { 6006 rx_ctl[unit]->rx_parser(unit, pkt); 6007 } 6008 } 6009 _Q_ENQUEUE(queue, pkt); 6010 RX_THREAD_NOTIFY(unit); 6011 } else { 6012 MARK_PKT_PROCESSED_LOCAL(unit, chan, dv); 6013 rx_ctl[unit]->no_hndlr++; 6014 } 6015 } else { /* No space; discard */ 6016 MARK_PKT_PROCESSED_LOCAL(unit, chan, dv); 6017 queue->qlen_disc++; 6018 } 6019 } else { 6020 /* 6021 * Preserving these flags that were conditionally set 6022 * in function bcm_pkt_flags_init(int unit, bcm_pkt_t *pkt, uint32 flags) 6023 */ 6024 pkt->flags &= (BCM_PKT_F_HGHDR | BCM_PKT_F_SLTAG); 6025 } 6026 6027 } 6028 6029 int 6030 rcpu_rx_pkt_enqueue(int unit, bcm_pkt_t *pkt) 6031 { 6032 rx_queue_t *queue; 6033 6034 if (!RX_UNIT_STARTED(unit) || !rx_control.thread_running) { 6035 return BCM_E_PARAM; 6036 } 6037 6038 queue = RX_QUEUE(unit, pkt->cos); 6039 6040 if ((queue->max_len > 0) && (queue->count < queue->max_len)) { 6041 _Q_ENQUEUE(queue, pkt); 6042 RX_THREAD_NOTIFY(unit); 6043 } else { /* No space; discard */ 6044 queue->qlen_disc++; 6045 return BCM_E_RESOURCE; 6046 } 6047 6048 return BCM_E_NONE; 6049 } 6050 6051 #if defined(BCM_RPC_SUPPORT) 6052 /* { */ 6053 6054 int bcm_rx_tunnel_count; 6055 6056 /* 6057 * Function: 6058 * bcm_rx_remote_pkt_enqueue 6059 * Purpose: 6060 * Enqueue a remote packet for normal RX processing 6061 * Parameters: 6062 * unit - The BCM unit in which queue the pkt is placed 6063 * pkt - The packet to enqueue 6064 * Returns: 6065 * BCM_E_XXX 6066 */ 6067 6068 int 6069 _bcm_common_rx_remote_pkt_enqueue(int unit, bcm_pkt_t *pkt) 6070 { 6071 rx_queue_t *queue; 6072 6073 if (!RX_IS_SETUP(unit) || RX_IS_LOCAL(unit) || RX_IS_RCPU(unit)) { 6074 return BCM_E_PARAM; 6075 } 6076 6077 queue = RX_QUEUE(unit, pkt->cos); 6078 6079 if ((queue->max_len > 0) && (queue->count < queue->max_len)) { 6080 _Q_ENQUEUE(queue, pkt); 6081 RX_THREAD_NOTIFY(unit); 6082 } else { /* No space; discard */ 6083 queue->qlen_disc++; 6084 return BCM_E_RESOURCE; 6085 } 6086 6087 bcm_rx_tunnel_count++; 6088 6089 return BCM_E_NONE; 6090 } 6091 #else 6092 int 6093 _bcm_common_rx_remote_pkt_enqueue(int unit, bcm_pkt_t *pkt) 6094 { 6095 return BCM_E_UNAVAIL; 6096 } 6097 /* } */ 6098 #endif /* BCM_RPC_SUPPORT */ 6099 6100 #if defined(INCLUDE_L3) && defined(BCM_TRX_SUPPORT) 6101 /* { */ 6102 6103 /* 6104 * Function: 6105 * fill_in_pkt_vpn_id 6106 * Purpose: 6107 * Fill pkt->vlan with vpn id if pkt->src_gport is a VPLS virtual port. 6108 * This function is necessary since the rx_higig_info_decode function is 6109 * not always able to derive vpn id from Higig2 header. Triumph does not 6110 * set PPD2 header's VNI field, and PPD3 header doesn't have a VNI field. 6111 * Parameters: 6112 * unit - StrataSwitch unit number. 6113 * pkt - The packet to process. 6114 * Returns: 6115 * Nothing. 6116 * Notes: 6117 * This function needs to read SOURCE_VPm table to obtain vpn id. 6118 * Hence, it's called in non-interrupt context by rx_process_packet. 6119 */ 6120 6121 STATIC void 6122 fill_in_pkt_vpn_id(int unit, bcm_pkt_t *pkt) 6123 { 6124 int src_vp; 6125 source_vp_entry_t svp_entry; 6126 int rv; 6127 int vfi; 6128 6129 if (BCM_GPORT_IS_MPLS_PORT(pkt->src_gport)) { 6130 src_vp = BCM_GPORT_MPLS_PORT_ID_GET(pkt->src_gport); 6131 if (!_BCM_VPN_IS_SET(pkt->vlan)) { 6132 rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ALL, src_vp, &svp_entry); 6133 if (BCM_SUCCESS(rv)) { 6134 if (0x1 == 6135 soc_SOURCE_VPm_field32_get(unit, &svp_entry, ENTRY_TYPEf)) { 6136 vfi = soc_SOURCE_VPm_field32_get(unit, &svp_entry, VFIf); 6137 if (_bcm_vfi_used_get(unit, vfi, _bcmVfiTypeMpls)) { 6138 _BCM_VPN_SET(pkt->vlan, _BCM_VPN_TYPE_VFI, vfi); 6139 } 6140 } 6141 } 6142 } 6143 } 6144 6145 return; 6146 } 6147 6148 /* } */ 6149 #endif /* INCLUDE_L3 && BCM_TRX_SUPPORT */ 6150 6151 #ifdef BCM_RCPU_SUPPORT 6152 /* { */ 6153 /* 6154 * Function: 6155 * rx_rcpu_process_packet 6156 * Purpose: 6157 * Processes a received RCPU packet in non-interrupt context 6158 * calling out to the handlers until the packet is consumed. 6159 * Parameters: 6160 * unit - StrataSwitch unit number. 6161 * rx_pkt - The packet to process 6162 * Returns: 6163 * Nothing. 6164 * Notes: 6165 * Assumes discard handler is registered with lowest priority 6166 */ 6167 6168 STATIC void 6169 rx_rcpu_process_packet(int unit, bcm_pkt_t *pkt) 6170 { 6171 volatile rx_callout_t *rco; 6172 bcm_rx_t handler_rc; 6173 int handled = FALSE; 6174 int i; 6175 6176 assert(pkt); 6177 6178 RX_LOCK(unit); /* Can't modify handler list while doing callbacks */ 6179 /* Loop through registered drivers until packet consumed */ 6180 for (rco = rx_ctl[unit]->rc_callout; rco; rco = rco->rco_next) { 6181 if (rco->rco_flags & BCM_RCO_F_INTR) { /* Non interrupt context */ 6182 continue; 6183 } 6184 if (!(SHR_BITGET(rco->rco_cos, pkt->cos))) { 6185 /* callback is not interested in this COS */ 6186 continue; 6187 } 6188 6189 handler_rc = rco->rco_function(unit, pkt, rco->rco_cookie); 6190 6191 switch (handler_rc) { 6192 case BCM_RX_NOT_HANDLED: 6193 break; /* Next callout */ 6194 case BCM_RX_HANDLED: 6195 handled = TRUE; 6196 bcm_rx_remote_pkt_free(pkt); /* Free the packet */ 6197 LOG_VERBOSE(BSL_LS_BCM_RX, 6198 (BSL_META_U(unit, 6199 BSL_META_U(unit, "rx: pkt handled by %s\n")), 6200 rco->rco_name)); 6201 rco->rco_pkts_handled++; 6202 break; 6203 case BCM_RX_HANDLED_OWNED: 6204 handled = TRUE; 6205 /* 6206 * Make the data buffer point to NULL 6207 * As a result, in pkt_free, only the pkt structure is freed 6208 * The data buffer itself is not. 6209 */ 6210 for (i = 0; i < pkt->blk_count; i++) { 6211 pkt->pkt_data[i].data = NULL; 6212 } 6213 pkt->alloc_ptr = NULL; 6214 bcm_rx_remote_pkt_free(pkt); 6215 LOG_VERBOSE(BSL_LS_BCM_RX, 6216 (BSL_META_U(unit, 6217 BSL_META_U(unit, "rx: pkt owned by %s\n")), 6218 rco->rco_name)); 6219 rx_ctl[unit]->pkts_owned++; 6220 rco->rco_pkts_owned++; 6221 break; 6222 default: 6223 LOG_WARN(BSL_LS_BCM_RX, 6224 (BSL_META_U(unit, 6225 BSL_META_U 6226 (unit, 6227 "rx_process_packet: unit=%d: " 6228 "Invalid callback return value=%d\n")), 6229 unit, handler_rc)); 6230 break; 6231 } 6232 6233 if (handled) { 6234 break; 6235 } 6236 } 6237 RX_UNLOCK(unit); 6238 6239 if (!handled) { 6240 /* Internal error as discard should have handled packet */ 6241 RX_ERROR((BSL_META_U(unit, 6242 "bcm_rx_process_packet: No handler processed packet: " 6243 "Port %s\n"), 6244 SOC_PORT_NAME(unit, pkt->rx_port))); 6245 bcm_rx_remote_pkt_free(pkt); 6246 } 6247 } 6248 /* } */ 6249 #endif /* BCM_RCPU_SUPPORT */ 6250 /* 6251 * Function: 6252 * rx_process_packet 6253 * Purpose: 6254 * Processes a received packet in non-interrupt context 6255 * calling out to the handlers until the packet is consumed. 6256 * Parameters: 6257 * unit - StrataSwitch unit number. 6258 * rx_pkt - The packet to process 6259 * Returns: 6260 * Nothing. 6261 * Notes: 6262 * Assumes discard handler is registered with lowest priority 6263 */ 6264 6265 STATIC void 6266 rx_process_packet(int unit, bcm_pkt_t *pkt) 6267 { 6268 volatile rx_callout_t *rco; 6269 bcm_rx_t handler_rc; 6270 dv_t *dv; 6271 int handled = FALSE; 6272 6273 assert(pkt); 6274 dv = pkt->_dv; 6275 if (RX_IS_LOCAL(unit) || RX_IS_RCPU(unit)) { 6276 assert(pkt == DV_PKT(dv, pkt->_idx)); 6277 } 6278 6279 #ifndef BCM_ARAD_PARSE_PACKET_IN_INTERRUPT_CONTEXT 6280 /* { */ 6281 #ifdef BCM_PETRA_SUPPORT 6282 /* { */ 6283 if (SOC_UNIT_VALID(unit) && SOC_IS_ARAD(unit)) { 6284 _bcm_dpp_rx_packet_parse(unit, pkt, 1); 6285 } 6286 /* } */ 6287 #endif 6288 6289 #ifdef BCM_DNX_SUPPORT 6290 if (SOC_UNIT_VALID(unit) && SOC_IS_DNX(unit)) 6291 { 6292 dnx_rx_packet_parse(unit, pkt, TRUE); 6293 } 6294 #endif 6295 /* } */ 6296 #endif /*BCM_ARAD_PARSE_PACKET_IN_INTERRUPT_CONTEXT*/ 6297 6298 #ifdef BROADCOM_DEBUG 6299 /* { */ 6300 if (bsl_check(bslLayerSoc, bslSourceRx, bslSeverityVerbose, unit)) { 6301 /* Dump the packet info */ 6302 RX_INFO((BSL_META_U(unit, "rx_process_packet: packet in\n"))); 6303 if ((RX_IS_LOCAL(unit) && SOC_UNIT_VALID(unit)) 6304 || RX_IS_RCPU(unit)) { 6305 soc_dma_dump_dv(unit, "rx dv: ", dv); 6306 } 6307 } 6308 /* } */ 6309 #endif /* BROADCOM_DEBUG */ 6310 6311 /* coverity[overrun-local : FALSE] */ 6312 if (!NON_INTR_CALLOUTS(unit)) { 6313 /* No one to talk to. Mark processed and return */ 6314 /* coverity[overrun-local : FALSE] */ 6315 MARK_PKT_PROCESSED(pkt, unit, pkt->dma_channel, dv); 6316 rx_ctl[unit]->no_hndlr++; 6317 return; 6318 } 6319 6320 #if defined(INCLUDE_L3) && defined(BCM_TRX_SUPPORT) 6321 /* { */ 6322 if (SOC_UNIT_VALID(unit) && SOC_IS_TR_VL(unit)) { 6323 fill_in_pkt_vpn_id(unit, pkt); 6324 } 6325 /* } */ 6326 #endif /* INCLUDE_L3 && BCM_TRX_SUPPORT */ 6327 6328 RX_LOCK(unit); /* Can't modify handler list while doing callbacks */ 6329 6330 /* Loop through registered drivers until packet consumed */ 6331 for (rco = rx_ctl[unit]->rc_callout; rco; rco = rco->rco_next) { 6332 BCM_API_XLATE_PORT_DECL(rx_port); 6333 BCM_API_XLATE_PORT_DECL(rx_port_orig); 6334 6335 if (rco->rco_flags & BCM_RCO_F_INTR) { /* Non interrupt context */ 6336 continue; 6337 } 6338 if (!(SHR_BITGET(rco->rco_cos, pkt->cos))) { 6339 /* callback is not interested in this COS */ 6340 continue; 6341 } 6342 6343 /* Since pkt->rx_port is an int8, it cannot be passed directly */ 6344 BCM_API_XLATE_PORT_SAVE(rx_port_orig, pkt->rx_port); 6345 BCM_API_XLATE_PORT_SAVE(rx_port, rx_port_orig); 6346 BCM_API_XLATE_PORT_P2A(unit, &rx_port); 6347 BCM_API_XLATE_PORT_SAVE(pkt->rx_port, rx_port); 6348 6349 handler_rc = rco->rco_function(unit, pkt, rco->rco_cookie); 6350 6351 BCM_API_XLATE_PORT_RESTORE(pkt->rx_port, rx_port_orig); 6352 6353 switch (handler_rc) { 6354 case BCM_RX_NOT_HANDLED: 6355 break; /* Next callout */ 6356 case BCM_RX_HANDLED: 6357 handled = TRUE; 6358 MARK_PKT_PROCESSED(pkt, unit, pkt->dma_channel, dv); 6359 LOG_DEBUG(BSL_LS_BCM_RX, 6360 (BSL_META_U(unit, 6361 BSL_META_U(unit, "rx: pkt handled by %s\n")), 6362 rco->rco_name)); 6363 rco->rco_pkts_handled++; 6364 break; 6365 case BCM_RX_HANDLED_OWNED: 6366 handled = TRUE; 6367 pkt->_pkt_data.data = NULL; 6368 pkt->alloc_ptr = NULL; 6369 MARK_PKT_PROCESSED(pkt, unit, pkt->dma_channel, dv); 6370 LOG_DEBUG(BSL_LS_BCM_RX, 6371 (BSL_META_U(unit, 6372 BSL_META_U(unit, "rx: pkt owned by %s\n")), 6373 rco->rco_name)); 6374 rx_ctl[unit]->pkts_owned++; 6375 rco->rco_pkts_owned++; 6376 break; 6377 default: 6378 LOG_WARN(BSL_LS_BCM_RX, 6379 (BSL_META_U(unit, 6380 BSL_META_U 6381 (unit, 6382 "rx_process_packet: unit=%d: " 6383 "Invalid callback return value=%d\n")), 6384 unit, handler_rc)); 6385 break; 6386 } 6387 6388 if (handled) { 6389 break; 6390 } 6391 } 6392 /* 6393 * Preserving these flags that were conditionally set 6394 * in function bcm_pkt_flags_init(int unit, bcm_pkt_t *pkt, uint32 flags) 6395 */ 6396 pkt->flags &= (BCM_PKT_F_HGHDR | BCM_PKT_F_SLTAG); 6397 RX_UNLOCK(unit); 6398 6399 if (!handled) { 6400 /* Internal error as discard should have handled packet */ 6401 if (SOC_UNIT_VALID(unit)) { 6402 RX_ERROR((BSL_META_U(unit, 6403 "bcm_rx_process_packet: No handler processed packet: " 6404 "Port %s\n"), 6405 SOC_PORT_NAME(unit, pkt->rx_port))); 6406 } else { 6407 RX_ERROR((BSL_META_U(unit, 6408 "bcm_rx_process_packet: No handler processed packet: " 6409 "Port %d\n"), 6410 pkt->rx_port)); 6411 } 6412 6413 MARK_PKT_PROCESSED(pkt, unit, pkt->dma_channel, dv); 6414 } 6415 } 6416 6417 /****************************************************************/ 6418 6419 6420 /**************************************************************** 6421 * 6422 * Setup routines 6423 */ 6424 6425 /* 6426 * Function: 6427 * rx_channel_dv_setup 6428 * Purpose: 6429 * Set up DVs and packets for a channel according to current config 6430 * Parameters: 6431 * unit, chan - what's being configured 6432 * Returns: 6433 * BCM_E_XXX 6434 * Notes: 6435 * This is only called during the init (bcm_rx_start) 6436 * Local units only. 6437 */ 6438 6439 STATIC int 6440 rx_channel_dv_setup(int unit, int chan) 6441 { 6442 int i, j; 6443 dv_t *dv; 6444 int rv; 6445 bcm_pkt_t *all_pkts; 6446 bcm_pkt_t *pkt; 6447 uint32 dma_flags = 0; 6448 6449 /* If channel is not configured for RX, configure it. */ 6450 switch (soc_dma_chan_dvt_get(unit, chan)) { 6451 case DV_RX: /* Already RX - check flags */ 6452 if (RX_CHAN_FLAGS(unit, chan) & BCM_RX_F_OVERSIZED_OK) { 6453 /* Force reconfiguration */ 6454 dma_flags = SOC_DMA_F_MBM | SOC_DMA_F_INTR_ON_DESC; 6455 LOG_VERBOSE(BSL_LS_BCM_RX, 6456 (BSL_META_U(unit, 6457 BSL_META_U(unit, "rx: accept oversized pkts\n")))); 6458 } 6459 break; 6460 case DV_NONE: /* Need to configure the channel */ 6461 dma_flags = SOC_DMA_F_MBM; 6462 break; 6463 default: /* Problem */ 6464 RX_ERROR((BSL_META_U(unit, "Incompatible channel setup for %d/%d\n"), 6465 unit, chan)); 6466 return BCM_E_PARAM; 6467 } 6468 6469 /* Check if we need to (re)configure Rx DMA channel */ 6470 if (dma_flags) { 6471 rv = soc_dma_chan_config(unit, chan, DV_RX, dma_flags); 6472 if (rv < 0) { 6473 RX_ERROR((BSL_META_U 6474 (unit, "Could not configure channel %d on %d\n"), 6475 chan, unit)); 6476 return rv; 6477 } 6478 } else { 6479 /* Clear the dma_started flag to allow DMA to be restarted without 6480 * a call to soc_dma_chan_config() 6481 */ 6482 soc_dma_chan_started_clear(unit, chan); 6483 } 6484 6485 /* Allocate the packet structures we need for the DVs */ 6486 if (RX_CHAN_PKTS(unit, chan) == NULL) { 6487 all_pkts = sal_alloc(sizeof(bcm_pkt_t) * 6488 RX_CHAN_PKT_COUNT(unit, chan), "rx_pkts"); 6489 if (all_pkts == NULL) { 6490 return BCM_E_MEMORY; 6491 } 6492 sal_memset(all_pkts, 0, sizeof(bcm_pkt_t) * RX_PPC(unit) * 6493 RX_CHAINS(unit, chan)); 6494 RX_CHAN_PKTS(unit, chan) = all_pkts; 6495 } 6496 6497 /* Set up packets and allocate DVs */ 6498 for (i = 0; i < RX_CHAINS(unit, chan); i++) { 6499 /* 6500 * coverity: unit already initialized 6501 * the unit is also check in 6502 * _bcm_common_rx_start from where rx_channel_dv_setup 6503 * is called. 6504 */ 6505 /* coverity[overrun-call] */ 6506 if ((dv = rx_dv_alloc(unit, chan, i)) == NULL) { 6507 for (j = 0; j < i; j++) { 6508 rx_dv_dealloc(unit, chan, j); 6509 RX_DV(unit, chan, i) = NULL; 6510 } 6511 sal_free(RX_CHAN_PKTS(unit, chan)); 6512 RX_CHAN_PKTS(unit, chan) = NULL; 6513 return BCM_E_MEMORY; 6514 } 6515 for (j = 0; j < RX_PPC(unit); j++) { 6516 pkt = RX_PKT(unit, chan, i, j); 6517 pkt->_idx = j; 6518 pkt->_dv = dv; 6519 pkt->unit = unit; 6520 pkt->pkt_data = &pkt->_pkt_data; 6521 pkt->blk_count = 1; 6522 if ((SOC_UNIT_VALID(unit) && SOC_IS_XGS12_FABRIC(unit)) 6523 && !RX_IGNORE_HG(unit)) { 6524 BCM_PKT_HGHDR_REQUIRE(pkt); 6525 } 6526 if ((SOC_UNIT_VALID(unit) && SOC_SL_MODE(unit)) 6527 && !RX_IGNORE_SL(unit)) { 6528 BCM_PKT_SLTAG_REQUIRE(pkt); 6529 } 6530 } 6531 6532 DV_STATE(dv) = DV_S_NEEDS_FILL; 6533 RX_DV(unit, chan, i) = dv; 6534 } 6535 6536 return BCM_E_NONE; 6537 } 6538 6539 6540 STATIC int 6541 rx_discard_handler_setup(int unit, rx_ctl_t *rx_ctrl_ptr) 6542 { 6543 volatile rx_callout_t *rco; 6544 int i; 6545 6546 if ((rco = sal_alloc(sizeof(*rco), "rx_callout")) == NULL) { 6547 return BCM_E_MEMORY; 6548 } 6549 SETUP_RCO(rco, "Discard", rx_discard_packet, BCM_RX_PRIO_MIN, NULL, NULL, 6550 BCM_RCO_F_ALL_COS); /* Accept any cos; non-interrupt */ 6551 for (i = 0; i <= rx_ctrl_ptr->queue_max; i++) { 6552 SETUP_RCO_COS_SET(rco, i); 6553 } 6554 rx_ctrl_ptr->rc_callout = rco; 6555 6556 return BCM_E_NONE; 6557 } 6558 6559 /* 6560 * Check the channel configuration passed in by the user for legal values 6561 */ 6562 6563 STATIC void 6564 rx_user_cfg_check(int unit) 6565 { 6566 int chan; 6567 uint32 cos_bmp = 0; 6568 int chan_count = 0; 6569 bcm_rx_cfg_t *cfg; 6570 int cos; 6571 rx_queue_t *queue; 6572 6573 cfg = &rx_ctl[unit]->user_cfg; 6574 6575 if (RX_IS_LOCAL(unit) || RX_IS_RCPU(unit)) { 6576 FOREACH_SETUP_CHANNEL(unit, chan) { 6577 if (RX_CHAINS(unit, chan) < 0) { 6578 LOG_WARN(BSL_LS_BCM_RX, 6579 (BSL_META_U(unit, 6580 BSL_META_U 6581 (unit, "rx_config %d %d: Warning: chains < 0.")), 6582 unit, chan)); 6583 RX_CHAINS(unit, chan) = 0; 6584 } else { 6585 chan_count++; 6586 if (RX_CHAINS(unit, chan) > RX_CHAINS_MAX) { 6587 LOG_WARN(BSL_LS_BCM_RX, 6588 (BSL_META_U(unit, 6589 BSL_META_U 6590 (unit, "rx_config %d %d: Warning: " 6591 "Bad chain cnt %d. Now %d.\n")), 6592 unit, chan, 6593 RX_CHAINS(unit, chan), RX_CHAINS_MAX)); 6594 RX_CHAINS(unit, chan) = RX_CHAINS_MAX; 6595 } 6596 } 6597 } 6598 if (cfg->pkts_per_chain <= 0 || 6599 cfg->pkts_per_chain > RX_PPC_MAX) { 6600 int dflt_pkts_per_chain = 0; 6601 /* unit is validated via bcm_rx_start that calls this routine */ 6602 /* coverity[overrun-local] */ 6603 if (soc_feature(unit, soc_feature_cmicx)) { 6604 dflt_pkts_per_chain = RX_CMICX_PPC_DFLT; 6605 } else { 6606 dflt_pkts_per_chain = RX_PPC_DFLT; 6607 } 6608 6609 LOG_WARN(BSL_LS_BCM_RX, 6610 (BSL_META_U(unit, 6611 BSL_META_U 6612 (unit, "rx_config: Warning: bad pkts/chn %d. Now %d.\n")), 6613 cfg->pkts_per_chain, dflt_pkts_per_chain)); 6614 cfg->pkts_per_chain = dflt_pkts_per_chain; 6615 } 6616 6617 if (SOC_UNIT_VALID(unit) && SOC_IS_XGS(unit)) { 6618 /* Assumes all XGS devices support 8 COS */ 6619 /* Check if all COS are accounted for and no overlap */ 6620 FOREACH_SETUP_CHANNEL(unit, chan) { 6621 if (cos_bmp & RX_CHAN_COS(unit, chan)) { 6622 LOG_WARN(BSL_LS_BCM_RX, 6623 (BSL_META_U(unit, 6624 BSL_META_U 6625 (unit, "rx_config: Warning: COS overlap may not " 6626 "function correctly, unit %d, channel %d\n")), 6627 unit, chan)); 6628 } 6629 cos_bmp |= RX_CHAN_COS(unit, chan); 6630 } 6631 if ((cos_bmp = (0xff & ~cos_bmp))) { 6632 LOG_WARN(BSL_LS_BCM_RX, 6633 (BSL_META_U(unit, 6634 BSL_META_U 6635 (unit, "rx_config: Warning: Not mapping " 6636 "COS 0x%x for unit %d\n")), cos_bmp, unit)); 6637 } 6638 } else { 6639 if (chan_count > 1 && !SOC_IS_DNX(unit)) { 6640 LOG_WARN(BSL_LS_BCM_RX, 6641 (BSL_META_U(unit, 6642 BSL_META_U 6643 (unit, "rx_config: Warning: Activating more " 6644 "than one channel on non-xgs system\n")))); 6645 } 6646 } 6647 } 6648 /* coverity[overrun-local : FALSE] */ 6649 6650 /* coverity[overrun-local] */ 6651 if (RX_PPS(unit) < 0) { 6652 RX_PPS(unit) = 0; 6653 } 6654 6655 for (cos = 0; cos <= RX_QUEUE_MAX(unit); cos++) { 6656 queue = RX_QUEUE(unit, cos); 6657 if (queue->pps < 0) { 6658 queue->pps = 0; 6659 } 6660 if (queue->max_len < 0) { 6661 queue->max_len = 0; 6662 } 6663 } 6664 6665 } 6666 6667 /**************************************************************** 6668 * 6669 * Tear down routines 6670 */ 6671 6672 /* 6673 * Function: 6674 * rx_channel_shutdown 6675 * Purpose: 6676 * Shutdown a channel, deallocating DVs and packets 6677 * Parameters: 6678 * unit, chan - what's being configured 6679 * Returns: 6680 * BCM_E_XXX 6681 * Notes: 6682 * This is only called when thread is brought down (bcm_rx_stop) 6683 * or on an error 6684 * 6685 * Must only be called on local units. 6686 */ 6687 6688 STATIC void 6689 rx_channel_shutdown(int unit, int chan) 6690 { 6691 int i; 6692 bcm_pkt_t *pkt; 6693 6694 _rx_chan_run_count--; 6695 rx_ctl[unit]->chan_running &= ~(1 << chan); 6696 if (RX_CHAN_USED(unit, chan)) { 6697 /* Deallocate all packets */ 6698 if (RX_CHAN_PKTS(unit, chan) != NULL) { 6699 /* Free any buffers held by packets */ 6700 for (i = 0; i < RX_CHAN_PKT_COUNT(unit, chan); i++) { 6701 pkt = &RX_CHAN_PKTS(unit, chan)[i]; 6702 if (pkt->alloc_ptr != NULL) { 6703 bcm_rx_free(unit, pkt->alloc_ptr); 6704 if (rx_ctl[unit] == NULL) { 6705 return; 6706 } 6707 pkt->_pkt_data.data = NULL; 6708 pkt->alloc_ptr = NULL; 6709 } 6710 } 6711 sal_free(RX_CHAN_PKTS(unit, chan)); 6712 RX_CHAN_PKTS(unit, chan) = NULL; 6713 } 6714 if (SOC_UNIT_VALID(unit)) { 6715 /* Deallocate the DVs */ 6716 for (i = 0; i < RX_CHAINS(unit, chan); i++) { 6717 rx_dv_dealloc(unit, chan, i); 6718 } 6719 } 6720 } 6721 } 6722 6723 /**************************************************************** 6724 * 6725 * Info/calculation routines 6726 */ 6727 6728 /* 6729 * Calculate number of DCBs per packet based on system cfg. 6730 * The MACs are always set up separately. The VLAN is skipped 6731 * on Hercules. 6732 * 6733 * The following always get a DCB: 6734 * HiGig header 6735 * SL tag 6736 * Everything past the SL tag 6737 * 6738 * If the NO_VTAG flag is given, then an extra DCB is needed for that. 6739 * In that case, we also need a DCB for the MAC addresses. 6740 */ 6741 6742 STATIC void 6743 rx_dcb_per_pkt_init(int unit) 6744 { 6745 int chan; 6746 int dcb; 6747 uint32 dma_chan; 6748 6749 dcb = 3; 6750 if (SOC_UNIT_VALID(unit) && SOC_SL_MODE(unit)) { 6751 dcb += 1; /* sl mode stack tag */ 6752 } 6753 6754 /* unit is already initialized and validated. unit can be between 0 to 127 */ 6755 /* coverity[overrun-call] */ 6756 soc_dma_max_rx_channels_get(unit, &dma_chan); 6757 6758 for (chan = 0; chan < dma_chan; chan++) { 6759 if (RX_CHAN_FLAGS(unit, chan) & BCM_RX_F_MULTI_DCB) { 6760 RX_CHAN_CTL(unit, chan).dcb_per_pkt = dcb; 6761 } else { 6762 RX_CHAN_CTL(unit, chan).dcb_per_pkt = 1; 6763 } 6764 } 6765 } 6766 6767 6768 /**************************************************************** 6769 * 6770 * DV manipulation functions 6771 * rx_dv_add_pkt Add a packet to a DV 6772 * rx_dv_fill Prepare a DV to be sent to the SOC layer 6773 * rx_dv_alloc Allocate an RX DV 6774 * rx_dv_dealloc Free an RX DV 6775 */ 6776 6777 /* Set up a DV for multiple DCBs (pkt scatter) according to packet format */ 6778 STATIC INLINE int 6779 rx_multi_dv_pkt(int unit, volatile bcm_pkt_t *pkt, dv_t *dv, int idx) 6780 { 6781 int bytes_used; 6782 uint8 *data_ptr; 6783 6784 #ifdef BCM_XGS_SUPPORT 6785 /* { */ 6786 /* HIGIG HEADER: Always into DV struct if present */ 6787 if (BCM_PKT_HAS_HGHDR(pkt)) { 6788 SOC_IF_ERROR_RETURN(SOC_DCB_ADDRX(unit, dv, 6789 (sal_vaddr_t)SOC_DV_HG_HDR(dv, idx), 6790 sizeof(soc_higig_hdr_t), 0)); 6791 } 6792 /* } */ 6793 #endif 6794 6795 /* Set up DCB for DMAC and SMAC: Always into packet */ 6796 SOC_IF_ERROR_RETURN(SOC_DCB_ADDRX(unit, dv, 6797 (sal_vaddr_t)BCM_PKT_DMAC(pkt), 6798 2 * sizeof(bcm_mac_t), 0)); 6799 bytes_used = 2 * sizeof(bcm_mac_t); 6800 6801 /* Setup DCB for VLAN: Either into DV struct, or pkt as per flags */ 6802 if (!SOC_IS_XGS12_FABRIC(unit)) { 6803 /* Assume VLAN tag goes into packet. */ 6804 data_ptr = &pkt->_pkt_data.data[12]; 6805 if (BCM_PKT_RX_VLAN_TAG_STRIP(pkt)) { 6806 /* Oops, VLAN tag must be placed in non-pkt buffer */ 6807 data_ptr = SOC_DV_VLAN_TAG(dv, idx); 6808 } else { 6809 /* Okay, VLAN in pkt. Adjust byte count for pkt buffer */ 6810 bytes_used += sizeof(uint32); /* Used for VLAN in pkt */ 6811 } 6812 /* data_ptr now points to where VLAN tag should be DMA'd */ 6813 SOC_IF_ERROR_RETURN(SOC_DCB_ADDRX(unit, dv, 6814 (sal_vaddr_t)data_ptr, 6815 sizeof(uint32), 0)); 6816 } else { /* Adjust bytes used to add space for VLAN tag if not stripped */ 6817 if (!BCM_PKT_RX_VLAN_TAG_STRIP(pkt)) { /* Save space for VLAN tag */ 6818 bytes_used += sizeof(uint32); 6819 } 6820 } 6821 6822 /* Setup DCB for SL TAG when present: Always put into DV struct */ 6823 if (BCM_PKT_HAS_SLTAG(pkt)) { 6824 SOC_IF_ERROR_RETURN(SOC_DCB_ADDRX(unit, dv, 6825 (sal_vaddr_t)SOC_DV_SL_TAG(dv, idx), 6826 sizeof(uint32), 0)); 6827 } 6828 6829 /* Setup DCB for PAYLOAD + CRC: Always into packet */ 6830 SOC_IF_ERROR_RETURN(SOC_DCB_ADDRX(unit, dv, 6831 (sal_vaddr_t)&(pkt->_pkt_data.data[bytes_used]), 6832 pkt->_pkt_data.len - bytes_used, 6833 0)); 6834 6835 return BCM_E_NONE; 6836 } 6837 6838 6839 /* 6840 * Set up a packet in a DV. Use packet scatter for parts of packet 6841 */ 6842 6843 STATIC INLINE int 6844 rx_dv_add_pkt(int unit, volatile bcm_pkt_t *pkt, int idx, dv_t *dv) 6845 { 6846 if (RX_CHAN_FLAGS(unit, DV_CHANNEL(dv)) & BCM_RX_F_MULTI_DCB) { 6847 BCM_IF_ERROR_RETURN(rx_multi_dv_pkt(unit, pkt, dv, idx)); 6848 } else { 6849 /* Setup single DCB for all headers + PAYLOAD + CRC */ 6850 SOC_IF_ERROR_RETURN(SOC_DCB_ADDRX(unit, dv, 6851 (sal_vaddr_t)(pkt->_pkt_data.data), 6852 pkt->_pkt_data.len, 6853 0)); 6854 } 6855 6856 soc_dma_desc_end_packet(dv); 6857 6858 return BCM_E_NONE; 6859 } 6860 6861 6862 /* 6863 * Function: 6864 * rx_dv_fill 6865 * Purpose: 6866 * Try to fill a DV with any packets it needs 6867 * Parameters: 6868 * unit 6869 * chan 6870 * dv 6871 * Returns: 6872 * BCM_E_XXX 6873 * Notes: 6874 * If successful changes the state of the DV. 6875 * If memory error occurs, the state of the DV is not 6876 * changed, but an error is not returned. 6877 */ 6878 6879 static INLINE void 6880 rx_dv_fill(int unit, int chan, dv_t *dv) 6881 { 6882 int i; 6883 volatile bcm_pkt_t *pkt; 6884 rx_dv_info_t *save_info; 6885 static int warned = 0; 6886 void *pkt_data; 6887 int rv; 6888 #if defined(BCM_CMICX_SUPPORT) 6889 uint32 prefetch = 0; 6890 #endif 6891 6892 pkt_data = NULL; 6893 save_info = DV_INFO(dv); /* Save info before resetting dv */ 6894 soc_dma_dv_reset(DV_RX, dv); 6895 #ifdef BCM_RX_REFILL_FROM_INTR 6896 /* { */ 6897 dv->dv_flags |= DV_F_NOTIFY_CHN; 6898 /* } */ 6899 #endif 6900 dv->_DV_INFO = save_info; /* Restore info to DV */ 6901 6902 assert(DV_STATE(dv) == DV_S_NEEDS_FILL); 6903 6904 for (i = 0; i < RX_PPC(unit); i++) { 6905 pkt = DV_PKT(dv, i); 6906 if (pkt->_pkt_data.data == NULL) { 6907 /* No pkt buffer; it needs to be allocated; use dflt size */ 6908 rv = bcm_rx_alloc(unit, -1, RX_CHAN_FLAGS(unit, chan), &pkt_data); 6909 if (BCM_FAILURE(rv)) {/* Failed to allocate a pkt for this DV. */ 6910 if (!warned) { 6911 warned = 1; 6912 LOG_WARN(BSL_LS_BCM_RX, (BSL_META_U(unit, BSL_META_U 6913 (unit, "RX: Failed to allocate packet" 6914 " memory, consider allocating a larger" 6915 " RX pool with config setting" 6916 " \"rx_pool_nof_pkts=<pkts>\"\n")))); 6917 } 6918 RX_CHAN_CTL(unit, chan).mem_fail++; 6919 return; /* Not an error, try again later */ 6920 } 6921 pkt->_pkt_data.data = pkt_data; 6922 pkt->alloc_ptr = pkt_data; 6923 pkt->_pkt_data.len = rx_ctl[unit]->user_cfg.pkt_size; 6924 } else { 6925 pkt->_pkt_data.data = pkt->alloc_ptr; 6926 } 6927 6928 /* Set up CRC stripping */ 6929 if (RX_CHAN_FLAGS(unit, chan) & BCM_RX_F_CRC_STRIP) { 6930 pkt->flags |= BCM_RX_CRC_STRIP; 6931 } else { 6932 pkt->flags &= ~BCM_RX_CRC_STRIP; 6933 } 6934 6935 /* Set up Vlan Tag stripping */ 6936 if (RX_CHAN_FLAGS(unit, chan) & BCM_RX_F_VTAG_STRIP) { 6937 pkt->flags |= BCM_PKT_F_NO_VTAG; 6938 } else { 6939 pkt->flags &= ~BCM_PKT_F_NO_VTAG; 6940 } 6941 6942 /* Set up the packet in the DCBs of the DV */ 6943 if ((rv = rx_dv_add_pkt(unit, pkt, i, dv)) < 0) { 6944 DV_STATE(dv) = DV_S_ERROR; 6945 LOG_WARN(BSL_LS_BCM_RX, 6946 (BSL_META_U(unit, 6947 BSL_META_U 6948 (unit, "Failed to add pkt %d to dv on unit %d: %s\n")), 6949 i, unit, bcm_errmsg(rv))); 6950 break; 6951 } 6952 } 6953 6954 #if defined (BCM_CMICDV2_SUPPORT) || defined(BCM_CMICX_SUPPORT) 6955 /* { */ 6956 /* Use dma_flags to check for continuous mode */ 6957 if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) { 6958 /* Add reload descriptor */ 6959 if((rv = soc_dma_rld_desc_add(dv, 0)) < 0) { 6960 RX_WARN((BSL_META_U 6961 (unit, "Failed to add reload desc to dv on unit/chan %d/%d\n"), 6962 unit, chan)); 6963 } 6964 } 6965 /* } */ 6966 #endif 6967 6968 #if defined(BCM_CMICX_SUPPORT) 6969 if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) { 6970 prefetch = 1; 6971 } 6972 6973 if (!prefetch) { 6974 soc_dma_contiguous_desc_add(dv); 6975 } 6976 #endif 6977 6978 if (DV_STATE(dv) != DV_S_ERROR) { /* Mark as ready to be started */ 6979 DV_STATE(dv) = DV_S_FILLED; 6980 DV_PKTS_PROCESSED(dv) = 0; 6981 } 6982 6983 return; 6984 } 6985 6986 /* 6987 * Allocate and clear a DV (DMA chain control unit) 6988 * Local units only 6989 */ 6990 static INLINE dv_t * 6991 rx_dv_alloc(int unit, int chan, int dv_idx) 6992 { 6993 dv_t *dv; 6994 rx_dv_info_t *dv_info; 6995 int clr_len; 6996 int dcbs_per_dv; 6997 6998 /* Add an extra DCB for reload in continuous mode */ 6999 if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) { 7000 dcbs_per_dv = RX_DCB_PER_DV(unit, chan) + 1; 7001 } else { 7002 dcbs_per_dv = RX_DCB_PER_DV(unit, chan); 7003 } 7004 7005 LOG_VERBOSE(BSL_LS_BCM_RX, 7006 (BSL_META_U(unit, 7007 "RX: Allocating %d %d %d- %d dcbs\n"), 7008 unit, chan, dv_idx, dcbs_per_dv)); 7009 7010 if ((dv = soc_dma_dv_alloc(unit, DV_RX, dcbs_per_dv)) == NULL) { 7011 return NULL; 7012 } 7013 7014 /* not a queued dv */ 7015 if (dv->_DV_INFO == NULL) { 7016 if ((dv_info = sal_alloc(sizeof(rx_dv_info_t), "dv_info")) == NULL) { 7017 soc_dma_dv_free(unit, dv); 7018 return NULL; 7019 } 7020 } else { 7021 dv_info = dv->_DV_INFO; 7022 } 7023 sal_memset(dv_info, 0, sizeof(rx_dv_info_t)); 7024 7025 /* DCBs MUST start off 0 */ 7026 clr_len = SOC_DCB_SIZE(unit) * dcbs_per_dv; 7027 7028 sal_memset(dv->dv_dcb, 0, clr_len); 7029 7030 /* Set up and install the DV and its info structure */ 7031 dv->dv_done_chain = rx_done_chain; 7032 dv->dv_done_packet = rx_done_packet; 7033 dv->dv_done_reload = rx_done_reload; 7034 7035 dv_info->idx = dv_idx; 7036 dv_info->chan = chan; 7037 dv_info->state = DV_S_NEEDS_FILL; 7038 dv->_DV_INFO = dv_info; 7039 7040 DV_RX_IDX_SET(dv, rx_dv_count++); /* Debug: Indicate DVs index */ 7041 7042 return dv; 7043 } 7044 7045 /* Free a DV and any packets it controls */ 7046 STATIC INLINE void 7047 rx_dv_dealloc(int unit, int chan, int dv_idx) 7048 { 7049 dv_t *dv; 7050 rx_dv_info_t *dv_info; 7051 7052 dv = RX_DV(unit, chan, dv_idx); 7053 7054 if (dv) { 7055 dv_info = DV_INFO(dv); 7056 /* release dv_info, no matter it's queued dv or not */ 7057 if (dv_info) { 7058 sal_free(dv_info); 7059 dv->_DV_INFO = NULL; 7060 } 7061 RX_DV(unit, chan, dv_idx) = NULL; 7062 soc_dma_dv_free(unit, dv); 7063 } 7064 } 7065 7066 void 7067 rx_dv_free_cb(int unit, dv_t *dv) 7068 { 7069 rx_dv_info_t *dv_info; 7070 if (unit) { 7071 ; 7072 } 7073 if (dv) { 7074 if (dv->dv_done_chain == rx_done_chain) { 7075 dv_info = DV_INFO(dv); 7076 if (dv_info) { 7077 sal_free(dv_info); 7078 } 7079 } 7080 } 7081 7082 } 7083 7084 /**************************************************************** 7085 * 7086 * Rate limiting code 7087 */ 7088 7089 /* 7090 * Function: 7091 * rx_init_all_tokens 7092 * Purpose: 7093 * Initialize all RX token buckets 7094 * Parameters: 7095 * unit - Strata XGS unit number 7096 * Returns: 7097 * BCM_E_XXX 7098 * Notes: 7099 * Includes top level limit, per channel limits and per cos limits. 7100 */ 7101 7102 STATIC void 7103 rx_init_all_tokens(int unit) 7104 { 7105 int cos; 7106 sal_usecs_t cur_time; 7107 rx_queue_t *queue; 7108 7109 cur_time = sal_time_usecs(); 7110 RX_TOKENS(unit) = RX_BURST(unit); 7111 rx_ctl[unit]->last_fill = cur_time; 7112 7113 last_fill_check = sal_time_usecs(); 7114 for (cos = 0; cos <= RX_QUEUE_MAX(unit); cos++) { 7115 queue = RX_QUEUE(unit, cos); 7116 queue->tokens = queue->burst; 7117 queue->last_fill = cur_time; 7118 } 7119 7120 rx_control.system_tokens = rx_control.system_pps; 7121 rx_control.system_last_fill = cur_time; 7122 } 7123 7124 /* Initialize the queues. */ 7125 STATIC int 7126 rx_queue_init(int unit, rx_ctl_t *rx_ctrl_ptr) 7127 { 7128 int queue_size, cos; 7129 rx_queue_t *queue; 7130 7131 queue_size = sizeof(rx_queue_t) * BCM_RX_COS; 7132 rx_ctrl_ptr->pkt_queue = sal_alloc(queue_size, "pkt_queue"); 7133 if (rx_ctrl_ptr->pkt_queue == NULL) { 7134 return BCM_E_MEMORY; 7135 } 7136 sal_memset(rx_ctrl_ptr->pkt_queue, 0, queue_size); 7137 7138 for (cos = 0; cos <= rx_ctrl_ptr->queue_max; cos++) { 7139 queue = rx_ctrl_ptr->pkt_queue + cos; 7140 queue->head = NULL; 7141 queue->tail = NULL; 7142 queue->count = 0; 7143 queue->max_len = RX_Q_MAX_DFLT; 7144 queue->lock = sal_spinlock_create("rx_queue"); 7145 if (!queue->lock) { 7146 rx_queue_cleanup(unit, rx_ctrl_ptr); 7147 return BCM_E_MEMORY; 7148 } 7149 } 7150 7151 return BCM_E_NONE; 7152 } 7153 7154 /* Deinitialize the queues. */ 7155 STATIC void 7156 rx_queue_cleanup(int unit, rx_ctl_t *rx_ctrl_ptr) 7157 { 7158 int cos; 7159 rx_queue_t *queue; 7160 7161 for (cos = 0; cos <= rx_ctrl_ptr->queue_max; cos++) { 7162 queue = rx_ctrl_ptr->pkt_queue + cos; 7163 if (queue->lock) { 7164 sal_spinlock_destroy(queue->lock); 7165 } 7166 } 7167 7168 sal_free(rx_ctrl_ptr->pkt_queue); 7169 } 7170 7171 /**************************************************************** 7172 * 7173 * Other functions accessed through RX subsystem: 7174 * Discard packet handler: Always registered first 7175 * Default alloc/free routines: Provided for default config 7176 */ 7177 7178 /* 7179 * Function: 7180 * rx_discard_packet 7181 * Purpose: 7182 * Lowest priority registered handler that discards packet. 7183 * Parameters: 7184 * unit - StrataSwitch Unit number. 7185 * pkt - The packet to handle 7186 * cookie - (Not used) 7187 * Returns: 7188 * bcm_rx_handled 7189 */ 7190 7191 STATIC bcm_rx_t 7192 rx_discard_packet(int unit, bcm_pkt_t *pkt, void *cookie) 7193 { 7194 int chan; 7195 7196 COMPILER_REFERENCE(cookie); 7197 chan = pkt->dma_channel; 7198 7199 ++(rx_ctl[unit]->chan_ctl[chan].dpkt); 7200 rx_ctl[unit]->chan_ctl[chan].dbyte += pkt->tot_len; 7201 7202 return(BCM_RX_HANDLED); 7203 } 7204 7205 #if defined(BROADCOM_DEBUG) 7206 /* { */ 7207 7208 static char *dv_state_names[] = DV_STATE_STRINGS; 7209 7210 /* 7211 * Function: 7212 * bcm_rx_show 7213 * Purpose: 7214 * Show RX information for the specified device. 7215 * Parameters: 7216 * unit - StrataSwitch unit number. 7217 * Returns: 7218 * Nothing. 7219 */ 7220 7221 int 7222 _bcm_common_rx_show(int unit) 7223 { 7224 volatile rx_callout_t *rco; 7225 int chan; 7226 dv_t *dv; 7227 int i; 7228 sal_usecs_t cur_time; 7229 rx_queue_t *queue; 7230 uint32 cosq0, cosq1; 7231 7232 RX_UNIT_CHECK(unit); 7233 7234 if (!RX_INIT_DONE(unit)) { 7235 RX_PRINT(("Initializing RX subsystem (%d)\n", 7236 bcm_rx_init(unit))); 7237 } 7238 7239 cur_time = sal_time_usecs(); 7240 RX_PRINT(("RX Info @ time=%u: %sstarted. Last fill %u. " 7241 "Thread is %srunning.\n" 7242 " +verbose for more info\n", 7243 cur_time, 7244 RX_UNIT_STARTED(unit) ? "" : "not ", 7245 last_fill_check, 7246 rx_control.thread_running ? "" : "not ")); 7247 7248 RX_PRINT((" Pkt Size %d. Pkts/Chain %d. All COS PPS %d. Burst %d." 7249 " Flags %x.\n", 7250 RX_PKT_SIZE(unit), RX_PPC(unit), RX_PPS(unit), RX_BURST(unit), 7251 RX_USER_FLAGS(unit))); 7252 RX_PRINT((" Sys PPS %d. Sys tokens %d. Sys fill %u.\n", 7253 rx_control.system_pps, rx_control.system_tokens, 7254 rx_control.system_last_fill)); 7255 RX_PRINT((" Cntrs: Pkts %d. Last start %d. Tunnel %d. Owned %d.\n" 7256 " Bad Hndlr %d. No Hndlr %d. Not Running %d.\n" 7257 " Thrd Not Running %d. DCB Errs %d.\n", 7258 rx_ctl[unit]->tot_pkts, 7259 rx_ctl[unit]->pkts_since_start, 7260 rx_ctl[unit]->tunnelled, 7261 rx_ctl[unit]->pkts_owned, 7262 rx_ctl[unit]->bad_hndlr_rv, 7263 rx_ctl[unit]->no_hndlr, 7264 rx_ctl[unit]->not_running, 7265 rx_ctl[unit]->thrd_not_running, 7266 rx_ctl[unit]->dcb_errs)); 7267 LOG_VERBOSE(BSL_LS_BCM_RX, 7268 (BSL_META_U(unit, 7269 BSL_META_U 7270 (unit, " Tokens %d. Sleep %d.\n" 7271 " Thread: %p. run %d. exitted %d. pri %d.\n")), 7272 RX_TOKENS(unit), 7273 rx_control.sleep_cur, 7274 (void *)rx_control.rx_tid, 7275 rx_control.thread_running, 7276 rx_control.thread_exit_complete, 7277 SOC_UNIT_VALID(unit) ? soc_property_get(unit, 7278 spn_BCM_RX_THREAD_PRI, 7279 RX_THREAD_PRI_DFLT) : 0)); 7280 7281 RX_PRINT((" Registered callbacks:\n")); 7282 /* Display callouts and priority in order */ 7283 for (rco = rx_ctl[unit]->rc_callout; rco; rco = rco->rco_next) { 7284 RX_PRINT((" %-10s Priority=%3d%s. " 7285 "Argument=0x%x. COS 0x%x%08x.\n", 7286 rco->rco_name, (uint32)rco->rco_priority, 7287 (rco->rco_flags & BCM_RCO_F_INTR) ? " Interrupt" : "", 7288 PTR_TO_INT(rco->rco_cookie), 7289 rco->rco_cos[1], rco->rco_cos[0])); 7290 RX_PRINT((" %10s Packets handled %u, owned %u.\n", " ", 7291 rco->rco_pkts_handled, 7292 rco->rco_pkts_owned)); 7293 } 7294 7295 RX_PRINT((" Channel Info\n")); 7296 7297 FOREACH_SETUP_CHANNEL(unit, chan) { 7298 RX_PRINT((" Chan %d is %s: Chains %d. COS 0x%x. DCB/pkt %d\n", 7299 chan, 7300 RX_CHAN_RUNNING(unit, chan) ? "running" : "setup", 7301 RX_CHAINS(unit, chan), 7302 RX_CHAN_CFG(unit, chan).cos_bmp, 7303 RX_CHAN_CTL(unit, chan).dcb_per_pkt)); 7304 RX_PRINT((" rpkt %d. rbyte %d. dpkt %d. dbyte %d. " 7305 "mem fail %d flags %x.\n", 7306 RX_CHAN_CTL(unit, chan).rpkt, RX_CHAN_CTL(unit, chan).rbyte, 7307 RX_CHAN_CTL(unit, chan).dpkt, RX_CHAN_CTL(unit, chan).dbyte, 7308 RX_CHAN_CTL(unit, chan).mem_fail, RX_CHAN_FLAGS(unit, chan))); 7309 /* 7310 * If unit is not within the permissible limit of 0 to 127, 7311 * then we exit from RX_INIT_CHECK itself. 7312 */ 7313 /* coverity[overrun-local] */ 7314 if (soc_feature(unit, soc_feature_cmicx)) { 7315 /* 7316 * unit is already initialized and validated. 7317 * unit can be between 0 to 127 7318 */ 7319 /* coverity[overrun-call] */ 7320 soc_dma_chan_cos_ctrl_get(unit, chan, 1, &cosq0); 7321 /* coverity[overrun-call] */ 7322 soc_dma_chan_cos_ctrl_get(unit, chan, 2, &cosq1); 7323 7324 RX_PRINT((" cosq1 0x%x. cosq0 0x%x.\n", cosq1, cosq0)); 7325 } 7326 7327 /* Display all DVs allocated */ 7328 if (bsl_check(bslLayerSoc, bslSourcePacketdma, bslSeverityVerbose, unit)) { 7329 for (i = 0; i < RX_CHAINS(unit, chan); i++) { 7330 dv = RX_DV(unit, chan, i); 7331 if (dv == NULL || !soc_dma_dv_valid(dv)) { 7332 RX_PRINT((" DV %d (%p) is not valid\n", 7333 i, (void *)dv)); 7334 } else { 7335 RX_PRINT((" DV %d (%d, %p) %s. chan %d. " 7336 "pkt cnt %d. pkt[%d] %p\n", 7337 i, DV_INDEX(dv), (void *)dv, 7338 dv_state_names[DV_STATE(dv)], 7339 DV_CHANNEL(dv), 7340 DV_PKTS_PROCESSED(dv), 7341 DV_PKTS_PROCESSED(dv), 7342 (void *)DV_PKT(dv, DV_PKTS_PROCESSED(dv)))); 7343 if (DV_STATE(dv) == DV_S_SCHEDULED) { 7344 RX_PRINT((" Sched at %u for %d; " 7345 "future %d\n", 7346 DV_SCHED_TIME(dv), 7347 DV_TIME_DIFF(dv), 7348 DV_FUTURE_US(dv, cur_time))); 7349 } 7350 } 7351 } 7352 } 7353 } 7354 7355 RX_PRINT((" Queue Info\n")); 7356 7357 /* Display queue info */ 7358 for (i = 0; i <= RX_QUEUE_MAX(unit); i++) { 7359 #if 0 7360 /* { */ 7361 if (i < 16) { 7362 /* legacy support */ 7363 if (!(BCM_RCO_F_COS_ACCEPT(i) & BCM_RCO_F_COS_ACCEPT_MASK)) { 7364 /* Skip unused queues */ 7365 continue; 7366 } 7367 } 7368 /* } */ 7369 #endif 7370 queue = RX_QUEUE(unit, i); 7371 RX_PRINT((" Queue %d: PPS %d. CurPkts %d. TotPkts %d. " 7372 "Disc rate %d, qlen %d.\n", 7373 i, queue->pps, 7374 queue->count, 7375 queue->tot_pkts, 7376 queue->rate_disc, 7377 queue->qlen_disc)); 7378 LOG_VERBOSE(BSL_LS_BCM_RX, 7379 (BSL_META_U(unit, 7380 BSL_META_U(unit, " Tokens %d. Fill %u. Max %d. " 7381 "Brst %d. Head %p. Tail %p.\n")), 7382 queue->tokens, 7383 queue->last_fill, 7384 queue->max_len, 7385 queue->burst, 7386 (void *)queue->head, 7387 (void *)queue->tail)); 7388 } 7389 7390 return BCM_E_NONE; 7391 } 7392 7393 /* } */ 7394 #endif /* BROADCOM_DEBUG */ 7395 7396 /* } */ 7397 #endif /* (defined(BCM_ESW_SUPPORT) || defined (BCM_SAND_SUPPORT)) */ 7398 7399 /* 7400 * Function: 7401 * bcm_rx_cfg_t_init 7402 * Purpose: 7403 * Initialize the RX configuration structure. 7404 * Parameters: 7405 * rx_cfg - Pointer to RX configuration structure. 7406 * Returns: 7407 * NONE 7408 */ 7409 void 7410 bcm_rx_cfg_t_init(bcm_rx_cfg_t *rx_cfg) 7411 { 7412 if (rx_cfg != NULL) { 7413 sal_memset(rx_cfg, 0, sizeof (*rx_cfg)); 7414 } 7415 return; 7416 } 7417 7418 7419 /* 7420 * Function: 7421 * bcm_rx_trap_config_t_init 7422 * Purpose: 7423 * Initialize the bcm_rx_trap_config_t structure. 7424 * Parameters: 7425 * rx_trap - Pointer to bcm_rx_trap_config_t structure. 7426 * Returns: 7427 * NONE 7428 */ 7429 void 7430 bcm_rx_trap_config_t_init(bcm_rx_trap_config_t *rx_trap) 7431 { 7432 if (rx_trap != NULL) { 7433 sal_memset(rx_trap, 0, sizeof (*rx_trap)); 7434 BCM_GPORT_TRAP_SET(rx_trap->cpu_trap_gport,0,0,0); 7435 } 7436 return; 7437 } 7438 7439 7440 /* 7441 * Function: 7442 * bcm_rx_snoop_config_t_init 7443 * Purpose: 7444 * Initialize the bcm_rx_snoop_config_t structure. 7445 * Parameters: 7446 * rx_snoop - Pointer to bcm_rx_snoop_config_t structure. 7447 * Returns: 7448 * NONE 7449 */ 7450 void 7451 bcm_rx_snoop_config_t_init(bcm_rx_snoop_config_t *rx_snoop) 7452 { 7453 if (rx_snoop != NULL) { 7454 sal_memset(rx_snoop, 0, sizeof (*rx_snoop)); 7455 } 7456 return; 7457 } 7458 7459 /* 7460 * Function: 7461 * bcm_rx_CopyToCpu_config_t_init 7462 * Purpose: 7463 * Initialize a copy-to-cpu config entry 7464 * Parameters: 7465 * copyToCpu_config - (IN) Pointer to the copy-to-cpu config structure 7466 * Returns: 7467 * BCM_E_* 7468 */ 7469 7470 void 7471 bcm_rx_CopyToCpu_config_t_init(bcm_rx_CopyToCpu_config_t *copyToCpu_config) 7472 { 7473 /* Sanity check */ 7474 if(copyToCpu_config == NULL) { 7475 return; 7476 } 7477 7478 /* Memset the struct */ 7479 sal_memset(copyToCpu_config, 0, sizeof(bcm_rx_CopyToCpu_config_t)); 7480 7481 /* Setup defaults */ 7482 copyToCpu_config->buffer_priority = 7483 BCM_RX_COPYTOCPU_BUFFER_PRIORITY_LOW; 7484 copyToCpu_config->cpu_cosq = 0; 7485 7486 return; 7487 } 7488 7489 /* 7490 * Function: 7491 * bcm_rx_cosq_mapping_t_init 7492 * Purpose: 7493 * Initialize a rx cosq mapping entry 7494 * Parameters: 7495 * rx_cosq_mapping - (IN) Pointer to the rx cosq mapping structure 7496 */ 7497 7498 void 7499 bcm_rx_cosq_mapping_t_init(bcm_rx_cosq_mapping_t *rx_cosq_mapping) 7500 { 7501 /* Sanity check */ 7502 if(rx_cosq_mapping == NULL) { 7503 return; 7504 } 7505 7506 /* Memset the struct */ 7507 sal_memset(rx_cosq_mapping, 0, sizeof(bcm_rx_cosq_mapping_t)); 7508 rx_cosq_mapping->index = -1; 7509 return; 7510 } 7511 7512 /* 7513 * Function: 7514 * bcm_rx_mtu_profile_key_t_init 7515 * Purpose: 7516 * Initialize the bcm_rx_mtu_profile_key_t structure. 7517 * Parameters: 7518 * mtu_config - Pointer to bcm_rx_mtu_profile_key_t structure. 7519 * Returns: 7520 * NONE 7521 */ 7522 void 7523 bcm_rx_mtu_profile_key_t_init(bcm_rx_mtu_profile_key_t *mtu_key) 7524 { 7525 if (mtu_key != NULL) { 7526 sal_memset(mtu_key, 0, sizeof (*mtu_key)); 7527 } 7528 return; 7529 } 7530 7531 /* 7532 * Function: 7533 * bcm_rx_mtu_profile_value_t_init 7534 * Purpose: 7535 * Initialize the bcm_rx_mtu_profile_value_t structure. 7536 * Parameters: 7537 * mtu_config - Pointer to bcm_rx_mtu_profile_value_t structure. 7538 * Returns: 7539 * NONE 7540 */ 7541 void 7542 bcm_rx_mtu_profile_value_t_init(bcm_rx_mtu_profile_value_t *mtu_value) 7543 { 7544 if (mtu_value != NULL) { 7545 mtu_value->mtu_val = 0; 7546 mtu_value->trap_gport = BCM_GPORT_INVALID; 7547 } 7548 return; 7549 } 7550 7551 /* 7552 * Function: 7553 * bcm_rx_mtu_config_t_init 7554 * Purpose: 7555 * Initialize the bcm_rx_mtu_config_t structure. 7556 * Parameters: 7557 * mtu_config - Pointer to bcm_rx_mtu_config_t structure. 7558 * Returns: 7559 * NONE 7560 */ 7561 void 7562 bcm_rx_mtu_config_t_init(bcm_rx_mtu_config_t *mtu_config) 7563 { 7564 if (mtu_config != NULL) { 7565 sal_memset(mtu_config, 0, sizeof (*mtu_config)); 7566 7567 mtu_config->gport = BCM_GPORT_INVALID; 7568 mtu_config->intf = BCM_IF_INVALID; 7569 } 7570 return; 7571 } 7572 7573 /* 7574 * Function: 7575 * bcm_rx_trap_prog_config_t_init 7576 * Purpose: 7577 * Initialize the bcm_rx_trap_prog_config_t structure. 7578 * Parameters: 7579 * prog_config_p - Pointer to bcm_rx_trap_prog_config_t structure. 7580 * Returns: 7581 * NONE 7582 */ 7583 void 7584 bcm_rx_trap_prog_config_t_init(bcm_rx_trap_prog_config_t *prog_config_p) 7585 { 7586 if (prog_config_p != NULL) 7587 { 7588 sal_memset(prog_config_p, 0, sizeof (bcm_rx_trap_prog_config_t)); 7589 BCM_GPORT_TRAP_SET(prog_config_p->trap_gport, 0, 0, 0); 7590 } 7591 7592 return; 7593 } 7594 7595 /* 7596 * Function: 7597 * bcm_rx_trap_lif_config_t_init 7598 * Purpose: 7599 * Initialize the bcm_rx_trap_lif_config_t structure. 7600 * Parameters: 7601 * lif_config_p - Pointer to bcm_rx_trap_lif_config_t structure. 7602 * Returns: 7603 * NONE 7604 */ 7605 void 7606 bcm_rx_trap_lif_config_t_init(bcm_rx_trap_lif_config_t *lif_config_p) 7607 { 7608 if (lif_config_p != NULL) 7609 { 7610 lif_config_p->lif_type = bcmRxTrapLifTypeCount; 7611 lif_config_p->rif_intf = BCM_IF_INVALID; 7612 lif_config_p->lif_gport = BCM_GPORT_INVALID; 7613 lif_config_p->action_gport = BCM_GPORT_INVALID; 7614 } 7615 return; 7616 } 7617 7618 /* Adapter's version of the process_packet function */ 7619 void rx_adapter_process_packet(int unit, bcm_pkt_t *pkt) 7620 { 7621 volatile rx_callout_t *rco; 7622 bcm_rx_t handler_rc; 7623 int handled = FALSE; 7624 7625 assert(pkt); 7626 7627 #ifndef BCM_ARAD_PARSE_PACKET_IN_INTERRUPT_CONTEXT 7628 /* { */ 7629 #ifdef BCM_PETRA_SUPPORT 7630 /* { */ 7631 if (SOC_UNIT_VALID(unit) && SOC_IS_ARAD(unit)) { 7632 _bcm_dpp_rx_packet_parse(unit, pkt, 1); 7633 } 7634 /* } */ 7635 #endif 7636 #ifdef BCM_DNX_SUPPORT 7637 /* Print the content of the package in debug mode */ 7638 if (SOC_IS_DNX(unit) && SOC_UNIT_VALID(unit)) { 7639 dnx_rx_packet_parse(unit, pkt, TRUE); 7640 } 7641 #endif 7642 /* } */ 7643 #endif /*BCM_ARAD_PARSE_PACKET_IN_INTERRUPT_CONTEXT*/ 7644 7645 #if defined(INCLUDE_L3) && defined(BCM_TRX_SUPPORT) 7646 /* { */ 7647 if (SOC_UNIT_VALID(unit) && SOC_IS_TR_VL(unit)) { 7648 fill_in_pkt_vpn_id(unit, pkt); 7649 } 7650 /* Not really needed. Just to avoid coverity defect */ 7651 if(!BCM_CONTROL_UNIT_LEGAL(unit)) { 7652 LOG_WARN(BSL_LS_BCM_RX, 7653 (BSL_META_U(unit, 7654 BSL_META_U 7655 (unit, 7656 "rx_process_packet: unit=%d: " 7657 "Invalid unit\n")), 7658 unit)); 7659 return; 7660 } 7661 /* } */ 7662 #endif /* INCLUDE_L3 && BCM_TRX_SUPPORT */ 7663 7664 RX_LOCK(unit); /* Can't modify handler list while doing callbacks */ 7665 7666 /* Loop through registered drivers until packet consumed */ 7667 for (rco = rx_ctl[unit]->rc_callout; rco; rco = rco->rco_next) { 7668 BCM_API_XLATE_PORT_DECL(rx_port); 7669 BCM_API_XLATE_PORT_DECL(rx_port_orig); 7670 7671 if (rco->rco_flags & BCM_RCO_F_INTR) { /* Non interrupt context */ 7672 continue; 7673 } 7674 /* Callback is not interested in this COS 7675 Not implemented in adapter 7676 if (!(SHR_BITGET(rco->rco_cos, pkt->cos))) { 7677 continue; 7678 } 7679 */ 7680 7681 /* Since pkt->rx_port is an int8, it cannot be passed directly */ 7682 BCM_API_XLATE_PORT_SAVE(rx_port_orig, pkt->rx_port); 7683 BCM_API_XLATE_PORT_SAVE(rx_port, rx_port_orig); 7684 BCM_API_XLATE_PORT_P2A(unit, &rx_port); 7685 BCM_API_XLATE_PORT_SAVE(pkt->rx_port, rx_port); 7686 7687 handler_rc = rco->rco_function(unit, pkt, rco->rco_cookie); 7688 7689 BCM_API_XLATE_PORT_RESTORE(pkt->rx_port, rx_port_orig); 7690 7691 switch (handler_rc) { 7692 case BCM_RX_NOT_HANDLED: 7693 break; /* Next callout */ 7694 case BCM_RX_HANDLED: 7695 handled = TRUE; 7696 LOG_DEBUG(BSL_LS_BCM_RX, 7697 (BSL_META_U(unit, 7698 BSL_META_U(unit, "rx: pkt handled by %s\n")), 7699 rco->rco_name)); 7700 rco->rco_pkts_handled++; 7701 break; 7702 case BCM_RX_HANDLED_OWNED: 7703 handled = TRUE; 7704 LOG_DEBUG(BSL_LS_BCM_RX, 7705 (BSL_META_U(unit, 7706 BSL_META_U(unit, "rx: pkt owned by %s\n")), 7707 rco->rco_name)); 7708 rx_ctl[unit]->pkts_owned++; 7709 rco->rco_pkts_owned++; 7710 break; 7711 default: 7712 LOG_WARN(BSL_LS_BCM_RX, 7713 (BSL_META_U(unit, 7714 BSL_META_U 7715 (unit, 7716 "rx_process_packet: unit=%d: " 7717 "Invalid callback return value=%d\n")), 7718 unit, handler_rc)); 7719 break; 7720 } 7721 7722 if (handled) { 7723 break; 7724 } 7725 } 7726 /* 7727 * Preserving these flags that were conditionally set 7728 * in function bcm_pkt_flags_init(int unit, bcm_pkt_t *pkt, uint32 flags) 7729 */ 7730 pkt->flags &= (BCM_PKT_F_HGHDR | BCM_PKT_F_SLTAG); 7731 RX_UNLOCK(unit); 7732 7733 if (!handled) { 7734 /* Internal error as discard should have handled packet */ 7735 if (SOC_UNIT_VALID(unit)) { 7736 RX_ERROR((BSL_META_U(unit, 7737 "bcm_rx_process_packet: No handler processed packet: " 7738 "Port %s\n"), 7739 SOC_PORT_NAME(unit, pkt->rx_port))); 7740 } else { 7741 RX_ERROR((BSL_META_U(unit, 7742 "bcm_rx_process_packet: No handler processed packet: " 7743 "Port %d\n"), 7744 pkt->rx_port)); 7745 } 7746 } 7747 } 7748 7749 /* 7750 * Function: 7751 * bcm_rx_trap_protocol_key_t_init 7752 * Purpose: 7753 * Initialize the bcm_rx_trap_protocol_key_t structure. 7754 * Parameters: 7755 * key_p - Pointer to bcm_rx_trap_protocol_key_t structure. 7756 * Returns: 7757 * NONE 7758 */ 7759 void 7760 bcm_rx_trap_protocol_key_t_init(bcm_rx_trap_protocol_key_t *key_p) 7761 { 7762 if (key_p != NULL) 7763 { 7764 sal_memset(key_p, 0, sizeof (bcm_rx_trap_protocol_key_t)); 7765 } 7766 return; 7767 } 7768 7769 /* 7770 * Function: 7771 * bcm_rx_trap_protocol_profiles_t_init 7772 * Purpose: 7773 * Initialize the bcm_rx_trap_protocol_profiles_t structure. 7774 * Parameters: 7775 * protocol_profiles_p - Pointer to bcm_rx_trap_protocol_profiles_t structure. 7776 * Returns: 7777 * NONE 7778 */ 7779 void 7780 bcm_rx_trap_protocol_profiles_t_init(bcm_rx_trap_protocol_profiles_t *protocol_profiles_p) 7781 { 7782 if (protocol_profiles_p != NULL) 7783 { 7784 sal_memset(protocol_profiles_p, 0, sizeof (bcm_rx_trap_protocol_profiles_t)); 7785 } 7786 return; 7787 }