108057504Sxy150489 /*
208057504Sxy150489 * This file is provided under a CDDLv1 license. When using or
308057504Sxy150489 * redistributing this file, you may do so under this license.
408057504Sxy150489 * In redistributing this file this license must be included
508057504Sxy150489 * and no other modification of this header file is permitted.
608057504Sxy150489 *
708057504Sxy150489 * CDDL LICENSE SUMMARY
808057504Sxy150489 *
9d5c3073dSchenlu chen - Sun Microsystems - Beijing China * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved.
1008057504Sxy150489 *
1108057504Sxy150489 * The contents of this file are subject to the terms of Version
1208057504Sxy150489 * 1.0 of the Common Development and Distribution License (the "License").
1308057504Sxy150489 *
1408057504Sxy150489 * You should have received a copy of the License with this software.
1508057504Sxy150489 * You can obtain a copy of the License at
1608057504Sxy150489 * http://www.opensolaris.org/os/licensing.
1708057504Sxy150489 * See the License for the specific language governing permissions
1808057504Sxy150489 * and limitations under the License.
1908057504Sxy150489 */
2008057504Sxy150489
2108057504Sxy150489 /*
220dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23da14cebeSEric Cheng * Use is subject to license terms.
2408057504Sxy150489 */
2508057504Sxy150489
2608057504Sxy150489 /*
27*7c5988f9SRobert Mustacchi * Copyright 2016 Joyent, Inc.
285c68564dSBryan Cantrill */
295c68564dSBryan Cantrill
305c68564dSBryan Cantrill /*
3108057504Sxy150489 * **********************************************************************
3208057504Sxy150489 * *
3308057504Sxy150489 * Module Name: *
3408057504Sxy150489 * e1000g_tx.c *
3508057504Sxy150489 * *
3608057504Sxy150489 * Abstract: *
3725f2d433Sxy150489 * This file contains some routines that take care of Transmit, *
3825f2d433Sxy150489 * make the hardware to send the data pointed by the packet out *
3925f2d433Sxy150489 * on to the physical medium. *
4008057504Sxy150489 * *
4108057504Sxy150489 * **********************************************************************
4208057504Sxy150489 */
4308057504Sxy150489
4408057504Sxy150489 #include "e1000g_sw.h"
4508057504Sxy150489 #include "e1000g_debug.h"
4608057504Sxy150489
4708057504Sxy150489 static boolean_t e1000g_send(struct e1000g *, mblk_t *);
4825f2d433Sxy150489 static int e1000g_tx_copy(e1000g_tx_ring_t *,
49c7770590Smx205022 p_tx_sw_packet_t, mblk_t *, boolean_t);
5025f2d433Sxy150489 static int e1000g_tx_bind(e1000g_tx_ring_t *,
5125f2d433Sxy150489 p_tx_sw_packet_t, mblk_t *);
524d737963Sxiangtao you - Sun Microsystems - Beijing China static boolean_t e1000g_retrieve_context(mblk_t *, context_data_t *, size_t);
53c7770590Smx205022 static boolean_t e1000g_check_context(e1000g_tx_ring_t *, context_data_t *);
5408057504Sxy150489 static int e1000g_fill_tx_ring(e1000g_tx_ring_t *, LIST_DESCRIBER *,
55c7770590Smx205022 context_data_t *);
56c7770590Smx205022 static void e1000g_fill_context_descriptor(context_data_t *,
5708057504Sxy150489 struct e1000_context_desc *);
5825f2d433Sxy150489 static int e1000g_fill_tx_desc(e1000g_tx_ring_t *,
5925f2d433Sxy150489 p_tx_sw_packet_t, uint64_t, size_t);
6008057504Sxy150489 static uint32_t e1000g_fill_82544_desc(uint64_t Address, size_t Length,
6125f2d433Sxy150489 p_desc_array_t desc_array);
6225f2d433Sxy150489 static int e1000g_tx_workaround_PCIX_82544(p_tx_sw_packet_t, uint64_t, size_t);
6325f2d433Sxy150489 static int e1000g_tx_workaround_jumbo_82544(p_tx_sw_packet_t, uint64_t, size_t);
6408057504Sxy150489 static void e1000g_82547_timeout(void *);
6508057504Sxy150489 static void e1000g_82547_tx_move_tail(e1000g_tx_ring_t *);
6608057504Sxy150489 static void e1000g_82547_tx_move_tail_work(e1000g_tx_ring_t *);
6708057504Sxy150489
6825f2d433Sxy150489 #ifndef E1000G_DEBUG
6908057504Sxy150489 #pragma inline(e1000g_tx_copy)
7008057504Sxy150489 #pragma inline(e1000g_tx_bind)
714d737963Sxiangtao you - Sun Microsystems - Beijing China #pragma inline(e1000g_retrieve_context)
72c7770590Smx205022 #pragma inline(e1000g_check_context)
7308057504Sxy150489 #pragma inline(e1000g_fill_tx_ring)
7408057504Sxy150489 #pragma inline(e1000g_fill_context_descriptor)
7508057504Sxy150489 #pragma inline(e1000g_fill_tx_desc)
7608057504Sxy150489 #pragma inline(e1000g_fill_82544_desc)
7708057504Sxy150489 #pragma inline(e1000g_tx_workaround_PCIX_82544)
7808057504Sxy150489 #pragma inline(e1000g_tx_workaround_jumbo_82544)
7925f2d433Sxy150489 #pragma inline(e1000g_free_tx_swpkt)
8008057504Sxy150489 #endif
8108057504Sxy150489
8208057504Sxy150489 /*
8325f2d433Sxy150489 * e1000g_free_tx_swpkt - free up the tx sw packet
8425f2d433Sxy150489 *
8525f2d433Sxy150489 * Unbind the previously bound DMA handle for a given
8625f2d433Sxy150489 * transmit sw packet. And reset the sw packet data.
8708057504Sxy150489 */
8808057504Sxy150489 void
e1000g_free_tx_swpkt(register p_tx_sw_packet_t packet)8925f2d433Sxy150489 e1000g_free_tx_swpkt(register p_tx_sw_packet_t packet)
9008057504Sxy150489 {
9108057504Sxy150489 switch (packet->data_transfer_type) {
9208057504Sxy150489 case USE_BCOPY:
9308057504Sxy150489 packet->tx_buf->len = 0;
9408057504Sxy150489 break;
9508057504Sxy150489 #ifdef __sparc
9608057504Sxy150489 case USE_DVMA:
9708057504Sxy150489 dvma_unload(packet->tx_dma_handle, 0, -1);
9808057504Sxy150489 break;
9908057504Sxy150489 #endif
10008057504Sxy150489 case USE_DMA:
101fe62dec3SChen-Liang Xu (void) ddi_dma_unbind_handle(packet->tx_dma_handle);
10208057504Sxy150489 break;
10308057504Sxy150489 default:
10408057504Sxy150489 break;
10508057504Sxy150489 }
10608057504Sxy150489
10708057504Sxy150489 /*
10808057504Sxy150489 * The mblk has been stripped off the sw packet
10908057504Sxy150489 * and will be freed in a triggered soft intr.
11008057504Sxy150489 */
11108057504Sxy150489 ASSERT(packet->mp == NULL);
11208057504Sxy150489
11308057504Sxy150489 packet->data_transfer_type = USE_NONE;
11408057504Sxy150489 packet->num_mblk_frag = 0;
11508057504Sxy150489 packet->num_desc = 0;
11608057504Sxy150489 }
11708057504Sxy150489
11808057504Sxy150489 mblk_t *
e1000g_m_tx(void * arg,mblk_t * mp)11908057504Sxy150489 e1000g_m_tx(void *arg, mblk_t *mp)
12008057504Sxy150489 {
12108057504Sxy150489 struct e1000g *Adapter = (struct e1000g *)arg;
12208057504Sxy150489 mblk_t *next;
12308057504Sxy150489
12408057504Sxy150489 rw_enter(&Adapter->chip_lock, RW_READER);
12508057504Sxy150489
126d5c3073dSchenlu chen - Sun Microsystems - Beijing China if ((Adapter->e1000g_state & E1000G_SUSPENDED) ||
127d5c3073dSchenlu chen - Sun Microsystems - Beijing China !(Adapter->e1000g_state & E1000G_STARTED) ||
1289b6541b3Sgl147354 (Adapter->link_state != LINK_STATE_UP)) {
12908057504Sxy150489 freemsgchain(mp);
13008057504Sxy150489 mp = NULL;
13108057504Sxy150489 }
13208057504Sxy150489
13308057504Sxy150489 while (mp != NULL) {
13408057504Sxy150489 next = mp->b_next;
13508057504Sxy150489 mp->b_next = NULL;
13608057504Sxy150489
13708057504Sxy150489 if (!e1000g_send(Adapter, mp)) {
13808057504Sxy150489 mp->b_next = next;
13908057504Sxy150489 break;
14008057504Sxy150489 }
14108057504Sxy150489
14208057504Sxy150489 mp = next;
14308057504Sxy150489 }
14408057504Sxy150489
14508057504Sxy150489 rw_exit(&Adapter->chip_lock);
14608057504Sxy150489 return (mp);
14708057504Sxy150489 }
14808057504Sxy150489
14908057504Sxy150489 /*
15025f2d433Sxy150489 * e1000g_send - send packets onto the wire
15125f2d433Sxy150489 *
15225f2d433Sxy150489 * Called from e1000g_m_tx with an mblk ready to send. this
15325f2d433Sxy150489 * routine sets up the transmit descriptors and sends data to
15425f2d433Sxy150489 * the wire. It also pushes the just transmitted packet to
15525f2d433Sxy150489 * the used tx sw packet list.
15608057504Sxy150489 */
15708057504Sxy150489 static boolean_t
e1000g_send(struct e1000g * Adapter,mblk_t * mp)15808057504Sxy150489 e1000g_send(struct e1000g *Adapter, mblk_t *mp)
15908057504Sxy150489 {
16025f2d433Sxy150489 p_tx_sw_packet_t packet;
16108057504Sxy150489 LIST_DESCRIBER pending_list;
16208057504Sxy150489 size_t len;
16308057504Sxy150489 size_t msg_size;
16408057504Sxy150489 uint32_t frag_count;
16508057504Sxy150489 int desc_count;
16608057504Sxy150489 uint32_t desc_total;
16743a17687SMiles Xu, Sun Microsystems uint32_t bcopy_thresh;
16843a17687SMiles Xu, Sun Microsystems uint32_t hdr_frag_len;
169c7770590Smx205022 boolean_t tx_undersize_flag;
17008057504Sxy150489 mblk_t *nmp;
17108057504Sxy150489 mblk_t *tmp;
17243a17687SMiles Xu, Sun Microsystems mblk_t *new_mp;
17343a17687SMiles Xu, Sun Microsystems mblk_t *pre_mp;
1741b5c080fSchangqing li - Sun Microsystems - Beijing China mblk_t *next_mp;
17508057504Sxy150489 e1000g_tx_ring_t *tx_ring;
176c7770590Smx205022 context_data_t cur_context;
17708057504Sxy150489
17825f2d433Sxy150489 tx_ring = Adapter->tx_ring;
17943a17687SMiles Xu, Sun Microsystems bcopy_thresh = Adapter->tx_bcopy_thresh;
18025f2d433Sxy150489
18108057504Sxy150489 /* Get the total size and frags number of the message */
182c7770590Smx205022 tx_undersize_flag = B_FALSE;
18308057504Sxy150489 frag_count = 0;
18408057504Sxy150489 msg_size = 0;
18508057504Sxy150489 for (nmp = mp; nmp; nmp = nmp->b_cont) {
18608057504Sxy150489 frag_count++;
18708057504Sxy150489 msg_size += MBLKL(nmp);
18808057504Sxy150489 }
18908057504Sxy150489
1904d737963Sxiangtao you - Sun Microsystems - Beijing China /* retrieve and compute information for context descriptor */
1914d737963Sxiangtao you - Sun Microsystems - Beijing China if (!e1000g_retrieve_context(mp, &cur_context, msg_size)) {
192c7770590Smx205022 freemsg(mp);
193c7770590Smx205022 return (B_TRUE);
194c7770590Smx205022 }
195c7770590Smx205022
196c7770590Smx205022 /*
197c7770590Smx205022 * Make sure the packet is less than the allowed size
198c7770590Smx205022 */
199c7770590Smx205022 if (!cur_context.lso_flag &&
200c7770590Smx205022 (msg_size > Adapter->max_frame_size - ETHERFCSL)) {
20108057504Sxy150489 /*
20208057504Sxy150489 * For the over size packet, we'll just drop it.
20308057504Sxy150489 * So we return B_TRUE here.
20408057504Sxy150489 */
20525f2d433Sxy150489 E1000G_DEBUGLOG_1(Adapter, E1000G_WARN_LEVEL,
20608057504Sxy150489 "Tx packet out of bound. length = %d \n", msg_size);
20725f2d433Sxy150489 E1000G_STAT(tx_ring->stat_over_size);
20808057504Sxy150489 freemsg(mp);
20908057504Sxy150489 return (B_TRUE);
21008057504Sxy150489 }
21108057504Sxy150489
21208057504Sxy150489 /*
21308057504Sxy150489 * Check and reclaim tx descriptors.
21408057504Sxy150489 * This low water mark check should be done all the time as
21508057504Sxy150489 * Transmit interrupt delay can produce Transmit interrupts little
21608057504Sxy150489 * late and that may cause few problems related to reaping Tx
21708057504Sxy150489 * Descriptors... As you may run short of them before getting any
21808057504Sxy150489 * transmit interrupt...
21908057504Sxy150489 */
220da14cebeSEric Cheng if (tx_ring->tbd_avail < DEFAULT_TX_NO_RESOURCE) {
22108057504Sxy150489 (void) e1000g_recycle(tx_ring);
22247b7744cSyy150190 E1000G_DEBUG_STAT(tx_ring->stat_recycle);
22308057504Sxy150489
22447b7744cSyy150190 if (tx_ring->tbd_avail < DEFAULT_TX_NO_RESOURCE) {
22525f2d433Sxy150489 E1000G_DEBUG_STAT(tx_ring->stat_lack_desc);
22608057504Sxy150489 goto tx_no_resource;
22708057504Sxy150489 }
22847b7744cSyy150190 }
22908057504Sxy150489
23008057504Sxy150489 /*
23108057504Sxy150489 * If the message size is less than the minimum ethernet packet size,
23208057504Sxy150489 * we'll use bcopy to send it, and padd it to 60 bytes later.
23308057504Sxy150489 */
2349ce7e93cScc210113 if (msg_size < ETHERMIN) {
23525f2d433Sxy150489 E1000G_DEBUG_STAT(tx_ring->stat_under_size);
236c7770590Smx205022 tx_undersize_flag = B_TRUE;
23708057504Sxy150489 }
23808057504Sxy150489
23908057504Sxy150489 /* Initialize variables */
24008057504Sxy150489 desc_count = 1; /* The initial value should be greater than 0 */
24108057504Sxy150489 desc_total = 0;
2421b5c080fSchangqing li - Sun Microsystems - Beijing China new_mp = NULL;
24308057504Sxy150489 QUEUE_INIT_LIST(&pending_list);
24408057504Sxy150489
24508057504Sxy150489 /* Process each mblk fragment and fill tx descriptors */
24643a17687SMiles Xu, Sun Microsystems /*
24743a17687SMiles Xu, Sun Microsystems * The software should guarantee LSO packet header(MAC+IP+TCP)
24843a17687SMiles Xu, Sun Microsystems * to be within one descriptor. Here we reallocate and refill the
24943a17687SMiles Xu, Sun Microsystems * the header if it's physical memory non-contiguous.
25043a17687SMiles Xu, Sun Microsystems */
25143a17687SMiles Xu, Sun Microsystems if (cur_context.lso_flag) {
25243a17687SMiles Xu, Sun Microsystems /* find the last fragment of the header */
25343a17687SMiles Xu, Sun Microsystems len = MBLKL(mp);
25443a17687SMiles Xu, Sun Microsystems ASSERT(len > 0);
2551b5c080fSchangqing li - Sun Microsystems - Beijing China next_mp = mp;
25643a17687SMiles Xu, Sun Microsystems pre_mp = NULL;
25743a17687SMiles Xu, Sun Microsystems while (len < cur_context.hdr_len) {
2581b5c080fSchangqing li - Sun Microsystems - Beijing China pre_mp = next_mp;
2591b5c080fSchangqing li - Sun Microsystems - Beijing China next_mp = next_mp->b_cont;
2601b5c080fSchangqing li - Sun Microsystems - Beijing China len += MBLKL(next_mp);
26143a17687SMiles Xu, Sun Microsystems }
26243a17687SMiles Xu, Sun Microsystems /*
26343a17687SMiles Xu, Sun Microsystems * If the header and the payload are in different mblks,
26443a17687SMiles Xu, Sun Microsystems * we simply force the header to be copied into pre-allocated
26543a17687SMiles Xu, Sun Microsystems * page-aligned buffer.
26643a17687SMiles Xu, Sun Microsystems */
26743a17687SMiles Xu, Sun Microsystems if (len == cur_context.hdr_len)
26843a17687SMiles Xu, Sun Microsystems goto adjust_threshold;
26943a17687SMiles Xu, Sun Microsystems
2701b5c080fSchangqing li - Sun Microsystems - Beijing China hdr_frag_len = cur_context.hdr_len - (len - MBLKL(next_mp));
27143a17687SMiles Xu, Sun Microsystems /*
27296ea4e93Schangqing li - Sun Microsystems - Beijing China * There are three cases we need to reallocate a mblk for the
27343a17687SMiles Xu, Sun Microsystems * last header fragment:
27496ea4e93Schangqing li - Sun Microsystems - Beijing China *
27543a17687SMiles Xu, Sun Microsystems * 1. the header is in multiple mblks and the last fragment
27643a17687SMiles Xu, Sun Microsystems * share the same mblk with the payload
27796ea4e93Schangqing li - Sun Microsystems - Beijing China *
27843a17687SMiles Xu, Sun Microsystems * 2. the header is in a single mblk shared with the payload
27943a17687SMiles Xu, Sun Microsystems * and the header is physical memory non-contiguous
28096ea4e93Schangqing li - Sun Microsystems - Beijing China *
28196ea4e93Schangqing li - Sun Microsystems - Beijing China * 3. there is 4 KB boundary within the header and 64 bytes
28296ea4e93Schangqing li - Sun Microsystems - Beijing China * following the end of the header bytes. The case may cause
28396ea4e93Schangqing li - Sun Microsystems - Beijing China * TCP data corruption issue.
28496ea4e93Schangqing li - Sun Microsystems - Beijing China *
28596ea4e93Schangqing li - Sun Microsystems - Beijing China * The workaround for the case #2 and case #3 is:
28696ea4e93Schangqing li - Sun Microsystems - Beijing China * Assuming standard Ethernet/IP/TCP headers of 54 bytes,
28796ea4e93Schangqing li - Sun Microsystems - Beijing China * this means that the buffer(containing the headers) should
28896ea4e93Schangqing li - Sun Microsystems - Beijing China * not start -118 bytes before a 4 KB boundary. For example,
28996ea4e93Schangqing li - Sun Microsystems - Beijing China * 128-byte alignment for this buffer could be used to fulfill
29096ea4e93Schangqing li - Sun Microsystems - Beijing China * this condition.
29143a17687SMiles Xu, Sun Microsystems */
2921b5c080fSchangqing li - Sun Microsystems - Beijing China if ((next_mp != mp) ||
29396ea4e93Schangqing li - Sun Microsystems - Beijing China (P2NPHASE((uintptr_t)next_mp->b_rptr,
29496ea4e93Schangqing li - Sun Microsystems - Beijing China E1000_LSO_FIRST_DESC_ALIGNMENT_BOUNDARY_4K)
29596ea4e93Schangqing li - Sun Microsystems - Beijing China < E1000_LSO_FIRST_DESC_ALIGNMENT)) {
29643a17687SMiles Xu, Sun Microsystems E1000G_DEBUG_STAT(tx_ring->stat_lso_header_fail);
29743a17687SMiles Xu, Sun Microsystems /*
29843a17687SMiles Xu, Sun Microsystems * reallocate the mblk for the last header fragment,
29943a17687SMiles Xu, Sun Microsystems * expect to bcopy into pre-allocated page-aligned
30043a17687SMiles Xu, Sun Microsystems * buffer
30143a17687SMiles Xu, Sun Microsystems */
30243a17687SMiles Xu, Sun Microsystems new_mp = allocb(hdr_frag_len, NULL);
30343a17687SMiles Xu, Sun Microsystems if (!new_mp)
30443a17687SMiles Xu, Sun Microsystems return (B_FALSE);
3051b5c080fSchangqing li - Sun Microsystems - Beijing China bcopy(next_mp->b_rptr, new_mp->b_rptr, hdr_frag_len);
30643a17687SMiles Xu, Sun Microsystems /* link the new header fragment with the other parts */
30743a17687SMiles Xu, Sun Microsystems new_mp->b_wptr = new_mp->b_rptr + hdr_frag_len;
3081b5c080fSchangqing li - Sun Microsystems - Beijing China new_mp->b_cont = next_mp;
30943a17687SMiles Xu, Sun Microsystems if (pre_mp)
31043a17687SMiles Xu, Sun Microsystems pre_mp->b_cont = new_mp;
31154e0d7a5SMiles Xu, Sun Microsystems else
31243a17687SMiles Xu, Sun Microsystems mp = new_mp;
3131b5c080fSchangqing li - Sun Microsystems - Beijing China next_mp->b_rptr += hdr_frag_len;
31443a17687SMiles Xu, Sun Microsystems frag_count++;
31543a17687SMiles Xu, Sun Microsystems }
31643a17687SMiles Xu, Sun Microsystems adjust_threshold:
31743a17687SMiles Xu, Sun Microsystems /*
31843a17687SMiles Xu, Sun Microsystems * adjust the bcopy threshhold to guarantee
31943a17687SMiles Xu, Sun Microsystems * the header to use bcopy way
32043a17687SMiles Xu, Sun Microsystems */
32143a17687SMiles Xu, Sun Microsystems if (bcopy_thresh < cur_context.hdr_len)
32243a17687SMiles Xu, Sun Microsystems bcopy_thresh = cur_context.hdr_len;
32343a17687SMiles Xu, Sun Microsystems }
32443a17687SMiles Xu, Sun Microsystems
32508057504Sxy150489 packet = NULL;
32608057504Sxy150489 nmp = mp;
32708057504Sxy150489 while (nmp) {
32808057504Sxy150489 tmp = nmp->b_cont;
32908057504Sxy150489
33008057504Sxy150489 len = MBLKL(nmp);
33108057504Sxy150489 /* Check zero length mblks */
33208057504Sxy150489 if (len == 0) {
33325f2d433Sxy150489 E1000G_DEBUG_STAT(tx_ring->stat_empty_frags);
33408057504Sxy150489 /*
33508057504Sxy150489 * If there're no packet buffers have been used,
33608057504Sxy150489 * or we just completed processing a buffer, then
33708057504Sxy150489 * skip the empty mblk fragment.
33808057504Sxy150489 * Otherwise, there's still a pending buffer that
33908057504Sxy150489 * needs to be processed (tx_copy).
34008057504Sxy150489 */
34108057504Sxy150489 if (desc_count > 0) {
34208057504Sxy150489 nmp = tmp;
34308057504Sxy150489 continue;
34408057504Sxy150489 }
34508057504Sxy150489 }
34608057504Sxy150489
34708057504Sxy150489 /*
34808057504Sxy150489 * Get a new TxSwPacket to process mblk buffers.
34908057504Sxy150489 */
35008057504Sxy150489 if (desc_count > 0) {
35108057504Sxy150489 mutex_enter(&tx_ring->freelist_lock);
35225f2d433Sxy150489 packet = (p_tx_sw_packet_t)
35308057504Sxy150489 QUEUE_POP_HEAD(&tx_ring->free_list);
35408057504Sxy150489 mutex_exit(&tx_ring->freelist_lock);
35508057504Sxy150489
35608057504Sxy150489 if (packet == NULL) {
35725f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
35808057504Sxy150489 "No Tx SwPacket available\n");
35925f2d433Sxy150489 E1000G_STAT(tx_ring->stat_no_swpkt);
36008057504Sxy150489 goto tx_send_failed;
36108057504Sxy150489 }
36208057504Sxy150489 QUEUE_PUSH_TAIL(&pending_list, &packet->Link);
36308057504Sxy150489 }
36408057504Sxy150489
36508057504Sxy150489 ASSERT(packet);
36608057504Sxy150489 /*
36708057504Sxy150489 * If the size of the fragment is less than the tx_bcopy_thresh
36808057504Sxy150489 * we'll use bcopy; Otherwise, we'll use DMA binding.
36908057504Sxy150489 */
37043a17687SMiles Xu, Sun Microsystems if ((len <= bcopy_thresh) || tx_undersize_flag) {
37108057504Sxy150489 desc_count =
372c7770590Smx205022 e1000g_tx_copy(tx_ring, packet, nmp,
373c7770590Smx205022 tx_undersize_flag);
37425f2d433Sxy150489 E1000G_DEBUG_STAT(tx_ring->stat_copy);
37508057504Sxy150489 } else {
37608057504Sxy150489 desc_count =
37725f2d433Sxy150489 e1000g_tx_bind(tx_ring, packet, nmp);
37825f2d433Sxy150489 E1000G_DEBUG_STAT(tx_ring->stat_bind);
37908057504Sxy150489 }
38008057504Sxy150489
38108057504Sxy150489 if (desc_count > 0)
38208057504Sxy150489 desc_total += desc_count;
38325f2d433Sxy150489 else if (desc_count < 0)
38425f2d433Sxy150489 goto tx_send_failed;
38508057504Sxy150489
38608057504Sxy150489 nmp = tmp;
38708057504Sxy150489 }
38808057504Sxy150489
38908057504Sxy150489 /* Assign the message to the last sw packet */
39008057504Sxy150489 ASSERT(packet);
39108057504Sxy150489 ASSERT(packet->mp == NULL);
39208057504Sxy150489 packet->mp = mp;
39308057504Sxy150489
39408057504Sxy150489 /* Try to recycle the tx descriptors again */
39596ea4e93Schangqing li - Sun Microsystems - Beijing China if (tx_ring->tbd_avail < (desc_total + 3)) {
39625f2d433Sxy150489 E1000G_DEBUG_STAT(tx_ring->stat_recycle_retry);
39708057504Sxy150489 (void) e1000g_recycle(tx_ring);
39808057504Sxy150489 }
39908057504Sxy150489
40008057504Sxy150489 mutex_enter(&tx_ring->tx_lock);
40108057504Sxy150489
40208057504Sxy150489 /*
40308057504Sxy150489 * If the number of available tx descriptors is not enough for transmit
40408057504Sxy150489 * (one redundant descriptor and one hw checksum context descriptor are
40508057504Sxy150489 * included), then return failure.
40608057504Sxy150489 */
40796ea4e93Schangqing li - Sun Microsystems - Beijing China if (tx_ring->tbd_avail < (desc_total + 3)) {
40825f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
40908057504Sxy150489 "No Enough Tx descriptors\n");
41025f2d433Sxy150489 E1000G_STAT(tx_ring->stat_no_desc);
41108057504Sxy150489 mutex_exit(&tx_ring->tx_lock);
41208057504Sxy150489 goto tx_send_failed;
41308057504Sxy150489 }
41408057504Sxy150489
415c7770590Smx205022 desc_count = e1000g_fill_tx_ring(tx_ring, &pending_list, &cur_context);
41608057504Sxy150489
41708057504Sxy150489 mutex_exit(&tx_ring->tx_lock);
41808057504Sxy150489
41908057504Sxy150489 ASSERT(desc_count > 0);
42008057504Sxy150489
42108057504Sxy150489 /* Send successful */
42208057504Sxy150489 return (B_TRUE);
42308057504Sxy150489
42408057504Sxy150489 tx_send_failed:
4251b5c080fSchangqing li - Sun Microsystems - Beijing China /* Restore mp to original */
4261b5c080fSchangqing li - Sun Microsystems - Beijing China if (new_mp) {
4271b5c080fSchangqing li - Sun Microsystems - Beijing China if (pre_mp) {
4281b5c080fSchangqing li - Sun Microsystems - Beijing China pre_mp->b_cont = next_mp;
4291b5c080fSchangqing li - Sun Microsystems - Beijing China }
4301b5c080fSchangqing li - Sun Microsystems - Beijing China new_mp->b_cont = NULL;
4311b5c080fSchangqing li - Sun Microsystems - Beijing China freemsg(new_mp);
4321b5c080fSchangqing li - Sun Microsystems - Beijing China
4331b5c080fSchangqing li - Sun Microsystems - Beijing China next_mp->b_rptr -= hdr_frag_len;
4341b5c080fSchangqing li - Sun Microsystems - Beijing China }
4351b5c080fSchangqing li - Sun Microsystems - Beijing China
43647b7744cSyy150190 /*
43747b7744cSyy150190 * Enable Transmit interrupts, so that the interrupt routine can
43847b7744cSyy150190 * call mac_tx_update() when transmit descriptors become available.
43947b7744cSyy150190 */
440da14cebeSEric Cheng tx_ring->resched_timestamp = ddi_get_lbolt();
44147b7744cSyy150190 tx_ring->resched_needed = B_TRUE;
44247b7744cSyy150190 if (!Adapter->tx_intr_enable)
44347b7744cSyy150190 e1000g_mask_tx_interrupt(Adapter);
44447b7744cSyy150190
44508057504Sxy150489 /* Free pending TxSwPackets */
44625f2d433Sxy150489 packet = (p_tx_sw_packet_t)QUEUE_GET_HEAD(&pending_list);
44708057504Sxy150489 while (packet) {
44808057504Sxy150489 packet->mp = NULL;
44925f2d433Sxy150489 e1000g_free_tx_swpkt(packet);
45025f2d433Sxy150489 packet = (p_tx_sw_packet_t)
45108057504Sxy150489 QUEUE_GET_NEXT(&pending_list, &packet->Link);
45208057504Sxy150489 }
45308057504Sxy150489
45408057504Sxy150489 /* Return pending TxSwPackets to the "Free" list */
45508057504Sxy150489 mutex_enter(&tx_ring->freelist_lock);
45608057504Sxy150489 QUEUE_APPEND(&tx_ring->free_list, &pending_list);
45708057504Sxy150489 mutex_exit(&tx_ring->freelist_lock);
45808057504Sxy150489
45925f2d433Sxy150489 E1000G_STAT(tx_ring->stat_send_fail);
46008057504Sxy150489
46147b7744cSyy150190 /* Message will be scheduled for re-transmit */
46247b7744cSyy150190 return (B_FALSE);
46308057504Sxy150489
46408057504Sxy150489 tx_no_resource:
46508057504Sxy150489 /*
46608057504Sxy150489 * Enable Transmit interrupts, so that the interrupt routine can
46708057504Sxy150489 * call mac_tx_update() when transmit descriptors become available.
46808057504Sxy150489 */
469da14cebeSEric Cheng tx_ring->resched_timestamp = ddi_get_lbolt();
47025f2d433Sxy150489 tx_ring->resched_needed = B_TRUE;
47108057504Sxy150489 if (!Adapter->tx_intr_enable)
47225f2d433Sxy150489 e1000g_mask_tx_interrupt(Adapter);
47308057504Sxy150489
47408057504Sxy150489 /* Message will be scheduled for re-transmit */
47508057504Sxy150489 return (B_FALSE);
47608057504Sxy150489 }
47708057504Sxy150489
4787941757cSxy150489 static boolean_t
e1000g_retrieve_context(mblk_t * mp,context_data_t * cur_context,size_t msg_size)4794d737963Sxiangtao you - Sun Microsystems - Beijing China e1000g_retrieve_context(mblk_t *mp, context_data_t *cur_context,
480c7770590Smx205022 size_t msg_size)
4817941757cSxy150489 {
482c7770590Smx205022 uintptr_t ip_start;
483c7770590Smx205022 uintptr_t tcp_start;
484c7770590Smx205022 mblk_t *nmp;
485da14cebeSEric Cheng uint32_t lsoflags;
486da14cebeSEric Cheng uint32_t mss;
4877941757cSxy150489
488c7770590Smx205022 bzero(cur_context, sizeof (context_data_t));
4897941757cSxy150489
490da14cebeSEric Cheng /* first check lso information */
4910dc2366fSVenugopal Iyer mac_lso_get(mp, &mss, &lsoflags);
492da14cebeSEric Cheng
493c7770590Smx205022 /* retrieve checksum info */
4940dc2366fSVenugopal Iyer mac_hcksum_get(mp, &cur_context->cksum_start,
495c7770590Smx205022 &cur_context->cksum_stuff, NULL, NULL, &cur_context->cksum_flags);
4964d737963Sxiangtao you - Sun Microsystems - Beijing China /* retrieve ethernet header size */
497fe62dec3SChen-Liang Xu if (((struct ether_vlan_header *)(uintptr_t)mp->b_rptr)->ether_tpid ==
498c7770590Smx205022 htons(ETHERTYPE_VLAN))
499c7770590Smx205022 cur_context->ether_header_size =
500c7770590Smx205022 sizeof (struct ether_vlan_header);
501c7770590Smx205022 else
502c7770590Smx205022 cur_context->ether_header_size =
503c7770590Smx205022 sizeof (struct ether_header);
5047941757cSxy150489
505da14cebeSEric Cheng if (lsoflags & HW_LSO) {
506da14cebeSEric Cheng ASSERT(mss != 0);
507da14cebeSEric Cheng
508da14cebeSEric Cheng /* free the invalid packet */
509da14cebeSEric Cheng if (mss == 0 ||
510da14cebeSEric Cheng !((cur_context->cksum_flags & HCK_PARTIALCKSUM) &&
511c7770590Smx205022 (cur_context->cksum_flags & HCK_IPV4_HDRCKSUM))) {
512c7770590Smx205022 return (B_FALSE);
513c7770590Smx205022 }
514da14cebeSEric Cheng cur_context->mss = (uint16_t)mss;
515c7770590Smx205022 cur_context->lso_flag = B_TRUE;
516da14cebeSEric Cheng
517c7770590Smx205022 /*
518c7770590Smx205022 * Some fields are cleared for the hardware to fill
519c7770590Smx205022 * in. We don't assume Ethernet header, IP header and
520c7770590Smx205022 * TCP header are always in the same mblk fragment,
521c7770590Smx205022 * while we assume each header is always within one
522c7770590Smx205022 * mblk fragment and Ethernet header is always in the
523c7770590Smx205022 * first mblk fragment.
524c7770590Smx205022 */
525c7770590Smx205022 nmp = mp;
526c7770590Smx205022 ip_start = (uintptr_t)(nmp->b_rptr)
527c7770590Smx205022 + cur_context->ether_header_size;
528c7770590Smx205022 if (ip_start >= (uintptr_t)(nmp->b_wptr)) {
529c7770590Smx205022 ip_start = (uintptr_t)nmp->b_cont->b_rptr
530c7770590Smx205022 + (ip_start - (uintptr_t)(nmp->b_wptr));
531c7770590Smx205022 nmp = nmp->b_cont;
532c7770590Smx205022 }
533c7770590Smx205022 tcp_start = ip_start +
534c7770590Smx205022 IPH_HDR_LENGTH((ipha_t *)ip_start);
535c7770590Smx205022 if (tcp_start >= (uintptr_t)(nmp->b_wptr)) {
536c7770590Smx205022 tcp_start = (uintptr_t)nmp->b_cont->b_rptr
537c7770590Smx205022 + (tcp_start - (uintptr_t)(nmp->b_wptr));
538c7770590Smx205022 nmp = nmp->b_cont;
539c7770590Smx205022 }
540c7770590Smx205022 cur_context->hdr_len = cur_context->ether_header_size
541c7770590Smx205022 + IPH_HDR_LENGTH((ipha_t *)ip_start)
542c7770590Smx205022 + TCP_HDR_LENGTH((tcph_t *)tcp_start);
543c7770590Smx205022 ((ipha_t *)ip_start)->ipha_length = 0;
544c7770590Smx205022 ((ipha_t *)ip_start)->ipha_hdr_checksum = 0;
545c7770590Smx205022 /* calculate the TCP packet payload length */
546c7770590Smx205022 cur_context->pay_len = msg_size - cur_context->hdr_len;
547c7770590Smx205022 }
548c7770590Smx205022 return (B_TRUE);
549c7770590Smx205022 }
550c7770590Smx205022
551c7770590Smx205022 static boolean_t
e1000g_check_context(e1000g_tx_ring_t * tx_ring,context_data_t * cur_context)552c7770590Smx205022 e1000g_check_context(e1000g_tx_ring_t *tx_ring, context_data_t *cur_context)
553c7770590Smx205022 {
554c7770590Smx205022 boolean_t context_reload;
555c7770590Smx205022 context_data_t *pre_context;
556c7770590Smx205022 struct e1000g *Adapter;
557c7770590Smx205022
558c7770590Smx205022 context_reload = B_FALSE;
559c7770590Smx205022 pre_context = &tx_ring->pre_context;
560c7770590Smx205022 Adapter = tx_ring->adapter;
561c7770590Smx205022
562c7770590Smx205022 /*
563c7770590Smx205022 * The following code determine if the context descriptor is
564c7770590Smx205022 * needed to be reloaded. The sequence of the conditions is
565c7770590Smx205022 * made by their possibilities of changing.
566c7770590Smx205022 */
567c7770590Smx205022 /*
568c7770590Smx205022 * workaround for 82546EB, context descriptor must be reloaded
569c7770590Smx205022 * per LSO/hw_cksum packet if LSO is enabled.
570c7770590Smx205022 */
571c7770590Smx205022 if (Adapter->lso_premature_issue &&
572c7770590Smx205022 Adapter->lso_enable &&
573c7770590Smx205022 (cur_context->cksum_flags != 0)) {
574c7770590Smx205022
575c7770590Smx205022 context_reload = B_TRUE;
576c7770590Smx205022 } else if (cur_context->lso_flag) {
57743a17687SMiles Xu, Sun Microsystems if ((cur_context->lso_flag != pre_context->lso_flag) ||
57843a17687SMiles Xu, Sun Microsystems (cur_context->cksum_flags != pre_context->cksum_flags) ||
579c7770590Smx205022 (cur_context->pay_len != pre_context->pay_len) ||
580c7770590Smx205022 (cur_context->mss != pre_context->mss) ||
581c7770590Smx205022 (cur_context->hdr_len != pre_context->hdr_len) ||
582c7770590Smx205022 (cur_context->cksum_stuff != pre_context->cksum_stuff) ||
583c7770590Smx205022 (cur_context->cksum_start != pre_context->cksum_start) ||
584c7770590Smx205022 (cur_context->ether_header_size !=
585c7770590Smx205022 pre_context->ether_header_size)) {
586c7770590Smx205022
587c7770590Smx205022 context_reload = B_TRUE;
588c7770590Smx205022 }
589c7770590Smx205022 } else if (cur_context->cksum_flags != 0) {
59043a17687SMiles Xu, Sun Microsystems if ((cur_context->lso_flag != pre_context->lso_flag) ||
59143a17687SMiles Xu, Sun Microsystems (cur_context->cksum_flags != pre_context->cksum_flags) ||
592c7770590Smx205022 (cur_context->cksum_stuff != pre_context->cksum_stuff) ||
593c7770590Smx205022 (cur_context->cksum_start != pre_context->cksum_start) ||
594c7770590Smx205022 (cur_context->ether_header_size !=
595c7770590Smx205022 pre_context->ether_header_size)) {
596c7770590Smx205022
597c7770590Smx205022 context_reload = B_TRUE;
5987941757cSxy150489 }
5997941757cSxy150489 }
6007941757cSxy150489
601c7770590Smx205022 return (context_reload);
6027941757cSxy150489 }
6037941757cSxy150489
60408057504Sxy150489 static int
e1000g_fill_tx_ring(e1000g_tx_ring_t * tx_ring,LIST_DESCRIBER * pending_list,context_data_t * cur_context)60508057504Sxy150489 e1000g_fill_tx_ring(e1000g_tx_ring_t *tx_ring, LIST_DESCRIBER *pending_list,
606c7770590Smx205022 context_data_t *cur_context)
60708057504Sxy150489 {
60808057504Sxy150489 struct e1000g *Adapter;
60925f2d433Sxy150489 struct e1000_hw *hw;
61025f2d433Sxy150489 p_tx_sw_packet_t first_packet;
61125f2d433Sxy150489 p_tx_sw_packet_t packet;
612c7770590Smx205022 p_tx_sw_packet_t previous_packet;
613c7770590Smx205022 boolean_t context_reload;
61408057504Sxy150489 struct e1000_tx_desc *first_data_desc;
61508057504Sxy150489 struct e1000_tx_desc *next_desc;
61608057504Sxy150489 struct e1000_tx_desc *descriptor;
6175c68564dSBryan Cantrill struct e1000_data_desc zeroed;
61808057504Sxy150489 int desc_count;
619c7770590Smx205022 boolean_t buff_overrun_flag;
62008057504Sxy150489 int i;
62108057504Sxy150489
62208057504Sxy150489 Adapter = tx_ring->adapter;
62325f2d433Sxy150489 hw = &Adapter->shared;
62408057504Sxy150489
62508057504Sxy150489 desc_count = 0;
6267941757cSxy150489 first_packet = NULL;
62708057504Sxy150489 first_data_desc = NULL;
62808057504Sxy150489 descriptor = NULL;
629c7770590Smx205022 first_packet = NULL;
630c7770590Smx205022 packet = NULL;
631c7770590Smx205022 buff_overrun_flag = B_FALSE;
6325c68564dSBryan Cantrill zeroed.upper.data = 0;
63308057504Sxy150489
63408057504Sxy150489 next_desc = tx_ring->tbd_next;
63508057504Sxy150489
636c7770590Smx205022 /* Context descriptor reload check */
637c7770590Smx205022 context_reload = e1000g_check_context(tx_ring, cur_context);
6387941757cSxy150489
639c7770590Smx205022 if (context_reload) {
64025f2d433Sxy150489 first_packet = (p_tx_sw_packet_t)QUEUE_GET_HEAD(pending_list);
6417941757cSxy150489
64208057504Sxy150489 descriptor = next_desc;
64308057504Sxy150489
644c7770590Smx205022 e1000g_fill_context_descriptor(cur_context,
6457941757cSxy150489 (struct e1000_context_desc *)descriptor);
64608057504Sxy150489
64708057504Sxy150489 /* Check the wrap-around case */
64808057504Sxy150489 if (descriptor == tx_ring->tbd_last)
64908057504Sxy150489 next_desc = tx_ring->tbd_first;
65008057504Sxy150489 else
65108057504Sxy150489 next_desc++;
65208057504Sxy150489
65308057504Sxy150489 desc_count++;
65408057504Sxy150489 }
65508057504Sxy150489
65608057504Sxy150489 first_data_desc = next_desc;
65708057504Sxy150489
6585c68564dSBryan Cantrill /*
6595c68564dSBryan Cantrill * According to the documentation, the packet options field (POPTS) is
6605c68564dSBryan Cantrill * "ignored except on the first data descriptor of a packet." However,
6615c68564dSBryan Cantrill * there is a bug in QEMU (638955) whereby the POPTS field within a
6625c68564dSBryan Cantrill * given data descriptor is used to interpret that data descriptor --
6635c68564dSBryan Cantrill * regardless of whether or not the descriptor is the first in a packet
6645c68564dSBryan Cantrill * or not. For a packet that spans multiple descriptors, the (virtual)
6655c68564dSBryan Cantrill * HW checksum (either TCP/UDP or IP or both) will therefore _not_ be
6665c68564dSBryan Cantrill * performed on descriptors after the first, resulting in incorrect
6675c68564dSBryan Cantrill * checksums and mysteriously dropped/retransmitted packets. Other
6685c68564dSBryan Cantrill * drivers do not have this issue because they (harmlessly) set the
6695c68564dSBryan Cantrill * POPTS field on every data descriptor to be the intended options for
6705c68564dSBryan Cantrill * the entire packet. To circumvent this QEMU bug, we engage in this
6715c68564dSBryan Cantrill * same behavior iff the subsystem vendor and device IDs indicate that
6725c68564dSBryan Cantrill * this is an emulated QEMU device (1af4,1100).
6735c68564dSBryan Cantrill */
6745c68564dSBryan Cantrill if (hw->subsystem_vendor_id == 0x1af4 &&
6755c68564dSBryan Cantrill hw->subsystem_device_id == 0x1100 &&
6765c68564dSBryan Cantrill cur_context->cksum_flags) {
6775c68564dSBryan Cantrill if (cur_context->cksum_flags & HCK_IPV4_HDRCKSUM)
6785c68564dSBryan Cantrill zeroed.upper.fields.popts |= E1000_TXD_POPTS_IXSM;
6795c68564dSBryan Cantrill
6805c68564dSBryan Cantrill if (cur_context->cksum_flags & HCK_PARTIALCKSUM)
6815c68564dSBryan Cantrill zeroed.upper.fields.popts |= E1000_TXD_POPTS_TXSM;
6825c68564dSBryan Cantrill }
6835c68564dSBryan Cantrill
68425f2d433Sxy150489 packet = (p_tx_sw_packet_t)QUEUE_GET_HEAD(pending_list);
68508057504Sxy150489 while (packet) {
68608057504Sxy150489 ASSERT(packet->num_desc);
68708057504Sxy150489
68808057504Sxy150489 for (i = 0; i < packet->num_desc; i++) {
68925f2d433Sxy150489 ASSERT(tx_ring->tbd_avail > 0);
69008057504Sxy150489
69108057504Sxy150489 descriptor = next_desc;
69208057504Sxy150489 descriptor->buffer_addr =
69325f2d433Sxy150489 packet->desc[i].address;
69408057504Sxy150489 descriptor->lower.data =
69525f2d433Sxy150489 packet->desc[i].length;
69608057504Sxy150489
69708057504Sxy150489 /* Zero out status */
6985c68564dSBryan Cantrill descriptor->upper.data = zeroed.upper.data;
69908057504Sxy150489
70008057504Sxy150489 descriptor->lower.data |=
70108057504Sxy150489 E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
70208057504Sxy150489 /* must set RS on every outgoing descriptor */
70308057504Sxy150489 descriptor->lower.data |=
70408057504Sxy150489 E1000_TXD_CMD_RS;
70508057504Sxy150489
706c7770590Smx205022 if (cur_context->lso_flag)
707c7770590Smx205022 descriptor->lower.data |= E1000_TXD_CMD_TSE;
708c7770590Smx205022
70908057504Sxy150489 /* Check the wrap-around case */
71008057504Sxy150489 if (descriptor == tx_ring->tbd_last)
71108057504Sxy150489 next_desc = tx_ring->tbd_first;
71208057504Sxy150489 else
71308057504Sxy150489 next_desc++;
71408057504Sxy150489
71508057504Sxy150489 desc_count++;
716c7770590Smx205022
717c7770590Smx205022 /*
718c7770590Smx205022 * workaround for 82546EB errata 33, hang in PCI-X
719c7770590Smx205022 * systems due to 2k Buffer Overrun during Transmit
720c7770590Smx205022 * Operation. The workaround applies to all the Intel
721c7770590Smx205022 * PCI-X chips.
722c7770590Smx205022 */
723c7770590Smx205022 if (hw->bus.type == e1000_bus_type_pcix &&
724c7770590Smx205022 descriptor == first_data_desc &&
725c7770590Smx205022 ((descriptor->lower.data & E1000G_TBD_LENGTH_MASK)
726c7770590Smx205022 > E1000_TX_BUFFER_OEVRRUN_THRESHOLD)) {
727c7770590Smx205022 /* modified the first descriptor */
728c7770590Smx205022 descriptor->lower.data &=
729c7770590Smx205022 ~E1000G_TBD_LENGTH_MASK;
730c7770590Smx205022 descriptor->lower.flags.length =
731c7770590Smx205022 E1000_TX_BUFFER_OEVRRUN_THRESHOLD;
732c7770590Smx205022
733c7770590Smx205022 /* insert a new descriptor */
734c7770590Smx205022 ASSERT(tx_ring->tbd_avail > 0);
735c7770590Smx205022 next_desc->buffer_addr =
736c7770590Smx205022 packet->desc[0].address +
737c7770590Smx205022 E1000_TX_BUFFER_OEVRRUN_THRESHOLD;
738c7770590Smx205022 next_desc->lower.data =
739c7770590Smx205022 packet->desc[0].length -
740c7770590Smx205022 E1000_TX_BUFFER_OEVRRUN_THRESHOLD;
741c7770590Smx205022
742c7770590Smx205022 /* Zero out status */
7435c68564dSBryan Cantrill next_desc->upper.data = zeroed.upper.data;
744c7770590Smx205022
745c7770590Smx205022 next_desc->lower.data |=
746c7770590Smx205022 E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
747c7770590Smx205022 /* must set RS on every outgoing descriptor */
748c7770590Smx205022 next_desc->lower.data |=
749c7770590Smx205022 E1000_TXD_CMD_RS;
750c7770590Smx205022
751c7770590Smx205022 if (cur_context->lso_flag)
752c7770590Smx205022 next_desc->lower.data |=
753c7770590Smx205022 E1000_TXD_CMD_TSE;
754c7770590Smx205022
755c7770590Smx205022 descriptor = next_desc;
756c7770590Smx205022
757c7770590Smx205022 /* Check the wrap-around case */
758c7770590Smx205022 if (next_desc == tx_ring->tbd_last)
759c7770590Smx205022 next_desc = tx_ring->tbd_first;
760c7770590Smx205022 else
761c7770590Smx205022 next_desc++;
762c7770590Smx205022
763c7770590Smx205022 desc_count++;
764c7770590Smx205022 buff_overrun_flag = B_TRUE;
765c7770590Smx205022 }
766c7770590Smx205022 }
767c7770590Smx205022
768c7770590Smx205022 if (buff_overrun_flag) {
769c7770590Smx205022 packet->num_desc++;
770c7770590Smx205022 buff_overrun_flag = B_FALSE;
77108057504Sxy150489 }
77208057504Sxy150489
77308057504Sxy150489 if (first_packet != NULL) {
77408057504Sxy150489 /*
77508057504Sxy150489 * Count the checksum context descriptor for
77608057504Sxy150489 * the first SwPacket.
77708057504Sxy150489 */
77808057504Sxy150489 first_packet->num_desc++;
77908057504Sxy150489 first_packet = NULL;
78008057504Sxy150489 }
78108057504Sxy150489
782d3d50737SRafael Vanoni packet->tickstamp = ddi_get_lbolt64();
78354e0d7a5SMiles Xu, Sun Microsystems
784c7770590Smx205022 previous_packet = packet;
78525f2d433Sxy150489 packet = (p_tx_sw_packet_t)
78608057504Sxy150489 QUEUE_GET_NEXT(pending_list, &packet->Link);
78708057504Sxy150489 }
78808057504Sxy150489
789c7770590Smx205022 /*
790c7770590Smx205022 * workaround for 82546EB errata 21, LSO Premature Descriptor Write Back
791c7770590Smx205022 */
792c7770590Smx205022 if (Adapter->lso_premature_issue && cur_context->lso_flag &&
793c7770590Smx205022 ((descriptor->lower.data & E1000G_TBD_LENGTH_MASK) > 8)) {
794c7770590Smx205022 /* modified the previous descriptor */
795c7770590Smx205022 descriptor->lower.data -= 4;
796c7770590Smx205022
797c7770590Smx205022 /* insert a new descriptor */
798c7770590Smx205022 ASSERT(tx_ring->tbd_avail > 0);
799c7770590Smx205022 /* the lower 20 bits of lower.data is the length field */
800c7770590Smx205022 next_desc->buffer_addr =
801c7770590Smx205022 descriptor->buffer_addr +
802c7770590Smx205022 (descriptor->lower.data & E1000G_TBD_LENGTH_MASK);
803c7770590Smx205022 next_desc->lower.data = 4;
804c7770590Smx205022
805c7770590Smx205022 /* Zero out status */
8065c68564dSBryan Cantrill next_desc->upper.data = zeroed.upper.data;
807c7770590Smx205022 /* It must be part of a LSO packet */
808c7770590Smx205022 next_desc->lower.data |=
809c7770590Smx205022 E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D |
810c7770590Smx205022 E1000_TXD_CMD_RS | E1000_TXD_CMD_TSE;
811c7770590Smx205022
812c7770590Smx205022 descriptor = next_desc;
813c7770590Smx205022
814c7770590Smx205022 /* Check the wrap-around case */
815c7770590Smx205022 if (descriptor == tx_ring->tbd_last)
816c7770590Smx205022 next_desc = tx_ring->tbd_first;
817c7770590Smx205022 else
818c7770590Smx205022 next_desc++;
819c7770590Smx205022
820c7770590Smx205022 desc_count++;
821c7770590Smx205022 /* update the number of descriptors */
822c7770590Smx205022 previous_packet->num_desc++;
823c7770590Smx205022 }
824c7770590Smx205022
82508057504Sxy150489 ASSERT(descriptor);
82608057504Sxy150489
827c7770590Smx205022 if (cur_context->cksum_flags) {
828c7770590Smx205022 if (cur_context->cksum_flags & HCK_IPV4_HDRCKSUM)
82908057504Sxy150489 ((struct e1000_data_desc *)first_data_desc)->
83008057504Sxy150489 upper.fields.popts |= E1000_TXD_POPTS_IXSM;
831c7770590Smx205022 if (cur_context->cksum_flags & HCK_PARTIALCKSUM)
83208057504Sxy150489 ((struct e1000_data_desc *)first_data_desc)->
83308057504Sxy150489 upper.fields.popts |= E1000_TXD_POPTS_TXSM;
83408057504Sxy150489 }
83508057504Sxy150489
83608057504Sxy150489 /*
83708057504Sxy150489 * Last Descriptor of Packet needs End Of Packet (EOP), Report
838c7770590Smx205022 * Status (RS) set.
83908057504Sxy150489 */
84025f2d433Sxy150489 if (Adapter->tx_intr_delay) {
84108057504Sxy150489 descriptor->lower.data |= E1000_TXD_CMD_IDE |
842c7770590Smx205022 E1000_TXD_CMD_EOP;
84308057504Sxy150489 } else {
844c7770590Smx205022 descriptor->lower.data |= E1000_TXD_CMD_EOP;
845c7770590Smx205022 }
846c7770590Smx205022
847c7770590Smx205022 /* Set append Ethernet CRC (IFCS) bits */
848c7770590Smx205022 if (cur_context->lso_flag) {
849c7770590Smx205022 first_data_desc->lower.data |= E1000_TXD_CMD_IFCS;
850c7770590Smx205022 } else {
851c7770590Smx205022 descriptor->lower.data |= E1000_TXD_CMD_IFCS;
85208057504Sxy150489 }
85308057504Sxy150489
85408057504Sxy150489 /*
85508057504Sxy150489 * Sync the Tx descriptors DMA buffer
85608057504Sxy150489 */
85708057504Sxy150489 (void) ddi_dma_sync(tx_ring->tbd_dma_handle,
85825f2d433Sxy150489 0, 0, DDI_DMA_SYNC_FORDEV);
85908057504Sxy150489
86008057504Sxy150489 tx_ring->tbd_next = next_desc;
86108057504Sxy150489
86208057504Sxy150489 /*
86308057504Sxy150489 * Advance the Transmit Descriptor Tail (Tdt), this tells the
86408057504Sxy150489 * FX1000 that this frame is available to transmit.
86508057504Sxy150489 */
86625f2d433Sxy150489 if (hw->mac.type == e1000_82547)
86708057504Sxy150489 e1000g_82547_tx_move_tail(tx_ring);
86808057504Sxy150489 else
869592a4d85Scc210113 E1000_WRITE_REG(hw, E1000_TDT(0),
87008057504Sxy150489 (uint32_t)(next_desc - tx_ring->tbd_first));
87108057504Sxy150489
8729b6541b3Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
8739b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
874d5c3073dSchenlu chen - Sun Microsystems - Beijing China Adapter->e1000g_state |= E1000G_ERROR;
8759b6541b3Sgl147354 }
8769b6541b3Sgl147354
87708057504Sxy150489 /* Put the pending SwPackets to the "Used" list */
87808057504Sxy150489 mutex_enter(&tx_ring->usedlist_lock);
87908057504Sxy150489 QUEUE_APPEND(&tx_ring->used_list, pending_list);
88025f2d433Sxy150489 tx_ring->tbd_avail -= desc_count;
88108057504Sxy150489 mutex_exit(&tx_ring->usedlist_lock);
88208057504Sxy150489
883c7770590Smx205022 /* update LSO related data */
884c7770590Smx205022 if (context_reload)
885c7770590Smx205022 tx_ring->pre_context = *cur_context;
8867941757cSxy150489
88708057504Sxy150489 return (desc_count);
88808057504Sxy150489 }
88908057504Sxy150489
89008057504Sxy150489 /*
89125f2d433Sxy150489 * e1000g_tx_setup - setup tx data structures
89225f2d433Sxy150489 *
89325f2d433Sxy150489 * This routine initializes all of the transmit related
89425f2d433Sxy150489 * structures. This includes the Transmit descriptors,
89525f2d433Sxy150489 * and the tx_sw_packet structures.
89608057504Sxy150489 */
89708057504Sxy150489 void
e1000g_tx_setup(struct e1000g * Adapter)89825f2d433Sxy150489 e1000g_tx_setup(struct e1000g *Adapter)
89908057504Sxy150489 {
90008057504Sxy150489 struct e1000_hw *hw;
90125f2d433Sxy150489 p_tx_sw_packet_t packet;
9024d737963Sxiangtao you - Sun Microsystems - Beijing China uint32_t i;
90308057504Sxy150489 uint32_t buf_high;
90408057504Sxy150489 uint32_t buf_low;
90508057504Sxy150489 uint32_t reg_tipg;
90608057504Sxy150489 uint32_t reg_tctl;
90708057504Sxy150489 int size;
90808057504Sxy150489 e1000g_tx_ring_t *tx_ring;
90908057504Sxy150489
91025f2d433Sxy150489 hw = &Adapter->shared;
91108057504Sxy150489 tx_ring = Adapter->tx_ring;
91208057504Sxy150489
91308057504Sxy150489 /* init the lists */
91408057504Sxy150489 /*
91508057504Sxy150489 * Here we don't need to protect the lists using the
91625f2d433Sxy150489 * usedlist_lock and freelist_lock, for they have
91708057504Sxy150489 * been protected by the chip_lock.
91808057504Sxy150489 */
91908057504Sxy150489 QUEUE_INIT_LIST(&tx_ring->used_list);
92008057504Sxy150489 QUEUE_INIT_LIST(&tx_ring->free_list);
92108057504Sxy150489
92208057504Sxy150489 /* Go through and set up each SW_Packet */
92308057504Sxy150489 packet = tx_ring->packet_area;
92425f2d433Sxy150489 for (i = 0; i < Adapter->tx_freelist_num; i++, packet++) {
92525f2d433Sxy150489 /* Initialize this tx_sw_apcket area */
92625f2d433Sxy150489 e1000g_free_tx_swpkt(packet);
92725f2d433Sxy150489 /* Add this tx_sw_packet to the free list */
92808057504Sxy150489 QUEUE_PUSH_TAIL(&tx_ring->free_list,
92908057504Sxy150489 &packet->Link);
93008057504Sxy150489 }
93108057504Sxy150489
93208057504Sxy150489 /* Setup TX descriptor pointers */
93308057504Sxy150489 tx_ring->tbd_next = tx_ring->tbd_first;
93408057504Sxy150489 tx_ring->tbd_oldest = tx_ring->tbd_first;
93508057504Sxy150489
93608057504Sxy150489 /*
93708057504Sxy150489 * Setup Hardware TX Registers
93808057504Sxy150489 */
93908057504Sxy150489 /* Setup the Transmit Control Register (TCTL). */
940a2e9a830Scc210113 reg_tctl = E1000_READ_REG(hw, E1000_TCTL);
941a2e9a830Scc210113 reg_tctl |= E1000_TCTL_PSP | E1000_TCTL_EN |
94208057504Sxy150489 (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT) |
94325f2d433Sxy150489 (E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT) |
94425f2d433Sxy150489 E1000_TCTL_RTLC;
94508057504Sxy150489
94608057504Sxy150489 /* Enable the MULR bit */
94725f2d433Sxy150489 if (hw->bus.type == e1000_bus_type_pci_express)
94808057504Sxy150489 reg_tctl |= E1000_TCTL_MULR;
94908057504Sxy150489
95025f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_TCTL, reg_tctl);
95108057504Sxy150489
95208057504Sxy150489 /* Setup HW Base and Length of Tx descriptor area */
95325f2d433Sxy150489 size = (Adapter->tx_desc_num * sizeof (struct e1000_tx_desc));
954592a4d85Scc210113 E1000_WRITE_REG(hw, E1000_TDLEN(0), size);
955592a4d85Scc210113 size = E1000_READ_REG(hw, E1000_TDLEN(0));
95608057504Sxy150489
95708057504Sxy150489 buf_low = (uint32_t)tx_ring->tbd_dma_addr;
95808057504Sxy150489 buf_high = (uint32_t)(tx_ring->tbd_dma_addr >> 32);
95908057504Sxy150489
960ede5269eSchenlu chen - Sun Microsystems - Beijing China /*
961ede5269eSchenlu chen - Sun Microsystems - Beijing China * Write the highest location first and work backward to the lowest.
962ede5269eSchenlu chen - Sun Microsystems - Beijing China * This is necessary for some adapter types to
963ede5269eSchenlu chen - Sun Microsystems - Beijing China * prevent write combining from occurring.
964ede5269eSchenlu chen - Sun Microsystems - Beijing China */
965592a4d85Scc210113 E1000_WRITE_REG(hw, E1000_TDBAH(0), buf_high);
966ede5269eSchenlu chen - Sun Microsystems - Beijing China E1000_WRITE_REG(hw, E1000_TDBAL(0), buf_low);
96708057504Sxy150489
96808057504Sxy150489 /* Setup our HW Tx Head & Tail descriptor pointers */
969592a4d85Scc210113 E1000_WRITE_REG(hw, E1000_TDH(0), 0);
970592a4d85Scc210113 E1000_WRITE_REG(hw, E1000_TDT(0), 0);
97108057504Sxy150489
97208057504Sxy150489 /* Set the default values for the Tx Inter Packet Gap timer */
97325f2d433Sxy150489 if ((hw->mac.type == e1000_82542) &&
97425f2d433Sxy150489 ((hw->revision_id == E1000_REVISION_2) ||
97525f2d433Sxy150489 (hw->revision_id == E1000_REVISION_3))) {
97608057504Sxy150489 reg_tipg = DEFAULT_82542_TIPG_IPGT;
97708057504Sxy150489 reg_tipg |=
97808057504Sxy150489 DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
97908057504Sxy150489 reg_tipg |=
98008057504Sxy150489 DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
981a2e9a830Scc210113 } else if (hw->mac.type == e1000_80003es2lan) {
982a2e9a830Scc210113 reg_tipg = DEFAULT_82543_TIPG_IPGR1;
98335ae85e6Scc210113 reg_tipg |= DEFAULT_80003ES2LAN_TIPG_IPGR2 <<
984a2e9a830Scc210113 E1000_TIPG_IPGR2_SHIFT;
98525f2d433Sxy150489 } else {
986592a4d85Scc210113 if (hw->phy.media_type == e1000_media_type_fiber)
98708057504Sxy150489 reg_tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
98808057504Sxy150489 else
98908057504Sxy150489 reg_tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
99008057504Sxy150489 reg_tipg |=
99108057504Sxy150489 DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
99208057504Sxy150489 reg_tipg |=
99308057504Sxy150489 DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
99408057504Sxy150489 }
99525f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_TIPG, reg_tipg);
99608057504Sxy150489
99708057504Sxy150489 /* Setup Transmit Interrupt Delay Value */
99825f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_TIDV, Adapter->tx_intr_delay);
99947b7744cSyy150190 E1000G_DEBUGLOG_1(Adapter, E1000G_INFO_LEVEL,
100047b7744cSyy150190 "E1000_TIDV: 0x%x\n", Adapter->tx_intr_delay);
100147b7744cSyy150190
100247b7744cSyy150190 if (hw->mac.type >= e1000_82540) {
100347b7744cSyy150190 E1000_WRITE_REG(&Adapter->shared, E1000_TADV,
100447b7744cSyy150190 Adapter->tx_intr_abs_delay);
100547b7744cSyy150190 E1000G_DEBUGLOG_1(Adapter, E1000G_INFO_LEVEL,
100647b7744cSyy150190 "E1000_TADV: 0x%x\n", Adapter->tx_intr_abs_delay);
100708057504Sxy150489 }
100808057504Sxy150489
100925f2d433Sxy150489 tx_ring->tbd_avail = Adapter->tx_desc_num;
101025f2d433Sxy150489
1011c7770590Smx205022 /* Initialize stored context information */
1012c7770590Smx205022 bzero(&(tx_ring->pre_context), sizeof (context_data_t));
101308057504Sxy150489 }
101408057504Sxy150489
101508057504Sxy150489 /*
101625f2d433Sxy150489 * e1000g_recycle - recycle the tx descriptors and tx sw packets
101708057504Sxy150489 */
101808057504Sxy150489 int
e1000g_recycle(e1000g_tx_ring_t * tx_ring)101908057504Sxy150489 e1000g_recycle(e1000g_tx_ring_t *tx_ring)
102008057504Sxy150489 {
102108057504Sxy150489 struct e1000g *Adapter;
102208057504Sxy150489 LIST_DESCRIBER pending_list;
102325f2d433Sxy150489 p_tx_sw_packet_t packet;
102408057504Sxy150489 mblk_t *mp;
102508057504Sxy150489 mblk_t *nmp;
102608057504Sxy150489 struct e1000_tx_desc *descriptor;
102708057504Sxy150489 int desc_count;
102854e0d7a5SMiles Xu, Sun Microsystems int64_t delta;
102908057504Sxy150489
103008057504Sxy150489 /*
103108057504Sxy150489 * This function will examine each TxSwPacket in the 'used' queue
103208057504Sxy150489 * if the e1000g is done with it then the associated resources (Tx
103308057504Sxy150489 * Descriptors) will be "freed" and the TxSwPacket will be
103408057504Sxy150489 * returned to the 'free' queue.
103508057504Sxy150489 */
103608057504Sxy150489 Adapter = tx_ring->adapter;
103754e0d7a5SMiles Xu, Sun Microsystems delta = 0;
103808057504Sxy150489
103925f2d433Sxy150489 packet = (p_tx_sw_packet_t)QUEUE_GET_HEAD(&tx_ring->used_list);
104008057504Sxy150489 if (packet == NULL) {
104154e0d7a5SMiles Xu, Sun Microsystems Adapter->stall_flag = B_FALSE;
104208057504Sxy150489 return (0);
104308057504Sxy150489 }
104408057504Sxy150489
104547b7744cSyy150190 desc_count = 0;
104647b7744cSyy150190 QUEUE_INIT_LIST(&pending_list);
104747b7744cSyy150190
104825f2d433Sxy150489 /* Sync the Tx descriptor DMA buffer */
104925f2d433Sxy150489 (void) ddi_dma_sync(tx_ring->tbd_dma_handle,
105025f2d433Sxy150489 0, 0, DDI_DMA_SYNC_FORKERNEL);
10519b6541b3Sgl147354 if (e1000g_check_dma_handle(
10529b6541b3Sgl147354 tx_ring->tbd_dma_handle) != DDI_FM_OK) {
10539b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
1054d5c3073dSchenlu chen - Sun Microsystems - Beijing China Adapter->e1000g_state |= E1000G_ERROR;
10559b6541b3Sgl147354 return (0);
10569b6541b3Sgl147354 }
105725f2d433Sxy150489
105808057504Sxy150489 /*
105908057504Sxy150489 * While there are still TxSwPackets in the used queue check them
106008057504Sxy150489 */
1061da14cebeSEric Cheng mutex_enter(&tx_ring->usedlist_lock);
1062fe62dec3SChen-Liang Xu while ((packet =
1063fe62dec3SChen-Liang Xu (p_tx_sw_packet_t)QUEUE_GET_HEAD(&tx_ring->used_list)) != NULL) {
106408057504Sxy150489
106508057504Sxy150489 /*
106608057504Sxy150489 * Get hold of the next descriptor that the e1000g will
106708057504Sxy150489 * report status back to (this will be the last descriptor
106825f2d433Sxy150489 * of a given sw packet). We only want to free the
106925f2d433Sxy150489 * sw packet (and it resources) if the e1000g is done
107008057504Sxy150489 * with ALL of the descriptors. If the e1000g is done
107108057504Sxy150489 * with the last one then it is done with all of them.
107208057504Sxy150489 */
107308057504Sxy150489 ASSERT(packet->num_desc);
107425f2d433Sxy150489 descriptor = tx_ring->tbd_oldest + (packet->num_desc - 1);
107508057504Sxy150489
107608057504Sxy150489 /* Check for wrap case */
107708057504Sxy150489 if (descriptor > tx_ring->tbd_last)
107825f2d433Sxy150489 descriptor -= Adapter->tx_desc_num;
107908057504Sxy150489
108008057504Sxy150489 /*
108108057504Sxy150489 * If the descriptor done bit is set free TxSwPacket and
108208057504Sxy150489 * associated resources
108308057504Sxy150489 */
108408057504Sxy150489 if (descriptor->upper.fields.status & E1000_TXD_STAT_DD) {
108508057504Sxy150489 QUEUE_POP_HEAD(&tx_ring->used_list);
108608057504Sxy150489 QUEUE_PUSH_TAIL(&pending_list, &packet->Link);
108708057504Sxy150489
108808057504Sxy150489 if (descriptor == tx_ring->tbd_last)
108908057504Sxy150489 tx_ring->tbd_oldest =
109008057504Sxy150489 tx_ring->tbd_first;
109108057504Sxy150489 else
109208057504Sxy150489 tx_ring->tbd_oldest =
109308057504Sxy150489 descriptor + 1;
109408057504Sxy150489
109508057504Sxy150489 desc_count += packet->num_desc;
109608057504Sxy150489 } else {
109708057504Sxy150489 /*
109825f2d433Sxy150489 * Found a sw packet that the e1000g is not done
109908057504Sxy150489 * with then there is no reason to check the rest
110008057504Sxy150489 * of the queue.
110108057504Sxy150489 */
1102d3d50737SRafael Vanoni delta = ddi_get_lbolt64() - packet->tickstamp;
110308057504Sxy150489 break;
110408057504Sxy150489 }
110508057504Sxy150489 }
110608057504Sxy150489
110725f2d433Sxy150489 tx_ring->tbd_avail += desc_count;
110847b7744cSyy150190 Adapter->tx_pkt_cnt += desc_count;
110925f2d433Sxy150489
111008057504Sxy150489 mutex_exit(&tx_ring->usedlist_lock);
111108057504Sxy150489
111208057504Sxy150489 if (desc_count == 0) {
111325f2d433Sxy150489 E1000G_DEBUG_STAT(tx_ring->stat_recycle_none);
111454e0d7a5SMiles Xu, Sun Microsystems /*
11155f0b6ff9Sguoqing zhu - Sun Microsystems - Beijing China * If the packet hasn't been sent out for seconds and
11165f0b6ff9Sguoqing zhu - Sun Microsystems - Beijing China * the transmitter is not under paused flowctrl condition,
111754e0d7a5SMiles Xu, Sun Microsystems * the transmitter is considered to be stalled.
111854e0d7a5SMiles Xu, Sun Microsystems */
11195f0b6ff9Sguoqing zhu - Sun Microsystems - Beijing China if ((delta > Adapter->stall_threshold) &&
11205f0b6ff9Sguoqing zhu - Sun Microsystems - Beijing China !(E1000_READ_REG(&Adapter->shared,
11215f0b6ff9Sguoqing zhu - Sun Microsystems - Beijing China E1000_STATUS) & E1000_STATUS_TXOFF)) {
112254e0d7a5SMiles Xu, Sun Microsystems Adapter->stall_flag = B_TRUE;
112354e0d7a5SMiles Xu, Sun Microsystems }
112408057504Sxy150489 return (0);
112508057504Sxy150489 }
112608057504Sxy150489
112754e0d7a5SMiles Xu, Sun Microsystems Adapter->stall_flag = B_FALSE;
112808057504Sxy150489
112908057504Sxy150489 mp = NULL;
113008057504Sxy150489 nmp = NULL;
113125f2d433Sxy150489 packet = (p_tx_sw_packet_t)QUEUE_GET_HEAD(&pending_list);
113208057504Sxy150489 ASSERT(packet != NULL);
113308057504Sxy150489 while (packet != NULL) {
113408057504Sxy150489 if (packet->mp != NULL) {
113508057504Sxy150489 ASSERT(packet->mp->b_next == NULL);
113608057504Sxy150489 /* Assemble the message chain */
113708057504Sxy150489 if (mp == NULL) {
113808057504Sxy150489 mp = packet->mp;
113908057504Sxy150489 nmp = packet->mp;
114008057504Sxy150489 } else {
114108057504Sxy150489 nmp->b_next = packet->mp;
114208057504Sxy150489 nmp = packet->mp;
114308057504Sxy150489 }
114408057504Sxy150489 /* Disconnect the message from the sw packet */
114508057504Sxy150489 packet->mp = NULL;
114608057504Sxy150489 }
114708057504Sxy150489
114808057504Sxy150489 /* Free the TxSwPackets */
114925f2d433Sxy150489 e1000g_free_tx_swpkt(packet);
115008057504Sxy150489
115125f2d433Sxy150489 packet = (p_tx_sw_packet_t)
115208057504Sxy150489 QUEUE_GET_NEXT(&pending_list, &packet->Link);
115308057504Sxy150489 }
115408057504Sxy150489
115508057504Sxy150489 /* Return the TxSwPackets back to the FreeList */
115608057504Sxy150489 mutex_enter(&tx_ring->freelist_lock);
115708057504Sxy150489 QUEUE_APPEND(&tx_ring->free_list, &pending_list);
115808057504Sxy150489 mutex_exit(&tx_ring->freelist_lock);
115908057504Sxy150489
116047b7744cSyy150190 if (mp != NULL)
116147b7744cSyy150190 freemsgchain(mp);
116247b7744cSyy150190
116308057504Sxy150489 return (desc_count);
116408057504Sxy150489 }
116508057504Sxy150489 /*
116608057504Sxy150489 * 82544 Coexistence issue workaround:
116708057504Sxy150489 * There are 2 issues.
116808057504Sxy150489 * 1. If a 32 bit split completion happens from P64H2 and another
116908057504Sxy150489 * agent drives a 64 bit request/split completion after ONLY
117008057504Sxy150489 * 1 idle clock (BRCM/Emulex/Adaptec fiber channel cards) then
117108057504Sxy150489 * 82544 has a problem where in to clock all the data in, it
117208057504Sxy150489 * looks at REQ64# signal and since it has changed so fast (i.e. 1
117308057504Sxy150489 * idle clock turn around), it will fail to clock all the data in.
117408057504Sxy150489 * Data coming from certain ending addresses has exposure to this issue.
117508057504Sxy150489 *
117608057504Sxy150489 * To detect this issue, following equation can be used...
117708057504Sxy150489 * SIZE[3:0] + ADDR[2:0] = SUM[3:0].
117808057504Sxy150489 * If SUM[3:0] is in between 1 to 4, we will have this issue.
117908057504Sxy150489 *
118008057504Sxy150489 * ROOT CAUSE:
118108057504Sxy150489 * The erratum involves the 82544 PCIX elasticity FIFO implementations as
118208057504Sxy150489 * 64-bit FIFO's and flushing of the final partial-bytes corresponding
118308057504Sxy150489 * to the end of a requested read burst. Under a specific burst condition
118408057504Sxy150489 * of ending-data alignment and 32-byte split-completions, the final
118508057504Sxy150489 * byte(s) of split-completion data require an extra clock cycle to flush
118608057504Sxy150489 * into 64-bit FIFO orientation. An incorrect logic dependency on the
118708057504Sxy150489 * REQ64# signal occurring during during this clock cycle may cause the
118808057504Sxy150489 * residual byte(s) to be lost, thereby rendering the internal DMA client
118908057504Sxy150489 * forever awaiting the final byte(s) for an outbound data-fetch. The
119008057504Sxy150489 * erratum is confirmed to *only* occur if certain subsequent external
119108057504Sxy150489 * 64-bit PCIX bus transactions occur immediately (minimum possible bus
119208057504Sxy150489 * turn- around) following the odd-aligned 32-bit split-completion
119308057504Sxy150489 * containing the final byte(s). Intel has confirmed that this has been
119408057504Sxy150489 * seen only with chipset/bridges which have the capability to provide
119508057504Sxy150489 * 32-bit split-completion data, and in the presence of newer PCIX bus
119608057504Sxy150489 * agents which fully-optimize the inter-transaction turn-around (zero
119708057504Sxy150489 * additional initiator latency when pre-granted bus ownership).
119808057504Sxy150489 *
119908057504Sxy150489 * This issue does not exist in PCI bus mode, when any agent is operating
120008057504Sxy150489 * in 32 bit only mode or on chipsets that do not do 32 bit split
120108057504Sxy150489 * completions for 64 bit read requests (Serverworks chipsets). P64H2 does
120208057504Sxy150489 * 32 bit split completions for any read request that has bit 2 set to 1
120308057504Sxy150489 * for the requested address and read request size is more than 8 bytes.
120408057504Sxy150489 *
120508057504Sxy150489 * 2. Another issue is related to 82544 driving DACs under the similar
120608057504Sxy150489 * scenario (32 bit split completion followed by 64 bit transaction with
120708057504Sxy150489 * only 1 cycle turnaround). This issue is still being root caused. We
120808057504Sxy150489 * think that both of these issues can be avoided if following workaround
120908057504Sxy150489 * is implemented. It seems DAC issues is related to ending addresses being
121008057504Sxy150489 * 0x9, 0xA, 0xB, 0xC and hence ending up at odd boundaries in elasticity
121108057504Sxy150489 * FIFO which does not get flushed due to REQ64# dependency. We will only
121208057504Sxy150489 * know the full story after it has been simulated successfully by HW team.
121308057504Sxy150489 *
121408057504Sxy150489 * WORKAROUND:
121508057504Sxy150489 * Make sure we do not have ending address as 1,2,3,4(Hang) or 9,a,b,c(DAC)
121608057504Sxy150489 */
121708057504Sxy150489 static uint32_t
e1000g_fill_82544_desc(uint64_t address,size_t length,p_desc_array_t desc_array)121825f2d433Sxy150489 e1000g_fill_82544_desc(uint64_t address,
121925f2d433Sxy150489 size_t length, p_desc_array_t desc_array)
122008057504Sxy150489 {
122108057504Sxy150489 /*
122208057504Sxy150489 * Since issue is sensitive to length and address.
122308057504Sxy150489 * Let us first check the address...
122408057504Sxy150489 */
122508057504Sxy150489 uint32_t safe_terminator;
122608057504Sxy150489
122725f2d433Sxy150489 if (length <= 4) {
122825f2d433Sxy150489 desc_array->descriptor[0].address = address;
1229fe62dec3SChen-Liang Xu desc_array->descriptor[0].length = (uint32_t)length;
123025f2d433Sxy150489 desc_array->elements = 1;
123125f2d433Sxy150489 return (desc_array->elements);
123208057504Sxy150489 }
123308057504Sxy150489 safe_terminator =
123425f2d433Sxy150489 (uint32_t)((((uint32_t)address & 0x7) +
123525f2d433Sxy150489 (length & 0xF)) & 0xF);
123608057504Sxy150489 /*
123708057504Sxy150489 * if it does not fall between 0x1 to 0x4 and 0x9 to 0xC then
123808057504Sxy150489 * return
123908057504Sxy150489 */
124008057504Sxy150489 if (safe_terminator == 0 ||
124125f2d433Sxy150489 (safe_terminator > 4 && safe_terminator < 9) ||
124208057504Sxy150489 (safe_terminator > 0xC && safe_terminator <= 0xF)) {
124325f2d433Sxy150489 desc_array->descriptor[0].address = address;
1244fe62dec3SChen-Liang Xu desc_array->descriptor[0].length = (uint32_t)length;
124525f2d433Sxy150489 desc_array->elements = 1;
124625f2d433Sxy150489 return (desc_array->elements);
124708057504Sxy150489 }
124808057504Sxy150489
124925f2d433Sxy150489 desc_array->descriptor[0].address = address;
125025f2d433Sxy150489 desc_array->descriptor[0].length = length - 4;
125125f2d433Sxy150489 desc_array->descriptor[1].address = address + (length - 4);
125225f2d433Sxy150489 desc_array->descriptor[1].length = 4;
125325f2d433Sxy150489 desc_array->elements = 2;
125425f2d433Sxy150489 return (desc_array->elements);
125508057504Sxy150489 }
125608057504Sxy150489
125708057504Sxy150489 static int
e1000g_tx_copy(e1000g_tx_ring_t * tx_ring,p_tx_sw_packet_t packet,mblk_t * mp,boolean_t tx_undersize_flag)125825f2d433Sxy150489 e1000g_tx_copy(e1000g_tx_ring_t *tx_ring, p_tx_sw_packet_t packet,
1259c7770590Smx205022 mblk_t *mp, boolean_t tx_undersize_flag)
126008057504Sxy150489 {
126108057504Sxy150489 size_t len;
126208057504Sxy150489 size_t len1;
126308057504Sxy150489 dma_buffer_t *tx_buf;
126408057504Sxy150489 mblk_t *nmp;
126508057504Sxy150489 boolean_t finished;
126608057504Sxy150489 int desc_count;
126708057504Sxy150489
126808057504Sxy150489 desc_count = 0;
126908057504Sxy150489 tx_buf = packet->tx_buf;
127008057504Sxy150489 len = MBLKL(mp);
127108057504Sxy150489
127208057504Sxy150489 ASSERT((tx_buf->len + len) <= tx_buf->size);
127308057504Sxy150489
127408057504Sxy150489 if (len > 0) {
127508057504Sxy150489 bcopy(mp->b_rptr,
127608057504Sxy150489 tx_buf->address + tx_buf->len,
127708057504Sxy150489 len);
127808057504Sxy150489 tx_buf->len += len;
127908057504Sxy150489
128008057504Sxy150489 packet->num_mblk_frag++;
128108057504Sxy150489 }
128208057504Sxy150489
128308057504Sxy150489 nmp = mp->b_cont;
128408057504Sxy150489 if (nmp == NULL) {
128508057504Sxy150489 finished = B_TRUE;
128608057504Sxy150489 } else {
128708057504Sxy150489 len1 = MBLKL(nmp);
128808057504Sxy150489 if ((tx_buf->len + len1) > tx_buf->size)
128908057504Sxy150489 finished = B_TRUE;
1290c7770590Smx205022 else if (tx_undersize_flag)
129108057504Sxy150489 finished = B_FALSE;
129225f2d433Sxy150489 else if (len1 > tx_ring->adapter->tx_bcopy_thresh)
129308057504Sxy150489 finished = B_TRUE;
129408057504Sxy150489 else
129508057504Sxy150489 finished = B_FALSE;
129608057504Sxy150489 }
129708057504Sxy150489
129808057504Sxy150489 if (finished) {
129925f2d433Sxy150489 E1000G_DEBUG_STAT_COND(tx_ring->stat_multi_copy,
130025f2d433Sxy150489 (tx_buf->len > len));
130108057504Sxy150489
130208057504Sxy150489 /*
130308057504Sxy150489 * If the packet is smaller than 64 bytes, which is the
130408057504Sxy150489 * minimum ethernet packet size, pad the packet to make
130508057504Sxy150489 * it at least 60 bytes. The hardware will add 4 bytes
130608057504Sxy150489 * for CRC.
130708057504Sxy150489 */
1308c7770590Smx205022 if (tx_undersize_flag) {
13099ce7e93cScc210113 ASSERT(tx_buf->len < ETHERMIN);
131008057504Sxy150489
131108057504Sxy150489 bzero(tx_buf->address + tx_buf->len,
13129ce7e93cScc210113 ETHERMIN - tx_buf->len);
13139ce7e93cScc210113 tx_buf->len = ETHERMIN;
131408057504Sxy150489 }
131508057504Sxy150489
131608057504Sxy150489 #ifdef __sparc
131725f2d433Sxy150489 if (packet->dma_type == USE_DVMA)
131808057504Sxy150489 dvma_sync(tx_buf->dma_handle, 0, DDI_DMA_SYNC_FORDEV);
131925f2d433Sxy150489 else
132008057504Sxy150489 (void) ddi_dma_sync(tx_buf->dma_handle, 0,
132108057504Sxy150489 tx_buf->len, DDI_DMA_SYNC_FORDEV);
132225f2d433Sxy150489 #else
132325f2d433Sxy150489 (void) ddi_dma_sync(tx_buf->dma_handle, 0,
132425f2d433Sxy150489 tx_buf->len, DDI_DMA_SYNC_FORDEV);
132525f2d433Sxy150489 #endif
132608057504Sxy150489
132708057504Sxy150489 packet->data_transfer_type = USE_BCOPY;
132808057504Sxy150489
132925f2d433Sxy150489 desc_count = e1000g_fill_tx_desc(tx_ring,
133008057504Sxy150489 packet,
133108057504Sxy150489 tx_buf->dma_address,
133208057504Sxy150489 tx_buf->len);
133308057504Sxy150489
133408057504Sxy150489 if (desc_count <= 0)
133508057504Sxy150489 return (-1);
133608057504Sxy150489 }
133708057504Sxy150489
133808057504Sxy150489 return (desc_count);
133908057504Sxy150489 }
134008057504Sxy150489
134108057504Sxy150489 static int
e1000g_tx_bind(e1000g_tx_ring_t * tx_ring,p_tx_sw_packet_t packet,mblk_t * mp)134225f2d433Sxy150489 e1000g_tx_bind(e1000g_tx_ring_t *tx_ring, p_tx_sw_packet_t packet, mblk_t *mp)
134308057504Sxy150489 {
134408057504Sxy150489 int j;
134508057504Sxy150489 int mystat;
134608057504Sxy150489 size_t len;
134708057504Sxy150489 ddi_dma_cookie_t dma_cookie;
134808057504Sxy150489 uint_t ncookies;
134908057504Sxy150489 int desc_count;
135008057504Sxy150489 uint32_t desc_total;
135108057504Sxy150489
135208057504Sxy150489 desc_total = 0;
135308057504Sxy150489 len = MBLKL(mp);
135408057504Sxy150489
135508057504Sxy150489 /*
135608057504Sxy150489 * ddi_dma_addr_bind_handle() allocates DMA resources for a
135708057504Sxy150489 * memory object such that a device can perform DMA to or from
135808057504Sxy150489 * the object. DMA resources are allocated considering the
135908057504Sxy150489 * device's DMA attributes as expressed by ddi_dma_attr(9S)
136008057504Sxy150489 * (see ddi_dma_alloc_handle(9F)).
136108057504Sxy150489 *
136208057504Sxy150489 * ddi_dma_addr_bind_handle() fills in the first DMA cookie
136308057504Sxy150489 * pointed to by cookiep with the appropriate address, length,
136408057504Sxy150489 * and bus type. *ccountp is set to the number of DMA cookies
136508057504Sxy150489 * representing this DMA object. Subsequent DMA cookies must be
136608057504Sxy150489 * retrieved by calling ddi_dma_nextcookie(9F) the number of
136708057504Sxy150489 * times specified by *countp - 1.
136808057504Sxy150489 */
136908057504Sxy150489 switch (packet->dma_type) {
137008057504Sxy150489 #ifdef __sparc
137108057504Sxy150489 case USE_DVMA:
137208057504Sxy150489 dvma_kaddr_load(packet->tx_dma_handle,
137308057504Sxy150489 (caddr_t)mp->b_rptr, len, 0, &dma_cookie);
137408057504Sxy150489
137508057504Sxy150489 dvma_sync(packet->tx_dma_handle, 0,
137608057504Sxy150489 DDI_DMA_SYNC_FORDEV);
137708057504Sxy150489
137808057504Sxy150489 ncookies = 1;
137908057504Sxy150489 packet->data_transfer_type = USE_DVMA;
138008057504Sxy150489 break;
138108057504Sxy150489 #endif
138208057504Sxy150489 case USE_DMA:
138308057504Sxy150489 if ((mystat = ddi_dma_addr_bind_handle(
138408057504Sxy150489 packet->tx_dma_handle, NULL,
138508057504Sxy150489 (caddr_t)mp->b_rptr, len,
138608057504Sxy150489 DDI_DMA_WRITE | DDI_DMA_STREAMING,
138708057504Sxy150489 DDI_DMA_DONTWAIT, 0, &dma_cookie,
138808057504Sxy150489 &ncookies)) != DDI_DMA_MAPPED) {
138908057504Sxy150489
139025f2d433Sxy150489 e1000g_log(tx_ring->adapter, CE_WARN,
139108057504Sxy150489 "Couldn't bind mblk buffer to Tx DMA handle: "
139208057504Sxy150489 "return: %X, Pkt: %X\n",
139308057504Sxy150489 mystat, packet);
139408057504Sxy150489 return (-1);
139508057504Sxy150489 }
139608057504Sxy150489
139708057504Sxy150489 /*
139808057504Sxy150489 * An implicit ddi_dma_sync() is done when the
139908057504Sxy150489 * ddi_dma_addr_bind_handle() is called. So we
140008057504Sxy150489 * don't need to explicitly call ddi_dma_sync()
140108057504Sxy150489 * here any more.
140208057504Sxy150489 */
140308057504Sxy150489 ASSERT(ncookies);
140425f2d433Sxy150489 E1000G_DEBUG_STAT_COND(tx_ring->stat_multi_cookie,
140525f2d433Sxy150489 (ncookies > 1));
140608057504Sxy150489
140708057504Sxy150489 /*
140808057504Sxy150489 * The data_transfer_type value must be set after the handle
140925f2d433Sxy150489 * has been bound, for it will be used in e1000g_free_tx_swpkt()
141008057504Sxy150489 * to decide whether we need to unbind the handle.
141108057504Sxy150489 */
141208057504Sxy150489 packet->data_transfer_type = USE_DMA;
141308057504Sxy150489 break;
141408057504Sxy150489 default:
141508057504Sxy150489 ASSERT(B_FALSE);
141608057504Sxy150489 break;
141708057504Sxy150489 }
141808057504Sxy150489
141908057504Sxy150489 packet->num_mblk_frag++;
142008057504Sxy150489
142108057504Sxy150489 /*
142208057504Sxy150489 * Each address could span thru multpile cookie..
142308057504Sxy150489 * Each cookie will have one descriptor
142408057504Sxy150489 */
142508057504Sxy150489 for (j = ncookies; j != 0; j--) {
142608057504Sxy150489
142725f2d433Sxy150489 desc_count = e1000g_fill_tx_desc(tx_ring,
142808057504Sxy150489 packet,
142908057504Sxy150489 dma_cookie.dmac_laddress,
143008057504Sxy150489 dma_cookie.dmac_size);
143108057504Sxy150489
143208057504Sxy150489 if (desc_count <= 0)
143308057504Sxy150489 return (-1);
143408057504Sxy150489
143508057504Sxy150489 desc_total += desc_count;
143608057504Sxy150489
143708057504Sxy150489 /*
143808057504Sxy150489 * ddi_dma_nextcookie() retrieves subsequent DMA
143908057504Sxy150489 * cookies for a DMA object.
144008057504Sxy150489 * ddi_dma_nextcookie() fills in the
144108057504Sxy150489 * ddi_dma_cookie(9S) structure pointed to by
144208057504Sxy150489 * cookiep. The ddi_dma_cookie(9S) structure
144308057504Sxy150489 * must be allocated prior to calling
144408057504Sxy150489 * ddi_dma_nextcookie(). The DMA cookie count
144508057504Sxy150489 * returned by ddi_dma_buf_bind_handle(9F),
144608057504Sxy150489 * ddi_dma_addr_bind_handle(9F), or
144708057504Sxy150489 * ddi_dma_getwin(9F) indicates the number of DMA
144808057504Sxy150489 * cookies a DMA object consists of. If the
144908057504Sxy150489 * resulting cookie count, N, is larger than 1,
145008057504Sxy150489 * ddi_dma_nextcookie() must be called N-1 times
145108057504Sxy150489 * to retrieve all DMA cookies.
145208057504Sxy150489 */
145308057504Sxy150489 if (j > 1) {
145408057504Sxy150489 ddi_dma_nextcookie(packet->tx_dma_handle,
145508057504Sxy150489 &dma_cookie);
145608057504Sxy150489 }
145708057504Sxy150489 }
145808057504Sxy150489
145908057504Sxy150489 return (desc_total);
146008057504Sxy150489 }
146108057504Sxy150489
146208057504Sxy150489 static void
e1000g_fill_context_descriptor(context_data_t * cur_context,struct e1000_context_desc * context_desc)1463c7770590Smx205022 e1000g_fill_context_descriptor(context_data_t *cur_context,
1464c7770590Smx205022 struct e1000_context_desc *context_desc)
146508057504Sxy150489 {
1466c7770590Smx205022 if (cur_context->cksum_flags & HCK_IPV4_HDRCKSUM) {
1467c7770590Smx205022 context_desc->lower_setup.ip_fields.ipcss =
1468c7770590Smx205022 cur_context->ether_header_size;
1469c7770590Smx205022 context_desc->lower_setup.ip_fields.ipcso =
1470c7770590Smx205022 cur_context->ether_header_size +
147108057504Sxy150489 offsetof(struct ip, ip_sum);
1472c7770590Smx205022 context_desc->lower_setup.ip_fields.ipcse =
1473c7770590Smx205022 cur_context->ether_header_size +
1474c7770590Smx205022 cur_context->cksum_start - 1;
147508057504Sxy150489 } else
1476c7770590Smx205022 context_desc->lower_setup.ip_config = 0;
147708057504Sxy150489
1478c7770590Smx205022 if (cur_context->cksum_flags & HCK_PARTIALCKSUM) {
147908057504Sxy150489 /*
148008057504Sxy150489 * The packet with same protocol has the following
148108057504Sxy150489 * stuff and start offset:
148208057504Sxy150489 * | Protocol | Stuff | Start | Checksum
148308057504Sxy150489 * | | Offset | Offset | Enable
148408057504Sxy150489 * | IPv4 + TCP | 0x24 | 0x14 | Yes
148508057504Sxy150489 * | IPv4 + UDP | 0x1A | 0x14 | Yes
148608057504Sxy150489 * | IPv6 + TCP | 0x20 | 0x10 | No
148708057504Sxy150489 * | IPv6 + UDP | 0x14 | 0x10 | No
148808057504Sxy150489 */
1489c7770590Smx205022 context_desc->upper_setup.tcp_fields.tucss =
1490c7770590Smx205022 cur_context->cksum_start + cur_context->ether_header_size;
1491c7770590Smx205022 context_desc->upper_setup.tcp_fields.tucso =
1492c7770590Smx205022 cur_context->cksum_stuff + cur_context->ether_header_size;
1493c7770590Smx205022 context_desc->upper_setup.tcp_fields.tucse = 0;
149408057504Sxy150489 } else
1495c7770590Smx205022 context_desc->upper_setup.tcp_config = 0;
149608057504Sxy150489
1497c7770590Smx205022 if (cur_context->lso_flag) {
1498c7770590Smx205022 context_desc->tcp_seg_setup.fields.mss = cur_context->mss;
1499c7770590Smx205022 context_desc->tcp_seg_setup.fields.hdr_len =
1500c7770590Smx205022 cur_context->hdr_len;
150108057504Sxy150489 /*
1502c7770590Smx205022 * workaround for 82546EB errata 23, status-writeback
1503c7770590Smx205022 * reporting (RS) should not be set on context or
1504c7770590Smx205022 * Null descriptors
150508057504Sxy150489 */
1506c7770590Smx205022 context_desc->cmd_and_length = E1000_TXD_CMD_DEXT
1507c7770590Smx205022 | E1000_TXD_CMD_TSE | E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP
1508c7770590Smx205022 | E1000_TXD_DTYP_C | cur_context->pay_len;
1509c7770590Smx205022 } else {
1510c7770590Smx205022 context_desc->cmd_and_length = E1000_TXD_CMD_DEXT
1511c7770590Smx205022 | E1000_TXD_DTYP_C;
1512c7770590Smx205022 /*
1513c7770590Smx205022 * Zero out the options for TCP Segmentation Offload
1514c7770590Smx205022 */
1515c7770590Smx205022 context_desc->tcp_seg_setup.data = 0;
1516c7770590Smx205022 }
151708057504Sxy150489 }
151808057504Sxy150489
151908057504Sxy150489 static int
e1000g_fill_tx_desc(e1000g_tx_ring_t * tx_ring,p_tx_sw_packet_t packet,uint64_t address,size_t size)152025f2d433Sxy150489 e1000g_fill_tx_desc(e1000g_tx_ring_t *tx_ring,
152125f2d433Sxy150489 p_tx_sw_packet_t packet, uint64_t address, size_t size)
152208057504Sxy150489 {
152325f2d433Sxy150489 struct e1000_hw *hw = &tx_ring->adapter->shared;
152425f2d433Sxy150489 p_sw_desc_t desc;
152508057504Sxy150489
152625f2d433Sxy150489 if (hw->mac.type == e1000_82544) {
152725f2d433Sxy150489 if (hw->bus.type == e1000_bus_type_pcix)
152825f2d433Sxy150489 return (e1000g_tx_workaround_PCIX_82544(packet,
152925f2d433Sxy150489 address, size));
153008057504Sxy150489
153125f2d433Sxy150489 if (size > JUMBO_FRAG_LENGTH)
153225f2d433Sxy150489 return (e1000g_tx_workaround_jumbo_82544(packet,
153325f2d433Sxy150489 address, size));
153425f2d433Sxy150489 }
153508057504Sxy150489
153608057504Sxy150489 ASSERT(packet->num_desc < MAX_TX_DESC_PER_PACKET);
153708057504Sxy150489
153808057504Sxy150489 desc = &packet->desc[packet->num_desc];
153925f2d433Sxy150489 desc->address = address;
1540fe62dec3SChen-Liang Xu desc->length = (uint32_t)size;
154108057504Sxy150489
154208057504Sxy150489 packet->num_desc++;
154308057504Sxy150489
154425f2d433Sxy150489 return (1);
154508057504Sxy150489 }
154608057504Sxy150489
154708057504Sxy150489 static int
e1000g_tx_workaround_PCIX_82544(p_tx_sw_packet_t packet,uint64_t address,size_t size)154825f2d433Sxy150489 e1000g_tx_workaround_PCIX_82544(p_tx_sw_packet_t packet,
154925f2d433Sxy150489 uint64_t address, size_t size)
155008057504Sxy150489 {
155125f2d433Sxy150489 p_sw_desc_t desc;
155208057504Sxy150489 int desc_count;
155308057504Sxy150489 long size_left;
155408057504Sxy150489 size_t len;
155508057504Sxy150489 uint32_t counter;
155608057504Sxy150489 uint32_t array_elements;
155725f2d433Sxy150489 desc_array_t desc_array;
155808057504Sxy150489
155908057504Sxy150489 /*
156008057504Sxy150489 * Coexist Workaround for cordova: RP: 07/04/03
156108057504Sxy150489 *
156208057504Sxy150489 * RP: ERRATA: Workaround ISSUE:
156308057504Sxy150489 * 8kb_buffer_Lockup CONTROLLER: Cordova Breakup
156408057504Sxy150489 * Eachbuffer in to 8kb pieces until the
156508057504Sxy150489 * remainder is < 8kb
156608057504Sxy150489 */
156708057504Sxy150489 size_left = size;
156808057504Sxy150489 desc_count = 0;
156908057504Sxy150489
157008057504Sxy150489 while (size_left > 0) {
157108057504Sxy150489 if (size_left > MAX_TX_BUF_SIZE)
157208057504Sxy150489 len = MAX_TX_BUF_SIZE;
157308057504Sxy150489 else
157408057504Sxy150489 len = size_left;
157508057504Sxy150489
157608057504Sxy150489 array_elements = e1000g_fill_82544_desc(address,
157708057504Sxy150489 len, &desc_array);
157808057504Sxy150489
157908057504Sxy150489 for (counter = 0; counter < array_elements; counter++) {
158008057504Sxy150489 ASSERT(packet->num_desc < MAX_TX_DESC_PER_PACKET);
158108057504Sxy150489 /*
158208057504Sxy150489 * Put in the buffer address
158308057504Sxy150489 */
158408057504Sxy150489 desc = &packet->desc[packet->num_desc];
158508057504Sxy150489
158625f2d433Sxy150489 desc->address =
158725f2d433Sxy150489 desc_array.descriptor[counter].address;
158825f2d433Sxy150489 desc->length =
158925f2d433Sxy150489 desc_array.descriptor[counter].length;
159008057504Sxy150489
159108057504Sxy150489 packet->num_desc++;
159208057504Sxy150489 desc_count++;
159308057504Sxy150489 } /* for */
159408057504Sxy150489
159508057504Sxy150489 /*
159608057504Sxy150489 * Update the buffer address and length
159708057504Sxy150489 */
159808057504Sxy150489 address += MAX_TX_BUF_SIZE;
159908057504Sxy150489 size_left -= MAX_TX_BUF_SIZE;
160008057504Sxy150489 } /* while */
160108057504Sxy150489
160208057504Sxy150489 return (desc_count);
160308057504Sxy150489 }
160408057504Sxy150489
160508057504Sxy150489 static int
e1000g_tx_workaround_jumbo_82544(p_tx_sw_packet_t packet,uint64_t address,size_t size)160625f2d433Sxy150489 e1000g_tx_workaround_jumbo_82544(p_tx_sw_packet_t packet,
160725f2d433Sxy150489 uint64_t address, size_t size)
160808057504Sxy150489 {
160925f2d433Sxy150489 p_sw_desc_t desc;
161008057504Sxy150489 int desc_count;
161108057504Sxy150489 long size_left;
161208057504Sxy150489 uint32_t offset;
161308057504Sxy150489
161408057504Sxy150489 /*
161508057504Sxy150489 * Workaround for Jumbo Frames on Cordova
161608057504Sxy150489 * PSD 06/01/2001
161708057504Sxy150489 */
161808057504Sxy150489 size_left = size;
161908057504Sxy150489 desc_count = 0;
162008057504Sxy150489 offset = 0;
162108057504Sxy150489 while (size_left > 0) {
162208057504Sxy150489 ASSERT(packet->num_desc < MAX_TX_DESC_PER_PACKET);
162308057504Sxy150489
162408057504Sxy150489 desc = &packet->desc[packet->num_desc];
162508057504Sxy150489
162625f2d433Sxy150489 desc->address = address + offset;
162708057504Sxy150489
162808057504Sxy150489 if (size_left > JUMBO_FRAG_LENGTH)
162925f2d433Sxy150489 desc->length = JUMBO_FRAG_LENGTH;
163008057504Sxy150489 else
1631fe62dec3SChen-Liang Xu desc->length = (uint32_t)size_left;
163208057504Sxy150489
163308057504Sxy150489 packet->num_desc++;
163408057504Sxy150489 desc_count++;
163508057504Sxy150489
163625f2d433Sxy150489 offset += desc->length;
163708057504Sxy150489 size_left -= JUMBO_FRAG_LENGTH;
163808057504Sxy150489 }
163908057504Sxy150489
164008057504Sxy150489 return (desc_count);
164108057504Sxy150489 }
164208057504Sxy150489
164325f2d433Sxy150489 #pragma inline(e1000g_82547_tx_move_tail_work)
164425f2d433Sxy150489
164508057504Sxy150489 static void
e1000g_82547_tx_move_tail_work(e1000g_tx_ring_t * tx_ring)164608057504Sxy150489 e1000g_82547_tx_move_tail_work(e1000g_tx_ring_t *tx_ring)
164708057504Sxy150489 {
164825f2d433Sxy150489 struct e1000_hw *hw;
164908057504Sxy150489 uint16_t hw_tdt;
165008057504Sxy150489 uint16_t sw_tdt;
165108057504Sxy150489 struct e1000_tx_desc *tx_desc;
165208057504Sxy150489 uint16_t length = 0;
165308057504Sxy150489 boolean_t eop = B_FALSE;
165408057504Sxy150489 struct e1000g *Adapter;
165508057504Sxy150489
165608057504Sxy150489 Adapter = tx_ring->adapter;
165725f2d433Sxy150489 hw = &Adapter->shared;
165808057504Sxy150489
1659592a4d85Scc210113 hw_tdt = E1000_READ_REG(hw, E1000_TDT(0));
166008057504Sxy150489 sw_tdt = tx_ring->tbd_next - tx_ring->tbd_first;
166108057504Sxy150489
166208057504Sxy150489 while (hw_tdt != sw_tdt) {
166308057504Sxy150489 tx_desc = &(tx_ring->tbd_first[hw_tdt]);
166408057504Sxy150489 length += tx_desc->lower.flags.length;
166508057504Sxy150489 eop = tx_desc->lower.data & E1000_TXD_CMD_EOP;
166625f2d433Sxy150489 if (++hw_tdt == Adapter->tx_desc_num)
166708057504Sxy150489 hw_tdt = 0;
166808057504Sxy150489
166908057504Sxy150489 if (eop) {
167008057504Sxy150489 if ((Adapter->link_duplex == HALF_DUPLEX) &&
167125f2d433Sxy150489 (e1000_fifo_workaround_82547(hw, length)
167225f2d433Sxy150489 != E1000_SUCCESS)) {
167308057504Sxy150489 if (tx_ring->timer_enable_82547) {
167408057504Sxy150489 ASSERT(tx_ring->timer_id_82547 == 0);
167508057504Sxy150489 tx_ring->timer_id_82547 =
167608057504Sxy150489 timeout(e1000g_82547_timeout,
16775633182fSyy150190 (void *)tx_ring,
167808057504Sxy150489 drv_usectohz(10000));
167908057504Sxy150489 }
168008057504Sxy150489 return;
168108057504Sxy150489
168208057504Sxy150489 } else {
1683592a4d85Scc210113 E1000_WRITE_REG(hw, E1000_TDT(0), hw_tdt);
168425f2d433Sxy150489 e1000_update_tx_fifo_head_82547(hw, length);
168508057504Sxy150489 length = 0;
168608057504Sxy150489 }
168708057504Sxy150489 }
168808057504Sxy150489 }
168908057504Sxy150489 }
169008057504Sxy150489
169108057504Sxy150489 static void
e1000g_82547_timeout(void * arg)169208057504Sxy150489 e1000g_82547_timeout(void *arg)
169308057504Sxy150489 {
169408057504Sxy150489 e1000g_tx_ring_t *tx_ring;
169508057504Sxy150489
169608057504Sxy150489 tx_ring = (e1000g_tx_ring_t *)arg;
169708057504Sxy150489
169808057504Sxy150489 mutex_enter(&tx_ring->tx_lock);
169908057504Sxy150489
170008057504Sxy150489 tx_ring->timer_id_82547 = 0;
170108057504Sxy150489 e1000g_82547_tx_move_tail_work(tx_ring);
170208057504Sxy150489
170308057504Sxy150489 mutex_exit(&tx_ring->tx_lock);
170408057504Sxy150489 }
170508057504Sxy150489
170608057504Sxy150489 static void
e1000g_82547_tx_move_tail(e1000g_tx_ring_t * tx_ring)170708057504Sxy150489 e1000g_82547_tx_move_tail(e1000g_tx_ring_t *tx_ring)
170808057504Sxy150489 {
170908057504Sxy150489 timeout_id_t tid;
171008057504Sxy150489
171108057504Sxy150489 ASSERT(MUTEX_HELD(&tx_ring->tx_lock));
171208057504Sxy150489
171308057504Sxy150489 tid = tx_ring->timer_id_82547;
171408057504Sxy150489 tx_ring->timer_id_82547 = 0;
171508057504Sxy150489 if (tid != 0) {
171608057504Sxy150489 tx_ring->timer_enable_82547 = B_FALSE;
171708057504Sxy150489 mutex_exit(&tx_ring->tx_lock);
171808057504Sxy150489
171908057504Sxy150489 (void) untimeout(tid);
172008057504Sxy150489
172108057504Sxy150489 mutex_enter(&tx_ring->tx_lock);
172208057504Sxy150489 }
172308057504Sxy150489 tx_ring->timer_enable_82547 = B_TRUE;
172408057504Sxy150489 e1000g_82547_tx_move_tail_work(tx_ring);
172508057504Sxy150489 }
1726*7c5988f9SRobert Mustacchi
1727*7c5988f9SRobert Mustacchi /*
1728*7c5988f9SRobert Mustacchi * This is part of a workaround for the I219, see e1000g_flush_desc_rings() for
1729*7c5988f9SRobert Mustacchi * more information.
1730*7c5988f9SRobert Mustacchi *
1731*7c5988f9SRobert Mustacchi * We need to clear any potential pending descriptors from the tx_ring. As
1732*7c5988f9SRobert Mustacchi * we're about to reset the device, we don't care about the data that we give it
1733*7c5988f9SRobert Mustacchi * itself.
1734*7c5988f9SRobert Mustacchi */
1735*7c5988f9SRobert Mustacchi void
e1000g_flush_tx_ring(struct e1000g * Adapter)1736*7c5988f9SRobert Mustacchi e1000g_flush_tx_ring(struct e1000g *Adapter)
1737*7c5988f9SRobert Mustacchi {
1738*7c5988f9SRobert Mustacchi struct e1000_hw *hw = &Adapter->shared;
1739*7c5988f9SRobert Mustacchi e1000g_tx_ring_t *tx_ring = &Adapter->tx_ring[0];
1740*7c5988f9SRobert Mustacchi uint32_t tctl, txd_lower = E1000_TXD_CMD_IFCS;
1741*7c5988f9SRobert Mustacchi uint16_t size = 512;
1742*7c5988f9SRobert Mustacchi struct e1000_tx_desc *desc;
1743*7c5988f9SRobert Mustacchi
1744*7c5988f9SRobert Mustacchi tctl = E1000_READ_REG(hw, E1000_TCTL);
1745*7c5988f9SRobert Mustacchi E1000_WRITE_REG(hw, E1000_TCTL, tctl | E1000_TCTL_EN);
1746*7c5988f9SRobert Mustacchi
1747*7c5988f9SRobert Mustacchi desc = tx_ring->tbd_next;
1748*7c5988f9SRobert Mustacchi if (tx_ring->tbd_next == tx_ring->tbd_last)
1749*7c5988f9SRobert Mustacchi tx_ring->tbd_next = tx_ring->tbd_first;
1750*7c5988f9SRobert Mustacchi else
1751*7c5988f9SRobert Mustacchi tx_ring->tbd_next++;
1752*7c5988f9SRobert Mustacchi
1753*7c5988f9SRobert Mustacchi /* We just need to set any valid address, so we use the ring itself */
1754*7c5988f9SRobert Mustacchi desc->buffer_addr = tx_ring->tbd_dma_addr;
1755*7c5988f9SRobert Mustacchi desc->lower.data = LE_32(txd_lower | size);
1756*7c5988f9SRobert Mustacchi desc->upper.data = 0;
1757*7c5988f9SRobert Mustacchi
1758*7c5988f9SRobert Mustacchi (void) ddi_dma_sync(tx_ring->tbd_dma_handle,
1759*7c5988f9SRobert Mustacchi 0, 0, DDI_DMA_SYNC_FORDEV);
1760*7c5988f9SRobert Mustacchi E1000_WRITE_REG(hw, E1000_TDT(0),
1761*7c5988f9SRobert Mustacchi (uint32_t)(tx_ring->tbd_next - tx_ring->tbd_first));
1762*7c5988f9SRobert Mustacchi (void) E1000_READ_REG(hw, E1000_STATUS);
1763*7c5988f9SRobert Mustacchi usec_delay(250);
1764*7c5988f9SRobert Mustacchi }
1765