cmicx_misc.c (25635B)
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 * CMICx miscllaneous functions 8 */ 9 10 #include <shared/bsl.h> 11 #include <sal/core/libc.h> 12 #include <sal/core/boot.h> 13 #include <soc/debug.h> 14 #include <soc/cm.h> 15 #include <soc/drv.h> 16 #include <soc/error.h> 17 #include <sal/core/sync.h> 18 #include <soc/util.h> 19 #include <soc/cmic.h> 20 21 #ifdef BCM_CMICX_SUPPORT 22 #include <soc/cmicx.h> 23 #include <soc/iproc.h> 24 #endif 25 26 /* PCIe capabilities */ 27 #ifndef PCI_CAPABILITY_LIST 28 #define PCI_CAPABILITY_LIST 0x34 29 #endif 30 #ifndef PCI_CAP_ID_EXP 31 #define PCI_CAP_ID_EXP 0x10 32 #endif 33 #ifndef PCI_EXP_DEVCAP 34 #define PCI_EXP_DEVCAP 4 35 #endif 36 #ifndef PCI_EXP_DEVCTL 37 #define PCI_EXP_DEVCTL 8 38 #endif 39 #ifndef PCI_EXT_CAP_START 40 #define PCI_EXT_CAP_START 0x100 41 #endif 42 #ifndef PCI_EXT_CAP_ID 43 #define PCI_EXT_CAP_ID(_hdr) (_hdr & 0x0000ffff) 44 #endif 45 #ifndef PCI_EXT_CAP_VER 46 #define PCI_EXT_CAP_VER(_hdr) ((_hdr >> 16) & 0xf) 47 #endif 48 #ifndef PCI_EXT_CAP_NEXT 49 #define PCI_EXT_CAP_NEXT(_hdr) ((_hdr >> 20) & 0xffc) 50 #endif 51 #ifndef PCI_EXT_CAP_ID_VNDR 52 #define PCI_EXT_CAP_ID_VNDR 0x0b 53 #endif 54 55 56 #ifdef BCM_CMICX_SUPPORT 57 /************************************************** 58 * @function soc_is_cmicx(unit) 59 * purpose API to test if soc has cmicx 60 * 61 * @param unit [in] unit 62 * 63 * @returns SOC_E_NONE 64 * @returns SOC_E_XXX 65 * 66 * @end 67 */ 68 int soc_is_cmicx(int unit) 69 { 70 unsigned int cap_base, rval; 71 if (SOC_IS_MONTEREY(unit)) 72 return FALSE; 73 /* Look for PCIe vendor-specific extended capability (VSEC) */ 74 cap_base = PCI_EXT_CAP_START; 75 while (cap_base) { 76 rval = soc_pci_conf_read(unit, cap_base); 77 if (rval == 0xffffffff) { 78 /* Assume PCI HW read error */ 79 return 0; 80 } 81 82 if (PCI_EXT_CAP_ID(rval) == PCI_EXT_CAP_ID_VNDR) { 83 break; 84 } 85 cap_base = PCI_EXT_CAP_NEXT(rval); 86 } 87 if (cap_base) { 88 /* 89 * VSEC layout: 90 * 91 * 0x00: PCI Express Extended Capability Header 92 * 0x04: Vendor-Specific Header 93 * 0x08: Vendor-Specific Register 1 94 * 0x0c: Vendor-Specific Register 2 95 * ... 96 * 0x24: Vendor-Specific Register 8 97 */ 98 /* Read PCIe Vendor Specific Register 1 */ 99 /* VENODR REG FORMAT 100 * [7:0] iProc Rev = 8'h0E (for P14) 101 * [11:8] CMIC BAR = 4'h1 (BAR64-1) 102 * [15:12] CMIC Version = 4'h4 103 * [19:16] CMIC Rev = 4'h1 104 * [22:20] SBUS Version = 4'h4 105 */ 106 107 rval = soc_pci_conf_read(unit, cap_base + 8); 108 109 if (((rval >> 12) & 0xf) == 0x4) { 110 return 1; 111 } 112 } 113 114 return 0; 115 116 } 117 /************************************************** 118 * @function soc_cmicx_iproc_version_get 119 * purpose API to test if soc has cmicx 120 * 121 * @param unit [in] unit 122 * @param iproc_ver [out] iproc version 123 * @param cmic_ver [out] cmic version 124 * @param cmic_rev [out] cmic revision 125 * 126 * @returns SOC_E_NONE 127 * @returns SOC_E_XXX 128 * 129 * @end 130 */ 131 int soc_cmicx_iproc_version_get(int unit, unsigned int *iproc_ver, 132 unsigned int *cmic_ver, 133 unsigned int *cmic_rev) 134 { 135 unsigned int cap_base, rval; 136 if (SOC_IS_MONTEREY(unit)) 137 return FALSE; 138 /* Look for PCIe vendor-specific extended capability (VSEC) */ 139 cap_base = PCI_EXT_CAP_START; 140 while (cap_base) { 141 rval = soc_pci_conf_read(unit, cap_base); 142 if (rval == 0xffffffff) { 143 /* Assume PCI HW read error */ 144 return 0; 145 } 146 147 if (PCI_EXT_CAP_ID(rval) == PCI_EXT_CAP_ID_VNDR) { 148 break; 149 } 150 cap_base = PCI_EXT_CAP_NEXT(rval); 151 } 152 if (cap_base) { 153 /* 154 * VSEC layout: 155 * 156 * 0x00: PCI Express Extended Capability Header 157 * 0x04: Vendor-Specific Header 158 * 0x08: Vendor-Specific Register 1 159 * 0x0c: Vendor-Specific Register 2 160 * ... 161 * 0x24: Vendor-Specific Register 8 162 */ 163 /* Read PCIe Vendor Specific Register 1 */ 164 /* VENODR REG FORMAT 165 * [7:0] iProc Rev = 8'h0E (for P14) 166 * [11:8] CMIC BAR = 4'h1 (BAR64-1) 167 * [15:12] CMIC Version = 4'h4 168 * [19:16] CMIC Rev = 4'h1 169 * [22:20] SBUS Version = 4'h4 170 */ 171 172 rval = soc_pci_conf_read(unit, cap_base + 8); 173 174 *iproc_ver = rval & 0xff; 175 *cmic_ver = (rval >> 12) & 0xf; 176 *cmic_rev = (rval >> 16) & 0xf; 177 return 1; 178 } 179 180 return 0; 181 182 } 183 184 /************************************************** 185 * @function soc_cmicx_pci_test 186 * purpose API to test PCI access to cmicx registers 187 * 188 * @param unit [in] unit 189 * 190 * @returns SOC_E_NONE 191 * @returns SOC_E_XXX 192 * 193 * @end 194 */ 195 int soc_cmicx_pci_test(int unit) 196 { 197 int i; 198 uint32 tmp, reread; 199 uint32 pat; 200 201 SCHAN_LOCK(unit); 202 203 /* Check for address uniqueness */ 204 205 for (i = 0; i < CMIC_SCHAN_WORDS(unit); i++) { 206 pat = 0x55555555 ^ (i << 24 | i << 16 | i << 8 | i); 207 soc_pci_write(unit, CMIC_COMMON_POOL_SCHAN_CHx_MESSAGEn(0, i), pat); 208 } 209 210 for (i = 0; i < CMIC_SCHAN_WORDS(unit); i++) { 211 pat = 0x55555555 ^ (i << 24 | i << 16 | i << 8 | i); 212 tmp = soc_pci_read(unit, CMIC_COMMON_POOL_SCHAN_CHx_MESSAGEn(0, i)); 213 if (tmp != pat) { 214 goto error; 215 } 216 } 217 218 if (!SAL_BOOT_QUICKTURN) { /* Takes too long */ 219 /* Rotate walking zero/one pattern through each register */ 220 221 pat = 0xff7f0080; /* Simultaneous walking 0 and 1 */ 222 223 for (i = 0; i < CMIC_SCHAN_WORDS(unit); i++) { 224 int j; 225 226 for (j = 0; j < 32; j++) { 227 soc_pci_write(unit, CMIC_COMMON_POOL_SCHAN_CHx_MESSAGEn(0, i), pat); 228 tmp = soc_pci_read(unit, CMIC_COMMON_POOL_SCHAN_CHx_MESSAGEn(0, i)); 229 if (tmp != pat) { 230 goto error; 231 } 232 pat = (pat << 1) | ((pat >> 31) & 1); /* Rotate left */ 233 } 234 } 235 } 236 237 /* Clear to zeroes when done */ 238 239 for (i = 0; i < CMIC_SCHAN_WORDS(unit); i++) { 240 soc_pci_write(unit, CMIC_COMMON_POOL_SCHAN_CHx_MESSAGEn(0, i), 0); 241 } 242 SCHAN_UNLOCK(unit); 243 return SOC_E_NONE; 244 245 error: 246 reread = soc_pci_read(unit, CMIC_COMMON_POOL_SCHAN_CHx_MESSAGEn(0, i)); 247 248 LOG_ERROR(BSL_LS_SOC_COMMON, 249 (BSL_META_U(unit, 250 "FATAL PCI error testing PCIM[0x%x]:\n" 251 "Wrote 0x%x, read 0x%x, re-read 0x%x\n"), 252 i, pat, tmp, reread)); 253 254 SCHAN_UNLOCK(unit); 255 return SOC_E_INTERNAL; 256 } 257 258 /************************************************** 259 * @function soc_cmicx_paxb_tx_arbiter_set 260 * purpose: API to set tx arbiter 261 * 262 * @param unit [in] unit 263 * @param unit [in] enable 264 * @param unit [in] priority 265 * 266 * @returns SOC_E_NONE 267 * @returns SOC_E_XXX 268 * 269 * @end 270 */ 271 int soc_cmicx_paxb_tx_arbiter_set(int unit, uint8 enable, uint8 priority) 272 { 273 uint32 cmic_reg_val = 0; 274 275 if (SOC_IS_TRIDENT3X(unit)) { 276 soc_reg_field_set(unit, PAXB_0_PAXB_TX_ARBITER_PRIORITYr, &cmic_reg_val, 277 TX_REQ_SEQ_ENf, enable); 278 soc_reg_field_set(unit, PAXB_0_PAXB_TX_ARBITER_PRIORITYr, &cmic_reg_val, 279 TX_ARB_PRIORITYf, priority); 280 SOC_IF_ERROR_RETURN(WRITE_PAXB_0_PAXB_TX_ARBITER_PRIORITYr(unit, cmic_reg_val)); 281 } 282 283 return SOC_E_NONE; 284 } 285 286 /************************************************** 287 * @function soc_cmicx_reg_offset_get 288 * purpose: API to get min and max offsets for cmicx reg 289 * 290 * @param unit [out] min 291 * @param unit [out] max 292 * 293 * @returns none 294 * 295 * @end 296 */ 297 298 void soc_cmicx_reg_offset_get(uint32 *min, uint32 *max) 299 { 300 *min = CMICX_OFFSET_MIN; 301 *max = CMICX_OFFSET_MAX; 302 303 return; 304 } 305 306 /* store the cmc and IF of a DMA channel */ 307 typedef struct { 308 uint8 channel_cmc; 309 uint8 channel_id; 310 } channel_ids_t; 311 312 /* 313 * structure/object storing channel_ids_ts that can be added, and then iterated, 314 * while the current channel_ids_t can be removed during iteration. 315 * All functions have O(1) runtime. 316 * Does not preserve the order of the channels. 317 */ 318 #define CHANS_GROUP_MAX_SIZE (CMIC_CMC_NUM_MAX * CMICX_N_DMA_CHAN) 319 typedef struct { 320 unsigned nof_chans; 321 channel_ids_t channels[CHANS_GROUP_MAX_SIZE]; 322 } chans_group_t; 323 typedef channel_ids_t *chans_group_iter_t; 324 /* init object to be empty */ 325 STATIC INLINE void chans_group_init(chans_group_t *group) { 326 group->nof_chans = 0; 327 } 328 /* init the itertor to the start of the group */ 329 STATIC INLINE void chans_group_iter_start(chans_group_t *group, chans_group_iter_t *iter) { 330 *iter = group->channels; 331 } 332 /* is iterator pointing to beyond the end of the group */ 333 STATIC INLINE int chans_group_is_end(chans_group_t *group, chans_group_iter_t iter) { 334 return iter >= group->channels + group->nof_chans; 335 } 336 /* return the size (number of channels) of the group */ 337 STATIC INLINE unsigned chans_group_get_nof_chans(chans_group_t *group) { 338 return group->nof_chans; 339 } 340 /* Insert a channel to the group */ 341 STATIC INLINE void chans_group_insert(chans_group_t *group, int cmc, int chan) { 342 chans_group_iter_t i = group->channels + group->nof_chans; 343 assert(group->nof_chans < CHANS_GROUP_MAX_SIZE); 344 i->channel_cmc = cmc; 345 i->channel_id = chan; 346 ++group->nof_chans; 347 } 348 /* 349 * Remove the channel pointed to by the iterator from the group, 350 * the iterator will point to a channel not yet traversed, 351 * or point past the end of the group if all channels were traversed 352 */ 353 STATIC INLINE void chans_group_delete(chans_group_t *group, chans_group_iter_t iter) { 354 assert(group->nof_chans > 0); 355 *iter = group->channels[--group->nof_chans]; 356 } 357 /* get the cahnnel pointed to by the iterator */ 358 STATIC INLINE void chans_group_iter_t_get(chans_group_iter_t channel_iter, int *cmc, int *chan) { 359 *cmc = channel_iter->channel_cmc; 360 *chan = channel_iter->channel_id; 361 } 362 363 typedef enum { /* possible states of the timeout used by cmicx_dma_abort() */ 364 abort_timeout_not_initialized, 365 abort_timeout_not_passed, 366 abort_timeout_passed 367 } abort_timeout_state_t; 368 369 /* The timeout needs to be at least 50ms which is the PCIe completion timeout value */ 370 #define MIN_CMICX_DMA_ABORT_TIMEOUT 50000 371 #define DEFAULT_CMICX_DMA_ABORT_TIMEOUT (MIN_CMICX_DMA_ABORT_TIMEOUT * 6 / 5) 372 #define CMICX_INITIAL_SLEEP 10000 373 374 /* 375 * Function: 376 * cmicx_dma_abort 377 * Purpose: 378 * Deconfigure previously defined DMA operations and abort pending operation. 379 * Useful in case SDK was not de-initialized / not brought down properly, 380 * and when not resetting on startup; like in an unscheduled warm boot. 381 * Most important for DMA operations initiated by the device operating on 382 * external CPU memory, like FIFO and packet DMA. 383 * Also handles operations that did not complete. 384 * Parameters: 385 * unit - SOC unit # 386 * flags - flags specifying not to handle some DMA types 387 * Returns: 388 * SOC_E_NONE - success 389 * SOC_E_XXXX - error code 390 * Notes: 391 */ 392 int 393 soc_cmicx_dma_abort(int unit, uint32 flags) 394 { 395 int cmc, chan, nof_channels, nof_failures = 0; 396 int cmc_num_max = CMIC_CMC_NUM_MAX; 397 uint32 val, cmic_address, done; 398 399 sal_usecs_t start_time = 0, iter_time, timeout, timeout_sleep = CMICX_INITIAL_SLEEP; 400 abort_timeout_state_t timeout_state = abort_timeout_not_initialized; 401 chans_group_iter_t channel_iter; 402 chans_group_t packet_channels, sbus_channels, fifo_channels, ccm_channels, schan_fifo_channels; 403 404 LOG_VERBOSE(BSL_LS_SOC_DMA, (BSL_META_U(unit, "aborting and disabling DMA\n"))); 405 406 /* Abort all DMA types */ 407 /* Use flag SOC_DMA_ABORT_CMC0 in case other CMC's are used by the internal Arm CPUs */ 408 409 if (flags & SOC_DMA_ABORT_CMC0) { 410 cmc_num_max = 1; 411 } 412 413 timeout = soc_property_get(unit, spn_DMA_ABORT_TIMEOUT_USEC, DEFAULT_CMICX_DMA_ABORT_TIMEOUT); 414 if (timeout < MIN_CMICX_DMA_ABORT_TIMEOUT) { 415 timeout = MIN_CMICX_DMA_ABORT_TIMEOUT; 416 } 417 418 /* abort packet DMA in all channels */ 419 chans_group_init(&packet_channels); 420 if ((flags & SOC_DMA_ABORT_SKIP_PACKET) == 0) { 421 for (cmc = 0; cmc < cmc_num_max; ++cmc) { 422 for (chan = 0; chan < CMIC_CMCx_PKTDMA_NOF_CHANS; ++chan) { 423 cmic_address = CMIC_CMCx_PKTDMA_CHy_CTRL_OFFSET(cmc, chan); 424 /* if CMIC_CMCx_PKTDMA_CHy_CTRL.DMA_EN == 1 */ 425 val = soc_pci_read(unit, cmic_address); 426 if (val & PKTDMA_ENABLE) { 427 /* set CMIC_CMCx_PKTDMA_CHy_CTRL.ABORT_DMA=1 to abort, and later wait for CMIC_CMCx_SHARED_IRQ_STAT0.CHy_CHAIN_DONE==1 */ 428 soc_pci_write(unit, cmic_address, val | PKTDMA_ABORT); 429 chans_group_insert(&packet_channels, cmc, chan); /* mark the channel to be waited on */ 430 LOG_DEBUG(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Aborting packet DMA CMC %d channel %d\n"), cmc, chan)); 431 } 432 } 433 } 434 } 435 436 /* abort s-bus DMA in all channels */ 437 chans_group_init(&sbus_channels); 438 if ((flags & SOC_DMA_ABORT_SKIP_SBUS) == 0) { 439 /* For CMCs x=0-1 and channels y=0-3 and [channel used by this CPU] */ 440 for (cmc = 0; cmc < cmc_num_max; ++cmc) { 441 for (chan = 0; chan < CMIC_CMCx_SBUSDMA_CHAN_MAX; ++chan) { 442 cmic_address = CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, chan); 443 /* if CMIC_CMCx_SBUSDMA_CHy_CONTROL.START == 1 */ 444 val = soc_pci_read(unit, cmic_address); 445 if (val & CMIC_CMCx_SBUSDMA_CHy_CONTROL_START) { 446 /* set CMIC_CMCx_SBUSDMA_CHy_CONTROL.ABORT=1 to abort */ 447 soc_pci_write(unit, cmic_address, val | CMIC_CMCx_SBUSDMA_CHy_CONTROL_ABORT); 448 chans_group_insert(&sbus_channels, cmc, chan); /* mark the channel to be waited on */ 449 LOG_DEBUG(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Aborting s-bus DMA CMC %d channel %d\n"), cmc, chan)); 450 } 451 } 452 } 453 } 454 455 /* abort FIFO DMA in all channels, FIFO DMA is not per CMC */ 456 chans_group_init(&fifo_channels); 457 if ((flags & SOC_DMA_ABORT_SKIP_FIFO) == 0) { 458 for (chan = 0; chan < CMICX_N_FIFODMA_CHAN; ++chan) { 459 cmic_address = CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG_OFFSET(chan); 460 /* if CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG.ENABLE == 1 */ 461 val = soc_pci_read(unit, cmic_address); 462 if (val & CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG_ENABLE) { 463 /* set CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG.ABORT=1 to abort */ 464 soc_pci_write(unit, cmic_address, val | CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG_ABORT); 465 chans_group_insert(&fifo_channels, 0, chan); /* mark the channel to be waited on */ 466 LOG_DEBUG(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Aborting FIFO DMA channel %d\n"), chan)); 467 } 468 } 469 } 470 471 /* abort CCM DMA in all channels */ 472 chans_group_init(&ccm_channels); 473 if ((flags & SOC_DMA_ABORT_SKIP_CCM) == 0) { 474 /* For CMCs x=0-1 and channels y=0-1 and [channel used by this CPU] */ 475 for (cmc = 0; cmc < cmc_num_max; ++cmc) { 476 for (chan = 0; chan < CMICX_N_CCMDMA_CHAN; ++chan) { 477 cmic_address = CMIC_CMCx_CCMDMA_CHy_CFG_OFFSET(cmc, chan); 478 /* if CMIC_CMCx_CCMDMA_CHy_CFG.EN == 1 */ 479 val = soc_pci_read(unit, cmic_address); 480 if (val & CMIC_CMCx_CCMDMA_CHy_CFG_EN) { 481 /* set CMIC_CMCx_CCMDMA_CHy_CFG.ABORT=1 to abort */ 482 soc_pci_write(unit, cmic_address, val | CMIC_CMCx_CCMDMA_CHy_CFG_ABORT); 483 chans_group_insert(&ccm_channels, cmc, chan); /* mark the channel to be waited on */ 484 LOG_DEBUG(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Aborting CCM DMA CMC %d channel %d\n"), cmc, chan)); 485 } 486 } 487 } 488 } 489 490 /* abort s-chan FIFO in all channels, s-chan FIFO is not per CMC */ 491 chans_group_init(&schan_fifo_channels); 492 if ((flags & SOC_DMA_ABORT_SKIP_SCHAN_FIFO) == 0) { 493 /* For channels y=0-1 and [channels used by this CPU] */ 494 for (chan = 0; chan < CMIC_SCHAN_FIFO_NUM_MAX; ++chan) { 495 cmic_address = CMIC_SCHAN_FIFO_CHx_CTRL(chan); 496 /* if CMIC_COMMON_POOL_SCHAN_FIFO_0_CHy_CTRL.START == 1 */ 497 val = soc_pci_read(unit, cmic_address); 498 if (val & SCHAN_FIFO_CTRL_START) { 499 /* set CMIC_COMMON_POOL_SCHAN_FIFO_0_CHy_CTRL.ABORT=1 to abort */ 500 soc_pci_write(unit, cmic_address, val | SCHAN_FIFO_CTRL_ABORT); 501 chans_group_insert(&schan_fifo_channels, 0, chan); /* mark the channel to be waited on */ 502 LOG_DEBUG(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Aborting s-chan FIFO channel %d\n"), chan)); 503 } 504 } 505 } 506 507 nof_channels = chans_group_get_nof_chans(&packet_channels) + chans_group_get_nof_chans(&sbus_channels) + 508 chans_group_get_nof_chans(&fifo_channels) + chans_group_get_nof_chans(&ccm_channels) + chans_group_get_nof_chans(&schan_fifo_channels); 509 510 /* loop and check that each abort finished. When it finished or after time out, clear the operation and disable the DMA */ 511 do { 512 /* measure time at the start of the iteration */ 513 iter_time = sal_time_usecs(); 514 if (timeout_state == abort_timeout_not_initialized) { 515 timeout_state = abort_timeout_not_passed; 516 start_time = iter_time; 517 } 518 if (iter_time - start_time >= timeout ) { /* was the timeout value reached? */ 519 timeout_state = abort_timeout_passed; 520 } 521 522 523 /* for all packet DMA channels still not done */ 524 for (chans_group_iter_start(&packet_channels, &channel_iter); !chans_group_is_end(&packet_channels, channel_iter); ++channel_iter) { 525 chans_group_iter_t_get(channel_iter, &cmc, &chan); /* get the channel to work on */ 526 /* If the abort is done (CMIC_CMCx_SHARED_IRQ_STAT0.CHy_CHAIN_DONE==1), disable packet DMA */ 527 done = soc_pci_read(unit, CMIC_CMCx_SHARED_IRQ_STAT0_OFFSET(cmc)) & DS_CMCx_CHy_DMA_CHAIN_DONE(chan); 528 if (done || timeout_state == abort_timeout_passed) { 529 /* clear CMIC_CMCx_PKTDMA_CHy_CTRL.ABORT_DMA|DMA_EN in the same write to disable; it also clears statuses */ 530 cmic_address = CMIC_CMCx_PKTDMA_CHy_CTRL_OFFSET(cmc, chan); 531 val = soc_pci_read(unit, cmic_address); 532 soc_pci_write(unit, cmic_address, val & ~(PKTDMA_ENABLE | PKTDMA_ABORT)); 533 if (done) { /* remove the channel from the channels waited on */ 534 chans_group_delete(&packet_channels, channel_iter--); 535 } else { 536 LOG_ERROR(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Failed to abort packet DMA in CMC %d channel %d, check with the design team\n"), cmc, chan)); 537 ++nof_failures; 538 } 539 } 540 } 541 542 /* for all s-bus DMA channels still not done */ 543 for (chans_group_iter_start(&sbus_channels, &channel_iter); !chans_group_is_end(&sbus_channels, channel_iter); ++channel_iter) { 544 chans_group_iter_t_get(channel_iter, &cmc, &chan); /* get the channel to work on */ 545 /* If the abort is done (CMIC_CMCx_SBUSDMA_CHy_STAT.DONE==1), then clear the operation */ 546 done = soc_pci_read(unit, CMIC_CMCx_SBUSDMA_CHy_STATUS(cmc, chan)) & CMIC_CMCx_SBUSDMA_CHy_STATUS_DONE; 547 if (done || timeout_state == abort_timeout_passed) { 548 /* clear CMIC_CMCx_SBUSDMA_CHy_CONTROL.ABORT|START in the same write disables the original operation and abort, and clears statuses */ 549 cmic_address = CMIC_CMCx_SBUSDMA_CHy_CONTROL(cmc, chan); 550 val = soc_pci_read(unit, cmic_address); 551 soc_pci_write(unit, cmic_address, val & ~(CMIC_CMCx_SBUSDMA_CHy_CONTROL_ABORT |CMIC_CMCx_SBUSDMA_CHy_CONTROL_START )); 552 if (done) { /* remove the channel from the channels waited on */ 553 chans_group_delete(&sbus_channels, channel_iter--); 554 } else { 555 LOG_ERROR(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Failed to abort s-bus DMA in CMC %d channel %d, check with the design team\n"), cmc, chan)); 556 ++nof_failures; 557 } 558 } 559 } 560 561 /* for all FIFO DMA channels still not done */ 562 for (chans_group_iter_start(&fifo_channels, &channel_iter); !chans_group_is_end(&fifo_channels, channel_iter); ++channel_iter) { 563 chans_group_iter_t_get(channel_iter, &cmc, &chan); /* get the channel to work on */ 564 /* If the abort is done (CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_STAT.ABORTED==1), then clear the operation and disable */ 565 done = soc_pci_read(unit, CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_STAT_OFFSET(chan)) & CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_STAT_ABORTED; 566 if (done || timeout_state == abort_timeout_passed) { 567 /* clear CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG.ABORT|ENABLE in the same write: disables and clears statuses */ 568 cmic_address = CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG_OFFSET(chan); 569 val = soc_pci_read(unit, cmic_address); 570 soc_pci_write(unit, cmic_address, val & ~(CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG_ABORT | CMIC_COMMON_POOL_FIFO_CHy_RD_DMA_CFG_ENABLE)); 571 if (done) { /* remove the channel from the channels waited on */ 572 chans_group_delete(&fifo_channels, channel_iter--); 573 } else { 574 LOG_ERROR(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Failed to abort FIFO DMA in channel %d, check with the design team\n"), chan)); 575 ++nof_failures; 576 } 577 } 578 } 579 580 /* for all CCM DMA channels still not done */ 581 for (chans_group_iter_start(&ccm_channels, &channel_iter); !chans_group_is_end(&ccm_channels, channel_iter); ++channel_iter) { 582 chans_group_iter_t_get(channel_iter, &cmc, &chan); /* get the channel to work on */ 583 /* If the abort is done (CMIC_CMCx_CCMDMA_CHy_STAT.DONE==1), then clear the operation */ 584 done = soc_pci_read(unit, CMIC_CMCx_CCMDMA_CHy_STAT_OFFSET(cmc, chan)) & CMIC_CMCx_CCMDMA_CHy_STAT_DONE; 585 if (done || timeout_state == abort_timeout_passed) { 586 /* clear CMIC_CMCx_CCMDMA_CHy_CFG.ABORT|EN in the same write: disables and clears statuses */ 587 cmic_address = CMIC_CMCx_CCMDMA_CHy_CFG_OFFSET(cmc, chan); 588 val = soc_pci_read(unit, cmic_address); 589 soc_pci_write(unit, cmic_address, val & ~(CMIC_CMCx_CCMDMA_CHy_CFG_ABORT | CMIC_CMCx_CCMDMA_CHy_CFG_EN)); 590 if (done) { /* remove the channel from the channels waited on */ 591 chans_group_delete(&ccm_channels, channel_iter--); 592 } else { 593 LOG_ERROR(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Failed to abort CCM DMA in CMC %d channel %d, check with the design team\n"), cmc, chan)); 594 ++nof_failures; 595 } 596 } 597 } 598 599 /* for all s-chan FIFO channels still not done */ 600 for (chans_group_iter_start(&schan_fifo_channels, &channel_iter); !chans_group_is_end(&schan_fifo_channels, channel_iter); ++channel_iter) { 601 chans_group_iter_t_get(channel_iter, &cmc, &chan); /* get the channel to work on */ 602 /* If the abort is done (CMIC_COMMON_POOL_SCHAN_FIFO_0_CHy_STATUS.DONE==1), then clear the operation */ 603 done = soc_pci_read(unit, CMIC_SCHAN_FIFO_CHx_STATUS(chan)) & SCHAN_FIFO_STATUS_DONE; 604 if (done || timeout_state == abort_timeout_passed) { 605 /* clear CMIC_COMMON_POOL_SCHAN_FIFO_0_CHy_CTRL.ABORT|START in the same write: disables and clears statuses*/ 606 cmic_address = CMIC_SCHAN_FIFO_CHx_CTRL(chan); 607 val = soc_pci_read(unit, cmic_address); 608 soc_pci_write(unit, cmic_address, val & ~(SCHAN_FIFO_CTRL_ABORT | SCHAN_FIFO_CTRL_START)); 609 if (done) { /* remove the channel from the channels waited on */ 610 chans_group_delete(&schan_fifo_channels, channel_iter--); 611 } else { 612 LOG_ERROR(BSL_LS_SOC_DMA, (BSL_META_U(unit, "Failed to abort s-chan FIFO in channel %d, check with the design team\n"), chan)); 613 ++nof_failures; 614 } 615 } 616 } 617 618 619 if (timeout_state != abort_timeout_not_passed || (!chans_group_get_nof_chans(&packet_channels) && 620 !chans_group_get_nof_chans(&sbus_channels) && !chans_group_get_nof_chans(&fifo_channels) && 621 !chans_group_get_nof_chans(&ccm_channels) && !chans_group_get_nof_chans(&schan_fifo_channels))) { 622 break; /* exist if the timeout passed at the start of the iteration, or if there is no channel left to wait for */ 623 } 624 sal_usleep(timeout_sleep); /* wait before the next iteration */ 625 timeout_sleep += CMICX_INITIAL_SLEEP; /* next time sleep more, will use less than sqrt(2 * timeout / CMICX_INITIAL_SLEEP) iterations */ 626 } while (1); 627 628 629 LOG_INFO(BSL_LS_SOC_DMA, (BSL_META_U(unit, 630 "Aborted and disabled %d DMA channels with %d abort failures\n"), nof_channels, nof_failures)); 631 632 return nof_failures ? SOC_E_TIMEOUT : SOC_E_NONE; 633 } 634 635 #endif /* BCM_CMICX_SUPPORT */