cmicx_sbusdma_reg.c (28237B)
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 SBUS-DMA Register 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_CMICX_SUPPORT) && defined(BCM_SBUSDMA_SUPPORT) 18 #include <soc/cmicx.h> 19 #include <soc/intr_cmicx.h> 20 21 #ifdef BCM_SAND_SUPPORT 22 #include <soc/sand/sand_aux_access.h> 23 #endif 24 25 #define SBUSDMA_REG_WAIT(wparam) \ 26 (&((cmic_sbusdma_wparam_t *)wparam)->wait) 27 28 typedef struct cmicx_sbusdma_prog_s { 29 uint8 rev_slam; 30 uint8 mem_clear; 31 int opcode; 32 int cmc; 33 int ch; 34 uint32 data_beats; 35 uint32 start_addr; 36 uint32 count; 37 uint32 ser_flags; 38 }cmicx_sbusdma_prog_t; 39 40 41 /******************************************* 42 * @function _cmicx_sbusdma_reg_program 43 * purpose Programing the registers and start DMA 44 * 45 * @param unit [in] unit 46 * @param param [in] soc_sbusdma_reg_param_t pointer 47 * @param prog [in] cmicx_sbusdma_prog_t pointer 48 * 49 * @returns SOC_E_NONE 50 * @returns SOC_E_XXX 51 * 52 * @end 53 */ 54 STATIC void 55 _cmicx_sbusdma_reg_program(int unit, schan_msg_t *msg, 56 soc_sbusdma_reg_param_t *param, 57 cmicx_sbusdma_prog_t *prog) 58 { 59 uint32 ctrl, rval; 60 uint32 spacing; 61 int big_pio, big_packet, big_other; 62 soc_control_t *soc = SOC_CONTROL(unit); 63 64 LOG_VERBOSE(BSL_LS_SOC_DMA, 65 (BSL_META_U(unit, 66 "CMIC_CMCx_SBUSDMA_CHy_REQUEST=0x%x, " 67 "CMIC_CMCx_SBUSDMA_CHy_CONTROL= 0x%x\n"), 68 CMIC_CMCx_SBUSDMA_CHy_REQUEST(prog->cmc, prog->ch), 69 CMIC_CMCx_SBUSDMA_CHy_CONTROL(prog->cmc, prog->ch))); 70 soc_endian_get(unit, &big_pio, &big_packet, &big_other); 71 ctrl = soc_pci_read(unit, 72 CMIC_CMCx_SBUSDMA_CHy_CONTROL(prog->cmc, prog->ch)); 73 /* Set mode */ 74 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl, 75 MODEf, 0); 76 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(prog->cmc, 77 prog->ch), ctrl); 78 /* Set 1st schan ctrl word as opcode */ 79 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_OPCODE(prog->cmc, prog->ch), 80 msg->dwords[0]); 81 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_HOSTADDR_LO(prog->cmc, prog->ch), 82 PTR_TO_INT(soc_cm_l2p(unit, param->buffer))); 83 /* Add HI ADDRESS */ 84 if (soc_cm_get_bus_type(unit) & SOC_PCI_DEV_TYPE) { 85 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_HOSTADDR_HI(prog->cmc, prog->ch), 86 (PTR_HI_TO_INT(soc_cm_l2p(unit, param->buffer)) | 87 CMIC_PCIE_SO_OFFSET)); 88 } else { 89 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_HOSTADDR_HI(prog->cmc, prog->ch), 90 PTR_HI_TO_INT(soc_cm_l2p(unit, param->buffer))); 91 } 92 /* Start Address */ 93 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_ADDRESS(prog->cmc, prog->ch), 94 prog->start_addr); 95 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_COUNT(prog->cmc, prog->ch), 96 prog->count); 97 98 /* Program beats, increment/decrement, single */ 99 100 rval = 0; 101 if (big_other) { 102 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 103 HOSTMEMWR_ENDIANESSf, 1); 104 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 105 HOSTMEMRD_ENDIANESSf, 1); 106 } 107 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 108 INCR_SHIFTf, 0); 109 110 if(prog->opcode == READ_MEMORY_CMD_MSG) { 111 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 112 REP_WORDSf, prog->data_beats); 113 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 114 REQ_WORDSf, 0); 115 } 116 117 if(prog->opcode == WRITE_MEMORY_CMD_MSG) { 118 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 119 REQ_WORDSf, prog->data_beats); 120 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 121 REP_WORDSf, 0); 122 if (prog->mem_clear) { 123 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 124 REQ_SINGLEf, 1); 125 } else { 126 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 127 REQ_SINGLEf, 0); 128 } 129 if (prog->rev_slam) { 130 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 131 DECRf, 1); 132 } else { 133 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 134 DECRf, 0); 135 } 136 #ifdef BCM_HELIX5_SUPPORT 137 if (SOC_IS_HELIX5(unit)) { 138 if(param->mem == PMQPORT_WC_UCMEM_DATAm) { 139 /* H/W will increment the PRAM address automatically per write transaction in PM4X10Q Q mode. 140 Disable CMIC SBUS increase address. 141 */ 142 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 143 INCR_NOADDf, 1); 144 } 145 } 146 #endif 147 } 148 149 if (soc_feature(unit, soc_feature_multi_sbus_cmds)) { 150 /* 151 * rules for spacing: 152 * 1. word_count + 1 153 * 2. special requirements (i.e. higher value) 154 * before collect all special requirement, set to 8 or above 155 */ 156 if (soc->sbusCmdSpacing < 0) { 157 spacing = prog->data_beats > 7 ? prog->data_beats + 1 : 8; 158 } else { 159 spacing = soc->sbusCmdSpacing; 160 } 161 if (!((SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_IPIPE) || 162 (SOC_BLOCK_TYPE(unit, param->copyno) == SOC_BLK_EPIPE))) { 163 spacing = 0; 164 } 165 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_REQUESTr, &rval, 166 PEND_CLOCKSf, spacing); 167 } 168 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_REQUEST(prog->cmc, 169 prog->ch), rval); 170 return; 171 } 172 173 /******************************************* 174 * @function _cmicx_sbusdma_reg_complete 175 * purpose Wait and complete the DMA 176 * 177 * @param unit [in] unit 178 * @param param [in] soc_sbusdma_reg_param_t pointer 179 * @param wparam [in] void pointer 180 * 181 * @returns SOC_E_NONE 182 * @returns SOC_E_XXX 183 * 184 * @end 185 */ 186 STATIC int 187 _cmicx_sbusdma_reg_complete(int unit, void *data, 188 void *wparam) 189 { 190 int rv; 191 uint32 do_not_perform_start_operation = 0; 192 uint32 ctrl, rval; 193 cmic_sbusdma_wait_t *wait; 194 soc_sbusdma_reg_param_t *param; 195 #ifdef PRINT_DMA_TIME 196 int diff_time; 197 uint32 count; 198 uint32 data_beats; 199 #endif 200 201 if ((data == NULL) || (wparam == NULL)) { 202 return SOC_E_PARAM; 203 } 204 205 param = (soc_sbusdma_reg_param_t *)data; 206 wait = SBUSDMA_REG_WAIT(wparam); 207 #ifdef PRINT_DMA_TIME 208 count = param->index_end - param->index_begin + 1; 209 data_beats = soc_mem_entry_words(unit, param->mem); 210 wait->start_time = sal_time_usecs(); 211 #endif 212 if((param->flags & SOC_MEM_WRITE_STATUS_ONLY) != 0) 213 { 214 do_not_perform_start_operation = 1; 215 } 216 if (wait->intr_enb) { 217 rv = cmicx_sbusdma_intr_wait(unit, wait->cmc, wait->ch, 218 wait->timeout, do_not_perform_start_operation); 219 if (rv != SOC_E_TIMEOUT) { 220 SOC_CONTROL(unit)->stat.intr_tslam++; 221 } 222 } else { 223 rv = cmicx_sbusdma_poll_wait(unit, wait->cmc, wait->ch, 224 wait->timeout, do_not_perform_start_operation); 225 } 226 227 #ifdef PRINT_DMA_TIME 228 diff_time = SAL_USECS_SUB(sal_time_usecs(), wait->start_time); 229 LOG_VERBOSE(BSL_LS_SOC_DMA, 230 (BSL_META_U(unit, 231 "(%s)HW dma time[count=%u beats=%u]: %d usecs, [%d nsecs per op]\n"), 232 SOC_MEM_UFNAME(unit, param->mem),count,data_beats, 233 diff_time, diff_time*1000/count)); 234 #endif 235 236 if (rv != SOC_E_NONE) { 237 if (rv != SOC_E_TIMEOUT) { 238 LOG_ERROR(BSL_LS_SOC_DMA, 239 (BSL_META_U(unit, 240 "%s.%s failed(ERR %d)\n"), 241 SOC_MEM_UFNAME(unit, param->mem), 242 SOC_BLOCK_NAME(unit, param->copyno), rv)); 243 cmicx_sbusdma_error_details(unit, 244 soc_pci_read(unit, 245 CMIC_CMCx_SBUSDMA_CHy_STATUS(wait->cmc, wait->ch))); 246 } else { /* Timeout cleanup */ 247 soc_timeout_t to; 248 249 LOG_ERROR(BSL_LS_SOC_DMA, 250 (BSL_META_U(unit, 251 "%s.%s %s timeout\n"), 252 SOC_MEM_UFNAME(unit, param->mem), 253 SOC_BLOCK_NAME(unit, param->copyno), 254 wait->intr_enb ? "interrupt" : "polling")); 255 256 /* Abort DMA */ 257 ctrl = soc_pci_read(unit, 258 CMIC_CMCx_SBUSDMA_CHy_CONTROL(wait->cmc, wait->ch)); 259 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl, 260 ABORTf, 1); 261 LOG_ERROR(BSL_LS_SOC_DMA, 262 (BSL_META_U(unit, 263 "CMIC_CMC0_SBUSDMA_CH0_CONTROLr = 0x%x\n"), ctrl)); 264 soc_pci_write(unit, 265 CMIC_CMCx_SBUSDMA_CHy_CONTROL(wait->cmc, wait->ch), ctrl); 266 267 /* Check the done bit to confirm */ 268 soc_timeout_init(&to, wait->timeout, 0); 269 while (1) { 270 rval = soc_pci_read(unit, 271 CMIC_CMCx_SBUSDMA_CHy_STATUS(wait->cmc, wait->ch)); 272 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 273 rval, DONEf)) { 274 break; 275 } 276 if (soc_timeout_check(&to)) { 277 LOG_ERROR(BSL_LS_SOC_DMA, 278 (BSL_META_U(unit, 279 "_cmicx_sbusdma_reg_read: Abort Failed\n"))); 280 break; 281 } 282 } 283 } 284 } else { 285 if (wait->opcode == READ_MEMORY_CMD_MSG) { 286 soc_cm_sinval(unit, (void *)param->buffer, 287 WORDS2BYTES(param->data_beats) * wait->count); 288 } 289 } 290 /* Stop and free the channel if not reserved */ 291 cmicx_sbusdma_stop(unit, wait->cmc, wait->ch); 292 293 if (param->vchan == -1) { 294 cmicx_sbusdma_ch_put(unit, wait->cmc, wait->ch); 295 } 296 297 return rv; 298 } 299 300 /******************************************* 301 * @function _cmicx_sbusdma_reg_prog_init 302 * purpose Helper function to initialize data for DMA program 303 * 304 * @param unit [in] unit 305 * @param param [in] soc_sbusdma_reg_param_t pointer 306 * @param msg[out] schan_msg_t pointer 307 * @param prog[out] cmicx_sbusdma_prog_t pointer 308 * @param opcode [in] opcode. 309 * 310 * @returns SOC_E_NONE 311 * @returns SOC_E_XXX 312 * 313 * @end 314 */ 315 STATIC int 316 _cmicx_sbusdma_reg_prog_init(int unit, soc_sbusdma_reg_param_t *param, 317 schan_msg_t *msg, 318 cmicx_sbusdma_prog_t *prog, int opcode) 319 { 320 int dst_blk, acc_type, dma; 321 int data_byte_len = 0; 322 323 LOG_VERBOSE(BSL_LS_SOC_DMA, 324 (BSL_META_U(unit, 325 "unit %d" 326 " mem %s[%u-%u].%s index %d-%d buffer %p\n"), 327 unit, SOC_MEM_UFNAME(unit, param->mem), 328 param->array_id_start, param->array_id_end, 329 SOC_BLOCK_NAME(unit, param->copyno), 330 param->index_begin, param->index_end, param->buffer)); 331 332 prog->data_beats = param->data_beats; 333 334 prog->opcode = opcode; 335 336 if (param->vchan == -1) { 337 SOC_IF_ERROR_RETURN(cmicx_sbusdma_ch_get(unit, &prog->cmc, &prog->ch)); 338 } else { 339 SOC_IF_ERROR_RETURN(cmicx_sbusdma_vchan_to_cmc_ch(unit, 340 param->vchan, &prog->cmc, &prog->ch)); 341 } 342 343 LOG_VERBOSE(BSL_LS_SOC_DMA, 344 (BSL_META_U(unit, 345 "unit %d" 346 "cmc = %d, channel =%d\n"), 347 unit, prog->cmc, prog->ch)); 348 349 assert((prog->ch >= 0) && (prog->ch < CMIC_CMCx_SBUSDMA_CHAN_MAX)); 350 351 if (opcode == WRITE_MEMORY_CMD_MSG) { 352 if (param->index_begin > param->index_end) { 353 prog->count = param->index_begin - param->index_end + 1; 354 prog->rev_slam = 1; 355 } else { 356 prog->count = param->index_end - param->index_begin + 1; 357 } 358 } else { 359 prog->count = param->index_end - param->index_begin + 1; 360 } 361 362 if (prog->count < 1) { 363 return SOC_E_NONE; 364 } 365 366 schan_msg_clear(msg); 367 acc_type = SOC_MEM_ACC_TYPE(unit, param->mem); 368 #if defined(BCM_XGS3_SWITCH_SUPPORT) 369 if (0 != (param->flags & _SOC_SER_FLAG_MULTI_PIPE)) { 370 if ((param->flags & _SOC_SER_FLAG_ACC_TYPE_MASK) || 371 (soc_feature(unit, soc_feature_unique_acc_type_access))) { 372 373 /* Override ACC_TYPE in opcode */ 374 acc_type = param->flags & _SOC_SER_FLAG_ACC_TYPE_MASK; 375 } 376 } 377 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 378 dst_blk = SOC_BLOCK2SCH(unit, param->copyno); 379 if (opcode == WRITE_MEMORY_CMD_MSG) { 380 data_byte_len = prog->data_beats * sizeof(uint32); 381 } else { 382 data_byte_len = 4; 383 } 384 385 LOG_VERBOSE(BSL_LS_SOC_DMA, 386 (BSL_META_U(unit, 387 "unit=%d %s.acc_type = %0x, idx[%0d-%0d]\n"), 388 unit, SOC_MEM_NAME(unit, param->mem), acc_type, 389 param->index_begin, param->index_end)); 390 /* DMA transaction indicator on SBUS */ 391 dma = 1; 392 393 soc_schan_header_cmd_set(unit, &msg->header, opcode, 394 dst_blk, 0, acc_type, data_byte_len, dma, 0); 395 396 return SOC_E_NONE; 397 } 398 399 /******************************************* 400 * @function _cmicx_sbusdma_reg_array_read_prog 401 * purpose : Program DMA for read 402 * 403 * @param unit [in] unit 404 * @param param [in] soc_sbusdma_reg_param_t pointer 405 * @param prog [in] pointer to void 406 * 407 * @returns SOC_E_NONE 408 * @returns SOC_E_XXX 409 * 410 * @end 411 */ 412 STATIC int 413 _cmicx_sbusdma_reg_array_read_prog(int unit, 414 void *data, void *wparam) 415 { 416 soc_control_t *soc = SOC_CONTROL(unit); 417 schan_msg_t msg; 418 cmicx_sbusdma_prog_t prog; 419 cmic_sbusdma_wait_t *wait; 420 uint8 at; 421 soc_sbusdma_reg_param_t *param; 422 423 if ((data == NULL) || (wparam == NULL)) { 424 return SOC_E_PARAM; 425 } 426 param = (soc_sbusdma_reg_param_t *)data; 427 428 wait = SBUSDMA_REG_WAIT(wparam); 429 430 if (wait == NULL) { 431 return SOC_E_PARAM; 432 } 433 434 if (param->copyno < 0) { 435 return SOC_E_PARAM; 436 } 437 438 LOG_VERBOSE(BSL_LS_SOC_DMA, 439 (BSL_META_U(unit, 440 "_cmicx_sbusdma_reg_read: unit %d" 441 " mem %s.%s[%u] index %d-%d" 442 "SER flags 0x%08x buffer %p, copyno = %d\n"), 443 unit, SOC_MEM_UFNAME(unit, param->mem), 444 SOC_BLOCK_NAME(unit, param->copyno), 445 param->array_id_start, param->index_begin, 446 param->index_end, param->flags, 447 param->buffer, param->copyno)); 448 449 sal_memset(&prog, 0, sizeof(cmicx_sbusdma_prog_t)); 450 451 param->data_beats = soc_mem_entry_words(unit, param->mem); 452 453 SOC_IF_ERROR_RETURN(_cmicx_sbusdma_reg_prog_init(unit, param, &msg, 454 &prog, READ_MEMORY_CMD_MSG)); 455 456 prog.ser_flags = param->flags; 457 prog.start_addr = soc_mem_addr_get(unit, param->mem, param->array_id_start, 458 param->copyno, param->index_begin, &at); 459 460 _cmicx_sbusdma_reg_program(unit, &msg, param, &prog); 461 462 LOG_VERBOSE(BSL_LS_SOC_DMA, 463 (BSL_META_U(unit, 464 "_cmicx_sbusdma_reg_read: %d entries %d beats " 465 "addr 0x%x (index %d-%d) Interrupt-Mode(%d)" 466 "Rev Slam %d\n"), 467 prog.count, prog.data_beats, prog.start_addr, 468 param->index_begin, param->index_end, 469 soc->tableDmaIntrEnb, prog.rev_slam)); 470 471 wait->count = prog.count; 472 wait->ch = prog.ch; 473 wait->cmc = prog.cmc; 474 wait->intr = INTR_SBUSDMA(prog.cmc, prog.ch); 475 wait->opcode = READ_MEMORY_CMD_MSG; 476 477 return SOC_E_NONE; 478 } 479 480 481 /******************************************* 482 * @function _cmicx_sbusdma_reg_array_read 483 * purpose DMA acceleration for soc_mem_read_range() on FB/ER 484 * 485 * @param unit [in] unit 486 * @param param [in] soc_sbusdma_reg_param_t pointer 487 * 488 * @returns SOC_E_NONE 489 * @returns SOC_E_XXX 490 * 491 * @end 492 */ 493 STATIC int 494 _cmicx_sbusdma_reg_array_read(int unit, soc_sbusdma_reg_param_t *param) 495 { 496 soc_control_t *soc = SOC_CONTROL(unit); 497 int rv = SOC_E_NONE; 498 cmic_sbusdma_wparam_t wparam; 499 500 wparam.wait.intr_enb = soc->tableDmaIntrEnb; 501 wparam.wait.timeout = soc->tableDmaTimeout; 502 503 rv = _cmicx_sbusdma_reg_array_read_prog(unit, param, &wparam); 504 SOC_IF_ERROR_RETURN(rv); 505 506 rv = _cmicx_sbusdma_reg_complete(unit, param, &wparam); 507 508 return rv; 509 } 510 511 /******************************************* 512 * @function _cmicx_sbusdma_reg_array_write_prog 513 * purpose DMA acceleration for soc_mem_write_range() on FB/ER 514 * 515 * @param unit [in] unit 516 * @param param [in] soc_sbusdma_reg_param_t pointer 517 * @param prog [in] pointer to void 518 * 519 * @returns SOC_E_NONE 520 * @returns SOC_E_XXX 521 * 522 * @end 523 */ 524 STATIC int 525 _cmicx_sbusdma_reg_array_write_prog(int unit, 526 void *data, void *wparam) 527 { 528 soc_control_t *soc = SOC_CONTROL(unit); 529 int rv = SOC_E_NONE; 530 schan_msg_t msg; 531 unsigned array_index; 532 cmicx_sbusdma_prog_t prog; 533 cmic_sbusdma_wait_t *wait; 534 uint8 at; 535 soc_sbusdma_reg_param_t *param; 536 537 if ((data == NULL) || (wparam == NULL)) { 538 return SOC_E_PARAM; 539 } 540 param = (soc_sbusdma_reg_param_t *)data; 541 542 if ((param->flags & (SOC_MEM_WRITE_COMMIT_ONLY | SOC_MEM_WRITE_STATUS_ONLY | SOC_MEM_WRITE_SET_ONLY)) != 0 && param->array_id_start < param->array_id_end) { 543 LOG_ERROR(BSL_LS_SOC_DMA, (BSL_META_U(unit, 544 "cannot perform partial write operations for multiple memory array indices\n"))); 545 return SOC_E_PARAM; 546 } 547 548 if ((param->flags & SOC_MEM_WRITE_COMMIT_ONLY) != 0 && param->vchan != -1) { 549 SOC_IF_ERROR_RETURN(cmicx_sbusdma_vchan_to_cmc_ch(unit, 550 param->vchan, &prog.cmc, &prog.ch)); 551 _cmicx_sbusdma_start(unit, prog.cmc, prog.ch); 552 return 0; 553 } 554 wait = SBUSDMA_REG_WAIT(wparam); 555 556 if (wait == NULL) { 557 return SOC_E_PARAM; 558 } 559 560 if (param->copyno < 0) { 561 return SOC_E_PARAM; 562 } 563 564 LOG_VERBOSE(BSL_LS_SOC_DMA, 565 (BSL_META_U(unit, 566 "_cmicx_sbusdma_reg_write: unit %d" 567 " mem %s[%u-%u].%s index %d-%d buffer %p\n"), 568 unit, SOC_MEM_UFNAME(unit, param->mem), 569 param->array_id_start, param->array_id_end, 570 SOC_BLOCK_NAME(unit, param->copyno), 571 param->index_begin, param->index_end, param->buffer)); 572 573 sal_memset(&prog, 0, sizeof(cmicx_sbusdma_prog_t)); 574 575 param->data_beats = soc_mem_entry_words(unit, param->mem); 576 577 if ((param->flags & (SOC_MEM_WRITE_COMMIT_ONLY | SOC_MEM_WRITE_STATUS_ONLY)) == 0) { /* used by SOC_MEM_WRITE_SET_ONLY */ 578 SOC_IF_ERROR_RETURN(_cmicx_sbusdma_reg_prog_init(unit, param, &msg, 579 &prog, WRITE_MEMORY_CMD_MSG)); 580 prog.mem_clear = param->mem_clear; 581 } else { /* calculate channel instead */ 582 if (param->vchan == -1) { 583 LOG_ERROR(BSL_LS_SOC_DMA, (BSL_META_U(unit, 584 "SOC_MEM_WRITE_STATUS_ONLY requires a channel to be specified\n"))); 585 return SOC_E_PARAM; 586 } else { 587 SOC_IF_ERROR_RETURN(cmicx_sbusdma_vchan_to_cmc_ch(unit, 588 param->vchan, &prog.cmc, &prog.ch)); 589 } 590 } 591 /* fill out the interrupt data */ 592 wait->ch = prog.ch; 593 wait->cmc = prog.cmc; 594 wait->intr = INTR_SBUSDMA(prog.cmc, prog.ch); 595 wait->opcode = WRITE_MEMORY_CMD_MSG; 596 597 for (array_index = param->array_id_start; 598 array_index <= param->array_id_end; ++array_index) { 599 if ((param->flags & (SOC_MEM_WRITE_COMMIT_ONLY | SOC_MEM_WRITE_STATUS_ONLY)) == 0) { /* used by SOC_MEM_WRITE_SET_ONLY */ 600 prog.start_addr = soc_mem_addr_get(unit, param->mem, array_index, 601 param->copyno, param->index_begin, &at); 602 603 _cmicx_sbusdma_reg_program(unit, &msg, param, &prog); 604 605 LOG_VERBOSE(BSL_LS_SOC_DMA, 606 (BSL_META_U(unit, 607 "_cmicx_sbusdma_reg_write: %d entries %d beats " 608 "addr 0x%x (index %d-%d) Interrupt-Mode(%d)\n"), 609 prog.count, prog.data_beats, prog.start_addr, 610 param->index_begin, param->index_end, 611 soc->tslamDmaIntrEnb)); 612 613 if (param->mem_clear) { 614 soc_cm_sflush(unit, param->buffer, WORDS2BYTES(prog.data_beats)); 615 } else { 616 soc_cm_sflush(unit, param->buffer, WORDS2BYTES(prog.data_beats) 617 * prog.count); 618 } 619 } 620 if ((param->flags & SOC_MEM_WRITE_SET_ONLY ) == 0) { /* used by SOC_MEM_WRITE_STATUS_ONLY */ 621 /* Wait for each index to finish, except the last one */ 622 if (array_index != param->array_id_end) { 623 rv = _cmicx_sbusdma_reg_complete(unit, param, wparam); 624 } 625 } 626 } /* end of loop over array indices */ 627 628 return rv; 629 630 631 } 632 633 /******************************************* 634 * @function _cmicx_sbusdma_reg_array_write 635 * purpose Program DMA for write 636 * 637 * @param unit [in] unit 638 * @param param [in] soc_sbusdma_reg_param_t pointer 639 * 640 * @returns SOC_E_NONE 641 * @returns SOC_E_XXX 642 * 643 * @end 644 */ 645 STATIC int 646 _cmicx_sbusdma_reg_array_write(int unit, soc_sbusdma_reg_param_t *param) 647 { 648 soc_control_t *soc = SOC_CONTROL(unit); 649 int rv = SOC_E_NONE; 650 cmic_sbusdma_wparam_t wparam; 651 652 wparam.wait.intr_enb = soc->tslamDmaIntrEnb; 653 wparam.wait.timeout = soc->tslamDmaTimeout; 654 655 rv = _cmicx_sbusdma_reg_array_write_prog(unit, param, &wparam); 656 SOC_IF_ERROR_RETURN(rv); 657 658 if ((param->flags & (SOC_MEM_WRITE_COMMIT_ONLY | SOC_MEM_WRITE_SET_ONLY)) == 0) { /* used by SOC_MEM_WRITE_STATUS_ONLY */ 659 rv = _cmicx_sbusdma_reg_complete(unit, param, &wparam); 660 } 661 662 return rv; 663 } 664 665 /******************************************* 666 * @function _cmicx_sbusdma_reg_clear_specific 667 * purpose: Program DMA to clear specific memory/table 668 * 669 * @param unit [in] unit 670 * @param param [in] soc_sbusdma_reg_param_t pointer 671 * 672 * @returns SOC_E_NONE 673 * @returns SOC_E_XXX 674 * 675 * @end 676 */ 677 STATIC int 678 _cmicx_sbusdma_reg_clear_specific_prog(int unit, 679 void *data, void *wparam) 680 { 681 int rv = SOC_E_NONE; 682 int chunk_size, chunk_entries, mem_size, entry_words; 683 int index, blk, tmp, copyno; 684 uint32 *buf; 685 soc_sbusdma_reg_param_t *param; 686 687 param = (soc_sbusdma_reg_param_t *)data; 688 689 if (param == NULL) { 690 return SOC_E_PARAM; 691 } 692 if (SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit)) { 693 return SOC_E_NONE; 694 } 695 chunk_size = SOC_MEM_CLEAR_CHUNK_SIZE_GET(unit); 696 /* get legal values for indices, if too 697 * small/big use the memory's boundaries 698 */ 699 tmp = soc_mem_index_min(unit, param->mem); 700 if (param->index_begin < soc_mem_index_min(unit, param->mem)) { 701 param->index_begin = tmp; 702 } 703 if (param->index_end < param->index_begin) { 704 param->index_end = param->index_begin; 705 } else { 706 tmp = soc_mem_index_max(unit, param->mem); 707 if (param->index_end > tmp) { 708 param->index_end = tmp; 709 } 710 } 711 712 entry_words = soc_mem_entry_words(unit, param->mem); 713 mem_size = (param->index_end - param->index_begin + 1) * entry_words * 4; 714 if (mem_size < chunk_size) { 715 chunk_size = mem_size; 716 } 717 718 buf = soc_cm_salloc(unit, chunk_size, "mem_clear_buf"); 719 if (buf == NULL) { 720 return SOC_E_MEMORY; 721 } 722 chunk_entries = chunk_size / (entry_words * 4); 723 for (index = 0; index < chunk_entries; index++) { 724 sal_memcpy(buf + (index * entry_words), 725 param->buffer, entry_words * 4); 726 } 727 728 /* get legal values for memory array indices */ 729 if (SOC_MEM_IS_ARRAY(unit, param->mem)) { 730 soc_mem_array_info_t *maip = SOC_MEM_ARRAY_INFOP(unit, param->mem); 731 if (maip) { 732 if (param->array_id_end >= maip->numels + maip->first_array_index) { 733 param->array_id_end = (maip->numels - 1) + maip->first_array_index; 734 } else if (param->array_id_start < maip->first_array_index) { 735 param->array_id_start = maip->first_array_index; 736 } 737 } 738 } else { 739 param->array_id_start = param->array_id_end = 0; 740 } 741 copyno = param->copyno; 742 MEM_LOCK(unit, param->mem); 743 SOC_MEM_BLOCK_ITER(unit, param->mem, blk) { 744 if (copyno != COPYNO_ALL && copyno != blk) { 745 continue; 746 } 747 param->buffer = buf; 748 param->flags = 0; 749 param->mem_clear = TRUE; 750 rv = _cmicx_sbusdma_reg_array_write(unit, param); 751 if (rv < 0) { 752 LOG_ERROR(BSL_LS_SOC_DMA, 753 (BSL_META_U(unit, 754 "soc_mem_sbusdma_clear: %s.%s[%d-%d] failed: %s\n"), 755 SOC_MEM_UFNAME(unit, param->mem), 756 SOC_BLOCK_NAME(unit, blk), 757 param->index_begin, param->index_end, 758 soc_errmsg(rv))); 759 } 760 } 761 MEM_UNLOCK(unit, param->mem); 762 /* restoring the copy number since it is modified */ 763 param->copyno = copyno; 764 soc_cm_sfree(unit, buf); 765 return rv; 766 767 } 768 769 /******************************************* 770 * @function _cmicx_sbusdma_reg_clear_specific 771 * purpose clear a specific memory/table region using 772 * DMA write (slam) acceleration. 773 * 774 * @param unit [in] unit 775 * @param param [in] soc_sbusdma_reg_param_t pointer 776 * 777 * @returns SOC_E_NONE 778 * @returns SOC_E_XXX 779 * 780 * @end 781 */ 782 STATIC int 783 _cmicx_sbusdma_reg_clear_specific(int unit, soc_sbusdma_reg_param_t *param) 784 { 785 int rv = SOC_E_NONE; 786 787 rv = _cmicx_sbusdma_reg_clear_specific_prog(unit, param, NULL); 788 789 return rv; 790 } 791 792 /******************************************* 793 * @function _cmicx_sbusdma_cmc_max_num_ch_get 794 * @Returns number of SBUSDMA channels in cmc 795 * 796 * @end 797 */ 798 STATIC uint32 799 _cmicx_sbusdma_cmc_max_num_ch_get(int unit) 800 { 801 return CMIC_CMCx_SBUSDMA_CHAN_MAX; 802 } 803 804 /******************************************* 805 * @function cmicx_sbusdma_reg_init 806 * purpose API to Initialize cmicx Register DMA 807 * 808 * @param unit [in] unit 809 * @param drv [out] soc_sbusdma_desc_drv_t pointer 810 * 811 * @returns SOC_E_NONE 812 * @returns SOC_E_XXX 813 * 814 * @end 815 */ 816 int cmicx_sbusdma_reg_init(int unit, soc_sbusdma_reg_drv_t *drv) 817 { 818 /* Set ARB control register */ 819 soc_pci_write(unit, CMIC_TOP_SBUS_RING_ARB_CTRL_SBUSDMA_OFFSET, 820 CMIC_TOP_SBUS_RING_ARB_CTRL_SET); 821 822 drv->soc_mem_sbusdma_read = _cmicx_sbusdma_reg_array_read; 823 drv->soc_mem_sbusdma_write = _cmicx_sbusdma_reg_array_write; 824 drv->soc_mem_sbusdma_clear = _cmicx_sbusdma_reg_clear_specific; 825 drv->soc_sbusdma_read_prog = _cmicx_sbusdma_reg_array_read_prog; 826 drv->soc_sbusdma_write_prog = _cmicx_sbusdma_reg_array_write_prog; 827 drv->soc_sbusdma_clear_prog = _cmicx_sbusdma_reg_clear_specific_prog; 828 drv->soc_sbusdma_reg_complete = _cmicx_sbusdma_reg_complete; 829 drv->soc_sbusdma_cmc_max_num_ch_get = _cmicx_sbusdma_cmc_max_num_ch_get; 830 831 return SOC_E_NONE; 832 } 833 834 #endif /* BCM_SBUSDMA_SUPPORT */ 835