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

cmicx_ccmdma.c (13582B)


      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: CMICX CCM DMA Driver
      8  */
      9 
     10 #include <shared/bsl.h>
     11 #include <shared/alloc.h>
     12 #include <soc/drv.h>
     13 #include <soc/debug.h>
     14 #include <soc/cm.h>
     15 #include <soc/ccmdma_internal.h>
     16 
     17 #if defined(BCM_CMICX_SUPPORT) && defined(BCM_CCMDMA_SUPPORT)
     18 #include <soc/cmicx.h>
     19 #endif
     20 
     21 #if defined(BCM_ESW_SUPPORT) || \
     22     defined(BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT)
     23 #if defined(BCM_CMICX_SUPPORT) && defined(BCM_CCMDMA_SUPPORT)
     24 
     25 typedef struct cmicx_ccmdma_ch_s {
     26     sal_spinlock_t  lock[SOC_MAX_NUM_DEVICES][CMIC_CMC_NUM_MAX];
     27     int timeout;
     28     uint32  ch[SOC_MAX_NUM_DEVICES][CMIC_CMC_NUM_MAX];
     29 }cmicx_ccmdma_ch_t;
     30 
     31 STATIC cmicx_ccmdma_ch_t  _cmicx_ccmdma_ch;
     32 
     33 /*******************************************
     34 * @function _cmicx_ccmdma_ch_get
     35 * purpose get idle DMA channel
     36 *
     37 * @param unit [in] unit #
     38 * @param vchan [out] channel number
     39 *
     40 * @returns SOC_E_BUSY
     41 * @returns SOC_E_NONE
     42 *
     43 * @end
     44  */
     45 static int
     46 _cmicx_ccmdma_ch_get(int unit, int *vchan)
     47 {
     48     int rv = SOC_E_BUSY;
     49     int j, ch;
     50     soc_timeout_t to;
     51 
     52     soc_timeout_init(&to, _cmicx_ccmdma_ch.timeout, 10);
     53     do {
     54         for(j = 0; j < CMIC_CMC_NUM_MAX; j++) {
     55             sal_spinlock_lock(_cmicx_ccmdma_ch.lock[unit][j]);
     56             for(ch = 0; ch < CMICX_N_CCMDMA_CHAN; ch++) {
     57                 if(_cmicx_ccmdma_ch.ch[unit][j] & (1 << ch)) {
     58                     *vchan = (j * CMICX_N_CCMDMA_CHAN) + ch;
     59                     _cmicx_ccmdma_ch.ch[unit][j] &= ~(1 << ch);
     60                     rv = SOC_E_NONE;
     61                     break;
     62                 }
     63             }
     64             sal_spinlock_unlock(_cmicx_ccmdma_ch.lock[unit][j]);
     65         }
     66         if (rv == SOC_E_NONE) {
     67             break;
     68         }
     69     } while (!soc_timeout_check(&to));
     70     return rv;
     71 }
     72 
     73 /*******************************************
     74 * @function _cmicx_ccmdma_ch_put
     75 * purpose put back the channel on free list
     76 *
     77 * @param ch [in] channel number
     78 *
     79 * @returns SOC_E_PARAM
     80 * @returns SOC_E_NONE
     81 *
     82 * @end
     83  */
     84 static int
     85 _cmicx_ccmdma_ch_put(int unit, int vchan)
     86 {
     87     int cmc, ch;
     88     cmc = vchan / CMICX_N_CCMDMA_CHAN;
     89     ch = vchan % CMICX_N_CCMDMA_CHAN;
     90     sal_spinlock_lock(_cmicx_ccmdma_ch.lock[unit][cmc]);
     91     _cmicx_ccmdma_ch.ch[unit][cmc] |= 1 << ch;
     92     sal_spinlock_unlock(_cmicx_ccmdma_ch.lock[unit][cmc]);
     93     return SOC_E_NONE;
     94 }
     95 
     96 /*******************************************
     97 * @function _cmicx_ccmdma_copy_wait
     98 * purpose to initiate DMA from source to
     99 *            destination memory on vchan
    100 * @param vchan [in] channel number
    101 *
    102 * @returns SOC_E_XXXX
    103 * @returns SOC_E_NONE
    104 *
    105 * @end
    106  */
    107 static int
    108 _cmicx_ccmdma_copy_wait(int unit, int vchan)
    109 {
    110     int cmc, ch;
    111     int rv = SOC_E_TIMEOUT;
    112     soc_control_t *soc = SOC_CONTROL(unit);
    113     unsigned int reg;
    114 
    115     cmc = vchan / CMICX_N_CCMDMA_CHAN;
    116     ch = vchan % CMICX_N_CCMDMA_CHAN;
    117 
    118     CCM_DMA_LOCK(unit, cmc);
    119 
    120     if (soc->ccmDmaIntrEnb) {
    121         if (sal_sem_take(soc->ccmDmaIntr[cmc], soc->ccmDmaTimeout) < 0) {
    122             rv = SOC_E_TIMEOUT;
    123         }
    124         reg = soc_pci_read(unit, CMIC_CMCx_CCMDMA_CHy_STAT_OFFSET(cmc, ch));
    125         if (soc_reg_field_get(unit, CMIC_CMC0_CCMDMA_CH0_STATr,
    126                                                     reg, DONEf)) {
    127             rv = SOC_E_NONE;
    128             if (soc_reg_field_get(unit, CMIC_CMC0_CCMDMA_CH0_STATr,
    129                                                     reg, ERRORf)) {
    130                 rv = SOC_E_FAIL;
    131             }
    132         }
    133     } else {
    134         soc_timeout_t to;
    135         LOG_DEBUG(BSL_LS_SOC_SOCMEM,
    136                  (BSL_META_U(unit,
    137                              "using Polling mode for CCM DMA\n")));
    138         soc_timeout_init(&to, soc->ccmDmaTimeout, 10000);
    139         do {
    140             reg = soc_pci_read(unit, CMIC_CMCx_CCMDMA_CHy_STAT_OFFSET(cmc, ch));
    141             if (soc_reg_field_get(unit, CMIC_CMC0_CCMDMA_CH0_STATr,
    142                                                     reg, DONEf)) {
    143                 rv = SOC_E_NONE;
    144                 if (soc_reg_field_get(unit, CMIC_CMC0_CCMDMA_CH0_STATr,
    145                                                     reg, ERRORf)) {
    146                     rv = SOC_E_FAIL;
    147                 }
    148                 break;
    149             }
    150         } while(!(soc_timeout_check(&to)));
    151     }
    152 
    153     if (rv == SOC_E_TIMEOUT) {
    154         LOG_ERROR(BSL_LS_SOC_SOCMEM,
    155                   (BSL_META_U(unit,
    156                               "CcmDmaTimeout: unit %d, ccm_dma timeout\n"), unit));
    157 
    158         /* Abort CCM DMA */
    159 
    160         /* Dummy read to allow abort to finish */
    161 
    162         /* Disable CCM DMA */
    163 
    164         /* Clear ccm DMA abort bit */
    165     }
    166     CCM_DMA_UNLOCK(unit, cmc);
    167 
    168     return rv;
    169 
    170 }
    171 
    172 /*******************************************
    173 * @function _cmicx_ccmdma_endian_config
    174 * purpose Configure endianess ccmdma engine
    175 *
    176 * @param unit [in] unit
    177 * @param val [in] uint32  pointer
    178 *
    179 * @returns None
    180 * @end
    181  */
    182 STATIC void
    183 _cmicx_ccmdma_endian_config(int unit,
    184                             unsigned int src_is_internal,
    185                             unsigned int dst_is_internal,
    186                             uint32 *val)
    187 {
    188     int  big_pio, big_packet, big_other;
    189 
    190     soc_endian_get(unit, &big_pio, &big_packet, &big_other);
    191 
    192     if (big_other & !src_is_internal) {
    193         soc_reg_field_set(unit, CMIC_CMC0_CCMDMA_CH0_CFGr, val, PROCESSOR0_ENDIANESSf, 1);
    194     } else {
    195         soc_reg_field_set(unit, CMIC_CMC0_CCMDMA_CH0_CFGr, val, PROCESSOR0_ENDIANESSf, 0);
    196     }
    197     if (big_other & !dst_is_internal) {
    198         soc_reg_field_set(unit, CMIC_CMC0_CCMDMA_CH0_CFGr, val, PROCESSOR1_ENDIANESSf, 1);
    199     } else {
    200         soc_reg_field_set(unit, CMIC_CMC0_CCMDMA_CH0_CFGr, val, PROCESSOR1_ENDIANESSf, 0);
    201     }
    202 }
    203 
    204 
    205 /*******************************************
    206 * @function _cmicx_ccmdma_copy
    207 * purpose to initiate DMA from source to
    208 *            destination memory on vchan
    209 * @param srcbuf [in] pointer to source memory
    210 * @param dstbuf [in] pointer to dest memory
    211 * @param count [in] number of bytes to xfer
    212 * @param flags [in]
    213 * @param vchan [in] channel number
    214 *
    215 * @returns SOC_E_XXXX
    216 * @returns SOC_E_NONE
    217 *
    218 * @end
    219  */
    220 static int
    221 _cmicx_ccmdma_copy(int unit, sal_paddr_t *srcbuf, sal_paddr_t *dstbuf,
    222                    unsigned int src_is_internal, unsigned int dst_is_internal,
    223                    int count, int flags, int vchan)
    224 {
    225     int i, rv = SOC_E_NONE;
    226     soc_control_t *soc = SOC_CONTROL(unit);
    227     unsigned int *srcptr = (unsigned int *)srcbuf;
    228     unsigned int *dstptr = (unsigned int *)dstbuf;
    229     unsigned int reg, reg2;
    230     int cmc, ch;
    231     unsigned int offset = 0;
    232     sal_paddr_t addr;
    233 
    234     /* If src/dst is internal, then the corresponding srcbuf/dstbuf 
    235      * should be a Physical Address. If external, then Logical Address.
    236      */
    237 
    238     srcptr = (unsigned int *)srcbuf;
    239     dstptr = (unsigned int *)dstbuf;
    240 
    241     assert (srcptr && dstptr);
    242 
    243     cmc = vchan / CMICX_N_CCMDMA_CHAN;
    244     ch = vchan % CMICX_N_CCMDMA_CHAN;
    245 
    246     if (soc->ccmDmaMutex[cmc] == 0) {
    247         /* If DMA not enabled, or short length use PIO to copy */
    248         for (i = 0; i < count; i ++ ) {
    249             if (flags & 2) {            /* Read from PCI */
    250                 reg = soc_cm_iproc_read(unit, PTR_TO_INT(srcptr));
    251             } else {
    252                 reg = *srcptr;
    253             }
    254 
    255             if (flags & 1) {
    256                 reg = ((reg & 0xff000000) >> 24) |
    257                     ((reg & 0x00ff0000) >> 8) |
    258                     ((reg & 0x0000ff00) << 8) |
    259                     ((reg & 0x000000ff) << 24);
    260             }
    261 
    262             if (flags & 2) {
    263                 *dstptr = reg;
    264             } else {
    265                 soc_cm_iproc_write(unit, PTR_TO_INT(dstptr), reg);
    266                 reg2 = soc_cm_iproc_read(unit, PTR_TO_INT(dstptr));
    267                 if (reg2 != reg) {
    268                     LOG_ERROR(BSL_LS_SOC_SOCMEM,
    269                               (BSL_META_U(unit,
    270                                           "ccm_dma: compare error %x (%x %x)\n"),
    271                                PTR_TO_INT(dstptr), reg, reg2));
    272                 }
    273             }
    274 
    275             dstptr++;
    276             srcptr++;
    277         }
    278         return SOC_E_NONE;
    279     }
    280 
    281     CCM_DMA_LOCK(unit, cmc);
    282 
    283     if (src_is_internal) {
    284         offset = 0;
    285 #if !defined(PTRS_ARE_64BITS) && defined(PHYS_ADDRS_ARE_64BITS)
    286         addr = (uint32) srcbuf;
    287 #else
    288         addr = (sal_paddr_t) srcbuf;
    289 #endif
    290     } else {
    291         if (soc_cm_get_bus_type(unit) & SOC_PCI_DEV_TYPE) {
    292             offset = 0x10000000;
    293         }
    294         addr = soc_cm_l2p(unit, srcbuf);
    295     }
    296 
    297     soc_pci_write(unit, CMIC_CMCx_CCMDMA_CHy_HOST0_MEM_START_ADDR_LO_OFFSET(cmc, ch), PTR_TO_INT(addr));
    298     soc_pci_write(unit, CMIC_CMCx_CCMDMA_CHy_HOST0_MEM_START_ADDR_HI_OFFSET(cmc, ch), offset | PTR_HI_TO_INT(addr));
    299 
    300     if (dst_is_internal) {
    301         offset = 0;
    302 #if !defined(PTRS_ARE_64BITS) && defined(PHYS_ADDRS_ARE_64BITS)
    303         addr = (uint32) dstbuf;
    304 #else
    305         addr = (sal_paddr_t) dstbuf;
    306 #endif
    307     } else {
    308         if (soc_cm_get_bus_type(unit) & SOC_PCI_DEV_TYPE) {
    309             offset = 0x10000000;
    310         }
    311         addr = soc_cm_l2p(unit, dstbuf);
    312     }
    313 
    314     soc_pci_write(unit, CMIC_CMCx_CCMDMA_CHy_HOST1_MEM_START_ADDR_LO_OFFSET(cmc, ch), PTR_TO_INT(addr));
    315     soc_pci_write(unit, CMIC_CMCx_CCMDMA_CHy_HOST1_MEM_START_ADDR_HI_OFFSET(cmc, ch), offset | PTR_HI_TO_INT(addr));
    316 
    317     soc_pci_write(unit, CMIC_CMCx_CCMDMA_CHy_ENTRY_COUNT_OFFSET(cmc, ch), count);
    318 
    319     reg = soc_pci_read(unit, CMIC_CMCx_CCMDMA_CHy_CFG_OFFSET(cmc, ch));
    320     soc_reg_field_set(unit, CMIC_CMC0_CCMDMA_CH0_CFGr, &reg, ABORTf, 0);
    321     _cmicx_ccmdma_endian_config(unit, src_is_internal, dst_is_internal, &reg);
    322     soc_reg_field_set(unit, CMIC_CMC0_CCMDMA_CH0_CFGr, &reg, ENf, 0);
    323     soc_pci_write(unit, CMIC_CMCx_CCMDMA_CHy_CFG_OFFSET(cmc, ch), reg);  /* Clearing EN clears stats */
    324 
    325     /* Start DMA */
    326     soc_reg_field_set(unit, CMIC_CMC0_CCMDMA_CH0_CFGr, &reg, ENf, 1);
    327     soc_pci_write(unit, CMIC_CMCx_CCMDMA_CHy_CFG_OFFSET(cmc, ch), reg);
    328 
    329     CCM_DMA_UNLOCK(unit, cmc);
    330     /* Don't wait for DMA Complete if flag bit 0x100 is set */
    331     if (!(flags & 4)) {
    332         rv = _cmicx_ccmdma_copy_wait(unit, vchan);
    333     }
    334     return rv;
    335 
    336 }
    337 
    338 /*******************************************
    339 * @function _cmicx_ccmdma_abort
    340 * purpose to abort active DMA operation on
    341 *            given channel
    342 * @param vchan [in] channel number
    343 *
    344 * @returns SOC_E_XXXX
    345 * @returns SOC_E_NONE
    346 *
    347 * @end
    348  */
    349 static int
    350 _cmicx_ccmdma_abort(int unit, int vchan)
    351 {
    352     int rv = SOC_E_UNAVAIL;
    353 
    354     return rv;
    355 }
    356 
    357 /*******************************************
    358 * @function cmicx_ccmdma_clean
    359 * purpose to clean
    360 * @param max_cmc [in] number of cmc
    361 *
    362 * @returns SOC_E_XXXX
    363 * @returns SOC_E_NONE
    364 *
    365 * @end
    366  */
    367 static int
    368 _cmicx_ccmdma_clean(int unit, int max_cmc)
    369 {
    370     int rv = 0;
    371     uint32 cfg_dw;
    372     int cmc, chan;
    373 
    374     for (cmc = 0; cmc < max_cmc; cmc++) {
    375         for (chan = 0; chan < CMICX_N_CCMDMA_CHAN; chan++) {
    376             cfg_dw = soc_pci_read(unit, CMIC_CMCx_CCMDMA_CHy_CFG_OFFSET(cmc, chan));
    377             soc_reg_field_set(unit, CMIC_CMC0_CCMDMA_CH0_CFGr, &cfg_dw, ABORTf, 0);
    378             soc_pci_write(unit, CMIC_CMCx_CCMDMA_CHy_CFG_OFFSET(cmc, chan), cfg_dw);
    379         }
    380     }
    381 
    382     sal_usleep(1000);
    383 
    384     for (cmc = 0; cmc < max_cmc; cmc++) {
    385         for (chan = 0; chan < CMICX_N_CCMDMA_CHAN; chan++) {
    386             soc_pci_write(unit, CMIC_CMCx_CCMDMA_CHy_CFG_OFFSET(cmc, chan), 0x00000000);
    387         }
    388     }
    389 
    390     return rv;
    391 }
    392 
    393 /*******************************************
    394 * @function cmicx_ccmdma_init
    395 * purpose API to Initialize cmicx CCM DMA
    396 *
    397 * @param unit [in] unit
    398 * @param drv [out] soc_ccmdma_drv_t pointer
    399 *
    400 * @returns SOC_E_NONE
    401 * @returns SOC_E_XXX
    402 *
    403 * @end
    404  */
    405 int cmicx_ccmdma_init(int unit, soc_ccmdma_drv_t *drv)
    406 {
    407     int rv = SOC_E_NONE;
    408     int j;
    409 
    410     for(j = 0; j < CMIC_CMC_NUM_MAX; j++) {
    411         _cmicx_ccmdma_ch.lock[unit][j] = sal_spinlock_create("ccmdma Lock");
    412         if (_cmicx_ccmdma_ch.lock[unit][j] == NULL) {
    413             rv = SOC_E_MEMORY;
    414             goto cleanup_exit;
    415         }
    416         if(j  < SOC_PCI_CMCS_NUM(unit)) {
    417             _cmicx_ccmdma_ch.ch[unit][j] = 0x3; /* Two CCMDMA channels/CMC */
    418         }
    419     }
    420 
    421     _cmicx_ccmdma_ch.timeout = SAL_BOOT_QUICKTURN ? CCMDMA_TIMEOUT_QT : CCMDMA_TIMEOUT;
    422     drv->soc_ccmdma_ch_get  = _cmicx_ccmdma_ch_get;
    423     drv->soc_ccmdma_ch_put = _cmicx_ccmdma_ch_put;
    424     drv->soc_ccmdma_copy = _cmicx_ccmdma_copy;
    425     drv->soc_ccmdma_copy_wait = _cmicx_ccmdma_copy_wait;
    426     drv->soc_ccmdma_abort = _cmicx_ccmdma_abort;
    427     drv->soc_ccmdma_clean = _cmicx_ccmdma_clean;
    428     return SOC_E_NONE;
    429 
    430 cleanup_exit:
    431     for(j = 0; j < CMIC_CMC_NUM_MAX; j++) {
    432         if(_cmicx_ccmdma_ch.lock[unit][j] != NULL)  {
    433             sal_spinlock_destroy(_cmicx_ccmdma_ch.lock[unit][j]);
    434         }
    435     }
    436     return(rv);
    437 }
    438 
    439 /*******************************************
    440 * @function cmicx_ccmdma_deinit
    441 * purpose API to Deinitialize cmicx CCM DMA
    442 *
    443 * @param unit [in] unit
    444 * @param drv [in] soc_ccmdma_drv_t pointer
    445 *
    446 * @returns SOC_E_NONE
    447 
    448 *
    449 * @end
    450  */
    451 int cmicx_ccmdma_deinit(int unit, soc_ccmdma_drv_t *drv)
    452 {
    453     int j;
    454 
    455     drv->soc_ccmdma_ch_get  = NULL;
    456     drv->soc_ccmdma_ch_put = NULL;
    457     drv->soc_ccmdma_copy = NULL;
    458     drv->soc_ccmdma_abort = NULL;
    459 
    460     for(j = 0; j < CMIC_CMC_NUM_MAX; j++) {
    461         if(_cmicx_ccmdma_ch.lock[unit][j] != NULL)  {
    462             (void)sal_spinlock_destroy(_cmicx_ccmdma_ch.lock[unit][j]);
    463         }
    464     }
    465     return SOC_E_NONE;
    466 }
    467 
    468 #endif /* BCM_CCMDMA_SUPPORT */
    469 #endif /* BCM_ESW_SUPPORT */
    470