sbusdma.c (35402B)
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: SOC SBUS-DMA and FIFO DMA driver. 8 */ 9 10 #include <shared/bsl.h> 11 12 #include <sal/core/boot.h> 13 #include <sal/core/libc.h> 14 #include <shared/alloc.h> 15 16 #include <soc/drv.h> 17 #include <soc/debug.h> 18 #include <soc/cm.h> 19 #include <soc/sbusdma_internal.h> 20 #include <soc/l2x.h> 21 #ifdef BCM_SAND_SUPPORT 22 #include <soc/sand/sand_aux_access.h> 23 #endif 24 25 #ifdef CRASH_RECOVERY_SUPPORT 26 #include <soc/hwstate/hw_log.h> 27 #include <soc/dcmn/dcmn_crash_recovery.h> 28 #endif 29 30 #ifdef BCM_DNX_SUPPORT 31 #include <soc/dnx/dnx_err_recovery_manager_utils.h> 32 #endif 33 34 #if defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) 35 #ifdef BCM_SBUSDMA_SUPPORT 36 37 #if (!defined(_LIMITS_H)) && !defined(_LIBC_LIMITS_H_) 38 39 #if (!defined(INT_MIN)) && !defined(INT_MAX) 40 #define INT_MIN (((int)1)<<(sizeof(int)*8-1)) 41 #define INT_MAX (~INT_MIN) 42 #endif 43 44 #ifndef UINT_MAX 45 #define UINT_MAX ((unsigned)-1) 46 #endif 47 48 #endif 49 50 #ifdef BCM_KATANA2_SUPPORT 51 #define RD_DMA_CFG_REG 0 52 #define RD_DMA_HOTMEM_THRESHOLD_REG 1 53 #define RD_DMA_STAT 2 54 #define RD_DMA_STAT_CLR 3 55 #endif 56 57 typedef struct soc_sbusdma_reg_s { 58 soc_sbusdma_reg_drv_t drv; 59 soc_sbusdma_cmic_ch_t ch; 60 } soc_sbusdma_reg_t; 61 62 STATIC soc_sbusdma_desc_drv_t _sbusdma_desc_drv[SOC_MAX_NUM_DEVICES]; 63 STATIC soc_sbusdma_reg_t _sbusdma_reg_drv[SOC_MAX_NUM_DEVICES]; 64 65 /* 66 * Function: 67 * _soc_mem_sbusdma_read 68 * Purpose: 69 * DMA acceleration for soc_mem_read_range() 70 * Parameters: 71 * buffer -- must be pointer to sufficiently large 72 * DMA-able block of memory 73 */ 74 int 75 _soc_mem_sbusdma_read(int unit, soc_mem_t mem, int copyno, 76 int index_min, int index_max, 77 uint32 ser_flags, void *buffer) 78 { 79 return _soc_mem_array_sbusdma_read(unit, mem, 0, copyno, 80 index_min, index_max, 81 ser_flags, buffer, -1); 82 } 83 84 int 85 _soc_mem_array_sbusdma_read(int unit, soc_mem_t mem, unsigned array_index, 86 int copyno, int index_min, int index_max, 87 uint32 ser_flags, void *buffer, int vchan) 88 { 89 int rv = SOC_E_MEMORY; 90 #ifdef CRASH_RECOVERY_SUPPORT 91 int rv_cr = SOC_E_NONE; 92 #endif 93 soc_sbusdma_reg_param_t param; 94 95 param.mem = mem; 96 param.array_id_start = array_index; 97 param.index_begin = index_min; 98 param.index_end = index_max; 99 param.copyno = copyno; 100 101 #if defined(BCM_TRIDENT2_SUPPORT) || defined(BCM_TRIDENT2PLUS_SUPPORT) || defined(BCM_MONTEREY_SUPPORT) || defined(BCM_APACHE_SUPPORT) 102 if (SOC_IS_TRIDENT2X(unit)) { 103 /* The ser and access flags use different macros, using the same bits. 104 They were not designed to be specified by the same values. 105 The argument contains a flags field supporting 106 SOC_MEM_WRITE_* values, and does not support any _SOC_SER_FLAG_* flags. 107 TD2X device seem to have code specifying SOC_MEM_WRITE_* flags in serflags arguments. */ 108 param.flags = ser_flags; 109 } 110 else 111 #endif 112 { 113 param.flags = 0; 114 } 115 param.buffer = buffer; 116 param.vchan = vchan; 117 118 #ifdef CRASH_RECOVERY_SUPPORT 119 soc_hw_set_immediate_hw_access(unit); 120 #endif 121 if (_sbusdma_reg_drv[unit].drv.soc_mem_sbusdma_read != NULL) { 122 rv = _sbusdma_reg_drv[unit].drv.soc_mem_sbusdma_read(unit, ¶m); 123 } 124 #ifdef CRASH_RECOVERY_SUPPORT 125 soc_hw_restore_immediate_hw_access(unit); 126 127 /* check the log if we have any updated values */ 128 if (BCM_UNIT_DO_HW_READ_WRITE(unit)) { 129 if(Hw_Log_List[unit].Access_cb.soc_sbusdma_read) { 130 rv_cr = Hw_Log_List[unit].Access_cb.soc_sbusdma_read(unit, mem, array_index, copyno, index_min, index_max, ser_flags, buffer, vchan); 131 if(rv_cr != SOC_E_NONE) { 132 soc_dcmn_cr_suppress(unit, dcmn_cr_no_support_dma); 133 /* Might have to re-read the entry from hardware after the suppression */ 134 _soc_mem_array_sbusdma_read(unit, mem, array_index, copyno, index_min, index_max, ser_flags, buffer, vchan); 135 } 136 } 137 } 138 #endif 139 140 return rv; 141 } 142 143 /* 144 * Function: 145 * _soc_mem_array_sbusdma_write 146 * Purpose: 147 * DMA acceleration for soc_mem_write_range() on FB/ER 148 * Parameters: 149 * buffer -- must be pointer to sufficiently large 150 * DMA-able block of memory 151 * index_begin <= index_end - Forward direction 152 * index_begin > index_end - Reverse direction 153 * mem_clear -- if TRUE: simply clear memory using one 154 * mem chunk from the supplied buffer 155 * clear_buf_ent is not used as SLAM DMA only supports 156 * a one entry buffer 157 */ 158 159 int 160 _soc_mem_array_sbusdma_write(int unit, int flags, soc_mem_t mem, 161 unsigned array_index_start, 162 unsigned array_index_end, int copyno, 163 int index_begin, int index_end, 164 void *buffer, uint8 mem_clear, 165 int clear_buf_ent, int vchan) 166 { 167 int rv = SOC_E_MEMORY; 168 169 soc_sbusdma_reg_param_t param; 170 171 172 #ifdef CRASH_RECOVERY_SUPPORT 173 if (BCM_UNIT_DO_HW_READ_WRITE(unit)) { 174 if(Hw_Log_List[unit].Access_cb.soc_sbusdma_write) { 175 return Hw_Log_List[unit].Access_cb.soc_sbusdma_write( 176 unit, flags, mem, 177 array_index_start, 178 array_index_end, copyno, 179 index_begin, index_end, 180 buffer, mem_clear, 181 clear_buf_ent, vchan); 182 } 183 } 184 #endif 185 186 param.mem = mem; 187 param.array_id_start = array_index_start; 188 param.array_id_end = array_index_end; 189 param.index_begin = index_begin; 190 param.index_end = index_end; 191 param.copyno = copyno; 192 param.flags= flags; 193 param.mem_clear = mem_clear; 194 param.buffer = buffer; 195 param.vchan = vchan; 196 197 if (_sbusdma_reg_drv[unit].drv.soc_mem_sbusdma_write != NULL) { 198 rv = _sbusdma_reg_drv[unit].drv.soc_mem_sbusdma_write(unit, 199 ¶m); 200 } 201 202 return rv; 203 } 204 205 /* 206 * Function: 207 * _soc_mem_sbusdma_write 208 * Purpose: 209 * DMA acceleration for soc_mem_write_range() on FB/ER 210 * Parameters: 211 * buffer -- must be pointer to sufficiently large 212 * DMA-able block of memory 213 * index_begin <= index_end - Forward direction 214 * index_begin > index_end - Reverse direction 215 * mem_clear -- if TRUE: simply clear memory using one 216 * mem chunk from the supplied buffer 217 */ 218 219 int 220 _soc_mem_sbusdma_write(int unit, soc_mem_t mem, int copyno, 221 int index_begin, int index_end, 222 void *buffer, uint8 mem_clear, 223 int clear_buf_ent) 224 { 225 return _soc_mem_array_sbusdma_write(unit, 0, mem, 0, 0, copyno, index_begin, 226 index_end, buffer, mem_clear, 227 clear_buf_ent, -1); 228 } 229 230 /* 231 * Function: 232 * _soc_mem_sbusdma_clear_specific 233 * Purpose: 234 * clear a specific memory/table region using DMA 235 * write (slam) acceleration. 236 */ 237 int 238 _soc_mem_sbusdma_clear_specific(int unit, soc_mem_t mem, 239 unsigned array_index_min, 240 unsigned array_index_max, 241 int copyno, 242 int index_min, int index_max, 243 void *null_entry) 244 { 245 int rv = SOC_E_MEMORY; 246 247 soc_sbusdma_reg_param_t param; 248 249 param.mem = mem; 250 param.array_id_start = array_index_min; 251 param.array_id_end = array_index_max; 252 param.index_begin = index_min; 253 param.index_end = index_max; 254 param.copyno = copyno; 255 param.buffer = null_entry; 256 param.vchan = -1; 257 258 if (_sbusdma_reg_drv[unit].drv.soc_mem_sbusdma_clear != NULL) { 259 rv = _sbusdma_reg_drv[unit].drv.soc_mem_sbusdma_clear(unit, ¶m); 260 } 261 262 263 return rv; 264 } 265 266 267 /* 268 * Function: 269 * _soc_mem_sbusdma_clear 270 * Purpose: 271 * soc_mem_clear acceleration using table DMA write (slam) 272 */ 273 int 274 _soc_mem_sbusdma_clear(int unit, soc_mem_t mem, int copyno, void *null_entry) 275 { 276 return _soc_mem_sbusdma_clear_specific(unit, mem, 0, UINT_MAX, copyno, 277 INT_MIN, INT_MAX, null_entry); 278 } 279 280 /* 281 **************************************************************** 282 * SBUSDMA descriptor mode 283 */ 284 285 STATIC int 286 _soc_sbusdma_desc_abort(int unit) 287 { 288 soc_timeout_t to; 289 /* signal abort */ 290 SOC_SBUSDMA_DM_TO(unit) = 0; 291 if (SOC_SBUSDMA_DM_PID(unit) != SAL_THREAD_ERROR) { 292 /* Wake up thread so it will check the exit flag */ 293 sal_sem_give(SOC_SBUSDMA_DM_INTR(unit)); 294 295 /* Give thread a few seconds to wake up and exit */ 296 if (SAL_BOOT_SIMULATION) { 297 soc_timeout_init(&to, 50 * 1000000, 0); 298 } else { 299 soc_timeout_init(&to, 10 * 1000000, 0); 300 } 301 302 while (SOC_SBUSDMA_DM_PID(unit) != SAL_THREAD_ERROR) { 303 if (soc_timeout_check(&to)) { 304 LOG_ERROR(BSL_LS_SOC_COMMON, 305 (BSL_META_U(unit, 306 "soc_sbusdma_desc_detach: SBUDMA Desc Mode thread will not exit\n"))); 307 return SOC_E_INTERNAL; 308 } 309 } 310 } 311 return SOC_E_NONE; 312 } 313 314 315 int 316 soc_sbusdma_desc_abort(int unit) 317 { 318 int rv = SOC_E_NONE; 319 320 if (!SOC_SBUSDMA_DM_INFO(unit)) { 321 return rv; 322 } 323 324 rv = _soc_sbusdma_desc_abort(unit); 325 326 return rv; 327 } 328 329 int 330 soc_sbusdma_desc_detach(int unit) 331 { 332 333 int i, rv = SOC_E_NONE; 334 _soc_sbusdma_state_t *swd; 335 336 if (!SOC_SBUSDMA_DM_INFO(unit)) { 337 return rv; 338 } 339 SOC_SBUSDMA_DM_INIT(unit) = 2; 340 /* Check if something is running and wait for it to complete 341 * (or issue an abort ?) */ 342 if (soc_sbusdma_desc_abort(unit)) { 343 return SOC_E_INTERNAL; 344 } 345 if (_sbusdma_desc_drv[unit].soc_sbusdma_desc_detach) { 346 rv = _sbusdma_desc_drv[unit].soc_sbusdma_desc_detach(unit); 347 } 348 349 for (i=1; i<SOC_SBUSDMA_MAX_DESC; i++) { 350 if (SOC_SBUSDMA_DM_HANDLES(unit)[i]) { 351 swd = SOC_SBUSDMA_DM_HANDLES(unit)[i]; 352 sal_free(swd->cfg); 353 if (!(swd->ctrl.flags & SOC_SBUSDMA_CFG_USE_SUPPLIED_DESC)) { 354 soc_cm_sfree(unit, swd->desc); 355 } 356 sal_free(swd); 357 SOC_SBUSDMA_DM_HANDLES(unit)[i] = 0; 358 SOC_SBUSDMA_DM_COUNT(unit)--; 359 } 360 } 361 362 if (SOC_SBUSDMA_DM_MUTEX(unit)) { 363 sal_mutex_destroy(SOC_SBUSDMA_DM_MUTEX(unit)); 364 SOC_SBUSDMA_DM_MUTEX(unit) = NULL; 365 } 366 if (SOC_SBUSDMA_DM_INTR(unit)) { 367 sal_sem_destroy(SOC_SBUSDMA_DM_INTR(unit)); 368 SOC_SBUSDMA_DM_INTR(unit) = NULL; 369 } 370 SOC_SBUSDMA_DM_INIT(unit) = 0; 371 sal_free(SOC_SBUSDMA_DM_INFO(unit)); 372 SOC_SBUSDMA_DM_INFO(unit) = NULL; 373 374 return rv; 375 } 376 377 STATIC void 378 _soc_sbusdma_desc(void *unit_vp) 379 { 380 int rv; 381 int unit = PTR_TO_INT(unit_vp); 382 soc_control_t *soc = SOC_CONTROL(unit); 383 sal_usecs_t interval; 384 sal_usecs_t stime, etime; 385 int cmc = SOC_PCI_CMC(unit); 386 int ch = soc->desc_ch; 387 _soc_sbusdma_state_t *swd; 388 389 assert((ch >= 0) && (ch < soc->max_sbusdma_channels)); 390 391 #ifdef BCM_DNX_SUPPORT 392 if(SOC_IS_DNX(unit)) 393 { 394 DNX_ERR_RECOVERY_UTILS_EXCLUDED_THREAD_ADD(unit); 395 } 396 #endif 397 398 while((interval = SOC_SBUSDMA_DM_TO(unit)) != 0) { 399 /* wait for run indication */ 400 (void)sal_sem_take(SOC_SBUSDMA_DM_INTR(unit), sal_sem_FOREVER); 401 if (!SOC_SBUSDMA_DM_TO(unit)) { 402 goto cleanup_exit; 403 } 404 if (!SOC_SBUSDMA_DM_ACTIVE(unit) || !SOC_SBUSDMA_DM_WORKING(unit)) { 405 continue; 406 } 407 408 LOG_VERBOSE(BSL_LS_SOC_DMA, 409 (BSL_META_U(unit, 410 "soc_sbusdma_desc: Process \n"))); 411 stime = sal_time_usecs(); 412 SOC_SBUSDMA_DM_LOCK(unit); 413 swd = SOC_SBUSDMA_DM_WORKING(unit); 414 415 /* execute preconfig */ 416 if (swd->ctrl.pc) { 417 swd->ctrl.pc(unit, swd->handle, swd->ctrl.pc_data); 418 } 419 420 rv = _sbusdma_desc_drv[unit].soc_sbusdma_program(unit, &cmc, swd, &ch); 421 422 if (rv == SOC_E_NONE) { 423 rv = _sbusdma_desc_drv[unit].soc_sbusdma_wait(unit, cmc, ch, 424 SOC_SBUSDMA_DM_TO(unit), 425 SOC_SBUSDMA_DM_INTRENB(unit)); 426 } 427 428 if (rv == SOC_E_NONE) { 429 etime = sal_time_usecs(); 430 LOG_VERBOSE(BSL_LS_SOC_DMA, 431 (BSL_META_U(unit, 432 "soc_sbusdma_desc: unit=%d mode(%s) done in %d usec\n"), 433 unit, SOC_SBUSDMA_DM_INTRENB(unit) ? "interrupt" : "polling", 434 SAL_USECS_SUB(etime, stime))); 435 } else { 436 LOG_ERROR(BSL_LS_SOC_COMMON, 437 (BSL_META_U(unit, 438 "soc_sbusdma_desc:%s Error\n"), 439 swd->ctrl.name)); 440 } 441 442 /* execute callback */ 443 swd->status = 0; 444 swd->ctrl.cb(unit, rv, swd->handle, swd->ctrl.data); 445 446 SOC_SBUSDMA_DM_ACTIVE(unit) = 0; 447 SOC_SBUSDMA_DM_UNLOCK(unit); 448 } 449 cleanup_exit: 450 451 /* cleanup the any pending/aborted descriptor */ 452 if (SOC_SBUSDMA_DM_ACTIVE(unit) && SOC_SBUSDMA_DM_WORKING(unit)) { 453 SOC_SBUSDMA_DM_LOCK(unit); 454 swd = SOC_SBUSDMA_DM_WORKING(unit); 455 swd->status = 0; 456 SOC_SBUSDMA_DM_ACTIVE(unit) = 0; 457 SOC_SBUSDMA_DM_UNLOCK(unit); 458 } 459 460 #ifdef BCM_DNX_SUPPORT 461 if(SOC_IS_DNX(unit)) 462 { 463 DNX_ERR_RECOVERY_UTILS_EXCLUDED_THREAD_REMOVE(unit); 464 } 465 #endif 466 467 LOG_INFO(BSL_LS_SOC_DMA, 468 (BSL_META_U(unit, 469 "_soc_sbusdma_desc: exiting\n"))); 470 SOC_SBUSDMA_DM_PID(unit) = SAL_THREAD_ERROR; 471 sal_thread_exit(0); 472 } 473 474 475 STATIC int 476 _soc_sbusdma_desc_init(int unit, int interval, uint8 intrEnb) 477 { 478 int rv; 479 if (SOC_SBUSDMA_DM_INFO(unit) && (SOC_SBUSDMA_DM_INIT(unit) == 2)) { 480 return SOC_E_BUSY; 481 } 482 if (SOC_SBUSDMA_DM_INFO(unit)) { 483 SOC_SBUSDMA_DM_INIT(unit) = 2; 484 if ((rv = soc_sbusdma_desc_detach(unit)) != SOC_E_NONE) { 485 return rv; 486 } 487 } 488 SOC_SBUSDMA_DM_INFO(unit) = sal_alloc(sizeof(soc_sbusdma_desc_info_t), 489 "sbusdma dm info"); 490 if (SOC_SBUSDMA_DM_INFO(unit) == NULL) { 491 return SOC_E_MEMORY; 492 } 493 sal_memset(SOC_SBUSDMA_DM_INFO(unit), 0, sizeof(soc_sbusdma_desc_info_t)); 494 SOC_SBUSDMA_DM_INIT(unit) = 2; 495 496 if ((SOC_SBUSDMA_DM_MUTEX(unit) = 497 sal_mutex_create("sbusdma dm lock")) == NULL) { 498 (void)soc_sbusdma_desc_detach(unit); 499 return SOC_E_MEMORY; 500 } 501 if ((SOC_SBUSDMA_DM_INTR(unit) = 502 sal_sem_create("Desc DMA interrupt", sal_sem_BINARY, 0)) == NULL) { 503 (void)soc_sbusdma_desc_detach(unit); 504 return SOC_E_MEMORY; 505 } 506 if (intrEnb) { 507 SOC_SBUSDMA_DM_INTRENB(unit) = 1; 508 } else { 509 SOC_SBUSDMA_DM_INTRENB(unit) = 0; 510 } 511 SOC_SBUSDMA_DM_TO(unit) = interval ? interval : SAL_BOOT_QUICKTURN ? 512 30000000 : 10000000; 513 sal_snprintf(SOC_SBUSDMA_DM_NAME(unit), sizeof(SOC_SBUSDMA_DM_NAME(unit)), 514 "socdmadesc.%d", unit); 515 SOC_SBUSDMA_DM_PID(unit) = sal_thread_create(SOC_SBUSDMA_DM_NAME(unit), 516 SAL_THREAD_STKSZ, 517 soc_property_get(unit, spn_SBUS_DMA_DESC_THREAD_PRI, 50), 518 _soc_sbusdma_desc, 519 INT_TO_PTR(unit)); 520 if (SOC_SBUSDMA_DM_PID(unit) == SAL_THREAD_ERROR) { 521 LOG_ERROR(BSL_LS_SOC_COMMON, 522 (BSL_META_U(unit, 523 "soc_sbusdma_desc_init: Could not start SBUDMA Desc Mode thread.\n"))); 524 (void)soc_sbusdma_desc_detach(unit); 525 return SOC_E_MEMORY; 526 } 527 528 SOC_SBUSDMA_DM_COUNT(unit) = 0; 529 SOC_SBUSDMA_DM_INIT(unit) = 1; 530 return SOC_E_NONE; 531 } 532 533 534 int 535 soc_sbusdma_desc_create(int unit, soc_sbusdma_desc_ctrl_t *ctrl, 536 soc_sbusdma_desc_cfg_t *cfg, 537 sbusdma_desc_handle_t *desc_handle) 538 { 539 uint32 i; 540 _soc_sbusdma_state_t *swd = NULL; 541 int rv; 542 543 if ((SOC_SBUSDMA_DM_INFO(unit) == NULL) || !SOC_SBUSDMA_DM_INIT(unit)) { 544 return SOC_E_INIT; 545 } 546 if (!ctrl || !cfg || !ctrl->cb || !ctrl->cfg_count) { 547 return SOC_E_PARAM; 548 } 549 550 SOC_SBUSDMA_DM_LOCK(unit); 551 552 swd = sal_alloc(sizeof(_soc_sbusdma_state_t), "_soc_sbusdma_state_t"); 553 if (swd == NULL) { 554 SOC_SBUSDMA_DM_UNLOCK(unit); 555 return SOC_E_MEMORY; 556 } 557 sal_memset(swd, 0, sizeof(_soc_sbusdma_state_t)); 558 /* save s/w ctrl and config */ 559 sal_memcpy(&swd->ctrl, ctrl, sizeof(soc_sbusdma_desc_ctrl_t)); 560 if (ctrl->cfg_count == 1) { /* single mode */ 561 swd->cfg = sal_alloc(sizeof(soc_sbusdma_desc_cfg_t), 562 "soc_sbusdma_desc_cfg_t"); 563 if (swd->cfg == NULL) { 564 sal_free(swd); 565 SOC_SBUSDMA_DM_UNLOCK(unit); 566 return SOC_E_MEMORY; 567 } 568 sal_memcpy(swd->cfg, cfg, sizeof(soc_sbusdma_desc_cfg_t)); 569 if (swd->ctrl.buff) { /* ctrl buff over-rides cfg buff */ 570 swd->cfg->buff = swd->ctrl.buff; 571 } 572 assert(swd->cfg->buff); 573 if (!(ctrl->flags & SOC_SBUSDMA_CFG_USE_SUPPLIED_DESC) || 574 !ctrl->hw_desc) { 575 576 /* Prepare h/w desc */ 577 rv = _sbusdma_desc_drv[unit].soc_sbusdma_desc_create( 578 unit, ctrl, 579 swd->cfg, 580 &swd->desc); 581 if (SOC_FAILURE(rv)) { 582 sal_free(swd->cfg); 583 sal_free(swd); 584 SOC_SBUSDMA_DM_UNLOCK(unit); 585 return rv; 586 } 587 } 588 } else { /* chain mode */ 589 590 swd->cfg = sal_alloc(sizeof(soc_sbusdma_desc_cfg_t) * ctrl->cfg_count, 591 "soc_sbusdma_desc_cfg_t"); 592 if (swd->cfg == NULL) { 593 sal_free(swd); 594 SOC_SBUSDMA_DM_UNLOCK(unit); 595 return SOC_E_MEMORY; 596 } 597 sal_memcpy(swd->cfg, cfg, sizeof(soc_sbusdma_desc_cfg_t) * 598 ctrl->cfg_count); 599 if (!(ctrl->flags & SOC_SBUSDMA_CFG_USE_SUPPLIED_DESC) || 600 !ctrl->hw_desc) { 601 602 /* Prepare h/w desc */ 603 rv = _sbusdma_desc_drv[unit].soc_sbusdma_desc_create( 604 unit, ctrl, 605 swd->cfg, 606 &swd->desc); 607 if (SOC_FAILURE(rv)) { 608 sal_free(swd->cfg); 609 sal_free(swd); 610 SOC_SBUSDMA_DM_UNLOCK(unit); 611 return rv; 612 } 613 } 614 } 615 /* find a free handle */ 616 for (i=1; i<SOC_SBUSDMA_MAX_DESC;) { 617 if (SOC_SBUSDMA_DM_HANDLES(unit)[i] == 0) { 618 break; 619 } 620 i++; 621 } 622 if(i >= SOC_SBUSDMA_MAX_DESC) { 623 LOG_WARN(BSL_LS_SOC_DMA, 624 (BSL_META_U(unit, 625 "No free DMA descriptors. All %d are used. \n"), i)); 626 if (!(swd->ctrl.flags & SOC_SBUSDMA_CFG_USE_SUPPLIED_DESC)) { 627 soc_cm_sfree(unit, swd->desc); 628 } 629 sal_free(swd->cfg); 630 sal_free(swd); 631 SOC_SBUSDMA_DM_UNLOCK(unit); 632 return SOC_E_RESOURCE; 633 } 634 635 *desc_handle = i; 636 swd->handle = *desc_handle; 637 SOC_SBUSDMA_DM_HANDLES(unit)[i] = swd; 638 SOC_SBUSDMA_DM_COUNT(unit)++; 639 SOC_SBUSDMA_DM_UNLOCK(unit); 640 if (ctrl->cfg_count == 1) { 641 LOG_INFO(BSL_LS_SOC_DMA, 642 (BSL_META_U(unit, 643 "Create Single:: Handle: %d," 644 "opcount: %d, buff: %p\n"), 645 swd->handle, swd->ctrl.cfg_count, swd->cfg->buff)); 646 } else { 647 LOG_INFO(BSL_LS_SOC_DMA, 648 (BSL_META_U(unit, 649 "Create Chain:: Handle: %d, desc count: %d\n"), 650 swd->handle, swd->ctrl.cfg_count)); 651 } 652 653 LOG_INFO(BSL_LS_SOC_DMA, 654 (BSL_META_U(unit, 655 "SBD DM count: %d\n"), SOC_SBUSDMA_DM_COUNT(unit))); 656 return SOC_E_NONE; 657 } 658 659 int 660 soc_sbusdma_desc_get(int unit, sbusdma_desc_handle_t desc_handle, 661 soc_sbusdma_desc_ctrl_t *ctrl, 662 soc_sbusdma_desc_cfg_t *cfg) 663 { 664 _soc_sbusdma_state_t *swd; 665 666 if ((SOC_SBUSDMA_DM_INFO(unit) == NULL) || !SOC_SBUSDMA_DM_INIT(unit) || 667 !SOC_SBUSDMA_DM_COUNT(unit)) { 668 return SOC_E_INIT; 669 } 670 671 if (!ctrl || !cfg) { 672 return SOC_E_PARAM; 673 } 674 675 SOC_SBUSDMA_DM_LOCK(unit); 676 if ((desc_handle > 0) && (desc_handle <= SOC_SBUSDMA_MAX_DESC) 677 && SOC_SBUSDMA_DM_HANDLES(unit)[desc_handle]) { 678 swd = SOC_SBUSDMA_DM_HANDLES(unit)[desc_handle]; 679 } else { 680 SOC_SBUSDMA_DM_UNLOCK(unit); 681 LOG_ERROR(BSL_LS_SOC_COMMON, 682 (BSL_META_U(unit, 683 "Get request for invalid or non-existing descriptor handle: %d\n"), 684 desc_handle)); 685 return SOC_E_PARAM; 686 } 687 if (swd->handle != desc_handle) { 688 SOC_SBUSDMA_DM_UNLOCK(unit); 689 LOG_ERROR(BSL_LS_SOC_COMMON, 690 (BSL_META_U(unit, 691 "Handle mismatch found: %d<=>%d\n"), swd->handle, 692 desc_handle)); 693 return SOC_E_INTERNAL; 694 } 695 sal_memcpy(ctrl, &swd->ctrl, sizeof(soc_sbusdma_desc_ctrl_t)); 696 sal_memcpy(cfg, swd->cfg, sizeof(soc_sbusdma_desc_cfg_t) * ctrl->cfg_count); 697 SOC_SBUSDMA_DM_UNLOCK(unit); 698 return SOC_E_NONE; 699 } 700 701 int 702 soc_sbusdma_desc_get_state(int unit, sbusdma_desc_handle_t desc_handle, 703 uint8 *state) 704 { 705 _soc_sbusdma_state_t *swd; 706 707 if ((SOC_SBUSDMA_DM_INFO(unit) == NULL) || !SOC_SBUSDMA_DM_INIT(unit) || 708 !SOC_SBUSDMA_DM_COUNT(unit)) { 709 return SOC_E_INIT; 710 } 711 SOC_SBUSDMA_DM_LOCK(unit); 712 if ((desc_handle > 0) && (desc_handle <= SOC_SBUSDMA_MAX_DESC) 713 && SOC_SBUSDMA_DM_HANDLES(unit)[desc_handle]) { 714 swd = SOC_SBUSDMA_DM_HANDLES(unit)[desc_handle]; 715 } else { 716 SOC_SBUSDMA_DM_UNLOCK(unit); 717 LOG_ERROR(BSL_LS_SOC_COMMON, 718 (BSL_META_U(unit, 719 "Get state request for invalid or non-existing descriptor handle: %d\n"), 720 desc_handle)); 721 return SOC_E_PARAM; 722 } 723 if (swd->handle != desc_handle) { 724 SOC_SBUSDMA_DM_UNLOCK(unit); 725 LOG_ERROR(BSL_LS_SOC_COMMON, 726 (BSL_META_U(unit, 727 "Handle mismatch found: %d<=>%d\n"), swd->handle, 728 desc_handle)); 729 return SOC_E_INTERNAL; 730 } 731 *state = swd->status; 732 SOC_SBUSDMA_DM_UNLOCK(unit); 733 return SOC_E_NONE; 734 } 735 736 int 737 soc_sbusdma_desc_run(int unit, sbusdma_desc_handle_t desc_handle) 738 { 739 _soc_sbusdma_state_t *swd; 740 741 if ((SOC_SBUSDMA_DM_INFO(unit) == NULL) || !SOC_SBUSDMA_DM_INIT(unit) || 742 !SOC_SBUSDMA_DM_COUNT(unit)) { 743 return SOC_E_INIT; 744 } 745 SOC_SBUSDMA_DM_LOCK(unit); 746 if (SOC_SBUSDMA_DM_ACTIVE(unit)) { 747 SOC_SBUSDMA_DM_UNLOCK(unit); 748 return SOC_E_BUSY; 749 } 750 if ((desc_handle > 0) && (desc_handle <= SOC_SBUSDMA_MAX_DESC) 751 && SOC_SBUSDMA_DM_HANDLES(unit)[desc_handle]) { 752 swd = SOC_SBUSDMA_DM_HANDLES(unit)[desc_handle]; 753 } else { 754 SOC_SBUSDMA_DM_UNLOCK(unit); 755 LOG_ERROR(BSL_LS_SOC_COMMON, 756 (BSL_META_U(unit, 757 "Run request for invalid or non-existing descriptor handle: %d\n"), 758 desc_handle)); 759 return SOC_E_PARAM; 760 } 761 if (swd->handle != desc_handle) { 762 SOC_SBUSDMA_DM_UNLOCK(unit); 763 LOG_ERROR(BSL_LS_SOC_COMMON, 764 (BSL_META_U(unit, 765 "Handle mismatch found: %d<=>%d\n"), 766 swd->handle, desc_handle)); 767 return SOC_E_INTERNAL; 768 } 769 770 /* process swd->desc */ 771 swd->status = 1; 772 SOC_SBUSDMA_DM_ACTIVE(unit) = 1; 773 SOC_SBUSDMA_DM_WORKING(unit) = swd; 774 775 if (swd->ctrl.cfg_count == 1) { 776 LOG_INFO(BSL_LS_SOC_DMA, 777 (BSL_META_U(unit, 778 "Run Single:: Handle: %d, desc count: %d," 779 "buff: %p\n"), 780 swd->handle, swd->ctrl.cfg_count, swd->cfg->buff)); 781 } else { 782 LOG_INFO(BSL_LS_SOC_DMA, 783 (BSL_META_U(unit, 784 "Run Chain:: Handle: %d, desc count: %d\n"), 785 swd->handle, swd->ctrl.cfg_count)); 786 } 787 sal_sem_give(SOC_SBUSDMA_DM_INTR(unit)); 788 789 SOC_SBUSDMA_DM_UNLOCK(unit); 790 791 return SOC_E_NONE; 792 } 793 794 int 795 soc_sbusdma_desc_start(int unit, sbusdma_desc_handle_t desc_handle) 796 { 797 soc_control_t *soc = SOC_CONTROL(unit); 798 _soc_sbusdma_state_t *swd; 799 sal_usecs_t stime, etime; 800 int cmc = SOC_PCI_CMC(unit); 801 int ch = soc->desc_ch; 802 int rv; 803 804 if (!SOC_CHECK_MULTI_CMC(unit)) { 805 return soc_sbusdma_desc_run(unit, desc_handle); 806 } 807 808 if ((SOC_SBUSDMA_DM_INFO(unit) == NULL) || !SOC_SBUSDMA_DM_INIT(unit) || 809 !SOC_SBUSDMA_DM_COUNT(unit)) { 810 return SOC_E_INIT; 811 } 812 SOC_SBUSDMA_DM_LOCK(unit); 813 if ((desc_handle > 0) && (desc_handle <= SOC_SBUSDMA_MAX_DESC) 814 && SOC_SBUSDMA_DM_HANDLES(unit)[desc_handle]) { 815 swd = SOC_SBUSDMA_DM_HANDLES(unit)[desc_handle]; 816 } else { 817 SOC_SBUSDMA_DM_UNLOCK(unit); 818 LOG_ERROR(BSL_LS_SOC_COMMON, 819 (BSL_META_U(unit, 820 "Start request for invalid or non-existing descriptor handle: %d\n"), 821 desc_handle)); 822 return SOC_E_PARAM; 823 } 824 if (swd->handle != desc_handle) { 825 SOC_SBUSDMA_DM_UNLOCK(unit); 826 LOG_ERROR(BSL_LS_SOC_COMMON, 827 (BSL_META_U(unit, 828 "Handle mismatch found: %d<=>%d\n"), 829 swd->handle, desc_handle)); 830 return SOC_E_INTERNAL; 831 } 832 if (swd->status) { 833 SOC_SBUSDMA_DM_UNLOCK(unit); 834 return SOC_E_BUSY; 835 } 836 swd->status = 1; 837 SOC_SBUSDMA_DM_UNLOCK(unit); 838 839 if (swd->ctrl.cfg_count == 1) { 840 LOG_INFO(BSL_LS_SOC_DMA, 841 (BSL_META_U(unit, 842 "Start Single:: Handle: %d, desc count: %d," 843 "buff: %p\n"), 844 swd->handle, swd->ctrl.cfg_count, swd->cfg->buff)); 845 } else { 846 LOG_INFO(BSL_LS_SOC_DMA, 847 (BSL_META_U(unit, 848 "Start Chain:: Handle: %d, desc count: %d\n"), 849 swd->handle, swd->ctrl.cfg_count)); 850 } 851 852 stime = sal_time_usecs(); 853 854 /* execute preconfig */ 855 if (swd->ctrl.pc) { 856 swd->ctrl.pc(unit, swd->handle, swd->ctrl.pc_data); 857 } 858 859 rv = _sbusdma_desc_drv[unit].soc_sbusdma_program(unit, &cmc, swd, &ch); 860 861 if (rv == SOC_E_NONE) { 862 rv = _sbusdma_desc_drv[unit].soc_sbusdma_wait(unit, cmc, ch, 863 SOC_SBUSDMA_DM_TO(unit), 864 SOC_SBUSDMA_DM_INTRENB(unit)); 865 } 866 867 if (rv == SOC_E_NONE) { 868 etime = sal_time_usecs(); 869 LOG_VERBOSE(BSL_LS_SOC_DMA, 870 (BSL_META_U(unit, 871 "soc_sbusdma_desc: unit=%d mode(%s) done in %d usec\n"), 872 unit, SOC_SBUSDMA_DM_INTRENB(unit) ? "interrupt" : "polling", 873 SAL_USECS_SUB(etime, stime))); 874 } else { 875 LOG_ERROR(BSL_LS_SOC_COMMON, 876 (BSL_META_U(unit, 877 "soc_sbusdma_desc:%s Error\n"), 878 swd->ctrl.name)); 879 } 880 881 /* execute callback */ 882 swd->ctrl.cb(unit, rv, swd->handle, swd->ctrl.data); 883 884 SOC_SBUSDMA_DM_LOCK(unit); 885 swd->status = 0; 886 SOC_SBUSDMA_DM_UNLOCK(unit); 887 888 return rv; 889 } 890 891 int 892 soc_sbusdma_desc_delete(int unit, sbusdma_desc_handle_t handle) 893 { 894 _soc_sbusdma_state_t *swd; 895 896 if ((SOC_SBUSDMA_DM_INFO(unit) == NULL) || !SOC_SBUSDMA_DM_INIT(unit) || 897 !SOC_SBUSDMA_DM_COUNT(unit)) { 898 return SOC_E_INIT; 899 } 900 SOC_SBUSDMA_DM_LOCK(unit); 901 if ((handle > 0) && (handle <= SOC_SBUSDMA_MAX_DESC) 902 && SOC_SBUSDMA_DM_HANDLES(unit)[handle]) { 903 swd = SOC_SBUSDMA_DM_HANDLES(unit)[handle]; 904 if (swd->handle != handle) { 905 SOC_SBUSDMA_DM_UNLOCK(unit); 906 LOG_ERROR(BSL_LS_SOC_COMMON, 907 (BSL_META_U(unit, 908 "Handle mismatch found: %d<=>%d\n"), 909 swd->handle, handle)); 910 return SOC_E_INTERNAL; 911 } 912 if (swd->ctrl.cfg_count == 1) { 913 LOG_INFO(BSL_LS_SOC_DMA, 914 (BSL_META_U(unit, 915 "Delete Single:: Handle: %d, desc count: %d," 916 "buff: %p\n"), 917 swd->handle, swd->ctrl.cfg_count, swd->cfg->buff)); 918 } else { 919 LOG_INFO(BSL_LS_SOC_DMA, 920 (BSL_META_U(unit, 921 "Delete Chain:: Handle: %d, desc count: %d\n"), 922 swd->handle, swd->ctrl.cfg_count)); 923 } 924 sal_free(swd->cfg); 925 if (!(swd->ctrl.flags & SOC_SBUSDMA_CFG_USE_SUPPLIED_DESC)) { 926 soc_cm_sfree(unit, swd->desc); 927 } 928 sal_free(swd); 929 SOC_SBUSDMA_DM_HANDLES(unit)[handle] = 0; 930 SOC_SBUSDMA_DM_COUNT(unit)--; 931 LOG_INFO(BSL_LS_SOC_DMA, 932 (BSL_META_U(unit, 933 "SBD DM count: %d\n"), 934 SOC_SBUSDMA_DM_COUNT(unit))); 935 } else { 936 SOC_SBUSDMA_DM_UNLOCK(unit); 937 LOG_ERROR(BSL_LS_SOC_COMMON, 938 (BSL_META_U(unit, 939 "Del request for invalid or non-existing descriptor handle: %d\n"), 940 handle)); 941 return SOC_E_PARAM; 942 } 943 SOC_SBUSDMA_DM_UNLOCK(unit); 944 return SOC_E_NONE; 945 } 946 947 /******************************************* 948 * @function soc_sbusdma_ch_try_get 949 * purpose get idle channel on cmc 950 * 951 * @param unit [in] unit # 952 * @param cmc [out] cmc number 953 * @param ch [out] channel number 954 * 955 * @returns SOC_E_BUSY 956 * @returns SOC_E_NONE 957 * 958 * @end 959 */ 960 int soc_sbusdma_ch_try_get(int unit, int cmc, int ch) 961 { 962 int rv = SOC_E_NONE; 963 964 if (_sbusdma_reg_drv[unit].ch.soc_sbusdma_ch_try_get != NULL) { 965 rv = 966 _sbusdma_reg_drv[unit].ch.soc_sbusdma_ch_try_get(unit, cmc, ch); 967 } else { 968 rv = SOC_E_INIT; 969 } 970 971 return rv; 972 } 973 974 /******************************************* 975 * @function soc_sbusdma_ch_put 976 * purpose put back the freed channel on cmc 977 * 978 * @param cmc [in] cmc number 979 * @param ch [in] channel number 980 * 981 * @returns SOC_E_PARAM 982 * @returns SOC_E_NONE 983 * 984 * @end 985 */ 986 int soc_sbusdma_ch_put(int unit, int cmc, int ch) 987 { 988 int rv; 989 990 if (_sbusdma_reg_drv[unit].ch.soc_sbusdma_ch_put != NULL) { 991 rv = 992 _sbusdma_reg_drv[unit].ch.soc_sbusdma_ch_put(unit, cmc, ch); 993 } else { 994 rv = SOC_E_INIT; 995 } 996 997 return rv; 998 } 999 1000 /******************************************* 1001 * @function soc_sbusdma_ch_endian_set 1002 * set the endianess value 1003 * 1004 * @param cmc [in] cmc number 1005 * @param ch [in] channel number 1006 * @param ch [in] big_endian 1007 * 1008 * @returns SOC_E_PARAM 1009 * @returns SOC_E_NONE 1010 * 1011 * @end 1012 */ 1013 int soc_sbusdma_ch_endian_set(int unit, int cmc, int ch, int be) 1014 { 1015 #ifdef BCM_CMICX_SUPPORT 1016 if (soc_feature(unit, soc_feature_cmicx)) { 1017 return cmicx_sbusdma_ch_endian_set(unit, cmc, ch, be); 1018 } 1019 #endif 1020 1021 return SOC_E_NONE; 1022 } 1023 1024 /******************************************* 1025 * @function soc_sbusdma_cmc_max_num_ch_get 1026 * @Returns number of SBUSDMA channels in cmc 1027 * 1028 * @end 1029 */ 1030 uint32 soc_sbusdma_cmc_max_num_ch_get(int unit) 1031 { 1032 if(_sbusdma_reg_drv[unit].drv.soc_sbusdma_cmc_max_num_ch_get == NULL) { 1033 /* driver is not attached yet, so return zero */ 1034 return 0; 1035 } 1036 return _sbusdma_reg_drv[unit].drv.soc_sbusdma_cmc_max_num_ch_get(unit); 1037 } 1038 1039 /******************************************* 1040 * @function soc_sbusdma_reg_init 1041 * purpose API to Initialize cmicx/cmicm Register DMA 1042 * 1043 * @param unit [in] unit 1044 * 1045 * @returns SOC_E_NONE 1046 * @returns SOC_E_XXX 1047 * 1048 * @end 1049 */ 1050 int soc_sbusdma_reg_init(int unit) 1051 { 1052 #ifdef BCM_CMICX_SUPPORT 1053 if (soc_feature(unit, soc_feature_cmicx)) { 1054 SOC_IF_ERROR_RETURN(cmicx_sbusdma_reg_init(unit, 1055 &_sbusdma_reg_drv[unit].drv)); 1056 } 1057 #endif 1058 1059 #ifdef BCM_CMICM_SUPPORT 1060 if (soc_feature(unit, soc_feature_cmicm)) { 1061 SOC_IF_ERROR_RETURN(cmicm_sbusdma_reg_init(unit, 1062 &_sbusdma_reg_drv[unit].drv)); 1063 } 1064 #endif 1065 1066 return SOC_E_NONE; 1067 } 1068 1069 1070 /******************************************* 1071 * @function soc_sbusdma_init 1072 * purpose API to Initialize SBUS DMA 1073 * 1074 * @param unit [in] unit 1075 * 1076 * @returns SOC_E_NONE 1077 * @returns SOC_E_XXX 1078 * 1079 * @end 1080 */ 1081 int soc_sbusdma_init(int unit, int interval, uint8 intrEnb) 1082 { 1083 int rv; 1084 1085 #ifdef BCM_CMICX_SUPPORT 1086 if (soc_feature(unit, soc_feature_cmicx)) { 1087 soc_control_t *soc = SOC_CONTROL(unit); 1088 SOC_IF_ERROR_RETURN(cmicx_sbusdma_reg_init(unit, 1089 &_sbusdma_reg_drv[unit].drv)); 1090 SOC_IF_ERROR_RETURN(cmicx_sbusdma_ch_init(unit, 1091 soc->sbusDmaTimeout + CMIC_CMCx_SBUSDMA_CHSELECT_TIMEOUT, 1092 &_sbusdma_reg_drv[unit].ch)); 1093 1094 if ((soc->sbusDmaIntrEnb) || (soc->tslamDmaIntrEnb) || 1095 (soc->tableDmaIntrEnb)) { 1096 SOC_IF_ERROR_RETURN(cmicx_sbusdma_intr_init(unit)); 1097 } 1098 1099 SOC_IF_ERROR_RETURN(_soc_sbusdma_desc_init(unit, interval, intrEnb)); 1100 1101 rv = cmicx_sbusdma_desc_init(unit, &_sbusdma_desc_drv[unit]); 1102 if (rv != SOC_E_NONE) { 1103 (void)soc_sbusdma_desc_detach(unit); 1104 return rv; 1105 } 1106 1107 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1108 (BSL_META_U(unit,":SUCCESS\n"))); 1109 } 1110 #endif 1111 1112 1113 #ifdef BCM_CMICM_SUPPORT 1114 if (soc_feature(unit, soc_feature_cmicm)) { 1115 1116 SOC_IF_ERROR_RETURN(cmicm_sbusdma_reg_init(unit, 1117 &_sbusdma_reg_drv[unit].drv)); 1118 SOC_IF_ERROR_RETURN(cmicm_sbusdma_ch_init(unit, 1119 CMIC_CMCx_SBUSDMA_CHSELECT_TIMEOUT, 1120 &_sbusdma_reg_drv[unit].ch)); 1121 1122 SOC_IF_ERROR_RETURN(_soc_sbusdma_desc_init(unit, interval, intrEnb)); 1123 1124 rv = cmicm_sbusdma_desc_init(unit, &_sbusdma_desc_drv[unit]); 1125 if (rv != SOC_E_NONE) { 1126 (void)soc_sbusdma_desc_detach(unit); 1127 return rv; 1128 } 1129 } 1130 #endif 1131 1132 return SOC_E_NONE; 1133 } 1134 1135 #endif /* BCM_SBUSDMA_SUPPORT */ 1136 #endif /* defined(BCM_ESW_SUPPORT) || defined(BCM_SAND_SUPPORT) */