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

rx.c (245309B)


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