144961713Sgirish /*
244961713Sgirish  * CDDL HEADER START
344961713Sgirish  *
444961713Sgirish  * The contents of this file are subject to the terms of the
544961713Sgirish  * Common Development and Distribution License (the "License").
644961713Sgirish  * You may not use this file except in compliance with the License.
744961713Sgirish  *
844961713Sgirish  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
944961713Sgirish  * or http://www.opensolaris.org/os/licensing.
1044961713Sgirish  * See the License for the specific language governing permissions
1144961713Sgirish  * and limitations under the License.
1244961713Sgirish  *
1344961713Sgirish  * When distributing Covered Code, include this CDDL HEADER in each
1444961713Sgirish  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1544961713Sgirish  * If applicable, add the following below this CDDL HEADER, with the
1644961713Sgirish  * fields enclosed by brackets "[]" replaced with your own identifying
1744961713Sgirish  * information: Portions Copyright [yyyy] [name of copyright owner]
1844961713Sgirish  *
1944961713Sgirish  * CDDL HEADER END
2044961713Sgirish  */
21952a2464SMichael Speer 
2244961713Sgirish /*
23257bdc55SMichael Speer  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2444961713Sgirish  * Use is subject to license terms.
2544961713Sgirish  */
2644961713Sgirish 
2744961713Sgirish #include <sys/nxge/nxge_impl.h>
2844961713Sgirish #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>
3244961713Sgirish #include <sys/llc1.h>
3344961713Sgirish 
3444961713Sgirish uint32_t 	nxge_reclaim_pending = TXDMA_RECLAIM_PENDING_DEFAULT;
35da14cebeSEric Cheng uint32_t	nxge_tx_minfree = 64;
3644961713Sgirish uint32_t	nxge_tx_intr_thres = 0;
3744961713Sgirish uint32_t	nxge_tx_max_gathers = TX_MAX_GATHER_POINTERS;
3844961713Sgirish uint32_t	nxge_tx_tiny_pack = 1;
3944961713Sgirish uint32_t	nxge_tx_use_bcopy = 1;
4044961713Sgirish 
4144961713Sgirish extern uint32_t 	nxge_tx_ring_size;
4244961713Sgirish extern uint32_t 	nxge_bcopy_thresh;
4344961713Sgirish extern uint32_t 	nxge_dvma_thresh;
4444961713Sgirish extern uint32_t 	nxge_dma_stream_thresh;
4544961713Sgirish extern dma_method_t 	nxge_force_dma;
46b4d05839Sml extern uint32_t		nxge_cksum_offload;
4744961713Sgirish 
4844961713Sgirish /* Device register access attributes for PIO.  */
4944961713Sgirish extern ddi_device_acc_attr_t nxge_dev_reg_acc_attr;
5044961713Sgirish /* Device descriptor access attributes for DMA.  */
5144961713Sgirish extern ddi_device_acc_attr_t nxge_dev_desc_dma_acc_attr;
5244961713Sgirish /* Device buffer access attributes for DMA.  */
5344961713Sgirish extern ddi_device_acc_attr_t nxge_dev_buf_dma_acc_attr;
5444961713Sgirish extern ddi_dma_attr_t nxge_desc_dma_attr;
5544961713Sgirish extern ddi_dma_attr_t nxge_tx_dma_attr;
5644961713Sgirish 
57da14cebeSEric Cheng extern void nxge_tx_ring_task(void *arg);
582d99c5d4SMichael Speer 
59678453a8Sspeer static nxge_status_t nxge_map_txdma(p_nxge_t, int);
6044961713Sgirish 
61678453a8Sspeer static nxge_status_t nxge_txdma_hw_start(p_nxge_t, int);
6244961713Sgirish 
6344961713Sgirish static nxge_status_t nxge_map_txdma_channel(p_nxge_t, uint16_t,
6444961713Sgirish 	p_nxge_dma_common_t *, p_tx_ring_t *,
6544961713Sgirish 	uint32_t, p_nxge_dma_common_t *,
6644961713Sgirish 	p_tx_mbox_t *);
67678453a8Sspeer static void nxge_unmap_txdma_channel(p_nxge_t, uint16_t);
6844961713Sgirish 
6944961713Sgirish static nxge_status_t nxge_map_txdma_channel_buf_ring(p_nxge_t, uint16_t,
7044961713Sgirish 	p_nxge_dma_common_t *, p_tx_ring_t *, uint32_t);
7144961713Sgirish static void nxge_unmap_txdma_channel_buf_ring(p_nxge_t, p_tx_ring_t);
7244961713Sgirish 
7344961713Sgirish static void nxge_map_txdma_channel_cfg_ring(p_nxge_t, uint16_t,
7444961713Sgirish 	p_nxge_dma_common_t *, p_tx_ring_t,
7544961713Sgirish 	p_tx_mbox_t *);
7644961713Sgirish static void nxge_unmap_txdma_channel_cfg_ring(p_nxge_t,
7744961713Sgirish 	p_tx_ring_t, p_tx_mbox_t);
7844961713Sgirish 
7944961713Sgirish static nxge_status_t nxge_txdma_start_channel(p_nxge_t, uint16_t,
8044961713Sgirish     p_tx_ring_t, p_tx_mbox_t);
81678453a8Sspeer static nxge_status_t nxge_txdma_stop_channel(p_nxge_t, uint16_t);
8244961713Sgirish 
8344961713Sgirish static p_tx_ring_t nxge_txdma_get_ring(p_nxge_t, uint16_t);
8444961713Sgirish static nxge_status_t nxge_tx_err_evnts(p_nxge_t, uint_t,
8544961713Sgirish 	p_nxge_ldv_t, tx_cs_t);
8644961713Sgirish static p_tx_mbox_t nxge_txdma_get_mbox(p_nxge_t, uint16_t);
8744961713Sgirish static nxge_status_t nxge_txdma_fatal_err_recover(p_nxge_t,
8844961713Sgirish 	uint16_t, p_tx_ring_t);
8944961713Sgirish 
90678453a8Sspeer static void nxge_txdma_fixup_hung_channel(p_nxge_t nxgep,
91678453a8Sspeer     p_tx_ring_t ring_p, uint16_t channel);
92678453a8Sspeer 
9344961713Sgirish nxge_status_t
9444961713Sgirish nxge_init_txdma_channels(p_nxge_t nxgep)
9544961713Sgirish {
96e11f0814SMichael Speer 	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;
101678453a8Sspeer 
102678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "==> nxge_init_txdma_channels"));
103678453a8Sspeer 
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;
120678453a8Sspeer 	}
121678453a8Sspeer 
122678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_init_txdma_channels"));
123678453a8Sspeer 	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 
145678453a8Sspeer }
146678453a8Sspeer 
147678453a8Sspeer nxge_status_t
148678453a8Sspeer nxge_init_txdma_channel(
149678453a8Sspeer 	p_nxge_t nxge,
150678453a8Sspeer 	int channel)
151678453a8Sspeer {
152678453a8Sspeer 	nxge_status_t status;
15344961713Sgirish 
154678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, MEM2_CTL, "==> nxge_init_txdma_channel"));
15544961713Sgirish 
156678453a8Sspeer 	status = nxge_map_txdma(nxge, channel);
15744961713Sgirish 	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);
16144961713Sgirish 		return (status);
16244961713Sgirish 	}
16344961713Sgirish 
164678453a8Sspeer 	status = nxge_txdma_hw_start(nxge, channel);
16544961713Sgirish 	if (status != NXGE_OK) {
166678453a8Sspeer 		(void) nxge_unmap_txdma_channel(nxge, channel);
167678453a8Sspeer 		(void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel);
16844961713Sgirish 		return (status);
16944961713Sgirish 	}
17044961713Sgirish 
171678453a8Sspeer 	if (!nxge->statsp->tdc_ksp[channel])
172678453a8Sspeer 		nxge_setup_tdc_kstats(nxge, channel);
17344961713Sgirish 
174678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, MEM2_CTL, "<== nxge_init_txdma_channel"));
175678453a8Sspeer 
176678453a8Sspeer 	return (status);
17744961713Sgirish }
17844961713Sgirish 
17944961713Sgirish void
18044961713Sgirish nxge_uninit_txdma_channels(p_nxge_t nxgep)
18144961713Sgirish {
182678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
183678453a8Sspeer 	int tdc;
184678453a8Sspeer 
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
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 	}
21144961713Sgirish 
212678453a8Sspeer 	(void) nxge_txdma_stop_channel(nxgep, channel);
213678453a8Sspeer 	nxge_unmap_txdma_channel(nxgep, channel);
21444961713Sgirish 
21544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
21652ccf843Smisaki 	    "<== nxge_uninit_txdma_channel"));
21744961713Sgirish }
21844961713Sgirish 
21944961713Sgirish void
22044961713Sgirish nxge_setup_dma_common(p_nxge_dma_common_t dest_p, p_nxge_dma_common_t src_p,
22144961713Sgirish 	uint32_t entries, uint32_t size)
22244961713Sgirish {
22344961713Sgirish 	size_t		tsize;
22444961713Sgirish 	*dest_p = *src_p;
22544961713Sgirish 	tsize = size * entries;
22644961713Sgirish 	dest_p->alength = tsize;
22744961713Sgirish 	dest_p->nblocks = entries;
22844961713Sgirish 	dest_p->block_size = size;
22944961713Sgirish 	dest_p->offset += tsize;
23044961713Sgirish 
23144961713Sgirish 	src_p->kaddrp = (caddr_t)dest_p->kaddrp + tsize;
23244961713Sgirish 	src_p->alength -= tsize;
23344961713Sgirish 	src_p->dma_cookie.dmac_laddress += tsize;
23444961713Sgirish 	src_p->dma_cookie.dmac_size -= tsize;
23544961713Sgirish }
23644961713Sgirish 
237678453a8Sspeer /*
238678453a8Sspeer  * nxge_reset_txdma_channel
239678453a8Sspeer  *
240678453a8Sspeer  *	Reset a TDC.
241678453a8Sspeer  *
242678453a8Sspeer  * Arguments:
243678453a8Sspeer  * 	nxgep
244678453a8Sspeer  * 	channel		The channel to reset.
245678453a8Sspeer  * 	reg_data	The current TX_CS.
246678453a8Sspeer  *
247678453a8Sspeer  * Notes:
248678453a8Sspeer  *
249678453a8Sspeer  * NPI/NXGE function calls:
250678453a8Sspeer  *	npi_txdma_channel_reset()
251678453a8Sspeer  *	npi_txdma_channel_control()
252678453a8Sspeer  *
253678453a8Sspeer  * Registers accessed:
254678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
255678453a8Sspeer  *	TX_RING_KICK	DMC+0x40018 Transmit Ring Kick
256678453a8Sspeer  *
257678453a8Sspeer  * Context:
258678453a8Sspeer  *	Any domain
259678453a8Sspeer  */
26044961713Sgirish nxge_status_t
26144961713Sgirish nxge_reset_txdma_channel(p_nxge_t nxgep, uint16_t channel, uint64_t reg_data)
26244961713Sgirish {
26344961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
26444961713Sgirish 	nxge_status_t		status = NXGE_OK;
26544961713Sgirish 	npi_handle_t		handle;
26644961713Sgirish 
26744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, " ==> nxge_reset_txdma_channel"));
26844961713Sgirish 
26944961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
27044961713Sgirish 	if ((reg_data & TX_CS_RST_MASK) == TX_CS_RST_MASK) {
27144961713Sgirish 		rs = npi_txdma_channel_reset(handle, channel);
27244961713Sgirish 	} else {
27344961713Sgirish 		rs = npi_txdma_channel_control(handle, TXDMA_RESET,
27452ccf843Smisaki 		    channel);
27544961713Sgirish 	}
27644961713Sgirish 
27744961713Sgirish 	if (rs != NPI_SUCCESS) {
27844961713Sgirish 		status = NXGE_ERROR | rs;
27944961713Sgirish 	}
28044961713Sgirish 
28144961713Sgirish 	/*
28244961713Sgirish 	 * Reset the tail (kick) register to 0.
28344961713Sgirish 	 * (Hardware will not reset it. Tx overflow fatal
28444961713Sgirish 	 * error if tail is not set to 0 after reset!
28544961713Sgirish 	 */
28644961713Sgirish 	TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0);
28744961713Sgirish 
28844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, " <== nxge_reset_txdma_channel"));
28944961713Sgirish 	return (status);
29044961713Sgirish }
29144961713Sgirish 
292678453a8Sspeer /*
293678453a8Sspeer  * nxge_init_txdma_channel_event_mask
294678453a8Sspeer  *
295678453a8Sspeer  *	Enable interrupts for a set of events.
296678453a8Sspeer  *
297678453a8Sspeer  * Arguments:
298678453a8Sspeer  * 	nxgep
299678453a8Sspeer  * 	channel	The channel to map.
300678453a8Sspeer  * 	mask_p	The events to enable.
301678453a8Sspeer  *
302678453a8Sspeer  * Notes:
303678453a8Sspeer  *
304678453a8Sspeer  * NPI/NXGE function calls:
305678453a8Sspeer  *	npi_txdma_event_mask()
306678453a8Sspeer  *
307678453a8Sspeer  * Registers accessed:
308678453a8Sspeer  *	TX_ENT_MSK	DMC+0x40020 Transmit Event Mask
309678453a8Sspeer  *
310678453a8Sspeer  * Context:
311678453a8Sspeer  *	Any domain
312678453a8Sspeer  */
31344961713Sgirish nxge_status_t
31444961713Sgirish nxge_init_txdma_channel_event_mask(p_nxge_t nxgep, uint16_t channel,
31544961713Sgirish 		p_tx_dma_ent_msk_t mask_p)
31644961713Sgirish {
31744961713Sgirish 	npi_handle_t		handle;
31844961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
31944961713Sgirish 	nxge_status_t		status = NXGE_OK;
32044961713Sgirish 
32144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
32252ccf843Smisaki 	    "<== nxge_init_txdma_channel_event_mask"));
32344961713Sgirish 
32444961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
32544961713Sgirish 	rs = npi_txdma_event_mask(handle, OP_SET, channel, mask_p);
32644961713Sgirish 	if (rs != NPI_SUCCESS) {
32744961713Sgirish 		status = NXGE_ERROR | rs;
32844961713Sgirish 	}
32944961713Sgirish 
33044961713Sgirish 	return (status);
33144961713Sgirish }
33244961713Sgirish 
333678453a8Sspeer /*
334678453a8Sspeer  * nxge_init_txdma_channel_cntl_stat
335678453a8Sspeer  *
336678453a8Sspeer  *	Stop a TDC.  If at first we don't succeed, inject an error.
337678453a8Sspeer  *
338678453a8Sspeer  * Arguments:
339678453a8Sspeer  * 	nxgep
340678453a8Sspeer  * 	channel		The channel to stop.
341678453a8Sspeer  *
342678453a8Sspeer  * Notes:
343678453a8Sspeer  *
344678453a8Sspeer  * NPI/NXGE function calls:
345678453a8Sspeer  *	npi_txdma_control_status()
346678453a8Sspeer  *
347678453a8Sspeer  * Registers accessed:
348678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
349678453a8Sspeer  *
350678453a8Sspeer  * Context:
351678453a8Sspeer  *	Any domain
352678453a8Sspeer  */
35344961713Sgirish nxge_status_t
35444961713Sgirish nxge_init_txdma_channel_cntl_stat(p_nxge_t nxgep, uint16_t channel,
35544961713Sgirish 	uint64_t reg_data)
35644961713Sgirish {
35744961713Sgirish 	npi_handle_t		handle;
35844961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
35944961713Sgirish 	nxge_status_t		status = NXGE_OK;
36044961713Sgirish 
36144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
36252ccf843Smisaki 	    "<== nxge_init_txdma_channel_cntl_stat"));
36344961713Sgirish 
36444961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
36544961713Sgirish 	rs = npi_txdma_control_status(handle, OP_SET, channel,
36652ccf843Smisaki 	    (p_tx_cs_t)&reg_data);
36744961713Sgirish 
36844961713Sgirish 	if (rs != NPI_SUCCESS) {
36944961713Sgirish 		status = NXGE_ERROR | rs;
37044961713Sgirish 	}
37144961713Sgirish 
37244961713Sgirish 	return (status);
37344961713Sgirish }
37444961713Sgirish 
375678453a8Sspeer /*
376678453a8Sspeer  * nxge_enable_txdma_channel
377678453a8Sspeer  *
378678453a8Sspeer  *	Enable a TDC.
379678453a8Sspeer  *
380678453a8Sspeer  * Arguments:
381678453a8Sspeer  * 	nxgep
382678453a8Sspeer  * 	channel		The channel to enable.
383678453a8Sspeer  * 	tx_desc_p	channel's transmit descriptor ring.
384678453a8Sspeer  * 	mbox_p		channel's mailbox,
385678453a8Sspeer  *
386678453a8Sspeer  * Notes:
387678453a8Sspeer  *
388678453a8Sspeer  * NPI/NXGE function calls:
389678453a8Sspeer  *	npi_txdma_ring_config()
390678453a8Sspeer  *	npi_txdma_mbox_config()
391678453a8Sspeer  *	npi_txdma_channel_init_enable()
392678453a8Sspeer  *
393678453a8Sspeer  * Registers accessed:
394678453a8Sspeer  *	TX_RNG_CFIG	DMC+0x40000 Transmit Ring Configuration
395678453a8Sspeer  *	TXDMA_MBH	DMC+0x40030 TXDMA Mailbox High
396678453a8Sspeer  *	TXDMA_MBL	DMC+0x40038 TXDMA Mailbox Low
397678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
398678453a8Sspeer  *
399678453a8Sspeer  * Context:
400678453a8Sspeer  *	Any domain
401678453a8Sspeer  */
40244961713Sgirish nxge_status_t
40344961713Sgirish nxge_enable_txdma_channel(p_nxge_t nxgep,
40444961713Sgirish 	uint16_t channel, p_tx_ring_t tx_desc_p, p_tx_mbox_t mbox_p)
40544961713Sgirish {
40644961713Sgirish 	npi_handle_t		handle;
40744961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
40844961713Sgirish 	nxge_status_t		status = NXGE_OK;
40944961713Sgirish 
41044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_enable_txdma_channel"));
41144961713Sgirish 
41244961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
41344961713Sgirish 	/*
41444961713Sgirish 	 * Use configuration data composed at init time.
41544961713Sgirish 	 * Write to hardware the transmit ring configurations.
41644961713Sgirish 	 */
41744961713Sgirish 	rs = npi_txdma_ring_config(handle, OP_SET, channel,
418678453a8Sspeer 	    (uint64_t *)&(tx_desc_p->tx_ring_cfig.value));
41944961713Sgirish 
42044961713Sgirish 	if (rs != NPI_SUCCESS) {
42144961713Sgirish 		return (NXGE_ERROR | rs);
42244961713Sgirish 	}
42344961713Sgirish 
424678453a8Sspeer 	if (isLDOMguest(nxgep)) {
425678453a8Sspeer 		/* Add interrupt handler for this channel. */
426678453a8Sspeer 		if (nxge_hio_intr_add(nxgep, VP_BOUND_TX, channel) != NXGE_OK)
427678453a8Sspeer 			return (NXGE_ERROR);
428678453a8Sspeer 	}
429678453a8Sspeer 
43044961713Sgirish 	/* Write to hardware the mailbox */
43144961713Sgirish 	rs = npi_txdma_mbox_config(handle, OP_SET, channel,
43252ccf843Smisaki 	    (uint64_t *)&mbox_p->tx_mbox.dma_cookie.dmac_laddress);
43344961713Sgirish 
43444961713Sgirish 	if (rs != NPI_SUCCESS) {
43544961713Sgirish 		return (NXGE_ERROR | rs);
43644961713Sgirish 	}
43744961713Sgirish 
43844961713Sgirish 	/* Start the DMA engine. */
43944961713Sgirish 	rs = npi_txdma_channel_init_enable(handle, channel);
44044961713Sgirish 
44144961713Sgirish 	if (rs != NPI_SUCCESS) {
44244961713Sgirish 		return (NXGE_ERROR | rs);
44344961713Sgirish 	}
44444961713Sgirish 
44544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_enable_txdma_channel"));
44644961713Sgirish 
44744961713Sgirish 	return (status);
44844961713Sgirish }
44944961713Sgirish 
45044961713Sgirish void
45144961713Sgirish nxge_fill_tx_hdr(p_mblk_t mp, boolean_t fill_len,
45244961713Sgirish 		boolean_t l4_cksum, int pkt_len, uint8_t npads,
453b4d05839Sml 		p_tx_pkt_hdr_all_t pkthdrp,
454b4d05839Sml 		t_uscalar_t start_offset,
455b4d05839Sml 		t_uscalar_t stuff_offset)
45644961713Sgirish {
45744961713Sgirish 	p_tx_pkt_header_t	hdrp;
45844961713Sgirish 	p_mblk_t 		nmp;
45944961713Sgirish 	uint64_t		tmp;
46044961713Sgirish 	size_t 			mblk_len;
46144961713Sgirish 	size_t 			iph_len;
46244961713Sgirish 	size_t 			hdrs_size;
46344961713Sgirish 	uint8_t			hdrs_buf[sizeof (struct ether_header) +
46452ccf843Smisaki 	    64 + sizeof (uint32_t)];
465ae2d3f74Smisaki 	uint8_t			*cursor;
46644961713Sgirish 	uint8_t 		*ip_buf;
46744961713Sgirish 	uint16_t		eth_type;
46844961713Sgirish 	uint8_t			ipproto;
46944961713Sgirish 	boolean_t		is_vlan = B_FALSE;
47044961713Sgirish 	size_t			eth_hdr_size;
47144961713Sgirish 
47244961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: mp $%p", mp));
47344961713Sgirish 
47444961713Sgirish 	/*
47544961713Sgirish 	 * Caller should zero out the headers first.
47644961713Sgirish 	 */
47744961713Sgirish 	hdrp = (p_tx_pkt_header_t)&pkthdrp->pkthdr;
47844961713Sgirish 
47944961713Sgirish 	if (fill_len) {
48044961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
48152ccf843Smisaki 		    "==> nxge_fill_tx_hdr: pkt_len %d "
48252ccf843Smisaki 		    "npads %d", pkt_len, npads));
48344961713Sgirish 		tmp = (uint64_t)pkt_len;
48444961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_TOT_XFER_LEN_SHIFT);
48544961713Sgirish 		goto fill_tx_header_done;
48644961713Sgirish 	}
48744961713Sgirish 
488b4d05839Sml 	hdrp->value |= (((uint64_t)npads) << TX_PKT_HEADER_PAD_SHIFT);
48944961713Sgirish 
49044961713Sgirish 	/*
49144961713Sgirish 	 * mp is the original data packet (does not include the
49244961713Sgirish 	 * Neptune transmit header).
49344961713Sgirish 	 */
49444961713Sgirish 	nmp = mp;
49544961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: "
49652ccf843Smisaki 	    "mp $%p b_rptr $%p len %d",
49752ccf843Smisaki 	    mp, nmp->b_rptr, MBLKL(nmp)));
498ae2d3f74Smisaki 	/* copy ether_header from mblk to hdrs_buf */
499ae2d3f74Smisaki 	cursor = &hdrs_buf[0];
500ae2d3f74Smisaki 	tmp = sizeof (struct ether_vlan_header);
501ae2d3f74Smisaki 	while ((nmp != NULL) && (tmp > 0)) {
502ae2d3f74Smisaki 		size_t buflen;
503ae2d3f74Smisaki 		mblk_len = MBLKL(nmp);
5047c29db66Smisaki 		buflen = min((size_t)tmp, mblk_len);
505ae2d3f74Smisaki 		bcopy(nmp->b_rptr, cursor, buflen);
506ae2d3f74Smisaki 		cursor += buflen;
507ae2d3f74Smisaki 		tmp -= buflen;
508ae2d3f74Smisaki 		nmp = nmp->b_cont;
509ae2d3f74Smisaki 	}
510ae2d3f74Smisaki 
511ae2d3f74Smisaki 	nmp = mp;
512ae2d3f74Smisaki 	mblk_len = MBLKL(nmp);
51344961713Sgirish 	ip_buf = NULL;
51444961713Sgirish 	eth_type = ntohs(((p_ether_header_t)hdrs_buf)->ether_type);
51544961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> : nxge_fill_tx_hdr: (value 0x%llx) "
51652ccf843Smisaki 	    "ether type 0x%x", eth_type, hdrp->value));
51744961713Sgirish 
51844961713Sgirish 	if (eth_type < ETHERMTU) {
51944961713Sgirish 		tmp = 1ull;
52044961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_LLC_SHIFT);
52144961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: LLC "
52252ccf843Smisaki 		    "value 0x%llx", hdrp->value));
52344961713Sgirish 		if (*(hdrs_buf + sizeof (struct ether_header))
52452ccf843Smisaki 		    == LLC_SNAP_SAP) {
52544961713Sgirish 			eth_type = ntohs(*((uint16_t *)(hdrs_buf +
52652ccf843Smisaki 			    sizeof (struct ether_header) + 6)));
52744961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
52852ccf843Smisaki 			    "==> nxge_tx_pkt_hdr_init: LLC ether type 0x%x",
52952ccf843Smisaki 			    eth_type));
53044961713Sgirish 		} else {
53144961713Sgirish 			goto fill_tx_header_done;
53244961713Sgirish 		}
53344961713Sgirish 	} else if (eth_type == VLAN_ETHERTYPE) {
53444961713Sgirish 		tmp = 1ull;
53544961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_VLAN__SHIFT);
53644961713Sgirish 
53744961713Sgirish 		eth_type = ntohs(((struct ether_vlan_header *)
53852ccf843Smisaki 		    hdrs_buf)->ether_type);
53944961713Sgirish 		is_vlan = B_TRUE;
54044961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: VLAN "
54152ccf843Smisaki 		    "value 0x%llx", hdrp->value));
54244961713Sgirish 	}
54344961713Sgirish 
54444961713Sgirish 	if (!is_vlan) {
54544961713Sgirish 		eth_hdr_size = sizeof (struct ether_header);
54644961713Sgirish 	} else {
54744961713Sgirish 		eth_hdr_size = sizeof (struct ether_vlan_header);
54844961713Sgirish 	}
54944961713Sgirish 
55044961713Sgirish 	switch (eth_type) {
55144961713Sgirish 	case ETHERTYPE_IP:
55244961713Sgirish 		if (mblk_len > eth_hdr_size + sizeof (uint8_t)) {
55344961713Sgirish 			ip_buf = nmp->b_rptr + eth_hdr_size;
55444961713Sgirish 			mblk_len -= eth_hdr_size;
55544961713Sgirish 			iph_len = ((*ip_buf) & 0x0f);
55644961713Sgirish 			if (mblk_len > (iph_len + sizeof (uint32_t))) {
55744961713Sgirish 				ip_buf = nmp->b_rptr;
55844961713Sgirish 				ip_buf += eth_hdr_size;
55944961713Sgirish 			} else {
56044961713Sgirish 				ip_buf = NULL;
56144961713Sgirish 			}
56244961713Sgirish 
56344961713Sgirish 		}
56444961713Sgirish 		if (ip_buf == NULL) {
56544961713Sgirish 			hdrs_size = 0;
56644961713Sgirish 			((p_ether_header_t)hdrs_buf)->ether_type = 0;
56744961713Sgirish 			while ((nmp) && (hdrs_size <
56852ccf843Smisaki 			    sizeof (hdrs_buf))) {
56944961713Sgirish 				mblk_len = (size_t)nmp->b_wptr -
57052ccf843Smisaki 				    (size_t)nmp->b_rptr;
57144961713Sgirish 				if (mblk_len >=
57252ccf843Smisaki 				    (sizeof (hdrs_buf) - hdrs_size))
57344961713Sgirish 					mblk_len = sizeof (hdrs_buf) -
57452ccf843Smisaki 					    hdrs_size;
57544961713Sgirish 				bcopy(nmp->b_rptr,
57652ccf843Smisaki 				    &hdrs_buf[hdrs_size], mblk_len);
57744961713Sgirish 				hdrs_size += mblk_len;
57844961713Sgirish 				nmp = nmp->b_cont;
57944961713Sgirish 			}
58044961713Sgirish 			ip_buf = hdrs_buf;
58144961713Sgirish 			ip_buf += eth_hdr_size;
58244961713Sgirish 			iph_len = ((*ip_buf) & 0x0f);
58344961713Sgirish 		}
58444961713Sgirish 
58544961713Sgirish 		ipproto = ip_buf[9];
58644961713Sgirish 
58744961713Sgirish 		tmp = (uint64_t)iph_len;
58844961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_IHL_SHIFT);
58944961713Sgirish 		tmp = (uint64_t)(eth_hdr_size >> 1);
59044961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT);
59144961713Sgirish 
59244961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv4 "
59352ccf843Smisaki 		    " iph_len %d l3start %d eth_hdr_size %d proto 0x%x"
59452ccf843Smisaki 		    "tmp 0x%x",
59552ccf843Smisaki 		    iph_len, hdrp->bits.hdw.l3start, eth_hdr_size,
59652ccf843Smisaki 		    ipproto, tmp));
59744961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IP "
59852ccf843Smisaki 		    "value 0x%llx", hdrp->value));
59944961713Sgirish 
60044961713Sgirish 		break;
60144961713Sgirish 
60244961713Sgirish 	case ETHERTYPE_IPV6:
60344961713Sgirish 		hdrs_size = 0;
60444961713Sgirish 		((p_ether_header_t)hdrs_buf)->ether_type = 0;
60544961713Sgirish 		while ((nmp) && (hdrs_size <
60652ccf843Smisaki 		    sizeof (hdrs_buf))) {
60744961713Sgirish 			mblk_len = (size_t)nmp->b_wptr - (size_t)nmp->b_rptr;
60844961713Sgirish 			if (mblk_len >=
60952ccf843Smisaki 			    (sizeof (hdrs_buf) - hdrs_size))
61044961713Sgirish 				mblk_len = sizeof (hdrs_buf) -
61152ccf843Smisaki 				    hdrs_size;
61244961713Sgirish 			bcopy(nmp->b_rptr,
61352ccf843Smisaki 			    &hdrs_buf[hdrs_size], mblk_len);
61444961713Sgirish 			hdrs_size += mblk_len;
61544961713Sgirish 			nmp = nmp->b_cont;
61644961713Sgirish 		}
61744961713Sgirish 		ip_buf = hdrs_buf;
61844961713Sgirish 		ip_buf += eth_hdr_size;
61944961713Sgirish 
62044961713Sgirish 		tmp = 1ull;
62144961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_IP_VER_SHIFT);
62244961713Sgirish 
62344961713Sgirish 		tmp = (eth_hdr_size >> 1);
62444961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT);
62544961713Sgirish 
62644961713Sgirish 		/* byte 6 is the next header protocol */
62744961713Sgirish 		ipproto = ip_buf[6];
62844961713Sgirish 
62944961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv6 "
63052ccf843Smisaki 		    " iph_len %d l3start %d eth_hdr_size %d proto 0x%x",
63152ccf843Smisaki 		    iph_len, hdrp->bits.hdw.l3start, eth_hdr_size,
63252ccf843Smisaki 		    ipproto));
63344961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IPv6 "
63452ccf843Smisaki 		    "value 0x%llx", hdrp->value));
63544961713Sgirish 
63644961713Sgirish 		break;
63744961713Sgirish 
63844961713Sgirish 	default:
63944961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: non-IP"));
64044961713Sgirish 		goto fill_tx_header_done;
64144961713Sgirish 	}
64244961713Sgirish 
64344961713Sgirish 	switch (ipproto) {
64444961713Sgirish 	case IPPROTO_TCP:
64544961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
646b4d05839Sml 		    "==> nxge_fill_tx_hdr: TCP (cksum flag %d)", l4_cksum));
64744961713Sgirish 		if (l4_cksum) {
648b4d05839Sml 			hdrp->value |= TX_CKSUM_EN_PKT_TYPE_TCP;
649b4d05839Sml 			hdrp->value |=
650b4d05839Sml 			    (((uint64_t)(start_offset >> 1)) <<
651b4d05839Sml 			    TX_PKT_HEADER_L4START_SHIFT);
652b4d05839Sml 			hdrp->value |=
653b4d05839Sml 			    (((uint64_t)(stuff_offset >> 1)) <<
654b4d05839Sml 			    TX_PKT_HEADER_L4STUFF_SHIFT);
655b4d05839Sml 
65644961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
657b4d05839Sml 			    "==> nxge_tx_pkt_hdr_init: TCP CKSUM "
658b4d05839Sml 			    "value 0x%llx", hdrp->value));
65944961713Sgirish 		}
66044961713Sgirish 
66144961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: TCP "
662b4d05839Sml 		    "value 0x%llx", hdrp->value));
66344961713Sgirish 		break;
66444961713Sgirish 
66544961713Sgirish 	case IPPROTO_UDP:
66644961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: UDP"));
66744961713Sgirish 		if (l4_cksum) {
668b4d05839Sml 			if (!nxge_cksum_offload) {
669b4d05839Sml 				uint16_t	*up;
670b4d05839Sml 				uint16_t	cksum;
671b4d05839Sml 				t_uscalar_t	stuff_len;
672b4d05839Sml 
673b4d05839Sml 				/*
674b4d05839Sml 				 * The checksum field has the
675b4d05839Sml 				 * partial checksum.
676b4d05839Sml 				 * IP_CSUM() macro calls ip_cksum() which
677b4d05839Sml 				 * can add in the partial checksum.
678b4d05839Sml 				 */
679b4d05839Sml 				cksum = IP_CSUM(mp, start_offset, 0);
680b4d05839Sml 				stuff_len = stuff_offset;
681b4d05839Sml 				nmp = mp;
682b4d05839Sml 				mblk_len = MBLKL(nmp);
683b4d05839Sml 				while ((nmp != NULL) &&
684b4d05839Sml 				    (mblk_len < stuff_len)) {
685b4d05839Sml 					stuff_len -= mblk_len;
686b4d05839Sml 					nmp = nmp->b_cont;
687b4d05839Sml 				}
688b4d05839Sml 				ASSERT(nmp);
689b4d05839Sml 				up = (uint16_t *)(nmp->b_rptr + stuff_len);
690b4d05839Sml 
691b4d05839Sml 				*up = cksum;
692b4d05839Sml 				hdrp->value &= ~TX_CKSUM_EN_PKT_TYPE_UDP;
693b4d05839Sml 				NXGE_DEBUG_MSG((NULL, TX_CTL,
694b4d05839Sml 				    "==> nxge_tx_pkt_hdr_init: UDP offset %d "
695b4d05839Sml 				    "use sw cksum "
696b4d05839Sml 				    "write to $%p cksum 0x%x content up 0x%x",
697b4d05839Sml 				    stuff_len,
698b4d05839Sml 				    up,
699b4d05839Sml 				    cksum,
700b4d05839Sml 				    *up));
701b4d05839Sml 			} else {
702b4d05839Sml 				/* Hardware will compute the full checksum */
703b4d05839Sml 				hdrp->value |= TX_CKSUM_EN_PKT_TYPE_UDP;
704b4d05839Sml 				hdrp->value |=
705b4d05839Sml 				    (((uint64_t)(start_offset >> 1)) <<
706b4d05839Sml 				    TX_PKT_HEADER_L4START_SHIFT);
707b4d05839Sml 				hdrp->value |=
708b4d05839Sml 				    (((uint64_t)(stuff_offset >> 1)) <<
709b4d05839Sml 				    TX_PKT_HEADER_L4STUFF_SHIFT);
710b4d05839Sml 
711b4d05839Sml 				NXGE_DEBUG_MSG((NULL, TX_CTL,
712b4d05839Sml 				    "==> nxge_tx_pkt_hdr_init: UDP offset %d "
713b4d05839Sml 				    " use partial checksum "
714b4d05839Sml 				    "cksum 0x%x ",
715b4d05839Sml 				    "value 0x%llx",
716b4d05839Sml 				    stuff_offset,
717b4d05839Sml 				    IP_CSUM(mp, start_offset, 0),
718b4d05839Sml 				    hdrp->value));
719b4d05839Sml 			}
72044961713Sgirish 		}
721b4d05839Sml 
72244961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
72352ccf843Smisaki 		    "==> nxge_tx_pkt_hdr_init: UDP"
72452ccf843Smisaki 		    "value 0x%llx", hdrp->value));
72544961713Sgirish 		break;
72644961713Sgirish 
72744961713Sgirish 	default:
72844961713Sgirish 		goto fill_tx_header_done;
72944961713Sgirish 	}
73044961713Sgirish 
73144961713Sgirish fill_tx_header_done:
73244961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
73352ccf843Smisaki 	    "==> nxge_fill_tx_hdr: pkt_len %d  "
73452ccf843Smisaki 	    "npads %d value 0x%llx", pkt_len, npads, hdrp->value));
73544961713Sgirish 
73644961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "<== nxge_fill_tx_hdr"));
73744961713Sgirish }
73844961713Sgirish 
73944961713Sgirish /*ARGSUSED*/
74044961713Sgirish p_mblk_t
74144961713Sgirish nxge_tx_pkt_header_reserve(p_mblk_t mp, uint8_t *npads)
74244961713Sgirish {
74344961713Sgirish 	p_mblk_t 		newmp = NULL;
74444961713Sgirish 
74544961713Sgirish 	if ((newmp = allocb(TX_PKT_HEADER_SIZE, BPRI_MED)) == NULL) {
74644961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
74752ccf843Smisaki 		    "<== nxge_tx_pkt_header_reserve: allocb failed"));
74844961713Sgirish 		return (NULL);
74944961713Sgirish 	}
75044961713Sgirish 
75144961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
75252ccf843Smisaki 	    "==> nxge_tx_pkt_header_reserve: get new mp"));
75344961713Sgirish 	DB_TYPE(newmp) = M_DATA;
75444961713Sgirish 	newmp->b_rptr = newmp->b_wptr = DB_LIM(newmp);
75544961713Sgirish 	linkb(newmp, mp);
75644961713Sgirish 	newmp->b_rptr -= TX_PKT_HEADER_SIZE;
75744961713Sgirish 
75844961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==>nxge_tx_pkt_header_reserve: "
75952ccf843Smisaki 	    "b_rptr $%p b_wptr $%p",
76052ccf843Smisaki 	    newmp->b_rptr, newmp->b_wptr));
76144961713Sgirish 
76244961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
76352ccf843Smisaki 	    "<== nxge_tx_pkt_header_reserve: use new mp"));
76444961713Sgirish 
76544961713Sgirish 	return (newmp);
76644961713Sgirish }
76744961713Sgirish 
76844961713Sgirish int
76944961713Sgirish nxge_tx_pkt_nmblocks(p_mblk_t mp, int *tot_xfer_len_p)
77044961713Sgirish {
77144961713Sgirish 	uint_t 			nmblks;
77244961713Sgirish 	ssize_t			len;
77344961713Sgirish 	uint_t 			pkt_len;
77444961713Sgirish 	p_mblk_t 		nmp, bmp, tmp;
77544961713Sgirish 	uint8_t 		*b_wptr;
77644961713Sgirish 
77744961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
77852ccf843Smisaki 	    "==> nxge_tx_pkt_nmblocks: mp $%p rptr $%p wptr $%p "
77952ccf843Smisaki 	    "len %d", mp, mp->b_rptr, mp->b_wptr, MBLKL(mp)));
78044961713Sgirish 
78144961713Sgirish 	nmp = mp;
78244961713Sgirish 	bmp = mp;
78344961713Sgirish 	nmblks = 0;
78444961713Sgirish 	pkt_len = 0;
78544961713Sgirish 	*tot_xfer_len_p = 0;
78644961713Sgirish 
78744961713Sgirish 	while (nmp) {
78844961713Sgirish 		len = MBLKL(nmp);
78944961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: "
79052ccf843Smisaki 		    "len %d pkt_len %d nmblks %d tot_xfer_len %d",
79152ccf843Smisaki 		    len, pkt_len, nmblks,
79252ccf843Smisaki 		    *tot_xfer_len_p));
79344961713Sgirish 
79444961713Sgirish 		if (len <= 0) {
79544961713Sgirish 			bmp = nmp;
79644961713Sgirish 			nmp = nmp->b_cont;
79744961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
79852ccf843Smisaki 			    "==> nxge_tx_pkt_nmblocks: "
79952ccf843Smisaki 			    "len (0) pkt_len %d nmblks %d",
80052ccf843Smisaki 			    pkt_len, nmblks));
80144961713Sgirish 			continue;
80244961713Sgirish 		}
80344961713Sgirish 
80444961713Sgirish 		*tot_xfer_len_p += len;
80544961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: "
80652ccf843Smisaki 		    "len %d pkt_len %d nmblks %d tot_xfer_len %d",
80752ccf843Smisaki 		    len, pkt_len, nmblks,
80852ccf843Smisaki 		    *tot_xfer_len_p));
80944961713Sgirish 
81044961713Sgirish 		if (len < nxge_bcopy_thresh) {
81144961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
81252ccf843Smisaki 			    "==> nxge_tx_pkt_nmblocks: "
81352ccf843Smisaki 			    "len %d (< thresh) pkt_len %d nmblks %d",
81452ccf843Smisaki 			    len, pkt_len, nmblks));
81544961713Sgirish 			if (pkt_len == 0)
81644961713Sgirish 				nmblks++;
81744961713Sgirish 			pkt_len += len;
81844961713Sgirish 			if (pkt_len >= nxge_bcopy_thresh) {
81944961713Sgirish 				pkt_len = 0;
82044961713Sgirish 				len = 0;
82144961713Sgirish 				nmp = bmp;
82244961713Sgirish 			}
82344961713Sgirish 		} else {
82444961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
82552ccf843Smisaki 			    "==> nxge_tx_pkt_nmblocks: "
82652ccf843Smisaki 			    "len %d (> thresh) pkt_len %d nmblks %d",
82752ccf843Smisaki 			    len, pkt_len, nmblks));
82844961713Sgirish 			pkt_len = 0;
82944961713Sgirish 			nmblks++;
83044961713Sgirish 			/*
83144961713Sgirish 			 * Hardware limits the transfer length to 4K.
83244961713Sgirish 			 * If len is more than 4K, we need to break
83344961713Sgirish 			 * it up to at most 2 more blocks.
83444961713Sgirish 			 */
83544961713Sgirish 			if (len > TX_MAX_TRANSFER_LENGTH) {
83644961713Sgirish 				uint32_t	nsegs;
83744961713Sgirish 
838678453a8Sspeer 				nsegs = 1;
83944961713Sgirish 				NXGE_DEBUG_MSG((NULL, TX_CTL,
84052ccf843Smisaki 				    "==> nxge_tx_pkt_nmblocks: "
84152ccf843Smisaki 				    "len %d pkt_len %d nmblks %d nsegs %d",
84252ccf843Smisaki 				    len, pkt_len, nmblks, nsegs));
84344961713Sgirish 				if (len % (TX_MAX_TRANSFER_LENGTH * 2)) {
84444961713Sgirish 					++nsegs;
84544961713Sgirish 				}
84644961713Sgirish 				do {
84744961713Sgirish 					b_wptr = nmp->b_rptr +
84852ccf843Smisaki 					    TX_MAX_TRANSFER_LENGTH;
84944961713Sgirish 					nmp->b_wptr = b_wptr;
85044961713Sgirish 					if ((tmp = dupb(nmp)) == NULL) {
85144961713Sgirish 						return (0);
85244961713Sgirish 					}
85344961713Sgirish 					tmp->b_rptr = b_wptr;
85444961713Sgirish 					tmp->b_wptr = nmp->b_wptr;
85544961713Sgirish 					tmp->b_cont = nmp->b_cont;
85644961713Sgirish 					nmp->b_cont = tmp;
85744961713Sgirish 					nmblks++;
85844961713Sgirish 					if (--nsegs) {
85944961713Sgirish 						nmp = tmp;
86044961713Sgirish 					}
86144961713Sgirish 				} while (nsegs);
86244961713Sgirish 				nmp = tmp;
86344961713Sgirish 			}
86444961713Sgirish 		}
86544961713Sgirish 
86644961713Sgirish 		/*
86744961713Sgirish 		 * Hardware limits the transmit gather pointers to 15.
86844961713Sgirish 		 */
86944961713Sgirish 		if (nmp->b_cont && (nmblks + TX_GATHER_POINTERS_THRESHOLD) >
87052ccf843Smisaki 		    TX_MAX_GATHER_POINTERS) {
87144961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
87252ccf843Smisaki 			    "==> nxge_tx_pkt_nmblocks: pull msg - "
87352ccf843Smisaki 			    "len %d pkt_len %d nmblks %d",
87452ccf843Smisaki 			    len, pkt_len, nmblks));
87544961713Sgirish 			/* Pull all message blocks from b_cont */
87644961713Sgirish 			if ((tmp = msgpullup(nmp->b_cont, -1)) == NULL) {
87744961713Sgirish 				return (0);
87844961713Sgirish 			}
87944961713Sgirish 			freemsg(nmp->b_cont);
88044961713Sgirish 			nmp->b_cont = tmp;
88144961713Sgirish 			pkt_len = 0;
88244961713Sgirish 		}
88344961713Sgirish 		bmp = nmp;
88444961713Sgirish 		nmp = nmp->b_cont;
88544961713Sgirish 	}
88644961713Sgirish 
88744961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
88852ccf843Smisaki 	    "<== nxge_tx_pkt_nmblocks: rptr $%p wptr $%p "
88952ccf843Smisaki 	    "nmblks %d len %d tot_xfer_len %d",
89052ccf843Smisaki 	    mp->b_rptr, mp->b_wptr, nmblks,
89152ccf843Smisaki 	    MBLKL(mp), *tot_xfer_len_p));
89244961713Sgirish 
89344961713Sgirish 	return (nmblks);
89444961713Sgirish }
89544961713Sgirish 
89644961713Sgirish boolean_t
89744961713Sgirish nxge_txdma_reclaim(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, int nmblks)
89844961713Sgirish {
89944961713Sgirish 	boolean_t 		status = B_TRUE;
90044961713Sgirish 	p_nxge_dma_common_t	tx_desc_dma_p;
90144961713Sgirish 	nxge_dma_common_t	desc_area;
90244961713Sgirish 	p_tx_desc_t 		tx_desc_ring_vp;
90344961713Sgirish 	p_tx_desc_t 		tx_desc_p;
90444961713Sgirish 	p_tx_desc_t 		tx_desc_pp;
90544961713Sgirish 	tx_desc_t 		r_tx_desc;
90644961713Sgirish 	p_tx_msg_t 		tx_msg_ring;
90744961713Sgirish 	p_tx_msg_t 		tx_msg_p;
90844961713Sgirish 	npi_handle_t		handle;
90944961713Sgirish 	tx_ring_hdl_t		tx_head;
91044961713Sgirish 	uint32_t 		pkt_len;
91144961713Sgirish 	uint_t			tx_rd_index;
91244961713Sgirish 	uint16_t		head_index, tail_index;
91344961713Sgirish 	uint8_t			tdc;
91444961713Sgirish 	boolean_t		head_wrap, tail_wrap;
915da14cebeSEric Cheng 	p_nxge_tx_ring_stats_t tdc_stats;
91644961713Sgirish 	int			rc;
91744961713Sgirish 
91844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_reclaim"));
91944961713Sgirish 
92044961713Sgirish 	status = ((tx_ring_p->descs_pending < nxge_reclaim_pending) &&
92152ccf843Smisaki 	    (nmblks != 0));
92244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
92352ccf843Smisaki 	    "==> nxge_txdma_reclaim: pending %d  reclaim %d nmblks %d",
92452ccf843Smisaki 	    tx_ring_p->descs_pending, nxge_reclaim_pending,
92552ccf843Smisaki 	    nmblks));
92644961713Sgirish 	if (!status) {
92744961713Sgirish 		tx_desc_dma_p = &tx_ring_p->tdc_desc;
92844961713Sgirish 		desc_area = tx_ring_p->tdc_desc;
92944961713Sgirish 		handle = NXGE_DEV_NPI_HANDLE(nxgep);
93044961713Sgirish 		tx_desc_ring_vp = tx_desc_dma_p->kaddrp;
93144961713Sgirish 		tx_desc_ring_vp =
93252ccf843Smisaki 		    (p_tx_desc_t)DMA_COMMON_VPTR(desc_area);
93344961713Sgirish 		tx_rd_index = tx_ring_p->rd_index;
93444961713Sgirish 		tx_desc_p = &tx_desc_ring_vp[tx_rd_index];
93544961713Sgirish 		tx_msg_ring = tx_ring_p->tx_msg_ring;
93644961713Sgirish 		tx_msg_p = &tx_msg_ring[tx_rd_index];
93744961713Sgirish 		tdc = tx_ring_p->tdc;
93844961713Sgirish 		tdc_stats = tx_ring_p->tdc_stats;
93944961713Sgirish 		if (tx_ring_p->descs_pending > tdc_stats->tx_max_pend) {
94044961713Sgirish 			tdc_stats->tx_max_pend = tx_ring_p->descs_pending;
94144961713Sgirish 		}
94244961713Sgirish 
94344961713Sgirish 		tail_index = tx_ring_p->wr_index;
94444961713Sgirish 		tail_wrap = tx_ring_p->wr_index_wrap;
94544961713Sgirish 
94644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
94752ccf843Smisaki 		    "==> nxge_txdma_reclaim: tdc %d tx_rd_index %d "
94852ccf843Smisaki 		    "tail_index %d tail_wrap %d "
94952ccf843Smisaki 		    "tx_desc_p $%p ($%p) ",
95052ccf843Smisaki 		    tdc, tx_rd_index, tail_index, tail_wrap,
95152ccf843Smisaki 		    tx_desc_p, (*(uint64_t *)tx_desc_p)));
95244961713Sgirish 		/*
95344961713Sgirish 		 * Read the hardware maintained transmit head
95444961713Sgirish 		 * and wrap around bit.
95544961713Sgirish 		 */
95644961713Sgirish 		TXDMA_REG_READ64(handle, TX_RING_HDL_REG, tdc, &tx_head.value);
95744961713Sgirish 		head_index =  tx_head.bits.ldw.head;
95844961713Sgirish 		head_wrap = tx_head.bits.ldw.wrap;
95944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
96052ccf843Smisaki 		    "==> nxge_txdma_reclaim: "
96152ccf843Smisaki 		    "tx_rd_index %d tail %d tail_wrap %d "
96252ccf843Smisaki 		    "head %d wrap %d",
96352ccf843Smisaki 		    tx_rd_index, tail_index, tail_wrap,
96452ccf843Smisaki 		    head_index, head_wrap));
96544961713Sgirish 
96644961713Sgirish 		if (head_index == tail_index) {
96744961713Sgirish 			if (TXDMA_RING_EMPTY(head_index, head_wrap,
96852ccf843Smisaki 			    tail_index, tail_wrap) &&
96952ccf843Smisaki 			    (head_index == tx_rd_index)) {
97044961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
97152ccf843Smisaki 				    "==> nxge_txdma_reclaim: EMPTY"));
97244961713Sgirish 				return (B_TRUE);
97344961713Sgirish 			}
97444961713Sgirish 
97544961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
97652ccf843Smisaki 			    "==> nxge_txdma_reclaim: Checking "
97752ccf843Smisaki 			    "if ring full"));
97844961713Sgirish 			if (TXDMA_RING_FULL(head_index, head_wrap, tail_index,
97952ccf843Smisaki 			    tail_wrap)) {
98044961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
98152ccf843Smisaki 				    "==> nxge_txdma_reclaim: full"));
98244961713Sgirish 				return (B_FALSE);
98344961713Sgirish 			}
98444961713Sgirish 		}
98544961713Sgirish 
98644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
98752ccf843Smisaki 		    "==> nxge_txdma_reclaim: tx_rd_index and head_index"));
98844961713Sgirish 
98944961713Sgirish 		tx_desc_pp = &r_tx_desc;
99044961713Sgirish 		while ((tx_rd_index != head_index) &&
99152ccf843Smisaki 		    (tx_ring_p->descs_pending != 0)) {
99244961713Sgirish 
99344961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
99452ccf843Smisaki 			    "==> nxge_txdma_reclaim: Checking if pending"));
99544961713Sgirish 
99644961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
99752ccf843Smisaki 			    "==> nxge_txdma_reclaim: "
99852ccf843Smisaki 			    "descs_pending %d ",
99952ccf843Smisaki 			    tx_ring_p->descs_pending));
100044961713Sgirish 
100144961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
100252ccf843Smisaki 			    "==> nxge_txdma_reclaim: "
100352ccf843Smisaki 			    "(tx_rd_index %d head_index %d "
100452ccf843Smisaki 			    "(tx_desc_p $%p)",
100552ccf843Smisaki 			    tx_rd_index, head_index,
100652ccf843Smisaki 			    tx_desc_p));
100744961713Sgirish 
100844961713Sgirish 			tx_desc_pp->value = tx_desc_p->value;
100944961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
101052ccf843Smisaki 			    "==> nxge_txdma_reclaim: "
101152ccf843Smisaki 			    "(tx_rd_index %d head_index %d "
101252ccf843Smisaki 			    "tx_desc_p $%p (desc value 0x%llx) ",
101352ccf843Smisaki 			    tx_rd_index, head_index,
101452ccf843Smisaki 			    tx_desc_pp, (*(uint64_t *)tx_desc_pp)));
101544961713Sgirish 
101644961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
101752ccf843Smisaki 			    "==> nxge_txdma_reclaim: dump desc:"));
101844961713Sgirish 
101944961713Sgirish 			pkt_len = tx_desc_pp->bits.hdw.tr_len;
102044961713Sgirish 			tdc_stats->obytes += pkt_len;
102144961713Sgirish 			tdc_stats->opackets += tx_desc_pp->bits.hdw.sop;
102244961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
102352ccf843Smisaki 			    "==> nxge_txdma_reclaim: pkt_len %d "
102452ccf843Smisaki 			    "tdc channel %d opackets %d",
102552ccf843Smisaki 			    pkt_len,
102652ccf843Smisaki 			    tdc,
102752ccf843Smisaki 			    tdc_stats->opackets));
102844961713Sgirish 
102944961713Sgirish 			if (tx_msg_p->flags.dma_type == USE_DVMA) {
103044961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
103152ccf843Smisaki 				    "tx_desc_p = $%p "
103252ccf843Smisaki 				    "tx_desc_pp = $%p "
103352ccf843Smisaki 				    "index = %d",
103452ccf843Smisaki 				    tx_desc_p,
103552ccf843Smisaki 				    tx_desc_pp,
103652ccf843Smisaki 				    tx_ring_p->rd_index));
103744961713Sgirish 				(void) dvma_unload(tx_msg_p->dvma_handle,
103852ccf843Smisaki 				    0, -1);
103944961713Sgirish 				tx_msg_p->dvma_handle = NULL;
104044961713Sgirish 				if (tx_ring_p->dvma_wr_index ==
104152ccf843Smisaki 				    tx_ring_p->dvma_wrap_mask) {
104244961713Sgirish 					tx_ring_p->dvma_wr_index = 0;
104344961713Sgirish 				} else {
104444961713Sgirish 					tx_ring_p->dvma_wr_index++;
104544961713Sgirish 				}
104644961713Sgirish 				tx_ring_p->dvma_pending--;
104744961713Sgirish 			} else if (tx_msg_p->flags.dma_type ==
104852ccf843Smisaki 			    USE_DMA) {
104944961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
105052ccf843Smisaki 				    "==> nxge_txdma_reclaim: "
105152ccf843Smisaki 				    "USE DMA"));
105244961713Sgirish 				if (rc = ddi_dma_unbind_handle
105352ccf843Smisaki 				    (tx_msg_p->dma_handle)) {
105444961713Sgirish 					cmn_err(CE_WARN, "!nxge_reclaim: "
105552ccf843Smisaki 					    "ddi_dma_unbind_handle "
105652ccf843Smisaki 					    "failed. status %d", rc);
105744961713Sgirish 				}
105844961713Sgirish 			}
105944961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
106052ccf843Smisaki 			    "==> nxge_txdma_reclaim: count packets"));
106144961713Sgirish 			/*
106244961713Sgirish 			 * count a chained packet only once.
106344961713Sgirish 			 */
106444961713Sgirish 			if (tx_msg_p->tx_message != NULL) {
1065da14cebeSEric Cheng 				freemsg(tx_msg_p->tx_message);
1066da14cebeSEric Cheng 				tx_msg_p->tx_message = NULL;
106744961713Sgirish 			}
106844961713Sgirish 
106944961713Sgirish 			tx_msg_p->flags.dma_type = USE_NONE;
107044961713Sgirish 			tx_rd_index = tx_ring_p->rd_index;
107144961713Sgirish 			tx_rd_index = (tx_rd_index + 1) &
107252ccf843Smisaki 			    tx_ring_p->tx_wrap_mask;
107344961713Sgirish 			tx_ring_p->rd_index = tx_rd_index;
107444961713Sgirish 			tx_ring_p->descs_pending--;
107544961713Sgirish 			tx_desc_p = &tx_desc_ring_vp[tx_rd_index];
107644961713Sgirish 			tx_msg_p = &tx_msg_ring[tx_rd_index];
107744961713Sgirish 		}
107844961713Sgirish 
1079257bdc55SMichael Speer 		status = (nmblks <= ((int)tx_ring_p->tx_ring_size -
1080257bdc55SMichael Speer 		    (int)tx_ring_p->descs_pending - TX_FULL_MARK));
108144961713Sgirish 		if (status) {
1082952a2464SMichael Speer 			(void) cas32((uint32_t *)&tx_ring_p->queueing, 1, 0);
108344961713Sgirish 		}
108444961713Sgirish 	} else {
1085257bdc55SMichael Speer 		status = (nmblks <= ((int)tx_ring_p->tx_ring_size -
1086257bdc55SMichael Speer 		    (int)tx_ring_p->descs_pending - TX_FULL_MARK));
108744961713Sgirish 	}
108844961713Sgirish 
108944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
109052ccf843Smisaki 	    "<== nxge_txdma_reclaim status = 0x%08x", status));
109144961713Sgirish 
109244961713Sgirish 	return (status);
109344961713Sgirish }
109444961713Sgirish 
1095678453a8Sspeer /*
1096678453a8Sspeer  * nxge_tx_intr
1097678453a8Sspeer  *
1098678453a8Sspeer  *	Process a TDC interrupt
1099678453a8Sspeer  *
1100678453a8Sspeer  * Arguments:
1101678453a8Sspeer  * 	arg1	A Logical Device state Vector (LSV) data structure.
1102678453a8Sspeer  * 	arg2	nxge_t *
1103678453a8Sspeer  *
1104678453a8Sspeer  * Notes:
1105678453a8Sspeer  *
1106678453a8Sspeer  * NPI/NXGE function calls:
1107678453a8Sspeer  *	npi_txdma_control_status()
1108678453a8Sspeer  *	npi_intr_ldg_mgmt_set()
1109678453a8Sspeer  *
1110678453a8Sspeer  *	nxge_tx_err_evnts()
1111678453a8Sspeer  *	nxge_txdma_reclaim()
1112678453a8Sspeer  *
1113678453a8Sspeer  * Registers accessed:
1114678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1115678453a8Sspeer  *	PIO_LDSV
1116678453a8Sspeer  *
1117678453a8Sspeer  * Context:
1118678453a8Sspeer  *	Any domain
1119678453a8Sspeer  */
112044961713Sgirish uint_t
112144961713Sgirish nxge_tx_intr(void *arg1, void *arg2)
112244961713Sgirish {
112344961713Sgirish 	p_nxge_ldv_t		ldvp = (p_nxge_ldv_t)arg1;
112444961713Sgirish 	p_nxge_t		nxgep = (p_nxge_t)arg2;
112544961713Sgirish 	p_nxge_ldg_t		ldgp;
112644961713Sgirish 	uint8_t			channel;
112744961713Sgirish 	uint32_t		vindex;
112844961713Sgirish 	npi_handle_t		handle;
112944961713Sgirish 	tx_cs_t			cs;
113044961713Sgirish 	p_tx_ring_t 		*tx_rings;
113144961713Sgirish 	p_tx_ring_t 		tx_ring_p;
113244961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
113344961713Sgirish 	uint_t 			serviced = DDI_INTR_UNCLAIMED;
113444961713Sgirish 	nxge_status_t 		status = NXGE_OK;
113544961713Sgirish 
113644961713Sgirish 	if (ldvp == NULL) {
113744961713Sgirish 		NXGE_DEBUG_MSG((NULL, INT_CTL,
113852ccf843Smisaki 		    "<== nxge_tx_intr: nxgep $%p ldvp $%p",
113952ccf843Smisaki 		    nxgep, ldvp));
114044961713Sgirish 		return (DDI_INTR_UNCLAIMED);
114144961713Sgirish 	}
114244961713Sgirish 
114344961713Sgirish 	if (arg2 == NULL || (void *)ldvp->nxgep != arg2) {
114444961713Sgirish 		nxgep = ldvp->nxgep;
114544961713Sgirish 	}
114644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
114752ccf843Smisaki 	    "==> nxge_tx_intr: nxgep(arg2) $%p ldvp(arg1) $%p",
114852ccf843Smisaki 	    nxgep, ldvp));
114922c0d73aSspeer 
115022c0d73aSspeer 	if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) ||
115122c0d73aSspeer 	    (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) {
115222c0d73aSspeer 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
115322c0d73aSspeer 		    "<== nxge_tx_intr: interface not started or intialized"));
115422c0d73aSspeer 		return (DDI_INTR_CLAIMED);
115522c0d73aSspeer 	}
115622c0d73aSspeer 
115744961713Sgirish 	/*
115844961713Sgirish 	 * This interrupt handler is for a specific
115944961713Sgirish 	 * transmit dma channel.
116044961713Sgirish 	 */
116144961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
116244961713Sgirish 	/* Get the control and status for this channel. */
116344961713Sgirish 	channel = ldvp->channel;
116444961713Sgirish 	ldgp = ldvp->ldgp;
116544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
116652ccf843Smisaki 	    "==> nxge_tx_intr: nxgep $%p ldvp (ldvp) $%p "
116752ccf843Smisaki 	    "channel %d",
116852ccf843Smisaki 	    nxgep, ldvp, channel));
116944961713Sgirish 
117044961713Sgirish 	rs = npi_txdma_control_status(handle, OP_GET, channel, &cs);
117144961713Sgirish 	vindex = ldvp->vdma_index;
117244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
117352ccf843Smisaki 	    "==> nxge_tx_intr:channel %d ring index %d status 0x%08x",
117452ccf843Smisaki 	    channel, vindex, rs));
117544961713Sgirish 	if (!rs && cs.bits.ldw.mk) {
117644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
117752ccf843Smisaki 		    "==> nxge_tx_intr:channel %d ring index %d "
117852ccf843Smisaki 		    "status 0x%08x (mk bit set)",
117952ccf843Smisaki 		    channel, vindex, rs));
118044961713Sgirish 		tx_rings = nxgep->tx_rings->rings;
118144961713Sgirish 		tx_ring_p = tx_rings[vindex];
118244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
118352ccf843Smisaki 		    "==> nxge_tx_intr:channel %d ring index %d "
118452ccf843Smisaki 		    "status 0x%08x (mk bit set, calling reclaim)",
118552ccf843Smisaki 		    channel, vindex, rs));
118644961713Sgirish 
1187da14cebeSEric Cheng 		nxge_tx_ring_task((void *)tx_ring_p);
118844961713Sgirish 	}
118944961713Sgirish 
119044961713Sgirish 	/*
119144961713Sgirish 	 * Process other transmit control and status.
119244961713Sgirish 	 * Check the ldv state.
119344961713Sgirish 	 */
119444961713Sgirish 	status = nxge_tx_err_evnts(nxgep, ldvp->vdma_index, ldvp, cs);
119544961713Sgirish 	/*
119644961713Sgirish 	 * Rearm this logical group if this is a single device
119744961713Sgirish 	 * group.
119844961713Sgirish 	 */
119944961713Sgirish 	if (ldgp->nldvs == 1) {
120044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
120152ccf843Smisaki 		    "==> nxge_tx_intr: rearm"));
120244961713Sgirish 		if (status == NXGE_OK) {
1203678453a8Sspeer 			if (isLDOMguest(nxgep)) {
1204678453a8Sspeer 				nxge_hio_ldgimgn(nxgep, ldgp);
1205678453a8Sspeer 			} else {
1206678453a8Sspeer 				(void) npi_intr_ldg_mgmt_set(handle, ldgp->ldg,
1207678453a8Sspeer 				    B_TRUE, ldgp->ldg_timer);
1208678453a8Sspeer 			}
120944961713Sgirish 		}
121044961713Sgirish 	}
121144961713Sgirish 
121244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_tx_intr"));
121344961713Sgirish 	serviced = DDI_INTR_CLAIMED;
121444961713Sgirish 	return (serviced);
121544961713Sgirish }
121644961713Sgirish 
121744961713Sgirish void
1218678453a8Sspeer nxge_txdma_stop(p_nxge_t nxgep)	/* Dead */
121944961713Sgirish {
122044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop"));
122144961713Sgirish 
122244961713Sgirish 	(void) nxge_link_monitor(nxgep, LINK_MONITOR_STOP);
122344961713Sgirish 
122444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop"));
122544961713Sgirish }
122644961713Sgirish 
122744961713Sgirish void
1228678453a8Sspeer nxge_txdma_stop_start(p_nxge_t nxgep) /* Dead */
122944961713Sgirish {
123044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_start"));
123144961713Sgirish 
123244961713Sgirish 	(void) nxge_txdma_stop(nxgep);
123344961713Sgirish 
123444961713Sgirish 	(void) nxge_fixup_txdma_rings(nxgep);
123544961713Sgirish 	(void) nxge_txdma_hw_mode(nxgep, NXGE_DMA_START);
123644961713Sgirish 	(void) nxge_tx_mac_enable(nxgep);
123744961713Sgirish 	(void) nxge_txdma_hw_kick(nxgep);
123844961713Sgirish 
123944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_start"));
124044961713Sgirish }
124144961713Sgirish 
1242678453a8Sspeer npi_status_t
1243678453a8Sspeer nxge_txdma_channel_disable(
1244678453a8Sspeer 	nxge_t *nxge,
1245678453a8Sspeer 	int channel)
1246678453a8Sspeer {
1247678453a8Sspeer 	npi_handle_t	handle = NXGE_DEV_NPI_HANDLE(nxge);
1248678453a8Sspeer 	npi_status_t	rs;
1249678453a8Sspeer 	tdmc_intr_dbg_t	intr_dbg;
1250678453a8Sspeer 
1251678453a8Sspeer 	/*
1252678453a8Sspeer 	 * Stop the dma channel and wait for the stop-done.
1253678453a8Sspeer 	 * If the stop-done bit is not present, then force
1254678453a8Sspeer 	 * an error so TXC will stop.
1255678453a8Sspeer 	 * All channels bound to this port need to be stopped
1256678453a8Sspeer 	 * and reset after injecting an interrupt error.
1257678453a8Sspeer 	 */
1258678453a8Sspeer 	rs = npi_txdma_channel_disable(handle, channel);
1259678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, MEM3_CTL,
126052ccf843Smisaki 	    "==> nxge_txdma_channel_disable(%d) "
126152ccf843Smisaki 	    "rs 0x%x", channel, rs));
1262678453a8Sspeer 	if (rs != NPI_SUCCESS) {
1263678453a8Sspeer 		/* Inject any error */
1264678453a8Sspeer 		intr_dbg.value = 0;
1265678453a8Sspeer 		intr_dbg.bits.ldw.nack_pref = 1;
1266678453a8Sspeer 		NXGE_DEBUG_MSG((nxge, MEM3_CTL,
126752ccf843Smisaki 		    "==> nxge_txdma_hw_mode: "
126852ccf843Smisaki 		    "channel %d (stop failed 0x%x) "
126952ccf843Smisaki 		    "(inject err)", rs, channel));
1270678453a8Sspeer 		(void) npi_txdma_inj_int_error_set(
127152ccf843Smisaki 		    handle, channel, &intr_dbg);
1272678453a8Sspeer 		rs = npi_txdma_channel_disable(handle, channel);
1273678453a8Sspeer 		NXGE_DEBUG_MSG((nxge, MEM3_CTL,
127452ccf843Smisaki 		    "==> nxge_txdma_hw_mode: "
127552ccf843Smisaki 		    "channel %d (stop again 0x%x) "
127652ccf843Smisaki 		    "(after inject err)",
127752ccf843Smisaki 		    rs, channel));
1278678453a8Sspeer 	}
1279678453a8Sspeer 
1280678453a8Sspeer 	return (rs);
1281678453a8Sspeer }
1282678453a8Sspeer 
1283678453a8Sspeer /*
1284678453a8Sspeer  * nxge_txdma_hw_mode
1285678453a8Sspeer  *
1286678453a8Sspeer  *	Toggle all TDCs on (enable) or off (disable).
1287678453a8Sspeer  *
1288678453a8Sspeer  * Arguments:
1289678453a8Sspeer  * 	nxgep
1290678453a8Sspeer  * 	enable	Enable or disable a TDC.
1291678453a8Sspeer  *
1292678453a8Sspeer  * Notes:
1293678453a8Sspeer  *
1294678453a8Sspeer  * NPI/NXGE function calls:
1295678453a8Sspeer  *	npi_txdma_channel_enable(TX_CS)
1296678453a8Sspeer  *	npi_txdma_channel_disable(TX_CS)
1297678453a8Sspeer  *	npi_txdma_inj_int_error_set(TDMC_INTR_DBG)
1298678453a8Sspeer  *
1299678453a8Sspeer  * Registers accessed:
1300678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1301678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
1302678453a8Sspeer  *
1303678453a8Sspeer  * Context:
1304678453a8Sspeer  *	Any domain
1305678453a8Sspeer  */
130644961713Sgirish nxge_status_t
130744961713Sgirish nxge_txdma_hw_mode(p_nxge_t nxgep, boolean_t enable)
130844961713Sgirish {
1309678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1310678453a8Sspeer 
1311678453a8Sspeer 	npi_handle_t	handle;
1312678453a8Sspeer 	nxge_status_t	status;
1313678453a8Sspeer 	npi_status_t	rs;
1314678453a8Sspeer 	int		tdc;
131544961713Sgirish 
131644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
131752ccf843Smisaki 	    "==> nxge_txdma_hw_mode: enable mode %d", enable));
131844961713Sgirish 
131944961713Sgirish 	if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) {
132044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
132152ccf843Smisaki 		    "<== nxge_txdma_mode: not initialized"));
132244961713Sgirish 		return (NXGE_ERROR);
132344961713Sgirish 	}
132444961713Sgirish 
1325678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
132644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1327678453a8Sspeer 		    "<== nxge_txdma_hw_mode: NULL ring pointer(s)"));
132844961713Sgirish 		return (NXGE_ERROR);
132944961713Sgirish 	}
133044961713Sgirish 
1331678453a8Sspeer 	/* Enable or disable all of the TDCs owned by us. */
133244961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
1333678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1334678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1335678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1336678453a8Sspeer 			if (ring) {
1337678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1338678453a8Sspeer 				    "==> nxge_txdma_hw_mode: channel %d", tdc));
1339678453a8Sspeer 				if (enable) {
1340678453a8Sspeer 					rs = npi_txdma_channel_enable
1341678453a8Sspeer 					    (handle, tdc);
134244961713Sgirish 					NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1343678453a8Sspeer 					    "==> nxge_txdma_hw_mode: "
1344678453a8Sspeer 					    "channel %d (enable) rs 0x%x",
1345678453a8Sspeer 					    tdc, rs));
1346678453a8Sspeer 				} else {
1347678453a8Sspeer 					rs = nxge_txdma_channel_disable
1348678453a8Sspeer 					    (nxgep, tdc);
134944961713Sgirish 				}
135044961713Sgirish 			}
135144961713Sgirish 		}
135244961713Sgirish 	}
135344961713Sgirish 
135444961713Sgirish 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
135544961713Sgirish 
135644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
135752ccf843Smisaki 	    "<== nxge_txdma_hw_mode: status 0x%x", status));
135844961713Sgirish 
135944961713Sgirish 	return (status);
136044961713Sgirish }
136144961713Sgirish 
136244961713Sgirish void
136344961713Sgirish nxge_txdma_enable_channel(p_nxge_t nxgep, uint16_t channel)
136444961713Sgirish {
136544961713Sgirish 	npi_handle_t		handle;
136644961713Sgirish 
136744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DMA_CTL,
136852ccf843Smisaki 	    "==> nxge_txdma_enable_channel: channel %d", channel));
136944961713Sgirish 
137044961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
137144961713Sgirish 	/* enable the transmit dma channels */
137244961713Sgirish 	(void) npi_txdma_channel_enable(handle, channel);
137344961713Sgirish 
137444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DMA_CTL, "<== nxge_txdma_enable_channel"));
137544961713Sgirish }
137644961713Sgirish 
137744961713Sgirish void
137844961713Sgirish nxge_txdma_disable_channel(p_nxge_t nxgep, uint16_t channel)
137944961713Sgirish {
138044961713Sgirish 	npi_handle_t		handle;
138144961713Sgirish 
138244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DMA_CTL,
138352ccf843Smisaki 	    "==> nxge_txdma_disable_channel: channel %d", channel));
138444961713Sgirish 
138544961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
138644961713Sgirish 	/* stop the transmit dma channels */
138744961713Sgirish 	(void) npi_txdma_channel_disable(handle, channel);
138844961713Sgirish 
138944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_disable_channel"));
139044961713Sgirish }
139144961713Sgirish 
1392678453a8Sspeer /*
1393678453a8Sspeer  * nxge_txdma_stop_inj_err
1394678453a8Sspeer  *
1395678453a8Sspeer  *	Stop a TDC.  If at first we don't succeed, inject an error.
1396678453a8Sspeer  *
1397678453a8Sspeer  * Arguments:
1398678453a8Sspeer  * 	nxgep
1399678453a8Sspeer  * 	channel		The channel to stop.
1400678453a8Sspeer  *
1401678453a8Sspeer  * Notes:
1402678453a8Sspeer  *
1403678453a8Sspeer  * NPI/NXGE function calls:
1404678453a8Sspeer  *	npi_txdma_channel_disable()
1405678453a8Sspeer  *	npi_txdma_inj_int_error_set()
1406678453a8Sspeer  * #if defined(NXGE_DEBUG)
1407678453a8Sspeer  *	nxge_txdma_regs_dump_channels(nxgep);
1408678453a8Sspeer  * #endif
1409678453a8Sspeer  *
1410678453a8Sspeer  * Registers accessed:
1411678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1412678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
1413678453a8Sspeer  *
1414678453a8Sspeer  * Context:
1415678453a8Sspeer  *	Any domain
1416678453a8Sspeer  */
141744961713Sgirish int
141844961713Sgirish nxge_txdma_stop_inj_err(p_nxge_t nxgep, int channel)
141944961713Sgirish {
142044961713Sgirish 	npi_handle_t		handle;
142144961713Sgirish 	tdmc_intr_dbg_t		intr_dbg;
142244961713Sgirish 	int			status;
142344961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
142444961713Sgirish 
142544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_inj_err"));
142644961713Sgirish 	/*
142744961713Sgirish 	 * Stop the dma channel waits for the stop done.
142844961713Sgirish 	 * If the stop done bit is not set, then create
142944961713Sgirish 	 * an error.
143044961713Sgirish 	 */
143144961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
143244961713Sgirish 	rs = npi_txdma_channel_disable(handle, channel);
143344961713Sgirish 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
143444961713Sgirish 	if (status == NXGE_OK) {
143544961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
143652ccf843Smisaki 		    "<== nxge_txdma_stop_inj_err (channel %d): "
143752ccf843Smisaki 		    "stopped OK", channel));
143844961713Sgirish 		return (status);
143944961713Sgirish 	}
144044961713Sgirish 
144144961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
144252ccf843Smisaki 	    "==> nxge_txdma_stop_inj_err (channel %d): stop failed (0x%x) "
144352ccf843Smisaki 	    "injecting error", channel, rs));
144444961713Sgirish 	/* Inject any error */
144544961713Sgirish 	intr_dbg.value = 0;
144644961713Sgirish 	intr_dbg.bits.ldw.nack_pref = 1;
144744961713Sgirish 	(void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg);
144844961713Sgirish 
144944961713Sgirish 	/* Stop done bit will be set as a result of error injection */
145044961713Sgirish 	rs = npi_txdma_channel_disable(handle, channel);
145144961713Sgirish 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
145244961713Sgirish 	if (!(rs & NPI_TXDMA_STOP_FAILED)) {
145344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
145452ccf843Smisaki 		    "<== nxge_txdma_stop_inj_err (channel %d): "
145552ccf843Smisaki 		    "stopped OK ", channel));
145644961713Sgirish 		return (status);
145744961713Sgirish 	}
145844961713Sgirish 
145944961713Sgirish #if	defined(NXGE_DEBUG)
146044961713Sgirish 	nxge_txdma_regs_dump_channels(nxgep);
146144961713Sgirish #endif
146244961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
146352ccf843Smisaki 	    "==> nxge_txdma_stop_inj_err (channel): stop failed (0x%x) "
146452ccf843Smisaki 	    " (injected error but still not stopped)", channel, rs));
146544961713Sgirish 
146644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_inj_err"));
146744961713Sgirish 	return (status);
146844961713Sgirish }
146944961713Sgirish 
147044961713Sgirish /*ARGSUSED*/
147144961713Sgirish void
147244961713Sgirish nxge_fixup_txdma_rings(p_nxge_t nxgep)
147344961713Sgirish {
1474678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1475678453a8Sspeer 	int tdc;
147644961713Sgirish 
147744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_txdma_rings"));
147844961713Sgirish 
1479678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
1480678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1481678453a8Sspeer 		    "<== nxge_fixup_txdma_rings: NULL ring pointer(s)"));
148244961713Sgirish 		return;
148344961713Sgirish 	}
148444961713Sgirish 
1485678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1486678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1487678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1488678453a8Sspeer 			if (ring) {
1489678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1490678453a8Sspeer 				    "==> nxge_fixup_txdma_rings: channel %d",
1491678453a8Sspeer 				    tdc));
1492678453a8Sspeer 				nxge_txdma_fixup_channel(nxgep, ring, tdc);
1493678453a8Sspeer 			}
1494678453a8Sspeer 		}
149544961713Sgirish 	}
149644961713Sgirish 
149744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_txdma_rings"));
149844961713Sgirish }
149944961713Sgirish 
150044961713Sgirish /*ARGSUSED*/
150144961713Sgirish void
150244961713Sgirish nxge_txdma_fix_channel(p_nxge_t nxgep, uint16_t channel)
150344961713Sgirish {
150444961713Sgirish 	p_tx_ring_t	ring_p;
150544961713Sgirish 
150644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_channel"));
150744961713Sgirish 	ring_p = nxge_txdma_get_ring(nxgep, channel);
150844961713Sgirish 	if (ring_p == NULL) {
150944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel"));
151044961713Sgirish 		return;
151144961713Sgirish 	}
151244961713Sgirish 
151344961713Sgirish 	if (ring_p->tdc != channel) {
151444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
151552ccf843Smisaki 		    "<== nxge_txdma_fix_channel: channel not matched "
151652ccf843Smisaki 		    "ring tdc %d passed channel",
151752ccf843Smisaki 		    ring_p->tdc, channel));
151844961713Sgirish 		return;
151944961713Sgirish 	}
152044961713Sgirish 
152144961713Sgirish 	nxge_txdma_fixup_channel(nxgep, ring_p, channel);
152244961713Sgirish 
152344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel"));
152444961713Sgirish }
152544961713Sgirish 
152644961713Sgirish /*ARGSUSED*/
152744961713Sgirish void
152844961713Sgirish nxge_txdma_fixup_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel)
152944961713Sgirish {
153044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_channel"));
153144961713Sgirish 
153244961713Sgirish 	if (ring_p == NULL) {
153344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
153452ccf843Smisaki 		    "<== nxge_txdma_fixup_channel: NULL ring pointer"));
153544961713Sgirish 		return;
153644961713Sgirish 	}
153744961713Sgirish 
153844961713Sgirish 	if (ring_p->tdc != channel) {
153944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
154052ccf843Smisaki 		    "<== nxge_txdma_fixup_channel: channel not matched "
154152ccf843Smisaki 		    "ring tdc %d passed channel",
154252ccf843Smisaki 		    ring_p->tdc, channel));
154344961713Sgirish 		return;
154444961713Sgirish 	}
154544961713Sgirish 
154644961713Sgirish 	MUTEX_ENTER(&ring_p->lock);
154744961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, ring_p, 0);
154844961713Sgirish 	ring_p->rd_index = 0;
154944961713Sgirish 	ring_p->wr_index = 0;
155044961713Sgirish 	ring_p->ring_head.value = 0;
155144961713Sgirish 	ring_p->ring_kick_tail.value = 0;
155244961713Sgirish 	ring_p->descs_pending = 0;
155344961713Sgirish 	MUTEX_EXIT(&ring_p->lock);
155444961713Sgirish 
155544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_channel"));
155644961713Sgirish }
155744961713Sgirish 
155844961713Sgirish /*ARGSUSED*/
155944961713Sgirish void
156044961713Sgirish nxge_txdma_hw_kick(p_nxge_t nxgep)
156144961713Sgirish {
1562678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1563678453a8Sspeer 	int tdc;
156444961713Sgirish 
156544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick"));
156644961713Sgirish 
1567678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
156844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1569678453a8Sspeer 		    "<== nxge_txdma_hw_kick: NULL ring pointer(s)"));
157044961713Sgirish 		return;
157144961713Sgirish 	}
157244961713Sgirish 
1573678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1574678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1575678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1576678453a8Sspeer 			if (ring) {
1577678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1578678453a8Sspeer 				    "==> nxge_txdma_hw_kick: channel %d", tdc));
1579678453a8Sspeer 				nxge_txdma_hw_kick_channel(nxgep, ring, tdc);
1580678453a8Sspeer 			}
1581678453a8Sspeer 		}
158244961713Sgirish 	}
158344961713Sgirish 
158444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick"));
158544961713Sgirish }
158644961713Sgirish 
158744961713Sgirish /*ARGSUSED*/
158844961713Sgirish void
158944961713Sgirish nxge_txdma_kick_channel(p_nxge_t nxgep, uint16_t channel)
159044961713Sgirish {
159144961713Sgirish 	p_tx_ring_t	ring_p;
159244961713Sgirish 
159344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_kick_channel"));
159444961713Sgirish 
159544961713Sgirish 	ring_p = nxge_txdma_get_ring(nxgep, channel);
159644961713Sgirish 	if (ring_p == NULL) {
159744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
159852ccf843Smisaki 		    " nxge_txdma_kick_channel"));
159944961713Sgirish 		return;
160044961713Sgirish 	}
160144961713Sgirish 
160244961713Sgirish 	if (ring_p->tdc != channel) {
160344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
160452ccf843Smisaki 		    "<== nxge_txdma_kick_channel: channel not matched "
160552ccf843Smisaki 		    "ring tdc %d passed channel",
160652ccf843Smisaki 		    ring_p->tdc, channel));
160744961713Sgirish 		return;
160844961713Sgirish 	}
160944961713Sgirish 
161044961713Sgirish 	nxge_txdma_hw_kick_channel(nxgep, ring_p, channel);
161144961713Sgirish 
161244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_kick_channel"));
161344961713Sgirish }
1614a3c5bd6dSspeer 
161544961713Sgirish /*ARGSUSED*/
161644961713Sgirish void
161744961713Sgirish nxge_txdma_hw_kick_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel)
161844961713Sgirish {
161944961713Sgirish 
162044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick_channel"));
162144961713Sgirish 
162244961713Sgirish 	if (ring_p == NULL) {
162344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
162452ccf843Smisaki 		    "<== nxge_txdma_hw_kick_channel: NULL ring pointer"));
162544961713Sgirish 		return;
162644961713Sgirish 	}
162744961713Sgirish 
162844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick_channel"));
162944961713Sgirish }
163044961713Sgirish 
1631678453a8Sspeer /*
1632678453a8Sspeer  * nxge_check_tx_hang
1633678453a8Sspeer  *
1634678453a8Sspeer  *	Check the state of all TDCs belonging to nxgep.
1635678453a8Sspeer  *
1636678453a8Sspeer  * Arguments:
1637678453a8Sspeer  * 	nxgep
1638678453a8Sspeer  *
1639678453a8Sspeer  * Notes:
1640678453a8Sspeer  *	Called by nxge_hw.c:nxge_check_hw_state().
1641678453a8Sspeer  *
1642678453a8Sspeer  * NPI/NXGE function calls:
1643678453a8Sspeer  *
1644678453a8Sspeer  * Registers accessed:
1645678453a8Sspeer  *
1646678453a8Sspeer  * Context:
1647678453a8Sspeer  *	Any domain
1648678453a8Sspeer  */
164944961713Sgirish /*ARGSUSED*/
165044961713Sgirish void
165144961713Sgirish nxge_check_tx_hang(p_nxge_t nxgep)
165244961713Sgirish {
165344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_check_tx_hang"));
165444961713Sgirish 
165522c0d73aSspeer 	if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) ||
165622c0d73aSspeer 	    (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) {
165722c0d73aSspeer 		goto nxge_check_tx_hang_exit;
165822c0d73aSspeer 	}
165922c0d73aSspeer 
166044961713Sgirish 	/*
166144961713Sgirish 	 * Needs inputs from hardware for regs:
166244961713Sgirish 	 *	head index had not moved since last timeout.
166344961713Sgirish 	 *	packets not transmitted or stuffed registers.
166444961713Sgirish 	 */
166544961713Sgirish 	if (nxge_txdma_hung(nxgep)) {
166644961713Sgirish 		nxge_fixup_hung_txdma_rings(nxgep);
166744961713Sgirish 	}
166822c0d73aSspeer 
166922c0d73aSspeer nxge_check_tx_hang_exit:
167044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_check_tx_hang"));
167144961713Sgirish }
167244961713Sgirish 
1673678453a8Sspeer /*
1674678453a8Sspeer  * nxge_txdma_hung
1675678453a8Sspeer  *
1676678453a8Sspeer  *	Reset a TDC.
1677678453a8Sspeer  *
1678678453a8Sspeer  * Arguments:
1679678453a8Sspeer  * 	nxgep
1680678453a8Sspeer  * 	channel		The channel to reset.
1681678453a8Sspeer  * 	reg_data	The current TX_CS.
1682678453a8Sspeer  *
1683678453a8Sspeer  * Notes:
1684678453a8Sspeer  *	Called by nxge_check_tx_hang()
1685678453a8Sspeer  *
1686678453a8Sspeer  * NPI/NXGE function calls:
1687678453a8Sspeer  *	nxge_txdma_channel_hung()
1688678453a8Sspeer  *
1689678453a8Sspeer  * Registers accessed:
1690678453a8Sspeer  *
1691678453a8Sspeer  * Context:
1692678453a8Sspeer  *	Any domain
1693678453a8Sspeer  */
169444961713Sgirish int
169544961713Sgirish nxge_txdma_hung(p_nxge_t nxgep)
169644961713Sgirish {
1697330cd344SMichael Speer 	nxge_grp_set_t	*set = &nxgep->tx_set;
1698330cd344SMichael Speer 	int		tdc;
1699330cd344SMichael Speer 	boolean_t	shared;
170044961713Sgirish 
170144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hung"));
170244961713Sgirish 
1703678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
170444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1705678453a8Sspeer 		    "<== nxge_txdma_hung: NULL ring pointer(s)"));
170644961713Sgirish 		return (B_FALSE);
170744961713Sgirish 	}
170844961713Sgirish 
1709678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1710330cd344SMichael Speer 		/*
1711330cd344SMichael Speer 		 * Grab the shared state of the TDC.
1712330cd344SMichael Speer 		 */
1713330cd344SMichael Speer 		if (isLDOMservice(nxgep)) {
1714330cd344SMichael Speer 			nxge_hio_data_t *nhd =
1715330cd344SMichael Speer 			    (nxge_hio_data_t *)nxgep->nxge_hw_p->hio;
1716330cd344SMichael Speer 
1717330cd344SMichael Speer 			MUTEX_ENTER(&nhd->lock);
1718330cd344SMichael Speer 			shared = nxgep->tdc_is_shared[tdc];
1719330cd344SMichael Speer 			MUTEX_EXIT(&nhd->lock);
1720330cd344SMichael Speer 		} else {
1721330cd344SMichael Speer 			shared = B_FALSE;
1722330cd344SMichael Speer 		}
1723330cd344SMichael Speer 
1724330cd344SMichael Speer 		/*
1725330cd344SMichael Speer 		 * Now, process continue to process.
1726330cd344SMichael Speer 		 */
1727330cd344SMichael Speer 		if (((1 << tdc) & set->owned.map) && !shared) {
1728678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1729678453a8Sspeer 			if (ring) {
1730678453a8Sspeer 				if (nxge_txdma_channel_hung(nxgep, ring, tdc)) {
1731678453a8Sspeer 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
1732678453a8Sspeer 					    "==> nxge_txdma_hung: TDC %d hung",
1733678453a8Sspeer 					    tdc));
1734678453a8Sspeer 					return (B_TRUE);
1735678453a8Sspeer 				}
1736678453a8Sspeer 			}
173744961713Sgirish 		}
173844961713Sgirish 	}
173944961713Sgirish 
174044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hung"));
174144961713Sgirish 
174244961713Sgirish 	return (B_FALSE);
174344961713Sgirish }
174444961713Sgirish 
1745678453a8Sspeer /*
1746678453a8Sspeer  * nxge_txdma_channel_hung
1747678453a8Sspeer  *
1748678453a8Sspeer  *	Reset a TDC.
1749678453a8Sspeer  *
1750678453a8Sspeer  * Arguments:
1751678453a8Sspeer  * 	nxgep
1752678453a8Sspeer  * 	ring		<channel>'s ring.
1753678453a8Sspeer  * 	channel		The channel to reset.
1754678453a8Sspeer  *
1755678453a8Sspeer  * Notes:
1756678453a8Sspeer  *	Called by nxge_txdma.c:nxge_txdma_hung()
1757678453a8Sspeer  *
1758678453a8Sspeer  * NPI/NXGE function calls:
1759678453a8Sspeer  *	npi_txdma_ring_head_get()
1760678453a8Sspeer  *
1761678453a8Sspeer  * Registers accessed:
1762678453a8Sspeer  *	TX_RING_HDL	DMC+0x40010 Transmit Ring Head Low
1763678453a8Sspeer  *
1764678453a8Sspeer  * Context:
1765678453a8Sspeer  *	Any domain
1766678453a8Sspeer  */
176744961713Sgirish int
176844961713Sgirish nxge_txdma_channel_hung(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, uint16_t channel)
176944961713Sgirish {
177044961713Sgirish 	uint16_t		head_index, tail_index;
177144961713Sgirish 	boolean_t		head_wrap, tail_wrap;
177244961713Sgirish 	npi_handle_t		handle;
177344961713Sgirish 	tx_ring_hdl_t		tx_head;
177444961713Sgirish 	uint_t			tx_rd_index;
177544961713Sgirish 
177644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_channel_hung"));
177744961713Sgirish 
177844961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
177944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
178052ccf843Smisaki 	    "==> nxge_txdma_channel_hung: channel %d", channel));
178144961713Sgirish 	MUTEX_ENTER(&tx_ring_p->lock);
178244961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
178344961713Sgirish 
178444961713Sgirish 	tail_index = tx_ring_p->wr_index;
178544961713Sgirish 	tail_wrap = tx_ring_p->wr_index_wrap;
178644961713Sgirish 	tx_rd_index = tx_ring_p->rd_index;
178744961713Sgirish 	MUTEX_EXIT(&tx_ring_p->lock);
178844961713Sgirish 
178944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
179052ccf843Smisaki 	    "==> nxge_txdma_channel_hung: tdc %d tx_rd_index %d "
179152ccf843Smisaki 	    "tail_index %d tail_wrap %d ",
179252ccf843Smisaki 	    channel, tx_rd_index, tail_index, tail_wrap));
179344961713Sgirish 	/*
179444961713Sgirish 	 * Read the hardware maintained transmit head
179544961713Sgirish 	 * and wrap around bit.
179644961713Sgirish 	 */
179744961713Sgirish 	(void) npi_txdma_ring_head_get(handle, channel, &tx_head);
179844961713Sgirish 	head_index =  tx_head.bits.ldw.head;
179944961713Sgirish 	head_wrap = tx_head.bits.ldw.wrap;
180044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
180152ccf843Smisaki 	    "==> nxge_txdma_channel_hung: "
180252ccf843Smisaki 	    "tx_rd_index %d tail %d tail_wrap %d "
180352ccf843Smisaki 	    "head %d wrap %d",
180452ccf843Smisaki 	    tx_rd_index, tail_index, tail_wrap,
180552ccf843Smisaki 	    head_index, head_wrap));
180644961713Sgirish 
180744961713Sgirish 	if (TXDMA_RING_EMPTY(head_index, head_wrap,
180852ccf843Smisaki 	    tail_index, tail_wrap) &&
180952ccf843Smisaki 	    (head_index == tx_rd_index)) {
181044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
181152ccf843Smisaki 		    "==> nxge_txdma_channel_hung: EMPTY"));
181244961713Sgirish 		return (B_FALSE);
181344961713Sgirish 	}
181444961713Sgirish 
181544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
181652ccf843Smisaki 	    "==> nxge_txdma_channel_hung: Checking if ring full"));
181744961713Sgirish 	if (TXDMA_RING_FULL(head_index, head_wrap, tail_index,
181852ccf843Smisaki 	    tail_wrap)) {
181944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
182052ccf843Smisaki 		    "==> nxge_txdma_channel_hung: full"));
182144961713Sgirish 		return (B_TRUE);
182244961713Sgirish 	}
182344961713Sgirish 
182444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_channel_hung"));
182544961713Sgirish 
182644961713Sgirish 	return (B_FALSE);
182744961713Sgirish }
182844961713Sgirish 
1829678453a8Sspeer /*
1830678453a8Sspeer  * nxge_fixup_hung_txdma_rings
1831678453a8Sspeer  *
1832678453a8Sspeer  *	Disable a TDC.
1833678453a8Sspeer  *
1834678453a8Sspeer  * Arguments:
1835678453a8Sspeer  * 	nxgep
1836678453a8Sspeer  * 	channel		The channel to reset.
1837678453a8Sspeer  * 	reg_data	The current TX_CS.
1838678453a8Sspeer  *
1839678453a8Sspeer  * Notes:
1840678453a8Sspeer  *	Called by nxge_check_tx_hang()
1841678453a8Sspeer  *
1842678453a8Sspeer  * NPI/NXGE function calls:
1843678453a8Sspeer  *	npi_txdma_ring_head_get()
1844678453a8Sspeer  *
1845678453a8Sspeer  * Registers accessed:
1846678453a8Sspeer  *	TX_RING_HDL	DMC+0x40010 Transmit Ring Head Low
1847678453a8Sspeer  *
1848678453a8Sspeer  * Context:
1849678453a8Sspeer  *	Any domain
1850678453a8Sspeer  */
185144961713Sgirish /*ARGSUSED*/
185244961713Sgirish void
185344961713Sgirish nxge_fixup_hung_txdma_rings(p_nxge_t nxgep)
185444961713Sgirish {
1855678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1856678453a8Sspeer 	int tdc;
185744961713Sgirish 
185844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_hung_txdma_rings"));
185944961713Sgirish 
1860678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
186144961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1862678453a8Sspeer 		    "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
186344961713Sgirish 		return;
186444961713Sgirish 	}
186544961713Sgirish 
1866678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1867678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1868678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1869678453a8Sspeer 			if (ring) {
1870678453a8Sspeer 				nxge_txdma_fixup_hung_channel(nxgep, ring, tdc);
1871678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
1872678453a8Sspeer 				    "==> nxge_fixup_hung_txdma_rings: TDC %d",
1873678453a8Sspeer 				    tdc));
1874678453a8Sspeer 			}
1875678453a8Sspeer 		}
187644961713Sgirish 	}
187744961713Sgirish 
187844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_hung_txdma_rings"));
187944961713Sgirish }
188044961713Sgirish 
1881678453a8Sspeer /*
1882678453a8Sspeer  * nxge_txdma_fixup_hung_channel
1883678453a8Sspeer  *
1884678453a8Sspeer  *	'Fix' a hung TDC.
1885678453a8Sspeer  *
1886678453a8Sspeer  * Arguments:
1887678453a8Sspeer  * 	nxgep
1888678453a8Sspeer  * 	channel		The channel to fix.
1889678453a8Sspeer  *
1890678453a8Sspeer  * Notes:
1891678453a8Sspeer  *	Called by nxge_fixup_hung_txdma_rings()
1892678453a8Sspeer  *
1893678453a8Sspeer  *	1. Reclaim the TDC.
1894678453a8Sspeer  *	2. Disable the TDC.
1895678453a8Sspeer  *
1896678453a8Sspeer  * NPI/NXGE function calls:
1897678453a8Sspeer  *	nxge_txdma_reclaim()
1898678453a8Sspeer  *	npi_txdma_channel_disable(TX_CS)
1899678453a8Sspeer  *	npi_txdma_inj_int_error_set(TDMC_INTR_DBG)
1900678453a8Sspeer  *
1901678453a8Sspeer  * Registers accessed:
1902678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1903678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
1904678453a8Sspeer  *
1905678453a8Sspeer  * Context:
1906678453a8Sspeer  *	Any domain
1907678453a8Sspeer  */
190844961713Sgirish /*ARGSUSED*/
190944961713Sgirish void
191044961713Sgirish nxge_txdma_fix_hung_channel(p_nxge_t nxgep, uint16_t channel)
191144961713Sgirish {
191244961713Sgirish 	p_tx_ring_t	ring_p;
191344961713Sgirish 
191444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_hung_channel"));
191544961713Sgirish 	ring_p = nxge_txdma_get_ring(nxgep, channel);
191644961713Sgirish 	if (ring_p == NULL) {
191744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
191852ccf843Smisaki 		    "<== nxge_txdma_fix_hung_channel"));
191944961713Sgirish 		return;
192044961713Sgirish 	}
192144961713Sgirish 
192244961713Sgirish 	if (ring_p->tdc != channel) {
192344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
192452ccf843Smisaki 		    "<== nxge_txdma_fix_hung_channel: channel not matched "
192552ccf843Smisaki 		    "ring tdc %d passed channel",
192652ccf843Smisaki 		    ring_p->tdc, channel));
192744961713Sgirish 		return;
192844961713Sgirish 	}
192944961713Sgirish 
193044961713Sgirish 	nxge_txdma_fixup_channel(nxgep, ring_p, channel);
193144961713Sgirish 
193244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_hung_channel"));
193344961713Sgirish }
193444961713Sgirish 
193544961713Sgirish /*ARGSUSED*/
193644961713Sgirish void
193744961713Sgirish nxge_txdma_fixup_hung_channel(p_nxge_t nxgep, p_tx_ring_t ring_p,
193844961713Sgirish 	uint16_t channel)
193944961713Sgirish {
194044961713Sgirish 	npi_handle_t		handle;
194144961713Sgirish 	tdmc_intr_dbg_t		intr_dbg;
194244961713Sgirish 	int			status = NXGE_OK;
194344961713Sgirish 
194444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_hung_channel"));
194544961713Sgirish 
194644961713Sgirish 	if (ring_p == NULL) {
194744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
194852ccf843Smisaki 		    "<== nxge_txdma_fixup_channel: NULL ring pointer"));
194944961713Sgirish 		return;
195044961713Sgirish 	}
195144961713Sgirish 
195244961713Sgirish 	if (ring_p->tdc != channel) {
195344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
195452ccf843Smisaki 		    "<== nxge_txdma_fixup_hung_channel: channel "
195552ccf843Smisaki 		    "not matched "
195652ccf843Smisaki 		    "ring tdc %d passed channel",
195752ccf843Smisaki 		    ring_p->tdc, channel));
195844961713Sgirish 		return;
195944961713Sgirish 	}
196044961713Sgirish 
196144961713Sgirish 	/* Reclaim descriptors */
196244961713Sgirish 	MUTEX_ENTER(&ring_p->lock);
196344961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, ring_p, 0);
196444961713Sgirish 	MUTEX_EXIT(&ring_p->lock);
196544961713Sgirish 
196644961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
196744961713Sgirish 	/*
196844961713Sgirish 	 * Stop the dma channel waits for the stop done.
196944961713Sgirish 	 * If the stop done bit is not set, then force
197044961713Sgirish 	 * an error.
197144961713Sgirish 	 */
197244961713Sgirish 	status = npi_txdma_channel_disable(handle, channel);
197344961713Sgirish 	if (!(status & NPI_TXDMA_STOP_FAILED)) {
197444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
197552ccf843Smisaki 		    "<== nxge_txdma_fixup_hung_channel: stopped OK "
197652ccf843Smisaki 		    "ring tdc %d passed channel %d",
197752ccf843Smisaki 		    ring_p->tdc, channel));
197844961713Sgirish 		return;
197944961713Sgirish 	}
198044961713Sgirish 
198144961713Sgirish 	/* Inject any error */
198244961713Sgirish 	intr_dbg.value = 0;
198344961713Sgirish 	intr_dbg.bits.ldw.nack_pref = 1;
198444961713Sgirish 	(void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg);
198544961713Sgirish 
198644961713Sgirish 	/* Stop done bit will be set as a result of error injection */
198744961713Sgirish 	status = npi_txdma_channel_disable(handle, channel);
198844961713Sgirish 	if (!(status & NPI_TXDMA_STOP_FAILED)) {
198944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
199052ccf843Smisaki 		    "<== nxge_txdma_fixup_hung_channel: stopped again"
199152ccf843Smisaki 		    "ring tdc %d passed channel",
199252ccf843Smisaki 		    ring_p->tdc, channel));
199344961713Sgirish 		return;
199444961713Sgirish 	}
199544961713Sgirish 
199644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
199752ccf843Smisaki 	    "<== nxge_txdma_fixup_hung_channel: stop done still not set!! "
199852ccf843Smisaki 	    "ring tdc %d passed channel",
199952ccf843Smisaki 	    ring_p->tdc, channel));
200044961713Sgirish 
200144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_hung_channel"));
200244961713Sgirish }
200344961713Sgirish 
200444961713Sgirish /*ARGSUSED*/
200544961713Sgirish void
200644961713Sgirish nxge_reclaim_rings(p_nxge_t nxgep)
200744961713Sgirish {
2008678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
2009678453a8Sspeer 	int tdc;
201044961713Sgirish 
2011678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_reclaim_rings"));
201244961713Sgirish 
2013678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
201444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
2015678453a8Sspeer 		    "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
201644961713Sgirish 		return;
201744961713Sgirish 	}
201844961713Sgirish 
2019678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
2020678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
2021678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
2022678453a8Sspeer 			if (ring) {
2023678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
2024678453a8Sspeer 				    "==> nxge_reclaim_rings: TDC %d", tdc));
2025678453a8Sspeer 				MUTEX_ENTER(&ring->lock);
2026da14cebeSEric Cheng 				(void) nxge_txdma_reclaim(nxgep, ring, 0);
2027678453a8Sspeer 				MUTEX_EXIT(&ring->lock);
2028678453a8Sspeer 			}
2029678453a8Sspeer 		}
203044961713Sgirish 	}
203144961713Sgirish 
203244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_reclaim_rings"));
203344961713Sgirish }
203444961713Sgirish 
203544961713Sgirish void
203644961713Sgirish nxge_txdma_regs_dump_channels(p_nxge_t nxgep)
203744961713Sgirish {
2038678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
2039678453a8Sspeer 	npi_handle_t handle;
2040678453a8Sspeer 	int tdc;
204144961713Sgirish 
2042678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_regs_dump_channels"));
204344961713Sgirish 
204444961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
204544961713Sgirish 
2046678453a8Sspeer 	if (!isLDOMguest(nxgep)) {
2047678453a8Sspeer 		(void) npi_txdma_dump_fzc_regs(handle);
204844961713Sgirish 
2049678453a8Sspeer 		/* Dump TXC registers. */
2050678453a8Sspeer 		(void) npi_txc_dump_fzc_regs(handle);
2051678453a8Sspeer 		(void) npi_txc_dump_port_fzc_regs(handle, nxgep->function_num);
205244961713Sgirish 	}
205344961713Sgirish 
2054678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
205544961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
2056678453a8Sspeer 		    "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
205744961713Sgirish 		return;
205844961713Sgirish 	}
205944961713Sgirish 
2060678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
2061678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
2062678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
2063678453a8Sspeer 			if (ring) {
2064678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
2065678453a8Sspeer 				    "==> nxge_txdma_regs_dump_channels: "
2066678453a8Sspeer 				    "TDC %d", tdc));
2067678453a8Sspeer 				(void) npi_txdma_dump_tdc_regs(handle, tdc);
2068678453a8Sspeer 
2069678453a8Sspeer 				/* Dump TXC registers, if able to. */
2070678453a8Sspeer 				if (!isLDOMguest(nxgep)) {
2071678453a8Sspeer 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
2072678453a8Sspeer 					    "==> nxge_txdma_regs_dump_channels:"
2073678453a8Sspeer 					    " FZC TDC %d", tdc));
2074678453a8Sspeer 					(void) npi_txc_dump_tdc_fzc_regs
2075678453a8Sspeer 					    (handle, tdc);
2076678453a8Sspeer 				}
2077678453a8Sspeer 				nxge_txdma_regs_dump(nxgep, tdc);
2078678453a8Sspeer 			}
2079678453a8Sspeer 		}
208044961713Sgirish 	}
208144961713Sgirish 
208244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_regs_dump"));
208344961713Sgirish }
208444961713Sgirish 
208544961713Sgirish void
208644961713Sgirish nxge_txdma_regs_dump(p_nxge_t nxgep, int channel)
208744961713Sgirish {
208844961713Sgirish 	npi_handle_t		handle;
208944961713Sgirish 	tx_ring_hdl_t 		hdl;
209044961713Sgirish 	tx_ring_kick_t 		kick;
209144961713Sgirish 	tx_cs_t 		cs;
209244961713Sgirish 	txc_control_t		control;
209344961713Sgirish 	uint32_t		bitmap = 0;
209444961713Sgirish 	uint32_t		burst = 0;
209544961713Sgirish 	uint32_t		bytes = 0;
209644961713Sgirish 	dma_log_page_t		cfg;
209744961713Sgirish 
209844961713Sgirish 	printf("\n\tfunc # %d tdc %d ",
209952ccf843Smisaki 	    nxgep->function_num, channel);
210044961713Sgirish 	cfg.page_num = 0;
210144961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
210244961713Sgirish 	(void) npi_txdma_log_page_get(handle, channel, &cfg);
210344961713Sgirish 	printf("\n\tlog page func %d valid page 0 %d",
210452ccf843Smisaki 	    cfg.func_num, cfg.valid);
210544961713Sgirish 	cfg.page_num = 1;
210644961713Sgirish 	(void) npi_txdma_log_page_get(handle, channel, &cfg);
210744961713Sgirish 	printf("\n\tlog page func %d valid page 1 %d",
210852ccf843Smisaki 	    cfg.func_num, cfg.valid);
210944961713Sgirish 
211044961713Sgirish 	(void) npi_txdma_ring_head_get(handle, channel, &hdl);
211144961713Sgirish 	(void) npi_txdma_desc_kick_reg_get(handle, channel, &kick);
211244961713Sgirish 	printf("\n\thead value is 0x%0llx",
211352ccf843Smisaki 	    (long long)hdl.value);
211444961713Sgirish 	printf("\n\thead index %d", hdl.bits.ldw.head);
211544961713Sgirish 	printf("\n\tkick value is 0x%0llx",
211652ccf843Smisaki 	    (long long)kick.value);
211744961713Sgirish 	printf("\n\ttail index %d\n", kick.bits.ldw.tail);
211844961713Sgirish 
211944961713Sgirish 	(void) npi_txdma_control_status(handle, OP_GET, channel, &cs);
212044961713Sgirish 	printf("\n\tControl statue is 0x%0llx", (long long)cs.value);
212144961713Sgirish 	printf("\n\tControl status RST state %d", cs.bits.ldw.rst);
212244961713Sgirish 
212344961713Sgirish 	(void) npi_txc_control(handle, OP_GET, &control);
212444961713Sgirish 	(void) npi_txc_port_dma_list_get(handle, nxgep->function_num, &bitmap);
212544961713Sgirish 	(void) npi_txc_dma_max_burst(handle, OP_GET, channel, &burst);
212644961713Sgirish 	(void) npi_txc_dma_bytes_transmitted(handle, channel, &bytes);
212744961713Sgirish 
212844961713Sgirish 	printf("\n\tTXC port control 0x%0llx",
212952ccf843Smisaki 	    (long long)control.value);
213044961713Sgirish 	printf("\n\tTXC port bitmap 0x%x", bitmap);
213144961713Sgirish 	printf("\n\tTXC max burst %d", burst);
213244961713Sgirish 	printf("\n\tTXC bytes xmt %d\n", bytes);
213344961713Sgirish 
213444961713Sgirish 	{
213544961713Sgirish 		ipp_status_t status;
213644961713Sgirish 
213744961713Sgirish 		(void) npi_ipp_get_status(handle, nxgep->function_num, &status);
2138adfcba55Sjoycey #if defined(__i386)
2139adfcba55Sjoycey 		printf("\n\tIPP status 0x%llux\n", (uint64_t)status.value);
2140adfcba55Sjoycey #else
214144961713Sgirish 		printf("\n\tIPP status 0x%lux\n", (uint64_t)status.value);
2142adfcba55Sjoycey #endif
214344961713Sgirish 	}
214444961713Sgirish }
214544961713Sgirish 
214644961713Sgirish /*
2147678453a8Sspeer  * nxge_tdc_hvio_setup
2148678453a8Sspeer  *
2149678453a8Sspeer  *	I'm not exactly sure what this code does.
2150678453a8Sspeer  *
2151678453a8Sspeer  * Arguments:
2152678453a8Sspeer  * 	nxgep
2153678453a8Sspeer  * 	channel	The channel to map.
2154678453a8Sspeer  *
2155678453a8Sspeer  * Notes:
2156678453a8Sspeer  *
2157678453a8Sspeer  * NPI/NXGE function calls:
2158678453a8Sspeer  *	na
2159678453a8Sspeer  *
2160678453a8Sspeer  * Context:
2161678453a8Sspeer  *	Service domain?
216244961713Sgirish  */
2163678453a8Sspeer #if defined(sun4v) && defined(NIU_LP_WORKAROUND)
2164678453a8Sspeer static void
2165678453a8Sspeer nxge_tdc_hvio_setup(
2166678453a8Sspeer 	nxge_t *nxgep, int channel)
216744961713Sgirish {
2168678453a8Sspeer 	nxge_dma_common_t	*data;
2169678453a8Sspeer 	nxge_dma_common_t	*control;
2170678453a8Sspeer 	tx_ring_t 		*ring;
2171678453a8Sspeer 
2172678453a8Sspeer 	ring = nxgep->tx_rings->rings[channel];
2173678453a8Sspeer 	data = nxgep->tx_buf_pool_p->dma_buf_pool_p[channel];
2174678453a8Sspeer 
2175678453a8Sspeer 	ring->hv_set = B_FALSE;
2176678453a8Sspeer 
2177678453a8Sspeer 	ring->hv_tx_buf_base_ioaddr_pp =
2178678453a8Sspeer 	    (uint64_t)data->orig_ioaddr_pp;
2179678453a8Sspeer 	ring->hv_tx_buf_ioaddr_size =
2180678453a8Sspeer 	    (uint64_t)data->orig_alength;
2181678453a8Sspeer 
2182678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: "
218352ccf843Smisaki 	    "hv data buf base io $%p size 0x%llx (%d) buf base io $%p "
218452ccf843Smisaki 	    "orig vatopa base io $%p orig_len 0x%llx (%d)",
218552ccf843Smisaki 	    ring->hv_tx_buf_base_ioaddr_pp,
218652ccf843Smisaki 	    ring->hv_tx_buf_ioaddr_size, ring->hv_tx_buf_ioaddr_size,
218752ccf843Smisaki 	    data->ioaddr_pp, data->orig_vatopa,
218852ccf843Smisaki 	    data->orig_alength, data->orig_alength));
2189678453a8Sspeer 
2190678453a8Sspeer 	control = nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel];
2191678453a8Sspeer 
2192678453a8Sspeer 	ring->hv_tx_cntl_base_ioaddr_pp =
2193678453a8Sspeer 	    (uint64_t)control->orig_ioaddr_pp;
2194678453a8Sspeer 	ring->hv_tx_cntl_ioaddr_size =
2195678453a8Sspeer 	    (uint64_t)control->orig_alength;
2196678453a8Sspeer 
2197678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: "
219852ccf843Smisaki 	    "hv cntl base io $%p orig ioaddr_pp ($%p) "
219952ccf843Smisaki 	    "orig vatopa ($%p) size 0x%llx (%d 0x%x)",
220052ccf843Smisaki 	    ring->hv_tx_cntl_base_ioaddr_pp,
220152ccf843Smisaki 	    control->orig_ioaddr_pp, control->orig_vatopa,
220252ccf843Smisaki 	    ring->hv_tx_cntl_ioaddr_size,
220352ccf843Smisaki 	    control->orig_alength, control->orig_alength));
2204678453a8Sspeer }
220544961713Sgirish #endif
220644961713Sgirish 
2207678453a8Sspeer static nxge_status_t
2208678453a8Sspeer nxge_map_txdma(p_nxge_t nxgep, int channel)
2209678453a8Sspeer {
2210678453a8Sspeer 	nxge_dma_common_t	**pData;
2211678453a8Sspeer 	nxge_dma_common_t	**pControl;
2212678453a8Sspeer 	tx_ring_t 		**pRing, *ring;
2213678453a8Sspeer 	tx_mbox_t		**mailbox;
2214678453a8Sspeer 	uint32_t		num_chunks;
2215678453a8Sspeer 
2216678453a8Sspeer 	nxge_status_t		status = NXGE_OK;
221744961713Sgirish 
2218678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma"));
221944961713Sgirish 
2220678453a8Sspeer 	if (!nxgep->tx_cntl_pool_p->buf_allocated) {
2221678453a8Sspeer 		if (nxge_alloc_tx_mem_pool(nxgep) != NXGE_OK) {
2222678453a8Sspeer 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2223678453a8Sspeer 			    "<== nxge_map_txdma: buf not allocated"));
2224678453a8Sspeer 			return (NXGE_ERROR);
2225678453a8Sspeer 		}
222644961713Sgirish 	}
222744961713Sgirish 
2228678453a8Sspeer 	if (nxge_alloc_txb(nxgep, channel) != NXGE_OK)
222944961713Sgirish 		return (NXGE_ERROR);
223044961713Sgirish 
2231678453a8Sspeer 	num_chunks = nxgep->tx_buf_pool_p->num_chunks[channel];
2232678453a8Sspeer 	pData = &nxgep->tx_buf_pool_p->dma_buf_pool_p[channel];
2233678453a8Sspeer 	pControl = &nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel];
2234678453a8Sspeer 	pRing = &nxgep->tx_rings->rings[channel];
2235678453a8Sspeer 	mailbox = &nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
223644961713Sgirish 
2237678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: "
223852ccf843Smisaki 	    "tx_rings $%p tx_desc_rings $%p",
223952ccf843Smisaki 	    nxgep->tx_rings, nxgep->tx_rings->rings));
224044961713Sgirish 
224144961713Sgirish 	/*
2242678453a8Sspeer 	 * Map descriptors from the buffer pools for <channel>.
224344961713Sgirish 	 */
224444961713Sgirish 
2245678453a8Sspeer 	/*
2246678453a8Sspeer 	 * Set up and prepare buffer blocks, descriptors
2247678453a8Sspeer 	 * and mailbox.
2248678453a8Sspeer 	 */
2249678453a8Sspeer 	status = nxge_map_txdma_channel(nxgep, channel,
2250678453a8Sspeer 	    pData, pRing, num_chunks, pControl, mailbox);
2251678453a8Sspeer 	if (status != NXGE_OK) {
2252678453a8Sspeer 		NXGE_ERROR_MSG((nxgep, MEM3_CTL,
225352ccf843Smisaki 		    "==> nxge_map_txdma(%d): nxge_map_txdma_channel() "
225452ccf843Smisaki 		    "returned 0x%x",
225552ccf843Smisaki 		    nxgep, channel, status));
2256678453a8Sspeer 		return (status);
225744961713Sgirish 	}
225844961713Sgirish 
2259678453a8Sspeer 	ring = *pRing;
226044961713Sgirish 
2261678453a8Sspeer 	ring->index = (uint16_t)channel;
2262678453a8Sspeer 	ring->tdc_stats = &nxgep->statsp->tdc_stats[channel];
226344961713Sgirish 
2264678453a8Sspeer #if defined(sun4v) && defined(NIU_LP_WORKAROUND)
2265678453a8Sspeer 	if (isLDOMguest(nxgep)) {
2266678453a8Sspeer 		(void) nxge_tdc_lp_conf(nxgep, channel);
2267678453a8Sspeer 	} else {
2268678453a8Sspeer 		nxge_tdc_hvio_setup(nxgep, channel);
226944961713Sgirish 	}
2270678453a8Sspeer #endif
227144961713Sgirish 
2272678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: "
2273678453a8Sspeer 	    "(status 0x%x channel %d)", status, channel));
227444961713Sgirish 
2275678453a8Sspeer 	return (status);
227644961713Sgirish }
227744961713Sgirish 
227844961713Sgirish static nxge_status_t
227944961713Sgirish nxge_map_txdma_channel(p_nxge_t nxgep, uint16_t channel,
228044961713Sgirish 	p_nxge_dma_common_t *dma_buf_p,
228144961713Sgirish 	p_tx_ring_t *tx_desc_p,
228244961713Sgirish 	uint32_t num_chunks,
228344961713Sgirish 	p_nxge_dma_common_t *dma_cntl_p,
228444961713Sgirish 	p_tx_mbox_t *tx_mbox_p)
228544961713Sgirish {
228644961713Sgirish 	int	status = NXGE_OK;
228744961713Sgirish 
228844961713Sgirish 	/*
228944961713Sgirish 	 * Set up and prepare buffer blocks, descriptors
229044961713Sgirish 	 * and mailbox.
229144961713Sgirish 	 */
2292678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL,
229352ccf843Smisaki 	    "==> nxge_map_txdma_channel (channel %d)", channel));
229444961713Sgirish 	/*
229544961713Sgirish 	 * Transmit buffer blocks
229644961713Sgirish 	 */
229744961713Sgirish 	status = nxge_map_txdma_channel_buf_ring(nxgep, channel,
229852ccf843Smisaki 	    dma_buf_p, tx_desc_p, num_chunks);
229944961713Sgirish 	if (status != NXGE_OK) {
230044961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
230152ccf843Smisaki 		    "==> nxge_map_txdma_channel (channel %d): "
230252ccf843Smisaki 		    "map buffer failed 0x%x", channel, status));
230344961713Sgirish 		goto nxge_map_txdma_channel_exit;
230444961713Sgirish 	}
230544961713Sgirish 
230644961713Sgirish 	/*
230744961713Sgirish 	 * Transmit block ring, and mailbox.
230844961713Sgirish 	 */
230944961713Sgirish 	nxge_map_txdma_channel_cfg_ring(nxgep, channel, dma_cntl_p, *tx_desc_p,
231052ccf843Smisaki 	    tx_mbox_p);
231144961713Sgirish 
231244961713Sgirish 	goto nxge_map_txdma_channel_exit;
231344961713Sgirish 
231444961713Sgirish nxge_map_txdma_channel_fail1:
2315678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL,
231652ccf843Smisaki 	    "==> nxge_map_txdma_channel: unmap buf"
231752ccf843Smisaki 	    "(status 0x%x channel %d)",
231852ccf843Smisaki 	    status, channel));
231944961713Sgirish 	nxge_unmap_txdma_channel_buf_ring(nxgep, *tx_desc_p);
232044961713Sgirish 
232144961713Sgirish nxge_map_txdma_channel_exit:
2322678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL,
232352ccf843Smisaki 	    "<== nxge_map_txdma_channel: "
232452ccf843Smisaki 	    "(status 0x%x channel %d)",
232552ccf843Smisaki 	    status, channel));
232644961713Sgirish 
232744961713Sgirish 	return (status);
232844961713Sgirish }
232944961713Sgirish 
233044961713Sgirish /*ARGSUSED*/
233144961713Sgirish static void
2332678453a8Sspeer nxge_unmap_txdma_channel(p_nxge_t nxgep, uint16_t channel)
233344961713Sgirish {
2334678453a8Sspeer 	tx_ring_t *ring;
2335678453a8Sspeer 	tx_mbox_t *mailbox;
2336678453a8Sspeer 
233744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
233852ccf843Smisaki 	    "==> nxge_unmap_txdma_channel (channel %d)", channel));
233944961713Sgirish 	/*
234044961713Sgirish 	 * unmap tx block ring, and mailbox.
234144961713Sgirish 	 */
2342678453a8Sspeer 	ring = nxgep->tx_rings->rings[channel];
2343678453a8Sspeer 	mailbox = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
2344678453a8Sspeer 
2345678453a8Sspeer 	(void) nxge_unmap_txdma_channel_cfg_ring(nxgep, ring, mailbox);
234644961713Sgirish 
234744961713Sgirish 	/* unmap buffer blocks */
2348678453a8Sspeer 	(void) nxge_unmap_txdma_channel_buf_ring(nxgep, ring);
2349678453a8Sspeer 
2350678453a8Sspeer 	nxge_free_txb(nxgep, channel);
235144961713Sgirish 
2352*48056c53SMichael Speer 	/*
2353*48056c53SMichael Speer 	 * Cleanup the reference to the ring now that it does not exist.
2354*48056c53SMichael Speer 	 */
2355*48056c53SMichael Speer 	nxgep->tx_rings->rings[channel] = NULL;
2356*48056c53SMichael Speer 
235744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_unmap_txdma_channel"));
235844961713Sgirish }
235944961713Sgirish 
2360678453a8Sspeer /*
2361678453a8Sspeer  * nxge_map_txdma_channel_cfg_ring
2362678453a8Sspeer  *
2363678453a8Sspeer  *	Map a TDC into our kernel space.
2364678453a8Sspeer  *	This function allocates all of the per-channel data structures.
2365678453a8Sspeer  *
2366678453a8Sspeer  * Arguments:
2367678453a8Sspeer  * 	nxgep
2368678453a8Sspeer  * 	dma_channel	The channel to map.
2369678453a8Sspeer  *	dma_cntl_p
2370678453a8Sspeer  *	tx_ring_p	dma_channel's transmit ring
2371678453a8Sspeer  *	tx_mbox_p	dma_channel's mailbox
2372678453a8Sspeer  *
2373678453a8Sspeer  * Notes:
2374678453a8Sspeer  *
2375678453a8Sspeer  * NPI/NXGE function calls:
2376678453a8Sspeer  *	nxge_setup_dma_common()
2377678453a8Sspeer  *
2378678453a8Sspeer  * Registers accessed:
2379678453a8Sspeer  *	none.
2380678453a8Sspeer  *
2381678453a8Sspeer  * Context:
2382678453a8Sspeer  *	Any domain
2383678453a8Sspeer  */
238444961713Sgirish /*ARGSUSED*/
238544961713Sgirish static void
238644961713Sgirish nxge_map_txdma_channel_cfg_ring(p_nxge_t nxgep, uint16_t dma_channel,
238744961713Sgirish 	p_nxge_dma_common_t *dma_cntl_p,
238844961713Sgirish 	p_tx_ring_t tx_ring_p,
238944961713Sgirish 	p_tx_mbox_t *tx_mbox_p)
239044961713Sgirish {
239144961713Sgirish 	p_tx_mbox_t 		mboxp;
239244961713Sgirish 	p_nxge_dma_common_t 	cntl_dmap;
239344961713Sgirish 	p_nxge_dma_common_t 	dmap;
239444961713Sgirish 	p_tx_rng_cfig_t		tx_ring_cfig_p;
239544961713Sgirish 	p_tx_ring_kick_t	tx_ring_kick_p;
239644961713Sgirish 	p_tx_cs_t		tx_cs_p;
239744961713Sgirish 	p_tx_dma_ent_msk_t	tx_evmask_p;
239844961713Sgirish 	p_txdma_mbh_t		mboxh_p;
239944961713Sgirish 	p_txdma_mbl_t		mboxl_p;
240044961713Sgirish 	uint64_t		tx_desc_len;
240144961713Sgirish 
240244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
240352ccf843Smisaki 	    "==> nxge_map_txdma_channel_cfg_ring"));
240444961713Sgirish 
240544961713Sgirish 	cntl_dmap = *dma_cntl_p;
240644961713Sgirish 
240744961713Sgirish 	dmap = (p_nxge_dma_common_t)&tx_ring_p->tdc_desc;
240844961713Sgirish 	nxge_setup_dma_common(dmap, cntl_dmap, tx_ring_p->tx_ring_size,
240952ccf843Smisaki 	    sizeof (tx_desc_t));
241044961713Sgirish 	/*
241144961713Sgirish 	 * Zero out transmit ring descriptors.
241244961713Sgirish 	 */
241344961713Sgirish 	bzero((caddr_t)dmap->kaddrp, dmap->alength);
241444961713Sgirish 	tx_ring_cfig_p = &(tx_ring_p->tx_ring_cfig);
241544961713Sgirish 	tx_ring_kick_p = &(tx_ring_p->tx_ring_kick);
241644961713Sgirish 	tx_cs_p = &(tx_ring_p->tx_cs);
241744961713Sgirish 	tx_evmask_p = &(tx_ring_p->tx_evmask);
241844961713Sgirish 	tx_ring_cfig_p->value = 0;
241944961713Sgirish 	tx_ring_kick_p->value = 0;
242044961713Sgirish 	tx_cs_p->value = 0;
242144961713Sgirish 	tx_evmask_p->value = 0;
242244961713Sgirish 
242344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
242452ccf843Smisaki 	    "==> nxge_map_txdma_channel_cfg_ring: channel %d des $%p",
242552ccf843Smisaki 	    dma_channel,
242652ccf843Smisaki 	    dmap->dma_cookie.dmac_laddress));
242744961713Sgirish 
242844961713Sgirish 	tx_ring_cfig_p->value = 0;
242944961713Sgirish 	tx_desc_len = (uint64_t)(tx_ring_p->tx_ring_size >> 3);
243044961713Sgirish 	tx_ring_cfig_p->value =
243152ccf843Smisaki 	    (dmap->dma_cookie.dmac_laddress & TX_RNG_CFIG_ADDR_MASK) |
243252ccf843Smisaki 	    (tx_desc_len << TX_RNG_CFIG_LEN_SHIFT);
243344961713Sgirish 
243444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
243552ccf843Smisaki 	    "==> nxge_map_txdma_channel_cfg_ring: channel %d cfg 0x%llx",
243652ccf843Smisaki 	    dma_channel,
243752ccf843Smisaki 	    tx_ring_cfig_p->value));
243844961713Sgirish 
243944961713Sgirish 	tx_cs_p->bits.ldw.rst = 1;
244044961713Sgirish 
244144961713Sgirish 	/* Map in mailbox */
244244961713Sgirish 	mboxp = (p_tx_mbox_t)
244352ccf843Smisaki 	    KMEM_ZALLOC(sizeof (tx_mbox_t), KM_SLEEP);
244444961713Sgirish 	dmap = (p_nxge_dma_common_t)&mboxp->tx_mbox;
244544961713Sgirish 	nxge_setup_dma_common(dmap, cntl_dmap, 1, sizeof (txdma_mailbox_t));
244644961713Sgirish 	mboxh_p = (p_txdma_mbh_t)&tx_ring_p->tx_mbox_mbh;
244744961713Sgirish 	mboxl_p = (p_txdma_mbl_t)&tx_ring_p->tx_mbox_mbl;
244844961713Sgirish 	mboxh_p->value = mboxl_p->value = 0;
244944961713Sgirish 
245044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
245152ccf843Smisaki 	    "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
245252ccf843Smisaki 	    dmap->dma_cookie.dmac_laddress));
245344961713Sgirish 
245444961713Sgirish 	mboxh_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress >>
245552ccf843Smisaki 	    TXDMA_MBH_ADDR_SHIFT) & TXDMA_MBH_MASK);
245644961713Sgirish 
245744961713Sgirish 	mboxl_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress &
245852ccf843Smisaki 	    TXDMA_MBL_MASK) >> TXDMA_MBL_SHIFT);
245944961713Sgirish 
246044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
246152ccf843Smisaki 	    "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
246252ccf843Smisaki 	    dmap->dma_cookie.dmac_laddress));
246344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
246452ccf843Smisaki 	    "==> nxge_map_txdma_channel_cfg_ring: hmbox $%p "
246552ccf843Smisaki 	    "mbox $%p",
246652ccf843Smisaki 	    mboxh_p->bits.ldw.mbaddr, mboxl_p->bits.ldw.mbaddr));
246744961713Sgirish 	tx_ring_p->page_valid.value = 0;
246844961713Sgirish 	tx_ring_p->page_mask_1.value = tx_ring_p->page_mask_2.value = 0;
246944961713Sgirish 	tx_ring_p->page_value_1.value = tx_ring_p->page_value_2.value = 0;
247044961713Sgirish 	tx_ring_p->page_reloc_1.value = tx_ring_p->page_reloc_2.value = 0;
247144961713Sgirish 	tx_ring_p->page_hdl.value = 0;
247244961713Sgirish 
247344961713Sgirish 	tx_ring_p->page_valid.bits.ldw.page0 = 1;
247444961713Sgirish 	tx_ring_p->page_valid.bits.ldw.page1 = 1;
247544961713Sgirish 
247644961713Sgirish 	tx_ring_p->max_burst.value = 0;
247744961713Sgirish 	tx_ring_p->max_burst.bits.ldw.dma_max_burst = TXC_DMA_MAX_BURST_DEFAULT;
247844961713Sgirish 
247944961713Sgirish 	*tx_mbox_p = mboxp;
248044961713Sgirish 
248144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
248252ccf843Smisaki 	    "<== nxge_map_txdma_channel_cfg_ring"));
248344961713Sgirish }
248444961713Sgirish 
248544961713Sgirish /*ARGSUSED*/
248644961713Sgirish static void
248744961713Sgirish nxge_unmap_txdma_channel_cfg_ring(p_nxge_t nxgep,
248844961713Sgirish 	p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p)
248944961713Sgirish {
249044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
249152ccf843Smisaki 	    "==> nxge_unmap_txdma_channel_cfg_ring: channel %d",
249252ccf843Smisaki 	    tx_ring_p->tdc));
249344961713Sgirish 
249444961713Sgirish 	KMEM_FREE(tx_mbox_p, sizeof (tx_mbox_t));
249544961713Sgirish 
249644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
249752ccf843Smisaki 	    "<== nxge_unmap_txdma_channel_cfg_ring"));
249844961713Sgirish }
249944961713Sgirish 
2500678453a8Sspeer /*
2501678453a8Sspeer  * nxge_map_txdma_channel_buf_ring
2502678453a8Sspeer  *
2503678453a8Sspeer  *
2504678453a8Sspeer  * Arguments:
2505678453a8Sspeer  * 	nxgep
2506678453a8Sspeer  * 	channel		The channel to map.
2507678453a8Sspeer  *	dma_buf_p
2508678453a8Sspeer  *	tx_desc_p	channel's descriptor ring
2509678453a8Sspeer  *	num_chunks
2510678453a8Sspeer  *
2511678453a8Sspeer  * Notes:
2512678453a8Sspeer  *
2513678453a8Sspeer  * NPI/NXGE function calls:
2514678453a8Sspeer  *	nxge_setup_dma_common()
2515678453a8Sspeer  *
2516678453a8Sspeer  * Registers accessed:
2517678453a8Sspeer  *	none.
2518678453a8Sspeer  *
2519678453a8Sspeer  * Context:
2520678453a8Sspeer  *	Any domain
2521678453a8Sspeer  */
252244961713Sgirish static nxge_status_t
252344961713Sgirish nxge_map_txdma_channel_buf_ring(p_nxge_t nxgep, uint16_t channel,
252444961713Sgirish 	p_nxge_dma_common_t *dma_buf_p,
252544961713Sgirish 	p_tx_ring_t *tx_desc_p, uint32_t num_chunks)
252644961713Sgirish {
252744961713Sgirish 	p_nxge_dma_common_t 	dma_bufp, tmp_bufp;
252844961713Sgirish 	p_nxge_dma_common_t 	dmap;
252944961713Sgirish 	nxge_os_dma_handle_t	tx_buf_dma_handle;
253044961713Sgirish 	p_tx_ring_t 		tx_ring_p;
253144961713Sgirish 	p_tx_msg_t 		tx_msg_ring;
253244961713Sgirish 	nxge_status_t		status = NXGE_OK;
253344961713Sgirish 	int			ddi_status = DDI_SUCCESS;
253444961713Sgirish 	int			i, j, index;
253544961713Sgirish 	uint32_t		size, bsize;
253644961713Sgirish 	uint32_t 		nblocks, nmsgs;
2537da14cebeSEric Cheng 	char			qname[TASKQ_NAMELEN];
253844961713Sgirish 
253944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
254052ccf843Smisaki 	    "==> nxge_map_txdma_channel_buf_ring"));
254144961713Sgirish 
254244961713Sgirish 	dma_bufp = tmp_bufp = *dma_buf_p;
254344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
254444961713Sgirish 		" nxge_map_txdma_channel_buf_ring: channel %d to map %d "
254544961713Sgirish 		"chunks bufp $%p",
254652ccf843Smisaki 		    channel, num_chunks, dma_bufp));
254744961713Sgirish 
254844961713Sgirish 	nmsgs = 0;
254944961713Sgirish 	for (i = 0; i < num_chunks; i++, tmp_bufp++) {
255044961713Sgirish 		nmsgs += tmp_bufp->nblocks;
255144961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
255252ccf843Smisaki 		    "==> nxge_map_txdma_channel_buf_ring: channel %d "
255352ccf843Smisaki 		    "bufp $%p nblocks %d nmsgs %d",
255452ccf843Smisaki 		    channel, tmp_bufp, tmp_bufp->nblocks, nmsgs));
255544961713Sgirish 	}
255644961713Sgirish 	if (!nmsgs) {
255744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
255852ccf843Smisaki 		    "<== nxge_map_txdma_channel_buf_ring: channel %d "
255952ccf843Smisaki 		    "no msg blocks",
256052ccf843Smisaki 		    channel));
256144961713Sgirish 		status = NXGE_ERROR;
256244961713Sgirish 		goto nxge_map_txdma_channel_buf_ring_exit;
256344961713Sgirish 	}
256444961713Sgirish 
256544961713Sgirish 	tx_ring_p = (p_tx_ring_t)
256652ccf843Smisaki 	    KMEM_ZALLOC(sizeof (tx_ring_t), KM_SLEEP);
256744961713Sgirish 	MUTEX_INIT(&tx_ring_p->lock, NULL, MUTEX_DRIVER,
256852ccf843Smisaki 	    (void *)nxgep->interrupt_cookie);
25691f8914d5Sml 
257022c0d73aSspeer 	(void) atomic_swap_32(&tx_ring_p->tx_ring_offline, NXGE_TX_RING_ONLINE);
25716895688eSspeer 	tx_ring_p->tx_ring_busy = B_FALSE;
25721f8914d5Sml 	tx_ring_p->nxgep = nxgep;
2573da14cebeSEric Cheng 	tx_ring_p->tx_ring_handle = (mac_ring_handle_t)NULL;
2574da14cebeSEric Cheng 	(void) snprintf(qname, TASKQ_NAMELEN, "tx_%d_%d",
2575da14cebeSEric Cheng 	    nxgep->instance, channel);
2576da14cebeSEric Cheng 	tx_ring_p->taskq = ddi_taskq_create(nxgep->dip, qname, 1,
2577da14cebeSEric Cheng 	    TASKQ_DEFAULTPRI, 0);
2578da14cebeSEric Cheng 	if (tx_ring_p->taskq == NULL) {
2579da14cebeSEric Cheng 		goto nxge_map_txdma_channel_buf_ring_fail1;
2580da14cebeSEric Cheng 	}
2581da14cebeSEric Cheng 
258244961713Sgirish 	/*
258344961713Sgirish 	 * Allocate transmit message rings and handles for packets
258444961713Sgirish 	 * not to be copied to premapped buffers.
258544961713Sgirish 	 */
258644961713Sgirish 	size = nmsgs * sizeof (tx_msg_t);
258744961713Sgirish 	tx_msg_ring = KMEM_ZALLOC(size, KM_SLEEP);
258844961713Sgirish 	for (i = 0; i < nmsgs; i++) {
258944961713Sgirish 		ddi_status = ddi_dma_alloc_handle(nxgep->dip, &nxge_tx_dma_attr,
259052ccf843Smisaki 		    DDI_DMA_DONTWAIT, 0,
259152ccf843Smisaki 		    &tx_msg_ring[i].dma_handle);
259244961713Sgirish 		if (ddi_status != DDI_SUCCESS) {
259344961713Sgirish 			status |= NXGE_DDI_FAILED;
259444961713Sgirish 			break;
259544961713Sgirish 		}
259644961713Sgirish 	}
259744961713Sgirish 	if (i < nmsgs) {
259856d930aeSspeer 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
259956d930aeSspeer 		    "Allocate handles failed."));
260044961713Sgirish 		goto nxge_map_txdma_channel_buf_ring_fail1;
260144961713Sgirish 	}
260244961713Sgirish 
260344961713Sgirish 	tx_ring_p->tdc = channel;
260444961713Sgirish 	tx_ring_p->tx_msg_ring = tx_msg_ring;
260544961713Sgirish 	tx_ring_p->tx_ring_size = nmsgs;
260644961713Sgirish 	tx_ring_p->num_chunks = num_chunks;
260744961713Sgirish 	if (!nxge_tx_intr_thres) {
260844961713Sgirish 		nxge_tx_intr_thres = tx_ring_p->tx_ring_size/4;
260944961713Sgirish 	}
261044961713Sgirish 	tx_ring_p->tx_wrap_mask = tx_ring_p->tx_ring_size - 1;
261144961713Sgirish 	tx_ring_p->rd_index = 0;
261244961713Sgirish 	tx_ring_p->wr_index = 0;
261344961713Sgirish 	tx_ring_p->ring_head.value = 0;
261444961713Sgirish 	tx_ring_p->ring_kick_tail.value = 0;
261544961713Sgirish 	tx_ring_p->descs_pending = 0;
261644961713Sgirish 
261744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
261852ccf843Smisaki 	    "==> nxge_map_txdma_channel_buf_ring: channel %d "
261952ccf843Smisaki 	    "actual tx desc max %d nmsgs %d "
262052ccf843Smisaki 	    "(config nxge_tx_ring_size %d)",
262152ccf843Smisaki 	    channel, tx_ring_p->tx_ring_size, nmsgs,
262252ccf843Smisaki 	    nxge_tx_ring_size));
262344961713Sgirish 
262444961713Sgirish 	/*
262544961713Sgirish 	 * Map in buffers from the buffer pool.
262644961713Sgirish 	 */
262744961713Sgirish 	index = 0;
262844961713Sgirish 	bsize = dma_bufp->block_size;
262944961713Sgirish 
263044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel_buf_ring: "
263152ccf843Smisaki 	    "dma_bufp $%p tx_rng_p $%p "
263252ccf843Smisaki 	    "tx_msg_rng_p $%p bsize %d",
263352ccf843Smisaki 	    dma_bufp, tx_ring_p, tx_msg_ring, bsize));
263444961713Sgirish 
263544961713Sgirish 	tx_buf_dma_handle = dma_bufp->dma_handle;
263644961713Sgirish 	for (i = 0; i < num_chunks; i++, dma_bufp++) {
263744961713Sgirish 		bsize = dma_bufp->block_size;
263844961713Sgirish 		nblocks = dma_bufp->nblocks;
263944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
264052ccf843Smisaki 		    "==> nxge_map_txdma_channel_buf_ring: dma chunk %d "
264152ccf843Smisaki 		    "size %d dma_bufp $%p",
264252ccf843Smisaki 		    i, sizeof (nxge_dma_common_t), dma_bufp));
264344961713Sgirish 
264444961713Sgirish 		for (j = 0; j < nblocks; j++) {
264544961713Sgirish 			tx_msg_ring[index].buf_dma_handle = tx_buf_dma_handle;
264644961713Sgirish 			dmap = &tx_msg_ring[index++].buf_dma;
264744961713Sgirish #ifdef TX_MEM_DEBUG
264844961713Sgirish 			NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
264952ccf843Smisaki 			    "==> nxge_map_txdma_channel_buf_ring: j %d"
265052ccf843Smisaki 			    "dmap $%p", i, dmap));
265144961713Sgirish #endif
265244961713Sgirish 			nxge_setup_dma_common(dmap, dma_bufp, 1,
265352ccf843Smisaki 			    bsize);
265444961713Sgirish 		}
265544961713Sgirish 	}
265644961713Sgirish 
265744961713Sgirish 	if (i < num_chunks) {
265856d930aeSspeer 		status = NXGE_ERROR;
265944961713Sgirish 		goto nxge_map_txdma_channel_buf_ring_fail1;
266044961713Sgirish 	}
266144961713Sgirish 
266244961713Sgirish 	*tx_desc_p = tx_ring_p;
266344961713Sgirish 
266444961713Sgirish 	goto nxge_map_txdma_channel_buf_ring_exit;
266544961713Sgirish 
266644961713Sgirish nxge_map_txdma_channel_buf_ring_fail1:
2667da14cebeSEric Cheng 	if (tx_ring_p->taskq) {
2668da14cebeSEric Cheng 		ddi_taskq_destroy(tx_ring_p->taskq);
2669da14cebeSEric Cheng 		tx_ring_p->taskq = NULL;
26701f8914d5Sml 	}
26711f8914d5Sml 
267244961713Sgirish 	index--;
267344961713Sgirish 	for (; index >= 0; index--) {
267456d930aeSspeer 		if (tx_msg_ring[index].dma_handle != NULL) {
267556d930aeSspeer 			ddi_dma_free_handle(&tx_msg_ring[index].dma_handle);
267644961713Sgirish 		}
267744961713Sgirish 	}
267844961713Sgirish 	MUTEX_DESTROY(&tx_ring_p->lock);
267956d930aeSspeer 	KMEM_FREE(tx_msg_ring, size);
268044961713Sgirish 	KMEM_FREE(tx_ring_p, sizeof (tx_ring_t));
268144961713Sgirish 
268256d930aeSspeer 	status = NXGE_ERROR;
268356d930aeSspeer 
268444961713Sgirish nxge_map_txdma_channel_buf_ring_exit:
268544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
268652ccf843Smisaki 	    "<== nxge_map_txdma_channel_buf_ring status 0x%x", status));
268744961713Sgirish 
268844961713Sgirish 	return (status);
268944961713Sgirish }
269044961713Sgirish 
269144961713Sgirish /*ARGSUSED*/
269244961713Sgirish static void
269344961713Sgirish nxge_unmap_txdma_channel_buf_ring(p_nxge_t nxgep, p_tx_ring_t tx_ring_p)
269444961713Sgirish {
269544961713Sgirish 	p_tx_msg_t 		tx_msg_ring;
269644961713Sgirish 	p_tx_msg_t 		tx_msg_p;
269744961713Sgirish 	int			i;
269844961713Sgirish 
269944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
270052ccf843Smisaki 	    "==> nxge_unmap_txdma_channel_buf_ring"));
270144961713Sgirish 	if (tx_ring_p == NULL) {
270244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
270352ccf843Smisaki 		    "<== nxge_unmap_txdma_channel_buf_ring: NULL ringp"));
270444961713Sgirish 		return;
270544961713Sgirish 	}
270644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
270752ccf843Smisaki 	    "==> nxge_unmap_txdma_channel_buf_ring: channel %d",
270852ccf843Smisaki 	    tx_ring_p->tdc));
270944961713Sgirish 
271044961713Sgirish 	tx_msg_ring = tx_ring_p->tx_msg_ring;
2711678453a8Sspeer 
2712678453a8Sspeer 	/*
2713678453a8Sspeer 	 * Since the serialization thread, timer thread and
2714678453a8Sspeer 	 * interrupt thread can all call the transmit reclaim,
2715678453a8Sspeer 	 * the unmapping function needs to acquire the lock
2716678453a8Sspeer 	 * to free those buffers which were transmitted
2717678453a8Sspeer 	 * by the hardware already.
2718678453a8Sspeer 	 */
2719678453a8Sspeer 	MUTEX_ENTER(&tx_ring_p->lock);
2720678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
2721678453a8Sspeer 	    "==> nxge_unmap_txdma_channel_buf_ring (reclaim): "
2722678453a8Sspeer 	    "channel %d",
2723678453a8Sspeer 	    tx_ring_p->tdc));
2724678453a8Sspeer 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
2725678453a8Sspeer 
272644961713Sgirish 	for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
272744961713Sgirish 		tx_msg_p = &tx_msg_ring[i];
272844961713Sgirish 		if (tx_msg_p->tx_message != NULL) {
272944961713Sgirish 			freemsg(tx_msg_p->tx_message);
273044961713Sgirish 			tx_msg_p->tx_message = NULL;
273144961713Sgirish 		}
273244961713Sgirish 	}
273344961713Sgirish 
273444961713Sgirish 	for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
273544961713Sgirish 		if (tx_msg_ring[i].dma_handle != NULL) {
273644961713Sgirish 			ddi_dma_free_handle(&tx_msg_ring[i].dma_handle);
273744961713Sgirish 		}
2738678453a8Sspeer 		tx_msg_ring[i].dma_handle = NULL;
273944961713Sgirish 	}
274044961713Sgirish 
2741678453a8Sspeer 	MUTEX_EXIT(&tx_ring_p->lock);
2742678453a8Sspeer 
2743da14cebeSEric Cheng 	if (tx_ring_p->taskq) {
2744da14cebeSEric Cheng 		ddi_taskq_destroy(tx_ring_p->taskq);
2745da14cebeSEric Cheng 		tx_ring_p->taskq = NULL;
27461f8914d5Sml 	}
27471f8914d5Sml 
274844961713Sgirish 	MUTEX_DESTROY(&tx_ring_p->lock);
274944961713Sgirish 	KMEM_FREE(tx_msg_ring, sizeof (tx_msg_t) * tx_ring_p->tx_ring_size);
275044961713Sgirish 	KMEM_FREE(tx_ring_p, sizeof (tx_ring_t));
275144961713Sgirish 
275244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
275352ccf843Smisaki 	    "<== nxge_unmap_txdma_channel_buf_ring"));
275444961713Sgirish }
275544961713Sgirish 
275644961713Sgirish static nxge_status_t
2757678453a8Sspeer nxge_txdma_hw_start(p_nxge_t nxgep, int channel)
275844961713Sgirish {
275944961713Sgirish 	p_tx_rings_t 		tx_rings;
276044961713Sgirish 	p_tx_ring_t 		*tx_desc_rings;
276144961713Sgirish 	p_tx_mbox_areas_t 	tx_mbox_areas_p;
276244961713Sgirish 	p_tx_mbox_t		*tx_mbox_p;
276344961713Sgirish 	nxge_status_t		status = NXGE_OK;
276444961713Sgirish 
276544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start"));
276644961713Sgirish 
276744961713Sgirish 	tx_rings = nxgep->tx_rings;
276844961713Sgirish 	if (tx_rings == NULL) {
276944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
277052ccf843Smisaki 		    "<== nxge_txdma_hw_start: NULL ring pointer"));
277144961713Sgirish 		return (NXGE_ERROR);
277244961713Sgirish 	}
277344961713Sgirish 	tx_desc_rings = tx_rings->rings;
277444961713Sgirish 	if (tx_desc_rings == NULL) {
277544961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
277652ccf843Smisaki 		    "<== nxge_txdma_hw_start: NULL ring pointers"));
277744961713Sgirish 		return (NXGE_ERROR);
277844961713Sgirish 	}
277944961713Sgirish 
2780678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
2781678453a8Sspeer 	    "tx_rings $%p tx_desc_rings $%p", tx_rings, tx_desc_rings));
278244961713Sgirish 
278344961713Sgirish 	tx_mbox_areas_p = nxgep->tx_mbox_areas_p;
278444961713Sgirish 	tx_mbox_p = tx_mbox_areas_p->txmbox_areas_p;
278544961713Sgirish 
2786678453a8Sspeer 	status = nxge_txdma_start_channel(nxgep, channel,
2787678453a8Sspeer 	    (p_tx_ring_t)tx_desc_rings[channel],
2788678453a8Sspeer 	    (p_tx_mbox_t)tx_mbox_p[channel]);
2789678453a8Sspeer 	if (status != NXGE_OK) {
2790678453a8Sspeer 		goto nxge_txdma_hw_start_fail1;
279144961713Sgirish 	}
279244961713Sgirish 
279344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
279452ccf843Smisaki 	    "tx_rings $%p rings $%p",
279552ccf843Smisaki 	    nxgep->tx_rings, nxgep->tx_rings->rings));
279644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
279752ccf843Smisaki 	    "tx_rings $%p tx_desc_rings $%p",
279852ccf843Smisaki 	    nxgep->tx_rings, tx_desc_rings));
279944961713Sgirish 
280044961713Sgirish 	goto nxge_txdma_hw_start_exit;
280144961713Sgirish 
280244961713Sgirish nxge_txdma_hw_start_fail1:
280344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
280452ccf843Smisaki 	    "==> nxge_txdma_hw_start: disable "
280552ccf843Smisaki 	    "(status 0x%x channel %d)", status, channel));
280644961713Sgirish 
280744961713Sgirish nxge_txdma_hw_start_exit:
280844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
280952ccf843Smisaki 	    "==> nxge_txdma_hw_start: (status 0x%x)", status));
281044961713Sgirish 
281144961713Sgirish 	return (status);
281244961713Sgirish }
281344961713Sgirish 
2814678453a8Sspeer /*
2815678453a8Sspeer  * nxge_txdma_start_channel
2816678453a8Sspeer  *
2817678453a8Sspeer  *	Start a TDC.
2818678453a8Sspeer  *
2819678453a8Sspeer  * Arguments:
2820678453a8Sspeer  * 	nxgep
2821678453a8Sspeer  * 	channel		The channel to start.
2822678453a8Sspeer  * 	tx_ring_p	channel's transmit descriptor ring.
2823678453a8Sspeer  * 	tx_mbox_p	channel' smailbox.
2824678453a8Sspeer  *
2825678453a8Sspeer  * Notes:
2826678453a8Sspeer  *
2827678453a8Sspeer  * NPI/NXGE function calls:
2828678453a8Sspeer  *	nxge_reset_txdma_channel()
2829678453a8Sspeer  *	nxge_init_txdma_channel_event_mask()
2830678453a8Sspeer  *	nxge_enable_txdma_channel()
2831678453a8Sspeer  *
2832678453a8Sspeer  * Registers accessed:
2833678453a8Sspeer  *	none directly (see functions above).
2834678453a8Sspeer  *
2835678453a8Sspeer  * Context:
2836678453a8Sspeer  *	Any domain
2837678453a8Sspeer  */
283844961713Sgirish static nxge_status_t
283944961713Sgirish nxge_txdma_start_channel(p_nxge_t nxgep, uint16_t channel,
284044961713Sgirish     p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p)
284144961713Sgirish 
284244961713Sgirish {
284344961713Sgirish 	nxge_status_t		status = NXGE_OK;
284444961713Sgirish 
284544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
284644961713Sgirish 		"==> nxge_txdma_start_channel (channel %d)", channel));
284744961713Sgirish 	/*
284844961713Sgirish 	 * TXDMA/TXC must be in stopped state.
284944961713Sgirish 	 */
285044961713Sgirish 	(void) nxge_txdma_stop_inj_err(nxgep, channel);
285144961713Sgirish 
285244961713Sgirish 	/*
285344961713Sgirish 	 * Reset TXDMA channel
285444961713Sgirish 	 */
285544961713Sgirish 	tx_ring_p->tx_cs.value = 0;
285644961713Sgirish 	tx_ring_p->tx_cs.bits.ldw.rst = 1;
285744961713Sgirish 	status = nxge_reset_txdma_channel(nxgep, channel,
285844961713Sgirish 			tx_ring_p->tx_cs.value);
285944961713Sgirish 	if (status != NXGE_OK) {
286044961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
286144961713Sgirish 			"==> nxge_txdma_start_channel (channel %d)"
286244961713Sgirish 			" reset channel failed 0x%x", channel, status));
286344961713Sgirish 		goto nxge_txdma_start_channel_exit;
286444961713Sgirish 	}
286544961713Sgirish 
286644961713Sgirish 	/*
286744961713Sgirish 	 * Initialize the TXDMA channel specific FZC control
286844961713Sgirish 	 * configurations. These FZC registers are pertaining
286944961713Sgirish 	 * to each TX channel (i.e. logical pages).
287044961713Sgirish 	 */
2871678453a8Sspeer 	if (!isLDOMguest(nxgep)) {
2872678453a8Sspeer 		status = nxge_init_fzc_txdma_channel(nxgep, channel,
2873678453a8Sspeer 		    tx_ring_p, tx_mbox_p);
2874678453a8Sspeer 		if (status != NXGE_OK) {
2875678453a8Sspeer 			goto nxge_txdma_start_channel_exit;
2876678453a8Sspeer 		}
287744961713Sgirish 	}
287844961713Sgirish 
287944961713Sgirish 	/*
288044961713Sgirish 	 * Initialize the event masks.
288144961713Sgirish 	 */
288244961713Sgirish 	tx_ring_p->tx_evmask.value = 0;
288344961713Sgirish 	status = nxge_init_txdma_channel_event_mask(nxgep,
2884678453a8Sspeer 	    channel, &tx_ring_p->tx_evmask);
288544961713Sgirish 	if (status != NXGE_OK) {
288644961713Sgirish 		goto nxge_txdma_start_channel_exit;
288744961713Sgirish 	}
288844961713Sgirish 
288944961713Sgirish 	/*
289044961713Sgirish 	 * Load TXDMA descriptors, buffers, mailbox,
289144961713Sgirish 	 * initialise the DMA channels and
289244961713Sgirish 	 * enable each DMA channel.
289344961713Sgirish 	 */
289444961713Sgirish 	status = nxge_enable_txdma_channel(nxgep, channel,
289544961713Sgirish 			tx_ring_p, tx_mbox_p);
289644961713Sgirish 	if (status != NXGE_OK) {
289744961713Sgirish 		goto nxge_txdma_start_channel_exit;
289844961713Sgirish 	}
289944961713Sgirish 
290044961713Sgirish nxge_txdma_start_channel_exit:
290144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_start_channel"));
290244961713Sgirish 
290344961713Sgirish 	return (status);
290444961713Sgirish }
290544961713Sgirish 
2906678453a8Sspeer /*
2907678453a8Sspeer  * nxge_txdma_stop_channel
2908678453a8Sspeer  *
2909678453a8Sspeer  *	Stop a TDC.
2910678453a8Sspeer  *
2911678453a8Sspeer  * Arguments:
2912678453a8Sspeer  * 	nxgep
2913678453a8Sspeer  * 	channel		The channel to stop.
2914678453a8Sspeer  * 	tx_ring_p	channel's transmit descriptor ring.
2915678453a8Sspeer  * 	tx_mbox_p	channel' smailbox.
2916678453a8Sspeer  *
2917678453a8Sspeer  * Notes:
2918678453a8Sspeer  *
2919678453a8Sspeer  * NPI/NXGE function calls:
2920678453a8Sspeer  *	nxge_txdma_stop_inj_err()
2921678453a8Sspeer  *	nxge_reset_txdma_channel()
2922678453a8Sspeer  *	nxge_init_txdma_channel_event_mask()
2923678453a8Sspeer  *	nxge_init_txdma_channel_cntl_stat()
2924678453a8Sspeer  *	nxge_disable_txdma_channel()
2925678453a8Sspeer  *
2926678453a8Sspeer  * Registers accessed:
2927678453a8Sspeer  *	none directly (see functions above).
2928678453a8Sspeer  *
2929678453a8Sspeer  * Context:
2930678453a8Sspeer  *	Any domain
2931678453a8Sspeer  */
293244961713Sgirish /*ARGSUSED*/
293344961713Sgirish static nxge_status_t
2934678453a8Sspeer nxge_txdma_stop_channel(p_nxge_t nxgep, uint16_t channel)
293544961713Sgirish {
2936678453a8Sspeer 	p_tx_ring_t tx_ring_p;
2937678453a8Sspeer 	int status = NXGE_OK;
293844961713Sgirish 
293944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
294052ccf843Smisaki 	    "==> nxge_txdma_stop_channel: channel %d", channel));
294144961713Sgirish 
294244961713Sgirish 	/*
294344961713Sgirish 	 * Stop (disable) TXDMA and TXC (if stop bit is set
294444961713Sgirish 	 * and STOP_N_GO bit not set, the TXDMA reset state will
294544961713Sgirish 	 * not be set if reset TXDMA.
294644961713Sgirish 	 */
294744961713Sgirish 	(void) nxge_txdma_stop_inj_err(nxgep, channel);
294844961713Sgirish 
2949678453a8Sspeer 	tx_ring_p = nxgep->tx_rings->rings[channel];
2950678453a8Sspeer 
295144961713Sgirish 	/*
295244961713Sgirish 	 * Reset TXDMA channel
295344961713Sgirish 	 */
295444961713Sgirish 	tx_ring_p->tx_cs.value = 0;
295544961713Sgirish 	tx_ring_p->tx_cs.bits.ldw.rst = 1;
295644961713Sgirish 	status = nxge_reset_txdma_channel(nxgep, channel,
295752ccf843Smisaki 	    tx_ring_p->tx_cs.value);
295844961713Sgirish 	if (status != NXGE_OK) {
295944961713Sgirish 		goto nxge_txdma_stop_channel_exit;
296044961713Sgirish 	}
296144961713Sgirish 
296244961713Sgirish #ifdef HARDWARE_REQUIRED
296344961713Sgirish 	/* Set up the interrupt event masks. */
296444961713Sgirish 	tx_ring_p->tx_evmask.value = 0;
296544961713Sgirish 	status = nxge_init_txdma_channel_event_mask(nxgep,
296652ccf843Smisaki 	    channel, &tx_ring_p->tx_evmask);
296744961713Sgirish 	if (status != NXGE_OK) {
296844961713Sgirish 		goto nxge_txdma_stop_channel_exit;
296944961713Sgirish 	}
297044961713Sgirish 
297144961713Sgirish 	/* Initialize the DMA control and status register */
297244961713Sgirish 	tx_ring_p->tx_cs.value = TX_ENT_MSK_MK_ALL;
297344961713Sgirish 	status = nxge_init_txdma_channel_cntl_stat(nxgep, channel,
297452ccf843Smisaki 	    tx_ring_p->tx_cs.value);
297544961713Sgirish 	if (status != NXGE_OK) {
297644961713Sgirish 		goto nxge_txdma_stop_channel_exit;
297744961713Sgirish 	}
297844961713Sgirish 
2979678453a8Sspeer 	tx_mbox_p = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
2980678453a8Sspeer 
298144961713Sgirish 	/* Disable channel */
298244961713Sgirish 	status = nxge_disable_txdma_channel(nxgep, channel,
2983678453a8Sspeer 	    tx_ring_p, tx_mbox_p);
298444961713Sgirish 	if (status != NXGE_OK) {
298544961713Sgirish 		goto nxge_txdma_start_channel_exit;
298644961713Sgirish 	}
298744961713Sgirish 
298844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
298952ccf843Smisaki 	    "==> nxge_txdma_stop_channel: event done"));
299044961713Sgirish 
299144961713Sgirish #endif
299244961713Sgirish 
299344961713Sgirish nxge_txdma_stop_channel_exit:
299444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_stop_channel"));
299544961713Sgirish 	return (status);
299644961713Sgirish }
299744961713Sgirish 
2998678453a8Sspeer /*
2999678453a8Sspeer  * nxge_txdma_get_ring
3000678453a8Sspeer  *
3001678453a8Sspeer  *	Get the ring for a TDC.
3002678453a8Sspeer  *
3003678453a8Sspeer  * Arguments:
3004678453a8Sspeer  * 	nxgep
3005678453a8Sspeer  * 	channel
3006678453a8Sspeer  *
3007678453a8Sspeer  * Notes:
3008678453a8Sspeer  *
3009678453a8Sspeer  * NPI/NXGE function calls:
3010678453a8Sspeer  *
3011678453a8Sspeer  * Registers accessed:
3012678453a8Sspeer  *
3013678453a8Sspeer  * Context:
3014678453a8Sspeer  *	Any domain
3015678453a8Sspeer  */
301644961713Sgirish static p_tx_ring_t
301744961713Sgirish nxge_txdma_get_ring(p_nxge_t nxgep, uint16_t channel)
301844961713Sgirish {
3019678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
3020678453a8Sspeer 	int tdc;
302144961713Sgirish 
302244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_ring"));
302344961713Sgirish 
3024678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
302544961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3026678453a8Sspeer 		    "<== nxge_txdma_get_ring: NULL ring pointer(s)"));
3027678453a8Sspeer 		goto return_null;
3028678453a8Sspeer 	}
3029678453a8Sspeer 
3030678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3031678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3032678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3033678453a8Sspeer 			if (ring) {
3034678453a8Sspeer 				if (channel == ring->tdc) {
3035678453a8Sspeer 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
3036678453a8Sspeer 					    "<== nxge_txdma_get_ring: "
3037678453a8Sspeer 					    "tdc %d ring $%p", tdc, ring));
3038678453a8Sspeer 					return (ring);
3039678453a8Sspeer 				}
3040678453a8Sspeer 			}
304144961713Sgirish 		}
304244961713Sgirish 	}
304344961713Sgirish 
3044678453a8Sspeer return_null:
3045678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_ring: "
304652ccf843Smisaki 	    "ring not found"));
3047678453a8Sspeer 
304844961713Sgirish 	return (NULL);
304944961713Sgirish }
305044961713Sgirish 
3051678453a8Sspeer /*
3052678453a8Sspeer  * nxge_txdma_get_mbox
3053678453a8Sspeer  *
3054678453a8Sspeer  *	Get the mailbox for a TDC.
3055678453a8Sspeer  *
3056678453a8Sspeer  * Arguments:
3057678453a8Sspeer  * 	nxgep
3058678453a8Sspeer  * 	channel
3059678453a8Sspeer  *
3060678453a8Sspeer  * Notes:
3061678453a8Sspeer  *
3062678453a8Sspeer  * NPI/NXGE function calls:
3063678453a8Sspeer  *
3064678453a8Sspeer  * Registers accessed:
3065678453a8Sspeer  *
3066678453a8Sspeer  * Context:
3067678453a8Sspeer  *	Any domain
3068678453a8Sspeer  */
306944961713Sgirish static p_tx_mbox_t
307044961713Sgirish nxge_txdma_get_mbox(p_nxge_t nxgep, uint16_t channel)
307144961713Sgirish {
3072678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
3073678453a8Sspeer 	int tdc;
307444961713Sgirish 
307544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_mbox"));
307644961713Sgirish 
3077678453a8Sspeer 	if (nxgep->tx_mbox_areas_p == 0 ||
3078678453a8Sspeer 	    nxgep->tx_mbox_areas_p->txmbox_areas_p == 0) {
3079678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3080678453a8Sspeer 		    "<== nxge_txdma_get_mbox: NULL mailbox pointer(s)"));
3081678453a8Sspeer 		goto return_null;
308244961713Sgirish 	}
308344961713Sgirish 
3084678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
3085678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3086678453a8Sspeer 		    "<== nxge_txdma_get_mbox: NULL ring pointer(s)"));
3087678453a8Sspeer 		goto return_null;
3088678453a8Sspeer 	}
3089678453a8Sspeer 
3090678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3091678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3092678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3093678453a8Sspeer 			if (ring) {
3094678453a8Sspeer 				if (channel == ring->tdc) {
3095678453a8Sspeer 					tx_mbox_t *mailbox = nxgep->
3096678453a8Sspeer 					    tx_mbox_areas_p->
3097678453a8Sspeer 					    txmbox_areas_p[tdc];
3098678453a8Sspeer 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
3099678453a8Sspeer 					    "<== nxge_txdma_get_mbox: tdc %d "
3100678453a8Sspeer 					    "ring $%p", tdc, mailbox));
3101678453a8Sspeer 					return (mailbox);
3102678453a8Sspeer 				}
3103678453a8Sspeer 			}
310444961713Sgirish 		}
310544961713Sgirish 	}
310644961713Sgirish 
3107678453a8Sspeer return_null:
3108678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_mbox: "
310952ccf843Smisaki 	    "mailbox not found"));
3110678453a8Sspeer 
311144961713Sgirish 	return (NULL);
311244961713Sgirish }
311344961713Sgirish 
3114678453a8Sspeer /*
3115678453a8Sspeer  * nxge_tx_err_evnts
3116678453a8Sspeer  *
3117678453a8Sspeer  *	Recover a TDC.
3118678453a8Sspeer  *
3119678453a8Sspeer  * Arguments:
3120678453a8Sspeer  * 	nxgep
3121678453a8Sspeer  * 	index	The index to the TDC ring.
3122678453a8Sspeer  * 	ldvp	Used to get the channel number ONLY.
3123678453a8Sspeer  * 	cs	A copy of the bits from TX_CS.
3124678453a8Sspeer  *
3125678453a8Sspeer  * Notes:
3126678453a8Sspeer  *	Calling tree:
3127678453a8Sspeer  *	 nxge_tx_intr()
3128678453a8Sspeer  *
3129678453a8Sspeer  * NPI/NXGE function calls:
3130678453a8Sspeer  *	npi_txdma_ring_error_get()
3131678453a8Sspeer  *	npi_txdma_inj_par_error_get()
3132678453a8Sspeer  *	nxge_txdma_fatal_err_recover()
3133678453a8Sspeer  *
3134678453a8Sspeer  * Registers accessed:
3135678453a8Sspeer  *	TX_RNG_ERR_LOGH	DMC+0x40048 Transmit Ring Error Log High
3136678453a8Sspeer  *	TX_RNG_ERR_LOGL DMC+0x40050 Transmit Ring Error Log Low
3137678453a8Sspeer  *	TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error
3138678453a8Sspeer  *
3139678453a8Sspeer  * Context:
3140678453a8Sspeer  *	Any domain	XXX Remove code which accesses TDMC_INJ_PAR_ERR.
3141678453a8Sspeer  */
314244961713Sgirish /*ARGSUSED*/
314344961713Sgirish static nxge_status_t
314444961713Sgirish nxge_tx_err_evnts(p_nxge_t nxgep, uint_t index, p_nxge_ldv_t ldvp, tx_cs_t cs)
314544961713Sgirish {
314644961713Sgirish 	npi_handle_t		handle;
314744961713Sgirish 	npi_status_t		rs;
314844961713Sgirish 	uint8_t			channel;
314944961713Sgirish 	p_tx_ring_t 		*tx_rings;
315044961713Sgirish 	p_tx_ring_t 		tx_ring_p;
315144961713Sgirish 	p_nxge_tx_ring_stats_t	tdc_stats;
315244961713Sgirish 	boolean_t		txchan_fatal = B_FALSE;
315344961713Sgirish 	nxge_status_t		status = NXGE_OK;
315444961713Sgirish 	tdmc_inj_par_err_t	par_err;
315544961713Sgirish 	uint32_t		value;
315644961713Sgirish 
3157678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX2_CTL, "==> nxge_tx_err_evnts"));
315844961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
315944961713Sgirish 	channel = ldvp->channel;
316044961713Sgirish 
316144961713Sgirish 	tx_rings = nxgep->tx_rings->rings;
316244961713Sgirish 	tx_ring_p = tx_rings[index];
316344961713Sgirish 	tdc_stats = tx_ring_p->tdc_stats;
316444961713Sgirish 	if ((cs.bits.ldw.pkt_size_err) || (cs.bits.ldw.pref_buf_par_err) ||
316552ccf843Smisaki 	    (cs.bits.ldw.nack_pref) || (cs.bits.ldw.nack_pkt_rd) ||
316652ccf843Smisaki 	    (cs.bits.ldw.conf_part_err) || (cs.bits.ldw.pkt_prt_err)) {
316744961713Sgirish 		if ((rs = npi_txdma_ring_error_get(handle, channel,
316852ccf843Smisaki 		    &tdc_stats->errlog)) != NPI_SUCCESS)
316944961713Sgirish 			return (NXGE_ERROR | rs);
317044961713Sgirish 	}
317144961713Sgirish 
317244961713Sgirish 	if (cs.bits.ldw.mbox_err) {
317344961713Sgirish 		tdc_stats->mbox_err++;
317444961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
317552ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_MBOX_ERR);
317644961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
317752ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
317852ccf843Smisaki 		    "fatal error: mailbox", channel));
317944961713Sgirish 		txchan_fatal = B_TRUE;
318044961713Sgirish 	}
318144961713Sgirish 	if (cs.bits.ldw.pkt_size_err) {
318244961713Sgirish 		tdc_stats->pkt_size_err++;
318344961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
318452ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR);
318544961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
318652ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
318752ccf843Smisaki 		    "fatal error: pkt_size_err", channel));
318844961713Sgirish 		txchan_fatal = B_TRUE;
318944961713Sgirish 	}
319044961713Sgirish 	if (cs.bits.ldw.tx_ring_oflow) {
319144961713Sgirish 		tdc_stats->tx_ring_oflow++;
319244961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
319352ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW);
319444961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
319552ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
319652ccf843Smisaki 		    "fatal error: tx_ring_oflow", channel));
319744961713Sgirish 		txchan_fatal = B_TRUE;
319844961713Sgirish 	}
319944961713Sgirish 	if (cs.bits.ldw.pref_buf_par_err) {
320044961713Sgirish 		tdc_stats->pre_buf_par_err++;
320144961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
320252ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR);
320344961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
320452ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
320552ccf843Smisaki 		    "fatal error: pre_buf_par_err", channel));
320644961713Sgirish 		/* Clear error injection source for parity error */
320744961713Sgirish 		(void) npi_txdma_inj_par_error_get(handle, &value);
320844961713Sgirish 		par_err.value = value;
320944961713Sgirish 		par_err.bits.ldw.inject_parity_error &= ~(1 << channel);
321044961713Sgirish 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
321144961713Sgirish 		txchan_fatal = B_TRUE;
321244961713Sgirish 	}
321344961713Sgirish 	if (cs.bits.ldw.nack_pref) {
321444961713Sgirish 		tdc_stats->nack_pref++;
321544961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
321652ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_NACK_PREF);
321744961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
321852ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
321952ccf843Smisaki 		    "fatal error: nack_pref", channel));
322044961713Sgirish 		txchan_fatal = B_TRUE;
322144961713Sgirish 	}
322244961713Sgirish 	if (cs.bits.ldw.nack_pkt_rd) {
322344961713Sgirish 		tdc_stats->nack_pkt_rd++;
322444961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
322552ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_NACK_PKT_RD);
322644961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
322752ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
322852ccf843Smisaki 		    "fatal error: nack_pkt_rd", channel));
322944961713Sgirish 		txchan_fatal = B_TRUE;
323044961713Sgirish 	}
323144961713Sgirish 	if (cs.bits.ldw.conf_part_err) {
323244961713Sgirish 		tdc_stats->conf_part_err++;
323344961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
323452ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_CONF_PART_ERR);
323544961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
323652ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
323752ccf843Smisaki 		    "fatal error: config_partition_err", channel));
323844961713Sgirish 		txchan_fatal = B_TRUE;
323944961713Sgirish 	}
324044961713Sgirish 	if (cs.bits.ldw.pkt_prt_err) {
324144961713Sgirish 		tdc_stats->pkt_part_err++;
324244961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
324352ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR);
324444961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
324552ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
324652ccf843Smisaki 		    "fatal error: pkt_prt_err", channel));
324744961713Sgirish 		txchan_fatal = B_TRUE;
324844961713Sgirish 	}
324944961713Sgirish 
325044961713Sgirish 	/* Clear error injection source in case this is an injected error */
325144961713Sgirish 	TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG, channel, 0);
325244961713Sgirish 
325344961713Sgirish 	if (txchan_fatal) {
325444961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
325552ccf843Smisaki 		    " nxge_tx_err_evnts: "
325652ccf843Smisaki 		    " fatal error on channel %d cs 0x%llx\n",
325752ccf843Smisaki 		    channel, cs.value));
325844961713Sgirish 		status = nxge_txdma_fatal_err_recover(nxgep, channel,
325952ccf843Smisaki 		    tx_ring_p);
326044961713Sgirish 		if (status == NXGE_OK) {
326144961713Sgirish 			FM_SERVICE_RESTORED(nxgep);
326244961713Sgirish 		}
326344961713Sgirish 	}
326444961713Sgirish 
3265678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX2_CTL, "<== nxge_tx_err_evnts"));
326644961713Sgirish 
326744961713Sgirish 	return (status);
326844961713Sgirish }
326944961713Sgirish 
327044961713Sgirish static nxge_status_t
3271678453a8Sspeer nxge_txdma_fatal_err_recover(
3272678453a8Sspeer 	p_nxge_t nxgep,
3273678453a8Sspeer 	uint16_t channel,
3274678453a8Sspeer 	p_tx_ring_t tx_ring_p)
327544961713Sgirish {
327644961713Sgirish 	npi_handle_t	handle;
327744961713Sgirish 	npi_status_t	rs = NPI_SUCCESS;
327844961713Sgirish 	p_tx_mbox_t	tx_mbox_p;
327944961713Sgirish 	nxge_status_t	status = NXGE_OK;
328044961713Sgirish 
328144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fatal_err_recover"));
328244961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
328352ccf843Smisaki 	    "Recovering from TxDMAChannel#%d error...", channel));
328444961713Sgirish 
328544961713Sgirish 	/*
328644961713Sgirish 	 * Stop the dma channel waits for the stop done.
328744961713Sgirish 	 * If the stop done bit is not set, then create
328844961713Sgirish 	 * an error.
328944961713Sgirish 	 */
329044961713Sgirish 
329144961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
329244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel stop..."));
329344961713Sgirish 	MUTEX_ENTER(&tx_ring_p->lock);
329444961713Sgirish 	rs = npi_txdma_channel_control(handle, TXDMA_STOP, channel);
329544961713Sgirish 	if (rs != NPI_SUCCESS) {
329644961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
329752ccf843Smisaki 		    "==> nxge_txdma_fatal_err_recover (channel %d): "
329852ccf843Smisaki 		    "stop failed ", channel));
329944961713Sgirish 		goto fail;
330044961713Sgirish 	}
330144961713Sgirish 
330244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reclaim..."));
330344961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
330444961713Sgirish 
330544961713Sgirish 	/*
330644961713Sgirish 	 * Reset TXDMA channel
330744961713Sgirish 	 */
330844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reset..."));
330944961713Sgirish 	if ((rs = npi_txdma_channel_control(handle, TXDMA_RESET, channel)) !=
331052ccf843Smisaki 	    NPI_SUCCESS) {
331144961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
331252ccf843Smisaki 		    "==> nxge_txdma_fatal_err_recover (channel %d)"
331352ccf843Smisaki 		    " reset channel failed 0x%x", channel, rs));
331444961713Sgirish 		goto fail;
331544961713Sgirish 	}
331644961713Sgirish 
331744961713Sgirish 	/*
331844961713Sgirish 	 * Reset the tail (kick) register to 0.
331944961713Sgirish 	 * (Hardware will not reset it. Tx overflow fatal
332044961713Sgirish 	 * error if tail is not set to 0 after reset!
332144961713Sgirish 	 */
332244961713Sgirish 	TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0);
332344961713Sgirish 
332444961713Sgirish 	/* Restart TXDMA channel */
332544961713Sgirish 
3326678453a8Sspeer 	if (!isLDOMguest(nxgep)) {
3327678453a8Sspeer 		tx_mbox_p = nxge_txdma_get_mbox(nxgep, channel);
332844961713Sgirish 
3329678453a8Sspeer 		// XXX This is a problem in HIO!
3330678453a8Sspeer 		/*
3331678453a8Sspeer 		 * Initialize the TXDMA channel specific FZC control
3332678453a8Sspeer 		 * configurations. These FZC registers are pertaining
3333678453a8Sspeer 		 * to each TX channel (i.e. logical pages).
3334678453a8Sspeer 		 */
3335678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel restart..."));
3336678453a8Sspeer 		status = nxge_init_fzc_txdma_channel(nxgep, channel,
3337678453a8Sspeer 		    tx_ring_p, tx_mbox_p);
3338678453a8Sspeer 		if (status != NXGE_OK)
3339678453a8Sspeer 			goto fail;
3340678453a8Sspeer 	}
334144961713Sgirish 
334244961713Sgirish 	/*
334344961713Sgirish 	 * Initialize the event masks.
334444961713Sgirish 	 */
334544961713Sgirish 	tx_ring_p->tx_evmask.value = 0;
334644961713Sgirish 	status = nxge_init_txdma_channel_event_mask(nxgep, channel,
334752ccf843Smisaki 	    &tx_ring_p->tx_evmask);
334844961713Sgirish 	if (status != NXGE_OK)
334944961713Sgirish 		goto fail;
335044961713Sgirish 
335144961713Sgirish 	tx_ring_p->wr_index_wrap = B_FALSE;
335244961713Sgirish 	tx_ring_p->wr_index = 0;
335344961713Sgirish 	tx_ring_p->rd_index = 0;
335444961713Sgirish 
335544961713Sgirish 	/*
335644961713Sgirish 	 * Load TXDMA descriptors, buffers, mailbox,
335744961713Sgirish 	 * initialise the DMA channels and
335844961713Sgirish 	 * enable each DMA channel.
335944961713Sgirish 	 */
336044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel enable..."));
336144961713Sgirish 	status = nxge_enable_txdma_channel(nxgep, channel,
336252ccf843Smisaki 	    tx_ring_p, tx_mbox_p);
336344961713Sgirish 	MUTEX_EXIT(&tx_ring_p->lock);
336444961713Sgirish 	if (status != NXGE_OK)
336544961713Sgirish 		goto fail;
336644961713Sgirish 
336744961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
336852ccf843Smisaki 	    "Recovery Successful, TxDMAChannel#%d Restored",
336952ccf843Smisaki 	    channel));
337044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fatal_err_recover"));
337144961713Sgirish 
337244961713Sgirish 	return (NXGE_OK);
337344961713Sgirish 
337444961713Sgirish fail:
337544961713Sgirish 	MUTEX_EXIT(&tx_ring_p->lock);
33762d99c5d4SMichael Speer 
337744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
337852ccf843Smisaki 	    "nxge_txdma_fatal_err_recover (channel %d): "
337952ccf843Smisaki 	    "failed to recover this txdma channel", channel));
338044961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed"));
338144961713Sgirish 
338244961713Sgirish 	return (status);
338344961713Sgirish }
338444961713Sgirish 
3385678453a8Sspeer /*
3386678453a8Sspeer  * nxge_tx_port_fatal_err_recover
3387678453a8Sspeer  *
3388678453a8Sspeer  *	Attempt to recover from a fatal port error.
3389678453a8Sspeer  *
3390678453a8Sspeer  * Arguments:
3391678453a8Sspeer  * 	nxgep
3392678453a8Sspeer  *
3393678453a8Sspeer  * Notes:
3394678453a8Sspeer  *	How would a guest do this?
3395678453a8Sspeer  *
3396678453a8Sspeer  * NPI/NXGE function calls:
3397678453a8Sspeer  *
3398678453a8Sspeer  * Registers accessed:
3399678453a8Sspeer  *
3400678453a8Sspeer  * Context:
3401678453a8Sspeer  *	Service domain
3402678453a8Sspeer  */
340344961713Sgirish nxge_status_t
340444961713Sgirish nxge_tx_port_fatal_err_recover(p_nxge_t nxgep)
340544961713Sgirish {
3406678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
3407678453a8Sspeer 	nxge_channel_t tdc;
3408678453a8Sspeer 
3409678453a8Sspeer 	tx_ring_t	*ring;
3410678453a8Sspeer 	tx_mbox_t	*mailbox;
3411678453a8Sspeer 
341244961713Sgirish 	npi_handle_t	handle;
3413678453a8Sspeer 	nxge_status_t	status;
3414678453a8Sspeer 	npi_status_t	rs;
341544961713Sgirish 
341644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_tx_port_fatal_err_recover"));
341744961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3418678453a8Sspeer 	    "Recovering from TxPort error..."));
341944961713Sgirish 
3420678453a8Sspeer 	if (isLDOMguest(nxgep)) {
3421678453a8Sspeer 		return (NXGE_OK);
342244961713Sgirish 	}
342344961713Sgirish 
3424678453a8Sspeer 	if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) {
3425678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3426678453a8Sspeer 		    "<== nxge_tx_port_fatal_err_recover: not initialized"));
3427678453a8Sspeer 		return (NXGE_ERROR);
342844961713Sgirish 	}
342944961713Sgirish 
3430678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
3431678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3432678453a8Sspeer 		    "<== nxge_tx_port_fatal_err_recover: "
3433678453a8Sspeer 		    "NULL ring pointer(s)"));
3434678453a8Sspeer 		return (NXGE_ERROR);
3435678453a8Sspeer 	}
343644961713Sgirish 
3437678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3438678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3439678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3440678453a8Sspeer 			if (ring)
3441678453a8Sspeer 				MUTEX_ENTER(&ring->lock);
344244961713Sgirish 		}
344344961713Sgirish 	}
344444961713Sgirish 
3445678453a8Sspeer 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
3446678453a8Sspeer 
344744961713Sgirish 	/*
3448678453a8Sspeer 	 * Stop all the TDCs owned by us.
3449678453a8Sspeer 	 * (The shared TDCs will have been stopped by their owners.)
345044961713Sgirish 	 */
3451678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3452678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3453678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3454678453a8Sspeer 			if (ring) {
3455678453a8Sspeer 				rs = npi_txdma_channel_control
3456678453a8Sspeer 				    (handle, TXDMA_STOP, tdc);
3457678453a8Sspeer 				if (rs != NPI_SUCCESS) {
3458678453a8Sspeer 					NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3459678453a8Sspeer 					    "nxge_tx_port_fatal_err_recover "
3460678453a8Sspeer 					    "(channel %d): stop failed ", tdc));
3461678453a8Sspeer 					goto fail;
3462678453a8Sspeer 				}
3463678453a8Sspeer 			}
346444961713Sgirish 		}
3465678453a8Sspeer 	}
346644961713Sgirish 
3467678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Reclaiming all TDCs..."));
346844961713Sgirish 
3469678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3470678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3471678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
34722d99c5d4SMichael Speer 			if (ring) {
3473678453a8Sspeer 				(void) nxge_txdma_reclaim(nxgep, ring, 0);
34742d99c5d4SMichael Speer 			}
3475678453a8Sspeer 		}
347644961713Sgirish 	}
347744961713Sgirish 
347844961713Sgirish 	/*
3479678453a8Sspeer 	 * Reset all the TDCs.
348044961713Sgirish 	 */
3481678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Resetting 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];
3486678453a8Sspeer 			if (ring) {
3487678453a8Sspeer 				if ((rs = npi_txdma_channel_control
348852ccf843Smisaki 				    (handle, TXDMA_RESET, tdc))
3489678453a8Sspeer 				    != NPI_SUCCESS) {
3490678453a8Sspeer 					NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3491678453a8Sspeer 					    "nxge_tx_port_fatal_err_recover "
3492678453a8Sspeer 					    "(channel %d) reset channel "
3493678453a8Sspeer 					    "failed 0x%x", tdc, rs));
3494678453a8Sspeer 					goto fail;
3495678453a8Sspeer 				}
3496678453a8Sspeer 			}
3497678453a8Sspeer 			/*
3498678453a8Sspeer 			 * Reset the tail (kick) register to 0.
3499678453a8Sspeer 			 * (Hardware will not reset it. Tx overflow fatal
3500678453a8Sspeer 			 * error if tail is not set to 0 after reset!
3501678453a8Sspeer 			 */
3502678453a8Sspeer 			TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, tdc, 0);
350344961713Sgirish 		}
3504678453a8Sspeer 	}
350544961713Sgirish 
3506678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Restarting all TDCs..."));
3507678453a8Sspeer 
3508678453a8Sspeer 	/* Restart all the TDCs */
3509678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3510678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3511678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3512678453a8Sspeer 			if (ring) {
3513678453a8Sspeer 				mailbox = nxge_txdma_get_mbox(nxgep, tdc);
3514678453a8Sspeer 				status = nxge_init_fzc_txdma_channel(nxgep, tdc,
3515678453a8Sspeer 				    ring, mailbox);
3516678453a8Sspeer 				ring->tx_evmask.value = 0;
3517678453a8Sspeer 				/*
3518678453a8Sspeer 				 * Initialize the event masks.
3519678453a8Sspeer 				 */
3520678453a8Sspeer 				status = nxge_init_txdma_channel_event_mask
3521678453a8Sspeer 				    (nxgep, tdc, &ring->tx_evmask);
3522678453a8Sspeer 
3523678453a8Sspeer 				ring->wr_index_wrap = B_FALSE;
3524678453a8Sspeer 				ring->wr_index = 0;
3525678453a8Sspeer 				ring->rd_index = 0;
3526678453a8Sspeer 
3527678453a8Sspeer 				if (status != NXGE_OK)
3528678453a8Sspeer 					goto fail;
3529678453a8Sspeer 				if (status != NXGE_OK)
3530678453a8Sspeer 					goto fail;
3531678453a8Sspeer 			}
3532678453a8Sspeer 		}
353344961713Sgirish 	}
353444961713Sgirish 
3535678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Re-enabling all TDCs..."));
353644961713Sgirish 
3537678453a8Sspeer 	/* Re-enable all the TDCs */
3538678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3539678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3540678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3541678453a8Sspeer 			if (ring) {
3542678453a8Sspeer 				mailbox = nxge_txdma_get_mbox(nxgep, tdc);
3543678453a8Sspeer 				status = nxge_enable_txdma_channel(nxgep, tdc,
3544678453a8Sspeer 				    ring, mailbox);
3545678453a8Sspeer 				if (status != NXGE_OK)
3546678453a8Sspeer 					goto fail;
3547678453a8Sspeer 			}
354844961713Sgirish 		}
354944961713Sgirish 	}
355044961713Sgirish 
3551678453a8Sspeer 	/*
3552678453a8Sspeer 	 * Unlock all the TDCs.
3553678453a8Sspeer 	 */
3554678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3555678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3556678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3557678453a8Sspeer 			if (ring)
3558678453a8Sspeer 				MUTEX_EXIT(&ring->lock);
355944961713Sgirish 		}
356044961713Sgirish 	}
356144961713Sgirish 
3562678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery succeeded"));
356344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover"));
356444961713Sgirish 
356544961713Sgirish 	return (NXGE_OK);
356644961713Sgirish 
356744961713Sgirish fail:
3568678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3569678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3570678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3571678453a8Sspeer 			if (ring)
3572678453a8Sspeer 				MUTEX_EXIT(&ring->lock);
357344961713Sgirish 		}
357444961713Sgirish 	}
357544961713Sgirish 
3576678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery failed"));
3577678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover"));
357844961713Sgirish 
357944961713Sgirish 	return (status);
358044961713Sgirish }
358144961713Sgirish 
3582678453a8Sspeer /*
3583678453a8Sspeer  * nxge_txdma_inject_err
3584678453a8Sspeer  *
3585678453a8Sspeer  *	Inject an error into a TDC.
3586678453a8Sspeer  *
3587678453a8Sspeer  * Arguments:
3588678453a8Sspeer  * 	nxgep
3589678453a8Sspeer  * 	err_id	The error to inject.
3590678453a8Sspeer  * 	chan	The channel to inject into.
3591678453a8Sspeer  *
3592678453a8Sspeer  * Notes:
3593678453a8Sspeer  *	This is called from nxge_main.c:nxge_err_inject()
3594678453a8Sspeer  *	Has this ioctl ever been used?
3595678453a8Sspeer  *
3596678453a8Sspeer  * NPI/NXGE function calls:
3597678453a8Sspeer  *	npi_txdma_inj_par_error_get()
3598678453a8Sspeer  *	npi_txdma_inj_par_error_set()
3599678453a8Sspeer  *
3600678453a8Sspeer  * Registers accessed:
3601678453a8Sspeer  *	TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error
3602678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
3603678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
3604678453a8Sspeer  *
3605678453a8Sspeer  * Context:
3606678453a8Sspeer  *	Service domain
3607678453a8Sspeer  */
360844961713Sgirish void
360944961713Sgirish nxge_txdma_inject_err(p_nxge_t nxgep, uint32_t err_id, uint8_t chan)
361044961713Sgirish {
361144961713Sgirish 	tdmc_intr_dbg_t		tdi;
361244961713Sgirish 	tdmc_inj_par_err_t	par_err;
361344961713Sgirish 	uint32_t		value;
361444961713Sgirish 	npi_handle_t		handle;
361544961713Sgirish 
361644961713Sgirish 	switch (err_id) {
361744961713Sgirish 
361844961713Sgirish 	case NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR:
361944961713Sgirish 		handle = NXGE_DEV_NPI_HANDLE(nxgep);
362044961713Sgirish 		/* Clear error injection source for parity error */
362144961713Sgirish 		(void) npi_txdma_inj_par_error_get(handle, &value);
362244961713Sgirish 		par_err.value = value;
362344961713Sgirish 		par_err.bits.ldw.inject_parity_error &= ~(1 << chan);
362444961713Sgirish 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
362544961713Sgirish 
362644961713Sgirish 		par_err.bits.ldw.inject_parity_error = (1 << chan);
362744961713Sgirish 		(void) npi_txdma_inj_par_error_get(handle, &value);
362844961713Sgirish 		par_err.value = value;
362944961713Sgirish 		par_err.bits.ldw.inject_parity_error |= (1 << chan);
363044961713Sgirish 		cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INJ_PAR_ERR_REG\n",
363152ccf843Smisaki 		    (unsigned long long)par_err.value);
363244961713Sgirish 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
363344961713Sgirish 		break;
363444961713Sgirish 
363544961713Sgirish 	case NXGE_FM_EREPORT_TDMC_MBOX_ERR:
363644961713Sgirish 	case NXGE_FM_EREPORT_TDMC_NACK_PREF:
363744961713Sgirish 	case NXGE_FM_EREPORT_TDMC_NACK_PKT_RD:
363844961713Sgirish 	case NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR:
363944961713Sgirish 	case NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW:
364044961713Sgirish 	case NXGE_FM_EREPORT_TDMC_CONF_PART_ERR:
364144961713Sgirish 	case NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR:
364244961713Sgirish 		TXDMA_REG_READ64(nxgep->npi_handle, TDMC_INTR_DBG_REG,
364352ccf843Smisaki 		    chan, &tdi.value);
364444961713Sgirish 		if (err_id == NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR)
364544961713Sgirish 			tdi.bits.ldw.pref_buf_par_err = 1;
364644961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_MBOX_ERR)
364744961713Sgirish 			tdi.bits.ldw.mbox_err = 1;
364844961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PREF)
364944961713Sgirish 			tdi.bits.ldw.nack_pref = 1;
365044961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PKT_RD)
365144961713Sgirish 			tdi.bits.ldw.nack_pkt_rd = 1;
365244961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR)
365344961713Sgirish 			tdi.bits.ldw.pkt_size_err = 1;
365444961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW)
365544961713Sgirish 			tdi.bits.ldw.tx_ring_oflow = 1;
365644961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_CONF_PART_ERR)
365744961713Sgirish 			tdi.bits.ldw.conf_part_err = 1;
365844961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR)
365944961713Sgirish 			tdi.bits.ldw.pkt_part_err = 1;
3660adfcba55Sjoycey #if defined(__i386)
3661adfcba55Sjoycey 		cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INTR_DBG_REG\n",
366252ccf843Smisaki 		    tdi.value);
3663adfcba55Sjoycey #else
366444961713Sgirish 		cmn_err(CE_NOTE, "!Write 0x%lx to TDMC_INTR_DBG_REG\n",
366552ccf843Smisaki 		    tdi.value);
3666adfcba55Sjoycey #endif
366744961713Sgirish 		TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG,
366852ccf843Smisaki 		    chan, tdi.value);
366944961713Sgirish 
367044961713Sgirish 		break;
367144961713Sgirish 	}
367244961713Sgirish }
3673