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  */
2144961713Sgirish /*
22678453a8Sspeer  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2344961713Sgirish  * Use is subject to license terms.
2444961713Sgirish  */
2544961713Sgirish 
2644961713Sgirish #pragma ident	"%Z%%M%	%I%	%E% SMI"
2744961713Sgirish 
2844961713Sgirish #include <sys/nxge/nxge_impl.h>
2944961713Sgirish #include <sys/nxge/nxge_txdma.h>
30678453a8Sspeer #include <sys/nxge/nxge_hio.h>
31678453a8Sspeer #include <npi_tx_rd64.h>
32678453a8Sspeer #include <npi_tx_wr64.h>
3344961713Sgirish #include <sys/llc1.h>
3444961713Sgirish 
3544961713Sgirish uint32_t 	nxge_reclaim_pending = TXDMA_RECLAIM_PENDING_DEFAULT;
3644961713Sgirish uint32_t	nxge_tx_minfree = 32;
3744961713Sgirish uint32_t	nxge_tx_intr_thres = 0;
3844961713Sgirish uint32_t	nxge_tx_max_gathers = TX_MAX_GATHER_POINTERS;
3944961713Sgirish uint32_t	nxge_tx_tiny_pack = 1;
4044961713Sgirish uint32_t	nxge_tx_use_bcopy = 1;
4144961713Sgirish 
4244961713Sgirish extern uint32_t 	nxge_tx_ring_size;
4344961713Sgirish extern uint32_t 	nxge_bcopy_thresh;
4444961713Sgirish extern uint32_t 	nxge_dvma_thresh;
4544961713Sgirish extern uint32_t 	nxge_dma_stream_thresh;
4644961713Sgirish extern dma_method_t 	nxge_force_dma;
47b4d05839Sml extern uint32_t		nxge_cksum_offload;
4844961713Sgirish 
4944961713Sgirish /* Device register access attributes for PIO.  */
5044961713Sgirish extern ddi_device_acc_attr_t nxge_dev_reg_acc_attr;
5144961713Sgirish /* Device descriptor access attributes for DMA.  */
5244961713Sgirish extern ddi_device_acc_attr_t nxge_dev_desc_dma_acc_attr;
5344961713Sgirish /* Device buffer access attributes for DMA.  */
5444961713Sgirish extern ddi_device_acc_attr_t nxge_dev_buf_dma_acc_attr;
5544961713Sgirish extern ddi_dma_attr_t nxge_desc_dma_attr;
5644961713Sgirish extern ddi_dma_attr_t nxge_tx_dma_attr;
5744961713Sgirish 
581f8914d5Sml extern int nxge_serial_tx(mblk_t *mp, void *arg);
591f8914d5Sml 
60678453a8Sspeer static nxge_status_t nxge_map_txdma(p_nxge_t, int);
6144961713Sgirish 
62678453a8Sspeer static nxge_status_t nxge_txdma_hw_start(p_nxge_t, int);
6344961713Sgirish 
6444961713Sgirish static nxge_status_t nxge_map_txdma_channel(p_nxge_t, uint16_t,
6544961713Sgirish 	p_nxge_dma_common_t *, p_tx_ring_t *,
6644961713Sgirish 	uint32_t, p_nxge_dma_common_t *,
6744961713Sgirish 	p_tx_mbox_t *);
68678453a8Sspeer static void nxge_unmap_txdma_channel(p_nxge_t, uint16_t);
6944961713Sgirish 
7044961713Sgirish static nxge_status_t nxge_map_txdma_channel_buf_ring(p_nxge_t, uint16_t,
7144961713Sgirish 	p_nxge_dma_common_t *, p_tx_ring_t *, uint32_t);
7244961713Sgirish static void nxge_unmap_txdma_channel_buf_ring(p_nxge_t, p_tx_ring_t);
7344961713Sgirish 
7444961713Sgirish static void nxge_map_txdma_channel_cfg_ring(p_nxge_t, uint16_t,
7544961713Sgirish 	p_nxge_dma_common_t *, p_tx_ring_t,
7644961713Sgirish 	p_tx_mbox_t *);
7744961713Sgirish static void nxge_unmap_txdma_channel_cfg_ring(p_nxge_t,
7844961713Sgirish 	p_tx_ring_t, p_tx_mbox_t);
7944961713Sgirish 
8044961713Sgirish static nxge_status_t nxge_txdma_start_channel(p_nxge_t, uint16_t,
8144961713Sgirish     p_tx_ring_t, p_tx_mbox_t);
82678453a8Sspeer static nxge_status_t nxge_txdma_stop_channel(p_nxge_t, uint16_t);
8344961713Sgirish 
8444961713Sgirish static p_tx_ring_t nxge_txdma_get_ring(p_nxge_t, uint16_t);
8544961713Sgirish static nxge_status_t nxge_tx_err_evnts(p_nxge_t, uint_t,
8644961713Sgirish 	p_nxge_ldv_t, tx_cs_t);
8744961713Sgirish static p_tx_mbox_t nxge_txdma_get_mbox(p_nxge_t, uint16_t);
8844961713Sgirish static nxge_status_t nxge_txdma_fatal_err_recover(p_nxge_t,
8944961713Sgirish 	uint16_t, p_tx_ring_t);
9044961713Sgirish 
91678453a8Sspeer static void nxge_txdma_fixup_hung_channel(p_nxge_t nxgep,
92678453a8Sspeer     p_tx_ring_t ring_p, uint16_t channel);
93678453a8Sspeer 
9444961713Sgirish nxge_status_t
9544961713Sgirish nxge_init_txdma_channels(p_nxge_t nxgep)
9644961713Sgirish {
97678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
98678453a8Sspeer 	int i, count;
99678453a8Sspeer 
100678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "==> nxge_init_txdma_channels"));
101678453a8Sspeer 
102678453a8Sspeer 	for (i = 0, count = 0; i < NXGE_LOGICAL_GROUP_MAX; i++) {
103678453a8Sspeer 		if ((1 << i) & set->lg.map) {
104678453a8Sspeer 			int tdc;
105678453a8Sspeer 			nxge_grp_t *group = set->group[i];
106678453a8Sspeer 			for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
107678453a8Sspeer 				if ((1 << tdc) & group->map) {
108678453a8Sspeer 					if ((nxge_grp_dc_add(nxgep,
109678453a8Sspeer 						(vr_handle_t)group,
110678453a8Sspeer 						VP_BOUND_TX, tdc)))
111678453a8Sspeer 						return (NXGE_ERROR);
112678453a8Sspeer 				}
113678453a8Sspeer 			}
114678453a8Sspeer 		}
115678453a8Sspeer 		if (++count == set->lg.count)
116678453a8Sspeer 			break;
117678453a8Sspeer 	}
118678453a8Sspeer 
119678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_init_txdma_channels"));
120678453a8Sspeer 
121678453a8Sspeer 	return (NXGE_OK);
122678453a8Sspeer }
123678453a8Sspeer 
124678453a8Sspeer nxge_status_t
125678453a8Sspeer nxge_init_txdma_channel(
126678453a8Sspeer 	p_nxge_t nxge,
127678453a8Sspeer 	int channel)
128678453a8Sspeer {
129678453a8Sspeer 	nxge_status_t status;
13044961713Sgirish 
131678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, MEM2_CTL, "==> nxge_init_txdma_channel"));
13244961713Sgirish 
133678453a8Sspeer 	status = nxge_map_txdma(nxge, channel);
13444961713Sgirish 	if (status != NXGE_OK) {
135678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
136678453a8Sspeer 		    "<== nxge_init_txdma_channel: status 0x%x", status));
137678453a8Sspeer 		(void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel);
13844961713Sgirish 		return (status);
13944961713Sgirish 	}
14044961713Sgirish 
141678453a8Sspeer 	status = nxge_txdma_hw_start(nxge, channel);
14244961713Sgirish 	if (status != NXGE_OK) {
143678453a8Sspeer 		(void) nxge_unmap_txdma_channel(nxge, channel);
144678453a8Sspeer 		(void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel);
14544961713Sgirish 		return (status);
14644961713Sgirish 	}
14744961713Sgirish 
148678453a8Sspeer 	if (!nxge->statsp->tdc_ksp[channel])
149678453a8Sspeer 		nxge_setup_tdc_kstats(nxge, channel);
15044961713Sgirish 
151678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, MEM2_CTL, "<== nxge_init_txdma_channel"));
152678453a8Sspeer 
153678453a8Sspeer 	return (status);
15444961713Sgirish }
15544961713Sgirish 
15644961713Sgirish void
15744961713Sgirish nxge_uninit_txdma_channels(p_nxge_t nxgep)
15844961713Sgirish {
159678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
160678453a8Sspeer 	int tdc;
161678453a8Sspeer 
162678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "==> nxge_uninit_txdma_channels"));
163678453a8Sspeer 
164678453a8Sspeer 	if (set->owned.map == 0) {
165678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, MEM2_CTL,
166678453a8Sspeer 		    "nxge_uninit_txdma_channels: no channels"));
167678453a8Sspeer 		return;
168678453a8Sspeer 	}
169678453a8Sspeer 
170678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
171678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
172678453a8Sspeer 			nxge_grp_dc_remove(nxgep, VP_BOUND_TX, tdc);
173678453a8Sspeer 		}
174678453a8Sspeer 	}
175678453a8Sspeer 
176678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_uninit_txdma_channels"));
177678453a8Sspeer }
178678453a8Sspeer 
179678453a8Sspeer void
180678453a8Sspeer nxge_uninit_txdma_channel(p_nxge_t nxgep, int channel)
181678453a8Sspeer {
182678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_uninit_txdma_channel"));
183678453a8Sspeer 
184678453a8Sspeer 	if (nxgep->statsp->tdc_ksp[channel]) {
185678453a8Sspeer 		kstat_delete(nxgep->statsp->tdc_ksp[channel]);
186678453a8Sspeer 		nxgep->statsp->tdc_ksp[channel] = 0;
187678453a8Sspeer 	}
18844961713Sgirish 
189678453a8Sspeer 	(void) nxge_txdma_stop_channel(nxgep, channel);
190678453a8Sspeer 	nxge_unmap_txdma_channel(nxgep, channel);
19144961713Sgirish 
19244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
193678453a8Sspeer 		"<== nxge_uninit_txdma_channel"));
19444961713Sgirish }
19544961713Sgirish 
19644961713Sgirish void
19744961713Sgirish nxge_setup_dma_common(p_nxge_dma_common_t dest_p, p_nxge_dma_common_t src_p,
19844961713Sgirish 	uint32_t entries, uint32_t size)
19944961713Sgirish {
20044961713Sgirish 	size_t		tsize;
20144961713Sgirish 	*dest_p = *src_p;
20244961713Sgirish 	tsize = size * entries;
20344961713Sgirish 	dest_p->alength = tsize;
20444961713Sgirish 	dest_p->nblocks = entries;
20544961713Sgirish 	dest_p->block_size = size;
20644961713Sgirish 	dest_p->offset += tsize;
20744961713Sgirish 
20844961713Sgirish 	src_p->kaddrp = (caddr_t)dest_p->kaddrp + tsize;
20944961713Sgirish 	src_p->alength -= tsize;
21044961713Sgirish 	src_p->dma_cookie.dmac_laddress += tsize;
21144961713Sgirish 	src_p->dma_cookie.dmac_size -= tsize;
21244961713Sgirish }
21344961713Sgirish 
214678453a8Sspeer /*
215678453a8Sspeer  * nxge_reset_txdma_channel
216678453a8Sspeer  *
217678453a8Sspeer  *	Reset a TDC.
218678453a8Sspeer  *
219678453a8Sspeer  * Arguments:
220678453a8Sspeer  * 	nxgep
221678453a8Sspeer  * 	channel		The channel to reset.
222678453a8Sspeer  * 	reg_data	The current TX_CS.
223678453a8Sspeer  *
224678453a8Sspeer  * Notes:
225678453a8Sspeer  *
226678453a8Sspeer  * NPI/NXGE function calls:
227678453a8Sspeer  *	npi_txdma_channel_reset()
228678453a8Sspeer  *	npi_txdma_channel_control()
229678453a8Sspeer  *
230678453a8Sspeer  * Registers accessed:
231678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
232678453a8Sspeer  *	TX_RING_KICK	DMC+0x40018 Transmit Ring Kick
233678453a8Sspeer  *
234678453a8Sspeer  * Context:
235678453a8Sspeer  *	Any domain
236678453a8Sspeer  */
23744961713Sgirish nxge_status_t
23844961713Sgirish nxge_reset_txdma_channel(p_nxge_t nxgep, uint16_t channel, uint64_t reg_data)
23944961713Sgirish {
24044961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
24144961713Sgirish 	nxge_status_t		status = NXGE_OK;
24244961713Sgirish 	npi_handle_t		handle;
24344961713Sgirish 
24444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, " ==> nxge_reset_txdma_channel"));
24544961713Sgirish 
24644961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
24744961713Sgirish 	if ((reg_data & TX_CS_RST_MASK) == TX_CS_RST_MASK) {
24844961713Sgirish 		rs = npi_txdma_channel_reset(handle, channel);
24944961713Sgirish 	} else {
25044961713Sgirish 		rs = npi_txdma_channel_control(handle, TXDMA_RESET,
25144961713Sgirish 				channel);
25244961713Sgirish 	}
25344961713Sgirish 
25444961713Sgirish 	if (rs != NPI_SUCCESS) {
25544961713Sgirish 		status = NXGE_ERROR | rs;
25644961713Sgirish 	}
25744961713Sgirish 
25844961713Sgirish 	/*
25944961713Sgirish 	 * Reset the tail (kick) register to 0.
26044961713Sgirish 	 * (Hardware will not reset it. Tx overflow fatal
26144961713Sgirish 	 * error if tail is not set to 0 after reset!
26244961713Sgirish 	 */
26344961713Sgirish 	TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0);
26444961713Sgirish 
26544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, " <== nxge_reset_txdma_channel"));
26644961713Sgirish 	return (status);
26744961713Sgirish }
26844961713Sgirish 
269678453a8Sspeer /*
270678453a8Sspeer  * nxge_init_txdma_channel_event_mask
271678453a8Sspeer  *
272678453a8Sspeer  *	Enable interrupts for a set of events.
273678453a8Sspeer  *
274678453a8Sspeer  * Arguments:
275678453a8Sspeer  * 	nxgep
276678453a8Sspeer  * 	channel	The channel to map.
277678453a8Sspeer  * 	mask_p	The events to enable.
278678453a8Sspeer  *
279678453a8Sspeer  * Notes:
280678453a8Sspeer  *
281678453a8Sspeer  * NPI/NXGE function calls:
282678453a8Sspeer  *	npi_txdma_event_mask()
283678453a8Sspeer  *
284678453a8Sspeer  * Registers accessed:
285678453a8Sspeer  *	TX_ENT_MSK	DMC+0x40020 Transmit Event Mask
286678453a8Sspeer  *
287678453a8Sspeer  * Context:
288678453a8Sspeer  *	Any domain
289678453a8Sspeer  */
29044961713Sgirish nxge_status_t
29144961713Sgirish nxge_init_txdma_channel_event_mask(p_nxge_t nxgep, uint16_t channel,
29244961713Sgirish 		p_tx_dma_ent_msk_t mask_p)
29344961713Sgirish {
29444961713Sgirish 	npi_handle_t		handle;
29544961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
29644961713Sgirish 	nxge_status_t		status = NXGE_OK;
29744961713Sgirish 
29844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
29944961713Sgirish 		"<== nxge_init_txdma_channel_event_mask"));
30044961713Sgirish 
30144961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
30244961713Sgirish 	rs = npi_txdma_event_mask(handle, OP_SET, channel, mask_p);
30344961713Sgirish 	if (rs != NPI_SUCCESS) {
30444961713Sgirish 		status = NXGE_ERROR | rs;
30544961713Sgirish 	}
30644961713Sgirish 
30744961713Sgirish 	return (status);
30844961713Sgirish }
30944961713Sgirish 
310678453a8Sspeer /*
311678453a8Sspeer  * nxge_init_txdma_channel_cntl_stat
312678453a8Sspeer  *
313678453a8Sspeer  *	Stop a TDC.  If at first we don't succeed, inject an error.
314678453a8Sspeer  *
315678453a8Sspeer  * Arguments:
316678453a8Sspeer  * 	nxgep
317678453a8Sspeer  * 	channel		The channel to stop.
318678453a8Sspeer  *
319678453a8Sspeer  * Notes:
320678453a8Sspeer  *
321678453a8Sspeer  * NPI/NXGE function calls:
322678453a8Sspeer  *	npi_txdma_control_status()
323678453a8Sspeer  *
324678453a8Sspeer  * Registers accessed:
325678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
326678453a8Sspeer  *
327678453a8Sspeer  * Context:
328678453a8Sspeer  *	Any domain
329678453a8Sspeer  */
33044961713Sgirish nxge_status_t
33144961713Sgirish nxge_init_txdma_channel_cntl_stat(p_nxge_t nxgep, uint16_t channel,
33244961713Sgirish 	uint64_t reg_data)
33344961713Sgirish {
33444961713Sgirish 	npi_handle_t		handle;
33544961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
33644961713Sgirish 	nxge_status_t		status = NXGE_OK;
33744961713Sgirish 
33844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
33944961713Sgirish 		"<== nxge_init_txdma_channel_cntl_stat"));
34044961713Sgirish 
34144961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
34244961713Sgirish 	rs = npi_txdma_control_status(handle, OP_SET, channel,
34344961713Sgirish 			(p_tx_cs_t)&reg_data);
34444961713Sgirish 
34544961713Sgirish 	if (rs != NPI_SUCCESS) {
34644961713Sgirish 		status = NXGE_ERROR | rs;
34744961713Sgirish 	}
34844961713Sgirish 
34944961713Sgirish 	return (status);
35044961713Sgirish }
35144961713Sgirish 
352678453a8Sspeer /*
353678453a8Sspeer  * nxge_enable_txdma_channel
354678453a8Sspeer  *
355678453a8Sspeer  *	Enable a TDC.
356678453a8Sspeer  *
357678453a8Sspeer  * Arguments:
358678453a8Sspeer  * 	nxgep
359678453a8Sspeer  * 	channel		The channel to enable.
360678453a8Sspeer  * 	tx_desc_p	channel's transmit descriptor ring.
361678453a8Sspeer  * 	mbox_p		channel's mailbox,
362678453a8Sspeer  *
363678453a8Sspeer  * Notes:
364678453a8Sspeer  *
365678453a8Sspeer  * NPI/NXGE function calls:
366678453a8Sspeer  *	npi_txdma_ring_config()
367678453a8Sspeer  *	npi_txdma_mbox_config()
368678453a8Sspeer  *	npi_txdma_channel_init_enable()
369678453a8Sspeer  *
370678453a8Sspeer  * Registers accessed:
371678453a8Sspeer  *	TX_RNG_CFIG	DMC+0x40000 Transmit Ring Configuration
372678453a8Sspeer  *	TXDMA_MBH	DMC+0x40030 TXDMA Mailbox High
373678453a8Sspeer  *	TXDMA_MBL	DMC+0x40038 TXDMA Mailbox Low
374678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
375678453a8Sspeer  *
376678453a8Sspeer  * Context:
377678453a8Sspeer  *	Any domain
378678453a8Sspeer  */
37944961713Sgirish nxge_status_t
38044961713Sgirish nxge_enable_txdma_channel(p_nxge_t nxgep,
38144961713Sgirish 	uint16_t channel, p_tx_ring_t tx_desc_p, p_tx_mbox_t mbox_p)
38244961713Sgirish {
38344961713Sgirish 	npi_handle_t		handle;
38444961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
38544961713Sgirish 	nxge_status_t		status = NXGE_OK;
38644961713Sgirish 
38744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_enable_txdma_channel"));
38844961713Sgirish 
38944961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
39044961713Sgirish 	/*
39144961713Sgirish 	 * Use configuration data composed at init time.
39244961713Sgirish 	 * Write to hardware the transmit ring configurations.
39344961713Sgirish 	 */
39444961713Sgirish 	rs = npi_txdma_ring_config(handle, OP_SET, channel,
395678453a8Sspeer 	    (uint64_t *)&(tx_desc_p->tx_ring_cfig.value));
39644961713Sgirish 
39744961713Sgirish 	if (rs != NPI_SUCCESS) {
39844961713Sgirish 		return (NXGE_ERROR | rs);
39944961713Sgirish 	}
40044961713Sgirish 
401678453a8Sspeer 	if (isLDOMguest(nxgep)) {
402678453a8Sspeer 		/* Add interrupt handler for this channel. */
403678453a8Sspeer 		if (nxge_hio_intr_add(nxgep, VP_BOUND_TX, channel) != NXGE_OK)
404678453a8Sspeer 			return (NXGE_ERROR);
405678453a8Sspeer 	}
406678453a8Sspeer 
40744961713Sgirish 	/* Write to hardware the mailbox */
40844961713Sgirish 	rs = npi_txdma_mbox_config(handle, OP_SET, channel,
40944961713Sgirish 		(uint64_t *)&mbox_p->tx_mbox.dma_cookie.dmac_laddress);
41044961713Sgirish 
41144961713Sgirish 	if (rs != NPI_SUCCESS) {
41244961713Sgirish 		return (NXGE_ERROR | rs);
41344961713Sgirish 	}
41444961713Sgirish 
41544961713Sgirish 	/* Start the DMA engine. */
41644961713Sgirish 	rs = npi_txdma_channel_init_enable(handle, channel);
41744961713Sgirish 
41844961713Sgirish 	if (rs != NPI_SUCCESS) {
41944961713Sgirish 		return (NXGE_ERROR | rs);
42044961713Sgirish 	}
42144961713Sgirish 
42244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_enable_txdma_channel"));
42344961713Sgirish 
42444961713Sgirish 	return (status);
42544961713Sgirish }
42644961713Sgirish 
42744961713Sgirish void
42844961713Sgirish nxge_fill_tx_hdr(p_mblk_t mp, boolean_t fill_len,
42944961713Sgirish 		boolean_t l4_cksum, int pkt_len, uint8_t npads,
430b4d05839Sml 		p_tx_pkt_hdr_all_t pkthdrp,
431b4d05839Sml 		t_uscalar_t start_offset,
432b4d05839Sml 		t_uscalar_t stuff_offset)
43344961713Sgirish {
43444961713Sgirish 	p_tx_pkt_header_t	hdrp;
43544961713Sgirish 	p_mblk_t 		nmp;
43644961713Sgirish 	uint64_t		tmp;
43744961713Sgirish 	size_t 			mblk_len;
43844961713Sgirish 	size_t 			iph_len;
43944961713Sgirish 	size_t 			hdrs_size;
44044961713Sgirish 	uint8_t			hdrs_buf[sizeof (struct ether_header) +
44144961713Sgirish 					64 + sizeof (uint32_t)];
442ae2d3f74Smisaki 	uint8_t			*cursor;
44344961713Sgirish 	uint8_t 		*ip_buf;
44444961713Sgirish 	uint16_t		eth_type;
44544961713Sgirish 	uint8_t			ipproto;
44644961713Sgirish 	boolean_t		is_vlan = B_FALSE;
44744961713Sgirish 	size_t			eth_hdr_size;
44844961713Sgirish 
44944961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: mp $%p", mp));
45044961713Sgirish 
45144961713Sgirish 	/*
45244961713Sgirish 	 * Caller should zero out the headers first.
45344961713Sgirish 	 */
45444961713Sgirish 	hdrp = (p_tx_pkt_header_t)&pkthdrp->pkthdr;
45544961713Sgirish 
45644961713Sgirish 	if (fill_len) {
45744961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
45844961713Sgirish 			"==> nxge_fill_tx_hdr: pkt_len %d "
45944961713Sgirish 			"npads %d", pkt_len, npads));
46044961713Sgirish 		tmp = (uint64_t)pkt_len;
46144961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_TOT_XFER_LEN_SHIFT);
46244961713Sgirish 		goto fill_tx_header_done;
46344961713Sgirish 	}
46444961713Sgirish 
465b4d05839Sml 	hdrp->value |= (((uint64_t)npads) << TX_PKT_HEADER_PAD_SHIFT);
46644961713Sgirish 
46744961713Sgirish 	/*
46844961713Sgirish 	 * mp is the original data packet (does not include the
46944961713Sgirish 	 * Neptune transmit header).
47044961713Sgirish 	 */
47144961713Sgirish 	nmp = mp;
47244961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: "
47344961713Sgirish 		"mp $%p b_rptr $%p len %d",
474ae2d3f74Smisaki 		mp, nmp->b_rptr, MBLKL(nmp)));
475ae2d3f74Smisaki 	/* copy ether_header from mblk to hdrs_buf */
476ae2d3f74Smisaki 	cursor = &hdrs_buf[0];
477ae2d3f74Smisaki 	tmp = sizeof (struct ether_vlan_header);
478ae2d3f74Smisaki 	while ((nmp != NULL) && (tmp > 0)) {
479ae2d3f74Smisaki 		size_t buflen;
480ae2d3f74Smisaki 		mblk_len = MBLKL(nmp);
4817c29db66Smisaki 		buflen = min((size_t)tmp, mblk_len);
482ae2d3f74Smisaki 		bcopy(nmp->b_rptr, cursor, buflen);
483ae2d3f74Smisaki 		cursor += buflen;
484ae2d3f74Smisaki 		tmp -= buflen;
485ae2d3f74Smisaki 		nmp = nmp->b_cont;
486ae2d3f74Smisaki 	}
487ae2d3f74Smisaki 
488ae2d3f74Smisaki 	nmp = mp;
489ae2d3f74Smisaki 	mblk_len = MBLKL(nmp);
49044961713Sgirish 	ip_buf = NULL;
49144961713Sgirish 	eth_type = ntohs(((p_ether_header_t)hdrs_buf)->ether_type);
49244961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> : nxge_fill_tx_hdr: (value 0x%llx) "
49344961713Sgirish 		"ether type 0x%x", eth_type, hdrp->value));
49444961713Sgirish 
49544961713Sgirish 	if (eth_type < ETHERMTU) {
49644961713Sgirish 		tmp = 1ull;
49744961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_LLC_SHIFT);
49844961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: LLC "
49944961713Sgirish 			"value 0x%llx", hdrp->value));
50044961713Sgirish 		if (*(hdrs_buf + sizeof (struct ether_header))
50144961713Sgirish 				== LLC_SNAP_SAP) {
50244961713Sgirish 			eth_type = ntohs(*((uint16_t *)(hdrs_buf +
50344961713Sgirish 					sizeof (struct ether_header) + 6)));
50444961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
50544961713Sgirish 				"==> nxge_tx_pkt_hdr_init: LLC ether type 0x%x",
50644961713Sgirish 				eth_type));
50744961713Sgirish 		} else {
50844961713Sgirish 			goto fill_tx_header_done;
50944961713Sgirish 		}
51044961713Sgirish 	} else if (eth_type == VLAN_ETHERTYPE) {
51144961713Sgirish 		tmp = 1ull;
51244961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_VLAN__SHIFT);
51344961713Sgirish 
51444961713Sgirish 		eth_type = ntohs(((struct ether_vlan_header *)
51544961713Sgirish 			hdrs_buf)->ether_type);
51644961713Sgirish 		is_vlan = B_TRUE;
51744961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: VLAN "
51844961713Sgirish 			"value 0x%llx", hdrp->value));
51944961713Sgirish 	}
52044961713Sgirish 
52144961713Sgirish 	if (!is_vlan) {
52244961713Sgirish 		eth_hdr_size = sizeof (struct ether_header);
52344961713Sgirish 	} else {
52444961713Sgirish 		eth_hdr_size = sizeof (struct ether_vlan_header);
52544961713Sgirish 	}
52644961713Sgirish 
52744961713Sgirish 	switch (eth_type) {
52844961713Sgirish 	case ETHERTYPE_IP:
52944961713Sgirish 		if (mblk_len > eth_hdr_size + sizeof (uint8_t)) {
53044961713Sgirish 			ip_buf = nmp->b_rptr + eth_hdr_size;
53144961713Sgirish 			mblk_len -= eth_hdr_size;
53244961713Sgirish 			iph_len = ((*ip_buf) & 0x0f);
53344961713Sgirish 			if (mblk_len > (iph_len + sizeof (uint32_t))) {
53444961713Sgirish 				ip_buf = nmp->b_rptr;
53544961713Sgirish 				ip_buf += eth_hdr_size;
53644961713Sgirish 			} else {
53744961713Sgirish 				ip_buf = NULL;
53844961713Sgirish 			}
53944961713Sgirish 
54044961713Sgirish 		}
54144961713Sgirish 		if (ip_buf == NULL) {
54244961713Sgirish 			hdrs_size = 0;
54344961713Sgirish 			((p_ether_header_t)hdrs_buf)->ether_type = 0;
54444961713Sgirish 			while ((nmp) && (hdrs_size <
54544961713Sgirish 					sizeof (hdrs_buf))) {
54644961713Sgirish 				mblk_len = (size_t)nmp->b_wptr -
54744961713Sgirish 					(size_t)nmp->b_rptr;
54844961713Sgirish 				if (mblk_len >=
54944961713Sgirish 					(sizeof (hdrs_buf) - hdrs_size))
55044961713Sgirish 					mblk_len = sizeof (hdrs_buf) -
55144961713Sgirish 						hdrs_size;
55244961713Sgirish 				bcopy(nmp->b_rptr,
55344961713Sgirish 					&hdrs_buf[hdrs_size], mblk_len);
55444961713Sgirish 				hdrs_size += mblk_len;
55544961713Sgirish 				nmp = nmp->b_cont;
55644961713Sgirish 			}
55744961713Sgirish 			ip_buf = hdrs_buf;
55844961713Sgirish 			ip_buf += eth_hdr_size;
55944961713Sgirish 			iph_len = ((*ip_buf) & 0x0f);
56044961713Sgirish 		}
56144961713Sgirish 
56244961713Sgirish 		ipproto = ip_buf[9];
56344961713Sgirish 
56444961713Sgirish 		tmp = (uint64_t)iph_len;
56544961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_IHL_SHIFT);
56644961713Sgirish 		tmp = (uint64_t)(eth_hdr_size >> 1);
56744961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT);
56844961713Sgirish 
56944961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv4 "
57044961713Sgirish 			" iph_len %d l3start %d eth_hdr_size %d proto 0x%x"
57144961713Sgirish 			"tmp 0x%x",
57244961713Sgirish 			iph_len, hdrp->bits.hdw.l3start, eth_hdr_size,
57344961713Sgirish 			ipproto, tmp));
57444961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IP "
57544961713Sgirish 			"value 0x%llx", hdrp->value));
57644961713Sgirish 
57744961713Sgirish 		break;
57844961713Sgirish 
57944961713Sgirish 	case ETHERTYPE_IPV6:
58044961713Sgirish 		hdrs_size = 0;
58144961713Sgirish 		((p_ether_header_t)hdrs_buf)->ether_type = 0;
58244961713Sgirish 		while ((nmp) && (hdrs_size <
58344961713Sgirish 				sizeof (hdrs_buf))) {
58444961713Sgirish 			mblk_len = (size_t)nmp->b_wptr - (size_t)nmp->b_rptr;
58544961713Sgirish 			if (mblk_len >=
58644961713Sgirish 				(sizeof (hdrs_buf) - hdrs_size))
58744961713Sgirish 				mblk_len = sizeof (hdrs_buf) -
58844961713Sgirish 					hdrs_size;
58944961713Sgirish 			bcopy(nmp->b_rptr,
59044961713Sgirish 				&hdrs_buf[hdrs_size], mblk_len);
59144961713Sgirish 			hdrs_size += mblk_len;
59244961713Sgirish 			nmp = nmp->b_cont;
59344961713Sgirish 		}
59444961713Sgirish 		ip_buf = hdrs_buf;
59544961713Sgirish 		ip_buf += eth_hdr_size;
59644961713Sgirish 
59744961713Sgirish 		tmp = 1ull;
59844961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_IP_VER_SHIFT);
59944961713Sgirish 
60044961713Sgirish 		tmp = (eth_hdr_size >> 1);
60144961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT);
60244961713Sgirish 
60344961713Sgirish 		/* byte 6 is the next header protocol */
60444961713Sgirish 		ipproto = ip_buf[6];
60544961713Sgirish 
60644961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv6 "
60744961713Sgirish 			" iph_len %d l3start %d eth_hdr_size %d proto 0x%x",
60844961713Sgirish 			iph_len, hdrp->bits.hdw.l3start, eth_hdr_size,
60944961713Sgirish 			ipproto));
61044961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IPv6 "
61144961713Sgirish 			"value 0x%llx", hdrp->value));
61244961713Sgirish 
61344961713Sgirish 		break;
61444961713Sgirish 
61544961713Sgirish 	default:
61644961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: non-IP"));
61744961713Sgirish 		goto fill_tx_header_done;
61844961713Sgirish 	}
61944961713Sgirish 
62044961713Sgirish 	switch (ipproto) {
62144961713Sgirish 	case IPPROTO_TCP:
62244961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
623b4d05839Sml 		    "==> nxge_fill_tx_hdr: TCP (cksum flag %d)", l4_cksum));
62444961713Sgirish 		if (l4_cksum) {
625b4d05839Sml 			hdrp->value |= TX_CKSUM_EN_PKT_TYPE_TCP;
626b4d05839Sml 			hdrp->value |=
627b4d05839Sml 			    (((uint64_t)(start_offset >> 1)) <<
628b4d05839Sml 			    TX_PKT_HEADER_L4START_SHIFT);
629b4d05839Sml 			hdrp->value |=
630b4d05839Sml 			    (((uint64_t)(stuff_offset >> 1)) <<
631b4d05839Sml 			    TX_PKT_HEADER_L4STUFF_SHIFT);
632b4d05839Sml 
63344961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
634b4d05839Sml 			    "==> nxge_tx_pkt_hdr_init: TCP CKSUM "
635b4d05839Sml 			    "value 0x%llx", hdrp->value));
63644961713Sgirish 		}
63744961713Sgirish 
63844961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: TCP "
639b4d05839Sml 		    "value 0x%llx", hdrp->value));
64044961713Sgirish 		break;
64144961713Sgirish 
64244961713Sgirish 	case IPPROTO_UDP:
64344961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: UDP"));
64444961713Sgirish 		if (l4_cksum) {
645b4d05839Sml 			if (!nxge_cksum_offload) {
646b4d05839Sml 				uint16_t	*up;
647b4d05839Sml 				uint16_t	cksum;
648b4d05839Sml 				t_uscalar_t	stuff_len;
649b4d05839Sml 
650b4d05839Sml 				/*
651b4d05839Sml 				 * The checksum field has the
652b4d05839Sml 				 * partial checksum.
653b4d05839Sml 				 * IP_CSUM() macro calls ip_cksum() which
654b4d05839Sml 				 * can add in the partial checksum.
655b4d05839Sml 				 */
656b4d05839Sml 				cksum = IP_CSUM(mp, start_offset, 0);
657b4d05839Sml 				stuff_len = stuff_offset;
658b4d05839Sml 				nmp = mp;
659b4d05839Sml 				mblk_len = MBLKL(nmp);
660b4d05839Sml 				while ((nmp != NULL) &&
661b4d05839Sml 				    (mblk_len < stuff_len)) {
662b4d05839Sml 					stuff_len -= mblk_len;
663b4d05839Sml 					nmp = nmp->b_cont;
664b4d05839Sml 				}
665b4d05839Sml 				ASSERT(nmp);
666b4d05839Sml 				up = (uint16_t *)(nmp->b_rptr + stuff_len);
667b4d05839Sml 
668b4d05839Sml 				*up = cksum;
669b4d05839Sml 				hdrp->value &= ~TX_CKSUM_EN_PKT_TYPE_UDP;
670b4d05839Sml 				NXGE_DEBUG_MSG((NULL, TX_CTL,
671b4d05839Sml 				    "==> nxge_tx_pkt_hdr_init: UDP offset %d "
672b4d05839Sml 				    "use sw cksum "
673b4d05839Sml 				    "write to $%p cksum 0x%x content up 0x%x",
674b4d05839Sml 				    stuff_len,
675b4d05839Sml 				    up,
676b4d05839Sml 				    cksum,
677b4d05839Sml 				    *up));
678b4d05839Sml 			} else {
679b4d05839Sml 				/* Hardware will compute the full checksum */
680b4d05839Sml 				hdrp->value |= TX_CKSUM_EN_PKT_TYPE_UDP;
681b4d05839Sml 				hdrp->value |=
682b4d05839Sml 				    (((uint64_t)(start_offset >> 1)) <<
683b4d05839Sml 				    TX_PKT_HEADER_L4START_SHIFT);
684b4d05839Sml 				hdrp->value |=
685b4d05839Sml 				    (((uint64_t)(stuff_offset >> 1)) <<
686b4d05839Sml 				    TX_PKT_HEADER_L4STUFF_SHIFT);
687b4d05839Sml 
688b4d05839Sml 				NXGE_DEBUG_MSG((NULL, TX_CTL,
689b4d05839Sml 				    "==> nxge_tx_pkt_hdr_init: UDP offset %d "
690b4d05839Sml 				    " use partial checksum "
691b4d05839Sml 				    "cksum 0x%x ",
692b4d05839Sml 				    "value 0x%llx",
693b4d05839Sml 				    stuff_offset,
694b4d05839Sml 				    IP_CSUM(mp, start_offset, 0),
695b4d05839Sml 				    hdrp->value));
696b4d05839Sml 			}
69744961713Sgirish 		}
698b4d05839Sml 
69944961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
70044961713Sgirish 			"==> nxge_tx_pkt_hdr_init: UDP"
70144961713Sgirish 			"value 0x%llx", hdrp->value));
70244961713Sgirish 		break;
70344961713Sgirish 
70444961713Sgirish 	default:
70544961713Sgirish 		goto fill_tx_header_done;
70644961713Sgirish 	}
70744961713Sgirish 
70844961713Sgirish fill_tx_header_done:
70944961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
71044961713Sgirish 		"==> nxge_fill_tx_hdr: pkt_len %d  "
71144961713Sgirish 		"npads %d value 0x%llx", pkt_len, npads, hdrp->value));
71244961713Sgirish 
71344961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "<== nxge_fill_tx_hdr"));
71444961713Sgirish }
71544961713Sgirish 
71644961713Sgirish /*ARGSUSED*/
71744961713Sgirish p_mblk_t
71844961713Sgirish nxge_tx_pkt_header_reserve(p_mblk_t mp, uint8_t *npads)
71944961713Sgirish {
72044961713Sgirish 	p_mblk_t 		newmp = NULL;
72144961713Sgirish 
72244961713Sgirish 	if ((newmp = allocb(TX_PKT_HEADER_SIZE, BPRI_MED)) == NULL) {
72344961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
72444961713Sgirish 			"<== nxge_tx_pkt_header_reserve: allocb failed"));
72544961713Sgirish 		return (NULL);
72644961713Sgirish 	}
72744961713Sgirish 
72844961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
72944961713Sgirish 		"==> nxge_tx_pkt_header_reserve: get new mp"));
73044961713Sgirish 	DB_TYPE(newmp) = M_DATA;
73144961713Sgirish 	newmp->b_rptr = newmp->b_wptr = DB_LIM(newmp);
73244961713Sgirish 	linkb(newmp, mp);
73344961713Sgirish 	newmp->b_rptr -= TX_PKT_HEADER_SIZE;
73444961713Sgirish 
73544961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==>nxge_tx_pkt_header_reserve: "
73644961713Sgirish 		"b_rptr $%p b_wptr $%p",
73744961713Sgirish 		newmp->b_rptr, newmp->b_wptr));
73844961713Sgirish 
73944961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
74044961713Sgirish 		"<== nxge_tx_pkt_header_reserve: use new mp"));
74144961713Sgirish 
74244961713Sgirish 	return (newmp);
74344961713Sgirish }
74444961713Sgirish 
74544961713Sgirish int
74644961713Sgirish nxge_tx_pkt_nmblocks(p_mblk_t mp, int *tot_xfer_len_p)
74744961713Sgirish {
74844961713Sgirish 	uint_t 			nmblks;
74944961713Sgirish 	ssize_t			len;
75044961713Sgirish 	uint_t 			pkt_len;
75144961713Sgirish 	p_mblk_t 		nmp, bmp, tmp;
75244961713Sgirish 	uint8_t 		*b_wptr;
75344961713Sgirish 
75444961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
75544961713Sgirish 		"==> nxge_tx_pkt_nmblocks: mp $%p rptr $%p wptr $%p "
75644961713Sgirish 		"len %d", mp, mp->b_rptr, mp->b_wptr, MBLKL(mp)));
75744961713Sgirish 
75844961713Sgirish 	nmp = mp;
75944961713Sgirish 	bmp = mp;
76044961713Sgirish 	nmblks = 0;
76144961713Sgirish 	pkt_len = 0;
76244961713Sgirish 	*tot_xfer_len_p = 0;
76344961713Sgirish 
76444961713Sgirish 	while (nmp) {
76544961713Sgirish 		len = MBLKL(nmp);
76644961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: "
76744961713Sgirish 			"len %d pkt_len %d nmblks %d tot_xfer_len %d",
76844961713Sgirish 			len, pkt_len, nmblks,
76944961713Sgirish 			*tot_xfer_len_p));
77044961713Sgirish 
77144961713Sgirish 		if (len <= 0) {
77244961713Sgirish 			bmp = nmp;
77344961713Sgirish 			nmp = nmp->b_cont;
77444961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
77544961713Sgirish 				"==> nxge_tx_pkt_nmblocks: "
77644961713Sgirish 				"len (0) pkt_len %d nmblks %d",
77744961713Sgirish 				pkt_len, nmblks));
77844961713Sgirish 			continue;
77944961713Sgirish 		}
78044961713Sgirish 
78144961713Sgirish 		*tot_xfer_len_p += len;
78244961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: "
78344961713Sgirish 			"len %d pkt_len %d nmblks %d tot_xfer_len %d",
78444961713Sgirish 			len, pkt_len, nmblks,
78544961713Sgirish 			*tot_xfer_len_p));
78644961713Sgirish 
78744961713Sgirish 		if (len < nxge_bcopy_thresh) {
78844961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
78944961713Sgirish 				"==> nxge_tx_pkt_nmblocks: "
79044961713Sgirish 				"len %d (< thresh) pkt_len %d nmblks %d",
79144961713Sgirish 				len, pkt_len, nmblks));
79244961713Sgirish 			if (pkt_len == 0)
79344961713Sgirish 				nmblks++;
79444961713Sgirish 			pkt_len += len;
79544961713Sgirish 			if (pkt_len >= nxge_bcopy_thresh) {
79644961713Sgirish 				pkt_len = 0;
79744961713Sgirish 				len = 0;
79844961713Sgirish 				nmp = bmp;
79944961713Sgirish 			}
80044961713Sgirish 		} else {
80144961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
80244961713Sgirish 				"==> nxge_tx_pkt_nmblocks: "
80344961713Sgirish 				"len %d (> thresh) pkt_len %d nmblks %d",
80444961713Sgirish 				len, pkt_len, nmblks));
80544961713Sgirish 			pkt_len = 0;
80644961713Sgirish 			nmblks++;
80744961713Sgirish 			/*
80844961713Sgirish 			 * Hardware limits the transfer length to 4K.
80944961713Sgirish 			 * If len is more than 4K, we need to break
81044961713Sgirish 			 * it up to at most 2 more blocks.
81144961713Sgirish 			 */
81244961713Sgirish 			if (len > TX_MAX_TRANSFER_LENGTH) {
81344961713Sgirish 				uint32_t	nsegs;
81444961713Sgirish 
815678453a8Sspeer 				nsegs = 1;
81644961713Sgirish 				NXGE_DEBUG_MSG((NULL, TX_CTL,
81744961713Sgirish 					"==> nxge_tx_pkt_nmblocks: "
81844961713Sgirish 					"len %d pkt_len %d nmblks %d nsegs %d",
81944961713Sgirish 					len, pkt_len, nmblks, nsegs));
82044961713Sgirish 				if (len % (TX_MAX_TRANSFER_LENGTH * 2)) {
82144961713Sgirish 					++nsegs;
82244961713Sgirish 				}
82344961713Sgirish 				do {
82444961713Sgirish 					b_wptr = nmp->b_rptr +
82544961713Sgirish 						TX_MAX_TRANSFER_LENGTH;
82644961713Sgirish 					nmp->b_wptr = b_wptr;
82744961713Sgirish 					if ((tmp = dupb(nmp)) == NULL) {
82844961713Sgirish 						return (0);
82944961713Sgirish 					}
83044961713Sgirish 					tmp->b_rptr = b_wptr;
83144961713Sgirish 					tmp->b_wptr = nmp->b_wptr;
83244961713Sgirish 					tmp->b_cont = nmp->b_cont;
83344961713Sgirish 					nmp->b_cont = tmp;
83444961713Sgirish 					nmblks++;
83544961713Sgirish 					if (--nsegs) {
83644961713Sgirish 						nmp = tmp;
83744961713Sgirish 					}
83844961713Sgirish 				} while (nsegs);
83944961713Sgirish 				nmp = tmp;
84044961713Sgirish 			}
84144961713Sgirish 		}
84244961713Sgirish 
84344961713Sgirish 		/*
84444961713Sgirish 		 * Hardware limits the transmit gather pointers to 15.
84544961713Sgirish 		 */
84644961713Sgirish 		if (nmp->b_cont && (nmblks + TX_GATHER_POINTERS_THRESHOLD) >
84744961713Sgirish 				TX_MAX_GATHER_POINTERS) {
84844961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
84944961713Sgirish 				"==> nxge_tx_pkt_nmblocks: pull msg - "
85044961713Sgirish 				"len %d pkt_len %d nmblks %d",
85144961713Sgirish 				len, pkt_len, nmblks));
85244961713Sgirish 			/* Pull all message blocks from b_cont */
85344961713Sgirish 			if ((tmp = msgpullup(nmp->b_cont, -1)) == NULL) {
85444961713Sgirish 				return (0);
85544961713Sgirish 			}
85644961713Sgirish 			freemsg(nmp->b_cont);
85744961713Sgirish 			nmp->b_cont = tmp;
85844961713Sgirish 			pkt_len = 0;
85944961713Sgirish 		}
86044961713Sgirish 		bmp = nmp;
86144961713Sgirish 		nmp = nmp->b_cont;
86244961713Sgirish 	}
86344961713Sgirish 
86444961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
86544961713Sgirish 		"<== nxge_tx_pkt_nmblocks: rptr $%p wptr $%p "
86644961713Sgirish 		"nmblks %d len %d tot_xfer_len %d",
86744961713Sgirish 		mp->b_rptr, mp->b_wptr, nmblks,
86844961713Sgirish 		MBLKL(mp), *tot_xfer_len_p));
86944961713Sgirish 
87044961713Sgirish 	return (nmblks);
87144961713Sgirish }
87244961713Sgirish 
87344961713Sgirish boolean_t
87444961713Sgirish nxge_txdma_reclaim(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, int nmblks)
87544961713Sgirish {
87644961713Sgirish 	boolean_t 		status = B_TRUE;
87744961713Sgirish 	p_nxge_dma_common_t	tx_desc_dma_p;
87844961713Sgirish 	nxge_dma_common_t	desc_area;
87944961713Sgirish 	p_tx_desc_t 		tx_desc_ring_vp;
88044961713Sgirish 	p_tx_desc_t 		tx_desc_p;
88144961713Sgirish 	p_tx_desc_t 		tx_desc_pp;
88244961713Sgirish 	tx_desc_t 		r_tx_desc;
88344961713Sgirish 	p_tx_msg_t 		tx_msg_ring;
88444961713Sgirish 	p_tx_msg_t 		tx_msg_p;
88544961713Sgirish 	npi_handle_t		handle;
88644961713Sgirish 	tx_ring_hdl_t		tx_head;
88744961713Sgirish 	uint32_t 		pkt_len;
88844961713Sgirish 	uint_t			tx_rd_index;
88944961713Sgirish 	uint16_t		head_index, tail_index;
89044961713Sgirish 	uint8_t			tdc;
89144961713Sgirish 	boolean_t		head_wrap, tail_wrap;
89244961713Sgirish 	p_nxge_tx_ring_stats_t tdc_stats;
89344961713Sgirish 	int			rc;
89444961713Sgirish 
89544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_reclaim"));
89644961713Sgirish 
89744961713Sgirish 	status = ((tx_ring_p->descs_pending < nxge_reclaim_pending) &&
89844961713Sgirish 			(nmblks != 0));
89944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
90044961713Sgirish 		"==> nxge_txdma_reclaim: pending %d  reclaim %d nmblks %d",
90144961713Sgirish 			tx_ring_p->descs_pending, nxge_reclaim_pending,
90244961713Sgirish 			nmblks));
90344961713Sgirish 	if (!status) {
90444961713Sgirish 		tx_desc_dma_p = &tx_ring_p->tdc_desc;
90544961713Sgirish 		desc_area = tx_ring_p->tdc_desc;
90644961713Sgirish 		handle = NXGE_DEV_NPI_HANDLE(nxgep);
90744961713Sgirish 		tx_desc_ring_vp = tx_desc_dma_p->kaddrp;
90844961713Sgirish 		tx_desc_ring_vp =
90944961713Sgirish 			(p_tx_desc_t)DMA_COMMON_VPTR(desc_area);
91044961713Sgirish 		tx_rd_index = tx_ring_p->rd_index;
91144961713Sgirish 		tx_desc_p = &tx_desc_ring_vp[tx_rd_index];
91244961713Sgirish 		tx_msg_ring = tx_ring_p->tx_msg_ring;
91344961713Sgirish 		tx_msg_p = &tx_msg_ring[tx_rd_index];
91444961713Sgirish 		tdc = tx_ring_p->tdc;
91544961713Sgirish 		tdc_stats = tx_ring_p->tdc_stats;
91644961713Sgirish 		if (tx_ring_p->descs_pending > tdc_stats->tx_max_pend) {
91744961713Sgirish 			tdc_stats->tx_max_pend = tx_ring_p->descs_pending;
91844961713Sgirish 		}
91944961713Sgirish 
92044961713Sgirish 		tail_index = tx_ring_p->wr_index;
92144961713Sgirish 		tail_wrap = tx_ring_p->wr_index_wrap;
92244961713Sgirish 
92344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
92444961713Sgirish 			"==> nxge_txdma_reclaim: tdc %d tx_rd_index %d "
92544961713Sgirish 			"tail_index %d tail_wrap %d "
92644961713Sgirish 			"tx_desc_p $%p ($%p) ",
92744961713Sgirish 			tdc, tx_rd_index, tail_index, tail_wrap,
92844961713Sgirish 			tx_desc_p, (*(uint64_t *)tx_desc_p)));
92944961713Sgirish 		/*
93044961713Sgirish 		 * Read the hardware maintained transmit head
93144961713Sgirish 		 * and wrap around bit.
93244961713Sgirish 		 */
93344961713Sgirish 		TXDMA_REG_READ64(handle, TX_RING_HDL_REG, tdc, &tx_head.value);
93444961713Sgirish 		head_index =  tx_head.bits.ldw.head;
93544961713Sgirish 		head_wrap = tx_head.bits.ldw.wrap;
93644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
93744961713Sgirish 			"==> nxge_txdma_reclaim: "
93844961713Sgirish 			"tx_rd_index %d tail %d tail_wrap %d "
93944961713Sgirish 			"head %d wrap %d",
94044961713Sgirish 			tx_rd_index, tail_index, tail_wrap,
94144961713Sgirish 			head_index, head_wrap));
94244961713Sgirish 
94344961713Sgirish 		if (head_index == tail_index) {
94444961713Sgirish 			if (TXDMA_RING_EMPTY(head_index, head_wrap,
94544961713Sgirish 					tail_index, tail_wrap) &&
94644961713Sgirish 					(head_index == tx_rd_index)) {
94744961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
94844961713Sgirish 					"==> nxge_txdma_reclaim: EMPTY"));
94944961713Sgirish 				return (B_TRUE);
95044961713Sgirish 			}
95144961713Sgirish 
95244961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
95344961713Sgirish 				"==> nxge_txdma_reclaim: Checking "
95444961713Sgirish 					"if ring full"));
95544961713Sgirish 			if (TXDMA_RING_FULL(head_index, head_wrap, tail_index,
95644961713Sgirish 					tail_wrap)) {
95744961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
95844961713Sgirish 					"==> nxge_txdma_reclaim: full"));
95944961713Sgirish 				return (B_FALSE);
96044961713Sgirish 			}
96144961713Sgirish 		}
96244961713Sgirish 
96344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
96444961713Sgirish 			"==> nxge_txdma_reclaim: tx_rd_index and head_index"));
96544961713Sgirish 
96644961713Sgirish 		tx_desc_pp = &r_tx_desc;
96744961713Sgirish 		while ((tx_rd_index != head_index) &&
96844961713Sgirish 			(tx_ring_p->descs_pending != 0)) {
96944961713Sgirish 
97044961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
97144961713Sgirish 				"==> nxge_txdma_reclaim: Checking if pending"));
97244961713Sgirish 
97344961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
97444961713Sgirish 				"==> nxge_txdma_reclaim: "
97544961713Sgirish 				"descs_pending %d ",
97644961713Sgirish 				tx_ring_p->descs_pending));
97744961713Sgirish 
97844961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
97944961713Sgirish 				"==> nxge_txdma_reclaim: "
98044961713Sgirish 				"(tx_rd_index %d head_index %d "
98144961713Sgirish 				"(tx_desc_p $%p)",
98244961713Sgirish 				tx_rd_index, head_index,
98344961713Sgirish 				tx_desc_p));
98444961713Sgirish 
98544961713Sgirish 			tx_desc_pp->value = tx_desc_p->value;
98644961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
98744961713Sgirish 				"==> nxge_txdma_reclaim: "
98844961713Sgirish 				"(tx_rd_index %d head_index %d "
98944961713Sgirish 				"tx_desc_p $%p (desc value 0x%llx) ",
99044961713Sgirish 				tx_rd_index, head_index,
99144961713Sgirish 				tx_desc_pp, (*(uint64_t *)tx_desc_pp)));
99244961713Sgirish 
99344961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
99444961713Sgirish 				"==> nxge_txdma_reclaim: dump desc:"));
99544961713Sgirish 
99644961713Sgirish 			pkt_len = tx_desc_pp->bits.hdw.tr_len;
99744961713Sgirish 			tdc_stats->obytes += pkt_len;
99844961713Sgirish 			tdc_stats->opackets += tx_desc_pp->bits.hdw.sop;
99944961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
100044961713Sgirish 				"==> nxge_txdma_reclaim: pkt_len %d "
100144961713Sgirish 				"tdc channel %d opackets %d",
100244961713Sgirish 				pkt_len,
100344961713Sgirish 				tdc,
100444961713Sgirish 				tdc_stats->opackets));
100544961713Sgirish 
100644961713Sgirish 			if (tx_msg_p->flags.dma_type == USE_DVMA) {
100744961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
100844961713Sgirish 					"tx_desc_p = $%p "
100944961713Sgirish 					"tx_desc_pp = $%p "
101044961713Sgirish 					"index = %d",
101144961713Sgirish 					tx_desc_p,
101244961713Sgirish 					tx_desc_pp,
101344961713Sgirish 					tx_ring_p->rd_index));
101444961713Sgirish 				(void) dvma_unload(tx_msg_p->dvma_handle,
101544961713Sgirish 					0, -1);
101644961713Sgirish 				tx_msg_p->dvma_handle = NULL;
101744961713Sgirish 				if (tx_ring_p->dvma_wr_index ==
101844961713Sgirish 					tx_ring_p->dvma_wrap_mask) {
101944961713Sgirish 					tx_ring_p->dvma_wr_index = 0;
102044961713Sgirish 				} else {
102144961713Sgirish 					tx_ring_p->dvma_wr_index++;
102244961713Sgirish 				}
102344961713Sgirish 				tx_ring_p->dvma_pending--;
102444961713Sgirish 			} else if (tx_msg_p->flags.dma_type ==
102544961713Sgirish 					USE_DMA) {
102644961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
102744961713Sgirish 					"==> nxge_txdma_reclaim: "
102844961713Sgirish 					"USE DMA"));
102944961713Sgirish 				if (rc = ddi_dma_unbind_handle
103044961713Sgirish 					(tx_msg_p->dma_handle)) {
103144961713Sgirish 					cmn_err(CE_WARN, "!nxge_reclaim: "
103244961713Sgirish 						"ddi_dma_unbind_handle "
103344961713Sgirish 						"failed. status %d", rc);
103444961713Sgirish 				}
103544961713Sgirish 			}
103644961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
103744961713Sgirish 				"==> nxge_txdma_reclaim: count packets"));
103844961713Sgirish 			/*
103944961713Sgirish 			 * count a chained packet only once.
104044961713Sgirish 			 */
104144961713Sgirish 			if (tx_msg_p->tx_message != NULL) {
104244961713Sgirish 				freemsg(tx_msg_p->tx_message);
104344961713Sgirish 				tx_msg_p->tx_message = NULL;
104444961713Sgirish 			}
104544961713Sgirish 
104644961713Sgirish 			tx_msg_p->flags.dma_type = USE_NONE;
104744961713Sgirish 			tx_rd_index = tx_ring_p->rd_index;
104844961713Sgirish 			tx_rd_index = (tx_rd_index + 1) &
104944961713Sgirish 					tx_ring_p->tx_wrap_mask;
105044961713Sgirish 			tx_ring_p->rd_index = tx_rd_index;
105144961713Sgirish 			tx_ring_p->descs_pending--;
105244961713Sgirish 			tx_desc_p = &tx_desc_ring_vp[tx_rd_index];
105344961713Sgirish 			tx_msg_p = &tx_msg_ring[tx_rd_index];
105444961713Sgirish 		}
105544961713Sgirish 
105644961713Sgirish 		status = (nmblks <= (tx_ring_p->tx_ring_size -
105744961713Sgirish 				tx_ring_p->descs_pending -
105844961713Sgirish 				TX_FULL_MARK));
105944961713Sgirish 		if (status) {
106044961713Sgirish 			cas32((uint32_t *)&tx_ring_p->queueing, 1, 0);
106144961713Sgirish 		}
106244961713Sgirish 	} else {
106344961713Sgirish 		status = (nmblks <=
106444961713Sgirish 			(tx_ring_p->tx_ring_size -
106544961713Sgirish 				tx_ring_p->descs_pending -
106644961713Sgirish 				TX_FULL_MARK));
106744961713Sgirish 	}
106844961713Sgirish 
106944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
107044961713Sgirish 		"<== nxge_txdma_reclaim status = 0x%08x", status));
107144961713Sgirish 
107244961713Sgirish 	return (status);
107344961713Sgirish }
107444961713Sgirish 
1075678453a8Sspeer /*
1076678453a8Sspeer  * nxge_tx_intr
1077678453a8Sspeer  *
1078678453a8Sspeer  *	Process a TDC interrupt
1079678453a8Sspeer  *
1080678453a8Sspeer  * Arguments:
1081678453a8Sspeer  * 	arg1	A Logical Device state Vector (LSV) data structure.
1082678453a8Sspeer  * 	arg2	nxge_t *
1083678453a8Sspeer  *
1084678453a8Sspeer  * Notes:
1085678453a8Sspeer  *
1086678453a8Sspeer  * NPI/NXGE function calls:
1087678453a8Sspeer  *	npi_txdma_control_status()
1088678453a8Sspeer  *	npi_intr_ldg_mgmt_set()
1089678453a8Sspeer  *
1090678453a8Sspeer  *	nxge_tx_err_evnts()
1091678453a8Sspeer  *	nxge_txdma_reclaim()
1092678453a8Sspeer  *
1093678453a8Sspeer  * Registers accessed:
1094678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1095678453a8Sspeer  *	PIO_LDSV
1096678453a8Sspeer  *
1097678453a8Sspeer  * Context:
1098678453a8Sspeer  *	Any domain
1099678453a8Sspeer  */
110044961713Sgirish uint_t
110144961713Sgirish nxge_tx_intr(void *arg1, void *arg2)
110244961713Sgirish {
110344961713Sgirish 	p_nxge_ldv_t		ldvp = (p_nxge_ldv_t)arg1;
110444961713Sgirish 	p_nxge_t		nxgep = (p_nxge_t)arg2;
110544961713Sgirish 	p_nxge_ldg_t		ldgp;
110644961713Sgirish 	uint8_t			channel;
110744961713Sgirish 	uint32_t		vindex;
110844961713Sgirish 	npi_handle_t		handle;
110944961713Sgirish 	tx_cs_t			cs;
111044961713Sgirish 	p_tx_ring_t 		*tx_rings;
111144961713Sgirish 	p_tx_ring_t 		tx_ring_p;
111244961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
111344961713Sgirish 	uint_t 			serviced = DDI_INTR_UNCLAIMED;
111444961713Sgirish 	nxge_status_t 		status = NXGE_OK;
111544961713Sgirish 
111644961713Sgirish 	if (ldvp == NULL) {
111744961713Sgirish 		NXGE_DEBUG_MSG((NULL, INT_CTL,
111844961713Sgirish 			"<== nxge_tx_intr: nxgep $%p ldvp $%p",
111944961713Sgirish 			nxgep, ldvp));
112044961713Sgirish 		return (DDI_INTR_UNCLAIMED);
112144961713Sgirish 	}
112244961713Sgirish 
112344961713Sgirish 	if (arg2 == NULL || (void *)ldvp->nxgep != arg2) {
112444961713Sgirish 		nxgep = ldvp->nxgep;
112544961713Sgirish 	}
112644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
112744961713Sgirish 		"==> nxge_tx_intr: nxgep(arg2) $%p ldvp(arg1) $%p",
112844961713Sgirish 		nxgep, ldvp));
1129*22c0d73aSspeer 
1130*22c0d73aSspeer 	if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) ||
1131*22c0d73aSspeer 	    (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) {
1132*22c0d73aSspeer 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
1133*22c0d73aSspeer 		    "<== nxge_tx_intr: interface not started or intialized"));
1134*22c0d73aSspeer 		return (DDI_INTR_CLAIMED);
1135*22c0d73aSspeer 	}
1136*22c0d73aSspeer 
113744961713Sgirish 	/*
113844961713Sgirish 	 * This interrupt handler is for a specific
113944961713Sgirish 	 * transmit dma channel.
114044961713Sgirish 	 */
114144961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
114244961713Sgirish 	/* Get the control and status for this channel. */
114344961713Sgirish 	channel = ldvp->channel;
114444961713Sgirish 	ldgp = ldvp->ldgp;
114544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
114644961713Sgirish 		"==> nxge_tx_intr: nxgep $%p ldvp (ldvp) $%p "
114744961713Sgirish 		"channel %d",
114844961713Sgirish 		nxgep, ldvp, channel));
114944961713Sgirish 
115044961713Sgirish 	rs = npi_txdma_control_status(handle, OP_GET, channel, &cs);
115144961713Sgirish 	vindex = ldvp->vdma_index;
115244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
115344961713Sgirish 		"==> nxge_tx_intr:channel %d ring index %d status 0x%08x",
115444961713Sgirish 		channel, vindex, rs));
115544961713Sgirish 	if (!rs && cs.bits.ldw.mk) {
115644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
115744961713Sgirish 			"==> nxge_tx_intr:channel %d ring index %d "
115844961713Sgirish 			"status 0x%08x (mk bit set)",
115944961713Sgirish 			channel, vindex, rs));
116044961713Sgirish 		tx_rings = nxgep->tx_rings->rings;
116144961713Sgirish 		tx_ring_p = tx_rings[vindex];
116244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
116344961713Sgirish 			"==> nxge_tx_intr:channel %d ring index %d "
116444961713Sgirish 			"status 0x%08x (mk bit set, calling reclaim)",
116544961713Sgirish 			channel, vindex, rs));
116644961713Sgirish 
116744961713Sgirish 		MUTEX_ENTER(&tx_ring_p->lock);
116844961713Sgirish 		(void) nxge_txdma_reclaim(nxgep, tx_rings[vindex], 0);
116944961713Sgirish 		MUTEX_EXIT(&tx_ring_p->lock);
117044961713Sgirish 		mac_tx_update(nxgep->mach);
117144961713Sgirish 	}
117244961713Sgirish 
117344961713Sgirish 	/*
117444961713Sgirish 	 * Process other transmit control and status.
117544961713Sgirish 	 * Check the ldv state.
117644961713Sgirish 	 */
117744961713Sgirish 	status = nxge_tx_err_evnts(nxgep, ldvp->vdma_index, ldvp, cs);
117844961713Sgirish 	/*
117944961713Sgirish 	 * Rearm this logical group if this is a single device
118044961713Sgirish 	 * group.
118144961713Sgirish 	 */
118244961713Sgirish 	if (ldgp->nldvs == 1) {
118344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
118444961713Sgirish 			"==> nxge_tx_intr: rearm"));
118544961713Sgirish 		if (status == NXGE_OK) {
1186678453a8Sspeer 			if (isLDOMguest(nxgep)) {
1187678453a8Sspeer 				nxge_hio_ldgimgn(nxgep, ldgp);
1188678453a8Sspeer 			} else {
1189678453a8Sspeer 				(void) npi_intr_ldg_mgmt_set(handle, ldgp->ldg,
1190678453a8Sspeer 				    B_TRUE, ldgp->ldg_timer);
1191678453a8Sspeer 			}
119244961713Sgirish 		}
119344961713Sgirish 	}
119444961713Sgirish 
119544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_tx_intr"));
119644961713Sgirish 	serviced = DDI_INTR_CLAIMED;
119744961713Sgirish 	return (serviced);
119844961713Sgirish }
119944961713Sgirish 
120044961713Sgirish void
1201678453a8Sspeer nxge_txdma_stop(p_nxge_t nxgep)	/* Dead */
120244961713Sgirish {
120344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop"));
120444961713Sgirish 
120544961713Sgirish 	(void) nxge_link_monitor(nxgep, LINK_MONITOR_STOP);
120644961713Sgirish 
120744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop"));
120844961713Sgirish }
120944961713Sgirish 
121044961713Sgirish void
1211678453a8Sspeer nxge_txdma_stop_start(p_nxge_t nxgep) /* Dead */
121244961713Sgirish {
121344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_start"));
121444961713Sgirish 
121544961713Sgirish 	(void) nxge_txdma_stop(nxgep);
121644961713Sgirish 
121744961713Sgirish 	(void) nxge_fixup_txdma_rings(nxgep);
121844961713Sgirish 	(void) nxge_txdma_hw_mode(nxgep, NXGE_DMA_START);
121944961713Sgirish 	(void) nxge_tx_mac_enable(nxgep);
122044961713Sgirish 	(void) nxge_txdma_hw_kick(nxgep);
122144961713Sgirish 
122244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_start"));
122344961713Sgirish }
122444961713Sgirish 
1225678453a8Sspeer npi_status_t
1226678453a8Sspeer nxge_txdma_channel_disable(
1227678453a8Sspeer 	nxge_t *nxge,
1228678453a8Sspeer 	int channel)
1229678453a8Sspeer {
1230678453a8Sspeer 	npi_handle_t	handle = NXGE_DEV_NPI_HANDLE(nxge);
1231678453a8Sspeer 	npi_status_t	rs;
1232678453a8Sspeer 	tdmc_intr_dbg_t	intr_dbg;
1233678453a8Sspeer 
1234678453a8Sspeer 	/*
1235678453a8Sspeer 	 * Stop the dma channel and wait for the stop-done.
1236678453a8Sspeer 	 * If the stop-done bit is not present, then force
1237678453a8Sspeer 	 * an error so TXC will stop.
1238678453a8Sspeer 	 * All channels bound to this port need to be stopped
1239678453a8Sspeer 	 * and reset after injecting an interrupt error.
1240678453a8Sspeer 	 */
1241678453a8Sspeer 	rs = npi_txdma_channel_disable(handle, channel);
1242678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, MEM3_CTL,
1243678453a8Sspeer 		"==> nxge_txdma_channel_disable(%d) "
1244678453a8Sspeer 		"rs 0x%x", channel, rs));
1245678453a8Sspeer 	if (rs != NPI_SUCCESS) {
1246678453a8Sspeer 		/* Inject any error */
1247678453a8Sspeer 		intr_dbg.value = 0;
1248678453a8Sspeer 		intr_dbg.bits.ldw.nack_pref = 1;
1249678453a8Sspeer 		NXGE_DEBUG_MSG((nxge, MEM3_CTL,
1250678453a8Sspeer 			"==> nxge_txdma_hw_mode: "
1251678453a8Sspeer 			"channel %d (stop failed 0x%x) "
1252678453a8Sspeer 			"(inject err)", rs, channel));
1253678453a8Sspeer 		(void) npi_txdma_inj_int_error_set(
1254678453a8Sspeer 			handle, channel, &intr_dbg);
1255678453a8Sspeer 		rs = npi_txdma_channel_disable(handle, channel);
1256678453a8Sspeer 		NXGE_DEBUG_MSG((nxge, MEM3_CTL,
1257678453a8Sspeer 			"==> nxge_txdma_hw_mode: "
1258678453a8Sspeer 			"channel %d (stop again 0x%x) "
1259678453a8Sspeer 			"(after inject err)",
1260678453a8Sspeer 			rs, channel));
1261678453a8Sspeer 	}
1262678453a8Sspeer 
1263678453a8Sspeer 	return (rs);
1264678453a8Sspeer }
1265678453a8Sspeer 
1266678453a8Sspeer /*
1267678453a8Sspeer  * nxge_txdma_hw_mode
1268678453a8Sspeer  *
1269678453a8Sspeer  *	Toggle all TDCs on (enable) or off (disable).
1270678453a8Sspeer  *
1271678453a8Sspeer  * Arguments:
1272678453a8Sspeer  * 	nxgep
1273678453a8Sspeer  * 	enable	Enable or disable a TDC.
1274678453a8Sspeer  *
1275678453a8Sspeer  * Notes:
1276678453a8Sspeer  *
1277678453a8Sspeer  * NPI/NXGE function calls:
1278678453a8Sspeer  *	npi_txdma_channel_enable(TX_CS)
1279678453a8Sspeer  *	npi_txdma_channel_disable(TX_CS)
1280678453a8Sspeer  *	npi_txdma_inj_int_error_set(TDMC_INTR_DBG)
1281678453a8Sspeer  *
1282678453a8Sspeer  * Registers accessed:
1283678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1284678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
1285678453a8Sspeer  *
1286678453a8Sspeer  * Context:
1287678453a8Sspeer  *	Any domain
1288678453a8Sspeer  */
128944961713Sgirish nxge_status_t
129044961713Sgirish nxge_txdma_hw_mode(p_nxge_t nxgep, boolean_t enable)
129144961713Sgirish {
1292678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1293678453a8Sspeer 
1294678453a8Sspeer 	npi_handle_t	handle;
1295678453a8Sspeer 	nxge_status_t	status;
1296678453a8Sspeer 	npi_status_t	rs;
1297678453a8Sspeer 	int		tdc;
129844961713Sgirish 
129944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
130044961713Sgirish 		"==> nxge_txdma_hw_mode: enable mode %d", enable));
130144961713Sgirish 
130244961713Sgirish 	if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) {
130344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
130444961713Sgirish 			"<== nxge_txdma_mode: not initialized"));
130544961713Sgirish 		return (NXGE_ERROR);
130644961713Sgirish 	}
130744961713Sgirish 
1308678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
130944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1310678453a8Sspeer 		    "<== nxge_txdma_hw_mode: NULL ring pointer(s)"));
131144961713Sgirish 		return (NXGE_ERROR);
131244961713Sgirish 	}
131344961713Sgirish 
1314678453a8Sspeer 	/* Enable or disable all of the TDCs owned by us. */
131544961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
1316678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1317678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1318678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1319678453a8Sspeer 			if (ring) {
1320678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1321678453a8Sspeer 				    "==> nxge_txdma_hw_mode: channel %d", tdc));
1322678453a8Sspeer 				if (enable) {
1323678453a8Sspeer 					rs = npi_txdma_channel_enable
1324678453a8Sspeer 					    (handle, tdc);
132544961713Sgirish 					NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1326678453a8Sspeer 					    "==> nxge_txdma_hw_mode: "
1327678453a8Sspeer 					    "channel %d (enable) rs 0x%x",
1328678453a8Sspeer 					    tdc, rs));
1329678453a8Sspeer 				} else {
1330678453a8Sspeer 					rs = nxge_txdma_channel_disable
1331678453a8Sspeer 					    (nxgep, tdc);
133244961713Sgirish 				}
133344961713Sgirish 			}
133444961713Sgirish 		}
133544961713Sgirish 	}
133644961713Sgirish 
133744961713Sgirish 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
133844961713Sgirish 
133944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
134044961713Sgirish 		"<== nxge_txdma_hw_mode: status 0x%x", status));
134144961713Sgirish 
134244961713Sgirish 	return (status);
134344961713Sgirish }
134444961713Sgirish 
134544961713Sgirish void
134644961713Sgirish nxge_txdma_enable_channel(p_nxge_t nxgep, uint16_t channel)
134744961713Sgirish {
134844961713Sgirish 	npi_handle_t		handle;
134944961713Sgirish 
135044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DMA_CTL,
135144961713Sgirish 		"==> nxge_txdma_enable_channel: channel %d", channel));
135244961713Sgirish 
135344961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
135444961713Sgirish 	/* enable the transmit dma channels */
135544961713Sgirish 	(void) npi_txdma_channel_enable(handle, channel);
135644961713Sgirish 
135744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DMA_CTL, "<== nxge_txdma_enable_channel"));
135844961713Sgirish }
135944961713Sgirish 
136044961713Sgirish void
136144961713Sgirish nxge_txdma_disable_channel(p_nxge_t nxgep, uint16_t channel)
136244961713Sgirish {
136344961713Sgirish 	npi_handle_t		handle;
136444961713Sgirish 
136544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DMA_CTL,
136644961713Sgirish 		"==> nxge_txdma_disable_channel: channel %d", channel));
136744961713Sgirish 
136844961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
136944961713Sgirish 	/* stop the transmit dma channels */
137044961713Sgirish 	(void) npi_txdma_channel_disable(handle, channel);
137144961713Sgirish 
137244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_disable_channel"));
137344961713Sgirish }
137444961713Sgirish 
1375678453a8Sspeer /*
1376678453a8Sspeer  * nxge_txdma_stop_inj_err
1377678453a8Sspeer  *
1378678453a8Sspeer  *	Stop a TDC.  If at first we don't succeed, inject an error.
1379678453a8Sspeer  *
1380678453a8Sspeer  * Arguments:
1381678453a8Sspeer  * 	nxgep
1382678453a8Sspeer  * 	channel		The channel to stop.
1383678453a8Sspeer  *
1384678453a8Sspeer  * Notes:
1385678453a8Sspeer  *
1386678453a8Sspeer  * NPI/NXGE function calls:
1387678453a8Sspeer  *	npi_txdma_channel_disable()
1388678453a8Sspeer  *	npi_txdma_inj_int_error_set()
1389678453a8Sspeer  * #if defined(NXGE_DEBUG)
1390678453a8Sspeer  *	nxge_txdma_regs_dump_channels(nxgep);
1391678453a8Sspeer  * #endif
1392678453a8Sspeer  *
1393678453a8Sspeer  * Registers accessed:
1394678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1395678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
1396678453a8Sspeer  *
1397678453a8Sspeer  * Context:
1398678453a8Sspeer  *	Any domain
1399678453a8Sspeer  */
140044961713Sgirish int
140144961713Sgirish nxge_txdma_stop_inj_err(p_nxge_t nxgep, int channel)
140244961713Sgirish {
140344961713Sgirish 	npi_handle_t		handle;
140444961713Sgirish 	tdmc_intr_dbg_t		intr_dbg;
140544961713Sgirish 	int			status;
140644961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
140744961713Sgirish 
140844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_inj_err"));
140944961713Sgirish 	/*
141044961713Sgirish 	 * Stop the dma channel waits for the stop done.
141144961713Sgirish 	 * If the stop done bit is not set, then create
141244961713Sgirish 	 * an error.
141344961713Sgirish 	 */
141444961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
141544961713Sgirish 	rs = npi_txdma_channel_disable(handle, channel);
141644961713Sgirish 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
141744961713Sgirish 	if (status == NXGE_OK) {
141844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
141944961713Sgirish 			"<== nxge_txdma_stop_inj_err (channel %d): "
142044961713Sgirish 			"stopped OK", channel));
142144961713Sgirish 		return (status);
142244961713Sgirish 	}
142344961713Sgirish 
142444961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
142544961713Sgirish 		"==> nxge_txdma_stop_inj_err (channel %d): stop failed (0x%x) "
142644961713Sgirish 		"injecting error", channel, rs));
142744961713Sgirish 	/* Inject any error */
142844961713Sgirish 	intr_dbg.value = 0;
142944961713Sgirish 	intr_dbg.bits.ldw.nack_pref = 1;
143044961713Sgirish 	(void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg);
143144961713Sgirish 
143244961713Sgirish 	/* Stop done bit will be set as a result of error injection */
143344961713Sgirish 	rs = npi_txdma_channel_disable(handle, channel);
143444961713Sgirish 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
143544961713Sgirish 	if (!(rs & NPI_TXDMA_STOP_FAILED)) {
143644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
143744961713Sgirish 			"<== nxge_txdma_stop_inj_err (channel %d): "
143844961713Sgirish 			"stopped OK ", channel));
143944961713Sgirish 		return (status);
144044961713Sgirish 	}
144144961713Sgirish 
144244961713Sgirish #if	defined(NXGE_DEBUG)
144344961713Sgirish 	nxge_txdma_regs_dump_channels(nxgep);
144444961713Sgirish #endif
144544961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
144644961713Sgirish 		"==> nxge_txdma_stop_inj_err (channel): stop failed (0x%x) "
144744961713Sgirish 		" (injected error but still not stopped)", channel, rs));
144844961713Sgirish 
144944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_inj_err"));
145044961713Sgirish 	return (status);
145144961713Sgirish }
145244961713Sgirish 
145344961713Sgirish /*ARGSUSED*/
145444961713Sgirish void
145544961713Sgirish nxge_fixup_txdma_rings(p_nxge_t nxgep)
145644961713Sgirish {
1457678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1458678453a8Sspeer 	int tdc;
145944961713Sgirish 
146044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_txdma_rings"));
146144961713Sgirish 
1462678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
1463678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1464678453a8Sspeer 		    "<== nxge_fixup_txdma_rings: NULL ring pointer(s)"));
146544961713Sgirish 		return;
146644961713Sgirish 	}
146744961713Sgirish 
1468678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1469678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1470678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1471678453a8Sspeer 			if (ring) {
1472678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1473678453a8Sspeer 				    "==> nxge_fixup_txdma_rings: channel %d",
1474678453a8Sspeer 				    tdc));
1475678453a8Sspeer 				nxge_txdma_fixup_channel(nxgep, ring, tdc);
1476678453a8Sspeer 			}
1477678453a8Sspeer 		}
147844961713Sgirish 	}
147944961713Sgirish 
148044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_txdma_rings"));
148144961713Sgirish }
148244961713Sgirish 
148344961713Sgirish /*ARGSUSED*/
148444961713Sgirish void
148544961713Sgirish nxge_txdma_fix_channel(p_nxge_t nxgep, uint16_t channel)
148644961713Sgirish {
148744961713Sgirish 	p_tx_ring_t	ring_p;
148844961713Sgirish 
148944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_channel"));
149044961713Sgirish 	ring_p = nxge_txdma_get_ring(nxgep, channel);
149144961713Sgirish 	if (ring_p == NULL) {
149244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel"));
149344961713Sgirish 		return;
149444961713Sgirish 	}
149544961713Sgirish 
149644961713Sgirish 	if (ring_p->tdc != channel) {
149744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
149844961713Sgirish 			"<== nxge_txdma_fix_channel: channel not matched "
149944961713Sgirish 			"ring tdc %d passed channel",
150044961713Sgirish 			ring_p->tdc, channel));
150144961713Sgirish 		return;
150244961713Sgirish 	}
150344961713Sgirish 
150444961713Sgirish 	nxge_txdma_fixup_channel(nxgep, ring_p, channel);
150544961713Sgirish 
150644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel"));
150744961713Sgirish }
150844961713Sgirish 
150944961713Sgirish /*ARGSUSED*/
151044961713Sgirish void
151144961713Sgirish nxge_txdma_fixup_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel)
151244961713Sgirish {
151344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_channel"));
151444961713Sgirish 
151544961713Sgirish 	if (ring_p == NULL) {
151644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
151744961713Sgirish 			"<== nxge_txdma_fixup_channel: NULL ring pointer"));
151844961713Sgirish 		return;
151944961713Sgirish 	}
152044961713Sgirish 
152144961713Sgirish 	if (ring_p->tdc != channel) {
152244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
152344961713Sgirish 			"<== nxge_txdma_fixup_channel: channel not matched "
152444961713Sgirish 			"ring tdc %d passed channel",
152544961713Sgirish 			ring_p->tdc, channel));
152644961713Sgirish 		return;
152744961713Sgirish 	}
152844961713Sgirish 
152944961713Sgirish 	MUTEX_ENTER(&ring_p->lock);
153044961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, ring_p, 0);
153144961713Sgirish 	ring_p->rd_index = 0;
153244961713Sgirish 	ring_p->wr_index = 0;
153344961713Sgirish 	ring_p->ring_head.value = 0;
153444961713Sgirish 	ring_p->ring_kick_tail.value = 0;
153544961713Sgirish 	ring_p->descs_pending = 0;
153644961713Sgirish 	MUTEX_EXIT(&ring_p->lock);
153744961713Sgirish 
153844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_channel"));
153944961713Sgirish }
154044961713Sgirish 
154144961713Sgirish /*ARGSUSED*/
154244961713Sgirish void
154344961713Sgirish nxge_txdma_hw_kick(p_nxge_t nxgep)
154444961713Sgirish {
1545678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1546678453a8Sspeer 	int tdc;
154744961713Sgirish 
154844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick"));
154944961713Sgirish 
1550678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
155144961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1552678453a8Sspeer 		    "<== nxge_txdma_hw_kick: NULL ring pointer(s)"));
155344961713Sgirish 		return;
155444961713Sgirish 	}
155544961713Sgirish 
1556678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1557678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1558678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1559678453a8Sspeer 			if (ring) {
1560678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1561678453a8Sspeer 				    "==> nxge_txdma_hw_kick: channel %d", tdc));
1562678453a8Sspeer 				nxge_txdma_hw_kick_channel(nxgep, ring, tdc);
1563678453a8Sspeer 			}
1564678453a8Sspeer 		}
156544961713Sgirish 	}
156644961713Sgirish 
156744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick"));
156844961713Sgirish }
156944961713Sgirish 
157044961713Sgirish /*ARGSUSED*/
157144961713Sgirish void
157244961713Sgirish nxge_txdma_kick_channel(p_nxge_t nxgep, uint16_t channel)
157344961713Sgirish {
157444961713Sgirish 	p_tx_ring_t	ring_p;
157544961713Sgirish 
157644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_kick_channel"));
157744961713Sgirish 
157844961713Sgirish 	ring_p = nxge_txdma_get_ring(nxgep, channel);
157944961713Sgirish 	if (ring_p == NULL) {
158044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
158144961713Sgirish 			    " nxge_txdma_kick_channel"));
158244961713Sgirish 		return;
158344961713Sgirish 	}
158444961713Sgirish 
158544961713Sgirish 	if (ring_p->tdc != channel) {
158644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
158744961713Sgirish 			"<== nxge_txdma_kick_channel: channel not matched "
158844961713Sgirish 			"ring tdc %d passed channel",
158944961713Sgirish 			ring_p->tdc, channel));
159044961713Sgirish 		return;
159144961713Sgirish 	}
159244961713Sgirish 
159344961713Sgirish 	nxge_txdma_hw_kick_channel(nxgep, ring_p, channel);
159444961713Sgirish 
159544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_kick_channel"));
159644961713Sgirish }
1597a3c5bd6dSspeer 
159844961713Sgirish /*ARGSUSED*/
159944961713Sgirish void
160044961713Sgirish nxge_txdma_hw_kick_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel)
160144961713Sgirish {
160244961713Sgirish 
160344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick_channel"));
160444961713Sgirish 
160544961713Sgirish 	if (ring_p == NULL) {
160644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
160744961713Sgirish 			"<== nxge_txdma_hw_kick_channel: NULL ring pointer"));
160844961713Sgirish 		return;
160944961713Sgirish 	}
161044961713Sgirish 
161144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick_channel"));
161244961713Sgirish }
161344961713Sgirish 
1614678453a8Sspeer /*
1615678453a8Sspeer  * nxge_check_tx_hang
1616678453a8Sspeer  *
1617678453a8Sspeer  *	Check the state of all TDCs belonging to nxgep.
1618678453a8Sspeer  *
1619678453a8Sspeer  * Arguments:
1620678453a8Sspeer  * 	nxgep
1621678453a8Sspeer  *
1622678453a8Sspeer  * Notes:
1623678453a8Sspeer  *	Called by nxge_hw.c:nxge_check_hw_state().
1624678453a8Sspeer  *
1625678453a8Sspeer  * NPI/NXGE function calls:
1626678453a8Sspeer  *
1627678453a8Sspeer  * Registers accessed:
1628678453a8Sspeer  *
1629678453a8Sspeer  * Context:
1630678453a8Sspeer  *	Any domain
1631678453a8Sspeer  */
163244961713Sgirish /*ARGSUSED*/
163344961713Sgirish void
163444961713Sgirish nxge_check_tx_hang(p_nxge_t nxgep)
163544961713Sgirish {
163644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_check_tx_hang"));
163744961713Sgirish 
1638*22c0d73aSspeer 	if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) ||
1639*22c0d73aSspeer 	    (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) {
1640*22c0d73aSspeer 		goto nxge_check_tx_hang_exit;
1641*22c0d73aSspeer 	}
1642*22c0d73aSspeer 
164344961713Sgirish 	/*
164444961713Sgirish 	 * Needs inputs from hardware for regs:
164544961713Sgirish 	 *	head index had not moved since last timeout.
164644961713Sgirish 	 *	packets not transmitted or stuffed registers.
164744961713Sgirish 	 */
164844961713Sgirish 	if (nxge_txdma_hung(nxgep)) {
164944961713Sgirish 		nxge_fixup_hung_txdma_rings(nxgep);
165044961713Sgirish 	}
1651*22c0d73aSspeer 
1652*22c0d73aSspeer nxge_check_tx_hang_exit:
165344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_check_tx_hang"));
165444961713Sgirish }
165544961713Sgirish 
1656678453a8Sspeer /*
1657678453a8Sspeer  * nxge_txdma_hung
1658678453a8Sspeer  *
1659678453a8Sspeer  *	Reset a TDC.
1660678453a8Sspeer  *
1661678453a8Sspeer  * Arguments:
1662678453a8Sspeer  * 	nxgep
1663678453a8Sspeer  * 	channel		The channel to reset.
1664678453a8Sspeer  * 	reg_data	The current TX_CS.
1665678453a8Sspeer  *
1666678453a8Sspeer  * Notes:
1667678453a8Sspeer  *	Called by nxge_check_tx_hang()
1668678453a8Sspeer  *
1669678453a8Sspeer  * NPI/NXGE function calls:
1670678453a8Sspeer  *	nxge_txdma_channel_hung()
1671678453a8Sspeer  *
1672678453a8Sspeer  * Registers accessed:
1673678453a8Sspeer  *
1674678453a8Sspeer  * Context:
1675678453a8Sspeer  *	Any domain
1676678453a8Sspeer  */
167744961713Sgirish int
167844961713Sgirish nxge_txdma_hung(p_nxge_t nxgep)
167944961713Sgirish {
1680678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1681678453a8Sspeer 	int tdc;
168244961713Sgirish 
168344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hung"));
168444961713Sgirish 
1685678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
168644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1687678453a8Sspeer 		    "<== nxge_txdma_hung: NULL ring pointer(s)"));
168844961713Sgirish 		return (B_FALSE);
168944961713Sgirish 	}
169044961713Sgirish 
1691678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1692678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1693678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1694678453a8Sspeer 			if (ring) {
1695678453a8Sspeer 				if (nxge_txdma_channel_hung(nxgep, ring, tdc)) {
1696678453a8Sspeer 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
1697678453a8Sspeer 					    "==> nxge_txdma_hung: TDC %d hung",
1698678453a8Sspeer 					    tdc));
1699678453a8Sspeer 					return (B_TRUE);
1700678453a8Sspeer 				}
1701678453a8Sspeer 			}
170244961713Sgirish 		}
170344961713Sgirish 	}
170444961713Sgirish 
170544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hung"));
170644961713Sgirish 
170744961713Sgirish 	return (B_FALSE);
170844961713Sgirish }
170944961713Sgirish 
1710678453a8Sspeer /*
1711678453a8Sspeer  * nxge_txdma_channel_hung
1712678453a8Sspeer  *
1713678453a8Sspeer  *	Reset a TDC.
1714678453a8Sspeer  *
1715678453a8Sspeer  * Arguments:
1716678453a8Sspeer  * 	nxgep
1717678453a8Sspeer  * 	ring		<channel>'s ring.
1718678453a8Sspeer  * 	channel		The channel to reset.
1719678453a8Sspeer  *
1720678453a8Sspeer  * Notes:
1721678453a8Sspeer  *	Called by nxge_txdma.c:nxge_txdma_hung()
1722678453a8Sspeer  *
1723678453a8Sspeer  * NPI/NXGE function calls:
1724678453a8Sspeer  *	npi_txdma_ring_head_get()
1725678453a8Sspeer  *
1726678453a8Sspeer  * Registers accessed:
1727678453a8Sspeer  *	TX_RING_HDL	DMC+0x40010 Transmit Ring Head Low
1728678453a8Sspeer  *
1729678453a8Sspeer  * Context:
1730678453a8Sspeer  *	Any domain
1731678453a8Sspeer  */
173244961713Sgirish int
173344961713Sgirish nxge_txdma_channel_hung(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, uint16_t channel)
173444961713Sgirish {
173544961713Sgirish 	uint16_t		head_index, tail_index;
173644961713Sgirish 	boolean_t		head_wrap, tail_wrap;
173744961713Sgirish 	npi_handle_t		handle;
173844961713Sgirish 	tx_ring_hdl_t		tx_head;
173944961713Sgirish 	uint_t			tx_rd_index;
174044961713Sgirish 
174144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_channel_hung"));
174244961713Sgirish 
174344961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
174444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
174544961713Sgirish 		"==> nxge_txdma_channel_hung: channel %d", channel));
174644961713Sgirish 	MUTEX_ENTER(&tx_ring_p->lock);
174744961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
174844961713Sgirish 
174944961713Sgirish 	tail_index = tx_ring_p->wr_index;
175044961713Sgirish 	tail_wrap = tx_ring_p->wr_index_wrap;
175144961713Sgirish 	tx_rd_index = tx_ring_p->rd_index;
175244961713Sgirish 	MUTEX_EXIT(&tx_ring_p->lock);
175344961713Sgirish 
175444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
175544961713Sgirish 		"==> nxge_txdma_channel_hung: tdc %d tx_rd_index %d "
175644961713Sgirish 		"tail_index %d tail_wrap %d ",
175744961713Sgirish 		channel, tx_rd_index, tail_index, tail_wrap));
175844961713Sgirish 	/*
175944961713Sgirish 	 * Read the hardware maintained transmit head
176044961713Sgirish 	 * and wrap around bit.
176144961713Sgirish 	 */
176244961713Sgirish 	(void) npi_txdma_ring_head_get(handle, channel, &tx_head);
176344961713Sgirish 	head_index =  tx_head.bits.ldw.head;
176444961713Sgirish 	head_wrap = tx_head.bits.ldw.wrap;
176544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
176644961713Sgirish 		"==> nxge_txdma_channel_hung: "
176744961713Sgirish 		"tx_rd_index %d tail %d tail_wrap %d "
176844961713Sgirish 		"head %d wrap %d",
176944961713Sgirish 		tx_rd_index, tail_index, tail_wrap,
177044961713Sgirish 		head_index, head_wrap));
177144961713Sgirish 
177244961713Sgirish 	if (TXDMA_RING_EMPTY(head_index, head_wrap,
177344961713Sgirish 			tail_index, tail_wrap) &&
177444961713Sgirish 			(head_index == tx_rd_index)) {
177544961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
177644961713Sgirish 			"==> nxge_txdma_channel_hung: EMPTY"));
177744961713Sgirish 		return (B_FALSE);
177844961713Sgirish 	}
177944961713Sgirish 
178044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
178144961713Sgirish 		"==> nxge_txdma_channel_hung: Checking if ring full"));
178244961713Sgirish 	if (TXDMA_RING_FULL(head_index, head_wrap, tail_index,
178344961713Sgirish 			tail_wrap)) {
178444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
178544961713Sgirish 			"==> nxge_txdma_channel_hung: full"));
178644961713Sgirish 		return (B_TRUE);
178744961713Sgirish 	}
178844961713Sgirish 
178944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_channel_hung"));
179044961713Sgirish 
179144961713Sgirish 	return (B_FALSE);
179244961713Sgirish }
179344961713Sgirish 
1794678453a8Sspeer /*
1795678453a8Sspeer  * nxge_fixup_hung_txdma_rings
1796678453a8Sspeer  *
1797678453a8Sspeer  *	Disable a TDC.
1798678453a8Sspeer  *
1799678453a8Sspeer  * Arguments:
1800678453a8Sspeer  * 	nxgep
1801678453a8Sspeer  * 	channel		The channel to reset.
1802678453a8Sspeer  * 	reg_data	The current TX_CS.
1803678453a8Sspeer  *
1804678453a8Sspeer  * Notes:
1805678453a8Sspeer  *	Called by nxge_check_tx_hang()
1806678453a8Sspeer  *
1807678453a8Sspeer  * NPI/NXGE function calls:
1808678453a8Sspeer  *	npi_txdma_ring_head_get()
1809678453a8Sspeer  *
1810678453a8Sspeer  * Registers accessed:
1811678453a8Sspeer  *	TX_RING_HDL	DMC+0x40010 Transmit Ring Head Low
1812678453a8Sspeer  *
1813678453a8Sspeer  * Context:
1814678453a8Sspeer  *	Any domain
1815678453a8Sspeer  */
181644961713Sgirish /*ARGSUSED*/
181744961713Sgirish void
181844961713Sgirish nxge_fixup_hung_txdma_rings(p_nxge_t nxgep)
181944961713Sgirish {
1820678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1821678453a8Sspeer 	int tdc;
182244961713Sgirish 
182344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_hung_txdma_rings"));
182444961713Sgirish 
1825678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
182644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1827678453a8Sspeer 		    "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
182844961713Sgirish 		return;
182944961713Sgirish 	}
183044961713Sgirish 
1831678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1832678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1833678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1834678453a8Sspeer 			if (ring) {
1835678453a8Sspeer 				nxge_txdma_fixup_hung_channel(nxgep, ring, tdc);
1836678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
1837678453a8Sspeer 				    "==> nxge_fixup_hung_txdma_rings: TDC %d",
1838678453a8Sspeer 				    tdc));
1839678453a8Sspeer 			}
1840678453a8Sspeer 		}
184144961713Sgirish 	}
184244961713Sgirish 
184344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_hung_txdma_rings"));
184444961713Sgirish }
184544961713Sgirish 
1846678453a8Sspeer /*
1847678453a8Sspeer  * nxge_txdma_fixup_hung_channel
1848678453a8Sspeer  *
1849678453a8Sspeer  *	'Fix' a hung TDC.
1850678453a8Sspeer  *
1851678453a8Sspeer  * Arguments:
1852678453a8Sspeer  * 	nxgep
1853678453a8Sspeer  * 	channel		The channel to fix.
1854678453a8Sspeer  *
1855678453a8Sspeer  * Notes:
1856678453a8Sspeer  *	Called by nxge_fixup_hung_txdma_rings()
1857678453a8Sspeer  *
1858678453a8Sspeer  *	1. Reclaim the TDC.
1859678453a8Sspeer  *	2. Disable the TDC.
1860678453a8Sspeer  *
1861678453a8Sspeer  * NPI/NXGE function calls:
1862678453a8Sspeer  *	nxge_txdma_reclaim()
1863678453a8Sspeer  *	npi_txdma_channel_disable(TX_CS)
1864678453a8Sspeer  *	npi_txdma_inj_int_error_set(TDMC_INTR_DBG)
1865678453a8Sspeer  *
1866678453a8Sspeer  * Registers accessed:
1867678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1868678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
1869678453a8Sspeer  *
1870678453a8Sspeer  * Context:
1871678453a8Sspeer  *	Any domain
1872678453a8Sspeer  */
187344961713Sgirish /*ARGSUSED*/
187444961713Sgirish void
187544961713Sgirish nxge_txdma_fix_hung_channel(p_nxge_t nxgep, uint16_t channel)
187644961713Sgirish {
187744961713Sgirish 	p_tx_ring_t	ring_p;
187844961713Sgirish 
187944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_hung_channel"));
188044961713Sgirish 	ring_p = nxge_txdma_get_ring(nxgep, channel);
188144961713Sgirish 	if (ring_p == NULL) {
188244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
188344961713Sgirish 			"<== nxge_txdma_fix_hung_channel"));
188444961713Sgirish 		return;
188544961713Sgirish 	}
188644961713Sgirish 
188744961713Sgirish 	if (ring_p->tdc != channel) {
188844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
188944961713Sgirish 			"<== nxge_txdma_fix_hung_channel: channel not matched "
189044961713Sgirish 			"ring tdc %d passed channel",
189144961713Sgirish 			ring_p->tdc, channel));
189244961713Sgirish 		return;
189344961713Sgirish 	}
189444961713Sgirish 
189544961713Sgirish 	nxge_txdma_fixup_channel(nxgep, ring_p, channel);
189644961713Sgirish 
189744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_hung_channel"));
189844961713Sgirish }
189944961713Sgirish 
190044961713Sgirish /*ARGSUSED*/
190144961713Sgirish void
190244961713Sgirish nxge_txdma_fixup_hung_channel(p_nxge_t nxgep, p_tx_ring_t ring_p,
190344961713Sgirish 	uint16_t channel)
190444961713Sgirish {
190544961713Sgirish 	npi_handle_t		handle;
190644961713Sgirish 	tdmc_intr_dbg_t		intr_dbg;
190744961713Sgirish 	int			status = NXGE_OK;
190844961713Sgirish 
190944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_hung_channel"));
191044961713Sgirish 
191144961713Sgirish 	if (ring_p == NULL) {
191244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
191344961713Sgirish 			"<== nxge_txdma_fixup_channel: NULL ring pointer"));
191444961713Sgirish 		return;
191544961713Sgirish 	}
191644961713Sgirish 
191744961713Sgirish 	if (ring_p->tdc != channel) {
191844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
191944961713Sgirish 			"<== nxge_txdma_fixup_hung_channel: channel "
192044961713Sgirish 			"not matched "
192144961713Sgirish 			"ring tdc %d passed channel",
192244961713Sgirish 			ring_p->tdc, channel));
192344961713Sgirish 		return;
192444961713Sgirish 	}
192544961713Sgirish 
192644961713Sgirish 	/* Reclaim descriptors */
192744961713Sgirish 	MUTEX_ENTER(&ring_p->lock);
192844961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, ring_p, 0);
192944961713Sgirish 	MUTEX_EXIT(&ring_p->lock);
193044961713Sgirish 
193144961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
193244961713Sgirish 	/*
193344961713Sgirish 	 * Stop the dma channel waits for the stop done.
193444961713Sgirish 	 * If the stop done bit is not set, then force
193544961713Sgirish 	 * an error.
193644961713Sgirish 	 */
193744961713Sgirish 	status = npi_txdma_channel_disable(handle, channel);
193844961713Sgirish 	if (!(status & NPI_TXDMA_STOP_FAILED)) {
193944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
194044961713Sgirish 			"<== nxge_txdma_fixup_hung_channel: stopped OK "
194144961713Sgirish 			"ring tdc %d passed channel %d",
194244961713Sgirish 			ring_p->tdc, channel));
194344961713Sgirish 		return;
194444961713Sgirish 	}
194544961713Sgirish 
194644961713Sgirish 	/* Inject any error */
194744961713Sgirish 	intr_dbg.value = 0;
194844961713Sgirish 	intr_dbg.bits.ldw.nack_pref = 1;
194944961713Sgirish 	(void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg);
195044961713Sgirish 
195144961713Sgirish 	/* Stop done bit will be set as a result of error injection */
195244961713Sgirish 	status = npi_txdma_channel_disable(handle, channel);
195344961713Sgirish 	if (!(status & NPI_TXDMA_STOP_FAILED)) {
195444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
195544961713Sgirish 			"<== nxge_txdma_fixup_hung_channel: stopped again"
195644961713Sgirish 			"ring tdc %d passed channel",
195744961713Sgirish 			ring_p->tdc, channel));
195844961713Sgirish 		return;
195944961713Sgirish 	}
196044961713Sgirish 
196144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
196244961713Sgirish 		"<== nxge_txdma_fixup_hung_channel: stop done still not set!! "
196344961713Sgirish 		"ring tdc %d passed channel",
196444961713Sgirish 		ring_p->tdc, channel));
196544961713Sgirish 
196644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_hung_channel"));
196744961713Sgirish }
196844961713Sgirish 
196944961713Sgirish /*ARGSUSED*/
197044961713Sgirish void
197144961713Sgirish nxge_reclaim_rings(p_nxge_t nxgep)
197244961713Sgirish {
1973678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1974678453a8Sspeer 	int tdc;
197544961713Sgirish 
1976678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_reclaim_rings"));
197744961713Sgirish 
1978678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
197944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1980678453a8Sspeer 		    "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
198144961713Sgirish 		return;
198244961713Sgirish 	}
198344961713Sgirish 
1984678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1985678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1986678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1987678453a8Sspeer 			if (ring) {
1988678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
1989678453a8Sspeer 				    "==> nxge_reclaim_rings: TDC %d", tdc));
1990678453a8Sspeer 				MUTEX_ENTER(&ring->lock);
1991678453a8Sspeer 				(void) nxge_txdma_reclaim(nxgep, ring, tdc);
1992678453a8Sspeer 				MUTEX_EXIT(&ring->lock);
1993678453a8Sspeer 			}
1994678453a8Sspeer 		}
199544961713Sgirish 	}
199644961713Sgirish 
199744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_reclaim_rings"));
199844961713Sgirish }
199944961713Sgirish 
200044961713Sgirish void
200144961713Sgirish nxge_txdma_regs_dump_channels(p_nxge_t nxgep)
200244961713Sgirish {
2003678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
2004678453a8Sspeer 	npi_handle_t handle;
2005678453a8Sspeer 	int tdc;
200644961713Sgirish 
2007678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_regs_dump_channels"));
200844961713Sgirish 
200944961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
201044961713Sgirish 
2011678453a8Sspeer 	if (!isLDOMguest(nxgep)) {
2012678453a8Sspeer 		(void) npi_txdma_dump_fzc_regs(handle);
201344961713Sgirish 
2014678453a8Sspeer 		/* Dump TXC registers. */
2015678453a8Sspeer 		(void) npi_txc_dump_fzc_regs(handle);
2016678453a8Sspeer 		(void) npi_txc_dump_port_fzc_regs(handle, nxgep->function_num);
201744961713Sgirish 	}
201844961713Sgirish 
2019678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
202044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
2021678453a8Sspeer 		    "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
202244961713Sgirish 		return;
202344961713Sgirish 	}
202444961713Sgirish 
2025678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
2026678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
2027678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
2028678453a8Sspeer 			if (ring) {
2029678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
2030678453a8Sspeer 				    "==> nxge_txdma_regs_dump_channels: "
2031678453a8Sspeer 				    "TDC %d", tdc));
2032678453a8Sspeer 				(void) npi_txdma_dump_tdc_regs(handle, tdc);
2033678453a8Sspeer 
2034678453a8Sspeer 				/* Dump TXC registers, if able to. */
2035678453a8Sspeer 				if (!isLDOMguest(nxgep)) {
2036678453a8Sspeer 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
2037678453a8Sspeer 					    "==> nxge_txdma_regs_dump_channels:"
2038678453a8Sspeer 					    " FZC TDC %d", tdc));
2039678453a8Sspeer 					(void) npi_txc_dump_tdc_fzc_regs
2040678453a8Sspeer 					    (handle, tdc);
2041678453a8Sspeer 				}
2042678453a8Sspeer 				nxge_txdma_regs_dump(nxgep, tdc);
2043678453a8Sspeer 			}
2044678453a8Sspeer 		}
204544961713Sgirish 	}
204644961713Sgirish 
204744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_regs_dump"));
204844961713Sgirish }
204944961713Sgirish 
205044961713Sgirish void
205144961713Sgirish nxge_txdma_regs_dump(p_nxge_t nxgep, int channel)
205244961713Sgirish {
205344961713Sgirish 	npi_handle_t		handle;
205444961713Sgirish 	tx_ring_hdl_t 		hdl;
205544961713Sgirish 	tx_ring_kick_t 		kick;
205644961713Sgirish 	tx_cs_t 		cs;
205744961713Sgirish 	txc_control_t		control;
205844961713Sgirish 	uint32_t		bitmap = 0;
205944961713Sgirish 	uint32_t		burst = 0;
206044961713Sgirish 	uint32_t		bytes = 0;
206144961713Sgirish 	dma_log_page_t		cfg;
206244961713Sgirish 
206344961713Sgirish 	printf("\n\tfunc # %d tdc %d ",
206444961713Sgirish 		nxgep->function_num, channel);
206544961713Sgirish 	cfg.page_num = 0;
206644961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
206744961713Sgirish 	(void) npi_txdma_log_page_get(handle, channel, &cfg);
206844961713Sgirish 	printf("\n\tlog page func %d valid page 0 %d",
206944961713Sgirish 		cfg.func_num, cfg.valid);
207044961713Sgirish 	cfg.page_num = 1;
207144961713Sgirish 	(void) npi_txdma_log_page_get(handle, channel, &cfg);
207244961713Sgirish 	printf("\n\tlog page func %d valid page 1 %d",
207344961713Sgirish 		cfg.func_num, cfg.valid);
207444961713Sgirish 
207544961713Sgirish 	(void) npi_txdma_ring_head_get(handle, channel, &hdl);
207644961713Sgirish 	(void) npi_txdma_desc_kick_reg_get(handle, channel, &kick);
207744961713Sgirish 	printf("\n\thead value is 0x%0llx",
207844961713Sgirish 		(long long)hdl.value);
207944961713Sgirish 	printf("\n\thead index %d", hdl.bits.ldw.head);
208044961713Sgirish 	printf("\n\tkick value is 0x%0llx",
208144961713Sgirish 		(long long)kick.value);
208244961713Sgirish 	printf("\n\ttail index %d\n", kick.bits.ldw.tail);
208344961713Sgirish 
208444961713Sgirish 	(void) npi_txdma_control_status(handle, OP_GET, channel, &cs);
208544961713Sgirish 	printf("\n\tControl statue is 0x%0llx", (long long)cs.value);
208644961713Sgirish 	printf("\n\tControl status RST state %d", cs.bits.ldw.rst);
208744961713Sgirish 
208844961713Sgirish 	(void) npi_txc_control(handle, OP_GET, &control);
208944961713Sgirish 	(void) npi_txc_port_dma_list_get(handle, nxgep->function_num, &bitmap);
209044961713Sgirish 	(void) npi_txc_dma_max_burst(handle, OP_GET, channel, &burst);
209144961713Sgirish 	(void) npi_txc_dma_bytes_transmitted(handle, channel, &bytes);
209244961713Sgirish 
209344961713Sgirish 	printf("\n\tTXC port control 0x%0llx",
209444961713Sgirish 		(long long)control.value);
209544961713Sgirish 	printf("\n\tTXC port bitmap 0x%x", bitmap);
209644961713Sgirish 	printf("\n\tTXC max burst %d", burst);
209744961713Sgirish 	printf("\n\tTXC bytes xmt %d\n", bytes);
209844961713Sgirish 
209944961713Sgirish 	{
210044961713Sgirish 		ipp_status_t status;
210144961713Sgirish 
210244961713Sgirish 		(void) npi_ipp_get_status(handle, nxgep->function_num, &status);
2103adfcba55Sjoycey #if defined(__i386)
2104adfcba55Sjoycey 		printf("\n\tIPP status 0x%llux\n", (uint64_t)status.value);
2105adfcba55Sjoycey #else
210644961713Sgirish 		printf("\n\tIPP status 0x%lux\n", (uint64_t)status.value);
2107adfcba55Sjoycey #endif
210844961713Sgirish 	}
210944961713Sgirish }
211044961713Sgirish 
211144961713Sgirish /*
2112678453a8Sspeer  * nxge_tdc_hvio_setup
2113678453a8Sspeer  *
2114678453a8Sspeer  *	I'm not exactly sure what this code does.
2115678453a8Sspeer  *
2116678453a8Sspeer  * Arguments:
2117678453a8Sspeer  * 	nxgep
2118678453a8Sspeer  * 	channel	The channel to map.
2119678453a8Sspeer  *
2120678453a8Sspeer  * Notes:
2121678453a8Sspeer  *
2122678453a8Sspeer  * NPI/NXGE function calls:
2123678453a8Sspeer  *	na
2124678453a8Sspeer  *
2125678453a8Sspeer  * Context:
2126678453a8Sspeer  *	Service domain?
212744961713Sgirish  */
2128678453a8Sspeer #if defined(sun4v) && defined(NIU_LP_WORKAROUND)
2129678453a8Sspeer static void
2130678453a8Sspeer nxge_tdc_hvio_setup(
2131678453a8Sspeer 	nxge_t *nxgep, int channel)
213244961713Sgirish {
2133678453a8Sspeer 	nxge_dma_common_t	*data;
2134678453a8Sspeer 	nxge_dma_common_t	*control;
2135678453a8Sspeer 	tx_ring_t 		*ring;
2136678453a8Sspeer 
2137678453a8Sspeer 	ring = nxgep->tx_rings->rings[channel];
2138678453a8Sspeer 	data = nxgep->tx_buf_pool_p->dma_buf_pool_p[channel];
2139678453a8Sspeer 
2140678453a8Sspeer 	ring->hv_set = B_FALSE;
2141678453a8Sspeer 
2142678453a8Sspeer 	ring->hv_tx_buf_base_ioaddr_pp =
2143678453a8Sspeer 	    (uint64_t)data->orig_ioaddr_pp;
2144678453a8Sspeer 	ring->hv_tx_buf_ioaddr_size =
2145678453a8Sspeer 	    (uint64_t)data->orig_alength;
2146678453a8Sspeer 
2147678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: "
2148678453a8Sspeer 		"hv data buf base io $%p size 0x%llx (%d) buf base io $%p "
2149678453a8Sspeer 		"orig vatopa base io $%p orig_len 0x%llx (%d)",
2150678453a8Sspeer 		ring->hv_tx_buf_base_ioaddr_pp,
2151678453a8Sspeer 		ring->hv_tx_buf_ioaddr_size, ring->hv_tx_buf_ioaddr_size,
2152678453a8Sspeer 		data->ioaddr_pp, data->orig_vatopa,
2153678453a8Sspeer 		data->orig_alength, data->orig_alength));
2154678453a8Sspeer 
2155678453a8Sspeer 	control = nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel];
2156678453a8Sspeer 
2157678453a8Sspeer 	ring->hv_tx_cntl_base_ioaddr_pp =
2158678453a8Sspeer 	    (uint64_t)control->orig_ioaddr_pp;
2159678453a8Sspeer 	ring->hv_tx_cntl_ioaddr_size =
2160678453a8Sspeer 	    (uint64_t)control->orig_alength;
2161678453a8Sspeer 
2162678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: "
2163678453a8Sspeer 		"hv cntl base io $%p orig ioaddr_pp ($%p) "
2164678453a8Sspeer 		"orig vatopa ($%p) size 0x%llx (%d 0x%x)",
2165678453a8Sspeer 		ring->hv_tx_cntl_base_ioaddr_pp,
2166678453a8Sspeer 		control->orig_ioaddr_pp, control->orig_vatopa,
2167678453a8Sspeer 		ring->hv_tx_cntl_ioaddr_size,
2168678453a8Sspeer 		control->orig_alength, control->orig_alength));
2169678453a8Sspeer }
217044961713Sgirish #endif
217144961713Sgirish 
2172678453a8Sspeer static nxge_status_t
2173678453a8Sspeer nxge_map_txdma(p_nxge_t nxgep, int channel)
2174678453a8Sspeer {
2175678453a8Sspeer 	nxge_dma_common_t	**pData;
2176678453a8Sspeer 	nxge_dma_common_t	**pControl;
2177678453a8Sspeer 	tx_ring_t 		**pRing, *ring;
2178678453a8Sspeer 	tx_mbox_t		**mailbox;
2179678453a8Sspeer 	uint32_t		num_chunks;
2180678453a8Sspeer 
2181678453a8Sspeer 	nxge_status_t		status = NXGE_OK;
218244961713Sgirish 
2183678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma"));
218444961713Sgirish 
2185678453a8Sspeer 	if (!nxgep->tx_cntl_pool_p->buf_allocated) {
2186678453a8Sspeer 		if (nxge_alloc_tx_mem_pool(nxgep) != NXGE_OK) {
2187678453a8Sspeer 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2188678453a8Sspeer 			    "<== nxge_map_txdma: buf not allocated"));
2189678453a8Sspeer 			return (NXGE_ERROR);
2190678453a8Sspeer 		}
219144961713Sgirish 	}
219244961713Sgirish 
2193678453a8Sspeer 	if (nxge_alloc_txb(nxgep, channel) != NXGE_OK)
219444961713Sgirish 		return (NXGE_ERROR);
219544961713Sgirish 
2196678453a8Sspeer 	num_chunks = nxgep->tx_buf_pool_p->num_chunks[channel];
2197678453a8Sspeer 	pData = &nxgep->tx_buf_pool_p->dma_buf_pool_p[channel];
2198678453a8Sspeer 	pControl = &nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel];
2199678453a8Sspeer 	pRing = &nxgep->tx_rings->rings[channel];
2200678453a8Sspeer 	mailbox = &nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
220144961713Sgirish 
2202678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: "
220344961713Sgirish 		"tx_rings $%p tx_desc_rings $%p",
2204678453a8Sspeer 		nxgep->tx_rings, nxgep->tx_rings->rings));
220544961713Sgirish 
220644961713Sgirish 	/*
2207678453a8Sspeer 	 * Map descriptors from the buffer pools for <channel>.
220844961713Sgirish 	 */
220944961713Sgirish 
2210678453a8Sspeer 	/*
2211678453a8Sspeer 	 * Set up and prepare buffer blocks, descriptors
2212678453a8Sspeer 	 * and mailbox.
2213678453a8Sspeer 	 */
2214678453a8Sspeer 	status = nxge_map_txdma_channel(nxgep, channel,
2215678453a8Sspeer 	    pData, pRing, num_chunks, pControl, mailbox);
2216678453a8Sspeer 	if (status != NXGE_OK) {
2217678453a8Sspeer 		NXGE_ERROR_MSG((nxgep, MEM3_CTL,
2218678453a8Sspeer 			"==> nxge_map_txdma(%d): nxge_map_txdma_channel() "
2219678453a8Sspeer 			"returned 0x%x",
2220678453a8Sspeer 			nxgep, channel, status));
2221678453a8Sspeer 		return (status);
222244961713Sgirish 	}
222344961713Sgirish 
2224678453a8Sspeer 	ring = *pRing;
222544961713Sgirish 
2226678453a8Sspeer 	ring->index = (uint16_t)channel;
2227678453a8Sspeer 	ring->tdc_stats = &nxgep->statsp->tdc_stats[channel];
222844961713Sgirish 
2229678453a8Sspeer #if defined(sun4v) && defined(NIU_LP_WORKAROUND)
2230678453a8Sspeer 	if (isLDOMguest(nxgep)) {
2231678453a8Sspeer 		(void) nxge_tdc_lp_conf(nxgep, channel);
2232678453a8Sspeer 	} else {
2233678453a8Sspeer 		nxge_tdc_hvio_setup(nxgep, channel);
223444961713Sgirish 	}
2235678453a8Sspeer #endif
223644961713Sgirish 
2237678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: "
2238678453a8Sspeer 	    "(status 0x%x channel %d)", status, channel));
223944961713Sgirish 
2240678453a8Sspeer 	return (status);
224144961713Sgirish }
224244961713Sgirish 
224344961713Sgirish static nxge_status_t
224444961713Sgirish nxge_map_txdma_channel(p_nxge_t nxgep, uint16_t channel,
224544961713Sgirish 	p_nxge_dma_common_t *dma_buf_p,
224644961713Sgirish 	p_tx_ring_t *tx_desc_p,
224744961713Sgirish 	uint32_t num_chunks,
224844961713Sgirish 	p_nxge_dma_common_t *dma_cntl_p,
224944961713Sgirish 	p_tx_mbox_t *tx_mbox_p)
225044961713Sgirish {
225144961713Sgirish 	int	status = NXGE_OK;
225244961713Sgirish 
225344961713Sgirish 	/*
225444961713Sgirish 	 * Set up and prepare buffer blocks, descriptors
225544961713Sgirish 	 * and mailbox.
225644961713Sgirish 	 */
2257678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL,
225844961713Sgirish 		"==> nxge_map_txdma_channel (channel %d)", channel));
225944961713Sgirish 	/*
226044961713Sgirish 	 * Transmit buffer blocks
226144961713Sgirish 	 */
226244961713Sgirish 	status = nxge_map_txdma_channel_buf_ring(nxgep, channel,
226344961713Sgirish 			dma_buf_p, tx_desc_p, num_chunks);
226444961713Sgirish 	if (status != NXGE_OK) {
226544961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
226644961713Sgirish 			"==> nxge_map_txdma_channel (channel %d): "
226744961713Sgirish 			"map buffer failed 0x%x", channel, status));
226844961713Sgirish 		goto nxge_map_txdma_channel_exit;
226944961713Sgirish 	}
227044961713Sgirish 
227144961713Sgirish 	/*
227244961713Sgirish 	 * Transmit block ring, and mailbox.
227344961713Sgirish 	 */
227444961713Sgirish 	nxge_map_txdma_channel_cfg_ring(nxgep, channel, dma_cntl_p, *tx_desc_p,
227544961713Sgirish 					tx_mbox_p);
227644961713Sgirish 
227744961713Sgirish 	goto nxge_map_txdma_channel_exit;
227844961713Sgirish 
227944961713Sgirish nxge_map_txdma_channel_fail1:
2280678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL,
228144961713Sgirish 		"==> nxge_map_txdma_channel: unmap buf"
228244961713Sgirish 		"(status 0x%x channel %d)",
228344961713Sgirish 		status, channel));
228444961713Sgirish 	nxge_unmap_txdma_channel_buf_ring(nxgep, *tx_desc_p);
228544961713Sgirish 
228644961713Sgirish nxge_map_txdma_channel_exit:
2287678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL,
228844961713Sgirish 		"<== nxge_map_txdma_channel: "
228944961713Sgirish 		"(status 0x%x channel %d)",
229044961713Sgirish 		status, channel));
229144961713Sgirish 
229244961713Sgirish 	return (status);
229344961713Sgirish }
229444961713Sgirish 
229544961713Sgirish /*ARGSUSED*/
229644961713Sgirish static void
2297678453a8Sspeer nxge_unmap_txdma_channel(p_nxge_t nxgep, uint16_t channel)
229844961713Sgirish {
2299678453a8Sspeer 	tx_ring_t *ring;
2300678453a8Sspeer 	tx_mbox_t *mailbox;
2301678453a8Sspeer 
230244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
230344961713Sgirish 		"==> nxge_unmap_txdma_channel (channel %d)", channel));
230444961713Sgirish 	/*
230544961713Sgirish 	 * unmap tx block ring, and mailbox.
230644961713Sgirish 	 */
2307678453a8Sspeer 	ring = nxgep->tx_rings->rings[channel];
2308678453a8Sspeer 	mailbox = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
2309678453a8Sspeer 
2310678453a8Sspeer 	(void) nxge_unmap_txdma_channel_cfg_ring(nxgep, ring, mailbox);
231144961713Sgirish 
231244961713Sgirish 	/* unmap buffer blocks */
2313678453a8Sspeer 	(void) nxge_unmap_txdma_channel_buf_ring(nxgep, ring);
2314678453a8Sspeer 
2315678453a8Sspeer 	nxge_free_txb(nxgep, channel);
231644961713Sgirish 
231744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_unmap_txdma_channel"));
231844961713Sgirish }
231944961713Sgirish 
2320678453a8Sspeer /*
2321678453a8Sspeer  * nxge_map_txdma_channel_cfg_ring
2322678453a8Sspeer  *
2323678453a8Sspeer  *	Map a TDC into our kernel space.
2324678453a8Sspeer  *	This function allocates all of the per-channel data structures.
2325678453a8Sspeer  *
2326678453a8Sspeer  * Arguments:
2327678453a8Sspeer  * 	nxgep
2328678453a8Sspeer  * 	dma_channel	The channel to map.
2329678453a8Sspeer  *	dma_cntl_p
2330678453a8Sspeer  *	tx_ring_p	dma_channel's transmit ring
2331678453a8Sspeer  *	tx_mbox_p	dma_channel's mailbox
2332678453a8Sspeer  *
2333678453a8Sspeer  * Notes:
2334678453a8Sspeer  *
2335678453a8Sspeer  * NPI/NXGE function calls:
2336678453a8Sspeer  *	nxge_setup_dma_common()
2337678453a8Sspeer  *
2338678453a8Sspeer  * Registers accessed:
2339678453a8Sspeer  *	none.
2340678453a8Sspeer  *
2341678453a8Sspeer  * Context:
2342678453a8Sspeer  *	Any domain
2343678453a8Sspeer  */
234444961713Sgirish /*ARGSUSED*/
234544961713Sgirish static void
234644961713Sgirish nxge_map_txdma_channel_cfg_ring(p_nxge_t nxgep, uint16_t dma_channel,
234744961713Sgirish 	p_nxge_dma_common_t *dma_cntl_p,
234844961713Sgirish 	p_tx_ring_t tx_ring_p,
234944961713Sgirish 	p_tx_mbox_t *tx_mbox_p)
235044961713Sgirish {
235144961713Sgirish 	p_tx_mbox_t 		mboxp;
235244961713Sgirish 	p_nxge_dma_common_t 	cntl_dmap;
235344961713Sgirish 	p_nxge_dma_common_t 	dmap;
235444961713Sgirish 	p_tx_rng_cfig_t		tx_ring_cfig_p;
235544961713Sgirish 	p_tx_ring_kick_t	tx_ring_kick_p;
235644961713Sgirish 	p_tx_cs_t		tx_cs_p;
235744961713Sgirish 	p_tx_dma_ent_msk_t	tx_evmask_p;
235844961713Sgirish 	p_txdma_mbh_t		mboxh_p;
235944961713Sgirish 	p_txdma_mbl_t		mboxl_p;
236044961713Sgirish 	uint64_t		tx_desc_len;
236144961713Sgirish 
236244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
236344961713Sgirish 		"==> nxge_map_txdma_channel_cfg_ring"));
236444961713Sgirish 
236544961713Sgirish 	cntl_dmap = *dma_cntl_p;
236644961713Sgirish 
236744961713Sgirish 	dmap = (p_nxge_dma_common_t)&tx_ring_p->tdc_desc;
236844961713Sgirish 	nxge_setup_dma_common(dmap, cntl_dmap, tx_ring_p->tx_ring_size,
236944961713Sgirish 			sizeof (tx_desc_t));
237044961713Sgirish 	/*
237144961713Sgirish 	 * Zero out transmit ring descriptors.
237244961713Sgirish 	 */
237344961713Sgirish 	bzero((caddr_t)dmap->kaddrp, dmap->alength);
237444961713Sgirish 	tx_ring_cfig_p = &(tx_ring_p->tx_ring_cfig);
237544961713Sgirish 	tx_ring_kick_p = &(tx_ring_p->tx_ring_kick);
237644961713Sgirish 	tx_cs_p = &(tx_ring_p->tx_cs);
237744961713Sgirish 	tx_evmask_p = &(tx_ring_p->tx_evmask);
237844961713Sgirish 	tx_ring_cfig_p->value = 0;
237944961713Sgirish 	tx_ring_kick_p->value = 0;
238044961713Sgirish 	tx_cs_p->value = 0;
238144961713Sgirish 	tx_evmask_p->value = 0;
238244961713Sgirish 
238344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
238444961713Sgirish 		"==> nxge_map_txdma_channel_cfg_ring: channel %d des $%p",
238544961713Sgirish 		dma_channel,
238644961713Sgirish 		dmap->dma_cookie.dmac_laddress));
238744961713Sgirish 
238844961713Sgirish 	tx_ring_cfig_p->value = 0;
238944961713Sgirish 	tx_desc_len = (uint64_t)(tx_ring_p->tx_ring_size >> 3);
239044961713Sgirish 	tx_ring_cfig_p->value =
239144961713Sgirish 		(dmap->dma_cookie.dmac_laddress & TX_RNG_CFIG_ADDR_MASK) |
239244961713Sgirish 		(tx_desc_len << TX_RNG_CFIG_LEN_SHIFT);
239344961713Sgirish 
239444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
239544961713Sgirish 		"==> nxge_map_txdma_channel_cfg_ring: channel %d cfg 0x%llx",
239644961713Sgirish 		dma_channel,
239744961713Sgirish 		tx_ring_cfig_p->value));
239844961713Sgirish 
239944961713Sgirish 	tx_cs_p->bits.ldw.rst = 1;
240044961713Sgirish 
240144961713Sgirish 	/* Map in mailbox */
240244961713Sgirish 	mboxp = (p_tx_mbox_t)
240344961713Sgirish 		KMEM_ZALLOC(sizeof (tx_mbox_t), KM_SLEEP);
240444961713Sgirish 	dmap = (p_nxge_dma_common_t)&mboxp->tx_mbox;
240544961713Sgirish 	nxge_setup_dma_common(dmap, cntl_dmap, 1, sizeof (txdma_mailbox_t));
240644961713Sgirish 	mboxh_p = (p_txdma_mbh_t)&tx_ring_p->tx_mbox_mbh;
240744961713Sgirish 	mboxl_p = (p_txdma_mbl_t)&tx_ring_p->tx_mbox_mbl;
240844961713Sgirish 	mboxh_p->value = mboxl_p->value = 0;
240944961713Sgirish 
241044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
241144961713Sgirish 		"==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
241244961713Sgirish 		dmap->dma_cookie.dmac_laddress));
241344961713Sgirish 
241444961713Sgirish 	mboxh_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress >>
241544961713Sgirish 				TXDMA_MBH_ADDR_SHIFT) & TXDMA_MBH_MASK);
241644961713Sgirish 
241744961713Sgirish 	mboxl_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress &
241844961713Sgirish 				TXDMA_MBL_MASK) >> TXDMA_MBL_SHIFT);
241944961713Sgirish 
242044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
242144961713Sgirish 		"==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
242244961713Sgirish 		dmap->dma_cookie.dmac_laddress));
242344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
242444961713Sgirish 		"==> nxge_map_txdma_channel_cfg_ring: hmbox $%p "
242544961713Sgirish 		"mbox $%p",
242644961713Sgirish 		mboxh_p->bits.ldw.mbaddr, mboxl_p->bits.ldw.mbaddr));
242744961713Sgirish 	tx_ring_p->page_valid.value = 0;
242844961713Sgirish 	tx_ring_p->page_mask_1.value = tx_ring_p->page_mask_2.value = 0;
242944961713Sgirish 	tx_ring_p->page_value_1.value = tx_ring_p->page_value_2.value = 0;
243044961713Sgirish 	tx_ring_p->page_reloc_1.value = tx_ring_p->page_reloc_2.value = 0;
243144961713Sgirish 	tx_ring_p->page_hdl.value = 0;
243244961713Sgirish 
243344961713Sgirish 	tx_ring_p->page_valid.bits.ldw.page0 = 1;
243444961713Sgirish 	tx_ring_p->page_valid.bits.ldw.page1 = 1;
243544961713Sgirish 
243644961713Sgirish 	tx_ring_p->max_burst.value = 0;
243744961713Sgirish 	tx_ring_p->max_burst.bits.ldw.dma_max_burst = TXC_DMA_MAX_BURST_DEFAULT;
243844961713Sgirish 
243944961713Sgirish 	*tx_mbox_p = mboxp;
244044961713Sgirish 
244144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
244244961713Sgirish 				"<== nxge_map_txdma_channel_cfg_ring"));
244344961713Sgirish }
244444961713Sgirish 
244544961713Sgirish /*ARGSUSED*/
244644961713Sgirish static void
244744961713Sgirish nxge_unmap_txdma_channel_cfg_ring(p_nxge_t nxgep,
244844961713Sgirish 	p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p)
244944961713Sgirish {
245044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
245144961713Sgirish 		"==> nxge_unmap_txdma_channel_cfg_ring: channel %d",
245244961713Sgirish 		tx_ring_p->tdc));
245344961713Sgirish 
245444961713Sgirish 	KMEM_FREE(tx_mbox_p, sizeof (tx_mbox_t));
245544961713Sgirish 
245644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
245744961713Sgirish 		"<== nxge_unmap_txdma_channel_cfg_ring"));
245844961713Sgirish }
245944961713Sgirish 
2460678453a8Sspeer /*
2461678453a8Sspeer  * nxge_map_txdma_channel_buf_ring
2462678453a8Sspeer  *
2463678453a8Sspeer  *
2464678453a8Sspeer  * Arguments:
2465678453a8Sspeer  * 	nxgep
2466678453a8Sspeer  * 	channel		The channel to map.
2467678453a8Sspeer  *	dma_buf_p
2468678453a8Sspeer  *	tx_desc_p	channel's descriptor ring
2469678453a8Sspeer  *	num_chunks
2470678453a8Sspeer  *
2471678453a8Sspeer  * Notes:
2472678453a8Sspeer  *
2473678453a8Sspeer  * NPI/NXGE function calls:
2474678453a8Sspeer  *	nxge_setup_dma_common()
2475678453a8Sspeer  *
2476678453a8Sspeer  * Registers accessed:
2477678453a8Sspeer  *	none.
2478678453a8Sspeer  *
2479678453a8Sspeer  * Context:
2480678453a8Sspeer  *	Any domain
2481678453a8Sspeer  */
248244961713Sgirish static nxge_status_t
248344961713Sgirish nxge_map_txdma_channel_buf_ring(p_nxge_t nxgep, uint16_t channel,
248444961713Sgirish 	p_nxge_dma_common_t *dma_buf_p,
248544961713Sgirish 	p_tx_ring_t *tx_desc_p, uint32_t num_chunks)
248644961713Sgirish {
248744961713Sgirish 	p_nxge_dma_common_t 	dma_bufp, tmp_bufp;
248844961713Sgirish 	p_nxge_dma_common_t 	dmap;
248944961713Sgirish 	nxge_os_dma_handle_t	tx_buf_dma_handle;
249044961713Sgirish 	p_tx_ring_t 		tx_ring_p;
249144961713Sgirish 	p_tx_msg_t 		tx_msg_ring;
249244961713Sgirish 	nxge_status_t		status = NXGE_OK;
249344961713Sgirish 	int			ddi_status = DDI_SUCCESS;
249444961713Sgirish 	int			i, j, index;
249544961713Sgirish 	uint32_t		size, bsize;
249644961713Sgirish 	uint32_t 		nblocks, nmsgs;
249744961713Sgirish 
249844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
249944961713Sgirish 		"==> nxge_map_txdma_channel_buf_ring"));
250044961713Sgirish 
250144961713Sgirish 	dma_bufp = tmp_bufp = *dma_buf_p;
250244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
250344961713Sgirish 		" nxge_map_txdma_channel_buf_ring: channel %d to map %d "
250444961713Sgirish 		"chunks bufp $%p",
250544961713Sgirish 		channel, num_chunks, dma_bufp));
250644961713Sgirish 
250744961713Sgirish 	nmsgs = 0;
250844961713Sgirish 	for (i = 0; i < num_chunks; i++, tmp_bufp++) {
250944961713Sgirish 		nmsgs += tmp_bufp->nblocks;
251044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
251144961713Sgirish 			"==> nxge_map_txdma_channel_buf_ring: channel %d "
251244961713Sgirish 			"bufp $%p nblocks %d nmsgs %d",
251344961713Sgirish 			channel, tmp_bufp, tmp_bufp->nblocks, nmsgs));
251444961713Sgirish 	}
251544961713Sgirish 	if (!nmsgs) {
251644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
251744961713Sgirish 			"<== nxge_map_txdma_channel_buf_ring: channel %d "
251844961713Sgirish 			"no msg blocks",
251944961713Sgirish 			channel));
252044961713Sgirish 		status = NXGE_ERROR;
252144961713Sgirish 		goto nxge_map_txdma_channel_buf_ring_exit;
252244961713Sgirish 	}
252344961713Sgirish 
252444961713Sgirish 	tx_ring_p = (p_tx_ring_t)
252544961713Sgirish 		KMEM_ZALLOC(sizeof (tx_ring_t), KM_SLEEP);
252644961713Sgirish 	MUTEX_INIT(&tx_ring_p->lock, NULL, MUTEX_DRIVER,
252744961713Sgirish 		(void *)nxgep->interrupt_cookie);
25281f8914d5Sml 
2529*22c0d73aSspeer 	(void) atomic_swap_32(&tx_ring_p->tx_ring_offline, NXGE_TX_RING_ONLINE);
25301f8914d5Sml 	tx_ring_p->nxgep = nxgep;
25311f8914d5Sml 	tx_ring_p->serial = nxge_serialize_create(nmsgs,
25321f8914d5Sml 				nxge_serial_tx, tx_ring_p);
253344961713Sgirish 	/*
253444961713Sgirish 	 * Allocate transmit message rings and handles for packets
253544961713Sgirish 	 * not to be copied to premapped buffers.
253644961713Sgirish 	 */
253744961713Sgirish 	size = nmsgs * sizeof (tx_msg_t);
253844961713Sgirish 	tx_msg_ring = KMEM_ZALLOC(size, KM_SLEEP);
253944961713Sgirish 	for (i = 0; i < nmsgs; i++) {
254044961713Sgirish 		ddi_status = ddi_dma_alloc_handle(nxgep->dip, &nxge_tx_dma_attr,
254144961713Sgirish 				DDI_DMA_DONTWAIT, 0,
254244961713Sgirish 				&tx_msg_ring[i].dma_handle);
254344961713Sgirish 		if (ddi_status != DDI_SUCCESS) {
254444961713Sgirish 			status |= NXGE_DDI_FAILED;
254544961713Sgirish 			break;
254644961713Sgirish 		}
254744961713Sgirish 	}
254844961713Sgirish 	if (i < nmsgs) {
254956d930aeSspeer 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
255056d930aeSspeer 		    "Allocate handles failed."));
255144961713Sgirish 		goto nxge_map_txdma_channel_buf_ring_fail1;
255244961713Sgirish 	}
255344961713Sgirish 
255444961713Sgirish 	tx_ring_p->tdc = channel;
255544961713Sgirish 	tx_ring_p->tx_msg_ring = tx_msg_ring;
255644961713Sgirish 	tx_ring_p->tx_ring_size = nmsgs;
255744961713Sgirish 	tx_ring_p->num_chunks = num_chunks;
255844961713Sgirish 	if (!nxge_tx_intr_thres) {
255944961713Sgirish 		nxge_tx_intr_thres = tx_ring_p->tx_ring_size/4;
256044961713Sgirish 	}
256144961713Sgirish 	tx_ring_p->tx_wrap_mask = tx_ring_p->tx_ring_size - 1;
256244961713Sgirish 	tx_ring_p->rd_index = 0;
256344961713Sgirish 	tx_ring_p->wr_index = 0;
256444961713Sgirish 	tx_ring_p->ring_head.value = 0;
256544961713Sgirish 	tx_ring_p->ring_kick_tail.value = 0;
256644961713Sgirish 	tx_ring_p->descs_pending = 0;
256744961713Sgirish 
256844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
256944961713Sgirish 		"==> nxge_map_txdma_channel_buf_ring: channel %d "
257044961713Sgirish 		"actual tx desc max %d nmsgs %d "
257144961713Sgirish 		"(config nxge_tx_ring_size %d)",
257244961713Sgirish 		channel, tx_ring_p->tx_ring_size, nmsgs,
257344961713Sgirish 		nxge_tx_ring_size));
257444961713Sgirish 
257544961713Sgirish 	/*
257644961713Sgirish 	 * Map in buffers from the buffer pool.
257744961713Sgirish 	 */
257844961713Sgirish 	index = 0;
257944961713Sgirish 	bsize = dma_bufp->block_size;
258044961713Sgirish 
258144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel_buf_ring: "
258244961713Sgirish 		"dma_bufp $%p tx_rng_p $%p "
258344961713Sgirish 		"tx_msg_rng_p $%p bsize %d",
258444961713Sgirish 		dma_bufp, tx_ring_p, tx_msg_ring, bsize));
258544961713Sgirish 
258644961713Sgirish 	tx_buf_dma_handle = dma_bufp->dma_handle;
258744961713Sgirish 	for (i = 0; i < num_chunks; i++, dma_bufp++) {
258844961713Sgirish 		bsize = dma_bufp->block_size;
258944961713Sgirish 		nblocks = dma_bufp->nblocks;
259044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
259144961713Sgirish 			"==> nxge_map_txdma_channel_buf_ring: dma chunk %d "
259244961713Sgirish 			"size %d dma_bufp $%p",
259344961713Sgirish 			i, sizeof (nxge_dma_common_t), dma_bufp));
259444961713Sgirish 
259544961713Sgirish 		for (j = 0; j < nblocks; j++) {
259644961713Sgirish 			tx_msg_ring[index].buf_dma_handle = tx_buf_dma_handle;
259744961713Sgirish 			dmap = &tx_msg_ring[index++].buf_dma;
259844961713Sgirish #ifdef TX_MEM_DEBUG
259944961713Sgirish 			NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
260044961713Sgirish 				"==> nxge_map_txdma_channel_buf_ring: j %d"
260144961713Sgirish 				"dmap $%p", i, dmap));
260244961713Sgirish #endif
260344961713Sgirish 			nxge_setup_dma_common(dmap, dma_bufp, 1,
260444961713Sgirish 				bsize);
260544961713Sgirish 		}
260644961713Sgirish 	}
260744961713Sgirish 
260844961713Sgirish 	if (i < num_chunks) {
260956d930aeSspeer 		status = NXGE_ERROR;
261044961713Sgirish 		goto nxge_map_txdma_channel_buf_ring_fail1;
261144961713Sgirish 	}
261244961713Sgirish 
261344961713Sgirish 	*tx_desc_p = tx_ring_p;
261444961713Sgirish 
261544961713Sgirish 	goto nxge_map_txdma_channel_buf_ring_exit;
261644961713Sgirish 
261744961713Sgirish nxge_map_txdma_channel_buf_ring_fail1:
26181f8914d5Sml 	if (tx_ring_p->serial) {
26191f8914d5Sml 		nxge_serialize_destroy(tx_ring_p->serial);
26201f8914d5Sml 		tx_ring_p->serial = NULL;
26211f8914d5Sml 	}
26221f8914d5Sml 
262344961713Sgirish 	index--;
262444961713Sgirish 	for (; index >= 0; index--) {
262556d930aeSspeer 		if (tx_msg_ring[index].dma_handle != NULL) {
262656d930aeSspeer 			ddi_dma_free_handle(&tx_msg_ring[index].dma_handle);
262744961713Sgirish 		}
262844961713Sgirish 	}
262944961713Sgirish 	MUTEX_DESTROY(&tx_ring_p->lock);
263056d930aeSspeer 	KMEM_FREE(tx_msg_ring, size);
263144961713Sgirish 	KMEM_FREE(tx_ring_p, sizeof (tx_ring_t));
263244961713Sgirish 
263356d930aeSspeer 	status = NXGE_ERROR;
263456d930aeSspeer 
263544961713Sgirish nxge_map_txdma_channel_buf_ring_exit:
263644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
263744961713Sgirish 		"<== nxge_map_txdma_channel_buf_ring status 0x%x", status));
263844961713Sgirish 
263944961713Sgirish 	return (status);
264044961713Sgirish }
264144961713Sgirish 
264244961713Sgirish /*ARGSUSED*/
264344961713Sgirish static void
264444961713Sgirish nxge_unmap_txdma_channel_buf_ring(p_nxge_t nxgep, p_tx_ring_t tx_ring_p)
264544961713Sgirish {
264644961713Sgirish 	p_tx_msg_t 		tx_msg_ring;
264744961713Sgirish 	p_tx_msg_t 		tx_msg_p;
264844961713Sgirish 	int			i;
264944961713Sgirish 
265044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
265144961713Sgirish 		"==> nxge_unmap_txdma_channel_buf_ring"));
265244961713Sgirish 	if (tx_ring_p == NULL) {
265344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
265444961713Sgirish 			"<== nxge_unmap_txdma_channel_buf_ring: NULL ringp"));
265544961713Sgirish 		return;
265644961713Sgirish 	}
265744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
265844961713Sgirish 		"==> nxge_unmap_txdma_channel_buf_ring: channel %d",
265944961713Sgirish 		tx_ring_p->tdc));
266044961713Sgirish 
266144961713Sgirish 	tx_msg_ring = tx_ring_p->tx_msg_ring;
2662678453a8Sspeer 
2663678453a8Sspeer 	/*
2664678453a8Sspeer 	 * Since the serialization thread, timer thread and
2665678453a8Sspeer 	 * interrupt thread can all call the transmit reclaim,
2666678453a8Sspeer 	 * the unmapping function needs to acquire the lock
2667678453a8Sspeer 	 * to free those buffers which were transmitted
2668678453a8Sspeer 	 * by the hardware already.
2669678453a8Sspeer 	 */
2670678453a8Sspeer 	MUTEX_ENTER(&tx_ring_p->lock);
2671678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
2672678453a8Sspeer 	    "==> nxge_unmap_txdma_channel_buf_ring (reclaim): "
2673678453a8Sspeer 	    "channel %d",
2674678453a8Sspeer 	    tx_ring_p->tdc));
2675678453a8Sspeer 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
2676678453a8Sspeer 
267744961713Sgirish 	for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
267844961713Sgirish 		tx_msg_p = &tx_msg_ring[i];
267944961713Sgirish 		if (tx_msg_p->tx_message != NULL) {
268044961713Sgirish 			freemsg(tx_msg_p->tx_message);
268144961713Sgirish 			tx_msg_p->tx_message = NULL;
268244961713Sgirish 		}
268344961713Sgirish 	}
268444961713Sgirish 
268544961713Sgirish 	for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
268644961713Sgirish 		if (tx_msg_ring[i].dma_handle != NULL) {
268744961713Sgirish 			ddi_dma_free_handle(&tx_msg_ring[i].dma_handle);
268844961713Sgirish 		}
2689678453a8Sspeer 		tx_msg_ring[i].dma_handle = NULL;
269044961713Sgirish 	}
269144961713Sgirish 
2692678453a8Sspeer 	MUTEX_EXIT(&tx_ring_p->lock);
2693678453a8Sspeer 
26941f8914d5Sml 	if (tx_ring_p->serial) {
26951f8914d5Sml 		nxge_serialize_destroy(tx_ring_p->serial);
26961f8914d5Sml 		tx_ring_p->serial = NULL;
26971f8914d5Sml 	}
26981f8914d5Sml 
269944961713Sgirish 	MUTEX_DESTROY(&tx_ring_p->lock);
270044961713Sgirish 	KMEM_FREE(tx_msg_ring, sizeof (tx_msg_t) * tx_ring_p->tx_ring_size);
270144961713Sgirish 	KMEM_FREE(tx_ring_p, sizeof (tx_ring_t));
270244961713Sgirish 
270344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
270444961713Sgirish 		"<== nxge_unmap_txdma_channel_buf_ring"));
270544961713Sgirish }
270644961713Sgirish 
270744961713Sgirish static nxge_status_t
2708678453a8Sspeer nxge_txdma_hw_start(p_nxge_t nxgep, int channel)
270944961713Sgirish {
271044961713Sgirish 	p_tx_rings_t 		tx_rings;
271144961713Sgirish 	p_tx_ring_t 		*tx_desc_rings;
271244961713Sgirish 	p_tx_mbox_areas_t 	tx_mbox_areas_p;
271344961713Sgirish 	p_tx_mbox_t		*tx_mbox_p;
271444961713Sgirish 	nxge_status_t		status = NXGE_OK;
271544961713Sgirish 
271644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start"));
271744961713Sgirish 
271844961713Sgirish 	tx_rings = nxgep->tx_rings;
271944961713Sgirish 	if (tx_rings == NULL) {
272044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
272144961713Sgirish 			"<== nxge_txdma_hw_start: NULL ring pointer"));
272244961713Sgirish 		return (NXGE_ERROR);
272344961713Sgirish 	}
272444961713Sgirish 	tx_desc_rings = tx_rings->rings;
272544961713Sgirish 	if (tx_desc_rings == NULL) {
272644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
272744961713Sgirish 			"<== nxge_txdma_hw_start: NULL ring pointers"));
272844961713Sgirish 		return (NXGE_ERROR);
272944961713Sgirish 	}
273044961713Sgirish 
2731678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
2732678453a8Sspeer 	    "tx_rings $%p tx_desc_rings $%p", tx_rings, tx_desc_rings));
273344961713Sgirish 
273444961713Sgirish 	tx_mbox_areas_p = nxgep->tx_mbox_areas_p;
273544961713Sgirish 	tx_mbox_p = tx_mbox_areas_p->txmbox_areas_p;
273644961713Sgirish 
2737678453a8Sspeer 	status = nxge_txdma_start_channel(nxgep, channel,
2738678453a8Sspeer 	    (p_tx_ring_t)tx_desc_rings[channel],
2739678453a8Sspeer 	    (p_tx_mbox_t)tx_mbox_p[channel]);
2740678453a8Sspeer 	if (status != NXGE_OK) {
2741678453a8Sspeer 		goto nxge_txdma_hw_start_fail1;
274244961713Sgirish 	}
274344961713Sgirish 
274444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
274544961713Sgirish 		"tx_rings $%p rings $%p",
274644961713Sgirish 		nxgep->tx_rings, nxgep->tx_rings->rings));
274744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
274844961713Sgirish 		"tx_rings $%p tx_desc_rings $%p",
274944961713Sgirish 		nxgep->tx_rings, tx_desc_rings));
275044961713Sgirish 
275144961713Sgirish 	goto nxge_txdma_hw_start_exit;
275244961713Sgirish 
275344961713Sgirish nxge_txdma_hw_start_fail1:
275444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
275544961713Sgirish 		"==> nxge_txdma_hw_start: disable "
2756678453a8Sspeer 		"(status 0x%x channel %d)", status, channel));
275744961713Sgirish 
275844961713Sgirish nxge_txdma_hw_start_exit:
275944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
276044961713Sgirish 		"==> nxge_txdma_hw_start: (status 0x%x)", status));
276144961713Sgirish 
276244961713Sgirish 	return (status);
276344961713Sgirish }
276444961713Sgirish 
2765678453a8Sspeer /*
2766678453a8Sspeer  * nxge_txdma_start_channel
2767678453a8Sspeer  *
2768678453a8Sspeer  *	Start a TDC.
2769678453a8Sspeer  *
2770678453a8Sspeer  * Arguments:
2771678453a8Sspeer  * 	nxgep
2772678453a8Sspeer  * 	channel		The channel to start.
2773678453a8Sspeer  * 	tx_ring_p	channel's transmit descriptor ring.
2774678453a8Sspeer  * 	tx_mbox_p	channel' smailbox.
2775678453a8Sspeer  *
2776678453a8Sspeer  * Notes:
2777678453a8Sspeer  *
2778678453a8Sspeer  * NPI/NXGE function calls:
2779678453a8Sspeer  *	nxge_reset_txdma_channel()
2780678453a8Sspeer  *	nxge_init_txdma_channel_event_mask()
2781678453a8Sspeer  *	nxge_enable_txdma_channel()
2782678453a8Sspeer  *
2783678453a8Sspeer  * Registers accessed:
2784678453a8Sspeer  *	none directly (see functions above).
2785678453a8Sspeer  *
2786678453a8Sspeer  * Context:
2787678453a8Sspeer  *	Any domain
2788678453a8Sspeer  */
278944961713Sgirish static nxge_status_t
279044961713Sgirish nxge_txdma_start_channel(p_nxge_t nxgep, uint16_t channel,
279144961713Sgirish     p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p)
279244961713Sgirish 
279344961713Sgirish {
279444961713Sgirish 	nxge_status_t		status = NXGE_OK;
279544961713Sgirish 
279644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
279744961713Sgirish 		"==> nxge_txdma_start_channel (channel %d)", channel));
279844961713Sgirish 	/*
279944961713Sgirish 	 * TXDMA/TXC must be in stopped state.
280044961713Sgirish 	 */
280144961713Sgirish 	(void) nxge_txdma_stop_inj_err(nxgep, channel);
280244961713Sgirish 
280344961713Sgirish 	/*
280444961713Sgirish 	 * Reset TXDMA channel
280544961713Sgirish 	 */
280644961713Sgirish 	tx_ring_p->tx_cs.value = 0;
280744961713Sgirish 	tx_ring_p->tx_cs.bits.ldw.rst = 1;
280844961713Sgirish 	status = nxge_reset_txdma_channel(nxgep, channel,
280944961713Sgirish 			tx_ring_p->tx_cs.value);
281044961713Sgirish 	if (status != NXGE_OK) {
281144961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
281244961713Sgirish 			"==> nxge_txdma_start_channel (channel %d)"
281344961713Sgirish 			" reset channel failed 0x%x", channel, status));
281444961713Sgirish 		goto nxge_txdma_start_channel_exit;
281544961713Sgirish 	}
281644961713Sgirish 
281744961713Sgirish 	/*
281844961713Sgirish 	 * Initialize the TXDMA channel specific FZC control
281944961713Sgirish 	 * configurations. These FZC registers are pertaining
282044961713Sgirish 	 * to each TX channel (i.e. logical pages).
282144961713Sgirish 	 */
2822678453a8Sspeer 	if (!isLDOMguest(nxgep)) {
2823678453a8Sspeer 		status = nxge_init_fzc_txdma_channel(nxgep, channel,
2824678453a8Sspeer 		    tx_ring_p, tx_mbox_p);
2825678453a8Sspeer 		if (status != NXGE_OK) {
2826678453a8Sspeer 			goto nxge_txdma_start_channel_exit;
2827678453a8Sspeer 		}
282844961713Sgirish 	}
282944961713Sgirish 
283044961713Sgirish 	/*
283144961713Sgirish 	 * Initialize the event masks.
283244961713Sgirish 	 */
283344961713Sgirish 	tx_ring_p->tx_evmask.value = 0;
283444961713Sgirish 	status = nxge_init_txdma_channel_event_mask(nxgep,
2835678453a8Sspeer 	    channel, &tx_ring_p->tx_evmask);
283644961713Sgirish 	if (status != NXGE_OK) {
283744961713Sgirish 		goto nxge_txdma_start_channel_exit;
283844961713Sgirish 	}
283944961713Sgirish 
284044961713Sgirish 	/*
284144961713Sgirish 	 * Load TXDMA descriptors, buffers, mailbox,
284244961713Sgirish 	 * initialise the DMA channels and
284344961713Sgirish 	 * enable each DMA channel.
284444961713Sgirish 	 */
284544961713Sgirish 	status = nxge_enable_txdma_channel(nxgep, channel,
284644961713Sgirish 			tx_ring_p, tx_mbox_p);
284744961713Sgirish 	if (status != NXGE_OK) {
284844961713Sgirish 		goto nxge_txdma_start_channel_exit;
284944961713Sgirish 	}
285044961713Sgirish 
285144961713Sgirish nxge_txdma_start_channel_exit:
285244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_start_channel"));
285344961713Sgirish 
285444961713Sgirish 	return (status);
285544961713Sgirish }
285644961713Sgirish 
2857678453a8Sspeer /*
2858678453a8Sspeer  * nxge_txdma_stop_channel
2859678453a8Sspeer  *
2860678453a8Sspeer  *	Stop a TDC.
2861678453a8Sspeer  *
2862678453a8Sspeer  * Arguments:
2863678453a8Sspeer  * 	nxgep
2864678453a8Sspeer  * 	channel		The channel to stop.
2865678453a8Sspeer  * 	tx_ring_p	channel's transmit descriptor ring.
2866678453a8Sspeer  * 	tx_mbox_p	channel' smailbox.
2867678453a8Sspeer  *
2868678453a8Sspeer  * Notes:
2869678453a8Sspeer  *
2870678453a8Sspeer  * NPI/NXGE function calls:
2871678453a8Sspeer  *	nxge_txdma_stop_inj_err()
2872678453a8Sspeer  *	nxge_reset_txdma_channel()
2873678453a8Sspeer  *	nxge_init_txdma_channel_event_mask()
2874678453a8Sspeer  *	nxge_init_txdma_channel_cntl_stat()
2875678453a8Sspeer  *	nxge_disable_txdma_channel()
2876678453a8Sspeer  *
2877678453a8Sspeer  * Registers accessed:
2878678453a8Sspeer  *	none directly (see functions above).
2879678453a8Sspeer  *
2880678453a8Sspeer  * Context:
2881678453a8Sspeer  *	Any domain
2882678453a8Sspeer  */
288344961713Sgirish /*ARGSUSED*/
288444961713Sgirish static nxge_status_t
2885678453a8Sspeer nxge_txdma_stop_channel(p_nxge_t nxgep, uint16_t channel)
288644961713Sgirish {
2887678453a8Sspeer 	p_tx_ring_t tx_ring_p;
2888678453a8Sspeer 	int status = NXGE_OK;
288944961713Sgirish 
289044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
289144961713Sgirish 		"==> nxge_txdma_stop_channel: channel %d", channel));
289244961713Sgirish 
289344961713Sgirish 	/*
289444961713Sgirish 	 * Stop (disable) TXDMA and TXC (if stop bit is set
289544961713Sgirish 	 * and STOP_N_GO bit not set, the TXDMA reset state will
289644961713Sgirish 	 * not be set if reset TXDMA.
289744961713Sgirish 	 */
289844961713Sgirish 	(void) nxge_txdma_stop_inj_err(nxgep, channel);
289944961713Sgirish 
2900678453a8Sspeer 	tx_ring_p = nxgep->tx_rings->rings[channel];
2901678453a8Sspeer 
290244961713Sgirish 	/*
290344961713Sgirish 	 * Reset TXDMA channel
290444961713Sgirish 	 */
290544961713Sgirish 	tx_ring_p->tx_cs.value = 0;
290644961713Sgirish 	tx_ring_p->tx_cs.bits.ldw.rst = 1;
290744961713Sgirish 	status = nxge_reset_txdma_channel(nxgep, channel,
290844961713Sgirish 			tx_ring_p->tx_cs.value);
290944961713Sgirish 	if (status != NXGE_OK) {
291044961713Sgirish 		goto nxge_txdma_stop_channel_exit;
291144961713Sgirish 	}
291244961713Sgirish 
291344961713Sgirish #ifdef HARDWARE_REQUIRED
291444961713Sgirish 	/* Set up the interrupt event masks. */
291544961713Sgirish 	tx_ring_p->tx_evmask.value = 0;
291644961713Sgirish 	status = nxge_init_txdma_channel_event_mask(nxgep,
291744961713Sgirish 			channel, &tx_ring_p->tx_evmask);
291844961713Sgirish 	if (status != NXGE_OK) {
291944961713Sgirish 		goto nxge_txdma_stop_channel_exit;
292044961713Sgirish 	}
292144961713Sgirish 
292244961713Sgirish 	/* Initialize the DMA control and status register */
292344961713Sgirish 	tx_ring_p->tx_cs.value = TX_ENT_MSK_MK_ALL;
292444961713Sgirish 	status = nxge_init_txdma_channel_cntl_stat(nxgep, channel,
292544961713Sgirish 			tx_ring_p->tx_cs.value);
292644961713Sgirish 	if (status != NXGE_OK) {
292744961713Sgirish 		goto nxge_txdma_stop_channel_exit;
292844961713Sgirish 	}
292944961713Sgirish 
2930678453a8Sspeer 	tx_mbox_p = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
2931678453a8Sspeer 
293244961713Sgirish 	/* Disable channel */
293344961713Sgirish 	status = nxge_disable_txdma_channel(nxgep, channel,
2934678453a8Sspeer 	    tx_ring_p, tx_mbox_p);
293544961713Sgirish 	if (status != NXGE_OK) {
293644961713Sgirish 		goto nxge_txdma_start_channel_exit;
293744961713Sgirish 	}
293844961713Sgirish 
293944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
294044961713Sgirish 		"==> nxge_txdma_stop_channel: event done"));
294144961713Sgirish 
294244961713Sgirish #endif
294344961713Sgirish 
294444961713Sgirish nxge_txdma_stop_channel_exit:
294544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_stop_channel"));
294644961713Sgirish 	return (status);
294744961713Sgirish }
294844961713Sgirish 
2949678453a8Sspeer /*
2950678453a8Sspeer  * nxge_txdma_get_ring
2951678453a8Sspeer  *
2952678453a8Sspeer  *	Get the ring for a TDC.
2953678453a8Sspeer  *
2954678453a8Sspeer  * Arguments:
2955678453a8Sspeer  * 	nxgep
2956678453a8Sspeer  * 	channel
2957678453a8Sspeer  *
2958678453a8Sspeer  * Notes:
2959678453a8Sspeer  *
2960678453a8Sspeer  * NPI/NXGE function calls:
2961678453a8Sspeer  *
2962678453a8Sspeer  * Registers accessed:
2963678453a8Sspeer  *
2964678453a8Sspeer  * Context:
2965678453a8Sspeer  *	Any domain
2966678453a8Sspeer  */
296744961713Sgirish static p_tx_ring_t
296844961713Sgirish nxge_txdma_get_ring(p_nxge_t nxgep, uint16_t channel)
296944961713Sgirish {
2970678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
2971678453a8Sspeer 	int tdc;
297244961713Sgirish 
297344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_ring"));
297444961713Sgirish 
2975678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
297644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
2977678453a8Sspeer 		    "<== nxge_txdma_get_ring: NULL ring pointer(s)"));
2978678453a8Sspeer 		goto return_null;
2979678453a8Sspeer 	}
2980678453a8Sspeer 
2981678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
2982678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
2983678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
2984678453a8Sspeer 			if (ring) {
2985678453a8Sspeer 				if (channel == ring->tdc) {
2986678453a8Sspeer 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
2987678453a8Sspeer 					    "<== nxge_txdma_get_ring: "
2988678453a8Sspeer 					    "tdc %d ring $%p", tdc, ring));
2989678453a8Sspeer 					return (ring);
2990678453a8Sspeer 				}
2991678453a8Sspeer 			}
299244961713Sgirish 		}
299344961713Sgirish 	}
299444961713Sgirish 
2995678453a8Sspeer return_null:
2996678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_ring: "
2997678453a8Sspeer 		"ring not found"));
2998678453a8Sspeer 
299944961713Sgirish 	return (NULL);
300044961713Sgirish }
300144961713Sgirish 
3002678453a8Sspeer /*
3003678453a8Sspeer  * nxge_txdma_get_mbox
3004678453a8Sspeer  *
3005678453a8Sspeer  *	Get the mailbox for a TDC.
3006678453a8Sspeer  *
3007678453a8Sspeer  * Arguments:
3008678453a8Sspeer  * 	nxgep
3009678453a8Sspeer  * 	channel
3010678453a8Sspeer  *
3011678453a8Sspeer  * Notes:
3012678453a8Sspeer  *
3013678453a8Sspeer  * NPI/NXGE function calls:
3014678453a8Sspeer  *
3015678453a8Sspeer  * Registers accessed:
3016678453a8Sspeer  *
3017678453a8Sspeer  * Context:
3018678453a8Sspeer  *	Any domain
3019678453a8Sspeer  */
302044961713Sgirish static p_tx_mbox_t
302144961713Sgirish nxge_txdma_get_mbox(p_nxge_t nxgep, uint16_t channel)
302244961713Sgirish {
3023678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
3024678453a8Sspeer 	int tdc;
302544961713Sgirish 
302644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_mbox"));
302744961713Sgirish 
3028678453a8Sspeer 	if (nxgep->tx_mbox_areas_p == 0 ||
3029678453a8Sspeer 	    nxgep->tx_mbox_areas_p->txmbox_areas_p == 0) {
3030678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3031678453a8Sspeer 		    "<== nxge_txdma_get_mbox: NULL mailbox pointer(s)"));
3032678453a8Sspeer 		goto return_null;
303344961713Sgirish 	}
303444961713Sgirish 
3035678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
3036678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3037678453a8Sspeer 		    "<== nxge_txdma_get_mbox: NULL ring pointer(s)"));
3038678453a8Sspeer 		goto return_null;
3039678453a8Sspeer 	}
3040678453a8Sspeer 
3041678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3042678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3043678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3044678453a8Sspeer 			if (ring) {
3045678453a8Sspeer 				if (channel == ring->tdc) {
3046678453a8Sspeer 					tx_mbox_t *mailbox = nxgep->
3047678453a8Sspeer 					    tx_mbox_areas_p->
3048678453a8Sspeer 					    txmbox_areas_p[tdc];
3049678453a8Sspeer 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
3050678453a8Sspeer 					    "<== nxge_txdma_get_mbox: tdc %d "
3051678453a8Sspeer 					    "ring $%p", tdc, mailbox));
3052678453a8Sspeer 					return (mailbox);
3053678453a8Sspeer 				}
3054678453a8Sspeer 			}
305544961713Sgirish 		}
305644961713Sgirish 	}
305744961713Sgirish 
3058678453a8Sspeer return_null:
3059678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_mbox: "
3060678453a8Sspeer 		"mailbox not found"));
3061678453a8Sspeer 
306244961713Sgirish 	return (NULL);
306344961713Sgirish }
306444961713Sgirish 
3065678453a8Sspeer /*
3066678453a8Sspeer  * nxge_tx_err_evnts
3067678453a8Sspeer  *
3068678453a8Sspeer  *	Recover a TDC.
3069678453a8Sspeer  *
3070678453a8Sspeer  * Arguments:
3071678453a8Sspeer  * 	nxgep
3072678453a8Sspeer  * 	index	The index to the TDC ring.
3073678453a8Sspeer  * 	ldvp	Used to get the channel number ONLY.
3074678453a8Sspeer  * 	cs	A copy of the bits from TX_CS.
3075678453a8Sspeer  *
3076678453a8Sspeer  * Notes:
3077678453a8Sspeer  *	Calling tree:
3078678453a8Sspeer  *	 nxge_tx_intr()
3079678453a8Sspeer  *
3080678453a8Sspeer  * NPI/NXGE function calls:
3081678453a8Sspeer  *	npi_txdma_ring_error_get()
3082678453a8Sspeer  *	npi_txdma_inj_par_error_get()
3083678453a8Sspeer  *	nxge_txdma_fatal_err_recover()
3084678453a8Sspeer  *
3085678453a8Sspeer  * Registers accessed:
3086678453a8Sspeer  *	TX_RNG_ERR_LOGH	DMC+0x40048 Transmit Ring Error Log High
3087678453a8Sspeer  *	TX_RNG_ERR_LOGL DMC+0x40050 Transmit Ring Error Log Low
3088678453a8Sspeer  *	TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error
3089678453a8Sspeer  *
3090678453a8Sspeer  * Context:
3091678453a8Sspeer  *	Any domain	XXX Remove code which accesses TDMC_INJ_PAR_ERR.
3092678453a8Sspeer  */
309344961713Sgirish /*ARGSUSED*/
309444961713Sgirish static nxge_status_t
309544961713Sgirish nxge_tx_err_evnts(p_nxge_t nxgep, uint_t index, p_nxge_ldv_t ldvp, tx_cs_t cs)
309644961713Sgirish {
309744961713Sgirish 	npi_handle_t		handle;
309844961713Sgirish 	npi_status_t		rs;
309944961713Sgirish 	uint8_t			channel;
310044961713Sgirish 	p_tx_ring_t 		*tx_rings;
310144961713Sgirish 	p_tx_ring_t 		tx_ring_p;
310244961713Sgirish 	p_nxge_tx_ring_stats_t	tdc_stats;
310344961713Sgirish 	boolean_t		txchan_fatal = B_FALSE;
310444961713Sgirish 	nxge_status_t		status = NXGE_OK;
310544961713Sgirish 	tdmc_inj_par_err_t	par_err;
310644961713Sgirish 	uint32_t		value;
310744961713Sgirish 
3108678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX2_CTL, "==> nxge_tx_err_evnts"));
310944961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
311044961713Sgirish 	channel = ldvp->channel;
311144961713Sgirish 
311244961713Sgirish 	tx_rings = nxgep->tx_rings->rings;
311344961713Sgirish 	tx_ring_p = tx_rings[index];
311444961713Sgirish 	tdc_stats = tx_ring_p->tdc_stats;
311544961713Sgirish 	if ((cs.bits.ldw.pkt_size_err) || (cs.bits.ldw.pref_buf_par_err) ||
311644961713Sgirish 		(cs.bits.ldw.nack_pref) || (cs.bits.ldw.nack_pkt_rd) ||
311744961713Sgirish 		(cs.bits.ldw.conf_part_err) || (cs.bits.ldw.pkt_prt_err)) {
311844961713Sgirish 		if ((rs = npi_txdma_ring_error_get(handle, channel,
311944961713Sgirish 					&tdc_stats->errlog)) != NPI_SUCCESS)
312044961713Sgirish 			return (NXGE_ERROR | rs);
312144961713Sgirish 	}
312244961713Sgirish 
312344961713Sgirish 	if (cs.bits.ldw.mbox_err) {
312444961713Sgirish 		tdc_stats->mbox_err++;
312544961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
312644961713Sgirish 					NXGE_FM_EREPORT_TDMC_MBOX_ERR);
312744961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
312844961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
312944961713Sgirish 			"fatal error: mailbox", channel));
313044961713Sgirish 		txchan_fatal = B_TRUE;
313144961713Sgirish 	}
313244961713Sgirish 	if (cs.bits.ldw.pkt_size_err) {
313344961713Sgirish 		tdc_stats->pkt_size_err++;
313444961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
313544961713Sgirish 					NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR);
313644961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
313744961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
313844961713Sgirish 			"fatal error: pkt_size_err", channel));
313944961713Sgirish 		txchan_fatal = B_TRUE;
314044961713Sgirish 	}
314144961713Sgirish 	if (cs.bits.ldw.tx_ring_oflow) {
314244961713Sgirish 		tdc_stats->tx_ring_oflow++;
314344961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
314444961713Sgirish 					NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW);
314544961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
314644961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
314744961713Sgirish 			"fatal error: tx_ring_oflow", channel));
314844961713Sgirish 		txchan_fatal = B_TRUE;
314944961713Sgirish 	}
315044961713Sgirish 	if (cs.bits.ldw.pref_buf_par_err) {
315144961713Sgirish 		tdc_stats->pre_buf_par_err++;
315244961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
315344961713Sgirish 					NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR);
315444961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
315544961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
315644961713Sgirish 			"fatal error: pre_buf_par_err", channel));
315744961713Sgirish 		/* Clear error injection source for parity error */
315844961713Sgirish 		(void) npi_txdma_inj_par_error_get(handle, &value);
315944961713Sgirish 		par_err.value = value;
316044961713Sgirish 		par_err.bits.ldw.inject_parity_error &= ~(1 << channel);
316144961713Sgirish 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
316244961713Sgirish 		txchan_fatal = B_TRUE;
316344961713Sgirish 	}
316444961713Sgirish 	if (cs.bits.ldw.nack_pref) {
316544961713Sgirish 		tdc_stats->nack_pref++;
316644961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
316744961713Sgirish 					NXGE_FM_EREPORT_TDMC_NACK_PREF);
316844961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
316944961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
317044961713Sgirish 			"fatal error: nack_pref", channel));
317144961713Sgirish 		txchan_fatal = B_TRUE;
317244961713Sgirish 	}
317344961713Sgirish 	if (cs.bits.ldw.nack_pkt_rd) {
317444961713Sgirish 		tdc_stats->nack_pkt_rd++;
317544961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
317644961713Sgirish 					NXGE_FM_EREPORT_TDMC_NACK_PKT_RD);
317744961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
317844961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
317944961713Sgirish 			"fatal error: nack_pkt_rd", channel));
318044961713Sgirish 		txchan_fatal = B_TRUE;
318144961713Sgirish 	}
318244961713Sgirish 	if (cs.bits.ldw.conf_part_err) {
318344961713Sgirish 		tdc_stats->conf_part_err++;
318444961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
318544961713Sgirish 					NXGE_FM_EREPORT_TDMC_CONF_PART_ERR);
318644961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
318744961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
318844961713Sgirish 			"fatal error: config_partition_err", channel));
318944961713Sgirish 		txchan_fatal = B_TRUE;
319044961713Sgirish 	}
319144961713Sgirish 	if (cs.bits.ldw.pkt_prt_err) {
319244961713Sgirish 		tdc_stats->pkt_part_err++;
319344961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
319444961713Sgirish 					NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR);
319544961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
319644961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
319744961713Sgirish 			"fatal error: pkt_prt_err", channel));
319844961713Sgirish 		txchan_fatal = B_TRUE;
319944961713Sgirish 	}
320044961713Sgirish 
320144961713Sgirish 	/* Clear error injection source in case this is an injected error */
320244961713Sgirish 	TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG, channel, 0);
320344961713Sgirish 
320444961713Sgirish 	if (txchan_fatal) {
320544961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
320644961713Sgirish 			" nxge_tx_err_evnts: "
320744961713Sgirish 			" fatal error on channel %d cs 0x%llx\n",
320844961713Sgirish 			channel, cs.value));
320944961713Sgirish 		status = nxge_txdma_fatal_err_recover(nxgep, channel,
321044961713Sgirish 								tx_ring_p);
321144961713Sgirish 		if (status == NXGE_OK) {
321244961713Sgirish 			FM_SERVICE_RESTORED(nxgep);
321344961713Sgirish 		}
321444961713Sgirish 	}
321544961713Sgirish 
3216678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX2_CTL, "<== nxge_tx_err_evnts"));
321744961713Sgirish 
321844961713Sgirish 	return (status);
321944961713Sgirish }
322044961713Sgirish 
322144961713Sgirish static nxge_status_t
3222678453a8Sspeer nxge_txdma_fatal_err_recover(
3223678453a8Sspeer 	p_nxge_t nxgep,
3224678453a8Sspeer 	uint16_t channel,
3225678453a8Sspeer 	p_tx_ring_t tx_ring_p)
322644961713Sgirish {
322744961713Sgirish 	npi_handle_t	handle;
322844961713Sgirish 	npi_status_t	rs = NPI_SUCCESS;
322944961713Sgirish 	p_tx_mbox_t	tx_mbox_p;
323044961713Sgirish 	nxge_status_t	status = NXGE_OK;
323144961713Sgirish 
323244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fatal_err_recover"));
323344961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
323444961713Sgirish 			"Recovering from TxDMAChannel#%d error...", channel));
323544961713Sgirish 
323644961713Sgirish 	/*
323744961713Sgirish 	 * Stop the dma channel waits for the stop done.
323844961713Sgirish 	 * If the stop done bit is not set, then create
323944961713Sgirish 	 * an error.
324044961713Sgirish 	 */
324144961713Sgirish 
324244961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
324344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel stop..."));
324444961713Sgirish 	MUTEX_ENTER(&tx_ring_p->lock);
324544961713Sgirish 	rs = npi_txdma_channel_control(handle, TXDMA_STOP, channel);
324644961713Sgirish 	if (rs != NPI_SUCCESS) {
324744961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
324844961713Sgirish 			"==> nxge_txdma_fatal_err_recover (channel %d): "
324944961713Sgirish 			"stop failed ", channel));
325044961713Sgirish 		goto fail;
325144961713Sgirish 	}
325244961713Sgirish 
325344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reclaim..."));
325444961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
325544961713Sgirish 
325644961713Sgirish 	/*
325744961713Sgirish 	 * Reset TXDMA channel
325844961713Sgirish 	 */
325944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reset..."));
326044961713Sgirish 	if ((rs = npi_txdma_channel_control(handle, TXDMA_RESET, channel)) !=
326144961713Sgirish 						NPI_SUCCESS) {
326244961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
326344961713Sgirish 			"==> nxge_txdma_fatal_err_recover (channel %d)"
326444961713Sgirish 			" reset channel failed 0x%x", channel, rs));
326544961713Sgirish 		goto fail;
326644961713Sgirish 	}
326744961713Sgirish 
326844961713Sgirish 	/*
326944961713Sgirish 	 * Reset the tail (kick) register to 0.
327044961713Sgirish 	 * (Hardware will not reset it. Tx overflow fatal
327144961713Sgirish 	 * error if tail is not set to 0 after reset!
327244961713Sgirish 	 */
327344961713Sgirish 	TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0);
327444961713Sgirish 
327544961713Sgirish 	/* Restart TXDMA channel */
327644961713Sgirish 
3277678453a8Sspeer 	if (!isLDOMguest(nxgep)) {
3278678453a8Sspeer 		tx_mbox_p = nxge_txdma_get_mbox(nxgep, channel);
327944961713Sgirish 
3280678453a8Sspeer 		// XXX This is a problem in HIO!
3281678453a8Sspeer 		/*
3282678453a8Sspeer 		 * Initialize the TXDMA channel specific FZC control
3283678453a8Sspeer 		 * configurations. These FZC registers are pertaining
3284678453a8Sspeer 		 * to each TX channel (i.e. logical pages).
3285678453a8Sspeer 		 */
3286678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel restart..."));
3287678453a8Sspeer 		status = nxge_init_fzc_txdma_channel(nxgep, channel,
3288678453a8Sspeer 		    tx_ring_p, tx_mbox_p);
3289678453a8Sspeer 		if (status != NXGE_OK)
3290678453a8Sspeer 			goto fail;
3291678453a8Sspeer 	}
329244961713Sgirish 
329344961713Sgirish 	/*
329444961713Sgirish 	 * Initialize the event masks.
329544961713Sgirish 	 */
329644961713Sgirish 	tx_ring_p->tx_evmask.value = 0;
329744961713Sgirish 	status = nxge_init_txdma_channel_event_mask(nxgep, channel,
329844961713Sgirish 							&tx_ring_p->tx_evmask);
329944961713Sgirish 	if (status != NXGE_OK)
330044961713Sgirish 		goto fail;
330144961713Sgirish 
330244961713Sgirish 	tx_ring_p->wr_index_wrap = B_FALSE;
330344961713Sgirish 	tx_ring_p->wr_index = 0;
330444961713Sgirish 	tx_ring_p->rd_index = 0;
330544961713Sgirish 
330644961713Sgirish 	/*
330744961713Sgirish 	 * Load TXDMA descriptors, buffers, mailbox,
330844961713Sgirish 	 * initialise the DMA channels and
330944961713Sgirish 	 * enable each DMA channel.
331044961713Sgirish 	 */
331144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel enable..."));
331244961713Sgirish 	status = nxge_enable_txdma_channel(nxgep, channel,
331344961713Sgirish 						tx_ring_p, tx_mbox_p);
331444961713Sgirish 	MUTEX_EXIT(&tx_ring_p->lock);
331544961713Sgirish 	if (status != NXGE_OK)
331644961713Sgirish 		goto fail;
331744961713Sgirish 
331844961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
331944961713Sgirish 			"Recovery Successful, TxDMAChannel#%d Restored",
332044961713Sgirish 			channel));
332144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fatal_err_recover"));
332244961713Sgirish 
332344961713Sgirish 	return (NXGE_OK);
332444961713Sgirish 
332544961713Sgirish fail:
332644961713Sgirish 	MUTEX_EXIT(&tx_ring_p->lock);
332744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
332844961713Sgirish 		"nxge_txdma_fatal_err_recover (channel %d): "
332944961713Sgirish 		"failed to recover this txdma channel", channel));
333044961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed"));
333144961713Sgirish 
333244961713Sgirish 	return (status);
333344961713Sgirish }
333444961713Sgirish 
3335678453a8Sspeer /*
3336678453a8Sspeer  * nxge_tx_port_fatal_err_recover
3337678453a8Sspeer  *
3338678453a8Sspeer  *	Attempt to recover from a fatal port error.
3339678453a8Sspeer  *
3340678453a8Sspeer  * Arguments:
3341678453a8Sspeer  * 	nxgep
3342678453a8Sspeer  *
3343678453a8Sspeer  * Notes:
3344678453a8Sspeer  *	How would a guest do this?
3345678453a8Sspeer  *
3346678453a8Sspeer  * NPI/NXGE function calls:
3347678453a8Sspeer  *
3348678453a8Sspeer  * Registers accessed:
3349678453a8Sspeer  *
3350678453a8Sspeer  * Context:
3351678453a8Sspeer  *	Service domain
3352678453a8Sspeer  */
335344961713Sgirish nxge_status_t
335444961713Sgirish nxge_tx_port_fatal_err_recover(p_nxge_t nxgep)
335544961713Sgirish {
3356678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
3357678453a8Sspeer 	nxge_channel_t tdc;
3358678453a8Sspeer 
3359678453a8Sspeer 	tx_ring_t	*ring;
3360678453a8Sspeer 	tx_mbox_t	*mailbox;
3361678453a8Sspeer 
336244961713Sgirish 	npi_handle_t	handle;
3363678453a8Sspeer 	nxge_status_t	status;
3364678453a8Sspeer 	npi_status_t	rs;
336544961713Sgirish 
336644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_tx_port_fatal_err_recover"));
336744961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3368678453a8Sspeer 	    "Recovering from TxPort error..."));
336944961713Sgirish 
3370678453a8Sspeer 	if (isLDOMguest(nxgep)) {
3371678453a8Sspeer 		return (NXGE_OK);
337244961713Sgirish 	}
337344961713Sgirish 
3374678453a8Sspeer 	if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) {
3375678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3376678453a8Sspeer 		    "<== nxge_tx_port_fatal_err_recover: not initialized"));
3377678453a8Sspeer 		return (NXGE_ERROR);
337844961713Sgirish 	}
337944961713Sgirish 
3380678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
3381678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3382678453a8Sspeer 		    "<== nxge_tx_port_fatal_err_recover: "
3383678453a8Sspeer 		    "NULL ring pointer(s)"));
3384678453a8Sspeer 		return (NXGE_ERROR);
3385678453a8Sspeer 	}
338644961713Sgirish 
3387678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3388678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3389678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3390678453a8Sspeer 			if (ring)
3391678453a8Sspeer 				MUTEX_ENTER(&ring->lock);
339244961713Sgirish 		}
339344961713Sgirish 	}
339444961713Sgirish 
3395678453a8Sspeer 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
3396678453a8Sspeer 
339744961713Sgirish 	/*
3398678453a8Sspeer 	 * Stop all the TDCs owned by us.
3399678453a8Sspeer 	 * (The shared TDCs will have been stopped by their owners.)
340044961713Sgirish 	 */
3401678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3402678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3403678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3404678453a8Sspeer 			if (ring) {
3405678453a8Sspeer 				rs = npi_txdma_channel_control
3406678453a8Sspeer 				    (handle, TXDMA_STOP, tdc);
3407678453a8Sspeer 				if (rs != NPI_SUCCESS) {
3408678453a8Sspeer 					NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3409678453a8Sspeer 					    "nxge_tx_port_fatal_err_recover "
3410678453a8Sspeer 					    "(channel %d): stop failed ", tdc));
3411678453a8Sspeer 					goto fail;
3412678453a8Sspeer 				}
3413678453a8Sspeer 			}
341444961713Sgirish 		}
3415678453a8Sspeer 	}
341644961713Sgirish 
3417678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Reclaiming all TDCs..."));
341844961713Sgirish 
3419678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3420678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3421678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3422678453a8Sspeer 			if (ring)
3423678453a8Sspeer 				(void) nxge_txdma_reclaim(nxgep, ring, 0);
3424678453a8Sspeer 		}
342544961713Sgirish 	}
342644961713Sgirish 
342744961713Sgirish 	/*
3428678453a8Sspeer 	 * Reset all the TDCs.
342944961713Sgirish 	 */
3430678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Resetting all TDCs..."));
3431678453a8Sspeer 
3432678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3433678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3434678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3435678453a8Sspeer 			if (ring) {
3436678453a8Sspeer 				if ((rs = npi_txdma_channel_control
3437678453a8Sspeer 					(handle, TXDMA_RESET, tdc))
3438678453a8Sspeer 				    != NPI_SUCCESS) {
3439678453a8Sspeer 					NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3440678453a8Sspeer 					    "nxge_tx_port_fatal_err_recover "
3441678453a8Sspeer 					    "(channel %d) reset channel "
3442678453a8Sspeer 					    "failed 0x%x", tdc, rs));
3443678453a8Sspeer 					goto fail;
3444678453a8Sspeer 				}
3445678453a8Sspeer 			}
3446678453a8Sspeer 			/*
3447678453a8Sspeer 			 * Reset the tail (kick) register to 0.
3448678453a8Sspeer 			 * (Hardware will not reset it. Tx overflow fatal
3449678453a8Sspeer 			 * error if tail is not set to 0 after reset!
3450678453a8Sspeer 			 */
3451678453a8Sspeer 			TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, tdc, 0);
345244961713Sgirish 		}
3453678453a8Sspeer 	}
345444961713Sgirish 
3455678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Restarting all TDCs..."));
3456678453a8Sspeer 
3457678453a8Sspeer 	/* Restart all the TDCs */
3458678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3459678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3460678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3461678453a8Sspeer 			if (ring) {
3462678453a8Sspeer 				mailbox = nxge_txdma_get_mbox(nxgep, tdc);
3463678453a8Sspeer 				status = nxge_init_fzc_txdma_channel(nxgep, tdc,
3464678453a8Sspeer 				    ring, mailbox);
3465678453a8Sspeer 				ring->tx_evmask.value = 0;
3466678453a8Sspeer 				/*
3467678453a8Sspeer 				 * Initialize the event masks.
3468678453a8Sspeer 				 */
3469678453a8Sspeer 				status = nxge_init_txdma_channel_event_mask
3470678453a8Sspeer 				    (nxgep, tdc, &ring->tx_evmask);
3471678453a8Sspeer 
3472678453a8Sspeer 				ring->wr_index_wrap = B_FALSE;
3473678453a8Sspeer 				ring->wr_index = 0;
3474678453a8Sspeer 				ring->rd_index = 0;
3475678453a8Sspeer 
3476678453a8Sspeer 				if (status != NXGE_OK)
3477678453a8Sspeer 					goto fail;
3478678453a8Sspeer 				if (status != NXGE_OK)
3479678453a8Sspeer 					goto fail;
3480678453a8Sspeer 			}
3481678453a8Sspeer 		}
348244961713Sgirish 	}
348344961713Sgirish 
3484678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Re-enabling all TDCs..."));
348544961713Sgirish 
3486678453a8Sspeer 	/* Re-enable all the TDCs */
3487678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3488678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3489678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3490678453a8Sspeer 			if (ring) {
3491678453a8Sspeer 				mailbox = nxge_txdma_get_mbox(nxgep, tdc);
3492678453a8Sspeer 				status = nxge_enable_txdma_channel(nxgep, tdc,
3493678453a8Sspeer 				    ring, mailbox);
3494678453a8Sspeer 				if (status != NXGE_OK)
3495678453a8Sspeer 					goto fail;
3496678453a8Sspeer 			}
349744961713Sgirish 		}
349844961713Sgirish 	}
349944961713Sgirish 
3500678453a8Sspeer 	/*
3501678453a8Sspeer 	 * Unlock all the TDCs.
3502678453a8Sspeer 	 */
3503678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3504678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3505678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3506678453a8Sspeer 			if (ring)
3507678453a8Sspeer 				MUTEX_EXIT(&ring->lock);
350844961713Sgirish 		}
350944961713Sgirish 	}
351044961713Sgirish 
3511678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery succeeded"));
351244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover"));
351344961713Sgirish 
351444961713Sgirish 	return (NXGE_OK);
351544961713Sgirish 
351644961713Sgirish fail:
3517678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3518678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3519678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3520678453a8Sspeer 			if (ring)
3521678453a8Sspeer 				MUTEX_EXIT(&ring->lock);
352244961713Sgirish 		}
352344961713Sgirish 	}
352444961713Sgirish 
3525678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery failed"));
3526678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover"));
352744961713Sgirish 
352844961713Sgirish 	return (status);
352944961713Sgirish }
353044961713Sgirish 
3531678453a8Sspeer /*
3532678453a8Sspeer  * nxge_txdma_inject_err
3533678453a8Sspeer  *
3534678453a8Sspeer  *	Inject an error into a TDC.
3535678453a8Sspeer  *
3536678453a8Sspeer  * Arguments:
3537678453a8Sspeer  * 	nxgep
3538678453a8Sspeer  * 	err_id	The error to inject.
3539678453a8Sspeer  * 	chan	The channel to inject into.
3540678453a8Sspeer  *
3541678453a8Sspeer  * Notes:
3542678453a8Sspeer  *	This is called from nxge_main.c:nxge_err_inject()
3543678453a8Sspeer  *	Has this ioctl ever been used?
3544678453a8Sspeer  *
3545678453a8Sspeer  * NPI/NXGE function calls:
3546678453a8Sspeer  *	npi_txdma_inj_par_error_get()
3547678453a8Sspeer  *	npi_txdma_inj_par_error_set()
3548678453a8Sspeer  *
3549678453a8Sspeer  * Registers accessed:
3550678453a8Sspeer  *	TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error
3551678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
3552678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
3553678453a8Sspeer  *
3554678453a8Sspeer  * Context:
3555678453a8Sspeer  *	Service domain
3556678453a8Sspeer  */
355744961713Sgirish void
355844961713Sgirish nxge_txdma_inject_err(p_nxge_t nxgep, uint32_t err_id, uint8_t chan)
355944961713Sgirish {
356044961713Sgirish 	tdmc_intr_dbg_t		tdi;
356144961713Sgirish 	tdmc_inj_par_err_t	par_err;
356244961713Sgirish 	uint32_t		value;
356344961713Sgirish 	npi_handle_t		handle;
356444961713Sgirish 
356544961713Sgirish 	switch (err_id) {
356644961713Sgirish 
356744961713Sgirish 	case NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR:
356844961713Sgirish 		handle = NXGE_DEV_NPI_HANDLE(nxgep);
356944961713Sgirish 		/* Clear error injection source for parity error */
357044961713Sgirish 		(void) npi_txdma_inj_par_error_get(handle, &value);
357144961713Sgirish 		par_err.value = value;
357244961713Sgirish 		par_err.bits.ldw.inject_parity_error &= ~(1 << chan);
357344961713Sgirish 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
357444961713Sgirish 
357544961713Sgirish 		par_err.bits.ldw.inject_parity_error = (1 << chan);
357644961713Sgirish 		(void) npi_txdma_inj_par_error_get(handle, &value);
357744961713Sgirish 		par_err.value = value;
357844961713Sgirish 		par_err.bits.ldw.inject_parity_error |= (1 << chan);
357944961713Sgirish 		cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INJ_PAR_ERR_REG\n",
358044961713Sgirish 				(unsigned long long)par_err.value);
358144961713Sgirish 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
358244961713Sgirish 		break;
358344961713Sgirish 
358444961713Sgirish 	case NXGE_FM_EREPORT_TDMC_MBOX_ERR:
358544961713Sgirish 	case NXGE_FM_EREPORT_TDMC_NACK_PREF:
358644961713Sgirish 	case NXGE_FM_EREPORT_TDMC_NACK_PKT_RD:
358744961713Sgirish 	case NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR:
358844961713Sgirish 	case NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW:
358944961713Sgirish 	case NXGE_FM_EREPORT_TDMC_CONF_PART_ERR:
359044961713Sgirish 	case NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR:
359144961713Sgirish 		TXDMA_REG_READ64(nxgep->npi_handle, TDMC_INTR_DBG_REG,
359244961713Sgirish 			chan, &tdi.value);
359344961713Sgirish 		if (err_id == NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR)
359444961713Sgirish 			tdi.bits.ldw.pref_buf_par_err = 1;
359544961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_MBOX_ERR)
359644961713Sgirish 			tdi.bits.ldw.mbox_err = 1;
359744961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PREF)
359844961713Sgirish 			tdi.bits.ldw.nack_pref = 1;
359944961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PKT_RD)
360044961713Sgirish 			tdi.bits.ldw.nack_pkt_rd = 1;
360144961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR)
360244961713Sgirish 			tdi.bits.ldw.pkt_size_err = 1;
360344961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW)
360444961713Sgirish 			tdi.bits.ldw.tx_ring_oflow = 1;
360544961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_CONF_PART_ERR)
360644961713Sgirish 			tdi.bits.ldw.conf_part_err = 1;
360744961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR)
360844961713Sgirish 			tdi.bits.ldw.pkt_part_err = 1;
3609adfcba55Sjoycey #if defined(__i386)
3610adfcba55Sjoycey 		cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INTR_DBG_REG\n",
3611adfcba55Sjoycey 				tdi.value);
3612adfcba55Sjoycey #else
361344961713Sgirish 		cmn_err(CE_NOTE, "!Write 0x%lx to TDMC_INTR_DBG_REG\n",
361444961713Sgirish 				tdi.value);
3615adfcba55Sjoycey #endif
361644961713Sgirish 		TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG,
361744961713Sgirish 			chan, tdi.value);
361844961713Sgirish 
361944961713Sgirish 		break;
362044961713Sgirish 	}
362144961713Sgirish }
3622