dma.c (128495B)
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 DMA LLC (Link Layer) driver; used for sending 8 * and receiving packets over PCI (and later, the uplink). 9 * 10 * NOTE: DV chains are different than hardware chains. The hardware 11 * chain bit is used to keep DMA going through multiple packets. 12 * This corresponds to the sequence of DCBs (and usually multiple 13 * packets) of one DV. DVs are chained in a linked list in software. 14 * The dv->dv_chain member (and dv_chain parameters) implement this 15 * linked list. 16 * To improve the performance of packets receiving, we introduced the 17 * method to mitigate descriptor done interrupts. When we detect the 18 * packet storm is coming, we will disable descriptor done interrupt and 19 * simultaneously start the monitor timer which will reenable the disabled 20 * interrupt while storm is stopped. 21 * 22 * Starting with CMICDv2 devices, the DCB reload support has been 23 * improved to allow DCB chains to be appended safely without 24 * stopping the DMA channel. This feature is called Continuous 25 * DMA mode and works like this: When initially added, each DCB 26 * chain will end with a reload DCB pointing to itself. To 27 * prevent it from reloading over and over, a new CMIC DMA HALT 28 * register is programmed with the address of the reload DCB. The 29 * DMA process will suspend itself when the DCB at the HALT 30 * address is reached. When a new DCB chain is added, the 31 * previous reload DCB is updated with the address of the new DCB 32 * chain. If the DMA process has already been suspended when the 33 * new DCB chain is added, it will automatically resume when the 34 * HALT register is updated with the address of the reload DCB at 35 * the end of the new DCB chain. The major difference between 36 * reload and non-reload mode is that in reload mode, the last DCB 37 * chain cannot be discarded (freed) when processing is done because 38 * the reload DCB is needed until the next DCB chain is started. 39 */ 40 41 #include <shared/bsl.h> 42 43 #include <sal/core/boot.h> 44 #include <sal/core/libc.h> 45 46 #include <shared/alloc.h> 47 #include <shared/bsl.h> 48 49 #include <soc/drv.h> 50 #include <soc/dcb.h> 51 #include <soc/dcbformats.h> /* only for 5670 crc erratum warning */ 52 #include <soc/pbsmh.h> 53 #include <soc/higig.h> 54 #include <soc/debug.h> 55 #include <soc/cm.h> 56 #ifdef BCM_CMICM_SUPPORT 57 #include <soc/cmicm.h> 58 #endif 59 60 #ifdef INCLUDE_KNET 61 #include <soc/knet.h> 62 #endif 63 64 #ifdef BCM_CMIC_SUPPORT 65 66 #define DV_MAGIC_NUMBER 0xba5eba11 67 68 #define DMA_CHAIN_DONE_TIMEOUT_USEC (4000) 69 #define DMA_CHAIN_DONE_INTERVAL_USEC (1000) 70 71 72 #define DMA_LAST_DESC_DONE_CTN(unit, dv_chain)\ 73 ((SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) &&\ 74 (dv_chain->dv_vcnt - dv_chain->dv_dcnt == 2)) 75 76 #define DMA_LAST_DESC_DONE_NON_CTN(unit, dv_chain)\ 77 ((SOC_DMA_MODE(unit) != SOC_DMA_MODE_CONTINUOUS) &&\ 78 (dv_chain->dv_vcnt - dv_chain->dv_dcnt == 1)) 79 80 #define DMA_LAST_DESC_DONE(unit, dv_chain)\ 81 (DMA_LAST_DESC_DONE_CTN(unit, dv_chain) ||\ 82 DMA_LAST_DESC_DONE_NON_CTN(unit, dv_chain)) 83 84 typedef struct sdc_intr_mitigate_s { 85 uint32 rx_chain_intr; 86 uint32 rx_chain_intr_prev; 87 sal_usecs_t cur_tm; 88 sal_usecs_t prev_tm; 89 char sem_name[16]; 90 sal_sem_t thread_sem; 91 sal_thread_t thread_id; 92 int thread_running; 93 int mitigation_started; 94 } sdc_intr_mitigate_t; 95 96 typedef struct soc_dma_intr_mitigate_s { 97 int enabled; 98 sdc_intr_mitigate_t chans_intr_mitigation[MAX_N_DMA_CHAN * SOC_CMCS_NUM_MAX]; 99 } soc_dma_intr_mitigate_t; 100 101 static soc_dma_intr_mitigate_t soc_dma_intr_mitigation[SOC_MAX_NUM_DEVICES]; 102 103 STATIC soc_cmic_dma_drv_t cmic_drv[SOC_MAX_NUM_DEVICES]; 104 105 #if (defined(BCM_ESW_SUPPORT) || defined (BCM_PETRA_SUPPORT)) 106 extern void tx_dv_free_cb(int unit, dv_t *dv) __attribute__ ((weak)); 107 extern void rx_dv_free_cb(int unit, dv_t *dv) __attribute__ ((weak)); 108 #else 109 static void (*tx_dv_free_cb)(int unit, dv_t *dv) = NULL; 110 static void (*rx_dv_free_cb)(int unit, dv_t *dv) = NULL; 111 #endif 112 113 STATIC void 114 soc_dma_monitor_thread(void *p) 115 { 116 uint32 param = PTR_TO_INT(p); 117 int unit = param >> 16 & 0xffff; 118 int vchan = param & 0xffff; 119 sdc_intr_mitigate_t *sdc_mtg = 120 &soc_dma_intr_mitigation[unit].chans_intr_mitigation[vchan]; 121 122 while (1) { 123 if (sdc_mtg->thread_running == 0) { 124 sal_sem_destroy(sdc_mtg->thread_sem); 125 sal_memset(sdc_mtg, 0, sizeof(* sdc_mtg)); 126 break; 127 } 128 if (!sdc_mtg->mitigation_started) { 129 sal_sem_take(sdc_mtg->thread_sem, sal_sem_FOREVER); 130 continue; 131 } 132 sal_usleep(DMA_CHAIN_DONE_TIMEOUT_USEC); 133 if (sdc_mtg->rx_chain_intr != sdc_mtg->rx_chain_intr_prev) { 134 sdc_mtg->rx_chain_intr_prev = sdc_mtg->rx_chain_intr; 135 } else { 136 sdc_mtg->mitigation_started = 0; 137 /* Enable descriptor done interrupt */ 138 cmic_drv[unit].chan_desc_done_intr_enable(unit, vchan); 139 140 sdc_mtg->rx_chain_intr_prev = sdc_mtg->rx_chain_intr = 0; 141 } 142 } 143 } 144 145 /* 146 * Function: 147 * soc_dma_channel 148 * Purpose: 149 * Choose a channel to send a DMA request over. 150 * Parameters: 151 * unit - StrataSwitch Unit #. 152 * vchan - -1 --> choose any virtual channel. 153 * 0-11 --> select given channel. 154 * Returns: 155 * Pointer to soc_dma_start structure to use, NULL if failed. 156 * Notes: 157 * If no channel is specified then the default channel for that 158 * operation type is chosen. 159 */ 160 161 STATIC sdc_t * 162 soc_dma_channel(int unit, dma_chan_t vchan, dv_t *dv_chain) 163 { 164 soc_control_t *soc = SOC_CONTROL(unit); 165 sdc_t *cd; 166 167 if (vchan < 0) { /* Choose a channel */ 168 switch(dv_chain->dv_op) { 169 case DV_TX: return(soc->soc_dma_default_tx); 170 case DV_RX: return(soc->soc_dma_default_rx); 171 default: return(NULL); 172 } 173 } else if (vchan < 0 || vchan >= soc->soc_dma_channels) { 174 return NULL; 175 } else { 176 cd = &soc->soc_channels[vchan]; 177 return((cd->sc_type == dv_chain->dv_op) ? cd : NULL); 178 } 179 } 180 181 /* 182 * Function: 183 * soc_dma_start_channel 184 * 185 * Purpose: 186 * Start the next queued DMA (ignoring channel state) 187 * Parameters: 188 * unit - StrataSwitch unit # 189 * sc - pointer to channel to start operation on. 190 * Returns: 191 * nothing. 192 * Notes: 193 * Assumes SOC_DMA_LOCK held on entry (or called from interrupt 194 * handler). 195 * 196 * Sets sc_dv_active, but NOT sc_dv_q. Safe to call if 197 * no pending DMA to start, in which case sc_dv_active is set to NULL. 198 */ 199 200 STATIC void 201 soc_dma_start_channel(int unit, sdc_t *sc) 202 { 203 dv_t *dv; 204 205 if ((dv = sc->sc_dv_active = sc->sc_q) == NULL) { 206 sc->sc_q_tail = NULL; 207 return; 208 } 209 210 #ifdef INCLUDE_KNET 211 if (SOC_KNET_MODE(unit)) { 212 return; 213 } 214 #endif 215 216 LOG_DEBUG(BSL_LS_SOC_PACKETDMA, 217 (BSL_META_U(unit, 218 "Starting DMA channel: c=%d\n"), sc->sc_channel)); 219 220 cmic_drv[unit].chan_start(unit, sc); 221 } 222 223 #ifdef BCM_XGS3_SWITCH_SUPPORT 224 /* 225 * Function: 226 * soc_dma_tx_purge 227 * Purpose: 228 * Purge the partial packet from the Pipeline left from TX DMA abort. 229 * Parameters: 230 * unit - Unit on which being transmitted 231 * Returns: 232 * SOC_E_XXX 233 */ 234 int 235 soc_dma_tx_purge(int unit, dma_chan_t vchan) 236 { 237 int rv = SOC_E_NONE; 238 239 #ifdef INCLUDE_KNET 240 if (SOC_KNET_MODE(unit)) { 241 return SOC_E_NONE; 242 } 243 #endif 244 245 if (soc_feature(unit, soc_feature_txdma_purge)) { 246 dv_t dvs; 247 dv_t *dv = &dvs; 248 dcb_t *dcb; 249 soc_control_t *soc = SOC_CONTROL(unit); 250 251 if (soc->tx_purge_pkt == NULL) { 252 return SOC_E_NONE; 253 } 254 sal_memset(dv, 0, sizeof(*dv)); 255 dv->dv_unit = unit; 256 dcb = dv->dv_dcb = soc->tx_purge_pkt; 257 258 dv->dv_op = DV_TX; 259 dv->dv_channel = vchan; 260 dv->dv_cnt = 1; 261 262 rv = SOC_DCB_ADDTX(unit, dv, 263 (sal_vaddr_t) SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, dv->dv_vcnt), 264 64, /* Some Non Zero Lenght */ 265 PBMP_ALL(unit), /* Not used */ 266 PBMP_ALL(unit), /* Not used */ 267 PBMP_ALL(unit), /* Not used */ 268 SOC_DMA_PURGE, /* Purge packet */ 269 NULL /* No Higig Header required */ 270 ); 271 /* Mark the end of the packet */ 272 SOC_DCB_SG_SET(dv->dv_unit, dcb, 0); 273 if (rv >= 0) { 274 soc_cm_sflush(unit, dv->dv_dcb, SOC_DCB_SIZE(unit)); 275 276 rv = cmic_drv[unit].chan_tx_purge(unit, vchan, dv); 277 278 SDK_CONFIG_MEMORY_BARRIER; 279 } 280 } 281 return rv; 282 } 283 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 284 285 /* 286 * Function: 287 * soc_dma_abort_channel 288 * Purpose: 289 * Abort currently active DMA on the specified channel. 290 * Parameters: 291 * unit - SOC unit # 292 * vchan - Virtual channel number to abort. 293 * Returns: 294 * SOC_E_NONE - Success 295 * SOC_E_TIMEOUT - failed (Timeout) 296 * Notes: 297 * This routine does not dequeue any operation, only 298 * terminate activity on the specified channel. 299 * 300 * No check is made for active operation, but this 301 * routine should succeed regardless. Assumes SOC_DMA_LOCK 302 * held for manipulation of CMIC_DMA_CTRL. 303 */ 304 305 STATIC int 306 soc_dma_abort_channel(int unit, dma_chan_t vchan) 307 { 308 309 int rv = SOC_E_NONE; 310 #ifdef INCLUDE_KNET 311 uint8 shutdown_knet = TRUE; 312 #endif 313 314 LOG_DEBUG(BSL_LS_SOC_PACKETDMA, 315 (BSL_META_U(unit, 316 "soc_dma_abort_channel: c=%d\n"), vchan)); 317 318 #ifdef INCLUDE_KNET 319 if (SOC_KNET_MODE(unit)) { 320 if (soc_property_get(unit, spn_WARMBOOT_KNET_SHUTDOWN_MODE, 0)) { 321 shutdown_knet = FALSE; 322 } 323 if (shutdown_knet) { 324 return soc_knet_hw_reset(unit, vchan); 325 } else { 326 return soc_knet_wb_cleanup(unit); 327 } 328 } 329 #endif 330 331 /* 332 * Write the abort, wait for active to clear, then clear abort. 333 */ 334 335 rv = cmic_drv[unit].chan_abort(unit, vchan); 336 337 #ifdef BCM_XGS3_SWITCH_SUPPORT 338 /* 339 * Send a purge packet to flush any partial packet in the ingress 340 * for TX DMA channel abvort 341 */ 342 if (!(SAL_BOOT_SIMULATION) && (rv >= 0) && 343 (soc_dma_chan_dvt_get(unit, vchan) == DV_TX)) { 344 rv = soc_dma_tx_purge(unit, vchan); 345 } 346 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 347 348 return rv; 349 } 350 351 /* 352 * Function: 353 * soc_dma_abort_dv 354 * Purpose: 355 * Abort active DMA operations. 356 * Parameters: 357 * unit - unit number to abort DMA on 358 * dv - dv chain to abort. 359 * Returns: 360 * SOC_E_NONE - Operation aborted. 361 * SOC_E_TIMEOUT - operation not located, or time-out waiting 362 * for abort. 363 */ 364 365 int 366 soc_dma_abort_dv(int unit, dv_t *dv_chain) 367 { 368 uint32 soc_dma_lock; 369 soc_control_t *soc = SOC_CONTROL(unit); 370 sdc_t *sc; 371 int rv; 372 373 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 374 (BSL_META_U(unit, 375 "Aborting DV: c=%d dv=%p\n"), 376 dv_chain->dv_channel, (void *)dv_chain)); 377 378 SOC_DMA_LOCK(soc_dma_lock); /* Be sure nothing changes */ 379 if ((dv_chain->dv_channel < 0) || 380 (dv_chain->dv_channel >= soc->soc_dma_channels)) { 381 SOC_DMA_UNLOCK(soc_dma_lock); 382 return (SOC_E_TIMEOUT); 383 } 384 385 sc = &soc->soc_channels[dv_chain->dv_channel]; 386 387 /* 388 * Check if active operation. soc_dma_start_channel will update the 389 * dv_active field if the operation is active, otherwise it is not 390 * required to update it. 391 */ 392 if (sc->sc_q == NULL) { 393 rv = SOC_E_TIMEOUT; 394 } else if (dv_chain == sc->sc_q) { 395 rv = soc_dma_abort_channel(unit, sc->sc_channel); 396 sc->sc_q = dv_chain->dv_next; /* Remove from Queue */ 397 sc->sc_q_cnt--; /* Decrement current Q length */ 398 /* Updates state and active values */ 399 soc_dma_start_channel(unit, sc); /* Try to start next operation */ 400 } else { 401 dv_t *dv; 402 /* 403 * Look down list for operation, if not found, it may have completed 404 * already. 405 */ 406 for (dv = sc->sc_q; 407 (dv->dv_next != dv_chain) && (dv->dv_next != NULL); 408 dv = dv->dv_next) 409 ; 410 if (dv->dv_next == dv_chain) { 411 dv->dv_next = dv->dv_next->dv_next; /* Off list */ 412 if (sc->sc_q_tail == dv_chain) { /* was on tail? */ 413 sc->sc_q_tail = dv; /* then make previous on tail */ 414 } 415 sc->sc_q_cnt--; 416 rv = SOC_E_NONE; 417 } else { 418 rv = SOC_E_TIMEOUT; 419 } 420 } 421 422 SOC_DMA_UNLOCK(soc_dma_lock); 423 return (rv); 424 } 425 426 /* 427 * Function: 428 * soc_dma_abort_channel_total 429 * Purpose: 430 * Abort ALL active DMA on the specified channel. 431 * Parameters: 432 * unit - SOC unit # 433 * vchan - Virtual channel number to abort. 434 * Returns: 435 * # of operations aborted. 436 * Notes: 437 * This routine _does_ dequeue any operations on the channel. 438 */ 439 int 440 soc_dma_abort_channel_total(int unit, dma_chan_t vchan) 441 { 442 uint32 soc_dma_lock; 443 soc_control_t *soc = SOC_CONTROL(unit); 444 sdc_t *sc; /* Channel pointer */ 445 int rv = 0; /* Return value */ 446 447 SOC_DMA_LOCK(soc_dma_lock); /* Be sure nothing changes */ 448 sc = &soc->soc_channels[vchan]; 449 soc_dma_abort_channel(unit, vchan); 450 451 /* Clear up all queued DMA operations */ 452 453 while (sc->sc_q != NULL) { 454 assert(sc->sc_q->dv_channel >= 0); 455 sc->sc_q->dv_channel = -sc->sc_q->dv_channel; 456 sc->sc_q = sc->sc_q->dv_next; 457 sc->sc_q_cnt--; 458 rv++; 459 } 460 sc->sc_dv_active = NULL; 461 sc->sc_q_tail = NULL; 462 assert(sc->sc_q == NULL); 463 assert(sc->sc_q_cnt == 0); 464 SOC_DMA_UNLOCK(soc_dma_lock); 465 return rv; 466 } 467 468 /* 469 * Function: 470 * soc_dma_abort 471 * Purpose: 472 * Abort ALL dma active on a CMIC. 473 * Parameters: 474 * unit - unit #. 475 * Returns: 476 * # of operations aborted. 477 */ 478 479 int 480 soc_dma_abort(int unit) 481 { 482 soc_control_t *soc = SOC_CONTROL(unit); 483 dma_chan_t vchan; /* Channel # */ 484 int rv = 0; /* Return value */ 485 486 for (vchan = 0; vchan < soc->soc_dma_channels; vchan++) { 487 rv += soc_dma_abort_channel_total(unit, vchan); 488 } 489 return (rv); 490 } 491 492 #define DP_FMT "%sdata[%04x]: " /* dump line start format */ 493 #define DP_HDR "%sheader[%04x]: " /* dump header */ 494 #define DP_BPL 16 /* dumped bytes per line */ 495 496 /* 497 * Function: 498 * soc_dma_higig_dump 499 * Purpose: 500 * Dump the HIGIG header of a packet in human readable form 501 * Parameters: 502 * pfx - prefix for all output strings 503 * addr - pointer to data bytes of packet 504 * len - length of data to dump 505 * ether_offset - (OUT) return offset of start of ether packet 506 * Returns: 507 * Nothing 508 */ 509 510 #if defined(BCM_XGS_FABRIC_SUPPORT) || defined(BCM_XGS3_SWITCH_SUPPORT) || defined(BCM_PETRA_SUPPORT) || defined(BCM_DNX_SUPPORT) 511 void 512 soc_dma_higig_dump(int unit, char *pfx, uint8 *addr, int len, int pkt_len, 513 int *ether_offset) 514 { 515 soc_higig_hdr_t *xgh = (soc_higig_hdr_t *)addr; 516 517 if (soc_higig_field_get(unit, xgh, HG_hgi) == SOC_HIGIG_HGI) { 518 if (!len) { 519 len = pkt_len + SOC_HIGIG_HDR_SIZE; 520 } 521 LOG_CLI((BSL_META_U(unit, 522 "%sHIGIG Frame:" 523 " len=%d (header=%d payload=%d)\n"), 524 pfx, len, SOC_HIGIG_HDR_SIZE, 525 len - SOC_HIGIG_HDR_SIZE)); 526 soc_higig_dump(unit, pfx, xgh); 527 LOG_CLI((BSL_META_U(unit, 528 "%s802.3 Ether-II VLAN-Tagged Payload (%d bytes)\n"), 529 pfx, len - SOC_HIGIG_HDR_SIZE)); 530 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_HURRICANE2_SUPPORT) 531 } else if ((SOC_IS_TRIUMPH3(unit) || SOC_IS_TD2_TT2(unit) || 532 SOC_IS_HURRICANE2(unit) || SOC_IS_KATANA2(unit) || 533 SOC_IS_GREYHOUND(unit) || SOC_IS_HURRICANE3(unit) || 534 SOC_IS_GREYHOUND2(unit)) && 535 (soc_pbsmh_field_get(unit, 536 (soc_pbsmh_hdr_t *)xgh, 537 PBSMH_start) == SOC_PBSMH_START_INTERNAL)) { 538 539 soc_pbsmh_dump(unit, pfx, (soc_pbsmh_hdr_t *)xgh); 540 #endif /* BCM_TRIUMPH3_SUPPORT */ 541 #ifdef BCM_XGS3_SWITCH_SUPPORT 542 } else if ((SOC_IS_XGS3_SWITCH(unit)) && 543 (soc_pbsmh_field_get(unit, 544 (soc_pbsmh_hdr_t *)xgh, 545 PBSMH_start) == SOC_PBSMH_START)) { 546 soc_pbsmh_dump(unit, pfx, (soc_pbsmh_hdr_t *)xgh); 547 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 548 #ifdef BCM_HIGIG2_SUPPORT 549 } else if (soc_feature(unit, soc_feature_higig2) || 550 soc_feature(unit, soc_feature_rx_pkt_hdr_format_higig2)) { 551 /* Not Higig/Higig+/PBS - assume Higig2 */ 552 if (!len) { 553 len = pkt_len + SOC_HIGIG2_HDR_SIZE; 554 } 555 LOG_CLI((BSL_META_U(unit, 556 "%sHIGIG2 Frame:" 557 " len=%d (header=%d payload=%d)\n"), 558 pfx, len, SOC_HIGIG2_HDR_SIZE, 559 len - SOC_HIGIG2_HDR_SIZE)); 560 soc_higig2_dump(unit, pfx, (soc_higig2_hdr_t *)xgh); 561 LOG_CLI((BSL_META_U(unit, 562 "%s802.3 Ether-II VLAN-Tagged Payload (%d bytes)\n"), 563 pfx, len - SOC_HIGIG2_HDR_SIZE)); 564 #endif /* BCM_HIGIG2_SUPPORT */ 565 #ifdef BCM_XGS_SUPPORT 566 } else if (xgh->overlay1.hgi == SOC_BCM5632_HGI) { 567 soc_bcm5632_hdr_t *bhdr = (soc_bcm5632_hdr_t *)addr; 568 if (!len) { 569 len = pkt_len + SOC_BCM5632_HDR_SIZE; 570 } 571 /* BCM5632 format */ 572 LOG_CLI((BSL_META_U(unit, 573 "%sBCM5632 Frame:" 574 " len=%d (header=%d payload=%d)\n"), 575 pfx, len, SOC_BCM5632_HDR_SIZE, 576 len - SOC_BCM5632_HDR_SIZE)); 577 LOG_CLI((BSL_META_U(unit, 578 "%s0x%02x%02x%02x%02x <D_PORTID=%d>\n"), 579 pfx, 580 bhdr->overlay0.bytes[0], 581 bhdr->overlay0.bytes[1], 582 bhdr->overlay0.bytes[2], 583 bhdr->overlay0.bytes[3], 584 bhdr->overlay1.d_portid)); 585 LOG_CLI((BSL_META_U(unit, 586 "%s0x%02x%02x%02x%02x <S_PORTID=%d> " 587 "<LEN=%d> START=<0x%x>\n"), 588 pfx, 589 bhdr->overlay0.bytes[4], 590 bhdr->overlay0.bytes[5], 591 bhdr->overlay0.bytes[6], 592 bhdr->overlay0.bytes[7], 593 bhdr->overlay1.s_portid, 594 (bhdr->overlay1.length_hi << 8 | 595 bhdr->overlay1.length_lo), 596 bhdr->overlay1.start)); 597 #endif /* BCM_XGS_SUPPORT */ 598 } 599 600 /* Calculate ether_offset if given */ 601 if (ether_offset) { 602 #ifdef BCM_HIGIG2_SUPPORT 603 if (soc_higig_field_get(unit, xgh, HG_start) == SOC_HIGIG2_START) { 604 *ether_offset = sizeof(soc_higig2_hdr_t); 605 } else 606 #endif 607 if (soc_higig_field_get(unit, xgh, HG_hgi) == SOC_HIGIG_HGI) { 608 *ether_offset = sizeof(soc_higig_hdr_t); 609 #ifdef BCM_XGS_SUPPORT 610 } else if (xgh->overlay1.hgi == SOC_BCM5632_HGI) { 611 *ether_offset = sizeof (soc_bcm5632_hdr_t); 612 #endif /* BCM_XGS_SUPPORT */ 613 } else { 614 *ether_offset = 0; 615 } 616 } 617 } 618 #endif /* defined(BCM_XGS_FABRIC_SUPPORT) || defined(BCM_XGS3_SWITCH_SUPPORT) */ 619 620 621 void 622 soc_dma_ether_dump(int unit, char *pfx, uint8 *addr, int len, int offset) 623 { 624 int i = 0, j; 625 626 627 if (addr == 0) { 628 LOG_CLI((BSL_META_U(unit, 629 "Bad packet ADDR!!\n"))); 630 return; 631 } 632 633 if (len > DP_BPL && (DP_BPL & 1) == 0) { 634 char linebuf[128], *s; 635 /* Show first line with MAC addresses in curly braces */ 636 s = linebuf; 637 sal_sprintf(s, DP_FMT "{", pfx, i); 638 while (*s != 0) s++; 639 for (i = offset; i < offset + 6; i++) { 640 sal_sprintf(s, "%02x", addr[i]); 641 while (*s != 0) s++; 642 } 643 sal_sprintf(s, "} {"); 644 while (*s != 0) s++; 645 for (; i < offset + 12; i++) { 646 sal_sprintf(s, "%02x", addr[i]); 647 while (*s != 0) s++; 648 } 649 sal_sprintf(s, "}"); 650 while (*s != 0) s++; 651 for (; i < offset + DP_BPL; i += 2) { 652 sal_sprintf(s, " %02x%02x", addr[i], addr[i + 1]); 653 while (*s != 0) s++; 654 } 655 LOG_CLI((BSL_META_U(unit, 656 "%s\n"), linebuf)); 657 } 658 659 for (; i < len; i += DP_BPL) { 660 char linebuf[128], *s; 661 s = linebuf; 662 sal_sprintf(s, DP_FMT, pfx, i); 663 while (*s != 0) s++; 664 for (j = i; j < i + DP_BPL && j < len; j++) { 665 sal_sprintf(s, "%02x%s", addr[j], j & 1 ? " " : ""); 666 while (*s != 0) s++; 667 } 668 LOG_CLI((BSL_META_U(unit, 669 "%s\n"), linebuf)); 670 } 671 672 } 673 674 void 675 soc_dma_ep_to_cpu_hdr_dump(int unit, char *pfx, uint8 *addr, int len, int offset) 676 { 677 int i, j; 678 uint8 hdr[96]; 679 #ifdef LE_HOST 680 int word = 0; 681 uint8 temp = 0; 682 #endif 683 684 if (addr == 0) { 685 LOG_CLI((BSL_META_U(unit, 686 "Bad Header ADDR!!\n"))); 687 return; 688 } 689 690 sal_memcpy(hdr, addr, len); 691 #ifdef LE_HOST 692 for (word = 0; word < BYTES2WORDS(len); word++) { 693 temp = hdr[(word * 4) + 0]; 694 hdr[(word * 4) + 0] = hdr[(word * 4) + 3]; 695 hdr[(word * 4) + 3] = temp; 696 697 temp = hdr[(word * 4) + 1]; 698 hdr[(word * 4) + 1] = hdr[(word * 4) + 2]; 699 hdr[(word * 4) + 2] = temp; 700 701 } 702 #endif 703 704 for (i = offset; i < len; i += DP_BPL) { 705 char linebuf[128], *s; 706 s = linebuf; 707 sal_sprintf(s, DP_HDR, pfx, i); 708 while (*s != 0) s++; 709 for (j = i; j < i + DP_BPL && j < len; j++) { 710 sal_sprintf(s, "%02x%s", hdr[j], j & 1 ? " " : ""); 711 while (*s != 0) s++; 712 } 713 LOG_CLI((BSL_META_U(unit, 714 "%s\n"), linebuf)); 715 } 716 717 } 718 719 void 720 soc_dma_usage_get(int unit) 721 { 722 #if !defined(__KERNEL__) 723 int sz; 724 extern int _dma_get_usage(void) __attribute__ ((weak)); 725 726 sz = _dma_get_usage(); 727 728 LOG_CLI((BSL_META_U(unit, 729 "DMA memory usage : %d (%dk)\n"), sz, sz/1024)); 730 #endif 731 } 732 733 /* 734 * Function: 735 * soc_dma_dump_rx_pkt 736 * Purpose: 737 * Dump packet data in human readable form with packet watch layout 738 * Parameters: 739 * pfx - prefix for all output strings 740 * dcb - dma control block 741 * Returns: 742 * Nothing 743 */ 744 745 void 746 soc_dma_dump_rx_pkt(int unit, char *pfx, dcb_t *dcb) 747 { 748 /* for alignment packet watch packet format */ 749 char prefix[64]; 750 uint8 rx_untagged; /* The packet was untagged on ingress. */ 751 rx_untagged = SOC_DCB_RX_UNTAGGED_GET(unit, dcb); 752 753 sal_sprintf(prefix, "%s Packet: ", pfx); 754 755 LOG_CLI((BSL_META_U(unit, 756 "%s length %d. rx-port %d. cos %d. prio_int %d. vlan %d. reason 0x%x. %s.\n"), 757 prefix, 758 SOC_DCB_XFERCOUNT_GET(unit, dcb), 759 SOC_DCB_RX_INGPORT_GET(unit, dcb), 760 SOC_DCB_RX_COS_GET(unit, dcb), 761 SOC_DCB_RX_PRIO_GET(unit, dcb), 762 SOC_DCB_RX_OUTER_VID_GET(unit, dcb), 763 SOC_DCB_RX_REASON_GET(unit, dcb), 764 (rx_untagged & 0x1) ? 765 ((rx_untagged & 0x2) ? "Untagged" : "Inner tagged") : 766 ((rx_untagged & 0x2) ? "Outer tagged" : "Double tagged") 767 )); 768 LOG_CLI((BSL_META_U(unit, 769 "%s dest-gport %d. dest-mod %d. src-gport %d. src-mod %d. opcode %d. matched %d. classification-tag %d.\n"), 770 prefix, 771 SOC_DCB_RX_DESTPORT_GET(unit, dcb), 772 SOC_DCB_RX_DESTMOD_GET(unit, dcb), 773 SOC_DCB_RX_SRCPORT_GET(unit, dcb), 774 SOC_DCB_RX_SRCMOD_GET(unit, dcb), 775 SOC_DCB_RX_OPCODE_GET(unit, dcb), 776 SOC_DCB_RX_MATCHRULE_GET(unit, dcb), 777 SOC_DCB_RX_CLASSTAG_GET(unit, dcb) 778 )); 779 SOC_DCB_REASON_DUMP(unit, dcb, prefix); 780 } 781 782 /* 783 * Function: 784 * soc_dma_dump_pkt 785 * Purpose: 786 * Dump packet data in human readable form 787 * Parameters: 788 * pfx - prefix for all output strings 789 * addr - pointer to data bytes of packet 790 * len - length of data to dump 791 * decode - assume this is start of packet and decode fields 792 * Returns: 793 * Nothing 794 */ 795 796 void 797 soc_dma_dump_pkt(int unit, char *pfx, uint8 *addr, int len, int decode) 798 { 799 int ether_offset; 800 801 COMPILER_REFERENCE(unit); 802 803 if (!addr || !pfx) { 804 LOG_CLI((BSL_META_U(unit, 805 "<ERROR>\n"))); 806 return; 807 } 808 809 if (len == 0) { 810 LOG_CLI((BSL_META_U(unit, 811 DP_FMT "<NONE>\n"), pfx, 0)); 812 } 813 814 ether_offset = 0; 815 816 #ifdef BCM_HERCULES_SUPPORT 817 /* All hercules chips have module header prepended to frame */ 818 if (SOC_IS_HERCULES(unit) && decode) { 819 soc_dma_higig_dump(unit, pfx, addr, len, 0, ðer_offset); 820 } 821 #endif /* BCM_HERCULES_SUPPORT */ 822 823 soc_dma_ether_dump(unit, pfx, addr, len, ether_offset); 824 } 825 826 #undef DP_FMT 827 #undef DP_BPL 828 829 /* 830 * Function: 831 * soc_dma_dv_valid 832 * Purpose: 833 * Check if a DV is (probably) valid 834 * Parameters: 835 * dv - The dv to examine 836 * Returns: 837 * BCM_E_XXX 838 * Notes: 839 * Does not guarantee a DV is valid, but will detect 840 * most _invalid_ DVs. 841 */ 842 843 int 844 soc_dma_dv_valid(dv_t *dv) 845 { 846 if (dv->dv_magic != DV_MAGIC_NUMBER) { 847 return FALSE; 848 } 849 850 return TRUE; 851 } 852 853 /* 854 * Function: 855 * soc_dma_dv_cnt_valid 856 * Purpose: 857 * Check if the cnt of the dv are valid 858 * Parameters: 859 * dv - The dv to examine 860 * Returns: 861 * BCM_E_XXX 862 */ 863 864 static int 865 soc_dma_dv_cnt_valid(int unit, dv_t *dv) 866 { 867 assert(dv != NULL); 868 if (dv->dv_cnt < 0 || dv->dv_dcnt < 0 || dv->dv_vcnt < 0 || 869 dv->dv_cnt < dv->dv_dcnt || 870 dv->dv_cnt < dv->dv_vcnt) { 871 LOG_WARN(BSL_LS_SOC_COMMON, 872 (BSL_META_U(unit, 873 "unit=%d, " 874 "dv->dv_cnt=%d, dv->dv_dcnt=%d, dv->dv_vcnt=%d"), 875 unit, dv->dv_cnt, dv->dv_dcnt, dv->dv_vcnt)); 876 return FALSE; 877 } 878 return TRUE; 879 } 880 881 /* 882 * Function: 883 * soc_dma_dump_dv 884 * Purpose: 885 * Dump a "dv" structure and all the DCB fields. 886 * Parameters: 887 * dv_chain - pointer to dv list to dump. 888 * Returns: 889 * Nothing. 890 */ 891 892 void 893 soc_dma_dump_dv(int unit, char *pfx, dv_t *dv_chain) 894 { 895 static char *channel[] = {"0","1","2","3"}; 896 char tmps[128]; 897 char *op_name; 898 int i; 899 dv_t *dv; 900 char * chan_str; 901 int len = 0; 902 int len_tmps = 0; 903 904 for (dv = dv_chain; dv; dv = dv->dv_chain) { 905 906 if (!soc_dma_dv_valid(dv)) { 907 LOG_CLI((BSL_META_U(unit, 908 "%sdv@%p appears invalid\n"), pfx, (void *)dv)); 909 break; 910 } 911 912 switch(dv_chain->dv_op) { 913 case DV_NONE: op_name = "None"; break; 914 case DV_TX: op_name = "TX"; break; 915 case DV_RX: op_name = "RX"; break; 916 default: op_name = "*ERR*"; break; 917 } 918 919 tmps[0] = '\0'; 920 len_tmps = sal_strlen(tmps); 921 922 if (dv_chain->dv_flags & DV_F_NOTIFY_DSC) { 923 len = sal_strlen("notify-dsc "); 924 sal_strncpy(tmps + len_tmps , "notify-dsc ", len); 925 *(tmps + len_tmps + len) = '\0'; 926 } 927 if (dv_chain->dv_flags & DV_F_NOTIFY_CHN) { 928 len = sal_strlen("notify-chn "); 929 sal_strncpy(tmps + len_tmps, "notify-chn ", len); 930 *(tmps + len_tmps + len) = '\0'; 931 } 932 if (dv_chain->dv_done_packet) { 933 len = sal_strlen("notify-pkt "); 934 sal_strncpy(tmps + len_tmps, "notify-pkt ", len); 935 *(tmps + len_tmps + len) = '\0'; 936 } 937 if (dv_chain->dv_flags & DV_F_COMBINE_DCB) { 938 len = sal_strlen("combine-dcb "); 939 sal_strncpy(tmps + len_tmps, "combine-dcb ", len); 940 *(tmps + len_tmps + len) = '\0'; 941 } 942 943 LOG_CLI((BSL_META_U(unit, 944 "%sdv@%p unit %d dcbtype-%d op=%s vcnt=%d dcnt=%d " 945 "cnt=%d\n"), 946 pfx, (void *)dv, unit, SOC_DCB_TYPE(unit), 947 op_name, dv->dv_vcnt, dv->dv_dcnt, dv->dv_cnt)); 948 if (dv->dv_channel == -1) { 949 chan_str = "any"; 950 } else if (dv->dv_channel < -1 || dv->dv_channel > 3) { 951 chan_str = "illegal"; 952 } else { 953 chan_str = channel[dv->dv_channel]; 954 } 955 LOG_CLI((BSL_META_U(unit, 956 "%s chan=%s chain=%p flags=0x%x-->%s\n"), 957 pfx, chan_str, 958 (void *)dv->dv_chain, 959 dv->dv_flags, tmps)); 960 LOG_CLI((BSL_META_U(unit, 961 "%s user1 %p. user2 %p. user3 %p. user4 %p\n"), 962 pfx, dv->dv_public1.ptr, dv->dv_public2.ptr, 963 dv->dv_public3.ptr, dv->dv_public4.ptr)); 964 if (dv->tx_param.flags != 0) { 965 soc_tx_param_t *prm = &dv->tx_param; 966 LOG_CLI((BSL_META_U(unit, 967 "%s tx-param flags 0x%x cos %d sp.sm %d.%d\n"), 968 pfx, prm->flags, prm->cos, prm->src_port, 969 prm->src_mod)); 970 } 971 for (i = 0; i < dv->dv_vcnt; i++) { 972 dcb_t *dcb; 973 sal_vaddr_t addr; 974 int decode = 0; 975 976 dcb = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, i); 977 addr = SOC_DCB_ADDR_GET(unit, dcb); 978 LOG_CLI((BSL_META_U(unit, 979 "%sdcb[%d] @%p:\n"), pfx, i, dcb)); 980 #ifdef BROADCOM_DEBUG 981 SOC_DCB_DUMP(dv->dv_unit, dcb, pfx, 982 (dv_chain->dv_op == DV_TX) ? 1 : 0); 983 #endif /* BROADCOM_DEBUG */ 984 decode = (i == 0 || 985 !SOC_DCB_SG_GET(dv->dv_unit, 986 SOC_DCB_IDX2PTR(dv->dv_unit, 987 dv->dv_dcb, i - 1))); 988 989 if (dv->dv_op == DV_TX) { 990 if (bsl_check(bslLayerSoc, bslSourceTx, bslSeverityNormal, unit)) { 991 LOG_VERBOSE(BSL_LS_SOC_TX, 992 (BSL_META_U(unit, 993 "soc_dma_dump_pkt: Tx DV infomation\n"))); 994 soc_dma_dump_pkt(unit, pfx, (uint8 *) addr, 995 SOC_DCB_REQCOUNT_GET(unit, dcb), 996 decode); 997 } 998 } else if (dv->dv_op == DV_RX && SOC_DCB_DONE_GET(unit, dcb)) { 999 if (bsl_check(bslLayerSoc, bslSourceRx, bslSeverityNormal, unit)) { 1000 LOG_VERBOSE(BSL_LS_SOC_RX, 1001 (BSL_META_U(unit, 1002 "soc_dma_dump_pkt: Rx DV infomation\n"))); 1003 1004 #if defined(BCM_CMICX_SUPPORT) 1005 if (soc_feature(unit, soc_feature_cmicx)) { 1006 uint32 hdr_size = 0; 1007 soc_dma_header_size_get(unit, &hdr_size); 1008 1009 soc_dma_ep_to_cpu_hdr_dump(unit, pfx, (uint8 *) addr, hdr_size, 0); 1010 1011 soc_dma_dump_pkt(unit, pfx, (uint8 *) (addr + hdr_size), 1012 SOC_DCB_XFERCOUNT_GET(unit, dcb) - hdr_size, 1013 decode); 1014 } else 1015 #endif 1016 { 1017 soc_dma_dump_pkt(unit, pfx, (uint8 *) addr, 1018 SOC_DCB_XFERCOUNT_GET(unit, dcb), 1019 decode); 1020 } 1021 LOG_VERBOSE(BSL_LS_SOC_RX, 1022 (BSL_META_U(unit, 1023 "soc_dma_dump_rx_pkt: Rx packet infomation\n"))); 1024 soc_dma_dump_rx_pkt(unit, pfx, dcb); 1025 } 1026 } 1027 } 1028 } 1029 } 1030 1031 void 1032 soc_dma_dump_dv_dcb(int unit, char *pfx, dv_t *dv_chain, int index) /* , dcb_t *dcb) */ 1033 { 1034 static char *channel[] = {"0","1","2","3"}; 1035 char tmps[128]; 1036 char *op_name; 1037 int i; 1038 dv_t *dv; 1039 char * chan_str; 1040 int len = 0; 1041 int len_tmps = 0; 1042 1043 dv = dv_chain; 1044 { 1045 if (!soc_dma_dv_valid(dv)) { 1046 LOG_CLI((BSL_META_U(unit, 1047 "%sdv@%p appears invalid\n"), pfx, (void *)dv)); 1048 return ; 1049 } 1050 switch(dv_chain->dv_op) { 1051 case DV_NONE: op_name = "None"; break; 1052 case DV_TX: op_name = "TX"; break; 1053 case DV_RX: op_name = "RX"; break; 1054 default: op_name = "*ERR*"; break; 1055 } 1056 tmps[0] = '\0'; 1057 len_tmps = sal_strlen(tmps); 1058 1059 if (dv_chain->dv_flags & DV_F_NOTIFY_DSC) { 1060 len = sal_strlen("notify-dsc "); 1061 sal_strncpy(tmps + len_tmps , "notify-dsc ", len); 1062 *(tmps + len_tmps + len) = '\0'; 1063 } 1064 if (dv_chain->dv_flags & DV_F_NOTIFY_CHN) { 1065 len = sal_strlen("notify-chn "); 1066 sal_strncpy(tmps + len_tmps, "notify-chn ", len); 1067 *(tmps + len_tmps + len) = '\0'; 1068 } 1069 if (dv_chain->dv_done_packet) { 1070 len = sal_strlen("notify-pkt "); 1071 sal_strncpy(tmps + len_tmps, "notify-pkt ", len); 1072 *(tmps + len_tmps + len) = '\0'; 1073 } 1074 if (dv_chain->dv_flags & DV_F_COMBINE_DCB) { 1075 len = sal_strlen("combine-dcb "); 1076 sal_strncpy(tmps + len_tmps, "combine-dcb ", len); 1077 *(tmps + len_tmps + len) = '\0'; 1078 } 1079 1080 LOG_CLI((BSL_META_U(unit, 1081 "%sdv@%p unit %d dcbtype-%d op=%s vcnt=%d dcnt=%d " 1082 "cnt=%d\n"), 1083 pfx, (void *)dv, unit, SOC_DCB_TYPE(unit), 1084 op_name, dv->dv_vcnt, dv->dv_dcnt, dv->dv_cnt)); 1085 if (dv->dv_channel == -1) { 1086 chan_str = "any"; 1087 } else if (dv->dv_channel < -1 || dv->dv_channel > 3) { 1088 chan_str = "illegal"; 1089 } else { 1090 chan_str = channel[dv->dv_channel]; 1091 } 1092 LOG_CLI((BSL_META_U(unit, 1093 "%s chan=%s chain=%p flags=0x%x-->%s\n"), 1094 pfx, chan_str, 1095 (void *)dv->dv_chain, 1096 dv->dv_flags, tmps)); 1097 LOG_CLI((BSL_META_U(unit, 1098 "%s user1 %p. user2 %p. user3 %p. user4 %p\n"), 1099 pfx, dv->dv_public1.ptr, dv->dv_public2.ptr, 1100 dv->dv_public3.ptr, dv->dv_public4.ptr)); 1101 if (dv->tx_param.flags != 0) { 1102 soc_tx_param_t *prm = &dv->tx_param; 1103 LOG_CLI((BSL_META_U(unit, 1104 "%s tx-param flags 0x%x cos %d sp.sm %d.%d\n"), 1105 pfx, prm->flags, prm->cos, prm->src_port, 1106 prm->src_mod)); 1107 } 1108 i= index; 1109 { 1110 dcb_t *dcb; 1111 sal_vaddr_t addr; 1112 dcb = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, i); 1113 addr = SOC_DCB_ADDR_GET(unit, dcb); 1114 LOG_CLI((BSL_META_U(unit, 1115 "%sdcb[%d] @%p:\n"), pfx, i, dcb)); 1116 #ifdef BROADCOM_DEBUG 1117 SOC_DCB_DUMP(dv->dv_unit, dcb, pfx, 1118 (dv_chain->dv_op == DV_TX) ? 1 : 0); 1119 #endif /* BROADCOM_DEBUG */ 1120 { 1121 int decode; 1122 decode = (i == 0 || 1123 !SOC_DCB_SG_GET(dv->dv_unit, 1124 SOC_DCB_IDX2PTR(dv->dv_unit, 1125 dv->dv_dcb, i - 1))); 1126 if (dv->dv_op == DV_TX) { 1127 if (bsl_check(bslLayerSoc, bslSourceTx, bslSeverityNormal, unit)) { 1128 LOG_VERBOSE(BSL_LS_SOC_TX, 1129 (BSL_META_U(unit, 1130 "soc_dma_dump_pkt: DV_TX infomation\n"))); 1131 soc_dma_dump_pkt(unit, pfx, (uint8 *) addr, 1132 SOC_DCB_REQCOUNT_GET(unit, dcb), 1133 decode); 1134 } 1135 } else if (dv->dv_op == DV_RX && SOC_DCB_DONE_GET(unit, dcb)) { 1136 if (bsl_check(bslLayerSoc, bslSourceRx, bslSeverityNormal, unit)) { 1137 LOG_VERBOSE(BSL_LS_SOC_RX, 1138 (BSL_META_U(unit, 1139 "soc_dma_dump_pkt: DV_RX infomation\n"))); 1140 soc_dma_dump_pkt(unit, pfx, (uint8 *) addr, 1141 SOC_DCB_XFERCOUNT_GET(unit, dcb), 1142 decode); 1143 LOG_VERBOSE(BSL_LS_SOC_RX, 1144 (BSL_META_U(unit, 1145 "soc_dma_dump_rx_pkt: Rx packet infomation\n"))); 1146 soc_dma_dump_rx_pkt(unit, pfx, dcb); 1147 } 1148 } 1149 } 1150 } 1151 } 1152 } 1153 1154 /* 1155 * Function: 1156 * soc_dma_start_dv (internal) 1157 * Purpose: 1158 * Main part of soc_dma_start function. 1159 * Parameters: 1160 * unit - StrataSwitch unit #. 1161 * sc - Pointer to channel structure to start 1162 * dv_chain - pointer to DV chain to start. 1163 * Returns: 1164 * SOC_E_XXX. 1165 */ 1166 1167 STATIC int 1168 soc_dma_start_dv(int unit, sdc_t *sc, dv_t *dv_chain) 1169 { 1170 uint32 soc_dma_lock; 1171 int i; 1172 dv_t *dv; 1173 dcb_t *dcb; 1174 int rv = SOC_E_NONE; 1175 1176 assert(sc->sc_type == dv_chain->dv_op); 1177 assert(!(dv_chain->dv_flags & DV_F_NOTIFY_CHN) || 1178 dv_chain->dv_done_chain); 1179 assert(!(dv_chain->dv_flags & DV_F_NOTIFY_DSC) || 1180 dv_chain->dv_done_desc); 1181 1182 #if defined(BROADCOM_DEBUG) 1183 /* Dump out info on request, before queued on channel */ 1184 if (bsl_check(bslLayerSoc, bslSourceDma, bslSeverityNormal, unit)) { 1185 soc_dma_dump_dv(unit, "dma (before): ", dv_chain); 1186 } 1187 #endif /* BROADCOM_DEBUG */ 1188 1189 /* Clean cache of any dirty data */ 1190 1191 for (dv = dv_chain; dv; dv = dv->dv_chain) { 1192 soc_cm_sflush(unit, dv->dv_dcb, 1193 dv->dv_vcnt * SOC_DCB_SIZE(unit)); 1194 1195 for (i = 0; i < dv->dv_vcnt; i++) { 1196 uint32 cnt; 1197 sal_vaddr_t addr; 1198 1199 dcb = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, i); 1200 cnt = SOC_DCB_REQCOUNT_GET(unit, dcb); 1201 addr = SOC_DCB_ADDR_GET(unit, dcb); 1202 if (dv_chain->dv_op == DV_TX) { 1203 soc_cm_sflush(unit, (void *)addr, cnt); 1204 } else { 1205 assert(dv_chain->dv_op == DV_RX); 1206 } 1207 } 1208 } 1209 1210 /* Mark Channel # */ 1211 1212 dv_chain->dv_channel = sc->sc_channel; 1213 1214 SOC_DMA_LOCK(soc_dma_lock); 1215 1216 cmic_drv[unit].chan_dv_start(unit, sc, dv_chain); 1217 1218 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 1219 (BSL_META_U(unit, 1220 "Starting DV: c=%d dv=%p\n"), 1221 dv_chain->dv_channel, (void *)dv_chain)); 1222 1223 #ifdef INCLUDE_KNET 1224 /* 1225 * For KNET mode it is still required to hold the DMA lock while 1226 * the DV chain is started. However, since this operation takes 1227 * place at the kernel level (via the KCOM user/kernel messaging 1228 * protocol,) it is critical that the DMA lock implementation does 1229 * not block task scheduling or hardware interrupts (this is 1230 * normally not possible to do from user mode anyway.) 1231 */ 1232 if (SOC_KNET_MODE(unit)) { 1233 kcom_msg_dma_info_t kmsg; 1234 int wsize = BYTES2WORDS(SOC_DCB_SIZE(unit)); 1235 int len; 1236 1237 for (dv = dv_chain; dv; dv = dv->dv_chain) { 1238 sal_memset(&kmsg, 0, sizeof(kmsg)); 1239 kmsg.hdr.opcode = KCOM_M_DMA_INFO; 1240 kmsg.hdr.unit = unit; 1241 if (dv_chain->dv_op == DV_TX) { 1242 kmsg.dma_info.type = KCOM_DMA_INFO_T_TX_DCB; 1243 } else { 1244 kmsg.dma_info.type = KCOM_DMA_INFO_T_RX_DCB; 1245 } 1246 kmsg.dma_info.cnt = dv->dv_vcnt; 1247 kmsg.dma_info.size = wsize; 1248 kmsg.dma_info.chan = dv_chain->dv_channel; 1249 dcb = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, 0); 1250 kmsg.dma_info.data.dcb_start = soc_cm_l2p(unit, dcb); 1251 len = sizeof(kmsg); 1252 rv = soc_knet_cmd_req((kcom_msg_t *)&kmsg, len, sizeof(kmsg)); 1253 } 1254 } 1255 #endif 1256 1257 SOC_DMA_UNLOCK(soc_dma_lock); 1258 return rv; 1259 } 1260 1261 /* 1262 * Function: 1263 * soc_dma_start 1264 * Purpose: 1265 * Launch a SOC_DMA DMA operation. 1266 * Parameters: 1267 * unit - unit number. 1268 * vchan - Virtual DMA channel to use (0-11) or -1 if any 1269 * channel ok. 1270 * dv_chain - dma request description. 1271 * Returns: 1272 * SOC_E_NONE - operation started. 1273 * SOC_E_TIMEOUT - operation failed to be queued. 1274 */ 1275 1276 int 1277 soc_dma_start(int unit, dma_chan_t vchan, dv_t *dv_chain) 1278 { 1279 sdc_t *sc; /* Channel pointer */ 1280 int rv = SOC_E_NONE; 1281 1282 /* Fire off DMA operation, let interrupt handler free channel */ 1283 1284 sc = soc_dma_channel(unit, vchan, dv_chain); 1285 if (sc == NULL) { 1286 return(SOC_E_RESOURCE); 1287 } 1288 1289 rv = soc_dma_start_dv(unit, sc, dv_chain); 1290 return rv; 1291 } 1292 1293 STATIC void 1294 soc_dma_free_list(int unit); 1295 1296 /* 1297 * Function: 1298 * soc_dma_dv_alloc 1299 * Purpose: 1300 * Allocate and initialize a dv struct. 1301 * Parameters: 1302 * op - operations iov requested for. 1303 * cnt - number of DCBs required. 1304 * Notes: 1305 * If a DV on the free list will accomodate the request, 1306 * satisfy it from there to avoid extra alloc/free calls. 1307 */ 1308 1309 dv_t * 1310 soc_dma_dv_alloc(int unit, dvt_t op, int cnt) 1311 { 1312 uint32 soc_dma_lock; 1313 soc_control_t *soc = SOC_CONTROL(unit); 1314 dv_t *dv; 1315 uint32 dmabuf_size; 1316 int *dv_free_cnt; 1317 dv_t **dv_free; 1318 void *info = NULL; 1319 1320 assert(cnt > 0); 1321 1322 /* Always bump up DCB count to free list size */ 1323 1324 if (cnt < soc->soc_dv_size) { 1325 cnt = soc->soc_dv_size; 1326 } 1327 1328 /* Check if we can use one off the free list */ 1329 1330 SOC_DMA_LOCK(soc_dma_lock); 1331 if (op == DV_TX) { 1332 dv_free_cnt = &(soc->soc_dv_tx_free_cnt); 1333 dv_free = &(soc->soc_dv_tx_free); 1334 } else if (op == DV_RX) { 1335 dv_free_cnt = &(soc->soc_dv_rx_free_cnt); 1336 dv_free = &(soc->soc_dv_rx_free); 1337 } else { 1338 SOC_DMA_UNLOCK(soc_dma_lock); 1339 return NULL; 1340 } 1341 soc->stat.dv_alloc++; 1342 if ((cnt == soc->soc_dv_size) && ((*dv_free_cnt) > 0)) { 1343 dv = *(dv_free); 1344 *(dv_free) = dv->dv_chain; 1345 (*dv_free_cnt)--; 1346 soc->stat.dv_alloc_q++; 1347 SOC_DMA_UNLOCK(soc_dma_lock); 1348 info = dv->dv_public1.ptr; 1349 } else { 1350 SOC_DMA_UNLOCK(soc_dma_lock); 1351 dv = soc_at_alloc(unit, sizeof(dv_t), "soc_dma_dv_alloc"); 1352 if (dv == NULL) { 1353 /* to release the free list */ 1354 soc_dma_free_list(unit); 1355 dv = soc_at_alloc(unit, sizeof(dv_t), "soc_dma_dv_alloc"); 1356 if (dv == NULL) { 1357 return(NULL); 1358 } 1359 } 1360 dmabuf_size = SOC_DV_DMABUF_SIZE; 1361 dv->dv_dma_buf_size = dmabuf_size; 1362 /* Optionally allocate one word per DCB for Tx alignment */ 1363 if (soc_feature(unit, soc_feature_pkt_tx_align)) { 1364 dmabuf_size += 4 * cnt; 1365 } 1366 dv->dv_dmabuf = soc_cm_salloc(unit, dmabuf_size, 1367 "sdma_dmabuf_alloc"); 1368 if (dv->dv_dmabuf == NULL) { 1369 /* to release the free list */ 1370 soc_dma_free_list(unit); 1371 1372 dv->dv_dmabuf = soc_cm_salloc(unit, dmabuf_size, 1373 "sdma_dmabuf_alloc"); 1374 if (dv->dv_dmabuf == NULL) { 1375 soc_at_free(unit, dv); 1376 return(NULL); 1377 } 1378 } 1379 dv->dv_dcb = soc_cm_salloc(unit, SOC_DCB_SIZE(unit) * cnt, 1380 "sdma_dcb_alloc"); 1381 if (dv->dv_dcb == NULL) { 1382 /* to release the free list */ 1383 soc_dma_free_list(unit); 1384 1385 dv->dv_dcb = soc_cm_salloc(unit, SOC_DCB_SIZE(unit) * cnt, 1386 "sdma_dcb_alloc"); 1387 if (dv->dv_dcb == NULL) { 1388 soc_cm_sfree(unit, dv->dv_dmabuf); 1389 soc_at_free(unit, dv); 1390 return(NULL); 1391 } 1392 } 1393 dv->dv_unit = unit; 1394 dv->dv_cnt = cnt; 1395 dv->dv_flags = ((op == DV_TX) ? DV_F_COMBINE_DCB : 0); 1396 } 1397 1398 dv->dv_done_packet = NULL; 1399 dv->dv_done_desc = NULL; 1400 dv->dv_done_chain = NULL; 1401 dv->dv_magic = DV_MAGIC_NUMBER; 1402 soc_dma_dv_reset(op, dv); /* Reset standard fields */ 1403 dv->dv_public1.ptr = info; 1404 return(dv); 1405 } 1406 1407 /* 1408 * Function: 1409 * soc_dma_dv_alloc_by_port 1410 * Purpose: 1411 * Allocate and initialize a dv struct. 1412 * Parameters: 1413 * op - operations iov requested for. 1414 * cnt - number of DCBs required. 1415 * pkt_to_ports - number of ports to send to (specify if 1416 * sending more than SOC_DV_PKTS_MAX) 1417 * Notes: 1418 * If a DV on the free list will accomodate the request, 1419 * satisfy it from there to avoid extra alloc/free calls. 1420 */ 1421 1422 dv_t * 1423 soc_dma_dv_alloc_by_port(int unit, dvt_t op, int cnt, int pkt_to_ports) 1424 { 1425 uint32 soc_dma_lock; 1426 soc_control_t *soc = SOC_CONTROL(unit); 1427 dv_t *dv; 1428 uint32 dmabuf_size; 1429 int *dv_free_cnt; 1430 dv_t **dv_free; 1431 void *info = NULL; 1432 1433 if (pkt_to_ports <= 0) { /* not specified */ 1434 return soc_dma_dv_alloc(unit, op, cnt); 1435 } 1436 assert(cnt > 0); 1437 1438 /* Always bump up DCB count to free list size */ 1439 1440 if (cnt < soc->soc_dv_size) { 1441 cnt = soc->soc_dv_size; 1442 } 1443 if (pkt_to_ports < SOC_DV_PKTS_MAX) { 1444 pkt_to_ports = SOC_DV_PKTS_MAX; 1445 } 1446 /* Check if we can use one off the free list */ 1447 1448 SOC_DMA_LOCK(soc_dma_lock); 1449 if (op == DV_TX) { 1450 dv_free_cnt = &(soc->soc_dv_tx_free_cnt); 1451 dv_free = &(soc->soc_dv_tx_free); 1452 } else if (op == DV_RX) { 1453 dv_free_cnt = &(soc->soc_dv_rx_free_cnt); 1454 dv_free = &(soc->soc_dv_rx_free); 1455 } else { 1456 SOC_DMA_UNLOCK(soc_dma_lock); 1457 return NULL; 1458 } 1459 soc->stat.dv_alloc++; 1460 if ((cnt == soc->soc_dv_size) && 1461 ((*dv_free_cnt) > 0) && 1462 (pkt_to_ports == SOC_DV_PKTS_MAX)) { 1463 dv = (*dv_free); 1464 (*dv_free) = dv->dv_chain; 1465 (*dv_free_cnt)--; 1466 soc->stat.dv_alloc_q++; 1467 SOC_DMA_UNLOCK(soc_dma_lock); 1468 info = dv->dv_public1.ptr; 1469 } else { 1470 SOC_DMA_UNLOCK(soc_dma_lock); 1471 dv = soc_at_alloc(unit, sizeof(dv_t), "soc_dma_dv_alloc"); 1472 if (dv == NULL) { 1473 /* to release the free list */ 1474 soc_dma_free_list(unit); 1475 dv = soc_at_alloc(unit, sizeof(dv_t), "soc_dma_dv_alloc"); 1476 if (dv == NULL) { 1477 return(NULL); 1478 } 1479 } 1480 dmabuf_size = pkt_to_ports * SOC_DMA_BUF_LEN; 1481 dv->dv_dma_buf_size = dmabuf_size; 1482 /* Optionally allocate one word per DCB for Tx alignment */ 1483 if (soc_feature(unit, soc_feature_pkt_tx_align)) { 1484 dmabuf_size += 4 * cnt; 1485 } 1486 dv->dv_dmabuf = soc_cm_salloc(unit, dmabuf_size, 1487 "sdma_dmabuf_alloc"); 1488 if (dv->dv_dmabuf == NULL) { 1489 /* to release the free list */ 1490 soc_dma_free_list(unit); 1491 1492 dv->dv_dmabuf = soc_cm_salloc(unit, dmabuf_size, 1493 "sdma_dmabuf_alloc"); 1494 if (dv->dv_dmabuf == NULL) { 1495 soc_at_free(unit, dv); 1496 return(NULL); 1497 } 1498 } 1499 dv->dv_dcb = soc_cm_salloc(unit, SOC_DCB_SIZE(unit) * cnt, 1500 "sdma_dcb_alloc"); 1501 if (dv->dv_dcb == NULL) { 1502 /* to release the free list */ 1503 soc_dma_free_list(unit); 1504 dv->dv_dcb = soc_cm_salloc(unit, SOC_DCB_SIZE(unit) * cnt, 1505 "sdma_dcb_alloc"); 1506 if (dv->dv_dcb == NULL) { 1507 soc_cm_sfree(unit, dv->dv_dmabuf); 1508 soc_at_free(unit, dv); 1509 return(NULL); 1510 } 1511 } 1512 dv->dv_unit = unit; 1513 dv->dv_cnt = cnt; 1514 dv->dv_flags = ((op == DV_TX) ? DV_F_COMBINE_DCB : 0); 1515 } 1516 dv->dv_done_packet = NULL; 1517 dv->dv_done_desc = NULL; 1518 dv->dv_done_chain = NULL; 1519 dv->dv_magic = DV_MAGIC_NUMBER; 1520 soc_dma_dv_reset(op, dv); /* Reset standard fields */ 1521 dv->dv_public1.ptr = info; 1522 return(dv); 1523 } 1524 1525 /* 1526 * Function: 1527 * soc_dma_dv_free 1528 * Purpose: 1529 * Free a dv struct. 1530 * Parameters: 1531 * dv - pointer to dv to free (NOT a dv chain). 1532 * Returns: 1533 * Nothing. 1534 */ 1535 1536 void 1537 soc_dma_dv_free(int unit, dv_t *dv) 1538 { 1539 uint32 soc_dma_lock; 1540 soc_control_t *soc = SOC_CONTROL(unit); 1541 int *dv_free_cnt; 1542 dv_t **dv_free; 1543 1544 SOC_DMA_LOCK(soc_dma_lock); 1545 if (dv->dv_op == DV_TX) { 1546 dv_free_cnt = &(soc->soc_dv_tx_free_cnt); 1547 dv_free = &(soc->soc_dv_tx_free); 1548 } else { 1549 dv_free_cnt = &(soc->soc_dv_rx_free_cnt); 1550 dv_free = &(soc->soc_dv_rx_free); 1551 } 1552 1553 soc->stat.dv_free++; 1554 assert(dv->dv_magic == DV_MAGIC_NUMBER); 1555 if ((dv->dv_cnt == soc->soc_dv_size) && 1556 ((*dv_free_cnt) < soc->soc_dv_cnt)) { 1557 assert(dv); 1558 assert(dv->dv_dcb); 1559 dv->dv_chain = (*dv_free); 1560 (*dv_free) = dv; 1561 (*dv_free_cnt)++; 1562 SOC_DMA_UNLOCK(soc_dma_lock); 1563 } else { 1564 dv->dv_magic = 0; 1565 SOC_DMA_UNLOCK(soc_dma_lock); 1566 if (dv->dv_dcb) { 1567 soc_cm_sfree(unit, dv->dv_dcb); 1568 } 1569 soc_cm_sfree(unit, dv->dv_dmabuf); 1570 soc_at_free(unit, dv); 1571 } 1572 } 1573 1574 /* 1575 * Function: 1576 * soc_dma_done_reload 1577 * Purpose: 1578 * Process completion of a reload descriptor. 1579 * Continuous DMA only. 1580 * Parameters: 1581 * unit - soc unit 1582 * vchan - Virtual channel number. 1583 * Returns: 1584 * Nothing 1585 */ 1586 1587 dv_t * 1588 soc_dma_done_reload(int unit, uint32 vchan) 1589 { 1590 dma_chan_t c = (dma_chan_t)vchan; 1591 uint32 soc_dma_lock; 1592 soc_control_t *soc = SOC_CONTROL(unit); 1593 sdc_t *sc = &soc->soc_channels[c]; 1594 dv_t *dv_chain; /* Head of current chain */ 1595 1596 SOC_DMA_LOCK(soc_dma_lock); 1597 1598 assert(sc->sc_q_cnt > 0); /* Be sure there is at least one */ 1599 assert(sc->sc_q != NULL); /* And a pointer too */ 1600 1601 dv_chain = sc->sc_q; /* Pick up request */ 1602 sc->sc_q = sc->sc_q->dv_next; /* Unlink current DV */ 1603 1604 if (dv_chain->dv_done_reload == NULL) { 1605 LOG_WARN(BSL_LS_SOC_COMMON, 1606 (BSL_META_U(unit, 1607 "_soc_dma_done_reload: NULL callback: " 1608 "unit=%d chain=%p\n"), 1609 unit, (void *)dv_chain)); 1610 } else { 1611 dv_chain->dv_done_reload(unit, dv_chain); 1612 LOG_DEBUG(BSL_LS_SOC_COMMON, 1613 (BSL_META_U(unit, 1614 "_soc_dma_done_reload: calling dv_done_reload()" 1615 " unit=%d chain=%p\n"), 1616 unit, (void *)dv_chain)); 1617 } 1618 soc->stat.intr_reload++; 1619 sc->sc_q_cnt--; /* Decrement */ 1620 1621 /* DMA followed reload descriptor set next as active */ 1622 sc->sc_dv_active = sc->sc_q; 1623 1624 SOC_DMA_UNLOCK(soc_dma_lock); 1625 1626 return(sc->sc_dv_active); 1627 } 1628 1629 /* 1630 * Function: 1631 * soc_dma_process_done_desc 1632 * Purpose: 1633 * Process and make callouts for completed descriptors. 1634 * Parameters: 1635 * unit - SOC unit number 1636 * dv_chain - pointer to currently active dv chain 1637 * dv - pointer to next individual dv to process (MAY BE NULL). 1638 * Returns: 1639 * Pointer to next descriptor that is not yet complete, 1640 * NULL if list is complete. 1641 * Notes: 1642 * This is done at INTERRUPT LEVEL so we know no more 1643 * completion interrupts will arrive during processing. 1644 */ 1645 1646 STATIC dv_t * 1647 soc_dma_process_done_desc(int unit, dv_t *dv_chain, dv_t *dv) 1648 { 1649 dcb_t *dcb; 1650 int i; 1651 int tx = (dv_chain->dv_op == DV_TX); 1652 soc_stat_t *stat = &SOC_CONTROL(unit)->stat; 1653 uint32 flags, count; 1654 int is_rld_done; 1655 dv_t *dv_next = NULL; 1656 1657 /* Process all DCBs in the current DV */ 1658 while (dv != NULL) { 1659 1660 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 1661 (BSL_META_U(unit, 1662 "soc_dma_process_done_desc " 1663 "dv_chain=%p dv_active=%p\n"), 1664 (void *)dv_chain, (void *)dv)); 1665 1666 /* 1667 * Valid dv cnt checks 1668 * To avoid SOC_DCB_IDX2PTR to get a invalid dcb address 1669 */ 1670 assert(soc_dma_dv_cnt_valid(unit, dv) == TRUE); 1671 1672 /* Store the next dv pointer of the chain */ 1673 if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) { 1674 dv_next = dv->dv_next; 1675 } else { 1676 dv_next = dv->dv_chain; 1677 } 1678 1679 /* Clean cache of any dirty data */ 1680 soc_cm_sinval(unit, dv->dv_dcb, 1681 dv->dv_vcnt * SOC_DCB_SIZE(unit)); 1682 1683 for (i = dv->dv_dcnt; i < dv->dv_vcnt; i++) { 1684 dcb = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, i); 1685 flags = SOC_DCB_INTRINFO(unit, dcb, tx, &count); 1686 1687 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, /* VERBOSE */ 1688 (BSL_META_U(unit, 1689 "soc_dma_process_done_desc " 1690 "at %p flags=0x%x dcnt = %d vcnt = %d\n"), 1691 (void *)dcb, (uint32)flags, dv->dv_dcnt, dv->dv_vcnt)); 1692 1693 #ifdef INCLUDE_KNET 1694 if (SOC_KNET_MODE(unit) && 1695 (!tx || (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS && 1696 i == dv->dv_vcnt - 2))) { 1697 1698 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 1699 (BSL_META_U(unit, 1700 "soc_dma_process_done_desc" 1701 "KNET dv=%p\n"), 1702 (void *)dv)); 1703 1704 if ((count & SOC_DCB_KNET_DONE) == 0) { 1705 LOG_DEBUG(BSL_LS_SOC_PACKETDMA, 1706 (BSL_META_U(unit, 1707 "soc_dma_process_done_desc " 1708 "KNET NOT_DONE dv_chain=%p\n"), 1709 (void *)dv_chain)); 1710 /* Processing not complete in kernel */ 1711 dv->dv_dcnt = i; 1712 return(dv); 1713 } 1714 /* Mask off indicator for kernel processing done */ 1715 count &= ~SOC_DCB_KNET_DONE; 1716 LOG_DEBUG(BSL_LS_SOC_PACKETDMA, 1717 (BSL_META_U(unit, 1718 "soc_dma_process_done_desc " 1719 "KNET DONE dv_chain=%p\n"), 1720 (void *)dv_chain)); 1721 } 1722 #endif 1723 1724 /* Check for reload DCB */ 1725 if (SOC_DCB_RELOAD_GET(unit, dcb)) { 1726 LOG_DEBUG(BSL_LS_SOC_PACKETDMA, 1727 (BSL_META_U(unit, 1728 "soc_dma_process_done_desc " 1729 "(is rld) dv=%p dcb=%p\n"), 1730 (void *)dv, (void *)dcb)); 1731 if (cmic_drv[unit].chan_reload_done) { 1732 is_rld_done = 0; 1733 if(cmic_drv[unit].chan_reload_done(unit, 1734 dv->dv_channel, 1735 dcb, 1736 &is_rld_done)) { 1737 /* Error processing reload */ 1738 LOG_ERROR(BSL_LS_SOC_PACKETDMA, 1739 (BSL_META_U(unit, 1740 "Error procesing reload " 1741 "descriptor: c=%d dv=%p\n"), 1742 dv->dv_channel, (void *)dv)); 1743 } else { 1744 if (is_rld_done) { 1745 dv->dv_dcnt = i + 1; /* Count it as done */ 1746 1747 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 1748 (BSL_META_U(unit, 1749 "soc_dma_process_done_desc " 1750 "(rld_done) dv=%p dcb=%p\n"), 1751 (void *)dv, (void *)dcb)); 1752 1753 soc_dma_done_reload(unit, dv->dv_channel); 1754 break; 1755 } 1756 else { 1757 dv->dv_dcnt = i; 1758 return(dv); 1759 } 1760 } 1761 } 1762 } 1763 1764 if (flags) { 1765 if ((dv->dv_flags & DV_F_NOTIFY_DSC) && 1766 dv->dv_done_desc && 1767 DMA_LAST_DESC_DONE(unit, dv)) { 1768 LOG_DEBUG(BSL_LS_SOC_PACKETDMA, 1769 (BSL_META_U(unit, 1770 "soc_dma_process_done_desc " 1771 "(notify desc) dv=%p dcb=%p\n"), 1772 (void *)dv, (void *)dcb)); 1773 dv->dv_done_desc(unit, dv, dcb); 1774 } 1775 1776 if (tx) { 1777 stat->dma_tbyt += count; 1778 if (flags & SOC_DCB_INFO_PKTEND) { 1779 if (dv->dv_done_packet) { 1780 dv->dv_done_packet(unit, dv, dcb); 1781 } 1782 stat->dma_tpkt++; 1783 LOG_DEBUG(BSL_LS_SOC_PACKETDMA, 1784 (BSL_META_U(unit, 1785 "soc_dma_process_done_desc " 1786 "(tpkt) dv=%p dcb=%p\n"), 1787 (void *)dv, (void *)dcb)); 1788 } 1789 } else { 1790 1791 sal_vaddr_t addr = SOC_DCB_ADDR_GET(unit, dcb); 1792 /* Clean cache lines associated with Rx buffer */ 1793 soc_cm_sinval(unit, (void *)addr, count); 1794 1795 #define MIN_PAYLOAD_SIZE (64-4-12) /* 4:VLAN, 12: DA+SA */ 1796 stat->dma_rbyt += count; 1797 if (flags & SOC_DCB_INFO_PKTEND) { 1798 if (dv->dv_done_packet) { 1799 dv->dv_done_packet(unit, dv, dcb); 1800 } 1801 stat->dma_rpkt++; 1802 LOG_DEBUG(BSL_LS_SOC_PACKETDMA, 1803 (BSL_META_U(unit, 1804 "soc_dma_process_done_desc " 1805 "(rpkt) dcb=%p\n"), 1806 (void *)dcb)); 1807 } 1808 /* pkt size > dma_len & !pkt_end */ 1809 else if (count >= MIN_PAYLOAD_SIZE) { 1810 if (dv->dv_done_packet) { 1811 dv->dv_done_packet(unit, dv, dcb); 1812 LOG_DEBUG(BSL_LS_SOC_PACKETDMA, 1813 (BSL_META_U(unit, 1814 "soc_dma_process_done_desc " 1815 "(rpkt-partial) dcb=%p\n"), 1816 (void *)dcb)); 1817 } 1818 } 1819 } 1820 dv->dv_dcnt = i + 1; 1821 } else { /* No flags */ 1822 1823 dv->dv_dcnt = i; 1824 return(dv); 1825 } 1826 } /* for */ 1827 1828 LOG_DEBUG(BSL_LS_SOC_PACKETDMA, 1829 (BSL_META_U(unit, 1830 "soc_dma_process_done_desc " 1831 "dv_next = %p, dv_chain = %p, dcnt = %d, vcnt = %d\n"), 1832 (void *)dv->dv_next, (void *)dv->dv_chain, dv->dv_dcnt, dv->dv_vcnt)); 1833 /* Move to next dv */ 1834 dv = dv_next; 1835 } /* while */ 1836 1837 return(dv); 1838 } 1839 1840 /* 1841 * Function: 1842 * soc_dma_cmicx_done_desc 1843 * Purpose: 1844 * Process a completion of a DMA descriptor in cmicx devices. 1845 * Parameters: 1846 * unit - soc unit 1847 * vchan - Virtual channel number. 1848 * Returns: 1849 * Nothing 1850 * Notes: 1851 * INTERRUPT LEVEL ROUTINE 1852 */ 1853 1854 void 1855 soc_dma_cmicx_done_desc(int unit, uint32 vchan) 1856 { 1857 dma_chan_t c = (dma_chan_t)vchan; 1858 soc_control_t *soc = SOC_CONTROL(unit); 1859 sdc_t *sc = &soc->soc_channels[c]; 1860 dv_t *dv_chain = sc->sc_q; /* Pick up request */ 1861 dv_t *dv_active = sc->sc_dv_active; 1862 int flag = 0; 1863 1864 #ifdef INCLUDE_KNET 1865 if (SOC_KNET_MODE(unit)) { 1866 return; 1867 } 1868 #endif 1869 1870 assert(sc->sc_q_cnt); /* Be sure there is at least one */ 1871 assert(dv_chain); 1872 1873 if (!dv_active) { 1874 cmic_drv[unit].chan_desc_done(unit, vchan); 1875 flag = 1; 1876 } 1877 1878 if (flag == 0) { 1879 soc->stat.intr_desc++; 1880 1881 /* Clear interrupt */ 1882 cmic_drv[unit].chan_desc_done(unit, vchan); 1883 1884 /* 1885 * Reap done descriptors, and possibly notify callers of descriptor 1886 * completion. 1887 */ 1888 sc->sc_dv_active = 1889 soc_dma_process_done_desc(unit, dv_chain, dv_active); 1890 } 1891 1892 if (!(sc->sc_flags & SOC_DMA_F_POLL)) { 1893 cmic_drv[unit].chan_desc_done_intr_enable(unit, vchan); 1894 } 1895 } 1896 1897 /* 1898 * Function: 1899 * soc_dma_done_desc 1900 * Purpose: 1901 * Process a completion of a DMA descriptor. 1902 * Parameters: 1903 * unit - soc unit 1904 * vchan - Virtual channel number. 1905 * Returns: 1906 * Nothing 1907 * Notes: 1908 * INTERRUPT LEVEL ROUTINE 1909 */ 1910 1911 void 1912 soc_dma_done_desc(int unit, uint32 vchan) 1913 { 1914 dma_chan_t c = (dma_chan_t)vchan; 1915 soc_control_t *soc = SOC_CONTROL(unit); 1916 sdc_t *sc = &soc->soc_channels[c]; 1917 dv_t *dv_chain = sc->sc_q; /* Pick up request */ 1918 dv_t *dv_active = sc->sc_dv_active; 1919 1920 #ifdef INCLUDE_KNET 1921 if (SOC_KNET_MODE(unit)) { 1922 return; 1923 } 1924 #endif 1925 1926 assert(sc->sc_q_cnt); /* Be sure there is at least one */ 1927 assert(dv_chain); 1928 1929 if (!dv_active) { 1930 cmic_drv[unit].chan_desc_done(unit, vchan); 1931 return; 1932 } 1933 1934 soc->stat.intr_desc++; 1935 1936 /* Clear interrupt */ 1937 cmic_drv[unit].chan_desc_done(unit, vchan); 1938 1939 /* 1940 * Reap done descriptors, and possibly notify callers of descriptor 1941 * completion. 1942 */ 1943 sc->sc_dv_active = 1944 soc_dma_process_done_desc(unit, dv_chain, dv_active); 1945 } 1946 1947 /* 1948 * Function: 1949 * soc_dma_pci_timeout_handle 1950 * Purpose: 1951 * Process PCI timeout error. 1952 * Parameters: 1953 * unit number 1954 * data 1955 * Returns: 1956 * Nothing 1957 * Notes: 1958 * INTERRUPT LEVEL ROUTINE 1959 */ 1960 void 1961 soc_dma_pci_timeout_handle(int unit, uint32 data) 1962 { 1963 #if defined(BCM_ESW_SUPPORT) && defined(BCM_IPROC_SUPPORT) 1964 if (cmic_drv[unit].pci_timeout_handle != NULL) { 1965 (void)cmic_drv[unit].pci_timeout_handle(unit); 1966 } 1967 #endif 1968 } 1969 1970 /* 1971 * Function: 1972 * soc_dma_done_chain 1973 * Purpose: 1974 * Process a completion of a DMA operation. 1975 * Parameters: 1976 * s - pointer to socket structure. 1977 * vchan - Virtual channel number. 1978 * Returns: 1979 * Nothing 1980 * Notes: 1981 * INTERRUPT LEVEL ROUTINE 1982 */ 1983 1984 void 1985 soc_dma_done_chain(int unit, uint32 vchan) 1986 { 1987 dma_chan_t c = (dma_chan_t)vchan; 1988 uint32 soc_dma_lock; 1989 soc_control_t *soc = SOC_CONTROL(unit); 1990 sdc_t *sc = &soc->soc_channels[c]; 1991 dv_t *dv_chain; /* Head of current chain */ 1992 dv_t *dv_active; /* Current DV needed if DV chaining */ 1993 sdc_intr_mitigate_t *sdc_mtg; 1994 int diff; 1995 1996 #ifdef INCLUDE_KNET 1997 if (SOC_KNET_MODE(unit)) { 1998 return; 1999 } 2000 #endif 2001 2002 sdc_mtg = &soc_dma_intr_mitigation[unit].chans_intr_mitigation[c]; 2003 if (sdc_mtg->thread_running) { 2004 if (sdc_mtg->mitigation_started) { 2005 sdc_mtg->rx_chain_intr++; 2006 } else { 2007 sdc_mtg->cur_tm = sal_time_usecs(); 2008 diff = SAL_USECS_SUB(sdc_mtg->cur_tm, sdc_mtg->prev_tm); 2009 if ((diff < DMA_CHAIN_DONE_INTERVAL_USEC) && (diff > 0)) { 2010 sdc_mtg->mitigation_started = 1; 2011 sdc_mtg->cur_tm = sdc_mtg->prev_tm = 0; 2012 sal_sem_give(sdc_mtg->thread_sem); 2013 } else { 2014 sdc_mtg->prev_tm = sdc_mtg->cur_tm; 2015 } 2016 } 2017 } 2018 2019 assert(sc->sc_q_cnt > 0); /* Be sure there is at least one */ 2020 assert(sc->sc_q != NULL); /* And a pointer too */ 2021 2022 soc->stat.intr_chain++; 2023 2024 cmic_drv[unit].chan_chain_done(unit, vchan, sdc_mtg->mitigation_started); 2025 2026 SOC_DMA_LOCK(soc_dma_lock); 2027 2028 dv_chain = sc->sc_q; /* Pick up request */ 2029 dv_active = sc->sc_dv_active; /* DV in processing - MAY BE NULL */ 2030 sc->sc_q = dv_chain->dv_next; /* Unlink current DV */ 2031 sc->sc_q_cnt--; /* Decrement */ 2032 2033 soc_dma_start_channel(unit, sc); 2034 2035 SOC_DMA_UNLOCK(soc_dma_lock); 2036 2037 soc_dma_process_done_desc(unit, dv_chain, dv_active); 2038 2039 if (!soc_feature(unit, soc_feature_cmicx)) { 2040 assert(dv_chain->dv_dcnt == dv_chain->dv_vcnt); 2041 } 2042 2043 if (dv_chain->dv_flags & DV_F_NOTIFY_CHN) { 2044 if (dv_chain->dv_done_chain == NULL) { 2045 LOG_WARN(BSL_LS_SOC_PACKETDMA, 2046 (BSL_META_U(unit, 2047 "_soc_dma_done_chain: NULL callback: " 2048 "unit=%d chain=%p\n"), 2049 unit, (void *)dv_chain)); 2050 } else { 2051 dv_chain->dv_done_chain(unit, dv_chain); 2052 } 2053 } 2054 } 2055 2056 /* 2057 * Function: 2058 * soc_dma_desc_end_packet 2059 * Purpose: 2060 * Mark last descriptor in dv as end of packet. 2061 * Parameters: 2062 * dv - pointer to DMA I/O Vector to be affected. 2063 * Returns: 2064 * Nothing 2065 */ 2066 2067 void 2068 soc_dma_desc_end_packet(dv_t *dv) 2069 { 2070 dcb_t *d; 2071 2072 if (dv->dv_vcnt > 0) { 2073 d = SOC_DCB_IDX2PTR(dv->dv_unit, dv->dv_dcb, dv->dv_vcnt - 1); 2074 SOC_DCB_SG_SET(dv->dv_unit, d, 0); 2075 } 2076 } 2077 2078 /* Initialize basic port bitmaps and cos/crc (used to be flags) for 2079 * the SOC packet structure in the given DV. 2080 */ 2081 void 2082 soc_dma_dv_pkt_init(dv_t *dv, soc_pbmp_t pbmp, soc_pbmp_t ut_pbmp, 2083 soc_pbmp_t l3_pbmp, int cos, int crc) 2084 { 2085 sal_memset(&dv->tx_param, 0, sizeof(soc_tx_param_t)); 2086 dv->tx_param.cos = cos; 2087 dv->tx_param.prio_int = cos; /* By default, same as COS */ 2088 if (crc) { 2089 dv->tx_param.flags |= SOC_DMA_CRC_REGEN; 2090 } 2091 SOC_PBMP_ASSIGN(dv->tx_param.tx_pbmp, pbmp); 2092 SOC_PBMP_ASSIGN(dv->tx_param.tx_upbmp, ut_pbmp); 2093 SOC_PBMP_ASSIGN(dv->tx_param.tx_l3pbmp, l3_pbmp); 2094 2095 dv->tx_param.src_mod = SOC_DEFAULT_DMA_SRCMOD_GET(dv->dv_unit); 2096 dv->tx_param.src_port = SOC_DEFAULT_DMA_SRCPORT_GET(dv->dv_unit); 2097 dv->tx_param.pfm = SOC_DEFAULT_DMA_PFM_GET(dv->dv_unit); 2098 } 2099 2100 /* 2101 * Function: 2102 * soc_dma_desc_add 2103 * Purpose: 2104 * Add a DMA descriptor to a DMA chain independent of the 2105 * descriptor type. 2106 * Parameters: 2107 * dv - pointer to DMA I/O Vector to be filled in. 2108 * addr/cnt/pbmp/ubmp/l3pbm - values to add to the DMA chain. 2109 * flags - COS/CRC/ etc. 2110 * Returns: 2111 * < 0 - SOC_E_XXXX error code 2112 * >= 0 - # entries left that may be filled. 2113 * Notes: 2114 * Calls the specific fastpath routine if it can, defaulting 2115 * to a general routine. 2116 */ 2117 2118 int 2119 soc_dma_desc_add(dv_t *dv, sal_vaddr_t addr, uint16 cnt, pbmp_t pbmp, 2120 pbmp_t ubmp, pbmp_t l3pbm, uint32 flags, uint32 *hgh) 2121 { 2122 if (dv->dv_op == DV_TX) { 2123 return SOC_DCB_ADDTX(dv->dv_unit, dv, addr, cnt, 2124 pbmp, ubmp, l3pbm, flags, hgh); 2125 } else { 2126 return SOC_DCB_ADDRX(dv->dv_unit, dv, addr, cnt, flags); 2127 } 2128 } 2129 2130 /* 2131 * Function: 2132 * soc_dma_rld_desc_add 2133 * Puporse: 2134 * Append a RELOAD descriptor to the end of the given DV. 2135 * Parameters: 2136 * dv - pointer to DV to add descriptor to. 2137 * addr - address to reload to. If 0, set to self. 2138 * Returns: 2139 * < 0 - SOC_E_XXXX error code 2140 * >= 0 - # entries left that may be filled. 2141 * Notes: 2142 * For legacy DMA, the reload operations addr will have a value 2143 * != 0. To add the reload descriptor in continuous mode this 2144 * function is called with addr=0. The addr is updated 2145 * to point to itself to match the DMA halt addr. 2146 */ 2147 2148 int 2149 soc_dma_rld_desc_add(dv_t *dv, sal_vaddr_t addr) 2150 { 2151 int unit; 2152 dcb_t *d; 2153 int i = 0; 2154 2155 /* Make sure there's room for a reload descriptor */ 2156 if (dv->dv_vcnt == dv->dv_cnt) { 2157 return SOC_E_FULL; 2158 } 2159 2160 unit = dv->dv_unit; 2161 2162 if (addr == 0) { 2163 /* Setup chain for continuous mode */ 2164 2165 /* Set desc done intr bit in all dcbs */ 2166 for (i = 0; i < dv->dv_vcnt; i++) { 2167 d = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, i); 2168 /* No Chain Interrupt */ 2169 SOC_DCB_CHAIN_SET(unit, d, 1); 2170 /* For TX- only set controlled desc done intr in last packet DCB */ 2171 if (dv->dv_op == DV_TX) { 2172 if (i == dv->dv_vcnt - 1) { 2173 SOC_DCB_DESC_INTR_SET(unit, d, SOC_DCB_CNTLD_DESC_INTR); 2174 } 2175 } else { 2176 /* Set controlled desc done intr bit in all RX DCBs */ 2177 SOC_DCB_DESC_INTR_SET(unit, d, SOC_DCB_CNTLD_DESC_INTR); 2178 } 2179 2180 if (soc_property_get(unit, spn_PDMA_DESCRIPTOR_PREFETCH_ENABLE, 0)) { 2181 if (soc_feature(unit, soc_feature_cmicx)) { 2182 if (i != dv->dv_vcnt) { 2183 if ((dv->dv_vcnt - i) >= CMICX_DMA_CONTIGUOUS_DESCS) { 2184 SOC_DCB_DESC_REMAINING_SET(unit, d, CMICX_DMA_CONTIGUOUS_DESCS); 2185 } else { 2186 SOC_DCB_DESC_REMAINING_SET(unit, d, (dv->dv_vcnt - i)); 2187 } 2188 } 2189 } 2190 } 2191 } 2192 2193 /* Find the reload DCB and configure it */ 2194 d = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, dv->dv_vcnt); 2195 SOC_DCB_INIT(unit, d); 2196 2197 /* Set reload addr to self until next dv is concatenated */ 2198 addr = (sal_vaddr_t) d; 2199 SOC_DCB_ADDR_SET(unit, d, (sal_vaddr_t)addr); 2200 2201 /* Reload Bit */ 2202 SOC_DCB_RELOAD_SET(unit, d, 1); 2203 /* No Chain Done Interrupt */ 2204 SOC_DCB_CHAIN_SET(unit, d, 1); 2205 /* Controlled Desc Done Interrupt */ 2206 SOC_DCB_DESC_INTR_SET(unit, d, SOC_DCB_CNTLD_DESC_INTR); 2207 } else { 2208 /* Setup chain for legacy mode */ 2209 2210 if (dv->dv_vcnt > 0) { 2211 /* Set chain bit in previous */ 2212 d = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, dv->dv_vcnt - 1); 2213 SOC_DCB_CHAIN_SET(unit, d, 1); 2214 } 2215 2216 if (soc_property_get(unit, spn_PDMA_DESCRIPTOR_PREFETCH_ENABLE, 0)) { 2217 if (soc_feature(unit, soc_feature_cmicx)) { 2218 for (i = 0; i < dv->dv_vcnt; i++) { 2219 d = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, i); 2220 if (i != dv->dv_vcnt) { 2221 if ((dv->dv_vcnt - i) >= CMICX_DMA_CONTIGUOUS_DESCS) { 2222 SOC_DCB_DESC_REMAINING_SET(unit, d, CMICX_DMA_CONTIGUOUS_DESCS); 2223 } else { 2224 SOC_DCB_DESC_REMAINING_SET(unit, d, (dv->dv_vcnt - i)); 2225 } 2226 } 2227 } 2228 } 2229 } 2230 2231 d = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, dv->dv_vcnt); 2232 SOC_DCB_INIT(unit, d); 2233 SOC_DCB_RELOAD_SET(unit, d, 1); 2234 SOC_DCB_ADDR_SET(unit, d, addr); 2235 LOG_DEBUG(BSL_LS_SOC_PACKETDMA, (BSL_META_U(unit, "reload address = %p\n"), d)); 2236 } 2237 2238 dv->dv_vcnt++; 2239 return (dv->dv_cnt - dv->dv_vcnt); 2240 } 2241 2242 /* 2243 * Function: 2244 * soc_dma_contiguous_desc_add 2245 * Puporse: 2246 * Setup contiguous descriptors in a DV. 2247 * Parameters: 2248 * dv - pointer to DV to add descriptor to. 2249 * Returns: 2250 * < 0 - SOC_E_XXXX error code 2251 * >= 0 - Success. 2252 * Notes: 2253 * This is a new feature that is available in cmicx based devices. 2254 */ 2255 2256 int 2257 soc_dma_contiguous_desc_add(dv_t *dv) 2258 { 2259 int unit; 2260 dcb_t *d = NULL; 2261 int i = 0; 2262 2263 unit = dv->dv_unit; 2264 2265 LOG_DEBUG(BSL_LS_SOC_PACKETDMA, (BSL_META_U(unit, "\n desc count = %d \n") ,dv->dv_vcnt)); 2266 2267 if (soc_property_get(unit, spn_PDMA_DESCRIPTOR_PREFETCH_ENABLE, 0)) { 2268 if (soc_feature(unit, soc_feature_cmicx)) { 2269 for (i = 0; i < dv->dv_vcnt; i++) { 2270 d = SOC_DCB_IDX2PTR(unit, dv->dv_dcb, i); 2271 if ((dv->dv_vcnt - i) > CMICX_DMA_CONTIGUOUS_DESCS) { 2272 SOC_DCB_DESC_REMAINING_SET(unit, d, CMICX_DMA_CONTIGUOUS_DESCS); 2273 } else { 2274 SOC_DCB_DESC_REMAINING_SET(unit, d, (dv->dv_vcnt - i - 1)); 2275 } 2276 } 2277 } 2278 } 2279 2280 LOG_DEBUG(BSL_LS_SOC_PACKETDMA, (BSL_META_U(unit, "\n contiguous address end = %p\n"), d)); 2281 2282 return 0; 2283 } 2284 2285 /* 2286 * Function: 2287 * soc_dma_dv_join 2288 * Purpose: 2289 * Append src_chain to the end of dv_chain 2290 * Parameters: 2291 * dv_chain - pointer to DV chain to be appended to. 2292 * src_chain - pointer to DV chain to add. 2293 * Returns: 2294 * SOC_E_NONE - success 2295 * SOC_E_XXXX - error code. 2296 * Note: 2297 * src_chain is consumed and should not be further referenced. 2298 * If the last DCB in the chained list has the S/G 2299 * bit set, then the S/G bit is set in the RLD dcb. 2300 * The notification routines MUST be the same in all 2301 * elements of the list (this condition is asserted) 2302 */ 2303 2304 int 2305 soc_dma_dv_join(dv_t *dv_chain, dv_t *src_chain) 2306 { 2307 dcb_t *d; 2308 int unit; 2309 2310 assert(dv_chain); 2311 assert(src_chain); 2312 2313 unit = dv_chain->dv_unit; 2314 2315 /* Go to last dv in chain */ 2316 2317 while (dv_chain->dv_chain) { 2318 dv_chain = dv_chain->dv_chain; 2319 } 2320 2321 /* Make sure there's room for a reload descriptor */ 2322 2323 if (dv_chain->dv_vcnt == dv_chain->dv_cnt) { 2324 return SOC_E_FULL; 2325 } 2326 2327 /* Ensure the same notification callbacks are used */ 2328 2329 assert(dv_chain->dv_done_chain == src_chain->dv_done_chain); 2330 assert(dv_chain->dv_done_desc == src_chain->dv_done_desc); 2331 2332 /* Add reload descriptor */ 2333 2334 d = SOC_DCB_IDX2PTR(unit, dv_chain->dv_dcb, dv_chain->dv_vcnt); 2335 2336 SOC_DCB_INIT(unit, d); 2337 SOC_DCB_ADDR_SET(src_chain->dv_unit, d, (sal_vaddr_t)src_chain->dv_dcb); 2338 SOC_DCB_RELOAD_SET(unit, d, 1); /* Reload */ 2339 SOC_DCB_CHAIN_SET(unit, d, 1); /* Chain */ 2340 2341 /* Set chain bit in last DCB */ 2342 2343 if (dv_chain->dv_vcnt > 0) { 2344 d = SOC_DCB_IDX2PTR(unit, dv_chain->dv_dcb, dv_chain->dv_vcnt - 1); 2345 SOC_DCB_CHAIN_SET(unit, d, 1); 2346 } 2347 2348 dv_chain->dv_vcnt++; /* Increment valid count */ 2349 2350 /* Concatenate new chain */ 2351 2352 dv_chain->dv_chain = src_chain; 2353 2354 return SOC_E_NONE; 2355 } 2356 2357 /* 2358 * Function: 2359 * soc_dma_dv_reset 2360 * Purpose: 2361 * Reinitialize a dv struct to avoid free/alloc to reuse it. 2362 * Parameters: 2363 * op - operation type requested. 2364 * Returns: 2365 * Nothing. 2366 */ 2367 2368 void 2369 soc_dma_dv_reset(dvt_t op, dv_t *dv) 2370 { 2371 uint32 soc_dma_lock; 2372 2373 SOC_DMA_LOCK(soc_dma_lock); 2374 dv->dv_op = op; 2375 dv->dv_channel = -1; 2376 dv->dv_vcnt = 0; 2377 dv->dv_dcnt = 0; 2378 2379 /* don't clear all flags */ 2380 dv->dv_flags &= ~(DV_F_NOTIFY_DSC | DV_F_NOTIFY_CHN); 2381 dv->dv_chain = NULL; 2382 dv->dv_public1.ptr = NULL; 2383 dv->dv_public2.ptr = NULL; 2384 dv->dv_public3.ptr = NULL; 2385 dv->dv_public4.ptr = NULL; 2386 sal_memset(&dv->tx_param, 0, sizeof(soc_tx_param_t)); 2387 SOC_DMA_UNLOCK(soc_dma_lock); 2388 } 2389 2390 /* 2391 * Function: 2392 * soc_dma_chan_started_clear 2393 * Purpose: 2394 * Clear the dma_started var for the given channel 2395 * Parameters: 2396 * unit - SOC unit #. 2397 * vchan - Virtual channel # 2398 * Returns: 2399 * Nothing 2400 */ 2401 2402 void 2403 soc_dma_chan_started_clear(int unit, dma_chan_t vchan) 2404 { 2405 soc_control_t *soc = SOC_CONTROL(unit); 2406 sdc_t *sc = &soc->soc_channels[vchan]; 2407 uint32 soc_dma_lock; 2408 2409 SOC_DMA_LOCK(soc_dma_lock); 2410 if (sc->sc_dma_started != 0) { 2411 sc->sc_dma_started = 0; 2412 } 2413 SOC_DMA_UNLOCK(soc_dma_lock); 2414 } 2415 2416 /* 2417 * Function: 2418 * soc_dma_chan_config 2419 * Purpose: 2420 * Configure a particular DMA channel for RX/TX, and configure 2421 * appropriate modes. 2422 * Parameters: 2423 * unit - SOC unit #. 2424 * c - channel # 2425 * type - DV_TX/DV_RX 2426 * flags - SOC_DMA_F_XXX 2427 * Returns: 2428 * SOC_E_NONE - success 2429 * SOC_E_XXXX - error 2430 */ 2431 2432 int 2433 soc_dma_chan_config(int unit, dma_chan_t vchan, dvt_t type, uint32 flags) 2434 { 2435 uint32 soc_dma_lock; 2436 soc_control_t *soc = SOC_CONTROL(unit); 2437 sdc_t *sc = &soc->soc_channels[vchan]; 2438 2439 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 2440 (BSL_META_U(unit, 2441 "soc_dma_chan_config: c=%d type=%d\n"), vchan, type)); 2442 2443 assert(vchan >= 0 && vchan < soc->soc_dma_channels); 2444 assert(!(flags & ~(SOC_DMA_F_MBM | SOC_DMA_F_POLL | SOC_DMA_F_INTR_ON_DESC | 2445 SOC_DMA_F_TX_DROP | SOC_DMA_F_DEFAULT))); 2446 2447 SOC_DMA_LOCK(soc_dma_lock); 2448 2449 if ((DV_NONE != sc->sc_type) && (sc->sc_q_cnt != 0)) { 2450 SOC_DMA_UNLOCK(soc_dma_lock); 2451 return SOC_E_BUSY; /* Return busy if operations pending */ 2452 } 2453 2454 /* 2455 * Clear defaults if the channel under configuration is the 2456 * current default 2457 */ 2458 if ((sc->sc_type == DV_RX) && (soc->soc_dma_default_rx == sc)) { 2459 soc->soc_dma_default_rx->sc_flags &= ~SOC_DMA_F_DEFAULT; 2460 soc->soc_dma_default_rx = NULL; 2461 } else if ((sc->sc_type == DV_TX) && (soc->soc_dma_default_tx == sc)) { 2462 soc->soc_dma_default_tx->sc_flags &= ~SOC_DMA_F_DEFAULT; 2463 soc->soc_dma_default_tx = NULL; 2464 } 2465 2466 /* Initialize dummy Q entry */ 2467 2468 sc->sc_q = NULL; /* No queued operations */ 2469 sc->sc_dv_active = NULL; /* No active operations */ 2470 sc->sc_q_cnt = 0; /* Queue count starts at 0 */ 2471 sc->sc_dma_started = 0; /* For continuous mode only */ 2472 2473 cmic_drv[unit].chan_config(unit, vchan, type, flags); 2474 2475 sc->sc_flags = flags; 2476 2477 #ifdef GNATS_2371_WAR 2478 /* 2479 * remember if any channels are in drop_tx mode (gnats 2371 workaround) 2480 */ 2481 soc->dma_droptx = (cr & DC_DROP_TX_ALL) ? 1 : 0; 2482 #endif /* GNATS_2371_WAR */ 2483 2484 SOC_DMA_UNLOCK(soc_dma_lock); 2485 return SOC_E_NONE; 2486 } 2487 2488 /* 2489 * Function: 2490 * soc_dma_chan_counter_get 2491 * Purpose: 2492 * Obtain tx and rx packet counters for a channel 2493 * Parameters: 2494 * unit - SOC unit # 2495 * vchan - channel # 2496 * tx_pkt - tx packet counter 2497 * rx_pkt - rx packet counter 2498 * Returns: 2499 * SOC_E_NONE - success 2500 * SOC_E_XXXX - error 2501 */ 2502 2503 int 2504 soc_dma_chan_counter_get(int unit, dma_chan_t vchan, uint32 *tx_pkt, uint32 *rx_pkt) 2505 { 2506 uint32 soc_dma_lock; 2507 2508 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 2509 (BSL_META_U(unit, 2510 "soc_dma_chan_counter_get: c=%d \n"), vchan)); 2511 2512 SOC_DMA_LOCK(soc_dma_lock); 2513 2514 cmic_drv[unit].chan_counter_get(unit, vchan, tx_pkt, rx_pkt); 2515 2516 SOC_DMA_UNLOCK(soc_dma_lock); 2517 return SOC_E_NONE; 2518 } 2519 2520 /* 2521 * Function: 2522 * soc_dma_chan_counter_clear 2523 * Purpose: 2524 * Clear counters for a channel based on mask. 2525 * Can clear any combination of 2526 * tx, tx, rx drop counters. 2527 * Parameters: 2528 * unit - SOC unit # 2529 * vchan - channel # 2530 * mask - to decide which counter type 2531 * Returns: 2532 * SOC_E_NONE - success 2533 * SOC_E_XXXX - error 2534 */ 2535 2536 int 2537 soc_dma_chan_counter_clear(int unit, dma_chan_t vchan, uint32 mask) 2538 { 2539 uint32 soc_dma_lock; 2540 2541 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 2542 (BSL_META_U(unit, 2543 "soc_dma_chan_counter_clear: c=%d \n"), vchan)); 2544 2545 SOC_DMA_LOCK(soc_dma_lock); 2546 2547 cmic_drv[unit].chan_counter_clear(unit, vchan, mask); 2548 2549 SOC_DMA_UNLOCK(soc_dma_lock); 2550 return SOC_E_NONE; 2551 } 2552 2553 /* 2554 * Function: 2555 * soc_dma_cmc_counter_get 2556 * Purpose: 2557 * Obtain tx and rx packet counters for a cmc 2558 * Parameters: 2559 * unit - SOC unit # 2560 * cmc - cmc # 2561 * tx_pkt - tx packet counter 2562 * rx_pkt - rx packet counter 2563 * Returns: 2564 * SOC_E_NONE - success 2565 * SOC_E_XXXX - error 2566 */ 2567 2568 int 2569 soc_dma_cmc_counter_get(int unit, int cmc, uint32 *tx_pkt, uint32 *rx_pkt) 2570 { 2571 uint32 soc_dma_lock; 2572 2573 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 2574 (BSL_META_U(unit, 2575 "soc_dma_cmc_counter_get: cmc=%d \n"), cmc)); 2576 2577 SOC_DMA_LOCK(soc_dma_lock); 2578 2579 cmic_drv[unit].cmc_counter_get(unit, cmc, tx_pkt, rx_pkt); 2580 2581 SOC_DMA_UNLOCK(soc_dma_lock); 2582 return SOC_E_NONE; 2583 } 2584 2585 /* 2586 * Function: 2587 * soc_dma_cmc_counter_clear 2588 * Purpose: 2589 * Clear counters for a cmc based on mask. 2590 * Can clear any combination of 2591 * tx, tx, rx drop counters. 2592 * Parameters: 2593 * unit - SOC unit # 2594 * cmc - cmc # 2595 * mask - to decide which counter type 2596 * Returns: 2597 * SOC_E_NONE - success 2598 * SOC_E_XXXX - error 2599 */ 2600 2601 int 2602 soc_dma_cmc_counter_clear(int unit, int cmc, uint32 mask) 2603 { 2604 uint32 soc_dma_lock; 2605 2606 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 2607 (BSL_META_U(unit, 2608 "soc_dma_cmc_counter_clear: cmc=%d \n"), cmc)); 2609 2610 SOC_DMA_LOCK(soc_dma_lock); 2611 2612 cmic_drv[unit].cmc_counter_clear(unit, cmc, mask); 2613 2614 SOC_DMA_UNLOCK(soc_dma_lock); 2615 return SOC_E_NONE; 2616 } 2617 2618 /* 2619 * Function: 2620 * soc_dma_chan_cos_ctrl_get 2621 * Purpose: 2622 * Obtain cos ctrl value for a channel 2623 * Parameters: 2624 * unit - SOC unit # 2625 * vchan - channel # 2626 * cfg - to decide which cos ctrl register either 0 or 1 2627 * cos_ctrl - obtaining cos ctrl value by reference 2628 * Returns: 2629 * SOC_E_NONE - success 2630 * SOC_E_XXXX - error 2631 */ 2632 2633 int 2634 soc_dma_chan_cos_ctrl_get(int unit, dma_chan_t vchan, 2635 uint32 cfg, uint32 *cos_ctrl) 2636 { 2637 uint32 soc_dma_lock; 2638 2639 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 2640 (BSL_META_U(unit, 2641 "soc_dma_cos_ctrl_get: c=%d \n"), vchan)); 2642 2643 SOC_DMA_LOCK(soc_dma_lock); 2644 2645 cmic_drv[unit].chan_cos_ctrl_get(unit, vchan, cfg, cos_ctrl); 2646 2647 SOC_DMA_UNLOCK(soc_dma_lock); 2648 return SOC_E_NONE; 2649 } 2650 2651 /* 2652 * Function: 2653 * soc_dma_chan_cos_ctrl_set 2654 * Purpose: 2655 * Set cos ctrl value for a channel 2656 * Parameters: 2657 * unit - SOC unit # 2658 * vchan - channel # 2659 * cfg - to decide which cos ctrl register either 0 or 1 2660 * cos_ctrl - cos ctrl value to be set 2661 * Returns: 2662 * SOC_E_NONE - success 2663 * SOC_E_XXXX - error 2664 */ 2665 2666 int 2667 soc_dma_chan_cos_ctrl_set(int unit, dma_chan_t vchan, 2668 uint32 cfg, uint32 cos_ctrl) 2669 { 2670 uint32 soc_dma_lock; 2671 2672 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 2673 (BSL_META_U(unit, 2674 "soc_dma_cos_ctrl_set: c=%d \n"), vchan)); 2675 2676 SOC_DMA_LOCK(soc_dma_lock); 2677 2678 cmic_drv[unit].chan_cos_ctrl_set(unit, vchan, cfg, cos_ctrl); 2679 2680 SOC_DMA_UNLOCK(soc_dma_lock); 2681 return SOC_E_NONE; 2682 } 2683 2684 /* 2685 * Function: 2686 * soc_dma_cos_ctrl_queue_get 2687 * Purpose: 2688 * Set cos ctrl value for a channel 2689 * Parameters: 2690 * unit - SOC unit # 2691 * vchan - channel # 2692 * cfg - to decide which cos ctrl register either 0 or 1 2693 * cos_ctrl - cos ctrl value to be set 2694 * Returns: 2695 * SOC_E_NONE - success 2696 * SOC_E_XXXX - error 2697 */ 2698 2699 int 2700 soc_dma_cos_ctrl_queue_get(int unit, int cmc, int chan, 2701 int queue, uint32 *cos_ctrl) 2702 { 2703 uint32 soc_dma_lock; 2704 2705 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 2706 (BSL_META_U(unit, 2707 "soc_dma_cos_ctrl_queue_get: c=%d \n"), chan)); 2708 2709 SOC_DMA_LOCK(soc_dma_lock); 2710 2711 cmic_drv[unit].chan_cos_ctrl_queue_get(unit, cmc, chan, queue, cos_ctrl); 2712 2713 SOC_DMA_UNLOCK(soc_dma_lock); 2714 return SOC_E_NONE; 2715 } 2716 2717 /* 2718 * Function: 2719 * soc_dma_cos_ctrl_queue_get 2720 * Purpose: 2721 * Set cos ctrl value for a channel 2722 * Parameters: 2723 * unit - SOC unit # 2724 * vchan - channel # 2725 * cfg - to decide which cos ctrl register either 0 or 1 2726 * cos_ctrl - cos ctrl value to be set 2727 * Returns: 2728 * SOC_E_NONE - success 2729 * SOC_E_XXXX - error 2730 */ 2731 2732 int 2733 soc_dma_cos_ctrl_reg_addr_get(int unit, int cmc, int chan, 2734 int queue, uint32 *reg_addr) 2735 { 2736 uint32 soc_dma_lock; 2737 2738 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 2739 (BSL_META_U(unit, 2740 "soc_dma_cos_ctrl_reg_addr_get: c=%d \n"), chan)); 2741 2742 SOC_DMA_LOCK(soc_dma_lock); 2743 2744 cmic_drv[unit].chan_cos_ctrl_reg_addr_get(unit, cmc, chan, queue, reg_addr); 2745 2746 SOC_DMA_UNLOCK(soc_dma_lock); 2747 return SOC_E_NONE; 2748 } 2749 2750 /* 2751 * Function: 2752 * soc_dma_loopback_config 2753 * Purpose: 2754 * setup cmic to operate in loopback mode 2755 * Parameters: 2756 * unit - SOC unit # 2757 * cfg - to decide to put/remove cmic in loopback mode 2758 * Returns: 2759 * SOC_E_NONE - success 2760 * SOC_E_XXXX - error 2761 */ 2762 2763 int 2764 soc_dma_loopback_config(int unit, uint32 cfg) 2765 { 2766 uint32 soc_dma_lock; 2767 2768 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 2769 (BSL_META_U(unit, 2770 "soc_dma_loopback_config\n"))); 2771 2772 2773 SOC_DMA_LOCK(soc_dma_lock); 2774 2775 cmic_drv[unit].loopback_config(unit, cfg); 2776 2777 SOC_DMA_UNLOCK(soc_dma_lock); 2778 return SOC_E_NONE; 2779 } 2780 2781 /* 2782 * Function: 2783 * soc_dma_header_size_get 2784 * Purpose: 2785 * obtain ep to cpu header size 2786 * Parameters: 2787 * unit - SOC unit # 2788 * hdr_size - return value of the ep to cpu header size 2789 * Returns: 2790 * SOC_E_NONE - success 2791 * SOC_E_XXXX - error 2792 */ 2793 2794 int 2795 soc_dma_header_size_get(int unit, uint32 *hdr_size) 2796 { 2797 cmic_drv[unit].header_size_get(unit, hdr_size); 2798 2799 return SOC_E_NONE; 2800 } 2801 2802 /* 2803 * Function: 2804 * soc_dma_max_rx_channels_get 2805 * Purpose: 2806 * obtain maximum number of dma channels that can be used for BCM RX 2807 * Parameters: 2808 * unit - SOC unit # 2809 * max_rx_channels - maximum rx channels that can be used 2810 * Returns: 2811 * SOC_E_NONE - success 2812 * SOC_E_XXXX - error 2813 */ 2814 2815 int 2816 soc_dma_max_rx_channels_get(int unit, uint32 *max_rx_channels) 2817 { 2818 cmic_drv[unit].max_rx_channels_get(unit, max_rx_channels); 2819 2820 return SOC_E_NONE; 2821 } 2822 2823 /* 2824 * Function: 2825 * soc_dma_masks_get 2826 * Purpose: 2827 * obtain the individual big endian masks 2828 * Parameters: 2829 * unit - SOC unit # 2830 * pkt_endian - pkt endian mask 2831 * desc_endian - desc endian mask 2832 * header_endian - header endian mask 2833 * Returns: 2834 * SOC_E_NONE - success 2835 * SOC_E_XXXX - error 2836 */ 2837 2838 int 2839 soc_dma_masks_get(int unit, uint32 *pkt_endian, 2840 uint32 *desc_endian, uint32 *header_endian) 2841 { 2842 uint32 soc_dma_lock; 2843 2844 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 2845 (BSL_META_U(unit, 2846 "soc_dma_maks_get\n"))); 2847 2848 2849 SOC_DMA_LOCK(soc_dma_lock); 2850 2851 cmic_drv[unit].masks_get(unit, pkt_endian, 2852 desc_endian, header_endian); 2853 2854 SOC_DMA_UNLOCK(soc_dma_lock); 2855 return SOC_E_NONE; 2856 } 2857 2858 /* 2859 * Function: 2860 * soc_dma_chan_check_done 2861 * Purpose: 2862 * to check whether the channel done has completed 2863 * Parameters: 2864 * unit - SOC unit # 2865 * vchan - channel # 2866 * type - either chain done or desc done 2867 * detected - return value 2868 * Returns: 2869 * SOC_E_NONE - success 2870 * SOC_E_XXXX - error 2871 */ 2872 2873 int 2874 soc_dma_chan_poll_done(int unit, dma_chan_t vchan, 2875 soc_dma_poll_type_t type, 2876 int *detected) 2877 { 2878 uint32 soc_dma_lock; 2879 2880 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 2881 (BSL_META_U(unit, 2882 "soc_dma_chan_poll_done\n"))); 2883 2884 2885 SOC_DMA_LOCK(soc_dma_lock); 2886 2887 cmic_drv[unit].chan_poll(unit, vchan, type, detected); 2888 2889 SOC_DMA_UNLOCK(soc_dma_lock); 2890 return SOC_E_NONE; 2891 } 2892 2893 /* 2894 * Function: 2895 * soc_dma_chan_status_get 2896 * Purpose: 2897 * to obtain channel status 2898 * Parameters: 2899 * unit - SOC unit # 2900 * vchan - channel # 2901 * status - channel status 2902 * Returns: 2903 * SOC_E_NONE - success 2904 * SOC_E_XXXX - error 2905 */ 2906 2907 int 2908 soc_dma_chan_status_get(int unit, dma_chan_t vchan, 2909 uint32 mask, int *status) 2910 { 2911 uint32 soc_dma_lock; 2912 2913 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 2914 (BSL_META_U(unit, 2915 "soc_dma_chan_status_get\n"))); 2916 2917 SOC_DMA_LOCK(soc_dma_lock); 2918 2919 cmic_drv[unit].chan_status_get(unit, vchan, mask, status); 2920 2921 SOC_DMA_UNLOCK(soc_dma_lock); 2922 return SOC_E_NONE; 2923 } 2924 2925 /* 2926 * Function: 2927 * soc_dma_chan_status_clear 2928 * Purpose: 2929 * to clear channel status 2930 * Parameters: 2931 * unit - SOC unit # 2932 * vchan - channel # 2933 * Returns: 2934 * SOC_E_NONE - success 2935 * SOC_E_XXXX - error 2936 */ 2937 2938 int 2939 soc_dma_chan_status_clear(int unit, dma_chan_t vchan) 2940 { 2941 uint32 soc_dma_lock; 2942 2943 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 2944 (BSL_META_U(unit, 2945 "soc_dma_chan_status_clear\n"))); 2946 2947 SOC_DMA_LOCK(soc_dma_lock); 2948 2949 cmic_drv[unit].chan_status_clear(unit, vchan); 2950 2951 SOC_DMA_UNLOCK(soc_dma_lock); 2952 return SOC_E_NONE; 2953 } 2954 2955 /* 2956 * Function: 2957 * soc_dma_chan_halt_get 2958 * Purpose: 2959 * to obtain channel halt status 2960 * Parameters: 2961 * unit - SOC unit # 2962 * vchan - channel # 2963 * halt - halt status 2964 * Returns: 2965 * SOC_E_NONE - success 2966 * SOC_E_XXXX - error 2967 */ 2968 2969 int 2970 soc_dma_chan_halt_get(int unit, dma_chan_t vchan, 2971 uint32 mask, int *halt) 2972 { 2973 uint32 soc_dma_lock; 2974 2975 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 2976 (BSL_META_U(unit, 2977 "soc_dma_chan_halt_get\n"))); 2978 2979 SOC_DMA_LOCK(soc_dma_lock); 2980 2981 cmic_drv[unit].chan_halt_get(unit, vchan, mask, halt); 2982 2983 SOC_DMA_UNLOCK(soc_dma_lock); 2984 return SOC_E_NONE; 2985 } 2986 2987 /* 2988 * Function: 2989 * soc_dma_chan_ctrl_reg_get 2990 * Purpose: 2991 * to obtain channel control reg value 2992 * Parameters: 2993 * unit - SOC unit # 2994 * vchan - channel # 2995 * val - channel control reg value 2996 * Returns: 2997 * SOC_E_NONE - success 2998 * SOC_E_XXXX - error 2999 */ 3000 3001 int 3002 soc_dma_chan_ctrl_reg_get(int unit, dma_chan_t vchan, 3003 uint32 *val) 3004 { 3005 uint32 soc_dma_lock; 3006 3007 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 3008 (BSL_META_U(unit, 3009 "soc_dma_chan_ctrl_reg_get\n"))); 3010 3011 SOC_DMA_LOCK(soc_dma_lock); 3012 3013 cmic_drv[unit].chan_ctrl_reg_get(unit, vchan, val); 3014 3015 SOC_DMA_UNLOCK(soc_dma_lock); 3016 return SOC_E_NONE; 3017 } 3018 3019 /* 3020 * Function: 3021 * soc_dma_chan_ctrl_reg_set 3022 * Purpose: 3023 * to set channel control reg value 3024 * Parameters: 3025 * unit - SOC unit # 3026 * vchan - channel # 3027 * val - channel control reg value 3028 * Returns: 3029 * SOC_E_NONE - success 3030 * SOC_E_XXXX - error 3031 */ 3032 3033 int 3034 soc_dma_chan_ctrl_reg_set(int unit, dma_chan_t vchan, 3035 uint32 val) 3036 { 3037 uint32 soc_dma_lock; 3038 3039 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 3040 (BSL_META_U(unit, 3041 "soc_dma_chan_ctrl_reg_set\n"))); 3042 3043 SOC_DMA_LOCK(soc_dma_lock); 3044 3045 cmic_drv[unit].chan_ctrl_reg_set(unit, vchan, val); 3046 3047 SOC_DMA_UNLOCK(soc_dma_lock); 3048 return SOC_E_NONE; 3049 } 3050 3051 /* 3052 * Function: 3053 * soc_dma_chan_rxbuf_threshold_cfg 3054 * Purpose: 3055 * to set channel rxbuf threshold value 3056 * Parameters: 3057 * unit - SOC unit # 3058 * vchan - channel # 3059 * val - mmu backpressure value 3060 * Returns: 3061 * SOC_E_NONE - success 3062 * SOC_E_XXXX - error 3063 */ 3064 3065 int 3066 soc_dma_chan_rxbuf_threshold_cfg(int unit, dma_chan_t vchan, 3067 uint32 val) 3068 { 3069 uint32 soc_dma_lock; 3070 3071 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 3072 (BSL_META_U(unit, 3073 "soc_dma_chan_rxbuf_threshold_cfg\n"))); 3074 3075 SOC_DMA_LOCK(soc_dma_lock); 3076 3077 cmic_drv[unit].chan_rxbuf_threshold_cfg(unit, vchan, val); 3078 3079 SOC_DMA_UNLOCK(soc_dma_lock); 3080 return SOC_E_NONE; 3081 } 3082 3083 /* 3084 * Function: 3085 * soc_dma_cmc_rxbuf_threshold_cfg 3086 * Purpose: 3087 * to set cmc rxbuf threshold value 3088 * Parameters: 3089 * unit - SOC unit # 3090 * cmx - cmc # 3091 * val - mmu backpressure value 3092 * Returns: 3093 * SOC_E_NONE - success 3094 * SOC_E_XXXX - error 3095 */ 3096 3097 int 3098 soc_dma_cmc_rxbuf_threshold_cfg(int unit, int cmc, 3099 uint32 val) 3100 { 3101 uint32 soc_dma_lock; 3102 3103 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 3104 (BSL_META_U(unit, 3105 "soc_dma_cmc_rxbuf_threshold_cfg\n"))); 3106 3107 SOC_DMA_LOCK(soc_dma_lock); 3108 3109 cmic_drv[unit].cmc_rxbuf_threshold_cfg(unit, cmc, val); 3110 3111 SOC_DMA_UNLOCK(soc_dma_lock); 3112 return SOC_E_NONE; 3113 } 3114 3115 /* 3116 * Function: 3117 * soc_dma_free_list 3118 * Purpose: 3119 * Free everything on the cached DV list. 3120 * Parameters: 3121 * unit - StrataSwitch unit #. 3122 * Returns: 3123 * Nothing. 3124 */ 3125 STATIC void 3126 soc_dma_free_list(int unit) 3127 { 3128 uint32 soc_dma_lock; 3129 soc_control_t *soc = SOC_CONTROL(unit); 3130 dv_t *dv; 3131 3132 SOC_DMA_LOCK(soc_dma_lock); 3133 soc->soc_dv_tx_free_cnt = 0; /* Mark no TX free DVs on list */ 3134 dv = soc->soc_dv_tx_free; /* Pick up TX free list */ 3135 soc->soc_dv_tx_free = NULL; /* NULL list off soc structure */ 3136 SOC_DMA_UNLOCK(soc_dma_lock); 3137 3138 while (NULL != dv) { 3139 dv_t *tdv = dv->dv_chain; 3140 if (tx_dv_free_cb) { 3141 tx_dv_free_cb(unit, dv); 3142 } 3143 soc_cm_sfree(unit, dv->dv_dcb); 3144 soc_cm_sfree(unit, dv->dv_dmabuf); 3145 soc_at_free(unit, dv); 3146 dv = tdv; 3147 } 3148 3149 SOC_DMA_LOCK(soc_dma_lock); 3150 soc->soc_dv_rx_free_cnt = 0; /* Mark no RX free DVs on list */ 3151 dv = soc->soc_dv_rx_free; /* Pick up RX free list */ 3152 soc->soc_dv_rx_free = NULL; /* NULL list off soc structure */ 3153 SOC_DMA_UNLOCK(soc_dma_lock); 3154 3155 while (NULL != dv) { 3156 dv_t *rdv = dv->dv_chain; 3157 if (rx_dv_free_cb) { 3158 rx_dv_free_cb(unit, dv); 3159 } 3160 soc_cm_sfree(unit, dv->dv_dcb); 3161 soc_cm_sfree(unit, dv->dv_dmabuf); 3162 soc_at_free(unit, dv); 3163 dv = rdv; 3164 } 3165 } 3166 3167 /* 3168 * Function: 3169 * soc_dma_init 3170 * Purpose: 3171 * Initialize the SOC DMA routines for a SOC unit. 3172 * Parameters: 3173 * unit - SOC unit # 3174 * Returns: 3175 * SOC_E_NONE - Success 3176 * SOC_E_BUSY - DMA channel busy. 3177 * SOC_E_XXX 3178 * Notes: 3179 * This routine frees all DV's on the free list, and configures 3180 * a default channel configuration. 3181 */ 3182 3183 int 3184 soc_dma_init(int unit) 3185 { 3186 int channel_bitmap; 3187 uint32 flags = 0; 3188 #ifdef INCLUDE_KNET 3189 uint8 init_knet_hw = TRUE; 3190 #endif 3191 3192 soc_dma_free_list(unit); /* Free current DV list */ 3193 3194 /* Init the device */ 3195 cmic_drv[unit].init(unit); 3196 3197 channel_bitmap = soc_property_get(unit, 3198 spn_PKTDMA_POLL_MODE_CHANNEL_BITMAP, 0x0); 3199 flags = channel_bitmap & (1 << 0) ? SOC_DMA_F_MBM | SOC_DMA_F_DEFAULT | 3200 SOC_DMA_F_POLL : 3201 SOC_DMA_F_MBM | SOC_DMA_F_DEFAULT; 3202 3203 SOC_IF_ERROR_RETURN 3204 (soc_dma_chan_config(unit, 0, DV_TX, flags)); 3205 3206 flags = channel_bitmap & (1 << 1) ? SOC_DMA_F_MBM | SOC_DMA_F_DEFAULT | 3207 SOC_DMA_F_POLL : 3208 SOC_DMA_F_MBM | SOC_DMA_F_DEFAULT; 3209 SOC_IF_ERROR_RETURN 3210 (soc_dma_chan_config(unit, 1, DV_RX, flags)); 3211 3212 if (SOC_IS_DNX(unit)) 3213 { 3214 /** Init all channels on CMC0 except channel 0 as RX on Dune */ 3215 SOC_IF_ERROR_RETURN 3216 (soc_dma_chan_config(unit, 2, DV_RX, flags)); 3217 SOC_IF_ERROR_RETURN 3218 (soc_dma_chan_config(unit, 3, DV_RX, flags)); 3219 if (soc_feature(unit, soc_feature_cmicx)) { 3220 SOC_IF_ERROR_RETURN 3221 (soc_dma_chan_config(unit, 4, DV_RX, flags)); 3222 SOC_IF_ERROR_RETURN 3223 (soc_dma_chan_config(unit, 5, DV_RX, flags)); 3224 SOC_IF_ERROR_RETURN 3225 (soc_dma_chan_config(unit, 6, DV_RX, flags)); 3226 SOC_IF_ERROR_RETURN 3227 (soc_dma_chan_config(unit, 7, DV_RX, flags)); 3228 } 3229 } 3230 else 3231 { 3232 SOC_IF_ERROR_RETURN 3233 (soc_dma_chan_config(unit, 2, DV_NONE, SOC_DMA_F_MBM)); 3234 SOC_IF_ERROR_RETURN 3235 (soc_dma_chan_config(unit, 3, DV_NONE, SOC_DMA_F_MBM)); 3236 3237 if (soc_feature(unit, soc_feature_cmicx)) { 3238 SOC_IF_ERROR_RETURN 3239 (soc_dma_chan_config(unit, 4, DV_NONE, SOC_DMA_F_MBM)); 3240 SOC_IF_ERROR_RETURN 3241 (soc_dma_chan_config(unit, 5, DV_NONE, SOC_DMA_F_MBM)); 3242 SOC_IF_ERROR_RETURN 3243 (soc_dma_chan_config(unit, 6, DV_NONE, SOC_DMA_F_MBM)); 3244 SOC_IF_ERROR_RETURN 3245 (soc_dma_chan_config(unit, 7, DV_NONE, SOC_DMA_F_MBM)); 3246 } 3247 } 3248 3249 #ifdef INCLUDE_KNET 3250 3251 if (SOC_KNET_MODE(unit)) { 3252 if (SOC_WARM_BOOT(unit) && 3253 soc_property_get(unit, spn_WARMBOOT_KNET_SHUTDOWN_MODE, 0)) { 3254 init_knet_hw = FALSE; 3255 } 3256 if (soc_feature(unit, soc_feature_cos_rx_dma)) { 3257 /* Enable additional Rx DMA channels by default */ 3258 SOC_IF_ERROR_RETURN 3259 (soc_dma_chan_config(unit, 2, DV_RX, SOC_DMA_F_MBM)); 3260 SOC_IF_ERROR_RETURN 3261 (soc_dma_chan_config(unit, 3, DV_RX, SOC_DMA_F_MBM)); 3262 if (soc_feature(unit, soc_feature_cmicx)) { 3263 SOC_IF_ERROR_RETURN 3264 (soc_dma_chan_config(unit, 4, DV_RX, SOC_DMA_F_MBM)); 3265 SOC_IF_ERROR_RETURN 3266 (soc_dma_chan_config(unit, 5, DV_RX, SOC_DMA_F_MBM)); 3267 SOC_IF_ERROR_RETURN 3268 (soc_dma_chan_config(unit, 6, DV_RX, SOC_DMA_F_MBM)); 3269 SOC_IF_ERROR_RETURN 3270 (soc_dma_chan_config(unit, 7, DV_RX, SOC_DMA_F_MBM)); 3271 } 3272 #ifdef BCM_CMICM_SUPPORT 3273 if (soc_feature(unit, soc_feature_cmicm)) { 3274 /* COS-based DMA channel mapping always enabled */ 3275 } else 3276 #endif 3277 #ifdef BCM_CMICX_SUPPORT 3278 if (soc_feature(unit, soc_feature_cmicx)) { 3279 /* COS-based DMA channel mapping always enabled */ 3280 } else 3281 #endif 3282 { 3283 /* Enable COS-based DMA channel mapping */ 3284 soc_pci_write(unit, CMIC_CONFIG, 3285 (soc_pci_read(unit, CMIC_CONFIG) | 3286 CC_COS_QUALIFIED_DMA_RX_EN)); 3287 } 3288 } 3289 if (init_knet_hw) { 3290 soc_knet_hw_init(unit); 3291 } 3292 } 3293 #endif 3294 3295 return(SOC_E_NONE); 3296 } 3297 3298 #ifdef INCLUDE_KNET 3299 3300 STATIC void 3301 soc_dma_done_knet(int unit, sdc_t *sc) 3302 { 3303 dv_t *dv_chain; 3304 dv_t *dv_active; 3305 3306 assert(SOC_KNET_MODE(unit)); 3307 3308 /* 3309 * Reap done descriptors, and possibly notify callers of descriptor 3310 * completion. 3311 */ 3312 if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) { 3313 dv_chain = sc->sc_q; 3314 dv_active = sc->sc_dv_active; 3315 if (dv_chain && dv_active) { 3316 soc_dma_process_done_desc(unit, dv_chain, dv_active); 3317 } 3318 return; 3319 } 3320 3321 do { 3322 dv_chain = sc->sc_q; 3323 dv_active = sc->sc_dv_active; 3324 if (dv_active && sc->sc_q_cnt) { 3325 sc->sc_dv_active = 3326 soc_dma_process_done_desc(unit, dv_chain, dv_active); 3327 3328 if (dv_chain->dv_dcnt && 3329 dv_chain->dv_dcnt == dv_chain->dv_vcnt) { 3330 3331 sc->sc_q = dv_chain->dv_next; /* Unlink current DV */ 3332 sc->sc_q_cnt--; /* Decrement */ 3333 3334 soc_dma_start_channel(unit, sc); 3335 3336 if (dv_chain->dv_flags & DV_F_NOTIFY_CHN) { 3337 if (dv_chain->dv_done_chain) { 3338 dv_chain->dv_done_chain(unit, dv_chain); 3339 } 3340 } 3341 } 3342 } 3343 } while (sc->sc_dv_active != dv_active); 3344 } 3345 3346 STATIC int 3347 soc_dma_handle_knet_event(kcom_msg_t *kmsg, unsigned int len, void *cookie) 3348 { 3349 if (kmsg->hdr.type == KCOM_MSG_TYPE_EVT && 3350 kmsg->hdr.opcode == KCOM_M_DMA_INFO) { 3351 kcom_dma_info_t *dma_info = &kmsg->dma_info.dma_info; 3352 int unit = kmsg->hdr.unit; 3353 uint32 soc_dma_lock; 3354 soc_control_t *soc = SOC_CONTROL(unit); 3355 int chan; 3356 3357 LOG_VERBOSE(BSL_LS_SOC_COMMON, 3358 (BSL_META_U(unit, 3359 "soc_knet_handle_event: KCOM_M_DMA_INFO\n"))); 3360 3361 SOC_DMA_LOCK(soc_dma_lock); 3362 3363 if (dma_info->flags & KCOM_DMA_INFO_F_TX_DONE) { 3364 soc_dma_done_knet(unit, &soc->soc_channels[0]); 3365 } 3366 3367 if (dma_info->flags & KCOM_DMA_INFO_F_RX_DONE) { 3368 for (chan = 1; chan < soc->soc_max_channels; chan++) { 3369 soc_dma_done_knet(unit, &soc->soc_channels[chan]); 3370 } 3371 } 3372 3373 SOC_DMA_UNLOCK(soc_dma_lock); 3374 3375 /* Handled */ 3376 return 1; 3377 } 3378 /* Not handled */ 3379 return 0; 3380 } 3381 3382 #endif /* INCLUDE_KNET */ 3383 3384 /* 3385 * Function: 3386 * soc_dma_attach 3387 * Purpose: 3388 * Setup DMA structures when a device is attached. 3389 * Parameters: 3390 * unit - StrataSwitch unit #. 3391 * Returns: 3392 * SOC_E_NONE - Attached successful. 3393 * SOC_E_xxx - Attach failed. 3394 * Notes: 3395 * Initializes data structure without regards to the current fields, 3396 * calling this routine without detach first may result in memory 3397 * leaks. 3398 */ 3399 3400 int 3401 soc_dma_attach(int unit, int reset) 3402 { 3403 uint32 soc_dma_lock; 3404 soc_control_t *soc = SOC_CONTROL(unit); 3405 int i; 3406 3407 #ifdef INCLUDE_KNET 3408 if (soc_knet_init(unit) == SOC_E_NONE) { 3409 SOC_KNET_MODE_SET(unit, 1); 3410 soc_knet_rx_unregister(soc_dma_handle_knet_event); 3411 soc_knet_rx_register(soc_dma_handle_knet_event, NULL, 0); 3412 } 3413 #endif 3414 3415 soc->soc_dv_size = soc_property_get(unit, spn_PDMA_DV_FREE_SIZE, SOC_DMA_DV_FREE_SIZE); 3416 soc->soc_dv_cnt = soc_property_get(unit, spn_PDMA_DV_FREE_COUNT, SOC_DMA_DV_FREE_CNT); 3417 3418 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 3419 (BSL_META_U(unit, 3420 "DMA driver using dv size = %d and dv cnt = %d\n"), 3421 soc->soc_dv_size, soc->soc_dv_cnt)); 3422 3423 soc->stat.dv_alloc = 0; /* Init Alloc count */ 3424 soc->stat.dv_free = 0; /* Init Free count */ 3425 soc->stat.dv_alloc_q = 0; /* Init Alloc from Q count */ 3426 soc->soc_dv_tx_free_cnt = 0; /* Init Free list Q Count */ 3427 soc->soc_dv_rx_free_cnt = 0; 3428 soc->soc_dma_default_tx = NULL; 3429 soc->soc_dma_default_rx = NULL; 3430 if (soc_feature(unit, soc_feature_cmicm_multi_dma_cmc)) { 3431 soc->soc_max_channels = SOC_CMCS_NUM(unit) * N_DMA_CHAN; 3432 soc->soc_dma_channels = SOC_PCI_CMCS_NUM(unit) * N_DMA_CHAN; 3433 } else if (soc_feature(unit, soc_feature_cmicx)) { 3434 soc->soc_max_channels = SOC_CMCS_NUM(unit) * CMICX_N_DMA_CHAN; 3435 soc->soc_dma_channels = SOC_PCI_CMCS_NUM(unit) * CMICX_N_DMA_CHAN; 3436 } else { 3437 soc->soc_max_channels = N_DMA_CHAN; 3438 soc->soc_dma_channels = N_DMA_CHAN; 3439 } 3440 3441 soc->next_int0_cmc = 0; 3442 3443 #ifdef BCM_XGS3_SWITCH_SUPPORT 3444 if (soc_feature(unit, soc_feature_txdma_purge)) { 3445 /* 3446 * Allocate a 64 byte packet for TX purge packet 3447 */ 3448 if (soc->tx_purge_pkt == NULL) { 3449 soc->tx_purge_pkt = soc_cm_salloc(unit, 64, "tx_purge"); 3450 } 3451 } 3452 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 3453 3454 3455 /* Clear and Assign the driver interface */ 3456 sal_memset(&cmic_drv[unit], 0, sizeof(soc_cmic_dma_drv_t)); 3457 soc->stat.pci_cmpl_timeout = 0; 3458 #ifdef BCM_CMICDV2_SUPPORT 3459 if (soc_feature(unit, soc_feature_continuous_dma)) { 3460 if (soc_property_get(unit, spn_PDMA_CONTINUOUS_MODE_ENABLE, 0)) { 3461 soc_cmicd_dma_drv_init(unit, &cmic_drv[unit]); 3462 } else { 3463 soc_cmicm_dma_drv_init(unit, &cmic_drv[unit]); 3464 } 3465 } 3466 #endif 3467 3468 #ifdef BCM_CMICX_SUPPORT 3469 if (soc_feature(unit, soc_feature_cmicx)) { 3470 soc_cmicx_dma_drv_init(unit, &cmic_drv[unit]); 3471 } 3472 #endif 3473 3474 #ifdef BCM_CMICM_SUPPORT 3475 if ((cmic_drv[unit].init == 0) && 3476 soc_feature(unit, soc_feature_cmicm)) { 3477 soc_cmicm_dma_drv_init(unit, &cmic_drv[unit]); 3478 } 3479 #endif 3480 if (cmic_drv[unit].init == 0) { 3481 soc_cmice_dma_drv_init(unit, &cmic_drv[unit]); 3482 } 3483 3484 if (reset) { 3485 /* Init specifics */ 3486 cmic_drv[unit].ctrl_init(unit); 3487 } 3488 3489 for (i = 0; i < soc->soc_dma_channels; i++) { 3490 sdc_t *s = &soc->soc_channels[i]; 3491 int rv; 3492 3493 if (! reset) { 3494 /* 3495 * soc_dma_abort_channel does not require any data structures be set 3496 * up, it clears hardware state only. 3497 */ 3498 SOC_DMA_LOCK(soc_dma_lock); 3499 rv = soc_dma_abort_channel(unit, i); 3500 SOC_DMA_UNLOCK(soc_dma_lock); 3501 SOC_IF_ERROR_RETURN(rv); 3502 } 3503 3504 sal_memset(s, 0, sizeof(*s)); /* Start off 0 */ 3505 s->sc_type = DV_NONE; 3506 s->sc_channel = i; 3507 } 3508 SOC_IF_ERROR_RETURN(soc_dma_init(unit)); 3509 3510 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 3511 (BSL_META_U(unit, 3512 "Enabling %s DMA mode\n"), 3513 ((SOC_DMA_MODE(unit) == 3514 SOC_DMA_MODE_CONTINUOUS) ? "Continuous" : "Legacy Chained"))); 3515 3516 #ifdef INCLUDE_KNET 3517 if (SOC_KNET_MODE(unit)) { 3518 return SOC_E_NONE; 3519 } 3520 #endif 3521 3522 if (soc_property_get(unit, spn_DCB_INTR_MITIGATE_ENABLE, 0) && 3523 (!soc_dma_intr_mitigation[unit].enabled)) { 3524 char thread_name[32]; 3525 sal_memset(&soc_dma_intr_mitigation[unit], 0, 3526 sizeof(soc_dma_intr_mitigation[unit])); 3527 soc_dma_intr_mitigation[unit].enabled = 1; 3528 for (i = 0; i < soc->soc_dma_channels; i++) { 3529 sdc_t *s = &soc->soc_channels[i]; 3530 sdc_intr_mitigate_t *sdc_mtg; 3531 if (s->sc_type == DV_RX) { 3532 sdc_mtg = 3533 &soc_dma_intr_mitigation[unit].chans_intr_mitigation[i]; 3534 sal_sprintf(sdc_mtg->sem_name, "semDmaM%d_%d", 3535 unit, s->sc_channel); 3536 sdc_mtg->thread_sem = sal_sem_create(sdc_mtg->sem_name, 3537 0, 0); 3538 sal_sprintf(thread_name, "bcmDmaIntrM%d_%d", 3539 unit, s->sc_channel); 3540 sdc_mtg->thread_running = 1; 3541 sdc_mtg->thread_id = sal_thread_create(thread_name, 4096, 3542 soc_property_get(unit, spn_SOC_DMA_MONITOR_THREAD_PRI, 0), 3543 (void (*)(void*))soc_dma_monitor_thread, 3544 INT_TO_PTR(unit << 16 | s->sc_channel)); 3545 } 3546 } 3547 } 3548 return SOC_E_NONE; 3549 } 3550 3551 /* 3552 * Function: 3553 * soc_dma_detach 3554 * Purpose: 3555 * Abort DMA active on the specified channel, and free 3556 * internal memory associated with DMA on the specified unit. 3557 * It is up to the caller to ensure NO more DMAs are started. 3558 * Parameters: 3559 * unit - StrataSwitch Unit number 3560 * Returns: 3561 * SOC_E_TIMEOUT - indicates attempts to abort active 3562 * operations failed. Device is detached, but operation 3563 * is undefined at this point. 3564 * SOC_E_NONE - Operation sucessful. 3565 */ 3566 3567 int 3568 soc_dma_detach(int unit) 3569 { 3570 soc_control_t *soc = SOC_CONTROL(unit); 3571 (void)soc_dma_abort(unit); 3572 #ifdef BCM_XGS3_SWITCH_SUPPORT 3573 if (soc_feature(unit, soc_feature_txdma_purge)) { 3574 if (SOC_CONTROL(unit)->tx_purge_pkt != NULL) { 3575 soc_cm_sfree(unit, SOC_CONTROL(unit)->tx_purge_pkt); 3576 SOC_CONTROL(unit)->tx_purge_pkt = NULL; 3577 } 3578 } 3579 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 3580 soc_dma_free_list(unit); 3581 3582 if (soc_dma_intr_mitigation[unit].enabled) { 3583 int i; 3584 for (i = 0; i < soc->soc_dma_channels ; i++) { 3585 sdc_intr_mitigate_t *sdc_mtg = 3586 &soc_dma_intr_mitigation[unit].chans_intr_mitigation[i]; 3587 if (sdc_mtg->thread_running) { 3588 sdc_mtg->mitigation_started = 0; 3589 sdc_mtg->thread_running = 0; 3590 sdc_mtg->rx_chain_intr = sdc_mtg->rx_chain_intr_prev = 0; 3591 sal_sem_give(sdc_mtg->thread_sem); 3592 } 3593 } 3594 soc_dma_intr_mitigation[unit].enabled = 0; 3595 } 3596 return SOC_E_NONE; 3597 } 3598 3599 /* 3600 * Function: 3601 * soc_dma_poll_channel 3602 * Purpose: 3603 * Poll one, or ALL of the channels. 3604 * Parameters: 3605 * unit - StrataSwitch unit number. 3606 * c - DMA channel to poll 3607 * Returns: 3608 * Nothing 3609 */ 3610 3611 STATIC void 3612 soc_dma_poll_channel(int unit, dma_chan_t vchan) 3613 { 3614 uint32 soc_dma_lock; 3615 soc_control_t *soc = SOC_CONTROL(unit); 3616 sdc_t *sc = &soc->soc_channels[vchan]; 3617 int done_detected; 3618 3619 if (((sc->sc_flags & SOC_DMA_F_POLL)) && (sc->sc_dv_active)) { 3620 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 3621 (BSL_META_U(unit, 3622 "soc_dma_poll_channel: c=%d"), vchan)); 3623 /* 3624 * The _soc_dma_done_[desc|chain] routines expect to be called 3625 * ONLY from an interrupt handler since they may not always 3626 * grab the lock. 3627 */ 3628 SOC_DMA_LOCK(soc_dma_lock); 3629 3630 done_detected = 0; 3631 cmic_drv[unit].chan_poll(unit, vchan, 3632 SOC_DMA_POLL_DESC_DONE, 3633 &done_detected); 3634 3635 if (done_detected) { 3636 if (soc_feature(unit, soc_feature_cmicx)) { 3637 soc_dma_cmicx_done_desc(unit, (uint32)vchan); 3638 } else { 3639 soc_dma_done_desc(unit, (uint32)vchan); 3640 } 3641 soc->stat.intr_desc--; /* undo increment in done_desc */ 3642 } 3643 3644 done_detected = 0; 3645 cmic_drv[unit].chan_poll(unit, vchan, 3646 SOC_DMA_POLL_CHAIN_DONE, 3647 &done_detected); 3648 3649 if (done_detected) { 3650 soc_dma_done_chain(unit, (uint32)vchan); 3651 soc->stat.intr_chain--; /* undo increment in done_chain */ 3652 } 3653 3654 SOC_DMA_UNLOCK(soc_dma_lock); 3655 } 3656 } 3657 3658 /* 3659 * Function: 3660 * soc_dma_poll 3661 * Purpose: 3662 * Poll one, or all DMA channels. 3663 * Parameters: 3664 * unit - StrataSwitch unit #. 3665 * c - DMA channel to poll, or -1 3666 * Returns: 3667 * Nothing 3668 */ 3669 3670 void 3671 soc_dma_poll(int unit, dma_chan_t vchan) 3672 { 3673 soc_control_t *soc = SOC_CONTROL(unit); 3674 3675 assert(vchan < soc->soc_dma_channels); 3676 3677 if (vchan < 0) { 3678 for (vchan = 0; vchan < soc->soc_dma_channels; vchan++) { 3679 soc_dma_poll_channel(unit, vchan); 3680 } 3681 } else { 3682 soc_dma_poll_channel(unit, vchan); 3683 } 3684 } 3685 3686 /* 3687 * Reuse DV field. 3688 */ 3689 #define dv_sem dv_public4.ptr 3690 #define dv_poll dv_public4.ptr 3691 3692 /* 3693 * Function: 3694 * soc_dma_wait_done (Internal only) 3695 * Purpose: 3696 * Callout for DMA chain done. 3697 * Parameters: 3698 * unit - StrataSwitch Unit #. 3699 * dv_chain - Chain completed. 3700 * Returns: 3701 * Nothing 3702 */ 3703 3704 STATIC void 3705 soc_dma_wait_done(int unit, dv_t *dv_chain) 3706 { 3707 COMPILER_REFERENCE(unit); 3708 sal_sem_give((sal_sem_t)dv_chain->dv_sem); 3709 } 3710 3711 STATIC void 3712 soc_dma_wait_desc_done(int unit, dv_t *dv_chain, dcb_t *dcb) 3713 { 3714 COMPILER_REFERENCE(unit); 3715 3716 if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) { 3717 if (dv_chain->dv_done_desc_subs != NULL) { 3718 dv_chain->dv_done_desc_subs(unit, dv_chain, NULL); 3719 } 3720 } 3721 sal_sem_give((sal_sem_t)dv_chain->dv_sem); 3722 } 3723 3724 /* 3725 * Function: 3726 * soc_dma_poll_done (internal) 3727 * Purpose: 3728 * Callout for DMA chain done. 3729 * Parameters: 3730 * unit - StrataSwitch Unit #. 3731 * dv_chain - Chain completed. 3732 * Returns: 3733 * Nothing 3734 */ 3735 3736 STATIC void 3737 soc_dma_poll_done(int unit, dv_t *dv_chain) 3738 { 3739 COMPILER_REFERENCE(unit); 3740 *(volatile int *)dv_chain->dv_poll = TRUE; 3741 } 3742 3743 STATIC void 3744 soc_dma_poll_desc_done(int unit, dv_t *dv_chain, dcb_t *dcb) 3745 { 3746 COMPILER_REFERENCE(unit); 3747 *(volatile int *)dv_chain->dv_poll = TRUE; 3748 } 3749 3750 /* 3751 * Function: 3752 * soc_dma_wait 3753 * Purpose: 3754 * Start a DMA operation and wait for it's completion. 3755 * Parameters: 3756 * unit - StrataSwitch unit #. 3757 * dv_chain - pointer to dv chain to execute. 3758 * usec - Time out in microseconds. Same meanings as sal_sem_take 3759 * Returns: 3760 * SOC_E_XXXX 3761 */ 3762 3763 STATIC sal_tls_key_t *dma_sem_key = NULL; 3764 3765 STATIC void 3766 soc_dma_sem_free(void *param) 3767 { 3768 sal_sem_t sem = (sal_sem_t)param; 3769 3770 if (sem) { 3771 sal_sem_destroy(sem); 3772 } 3773 } 3774 3775 int 3776 soc_dma_wait_timeout(int unit, dv_t *dv_chain, int usec) 3777 { 3778 int rv = SOC_E_NONE; 3779 sdc_t *sc; 3780 volatile int done; 3781 sal_usecs_t start_time; 3782 int diff_time; 3783 3784 if ((sc = soc_dma_channel(unit, -1, dv_chain)) == NULL) { 3785 return(SOC_E_RESOURCE); 3786 } 3787 3788 /* If a polling channel, use POLLED mode */ 3789 3790 if ((sc->sc_flags & SOC_DMA_F_POLL) ) { 3791 dv_chain->dv_sem = NULL; 3792 dv_chain->dv_done_chain = soc_dma_poll_done; 3793 dv_chain->dv_done_desc = soc_dma_poll_desc_done; 3794 dv_chain->dv_poll = (void *) &done; 3795 done = FALSE; 3796 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 3797 (BSL_META_U(unit, 3798 "soc_dma_wait_timeout- Polled\n"))); 3799 } else { 3800 if (dma_sem_key == NULL) { 3801 dma_sem_key = sal_tls_key_create(soc_dma_sem_free); 3802 } 3803 dv_chain->dv_sem = sal_tls_key_get(dma_sem_key); 3804 if (dv_chain->dv_sem == NULL) { 3805 dv_chain->dv_sem = sal_sem_create("dv_sem", sal_sem_BINARY, 0); 3806 if (!dv_chain->dv_sem) { 3807 return(SOC_E_MEMORY); 3808 } 3809 sal_tls_key_set(dma_sem_key, (void *)dv_chain->dv_sem); 3810 } 3811 dv_chain->dv_done_chain = soc_dma_wait_done; 3812 dv_chain->dv_done_desc = soc_dma_wait_desc_done; 3813 LOG_VERBOSE(BSL_LS_SOC_PACKETDMA, 3814 (BSL_META_U(unit, 3815 "soc_dma_wait_timeout- Not polled\n"))); 3816 } 3817 3818 if (SOC_DMA_MODE(unit) == SOC_DMA_MODE_CONTINUOUS) { 3819 SET_NOTIFY_DSC_ONLY(dv_chain->dv_flags); 3820 } else { 3821 SET_NOTIFY_CHN_ONLY(dv_chain->dv_flags); 3822 } 3823 3824 rv = soc_dma_start_dv(unit, sc, dv_chain); 3825 if (SOC_FAILURE(rv)) { 3826 if (dma_sem_key == NULL) { 3827 if (dv_chain->dv_sem != NULL) { 3828 sal_sem_destroy((sal_sem_t)dv_chain->dv_sem); 3829 } 3830 } 3831 return rv; 3832 } 3833 3834 start_time = sal_time_usecs(); 3835 diff_time = 0; 3836 3837 if ((sc->sc_flags & SOC_DMA_F_POLL) ) { 3838 while (!done) { 3839 soc_dma_poll(unit, sc->sc_channel); 3840 if ((usec != sal_sem_FOREVER) && !done) { 3841 diff_time = SAL_USECS_SUB(sal_time_usecs(), start_time); 3842 if (diff_time > usec) { 3843 rv = SOC_E_TIMEOUT; 3844 break; 3845 } else if (diff_time < 0) { 3846 /* Restart in case system time changed */ 3847 start_time = sal_time_usecs(); 3848 } 3849 } 3850 } 3851 } else { 3852 if (sal_sem_take((sal_sem_t)dv_chain->dv_sem, sal_sem_FOREVER)) { 3853 (void)soc_dma_abort_dv(unit, dv_chain); /* Clean up */ 3854 rv = SOC_E_TIMEOUT; 3855 } 3856 if (dma_sem_key == NULL) { 3857 if (dv_chain->dv_sem != NULL) { 3858 sal_sem_destroy((sal_sem_t)dv_chain->dv_sem); 3859 } 3860 } 3861 } 3862 3863 return(rv); 3864 } 3865 3866 /* 3867 * Function: 3868 * soc_dma_wait 3869 * Purpose: 3870 * Start a DMA operation and wait for it's completion. 3871 * Parameters: 3872 * unit - StrataSwitch unit #. 3873 * dv_chain - pointer to dv chain to execute. 3874 * Returns: 3875 * SOC_E_XXXX 3876 */ 3877 3878 int 3879 soc_dma_wait(int unit, dv_t *dv_chain) 3880 { 3881 return soc_dma_wait_timeout(unit, dv_chain, sal_sem_FOREVER); 3882 } 3883 3884 /* 3885 * Function: 3886 * soc_dma_chan_dvt_get 3887 * Purpose: 3888 * Get the DV type for the given channel 3889 * Parameters: 3890 * unit 3891 * chan 3892 * Returns: 3893 * BCM_E_XXX 3894 * Notes: 3895 * Does not check if channel is valid 3896 */ 3897 3898 dvt_t 3899 soc_dma_chan_dvt_get(int unit, dma_chan_t vchan) 3900 { 3901 return SOC_CONTROL(unit)->soc_channels[vchan].sc_type; 3902 } 3903 3904 /*********************************************************************** 3905 * 3906 * Simple ROM TX/RX Mode 3907 * 3908 * The following API calls may be used in lieue of the regular calls in 3909 * order to provide a simplified, polling-driven transmit/receive API. 3910 * These routines are very inefficient, but they are easy to use and 3911 * don't require interrupt processing. 3912 * 3913 * soc_dma_rom_init() - configure chip for this mode 3914 * soc_dma_rom_detach() - deconfigure 3915 * soc_dma_rom_tx_start() - start a packet transmit; returns immediately 3916 * soc_dma_rom_tx_poll() - check if transmit is done yet 3917 * soc_dma_rom_tx_abort() - abort a transmit in progress 3918 * soc_dma_rom_rx_poll() - get receive packet, if any; returns immediately 3919 * 3920 * soc_dma_rom_dcb_alloc() - utility routine for creating packet descriptor 3921 * soc_dma_rom_dcb_free() - utility routine for freeing packet descriptor 3922 */ 3923 3924 /* 3925 * Variable: 3926 * soc_dma_rom_control 3927 * Purpose: 3928 * Global control variables for the soc_dma_rom API. 3929 */ 3930 3931 static struct { 3932 struct { 3933 dv_t *dv; 3934 volatile int done; 3935 } tx, rx; 3936 int psize; 3937 } soc_dma_rom_control[SOC_MAX_NUM_DEVICES]; 3938 3939 /* 3940 * Function: 3941 * soc_dma_rom_dcb_alloc 3942 * Purpose: 3943 * Allocate a DCB packet structure for use with RX and TX functions. 3944 * Parameters: 3945 * unit - unit number 3946 * psize - packet buffer size 3947 * Returns: 3948 * DCB pointer on success, NULL on failure. 3949 * Notes: 3950 * Use this function to allocate a DCB structure and associated 3951 * packet memory. A packet buffer of size 'psize' will be 3952 * allocated and associated with this DCB. 3953 */ 3954 3955 dcb_t * 3956 soc_dma_rom_dcb_alloc(int unit, int psize) 3957 { 3958 void *pkt; 3959 dcb_t *dcb; 3960 3961 if ((dcb = soc_cm_salloc(unit, 3962 SOC_DCB_SIZE(unit), 3963 "soc_dma_rom_dcb_alloc")) == NULL) { 3964 return NULL; 3965 } 3966 3967 if ((pkt = soc_cm_salloc(unit, 3968 psize, 3969 "soc_dma_rom_dcb_alloc_packet")) == NULL) { 3970 soc_cm_sfree(unit, dcb); 3971 return NULL; 3972 } 3973 3974 /* Setup DCB defaults */ 3975 sal_memset(dcb, 0, SOC_DCB_SIZE(unit)); 3976 SOC_DCB_INIT(unit, dcb); 3977 SOC_DCB_ADDR_SET(unit, dcb, (sal_vaddr_t)pkt); 3978 SOC_DCB_REQCOUNT_SET(unit, dcb, psize); 3979 SOC_DCB_SG_SET(unit, dcb, 0); 3980 SOC_DCB_CHAIN_SET(unit, dcb, 0); 3981 3982 /* Everything else should be specified by the caller */ 3983 return dcb; 3984 } 3985 3986 /* 3987 * Function: 3988 * soc_dma_rom_dcb_free 3989 * Purpose: 3990 * Free a DCB packet structure allocated with soc_dma_rom_dcb_free() 3991 * Parameters: 3992 * unit - unit number 3993 * dcb - dcb pointer 3994 * Returns: 3995 * SOC_E_XXX 3996 */ 3997 3998 int 3999 soc_dma_rom_dcb_free(int unit, dcb_t *dcb) 4000 { 4001 if (dcb) { 4002 void *pkt; 4003 4004 pkt = (void *)SOC_DCB_ADDR_GET(unit, dcb); 4005 4006 if (pkt != NULL) { 4007 soc_cm_sfree(unit, pkt); 4008 } 4009 4010 soc_cm_sfree(unit, dcb); 4011 } 4012 4013 return SOC_E_NONE; 4014 } 4015 4016 /* 4017 * Function: 4018 * soc_dma_rom_dv_start_polled 4019 * Purpose: 4020 * Start an asyncronous, polled DV DMA op 4021 * Parameters: 4022 * unit - unit 4023 * channel - channel to start on 4024 * dv - dv 4025 * poll - pointer to poll-done variable 4026 * Returns: 4027 * SOC_E_XXX 4028 * Notes: 4029 * Helper function for soc_dma_rom() rx and tx. 4030 */ 4031 4032 static int 4033 soc_dma_rom_dv_start_polled(int unit, int vchan, 4034 dv_t *dv, volatile void *poll) 4035 { 4036 assert(dv); 4037 4038 /* Setup chain-done notification */ 4039 4040 dv->dv_flags |= DV_F_NOTIFY_CHN; 4041 dv->dv_sem = NULL; 4042 dv->dv_done_chain = soc_dma_poll_done; 4043 dv->dv_poll = (void *)poll; 4044 4045 /* Start up this chain */ 4046 4047 return soc_dma_start(unit, vchan, dv); 4048 } 4049 4050 /* 4051 * Function: 4052 * soc_dma_rom_rx_start 4053 * Purpose: 4054 * Start one packet DMA rx 4055 * Parameters: 4056 * unit - unit 4057 * Returns: 4058 * SOC_E_XXX 4059 */ 4060 4061 static int 4062 soc_dma_rom_rx_start(int unit) 4063 { 4064 dv_t *dv; 4065 int rv; 4066 4067 /* Get our RX DV */ 4068 4069 if ((dv = soc_dma_rom_control[unit].rx.dv) == NULL) { 4070 return SOC_E_INIT; 4071 } 4072 4073 /* Reset our DV */ 4074 4075 soc_dma_dv_reset(DV_RX, dv); 4076 4077 /* Allocate a DCB/packet structure */ 4078 4079 dv->dv_dcb = soc_dma_rom_dcb_alloc(unit, 4080 soc_dma_rom_control[unit].psize); 4081 4082 /* Bring it on */ 4083 4084 if ((rv = soc_dma_rom_dv_start_polled(unit, SOC_DMA_ROM_RX_CHANNEL, dv, 4085 &soc_dma_rom_control[unit].rx.done)) < 0) { 4086 /* D'oh */ 4087 soc_dma_rom_dcb_free(unit, dv->dv_dcb); 4088 4089 dv->dv_dcb = NULL; 4090 4091 return rv; 4092 } 4093 4094 return rv; 4095 } 4096 4097 4098 4099 /* 4100 * Function: 4101 * soc_dma_rom_init 4102 * Purpose: 4103 * Initialize simple polled tx/rx (ROM mode). 4104 * Parameters: 4105 * unit - StrataSwitch unit # 4106 * max_packet_rx - Maximum RX packet size 4107 * Returns: 4108 * SOC_E_XXX 4109 */ 4110 4111 int 4112 soc_dma_rom_init(int unit, int max_packet_rx, int tx, int rx) 4113 { 4114 dv_t *dv_rx, *dv_tx; 4115 4116 sal_memset(&soc_dma_rom_control[unit], 0, 4117 sizeof(soc_dma_rom_control[unit])); 4118 4119 /* Reconfigure TX/RX channels for polling */ 4120 4121 if (tx) { 4122 SOC_IF_ERROR_RETURN( 4123 soc_dma_chan_config(unit, SOC_DMA_ROM_TX_CHANNEL, DV_TX, 4124 SOC_DMA_F_MBM | SOC_DMA_F_POLL | SOC_DMA_F_DEFAULT)); 4125 } 4126 4127 if (rx) { 4128 SOC_IF_ERROR_RETURN( 4129 soc_dma_chan_config(unit, SOC_DMA_ROM_RX_CHANNEL, DV_RX, 4130 SOC_DMA_F_MBM | SOC_DMA_F_POLL | SOC_DMA_F_DEFAULT)); 4131 } 4132 4133 soc_dma_rom_control[unit].psize = max_packet_rx; 4134 4135 /* Allocate our TX/RX DVs */ 4136 4137 if ((dv_rx = soc_dma_dv_alloc(unit, DV_RX, 1)) == NULL) { 4138 return SOC_E_MEMORY; 4139 } 4140 4141 if ((dv_tx = soc_dma_dv_alloc(unit, DV_TX, 1)) == NULL) { 4142 soc_dma_dv_free(unit, dv_rx); 4143 return SOC_E_MEMORY; 4144 } 4145 4146 /* 4147 * We play around with the DCB in these DVs quite a bit. Free the 4148 * originals so we can muck with it later. 4149 */ 4150 4151 soc_cm_sfree(unit, dv_rx->dv_dcb); 4152 soc_cm_sfree(unit, dv_tx->dv_dcb); 4153 4154 /* Store our new DVs */ 4155 4156 soc_dma_rom_control[unit].rx.dv = dv_rx; 4157 soc_dma_rom_control[unit].tx.dv = dv_tx; 4158 4159 /* Startup an RX */ 4160 4161 if (rx) { 4162 soc_dma_rom_rx_start(unit); 4163 } 4164 4165 /* No TX's outstanding */ 4166 4167 soc_dma_rom_control[unit].tx.done = 1; 4168 4169 return SOC_E_NONE; 4170 } 4171 4172 /* 4173 * Function: 4174 * soc_dma_rom_detach 4175 * Purpose: 4176 * Finalize the polled TX/RX module 4177 * Parameters: 4178 * unit - StrataSwitch unit # 4179 * Returns: 4180 * SOC_E_XXX 4181 */ 4182 4183 int 4184 soc_dma_rom_detach(int unit) 4185 { 4186 int rv; 4187 dv_t *dv; 4188 4189 /* Kill DMA */ 4190 4191 rv = soc_dma_detach(unit); 4192 4193 /* 4194 * Free our buffers We need to free our custom packet DCBs, then 4195 * replace the DV's dcb pointer which we freed at init time with a 4196 * new pointer before we hand it back. 4197 */ 4198 4199 dv = soc_dma_rom_control[unit].rx.dv; 4200 4201 /* Free our RX DCB */ 4202 4203 if (dv->dv_dcb) { 4204 soc_dma_rom_dcb_free(unit, dv->dv_dcb); 4205 } 4206 4207 dv->dv_dcb = soc_cm_salloc(unit, SOC_DCB_SIZE(unit), "sdma_dv_alloc"); 4208 4209 dv = soc_dma_rom_control[unit].tx.dv; 4210 4211 /* 4212 * Do not deallocate the DCB associated with TX. 4213 * This was allocated by the caller. 4214 */ 4215 4216 dv->dv_dcb = soc_cm_salloc(unit, SOC_DCB_SIZE(unit), "sdma_dv_alloc"); 4217 4218 sal_memset(&soc_dma_rom_control[unit], 0, 4219 sizeof(soc_dma_rom_control[unit])); 4220 4221 return rv; 4222 } 4223 4224 /* 4225 * Function: 4226 * soc_dma_rom_tx_start 4227 * Purpose: 4228 * Kick off a packet transmit (ROM mode) 4229 * Parameters: 4230 * unit - StrataSwitch unit # 4231 * dcb - Device specific DMA descriptor block structure 4232 * Notes: 4233 * This function will transmit one packet as described by the dcb 4234 * parameter. 4235 * 4236 * The DCB packet structure should be allocated using 4237 * soc_dma_rom_dcb_alloc(). 4238 * 4239 * The caller must setup the DCB structure correctly for the chip 4240 * on which the packet will be transmitted. On the BCM5670 the 4241 * packet data must contain the Higig header. 4242 * 4243 * This routine does not wait for transmit complete. Use 4244 * soc_dma_rom_tx_poll() to determine transmit completion. 4245 * 4246 * The application may not re-use the dcb or packet buffer memory 4247 * or transmit any other packets until the transmit is complete. 4248 */ 4249 4250 int 4251 soc_dma_rom_tx_start(int unit, dcb_t *dcb) 4252 { 4253 dv_t *dv; 4254 4255 /* Get our TX DV */ 4256 4257 if ((dv = soc_dma_rom_control[unit].tx.dv) == NULL) { 4258 return SOC_E_INIT; 4259 } 4260 4261 /* Reset our DV */ 4262 soc_dma_dv_reset(DV_TX, dv); 4263 4264 /* Our DCB has already been allocated. Drop it in our DV. */ 4265 4266 dv->dv_dcb = dcb; 4267 dv->dv_vcnt = 1; 4268 4269 /* Send it */ 4270 4271 soc_dma_rom_control[unit].tx.done = 0; 4272 4273 return soc_dma_rom_dv_start_polled(unit, SOC_DMA_ROM_TX_CHANNEL, 4274 dv, 4275 &soc_dma_rom_control[unit].tx.done); 4276 } 4277 4278 /* 4279 * Function: 4280 * soc_dma_rom_tx_poll 4281 * Purpose: 4282 * Indicate whether previous transmit with soc_dma_rom_tx_start() 4283 * has completed. 4284 * Parameters: 4285 * unit - StrataSwitch unit # 4286 * done - (OUT) TRUE or FALSE, indicating whether transmit was done 4287 * Returns: 4288 * SOC_E_XXX 4289 * Notes: 4290 * After completion, the original DCB and packet memory may be reused. 4291 */ 4292 4293 int 4294 soc_dma_rom_tx_poll(int unit, int *done) 4295 { 4296 soc_dma_poll(unit, SOC_DMA_ROM_TX_CHANNEL); 4297 4298 *done = soc_dma_rom_control[unit].tx.done; 4299 4300 return SOC_E_NONE; 4301 } 4302 4303 /* 4304 * Function: 4305 * soc_dma_rom_tx_abort 4306 * Purpose: 4307 * Abort a transmit in progress. 4308 * Parameters: 4309 * unit - StrataSwitch unit # 4310 * Returns: 4311 * SOC_E_XXX 4312 */ 4313 4314 int 4315 soc_dma_rom_tx_abort(int unit) 4316 { 4317 if (soc_dma_rom_control[unit].tx.done == 0) { 4318 soc_dma_rom_control[unit].tx.done = 1; 4319 return soc_dma_abort_channel(unit, SOC_DMA_ROM_TX_CHANNEL); 4320 } 4321 4322 return SOC_E_NONE; 4323 } 4324 4325 4326 /* 4327 * Function: 4328 * soc_dma_rom_rx_poll 4329 * Purpose: 4330 * See if a packet is waiting, and it so, return it 4331 * Parameters: 4332 * unit - StrataSwitch unit # 4333 * dcb - (OUT) The packet's associated dcb, NULL if no packet ready. 4334 * Returns: 4335 * SOC_E_XXX 4336 * Notes: 4337 * The caller must parse the DCB structure to retrieve the 4338 * the packet information. 4339 * 4340 * The caller must call soc_dma_rom_dcb_free() when done with 4341 * this packet. 4342 */ 4343 4344 int 4345 soc_dma_rom_rx_poll(int unit, dcb_t **dcb) 4346 { 4347 /* Has our last RX DMA completed? */ 4348 4349 soc_dma_poll(unit, SOC_DMA_ROM_RX_CHANNEL); 4350 4351 if (soc_dma_rom_control[unit].rx.done) { 4352 /* Packet received. Pull out the DCB */ 4353 4354 *dcb = soc_dma_rom_control[unit].rx.dv->dv_dcb; 4355 soc_dma_rom_control[unit].rx.dv->dv_dcb = NULL; 4356 soc_dma_rom_control[unit].rx.done = 0; 4357 4358 /* Start another DMA */ 4359 4360 soc_dma_rom_rx_start(unit); 4361 } else { 4362 *dcb = NULL; 4363 } 4364 4365 return SOC_E_NONE; 4366 } 4367 4368 #endif /* BCM_CMIC_SUPPORT */