1 /* 2 * Copyright 2014-2017 Cavium, Inc. 3 * The contents of this file are subject to the terms of the Common Development 4 * and Distribution License, v.1, (the "License"). 5 * 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the License at available 9 * at http://opensource.org/licenses/CDDL-1.0 10 * 11 * See the License for the specific language governing permissions and 12 * limitations under the License. 13 */ 14 15 /* 16 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 17 * Copyright (c) 2019, Joyent, Inc. 18 */ 19 20 #include "bnxsnd.h" 21 22 23 /* Low water marks for transmit credits. */ 24 #define BNX_DCOPY_ALIGN 32 25 #define BNX_XMIT_INIT_FAIL_THRESH 1 26 #define BNX_PDWM_THRESHOLD 8 27 28 29 #ifndef NUM_TX_CHAIN 30 #error NUM_TX_CHAIN is not defined. 31 #else 32 /* 33 * Range check NUM_TX_CHAIN. Technically the LM controls this definition, 34 * but it makes sense to use what the LM uses. 35 */ 36 #if NUM_TX_CHAIN < 0 37 #error Invalid NUM_TX_CHAIN definition. 38 #elif NUM_TX_CHAIN > 1 39 #warning NUM_TX_CHAIN is greater than 1. 40 #endif 41 #endif 42 43 44 static ddi_dma_attr_t bnx_snd_dma_attrib = { 45 DMA_ATTR_V0, /* dma_attr_version */ 46 0, /* dma_attr_addr_lo */ 47 0xffffffffffffffff, /* dma_attr_addr_hi */ 48 0x0ffffff, /* dma_attr_count_max */ 49 BNX_DMA_ALIGNMENT, /* dma_attr_align */ 50 0xffffffff, /* dma_attr_burstsizes */ 51 1, /* dma_attr_minxfer */ 52 0x00ffffff, /* dma_attr_maxxfer */ 53 0xffffffff, /* dma_attr_seg */ 54 BNX_MAX_SGL_ENTRIES, /* dma_attr_sgllen */ 55 BNX_MIN_BYTES_PER_FRAGMENT, /* dma_attr_granular */ 56 0, /* dma_attr_flags */ 57 }; 58 59 /* 60 * Description: This function will map the fragments of the message block 61 * 62 * Return: DDI_DMA_MAPPED: Success 63 * DDI_DMA_INUSE: Another I/O transaction is using the DMA handle 64 * DDI_DMA_NORESOURCES: No resources are available at the present time 65 * DDI_DMA_NOMAPPING: The object cannot be reached by the device 66 * requesting the resources. 67 * DDI_DMA_TOOBIG: The object is too big. A request of this size can 68 * never be satisfied on this particular system. 69 * The maximum size varies depending on machine 70 * and configuration. 71 */ 72 static int 73 bnx_xmit_frag_map(mblk_t *mp, ddi_dma_handle_t *handle, 74 lm_frag_list_t *fraglist) 75 { 76 int i; 77 uint_t ccount; 78 ddi_dma_cookie_t cookie; 79 lm_frag_t *fragment; 80 81 if (fraglist->cnt >= BNX_MAX_SGL_ENTRIES) { 82 return (DDI_DMA_NOMAPPING); 83 } 84 85 i = ddi_dma_addr_bind_handle(*handle, NULL, 86 (caddr_t)mp->b_rptr, mp->b_wptr - mp->b_rptr, 87 DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, NULL, 88 &cookie, &ccount); 89 if (i != DDI_DMA_MAPPED) { 90 return (i); 91 } 92 93 /* 94 * It looks strange at first, but the below check is needed. 95 * ddi_dma_addr_bind_handle() correctly returns an error if 96 * the physical fragment count exceeds the maximum fragment 97 * count specified in the ddi_dma_attrib structure for the 98 * current mp. However, a packet can span multiple mp's. 99 * The purpose of the check below is to make sure we do not 100 * overflow the global fragment count limit. 101 */ 102 if (fraglist->cnt + ccount > BNX_MAX_SGL_ENTRIES) { 103 /* We hit our fragment count limit. */ 104 (void) ddi_dma_unbind_handle(*handle); 105 106 return (DDI_DMA_NOMAPPING); 107 } 108 109 fragment = &(fraglist->frag_arr[fraglist->cnt]); 110 fraglist->cnt += ccount; 111 112 for (i = 0; i < ccount-1; i++) { 113 fragment->addr.as_u64 = cookie.dmac_laddress; 114 fragment->size = cookie.dmac_size; 115 116 fragment++; 117 118 ddi_dma_nextcookie(*handle, &cookie); 119 } 120 121 fragment->addr.as_u64 = cookie.dmac_laddress; 122 fragment->size = cookie.dmac_size; 123 124 return (0); 125 } 126 127 static void 128 bnx_xmit_pkt_unmap(um_txpacket_t * const umpacket) 129 { 130 int i; 131 132 for (i = 0; i < umpacket->num_handles; i++) { 133 (void) ddi_dma_unbind_handle(umpacket->dma_handle[i]); 134 } 135 136 umpacket->num_handles = 0; 137 } 138 139 int 140 bnx_xmit_pkt_map(um_txpacket_t * const umpacket, mblk_t * mp) 141 { 142 int rc; 143 u32_t num_dma_handle; 144 145 num_dma_handle = umpacket->num_handles; 146 147 if (num_dma_handle == BNX_MAX_SGL_ENTRIES) { 148 return (BNX_TX_RESOURCES_TOO_MANY_FRAGS); 149 } 150 151 rc = bnx_xmit_frag_map(mp, &umpacket->dma_handle[num_dma_handle++], 152 &(umpacket->frag_list)); 153 if (rc) { 154 return (BNX_TX_RESOURCES_NO_OS_DMA_RES); 155 } 156 157 umpacket->num_handles = num_dma_handle; 158 159 return (0); 160 } 161 162 static void 163 bnx_xmit_pkt_cpy(um_device_t * const umdevice, um_txpacket_t * const umpacket) 164 { 165 size_t msgsize; 166 u32_t cpysize; 167 lm_frag_t *cpyfrag; 168 boolean_t map_enable; 169 mblk_t *mp; 170 int rc; 171 172 map_enable = B_TRUE; 173 cpysize = 0; 174 cpyfrag = NULL; 175 176 for (mp = umpacket->mp; mp; mp = mp->b_cont) { 177 msgsize = MBLKL(mp); 178 179 if (msgsize == 0) 180 continue; 181 182 if (map_enable && msgsize > umdevice->tx_copy_threshold) { 183 rc = bnx_xmit_pkt_map(umpacket, mp); 184 if (rc == 0) { 185 cpyfrag = NULL; 186 continue; 187 } else { 188 map_enable = B_FALSE; 189 } 190 } 191 192 ASSERT(cpysize + msgsize <= umdevice->dev_var.mtu + 193 sizeof (struct ether_vlan_header)); 194 195 bcopy(mp->b_rptr, (char *)umpacket->cpymem + cpysize, msgsize); 196 197 if (cpyfrag != NULL) { 198 cpyfrag->size += msgsize; 199 } else { 200 cpyfrag = &umpacket->frag_list.frag_arr[ 201 umpacket->frag_list.cnt++]; 202 ASSERT(umpacket->frag_list.cnt <= BNX_MAX_SGL_ENTRIES + 203 1); 204 cpyfrag->size = msgsize; 205 206 cpyfrag->addr.as_u64 = umpacket->cpyphy.as_u64 + 207 cpysize; 208 } 209 210 cpysize += msgsize; 211 } 212 213 if (cpysize > 0) { 214 (void) ddi_dma_sync(*(umpacket->cpyhdl), umpacket->cpyoff, 215 cpysize, DDI_DMA_SYNC_FORDEV); 216 } 217 218 if (umpacket->num_handles == 0) { 219 freemsg(umpacket->mp); 220 umpacket->mp = NULL; 221 } 222 223 } 224 225 static int 226 bnx_xmit_pkt_init(um_device_t * const umdevice, um_txpacket_t * const umpacket, 227 int num, lm_u64_t memphys) 228 { 229 int i; 230 int rc; 231 um_xmit_qinfo * xmitinfo; 232 233 xmitinfo = &_TX_QINFO(umdevice, 0); 234 235 for (i = 0; i < BNX_MAX_SGL_ENTRIES; i++) { 236 rc = ddi_dma_alloc_handle(umdevice->os_param.dip, 237 &bnx_snd_dma_attrib, DDI_DMA_DONTWAIT, 238 (void *)0, &umpacket->dma_handle[i]); 239 if (rc != DDI_SUCCESS) { 240 cmn_err(CE_WARN, "%s:%s failed. (errno=%d)", 241 umdevice->dev_name, __func__, rc); 242 goto error; 243 } 244 } 245 246 /* Init the relavant informations in the packet structure */ 247 umpacket->mp = NULL; 248 umpacket->num_handles = 0; 249 umpacket->frag_list.cnt = 0; 250 251 umpacket->cpyhdl = &(xmitinfo->dcpyhndl); 252 umpacket->cpyoff = num * xmitinfo->dcpyhard; 253 umpacket->cpymem = xmitinfo->dcpyvirt + umpacket->cpyoff; 254 umpacket->cpyphy = memphys; 255 256 return (rc); 257 258 error: 259 for (i--; i >= 0; i--) { 260 ddi_dma_free_handle(&umpacket->dma_handle[i]); 261 } 262 263 return (-1); 264 } 265 266 static void 267 bnx_xmit_pkt_fini(um_txpacket_t * const umpacket) 268 { 269 int i; 270 271 for (i = BNX_MAX_SGL_ENTRIES - 1; i >= 0; i--) { 272 ddi_dma_free_handle(&umpacket->dma_handle[i]); 273 } 274 275 umpacket->mp = NULL; 276 umpacket->num_handles = 0; 277 umpacket->frag_list.cnt = 0; 278 279 umpacket->cpyhdl = NULL; 280 umpacket->cpyoff = 0; 281 umpacket->cpymem = NULL; 282 } 283 284 static int 285 bnx_xmit_packet(um_device_t * const umdevice, const unsigned int ringidx, 286 um_txpacket_t * const umpacket) 287 { 288 int rc; 289 s_list_t *waitq; 290 lm_tx_chain_t *txq; 291 lm_packet_t *lmpacket; 292 lm_device_t *lmdevice; 293 lm_frag_list_t *lmfraglist; 294 295 lmdevice = &(umdevice->lm_dev); 296 lmpacket = &(umpacket->lm_pkt); 297 298 lmfraglist = &(umpacket->frag_list); 299 txq = &lmdevice->tx_info.chain[ringidx]; 300 301 /* Try to recycle, if available bd is lower than threshold */ 302 if (txq->bd_left < BNX_MAX_SGL_ENTRIES) { 303 s_list_t xmitpkts; 304 305 s_list_init(&xmitpkts, NULL, NULL, 0); 306 307 rc = lm_get_packets_sent(lmdevice, ringidx, 0, &xmitpkts); 308 309 if (rc) { 310 bnx_xmit_ring_reclaim(umdevice, ringidx, &xmitpkts); 311 } 312 } 313 314 waitq = &_TXQ_RESC_DESC(umdevice, ringidx); 315 if (s_list_is_empty(waitq) && txq->bd_left >= lmfraglist->cnt) { 316 (void) lm_send_packet(lmdevice, ringidx, lmpacket, lmfraglist); 317 318 return (BNX_SEND_GOODXMIT); 319 } 320 321 s_list_push_tail(waitq, &umpacket->lm_pkt.link); 322 323 if (txq->bd_left >= BNX_MAX_SGL_ENTRIES) { 324 rc = bnx_xmit_ring_xmit_qpkt(umdevice, ringidx); 325 if (rc == BNX_SEND_GOODXMIT) { 326 return (BNX_SEND_GOODXMIT); 327 } 328 } 329 330 umdevice->no_tx_credits |= BNX_TX_RESOURCES_NO_CREDIT; 331 332 return (BNX_SEND_DEFERPKT); 333 } 334 335 static int 336 bnx_xmit_ring_cpybuf_alloc(um_device_t * const umdevice, 337 um_xmit_qinfo * const xmitinfo, 338 unsigned int buffsize) 339 { 340 int rc; 341 size_t actualsize; 342 unsigned int alignedsize; 343 unsigned int count; 344 ddi_dma_cookie_t cookie; 345 346 ASSERT(buffsize > 0); 347 348 alignedsize = buffsize; 349 alignedsize += (BNX_DCOPY_ALIGN - 1); 350 alignedsize &= ~((unsigned int)(BNX_DCOPY_ALIGN - 1)); 351 352 /* We want double copy buffers to be completely contiguous. */ 353 rc = ddi_dma_alloc_handle(umdevice->os_param.dip, &bnx_std_dma_attrib, 354 DDI_DMA_DONTWAIT, (void *)0, &xmitinfo->dcpyhndl); 355 if (rc != DDI_SUCCESS) { 356 cmn_err(CE_WARN, 357 "%s: %s: Failed to alloc phys dma handle.\n", 358 umdevice->dev_name, __func__); 359 return (-1); 360 } 361 362 rc = ddi_dma_mem_alloc(xmitinfo->dcpyhndl, 363 alignedsize * xmitinfo->desc_cnt, &bnxAccessAttribBUF, 364 DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, (void *)0, 365 &xmitinfo->dcpyvirt, &actualsize, &xmitinfo->dcpyahdl); 366 if (rc != DDI_SUCCESS) { 367 cmn_err(CE_WARN, 368 "%s: %s: Failed to alloc phys memory.\n", 369 umdevice->dev_name, __func__); 370 goto error1; 371 } 372 373 rc = ddi_dma_addr_bind_handle(xmitinfo->dcpyhndl, 374 (struct as *)0, xmitinfo->dcpyvirt, actualsize, 375 DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, (void *)0, 376 &cookie, &count); 377 if (rc != DDI_SUCCESS) { 378 cmn_err(CE_WARN, 379 "%s: %s: Failed to bind DMA address.\n", 380 umdevice->dev_name, __func__); 381 goto error2; 382 } 383 384 xmitinfo->dcpyhard = alignedsize; 385 xmitinfo->dcpyphys.as_u64 = (u64_t)cookie.dmac_laddress; 386 387 return (0); 388 389 error2: 390 ddi_dma_mem_free(&xmitinfo->dcpyahdl); 391 392 error1: 393 ddi_dma_free_handle(&xmitinfo->dcpyhndl); 394 395 return (-1); 396 } 397 398 static void 399 bnx_xmit_ring_cpybuf_free(um_device_t * const umdevice, 400 um_xmit_qinfo * const xmitinfo) 401 { 402 (void) ddi_dma_unbind_handle(xmitinfo->dcpyhndl); 403 ddi_dma_mem_free(&xmitinfo->dcpyahdl); 404 ddi_dma_free_handle(&xmitinfo->dcpyhndl); 405 406 xmitinfo->dcpyvirt = NULL; 407 xmitinfo->dcpyphys.as_u64 = 0; 408 xmitinfo->dcpyhard = 0; 409 } 410 411 static int 412 bnx_xmit_ring_init(um_device_t * const umdevice, const unsigned int ringidx) 413 { 414 int i; 415 size_t memsize; 416 void *memvirt; 417 s_list_t *freeq; 418 lm_u64_t memphys; 419 um_txpacket_t *umpacket; 420 um_xmit_qinfo *xmitinfo; 421 422 xmitinfo = &_TX_QINFO(umdevice, ringidx); 423 424 s_list_init(&_TXQ_FREE_DESC(umdevice, ringidx), NULL, NULL, 0); 425 s_list_init(&_TXQ_RESC_DESC(umdevice, ringidx), NULL, NULL, 0); 426 427 if (xmitinfo->desc_cnt == 0) { 428 return (0); 429 } 430 431 xmitinfo->thresh_pdwm = BNX_PDWM_THRESHOLD; 432 433 memsize = xmitinfo->desc_cnt * sizeof (um_txpacket_t); 434 memvirt = kmem_zalloc(memsize, KM_NOSLEEP); 435 if (memvirt == NULL) { 436 cmn_err(CE_WARN, "%s: Failed to allocate TX packet " 437 "descriptor memory (%d).\n", umdevice->dev_name, ringidx); 438 return (-1); 439 } 440 441 xmitinfo->desc_mem.addr = memvirt; 442 xmitinfo->desc_mem.size = memsize; 443 444 if (bnx_xmit_ring_cpybuf_alloc(umdevice, xmitinfo, 445 umdevice->dev_var.mtu + sizeof (struct ether_vlan_header))) { 446 kmem_free(xmitinfo->desc_mem.addr, xmitinfo->desc_mem.size); 447 xmitinfo->desc_mem.addr = NULL; 448 xmitinfo->desc_mem.size = 0; 449 450 return (-1); 451 } 452 453 /* 454 * Driver successfully allocated memory for this transmit queue, now 455 * link them together and place them in the free pool. 456 */ 457 458 freeq = &_TXQ_FREE_DESC(umdevice, ringidx); 459 umpacket = (um_txpacket_t *)memvirt; 460 461 memphys = xmitinfo->dcpyphys; 462 463 for (i = 0; i < xmitinfo->desc_cnt; i++) { 464 if (bnx_xmit_pkt_init(umdevice, umpacket, i, memphys)) { 465 break; 466 } 467 468 LM_INC64(&memphys, xmitinfo->dcpyhard); 469 470 s_list_push_tail(freeq, &umpacket->lm_pkt.link); 471 472 umpacket++; 473 } 474 475 mutex_init(&xmitinfo->free_mutex, NULL, MUTEX_DRIVER, 476 DDI_INTR_PRI(umdevice->intrPriority)); 477 478 return (0); 479 } 480 481 void 482 bnx_xmit_ring_reclaim(um_device_t * const umdevice, 483 const unsigned int ringidx, s_list_t *srcq) 484 { 485 s_list_t *freeq; 486 s_list_entry_t *lmpacket; 487 um_txpacket_t *umpacket; 488 um_xmit_qinfo *xmitinfo; 489 490 if (s_list_entry_cnt(srcq) == 0) { 491 return; 492 } 493 494 for (lmpacket = s_list_peek_head(srcq); lmpacket; 495 lmpacket = s_list_next_entry(lmpacket)) { 496 497 umpacket = (um_txpacket_t *)lmpacket; 498 499 if (umpacket->num_handles > 0) { 500 bnx_xmit_pkt_unmap(umpacket); 501 } 502 503 if (umpacket->mp != NULL) { 504 freemsg(umpacket->mp); 505 umpacket->mp = NULL; 506 } 507 } 508 509 freeq = &_TXQ_FREE_DESC(umdevice, ringidx); 510 xmitinfo = &_TX_QINFO(umdevice, ringidx); 511 512 mutex_enter(&xmitinfo->free_mutex); 513 s_list_add_tail(freeq, srcq); 514 mutex_exit(&xmitinfo->free_mutex); 515 516 } 517 518 int 519 bnx_xmit_ring_xmit_qpkt(um_device_t * const umdevice, 520 const unsigned int ringidx) 521 { 522 s_list_t *waitq; 523 lm_tx_chain_t *txq; 524 lm_packet_t *lmpacket; 525 lm_device_t *lmdevice; 526 lm_frag_list_t *lmfraglist; 527 um_txpacket_t *umpacket; 528 int rc = 0; 529 530 lmdevice = &(umdevice->lm_dev); 531 waitq = &_TXQ_RESC_DESC(umdevice, ringidx); 532 txq = &lmdevice->tx_info.chain[ringidx]; 533 534 while (s_list_entry_cnt(waitq)) { 535 umpacket = (um_txpacket_t *)s_list_peek_head(waitq); 536 lmfraglist = &(umpacket->frag_list); 537 538 if (lmfraglist->cnt > txq->bd_left) { 539 rc = BNX_SEND_DEFERPKT; 540 break; 541 } 542 543 umpacket = (um_txpacket_t *)s_list_pop_head(waitq); 544 lmpacket = &(umpacket->lm_pkt); 545 546 /* 547 * The main way that this can fail is in the check we just 548 * performed around the fragment list versus txq, so we ignore 549 * the return value. 550 */ 551 (void) lm_send_packet(lmdevice, ringidx, lmpacket, lmfraglist); 552 } 553 554 return (rc); 555 } 556 557 int 558 bnx_xmit_ring_xmit_mblk(um_device_t * const umdevice, 559 const unsigned int ringidx, mblk_t *mp) 560 { 561 int rc; 562 uint32_t pflags; 563 s_list_t *txfreeq; 564 lm_packet_t *lmpacket; 565 um_txpacket_t *umpacket; 566 um_xmit_qinfo *xmitinfo; 567 568 xmitinfo = &_TX_QINFO(umdevice, ringidx); 569 570 txfreeq = &_TXQ_FREE_DESC(umdevice, ringidx); 571 572 mutex_enter(&xmitinfo->free_mutex); 573 umpacket = (um_txpacket_t *)s_list_pop_head(txfreeq); 574 mutex_exit(&xmitinfo->free_mutex); 575 576 /* Try to recycle, if no more packet available */ 577 if (umpacket == NULL) { 578 s_list_t xmitpkts; 579 lm_device_t *lmdevice; 580 581 lmdevice = &(umdevice->lm_dev); 582 583 s_list_init(&xmitpkts, NULL, NULL, 0); 584 585 mutex_enter(&umdevice->os_param.xmit_mutex); 586 rc = lm_get_packets_sent(lmdevice, ringidx, 0, &xmitpkts); 587 if (rc == 0) { 588 umdevice->no_tx_credits |= BNX_TX_RESOURCES_NO_DESC; 589 590 mutex_exit(&umdevice->os_param.xmit_mutex); 591 return (BNX_SEND_HDWRFULL); 592 } 593 mutex_exit(&umdevice->os_param.xmit_mutex); 594 595 umpacket = (um_txpacket_t *)s_list_pop_head(&xmitpkts); 596 if (umpacket->num_handles > 0) { 597 bnx_xmit_pkt_unmap(umpacket); 598 } 599 if (umpacket->mp != NULL) { 600 freemsg(umpacket->mp); 601 umpacket->mp = NULL; 602 } 603 604 /* clean up resources */ 605 bnx_xmit_ring_reclaim(umdevice, ringidx, &xmitpkts); 606 } 607 608 umpacket->lm_pkt.link.next = NULL; 609 ASSERT(umpacket->mp == NULL); 610 ASSERT(umpacket->num_handles == 0); 611 umpacket->frag_list.cnt = 0; 612 umpacket->mp = mp; 613 614 hcksum_retrieve(mp, NULL, NULL, NULL, NULL, NULL, NULL, &pflags); 615 616 bnx_xmit_pkt_cpy(umdevice, umpacket); 617 618 lmpacket = &(umpacket->lm_pkt); 619 620 lmpacket->u1.tx.flags = 0; 621 lmpacket->u1.tx.lso_mss = 0; 622 623 lmpacket->u1.tx.vlan_tag = 0; 624 625 if (pflags & HCK_IPV4_HDRCKSUM) { 626 lmpacket->u1.tx.flags |= LM_TX_FLAG_COMPUTE_IP_CKSUM; 627 } 628 629 if (pflags & HCK_FULLCKSUM) { 630 lmpacket->u1.tx.flags |= LM_TX_FLAG_COMPUTE_TCP_UDP_CKSUM; 631 } 632 633 mutex_enter(&umdevice->os_param.xmit_mutex); 634 rc = bnx_xmit_packet(umdevice, ringidx, umpacket); 635 mutex_exit(&umdevice->os_param.xmit_mutex); 636 637 return (rc); 638 } 639 640 void 641 bnx_xmit_ring_intr(um_device_t * const umdevice, const unsigned int ringidx) 642 { 643 u32_t rc; 644 s_list_t xmitpkts; 645 lm_device_t *lmdevice; 646 647 lmdevice = &(umdevice->lm_dev); 648 649 s_list_init(&xmitpkts, NULL, NULL, 0); 650 651 mutex_enter(&umdevice->os_param.xmit_mutex); 652 653 rc = lm_get_packets_sent(lmdevice, ringidx, 0, &xmitpkts); 654 655 mutex_exit(&umdevice->os_param.xmit_mutex); 656 657 if (rc) { 658 bnx_xmit_ring_reclaim(umdevice, ringidx, &xmitpkts); 659 } 660 } 661 662 void 663 bnx_xmit_ring_post(um_device_t * const umdevice, const unsigned int ringidx) 664 { 665 int rc; 666 s_list_t *freeq; 667 lm_device_t *lmdevice; 668 um_xmit_qinfo *xmitinfo; 669 lm_tx_chain_t *lmtxring; 670 671 if (umdevice->no_tx_credits != 0) { 672 if (umdevice->no_tx_credits & BNX_TX_RESOURCES_NO_CREDIT) { 673 rc = bnx_xmit_ring_xmit_qpkt(umdevice, ringidx); 674 675 if (rc == BNX_SEND_GOODXMIT) { 676 lmdevice = &(umdevice->lm_dev); 677 lmtxring = &(lmdevice->tx_info.chain[ringidx]); 678 679 if (lmtxring->bd_left >= BNX_MAX_SGL_ENTRIES) { 680 umdevice->no_tx_credits &= 681 ~BNX_TX_RESOURCES_NO_CREDIT; 682 } 683 } 684 } 685 686 if (umdevice->no_tx_credits & BNX_TX_RESOURCES_NO_DESC) { 687 freeq = &_TXQ_FREE_DESC(umdevice, ringidx); 688 xmitinfo = &_TX_QINFO(umdevice, ringidx); 689 690 if (s_list_entry_cnt(freeq) > xmitinfo->thresh_pdwm) { 691 umdevice->no_tx_credits &= 692 ~BNX_TX_RESOURCES_NO_DESC; 693 } 694 } 695 696 if (umdevice->no_tx_credits == 0) { 697 mac_tx_update(umdevice->os_param.macp); 698 } 699 } 700 } 701 702 static void 703 bnx_xmit_ring_fini(um_device_t * const umdevice, const unsigned int ringidx) 704 { 705 s_list_t *srcq; 706 um_txpacket_t *umpacket; 707 um_xmit_qinfo *xmitinfo; 708 709 xmitinfo = &_TX_QINFO(umdevice, ringidx); 710 711 mutex_destroy(&xmitinfo->free_mutex); 712 713 srcq = &_TXQ_FREE_DESC(umdevice, ringidx); 714 715 /* CONSTANTCONDITION */ 716 /* Pop all the packet descriptors off the free list and discard them. */ 717 while (1) { 718 umpacket = (um_txpacket_t *)s_list_pop_head(srcq); 719 if (umpacket == NULL) { 720 break; 721 } 722 723 bnx_xmit_pkt_fini(umpacket); 724 } 725 726 bnx_xmit_ring_cpybuf_free(umdevice, xmitinfo); 727 728 kmem_free(xmitinfo->desc_mem.addr, xmitinfo->desc_mem.size); 729 xmitinfo->desc_mem.addr = NULL; 730 xmitinfo->desc_mem.size = 0; 731 } 732 733 int 734 bnx_txpkts_init(um_device_t * const umdevice) 735 { 736 int i; 737 int alloccnt; 738 um_xmit_qinfo *xmitinfo; 739 740 xmitinfo = &_TX_QINFO(umdevice, 0); 741 742 mutex_init(&umdevice->os_param.xmit_mutex, NULL, 743 MUTEX_DRIVER, DDI_INTR_PRI(umdevice->intrPriority)); 744 745 alloccnt = 0; 746 747 /* Allocate packet descriptors for the TX queue. */ 748 for (i = TX_CHAIN_IDX0; i < NUM_TX_CHAIN; i++) { 749 int desc_cnt; 750 751 if (bnx_xmit_ring_init(umdevice, i)) { 752 goto error; 753 } 754 755 desc_cnt = s_list_entry_cnt(&_TXQ_FREE_DESC(umdevice, i)); 756 757 if (desc_cnt != xmitinfo->desc_cnt) { 758 cmn_err(CE_NOTE, 759 "%s: %d tx buffers requested. %d allocated.\n", 760 umdevice->dev_name, xmitinfo->desc_cnt, desc_cnt); 761 } 762 763 alloccnt += desc_cnt; 764 } 765 766 /* FIXME -- Review TX buffer allocation failure threshold. */ 767 if (alloccnt < BNX_XMIT_INIT_FAIL_THRESH) { 768 cmn_err(CE_WARN, 769 "%s: Failed to allocate minimum number of TX buffers.\n", 770 umdevice->dev_name); 771 772 goto error; 773 } 774 775 return (0); 776 777 error: 778 for (i--; i >= TX_CHAIN_IDX0; i--) { 779 bnx_xmit_ring_fini(umdevice, i); 780 } 781 782 mutex_destroy(&umdevice->os_param.xmit_mutex); 783 784 return (-1); 785 } 786 787 void 788 bnx_txpkts_flush(um_device_t * const umdevice) 789 { 790 int i; 791 boolean_t notx_fl = B_FALSE; 792 793 for (i = NUM_TX_CHAIN - 1; i >= TX_CHAIN_IDX0; i--) { 794 lm_abort(&(umdevice->lm_dev), ABORT_OP_TX_CHAIN, i); 795 796 bnx_xmit_ring_reclaim(umdevice, i, 797 &_TXQ_RESC_DESC(umdevice, i)); 798 799 s_list_init(&_TXQ_RESC_DESC(umdevice, i), NULL, NULL, 0); 800 801 if (umdevice->no_tx_credits & BNX_TX_RESOURCES_NO_CREDIT) { 802 umdevice->no_tx_credits &= ~BNX_TX_RESOURCES_NO_CREDIT; 803 notx_fl = B_TRUE; 804 } 805 if (umdevice->no_tx_credits & BNX_TX_RESOURCES_NO_DESC) { 806 umdevice->no_tx_credits &= ~BNX_TX_RESOURCES_NO_DESC; 807 notx_fl = B_TRUE; 808 } 809 if (umdevice->no_tx_credits == 0 && notx_fl == B_TRUE) { 810 mac_tx_update(umdevice->os_param.macp); 811 } 812 } 813 } 814 815 void 816 bnx_txpkts_intr(um_device_t * const umdevice) 817 { 818 int i; 819 820 for (i = TX_CHAIN_IDX0; i < NUM_TX_CHAIN; i++) { 821 bnx_xmit_ring_post(umdevice, i); 822 } 823 } 824 825 void 826 bnx_txpkts_fini(um_device_t * const umdevice) 827 { 828 int i; 829 830 for (i = NUM_TX_CHAIN - 1; i >= TX_CHAIN_IDX0; i--) { 831 bnx_xmit_ring_fini(umdevice, i); 832 } 833 834 mutex_destroy(&umdevice->os_param.xmit_mutex); 835 } 836