diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/common/io/igb/igb_gld.c | 13 | ||||
-rw-r--r-- | usr/src/uts/common/io/igb/igb_main.c | 31 | ||||
-rw-r--r-- | usr/src/uts/common/io/igb/igb_sw.h | 29 | ||||
-rw-r--r-- | usr/src/uts/common/io/igb/igb_tx.c | 361 |
4 files changed, 314 insertions, 120 deletions
diff --git a/usr/src/uts/common/io/igb/igb_gld.c b/usr/src/uts/common/io/igb/igb_gld.c index c1213647ec..539b1992cc 100644 --- a/usr/src/uts/common/io/igb/igb_gld.c +++ b/usr/src/uts/common/io/igb/igb_gld.c @@ -24,7 +24,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -926,6 +926,17 @@ igb_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) *tx_hcksum_flags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM; break; } + case MAC_CAPAB_LSO: { + mac_capab_lso_t *cap_lso = cap_data; + + if (igb->lso_enable) { + cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4; + cap_lso->lso_basic_tcp_ipv4.lso_max = IGB_LSO_MAXLEN; + break; + } else { + return (B_FALSE); + } + } case MAC_CAPAB_RINGS: { mac_capab_rings_t *cap_rings = cap_data; diff --git a/usr/src/uts/common/io/igb/igb_main.c b/usr/src/uts/common/io/igb/igb_main.c index 9e75df9ff5..e23d34949a 100644 --- a/usr/src/uts/common/io/igb/igb_main.c +++ b/usr/src/uts/common/io/igb/igb_main.c @@ -23,13 +23,13 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms of the CDDL. + * Use is subject to license terms. */ #include "igb_sw.h" static char ident[] = "Intel 1Gb Ethernet"; -static char igb_version[] = "igb 1.1.5"; +static char igb_version[] = "igb 1.1.6"; /* * Local function protoypes @@ -891,6 +891,11 @@ igb_init_driver_settings(igb_t *igb) } /* + * Get the system page size + */ + igb->page_size = ddi_ptob(igb->dip, (ulong_t)1); + + /* * Set rx buffer size * The IP header alignment room is counted in the calculation. * The rx buffer size is in unit of 1K that is required by the @@ -2109,19 +2114,16 @@ igb_setup_tx_ring(igb_tx_ring_t *tx_ring) } /* - * Initialize hardware checksum offload settings - */ - tx_ring->hcksum_context.hcksum_flags = 0; - tx_ring->hcksum_context.ip_hdr_len = 0; - tx_ring->hcksum_context.mac_hdr_len = 0; - tx_ring->hcksum_context.l4_proto = 0; - - /* * Enable TXDCTL per queue */ reg_val = E1000_READ_REG(hw, E1000_TXDCTL(tx_ring->index)); reg_val |= E1000_TXDCTL_QUEUE_ENABLE; E1000_WRITE_REG(hw, E1000_TXDCTL(tx_ring->index), reg_val); + + /* + * Initialize hardware checksum offload settings + */ + bzero(&tx_ring->tx_context, sizeof (tx_context_t)); } static void @@ -2694,10 +2696,17 @@ igb_get_conf(igb_t *igb) igb->rx_hcksum_enable = igb_get_prop(igb, PROP_RX_HCKSUM_ENABLE, 0, 1, 1); igb->lso_enable = igb_get_prop(igb, PROP_LSO_ENABLE, - 0, 1, 0); + 0, 1, 1); igb->tx_head_wb_enable = igb_get_prop(igb, PROP_TX_HEAD_WB_ENABLE, 0, 1, 1); + /* + * igb LSO needs the tx h/w checksum support. + * Here LSO will be disabled if tx h/w checksum has been disabled. + */ + if (igb->tx_hcksum_enable == B_FALSE) + igb->lso_enable = B_FALSE; + igb->tx_copy_thresh = igb_get_prop(igb, PROP_TX_COPY_THRESHOLD, MIN_TX_COPY_THRESHOLD, MAX_TX_COPY_THRESHOLD, DEFAULT_TX_COPY_THRESHOLD); diff --git a/usr/src/uts/common/io/igb/igb_sw.h b/usr/src/uts/common/io/igb/igb_sw.h index 5f7c977f0b..fdfdf1d0e8 100644 --- a/usr/src/uts/common/io/igb/igb_sw.h +++ b/usr/src/uts/common/io/igb/igb_sw.h @@ -23,7 +23,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms of the CDDL. + * Use is subject to license terms. */ #ifndef _IGB_SW_H @@ -60,6 +60,7 @@ extern "C" { #include <sys/netlb.h> #include <sys/random.h> #include <inet/common.h> +#include <inet/tcp.h> #include <inet/ip.h> #include <inet/mi.h> #include <inet/nd.h> @@ -94,7 +95,7 @@ extern "C" { #define MAX_NUM_UNICAST_ADDRESSES E1000_RAR_ENTRIES #define MAX_NUM_MULTICAST_ADDRESSES 256 -#define MAX_COOKIE 16 +#define MAX_COOKIE 18 #define MIN_NUM_TX_DESC 2 /* @@ -158,10 +159,12 @@ extern "C" { #define DEFAULT_TX_INTR_ABS_DELAY 0 #define DEFAULT_RX_COPY_THRESHOLD 128 #define DEFAULT_TX_COPY_THRESHOLD 512 -#define DEFAULT_TX_RECYCLE_THRESHOLD MAX_COOKIE +#define DEFAULT_TX_RECYCLE_THRESHOLD (MAX_COOKIE + 1) #define DEFAULT_TX_OVERLOAD_THRESHOLD MIN_NUM_TX_DESC #define DEFAULT_TX_RESCHED_THRESHOLD 128 +#define IGB_LSO_MAXLEN 65535 + #define TX_DRAIN_TIME 200 #define RX_DRAIN_TIME 200 @@ -270,8 +273,12 @@ enum ioc_reply { IOC_REPLY /* OK, just send reply */ }; -#define MBLK_LEN(mp) ((uintptr_t)(mp)->b_wptr - \ - (uintptr_t)(mp)->b_rptr) +/* + * For s/w context extraction from a tx frame + */ +#define TX_CXT_SUCCESS 0 +#define TX_CXT_E_LSO_CSUM (-1) +#define TX_CXT_E_ETHER_TYPE (-2) #define DMA_SYNC(area, flag) ((void) ddi_dma_sync((area)->dma_handle, \ 0, 0, (flag))) @@ -457,12 +464,15 @@ typedef enum { RCB_SENDUP } rcb_state_t; -typedef struct hcksum_context { +typedef struct tx_context { uint32_t hcksum_flags; uint32_t ip_hdr_len; uint32_t mac_hdr_len; uint32_t l4_proto; -} hcksum_context_t; + uint32_t mss; + uint32_t l4_hdr_len; + boolean_t lso_flag; +} tx_context_t; /* Hold address/length of each DMA segment */ typedef struct sw_desc { @@ -543,9 +553,9 @@ typedef struct igb_tx_ring { uint32_t (*tx_recycle)(struct igb_tx_ring *); /* - * TCP/UDP checksum offload + * s/w context structure for TCP/UDP checksum offload and LSO. */ - hcksum_context_t hcksum_context; + tx_context_t tx_context; /* * Tx ring settings and status @@ -738,6 +748,7 @@ typedef struct igb { */ int fm_capabilities; + ulong_t page_size; } igb_t; typedef struct igb_stat { diff --git a/usr/src/uts/common/io/igb/igb_tx.c b/usr/src/uts/common/io/igb/igb_tx.c index 5b7883435e..5343fe32ac 100644 --- a/usr/src/uts/common/io/igb/igb_tx.c +++ b/usr/src/uts/common/io/igb/igb_tx.c @@ -23,7 +23,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms of the CDDL. + * Use is subject to license terms. */ #include "igb_sw.h" @@ -33,20 +33,20 @@ static int igb_tx_copy(igb_tx_ring_t *, tx_control_block_t *, mblk_t *, uint32_t, boolean_t); static int igb_tx_bind(igb_tx_ring_t *, tx_control_block_t *, mblk_t *, uint32_t); -static int igb_tx_fill_ring(igb_tx_ring_t *, link_list_t *, hcksum_context_t *); +static int igb_tx_fill_ring(igb_tx_ring_t *, link_list_t *, tx_context_t *, + size_t); static void igb_save_desc(tx_control_block_t *, uint64_t, size_t); static tx_control_block_t *igb_get_free_list(igb_tx_ring_t *); - -static void igb_get_hcksum_context(mblk_t *, hcksum_context_t *); -static boolean_t igb_check_hcksum_context(igb_tx_ring_t *, hcksum_context_t *); -static void igb_fill_hcksum_context(struct e1000_adv_tx_context_desc *, - hcksum_context_t *, uint32_t); +static int igb_get_tx_context(mblk_t *, tx_context_t *); +static boolean_t igb_check_tx_context(igb_tx_ring_t *, tx_context_t *); +static void igb_fill_tx_context(struct e1000_adv_tx_context_desc *, + tx_context_t *, uint32_t); #ifndef IGB_DEBUG #pragma inline(igb_save_desc) -#pragma inline(igb_get_hcksum_context) -#pragma inline(igb_check_hcksum_context) -#pragma inline(igb_fill_hcksum_context) +#pragma inline(igb_get_tx_context) +#pragma inline(igb_check_tx_context) +#pragma inline(igb_fill_tx_context) #endif mblk_t * @@ -100,23 +100,49 @@ igb_tx(igb_tx_ring_t *tx_ring, mblk_t *mp) boolean_t copy_done, eop; mblk_t *current_mp, *next_mp, *nmp; tx_control_block_t *tcb; - hcksum_context_t hcksum_context, *hcksum; + tx_context_t tx_context, *ctx; link_list_t pending_list; + mblk_t *new_mp; + mblk_t *previous_mp; + uint32_t hdr_frag_len; + uint32_t hdr_len, len; + uint32_t copy_thresh; + + copy_thresh = tx_ring->copy_thresh; /* Get the mblk size */ mbsize = 0; for (nmp = mp; nmp != NULL; nmp = nmp->b_cont) { - mbsize += MBLK_LEN(nmp); + mbsize += MBLKL(nmp); } - /* - * If the mblk size exceeds the max frame size, - * discard this mblk, and return B_TRUE - */ - if (mbsize > (igb->max_frame_size - ETHERFCSL)) { - freemsg(mp); - IGB_DEBUGLOG_0(igb, "igb_tx: packet oversize"); - return (B_TRUE); + if (igb->tx_hcksum_enable) { + ctx = &tx_context; + /* + * Retrieve offloading context information from the mblk + * that will be used to decide whether/how to fill the + * context descriptor. + */ + if (igb_get_tx_context(mp, ctx) != TX_CXT_SUCCESS) { + freemsg(mp); + return (B_TRUE); + } + + if ((ctx->lso_flag && + (mbsize > (ctx->mac_hdr_len + IGB_LSO_MAXLEN))) || + (!ctx->lso_flag && + (mbsize > (igb->max_frame_size - ETHERFCSL)))) { + freemsg(mp); + IGB_DEBUGLOG_0(igb, "igb_tx: packet oversize"); + return (B_TRUE); + } + } else { + ctx = NULL; + if (mbsize > (igb->max_frame_size - ETHERFCSL)) { + freemsg(mp); + IGB_DEBUGLOG_0(igb, "igb_tx: packet oversize"); + return (B_TRUE); + } } /* @@ -138,6 +164,86 @@ igb_tx(igb_tx_ring_t *tx_ring, mblk_t *mp) } /* + * The software should guarantee LSO packet header(MAC+IP+TCP) + * to be within one descriptor - this is required by h/w. + * Here will reallocate and refill the header if + * the headers(MAC+IP+TCP) is physical memory non-contiguous. + */ + if (ctx && ctx->lso_flag) { + hdr_len = ctx->mac_hdr_len + ctx->ip_hdr_len + + ctx->l4_hdr_len; + len = MBLKL(mp); + current_mp = mp; + previous_mp = NULL; + while (len < hdr_len) { + previous_mp = current_mp; + current_mp = current_mp->b_cont; + len += MBLKL(current_mp); + } + + /* + * If len is larger than copy_thresh, we do not + * need to do anything since igb's tx copy mechanism + * will ensure that the headers will be handled + * in one descriptor. + */ + if (len > copy_thresh) { + if (len != hdr_len) { + /* + * If the header and the payload are in + * different mblks, we simply force the + * header to be copied into a + * new-allocated buffer. + */ + hdr_frag_len = hdr_len - + (len - MBLKL(current_mp)); + + /* + * There are two cases we will reallocate + * a mblk for the last header fragment. + * 1. the header is in multiple mblks and + * the last fragment shares the same mblk + * with the payload + * 2. the header is in a single mblk shared + * with the payload but the header crosses + * a page. + */ + if ((current_mp != mp) || + (P2NPHASE((uintptr_t)current_mp->b_rptr, + igb->page_size) < hdr_len)) { + /* + * reallocate the mblk for the last + * header fragment, expect it to be + * copied into pre-allocated + * page-aligned buffer + */ + new_mp = allocb(hdr_frag_len, NULL); + if (!new_mp) { + return (B_FALSE); + } + + /* + * Insert the new mblk + */ + bcopy(current_mp->b_rptr, + new_mp->b_rptr, hdr_frag_len); + new_mp->b_wptr = new_mp->b_rptr + + hdr_frag_len; + new_mp->b_cont = current_mp; + if (previous_mp) + previous_mp->b_cont = new_mp; + else + mp = new_mp; + current_mp->b_rptr += hdr_frag_len; + } + } + + if (copy_thresh < hdr_len) + copy_thresh = hdr_len; + } + } + + /* * The pending_list is a linked list that is used to save * the tx control blocks that have packet data processed * but have not put the data to the tx descriptor ring. @@ -148,11 +254,11 @@ igb_tx(igb_tx_ring_t *tx_ring, mblk_t *mp) desc_total = 0; current_mp = mp; - current_len = MBLK_LEN(current_mp); + current_len = MBLKL(current_mp); /* * Decide which method to use for the first fragment */ - current_flag = (current_len <= tx_ring->copy_thresh) ? + current_flag = (current_len <= copy_thresh) ? USE_COPY : USE_DMA; /* * If the mblk includes several contiguous small fragments, @@ -172,7 +278,7 @@ igb_tx(igb_tx_ring_t *tx_ring, mblk_t *mp) while (current_mp) { next_mp = current_mp->b_cont; eop = (next_mp == NULL); /* Last fragment of the packet? */ - next_len = eop ? 0: MBLK_LEN(next_mp); + next_len = eop ? 0: MBLKL(next_mp); /* * When the current fragment is an empty fragment, if @@ -188,7 +294,7 @@ igb_tx(igb_tx_ring_t *tx_ring, mblk_t *mp) if ((current_len == 0) && (copy_done)) { current_mp = next_mp; current_len = next_len; - current_flag = (current_len <= tx_ring->copy_thresh) ? + current_flag = (current_len <= copy_thresh) ? USE_COPY : USE_DMA; continue; } @@ -236,10 +342,10 @@ igb_tx(igb_tx_ring_t *tx_ring, mblk_t *mp) * copied to the current tx buffer, we need * to complete the current copy processing. */ - next_flag = (next_len > tx_ring->copy_thresh) ? + next_flag = (next_len > copy_thresh) ? USE_DMA: USE_COPY; copy_done = B_TRUE; - } else if (next_len > tx_ring->copy_thresh) { + } else if (next_len > copy_thresh) { /* * The next fragment needs to be processed with * DMA binding. So the copy prcessing will be @@ -263,7 +369,7 @@ igb_tx(igb_tx_ring_t *tx_ring, mblk_t *mp) * Check whether to use bcopy or DMA binding to process * the next fragment. */ - next_flag = (next_len > tx_ring->copy_thresh) ? + next_flag = (next_len > copy_thresh) ? USE_DMA: USE_COPY; ASSERT(copy_done == B_TRUE); @@ -288,17 +394,6 @@ igb_tx(igb_tx_ring_t *tx_ring, mblk_t *mp) ASSERT(tcb->mp == NULL); tcb->mp = mp; - if (igb->tx_hcksum_enable) { - /* - * Retrieve checksum context information from the mblk that will - * be used to decide whether/how to fill the context descriptor. - */ - hcksum = &hcksum_context; - igb_get_hcksum_context(mp, hcksum); - } else { - hcksum = NULL; - } - /* * Before fill the tx descriptor ring with the data, we need to * ensure there are adequate free descriptors for transmit @@ -324,7 +419,7 @@ igb_tx(igb_tx_ring_t *tx_ring, mblk_t *mp) goto tx_failure; } - desc_num = igb_tx_fill_ring(tx_ring, &pending_list, hcksum); + desc_num = igb_tx_fill_ring(tx_ring, &pending_list, ctx, mbsize); ASSERT((desc_num == desc_total) || (desc_num == (desc_total + 1))); @@ -472,15 +567,17 @@ igb_tx_bind(igb_tx_ring_t *tx_ring, tx_control_block_t *tcb, mblk_t *mp, } /* - * igb_get_hcksum_context + * igb_get_tx_context * - * Get the hcksum context information from the mblk + * Get the tx context information from the mblk */ -static void -igb_get_hcksum_context(mblk_t *mp, hcksum_context_t *hcksum) +static int +igb_get_tx_context(mblk_t *mp, tx_context_t *ctx) { uint32_t start; uint32_t flags; + uint32_t lso_flag; + uint32_t mss; uint32_t len; uint32_t size; uint32_t offset; @@ -488,15 +585,34 @@ igb_get_hcksum_context(mblk_t *mp, hcksum_context_t *hcksum) ushort_t etype; uint32_t mac_hdr_len; uint32_t l4_proto; + uint32_t l4_hdr_len; ASSERT(mp != NULL); hcksum_retrieve(mp, NULL, NULL, &start, NULL, NULL, NULL, &flags); + bzero(ctx, sizeof (tx_context_t)); - hcksum->hcksum_flags = flags; + ctx->hcksum_flags = flags; if (flags == 0) - return; + return (TX_CXT_SUCCESS); + + lso_info_get(mp, &mss, &lso_flag); + ctx->mss = mss; + ctx->lso_flag = (lso_flag == HW_LSO); + + /* + * LSO relies on tx h/w checksum, so here the packet will be + * dropped if the h/w checksum flags are not set. + */ + if (ctx->lso_flag) { + if (!((ctx->hcksum_flags & HCK_PARTIALCKSUM) && + (ctx->hcksum_flags & HCK_IPV4_HDRCKSUM))) { + IGB_DEBUGLOG_0(NULL, "igb_tx: h/w " + "checksum flags are not set for LSO"); + return (TX_CXT_E_LSO_CSUM); + } + } etype = 0; mac_hdr_len = 0; @@ -508,12 +624,12 @@ igb_get_hcksum_context(mblk_t *mp, hcksum_context_t *hcksum) * in one mblk fragment, so we go thourgh the fragments to parse * the ether type. */ - size = len = MBLK_LEN(mp); + size = len = MBLKL(mp); offset = offsetof(struct ether_header, ether_type); while (size <= offset) { mp = mp->b_cont; ASSERT(mp != NULL); - len = MBLK_LEN(mp); + len = MBLKL(mp); size += len; } pos = mp->b_rptr + offset + len - size; @@ -527,7 +643,7 @@ igb_get_hcksum_context(mblk_t *mp, hcksum_context_t *hcksum) while (size <= offset) { mp = mp->b_cont; ASSERT(mp != NULL); - len = MBLK_LEN(mp); + len = MBLKL(mp); size += len; } pos = mp->b_rptr + offset + len - size; @@ -539,29 +655,43 @@ igb_get_hcksum_context(mblk_t *mp, hcksum_context_t *hcksum) } /* - * Here we don't assume the IP(V6) header is fully included in - * one mblk fragment, so we go thourgh the fragments to parse - * the protocol type. + * Here we assume the IP(V6) header is fully included in one + * mblk fragment. */ switch (etype) { case ETHERTYPE_IP: - offset = offsetof(ipha_t, ipha_protocol) + mac_hdr_len; + offset = mac_hdr_len; while (size <= offset) { mp = mp->b_cont; ASSERT(mp != NULL); - len = MBLK_LEN(mp); + len = MBLKL(mp); size += len; } pos = mp->b_rptr + offset + len - size; - l4_proto = *(uint8_t *)pos; + if (ctx->lso_flag) { + *((uint16_t *)(uintptr_t)(pos + offsetof(ipha_t, + ipha_length))) = 0; + + /* + * To utilize igb LSO, here need to fill + * the tcp checksum field of the packet with the + * following pseudo-header checksum: + * (ip_source_addr, ip_destination_addr, l4_proto) + * and also need to fill the ip header checksum + * with zero. Currently the tcp/ip stack has done + * these. + */ + } + + l4_proto = *(uint8_t *)(pos + offsetof(ipha_t, ipha_protocol)); break; case ETHERTYPE_IPV6: offset = offsetof(ip6_t, ip6_nxt) + mac_hdr_len; while (size <= offset) { mp = mp->b_cont; ASSERT(mp != NULL); - len = MBLK_LEN(mp); + len = MBLKL(mp); size += len; } pos = mp->b_rptr + offset + len - size; @@ -570,47 +700,72 @@ igb_get_hcksum_context(mblk_t *mp, hcksum_context_t *hcksum) break; default: /* Unrecoverable error */ - IGB_DEBUGLOG_0(NULL, "Ether type error with tx hcksum"); - return; + IGB_DEBUGLOG_0(NULL, "Ethernet type field error with " + "tx hcksum flag set"); + return (TX_CXT_E_ETHER_TYPE); + } + + if (ctx->lso_flag) { + offset = mac_hdr_len + start; + while (size <= offset) { + mp = mp->b_cont; + ASSERT(mp != NULL); + len = MBLKL(mp); + size += len; + } + pos = mp->b_rptr + offset + len - size; + + l4_hdr_len = TCP_HDR_LENGTH((tcph_t *)pos); + } else { + /* + * l4 header length is only required for LSO + */ + l4_hdr_len = 0; } - hcksum->mac_hdr_len = mac_hdr_len; - hcksum->ip_hdr_len = start; - hcksum->l4_proto = l4_proto; + ctx->mac_hdr_len = mac_hdr_len; + ctx->ip_hdr_len = start; + ctx->l4_proto = l4_proto; + ctx->l4_hdr_len = l4_hdr_len; + + return (TX_CXT_SUCCESS); } /* - * igb_check_hcksum_context + * igb_check_tx_context * * Check if a new context descriptor is needed */ static boolean_t -igb_check_hcksum_context(igb_tx_ring_t *tx_ring, hcksum_context_t *hcksum) +igb_check_tx_context(igb_tx_ring_t *tx_ring, tx_context_t *ctx) { - hcksum_context_t *last; + tx_context_t *last; - if (hcksum == NULL) + if (ctx == NULL) return (B_FALSE); /* - * Compare the checksum data retrieved from the mblk and the - * stored checksum data of the last context descriptor. The data + * Compare the context data retrieved from the mblk and the + * stored context data of the last context descriptor. The data * need to be checked are: * hcksum_flags * l4_proto - * mac_hdr_len + * mss (only check for LSO) + * l4_hdr_len (only check for LSO) * ip_hdr_len + * mac_hdr_len * Either one of the above data is changed, a new context descriptor * will be needed. */ - last = &tx_ring->hcksum_context; - - if (hcksum->hcksum_flags != 0) { - if ((hcksum->hcksum_flags != last->hcksum_flags) || - (hcksum->l4_proto != last->l4_proto) || - (hcksum->mac_hdr_len != last->mac_hdr_len) || - (hcksum->ip_hdr_len != last->ip_hdr_len)) { - + last = &tx_ring->tx_context; + + if (ctx->hcksum_flags != 0) { + if ((ctx->hcksum_flags != last->hcksum_flags) || + (ctx->l4_proto != last->l4_proto) || + (ctx->lso_flag && ((ctx->mss != last->mss) || + (ctx->l4_hdr_len != last->l4_hdr_len))) || + (ctx->ip_hdr_len != last->ip_hdr_len) || + (ctx->mac_hdr_len != last->mac_hdr_len)) { return (B_TRUE); } } @@ -619,30 +774,30 @@ igb_check_hcksum_context(igb_tx_ring_t *tx_ring, hcksum_context_t *hcksum) } /* - * igb_fill_hcksum_context + * igb_fill_tx_context * * Fill the context descriptor with hardware checksum informations */ static void -igb_fill_hcksum_context(struct e1000_adv_tx_context_desc *ctx_tbd, - hcksum_context_t *hcksum, uint32_t ring_index) +igb_fill_tx_context(struct e1000_adv_tx_context_desc *ctx_tbd, + tx_context_t *ctx, uint32_t ring_index) { /* * Fill the context descriptor with the checksum * context information we've got */ - ctx_tbd->vlan_macip_lens = hcksum->ip_hdr_len; - ctx_tbd->vlan_macip_lens |= hcksum->mac_hdr_len << + ctx_tbd->vlan_macip_lens = ctx->ip_hdr_len; + ctx_tbd->vlan_macip_lens |= ctx->mac_hdr_len << E1000_ADVTXD_MACLEN_SHIFT; ctx_tbd->type_tucmd_mlhl = E1000_ADVTXD_DCMD_DEXT | E1000_ADVTXD_DTYP_CTXT; - if (hcksum->hcksum_flags & HCK_IPV4_HDRCKSUM) + if (ctx->hcksum_flags & HCK_IPV4_HDRCKSUM) ctx_tbd->type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_IPV4; - if (hcksum->hcksum_flags & HCK_PARTIALCKSUM) { - switch (hcksum->l4_proto) { + if (ctx->hcksum_flags & HCK_PARTIALCKSUM) { + switch (ctx->l4_proto) { case IPPROTO_TCP: ctx_tbd->type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_TCP; break; @@ -663,6 +818,11 @@ igb_fill_hcksum_context(struct e1000_adv_tx_context_desc *ctx_tbd, ctx_tbd->seqnum_seed = 0; ctx_tbd->mss_l4len_idx = ring_index << 4; + if (ctx->lso_flag) { + ctx_tbd->mss_l4len_idx |= + (ctx->l4_hdr_len << E1000_ADVTXD_L4LEN_SHIFT) | + (ctx->mss << E1000_ADVTXD_MSS_SHIFT); + } } /* @@ -672,7 +832,7 @@ igb_fill_hcksum_context(struct e1000_adv_tx_context_desc *ctx_tbd, */ static int igb_tx_fill_ring(igb_tx_ring_t *tx_ring, link_list_t *pending_list, - hcksum_context_t *hcksum) + tx_context_t *ctx, size_t mbsize) { struct e1000_hw *hw = &tx_ring->igb->hw; boolean_t load_context; @@ -680,7 +840,6 @@ igb_tx_fill_ring(igb_tx_ring_t *tx_ring, link_list_t *pending_list, union e1000_adv_tx_desc *tbd, *first_tbd; tx_control_block_t *tcb, *first_tcb; uint32_t hcksum_flags; - uint32_t pay_len; int i; igb_t *igb = tx_ring->igb; @@ -691,7 +850,6 @@ igb_tx_fill_ring(igb_tx_ring_t *tx_ring, link_list_t *pending_list, first_tcb = NULL; desc_num = 0; hcksum_flags = 0; - pay_len = 0; load_context = B_FALSE; /* @@ -703,13 +861,13 @@ igb_tx_fill_ring(igb_tx_ring_t *tx_ring, link_list_t *pending_list, index = tx_ring->tbd_tail; tcb_index = tx_ring->tbd_tail; - if (hcksum != NULL) { - hcksum_flags = hcksum->hcksum_flags; + if (ctx != NULL) { + hcksum_flags = ctx->hcksum_flags; /* * Check if a new context descriptor is needed for this packet */ - load_context = igb_check_hcksum_context(tx_ring, hcksum); + load_context = igb_check_tx_context(tx_ring, ctx); if (load_context) { first_tcb = (tx_control_block_t *) LIST_GET_HEAD(pending_list); @@ -719,9 +877,9 @@ igb_tx_fill_ring(igb_tx_ring_t *tx_ring, link_list_t *pending_list, * Fill the context descriptor with the * hardware checksum offload informations. */ - igb_fill_hcksum_context( - (struct e1000_adv_tx_context_desc *)tbd, hcksum, - tx_ring->index); + igb_fill_tx_context( + (struct e1000_adv_tx_context_desc *)tbd, + ctx, tx_ring->index); index = NEXT_INDEX(index, 1, tx_ring->ring_size); desc_num++; @@ -730,7 +888,7 @@ igb_tx_fill_ring(igb_tx_ring_t *tx_ring, link_list_t *pending_list, * Store the checksum context data if * a new context descriptor is added */ - tx_ring->hcksum_context = *hcksum; + tx_ring->tx_context = *ctx; } } @@ -763,8 +921,6 @@ igb_tx_fill_ring(igb_tx_ring_t *tx_ring, link_list_t *pending_list, tbd->read.olinfo_status = 0; - pay_len += tcb->desc[i].length; - index = NEXT_INDEX(index, 1, tx_ring->ring_size); desc_num++; } @@ -791,13 +947,20 @@ igb_tx_fill_ring(igb_tx_ring_t *tx_ring, link_list_t *pending_list, /* * The Insert Ethernet CRC (IFCS) bit and the checksum fields are only * valid in the first descriptor of the packet. - * 82576 also requires the payload length setting even without TSO + * 82576 also requires the payload length setting even without LSO */ ASSERT(first_tbd != NULL); first_tbd->read.cmd_type_len |= E1000_ADVTXD_DCMD_IFCS; - if (hw->mac.type == e1000_82576) { - first_tbd->read.olinfo_status = - (pay_len << E1000_ADVTXD_PAYLEN_SHIFT); + if (ctx != NULL && ctx->lso_flag) { + first_tbd->read.cmd_type_len |= E1000_ADVTXD_DCMD_TSE; + first_tbd->read.olinfo_status |= + (mbsize - ctx->mac_hdr_len - ctx->ip_hdr_len + - ctx->l4_hdr_len) << E1000_ADVTXD_PAYLEN_SHIFT; + } else { + if (hw->mac.type == e1000_82576) { + first_tbd->read.olinfo_status |= + (mbsize << E1000_ADVTXD_PAYLEN_SHIFT); + } } /* Set hardware checksum bits */ |