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, ®, ABORTf, 0); 182 soc_reg_field_set(unit, CMIC_CMC0_CCM_DMA_CFGr, ®, 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, ®, 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) */