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

l2.c (14823B)


      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:        l2.c
      8  * Purpose:     Katana L2 functions
      9  */
     10 
     11 #include <soc/mem.h>
     12 #include <soc/drv.h>
     13 #include <bcm/error.h>
     14 #include <shared/bsl.h>
     15 #ifdef BCM_CMICM_SUPPORT
     16 #include <soc/cmicm.h>
     17 #endif
     18 #ifdef BCM_KATANA_SUPPORT
     19 #include <soc/katana.h>
     20 #endif
     21 
     22 
     23 #if defined(BCM_ESW_SUPPORT)
     24 #if defined(BCM_KATANA_SUPPORT) && defined(BCM_CMICM_SUPPORT)
     25 
     26 #define RD_DMA_CFG_REG                   0
     27 #define RD_DMA_HOTMEM_THRESHOLD_REG      1
     28 #define RD_DMA_STAT                      2
     29 #define RD_DMA_STAT_CLR                  3
     30 
     31 int
     32 _soc_mem_kt_fifo_dma_start(int unit, int chan, soc_mem_t mem, int copyno,
     33                         int host_entries, void *host_buf)
     34 {
     35     soc_control_t  *soc = SOC_CONTROL(unit);
     36     soc_reg_t cfg_reg, thresh_reg;
     37     uint32 addr, rval, data_beats, sel, spacing;
     38     uint8 at;
     39     int cmc = SOC_PCI_CMC(unit);
     40 
     41     if (chan < 0 || chan > 3 || host_buf == NULL) {
     42         return SOC_E_PARAM;
     43     }
     44 
     45     if(!soc_feature(unit, soc_feature_cmicm)) {
     46         return BCM_E_UNAVAIL;
     47     }
     48 
     49     switch (host_entries) {
     50     case 64:    sel = 0; break;
     51     case 128:   sel = 1; break;
     52     case 256:   sel = 2; break;
     53     case 512:   sel = 3; break;
     54     case 1024:  sel = 4; break;
     55     case 2048:  sel = 5; break;
     56     case 4096:  sel = 6; break;
     57     case 8192:  sel = 7; break;
     58     case 16384: sel = 8; break;
     59     case 32768: sel = 9; break;
     60     case 65536: sel = 10; break;
     61     default:
     62         return SOC_E_PARAM;
     63     }
     64 
     65     if (mem != ING_IPFIX_EXPORT_FIFOm && mem != EGR_IPFIX_EXPORT_FIFOm &&
     66         mem != EXT_L2_MOD_FIFOm && mem != L2_MOD_FIFOm) {
     67         return SOC_E_BADID;
     68     }
     69 
     70     if (copyno == MEM_BLOCK_ANY) {
     71         copyno = SOC_MEM_BLOCK_ANY(unit, mem);
     72     }
     73 
     74     data_beats = soc_mem_entry_words(unit, mem);
     75 
     76     addr = CMIC_CMCx_FIFO_CHy_RD_DMA_SBUS_START_ADDRESS_OFFSET(cmc, chan);
     77     rval = soc_mem_addr_get(unit, mem, 0, copyno, 0, &at);
     78     soc_pci_write(unit, addr, rval);
     79 
     80     addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_START_ADDRESS_OFFSET(cmc, chan);
     81     rval = soc_cm_l2p(unit, host_buf);
     82     soc_pci_write(unit, addr, rval);
     83 
     84     addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_READ_PTR_OFFSET(cmc, chan);
     85     soc_pci_write(unit, addr, rval);
     86 
     87     addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_THRESHOLD_OFFSET(cmc, chan);
     88     rval = 0;
     89     thresh_reg = _soc_kt_fifo_reg_get (unit, 
     90                     cmc, chan, RD_DMA_HOTMEM_THRESHOLD_REG);
     91     soc_reg_field_set(unit, thresh_reg, &rval, ADDRESSf,
     92             host_entries / 16 * data_beats * sizeof(uint32));
     93     soc_pci_write(unit, addr, rval);
     94 
     95     cfg_reg = _soc_kt_fifo_reg_get (unit, cmc, chan, RD_DMA_CFG_REG);
     96     addr = CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, chan);
     97     rval = 0;
     98     rval = soc_pci_read(unit, addr);
     99     soc_reg_field_set(unit, cfg_reg, &rval, BEAT_COUNTf, data_beats);
    100     soc_reg_field_set(unit, cfg_reg, &rval, HOST_NUM_ENTRIES_SELf, sel);
    101     soc_reg_field_set(unit, cfg_reg, &rval, TIMEOUT_COUNTf, 200);
    102 
    103     if (soc_feature(unit, soc_feature_multi_sbus_cmds)) {
    104         
    105         if (soc->sbusCmdSpacing < 0) {
    106             spacing = data_beats > 7 ? data_beats + 1 : 8;
    107         } else {
    108             spacing = soc->sbusCmdSpacing;
    109         }
    110         if ((SOC_BLOCK_TYPE(unit, copyno) == SOC_BLK_ESM) ||
    111             (SOC_BLOCK_TYPE(unit, copyno) == SOC_BLK_XQPORT) ||
    112             (SOC_BLOCK_TYPE(unit, copyno) == SOC_BLK_GXPORT) ||
    113             (SOC_BLOCK_TYPE(unit, copyno) == SOC_BLK_SPORT) ||
    114             (SOC_BLOCK_TYPE(unit, copyno) == SOC_BLK_GPORT)) {
    115             spacing = 0;
    116         }
    117         if (spacing) {
    118             soc_reg_field_set(unit, cfg_reg, &rval,
    119                               MULTIPLE_SBUS_CMD_SPACINGf, spacing);
    120             soc_reg_field_set(unit, cfg_reg, &rval,
    121                               ENABLE_MULTIPLE_SBUS_CMDSf, 1);
    122         }
    123     }
    124     soc_pci_write(unit, addr, rval);
    125 
    126     soc_reg_field_set(unit, cfg_reg, &rval, ENABLEf, 1);
    127 /*    soc_reg_field_set(unit, cfg_reg, &rval, ENABLE_VALf, 1);*/
    128     soc_pci_write(unit, addr, rval);
    129 
    130     return SOC_E_NONE;
    131 }
    132 
    133 int
    134 _soc_mem_kt_fifo_dma_stop(int unit, int chan)
    135 {
    136     soc_reg_t cfg_reg;
    137     uint32 addr, rval;
    138     int cmc = SOC_PCI_CMC(unit);
    139 
    140     if (chan < 0 || chan > 3) {
    141         return SOC_E_PARAM;
    142     }
    143 
    144     if(!soc_feature(unit, soc_feature_cmicm)) {
    145         return BCM_E_UNAVAIL;
    146     }
    147     
    148     addr = CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, chan);
    149     cfg_reg = _soc_kt_fifo_reg_get (unit, cmc, chan, RD_DMA_CFG_REG);
    150     rval = soc_pci_read(unit, addr);
    151 
    152    /* Resetting ENABLE field disables the channel on which the DMA thread 
    153    is running. This is done to ensure that no operation is performed in that 
    154    channel when corresponding DMA thread is not active. As the operations 
    155    happening in the L2 layer in Mod_Fifo mode are communicated to upper layer 
    156    via callbacks processed from DMA copy, it is important to disable channel 
    157    when dma thread is stopped and is enabled again when DMA thread is started*/
    158 
    159     soc_reg_field_set(unit, cfg_reg, &rval, ENABLEf, 0);
    160     soc_pci_write(unit, addr, rval);
    161 
    162     return SOC_E_NONE;
    163 }
    164 
    165 int
    166 _soc_mem_kt_fifo_dma_get_read_ptr(int unit, int chan, void **host_ptr, int *count)
    167 {
    168     soc_reg_t cfg_reg, stat_reg;
    169     int host_entries, data_beats;
    170     soc_field_t overflow_field;
    171     uint32 addr, rval, stat, hostmem_addr, read_ptr, write_ptr;
    172     int cmc = SOC_PCI_CMC(unit);
    173     
    174     if (chan < 0 || chan > 3 || host_ptr == NULL) {
    175         return SOC_E_PARAM;
    176     }
    177 
    178     if(!soc_feature(unit, soc_feature_cmicm)) {
    179         return BCM_E_UNAVAIL;
    180     }
    181 
    182     read_ptr = 0;
    183     addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_READ_PTR_OFFSET(cmc, chan);
    184     soc_pci_getreg(unit, addr, &read_ptr);
    185 
    186     addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_WRITE_PTR_OFFSET(cmc, chan);
    187     write_ptr = 0;
    188     soc_pci_getreg(unit, addr, &write_ptr);
    189 
    190     if (write_ptr == 0) {
    191         return SOC_E_EMPTY;
    192     }
    193 
    194     switch(chan) {
    195     case 1: overflow_field = FIFO_CH1_DMA_HOSTMEM_OVERFLOWf; break;
    196     case 2: overflow_field = FIFO_CH2_DMA_HOSTMEM_OVERFLOWf; break;
    197     case 3: overflow_field = FIFO_CH3_DMA_HOSTMEM_OVERFLOWf; break;
    198     default: overflow_field = FIFO_CH0_DMA_HOSTMEM_OVERFLOWf; break;
    199     }
    200 
    201     if (read_ptr == write_ptr) {
    202         addr = CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_OFFSET(cmc, chan);
    203         stat = 0;
    204         soc_pci_getreg(unit, addr, &stat);
    205         stat_reg = _soc_kt_fifo_reg_get (unit, cmc, chan, RD_DMA_STAT);
    206         if (!soc_reg_field_get(unit, stat_reg, stat, overflow_field)) {
    207             return SOC_E_EMPTY;
    208         }
    209 
    210         /* Re-read write pointer */
    211         addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_WRITE_PTR_OFFSET(cmc, chan);
    212         write_ptr = 0;
    213         soc_pci_getreg(unit, addr, &write_ptr);
    214     }
    215 
    216     addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_START_ADDRESS_OFFSET(cmc, chan);
    217     hostmem_addr = 0;
    218     soc_pci_getreg(unit, addr, &hostmem_addr);
    219     addr = CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, chan);
    220     rval = 0;
    221     soc_pci_getreg(unit, addr, &rval);
    222 
    223     cfg_reg = _soc_kt_fifo_reg_get (unit, cmc, chan, RD_DMA_CFG_REG);
    224     data_beats = soc_reg_field_get(unit, cfg_reg, rval, BEAT_COUNTf);
    225     if (data_beats <= 0) {
    226         LOG_ERROR(BSL_LS_BCM_L2,
    227                   (BSL_META_U(unit,
    228                               "Invalid BEAT_COUNT (%d) in "
    229                               "CMIC_CMC%d_FIFO_CH%d_RD_DMA_CFG \n"), data_beats, cmc, chan));
    230         return SOC_E_CONFIG;
    231     }
    232 
    233     switch (soc_reg_field_get(unit, cfg_reg, rval, HOST_NUM_ENTRIES_SELf)) {
    234     case 0:  host_entries = 64;    break;
    235     case 1:  host_entries = 128;   break;
    236     case 2:  host_entries = 256;   break;
    237     case 3:  host_entries = 512;   break;
    238     case 4:  host_entries = 1024;  break;
    239     case 5:  host_entries = 2048;  break;
    240     case 6:  host_entries = 4096;  break;
    241     case 7:  host_entries = 8192;  break;
    242     case 8:  host_entries = 16384; break;
    243     case 9:  host_entries = 32768; break;
    244     case 10: host_entries = 65536; break;
    245     default: return SOC_E_CONFIG;
    246     }
    247 
    248     *host_ptr = soc_cm_p2l(unit, read_ptr);
    249     if (read_ptr >= write_ptr) {
    250         *count = host_entries -
    251             (read_ptr - hostmem_addr) / data_beats / sizeof(uint32);
    252     } else {
    253         *count = (write_ptr - read_ptr) / data_beats / sizeof(uint32);
    254     }
    255 
    256     return (*count) ? SOC_E_NONE : SOC_E_EMPTY;
    257 }
    258 
    259 int
    260 _soc_mem_kt_fifo_dma_advance_read_ptr(int unit, int chan, int count)
    261 {
    262     soc_reg_t cfg_reg, statclr_reg;
    263     soc_field_t overflow_field;
    264     int host_entries, data_beats;
    265     uint32 addr, rval, statclr;
    266     uint32 *host_buf, *read_ptr;
    267     int cmc = SOC_PCI_CMC(unit);
    268 
    269     if (chan < 0 || chan > 3) {
    270         return SOC_E_PARAM;
    271     }
    272 
    273     if(!soc_feature(unit, soc_feature_cmicm)) {
    274         return BCM_E_UNAVAIL;
    275     }
    276 
    277     cfg_reg = _soc_kt_fifo_reg_get (unit, cmc, chan, RD_DMA_CFG_REG);
    278     addr = CMIC_CMCx_FIFO_CHy_RD_DMA_CFG_OFFSET(cmc, chan);
    279     rval = 0;
    280     soc_pci_getreg(unit, addr, &rval);
    281     data_beats = soc_reg_field_get(unit, cfg_reg, rval, BEAT_COUNTf);
    282 
    283     switch (soc_reg_field_get(unit, cfg_reg, rval, HOST_NUM_ENTRIES_SELf)) {
    284     case 0:  host_entries = 64;    break;
    285     case 1:  host_entries = 128;   break;
    286     case 2:  host_entries = 256;   break;
    287     case 3:  host_entries = 512;   break;
    288     case 4:  host_entries = 1024;  break;
    289     case 5:  host_entries = 2048;  break;
    290     case 6:  host_entries = 4096;  break;
    291     case 7:  host_entries = 8192;  break;
    292     case 8:  host_entries = 16384; break;
    293     case 9:  host_entries = 32768; break;
    294     case 10: host_entries = 65536; break;
    295     default: return SOC_E_CONFIG;
    296     }
    297 
    298     if (count < 0 || count >= host_entries) {
    299         return SOC_E_PARAM;
    300     }
    301 
    302     /* Clear threshold overflow_field bit */
    303     switch(chan) {
    304     case 1: overflow_field = FIFO_CH1_DMA_HOSTMEM_OVERFLOWf; break;
    305     case 2: overflow_field = FIFO_CH2_DMA_HOSTMEM_OVERFLOWf; break;
    306     case 3: overflow_field = FIFO_CH3_DMA_HOSTMEM_OVERFLOWf; break;
    307     default: overflow_field = FIFO_CH0_DMA_HOSTMEM_OVERFLOWf; break;
    308     }
    309 
    310     addr = CMIC_CMCx_FIFO_CHy_RD_DMA_STAT_CLR_OFFSET(cmc, chan);
    311     statclr_reg = _soc_kt_fifo_reg_get (unit, cmc, chan, RD_DMA_STAT_CLR);
    312     statclr = 0;
    313     soc_reg_field_set(unit, statclr_reg, &statclr, overflow_field, 1);
    314     soc_pci_write(unit, addr, statclr);
    315 
    316     addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_START_ADDRESS_OFFSET(cmc, chan);
    317     rval = 0;
    318     soc_pci_getreg(unit, addr, &rval);
    319     host_buf = soc_cm_p2l(unit, rval);
    320 
    321     addr = CMIC_CMCx_FIFO_CHy_RD_DMA_HOSTMEM_READ_PTR_OFFSET(cmc, chan);
    322     rval = 0;
    323     soc_pci_getreg(unit, addr, &rval);
    324     read_ptr = soc_cm_p2l(unit, rval);
    325 
    326     read_ptr += count * data_beats;
    327     if (read_ptr >= &host_buf[host_entries * data_beats]) {
    328         read_ptr -= host_entries * data_beats;
    329     }
    330     rval = soc_cm_l2p(unit, read_ptr);
    331     soc_pci_write(unit, addr, rval);
    332 
    333     return SOC_E_NONE;
    334 }
    335 
    336 soc_reg_t
    337 _soc_kt_fifo_reg_get(int unit, int cmc, int chan, int type)
    338 {
    339     switch(type) {
    340     case RD_DMA_HOTMEM_THRESHOLD_REG:
    341         switch((cmc << 4) + chan) {
    342         case 0x00: return CMIC_CMC0_FIFO_CH0_RD_DMA_HOSTMEM_THRESHOLDr;
    343         case 0x01: return CMIC_CMC0_FIFO_CH1_RD_DMA_HOSTMEM_THRESHOLDr;
    344         case 0x02: return CMIC_CMC0_FIFO_CH2_RD_DMA_HOSTMEM_THRESHOLDr;
    345         case 0x03: return CMIC_CMC0_FIFO_CH3_RD_DMA_HOSTMEM_THRESHOLDr;
    346         case 0x10: return CMIC_CMC1_FIFO_CH0_RD_DMA_HOSTMEM_THRESHOLDr;
    347         case 0x11: return CMIC_CMC1_FIFO_CH1_RD_DMA_HOSTMEM_THRESHOLDr;
    348         case 0x12: return CMIC_CMC1_FIFO_CH2_RD_DMA_HOSTMEM_THRESHOLDr;
    349         case 0x13: return CMIC_CMC1_FIFO_CH3_RD_DMA_HOSTMEM_THRESHOLDr;
    350         case 0x20: return CMIC_CMC2_FIFO_CH0_RD_DMA_HOSTMEM_THRESHOLDr;
    351         case 0x21: return CMIC_CMC2_FIFO_CH1_RD_DMA_HOSTMEM_THRESHOLDr;
    352         case 0x22: return CMIC_CMC2_FIFO_CH2_RD_DMA_HOSTMEM_THRESHOLDr;
    353         case 0x23: return CMIC_CMC2_FIFO_CH3_RD_DMA_HOSTMEM_THRESHOLDr;
    354         default: return CMIC_CMC0_FIFO_CH0_RD_DMA_HOSTMEM_THRESHOLDr;
    355         }
    356         break;
    357     case RD_DMA_CFG_REG:
    358         switch((cmc << 4) + chan) {
    359         case 0x00: return CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr;
    360         case 0x01: return CMIC_CMC0_FIFO_CH1_RD_DMA_CFGr;
    361         case 0x02: return CMIC_CMC0_FIFO_CH2_RD_DMA_CFGr;
    362         case 0x03: return CMIC_CMC0_FIFO_CH3_RD_DMA_CFGr;
    363         case 0x10: return CMIC_CMC1_FIFO_CH0_RD_DMA_CFGr;
    364         case 0x11: return CMIC_CMC1_FIFO_CH1_RD_DMA_CFGr;
    365         case 0x12: return CMIC_CMC1_FIFO_CH2_RD_DMA_CFGr;
    366         case 0x13: return CMIC_CMC1_FIFO_CH3_RD_DMA_CFGr;
    367         case 0x20: return CMIC_CMC2_FIFO_CH0_RD_DMA_CFGr;
    368         case 0x21: return CMIC_CMC2_FIFO_CH1_RD_DMA_CFGr;
    369         case 0x22: return CMIC_CMC2_FIFO_CH2_RD_DMA_CFGr;
    370         case 0x23: return CMIC_CMC2_FIFO_CH3_RD_DMA_CFGr;
    371         default: return CMIC_CMC0_FIFO_CH0_RD_DMA_CFGr;
    372         }
    373     case RD_DMA_STAT:
    374         switch((cmc << 4) + chan) {
    375         case 0x00: return CMIC_CMC0_FIFO_CH0_RD_DMA_STATr;
    376         case 0x01: return CMIC_CMC0_FIFO_CH1_RD_DMA_STATr;
    377         case 0x02: return CMIC_CMC0_FIFO_CH2_RD_DMA_STATr;
    378         case 0x03: return CMIC_CMC0_FIFO_CH3_RD_DMA_STATr;
    379         case 0x10: return CMIC_CMC1_FIFO_CH0_RD_DMA_STATr;
    380         case 0x11: return CMIC_CMC1_FIFO_CH1_RD_DMA_STATr;
    381         case 0x12: return CMIC_CMC1_FIFO_CH2_RD_DMA_STATr;
    382         case 0x13: return CMIC_CMC1_FIFO_CH3_RD_DMA_STATr;
    383         case 0x20: return CMIC_CMC2_FIFO_CH0_RD_DMA_STATr;
    384         case 0x21: return CMIC_CMC2_FIFO_CH1_RD_DMA_STATr;
    385         case 0x22: return CMIC_CMC2_FIFO_CH2_RD_DMA_STATr;
    386         case 0x23: return CMIC_CMC2_FIFO_CH3_RD_DMA_STATr;
    387         default: return CMIC_CMC0_FIFO_CH0_RD_DMA_STATr;
    388         }
    389     case RD_DMA_STAT_CLR:
    390         switch((cmc << 4) + chan) {
    391         case 0x00: return CMIC_CMC0_FIFO_CH0_RD_DMA_STAT_CLRr;
    392         case 0x01: return CMIC_CMC0_FIFO_CH1_RD_DMA_STAT_CLRr;
    393         case 0x02: return CMIC_CMC0_FIFO_CH2_RD_DMA_STAT_CLRr;
    394         case 0x03: return CMIC_CMC0_FIFO_CH3_RD_DMA_STAT_CLRr;
    395         case 0x10: return CMIC_CMC1_FIFO_CH0_RD_DMA_STAT_CLRr;
    396         case 0x11: return CMIC_CMC1_FIFO_CH1_RD_DMA_STAT_CLRr;
    397         case 0x12: return CMIC_CMC1_FIFO_CH2_RD_DMA_STAT_CLRr;
    398         case 0x13: return CMIC_CMC1_FIFO_CH3_RD_DMA_STAT_CLRr;
    399         case 0x20: return CMIC_CMC2_FIFO_CH0_RD_DMA_STAT_CLRr;
    400         case 0x21: return CMIC_CMC2_FIFO_CH1_RD_DMA_STAT_CLRr;
    401         case 0x22: return CMIC_CMC2_FIFO_CH2_RD_DMA_STAT_CLRr;
    402         case 0x23: return CMIC_CMC2_FIFO_CH3_RD_DMA_STAT_CLRr;
    403         default: return CMIC_CMC0_FIFO_CH0_RD_DMA_STAT_CLRr;
    404         }
    405     default: return INVALIDr; break;
    406     }
    407 }
    408 
    409 #endif /*BCM_CMICM_SUPPORT && BCM_KATANA_SUPPORT*/
    410 #endif /*BCM_ESW_SUPPORT*/