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_ccmdma.c (10810B)


      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 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_CMICM_SUPPORT) && defined(BCM_CCMDMA_SUPPORT)
     18 #include <soc/cmicm.h>
     19 #endif
     20 
     21 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT)
     22 #if defined(BCM_CMICM_SUPPORT) && defined(BCM_CCMDMA_SUPPORT)
     23 
     24 typedef struct cmicm_ccmdma_ch_s {
     25     sal_spinlock_t  lock[SOC_MAX_NUM_DEVICES][CMIC_CMC_NUM_MAX];
     26     int timeout;
     27     uint32  ch[SOC_MAX_NUM_DEVICES][CMIC_CMC_NUM_MAX];
     28 }cmicm_ccmdma_ch_t;
     29 
     30 STATIC cmicm_ccmdma_ch_t  _cmicm_ccmdma_ch;
     31 
     32 /*******************************************
     33 * @function _cmicm_ccmdma_ch_get
     34 * purpose get idle DMA channel
     35 *
     36 * @param unit [in] unit #
     37 * @param vchan [out] channel number
     38 *
     39 * @returns SOC_E_BUSY
     40 * @returns SOC_E_NONE
     41 *
     42 * @end
     43  */
     44 static int
     45 _cmicm_ccmdma_ch_get(int unit, int *vchan)
     46 {
     47     int rv = SOC_E_BUSY;
     48     int j;
     49     soc_timeout_t to;
     50 
     51     soc_timeout_init(&to, _cmicm_ccmdma_ch.timeout, 10);
     52     do {
     53         for(j = 0; j < CMIC_CMC_NUM_MAX; j++) {
     54             sal_spinlock_lock(_cmicm_ccmdma_ch.lock[unit][j]);
     55             if(_cmicm_ccmdma_ch.ch[unit][j] == 1) {
     56                 *vchan = j;
     57                 _cmicm_ccmdma_ch.ch[unit][j] = 0;
     58                 sal_spinlock_unlock(_cmicm_ccmdma_ch.lock[unit][j]);
     59                 rv = SOC_E_NONE;
     60                 break;
     61             }
     62             sal_spinlock_unlock(_cmicm_ccmdma_ch.lock[unit][j]);
     63         }
     64         if (rv == SOC_E_NONE) {
     65             break;
     66         }
     67     } while (!soc_timeout_check(&to));
     68     return rv;
     69 }
     70 
     71 /*******************************************
     72 * @function _cmicm_ccmdma_ch_put
     73 * purpose put back the channel on free list
     74 *
     75 * @param ch [in] channel number
     76 *
     77 * @returns SOC_E_PARAM
     78 * @returns SOC_E_NONE
     79 *
     80 * @end
     81  */
     82 static int
     83 _cmicm_ccmdma_ch_put(int unit, int vchan)
     84 {
     85     sal_spinlock_lock(_cmicm_ccmdma_ch.lock[unit][vchan]);
     86     _cmicm_ccmdma_ch.ch[unit][vchan] = 1;
     87     sal_spinlock_unlock(_cmicm_ccmdma_ch.lock[unit][vchan]);
     88     return SOC_E_NONE;
     89 }
     90 
     91 /*******************************************
     92 * @function _cmicm_ccmdma_copy
     93 * purpose to initiate DMA from source to
     94 *            destination memory on vchan
     95 * @param srcbuf [in] pointer to source memory
     96 * @param dstbuf [in] pointer to dest memory
     97 * @param count [in] number of bytes to xfer
     98 * @param flags [in]
     99 * @param vchan [in] channel number
    100 *
    101 * @returns SOC_E_XXXX
    102 * @returns SOC_E_NONE
    103 *
    104 * @end
    105  */
    106 static int
    107 _cmicm_ccmdma_copy(int unit, sal_paddr_t *srcbuf, sal_paddr_t *dstbuf,
    108                    unsigned int src_is_internal, unsigned int dst_is_internal,
    109                    int count, int flags, int vchan)
    110 {
    111     int i, rv;
    112     soc_control_t *soc = SOC_CONTROL(unit);
    113     uint32 *srcptr;
    114     uint32 *dstptr;
    115     uint32 reg, reg2;
    116     int cmc = vchan; /* as one channel/CMC in CMICM/D */
    117 
    118     if (src_is_internal) {
    119 #ifdef PTRS_ARE_64BITS
    120          srcbuf = (sal_paddr_t *)soc_cm_p2l(unit, ((uint64)srcbuf | 0xf0000000));
    121 #else
    122          srcbuf = (sal_paddr_t *)soc_cm_p2l(unit, ((uint32)srcbuf | 0xf0000000));
    123 #endif
    124     }
    125 
    126     if (dst_is_internal) {
    127 #ifdef PTRS_ARE_64BITS
    128          dstbuf = (sal_paddr_t *)soc_cm_p2l(unit, ((uint64)dstbuf | 0xf0000000));
    129 #else
    130          dstbuf = (sal_paddr_t *)soc_cm_p2l(unit, ((uint32)dstbuf | 0xf0000000));
    131 #endif
    132     }
    133 
    134     srcptr = (uint32 *)srcbuf;
    135     dstptr = (uint32 *)dstbuf;
    136 
    137     assert (srcptr && dstptr);
    138 
    139     if (SOC_CONTROL(unit)->ccmDmaMutex[cmc] == 0) {
    140         /* If DMA not enabled, or short length use PIO to copy */
    141         for (i = 0; i < count; i ++ ) {
    142             if (flags & 2) {            /* Read from PCI */
    143                 reg = soc_pci_mcs_read(unit, PTR_TO_INT(srcptr));
    144             } else {
    145                 reg = *srcptr;
    146             }
    147 
    148             if (flags & 1) {
    149                 reg = ((reg & 0xff000000) >> 24) |
    150                     ((reg & 0x00ff0000) >> 8) |
    151                     ((reg & 0x0000ff00) << 8) |
    152                     ((reg & 0x000000ff) << 24);
    153             }
    154 
    155             if (flags & 2) {
    156                 *dstptr = reg;
    157             } else {
    158                 soc_pci_mcs_write(unit, PTR_TO_INT(dstptr), reg);
    159                 reg2 = soc_pci_mcs_read(unit, PTR_TO_INT(dstptr));
    160                 if (reg2 != reg) {
    161                     LOG_ERROR(BSL_LS_SOC_SOCMEM,
    162                               (BSL_META_U(unit,
    163                                           "ccm_dma: compare error %x (%x %x)\n"),
    164                                PTR_TO_INT(dstptr), reg, reg2));
    165                 }
    166             }
    167 
    168             dstptr++;
    169             srcptr++;
    170         }
    171         return SOC_E_NONE;
    172     }
    173 
    174     CCM_DMA_LOCK(unit, cmc);
    175 
    176     soc_pci_write(unit, CMIC_CMCx_CCM_DMA_HOST0_MEM_START_ADDR_OFFSET(cmc), soc_cm_l2p(unit, srcbuf));
    177     soc_pci_write(unit, CMIC_CMCx_CCM_DMA_HOST1_MEM_START_ADDR_OFFSET(cmc), soc_cm_l2p(unit, dstbuf));
    178     soc_pci_write(unit, CMIC_CMCx_CCM_DMA_ENTRY_COUNT_OFFSET(cmc), count);
    179     /* Keep endianess default... */
    180     reg = soc_pci_read(unit, CMIC_CMCx_CCM_DMA_CFG_OFFSET(cmc));
    181     soc_reg_field_set(unit, CMIC_CMC0_CCM_DMA_CFGr, &reg, ABORTf, 0);
    182     soc_reg_field_set(unit, CMIC_CMC0_CCM_DMA_CFGr, &reg, ENf, 0);
    183     soc_pci_write(unit, CMIC_CMCx_CCM_DMA_CFG_OFFSET(cmc), reg);  /* Clearing EN clears stats */
    184     /* Start DMA */
    185     soc_reg_field_set(unit, CMIC_CMC0_CCM_DMA_CFGr, &reg, ENf, 1);
    186     soc_pci_write(unit, CMIC_CMCx_CCM_DMA_CFG_OFFSET(cmc), reg);
    187 
    188     rv = SOC_E_TIMEOUT;
    189     if (soc->ccmDmaIntrEnb) {
    190             (void)soc_cmicm_cmcx_intr0_enable(unit, cmc, IRQ_CMCx_CCMDMA_DONE);
    191             if (sal_sem_take(soc->ccmDmaIntr[cmc], soc->ccmDmaTimeout) < 0) {
    192                 rv = SOC_E_TIMEOUT;
    193             }
    194            (void)soc_cmicm_cmcx_intr0_disable(unit, cmc, IRQ_CMCx_CCMDMA_DONE);
    195 
    196             reg = soc_pci_read(unit, CMIC_CMCx_CCM_DMA_STAT_OFFSET(cmc));
    197             if (soc_reg_field_get(unit, CMIC_CMC0_CCM_DMA_STATr,
    198                                                         reg, DONEf)) {
    199                 rv = SOC_E_NONE;
    200                 if (soc_reg_field_get(unit, CMIC_CMC0_CCM_DMA_STATr,
    201                                                         reg, ERRORf)) {
    202                     rv = SOC_E_FAIL;
    203                 }
    204             }
    205     } else {
    206         soc_timeout_t to;
    207         LOG_WARN(BSL_LS_SOC_SOCMEM,
    208                  (BSL_META_U(unit,
    209                              "using Polling mode for CCM DMA\n")));
    210         soc_timeout_init(&to, soc->ccmDmaTimeout, 10000);
    211         do {
    212             reg = soc_pci_read(unit, CMIC_CMCx_CCM_DMA_STAT_OFFSET(cmc));
    213             if (soc_reg_field_get(unit, CMIC_CMC0_CCM_DMA_STATr,
    214                                                     reg, DONEf)) {
    215                 rv = SOC_E_NONE;
    216                 if (soc_reg_field_get(unit, CMIC_CMC0_CCM_DMA_STATr,
    217                                                     reg, ERRORf)) {
    218                     rv = SOC_E_FAIL;
    219                 }
    220                 break;
    221             }
    222         } while(!(soc_timeout_check(&to)));
    223     }
    224 
    225     if (rv == SOC_E_TIMEOUT) {
    226         LOG_ERROR(BSL_LS_SOC_SOCMEM,
    227                   (BSL_META_U(unit,
    228                               "CcmDmaTimeout: unit %d, ccm_dma timeout\n"), unit));
    229 
    230         /* Abort CCM DMA */
    231 
    232         /* Dummy read to allow abort to finish */
    233 
    234         /* Disable CCM DMA */
    235 
    236         /* Clear ccm DMA abort bit */
    237     }
    238 
    239     CCM_DMA_UNLOCK(unit, cmc);
    240     return rv;
    241 
    242 }
    243 
    244 /*******************************************
    245 * @function _cmicm_ccmdma_abort
    246 * purpose to abort active DMA operation on
    247 *            given channel
    248 * @param vchan [in] channel number
    249 *
    250 * @returns SOC_E_XXXX
    251 * @returns SOC_E_NONE
    252 *
    253 * @end
    254  */
    255 static int
    256 _cmicm_ccmdma_abort(int unit, int vchan)
    257 {
    258     int rv = SOC_E_UNAVAIL;
    259 
    260 
    261     return rv;
    262 }
    263 
    264 /*******************************************
    265 * @function cmicm_ccmdma_clean
    266 * purpose to clean
    267 * @param max_cmc [in] number of cmc
    268 *
    269 * @returns SOC_E_XXXX
    270 * @returns SOC_E_NONE
    271 *
    272 * @end
    273  */
    274 static int
    275 _cmicm_ccmdma_clean(int unit, int max_cmc)
    276 {
    277     int rv = 0;
    278     uint32 cfg_dw;
    279     int cmc;
    280 
    281     for (cmc = 0; cmc < max_cmc; cmc++) {
    282         cfg_dw = soc_pci_read(unit, CMIC_CMCx_CCM_DMA_CFG_OFFSET(cmc));
    283         soc_reg_field_set(unit, CMIC_CMC0_CCM_DMA_CFGr, &cfg_dw, ABORTf, 1);
    284         soc_pci_write(unit, CMIC_CMCx_CCM_DMA_CFG_OFFSET(cmc), cfg_dw);
    285     }
    286     sal_usleep(1000);
    287     for (cmc = 0; cmc < max_cmc; cmc++) {
    288         soc_pci_write(unit, CMIC_CMCx_CCM_DMA_CFG_OFFSET(cmc), 0x00000000);
    289         soc_pci_write(unit, CMIC_CMCx_CCM_DMA_STAT_OFFSET(cmc), 0x00000000);
    290     }
    291 
    292     return rv;
    293 }
    294 
    295 /*******************************************
    296 * @function cmicm_ccmdma_init
    297 * purpose API to Initialize cmicm CCM DMA
    298 *
    299 * @param unit [in] unit
    300 * @param drv [out] soc_ccmdma_drv_t pointer
    301 *
    302 * @returns SOC_E_NONE
    303 * @returns SOC_E_XXX
    304 *
    305 * @end
    306  */
    307 int cmicm_ccmdma_init(int unit, soc_ccmdma_drv_t *drv)
    308 {
    309     int rv = SOC_E_NONE;
    310     int j;
    311 
    312     for(j = 0; j < CMIC_CMC_NUM_MAX; j++) {
    313         _cmicm_ccmdma_ch.lock[unit][j] = sal_spinlock_create("ccmdma Lock");
    314         if (_cmicm_ccmdma_ch.lock[unit][j] == NULL) {
    315             rv = SOC_E_MEMORY;
    316             goto cleanup_exit;
    317         }
    318         if(j  < SOC_PCI_CMCS_NUM(unit)) {
    319             _cmicm_ccmdma_ch.ch[unit][j] = 1; /* only one CCMDMA channel/CMC */
    320         }
    321     }
    322 
    323     _cmicm_ccmdma_ch.timeout = SAL_BOOT_QUICKTURN ? CCMDMA_TIMEOUT_QT : CCMDMA_TIMEOUT;
    324     drv->soc_ccmdma_ch_get  = _cmicm_ccmdma_ch_get;
    325     drv->soc_ccmdma_ch_put = _cmicm_ccmdma_ch_put;
    326     drv->soc_ccmdma_copy = _cmicm_ccmdma_copy;
    327     drv->soc_ccmdma_abort = _cmicm_ccmdma_abort;
    328     drv->soc_ccmdma_clean = _cmicm_ccmdma_clean;
    329     return SOC_E_NONE;
    330 
    331 cleanup_exit:
    332     for(j = 0; j < CMIC_CMC_NUM_MAX; j++) {
    333         if(_cmicm_ccmdma_ch.lock[unit][j] != NULL)  {
    334             sal_spinlock_destroy(_cmicm_ccmdma_ch.lock[unit][j]);
    335         }
    336     }
    337     return(rv);
    338 }
    339 
    340 /*******************************************
    341 * @function cmicm_ccmdma_deinit
    342 * purpose API to Deinitialize cmicm CCM DMA
    343 *
    344 * @param unit [in] unit
    345 * @param drv [in] soc_ccmdma_drv_t pointer
    346 *
    347 * @returns SOC_E_NONE
    348 
    349 *
    350 * @end
    351  */
    352 int cmicm_ccmdma_deinit(int unit, soc_ccmdma_drv_t *drv)
    353 {
    354     int j;
    355 
    356     drv->soc_ccmdma_ch_get  = NULL;
    357     drv->soc_ccmdma_ch_put = NULL;
    358     drv->soc_ccmdma_copy = NULL;
    359     drv->soc_ccmdma_abort = NULL;
    360 
    361     for(j = 0; j < CMIC_CMC_NUM_MAX; j++) {
    362         if(_cmicm_ccmdma_ch.lock[unit][j] != NULL)  {
    363             (void)sal_spinlock_destroy(_cmicm_ccmdma_ch.lock[unit][j]);
    364         }
    365     }
    366     return SOC_E_NONE;
    367 }
    368 
    369 #endif /* BCM_CCMDMA_SUPPORT */
    370 #endif /* defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) */