xref: /titanic_44/usr/src/uts/common/io/nxge/nxge_txdma.c (revision 75d94465dbafa487b716482dc36d5150a4ec9853)
16f45ec7bSml29623 /*
26f45ec7bSml29623  * CDDL HEADER START
36f45ec7bSml29623  *
46f45ec7bSml29623  * The contents of this file are subject to the terms of the
56f45ec7bSml29623  * Common Development and Distribution License (the "License").
66f45ec7bSml29623  * You may not use this file except in compliance with the License.
76f45ec7bSml29623  *
86f45ec7bSml29623  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96f45ec7bSml29623  * or http://www.opensolaris.org/os/licensing.
106f45ec7bSml29623  * See the License for the specific language governing permissions
116f45ec7bSml29623  * and limitations under the License.
126f45ec7bSml29623  *
136f45ec7bSml29623  * When distributing Covered Code, include this CDDL HEADER in each
146f45ec7bSml29623  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156f45ec7bSml29623  * If applicable, add the following below this CDDL HEADER, with the
166f45ec7bSml29623  * fields enclosed by brackets "[]" replaced with your own identifying
176f45ec7bSml29623  * information: Portions Copyright [yyyy] [name of copyright owner]
186f45ec7bSml29623  *
196f45ec7bSml29623  * CDDL HEADER END
206f45ec7bSml29623  */
21952a2464SMichael Speer 
226f45ec7bSml29623 /*
230dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
246f45ec7bSml29623  * Use is subject to license terms.
256f45ec7bSml29623  */
266f45ec7bSml29623 
276f45ec7bSml29623 #include <sys/nxge/nxge_impl.h>
286f45ec7bSml29623 #include <sys/nxge/nxge_txdma.h>
29678453a8Sspeer #include <sys/nxge/nxge_hio.h>
30678453a8Sspeer #include <npi_tx_rd64.h>
31678453a8Sspeer #include <npi_tx_wr64.h>
326f45ec7bSml29623 #include <sys/llc1.h>
336f45ec7bSml29623 
346f45ec7bSml29623 uint32_t 	nxge_reclaim_pending = TXDMA_RECLAIM_PENDING_DEFAULT;
35da14cebeSEric Cheng uint32_t	nxge_tx_minfree = 64;
366f45ec7bSml29623 uint32_t	nxge_tx_intr_thres = 0;
376f45ec7bSml29623 uint32_t	nxge_tx_max_gathers = TX_MAX_GATHER_POINTERS;
386f45ec7bSml29623 uint32_t	nxge_tx_tiny_pack = 1;
396f45ec7bSml29623 uint32_t	nxge_tx_use_bcopy = 1;
406f45ec7bSml29623 
416f45ec7bSml29623 extern uint32_t 	nxge_tx_ring_size;
426f45ec7bSml29623 extern uint32_t 	nxge_bcopy_thresh;
436f45ec7bSml29623 extern uint32_t 	nxge_dvma_thresh;
446f45ec7bSml29623 extern uint32_t 	nxge_dma_stream_thresh;
456f45ec7bSml29623 extern dma_method_t 	nxge_force_dma;
46b4d05839Sml29623 extern uint32_t		nxge_cksum_offload;
476f45ec7bSml29623 
486f45ec7bSml29623 /* Device register access attributes for PIO.  */
496f45ec7bSml29623 extern ddi_device_acc_attr_t nxge_dev_reg_acc_attr;
506f45ec7bSml29623 /* Device descriptor access attributes for DMA.  */
516f45ec7bSml29623 extern ddi_device_acc_attr_t nxge_dev_desc_dma_acc_attr;
526f45ec7bSml29623 /* Device buffer access attributes for DMA.  */
536f45ec7bSml29623 extern ddi_device_acc_attr_t nxge_dev_buf_dma_acc_attr;
546f45ec7bSml29623 extern ddi_dma_attr_t nxge_desc_dma_attr;
556f45ec7bSml29623 extern ddi_dma_attr_t nxge_tx_dma_attr;
566f45ec7bSml29623 
57da14cebeSEric Cheng extern void nxge_tx_ring_task(void *arg);
582d99c5d4SMichael Speer 
59678453a8Sspeer static nxge_status_t nxge_map_txdma(p_nxge_t, int);
606f45ec7bSml29623 
61678453a8Sspeer static nxge_status_t nxge_txdma_hw_start(p_nxge_t, int);
626f45ec7bSml29623 
636f45ec7bSml29623 static nxge_status_t nxge_map_txdma_channel(p_nxge_t, uint16_t,
646f45ec7bSml29623 	p_nxge_dma_common_t *, p_tx_ring_t *,
656f45ec7bSml29623 	uint32_t, p_nxge_dma_common_t *,
666f45ec7bSml29623 	p_tx_mbox_t *);
67678453a8Sspeer static void nxge_unmap_txdma_channel(p_nxge_t, uint16_t);
686f45ec7bSml29623 
696f45ec7bSml29623 static nxge_status_t nxge_map_txdma_channel_buf_ring(p_nxge_t, uint16_t,
706f45ec7bSml29623 	p_nxge_dma_common_t *, p_tx_ring_t *, uint32_t);
716f45ec7bSml29623 static void nxge_unmap_txdma_channel_buf_ring(p_nxge_t, p_tx_ring_t);
726f45ec7bSml29623 
736f45ec7bSml29623 static void nxge_map_txdma_channel_cfg_ring(p_nxge_t, uint16_t,
746f45ec7bSml29623 	p_nxge_dma_common_t *, p_tx_ring_t,
756f45ec7bSml29623 	p_tx_mbox_t *);
766f45ec7bSml29623 static void nxge_unmap_txdma_channel_cfg_ring(p_nxge_t,
776f45ec7bSml29623 	p_tx_ring_t, p_tx_mbox_t);
786f45ec7bSml29623 
796f45ec7bSml29623 static nxge_status_t nxge_txdma_start_channel(p_nxge_t, uint16_t,
806f45ec7bSml29623     p_tx_ring_t, p_tx_mbox_t);
81678453a8Sspeer static nxge_status_t nxge_txdma_stop_channel(p_nxge_t, uint16_t);
826f45ec7bSml29623 
836f45ec7bSml29623 static p_tx_ring_t nxge_txdma_get_ring(p_nxge_t, uint16_t);
846f45ec7bSml29623 static nxge_status_t nxge_tx_err_evnts(p_nxge_t, uint_t,
856f45ec7bSml29623 	p_nxge_ldv_t, tx_cs_t);
866f45ec7bSml29623 static p_tx_mbox_t nxge_txdma_get_mbox(p_nxge_t, uint16_t);
876f45ec7bSml29623 static nxge_status_t nxge_txdma_fatal_err_recover(p_nxge_t,
886f45ec7bSml29623 	uint16_t, p_tx_ring_t);
896f45ec7bSml29623 
90678453a8Sspeer static void nxge_txdma_fixup_hung_channel(p_nxge_t nxgep,
91678453a8Sspeer     p_tx_ring_t ring_p, uint16_t channel);
92678453a8Sspeer 
936f45ec7bSml29623 nxge_status_t
nxge_init_txdma_channels(p_nxge_t nxgep)946f45ec7bSml29623 nxge_init_txdma_channels(p_nxge_t nxgep)
956f45ec7bSml29623 {
96678453a8Sspeer 	nxge_grp_set_t	*set = &nxgep->tx_set;
97e11f0814SMichael Speer 	int		i, tdc, count;
98e11f0814SMichael Speer 	nxge_grp_t	*group;
99da14cebeSEric Cheng 	dc_map_t	map;
100da14cebeSEric Cheng 	int		dev_gindex;
1016f45ec7bSml29623 
102678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "==> nxge_init_txdma_channels"));
1036f45ec7bSml29623 
104678453a8Sspeer 	for (i = 0, count = 0; i < NXGE_LOGICAL_GROUP_MAX; i++) {
105678453a8Sspeer 		if ((1 << i) & set->lg.map) {
106e11f0814SMichael Speer 			group = set->group[i];
107da14cebeSEric Cheng 			dev_gindex =
108da14cebeSEric Cheng 			    nxgep->pt_config.hw_config.def_mac_txdma_grpid + i;
109da14cebeSEric Cheng 			map = nxgep->pt_config.tdc_grps[dev_gindex].map;
110678453a8Sspeer 			for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
111da14cebeSEric Cheng 				if ((1 << tdc) & map) {
112da14cebeSEric Cheng 					if ((nxge_grp_dc_add(nxgep,
113da14cebeSEric Cheng 					    group, VP_BOUND_TX, tdc)))
114e11f0814SMichael Speer 						goto init_txdma_channels_exit;
115678453a8Sspeer 				}
116678453a8Sspeer 			}
117678453a8Sspeer 		}
118678453a8Sspeer 		if (++count == set->lg.count)
119678453a8Sspeer 			break;
1206f45ec7bSml29623 	}
1216f45ec7bSml29623 
122678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_init_txdma_channels"));
1236f45ec7bSml29623 	return (NXGE_OK);
124e11f0814SMichael Speer 
125e11f0814SMichael Speer init_txdma_channels_exit:
126e11f0814SMichael Speer 	for (i = 0, count = 0; i < NXGE_LOGICAL_GROUP_MAX; i++) {
127e11f0814SMichael Speer 		if ((1 << i) & set->lg.map) {
128e11f0814SMichael Speer 			group = set->group[i];
129da14cebeSEric Cheng 			dev_gindex =
130da14cebeSEric Cheng 			    nxgep->pt_config.hw_config.def_mac_txdma_grpid + i;
131da14cebeSEric Cheng 			map = nxgep->pt_config.tdc_grps[dev_gindex].map;
132e11f0814SMichael Speer 			for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
133da14cebeSEric Cheng 				if ((1 << tdc) & map) {
134e11f0814SMichael Speer 					nxge_grp_dc_remove(nxgep,
135e11f0814SMichael Speer 					    VP_BOUND_TX, tdc);
136e11f0814SMichael Speer 				}
137e11f0814SMichael Speer 			}
138e11f0814SMichael Speer 		}
139e11f0814SMichael Speer 		if (++count == set->lg.count)
140e11f0814SMichael Speer 			break;
141e11f0814SMichael Speer 	}
142e11f0814SMichael Speer 
143e11f0814SMichael Speer 	return (NXGE_ERROR);
144da14cebeSEric Cheng 
1456f45ec7bSml29623 }
1466f45ec7bSml29623 
147678453a8Sspeer nxge_status_t
nxge_init_txdma_channel(p_nxge_t nxge,int channel)148678453a8Sspeer nxge_init_txdma_channel(
149678453a8Sspeer 	p_nxge_t nxge,
150678453a8Sspeer 	int channel)
151678453a8Sspeer {
152678453a8Sspeer 	nxge_status_t status;
153678453a8Sspeer 
154678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, MEM2_CTL, "==> nxge_init_txdma_channel"));
155678453a8Sspeer 
156678453a8Sspeer 	status = nxge_map_txdma(nxge, channel);
157678453a8Sspeer 	if (status != NXGE_OK) {
158678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
159678453a8Sspeer 		    "<== nxge_init_txdma_channel: status 0x%x", status));
160678453a8Sspeer 		(void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel);
161678453a8Sspeer 		return (status);
162678453a8Sspeer 	}
163678453a8Sspeer 
164678453a8Sspeer 	status = nxge_txdma_hw_start(nxge, channel);
165678453a8Sspeer 	if (status != NXGE_OK) {
166678453a8Sspeer 		(void) nxge_unmap_txdma_channel(nxge, channel);
167678453a8Sspeer 		(void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel);
168678453a8Sspeer 		return (status);
169678453a8Sspeer 	}
170678453a8Sspeer 
171678453a8Sspeer 	if (!nxge->statsp->tdc_ksp[channel])
172678453a8Sspeer 		nxge_setup_tdc_kstats(nxge, channel);
173678453a8Sspeer 
174678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, MEM2_CTL, "<== nxge_init_txdma_channel"));
175678453a8Sspeer 
176678453a8Sspeer 	return (status);
177678453a8Sspeer }
178678453a8Sspeer 
1796f45ec7bSml29623 void
nxge_uninit_txdma_channels(p_nxge_t nxgep)1806f45ec7bSml29623 nxge_uninit_txdma_channels(p_nxge_t nxgep)
1816f45ec7bSml29623 {
182678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
183678453a8Sspeer 	int tdc;
1846f45ec7bSml29623 
185678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "==> nxge_uninit_txdma_channels"));
186678453a8Sspeer 
187678453a8Sspeer 	if (set->owned.map == 0) {
188678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, MEM2_CTL,
189678453a8Sspeer 		    "nxge_uninit_txdma_channels: no channels"));
190678453a8Sspeer 		return;
191678453a8Sspeer 	}
192678453a8Sspeer 
193678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
194678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
195678453a8Sspeer 			nxge_grp_dc_remove(nxgep, VP_BOUND_TX, tdc);
196678453a8Sspeer 		}
197678453a8Sspeer 	}
198678453a8Sspeer 
199678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_uninit_txdma_channels"));
200678453a8Sspeer }
201678453a8Sspeer 
202678453a8Sspeer void
nxge_uninit_txdma_channel(p_nxge_t nxgep,int channel)203678453a8Sspeer nxge_uninit_txdma_channel(p_nxge_t nxgep, int channel)
204678453a8Sspeer {
205678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_uninit_txdma_channel"));
206678453a8Sspeer 
207678453a8Sspeer 	if (nxgep->statsp->tdc_ksp[channel]) {
208678453a8Sspeer 		kstat_delete(nxgep->statsp->tdc_ksp[channel]);
209678453a8Sspeer 		nxgep->statsp->tdc_ksp[channel] = 0;
210678453a8Sspeer 	}
211678453a8Sspeer 
212ef523517SMichael Speer 	if (nxge_txdma_stop_channel(nxgep, channel) != NXGE_OK)
213ef523517SMichael Speer 		goto nxge_uninit_txdma_channel_exit;
214ef523517SMichael Speer 
215678453a8Sspeer 	nxge_unmap_txdma_channel(nxgep, channel);
2166f45ec7bSml29623 
217ef523517SMichael Speer nxge_uninit_txdma_channel_exit:
218ef523517SMichael Speer 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_uninit_txdma_channel"));
2196f45ec7bSml29623 }
2206f45ec7bSml29623 
2216f45ec7bSml29623 void
nxge_setup_dma_common(p_nxge_dma_common_t dest_p,p_nxge_dma_common_t src_p,uint32_t entries,uint32_t size)2226f45ec7bSml29623 nxge_setup_dma_common(p_nxge_dma_common_t dest_p, p_nxge_dma_common_t src_p,
2236f45ec7bSml29623 	uint32_t entries, uint32_t size)
2246f45ec7bSml29623 {
2256f45ec7bSml29623 	size_t		tsize;
2266f45ec7bSml29623 	*dest_p = *src_p;
2276f45ec7bSml29623 	tsize = size * entries;
2286f45ec7bSml29623 	dest_p->alength = tsize;
2296f45ec7bSml29623 	dest_p->nblocks = entries;
2306f45ec7bSml29623 	dest_p->block_size = size;
2316f45ec7bSml29623 	dest_p->offset += tsize;
2326f45ec7bSml29623 
2336f45ec7bSml29623 	src_p->kaddrp = (caddr_t)dest_p->kaddrp + tsize;
2346f45ec7bSml29623 	src_p->alength -= tsize;
2356f45ec7bSml29623 	src_p->dma_cookie.dmac_laddress += tsize;
2366f45ec7bSml29623 	src_p->dma_cookie.dmac_size -= tsize;
2376f45ec7bSml29623 }
2386f45ec7bSml29623 
239678453a8Sspeer /*
240678453a8Sspeer  * nxge_reset_txdma_channel
241678453a8Sspeer  *
242678453a8Sspeer  *	Reset a TDC.
243678453a8Sspeer  *
244678453a8Sspeer  * Arguments:
245678453a8Sspeer  * 	nxgep
246678453a8Sspeer  * 	channel		The channel to reset.
247678453a8Sspeer  * 	reg_data	The current TX_CS.
248678453a8Sspeer  *
249678453a8Sspeer  * Notes:
250678453a8Sspeer  *
251678453a8Sspeer  * NPI/NXGE function calls:
252678453a8Sspeer  *	npi_txdma_channel_reset()
253678453a8Sspeer  *	npi_txdma_channel_control()
254678453a8Sspeer  *
255678453a8Sspeer  * Registers accessed:
256678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
257678453a8Sspeer  *	TX_RING_KICK	DMC+0x40018 Transmit Ring Kick
258678453a8Sspeer  *
259678453a8Sspeer  * Context:
260678453a8Sspeer  *	Any domain
261678453a8Sspeer  */
2626f45ec7bSml29623 nxge_status_t
nxge_reset_txdma_channel(p_nxge_t nxgep,uint16_t channel,uint64_t reg_data)2636f45ec7bSml29623 nxge_reset_txdma_channel(p_nxge_t nxgep, uint16_t channel, uint64_t reg_data)
2646f45ec7bSml29623 {
2656f45ec7bSml29623 	npi_status_t		rs = NPI_SUCCESS;
2666f45ec7bSml29623 	nxge_status_t		status = NXGE_OK;
2676f45ec7bSml29623 	npi_handle_t		handle;
2686f45ec7bSml29623 
2696f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, " ==> nxge_reset_txdma_channel"));
2706f45ec7bSml29623 
2716f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
2726f45ec7bSml29623 	if ((reg_data & TX_CS_RST_MASK) == TX_CS_RST_MASK) {
2736f45ec7bSml29623 		rs = npi_txdma_channel_reset(handle, channel);
2746f45ec7bSml29623 	} else {
2756f45ec7bSml29623 		rs = npi_txdma_channel_control(handle, TXDMA_RESET,
2766f45ec7bSml29623 		    channel);
2776f45ec7bSml29623 	}
2786f45ec7bSml29623 
2796f45ec7bSml29623 	if (rs != NPI_SUCCESS) {
2806f45ec7bSml29623 		status = NXGE_ERROR | rs;
2816f45ec7bSml29623 	}
2826f45ec7bSml29623 
2836f45ec7bSml29623 	/*
2846f45ec7bSml29623 	 * Reset the tail (kick) register to 0.
2856f45ec7bSml29623 	 * (Hardware will not reset it. Tx overflow fatal
2866f45ec7bSml29623 	 * error if tail is not set to 0 after reset!
2876f45ec7bSml29623 	 */
2886f45ec7bSml29623 	TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0);
2896f45ec7bSml29623 
2906f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, " <== nxge_reset_txdma_channel"));
2916f45ec7bSml29623 	return (status);
2926f45ec7bSml29623 }
2936f45ec7bSml29623 
294678453a8Sspeer /*
295678453a8Sspeer  * nxge_init_txdma_channel_event_mask
296678453a8Sspeer  *
297678453a8Sspeer  *	Enable interrupts for a set of events.
298678453a8Sspeer  *
299678453a8Sspeer  * Arguments:
300678453a8Sspeer  * 	nxgep
301678453a8Sspeer  * 	channel	The channel to map.
302678453a8Sspeer  * 	mask_p	The events to enable.
303678453a8Sspeer  *
304678453a8Sspeer  * Notes:
305678453a8Sspeer  *
306678453a8Sspeer  * NPI/NXGE function calls:
307678453a8Sspeer  *	npi_txdma_event_mask()
308678453a8Sspeer  *
309678453a8Sspeer  * Registers accessed:
310678453a8Sspeer  *	TX_ENT_MSK	DMC+0x40020 Transmit Event Mask
311678453a8Sspeer  *
312678453a8Sspeer  * Context:
313678453a8Sspeer  *	Any domain
314678453a8Sspeer  */
3156f45ec7bSml29623 nxge_status_t
nxge_init_txdma_channel_event_mask(p_nxge_t nxgep,uint16_t channel,p_tx_dma_ent_msk_t mask_p)3166f45ec7bSml29623 nxge_init_txdma_channel_event_mask(p_nxge_t nxgep, uint16_t channel,
3176f45ec7bSml29623 		p_tx_dma_ent_msk_t mask_p)
3186f45ec7bSml29623 {
3196f45ec7bSml29623 	npi_handle_t		handle;
3206f45ec7bSml29623 	npi_status_t		rs = NPI_SUCCESS;
3216f45ec7bSml29623 	nxge_status_t		status = NXGE_OK;
3226f45ec7bSml29623 
3236f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
3246f45ec7bSml29623 	    "<== nxge_init_txdma_channel_event_mask"));
3256f45ec7bSml29623 
3266f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
3276f45ec7bSml29623 	rs = npi_txdma_event_mask(handle, OP_SET, channel, mask_p);
3286f45ec7bSml29623 	if (rs != NPI_SUCCESS) {
3296f45ec7bSml29623 		status = NXGE_ERROR | rs;
3306f45ec7bSml29623 	}
3316f45ec7bSml29623 
3326f45ec7bSml29623 	return (status);
3336f45ec7bSml29623 }
3346f45ec7bSml29623 
335678453a8Sspeer /*
336678453a8Sspeer  * nxge_init_txdma_channel_cntl_stat
337678453a8Sspeer  *
338678453a8Sspeer  *	Stop a TDC.  If at first we don't succeed, inject an error.
339678453a8Sspeer  *
340678453a8Sspeer  * Arguments:
341678453a8Sspeer  * 	nxgep
342678453a8Sspeer  * 	channel		The channel to stop.
343678453a8Sspeer  *
344678453a8Sspeer  * Notes:
345678453a8Sspeer  *
346678453a8Sspeer  * NPI/NXGE function calls:
347678453a8Sspeer  *	npi_txdma_control_status()
348678453a8Sspeer  *
349678453a8Sspeer  * Registers accessed:
350678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
351678453a8Sspeer  *
352678453a8Sspeer  * Context:
353678453a8Sspeer  *	Any domain
354678453a8Sspeer  */
3556f45ec7bSml29623 nxge_status_t
nxge_init_txdma_channel_cntl_stat(p_nxge_t nxgep,uint16_t channel,uint64_t reg_data)3566f45ec7bSml29623 nxge_init_txdma_channel_cntl_stat(p_nxge_t nxgep, uint16_t channel,
3576f45ec7bSml29623 	uint64_t reg_data)
3586f45ec7bSml29623 {
3596f45ec7bSml29623 	npi_handle_t		handle;
3606f45ec7bSml29623 	npi_status_t		rs = NPI_SUCCESS;
3616f45ec7bSml29623 	nxge_status_t		status = NXGE_OK;
3626f45ec7bSml29623 
3636f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
3646f45ec7bSml29623 	    "<== nxge_init_txdma_channel_cntl_stat"));
3656f45ec7bSml29623 
3666f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
3676f45ec7bSml29623 	rs = npi_txdma_control_status(handle, OP_SET, channel,
3686f45ec7bSml29623 	    (p_tx_cs_t)&reg_data);
3696f45ec7bSml29623 
3706f45ec7bSml29623 	if (rs != NPI_SUCCESS) {
3716f45ec7bSml29623 		status = NXGE_ERROR | rs;
3726f45ec7bSml29623 	}
3736f45ec7bSml29623 
3746f45ec7bSml29623 	return (status);
3756f45ec7bSml29623 }
3766f45ec7bSml29623 
377678453a8Sspeer /*
378678453a8Sspeer  * nxge_enable_txdma_channel
379678453a8Sspeer  *
380678453a8Sspeer  *	Enable a TDC.
381678453a8Sspeer  *
382678453a8Sspeer  * Arguments:
383678453a8Sspeer  * 	nxgep
384678453a8Sspeer  * 	channel		The channel to enable.
385678453a8Sspeer  * 	tx_desc_p	channel's transmit descriptor ring.
386678453a8Sspeer  * 	mbox_p		channel's mailbox,
387678453a8Sspeer  *
388678453a8Sspeer  * Notes:
389678453a8Sspeer  *
390678453a8Sspeer  * NPI/NXGE function calls:
391678453a8Sspeer  *	npi_txdma_ring_config()
392678453a8Sspeer  *	npi_txdma_mbox_config()
393678453a8Sspeer  *	npi_txdma_channel_init_enable()
394678453a8Sspeer  *
395678453a8Sspeer  * Registers accessed:
396678453a8Sspeer  *	TX_RNG_CFIG	DMC+0x40000 Transmit Ring Configuration
397678453a8Sspeer  *	TXDMA_MBH	DMC+0x40030 TXDMA Mailbox High
398678453a8Sspeer  *	TXDMA_MBL	DMC+0x40038 TXDMA Mailbox Low
399678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
400678453a8Sspeer  *
401678453a8Sspeer  * Context:
402678453a8Sspeer  *	Any domain
403678453a8Sspeer  */
4046f45ec7bSml29623 nxge_status_t
nxge_enable_txdma_channel(p_nxge_t nxgep,uint16_t channel,p_tx_ring_t tx_desc_p,p_tx_mbox_t mbox_p)4056f45ec7bSml29623 nxge_enable_txdma_channel(p_nxge_t nxgep,
4066f45ec7bSml29623 	uint16_t channel, p_tx_ring_t tx_desc_p, p_tx_mbox_t mbox_p)
4076f45ec7bSml29623 {
4086f45ec7bSml29623 	npi_handle_t		handle;
4096f45ec7bSml29623 	npi_status_t		rs = NPI_SUCCESS;
4106f45ec7bSml29623 	nxge_status_t		status = NXGE_OK;
4116f45ec7bSml29623 
4126f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_enable_txdma_channel"));
4136f45ec7bSml29623 
4146f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
4156f45ec7bSml29623 	/*
4166f45ec7bSml29623 	 * Use configuration data composed at init time.
4176f45ec7bSml29623 	 * Write to hardware the transmit ring configurations.
4186f45ec7bSml29623 	 */
4196f45ec7bSml29623 	rs = npi_txdma_ring_config(handle, OP_SET, channel,
4206f45ec7bSml29623 	    (uint64_t *)&(tx_desc_p->tx_ring_cfig.value));
4216f45ec7bSml29623 
4226f45ec7bSml29623 	if (rs != NPI_SUCCESS) {
4236f45ec7bSml29623 		return (NXGE_ERROR | rs);
4246f45ec7bSml29623 	}
4256f45ec7bSml29623 
426678453a8Sspeer 	if (isLDOMguest(nxgep)) {
427678453a8Sspeer 		/* Add interrupt handler for this channel. */
428678453a8Sspeer 		if (nxge_hio_intr_add(nxgep, VP_BOUND_TX, channel) != NXGE_OK)
429678453a8Sspeer 			return (NXGE_ERROR);
430678453a8Sspeer 	}
431678453a8Sspeer 
4326f45ec7bSml29623 	/* Write to hardware the mailbox */
4336f45ec7bSml29623 	rs = npi_txdma_mbox_config(handle, OP_SET, channel,
4346f45ec7bSml29623 	    (uint64_t *)&mbox_p->tx_mbox.dma_cookie.dmac_laddress);
4356f45ec7bSml29623 
4366f45ec7bSml29623 	if (rs != NPI_SUCCESS) {
4376f45ec7bSml29623 		return (NXGE_ERROR | rs);
4386f45ec7bSml29623 	}
4396f45ec7bSml29623 
4406f45ec7bSml29623 	/* Start the DMA engine. */
4416f45ec7bSml29623 	rs = npi_txdma_channel_init_enable(handle, channel);
4426f45ec7bSml29623 
4436f45ec7bSml29623 	if (rs != NPI_SUCCESS) {
4446f45ec7bSml29623 		return (NXGE_ERROR | rs);
4456f45ec7bSml29623 	}
4466f45ec7bSml29623 
4476f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_enable_txdma_channel"));
4486f45ec7bSml29623 
4496f45ec7bSml29623 	return (status);
4506f45ec7bSml29623 }
4516f45ec7bSml29623 
4526f45ec7bSml29623 void
nxge_fill_tx_hdr(p_mblk_t mp,boolean_t fill_len,boolean_t l4_cksum,int pkt_len,uint8_t npads,p_tx_pkt_hdr_all_t pkthdrp,t_uscalar_t start_offset,t_uscalar_t stuff_offset)4536f45ec7bSml29623 nxge_fill_tx_hdr(p_mblk_t mp, boolean_t fill_len,
4546f45ec7bSml29623 		boolean_t l4_cksum, int pkt_len, uint8_t npads,
455b4d05839Sml29623 		p_tx_pkt_hdr_all_t pkthdrp,
456b4d05839Sml29623 		t_uscalar_t start_offset,
457b4d05839Sml29623 		t_uscalar_t stuff_offset)
4586f45ec7bSml29623 {
4596f45ec7bSml29623 	p_tx_pkt_header_t	hdrp;
4606f45ec7bSml29623 	p_mblk_t 		nmp;
4616f45ec7bSml29623 	uint64_t		tmp;
4626f45ec7bSml29623 	size_t 			mblk_len;
4636f45ec7bSml29623 	size_t 			iph_len;
4646f45ec7bSml29623 	size_t 			hdrs_size;
4656f45ec7bSml29623 	uint8_t			hdrs_buf[sizeof (struct ether_header) +
4666f45ec7bSml29623 	    64 + sizeof (uint32_t)];
467ae2d3f74Smisaki 	uint8_t			*cursor;
4686f45ec7bSml29623 	uint8_t 		*ip_buf;
4696f45ec7bSml29623 	uint16_t		eth_type;
4706f45ec7bSml29623 	uint8_t			ipproto;
4716f45ec7bSml29623 	boolean_t		is_vlan = B_FALSE;
4726f45ec7bSml29623 	size_t			eth_hdr_size;
4736f45ec7bSml29623 
4746f45ec7bSml29623 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: mp $%p", mp));
4756f45ec7bSml29623 
4766f45ec7bSml29623 	/*
4776f45ec7bSml29623 	 * Caller should zero out the headers first.
4786f45ec7bSml29623 	 */
4796f45ec7bSml29623 	hdrp = (p_tx_pkt_header_t)&pkthdrp->pkthdr;
4806f45ec7bSml29623 
4816f45ec7bSml29623 	if (fill_len) {
4826f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, TX_CTL,
4836f45ec7bSml29623 		    "==> nxge_fill_tx_hdr: pkt_len %d "
4846f45ec7bSml29623 		    "npads %d", pkt_len, npads));
4856f45ec7bSml29623 		tmp = (uint64_t)pkt_len;
4866f45ec7bSml29623 		hdrp->value |= (tmp << TX_PKT_HEADER_TOT_XFER_LEN_SHIFT);
4876f45ec7bSml29623 		goto fill_tx_header_done;
4886f45ec7bSml29623 	}
4896f45ec7bSml29623 
490b4d05839Sml29623 	hdrp->value |= (((uint64_t)npads) << TX_PKT_HEADER_PAD_SHIFT);
4916f45ec7bSml29623 
4926f45ec7bSml29623 	/*
4936f45ec7bSml29623 	 * mp is the original data packet (does not include the
4946f45ec7bSml29623 	 * Neptune transmit header).
4956f45ec7bSml29623 	 */
4966f45ec7bSml29623 	nmp = mp;
4976f45ec7bSml29623 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: "
4986f45ec7bSml29623 	    "mp $%p b_rptr $%p len %d",
499ae2d3f74Smisaki 	    mp, nmp->b_rptr, MBLKL(nmp)));
500ae2d3f74Smisaki 	/* copy ether_header from mblk to hdrs_buf */
501ae2d3f74Smisaki 	cursor = &hdrs_buf[0];
502ae2d3f74Smisaki 	tmp = sizeof (struct ether_vlan_header);
503ae2d3f74Smisaki 	while ((nmp != NULL) && (tmp > 0)) {
504ae2d3f74Smisaki 		size_t buflen;
505ae2d3f74Smisaki 		mblk_len = MBLKL(nmp);
5067c29db66Smisaki 		buflen = min((size_t)tmp, mblk_len);
507ae2d3f74Smisaki 		bcopy(nmp->b_rptr, cursor, buflen);
508ae2d3f74Smisaki 		cursor += buflen;
509ae2d3f74Smisaki 		tmp -= buflen;
510ae2d3f74Smisaki 		nmp = nmp->b_cont;
511ae2d3f74Smisaki 	}
512ae2d3f74Smisaki 
513ae2d3f74Smisaki 	nmp = mp;
514ae2d3f74Smisaki 	mblk_len = MBLKL(nmp);
5156f45ec7bSml29623 	ip_buf = NULL;
5166f45ec7bSml29623 	eth_type = ntohs(((p_ether_header_t)hdrs_buf)->ether_type);
5176f45ec7bSml29623 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> : nxge_fill_tx_hdr: (value 0x%llx) "
5186f45ec7bSml29623 	    "ether type 0x%x", eth_type, hdrp->value));
5196f45ec7bSml29623 
5206f45ec7bSml29623 	if (eth_type < ETHERMTU) {
5216f45ec7bSml29623 		tmp = 1ull;
5226f45ec7bSml29623 		hdrp->value |= (tmp << TX_PKT_HEADER_LLC_SHIFT);
5236f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: LLC "
5246f45ec7bSml29623 		    "value 0x%llx", hdrp->value));
5256f45ec7bSml29623 		if (*(hdrs_buf + sizeof (struct ether_header))
5266f45ec7bSml29623 		    == LLC_SNAP_SAP) {
5276f45ec7bSml29623 			eth_type = ntohs(*((uint16_t *)(hdrs_buf +
5286f45ec7bSml29623 			    sizeof (struct ether_header) + 6)));
5296f45ec7bSml29623 			NXGE_DEBUG_MSG((NULL, TX_CTL,
5306f45ec7bSml29623 			    "==> nxge_tx_pkt_hdr_init: LLC ether type 0x%x",
5316f45ec7bSml29623 			    eth_type));
5326f45ec7bSml29623 		} else {
5336f45ec7bSml29623 			goto fill_tx_header_done;
5346f45ec7bSml29623 		}
5356f45ec7bSml29623 	} else if (eth_type == VLAN_ETHERTYPE) {
5366f45ec7bSml29623 		tmp = 1ull;
5376f45ec7bSml29623 		hdrp->value |= (tmp << TX_PKT_HEADER_VLAN__SHIFT);
5386f45ec7bSml29623 
5396f45ec7bSml29623 		eth_type = ntohs(((struct ether_vlan_header *)
5406f45ec7bSml29623 		    hdrs_buf)->ether_type);
5416f45ec7bSml29623 		is_vlan = B_TRUE;
5426f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: VLAN "
5436f45ec7bSml29623 		    "value 0x%llx", hdrp->value));
5446f45ec7bSml29623 	}
5456f45ec7bSml29623 
5466f45ec7bSml29623 	if (!is_vlan) {
5476f45ec7bSml29623 		eth_hdr_size = sizeof (struct ether_header);
5486f45ec7bSml29623 	} else {
5496f45ec7bSml29623 		eth_hdr_size = sizeof (struct ether_vlan_header);
5506f45ec7bSml29623 	}
5516f45ec7bSml29623 
5526f45ec7bSml29623 	switch (eth_type) {
5536f45ec7bSml29623 	case ETHERTYPE_IP:
5546f45ec7bSml29623 		if (mblk_len > eth_hdr_size + sizeof (uint8_t)) {
5556f45ec7bSml29623 			ip_buf = nmp->b_rptr + eth_hdr_size;
5566f45ec7bSml29623 			mblk_len -= eth_hdr_size;
5576f45ec7bSml29623 			iph_len = ((*ip_buf) & 0x0f);
5586f45ec7bSml29623 			if (mblk_len > (iph_len + sizeof (uint32_t))) {
5596f45ec7bSml29623 				ip_buf = nmp->b_rptr;
5606f45ec7bSml29623 				ip_buf += eth_hdr_size;
5616f45ec7bSml29623 			} else {
5626f45ec7bSml29623 				ip_buf = NULL;
5636f45ec7bSml29623 			}
5646f45ec7bSml29623 
5656f45ec7bSml29623 		}
5666f45ec7bSml29623 		if (ip_buf == NULL) {
5676f45ec7bSml29623 			hdrs_size = 0;
5686f45ec7bSml29623 			((p_ether_header_t)hdrs_buf)->ether_type = 0;
5696f45ec7bSml29623 			while ((nmp) && (hdrs_size <
5706f45ec7bSml29623 			    sizeof (hdrs_buf))) {
5716f45ec7bSml29623 				mblk_len = (size_t)nmp->b_wptr -
5726f45ec7bSml29623 				    (size_t)nmp->b_rptr;
5736f45ec7bSml29623 				if (mblk_len >=
5746f45ec7bSml29623 				    (sizeof (hdrs_buf) - hdrs_size))
5756f45ec7bSml29623 					mblk_len = sizeof (hdrs_buf) -
5766f45ec7bSml29623 					    hdrs_size;
5776f45ec7bSml29623 				bcopy(nmp->b_rptr,
5786f45ec7bSml29623 				    &hdrs_buf[hdrs_size], mblk_len);
5796f45ec7bSml29623 				hdrs_size += mblk_len;
5806f45ec7bSml29623 				nmp = nmp->b_cont;
5816f45ec7bSml29623 			}
5826f45ec7bSml29623 			ip_buf = hdrs_buf;
5836f45ec7bSml29623 			ip_buf += eth_hdr_size;
5846f45ec7bSml29623 			iph_len = ((*ip_buf) & 0x0f);
5856f45ec7bSml29623 		}
5866f45ec7bSml29623 
5876f45ec7bSml29623 		ipproto = ip_buf[9];
5886f45ec7bSml29623 
5896f45ec7bSml29623 		tmp = (uint64_t)iph_len;
5906f45ec7bSml29623 		hdrp->value |= (tmp << TX_PKT_HEADER_IHL_SHIFT);
5916f45ec7bSml29623 		tmp = (uint64_t)(eth_hdr_size >> 1);
5926f45ec7bSml29623 		hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT);
5936f45ec7bSml29623 
5946f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv4 "
5956f45ec7bSml29623 		    " iph_len %d l3start %d eth_hdr_size %d proto 0x%x"
5966f45ec7bSml29623 		    "tmp 0x%x",
5976f45ec7bSml29623 		    iph_len, hdrp->bits.hdw.l3start, eth_hdr_size,
5986f45ec7bSml29623 		    ipproto, tmp));
5996f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IP "
6006f45ec7bSml29623 		    "value 0x%llx", hdrp->value));
6016f45ec7bSml29623 
6026f45ec7bSml29623 		break;
6036f45ec7bSml29623 
6046f45ec7bSml29623 	case ETHERTYPE_IPV6:
6056f45ec7bSml29623 		hdrs_size = 0;
6066f45ec7bSml29623 		((p_ether_header_t)hdrs_buf)->ether_type = 0;
6076f45ec7bSml29623 		while ((nmp) && (hdrs_size <
6086f45ec7bSml29623 		    sizeof (hdrs_buf))) {
6096f45ec7bSml29623 			mblk_len = (size_t)nmp->b_wptr - (size_t)nmp->b_rptr;
6106f45ec7bSml29623 			if (mblk_len >=
6116f45ec7bSml29623 			    (sizeof (hdrs_buf) - hdrs_size))
6126f45ec7bSml29623 				mblk_len = sizeof (hdrs_buf) -
6136f45ec7bSml29623 				    hdrs_size;
6146f45ec7bSml29623 			bcopy(nmp->b_rptr,
6156f45ec7bSml29623 			    &hdrs_buf[hdrs_size], mblk_len);
6166f45ec7bSml29623 			hdrs_size += mblk_len;
6176f45ec7bSml29623 			nmp = nmp->b_cont;
6186f45ec7bSml29623 		}
6196f45ec7bSml29623 		ip_buf = hdrs_buf;
6206f45ec7bSml29623 		ip_buf += eth_hdr_size;
6216f45ec7bSml29623 
6226f45ec7bSml29623 		tmp = 1ull;
6236f45ec7bSml29623 		hdrp->value |= (tmp << TX_PKT_HEADER_IP_VER_SHIFT);
6246f45ec7bSml29623 
6256f45ec7bSml29623 		tmp = (eth_hdr_size >> 1);
6266f45ec7bSml29623 		hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT);
6276f45ec7bSml29623 
6286f45ec7bSml29623 		/* byte 6 is the next header protocol */
6296f45ec7bSml29623 		ipproto = ip_buf[6];
6306f45ec7bSml29623 
6316f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv6 "
6326f45ec7bSml29623 		    " iph_len %d l3start %d eth_hdr_size %d proto 0x%x",
6336f45ec7bSml29623 		    iph_len, hdrp->bits.hdw.l3start, eth_hdr_size,
6346f45ec7bSml29623 		    ipproto));
6356f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IPv6 "
6366f45ec7bSml29623 		    "value 0x%llx", hdrp->value));
6376f45ec7bSml29623 
6386f45ec7bSml29623 		break;
6396f45ec7bSml29623 
6406f45ec7bSml29623 	default:
6416f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: non-IP"));
6426f45ec7bSml29623 		goto fill_tx_header_done;
6436f45ec7bSml29623 	}
6446f45ec7bSml29623 
6456f45ec7bSml29623 	switch (ipproto) {
6466f45ec7bSml29623 	case IPPROTO_TCP:
6476f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, TX_CTL,
6486f45ec7bSml29623 		    "==> nxge_fill_tx_hdr: TCP (cksum flag %d)", l4_cksum));
6496f45ec7bSml29623 		if (l4_cksum) {
650b4d05839Sml29623 			hdrp->value |= TX_CKSUM_EN_PKT_TYPE_TCP;
651b4d05839Sml29623 			hdrp->value |=
652b4d05839Sml29623 			    (((uint64_t)(start_offset >> 1)) <<
653b4d05839Sml29623 			    TX_PKT_HEADER_L4START_SHIFT);
654b4d05839Sml29623 			hdrp->value |=
655b4d05839Sml29623 			    (((uint64_t)(stuff_offset >> 1)) <<
656b4d05839Sml29623 			    TX_PKT_HEADER_L4STUFF_SHIFT);
657b4d05839Sml29623 
6586f45ec7bSml29623 			NXGE_DEBUG_MSG((NULL, TX_CTL,
6596f45ec7bSml29623 			    "==> nxge_tx_pkt_hdr_init: TCP CKSUM "
6606f45ec7bSml29623 			    "value 0x%llx", hdrp->value));
6616f45ec7bSml29623 		}
6626f45ec7bSml29623 
6636f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: TCP "
6646f45ec7bSml29623 		    "value 0x%llx", hdrp->value));
6656f45ec7bSml29623 		break;
6666f45ec7bSml29623 
6676f45ec7bSml29623 	case IPPROTO_UDP:
6686f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: UDP"));
6696f45ec7bSml29623 		if (l4_cksum) {
670b4d05839Sml29623 			if (!nxge_cksum_offload) {
671b4d05839Sml29623 				uint16_t	*up;
672b4d05839Sml29623 				uint16_t	cksum;
673b4d05839Sml29623 				t_uscalar_t	stuff_len;
674b4d05839Sml29623 
675b4d05839Sml29623 				/*
676b4d05839Sml29623 				 * The checksum field has the
677b4d05839Sml29623 				 * partial checksum.
678b4d05839Sml29623 				 * IP_CSUM() macro calls ip_cksum() which
679b4d05839Sml29623 				 * can add in the partial checksum.
680b4d05839Sml29623 				 */
681b4d05839Sml29623 				cksum = IP_CSUM(mp, start_offset, 0);
682b4d05839Sml29623 				stuff_len = stuff_offset;
683b4d05839Sml29623 				nmp = mp;
684b4d05839Sml29623 				mblk_len = MBLKL(nmp);
685b4d05839Sml29623 				while ((nmp != NULL) &&
686b4d05839Sml29623 				    (mblk_len < stuff_len)) {
687b4d05839Sml29623 					stuff_len -= mblk_len;
688b4d05839Sml29623 					nmp = nmp->b_cont;
689ef523517SMichael Speer 					if (nmp)
690ef523517SMichael Speer 						mblk_len = MBLKL(nmp);
6916f45ec7bSml29623 				}
692b4d05839Sml29623 				ASSERT(nmp);
693b4d05839Sml29623 				up = (uint16_t *)(nmp->b_rptr + stuff_len);
694b4d05839Sml29623 
695b4d05839Sml29623 				*up = cksum;
696b4d05839Sml29623 				hdrp->value &= ~TX_CKSUM_EN_PKT_TYPE_UDP;
697b4d05839Sml29623 				NXGE_DEBUG_MSG((NULL, TX_CTL,
698b4d05839Sml29623 				    "==> nxge_tx_pkt_hdr_init: UDP offset %d "
699b4d05839Sml29623 				    "use sw cksum "
700b4d05839Sml29623 				    "write to $%p cksum 0x%x content up 0x%x",
701b4d05839Sml29623 				    stuff_len,
702b4d05839Sml29623 				    up,
703b4d05839Sml29623 				    cksum,
704b4d05839Sml29623 				    *up));
705b4d05839Sml29623 			} else {
706b4d05839Sml29623 				/* Hardware will compute the full checksum */
707b4d05839Sml29623 				hdrp->value |= TX_CKSUM_EN_PKT_TYPE_UDP;
708b4d05839Sml29623 				hdrp->value |=
709b4d05839Sml29623 				    (((uint64_t)(start_offset >> 1)) <<
710b4d05839Sml29623 				    TX_PKT_HEADER_L4START_SHIFT);
711b4d05839Sml29623 				hdrp->value |=
712b4d05839Sml29623 				    (((uint64_t)(stuff_offset >> 1)) <<
713b4d05839Sml29623 				    TX_PKT_HEADER_L4STUFF_SHIFT);
714b4d05839Sml29623 
715b4d05839Sml29623 				NXGE_DEBUG_MSG((NULL, TX_CTL,
716b4d05839Sml29623 				    "==> nxge_tx_pkt_hdr_init: UDP offset %d "
717b4d05839Sml29623 				    " use partial checksum "
718b4d05839Sml29623 				    "cksum 0x%x ",
719b4d05839Sml29623 				    "value 0x%llx",
720b4d05839Sml29623 				    stuff_offset,
721b4d05839Sml29623 				    IP_CSUM(mp, start_offset, 0),
722b4d05839Sml29623 				    hdrp->value));
723b4d05839Sml29623 			}
724b4d05839Sml29623 		}
725b4d05839Sml29623 
7266f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, TX_CTL,
7276f45ec7bSml29623 		    "==> nxge_tx_pkt_hdr_init: UDP"
7286f45ec7bSml29623 		    "value 0x%llx", hdrp->value));
7296f45ec7bSml29623 		break;
7306f45ec7bSml29623 
7316f45ec7bSml29623 	default:
7326f45ec7bSml29623 		goto fill_tx_header_done;
7336f45ec7bSml29623 	}
7346f45ec7bSml29623 
7356f45ec7bSml29623 fill_tx_header_done:
7366f45ec7bSml29623 	NXGE_DEBUG_MSG((NULL, TX_CTL,
7376f45ec7bSml29623 	    "==> nxge_fill_tx_hdr: pkt_len %d  "
7386f45ec7bSml29623 	    "npads %d value 0x%llx", pkt_len, npads, hdrp->value));
7396f45ec7bSml29623 
7406f45ec7bSml29623 	NXGE_DEBUG_MSG((NULL, TX_CTL, "<== nxge_fill_tx_hdr"));
7416f45ec7bSml29623 }
7426f45ec7bSml29623 
7436f45ec7bSml29623 /*ARGSUSED*/
7446f45ec7bSml29623 p_mblk_t
nxge_tx_pkt_header_reserve(p_mblk_t mp,uint8_t * npads)7456f45ec7bSml29623 nxge_tx_pkt_header_reserve(p_mblk_t mp, uint8_t *npads)
7466f45ec7bSml29623 {
7476f45ec7bSml29623 	p_mblk_t 		newmp = NULL;
7486f45ec7bSml29623 
7496f45ec7bSml29623 	if ((newmp = allocb(TX_PKT_HEADER_SIZE, BPRI_MED)) == NULL) {
7506f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, TX_CTL,
7516f45ec7bSml29623 		    "<== nxge_tx_pkt_header_reserve: allocb failed"));
7526f45ec7bSml29623 		return (NULL);
7536f45ec7bSml29623 	}
7546f45ec7bSml29623 
7556f45ec7bSml29623 	NXGE_DEBUG_MSG((NULL, TX_CTL,
7566f45ec7bSml29623 	    "==> nxge_tx_pkt_header_reserve: get new mp"));
7576f45ec7bSml29623 	DB_TYPE(newmp) = M_DATA;
7586f45ec7bSml29623 	newmp->b_rptr = newmp->b_wptr = DB_LIM(newmp);
7596f45ec7bSml29623 	linkb(newmp, mp);
7606f45ec7bSml29623 	newmp->b_rptr -= TX_PKT_HEADER_SIZE;
7616f45ec7bSml29623 
7626f45ec7bSml29623 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==>nxge_tx_pkt_header_reserve: "
7636f45ec7bSml29623 	    "b_rptr $%p b_wptr $%p",
7646f45ec7bSml29623 	    newmp->b_rptr, newmp->b_wptr));
7656f45ec7bSml29623 
7666f45ec7bSml29623 	NXGE_DEBUG_MSG((NULL, TX_CTL,
7676f45ec7bSml29623 	    "<== nxge_tx_pkt_header_reserve: use new mp"));
7686f45ec7bSml29623 
7696f45ec7bSml29623 	return (newmp);
7706f45ec7bSml29623 }
7716f45ec7bSml29623 
7726f45ec7bSml29623 int
nxge_tx_pkt_nmblocks(p_mblk_t mp,int * tot_xfer_len_p)7736f45ec7bSml29623 nxge_tx_pkt_nmblocks(p_mblk_t mp, int *tot_xfer_len_p)
7746f45ec7bSml29623 {
7756f45ec7bSml29623 	uint_t 			nmblks;
7766f45ec7bSml29623 	ssize_t			len;
7776f45ec7bSml29623 	uint_t 			pkt_len;
7786f45ec7bSml29623 	p_mblk_t 		nmp, bmp, tmp;
7796f45ec7bSml29623 	uint8_t 		*b_wptr;
7806f45ec7bSml29623 
7816f45ec7bSml29623 	NXGE_DEBUG_MSG((NULL, TX_CTL,
7826f45ec7bSml29623 	    "==> nxge_tx_pkt_nmblocks: mp $%p rptr $%p wptr $%p "
7836f45ec7bSml29623 	    "len %d", mp, mp->b_rptr, mp->b_wptr, MBLKL(mp)));
7846f45ec7bSml29623 
7856f45ec7bSml29623 	nmp = mp;
7866f45ec7bSml29623 	bmp = mp;
7876f45ec7bSml29623 	nmblks = 0;
7886f45ec7bSml29623 	pkt_len = 0;
7896f45ec7bSml29623 	*tot_xfer_len_p = 0;
7906f45ec7bSml29623 
7916f45ec7bSml29623 	while (nmp) {
7926f45ec7bSml29623 		len = MBLKL(nmp);
7936f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: "
7946f45ec7bSml29623 		    "len %d pkt_len %d nmblks %d tot_xfer_len %d",
7956f45ec7bSml29623 		    len, pkt_len, nmblks,
7966f45ec7bSml29623 		    *tot_xfer_len_p));
7976f45ec7bSml29623 
7986f45ec7bSml29623 		if (len <= 0) {
7996f45ec7bSml29623 			bmp = nmp;
8006f45ec7bSml29623 			nmp = nmp->b_cont;
8016f45ec7bSml29623 			NXGE_DEBUG_MSG((NULL, TX_CTL,
8026f45ec7bSml29623 			    "==> nxge_tx_pkt_nmblocks: "
8036f45ec7bSml29623 			    "len (0) pkt_len %d nmblks %d",
8046f45ec7bSml29623 			    pkt_len, nmblks));
8056f45ec7bSml29623 			continue;
8066f45ec7bSml29623 		}
8076f45ec7bSml29623 
8086f45ec7bSml29623 		*tot_xfer_len_p += len;
8096f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: "
8106f45ec7bSml29623 		    "len %d pkt_len %d nmblks %d tot_xfer_len %d",
8116f45ec7bSml29623 		    len, pkt_len, nmblks,
8126f45ec7bSml29623 		    *tot_xfer_len_p));
8136f45ec7bSml29623 
8146f45ec7bSml29623 		if (len < nxge_bcopy_thresh) {
8156f45ec7bSml29623 			NXGE_DEBUG_MSG((NULL, TX_CTL,
8166f45ec7bSml29623 			    "==> nxge_tx_pkt_nmblocks: "
8176f45ec7bSml29623 			    "len %d (< thresh) pkt_len %d nmblks %d",
8186f45ec7bSml29623 			    len, pkt_len, nmblks));
8196f45ec7bSml29623 			if (pkt_len == 0)
8206f45ec7bSml29623 				nmblks++;
8216f45ec7bSml29623 			pkt_len += len;
8226f45ec7bSml29623 			if (pkt_len >= nxge_bcopy_thresh) {
8236f45ec7bSml29623 				pkt_len = 0;
8246f45ec7bSml29623 				len = 0;
8256f45ec7bSml29623 				nmp = bmp;
8266f45ec7bSml29623 			}
8276f45ec7bSml29623 		} else {
8286f45ec7bSml29623 			NXGE_DEBUG_MSG((NULL, TX_CTL,
8296f45ec7bSml29623 			    "==> nxge_tx_pkt_nmblocks: "
8306f45ec7bSml29623 			    "len %d (> thresh) pkt_len %d nmblks %d",
8316f45ec7bSml29623 			    len, pkt_len, nmblks));
8326f45ec7bSml29623 			pkt_len = 0;
8336f45ec7bSml29623 			nmblks++;
8346f45ec7bSml29623 			/*
8356f45ec7bSml29623 			 * Hardware limits the transfer length to 4K.
8366f45ec7bSml29623 			 * If len is more than 4K, we need to break
8376f45ec7bSml29623 			 * it up to at most 2 more blocks.
8386f45ec7bSml29623 			 */
8396f45ec7bSml29623 			if (len > TX_MAX_TRANSFER_LENGTH) {
8406f45ec7bSml29623 				uint32_t	nsegs;
8416f45ec7bSml29623 
842678453a8Sspeer 				nsegs = 1;
8436f45ec7bSml29623 				NXGE_DEBUG_MSG((NULL, TX_CTL,
8446f45ec7bSml29623 				    "==> nxge_tx_pkt_nmblocks: "
8456f45ec7bSml29623 				    "len %d pkt_len %d nmblks %d nsegs %d",
8466f45ec7bSml29623 				    len, pkt_len, nmblks, nsegs));
8476f45ec7bSml29623 				if (len % (TX_MAX_TRANSFER_LENGTH * 2)) {
8486f45ec7bSml29623 					++nsegs;
8496f45ec7bSml29623 				}
8506f45ec7bSml29623 				do {
8516f45ec7bSml29623 					b_wptr = nmp->b_rptr +
8526f45ec7bSml29623 					    TX_MAX_TRANSFER_LENGTH;
8536f45ec7bSml29623 					nmp->b_wptr = b_wptr;
8546f45ec7bSml29623 					if ((tmp = dupb(nmp)) == NULL) {
8556f45ec7bSml29623 						return (0);
8566f45ec7bSml29623 					}
8576f45ec7bSml29623 					tmp->b_rptr = b_wptr;
8586f45ec7bSml29623 					tmp->b_wptr = nmp->b_wptr;
8596f45ec7bSml29623 					tmp->b_cont = nmp->b_cont;
8606f45ec7bSml29623 					nmp->b_cont = tmp;
8616f45ec7bSml29623 					nmblks++;
8626f45ec7bSml29623 					if (--nsegs) {
8636f45ec7bSml29623 						nmp = tmp;
8646f45ec7bSml29623 					}
8656f45ec7bSml29623 				} while (nsegs);
8666f45ec7bSml29623 				nmp = tmp;
8676f45ec7bSml29623 			}
8686f45ec7bSml29623 		}
8696f45ec7bSml29623 
8706f45ec7bSml29623 		/*
8716f45ec7bSml29623 		 * Hardware limits the transmit gather pointers to 15.
8726f45ec7bSml29623 		 */
8736f45ec7bSml29623 		if (nmp->b_cont && (nmblks + TX_GATHER_POINTERS_THRESHOLD) >
8746f45ec7bSml29623 		    TX_MAX_GATHER_POINTERS) {
8756f45ec7bSml29623 			NXGE_DEBUG_MSG((NULL, TX_CTL,
8766f45ec7bSml29623 			    "==> nxge_tx_pkt_nmblocks: pull msg - "
8776f45ec7bSml29623 			    "len %d pkt_len %d nmblks %d",
8786f45ec7bSml29623 			    len, pkt_len, nmblks));
8796f45ec7bSml29623 			/* Pull all message blocks from b_cont */
8806f45ec7bSml29623 			if ((tmp = msgpullup(nmp->b_cont, -1)) == NULL) {
8816f45ec7bSml29623 				return (0);
8826f45ec7bSml29623 			}
8836f45ec7bSml29623 			freemsg(nmp->b_cont);
8846f45ec7bSml29623 			nmp->b_cont = tmp;
8856f45ec7bSml29623 			pkt_len = 0;
8866f45ec7bSml29623 		}
8876f45ec7bSml29623 		bmp = nmp;
8886f45ec7bSml29623 		nmp = nmp->b_cont;
8896f45ec7bSml29623 	}
8906f45ec7bSml29623 
8916f45ec7bSml29623 	NXGE_DEBUG_MSG((NULL, TX_CTL,
8926f45ec7bSml29623 	    "<== nxge_tx_pkt_nmblocks: rptr $%p wptr $%p "
8936f45ec7bSml29623 	    "nmblks %d len %d tot_xfer_len %d",
8946f45ec7bSml29623 	    mp->b_rptr, mp->b_wptr, nmblks,
8956f45ec7bSml29623 	    MBLKL(mp), *tot_xfer_len_p));
8966f45ec7bSml29623 
8976f45ec7bSml29623 	return (nmblks);
8986f45ec7bSml29623 }
8996f45ec7bSml29623 
9006f45ec7bSml29623 boolean_t
nxge_txdma_reclaim(p_nxge_t nxgep,p_tx_ring_t tx_ring_p,int nmblks)9016f45ec7bSml29623 nxge_txdma_reclaim(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, int nmblks)
9026f45ec7bSml29623 {
9036f45ec7bSml29623 	boolean_t 		status = B_TRUE;
9046f45ec7bSml29623 	p_nxge_dma_common_t	tx_desc_dma_p;
9056f45ec7bSml29623 	nxge_dma_common_t	desc_area;
9066f45ec7bSml29623 	p_tx_desc_t 		tx_desc_ring_vp;
9076f45ec7bSml29623 	p_tx_desc_t 		tx_desc_p;
9086f45ec7bSml29623 	p_tx_desc_t 		tx_desc_pp;
9096f45ec7bSml29623 	tx_desc_t 		r_tx_desc;
9106f45ec7bSml29623 	p_tx_msg_t 		tx_msg_ring;
9116f45ec7bSml29623 	p_tx_msg_t 		tx_msg_p;
9126f45ec7bSml29623 	npi_handle_t		handle;
9136f45ec7bSml29623 	tx_ring_hdl_t		tx_head;
9146f45ec7bSml29623 	uint32_t 		pkt_len;
9156f45ec7bSml29623 	uint_t			tx_rd_index;
9166f45ec7bSml29623 	uint16_t		head_index, tail_index;
9176f45ec7bSml29623 	uint8_t			tdc;
9186f45ec7bSml29623 	boolean_t		head_wrap, tail_wrap;
9196f45ec7bSml29623 	p_nxge_tx_ring_stats_t tdc_stats;
9206f45ec7bSml29623 	int			rc;
9216f45ec7bSml29623 
9226f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_reclaim"));
9236f45ec7bSml29623 
9246f45ec7bSml29623 	status = ((tx_ring_p->descs_pending < nxge_reclaim_pending) &&
9256f45ec7bSml29623 	    (nmblks != 0));
9266f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
9276f45ec7bSml29623 	    "==> nxge_txdma_reclaim: pending %d  reclaim %d nmblks %d",
9286f45ec7bSml29623 	    tx_ring_p->descs_pending, nxge_reclaim_pending,
9296f45ec7bSml29623 	    nmblks));
9306f45ec7bSml29623 	if (!status) {
9316f45ec7bSml29623 		tx_desc_dma_p = &tx_ring_p->tdc_desc;
9326f45ec7bSml29623 		desc_area = tx_ring_p->tdc_desc;
9336f45ec7bSml29623 		handle = NXGE_DEV_NPI_HANDLE(nxgep);
9346f45ec7bSml29623 		tx_desc_ring_vp = tx_desc_dma_p->kaddrp;
9356f45ec7bSml29623 		tx_desc_ring_vp =
9366f45ec7bSml29623 		    (p_tx_desc_t)DMA_COMMON_VPTR(desc_area);
9376f45ec7bSml29623 		tx_rd_index = tx_ring_p->rd_index;
9386f45ec7bSml29623 		tx_desc_p = &tx_desc_ring_vp[tx_rd_index];
9396f45ec7bSml29623 		tx_msg_ring = tx_ring_p->tx_msg_ring;
9406f45ec7bSml29623 		tx_msg_p = &tx_msg_ring[tx_rd_index];
9416f45ec7bSml29623 		tdc = tx_ring_p->tdc;
9426f45ec7bSml29623 		tdc_stats = tx_ring_p->tdc_stats;
9436f45ec7bSml29623 		if (tx_ring_p->descs_pending > tdc_stats->tx_max_pend) {
9446f45ec7bSml29623 			tdc_stats->tx_max_pend = tx_ring_p->descs_pending;
9456f45ec7bSml29623 		}
9466f45ec7bSml29623 
9476f45ec7bSml29623 		tail_index = tx_ring_p->wr_index;
9486f45ec7bSml29623 		tail_wrap = tx_ring_p->wr_index_wrap;
9496f45ec7bSml29623 
9506f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
9516f45ec7bSml29623 		    "==> nxge_txdma_reclaim: tdc %d tx_rd_index %d "
9526f45ec7bSml29623 		    "tail_index %d tail_wrap %d "
9536f45ec7bSml29623 		    "tx_desc_p $%p ($%p) ",
9546f45ec7bSml29623 		    tdc, tx_rd_index, tail_index, tail_wrap,
9556f45ec7bSml29623 		    tx_desc_p, (*(uint64_t *)tx_desc_p)));
9566f45ec7bSml29623 		/*
9576f45ec7bSml29623 		 * Read the hardware maintained transmit head
9586f45ec7bSml29623 		 * and wrap around bit.
9596f45ec7bSml29623 		 */
9606f45ec7bSml29623 		TXDMA_REG_READ64(handle, TX_RING_HDL_REG, tdc, &tx_head.value);
9616f45ec7bSml29623 		head_index =  tx_head.bits.ldw.head;
9626f45ec7bSml29623 		head_wrap = tx_head.bits.ldw.wrap;
9636f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
9646f45ec7bSml29623 		    "==> nxge_txdma_reclaim: "
9656f45ec7bSml29623 		    "tx_rd_index %d tail %d tail_wrap %d "
9666f45ec7bSml29623 		    "head %d wrap %d",
9676f45ec7bSml29623 		    tx_rd_index, tail_index, tail_wrap,
9686f45ec7bSml29623 		    head_index, head_wrap));
9696f45ec7bSml29623 
9706f45ec7bSml29623 		if (head_index == tail_index) {
9716f45ec7bSml29623 			if (TXDMA_RING_EMPTY(head_index, head_wrap,
9726f45ec7bSml29623 			    tail_index, tail_wrap) &&
9736f45ec7bSml29623 			    (head_index == tx_rd_index)) {
9746f45ec7bSml29623 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
9756f45ec7bSml29623 				    "==> nxge_txdma_reclaim: EMPTY"));
9766f45ec7bSml29623 				return (B_TRUE);
9776f45ec7bSml29623 			}
9786f45ec7bSml29623 
9796f45ec7bSml29623 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
9806f45ec7bSml29623 			    "==> nxge_txdma_reclaim: Checking "
9816f45ec7bSml29623 			    "if ring full"));
9826f45ec7bSml29623 			if (TXDMA_RING_FULL(head_index, head_wrap, tail_index,
9836f45ec7bSml29623 			    tail_wrap)) {
9846f45ec7bSml29623 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
9856f45ec7bSml29623 				    "==> nxge_txdma_reclaim: full"));
9866f45ec7bSml29623 				return (B_FALSE);
9876f45ec7bSml29623 			}
9886f45ec7bSml29623 		}
9896f45ec7bSml29623 
9906f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
9916f45ec7bSml29623 		    "==> nxge_txdma_reclaim: tx_rd_index and head_index"));
9926f45ec7bSml29623 
9936f45ec7bSml29623 		tx_desc_pp = &r_tx_desc;
9946f45ec7bSml29623 		while ((tx_rd_index != head_index) &&
9956f45ec7bSml29623 		    (tx_ring_p->descs_pending != 0)) {
9966f45ec7bSml29623 
9976f45ec7bSml29623 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
9986f45ec7bSml29623 			    "==> nxge_txdma_reclaim: Checking if pending"));
9996f45ec7bSml29623 
10006f45ec7bSml29623 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
10016f45ec7bSml29623 			    "==> nxge_txdma_reclaim: "
10026f45ec7bSml29623 			    "descs_pending %d ",
10036f45ec7bSml29623 			    tx_ring_p->descs_pending));
10046f45ec7bSml29623 
10056f45ec7bSml29623 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
10066f45ec7bSml29623 			    "==> nxge_txdma_reclaim: "
10076f45ec7bSml29623 			    "(tx_rd_index %d head_index %d "
10086f45ec7bSml29623 			    "(tx_desc_p $%p)",
10096f45ec7bSml29623 			    tx_rd_index, head_index,
10106f45ec7bSml29623 			    tx_desc_p));
10116f45ec7bSml29623 
10126f45ec7bSml29623 			tx_desc_pp->value = tx_desc_p->value;
10136f45ec7bSml29623 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
10146f45ec7bSml29623 			    "==> nxge_txdma_reclaim: "
10156f45ec7bSml29623 			    "(tx_rd_index %d head_index %d "
10166f45ec7bSml29623 			    "tx_desc_p $%p (desc value 0x%llx) ",
10176f45ec7bSml29623 			    tx_rd_index, head_index,
10186f45ec7bSml29623 			    tx_desc_pp, (*(uint64_t *)tx_desc_pp)));
10196f45ec7bSml29623 
10206f45ec7bSml29623 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
10216f45ec7bSml29623 			    "==> nxge_txdma_reclaim: dump desc:"));
10226f45ec7bSml29623 
10236f45ec7bSml29623 			pkt_len = tx_desc_pp->bits.hdw.tr_len;
10240dc2366fSVenugopal Iyer 			tdc_stats->obytes += (pkt_len - TX_PKT_HEADER_SIZE);
10256f45ec7bSml29623 			tdc_stats->opackets += tx_desc_pp->bits.hdw.sop;
10266f45ec7bSml29623 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
10276f45ec7bSml29623 			    "==> nxge_txdma_reclaim: pkt_len %d "
10286f45ec7bSml29623 			    "tdc channel %d opackets %d",
10296f45ec7bSml29623 			    pkt_len,
10306f45ec7bSml29623 			    tdc,
10316f45ec7bSml29623 			    tdc_stats->opackets));
10326f45ec7bSml29623 
10336f45ec7bSml29623 			if (tx_msg_p->flags.dma_type == USE_DVMA) {
10346f45ec7bSml29623 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
10356f45ec7bSml29623 				    "tx_desc_p = $%p "
10366f45ec7bSml29623 				    "tx_desc_pp = $%p "
10376f45ec7bSml29623 				    "index = %d",
10386f45ec7bSml29623 				    tx_desc_p,
10396f45ec7bSml29623 				    tx_desc_pp,
10406f45ec7bSml29623 				    tx_ring_p->rd_index));
10416f45ec7bSml29623 				(void) dvma_unload(tx_msg_p->dvma_handle,
10426f45ec7bSml29623 				    0, -1);
10436f45ec7bSml29623 				tx_msg_p->dvma_handle = NULL;
10446f45ec7bSml29623 				if (tx_ring_p->dvma_wr_index ==
10456f45ec7bSml29623 				    tx_ring_p->dvma_wrap_mask) {
10466f45ec7bSml29623 					tx_ring_p->dvma_wr_index = 0;
10476f45ec7bSml29623 				} else {
10486f45ec7bSml29623 					tx_ring_p->dvma_wr_index++;
10496f45ec7bSml29623 				}
10506f45ec7bSml29623 				tx_ring_p->dvma_pending--;
10516f45ec7bSml29623 			} else if (tx_msg_p->flags.dma_type ==
10526f45ec7bSml29623 			    USE_DMA) {
10536f45ec7bSml29623 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
10546f45ec7bSml29623 				    "==> nxge_txdma_reclaim: "
10556f45ec7bSml29623 				    "USE DMA"));
10566f45ec7bSml29623 				if (rc = ddi_dma_unbind_handle
10576f45ec7bSml29623 				    (tx_msg_p->dma_handle)) {
10586f45ec7bSml29623 					cmn_err(CE_WARN, "!nxge_reclaim: "
10596f45ec7bSml29623 					    "ddi_dma_unbind_handle "
10606f45ec7bSml29623 					    "failed. status %d", rc);
10616f45ec7bSml29623 				}
10626f45ec7bSml29623 			}
10636f45ec7bSml29623 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
10646f45ec7bSml29623 			    "==> nxge_txdma_reclaim: count packets"));
10656f45ec7bSml29623 			/*
10666f45ec7bSml29623 			 * count a chained packet only once.
10676f45ec7bSml29623 			 */
10686f45ec7bSml29623 			if (tx_msg_p->tx_message != NULL) {
1069da14cebeSEric Cheng 				freemsg(tx_msg_p->tx_message);
1070da14cebeSEric Cheng 				tx_msg_p->tx_message = NULL;
10716f45ec7bSml29623 			}
10726f45ec7bSml29623 
10736f45ec7bSml29623 			tx_msg_p->flags.dma_type = USE_NONE;
10746f45ec7bSml29623 			tx_rd_index = tx_ring_p->rd_index;
10756f45ec7bSml29623 			tx_rd_index = (tx_rd_index + 1) &
10766f45ec7bSml29623 			    tx_ring_p->tx_wrap_mask;
10776f45ec7bSml29623 			tx_ring_p->rd_index = tx_rd_index;
10786f45ec7bSml29623 			tx_ring_p->descs_pending--;
10796f45ec7bSml29623 			tx_desc_p = &tx_desc_ring_vp[tx_rd_index];
10806f45ec7bSml29623 			tx_msg_p = &tx_msg_ring[tx_rd_index];
10816f45ec7bSml29623 		}
10826f45ec7bSml29623 
1083257bdc55SMichael Speer 		status = (nmblks <= ((int)tx_ring_p->tx_ring_size -
1084257bdc55SMichael Speer 		    (int)tx_ring_p->descs_pending - TX_FULL_MARK));
10856f45ec7bSml29623 		if (status) {
1086*75d94465SJosef 'Jeff' Sipek 			(void) atomic_cas_32((uint32_t *)&tx_ring_p->queueing,
1087*75d94465SJosef 'Jeff' Sipek 			    1, 0);
10886f45ec7bSml29623 		}
10896f45ec7bSml29623 	} else {
1090257bdc55SMichael Speer 		status = (nmblks <= ((int)tx_ring_p->tx_ring_size -
1091257bdc55SMichael Speer 		    (int)tx_ring_p->descs_pending - TX_FULL_MARK));
10926f45ec7bSml29623 	}
10936f45ec7bSml29623 
10946f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
10956f45ec7bSml29623 	    "<== nxge_txdma_reclaim status = 0x%08x", status));
10966f45ec7bSml29623 
10976f45ec7bSml29623 	return (status);
10986f45ec7bSml29623 }
10996f45ec7bSml29623 
1100678453a8Sspeer /*
1101678453a8Sspeer  * nxge_tx_intr
1102678453a8Sspeer  *
1103678453a8Sspeer  *	Process a TDC interrupt
1104678453a8Sspeer  *
1105678453a8Sspeer  * Arguments:
1106678453a8Sspeer  * 	arg1	A Logical Device state Vector (LSV) data structure.
1107678453a8Sspeer  * 	arg2	nxge_t *
1108678453a8Sspeer  *
1109678453a8Sspeer  * Notes:
1110678453a8Sspeer  *
1111678453a8Sspeer  * NPI/NXGE function calls:
1112678453a8Sspeer  *	npi_txdma_control_status()
1113678453a8Sspeer  *	npi_intr_ldg_mgmt_set()
1114678453a8Sspeer  *
1115678453a8Sspeer  *	nxge_tx_err_evnts()
1116678453a8Sspeer  *	nxge_txdma_reclaim()
1117678453a8Sspeer  *
1118678453a8Sspeer  * Registers accessed:
1119678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1120678453a8Sspeer  *	PIO_LDSV
1121678453a8Sspeer  *
1122678453a8Sspeer  * Context:
1123678453a8Sspeer  *	Any domain
1124678453a8Sspeer  */
11256f45ec7bSml29623 uint_t
nxge_tx_intr(void * arg1,void * arg2)11266f45ec7bSml29623 nxge_tx_intr(void *arg1, void *arg2)
11276f45ec7bSml29623 {
11286f45ec7bSml29623 	p_nxge_ldv_t		ldvp = (p_nxge_ldv_t)arg1;
11296f45ec7bSml29623 	p_nxge_t		nxgep = (p_nxge_t)arg2;
11306f45ec7bSml29623 	p_nxge_ldg_t		ldgp;
11316f45ec7bSml29623 	uint8_t			channel;
11326f45ec7bSml29623 	uint32_t		vindex;
11336f45ec7bSml29623 	npi_handle_t		handle;
11346f45ec7bSml29623 	tx_cs_t			cs;
11356f45ec7bSml29623 	p_tx_ring_t 		*tx_rings;
11366f45ec7bSml29623 	p_tx_ring_t 		tx_ring_p;
11376f45ec7bSml29623 	npi_status_t		rs = NPI_SUCCESS;
11386f45ec7bSml29623 	uint_t 			serviced = DDI_INTR_UNCLAIMED;
11396f45ec7bSml29623 	nxge_status_t 		status = NXGE_OK;
11406f45ec7bSml29623 
11416f45ec7bSml29623 	if (ldvp == NULL) {
11426f45ec7bSml29623 		NXGE_DEBUG_MSG((NULL, INT_CTL,
11436f45ec7bSml29623 		    "<== nxge_tx_intr: nxgep $%p ldvp $%p",
11446f45ec7bSml29623 		    nxgep, ldvp));
11456f45ec7bSml29623 		return (DDI_INTR_UNCLAIMED);
11466f45ec7bSml29623 	}
11476f45ec7bSml29623 
11486f45ec7bSml29623 	if (arg2 == NULL || (void *)ldvp->nxgep != arg2) {
11496f45ec7bSml29623 		nxgep = ldvp->nxgep;
11506f45ec7bSml29623 	}
11516f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
11526f45ec7bSml29623 	    "==> nxge_tx_intr: nxgep(arg2) $%p ldvp(arg1) $%p",
11536f45ec7bSml29623 	    nxgep, ldvp));
115422c0d73aSspeer 
115522c0d73aSspeer 	if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) ||
115622c0d73aSspeer 	    (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) {
115722c0d73aSspeer 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
115822c0d73aSspeer 		    "<== nxge_tx_intr: interface not started or intialized"));
115922c0d73aSspeer 		return (DDI_INTR_CLAIMED);
116022c0d73aSspeer 	}
116122c0d73aSspeer 
11626f45ec7bSml29623 	/*
11636f45ec7bSml29623 	 * This interrupt handler is for a specific
11646f45ec7bSml29623 	 * transmit dma channel.
11656f45ec7bSml29623 	 */
11666f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
11676f45ec7bSml29623 	/* Get the control and status for this channel. */
11686f45ec7bSml29623 	channel = ldvp->channel;
11696f45ec7bSml29623 	ldgp = ldvp->ldgp;
11706f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
11716f45ec7bSml29623 	    "==> nxge_tx_intr: nxgep $%p ldvp (ldvp) $%p "
11726f45ec7bSml29623 	    "channel %d",
11736f45ec7bSml29623 	    nxgep, ldvp, channel));
11746f45ec7bSml29623 
11756f45ec7bSml29623 	rs = npi_txdma_control_status(handle, OP_GET, channel, &cs);
11766f45ec7bSml29623 	vindex = ldvp->vdma_index;
11776f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
11786f45ec7bSml29623 	    "==> nxge_tx_intr:channel %d ring index %d status 0x%08x",
11796f45ec7bSml29623 	    channel, vindex, rs));
11806f45ec7bSml29623 	if (!rs && cs.bits.ldw.mk) {
11816f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
11826f45ec7bSml29623 		    "==> nxge_tx_intr:channel %d ring index %d "
11836f45ec7bSml29623 		    "status 0x%08x (mk bit set)",
11846f45ec7bSml29623 		    channel, vindex, rs));
11856f45ec7bSml29623 		tx_rings = nxgep->tx_rings->rings;
11866f45ec7bSml29623 		tx_ring_p = tx_rings[vindex];
11876f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
11886f45ec7bSml29623 		    "==> nxge_tx_intr:channel %d ring index %d "
11896f45ec7bSml29623 		    "status 0x%08x (mk bit set, calling reclaim)",
11906f45ec7bSml29623 		    channel, vindex, rs));
11916f45ec7bSml29623 
1192da14cebeSEric Cheng 		nxge_tx_ring_task((void *)tx_ring_p);
11936f45ec7bSml29623 	}
11946f45ec7bSml29623 
11956f45ec7bSml29623 	/*
11966f45ec7bSml29623 	 * Process other transmit control and status.
11976f45ec7bSml29623 	 * Check the ldv state.
11986f45ec7bSml29623 	 */
11996f45ec7bSml29623 	status = nxge_tx_err_evnts(nxgep, ldvp->vdma_index, ldvp, cs);
12006f45ec7bSml29623 	/*
12016f45ec7bSml29623 	 * Rearm this logical group if this is a single device
12026f45ec7bSml29623 	 * group.
12036f45ec7bSml29623 	 */
12046f45ec7bSml29623 	if (ldgp->nldvs == 1) {
12056f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
12066f45ec7bSml29623 		    "==> nxge_tx_intr: rearm"));
12076f45ec7bSml29623 		if (status == NXGE_OK) {
1208678453a8Sspeer 			if (isLDOMguest(nxgep)) {
1209678453a8Sspeer 				nxge_hio_ldgimgn(nxgep, ldgp);
1210678453a8Sspeer 			} else {
12116f45ec7bSml29623 				(void) npi_intr_ldg_mgmt_set(handle, ldgp->ldg,
12126f45ec7bSml29623 				    B_TRUE, ldgp->ldg_timer);
12136f45ec7bSml29623 			}
12146f45ec7bSml29623 		}
1215678453a8Sspeer 	}
12166f45ec7bSml29623 
12176f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_tx_intr"));
12186f45ec7bSml29623 	serviced = DDI_INTR_CLAIMED;
12196f45ec7bSml29623 	return (serviced);
12206f45ec7bSml29623 }
12216f45ec7bSml29623 
12226f45ec7bSml29623 void
nxge_txdma_stop(p_nxge_t nxgep)1223678453a8Sspeer nxge_txdma_stop(p_nxge_t nxgep)	/* Dead */
12246f45ec7bSml29623 {
12256f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop"));
12266f45ec7bSml29623 
12276f45ec7bSml29623 	(void) nxge_link_monitor(nxgep, LINK_MONITOR_STOP);
12286f45ec7bSml29623 
12296f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop"));
12306f45ec7bSml29623 }
12316f45ec7bSml29623 
12326f45ec7bSml29623 void
nxge_txdma_stop_start(p_nxge_t nxgep)1233678453a8Sspeer nxge_txdma_stop_start(p_nxge_t nxgep) /* Dead */
12346f45ec7bSml29623 {
12356f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_start"));
12366f45ec7bSml29623 
12376f45ec7bSml29623 	(void) nxge_txdma_stop(nxgep);
12386f45ec7bSml29623 
12396f45ec7bSml29623 	(void) nxge_fixup_txdma_rings(nxgep);
12406f45ec7bSml29623 	(void) nxge_txdma_hw_mode(nxgep, NXGE_DMA_START);
12416f45ec7bSml29623 	(void) nxge_tx_mac_enable(nxgep);
12426f45ec7bSml29623 	(void) nxge_txdma_hw_kick(nxgep);
12436f45ec7bSml29623 
12446f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_start"));
12456f45ec7bSml29623 }
12466f45ec7bSml29623 
1247678453a8Sspeer npi_status_t
nxge_txdma_channel_disable(nxge_t * nxge,int channel)1248678453a8Sspeer nxge_txdma_channel_disable(
1249678453a8Sspeer 	nxge_t *nxge,
1250678453a8Sspeer 	int channel)
1251678453a8Sspeer {
1252678453a8Sspeer 	npi_handle_t	handle = NXGE_DEV_NPI_HANDLE(nxge);
1253678453a8Sspeer 	npi_status_t	rs;
1254678453a8Sspeer 	tdmc_intr_dbg_t	intr_dbg;
1255678453a8Sspeer 
1256678453a8Sspeer 	/*
1257678453a8Sspeer 	 * Stop the dma channel and wait for the stop-done.
1258678453a8Sspeer 	 * If the stop-done bit is not present, then force
1259678453a8Sspeer 	 * an error so TXC will stop.
1260678453a8Sspeer 	 * All channels bound to this port need to be stopped
1261678453a8Sspeer 	 * and reset after injecting an interrupt error.
1262678453a8Sspeer 	 */
1263678453a8Sspeer 	rs = npi_txdma_channel_disable(handle, channel);
1264678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, MEM3_CTL,
1265678453a8Sspeer 	    "==> nxge_txdma_channel_disable(%d) "
1266678453a8Sspeer 	    "rs 0x%x", channel, rs));
1267678453a8Sspeer 	if (rs != NPI_SUCCESS) {
1268678453a8Sspeer 		/* Inject any error */
1269678453a8Sspeer 		intr_dbg.value = 0;
1270678453a8Sspeer 		intr_dbg.bits.ldw.nack_pref = 1;
1271678453a8Sspeer 		NXGE_DEBUG_MSG((nxge, MEM3_CTL,
1272678453a8Sspeer 		    "==> nxge_txdma_hw_mode: "
1273678453a8Sspeer 		    "channel %d (stop failed 0x%x) "
1274678453a8Sspeer 		    "(inject err)", rs, channel));
1275678453a8Sspeer 		(void) npi_txdma_inj_int_error_set(
1276678453a8Sspeer 		    handle, channel, &intr_dbg);
1277678453a8Sspeer 		rs = npi_txdma_channel_disable(handle, channel);
1278678453a8Sspeer 		NXGE_DEBUG_MSG((nxge, MEM3_CTL,
1279678453a8Sspeer 		    "==> nxge_txdma_hw_mode: "
1280678453a8Sspeer 		    "channel %d (stop again 0x%x) "
1281678453a8Sspeer 		    "(after inject err)",
1282678453a8Sspeer 		    rs, channel));
1283678453a8Sspeer 	}
1284678453a8Sspeer 
1285678453a8Sspeer 	return (rs);
1286678453a8Sspeer }
1287678453a8Sspeer 
1288678453a8Sspeer /*
1289678453a8Sspeer  * nxge_txdma_hw_mode
1290678453a8Sspeer  *
1291678453a8Sspeer  *	Toggle all TDCs on (enable) or off (disable).
1292678453a8Sspeer  *
1293678453a8Sspeer  * Arguments:
1294678453a8Sspeer  * 	nxgep
1295678453a8Sspeer  * 	enable	Enable or disable a TDC.
1296678453a8Sspeer  *
1297678453a8Sspeer  * Notes:
1298678453a8Sspeer  *
1299678453a8Sspeer  * NPI/NXGE function calls:
1300678453a8Sspeer  *	npi_txdma_channel_enable(TX_CS)
1301678453a8Sspeer  *	npi_txdma_channel_disable(TX_CS)
1302678453a8Sspeer  *	npi_txdma_inj_int_error_set(TDMC_INTR_DBG)
1303678453a8Sspeer  *
1304678453a8Sspeer  * Registers accessed:
1305678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1306678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
1307678453a8Sspeer  *
1308678453a8Sspeer  * Context:
1309678453a8Sspeer  *	Any domain
1310678453a8Sspeer  */
13116f45ec7bSml29623 nxge_status_t
nxge_txdma_hw_mode(p_nxge_t nxgep,boolean_t enable)13126f45ec7bSml29623 nxge_txdma_hw_mode(p_nxge_t nxgep, boolean_t enable)
13136f45ec7bSml29623 {
1314678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1315678453a8Sspeer 
13166f45ec7bSml29623 	npi_handle_t	handle;
1317678453a8Sspeer 	nxge_status_t	status;
1318678453a8Sspeer 	npi_status_t	rs;
1319678453a8Sspeer 	int		tdc;
13206f45ec7bSml29623 
13216f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
13226f45ec7bSml29623 	    "==> nxge_txdma_hw_mode: enable mode %d", enable));
13236f45ec7bSml29623 
13246f45ec7bSml29623 	if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) {
13256f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
13266f45ec7bSml29623 		    "<== nxge_txdma_mode: not initialized"));
13276f45ec7bSml29623 		return (NXGE_ERROR);
13286f45ec7bSml29623 	}
13296f45ec7bSml29623 
1330678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
13316f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1332678453a8Sspeer 		    "<== nxge_txdma_hw_mode: NULL ring pointer(s)"));
13336f45ec7bSml29623 		return (NXGE_ERROR);
13346f45ec7bSml29623 	}
13356f45ec7bSml29623 
1336678453a8Sspeer 	/* Enable or disable all of the TDCs owned by us. */
13376f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
1338678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1339678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1340678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1341678453a8Sspeer 			if (ring) {
13426f45ec7bSml29623 				NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1343678453a8Sspeer 				    "==> nxge_txdma_hw_mode: channel %d", tdc));
13446f45ec7bSml29623 				if (enable) {
1345678453a8Sspeer 					rs = npi_txdma_channel_enable
1346678453a8Sspeer 					    (handle, tdc);
13476f45ec7bSml29623 					NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1348678453a8Sspeer 					    "==> nxge_txdma_hw_mode: "
1349678453a8Sspeer 					    "channel %d (enable) rs 0x%x",
1350678453a8Sspeer 					    tdc, rs));
13516f45ec7bSml29623 				} else {
1352678453a8Sspeer 					rs = nxge_txdma_channel_disable
1353678453a8Sspeer 					    (nxgep, tdc);
13546f45ec7bSml29623 				}
13556f45ec7bSml29623 			}
13566f45ec7bSml29623 		}
13576f45ec7bSml29623 	}
13586f45ec7bSml29623 
13596f45ec7bSml29623 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
13606f45ec7bSml29623 
13616f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
13626f45ec7bSml29623 	    "<== nxge_txdma_hw_mode: status 0x%x", status));
13636f45ec7bSml29623 
13646f45ec7bSml29623 	return (status);
13656f45ec7bSml29623 }
13666f45ec7bSml29623 
13676f45ec7bSml29623 void
nxge_txdma_enable_channel(p_nxge_t nxgep,uint16_t channel)13686f45ec7bSml29623 nxge_txdma_enable_channel(p_nxge_t nxgep, uint16_t channel)
13696f45ec7bSml29623 {
13706f45ec7bSml29623 	npi_handle_t		handle;
13716f45ec7bSml29623 
13726f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, DMA_CTL,
13736f45ec7bSml29623 	    "==> nxge_txdma_enable_channel: channel %d", channel));
13746f45ec7bSml29623 
13756f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
13766f45ec7bSml29623 	/* enable the transmit dma channels */
13776f45ec7bSml29623 	(void) npi_txdma_channel_enable(handle, channel);
13786f45ec7bSml29623 
13796f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, DMA_CTL, "<== nxge_txdma_enable_channel"));
13806f45ec7bSml29623 }
13816f45ec7bSml29623 
13826f45ec7bSml29623 void
nxge_txdma_disable_channel(p_nxge_t nxgep,uint16_t channel)13836f45ec7bSml29623 nxge_txdma_disable_channel(p_nxge_t nxgep, uint16_t channel)
13846f45ec7bSml29623 {
13856f45ec7bSml29623 	npi_handle_t		handle;
13866f45ec7bSml29623 
13876f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, DMA_CTL,
13886f45ec7bSml29623 	    "==> nxge_txdma_disable_channel: channel %d", channel));
13896f45ec7bSml29623 
13906f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
13916f45ec7bSml29623 	/* stop the transmit dma channels */
13926f45ec7bSml29623 	(void) npi_txdma_channel_disable(handle, channel);
13936f45ec7bSml29623 
13946f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_disable_channel"));
13956f45ec7bSml29623 }
13966f45ec7bSml29623 
1397678453a8Sspeer /*
1398678453a8Sspeer  * nxge_txdma_stop_inj_err
1399678453a8Sspeer  *
1400678453a8Sspeer  *	Stop a TDC.  If at first we don't succeed, inject an error.
1401678453a8Sspeer  *
1402678453a8Sspeer  * Arguments:
1403678453a8Sspeer  * 	nxgep
1404678453a8Sspeer  * 	channel		The channel to stop.
1405678453a8Sspeer  *
1406678453a8Sspeer  * Notes:
1407678453a8Sspeer  *
1408678453a8Sspeer  * NPI/NXGE function calls:
1409678453a8Sspeer  *	npi_txdma_channel_disable()
1410678453a8Sspeer  *	npi_txdma_inj_int_error_set()
1411678453a8Sspeer  * #if defined(NXGE_DEBUG)
1412678453a8Sspeer  *	nxge_txdma_regs_dump_channels(nxgep);
1413678453a8Sspeer  * #endif
1414678453a8Sspeer  *
1415678453a8Sspeer  * Registers accessed:
1416678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1417678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
1418678453a8Sspeer  *
1419678453a8Sspeer  * Context:
1420678453a8Sspeer  *	Any domain
1421678453a8Sspeer  */
14226f45ec7bSml29623 int
nxge_txdma_stop_inj_err(p_nxge_t nxgep,int channel)14236f45ec7bSml29623 nxge_txdma_stop_inj_err(p_nxge_t nxgep, int channel)
14246f45ec7bSml29623 {
14256f45ec7bSml29623 	npi_handle_t		handle;
14266f45ec7bSml29623 	tdmc_intr_dbg_t		intr_dbg;
14276f45ec7bSml29623 	int			status;
14286f45ec7bSml29623 	npi_status_t		rs = NPI_SUCCESS;
14296f45ec7bSml29623 
14306f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_inj_err"));
14316f45ec7bSml29623 	/*
14326f45ec7bSml29623 	 * Stop the dma channel waits for the stop done.
14336f45ec7bSml29623 	 * If the stop done bit is not set, then create
14346f45ec7bSml29623 	 * an error.
14356f45ec7bSml29623 	 */
14366f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
14376f45ec7bSml29623 	rs = npi_txdma_channel_disable(handle, channel);
14386f45ec7bSml29623 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
14396f45ec7bSml29623 	if (status == NXGE_OK) {
14406f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
14416f45ec7bSml29623 		    "<== nxge_txdma_stop_inj_err (channel %d): "
14426f45ec7bSml29623 		    "stopped OK", channel));
14436f45ec7bSml29623 		return (status);
14446f45ec7bSml29623 	}
14456f45ec7bSml29623 
14466f45ec7bSml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
14476f45ec7bSml29623 	    "==> nxge_txdma_stop_inj_err (channel %d): stop failed (0x%x) "
14486f45ec7bSml29623 	    "injecting error", channel, rs));
14496f45ec7bSml29623 	/* Inject any error */
14506f45ec7bSml29623 	intr_dbg.value = 0;
14516f45ec7bSml29623 	intr_dbg.bits.ldw.nack_pref = 1;
14526f45ec7bSml29623 	(void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg);
14536f45ec7bSml29623 
14546f45ec7bSml29623 	/* Stop done bit will be set as a result of error injection */
14556f45ec7bSml29623 	rs = npi_txdma_channel_disable(handle, channel);
14566f45ec7bSml29623 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
14576f45ec7bSml29623 	if (!(rs & NPI_TXDMA_STOP_FAILED)) {
14586f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
14596f45ec7bSml29623 		    "<== nxge_txdma_stop_inj_err (channel %d): "
14606f45ec7bSml29623 		    "stopped OK ", channel));
14616f45ec7bSml29623 		return (status);
14626f45ec7bSml29623 	}
14636f45ec7bSml29623 
14646f45ec7bSml29623 #if	defined(NXGE_DEBUG)
14656f45ec7bSml29623 	nxge_txdma_regs_dump_channels(nxgep);
14666f45ec7bSml29623 #endif
14676f45ec7bSml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
14686f45ec7bSml29623 	    "==> nxge_txdma_stop_inj_err (channel): stop failed (0x%x) "
14696f45ec7bSml29623 	    " (injected error but still not stopped)", channel, rs));
14706f45ec7bSml29623 
14716f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_inj_err"));
14726f45ec7bSml29623 	return (status);
14736f45ec7bSml29623 }
14746f45ec7bSml29623 
14756f45ec7bSml29623 /*ARGSUSED*/
14766f45ec7bSml29623 void
nxge_fixup_txdma_rings(p_nxge_t nxgep)14776f45ec7bSml29623 nxge_fixup_txdma_rings(p_nxge_t nxgep)
14786f45ec7bSml29623 {
1479678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1480678453a8Sspeer 	int tdc;
14816f45ec7bSml29623 
14826f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_txdma_rings"));
14836f45ec7bSml29623 
1484678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
1485678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1486678453a8Sspeer 		    "<== nxge_fixup_txdma_rings: NULL ring pointer(s)"));
14876f45ec7bSml29623 		return;
14886f45ec7bSml29623 	}
14896f45ec7bSml29623 
1490678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1491678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1492678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1493678453a8Sspeer 			if (ring) {
14946f45ec7bSml29623 				NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1495678453a8Sspeer 				    "==> nxge_fixup_txdma_rings: channel %d",
1496678453a8Sspeer 				    tdc));
1497678453a8Sspeer 				nxge_txdma_fixup_channel(nxgep, ring, tdc);
14986f45ec7bSml29623 			}
14996f45ec7bSml29623 		}
15006f45ec7bSml29623 	}
15016f45ec7bSml29623 
15026f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_txdma_rings"));
15036f45ec7bSml29623 }
15046f45ec7bSml29623 
15056f45ec7bSml29623 /*ARGSUSED*/
15066f45ec7bSml29623 void
nxge_txdma_fix_channel(p_nxge_t nxgep,uint16_t channel)15076f45ec7bSml29623 nxge_txdma_fix_channel(p_nxge_t nxgep, uint16_t channel)
15086f45ec7bSml29623 {
15096f45ec7bSml29623 	p_tx_ring_t	ring_p;
15106f45ec7bSml29623 
15116f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_channel"));
15126f45ec7bSml29623 	ring_p = nxge_txdma_get_ring(nxgep, channel);
15136f45ec7bSml29623 	if (ring_p == NULL) {
15146f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel"));
15156f45ec7bSml29623 		return;
15166f45ec7bSml29623 	}
15176f45ec7bSml29623 
15186f45ec7bSml29623 	if (ring_p->tdc != channel) {
15196f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
15206f45ec7bSml29623 		    "<== nxge_txdma_fix_channel: channel not matched "
15216f45ec7bSml29623 		    "ring tdc %d passed channel",
15226f45ec7bSml29623 		    ring_p->tdc, channel));
15236f45ec7bSml29623 		return;
15246f45ec7bSml29623 	}
15256f45ec7bSml29623 
15266f45ec7bSml29623 	nxge_txdma_fixup_channel(nxgep, ring_p, channel);
15276f45ec7bSml29623 
15286f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel"));
15296f45ec7bSml29623 }
15306f45ec7bSml29623 
15316f45ec7bSml29623 /*ARGSUSED*/
15326f45ec7bSml29623 void
nxge_txdma_fixup_channel(p_nxge_t nxgep,p_tx_ring_t ring_p,uint16_t channel)15336f45ec7bSml29623 nxge_txdma_fixup_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel)
15346f45ec7bSml29623 {
15356f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_channel"));
15366f45ec7bSml29623 
15376f45ec7bSml29623 	if (ring_p == NULL) {
15386f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
15396f45ec7bSml29623 		    "<== nxge_txdma_fixup_channel: NULL ring pointer"));
15406f45ec7bSml29623 		return;
15416f45ec7bSml29623 	}
15426f45ec7bSml29623 
15436f45ec7bSml29623 	if (ring_p->tdc != channel) {
15446f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
15456f45ec7bSml29623 		    "<== nxge_txdma_fixup_channel: channel not matched "
15466f45ec7bSml29623 		    "ring tdc %d passed channel",
15476f45ec7bSml29623 		    ring_p->tdc, channel));
15486f45ec7bSml29623 		return;
15496f45ec7bSml29623 	}
15506f45ec7bSml29623 
15516f45ec7bSml29623 	MUTEX_ENTER(&ring_p->lock);
15526f45ec7bSml29623 	(void) nxge_txdma_reclaim(nxgep, ring_p, 0);
15536f45ec7bSml29623 	ring_p->rd_index = 0;
15546f45ec7bSml29623 	ring_p->wr_index = 0;
15556f45ec7bSml29623 	ring_p->ring_head.value = 0;
15566f45ec7bSml29623 	ring_p->ring_kick_tail.value = 0;
15576f45ec7bSml29623 	ring_p->descs_pending = 0;
15586f45ec7bSml29623 	MUTEX_EXIT(&ring_p->lock);
15596f45ec7bSml29623 
15606f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_channel"));
15616f45ec7bSml29623 }
15626f45ec7bSml29623 
15636f45ec7bSml29623 /*ARGSUSED*/
15646f45ec7bSml29623 void
nxge_txdma_hw_kick(p_nxge_t nxgep)15656f45ec7bSml29623 nxge_txdma_hw_kick(p_nxge_t nxgep)
15666f45ec7bSml29623 {
1567678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1568678453a8Sspeer 	int tdc;
15696f45ec7bSml29623 
15706f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick"));
15716f45ec7bSml29623 
1572678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
15736f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1574678453a8Sspeer 		    "<== nxge_txdma_hw_kick: NULL ring pointer(s)"));
15756f45ec7bSml29623 		return;
15766f45ec7bSml29623 	}
15776f45ec7bSml29623 
1578678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1579678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1580678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1581678453a8Sspeer 			if (ring) {
15826f45ec7bSml29623 				NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1583678453a8Sspeer 				    "==> nxge_txdma_hw_kick: channel %d", tdc));
1584678453a8Sspeer 				nxge_txdma_hw_kick_channel(nxgep, ring, tdc);
1585678453a8Sspeer 			}
1586678453a8Sspeer 		}
15876f45ec7bSml29623 	}
15886f45ec7bSml29623 
15896f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick"));
15906f45ec7bSml29623 }
15916f45ec7bSml29623 
15926f45ec7bSml29623 /*ARGSUSED*/
15936f45ec7bSml29623 void
nxge_txdma_kick_channel(p_nxge_t nxgep,uint16_t channel)15946f45ec7bSml29623 nxge_txdma_kick_channel(p_nxge_t nxgep, uint16_t channel)
15956f45ec7bSml29623 {
15966f45ec7bSml29623 	p_tx_ring_t	ring_p;
15976f45ec7bSml29623 
15986f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_kick_channel"));
15996f45ec7bSml29623 
16006f45ec7bSml29623 	ring_p = nxge_txdma_get_ring(nxgep, channel);
16016f45ec7bSml29623 	if (ring_p == NULL) {
16026f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
16036f45ec7bSml29623 		    " nxge_txdma_kick_channel"));
16046f45ec7bSml29623 		return;
16056f45ec7bSml29623 	}
16066f45ec7bSml29623 
16076f45ec7bSml29623 	if (ring_p->tdc != channel) {
16086f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
16096f45ec7bSml29623 		    "<== nxge_txdma_kick_channel: channel not matched "
16106f45ec7bSml29623 		    "ring tdc %d passed channel",
16116f45ec7bSml29623 		    ring_p->tdc, channel));
16126f45ec7bSml29623 		return;
16136f45ec7bSml29623 	}
16146f45ec7bSml29623 
16156f45ec7bSml29623 	nxge_txdma_hw_kick_channel(nxgep, ring_p, channel);
16166f45ec7bSml29623 
16176f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_kick_channel"));
16186f45ec7bSml29623 }
16196f45ec7bSml29623 
16206f45ec7bSml29623 /*ARGSUSED*/
16216f45ec7bSml29623 void
nxge_txdma_hw_kick_channel(p_nxge_t nxgep,p_tx_ring_t ring_p,uint16_t channel)16226f45ec7bSml29623 nxge_txdma_hw_kick_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel)
16236f45ec7bSml29623 {
16246f45ec7bSml29623 
16256f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick_channel"));
16266f45ec7bSml29623 
16276f45ec7bSml29623 	if (ring_p == NULL) {
16286f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
16296f45ec7bSml29623 		    "<== nxge_txdma_hw_kick_channel: NULL ring pointer"));
16306f45ec7bSml29623 		return;
16316f45ec7bSml29623 	}
16326f45ec7bSml29623 
16336f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick_channel"));
16346f45ec7bSml29623 }
16356f45ec7bSml29623 
1636678453a8Sspeer /*
1637678453a8Sspeer  * nxge_check_tx_hang
1638678453a8Sspeer  *
1639678453a8Sspeer  *	Check the state of all TDCs belonging to nxgep.
1640678453a8Sspeer  *
1641678453a8Sspeer  * Arguments:
1642678453a8Sspeer  * 	nxgep
1643678453a8Sspeer  *
1644678453a8Sspeer  * Notes:
1645678453a8Sspeer  *	Called by nxge_hw.c:nxge_check_hw_state().
1646678453a8Sspeer  *
1647678453a8Sspeer  * NPI/NXGE function calls:
1648678453a8Sspeer  *
1649678453a8Sspeer  * Registers accessed:
1650678453a8Sspeer  *
1651678453a8Sspeer  * Context:
1652678453a8Sspeer  *	Any domain
1653678453a8Sspeer  */
16546f45ec7bSml29623 /*ARGSUSED*/
16556f45ec7bSml29623 void
nxge_check_tx_hang(p_nxge_t nxgep)16566f45ec7bSml29623 nxge_check_tx_hang(p_nxge_t nxgep)
16576f45ec7bSml29623 {
16586f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_check_tx_hang"));
16596f45ec7bSml29623 
166022c0d73aSspeer 	if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) ||
166122c0d73aSspeer 	    (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) {
166222c0d73aSspeer 		goto nxge_check_tx_hang_exit;
166322c0d73aSspeer 	}
166422c0d73aSspeer 
16656f45ec7bSml29623 	/*
16666f45ec7bSml29623 	 * Needs inputs from hardware for regs:
16676f45ec7bSml29623 	 *	head index had not moved since last timeout.
16686f45ec7bSml29623 	 *	packets not transmitted or stuffed registers.
16696f45ec7bSml29623 	 */
16706f45ec7bSml29623 	if (nxge_txdma_hung(nxgep)) {
16716f45ec7bSml29623 		nxge_fixup_hung_txdma_rings(nxgep);
16726f45ec7bSml29623 	}
167322c0d73aSspeer 
167422c0d73aSspeer nxge_check_tx_hang_exit:
16756f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_check_tx_hang"));
16766f45ec7bSml29623 }
16776f45ec7bSml29623 
1678678453a8Sspeer /*
1679678453a8Sspeer  * nxge_txdma_hung
1680678453a8Sspeer  *
1681678453a8Sspeer  *	Reset a TDC.
1682678453a8Sspeer  *
1683678453a8Sspeer  * Arguments:
1684678453a8Sspeer  * 	nxgep
1685678453a8Sspeer  * 	channel		The channel to reset.
1686678453a8Sspeer  * 	reg_data	The current TX_CS.
1687678453a8Sspeer  *
1688678453a8Sspeer  * Notes:
1689678453a8Sspeer  *	Called by nxge_check_tx_hang()
1690678453a8Sspeer  *
1691678453a8Sspeer  * NPI/NXGE function calls:
1692678453a8Sspeer  *	nxge_txdma_channel_hung()
1693678453a8Sspeer  *
1694678453a8Sspeer  * Registers accessed:
1695678453a8Sspeer  *
1696678453a8Sspeer  * Context:
1697678453a8Sspeer  *	Any domain
1698678453a8Sspeer  */
16996f45ec7bSml29623 int
nxge_txdma_hung(p_nxge_t nxgep)17006f45ec7bSml29623 nxge_txdma_hung(p_nxge_t nxgep)
17016f45ec7bSml29623 {
1702678453a8Sspeer 	nxge_grp_set_t	*set = &nxgep->tx_set;
1703678453a8Sspeer 	int		tdc;
1704330cd344SMichael Speer 	boolean_t	shared;
17056f45ec7bSml29623 
17066f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hung"));
1707678453a8Sspeer 
1708678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
17096f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1710678453a8Sspeer 		    "<== nxge_txdma_hung: NULL ring pointer(s)"));
17116f45ec7bSml29623 		return (B_FALSE);
17126f45ec7bSml29623 	}
17136f45ec7bSml29623 
1714678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1715330cd344SMichael Speer 		/*
1716330cd344SMichael Speer 		 * Grab the shared state of the TDC.
1717330cd344SMichael Speer 		 */
1718330cd344SMichael Speer 		if (isLDOMservice(nxgep)) {
1719330cd344SMichael Speer 			nxge_hio_data_t *nhd =
1720330cd344SMichael Speer 			    (nxge_hio_data_t *)nxgep->nxge_hw_p->hio;
1721330cd344SMichael Speer 
1722330cd344SMichael Speer 			MUTEX_ENTER(&nhd->lock);
1723330cd344SMichael Speer 			shared = nxgep->tdc_is_shared[tdc];
1724330cd344SMichael Speer 			MUTEX_EXIT(&nhd->lock);
1725330cd344SMichael Speer 		} else {
1726330cd344SMichael Speer 			shared = B_FALSE;
1727330cd344SMichael Speer 		}
1728330cd344SMichael Speer 
1729330cd344SMichael Speer 		/*
1730330cd344SMichael Speer 		 * Now, process continue to process.
1731330cd344SMichael Speer 		 */
1732330cd344SMichael Speer 		if (((1 << tdc) & set->owned.map) && !shared) {
1733678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1734678453a8Sspeer 			if (ring) {
1735678453a8Sspeer 				if (nxge_txdma_channel_hung(nxgep, ring, tdc)) {
17366f45ec7bSml29623 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
1737678453a8Sspeer 					    "==> nxge_txdma_hung: TDC %d hung",
1738678453a8Sspeer 					    tdc));
17396f45ec7bSml29623 					return (B_TRUE);
17406f45ec7bSml29623 				}
17416f45ec7bSml29623 			}
1742678453a8Sspeer 		}
1743678453a8Sspeer 	}
17446f45ec7bSml29623 
17456f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hung"));
17466f45ec7bSml29623 
17476f45ec7bSml29623 	return (B_FALSE);
17486f45ec7bSml29623 }
17496f45ec7bSml29623 
1750678453a8Sspeer /*
1751678453a8Sspeer  * nxge_txdma_channel_hung
1752678453a8Sspeer  *
1753678453a8Sspeer  *	Reset a TDC.
1754678453a8Sspeer  *
1755678453a8Sspeer  * Arguments:
1756678453a8Sspeer  * 	nxgep
1757678453a8Sspeer  * 	ring		<channel>'s ring.
1758678453a8Sspeer  * 	channel		The channel to reset.
1759678453a8Sspeer  *
1760678453a8Sspeer  * Notes:
1761678453a8Sspeer  *	Called by nxge_txdma.c:nxge_txdma_hung()
1762678453a8Sspeer  *
1763678453a8Sspeer  * NPI/NXGE function calls:
1764678453a8Sspeer  *	npi_txdma_ring_head_get()
1765678453a8Sspeer  *
1766678453a8Sspeer  * Registers accessed:
1767678453a8Sspeer  *	TX_RING_HDL	DMC+0x40010 Transmit Ring Head Low
1768678453a8Sspeer  *
1769678453a8Sspeer  * Context:
1770678453a8Sspeer  *	Any domain
1771678453a8Sspeer  */
17726f45ec7bSml29623 int
nxge_txdma_channel_hung(p_nxge_t nxgep,p_tx_ring_t tx_ring_p,uint16_t channel)17736f45ec7bSml29623 nxge_txdma_channel_hung(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, uint16_t channel)
17746f45ec7bSml29623 {
17756f45ec7bSml29623 	uint16_t		head_index, tail_index;
17766f45ec7bSml29623 	boolean_t		head_wrap, tail_wrap;
17776f45ec7bSml29623 	npi_handle_t		handle;
17786f45ec7bSml29623 	tx_ring_hdl_t		tx_head;
17796f45ec7bSml29623 	uint_t			tx_rd_index;
17806f45ec7bSml29623 
17816f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_channel_hung"));
17826f45ec7bSml29623 
17836f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
17846f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
17856f45ec7bSml29623 	    "==> nxge_txdma_channel_hung: channel %d", channel));
17866f45ec7bSml29623 	MUTEX_ENTER(&tx_ring_p->lock);
17876f45ec7bSml29623 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
17886f45ec7bSml29623 
17896f45ec7bSml29623 	tail_index = tx_ring_p->wr_index;
17906f45ec7bSml29623 	tail_wrap = tx_ring_p->wr_index_wrap;
17916f45ec7bSml29623 	tx_rd_index = tx_ring_p->rd_index;
17926f45ec7bSml29623 	MUTEX_EXIT(&tx_ring_p->lock);
17936f45ec7bSml29623 
17946f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
17956f45ec7bSml29623 	    "==> nxge_txdma_channel_hung: tdc %d tx_rd_index %d "
17966f45ec7bSml29623 	    "tail_index %d tail_wrap %d ",
17976f45ec7bSml29623 	    channel, tx_rd_index, tail_index, tail_wrap));
17986f45ec7bSml29623 	/*
17996f45ec7bSml29623 	 * Read the hardware maintained transmit head
18006f45ec7bSml29623 	 * and wrap around bit.
18016f45ec7bSml29623 	 */
18026f45ec7bSml29623 	(void) npi_txdma_ring_head_get(handle, channel, &tx_head);
18036f45ec7bSml29623 	head_index =  tx_head.bits.ldw.head;
18046f45ec7bSml29623 	head_wrap = tx_head.bits.ldw.wrap;
18056f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
18066f45ec7bSml29623 	    "==> nxge_txdma_channel_hung: "
18076f45ec7bSml29623 	    "tx_rd_index %d tail %d tail_wrap %d "
18086f45ec7bSml29623 	    "head %d wrap %d",
18096f45ec7bSml29623 	    tx_rd_index, tail_index, tail_wrap,
18106f45ec7bSml29623 	    head_index, head_wrap));
18116f45ec7bSml29623 
18126f45ec7bSml29623 	if (TXDMA_RING_EMPTY(head_index, head_wrap,
18136f45ec7bSml29623 	    tail_index, tail_wrap) &&
18146f45ec7bSml29623 	    (head_index == tx_rd_index)) {
18156f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
18166f45ec7bSml29623 		    "==> nxge_txdma_channel_hung: EMPTY"));
18176f45ec7bSml29623 		return (B_FALSE);
18186f45ec7bSml29623 	}
18196f45ec7bSml29623 
18206f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
18216f45ec7bSml29623 	    "==> nxge_txdma_channel_hung: Checking if ring full"));
18226f45ec7bSml29623 	if (TXDMA_RING_FULL(head_index, head_wrap, tail_index,
18236f45ec7bSml29623 	    tail_wrap)) {
18246f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
18256f45ec7bSml29623 		    "==> nxge_txdma_channel_hung: full"));
18266f45ec7bSml29623 		return (B_TRUE);
18276f45ec7bSml29623 	}
18286f45ec7bSml29623 
18296f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_channel_hung"));
18306f45ec7bSml29623 
18316f45ec7bSml29623 	return (B_FALSE);
18326f45ec7bSml29623 }
18336f45ec7bSml29623 
1834678453a8Sspeer /*
1835678453a8Sspeer  * nxge_fixup_hung_txdma_rings
1836678453a8Sspeer  *
1837678453a8Sspeer  *	Disable a TDC.
1838678453a8Sspeer  *
1839678453a8Sspeer  * Arguments:
1840678453a8Sspeer  * 	nxgep
1841678453a8Sspeer  * 	channel		The channel to reset.
1842678453a8Sspeer  * 	reg_data	The current TX_CS.
1843678453a8Sspeer  *
1844678453a8Sspeer  * Notes:
1845678453a8Sspeer  *	Called by nxge_check_tx_hang()
1846678453a8Sspeer  *
1847678453a8Sspeer  * NPI/NXGE function calls:
1848678453a8Sspeer  *	npi_txdma_ring_head_get()
1849678453a8Sspeer  *
1850678453a8Sspeer  * Registers accessed:
1851678453a8Sspeer  *	TX_RING_HDL	DMC+0x40010 Transmit Ring Head Low
1852678453a8Sspeer  *
1853678453a8Sspeer  * Context:
1854678453a8Sspeer  *	Any domain
1855678453a8Sspeer  */
18566f45ec7bSml29623 /*ARGSUSED*/
18576f45ec7bSml29623 void
nxge_fixup_hung_txdma_rings(p_nxge_t nxgep)18586f45ec7bSml29623 nxge_fixup_hung_txdma_rings(p_nxge_t nxgep)
18596f45ec7bSml29623 {
1860678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1861678453a8Sspeer 	int tdc;
18626f45ec7bSml29623 
18636f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_hung_txdma_rings"));
1864678453a8Sspeer 
1865678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
18666f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1867678453a8Sspeer 		    "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
18686f45ec7bSml29623 		return;
18696f45ec7bSml29623 	}
18706f45ec7bSml29623 
1871678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1872678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1873678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1874678453a8Sspeer 			if (ring) {
1875678453a8Sspeer 				nxge_txdma_fixup_hung_channel(nxgep, ring, tdc);
18766f45ec7bSml29623 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
1877678453a8Sspeer 				    "==> nxge_fixup_hung_txdma_rings: TDC %d",
1878678453a8Sspeer 				    tdc));
18796f45ec7bSml29623 			}
18806f45ec7bSml29623 		}
18816f45ec7bSml29623 	}
18826f45ec7bSml29623 
18836f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_hung_txdma_rings"));
18846f45ec7bSml29623 }
18856f45ec7bSml29623 
1886678453a8Sspeer /*
1887678453a8Sspeer  * nxge_txdma_fixup_hung_channel
1888678453a8Sspeer  *
1889678453a8Sspeer  *	'Fix' a hung TDC.
1890678453a8Sspeer  *
1891678453a8Sspeer  * Arguments:
1892678453a8Sspeer  * 	nxgep
1893678453a8Sspeer  * 	channel		The channel to fix.
1894678453a8Sspeer  *
1895678453a8Sspeer  * Notes:
1896678453a8Sspeer  *	Called by nxge_fixup_hung_txdma_rings()
1897678453a8Sspeer  *
1898678453a8Sspeer  *	1. Reclaim the TDC.
1899678453a8Sspeer  *	2. Disable the TDC.
1900678453a8Sspeer  *
1901678453a8Sspeer  * NPI/NXGE function calls:
1902678453a8Sspeer  *	nxge_txdma_reclaim()
1903678453a8Sspeer  *	npi_txdma_channel_disable(TX_CS)
1904678453a8Sspeer  *	npi_txdma_inj_int_error_set(TDMC_INTR_DBG)
1905678453a8Sspeer  *
1906678453a8Sspeer  * Registers accessed:
1907678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1908678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
1909678453a8Sspeer  *
1910678453a8Sspeer  * Context:
1911678453a8Sspeer  *	Any domain
1912678453a8Sspeer  */
19136f45ec7bSml29623 /*ARGSUSED*/
19146f45ec7bSml29623 void
nxge_txdma_fix_hung_channel(p_nxge_t nxgep,uint16_t channel)19156f45ec7bSml29623 nxge_txdma_fix_hung_channel(p_nxge_t nxgep, uint16_t channel)
19166f45ec7bSml29623 {
19176f45ec7bSml29623 	p_tx_ring_t	ring_p;
19186f45ec7bSml29623 
19196f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_hung_channel"));
19206f45ec7bSml29623 	ring_p = nxge_txdma_get_ring(nxgep, channel);
19216f45ec7bSml29623 	if (ring_p == NULL) {
19226f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
19236f45ec7bSml29623 		    "<== nxge_txdma_fix_hung_channel"));
19246f45ec7bSml29623 		return;
19256f45ec7bSml29623 	}
19266f45ec7bSml29623 
19276f45ec7bSml29623 	if (ring_p->tdc != channel) {
19286f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
19296f45ec7bSml29623 		    "<== nxge_txdma_fix_hung_channel: channel not matched "
19306f45ec7bSml29623 		    "ring tdc %d passed channel",
19316f45ec7bSml29623 		    ring_p->tdc, channel));
19326f45ec7bSml29623 		return;
19336f45ec7bSml29623 	}
19346f45ec7bSml29623 
19356f45ec7bSml29623 	nxge_txdma_fixup_channel(nxgep, ring_p, channel);
19366f45ec7bSml29623 
19376f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_hung_channel"));
19386f45ec7bSml29623 }
19396f45ec7bSml29623 
19406f45ec7bSml29623 /*ARGSUSED*/
19416f45ec7bSml29623 void
nxge_txdma_fixup_hung_channel(p_nxge_t nxgep,p_tx_ring_t ring_p,uint16_t channel)19426f45ec7bSml29623 nxge_txdma_fixup_hung_channel(p_nxge_t nxgep, p_tx_ring_t ring_p,
19436f45ec7bSml29623 	uint16_t channel)
19446f45ec7bSml29623 {
19456f45ec7bSml29623 	npi_handle_t		handle;
19466f45ec7bSml29623 	tdmc_intr_dbg_t		intr_dbg;
19476f45ec7bSml29623 	int			status = NXGE_OK;
19486f45ec7bSml29623 
19496f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_hung_channel"));
19506f45ec7bSml29623 
19516f45ec7bSml29623 	if (ring_p == NULL) {
19526f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
19536f45ec7bSml29623 		    "<== nxge_txdma_fixup_channel: NULL ring pointer"));
19546f45ec7bSml29623 		return;
19556f45ec7bSml29623 	}
19566f45ec7bSml29623 
19576f45ec7bSml29623 	if (ring_p->tdc != channel) {
19586f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
19596f45ec7bSml29623 		    "<== nxge_txdma_fixup_hung_channel: channel "
19606f45ec7bSml29623 		    "not matched "
19616f45ec7bSml29623 		    "ring tdc %d passed channel",
19626f45ec7bSml29623 		    ring_p->tdc, channel));
19636f45ec7bSml29623 		return;
19646f45ec7bSml29623 	}
19656f45ec7bSml29623 
19666f45ec7bSml29623 	/* Reclaim descriptors */
19676f45ec7bSml29623 	MUTEX_ENTER(&ring_p->lock);
19686f45ec7bSml29623 	(void) nxge_txdma_reclaim(nxgep, ring_p, 0);
19696f45ec7bSml29623 	MUTEX_EXIT(&ring_p->lock);
19706f45ec7bSml29623 
19716f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
19726f45ec7bSml29623 	/*
19736f45ec7bSml29623 	 * Stop the dma channel waits for the stop done.
19746f45ec7bSml29623 	 * If the stop done bit is not set, then force
19756f45ec7bSml29623 	 * an error.
19766f45ec7bSml29623 	 */
19776f45ec7bSml29623 	status = npi_txdma_channel_disable(handle, channel);
19786f45ec7bSml29623 	if (!(status & NPI_TXDMA_STOP_FAILED)) {
19796f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
19806f45ec7bSml29623 		    "<== nxge_txdma_fixup_hung_channel: stopped OK "
19816f45ec7bSml29623 		    "ring tdc %d passed channel %d",
19826f45ec7bSml29623 		    ring_p->tdc, channel));
19836f45ec7bSml29623 		return;
19846f45ec7bSml29623 	}
19856f45ec7bSml29623 
19866f45ec7bSml29623 	/* Inject any error */
19876f45ec7bSml29623 	intr_dbg.value = 0;
19886f45ec7bSml29623 	intr_dbg.bits.ldw.nack_pref = 1;
19896f45ec7bSml29623 	(void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg);
19906f45ec7bSml29623 
19916f45ec7bSml29623 	/* Stop done bit will be set as a result of error injection */
19926f45ec7bSml29623 	status = npi_txdma_channel_disable(handle, channel);
19936f45ec7bSml29623 	if (!(status & NPI_TXDMA_STOP_FAILED)) {
19946f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
19956f45ec7bSml29623 		    "<== nxge_txdma_fixup_hung_channel: stopped again"
19966f45ec7bSml29623 		    "ring tdc %d passed channel",
19976f45ec7bSml29623 		    ring_p->tdc, channel));
19986f45ec7bSml29623 		return;
19996f45ec7bSml29623 	}
20006f45ec7bSml29623 
20016f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
20026f45ec7bSml29623 	    "<== nxge_txdma_fixup_hung_channel: stop done still not set!! "
20036f45ec7bSml29623 	    "ring tdc %d passed channel",
20046f45ec7bSml29623 	    ring_p->tdc, channel));
20056f45ec7bSml29623 
20066f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_hung_channel"));
20076f45ec7bSml29623 }
20086f45ec7bSml29623 
20096f45ec7bSml29623 /*ARGSUSED*/
20106f45ec7bSml29623 void
nxge_reclaim_rings(p_nxge_t nxgep)20116f45ec7bSml29623 nxge_reclaim_rings(p_nxge_t nxgep)
20126f45ec7bSml29623 {
2013678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
2014678453a8Sspeer 	int tdc;
20156f45ec7bSml29623 
2016678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_reclaim_rings"));
2017678453a8Sspeer 
2018678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
20196f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
2020678453a8Sspeer 		    "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
20216f45ec7bSml29623 		return;
20226f45ec7bSml29623 	}
20236f45ec7bSml29623 
2024678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
2025678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
2026678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
2027678453a8Sspeer 			if (ring) {
20286f45ec7bSml29623 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
2029678453a8Sspeer 				    "==> nxge_reclaim_rings: TDC %d", tdc));
2030678453a8Sspeer 				MUTEX_ENTER(&ring->lock);
2031da14cebeSEric Cheng 				(void) nxge_txdma_reclaim(nxgep, ring, 0);
2032678453a8Sspeer 				MUTEX_EXIT(&ring->lock);
20336f45ec7bSml29623 			}
20346f45ec7bSml29623 		}
20356f45ec7bSml29623 	}
20366f45ec7bSml29623 
20376f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_reclaim_rings"));
20386f45ec7bSml29623 }
20396f45ec7bSml29623 
20406f45ec7bSml29623 void
nxge_txdma_regs_dump_channels(p_nxge_t nxgep)20416f45ec7bSml29623 nxge_txdma_regs_dump_channels(p_nxge_t nxgep)
20426f45ec7bSml29623 {
2043678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
20446f45ec7bSml29623 	npi_handle_t handle;
2045678453a8Sspeer 	int tdc;
20466f45ec7bSml29623 
2047678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_regs_dump_channels"));
20486f45ec7bSml29623 
20496f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
2050678453a8Sspeer 
2051678453a8Sspeer 	if (!isLDOMguest(nxgep)) {
20526f45ec7bSml29623 		(void) npi_txdma_dump_fzc_regs(handle);
20536f45ec7bSml29623 
2054678453a8Sspeer 		/* Dump TXC registers. */
20556f45ec7bSml29623 		(void) npi_txc_dump_fzc_regs(handle);
20566f45ec7bSml29623 		(void) npi_txc_dump_port_fzc_regs(handle, nxgep->function_num);
20576f45ec7bSml29623 	}
20586f45ec7bSml29623 
2059678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
20606f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
2061678453a8Sspeer 		    "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
2062678453a8Sspeer 		return;
2063678453a8Sspeer 	}
2064678453a8Sspeer 
2065678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
2066678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
2067678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
2068678453a8Sspeer 			if (ring) {
2069678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
2070678453a8Sspeer 				    "==> nxge_txdma_regs_dump_channels: "
2071678453a8Sspeer 				    "TDC %d", tdc));
2072678453a8Sspeer 				(void) npi_txdma_dump_tdc_regs(handle, tdc);
2073678453a8Sspeer 
2074678453a8Sspeer 				/* Dump TXC registers, if able to. */
2075678453a8Sspeer 				if (!isLDOMguest(nxgep)) {
2076678453a8Sspeer 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
2077678453a8Sspeer 					    "==> nxge_txdma_regs_dump_channels:"
2078678453a8Sspeer 					    " FZC TDC %d", tdc));
2079678453a8Sspeer 					(void) npi_txc_dump_tdc_fzc_regs
2080678453a8Sspeer 					    (handle, tdc);
2081678453a8Sspeer 				}
2082678453a8Sspeer 				nxge_txdma_regs_dump(nxgep, tdc);
2083678453a8Sspeer 			}
2084678453a8Sspeer 		}
20856f45ec7bSml29623 	}
20866f45ec7bSml29623 
20876f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_regs_dump"));
20886f45ec7bSml29623 }
20896f45ec7bSml29623 
20906f45ec7bSml29623 void
nxge_txdma_regs_dump(p_nxge_t nxgep,int channel)20916f45ec7bSml29623 nxge_txdma_regs_dump(p_nxge_t nxgep, int channel)
20926f45ec7bSml29623 {
20936f45ec7bSml29623 	npi_handle_t		handle;
20946f45ec7bSml29623 	tx_ring_hdl_t 		hdl;
20956f45ec7bSml29623 	tx_ring_kick_t 		kick;
20966f45ec7bSml29623 	tx_cs_t 		cs;
20976f45ec7bSml29623 	txc_control_t		control;
20986f45ec7bSml29623 	uint32_t		bitmap = 0;
20996f45ec7bSml29623 	uint32_t		burst = 0;
21006f45ec7bSml29623 	uint32_t		bytes = 0;
21016f45ec7bSml29623 	dma_log_page_t		cfg;
21026f45ec7bSml29623 
21036f45ec7bSml29623 	printf("\n\tfunc # %d tdc %d ",
21046f45ec7bSml29623 	    nxgep->function_num, channel);
21056f45ec7bSml29623 	cfg.page_num = 0;
21066f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
21076f45ec7bSml29623 	(void) npi_txdma_log_page_get(handle, channel, &cfg);
21086f45ec7bSml29623 	printf("\n\tlog page func %d valid page 0 %d",
21096f45ec7bSml29623 	    cfg.func_num, cfg.valid);
21106f45ec7bSml29623 	cfg.page_num = 1;
21116f45ec7bSml29623 	(void) npi_txdma_log_page_get(handle, channel, &cfg);
21126f45ec7bSml29623 	printf("\n\tlog page func %d valid page 1 %d",
21136f45ec7bSml29623 	    cfg.func_num, cfg.valid);
21146f45ec7bSml29623 
21156f45ec7bSml29623 	(void) npi_txdma_ring_head_get(handle, channel, &hdl);
21166f45ec7bSml29623 	(void) npi_txdma_desc_kick_reg_get(handle, channel, &kick);
21176f45ec7bSml29623 	printf("\n\thead value is 0x%0llx",
21186f45ec7bSml29623 	    (long long)hdl.value);
21196f45ec7bSml29623 	printf("\n\thead index %d", hdl.bits.ldw.head);
21206f45ec7bSml29623 	printf("\n\tkick value is 0x%0llx",
21216f45ec7bSml29623 	    (long long)kick.value);
21226f45ec7bSml29623 	printf("\n\ttail index %d\n", kick.bits.ldw.tail);
21236f45ec7bSml29623 
21246f45ec7bSml29623 	(void) npi_txdma_control_status(handle, OP_GET, channel, &cs);
21256f45ec7bSml29623 	printf("\n\tControl statue is 0x%0llx", (long long)cs.value);
21266f45ec7bSml29623 	printf("\n\tControl status RST state %d", cs.bits.ldw.rst);
21276f45ec7bSml29623 
21286f45ec7bSml29623 	(void) npi_txc_control(handle, OP_GET, &control);
21296f45ec7bSml29623 	(void) npi_txc_port_dma_list_get(handle, nxgep->function_num, &bitmap);
21306f45ec7bSml29623 	(void) npi_txc_dma_max_burst(handle, OP_GET, channel, &burst);
21316f45ec7bSml29623 	(void) npi_txc_dma_bytes_transmitted(handle, channel, &bytes);
21326f45ec7bSml29623 
21336f45ec7bSml29623 	printf("\n\tTXC port control 0x%0llx",
21346f45ec7bSml29623 	    (long long)control.value);
21356f45ec7bSml29623 	printf("\n\tTXC port bitmap 0x%x", bitmap);
21366f45ec7bSml29623 	printf("\n\tTXC max burst %d", burst);
21376f45ec7bSml29623 	printf("\n\tTXC bytes xmt %d\n", bytes);
21386f45ec7bSml29623 
21396f45ec7bSml29623 	{
21406f45ec7bSml29623 		ipp_status_t status;
21416f45ec7bSml29623 
21426f45ec7bSml29623 		(void) npi_ipp_get_status(handle, nxgep->function_num, &status);
2143adfcba55Sjoycey #if defined(__i386)
2144adfcba55Sjoycey 		printf("\n\tIPP status 0x%llux\n", (uint64_t)status.value);
2145adfcba55Sjoycey #else
21466f45ec7bSml29623 		printf("\n\tIPP status 0x%lux\n", (uint64_t)status.value);
2147adfcba55Sjoycey #endif
21486f45ec7bSml29623 	}
21496f45ec7bSml29623 }
21506f45ec7bSml29623 
21516f45ec7bSml29623 /*
2152678453a8Sspeer  * nxge_tdc_hvio_setup
2153678453a8Sspeer  *
2154678453a8Sspeer  *	I'm not exactly sure what this code does.
2155678453a8Sspeer  *
2156678453a8Sspeer  * Arguments:
2157678453a8Sspeer  * 	nxgep
2158678453a8Sspeer  * 	channel	The channel to map.
2159678453a8Sspeer  *
2160678453a8Sspeer  * Notes:
2161678453a8Sspeer  *
2162678453a8Sspeer  * NPI/NXGE function calls:
2163678453a8Sspeer  *	na
2164678453a8Sspeer  *
2165678453a8Sspeer  * Context:
2166678453a8Sspeer  *	Service domain?
21676f45ec7bSml29623  */
21686f45ec7bSml29623 #if defined(sun4v) && defined(NIU_LP_WORKAROUND)
2169678453a8Sspeer static void
nxge_tdc_hvio_setup(nxge_t * nxgep,int channel)2170678453a8Sspeer nxge_tdc_hvio_setup(
2171678453a8Sspeer 	nxge_t *nxgep, int channel)
2172678453a8Sspeer {
2173678453a8Sspeer 	nxge_dma_common_t	*data;
2174678453a8Sspeer 	nxge_dma_common_t	*control;
2175678453a8Sspeer 	tx_ring_t 		*ring;
2176678453a8Sspeer 
2177678453a8Sspeer 	ring = nxgep->tx_rings->rings[channel];
2178678453a8Sspeer 	data = nxgep->tx_buf_pool_p->dma_buf_pool_p[channel];
2179678453a8Sspeer 
2180678453a8Sspeer 	ring->hv_set = B_FALSE;
2181678453a8Sspeer 
2182678453a8Sspeer 	ring->hv_tx_buf_base_ioaddr_pp =
2183678453a8Sspeer 	    (uint64_t)data->orig_ioaddr_pp;
2184678453a8Sspeer 	ring->hv_tx_buf_ioaddr_size =
2185678453a8Sspeer 	    (uint64_t)data->orig_alength;
2186678453a8Sspeer 
2187678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: "
2188678453a8Sspeer 	    "hv data buf base io $%p size 0x%llx (%d) buf base io $%p "
2189678453a8Sspeer 	    "orig vatopa base io $%p orig_len 0x%llx (%d)",
2190678453a8Sspeer 	    ring->hv_tx_buf_base_ioaddr_pp,
2191678453a8Sspeer 	    ring->hv_tx_buf_ioaddr_size, ring->hv_tx_buf_ioaddr_size,
2192678453a8Sspeer 	    data->ioaddr_pp, data->orig_vatopa,
2193678453a8Sspeer 	    data->orig_alength, data->orig_alength));
2194678453a8Sspeer 
2195678453a8Sspeer 	control = nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel];
2196678453a8Sspeer 
2197678453a8Sspeer 	ring->hv_tx_cntl_base_ioaddr_pp =
2198678453a8Sspeer 	    (uint64_t)control->orig_ioaddr_pp;
2199678453a8Sspeer 	ring->hv_tx_cntl_ioaddr_size =
2200678453a8Sspeer 	    (uint64_t)control->orig_alength;
2201678453a8Sspeer 
2202678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: "
2203678453a8Sspeer 	    "hv cntl base io $%p orig ioaddr_pp ($%p) "
2204678453a8Sspeer 	    "orig vatopa ($%p) size 0x%llx (%d 0x%x)",
2205678453a8Sspeer 	    ring->hv_tx_cntl_base_ioaddr_pp,
2206678453a8Sspeer 	    control->orig_ioaddr_pp, control->orig_vatopa,
2207678453a8Sspeer 	    ring->hv_tx_cntl_ioaddr_size,
2208678453a8Sspeer 	    control->orig_alength, control->orig_alength));
2209678453a8Sspeer }
22106f45ec7bSml29623 #endif
22116f45ec7bSml29623 
2212678453a8Sspeer static nxge_status_t
nxge_map_txdma(p_nxge_t nxgep,int channel)2213678453a8Sspeer nxge_map_txdma(p_nxge_t nxgep, int channel)
2214678453a8Sspeer {
2215678453a8Sspeer 	nxge_dma_common_t	**pData;
2216678453a8Sspeer 	nxge_dma_common_t	**pControl;
2217678453a8Sspeer 	tx_ring_t 		**pRing, *ring;
2218678453a8Sspeer 	tx_mbox_t		**mailbox;
2219678453a8Sspeer 	uint32_t		num_chunks;
22206f45ec7bSml29623 
2221678453a8Sspeer 	nxge_status_t		status = NXGE_OK;
22226f45ec7bSml29623 
2223678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma"));
2224678453a8Sspeer 
2225678453a8Sspeer 	if (!nxgep->tx_cntl_pool_p->buf_allocated) {
2226678453a8Sspeer 		if (nxge_alloc_tx_mem_pool(nxgep) != NXGE_OK) {
2227678453a8Sspeer 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2228678453a8Sspeer 			    "<== nxge_map_txdma: buf not allocated"));
22296f45ec7bSml29623 			return (NXGE_ERROR);
22306f45ec7bSml29623 		}
22316f45ec7bSml29623 	}
22326f45ec7bSml29623 
2233678453a8Sspeer 	if (nxge_alloc_txb(nxgep, channel) != NXGE_OK)
2234678453a8Sspeer 		return (NXGE_ERROR);
22356f45ec7bSml29623 
2236678453a8Sspeer 	num_chunks = nxgep->tx_buf_pool_p->num_chunks[channel];
2237678453a8Sspeer 	pData = &nxgep->tx_buf_pool_p->dma_buf_pool_p[channel];
2238678453a8Sspeer 	pControl = &nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel];
2239678453a8Sspeer 	pRing = &nxgep->tx_rings->rings[channel];
2240678453a8Sspeer 	mailbox = &nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
22416f45ec7bSml29623 
2242678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: "
22436f45ec7bSml29623 	    "tx_rings $%p tx_desc_rings $%p",
2244678453a8Sspeer 	    nxgep->tx_rings, nxgep->tx_rings->rings));
22456f45ec7bSml29623 
22466f45ec7bSml29623 	/*
2247678453a8Sspeer 	 * Map descriptors from the buffer pools for <channel>.
22486f45ec7bSml29623 	 */
2249678453a8Sspeer 
22506f45ec7bSml29623 	/*
22516f45ec7bSml29623 	 * Set up and prepare buffer blocks, descriptors
22526f45ec7bSml29623 	 * and mailbox.
22536f45ec7bSml29623 	 */
22546f45ec7bSml29623 	status = nxge_map_txdma_channel(nxgep, channel,
2255678453a8Sspeer 	    pData, pRing, num_chunks, pControl, mailbox);
22566f45ec7bSml29623 	if (status != NXGE_OK) {
2257678453a8Sspeer 		NXGE_ERROR_MSG((nxgep, MEM3_CTL,
2258678453a8Sspeer 		    "==> nxge_map_txdma(%d): nxge_map_txdma_channel() "
2259678453a8Sspeer 		    "returned 0x%x",
2260678453a8Sspeer 		    nxgep, channel, status));
22616f45ec7bSml29623 		return (status);
22626f45ec7bSml29623 	}
22636f45ec7bSml29623 
2264678453a8Sspeer 	ring = *pRing;
22656f45ec7bSml29623 
2266678453a8Sspeer 	ring->index = (uint16_t)channel;
2267678453a8Sspeer 	ring->tdc_stats = &nxgep->statsp->tdc_stats[channel];
22686f45ec7bSml29623 
2269678453a8Sspeer #if defined(sun4v) && defined(NIU_LP_WORKAROUND)
2270678453a8Sspeer 	if (isLDOMguest(nxgep)) {
2271678453a8Sspeer 		(void) nxge_tdc_lp_conf(nxgep, channel);
2272678453a8Sspeer 	} else {
2273678453a8Sspeer 		nxge_tdc_hvio_setup(nxgep, channel);
22746f45ec7bSml29623 	}
2275678453a8Sspeer #endif
22766f45ec7bSml29623 
2277678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: "
2278678453a8Sspeer 	    "(status 0x%x channel %d)", status, channel));
22796f45ec7bSml29623 
2280678453a8Sspeer 	return (status);
22816f45ec7bSml29623 }
22826f45ec7bSml29623 
22836f45ec7bSml29623 static nxge_status_t
nxge_map_txdma_channel(p_nxge_t nxgep,uint16_t channel,p_nxge_dma_common_t * dma_buf_p,p_tx_ring_t * tx_desc_p,uint32_t num_chunks,p_nxge_dma_common_t * dma_cntl_p,p_tx_mbox_t * tx_mbox_p)22846f45ec7bSml29623 nxge_map_txdma_channel(p_nxge_t nxgep, uint16_t channel,
22856f45ec7bSml29623 	p_nxge_dma_common_t *dma_buf_p,
22866f45ec7bSml29623 	p_tx_ring_t *tx_desc_p,
22876f45ec7bSml29623 	uint32_t num_chunks,
22886f45ec7bSml29623 	p_nxge_dma_common_t *dma_cntl_p,
22896f45ec7bSml29623 	p_tx_mbox_t *tx_mbox_p)
22906f45ec7bSml29623 {
22916f45ec7bSml29623 	int	status = NXGE_OK;
22926f45ec7bSml29623 
22936f45ec7bSml29623 	/*
22946f45ec7bSml29623 	 * Set up and prepare buffer blocks, descriptors
22956f45ec7bSml29623 	 * and mailbox.
22966f45ec7bSml29623 	 */
2297678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL,
22986f45ec7bSml29623 	    "==> nxge_map_txdma_channel (channel %d)", channel));
22996f45ec7bSml29623 	/*
23006f45ec7bSml29623 	 * Transmit buffer blocks
23016f45ec7bSml29623 	 */
23026f45ec7bSml29623 	status = nxge_map_txdma_channel_buf_ring(nxgep, channel,
23036f45ec7bSml29623 	    dma_buf_p, tx_desc_p, num_chunks);
23046f45ec7bSml29623 	if (status != NXGE_OK) {
23056f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
23066f45ec7bSml29623 		    "==> nxge_map_txdma_channel (channel %d): "
23076f45ec7bSml29623 		    "map buffer failed 0x%x", channel, status));
23086f45ec7bSml29623 		goto nxge_map_txdma_channel_exit;
23096f45ec7bSml29623 	}
23106f45ec7bSml29623 
23116f45ec7bSml29623 	/*
23126f45ec7bSml29623 	 * Transmit block ring, and mailbox.
23136f45ec7bSml29623 	 */
23146f45ec7bSml29623 	nxge_map_txdma_channel_cfg_ring(nxgep, channel, dma_cntl_p, *tx_desc_p,
23156f45ec7bSml29623 	    tx_mbox_p);
23166f45ec7bSml29623 
23176f45ec7bSml29623 	goto nxge_map_txdma_channel_exit;
23186f45ec7bSml29623 
23196f45ec7bSml29623 nxge_map_txdma_channel_fail1:
2320678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL,
23216f45ec7bSml29623 	    "==> nxge_map_txdma_channel: unmap buf"
23226f45ec7bSml29623 	    "(status 0x%x channel %d)",
23236f45ec7bSml29623 	    status, channel));
23246f45ec7bSml29623 	nxge_unmap_txdma_channel_buf_ring(nxgep, *tx_desc_p);
23256f45ec7bSml29623 
23266f45ec7bSml29623 nxge_map_txdma_channel_exit:
2327678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL,
23286f45ec7bSml29623 	    "<== nxge_map_txdma_channel: "
23296f45ec7bSml29623 	    "(status 0x%x channel %d)",
23306f45ec7bSml29623 	    status, channel));
23316f45ec7bSml29623 
23326f45ec7bSml29623 	return (status);
23336f45ec7bSml29623 }
23346f45ec7bSml29623 
23356f45ec7bSml29623 /*ARGSUSED*/
23366f45ec7bSml29623 static void
nxge_unmap_txdma_channel(p_nxge_t nxgep,uint16_t channel)2337678453a8Sspeer nxge_unmap_txdma_channel(p_nxge_t nxgep, uint16_t channel)
23386f45ec7bSml29623 {
2339678453a8Sspeer 	tx_ring_t *ring;
2340678453a8Sspeer 	tx_mbox_t *mailbox;
2341678453a8Sspeer 
23426f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
23436f45ec7bSml29623 	    "==> nxge_unmap_txdma_channel (channel %d)", channel));
23446f45ec7bSml29623 	/*
23456f45ec7bSml29623 	 * unmap tx block ring, and mailbox.
23466f45ec7bSml29623 	 */
2347678453a8Sspeer 	ring = nxgep->tx_rings->rings[channel];
2348678453a8Sspeer 	mailbox = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
2349678453a8Sspeer 
2350678453a8Sspeer 	(void) nxge_unmap_txdma_channel_cfg_ring(nxgep, ring, mailbox);
23516f45ec7bSml29623 
23526f45ec7bSml29623 	/* unmap buffer blocks */
2353678453a8Sspeer 	(void) nxge_unmap_txdma_channel_buf_ring(nxgep, ring);
2354678453a8Sspeer 
2355678453a8Sspeer 	nxge_free_txb(nxgep, channel);
23566f45ec7bSml29623 
235748056c53SMichael Speer 	/*
235848056c53SMichael Speer 	 * Cleanup the reference to the ring now that it does not exist.
235948056c53SMichael Speer 	 */
236048056c53SMichael Speer 	nxgep->tx_rings->rings[channel] = NULL;
236148056c53SMichael Speer 
23626f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_unmap_txdma_channel"));
23636f45ec7bSml29623 }
23646f45ec7bSml29623 
2365678453a8Sspeer /*
2366678453a8Sspeer  * nxge_map_txdma_channel_cfg_ring
2367678453a8Sspeer  *
2368678453a8Sspeer  *	Map a TDC into our kernel space.
2369678453a8Sspeer  *	This function allocates all of the per-channel data structures.
2370678453a8Sspeer  *
2371678453a8Sspeer  * Arguments:
2372678453a8Sspeer  * 	nxgep
2373678453a8Sspeer  * 	dma_channel	The channel to map.
2374678453a8Sspeer  *	dma_cntl_p
2375678453a8Sspeer  *	tx_ring_p	dma_channel's transmit ring
2376678453a8Sspeer  *	tx_mbox_p	dma_channel's mailbox
2377678453a8Sspeer  *
2378678453a8Sspeer  * Notes:
2379678453a8Sspeer  *
2380678453a8Sspeer  * NPI/NXGE function calls:
2381678453a8Sspeer  *	nxge_setup_dma_common()
2382678453a8Sspeer  *
2383678453a8Sspeer  * Registers accessed:
2384678453a8Sspeer  *	none.
2385678453a8Sspeer  *
2386678453a8Sspeer  * Context:
2387678453a8Sspeer  *	Any domain
2388678453a8Sspeer  */
23896f45ec7bSml29623 /*ARGSUSED*/
23906f45ec7bSml29623 static void
nxge_map_txdma_channel_cfg_ring(p_nxge_t nxgep,uint16_t dma_channel,p_nxge_dma_common_t * dma_cntl_p,p_tx_ring_t tx_ring_p,p_tx_mbox_t * tx_mbox_p)23916f45ec7bSml29623 nxge_map_txdma_channel_cfg_ring(p_nxge_t nxgep, uint16_t dma_channel,
23926f45ec7bSml29623 	p_nxge_dma_common_t *dma_cntl_p,
23936f45ec7bSml29623 	p_tx_ring_t tx_ring_p,
23946f45ec7bSml29623 	p_tx_mbox_t *tx_mbox_p)
23956f45ec7bSml29623 {
23966f45ec7bSml29623 	p_tx_mbox_t 		mboxp;
23976f45ec7bSml29623 	p_nxge_dma_common_t 	cntl_dmap;
23986f45ec7bSml29623 	p_nxge_dma_common_t 	dmap;
23996f45ec7bSml29623 	p_tx_rng_cfig_t		tx_ring_cfig_p;
24006f45ec7bSml29623 	p_tx_ring_kick_t	tx_ring_kick_p;
24016f45ec7bSml29623 	p_tx_cs_t		tx_cs_p;
24026f45ec7bSml29623 	p_tx_dma_ent_msk_t	tx_evmask_p;
24036f45ec7bSml29623 	p_txdma_mbh_t		mboxh_p;
24046f45ec7bSml29623 	p_txdma_mbl_t		mboxl_p;
24056f45ec7bSml29623 	uint64_t		tx_desc_len;
24066f45ec7bSml29623 
24076f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
24086f45ec7bSml29623 	    "==> nxge_map_txdma_channel_cfg_ring"));
24096f45ec7bSml29623 
24106f45ec7bSml29623 	cntl_dmap = *dma_cntl_p;
24116f45ec7bSml29623 
24126f45ec7bSml29623 	dmap = (p_nxge_dma_common_t)&tx_ring_p->tdc_desc;
24136f45ec7bSml29623 	nxge_setup_dma_common(dmap, cntl_dmap, tx_ring_p->tx_ring_size,
24146f45ec7bSml29623 	    sizeof (tx_desc_t));
24156f45ec7bSml29623 	/*
24166f45ec7bSml29623 	 * Zero out transmit ring descriptors.
24176f45ec7bSml29623 	 */
24186f45ec7bSml29623 	bzero((caddr_t)dmap->kaddrp, dmap->alength);
24196f45ec7bSml29623 	tx_ring_cfig_p = &(tx_ring_p->tx_ring_cfig);
24206f45ec7bSml29623 	tx_ring_kick_p = &(tx_ring_p->tx_ring_kick);
24216f45ec7bSml29623 	tx_cs_p = &(tx_ring_p->tx_cs);
24226f45ec7bSml29623 	tx_evmask_p = &(tx_ring_p->tx_evmask);
24236f45ec7bSml29623 	tx_ring_cfig_p->value = 0;
24246f45ec7bSml29623 	tx_ring_kick_p->value = 0;
24256f45ec7bSml29623 	tx_cs_p->value = 0;
24266f45ec7bSml29623 	tx_evmask_p->value = 0;
24276f45ec7bSml29623 
24286f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
24296f45ec7bSml29623 	    "==> nxge_map_txdma_channel_cfg_ring: channel %d des $%p",
24306f45ec7bSml29623 	    dma_channel,
24316f45ec7bSml29623 	    dmap->dma_cookie.dmac_laddress));
24326f45ec7bSml29623 
24336f45ec7bSml29623 	tx_ring_cfig_p->value = 0;
24346f45ec7bSml29623 	tx_desc_len = (uint64_t)(tx_ring_p->tx_ring_size >> 3);
24356f45ec7bSml29623 	tx_ring_cfig_p->value =
24366f45ec7bSml29623 	    (dmap->dma_cookie.dmac_laddress & TX_RNG_CFIG_ADDR_MASK) |
24376f45ec7bSml29623 	    (tx_desc_len << TX_RNG_CFIG_LEN_SHIFT);
24386f45ec7bSml29623 
24396f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
24406f45ec7bSml29623 	    "==> nxge_map_txdma_channel_cfg_ring: channel %d cfg 0x%llx",
24416f45ec7bSml29623 	    dma_channel,
24426f45ec7bSml29623 	    tx_ring_cfig_p->value));
24436f45ec7bSml29623 
24446f45ec7bSml29623 	tx_cs_p->bits.ldw.rst = 1;
24456f45ec7bSml29623 
24466f45ec7bSml29623 	/* Map in mailbox */
24476f45ec7bSml29623 	mboxp = (p_tx_mbox_t)
24486f45ec7bSml29623 	    KMEM_ZALLOC(sizeof (tx_mbox_t), KM_SLEEP);
24496f45ec7bSml29623 	dmap = (p_nxge_dma_common_t)&mboxp->tx_mbox;
24506f45ec7bSml29623 	nxge_setup_dma_common(dmap, cntl_dmap, 1, sizeof (txdma_mailbox_t));
24516f45ec7bSml29623 	mboxh_p = (p_txdma_mbh_t)&tx_ring_p->tx_mbox_mbh;
24526f45ec7bSml29623 	mboxl_p = (p_txdma_mbl_t)&tx_ring_p->tx_mbox_mbl;
24536f45ec7bSml29623 	mboxh_p->value = mboxl_p->value = 0;
24546f45ec7bSml29623 
24556f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
24566f45ec7bSml29623 	    "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
24576f45ec7bSml29623 	    dmap->dma_cookie.dmac_laddress));
24586f45ec7bSml29623 
24596f45ec7bSml29623 	mboxh_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress >>
24606f45ec7bSml29623 	    TXDMA_MBH_ADDR_SHIFT) & TXDMA_MBH_MASK);
24616f45ec7bSml29623 
24626f45ec7bSml29623 	mboxl_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress &
24636f45ec7bSml29623 	    TXDMA_MBL_MASK) >> TXDMA_MBL_SHIFT);
24646f45ec7bSml29623 
24656f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
24666f45ec7bSml29623 	    "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
24676f45ec7bSml29623 	    dmap->dma_cookie.dmac_laddress));
24686f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
24696f45ec7bSml29623 	    "==> nxge_map_txdma_channel_cfg_ring: hmbox $%p "
24706f45ec7bSml29623 	    "mbox $%p",
24716f45ec7bSml29623 	    mboxh_p->bits.ldw.mbaddr, mboxl_p->bits.ldw.mbaddr));
24726f45ec7bSml29623 	tx_ring_p->page_valid.value = 0;
24736f45ec7bSml29623 	tx_ring_p->page_mask_1.value = tx_ring_p->page_mask_2.value = 0;
24746f45ec7bSml29623 	tx_ring_p->page_value_1.value = tx_ring_p->page_value_2.value = 0;
24756f45ec7bSml29623 	tx_ring_p->page_reloc_1.value = tx_ring_p->page_reloc_2.value = 0;
24766f45ec7bSml29623 	tx_ring_p->page_hdl.value = 0;
24776f45ec7bSml29623 
24786f45ec7bSml29623 	tx_ring_p->page_valid.bits.ldw.page0 = 1;
24796f45ec7bSml29623 	tx_ring_p->page_valid.bits.ldw.page1 = 1;
24806f45ec7bSml29623 
24816f45ec7bSml29623 	tx_ring_p->max_burst.value = 0;
24826f45ec7bSml29623 	tx_ring_p->max_burst.bits.ldw.dma_max_burst = TXC_DMA_MAX_BURST_DEFAULT;
24836f45ec7bSml29623 
24846f45ec7bSml29623 	*tx_mbox_p = mboxp;
24856f45ec7bSml29623 
24866f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
24876f45ec7bSml29623 	    "<== nxge_map_txdma_channel_cfg_ring"));
24886f45ec7bSml29623 }
24896f45ec7bSml29623 
24906f45ec7bSml29623 /*ARGSUSED*/
24916f45ec7bSml29623 static void
nxge_unmap_txdma_channel_cfg_ring(p_nxge_t nxgep,p_tx_ring_t tx_ring_p,p_tx_mbox_t tx_mbox_p)24926f45ec7bSml29623 nxge_unmap_txdma_channel_cfg_ring(p_nxge_t nxgep,
24936f45ec7bSml29623 	p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p)
24946f45ec7bSml29623 {
24956f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
24966f45ec7bSml29623 	    "==> nxge_unmap_txdma_channel_cfg_ring: channel %d",
24976f45ec7bSml29623 	    tx_ring_p->tdc));
24986f45ec7bSml29623 
24996f45ec7bSml29623 	KMEM_FREE(tx_mbox_p, sizeof (tx_mbox_t));
25006f45ec7bSml29623 
25016f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
25026f45ec7bSml29623 	    "<== nxge_unmap_txdma_channel_cfg_ring"));
25036f45ec7bSml29623 }
25046f45ec7bSml29623 
2505678453a8Sspeer /*
2506678453a8Sspeer  * nxge_map_txdma_channel_buf_ring
2507678453a8Sspeer  *
2508678453a8Sspeer  *
2509678453a8Sspeer  * Arguments:
2510678453a8Sspeer  * 	nxgep
2511678453a8Sspeer  * 	channel		The channel to map.
2512678453a8Sspeer  *	dma_buf_p
2513678453a8Sspeer  *	tx_desc_p	channel's descriptor ring
2514678453a8Sspeer  *	num_chunks
2515678453a8Sspeer  *
2516678453a8Sspeer  * Notes:
2517678453a8Sspeer  *
2518678453a8Sspeer  * NPI/NXGE function calls:
2519678453a8Sspeer  *	nxge_setup_dma_common()
2520678453a8Sspeer  *
2521678453a8Sspeer  * Registers accessed:
2522678453a8Sspeer  *	none.
2523678453a8Sspeer  *
2524678453a8Sspeer  * Context:
2525678453a8Sspeer  *	Any domain
2526678453a8Sspeer  */
25276f45ec7bSml29623 static nxge_status_t
nxge_map_txdma_channel_buf_ring(p_nxge_t nxgep,uint16_t channel,p_nxge_dma_common_t * dma_buf_p,p_tx_ring_t * tx_desc_p,uint32_t num_chunks)25286f45ec7bSml29623 nxge_map_txdma_channel_buf_ring(p_nxge_t nxgep, uint16_t channel,
25296f45ec7bSml29623 	p_nxge_dma_common_t *dma_buf_p,
25306f45ec7bSml29623 	p_tx_ring_t *tx_desc_p, uint32_t num_chunks)
25316f45ec7bSml29623 {
25326f45ec7bSml29623 	p_nxge_dma_common_t 	dma_bufp, tmp_bufp;
25336f45ec7bSml29623 	p_nxge_dma_common_t 	dmap;
25346f45ec7bSml29623 	nxge_os_dma_handle_t	tx_buf_dma_handle;
25356f45ec7bSml29623 	p_tx_ring_t 		tx_ring_p;
25366f45ec7bSml29623 	p_tx_msg_t 		tx_msg_ring;
25376f45ec7bSml29623 	nxge_status_t		status = NXGE_OK;
25386f45ec7bSml29623 	int			ddi_status = DDI_SUCCESS;
25396f45ec7bSml29623 	int			i, j, index;
25406f45ec7bSml29623 	uint32_t		size, bsize;
25416f45ec7bSml29623 	uint32_t 		nblocks, nmsgs;
2542da14cebeSEric Cheng 	char			qname[TASKQ_NAMELEN];
25436f45ec7bSml29623 
25446f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
25456f45ec7bSml29623 	    "==> nxge_map_txdma_channel_buf_ring"));
25466f45ec7bSml29623 
25476f45ec7bSml29623 	dma_bufp = tmp_bufp = *dma_buf_p;
25486f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
25496f45ec7bSml29623 		" nxge_map_txdma_channel_buf_ring: channel %d to map %d "
25506f45ec7bSml29623 		"chunks bufp $%p",
25516f45ec7bSml29623 		    channel, num_chunks, dma_bufp));
25526f45ec7bSml29623 
25536f45ec7bSml29623 	nmsgs = 0;
25546f45ec7bSml29623 	for (i = 0; i < num_chunks; i++, tmp_bufp++) {
25556f45ec7bSml29623 		nmsgs += tmp_bufp->nblocks;
25566f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
25576f45ec7bSml29623 		    "==> nxge_map_txdma_channel_buf_ring: channel %d "
25586f45ec7bSml29623 		    "bufp $%p nblocks %d nmsgs %d",
25596f45ec7bSml29623 		    channel, tmp_bufp, tmp_bufp->nblocks, nmsgs));
25606f45ec7bSml29623 	}
25616f45ec7bSml29623 	if (!nmsgs) {
25626f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
25636f45ec7bSml29623 		    "<== nxge_map_txdma_channel_buf_ring: channel %d "
25646f45ec7bSml29623 		    "no msg blocks",
25656f45ec7bSml29623 		    channel));
25666f45ec7bSml29623 		status = NXGE_ERROR;
25676f45ec7bSml29623 		goto nxge_map_txdma_channel_buf_ring_exit;
25686f45ec7bSml29623 	}
25696f45ec7bSml29623 
25706f45ec7bSml29623 	tx_ring_p = (p_tx_ring_t)
25716f45ec7bSml29623 	    KMEM_ZALLOC(sizeof (tx_ring_t), KM_SLEEP);
25726f45ec7bSml29623 	MUTEX_INIT(&tx_ring_p->lock, NULL, MUTEX_DRIVER,
25736f45ec7bSml29623 	    (void *)nxgep->interrupt_cookie);
25741f8914d5Sml29623 
257522c0d73aSspeer 	(void) atomic_swap_32(&tx_ring_p->tx_ring_offline, NXGE_TX_RING_ONLINE);
25766895688eSspeer 	tx_ring_p->tx_ring_busy = B_FALSE;
25771f8914d5Sml29623 	tx_ring_p->nxgep = nxgep;
2578da14cebeSEric Cheng 	tx_ring_p->tx_ring_handle = (mac_ring_handle_t)NULL;
2579da14cebeSEric Cheng 	(void) snprintf(qname, TASKQ_NAMELEN, "tx_%d_%d",
2580da14cebeSEric Cheng 	    nxgep->instance, channel);
2581da14cebeSEric Cheng 	tx_ring_p->taskq = ddi_taskq_create(nxgep->dip, qname, 1,
2582da14cebeSEric Cheng 	    TASKQ_DEFAULTPRI, 0);
2583da14cebeSEric Cheng 	if (tx_ring_p->taskq == NULL) {
2584da14cebeSEric Cheng 		goto nxge_map_txdma_channel_buf_ring_fail1;
2585da14cebeSEric Cheng 	}
2586da14cebeSEric Cheng 
25876f45ec7bSml29623 	/*
25886f45ec7bSml29623 	 * Allocate transmit message rings and handles for packets
25896f45ec7bSml29623 	 * not to be copied to premapped buffers.
25906f45ec7bSml29623 	 */
25916f45ec7bSml29623 	size = nmsgs * sizeof (tx_msg_t);
25926f45ec7bSml29623 	tx_msg_ring = KMEM_ZALLOC(size, KM_SLEEP);
25936f45ec7bSml29623 	for (i = 0; i < nmsgs; i++) {
25946f45ec7bSml29623 		ddi_status = ddi_dma_alloc_handle(nxgep->dip, &nxge_tx_dma_attr,
25956f45ec7bSml29623 		    DDI_DMA_DONTWAIT, 0,
25966f45ec7bSml29623 		    &tx_msg_ring[i].dma_handle);
25976f45ec7bSml29623 		if (ddi_status != DDI_SUCCESS) {
25986f45ec7bSml29623 			status |= NXGE_DDI_FAILED;
25996f45ec7bSml29623 			break;
26006f45ec7bSml29623 		}
26016f45ec7bSml29623 	}
26026f45ec7bSml29623 	if (i < nmsgs) {
260356d930aeSspeer 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
260456d930aeSspeer 		    "Allocate handles failed."));
26056f45ec7bSml29623 		goto nxge_map_txdma_channel_buf_ring_fail1;
26066f45ec7bSml29623 	}
26076f45ec7bSml29623 
26086f45ec7bSml29623 	tx_ring_p->tdc = channel;
26096f45ec7bSml29623 	tx_ring_p->tx_msg_ring = tx_msg_ring;
26106f45ec7bSml29623 	tx_ring_p->tx_ring_size = nmsgs;
26116f45ec7bSml29623 	tx_ring_p->num_chunks = num_chunks;
26126f45ec7bSml29623 	if (!nxge_tx_intr_thres) {
26136f45ec7bSml29623 		nxge_tx_intr_thres = tx_ring_p->tx_ring_size/4;
26146f45ec7bSml29623 	}
26156f45ec7bSml29623 	tx_ring_p->tx_wrap_mask = tx_ring_p->tx_ring_size - 1;
26166f45ec7bSml29623 	tx_ring_p->rd_index = 0;
26176f45ec7bSml29623 	tx_ring_p->wr_index = 0;
26186f45ec7bSml29623 	tx_ring_p->ring_head.value = 0;
26196f45ec7bSml29623 	tx_ring_p->ring_kick_tail.value = 0;
26206f45ec7bSml29623 	tx_ring_p->descs_pending = 0;
26216f45ec7bSml29623 
26226f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
26236f45ec7bSml29623 	    "==> nxge_map_txdma_channel_buf_ring: channel %d "
26246f45ec7bSml29623 	    "actual tx desc max %d nmsgs %d "
26256f45ec7bSml29623 	    "(config nxge_tx_ring_size %d)",
26266f45ec7bSml29623 	    channel, tx_ring_p->tx_ring_size, nmsgs,
26276f45ec7bSml29623 	    nxge_tx_ring_size));
26286f45ec7bSml29623 
26296f45ec7bSml29623 	/*
26306f45ec7bSml29623 	 * Map in buffers from the buffer pool.
26316f45ec7bSml29623 	 */
26326f45ec7bSml29623 	index = 0;
26336f45ec7bSml29623 	bsize = dma_bufp->block_size;
26346f45ec7bSml29623 
26356f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel_buf_ring: "
26366f45ec7bSml29623 	    "dma_bufp $%p tx_rng_p $%p "
26376f45ec7bSml29623 	    "tx_msg_rng_p $%p bsize %d",
26386f45ec7bSml29623 	    dma_bufp, tx_ring_p, tx_msg_ring, bsize));
26396f45ec7bSml29623 
26406f45ec7bSml29623 	tx_buf_dma_handle = dma_bufp->dma_handle;
26416f45ec7bSml29623 	for (i = 0; i < num_chunks; i++, dma_bufp++) {
26426f45ec7bSml29623 		bsize = dma_bufp->block_size;
26436f45ec7bSml29623 		nblocks = dma_bufp->nblocks;
26446f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
26456f45ec7bSml29623 		    "==> nxge_map_txdma_channel_buf_ring: dma chunk %d "
26466f45ec7bSml29623 		    "size %d dma_bufp $%p",
26476f45ec7bSml29623 		    i, sizeof (nxge_dma_common_t), dma_bufp));
26486f45ec7bSml29623 
26496f45ec7bSml29623 		for (j = 0; j < nblocks; j++) {
26506f45ec7bSml29623 			tx_msg_ring[index].buf_dma_handle = tx_buf_dma_handle;
26516f45ec7bSml29623 			dmap = &tx_msg_ring[index++].buf_dma;
26526f45ec7bSml29623 #ifdef TX_MEM_DEBUG
26536f45ec7bSml29623 			NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
26546f45ec7bSml29623 			    "==> nxge_map_txdma_channel_buf_ring: j %d"
26556f45ec7bSml29623 			    "dmap $%p", i, dmap));
26566f45ec7bSml29623 #endif
26576f45ec7bSml29623 			nxge_setup_dma_common(dmap, dma_bufp, 1,
26586f45ec7bSml29623 			    bsize);
26596f45ec7bSml29623 		}
26606f45ec7bSml29623 	}
26616f45ec7bSml29623 
26626f45ec7bSml29623 	if (i < num_chunks) {
266356d930aeSspeer 		status = NXGE_ERROR;
26646f45ec7bSml29623 		goto nxge_map_txdma_channel_buf_ring_fail1;
26656f45ec7bSml29623 	}
26666f45ec7bSml29623 
26676f45ec7bSml29623 	*tx_desc_p = tx_ring_p;
26686f45ec7bSml29623 
26696f45ec7bSml29623 	goto nxge_map_txdma_channel_buf_ring_exit;
26706f45ec7bSml29623 
26716f45ec7bSml29623 nxge_map_txdma_channel_buf_ring_fail1:
2672da14cebeSEric Cheng 	if (tx_ring_p->taskq) {
2673da14cebeSEric Cheng 		ddi_taskq_destroy(tx_ring_p->taskq);
2674da14cebeSEric Cheng 		tx_ring_p->taskq = NULL;
26751f8914d5Sml29623 	}
26761f8914d5Sml29623 
26776f45ec7bSml29623 	index--;
26786f45ec7bSml29623 	for (; index >= 0; index--) {
267956d930aeSspeer 		if (tx_msg_ring[index].dma_handle != NULL) {
268056d930aeSspeer 			ddi_dma_free_handle(&tx_msg_ring[index].dma_handle);
26816f45ec7bSml29623 		}
26826f45ec7bSml29623 	}
26836f45ec7bSml29623 	MUTEX_DESTROY(&tx_ring_p->lock);
268456d930aeSspeer 	KMEM_FREE(tx_msg_ring, size);
26856f45ec7bSml29623 	KMEM_FREE(tx_ring_p, sizeof (tx_ring_t));
26866f45ec7bSml29623 
268756d930aeSspeer 	status = NXGE_ERROR;
268856d930aeSspeer 
26896f45ec7bSml29623 nxge_map_txdma_channel_buf_ring_exit:
26906f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
26916f45ec7bSml29623 	    "<== nxge_map_txdma_channel_buf_ring status 0x%x", status));
26926f45ec7bSml29623 
26936f45ec7bSml29623 	return (status);
26946f45ec7bSml29623 }
26956f45ec7bSml29623 
26966f45ec7bSml29623 /*ARGSUSED*/
26976f45ec7bSml29623 static void
nxge_unmap_txdma_channel_buf_ring(p_nxge_t nxgep,p_tx_ring_t tx_ring_p)26986f45ec7bSml29623 nxge_unmap_txdma_channel_buf_ring(p_nxge_t nxgep, p_tx_ring_t tx_ring_p)
26996f45ec7bSml29623 {
27006f45ec7bSml29623 	p_tx_msg_t 		tx_msg_ring;
27016f45ec7bSml29623 	p_tx_msg_t 		tx_msg_p;
27026f45ec7bSml29623 	int			i;
27036f45ec7bSml29623 
27046f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
27056f45ec7bSml29623 	    "==> nxge_unmap_txdma_channel_buf_ring"));
27066f45ec7bSml29623 	if (tx_ring_p == NULL) {
27076f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
27086f45ec7bSml29623 		    "<== nxge_unmap_txdma_channel_buf_ring: NULL ringp"));
27096f45ec7bSml29623 		return;
27106f45ec7bSml29623 	}
27116f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
27126f45ec7bSml29623 	    "==> nxge_unmap_txdma_channel_buf_ring: channel %d",
27136f45ec7bSml29623 	    tx_ring_p->tdc));
27146f45ec7bSml29623 
27156f45ec7bSml29623 	tx_msg_ring = tx_ring_p->tx_msg_ring;
2716678453a8Sspeer 
2717678453a8Sspeer 	/*
2718678453a8Sspeer 	 * Since the serialization thread, timer thread and
2719678453a8Sspeer 	 * interrupt thread can all call the transmit reclaim,
2720678453a8Sspeer 	 * the unmapping function needs to acquire the lock
2721678453a8Sspeer 	 * to free those buffers which were transmitted
2722678453a8Sspeer 	 * by the hardware already.
2723678453a8Sspeer 	 */
2724678453a8Sspeer 	MUTEX_ENTER(&tx_ring_p->lock);
2725678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
2726678453a8Sspeer 	    "==> nxge_unmap_txdma_channel_buf_ring (reclaim): "
2727678453a8Sspeer 	    "channel %d",
2728678453a8Sspeer 	    tx_ring_p->tdc));
2729678453a8Sspeer 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
2730678453a8Sspeer 
27316f45ec7bSml29623 	for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
27326f45ec7bSml29623 		tx_msg_p = &tx_msg_ring[i];
27336f45ec7bSml29623 		if (tx_msg_p->tx_message != NULL) {
27346f45ec7bSml29623 			freemsg(tx_msg_p->tx_message);
27356f45ec7bSml29623 			tx_msg_p->tx_message = NULL;
27366f45ec7bSml29623 		}
27376f45ec7bSml29623 	}
27386f45ec7bSml29623 
27396f45ec7bSml29623 	for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
27406f45ec7bSml29623 		if (tx_msg_ring[i].dma_handle != NULL) {
27416f45ec7bSml29623 			ddi_dma_free_handle(&tx_msg_ring[i].dma_handle);
27426f45ec7bSml29623 		}
2743678453a8Sspeer 		tx_msg_ring[i].dma_handle = NULL;
27446f45ec7bSml29623 	}
27456f45ec7bSml29623 
2746678453a8Sspeer 	MUTEX_EXIT(&tx_ring_p->lock);
2747678453a8Sspeer 
2748da14cebeSEric Cheng 	if (tx_ring_p->taskq) {
2749da14cebeSEric Cheng 		ddi_taskq_destroy(tx_ring_p->taskq);
2750da14cebeSEric Cheng 		tx_ring_p->taskq = NULL;
27511f8914d5Sml29623 	}
27521f8914d5Sml29623 
27536f45ec7bSml29623 	MUTEX_DESTROY(&tx_ring_p->lock);
27546f45ec7bSml29623 	KMEM_FREE(tx_msg_ring, sizeof (tx_msg_t) * tx_ring_p->tx_ring_size);
27556f45ec7bSml29623 	KMEM_FREE(tx_ring_p, sizeof (tx_ring_t));
27566f45ec7bSml29623 
27576f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
27586f45ec7bSml29623 	    "<== nxge_unmap_txdma_channel_buf_ring"));
27596f45ec7bSml29623 }
27606f45ec7bSml29623 
27616f45ec7bSml29623 static nxge_status_t
nxge_txdma_hw_start(p_nxge_t nxgep,int channel)2762678453a8Sspeer nxge_txdma_hw_start(p_nxge_t nxgep, int channel)
27636f45ec7bSml29623 {
27646f45ec7bSml29623 	p_tx_rings_t 		tx_rings;
27656f45ec7bSml29623 	p_tx_ring_t 		*tx_desc_rings;
27666f45ec7bSml29623 	p_tx_mbox_areas_t 	tx_mbox_areas_p;
27676f45ec7bSml29623 	p_tx_mbox_t		*tx_mbox_p;
27686f45ec7bSml29623 	nxge_status_t		status = NXGE_OK;
27696f45ec7bSml29623 
27706f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start"));
27716f45ec7bSml29623 
27726f45ec7bSml29623 	tx_rings = nxgep->tx_rings;
27736f45ec7bSml29623 	if (tx_rings == NULL) {
27746f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
27756f45ec7bSml29623 		    "<== nxge_txdma_hw_start: NULL ring pointer"));
27766f45ec7bSml29623 		return (NXGE_ERROR);
27776f45ec7bSml29623 	}
27786f45ec7bSml29623 	tx_desc_rings = tx_rings->rings;
27796f45ec7bSml29623 	if (tx_desc_rings == NULL) {
27806f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
27816f45ec7bSml29623 		    "<== nxge_txdma_hw_start: NULL ring pointers"));
27826f45ec7bSml29623 		return (NXGE_ERROR);
27836f45ec7bSml29623 	}
27846f45ec7bSml29623 
2785678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
2786678453a8Sspeer 	    "tx_rings $%p tx_desc_rings $%p", tx_rings, tx_desc_rings));
27876f45ec7bSml29623 
27886f45ec7bSml29623 	tx_mbox_areas_p = nxgep->tx_mbox_areas_p;
27896f45ec7bSml29623 	tx_mbox_p = tx_mbox_areas_p->txmbox_areas_p;
27906f45ec7bSml29623 
27916f45ec7bSml29623 	status = nxge_txdma_start_channel(nxgep, channel,
2792678453a8Sspeer 	    (p_tx_ring_t)tx_desc_rings[channel],
2793678453a8Sspeer 	    (p_tx_mbox_t)tx_mbox_p[channel]);
27946f45ec7bSml29623 	if (status != NXGE_OK) {
27956f45ec7bSml29623 		goto nxge_txdma_hw_start_fail1;
27966f45ec7bSml29623 	}
27976f45ec7bSml29623 
27986f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
27996f45ec7bSml29623 	    "tx_rings $%p rings $%p",
28006f45ec7bSml29623 	    nxgep->tx_rings, nxgep->tx_rings->rings));
28016f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
28026f45ec7bSml29623 	    "tx_rings $%p tx_desc_rings $%p",
28036f45ec7bSml29623 	    nxgep->tx_rings, tx_desc_rings));
28046f45ec7bSml29623 
28056f45ec7bSml29623 	goto nxge_txdma_hw_start_exit;
28066f45ec7bSml29623 
28076f45ec7bSml29623 nxge_txdma_hw_start_fail1:
28086f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
28096f45ec7bSml29623 	    "==> nxge_txdma_hw_start: disable "
2810678453a8Sspeer 	    "(status 0x%x channel %d)", status, channel));
28116f45ec7bSml29623 
28126f45ec7bSml29623 nxge_txdma_hw_start_exit:
28136f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
28146f45ec7bSml29623 	    "==> nxge_txdma_hw_start: (status 0x%x)", status));
28156f45ec7bSml29623 
28166f45ec7bSml29623 	return (status);
28176f45ec7bSml29623 }
28186f45ec7bSml29623 
2819678453a8Sspeer /*
2820678453a8Sspeer  * nxge_txdma_start_channel
2821678453a8Sspeer  *
2822678453a8Sspeer  *	Start a TDC.
2823678453a8Sspeer  *
2824678453a8Sspeer  * Arguments:
2825678453a8Sspeer  * 	nxgep
2826678453a8Sspeer  * 	channel		The channel to start.
2827678453a8Sspeer  * 	tx_ring_p	channel's transmit descriptor ring.
2828678453a8Sspeer  * 	tx_mbox_p	channel' smailbox.
2829678453a8Sspeer  *
2830678453a8Sspeer  * Notes:
2831678453a8Sspeer  *
2832678453a8Sspeer  * NPI/NXGE function calls:
2833678453a8Sspeer  *	nxge_reset_txdma_channel()
2834678453a8Sspeer  *	nxge_init_txdma_channel_event_mask()
2835678453a8Sspeer  *	nxge_enable_txdma_channel()
2836678453a8Sspeer  *
2837678453a8Sspeer  * Registers accessed:
2838678453a8Sspeer  *	none directly (see functions above).
2839678453a8Sspeer  *
2840678453a8Sspeer  * Context:
2841678453a8Sspeer  *	Any domain
2842678453a8Sspeer  */
28436f45ec7bSml29623 static nxge_status_t
nxge_txdma_start_channel(p_nxge_t nxgep,uint16_t channel,p_tx_ring_t tx_ring_p,p_tx_mbox_t tx_mbox_p)28446f45ec7bSml29623 nxge_txdma_start_channel(p_nxge_t nxgep, uint16_t channel,
28456f45ec7bSml29623     p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p)
28466f45ec7bSml29623 
28476f45ec7bSml29623 {
28486f45ec7bSml29623 	nxge_status_t		status = NXGE_OK;
28496f45ec7bSml29623 
28506f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
28516f45ec7bSml29623 		"==> nxge_txdma_start_channel (channel %d)", channel));
28526f45ec7bSml29623 	/*
28536f45ec7bSml29623 	 * TXDMA/TXC must be in stopped state.
28546f45ec7bSml29623 	 */
28556f45ec7bSml29623 	(void) nxge_txdma_stop_inj_err(nxgep, channel);
28566f45ec7bSml29623 
28576f45ec7bSml29623 	/*
28586f45ec7bSml29623 	 * Reset TXDMA channel
28596f45ec7bSml29623 	 */
28606f45ec7bSml29623 	tx_ring_p->tx_cs.value = 0;
28616f45ec7bSml29623 	tx_ring_p->tx_cs.bits.ldw.rst = 1;
28626f45ec7bSml29623 	status = nxge_reset_txdma_channel(nxgep, channel,
28636f45ec7bSml29623 			tx_ring_p->tx_cs.value);
28646f45ec7bSml29623 	if (status != NXGE_OK) {
28656f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
28666f45ec7bSml29623 			"==> nxge_txdma_start_channel (channel %d)"
28676f45ec7bSml29623 			" reset channel failed 0x%x", channel, status));
28686f45ec7bSml29623 		goto nxge_txdma_start_channel_exit;
28696f45ec7bSml29623 	}
28706f45ec7bSml29623 
28716f45ec7bSml29623 	/*
28726f45ec7bSml29623 	 * Initialize the TXDMA channel specific FZC control
28736f45ec7bSml29623 	 * configurations. These FZC registers are pertaining
28746f45ec7bSml29623 	 * to each TX channel (i.e. logical pages).
28756f45ec7bSml29623 	 */
2876678453a8Sspeer 	if (!isLDOMguest(nxgep)) {
28776f45ec7bSml29623 		status = nxge_init_fzc_txdma_channel(nxgep, channel,
28786f45ec7bSml29623 		    tx_ring_p, tx_mbox_p);
28796f45ec7bSml29623 		if (status != NXGE_OK) {
28806f45ec7bSml29623 			goto nxge_txdma_start_channel_exit;
28816f45ec7bSml29623 		}
2882678453a8Sspeer 	}
28836f45ec7bSml29623 
28846f45ec7bSml29623 	/*
28856f45ec7bSml29623 	 * Initialize the event masks.
28866f45ec7bSml29623 	 */
28876f45ec7bSml29623 	tx_ring_p->tx_evmask.value = 0;
28886f45ec7bSml29623 	status = nxge_init_txdma_channel_event_mask(nxgep,
28896f45ec7bSml29623 	    channel, &tx_ring_p->tx_evmask);
28906f45ec7bSml29623 	if (status != NXGE_OK) {
28916f45ec7bSml29623 		goto nxge_txdma_start_channel_exit;
28926f45ec7bSml29623 	}
28936f45ec7bSml29623 
28946f45ec7bSml29623 	/*
28956f45ec7bSml29623 	 * Load TXDMA descriptors, buffers, mailbox,
28966f45ec7bSml29623 	 * initialise the DMA channels and
28976f45ec7bSml29623 	 * enable each DMA channel.
28986f45ec7bSml29623 	 */
28996f45ec7bSml29623 	status = nxge_enable_txdma_channel(nxgep, channel,
29006f45ec7bSml29623 			tx_ring_p, tx_mbox_p);
29016f45ec7bSml29623 	if (status != NXGE_OK) {
29026f45ec7bSml29623 		goto nxge_txdma_start_channel_exit;
29036f45ec7bSml29623 	}
29046f45ec7bSml29623 
29056f45ec7bSml29623 nxge_txdma_start_channel_exit:
29066f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_start_channel"));
29076f45ec7bSml29623 
29086f45ec7bSml29623 	return (status);
29096f45ec7bSml29623 }
29106f45ec7bSml29623 
2911678453a8Sspeer /*
2912678453a8Sspeer  * nxge_txdma_stop_channel
2913678453a8Sspeer  *
2914678453a8Sspeer  *	Stop a TDC.
2915678453a8Sspeer  *
2916678453a8Sspeer  * Arguments:
2917678453a8Sspeer  * 	nxgep
2918678453a8Sspeer  * 	channel		The channel to stop.
2919678453a8Sspeer  * 	tx_ring_p	channel's transmit descriptor ring.
2920678453a8Sspeer  * 	tx_mbox_p	channel' smailbox.
2921678453a8Sspeer  *
2922678453a8Sspeer  * Notes:
2923678453a8Sspeer  *
2924678453a8Sspeer  * NPI/NXGE function calls:
2925678453a8Sspeer  *	nxge_txdma_stop_inj_err()
2926678453a8Sspeer  *	nxge_reset_txdma_channel()
2927678453a8Sspeer  *	nxge_init_txdma_channel_event_mask()
2928678453a8Sspeer  *	nxge_init_txdma_channel_cntl_stat()
2929678453a8Sspeer  *	nxge_disable_txdma_channel()
2930678453a8Sspeer  *
2931678453a8Sspeer  * Registers accessed:
2932678453a8Sspeer  *	none directly (see functions above).
2933678453a8Sspeer  *
2934678453a8Sspeer  * Context:
2935678453a8Sspeer  *	Any domain
2936678453a8Sspeer  */
29376f45ec7bSml29623 /*ARGSUSED*/
29386f45ec7bSml29623 static nxge_status_t
nxge_txdma_stop_channel(p_nxge_t nxgep,uint16_t channel)2939678453a8Sspeer nxge_txdma_stop_channel(p_nxge_t nxgep, uint16_t channel)
29406f45ec7bSml29623 {
2941678453a8Sspeer 	p_tx_ring_t tx_ring_p;
29426f45ec7bSml29623 	int status = NXGE_OK;
29436f45ec7bSml29623 
29446f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
29456f45ec7bSml29623 	    "==> nxge_txdma_stop_channel: channel %d", channel));
29466f45ec7bSml29623 
29476f45ec7bSml29623 	/*
29486f45ec7bSml29623 	 * Stop (disable) TXDMA and TXC (if stop bit is set
29496f45ec7bSml29623 	 * and STOP_N_GO bit not set, the TXDMA reset state will
29506f45ec7bSml29623 	 * not be set if reset TXDMA.
29516f45ec7bSml29623 	 */
29526f45ec7bSml29623 	(void) nxge_txdma_stop_inj_err(nxgep, channel);
29536f45ec7bSml29623 
2954ef523517SMichael Speer 	if (nxgep->tx_rings == NULL) {
2955ef523517SMichael Speer 		status = NXGE_ERROR;
2956ef523517SMichael Speer 		goto nxge_txdma_stop_channel_exit;
2957ef523517SMichael Speer 	}
2958ef523517SMichael Speer 
2959678453a8Sspeer 	tx_ring_p = nxgep->tx_rings->rings[channel];
2960ef523517SMichael Speer 	if (tx_ring_p == NULL) {
2961ef523517SMichael Speer 		status = NXGE_ERROR;
2962ef523517SMichael Speer 		goto nxge_txdma_stop_channel_exit;
2963ef523517SMichael Speer 	}
2964678453a8Sspeer 
29656f45ec7bSml29623 	/*
29666f45ec7bSml29623 	 * Reset TXDMA channel
29676f45ec7bSml29623 	 */
29686f45ec7bSml29623 	tx_ring_p->tx_cs.value = 0;
29696f45ec7bSml29623 	tx_ring_p->tx_cs.bits.ldw.rst = 1;
29706f45ec7bSml29623 	status = nxge_reset_txdma_channel(nxgep, channel,
29716f45ec7bSml29623 	    tx_ring_p->tx_cs.value);
29726f45ec7bSml29623 	if (status != NXGE_OK) {
29736f45ec7bSml29623 		goto nxge_txdma_stop_channel_exit;
29746f45ec7bSml29623 	}
29756f45ec7bSml29623 
29766f45ec7bSml29623 #ifdef HARDWARE_REQUIRED
29776f45ec7bSml29623 	/* Set up the interrupt event masks. */
29786f45ec7bSml29623 	tx_ring_p->tx_evmask.value = 0;
29796f45ec7bSml29623 	status = nxge_init_txdma_channel_event_mask(nxgep,
29806f45ec7bSml29623 	    channel, &tx_ring_p->tx_evmask);
29816f45ec7bSml29623 	if (status != NXGE_OK) {
29826f45ec7bSml29623 		goto nxge_txdma_stop_channel_exit;
29836f45ec7bSml29623 	}
29846f45ec7bSml29623 
29856f45ec7bSml29623 	/* Initialize the DMA control and status register */
29866f45ec7bSml29623 	tx_ring_p->tx_cs.value = TX_ENT_MSK_MK_ALL;
29876f45ec7bSml29623 	status = nxge_init_txdma_channel_cntl_stat(nxgep, channel,
29886f45ec7bSml29623 	    tx_ring_p->tx_cs.value);
29896f45ec7bSml29623 	if (status != NXGE_OK) {
29906f45ec7bSml29623 		goto nxge_txdma_stop_channel_exit;
29916f45ec7bSml29623 	}
29926f45ec7bSml29623 
2993678453a8Sspeer 	tx_mbox_p = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
2994678453a8Sspeer 
29956f45ec7bSml29623 	/* Disable channel */
29966f45ec7bSml29623 	status = nxge_disable_txdma_channel(nxgep, channel,
29976f45ec7bSml29623 	    tx_ring_p, tx_mbox_p);
29986f45ec7bSml29623 	if (status != NXGE_OK) {
29996f45ec7bSml29623 		goto nxge_txdma_start_channel_exit;
30006f45ec7bSml29623 	}
30016f45ec7bSml29623 
30026f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
30036f45ec7bSml29623 	    "==> nxge_txdma_stop_channel: event done"));
30046f45ec7bSml29623 
30056f45ec7bSml29623 #endif
30066f45ec7bSml29623 
30076f45ec7bSml29623 nxge_txdma_stop_channel_exit:
30086f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_stop_channel"));
30096f45ec7bSml29623 	return (status);
30106f45ec7bSml29623 }
30116f45ec7bSml29623 
3012678453a8Sspeer /*
3013678453a8Sspeer  * nxge_txdma_get_ring
3014678453a8Sspeer  *
3015678453a8Sspeer  *	Get the ring for a TDC.
3016678453a8Sspeer  *
3017678453a8Sspeer  * Arguments:
3018678453a8Sspeer  * 	nxgep
3019678453a8Sspeer  * 	channel
3020678453a8Sspeer  *
3021678453a8Sspeer  * Notes:
3022678453a8Sspeer  *
3023678453a8Sspeer  * NPI/NXGE function calls:
3024678453a8Sspeer  *
3025678453a8Sspeer  * Registers accessed:
3026678453a8Sspeer  *
3027678453a8Sspeer  * Context:
3028678453a8Sspeer  *	Any domain
3029678453a8Sspeer  */
30306f45ec7bSml29623 static p_tx_ring_t
nxge_txdma_get_ring(p_nxge_t nxgep,uint16_t channel)30316f45ec7bSml29623 nxge_txdma_get_ring(p_nxge_t nxgep, uint16_t channel)
30326f45ec7bSml29623 {
3033678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
3034678453a8Sspeer 	int tdc;
30356f45ec7bSml29623 
30366f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_ring"));
30376f45ec7bSml29623 
3038678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
30396f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3040678453a8Sspeer 		    "<== nxge_txdma_get_ring: NULL ring pointer(s)"));
3041678453a8Sspeer 		goto return_null;
3042678453a8Sspeer 	}
3043678453a8Sspeer 
3044678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3045678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3046678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3047678453a8Sspeer 			if (ring) {
3048678453a8Sspeer 				if (channel == ring->tdc) {
3049678453a8Sspeer 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
3050678453a8Sspeer 					    "<== nxge_txdma_get_ring: "
3051678453a8Sspeer 					    "tdc %d ring $%p", tdc, ring));
3052678453a8Sspeer 					return (ring);
3053678453a8Sspeer 				}
3054678453a8Sspeer 			}
3055678453a8Sspeer 		}
3056678453a8Sspeer 	}
3057678453a8Sspeer 
3058678453a8Sspeer return_null:
3059678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_ring: "
3060678453a8Sspeer 	    "ring not found"));
3061678453a8Sspeer 
30626f45ec7bSml29623 	return (NULL);
30636f45ec7bSml29623 }
30646f45ec7bSml29623 
3065678453a8Sspeer /*
3066678453a8Sspeer  * nxge_txdma_get_mbox
3067678453a8Sspeer  *
3068678453a8Sspeer  *	Get the mailbox for a TDC.
3069678453a8Sspeer  *
3070678453a8Sspeer  * Arguments:
3071678453a8Sspeer  * 	nxgep
3072678453a8Sspeer  * 	channel
3073678453a8Sspeer  *
3074678453a8Sspeer  * Notes:
3075678453a8Sspeer  *
3076678453a8Sspeer  * NPI/NXGE function calls:
3077678453a8Sspeer  *
3078678453a8Sspeer  * Registers accessed:
3079678453a8Sspeer  *
3080678453a8Sspeer  * Context:
3081678453a8Sspeer  *	Any domain
3082678453a8Sspeer  */
30836f45ec7bSml29623 static p_tx_mbox_t
nxge_txdma_get_mbox(p_nxge_t nxgep,uint16_t channel)30846f45ec7bSml29623 nxge_txdma_get_mbox(p_nxge_t nxgep, uint16_t channel)
30856f45ec7bSml29623 {
3086678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
3087678453a8Sspeer 	int tdc;
30886f45ec7bSml29623 
30896f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_mbox"));
30906f45ec7bSml29623 
3091678453a8Sspeer 	if (nxgep->tx_mbox_areas_p == 0 ||
3092678453a8Sspeer 	    nxgep->tx_mbox_areas_p->txmbox_areas_p == 0) {
3093678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3094678453a8Sspeer 		    "<== nxge_txdma_get_mbox: NULL mailbox pointer(s)"));
3095678453a8Sspeer 		goto return_null;
30966f45ec7bSml29623 	}
30976f45ec7bSml29623 
3098678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
3099678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3100678453a8Sspeer 		    "<== nxge_txdma_get_mbox: NULL ring pointer(s)"));
3101678453a8Sspeer 		goto return_null;
31026f45ec7bSml29623 	}
31036f45ec7bSml29623 
3104678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3105678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3106678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3107678453a8Sspeer 			if (ring) {
3108678453a8Sspeer 				if (channel == ring->tdc) {
3109678453a8Sspeer 					tx_mbox_t *mailbox = nxgep->
3110678453a8Sspeer 					    tx_mbox_areas_p->
3111678453a8Sspeer 					    txmbox_areas_p[tdc];
31126f45ec7bSml29623 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
31136f45ec7bSml29623 					    "<== nxge_txdma_get_mbox: tdc %d "
3114678453a8Sspeer 					    "ring $%p", tdc, mailbox));
3115678453a8Sspeer 					return (mailbox);
3116678453a8Sspeer 				}
3117678453a8Sspeer 			}
31186f45ec7bSml29623 		}
31196f45ec7bSml29623 	}
31206f45ec7bSml29623 
3121678453a8Sspeer return_null:
3122678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_mbox: "
3123678453a8Sspeer 	    "mailbox not found"));
3124678453a8Sspeer 
31256f45ec7bSml29623 	return (NULL);
31266f45ec7bSml29623 }
31276f45ec7bSml29623 
3128678453a8Sspeer /*
3129678453a8Sspeer  * nxge_tx_err_evnts
3130678453a8Sspeer  *
3131678453a8Sspeer  *	Recover a TDC.
3132678453a8Sspeer  *
3133678453a8Sspeer  * Arguments:
3134678453a8Sspeer  * 	nxgep
3135678453a8Sspeer  * 	index	The index to the TDC ring.
3136678453a8Sspeer  * 	ldvp	Used to get the channel number ONLY.
3137678453a8Sspeer  * 	cs	A copy of the bits from TX_CS.
3138678453a8Sspeer  *
3139678453a8Sspeer  * Notes:
3140678453a8Sspeer  *	Calling tree:
3141678453a8Sspeer  *	 nxge_tx_intr()
3142678453a8Sspeer  *
3143678453a8Sspeer  * NPI/NXGE function calls:
3144678453a8Sspeer  *	npi_txdma_ring_error_get()
3145678453a8Sspeer  *	npi_txdma_inj_par_error_get()
3146678453a8Sspeer  *	nxge_txdma_fatal_err_recover()
3147678453a8Sspeer  *
3148678453a8Sspeer  * Registers accessed:
3149678453a8Sspeer  *	TX_RNG_ERR_LOGH	DMC+0x40048 Transmit Ring Error Log High
3150678453a8Sspeer  *	TX_RNG_ERR_LOGL DMC+0x40050 Transmit Ring Error Log Low
3151678453a8Sspeer  *	TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error
3152678453a8Sspeer  *
3153678453a8Sspeer  * Context:
3154678453a8Sspeer  *	Any domain	XXX Remove code which accesses TDMC_INJ_PAR_ERR.
3155678453a8Sspeer  */
31566f45ec7bSml29623 /*ARGSUSED*/
31576f45ec7bSml29623 static nxge_status_t
nxge_tx_err_evnts(p_nxge_t nxgep,uint_t index,p_nxge_ldv_t ldvp,tx_cs_t cs)31586f45ec7bSml29623 nxge_tx_err_evnts(p_nxge_t nxgep, uint_t index, p_nxge_ldv_t ldvp, tx_cs_t cs)
31596f45ec7bSml29623 {
31606f45ec7bSml29623 	npi_handle_t		handle;
31616f45ec7bSml29623 	npi_status_t		rs;
31626f45ec7bSml29623 	uint8_t			channel;
31636f45ec7bSml29623 	p_tx_ring_t 		*tx_rings;
31646f45ec7bSml29623 	p_tx_ring_t 		tx_ring_p;
31656f45ec7bSml29623 	p_nxge_tx_ring_stats_t	tdc_stats;
31666f45ec7bSml29623 	boolean_t		txchan_fatal = B_FALSE;
31676f45ec7bSml29623 	nxge_status_t		status = NXGE_OK;
31686f45ec7bSml29623 	tdmc_inj_par_err_t	par_err;
31696f45ec7bSml29623 	uint32_t		value;
31706f45ec7bSml29623 
3171678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX2_CTL, "==> nxge_tx_err_evnts"));
31726f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
31736f45ec7bSml29623 	channel = ldvp->channel;
31746f45ec7bSml29623 
31756f45ec7bSml29623 	tx_rings = nxgep->tx_rings->rings;
31766f45ec7bSml29623 	tx_ring_p = tx_rings[index];
31776f45ec7bSml29623 	tdc_stats = tx_ring_p->tdc_stats;
31786f45ec7bSml29623 	if ((cs.bits.ldw.pkt_size_err) || (cs.bits.ldw.pref_buf_par_err) ||
31796f45ec7bSml29623 	    (cs.bits.ldw.nack_pref) || (cs.bits.ldw.nack_pkt_rd) ||
31806f45ec7bSml29623 	    (cs.bits.ldw.conf_part_err) || (cs.bits.ldw.pkt_prt_err)) {
31816f45ec7bSml29623 		if ((rs = npi_txdma_ring_error_get(handle, channel,
31826f45ec7bSml29623 		    &tdc_stats->errlog)) != NPI_SUCCESS)
31836f45ec7bSml29623 			return (NXGE_ERROR | rs);
31846f45ec7bSml29623 	}
31856f45ec7bSml29623 
31866f45ec7bSml29623 	if (cs.bits.ldw.mbox_err) {
31876f45ec7bSml29623 		tdc_stats->mbox_err++;
31886f45ec7bSml29623 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
31896f45ec7bSml29623 		    NXGE_FM_EREPORT_TDMC_MBOX_ERR);
31906f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
31916f45ec7bSml29623 		    "==> nxge_tx_err_evnts(channel %d): "
31926f45ec7bSml29623 		    "fatal error: mailbox", channel));
31936f45ec7bSml29623 		txchan_fatal = B_TRUE;
31946f45ec7bSml29623 	}
31956f45ec7bSml29623 	if (cs.bits.ldw.pkt_size_err) {
31966f45ec7bSml29623 		tdc_stats->pkt_size_err++;
31976f45ec7bSml29623 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
31986f45ec7bSml29623 		    NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR);
31996f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
32006f45ec7bSml29623 		    "==> nxge_tx_err_evnts(channel %d): "
32016f45ec7bSml29623 		    "fatal error: pkt_size_err", channel));
32026f45ec7bSml29623 		txchan_fatal = B_TRUE;
32036f45ec7bSml29623 	}
32046f45ec7bSml29623 	if (cs.bits.ldw.tx_ring_oflow) {
32056f45ec7bSml29623 		tdc_stats->tx_ring_oflow++;
32066f45ec7bSml29623 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
32076f45ec7bSml29623 		    NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW);
32086f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
32096f45ec7bSml29623 		    "==> nxge_tx_err_evnts(channel %d): "
32106f45ec7bSml29623 		    "fatal error: tx_ring_oflow", channel));
32116f45ec7bSml29623 		txchan_fatal = B_TRUE;
32126f45ec7bSml29623 	}
32136f45ec7bSml29623 	if (cs.bits.ldw.pref_buf_par_err) {
32146f45ec7bSml29623 		tdc_stats->pre_buf_par_err++;
32156f45ec7bSml29623 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
32166f45ec7bSml29623 		    NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR);
32176f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
32186f45ec7bSml29623 		    "==> nxge_tx_err_evnts(channel %d): "
32196f45ec7bSml29623 		    "fatal error: pre_buf_par_err", channel));
32206f45ec7bSml29623 		/* Clear error injection source for parity error */
32216f45ec7bSml29623 		(void) npi_txdma_inj_par_error_get(handle, &value);
32226f45ec7bSml29623 		par_err.value = value;
32236f45ec7bSml29623 		par_err.bits.ldw.inject_parity_error &= ~(1 << channel);
32246f45ec7bSml29623 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
32256f45ec7bSml29623 		txchan_fatal = B_TRUE;
32266f45ec7bSml29623 	}
32276f45ec7bSml29623 	if (cs.bits.ldw.nack_pref) {
32286f45ec7bSml29623 		tdc_stats->nack_pref++;
32296f45ec7bSml29623 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
32306f45ec7bSml29623 		    NXGE_FM_EREPORT_TDMC_NACK_PREF);
32316f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
32326f45ec7bSml29623 		    "==> nxge_tx_err_evnts(channel %d): "
32336f45ec7bSml29623 		    "fatal error: nack_pref", channel));
32346f45ec7bSml29623 		txchan_fatal = B_TRUE;
32356f45ec7bSml29623 	}
32366f45ec7bSml29623 	if (cs.bits.ldw.nack_pkt_rd) {
32376f45ec7bSml29623 		tdc_stats->nack_pkt_rd++;
32386f45ec7bSml29623 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
32396f45ec7bSml29623 		    NXGE_FM_EREPORT_TDMC_NACK_PKT_RD);
32406f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
32416f45ec7bSml29623 		    "==> nxge_tx_err_evnts(channel %d): "
32426f45ec7bSml29623 		    "fatal error: nack_pkt_rd", channel));
32436f45ec7bSml29623 		txchan_fatal = B_TRUE;
32446f45ec7bSml29623 	}
32456f45ec7bSml29623 	if (cs.bits.ldw.conf_part_err) {
32466f45ec7bSml29623 		tdc_stats->conf_part_err++;
32476f45ec7bSml29623 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
32486f45ec7bSml29623 		    NXGE_FM_EREPORT_TDMC_CONF_PART_ERR);
32496f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
32506f45ec7bSml29623 		    "==> nxge_tx_err_evnts(channel %d): "
32516f45ec7bSml29623 		    "fatal error: config_partition_err", channel));
32526f45ec7bSml29623 		txchan_fatal = B_TRUE;
32536f45ec7bSml29623 	}
32546f45ec7bSml29623 	if (cs.bits.ldw.pkt_prt_err) {
32556f45ec7bSml29623 		tdc_stats->pkt_part_err++;
32566f45ec7bSml29623 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
32576f45ec7bSml29623 		    NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR);
32586f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
32596f45ec7bSml29623 		    "==> nxge_tx_err_evnts(channel %d): "
32606f45ec7bSml29623 		    "fatal error: pkt_prt_err", channel));
32616f45ec7bSml29623 		txchan_fatal = B_TRUE;
32626f45ec7bSml29623 	}
32636f45ec7bSml29623 
32646f45ec7bSml29623 	/* Clear error injection source in case this is an injected error */
32656f45ec7bSml29623 	TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG, channel, 0);
32666f45ec7bSml29623 
32676f45ec7bSml29623 	if (txchan_fatal) {
32686f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
32696f45ec7bSml29623 		    " nxge_tx_err_evnts: "
32706f45ec7bSml29623 		    " fatal error on channel %d cs 0x%llx\n",
32716f45ec7bSml29623 		    channel, cs.value));
32726f45ec7bSml29623 		status = nxge_txdma_fatal_err_recover(nxgep, channel,
32736f45ec7bSml29623 		    tx_ring_p);
32746f45ec7bSml29623 		if (status == NXGE_OK) {
32756f45ec7bSml29623 			FM_SERVICE_RESTORED(nxgep);
32766f45ec7bSml29623 		}
32776f45ec7bSml29623 	}
32786f45ec7bSml29623 
3279678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX2_CTL, "<== nxge_tx_err_evnts"));
32806f45ec7bSml29623 
32816f45ec7bSml29623 	return (status);
32826f45ec7bSml29623 }
32836f45ec7bSml29623 
32846f45ec7bSml29623 static nxge_status_t
nxge_txdma_fatal_err_recover(p_nxge_t nxgep,uint16_t channel,p_tx_ring_t tx_ring_p)3285678453a8Sspeer nxge_txdma_fatal_err_recover(
3286678453a8Sspeer 	p_nxge_t nxgep,
3287678453a8Sspeer 	uint16_t channel,
32886f45ec7bSml29623 	p_tx_ring_t tx_ring_p)
32896f45ec7bSml29623 {
32906f45ec7bSml29623 	npi_handle_t	handle;
32916f45ec7bSml29623 	npi_status_t	rs = NPI_SUCCESS;
32926f45ec7bSml29623 	p_tx_mbox_t	tx_mbox_p;
32936f45ec7bSml29623 	nxge_status_t	status = NXGE_OK;
32946f45ec7bSml29623 
32956f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fatal_err_recover"));
32966f45ec7bSml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
32976f45ec7bSml29623 	    "Recovering from TxDMAChannel#%d error...", channel));
32986f45ec7bSml29623 
32996f45ec7bSml29623 	/*
33006f45ec7bSml29623 	 * Stop the dma channel waits for the stop done.
33016f45ec7bSml29623 	 * If the stop done bit is not set, then create
33026f45ec7bSml29623 	 * an error.
33036f45ec7bSml29623 	 */
33046f45ec7bSml29623 
33056f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
33066f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel stop..."));
33076f45ec7bSml29623 	MUTEX_ENTER(&tx_ring_p->lock);
33086f45ec7bSml29623 	rs = npi_txdma_channel_control(handle, TXDMA_STOP, channel);
33096f45ec7bSml29623 	if (rs != NPI_SUCCESS) {
33106f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
33116f45ec7bSml29623 		    "==> nxge_txdma_fatal_err_recover (channel %d): "
33126f45ec7bSml29623 		    "stop failed ", channel));
33136f45ec7bSml29623 		goto fail;
33146f45ec7bSml29623 	}
33156f45ec7bSml29623 
33166f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reclaim..."));
33176f45ec7bSml29623 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
33186f45ec7bSml29623 
33196f45ec7bSml29623 	/*
33206f45ec7bSml29623 	 * Reset TXDMA channel
33216f45ec7bSml29623 	 */
33226f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reset..."));
33236f45ec7bSml29623 	if ((rs = npi_txdma_channel_control(handle, TXDMA_RESET, channel)) !=
33246f45ec7bSml29623 	    NPI_SUCCESS) {
33256f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
33266f45ec7bSml29623 		    "==> nxge_txdma_fatal_err_recover (channel %d)"
33276f45ec7bSml29623 		    " reset channel failed 0x%x", channel, rs));
33286f45ec7bSml29623 		goto fail;
33296f45ec7bSml29623 	}
33306f45ec7bSml29623 
33316f45ec7bSml29623 	/*
33326f45ec7bSml29623 	 * Reset the tail (kick) register to 0.
33336f45ec7bSml29623 	 * (Hardware will not reset it. Tx overflow fatal
33346f45ec7bSml29623 	 * error if tail is not set to 0 after reset!
33356f45ec7bSml29623 	 */
33366f45ec7bSml29623 	TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0);
33376f45ec7bSml29623 
33386f45ec7bSml29623 	/* Restart TXDMA channel */
33396f45ec7bSml29623 
3340678453a8Sspeer 	if (!isLDOMguest(nxgep)) {
3341678453a8Sspeer 		tx_mbox_p = nxge_txdma_get_mbox(nxgep, channel);
3342678453a8Sspeer 
3343678453a8Sspeer 		// XXX This is a problem in HIO!
33446f45ec7bSml29623 		/*
33456f45ec7bSml29623 		 * Initialize the TXDMA channel specific FZC control
33466f45ec7bSml29623 		 * configurations. These FZC registers are pertaining
33476f45ec7bSml29623 		 * to each TX channel (i.e. logical pages).
33486f45ec7bSml29623 		 */
33496f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel restart..."));
33506f45ec7bSml29623 		status = nxge_init_fzc_txdma_channel(nxgep, channel,
33516f45ec7bSml29623 		    tx_ring_p, tx_mbox_p);
33526f45ec7bSml29623 		if (status != NXGE_OK)
33536f45ec7bSml29623 			goto fail;
3354678453a8Sspeer 	}
33556f45ec7bSml29623 
33566f45ec7bSml29623 	/*
33576f45ec7bSml29623 	 * Initialize the event masks.
33586f45ec7bSml29623 	 */
33596f45ec7bSml29623 	tx_ring_p->tx_evmask.value = 0;
33606f45ec7bSml29623 	status = nxge_init_txdma_channel_event_mask(nxgep, channel,
33616f45ec7bSml29623 	    &tx_ring_p->tx_evmask);
33626f45ec7bSml29623 	if (status != NXGE_OK)
33636f45ec7bSml29623 		goto fail;
33646f45ec7bSml29623 
33656f45ec7bSml29623 	tx_ring_p->wr_index_wrap = B_FALSE;
33666f45ec7bSml29623 	tx_ring_p->wr_index = 0;
33676f45ec7bSml29623 	tx_ring_p->rd_index = 0;
33686f45ec7bSml29623 
33696f45ec7bSml29623 	/*
33706f45ec7bSml29623 	 * Load TXDMA descriptors, buffers, mailbox,
33716f45ec7bSml29623 	 * initialise the DMA channels and
33726f45ec7bSml29623 	 * enable each DMA channel.
33736f45ec7bSml29623 	 */
33746f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel enable..."));
33756f45ec7bSml29623 	status = nxge_enable_txdma_channel(nxgep, channel,
33766f45ec7bSml29623 	    tx_ring_p, tx_mbox_p);
33776f45ec7bSml29623 	MUTEX_EXIT(&tx_ring_p->lock);
33786f45ec7bSml29623 	if (status != NXGE_OK)
33796f45ec7bSml29623 		goto fail;
33806f45ec7bSml29623 
33816f45ec7bSml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
33826f45ec7bSml29623 	    "Recovery Successful, TxDMAChannel#%d Restored",
33836f45ec7bSml29623 	    channel));
33846f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fatal_err_recover"));
33856f45ec7bSml29623 
33866f45ec7bSml29623 	return (NXGE_OK);
33876f45ec7bSml29623 
33886f45ec7bSml29623 fail:
33896f45ec7bSml29623 	MUTEX_EXIT(&tx_ring_p->lock);
33902d99c5d4SMichael Speer 
33916f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
33926f45ec7bSml29623 	    "nxge_txdma_fatal_err_recover (channel %d): "
33936f45ec7bSml29623 	    "failed to recover this txdma channel", channel));
33946f45ec7bSml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed"));
33956f45ec7bSml29623 
33966f45ec7bSml29623 	return (status);
33976f45ec7bSml29623 }
33986f45ec7bSml29623 
3399678453a8Sspeer /*
3400678453a8Sspeer  * nxge_tx_port_fatal_err_recover
3401678453a8Sspeer  *
3402678453a8Sspeer  *	Attempt to recover from a fatal port error.
3403678453a8Sspeer  *
3404678453a8Sspeer  * Arguments:
3405678453a8Sspeer  * 	nxgep
3406678453a8Sspeer  *
3407678453a8Sspeer  * Notes:
3408678453a8Sspeer  *	How would a guest do this?
3409678453a8Sspeer  *
3410678453a8Sspeer  * NPI/NXGE function calls:
3411678453a8Sspeer  *
3412678453a8Sspeer  * Registers accessed:
3413678453a8Sspeer  *
3414678453a8Sspeer  * Context:
3415678453a8Sspeer  *	Service domain
3416678453a8Sspeer  */
34176f45ec7bSml29623 nxge_status_t
nxge_tx_port_fatal_err_recover(p_nxge_t nxgep)34186f45ec7bSml29623 nxge_tx_port_fatal_err_recover(p_nxge_t nxgep)
34196f45ec7bSml29623 {
3420678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
3421678453a8Sspeer 	nxge_channel_t tdc;
3422678453a8Sspeer 
3423678453a8Sspeer 	tx_ring_t	*ring;
3424678453a8Sspeer 	tx_mbox_t	*mailbox;
3425678453a8Sspeer 
34266f45ec7bSml29623 	npi_handle_t	handle;
3427678453a8Sspeer 	nxge_status_t	status;
3428678453a8Sspeer 	npi_status_t	rs;
34296f45ec7bSml29623 
34306f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_tx_port_fatal_err_recover"));
34316f45ec7bSml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
34326f45ec7bSml29623 	    "Recovering from TxPort error..."));
34336f45ec7bSml29623 
3434678453a8Sspeer 	if (isLDOMguest(nxgep)) {
3435678453a8Sspeer 		return (NXGE_OK);
3436678453a8Sspeer 	}
3437678453a8Sspeer 
3438678453a8Sspeer 	if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) {
3439678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3440678453a8Sspeer 		    "<== nxge_tx_port_fatal_err_recover: not initialized"));
3441678453a8Sspeer 		return (NXGE_ERROR);
3442678453a8Sspeer 	}
3443678453a8Sspeer 
3444678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
3445678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3446678453a8Sspeer 		    "<== nxge_tx_port_fatal_err_recover: "
3447678453a8Sspeer 		    "NULL ring pointer(s)"));
3448678453a8Sspeer 		return (NXGE_ERROR);
3449678453a8Sspeer 	}
3450678453a8Sspeer 
3451678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3452678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3453678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3454678453a8Sspeer 			if (ring)
3455678453a8Sspeer 				MUTEX_ENTER(&ring->lock);
3456678453a8Sspeer 		}
3457678453a8Sspeer 	}
34586f45ec7bSml29623 
34596f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
34606f45ec7bSml29623 
3461678453a8Sspeer 	/*
3462678453a8Sspeer 	 * Stop all the TDCs owned by us.
3463678453a8Sspeer 	 * (The shared TDCs will have been stopped by their owners.)
3464678453a8Sspeer 	 */
3465678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3466678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3467678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3468678453a8Sspeer 			if (ring) {
3469678453a8Sspeer 				rs = npi_txdma_channel_control
3470678453a8Sspeer 				    (handle, TXDMA_STOP, tdc);
34716f45ec7bSml29623 				if (rs != NPI_SUCCESS) {
34726f45ec7bSml29623 					NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3473678453a8Sspeer 					    "nxge_tx_port_fatal_err_recover "
3474678453a8Sspeer 					    "(channel %d): stop failed ", tdc));
34756f45ec7bSml29623 					goto fail;
34766f45ec7bSml29623 				}
34776f45ec7bSml29623 			}
34786f45ec7bSml29623 		}
3479678453a8Sspeer 	}
3480678453a8Sspeer 
3481678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Reclaiming all TDCs..."));
3482678453a8Sspeer 
3483678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3484678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3485678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
34862d99c5d4SMichael Speer 			if (ring) {
3487678453a8Sspeer 				(void) nxge_txdma_reclaim(nxgep, ring, 0);
34882d99c5d4SMichael Speer 			}
3489678453a8Sspeer 		}
34906f45ec7bSml29623 	}
34916f45ec7bSml29623 
34926f45ec7bSml29623 	/*
3493678453a8Sspeer 	 * Reset all the TDCs.
34946f45ec7bSml29623 	 */
3495678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Resetting all TDCs..."));
34966f45ec7bSml29623 
3497678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3498678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3499678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3500678453a8Sspeer 			if (ring) {
3501678453a8Sspeer 				if ((rs = npi_txdma_channel_control
3502678453a8Sspeer 				    (handle, TXDMA_RESET, tdc))
3503678453a8Sspeer 				    != NPI_SUCCESS) {
35046f45ec7bSml29623 					NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3505678453a8Sspeer 					    "nxge_tx_port_fatal_err_recover "
3506678453a8Sspeer 					    "(channel %d) reset channel "
3507678453a8Sspeer 					    "failed 0x%x", tdc, rs));
35086f45ec7bSml29623 					goto fail;
35096f45ec7bSml29623 				}
3510678453a8Sspeer 			}
35116f45ec7bSml29623 			/*
35126f45ec7bSml29623 			 * Reset the tail (kick) register to 0.
35136f45ec7bSml29623 			 * (Hardware will not reset it. Tx overflow fatal
35146f45ec7bSml29623 			 * error if tail is not set to 0 after reset!
35156f45ec7bSml29623 			 */
3516678453a8Sspeer 			TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, tdc, 0);
3517678453a8Sspeer 		}
35186f45ec7bSml29623 	}
35196f45ec7bSml29623 
3520678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Restarting all TDCs..."));
35216f45ec7bSml29623 
3522678453a8Sspeer 	/* Restart all the TDCs */
3523678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3524678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3525678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3526678453a8Sspeer 			if (ring) {
3527678453a8Sspeer 				mailbox = nxge_txdma_get_mbox(nxgep, tdc);
3528678453a8Sspeer 				status = nxge_init_fzc_txdma_channel(nxgep, tdc,
3529678453a8Sspeer 				    ring, mailbox);
3530678453a8Sspeer 				ring->tx_evmask.value = 0;
35316f45ec7bSml29623 				/*
35326f45ec7bSml29623 				 * Initialize the event masks.
35336f45ec7bSml29623 				 */
3534678453a8Sspeer 				status = nxge_init_txdma_channel_event_mask
3535678453a8Sspeer 				    (nxgep, tdc, &ring->tx_evmask);
35366f45ec7bSml29623 
3537678453a8Sspeer 				ring->wr_index_wrap = B_FALSE;
3538678453a8Sspeer 				ring->wr_index = 0;
3539678453a8Sspeer 				ring->rd_index = 0;
35406f45ec7bSml29623 
35416f45ec7bSml29623 				if (status != NXGE_OK)
35426f45ec7bSml29623 					goto fail;
35436f45ec7bSml29623 				if (status != NXGE_OK)
35446f45ec7bSml29623 					goto fail;
35456f45ec7bSml29623 			}
3546678453a8Sspeer 		}
3547678453a8Sspeer 	}
3548678453a8Sspeer 
3549678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Re-enabling all TDCs..."));
3550678453a8Sspeer 
3551678453a8Sspeer 	/* Re-enable all the TDCs */
3552678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3553678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3554678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3555678453a8Sspeer 			if (ring) {
3556678453a8Sspeer 				mailbox = nxge_txdma_get_mbox(nxgep, tdc);
3557678453a8Sspeer 				status = nxge_enable_txdma_channel(nxgep, tdc,
3558678453a8Sspeer 				    ring, mailbox);
3559678453a8Sspeer 				if (status != NXGE_OK)
3560678453a8Sspeer 					goto fail;
3561678453a8Sspeer 			}
3562678453a8Sspeer 		}
3563678453a8Sspeer 	}
35646f45ec7bSml29623 
35656f45ec7bSml29623 	/*
3566678453a8Sspeer 	 * Unlock all the TDCs.
35676f45ec7bSml29623 	 */
3568678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3569678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3570678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3571678453a8Sspeer 			if (ring)
3572678453a8Sspeer 				MUTEX_EXIT(&ring->lock);
35736f45ec7bSml29623 		}
35746f45ec7bSml29623 	}
35756f45ec7bSml29623 
3576678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery succeeded"));
35776f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover"));
35786f45ec7bSml29623 
35796f45ec7bSml29623 	return (NXGE_OK);
35806f45ec7bSml29623 
35816f45ec7bSml29623 fail:
3582678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3583678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3584678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3585678453a8Sspeer 			if (ring)
3586678453a8Sspeer 				MUTEX_EXIT(&ring->lock);
35876f45ec7bSml29623 		}
35886f45ec7bSml29623 	}
35896f45ec7bSml29623 
3590678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery failed"));
3591678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover"));
35926f45ec7bSml29623 
35936f45ec7bSml29623 	return (status);
35946f45ec7bSml29623 }
35956f45ec7bSml29623 
3596678453a8Sspeer /*
3597678453a8Sspeer  * nxge_txdma_inject_err
3598678453a8Sspeer  *
3599678453a8Sspeer  *	Inject an error into a TDC.
3600678453a8Sspeer  *
3601678453a8Sspeer  * Arguments:
3602678453a8Sspeer  * 	nxgep
3603678453a8Sspeer  * 	err_id	The error to inject.
3604678453a8Sspeer  * 	chan	The channel to inject into.
3605678453a8Sspeer  *
3606678453a8Sspeer  * Notes:
3607678453a8Sspeer  *	This is called from nxge_main.c:nxge_err_inject()
3608678453a8Sspeer  *	Has this ioctl ever been used?
3609678453a8Sspeer  *
3610678453a8Sspeer  * NPI/NXGE function calls:
3611678453a8Sspeer  *	npi_txdma_inj_par_error_get()
3612678453a8Sspeer  *	npi_txdma_inj_par_error_set()
3613678453a8Sspeer  *
3614678453a8Sspeer  * Registers accessed:
3615678453a8Sspeer  *	TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error
3616678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
3617678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
3618678453a8Sspeer  *
3619678453a8Sspeer  * Context:
3620678453a8Sspeer  *	Service domain
3621678453a8Sspeer  */
36226f45ec7bSml29623 void
nxge_txdma_inject_err(p_nxge_t nxgep,uint32_t err_id,uint8_t chan)36236f45ec7bSml29623 nxge_txdma_inject_err(p_nxge_t nxgep, uint32_t err_id, uint8_t chan)
36246f45ec7bSml29623 {
36256f45ec7bSml29623 	tdmc_intr_dbg_t		tdi;
36266f45ec7bSml29623 	tdmc_inj_par_err_t	par_err;
36276f45ec7bSml29623 	uint32_t		value;
36286f45ec7bSml29623 	npi_handle_t		handle;
36296f45ec7bSml29623 
36306f45ec7bSml29623 	switch (err_id) {
36316f45ec7bSml29623 
36326f45ec7bSml29623 	case NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR:
36336f45ec7bSml29623 		handle = NXGE_DEV_NPI_HANDLE(nxgep);
36346f45ec7bSml29623 		/* Clear error injection source for parity error */
36356f45ec7bSml29623 		(void) npi_txdma_inj_par_error_get(handle, &value);
36366f45ec7bSml29623 		par_err.value = value;
36376f45ec7bSml29623 		par_err.bits.ldw.inject_parity_error &= ~(1 << chan);
36386f45ec7bSml29623 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
36396f45ec7bSml29623 
36406f45ec7bSml29623 		par_err.bits.ldw.inject_parity_error = (1 << chan);
36416f45ec7bSml29623 		(void) npi_txdma_inj_par_error_get(handle, &value);
36426f45ec7bSml29623 		par_err.value = value;
36436f45ec7bSml29623 		par_err.bits.ldw.inject_parity_error |= (1 << chan);
36446f45ec7bSml29623 		cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INJ_PAR_ERR_REG\n",
36456f45ec7bSml29623 		    (unsigned long long)par_err.value);
36466f45ec7bSml29623 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
36476f45ec7bSml29623 		break;
36486f45ec7bSml29623 
36496f45ec7bSml29623 	case NXGE_FM_EREPORT_TDMC_MBOX_ERR:
36506f45ec7bSml29623 	case NXGE_FM_EREPORT_TDMC_NACK_PREF:
36516f45ec7bSml29623 	case NXGE_FM_EREPORT_TDMC_NACK_PKT_RD:
36526f45ec7bSml29623 	case NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR:
36536f45ec7bSml29623 	case NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW:
36546f45ec7bSml29623 	case NXGE_FM_EREPORT_TDMC_CONF_PART_ERR:
36556f45ec7bSml29623 	case NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR:
36566f45ec7bSml29623 		TXDMA_REG_READ64(nxgep->npi_handle, TDMC_INTR_DBG_REG,
36576f45ec7bSml29623 		    chan, &tdi.value);
36586f45ec7bSml29623 		if (err_id == NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR)
36596f45ec7bSml29623 			tdi.bits.ldw.pref_buf_par_err = 1;
36606f45ec7bSml29623 		else if (err_id == NXGE_FM_EREPORT_TDMC_MBOX_ERR)
36616f45ec7bSml29623 			tdi.bits.ldw.mbox_err = 1;
36626f45ec7bSml29623 		else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PREF)
36636f45ec7bSml29623 			tdi.bits.ldw.nack_pref = 1;
36646f45ec7bSml29623 		else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PKT_RD)
36656f45ec7bSml29623 			tdi.bits.ldw.nack_pkt_rd = 1;
36666f45ec7bSml29623 		else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR)
36676f45ec7bSml29623 			tdi.bits.ldw.pkt_size_err = 1;
36686f45ec7bSml29623 		else if (err_id == NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW)
36696f45ec7bSml29623 			tdi.bits.ldw.tx_ring_oflow = 1;
36706f45ec7bSml29623 		else if (err_id == NXGE_FM_EREPORT_TDMC_CONF_PART_ERR)
36716f45ec7bSml29623 			tdi.bits.ldw.conf_part_err = 1;
36726f45ec7bSml29623 		else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR)
36736f45ec7bSml29623 			tdi.bits.ldw.pkt_part_err = 1;
3674adfcba55Sjoycey #if defined(__i386)
3675adfcba55Sjoycey 		cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INTR_DBG_REG\n",
3676adfcba55Sjoycey 		    tdi.value);
3677adfcba55Sjoycey #else
36786f45ec7bSml29623 		cmn_err(CE_NOTE, "!Write 0x%lx to TDMC_INTR_DBG_REG\n",
36796f45ec7bSml29623 		    tdi.value);
3680adfcba55Sjoycey #endif
36816f45ec7bSml29623 		TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG,
36826f45ec7bSml29623 		    chan, tdi.value);
36836f45ec7bSml29623 
36846f45ec7bSml29623 		break;
36856f45ec7bSml29623 	}
36866f45ec7bSml29623 }
3687