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

cmicm_dma_fifo.c (46739B)


      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  * Purpose:  CMICM FIFO DMA driver.
      8  */
      9 
     10 #include <shared/bsl.h>
     11 #include <shared/bitop.h>
     12 
     13 
     14 #include <sal/core/boot.h>
     15 #include <sal/core/libc.h>
     16 #include <shared/alloc.h>
     17 
     18 #include <soc/drv.h>
     19 #include <soc/debug.h>
     20 #include <soc/cm.h>
     21 #include <soc/l2x.h>
     22 
     23 #ifdef BCM_CMICM_SUPPORT
     24 #include <soc/cmicm.h>
     25 #endif
     26 
     27 #ifdef BCM_TRIUMPH3_SUPPORT
     28 #include <soc/er_tcam.h>
     29 #include <soc/triumph3.h>
     30 #endif
     31 
     32 #ifdef BCM_KATANA2_SUPPORT
     33 #include <soc/katana2.h>
     34 #include <soc/katana.h>
     35 #endif
     36 
     37 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT)
     38 
     39 #if (!defined(_LIMITS_H)) && !defined(_LIBC_LIMITS_H_)
     40 
     41 #if (!defined(INT_MIN)) && !defined(INT_MAX)
     42 #define INT_MIN (((int)1)<<(sizeof(int)*8-1))
     43 #define INT_MAX (~INT_MIN)
     44 #endif
     45 
     46 #ifndef UINT_MAX
     47 #define UINT_MAX ((unsigned)-1)
     48 #endif
     49 
     50 #endif
     51 
     52 #ifdef BCM_KATANA2_SUPPORT
     53 #define RD_DMA_CFG_REG                   0
     54 #define RD_DMA_HOTMEM_THRESHOLD_REG      1
     55 #define RD_DMA_STAT                      2
     56 #define RD_DMA_STAT_CLR                  3
     57 #endif
     58 
     59 #if defined(BCM_CMICM_SUPPORT) && defined(BCM_XGS3_SWITCH_SUPPORT)
     60 
     61 #define API_DISABLE  0
     62 #define API_ENABLE   1
     63 
     64 #define API_USE      1
     65 #define API_NOT_USE  2
     66 
     67 typedef struct _l2_mod_fifo_enable {
     68     uint32      api_val;
     69     uint32      api_is_set;
     70 } _l2_mod_fifo_enable_t;
     71 
     72 typedef struct _aux_arb_cntl {
     73     uint32      api_val;
     74     uint32      api_is_set;
     75 } _aux_arb_cntl_t;
     76 
     77 static _aux_arb_cntl_t aux_arb_cntl_reg[SOC_MAX_NUM_DEVICES];
     78 static _l2_mod_fifo_enable_t l2_mod_fifo_reg[SOC_MAX_NUM_DEVICES];
     79 
     80 #define API_SET_AUX_ARB_CNTL(unit, field, fvalue) do { \
     81             soc_reg_field_set(unit, AUX_ARB_CONTROLr, \
     82                               &aux_arb_cntl_reg[unit].api_val, field, \
     83                               ((fvalue) ? API_ENABLE: API_DISABLE)); \
     84             soc_reg_field_set(unit, AUX_ARB_CONTROLr, \
     85                               &aux_arb_cntl_reg[unit].api_is_set, field, API_USE); \
     86         } while(0)
     87 
     88 #define API_GET_AUX_ARB_CNTL(unit, field) \
     89             ((soc_reg_field_get(unit, AUX_ARB_CONTROLr, \
     90                                 aux_arb_cntl_reg[unit].api_is_set, field)) ? \
     91                 ((soc_reg_field_get(unit, AUX_ARB_CONTROLr, \
     92                                     aux_arb_cntl_reg[unit].api_val, field)) ? \
     93                      API_ENABLE :  API_DISABLE) : \
     94                  API_NOT_USE)
     95 
     96 
     97 #define API_SET_L2_MOD_FIFO_ENABLE(unit, field, fvalue) do { \
     98             soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, \
     99                               &l2_mod_fifo_reg[unit].api_val, field, \
    100                               ((fvalue) ? API_ENABLE: API_DISABLE)); \
    101             soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, \
    102                               &l2_mod_fifo_reg[unit].api_is_set, field, API_USE); \
    103         } while(0)
    104 
    105 #define API_GET_L2_MOD_FIFO_ENABLE(unit, field) \
    106             ((soc_reg_field_get(unit, L2_MOD_FIFO_ENABLEr, \
    107                                 l2_mod_fifo_reg[unit].api_is_set, field)) ? \
    108                 ((soc_reg_field_get(unit, L2_MOD_FIFO_ENABLEr, \
    109                                     l2_mod_fifo_reg[unit].api_val, field)) ? \
    110                      API_ENABLE :  API_DISABLE) : \
    111                  API_NOT_USE)
    112 #endif
    113 
    114 #ifdef BCM_CMICM_SUPPORT
    115 
    116 typedef struct _hostmem_address_remap_allocation{
    117     int in_use;
    118     int cmc;
    119     int ch;
    120 } _hostmem_address_remap_allocation_t;
    121 
    122 #define NOF_HOSTMEM_ADDR_REMAP_ENTRIES (16)
    123 #define HOSTMEM_ADDR_REMAP_POSITION (28)
    124 #define HOSTMEM_ADDR_REMAP_MASK (0xF)
    125 
    126 
    127 _hostmem_address_remap_allocation_t hostmem_address_remap_allocation[SOC_MAX_NUM_DEVICES][NOF_HOSTMEM_ADDR_REMAP_ENTRIES];
    128 
    129 static void
    130 _soc_mem_fifo_dma_address_remap_set(
    131     int unit,
    132     int cmc,
    133     int entry_idx,
    134     uint32 value)
    135 {   
    136     uint32 remap_address[NOF_HOSTMEM_ADDR_REMAP_ENTRIES];                     
    137     soc_field_t remap_f[NOF_HOSTMEM_ADDR_REMAP_ENTRIES] = {
    138                      ADDR_0f, ADDR_1f, ADDR_2f, ADDR_3f, ADDR_4f,
    139                      ADDR_0f, ADDR_1f, ADDR_2f, ADDR_3f, ADDR_4f,
    140                      ADDR_0f, ADDR_1f, ADDR_2f, ADDR_3f, ADDR_4f,
    141                      ADDR_0f};
    142     uint32 rval;
    143     
    144     remap_address[0] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_0_OFFSET(cmc);
    145     remap_address[1] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_0_OFFSET(cmc);
    146     remap_address[2] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_0_OFFSET(cmc);
    147     remap_address[3] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_0_OFFSET(cmc);
    148     remap_address[4] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_0_OFFSET(cmc);
    149     remap_address[5] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_1_OFFSET(cmc);
    150     remap_address[6] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_1_OFFSET(cmc);
    151     remap_address[7] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_1_OFFSET(cmc);
    152     remap_address[8] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_1_OFFSET(cmc);
    153     remap_address[9] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_1_OFFSET(cmc);
    154     remap_address[10] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_2_OFFSET(cmc);
    155     remap_address[11] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_2_OFFSET(cmc);
    156     remap_address[12] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_2_OFFSET(cmc);
    157     remap_address[13] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_2_OFFSET(cmc);
    158     remap_address[14] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_2_OFFSET(cmc);
    159     remap_address[15] = CMIC_CMCx_HOSTMEM_ADDR_REMAP_3_OFFSET(cmc);
    160     
    161     rval = soc_pci_read(unit, remap_address[entry_idx]);
    162     soc_reg_field_set(unit, CMIC_CMC0_HOSTMEM_ADDR_REMAP_0r, &rval, remap_f[entry_idx], value);
    163     soc_pci_write(unit, remap_address[entry_idx], rval);
    164 }    
    165 
    166 int
    167 _soc_mem_address_remap_allocation_init(
    168     int unit)
    169 {
    170     int base_cmc = SOC_PCI_CMC(unit);
    171     int num_of_cmc = SOC_PCI_CMCS_NUM(unit);
    172     int cmc, entry_idx;
    173     char *propkey;
    174     uint32 remap_entries_reserved;
    175 
    176     propkey = spn_HOST_MEMORY_ADDRESS_REMAP_ENTRIES_RESERVED_CMC;
    177     sal_memset(hostmem_address_remap_allocation[unit], 0x0, 
    178         sizeof(_hostmem_address_remap_allocation_t)*NOF_HOSTMEM_ADDR_REMAP_ENTRIES);  
    179 
    180     /* consider remap_entries_reserved!=0 only for cmc=1 and pci_cmc=0 */
    181     /* this is the only constelation that the remap management is allowed */
    182     for(cmc=base_cmc; cmc<(num_of_cmc+base_cmc); cmc++)
    183     {
    184         remap_entries_reserved = soc_property_port_get(unit, cmc, propkey, 0);
    185         if(remap_entries_reserved != 0)
    186         {
    187            if ((cmc != 1) || (base_cmc != 0))
    188            {
    189                 LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U
    190                     (unit, "Soc host_memory_address_remap_entries_cmc_%d!=0 is allowed only for cmc=1 and pci_cmc=0\n"), cmc));
    191                 return SOC_E_PARAM;                
    192            }
    193            else
    194            {
    195                 /* mark the reserved entries in database */
    196                 for(entry_idx = 0; entry_idx < NOF_HOSTMEM_ADDR_REMAP_ENTRIES; entry_idx++)
    197                 {
    198                     if(SHR_BITGET(&remap_entries_reserved, entry_idx))
    199                     {
    200                         hostmem_address_remap_allocation[unit][entry_idx].in_use = TRUE;
    201                         hostmem_address_remap_allocation[unit][entry_idx].cmc = -1;
    202                         hostmem_address_remap_allocation[unit][entry_idx].ch = -1;                                                
    203                     }
    204                     else
    205                     {
    206                         /* clear the HW table for none ukernel (Arm-firmware) entries */
    207                         _soc_mem_fifo_dma_address_remap_set(unit, cmc, entry_idx, 0);
    208                     }
    209                 }
    210            }
    211         }
    212     }           
    213     return SOC_E_NONE;
    214 }
    215 
    216 int
    217 _soc_mem_address_remap_dealloc(
    218     int unit, 
    219     int cmc, 
    220     int ch)
    221 {
    222     int entry_idx;
    223     
    224     for(entry_idx = 0; entry_idx < NOF_HOSTMEM_ADDR_REMAP_ENTRIES; entry_idx++)
    225     {
    226         if(hostmem_address_remap_allocation[unit][entry_idx].cmc == cmc &&
    227            hostmem_address_remap_allocation[unit][entry_idx].ch == ch &&
    228            hostmem_address_remap_allocation[unit][entry_idx].in_use == TRUE)
    229         {
    230             hostmem_address_remap_allocation[unit][entry_idx].in_use = FALSE;
    231             /* clear HW */
    232             _soc_mem_fifo_dma_address_remap_set(unit, cmc, entry_idx, 0);
    233         }
    234     }
    235     
    236     return SOC_E_NONE;    
    237 }
    238 
    239 int
    240 _soc_mem_address_remap_alloc(
    241     int unit, 
    242     int cmc, 
    243     int ch, 
    244     int nof_entries, 
    245     uint32 remap_val,
    246     uint32 *remap_entry_base)
    247 {
    248     int entry_idx;
    249     int base_entry = 0, available_entries = 0;
    250 
    251     if((nof_entries == 0) || (nof_entries > NOF_HOSTMEM_ADDR_REMAP_ENTRIES))
    252     {
    253         return SOC_E_INTERNAL;
    254     }
    255     /* find free entry. If need to allocate more than one entry, all the entries must be consecutive */
    256     for(entry_idx = 0; (entry_idx < NOF_HOSTMEM_ADDR_REMAP_ENTRIES); entry_idx++)
    257     {        
    258         if(hostmem_address_remap_allocation[unit][entry_idx].in_use == FALSE)
    259         {
    260             if(available_entries == 0)
    261             {
    262                 base_entry = entry_idx;
    263             }
    264             available_entries++;
    265         }
    266         else
    267         {
    268             available_entries = 0;
    269         }
    270         if(available_entries == nof_entries)
    271         {
    272             break;
    273         }
    274     }
    275     if(entry_idx == NOF_HOSTMEM_ADDR_REMAP_ENTRIES)
    276     {
    277         return SOC_E_RESOURCE;
    278     }
    279     /* update database and write to HW */
    280     for (entry_idx = base_entry; entry_idx < (base_entry + nof_entries); entry_idx++)
    281     {
    282         hostmem_address_remap_allocation[unit][entry_idx].in_use = TRUE;
    283         hostmem_address_remap_allocation[unit][entry_idx].cmc = cmc;
    284         hostmem_address_remap_allocation[unit][entry_idx].ch = ch;    
    285         /* write to HW: update the remap value into the relevant register */        
    286         _soc_mem_fifo_dma_address_remap_set(unit, cmc, entry_idx, remap_val);
    287         remap_val++;        
    288     }
    289 
    290     * remap_entry_base = base_entry;
    291     
    292     return SOC_E_NONE;
    293 }
    294 
    295 /**
    296  * Function used to update HOSTMEM_ADDR_REMAP in case that it wasn't made during init stage.
    297  * This function is called for manage a scenario when both SDK and Ukernel (ARM) use the same CMC
    298  * SDK use the DMA channels and ARM use other CMC capbilities.
    299  * Still, the remap table is common per cmc and need to verify that both application 
    300  * do not run each other entries in the table. 
    301  * Here we just write the value into the given entry.
    302  *
    303  * @param unit
    304  * @param cmc - cmc to update
    305  * @param ch - Channel used. should be between 0 and 3. 
    306  * @param phy_address - the phiscal address wich need to remap.
    307  * @param remap_entry_base - indicates what is the base remap entry that need to update. 
    308  *                           relevant only for cmc1. if remap_entry_base=-1, no remap is required.
    309  * @param base_entry - output value which indicate which is the base entry that allocated, 
    310  *                      and will be used in the hostmem start address offset register
    311  *
    312  *
    313  * @return int - success or failure.
    314  */
    315 static int
    316 _soc_mem_fifo_dma_address_remap_handle(
    317     int unit,
    318     int cmc,
    319     int ch,
    320     uint32 phy_address,
    321     uint32 *base_entry)
    322 {
    323     int nof_entries = 1;
    324     uint32 remap_entry_base;
    325     uint32 remamp_base_val, remap_val;
    326     uint32 rval;    
    327 
    328     /** calculate the remap value: { 1'b0, 1'b1, physical_address_bits_31..28(4) } */
    329     remamp_base_val = ((phy_address >> HOSTMEM_ADDR_REMAP_POSITION) & HOSTMEM_ADDR_REMAP_MASK);
    330     remap_val = (0x10 | remamp_base_val);
    331 
    332     /* if the phy_address-bits31..28 is not the max value, we will allocate another entry consecutive to the base entry */
    333     /* for case that the size of the host_buffer crossing "sections" */
    334     if(remamp_base_val != HOSTMEM_ADDR_REMAP_MASK)
    335     {
    336         nof_entries++;
    337     }
    338 
    339     rval = _soc_mem_address_remap_alloc(unit, cmc, ch, nof_entries, remap_val, &remap_entry_base);
    340     if (rval != SOC_E_NONE)
    341     {
    342         LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "can't alloc hostmem address remap entry\n")));
    343         return rval;
    344     }
    345         
    346     *base_entry = remap_entry_base;
    347     return SOC_E_NONE;
    348 }
    349                                       
    350 
    351 /* DMA FIFO init for registers or memories */
    352 
    353 /**
    354  * Function used to (partially) configure the DMA to
    355  * write to a redirect writes from a register/memory
    356  * to a host memory.
    357  *
    358  *
    359  * @param unit
    360  * @param ch - Channel used. should be between 0 and 3.
    361  * @param is_mem
    362  * @param mem -name of memory, if memory is used (0 otherwise).
    363  * @param reg - name of register, if register used (0 otherwise).
    364  * @param copyno
    365  * @param force_entry_size - in a case that entry size does not match
    366  *        the register\memory size  - ignore when equals to 0.
    367  * @param host_entries  - number of host entries used by the DMA.
    368  *  Must be a power of 2 between 64 and 16384.
    369  *  Note that only after host_entries writes does the DMA wrap around the host_buff.
    370  * @param host_buff - local memory on which the DMA writes. should be big enough to
    371  *                     allow host_entries writes,
    372  * in other words whould be the size of host_entries * ( size of memory or
    373  *                         register used, in bytes).
    374  * Other register the caller may need to configure seperatly:
    375  *  CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_THRESHOLD - The amount of writes by the DMA until a
    376  *  threshold based interrupt occurs.
    377  *
    378  *  TIMEOUT_COUNT field in CMIC_CMCx_FIFO_CHy_RD_DMA - Time between a DMA write and a
    379  *                          timeout based interrupt.
    380  *  (May be set to 0 to disable timeout based interrupts).
    381  *
    382  *  Endianess field in CMIC_CMCx_FIFO_CHy_RD_DMA.
    383  *
    384  * @return int - success or failure.
    385  */
    386 int
    387 _soc_mem_sbus_fifo_dma_start_memreg(int unit, int ch,
    388                                     int is_mem, soc_mem_t mem, soc_reg_t reg,
    389                                     int copyno, int force_entry_size,
    390                                     int host_entries, void *host_buff)
    391 {
    392     uint8 at;
    393     uint32 rval, data_beats, sel, phy_address;
    394     int cmc;
    395     int blk;
    396     schan_msg_t msg;
    397     int acc_type;
    398     uint32 base_remap_entry;
    399     char *propkey;
    400     uint32 remap_entries_reserved;
    401 
    402     if (soc_feature(unit, soc_feature_cmicm_multi_dma_cmc)) {
    403         if (ch < 0 || ch > 12 || host_buff == NULL) {
    404             return SOC_E_PARAM;
    405         }
    406         cmc = ch / 4;
    407         ch = ch % 4;
    408     } else {
    409         cmc = SOC_PCI_CMC(unit);
    410         if (ch < 0 || ch > 3 || host_buff == NULL) {
    411             return SOC_E_PARAM;
    412         }
    413     }
    414 
    415     switch (host_entries) {
    416     case 64:    sel = 0; break;
    417     case 128:   sel = 1; break;
    418     case 256:   sel = 2; break;
    419     case 512:   sel = 3; break;
    420     case 1024:  sel = 4; break;
    421     case 2048:  sel = 5; break;
    422     case 4096:  sel = 6; break;
    423     case 8192:  sel = 7; break;
    424     case 16384: sel = 8; break;
    425     default:
    426         return SOC_E_PARAM;
    427     }
    428 
    429 #ifdef BCM_IPFIX_SUPPORT
    430 #ifdef BCM_PETRA_SUPPORT
    431     if (!SOC_IS_SAND(unit))
    432 #endif
    433     {
    434         if (mem != ING_IPFIX_EXPORT_FIFOm && mem != EGR_IPFIX_EXPORT_FIFOm &&
    435             mem !=  L2_MOD_FIFOm && mem != FT_EXPORT_FIFOm &&
    436             mem != FT_EXPORT_DATA_ONLYm &&
    437             mem != EGR_SER_FIFOm && mem != ING_SER_FIFOm &&
    438             mem != CENTRAL_CTR_EVICTION_FIFOm) {
    439             return SOC_E_BADID;
    440         }
    441     }
    442 #endif
    443 
    444     /* Differentiate between reg and mem to get address, size and block */
    445     if ((!is_mem) && SOC_REG_IS_VALID(unit, reg)) {
    446         data_beats = BYTES2WORDS(soc_reg_bytes(unit, reg));
    447         rval = soc_reg_addr_get(unit, reg, REG_PORT_ANY, 0,
    448                                 SOC_REG_ADDR_OPTION_NONE, &blk, &at);
    449     } else {
    450         data_beats = soc_mem_entry_words(unit, mem);
    451         if (copyno == MEM_BLOCK_ANY) {
    452             copyno = SOC_MEM_BLOCK_ANY(unit, mem);
    453         }
    454         rval = soc_mem_addr_get(unit, mem, 0, copyno, 0, &at);
    455         blk = SOC_BLOCK2SCH(unit, copyno);
    456     }
    457     /*Force entry size*/
    458     if (force_entry_size > 0)
    459     {
    460         data_beats = BYTES2WORDS(force_entry_size);
    461     }
    462 
    463     soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_SBUS_START_ADDRESS_OFFSET(cmc, ch), rval);
    464 
    465     schan_msg_clear(&msg);
    466     if (is_mem) {
    467         acc_type = SOC_MEM_ACC_TYPE(unit, mem);
    468     } else {
    469         acc_type = 0;
    470     }
    471     soc_schan_header_cmd_set(unit, &msg.header, FIFO_POP_CMD_MSG, blk, 0,
    472                              acc_type, 4, 0, 0);
    473 
    474     /* Set 1st schan ctrl word as opcode */
    475     soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_OPCODE_OFFSET(cmc, ch), msg.dwords[0]);
    476 
    477     phy_address = soc_cm_l2p(unit, host_buff);
    478 
    479     /** workarroud for issue when both ukernel (ARM) and SDK (Pci-e) use cmc-1 and need to share the remap entries*/
    480     /** in this case, the remap table is not 1x1 and need to update the relevant entries */    
    481     propkey = spn_HOST_MEMORY_ADDRESS_REMAP_ENTRIES_RESERVED_CMC;    
    482     remap_entries_reserved = soc_property_port_get(unit, cmc, propkey, 0);
    483     if ((SOC_IS_JERICHO(unit)) && 
    484         (SOC_PCI_CMCS_NUM(unit) > 1) && (remap_entries_reserved != 0))
    485     {    
    486         rval = _soc_mem_fifo_dma_address_remap_handle(unit, cmc, ch, phy_address, &base_remap_entry); 
    487         if (rval != SOC_E_NONE)
    488         {
    489             return rval;
    490         }
    491         
    492         phy_address = ((phy_address & ((1<<HOSTMEM_ADDR_REMAP_POSITION) - 1)) | (base_remap_entry << HOSTMEM_ADDR_REMAP_POSITION));
    493         soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_START_ADDRESS_OFFSET(cmc, ch),
    494                       phy_address);         
    495     }
    496     else
    497     {
    498         soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_START_ADDRESS_OFFSET(cmc, ch),
    499                       phy_address);    
    500     }
    501     rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch));
    502     soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval, BEAT_COUNTf,
    503                       data_beats);
    504     soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval,
    505                       HOST_NUM_ENTRIES_SELf, sel);
    506     soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval, ABORTf, 0);
    507 
    508         /* Note: Following might need to be tuned */
    509         soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval,
    510                       TIMEOUT_COUNTf, 1000);
    511         /* Note: Following could be removed ?? */
    512         soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval,
    513                       NACK_FATALf, 1);
    514 
    515     if (soc_feature(unit, soc_feature_multi_sbus_cmds)) {
    516         
    517     }
    518     soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval);
    519 
    520     if (SOC_IS_SAND(unit)) {
    521         /* Always 1 in Arad when interrupt mechanism is not enabled */
    522         soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_THRESHOLD_OFFSET(cmc, ch),
    523                      1);
    524     } else {
    525         /* Note: Following might need to be tuned */
    526         soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_THRESHOLD_OFFSET(cmc, ch),
    527                       host_entries/10);
    528     }
    529     soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval, ENABLEf, 1);
    530     soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval);
    531     return SOC_E_NONE;
    532 }
    533 
    534 #ifdef BCM_KATANA2_SUPPORT
    535     int
    536 _soc_kt2_mem_sbus_fifo_dma_start_memreg(int unit, int ch,
    537         int is_mem, soc_mem_t mem, soc_reg_t reg,
    538         int copyno, int host_entries, void *host_buff)
    539 {
    540     uint8 at;
    541     uint32 rval, data_beats, sel;
    542     int cmc;
    543     int blk;
    544     schan_msg_t msg;
    545     soc_reg_t cfg_reg;
    546     int acc_type;
    547     if (soc_feature(unit, soc_feature_cmicm_multi_dma_cmc)) {
    548         if (ch < 0 || ch > 12 || host_buff == NULL) {
    549             return SOC_E_PARAM;
    550         }
    551         cmc = ch / 4;
    552         ch = ch % 4;
    553     } else {
    554         cmc = SOC_PCI_CMC(unit);
    555         if (ch < 0 || ch > 3 || host_buff == NULL) {
    556             return SOC_E_PARAM;
    557         }
    558     }
    559 
    560     switch (host_entries) {
    561         case 64:    sel = 0; break;
    562         case 128:   sel = 1; break;
    563         case 256:   sel = 2; break;
    564         case 512:   sel = 3; break;
    565         case 1024:  sel = 4; break;
    566         case 2048:  sel = 5; break;
    567         case 4096:  sel = 6; break;
    568         case 8192:  sel = 7; break;
    569         case 16384: sel = 8; break;
    570         default:
    571                     return SOC_E_PARAM;
    572     }
    573 
    574     if (mem != L2_MOD_FIFOm) {
    575         return SOC_E_BADID;
    576     }
    577 
    578     /* Differentiate between reg and mem to get address, size and block */
    579     if ((!is_mem) && SOC_REG_IS_VALID(unit, reg)) {
    580         data_beats = BYTES2WORDS(soc_reg_bytes(unit, reg));
    581         rval = soc_reg_addr_get(unit, reg, REG_PORT_ANY, 0,
    582                                 SOC_REG_ADDR_OPTION_NONE, &blk, &at);
    583     } else {
    584         data_beats = soc_mem_entry_words(unit, mem);
    585         if (copyno == MEM_BLOCK_ANY) {
    586             copyno = SOC_MEM_BLOCK_ANY(unit, mem);
    587         }
    588         rval = soc_mem_addr_get(unit, mem, 0, copyno, 0, &at);
    589         blk = SOC_BLOCK2SCH(unit, copyno);
    590     }
    591 
    592     soc_pci_write(unit,
    593             CMIC_CMCx_FIFO_CHy_RD_DMA_SBUS_START_ADDRESS_OFFSET(cmc, ch), rval);
    594 
    595     schan_msg_clear(&msg);
    596     if (is_mem) {
    597         acc_type = SOC_MEM_ACC_TYPE(unit, mem);
    598     } else {
    599         acc_type = 0;
    600     }
    601     soc_schan_header_cmd_set(unit, &msg.header, FIFO_POP_CMD_MSG,
    602                              blk, 0, acc_type, 4, 0, 0);
    603 
    604 
    605     /* Set 1st schan ctrl word as opcode */
    606     soc_pci_write(unit,
    607             CMIC_CMCx_FIFO_CHy_RD_DMA_OPCODE_OFFSET(cmc, ch), msg.dwords[0]);
    608 
    609     rval = soc_cm_l2p(unit, host_buff);
    610     soc_pci_write(unit,
    611             CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_START_ADDRESS_OFFSET(cmc, ch),
    612             rval);
    613 
    614     rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch));
    615     cfg_reg = _soc_kt_fifo_reg_get (unit, cmc, ch, RD_DMA_CFG_REG);
    616 
    617     soc_reg_field_set(unit, cfg_reg, &rval, BEAT_COUNTf,
    618             data_beats);
    619     soc_reg_field_set(unit, cfg_reg, &rval,
    620             HOST_NUM_ENTRIES_SELf, sel);
    621     soc_reg_field_set(unit, cfg_reg, &rval, ABORTf, 0);
    622 
    623     /* Note: Following might need to be tuned */
    624     soc_reg_field_set(unit, cfg_reg, &rval,
    625             TIMEOUT_COUNTf, 1000);
    626     /* Note: Following could be removed ?? */
    627     soc_reg_field_set(unit, cfg_reg, &rval,
    628             NACK_FATALf, 1);
    629 
    630     if (soc_feature(unit, soc_feature_multi_sbus_cmds)) {
    631         
    632     }
    633     soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval);
    634 
    635     /* Note: Following might need to be tuned */
    636     soc_pci_write(unit,
    637             CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_THRESHOLD_OFFSET(cmc, ch),
    638             host_entries/10);
    639     soc_reg_field_set(unit, cfg_reg, &rval, ENABLEf, 1);
    640     soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval);
    641     return SOC_E_NONE;
    642 }
    643 
    644 #endif
    645 
    646 int
    647 _soc_mem_sbus_fifo_dma_start(int unit, int ch, soc_mem_t mem, int copyno,
    648                              int host_entries, void *host_buff)
    649 {
    650 
    651 #ifdef BCM_KATANA2_SUPPORT
    652     if (SOC_IS_KATANA2(unit)) {
    653         return _soc_kt2_mem_sbus_fifo_dma_start_memreg(unit, ch,
    654                 TRUE /* is_mem */, mem, 0,
    655                 copyno, host_entries, host_buff);
    656     }
    657 #endif
    658     return _soc_mem_sbus_fifo_dma_start_memreg(unit, ch,
    659                                                TRUE /* is_mem */, mem, 0,
    660                                                copyno, 0, host_entries, host_buff);
    661 
    662 }
    663 
    664 #ifdef BCM_KATANA2_SUPPORT
    665 int
    666 _soc_kt2_mem_sbus_fifo_dma_stop(int unit, int ch)
    667 {
    668     int cmc, iter = 0;
    669     uint32 rval;
    670     int to = SAL_BOOT_QUICKTURN ? 30000000 : 10000000;
    671     soc_reg_t cfg_reg , cfg_stat;
    672 
    673     if (soc_feature(unit, soc_feature_cmicm_multi_dma_cmc)) {
    674         if (ch < 0 || ch > 12) {
    675             return SOC_E_PARAM;
    676         }
    677         cmc = ch / 4;
    678         ch = ch % 4;
    679     } else {
    680         cmc = SOC_PCI_CMC(unit);
    681         if (ch < 0 || ch > 3) {
    682             return SOC_E_PARAM;
    683         }
    684     }
    685     cfg_reg = _soc_kt_fifo_reg_get (unit, cmc, ch, RD_DMA_CFG_REG);
    686     cfg_stat= _soc_kt_fifo_reg_get (unit, cmc, ch,RD_DMA_STAT);
    687     rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch));
    688     if (!soc_reg_field_get(unit, cfg_reg, rval, ENABLEf)) {
    689         return SOC_E_NONE;
    690     }
    691     rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch));
    692     soc_reg_field_set(unit, cfg_reg, &rval, ABORTf, 1);
    693     soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval);
    694 
    695     sal_udelay(1000);
    696     rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, ch));
    697 
    698     while (soc_reg_field_get(unit, cfg_stat, rval, DONEf) == 0 &&
    699            iter++ <to) {
    700         sal_udelay(1000);
    701         rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, ch));
    702     }
    703     rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch));
    704     soc_reg_field_set(unit, cfg_reg, &rval, ENABLEf, 0);
    705     soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval);
    706 
    707     if (iter >= to) {
    708         LOG_ERROR(BSL_LS_SOC_COMMON,
    709                   (BSL_META_U(unit,
    710                               "FIFO DMA abort failed !!\n")));
    711         return SOC_E_INTERNAL;
    712     }
    713     return SOC_E_NONE;
    714 }
    715 #endif
    716 
    717 
    718 int
    719 _soc_mem_sbus_fifo_dma_stop(int unit, int ch)
    720 {
    721     int cmc, iter = 0;
    722     uint32 rval;
    723     int to = SAL_BOOT_QUICKTURN ? 30000000 : 10000000;
    724 
    725 #ifdef BCM_KATANA2_SUPPORT
    726     if (SOC_IS_KATANA2(unit) ) {
    727         return _soc_kt2_mem_sbus_fifo_dma_stop(unit,ch);
    728     }
    729 #endif
    730 
    731     if (soc_feature(unit, soc_feature_cmicm_multi_dma_cmc)) {
    732         if (ch < 0 || ch > 12) {
    733             return SOC_E_PARAM;
    734         }
    735         cmc = ch / 4;
    736         ch = ch % 4;
    737     } else {
    738         cmc = SOC_PCI_CMC(unit);
    739         if (ch < 0 || ch > 3) {
    740             return SOC_E_PARAM;
    741         }
    742     }
    743 
    744     rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch));
    745     if (!soc_reg_field_get(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, rval, ENABLEf)) {
    746         return SOC_E_NONE;
    747     }
    748     rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch));
    749     soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval, ABORTf, 1);
    750     soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval);
    751 
    752     sal_udelay(1000);
    753     rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, ch));
    754 
    755     while (soc_reg_field_get(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STATr, rval, DONEf) == 0 &&
    756            iter++ <to) {
    757         sal_udelay(1000);
    758         rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, ch));
    759     }
    760     rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch));
    761     soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr, &rval, ENABLEf, 0);
    762     soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, ch), rval);
    763 
    764     if (iter >= to) {
    765         LOG_ERROR(BSL_LS_SOC_COMMON,
    766                   (BSL_META_U(unit,
    767                               "FIFO DMA abort failed !!\n")));
    768         return SOC_E_INTERNAL;
    769     }
    770     return SOC_E_NONE;
    771 }
    772 
    773 int
    774 _soc_mem_sbus_fifo_dma_get_num_entries(int unit, int ch, int *count)
    775 {
    776     uint32 val = 0;
    777     int cmc;
    778 
    779     if (soc_feature(unit, soc_feature_cmicm_multi_dma_cmc)) {
    780         if (ch < 0 || ch > 12) {
    781             return SOC_E_PARAM;
    782         }
    783         cmc = ch / 4;
    784         ch = ch % 4;
    785     } else {
    786         cmc = SOC_PCI_CMC(unit);
    787         if (ch < 0 || ch > 3) {
    788             return SOC_E_PARAM;
    789         }
    790     }
    791 
    792     val = soc_pci_read(unit,
    793                   CMIC_CMCx_FIFO_CHy_RD_DMA_NUM_OF_ENTRIES_VALID_IN_HOSTMEM_OFFSET(cmc, ch));
    794     *count = val;
    795     if (val) {
    796         return SOC_E_NONE;
    797     }
    798     return SOC_E_EMPTY;
    799 }
    800 
    801 int
    802 _soc_mem_sbus_fifo_dma_set_entries_read(int unit, int ch, uint32 num)
    803 {
    804     int cmc;
    805 
    806     if (soc_feature(unit, soc_feature_cmicm_multi_dma_cmc)) {
    807         if (ch < 0 || ch > 12) {
    808             return SOC_E_PARAM;
    809         }
    810         cmc = ch / 4;
    811         ch = ch % 4;
    812     } else {
    813         cmc = SOC_PCI_CMC(unit);
    814         if (ch < 0 || ch > 3) {
    815             return SOC_E_PARAM;
    816         }
    817     }
    818 
    819     
    820 
    821     soc_pci_write(unit,
    822         CMIC_CMCx_FIFO_CHy_RD_DMA_NUM_OF_ENTRIES_READ_FRM_HOSTMEM_OFFSET(cmc, ch), num);
    823     return SOC_E_NONE;
    824 }
    825 
    826 #ifdef BCM_XGS3_SWITCH_SUPPORT /* DPPCOMPILEENABLE */
    827 
    828 STATIC int
    829 _soc_l2mod_sbus_fifo_enable(int unit, uint8 val)
    830 {
    831     uint32 rval = 0;
    832 
    833     if (val == 0) {
    834         SOC_IF_ERROR_RETURN(WRITE_L2_MOD_FIFO_ENABLEr(unit, rval));
    835         return SOC_E_NONE;
    836     } else {
    837         SOC_IF_ERROR_RETURN(READ_L2_MOD_FIFO_ENABLEr(unit, &rval));
    838 
    839         soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval,
    840                           INTERNAL_L2_ENTRYf, val);
    841         if (soc_feature(unit, soc_feature_esm_support)) {
    842             soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval,
    843                               EXTERNAL_L2_ENTRYf, val);
    844         }
    845         /* enable by default unless API disable explicitly */
    846         if (API_DISABLE != API_GET_L2_MOD_FIFO_ENABLE(unit, L2_DELETEf)) {
    847             soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, L2_DELETEf, val);
    848         }
    849         if (API_DISABLE != API_GET_L2_MOD_FIFO_ENABLE(unit, L2_INSERTf)) {
    850             soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, L2_INSERTf, val);
    851         }
    852         if (API_DISABLE != API_GET_L2_MOD_FIFO_ENABLE(unit, L2_LEARNf)) {
    853             soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, L2_LEARNf, val);
    854         }
    855         if (API_DISABLE != API_GET_L2_MOD_FIFO_ENABLE(unit, L2_MEMWRf)) {
    856             soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, L2_MEMWRf, val);
    857         }
    858         SOC_IF_ERROR_RETURN(WRITE_L2_MOD_FIFO_ENABLEr(unit, rval));
    859     }
    860     return SOC_E_NONE;
    861 }
    862 
    863 STATIC int
    864 _soc_td2_l2mod_sbus_fifo_enable(int unit, int enable)
    865 {
    866     uint32 rval = 0;
    867 
    868     if (enable == 0) {
    869         SOC_IF_ERROR_RETURN(WRITE_AUX_ARB_CONTROLr(unit, rval));
    870         return SOC_E_NONE;
    871     } else {
    872         SOC_IF_ERROR_RETURN(READ_AUX_ARB_CONTROLr(unit, &rval));
    873         /* enable by default unless API disable explicitly */
    874         if (API_DISABLE != API_GET_AUX_ARB_CNTL(unit, L2_MOD_FIFO_ENABLE_L2_DELETEf)) {
    875             soc_reg_field_set(unit, AUX_ARB_CONTROLr, &rval,
    876                               L2_MOD_FIFO_ENABLE_L2_DELETEf, enable);
    877         }
    878         if (API_DISABLE != API_GET_AUX_ARB_CNTL(unit, L2_MOD_FIFO_ENABLE_AGEf)) {
    879             soc_reg_field_set(unit, AUX_ARB_CONTROLr, &rval, L2_MOD_FIFO_ENABLE_AGEf,
    880                               enable);
    881         }
    882         if (API_DISABLE != API_GET_AUX_ARB_CNTL(unit, L2_MOD_FIFO_ENABLE_LEARNf)) {
    883             soc_reg_field_set(unit, AUX_ARB_CONTROLr, &rval, L2_MOD_FIFO_ENABLE_LEARNf,
    884                               enable);
    885         }
    886         /* disable by default unless API enable explicitly */
    887         if (API_ENABLE == API_GET_AUX_ARB_CNTL(unit, L2_MOD_FIFO_ENABLE_L2_INSERTf)) {
    888             soc_reg_field_set(unit, AUX_ARB_CONTROLr, &rval, L2_MOD_FIFO_ENABLE_L2_INSERTf,
    889                               enable);
    890         }
    891         SOC_IF_ERROR_RETURN(WRITE_AUX_ARB_CONTROLr(unit, rval));
    892     }
    893     return SOC_E_NONE;
    894 }
    895 
    896 #ifdef BCM_TOMAHAWK_SUPPORT
    897 STATIC int
    898 _soc_th_l2mod_sbus_fifo_enable(int unit, int enable)
    899 {
    900     uint32 rval = 0;
    901 
    902     if (enable == 0) {
    903         SOC_IF_ERROR_RETURN(WRITE_L2_MOD_FIFO_ENABLEr(unit, enable));
    904         return SOC_E_NONE;
    905     } else {
    906         SOC_IF_ERROR_RETURN(READ_L2_MOD_FIFO_ENABLEr(unit, &rval));
    907 
    908         /* enable by default unless API disable explicitly */
    909         if (API_DISABLE != API_GET_L2_MOD_FIFO_ENABLE(unit, L2_DELETEf)) {
    910             soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, L2_DELETEf, enable);
    911         }
    912         if (API_DISABLE != API_GET_L2_MOD_FIFO_ENABLE(unit, L2_LEARNf)) {
    913             soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, L2_LEARNf, enable);
    914         }
    915         SOC_IF_ERROR_RETURN(WRITE_L2_MOD_FIFO_ENABLEr(unit, rval));
    916     }
    917 
    918     return SOC_E_NONE;
    919 }
    920 #endif /* BCM_TOMAHAWK_SUPPORT */
    921 
    922 extern uint32 soc_mem_fifo_delay_value;
    923 
    924 STATIC void
    925 _soc_l2mod_sbus_fifo_dma_thread(void *unit_vp)
    926 {
    927     uint8 overflow, timeout;
    928     int i, count, handled_count, adv_threshold;
    929     int unit = PTR_TO_INT(unit_vp);
    930     int cmc = SOC_PCI_CMC(unit);
    931     soc_control_t *soc = SOC_CONTROL(unit);
    932     uint32 entries_per_buf, rval;
    933     int rv, interval, non_empty;
    934     uint8 ch;
    935     uint32 *buff_max, intr_mask;
    936     void *host_entry, *host_buff;
    937     int entry_words;
    938 
    939     if (SOC_IS_TD2_TT2(unit)) {
    940         /*
    941          * Channel 0 is for X pipe
    942          * Channel 1 is for Y pipe but nothing will go into Y pipe L2_MOD_FIFO.
    943          */
    944         ch = SOC_MEM_FIFO_DMA_CHANNEL_0;
    945     } else {
    946         ch = SOC_MEM_FIFO_DMA_CHANNEL_1;
    947     }
    948     intr_mask = IRQ_CMCx_FIFO_CH_DMA(ch);
    949 
    950     entries_per_buf = soc_property_get(unit, spn_L2XMSG_HOSTBUF_SIZE, 1024);
    951     adv_threshold = entries_per_buf / 2;
    952 
    953     entry_words = soc_mem_entry_words(unit, L2_MOD_FIFOm);
    954     host_buff = soc_cm_salloc(unit, entries_per_buf * entry_words * sizeof(uint32),
    955                              "L2_MOD DMA Buffer");
    956     if (host_buff == NULL) {
    957         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR,
    958                            SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__,
    959                            SOC_E_MEMORY);
    960         goto cleanup_exit;
    961     }
    962     (void)_soc_mem_sbus_fifo_dma_stop(unit, ch);
    963 
    964     rv = _soc_mem_sbus_fifo_dma_start(unit, ch, L2_MOD_FIFOm, MEM_BLOCK_ANY,
    965                                       entries_per_buf, host_buff);
    966     if (SOC_FAILURE(rv)) {
    967         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR,
    968                            SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, rv);
    969         goto cleanup_exit;
    970     }
    971 
    972     host_entry = host_buff;
    973     buff_max = (uint32 *)host_entry + (entries_per_buf * entry_words);
    974 
    975     if (!soc_feature(unit, soc_feature_fifo_dma)) {
    976         soc_cmicm_intr0_enable(unit,
    977                 IRQ_CMCx_FIFO_CH_DMA(SOC_MEM_FIFO_DMA_CHANNEL_1));
    978     }
    979     if (SOC_IS_TRIUMPH3(unit)) {
    980         _soc_l2mod_sbus_fifo_enable(unit, 1);
    981 #ifdef BCM_TOMAHAWK_SUPPORT
    982     } else if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
    983         _soc_th_l2mod_sbus_fifo_enable(unit, 1);
    984 #endif /* BCM_TOMAHAWK_SUPPORT */
    985     } else {
    986         _soc_td2_l2mod_sbus_fifo_enable(unit, 1);
    987     }
    988 
    989     while ((interval = soc->l2x_interval)) {
    990         overflow = 0; timeout = 0;
    991         if (soc->l2modDmaIntrEnb) {
    992             soc_cmicm_intr0_enable(unit, intr_mask);
    993             if (sal_sem_take(soc->arl_notify, interval) < 0) {
    994                 LOG_VERBOSE(BSL_LS_SOC_INTR,
    995                             (BSL_META_U(unit,
    996                                         "%s polling timeout soc_mem_fifo_delay_value=%d\n"),
    997                              soc->l2x_name, soc_mem_fifo_delay_value));
    998             } else {
    999                 LOG_VERBOSE(BSL_LS_SOC_INTR,
   1000                             (BSL_META_U(unit,
   1001                                         "%s woken up soc_mem_fifo_delay_value=%d\n"),
   1002                              soc->l2x_name, soc_mem_fifo_delay_value));
   1003                 /* check for timeout or overflow and either process or continue */
   1004                 rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, ch));
   1005                 timeout = soc_reg_field_get(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STATr,
   1006                                             rval, HOSTMEM_TIMEOUTf);
   1007                 if (!timeout) {
   1008                     overflow = soc_reg_field_get(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STATr,
   1009                                                  rval, HOSTMEM_OVERFLOWf);
   1010                     timeout |= overflow;
   1011                 }
   1012             }
   1013 
   1014         } else {
   1015             sal_usleep(interval);
   1016         }
   1017 
   1018         handled_count = 0;
   1019         do {
   1020             non_empty = FALSE;
   1021             /* get entry count, process if nonzero else continue */
   1022             rv = _soc_mem_sbus_fifo_dma_get_num_entries(unit, ch, &count);
   1023             if (SOC_SUCCESS(rv)) {
   1024                 non_empty = TRUE;
   1025                 if (count > adv_threshold) {
   1026                     count = adv_threshold;
   1027                 }
   1028                 /* Invalidate DMA memory to read */
   1029                 if (((uint32 *)host_entry + count * entry_words) > buff_max) {
   1030                     /* roll-over cases */
   1031                     soc_cm_sinval(unit, host_entry,
   1032                         (buff_max - (uint32 *)host_entry) * sizeof(uint32));
   1033                     soc_cm_sinval(unit, host_buff,
   1034                         ((count * entry_words) - (buff_max - (uint32 *)host_entry)) * sizeof(uint32));
   1035                 }
   1036                 else {
   1037                     soc_cm_sinval(unit, host_entry, (count * entry_words) * sizeof(uint32));
   1038                 }
   1039                 for (i = 0; i < count; i++) {
   1040                     if(!soc->l2x_interval) {
   1041                         goto cleanup_exit;
   1042                     }
   1043 #ifdef BCM_TRIUMPH3_SUPPORT
   1044                     if (SOC_IS_TRIUMPH3(unit)) {
   1045                         soc_tr3_l2mod_fifo_process(unit, soc->l2x_flags,
   1046                                                    host_entry);
   1047                     } else
   1048 #endif
   1049                     {
   1050 #ifdef BCM_KATANA2_SUPPORT
   1051                         if (SOC_IS_KATANA2(unit)) {
   1052                             _soc_kt_l2mod_fifo_process(unit, soc->l2x_flags,
   1053                                     host_entry);
   1054 
   1055                         } else
   1056 #endif
   1057 #ifdef BCM_HURRICANE2_SUPPORT
   1058                         if (soc_feature(unit, soc_feature_fifo_dma_hu2)) {
   1059                             _soc_hu2_l2mod_fifo_process(unit, soc->l2x_flags,
   1060                                     host_entry);
   1061 
   1062                         } else
   1063 #endif
   1064                         {
   1065 #ifdef BCM_TRIDENT2_SUPPORT
   1066                             _soc_td2_l2mod_fifo_process(unit, soc->l2x_flags,
   1067                                     host_entry);
   1068 #endif /* BCM_TRIDENT2_SUPPORT*/
   1069                         }
   1070                     }
   1071                     host_entry = (uint32 *)host_entry + entry_words;
   1072                     /* handle roll over */
   1073                     if ((uint32 *)host_entry >= buff_max) {
   1074                         host_entry = host_buff;
   1075                     }
   1076 
   1077                     handled_count ++;
   1078                     /*
   1079                      * PPA may wait for available space in mod_fifo, lower the
   1080                      * threshold when ppa is running, therefore read point can
   1081                      * be updated sooner.
   1082                      */
   1083                     if (SOC_CONTROL(unit)->l2x_ppa_in_progress && i >= 63) {
   1084                         i++;
   1085                         break;
   1086                     }
   1087                 }
   1088                 (void)_soc_mem_sbus_fifo_dma_set_entries_read(unit, ch, i);
   1089             }
   1090 
   1091             /* check and clear error */
   1092             rval = soc_pci_read(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, ch));
   1093             if (soc_reg_field_get(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STATr, rval,
   1094                                   DONEf)) {
   1095                 LOG_ERROR(BSL_LS_SOC_COMMON,
   1096                           (BSL_META_U(unit,
   1097                                       "FIFO DMA engine terminated for cmc[%d]:ch[%d]\n"),
   1098                            cmc, ch));
   1099                 if (soc_reg_field_get(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STATr, rval,
   1100                                   ERRORf)) {
   1101                     LOG_ERROR(BSL_LS_SOC_COMMON,
   1102                               (BSL_META_U(unit,
   1103                                           "FIFO DMA engine encountered error: [0x%x]\n"),
   1104                                rval));
   1105                 }
   1106                 soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR,
   1107                                    SOC_SWITCH_EVENT_THREAD_L2MOD_DMA, __LINE__, SOC_E_INTERNAL);
   1108                 goto cleanup_exit;
   1109             }
   1110 
   1111             if (!SOC_CONTROL(unit)->l2x_ppa_in_progress) {
   1112                 /* For some operating systems, sal_thread_yield is
   1113                  * not sufficient to yield CPU resource to other lower
   1114                  * priority thread
   1115                  */
   1116                 if ((handled_count * 2) >= adv_threshold) {
   1117                     sal_usleep(1000);
   1118                     handled_count = 0;
   1119                 }
   1120             }
   1121         } while (non_empty);
   1122         /* Clearing of the FIFO_CH_DMA_INT interrupt by resetting
   1123            overflow & timeout status in FIFO_CHy_RD_DMA_STAT_CLR reg */
   1124         if (timeout) {
   1125             rval = 0;
   1126             soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STAT_CLRr, &rval,
   1127                               HOSTMEM_OVERFLOWf, 1);
   1128             soc_reg_field_set(unit, CMIC_CMC0_FIFO_CH0_RD_DMA_STAT_CLRr, &rval,
   1129                               HOSTMEM_TIMEOUTf, 1);
   1130             soc_pci_write(unit, CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_CLR_OFFSET(cmc, ch),
   1131                           rval);
   1132         }
   1133     }
   1134 
   1135 cleanup_exit:
   1136     (void)_soc_mem_sbus_fifo_dma_stop(unit, ch);
   1137 
   1138     if (host_buff != NULL) {
   1139         soc_cm_sfree(unit, host_buff);
   1140     }
   1141     if (SOC_IS_TRIUMPH3(unit)) {
   1142         _soc_l2mod_sbus_fifo_enable(unit, 0);
   1143 #ifdef BCM_TOMAHAWK_SUPPORT
   1144     } else if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   1145         _soc_th_l2mod_sbus_fifo_enable(unit, 0);
   1146 #endif /* BCM_TOMAHAWK_SUPPORT */
   1147     } else {
   1148         _soc_td2_l2mod_sbus_fifo_enable(unit, 0);
   1149     }
   1150 
   1151     soc->l2x_pid = SAL_THREAD_ERROR;
   1152     sal_thread_exit(0);
   1153 }
   1154 
   1155 /*
   1156  * Function:
   1157  *     soc_l2mod_running
   1158  * Purpose:
   1159  *     Determine the L2MOD sync thread running parameters
   1160  * Parameters:
   1161  *     unit - unit number.
   1162  *     flags (OUT) - if non-NULL, receives the current flag settings
   1163  *     interval (OUT) - if non-NULL, receives the current pass interval
   1164  * Returns:
   1165  *     Boolean; TRUE if L2MOD sync thread is running
   1166  */
   1167 
   1168 int
   1169 _soc_l2mod_running(int unit, uint32 *flags, sal_usecs_t *interval)
   1170 {
   1171 #ifdef BCM_XGS3_SWITCH_SUPPORT
   1172     soc_control_t *soc = SOC_CONTROL(unit);
   1173 
   1174     if (SOC_IS_XGS3_SWITCH(unit)) {
   1175         if (soc->l2x_pid != SAL_THREAD_ERROR) {
   1176             if (flags != NULL) {
   1177                 *flags = soc->l2x_flags;
   1178             }
   1179             if (interval != NULL) {
   1180                 *interval = soc->l2x_interval;
   1181             }
   1182         }
   1183 
   1184         return (soc->l2x_pid != SAL_THREAD_ERROR);
   1185     }
   1186 #endif /* BCM_XGS3_SWITCH_SUPPORT */
   1187     return SOC_E_UNAVAIL;
   1188 }
   1189 
   1190 /*
   1191  * Function:
   1192  *     _soc_l2mod_stop
   1193  * Purpose:
   1194  *     Stop L2MOD-related thread
   1195  * Parameters:
   1196  *     unit - unit number.
   1197  * Returns:
   1198  *     SOC_E_XXX
   1199  */
   1200 int
   1201 _soc_l2mod_stop(int unit)
   1202 {
   1203     soc_control_t * soc = SOC_CONTROL(unit);
   1204     int rv = SOC_E_NONE;
   1205     uint8 ch = SOC_MEM_FIFO_DMA_CHANNEL_1;
   1206 
   1207     if (SOC_IS_XGS3_SWITCH(unit)) {
   1208         LOG_INFO(BSL_LS_SOC_ARL,
   1209                  (BSL_META_U(unit,
   1210                              "soc_l2mod_stop: unit=%d\n"), unit));
   1211 
   1212         if (SOC_IS_TRIUMPH3(unit)) {
   1213             _soc_l2mod_sbus_fifo_enable(unit, 0);
   1214 #ifdef BCM_TOMAHAWK_SUPPORT
   1215         } else if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) {
   1216             _soc_th_l2mod_sbus_fifo_enable(unit, 0);
   1217 #endif /* BCM_TOMAHAWK_SUPPORT */
   1218         } else {
   1219             _soc_td2_l2mod_sbus_fifo_enable(unit, 0);
   1220         }
   1221         if (!soc_feature(unit, soc_feature_fifo_dma)) {
   1222             soc_cmicm_intr0_disable(unit, IRQ_CMCx_FIFO_CH_DMA(ch));
   1223             soc->l2x_interval = 0;  /* Request exit */
   1224         }
   1225 
   1226         if (soc->l2modDmaIntrEnb) {
   1227             /* Wake up thread so it will check the exit flag */
   1228             sal_sem_give(soc->arl_notify);
   1229         }
   1230 
   1231         return rv;
   1232     }
   1233     return SOC_E_UNAVAIL;
   1234 }
   1235 
   1236 int
   1237 _soc_l2mod_start(int unit, uint32 flags, sal_usecs_t interval)
   1238 {
   1239     soc_control_t * soc = SOC_CONTROL(unit);
   1240     int             pri;
   1241 
   1242     if (!soc_feature(unit, soc_feature_arl_hashed)) {
   1243         return SOC_E_UNAVAIL;
   1244     }
   1245 
   1246     if (soc->l2x_interval != 0) {
   1247         SOC_IF_ERROR_RETURN(_soc_l2mod_stop(unit));
   1248     }
   1249 
   1250     sal_snprintf(soc->l2x_name, sizeof(soc->l2x_name), "bcmL2MOD.%d", unit);
   1251 
   1252     soc->l2x_flags = flags;
   1253     soc->l2x_interval = interval;
   1254 
   1255     if (interval == 0) {
   1256         return SOC_E_NONE;
   1257     }
   1258 
   1259     if (soc->l2x_pid == SAL_THREAD_ERROR) {
   1260         pri = soc_property_get(unit, spn_L2XMSG_THREAD_PRI, 50);
   1261 
   1262         soc->l2x_pid =
   1263                 sal_thread_create(soc->l2x_name, SAL_THREAD_STKSZ, pri,
   1264                                   _soc_l2mod_sbus_fifo_dma_thread, INT_TO_PTR(unit));
   1265         if (soc->l2x_pid == SAL_THREAD_ERROR) {
   1266             LOG_ERROR(BSL_LS_SOC_COMMON,
   1267                       (BSL_META_U(unit,
   1268                                   "soc_l2mod_start: Could not start L2MOD thread\n")));
   1269             return SOC_E_MEMORY;
   1270         }
   1271     }
   1272 
   1273     return SOC_E_NONE;
   1274 }
   1275 
   1276 int
   1277 _soc_l2mod_sbus_fifo_field_set(int unit, soc_field_t field, int enable)
   1278 {
   1279     uint32 rval = 0;
   1280     uint32 fval = enable?1:0;
   1281 
   1282     if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT(unit) ||
   1283         SOC_IS_TITAN2(unit) || SOC_IS_TITAN(unit)|| 
   1284         SOC_IS_HURRICANE2(unit)|| SOC_IS_HURRICANE3(unit)||
   1285         SOC_IS_GREYHOUND(unit) || SOC_IS_GREYHOUND2(unit) ||
   1286         SOC_IS_KATANA2(unit)) {
   1287         if(soc_reg_field_valid(unit, AUX_ARB_CONTROLr, field)) {
   1288             SOC_IF_ERROR_RETURN(READ_AUX_ARB_CONTROLr(unit, &rval));
   1289 
   1290             soc_reg_field_set(unit, AUX_ARB_CONTROLr, &rval, field, fval);
   1291 
   1292             SOC_IF_ERROR_RETURN(WRITE_AUX_ARB_CONTROLr(unit, rval));
   1293 
   1294             API_SET_AUX_ARB_CNTL(unit, field, fval);
   1295         }
   1296         return SOC_E_NONE;
   1297     }
   1298     if (SOC_IS_TRIUMPH3(unit) || SOC_IS_TOMAHAWKX(unit)) {
   1299         if(soc_reg_field_valid(unit, L2_MOD_FIFO_ENABLEr, field)) {
   1300             SOC_IF_ERROR_RETURN(READ_L2_MOD_FIFO_ENABLEr(unit, &rval));
   1301 
   1302             soc_reg_field_set(unit, L2_MOD_FIFO_ENABLEr, &rval, field, fval);
   1303 
   1304             SOC_IF_ERROR_RETURN(WRITE_L2_MOD_FIFO_ENABLEr(unit, rval));
   1305 
   1306             API_SET_L2_MOD_FIFO_ENABLE(unit, field, fval);
   1307         }
   1308         return SOC_E_NONE;
   1309     }
   1310     return SOC_E_UNAVAIL;
   1311 }
   1312 
   1313 int
   1314 _soc_l2mod_sbus_fifo_field_get(int unit, soc_field_t field, int *enable)
   1315 {
   1316     uint32 reg = 0;
   1317     uint32 fval = 0;
   1318 
   1319     if (SOC_IS_TRIDENT2X(unit) || SOC_IS_TRIDENT(unit) ||
   1320         SOC_IS_TITAN2(unit) || SOC_IS_TITAN(unit) ||
   1321         SOC_IS_HURRICANE2(unit) || SOC_IS_HURRICANE3(unit) ||
   1322         SOC_IS_GREYHOUND(unit) || SOC_IS_GREYHOUND2(unit) ||
   1323         SOC_IS_KATANA2(unit)) {
   1324         if(soc_reg_field_valid(unit, AUX_ARB_CONTROLr, field)) {
   1325             SOC_IF_ERROR_RETURN(READ_AUX_ARB_CONTROLr(unit, &reg));
   1326 
   1327             fval = soc_reg_field_get(unit, AUX_ARB_CONTROLr, reg, field);
   1328         }
   1329         *enable = fval?1:0;
   1330         return SOC_E_NONE;
   1331     }
   1332     if (SOC_IS_TRIUMPH3(unit) || SOC_IS_TOMAHAWKX(unit)) {
   1333         if(soc_reg_field_valid(unit, L2_MOD_FIFO_ENABLEr, field)) {
   1334             SOC_IF_ERROR_RETURN(READ_L2_MOD_FIFO_ENABLEr(unit, &reg));
   1335 
   1336             fval = soc_reg_field_get(unit, L2_MOD_FIFO_ENABLEr, reg, field);
   1337 
   1338         }
   1339         *enable = fval?1:0;
   1340         return SOC_E_NONE;
   1341     }
   1342 
   1343     return SOC_E_UNAVAIL;
   1344 }
   1345 
   1346 #endif /* BCM_XGS3_SWITCH_SUPPORT */ /* DPPCOMPILEENABLE */
   1347 #endif /* BCM_CMICM_SUPPORT */
   1348 #endif /* defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) */
   1349 
   1350