15779Sxy150489 /* 25779Sxy150489 * CDDL HEADER START 35779Sxy150489 * 48571SChenlu.Chen@Sun.COM * Copyright(c) 2007-2009 Intel Corporation. All rights reserved. 55779Sxy150489 * The contents of this file are subject to the terms of the 65779Sxy150489 * Common Development and Distribution License (the "License"). 75779Sxy150489 * You may not use this file except in compliance with the License. 85779Sxy150489 * 98571SChenlu.Chen@Sun.COM * You can obtain a copy of the license at: 108571SChenlu.Chen@Sun.COM * http://www.opensolaris.org/os/licensing. 115779Sxy150489 * See the License for the specific language governing permissions 125779Sxy150489 * and limitations under the License. 135779Sxy150489 * 148571SChenlu.Chen@Sun.COM * When using or redistributing this file, you may do so under the 158571SChenlu.Chen@Sun.COM * License only. No other modification of this header is permitted. 168571SChenlu.Chen@Sun.COM * 175779Sxy150489 * If applicable, add the following below this CDDL HEADER, with the 185779Sxy150489 * fields enclosed by brackets "[]" replaced with your own identifying 195779Sxy150489 * information: Portions Copyright [yyyy] [name of copyright owner] 205779Sxy150489 * 215779Sxy150489 * CDDL HEADER END 225779Sxy150489 */ 235779Sxy150489 245779Sxy150489 /* 258571SChenlu.Chen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 269188SPaul.Guo@Sun.COM * Use is subject to license terms. 278275SEric Cheng */ 285779Sxy150489 295779Sxy150489 #include "igb_sw.h" 305779Sxy150489 315779Sxy150489 static boolean_t igb_tx(igb_tx_ring_t *, mblk_t *); 325779Sxy150489 static int igb_tx_copy(igb_tx_ring_t *, tx_control_block_t *, mblk_t *, 337072Sxy150489 uint32_t, boolean_t); 345779Sxy150489 static int igb_tx_bind(igb_tx_ring_t *, tx_control_block_t *, mblk_t *, 355779Sxy150489 uint32_t); 369188SPaul.Guo@Sun.COM static int igb_tx_fill_ring(igb_tx_ring_t *, link_list_t *, tx_context_t *, 379188SPaul.Guo@Sun.COM size_t); 385779Sxy150489 static void igb_save_desc(tx_control_block_t *, uint64_t, size_t); 395779Sxy150489 static tx_control_block_t *igb_get_free_list(igb_tx_ring_t *); 409188SPaul.Guo@Sun.COM static int igb_get_tx_context(mblk_t *, tx_context_t *); 419188SPaul.Guo@Sun.COM static boolean_t igb_check_tx_context(igb_tx_ring_t *, tx_context_t *); 429188SPaul.Guo@Sun.COM static void igb_fill_tx_context(struct e1000_adv_tx_context_desc *, 439188SPaul.Guo@Sun.COM tx_context_t *, uint32_t); 445779Sxy150489 455779Sxy150489 #ifndef IGB_DEBUG 465779Sxy150489 #pragma inline(igb_save_desc) 479188SPaul.Guo@Sun.COM #pragma inline(igb_get_tx_context) 489188SPaul.Guo@Sun.COM #pragma inline(igb_check_tx_context) 499188SPaul.Guo@Sun.COM #pragma inline(igb_fill_tx_context) 505779Sxy150489 #endif 515779Sxy150489 525779Sxy150489 mblk_t * 538275SEric Cheng igb_tx_ring_send(void *arg, mblk_t *mp) 545779Sxy150489 { 558275SEric Cheng igb_tx_ring_t *tx_ring = (igb_tx_ring_t *)arg; 565779Sxy150489 578275SEric Cheng ASSERT(tx_ring != NULL); 585779Sxy150489 59*11367SJason.Xu@Sun.COM if ((tx_ring->igb->igb_state & IGB_SUSPENDED) || 60*11367SJason.Xu@Sun.COM (tx_ring->igb->igb_state & IGB_ERROR) || 61*11367SJason.Xu@Sun.COM !(tx_ring->igb->igb_state & IGB_STARTED)) { 62*11367SJason.Xu@Sun.COM freemsg(mp); 63*11367SJason.Xu@Sun.COM return (NULL); 64*11367SJason.Xu@Sun.COM } 65*11367SJason.Xu@Sun.COM 668275SEric Cheng return ((igb_tx(tx_ring, mp)) ? NULL : mp); 675779Sxy150489 } 685779Sxy150489 695779Sxy150489 /* 705779Sxy150489 * igb_tx - Main transmit processing 715779Sxy150489 * 725779Sxy150489 * Called from igb_m_tx with an mblk ready to transmit. this 735779Sxy150489 * routine sets up the transmit descriptors and sends data to 745779Sxy150489 * the wire. 755779Sxy150489 * 765779Sxy150489 * One mblk can consist of several fragments, each fragment 775779Sxy150489 * will be processed with different methods based on the size. 785779Sxy150489 * For the fragments with size less than the bcopy threshold, 795779Sxy150489 * they will be processed by using bcopy; otherwise, they will 805779Sxy150489 * be processed by using DMA binding. 815779Sxy150489 * 825779Sxy150489 * To process the mblk, a tx control block is got from the 835779Sxy150489 * free list. One tx control block contains one tx buffer, which 845779Sxy150489 * is used to copy mblk fragments' data; and one tx DMA handle, 855779Sxy150489 * which is used to bind a mblk fragment with DMA resource. 865779Sxy150489 * 875779Sxy150489 * Several small mblk fragments can be copied into one tx control 885779Sxy150489 * block's buffer, and then the buffer will be transmitted with 895779Sxy150489 * one tx descriptor. 905779Sxy150489 * 915779Sxy150489 * A large fragment only binds with one tx control block's DMA 925779Sxy150489 * handle, and it can span several tx descriptors for transmitting. 935779Sxy150489 * 945779Sxy150489 * So to transmit a packet (mblk), several tx control blocks can 955779Sxy150489 * be used. After the processing, those tx control blocks will 965779Sxy150489 * be put to the work list. 975779Sxy150489 */ 985779Sxy150489 static boolean_t 995779Sxy150489 igb_tx(igb_tx_ring_t *tx_ring, mblk_t *mp) 1005779Sxy150489 { 1015779Sxy150489 igb_t *igb = tx_ring->igb; 1025779Sxy150489 tx_type_t current_flag, next_flag; 1035779Sxy150489 uint32_t current_len, next_len; 1045779Sxy150489 uint32_t desc_total; 1055779Sxy150489 size_t mbsize; 1065779Sxy150489 int desc_num; 1075779Sxy150489 boolean_t copy_done, eop; 1085779Sxy150489 mblk_t *current_mp, *next_mp, *nmp; 1095779Sxy150489 tx_control_block_t *tcb; 1109188SPaul.Guo@Sun.COM tx_context_t tx_context, *ctx; 1115779Sxy150489 link_list_t pending_list; 1129188SPaul.Guo@Sun.COM mblk_t *new_mp; 1139188SPaul.Guo@Sun.COM mblk_t *previous_mp; 1149188SPaul.Guo@Sun.COM uint32_t hdr_frag_len; 1159188SPaul.Guo@Sun.COM uint32_t hdr_len, len; 1169188SPaul.Guo@Sun.COM uint32_t copy_thresh; 1179188SPaul.Guo@Sun.COM 1189188SPaul.Guo@Sun.COM copy_thresh = tx_ring->copy_thresh; 1195779Sxy150489 1205779Sxy150489 /* Get the mblk size */ 1215779Sxy150489 mbsize = 0; 1225779Sxy150489 for (nmp = mp; nmp != NULL; nmp = nmp->b_cont) { 1239188SPaul.Guo@Sun.COM mbsize += MBLKL(nmp); 1245779Sxy150489 } 1255779Sxy150489 1269188SPaul.Guo@Sun.COM if (igb->tx_hcksum_enable) { 1279188SPaul.Guo@Sun.COM ctx = &tx_context; 1289188SPaul.Guo@Sun.COM /* 1299188SPaul.Guo@Sun.COM * Retrieve offloading context information from the mblk 1309188SPaul.Guo@Sun.COM * that will be used to decide whether/how to fill the 1319188SPaul.Guo@Sun.COM * context descriptor. 1329188SPaul.Guo@Sun.COM */ 1339188SPaul.Guo@Sun.COM if (igb_get_tx_context(mp, ctx) != TX_CXT_SUCCESS) { 1349188SPaul.Guo@Sun.COM freemsg(mp); 1359188SPaul.Guo@Sun.COM return (B_TRUE); 1369188SPaul.Guo@Sun.COM } 1379188SPaul.Guo@Sun.COM 1389188SPaul.Guo@Sun.COM if ((ctx->lso_flag && 1399188SPaul.Guo@Sun.COM (mbsize > (ctx->mac_hdr_len + IGB_LSO_MAXLEN))) || 1409188SPaul.Guo@Sun.COM (!ctx->lso_flag && 1419188SPaul.Guo@Sun.COM (mbsize > (igb->max_frame_size - ETHERFCSL)))) { 1429188SPaul.Guo@Sun.COM freemsg(mp); 1439188SPaul.Guo@Sun.COM IGB_DEBUGLOG_0(igb, "igb_tx: packet oversize"); 1449188SPaul.Guo@Sun.COM return (B_TRUE); 1459188SPaul.Guo@Sun.COM } 1469188SPaul.Guo@Sun.COM } else { 1479188SPaul.Guo@Sun.COM ctx = NULL; 1489188SPaul.Guo@Sun.COM if (mbsize > (igb->max_frame_size - ETHERFCSL)) { 1499188SPaul.Guo@Sun.COM freemsg(mp); 1509188SPaul.Guo@Sun.COM IGB_DEBUGLOG_0(igb, "igb_tx: packet oversize"); 1519188SPaul.Guo@Sun.COM return (B_TRUE); 1529188SPaul.Guo@Sun.COM } 1535779Sxy150489 } 1545779Sxy150489 1555779Sxy150489 /* 1565779Sxy150489 * Check and recycle tx descriptors. 1575779Sxy150489 * The recycle threshold here should be selected carefully 1585779Sxy150489 */ 1595779Sxy150489 if (tx_ring->tbd_free < tx_ring->recycle_thresh) 1605779Sxy150489 tx_ring->tx_recycle(tx_ring); 1615779Sxy150489 1625779Sxy150489 /* 1635779Sxy150489 * After the recycling, if the tbd_free is less than the 1645779Sxy150489 * overload_threshold, assert overload, return B_FALSE; 1655779Sxy150489 * and we need to re-schedule the tx again. 1665779Sxy150489 */ 1675779Sxy150489 if (tx_ring->tbd_free < tx_ring->overload_thresh) { 1685779Sxy150489 tx_ring->reschedule = B_TRUE; 1695779Sxy150489 IGB_DEBUG_STAT(tx_ring->stat_overload); 1705779Sxy150489 return (B_FALSE); 1715779Sxy150489 } 1725779Sxy150489 1735779Sxy150489 /* 1749188SPaul.Guo@Sun.COM * The software should guarantee LSO packet header(MAC+IP+TCP) 1759188SPaul.Guo@Sun.COM * to be within one descriptor - this is required by h/w. 1769188SPaul.Guo@Sun.COM * Here will reallocate and refill the header if 1779188SPaul.Guo@Sun.COM * the headers(MAC+IP+TCP) is physical memory non-contiguous. 1789188SPaul.Guo@Sun.COM */ 1799188SPaul.Guo@Sun.COM if (ctx && ctx->lso_flag) { 1809188SPaul.Guo@Sun.COM hdr_len = ctx->mac_hdr_len + ctx->ip_hdr_len + 1819188SPaul.Guo@Sun.COM ctx->l4_hdr_len; 1829188SPaul.Guo@Sun.COM len = MBLKL(mp); 1839188SPaul.Guo@Sun.COM current_mp = mp; 1849188SPaul.Guo@Sun.COM previous_mp = NULL; 1859188SPaul.Guo@Sun.COM while (len < hdr_len) { 1869188SPaul.Guo@Sun.COM previous_mp = current_mp; 1879188SPaul.Guo@Sun.COM current_mp = current_mp->b_cont; 1889188SPaul.Guo@Sun.COM len += MBLKL(current_mp); 1899188SPaul.Guo@Sun.COM } 1909188SPaul.Guo@Sun.COM 1919188SPaul.Guo@Sun.COM /* 1929188SPaul.Guo@Sun.COM * If len is larger than copy_thresh, we do not 1939188SPaul.Guo@Sun.COM * need to do anything since igb's tx copy mechanism 1949188SPaul.Guo@Sun.COM * will ensure that the headers will be handled 1959188SPaul.Guo@Sun.COM * in one descriptor. 1969188SPaul.Guo@Sun.COM */ 1979188SPaul.Guo@Sun.COM if (len > copy_thresh) { 1989188SPaul.Guo@Sun.COM if (len != hdr_len) { 1999188SPaul.Guo@Sun.COM /* 2009188SPaul.Guo@Sun.COM * If the header and the payload are in 2019188SPaul.Guo@Sun.COM * different mblks, we simply force the 2029188SPaul.Guo@Sun.COM * header to be copied into a 2039188SPaul.Guo@Sun.COM * new-allocated buffer. 2049188SPaul.Guo@Sun.COM */ 2059188SPaul.Guo@Sun.COM hdr_frag_len = hdr_len - 2069188SPaul.Guo@Sun.COM (len - MBLKL(current_mp)); 2079188SPaul.Guo@Sun.COM 2089188SPaul.Guo@Sun.COM /* 2099188SPaul.Guo@Sun.COM * There are two cases we will reallocate 2109188SPaul.Guo@Sun.COM * a mblk for the last header fragment. 2119188SPaul.Guo@Sun.COM * 1. the header is in multiple mblks and 2129188SPaul.Guo@Sun.COM * the last fragment shares the same mblk 2139188SPaul.Guo@Sun.COM * with the payload 2149188SPaul.Guo@Sun.COM * 2. the header is in a single mblk shared 2159188SPaul.Guo@Sun.COM * with the payload but the header crosses 2169188SPaul.Guo@Sun.COM * a page. 2179188SPaul.Guo@Sun.COM */ 2189188SPaul.Guo@Sun.COM if ((current_mp != mp) || 2199188SPaul.Guo@Sun.COM (P2NPHASE((uintptr_t)current_mp->b_rptr, 2209188SPaul.Guo@Sun.COM igb->page_size) < hdr_len)) { 2219188SPaul.Guo@Sun.COM /* 2229188SPaul.Guo@Sun.COM * reallocate the mblk for the last 2239188SPaul.Guo@Sun.COM * header fragment, expect it to be 2249188SPaul.Guo@Sun.COM * copied into pre-allocated 2259188SPaul.Guo@Sun.COM * page-aligned buffer 2269188SPaul.Guo@Sun.COM */ 2279188SPaul.Guo@Sun.COM new_mp = allocb(hdr_frag_len, NULL); 2289188SPaul.Guo@Sun.COM if (!new_mp) { 2299188SPaul.Guo@Sun.COM return (B_FALSE); 2309188SPaul.Guo@Sun.COM } 2319188SPaul.Guo@Sun.COM 2329188SPaul.Guo@Sun.COM /* 2339188SPaul.Guo@Sun.COM * Insert the new mblk 2349188SPaul.Guo@Sun.COM */ 2359188SPaul.Guo@Sun.COM bcopy(current_mp->b_rptr, 2369188SPaul.Guo@Sun.COM new_mp->b_rptr, hdr_frag_len); 2379188SPaul.Guo@Sun.COM new_mp->b_wptr = new_mp->b_rptr + 2389188SPaul.Guo@Sun.COM hdr_frag_len; 2399188SPaul.Guo@Sun.COM new_mp->b_cont = current_mp; 2409188SPaul.Guo@Sun.COM if (previous_mp) 2419188SPaul.Guo@Sun.COM previous_mp->b_cont = new_mp; 2429188SPaul.Guo@Sun.COM else 2439188SPaul.Guo@Sun.COM mp = new_mp; 2449188SPaul.Guo@Sun.COM current_mp->b_rptr += hdr_frag_len; 2459188SPaul.Guo@Sun.COM } 2469188SPaul.Guo@Sun.COM } 2479188SPaul.Guo@Sun.COM 2489188SPaul.Guo@Sun.COM if (copy_thresh < hdr_len) 2499188SPaul.Guo@Sun.COM copy_thresh = hdr_len; 2509188SPaul.Guo@Sun.COM } 2519188SPaul.Guo@Sun.COM } 2529188SPaul.Guo@Sun.COM 2539188SPaul.Guo@Sun.COM /* 2545779Sxy150489 * The pending_list is a linked list that is used to save 2555779Sxy150489 * the tx control blocks that have packet data processed 2565779Sxy150489 * but have not put the data to the tx descriptor ring. 2575779Sxy150489 * It is used to reduce the lock contention of the tx_lock. 2585779Sxy150489 */ 2595779Sxy150489 LINK_LIST_INIT(&pending_list); 2605779Sxy150489 desc_num = 0; 2615779Sxy150489 desc_total = 0; 2625779Sxy150489 2635779Sxy150489 current_mp = mp; 2649188SPaul.Guo@Sun.COM current_len = MBLKL(current_mp); 2655779Sxy150489 /* 2665779Sxy150489 * Decide which method to use for the first fragment 2675779Sxy150489 */ 2689188SPaul.Guo@Sun.COM current_flag = (current_len <= copy_thresh) ? 2695779Sxy150489 USE_COPY : USE_DMA; 2705779Sxy150489 /* 2715779Sxy150489 * If the mblk includes several contiguous small fragments, 2725779Sxy150489 * they may be copied into one buffer. This flag is used to 2735779Sxy150489 * indicate whether there are pending fragments that need to 2745779Sxy150489 * be copied to the current tx buffer. 2755779Sxy150489 * 2765779Sxy150489 * If this flag is B_TRUE, it indicates that a new tx control 2775779Sxy150489 * block is needed to process the next fragment using either 2785779Sxy150489 * copy or DMA binding. 2795779Sxy150489 * 2805779Sxy150489 * Otherwise, it indicates that the next fragment will be 2815779Sxy150489 * copied to the current tx buffer that is maintained by the 2825779Sxy150489 * current tx control block. No new tx control block is needed. 2835779Sxy150489 */ 2845779Sxy150489 copy_done = B_TRUE; 2855779Sxy150489 while (current_mp) { 2865779Sxy150489 next_mp = current_mp->b_cont; 2875779Sxy150489 eop = (next_mp == NULL); /* Last fragment of the packet? */ 2889188SPaul.Guo@Sun.COM next_len = eop ? 0: MBLKL(next_mp); 2895779Sxy150489 2905779Sxy150489 /* 2915779Sxy150489 * When the current fragment is an empty fragment, if 2925779Sxy150489 * the next fragment will still be copied to the current 2935779Sxy150489 * tx buffer, we cannot skip this fragment here. Because 2945779Sxy150489 * the copy processing is pending for completion. We have 2955779Sxy150489 * to process this empty fragment in the tx_copy routine. 2965779Sxy150489 * 2975779Sxy150489 * If the copy processing is completed or a DMA binding 2985779Sxy150489 * processing is just completed, we can just skip this 2995779Sxy150489 * empty fragment. 3005779Sxy150489 */ 3015779Sxy150489 if ((current_len == 0) && (copy_done)) { 3025779Sxy150489 current_mp = next_mp; 3035779Sxy150489 current_len = next_len; 3049188SPaul.Guo@Sun.COM current_flag = (current_len <= copy_thresh) ? 3055779Sxy150489 USE_COPY : USE_DMA; 3065779Sxy150489 continue; 3075779Sxy150489 } 3085779Sxy150489 3095779Sxy150489 if (copy_done) { 3105779Sxy150489 /* 3115779Sxy150489 * Get a new tx control block from the free list 3125779Sxy150489 */ 3135779Sxy150489 tcb = igb_get_free_list(tx_ring); 3145779Sxy150489 3155779Sxy150489 if (tcb == NULL) { 3165779Sxy150489 IGB_DEBUG_STAT(tx_ring->stat_fail_no_tcb); 3175779Sxy150489 goto tx_failure; 3185779Sxy150489 } 3195779Sxy150489 3205779Sxy150489 /* 3215779Sxy150489 * Push the tx control block to the pending list 3225779Sxy150489 * to avoid using lock too early 3235779Sxy150489 */ 3245779Sxy150489 LIST_PUSH_TAIL(&pending_list, &tcb->link); 3255779Sxy150489 } 3265779Sxy150489 3275779Sxy150489 if (current_flag == USE_COPY) { 3285779Sxy150489 /* 3295779Sxy150489 * Check whether to use bcopy or DMA binding to process 3305779Sxy150489 * the next fragment, and if using bcopy, whether we 3315779Sxy150489 * need to continue copying the next fragment into the 3325779Sxy150489 * current tx buffer. 3335779Sxy150489 */ 3345779Sxy150489 ASSERT((tcb->tx_buf.len + current_len) <= 3355779Sxy150489 tcb->tx_buf.size); 3365779Sxy150489 3375779Sxy150489 if (eop) { 3385779Sxy150489 /* 3395779Sxy150489 * This is the last fragment of the packet, so 3405779Sxy150489 * the copy processing will be completed with 3415779Sxy150489 * this fragment. 3425779Sxy150489 */ 3435779Sxy150489 next_flag = USE_NONE; 3445779Sxy150489 copy_done = B_TRUE; 3455779Sxy150489 } else if ((tcb->tx_buf.len + current_len + next_len) > 3465779Sxy150489 tcb->tx_buf.size) { 3475779Sxy150489 /* 3485779Sxy150489 * If the next fragment is too large to be 3495779Sxy150489 * copied to the current tx buffer, we need 3505779Sxy150489 * to complete the current copy processing. 3515779Sxy150489 */ 3529188SPaul.Guo@Sun.COM next_flag = (next_len > copy_thresh) ? 3535779Sxy150489 USE_DMA: USE_COPY; 3545779Sxy150489 copy_done = B_TRUE; 3559188SPaul.Guo@Sun.COM } else if (next_len > copy_thresh) { 3565779Sxy150489 /* 3575779Sxy150489 * The next fragment needs to be processed with 3585779Sxy150489 * DMA binding. So the copy prcessing will be 3595779Sxy150489 * completed with the current fragment. 3605779Sxy150489 */ 3615779Sxy150489 next_flag = USE_DMA; 3625779Sxy150489 copy_done = B_TRUE; 3635779Sxy150489 } else { 3645779Sxy150489 /* 3655779Sxy150489 * Continue to copy the next fragment to the 3665779Sxy150489 * current tx buffer. 3675779Sxy150489 */ 3685779Sxy150489 next_flag = USE_COPY; 3695779Sxy150489 copy_done = B_FALSE; 3705779Sxy150489 } 3715779Sxy150489 3725779Sxy150489 desc_num = igb_tx_copy(tx_ring, tcb, current_mp, 3737072Sxy150489 current_len, copy_done); 3745779Sxy150489 } else { 3755779Sxy150489 /* 3765779Sxy150489 * Check whether to use bcopy or DMA binding to process 3775779Sxy150489 * the next fragment. 3785779Sxy150489 */ 3799188SPaul.Guo@Sun.COM next_flag = (next_len > copy_thresh) ? 3805779Sxy150489 USE_DMA: USE_COPY; 3815779Sxy150489 ASSERT(copy_done == B_TRUE); 3825779Sxy150489 3835779Sxy150489 desc_num = igb_tx_bind(tx_ring, tcb, current_mp, 3845779Sxy150489 current_len); 3855779Sxy150489 } 3865779Sxy150489 3875779Sxy150489 if (desc_num > 0) 3885779Sxy150489 desc_total += desc_num; 3895779Sxy150489 else if (desc_num < 0) 3905779Sxy150489 goto tx_failure; 3915779Sxy150489 3925779Sxy150489 current_mp = next_mp; 3935779Sxy150489 current_len = next_len; 3945779Sxy150489 current_flag = next_flag; 3955779Sxy150489 } 3965779Sxy150489 3975779Sxy150489 /* 3985779Sxy150489 * Attach the mblk to the last tx control block 3995779Sxy150489 */ 4005779Sxy150489 ASSERT(tcb); 4015779Sxy150489 ASSERT(tcb->mp == NULL); 4025779Sxy150489 tcb->mp = mp; 4035779Sxy150489 4045779Sxy150489 /* 4055779Sxy150489 * Before fill the tx descriptor ring with the data, we need to 4065779Sxy150489 * ensure there are adequate free descriptors for transmit 4075779Sxy150489 * (including one context descriptor). 4085779Sxy150489 */ 4095779Sxy150489 if (tx_ring->tbd_free < (desc_total + 1)) { 4105779Sxy150489 tx_ring->tx_recycle(tx_ring); 4115779Sxy150489 } 4125779Sxy150489 4135779Sxy150489 mutex_enter(&tx_ring->tx_lock); 4145779Sxy150489 4155779Sxy150489 /* 4165779Sxy150489 * If the number of free tx descriptors is not enough for transmit 4175779Sxy150489 * then return failure. 4185779Sxy150489 * 4195779Sxy150489 * Note: we must put this check under the mutex protection to 4205779Sxy150489 * ensure the correctness when multiple threads access it in 4215779Sxy150489 * parallel. 4225779Sxy150489 */ 4235779Sxy150489 if (tx_ring->tbd_free < (desc_total + 1)) { 4245779Sxy150489 IGB_DEBUG_STAT(tx_ring->stat_fail_no_tbd); 4255779Sxy150489 mutex_exit(&tx_ring->tx_lock); 4265779Sxy150489 goto tx_failure; 4275779Sxy150489 } 4285779Sxy150489 4299188SPaul.Guo@Sun.COM desc_num = igb_tx_fill_ring(tx_ring, &pending_list, ctx, mbsize); 4305779Sxy150489 4315779Sxy150489 ASSERT((desc_num == desc_total) || (desc_num == (desc_total + 1))); 4325779Sxy150489 4335779Sxy150489 mutex_exit(&tx_ring->tx_lock); 4345779Sxy150489 4355779Sxy150489 return (B_TRUE); 4365779Sxy150489 4375779Sxy150489 tx_failure: 4385779Sxy150489 /* 4395779Sxy150489 * Discard the mblk and free the used resources 4405779Sxy150489 */ 4415779Sxy150489 tcb = (tx_control_block_t *)LIST_GET_HEAD(&pending_list); 4425779Sxy150489 while (tcb) { 4435779Sxy150489 tcb->mp = NULL; 4445779Sxy150489 4455779Sxy150489 igb_free_tcb(tcb); 4465779Sxy150489 4475779Sxy150489 tcb = (tx_control_block_t *) 4485779Sxy150489 LIST_GET_NEXT(&pending_list, &tcb->link); 4495779Sxy150489 } 4505779Sxy150489 4515779Sxy150489 /* 4525779Sxy150489 * Return the tx control blocks in the pending list to the free list. 4535779Sxy150489 */ 4545779Sxy150489 igb_put_free_list(tx_ring, &pending_list); 4555779Sxy150489 4565779Sxy150489 /* Transmit failed, do not drop the mblk, rechedule the transmit */ 4575779Sxy150489 tx_ring->reschedule = B_TRUE; 4585779Sxy150489 4595779Sxy150489 return (B_FALSE); 4605779Sxy150489 } 4615779Sxy150489 4625779Sxy150489 /* 4635779Sxy150489 * igb_tx_copy 4645779Sxy150489 * 4655779Sxy150489 * Copy the mblk fragment to the pre-allocated tx buffer 4665779Sxy150489 */ 4675779Sxy150489 static int 4685779Sxy150489 igb_tx_copy(igb_tx_ring_t *tx_ring, tx_control_block_t *tcb, mblk_t *mp, 4697072Sxy150489 uint32_t len, boolean_t copy_done) 4705779Sxy150489 { 4715779Sxy150489 dma_buffer_t *tx_buf; 4725779Sxy150489 uint32_t desc_num; 4735779Sxy150489 _NOTE(ARGUNUSED(tx_ring)); 4745779Sxy150489 4755779Sxy150489 tx_buf = &tcb->tx_buf; 4765779Sxy150489 4775779Sxy150489 /* 4785779Sxy150489 * Copy the packet data of the mblk fragment into the 4795779Sxy150489 * pre-allocated tx buffer, which is maintained by the 4805779Sxy150489 * tx control block. 4815779Sxy150489 * 4825779Sxy150489 * Several mblk fragments can be copied into one tx buffer. 4835779Sxy150489 * The destination address of the current copied fragment in 4845779Sxy150489 * the tx buffer is next to the end of the previous copied 4855779Sxy150489 * fragment. 4865779Sxy150489 */ 4875779Sxy150489 if (len > 0) { 4885779Sxy150489 bcopy(mp->b_rptr, tx_buf->address + tx_buf->len, len); 4895779Sxy150489 4905779Sxy150489 tx_buf->len += len; 4915779Sxy150489 tcb->frag_num++; 4925779Sxy150489 } 4935779Sxy150489 4945779Sxy150489 desc_num = 0; 4955779Sxy150489 4965779Sxy150489 /* 4975779Sxy150489 * If it is the last fragment copied to the current tx buffer, 4985779Sxy150489 * in other words, if there's no remaining fragment or the remaining 4995779Sxy150489 * fragment requires a new tx control block to process, we need to 5005779Sxy150489 * complete the current copy processing by syncing up the current 5015779Sxy150489 * DMA buffer and saving the descriptor data. 5025779Sxy150489 */ 5035779Sxy150489 if (copy_done) { 5045779Sxy150489 /* 5055779Sxy150489 * Sync the DMA buffer of the packet data 5065779Sxy150489 */ 5075779Sxy150489 DMA_SYNC(tx_buf, DDI_DMA_SYNC_FORDEV); 5085779Sxy150489 5095779Sxy150489 tcb->tx_type = USE_COPY; 5105779Sxy150489 5115779Sxy150489 /* 5125779Sxy150489 * Save the address and length to the private data structure 5135779Sxy150489 * of the tx control block, which will be used to fill the 5145779Sxy150489 * tx descriptor ring after all the fragments are processed. 5155779Sxy150489 */ 5165779Sxy150489 igb_save_desc(tcb, tx_buf->dma_address, tx_buf->len); 5175779Sxy150489 desc_num++; 5185779Sxy150489 } 5195779Sxy150489 5205779Sxy150489 return (desc_num); 5215779Sxy150489 } 5225779Sxy150489 5235779Sxy150489 /* 5245779Sxy150489 * igb_tx_bind 5255779Sxy150489 * 5265779Sxy150489 * Bind the mblk fragment with DMA 5275779Sxy150489 */ 5285779Sxy150489 static int 5295779Sxy150489 igb_tx_bind(igb_tx_ring_t *tx_ring, tx_control_block_t *tcb, mblk_t *mp, 5305779Sxy150489 uint32_t len) 5315779Sxy150489 { 5325779Sxy150489 int status, i; 5335779Sxy150489 ddi_dma_cookie_t dma_cookie; 5345779Sxy150489 uint_t ncookies; 5355779Sxy150489 int desc_num; 5365779Sxy150489 5375779Sxy150489 /* 5385779Sxy150489 * Use DMA binding to process the mblk fragment 5395779Sxy150489 */ 5405779Sxy150489 status = ddi_dma_addr_bind_handle(tcb->tx_dma_handle, NULL, 5415779Sxy150489 (caddr_t)mp->b_rptr, len, 5425779Sxy150489 DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 5435779Sxy150489 0, &dma_cookie, &ncookies); 5445779Sxy150489 5455779Sxy150489 if (status != DDI_DMA_MAPPED) { 5465779Sxy150489 IGB_DEBUG_STAT(tx_ring->stat_fail_dma_bind); 5475779Sxy150489 return (-1); 5485779Sxy150489 } 5495779Sxy150489 5505779Sxy150489 tcb->frag_num++; 5515779Sxy150489 tcb->tx_type = USE_DMA; 5525779Sxy150489 /* 5535779Sxy150489 * Each fragment can span several cookies. One cookie will have 5545779Sxy150489 * one tx descriptor to transmit. 5555779Sxy150489 */ 5565779Sxy150489 desc_num = 0; 5575779Sxy150489 for (i = ncookies; i > 0; i--) { 5585779Sxy150489 /* 5595779Sxy150489 * Save the address and length to the private data structure 5605779Sxy150489 * of the tx control block, which will be used to fill the 5615779Sxy150489 * tx descriptor ring after all the fragments are processed. 5625779Sxy150489 */ 5635779Sxy150489 igb_save_desc(tcb, 5645779Sxy150489 dma_cookie.dmac_laddress, 5655779Sxy150489 dma_cookie.dmac_size); 5665779Sxy150489 5675779Sxy150489 desc_num++; 5685779Sxy150489 5695779Sxy150489 if (i > 1) 5705779Sxy150489 ddi_dma_nextcookie(tcb->tx_dma_handle, &dma_cookie); 5715779Sxy150489 } 5725779Sxy150489 5735779Sxy150489 return (desc_num); 5745779Sxy150489 } 5755779Sxy150489 5765779Sxy150489 /* 5779188SPaul.Guo@Sun.COM * igb_get_tx_context 5785779Sxy150489 * 5799188SPaul.Guo@Sun.COM * Get the tx context information from the mblk 5805779Sxy150489 */ 5819188SPaul.Guo@Sun.COM static int 5829188SPaul.Guo@Sun.COM igb_get_tx_context(mblk_t *mp, tx_context_t *ctx) 5835779Sxy150489 { 5845779Sxy150489 uint32_t start; 5855779Sxy150489 uint32_t flags; 5869188SPaul.Guo@Sun.COM uint32_t lso_flag; 5879188SPaul.Guo@Sun.COM uint32_t mss; 5885779Sxy150489 uint32_t len; 5895779Sxy150489 uint32_t size; 5905779Sxy150489 uint32_t offset; 5915779Sxy150489 unsigned char *pos; 5925779Sxy150489 ushort_t etype; 5935779Sxy150489 uint32_t mac_hdr_len; 5945779Sxy150489 uint32_t l4_proto; 5959188SPaul.Guo@Sun.COM uint32_t l4_hdr_len; 5965779Sxy150489 5975779Sxy150489 ASSERT(mp != NULL); 5985779Sxy150489 5995779Sxy150489 hcksum_retrieve(mp, NULL, NULL, &start, NULL, NULL, NULL, &flags); 6009188SPaul.Guo@Sun.COM bzero(ctx, sizeof (tx_context_t)); 6015779Sxy150489 6029188SPaul.Guo@Sun.COM ctx->hcksum_flags = flags; 6035779Sxy150489 6045779Sxy150489 if (flags == 0) 6059188SPaul.Guo@Sun.COM return (TX_CXT_SUCCESS); 6069188SPaul.Guo@Sun.COM 6079188SPaul.Guo@Sun.COM lso_info_get(mp, &mss, &lso_flag); 6089188SPaul.Guo@Sun.COM ctx->mss = mss; 6099188SPaul.Guo@Sun.COM ctx->lso_flag = (lso_flag == HW_LSO); 6109188SPaul.Guo@Sun.COM 6119188SPaul.Guo@Sun.COM /* 6129188SPaul.Guo@Sun.COM * LSO relies on tx h/w checksum, so here the packet will be 6139188SPaul.Guo@Sun.COM * dropped if the h/w checksum flags are not set. 6149188SPaul.Guo@Sun.COM */ 6159188SPaul.Guo@Sun.COM if (ctx->lso_flag) { 6169188SPaul.Guo@Sun.COM if (!((ctx->hcksum_flags & HCK_PARTIALCKSUM) && 6179188SPaul.Guo@Sun.COM (ctx->hcksum_flags & HCK_IPV4_HDRCKSUM))) { 6189188SPaul.Guo@Sun.COM IGB_DEBUGLOG_0(NULL, "igb_tx: h/w " 6199188SPaul.Guo@Sun.COM "checksum flags are not set for LSO"); 6209188SPaul.Guo@Sun.COM return (TX_CXT_E_LSO_CSUM); 6219188SPaul.Guo@Sun.COM } 6229188SPaul.Guo@Sun.COM } 6235779Sxy150489 6245779Sxy150489 etype = 0; 6255779Sxy150489 mac_hdr_len = 0; 6265779Sxy150489 l4_proto = 0; 6275779Sxy150489 6285779Sxy150489 /* 6295779Sxy150489 * Firstly get the position of the ether_type/ether_tpid. 6305779Sxy150489 * Here we don't assume the ether (VLAN) header is fully included 6315779Sxy150489 * in one mblk fragment, so we go thourgh the fragments to parse 6325779Sxy150489 * the ether type. 6335779Sxy150489 */ 6349188SPaul.Guo@Sun.COM size = len = MBLKL(mp); 6355779Sxy150489 offset = offsetof(struct ether_header, ether_type); 6365779Sxy150489 while (size <= offset) { 6375779Sxy150489 mp = mp->b_cont; 6385779Sxy150489 ASSERT(mp != NULL); 6399188SPaul.Guo@Sun.COM len = MBLKL(mp); 6405779Sxy150489 size += len; 6415779Sxy150489 } 6425779Sxy150489 pos = mp->b_rptr + offset + len - size; 6435779Sxy150489 6445779Sxy150489 etype = ntohs(*(ushort_t *)(uintptr_t)pos); 6455779Sxy150489 if (etype == ETHERTYPE_VLAN) { 6465779Sxy150489 /* 6475779Sxy150489 * Get the position of the ether_type in VLAN header 6485779Sxy150489 */ 6495779Sxy150489 offset = offsetof(struct ether_vlan_header, ether_type); 6505779Sxy150489 while (size <= offset) { 6515779Sxy150489 mp = mp->b_cont; 6525779Sxy150489 ASSERT(mp != NULL); 6539188SPaul.Guo@Sun.COM len = MBLKL(mp); 6545779Sxy150489 size += len; 6555779Sxy150489 } 6565779Sxy150489 pos = mp->b_rptr + offset + len - size; 6575779Sxy150489 6585779Sxy150489 etype = ntohs(*(ushort_t *)(uintptr_t)pos); 6595779Sxy150489 mac_hdr_len = sizeof (struct ether_vlan_header); 6605779Sxy150489 } else { 6615779Sxy150489 mac_hdr_len = sizeof (struct ether_header); 6625779Sxy150489 } 6635779Sxy150489 6645779Sxy150489 /* 6659188SPaul.Guo@Sun.COM * Here we assume the IP(V6) header is fully included in one 6669188SPaul.Guo@Sun.COM * mblk fragment. 6675779Sxy150489 */ 6685779Sxy150489 switch (etype) { 6695779Sxy150489 case ETHERTYPE_IP: 6709188SPaul.Guo@Sun.COM offset = mac_hdr_len; 6715779Sxy150489 while (size <= offset) { 6725779Sxy150489 mp = mp->b_cont; 6735779Sxy150489 ASSERT(mp != NULL); 6749188SPaul.Guo@Sun.COM len = MBLKL(mp); 6755779Sxy150489 size += len; 6765779Sxy150489 } 6775779Sxy150489 pos = mp->b_rptr + offset + len - size; 6785779Sxy150489 6799188SPaul.Guo@Sun.COM if (ctx->lso_flag) { 6809188SPaul.Guo@Sun.COM *((uint16_t *)(uintptr_t)(pos + offsetof(ipha_t, 6819188SPaul.Guo@Sun.COM ipha_length))) = 0; 6829188SPaul.Guo@Sun.COM 6839188SPaul.Guo@Sun.COM /* 6849188SPaul.Guo@Sun.COM * To utilize igb LSO, here need to fill 6859188SPaul.Guo@Sun.COM * the tcp checksum field of the packet with the 6869188SPaul.Guo@Sun.COM * following pseudo-header checksum: 6879188SPaul.Guo@Sun.COM * (ip_source_addr, ip_destination_addr, l4_proto) 6889188SPaul.Guo@Sun.COM * and also need to fill the ip header checksum 6899188SPaul.Guo@Sun.COM * with zero. Currently the tcp/ip stack has done 6909188SPaul.Guo@Sun.COM * these. 6919188SPaul.Guo@Sun.COM */ 6929188SPaul.Guo@Sun.COM } 6939188SPaul.Guo@Sun.COM 6949188SPaul.Guo@Sun.COM l4_proto = *(uint8_t *)(pos + offsetof(ipha_t, ipha_protocol)); 6955779Sxy150489 break; 6965779Sxy150489 case ETHERTYPE_IPV6: 6975779Sxy150489 offset = offsetof(ip6_t, ip6_nxt) + mac_hdr_len; 6985779Sxy150489 while (size <= offset) { 6995779Sxy150489 mp = mp->b_cont; 7005779Sxy150489 ASSERT(mp != NULL); 7019188SPaul.Guo@Sun.COM len = MBLKL(mp); 7025779Sxy150489 size += len; 7035779Sxy150489 } 7045779Sxy150489 pos = mp->b_rptr + offset + len - size; 7055779Sxy150489 7065779Sxy150489 l4_proto = *(uint8_t *)pos; 7075779Sxy150489 break; 7085779Sxy150489 default: 7095779Sxy150489 /* Unrecoverable error */ 7109188SPaul.Guo@Sun.COM IGB_DEBUGLOG_0(NULL, "Ethernet type field error with " 7119188SPaul.Guo@Sun.COM "tx hcksum flag set"); 7129188SPaul.Guo@Sun.COM return (TX_CXT_E_ETHER_TYPE); 7135779Sxy150489 } 7145779Sxy150489 7159188SPaul.Guo@Sun.COM if (ctx->lso_flag) { 7169188SPaul.Guo@Sun.COM offset = mac_hdr_len + start; 7179188SPaul.Guo@Sun.COM while (size <= offset) { 7189188SPaul.Guo@Sun.COM mp = mp->b_cont; 7199188SPaul.Guo@Sun.COM ASSERT(mp != NULL); 7209188SPaul.Guo@Sun.COM len = MBLKL(mp); 7219188SPaul.Guo@Sun.COM size += len; 7229188SPaul.Guo@Sun.COM } 7239188SPaul.Guo@Sun.COM pos = mp->b_rptr + offset + len - size; 7249188SPaul.Guo@Sun.COM 7259188SPaul.Guo@Sun.COM l4_hdr_len = TCP_HDR_LENGTH((tcph_t *)pos); 7269188SPaul.Guo@Sun.COM } else { 7279188SPaul.Guo@Sun.COM /* 7289188SPaul.Guo@Sun.COM * l4 header length is only required for LSO 7299188SPaul.Guo@Sun.COM */ 7309188SPaul.Guo@Sun.COM l4_hdr_len = 0; 7319188SPaul.Guo@Sun.COM } 7329188SPaul.Guo@Sun.COM 7339188SPaul.Guo@Sun.COM ctx->mac_hdr_len = mac_hdr_len; 7349188SPaul.Guo@Sun.COM ctx->ip_hdr_len = start; 7359188SPaul.Guo@Sun.COM ctx->l4_proto = l4_proto; 7369188SPaul.Guo@Sun.COM ctx->l4_hdr_len = l4_hdr_len; 7379188SPaul.Guo@Sun.COM 7389188SPaul.Guo@Sun.COM return (TX_CXT_SUCCESS); 7395779Sxy150489 } 7405779Sxy150489 7415779Sxy150489 /* 7429188SPaul.Guo@Sun.COM * igb_check_tx_context 7435779Sxy150489 * 7445779Sxy150489 * Check if a new context descriptor is needed 7455779Sxy150489 */ 7465779Sxy150489 static boolean_t 7479188SPaul.Guo@Sun.COM igb_check_tx_context(igb_tx_ring_t *tx_ring, tx_context_t *ctx) 7485779Sxy150489 { 7499188SPaul.Guo@Sun.COM tx_context_t *last; 7505779Sxy150489 7519188SPaul.Guo@Sun.COM if (ctx == NULL) 7525779Sxy150489 return (B_FALSE); 7535779Sxy150489 7545779Sxy150489 /* 7559188SPaul.Guo@Sun.COM * Compare the context data retrieved from the mblk and the 7569188SPaul.Guo@Sun.COM * stored context data of the last context descriptor. The data 7575779Sxy150489 * need to be checked are: 7585779Sxy150489 * hcksum_flags 7595779Sxy150489 * l4_proto 7609188SPaul.Guo@Sun.COM * mss (only check for LSO) 7619188SPaul.Guo@Sun.COM * l4_hdr_len (only check for LSO) 7629188SPaul.Guo@Sun.COM * ip_hdr_len 7635779Sxy150489 * mac_hdr_len 7645779Sxy150489 * Either one of the above data is changed, a new context descriptor 7655779Sxy150489 * will be needed. 7665779Sxy150489 */ 7679188SPaul.Guo@Sun.COM last = &tx_ring->tx_context; 7685779Sxy150489 7699188SPaul.Guo@Sun.COM if (ctx->hcksum_flags != 0) { 7709188SPaul.Guo@Sun.COM if ((ctx->hcksum_flags != last->hcksum_flags) || 7719188SPaul.Guo@Sun.COM (ctx->l4_proto != last->l4_proto) || 7729188SPaul.Guo@Sun.COM (ctx->lso_flag && ((ctx->mss != last->mss) || 7739188SPaul.Guo@Sun.COM (ctx->l4_hdr_len != last->l4_hdr_len))) || 7749188SPaul.Guo@Sun.COM (ctx->ip_hdr_len != last->ip_hdr_len) || 7759188SPaul.Guo@Sun.COM (ctx->mac_hdr_len != last->mac_hdr_len)) { 7765779Sxy150489 return (B_TRUE); 7775779Sxy150489 } 7785779Sxy150489 } 7795779Sxy150489 7805779Sxy150489 return (B_FALSE); 7815779Sxy150489 } 7825779Sxy150489 7835779Sxy150489 /* 7849188SPaul.Guo@Sun.COM * igb_fill_tx_context 7855779Sxy150489 * 7865779Sxy150489 * Fill the context descriptor with hardware checksum informations 7875779Sxy150489 */ 7885779Sxy150489 static void 7899188SPaul.Guo@Sun.COM igb_fill_tx_context(struct e1000_adv_tx_context_desc *ctx_tbd, 7909188SPaul.Guo@Sun.COM tx_context_t *ctx, uint32_t ring_index) 7915779Sxy150489 { 7925779Sxy150489 /* 7935779Sxy150489 * Fill the context descriptor with the checksum 7945779Sxy150489 * context information we've got 7955779Sxy150489 */ 7969188SPaul.Guo@Sun.COM ctx_tbd->vlan_macip_lens = ctx->ip_hdr_len; 7979188SPaul.Guo@Sun.COM ctx_tbd->vlan_macip_lens |= ctx->mac_hdr_len << 7985779Sxy150489 E1000_ADVTXD_MACLEN_SHIFT; 7995779Sxy150489 8005779Sxy150489 ctx_tbd->type_tucmd_mlhl = 8015779Sxy150489 E1000_ADVTXD_DCMD_DEXT | E1000_ADVTXD_DTYP_CTXT; 8025779Sxy150489 8039188SPaul.Guo@Sun.COM if (ctx->hcksum_flags & HCK_IPV4_HDRCKSUM) 8045779Sxy150489 ctx_tbd->type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_IPV4; 8055779Sxy150489 8069188SPaul.Guo@Sun.COM if (ctx->hcksum_flags & HCK_PARTIALCKSUM) { 8079188SPaul.Guo@Sun.COM switch (ctx->l4_proto) { 8085779Sxy150489 case IPPROTO_TCP: 8095779Sxy150489 ctx_tbd->type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_TCP; 8105779Sxy150489 break; 8115779Sxy150489 case IPPROTO_UDP: 8125779Sxy150489 /* 8135779Sxy150489 * We don't have to explicitly set: 8145779Sxy150489 * ctx_tbd->type_tucmd_mlhl |= 8155779Sxy150489 * E1000_ADVTXD_TUCMD_L4T_UDP; 8165779Sxy150489 * Because E1000_ADVTXD_TUCMD_L4T_UDP == 0b 8175779Sxy150489 */ 8185779Sxy150489 break; 8195779Sxy150489 default: 8205779Sxy150489 /* Unrecoverable error */ 8215779Sxy150489 IGB_DEBUGLOG_0(NULL, "L4 type error with tx hcksum"); 8225779Sxy150489 break; 8235779Sxy150489 } 8245779Sxy150489 } 8255779Sxy150489 8265779Sxy150489 ctx_tbd->seqnum_seed = 0; 8278275SEric Cheng ctx_tbd->mss_l4len_idx = ring_index << 4; 8289188SPaul.Guo@Sun.COM if (ctx->lso_flag) { 8299188SPaul.Guo@Sun.COM ctx_tbd->mss_l4len_idx |= 8309188SPaul.Guo@Sun.COM (ctx->l4_hdr_len << E1000_ADVTXD_L4LEN_SHIFT) | 8319188SPaul.Guo@Sun.COM (ctx->mss << E1000_ADVTXD_MSS_SHIFT); 8329188SPaul.Guo@Sun.COM } 8335779Sxy150489 } 8345779Sxy150489 8355779Sxy150489 /* 8365779Sxy150489 * igb_tx_fill_ring 8375779Sxy150489 * 8385779Sxy150489 * Fill the tx descriptor ring with the data 8395779Sxy150489 */ 8405779Sxy150489 static int 8415779Sxy150489 igb_tx_fill_ring(igb_tx_ring_t *tx_ring, link_list_t *pending_list, 8429188SPaul.Guo@Sun.COM tx_context_t *ctx, size_t mbsize) 8435779Sxy150489 { 8445779Sxy150489 struct e1000_hw *hw = &tx_ring->igb->hw; 8455779Sxy150489 boolean_t load_context; 8465779Sxy150489 uint32_t index, tcb_index, desc_num; 8475779Sxy150489 union e1000_adv_tx_desc *tbd, *first_tbd; 8485779Sxy150489 tx_control_block_t *tcb, *first_tcb; 8495779Sxy150489 uint32_t hcksum_flags; 8505779Sxy150489 int i; 8516624Sgl147354 igb_t *igb = tx_ring->igb; 8525779Sxy150489 8535779Sxy150489 ASSERT(mutex_owned(&tx_ring->tx_lock)); 8545779Sxy150489 8555779Sxy150489 tbd = NULL; 8565779Sxy150489 first_tbd = NULL; 8575779Sxy150489 first_tcb = NULL; 8585779Sxy150489 desc_num = 0; 8595779Sxy150489 hcksum_flags = 0; 8605779Sxy150489 load_context = B_FALSE; 8615779Sxy150489 8625779Sxy150489 /* 8635779Sxy150489 * Get the index of the first tx descriptor that will be filled, 8645779Sxy150489 * and the index of the first work list item that will be attached 8655779Sxy150489 * with the first used tx control block in the pending list. 8665779Sxy150489 * Note: the two indexes are the same. 8675779Sxy150489 */ 8685779Sxy150489 index = tx_ring->tbd_tail; 8695779Sxy150489 tcb_index = tx_ring->tbd_tail; 8705779Sxy150489 8719188SPaul.Guo@Sun.COM if (ctx != NULL) { 8729188SPaul.Guo@Sun.COM hcksum_flags = ctx->hcksum_flags; 8735779Sxy150489 8745779Sxy150489 /* 8755779Sxy150489 * Check if a new context descriptor is needed for this packet 8765779Sxy150489 */ 8779188SPaul.Guo@Sun.COM load_context = igb_check_tx_context(tx_ring, ctx); 8785779Sxy150489 if (load_context) { 8795779Sxy150489 first_tcb = (tx_control_block_t *) 8805779Sxy150489 LIST_GET_HEAD(pending_list); 8815779Sxy150489 tbd = &tx_ring->tbd_ring[index]; 8825779Sxy150489 8835779Sxy150489 /* 8845779Sxy150489 * Fill the context descriptor with the 8855779Sxy150489 * hardware checksum offload informations. 8865779Sxy150489 */ 8879188SPaul.Guo@Sun.COM igb_fill_tx_context( 8889188SPaul.Guo@Sun.COM (struct e1000_adv_tx_context_desc *)tbd, 8899188SPaul.Guo@Sun.COM ctx, tx_ring->index); 8905779Sxy150489 8915779Sxy150489 index = NEXT_INDEX(index, 1, tx_ring->ring_size); 8925779Sxy150489 desc_num++; 8935779Sxy150489 8945779Sxy150489 /* 8955779Sxy150489 * Store the checksum context data if 8965779Sxy150489 * a new context descriptor is added 8975779Sxy150489 */ 8989188SPaul.Guo@Sun.COM tx_ring->tx_context = *ctx; 8995779Sxy150489 } 9005779Sxy150489 } 9015779Sxy150489 9025779Sxy150489 first_tbd = &tx_ring->tbd_ring[index]; 9035779Sxy150489 9045779Sxy150489 /* 9055779Sxy150489 * Fill tx data descriptors with the data saved in the pending list. 9065779Sxy150489 * The tx control blocks in the pending list are added to the work list 9075779Sxy150489 * at the same time. 9085779Sxy150489 * 9095779Sxy150489 * The work list is strictly 1:1 corresponding to the descriptor ring. 9105779Sxy150489 * One item of the work list corresponds to one tx descriptor. Because 9115779Sxy150489 * one tx control block can span multiple tx descriptors, the tx 9125779Sxy150489 * control block will be added to the first work list item that 9135779Sxy150489 * corresponds to the first tx descriptor generated from that tx 9145779Sxy150489 * control block. 9155779Sxy150489 */ 9165779Sxy150489 tcb = (tx_control_block_t *)LIST_POP_HEAD(pending_list); 9175779Sxy150489 while (tcb != NULL) { 9185779Sxy150489 9195779Sxy150489 for (i = 0; i < tcb->desc_num; i++) { 9205779Sxy150489 tbd = &tx_ring->tbd_ring[index]; 9215779Sxy150489 9225779Sxy150489 tbd->read.buffer_addr = tcb->desc[i].address; 9235779Sxy150489 tbd->read.cmd_type_len = tcb->desc[i].length; 9245779Sxy150489 9255779Sxy150489 tbd->read.cmd_type_len |= E1000_ADVTXD_DCMD_RS | 9268571SChenlu.Chen@Sun.COM E1000_ADVTXD_DCMD_DEXT | E1000_ADVTXD_DTYP_DATA | 9278571SChenlu.Chen@Sun.COM E1000_ADVTXD_DCMD_IFCS; 9285779Sxy150489 9295779Sxy150489 tbd->read.olinfo_status = 0; 9305779Sxy150489 9315779Sxy150489 index = NEXT_INDEX(index, 1, tx_ring->ring_size); 9325779Sxy150489 desc_num++; 9335779Sxy150489 } 9345779Sxy150489 9355779Sxy150489 if (first_tcb != NULL) { 9365779Sxy150489 /* 9375779Sxy150489 * Count the checksum context descriptor for 9385779Sxy150489 * the first tx control block. 9395779Sxy150489 */ 9405779Sxy150489 first_tcb->desc_num++; 9415779Sxy150489 first_tcb = NULL; 9425779Sxy150489 } 9435779Sxy150489 9445779Sxy150489 /* 9455779Sxy150489 * Add the tx control block to the work list 9465779Sxy150489 */ 9475779Sxy150489 ASSERT(tx_ring->work_list[tcb_index] == NULL); 9485779Sxy150489 tx_ring->work_list[tcb_index] = tcb; 9495779Sxy150489 9505779Sxy150489 tcb_index = index; 9515779Sxy150489 tcb = (tx_control_block_t *)LIST_POP_HEAD(pending_list); 9525779Sxy150489 } 9535779Sxy150489 9545779Sxy150489 /* 9555779Sxy150489 * The Insert Ethernet CRC (IFCS) bit and the checksum fields are only 9565779Sxy150489 * valid in the first descriptor of the packet. 9579188SPaul.Guo@Sun.COM * 82576 also requires the payload length setting even without LSO 9585779Sxy150489 */ 9595779Sxy150489 ASSERT(first_tbd != NULL); 9605779Sxy150489 first_tbd->read.cmd_type_len |= E1000_ADVTXD_DCMD_IFCS; 9619188SPaul.Guo@Sun.COM if (ctx != NULL && ctx->lso_flag) { 9629188SPaul.Guo@Sun.COM first_tbd->read.cmd_type_len |= E1000_ADVTXD_DCMD_TSE; 9639188SPaul.Guo@Sun.COM first_tbd->read.olinfo_status |= 9649188SPaul.Guo@Sun.COM (mbsize - ctx->mac_hdr_len - ctx->ip_hdr_len 9659188SPaul.Guo@Sun.COM - ctx->l4_hdr_len) << E1000_ADVTXD_PAYLEN_SHIFT; 9669188SPaul.Guo@Sun.COM } else { 96711155SJason.Xu@Sun.COM if (hw->mac.type >= e1000_82576) { 9689188SPaul.Guo@Sun.COM first_tbd->read.olinfo_status |= 9699188SPaul.Guo@Sun.COM (mbsize << E1000_ADVTXD_PAYLEN_SHIFT); 9709188SPaul.Guo@Sun.COM } 9718571SChenlu.Chen@Sun.COM } 9725779Sxy150489 9735779Sxy150489 /* Set hardware checksum bits */ 9745779Sxy150489 if (hcksum_flags != 0) { 9755779Sxy150489 if (hcksum_flags & HCK_IPV4_HDRCKSUM) 9765779Sxy150489 first_tbd->read.olinfo_status |= 9775779Sxy150489 E1000_TXD_POPTS_IXSM << 8; 9785779Sxy150489 if (hcksum_flags & HCK_PARTIALCKSUM) 9795779Sxy150489 first_tbd->read.olinfo_status |= 9805779Sxy150489 E1000_TXD_POPTS_TXSM << 8; 9818275SEric Cheng first_tbd->read.olinfo_status |= tx_ring->index << 4; 9825779Sxy150489 } 9835779Sxy150489 9845779Sxy150489 /* 9855779Sxy150489 * The last descriptor of packet needs End Of Packet (EOP), 9865779Sxy150489 * and Report Status (RS) bits set 9875779Sxy150489 */ 9885779Sxy150489 ASSERT(tbd != NULL); 9895779Sxy150489 tbd->read.cmd_type_len |= 9905779Sxy150489 E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_RS; 9915779Sxy150489 9928275SEric Cheng IGB_DEBUG_STAT(tx_ring->stat_pkt_cnt); 9938275SEric Cheng 9945779Sxy150489 /* 9955779Sxy150489 * Sync the DMA buffer of the tx descriptor ring 9965779Sxy150489 */ 9975779Sxy150489 DMA_SYNC(&tx_ring->tbd_area, DDI_DMA_SYNC_FORDEV); 9985779Sxy150489 9995779Sxy150489 /* 10005779Sxy150489 * Update the number of the free tx descriptors. 10015779Sxy150489 * The mutual exclusion between the transmission and the recycling 10025779Sxy150489 * (for the tx descriptor ring and the work list) is implemented 10035779Sxy150489 * with the atomic operation on the number of the free tx descriptors. 10045779Sxy150489 * 10055779Sxy150489 * Note: we should always decrement the counter tbd_free before 10065779Sxy150489 * advancing the hardware TDT pointer to avoid the race condition - 10075779Sxy150489 * before the counter tbd_free is decremented, the transmit of the 10085779Sxy150489 * tx descriptors has done and the counter tbd_free is increased by 10095779Sxy150489 * the tx recycling. 10105779Sxy150489 */ 10115779Sxy150489 i = igb_atomic_reserve(&tx_ring->tbd_free, desc_num); 10125779Sxy150489 ASSERT(i >= 0); 10135779Sxy150489 10145779Sxy150489 tx_ring->tbd_tail = index; 10155779Sxy150489 10165779Sxy150489 /* 10175779Sxy150489 * Advance the hardware TDT pointer of the tx descriptor ring 10185779Sxy150489 */ 10195779Sxy150489 E1000_WRITE_REG(hw, E1000_TDT(tx_ring->index), index); 10205779Sxy150489 10216624Sgl147354 if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) { 10226624Sgl147354 ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED); 1023*11367SJason.Xu@Sun.COM atomic_or_32(&igb->igb_state, IGB_ERROR); 10246624Sgl147354 } 10256624Sgl147354 10265779Sxy150489 return (desc_num); 10275779Sxy150489 } 10285779Sxy150489 10295779Sxy150489 /* 10305779Sxy150489 * igb_save_desc 10315779Sxy150489 * 10325779Sxy150489 * Save the address/length pair to the private array 10335779Sxy150489 * of the tx control block. The address/length pairs 10345779Sxy150489 * will be filled into the tx descriptor ring later. 10355779Sxy150489 */ 10365779Sxy150489 static void 10375779Sxy150489 igb_save_desc(tx_control_block_t *tcb, uint64_t address, size_t length) 10385779Sxy150489 { 10395779Sxy150489 sw_desc_t *desc; 10405779Sxy150489 10415779Sxy150489 desc = &tcb->desc[tcb->desc_num]; 10425779Sxy150489 desc->address = address; 10435779Sxy150489 desc->length = length; 10445779Sxy150489 10455779Sxy150489 tcb->desc_num++; 10465779Sxy150489 } 10475779Sxy150489 10485779Sxy150489 /* 10495779Sxy150489 * igb_tx_recycle_legacy 10505779Sxy150489 * 10515779Sxy150489 * Recycle the tx descriptors and tx control blocks. 10525779Sxy150489 * 10535779Sxy150489 * The work list is traversed to check if the corresponding 10545779Sxy150489 * tx descriptors have been transmitted. If so, the resources 10555779Sxy150489 * bound to the tx control blocks will be freed, and those 10565779Sxy150489 * tx control blocks will be returned to the free list. 10575779Sxy150489 */ 10585779Sxy150489 uint32_t 10595779Sxy150489 igb_tx_recycle_legacy(igb_tx_ring_t *tx_ring) 10605779Sxy150489 { 10615779Sxy150489 uint32_t index, last_index; 10625779Sxy150489 int desc_num; 10635779Sxy150489 boolean_t desc_done; 10645779Sxy150489 tx_control_block_t *tcb; 10655779Sxy150489 link_list_t pending_list; 10666624Sgl147354 igb_t *igb = tx_ring->igb; 10675779Sxy150489 10685779Sxy150489 /* 10695779Sxy150489 * The mutex_tryenter() is used to avoid unnecessary 10705779Sxy150489 * lock contention. 10715779Sxy150489 */ 10725779Sxy150489 if (mutex_tryenter(&tx_ring->recycle_lock) == 0) 10735779Sxy150489 return (0); 10745779Sxy150489 10755779Sxy150489 ASSERT(tx_ring->tbd_free <= tx_ring->ring_size); 10765779Sxy150489 10775779Sxy150489 if (tx_ring->tbd_free == tx_ring->ring_size) { 10785779Sxy150489 tx_ring->recycle_fail = 0; 10795779Sxy150489 tx_ring->stall_watchdog = 0; 10805779Sxy150489 mutex_exit(&tx_ring->recycle_lock); 10815779Sxy150489 return (0); 10825779Sxy150489 } 10835779Sxy150489 10845779Sxy150489 /* 10855779Sxy150489 * Sync the DMA buffer of the tx descriptor ring 10865779Sxy150489 */ 10875779Sxy150489 DMA_SYNC(&tx_ring->tbd_area, DDI_DMA_SYNC_FORKERNEL); 10885779Sxy150489 10896624Sgl147354 if (igb_check_dma_handle( 10906624Sgl147354 tx_ring->tbd_area.dma_handle) != DDI_FM_OK) { 10916624Sgl147354 ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED); 1092*11367SJason.Xu@Sun.COM atomic_or_32(&igb->igb_state, IGB_ERROR); 1093*11367SJason.Xu@Sun.COM return (0); 10946624Sgl147354 } 10956624Sgl147354 10965779Sxy150489 LINK_LIST_INIT(&pending_list); 10975779Sxy150489 desc_num = 0; 10985779Sxy150489 index = tx_ring->tbd_head; /* Index of next tbd/tcb to recycle */ 10995779Sxy150489 11005779Sxy150489 tcb = tx_ring->work_list[index]; 11015779Sxy150489 ASSERT(tcb != NULL); 11025779Sxy150489 11035779Sxy150489 desc_done = B_TRUE; 11045779Sxy150489 while (desc_done && (tcb != NULL)) { 11055779Sxy150489 11065779Sxy150489 /* 11075779Sxy150489 * Get the last tx descriptor of the tx control block. 11085779Sxy150489 * If the last tx descriptor is done, it is done with 11095779Sxy150489 * all the tx descriptors of the tx control block. 11105779Sxy150489 * Then the tx control block and all the corresponding 11115779Sxy150489 * tx descriptors can be recycled. 11125779Sxy150489 */ 11135779Sxy150489 last_index = NEXT_INDEX(index, tcb->desc_num - 1, 11145779Sxy150489 tx_ring->ring_size); 11155779Sxy150489 11165779Sxy150489 /* 11175779Sxy150489 * Check if the Descriptor Done bit is set 11185779Sxy150489 */ 11195779Sxy150489 desc_done = tx_ring->tbd_ring[last_index].wb.status & 11205779Sxy150489 E1000_TXD_STAT_DD; 11215779Sxy150489 if (desc_done) { 11225779Sxy150489 /* 11235779Sxy150489 * Strip off the tx control block from the work list, 11245779Sxy150489 * and add it to the pending list. 11255779Sxy150489 */ 11265779Sxy150489 tx_ring->work_list[index] = NULL; 11275779Sxy150489 LIST_PUSH_TAIL(&pending_list, &tcb->link); 11285779Sxy150489 11295779Sxy150489 /* 11305779Sxy150489 * Count the total number of the tx descriptors recycled 11315779Sxy150489 */ 11325779Sxy150489 desc_num += tcb->desc_num; 11335779Sxy150489 11345779Sxy150489 /* 11355779Sxy150489 * Advance the index of the tx descriptor ring 11365779Sxy150489 */ 11375779Sxy150489 index = NEXT_INDEX(last_index, 1, tx_ring->ring_size); 11385779Sxy150489 11395779Sxy150489 tcb = tx_ring->work_list[index]; 11405779Sxy150489 } 11415779Sxy150489 } 11425779Sxy150489 11435779Sxy150489 /* 11445779Sxy150489 * If no tx descriptors are recycled, no need to do more processing 11455779Sxy150489 */ 11465779Sxy150489 if (desc_num == 0) { 11475779Sxy150489 tx_ring->recycle_fail++; 11485779Sxy150489 mutex_exit(&tx_ring->recycle_lock); 11495779Sxy150489 return (0); 11505779Sxy150489 } 11515779Sxy150489 11525779Sxy150489 tx_ring->recycle_fail = 0; 11535779Sxy150489 tx_ring->stall_watchdog = 0; 11545779Sxy150489 11555779Sxy150489 /* 11565779Sxy150489 * Update the head index of the tx descriptor ring 11575779Sxy150489 */ 11585779Sxy150489 tx_ring->tbd_head = index; 11595779Sxy150489 11605779Sxy150489 /* 11615779Sxy150489 * Update the number of the free tx descriptors with atomic operations 11625779Sxy150489 */ 11635779Sxy150489 atomic_add_32(&tx_ring->tbd_free, desc_num); 11645779Sxy150489 11655779Sxy150489 mutex_exit(&tx_ring->recycle_lock); 11665779Sxy150489 11675779Sxy150489 /* 11685779Sxy150489 * Free the resources used by the tx control blocks 11695779Sxy150489 * in the pending list 11705779Sxy150489 */ 11715779Sxy150489 tcb = (tx_control_block_t *)LIST_GET_HEAD(&pending_list); 11725779Sxy150489 while (tcb != NULL) { 11735779Sxy150489 /* 11745779Sxy150489 * Release the resources occupied by the tx control block 11755779Sxy150489 */ 11765779Sxy150489 igb_free_tcb(tcb); 11775779Sxy150489 11785779Sxy150489 tcb = (tx_control_block_t *) 11795779Sxy150489 LIST_GET_NEXT(&pending_list, &tcb->link); 11805779Sxy150489 } 11815779Sxy150489 11825779Sxy150489 /* 11835779Sxy150489 * Add the tx control blocks in the pending list to the free list. 11845779Sxy150489 */ 11855779Sxy150489 igb_put_free_list(tx_ring, &pending_list); 11865779Sxy150489 11875779Sxy150489 return (desc_num); 11885779Sxy150489 } 11895779Sxy150489 11905779Sxy150489 /* 11915779Sxy150489 * igb_tx_recycle_head_wb 11925779Sxy150489 * 11935779Sxy150489 * Check the head write-back, and recycle all the transmitted 11945779Sxy150489 * tx descriptors and tx control blocks. 11955779Sxy150489 */ 11965779Sxy150489 uint32_t 11975779Sxy150489 igb_tx_recycle_head_wb(igb_tx_ring_t *tx_ring) 11985779Sxy150489 { 11995779Sxy150489 uint32_t index; 12005779Sxy150489 uint32_t head_wb; 12015779Sxy150489 int desc_num; 12025779Sxy150489 tx_control_block_t *tcb; 12035779Sxy150489 link_list_t pending_list; 12046624Sgl147354 igb_t *igb = tx_ring->igb; 12055779Sxy150489 12065779Sxy150489 /* 12075779Sxy150489 * The mutex_tryenter() is used to avoid unnecessary 12085779Sxy150489 * lock contention. 12095779Sxy150489 */ 12105779Sxy150489 if (mutex_tryenter(&tx_ring->recycle_lock) == 0) 12115779Sxy150489 return (0); 12125779Sxy150489 12135779Sxy150489 ASSERT(tx_ring->tbd_free <= tx_ring->ring_size); 12145779Sxy150489 12155779Sxy150489 if (tx_ring->tbd_free == tx_ring->ring_size) { 12165779Sxy150489 tx_ring->recycle_fail = 0; 12175779Sxy150489 tx_ring->stall_watchdog = 0; 12185779Sxy150489 mutex_exit(&tx_ring->recycle_lock); 12195779Sxy150489 return (0); 12205779Sxy150489 } 12215779Sxy150489 12225779Sxy150489 /* 12235779Sxy150489 * Sync the DMA buffer of the tx descriptor ring 12245779Sxy150489 * 12255779Sxy150489 * Note: For head write-back mode, the tx descriptors will not 12265779Sxy150489 * be written back, but the head write-back value is stored at 12275779Sxy150489 * the last extra tbd at the end of the DMA area, we still need 12285779Sxy150489 * to sync the head write-back value for kernel. 12295779Sxy150489 * 12305779Sxy150489 * DMA_SYNC(&tx_ring->tbd_area, DDI_DMA_SYNC_FORKERNEL); 12315779Sxy150489 */ 12325779Sxy150489 (void) ddi_dma_sync(tx_ring->tbd_area.dma_handle, 12335779Sxy150489 sizeof (union e1000_adv_tx_desc) * tx_ring->ring_size, 12345779Sxy150489 sizeof (uint32_t), 12355779Sxy150489 DDI_DMA_SYNC_FORKERNEL); 12365779Sxy150489 12376624Sgl147354 if (igb_check_dma_handle( 12386624Sgl147354 tx_ring->tbd_area.dma_handle) != DDI_FM_OK) { 12396624Sgl147354 ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED); 1240*11367SJason.Xu@Sun.COM atomic_or_32(&igb->igb_state, IGB_ERROR); 1241*11367SJason.Xu@Sun.COM return (0); 12426624Sgl147354 } 12436624Sgl147354 12445779Sxy150489 LINK_LIST_INIT(&pending_list); 12455779Sxy150489 desc_num = 0; 12465779Sxy150489 index = tx_ring->tbd_head; /* Next index to clean */ 12475779Sxy150489 12485779Sxy150489 /* 12495779Sxy150489 * Get the value of head write-back 12505779Sxy150489 */ 12515779Sxy150489 head_wb = *tx_ring->tbd_head_wb; 12525779Sxy150489 while (index != head_wb) { 12535779Sxy150489 tcb = tx_ring->work_list[index]; 12545779Sxy150489 ASSERT(tcb != NULL); 12555779Sxy150489 12565779Sxy150489 if (OFFSET(index, head_wb, tx_ring->ring_size) < 12575779Sxy150489 tcb->desc_num) { 12585779Sxy150489 /* 12595779Sxy150489 * The current tx control block is not 12605779Sxy150489 * completely transmitted, stop recycling 12615779Sxy150489 */ 12625779Sxy150489 break; 12635779Sxy150489 } 12645779Sxy150489 12655779Sxy150489 /* 12665779Sxy150489 * Strip off the tx control block from the work list, 12675779Sxy150489 * and add it to the pending list. 12685779Sxy150489 */ 12695779Sxy150489 tx_ring->work_list[index] = NULL; 12705779Sxy150489 LIST_PUSH_TAIL(&pending_list, &tcb->link); 12715779Sxy150489 12725779Sxy150489 /* 12735779Sxy150489 * Advance the index of the tx descriptor ring 12745779Sxy150489 */ 12755779Sxy150489 index = NEXT_INDEX(index, tcb->desc_num, tx_ring->ring_size); 12765779Sxy150489 12775779Sxy150489 /* 12785779Sxy150489 * Count the total number of the tx descriptors recycled 12795779Sxy150489 */ 12805779Sxy150489 desc_num += tcb->desc_num; 12815779Sxy150489 } 12825779Sxy150489 12835779Sxy150489 /* 12845779Sxy150489 * If no tx descriptors are recycled, no need to do more processing 12855779Sxy150489 */ 12865779Sxy150489 if (desc_num == 0) { 12875779Sxy150489 tx_ring->recycle_fail++; 12885779Sxy150489 mutex_exit(&tx_ring->recycle_lock); 12895779Sxy150489 return (0); 12905779Sxy150489 } 12915779Sxy150489 12925779Sxy150489 tx_ring->recycle_fail = 0; 12935779Sxy150489 tx_ring->stall_watchdog = 0; 12945779Sxy150489 12955779Sxy150489 /* 12965779Sxy150489 * Update the head index of the tx descriptor ring 12975779Sxy150489 */ 12985779Sxy150489 tx_ring->tbd_head = index; 12995779Sxy150489 13005779Sxy150489 /* 13015779Sxy150489 * Update the number of the free tx descriptors with atomic operations 13025779Sxy150489 */ 13035779Sxy150489 atomic_add_32(&tx_ring->tbd_free, desc_num); 13045779Sxy150489 13055779Sxy150489 mutex_exit(&tx_ring->recycle_lock); 13065779Sxy150489 13075779Sxy150489 /* 13085779Sxy150489 * Free the resources used by the tx control blocks 13095779Sxy150489 * in the pending list 13105779Sxy150489 */ 13115779Sxy150489 tcb = (tx_control_block_t *)LIST_GET_HEAD(&pending_list); 13125779Sxy150489 while (tcb) { 13135779Sxy150489 /* 13145779Sxy150489 * Release the resources occupied by the tx control block 13155779Sxy150489 */ 13165779Sxy150489 igb_free_tcb(tcb); 13175779Sxy150489 13185779Sxy150489 tcb = (tx_control_block_t *) 13195779Sxy150489 LIST_GET_NEXT(&pending_list, &tcb->link); 13205779Sxy150489 } 13215779Sxy150489 13225779Sxy150489 /* 13235779Sxy150489 * Add the tx control blocks in the pending list to the free list. 13245779Sxy150489 */ 13255779Sxy150489 igb_put_free_list(tx_ring, &pending_list); 13265779Sxy150489 13275779Sxy150489 return (desc_num); 13285779Sxy150489 } 13295779Sxy150489 13305779Sxy150489 /* 13315779Sxy150489 * igb_free_tcb - free up the tx control block 13325779Sxy150489 * 13335779Sxy150489 * Free the resources of the tx control block, including 13345779Sxy150489 * unbind the previously bound DMA handle, and reset other 13355779Sxy150489 * control fields. 13365779Sxy150489 */ 13375779Sxy150489 void 13385779Sxy150489 igb_free_tcb(tx_control_block_t *tcb) 13395779Sxy150489 { 13405779Sxy150489 switch (tcb->tx_type) { 13415779Sxy150489 case USE_COPY: 13425779Sxy150489 /* 13435779Sxy150489 * Reset the buffer length that is used for copy 13445779Sxy150489 */ 13455779Sxy150489 tcb->tx_buf.len = 0; 13465779Sxy150489 break; 13475779Sxy150489 case USE_DMA: 13485779Sxy150489 /* 13495779Sxy150489 * Release the DMA resource that is used for 13505779Sxy150489 * DMA binding. 13515779Sxy150489 */ 13525779Sxy150489 (void) ddi_dma_unbind_handle(tcb->tx_dma_handle); 13535779Sxy150489 break; 13545779Sxy150489 default: 13555779Sxy150489 break; 13565779Sxy150489 } 13575779Sxy150489 13585779Sxy150489 /* 13595779Sxy150489 * Free the mblk 13605779Sxy150489 */ 13615779Sxy150489 if (tcb->mp != NULL) { 13625779Sxy150489 freemsg(tcb->mp); 13635779Sxy150489 tcb->mp = NULL; 13645779Sxy150489 } 13655779Sxy150489 13665779Sxy150489 tcb->tx_type = USE_NONE; 13675779Sxy150489 tcb->frag_num = 0; 13685779Sxy150489 tcb->desc_num = 0; 13695779Sxy150489 } 13705779Sxy150489 13715779Sxy150489 /* 13725779Sxy150489 * igb_get_free_list - Get a free tx control block from the free list 13735779Sxy150489 * 13745779Sxy150489 * The atomic operation on the number of the available tx control block 13755779Sxy150489 * in the free list is used to keep this routine mutual exclusive with 13765779Sxy150489 * the routine igb_put_check_list. 13775779Sxy150489 */ 13785779Sxy150489 static tx_control_block_t * 13795779Sxy150489 igb_get_free_list(igb_tx_ring_t *tx_ring) 13805779Sxy150489 { 13815779Sxy150489 tx_control_block_t *tcb; 13825779Sxy150489 13835779Sxy150489 /* 13845779Sxy150489 * Check and update the number of the free tx control block 13855779Sxy150489 * in the free list. 13865779Sxy150489 */ 13875779Sxy150489 if (igb_atomic_reserve(&tx_ring->tcb_free, 1) < 0) 13885779Sxy150489 return (NULL); 13895779Sxy150489 13905779Sxy150489 mutex_enter(&tx_ring->tcb_head_lock); 13915779Sxy150489 13925779Sxy150489 tcb = tx_ring->free_list[tx_ring->tcb_head]; 13935779Sxy150489 ASSERT(tcb != NULL); 13945779Sxy150489 tx_ring->free_list[tx_ring->tcb_head] = NULL; 13955779Sxy150489 tx_ring->tcb_head = NEXT_INDEX(tx_ring->tcb_head, 1, 13965779Sxy150489 tx_ring->free_list_size); 13975779Sxy150489 13985779Sxy150489 mutex_exit(&tx_ring->tcb_head_lock); 13995779Sxy150489 14005779Sxy150489 return (tcb); 14015779Sxy150489 } 14025779Sxy150489 14035779Sxy150489 /* 14045779Sxy150489 * igb_put_free_list 14055779Sxy150489 * 14065779Sxy150489 * Put a list of used tx control blocks back to the free list 14075779Sxy150489 * 14085779Sxy150489 * A mutex is used here to ensure the serialization. The mutual exclusion 14095779Sxy150489 * between igb_get_free_list and igb_put_free_list is implemented with 14105779Sxy150489 * the atomic operation on the counter tcb_free. 14115779Sxy150489 */ 14125779Sxy150489 void 14135779Sxy150489 igb_put_free_list(igb_tx_ring_t *tx_ring, link_list_t *pending_list) 14145779Sxy150489 { 14155779Sxy150489 uint32_t index; 14165779Sxy150489 int tcb_num; 14175779Sxy150489 tx_control_block_t *tcb; 14185779Sxy150489 14195779Sxy150489 mutex_enter(&tx_ring->tcb_tail_lock); 14205779Sxy150489 14215779Sxy150489 index = tx_ring->tcb_tail; 14225779Sxy150489 14235779Sxy150489 tcb_num = 0; 14245779Sxy150489 tcb = (tx_control_block_t *)LIST_POP_HEAD(pending_list); 14255779Sxy150489 while (tcb != NULL) { 14265779Sxy150489 ASSERT(tx_ring->free_list[index] == NULL); 14275779Sxy150489 tx_ring->free_list[index] = tcb; 14285779Sxy150489 14295779Sxy150489 tcb_num++; 14305779Sxy150489 14315779Sxy150489 index = NEXT_INDEX(index, 1, tx_ring->free_list_size); 14325779Sxy150489 14335779Sxy150489 tcb = (tx_control_block_t *)LIST_POP_HEAD(pending_list); 14345779Sxy150489 } 14355779Sxy150489 14365779Sxy150489 tx_ring->tcb_tail = index; 14375779Sxy150489 14385779Sxy150489 /* 14395779Sxy150489 * Update the number of the free tx control block 14405779Sxy150489 * in the free list. This operation must be placed 14415779Sxy150489 * under the protection of the lock. 14425779Sxy150489 */ 14435779Sxy150489 atomic_add_32(&tx_ring->tcb_free, tcb_num); 14445779Sxy150489 14455779Sxy150489 mutex_exit(&tx_ring->tcb_tail_lock); 14465779Sxy150489 } 1447