1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include "nge.h" 28 29 #define TXD_OWN 0x80000000 30 #define TXD_ERR 0x40000000 31 #define TXD_END 0x20000000 32 #define TXD_BCNT_MSK 0x00003FFF 33 34 35 #undef NGE_DBG 36 #define NGE_DBG NGE_DBG_SEND 37 38 #define NGE_TXSWD_RECYCLE(sd) {\ 39 (sd)->mp = NULL; \ 40 (sd)->frags = 0; \ 41 (sd)->mp_hndl.head = NULL; \ 42 (sd)->mp_hndl.tail = NULL; \ 43 (sd)->flags = HOST_OWN; \ 44 } 45 46 47 static size_t nge_tx_dmah_pop(nge_dmah_list_t *, nge_dmah_list_t *, size_t); 48 static void nge_tx_dmah_push(nge_dmah_list_t *, nge_dmah_list_t *); 49 50 51 void nge_tx_recycle_all(nge_t *ngep); 52 #pragma no_inline(nge_tx_recycle_all) 53 54 void 55 nge_tx_recycle_all(nge_t *ngep) 56 { 57 send_ring_t *srp; 58 sw_tx_sbd_t *ssbdp; 59 nge_dmah_node_t *dmah; 60 uint32_t slot; 61 uint32_t nslots; 62 63 srp = ngep->send; 64 nslots = srp->desc.nslots; 65 66 for (slot = 0; slot < nslots; ++slot) { 67 68 ssbdp = srp->sw_sbds + slot; 69 70 DMA_ZERO(ssbdp->desc); 71 72 if (ssbdp->mp != NULL) { 73 74 for (dmah = ssbdp->mp_hndl.head; dmah != NULL; 75 dmah = dmah->next) 76 (void) ddi_dma_unbind_handle(dmah->hndl); 77 78 freemsg(ssbdp->mp); 79 } 80 81 NGE_TXSWD_RECYCLE(ssbdp); 82 } 83 if (ngep->nge_mac_state == NGE_MAC_STARTED && 84 ngep->resched_needed == 1) { 85 ngep->resched_needed = 0; 86 mac_tx_update(ngep->mh); 87 } 88 89 } 90 91 static size_t 92 nge_tx_dmah_pop(nge_dmah_list_t *src, nge_dmah_list_t *dst, size_t num) 93 { 94 nge_dmah_node_t *node; 95 96 for (node = src->head; node != NULL && --num != 0; node = node->next) 97 ; 98 99 if (num == 0) { 100 101 dst->head = src->head; 102 dst->tail = node; 103 104 if ((src->head = node->next) == NULL) 105 src->tail = NULL; 106 107 node->next = NULL; 108 } 109 110 return (num); 111 } 112 113 static void 114 nge_tx_dmah_push(nge_dmah_list_t *src, nge_dmah_list_t *dst) 115 { 116 if (dst->tail != NULL) 117 dst->tail->next = src->head; 118 else 119 dst->head = src->head; 120 121 dst->tail = src->tail; 122 } 123 124 static void 125 nge_tx_desc_sync(nge_t *ngep, uint32_t start_index, uint32_t bds, uint_t type) 126 { 127 send_ring_t *srp = ngep->send; 128 const size_t txd_size = ngep->desc_attr.txd_size; 129 const uint64_t end = srp->desc.nslots * txd_size; 130 uint64_t start; 131 uint64_t num; 132 133 start = start_index * txd_size; 134 num = bds * txd_size; 135 136 if (start + num <= end) 137 (void) ddi_dma_sync(srp->desc.dma_hdl, start, num, type); 138 else { 139 140 (void) ddi_dma_sync(srp->desc.dma_hdl, start, 0, type); 141 (void) ddi_dma_sync(srp->desc.dma_hdl, 0, start + num - end, 142 type); 143 } 144 } 145 146 /* 147 * Reclaim the resource after tx's completion 148 */ 149 void 150 nge_tx_recycle(nge_t *ngep, boolean_t is_intr) 151 { 152 int resched; 153 uint32_t stflg; 154 uint32_t free; 155 uint32_t slot; 156 uint32_t used; 157 uint32_t next; 158 uint32_t nslots; 159 mblk_t *mp; 160 sw_tx_sbd_t *ssbdp; 161 void *hw_sbd_p; 162 send_ring_t *srp; 163 nge_dmah_node_t *dme; 164 nge_dmah_list_t dmah; 165 166 srp = ngep->send; 167 168 if (is_intr) { 169 if (mutex_tryenter(srp->tc_lock) == 0) 170 return; 171 } else 172 mutex_enter(srp->tc_lock); 173 mutex_enter(srp->tx_lock); 174 175 next = srp->tx_next; 176 used = srp->tx_flow; 177 free = srp->tx_free; 178 179 mutex_exit(srp->tx_lock); 180 181 slot = srp->tc_next; 182 nslots = srp->desc.nslots; 183 184 used = nslots - free - used; 185 186 ASSERT(slot == NEXT_INDEX(next, free, nslots)); 187 if (used == 0) { 188 ngep->watchdog = 0; 189 mutex_exit(srp->tc_lock); 190 return; 191 } 192 193 if (used > srp->tx_hwmark && ngep->resched_needed == 0) 194 used = srp->tx_hwmark; 195 196 nge_tx_desc_sync(ngep, slot, used, DDI_DMA_SYNC_FORKERNEL); 197 198 /* 199 * Look through the send ring by bd's status part 200 * to find all the bds which has been transmitted sucessfully 201 * then reclaim all resouces associated with these bds 202 */ 203 204 mp = NULL; 205 dmah.head = NULL; 206 dmah.tail = NULL; 207 208 for (free = 0; used-- != 0; slot = NEXT(slot, nslots), ++free) { 209 210 ssbdp = &srp->sw_sbds[slot]; 211 hw_sbd_p = DMA_VPTR(ssbdp->desc); 212 213 if (ssbdp->flags == HOST_OWN) 214 break; 215 stflg = ngep->desc_attr.txd_check(hw_sbd_p); 216 if ((stflg & TXD_OWN) != 0) 217 break; 218 DMA_ZERO(ssbdp->desc); 219 if (ssbdp->mp != NULL) { 220 ssbdp->mp->b_next = mp; 221 mp = ssbdp->mp; 222 223 if (ssbdp->mp_hndl.head != NULL) 224 nge_tx_dmah_push(&ssbdp->mp_hndl, &dmah); 225 } 226 227 NGE_TXSWD_RECYCLE(ssbdp); 228 } 229 230 /* 231 * We're about to release one or more places :-) 232 * These ASSERTions check that our invariants still hold: 233 * there must always be at least one free place 234 * at this point, there must be at least one place NOT free 235 * we're not about to free more places than were claimed! 236 */ 237 238 if (free == 0) { 239 mutex_exit(srp->tc_lock); 240 return; 241 } 242 243 mutex_enter(srp->tx_lock); 244 245 srp->tx_free += free; 246 ngep->watchdog = (srp->desc.nslots - srp->tx_free != 0); 247 248 srp->tc_next = slot; 249 250 ASSERT(srp->tx_free <= nslots); 251 ASSERT(srp->tc_next == NEXT_INDEX(srp->tx_next, srp->tx_free, nslots)); 252 253 resched = (ngep->resched_needed != 0 && srp->tx_hwmark <= srp->tx_free); 254 255 mutex_exit(srp->tx_lock); 256 mutex_exit(srp->tc_lock); 257 258 /* unbind/free mblks */ 259 260 for (dme = dmah.head; dme != NULL; dme = dme->next) 261 (void) ddi_dma_unbind_handle(dme->hndl); 262 if (dmah.head != NULL) { 263 mutex_enter(&srp->dmah_lock); 264 nge_tx_dmah_push(&dmah, &srp->dmah_free); 265 mutex_exit(&srp->dmah_lock); 266 } 267 freemsgchain(mp); 268 269 /* 270 * up to this place, we maybe have reclaim some resouce 271 * if there is a requirement to report to gld, report this. 272 */ 273 274 if (resched) 275 (void) ddi_intr_trigger_softint(ngep->resched_hdl, NULL); 276 } 277 278 static uint32_t 279 nge_tx_alloc(nge_t *ngep, uint32_t num) 280 { 281 uint32_t start; 282 send_ring_t *srp; 283 284 start = (uint32_t)-1; 285 srp = ngep->send; 286 287 mutex_enter(srp->tx_lock); 288 289 if (srp->tx_free < srp->tx_lwmark) { 290 291 mutex_exit(srp->tx_lock); 292 nge_tx_recycle(ngep, B_FALSE); 293 mutex_enter(srp->tx_lock); 294 } 295 296 if (srp->tx_free >= num) { 297 298 start = srp->tx_next; 299 300 srp->tx_next = NEXT_INDEX(start, num, srp->desc.nslots); 301 srp->tx_free -= num; 302 srp->tx_flow += num; 303 } 304 305 mutex_exit(srp->tx_lock); 306 return (start); 307 } 308 309 static void 310 nge_tx_start(nge_t *ngep, uint32_t slotnum) 311 { 312 nge_mode_cntl mode_cntl; 313 send_ring_t *srp; 314 315 srp = ngep->send; 316 317 /* 318 * Because there can be multiple concurrent threads in 319 * transit through this code, we only want to notify the 320 * hardware once the last one is departing ... 321 */ 322 323 mutex_enter(srp->tx_lock); 324 325 srp->tx_flow -= slotnum; 326 if (srp->tx_flow == 0) { 327 328 /* 329 * Bump the watchdog counter, thus guaranteeing that it's 330 * nonzero (watchdog activated). Note that non-synchonised 331 * access here means we may race with the reclaim() code 332 * above, but the outcome will be harmless. At worst, the 333 * counter may not get reset on a partial reclaim; but the 334 * large trigger threshold makes false positives unlikely 335 */ 336 if (ngep->watchdog == 0) 337 ngep->watchdog = 1; 338 339 mode_cntl.mode_val = nge_reg_get32(ngep, NGE_MODE_CNTL); 340 mode_cntl.mode_bits.txdm = NGE_SET; 341 mode_cntl.mode_bits.tx_rcom_en = NGE_SET; 342 nge_reg_put32(ngep, NGE_MODE_CNTL, mode_cntl.mode_val); 343 } 344 mutex_exit(srp->tx_lock); 345 } 346 347 static enum send_status 348 nge_send_copy(nge_t *ngep, mblk_t *mp, send_ring_t *srp); 349 #pragma inline(nge_send_copy) 350 351 static enum send_status 352 nge_send_copy(nge_t *ngep, mblk_t *mp, send_ring_t *srp) 353 { 354 size_t totlen; 355 size_t mblen; 356 uint32_t flags; 357 uint32_t bds; 358 uint32_t start_index; 359 char *txb; 360 mblk_t *bp; 361 void *hw_sbd_p; 362 sw_tx_sbd_t *ssbdp; 363 boolean_t tfint; 364 365 mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &flags); 366 bds = 0x1; 367 368 if ((uint32_t)-1 == (start_index = nge_tx_alloc(ngep, bds))) 369 return (SEND_COPY_FAIL); 370 371 ASSERT(start_index < srp->desc.nslots); 372 373 /* 374 * up to this point, there's nothing that can fail, 375 * so we can go straight to claiming our 376 * already-reserved place son the train. 377 * 378 * This is the point of no return! 379 */ 380 381 tfint = ((start_index % ngep->tfint_threshold) == 0); 382 bp = mp; 383 totlen = 0; 384 ssbdp = &srp->sw_sbds[start_index]; 385 ASSERT(ssbdp->flags == HOST_OWN); 386 387 txb = DMA_VPTR(ssbdp->pbuf); 388 totlen = 0; 389 for (; bp != NULL; bp = bp->b_cont) { 390 if ((mblen = MBLKL(bp)) == 0) 391 continue; 392 if ((totlen += mblen) <= ngep->max_sdu) { 393 bcopy(bp->b_rptr, txb, mblen); 394 txb += mblen; 395 } 396 } 397 398 DMA_SYNC(ssbdp->pbuf, DDI_DMA_SYNC_FORDEV); 399 400 /* Fill & sync hw desc */ 401 402 hw_sbd_p = DMA_VPTR(ssbdp->desc); 403 404 ngep->desc_attr.txd_fill(hw_sbd_p, &ssbdp->pbuf.cookie, totlen, 405 flags, B_TRUE, tfint); 406 nge_tx_desc_sync(ngep, start_index, bds, DDI_DMA_SYNC_FORDEV); 407 408 ssbdp->flags = CONTROLER_OWN; 409 410 nge_tx_start(ngep, bds); 411 412 /* 413 * The return status indicates that the message can be freed 414 * right away, as we've already copied the contents ... 415 */ 416 417 freemsg(mp); 418 return (SEND_COPY_SUCESS); 419 } 420 421 /* 422 * static enum send_status 423 * nge_send_mapped(nge_t *ngep, mblk_t *mp, size_t fragno); 424 * #pragma inline(nge_send_mapped) 425 */ 426 427 static enum send_status 428 nge_send_mapped(nge_t *ngep, mblk_t *mp, size_t fragno) 429 { 430 int err; 431 boolean_t end; 432 uint32_t i; 433 uint32_t j; 434 uint32_t ncookies; 435 uint32_t slot; 436 uint32_t nslots; 437 uint32_t mblen; 438 uint32_t flags; 439 uint32_t start_index; 440 uint32_t end_index; 441 mblk_t *bp; 442 void *hw_sbd_p; 443 send_ring_t *srp; 444 nge_dmah_node_t *dmah; 445 nge_dmah_node_t *dmer; 446 nge_dmah_list_t dmah_list; 447 ddi_dma_cookie_t cookie[NGE_MAX_COOKIES * NGE_MAP_FRAGS]; 448 boolean_t tfint; 449 450 srp = ngep->send; 451 nslots = srp->desc.nslots; 452 453 mutex_enter(&srp->dmah_lock); 454 err = nge_tx_dmah_pop(&srp->dmah_free, &dmah_list, fragno); 455 mutex_exit(&srp->dmah_lock); 456 457 if (err != 0) { 458 459 return (SEND_MAP_FAIL); 460 } 461 462 /* 463 * Pre-scan the message chain, noting the total number of bytes, 464 * the number of fragments by pre-doing dma addr bind 465 * if the fragment is larger than NGE_COPY_SIZE. 466 * This way has the following advantages: 467 * 1. Acquire the detailed information of resouce 468 * need to send the message 469 * 470 * 2. If can not pre-apply enough resouce, fails at once 471 * and the driver will chose copy way to send out the 472 * message 473 */ 474 475 slot = 0; 476 dmah = dmah_list.head; 477 478 mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &flags); 479 480 for (bp = mp; bp != NULL; bp = bp->b_cont) { 481 482 mblen = MBLKL(bp); 483 if (mblen == 0) 484 continue; 485 486 err = ddi_dma_addr_bind_handle(dmah->hndl, 487 NULL, (caddr_t)bp->b_rptr, mblen, 488 DDI_DMA_STREAMING | DDI_DMA_WRITE, 489 DDI_DMA_DONTWAIT, NULL, cookie + slot, &ncookies); 490 491 /* 492 * If there can not map successfully, it is uncessary 493 * sending the message by map way. Sending the message 494 * by copy way. 495 * 496 * By referring to intel's suggestion, it is better 497 * the number of cookies should be less than 4. 498 */ 499 if (err != DDI_DMA_MAPPED || ncookies > NGE_MAX_COOKIES) { 500 NGE_DEBUG(("err(%x) map tx bulk fails" 501 " cookie(%x), ncookies(%x)", 502 err, cookie[slot].dmac_laddress, ncookies)); 503 goto map_fail; 504 } 505 506 /* 507 * Check How many bds a cookie will consume 508 */ 509 for (end_index = slot + ncookies; 510 ++slot != end_index; 511 ddi_dma_nextcookie(dmah->hndl, cookie + slot)) 512 ; 513 514 dmah = dmah->next; 515 } 516 517 /* 518 * Now allocate tx descriptors and fill them 519 * IMPORTANT: 520 * Up to the point where it claims a place, It is impossibel 521 * to fail. 522 * 523 * In this version, there's no setup to be done here, and there's 524 * nothing that can fail, so we can go straight to claiming our 525 * already-reserved places on the train. 526 * 527 * This is the point of no return! 528 */ 529 530 531 if ((uint32_t)-1 == (start_index = nge_tx_alloc(ngep, slot))) 532 goto map_fail; 533 534 ASSERT(start_index < nslots); 535 536 /* fill&sync hw desc, going in reverse order */ 537 538 end = B_TRUE; 539 end_index = NEXT_INDEX(start_index, slot - 1, nslots); 540 541 for (i = slot - 1, j = end_index; start_index - j != 0; 542 j = PREV(j, nslots), --i) { 543 544 tfint = ((j % ngep->tfint_threshold) == 0); 545 hw_sbd_p = DMA_VPTR(srp->sw_sbds[j].desc); 546 ngep->desc_attr.txd_fill(hw_sbd_p, cookie + i, 547 cookie[i].dmac_size, 0, end, tfint); 548 549 end = B_FALSE; 550 } 551 552 hw_sbd_p = DMA_VPTR(srp->sw_sbds[j].desc); 553 tfint = ((j % ngep->tfint_threshold) == 0); 554 ngep->desc_attr.txd_fill(hw_sbd_p, cookie + i, cookie[i].dmac_size, 555 flags, end, tfint); 556 557 nge_tx_desc_sync(ngep, start_index, slot, DDI_DMA_SYNC_FORDEV); 558 559 /* fill sw desc */ 560 561 for (j = start_index; end_index - j != 0; j = NEXT(j, nslots)) { 562 563 srp->sw_sbds[j].flags = CONTROLER_OWN; 564 } 565 566 srp->sw_sbds[j].mp = mp; 567 srp->sw_sbds[j].mp_hndl = dmah_list; 568 srp->sw_sbds[j].frags = (uint32_t)fragno; 569 srp->sw_sbds[j].flags = CONTROLER_OWN; 570 571 nge_tx_start(ngep, slot); 572 573 /* 574 * The return status indicates that the message can not be freed 575 * right away, until we can make assure the message has been sent 576 * out sucessfully. 577 */ 578 return (SEND_MAP_SUCCESS); 579 580 map_fail: 581 for (dmer = dmah_list.head; dmah - dmer != 0; dmer = dmer->next) 582 (void) ddi_dma_unbind_handle(dmer->hndl); 583 584 mutex_enter(&srp->dmah_lock); 585 nge_tx_dmah_push(&dmah_list, &srp->dmah_free); 586 mutex_exit(&srp->dmah_lock); 587 588 return (SEND_MAP_FAIL); 589 } 590 591 static boolean_t 592 nge_send(nge_t *ngep, mblk_t *mp) 593 { 594 mblk_t *bp; 595 send_ring_t *srp; 596 enum send_status status; 597 uint32_t mblen = 0; 598 uint32_t frags = 0; 599 nge_statistics_t *nstp = &ngep->statistics; 600 nge_sw_statistics_t *sw_stp = &nstp->sw_statistics; 601 602 ASSERT(mp != NULL); 603 ASSERT(ngep->nge_mac_state == NGE_MAC_STARTED); 604 605 srp = ngep->send; 606 /* 607 * 1.Check the number of the fragments of the messages 608 * If the total number is larger than 3, 609 * Chose copy way 610 * 611 * 2. Check the length of the message whether is larger than 612 * NGE_TX_COPY_SIZE, if so, choose the map way. 613 */ 614 for (frags = 0, bp = mp; bp != NULL; bp = bp->b_cont) { 615 if (MBLKL(bp) == 0) 616 continue; 617 frags++; 618 mblen += MBLKL(bp); 619 } 620 if (mblen > (ngep->max_sdu) || mblen == 0) { 621 freemsg(mp); 622 return (B_TRUE); 623 } 624 if ((mblen > ngep->param_txbcopy_threshold) && 625 (frags <= NGE_MAP_FRAGS) && 626 (srp->tx_free > frags * NGE_MAX_COOKIES)) { 627 status = nge_send_mapped(ngep, mp, frags); 628 if (status == SEND_MAP_FAIL) 629 status = nge_send_copy(ngep, mp, srp); 630 } else { 631 status = nge_send_copy(ngep, mp, srp); 632 } 633 if (status == SEND_COPY_FAIL) { 634 nge_tx_recycle(ngep, B_FALSE); 635 status = nge_send_copy(ngep, mp, srp); 636 if (status == SEND_COPY_FAIL) { 637 ngep->resched_needed = 1; 638 NGE_DEBUG(("nge_send: send fail!")); 639 return (B_FALSE); 640 } 641 } 642 /* Update the software statistics */ 643 sw_stp->obytes += mblen + ETHERFCSL; 644 sw_stp->xmit_count ++; 645 646 return (B_TRUE); 647 } 648 649 /* 650 * nge_m_tx : Send a chain of packets. 651 */ 652 mblk_t * 653 nge_m_tx(void *arg, mblk_t *mp) 654 { 655 nge_t *ngep = arg; 656 mblk_t *next; 657 658 rw_enter(ngep->rwlock, RW_READER); 659 ASSERT(mp != NULL); 660 if (ngep->nge_chip_state != NGE_CHIP_RUNNING) { 661 freemsgchain(mp); 662 mp = NULL; 663 } 664 while (mp != NULL) { 665 next = mp->b_next; 666 mp->b_next = NULL; 667 668 if (!nge_send(ngep, mp)) { 669 mp->b_next = next; 670 break; 671 } 672 673 mp = next; 674 } 675 rw_exit(ngep->rwlock); 676 677 return (mp); 678 } 679 680 /* ARGSUSED */ 681 uint_t 682 nge_reschedule(caddr_t args1, caddr_t args2) 683 { 684 nge_t *ngep; 685 uint_t rslt; 686 687 ngep = (nge_t *)args1; 688 rslt = DDI_INTR_UNCLAIMED; 689 690 /* 691 * when softintr is trigged, checking whether this 692 * is caused by our expected interrupt 693 */ 694 if (ngep->nge_mac_state == NGE_MAC_STARTED && 695 ngep->resched_needed == 1) { 696 ngep->resched_needed = 0; 697 ++ngep->statistics.sw_statistics.tx_resched; 698 mac_tx_update(ngep->mh); 699 rslt = DDI_INTR_CLAIMED; 700 } 701 return (rslt); 702 } 703 704 uint32_t 705 nge_hot_txd_check(const void *hwd) 706 { 707 uint32_t err_flag; 708 const hot_tx_bd * htbdp; 709 710 htbdp = hwd; 711 err_flag = htbdp->control_status.cntl_val; 712 return (err_flag); 713 } 714 715 uint32_t 716 nge_sum_txd_check(const void *hwd) 717 { 718 uint32_t err_flag; 719 const sum_tx_bd * htbdp; 720 721 htbdp = hwd; 722 err_flag = htbdp->control_status.cntl_val; 723 return (err_flag); 724 } 725 726 727 /* 728 * Filling the contents of Tx's data descriptor 729 * before transmitting. 730 */ 731 732 void 733 nge_hot_txd_fill(void *hwdesc, const ddi_dma_cookie_t *cookie, 734 size_t length, uint32_t sum_flag, boolean_t end, boolean_t tfint) 735 { 736 hot_tx_bd * hw_sbd_p = hwdesc; 737 738 hw_sbd_p->host_buf_addr_hi = cookie->dmac_laddress >> 32; 739 hw_sbd_p->host_buf_addr_lo = cookie->dmac_laddress; 740 741 /* 742 * Setting the length of the packet 743 * Note: the length filled in the part should be 744 * the original length subtract 1; 745 */ 746 747 hw_sbd_p->control_status.control_sum_bits.bcnt = length - 1; 748 749 /* setting ip checksum */ 750 if (sum_flag & HCK_IPV4_HDRCKSUM) 751 hw_sbd_p->control_status.control_sum_bits.ip_hsum 752 = NGE_SET; 753 /* setting tcp checksum */ 754 if (sum_flag & HCK_FULLCKSUM) 755 hw_sbd_p->control_status.control_sum_bits.tcp_hsum 756 = NGE_SET; 757 /* 758 * indicating the end of BDs 759 */ 760 if (tfint) 761 hw_sbd_p->control_status.control_sum_bits.inten = NGE_SET; 762 if (end) 763 hw_sbd_p->control_status.control_sum_bits.end = NGE_SET; 764 765 membar_producer(); 766 767 /* pass desc to HW */ 768 hw_sbd_p->control_status.control_sum_bits.own = NGE_SET; 769 } 770 771 void 772 nge_sum_txd_fill(void *hwdesc, const ddi_dma_cookie_t *cookie, 773 size_t length, uint32_t sum_flag, boolean_t end, boolean_t tfint) 774 { 775 sum_tx_bd * hw_sbd_p = hwdesc; 776 777 hw_sbd_p->host_buf_addr = cookie->dmac_address; 778 779 /* 780 * Setting the length of the packet 781 * Note: the length filled in the part should be 782 * the original length subtract 1; 783 */ 784 785 hw_sbd_p->control_status.control_sum_bits.bcnt = length - 1; 786 787 /* setting ip checksum */ 788 if (sum_flag & HCK_IPV4_HDRCKSUM) 789 hw_sbd_p->control_status.control_sum_bits.ip_hsum 790 = NGE_SET; 791 /* setting tcp checksum */ 792 if (sum_flag & HCK_FULLCKSUM) 793 hw_sbd_p->control_status.control_sum_bits.tcp_hsum 794 = NGE_SET; 795 /* 796 * indicating the end of BDs 797 */ 798 if (tfint) 799 hw_sbd_p->control_status.control_sum_bits.inten = NGE_SET; 800 if (end) 801 hw_sbd_p->control_status.control_sum_bits.end = NGE_SET; 802 803 membar_producer(); 804 805 /* pass desc to HW */ 806 hw_sbd_p->control_status.control_sum_bits.own = NGE_SET; 807 } 808