cmicx_sbusdma_common.c (23428B)
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 Common utility functions 8 */ 9 10 #include <shared/bsl.h> 11 #include <soc/debug.h> 12 #include <soc/cm.h> 13 #include <sal/core/sync.h> 14 #include <soc/util.h> 15 #include <soc/drv.h> 16 #include <soc/sbusdma_internal.h> 17 18 #if defined(BCM_CMICX_SUPPORT) && defined(BCM_SBUSDMA_SUPPORT) 19 #include <soc/cmicx.h> 20 #include <soc/intr_cmicx.h> 21 22 23 typedef struct intr_data_s { 24 int cmc; 25 int ch; 26 }intr_data_t; 27 28 29 typedef struct cmicx_sbusdma_ch_s { 30 sal_spinlock_t lock[SOC_MAX_NUM_DEVICES]; 31 int timeout; 32 sal_sem_t sem[SOC_MAX_NUM_DEVICES]; 33 uint8 ch[SOC_MAX_NUM_DEVICES][CMIC_CMC_NUM_MAX]; 34 uint8 wait[SOC_MAX_NUM_DEVICES][CMIC_CMC_NUM_MAX]; 35 }cmicx_sbusdma_ch_t; 36 37 38 STATIC intr_data_t _intr_data[CMIC_CMC_NUM_MAX][CMIC_CMCx_SBUSDMA_CHAN_MAX]; 39 40 STATIC cmicx_sbusdma_ch_t _cmicx_sbusdma_ch; 41 42 43 /******************************************* 44 * @function cmicx_sbusdma_curr_op_details 45 * purpose Print operation details 46 * 47 * @param unit [in] unit 48 * @param cmc [in] cmc number 49 * @param ch [in] channel number 50 * 51 * @returns SOC_E_NONE 52 * @returns SOC_E_XXX 53 * 54 * @end 55 */ 56 void 57 cmicx_sbusdma_curr_op_details(int unit, int cmc, int ch) 58 { 59 uint32 rval; 60 61 /* Set up the trigger incase PCI trace need to be taken */ 62 soc_pci_analyzer_trigger(unit); 63 64 rval = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch)); 65 LOG_WARN(BSL_LS_SOC_COMMON, 66 (BSL_META_U(unit, 67 "STATUS: 0x%08x. cmc = %d, ch = %d\n"), rval, cmc, ch)); 68 rval = soc_pci_read(unit, 69 CMIC_CMCx_SBUSDMA_CHy_CUR_SBUSDMA_CONFIG_OPCODE(cmc, ch)); 70 LOG_WARN(BSL_LS_SOC_COMMON, 71 (BSL_META_U(unit, 72 "OPCODE: 0x%08x\n"), rval)); 73 rval = soc_pci_read(unit, 74 CMIC_CMCx_SBUSDMA_CHy_CUR_SBUSDMA_CONFIG_ADDR_LO(cmc, ch)); 75 LOG_WARN(BSL_LS_SOC_COMMON, 76 (BSL_META_U(unit, 77 "HOSTMEM ADDR LO: 0x%08x\n"), rval)); 78 rval = soc_pci_read(unit, 79 CMIC_CMCx_SBUSDMA_CHy_CUR_SBUSDMA_CONFIG_ADDR_HI(cmc, ch)); 80 LOG_WARN(BSL_LS_SOC_COMMON, 81 (BSL_META_U(unit, 82 "HOSTMEM ADDR HI: 0x%08x\n"), rval)); 83 rval = soc_pci_read(unit, 84 CMIC_CMCx_SBUSDMA_CHy_CUR_SBUSDMA_CONFIG_SBUS_START_ADDRESS(cmc, ch)); 85 LOG_WARN(BSL_LS_SOC_COMMON, 86 (BSL_META_U(unit, 87 "START ADDR: 0x%08x\n"), rval)); 88 rval = soc_pci_read(unit, 89 CMIC_CMCx_SBUSDMA_CHy_CUR_SBUSDMA_CONFIG_COUNT(cmc, ch)); 90 LOG_WARN(BSL_LS_SOC_COMMON, 91 (BSL_META_U(unit, 92 "COUNT: 0x%08x\n"), rval)); 93 rval = soc_pci_read(unit, 94 CMIC_CMCx_SBUSDMA_CHy_CUR_SBUSDMA_CONFIG_REQUEST(cmc, ch)); 95 LOG_WARN(BSL_LS_SOC_COMMON, 96 (BSL_META_U(unit, 97 "REQUEST: 0x%08x\n"), rval)); 98 99 rval = soc_pci_read(unit, 100 CMIC_CMCx_SBUSDMA_CHy_CUR_SBUSDMA_ITER_COUNT(cmc, ch)); 101 LOG_WARN(BSL_LS_SOC_COMMON, 102 (BSL_META_U(unit, 103 "ITER COUNT: 0x%08x\n"), rval)); 104 105 rval = soc_pci_read(unit, 106 CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch)); 107 108 LOG_WARN(BSL_LS_SOC_COMMON, 109 (BSL_META_U(unit, 110 "CONTROL: 0x%08x\n"), rval)); 111 112 rval = soc_pci_read(unit, 113 CMIC_CMCx_SBUSDMA_CHy_CUR_HOSTMEM_ADDRESS_LO(cmc, ch)); 114 115 LOG_WARN(BSL_LS_SOC_COMMON, 116 (BSL_META_U(unit, 117 "CUR_HOSTMEM_ADDRESS_LO: 0x%08x\n"), rval)); 118 119 rval = soc_pci_read(unit, 120 CMIC_CMCx_SBUSDMA_CHy_CUR_HOSTMEM_ADDRESS_HI(cmc, ch)); 121 122 LOG_WARN(BSL_LS_SOC_COMMON, 123 (BSL_META_U(unit, 124 "CUR_HOSTMEM_ADDRESS_HI: 0x%08x\n"), rval)); 125 126 rval = soc_pci_read(unit, 127 CMIC_CMCx_SBUSDMA_CHy_CUR_DESC_ADDRESS_LO(cmc, ch)); 128 129 LOG_WARN(BSL_LS_SOC_COMMON, 130 (BSL_META_U(unit, 131 "CUR_DESC_ADDRESS_LO: 0x%08x\n"), rval)); 132 133 rval = soc_pci_read(unit, 134 CMIC_CMCx_SBUSDMA_CHy_CUR_DESC_ADDRESS_HI(cmc, ch)); 135 136 LOG_WARN(BSL_LS_SOC_COMMON, 137 (BSL_META_U(unit, 138 "CUR_DESC_ADDRESS_HI: 0x%08x\n"), rval)); 139 140 #ifdef BCM_ESW_SUPPORT 141 if (SOC_IS_TRIDENT3X(unit) || SOC_IS_TOMAHAWKX(unit)){ 142 uint32 val; 143 for (val = 0x10800; val <= 0x10840; val += 0x10) { 144 soc_iproc_setreg( 145 unit, soc_reg_addr(unit, DMU_CRU_IPROC_DEBUG_SELr, 146 REG_PORT_ANY, 0), val); 147 sal_udelay(1); 148 soc_iproc_getreg( 149 unit, soc_reg_addr(unit, DMU_CRU_IPROC_DEBUG_STATUSr, 150 REG_PORT_ANY, 0), &rval); 151 LOG_WARN(BSL_LS_SOC_COMMON, 152 (BSL_META_U(unit, 153 "DMU_SEL = 0x%08x, DMU_STAT = 0x%08x\n"), val, rval)); 154 rval = soc_pci_read(unit, 155 CMIC_CMCx_SHARED_AXI_STAT_OFFSET(cmc)); 156 LOG_WARN(BSL_LS_SOC_COMMON, 157 (BSL_META_U(unit, 158 "CMIC_CMCx_SHARED_AXI_STAT: 0x%08x\n"), rval)); 159 } 160 } 161 #endif 162 163 } 164 165 /******************************************* 166 * @function cmicx_sbusdma_error_details 167 * purpose Print error details 168 * 169 * @param unit [in] unit 170 * @param rval [in] Error value 171 * 172 * @returns SOC_E_NONE 173 * @returns SOC_E_XXX 174 * 175 * @end 176 */ 177 void 178 cmicx_sbusdma_error_details(int unit, uint32 rval) 179 { 180 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 181 rval, DESCRD_ERRORf)) { 182 LOG_ERROR(BSL_LS_SOC_COMMON, 183 (BSL_META_U(unit, 184 "Error while reading descriptor from host memory.\n"))); 185 } 186 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 187 rval, SBUSACK_TIMEOUTf)) { 188 LOG_ERROR(BSL_LS_SOC_COMMON, 189 (BSL_META_U(unit, 190 "sbus ack not received within configured time.\n"))); 191 } 192 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 193 rval, SBUSACK_ERRORf)) { 194 LOG_ERROR(BSL_LS_SOC_COMMON, 195 (BSL_META_U(unit, 196 "H/W received sbus ack with error bit set.\n"))); 197 } 198 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 199 rval, SBUSACK_NACKf)) { 200 LOG_ERROR(BSL_LS_SOC_COMMON, 201 (BSL_META_U(unit, 202 "H/W received sbus nack with error bit set.\n"))); 203 } 204 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 205 rval, SBUSACK_WRONG_OPCODEf)) { 206 LOG_ERROR(BSL_LS_SOC_COMMON, 207 (BSL_META_U(unit, 208 "Received sbus ack has wrong opcode.\n"))); 209 } 210 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 211 rval, SBUSACK_WRONG_BEATCOUNTf)) { 212 LOG_ERROR(BSL_LS_SOC_COMMON, 213 (BSL_META_U(unit, 214 "Received sbus ack data size is not the same as in rep_words " 215 "fields.\n"))); 216 } 217 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 218 rval, SER_CHECK_FAILf)) { 219 LOG_ERROR(BSL_LS_SOC_COMMON, 220 (BSL_META_U(unit, 221 "Received sbus ack with SER_CHECK_FAIL set.\n"))); 222 } 223 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 224 rval, HOSTMEMRD_ERRORf)) { 225 LOG_ERROR(BSL_LS_SOC_COMMON, 226 (BSL_META_U(unit, 227 "Error while copying SBUSDMA data from Host Memory.\n"))); 228 } 229 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 230 rval, HOSTMEMWR_ERRORf)) { 231 LOG_ERROR(BSL_LS_SOC_COMMON, 232 (BSL_META_U(unit, 233 "DMA operation encountered a schan response error " 234 "or host side error.\n"))); 235 } 236 } 237 238 /******************************************* 239 * @function _cmicx_sbusdma_ch_get 240 * purpose get idle channel and cmc 241 * 242 * @param unit [in] unit # 243 * @param cmc [out] cmc number 0-1 244 * @param ch [out] channel number 0-3 245 * 246 * @returns SOC_E_BUSY 247 * @returns SOC_E_NONE 248 * 249 * @end 250 */ 251 STATIC int 252 _cmicx_sbusdma_ch_get(int unit, int *cmc, int *ch) 253 { 254 int rv = SOC_E_BUSY; 255 int i; 256 uint8 mask = 0; 257 258 /* 259 By Default all resources in CMC1 are reserved for embedded apps, i.e R5 apps, 260 only CMC0 is avaiable for use. 261 Return error in case channel allocation failure 262 */ 263 if (sal_sem_take(_cmicx_sbusdma_ch.sem[unit], 264 _cmicx_sbusdma_ch.timeout) < 0) { 265 return rv; 266 } 267 268 sal_spinlock_lock(_cmicx_sbusdma_ch.lock[unit]); 269 /* Allocate CMC*/ 270 if (soc_cm_get_bus_type(unit) & SOC_PCI_DEV_TYPE) { 271 *cmc = CMIC_CMCx_PCI; 272 mask = CMIC_CMC0_SBUSDMA_CH_MASK; 273 if (_cmicx_sbusdma_ch.ch[unit][*cmc] == 0) { 274 /* Check if CMIC_CMCx_AXI is configured */ 275 if (SOC_PCI_CMCS_NUM(unit) > 1) { 276 *cmc = CMIC_CMCx_AXI; 277 mask = CMIC_CMC1_SBUSDMA_CH_MASK; 278 } 279 } 280 } else { 281 *cmc = CMIC_CMCx_AXI; 282 mask = CMIC_CMC1_SBUSDMA_CH_MASK; 283 if (_cmicx_sbusdma_ch.ch[unit][*cmc] == 0) { 284 /* Check if CMIC_CMCx_AXI is configured */ 285 if (SOC_PCI_CMCS_NUM(unit) > 1) { 286 *cmc = CMIC_CMCx_PCI; 287 mask = CMIC_CMC0_SBUSDMA_CH_MASK; 288 } 289 } 290 } 291 /* Allocate Channel */ 292 for (i = 0; i < CMIC_CMCx_SBUSDMA_CHAN_MAX; i++) { 293 if ((mask & 0x01 << i) && 294 (_cmicx_sbusdma_ch.ch[unit][*cmc] & 0x01 << i)) { 295 rv = SOC_E_NONE; 296 *ch = i; 297 _cmicx_sbusdma_ch.ch[unit][*cmc] &= ~(0x01 << i); 298 break; 299 } 300 } 301 sal_spinlock_unlock(_cmicx_sbusdma_ch.lock[unit]); 302 return rv; 303 } 304 305 /******************************************* 306 * @function cmicx_sbusdma_ch_try_get 307 * purpose try to get channel on cmc 308 * 309 * @param unit [in] unit # 310 * @param cmc [out] cmc number 0-1 311 * @param ch [out] channel number 0-3 312 * 313 * @returns SOC_E_BUSY 314 * @returns SOC_E_NONE 315 * 316 * @end 317 */ 318 int cmicx_sbusdma_ch_try_get(int unit, int cmc, int ch) 319 { 320 int rv = SOC_E_BUSY; 321 soc_timeout_t to; 322 soc_timeout_init(&to, _cmicx_sbusdma_ch.timeout, 100); 323 324 /* Try to allocate specified Channel from specified CMC */ 325 do { 326 sal_spinlock_lock(_cmicx_sbusdma_ch.lock[unit]); 327 if (_cmicx_sbusdma_ch.ch[unit][cmc] & (0x01 << ch)) { 328 rv = SOC_E_NONE; 329 _cmicx_sbusdma_ch.ch[unit][cmc] &= ~(0x01 << ch); 330 sal_spinlock_unlock(_cmicx_sbusdma_ch.lock[unit]); 331 break; 332 } 333 sal_spinlock_unlock(_cmicx_sbusdma_ch.lock[unit]); 334 } while (!soc_timeout_check(&to)); 335 /* Channel consumed */ 336 if (rv == SOC_E_NONE) { 337 (void)sal_sem_take(_cmicx_sbusdma_ch.sem[unit] 338 ,_cmicx_sbusdma_ch.timeout); 339 } 340 341 return rv; 342 } 343 344 /******************************************* 345 * @function cmicx_sbusdma_ch_get 346 * purpose get idle channel on cmc 347 * 348 * @param unit [in] unit # 349 * @param cmc [out] cmc number 0-1 350 * @param ch [out] channel number 0-3 351 * 352 * @returns SOC_E_BUSY 353 * @returns SOC_E_NONE 354 * 355 * @end 356 */ 357 int cmicx_sbusdma_ch_get(int unit, int *cmc, int *ch) 358 { 359 int rv; 360 361 if ((soc_cm_get_bus_type(unit) & SOC_PCI_DEV_TYPE) || 362 (soc_cm_get_bus_type(unit) & SOC_AXI_DEV_TYPE)) { 363 rv = _cmicx_sbusdma_ch_get(unit, cmc, ch); 364 } else { 365 rv = SOC_E_FAIL; 366 } 367 368 if (SOC_SUCCESS(rv)) { 369 /* Check if interrupt resources are initialized */ 370 if (SOC_CMC_SBUSDMA_INTR(unit, *cmc, *ch) == NULL) { 371 cmicx_sbusdma_ch_put(unit, *cmc, *ch); 372 SOC_STAT(unit)->err_sbusdma_intr_res++; 373 rv = SOC_E_FAIL; 374 } 375 } else { 376 int i; 377 /* Get the details of each channel in case of channel allocation fails */ 378 for (i = 0; i < CMIC_CMCx_SBUSDMA_CHAN_MAX; i++) { 379 cmicx_sbusdma_curr_op_details(unit, *cmc, i); 380 } 381 } 382 return rv; 383 } 384 385 386 /******************************************* 387 * @function cmicx_sbusdma_ch_put 388 * purpose put back the freed channel on cmc 389 * 390 * @param cmc [in] cmc number 0 391 * @param ch [in] channel number 0-2 392 * 393 * @returns SOC_E_PARAM 394 * @returns SOC_E_NONE 395 * 396 * @end 397 */ 398 int cmicx_sbusdma_ch_put(int unit, int cmc, int ch) 399 { 400 int rv = SOC_E_NONE; 401 402 if ((ch < 0) || (ch > CMIC_CMCx_SBUSDMA_CHAN_MAX -1)) { 403 rv = SOC_E_PARAM; 404 return rv; 405 } 406 sal_spinlock_lock(_cmicx_sbusdma_ch.lock[unit]); 407 _cmicx_sbusdma_ch.ch[unit][cmc] |= (0x01 << ch); 408 sal_spinlock_unlock(_cmicx_sbusdma_ch.lock[unit]); 409 sal_sem_give(_cmicx_sbusdma_ch.sem[unit]); 410 return rv; 411 } 412 413 /******************************************* 414 * @function cmicx_sbusdma_ch_deinit 415 * purpose API to de-Initialize sbusdma channel 416 * 417 * @param unit [in] unit 418 * 419 * @returns SOC_E_NONE 420 * @returns SOC_E_XXX 421 * 422 * @end 423 */ 424 int cmicx_sbusdma_ch_deinit(int unit) 425 426 { 427 int i; 428 429 for (i = 0; i < SOC_MAX_NUM_DEVICES; i++) { 430 if (_cmicx_sbusdma_ch.lock[i] != NULL) { 431 sal_spinlock_destroy(_cmicx_sbusdma_ch.lock[i]); 432 _cmicx_sbusdma_ch.lock[i] = NULL; 433 } 434 } 435 /* Cleanup channel semaphore */ 436 for (i = 0; i < SOC_MAX_NUM_DEVICES; i++) { 437 if (_cmicx_sbusdma_ch.sem[i] != NULL) { 438 sal_sem_destroy(_cmicx_sbusdma_ch.sem[i]); 439 _cmicx_sbusdma_ch.sem[i] = NULL; 440 } 441 } 442 443 return SOC_E_NONE; 444 } 445 446 /******************************************* 447 * @function cmicx_sbusdma_ch_init 448 * purpose API to Initialize sbusdma channel seletion mechanism 449 * 450 * @param unit [in] unit 451 * @param timeout [in] int 452 * @param cmic_ch [out] soc_sbusdma_cmic_ch_t pointer 453 * 454 * @returns SOC_E_NONE 455 * @returns SOC_E_XXX 456 * 457 * @end 458 */ 459 int cmicx_sbusdma_ch_init(int unit, int timeout, 460 soc_sbusdma_cmic_ch_t *cmic_ch) 461 462 { 463 int rv = SOC_E_NONE; 464 int i; 465 466 for (i = 0; i < SOC_MAX_NUM_DEVICES; i++) { 467 _cmicx_sbusdma_ch.lock[i] = sal_spinlock_create("sbusdma Lock"); 468 if (_cmicx_sbusdma_ch.lock[i] == NULL) { 469 return SOC_E_MEMORY; 470 } 471 } 472 /* Initialize channel semaphore */ 473 for (i = 0; i < SOC_MAX_NUM_DEVICES; i++) { 474 _cmicx_sbusdma_ch.sem[i] = 475 sal_sem_create("SBUSDMA Channel", 476 sal_sem_COUNTING, 477 CMIC_CMCx_SBUSDMA_CHAN_MAX * SOC_PCI_CMCS_NUM(unit)); 478 if (_cmicx_sbusdma_ch.sem[i] == NULL) { 479 return SOC_E_MEMORY; 480 } 481 } 482 /* Availability of channels */ 483 _cmicx_sbusdma_ch.ch[unit][0] = CMIC_CMC0_SBUSDMA_CH_MASK; 484 _cmicx_sbusdma_ch.ch[unit][1] = CMIC_CMC1_SBUSDMA_CH_MASK; 485 _cmicx_sbusdma_ch.timeout = timeout; 486 cmic_ch->soc_sbusdma_ch_try_get = cmicx_sbusdma_ch_try_get; 487 cmic_ch->soc_sbusdma_ch_put = cmicx_sbusdma_ch_put; 488 return rv; 489 490 } 491 492 /******************************************* 493 * @function cmicx_sbusdma_ch_endian_set 494 * set the endianess value 495 * 496 * @param cmc [in] cmc number 497 * @param ch [in] channel number 498 * @param ch [in] big_endian 499 * 500 * @returns SOC_E_PARAM 501 * @returns SOC_E_NONE 502 * 503 * @end 504 */ 505 extern int 506 cmicx_sbusdma_ch_endian_set(int unit, int cmc, int ch, int be) 507 { 508 uint32 val; 509 510 if ( ((be != 0) && (be != 1)) || 511 (ch >= SOC_SBUSDMA_CH_PER_CMC) ) { 512 return SOC_E_PARAM; 513 } 514 515 val = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch)); 516 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, 517 &val, DESCRIPTOR_ENDIANESSf, be); 518 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch), val); 519 520 return SOC_E_NONE; 521 } 522 523 /******************************************* 524 * @function _cmicx_sbusdma_start 525 * start the SBUSDMA 526 * 527 * @param unit [in] unit 528 * @param cmc [in] cmc 529 * @param ch [in] channel 530 * 531 * @returns SOC_E_NONE 532 * 533 * @end 534 */ 535 int 536 _cmicx_sbusdma_start(int unit, int cmc, int ch) 537 { 538 int rv = SOC_E_NONE; 539 uint32 ctrl; 540 ctrl = soc_pci_read(unit, 541 CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch)); 542 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, 543 &ctrl, STARTf, 1); 544 soc_pci_write(unit, CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch), 545 ctrl); 546 547 return rv; 548 } 549 /******************************************* 550 * @function cmicx_sbusdma_stop 551 * start the SBUSDMA 552 * 553 * @param unit [in] unit 554 * @param cmc [in] cmc 555 * @param ch [in] channel 556 * 557 * @returns SOC_E_NONE 558 * 559 * @end 560 */ 561 int 562 cmicx_sbusdma_stop(int unit, int cmc, int ch) 563 { 564 int rv = SOC_E_NONE; 565 uint32 ctrl; 566 567 ctrl = soc_pci_read(unit, 568 CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch)); 569 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl, 570 STARTf, 0); 571 soc_reg_field_set(unit, CMIC_CMC0_SBUSDMA_CH0_CONTROLr, &ctrl, 572 ABORTf, 0); 573 soc_pci_write(unit, 574 CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, ch), ctrl); 575 576 return rv; 577 } 578 579 /******************************************* 580 * @function cmicx_sbusdma_intr_wait 581 * purpose API to wait for DMA complete using interrupt mode 582 * 583 * @param unit [in] unit 584 * @param cmc [in] cmc 585 * @param ch [in] channel 586 * @param interval [in] timeout 587 * @param do_not_perform_start_operation [in] if the argument is non-zero, the operation is assumed to be already started. 588 * 589 * @returns SOC_E_NONE 590 * @returns SOC_E_XXX 591 * 592 * @end 593 */ 594 int 595 cmicx_sbusdma_intr_wait(int unit, int cmc, int ch, int timeout, uint32 do_not_perform_start_operation) 596 { 597 int rv = SOC_E_NONE; 598 int rval; 599 soc_control_t *soc = SOC_CONTROL(unit); 600 601 LOG_VERBOSE(BSL_LS_SOC_COMMON, 602 (BSL_META_U(unit, 603 "cmc = %d, ch = %d, timeout = %d\n"), 604 cmc, ch, timeout)); 605 606 soc_cmic_intr_enable(unit, INTR_SBUSDMA(cmc, ch)); 607 608 if (do_not_perform_start_operation == 0 ) { 609 _cmicx_sbusdma_start(unit, cmc, ch); 610 } 611 _cmicx_sbusdma_ch.wait[unit][cmc] |= (0x01 << ch); 612 613 if (sal_sem_take(soc->sbusDmaIntrs[cmc][ch], timeout) < 0) { 614 rv = SOC_E_TIMEOUT; 615 LOG_VERBOSE(BSL_LS_SOC_COMMON, 616 (BSL_META_U(unit, "Interrupt Timeout\n"))); 617 } 618 _cmicx_sbusdma_ch.wait[unit][cmc] &= ~(0x01 << ch); 619 soc_cmic_intr_disable(unit, INTR_SBUSDMA(cmc, ch)); 620 621 rval = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch)); 622 /* Check if DMA is DONE */ 623 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 624 rval, DONEf)) { 625 rv = SOC_E_NONE; 626 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 627 rval, ERRORf)) { 628 rv = SOC_E_FAIL; 629 } 630 } 631 if (rv != SOC_E_NONE) { 632 cmicx_sbusdma_curr_op_details(unit, cmc, ch); 633 soc_event_generate(unit, SOC_SWITCH_EVENT_IO_ERROR, cmc, ch, 0); 634 } 635 636 return rv; 637 } 638 639 640 /******************************************* 641 * @function cmicx_sbusdma_poll_wait 642 * purpose API to wait Descriptor using Polling mode 643 * 644 * @param unit [in] unit 645 * @param cmc [in] cmc 646 * @param ch [in] channel 647 * @param interval [in] timeout 648 * @param do_not_perform_start_operation [in] if the argument is non-zero, the operation is assumed to be already started. 649 * 650 * @returns SOC_E_NONE 651 * @returns SOC_E_XXX 652 * 653 * @end 654 */ 655 int 656 cmicx_sbusdma_poll_wait(int unit, int cmc, int ch, int timeout, uint32 do_not_perform_start_operation) 657 { 658 soc_timeout_t to; 659 int rv = SOC_E_TIMEOUT; 660 int rval; 661 662 if (do_not_perform_start_operation == 0 ) { 663 _cmicx_sbusdma_start(unit, cmc, ch); 664 } 665 _cmicx_sbusdma_ch.wait[unit][cmc] |= (0x01 << ch); 666 soc_timeout_init(&to, timeout, 0); 667 668 do { 669 rval = soc_pci_read(unit, 670 CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, ch)); 671 LOG_VERBOSE(BSL_LS_SOC_COMMON, 672 (BSL_META_U(unit, 673 "cmc = %d, ch = %d, rval = %x\n"), 674 cmc, ch, rval)); 675 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 676 rval, DONEf)) { 677 rv = SOC_E_NONE; 678 if (soc_reg_field_get(unit, CMIC_CMC0_SBUSDMA_CH0_STATUSr, 679 rval, ERRORf)) { 680 rv = SOC_E_FAIL; 681 } 682 break; 683 } 684 } while(!(soc_timeout_check(&to))); 685 686 _cmicx_sbusdma_ch.wait[unit][cmc] &= ~(0x01 << ch); 687 if (rv != SOC_E_NONE) { 688 cmicx_sbusdma_curr_op_details(unit, cmc, ch); 689 soc_event_generate(unit, SOC_SWITCH_EVENT_IO_ERROR, cmc, ch, 0); 690 } 691 692 return rv; 693 694 } 695 696 697 /******************************************* 698 * @function cmicx_sbusdma_desc_done 699 * Interrupt handler for descriptor done 700 * 701 * @param unit [in] unit 702 * @param data [in] pointer provided during registration 703 * 704 * 705 * @end 706 */ 707 708 STATIC void 709 cmicx_sbusdma_ch_done(int unit, void *data) 710 { 711 soc_control_t *soc = SOC_CONTROL(unit); 712 intr_data_t *in_d = (intr_data_t *)data; 713 714 if ((soc->sbusDmaIntrEnb) || (soc->tslamDmaIntrEnb) || 715 (soc->tableDmaIntrEnb)) { 716 if (_cmicx_sbusdma_ch.wait[unit][in_d->cmc] & 0x01 << in_d->ch) { 717 sal_sem_give(soc->sbusDmaIntrs[in_d->cmc][in_d->ch]); 718 } 719 } 720 } 721 722 /******************************************* 723 * @function cmicx_sbusdma_vchan_to_cmc_ch 724 * API takes vchan as input and return cmc and channel 725 * 726 * @param unit [in] int 727 * @param vchan [in] virtual channel 728 * @param cmc [out] cmc associated 729 * @param channel [out] channel associated 730 * 731 * @returns SOC_E_NONE 732 * @returns SOC_E_XXX 733 * 734 * @end 735 */ 736 int 737 cmicx_sbusdma_vchan_to_cmc_ch(int unit, int vchan, 738 int *cmc, int *ch) 739 { 740 if (vchan < 0 || 741 vchan >= SOC_PCI_CMCS_NUM(unit) * CMIC_CMCx_SBUSDMA_CHAN_MAX) { 742 return SOC_E_PARAM; 743 } 744 *cmc = vchan / CMIC_CMCx_SBUSDMA_CHAN_MAX; 745 *ch = vchan % CMIC_CMCx_SBUSDMA_CHAN_MAX; 746 747 return SOC_E_NONE; 748 } 749 750 /******************************************* 751 * @function cmicx_sbusdma_intr_init 752 * purpose API to Initialize SBUSDMA interrupts 753 * 754 * @param unit [in] unit 755 * 756 * @returns SOC_E_NONE 757 * @returns SOC_E_XXX 758 * 759 * @end 760 */ 761 extern int 762 cmicx_sbusdma_intr_init(int unit) 763 { 764 int cmc, ch; 765 soc_cmic_intr_handler_t *handle; 766 soc_cmic_intr_handler_t *hitr; 767 int rv; 768 769 /* Register the descriptor interrupts */ 770 handle = sal_alloc(sizeof(soc_cmic_intr_handler_t)*CMIC_CMC_NUM_MAX* 771 CMIC_CMCx_SBUSDMA_CHAN_MAX, "sbusdma_interrupt"); 772 if (handle == NULL) { 773 return SOC_E_MEMORY; 774 } 775 hitr = handle; 776 for (cmc = 0; cmc < CMIC_CMC_NUM_MAX; cmc++) { 777 for (ch = 0; ch < CMIC_CMCx_SBUSDMA_CHAN_MAX; ch++) { 778 _intr_data[cmc][ch].cmc = cmc; 779 _intr_data[cmc][ch].ch = ch; 780 hitr->num = INTR_SBUSDMA(cmc, ch); 781 hitr->intr_fn = cmicx_sbusdma_ch_done; 782 hitr->intr_data = &_intr_data[cmc][ch]; 783 hitr++; 784 } 785 } 786 rv = soc_cmic_intr_register(unit, handle, 787 CMIC_CMC_NUM_MAX*CMIC_CMCx_SBUSDMA_CHAN_MAX); 788 sal_free(handle); 789 790 return rv; 791 } 792 793 794 #endif