openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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