summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorml29623 <none@none>2008-01-04 11:32:17 -0800
committerml29623 <none@none>2008-01-04 11:32:17 -0800
commit30ac2e7bcba3a0a4c91d060d5ac3d60cd00f7a3a (patch)
treed847bc1e4a002173f04a8f8c82e1daa29789ac70
parentf5f5959bd78f309ae446ddd7d5051717490edd2a (diff)
downloadillumos-gate-30ac2e7bcba3a0a4c91d060d5ac3d60cd00f7a3a.tar.gz
6633097 nxge needs to implement Software LSO to reach Maramba transmit throughput goal
6614965 Neptune 2XGF TCP RX doesn't scale on Maramba & Huron due to lack of DMA buffer 6634075 global counter nxge_mblks_pending is getting too hot
-rw-r--r--usr/src/uts/common/io/nxge/nxge_main.c73
-rw-r--r--usr/src/uts/common/io/nxge/nxge_rxdma.c15
-rw-r--r--usr/src/uts/common/io/nxge/nxge_send.c839
-rw-r--r--usr/src/uts/common/sys/nxge/nxge_common.h2
-rw-r--r--usr/src/uts/common/sys/nxge/nxge_defs.h6
5 files changed, 901 insertions, 34 deletions
diff --git a/usr/src/uts/common/io/nxge/nxge_main.c b/usr/src/uts/common/io/nxge/nxge_main.c
index a6ecb08d5d..9c8f5069d8 100644
--- a/usr/src/uts/common/io/nxge/nxge_main.c
+++ b/usr/src/uts/common/io/nxge/nxge_main.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -64,6 +64,12 @@ uint16_t nxge_rcr_timeout = NXGE_RDC_RCR_TIMEOUT;
uint16_t nxge_rcr_threshold = NXGE_RDC_RCR_THRESHOLD;
nxge_tx_mode_t nxge_tx_scheme = NXGE_USE_SERIAL;
+/* MAX LSO size */
+#define NXGE_LSO_MAXLEN 65535
+/* Enable Software LSO flag */
+uint32_t nxge_lso_enable = 1;
+uint32_t nxge_lso_max = NXGE_LSO_MAXLEN;
+
/*
* Debugging flags:
* nxge_no_tx_lb : transmit load balancing
@@ -370,7 +376,8 @@ size_t alloc_sizes [] = {0x2000};
#else
size_t alloc_sizes [] = {0x1000, 0x2000, 0x4000, 0x8000,
0x10000, 0x20000, 0x40000, 0x80000,
- 0x100000, 0x200000, 0x400000, 0x800000, 0x1000000};
+ 0x100000, 0x200000, 0x400000, 0x800000,
+ 0x1000000, 0x2000000, 0x4000000};
#endif
/*
@@ -1938,6 +1945,20 @@ nxge_alloc_rx_mem_pool(p_nxge_t nxgep)
nxge_port_rbr_spare_size = (NXGE_RXDMA_POST_BATCH *
(nxge_port_rbr_spare_size / NXGE_RXDMA_POST_BATCH + 1));
}
+ if (nxge_port_rbr_size > RBR_DEFAULT_MAX_BLKS) {
+ NXGE_DEBUG_MSG((nxgep, MEM_CTL,
+ "nxge_alloc_rx_mem_pool: RBR size too high %d, "
+ "set to default %d",
+ nxge_port_rbr_size, RBR_DEFAULT_MAX_BLKS));
+ nxge_port_rbr_size = RBR_DEFAULT_MAX_BLKS;
+ }
+ if (nxge_port_rcr_size > RCR_DEFAULT_MAX) {
+ NXGE_DEBUG_MSG((nxgep, MEM_CTL,
+ "nxge_alloc_rx_mem_pool: RCR too high %d, "
+ "set to default %d",
+ nxge_port_rcr_size, RCR_DEFAULT_MAX));
+ nxge_port_rcr_size = RCR_DEFAULT_MAX;
+ }
/*
* N2/NIU has limitation on the descriptor sizes (contiguous
@@ -2249,9 +2270,21 @@ nxge_alloc_rx_buf_dma(p_nxge_t nxgep, uint16_t dma_channel,
if (allocated < total_alloc_size) {
+ NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
+ "==> nxge_alloc_rx_buf_dma: not enough for channe %d "
+ "allocated 0x%x requested 0x%x",
+ dma_channel,
+ allocated, total_alloc_size));
+ status = NXGE_ERROR;
goto nxge_alloc_rx_mem_fail1;
}
+ NXGE_DEBUG_MSG((nxgep, MEM2_CTL,
+ "==> nxge_alloc_rx_buf_dma: Allocated for channe %d "
+ "allocated 0x%x requested 0x%x",
+ dma_channel,
+ allocated, total_alloc_size));
+
NXGE_DEBUG_MSG((nxgep, DMA_CTL,
" alloc_rx_buf_dma rdc %d allocated %d chunks",
dma_channel, i));
@@ -2379,6 +2412,14 @@ nxge_alloc_tx_mem_pool(p_nxge_t nxgep)
dma_cntl_p = (p_nxge_dma_common_t *)KMEM_ZALLOC(
sizeof (p_nxge_dma_common_t) * ndmas, KM_SLEEP);
+ if (nxge_tx_ring_size > TDC_DEFAULT_MAX) {
+ NXGE_DEBUG_MSG((nxgep, MEM_CTL,
+ "nxge_alloc_tx_mem_pool: TDC too high %d, "
+ "set to default %d",
+ nxge_tx_ring_size, TDC_DEFAULT_MAX));
+ nxge_tx_ring_size = TDC_DEFAULT_MAX;
+ }
+
#if defined(sun4v) && defined(NIU_LP_WORKAROUND)
/*
* N2/NIU has limitation on the descriptor sizes (contiguous
@@ -2592,9 +2633,21 @@ nxge_alloc_tx_buf_dma(p_nxge_t nxgep, uint16_t dma_channel,
}
if (allocated < total_alloc_size) {
+ NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
+ "==> nxge_alloc_tx_buf_dma: not enough channel %d: "
+ "allocated 0x%x requested 0x%x",
+ dma_channel,
+ allocated, total_alloc_size));
+ status = NXGE_ERROR;
goto nxge_alloc_tx_mem_fail1;
}
+ NXGE_DEBUG_MSG((nxgep, MEM2_CTL,
+ "==> nxge_alloc_tx_buf_dma: Allocated for channel %d: "
+ "allocated 0x%x requested 0x%x",
+ dma_channel,
+ allocated, total_alloc_size));
+
*num_chunks = i;
*dmap = tx_dmap;
NXGE_DEBUG_MSG((nxgep, DMA_CTL,
@@ -3795,6 +3848,21 @@ nxge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
mutex_exit(nxgep->genlock);
break;
+ case MAC_CAPAB_LSO: {
+ mac_capab_lso_t *cap_lso = cap_data;
+
+ if (nxge_lso_enable) {
+ cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
+ if (nxge_lso_max > NXGE_LSO_MAXLEN) {
+ nxge_lso_max = NXGE_LSO_MAXLEN;
+ }
+ cap_lso->lso_basic_tcp_ipv4.lso_max = nxge_lso_max;
+ break;
+ } else {
+ return (B_FALSE);
+ }
+ }
+
default:
return (B_FALSE);
}
@@ -3870,7 +3938,6 @@ _init(void)
"failed to init device soft state"));
goto _init_exit;
}
-
status = mod_install(&modlinkage);
if (status != 0) {
ddi_soft_state_fini(&nxge_list);
diff --git a/usr/src/uts/common/io/nxge/nxge_rxdma.c b/usr/src/uts/common/io/nxge/nxge_rxdma.c
index 962f030d71..760546ed05 100644
--- a/usr/src/uts/common/io/nxge/nxge_rxdma.c
+++ b/usr/src/uts/common/io/nxge/nxge_rxdma.c
@@ -1571,7 +1571,6 @@ nxge_dupb(p_rx_msg_t nxge_mp, uint_t offset, size_t size)
goto nxge_dupb_exit;
}
atomic_inc_32(&nxge_mp->ref_cnt);
- atomic_inc_32(&nxge_mblks_pending);
nxge_dupb_exit:
@@ -1607,9 +1606,6 @@ void nxge_post_page(p_nxge_t nxgep, p_rx_rbr_ring_t rx_rbr_p,
void
nxge_post_page(p_nxge_t nxgep, p_rx_rbr_ring_t rx_rbr_p, p_rx_msg_t rx_msg_p)
{
-
- npi_handle_t handle;
-
NXGE_DEBUG_MSG((nxgep, RX_CTL, "==> nxge_post_page"));
/* Reuse this buffer */
@@ -1627,14 +1623,12 @@ nxge_post_page(p_nxge_t nxgep, p_rx_rbr_ring_t rx_rbr_p, p_rx_msg_t rx_msg_p)
* Get the rbr header pointer and its offset index.
*/
MUTEX_ENTER(&rx_rbr_p->post_lock);
-
-
rx_rbr_p->rbr_wr_index = ((rx_rbr_p->rbr_wr_index + 1) &
rx_rbr_p->rbr_wrap_mask);
rx_rbr_p->rbr_desc_vp[rx_rbr_p->rbr_wr_index] = rx_msg_p->shifted_addr;
MUTEX_EXIT(&rx_rbr_p->post_lock);
- handle = NXGE_DEV_NPI_HANDLE(nxgep);
- npi_rxdma_rdc_rbr_kick(handle, rx_rbr_p->rdc, 1);
+ npi_rxdma_rdc_rbr_kick(NXGE_DEV_NPI_HANDLE(nxgep),
+ rx_rbr_p->rdc, 1);
NXGE_DEBUG_MSG((nxgep, RX_CTL,
"<== nxge_post_page (channel %d post_next_index %d)",
@@ -1658,7 +1652,6 @@ nxge_freeb(p_rx_msg_t rx_msg_p)
"nxge_freeb:rx_msg_p = $%p (block pending %d)",
rx_msg_p, nxge_mblks_pending));
- atomic_dec_32(&nxge_mblks_pending);
/*
* First we need to get the free state, then
* atomic decrement the reference count to prevent
@@ -1668,6 +1661,7 @@ nxge_freeb(p_rx_msg_t rx_msg_p)
free_state = rx_msg_p->free;
ref_cnt = atomic_add_32_nv(&rx_msg_p->ref_cnt, -1);
if (!ref_cnt) {
+ atomic_dec_32(&nxge_mblks_pending);
buffer = rx_msg_p->buffer;
size = rx_msg_p->block_size;
NXGE_DEBUG_MSG((NULL, MEM2_CTL, "nxge_freeb: "
@@ -2442,7 +2436,6 @@ nxge_receive_packet(p_nxge_t nxgep,
*/
if (error_send_up == B_FALSE) {
atomic_inc_32(&rx_msg_p->ref_cnt);
- atomic_inc_32(&nxge_mblks_pending);
if (buffer_free == B_TRUE) {
rx_msg_p->free = B_TRUE;
}
@@ -2513,7 +2506,6 @@ nxge_receive_packet(p_nxge_t nxgep,
cmn_err(CE_WARN, "!nxge_receive_packet: "
"update stats (error)");
atomic_inc_32(&rx_msg_p->ref_cnt);
- atomic_inc_32(&nxge_mblks_pending);
if (buffer_free == B_TRUE) {
rx_msg_p->free = B_TRUE;
}
@@ -2549,7 +2541,6 @@ nxge_receive_packet(p_nxge_t nxgep,
if (rx_msg_p->free && rx_msg_p->rx_use_bcopy) {
atomic_inc_32(&rx_msg_p->ref_cnt);
- atomic_inc_32(&nxge_mblks_pending);
nxge_freeb(rx_msg_p);
}
diff --git a/usr/src/uts/common/io/nxge/nxge_send.c b/usr/src/uts/common/io/nxge/nxge_send.c
index b1e90fd719..5ee828489a 100644
--- a/usr/src/uts/common/io/nxge/nxge_send.c
+++ b/usr/src/uts/common/io/nxge/nxge_send.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -27,6 +27,19 @@
#include <sys/nxge/nxge_impl.h>
+/* Software LSO required header files */
+#include <netinet/tcp.h>
+#include <inet/ip_impl.h>
+#include <inet/tcp.h>
+
+static mblk_t *nxge_lso_eliminate(mblk_t *);
+static mblk_t *nxge_do_softlso(mblk_t *mp, uint32_t mss);
+static void nxge_lso_info_get(mblk_t *, uint32_t *, uint32_t *);
+static void nxge_hcksum_retrieve(mblk_t *,
+ uint32_t *, uint32_t *, uint32_t *,
+ uint32_t *, uint32_t *);
+static uint32_t nxge_csgen(uint16_t *, int);
+
extern uint32_t nxge_reclaim_pending;
extern uint32_t nxge_bcopy_thresh;
extern uint32_t nxge_dvma_thresh;
@@ -39,6 +52,8 @@ extern uint32_t nxge_tx_use_bcopy;
extern uint32_t nxge_tx_lb_policy;
extern uint32_t nxge_no_tx_lb;
extern nxge_tx_mode_t nxge_tx_scheme;
+extern uint32_t nxge_lso_enable;
+uint32_t nxge_lso_kick_cnt = 2;
typedef struct _mac_tx_hint {
uint16_t sap;
@@ -107,6 +122,13 @@ nxge_start(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, p_mblk_t mp)
int xfer_len;
uint32_t msgsize;
#endif
+ p_mblk_t mp_chain = NULL;
+ boolean_t is_lso = B_FALSE;
+ boolean_t lso_again;
+ int cur_index_lso;
+ p_mblk_t nmp_lso_save;
+ uint32_t lso_ngathers;
+ boolean_t lso_tail_wrap = B_FALSE;
NXGE_DEBUG_MSG((nxgep, TX_CTL,
"==> nxge_start: tx dma channel %d", tx_ring_p->tdc));
@@ -125,6 +147,28 @@ nxge_start(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, p_mblk_t mp)
}
}
+ if (nxge_lso_enable) {
+ mp_chain = nxge_lso_eliminate(mp);
+ NXGE_DEBUG_MSG((nxgep, TX_CTL,
+ "==> nxge_start(0): LSO mp $%p mp_chain $%p",
+ mp, mp_chain));
+ if (mp_chain == NULL) {
+ NXGE_ERROR_MSG((nxgep, TX_CTL,
+ "==> nxge_send(0): NULL mp_chain $%p != mp $%p",
+ mp_chain, mp));
+ goto nxge_start_fail1;
+ }
+ if (mp_chain != mp) {
+ NXGE_DEBUG_MSG((nxgep, TX_CTL,
+ "==> nxge_send(1): IS LSO mp_chain $%p != mp $%p",
+ mp_chain, mp));
+ is_lso = B_TRUE;
+ mp = mp_chain;
+ mp_chain = mp_chain->b_next;
+ mp->b_next = NULL;
+ }
+ }
+
hcksum_retrieve(mp, NULL, NULL, &start_offset,
&stuff_offset, &end_offset, &value, &cksum_flags);
if (!NXGE_IS_VLAN_PACKET(mp->b_rptr)) {
@@ -137,11 +181,21 @@ nxge_start(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, p_mblk_t mp)
if (cksum_flags & HCK_PARTIALCKSUM) {
NXGE_DEBUG_MSG((nxgep, TX_CTL,
- "==> nxge_start: cksum_flags 0x%x (partial checksum) ",
- cksum_flags));
+ "==> nxge_start: mp $%p len %d "
+ "cksum_flags 0x%x (partial checksum) ",
+ mp, MBLKL(mp), cksum_flags));
cksum_on = B_TRUE;
}
+ lso_again = B_FALSE;
+ lso_ngathers = 0;
+
+ MUTEX_ENTER(&tx_ring_p->lock);
+ cur_index_lso = tx_ring_p->wr_index;
+ lso_tail_wrap = tx_ring_p->wr_index_wrap;
+start_again:
+ ngathers = 0;
+ sop_index = tx_ring_p->wr_index;
#ifdef NXGE_DEBUG
if (tx_ring_p->descs_pending) {
NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_start: "
@@ -163,7 +217,6 @@ nxge_start(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, p_mblk_t mp)
nxge_dump_packet((char *)mp->b_rptr, dump_len)));
#endif
- MUTEX_ENTER(&tx_ring_p->lock);
tdc_stats = tx_ring_p->tdc_stats;
mark_mode = (tx_ring_p->descs_pending &&
((tx_ring_p->tx_ring_size - tx_ring_p->descs_pending)
@@ -177,15 +230,28 @@ nxge_start(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, p_mblk_t mp)
NXGE_DEBUG_MSG((nxgep, TX_CTL,
"TX Descriptor ring is full: channel %d",
tx_ring_p->tdc));
- cas32((uint32_t *)&tx_ring_p->queueing, 0, 1);
- tdc_stats->tx_no_desc++;
- MUTEX_EXIT(&tx_ring_p->lock);
- if (nxgep->resched_needed && !nxgep->resched_running) {
- nxgep->resched_running = B_TRUE;
- ddi_trigger_softintr(nxgep->resched_id);
+ NXGE_DEBUG_MSG((nxgep, TX_CTL,
+ "TX Descriptor ring is full: channel %d",
+ tx_ring_p->tdc));
+ if (is_lso) {
+ /* free the current mp and mp_chain if not FULL */
+ tdc_stats->tx_no_desc++;
+ NXGE_DEBUG_MSG((nxgep, TX_CTL,
+ "LSO packet: TX Descriptor ring is full: "
+ "channel %d",
+ tx_ring_p->tdc));
+ goto nxge_start_fail_lso;
+ } else {
+ cas32((uint32_t *)&tx_ring_p->queueing, 0, 1);
+ tdc_stats->tx_no_desc++;
+ MUTEX_EXIT(&tx_ring_p->lock);
+ if (nxgep->resched_needed && !nxgep->resched_running) {
+ nxgep->resched_running = B_TRUE;
+ ddi_trigger_softintr(nxgep->resched_id);
+ }
+ status = 1;
+ goto nxge_start_fail1;
}
- status = 1;
- goto nxge_start_fail1;
}
nmp = mp;
@@ -262,8 +328,17 @@ nxge_start(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, p_mblk_t mp)
nmp->b_cont = t_mp;
len = MBLKL(nmp);
} else {
- good_packet = B_FALSE;
- goto nxge_start_fail2;
+ if (is_lso) {
+ NXGE_DEBUG_MSG((nxgep, TX_CTL,
+ "LSO packet: dupb failed: "
+ "channel %d",
+ tx_ring_p->tdc));
+ mp = nmp;
+ goto nxge_start_fail_lso;
+ } else {
+ good_packet = B_FALSE;
+ goto nxge_start_fail2;
+ }
}
}
tx_desc.value = 0;
@@ -452,7 +527,7 @@ nxge_start(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, p_mblk_t mp)
ngathers++;
/*
* this is the fix for multiple
- * cookies, which are basicaly
+ * cookies, which are basically
* a descriptor entry, we don't set
* SOP bit as well as related fields
*/
@@ -518,10 +593,18 @@ nxge_start(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, p_mblk_t mp)
good_packet = B_FALSE;
tdc_stats->tx_dma_bind_fail++;
tx_msg_p->flags.dma_type = USE_NONE;
- goto nxge_start_fail2;
+ if (is_lso) {
+ mp = nmp;
+ goto nxge_start_fail_lso;
+ } else {
+ goto nxge_start_fail2;
+ }
}
} /* ddi dvma */
+ if (is_lso) {
+ nmp_lso_save = nmp;
+ }
nmp = nmp->b_cont;
nxge_start_control_header_only:
#if defined(__i386)
@@ -599,6 +682,10 @@ nxge_start_control_header_only:
"len %d pkt_len %d ngathers %d",
len, pkt_len, ngathers));
/* Pull all message blocks from b_cont */
+ if (is_lso) {
+ mp = nmp_lso_save;
+ goto nxge_start_fail_lso;
+ }
if ((msgpullup(mp, -1)) == NULL) {
goto nxge_start_fail2;
}
@@ -792,6 +879,54 @@ nxge_start_control_header_only:
ngathers,
tx_ring_p->descs_pending));
+ if (is_lso) {
+ lso_ngathers += ngathers;
+ if (mp_chain != NULL) {
+ mp = mp_chain;
+ mp_chain = mp_chain->b_next;
+ mp->b_next = NULL;
+ if (nxge_lso_kick_cnt == lso_ngathers) {
+ {
+ tx_ring_kick_t kick;
+
+ kick.value = 0;
+ kick.bits.ldw.wrap =
+ tx_ring_p->wr_index_wrap;
+ kick.bits.ldw.tail =
+ (uint16_t)tx_ring_p->wr_index;
+
+ /* Kick the Transmit kick register */
+ TXDMA_REG_WRITE64(
+ NXGE_DEV_NPI_HANDLE(nxgep),
+ TX_RING_KICK_REG,
+ (uint8_t)tx_ring_p->tdc,
+ kick.value);
+ tdc_stats->tx_starts++;
+ NXGE_DEBUG_MSG((nxgep, TX_CTL,
+ "==> nxge_start: more LSO: "
+ "LSO_CNT %d",
+ lso_gathers));
+ }
+ lso_ngathers = 0;
+ ngathers = 0;
+ cur_index_lso = sop_index = tx_ring_p->wr_index;
+ lso_tail_wrap = tx_ring_p->wr_index_wrap;
+ }
+ NXGE_DEBUG_MSG((nxgep, TX_CTL,
+ "==> nxge_start: lso again: "
+ "lso_gathers %d ngathers %d cur_index_lso %d "
+ "wr_index %d sop_index %d",
+ lso_ngathers, ngathers, cur_index_lso,
+ tx_ring_p->wr_index, sop_index));
+
+ NXGE_DEBUG_MSG((nxgep, TX_CTL,
+ "==> nxge_start: next : count %d",
+ lso_gathers));
+ lso_again = B_TRUE;
+ goto start_again;
+ }
+ }
+
NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_start: TX KICKING: "));
{
@@ -816,6 +951,46 @@ nxge_start_control_header_only:
return (status);
+nxge_start_fail_lso:
+ status = 0;
+ good_packet = B_FALSE;
+ if (mp != NULL) {
+ freemsg(mp);
+ }
+ if (mp_chain != NULL) {
+ freemsg(mp_chain);
+ }
+ if (!lso_again && !ngathers) {
+ MUTEX_EXIT(&tx_ring_p->lock);
+ NXGE_DEBUG_MSG((nxgep, TX_CTL,
+ "==> nxge_start: lso exit (nothing changed)"));
+ goto nxge_start_fail1;
+ }
+
+ NXGE_DEBUG_MSG((nxgep, TX_CTL,
+ "==> nxge_start (channel %d): before lso "
+ "lso_gathers %d ngathers %d cur_index_lso %d "
+ "wr_index %d sop_index %d lso_again %d",
+ tx_ring_p->tdc,
+ lso_ngathers, ngathers, cur_index_lso,
+ tx_ring_p->wr_index, sop_index, lso_again));
+
+ if (lso_again) {
+ lso_ngathers += ngathers;
+ ngathers = lso_ngathers;
+ sop_index = cur_index_lso;
+ tx_ring_p->wr_index = sop_index;
+ tx_ring_p->wr_index_wrap = lso_tail_wrap;
+ }
+
+ NXGE_DEBUG_MSG((nxgep, TX_CTL,
+ "==> nxge_start (channel %d): after lso "
+ "lso_gathers %d ngathers %d cur_index_lso %d "
+ "wr_index %d sop_index %d lso_again %d",
+ tx_ring_p->tdc,
+ lso_ngathers, ngathers, cur_index_lso,
+ tx_ring_p->wr_index, sop_index, lso_again));
+
nxge_start_fail2:
if (good_packet == B_FALSE) {
cur_index = sop_index;
@@ -955,6 +1130,10 @@ nxge_m_tx(void *arg, mblk_t *mp)
}
mp = next;
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_m_tx: (go back to loop) mp $%p next $%p",
+ mp, next));
}
return (mp);
@@ -1101,3 +1280,631 @@ nxge_reschedule(caddr_t arg)
NXGE_DEBUG_MSG((NULL, TX_CTL, "<== nxge_reschedule"));
return (DDI_INTR_CLAIMED);
}
+
+
+/* Software LSO starts here */
+static void
+nxge_hcksum_retrieve(mblk_t *mp,
+ uint32_t *start, uint32_t *stuff, uint32_t *end,
+ uint32_t *value, uint32_t *flags)
+{
+ if (mp->b_datap->db_type == M_DATA) {
+ if (flags != NULL) {
+ *flags = DB_CKSUMFLAGS(mp) & (HCK_IPV4_HDRCKSUM |
+ HCK_PARTIALCKSUM | HCK_FULLCKSUM |
+ HCK_FULLCKSUM_OK);
+ if ((*flags & (HCK_PARTIALCKSUM |
+ HCK_FULLCKSUM)) != 0) {
+ if (value != NULL)
+ *value = (uint32_t)DB_CKSUM16(mp);
+ if ((*flags & HCK_PARTIALCKSUM) != 0) {
+ if (start != NULL)
+ *start =
+ (uint32_t)DB_CKSUMSTART(mp);
+ if (stuff != NULL)
+ *stuff =
+ (uint32_t)DB_CKSUMSTUFF(mp);
+ if (end != NULL)
+ *end =
+ (uint32_t)DB_CKSUMEND(mp);
+ }
+ }
+ }
+ }
+}
+
+static void
+nxge_lso_info_get(mblk_t *mp, uint32_t *mss, uint32_t *flags)
+{
+ ASSERT(DB_TYPE(mp) == M_DATA);
+
+ *mss = 0;
+ if (flags != NULL) {
+ *flags = DB_CKSUMFLAGS(mp) & HW_LSO;
+ if ((*flags != 0) && (mss != NULL)) {
+ *mss = (uint32_t)DB_LSOMSS(mp);
+ }
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_lso_info_get(flag !=NULL): mss %d *flags 0x%x",
+ *mss, *flags));
+ }
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "<== nxge_lso_info_get: mss %d", *mss));
+}
+
+/*
+ * Do Soft LSO on the oversized packet.
+ *
+ * 1. Create a chain of message for headers.
+ * 2. Fill up header messages with proper information.
+ * 3. Copy Eithernet, IP, and TCP headers from the original message to
+ * each new message with necessary adjustments.
+ * * Unchange the ethernet header for DIX frames. (by default)
+ * * IP Total Length field is updated to MSS or less(only for the last one).
+ * * IP Identification value is incremented by one for each packet.
+ * * TCP sequence Number is recalculated according to the payload length.
+ * * Set FIN and/or PSH flags for the *last* packet if applied.
+ * * TCP partial Checksum
+ * 4. Update LSO information in the first message header.
+ * 5. Release the original message header.
+ */
+static mblk_t *
+nxge_do_softlso(mblk_t *mp, uint32_t mss)
+{
+ uint32_t hckflags;
+ int pktlen;
+ int hdrlen;
+ int segnum;
+ int i;
+ struct ether_vlan_header *evh;
+ int ehlen, iphlen, tcphlen;
+ struct ip *oiph, *niph;
+ struct tcphdr *otcph, *ntcph;
+ int available, len, left;
+ uint16_t ip_id;
+ uint32_t tcp_seq;
+#ifdef __sparc
+ uint32_t tcp_seq_tmp;
+#endif
+ mblk_t *datamp;
+ uchar_t *rptr;
+ mblk_t *nmp;
+ mblk_t *cmp;
+ mblk_t *mp_chain;
+ boolean_t do_cleanup = B_FALSE;
+ t_uscalar_t start_offset = 0;
+ t_uscalar_t stuff_offset = 0;
+ t_uscalar_t value = 0;
+ uint16_t l4_len;
+ ipaddr_t src, dst;
+ uint32_t cksum, sum, l4cksum;
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_do_softlso"));
+ /*
+ * check the length of LSO packet payload and calculate the number of
+ * segments to be generated.
+ */
+ pktlen = msgsize(mp);
+ evh = (struct ether_vlan_header *)mp->b_rptr;
+
+ /* VLAN? */
+ if (evh->ether_tpid == htons(ETHERTYPE_VLAN))
+ ehlen = sizeof (struct ether_vlan_header);
+ else
+ ehlen = sizeof (struct ether_header);
+ oiph = (struct ip *)(mp->b_rptr + ehlen);
+ iphlen = oiph->ip_hl * 4;
+ otcph = (struct tcphdr *)(mp->b_rptr + ehlen + iphlen);
+ tcphlen = otcph->th_off * 4;
+
+ l4_len = pktlen - ehlen - iphlen;
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_do_softlso: mss %d oiph $%p "
+ "original ip_sum oiph->ip_sum 0x%x "
+ "original tcp_sum otcph->th_sum 0x%x "
+ "oiph->ip_len %d pktlen %d ehlen %d "
+ "l4_len %d (0x%x) ip_len - iphlen %d ",
+ mss,
+ oiph,
+ oiph->ip_sum,
+ otcph->th_sum,
+ ntohs(oiph->ip_len), pktlen,
+ ehlen,
+ l4_len,
+ l4_len,
+ ntohs(oiph->ip_len) - iphlen));
+
+ /* IPv4 + TCP */
+ if (!(oiph->ip_v == IPV4_VERSION)) {
+ NXGE_ERROR_MSG((NULL, NXGE_ERR_CTL,
+ "<== nxge_do_softlso: not IPV4 "
+ "oiph->ip_len %d pktlen %d ehlen %d tcphlen %d",
+ ntohs(oiph->ip_len), pktlen, ehlen,
+ tcphlen));
+ freemsg(mp);
+ return (NULL);
+ }
+
+ if (!(oiph->ip_p == IPPROTO_TCP)) {
+ NXGE_ERROR_MSG((NULL, NXGE_ERR_CTL,
+ "<== nxge_do_softlso: not TCP "
+ "oiph->ip_len %d pktlen %d ehlen %d tcphlen %d",
+ ntohs(oiph->ip_len), pktlen, ehlen,
+ tcphlen));
+ freemsg(mp);
+ return (NULL);
+ }
+
+ if (!(ntohs(oiph->ip_len) == pktlen - ehlen)) {
+ NXGE_ERROR_MSG((NULL, NXGE_ERR_CTL,
+ "<== nxge_do_softlso: len not matched "
+ "oiph->ip_len %d pktlen %d ehlen %d tcphlen %d",
+ ntohs(oiph->ip_len), pktlen, ehlen,
+ tcphlen));
+ freemsg(mp);
+ return (NULL);
+ }
+
+ otcph = (struct tcphdr *)(mp->b_rptr + ehlen + iphlen);
+ tcphlen = otcph->th_off * 4;
+
+ /* TCP flags can not include URG, RST, or SYN */
+ VERIFY((otcph->th_flags & (TH_SYN | TH_RST | TH_URG)) == 0);
+
+ hdrlen = ehlen + iphlen + tcphlen;
+
+ VERIFY(MBLKL(mp) >= hdrlen);
+
+ if (MBLKL(mp) > hdrlen) {
+ datamp = mp;
+ rptr = mp->b_rptr + hdrlen;
+ } else { /* = */
+ datamp = mp->b_cont;
+ rptr = datamp->b_rptr;
+ }
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "nxge_do_softlso: otcph $%p pktlen: %d, "
+ "hdrlen %d ehlen %d iphlen %d tcphlen %d "
+ "mblkl(mp): %d, mblkl(datamp): %d",
+ otcph,
+ pktlen, hdrlen, ehlen, iphlen, tcphlen,
+ (int)MBLKL(mp), (int)MBLKL(datamp)));
+
+ hckflags = 0;
+ nxge_hcksum_retrieve(mp,
+ &start_offset, &stuff_offset, &value, NULL, &hckflags);
+
+ dst = oiph->ip_dst.s_addr;
+ src = oiph->ip_src.s_addr;
+
+ cksum = (dst >> 16) + (dst & 0xFFFF) +
+ (src >> 16) + (src & 0xFFFF);
+ l4cksum = cksum + IP_TCP_CSUM_COMP;
+
+ sum = l4_len + l4cksum;
+ sum = (sum & 0xFFFF) + (sum >> 16);
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_do_softlso: dst 0x%x src 0x%x sum 0x%x ~new 0x%x "
+ "hckflags 0x%x start_offset %d stuff_offset %d "
+ "value (original) 0x%x th_sum 0x%x "
+ "pktlen %d l4_len %d (0x%x) "
+ "MBLKL(mp): %d, MBLKL(datamp): %d dump header %s",
+ dst, src,
+ (sum & 0xffff), (~sum & 0xffff),
+ hckflags, start_offset, stuff_offset,
+ value, otcph->th_sum,
+ pktlen,
+ l4_len,
+ l4_len,
+ ntohs(oiph->ip_len) - (int)MBLKL(mp),
+ (int)MBLKL(datamp),
+ nxge_dump_packet((char *)evh, 12)));
+
+ /*
+ * Start to process.
+ */
+ available = pktlen - hdrlen;
+ segnum = (available - 1) / mss + 1;
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_do_softlso: pktlen %d "
+ "MBLKL(mp): %d, MBLKL(datamp): %d "
+ "available %d mss %d segnum %d",
+ pktlen, (int)MBLKL(mp), (int)MBLKL(datamp),
+ available,
+ mss,
+ segnum));
+
+ VERIFY(segnum >= 2);
+
+ /*
+ * Try to pre-allocate all header messages
+ */
+ mp_chain = NULL;
+ for (i = 0; i < segnum; i++) {
+ if ((nmp = allocb(hdrlen, 0)) == NULL) {
+ /* Clean up the mp_chain */
+ while (mp_chain != NULL) {
+ nmp = mp_chain;
+ mp_chain = mp_chain->b_next;
+ freemsg(nmp);
+ }
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "<== nxge_do_softlso: "
+ "Could not allocate enough messages for headers!"));
+ freemsg(mp);
+ return (NULL);
+ }
+ nmp->b_next = mp_chain;
+ mp_chain = nmp;
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_do_softlso: "
+ "mp $%p nmp $%p mp_chain $%p mp_chain->b_next $%p",
+ mp, nmp, mp_chain, mp_chain->b_next));
+ }
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_do_softlso: mp $%p nmp $%p mp_chain $%p",
+ mp, nmp, mp_chain));
+
+ /*
+ * Associate payload with new packets
+ */
+ cmp = mp_chain;
+ left = available;
+ while (cmp != NULL) {
+ nmp = dupb(datamp);
+ if (nmp == NULL) {
+ do_cleanup = B_TRUE;
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==>nxge_do_softlso: "
+ "Can not dupb(datamp), have to do clean up"));
+ goto cleanup_allocated_msgs;
+ }
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_do_softlso: (loop) before mp $%p cmp $%p "
+ "dupb nmp $%p len %d left %d msd %d ",
+ mp, cmp, nmp, len, left, mss));
+
+ cmp->b_cont = nmp;
+ nmp->b_rptr = rptr;
+ len = (left < mss) ? left : mss;
+ left -= len;
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_do_softlso: (loop) after mp $%p cmp $%p "
+ "dupb nmp $%p len %d left %d mss %d ",
+ mp, cmp, nmp, len, left, mss));
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "nxge_do_softlso: before available: %d, "
+ "left: %d, len: %d, segnum: %d MBLK(nmp): %d",
+ available, left, len, segnum, (int)MBLKL(nmp)));
+
+ len -= MBLKL(nmp);
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "nxge_do_softlso: after available: %d, "
+ "left: %d, len: %d, segnum: %d MBLK(nmp): %d",
+ available, left, len, segnum, (int)MBLKL(nmp)));
+
+ while (len > 0) {
+ mblk_t *mmp = NULL;
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "nxge_do_softlso: (4) len > 0 available: %d, "
+ "left: %d, len: %d, segnum: %d MBLK(nmp): %d",
+ available, left, len, segnum, (int)MBLKL(nmp)));
+
+ if (datamp->b_cont != NULL) {
+ datamp = datamp->b_cont;
+ rptr = datamp->b_rptr;
+ mmp = dupb(datamp);
+ if (mmp == NULL) {
+ do_cleanup = B_TRUE;
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_do_softlso: "
+ "Can not dupb(datamp) (1), :
+ "have to do clean up"));
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_do_softlso: "
+ "available: %d, left: %d, "
+ "len: %d, MBLKL(nmp): %d",
+ available, left, len,
+ (int)MBLKL(nmp)));
+ goto cleanup_allocated_msgs;
+ }
+ } else {
+ NXGE_ERROR_MSG((NULL, NXGE_ERR_CTL,
+ "==> nxge_do_softlso: "
+ "(1)available: %d, left: %d, "
+ "len: %d, MBLKL(nmp): %d",
+ available, left, len,
+ (int)MBLKL(nmp)));
+ cmn_err(CE_PANIC,
+ "==> nxge_do_softlso: "
+ "Pointers must have been corrupted!\n"
+ "datamp: $%p, nmp: $%p, rptr: $%p",
+ (void *)datamp,
+ (void *)nmp,
+ (void *)rptr);
+ }
+ nmp->b_cont = mmp;
+ nmp = mmp;
+ len -= MBLKL(nmp);
+ }
+ if (len < 0) {
+ nmp->b_wptr += len;
+ rptr = nmp->b_wptr;
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "(5) len < 0 (less than 0)"
+ "available: %d, left: %d, len: %d, MBLKL(nmp): %d",
+ available, left, len, (int)MBLKL(nmp)));
+
+ } else if (len == 0) {
+ if (datamp->b_cont != NULL) {
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "(5) len == 0"
+ "available: %d, left: %d, len: %d, "
+ "MBLKL(nmp): %d",
+ available, left, len, (int)MBLKL(nmp)));
+ datamp = datamp->b_cont;
+ rptr = datamp->b_rptr;
+ } else {
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "(6)available b_cont == NULL : %d, "
+ "left: %d, len: %d, MBLKL(nmp): %d",
+ available, left, len, (int)MBLKL(nmp)));
+
+ VERIFY(cmp->b_next == NULL);
+ VERIFY(left == 0);
+ break; /* Done! */
+ }
+ }
+ cmp = cmp->b_next;
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "(7) do_softlso: "
+ "next mp in mp_chain available len != 0 : %d, "
+ "left: %d, len: %d, MBLKL(nmp): %d",
+ available, left, len, (int)MBLKL(nmp)));
+ }
+
+ /*
+ * From now, start to fill up all headers for the first message
+ * Hardware checksum flags need to be updated separately for FULLCKSUM
+ * and PARTIALCKSUM cases. For full checksum, copy the original flags
+ * into every new packet is enough. But for HCK_PARTIALCKSUM, all
+ * required fields need to be updated properly.
+ */
+ nmp = mp_chain;
+ bcopy(mp->b_rptr, nmp->b_rptr, hdrlen);
+ nmp->b_wptr = nmp->b_rptr + hdrlen;
+ niph = (struct ip *)(nmp->b_rptr + ehlen);
+ niph->ip_len = htons(mss + iphlen + tcphlen);
+ ip_id = ntohs(niph->ip_id);
+ ntcph = (struct tcphdr *)(nmp->b_rptr + ehlen + iphlen);
+#ifdef __sparc
+ bcopy((char *)&ntcph->th_seq, &tcp_seq_tmp, 4);
+ tcp_seq = ntohl(tcp_seq_tmp);
+#else
+ tcp_seq = ntohl(ntcph->th_seq);
+#endif
+
+ ntcph->th_flags &= ~(TH_FIN | TH_PUSH | TH_RST);
+
+ DB_CKSUMFLAGS(nmp) = (uint16_t)hckflags;
+ DB_CKSUMSTART(nmp) = start_offset;
+ DB_CKSUMSTUFF(nmp) = stuff_offset;
+
+ /* calculate IP checksum and TCP pseudo header checksum */
+ niph->ip_sum = 0;
+ niph->ip_sum = (uint16_t)nxge_csgen((uint16_t *)niph, iphlen);
+
+ l4_len = mss + tcphlen;
+ sum = htons(l4_len) + l4cksum;
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ ntcph->th_sum = (sum & 0xffff);
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_do_softlso: first mp $%p (mp_chain $%p) "
+ "mss %d pktlen %d l4_len %d (0x%x) "
+ "MBLKL(mp): %d, MBLKL(datamp): %d "
+ "ip_sum 0x%x "
+ "th_sum 0x%x sum 0x%x ) "
+ "dump first ip->tcp %s",
+ nmp, mp_chain,
+ mss,
+ pktlen,
+ l4_len,
+ l4_len,
+ (int)MBLKL(mp), (int)MBLKL(datamp),
+ niph->ip_sum,
+ ntcph->th_sum,
+ sum,
+ nxge_dump_packet((char *)niph, 52)));
+
+ cmp = nmp;
+ while ((nmp = nmp->b_next)->b_next != NULL) {
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==>nxge_do_softlso: middle l4_len %d ", l4_len));
+ bcopy(cmp->b_rptr, nmp->b_rptr, hdrlen);
+ nmp->b_wptr = nmp->b_rptr + hdrlen;
+ niph = (struct ip *)(nmp->b_rptr + ehlen);
+ niph->ip_id = htons(++ip_id);
+ niph->ip_len = htons(mss + iphlen + tcphlen);
+ ntcph = (struct tcphdr *)(nmp->b_rptr + ehlen + iphlen);
+ tcp_seq += mss;
+
+ ntcph->th_flags &= ~(TH_FIN | TH_PUSH | TH_RST | TH_URG);
+
+#ifdef __sparc
+ tcp_seq_tmp = htonl(tcp_seq);
+ bcopy(&tcp_seq_tmp, (char *)&ntcph->th_seq, 4);
+#else
+ ntcph->th_seq = htonl(tcp_seq);
+#endif
+ DB_CKSUMFLAGS(nmp) = (uint16_t)hckflags;
+ DB_CKSUMSTART(nmp) = start_offset;
+ DB_CKSUMSTUFF(nmp) = stuff_offset;
+
+ /* calculate IP checksum and TCP pseudo header checksum */
+ niph->ip_sum = 0;
+ niph->ip_sum = (uint16_t)nxge_csgen((uint16_t *)niph, iphlen);
+ ntcph->th_sum = (sum & 0xffff);
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_do_softlso: middle ip_sum 0x%x "
+ "th_sum 0x%x "
+ " mp $%p (mp_chain $%p) pktlen %d "
+ "MBLKL(mp): %d, MBLKL(datamp): %d ",
+ niph->ip_sum,
+ ntcph->th_sum,
+ nmp, mp_chain,
+ pktlen, (int)MBLKL(mp), (int)MBLKL(datamp)));
+ }
+
+ /* Last segment */
+ /*
+ * Set FIN and/or PSH flags if present only in the last packet.
+ * The ip_len could be different from prior packets.
+ */
+ bcopy(cmp->b_rptr, nmp->b_rptr, hdrlen);
+ nmp->b_wptr = nmp->b_rptr + hdrlen;
+ niph = (struct ip *)(nmp->b_rptr + ehlen);
+ niph->ip_id = htons(++ip_id);
+ niph->ip_len = htons(msgsize(nmp->b_cont) + iphlen + tcphlen);
+ ntcph = (struct tcphdr *)(nmp->b_rptr + ehlen + iphlen);
+ tcp_seq += mss;
+#ifdef __sparc
+ tcp_seq_tmp = htonl(tcp_seq);
+ bcopy(&tcp_seq_tmp, (char *)&ntcph->th_seq, 4);
+#else
+ ntcph->th_seq = htonl(tcp_seq);
+#endif
+ ntcph->th_flags = (otcph->th_flags & ~TH_URG);
+
+ DB_CKSUMFLAGS(nmp) = (uint16_t)hckflags;
+ DB_CKSUMSTART(nmp) = start_offset;
+ DB_CKSUMSTUFF(nmp) = stuff_offset;
+
+ /* calculate IP checksum and TCP pseudo header checksum */
+ niph->ip_sum = 0;
+ niph->ip_sum = (uint16_t)nxge_csgen((uint16_t *)niph, iphlen);
+
+ l4_len = ntohs(niph->ip_len) - iphlen;
+ sum = htons(l4_len) + l4cksum;
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ ntcph->th_sum = (sum & 0xffff);
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_do_softlso: last next "
+ "niph->ip_sum 0x%x "
+ "ntcph->th_sum 0x%x sum 0x%x "
+ "dump last ip->tcp %s "
+ "cmp $%p mp $%p (mp_chain $%p) pktlen %d (0x%x) "
+ "l4_len %d (0x%x) "
+ "MBLKL(mp): %d, MBLKL(datamp): %d ",
+ niph->ip_sum,
+ ntcph->th_sum, sum,
+ nxge_dump_packet((char *)niph, 52),
+ cmp, nmp, mp_chain,
+ pktlen, pktlen,
+ l4_len,
+ l4_len,
+ (int)MBLKL(mp), (int)MBLKL(datamp)));
+
+cleanup_allocated_msgs:
+ if (do_cleanup) {
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==> nxge_do_softlso: "
+ "Failed allocating messages, "
+ "have to clean up and fail!"));
+ while (mp_chain != NULL) {
+ nmp = mp_chain;
+ mp_chain = mp_chain->b_next;
+ freemsg(nmp);
+ }
+ }
+ /*
+ * We're done here, so just free the original message and return the
+ * new message chain, that could be NULL if failed, back to the caller.
+ */
+ freemsg(mp);
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "<== nxge_do_softlso:mp_chain $%p", mp_chain));
+ return (mp_chain);
+}
+
+/*
+ * Will be called before NIC driver do further operation on the message.
+ * The input message may include LSO information, if so, go to softlso logic
+ * to eliminate the oversized LSO packet for the incapable underlying h/w.
+ * The return could be the same non-LSO message or a message chain for LSO case.
+ *
+ * The driver needs to call this function per packet and process the whole chain
+ * if applied.
+ */
+static mblk_t *
+nxge_lso_eliminate(mblk_t *mp)
+{
+ uint32_t lsoflags;
+ uint32_t mss;
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==>nxge_lso_eliminate:"));
+ nxge_lso_info_get(mp, &mss, &lsoflags);
+
+ if (lsoflags & HW_LSO) {
+ mblk_t *nmp;
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "==>nxge_lso_eliminate:"
+ "HW_LSO:mss %d mp $%p",
+ mss, mp));
+ if ((nmp = nxge_do_softlso(mp, mss)) != NULL) {
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "<== nxge_lso_eliminate: "
+ "LSO: nmp not NULL nmp $%p mss %d mp $%p",
+ nmp, mss, mp));
+ return (nmp);
+ } else {
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "<== nxge_lso_eliminate_ "
+ "LSO: failed nmp NULL nmp $%p mss %d mp $%p",
+ nmp, mss, mp));
+ return (NULL);
+ }
+ }
+
+ NXGE_DEBUG_MSG((NULL, TX_CTL,
+ "<== nxge_lso_eliminate"));
+ return (mp);
+}
+
+static uint32_t
+nxge_csgen(uint16_t *adr, int len)
+{
+ int i, odd;
+ uint32_t sum = 0;
+ uint32_t c = 0;
+
+ odd = len % 2;
+ for (i = 0; i < (len / 2); i++) {
+ sum += (adr[i] & 0xffff);
+ }
+ if (odd) {
+ sum += adr[len / 2] & 0xff00;
+ }
+ while ((c = ((sum & 0xffff0000) >> 16)) != 0) {
+ sum &= 0xffff;
+ sum += c;
+ }
+ return (~sum & 0xffff);
+}
diff --git a/usr/src/uts/common/sys/nxge/nxge_common.h b/usr/src/uts/common/sys/nxge/nxge_common.h
index 46e3880409..fc4f4bf0f9 100644
--- a/usr/src/uts/common/sys/nxge/nxge_common.h
+++ b/usr/src/uts/common/sys/nxge/nxge_common.h
@@ -93,7 +93,7 @@ extern "C" {
#define NXGE_RCR_MIN (NXGE_RBR_RBB_MIN * 2)
#if defined(sun4v) && defined(NIU_LP_WORKAROUND)
-#define NXGE_RCR_MAX (NXGE_NIU_CONTIG_RCR_MAX)
+#define NXGE_RCR_MAX (8192)
#define NXGE_RCR_DEFAULT (512)
#define NXGE_TX_RING_DEFAULT (512)
#else
diff --git a/usr/src/uts/common/sys/nxge/nxge_defs.h b/usr/src/uts/common/sys/nxge/nxge_defs.h
index 60d4b26965..4b5feb7fcb 100644
--- a/usr/src/uts/common/sys/nxge/nxge_defs.h
+++ b/usr/src/uts/common/sys/nxge/nxge_defs.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -204,16 +204,18 @@ extern "C" {
/*
* Define the Default RBR, RCR
*/
-#define RBR_DEFAULT_MAX_BLKS 4096 /* each entry (16 blockaddr/64B) */
+#define RBR_DEFAULT_MAX_BLKS 8192 /* each entry (16 blockaddr/64B) */
#define RBR_NBLK_PER_LINE 16 /* 16 block addresses per 64 B line */
#define RBR_DEFAULT_MAX_LEN (RBR_DEFAULT_MAX_BLKS)
#define RBR_DEFAULT_MIN_LEN 1
+#define RCR_DEFAULT_MAX 8192
#define SW_OFFSET_NO_OFFSET 0
#define SW_OFFSET_64 1 /* 64 bytes */
#define SW_OFFSET_128 2 /* 128 bytes */
#define SW_OFFSET_INVALID 3
+#define TDC_DEFAULT_MAX 8192
/*
* RBR block descriptor is 32 bits (bits [43:12]
*/