cmicm_sbusdma_reg.c (39488B)
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 Register Based SBUS 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/sbusdma_internal.h> 16 17 #if defined(BCM_CMICM_SUPPORT) && defined(BCM_SBUSDMA_SUPPORT) 18 #include <soc/cmicm.h> 19 #endif 20 21 #ifdef BCM_TRIUMPH3_SUPPORT 22 #include <soc/er_tcam.h> 23 #include <soc/triumph3.h> 24 #endif 25 26 #ifdef BCM_KATANA2_SUPPORT 27 #include <soc/katana2.h> 28 #include <soc/katana.h> 29 #endif 30 31 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) 32 #if defined(BCM_CMICM_SUPPORT) && defined(BCM_SBUSDMA_SUPPORT) 33 34 #ifdef BCM_KATANA2_SUPPORT 35 #define RD_DMA_CFG_REG 0 36 #define RD_DMA_HOTMEM_THRESHOLD_REG 1 37 #define RD_DMA_STAT 2 38 #define RD_DMA_STAT_CLR 3 39 #endif 40 41 #define SOC_SBUSDMA_FP_RETRIES 200 42 43 #undef PRINT_DMA_TIME 44 45 STATIC uint32 _soc_irq_sbusdma_ch[] = { 46 IRQ_SBUSDMA_CH0_DONE, 47 IRQ_SBUSDMA_CH1_DONE, 48 IRQ_SBUSDMA_CH2_DONE 49 }; 50 51 STATIC int _soc_multi_cmc = 0; 52 53 /******************************************* 54 * @function _cmicm_sbusdma_reg_array_read 55 * purpose DMA acceleration for soc_mem_read_range() on FB/ER 56 * 57 * @param unit [in] unit 58 * @param drv [in] soc_sbusdma_reg_param_t pointer 59 * 60 * @returns SOC_E_NONE 61 * @returns SOC_E_XXX 62 * 63 * @end 64 */ 65 STATIC int 66 _cmicm_sbusdma_reg_array_read(int unit, soc_sbusdma_reg_param_t *param) 67 { 68 soc_control_t *soc = SOC_CONTROL(unit); 69 uint32 start_addr; 70 uint32 count; 71 uint32 data_beats; 72 uint32 spacing; 73 int rv = SOC_E_NONE; 74 uint32 ctrl, rval; 75 uint8 at; 76 int ch; 77 int cmc = SOC_PCI_CMC(unit); 78 schan_msg_t msg; 79 int dst_blk, acc_type, dma; 80 #ifdef PRINT_DMA_TIME 81 sal_usecs_t start_time; 82 int diff_time; 83 #endif 84 #if defined(BCM_TRIUMPH3_SUPPORT) 85 uint32 wa_rval, wa_val = 0; 86 #endif 87 88 LOG_VERBOSE(BSL_LS_SOC_DMA, 89 (BSL_META_U(unit, 90 "unit %d" 91 " mem %s.%s[%u] index %d-%d SER flags 0x%08x buffer %p\n"), 92 unit, SOC_MEM_UFNAME(unit, param->mem), SOC_BLOCK_NAME(unit, 93 param->copyno), param->array_id_start, param->index_begin, 94 param->index_end, param->flags, param->buffer)); 95 96 if (param->copyno == COPYNO_ALL) { 97 return SOC_E_INTERNAL; 98 } 99 100 data_beats = soc_mem_entry_words(unit, param->mem); 101 102 /* muticmc with grab all the channels and release one to grab */ 103 if (_soc_multi_cmc) { 104 SOC_IF_ERROR_RETURN(cmicm_sbusdma_ch_get(unit, &cmc, &ch)); 105 assert((ch >= 0) && (ch < CMIC_CMCx_SBUSDMA_CHAN_MAX)); 106 } else { 107 ch = soc->tdma_ch; 108 } 109 110 assert((ch >= 0) && (ch < soc->max_sbusdma_channels)); 111 count = param->index_end - param->index_begin + 1; 112 if (count < 1) { 113 if (_soc_multi_cmc) { 114 cmicm_sbusdma_ch_put(unit, cmc, ch); 115 } 116 return SOC_E_NONE; 117 } 118 schan_msg_clear(&msg); 119 acc_type = SOC_MEM_ACC_TYPE(unit, param->mem); 120 dst_blk = SOC_BLOCK2SCH(unit, param->copyno); 121 122 #if defined(BCM_XGS3_SWITCH_SUPPORT) 123 if (0 != (param->flags & _SOC_SER_FLAG_MULTI_PIPE)) { 124 if ((param->flags & _SOC_SER_FLAG_ACC_TYPE_MASK) || 125 (soc_feature(unit, soc_feature_unique_acc_type_access))) { 126 127 /* Override ACC_TYPE in opcode */ 128 acc_type = param->flags & _SOC_SER_FLAG_ACC_TYPE_MASK; 129 } 130 } 131 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 132 133 if (SOC_IS_ARAD(unit)) { 134 /* DMA transaction indicator on SBUS */ 135 dma = 1; 136 } else { 137 dma = 0; 138 } 139 soc_schan_header_cmd_set(unit, &msg.header, READ_MEMORY_CMD_MSG, 140 dst_blk, 0, acc_type, 4, dma, 0); 141 start_addr = soc_mem_addr_get(unit, param->mem, param->array_id_start, 142 param->copyno, param->index_begin, &at); 143 144 if (_soc_multi_cmc) { 145 SBUS_DMA_LOCK(unit, cmc, ch); 146 } else { 147 TABLE_DMA_LOCK(unit); 148 } 149 150 LOG_VERBOSE(BSL_LS_SOC_DMA, 151 (BSL_META_U(unit, 152 "unit=%d %s.acc_type = %0x, idx[%0d-%0d], cmc= %d, ch = %d\n"), 153 unit, SOC_MEM_NAME(unit, param->mem), acc_type, 154 param->index_begin, param->index_end, cmc, ch)); 155 156 #if defined(BCM_TRIUMPH3_SUPPORT) 157 if (soc_feature(unit, soc_feature_esm_correction) && 158 ((SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_ESM) || 159 (SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_ETU))) { 160 SOC_ESM_LOCK(unit); 161 } 162 #endif 163 164 ctrl = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch)); 165 /* Set mode, clear abort, start (clears status and errors) */ 166 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl, 167 MODEf, 0); 168 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl, 169 ABORTf, 0); 170 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl, 171 STARTf, 0); 172 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch), ctrl); 173 /* Set 1st schan ctrl word as opcode */ 174 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_OPCODE(cmc, ch), msg.dwords[0]); 175 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_HOSTADDR(cmc, ch), 176 soc_cm_l2p(unit, param->buffer)); 177 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_ADDRESS(cmc, ch), start_addr); 178 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_COUNT(cmc, ch), count); 179 180 /* Program beats, increment etc */ 181 rval = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_REQUEST(cmc, ch)); 182 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 183 REP_WORDSf, data_beats); 184 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 185 REQ_WORDSf, 0); 186 187 #if defined(BCM_TRIUMPH3_SUPPORT) 188 if (soc_feature(unit, soc_feature_etu_support)) { 189 if (SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_ETU) { 190 int index0, index1, increment; 191 soc_mem_t real_mem; 192 193 soc_tcam_mem_index_to_raw_index(unit, param->mem, 0, 194 &real_mem, &index0); 195 soc_tcam_mem_index_to_raw_index(unit, param->mem, 1, 196 &real_mem, &index1); 197 increment = _shr_popcount(index1 - index0 - 1); 198 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 199 INCR_SHIFTf, increment); 200 SOC_IF_ERROR_RETURN(READ_ETU_TX_REQ_FIFO_CTLr(unit, &wa_rval)); 201 wa_val = soc_reg_field_get(unit, ETU_TX_REQ_FIFO_CTLr, wa_rval, 202 CP_ACC_THRf); 203 soc_reg_field_set(unit, ETU_TX_REQ_FIFO_CTLr, &wa_rval, 204 CP_ACC_THRf, 0); 205 SOC_IF_ERROR_RETURN(WRITE_ETU_TX_REQ_FIFO_CTLr(unit, wa_rval)); 206 } else { 207 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 208 INCR_SHIFTf, 0); 209 if ((param->mem == EXT_L2_ENTRY_1m) || 210 (param->mem == EXT_L2_ENTRY_2m)) { 211 SOC_IF_ERROR_RETURN(READ_ETU_TX_REQ_FIFO_CTLr(unit, &wa_rval)); 212 wa_val = soc_reg_field_get(unit, ETU_TX_REQ_FIFO_CTLr, wa_rval, 213 CP_ACC_THRf); 214 soc_reg_field_set(unit, ETU_TX_REQ_FIFO_CTLr, &wa_rval, 215 CP_ACC_THRf, 0); 216 SOC_IF_ERROR_RETURN(WRITE_ETU_TX_REQ_FIFO_CTLr(unit, wa_rval)); 217 } 218 } 219 } else 220 #endif /* BCM_TRIUMPH3_SUPPORT */ 221 #if defined(BCM_SAND_SUPPORT) 222 if (SOC_IS_SAND(unit)) { 223 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 224 INCR_SHIFTf, 0); 225 } else 226 #endif 227 { 228 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 229 INCR_SHIFTf, 0); 230 } 231 if (soc_feature(unit, soc_feature_multi_sbus_cmds)) { 232 233 if (soc->sbusCmdSpacing < 0) { 234 spacing = data_beats > 7 ? data_beats + 1 : 8; 235 } else { 236 spacing = soc->sbusCmdSpacing; 237 } 238 if (!((SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_IPIPE) || 239 (SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_EPIPE))) { 240 spacing = 0; 241 } 242 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 243 PEND_CLOCKSf, spacing); 244 } 245 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_REQUEST(cmc, ch), rval); 246 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl, STARTf, 1); 247 /* Start DMA */ 248 #ifdef PRINT_DMA_TIME 249 start_time = sal_time_usecs(); 250 #endif 251 /* On BCMSIM, this interrupt just be reported one time. 252 If we enable this interrupt after starting table DMA, the interrupt may be lost. 253 But on chip, the interrupt will be reported continually until we clear STARTf of 254 CMIC_CMC0_SBUSDMA_CH0_CONTROLr */ 255 if (soc->tableDmaIntrEnb) { 256 soc_cmicm_cmcx_intr0_enable(unit, cmc, _soc_irq_sbusdma_ch[ch]); 257 } 258 259 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch), ctrl); 260 261 LOG_VERBOSE(BSL_LS_SOC_DMA, 262 (BSL_META_U(unit, 263 "%d entries %d beats " 264 "addr 0x%x (index %d-%d) Interrupt-Mode(%d)\n"), 265 count, data_beats, start_addr, param->index_begin, 266 param->index_end, soc->tableDmaIntrEnb)); 267 268 rv = SOC_E_TIMEOUT; 269 if (soc->tableDmaIntrEnb) { 270 if (SBUSDMA_DMA_INTR_WAIT(unit, cmc, ch, soc->tableDmaTimeout) < 0) { 271 rv = SOC_E_TIMEOUT; 272 LOG_VERBOSE(BSL_LS_SOC_COMMON, 273 (BSL_META_U(unit, 274 "%s.%s interrupt timeout\n"), 275 SOC_MEM_UFNAME(unit, param->mem), 276 SOC_BLOCK_NAME(unit, param->copyno))); 277 } 278 #ifdef PRINT_DMA_TIME 279 diff_time = SAL_USECS_SUB(sal_time_usecs(), start_time); 280 LOG_VERBOSE(BSL_LS_SOC_DMA, 281 (BSL_META_U(unit, 282 "(%s)HW dma read time[count=%u, beats=%u]: %d usecs, [%d nsecs per op]\n"), 283 SOC_MEM_UFNAME(unit, param->mem),count,data_beats, 284 diff_time, diff_time*1000/count)); 285 #endif 286 soc_cmicm_cmcx_intr0_disable(unit, cmc, _soc_irq_sbusdma_ch[ch]); 287 288 rval = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch)); 289 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 290 rval, DONEf)) { 291 rv = SOC_E_NONE; 292 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 293 rval, ERRORf)) { 294 rv = SOC_E_FAIL; 295 cmicm_sbusdma_curr_op_details(unit, cmc, ch); 296 } 297 } 298 } else { 299 soc_timeout_t to; 300 soc_timeout_init(&to, soc->tableDmaTimeout, 0); 301 do { 302 rval = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch)); 303 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 304 rval, DONEf)) { 305 rv = SOC_E_NONE; 306 #ifdef PRINT_DMA_TIME 307 diff_time = SAL_USECS_SUB(sal_time_usecs(), start_time); 308 LOG_VERBOSE(BSL_LS_SOC_DMA, 309 (BSL_META_U(unit, 310 "(%s)HW dma read poll time[count=%u, beats=%u]: %d usecs, [%d nsecs per op]\n"), 311 SOC_MEM_UFNAME(unit, param->mem),count, 312 data_beats, diff_time, diff_time*1000/count)); 313 #endif 314 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 315 rval, ERRORf)) { 316 rv = SOC_E_FAIL; 317 cmicm_sbusdma_curr_op_details(unit, cmc, ch); 318 } 319 break; 320 } 321 } while(!(soc_timeout_check(&to))); 322 } 323 324 #if defined(BCM_TRIUMPH3_SUPPORT) 325 if (soc_feature(unit, soc_feature_etu_support)) { 326 if ((SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_ETU) || 327 ((param->mem == EXT_L2_ENTRY_1m) || 328 (param->mem == EXT_L2_ENTRY_2m))) { 329 SOC_IF_ERROR_RETURN 330 (soc_reg_field32_modify(unit, ETU_TX_REQ_FIFO_CTLr, 331 REG_PORT_ANY, 332 CP_ACC_THRf, wa_val)); 333 } 334 } 335 #endif 336 337 if (rv != SOC_E_NONE) { 338 if (rv != SOC_E_TIMEOUT) { 339 LOG_ERROR(BSL_LS_SOC_COMMON, 340 (BSL_META_U(unit, 341 "%s.%s failed(ERR)\n"), 342 SOC_MEM_UFNAME(unit, param->mem), 343 SOC_BLOCK_NAME(unit, param->copyno))); 344 cmicm_sbusdma_error_details(unit, 345 soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch))); 346 } else { /* Timeout cleanup */ 347 soc_timeout_t to; 348 349 LOG_ERROR(BSL_LS_SOC_COMMON, 350 (BSL_META_U(unit, 351 "%s.%s %s timeout\n"), 352 SOC_MEM_UFNAME(unit, param->mem), 353 SOC_BLOCK_NAME(unit, param->copyno), 354 soc->tableDmaIntrEnb ? "interrupt" : "polling")); 355 #ifdef BCM_PETRA_SUPPORT 356 if (SOC_IS_ARAD(unit)) { 357 LOG_ERROR(BSL_LS_SOC_COMMON, 358 (BSL_META_U(unit, 359 "This DMA failure may be due to wrong PCI configuration. " 360 "Timeout configured to %dus.\n"), 361 soc->tableDmaTimeout)); 362 } 363 #endif /* BCM_PETRA_SUPPORT */ 364 365 /* Abort Table DMA */ 366 ctrl = soc_pci_read(unit, 367 CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch)); 368 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl, 369 ABORTf, 1); 370 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch), ctrl); 371 372 /* Check the done bit to confirm */ 373 soc_timeout_init(&to, soc->tableDmaTimeout, 0); 374 while (1) { 375 rval = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch)); 376 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 377 rval, DONEf)) { 378 break; 379 } 380 if (soc_timeout_check(&to)) { 381 LOG_ERROR(BSL_LS_SOC_COMMON, 382 (BSL_META_U(unit, 383 "_cmicm_sbusdma_reg_read: Abort Failed\n"))); 384 break; 385 } 386 } 387 } 388 } 389 390 soc_cm_sinval(unit, (void *)param->buffer, WORDS2BYTES(data_beats) * count); 391 #if defined(BCM_TRIUMPH3_SUPPORT) 392 if (soc_feature(unit, soc_feature_esm_correction) && 393 ((SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_ESM) || 394 (SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_ETU))) { 395 SOC_ESM_UNLOCK(unit); 396 } 397 #endif 398 if (_soc_multi_cmc) { 399 SBUS_DMA_UNLOCK(unit, cmc, ch); 400 cmicm_sbusdma_ch_put(unit, cmc, ch); 401 } else { 402 TABLE_DMA_UNLOCK(unit); 403 } 404 405 return rv; 406 } 407 408 /******************************************* 409 * @function _cmicm_sbusdma_reg_array_write 410 * purpose DMA acceleration for soc_mem_write_range() on FB/ER 411 * 412 * @param unit [in] unit 413 * @param drv [in] soc_sbusdma_reg_param_t pointer 414 * @param mem_clear [in] flag to clear the memory 415 * @param clear_buf_ent [in] clear_buf_ent is not used as 416 * SLAM DMA only supports a one entry buffer 417 * 418 * @returns SOC_E_NONE 419 * @returns SOC_E_XXX 420 * 421 * @end 422 */ 423 424 STATIC int 425 _cmicm_sbusdma_reg_array_write(int unit, soc_sbusdma_reg_param_t *param) 426 { 427 soc_control_t *soc = SOC_CONTROL(unit); 428 uint32 start_addr; 429 uint32 count = 0; 430 uint32 data_beats; 431 uint32 spacing; 432 int rv = SOC_E_NONE; 433 uint32 ctrl, rval; 434 uint8 at, rev_slam = 0; 435 int ch; 436 int cmc = SOC_PCI_CMC(unit); 437 schan_msg_t msg; 438 int dst_blk, acc_type, data_byte_len, dma; 439 unsigned array_index; 440 int dma_retries=0; 441 int max_retries=0; 442 443 #ifdef PRINT_DMA_TIME 444 sal_usecs_t start_time; 445 int diff_time; 446 #endif 447 #if defined(BCM_TRIUMPH3_SUPPORT) 448 uint32 wa_rval, wa_val = 0; 449 #endif 450 #if defined(BCM_PETRA_SUPPORT) 451 uint32 *cache; 452 uint8 *vmap; 453 int index = 0; 454 int mem_array_vmap_offset; 455 int mem_array_cache_offset; 456 int blk, copyno_override, cache_copyno = param->copyno; 457 #endif 458 459 LOG_VERBOSE(BSL_LS_SOC_DMA, 460 (BSL_META_U(unit, 461 "unit %d" 462 " mem %s[%u-%u].%s index %d-%d buffer %p\n"), 463 unit, SOC_MEM_UFNAME(unit, param->mem), param->array_id_start, 464 param->array_id_end, SOC_BLOCK_NAME(unit, param->copyno), 465 param->index_begin, param->index_end, param->buffer)); 466 467 data_beats = soc_mem_entry_words(unit, param->mem); 468 469 /* muticmc with grab all the channels and release one to grab */ 470 if (_soc_multi_cmc) { 471 SOC_IF_ERROR_RETURN(cmicm_sbusdma_ch_get(unit, &cmc, &ch)); 472 assert((ch >= 0) && (ch < CMIC_CMCx_SBUSDMA_CHAN_MAX)); 473 } else { 474 ch = soc->tslam_ch; 475 } 476 477 assert((ch >= 0) && (ch < soc->max_sbusdma_channels)); 478 479 if (param->index_begin > param->index_end) { 480 count = param->index_begin - param->index_end + 1; 481 rev_slam = 1; 482 } else { 483 count = param->index_end - param->index_begin + 1; 484 } 485 if (count < 1) { 486 if (_soc_multi_cmc) { 487 cmicm_sbusdma_ch_put(unit, cmc, ch); 488 } 489 return SOC_E_NONE; 490 } 491 492 schan_msg_clear(&msg); 493 acc_type = SOC_MEM_ACC_TYPE(unit, param->mem); 494 dst_blk = SOC_BLOCK2SCH(unit, param->copyno); 495 data_byte_len = data_beats * sizeof(uint32); 496 497 #ifdef FW_BCAST_DOWNLOAD 498 if (SOC_IS_TOMAHAWK2(unit)) { 499 if (param->flags & SOC_MEM_WRITE_BCAST_OP) { 500 int bcast_id = 0; 501 502 rv = SOC_E_FAIL; 503 if ((SOC_PORTCTRL_FUNCTIONS(unit) != NULL) 504 && (SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_sbus_bcast_id_get != NULL)) { 505 rv = SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_sbus_bcast_id_get(unit, dst_blk, &bcast_id); 506 if (SOC_SUCCESS(rv)) { 507 dst_blk = bcast_id; 508 } 509 } 510 511 param->flags &= ~SOC_MEM_WRITE_BCAST_OP; 512 } 513 } 514 #endif 515 516 if (SOC_IS_ARAD(unit)) { 517 dma = 1; 518 } else { 519 dma = 0; 520 } 521 522 soc_schan_header_cmd_set(unit, &msg.header, WRITE_MEMORY_CMD_MSG, 523 dst_blk, 0, acc_type, data_byte_len, dma, 0); 524 525 if (_soc_multi_cmc) { 526 SBUS_DMA_LOCK(unit, cmc, ch); 527 } else { 528 TSLAM_DMA_LOCK(unit); 529 } 530 531 LOG_VERBOSE(BSL_LS_SOC_DMA, 532 (BSL_META_U(unit, 533 "unit=%d %s.acc_type = %0x, idx[%0d-%0d], cmc= %d, ch = %d\n"), 534 unit, SOC_MEM_NAME(unit, param->mem), acc_type, 535 param->index_begin, param->index_end, cmc, ch)); 536 537 #if defined(BCM_TRIUMPH3_SUPPORT) 538 if (soc_feature(unit, soc_feature_esm_correction) && 539 ((SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_ESM) || 540 (SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_ETU))) { 541 SOC_ESM_LOCK(unit); 542 } 543 #endif 544 545 for (array_index = param->array_id_start; 546 array_index <= param->array_id_end; ++array_index) { 547 if (!param->flags || (param->flags & SOC_MEM_WRITE_SET_ONLY)) { 548 start_addr = soc_mem_addr_get(unit, param->mem, array_index, 549 param->copyno, param->index_begin, &at); 550 551 ctrl = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch)); 552 /* Set mode, clear abort, start (clears status and errors) */ 553 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl, 554 MODEf, 0); 555 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl, 556 ABORTf, 0); 557 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl, 558 STARTf, 0); 559 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch), ctrl); 560 /* Set 1st schan ctrl word as opcode */ 561 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_OPCODE(cmc, ch), 562 msg.dwords[0]); 563 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_HOSTADDR(cmc, ch), 564 soc_cm_l2p(unit, param->buffer)); 565 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_ADDRESS(cmc, ch), 566 start_addr); 567 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_COUNT(cmc, ch), count); 568 569 /* Program beats, increment/decrement, single etc */ 570 rval = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_REQUEST(cmc, ch)); 571 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 572 REQ_WORDSf, data_beats); 573 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 574 REP_WORDSf, 0); 575 576 #if defined(BCM_TRIUMPH3_SUPPORT) 577 if (soc_feature(unit, soc_feature_etu_support)) { 578 if (SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_ETU) { 579 int index0, index1, increment; 580 soc_mem_t real_mem; 581 582 soc_tcam_mem_index_to_raw_index(unit, param->mem, 0, 583 &real_mem, &index0); 584 soc_tcam_mem_index_to_raw_index(unit, param->mem, 1, 585 &real_mem, &index1); 586 increment = _shr_popcount(index1 - index0 - 1); 587 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 588 INCR_SHIFTf, increment); 589 SOC_IF_ERROR_RETURN(READ_ETU_TX_REQ_FIFO_CTLr(unit, &wa_rval)); 590 wa_val = soc_reg_field_get(unit, ETU_TX_REQ_FIFO_CTLr, wa_rval, 591 CP_ACC_THRf); 592 soc_reg_field_set(unit, ETU_TX_REQ_FIFO_CTLr, &wa_rval, 593 CP_ACC_THRf, 0); 594 SOC_IF_ERROR_RETURN(WRITE_ETU_TX_REQ_FIFO_CTLr(unit, wa_rval)); 595 } else { 596 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 597 INCR_SHIFTf, 0); 598 if ((param->mem == EXT_L2_ENTRY_1m) || 599 (param->mem == EXT_L2_ENTRY_2m)) { 600 SOC_IF_ERROR_RETURN(READ_ETU_TX_REQ_FIFO_CTLr(unit, &wa_rval)); 601 wa_val = soc_reg_field_get(unit, ETU_TX_REQ_FIFO_CTLr, wa_rval, 602 CP_ACC_THRf); 603 soc_reg_field_set(unit, ETU_TX_REQ_FIFO_CTLr, &wa_rval, 604 CP_ACC_THRf, 0); 605 SOC_IF_ERROR_RETURN(WRITE_ETU_TX_REQ_FIFO_CTLr(unit, wa_rval)); 606 } 607 } 608 } else 609 #endif /* BCM_TRIUMPH3_SUPPORT */ 610 #if defined(BCM_SAND_SUPPORT) 611 if (SOC_IS_SAND(unit)) { 612 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 613 INCR_SHIFTf, 0); 614 } else 615 #endif 616 { 617 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 618 INCR_SHIFTf, 0); 619 } 620 if (param->mem_clear) { 621 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 622 REQ_SINGLEf, 1); 623 } else { 624 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 625 REQ_SINGLEf, 0); 626 } 627 if (rev_slam) { 628 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 629 DECRf, 1); 630 } else { 631 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 632 DECRf, 0); 633 } 634 if (soc_feature(unit, soc_feature_multi_sbus_cmds)) { 635 636 if (soc->sbusCmdSpacing < 0) { 637 spacing = data_beats > 7 ? data_beats + 1 : 8; 638 } else { 639 spacing = soc->sbusCmdSpacing; 640 } 641 if (!((SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_IPIPE) || 642 (SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_EPIPE))) { 643 spacing = 0; 644 } 645 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 646 PEND_CLOCKSf, spacing); 647 } 648 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_REQUEST(cmc, ch), rval); 649 650 if (param->mem_clear) { 651 soc_cm_sflush(unit, param->buffer, WORDS2BYTES(data_beats)); 652 } else { 653 soc_cm_sflush(unit, param->buffer, WORDS2BYTES(data_beats) * count); 654 } 655 656 LOG_VERBOSE(BSL_LS_SOC_DMA, 657 (BSL_META_U(unit, 658 "_soc_mem_sbusdma_write: %d entries %d beats " 659 "addr 0x%x (index %d-%d) Interrupt-Mode(%d)\n"), 660 count, data_beats, start_addr, 661 param->index_begin, param->index_end, 662 soc->tslamDmaIntrEnb)); 663 } 664 665 if (!param->flags || (param->flags & SOC_MEM_WRITE_COMMIT_ONLY)) { 666 ctrl = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch)); 667 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl, STARTf, 1); 668 /* On BCMSIM, this interrupt just be reported one time. 669 If we enable this interrupt after starting table DMA, the interrupt may be lost. 670 But on chip, the interrupt will be reported continually until we clear STARTf of 671 CMIC_CMC0_SBUSDMA_CH0_CONTROLr */ 672 if (soc->tslamDmaIntrEnb) { 673 soc_cmicm_cmcx_intr0_enable(unit, cmc, _soc_irq_sbusdma_ch[ch]); 674 } 675 676 /* Start DMA */ 677 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch), ctrl); 678 } 679 680 if (!param->flags || (param->flags & SOC_MEM_WRITE_STATUS_ONLY)) { 681 #ifdef PRINT_DMA_TIME 682 start_time = sal_time_usecs(); 683 #endif 684 rv = SOC_E_TIMEOUT; 685 if (soc->tslamDmaIntrEnb) { 686 if (SBUSDMA_DMA_INTR_WAIT(unit, cmc, ch, soc->tslamDmaTimeout) < 0) { 687 rv = SOC_E_TIMEOUT; 688 LOG_VERBOSE(BSL_LS_SOC_COMMON, 689 (BSL_META_U(unit, 690 "%s.%s interrupt timeout\n"), 691 SOC_MEM_UFNAME(unit, param->mem), 692 SOC_BLOCK_NAME(unit, param->copyno))); 693 } 694 #ifdef PRINT_DMA_TIME 695 diff_time = SAL_USECS_SUB(sal_time_usecs(), start_time); 696 LOG_VERBOSE(BSL_LS_SOC_DMA, 697 (BSL_META_U(unit, 698 "(%s)HW dma write time[count=%u, beats=%u]: %d usecs, [%d nsecs per op]\n"), 699 SOC_MEM_UFNAME(unit, param->mem),count,data_beats, 700 diff_time, diff_time*1000/count)); 701 #endif 702 soc_cmicm_cmcx_intr0_disable(unit, cmc, _soc_irq_sbusdma_ch[ch]); 703 704 rval = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch)); 705 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 706 rval, DONEf)) { 707 rv = SOC_E_NONE; 708 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 709 rval, ERRORf)) { 710 rv = SOC_E_FAIL; 711 cmicm_sbusdma_curr_op_details(unit, cmc, ch); 712 } 713 } 714 } else { 715 soc_timeout_t to; 716 soc_timeout_init(&to, soc->tslamDmaTimeout, 0); 717 /* Accessing the memory location prior to read loop improves performance */ 718 rval=soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch)); 719 do { 720 rval = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch)); 721 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 722 rval, DONEf)) { 723 #ifdef PRINT_DMA_TIME 724 diff_time = SAL_USECS_SUB(sal_time_usecs(), start_time); 725 LOG_VERBOSE(BSL_LS_SOC_DMA, 726 (BSL_META_U(unit, 727 "(%s)HW dma write poll time[count=%u, beats=%u]: %d usecs, [%d nsecs per op]\n"), 728 SOC_MEM_UFNAME(unit, param->mem),count, data_beats, 729 diff_time, diff_time*1000/count)); 730 #endif 731 rv = SOC_E_NONE; 732 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 733 rval, ERRORf)) { 734 rv = SOC_E_FAIL; 735 cmicm_sbusdma_curr_op_details(unit, cmc, ch); 736 } 737 break; 738 } 739 } while(dma_retries++ < max_retries || !(soc_timeout_check(&to))); 740 } 741 742 #if defined(BCM_TRIUMPH3_SUPPORT) 743 if (soc_feature(unit, soc_feature_etu_support)) { 744 if ((SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_ETU) || 745 ((param->mem == EXT_L2_ENTRY_1m) || 746 (param->mem == EXT_L2_ENTRY_2m))) { 747 SOC_IF_ERROR_RETURN 748 (soc_reg_field32_modify(unit, ETU_TX_REQ_FIFO_CTLr, 749 REG_PORT_ANY, CP_ACC_THRf, wa_val)); 750 } 751 } 752 #endif 753 754 if (rv < 0) { 755 if (rv != SOC_E_TIMEOUT) { 756 LOG_ERROR(BSL_LS_SOC_COMMON, 757 (BSL_META_U(unit, 758 "%s[%u].%s failed(ERR)\n"), 759 SOC_MEM_UFNAME(unit, param->mem), array_index, 760 SOC_BLOCK_NAME(unit, param->copyno))); 761 cmicm_sbusdma_error_details(unit, 762 soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch))); 763 } else { /* Timeout cleanup */ 764 soc_timeout_t to; 765 766 LOG_ERROR(BSL_LS_SOC_COMMON, 767 (BSL_META_U(unit, 768 "%s[%u].%s %s timeout\n"), 769 SOC_MEM_UFNAME(unit, param->mem), array_index, 770 SOC_BLOCK_NAME(unit, param->copyno), 771 soc->tslamDmaIntrEnb ? "interrupt" : "polling")); 772 773 /* Abort Table DMA */ 774 ctrl = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch)); 775 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl, ABORTf, 1); 776 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch), ctrl); 777 778 /* Check the done bit to confirm */ 779 soc_timeout_init(&to, soc->tslamDmaTimeout, 0); 780 while (1) { 781 rval = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch)); 782 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 783 rval, DONEf)) { 784 break; 785 } 786 if (soc_timeout_check(&to)) { 787 LOG_ERROR(BSL_LS_SOC_COMMON, 788 (BSL_META_U(unit, 789 "_soc_mem_sbusdma_write: Abort Failed\n"))); 790 break; 791 } 792 } 793 } 794 } 795 } 796 #if defined(BCM_PETRA_SUPPORT) 797 /* update cache, for broadcast block loop each block */ 798 copyno_override = soc_mem_broadcast_block_get(unit,param->mem); 799 if (cache_copyno == copyno_override) { 800 cache_copyno = COPYNO_ALL; 801 } 802 SOC_MEM_BLOCK_ITER(unit, param->mem, blk) { 803 if ((cache_copyno != COPYNO_ALL) && (cache_copyno != blk)) { 804 continue; 805 } 806 /* It will not go into this API if param->copyno = -1. */ 807 /* coverity[negative_returns] */ 808 cache = SOC_MEM_STATE(unit, param->mem).cache[blk]; 809 vmap = SOC_MEM_STATE(unit, param->mem).vmap[blk]; 810 mem_array_vmap_offset = array_index * soc_mem_index_count(unit, param->mem); 811 mem_array_cache_offset = mem_array_vmap_offset * data_beats; 812 if (cache != NULL && !SOC_MEM_TEST_SKIP_CACHE(unit)) { 813 for (index = param->index_begin; index <= param->index_end; index ++) { 814 if ((param->mem_clear) && 815 !(CACHE_VMAP_TST(vmap, index + mem_array_vmap_offset))) { 816 continue; 817 } 818 sal_memcpy(cache + mem_array_cache_offset + index * data_beats, 819 param->buffer, data_beats * 4); 820 /* update vmap */ 821 CACHE_VMAP_SET(vmap, mem_array_vmap_offset + index); 822 } 823 } 824 } 825 #endif 826 } /* end of loop over array indices */ 827 828 #if defined(BCM_TRIUMPH3_SUPPORT) 829 if (soc_feature(unit, soc_feature_esm_correction) && 830 ((SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_ESM) || 831 (SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_ETU))) { 832 SOC_ESM_UNLOCK(unit); 833 } 834 #endif 835 if (_soc_multi_cmc) { 836 SBUS_DMA_UNLOCK(unit, cmc, ch); 837 cmicm_sbusdma_ch_put(unit, cmc, ch); 838 } else { 839 TSLAM_DMA_UNLOCK(unit); 840 } 841 842 return rv; 843 } 844 845 /******************************************* 846 * @function _cmicm_sbusdma_reg_clear_specific 847 * purpose clear a specific memory/table region using 848 * DMA write (slam) acceleration. 849 * 850 * @param unit [in] unit 851 * @param param [in] soc_sbusdma_reg_param_t pointer 852 * 853 * @returns SOC_E_NONE 854 * @returns SOC_E_XXX 855 * 856 * @end 857 */ 858 STATIC int 859 _cmicm_sbusdma_reg_clear_specific(int unit, soc_sbusdma_reg_param_t *param) 860 { 861 int rv = 0, chunk_size, chunk_entries, mem_size, entry_words; 862 int index, blk, tmp, copyno; 863 uint32 *buf; 864 865 if (SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit)) { 866 return SOC_E_NONE; 867 } 868 chunk_size = SOC_MEM_CLEAR_CHUNK_SIZE_GET(unit); 869 /* get legal values for indices, if too 870 * small/big use the memory's boundaries 871 */ 872 tmp = soc_mem_index_min(unit, param->mem); 873 if (param->index_begin < soc_mem_index_min(unit, param->mem)) { 874 param->index_begin = tmp; 875 } 876 if (param->index_end < param->index_begin) { 877 param->index_end = param->index_begin; 878 } else { 879 tmp = soc_mem_index_max(unit, param->mem); 880 if (param->index_end > tmp) { 881 param->index_end = tmp; 882 } 883 } 884 885 entry_words = soc_mem_entry_words(unit, param->mem); 886 mem_size = (param->index_end - param->index_begin + 1) * entry_words * 4; 887 if (mem_size < chunk_size) { 888 chunk_size = mem_size; 889 } 890 #ifdef BCM_PETRA_SUPPORT 891 if (SOC_IS_ARAD(unit) && (entry_words * 4 > chunk_size)) { 892 /* The default is to use a one table entry buffer, 893 * if not given a bigger chunk size 894 * make sure the buffer size holds at least one table entry 895 */ 896 chunk_size = entry_words * 4; 897 } 898 #endif 899 900 buf = soc_cm_salloc(unit, chunk_size, "mem_clear_buf"); 901 if (buf == NULL) { 902 return SOC_E_MEMORY; 903 } 904 chunk_entries = chunk_size / (entry_words * 4); 905 for (index = 0; index < chunk_entries; index++) { 906 sal_memcpy(buf + (index * entry_words), 907 param->buffer, entry_words * 4); 908 } 909 910 /* get legal values for memory array indices */ 911 if (SOC_MEM_IS_ARRAY(unit, param->mem)) { 912 soc_mem_array_info_t *maip = SOC_MEM_ARRAY_INFOP(unit, param->mem); 913 if (maip) { 914 if (param->array_id_end >= (maip->numels + maip->first_array_index)) { 915 param->array_id_end = (maip->numels - 1) + maip->first_array_index; 916 } else if (param->array_id_start < maip->first_array_index) { 917 param->array_id_start = maip->first_array_index; 918 } 919 } 920 } else { 921 param->array_id_start = param->array_id_end = 0; 922 } 923 copyno = param->copyno; 924 MEM_LOCK(unit, param->mem); 925 SOC_MEM_BLOCK_ITER(unit, param->mem, blk) { 926 if (copyno != COPYNO_ALL && copyno != blk) { 927 continue; 928 } 929 param->buffer = buf; 930 param->flags = 0; 931 param->mem_clear = TRUE; 932 param->copyno = blk; 933 rv = _cmicm_sbusdma_reg_array_write(unit, param); 934 if (rv < 0) { 935 LOG_ERROR(BSL_LS_SOC_COMMON, 936 (BSL_META_U(unit, 937 "soc_mem_sbusdma_clear: %s.%s[%d-%d] failed: %s\n"), 938 SOC_MEM_UFNAME(unit, param->mem), 939 SOC_BLOCK_NAME(unit, blk), 940 param->index_begin, param->index_end, 941 soc_errmsg(rv))); 942 } 943 } 944 MEM_UNLOCK(unit, param->mem); 945 /* restoring the copy number since it is modified */ 946 param->copyno = copyno; 947 soc_cm_sfree(unit, buf); 948 return rv; 949 } 950 951 /******************************************* 952 * @function _cmicm_sbusdma_cmc_max_num_ch_get 953 * @Returns number of SBUSDMA channels in cmc 954 * 955 * @end 956 */ 957 STATIC uint32 958 _cmicm_sbusdma_cmc_max_num_ch_get(int unit) 959 { 960 return CMIC_CMCx_SBUSDMA_CHAN_MAX; 961 } 962 963 964 /******************************************* 965 * @function cmicm_sbusdma_reg_init 966 * purpose API to Initialize cmicm Register DMA 967 * 968 * @param unit [in] unit 969 * @param drv [out] soc_sbusdma_desc_drv_t pointer 970 * 971 * @returns SOC_E_NONE 972 * @returns SOC_E_XXX 973 * 974 * @end 975 */ 976 int cmicm_sbusdma_reg_init(int unit, soc_sbusdma_reg_drv_t *drv) 977 { 978 /* Cache multi CMC flag */ 979 if (SOC_CHECK_MULTI_CMC(unit)) { 980 _soc_multi_cmc = 1; 981 } 982 drv->soc_mem_sbusdma_read = _cmicm_sbusdma_reg_array_read; 983 drv->soc_mem_sbusdma_write = _cmicm_sbusdma_reg_array_write; 984 drv->soc_mem_sbusdma_clear = _cmicm_sbusdma_reg_clear_specific; 985 drv->soc_sbusdma_cmc_max_num_ch_get = _cmicm_sbusdma_cmc_max_num_ch_get; 986 987 return SOC_E_NONE; 988 } 989 990 #endif /* BCM_SBUSDMA_SUPPORT */ 991 #endif /* defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) */ 992