tx.c (224660B)
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 8 #ifdef BCM_HIDE_DISPATCHABLE 9 #undef BCM_HIDE_DISPATCHABLE 10 #endif 11 12 #include <shared/bsl.h> 13 14 #include <assert.h> 15 16 #include <sal/types.h> 17 #include <sal/core/time.h> 18 #include <sal/core/boot.h> 19 #include <shared/bsl.h> 20 #include <soc/dma.h> 21 #include <soc/cm.h> 22 #include <soc/dcbformats.h> 23 #include <soc/debug.h> 24 #include <soc/drv.h> 25 #include <soc/util.h> 26 #include <soc/error.h> 27 #include <soc/higig.h> 28 #include <soc/pbsmh.h> 29 #include <soc/enet.h> 30 #include <soc/loopback.h> 31 #if defined(BCM_CPU_TX_PROC_SUPPORT) 32 #include <soc/proc_hdr.h> 33 #endif /* BCM_CPU_TX_PROC_SUPPORT */ 34 35 #if defined(BCM_BRADLEY_SUPPORT) 36 #include <soc/bradley.h> 37 #endif 38 #if defined(BCM_TRIUMPH_SUPPORT) 39 #include <bcm_int/esw/triumph.h> 40 #endif 41 #if defined(BCM_TRIDENT2_SUPPORT) 42 #include <soc/trident2.h> 43 #endif 44 #if defined(BCM_APACHE_SUPPORT) 45 #include <soc/apache.h> 46 #endif 47 #if defined(BCM_MONTEREY_SUPPORT) 48 #include <soc/monterey.h> 49 #endif 50 #if defined(BCM_TOMAHAWK3_SUPPORT) 51 #include <soc/tomahawk3.h> 52 #endif 53 54 #include <soc/dnxc/multithread_analyzer.h> 55 56 #ifdef BCM_DNX_SUPPORT 57 #include <soc/dnx/dnx_err_recovery_manager_utils.h> 58 #endif 59 60 #if defined(BCM_ESW_SUPPORT) 61 #include <bcm_int/esw/tx.h> 62 #if defined(BCM_INSTRUMENTATION_SUPPORT) 63 #include <bcm_int/esw/instrumentation.h> 64 #endif /* BCM_INSTRUMENTATION_SUPPORT */ 65 #endif 66 #include <bcm_int/control.h> 67 68 #include <bcm/pkt.h> 69 #include <bcm/tx.h> 70 #include <bcm/stack.h> 71 #include <bcm/error.h> 72 73 #if defined(BCM_ESW_SUPPORT) 74 #include <bcm_int/common/multicast.h> 75 #include <bcm_int/esw/rcpu.h> 76 #include <bcm_int/esw/stack.h> 77 #endif 78 #include <bcm_int/api_xlate_port.h> 79 #include <bcm_int/common/tx.h> 80 #if defined(BCM_ESW_SUPPORT) 81 #include <bcm_int/esw/tx.h> 82 #endif 83 #if defined(INCLUDE_L3) && defined(BCM_XGS_SWITCH_SUPPORT) 84 #include <bcm_int/esw/firebolt.h> 85 #endif /* INCLUDE_L3 && BCM_XGS_SWITCH_SUPPORT */ 86 #if defined(INCLUDE_L3) && defined(BCM_TRX_SUPPORT) 87 #include <bcm_int/esw/vpn.h> 88 #endif /* INCLUDE_L3 && BCM_TRX_SUPPORT */ 89 90 #if defined (BCM_ARAD_SUPPORT) 91 #include <soc/dpp/ARAD/arad_action_cmd.h> 92 #endif 93 94 #if defined(BCM_ESW_SUPPORT) || defined (BCM_ARAD_SUPPORT) || defined (BCM_DNX_SUPPORT) 95 #if defined (BCM_OLP_SUPPORT) 96 #include <soc/shared/olp_pkt.h> 97 #include <soc/shared/olp_pack.h> 98 #endif 99 #if defined(BCM_TRIDENT2PLUS_SUPPORT) || defined (BCM_SABER2_SUPPORT) 100 #include <bcm_int/esw/flex_ctr.h> 101 #include <bcm_int/esw/switch.h> 102 #endif 103 104 #if defined(BCM_TRIDENT3_SUPPORT) 105 #include <bcm_int/esw/trident3.h> 106 #endif 107 108 109 #if defined(BCM_HGPROXY_COE_SUPPORT) 110 #include <bcm_int/esw/subport.h> 111 #include <bcm_int/esw/xgs5.h> 112 #endif 113 114 #if defined(BROADCOM_DEBUG) 115 int bcm_tx_pkt_count[BCM_COS_COUNT]; 116 int bcm_tx_pkt_count_bad_cos; 117 #endif /* BROADCOM_DEBUG */ 118 119 #if defined(BCM_TRIDENT2PLUS_SUPPORT) && defined(BCM_TX_HGOE_LIMITED_SOLUTION) 120 #if defined (BROADCOM_DEBUG) && defined(BCM_TX_HGOE_DBG) 121 typedef struct _bcm_tx_hgoe_dbg_ctr_s { 122 sal_sem_t tx_hgoe_ctr_sem; 123 uint32 both_cb_cnt; 124 uint32 internal_fail_cnt; 125 uint32 dma_alloc_cnt; 126 uint32 dma_free_cnt; 127 uint32 blk_alloc_cnt; 128 uint32 blk_free_cnt; 129 uint32 ck_alloc_cnt; 130 uint32 ck_free_cnt; 131 uint32 pkt_blk_chg_cnt; 132 uint32 pkt_blk_rvt_cnt; 133 uint32 tx_list_master_ck_cnt; 134 uint32 tx_list_pkt_ck_arr_cnt; 135 uint32 tx_list_port_info_cnt; 136 } bcm_tx_hgoe_dbg_ctr_t; 137 volatile bcm_tx_hgoe_dbg_ctr_t g_hgoe_dbg_ctrs = {0}; 138 139 #define BCM_TX_HGOE_DBG_CTR_SEM_ACQ \ 140 sal_sem_take(g_hgoe_dbg_ctrs.tx_hgoe_ctr_sem, sal_sem_FOREVER); 141 142 #define BCM_TX_HGOE_DBG_CTR_SEM_REL \ 143 sal_sem_give(g_hgoe_dbg_ctrs.tx_hgoe_ctr_sem); 144 145 #define BCM_TX_HGOE_DBG_CTR_SEM_INCR(_ctr_) \ 146 {\ 147 BCM_TX_HGOE_DBG_CTR_SEM_ACQ; \ 148 (g_hgoe_dbg_ctrs._ctr_)++; \ 149 BCM_TX_HGOE_DBG_CTR_SEM_REL; \ 150 } 151 152 #define BCM_TX_HGOE_DBG_CTR_SEM_DECR(_ctr_) \ 153 {\ 154 BCM_TX_HGOE_DBG_CTR_SEM_ACQ; \ 155 (g_hgoe_dbg_ctrs._ctr_)--;\ 156 BCM_TX_HGOE_DBG_CTR_SEM_REL; \ 157 } 158 #define BCM_TX_HGOE_DBG_CTR_INCR(_ctr_) { (g_hgoe_dbg_ctrs._ctr_)++; } 159 160 #define BCM_TX_HGOE_DBG_CTR_DECR(_ctr_) { (g_hgoe_dbg_ctrs._ctr_)--; } 161 162 #else 163 164 #define BCM_TX_HGOE_DBG_CTR_SEM_ACQ 165 #define BCM_TX_HGOE_DBG_CTR_SEM_REL 166 #define BCM_TX_HGOE_DBG_CTR_SEM_INCR(_ctr_) 167 #define BCM_TX_HGOE_DBG_CTR_SEM_DECR(_ctr_) 168 #define BCM_TX_HGOE_DBG_CTR_INCR(_ctr_) 169 #define BCM_TX_HGOE_DBG_CTR_DECR(_ctr_) 170 171 #endif 172 #endif /* BCM_TRIDENT2PLUS_SUPPORT && BCM_TX_HGOE_LIMITED_SOLUTION */ 173 174 /* Forward declarations of static functions */ 175 STATIC dv_t *_tx_dv_alloc(int unit, int pkt_count, int dcb_count, 176 bcm_pkt_cb_f call_back, void *cookie, int pkt_cb); 177 STATIC void _tx_dv_free(int unit, dv_t *dv); 178 179 STATIC int _tx_pkt_desc_add(int unit, bcm_pkt_t *pkt, dv_t *dv, int pkt_idx); 180 181 #if defined(BCM_PETRA_SUPPORT) || defined(BCM_DNX_SUPPORT) 182 STATIC int _sand_tx_pkt_desc_add(int unit, bcm_pkt_t *pkt, dv_t *dv, int pkt_idx); 183 #endif 184 STATIC int _bcm_tx_chain_send(int unit, dv_t *dv, int async); 185 186 STATIC void _bcm_tx_chain_done_cb(int unit, dv_t *dv); 187 STATIC void _bcm_tx_desc_done_cb(int unit, dv_t *dv, dcb_t *dcb); 188 STATIC void _bcm_tx_reload_done_cb(int unit, dv_t *dv); 189 STATIC void _bcm_tx_chain_done(int unit, dv_t *dv); 190 STATIC void _bcm_tx_desc_done(int unit, dv_t *dv, dcb_t *dcb); 191 STATIC void _bcm_tx_reload_done(int unit, dv_t *dv); 192 STATIC void _bcm_tx_packet_done_cb(int unit, dv_t *dv, dcb_t *dcb); 193 STATIC void _bcm_tx_packet_done(bcm_pkt_t *pkt); 194 195 STATIC void _bcm_tx_callback_thread(void *param); 196 197 #if defined (BCM_ARAD_SUPPORT) || defined (BCM_DNX_SUPPORT) 198 STATIC INLINE int _bcm_tx_pkt_tag_setup(int unit, bcm_pkt_t *pkt); 199 200 201 #if (defined (BCM_ARAD_SUPPORT) || defined (BCM_DNX_SUPPORT)) && !defined (BCM_ESW_SUPPORT) 202 typedef struct stk_tag_s { 203 #if defined(LE_HOST) 204 uint32 rsvp:2; 205 uint32 stk_modid:5; 206 uint32 ed:1; 207 uint32 em:1; 208 uint32 md:1; 209 uint32 mirr:1; 210 uint32 pfm:2; 211 uint32 dst_rtag:3; 212 uint32 dst_tgid:3; 213 uint32 dst_t:1; 214 uint32 src_rtag:3; 215 uint32 src_tgid:3; 216 uint32 src_t:1; 217 uint32 stk_cnt:5; 218 #else 219 uint32 stk_cnt:5; 220 uint32 src_t:1; 221 uint32 src_tgid:3; 222 uint32 src_rtag:3; 223 uint32 dst_t:1; 224 uint32 dst_tgid:3; 225 uint32 dst_rtag:3; 226 uint32 pfm:2; 227 uint32 mirr:1; 228 uint32 md:1; 229 uint32 em:1; 230 uint32 ed:1; 231 uint32 stk_modid:5; 232 uint32 rsvp:2; 233 #endif 234 } stk_tag_t; 235 236 typedef struct tx_dv_info_s { 237 volatile bcm_pkt_t **pkt; 238 int pkt_count; 239 volatile uint8 pkt_done_cnt; 240 bcm_pkt_cb_f chain_done_cb; 241 void *cookie; 242 } tx_dv_info_t; 243 244 #define TX_INFO_SET(dv, val) ((dv)->dv_public1.ptr = val) 245 #define TX_INFO(dv) ((tx_dv_info_t *)((dv)->dv_public1.ptr)) 246 #define TX_INFO_PKT_ADD(dv, pkt) \ 247 TX_INFO(dv)->pkt[TX_INFO(dv)->pkt_count++] = (pkt) 248 #define TX_INFO_CUR_PKT(dv) (TX_INFO(dv)->pkt[TX_INFO(dv)->pkt_done_cnt]) 249 #define TX_INFO_PKT_MARK_DONE(dv) ((TX_INFO(dv)->pkt_done_cnt)++) 250 251 #define TX_DV_NEXT(dv) ((dv_t *)((dv)->dv_public2.ptr)) 252 #define TX_DV_NEXT_SET(dv, dv_next) \ 253 ((dv)->dv_public2.ptr = (void *)(dv_next)) 254 255 #define TX_EXTRA_DCB_COUNT 4 256 #endif 257 258 #endif 259 260 #ifdef BCM_XGS3_SWITCH_SUPPORT 261 262 typedef struct _xgs3_async_queue_s { 263 struct _xgs3_async_queue_s * next; 264 int unit; 265 bcm_pkt_t * pkt; 266 void * cookie; 267 } _xgs3_async_queue_t; 268 269 static _xgs3_async_queue_t * _xgs3_async_head; 270 static _xgs3_async_queue_t * _xgs3_async_tail; 271 272 static sal_sem_t _xgs3_async_tx_sem; 273 static sal_spinlock_t _xgs3_async_queue_lock; 274 275 STATIC void _xgs3_async_thread(void * param); 276 #endif 277 278 /* Some macros: 279 * 280 * _ON_ERROR_GOTO: Check the return code of an action; 281 * if error, goto the label provided. 282 * _PROCESS_ERROR: If rv indicates an error, free the DV (if non-NULL) 283 * and display the "err_msg" if provided. 284 */ 285 286 #define _ON_ERROR_GOTO(act, rv, label) if (((rv) = (act)) < 0) goto label 287 288 #define _PROCESS_ERROR(unit, rv, dv, err_msg) \ 289 do { \ 290 if ((rv) < 0) { /* Error detected */ \ 291 if (dv != NULL) { \ 292 _tx_dv_free(unit, dv); \ 293 } \ 294 if (err_msg) { \ 295 LOG_ERROR(BSL_LS_BCM_TX, \ 296 (BSL_META_U(unit, \ 297 "bcm_tx: %s\n"), err_msg)); \ 298 } \ 299 } \ 300 } while (0) 301 302 /* Call back synchronization and lists */ 303 static sal_sem_t tx_cb_sem = NULL; 304 /* Used to notify tx DV available */ 305 static sal_sem_t tx_dv_done = NULL; 306 /* used to notify tx thread had exit */ 307 static sal_sem_t tx_exit_notify = NULL; 308 309 volatile static dv_t *dv_pend_first; 310 volatile static dv_t *dv_pend_last; 311 volatile static dv_t *dvdesc_pend_first; 312 volatile static dv_t *dvdesc_pend_last; 313 volatile static dv_t *dvrld_pend_first; 314 volatile static dv_t *dvrld_pend_last; 315 volatile static bcm_pkt_t *pkt_pend_first; 316 volatile static bcm_pkt_t *pkt_pend_last; 317 318 static sal_spinlock_t sal_tx_spinlock = NULL; 319 320 #define TX_SPIN_LOCK() sal_spinlock_lock(sal_tx_spinlock) 321 #define TX_SPIN_UNLOCK() sal_spinlock_unlock(sal_tx_spinlock) 322 323 #define DEFAULT_TX_PRI 50 /* Default Thread Priority */ 324 325 static uint8* _null_crc_ptr = NULL; 326 static uint8* _pkt_pad_ptr = NULL; 327 static int _tx_init = FALSE; 328 static sal_thread_t _tx_tid = SAL_THREAD_ERROR; 329 volatile static int _tx_chain_send; 330 volatile static int _tx_chain_done; 331 volatile static int _tx_desc_done; 332 volatile static int _tx_rld_done; 333 volatile static int _tx_chain_done_intr; 334 volatile static int _tx_desc_done_intr; 335 volatile static int _tx_rld_done_intr; 336 337 #ifdef BCM_XGS3_SWITCH_SUPPORT 338 /* Lookup table: Return the first bit set. -1 if no bit set. */ 339 static int8 bpos[256] = { 340 /* 0x00 */ -1, /* 0x01 */ 0, /* 0x02 */ 1, /* 0x03 */ 0, 341 /* 0x04 */ 2, /* 0x05 */ 0, /* 0x06 */ 1, /* 0x07 */ 0, 342 /* 0x08 */ 3, /* 0x09 */ 0, /* 0x0a */ 1, /* 0x0b */ 0, 343 /* 0x0c */ 2, /* 0x0d */ 0, /* 0x0e */ 1, /* 0x0f */ 0, 344 /* 0x10 */ 4, /* 0x11 */ 0, /* 0x12 */ 1, /* 0x13 */ 0, 345 /* 0x14 */ 2, /* 0x15 */ 0, /* 0x16 */ 1, /* 0x17 */ 0, 346 /* 0x18 */ 3, /* 0x19 */ 0, /* 0x1a */ 1, /* 0x1b */ 0, 347 /* 0x1c */ 2, /* 0x1d */ 0, /* 0x1e */ 1, /* 0x1f */ 0, 348 /* 0x20 */ 5, /* 0x21 */ 0, /* 0x22 */ 1, /* 0x23 */ 0, 349 /* 0x24 */ 2, /* 0x25 */ 0, /* 0x26 */ 1, /* 0x27 */ 0, 350 /* 0x28 */ 3, /* 0x29 */ 0, /* 0x2a */ 1, /* 0x2b */ 0, 351 /* 0x2c */ 2, /* 0x2d */ 0, /* 0x2e */ 1, /* 0x2f */ 0, 352 /* 0x30 */ 4, /* 0x31 */ 0, /* 0x32 */ 1, /* 0x33 */ 0, 353 /* 0x34 */ 2, /* 0x35 */ 0, /* 0x36 */ 1, /* 0x37 */ 0, 354 /* 0x38 */ 3, /* 0x39 */ 0, /* 0x3a */ 1, /* 0x3b */ 0, 355 /* 0x3c */ 2, /* 0x3d */ 0, /* 0x3e */ 1, /* 0x3f */ 0, 356 /* 0x40 */ 6, /* 0x41 */ 0, /* 0x42 */ 1, /* 0x43 */ 0, 357 /* 0x44 */ 2, /* 0x45 */ 0, /* 0x46 */ 1, /* 0x47 */ 0, 358 /* 0x48 */ 3, /* 0x49 */ 0, /* 0x4a */ 1, /* 0x4b */ 0, 359 /* 0x4c */ 2, /* 0x4d */ 0, /* 0x4e */ 1, /* 0x4f */ 0, 360 /* 0x50 */ 4, /* 0x51 */ 0, /* 0x52 */ 1, /* 0x53 */ 0, 361 /* 0x54 */ 2, /* 0x55 */ 0, /* 0x56 */ 1, /* 0x57 */ 0, 362 /* 0x58 */ 3, /* 0x59 */ 0, /* 0x5a */ 1, /* 0x5b */ 0, 363 /* 0x5c */ 2, /* 0x5d */ 0, /* 0x5e */ 1, /* 0x5f */ 0, 364 /* 0x60 */ 5, /* 0x61 */ 0, /* 0x62 */ 1, /* 0x63 */ 0, 365 /* 0x64 */ 2, /* 0x65 */ 0, /* 0x66 */ 1, /* 0x67 */ 0, 366 /* 0x68 */ 3, /* 0x69 */ 0, /* 0x6a */ 1, /* 0x6b */ 0, 367 /* 0x6c */ 2, /* 0x6d */ 0, /* 0x6e */ 1, /* 0x6f */ 0, 368 /* 0x70 */ 4, /* 0x71 */ 0, /* 0x72 */ 1, /* 0x73 */ 0, 369 /* 0x74 */ 2, /* 0x75 */ 0, /* 0x76 */ 1, /* 0x77 */ 0, 370 /* 0x78 */ 3, /* 0x79 */ 0, /* 0x7a */ 1, /* 0x7b */ 0, 371 /* 0x7c */ 2, /* 0x7d */ 0, /* 0x7e */ 1, /* 0x7f */ 0, 372 /* 0x80 */ 7, /* 0x81 */ 0, /* 0x82 */ 1, /* 0x83 */ 0, 373 /* 0x84 */ 2, /* 0x85 */ 0, /* 0x86 */ 1, /* 0x87 */ 0, 374 /* 0x88 */ 3, /* 0x89 */ 0, /* 0x8a */ 1, /* 0x8b */ 0, 375 /* 0x8c */ 2, /* 0x8d */ 0, /* 0x8e */ 1, /* 0x8f */ 0, 376 /* 0x90 */ 4, /* 0x91 */ 0, /* 0x92 */ 1, /* 0x93 */ 0, 377 /* 0x94 */ 2, /* 0x95 */ 0, /* 0x96 */ 1, /* 0x97 */ 0, 378 /* 0x98 */ 3, /* 0x99 */ 0, /* 0x9a */ 1, /* 0x9b */ 0, 379 /* 0x9c */ 2, /* 0x9d */ 0, /* 0x9e */ 1, /* 0x9f */ 0, 380 /* 0xa0 */ 5, /* 0xa1 */ 0, /* 0xa2 */ 1, /* 0xa3 */ 0, 381 /* 0xa4 */ 2, /* 0xa5 */ 0, /* 0xa6 */ 1, /* 0xa7 */ 0, 382 /* 0xa8 */ 3, /* 0xa9 */ 0, /* 0xaa */ 1, /* 0xab */ 0, 383 /* 0xac */ 2, /* 0xad */ 0, /* 0xae */ 1, /* 0xaf */ 0, 384 /* 0xb0 */ 4, /* 0xb1 */ 0, /* 0xb2 */ 1, /* 0xb3 */ 0, 385 /* 0xb4 */ 2, /* 0xb5 */ 0, /* 0xb6 */ 1, /* 0xb7 */ 0, 386 /* 0xb8 */ 3, /* 0xb9 */ 0, /* 0xba */ 1, /* 0xbb */ 0, 387 /* 0xbc */ 2, /* 0xbd */ 0, /* 0xbe */ 1, /* 0xbf */ 0, 388 /* 0xc0 */ 6, /* 0xc1 */ 0, /* 0xc2 */ 1, /* 0xc3 */ 0, 389 /* 0xc4 */ 2, /* 0xc5 */ 0, /* 0xc6 */ 1, /* 0xc7 */ 0, 390 /* 0xc8 */ 3, /* 0xc9 */ 0, /* 0xca */ 1, /* 0xcb */ 0, 391 /* 0xcc */ 2, /* 0xcd */ 0, /* 0xce */ 1, /* 0xcf */ 0, 392 /* 0xd0 */ 4, /* 0xd1 */ 0, /* 0xd2 */ 1, /* 0xd3 */ 0, 393 /* 0xd4 */ 2, /* 0xd5 */ 0, /* 0xd6 */ 1, /* 0xd7 */ 0, 394 /* 0xd8 */ 3, /* 0xd9 */ 0, /* 0xda */ 1, /* 0xdb */ 0, 395 /* 0xdc */ 2, /* 0xdd */ 0, /* 0xde */ 1, /* 0xdf */ 0, 396 /* 0xe0 */ 5, /* 0xe1 */ 0, /* 0xe2 */ 1, /* 0xe3 */ 0, 397 /* 0xe4 */ 2, /* 0xe5 */ 0, /* 0xe6 */ 1, /* 0xe7 */ 0, 398 /* 0xe8 */ 3, /* 0xe9 */ 0, /* 0xea */ 1, /* 0xeb */ 0, 399 /* 0xec */ 2, /* 0xed */ 0, /* 0xee */ 1, /* 0xef */ 0, 400 /* 0xf0 */ 4, /* 0xf1 */ 0, /* 0xf2 */ 1, /* 0xf3 */ 0, 401 /* 0xf4 */ 2, /* 0xf5 */ 0, /* 0xf6 */ 1, /* 0xf7 */ 0, 402 /* 0xf8 */ 3, /* 0xf9 */ 0, /* 0xfa */ 1, /* 0xfb */ 0, 403 /* 0xfc */ 2, /* 0xfd */ 0, /* 0xfe */ 1, /* 0xff */ 0, 404 }; 405 406 /* 407 * Extract port from PBM 408 */ 409 #define _pbm2port(bmp) \ 410 ((bpos[(bmp >> 0) & 0xFF] != -1) ? (0 + bpos[(bmp >> 0) & 0xFF]) : \ 411 (bpos[(bmp >> 8) & 0xFF] != -1) ? (8 + bpos[(bmp >> 8) & 0xFF]) : \ 412 (bpos[(bmp >> 16) & 0xFF] != -1) ? (16 + bpos[(bmp >> 16) & 0xFF]) : \ 413 (bpos[(bmp >> 24) & 0xFF] != -1) ? (24 + bpos[(bmp >> 24) & 0xFF]) : \ 414 (-1) \ 415 ) 416 417 STATIC INLINE void 418 _bcm_xgs3_tx_pipe_handle_timestamp_flags(int unit, bcm_pkt_t *pkt) 419 { 420 soc_pbsmh_hdr_t *pbh = (soc_pbsmh_hdr_t *)pkt->_pb_hdr; 421 if (pkt->flags & BCM_PKT_F_TIMESYNC) { 422 /* TD2+ timestamp fields set */ 423 if (SOC_DCB_TYPE(unit) == 33) { 424 if (pkt->timestamp_flags & BCM_TX_TIMESYNC_ONE_STEP) { 425 /* one step timestamp */ 426 soc_pbsmh_field_set(unit, pbh, PBSMH_osts, 1 ); 427 } else { 428 /* Two-step time stamping */ 429 soc_pbsmh_field_set(unit, pbh, PBSMH_tx_ts, 1 ); 430 } 431 if ( pkt->timestamp_flags & BCM_TX_TIMESYNC_INGRESS_SIGN) { 432 soc_pbsmh_field_set(unit, pbh, PBSMH_its_sign, 1 ); 433 } 434 if ( pkt->timestamp_flags & BCM_TX_TIMESYNC_HDR_START_OFFSET) { 435 soc_pbsmh_field_set(unit, pbh, PBSMH_hdr_offset, 436 pkt->timestamp_offset); 437 } 438 if ( pkt->timestamp_flags & BCM_TX_TIMESYNC_REGEN_UDP_CHKSUM) { 439 soc_pbsmh_field_set(unit, pbh, PBSMH_regen_udp_checksum, 1 ); 440 } 441 } /* if (SOC_DCB_TYPE(unit) == 33) */ 442 } /* if (pkt->flags & BCM_PKT_F_TIMESYNC) */ 443 } 444 445 /* 446 * Function: 447 * _bcm_xgs3_tx_pipe_bypass_header_setup 448 * Purpose: 449 * Setup up header required to steer raw packet data stream 450 * out of a port. 451 * Parameters: 452 * unit - transmission unit 453 * pkt - To be updated 454 * Returns: 455 * BCM_E_XXX 456 * Notes: 457 * The TX port is extracted from tx_pbmp. If port is a member 458 * of tx_upbmp then the VLAN TAG is removed. 459 */ 460 static INLINE int 461 _bcm_xgs3_tx_pipe_bypass_header_setup(int unit, bcm_pkt_t *pkt) 462 { 463 soc_pbsmh_hdr_t *pbh = (soc_pbsmh_hdr_t *)pkt->_pb_hdr; 464 uint32 bmap = SOC_PBMP_WORD_GET(pkt->tx_pbmp, 0); 465 int port = _pbm2port(bmap); 466 int port_adj = 0; 467 uint32 prio_val; 468 uint32 src_mod; 469 int qnum; 470 int max_num_port = 0; 471 int unicast = 1; 472 473 if (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS) { 474 max_num_port = SOC_MAX_NUM_PP_PORTS; 475 } else { 476 max_num_port = SOC_INFO(unit).port_addr_max > SOC_INFO(unit).port_num ? 477 SOC_INFO(unit).port_addr_max:SOC_INFO(unit).port_num; 478 } 479 480 /* If this is a TD2P CoE port, get the physical-port from the 481 subport-gport passed in */ 482 #if defined BCM_HGPROXY_COE_SUPPORT 483 if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) && 484 _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, pkt->dst_gport)) { 485 BCM_IF_ERROR_RETURN( 486 _bcmi_coe_subport_physical_port_get(unit, pkt->dst_gport, &port)); 487 /* Update the bmap with the physical port retrieved */ 488 BCM_PBMP_PORT_ADD(pkt->tx_pbmp, port); 489 bmap = SOC_PBMP_WORD_GET(pkt->tx_pbmp, 0); 490 } 491 #endif 492 493 src_mod = (pkt->flags & BCM_TX_SRC_MOD) ? 494 pkt->src_mod : SOC_DEFAULT_DMA_SRCMOD_GET(unit); 495 prio_val = (pkt->flags & BCM_TX_PRIO_INT) ? pkt->prio_int : pkt->cos; 496 #ifdef BCM_INSTRUMENTATION_SUPPORT 497 if (soc_feature(unit, soc_feature_visibility)) { 498 if ((port == -1) && (pkt->flags2 & BCM_PKT_F2_RX_PORT)) { 499 /* Set the masquerad source port */ 500 port = pkt->rx_port; 501 _bcm_esw_pkt_trace_src_port_set(unit, port); 502 } else if (pkt->flags2 & BCM_PKT_F2_RX_PORT) { 503 if (pkt->rx_port != 0) { 504 port = pkt->rx_port; 505 } 506 _bcm_esw_pkt_trace_src_port_set(unit, port); 507 } 508 } 509 #endif /* BCM_INSTRUMENTATION_SUPPORT */ 510 #ifdef BCM_CPU_TX_PROC_SUPPORT 511 if (soc_feature(unit, soc_feature_cpu_tx_proc)) { 512 if ((port == -1) && (pkt->flags2 & BCM_PKT_F2_CPU_TX_PROC)) { 513 port = pkt->rx_port; 514 } else if (pkt->flags2 & BCM_PKT_F2_CPU_TX_PROC) { 515 if (pkt->rx_port != 0) { 516 port = pkt->rx_port; 517 } 518 } 519 } 520 #endif /* BCM_CPU_TX_PROC_SUPPORT */ 521 #ifdef BCM_KATANA2_SUPPORT 522 if (SOC_IS_KATANA2(unit)) { 523 if (BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(pkt->dst_gport)) { 524 port = BCM_GPORT_UCAST_SUBSCRIBER_QUEUE_GROUP_SYSPORTID_GET( 525 pkt->dst_gport); 526 BCM_PBMP_PORT_ADD(pkt->tx_pbmp, port); 527 bmap = SOC_PBMP_WORD_GET(pkt->tx_pbmp, 0); 528 } 529 } 530 #endif 531 if (port == -1) { 532 if (soc_feature(unit, soc_feature_register_hi) || SOC_IS_TR_VL(unit)) { 533 bmap = SOC_PBMP_WORD_GET(pkt->tx_pbmp, 1); 534 port = _pbm2port(bmap); 535 port_adj = 32; 536 if (port == -1) { 537 if (max_num_port > 64) { 538 bmap = SOC_PBMP_WORD_GET(pkt->tx_pbmp, 2); 539 port = _pbm2port(bmap); 540 port_adj = 64; 541 if (port == -1) { 542 if (max_num_port > 96) { 543 bmap = SOC_PBMP_WORD_GET(pkt->tx_pbmp, 3); 544 port = _pbm2port(bmap); 545 port_adj = 96; 546 } 547 if (port == -1) { 548 if (max_num_port > 128) { 549 bmap = SOC_PBMP_WORD_GET(pkt->tx_pbmp, 4); 550 port = _pbm2port(bmap); 551 port_adj = 128; 552 } 553 if (port == -1) { 554 if (max_num_port > 160) { 555 bmap = SOC_PBMP_WORD_GET(pkt->tx_pbmp, 5); 556 port = _pbm2port(bmap); 557 port_adj = 160; 558 } 559 } 560 } 561 } 562 } 563 } 564 } 565 if (port == -1) { 566 return BCM_E_PARAM; 567 } 568 } 569 if ((bmap & (~(1 << port))) != 0) { 570 return BCM_E_PARAM; 571 } 572 port += port_adj; 573 574 /* Check untag membership before translating */ 575 if (PBMP_MEMBER(pkt->tx_upbmp, port)) { 576 pkt->flags |= BCM_PKT_F_TX_UNTAG; 577 } else { 578 pkt->flags &= (~BCM_PKT_F_TX_UNTAG); 579 } 580 581 BCM_API_XLATE_PORT_A2P(unit, &port); 582 583 584 if ((SOC_DCB_TYPE(unit) == 23) || (SOC_DCB_TYPE(unit) == 26) || 585 (SOC_DCB_TYPE(unit) == 29) || (SOC_DCB_TYPE(unit) == 30) || 586 (SOC_DCB_TYPE(unit) == 31) || (SOC_DCB_TYPE(unit) == 33) || 587 (SOC_DCB_TYPE(unit) == 35) || (SOC_DCB_TYPE(unit) == 34) || 588 (SOC_DCB_TYPE(unit) == 37)) { 589 590 qnum = SOC_INFO(unit).port_uc_cosq_base[port] + pkt->cos; 591 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT) 592 if ((SOC_DCB_TYPE(unit) == 26) || (SOC_DCB_TYPE(unit) == 33)) { 593 qnum = soc_td2_logical_qnum_hw_qnum(unit, port, qnum, 1); 594 } 595 #endif /* BCM_TRIDENT2_SUPPORT */ 596 #if defined (BCM_APACHE_SUPPORT) 597 if ((SOC_DCB_TYPE(unit) == 35)) { 598 #if defined (BCM_MONTEREY_SUPPORT) 599 if (SOC_IS_MONTEREY(unit)) { 600 qnum = soc_monterey_logical_qnum_hw_qnum(unit, port, qnum, 1); 601 } else 602 #endif 603 { 604 qnum = soc_apache_logical_qnum_hw_qnum(unit, port, qnum, 1); 605 } 606 } 607 #endif /* BCM_APACHE_SUPPORT */ 608 #ifdef BCM_KATANA2_SUPPORT 609 if ((SOC_DCB_TYPE(unit) == 29) && (pkt->flags2 & BCM_PKT_F2_MA_PTR)) { 610 /* OAM case */ 611 qnum = SOC_INFO(unit).port_uc_cosq_base[port] + pkt->cos; 612 /* 613 * KATANA2: 614 * For UPMEP Packet tx, queue num is not valid 615 * Refer to SOBMH format for more details on 616 * UPMEP packet fields. 617 */ 618 if(!(pkt->flags2 & BCM_PKT_F2_MEP_TYPE_UPMEP)) { 619 PBS_MH_V8_W2_SMOD_COS_QNUM_SET(pbh, src_mod, 1, pkt->cos, qnum); 620 } 621 soc_pbsmh_field_set(unit, pbh, PBSMH_pp_port, port); 622 if(pkt->flags2 & BCM_PKT_F2_MEP_TYPE_UPMEP) { 623 PBS_MH_V8_W0_OAM_UPMEP_START_SET(pbh); 624 /* set internal priority */ 625 soc_pbsmh_field_set(unit, pbh, PBSMH_int_pri, prio_val); 626 } else { 627 PBS_MH_V8_W0_OAM_DOWNMEP_START_SET(pbh); 628 PBS_MH_V8_W0_OAM_DOWNMEP_CTR_LOCATION_SET(unit, pbh); 629 } 630 soc_pbsmh_field_set(unit, pbh, PBSMH_oam_ma_ptr, pkt->ma_ptr); 631 if(pkt->flags2 & BCM_PKT_F2_TIMESTAMP_MODE) { 632 soc_pbsmh_field_set(unit, pbh, PBSMH_ts_action, pkt->timestamp_mode); 633 } 634 if(pkt->flags2 & BCM_PKT_F2_SAMPLE_RDI) { 635 soc_pbsmh_field_set(unit, pbh, PBSMH_sample_rdi, 1); 636 } 637 if((pkt->flags2 & BCM_PKT_F2_REPLACEMENT_OFFSET)) { 638 soc_pbsmh_field_set(unit, pbh, PBSMH_oam_replacement_offset, 639 pkt->oam_replacement_offset); 640 } 641 if(pkt->flags2 & BCM_PKT_F2_LM_COUNTER_INDEX) { 642 soc_pbsmh_field_set(unit, pbh, PBSMH_lm_ctr1_index, 643 pkt->oam_lm_counter_index); 644 if(pkt->flags2 & BCM_PKT_F2_COUNTER_MODE_1) { 645 soc_pbsmh_field_set(unit, pbh, PBSMH_ctr1_action, 646 pkt->counter_mode_1); 647 } 648 } 649 if(pkt->flags2 & BCM_PKT_F2_LM_COUNTER_INDEX_2) { 650 soc_pbsmh_field_set(unit, pbh, PBSMH_lm_ctr2_index, 651 pkt->oam_lm_counter_index_2); 652 if(pkt->flags2 & BCM_PKT_F2_COUNTER_MODE_2) { 653 soc_pbsmh_field_set(unit, pbh, PBSMH_ctr2_action, 654 pkt->counter_mode_2); 655 } 656 } 657 } else if (SOC_DCB_TYPE(unit) == 29) { 658 if (BCM_GPORT_IS_UCAST_SUBSCRIBER_QUEUE_GROUP(pkt->dst_gport)) { 659 qnum = BCM_GPORT_UCAST_SUBSCRIBER_QUEUE_GROUP_QID_GET( 660 pkt->dst_gport); 661 } 662 PBS_MH_V7_W0_START_SET(pbh); 663 PBS_MH_V8_W1_DPORT_IPRI_SET(pbh, port,prio_val); 664 PBS_MH_V8_W2_SMOD_COS_QNUM_SET(pbh, src_mod, 1, pkt->cos, qnum); 665 soc_pbsmh_field_set(unit, pbh, PBSMH_dst_port, port); 666 } else 667 #endif /* BCM_KATANA2_SUPPORT */ 668 if ((SOC_DCB_TYPE(unit) == 33) || (SOC_DCB_TYPE(unit) == 35)) { 669 soc_pbsmh_field_set(unit, pbh, PBSMH_start, SOC_PBSMH_START_INTERNAL ); 670 soc_pbsmh_field_set(unit, pbh, PBSMH_header_type, SOC_SOBMH_FROM_CPU ); 671 soc_pbsmh_field_set(unit, pbh, PBSMH_unicast, 1 ); /* unicast */ 672 soc_pbsmh_field_set(unit, pbh, PBSMH_queue_num, qnum); 673 soc_pbsmh_field_set(unit, pbh, PBSMH_src_mod, src_mod); 674 soc_pbsmh_field_set(unit, pbh, PBSMH_cos, pkt->cos); 675 soc_pbsmh_field_set(unit, pbh, PBSMH_pri, prio_val); 676 soc_pbsmh_field_set(unit, pbh, PBSMH_dst_port, port); 677 } else { 678 PBS_MH_V7_W0_START_SET(pbh); 679 PBS_MH_V7_W1_DPORT_QNUM_SET(pbh, port, qnum); 680 PBS_MH_V7_W2_SMOD_COS_QNUM_SET(pbh, src_mod, 1, pkt->cos, qnum, 681 prio_val); 682 } 683 684 if (SOC_DCB_TYPE(unit) == 23) { 685 if((pkt->flags2 & BCM_PKT_F2_REPLACEMENT_TYPE) && 686 (pkt->flags2 & BCM_PKT_F2_REPLACEMENT_OFFSET)) { 687 soc_pbsmh_field_set(unit, pbh, PBSMH_oam_replacement_type, 688 pkt->oam_replacement_type); 689 soc_pbsmh_field_set(unit, pbh, PBSMH_oam_replacement_offset, 690 pkt->oam_replacement_offset); 691 if(pkt->flags2 & BCM_PKT_F2_LM_COUNTER_INDEX) { 692 soc_pbsmh_field_set(unit, pbh, PBSMH_lm_ctr_index, 693 pkt->oam_lm_counter_index); 694 } 695 } 696 } 697 } else if ((SOC_DCB_TYPE(unit) == 32) || (SOC_DCB_TYPE(unit) == 38)) { 698 /* 32 for TH, 38 for TH3 */ 699 PBS_MH_V9_W0_START_SET(pbh); 700 PBS_MH_V9_W1_DPORT_SET(pbh, port); 701 #ifdef BCM_INSTRUMENTATION_SUPPORT 702 if ((soc_feature(unit, soc_feature_visibility)) && 703 (pkt->flags2 & BCM_PKT_F2_RX_PORT)) { 704 705 uint32 loopback_port = soc_loopback_lbport_num_get(unit, 706 _bcm_esw_pkt_trace_src_pipe_get(unit)); 707 uint32 use_unicast_queues = 0; 708 709 if (loopback_port == -1) { 710 return BCM_E_PARAM; 711 } 712 713 PBS_MH_V9_W1_DPORT_SET(pbh, loopback_port); 714 715 if (SOC_DCB_TYPE(unit) == 38) { 716 use_unicast_queues = soc_property_get(unit, spn_LB_PORT_USE_UC_QUEUES, 0); 717 718 if (use_unicast_queues) { 719 /* for visibility packet, when using unicast queues unicast bit must be 1 and l2bm 0 */ 720 PBS_MH_V9_W2_SMOD_COS_L2BM_SET(pbh, src_mod, unicast, pkt->cos, 0); 721 } else { 722 /* for visibility packet, when using multicast queues unicast bit must be 0 and l2bm 1 */ 723 PBS_MH_V9_W2_SMOD_COS_L2BM_SET(pbh, src_mod, !(unicast), pkt->cos, 1); 724 } 725 } else { 726 /* for visibility packet, unicast bit must be 0 and l2bm 1 */ 727 PBS_MH_V9_W2_SMOD_COS_L2BM_SET(pbh, src_mod, !(unicast), pkt->cos, 1); 728 } 729 } else 730 #endif /* BCM_INSTRUMENTATION_SUPPORT */ 731 #ifdef BCM_CPU_TX_PROC_SUPPORT 732 if ((soc_feature(unit, soc_feature_cpu_tx_proc)) && 733 (pkt->flags2 & BCM_PKT_F2_CPU_TX_PROC)) { 734 735 uint32 pipe_num = soc_pipe_get(unit, pkt->rx_port); 736 uint32 sobmh_loopback_port = soc_lbport_num_get(unit, pipe_num); 737 uint32 use_unicast_queues = 0; 738 739 #ifdef BCM_TOMAHAWK3_SUPPORT 740 if (SOC_IS_TOMAHAWK3(unit)) { 741 if (pkt->rx_port == _TH3_MMU_SPARE_SRC_PORT) { 742 pipe_num = _TH3_MMU_SPARE_SRC_PORT_PIPE; 743 } 744 } 745 #endif 746 if (sobmh_loopback_port == -1) { 747 return BCM_E_PARAM; 748 } 749 750 use_unicast_queues = soc_property_get(unit, spn_LB_PORT_USE_UC_QUEUES, 0); 751 752 PBS_MH_V9_W1_DPORT_SET(pbh, sobmh_loopback_port); 753 754 if (use_unicast_queues) { 755 /* for cpu tx proc packet, when using unicast queues unicast bit must be 1 and l2bm 0 */ 756 PBS_MH_V9_W2_SMOD_COS_L2BM_SET(pbh, src_mod, unicast, pkt->cos, 0); 757 } else { 758 /* for cpu tx proc packet, when using multicast queues unicast bit must be 0 and l2bm 1 */ 759 PBS_MH_V9_W2_SMOD_COS_L2BM_SET(pbh, src_mod, !(unicast), pkt->cos, 1); 760 } 761 } else 762 #endif /* BCM_CPU_TX_PROC_SUPPORT */ 763 { 764 if (port == CMIC_PORT(unit)) { 765 /* send to multicast queue of CPU port */ 766 PBS_MH_V9_W2_SMOD_COS_L2BM_SET(pbh, src_mod, !(unicast), pkt->cos, 1); 767 } else { 768 PBS_MH_V9_W2_SMOD_COS_SET(pbh, src_mod, unicast, pkt->cos); 769 } 770 } 771 772 if (pkt->flags & BCM_PKT_F_TIMESYNC) { 773 /* Triumph3 timestamp fields set */ 774 if (pkt->timestamp_flags & BCM_TX_TIMESYNC_ONE_STEP) { 775 /* one step timestamp */ 776 soc_pbsmh_field_set(unit, pbh, PBSMH_osts, 1); 777 } else { 778 /* Two-step time stamping */ 779 soc_pbsmh_field_set(unit, pbh, PBSMH_tx_ts, 1); 780 } 781 if (pkt->timestamp_flags & 782 BCM_TX_TIMESYNC_INGRESS_SIGN) { 783 soc_pbsmh_field_set(unit, pbh, PBSMH_its_sign, 1); 784 } 785 786 if (pkt->timestamp_flags & 787 BCM_TX_TIMESYNC_HDR_START_OFFSET) { 788 soc_pbsmh_field_set(unit, pbh, PBSMH_hdr_offset, 789 pkt->timestamp_offset); 790 } 791 if (pkt->timestamp_flags & 792 BCM_TX_TIMESYNC_REGEN_UDP_CHKSUM) { 793 soc_pbsmh_field_set(unit, pbh, PBSMH_regen_udp_checksum, 1); 794 } 795 } 796 #ifdef BCM_TOMAHAWK3_SUPPORT 797 if (pkt->rqe_q_num) { 798 PBS_MH_V9_W2_RQE_SET(pbh, pkt->rqe_q_num); 799 } 800 #endif 801 } else if (SOC_DCB_TYPE(unit) == 36) { /* TD3 */ 802 PBS_MH_V11_W0_START_SET(pbh); 803 PBS_MH_V11_W1_DPORT_SET(pbh, port); 804 #ifdef BCM_INSTRUMENTATION_SUPPORT 805 if ((soc_feature(unit, soc_feature_visibility)) && 806 (pkt->flags2 & BCM_PKT_F2_RX_PORT)) { 807 808 uint32 loopback_port = soc_loopback_lbport_num_get(unit, 809 _bcm_esw_pkt_trace_src_pipe_get(unit)); 810 811 if (loopback_port == -1) { 812 return BCM_E_PARAM; 813 } 814 PBS_MH_V11_W1_DPORT_SET(pbh, loopback_port); 815 /* for visibility packet, unicast bit must be 0 and l2bm 1*/ 816 PBS_MH_V11_W2_SMOD_COS_L2BM_SET(pbh, src_mod, !(unicast), pkt->cos, 1); 817 } else 818 #endif /* BCM_INSTRUMENTATION_SUPPORT */ 819 { 820 if (port == CMIC_PORT(unit)) { 821 /* send to multicast queue of CPU port */ 822 PBS_MH_V11_W2_SMOD_COS_L2BM_SET(pbh, src_mod, !(unicast), pkt->cos, 1); 823 } else { 824 PBS_MH_V11_W2_SMOD_COS_SET(pbh, src_mod, unicast, pkt->cos); 825 } 826 } 827 828 if (pkt->flags & BCM_PKT_F_TIMESYNC) { 829 /* Triumph3 timestamp fields set */ 830 if (pkt->timestamp_flags & BCM_TX_TIMESYNC_ONE_STEP) { 831 /* one step timestamp */ 832 soc_pbsmh_field_set(unit, pbh, PBSMH_osts, 1); 833 } else { 834 /* Two-step time stamping */ 835 soc_pbsmh_field_set(unit, pbh, PBSMH_tx_ts, 1); 836 } 837 if (pkt->timestamp_flags & 838 BCM_TX_TIMESYNC_INGRESS_SIGN) { 839 soc_pbsmh_field_set(unit, pbh, PBSMH_its_sign, 1); 840 } 841 842 if (pkt->timestamp_flags & 843 BCM_TX_TIMESYNC_HDR_START_OFFSET) { 844 soc_pbsmh_field_set(unit, pbh, PBSMH_hdr_offset, 845 pkt->timestamp_offset); 846 } 847 848 if (pkt->timestamp_flags & 849 BCM_TX_TIMESYNC_REGEN_UDP_CHKSUM) { 850 soc_pbsmh_field_set(unit, pbh, PBSMH_regen_udp_checksum, 1); 851 } 852 } 853 /* TWAMP/OWAMP specific bits to be set in 854 * SOBMH header during TX */ 855 if (pkt->flags & BCM_PKT_F2_TWAMP_OWAMP_TS) { 856 if (soc_feature(unit, soc_feature_twamp_owamp_support)) { 857 soc_pbsmh_field_set(unit, pbh, PBSMH_amp_ts_act, 1); 858 soc_pbsmh_field_set(unit, pbh, PBSMH_hdr_offset, 859 BCM_PKT_HDR_TS_OFFSET_TWAMP_OWAMP); 860 } else { 861 return BCM_E_UNAVAIL; 862 } 863 } 864 } else { 865 PBS_MH_W0_START_SET(pbh); 866 PBS_MH_W1_RSVD_SET(pbh); 867 868 if ((SOC_DCB_TYPE(unit) == 11) || (SOC_DCB_TYPE(unit) == 12) || 869 (SOC_DCB_TYPE(unit) == 15) || (SOC_DCB_TYPE(unit) == 17) || 870 (SOC_DCB_TYPE(unit) == 18)) { 871 PBS_MH_V2_W2_SMOD_DPORT_COS_SET(pbh, src_mod, port, 872 pkt->cos, prio_val, 0); 873 if (pkt->flags & BCM_PKT_F_TIMESYNC) { 874 PBS_MH_V2_TS_PKT_SET(pbh); 875 } 876 } else if ((SOC_DCB_TYPE(unit) == 14) || (SOC_DCB_TYPE(unit) == 19) || 877 (SOC_DCB_TYPE(unit) == 20)) { 878 if (!(pkt->flags & BCM_TX_PRIO_INT)) { 879 /* If BCM_TX_PRIO_INT is not specified, the int_pri 880 * is set to the cos value. However in version 3 of 881 * the PBS_MH, cos is 6 bit, but int_prio is only 4. 882 * To be safe, set the int_prio to 0 if it wasn't 883 * explicitly set as indicated by BCM_TX_PRIO_INT flag. 884 */ 885 prio_val = 0; 886 } 887 PBS_MH_V3_W2_SMOD_DPORT_COS_SET(pbh, src_mod, port, 888 pkt->cos, prio_val, 0); 889 if (pkt->flags & BCM_PKT_F_TIMESYNC) { 890 PBS_MH_V3_TS_PKT_SET(pbh); 891 } 892 } else if (SOC_DCB_TYPE(unit) == 16) { 893 PBS_MH_V4_W2_SMOD_DPORT_COS_SET(pbh, src_mod, port, 894 pkt->cos, prio_val, 0); 895 } else if (SOC_DCB_TYPE(unit) == 21) { 896 PBS_MH_V5_W1_SMOD_SET(pbh, src_mod, 1, 0, 0); 897 PBS_MH_V5_W2_DPORT_COS_SET(pbh, port, pkt->cos, prio_val); 898 if (pkt->flags & BCM_PKT_F_TIMESYNC) { 899 PBS_MH_V5_TS_PKT_SET(pbh); 900 } 901 } else if (SOC_DCB_TYPE(unit) == 24) { 902 PBS_MH_V5_W1_SMOD_SET(pbh, src_mod, 1, 0, 0); 903 PBS_MH_V6_W2_DPORT_COS_QNUM_SET(pbh, port, pkt->cos, 904 (SOC_INFO(unit).port_cosq_base[port] + pkt->cos), 905 prio_val); 906 907 if (pkt->flags & BCM_PKT_F_TIMESYNC) { 908 PBS_MH_V5_TS_PKT_SET(pbh); 909 } 910 } else if ((SOC_DCB_TYPE(unit) == 16) || (SOC_DCB_TYPE(unit) == 22)) { 911 PBS_MH_V4_W2_SMOD_DPORT_COS_SET(pbh, src_mod, port, 912 pkt->cos, prio_val, 0); 913 } else { 914 PBS_MH_V1_W2_SMOD_DPORT_COS_SET(pbh, src_mod, port, 915 pkt->cos, prio_val, 0); 916 } 917 } 918 #ifdef BCM_TRIDENT_SUPPORT 919 if (pkt->flags2 & BCM_PKT_F2_MC_QUEUE) { 920 /*TD,TD2,TD2+,TH&TR3 support this feature*/ 921 if ((SOC_DCB_TYPE(unit) == 21) || (SOC_DCB_TYPE(unit) == 23) || 922 (SOC_DCB_TYPE(unit) == 26) || (SOC_DCB_TYPE(unit) == 32) || 923 (SOC_DCB_TYPE(unit) == 33) || (SOC_DCB_TYPE(unit) == 36) || 924 (SOC_DCB_TYPE(unit) == 38)) { 925 /* send to multicast queue of TX port */ 926 soc_pbsmh_field_set(unit, pbh, PBSMH_unicast, 0); 927 soc_pbsmh_field_set(unit, pbh, PBSMH_l2pbm_sel, 1); 928 } 929 } 930 #endif 931 if (pkt->flags & BCM_PKT_F_TIMESYNC) { 932 if (SOC_DCB_TYPE(unit) == 23 || SOC_DCB_TYPE(unit) == 26 || \ 933 SOC_DCB_TYPE(unit) == 30 || SOC_DCB_TYPE(unit) == 31 || \ 934 SOC_DCB_TYPE(unit) == 34 || \ 935 SOC_DCB_TYPE(unit) == 37) { 936 /* Triumph3 timestamp fields set */ 937 if (pkt->timestamp_flags & BCM_TX_TIMESYNC_ONE_STEP) { 938 PBS_MH_V7_TS_ONE_STEP_PKT_SET(pbh); 939 } else { 940 /* Two-step time stamping */ 941 PBS_MH_V7_TS_PKT_SET(pbh); 942 } 943 944 if ( pkt->timestamp_flags & 945 BCM_TX_TIMESYNC_INGRESS_SIGN) { 946 PBS_MH_V7_TS_ONE_STEP_INGRESS_SIGN_PKT_SET(pbh); 947 } 948 949 if ( pkt->timestamp_flags & 950 BCM_TX_TIMESYNC_HDR_START_OFFSET) { 951 PBS_MH_V7_TS_ONE_STEP_HDR_START_OFFSET_PKT_SET(pbh, 952 pkt->timestamp_offset); 953 } 954 955 if ( pkt->timestamp_flags & 956 BCM_TX_TIMESYNC_REGEN_UDP_CHKSUM) { 957 PBS_MH_V7_TS_ONE_STEP_HDR_START_REGEN_UDP_CHEKSUM_PKT_SET(pbh); 958 } 959 } else if (SOC_DCB_TYPE(unit) == 35) { 960 /* Triumph3 timestamp fields set */ 961 if (pkt->timestamp_flags & BCM_TX_TIMESYNC_ONE_STEP) { 962 soc_pbsmh_field_set(unit, pbh, PBSMH_osts, 1 ); /* one step timestamp */ 963 } else { 964 /* Two-step time stamping */ 965 soc_pbsmh_field_set(unit, pbh, PBSMH_tx_ts, 1 ); 966 } 967 968 if ( pkt->timestamp_flags & 969 BCM_TX_TIMESYNC_INGRESS_SIGN) { 970 soc_pbsmh_field_set(unit, pbh, PBSMH_its_sign, 1 ); 971 } 972 973 if ( pkt->timestamp_flags & 974 BCM_TX_TIMESYNC_HDR_START_OFFSET) { 975 soc_pbsmh_field_set(unit, pbh, PBSMH_hdr_offset, 976 pkt->timestamp_offset); 977 } 978 979 if ( pkt->timestamp_flags & 980 BCM_TX_TIMESYNC_REGEN_UDP_CHKSUM) { 981 soc_pbsmh_field_set(unit, pbh, PBSMH_regen_udp_checksum, 1 ); 982 } 983 } else if (SOC_DCB_TYPE(unit) == 33) { 984 /* TD2+ timestamp fields set */ 985 _bcm_xgs3_tx_pipe_handle_timestamp_flags(unit, pkt); 986 987 } else if (SOC_DCB_TYPE(unit) == 24) { 988 /* Katana timestamp fields set */ 989 if (pkt->timestamp_flags & BCM_TX_TIMESYNC_ONE_STEP) { 990 PBS_MH_V6_TS_ONE_STEP_PKT_SET(pbh); 991 } else { 992 /* Two-step time stamping */ 993 PBS_MH_V6_TS_PKT_SET(pbh); 994 } 995 996 if ( pkt->timestamp_flags & 997 BCM_TX_TIMESYNC_INGRESS_SIGN) { 998 PBS_MH_V6_TS_ONE_STEP_INGRESS_SIGN_PKT_SET(pbh); 999 } 1000 1001 if ( pkt->timestamp_flags & 1002 BCM_TX_TIMESYNC_HDR_START_OFFSET) { 1003 PBS_MH_V6_TS_ONE_STEP_HDR_START_OFFSET_PKT_SET(pbh, 1004 pkt->timestamp_offset); 1005 } 1006 1007 if ( pkt->timestamp_flags & 1008 BCM_TX_TIMESYNC_REGEN_UDP_CHKSUM) { 1009 PBS_MH_V6_TS_ONE_STEP_HDR_START_REGEN_UDP_CHEKSUM_PKT_SET(pbh); 1010 } 1011 } 1012 else if (SOC_DCB_TYPE(unit) == 29) { 1013 if (pkt->timestamp_flags & BCM_TX_TIMESYNC_ONE_STEP) { 1014 soc_pbsmh_field_set(unit, pbh, PBSMH_osts, 1); 1015 } else { 1016 soc_pbsmh_field_set(unit, pbh, PBSMH_tx_ts, 1); 1017 } 1018 if ( pkt->timestamp_flags & 1019 BCM_TX_TIMESYNC_INGRESS_SIGN) { 1020 soc_pbsmh_field_set(unit, pbh, PBSMH_its_sign, 1); 1021 } 1022 if ( pkt->timestamp_flags & 1023 BCM_TX_TIMESYNC_HDR_START_OFFSET) { 1024 soc_pbsmh_field_set(unit, pbh, PBSMH_hdr_offset, 1025 pkt->timestamp_offset); 1026 } 1027 if ( pkt->timestamp_flags & 1028 BCM_TX_TIMESYNC_REGEN_UDP_CHKSUM) { 1029 soc_pbsmh_field_set(unit, pbh, 1030 PBSMH_regen_udp_checksum, 1); 1031 } 1032 } 1033 } 1034 1035 return BCM_E_NONE; 1036 } 1037 #endif 1038 1039 #if defined(BCM_XGS_SUPPORT) && defined(BCM_HIGIG2_SUPPORT) 1040 /* 1041 * Function: 1042 * _bcm_tx_gport_resolve 1043 * Purpose: 1044 * Analyze the provided gport and convert it into Higig2 PPD2/3 1045 * suitable format, if appropriate. 1046 * Parameters: 1047 * gport - provided potential virtual port to resolve 1048 * vp - (OUT) resolved port info in Higig2 PD2/3 format 1049 * physical - (OUT) TRUE if physical port, FALSE if virtual port 1050 * Returns: 1051 * BCM_E_XXX 1052 * Notes: 1053 */ 1054 STATIC INLINE int 1055 _bcm_tx_gport_resolve(bcm_gport_t gport, bcm_port_t *vp) 1056 { 1057 bcm_port_t port; 1058 1059 if (BCM_GPORT_IS_MPLS_PORT(gport)) { 1060 port = BCM_GPORT_MPLS_PORT_ID_GET(gport); 1061 } else if (BCM_GPORT_IS_MIM_PORT(gport)) { 1062 port = BCM_GPORT_MIM_PORT_ID_GET(gport); 1063 } else if (BCM_GPORT_IS_WLAN_PORT(gport)) { 1064 port = BCM_GPORT_WLAN_PORT_ID_GET(gport); 1065 } else if (BCM_GPORT_IS_VLAN_PORT(gport)) { 1066 port = BCM_GPORT_VLAN_PORT_ID_GET(gport); 1067 } else if (BCM_GPORT_IS_SUBPORT_PORT(gport)) { 1068 port = BCM_GPORT_SUBPORT_PORT_GET(gport); 1069 } else if (BCM_GPORT_IS_NIV_PORT(gport)) { 1070 port = BCM_GPORT_NIV_PORT_ID_GET(gport); 1071 } else if (BCM_GPORT_IS_VXLAN_PORT(gport)) { 1072 port = BCM_GPORT_VXLAN_PORT_ID_GET(gport); 1073 } else { 1074 /* Can't parse */ 1075 return BCM_E_PORT; 1076 } 1077 1078 *vp = port; 1079 return BCM_E_NONE; 1080 } 1081 1082 STATIC INLINE int 1083 _bcm_tx_pkt_stk_forward_to_hg2(int forward, int *fwd_type, int *multicast) 1084 { 1085 /* Note: All multicast types are translated to SOC_HIGIG_OP_IPMC 1086 * because the MC index must be translated into the IPMC range for 1087 * the FRC multicast field. 1088 */ 1089 switch (forward) { 1090 case BCM_PKT_STK_FORWARD_CPU: 1091 *fwd_type = 0; 1092 *multicast = 0; 1093 break; 1094 case BCM_PKT_STK_FORWARD_L2_UNICAST: 1095 *fwd_type = 4; 1096 *multicast = 0; 1097 break; 1098 case BCM_PKT_STK_FORWARD_L3_UNICAST: 1099 *fwd_type = 2; 1100 *multicast = 0; 1101 break; 1102 case BCM_PKT_STK_FORWARD_L2_MULTICAST: 1103 *fwd_type = 4; 1104 *multicast = SOC_HIGIG_OP_IPMC; 1105 break; 1106 case BCM_PKT_STK_FORWARD_L2_MULTICAST_UNKNOWN: 1107 *fwd_type = 5; 1108 *multicast = SOC_HIGIG_OP_IPMC; 1109 break; 1110 case BCM_PKT_STK_FORWARD_L3_MULTICAST: 1111 *fwd_type = 2; 1112 *multicast = SOC_HIGIG_OP_IPMC; 1113 break; 1114 case BCM_PKT_STK_FORWARD_L3_MULTICAST_UNKNOWN: 1115 *fwd_type = 3; 1116 *multicast = SOC_HIGIG_OP_IPMC; 1117 break; 1118 case BCM_PKT_STK_FORWARD_L2_UNICAST_UNKNOWN: 1119 *fwd_type = 6; 1120 *multicast = SOC_HIGIG_OP_IPMC; 1121 break; 1122 case BCM_PKT_STK_FORWARD_BROADCAST: 1123 *fwd_type = 7; 1124 *multicast = SOC_HIGIG_OP_IPMC; 1125 break; 1126 default: 1127 return BCM_E_PARAM; 1128 } 1129 return BCM_E_NONE; 1130 } 1131 1132 #if defined(INCLUDE_L3) && defined(BCM_XGS3_SWITCH_SUPPORT) 1133 STATIC INLINE int 1134 _bcm_tx_pkt_stk_encap_to_repl_id(int unit, bcm_if_t encap, uint32 *repl_id) 1135 { 1136 if (encap > 0) { 1137 if (encap < BCM_XGS3_EGRESS_IDX_MIN(unit)) { 1138 *repl_id = encap; 1139 } else if (encap < BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)) { 1140 *repl_id = encap - BCM_XGS3_EGRESS_IDX_MIN(unit); 1141 } else if (encap < BCM_XGS3_MPLS_IF_EGRESS_IDX_MIN(unit)) { 1142 *repl_id = encap - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 1143 } else if (encap < BCM_XGS3_DVP_EGRESS_IDX_MIN(unit)) { 1144 *repl_id = encap - BCM_XGS3_MPLS_IF_EGRESS_IDX_MIN(unit); 1145 } else { 1146 *repl_id = encap - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 1147 } 1148 } else { 1149 return BCM_E_PARAM; 1150 } 1151 return BCM_E_NONE; 1152 } 1153 #endif /* INCLUDE_L3 && BCM_XGS3_SWITCH_SUPPORT */ 1154 1155 /* 1156 * Function: 1157 * _bcm_tx_hg2hdr_setup 1158 * Purpose: 1159 * Setup HiGig2 header local buffer consistently with packet's 1160 * data members. Legacy HiGig header members are done by 1161 * _bcm_tx_hghdr_setup. 1162 * Parameters: 1163 * pkt - Packet to set up header from 1164 * Returns: 1165 * BCM_E_XXX 1166 * Notes: 1167 */ 1168 1169 STATIC INLINE int 1170 _bcm_tx_hg2hdr_setup(bcm_pkt_t *pkt) 1171 { 1172 soc_higig2_hdr_t *xgh = (soc_higig2_hdr_t *)pkt->_higig; 1173 int unit = pkt->unit; 1174 uint32 vlan_val, prio_val, color, pfm, ppd = 0; 1175 uint32 src_port, src_mod; 1176 bcm_port_t dst_vp = 0, src_vp = 0; 1177 int multicast, fwd_type, mc_index_offset, mc_index; 1178 #if defined(BCM_BRADLEY_SUPPORT) 1179 int bcast_size, mcast_size, ipmc_size; 1180 #endif 1181 bcm_vlan_t vfi = 0; 1182 #if defined(INCLUDE_L3) && defined(BCM_XGS3_SWITCH_SUPPORT) 1183 uint32 repl_id; 1184 #endif /* INCLUDE_L3 && BCM_XGS3_SWITCH_SUPPORT */ 1185 1186 /* This must be first, so all of the following operate properly */ 1187 soc_higig2_field_set(unit, xgh, HG_start, SOC_HIGIG2_START); 1188 1189 if (pkt->flags2 & BCM_PKT_F2_EXT_HG_HDR) { 1190 soc_higig2_field_set(unit, xgh, HG_ehv, 1); 1191 } 1192 1193 /* Analyze the GPORTS */ 1194 if (pkt->stk_flags & BCM_PKT_STK_F_DST_PORT) { 1195 if (pkt->stk_flags & BCM_PKT_STK_F_ENCAP_ID) { 1196 /* Can't mix dest port and encap ID */ 1197 return BCM_E_PARAM; 1198 } 1199 BCM_IF_ERROR_RETURN 1200 (_bcm_tx_gport_resolve(pkt->dst_gport, &dst_vp)); 1201 } 1202 if (pkt->stk_flags & BCM_PKT_STK_F_SRC_PORT) { 1203 BCM_IF_ERROR_RETURN 1204 (_bcm_tx_gport_resolve(pkt->src_gport, &src_vp)); 1205 } 1206 1207 /* What kind of PPD are we dealing with? */ 1208 if (pkt->stk_flags & 1209 (BCM_PKT_STK_F_DEFERRED_DROP | 1210 BCM_PKT_STK_F_DEFERRED_CHANGE_PKT_PRIO | 1211 BCM_PKT_STK_F_DEFERRED_CHANGE_DSCP | 1212 BCM_PKT_STK_F_VLAN_TRANSLATE_NONE | 1213 BCM_PKT_STK_F_VLAN_TRANSLATE_UNCHANGED | 1214 BCM_PKT_STK_F_VLAN_TRANSLATE_CHANGED)) { 1215 ppd = 3; 1216 } 1217 if (dst_vp) { 1218 if (ppd > 2) { /* Conflict */ 1219 return BCM_E_PARAM; 1220 } 1221 ppd = 2; /* Virtual dest port type */ 1222 } 1223 if (pkt->stk_forward != BCM_PKT_STK_FORWARD_CPU) { 1224 if (ppd > 2) { /* Conflict */ 1225 return BCM_E_PARAM; 1226 } 1227 ppd = 2; /* Virtual dest port type */ 1228 } 1229 if (pkt->stk_flags & 1230 (BCM_PKT_STK_F_TRUNK_FAILOVER | BCM_PKT_STK_F_DO_NOT_MODIFY)) { 1231 if (ppd > 2) { /* Conflict */ 1232 return BCM_E_PARAM; 1233 } 1234 } 1235 if (pkt->stk_flags & BCM_PKT_STK_F_FAILOVER) { 1236 if (ppd > 2) { /* Conflict */ 1237 return BCM_E_PARAM; 1238 } 1239 ppd = 2; /* Protection nexthop only availabe in PPD 2 */ 1240 } 1241 #if defined(INCLUDE_L3) && defined(BCM_TRX_SUPPORT) 1242 if (_BCM_VPN_IS_VPLS(pkt->vlan) || _BCM_VPN_IS_MIM(pkt->vlan)) { 1243 if (ppd > 2) { /* Conflict */ 1244 return BCM_E_PARAM; 1245 } 1246 _BCM_VPN_GET(vfi, _BCM_VPN_TYPE_VFI, pkt->vlan); 1247 ppd = 2; /* Only PPD with VFI */ 1248 } 1249 #endif /* INCLUDE_L3 && BCM_TRX_SUPPORT */ 1250 if (pkt->stk_flags & BCM_PKT_STK_F_CLASSIFICATION_TAG) { 1251 if (ppd == 2) { /* Conflict */ 1252 return BCM_E_PARAM; 1253 } 1254 /* coverity[new_values] */ 1255 if (ppd != 3) { /* Conflict */ 1256 ppd = 1; /* Only PPD with VFI */ 1257 if (pkt->stk_flags & (BCM_PKT_STK_F_PRESERVE_DSCP | 1258 BCM_PKT_STK_F_PRESERVE_PKT_PRIO)) { 1259 return BCM_E_PARAM; 1260 } 1261 } 1262 } 1263 if ((pkt->stk_flags & BCM_PKT_STK_F_MIRROR) || 1264 (pkt->stk_flags & BCM_PKT_STK_F_ENCAP_ID) ){ 1265 if ((ppd == 1) || (ppd == 3)) { /* Conflict */ 1266 return BCM_E_PARAM; 1267 } 1268 } 1269 /* Otherwise, we will just use PPD0 */ 1270 1271 /* We must fill in the type before filling in the PPD-specific fields */ 1272 soc_higig2_field_set(unit, xgh, HG_ppd_type, ppd); 1273 1274 /* This field is common to all PPDs */ 1275 soc_higig2_field_set(unit, xgh, HG_opcode, pkt->opcode); 1276 /* Get multicast from opcode. Override if PPD2 */ 1277 multicast = ((pkt->opcode == SOC_HIGIG_OP_CPU) || 1278 (pkt->opcode == SOC_HIGIG_OP_UC)) ? 0 : pkt->opcode; 1279 1280 /* Now fill in by type */ 1281 switch (ppd) { 1282 case 3: 1283 soc_higig2_field_set(unit, xgh, HG_src_vp, src_vp); 1284 soc_higig2_field_set(unit, xgh, HG_src_type, 0); 1285 if (pkt->stk_flags & BCM_PKT_STK_F_PRESERVE_DSCP) { 1286 soc_higig2_field_set(unit, xgh, HG_preserve_dscp, 1); 1287 } 1288 if (pkt->stk_flags & BCM_PKT_STK_F_PRESERVE_PKT_PRIO) { 1289 soc_higig2_field_set(unit, xgh, HG_preserve_dot1p, 1); 1290 } 1291 if (pkt->stk_flags & BCM_PKT_STK_F_DO_NOT_LEARN) { 1292 soc_higig2_field_set(unit, xgh, HG_donot_learn, 1); 1293 } 1294 soc_higig2_field_set(unit, xgh, HG_opcode, pkt->opcode); 1295 soc_higig2_field_set(unit, xgh, HG_data_container_type, 1); 1296 /* Container info */ 1297 if (pkt->stk_flags & BCM_PKT_STK_F_CLASSIFICATION_TAG) { 1298 soc_higig2_field_set(unit, xgh, HG_ctag, 1299 pkt->stk_classification_tag); 1300 } 1301 if (pkt->stk_flags & BCM_PKT_STK_F_DEFERRED_DROP) { 1302 soc_higig2_field_set(unit, xgh, HG_deferred_drop, 1); 1303 } 1304 if (pkt->stk_flags & BCM_PKT_STK_F_DEFERRED_CHANGE_PKT_PRIO) { 1305 soc_higig2_field_set(unit, xgh, HG_deferred_change_pkt_pri, 1); 1306 soc_higig2_field_set(unit, xgh, HG_new_pkt_pri, pkt->stk_pkt_prio); 1307 } 1308 if (pkt->stk_flags & BCM_PKT_STK_F_DEFERRED_CHANGE_DSCP) { 1309 soc_higig2_field_set(unit, xgh, HG_deferred_change_dscp, 1); 1310 soc_higig2_field_set(unit, xgh, HG_new_dscp, pkt->stk_dscp); 1311 } 1312 if (pkt->stk_flags & BCM_PKT_STK_F_VLAN_TRANSLATE_CHANGED) { 1313 soc_higig2_field_set(unit, xgh, HG_vxlt_done, 3); 1314 } else if (pkt->stk_flags & BCM_PKT_STK_F_VLAN_TRANSLATE_UNCHANGED) { 1315 soc_higig2_field_set(unit, xgh, HG_vxlt_done, 1); 1316 } else if (pkt->stk_flags & BCM_PKT_STK_F_VLAN_TRANSLATE_NONE) { 1317 soc_higig2_field_set(unit, xgh, HG_vxlt_done, 0); 1318 } 1319 /* Must transmit VLAN tag with this format */ 1320 pkt->stk_flags |= BCM_PKT_STK_F_TX_TAG; 1321 break; 1322 case 2: 1323 BCM_IF_ERROR_RETURN 1324 (_bcm_tx_pkt_stk_forward_to_hg2(pkt->stk_forward, &fwd_type, 1325 &multicast)); 1326 soc_higig2_field_set(unit, xgh, HG_fwd_type, fwd_type); 1327 soc_higig2_field_set(unit, xgh, HG_multipoint, multicast ? 1 : 0); 1328 #if defined(INCLUDE_L3) && defined(BCM_XGS3_SWITCH_SUPPORT) 1329 if (pkt->stk_flags & BCM_PKT_STK_F_ENCAP_ID) { 1330 BCM_IF_ERROR_RETURN 1331 (_bcm_tx_pkt_stk_encap_to_repl_id(unit, pkt->stk_encap_id, 1332 &repl_id)); 1333 soc_higig2_field_set(unit, xgh, HG_replication_id, repl_id); 1334 } else 1335 #endif /* INCLUDE_L3 && BCM_XGS3_SWITCH_SUPPORT */ 1336 { 1337 if (multicast) { 1338 mc_index = _BCM_MULTICAST_ID_GET(pkt->multicast_group); 1339 /* This field is idetified as valid dvp on TD3X. 1340 * Keep hg_dst_vp as zero instead of mc index on TD3X, in the case 1341 * of multicast packets with ppd2 header injected by CPU. 1342 */ 1343 if (!SOC_IS_TRIDENT3X(unit)) { 1344 soc_higig2_field_set(unit, xgh, HG_dst_vp, mc_index); 1345 } 1346 } else { 1347 soc_higig2_field_set(unit, xgh, HG_dst_vp, dst_vp); 1348 soc_higig2_field_set(unit, xgh, HG_dst_type, 0); 1349 } 1350 } 1351 soc_higig2_field_set(unit, xgh, HG_src_vp, src_vp); 1352 soc_higig2_field_set(unit, xgh, HG_src_type, 0); 1353 soc_higig2_field_set(unit, xgh, HG_vni, vfi); 1354 if (pkt->stk_flags & BCM_PKT_STK_F_MIRROR) { 1355 soc_higig2_field_set(unit, xgh, HG_mirror, 1); 1356 } 1357 if (pkt->stk_flags & BCM_PKT_STK_F_DO_NOT_MODIFY) { 1358 soc_higig2_field_set(unit, xgh, HG_donot_modify, 1); 1359 } 1360 if (pkt->stk_flags & BCM_PKT_STK_F_DO_NOT_LEARN) { 1361 soc_higig2_field_set(unit, xgh, HG_donot_learn, 1); 1362 } 1363 if (pkt->stk_flags & BCM_PKT_STK_F_TRUNK_FAILOVER) { 1364 soc_higig2_field_set(unit, xgh, HG_lag_failover, 1); 1365 } 1366 if (pkt->stk_flags & BCM_PKT_STK_F_FAILOVER) { 1367 soc_higig2_field_set(unit, xgh, HG_protection_status, 1); 1368 } 1369 if (pkt->stk_flags & BCM_PKT_STK_F_PRESERVE_DSCP) { 1370 soc_higig2_field_set(unit, xgh, HG_preserve_dscp, 1); 1371 } 1372 if (pkt->stk_flags & BCM_PKT_STK_F_PRESERVE_PKT_PRIO) { 1373 soc_higig2_field_set(unit, xgh, HG_preserve_dot1p, 1); 1374 } 1375 /* Must transmit VLAN tag with this format */ 1376 pkt->stk_flags |= BCM_PKT_STK_F_TX_TAG; 1377 break; 1378 case 1: 1379 if (pkt->stk_flags & BCM_PKT_STK_F_CLASSIFICATION_TAG) { 1380 soc_higig2_field_set(unit, xgh, HG_ctag, 1381 pkt->stk_classification_tag); 1382 } 1383 vlan_val = BCM_PKT_VLAN_CONTROL(pkt); 1384 soc_higig2_field_set(unit, xgh, HG_vlan_tag, vlan_val); 1385 pfm = (pkt->flags & BCM_TX_PFM) ? 1386 pkt->pfm : SOC_DEFAULT_DMA_PFM_GET(unit); 1387 soc_higig2_field_set(unit, xgh, HG_pfm, pfm); 1388 break; 1389 case 0: 1390 if (!(pkt->rx_untagged & BCM_PKT_OUTER_UNTAGGED)) { 1391 soc_higig2_field_set(unit, xgh, HG_ingress_tagged, 1); 1392 } 1393 if (pkt->stk_flags & BCM_PKT_STK_F_MIRROR) { 1394 soc_higig2_field_set(unit, xgh, HG_mirror_only, 1); 1395 soc_higig2_field_set(unit, xgh, HG_mirror, 1); 1396 } 1397 if (pkt->stk_flags & BCM_PKT_STK_F_DO_NOT_MODIFY) { 1398 soc_higig2_field_set(unit, xgh, HG_donot_modify, 1); 1399 } 1400 if (pkt->stk_flags & BCM_PKT_STK_F_DO_NOT_LEARN) { 1401 soc_higig2_field_set(unit, xgh, HG_donot_learn, 1); 1402 } 1403 if (pkt->stk_flags & BCM_PKT_STK_F_TRUNK_FAILOVER) { 1404 soc_higig2_field_set(unit, xgh, HG_lag_failover, 1); 1405 } 1406 if (pkt->flags & BCM_PKT_F_ROUTED) { 1407 soc_higig2_field_set(unit, xgh, HG_l3, 1); 1408 } 1409 vlan_val = BCM_PKT_VLAN_CONTROL(pkt); 1410 soc_higig2_field_set(unit, xgh, HG_vlan_tag, vlan_val); 1411 pfm = (pkt->flags & BCM_TX_PFM) ? 1412 pkt->pfm : SOC_DEFAULT_DMA_PFM_GET(unit); 1413 soc_higig2_field_set(unit, xgh, HG_pfm, pfm); 1414 if (pkt->stk_flags & BCM_PKT_STK_F_PRESERVE_DSCP) { 1415 soc_higig2_field_set(unit, xgh, HG_preserve_dscp, 1); 1416 } 1417 if (pkt->stk_flags & BCM_PKT_STK_F_PRESERVE_PKT_PRIO) { 1418 soc_higig2_field_set(unit, xgh, HG_preserve_dot1p, 1); 1419 } 1420 #if defined(INCLUDE_L3) && defined(BCM_XGS3_SWITCH_SUPPORT) 1421 if (pkt->stk_flags & BCM_PKT_STK_F_ENCAP_ID) { 1422 BCM_IF_ERROR_RETURN 1423 (_bcm_tx_pkt_stk_encap_to_repl_id(unit, pkt->stk_encap_id, 1424 &repl_id)); 1425 soc_higig2_field_set(unit, xgh, HG_replication_id, repl_id); 1426 } 1427 #endif /* INCLUDE_L3 && BCM_XGS3_SWITCH_SUPPORT */ 1428 break; 1429 /* Defensive Default */ 1430 /* coverity[dead_error_begin] */ 1431 default: 1432 return BCM_E_INTERNAL; 1433 } 1434 1435 /* Finally, fill in the common FRC fields */ 1436 prio_val = (pkt->flags & BCM_TX_PRIO_INT) ? pkt->prio_int : pkt->cos; 1437 soc_higig2_field_set(unit, xgh, HG_tc, prio_val); 1438 1439 /* multicast from opcode or PPD2 flags */ 1440 if (multicast) { 1441 mc_index_offset = 0; 1442 1443 #if defined(BCM_BRADLEY_SUPPORT) 1444 /* Higig2 has different ranges for different multicast types */ 1445 1446 BCM_IF_ERROR_RETURN 1447 (soc_hbx_higig2_mcast_sizes_get(unit, &bcast_size, &mcast_size, 1448 &ipmc_size)); 1449 switch (multicast) { 1450 case SOC_HIGIG_OP_IPMC: 1451 mc_index_offset += mcast_size; 1452 /* Fall thru */ 1453 case SOC_HIGIG_OP_MC: 1454 mc_index_offset += bcast_size; 1455 /* Fall thru */ 1456 case SOC_HIGIG_OP_BC: 1457 break; 1458 default: 1459 /* Unknown opcode */ 1460 return BCM_E_PARAM; 1461 } 1462 #endif 1463 soc_higig2_field_set(unit, xgh, HG_mcst, 1); 1464 mc_index = _BCM_MULTICAST_ID_GET(pkt->multicast_group); 1465 soc_higig2_field_set(unit, xgh, HG_mgid, 1466 mc_index + mc_index_offset); 1467 } else { 1468 soc_higig2_field_set(unit, xgh, HG_dst_mod, pkt->dest_mod); 1469 soc_higig2_field_set(unit, xgh, HG_dst_port, pkt->dest_port); 1470 } 1471 1472 src_mod = (pkt->flags & BCM_TX_SRC_MOD) ? 1473 pkt->src_mod : SOC_DEFAULT_DMA_SRCMOD_GET(unit); 1474 soc_higig2_field_set(unit, xgh, HG_src_mod, src_mod); 1475 1476 src_port = (pkt->flags & BCM_TX_SRC_PORT) ? 1477 pkt->src_port : SOC_DEFAULT_DMA_SRCPORT_GET(unit); 1478 soc_higig2_field_set(unit, xgh, HG_src_port, src_port); 1479 1480 soc_higig2_field_set(unit, xgh, HG_lbid, pkt->stk_load_balancing_number); 1481 1482 switch (pkt->color) { 1483 case bcmColorGreen: 1484 color = 0; 1485 break; 1486 case bcmColorYellow: 1487 color = 3; 1488 break; 1489 case bcmColorRed: 1490 color = 1; 1491 break; 1492 case bcmColorBlack: 1493 default: 1494 return BCM_E_PARAM; 1495 } 1496 soc_higig2_field_set(unit, xgh, HG_dp, color); 1497 1498 return BCM_E_NONE; 1499 } 1500 #endif /* defined(BCM_XGS_SUPPORT) && defined(BCM_HIGIG2_SUPPORT) */ 1501 1502 /* 1503 * Function: 1504 * _bcm_tx_hghdr_setup 1505 * Purpose: 1506 * Setup HiGig header local buffer consistently with packet's 1507 * data members. 1508 * Parameters: 1509 * pkt - Packet to set up header from 1510 * Returns: 1511 * BCM_E_XXX 1512 * Notes: 1513 * The VLAN value is generally gotten from packet data (determined 1514 * by flags; The HG priority field (aka HG_cos) is either the 1515 * prio_int or cos field of the packet depending on the TX_PRIO_INT 1516 * flag. 1517 */ 1518 1519 STATIC INLINE int 1520 _bcm_tx_hghdr_setup(bcm_pkt_t *pkt) 1521 { 1522 #ifdef BCM_XGS_SUPPORT 1523 soc_higig_hdr_t *xgh = (soc_higig_hdr_t *)pkt->_higig; 1524 int unit = pkt->unit; 1525 uint32 vlan_val; 1526 uint32 prio_val; 1527 uint32 src_port; 1528 uint32 src_mod; 1529 uint32 pfm, color; 1530 1531 sal_memset(xgh, 0, sizeof(pkt->_higig)); 1532 soc_higig_field_set(unit, xgh, HG_start, SOC_HIGIG_START); 1533 #ifdef BCM_HIGIG2_SUPPORT 1534 if (SOC_IS_XGS3_SWITCH(unit)) { 1535 1536 if (!BCM_PKT_TX_ETHER(pkt)) { /* Raw mode */ 1537 bcm_pbmp_t tx_pbmp; 1538 int port; 1539 /* 1540 * Use HiGig2 format if port is configured for HiGig2 encapsulation. 1541 * Note that tx_pbmp only contains a single port at this point. 1542 */ 1543 BCM_PBMP_ASSIGN(tx_pbmp, pkt->tx_pbmp); 1544 BCM_API_XLATE_PORT_PBMP_A2P(unit, &tx_pbmp); 1545 BCM_PBMP_ITER(tx_pbmp, port) { 1546 /* Use cached info about HiGig2 instead of reading h/w registers */ 1547 if (IS_HG2_ENABLED_PORT(unit, port)) { 1548 return _bcm_tx_hg2hdr_setup(pkt); 1549 } 1550 #if defined(BCM_TRIDENT3_SUPPORT) 1551 else if (SOC_IS_TRIDENT3X(unit) && 1552 soc_feature(unit, soc_feature_higig_over_ethernet)) { 1553 bcm_port_encap_config_t encap_cfg; 1554 BCM_IF_ERROR_RETURN( 1555 bcm_port_encap_config_get(unit, port, &encap_cfg)); 1556 if (encap_cfg.encap == BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET) { 1557 return _bcm_tx_hg2hdr_setup(pkt); 1558 } 1559 } 1560 #endif 1561 #if defined(BCM_TRIDENT2PLUS_SUPPORT) && defined(BCM_TX_HGOE_LIMITED_SOLUTION) 1562 else if (SOC_IS_TRIDENT2PLUS(unit)) { 1563 int rv = BCM_E_NONE; 1564 bcm_port_encap_config_t encap_cfg; 1565 rv = bcm_port_encap_config_get(unit, port, &encap_cfg); 1566 if (!BCM_FAILURE(rv) && 1567 encap_cfg.encap==BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET) { 1568 return _bcm_tx_hg2hdr_setup(pkt); 1569 } 1570 } 1571 #endif /* BCM_TRIDENT2PLUS_SUPPORT && BCM_TX_HGOE_LIMITED_SOLUTION */ 1572 break; 1573 } 1574 } else { /* Packet to be sent through ingress logic */ 1575 /* If unit is Higig2 capable, set up Higig2 header */ 1576 if (soc_feature(unit, soc_feature_higig2)) { 1577 return _bcm_tx_hg2hdr_setup(pkt); 1578 } 1579 } 1580 } 1581 #endif /* BCM_HIGIG2_SUPPORT */ 1582 soc_higig_field_set(unit, xgh, HG_hgi, SOC_HIGIG_HGI); 1583 soc_higig_field_set(unit, xgh, HG_opcode, pkt->opcode); 1584 soc_higig_field_set(unit, xgh, HG_hdr_format, SOC_HIGIG_HDR_DEFAULT); 1585 1586 vlan_val = BCM_PKT_VLAN_CONTROL(pkt); 1587 soc_higig_field_set(unit, xgh, HG_vlan_tag, vlan_val); 1588 if ((pkt->opcode == SOC_HIGIG_OP_MC) || 1589 (pkt->opcode == SOC_HIGIG_OP_IPMC)) { 1590 soc_higig_field_set(unit, xgh, HG_l2mc_ptr, 1591 _BCM_MULTICAST_ID_GET(pkt->multicast_group)); 1592 } else { 1593 soc_higig_field_set(unit, xgh, HG_dst_mod, pkt->dest_mod); 1594 soc_higig_field_set(unit, xgh, HG_dst_port, pkt->dest_port); 1595 } 1596 1597 src_mod = (pkt->flags & BCM_TX_SRC_MOD) ? 1598 pkt->src_mod : SOC_DEFAULT_DMA_SRCMOD_GET(unit); 1599 soc_higig_field_set(unit, xgh, HG_src_mod, src_mod); 1600 1601 src_port = (pkt->flags & BCM_TX_SRC_PORT) ? 1602 pkt->src_port : SOC_DEFAULT_DMA_SRCPORT_GET(unit); 1603 soc_higig_field_set(unit, xgh, HG_src_port, src_port); 1604 1605 pfm = (pkt->flags & BCM_TX_PFM) ? 1606 pkt->pfm : SOC_DEFAULT_DMA_PFM_GET(unit); 1607 soc_higig_field_set(unit, xgh, HG_pfm, pfm); 1608 1609 prio_val = (pkt->flags & BCM_TX_PRIO_INT) ? pkt->prio_int : pkt->cos; 1610 soc_higig_field_set(unit, xgh, HG_cos, prio_val); 1611 1612 if (pkt->stk_flags & BCM_PKT_STK_F_CLASSIFICATION_TAG) { 1613 /* Overlay 2 */ 1614 if ((pkt->stk_flags & (BCM_PKT_STK_F_MIRROR | 1615 BCM_PKT_STK_F_DO_NOT_MODIFY | 1616 BCM_PKT_STK_F_DO_NOT_LEARN | 1617 BCM_PKT_STK_F_TRUNK_FAILOVER)) | 1618 (pkt->flags & BCM_PKT_F_ROUTED)) { 1619 /* Conflict */ 1620 return BCM_E_PARAM; 1621 } 1622 soc_higig_field_set(unit, xgh, HG_ctag, 1623 pkt->stk_classification_tag); 1624 soc_higig_field_set(unit, xgh, HG_hdr_format, 1); 1625 } else { 1626 /* Overlay 1 */ 1627 if (pkt->stk_flags & BCM_PKT_STK_F_MIRROR) { 1628 soc_higig_field_set(unit, xgh, HG_mirror_only, 1); 1629 soc_higig_field_set(unit, xgh, HG_mirror, 1); 1630 } 1631 if (pkt->stk_flags & BCM_PKT_STK_F_DO_NOT_MODIFY) { 1632 soc_higig_field_set(unit, xgh, HG_donot_modify, 1); 1633 } 1634 if (pkt->stk_flags & BCM_PKT_STK_F_DO_NOT_LEARN) { 1635 soc_higig_field_set(unit, xgh, HG_donot_learn, 1); 1636 } 1637 if (pkt->stk_flags & BCM_PKT_STK_F_TRUNK_FAILOVER) { 1638 soc_higig_field_set(unit, xgh, HG_lag_failover, 1); 1639 } 1640 if (pkt->flags & BCM_PKT_F_ROUTED) { 1641 soc_higig_field_set(unit, xgh, HG_l3, 1); 1642 } 1643 /* Header format 0 */ 1644 } 1645 1646 switch (pkt->color) { 1647 case bcmColorGreen: 1648 color = 0; 1649 break; 1650 case bcmColorYellow: 1651 color = 3; 1652 break; 1653 case bcmColorRed: 1654 color = 1; 1655 break; 1656 case bcmColorBlack: 1657 default: 1658 return BCM_E_PARAM; 1659 } 1660 soc_higig_field_set(unit, xgh, HG_cng, color); 1661 1662 return BCM_E_NONE; 1663 #endif /* BCM_XGS_SUPPORT */ 1664 1665 return BCM_E_UNAVAIL; 1666 } 1667 1668 1669 /* 1670 * Function: 1671 * _bcm_tx_sltag_setup 1672 * Purpose: 1673 * Setup the SL tag consistently with data in packet. 1674 * Parameters: 1675 * pkt - Packet to set up header from 1676 * Returns: 1677 * BCM_E_XXX 1678 * Notes: 1679 */ 1680 1681 STATIC INLINE int 1682 _bcm_tx_sltag_setup(bcm_pkt_t *pkt) 1683 { 1684 stk_tag_t *sltag = (stk_tag_t *)pkt->_sltag; 1685 int slcount; 1686 1687 sal_memset(sltag, 0, sizeof(*sltag)); 1688 if (pkt->opcode == BCM_HG_OPCODE_CPU) { 1689 slcount = 1; 1690 } else { 1691 slcount = 0; 1692 } 1693 sltag->stk_cnt = slcount; 1694 sltag->src_tgid = (pkt->src_port >> 3) & 0x7; 1695 sltag->src_rtag = pkt->src_port & 0x7; 1696 sltag->pfm = pkt->pfm; 1697 sltag->ed = 1; 1698 sltag->stk_modid = pkt->src_mod; 1699 return BCM_E_NONE; 1700 } 1701 1702 /* 1703 * Set up SL/HG tags according to system setup; 1704 * Assumes unit is local and packet is non-NULL 1705 */ 1706 1707 STATIC INLINE int 1708 _bcm_tx_pkt_tag_setup(int unit, bcm_pkt_t *pkt) 1709 { 1710 if (pkt == NULL) { 1711 return BCM_E_PARAM; 1712 } 1713 1714 if (!(SOC_IS_ARAD(unit) || SOC_IS_DNX(unit))) { 1715 /* 1716 * Ignore user provided BCM_PKT_F_HGHDR flag 1717 * keep it on Dune devices to indicate incoming CPU channel is set 1718 */ 1719 BCM_PKT_HGHDR_CLR(pkt); 1720 } 1721 1722 if (SOC_IS_XGS3_SWITCH(unit)) { 1723 /* 1724 * XGS3: Higig header in packet data stream (Raw mode) 1725 */ 1726 bcm_pbmp_t tmp_pbm; 1727 SOC_PBMP_ASSIGN(tmp_pbm, PBMP_HG_ALL(unit)); 1728 SOC_PBMP_OR(tmp_pbm, PBMP_HL_ALL(unit)); 1729 BCM_API_XLATE_PORT_PBMP_P2A(unit, &tmp_pbm); 1730 SOC_PBMP_AND(tmp_pbm, pkt->tx_pbmp); 1731 1732 if ((!BCM_PKT_TX_ETHER(pkt)) && 1733 (SOC_PBMP_NOT_NULL(tmp_pbm))) { /* Raw mode on HG port */ 1734 BCM_PKT_HGHDR_REQUIRE(pkt); 1735 } 1736 1737 /* 1738 * Construct higig header from discrete members in the pkt 1739 * if one is not provided. 1740 */ 1741 if (!BCM_PKT_TX_HG_READY(pkt)) { 1742 BCM_IF_ERROR_RETURN(_bcm_tx_hghdr_setup(pkt)); 1743 } 1744 #ifdef BCM_TRIDENT3_SUPPORT 1745 if (SOC_IS_TRIDENT3X(unit) && 1746 soc_feature(unit, soc_feature_higig_over_ethernet)) { 1747 int rv = BCM_E_NONE; 1748 bcm_port_t tmp_port = 0; 1749 bcm_port_encap_config_t encap_config = {0}; 1750 BCM_PBMP_ITER(pkt->tx_pbmp, tmp_port) { 1751 rv = bcm_port_encap_config_get(unit, tmp_port, &encap_config); 1752 if (!BCM_FAILURE(rv) 1753 && encap_config.encap==BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET) { 1754 /* clear HG flag in packet*/ 1755 BCM_PKT_HGHDR_CLR(pkt); 1756 break; 1757 } 1758 } 1759 } 1760 #endif 1761 } else if (SOC_IS_XGS12_FABRIC(unit)) { 1762 BCM_PKT_HGHDR_REQUIRE(pkt); 1763 if (!BCM_PKT_TX_HG_READY(pkt)) { 1764 BCM_IF_ERROR_RETURN(_bcm_tx_hghdr_setup(pkt)); 1765 } 1766 } else if (SOC_SL_MODE(unit)) { 1767 1768 1769 BCM_PKT_SLTAG_REQUIRE(pkt); 1770 BCM_IF_ERROR_RETURN(_bcm_tx_sltag_setup(pkt)); 1771 } 1772 1773 return BCM_E_NONE; 1774 } 1775 1776 1777 /* 1778 * Function: 1779 * bcm_tx_pkt_setup 1780 * Purpose: 1781 * Default packet setup routine for transmit 1782 * Parameters: 1783 * unit - Unit on which being transmitted 1784 * tx_pkt - Packet to update 1785 * Returns: 1786 * BCM_E_XXX 1787 * Notes: 1788 * tx_pkt->tx_pbmp should be set before calling this function 1789 * Currently, the main thing this does is force the HG header 1790 * on Hercules. 1791 */ 1792 1793 int 1794 bcm_common_tx_pkt_setup(int unit, bcm_pkt_t *tx_pkt) 1795 { 1796 if (tx_pkt == NULL) { 1797 return BCM_E_PARAM; 1798 } 1799 1800 if (!BCM_UNIT_VALID(unit)) { 1801 return BCM_E_UNIT; 1802 } 1803 if (!SOC_UNIT_VALID(unit)) { 1804 return BCM_E_UNIT; 1805 } 1806 if (!BCM_IS_LOCAL(unit)) { 1807 /* Don't need to do special setup for tunnelled packets */ 1808 return BCM_E_NONE; 1809 } 1810 1811 return _bcm_tx_pkt_tag_setup(unit, tx_pkt); 1812 } 1813 1814 /* 1815 * Function: 1816 * bcm_tx_init 1817 * Purpose: 1818 * Initialize BCM TX API 1819 * Parameters: 1820 * unit - transmission unit 1821 * Returns: 1822 * BCM_E_XXX 1823 * Notes: 1824 * Currently, this just allocates shared memory space for the 1825 * CRC append memory. This memory is zero and used by all packets 1826 * that require CRC append (allocate). 1827 * 1828 * This pointer is only allocated once. If allocation fails, 1829 * BCM_E_MEMORY is returned. 1830 */ 1831 1832 int 1833 bcm_common_tx_init(int unit) 1834 { 1835 #ifdef BCM_XGS3_SWITCH_SUPPORT 1836 sal_thread_t xgs3_async_tid = SAL_THREAD_ERROR; 1837 #endif 1838 1839 if (!BCM_CONTROL_UNIT_VALID(unit)) { 1840 return BCM_E_UNIT; 1841 } 1842 if (!BCM_IS_LOCAL(unit)) { 1843 /* Set up TX tunnel receiver and transmitter */ 1844 /* Currently this is done elsewhere */ 1845 return BCM_E_NONE; 1846 } 1847 if (!SOC_UNIT_VALID(unit)) { 1848 return BCM_E_UNIT; 1849 } 1850 1851 if (SOC_IS_RCPU_ONLY(unit)) { 1852 return BCM_E_NONE; 1853 } 1854 1855 if (_null_crc_ptr == NULL) { 1856 _null_crc_ptr = soc_cm_salloc(unit, sizeof(uint32), "Static CRC"); 1857 if (_null_crc_ptr == NULL) { 1858 goto error; 1859 } 1860 sal_memset(_null_crc_ptr, 0, sizeof(uint32)); 1861 } 1862 1863 if (tx_cb_sem == NULL) { 1864 tx_cb_sem = sal_sem_create("tx cb", sal_sem_BINARY, 0); 1865 if (tx_cb_sem == NULL) { 1866 goto error; 1867 } 1868 } 1869 if (tx_dv_done == NULL) { 1870 tx_dv_done = sal_sem_create("tx dv notify", sal_sem_BINARY, 0); 1871 if (tx_dv_done == NULL) { 1872 goto error; 1873 } 1874 } 1875 if (tx_exit_notify == NULL) { 1876 tx_exit_notify = sal_sem_create("tx exit notify", sal_sem_BINARY, 0); 1877 if (tx_exit_notify == NULL) { 1878 goto error; 1879 } 1880 } 1881 if (sal_tx_spinlock == NULL) { 1882 sal_tx_spinlock = sal_spinlock_create("sal_tx_lock"); 1883 if (sal_tx_spinlock == NULL) { 1884 goto error; 1885 } 1886 } 1887 1888 /* Allocate a min size pkt for padding */ 1889 if (_pkt_pad_ptr == NULL) { 1890 _pkt_pad_ptr = soc_cm_salloc(unit, ENET_MIN_PKT_SIZE, "TX Pkt Pad"); 1891 if (_pkt_pad_ptr == NULL) { 1892 goto error; 1893 } 1894 sal_memset(_pkt_pad_ptr, 0, ENET_MIN_PKT_SIZE); 1895 } 1896 1897 if (!_tx_init) { /* Only create the thread once */ 1898 1899 /* Start up the tx callback handler thread */ 1900 _tx_tid = sal_thread_create("bcmTX", SAL_THREAD_STKSZ, 1901 soc_property_get(unit, 1902 spn_BCM_TX_THREAD_PRI, 1903 DEFAULT_TX_PRI), 1904 _bcm_tx_callback_thread, NULL); 1905 if (_tx_tid == SAL_THREAD_ERROR) { 1906 goto error; 1907 } 1908 1909 #ifdef BCM_XGS3_SWITCH_SUPPORT 1910 if (SOC_IS_XGS3_SWITCH(unit)) { 1911 _xgs3_async_tx_sem = sal_sem_create("xgs3 tx async", 1912 sal_sem_COUNTING, 0); 1913 if (_xgs3_async_tx_sem == NULL) { 1914 goto error; 1915 } 1916 1917 _xgs3_async_queue_lock = sal_spinlock_create("xgs3 tx async"); 1918 if (_xgs3_async_queue_lock == NULL) { 1919 goto error; 1920 } 1921 1922 xgs3_async_tid = sal_thread_create("bcmXGS3AsyncTX", 1923 SAL_THREAD_STKSZ, 1924 soc_property_get(unit, 1925 spn_BCM_TX_THREAD_PRI, 1926 DEFAULT_TX_PRI), 1927 _xgs3_async_thread, NULL); 1928 if (xgs3_async_tid == SAL_THREAD_ERROR) { 1929 goto error; 1930 } 1931 } 1932 #endif 1933 #if defined(BCM_TRIDENT2PLUS_SUPPORT) && defined(BCM_TX_HGOE_LIMITED_SOLUTION) 1934 #if defined(BROADCOM_DEBUG) && defined(BCM_TX_HGOE_DBG) 1935 if (!g_hgoe_dbg_ctrs.tx_hgoe_ctr_sem) { 1936 g_hgoe_dbg_ctrs.tx_hgoe_ctr_sem = 1937 sal_sem_create("hgoe dbg sem", sal_sem_BINARY, 1); 1938 if (g_hgoe_dbg_ctrs.tx_hgoe_ctr_sem == NULL) { 1939 goto error; 1940 } 1941 } 1942 #endif /*BROADCOM_DEBUG*/ 1943 #endif /*TD2P && TX_HGOE_LIMITED_SOL*/ 1944 } 1945 _tx_init = TRUE; 1946 1947 return BCM_E_NONE; 1948 1949 error: 1950 1951 /* Clean up any allocated resources */ 1952 1953 #ifdef BCM_XGS3_SWITCH_SUPPORT 1954 if (_xgs3_async_tx_sem) { 1955 sal_sem_destroy(_xgs3_async_tx_sem); 1956 } 1957 if (_xgs3_async_queue_lock) { 1958 sal_spinlock_destroy(_xgs3_async_queue_lock); 1959 } 1960 #endif 1961 1962 if (_tx_tid != SAL_THREAD_ERROR) { 1963 sal_thread_destroy(_tx_tid); 1964 _tx_tid = SAL_THREAD_ERROR; 1965 } 1966 1967 if (_pkt_pad_ptr) { 1968 soc_cm_sfree(unit, _pkt_pad_ptr); 1969 _pkt_pad_ptr = NULL; 1970 } 1971 1972 if (tx_cb_sem) { 1973 sal_sem_destroy(tx_cb_sem); 1974 tx_cb_sem = NULL; 1975 } 1976 1977 if (tx_dv_done) { 1978 sal_sem_destroy(tx_dv_done); 1979 tx_dv_done = NULL; 1980 } 1981 1982 if (tx_exit_notify) { 1983 sal_sem_destroy(tx_exit_notify); 1984 tx_exit_notify = NULL; 1985 } 1986 1987 if (sal_tx_spinlock != NULL) { 1988 sal_spinlock_destroy(sal_tx_spinlock); 1989 sal_tx_spinlock = NULL; 1990 } 1991 1992 if (_null_crc_ptr) { 1993 soc_cm_sfree(unit, _null_crc_ptr); 1994 _null_crc_ptr = NULL; 1995 } 1996 #if defined(BCM_TRIDENT2PLUS_SUPPORT) && defined(BCM_TX_HGOE_LIMITED_SOLUTION) 1997 #if defined(BROADCOM_DEBUG) && defined(BCM_TX_HGOE_DBG) 1998 if (g_hgoe_dbg_ctrs.tx_hgoe_ctr_sem) { 1999 sal_sem_destroy(g_hgoe_dbg_ctrs.tx_hgoe_ctr_sem); 2000 g_hgoe_dbg_ctrs.tx_hgoe_ctr_sem = NULL; 2001 } 2002 #endif 2003 #endif /*TD2P && TX_HGOE_LIMITED_SOL && BCM_DEBUG */ 2004 2005 return BCM_E_MEMORY; 2006 2007 } 2008 2009 /* 2010 * Function: 2011 * bcm_common_tx_deinit 2012 * Purpose: 2013 * De-Initialize BCM TX API 2014 * Parameters: 2015 * unit - transmission unit 2016 * Returns: 2017 * BCM_E_XXX 2018 * Notes: 2019 * Currently, this just free memory allocated in bcm_tx_init 2020 */ 2021 2022 int 2023 bcm_common_tx_deinit(int unit) 2024 { 2025 if (!BCM_CONTROL_UNIT_VALID(unit)) { 2026 return BCM_E_UNIT; 2027 } 2028 if (!BCM_IS_LOCAL(unit)) { 2029 return BCM_E_NONE; 2030 } 2031 if (!SOC_UNIT_VALID(unit)) { 2032 return BCM_E_UNIT; 2033 } 2034 if (SOC_IS_RCPU_ONLY(unit)) { 2035 return BCM_E_NONE; 2036 } 2037 2038 if (1 == soc_ndev_attached) { 2039 if (_tx_tid != SAL_THREAD_ERROR) { 2040 /* Request exit */ 2041 _tx_init = FALSE; 2042 sal_sem_give(tx_cb_sem); 2043 /*wait tx thread had exit*/ 2044 (void)sal_sem_take(tx_exit_notify, sal_sem_FOREVER); 2045 2046 } 2047 if (sal_tx_spinlock != NULL) { 2048 sal_spinlock_destroy(sal_tx_spinlock); 2049 sal_tx_spinlock = NULL; 2050 } 2051 if (tx_cb_sem != NULL) { 2052 sal_sem_destroy(tx_cb_sem); 2053 tx_cb_sem = NULL; 2054 } 2055 if (tx_dv_done != NULL) { 2056 sal_sem_destroy(tx_dv_done); 2057 tx_dv_done = NULL; 2058 } 2059 if (tx_exit_notify != NULL) { 2060 sal_sem_destroy(tx_exit_notify); 2061 tx_exit_notify = NULL; 2062 } 2063 if (_pkt_pad_ptr != NULL) { 2064 soc_cm_sfree(unit, _pkt_pad_ptr); 2065 _pkt_pad_ptr = NULL; 2066 } 2067 if (_null_crc_ptr != NULL) { 2068 soc_cm_sfree(unit, _null_crc_ptr); 2069 _null_crc_ptr = NULL; 2070 } 2071 } 2072 return BCM_E_NONE; 2073 } 2074 2075 /* Check the packet flags for inconsistencies or unsupported configs */ 2076 2077 STATIC int 2078 _tx_flags_check(int unit, bcm_pkt_t *pkt) 2079 { 2080 if (pkt == NULL) { 2081 return BCM_E_PARAM; 2082 } 2083 2084 /* Check for acceptable/consistent flags */ 2085 if (pkt->flags & BCM_TX_PRIO_INT) { 2086 if (SOC_IS_DRACO1(unit) || SOC_IS_LYNX(unit)) { 2087 if (pkt->cos != pkt->prio_int) { 2088 LOG_ERROR(BSL_LS_BCM_TX, 2089 (BSL_META_U(unit, 2090 "Cannot set cos != prio_int on TX for 5690/74\n"))); 2091 return BCM_E_PARAM; 2092 } 2093 } 2094 } 2095 2096 return BCM_E_NONE; 2097 } 2098 2099 STATIC INLINE int 2100 _bcm_tx_cb_intr_enabled(void) 2101 { 2102 #ifdef TX_CB_INTR 2103 return BCM_E_NONE; 2104 #else 2105 return BCM_E_UNAVAIL; 2106 #endif 2107 } 2108 #ifdef BCM_XGS3_SWITCH_SUPPORT 2109 STATIC void 2110 _xgs3_calculate_tx_packet_size(int unit, dv_t *dv, int *bytes) 2111 { 2112 int i; 2113 switch (SOC_DCB_TYPE(unit)) { 2114 default: 2115 case 9: 2116 for (i = 0; i < dv->dv_vcnt; i++) { 2117 *bytes += ((dcb9_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2118 } 2119 return; 2120 #ifdef BCM_EASYRIDER_SUPPORT 2121 case 10: 2122 for (i = 0; i < dv->dv_vcnt; i++) { 2123 *bytes += ((dcb10_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2124 } 2125 return; 2126 #endif /* BCM_EASYRIDER_SUPPORT */ 2127 #ifdef BCM_BRADLEY_SUPPORT 2128 case 11: 2129 for (i = 0; i < dv->dv_vcnt; i++) { 2130 *bytes += ((dcb11_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2131 } 2132 return; 2133 #endif /* BCM_BRADLEY_SUPPORT */ 2134 #ifdef BCM_RAPTOR_SUPPORT 2135 case 12: 2136 for (i = 0; i < dv->dv_vcnt; i++) { 2137 *bytes += ((dcb12_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2138 } 2139 return; 2140 #endif /* BCM_RAPTOR_SUPPORT */ 2141 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_FIREBOLT_SUPPORT) 2142 case 13: 2143 for (i = 0; i < dv->dv_vcnt; i++) { 2144 *bytes += ((dcb13_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2145 } 2146 return; 2147 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_FIREBOLT_SUPPORT */ 2148 #ifdef BCM_TRIUMPH_SUPPORT 2149 case 14: 2150 for (i = 0; i < dv->dv_vcnt; i++) { 2151 *bytes += ((dcb14_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2152 } 2153 return; 2154 #endif /* BCM_TRIUMPH_SUPPORT */ 2155 #ifdef BCM_RAPTOR_SUPPORT 2156 case 15: 2157 for (i = 0; i < dv->dv_vcnt; i++) { 2158 *bytes += ((dcb15_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2159 } 2160 return; 2161 #endif /* BCM_RAPTOR_SUPPORT */ 2162 #ifdef BCM_SCORPION_SUPPORT 2163 case 16: 2164 for (i = 0; i < dv->dv_vcnt; i++) { 2165 *bytes += ((dcb16_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2166 } 2167 return; 2168 #endif /* BCM_SCORPION_SUPPORT */ 2169 #ifdef BCM_HAWKEYE_SUPPORT 2170 case 17: 2171 for (i = 0; i < dv->dv_vcnt; i++) { 2172 *bytes += ((dcb17_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2173 } 2174 return; 2175 #endif /* BCM_HAWKEYE_SUPPORT */ 2176 #ifdef BCM_RAPTOR_SUPPORT 2177 case 18: 2178 for (i = 0; i < dv->dv_vcnt; i++) { 2179 *bytes += ((dcb18_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2180 } 2181 return; 2182 #endif /* BCM_RAPTOR_SUPPORT */ 2183 #ifdef BCM_TRIUMPH2_SUPPORT 2184 case 19: 2185 for (i = 0; i < dv->dv_vcnt; i++) { 2186 *bytes += ((dcb19_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2187 } 2188 return; 2189 #endif /* BCM_TRIUMPH2_SUPPORT */ 2190 #ifdef BCM_ENDURO_SUPPORT 2191 case 20: 2192 case 30: 2193 for (i = 0; i < dv->dv_vcnt; i++) { 2194 *bytes += ((dcb20_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2195 } 2196 return; 2197 #endif /* BCM_ENDURO_SUPPORT */ 2198 #ifdef BCM_TRIDENT_SUPPORT 2199 case 21: 2200 for (i = 0; i < dv->dv_vcnt; i++) { 2201 *bytes += ((dcb21_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2202 } 2203 return; 2204 #endif /* BCM_TRIDENT_SUPPORT */ 2205 #ifdef BCM_SHADOW_SUPPORT 2206 case 22: 2207 for (i = 0; i < dv->dv_vcnt; i++) { 2208 *bytes += ((dcb22_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2209 } 2210 return; 2211 #endif /* BCM_SHADOW_SUPPORT */ 2212 #ifdef BCM_TRIUMPH3_SUPPORT 2213 case 23: 2214 for (i = 0; i < dv->dv_vcnt; i++) { 2215 *bytes += ((dcb23_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2216 } 2217 return; 2218 #endif /* BCM_TRIUMPH3_SUPPORT */ 2219 #ifdef BCM_KATANA_SUPPORT 2220 case 24: 2221 for (i = 0; i < dv->dv_vcnt; i++) { 2222 *bytes += ((dcb24_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2223 } 2224 return; 2225 #endif /* BCM_KATANA_SUPPORT */ 2226 #if defined(BCM_TRIDENT2_SUPPORT) 2227 case 26: 2228 for (i = 0; i < dv->dv_vcnt; i++) { 2229 *bytes += ((dcb26_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2230 } 2231 return; 2232 #endif /* BCM_TRIDENT2_SUPPORT */ 2233 #ifdef BCM_KATANA2_SUPPORT 2234 case 29: 2235 for (i = 0; i < dv->dv_vcnt; i++) { 2236 *bytes += ((dcb29_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2237 } 2238 return; 2239 #endif /* BCM_KATANA2_SUPPORT */ 2240 #ifdef BCM_GREYHOUND_SUPPORT 2241 case 31: 2242 for (i = 0; i < dv->dv_vcnt; i++) { 2243 *bytes += ((dcb31_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2244 } 2245 return; 2246 #endif /* BCM_GREYHOUND_SUPPORT */ 2247 #if defined(BCM_TOMAHAWK_SUPPORT) 2248 case 32: 2249 for (i = 0; i < dv->dv_vcnt; i++) { 2250 *bytes += ((dcb32_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2251 } 2252 return; 2253 #endif /* BCM_TOMAHAWK_SUPPORT */ 2254 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 2255 case 33: 2256 for (i = 0; i < dv->dv_vcnt; i++) { 2257 *bytes += 2258 ((dcb33_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2259 } 2260 return; 2261 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 2262 #if defined(BCM_APACHE_SUPPORT) 2263 case 35: 2264 for (i = 0; i < dv->dv_vcnt; i++) { 2265 *bytes += 2266 ((dcb35_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2267 } 2268 return; 2269 #endif /* BCM_APACHE_SUPPORT */ 2270 #if defined(BCM_TRIDENT3_SUPPORT) 2271 case 36: 2272 for (i = 0; i < dv->dv_vcnt; i++) { 2273 *bytes += 2274 ((dcb36_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2275 } 2276 return; 2277 #endif /* BCM_TRIDENT3_SUPPORT */ 2278 #if defined(BCM_TOMAHAWK3_SUPPORT) 2279 case 38: 2280 for (i = 0; i < dv->dv_vcnt; i++) { 2281 *bytes += 2282 ((dcb38_t *)SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, i))->c_count; 2283 } 2284 return; 2285 #endif /* BCM_TOMAHAWK3_SUPPORT */ 2286 } 2287 } 2288 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 2289 2290 /* 2291 * Function: 2292 * _bcm_tx 2293 * Purpose: 2294 * Transmit a single packet 2295 * Parameters: 2296 * unit - transmission unit 2297 * pkt - The tx packet structure 2298 * cookie - Callback cookie when tx done 2299 * Returns: 2300 * BCM_E_XXX 2301 * Notes: 2302 * To send unicast, broadcast or multicast packets from a switch 2303 * chip, one must include all the outgoing ports in the port bitmap 2304 * (pkt->pi_pbmp, pkt->pi_upbmp) and include the appropriate MAC DA 2305 * in the packet data. To send different types of packet from a 2306 * fabric chip, it is different and the Higig opcode 2307 * (BCM_HG_OPCODE_xxx) indicates the type of packet. 2308 * 2309 * If the pkt->call_back function is non-null, executes async. 2310 * Otherwise, will not return until DMA completes. 2311 * 2312 * Packet format is described by the packet flags. In particular, 2313 * if the packet has a HiGig header (as indicated in the packet's 2314 * flags) it will not have a VLAN tag set up for DMA. Care should 2315 * be taken as this should only happen for Hercules (5670, 71). 2316 * No provision is made for forcing the addition of both a VLAN 2317 * tag and a HiGig header. 2318 * 2319 * If the unit is not local, TX tunneling is automatically 2320 * invoked. CURRENT RESTRICTION: Asynchronous tunneled packets 2321 * cannot receive cookie on callback. 2322 */ 2323 2324 int 2325 _bcm_tx(int unit, bcm_pkt_t *pkt, void *cookie) 2326 { 2327 dv_t *dv = NULL; 2328 int rv = BCM_E_NONE; 2329 char fmt[SOC_PBMP_FMT_LEN]; 2330 char *err_msg = NULL; 2331 const int pkt_unit = (int) pkt->unit; 2332 int async = pkt->call_back != NULL; 2333 #if defined(BCM_CMICX_SUPPORT) 2334 uint32 prefetch = 0; 2335 #endif 2336 2337 if (!BCM_UNIT_VALID(unit)) { 2338 return BCM_E_UNIT; 2339 } 2340 2341 if (!SOC_UNIT_VALID(unit)) { 2342 return BCM_E_UNIT; 2343 } 2344 2345 if (!pkt || !pkt->pkt_data || (pkt->blk_count == 0) || 2346 !BCM_UNIT_VALID(pkt_unit) 2347 ) { 2348 return BCM_E_PARAM; 2349 } 2350 2351 if (bsl_check(bslLayerSoc, bslSourceTx, bslSeverityNormal, unit)) { 2352 bcm_pbmp_t tx_pbmp, tx_upbmp; 2353 BCM_PBMP_ASSIGN(tx_pbmp, pkt->tx_pbmp); 2354 BCM_PBMP_ASSIGN(tx_upbmp, pkt->tx_upbmp); 2355 BCM_API_XLATE_PORT_PBMP_A2P(unit, &tx_pbmp); 2356 BCM_API_XLATE_PORT_PBMP_A2P(unit, &tx_upbmp); 2357 LOG_INFO(BSL_LS_BCM_TX, 2358 (BSL_META_U(unit, 2359 "bcm_tx: pkt, u %d. len[0] %d to %s. "), 2360 unit, pkt->pkt_data[0].len, 2361 SOC_PBMP_FMT(tx_pbmp, fmt) 2362 )); 2363 LOG_INFO(BSL_LS_BCM_TX, 2364 (BSL_META_U(unit, 2365 "%s. flags 0x%x\n"), 2366 SOC_PBMP_FMT(tx_upbmp, fmt), 2367 pkt->flags)); 2368 LOG_INFO(BSL_LS_BCM_TX, 2369 (BSL_META_U(unit, 2370 "bcm_tx: dmod %d, dport %d, chan %d, op %d cos %d\n"), 2371 pkt->dest_mod, pkt->dest_port, pkt->dma_channel, pkt->opcode, 2372 pkt->cos)); 2373 { 2374 uint16 i; 2375 LOG_INFO(BSL_LS_BCM_TX, 2376 (BSL_META_U(unit, 2377 "bcm_tx: packet: "))); 2378 for (i=0; i<pkt->pkt_data[0].len ; i++) { 2379 LOG_INFO(BSL_LS_BCM_TX, 2380 (BSL_META_U(unit, 2381 "%.2x"),pkt->pkt_data[0].data[i])); 2382 } 2383 LOG_INFO(BSL_LS_BCM_TX, 2384 (BSL_META_U(unit, 2385 "\n"))); 2386 } 2387 } 2388 #ifdef BCM_RPC_SUPPORT 2389 if (!BCM_IS_LOCAL(unit)) { /* Tunnel the packet to the remote CPU */ 2390 bcm_cpu_tunnel_mode_t mode = BCM_CPU_TUNNEL_PACKET; /* default */ 2391 2392 if (pkt->call_back != NULL && cookie != NULL) { 2393 LOG_ERROR(BSL_LS_BCM_TX, 2394 (BSL_META_U(unit, 2395 "bcm_tx ERROR: " 2396 "Cookie non-NULL on async tunnel call\n"))); 2397 return BCM_E_PARAM; 2398 } 2399 2400 if (pkt->flags & BCM_TX_BEST_EFFORT) { 2401 mode = BCM_CPU_TUNNEL_PACKET_BEST_EFFORT; 2402 } else if (pkt->flags & BCM_TX_RELIABLE) { 2403 mode = BCM_CPU_TUNNEL_PACKET_RELIABLE; 2404 } 2405 2406 return bcm_tx_cpu_tunnel(pkt, unit, 0, BCM_CPU_TUNNEL_F_PBMP, mode); 2407 } 2408 #endif /* BCM_RPC_SUPPORT */ 2409 2410 err_msg = "Bad flags for bcm_tx"; 2411 /* coverity[overrun-call] */ 2412 _ON_ERROR_GOTO(_tx_flags_check(unit, pkt), rv, error); 2413 2414 err_msg = "Could not set up pkt for bcm_tx"; 2415 /* coverity[overrun-call] */ 2416 _ON_ERROR_GOTO(_bcm_tx_pkt_tag_setup(unit, pkt), rv, error); 2417 2418 #if defined (INCLUDE_RCPU) && defined(BCM_XGS3_SWITCH_SUPPORT) 2419 if ((SOC_UNIT_VALID(unit)) && (SOC_IS_RCPU_UNIT(unit))) { 2420 if (!BCM_PKT_TX_ETHER(pkt)) { 2421 BCM_IF_ERROR_RETURN(_bcm_xgs3_tx_pipe_bypass_header_setup(unit, pkt)); 2422 } 2423 return _bcm_rcpu_tx(unit, pkt, cookie); 2424 } 2425 #endif /* INCLUDE_RCPU && BCM_XGS3_SWITCH_SUPPORT */ 2426 2427 err_msg = "Could not allocate dv/dv info"; 2428 do { 2429 dv = _tx_dv_alloc(unit, 1, pkt->blk_count + TX_EXTRA_DCB_COUNT, 2430 NULL, cookie, pkt->call_back != NULL); 2431 if (!dv) { 2432 if (BCM_SUCCESS(_bcm_tx_cb_intr_enabled())) { 2433 rv = BCM_E_MEMORY; 2434 goto error; 2435 } 2436 LOG_WARN(BSL_LS_BCM_TX, 2437 (BSL_META_U(unit, "%s%s\n"), err_msg, ", will retry ...")); 2438 if (sal_sem_take(tx_dv_done, sal_sem_FOREVER) < 0) { 2439 err_msg = "Failed to take tx_dv_done"; 2440 rv = BCM_E_FAIL; 2441 goto error; 2442 } 2443 } 2444 } while (!dv); 2445 2446 err_msg = "Could not setup or add pkt to DV"; 2447 #ifdef BCM_PETRA_SUPPORT 2448 if (SOC_IS_ARAD(unit)) 2449 { 2450 _ON_ERROR_GOTO(_sand_tx_pkt_desc_add(unit, pkt, dv, 0), rv, error); 2451 } 2452 else 2453 #endif 2454 #ifdef BCM_DNX_SUPPORT 2455 if (SOC_IS_DNX(unit)) 2456 { 2457 _ON_ERROR_GOTO(_sand_tx_pkt_desc_add(unit, pkt, dv, 0), rv, error); 2458 } 2459 else 2460 #endif 2461 { 2462 _ON_ERROR_GOTO(_tx_pkt_desc_add(unit, pkt, dv, 0), rv, error); 2463 } 2464 2465 if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) { 2466 if (dv->dv_vcnt > 0) { /* Only add reload dcb if pkt dcb added */ 2467 err_msg = "Could not allocate a reload descriptor"; 2468 if (soc_dma_rld_desc_add(dv, 0) < 0) { 2469 rv = BCM_E_MEMORY; 2470 goto error; 2471 } 2472 #if defined(BCM_CMICX_SUPPORT) 2473 prefetch = 1; 2474 #endif 2475 } 2476 } 2477 #if defined(BCM_CMICX_SUPPORT) 2478 if (!prefetch) { 2479 soc_dma_contiguous_desc_add(dv); 2480 } 2481 #endif 2482 2483 #ifdef BCM_XGS3_SWITCH_SUPPORT 2484 if ((pkt->flags & BCM_TX_NO_PAD) && (dv->dv_vcnt > 0)) { 2485 int bytes = 0; 2486 _xgs3_calculate_tx_packet_size(unit, dv, &bytes); 2487 2488 if (SOC_IS_XGS3_SWITCH(unit)) { 2489 if ((BCM_PKT_NO_VLAN_TAG(pkt) && bytes < 60) || 2490 (!BCM_PKT_NO_VLAN_TAG(pkt) && BCM_PKT_HAS_HGHDR(pkt) && 2491 BCM_PKT_TX_FABRIC_MAPPED(pkt) && bytes < 60) || 2492 (!BCM_PKT_NO_VLAN_TAG(pkt) && !BCM_PKT_HAS_HGHDR(pkt) && 2493 !BCM_PKT_TX_FABRIC_MAPPED(pkt) && bytes < 64)) { 2494 LOG_ERROR(BSL_LS_BCM_TX, 2495 (BSL_META_U(unit, 2496 "bcm_tx: Discarding %s runt packet %s higig header %d\n"), 2497 BCM_PKT_NO_VLAN_TAG(pkt) ? "untagged" : "tagged", 2498 BCM_PKT_HAS_HGHDR(pkt) ? "with" : "without", bytes)); 2499 err_msg = ""; 2500 rv = BCM_E_PARAM; 2501 goto error; 2502 } 2503 } 2504 } 2505 #ifdef BCM_INSTRUMENTATION_SUPPORT 2506 if (pkt->flags2 & BCM_PKT_F2_VISIBILITY_PKT) { 2507 _bcm_esw_pkt_trace_hw_reset(unit); 2508 } 2509 #endif /* BCM_INSTRUMENTATION_SUPPORT */ 2510 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 2511 2512 err_msg = "Could not send pkt"; 2513 if ((dv->dv_vcnt > 0) || (SOC_IS_ARAD(unit)) || (SOC_IS_DNX(unit))) { 2514 rv = _bcm_tx_chain_send(unit, dv, async); 2515 2516 } else { 2517 /* Call the registered callback if any */ 2518 if (pkt->call_back != NULL) { 2519 (pkt->call_back)(unit, pkt, cookie); 2520 } 2521 if (dv != NULL) { 2522 _tx_dv_free(unit, dv); 2523 } 2524 rv = BCM_E_NONE; 2525 } 2526 2527 error: 2528 _PROCESS_ERROR(unit, rv, dv, err_msg); 2529 return rv; 2530 } 2531 2532 /* 2533 * Function: 2534 * _xgs3_async_thread 2535 * Purpose: 2536 * Handles anync transmit for XGS3 devices 2537 * Parameters: 2538 */ 2539 2540 #ifdef BCM_XGS3_SWITCH_SUPPORT 2541 STATIC int 2542 _xgs3_async_tx(int unit, bcm_pkt_t * pkt, void * cookie) 2543 { 2544 _xgs3_async_queue_t * item; 2545 2546 item = sal_alloc(sizeof(_xgs3_async_queue_t), "Async packet info"); 2547 if (item == NULL) { 2548 LOG_ERROR(BSL_LS_BCM_TX, 2549 (BSL_META_U(unit, 2550 "Can't allocate packet info\n"))); 2551 return BCM_E_MEMORY; 2552 } 2553 sal_memset(item, 0, sizeof(_xgs3_async_queue_t)); 2554 2555 item->unit = unit; 2556 item->pkt = pkt; 2557 item->cookie = cookie; 2558 item->next = NULL; 2559 2560 sal_spinlock_lock(_xgs3_async_queue_lock); 2561 2562 if (_xgs3_async_head == NULL) { 2563 _xgs3_async_head = item; 2564 } else { 2565 _xgs3_async_tail->next = item; 2566 } 2567 _xgs3_async_tail = item; 2568 2569 sal_spinlock_unlock(_xgs3_async_queue_lock); 2570 2571 sal_sem_give(_xgs3_async_tx_sem); 2572 return BCM_E_NONE; 2573 } 2574 2575 STATIC int 2576 _xgs3_async_queue_fetch(int * unit, bcm_pkt_t ** pkt, void ** cookie) 2577 { 2578 _xgs3_async_queue_t * item; 2579 2580 if (sal_sem_take(_xgs3_async_tx_sem, sal_sem_FOREVER) < 0) { 2581 LOG_ERROR(BSL_LS_BCM_TX, 2582 (BSL_META("async fetch: Can't take async TX semaphore\n"))); 2583 return BCM_E_RESOURCE; 2584 } 2585 2586 sal_spinlock_lock(_xgs3_async_queue_lock); 2587 2588 item = _xgs3_async_head; 2589 _xgs3_async_head = item->next; 2590 if (_xgs3_async_head == NULL) { 2591 _xgs3_async_tail = NULL; 2592 } 2593 2594 sal_spinlock_unlock(_xgs3_async_queue_lock); 2595 2596 *unit = item->unit; 2597 *pkt = item->pkt; 2598 *cookie = item->cookie; 2599 sal_free(item); 2600 2601 return BCM_E_NONE; 2602 } 2603 2604 typedef struct _xgs3_tx_cb_cookie_s { 2605 bcm_pkt_t *orig_pkt; 2606 2607 void *orig_cookie; 2608 void *cleanup_mem; 2609 } _xgs3_tx_cb_cookie_t; 2610 2611 void _xgs3_tx_cb(int unit, bcm_pkt_t *pkt, void *cookie) 2612 { 2613 _xgs3_tx_cb_cookie_t *mycookie = cookie; 2614 2615 if (mycookie->orig_pkt->call_back != NULL) { 2616 (mycookie->orig_pkt->call_back)(unit, mycookie->orig_pkt, mycookie->orig_cookie); 2617 } 2618 2619 if(mycookie->cleanup_mem != NULL) { 2620 sal_free(mycookie->cleanup_mem); 2621 } 2622 2623 sal_free (cookie); 2624 2625 return; 2626 } 2627 2628 #ifdef BCM_SHADOW_SUPPORT 2629 STATIC int 2630 _shadow_tx(int unit, bcm_pkt_t *pkt, void *cookie) 2631 { 2632 /* int pkt_cnt; */ 2633 int port; 2634 2635 int rv = BCM_E_NONE; 2636 bcm_pkt_t *packet_p; 2637 bcm_pkt_t packet; 2638 /* _xgs3_tx_cb_cookie_t *_xgs3_tx_cb_cookie; */ 2639 2640 packet_p = &packet; 2641 2642 BCM_PBMP_ITER(pkt->tx_pbmp, port) 2643 { 2644 sal_memcpy(packet_p, pkt, sizeof(bcm_pkt_t)); 2645 2646 /* Set port control */ 2647 soc_reg_field32_modify(unit, UFLOW_PORT_CONTROLr, 0, 2648 DEST_PORTf, port); 2649 2650 BCM_PBMP_PORT_SET(packet_p->tx_pbmp, port); 2651 BCM_PBMP_PORT_SET(packet_p->tx_upbmp, port); 2652 BCM_PBMP_AND(packet_p->tx_upbmp, pkt->tx_upbmp); 2653 2654 BCM_PBMP_CLEAR(packet_p->tx_l3pbmp); 2655 2656 /* Check untag membership before translating */ 2657 if (PBMP_MEMBER(pkt->tx_upbmp, port)) { 2658 packet_p->flags |= BCM_PKT_F_TX_UNTAG; 2659 } else { 2660 packet_p->flags &= (~BCM_PKT_F_TX_UNTAG); 2661 } 2662 2663 packet_p->call_back = NULL; /* Synchronus send */ 2664 2665 rv = _bcm_tx(unit, packet_p, cookie); 2666 2667 /* Revert back port control */ 2668 soc_reg_field32_modify(unit, UFLOW_PORT_CONTROLr, 0, 2669 DEST_PORTf, 0); 2670 } 2671 return rv; 2672 } 2673 #endif /* BCM_SHADOW_SUPPORT */ 2674 2675 STATIC int 2676 _xgs3_tx(int unit, bcm_pkt_t *pkt, void *cookie) 2677 { 2678 int pkt_cnt; 2679 int port; 2680 2681 int rv; 2682 bcm_pkt_t *packets_p; 2683 bcm_pkt_t *packet_p; 2684 bcm_pkt_t **packet_pointers_p; 2685 bcm_pkt_t **packet_pointer_p; 2686 _xgs3_tx_cb_cookie_t *_xgs3_tx_cb_cookie; 2687 2688 BCM_PBMP_COUNT(pkt->tx_pbmp, pkt_cnt); 2689 2690 /* Create an array of packets, one per port */ 2691 2692 packets_p = sal_alloc(pkt_cnt * sizeof(bcm_pkt_t), "Packet copies"); 2693 2694 if (packets_p == NULL) { 2695 return BCM_E_MEMORY; 2696 } 2697 2698 packet_pointers_p = sal_alloc(pkt_cnt * sizeof(bcm_pkt_t *), 2699 "Packet pointers"); 2700 2701 if (packet_pointers_p == NULL) { 2702 sal_free(packets_p); 2703 return BCM_E_MEMORY; 2704 } 2705 2706 packet_p = packets_p; 2707 packet_pointer_p = packet_pointers_p; 2708 2709 BCM_PBMP_ITER(pkt->tx_pbmp, port) 2710 { 2711 sal_memcpy(packet_p, pkt, sizeof(bcm_pkt_t)); 2712 2713 BCM_PBMP_PORT_SET(packet_p->tx_pbmp, port); 2714 2715 BCM_PBMP_PORT_SET(packet_p->tx_upbmp, port); 2716 BCM_PBMP_AND(packet_p->tx_upbmp, pkt->tx_upbmp); 2717 2718 BCM_PBMP_CLEAR(packet_p->tx_l3pbmp); 2719 2720 packet_p->call_back = NULL; /* We don't need individual Callbacks for each packet */ 2721 2722 *packet_pointer_p = packet_p; 2723 2724 ++packet_p; 2725 ++packet_pointer_p; 2726 } 2727 2728 if (NULL != pkt->call_back) { 2729 _xgs3_tx_cb_cookie = sal_alloc(sizeof(_xgs3_tx_cb_cookie_t), "Callback Cookie"); 2730 if (_xgs3_tx_cb_cookie == NULL) { 2731 sal_free(packet_pointers_p); 2732 sal_free(packets_p); 2733 return BCM_E_MEMORY; 2734 } 2735 _xgs3_tx_cb_cookie->orig_pkt = pkt; 2736 _xgs3_tx_cb_cookie->orig_cookie = cookie; 2737 _xgs3_tx_cb_cookie->cleanup_mem = packets_p; 2738 #ifdef BCM_TRIDENT3_SUPPORT 2739 if (SOC_IS_TRIDENT3X(unit) && 2740 soc_feature(unit, soc_feature_higig_over_ethernet)) { 2741 rv = bcm_td3_tx_hgoe_array(unit, packet_pointers_p, pkt_cnt, 2742 &_xgs3_tx_cb, _xgs3_tx_cb_cookie); 2743 } else 2744 #endif 2745 { 2746 rv = bcm_common_tx_array(unit, packet_pointers_p, pkt_cnt, &_xgs3_tx_cb, 2747 _xgs3_tx_cb_cookie); 2748 } 2749 sal_free(packet_pointers_p); 2750 /* packets_p and _xgs3_tx_cb_cookie will be freed by _xgs3_tx_cb */ 2751 2752 } else { 2753 #ifdef BCM_TRIDENT3_SUPPORT 2754 if (SOC_IS_TRIDENT3X(unit) && 2755 soc_feature(unit, soc_feature_higig_over_ethernet)) { 2756 rv = bcm_td3_tx_hgoe_array(unit, packet_pointers_p, 2757 pkt_cnt, NULL, NULL); 2758 } else 2759 #endif 2760 { 2761 rv = bcm_common_tx_array(unit, packet_pointers_p, pkt_cnt, NULL, NULL); 2762 } 2763 sal_free(packet_pointers_p); 2764 sal_free(packets_p); 2765 } 2766 2767 return rv; 2768 } 2769 2770 STATIC void 2771 _xgs3_async_thread(void * param) 2772 { 2773 int unit = 0; 2774 bcm_pkt_t * pkt; 2775 void * cookie; 2776 int rv; 2777 char thread_name[SAL_THREAD_NAME_MAX_LEN]; 2778 sal_thread_t thread; 2779 2780 COMPILER_REFERENCE(param); 2781 2782 while(1) { 2783 if ((rv = _xgs3_async_queue_fetch(&unit, &pkt, &cookie)) < 0) { 2784 LOG_ERROR(BSL_LS_BCM_TX, 2785 (BSL_META_U(unit, 2786 "Async TX: fetch: %s\n"), bcm_errmsg(rv))); 2787 break; 2788 } 2789 if ((rv = _xgs3_tx(unit, pkt, cookie)) < 0) { 2790 LOG_ERROR(BSL_LS_BCM_TX, 2791 (BSL_META_U(unit, 2792 "Async TX: tx: %s\n"), bcm_errmsg(rv))); 2793 break; 2794 } 2795 } 2796 2797 thread = sal_thread_self(); 2798 thread_name[0] = 0; 2799 sal_thread_name(thread, thread_name, sizeof (thread_name)); 2800 LOG_ERROR(BSL_LS_BCM_TX, 2801 (BSL_META_U(unit, 2802 "AbnormalThreadExit:%s\n"), thread_name)); 2803 sal_thread_exit(0); 2804 } 2805 #endif 2806 2807 #if defined(BCM_TRIDENT2PLUS_SUPPORT) && defined(BCM_TX_HGOE_LIMITED_SOLUTION) 2808 typedef struct bcm_tx_hgoe_cookie_s { 2809 bcm_pkt_cb_f chain_cb; 2810 bcm_pkt_cb_f pkt_cb; 2811 bcm_pkt_t *org_pkt; 2812 void *org_cookie; 2813 uint32 org_pkt_flags; 2814 bcm_pkt_blk_t *org_pkt_blk_addr; 2815 bcm_pkt_blk_t *new_pkt_blk_addr; 2816 } bcm_tx_hgoe_cookie_t; 2817 2818 typedef struct bcm_tx_hgoe_chain_cb_cookie_s { 2819 bcm_pkt_cb_f user_given_chain_cb; 2820 void *user_given_cookie; 2821 uint32 pkt_cnt; 2822 bcm_tx_hgoe_cookie_t *pkt_cookie_arr; 2823 } bcm_tx_hgoe_chain_cb_cookie_t; 2824 2825 STATIC void 2826 bcm_common_tx_hgoe_pkt_cb(int unit, bcm_pkt_t *pkt, void *cookie) { 2827 bcm_tx_hgoe_cookie_t *my_cookie = (bcm_tx_hgoe_cookie_t *)cookie; 2828 2829 if (my_cookie) { 2830 2831 if (my_cookie->pkt_cb || !my_cookie->chain_cb) { 2832 /* Revert the changes done to the original pkt blk data */ 2833 pkt->pkt_data = my_cookie->org_pkt_blk_addr; 2834 pkt->blk_count--; 2835 pkt->flags |= 2836 (my_cookie->org_pkt_flags & (BCM_TX_ETHER | BCM_TX_HG_READY)); 2837 pkt->call_back = my_cookie->pkt_cb; 2838 BCM_TX_HGOE_DBG_CTR_SEM_INCR(pkt_blk_rvt_cnt) 2839 } 2840 2841 if (my_cookie->pkt_cb) { 2842 /* Now call the org call back*/ 2843 my_cookie->pkt_cb(unit, pkt, my_cookie->org_cookie); 2844 } 2845 2846 /* If chain cb is not defined then release the pkt blk related 2847 * memories, otherwise let chain_cb take care of releasing them. 2848 */ 2849 if (!my_cookie->chain_cb) { 2850 if (my_cookie->new_pkt_blk_addr) { 2851 if (my_cookie->new_pkt_blk_addr->data) { 2852 sal_dma_free(my_cookie->new_pkt_blk_addr->data); 2853 BCM_TX_HGOE_DBG_CTR_SEM_INCR(dma_free_cnt) 2854 } 2855 sal_free(my_cookie->new_pkt_blk_addr); 2856 BCM_TX_HGOE_DBG_CTR_SEM_INCR(blk_free_cnt) 2857 } 2858 sal_free(my_cookie); 2859 BCM_TX_HGOE_DBG_CTR_SEM_INCR(ck_free_cnt) 2860 } 2861 } 2862 } 2863 2864 STATIC void * 2865 _bcm_common_tx_hgoe_cb_cookie_set(bcm_pkt_t *pkt, 2866 bcm_pkt_cb_f chain_cb, 2867 void *org_cookie, 2868 uint32 org_flags, 2869 bcm_pkt_blk_t *org_blk_addr) { 2870 2871 if (pkt->call_back || chain_cb) { 2872 2873 bcm_tx_hgoe_cookie_t *cookie = sal_alloc(sizeof(*cookie), "hgoecookie"); 2874 2875 if (cookie) { 2876 sal_memset(cookie, 0, sizeof(bcm_tx_hgoe_cookie_t)); 2877 cookie->pkt_cb = pkt->call_back; 2878 cookie->chain_cb = chain_cb; 2879 cookie->org_pkt = pkt; 2880 cookie->org_cookie = org_cookie; 2881 cookie->org_pkt_flags = org_flags; 2882 cookie->org_pkt_blk_addr = org_blk_addr; 2883 cookie->new_pkt_blk_addr = pkt->pkt_data; 2884 pkt->call_back = pkt->call_back ? bcm_common_tx_hgoe_pkt_cb : NULL; 2885 BCM_TX_HGOE_DBG_CTR_SEM_INCR(ck_alloc_cnt) 2886 } 2887 return (void *)cookie; 2888 } 2889 else 2890 return org_cookie; 2891 } 2892 2893 STATIC void 2894 _bcm_common_tx_hgoe_manual_cleanup(bcm_pkt_t *pkt, 2895 uint32 org_flags, bcm_pkt_blk_t *org_blk_addr, bcm_pkt_cb_f org_pkt_cb) { 2896 2897 BCM_TX_HGOE_DBG_CTR_SEM_ACQ 2898 2899 if (pkt->pkt_data) { 2900 if (pkt->pkt_data[0].data) { 2901 sal_dma_free(pkt->pkt_data[0].data); 2902 BCM_TX_HGOE_DBG_CTR_INCR(dma_free_cnt) 2903 } 2904 sal_free(pkt->pkt_data); 2905 BCM_TX_HGOE_DBG_CTR_INCR(blk_free_cnt) 2906 } 2907 pkt->pkt_data = org_blk_addr; 2908 pkt->flags |= (org_flags & (BCM_TX_ETHER | BCM_TX_HG_READY)); 2909 pkt->blk_count--; 2910 pkt->call_back = org_pkt_cb; 2911 BCM_TX_HGOE_DBG_CTR_INCR(pkt_blk_rvt_cnt) 2912 2913 BCM_TX_HGOE_DBG_CTR_SEM_REL 2914 return; 2915 } 2916 2917 STATIC void 2918 bcm_common_tx_hgoe_tx_chain_cb(int unit, bcm_pkt_t *pkt, void *cookie) { 2919 uint32 pkt_idx; 2920 bcm_tx_hgoe_cookie_t *per_pkt_info = NULL; 2921 bcm_tx_hgoe_chain_cb_cookie_t *my_cookie = 2922 (bcm_tx_hgoe_chain_cb_cookie_t *) cookie; 2923 2924 if (my_cookie) { 2925 per_pkt_info = my_cookie->pkt_cookie_arr; 2926 if (per_pkt_info) { 2927 /* Revert the pkt data blk changes for eack packet in the chain */ 2928 for (pkt_idx=0 ; pkt_idx<my_cookie->pkt_cnt ; pkt_idx++) { 2929 if (per_pkt_info[pkt_idx].chain_cb) { 2930 _bcm_common_tx_hgoe_manual_cleanup( 2931 per_pkt_info[pkt_idx].org_pkt, 2932 per_pkt_info[pkt_idx].org_pkt_flags, 2933 per_pkt_info[pkt_idx].org_pkt_blk_addr, 2934 per_pkt_info[pkt_idx].pkt_cb); 2935 } 2936 } 2937 2938 /* Call any user given pkt cb for eack packet */ 2939 for (pkt_idx=0 ; pkt_idx<my_cookie->pkt_cnt ; pkt_idx++) { 2940 if (per_pkt_info[pkt_idx].pkt_cb) { 2941 (per_pkt_info[pkt_idx].pkt_cb)(unit, 2942 per_pkt_info[pkt_idx].org_pkt, 2943 per_pkt_info[pkt_idx].org_cookie); 2944 } 2945 } 2946 2947 /* Remove the per packet info/cookie */ 2948 sal_free(per_pkt_info); 2949 BCM_TX_HGOE_DBG_CTR_SEM_DECR(tx_list_pkt_ck_arr_cnt) 2950 } 2951 2952 /* Call user given chain cb, if any */ 2953 if (my_cookie->user_given_chain_cb) { 2954 my_cookie->user_given_chain_cb(unit, pkt, 2955 my_cookie->user_given_cookie); 2956 } 2957 2958 /* Remove the master cookie */ 2959 sal_free(my_cookie); 2960 BCM_TX_HGOE_DBG_CTR_SEM_DECR(tx_list_master_ck_cnt) 2961 } 2962 return; 2963 } 2964 2965 STATIC int 2966 _bcm_common_tx_hgoe_prepare_pkt(int unit, 2967 bcm_pkt_t *pkt, 2968 uint32 *org_flags, 2969 bcm_pkt_blk_t **org_blk_start, 2970 bcm_port_encap_config_t encap_cfg) { 2971 int rv = BCM_E_NONE; 2972 int blk_idx = 0; 2973 uint8 vlan_adj = 0; 2974 bcm_pkt_blk_t *tmpPktBlkArr = NULL; 2975 uint8 *dma_buffer = NULL; 2976 uint16 htons_val = 0; 2977 2978 if (!pkt || !org_blk_start || !org_flags) { 2979 BCM_TX_HGOE_DBG_CTR_INCR(internal_fail_cnt) 2980 return(BCM_E_PARAM); 2981 } 2982 2983 /* Re-Adjust the size for VLAN tag */ 2984 if (!BCM_PKT_NO_VLAN_TAG(pkt)) { 2985 vlan_adj = 4; 2986 } 2987 2988 /* Blk 0 should have DMAC, SMAC and VLAN (if VLAN tag exists) */ 2989 if (pkt->pkt_data[0].len < (12 + vlan_adj)) { 2990 BCM_TX_HGOE_DBG_CTR_INCR(internal_fail_cnt) 2991 return (BCM_E_FAIL); 2992 } 2993 2994 /* Create a HG2 hdr if not provided */ 2995 if( SOC_HIGIG2_START != *BCM_PKT_HG_HDR(pkt) ) { 2996 rv = _bcm_tx_pkt_tag_setup(unit, pkt); 2997 2998 /* If HG Hdr build fails then bail out as HGoE requires the HG Hdr. */ 2999 if (BCM_FAILURE(rv)) { 3000 BCM_TX_HGOE_DBG_CTR_INCR(internal_fail_cnt) 3001 return rv; 3002 } 3003 3004 /* If HG Hdr was not built return back error. */ 3005 if (SOC_HIGIG2_START != *BCM_PKT_HG_HDR(pkt)) { 3006 BCM_TX_HGOE_DBG_CTR_INCR(internal_fail_cnt) 3007 return (BCM_E_FAIL); 3008 } 3009 } 3010 3011 /* Create a dma'able block of memory */ 3012 dma_buffer = sal_dma_alloc(32, "HGoEHdrs"); 3013 if (!dma_buffer) { 3014 BCM_TX_HGOE_DBG_CTR_INCR(internal_fail_cnt) 3015 return BCM_E_MEMORY; 3016 } 3017 3018 /* Create a pkt data block */ 3019 tmpPktBlkArr = 3020 sal_alloc(sizeof(bcm_pkt_blk_t) * (pkt->blk_count + 1), "HGoEBlks"); 3021 if (!tmpPktBlkArr) { 3022 BCM_TX_HGOE_DBG_CTR_INCR(internal_fail_cnt) 3023 sal_dma_free(dma_buffer); 3024 return BCM_E_MEMORY; 3025 } 3026 3027 /* Fill in the block details */ 3028 tmpPktBlkArr[0].data = dma_buffer; 3029 tmpPktBlkArr[0].len = 32; 3030 for (blk_idx=0 ; blk_idx<pkt->blk_count ; blk_idx++ ) { 3031 tmpPktBlkArr[blk_idx+1] = pkt->pkt_data[blk_idx]; 3032 } 3033 3034 /* Create and copy 16 byte HGoE HDR */ 3035 sal_memcpy(dma_buffer, pkt->pkt_data[0].data, 12); 3036 htons_val = bcm_htons(encap_cfg.higig_ethertype); 3037 sal_memcpy(dma_buffer + 12, &htons_val, 2); 3038 htons_val = bcm_htons(encap_cfg.hgoe_reserved); 3039 sal_memcpy(dma_buffer + 14, &htons_val, 2); 3040 3041 /* Copy 16 byte HG2 HDR */ 3042 sal_memcpy(dma_buffer + 16, BCM_PKT_HG_HDR(pkt), 16); 3043 /* Rewrite the SOP as HGoE requires the SOP to be 0xFB */ 3044 dma_buffer[16] = SOC_HIGIG_START; 3045 3046 /* Keep hold of the start of the org blk address */ 3047 *org_blk_start = pkt->pkt_data; 3048 3049 /* Replace the block list with new blk list */ 3050 pkt->pkt_data = tmpPktBlkArr; 3051 pkt->blk_count++; 3052 3053 /* Readjust the len of org payload as SMAC/DMAC are already in HGoE Hdr */ 3054 tmpPktBlkArr[1].len -= (12 + vlan_adj); 3055 tmpPktBlkArr[1].data += (12 + vlan_adj); 3056 3057 BCM_TX_HGOE_DBG_CTR_SEM_ACQ 3058 BCM_TX_HGOE_DBG_CTR_INCR(dma_alloc_cnt) 3059 BCM_TX_HGOE_DBG_CTR_INCR(blk_alloc_cnt) 3060 BCM_TX_HGOE_DBG_CTR_INCR(pkt_blk_chg_cnt) 3061 BCM_TX_HGOE_DBG_CTR_SEM_REL 3062 3063 /* Store the org flags */ 3064 *org_flags = pkt->flags; 3065 3066 /* Mark the packet as SoBMH */ 3067 pkt->flags &= ~BCM_TX_ETHER; 3068 pkt->flags &= ~BCM_TX_HG_READY; 3069 3070 return rv; 3071 } 3072 #endif /* BCM_TRIDENT2PLUS_SUPPORT && BCM_TX_HGOE_LIMITED_SOLUTION */ 3073 3074 /* 3075 * Function: 3076 * bcm_tx 3077 * Purpose: 3078 * Wrapper for _bcm_tx to work around a lack of XGS3 support for 3079 * transmitting to a bitmap. 3080 * Parameters: 3081 * unit - transmission unit 3082 * pkt - The tx packet structure 3083 * cookie - Callback cookie when tx done 3084 * Returns: 3085 * BCM_E_XXX 3086 * Notes: 3087 * XGS3 devices cannot dispatch packets to multiple ports. To emulate this 3088 * functionality, bcm_tx iterates over the requested bitmaps. The callback, 3089 * if applicable, shall be called only once. 3090 */ 3091 3092 int 3093 bcm_common_tx(int unit, bcm_pkt_t *pkt, void *cookie) 3094 { 3095 int rv = BCM_E_NONE; 3096 #if defined(BCM_TRIDENT2PLUS_SUPPORT) && defined(BCM_TX_HGOE_LIMITED_SOLUTION) 3097 void *my_cookie = NULL; 3098 bcm_port_t tx_port = 0; 3099 uint32 org_pkt_flags = 0; 3100 bcm_pkt_cb_f pkt_org_cb = NULL; 3101 bcm_pkt_blk_t *org_pkt_blk_addr = NULL; 3102 bcm_port_encap_config_t encap_cfg = {0}; 3103 #endif /* BCM_TRIDENT2PLUS_SUPPORT && BCM_TX_HGOE_LIMITED_SOLUTION */ 3104 3105 #ifdef BCM_SHADOW_SUPPORT 3106 if (BCM_IS_LOCAL(unit) && SOC_IS_SHADOW(unit)) { 3107 /* In BCM88732 device the packets tx is handled differntly than an XGS 3108 * device, although there are many similarites hence most of the code 3109 * is reused. 3110 */ 3111 _shadow_tx(unit, pkt, cookie); 3112 } else 3113 #endif 3114 #ifdef BCM_XGS3_SWITCH_SUPPORT 3115 if (BCM_IS_LOCAL(unit) && SOC_IS_XGS3_SWITCH(unit)) { 3116 int pkt_cnt; 3117 BCM_PBMP_COUNT(pkt->tx_pbmp, pkt_cnt); 3118 if ((pkt_cnt <= 1) || (BCM_PKT_TX_ETHER(pkt))) { 3119 #if defined(BCM_TRIDENT3_SUPPORT) 3120 if (SOC_IS_TRIDENT3X(unit) && 3121 soc_feature(unit, soc_feature_higig_over_ethernet)) { 3122 if (1 == pkt_cnt && !BCM_PKT_TX_ETHER(pkt)) { 3123 bcm_port_t tmp_port = 0; 3124 bcm_port_encap_config_t encap_config = {0}; 3125 BCM_PBMP_ITER(pkt->tx_pbmp, tmp_port) { 3126 rv = bcm_port_encap_config_get(unit, tmp_port, &encap_config); 3127 if (!BCM_FAILURE(rv) 3128 && encap_config.encap == BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET) { 3129 /* Tx a HGOE packet */ 3130 rv = bcm_td3_tx_hgoe_pkt(unit, pkt, &encap_config, cookie, _bcm_tx); 3131 } else if (!BCM_FAILURE(rv)) { 3132 /* Tx a normal packet */ 3133 rv = _bcm_tx(unit, pkt, cookie); 3134 } 3135 /* End the port iteration as only 1 TX prt */ 3136 break; 3137 } 3138 } else { 3139 rv = _bcm_tx(unit, pkt, cookie); 3140 } 3141 return rv; 3142 } 3143 #endif 3144 #if defined(BCM_TRIDENT2PLUS_SUPPORT) && defined(BCM_TX_HGOE_LIMITED_SOLUTION) 3145 /* Check for TD2P and other limitations */ 3146 if (SOC_IS_TRIDENT2PLUS(unit) 3147 && 1==pkt_cnt && !BCM_PKT_TX_ETHER(pkt)) { 3148 3149 /* Iterate through given pbmp to find the one TX port */ 3150 BCM_PBMP_ITER(pkt->tx_pbmp, tx_port) 3151 { 3152 rv = bcm_port_encap_config_get(unit, tx_port, &encap_cfg); 3153 3154 /* If the tx port is HGoE then go through the trouble of 3155 * forming a sobmh pkt otherwise just use the default way 3156 */ 3157 if (!BCM_FAILURE(rv) 3158 && encap_cfg.encap==BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET) { 3159 3160 /* Prepare the packet */ 3161 rv = 3162 _bcm_common_tx_hgoe_prepare_pkt(unit, pkt, 3163 &org_pkt_flags, &org_pkt_blk_addr, encap_cfg); 3164 3165 /* Sanity check for copied data length */ 3166 if (!BCM_FAILURE(rv)) { 3167 pkt_org_cb = pkt->call_back; 3168 3169 /* cookie setup*/ 3170 my_cookie = 3171 _bcm_common_tx_hgoe_cb_cookie_set(pkt, NULL, 3172 cookie, org_pkt_flags, org_pkt_blk_addr); 3173 3174 /* Send the pkt if the cookie creation succeeded */ 3175 if (my_cookie || !pkt_org_cb) { 3176 rv = _bcm_tx(unit, pkt, my_cookie); 3177 } else { /* cookie alloc err */ 3178 BCM_TX_HGOE_DBG_CTR_INCR(internal_fail_cnt) 3179 rv = BCM_E_MEMORY; 3180 } 3181 3182 /* Cookie cleanup in an event of failure */ 3183 if (BCM_FAILURE(rv) 3184 && my_cookie && cookie!=my_cookie) { 3185 sal_free(my_cookie); 3186 BCM_TX_HGOE_DBG_CTR_SEM_INCR(ck_free_cnt) 3187 } 3188 3189 /* Pkt cleanup if no callback or failure to send */ 3190 if (BCM_FAILURE(rv) || !pkt_org_cb) { 3191 _bcm_common_tx_hgoe_manual_cleanup(pkt, 3192 org_pkt_flags, 3193 org_pkt_blk_addr, 3194 pkt_org_cb); 3195 } 3196 } 3197 } else { /* Dest. port is not HGoE default to the old way */ 3198 rv= _bcm_tx(unit, pkt, cookie); 3199 } 3200 3201 /* End the port iteration as only 1 TX prt */ 3202 break; 3203 } /* Loop on the tx port bitmap */ 3204 } else { /* NonTD2P or limitations not satisfied use the old way */ 3205 rv= _bcm_tx(unit, pkt, cookie); 3206 } 3207 3208 return rv; 3209 #else 3210 return _bcm_tx(unit, pkt, cookie); 3211 #endif /* BCM_TRIDENT2PLUS_SUPPORT && BCM_TX_HGOE_LIMITED_SOLUTION */ 3212 } else if (pkt->call_back == NULL) { 3213 return _xgs3_tx(unit, pkt, cookie); 3214 } else { 3215 return _xgs3_async_tx(unit, pkt, cookie); 3216 } 3217 } else 3218 #endif 3219 { 3220 rv = _bcm_tx(unit, pkt, cookie); 3221 } 3222 return rv; 3223 } 3224 3225 /* 3226 * Function: 3227 * bcm_tx_array 3228 * Purpose: 3229 * Transmit an array of packets 3230 * Parameters: 3231 * unit - transmission unit 3232 * pkt - array of pointers to packets to transmit 3233 * count - Number of packets in list 3234 * all_done_cb - Callback function (if non-NULL) when all pkts tx'd 3235 * cookie - Callback cookie. 3236 * Returns: 3237 * BCM_E_XXX 3238 * Notes: 3239 * If all_done_cb is non-NULL, the packets are sent asynchronously 3240 * (the routine returns before all the pkts are sent) 3241 * 3242 * The "packet callback" will be set according to the value 3243 * in each packet's "call_back" member, so that must be initialized 3244 * for all packets in the chain. 3245 * 3246 * If any packet requires a callback, the packet-done callback is 3247 * enabled for all packets in the chain. 3248 * 3249 * This routine does not support tunnelling to a remote CPU for 3250 * forwarding. 3251 * 3252 * CURRENTLY: The TX parameters, src mod, src port, PFM 3253 * and internal priority, are determined by the first packet in 3254 * the array. This may change to break the array into subchains 3255 * when differences are detected. 3256 */ 3257 3258 #if defined(BCM_TRIDENT2PLUS_SUPPORT) && defined(BCM_TX_HGOE_LIMITED_SOLUTION) 3259 STATIC int 3260 _bcm_common_tx_array(int unit, bcm_pkt_t **pkt, int count, 3261 bcm_pkt_cb_f all_done_cb, void *cookie); 3262 int 3263 bcm_common_tx_array(int unit, bcm_pkt_t **pkt_arr, int count, 3264 bcm_pkt_cb_f all_done_cb, void *cookie) 3265 { 3266 int rv = BCM_E_NONE; 3267 int port_cnt = 0; 3268 bcm_pbmp_t pbmp; 3269 uint32 pkt_idx = 0; 3270 uint32 prt_idx = 0; 3271 uint8 is_pkt_cb = 0; 3272 bcm_port_t tx_port = 0; 3273 uint32 org_pkt_flags = 0; 3274 uint8 use_dflt_method = 1; 3275 bcm_pkt_t *cur_pkt = NULL; 3276 bcm_pkt_blk_t *org_pkt_blk_addr = NULL; 3277 bcm_port_encap_config_t encapcfg = {0}; 3278 bcm_tx_hgoe_cookie_t *pkt_info_arr = NULL; 3279 bcm_tx_hgoe_chain_cb_cookie_t *master_cookie = NULL; 3280 typedef struct { 3281 bcm_port_t port; 3282 uint16 ether_type; 3283 uint16 hgoe_rsvd; 3284 } hgoe_port_info_t; 3285 hgoe_port_info_t *port_info_arr = NULL; 3286 3287 /* Input paramter check */ 3288 if (!pkt_arr) { 3289 return BCM_E_PARAM; 3290 } 3291 3292 if (count<1 || !*pkt_arr) { 3293 return BCM_E_PARAM; 3294 } 3295 3296 if (!BCM_UNIT_VALID(unit)) { 3297 return BCM_E_UNIT; 3298 } 3299 3300 if (!SOC_UNIT_VALID(unit)) { 3301 return BCM_E_UNIT; 3302 } 3303 3304 if (!BCM_IS_LOCAL(unit)) { /* Tunnel the packet to the remote CPU */ 3305 LOG_ERROR(BSL_LS_BCM_TX, 3306 (BSL_META_U(unit, 3307 "bcm_tx_array ERROR: Cannot tunnel\n"))); 3308 return BCM_E_PARAM; 3309 } 3310 3311 if (SOC_IS_TRIDENT2PLUS(unit)) { 3312 BCM_PBMP_CLEAR(pbmp); 3313 /* Do fast check if the HGoE logic can be invoked or not */ 3314 for ( pkt_idx=0 ; pkt_idx<count ; pkt_idx++) { 3315 3316 /* Get hold of the current packet */ 3317 cur_pkt = pkt_arr[pkt_idx]; 3318 3319 /* If even a single pkt is smart switched then go default route */ 3320 if (BCM_PKT_TX_ETHER(cur_pkt)) { 3321 break; 3322 } 3323 3324 /* If pkt has to be sent on multiple ports then go default route */ 3325 BCM_PBMP_COUNT(cur_pkt->tx_pbmp, port_cnt); 3326 if (1!=port_cnt) { 3327 break; 3328 } 3329 3330 BCM_PBMP_OR(pbmp, cur_pkt->tx_pbmp); 3331 3332 /* Mark if individual pkt call back exists. */ 3333 if (!is_pkt_cb && cur_pkt->call_back) { 3334 is_pkt_cb = 1; 3335 } 3336 } 3337 3338 /* If previous loop did not complete successfully or there is a case 3339 * where individual pkt callback esists but chain done callback not then 3340 * the HGoE logic cannot be invoked as it wont handle the said scenario. 3341 * Hence send the pkt using default way and hope TX happens successfully 3342 */ 3343 if ((pkt_idx >= count) && !(is_pkt_cb && !all_done_cb) ) { 3344 use_dflt_method = 0; 3345 } 3346 } 3347 3348 if (use_dflt_method) { 3349 return(_bcm_common_tx_array(unit, pkt_arr, count, all_done_cb, cookie)); 3350 } 3351 3352 /*** Check for port encapsulation type ***/ 3353 /* Create a buffer to hold HGoE tag to be used later */ 3354 BCM_PBMP_COUNT(pbmp, port_cnt); 3355 port_info_arr=sal_alloc(sizeof(hgoe_port_info_t) * port_cnt, "HGoEPrtInfo"); 3356 if (!port_info_arr) { 3357 BCM_TX_HGOE_DBG_CTR_INCR(internal_fail_cnt) 3358 return (BCM_E_MEMORY); 3359 } 3360 BCM_TX_HGOE_DBG_CTR_SEM_INCR(tx_list_port_info_cnt) 3361 3362 /* If all tx ports are HGoE then go through the trouble of 3363 * forming a sobmh pkt otherwise just use the default way 3364 */ 3365 prt_idx = 0; 3366 rv = BCM_E_NONE; 3367 BCM_PBMP_ITER(pbmp, tx_port) 3368 { 3369 if (prt_idx >= port_cnt) { 3370 BCM_TX_HGOE_DBG_CTR_INCR(internal_fail_cnt) 3371 rv = BCM_E_FAIL; 3372 break; 3373 } 3374 3375 rv = bcm_port_encap_config_get(unit, tx_port, &encapcfg); 3376 3377 if (BCM_FAILURE(rv) 3378 || (encapcfg.encap != BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET)) { 3379 rv = BCM_E_FAIL; 3380 break; 3381 } else { 3382 port_info_arr[prt_idx].port = tx_port; 3383 port_info_arr[prt_idx].ether_type = encapcfg.higig_ethertype; 3384 port_info_arr[prt_idx++].hgoe_rsvd = encapcfg.hgoe_reserved; 3385 } 3386 } 3387 3388 if (BCM_FAILURE(rv)) { 3389 /* Error in getting the port encap. info or port is non HGoE */ 3390 sal_free(port_info_arr); 3391 BCM_TX_HGOE_DBG_CTR_SEM_DECR(tx_list_port_info_cnt) 3392 return(_bcm_common_tx_array(unit, pkt_arr, count, all_done_cb, cookie)); 3393 } 3394 3395 /*** Past this point the pkt tx has to go through HGoE logic ***/ 3396 3397 /* Allocate memory to hold per pkt cookie */ 3398 pkt_info_arr = 3399 sal_alloc(sizeof(bcm_tx_hgoe_cookie_t)*count, "PerPktCkArr"); 3400 if (!pkt_info_arr) { 3401 BCM_TX_HGOE_DBG_CTR_INCR(internal_fail_cnt) 3402 sal_free(port_info_arr); 3403 BCM_TX_HGOE_DBG_CTR_SEM_DECR(tx_list_port_info_cnt) 3404 return (BCM_E_MEMORY); 3405 } 3406 BCM_TX_HGOE_DBG_CTR_SEM_INCR(tx_list_pkt_ck_arr_cnt) 3407 3408 /* Allocate memory for master cookie */ 3409 master_cookie = 3410 sal_alloc(sizeof(bcm_tx_hgoe_chain_cb_cookie_t), "ChainCBCk"); 3411 if (!master_cookie) { 3412 BCM_TX_HGOE_DBG_CTR_INCR(internal_fail_cnt) 3413 sal_free(port_info_arr); 3414 sal_free(pkt_info_arr); 3415 BCM_TX_HGOE_DBG_CTR_SEM_ACQ 3416 BCM_TX_HGOE_DBG_CTR_DECR(tx_list_pkt_ck_arr_cnt) 3417 BCM_TX_HGOE_DBG_CTR_DECR(tx_list_port_info_cnt) 3418 BCM_TX_HGOE_DBG_CTR_SEM_REL 3419 return (BCM_E_MEMORY); 3420 } 3421 BCM_TX_HGOE_DBG_CTR_SEM_INCR(tx_list_master_ck_cnt) 3422 3423 /* Fill in master cookie */ 3424 master_cookie->pkt_cnt = count; 3425 master_cookie->user_given_chain_cb = all_done_cb; 3426 master_cookie->user_given_cookie = cookie; 3427 master_cookie->pkt_cookie_arr = pkt_info_arr; 3428 3429 /* Initialize the per pkt cookie arr */ 3430 sal_memset(pkt_info_arr, 0, sizeof(bcm_tx_hgoe_cookie_t)*count); 3431 3432 sal_memset(&encapcfg, 0, sizeof(encapcfg)); 3433 for (pkt_idx=0, rv=BCM_E_NONE; pkt_idx<count ; pkt_idx++) { 3434 org_pkt_flags = 0; 3435 org_pkt_blk_addr = NULL; 3436 3437 /* Get hold of the current packet */ 3438 cur_pkt = pkt_arr[pkt_idx]; 3439 3440 /* Find out the appr. HGoE tag from the cached copy. It is sure that the 3441 * information will be retrieved succesfully every time as the logic 3442 * dictates no failure, hence no need to worry if hgoe tag is not found 3443 */ 3444 BCM_PBMP_ITER(cur_pkt->tx_pbmp, tx_port) 3445 { 3446 for (prt_idx=0 ; prt_idx<port_cnt ;prt_idx++) { 3447 if (port_info_arr[prt_idx].port == tx_port) { 3448 encapcfg.higig_ethertype =port_info_arr[prt_idx].ether_type; 3449 encapcfg.hgoe_reserved = port_info_arr[prt_idx].hgoe_rsvd; 3450 break; 3451 } 3452 } 3453 break; /* Only one TX port limitation */ 3454 } 3455 3456 /* Prepare the packet */ 3457 rv = _bcm_common_tx_hgoe_prepare_pkt( 3458 unit, cur_pkt, &org_pkt_flags, &org_pkt_blk_addr, encapcfg); 3459 3460 if (BCM_FAILURE(rv)) { 3461 break; 3462 } 3463 3464 /* Fill in the per packet callback info*/ 3465 pkt_info_arr[pkt_idx].chain_cb = bcm_common_tx_hgoe_tx_chain_cb; 3466 pkt_info_arr[pkt_idx].org_cookie = cookie; 3467 pkt_info_arr[pkt_idx].org_pkt = cur_pkt; 3468 pkt_info_arr[pkt_idx].pkt_cb = cur_pkt->call_back; 3469 pkt_info_arr[pkt_idx].org_pkt_flags = org_pkt_flags; 3470 pkt_info_arr[pkt_idx].org_pkt_blk_addr = org_pkt_blk_addr; 3471 pkt_info_arr[pkt_idx].new_pkt_blk_addr = cur_pkt->pkt_data; 3472 3473 /* Remove the call back from the pkt */ 3474 cur_pkt->call_back = NULL; 3475 } 3476 3477 if (!BCM_FAILURE(rv)) { 3478 /* All packets processed, now send the call down */ 3479 if (all_done_cb) { 3480 rv = _bcm_common_tx_array(unit, pkt_arr, 3481 count, bcm_common_tx_hgoe_tx_chain_cb, master_cookie); 3482 } else { 3483 rv = _bcm_common_tx_array(unit, pkt_arr, count, NULL, cookie); 3484 } 3485 } 3486 3487 if (BCM_FAILURE(rv) || !all_done_cb) { 3488 /* Something went wrong or no callback requested, cleanup */ 3489 for (pkt_idx=0 ; pkt_idx<count ; pkt_idx++) { 3490 if (pkt_info_arr[pkt_idx].chain_cb) { 3491 _bcm_common_tx_hgoe_manual_cleanup( 3492 pkt_info_arr[pkt_idx].org_pkt, 3493 pkt_info_arr[pkt_idx].org_pkt_flags, 3494 pkt_info_arr[pkt_idx].org_pkt_blk_addr, 3495 pkt_info_arr[pkt_idx].pkt_cb); 3496 } 3497 } 3498 sal_free(pkt_info_arr); 3499 sal_free(master_cookie); 3500 BCM_TX_HGOE_DBG_CTR_SEM_ACQ 3501 BCM_TX_HGOE_DBG_CTR_DECR(tx_list_pkt_ck_arr_cnt) 3502 BCM_TX_HGOE_DBG_CTR_DECR(tx_list_master_ck_cnt) 3503 BCM_TX_HGOE_DBG_CTR_SEM_REL 3504 } 3505 sal_free(port_info_arr); 3506 BCM_TX_HGOE_DBG_CTR_SEM_DECR(tx_list_port_info_cnt) 3507 3508 return rv; 3509 } 3510 3511 STATIC int 3512 _bcm_common_tx_array(int unit, bcm_pkt_t **pkt, int count, 3513 bcm_pkt_cb_f all_done_cb, void *cookie) 3514 #else 3515 int 3516 bcm_common_tx_array(int unit, bcm_pkt_t **pkt, int count, bcm_pkt_cb_f all_done_cb, 3517 void *cookie) 3518 #endif /* BCM_TRIDENT2PLUS_SUPPORT && BCM_TX_HGOE_LIMITED_SOLUTION */ 3519 { 3520 dv_t *dv = NULL; 3521 int rv = BCM_E_NONE; 3522 int tot_blks = 0; /* How many dcbs needed for packets */ 3523 #if defined(BCM_CMICX_SUPPORT) 3524 uint32 prefetch = 0; 3525 #endif 3526 int i; 3527 char *err_msg = NULL; 3528 int pkt_cb = FALSE; /* Are any pkts asking for callback? */ 3529 volatile bcm_pkt_t *pkt_ptr; 3530 #if !defined(BCM_TRIDENT2PLUS_SUPPORT) || !defined(BCM_TX_HGOE_LIMITED_SOLUTION) 3531 if (!pkt) { 3532 return BCM_E_PARAM; 3533 } 3534 3535 if (!BCM_UNIT_VALID(unit)) { 3536 return BCM_E_UNIT; 3537 } 3538 3539 if (!SOC_UNIT_VALID(unit)) { 3540 return BCM_E_UNIT; 3541 } 3542 3543 if (!BCM_IS_LOCAL(unit)) { /* Tunnel the packet to the remote CPU */ 3544 LOG_ERROR(BSL_LS_BCM_TX, 3545 (BSL_META_U(unit, 3546 "bcm_tx_array ERROR: Cannot tunnel\n"))); 3547 return BCM_E_PARAM; 3548 } 3549 #endif /* !BCM_TRIDENT2PLUS_SUPPORT || !BCM_TX_HGOE_LIMITED_SOLUTION */ 3550 3551 #if defined (INCLUDE_RCPU) && defined(BCM_XGS3_SWITCH_SUPPORT) 3552 if (SOC_IS_RCPU_UNIT(unit)) { 3553 for (i = 0; i < count; i++) { 3554 if (!pkt[i]) { 3555 return BCM_E_PARAM; 3556 } 3557 BCM_IF_ERROR_RETURN(_bcm_tx_pkt_tag_setup(unit, pkt[i])); 3558 if (!BCM_PKT_TX_ETHER(pkt[i])) { 3559 BCM_IF_ERROR_RETURN(_bcm_xgs3_tx_pipe_bypass_header_setup(unit, pkt[i])); 3560 } 3561 } 3562 return _bcm_rcpu_tx_array(unit, pkt, count, all_done_cb, cookie); 3563 } 3564 #endif /* INCLUDE_RCPU && BCM_XGS3_SWITCH_SUPPORT */ 3565 3566 /* Count the blocks and check for per-packet callback */ 3567 for (i = 0; i < count; i++) { 3568 if (!pkt[i]) { 3569 return BCM_E_PARAM; 3570 } 3571 tot_blks += pkt[i]->blk_count; 3572 if (pkt[i]->call_back) { 3573 pkt_cb = TRUE; 3574 } 3575 } 3576 3577 err_msg = "Bad flags for bcm_tx_array"; 3578 _ON_ERROR_GOTO(_tx_flags_check(unit, pkt[0]), rv, error); 3579 3580 err_msg = "Could not set up pkt for bcm_tx_array"; 3581 for (i = 0; i < count; i++) { 3582 _ON_ERROR_GOTO(_bcm_tx_pkt_tag_setup(unit, pkt[i]), rv, error); 3583 } 3584 3585 /* Allocate the DV */ 3586 err_msg = "Could not allocate dv/dv info"; 3587 do { 3588 dv = _tx_dv_alloc(unit, count, tot_blks + count * TX_EXTRA_DCB_COUNT, 3589 all_done_cb, cookie, pkt_cb); 3590 if (!dv) { 3591 if (BCM_SUCCESS(_bcm_tx_cb_intr_enabled())) { 3592 rv = BCM_E_MEMORY; 3593 goto error; 3594 } 3595 LOG_WARN(BSL_LS_BCM_TX, 3596 (BSL_META_U(unit, "%s%s\n"), err_msg, ", will retry ...")); 3597 if (sal_sem_take(tx_dv_done, sal_sem_FOREVER) < 0) { 3598 err_msg = "Failed to take tx_dv_done"; 3599 rv = BCM_E_FAIL; 3600 goto error; 3601 } 3602 } 3603 } while (!dv); 3604 3605 err_msg = "Could not set up or add pkt to DV"; 3606 for (i = 0; i < count; i++) { 3607 #ifdef BCM_PETRA_SUPPORT 3608 if (SOC_IS_ARAD(unit)) 3609 { 3610 _ON_ERROR_GOTO(_sand_tx_pkt_desc_add(unit, pkt[i], dv, 0), rv, error); 3611 } 3612 else 3613 #endif 3614 #ifdef BCM_DNX_SUPPORT 3615 if (SOC_IS_DNX(unit)) 3616 { 3617 _ON_ERROR_GOTO(_sand_tx_pkt_desc_add(unit, pkt[i], dv, 0), rv, error); 3618 } 3619 else 3620 #endif 3621 { 3622 _ON_ERROR_GOTO(_tx_pkt_desc_add(unit, pkt[i], dv, i), rv, error); 3623 } 3624 } 3625 3626 if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) { 3627 if (dv->dv_vcnt > 0) { /* Only add reload dcb if pkt dcb added */ 3628 err_msg = "Could not allocate a reload descriptor"; 3629 if (soc_dma_rld_desc_add(dv, 0) < 0) { 3630 rv = BCM_E_MEMORY; 3631 goto error; 3632 } 3633 #if defined(BCM_CMICX_SUPPORT) 3634 prefetch = 1; 3635 #endif 3636 } 3637 } 3638 #if defined(BCM_CMICX_SUPPORT) 3639 if (!prefetch) { 3640 soc_dma_contiguous_desc_add(dv); 3641 } 3642 #endif 3643 3644 err_msg = "Could not send array"; 3645 if (dv->dv_vcnt > 0) { 3646 rv = _bcm_tx_chain_send(unit, dv, 0); /* all_done_cb != NULL);*/ 3647 /* if (SOC_IS_ARAD(unit)) { 3648 if (all_done_cb != NULL) { 3649 pkt_ptr = TX_INFO(dv)->pkt[0]; 3650 (all_done_cb)(unit, (bcm_pkt_t *)pkt_ptr, cookie); 3651 3652 } 3653 } */ 3654 } else { 3655 /* Call the registered callback if any */ 3656 if (all_done_cb != NULL) { 3657 pkt_ptr = TX_INFO(dv)->pkt[0]; 3658 (all_done_cb)(unit, (bcm_pkt_t *)pkt_ptr, cookie); 3659 } 3660 if (dv != NULL) { 3661 _tx_dv_free(unit, dv); 3662 } 3663 rv = BCM_E_NONE; 3664 } 3665 error: 3666 _PROCESS_ERROR(unit, rv, dv, err_msg); 3667 return rv; 3668 } 3669 3670 /* 3671 * Function: 3672 * bcm_tx_list 3673 * Purpose: 3674 * Transmit a linked list of packets 3675 * Parameters: 3676 * unit - transmission unit 3677 * pkt - Pointer to linked list of packets 3678 * all_done_cb - Callback function (if non-NULL) when all pkts tx'd 3679 * cookie - Callback cookie. 3680 * Returns: 3681 * BCM_E_XXX 3682 * Notes: 3683 * If callback is non-NULL, the packets are sent asynchronously 3684 * (the routine returns before all the pkts are sent) 3685 * 3686 * The "packet callback" will be set according to the value 3687 * in each packet's "call_back" member, so that must be initialized 3688 * for all packets in the chain. 3689 * 3690 * The "next" member of the packet is used for the linked list. 3691 * CAREFUL: The internal _next member is not used for this. 3692 * 3693 * This routine does not support tunnelling to a remote CPU for 3694 * forwarding. 3695 * 3696 * The TX parameters, src mod, src port, PFM and internal priority, 3697 * are currently determined by the first packet in the list. 3698 */ 3699 #if defined(BCM_TRIDENT2PLUS_SUPPORT) && defined(BCM_TX_HGOE_LIMITED_SOLUTION) 3700 STATIC int 3701 _bcm_common_tx_list(int unit, bcm_pkt_t *pkt, 3702 bcm_pkt_cb_f all_done_cb, void *cookie); 3703 3704 int 3705 bcm_common_tx_list(int unit, bcm_pkt_t *pkt, 3706 bcm_pkt_cb_f all_done_cb, void *cookie) { 3707 3708 int rv = BCM_E_NONE; 3709 int port_cnt = 0; 3710 bcm_pbmp_t pbmp; 3711 uint32 pkt_cnt = 0; 3712 uint32 pkt_idx = 0; 3713 uint32 prt_idx = 0; 3714 uint8 is_pkt_cb = 0; 3715 bcm_port_t tx_port = 0; 3716 uint32 org_pkt_flags = 0; 3717 uint8 use_dflt_method = 1; 3718 bcm_pkt_t *cur_pkt = NULL; 3719 bcm_pkt_blk_t *org_pkt_blk_addr = NULL; 3720 bcm_port_encap_config_t encapcfg = {0}; 3721 bcm_tx_hgoe_cookie_t *pkt_info_arr = NULL; 3722 bcm_tx_hgoe_chain_cb_cookie_t *master_cookie = NULL; 3723 typedef struct { 3724 bcm_port_t port; 3725 uint16 ether_type; 3726 uint16 hgoe_rsvd; 3727 } hgoe_port_info_t; 3728 hgoe_port_info_t *port_info_arr = NULL; 3729 3730 /* Input parameter check */ 3731 if (!pkt) { 3732 return BCM_E_PARAM; 3733 } 3734 3735 if (!BCM_UNIT_VALID(unit)) { 3736 return BCM_E_UNIT; 3737 } 3738 3739 if (!SOC_UNIT_VALID(unit)) { 3740 return BCM_E_UNIT; 3741 } 3742 3743 if (!BCM_IS_LOCAL(unit)) { /* Tunnel the packet to the remote CPU */ 3744 LOG_ERROR(BSL_LS_BCM_TX, 3745 (BSL_META_U(unit, 3746 "bcm_tx_list ERROR: Cannot tunnel\n"))); 3747 return BCM_E_PARAM; 3748 } 3749 3750 if (SOC_IS_TRIDENT2PLUS(unit)) { 3751 BCM_PBMP_CLEAR(pbmp); 3752 /* Do fast check if the HGoE logic can be invoked or not */ 3753 for (cur_pkt=pkt ; cur_pkt ; cur_pkt=cur_pkt->next, pkt_cnt++) { 3754 3755 /* If even a single pkt is smart switched then go default route */ 3756 if (BCM_PKT_TX_ETHER(cur_pkt)) { 3757 break; 3758 } 3759 3760 /* If pkt has to be sent on multiple ports then go default route */ 3761 BCM_PBMP_COUNT(cur_pkt->tx_pbmp, port_cnt); 3762 if (1!=port_cnt) { 3763 break; 3764 } 3765 3766 BCM_PBMP_OR(pbmp, cur_pkt->tx_pbmp); 3767 3768 /* Mark if individual pkt call back exists. */ 3769 if (!is_pkt_cb && cur_pkt->call_back) { 3770 is_pkt_cb = 1; 3771 } 3772 } 3773 3774 /* If previous loop did not complete successfully or there is a case 3775 * where individual pkt callback esists but chain done callback not then 3776 * the HGoE logic cannot be invoked as it wont handle the said scenario. 3777 * Hence send the pkt using default way and hope TX happens successfully 3778 */ 3779 if (!cur_pkt && !(is_pkt_cb && !all_done_cb) ) { 3780 use_dflt_method = 0; 3781 } 3782 } 3783 3784 if (use_dflt_method) { 3785 rv = _bcm_common_tx_list(unit, pkt, all_done_cb, cookie); 3786 return rv; 3787 } 3788 3789 /* Check for port encapsulation type */ 3790 3791 /* Create a buffer to hold HGoE tag to be used later */ 3792 BCM_PBMP_COUNT(pbmp, port_cnt); 3793 port_info_arr=sal_alloc(sizeof(hgoe_port_info_t) * port_cnt, "HGoEPrtInfo"); 3794 if (!port_info_arr) { 3795 BCM_TX_HGOE_DBG_CTR_INCR(internal_fail_cnt) 3796 return (BCM_E_MEMORY); 3797 } 3798 BCM_TX_HGOE_DBG_CTR_SEM_INCR(tx_list_port_info_cnt) 3799 3800 /* If all tx ports are HGoE then go through the trouble of 3801 * forming a sobmh pkt otherwise just use the default way 3802 */ 3803 prt_idx = 0; 3804 rv = BCM_E_NONE; 3805 BCM_PBMP_ITER(pbmp, tx_port) 3806 { 3807 if (prt_idx >= port_cnt) { 3808 BCM_TX_HGOE_DBG_CTR_INCR(internal_fail_cnt) 3809 rv = BCM_E_FAIL; 3810 break; 3811 } 3812 3813 rv = bcm_port_encap_config_get(unit, tx_port, &encapcfg); 3814 3815 if (BCM_FAILURE(rv) 3816 || (encapcfg.encap != BCM_PORT_ENCAP_HIGIG_OVER_ETHERNET)) { 3817 rv = BCM_E_FAIL; 3818 break; 3819 } else { 3820 port_info_arr[prt_idx].port = tx_port; 3821 port_info_arr[prt_idx].ether_type = encapcfg.higig_ethertype; 3822 port_info_arr[prt_idx++].hgoe_rsvd = encapcfg.hgoe_reserved; 3823 } 3824 } 3825 3826 if (BCM_FAILURE(rv)) { 3827 /* Error in getting the port encap. info or port is non HGoE */ 3828 sal_free(port_info_arr); 3829 BCM_TX_HGOE_DBG_CTR_SEM_DECR(tx_list_port_info_cnt) 3830 return(_bcm_common_tx_list(unit, pkt, all_done_cb, cookie)); 3831 } 3832 3833 /* Past this point the pkt tx has to go through HGoE logic */ 3834 3835 /* Allocate memory to hold per pkt cookie */ 3836 pkt_info_arr = 3837 sal_alloc(sizeof(bcm_tx_hgoe_cookie_t)*pkt_cnt, "PerPktCkArr"); 3838 if (!pkt_info_arr) { 3839 BCM_TX_HGOE_DBG_CTR_INCR(internal_fail_cnt) 3840 sal_free(port_info_arr); 3841 BCM_TX_HGOE_DBG_CTR_SEM_DECR(tx_list_port_info_cnt) 3842 return (BCM_E_MEMORY); 3843 } 3844 BCM_TX_HGOE_DBG_CTR_SEM_INCR(tx_list_pkt_ck_arr_cnt) 3845 3846 /* Allocate memory for master cookie */ 3847 master_cookie = 3848 sal_alloc(sizeof(bcm_tx_hgoe_chain_cb_cookie_t), "ChainCBCk"); 3849 if (!master_cookie) { 3850 BCM_TX_HGOE_DBG_CTR_INCR(internal_fail_cnt) 3851 sal_free(port_info_arr); 3852 sal_free(pkt_info_arr); 3853 BCM_TX_HGOE_DBG_CTR_SEM_ACQ 3854 BCM_TX_HGOE_DBG_CTR_DECR(tx_list_port_info_cnt) 3855 BCM_TX_HGOE_DBG_CTR_DECR(tx_list_pkt_ck_arr_cnt) 3856 BCM_TX_HGOE_DBG_CTR_SEM_REL 3857 return (BCM_E_MEMORY); 3858 } 3859 BCM_TX_HGOE_DBG_CTR_SEM_INCR(tx_list_master_ck_cnt) 3860 3861 /* Fill in master cookie */ 3862 master_cookie->pkt_cnt = pkt_cnt; 3863 master_cookie->user_given_chain_cb = all_done_cb; 3864 master_cookie->user_given_cookie = cookie; 3865 master_cookie->pkt_cookie_arr = pkt_info_arr; 3866 3867 /* Initialize the per pkt cookie arr */ 3868 sal_memset(pkt_info_arr, 0, sizeof(bcm_tx_hgoe_cookie_t)*pkt_cnt); 3869 3870 sal_memset(&encapcfg, 0, sizeof(encapcfg)); 3871 for (cur_pkt=pkt, rv=BCM_E_NONE, pkt_idx=0 ; 3872 cur_pkt ; cur_pkt=cur_pkt->next, pkt_idx++) { 3873 3874 org_pkt_flags = 0; 3875 org_pkt_blk_addr = NULL; 3876 3877 /* Find out the appr. HGoE tag from the cached copy. It is sure that the 3878 * information will be retrieved succesfully every time as the logic 3879 * dictates no failure, hence no need to worry if hgoe tag is not found 3880 */ 3881 BCM_PBMP_ITER(cur_pkt->tx_pbmp, tx_port) 3882 { 3883 for (prt_idx=0 ; prt_idx<port_cnt ;prt_idx++) { 3884 if (port_info_arr[prt_idx].port == tx_port) { 3885 encapcfg.higig_ethertype =port_info_arr[prt_idx].ether_type; 3886 encapcfg.hgoe_reserved = port_info_arr[prt_idx].hgoe_rsvd; 3887 break; 3888 } 3889 } 3890 break; /* Only one TX port limitation */ 3891 } 3892 3893 /* Prepare the packet */ 3894 rv = _bcm_common_tx_hgoe_prepare_pkt( 3895 unit, cur_pkt, &org_pkt_flags, &org_pkt_blk_addr, encapcfg); 3896 3897 if (BCM_FAILURE(rv)) { 3898 break; 3899 } 3900 3901 /* Fill in the per packet callback info*/ 3902 pkt_info_arr[pkt_idx].chain_cb = bcm_common_tx_hgoe_tx_chain_cb; 3903 pkt_info_arr[pkt_idx].org_cookie = cookie; 3904 pkt_info_arr[pkt_idx].org_pkt = cur_pkt; 3905 pkt_info_arr[pkt_idx].pkt_cb = cur_pkt->call_back; 3906 pkt_info_arr[pkt_idx].org_pkt_flags = org_pkt_flags; 3907 pkt_info_arr[pkt_idx].org_pkt_blk_addr = org_pkt_blk_addr; 3908 pkt_info_arr[pkt_idx].new_pkt_blk_addr = cur_pkt->pkt_data; 3909 3910 /* Remove the call back from the pkt */ 3911 cur_pkt->call_back = NULL; 3912 } 3913 3914 if (!BCM_FAILURE(rv)) { 3915 /* All packets processed, now send the call down */ 3916 if (all_done_cb) { 3917 rv = _bcm_common_tx_list(unit, 3918 pkt, bcm_common_tx_hgoe_tx_chain_cb, master_cookie); 3919 } else { 3920 rv = _bcm_common_tx_list(unit, pkt, NULL, cookie); 3921 } 3922 } 3923 3924 if (BCM_FAILURE(rv) || !all_done_cb) { 3925 /* Something went wrong or no callback requested, cleanup */ 3926 for (pkt_idx=0 ; pkt_idx<pkt_cnt ; pkt_idx++) { 3927 if (pkt_info_arr[pkt_idx].chain_cb) { 3928 _bcm_common_tx_hgoe_manual_cleanup( 3929 pkt_info_arr[pkt_idx].org_pkt, 3930 pkt_info_arr[pkt_idx].org_pkt_flags, 3931 pkt_info_arr[pkt_idx].org_pkt_blk_addr, 3932 pkt_info_arr[pkt_idx].pkt_cb); 3933 } 3934 } 3935 sal_free(pkt_info_arr); 3936 sal_free(master_cookie); 3937 BCM_TX_HGOE_DBG_CTR_SEM_ACQ 3938 BCM_TX_HGOE_DBG_CTR_DECR(tx_list_pkt_ck_arr_cnt) 3939 BCM_TX_HGOE_DBG_CTR_DECR(tx_list_master_ck_cnt) 3940 BCM_TX_HGOE_DBG_CTR_SEM_REL 3941 } 3942 sal_free(port_info_arr); 3943 BCM_TX_HGOE_DBG_CTR_SEM_DECR(tx_list_port_info_cnt) 3944 3945 return rv; 3946 } 3947 3948 STATIC int 3949 _bcm_common_tx_list(int unit, bcm_pkt_t *pkt, 3950 bcm_pkt_cb_f all_done_cb, void *cookie) 3951 #else 3952 int 3953 bcm_common_tx_list(int unit, bcm_pkt_t *pkt, bcm_pkt_cb_f all_done_cb, void *cookie) 3954 #endif /* BCM_TRIDENT2PLUS_SUPPORT && BCM_TX_HGOE_LIMITED_SOLUTION */ 3955 { 3956 dv_t *dv = NULL; 3957 int rv = BCM_E_NONE; 3958 int tot_blks = 0; /* How many dcbs needed for packets */ 3959 int count; 3960 #if defined(BCM_CMICX_SUPPORT) 3961 uint32 prefetch = 0; 3962 #endif 3963 bcm_pkt_t *cur_pkt; 3964 char *err_msg = NULL; 3965 int pkt_cb = FALSE; /* Are any pkts asking for callback? */ 3966 int i = 0; 3967 volatile bcm_pkt_t *pkt_ptr; 3968 3969 #if !defined(BCM_TRIDENT2PLUS_SUPPORT) || !defined(BCM_TX_HGOE_LIMITED_SOLUTION) 3970 if (!pkt) { 3971 return BCM_E_PARAM; 3972 } 3973 3974 if (!BCM_UNIT_VALID(unit)) { 3975 return BCM_E_UNIT; 3976 } 3977 3978 if (!SOC_UNIT_VALID(unit)) { 3979 return BCM_E_UNIT; 3980 } 3981 3982 if (!BCM_IS_LOCAL(unit)) { /* Tunnel the packet to the remote CPU */ 3983 LOG_ERROR(BSL_LS_BCM_TX, 3984 (BSL_META_U(unit, 3985 "bcm_tx_list ERROR: Cannot tunnel\n"))); 3986 return BCM_E_PARAM; 3987 } 3988 #endif /* !BCM_TRIDENT2PLUS_SUPPORT || !BCM_TX_HGOE_LIMITED_SOLUTION */ 3989 3990 #if defined (INCLUDE_RCPU) && defined(BCM_XGS3_SWITCH_SUPPORT) 3991 if (SOC_IS_RCPU_UNIT(unit)) { 3992 for (cur_pkt = pkt; cur_pkt; cur_pkt = cur_pkt->next) { 3993 BCM_IF_ERROR_RETURN(_bcm_tx_pkt_tag_setup(unit, cur_pkt)); 3994 if (!BCM_PKT_TX_ETHER(cur_pkt)) { 3995 BCM_IF_ERROR_RETURN(_bcm_xgs3_tx_pipe_bypass_header_setup(unit, cur_pkt)); 3996 } 3997 } 3998 return _bcm_rcpu_tx_list(unit, pkt, all_done_cb, cookie); 3999 } 4000 #endif /* INCLUDE_RCPU && BCM_XGS3_SWITCH_SUPPORT */ 4001 4002 /* Count the blocks and check for per-packet callback */ 4003 count = 0; 4004 for (cur_pkt = pkt; cur_pkt; cur_pkt = cur_pkt->next) { 4005 tot_blks += cur_pkt->blk_count; 4006 if (cur_pkt->call_back) { 4007 pkt_cb = TRUE; 4008 } 4009 ++count; 4010 } 4011 4012 err_msg = "Bad flags for bcm_tx_list"; 4013 _ON_ERROR_GOTO(_tx_flags_check(unit, pkt), rv, error); 4014 4015 err_msg = "Could not set up pkt for bcm_tx_list"; 4016 for (cur_pkt = pkt; cur_pkt != NULL; cur_pkt = cur_pkt->next) { 4017 _ON_ERROR_GOTO(_bcm_tx_pkt_tag_setup(unit, cur_pkt), rv, error); 4018 } 4019 4020 /* Allocate the DV */ 4021 err_msg = "Could not allocate dv/dv info"; 4022 do { 4023 dv = _tx_dv_alloc(unit, count, tot_blks + count * TX_EXTRA_DCB_COUNT, 4024 all_done_cb, cookie, pkt_cb); 4025 if (!dv) { 4026 if (BCM_SUCCESS(_bcm_tx_cb_intr_enabled())) { 4027 rv = BCM_E_MEMORY; 4028 goto error; 4029 } 4030 LOG_WARN(BSL_LS_BCM_TX, 4031 (BSL_META_U(unit, "%s%s\n"), err_msg, ", will retry ...")); 4032 if (sal_sem_take(tx_dv_done, sal_sem_FOREVER) < 0) { 4033 err_msg = "Failed to take tx_dv_done"; 4034 rv = BCM_E_FAIL; 4035 goto error; 4036 } 4037 } 4038 } while (!dv); 4039 4040 err_msg = "Could not set up or add pkt to DV"; 4041 for (i = 0, cur_pkt = pkt; cur_pkt; cur_pkt = cur_pkt->next, i++) { 4042 #ifdef BCM_PETRA_SUPPORT 4043 if (SOC_IS_ARAD(unit)) 4044 { 4045 _ON_ERROR_GOTO(_sand_tx_pkt_desc_add(unit, cur_pkt, dv, 0), rv, error); 4046 } 4047 else 4048 #endif 4049 #ifdef BCM_DNX_SUPPORT 4050 if (SOC_IS_DNX(unit)) 4051 { 4052 _ON_ERROR_GOTO(_sand_tx_pkt_desc_add(unit, cur_pkt, dv, 0), rv, error); 4053 } 4054 else 4055 #endif 4056 { 4057 _ON_ERROR_GOTO(_tx_pkt_desc_add(unit, cur_pkt, dv, i), rv, error); 4058 } 4059 } 4060 4061 if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) { 4062 if (dv->dv_vcnt > 0) { /* Only add reload dcb if pkt dcb added */ 4063 err_msg = "Could not allocate a reload descriptor"; 4064 if (soc_dma_rld_desc_add(dv, 0) < 0) { 4065 rv = BCM_E_MEMORY; 4066 goto error; 4067 } 4068 #if defined(BCM_CMICX_SUPPORT) 4069 prefetch = 1; 4070 #endif 4071 } 4072 } 4073 #if defined(BCM_CMICX_SUPPORT) 4074 if (!prefetch) { 4075 soc_dma_contiguous_desc_add(dv); 4076 } 4077 #endif 4078 4079 err_msg = "Could not send list"; 4080 if (dv->dv_vcnt > 0) { 4081 rv = _bcm_tx_chain_send(unit, dv, all_done_cb != NULL); 4082 #if 0 4083 if (SOC_IS_ARAD(unit)) { 4084 if (all_done_cb != NULL) { 4085 pkt_ptr = TX_INFO(dv)->pkt[0]; 4086 (all_done_cb)(unit, (bcm_pkt_t *)pkt_ptr, cookie); 4087 } 4088 } 4089 #endif 4090 } else { 4091 /* Call the registered callback if any */ 4092 if (all_done_cb != NULL) { 4093 pkt_ptr = TX_INFO(dv)->pkt[0]; 4094 if (pkt_ptr == NULL) { 4095 LOG_VERBOSE(BSL_LS_BCM_TX, 4096 (BSL_META_U(unit, 4097 "NULL pkt\n"))); 4098 pkt_ptr = pkt; 4099 } 4100 (all_done_cb)(unit, (bcm_pkt_t *)pkt_ptr, cookie); 4101 } 4102 if (dv != NULL) { 4103 _tx_dv_free(unit, dv); 4104 } 4105 rv = BCM_E_NONE; 4106 } 4107 error: 4108 _PROCESS_ERROR(unit, rv, dv, err_msg); 4109 return rv; 4110 } 4111 4112 /* 4113 * Function: 4114 * _bcm_tx_chain_send 4115 * Purpose: 4116 * Send out a chain of one or more packets 4117 */ 4118 4119 STATIC int 4120 _bcm_tx_chain_send(int unit, dv_t *dv, int async) 4121 { 4122 ++_tx_chain_send; 4123 4124 #if defined(BROADCOM_DEBUG) 4125 if (!bsl_check(bslLayerSoc, bslSourcePacketdma, bslSeverityNormal, unit) && 4126 bsl_check(bslLayerSoc, bslSourceTx, bslSeverityVerbose, unit)) { 4127 int i = 0, j, k, len, dv_cnt = 0; 4128 dcb_t *dcb; 4129 uint8 *addr; 4130 char linebuf[128], *s; 4131 dv_t *dv_i; 4132 4133 LOG_INFO(BSL_LS_BCM_TX, 4134 (BSL_META_U(unit, 4135 "_bcm_tx_chain_send: packet send\n"))); 4136 4137 for (dv_i = dv; dv_i != NULL; dv_i = dv_i->dv_chain, dv_cnt++) { 4138 for (k = 0; k < dv_i->dv_vcnt; k++) { 4139 soc_dma_dump_dv_dcb(unit, "tx Dma descr: ", dv, k); 4140 dcb = SOC_DCB_IDX2PTR(unit, dv_i->dv_dcb, k); 4141 addr = (uint8*)SOC_DCB_ADDR_GET(unit, dcb); 4142 len = SOC_DCB_REQCOUNT_GET(unit, dcb); 4143 for (i = 0; i < len; i += 16) { 4144 s = linebuf; 4145 sal_sprintf(s, "TXDV %d data[%04x]: ", dv_cnt, i); 4146 while (*s != 0) s++; 4147 for (j = i; j < i + 16 && j < len; j++) { 4148 sal_sprintf(s, "%02x%s", addr[j], j & 1 ? " " : ""); 4149 while (*s != 0) s++; 4150 } 4151 LOG_CLI((BSL_META_U(unit, 4152 "%s\n"), linebuf)); 4153 } 4154 } 4155 } 4156 } 4157 #endif /* BROADCOM_DEBUG */ 4158 4159 if (async) { /* Send packet(s) asynchronously */ 4160 LOG_INFO(BSL_LS_BCM_TX, 4161 (BSL_META_U(unit, 4162 "bcm_tx: async send\n"))); 4163 4164 if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) { 4165 dv->dv_flags |= DV_F_NOTIFY_DSC; 4166 4167 } else { 4168 dv->dv_flags |= DV_F_NOTIFY_CHN; 4169 } 4170 4171 SOC_IF_ERROR_RETURN(soc_dma_start(unit, -1, dv)); 4172 } else { /* Send sync */ 4173 LOG_INFO(BSL_LS_BCM_TX, 4174 (BSL_META_U(unit, 4175 "bcm_tx: sync send\n"))); 4176 SOC_IF_ERROR_RETURN(soc_dma_wait(unit, dv)); 4177 LOG_INFO(BSL_LS_BCM_TX, 4178 (BSL_META_U(unit, 4179 "bcm_tx: Sent synchronously.\n"))); 4180 4181 if (SOC_DMA_MODE(unit) != SOC_DMA_MODE_CONTINUOUS) { 4182 _bcm_tx_chain_done_cb(unit, dv); 4183 } 4184 } 4185 4186 return BCM_E_NONE; 4187 } 4188 4189 /**************************************************************** 4190 * 4191 * Map a destination MAC address to port bitmaps. Uses 4192 * the dest_mac passed as a parameter. Sets the 4193 * bitmaps in the pkt structure. 4194 */ 4195 4196 /* 4197 * Function: 4198 * bcm_tx_pkt_l2_map 4199 * Purpose: 4200 * Resolve the packet's L2 destination and update the necessary 4201 * fields of the packet. 4202 * Parameters: 4203 * unit - Transmit unit 4204 * pkt - Pointer to pkt being transmitted 4205 * dest_mac - use for L2 lookup 4206 * vid - use for L2 lookup 4207 * Returns: 4208 * BCM_E_XXX 4209 * Notes: 4210 * Deprecated, not implemented. 4211 */ 4212 4213 int 4214 bcm_common_tx_pkt_l2_map(int unit, bcm_pkt_t *pkt, bcm_mac_t dest_mac, int vid) 4215 { 4216 return BCM_E_UNAVAIL; 4217 } 4218 4219 /**************************************************************** 4220 * 4221 * Functions to setup DVs and DCBs. 4222 * _tx_dv_alloc: Allocate and init a TX DV 4223 * _tx_pkt_desc_add: Add all the descriptors for a packet to a DV 4224 * 4225 * Minor functions: 4226 * _dcb_flags_get: Calculate the DCB flags. 4227 * _get_mac_vlan_ptrs: Determine DMA pointers for src_mac and 4228 * vlan. This is in case the src_mac is not 4229 * in the same pkt block as the dest_mac; or 4230 * the packet is untagged. Also sets the 4231 * byte and block offsets for data that follows. 4232 */ 4233 4234 4235 4236 /* 4237 * Function: 4238 * _tx_dv_alloc 4239 * Purpose: 4240 * Allocate a DV, a dv_info structure and initialize. 4241 * Parameters: 4242 * unit - Strata unit number for allocation 4243 * pkt_count - Number of packets to TX 4244 * dcb_count - The number of DCBs to provide 4245 * chain_done_cb - Chain done callback function 4246 * cookie - User cookie used for chain done and packet callbacks. 4247 * per_pkt_cb - Do we need to callback on each packet complete? 4248 * Returns: 4249 * BCM_E_XXX 4250 * Notes: 4251 * Always sets the dv_done_chain callback; sets packet done 4252 * call back according to per_pkt_cb parameter. 4253 */ 4254 4255 STATIC dv_t * 4256 _tx_dv_alloc(int unit, int pkt_count, int dcb_count, 4257 bcm_pkt_cb_f chain_done_cb, void *cookie, int per_pkt_cb) 4258 { 4259 dv_t *dv; 4260 tx_dv_info_t *dv_info; 4261 volatile bcm_pkt_t **pkt; 4262 int packet_count_limit = SOC_DV_PKTS_MAX; 4263 4264 #ifdef BCM_XGS3_SWITCH_SUPPORT 4265 if (SOC_IS_XGS3_SWITCH(unit)) { 4266 int port_count; 4267 /* On XGS3 we allow a larger DV chain to allow a single TX to 4268 all ports */ 4269 BCM_PBMP_COUNT(PBMP_PORT_ALL(unit), port_count); 4270 if (packet_count_limit < port_count) { 4271 packet_count_limit = port_count; 4272 } 4273 } 4274 #endif 4275 4276 if (pkt_count > packet_count_limit) { 4277 LOG_ERROR(BSL_LS_BCM_TX, 4278 (BSL_META_U(unit, 4279 "TX array: Cannot TX more than %d pkts. " 4280 "Attempting %d.\n"), 4281 packet_count_limit, pkt_count)); 4282 return NULL; 4283 } 4284 4285 /* In continuous mode, make room for the reload descriptor */ 4286 /* This check assumes that TX is always on channel 0 */ 4287 if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) { 4288 dcb_count++; 4289 } 4290 4291 LOG_DEBUG(BSL_LS_BCM_TX, 4292 (BSL_META_U(unit, 4293 "pkt_cnt %d dcb_cnt %d\n"), 4294 pkt_count, dcb_count)); 4295 4296 if ((dv = soc_dma_dv_alloc_by_port(unit, DV_TX, dcb_count, 4297 pkt_count)) == NULL) { 4298 return NULL; 4299 } 4300 /* not a queued dv */ 4301 if (TX_INFO(dv) == NULL) { 4302 if ((dv_info = soc_at_alloc(unit, sizeof(tx_dv_info_t), "tx_dv")) == NULL) { 4303 soc_dma_dv_free(unit, dv); 4304 return NULL; 4305 } 4306 pkt = soc_at_alloc(unit, (sizeof(bcm_pkt_t *) * packet_count_limit), "tx_dv pkt"); 4307 if (pkt == NULL) { 4308 soc_dma_dv_free(unit, dv); 4309 soc_at_free(unit, dv_info); 4310 return NULL; 4311 } 4312 } else { 4313 dv_info = TX_INFO(dv); 4314 pkt = dv_info->pkt; 4315 } 4316 TX_INFO_SET(dv, dv_info); 4317 sal_memset(TX_INFO(dv), 0, sizeof(tx_dv_info_t)); 4318 TX_INFO(dv)->pkt = pkt; 4319 /* 4320 * Clear memory depending on the pkt_count to avoid trashing the "pkt" 4321 * buffer allocated before the flex port operation; flexing can increase 4322 * the packet_count_limit. Allocation happens in soc_dma_dv_alloc_by_port, 4323 * depending on pkt_count. 4324 */ 4325 if (pkt_count <= SOC_DV_PKTS_MAX) { 4326 sal_memset(TX_INFO(dv)->pkt, 0, 4327 (sizeof(bcm_pkt_t *) * SOC_DV_PKTS_MAX)); 4328 } else { 4329 sal_memset(TX_INFO(dv)->pkt, 0, 4330 (sizeof(bcm_pkt_t *) * packet_count_limit)); 4331 } 4332 TX_INFO(dv)->cookie = cookie; 4333 TX_INFO(dv)->chain_done_cb = chain_done_cb; 4334 dv->dv_done_chain = _bcm_tx_chain_done_cb; 4335 dv->dv_done_desc = _bcm_tx_desc_done_cb; 4336 dv->dv_done_desc_subs = _bcm_tx_desc_done_cb; 4337 dv->dv_done_reload = _bcm_tx_reload_done_cb; 4338 if (per_pkt_cb) { 4339 dv->dv_done_packet = _bcm_tx_packet_done_cb; 4340 } 4341 return dv; 4342 } 4343 4344 /* 4345 * Function: 4346 * _tx_dv_free 4347 * Purpose: 4348 * Free a DV and associated dv_info structure 4349 * Parameters: 4350 * unit - Strata unit number for allocation 4351 * dv - The DV to free 4352 * Returns: 4353 * None 4354 */ 4355 4356 STATIC void 4357 _tx_dv_free(int unit, dv_t *dv) 4358 { 4359 tx_dv_info_t *dv_info; 4360 4361 LOG_DEBUG(BSL_LS_BCM_TX, 4362 (BSL_META_U(unit, 4363 "Freeing DV %p\n"), 4364 (void *)dv)); 4365 4366 if (dv) { 4367 dv_info = TX_INFO(dv); 4368 /* release dv_info, no matter it's queued dv or not */ 4369 if (dv_info) { 4370 if (dv_info->pkt) { 4371 soc_at_free(unit, dv_info->pkt); 4372 } 4373 soc_at_free(unit, dv_info); 4374 TX_INFO_SET(dv, NULL); 4375 } 4376 soc_dma_dv_free(unit, dv); 4377 } 4378 } 4379 4380 void 4381 tx_dv_free_cb(int unit, dv_t *dv) 4382 { 4383 tx_dv_info_t *dv_info; 4384 4385 if (dv) { 4386 if (dv->dv_done_chain == _bcm_tx_chain_done_cb) { 4387 dv_info = TX_INFO(dv); 4388 if (dv_info) { 4389 if (dv_info->pkt) { 4390 soc_at_free(unit, dv_info->pkt); 4391 } 4392 soc_at_free(unit, dv_info); 4393 } 4394 } 4395 } 4396 } 4397 4398 /* Set up the DV for bcm_tx; 4399 * Assert: unit is local 4400 */ 4401 STATIC INLINE uint32 4402 _dcb_flags_get(int unit, bcm_pkt_t *pkt, dv_t *dv) 4403 { 4404 uint32 dcb_flags = 0; 4405 4406 COMPILER_REFERENCE(dv); 4407 if (SOC_IS_XGS3_SWITCH(unit)) { 4408 /* 4409 * XGS3: HG bit in descriptor needs to be set 4410 * 1. Raw mode HG/Ethernet TX (Unmodified Packet steering). 4411 * 2. Fabric mapped TX 4412 * For fully mapped Ethernet transmit this should not be set. 4413 */ 4414 if ((! BCM_PKT_TX_ETHER(pkt)) || /* Raw mode TX */ 4415 BCM_TX_PKT_PROP_ANY_TST(pkt) || /* Fabric mapped TX */ 4416 BCM_PKT_TX_HG_READY(pkt)) { 4417 SOC_DMA_HG_SET(dcb_flags, 1); 4418 } 4419 if (pkt->flags & BCM_TX_PURGE) { 4420 SOC_DMA_PURGE_SET(dcb_flags, 1); 4421 } 4422 4423 return dcb_flags; 4424 } 4425 #ifdef BCM_ARAD_SUPPORT 4426 else if (SOC_IS_ARAD(unit)) { 4427 if (pkt->flags & BCM_TX_PURGE) { 4428 SOC_DMA_PURGE_SET(dcb_flags, 1); 4429 } 4430 if (pkt->flags & BCM_PKT_F_HGHDR) { 4431 SOC_DMA_HG_SET(dcb_flags, 1); 4432 } 4433 } 4434 #endif 4435 #ifdef BCM_DNX_SUPPORT 4436 else if (SOC_IS_DNX(unit)) 4437 { 4438 if (pkt->flags & BCM_TX_PURGE) 4439 { 4440 SOC_DMA_PURGE_SET(dcb_flags, 1); 4441 } 4442 if (pkt->flags & BCM_PKT_F_HGHDR) { 4443 SOC_DMA_HG_SET(dcb_flags, 1); 4444 } 4445 } 4446 #endif 4447 4448 dcb_flags |= SOC_DMA_COS(pkt->cos); 4449 /* This level does not handle CRC append, but marks for HW to generate */ 4450 if (pkt->flags & (BCM_TX_CRC_APPEND | BCM_TX_CRC_REGEN)) { 4451 dcb_flags |= SOC_DMA_CRC_REGEN; 4452 } 4453 4454 return dcb_flags; 4455 } 4456 4457 /* 4458 * Based on packet settings, get pointers to vlan, and src mac 4459 * Update the "current" block and byte offset 4460 */ 4461 4462 STATIC INLINE void 4463 _get_mac_vlan_ptrs(dv_t *dv, bcm_pkt_t *pkt, uint8 **src_mac, 4464 uint8 **vlan_ptr, int *block_offset, int *byte_offset, 4465 int pkt_idx) 4466 { 4467 /* Assume everything is in block 0 */ 4468 *src_mac = &pkt->pkt_data[0].data[sizeof(bcm_mac_t)]; 4469 *block_offset = 0; 4470 4471 if (BCM_PKT_NO_VLAN_TAG(pkt)) { /* Get VLAN from _vtag pkt member */ 4472 *byte_offset = 2 * sizeof(bcm_mac_t); 4473 sal_memcpy(SOC_DV_VLAN_TAG(dv, pkt_idx), pkt->_vtag, sizeof(uint32)); 4474 *vlan_ptr = SOC_DV_VLAN_TAG(dv, pkt_idx); 4475 4476 if (pkt->pkt_data[0].len < 2 * sizeof(bcm_mac_t)) { 4477 /* Src MAC in block 1 */ 4478 *src_mac = pkt->pkt_data[1].data; 4479 *block_offset = 1; 4480 *byte_offset = sizeof(bcm_mac_t); 4481 } 4482 } else { /* Packet has VLAN tag */ 4483 *byte_offset = 2 * sizeof(bcm_mac_t) + sizeof(uint32); 4484 *vlan_ptr = &pkt->pkt_data[0].data[2 * sizeof(bcm_mac_t)]; 4485 4486 if (pkt->pkt_data[0].len < 2 * sizeof(bcm_mac_t)) { 4487 /* Src MAC in block 1; assume VLAN there too at first */ 4488 *src_mac = pkt->pkt_data[1].data; 4489 *vlan_ptr = &pkt->pkt_data[1].data[sizeof(bcm_mac_t)]; 4490 *block_offset = 1; 4491 *byte_offset = sizeof(bcm_mac_t) + sizeof(uint32); 4492 if (pkt->pkt_data[1].len < sizeof(bcm_mac_t) + sizeof(uint32)) { 4493 /* Oops, VLAN in block 2 */ 4494 *vlan_ptr = pkt->pkt_data[2].data; 4495 *block_offset = 2; 4496 *byte_offset = sizeof(uint32); 4497 } 4498 } else if (pkt->pkt_data[0].len < 4499 2 * sizeof(bcm_mac_t) + sizeof(uint32)) { 4500 /* VLAN in block 2 */ 4501 *block_offset = 1; 4502 *byte_offset = sizeof(uint32); 4503 *vlan_ptr = pkt->pkt_data[1].data; 4504 } 4505 } 4506 } 4507 4508 /* Set up the SOC layer TX packet according to flags and BCM pkt */ 4509 4510 /* PFM is two bits */ 4511 #define PFM_MASK 0x3 4512 4513 STATIC INLINE void 4514 _soc_tx_pkt_setup(int unit, bcm_pkt_t *pkt, soc_tx_param_t *tx_param) 4515 { 4516 /* Decide which source mod/port to use */ 4517 tx_param->src_mod = (pkt->flags & BCM_TX_SRC_MOD) ? pkt->src_mod : 4518 SOC_DEFAULT_DMA_SRCMOD_GET(unit); 4519 tx_param->src_port = (pkt->flags & BCM_TX_SRC_PORT) ? pkt->src_port : 4520 SOC_DEFAULT_DMA_SRCPORT_GET(unit); 4521 tx_param->pfm = (pkt->flags & BCM_TX_PFM) ? pkt->pfm : 4522 SOC_DEFAULT_DMA_PFM_GET(unit); 4523 4524 if ((tx_param->pfm & (~PFM_MASK)) != 0) { 4525 LOG_WARN(BSL_LS_BCM_TX, 4526 (BSL_META_U(unit, 4527 "bcm_tx: PFM too big, truncating\n"))); 4528 tx_param->pfm &= PFM_MASK; 4529 } 4530 4531 /* 4532 * the default ought to be BCM_PKT_VLAN_PRI(pkt), 4533 * but we need backwards compatibility with 5690 4534 */ 4535 tx_param->prio_int = (pkt->flags & BCM_TX_PRIO_INT) ? pkt->prio_int : 4536 pkt->cos; 4537 4538 tx_param->cos = pkt->cos; 4539 } 4540 4541 #define BCM_PKT_TX_OLP(pkt) \ 4542 (((pkt)->flags2 & BCM_PKT_F2_OAM_TX) != 0) 4543 4544 #define BCM_PKT_TX_HAS_OLP_READY(pkt) \ 4545 (((pkt)->flags2 & BCM_PKT_F2_OLP_READY) != 0) 4546 #define BCM_PKT_OLP_HDR(pkt) \ 4547 ((pkt)->_olp_hdr) 4548 4549 #define _OLP_OAM_MIN_OFFSET 14 4550 4551 #if defined (BCM_TRIDENT2PLUS_SUPPORT) || defined (BCM_SABER2_SUPPORT) 4552 /* 4553 * Function: 4554 * _bcm_olp_l2_hdr_get 4555 * Purpose: 4556 * Get the OLP L2 header 4557 * Parameters: 4558 * unit - (IN) BCM device number 4559 * glp - (IN) OLP port 4560 * nbo - (IN) Switch to indicate if each member in l2hdr has to 4561 * be converted to NBO 4562 * l2hdr - (OUT) OLP header 4563 * Returns: 4564 * BCM_E_XXX 4565 */ 4566 int _bcm_olp_l2_hdr_get(int unit, int glp, uint8 nbo, soc_olp_l2_hdr_t *l2hdr) 4567 { 4568 int rv = BCM_E_NONE; 4569 uint64 rval; 4570 uint64 mac_field; 4571 int index; 4572 BCM_IF_ERROR_RETURN(_bcm_switch_olp_dglp_get( 4573 unit, glp, (bcm_mac_t *)(l2hdr->src_mac), &index)); 4574 COMPILER_64_ZERO(rval); 4575 SOC_IF_ERROR_RETURN(READ_IARB_OLP_CONFIGr(unit, &rval)); 4576 mac_field = soc_reg64_field_get(unit, IARB_OLP_CONFIGr, rval,MACDAf); 4577 SAL_MAC_ADDR_FROM_UINT64(l2hdr->dst_mac,mac_field); 4578 4579 l2hdr->etherType = soc_reg64_field32_get(unit, IARB_OLP_CONFIGr, rval,ETHERTYPEf); 4580 4581 COMPILER_64_ZERO(rval); 4582 SOC_IF_ERROR_RETURN(READ_IARB_OLP_CONFIG_1r(unit, &rval)); 4583 l2hdr->vlan = soc_reg64_field32_get(unit, IARB_OLP_CONFIG_1r, rval,VLAN_IDf); 4584 4585 l2hdr->tpid = soc_reg64_field32_get(unit, IARB_OLP_CONFIG_1r, rval, VLAN_TPIDf); 4586 4587 if (nbo) { 4588 /* Convert to Network Byte Order */ 4589 l2hdr->etherType = soc_htons(l2hdr->etherType); 4590 l2hdr->vlan = soc_htons(l2hdr->vlan); 4591 l2hdr->tpid = soc_htons(l2hdr->tpid); 4592 } 4593 4594 LOG_DEBUG(BSL_LS_BCM_TX, 4595 (BSL_META_U(unit, 4596 "%s,dmac 0x%x:0x%x,smac 0x%x:0x%x,tpid 0x%x,vlan %d,ether 0x%x" 4597 "\n"),__FUNCTION__,l2hdr->dst_mac[5],l2hdr->dst_mac[0],l2hdr->src_mac[5],l2hdr->src_mac[0], 4598 soc_htons(l2hdr->tpid),soc_htons(l2hdr->vlan),soc_htons(l2hdr->etherType))); 4599 return rv; 4600 } 4601 4602 #if defined (BCM_TRIDENT2PLUS_SUPPORT) 4603 STATIC int 4604 _bcm_td2plus_tx_olp_hdr_ts_lm_offset_fill(int unit, 4605 bcm_pkt_t *pkt, 4606 soc_olp_tx_hdr_t *otxhdr) 4607 { 4608 if(pkt->flags2 & BCM_PKT_F2_TIMESTAMP_MODE) { 4609 SOC_OLP_TX_TIMESTAMP_ACTION(otxhdr) = pkt->timestamp_mode; 4610 } 4611 if((pkt->flags2 & BCM_PKT_F2_REPLACEMENT_OFFSET)) { 4612 if(pkt->oam_replacement_offset <= _OLP_OAM_MIN_OFFSET) { 4613 return BCM_E_PARAM; 4614 } 4615 SOC_OLP_TX_OAM_OFFSET(otxhdr) = 4616 (pkt->oam_replacement_offset - _OLP_OAM_MIN_OFFSET) / 2; 4617 } 4618 return BCM_E_NONE; 4619 } 4620 #endif 4621 4622 #if defined (BCM_SABER2_SUPPORT) 4623 STATIC int _bcm_sb2_tx_olp_hdr_ts_lm_offset_fill(int unit, 4624 bcm_pkt_t *pkt, 4625 soc_olp_tx_hdr_t *otxhdr) 4626 { 4627 int add_sub = 0; 4628 uint8 dm_replacement_offset = 0; 4629 uint8 lm_replacement_offset = 0; 4630 4631 if (SOC_IS_SABER2(unit)) { 4632 if (pkt->flags2 & BCM_PKT_F2_LM_REPLACEMENT_OFFSET) { 4633 lm_replacement_offset = pkt->oam_lm_replacement_offset; 4634 if (lm_replacement_offset == 0){ 4635 return BCM_E_PARAM; 4636 } 4637 } 4638 if (pkt->flags2 & BCM_PKT_F2_REPLACEMENT_OFFSET) { 4639 if(pkt->oam_replacement_offset <= _OLP_OAM_MIN_OFFSET) { 4640 return BCM_E_PARAM; 4641 } 4642 dm_replacement_offset = pkt->oam_replacement_offset; 4643 if (dm_replacement_offset == 0){ 4644 return BCM_E_PARAM; 4645 } 4646 } 4647 4648 if (lm_replacement_offset == 0 && dm_replacement_offset == 0) { 4649 /* Nothing to do */ 4650 } else if (dm_replacement_offset == 0) { /* Only LM case */ 4651 if (pkt->flags2 & BCM_PKT_F2_TIMESTAMP_MODE) { 4652 /* Timestamp mode given when no timestamp 4653 * replacment offset is given. */ 4654 return BCM_E_PARAM; 4655 } 4656 SOC_OLP_TX_OAM_OFFSET(otxhdr) = 4657 (lm_replacement_offset - _OLP_OAM_MIN_OFFSET) / 2; 4658 } else if (lm_replacement_offset == 0) { /* Only DM case */ 4659 SOC_OLP_TX_OAM_OFFSET(otxhdr) = 4660 (dm_replacement_offset - _OLP_OAM_MIN_OFFSET) / 2; 4661 SOC_OLP_TX_TIMESTAMP_ACTION(otxhdr) = pkt->timestamp_mode; 4662 } else { /* LM + DM case */ 4663 /* Check if lm replacement offset is bigger/smaller than 4664 * dm replacement offset */ 4665 if (lm_replacement_offset > dm_replacement_offset) { 4666 add_sub = 0; /* Add */ 4667 } else if (lm_replacement_offset < dm_replacement_offset) { 4668 add_sub = 1; /* Sub */ 4669 } else { 4670 return BCM_E_PARAM; /* both should not be equal */ 4671 } 4672 SOC_OLP_TX_OAM_OFFSET(otxhdr) = 4673 (dm_replacement_offset - _OLP_OAM_MIN_OFFSET) / 2; 4674 SOC_OLP_TX_TIMESTAMP_ACTION(otxhdr) = pkt->timestamp_mode; 4675 4676 if (add_sub == 0) { 4677 SOC_OLP_TX_REL_LM_REP_OFF(otxhdr) = 4678 (lm_replacement_offset - dm_replacement_offset - 4)/2; 4679 } else if (add_sub == 1) { 4680 SOC_OLP_TX_REL_LM_REP_OFF(otxhdr) = 4681 (dm_replacement_offset - lm_replacement_offset + 4)/2; 4682 } 4683 4684 SOC_OLP_TX_REL_LM_REP_OP(otxhdr) = add_sub; 4685 } 4686 } 4687 return BCM_E_NONE; 4688 } 4689 #endif 4690 4691 int _bcm_tx_olp_hdr_fill(int unit, bcm_pkt_t *pkt,soc_olp_tx_hdr_t *otxhdr) 4692 { 4693 int rv = BCM_E_NONE; 4694 int index, max_ctr, max_index; 4695 uint32 pool_number=0; 4696 uint32 base_index=0; 4697 bcm_stat_flex_mode_t offset_mode=0; 4698 bcm_stat_object_t object=bcmStatObjectIngPort; 4699 bcm_stat_group_mode_t group_mode= bcmStatGroupModeSingle; 4700 bcm_stat_flex_direction_t flex_direction = bcmStatFlexDirectionIngress; 4701 int direction = 1;/* Default down mep 4702 direction is EP */ 4703 4704 SOC_OLP_TX_HDR_TYPE(otxhdr) = 0; 4705 4706 if(pkt->flags2 & BCM_PKT_F2_MEP_TYPE_UPMEP) { 4707 SOC_OLP_TX_HDR_STYPE(otxhdr) = 1; 4708 direction = 0; /* For UpMEP direction must be IP */ 4709 } else if (pkt->flags2 & BCM_PKT_F2_MEP_TYPE_SAT_DOWNMEP) { 4710 SOC_OLP_TX_HDR_STYPE(otxhdr) = 2; /* For DnMEP default direction */ 4711 } else if (pkt->flags2 & BCM_PKT_F2_MEP_TYPE_SAT_UPMEP) { 4712 SOC_OLP_TX_HDR_STYPE(otxhdr) = 3; 4713 direction = 0; /* For UpMEP direction must be IP */ 4714 } 4715 SOC_OLP_TX_PRI(otxhdr) = (pkt->flags & BCM_TX_PRIO_INT) ? 4716 pkt->prio_int : pkt->cos; 4717 SOC_OLP_TX_MODID(otxhdr) = pkt->dest_mod; 4718 SOC_OLP_TX_PORT(otxhdr) = pkt->dest_port; 4719 4720 #if defined (BCM_TRIDENT2PLUS_SUPPORT) 4721 if (SOC_IS_TRIDENT2PLUS(unit) || SOC_IS_APACHE(unit)) { 4722 rv = _bcm_td2plus_tx_olp_hdr_ts_lm_offset_fill(unit, pkt, otxhdr); 4723 } 4724 #endif 4725 4726 #if defined (BCM_SABER2_SUPPORT) 4727 if (SOC_IS_SABER2(unit)) { 4728 rv = _bcm_sb2_tx_olp_hdr_ts_lm_offset_fill(unit, pkt, otxhdr); 4729 } 4730 #endif 4731 4732 if (BCM_FAILURE(rv)) { 4733 return rv; 4734 } 4735 4736 /*Counter index*/ 4737 if(pkt->oam_counter_size) { 4738 max_ctr = SOC_IS_TRIDENT2PLUS(unit) ? 4739 (BCM_PKT_OAM_COUNTER_MAX-1) : BCM_PKT_OAM_COUNTER_MAX; 4740 max_index = (pkt->oam_counter_size < max_ctr) ? 4741 pkt->oam_counter_size : max_ctr; 4742 for(index = 0; index < max_index; index++) { 4743 if (pkt->oam_counter[index].counter_object == 4744 bcmOamCounterObjectEndpointId) { 4745 pool_number = 4746 pkt->oam_counter[index].counter_object_id >> 24; 4747 base_index = 4748 pkt->oam_counter[index].counter_object_id & 0xffffff; 4749 4750 switch (pool_number) { 4751 case 0: 4752 SOC_OLP_TX_CTR1_LOCATION(otxhdr) = direction; 4753 SOC_OLP_TX_CTR1_ID(otxhdr) = base_index; 4754 SOC_OLP_TX_CTR1_ACTION(otxhdr) = pkt->oam_counter[index].counter_mode; 4755 break; 4756 case 1: 4757 SOC_OLP_TX_CTR2_LOCATION(otxhdr) = direction; 4758 SOC_OLP_TX_CTR2_ID_SET(otxhdr, base_index); 4759 SOC_OLP_TX_CTR2_ACTION(otxhdr) = pkt->oam_counter[index].counter_mode; 4760 break; 4761 case 2: 4762 #if defined (BCM_SABER2_SUPPORT) 4763 SOC_OLP_TX_CTR3_LOCATION(otxhdr) = direction; 4764 SOC_OLP_TX_CTR3_ID_SET(otxhdr, base_index); 4765 SOC_OLP_TX_CTR3_ACTION(otxhdr) = pkt->oam_counter[index].counter_mode; 4766 #endif 4767 break; 4768 default: 4769 break; 4770 } 4771 } else if (pkt->oam_counter[index].counter_object == 4772 bcmOamCounterObjectFlexStatId) { 4773 _bcm_esw_stat_get_counter_id_info( 4774 unit, pkt->oam_counter[index].counter_object_id, 4775 &group_mode,&object,&offset_mode,&pool_number,&base_index); 4776 BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit,object,&flex_direction)); 4777 BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit,group_mode)); 4778 4779 switch(index) { 4780 case 0: 4781 SOC_OLP_TX_CTR1_LOCATION(otxhdr) = flex_direction; 4782 SOC_OLP_TX_CTR1_ID(otxhdr) = SOC_OLP_TX_CTR(pool_number, 4783 (base_index + pkt->oam_counter[index].counter_offset)); 4784 SOC_OLP_TX_CTR1_ACTION(otxhdr) = pkt->oam_counter[index].counter_mode; 4785 4786 break; 4787 case 1: 4788 SOC_OLP_TX_CTR2_LOCATION(otxhdr) = flex_direction; 4789 SOC_OLP_TX_CTR2_ID_SET(otxhdr,SOC_OLP_TX_CTR(pool_number, 4790 (base_index + pkt->oam_counter[index].counter_offset))); 4791 SOC_OLP_TX_CTR2_ACTION(otxhdr) = pkt->oam_counter[index].counter_mode; 4792 break; 4793 case 2: 4794 #if defined (BCM_APACHE_SUPPORT) 4795 SOC_OLP_TX_CTR3_LOCATION(otxhdr) = flex_direction; 4796 SOC_OLP_TX_CTR3_ID_SET(otxhdr,SOC_OLP_TX_CTR(pool_number, 4797 (base_index + pkt->oam_counter[index].counter_offset))); 4798 SOC_OLP_TX_CTR3_ACTION(otxhdr) = pkt->oam_counter[index].counter_mode; 4799 #endif 4800 break; 4801 default: 4802 break; 4803 } 4804 } 4805 } 4806 } 4807 LOG_DEBUG(BSL_LS_BCM_TX, 4808 (BSL_META_U(0, 4809 "%s,hdr 0x%x,hdrst 0x%x,destmod %d,destport %d,cos %d\n" 4810 "timestamp ac 0x%x, oamOff 0x%x, ctr2 id 0x%x,pool 0x%x, base 0x%x\n"), 4811 __FUNCTION__,SOC_OLP_TX_HDR_TYPE_GET(otxhdr), 4812 SOC_OLP_TX_HDR_STYPE_GET(otxhdr),SOC_OLP_TX_MODID_GET(otxhdr), 4813 SOC_OLP_TX_PORT_GET(otxhdr),SOC_OLP_TX_PRI_GET(otxhdr), 4814 SOC_OLP_TX_TIMESTAMP_ACTION_GET(otxhdr), 4815 SOC_OLP_TX_OAM_OFFSET_GET(otxhdr),SOC_OLP_TX_CTR2_ID_GET(otxhdr),pool_number,base_index)); 4816 4817 shr_olp_tx_header_pack(pkt->_olp_hdr,otxhdr); 4818 return rv; 4819 } 4820 4821 /* 4822 * Function: 4823 * _tx_pkt_olp_desc_add 4824 * Purpose: 4825 * Add all descriptors to a DV for a given packet. 4826 * Parameters: 4827 * unit - Strataswitch device ID 4828 * pkt - Pointer to packet 4829 * dv - DCB vector to update 4830 * pkt_idx - Index of packet. 4831 * Index value is 0, except for arrays or link lists. 4832 * For arrays or link lists, the value must be the 4833 * the index number of the packet. 4834 * Returns: 4835 * BCM_E_XXX 4836 * Notes: 4837 * Uses tx info pkt_count member to get packet index; then advances 4838 * the pkt_count member. 4839 * 4840 * See sdk/doc/pkt.txt for info about restrictions on MACs, 4841 * and the VLAN not crossing block boundaries. 4842 * 4843 * Assert: unit is local 4844 */ 4845 4846 STATIC int 4847 _tx_pkt_olp_desc_add(int unit, bcm_pkt_t *pkt, dv_t *dv, int pkt_idx) 4848 { 4849 int pkt_len = 0; /* Length calculation for byte padding */ 4850 int tmp_len; 4851 int min_len = ENET_MIN_PKT_SIZE; /* Min length pkt before padded */ 4852 int block_offset = 0; 4853 int i; 4854 uint32 dcb_flags = 0; 4855 uint32 *pkt_hg_hdr = NULL; 4856 bcm_pbmp_t tx_pbmp, tx_upbmp, tx_l3pbmp; 4857 soc_persist_t *sop = SOC_PERSIST(unit); 4858 soc_olp_tx_pkt_t opkt; 4859 bcm_port_t sglp; 4860 bcm_module_t modid; 4861 COMPILER_REFERENCE(pkt_idx); /* May not be ref'd depending on defines */ 4862 4863 /* Calculate the DCB flags for this packet. */ 4864 dcb_flags = _dcb_flags_get(unit, pkt, dv); 4865 4866 #if defined(BROADCOM_DEBUG) 4867 if (pkt->cos < BCM_COS_COUNT) { /* COS is unsigned */ 4868 bcm_tx_pkt_count[pkt->cos]++; 4869 } else { 4870 bcm_tx_pkt_count_bad_cos++; 4871 } 4872 #endif /* BROADCOM_DEBUG */ 4873 4874 _soc_tx_pkt_setup(unit, pkt, &dv->tx_param); 4875 4876 BCM_PBMP_ASSIGN(tx_pbmp, pkt->tx_pbmp); 4877 BCM_PBMP_ASSIGN(tx_upbmp, pkt->tx_upbmp); 4878 BCM_PBMP_ASSIGN(tx_l3pbmp, pkt->tx_l3pbmp); 4879 BCM_API_XLATE_PORT_PBMP_A2P(unit, &tx_pbmp); 4880 BCM_API_XLATE_PORT_PBMP_A2P(unit, &tx_upbmp); 4881 BCM_API_XLATE_PORT_PBMP_A2P(unit, &tx_l3pbmp); 4882 4883 /* 4884 * bcm_attach_early_txrx can be used to initialise tx and rx modules before 4885 * other modules. However checking link status of the port has to be avoided 4886 * until warmboot is complete, because the link status will not be available 4887 * until linkscan module is initialised. Port module initialization and link 4888 * module recovery and successful linkscan processing will ensure avoiding 4889 * transmitting the packets to linked down ports. 4890 */ 4891 if (!(pkt->flags & BCM_TX_LINKDOWN_TRANSMIT)) { 4892 if (!SOC_WARM_BOOT(unit)) { 4893 BCM_PBMP_AND(tx_pbmp, sop->lc_pbm_link); 4894 } 4895 } 4896 if (pkt->pkt_data[0].len < sizeof(bcm_mac_t)) { 4897 LOG_INFO(BSL_LS_BCM_TX, 4898 (BSL_META_U(unit, 4899 "_tx_pkt_olp_desc_add: pkt->pkt_data[0].len < sizeof(bcm_mac_t) exit "))); 4900 return BCM_E_PARAM; 4901 } 4902 4903 sal_memset(&opkt, 0, sizeof(soc_olp_tx_pkt_t)); 4904 BCM_PKT_HGHDR_CLR(pkt); 4905 (pkt)->flags &= (~BCM_TX_HG_READY); 4906 pkt_hg_hdr = NULL; 4907 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid)); 4908 _bcm_esw_glp_construct(unit, BCM_TRUNK_INVALID, modid, CMIC_PORT(unit) , &sglp); 4909 _bcm_olp_l2_hdr_get(unit, sglp, 1, &(opkt.l2_hdr)); 4910 4911 if(!BCM_PKT_TX_HAS_OLP_READY(pkt)) { 4912 _bcm_tx_olp_hdr_fill(unit, pkt, &(opkt.tx_hdr)); 4913 } 4914 sal_memcpy((uint8 *)&(opkt.tx_hdr),BCM_PKT_OLP_HDR(pkt),sizeof(soc_olp_tx_hdr_t)); 4915 sal_memcpy(SOC_DV_HG_HDR(dv, pkt_idx),(uint8*) &opkt, sizeof(soc_olp_tx_pkt_t)); 4916 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 4917 (sal_vaddr_t) SOC_DV_HG_HDR(dv, pkt_idx), sizeof(soc_olp_tx_pkt_t), 4918 tx_pbmp, tx_upbmp, tx_l3pbmp, 4919 dcb_flags, (uint32 *)BCM_PKT_OLP_HDR(pkt))); 4920 pkt_len = sizeof(soc_olp_tx_pkt_t); 4921 4922 /* Set up pointer to the packet in TX info structure. */ 4923 TX_INFO_PKT_ADD(dv, pkt); 4924 4925 pkt_hg_hdr = NULL; 4926 SOC_DMA_HG_SET(dcb_flags, 0); 4927 4928 /* Add DCBs for the remainder of the blocks. */ 4929 for (i = block_offset; i < pkt->blk_count; i++) { 4930 tmp_len = pkt->pkt_data[i].len; 4931 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 4932 (sal_vaddr_t) pkt->pkt_data[i].data, 4933 tmp_len, tx_pbmp, tx_upbmp, tx_l3pbmp, 4934 dcb_flags, pkt_hg_hdr)); 4935 pkt_len += tmp_len; 4936 } 4937 4938 /* If CRC allocated, adjust min length */ 4939 if (pkt->flags & BCM_TX_CRC_ALLOC) { 4940 min_len = ENET_MIN_PKT_SIZE - ENET_FCS_SIZE; 4941 } 4942 4943 /* Pad runt packets */ 4944 if ((pkt_len < min_len) && !(pkt->flags & BCM_TX_NO_PAD)) { 4945 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 4946 (sal_vaddr_t) _pkt_pad_ptr, min_len - pkt_len, 4947 tx_pbmp, tx_upbmp, tx_l3pbmp, 4948 dcb_flags, pkt_hg_hdr)); 4949 } 4950 4951 /* If "CRC allocate" set (includes append), add static ptr to it */ 4952 if (pkt->flags & BCM_TX_CRC_ALLOC) { 4953 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 4954 (sal_vaddr_t) _null_crc_ptr, sizeof(uint32), 4955 tx_pbmp, tx_upbmp, tx_l3pbmp, 4956 dcb_flags, pkt_hg_hdr)); 4957 } 4958 /* Mark the end of the packet */ 4959 soc_dma_desc_end_packet(dv); 4960 return BCM_E_NONE; 4961 } 4962 4963 #endif /* BCM_TRIDENT2PLUS_SUPPORT || BCM_SABER2_SUPPORT */ 4964 4965 /* 4966 * Function: 4967 * _tx_pkt_desc_add 4968 * Purpose: 4969 * Add all descriptors to a DV for a given packet. 4970 * Parameters: 4971 * unit - Strataswitch device ID 4972 * pkt - Pointer to packet 4973 * dv - DCB vector to update 4974 * pkt_idx - Index of packet. 4975 * Index value is 0, except for arrays or link lists. 4976 * For arrays or link lists, the value must be the 4977 * the index number of the packet. 4978 * Returns: 4979 * BCM_E_XXX 4980 * Notes: 4981 * Uses tx info pkt_count member to get packet index; then advances 4982 * the pkt_count member. 4983 * 4984 * See sdk/doc/pkt.txt for info about restrictions on MACs, 4985 * and the VLAN not crossing block boundaries. 4986 * 4987 * Assert: unit is local 4988 */ 4989 4990 STATIC int 4991 _tx_pkt_desc_add(int unit, bcm_pkt_t *pkt, dv_t *dv, int pkt_idx) 4992 { 4993 int byte_offset = 0; 4994 int pkt_len = 0; /* Length calculation for byte padding */ 4995 int tmp_len; 4996 int min_len = ENET_MIN_PKT_SIZE; /* Min length pkt before padded */ 4997 uint8 *vlan_ptr = NULL; 4998 uint8 *src_mac; 4999 int block_offset = 0; 5000 int i; 5001 uint32 dcb_flags = 0; 5002 uint32 *pkt_hg_hdr = NULL; 5003 int clear_crc = FALSE; 5004 int crc_block_offset = 0; 5005 bcm_pbmp_t tx_pbmp, tx_upbmp, tx_l3pbmp; 5006 bcm_pbmp_t tx_macpbmp; 5007 soc_persist_t *sop = SOC_PERSIST(unit); 5008 int pb_hdr = 0; 5009 5010 COMPILER_REFERENCE(pkt_idx); /* May not be ref'd depending on defines */ 5011 /* Clear private UNTAG flag */ 5012 #ifdef BCM_SHADOW_SUPPORT 5013 /* BCM88732 device doesn't introduce any headers */ 5014 if (!SOC_IS_SHADOW(unit)) { 5015 #endif 5016 pkt->flags &= (~BCM_PKT_F_TX_UNTAG); 5017 #ifdef BCM_SHADOW_SUPPORT 5018 } 5019 #endif 5020 #if defined (BCM_TRIDENT2PLUS_SUPPORT) || defined (BCM_SABER2_SUPPORT) 5021 if(soc_feature(unit, soc_feature_cpu_as_olp) && 5022 BCM_PKT_TX_OLP(pkt)) { 5023 return _tx_pkt_olp_desc_add(unit, pkt, dv, pkt_idx); 5024 } 5025 #endif 5026 /* Calculate the DCB flags for this packet. */ 5027 dcb_flags = _dcb_flags_get(unit, pkt, dv); 5028 5029 #if defined(BROADCOM_DEBUG) 5030 if (pkt->cos < BCM_COS_COUNT) { /* COS is unsigned */ 5031 bcm_tx_pkt_count[pkt->cos]++; 5032 } else { 5033 bcm_tx_pkt_count_bad_cos++; 5034 } 5035 #endif /* BROADCOM_DEBUG */ 5036 5037 _soc_tx_pkt_setup(unit, pkt, &dv->tx_param); 5038 5039 /* If the CRC is being regenerated and the transmit device 5040 * is a fabric, zero out the last four bytes by subtracting 5041 * four bytes from the end and appending four byte zero'd out 5042 * tx descriptor. 5043 */ 5044 if (SOC_IS_HERCULES1(unit) && 5045 (pkt->flags & BCM_TX_CRC_REGEN) && 5046 (!(pkt->flags & BCM_TX_CRC_ALLOC))) { 5047 5048 /* Assumes the CRC is in the last block containing data */ 5049 for (i = pkt->blk_count - 1; i > 0; i--) { 5050 if (pkt->pkt_data[i].len > 0) { 5051 break; 5052 } 5053 } 5054 byte_offset = pkt->pkt_data[i].len - ENET_FCS_SIZE; 5055 if (byte_offset < 0) { 5056 LOG_WARN(BSL_LS_BCM_TX, 5057 (BSL_META_U(unit, 5058 "TX CRC clear: CRC not contiguous or runt pkt\n"))); 5059 } else { 5060 clear_crc = TRUE; 5061 crc_block_offset = i; 5062 } 5063 } 5064 5065 BCM_PBMP_ASSIGN(tx_pbmp, pkt->tx_pbmp); 5066 BCM_PBMP_ASSIGN(tx_upbmp, pkt->tx_upbmp); 5067 BCM_PBMP_ASSIGN(tx_l3pbmp, pkt->tx_l3pbmp); 5068 BCM_API_XLATE_PORT_PBMP_A2P(unit, &tx_pbmp); 5069 BCM_API_XLATE_PORT_PBMP_A2P(unit, &tx_upbmp); 5070 BCM_API_XLATE_PORT_PBMP_A2P(unit, &tx_l3pbmp); 5071 5072 /* 5073 * bcm_attach_early_txrx can be used to initialise tx and rx modules before 5074 * other modules. However checking link status of the port has to be avoided 5075 * until warmboot is complete, because the link status will not be available 5076 * until linkscan module is initialised. Port module initialization and link 5077 * module recovery and successful linkscan processing will ensure avoiding 5078 * transmitting the packets to linked down ports. 5079 */ 5080 if (!(pkt->flags & BCM_TX_LINKDOWN_TRANSMIT)) { 5081 if (!SOC_WARM_BOOT(unit)) { 5082 soc_link_mask2_get(unit, &tx_macpbmp); 5083 BCM_PBMP_AND(tx_pbmp, tx_macpbmp); 5084 BCM_PBMP_AND(tx_pbmp, sop->lc_pbm_link); 5085 SOC_PBMP_REMOVE(tx_pbmp, sop->lc_pbm_remote_fault); 5086 } 5087 } 5088 if (!SOC_IS_ARAD(unit) && !SOC_IS_DNX(unit)) { 5089 if (BCM_PBMP_IS_NULL(tx_pbmp) && !BCM_PBMP_IS_NULL(pkt->tx_pbmp)) { 5090 return BCM_E_NONE; 5091 } 5092 } 5093 5094 /* 5095 * XGS3 devices do not take TXPBM/TXUBM. 5096 * This is emulated below using PBS TX mode. 5097 * Only used on 5675 now. 5098 */ 5099 #if defined(BCM_XGS12_SUPPORT) 5100 if (soc_feature(unit, soc_feature_tx_fast_path)) { 5101 /* Just set up the packet as is and return */ 5102 if (pkt->flags & BCM_TX_FAST_PATH) { 5103 for (i = 0; i < pkt->blk_count; i++) { 5104 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5105 (sal_vaddr_t) pkt->pkt_data[i].data, pkt->pkt_data[i].len, 5106 tx_pbmp, tx_upbmp, tx_l3pbmp, 5107 dcb_flags, (uint32 *)BCM_PKT_HG_HDR(pkt))); 5108 } 5109 5110 /* Mark the end of the packet */ 5111 soc_dma_desc_end_packet(dv); 5112 5113 return BCM_E_NONE; 5114 } 5115 } 5116 #endif /* BCM_XGS12_SUPPORT */ 5117 5118 if (pkt->pkt_data[0].len < sizeof(bcm_mac_t)) { 5119 LOG_INFO(BSL_LS_BCM_TX, 5120 (BSL_META_U(unit, 5121 "_tx_pkt_desc_add: pkt->pkt_data[0].len < sizeof(bcm_mac_t) exit "))); 5122 return BCM_E_PARAM; 5123 } 5124 5125 /* Get pointers to srcmac and vlan; check if bad block count */ 5126 _get_mac_vlan_ptrs(dv, pkt, &src_mac, &vlan_ptr, &block_offset, 5127 &byte_offset, pkt_idx); 5128 if (block_offset >= pkt->blk_count) { 5129 LOG_INFO(BSL_LS_BCM_TX, 5130 (BSL_META_U(unit, 5131 "_tx_pkt_desc_add: block_offset >= pkt->blk_count exit "))); 5132 return BCM_E_PARAM; 5133 } 5134 5135 if (byte_offset >= pkt->pkt_data[block_offset].len) { 5136 byte_offset = 0; 5137 block_offset++; 5138 } 5139 /* Set up pointer to the packet in TX info structure. */ 5140 TX_INFO_PKT_ADD(dv, pkt); 5141 5142 #ifdef BCM_XGS3_SWITCH_SUPPORT 5143 /* 5144 * XGS3: Decide whether to put Higig header or PB (Pipe Bypass) 5145 * header in the TX descriptor 5146 * 1. Fabric mapped mode (HG header in descriptor) 5147 * 2. Raw Ethernet packet steered mode (PB header in descriptor) 5148 */ 5149 if ((!SOC_IS_SHADOW(unit) && 5150 SOC_IS_XGS3_SWITCH(unit) && 5151 (!BCM_PKT_TX_ETHER(pkt))) || 5152 (pkt->flags2 & BCM_PKT_F2_RX_PORT) || 5153 (pkt->flags2 & BCM_PKT_F2_CPU_TX_PROC)) { 5154 /* 5155 * Raw packet steered mode (PB header in descriptor) 5156 */ 5157 BCM_IF_ERROR_RETURN(_bcm_xgs3_tx_pipe_bypass_header_setup(unit, pkt)); 5158 5159 pkt_hg_hdr = (uint32 *)BCM_PKT_PB_HDR(pkt); 5160 pb_hdr = 1; 5161 } else { 5162 pkt_hg_hdr = (uint32 *)BCM_PKT_HG_HDR(pkt); 5163 if (PBS_MH_START_IS_SET(pkt_hg_hdr)) { 5164 /* A PBSMH tag was supplied. 5165 * Clear the HG flags so the VLAN tag isn't stripped off. 5166 */ 5167 BCM_PKT_HGHDR_CLR(pkt); 5168 (pkt)->flags &= (~BCM_TX_HG_READY); 5169 } 5170 } 5171 #else 5172 pkt_hg_hdr = NULL; 5173 #endif 5174 5175 #ifdef BCM_SHADOW_SUPPORT 5176 if(SOC_IS_SHADOW(unit)) { 5177 /* No Module header for BCM88732 device */ 5178 pkt_hg_hdr = NULL; 5179 SOC_DMA_HG_SET(dcb_flags, 0); 5180 } 5181 #endif 5182 5183 #ifdef BCM_XGS_SUPPORT 5184 /* 5185 * BCM_PKT_F_HGHDR flag indicates higig header is part of 5186 * packet data stream. 5187 */ 5188 5189 if (BCM_PKT_HAS_HGHDR(pkt) 5190 #ifdef BCM_ARAD_SUPPORT 5191 && (!SOC_IS_ARAD(unit)) 5192 #endif 5193 #ifdef BCM_DNX_SUPPORT 5194 && (!SOC_IS_DNX(unit)) 5195 #endif 5196 ) 5197 { 5198 uint8 *tmp_pkt_hg_hdr = BCM_PKT_HG_HDR(pkt); 5199 int hg_hdr_len = SOC_HIGIG_HDR_SIZE; 5200 /* 5201 * XGS3: Raw Higig packet steered mode. 5202 * Make higig header part of packet stream and PB 5203 * header part of descriptor 5204 */ 5205 #ifdef BCM_HIGIG2_SUPPORT 5206 if (tmp_pkt_hg_hdr[0] == SOC_HIGIG2_START) { 5207 hg_hdr_len = SOC_HIGIG2_HDR_SIZE; 5208 } 5209 #endif /* BCM_HIGIG2_SUPPORT */ 5210 sal_memcpy(SOC_DV_HG_HDR(dv, pkt_idx), tmp_pkt_hg_hdr, hg_hdr_len); 5211 if (!soc_feature(unit, soc_feature_cmicx)) { 5212 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5213 (sal_vaddr_t) SOC_DV_HG_HDR(dv, pkt_idx), hg_hdr_len, 5214 tx_pbmp, tx_upbmp, tx_l3pbmp, 5215 dcb_flags, (uint32 *)BCM_PKT_PB_HDR(pkt))); 5216 } 5217 } 5218 #endif /* BCM_XGS_SUPPORT */ 5219 5220 #ifdef BCM_ARAD_SUPPORT 5221 if (SOC_IS_ARAD(unit)) { 5222 pkt_hg_hdr = (uint32 *)((pkt)->_dpp_hdr); 5223 } 5224 #endif 5225 5226 #if defined(ADAPTER_SERVER_MODE) 5227 if (SOC_IS_DNX(unit)) 5228 { 5229 if (pkt->flags & BCM_PKT_F_HGHDR) 5230 { 5231 /* 5232 * Module Header is not supported on cmodel 5233 * Clear BCM_PKT_F_HGHDR, indicate no Module Header 5234 * CPU channel will be register CpuChannel, always 0 by default 5235 */ 5236 pkt->flags &= ~BCM_PKT_F_HGHDR; 5237 SOC_DMA_HG_SET(dcb_flags, 0); 5238 } 5239 } 5240 #elif defined(BCM_DNX_SUPPORT) 5241 if (SOC_IS_DNX(unit)) 5242 { 5243 if (pkt->flags & BCM_PKT_F_HGHDR) 5244 { 5245 /* 5246 * HiGig flag indicates Module header is present, Module Header is 20 bytes at the start of the packet 5247 * Update first byte of Module header to CPU Channel 5248 */ 5249 pkt->pkt_data[0].data[0] = pkt ->_dpp_hdr[0]; 5250 } 5251 } 5252 #endif 5253 5254 5255 if (soc_feature(unit, soc_feature_cmicx) && (pkt_hg_hdr != NULL)) { 5256 if (NULL != pkt->tx_header) { 5257 LOG_ERROR(BSL_LS_BCM_TX, 5258 (BSL_META_U(unit, 5259 "_tx_pkt_desc_add: Cannot re-allocate mem to" 5260 " tx_header as Pkt might me in-flight!!!\n"))); 5261 return BCM_E_MEMORY; 5262 } 5263 5264 if ((pkt->_higig[7] & BCM_TX_EXT_HG_HDR) && !SOC_IS_TOMAHAWK3(unit)) { 5265 pkt->tx_header = soc_cm_salloc(unit, sizeof(pkt->_higig) + sizeof(pkt->_ext_higig), "tx_header"); 5266 if (pkt->tx_header == NULL) { 5267 LOG_INFO(BSL_LS_BCM_TX, 5268 (BSL_META_U(unit, 5269 "_tx_pkt_desc_add: unable to obtain dma'ble memory\n"))); 5270 return BCM_E_MEMORY; 5271 } 5272 sal_memset(pkt->tx_header, 0, sizeof(pkt->_higig) + sizeof(pkt->_ext_higig)); 5273 } else { 5274 pkt->tx_header = soc_cm_salloc(unit, sizeof(pkt->_higig), "tx_header"); 5275 if (pkt->tx_header == NULL) { 5276 LOG_INFO(BSL_LS_BCM_TX, 5277 (BSL_META_U(unit, 5278 "_tx_pkt_desc_add: unable to obtain dma'ble memory\n"))); 5279 return BCM_E_MEMORY; 5280 } 5281 sal_memset(pkt->tx_header, 0, sizeof(pkt->_higig)); 5282 } 5283 5284 if (SOC_DMA_HG_GET(dcb_flags)) { 5285 if (pb_hdr == 1) { 5286 /* We cannot have pkt_hg_dhr as NULL, This is also checked in SOC_DMA_HG_GET */ 5287 /* coverity[var_deref_model] */ 5288 sal_memcpy(pkt->tx_header, pkt_hg_hdr, sizeof(pkt->_pb_hdr)); 5289 } else { 5290 sal_memcpy(pkt->tx_header, pkt_hg_hdr, sizeof(pkt->_higig)); 5291 } 5292 5293 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5294 (sal_vaddr_t)(uint8 *)pkt->tx_header, sizeof(pkt->_higig), 5295 tx_pbmp, tx_upbmp, tx_l3pbmp, 5296 dcb_flags, pkt_hg_hdr)); 5297 } 5298 5299 /* 5300 * BCM_PKT_F_HGHDR flag indicates higig header is part of 5301 * packet data stream. 5302 */ 5303 if ((pb_hdr == 1) && BCM_PKT_HAS_HGHDR(pkt)) { 5304 uint8 *tmp_hg_hdr = BCM_PKT_HG_HDR(pkt); 5305 int hg_hdr_len = SOC_HIGIG_HDR_SIZE; 5306 5307 #ifdef BCM_HIGIG2_SUPPORT 5308 if (tmp_hg_hdr[0] == SOC_HIGIG2_START) { 5309 hg_hdr_len = SOC_HIGIG2_HDR_SIZE; 5310 } 5311 #endif /* BCM_HIGIG2_SUPPORT */ 5312 5313 sal_memcpy(SOC_DV_HG_HDR(dv, pkt_idx), tmp_hg_hdr, hg_hdr_len); 5314 5315 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5316 (sal_vaddr_t) SOC_DV_HG_HDR(dv, pkt_idx), hg_hdr_len, 5317 tx_pbmp, tx_upbmp, tx_l3pbmp, 5318 dcb_flags, (uint32 *)BCM_PKT_PB_HDR(pkt))); 5319 } 5320 5321 if ((pkt->_higig[7] & BCM_TX_EXT_HG_HDR) && !SOC_IS_TOMAHAWK3(unit)) { 5322 uint8 *c = (uint8 *)pkt->tx_header; 5323 c += sizeof(pkt->_higig); 5324 5325 sal_memcpy(c, pkt->_ext_higig, sizeof(pkt->_ext_higig)); 5326 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5327 (sal_vaddr_t)(uint8 *)c, sizeof(pkt->_ext_higig), 5328 tx_pbmp, tx_upbmp, tx_l3pbmp, 5329 dcb_flags, pkt_hg_hdr)); 5330 } 5331 5332 if (bsl_check(bslLayerSoc, bslSourceTx, bslSeverityVerbose, unit)) { 5333 soc_dma_higig_dump(unit, "TX Header ", (uint8 *)pkt->tx_header, sizeof(pkt->_higig), 0, NULL); 5334 } 5335 } else { 5336 pkt->tx_header = NULL; 5337 } 5338 5339 #ifdef BCM_XGS_SUPPORT 5340 #ifdef BCM_INSTRUMENTATION_SUPPORT 5341 if ((soc_feature(unit, soc_feature_visibility)) && 5342 (pkt->flags2 & BCM_PKT_F2_RX_PORT)) { 5343 5344 bcm_gport_t visibility_source_gport; 5345 soc_loopback_hdr_t loopback_hdr; 5346 bcm_trunk_t pkt_trace_src_tgid; 5347 bcm_port_t pkt_trace_src_pp_port; 5348 int id; 5349 bcm_module_t pkt_trace_src_modid; 5350 uint16 pkt_trace_src; 5351 uint32 visibility_cpu_profile_id = 0; 5352 uint32 pkt_trace_src_port = pkt->rx_port; 5353 SOC_IF_ERROR_RETURN(bcm_port_gport_get(unit, pkt_trace_src_port, 5354 &visibility_source_gport)); 5355 5356 SOC_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, visibility_source_gport, 5357 &pkt_trace_src_modid, &pkt_trace_src_pp_port, 5358 &pkt_trace_src_tgid, &id)); 5359 pkt_trace_src = (pkt_trace_src_modid << 8) | (pkt_trace_src_pp_port & 0xFF); 5360 5361 sal_memset(&loopback_hdr, 0, sizeof(soc_loopback_hdr_t)); 5362 soc_loopback_hdr_field_set(unit, &loopback_hdr, LBMH_start, START_LBMH_HDR); 5363 soc_loopback_hdr_field_set(unit, &loopback_hdr, LBMH_pp_port, pkt_trace_src_port); 5364 /* LBMH_src is GPP associate with pp_port, and modid, 5365 in tomahawk, GPP is same as the logical port number */ 5366 soc_loopback_hdr_field_set(unit, &loopback_hdr, LBMH_src, pkt_trace_src ); 5367 5368 /* fixed configuration of loopback header for visibilty packet */ 5369 if (SOC_IS_TRIDENT3X(unit)) { 5370 soc_loopback_hdr_field_set(unit, &loopback_hdr, LBMH_common_hdr, TD3X_LBMH_HDR); 5371 } else { 5372 soc_loopback_hdr_field_set(unit, &loopback_hdr, LBMH_common_hdr, COMMON_LBMH_HDR); 5373 } 5374 5375 soc_loopback_hdr_field_set(unit, &loopback_hdr, LBMH_src_type, SRC_TYPE_GPP_LBMH_HDR); 5376 if (pkt->flags2 & BCM_PKT_F2_VISIBILITY_PKT) { 5377 soc_loopback_hdr_field_set(unit, &loopback_hdr, LBMH_visibility, VIS_LBMH_HDR); 5378 BCM_IF_ERROR_RETURN(_bcm_esw_pkt_trace_cpu_profile_get( 5379 unit, &visibility_cpu_profile_id)); 5380 soc_loopback_hdr_field_set(unit, &loopback_hdr, 5381 LBMH_pkt_profile, visibility_cpu_profile_id); 5382 } else { 5383 /* set masquerade packet profile to default - learn, forward, and ifp apply */ 5384 soc_loopback_hdr_field_set(unit, &loopback_hdr, 5385 LBMH_pkt_profile, 2); 5386 } 5387 5388 sal_memcpy(SOC_DV_HG_HDR(dv, pkt_idx), &loopback_hdr, LOOPBACK_HDR_SIZE); 5389 5390 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5391 (sal_vaddr_t) SOC_DV_HG_HDR(dv, pkt_idx), LOOPBACK_HDR_SIZE, 5392 tx_pbmp, tx_upbmp, tx_l3pbmp, 5393 dcb_flags, pkt_hg_hdr)); 5394 5395 if (bsl_check(bslLayerSoc, bslSourceTx, bslSeverityVerbose, unit)) { 5396 soc_loopback_hdr_dump(unit, "Loopback Header", &loopback_hdr); 5397 } 5398 } 5399 #endif /* BCM_INSTRUMENTATION_SUPPORT */ 5400 #endif 5401 5402 #ifdef BCM_XGS_SUPPORT 5403 #ifdef BCM_CPU_TX_PROC_SUPPORT 5404 if ((soc_feature(unit, soc_feature_cpu_tx_proc)) && 5405 (pkt->flags2 & BCM_PKT_F2_CPU_TX_PROC)) { 5406 int id; 5407 bcm_gport_t proc_hdr_source_gport; 5408 soc_proc_hdr_t proc_hdr; 5409 bcm_trunk_t proc_hdr_src_tgid; 5410 bcm_port_t proc_hdr_src_pp_port; 5411 bcm_module_t proc_hdr_src_modid; 5412 uint16 proc_hdr_src; 5413 uint32 proc_hdr_cpu_profile_id = 0; 5414 5415 #ifdef BCM_TOMAHAWK3_SUPPORT 5416 if ((pkt->rx_port == _TH3_MMU_SPARE_SRC_PORT) && SOC_IS_TOMAHAWK3(unit)) { 5417 proc_hdr_src_modid = 0; 5418 proc_hdr_src_pp_port = pkt->rx_port; 5419 } else 5420 #endif 5421 { 5422 SOC_IF_ERROR_RETURN(bcm_port_gport_get(unit, pkt->rx_port, 5423 &proc_hdr_source_gport)); 5424 5425 SOC_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, proc_hdr_source_gport, 5426 &proc_hdr_src_modid, &proc_hdr_src_pp_port, 5427 &proc_hdr_src_tgid, &id)); 5428 } 5429 5430 proc_hdr_src = (proc_hdr_src_modid << 8) | (proc_hdr_src_pp_port & 0xFF); 5431 5432 sal_memset(&proc_hdr, 0, sizeof(soc_proc_hdr_t)); 5433 5434 /* fixed configuration of cpu tx proc packet */ 5435 soc_proc_hdr_field_set(unit, &proc_hdr, PH_start, SOC_TX_PROC_START); 5436 soc_proc_hdr_field_set(unit, &proc_hdr, PH_header_types, SOC_TX_PROC_ETHERNET_HEADER_TYPE); 5437 soc_proc_hdr_field_set(unit, &proc_hdr, PH_source_type, SOC_TX_PROC_SOURCE_TYPE); 5438 soc_proc_hdr_field_set(unit, &proc_hdr, PH_visibility_pkt, SOC_TX_PROC_VISIBILITY_PKT); 5439 soc_proc_hdr_field_set(unit, &proc_hdr, PH_subflow_type, SOC_TX_PROC_SUBFLOW_TYPE); 5440 5441 soc_proc_hdr_field_set(unit, &proc_hdr, PH_pp_port, pkt->rx_port); 5442 /* 5443 * LBMH_src is GPP associate with pp_port, and modid, 5444 * GPP is same as the logical port number 5445 */ 5446 soc_proc_hdr_field_set(unit, &proc_hdr, PH_source, proc_hdr_src); 5447 5448 /* Program the destination type/opcode and destination */ 5449 soc_proc_hdr_field_set(unit, &proc_hdr, PH_destination_type, pkt->txprocmh_destination_type); 5450 5451 if ((pkt->txprocmh_destination_type == SOC_TX_PROC_OP_ECMP_MEMBER) || 5452 (pkt->txprocmh_destination_type == SOC_TX_PROC_OP_ECMP)) { 5453 soc_proc_hdr_field_set(unit, &proc_hdr, PH_destination, pkt->txprocmh_ecmp_group_index); 5454 } else { 5455 soc_proc_hdr_field_set(unit, &proc_hdr, PH_destination, pkt->txprocmh_destination); 5456 } 5457 5458 if (pkt->txprocmh_destination_type == SOC_TX_PROC_OP_ECMP_MEMBER) { 5459 soc_proc_hdr_field_set(unit, &proc_hdr, PH_ecmp_member_id, pkt->txprocmh_ecmp_member_index); 5460 } 5461 5462 if (pkt->txprocmh_mcast_lb_index_valid) { 5463 soc_proc_hdr_field_set(unit, &proc_hdr, PH_mcast_lb_idx_valid, pkt->txprocmh_mcast_lb_index_valid); 5464 soc_proc_hdr_field_set(unit, &proc_hdr, PH_mcast_lb_idx, pkt->txprocmh_mcast_lb_index); 5465 } 5466 5467 if (pkt->txprocmh_qos_fields_valid) { 5468 uint32 prio_int, color; 5469 soc_proc_hdr_field_set(unit, &proc_hdr, PH_qos_fields_valid, pkt->txprocmh_qos_fields_valid); 5470 5471 prio_int = (pkt->flags & BCM_TX_PRIO_INT) ? pkt->prio_int : pkt->cos; 5472 5473 soc_proc_hdr_field_set(unit, &proc_hdr, PH_int_pri, prio_int); 5474 5475 if (pkt->flags2 & BCM_PKT_F2_CONG_INT) { 5476 soc_proc_hdr_field_set(unit, &proc_hdr, PH_int_cn, pkt->txprocmh_congestion_int); 5477 } 5478 5479 switch (pkt->color) { 5480 case bcmColorGreen: 5481 color = 0; 5482 break; 5483 case bcmColorYellow: 5484 color = 3; 5485 break; 5486 case bcmColorRed: 5487 color = 1; 5488 break; 5489 case bcmColorBlack: 5490 default: 5491 return BCM_E_PARAM; 5492 } 5493 soc_proc_hdr_field_set(unit, &proc_hdr, PH_dp, color); 5494 } 5495 5496 if (pkt->flags & BCM_PKT_F_ROUTED) { 5497 soc_proc_hdr_field_set(unit, &proc_hdr, PH_routed_pkt, SOC_TX_PROC_ROUTED_PKT); 5498 } 5499 5500 soc_proc_hdr_field_set(unit, &proc_hdr, 5501 PH_pkt_profile, proc_hdr_cpu_profile_id); 5502 5503 /* Move the cpu tx proc hdr to dma capable memory */ 5504 sal_memcpy(SOC_DV_HG_HDR(dv, pkt_idx), &proc_hdr, SOC_PROC_HDR_SIZE); 5505 5506 /* Add a descriptor for the cpu tx proc header to the chain */ 5507 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5508 (sal_vaddr_t) SOC_DV_HG_HDR(dv, pkt_idx), SOC_PROC_HDR_SIZE, 5509 tx_pbmp, tx_upbmp, tx_l3pbmp, 5510 dcb_flags, pkt_hg_hdr)); 5511 5512 if (bsl_check(bslLayerSoc, bslSourceTx, bslSeverityVerbose, unit)) { 5513 soc_proc_hdr_dump(unit, "CPU_TX_PROC Header ", &proc_hdr); 5514 } 5515 } 5516 #endif /* BCM_CPU_TX_PROC_SUPPORT */ 5517 #endif 5518 5519 /* Dest mac */ 5520 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5521 (sal_vaddr_t) pkt->pkt_data[0].data, sizeof(bcm_mac_t), 5522 tx_pbmp, tx_upbmp, tx_l3pbmp, 5523 dcb_flags, pkt_hg_hdr)); 5524 pkt_len = ENET_MAC_SIZE; 5525 5526 /* Source mac */ 5527 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5528 (sal_vaddr_t) src_mac, sizeof(bcm_mac_t), 5529 tx_pbmp, tx_upbmp, tx_l3pbmp, 5530 dcb_flags, pkt_hg_hdr)); 5531 5532 pkt_len += ENET_MAC_SIZE; 5533 5534 /* VLAN tag */ 5535 /* No VLAN tag for Fabric mapped Higig TX as well */ 5536 if ((!BCM_PKT_HAS_HGHDR(pkt) 5537 #ifdef BCM_ARAD_SUPPORT 5538 ||(BCM_PKT_HAS_HGHDR(pkt) && SOC_IS_ARAD(unit)) 5539 #endif 5540 #ifdef BCM_DNX_SUPPORT 5541 ||(BCM_PKT_HAS_HGHDR(pkt) && SOC_IS_DNX(unit)) 5542 #endif 5543 ) 5544 && !(pkt->flags & BCM_PKT_F_TX_UNTAG) 5545 && !BCM_PKT_TX_FABRIC_MAPPED(pkt) && (vlan_ptr != NULL)) 5546 { /* No HG Hdr, so add VLAN tag */ 5547 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5548 (sal_vaddr_t) vlan_ptr, sizeof(uint32), 5549 tx_pbmp, tx_upbmp, tx_l3pbmp, 5550 dcb_flags, pkt_hg_hdr)); 5551 pkt_len += sizeof(uint32); 5552 } 5553 #ifdef BCM_HIGIG2_SUPPORT 5554 else if (pkt->stk_flags & BCM_PKT_STK_F_TX_TAG) { 5555 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5556 (sal_vaddr_t) vlan_ptr, sizeof(uint32), 5557 tx_pbmp, tx_upbmp, tx_l3pbmp, 5558 dcb_flags, pkt_hg_hdr)); 5559 } 5560 #endif /* BCM_HIGIG2_SUPPORT */ 5561 5562 /* SL TAG */ 5563 if (pkt->flags & BCM_PKT_F_SLTAG) { 5564 sal_memcpy(SOC_DV_SL_TAG(dv, pkt_idx), pkt->_sltag, sizeof(uint32)); 5565 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5566 (sal_vaddr_t)SOC_DV_SL_TAG(dv, pkt_idx), sizeof(uint32), 5567 tx_pbmp, tx_upbmp, tx_l3pbmp, 5568 dcb_flags, pkt_hg_hdr)); 5569 } 5570 5571 /* 5572 * If byte offset indicates we're not at the end of a packet's data 5573 * block, add a DCB for the rest of the current block. 5574 */ 5575 if (byte_offset != 0) { 5576 tmp_len = pkt->pkt_data[block_offset].len - byte_offset; 5577 if (clear_crc && (block_offset == crc_block_offset)) { 5578 tmp_len -= ENET_FCS_SIZE; 5579 } 5580 #ifdef BCM_ARAD_SUPPORT 5581 if (((pkt->flags & BCM_TX_CRC_REGEN) && (!(pkt->flags & BCM_TX_CRC_ALLOC))) 5582 && (pkt->pkt_data[block_offset].len >= ENET_MIN_PKT_SIZE) && SOC_IS_ARAD(unit)) { 5583 tmp_len -= ENET_FCS_SIZE; /*For DNX CRC regen,subtract CRC len*/ 5584 } 5585 #endif /*BCM_ARAD_SUPPORT*/ 5586 #ifdef BCM_DNX_SUPPORT 5587 if (((pkt->flags & BCM_TX_CRC_REGEN) && (!(pkt->flags & BCM_TX_CRC_ALLOC))) 5588 && SOC_IS_DNX(unit)) 5589 { 5590 /** Last 4 bytes of packet are taken as CRC field */ 5591 tmp_len -= ENET_FCS_SIZE; 5592 } 5593 #endif /*BCM_DNX_SUPPORT*/ 5594 5595 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5596 (sal_vaddr_t) &pkt->pkt_data[block_offset].data[byte_offset], 5597 tmp_len, tx_pbmp, tx_upbmp, tx_l3pbmp, 5598 dcb_flags, pkt_hg_hdr)); 5599 block_offset++; 5600 pkt_len += tmp_len; 5601 } 5602 5603 /* Add DCBs for the remainder of the blocks. */ 5604 for (i = block_offset; i < pkt->blk_count; i++) { 5605 tmp_len = pkt->pkt_data[i].len; 5606 if (clear_crc && (i == crc_block_offset)) { 5607 tmp_len -= ENET_FCS_SIZE; 5608 } 5609 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5610 (sal_vaddr_t) pkt->pkt_data[i].data, 5611 tmp_len, tx_pbmp, tx_upbmp, tx_l3pbmp, 5612 dcb_flags, pkt_hg_hdr)); 5613 pkt_len += tmp_len; 5614 } 5615 5616 /* If CRC allocated, adjust min length */ 5617 if (((pkt->flags & BCM_TX_CRC_ALLOC) || clear_crc) 5618 #ifdef BCM_ARAD_SUPPORT 5619 && !SOC_IS_ARAD(unit) /*DNX device has different MAC behavior*/ 5620 #endif /*BCM_ARAD_SUPPORT*/ 5621 #ifdef BCM_DNX_SUPPORT 5622 && !SOC_IS_DNX(unit) /*Dune device has different MAC behavior*/ 5623 #endif /*BCM_DNX_SUPPORT*/ 5624 ) { 5625 min_len = ENET_MIN_PKT_SIZE - ENET_FCS_SIZE; 5626 } 5627 #ifdef BCM_DNX_SUPPORT 5628 if (SOC_IS_DNX(unit)) 5629 { 5630 /** Module Header */ 5631 min_len += 16; 5632 } 5633 #endif 5634 5635 /* Pad runt packets */ 5636 if ((pkt_len < min_len) && !(pkt->flags & BCM_TX_NO_PAD)) { 5637 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5638 (sal_vaddr_t) _pkt_pad_ptr, min_len - pkt_len, 5639 tx_pbmp, tx_upbmp, tx_l3pbmp, 5640 dcb_flags, pkt_hg_hdr)); 5641 } 5642 5643 /* If "CRC allocate" set (includes append), add static ptr to it */ 5644 if (((pkt->flags & BCM_TX_CRC_ALLOC) || clear_crc) 5645 #ifdef BCM_ARAD_SUPPORT 5646 && !SOC_IS_ARAD(unit) 5647 #endif /*BCM_ARAD_SUPPORT*/ 5648 #ifdef BCM_DNX_SUPPORT 5649 && !SOC_IS_DNX(unit) 5650 #endif /*BCM_DNX_SUPPORT*/ 5651 5652 ) { 5653 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5654 (sal_vaddr_t) _null_crc_ptr, sizeof(uint32), 5655 tx_pbmp, tx_upbmp, tx_l3pbmp, 5656 dcb_flags, pkt_hg_hdr)); 5657 } 5658 5659 /* Mark the end of the packet */ 5660 soc_dma_desc_end_packet(dv); 5661 5662 return BCM_E_NONE; 5663 } 5664 5665 #if defined(BCM_PETRA_SUPPORT) || defined(BCM_DNX_SUPPORT) 5666 /* 5667 * Function: 5668 * _sand_tx_pkt_desc_add 5669 * Purpose: 5670 * Add all descriptors to a DV for a given packet. 5671 * Parameters: 5672 * unit - Strataswitch device ID 5673 * pkt - Pointer to packet 5674 * dv - DCB vector to update 5675 * pkt_idx - Index of packet. 5676 * Index value is 0, except for arrays or link lists. 5677 * For arrays or link lists, the value must be the 5678 * the index number of the packet. 5679 * Returns: 5680 * BCM_E_XXX 5681 * Notes: 5682 * Uses tx info pkt_count member to get packet index; then advances 5683 * the pkt_count member. 5684 * 5685 * See sdk/doc/pkt.txt for info about restrictions on MACs, 5686 * and the VLAN not crossing block boundaries. 5687 * 5688 * Assert: unit is local 5689 */ 5690 5691 STATIC int 5692 _sand_tx_pkt_desc_add(int unit, bcm_pkt_t *pkt, dv_t *dv, int pkt_idx) 5693 { 5694 int pkt_len = 0; /* Length calculation for byte padding */ 5695 int tmp_len = 0; 5696 int min_len = ENET_MIN_PKT_SIZE; /* Min length pkt before padded */ 5697 int i = 0; 5698 uint32 dcb_flags = 0; 5699 int crc_block_offset = 0; 5700 uint32 *pkt_hg_hdr = NULL; 5701 5702 /* May not be ref'd depending on defines */ 5703 COMPILER_REFERENCE(pkt_idx); 5704 5705 /* Calculate the DCB flags for this packet. */ 5706 dcb_flags = _dcb_flags_get(unit, pkt, dv); 5707 5708 #if defined(BROADCOM_DEBUG) 5709 if (pkt->cos < BCM_COS_COUNT) 5710 { 5711 bcm_tx_pkt_count[pkt->cos]++; 5712 } 5713 else 5714 { 5715 bcm_tx_pkt_count_bad_cos++; 5716 } 5717 #endif 5718 5719 if (pkt->pkt_data[0].len < sizeof(bcm_mac_t)) 5720 { 5721 LOG_INFO(BSL_LS_BCM_TX, 5722 (BSL_META_U(unit, 5723 "_tx_pkt_desc_add: pkt->pkt_data[0].len < sizeof(bcm_mac_t) exit "))); 5724 return BCM_E_PARAM; 5725 } 5726 5727 /* Set up pointer to the packet in TX info structure. */ 5728 TX_INFO_PKT_ADD(dv, pkt); 5729 5730 /* Assumes the CRC is in the last block containing data */ 5731 for (i = pkt->blk_count - 1; i >= 0; i--) 5732 { 5733 if (pkt->pkt_data[i].len > 0) 5734 { 5735 break; 5736 } 5737 } 5738 if (pkt->pkt_data[i].len >= ENET_MIN_PKT_SIZE) 5739 { 5740 crc_block_offset = i; 5741 } 5742 else 5743 { 5744 LOG_WARN(BSL_LS_BCM_TX, 5745 (BSL_META_U(unit, 5746 "TX CRC clear: CRC not contiguous or runt pkt\n"))); 5747 } 5748 5749 #if defined(ADAPTER_SERVER_MODE) 5750 if (SOC_IS_DNX(unit)) 5751 { 5752 if (pkt->flags & BCM_PKT_F_HGHDR) 5753 { 5754 /* 5755 * Module Header is not supported on cmodel 5756 * Clear BCM_PKT_F_HGHDR, indicate no Module Header 5757 */ 5758 pkt->flags &= ~BCM_PKT_F_HGHDR; 5759 SOC_DMA_HG_SET(dcb_flags, 0); 5760 } 5761 } 5762 #endif 5763 5764 if (SOC_IS_ARAD(unit)) 5765 { 5766 pkt_hg_hdr = (uint32 *)((pkt)->_dpp_hdr); 5767 } 5768 5769 if (SOC_IS_DNX(unit)) 5770 { 5771 if (pkt->flags & BCM_PKT_F_HGHDR) 5772 { 5773 /* 5774 * Update CPU channel value here 5775 * HiGig flag indicates Module header is present, Module Header is 16 bytes at the start of the packet 5776 * Update first byte of Module header to CPU Channel 5777 */ 5778 pkt->pkt_data[0].data[0] = pkt ->_dpp_hdr[0]; 5779 } 5780 } 5781 5782 /* Add DCBs for the remainder of the blocks. */ 5783 for (i = 0; i <= crc_block_offset; i++) { 5784 tmp_len = pkt->pkt_data[i].len; 5785 5786 /* 5787 * BCM_TX_CRC_ALLOC: append 4 bytes CRC to packet data, default action, so BCM_TX_CRC_ALLOC we do nothing 5788 * BCM_TX_CRC_REGEN: regenerate 4 bytes CRC at last 4 bytes of packet data, remove last 4 bytes at first, HW appends 4 bytes CRC. 5789 */ 5790 if ((i == crc_block_offset) && ((pkt->flags & BCM_TX_CRC_REGEN) && (!(pkt->flags & BCM_TX_CRC_ALLOC)))) { 5791 tmp_len -= ENET_FCS_SIZE; 5792 } 5793 5794 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5795 (sal_vaddr_t) pkt->pkt_data[i].data, 5796 tmp_len, pkt->tx_pbmp, pkt->tx_upbmp, pkt->tx_l3pbmp, 5797 dcb_flags, pkt_hg_hdr)); 5798 pkt_len += tmp_len; 5799 } 5800 5801 if (SOC_IS_DNX(unit)) 5802 { 5803 /* Module Header */ 5804 min_len += 16; 5805 } 5806 5807 /* Pad runt packets */ 5808 if ((pkt_len < min_len) && !(pkt->flags & BCM_TX_NO_PAD)) { 5809 SOC_IF_ERROR_RETURN(SOC_DCB_ADDTX(unit, dv, 5810 (sal_vaddr_t) _pkt_pad_ptr, min_len - pkt_len, 5811 pkt->tx_pbmp, pkt->tx_upbmp, pkt->tx_l3pbmp, 5812 dcb_flags, pkt_hg_hdr)); 5813 } 5814 5815 /* Mark the end of the packet */ 5816 soc_dma_desc_end_packet(dv); 5817 5818 return BCM_E_NONE; 5819 } 5820 #endif 5821 5822 /**************************************************************** 5823 * 5824 * Functions to handle callbacks: 5825 * 5826 * _bcm_tx_callback_thread: The non-interrupt thread that manages 5827 * packet done completions. 5828 * _bcm_tx_chain_done_cb: The interrupt handler callback for chain 5829 * done. Adds dv-s to pending list. 5830 * _bcm_tx_chain_done: Makes user level call back and 5831 * frees the DV. 5832 * _bcm_tx_packet_done_cb: Interrupt handler for packet done. 5833 * Adds pkt to callback list if needed. 5834 * _bcm_tx_packet_done: Makes user level call back. 5835 */ 5836 /* 5837 * Function: 5838 * _bcm_tx_callback_thread 5839 * Purpose: 5840 * Non-interrupt tx callback context 5841 * Parameters: 5842 * param - ignored 5843 * Returns: 5844 * BCM_E_XXX 5845 * Notes: 5846 * Currently assumes that the packet done interrupt will 5847 * be handled before (or at same time) as the corresponding 5848 * chain done interrupt. This only matters when there's 5849 * a per-packet callback since that refers to the cookie 5850 * in the dv. 5851 */ 5852 STATIC void 5853 _bcm_tx_callback_thread(void *param) 5854 { 5855 int free_number = 0; 5856 dv_t *dv_list, *dv, *dv_next; 5857 dv_t *dvdesc_list, *dvdesc, *dvdesc_next, *dvdesc_list_end; 5858 dv_t *dvrld_list, *dvrld, *dvrld_next, *dvrld_list_end; 5859 bcm_pkt_t *pkt_list, *pkt, *pkt_next, *pkt_list_end; 5860 dcb_t * null_dcb = NULL; 5861 5862 COMPILER_REFERENCE(param); 5863 5864 #ifdef BCM_DNX_SUPPORT 5865 DNX_ERR_RECOVERY_UTILS_EXCLUDED_THREADS_ADD_ALL_UNITS(); 5866 #endif 5867 5868 while (1) { 5869 if (sal_sem_take(tx_cb_sem, sal_sem_FOREVER) < 0) { 5870 LOG_ERROR(BSL_LS_BCM_TX, 5871 (BSL_META("TX callback thread error\n"))); 5872 break; 5873 } 5874 if (_tx_init == FALSE) { 5875 break; 5876 } 5877 TX_SPIN_LOCK(); /* Grab the lists from the interrupt handler */ 5878 dv_list = (dv_t *)dv_pend_first; 5879 dv_pend_first = dv_pend_last = NULL; 5880 dvdesc_list = (dv_t *)dvdesc_pend_first; 5881 dvdesc_list_end = (dv_t *)dvdesc_pend_last; 5882 dvdesc_pend_first = dvdesc_pend_last = NULL; 5883 dvrld_list = (dv_t *)dvrld_pend_first; 5884 dvrld_list_end = (dv_t *)dvrld_pend_last; 5885 dvrld_pend_first = dvrld_pend_last = NULL; 5886 pkt_list = (bcm_pkt_t *)pkt_pend_first; 5887 pkt_list_end = (bcm_pkt_t *)pkt_pend_last; 5888 pkt_pend_first = pkt_pend_last = NULL; 5889 TX_SPIN_UNLOCK(); 5890 5891 /* 5892 * Handle the per pkt callbacks first (which use DVs), 5893 * then the DVs. See notes above 5894 */ 5895 pkt = pkt_list; 5896 while (pkt) { 5897 pkt_next = pkt->_next; 5898 _bcm_tx_packet_done(pkt); 5899 5900 if (pkt == pkt_list_end) { 5901 break; 5902 } 5903 pkt = pkt_next; 5904 } 5905 5906 dvdesc = dvdesc_list; 5907 while (dvdesc) { 5908 /* 5909 * In continuous mode, we must process the 5910 * controlled descriptor done interrupts for data desc 5911 */ 5912 dvdesc_next = TX_DV_NEXT(dvdesc); 5913 5914 DNXC_MTA(dnxc_multithread_analyzer_declare_api_in_play(dvdesc->dv_unit, __FUNCTION__, MTA_FLAG_THREAD_MAIN_FUNC, TRUE)); 5915 _bcm_tx_desc_done(dvdesc->dv_unit, dvdesc, null_dcb); 5916 DNXC_MTA(dnxc_multithread_analyzer_declare_api_in_play(dvdesc->dv_unit, __FUNCTION__, MTA_FLAG_THREAD_MAIN_FUNC, FALSE)); 5917 5918 if (dvdesc == dvdesc_list_end) { 5919 break; 5920 } 5921 dvdesc = dvdesc_next; 5922 } 5923 5924 LOG_DEBUG(BSL_LS_BCM_TX, 5925 (BSL_META_U(0, 5926 "rld list start=%p end=%p\n"), 5927 (void *)dvrld_list, (void *)dvrld_list_end)); 5928 dvrld = dvrld_list; 5929 while (dvrld) { 5930 /* 5931 * In continuous mode, we must process the 5932 * controlled descriptor done interrupts for rld desc 5933 */ 5934 LOG_DEBUG(BSL_LS_BCM_TX, 5935 (BSL_META_U(0, 5936 "looping through rld list cur_dv=%p\n"), 5937 (void *)dvrld)); 5938 dvrld_next = TX_DV_NEXT(dvrld); 5939 5940 DNXC_MTA(dnxc_multithread_analyzer_declare_api_in_play(dvrld->dv_unit, __FUNCTION__, MTA_FLAG_THREAD_MAIN_FUNC, TRUE)); 5941 _bcm_tx_reload_done(dvrld->dv_unit, dvrld); 5942 DNXC_MTA(dnxc_multithread_analyzer_declare_api_in_play(dvrld->dv_unit, __FUNCTION__, MTA_FLAG_THREAD_MAIN_FUNC, FALSE)); 5943 5944 if (dvrld != NULL) { 5945 free_number++; 5946 } 5947 if (dvrld == dvrld_list_end) { 5948 break; 5949 } 5950 dvrld = dvrld_next; 5951 } 5952 5953 dv = dv_list; 5954 while (dv) { 5955 /* Chain done may deallocate dv */ 5956 dv_next = TX_DV_NEXT(dv); 5957 5958 DNXC_MTA(dnxc_multithread_analyzer_declare_api_in_play(dv->dv_unit, __FUNCTION__, MTA_FLAG_THREAD_MAIN_FUNC, TRUE)); 5959 _bcm_tx_chain_done(dv->dv_unit, dv); 5960 DNXC_MTA(dnxc_multithread_analyzer_declare_api_in_play(dv->dv_unit, __FUNCTION__, MTA_FLAG_THREAD_MAIN_FUNC, FALSE)); 5961 5962 dv = dv_next; 5963 free_number++; 5964 } 5965 5966 LOG_VERBOSE(BSL_LS_BCM_TX, 5967 (BSL_META("TX callback thread free number of dv is %d\n"), 5968 free_number)); 5969 if (free_number) { 5970 sal_sem_give(tx_dv_done); 5971 } 5972 free_number = 0; 5973 } 5974 _tx_tid = SAL_THREAD_ERROR; 5975 (void)sal_sem_give(tx_exit_notify); 5976 5977 #ifdef BCM_DNX_SUPPORT 5978 DNX_ERR_RECOVERY_UTILS_EXCLUDED_THREADS_REMOVE_ALL_UNITS(); 5979 #endif 5980 5981 sal_thread_exit(0); 5982 } 5983 5984 /* 5985 * Function: 5986 * _bcm_tx_desc_done_cb 5987 * Purpose: 5988 * Interrupt handler callback to schedule desc done processing 5989 * Parameters: 5990 * unit - SOC unit # 5991 * dv - pointer to dv that has completed. 5992 * dcb - pointer to dcb (not used for TX) 5993 * Returns: 5994 * Nothing 5995 * Notes: 5996 * All the handler does is put the DVDCB on a queue and 5997 * check if the handler thread needs to be awakened. 5998 * 5999 * This function is called in INTERRUPT CONTEXT, 6000 * but is also called in non-interrupt context from 6001 * _bcm_tx_chain_send, so TX_SPIN_LOCK must be used. 6002 */ 6003 6004 STATIC void 6005 _bcm_tx_desc_done_cb(int unit, dv_t *dv, dcb_t *dcb) 6006 { 6007 if (soc_feature(unit, soc_feature_cmicx)) { 6008 soc_stat_t *stat = &SOC_CONTROL(unit)->stat; 6009 tx_dv_info_t *dv_info; 6010 int i; 6011 6012 dv_info = TX_INFO(dv); 6013 6014 for (i = 0; i < dv_info->pkt_count; ++i) { 6015 if (dv_info->pkt[i] && dv_info->pkt[i]->tx_header) { 6016 stat->dma_tbyt -= sizeof(dv_info->pkt[i]->_higig); 6017 soc_cm_sfree(unit, dv_info->pkt[i]->tx_header); 6018 dv_info->pkt[i]->tx_header = NULL; 6019 } 6020 } 6021 } 6022 6023 if (BCM_SUCCESS(_bcm_tx_cb_intr_enabled())) { 6024 _bcm_tx_desc_done(unit, dv, dcb); 6025 } else { 6026 TX_SPIN_LOCK(); 6027 ++_tx_desc_done_intr; 6028 dv->dv_unit = unit; 6029 TX_DV_NEXT_SET(dv, NULL); 6030 if (dvdesc_pend_last) { /* Queue is non-empty */ 6031 TX_DV_NEXT_SET(dvdesc_pend_last, dv); 6032 LOG_DEBUG(BSL_LS_BCM_TX, 6033 (BSL_META_U(unit, 6034 "_tx_desc_done_cb appending dv=%p" 6035 " to dv=%p for processing\n"), 6036 (void *)dv, (void *)dvdesc_pend_last)); 6037 dvdesc_pend_last = dv; 6038 } else { /* Empty queue; init first and last */ 6039 dvdesc_pend_first = dv; 6040 dvdesc_pend_last = dv; 6041 LOG_DEBUG(BSL_LS_BCM_TX, 6042 (BSL_META_U(unit, 6043 "_tx_desc_done_cb adding dv=%p" 6044 " for processing\n"), 6045 (void *)dv)); 6046 } 6047 TX_SPIN_UNLOCK(); 6048 sal_sem_give(tx_cb_sem); 6049 } 6050 } 6051 6052 /* 6053 * Function: 6054 * _bcm_tx_reload_done_cb 6055 * Purpose: 6056 * Interrupt handler callback to schedule reload done processing 6057 * Parameters: 6058 * unit - SOC unit # 6059 * dv - pointer to dv that has completed. 6060 * Returns: 6061 * Nothing 6062 * Notes: 6063 * All the handler does is put the DVDCB on a queue and 6064 * check if the handler thread needs to be awakened. 6065 * 6066 * This function is called in INTERRUPT CONTEXT, 6067 * but is also called in non-interrupt context from 6068 * _bcm_tx_chain_send, so TX_SPIN_LOCK must be used. 6069 */ 6070 6071 STATIC void 6072 _bcm_tx_reload_done_cb(int unit, dv_t *dv) 6073 { 6074 if (BCM_SUCCESS(_bcm_tx_cb_intr_enabled())) { 6075 _bcm_tx_reload_done(unit, dv); 6076 } else { 6077 TX_SPIN_LOCK(); 6078 ++_tx_rld_done_intr; 6079 dv->dv_unit = unit; 6080 TX_DV_NEXT_SET(dv, NULL); 6081 if (dvrld_pend_last) { /* Queue is non-empty */ 6082 TX_DV_NEXT_SET(dvrld_pend_last, dv); 6083 LOG_DEBUG(BSL_LS_BCM_TX, 6084 (BSL_META_U(unit, 6085 "_tx_reload_done_cb appending dv=%p" 6086 " to dv=%p for processing\n"), 6087 (void *)dv, (void *)dvrld_pend_last)); 6088 dvrld_pend_last = dv; 6089 } else { /* Empty queue; init first and last */ 6090 dvrld_pend_first = dv; 6091 dvrld_pend_last = dv; 6092 LOG_DEBUG(BSL_LS_BCM_TX, 6093 (BSL_META_U(unit, 6094 "_tx_reload_done_cb adding dv=%p" 6095 " for processing\n"), 6096 (void *)dv)); 6097 } 6098 TX_SPIN_UNLOCK(); 6099 sal_sem_give(tx_cb_sem); 6100 } 6101 } 6102 6103 /* 6104 * Function: 6105 * _bcm_tx_chain_done_cb 6106 * Purpose: 6107 * Interrupt handler callback to schedule chain done processing 6108 * Parameters: 6109 * unit - SOC unit # 6110 * dv - pointer to dv that has completed. 6111 * Returns: 6112 * Nothing 6113 * Notes: 6114 * All the handler does is put the DV on a queue and 6115 * check if the handler thread needs to be awakened. 6116 * 6117 * This function is called in INTERRUPT CONTEXT, 6118 * but is also called in non-interrupt context from 6119 * _bcm_tx_chain_send, so TX_SPIN_LOCK must be used. 6120 */ 6121 6122 STATIC void 6123 _bcm_tx_chain_done_cb(int unit, dv_t *dv) 6124 { 6125 if (soc_feature(unit, soc_feature_cmicx)) { 6126 soc_stat_t *stat = &SOC_CONTROL(unit)->stat; 6127 tx_dv_info_t *dv_info; 6128 int i; 6129 6130 dv_info = TX_INFO(dv); 6131 6132 for (i = 0; i < dv_info->pkt_count; ++i) { 6133 if (dv_info->pkt[i]->tx_header) { 6134 stat->dma_tbyt -= sizeof(dv_info->pkt[i]->_higig); 6135 soc_cm_sfree(unit, dv_info->pkt[i]->tx_header); 6136 dv_info->pkt[i]->tx_header = NULL; 6137 } 6138 } 6139 } 6140 6141 if (BCM_SUCCESS(_bcm_tx_cb_intr_enabled())) { 6142 _bcm_tx_chain_done(unit, dv); 6143 } else { 6144 TX_SPIN_LOCK(); 6145 ++_tx_chain_done_intr; 6146 dv->dv_unit = unit; 6147 TX_DV_NEXT_SET(dv, NULL); 6148 if (dv_pend_last) { /* Queue is non-empty */ 6149 TX_DV_NEXT_SET(dv_pend_last, dv); 6150 dv_pend_last = dv; 6151 } else { /* Empty queue; init first and last */ 6152 dv_pend_first = dv; 6153 dv_pend_last = dv; 6154 } 6155 TX_SPIN_UNLOCK(); 6156 sal_sem_give(tx_cb_sem); 6157 } 6158 } 6159 6160 /* 6161 * Function: 6162 * _bcm_tx_desc_done 6163 * Purpose: 6164 * Process the completion of a TX DMA controlled descriptor. 6165 * Parameters: 6166 * unit - SOC unit number. 6167 * dv - pointer to DV containing the completed DMA descriptor. 6168 * Returns: 6169 * Nothing. 6170 * Notes: 6171 * This is new for continuous mode. The controlled desc intr 6172 * is only enabled for the final data descriptor and the reload 6173 * descriptor. Call all_done_callback for non reload descriptors. 6174 * De-allocate the DV on reload done. 6175 */ 6176 6177 STATIC void 6178 _bcm_tx_desc_done(int unit, dv_t *dv, dcb_t *dcb) 6179 { 6180 bcm_pkt_cb_f callback; 6181 volatile bcm_pkt_t *pkt; 6182 void *cookie; 6183 assert(dv != NULL); 6184 assert(soc_dma_dv_valid(dv)); 6185 6186 ++_tx_desc_done; 6187 6188 /* Operation complete; call user's completion callback routine, if any */ 6189 callback = TX_INFO(dv)->chain_done_cb; 6190 if (callback) { 6191 pkt = TX_INFO(dv)->pkt[0]; 6192 cookie = TX_INFO(dv)->cookie; 6193 callback(unit, (bcm_pkt_t *)pkt, cookie); 6194 } 6195 LOG_DEBUG(BSL_LS_BCM_TX, 6196 (BSL_META_U(unit, 6197 "TX Desc Done for c=%d, dv=%p, dcb=%p\n"), 6198 dv->dv_channel, (void *)dv, (void *)dcb)); 6199 } 6200 6201 /* 6202 * Function: 6203 * _bcm_tx_reload_done 6204 * Purpose: 6205 * Process the completion of a TX DMA reload descriptor. 6206 * Parameters: 6207 * unit - SOC unit number. 6208 * dv - pointer to DV containing the completed DMA descriptor. 6209 * dcb - pointer to the completed descriptor 6210 * Returns: 6211 * Nothing. 6212 * Notes: 6213 * This is new for continuous mode. The controlled desc intr 6214 * is only enabled for the final data descriptor and the reload 6215 * descriptor. De-allocate the DV on reload done. 6216 */ 6217 6218 STATIC void 6219 _bcm_tx_reload_done(int unit, dv_t *dv) 6220 { 6221 6222 ++_tx_rld_done; 6223 6224 if (dv != NULL) { 6225 LOG_DEBUG(BSL_LS_BCM_TX, 6226 (BSL_META_U(unit, 6227 "TX Reload Done for c=%d, dv=%p\n"), 6228 dv->dv_channel, 6229 (void *)dv)); 6230 _tx_dv_free(unit, dv); 6231 } 6232 } 6233 6234 /* 6235 * Function: 6236 * _bcm_tx_chain_done 6237 * Purpose: 6238 * Process the completion of a TX DMA chain. 6239 * Parameters: 6240 * unit - SOC unit number. 6241 * dv - pointer to completed DMA chain. 6242 * dcb - ignored 6243 * Returns: 6244 * Nothing. 6245 * Notes: 6246 */ 6247 6248 STATIC void 6249 _bcm_tx_chain_done(int unit, dv_t *dv) 6250 { 6251 bcm_pkt_cb_f callback; 6252 volatile bcm_pkt_t *pkt; 6253 void *cookie; 6254 6255 assert(dv != NULL); 6256 6257 ++_tx_chain_done; 6258 6259 /* Operation complete; call user's completion callback routine, if any */ 6260 callback = TX_INFO(dv)->chain_done_cb; 6261 if (callback) { 6262 pkt = TX_INFO(dv)->pkt[0]; 6263 cookie = TX_INFO(dv)->cookie; 6264 callback(unit, (bcm_pkt_t *)pkt, cookie); 6265 } 6266 LOG_DEBUG(BSL_LS_BCM_TX, 6267 (BSL_META_U(unit, 6268 "TX Chain Done for c=%d, dv=%p\n"), 6269 dv->dv_channel, (void *)dv)); 6270 6271 _tx_dv_free(unit, dv); 6272 } 6273 6274 /* 6275 * Function: 6276 * _bcm_tx_packet_done_cb 6277 * Purpose: 6278 * Packet done interrupt callback 6279 * Parameters: 6280 * unit - SOC unit number. 6281 * dv - pointer to completed DMA chain. 6282 * Returns: 6283 * Nothing. 6284 * Notes: 6285 * Just checks to see if the packet's callback is set. If 6286 * it is, the packet is added to the packet pending list 6287 * and the tx thread is woken up. 6288 * 6289 * This will only be set up as a call back if some packet in the 6290 * chain requires a callback. 6291 */ 6292 6293 STATIC void 6294 _bcm_tx_packet_done_cb(int unit, dv_t *dv, dcb_t *dcb) 6295 { 6296 bcm_pkt_t *pkt; 6297 soc_stat_t *stat = &SOC_CONTROL(unit)->stat; 6298 6299 COMPILER_REFERENCE(dcb); 6300 assert(dv); 6301 assert(TX_INFO(dv)); 6302 assert(TX_INFO(dv)->pkt_count > TX_INFO(dv)->pkt_done_cnt); 6303 6304 pkt = (bcm_pkt_t *)TX_INFO_CUR_PKT(dv); 6305 if (pkt) { 6306 pkt->_dv = dv; 6307 pkt->unit = unit; 6308 pkt->_next = NULL; 6309 } 6310 6311 if (soc_feature(unit, soc_feature_cmicx)) { 6312 if (pkt && pkt->tx_header) { 6313 stat->dma_tbyt -= sizeof(pkt->_higig); 6314 soc_cm_sfree(unit, pkt->tx_header); 6315 pkt->tx_header = NULL; 6316 } 6317 } 6318 6319 /* 6320 * If callback present, add to list 6321 */ 6322 if (BCM_SUCCESS(_bcm_tx_cb_intr_enabled())) { 6323 TX_INFO_PKT_MARK_DONE(dv); 6324 _bcm_tx_packet_done(pkt); 6325 } else { 6326 if (pkt && pkt->call_back) { 6327 TX_SPIN_LOCK(); 6328 /* Assumes interrupt context */ 6329 if (pkt_pend_last) { /* Queue is non-empty */ 6330 pkt_pend_last->_next = pkt; 6331 pkt_pend_last = pkt; 6332 } else { /* Empty queue; init first and last */ 6333 pkt_pend_first = pkt; 6334 pkt_pend_last = pkt; 6335 } 6336 TX_SPIN_UNLOCK(); 6337 sal_sem_give(tx_cb_sem); 6338 } 6339 TX_INFO_PKT_MARK_DONE(dv); 6340 } 6341 } 6342 6343 STATIC void 6344 _bcm_tx_packet_done(bcm_pkt_t *pkt) 6345 { 6346 if (pkt && pkt->call_back) { 6347 #if defined (INCLUDE_RCPU) && defined(BCM_XGS3_SWITCH_SUPPORT) 6348 if (SOC_IS_RCPU_UNIT(pkt->unit)) { 6349 (pkt->call_back)(pkt->unit, pkt, pkt->_dv); 6350 } else { 6351 (pkt->call_back)(pkt->unit, pkt, 6352 TX_INFO((dv_t *)(pkt->_dv))->cookie); 6353 } 6354 #else 6355 (pkt->call_back)(pkt->unit, pkt, 6356 TX_INFO((dv_t *)(pkt->_dv))->cookie); 6357 #endif /* INCLUDE_RCPU && BCM_XGS3_SWITCH_SUPPORT */ 6358 } 6359 } 6360 6361 #if defined (INCLUDE_RCPU) && defined(BCM_XGS3_SWITCH_SUPPORT) 6362 /* 6363 * Function: 6364 * _bcm_rcpu_tx_packet_done_cb 6365 * Purpose: 6366 * Packet done callback from rcpu 6367 * Parameters: 6368 * unit - SOC unit number. 6369 * pkt - packet pointer 6370 * Returns: 6371 * Nothing. 6372 * Notes: 6373 * The packet is added to the packet pending list 6374 * and the tx thread is woken up. 6375 * 6376 * This will only be set up as a call back if some packet in the 6377 * chain requires a callback. 6378 * 6379 * This function should be only called in Task context. 6380 */ 6381 6382 void 6383 _bcm_rcpu_tx_packet_done_cb(int unit, bcm_pkt_t *pkt) 6384 { 6385 /* 6386 * If callback present, add to list 6387 */ 6388 if (pkt->call_back) { 6389 TX_SPIN_LOCK(); 6390 /* Assumes interrupt context */ 6391 if (pkt_pend_last) { /* Queue is non-empty */ 6392 pkt_pend_last->_next = pkt; 6393 pkt_pend_last = pkt; 6394 } else { /* Empty queue; init first and last */ 6395 pkt_pend_first = pkt; 6396 pkt_pend_last = pkt; 6397 } 6398 TX_SPIN_UNLOCK(); 6399 6400 sal_sem_give(tx_cb_sem); 6401 } 6402 } 6403 #endif /* INCLUDE_RCPU && BCM_XGS3_SWITCH_SUPPORT */ 6404 6405 /**************************************************************** 6406 * 6407 * TX DV info dump routine. 6408 */ 6409 6410 #if defined(BROADCOM_DEBUG) 6411 /* 6412 * Function: 6413 * bcm_tx_show 6414 * Purpose: 6415 * Display info about tx state 6416 * Parameters: 6417 * unit - ignored 6418 * Returns: 6419 * None 6420 * Notes: 6421 */ 6422 6423 int 6424 bcm_common_tx_show(int unit) 6425 { 6426 6427 COMPILER_REFERENCE(unit); 6428 6429 LOG_CLI((BSL_META_U(unit, 6430 "TX state: chain_send %d. chain_done %d. " 6431 "chain_done_intr %d\n"), 6432 _tx_chain_send, 6433 _tx_chain_done, 6434 _tx_chain_done_intr)); 6435 6436 LOG_CLI((BSL_META_U(unit, 6437 "TX state: chain_send %d. desc_done %d. " 6438 "desc_done_intr %d\n"), 6439 _tx_chain_send, 6440 _tx_desc_done, 6441 _tx_desc_done_intr)); 6442 6443 LOG_CLI((BSL_META_U(unit, 6444 "TX state: chain_send %d. rld_done %d. " 6445 "rld_done_intr %d\n"), 6446 _tx_chain_send, 6447 _tx_rld_done, 6448 _tx_rld_done_intr)); 6449 6450 LOG_CLI((BSL_META_U(unit, 6451 " pkt_pend_first %p. pkt_pend_last %p.\n"), 6452 (void *)pkt_pend_first, 6453 (void *)pkt_pend_last)); 6454 LOG_CLI((BSL_META_U(unit, 6455 " dv_pend_first %p. dv_pend_last %p.\n"), 6456 (void *)dv_pend_first, 6457 (void *)dv_pend_last)); 6458 6459 return BCM_E_NONE; 6460 } 6461 6462 /* 6463 * Function: 6464 * bcm_tx_dv_dump 6465 * Purpose: 6466 * Display info about a DV that is setup for TX. 6467 * Parameters: 6468 * unit - transmission unit 6469 * dv - The DV to show info about 6470 * Returns: 6471 * None 6472 * Notes: 6473 * Mainly, dumps the tx_dv_info_t structure; then calls soc_dma_dump_dv 6474 */ 6475 6476 int 6477 bcm_common_tx_dv_dump(int unit, void *dv_p) 6478 { 6479 tx_dv_info_t *dv_info; 6480 dv_t *dv = (dv_t *)dv_p; 6481 6482 dv_info = TX_INFO(dv); 6483 if (dv_info != NULL) { 6484 LOG_CLI((BSL_META_U(unit, 6485 "TX DV info:\n DV %p. pkt count %d. done count %d.\n"), 6486 (void *)dv, dv_info->pkt_count, dv_info->pkt_done_cnt)); 6487 #if !defined(__PEDANTIC__) 6488 LOG_CLI((BSL_META_U(unit, 6489 " cookie %p. cb %p\n"), (void *)dv_info->cookie, 6490 (void *)dv_info->chain_done_cb)); 6491 #else /* !defined(__PEDANTIC__) */ 6492 LOG_CLI((BSL_META_U(unit, 6493 " cookie %p. cb pointer unprintable\n"), 6494 (void *)dv_info->cookie)); 6495 #endif /* !defined(__PEDANTIC__) */ 6496 } else { 6497 LOG_CLI((BSL_META_U(unit, 6498 "TX DV info is NULL\n"))); 6499 } 6500 if (bsl_check(bslLayerSoc, bslSourceTx, bslSeverityVerbose, unit)) { 6501 soc_dma_dump_dv(dv->dv_unit, "tx dv: ", dv); 6502 } 6503 return BCM_E_NONE; 6504 } 6505 6506 #endif /* BROADCOM_DEBUG */ 6507 6508 6509 #endif /* defined(BCM_ESW_SUPPORT) */ 6510 6511 6512 #ifdef BCM_RPC_SUPPORT 6513 6514 /**************************************************************** 6515 * 6516 * TX CPU tunnel support 6517 */ 6518 6519 /* 6520 * Function: 6521 * bcm_tx_cpu_tunnel_set/get 6522 * Purpose: 6523 * Set/get the function used to tunnel packets to remote CPUs for TX 6524 * Returns: 6525 * BCM_E_NONE 6526 * Notes: 6527 * If set to NULL, tunneling won't happen and an error will be 6528 * returned by bcm_tx if a remoted device is specified. 6529 */ 6530 6531 static bcm_tx_cpu_tunnel_f tx_cpu_tunnel; 6532 6533 int 6534 bcm_tx_cpu_tunnel_set(bcm_tx_cpu_tunnel_f f) 6535 { 6536 tx_cpu_tunnel = f; 6537 6538 return BCM_E_NONE; 6539 } 6540 6541 int 6542 bcm_tx_cpu_tunnel_get(bcm_tx_cpu_tunnel_f *f) 6543 { 6544 if (f != NULL) { 6545 *f = tx_cpu_tunnel; 6546 } 6547 6548 return BCM_E_NONE; 6549 } 6550 6551 6552 /* 6553 * Function: 6554 * bcm_tx_cpu_tunnel 6555 * Purpose: 6556 * Call the programmed tx tunnel function, if programmed 6557 * Returns: 6558 * BCM_E_INIT if tunnel function is not initialized 6559 * Otherwise, returns the value from the tunnel call 6560 */ 6561 6562 int 6563 bcm_tx_cpu_tunnel(bcm_pkt_t *pkt, 6564 int dest_unit, 6565 int remote_port, 6566 uint32 flags, 6567 bcm_cpu_tunnel_mode_t mode) 6568 { 6569 if (tx_cpu_tunnel != NULL) { 6570 return tx_cpu_tunnel(pkt, dest_unit, remote_port, flags, mode); 6571 } 6572 6573 return BCM_E_INIT; 6574 } 6575 6576 #endif /* BCM_RPC_SUPPORT */ 6577