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 #include <sys/nxge/nxge_impl.h>
2744961713Sgirish #include <sys/nxge/nxge_txdma.h>
28678453a8Sspeer #include <sys/nxge/nxge_hio.h>
29678453a8Sspeer #include <npi_tx_rd64.h>
30678453a8Sspeer #include <npi_tx_wr64.h>
3144961713Sgirish #include <sys/llc1.h>
3244961713Sgirish 
3344961713Sgirish uint32_t 	nxge_reclaim_pending = TXDMA_RECLAIM_PENDING_DEFAULT;
3444961713Sgirish uint32_t	nxge_tx_minfree = 32;
3544961713Sgirish uint32_t	nxge_tx_intr_thres = 0;
3644961713Sgirish uint32_t	nxge_tx_max_gathers = TX_MAX_GATHER_POINTERS;
3744961713Sgirish uint32_t	nxge_tx_tiny_pack = 1;
3844961713Sgirish uint32_t	nxge_tx_use_bcopy = 1;
3944961713Sgirish 
4044961713Sgirish extern uint32_t 	nxge_tx_ring_size;
4144961713Sgirish extern uint32_t 	nxge_bcopy_thresh;
4244961713Sgirish extern uint32_t 	nxge_dvma_thresh;
4344961713Sgirish extern uint32_t 	nxge_dma_stream_thresh;
4444961713Sgirish extern dma_method_t 	nxge_force_dma;
45b4d05839Sml extern uint32_t		nxge_cksum_offload;
4644961713Sgirish 
4744961713Sgirish /* Device register access attributes for PIO.  */
4844961713Sgirish extern ddi_device_acc_attr_t nxge_dev_reg_acc_attr;
4944961713Sgirish /* Device descriptor access attributes for DMA.  */
5044961713Sgirish extern ddi_device_acc_attr_t nxge_dev_desc_dma_acc_attr;
5144961713Sgirish /* Device buffer access attributes for DMA.  */
5244961713Sgirish extern ddi_device_acc_attr_t nxge_dev_buf_dma_acc_attr;
5344961713Sgirish extern ddi_dma_attr_t nxge_desc_dma_attr;
5444961713Sgirish extern ddi_dma_attr_t nxge_tx_dma_attr;
5544961713Sgirish 
561f8914d5Sml extern int nxge_serial_tx(mblk_t *mp, void *arg);
571f8914d5Sml 
58*2d99c5d4SMichael Speer void nxge_txdma_freemsg_task(p_tx_ring_t tx_ring_p);
59*2d99c5d4SMichael Speer 
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,
1096920a987SMisaki Miyashita 					    group, VP_BOUND_TX, tdc)))
110678453a8Sspeer 						return (NXGE_ERROR);
111678453a8Sspeer 				}
112678453a8Sspeer 			}
113678453a8Sspeer 		}
114678453a8Sspeer 		if (++count == set->lg.count)
115678453a8Sspeer 			break;
116678453a8Sspeer 	}
117678453a8Sspeer 
118678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_init_txdma_channels"));
119678453a8Sspeer 
120678453a8Sspeer 	return (NXGE_OK);
121678453a8Sspeer }
122678453a8Sspeer 
123678453a8Sspeer nxge_status_t
124678453a8Sspeer nxge_init_txdma_channel(
125678453a8Sspeer 	p_nxge_t nxge,
126678453a8Sspeer 	int channel)
127678453a8Sspeer {
128678453a8Sspeer 	nxge_status_t status;
12944961713Sgirish 
130678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, MEM2_CTL, "==> nxge_init_txdma_channel"));
13144961713Sgirish 
132678453a8Sspeer 	status = nxge_map_txdma(nxge, channel);
13344961713Sgirish 	if (status != NXGE_OK) {
134678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
135678453a8Sspeer 		    "<== nxge_init_txdma_channel: status 0x%x", status));
136678453a8Sspeer 		(void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel);
13744961713Sgirish 		return (status);
13844961713Sgirish 	}
13944961713Sgirish 
140678453a8Sspeer 	status = nxge_txdma_hw_start(nxge, channel);
14144961713Sgirish 	if (status != NXGE_OK) {
142678453a8Sspeer 		(void) nxge_unmap_txdma_channel(nxge, channel);
143678453a8Sspeer 		(void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel);
14444961713Sgirish 		return (status);
14544961713Sgirish 	}
14644961713Sgirish 
147678453a8Sspeer 	if (!nxge->statsp->tdc_ksp[channel])
148678453a8Sspeer 		nxge_setup_tdc_kstats(nxge, channel);
14944961713Sgirish 
150678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, MEM2_CTL, "<== nxge_init_txdma_channel"));
151678453a8Sspeer 
152678453a8Sspeer 	return (status);
15344961713Sgirish }
15444961713Sgirish 
15544961713Sgirish void
15644961713Sgirish nxge_uninit_txdma_channels(p_nxge_t nxgep)
15744961713Sgirish {
158678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
159678453a8Sspeer 	int tdc;
160678453a8Sspeer 
161678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "==> nxge_uninit_txdma_channels"));
162678453a8Sspeer 
163678453a8Sspeer 	if (set->owned.map == 0) {
164678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, MEM2_CTL,
165678453a8Sspeer 		    "nxge_uninit_txdma_channels: no channels"));
166678453a8Sspeer 		return;
167678453a8Sspeer 	}
168678453a8Sspeer 
169678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
170678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
171678453a8Sspeer 			nxge_grp_dc_remove(nxgep, VP_BOUND_TX, tdc);
172678453a8Sspeer 		}
173678453a8Sspeer 	}
174678453a8Sspeer 
175678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_uninit_txdma_channels"));
176678453a8Sspeer }
177678453a8Sspeer 
178678453a8Sspeer void
179678453a8Sspeer nxge_uninit_txdma_channel(p_nxge_t nxgep, int channel)
180678453a8Sspeer {
181678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_uninit_txdma_channel"));
182678453a8Sspeer 
183678453a8Sspeer 	if (nxgep->statsp->tdc_ksp[channel]) {
184678453a8Sspeer 		kstat_delete(nxgep->statsp->tdc_ksp[channel]);
185678453a8Sspeer 		nxgep->statsp->tdc_ksp[channel] = 0;
186678453a8Sspeer 	}
18744961713Sgirish 
188678453a8Sspeer 	(void) nxge_txdma_stop_channel(nxgep, channel);
189678453a8Sspeer 	nxge_unmap_txdma_channel(nxgep, channel);
19044961713Sgirish 
19144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
19252ccf843Smisaki 	    "<== nxge_uninit_txdma_channel"));
19344961713Sgirish }
19444961713Sgirish 
19544961713Sgirish void
19644961713Sgirish nxge_setup_dma_common(p_nxge_dma_common_t dest_p, p_nxge_dma_common_t src_p,
19744961713Sgirish 	uint32_t entries, uint32_t size)
19844961713Sgirish {
19944961713Sgirish 	size_t		tsize;
20044961713Sgirish 	*dest_p = *src_p;
20144961713Sgirish 	tsize = size * entries;
20244961713Sgirish 	dest_p->alength = tsize;
20344961713Sgirish 	dest_p->nblocks = entries;
20444961713Sgirish 	dest_p->block_size = size;
20544961713Sgirish 	dest_p->offset += tsize;
20644961713Sgirish 
20744961713Sgirish 	src_p->kaddrp = (caddr_t)dest_p->kaddrp + tsize;
20844961713Sgirish 	src_p->alength -= tsize;
20944961713Sgirish 	src_p->dma_cookie.dmac_laddress += tsize;
21044961713Sgirish 	src_p->dma_cookie.dmac_size -= tsize;
21144961713Sgirish }
21244961713Sgirish 
213678453a8Sspeer /*
214678453a8Sspeer  * nxge_reset_txdma_channel
215678453a8Sspeer  *
216678453a8Sspeer  *	Reset a TDC.
217678453a8Sspeer  *
218678453a8Sspeer  * Arguments:
219678453a8Sspeer  * 	nxgep
220678453a8Sspeer  * 	channel		The channel to reset.
221678453a8Sspeer  * 	reg_data	The current TX_CS.
222678453a8Sspeer  *
223678453a8Sspeer  * Notes:
224678453a8Sspeer  *
225678453a8Sspeer  * NPI/NXGE function calls:
226678453a8Sspeer  *	npi_txdma_channel_reset()
227678453a8Sspeer  *	npi_txdma_channel_control()
228678453a8Sspeer  *
229678453a8Sspeer  * Registers accessed:
230678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
231678453a8Sspeer  *	TX_RING_KICK	DMC+0x40018 Transmit Ring Kick
232678453a8Sspeer  *
233678453a8Sspeer  * Context:
234678453a8Sspeer  *	Any domain
235678453a8Sspeer  */
23644961713Sgirish nxge_status_t
23744961713Sgirish nxge_reset_txdma_channel(p_nxge_t nxgep, uint16_t channel, uint64_t reg_data)
23844961713Sgirish {
23944961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
24044961713Sgirish 	nxge_status_t		status = NXGE_OK;
24144961713Sgirish 	npi_handle_t		handle;
24244961713Sgirish 
24344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, " ==> nxge_reset_txdma_channel"));
24444961713Sgirish 
24544961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
24644961713Sgirish 	if ((reg_data & TX_CS_RST_MASK) == TX_CS_RST_MASK) {
24744961713Sgirish 		rs = npi_txdma_channel_reset(handle, channel);
24844961713Sgirish 	} else {
24944961713Sgirish 		rs = npi_txdma_channel_control(handle, TXDMA_RESET,
25052ccf843Smisaki 		    channel);
25144961713Sgirish 	}
25244961713Sgirish 
25344961713Sgirish 	if (rs != NPI_SUCCESS) {
25444961713Sgirish 		status = NXGE_ERROR | rs;
25544961713Sgirish 	}
25644961713Sgirish 
25744961713Sgirish 	/*
25844961713Sgirish 	 * Reset the tail (kick) register to 0.
25944961713Sgirish 	 * (Hardware will not reset it. Tx overflow fatal
26044961713Sgirish 	 * error if tail is not set to 0 after reset!
26144961713Sgirish 	 */
26244961713Sgirish 	TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0);
26344961713Sgirish 
26444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, " <== nxge_reset_txdma_channel"));
26544961713Sgirish 	return (status);
26644961713Sgirish }
26744961713Sgirish 
268678453a8Sspeer /*
269678453a8Sspeer  * nxge_init_txdma_channel_event_mask
270678453a8Sspeer  *
271678453a8Sspeer  *	Enable interrupts for a set of events.
272678453a8Sspeer  *
273678453a8Sspeer  * Arguments:
274678453a8Sspeer  * 	nxgep
275678453a8Sspeer  * 	channel	The channel to map.
276678453a8Sspeer  * 	mask_p	The events to enable.
277678453a8Sspeer  *
278678453a8Sspeer  * Notes:
279678453a8Sspeer  *
280678453a8Sspeer  * NPI/NXGE function calls:
281678453a8Sspeer  *	npi_txdma_event_mask()
282678453a8Sspeer  *
283678453a8Sspeer  * Registers accessed:
284678453a8Sspeer  *	TX_ENT_MSK	DMC+0x40020 Transmit Event Mask
285678453a8Sspeer  *
286678453a8Sspeer  * Context:
287678453a8Sspeer  *	Any domain
288678453a8Sspeer  */
28944961713Sgirish nxge_status_t
29044961713Sgirish nxge_init_txdma_channel_event_mask(p_nxge_t nxgep, uint16_t channel,
29144961713Sgirish 		p_tx_dma_ent_msk_t mask_p)
29244961713Sgirish {
29344961713Sgirish 	npi_handle_t		handle;
29444961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
29544961713Sgirish 	nxge_status_t		status = NXGE_OK;
29644961713Sgirish 
29744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
29852ccf843Smisaki 	    "<== nxge_init_txdma_channel_event_mask"));
29944961713Sgirish 
30044961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
30144961713Sgirish 	rs = npi_txdma_event_mask(handle, OP_SET, channel, mask_p);
30244961713Sgirish 	if (rs != NPI_SUCCESS) {
30344961713Sgirish 		status = NXGE_ERROR | rs;
30444961713Sgirish 	}
30544961713Sgirish 
30644961713Sgirish 	return (status);
30744961713Sgirish }
30844961713Sgirish 
309678453a8Sspeer /*
310678453a8Sspeer  * nxge_init_txdma_channel_cntl_stat
311678453a8Sspeer  *
312678453a8Sspeer  *	Stop a TDC.  If at first we don't succeed, inject an error.
313678453a8Sspeer  *
314678453a8Sspeer  * Arguments:
315678453a8Sspeer  * 	nxgep
316678453a8Sspeer  * 	channel		The channel to stop.
317678453a8Sspeer  *
318678453a8Sspeer  * Notes:
319678453a8Sspeer  *
320678453a8Sspeer  * NPI/NXGE function calls:
321678453a8Sspeer  *	npi_txdma_control_status()
322678453a8Sspeer  *
323678453a8Sspeer  * Registers accessed:
324678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
325678453a8Sspeer  *
326678453a8Sspeer  * Context:
327678453a8Sspeer  *	Any domain
328678453a8Sspeer  */
32944961713Sgirish nxge_status_t
33044961713Sgirish nxge_init_txdma_channel_cntl_stat(p_nxge_t nxgep, uint16_t channel,
33144961713Sgirish 	uint64_t reg_data)
33244961713Sgirish {
33344961713Sgirish 	npi_handle_t		handle;
33444961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
33544961713Sgirish 	nxge_status_t		status = NXGE_OK;
33644961713Sgirish 
33744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
33852ccf843Smisaki 	    "<== nxge_init_txdma_channel_cntl_stat"));
33944961713Sgirish 
34044961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
34144961713Sgirish 	rs = npi_txdma_control_status(handle, OP_SET, channel,
34252ccf843Smisaki 	    (p_tx_cs_t)&reg_data);
34344961713Sgirish 
34444961713Sgirish 	if (rs != NPI_SUCCESS) {
34544961713Sgirish 		status = NXGE_ERROR | rs;
34644961713Sgirish 	}
34744961713Sgirish 
34844961713Sgirish 	return (status);
34944961713Sgirish }
35044961713Sgirish 
351678453a8Sspeer /*
352678453a8Sspeer  * nxge_enable_txdma_channel
353678453a8Sspeer  *
354678453a8Sspeer  *	Enable a TDC.
355678453a8Sspeer  *
356678453a8Sspeer  * Arguments:
357678453a8Sspeer  * 	nxgep
358678453a8Sspeer  * 	channel		The channel to enable.
359678453a8Sspeer  * 	tx_desc_p	channel's transmit descriptor ring.
360678453a8Sspeer  * 	mbox_p		channel's mailbox,
361678453a8Sspeer  *
362678453a8Sspeer  * Notes:
363678453a8Sspeer  *
364678453a8Sspeer  * NPI/NXGE function calls:
365678453a8Sspeer  *	npi_txdma_ring_config()
366678453a8Sspeer  *	npi_txdma_mbox_config()
367678453a8Sspeer  *	npi_txdma_channel_init_enable()
368678453a8Sspeer  *
369678453a8Sspeer  * Registers accessed:
370678453a8Sspeer  *	TX_RNG_CFIG	DMC+0x40000 Transmit Ring Configuration
371678453a8Sspeer  *	TXDMA_MBH	DMC+0x40030 TXDMA Mailbox High
372678453a8Sspeer  *	TXDMA_MBL	DMC+0x40038 TXDMA Mailbox Low
373678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
374678453a8Sspeer  *
375678453a8Sspeer  * Context:
376678453a8Sspeer  *	Any domain
377678453a8Sspeer  */
37844961713Sgirish nxge_status_t
37944961713Sgirish nxge_enable_txdma_channel(p_nxge_t nxgep,
38044961713Sgirish 	uint16_t channel, p_tx_ring_t tx_desc_p, p_tx_mbox_t mbox_p)
38144961713Sgirish {
38244961713Sgirish 	npi_handle_t		handle;
38344961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
38444961713Sgirish 	nxge_status_t		status = NXGE_OK;
38544961713Sgirish 
38644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_enable_txdma_channel"));
38744961713Sgirish 
38844961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
38944961713Sgirish 	/*
39044961713Sgirish 	 * Use configuration data composed at init time.
39144961713Sgirish 	 * Write to hardware the transmit ring configurations.
39244961713Sgirish 	 */
39344961713Sgirish 	rs = npi_txdma_ring_config(handle, OP_SET, channel,
394678453a8Sspeer 	    (uint64_t *)&(tx_desc_p->tx_ring_cfig.value));
39544961713Sgirish 
39644961713Sgirish 	if (rs != NPI_SUCCESS) {
39744961713Sgirish 		return (NXGE_ERROR | rs);
39844961713Sgirish 	}
39944961713Sgirish 
400678453a8Sspeer 	if (isLDOMguest(nxgep)) {
401678453a8Sspeer 		/* Add interrupt handler for this channel. */
402678453a8Sspeer 		if (nxge_hio_intr_add(nxgep, VP_BOUND_TX, channel) != NXGE_OK)
403678453a8Sspeer 			return (NXGE_ERROR);
404678453a8Sspeer 	}
405678453a8Sspeer 
40644961713Sgirish 	/* Write to hardware the mailbox */
40744961713Sgirish 	rs = npi_txdma_mbox_config(handle, OP_SET, channel,
40852ccf843Smisaki 	    (uint64_t *)&mbox_p->tx_mbox.dma_cookie.dmac_laddress);
40944961713Sgirish 
41044961713Sgirish 	if (rs != NPI_SUCCESS) {
41144961713Sgirish 		return (NXGE_ERROR | rs);
41244961713Sgirish 	}
41344961713Sgirish 
41444961713Sgirish 	/* Start the DMA engine. */
41544961713Sgirish 	rs = npi_txdma_channel_init_enable(handle, channel);
41644961713Sgirish 
41744961713Sgirish 	if (rs != NPI_SUCCESS) {
41844961713Sgirish 		return (NXGE_ERROR | rs);
41944961713Sgirish 	}
42044961713Sgirish 
42144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_enable_txdma_channel"));
42244961713Sgirish 
42344961713Sgirish 	return (status);
42444961713Sgirish }
42544961713Sgirish 
42644961713Sgirish void
42744961713Sgirish nxge_fill_tx_hdr(p_mblk_t mp, boolean_t fill_len,
42844961713Sgirish 		boolean_t l4_cksum, int pkt_len, uint8_t npads,
429b4d05839Sml 		p_tx_pkt_hdr_all_t pkthdrp,
430b4d05839Sml 		t_uscalar_t start_offset,
431b4d05839Sml 		t_uscalar_t stuff_offset)
43244961713Sgirish {
43344961713Sgirish 	p_tx_pkt_header_t	hdrp;
43444961713Sgirish 	p_mblk_t 		nmp;
43544961713Sgirish 	uint64_t		tmp;
43644961713Sgirish 	size_t 			mblk_len;
43744961713Sgirish 	size_t 			iph_len;
43844961713Sgirish 	size_t 			hdrs_size;
43944961713Sgirish 	uint8_t			hdrs_buf[sizeof (struct ether_header) +
44052ccf843Smisaki 	    64 + sizeof (uint32_t)];
441ae2d3f74Smisaki 	uint8_t			*cursor;
44244961713Sgirish 	uint8_t 		*ip_buf;
44344961713Sgirish 	uint16_t		eth_type;
44444961713Sgirish 	uint8_t			ipproto;
44544961713Sgirish 	boolean_t		is_vlan = B_FALSE;
44644961713Sgirish 	size_t			eth_hdr_size;
44744961713Sgirish 
44844961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: mp $%p", mp));
44944961713Sgirish 
45044961713Sgirish 	/*
45144961713Sgirish 	 * Caller should zero out the headers first.
45244961713Sgirish 	 */
45344961713Sgirish 	hdrp = (p_tx_pkt_header_t)&pkthdrp->pkthdr;
45444961713Sgirish 
45544961713Sgirish 	if (fill_len) {
45644961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
45752ccf843Smisaki 		    "==> nxge_fill_tx_hdr: pkt_len %d "
45852ccf843Smisaki 		    "npads %d", pkt_len, npads));
45944961713Sgirish 		tmp = (uint64_t)pkt_len;
46044961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_TOT_XFER_LEN_SHIFT);
46144961713Sgirish 		goto fill_tx_header_done;
46244961713Sgirish 	}
46344961713Sgirish 
464b4d05839Sml 	hdrp->value |= (((uint64_t)npads) << TX_PKT_HEADER_PAD_SHIFT);
46544961713Sgirish 
46644961713Sgirish 	/*
46744961713Sgirish 	 * mp is the original data packet (does not include the
46844961713Sgirish 	 * Neptune transmit header).
46944961713Sgirish 	 */
47044961713Sgirish 	nmp = mp;
47144961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: "
47252ccf843Smisaki 	    "mp $%p b_rptr $%p len %d",
47352ccf843Smisaki 	    mp, nmp->b_rptr, MBLKL(nmp)));
474ae2d3f74Smisaki 	/* copy ether_header from mblk to hdrs_buf */
475ae2d3f74Smisaki 	cursor = &hdrs_buf[0];
476ae2d3f74Smisaki 	tmp = sizeof (struct ether_vlan_header);
477ae2d3f74Smisaki 	while ((nmp != NULL) && (tmp > 0)) {
478ae2d3f74Smisaki 		size_t buflen;
479ae2d3f74Smisaki 		mblk_len = MBLKL(nmp);
4807c29db66Smisaki 		buflen = min((size_t)tmp, mblk_len);
481ae2d3f74Smisaki 		bcopy(nmp->b_rptr, cursor, buflen);
482ae2d3f74Smisaki 		cursor += buflen;
483ae2d3f74Smisaki 		tmp -= buflen;
484ae2d3f74Smisaki 		nmp = nmp->b_cont;
485ae2d3f74Smisaki 	}
486ae2d3f74Smisaki 
487ae2d3f74Smisaki 	nmp = mp;
488ae2d3f74Smisaki 	mblk_len = MBLKL(nmp);
48944961713Sgirish 	ip_buf = NULL;
49044961713Sgirish 	eth_type = ntohs(((p_ether_header_t)hdrs_buf)->ether_type);
49144961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> : nxge_fill_tx_hdr: (value 0x%llx) "
49252ccf843Smisaki 	    "ether type 0x%x", eth_type, hdrp->value));
49344961713Sgirish 
49444961713Sgirish 	if (eth_type < ETHERMTU) {
49544961713Sgirish 		tmp = 1ull;
49644961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_LLC_SHIFT);
49744961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: LLC "
49852ccf843Smisaki 		    "value 0x%llx", hdrp->value));
49944961713Sgirish 		if (*(hdrs_buf + sizeof (struct ether_header))
50052ccf843Smisaki 		    == LLC_SNAP_SAP) {
50144961713Sgirish 			eth_type = ntohs(*((uint16_t *)(hdrs_buf +
50252ccf843Smisaki 			    sizeof (struct ether_header) + 6)));
50344961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
50452ccf843Smisaki 			    "==> nxge_tx_pkt_hdr_init: LLC ether type 0x%x",
50552ccf843Smisaki 			    eth_type));
50644961713Sgirish 		} else {
50744961713Sgirish 			goto fill_tx_header_done;
50844961713Sgirish 		}
50944961713Sgirish 	} else if (eth_type == VLAN_ETHERTYPE) {
51044961713Sgirish 		tmp = 1ull;
51144961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_VLAN__SHIFT);
51244961713Sgirish 
51344961713Sgirish 		eth_type = ntohs(((struct ether_vlan_header *)
51452ccf843Smisaki 		    hdrs_buf)->ether_type);
51544961713Sgirish 		is_vlan = B_TRUE;
51644961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: VLAN "
51752ccf843Smisaki 		    "value 0x%llx", hdrp->value));
51844961713Sgirish 	}
51944961713Sgirish 
52044961713Sgirish 	if (!is_vlan) {
52144961713Sgirish 		eth_hdr_size = sizeof (struct ether_header);
52244961713Sgirish 	} else {
52344961713Sgirish 		eth_hdr_size = sizeof (struct ether_vlan_header);
52444961713Sgirish 	}
52544961713Sgirish 
52644961713Sgirish 	switch (eth_type) {
52744961713Sgirish 	case ETHERTYPE_IP:
52844961713Sgirish 		if (mblk_len > eth_hdr_size + sizeof (uint8_t)) {
52944961713Sgirish 			ip_buf = nmp->b_rptr + eth_hdr_size;
53044961713Sgirish 			mblk_len -= eth_hdr_size;
53144961713Sgirish 			iph_len = ((*ip_buf) & 0x0f);
53244961713Sgirish 			if (mblk_len > (iph_len + sizeof (uint32_t))) {
53344961713Sgirish 				ip_buf = nmp->b_rptr;
53444961713Sgirish 				ip_buf += eth_hdr_size;
53544961713Sgirish 			} else {
53644961713Sgirish 				ip_buf = NULL;
53744961713Sgirish 			}
53844961713Sgirish 
53944961713Sgirish 		}
54044961713Sgirish 		if (ip_buf == NULL) {
54144961713Sgirish 			hdrs_size = 0;
54244961713Sgirish 			((p_ether_header_t)hdrs_buf)->ether_type = 0;
54344961713Sgirish 			while ((nmp) && (hdrs_size <
54452ccf843Smisaki 			    sizeof (hdrs_buf))) {
54544961713Sgirish 				mblk_len = (size_t)nmp->b_wptr -
54652ccf843Smisaki 				    (size_t)nmp->b_rptr;
54744961713Sgirish 				if (mblk_len >=
54852ccf843Smisaki 				    (sizeof (hdrs_buf) - hdrs_size))
54944961713Sgirish 					mblk_len = sizeof (hdrs_buf) -
55052ccf843Smisaki 					    hdrs_size;
55144961713Sgirish 				bcopy(nmp->b_rptr,
55252ccf843Smisaki 				    &hdrs_buf[hdrs_size], mblk_len);
55344961713Sgirish 				hdrs_size += mblk_len;
55444961713Sgirish 				nmp = nmp->b_cont;
55544961713Sgirish 			}
55644961713Sgirish 			ip_buf = hdrs_buf;
55744961713Sgirish 			ip_buf += eth_hdr_size;
55844961713Sgirish 			iph_len = ((*ip_buf) & 0x0f);
55944961713Sgirish 		}
56044961713Sgirish 
56144961713Sgirish 		ipproto = ip_buf[9];
56244961713Sgirish 
56344961713Sgirish 		tmp = (uint64_t)iph_len;
56444961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_IHL_SHIFT);
56544961713Sgirish 		tmp = (uint64_t)(eth_hdr_size >> 1);
56644961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT);
56744961713Sgirish 
56844961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv4 "
56952ccf843Smisaki 		    " iph_len %d l3start %d eth_hdr_size %d proto 0x%x"
57052ccf843Smisaki 		    "tmp 0x%x",
57152ccf843Smisaki 		    iph_len, hdrp->bits.hdw.l3start, eth_hdr_size,
57252ccf843Smisaki 		    ipproto, tmp));
57344961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IP "
57452ccf843Smisaki 		    "value 0x%llx", hdrp->value));
57544961713Sgirish 
57644961713Sgirish 		break;
57744961713Sgirish 
57844961713Sgirish 	case ETHERTYPE_IPV6:
57944961713Sgirish 		hdrs_size = 0;
58044961713Sgirish 		((p_ether_header_t)hdrs_buf)->ether_type = 0;
58144961713Sgirish 		while ((nmp) && (hdrs_size <
58252ccf843Smisaki 		    sizeof (hdrs_buf))) {
58344961713Sgirish 			mblk_len = (size_t)nmp->b_wptr - (size_t)nmp->b_rptr;
58444961713Sgirish 			if (mblk_len >=
58552ccf843Smisaki 			    (sizeof (hdrs_buf) - hdrs_size))
58644961713Sgirish 				mblk_len = sizeof (hdrs_buf) -
58752ccf843Smisaki 				    hdrs_size;
58844961713Sgirish 			bcopy(nmp->b_rptr,
58952ccf843Smisaki 			    &hdrs_buf[hdrs_size], mblk_len);
59044961713Sgirish 			hdrs_size += mblk_len;
59144961713Sgirish 			nmp = nmp->b_cont;
59244961713Sgirish 		}
59344961713Sgirish 		ip_buf = hdrs_buf;
59444961713Sgirish 		ip_buf += eth_hdr_size;
59544961713Sgirish 
59644961713Sgirish 		tmp = 1ull;
59744961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_IP_VER_SHIFT);
59844961713Sgirish 
59944961713Sgirish 		tmp = (eth_hdr_size >> 1);
60044961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT);
60144961713Sgirish 
60244961713Sgirish 		/* byte 6 is the next header protocol */
60344961713Sgirish 		ipproto = ip_buf[6];
60444961713Sgirish 
60544961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv6 "
60652ccf843Smisaki 		    " iph_len %d l3start %d eth_hdr_size %d proto 0x%x",
60752ccf843Smisaki 		    iph_len, hdrp->bits.hdw.l3start, eth_hdr_size,
60852ccf843Smisaki 		    ipproto));
60944961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IPv6 "
61052ccf843Smisaki 		    "value 0x%llx", hdrp->value));
61144961713Sgirish 
61244961713Sgirish 		break;
61344961713Sgirish 
61444961713Sgirish 	default:
61544961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: non-IP"));
61644961713Sgirish 		goto fill_tx_header_done;
61744961713Sgirish 	}
61844961713Sgirish 
61944961713Sgirish 	switch (ipproto) {
62044961713Sgirish 	case IPPROTO_TCP:
62144961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
622b4d05839Sml 		    "==> nxge_fill_tx_hdr: TCP (cksum flag %d)", l4_cksum));
62344961713Sgirish 		if (l4_cksum) {
624b4d05839Sml 			hdrp->value |= TX_CKSUM_EN_PKT_TYPE_TCP;
625b4d05839Sml 			hdrp->value |=
626b4d05839Sml 			    (((uint64_t)(start_offset >> 1)) <<
627b4d05839Sml 			    TX_PKT_HEADER_L4START_SHIFT);
628b4d05839Sml 			hdrp->value |=
629b4d05839Sml 			    (((uint64_t)(stuff_offset >> 1)) <<
630b4d05839Sml 			    TX_PKT_HEADER_L4STUFF_SHIFT);
631b4d05839Sml 
63244961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
633b4d05839Sml 			    "==> nxge_tx_pkt_hdr_init: TCP CKSUM "
634b4d05839Sml 			    "value 0x%llx", hdrp->value));
63544961713Sgirish 		}
63644961713Sgirish 
63744961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: TCP "
638b4d05839Sml 		    "value 0x%llx", hdrp->value));
63944961713Sgirish 		break;
64044961713Sgirish 
64144961713Sgirish 	case IPPROTO_UDP:
64244961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: UDP"));
64344961713Sgirish 		if (l4_cksum) {
644b4d05839Sml 			if (!nxge_cksum_offload) {
645b4d05839Sml 				uint16_t	*up;
646b4d05839Sml 				uint16_t	cksum;
647b4d05839Sml 				t_uscalar_t	stuff_len;
648b4d05839Sml 
649b4d05839Sml 				/*
650b4d05839Sml 				 * The checksum field has the
651b4d05839Sml 				 * partial checksum.
652b4d05839Sml 				 * IP_CSUM() macro calls ip_cksum() which
653b4d05839Sml 				 * can add in the partial checksum.
654b4d05839Sml 				 */
655b4d05839Sml 				cksum = IP_CSUM(mp, start_offset, 0);
656b4d05839Sml 				stuff_len = stuff_offset;
657b4d05839Sml 				nmp = mp;
658b4d05839Sml 				mblk_len = MBLKL(nmp);
659b4d05839Sml 				while ((nmp != NULL) &&
660b4d05839Sml 				    (mblk_len < stuff_len)) {
661b4d05839Sml 					stuff_len -= mblk_len;
662b4d05839Sml 					nmp = nmp->b_cont;
663b4d05839Sml 				}
664b4d05839Sml 				ASSERT(nmp);
665b4d05839Sml 				up = (uint16_t *)(nmp->b_rptr + stuff_len);
666b4d05839Sml 
667b4d05839Sml 				*up = cksum;
668b4d05839Sml 				hdrp->value &= ~TX_CKSUM_EN_PKT_TYPE_UDP;
669b4d05839Sml 				NXGE_DEBUG_MSG((NULL, TX_CTL,
670b4d05839Sml 				    "==> nxge_tx_pkt_hdr_init: UDP offset %d "
671b4d05839Sml 				    "use sw cksum "
672b4d05839Sml 				    "write to $%p cksum 0x%x content up 0x%x",
673b4d05839Sml 				    stuff_len,
674b4d05839Sml 				    up,
675b4d05839Sml 				    cksum,
676b4d05839Sml 				    *up));
677b4d05839Sml 			} else {
678b4d05839Sml 				/* Hardware will compute the full checksum */
679b4d05839Sml 				hdrp->value |= TX_CKSUM_EN_PKT_TYPE_UDP;
680b4d05839Sml 				hdrp->value |=
681b4d05839Sml 				    (((uint64_t)(start_offset >> 1)) <<
682b4d05839Sml 				    TX_PKT_HEADER_L4START_SHIFT);
683b4d05839Sml 				hdrp->value |=
684b4d05839Sml 				    (((uint64_t)(stuff_offset >> 1)) <<
685b4d05839Sml 				    TX_PKT_HEADER_L4STUFF_SHIFT);
686b4d05839Sml 
687b4d05839Sml 				NXGE_DEBUG_MSG((NULL, TX_CTL,
688b4d05839Sml 				    "==> nxge_tx_pkt_hdr_init: UDP offset %d "
689b4d05839Sml 				    " use partial checksum "
690b4d05839Sml 				    "cksum 0x%x ",
691b4d05839Sml 				    "value 0x%llx",
692b4d05839Sml 				    stuff_offset,
693b4d05839Sml 				    IP_CSUM(mp, start_offset, 0),
694b4d05839Sml 				    hdrp->value));
695b4d05839Sml 			}
69644961713Sgirish 		}
697b4d05839Sml 
69844961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
69952ccf843Smisaki 		    "==> nxge_tx_pkt_hdr_init: UDP"
70052ccf843Smisaki 		    "value 0x%llx", hdrp->value));
70144961713Sgirish 		break;
70244961713Sgirish 
70344961713Sgirish 	default:
70444961713Sgirish 		goto fill_tx_header_done;
70544961713Sgirish 	}
70644961713Sgirish 
70744961713Sgirish fill_tx_header_done:
70844961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
70952ccf843Smisaki 	    "==> nxge_fill_tx_hdr: pkt_len %d  "
71052ccf843Smisaki 	    "npads %d value 0x%llx", pkt_len, npads, hdrp->value));
71144961713Sgirish 
71244961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "<== nxge_fill_tx_hdr"));
71344961713Sgirish }
71444961713Sgirish 
71544961713Sgirish /*ARGSUSED*/
71644961713Sgirish p_mblk_t
71744961713Sgirish nxge_tx_pkt_header_reserve(p_mblk_t mp, uint8_t *npads)
71844961713Sgirish {
71944961713Sgirish 	p_mblk_t 		newmp = NULL;
72044961713Sgirish 
72144961713Sgirish 	if ((newmp = allocb(TX_PKT_HEADER_SIZE, BPRI_MED)) == NULL) {
72244961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
72352ccf843Smisaki 		    "<== nxge_tx_pkt_header_reserve: allocb failed"));
72444961713Sgirish 		return (NULL);
72544961713Sgirish 	}
72644961713Sgirish 
72744961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
72852ccf843Smisaki 	    "==> nxge_tx_pkt_header_reserve: get new mp"));
72944961713Sgirish 	DB_TYPE(newmp) = M_DATA;
73044961713Sgirish 	newmp->b_rptr = newmp->b_wptr = DB_LIM(newmp);
73144961713Sgirish 	linkb(newmp, mp);
73244961713Sgirish 	newmp->b_rptr -= TX_PKT_HEADER_SIZE;
73344961713Sgirish 
73444961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==>nxge_tx_pkt_header_reserve: "
73552ccf843Smisaki 	    "b_rptr $%p b_wptr $%p",
73652ccf843Smisaki 	    newmp->b_rptr, newmp->b_wptr));
73744961713Sgirish 
73844961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
73952ccf843Smisaki 	    "<== nxge_tx_pkt_header_reserve: use new mp"));
74044961713Sgirish 
74144961713Sgirish 	return (newmp);
74244961713Sgirish }
74344961713Sgirish 
74444961713Sgirish int
74544961713Sgirish nxge_tx_pkt_nmblocks(p_mblk_t mp, int *tot_xfer_len_p)
74644961713Sgirish {
74744961713Sgirish 	uint_t 			nmblks;
74844961713Sgirish 	ssize_t			len;
74944961713Sgirish 	uint_t 			pkt_len;
75044961713Sgirish 	p_mblk_t 		nmp, bmp, tmp;
75144961713Sgirish 	uint8_t 		*b_wptr;
75244961713Sgirish 
75344961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
75452ccf843Smisaki 	    "==> nxge_tx_pkt_nmblocks: mp $%p rptr $%p wptr $%p "
75552ccf843Smisaki 	    "len %d", mp, mp->b_rptr, mp->b_wptr, MBLKL(mp)));
75644961713Sgirish 
75744961713Sgirish 	nmp = mp;
75844961713Sgirish 	bmp = mp;
75944961713Sgirish 	nmblks = 0;
76044961713Sgirish 	pkt_len = 0;
76144961713Sgirish 	*tot_xfer_len_p = 0;
76244961713Sgirish 
76344961713Sgirish 	while (nmp) {
76444961713Sgirish 		len = MBLKL(nmp);
76544961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: "
76652ccf843Smisaki 		    "len %d pkt_len %d nmblks %d tot_xfer_len %d",
76752ccf843Smisaki 		    len, pkt_len, nmblks,
76852ccf843Smisaki 		    *tot_xfer_len_p));
76944961713Sgirish 
77044961713Sgirish 		if (len <= 0) {
77144961713Sgirish 			bmp = nmp;
77244961713Sgirish 			nmp = nmp->b_cont;
77344961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
77452ccf843Smisaki 			    "==> nxge_tx_pkt_nmblocks: "
77552ccf843Smisaki 			    "len (0) pkt_len %d nmblks %d",
77652ccf843Smisaki 			    pkt_len, nmblks));
77744961713Sgirish 			continue;
77844961713Sgirish 		}
77944961713Sgirish 
78044961713Sgirish 		*tot_xfer_len_p += len;
78144961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: "
78252ccf843Smisaki 		    "len %d pkt_len %d nmblks %d tot_xfer_len %d",
78352ccf843Smisaki 		    len, pkt_len, nmblks,
78452ccf843Smisaki 		    *tot_xfer_len_p));
78544961713Sgirish 
78644961713Sgirish 		if (len < nxge_bcopy_thresh) {
78744961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
78852ccf843Smisaki 			    "==> nxge_tx_pkt_nmblocks: "
78952ccf843Smisaki 			    "len %d (< thresh) pkt_len %d nmblks %d",
79052ccf843Smisaki 			    len, pkt_len, nmblks));
79144961713Sgirish 			if (pkt_len == 0)
79244961713Sgirish 				nmblks++;
79344961713Sgirish 			pkt_len += len;
79444961713Sgirish 			if (pkt_len >= nxge_bcopy_thresh) {
79544961713Sgirish 				pkt_len = 0;
79644961713Sgirish 				len = 0;
79744961713Sgirish 				nmp = bmp;
79844961713Sgirish 			}
79944961713Sgirish 		} else {
80044961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
80152ccf843Smisaki 			    "==> nxge_tx_pkt_nmblocks: "
80252ccf843Smisaki 			    "len %d (> thresh) pkt_len %d nmblks %d",
80352ccf843Smisaki 			    len, pkt_len, nmblks));
80444961713Sgirish 			pkt_len = 0;
80544961713Sgirish 			nmblks++;
80644961713Sgirish 			/*
80744961713Sgirish 			 * Hardware limits the transfer length to 4K.
80844961713Sgirish 			 * If len is more than 4K, we need to break
80944961713Sgirish 			 * it up to at most 2 more blocks.
81044961713Sgirish 			 */
81144961713Sgirish 			if (len > TX_MAX_TRANSFER_LENGTH) {
81244961713Sgirish 				uint32_t	nsegs;
81344961713Sgirish 
814678453a8Sspeer 				nsegs = 1;
81544961713Sgirish 				NXGE_DEBUG_MSG((NULL, TX_CTL,
81652ccf843Smisaki 				    "==> nxge_tx_pkt_nmblocks: "
81752ccf843Smisaki 				    "len %d pkt_len %d nmblks %d nsegs %d",
81852ccf843Smisaki 				    len, pkt_len, nmblks, nsegs));
81944961713Sgirish 				if (len % (TX_MAX_TRANSFER_LENGTH * 2)) {
82044961713Sgirish 					++nsegs;
82144961713Sgirish 				}
82244961713Sgirish 				do {
82344961713Sgirish 					b_wptr = nmp->b_rptr +
82452ccf843Smisaki 					    TX_MAX_TRANSFER_LENGTH;
82544961713Sgirish 					nmp->b_wptr = b_wptr;
82644961713Sgirish 					if ((tmp = dupb(nmp)) == NULL) {
82744961713Sgirish 						return (0);
82844961713Sgirish 					}
82944961713Sgirish 					tmp->b_rptr = b_wptr;
83044961713Sgirish 					tmp->b_wptr = nmp->b_wptr;
83144961713Sgirish 					tmp->b_cont = nmp->b_cont;
83244961713Sgirish 					nmp->b_cont = tmp;
83344961713Sgirish 					nmblks++;
83444961713Sgirish 					if (--nsegs) {
83544961713Sgirish 						nmp = tmp;
83644961713Sgirish 					}
83744961713Sgirish 				} while (nsegs);
83844961713Sgirish 				nmp = tmp;
83944961713Sgirish 			}
84044961713Sgirish 		}
84144961713Sgirish 
84244961713Sgirish 		/*
84344961713Sgirish 		 * Hardware limits the transmit gather pointers to 15.
84444961713Sgirish 		 */
84544961713Sgirish 		if (nmp->b_cont && (nmblks + TX_GATHER_POINTERS_THRESHOLD) >
84652ccf843Smisaki 		    TX_MAX_GATHER_POINTERS) {
84744961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
84852ccf843Smisaki 			    "==> nxge_tx_pkt_nmblocks: pull msg - "
84952ccf843Smisaki 			    "len %d pkt_len %d nmblks %d",
85052ccf843Smisaki 			    len, pkt_len, nmblks));
85144961713Sgirish 			/* Pull all message blocks from b_cont */
85244961713Sgirish 			if ((tmp = msgpullup(nmp->b_cont, -1)) == NULL) {
85344961713Sgirish 				return (0);
85444961713Sgirish 			}
85544961713Sgirish 			freemsg(nmp->b_cont);
85644961713Sgirish 			nmp->b_cont = tmp;
85744961713Sgirish 			pkt_len = 0;
85844961713Sgirish 		}
85944961713Sgirish 		bmp = nmp;
86044961713Sgirish 		nmp = nmp->b_cont;
86144961713Sgirish 	}
86244961713Sgirish 
86344961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
86452ccf843Smisaki 	    "<== nxge_tx_pkt_nmblocks: rptr $%p wptr $%p "
86552ccf843Smisaki 	    "nmblks %d len %d tot_xfer_len %d",
86652ccf843Smisaki 	    mp->b_rptr, mp->b_wptr, nmblks,
86752ccf843Smisaki 	    MBLKL(mp), *tot_xfer_len_p));
86844961713Sgirish 
86944961713Sgirish 	return (nmblks);
87044961713Sgirish }
87144961713Sgirish 
872*2d99c5d4SMichael Speer static void
873*2d99c5d4SMichael Speer nxge_txdma_freemsg_list_add(p_tx_ring_t tx_ring_p, p_tx_msg_t msgp)
874*2d99c5d4SMichael Speer {
875*2d99c5d4SMichael Speer 	MUTEX_ENTER(&tx_ring_p->freelock);
876*2d99c5d4SMichael Speer 	if (tx_ring_p->tx_free_list_p != NULL)
877*2d99c5d4SMichael Speer 		msgp->nextp = tx_ring_p->tx_free_list_p;
878*2d99c5d4SMichael Speer 	tx_ring_p->tx_free_list_p = msgp;
879*2d99c5d4SMichael Speer 	MUTEX_EXIT(&tx_ring_p->freelock);
880*2d99c5d4SMichael Speer }
881*2d99c5d4SMichael Speer 
882*2d99c5d4SMichael Speer /*
883*2d99c5d4SMichael Speer  * void
884*2d99c5d4SMichael Speer  * nxge_txdma_freemsg_task() -- walk the list of messages to be
885*2d99c5d4SMichael Speer  *	freed and free the messages.
886*2d99c5d4SMichael Speer  */
887*2d99c5d4SMichael Speer void
888*2d99c5d4SMichael Speer nxge_txdma_freemsg_task(p_tx_ring_t tx_ring_p)
889*2d99c5d4SMichael Speer {
890*2d99c5d4SMichael Speer 	p_tx_msg_t	msgp, nextp;
891*2d99c5d4SMichael Speer 
892*2d99c5d4SMichael Speer 	if (tx_ring_p->tx_free_list_p != NULL) {
893*2d99c5d4SMichael Speer 		MUTEX_ENTER(&tx_ring_p->freelock);
894*2d99c5d4SMichael Speer 		msgp = tx_ring_p->tx_free_list_p;
895*2d99c5d4SMichael Speer 		tx_ring_p->tx_free_list_p = (p_tx_msg_t)NULL;
896*2d99c5d4SMichael Speer 		MUTEX_EXIT(&tx_ring_p->freelock);
897*2d99c5d4SMichael Speer 
898*2d99c5d4SMichael Speer 		while (msgp != NULL) {
899*2d99c5d4SMichael Speer 			nextp = msgp->nextp;
900*2d99c5d4SMichael Speer 			if (msgp->tx_message != NULL) {
901*2d99c5d4SMichael Speer 				freemsg(msgp->tx_message);
902*2d99c5d4SMichael Speer 				msgp->tx_message = NULL;
903*2d99c5d4SMichael Speer 			}
904*2d99c5d4SMichael Speer 			msgp->nextp = NULL;
905*2d99c5d4SMichael Speer 			msgp = nextp;
906*2d99c5d4SMichael Speer 		}
907*2d99c5d4SMichael Speer 	}
908*2d99c5d4SMichael Speer }
909*2d99c5d4SMichael Speer 
91044961713Sgirish boolean_t
91144961713Sgirish nxge_txdma_reclaim(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, int nmblks)
91244961713Sgirish {
91344961713Sgirish 	boolean_t 		status = B_TRUE;
91444961713Sgirish 	p_nxge_dma_common_t	tx_desc_dma_p;
91544961713Sgirish 	nxge_dma_common_t	desc_area;
91644961713Sgirish 	p_tx_desc_t 		tx_desc_ring_vp;
91744961713Sgirish 	p_tx_desc_t 		tx_desc_p;
91844961713Sgirish 	p_tx_desc_t 		tx_desc_pp;
91944961713Sgirish 	tx_desc_t 		r_tx_desc;
92044961713Sgirish 	p_tx_msg_t 		tx_msg_ring;
92144961713Sgirish 	p_tx_msg_t 		tx_msg_p;
92244961713Sgirish 	npi_handle_t		handle;
92344961713Sgirish 	tx_ring_hdl_t		tx_head;
92444961713Sgirish 	uint32_t 		pkt_len;
92544961713Sgirish 	uint_t			tx_rd_index;
92644961713Sgirish 	uint16_t		head_index, tail_index;
92744961713Sgirish 	uint8_t			tdc;
92844961713Sgirish 	boolean_t		head_wrap, tail_wrap;
929*2d99c5d4SMichael Speer 	p_nxge_tx_ring_stats_t	tdc_stats;
93044961713Sgirish 	int			rc;
93144961713Sgirish 
93244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_reclaim"));
93344961713Sgirish 
93444961713Sgirish 	status = ((tx_ring_p->descs_pending < nxge_reclaim_pending) &&
93552ccf843Smisaki 	    (nmblks != 0));
93644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
93752ccf843Smisaki 	    "==> nxge_txdma_reclaim: pending %d  reclaim %d nmblks %d",
93852ccf843Smisaki 	    tx_ring_p->descs_pending, nxge_reclaim_pending,
93952ccf843Smisaki 	    nmblks));
94044961713Sgirish 	if (!status) {
94144961713Sgirish 		tx_desc_dma_p = &tx_ring_p->tdc_desc;
94244961713Sgirish 		desc_area = tx_ring_p->tdc_desc;
94344961713Sgirish 		handle = NXGE_DEV_NPI_HANDLE(nxgep);
94444961713Sgirish 		tx_desc_ring_vp = tx_desc_dma_p->kaddrp;
94544961713Sgirish 		tx_desc_ring_vp =
94652ccf843Smisaki 		    (p_tx_desc_t)DMA_COMMON_VPTR(desc_area);
94744961713Sgirish 		tx_rd_index = tx_ring_p->rd_index;
94844961713Sgirish 		tx_desc_p = &tx_desc_ring_vp[tx_rd_index];
94944961713Sgirish 		tx_msg_ring = tx_ring_p->tx_msg_ring;
95044961713Sgirish 		tx_msg_p = &tx_msg_ring[tx_rd_index];
95144961713Sgirish 		tdc = tx_ring_p->tdc;
95244961713Sgirish 		tdc_stats = tx_ring_p->tdc_stats;
95344961713Sgirish 		if (tx_ring_p->descs_pending > tdc_stats->tx_max_pend) {
95444961713Sgirish 			tdc_stats->tx_max_pend = tx_ring_p->descs_pending;
95544961713Sgirish 		}
95644961713Sgirish 
95744961713Sgirish 		tail_index = tx_ring_p->wr_index;
95844961713Sgirish 		tail_wrap = tx_ring_p->wr_index_wrap;
95944961713Sgirish 
96044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
96152ccf843Smisaki 		    "==> nxge_txdma_reclaim: tdc %d tx_rd_index %d "
96252ccf843Smisaki 		    "tail_index %d tail_wrap %d "
96352ccf843Smisaki 		    "tx_desc_p $%p ($%p) ",
96452ccf843Smisaki 		    tdc, tx_rd_index, tail_index, tail_wrap,
96552ccf843Smisaki 		    tx_desc_p, (*(uint64_t *)tx_desc_p)));
96644961713Sgirish 		/*
96744961713Sgirish 		 * Read the hardware maintained transmit head
96844961713Sgirish 		 * and wrap around bit.
96944961713Sgirish 		 */
97044961713Sgirish 		TXDMA_REG_READ64(handle, TX_RING_HDL_REG, tdc, &tx_head.value);
97144961713Sgirish 		head_index =  tx_head.bits.ldw.head;
97244961713Sgirish 		head_wrap = tx_head.bits.ldw.wrap;
97344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
97452ccf843Smisaki 		    "==> nxge_txdma_reclaim: "
97552ccf843Smisaki 		    "tx_rd_index %d tail %d tail_wrap %d "
97652ccf843Smisaki 		    "head %d wrap %d",
97752ccf843Smisaki 		    tx_rd_index, tail_index, tail_wrap,
97852ccf843Smisaki 		    head_index, head_wrap));
97944961713Sgirish 
98044961713Sgirish 		if (head_index == tail_index) {
98144961713Sgirish 			if (TXDMA_RING_EMPTY(head_index, head_wrap,
98252ccf843Smisaki 			    tail_index, tail_wrap) &&
98352ccf843Smisaki 			    (head_index == tx_rd_index)) {
98444961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
98552ccf843Smisaki 				    "==> nxge_txdma_reclaim: EMPTY"));
98644961713Sgirish 				return (B_TRUE);
98744961713Sgirish 			}
98844961713Sgirish 
98944961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
99052ccf843Smisaki 			    "==> nxge_txdma_reclaim: Checking "
99152ccf843Smisaki 			    "if ring full"));
99244961713Sgirish 			if (TXDMA_RING_FULL(head_index, head_wrap, tail_index,
99352ccf843Smisaki 			    tail_wrap)) {
99444961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
99552ccf843Smisaki 				    "==> nxge_txdma_reclaim: full"));
99644961713Sgirish 				return (B_FALSE);
99744961713Sgirish 			}
99844961713Sgirish 		}
99944961713Sgirish 
100044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
100152ccf843Smisaki 		    "==> nxge_txdma_reclaim: tx_rd_index and head_index"));
100244961713Sgirish 
100344961713Sgirish 		tx_desc_pp = &r_tx_desc;
100444961713Sgirish 		while ((tx_rd_index != head_index) &&
100552ccf843Smisaki 		    (tx_ring_p->descs_pending != 0)) {
100644961713Sgirish 
100744961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
100852ccf843Smisaki 			    "==> nxge_txdma_reclaim: Checking if pending"));
100944961713Sgirish 
101044961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
101152ccf843Smisaki 			    "==> nxge_txdma_reclaim: "
101252ccf843Smisaki 			    "descs_pending %d ",
101352ccf843Smisaki 			    tx_ring_p->descs_pending));
101444961713Sgirish 
101544961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
101652ccf843Smisaki 			    "==> nxge_txdma_reclaim: "
101752ccf843Smisaki 			    "(tx_rd_index %d head_index %d "
101852ccf843Smisaki 			    "(tx_desc_p $%p)",
101952ccf843Smisaki 			    tx_rd_index, head_index,
102052ccf843Smisaki 			    tx_desc_p));
102144961713Sgirish 
102244961713Sgirish 			tx_desc_pp->value = tx_desc_p->value;
102344961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
102452ccf843Smisaki 			    "==> nxge_txdma_reclaim: "
102552ccf843Smisaki 			    "(tx_rd_index %d head_index %d "
102652ccf843Smisaki 			    "tx_desc_p $%p (desc value 0x%llx) ",
102752ccf843Smisaki 			    tx_rd_index, head_index,
102852ccf843Smisaki 			    tx_desc_pp, (*(uint64_t *)tx_desc_pp)));
102944961713Sgirish 
103044961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
103152ccf843Smisaki 			    "==> nxge_txdma_reclaim: dump desc:"));
103244961713Sgirish 
103344961713Sgirish 			pkt_len = tx_desc_pp->bits.hdw.tr_len;
103444961713Sgirish 			tdc_stats->obytes += pkt_len;
103544961713Sgirish 			tdc_stats->opackets += tx_desc_pp->bits.hdw.sop;
103644961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
103752ccf843Smisaki 			    "==> nxge_txdma_reclaim: pkt_len %d "
103852ccf843Smisaki 			    "tdc channel %d opackets %d",
103952ccf843Smisaki 			    pkt_len,
104052ccf843Smisaki 			    tdc,
104152ccf843Smisaki 			    tdc_stats->opackets));
104244961713Sgirish 
104344961713Sgirish 			if (tx_msg_p->flags.dma_type == USE_DVMA) {
104444961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
104552ccf843Smisaki 				    "tx_desc_p = $%p "
104652ccf843Smisaki 				    "tx_desc_pp = $%p "
104752ccf843Smisaki 				    "index = %d",
104852ccf843Smisaki 				    tx_desc_p,
104952ccf843Smisaki 				    tx_desc_pp,
105052ccf843Smisaki 				    tx_ring_p->rd_index));
105144961713Sgirish 				(void) dvma_unload(tx_msg_p->dvma_handle,
105252ccf843Smisaki 				    0, -1);
105344961713Sgirish 				tx_msg_p->dvma_handle = NULL;
105444961713Sgirish 				if (tx_ring_p->dvma_wr_index ==
105552ccf843Smisaki 				    tx_ring_p->dvma_wrap_mask) {
105644961713Sgirish 					tx_ring_p->dvma_wr_index = 0;
105744961713Sgirish 				} else {
105844961713Sgirish 					tx_ring_p->dvma_wr_index++;
105944961713Sgirish 				}
106044961713Sgirish 				tx_ring_p->dvma_pending--;
106144961713Sgirish 			} else if (tx_msg_p->flags.dma_type ==
106252ccf843Smisaki 			    USE_DMA) {
106344961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
106452ccf843Smisaki 				    "==> nxge_txdma_reclaim: "
106552ccf843Smisaki 				    "USE DMA"));
106644961713Sgirish 				if (rc = ddi_dma_unbind_handle
106752ccf843Smisaki 				    (tx_msg_p->dma_handle)) {
106844961713Sgirish 					cmn_err(CE_WARN, "!nxge_reclaim: "
106952ccf843Smisaki 					    "ddi_dma_unbind_handle "
107052ccf843Smisaki 					    "failed. status %d", rc);
107144961713Sgirish 				}
107244961713Sgirish 			}
107344961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
107452ccf843Smisaki 			    "==> nxge_txdma_reclaim: count packets"));
1075*2d99c5d4SMichael Speer 
107644961713Sgirish 			/*
107744961713Sgirish 			 * count a chained packet only once.
107844961713Sgirish 			 */
107944961713Sgirish 			if (tx_msg_p->tx_message != NULL) {
1080*2d99c5d4SMichael Speer 				nxge_txdma_freemsg_list_add(tx_ring_p,
1081*2d99c5d4SMichael Speer 				    tx_msg_p);
108244961713Sgirish 			}
108344961713Sgirish 
108444961713Sgirish 			tx_msg_p->flags.dma_type = USE_NONE;
108544961713Sgirish 			tx_rd_index = tx_ring_p->rd_index;
108644961713Sgirish 			tx_rd_index = (tx_rd_index + 1) &
108752ccf843Smisaki 			    tx_ring_p->tx_wrap_mask;
108844961713Sgirish 			tx_ring_p->rd_index = tx_rd_index;
108944961713Sgirish 			tx_ring_p->descs_pending--;
109044961713Sgirish 			tx_desc_p = &tx_desc_ring_vp[tx_rd_index];
109144961713Sgirish 			tx_msg_p = &tx_msg_ring[tx_rd_index];
109244961713Sgirish 		}
109344961713Sgirish 
109444961713Sgirish 		status = (nmblks <= (tx_ring_p->tx_ring_size -
109552ccf843Smisaki 		    tx_ring_p->descs_pending -
109652ccf843Smisaki 		    TX_FULL_MARK));
109744961713Sgirish 		if (status) {
109844961713Sgirish 			cas32((uint32_t *)&tx_ring_p->queueing, 1, 0);
109944961713Sgirish 		}
110044961713Sgirish 	} else {
110144961713Sgirish 		status = (nmblks <=
110252ccf843Smisaki 		    (tx_ring_p->tx_ring_size -
110352ccf843Smisaki 		    tx_ring_p->descs_pending -
110452ccf843Smisaki 		    TX_FULL_MARK));
110544961713Sgirish 	}
110644961713Sgirish 
110744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
110852ccf843Smisaki 	    "<== nxge_txdma_reclaim status = 0x%08x", status));
110944961713Sgirish 
111044961713Sgirish 	return (status);
111144961713Sgirish }
111244961713Sgirish 
1113678453a8Sspeer /*
1114678453a8Sspeer  * nxge_tx_intr
1115678453a8Sspeer  *
1116678453a8Sspeer  *	Process a TDC interrupt
1117678453a8Sspeer  *
1118678453a8Sspeer  * Arguments:
1119678453a8Sspeer  * 	arg1	A Logical Device state Vector (LSV) data structure.
1120678453a8Sspeer  * 	arg2	nxge_t *
1121678453a8Sspeer  *
1122678453a8Sspeer  * Notes:
1123678453a8Sspeer  *
1124678453a8Sspeer  * NPI/NXGE function calls:
1125678453a8Sspeer  *	npi_txdma_control_status()
1126678453a8Sspeer  *	npi_intr_ldg_mgmt_set()
1127678453a8Sspeer  *
1128678453a8Sspeer  *	nxge_tx_err_evnts()
1129678453a8Sspeer  *	nxge_txdma_reclaim()
1130678453a8Sspeer  *
1131678453a8Sspeer  * Registers accessed:
1132678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1133678453a8Sspeer  *	PIO_LDSV
1134678453a8Sspeer  *
1135678453a8Sspeer  * Context:
1136678453a8Sspeer  *	Any domain
1137678453a8Sspeer  */
113844961713Sgirish uint_t
113944961713Sgirish nxge_tx_intr(void *arg1, void *arg2)
114044961713Sgirish {
114144961713Sgirish 	p_nxge_ldv_t		ldvp = (p_nxge_ldv_t)arg1;
114244961713Sgirish 	p_nxge_t		nxgep = (p_nxge_t)arg2;
114344961713Sgirish 	p_nxge_ldg_t		ldgp;
114444961713Sgirish 	uint8_t			channel;
114544961713Sgirish 	uint32_t		vindex;
114644961713Sgirish 	npi_handle_t		handle;
114744961713Sgirish 	tx_cs_t			cs;
114844961713Sgirish 	p_tx_ring_t 		*tx_rings;
114944961713Sgirish 	p_tx_ring_t 		tx_ring_p;
115044961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
115144961713Sgirish 	uint_t 			serviced = DDI_INTR_UNCLAIMED;
115244961713Sgirish 	nxge_status_t 		status = NXGE_OK;
115344961713Sgirish 
115444961713Sgirish 	if (ldvp == NULL) {
115544961713Sgirish 		NXGE_DEBUG_MSG((NULL, INT_CTL,
115652ccf843Smisaki 		    "<== nxge_tx_intr: nxgep $%p ldvp $%p",
115752ccf843Smisaki 		    nxgep, ldvp));
115844961713Sgirish 		return (DDI_INTR_UNCLAIMED);
115944961713Sgirish 	}
116044961713Sgirish 
116144961713Sgirish 	if (arg2 == NULL || (void *)ldvp->nxgep != arg2) {
116244961713Sgirish 		nxgep = ldvp->nxgep;
116344961713Sgirish 	}
116444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
116552ccf843Smisaki 	    "==> nxge_tx_intr: nxgep(arg2) $%p ldvp(arg1) $%p",
116652ccf843Smisaki 	    nxgep, ldvp));
116722c0d73aSspeer 
116822c0d73aSspeer 	if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) ||
116922c0d73aSspeer 	    (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) {
117022c0d73aSspeer 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
117122c0d73aSspeer 		    "<== nxge_tx_intr: interface not started or intialized"));
117222c0d73aSspeer 		return (DDI_INTR_CLAIMED);
117322c0d73aSspeer 	}
117422c0d73aSspeer 
117544961713Sgirish 	/*
117644961713Sgirish 	 * This interrupt handler is for a specific
117744961713Sgirish 	 * transmit dma channel.
117844961713Sgirish 	 */
117944961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
118044961713Sgirish 	/* Get the control and status for this channel. */
118144961713Sgirish 	channel = ldvp->channel;
118244961713Sgirish 	ldgp = ldvp->ldgp;
118344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
118452ccf843Smisaki 	    "==> nxge_tx_intr: nxgep $%p ldvp (ldvp) $%p "
118552ccf843Smisaki 	    "channel %d",
118652ccf843Smisaki 	    nxgep, ldvp, channel));
118744961713Sgirish 
118844961713Sgirish 	rs = npi_txdma_control_status(handle, OP_GET, channel, &cs);
118944961713Sgirish 	vindex = ldvp->vdma_index;
119044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
119152ccf843Smisaki 	    "==> nxge_tx_intr:channel %d ring index %d status 0x%08x",
119252ccf843Smisaki 	    channel, vindex, rs));
119344961713Sgirish 	if (!rs && cs.bits.ldw.mk) {
119444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
119552ccf843Smisaki 		    "==> nxge_tx_intr:channel %d ring index %d "
119652ccf843Smisaki 		    "status 0x%08x (mk bit set)",
119752ccf843Smisaki 		    channel, vindex, rs));
119844961713Sgirish 		tx_rings = nxgep->tx_rings->rings;
119944961713Sgirish 		tx_ring_p = tx_rings[vindex];
120044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
120152ccf843Smisaki 		    "==> nxge_tx_intr:channel %d ring index %d "
120252ccf843Smisaki 		    "status 0x%08x (mk bit set, calling reclaim)",
120352ccf843Smisaki 		    channel, vindex, rs));
120444961713Sgirish 
120544961713Sgirish 		MUTEX_ENTER(&tx_ring_p->lock);
120644961713Sgirish 		(void) nxge_txdma_reclaim(nxgep, tx_rings[vindex], 0);
120744961713Sgirish 		MUTEX_EXIT(&tx_ring_p->lock);
1208*2d99c5d4SMichael Speer 
1209*2d99c5d4SMichael Speer 		nxge_txdma_freemsg_task(tx_ring_p);
1210*2d99c5d4SMichael Speer 
121144961713Sgirish 		mac_tx_update(nxgep->mach);
121244961713Sgirish 	}
121344961713Sgirish 
121444961713Sgirish 	/*
121544961713Sgirish 	 * Process other transmit control and status.
121644961713Sgirish 	 * Check the ldv state.
121744961713Sgirish 	 */
121844961713Sgirish 	status = nxge_tx_err_evnts(nxgep, ldvp->vdma_index, ldvp, cs);
121944961713Sgirish 	/*
122044961713Sgirish 	 * Rearm this logical group if this is a single device
122144961713Sgirish 	 * group.
122244961713Sgirish 	 */
122344961713Sgirish 	if (ldgp->nldvs == 1) {
122444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
122552ccf843Smisaki 		    "==> nxge_tx_intr: rearm"));
122644961713Sgirish 		if (status == NXGE_OK) {
1227678453a8Sspeer 			if (isLDOMguest(nxgep)) {
1228678453a8Sspeer 				nxge_hio_ldgimgn(nxgep, ldgp);
1229678453a8Sspeer 			} else {
1230678453a8Sspeer 				(void) npi_intr_ldg_mgmt_set(handle, ldgp->ldg,
1231678453a8Sspeer 				    B_TRUE, ldgp->ldg_timer);
1232678453a8Sspeer 			}
123344961713Sgirish 		}
123444961713Sgirish 	}
123544961713Sgirish 
123644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_tx_intr"));
123744961713Sgirish 	serviced = DDI_INTR_CLAIMED;
123844961713Sgirish 	return (serviced);
123944961713Sgirish }
124044961713Sgirish 
124144961713Sgirish void
1242678453a8Sspeer nxge_txdma_stop(p_nxge_t nxgep)	/* Dead */
124344961713Sgirish {
124444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop"));
124544961713Sgirish 
124644961713Sgirish 	(void) nxge_link_monitor(nxgep, LINK_MONITOR_STOP);
124744961713Sgirish 
124844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop"));
124944961713Sgirish }
125044961713Sgirish 
125144961713Sgirish void
1252678453a8Sspeer nxge_txdma_stop_start(p_nxge_t nxgep) /* Dead */
125344961713Sgirish {
125444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_start"));
125544961713Sgirish 
125644961713Sgirish 	(void) nxge_txdma_stop(nxgep);
125744961713Sgirish 
125844961713Sgirish 	(void) nxge_fixup_txdma_rings(nxgep);
125944961713Sgirish 	(void) nxge_txdma_hw_mode(nxgep, NXGE_DMA_START);
126044961713Sgirish 	(void) nxge_tx_mac_enable(nxgep);
126144961713Sgirish 	(void) nxge_txdma_hw_kick(nxgep);
126244961713Sgirish 
126344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_start"));
126444961713Sgirish }
126544961713Sgirish 
1266678453a8Sspeer npi_status_t
1267678453a8Sspeer nxge_txdma_channel_disable(
1268678453a8Sspeer 	nxge_t *nxge,
1269678453a8Sspeer 	int channel)
1270678453a8Sspeer {
1271678453a8Sspeer 	npi_handle_t	handle = NXGE_DEV_NPI_HANDLE(nxge);
1272678453a8Sspeer 	npi_status_t	rs;
1273678453a8Sspeer 	tdmc_intr_dbg_t	intr_dbg;
1274678453a8Sspeer 
1275678453a8Sspeer 	/*
1276678453a8Sspeer 	 * Stop the dma channel and wait for the stop-done.
1277678453a8Sspeer 	 * If the stop-done bit is not present, then force
1278678453a8Sspeer 	 * an error so TXC will stop.
1279678453a8Sspeer 	 * All channels bound to this port need to be stopped
1280678453a8Sspeer 	 * and reset after injecting an interrupt error.
1281678453a8Sspeer 	 */
1282678453a8Sspeer 	rs = npi_txdma_channel_disable(handle, channel);
1283678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, MEM3_CTL,
128452ccf843Smisaki 	    "==> nxge_txdma_channel_disable(%d) "
128552ccf843Smisaki 	    "rs 0x%x", channel, rs));
1286678453a8Sspeer 	if (rs != NPI_SUCCESS) {
1287678453a8Sspeer 		/* Inject any error */
1288678453a8Sspeer 		intr_dbg.value = 0;
1289678453a8Sspeer 		intr_dbg.bits.ldw.nack_pref = 1;
1290678453a8Sspeer 		NXGE_DEBUG_MSG((nxge, MEM3_CTL,
129152ccf843Smisaki 		    "==> nxge_txdma_hw_mode: "
129252ccf843Smisaki 		    "channel %d (stop failed 0x%x) "
129352ccf843Smisaki 		    "(inject err)", rs, channel));
1294678453a8Sspeer 		(void) npi_txdma_inj_int_error_set(
129552ccf843Smisaki 		    handle, channel, &intr_dbg);
1296678453a8Sspeer 		rs = npi_txdma_channel_disable(handle, channel);
1297678453a8Sspeer 		NXGE_DEBUG_MSG((nxge, MEM3_CTL,
129852ccf843Smisaki 		    "==> nxge_txdma_hw_mode: "
129952ccf843Smisaki 		    "channel %d (stop again 0x%x) "
130052ccf843Smisaki 		    "(after inject err)",
130152ccf843Smisaki 		    rs, channel));
1302678453a8Sspeer 	}
1303678453a8Sspeer 
1304678453a8Sspeer 	return (rs);
1305678453a8Sspeer }
1306678453a8Sspeer 
1307678453a8Sspeer /*
1308678453a8Sspeer  * nxge_txdma_hw_mode
1309678453a8Sspeer  *
1310678453a8Sspeer  *	Toggle all TDCs on (enable) or off (disable).
1311678453a8Sspeer  *
1312678453a8Sspeer  * Arguments:
1313678453a8Sspeer  * 	nxgep
1314678453a8Sspeer  * 	enable	Enable or disable a TDC.
1315678453a8Sspeer  *
1316678453a8Sspeer  * Notes:
1317678453a8Sspeer  *
1318678453a8Sspeer  * NPI/NXGE function calls:
1319678453a8Sspeer  *	npi_txdma_channel_enable(TX_CS)
1320678453a8Sspeer  *	npi_txdma_channel_disable(TX_CS)
1321678453a8Sspeer  *	npi_txdma_inj_int_error_set(TDMC_INTR_DBG)
1322678453a8Sspeer  *
1323678453a8Sspeer  * Registers accessed:
1324678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1325678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
1326678453a8Sspeer  *
1327678453a8Sspeer  * Context:
1328678453a8Sspeer  *	Any domain
1329678453a8Sspeer  */
133044961713Sgirish nxge_status_t
133144961713Sgirish nxge_txdma_hw_mode(p_nxge_t nxgep, boolean_t enable)
133244961713Sgirish {
1333678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1334678453a8Sspeer 
1335678453a8Sspeer 	npi_handle_t	handle;
1336678453a8Sspeer 	nxge_status_t	status;
1337678453a8Sspeer 	npi_status_t	rs;
1338678453a8Sspeer 	int		tdc;
133944961713Sgirish 
134044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
134152ccf843Smisaki 	    "==> nxge_txdma_hw_mode: enable mode %d", enable));
134244961713Sgirish 
134344961713Sgirish 	if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) {
134444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
134552ccf843Smisaki 		    "<== nxge_txdma_mode: not initialized"));
134644961713Sgirish 		return (NXGE_ERROR);
134744961713Sgirish 	}
134844961713Sgirish 
1349678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
135044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1351678453a8Sspeer 		    "<== nxge_txdma_hw_mode: NULL ring pointer(s)"));
135244961713Sgirish 		return (NXGE_ERROR);
135344961713Sgirish 	}
135444961713Sgirish 
1355678453a8Sspeer 	/* Enable or disable all of the TDCs owned by us. */
135644961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
1357678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1358678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1359678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1360678453a8Sspeer 			if (ring) {
1361678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1362678453a8Sspeer 				    "==> nxge_txdma_hw_mode: channel %d", tdc));
1363678453a8Sspeer 				if (enable) {
1364678453a8Sspeer 					rs = npi_txdma_channel_enable
1365678453a8Sspeer 					    (handle, tdc);
136644961713Sgirish 					NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1367678453a8Sspeer 					    "==> nxge_txdma_hw_mode: "
1368678453a8Sspeer 					    "channel %d (enable) rs 0x%x",
1369678453a8Sspeer 					    tdc, rs));
1370678453a8Sspeer 				} else {
1371678453a8Sspeer 					rs = nxge_txdma_channel_disable
1372678453a8Sspeer 					    (nxgep, tdc);
137344961713Sgirish 				}
137444961713Sgirish 			}
137544961713Sgirish 		}
137644961713Sgirish 	}
137744961713Sgirish 
137844961713Sgirish 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
137944961713Sgirish 
138044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
138152ccf843Smisaki 	    "<== nxge_txdma_hw_mode: status 0x%x", status));
138244961713Sgirish 
138344961713Sgirish 	return (status);
138444961713Sgirish }
138544961713Sgirish 
138644961713Sgirish void
138744961713Sgirish nxge_txdma_enable_channel(p_nxge_t nxgep, uint16_t channel)
138844961713Sgirish {
138944961713Sgirish 	npi_handle_t		handle;
139044961713Sgirish 
139144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DMA_CTL,
139252ccf843Smisaki 	    "==> nxge_txdma_enable_channel: channel %d", channel));
139344961713Sgirish 
139444961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
139544961713Sgirish 	/* enable the transmit dma channels */
139644961713Sgirish 	(void) npi_txdma_channel_enable(handle, channel);
139744961713Sgirish 
139844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DMA_CTL, "<== nxge_txdma_enable_channel"));
139944961713Sgirish }
140044961713Sgirish 
140144961713Sgirish void
140244961713Sgirish nxge_txdma_disable_channel(p_nxge_t nxgep, uint16_t channel)
140344961713Sgirish {
140444961713Sgirish 	npi_handle_t		handle;
140544961713Sgirish 
140644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DMA_CTL,
140752ccf843Smisaki 	    "==> nxge_txdma_disable_channel: channel %d", channel));
140844961713Sgirish 
140944961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
141044961713Sgirish 	/* stop the transmit dma channels */
141144961713Sgirish 	(void) npi_txdma_channel_disable(handle, channel);
141244961713Sgirish 
141344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_disable_channel"));
141444961713Sgirish }
141544961713Sgirish 
1416678453a8Sspeer /*
1417678453a8Sspeer  * nxge_txdma_stop_inj_err
1418678453a8Sspeer  *
1419678453a8Sspeer  *	Stop a TDC.  If at first we don't succeed, inject an error.
1420678453a8Sspeer  *
1421678453a8Sspeer  * Arguments:
1422678453a8Sspeer  * 	nxgep
1423678453a8Sspeer  * 	channel		The channel to stop.
1424678453a8Sspeer  *
1425678453a8Sspeer  * Notes:
1426678453a8Sspeer  *
1427678453a8Sspeer  * NPI/NXGE function calls:
1428678453a8Sspeer  *	npi_txdma_channel_disable()
1429678453a8Sspeer  *	npi_txdma_inj_int_error_set()
1430678453a8Sspeer  * #if defined(NXGE_DEBUG)
1431678453a8Sspeer  *	nxge_txdma_regs_dump_channels(nxgep);
1432678453a8Sspeer  * #endif
1433678453a8Sspeer  *
1434678453a8Sspeer  * Registers accessed:
1435678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1436678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
1437678453a8Sspeer  *
1438678453a8Sspeer  * Context:
1439678453a8Sspeer  *	Any domain
1440678453a8Sspeer  */
144144961713Sgirish int
144244961713Sgirish nxge_txdma_stop_inj_err(p_nxge_t nxgep, int channel)
144344961713Sgirish {
144444961713Sgirish 	npi_handle_t		handle;
144544961713Sgirish 	tdmc_intr_dbg_t		intr_dbg;
144644961713Sgirish 	int			status;
144744961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
144844961713Sgirish 
144944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_inj_err"));
145044961713Sgirish 	/*
145144961713Sgirish 	 * Stop the dma channel waits for the stop done.
145244961713Sgirish 	 * If the stop done bit is not set, then create
145344961713Sgirish 	 * an error.
145444961713Sgirish 	 */
145544961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
145644961713Sgirish 	rs = npi_txdma_channel_disable(handle, channel);
145744961713Sgirish 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
145844961713Sgirish 	if (status == NXGE_OK) {
145944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
146052ccf843Smisaki 		    "<== nxge_txdma_stop_inj_err (channel %d): "
146152ccf843Smisaki 		    "stopped OK", channel));
146244961713Sgirish 		return (status);
146344961713Sgirish 	}
146444961713Sgirish 
146544961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
146652ccf843Smisaki 	    "==> nxge_txdma_stop_inj_err (channel %d): stop failed (0x%x) "
146752ccf843Smisaki 	    "injecting error", channel, rs));
146844961713Sgirish 	/* Inject any error */
146944961713Sgirish 	intr_dbg.value = 0;
147044961713Sgirish 	intr_dbg.bits.ldw.nack_pref = 1;
147144961713Sgirish 	(void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg);
147244961713Sgirish 
147344961713Sgirish 	/* Stop done bit will be set as a result of error injection */
147444961713Sgirish 	rs = npi_txdma_channel_disable(handle, channel);
147544961713Sgirish 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
147644961713Sgirish 	if (!(rs & NPI_TXDMA_STOP_FAILED)) {
147744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
147852ccf843Smisaki 		    "<== nxge_txdma_stop_inj_err (channel %d): "
147952ccf843Smisaki 		    "stopped OK ", channel));
148044961713Sgirish 		return (status);
148144961713Sgirish 	}
148244961713Sgirish 
148344961713Sgirish #if	defined(NXGE_DEBUG)
148444961713Sgirish 	nxge_txdma_regs_dump_channels(nxgep);
148544961713Sgirish #endif
148644961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
148752ccf843Smisaki 	    "==> nxge_txdma_stop_inj_err (channel): stop failed (0x%x) "
148852ccf843Smisaki 	    " (injected error but still not stopped)", channel, rs));
148944961713Sgirish 
149044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_inj_err"));
149144961713Sgirish 	return (status);
149244961713Sgirish }
149344961713Sgirish 
149444961713Sgirish /*ARGSUSED*/
149544961713Sgirish void
149644961713Sgirish nxge_fixup_txdma_rings(p_nxge_t nxgep)
149744961713Sgirish {
1498678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1499678453a8Sspeer 	int tdc;
150044961713Sgirish 
150144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_txdma_rings"));
150244961713Sgirish 
1503678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
1504678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1505678453a8Sspeer 		    "<== nxge_fixup_txdma_rings: NULL ring pointer(s)"));
150644961713Sgirish 		return;
150744961713Sgirish 	}
150844961713Sgirish 
1509678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1510678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1511678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1512678453a8Sspeer 			if (ring) {
1513678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1514678453a8Sspeer 				    "==> nxge_fixup_txdma_rings: channel %d",
1515678453a8Sspeer 				    tdc));
1516678453a8Sspeer 				nxge_txdma_fixup_channel(nxgep, ring, tdc);
1517678453a8Sspeer 			}
1518678453a8Sspeer 		}
151944961713Sgirish 	}
152044961713Sgirish 
152144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_txdma_rings"));
152244961713Sgirish }
152344961713Sgirish 
152444961713Sgirish /*ARGSUSED*/
152544961713Sgirish void
152644961713Sgirish nxge_txdma_fix_channel(p_nxge_t nxgep, uint16_t channel)
152744961713Sgirish {
152844961713Sgirish 	p_tx_ring_t	ring_p;
152944961713Sgirish 
153044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_channel"));
153144961713Sgirish 	ring_p = nxge_txdma_get_ring(nxgep, channel);
153244961713Sgirish 	if (ring_p == NULL) {
153344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel"));
153444961713Sgirish 		return;
153544961713Sgirish 	}
153644961713Sgirish 
153744961713Sgirish 	if (ring_p->tdc != channel) {
153844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
153952ccf843Smisaki 		    "<== nxge_txdma_fix_channel: channel not matched "
154052ccf843Smisaki 		    "ring tdc %d passed channel",
154152ccf843Smisaki 		    ring_p->tdc, channel));
154244961713Sgirish 		return;
154344961713Sgirish 	}
154444961713Sgirish 
154544961713Sgirish 	nxge_txdma_fixup_channel(nxgep, ring_p, channel);
154644961713Sgirish 
154744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel"));
154844961713Sgirish }
154944961713Sgirish 
155044961713Sgirish /*ARGSUSED*/
155144961713Sgirish void
155244961713Sgirish nxge_txdma_fixup_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel)
155344961713Sgirish {
155444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_channel"));
155544961713Sgirish 
155644961713Sgirish 	if (ring_p == NULL) {
155744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
155852ccf843Smisaki 		    "<== nxge_txdma_fixup_channel: NULL ring pointer"));
155944961713Sgirish 		return;
156044961713Sgirish 	}
156144961713Sgirish 
156244961713Sgirish 	if (ring_p->tdc != channel) {
156344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
156452ccf843Smisaki 		    "<== nxge_txdma_fixup_channel: channel not matched "
156552ccf843Smisaki 		    "ring tdc %d passed channel",
156652ccf843Smisaki 		    ring_p->tdc, channel));
156744961713Sgirish 		return;
156844961713Sgirish 	}
156944961713Sgirish 
157044961713Sgirish 	MUTEX_ENTER(&ring_p->lock);
157144961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, ring_p, 0);
157244961713Sgirish 	ring_p->rd_index = 0;
157344961713Sgirish 	ring_p->wr_index = 0;
157444961713Sgirish 	ring_p->ring_head.value = 0;
157544961713Sgirish 	ring_p->ring_kick_tail.value = 0;
157644961713Sgirish 	ring_p->descs_pending = 0;
157744961713Sgirish 	MUTEX_EXIT(&ring_p->lock);
1578*2d99c5d4SMichael Speer 	nxge_txdma_freemsg_task(ring_p);
157944961713Sgirish 
158044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_channel"));
158144961713Sgirish }
158244961713Sgirish 
158344961713Sgirish /*ARGSUSED*/
158444961713Sgirish void
158544961713Sgirish nxge_txdma_hw_kick(p_nxge_t nxgep)
158644961713Sgirish {
1587678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1588678453a8Sspeer 	int tdc;
158944961713Sgirish 
159044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick"));
159144961713Sgirish 
1592678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
159344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1594678453a8Sspeer 		    "<== nxge_txdma_hw_kick: NULL ring pointer(s)"));
159544961713Sgirish 		return;
159644961713Sgirish 	}
159744961713Sgirish 
1598678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1599678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1600678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1601678453a8Sspeer 			if (ring) {
1602678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1603678453a8Sspeer 				    "==> nxge_txdma_hw_kick: channel %d", tdc));
1604678453a8Sspeer 				nxge_txdma_hw_kick_channel(nxgep, ring, tdc);
1605678453a8Sspeer 			}
1606678453a8Sspeer 		}
160744961713Sgirish 	}
160844961713Sgirish 
160944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick"));
161044961713Sgirish }
161144961713Sgirish 
161244961713Sgirish /*ARGSUSED*/
161344961713Sgirish void
161444961713Sgirish nxge_txdma_kick_channel(p_nxge_t nxgep, uint16_t channel)
161544961713Sgirish {
161644961713Sgirish 	p_tx_ring_t	ring_p;
161744961713Sgirish 
161844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_kick_channel"));
161944961713Sgirish 
162044961713Sgirish 	ring_p = nxge_txdma_get_ring(nxgep, channel);
162144961713Sgirish 	if (ring_p == NULL) {
162244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
162352ccf843Smisaki 		    " nxge_txdma_kick_channel"));
162444961713Sgirish 		return;
162544961713Sgirish 	}
162644961713Sgirish 
162744961713Sgirish 	if (ring_p->tdc != channel) {
162844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
162952ccf843Smisaki 		    "<== nxge_txdma_kick_channel: channel not matched "
163052ccf843Smisaki 		    "ring tdc %d passed channel",
163152ccf843Smisaki 		    ring_p->tdc, channel));
163244961713Sgirish 		return;
163344961713Sgirish 	}
163444961713Sgirish 
163544961713Sgirish 	nxge_txdma_hw_kick_channel(nxgep, ring_p, channel);
163644961713Sgirish 
163744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_kick_channel"));
163844961713Sgirish }
1639a3c5bd6dSspeer 
164044961713Sgirish /*ARGSUSED*/
164144961713Sgirish void
164244961713Sgirish nxge_txdma_hw_kick_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel)
164344961713Sgirish {
164444961713Sgirish 
164544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick_channel"));
164644961713Sgirish 
164744961713Sgirish 	if (ring_p == NULL) {
164844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
164952ccf843Smisaki 		    "<== nxge_txdma_hw_kick_channel: NULL ring pointer"));
165044961713Sgirish 		return;
165144961713Sgirish 	}
165244961713Sgirish 
165344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick_channel"));
165444961713Sgirish }
165544961713Sgirish 
1656678453a8Sspeer /*
1657678453a8Sspeer  * nxge_check_tx_hang
1658678453a8Sspeer  *
1659678453a8Sspeer  *	Check the state of all TDCs belonging to nxgep.
1660678453a8Sspeer  *
1661678453a8Sspeer  * Arguments:
1662678453a8Sspeer  * 	nxgep
1663678453a8Sspeer  *
1664678453a8Sspeer  * Notes:
1665678453a8Sspeer  *	Called by nxge_hw.c:nxge_check_hw_state().
1666678453a8Sspeer  *
1667678453a8Sspeer  * NPI/NXGE function calls:
1668678453a8Sspeer  *
1669678453a8Sspeer  * Registers accessed:
1670678453a8Sspeer  *
1671678453a8Sspeer  * Context:
1672678453a8Sspeer  *	Any domain
1673678453a8Sspeer  */
167444961713Sgirish /*ARGSUSED*/
167544961713Sgirish void
167644961713Sgirish nxge_check_tx_hang(p_nxge_t nxgep)
167744961713Sgirish {
167844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_check_tx_hang"));
167944961713Sgirish 
168022c0d73aSspeer 	if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) ||
168122c0d73aSspeer 	    (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) {
168222c0d73aSspeer 		goto nxge_check_tx_hang_exit;
168322c0d73aSspeer 	}
168422c0d73aSspeer 
168544961713Sgirish 	/*
168644961713Sgirish 	 * Needs inputs from hardware for regs:
168744961713Sgirish 	 *	head index had not moved since last timeout.
168844961713Sgirish 	 *	packets not transmitted or stuffed registers.
168944961713Sgirish 	 */
169044961713Sgirish 	if (nxge_txdma_hung(nxgep)) {
169144961713Sgirish 		nxge_fixup_hung_txdma_rings(nxgep);
169244961713Sgirish 	}
169322c0d73aSspeer 
169422c0d73aSspeer nxge_check_tx_hang_exit:
169544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_check_tx_hang"));
169644961713Sgirish }
169744961713Sgirish 
1698678453a8Sspeer /*
1699678453a8Sspeer  * nxge_txdma_hung
1700678453a8Sspeer  *
1701678453a8Sspeer  *	Reset a TDC.
1702678453a8Sspeer  *
1703678453a8Sspeer  * Arguments:
1704678453a8Sspeer  * 	nxgep
1705678453a8Sspeer  * 	channel		The channel to reset.
1706678453a8Sspeer  * 	reg_data	The current TX_CS.
1707678453a8Sspeer  *
1708678453a8Sspeer  * Notes:
1709678453a8Sspeer  *	Called by nxge_check_tx_hang()
1710678453a8Sspeer  *
1711678453a8Sspeer  * NPI/NXGE function calls:
1712678453a8Sspeer  *	nxge_txdma_channel_hung()
1713678453a8Sspeer  *
1714678453a8Sspeer  * Registers accessed:
1715678453a8Sspeer  *
1716678453a8Sspeer  * Context:
1717678453a8Sspeer  *	Any domain
1718678453a8Sspeer  */
171944961713Sgirish int
172044961713Sgirish nxge_txdma_hung(p_nxge_t nxgep)
172144961713Sgirish {
1722330cd344SMichael Speer 	nxge_grp_set_t	*set = &nxgep->tx_set;
1723330cd344SMichael Speer 	int		tdc;
1724330cd344SMichael Speer 	boolean_t	shared;
172544961713Sgirish 
172644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hung"));
172744961713Sgirish 
1728678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
172944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1730678453a8Sspeer 		    "<== nxge_txdma_hung: NULL ring pointer(s)"));
173144961713Sgirish 		return (B_FALSE);
173244961713Sgirish 	}
173344961713Sgirish 
1734678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1735330cd344SMichael Speer 		/*
1736330cd344SMichael Speer 		 * Grab the shared state of the TDC.
1737330cd344SMichael Speer 		 */
1738330cd344SMichael Speer 		if (isLDOMservice(nxgep)) {
1739330cd344SMichael Speer 			nxge_hio_data_t *nhd =
1740330cd344SMichael Speer 			    (nxge_hio_data_t *)nxgep->nxge_hw_p->hio;
1741330cd344SMichael Speer 
1742330cd344SMichael Speer 			MUTEX_ENTER(&nhd->lock);
1743330cd344SMichael Speer 			shared = nxgep->tdc_is_shared[tdc];
1744330cd344SMichael Speer 			MUTEX_EXIT(&nhd->lock);
1745330cd344SMichael Speer 		} else {
1746330cd344SMichael Speer 			shared = B_FALSE;
1747330cd344SMichael Speer 		}
1748330cd344SMichael Speer 
1749330cd344SMichael Speer 		/*
1750330cd344SMichael Speer 		 * Now, process continue to process.
1751330cd344SMichael Speer 		 */
1752330cd344SMichael Speer 		if (((1 << tdc) & set->owned.map) && !shared) {
1753678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1754678453a8Sspeer 			if (ring) {
1755678453a8Sspeer 				if (nxge_txdma_channel_hung(nxgep, ring, tdc)) {
1756678453a8Sspeer 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
1757678453a8Sspeer 					    "==> nxge_txdma_hung: TDC %d hung",
1758678453a8Sspeer 					    tdc));
1759678453a8Sspeer 					return (B_TRUE);
1760678453a8Sspeer 				}
1761678453a8Sspeer 			}
176244961713Sgirish 		}
176344961713Sgirish 	}
176444961713Sgirish 
176544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hung"));
176644961713Sgirish 
176744961713Sgirish 	return (B_FALSE);
176844961713Sgirish }
176944961713Sgirish 
1770678453a8Sspeer /*
1771678453a8Sspeer  * nxge_txdma_channel_hung
1772678453a8Sspeer  *
1773678453a8Sspeer  *	Reset a TDC.
1774678453a8Sspeer  *
1775678453a8Sspeer  * Arguments:
1776678453a8Sspeer  * 	nxgep
1777678453a8Sspeer  * 	ring		<channel>'s ring.
1778678453a8Sspeer  * 	channel		The channel to reset.
1779678453a8Sspeer  *
1780678453a8Sspeer  * Notes:
1781678453a8Sspeer  *	Called by nxge_txdma.c:nxge_txdma_hung()
1782678453a8Sspeer  *
1783678453a8Sspeer  * NPI/NXGE function calls:
1784678453a8Sspeer  *	npi_txdma_ring_head_get()
1785678453a8Sspeer  *
1786678453a8Sspeer  * Registers accessed:
1787678453a8Sspeer  *	TX_RING_HDL	DMC+0x40010 Transmit Ring Head Low
1788678453a8Sspeer  *
1789678453a8Sspeer  * Context:
1790678453a8Sspeer  *	Any domain
1791678453a8Sspeer  */
179244961713Sgirish int
179344961713Sgirish nxge_txdma_channel_hung(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, uint16_t channel)
179444961713Sgirish {
179544961713Sgirish 	uint16_t		head_index, tail_index;
179644961713Sgirish 	boolean_t		head_wrap, tail_wrap;
179744961713Sgirish 	npi_handle_t		handle;
179844961713Sgirish 	tx_ring_hdl_t		tx_head;
179944961713Sgirish 	uint_t			tx_rd_index;
180044961713Sgirish 
180144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_channel_hung"));
180244961713Sgirish 
180344961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
180444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
180552ccf843Smisaki 	    "==> nxge_txdma_channel_hung: channel %d", channel));
180644961713Sgirish 	MUTEX_ENTER(&tx_ring_p->lock);
180744961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
180844961713Sgirish 
180944961713Sgirish 	tail_index = tx_ring_p->wr_index;
181044961713Sgirish 	tail_wrap = tx_ring_p->wr_index_wrap;
181144961713Sgirish 	tx_rd_index = tx_ring_p->rd_index;
181244961713Sgirish 	MUTEX_EXIT(&tx_ring_p->lock);
1813*2d99c5d4SMichael Speer 	nxge_txdma_freemsg_task(tx_ring_p);
181444961713Sgirish 
181544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
181652ccf843Smisaki 	    "==> nxge_txdma_channel_hung: tdc %d tx_rd_index %d "
181752ccf843Smisaki 	    "tail_index %d tail_wrap %d ",
181852ccf843Smisaki 	    channel, tx_rd_index, tail_index, tail_wrap));
181944961713Sgirish 	/*
182044961713Sgirish 	 * Read the hardware maintained transmit head
182144961713Sgirish 	 * and wrap around bit.
182244961713Sgirish 	 */
182344961713Sgirish 	(void) npi_txdma_ring_head_get(handle, channel, &tx_head);
182444961713Sgirish 	head_index =  tx_head.bits.ldw.head;
182544961713Sgirish 	head_wrap = tx_head.bits.ldw.wrap;
182644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
182752ccf843Smisaki 	    "==> nxge_txdma_channel_hung: "
182852ccf843Smisaki 	    "tx_rd_index %d tail %d tail_wrap %d "
182952ccf843Smisaki 	    "head %d wrap %d",
183052ccf843Smisaki 	    tx_rd_index, tail_index, tail_wrap,
183152ccf843Smisaki 	    head_index, head_wrap));
183244961713Sgirish 
183344961713Sgirish 	if (TXDMA_RING_EMPTY(head_index, head_wrap,
183452ccf843Smisaki 	    tail_index, tail_wrap) &&
183552ccf843Smisaki 	    (head_index == tx_rd_index)) {
183644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
183752ccf843Smisaki 		    "==> nxge_txdma_channel_hung: EMPTY"));
183844961713Sgirish 		return (B_FALSE);
183944961713Sgirish 	}
184044961713Sgirish 
184144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
184252ccf843Smisaki 	    "==> nxge_txdma_channel_hung: Checking if ring full"));
184344961713Sgirish 	if (TXDMA_RING_FULL(head_index, head_wrap, tail_index,
184452ccf843Smisaki 	    tail_wrap)) {
184544961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
184652ccf843Smisaki 		    "==> nxge_txdma_channel_hung: full"));
184744961713Sgirish 		return (B_TRUE);
184844961713Sgirish 	}
184944961713Sgirish 
185044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_channel_hung"));
185144961713Sgirish 
185244961713Sgirish 	return (B_FALSE);
185344961713Sgirish }
185444961713Sgirish 
1855678453a8Sspeer /*
1856678453a8Sspeer  * nxge_fixup_hung_txdma_rings
1857678453a8Sspeer  *
1858678453a8Sspeer  *	Disable a TDC.
1859678453a8Sspeer  *
1860678453a8Sspeer  * Arguments:
1861678453a8Sspeer  * 	nxgep
1862678453a8Sspeer  * 	channel		The channel to reset.
1863678453a8Sspeer  * 	reg_data	The current TX_CS.
1864678453a8Sspeer  *
1865678453a8Sspeer  * Notes:
1866678453a8Sspeer  *	Called by nxge_check_tx_hang()
1867678453a8Sspeer  *
1868678453a8Sspeer  * NPI/NXGE function calls:
1869678453a8Sspeer  *	npi_txdma_ring_head_get()
1870678453a8Sspeer  *
1871678453a8Sspeer  * Registers accessed:
1872678453a8Sspeer  *	TX_RING_HDL	DMC+0x40010 Transmit Ring Head Low
1873678453a8Sspeer  *
1874678453a8Sspeer  * Context:
1875678453a8Sspeer  *	Any domain
1876678453a8Sspeer  */
187744961713Sgirish /*ARGSUSED*/
187844961713Sgirish void
187944961713Sgirish nxge_fixup_hung_txdma_rings(p_nxge_t nxgep)
188044961713Sgirish {
1881678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
1882678453a8Sspeer 	int tdc;
188344961713Sgirish 
188444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_hung_txdma_rings"));
188544961713Sgirish 
1886678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
188744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1888678453a8Sspeer 		    "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
188944961713Sgirish 		return;
189044961713Sgirish 	}
189144961713Sgirish 
1892678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1893678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
1894678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1895678453a8Sspeer 			if (ring) {
1896678453a8Sspeer 				nxge_txdma_fixup_hung_channel(nxgep, ring, tdc);
1897678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
1898678453a8Sspeer 				    "==> nxge_fixup_hung_txdma_rings: TDC %d",
1899678453a8Sspeer 				    tdc));
1900678453a8Sspeer 			}
1901678453a8Sspeer 		}
190244961713Sgirish 	}
190344961713Sgirish 
190444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_hung_txdma_rings"));
190544961713Sgirish }
190644961713Sgirish 
1907678453a8Sspeer /*
1908678453a8Sspeer  * nxge_txdma_fixup_hung_channel
1909678453a8Sspeer  *
1910678453a8Sspeer  *	'Fix' a hung TDC.
1911678453a8Sspeer  *
1912678453a8Sspeer  * Arguments:
1913678453a8Sspeer  * 	nxgep
1914678453a8Sspeer  * 	channel		The channel to fix.
1915678453a8Sspeer  *
1916678453a8Sspeer  * Notes:
1917678453a8Sspeer  *	Called by nxge_fixup_hung_txdma_rings()
1918678453a8Sspeer  *
1919678453a8Sspeer  *	1. Reclaim the TDC.
1920678453a8Sspeer  *	2. Disable the TDC.
1921678453a8Sspeer  *
1922678453a8Sspeer  * NPI/NXGE function calls:
1923678453a8Sspeer  *	nxge_txdma_reclaim()
1924678453a8Sspeer  *	npi_txdma_channel_disable(TX_CS)
1925678453a8Sspeer  *	npi_txdma_inj_int_error_set(TDMC_INTR_DBG)
1926678453a8Sspeer  *
1927678453a8Sspeer  * Registers accessed:
1928678453a8Sspeer  *	TX_CS		DMC+0x40028 Transmit Control And Status
1929678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
1930678453a8Sspeer  *
1931678453a8Sspeer  * Context:
1932678453a8Sspeer  *	Any domain
1933678453a8Sspeer  */
193444961713Sgirish /*ARGSUSED*/
193544961713Sgirish void
193644961713Sgirish nxge_txdma_fix_hung_channel(p_nxge_t nxgep, uint16_t channel)
193744961713Sgirish {
193844961713Sgirish 	p_tx_ring_t	ring_p;
193944961713Sgirish 
194044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_hung_channel"));
194144961713Sgirish 	ring_p = nxge_txdma_get_ring(nxgep, channel);
194244961713Sgirish 	if (ring_p == NULL) {
194344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
194452ccf843Smisaki 		    "<== nxge_txdma_fix_hung_channel"));
194544961713Sgirish 		return;
194644961713Sgirish 	}
194744961713Sgirish 
194844961713Sgirish 	if (ring_p->tdc != channel) {
194944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
195052ccf843Smisaki 		    "<== nxge_txdma_fix_hung_channel: channel not matched "
195152ccf843Smisaki 		    "ring tdc %d passed channel",
195252ccf843Smisaki 		    ring_p->tdc, channel));
195344961713Sgirish 		return;
195444961713Sgirish 	}
195544961713Sgirish 
195644961713Sgirish 	nxge_txdma_fixup_channel(nxgep, ring_p, channel);
195744961713Sgirish 
195844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_hung_channel"));
195944961713Sgirish }
196044961713Sgirish 
196144961713Sgirish /*ARGSUSED*/
196244961713Sgirish void
196344961713Sgirish nxge_txdma_fixup_hung_channel(p_nxge_t nxgep, p_tx_ring_t ring_p,
196444961713Sgirish 	uint16_t channel)
196544961713Sgirish {
196644961713Sgirish 	npi_handle_t		handle;
196744961713Sgirish 	tdmc_intr_dbg_t		intr_dbg;
196844961713Sgirish 	int			status = NXGE_OK;
196944961713Sgirish 
197044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_hung_channel"));
197144961713Sgirish 
197244961713Sgirish 	if (ring_p == NULL) {
197344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
197452ccf843Smisaki 		    "<== nxge_txdma_fixup_channel: NULL ring pointer"));
197544961713Sgirish 		return;
197644961713Sgirish 	}
197744961713Sgirish 
197844961713Sgirish 	if (ring_p->tdc != channel) {
197944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
198052ccf843Smisaki 		    "<== nxge_txdma_fixup_hung_channel: channel "
198152ccf843Smisaki 		    "not matched "
198252ccf843Smisaki 		    "ring tdc %d passed channel",
198352ccf843Smisaki 		    ring_p->tdc, channel));
198444961713Sgirish 		return;
198544961713Sgirish 	}
198644961713Sgirish 
198744961713Sgirish 	/* Reclaim descriptors */
198844961713Sgirish 	MUTEX_ENTER(&ring_p->lock);
198944961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, ring_p, 0);
199044961713Sgirish 	MUTEX_EXIT(&ring_p->lock);
199144961713Sgirish 
1992*2d99c5d4SMichael Speer 	nxge_txdma_freemsg_task(ring_p);
1993*2d99c5d4SMichael Speer 
199444961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
199544961713Sgirish 	/*
199644961713Sgirish 	 * Stop the dma channel waits for the stop done.
199744961713Sgirish 	 * If the stop done bit is not set, then force
199844961713Sgirish 	 * an error.
199944961713Sgirish 	 */
200044961713Sgirish 	status = npi_txdma_channel_disable(handle, channel);
200144961713Sgirish 	if (!(status & NPI_TXDMA_STOP_FAILED)) {
200244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
200352ccf843Smisaki 		    "<== nxge_txdma_fixup_hung_channel: stopped OK "
200452ccf843Smisaki 		    "ring tdc %d passed channel %d",
200552ccf843Smisaki 		    ring_p->tdc, channel));
200644961713Sgirish 		return;
200744961713Sgirish 	}
200844961713Sgirish 
200944961713Sgirish 	/* Inject any error */
201044961713Sgirish 	intr_dbg.value = 0;
201144961713Sgirish 	intr_dbg.bits.ldw.nack_pref = 1;
201244961713Sgirish 	(void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg);
201344961713Sgirish 
201444961713Sgirish 	/* Stop done bit will be set as a result of error injection */
201544961713Sgirish 	status = npi_txdma_channel_disable(handle, channel);
201644961713Sgirish 	if (!(status & NPI_TXDMA_STOP_FAILED)) {
201744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
201852ccf843Smisaki 		    "<== nxge_txdma_fixup_hung_channel: stopped again"
201952ccf843Smisaki 		    "ring tdc %d passed channel",
202052ccf843Smisaki 		    ring_p->tdc, channel));
202144961713Sgirish 		return;
202244961713Sgirish 	}
202344961713Sgirish 
202444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
202552ccf843Smisaki 	    "<== nxge_txdma_fixup_hung_channel: stop done still not set!! "
202652ccf843Smisaki 	    "ring tdc %d passed channel",
202752ccf843Smisaki 	    ring_p->tdc, channel));
202844961713Sgirish 
202944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_hung_channel"));
203044961713Sgirish }
203144961713Sgirish 
203244961713Sgirish /*ARGSUSED*/
203344961713Sgirish void
203444961713Sgirish nxge_reclaim_rings(p_nxge_t nxgep)
203544961713Sgirish {
2036678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
2037678453a8Sspeer 	int tdc;
203844961713Sgirish 
2039678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_reclaim_rings"));
204044961713Sgirish 
2041678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
204244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
2043678453a8Sspeer 		    "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
204444961713Sgirish 		return;
204544961713Sgirish 	}
204644961713Sgirish 
2047678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
2048678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
2049678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
2050678453a8Sspeer 			if (ring) {
2051678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
2052678453a8Sspeer 				    "==> nxge_reclaim_rings: TDC %d", tdc));
2053678453a8Sspeer 				MUTEX_ENTER(&ring->lock);
2054678453a8Sspeer 				(void) nxge_txdma_reclaim(nxgep, ring, tdc);
2055678453a8Sspeer 				MUTEX_EXIT(&ring->lock);
2056*2d99c5d4SMichael Speer 
2057*2d99c5d4SMichael Speer 				nxge_txdma_freemsg_task(ring);
2058678453a8Sspeer 			}
2059678453a8Sspeer 		}
206044961713Sgirish 	}
206144961713Sgirish 
206244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_reclaim_rings"));
206344961713Sgirish }
206444961713Sgirish 
206544961713Sgirish void
206644961713Sgirish nxge_txdma_regs_dump_channels(p_nxge_t nxgep)
206744961713Sgirish {
2068678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
2069678453a8Sspeer 	npi_handle_t handle;
2070678453a8Sspeer 	int tdc;
207144961713Sgirish 
2072678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_regs_dump_channels"));
207344961713Sgirish 
207444961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
207544961713Sgirish 
2076678453a8Sspeer 	if (!isLDOMguest(nxgep)) {
2077678453a8Sspeer 		(void) npi_txdma_dump_fzc_regs(handle);
207844961713Sgirish 
2079678453a8Sspeer 		/* Dump TXC registers. */
2080678453a8Sspeer 		(void) npi_txc_dump_fzc_regs(handle);
2081678453a8Sspeer 		(void) npi_txc_dump_port_fzc_regs(handle, nxgep->function_num);
208244961713Sgirish 	}
208344961713Sgirish 
2084678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
208544961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
2086678453a8Sspeer 		    "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
208744961713Sgirish 		return;
208844961713Sgirish 	}
208944961713Sgirish 
2090678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
2091678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
2092678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
2093678453a8Sspeer 			if (ring) {
2094678453a8Sspeer 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
2095678453a8Sspeer 				    "==> nxge_txdma_regs_dump_channels: "
2096678453a8Sspeer 				    "TDC %d", tdc));
2097678453a8Sspeer 				(void) npi_txdma_dump_tdc_regs(handle, tdc);
2098678453a8Sspeer 
2099678453a8Sspeer 				/* Dump TXC registers, if able to. */
2100678453a8Sspeer 				if (!isLDOMguest(nxgep)) {
2101678453a8Sspeer 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
2102678453a8Sspeer 					    "==> nxge_txdma_regs_dump_channels:"
2103678453a8Sspeer 					    " FZC TDC %d", tdc));
2104678453a8Sspeer 					(void) npi_txc_dump_tdc_fzc_regs
2105678453a8Sspeer 					    (handle, tdc);
2106678453a8Sspeer 				}
2107678453a8Sspeer 				nxge_txdma_regs_dump(nxgep, tdc);
2108678453a8Sspeer 			}
2109678453a8Sspeer 		}
211044961713Sgirish 	}
211144961713Sgirish 
211244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_regs_dump"));
211344961713Sgirish }
211444961713Sgirish 
211544961713Sgirish void
211644961713Sgirish nxge_txdma_regs_dump(p_nxge_t nxgep, int channel)
211744961713Sgirish {
211844961713Sgirish 	npi_handle_t		handle;
211944961713Sgirish 	tx_ring_hdl_t 		hdl;
212044961713Sgirish 	tx_ring_kick_t 		kick;
212144961713Sgirish 	tx_cs_t 		cs;
212244961713Sgirish 	txc_control_t		control;
212344961713Sgirish 	uint32_t		bitmap = 0;
212444961713Sgirish 	uint32_t		burst = 0;
212544961713Sgirish 	uint32_t		bytes = 0;
212644961713Sgirish 	dma_log_page_t		cfg;
212744961713Sgirish 
212844961713Sgirish 	printf("\n\tfunc # %d tdc %d ",
212952ccf843Smisaki 	    nxgep->function_num, channel);
213044961713Sgirish 	cfg.page_num = 0;
213144961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
213244961713Sgirish 	(void) npi_txdma_log_page_get(handle, channel, &cfg);
213344961713Sgirish 	printf("\n\tlog page func %d valid page 0 %d",
213452ccf843Smisaki 	    cfg.func_num, cfg.valid);
213544961713Sgirish 	cfg.page_num = 1;
213644961713Sgirish 	(void) npi_txdma_log_page_get(handle, channel, &cfg);
213744961713Sgirish 	printf("\n\tlog page func %d valid page 1 %d",
213852ccf843Smisaki 	    cfg.func_num, cfg.valid);
213944961713Sgirish 
214044961713Sgirish 	(void) npi_txdma_ring_head_get(handle, channel, &hdl);
214144961713Sgirish 	(void) npi_txdma_desc_kick_reg_get(handle, channel, &kick);
214244961713Sgirish 	printf("\n\thead value is 0x%0llx",
214352ccf843Smisaki 	    (long long)hdl.value);
214444961713Sgirish 	printf("\n\thead index %d", hdl.bits.ldw.head);
214544961713Sgirish 	printf("\n\tkick value is 0x%0llx",
214652ccf843Smisaki 	    (long long)kick.value);
214744961713Sgirish 	printf("\n\ttail index %d\n", kick.bits.ldw.tail);
214844961713Sgirish 
214944961713Sgirish 	(void) npi_txdma_control_status(handle, OP_GET, channel, &cs);
215044961713Sgirish 	printf("\n\tControl statue is 0x%0llx", (long long)cs.value);
215144961713Sgirish 	printf("\n\tControl status RST state %d", cs.bits.ldw.rst);
215244961713Sgirish 
215344961713Sgirish 	(void) npi_txc_control(handle, OP_GET, &control);
215444961713Sgirish 	(void) npi_txc_port_dma_list_get(handle, nxgep->function_num, &bitmap);
215544961713Sgirish 	(void) npi_txc_dma_max_burst(handle, OP_GET, channel, &burst);
215644961713Sgirish 	(void) npi_txc_dma_bytes_transmitted(handle, channel, &bytes);
215744961713Sgirish 
215844961713Sgirish 	printf("\n\tTXC port control 0x%0llx",
215952ccf843Smisaki 	    (long long)control.value);
216044961713Sgirish 	printf("\n\tTXC port bitmap 0x%x", bitmap);
216144961713Sgirish 	printf("\n\tTXC max burst %d", burst);
216244961713Sgirish 	printf("\n\tTXC bytes xmt %d\n", bytes);
216344961713Sgirish 
216444961713Sgirish 	{
216544961713Sgirish 		ipp_status_t status;
216644961713Sgirish 
216744961713Sgirish 		(void) npi_ipp_get_status(handle, nxgep->function_num, &status);
2168adfcba55Sjoycey #if defined(__i386)
2169adfcba55Sjoycey 		printf("\n\tIPP status 0x%llux\n", (uint64_t)status.value);
2170adfcba55Sjoycey #else
217144961713Sgirish 		printf("\n\tIPP status 0x%lux\n", (uint64_t)status.value);
2172adfcba55Sjoycey #endif
217344961713Sgirish 	}
217444961713Sgirish }
217544961713Sgirish 
217644961713Sgirish /*
2177678453a8Sspeer  * nxge_tdc_hvio_setup
2178678453a8Sspeer  *
2179678453a8Sspeer  *	I'm not exactly sure what this code does.
2180678453a8Sspeer  *
2181678453a8Sspeer  * Arguments:
2182678453a8Sspeer  * 	nxgep
2183678453a8Sspeer  * 	channel	The channel to map.
2184678453a8Sspeer  *
2185678453a8Sspeer  * Notes:
2186678453a8Sspeer  *
2187678453a8Sspeer  * NPI/NXGE function calls:
2188678453a8Sspeer  *	na
2189678453a8Sspeer  *
2190678453a8Sspeer  * Context:
2191678453a8Sspeer  *	Service domain?
219244961713Sgirish  */
2193678453a8Sspeer #if defined(sun4v) && defined(NIU_LP_WORKAROUND)
2194678453a8Sspeer static void
2195678453a8Sspeer nxge_tdc_hvio_setup(
2196678453a8Sspeer 	nxge_t *nxgep, int channel)
219744961713Sgirish {
2198678453a8Sspeer 	nxge_dma_common_t	*data;
2199678453a8Sspeer 	nxge_dma_common_t	*control;
2200678453a8Sspeer 	tx_ring_t 		*ring;
2201678453a8Sspeer 
2202678453a8Sspeer 	ring = nxgep->tx_rings->rings[channel];
2203678453a8Sspeer 	data = nxgep->tx_buf_pool_p->dma_buf_pool_p[channel];
2204678453a8Sspeer 
2205678453a8Sspeer 	ring->hv_set = B_FALSE;
2206678453a8Sspeer 
2207678453a8Sspeer 	ring->hv_tx_buf_base_ioaddr_pp =
2208678453a8Sspeer 	    (uint64_t)data->orig_ioaddr_pp;
2209678453a8Sspeer 	ring->hv_tx_buf_ioaddr_size =
2210678453a8Sspeer 	    (uint64_t)data->orig_alength;
2211678453a8Sspeer 
2212678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: "
221352ccf843Smisaki 	    "hv data buf base io $%p size 0x%llx (%d) buf base io $%p "
221452ccf843Smisaki 	    "orig vatopa base io $%p orig_len 0x%llx (%d)",
221552ccf843Smisaki 	    ring->hv_tx_buf_base_ioaddr_pp,
221652ccf843Smisaki 	    ring->hv_tx_buf_ioaddr_size, ring->hv_tx_buf_ioaddr_size,
221752ccf843Smisaki 	    data->ioaddr_pp, data->orig_vatopa,
221852ccf843Smisaki 	    data->orig_alength, data->orig_alength));
2219678453a8Sspeer 
2220678453a8Sspeer 	control = nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel];
2221678453a8Sspeer 
2222678453a8Sspeer 	ring->hv_tx_cntl_base_ioaddr_pp =
2223678453a8Sspeer 	    (uint64_t)control->orig_ioaddr_pp;
2224678453a8Sspeer 	ring->hv_tx_cntl_ioaddr_size =
2225678453a8Sspeer 	    (uint64_t)control->orig_alength;
2226678453a8Sspeer 
2227678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: "
222852ccf843Smisaki 	    "hv cntl base io $%p orig ioaddr_pp ($%p) "
222952ccf843Smisaki 	    "orig vatopa ($%p) size 0x%llx (%d 0x%x)",
223052ccf843Smisaki 	    ring->hv_tx_cntl_base_ioaddr_pp,
223152ccf843Smisaki 	    control->orig_ioaddr_pp, control->orig_vatopa,
223252ccf843Smisaki 	    ring->hv_tx_cntl_ioaddr_size,
223352ccf843Smisaki 	    control->orig_alength, control->orig_alength));
2234678453a8Sspeer }
223544961713Sgirish #endif
223644961713Sgirish 
2237678453a8Sspeer static nxge_status_t
2238678453a8Sspeer nxge_map_txdma(p_nxge_t nxgep, int channel)
2239678453a8Sspeer {
2240678453a8Sspeer 	nxge_dma_common_t	**pData;
2241678453a8Sspeer 	nxge_dma_common_t	**pControl;
2242678453a8Sspeer 	tx_ring_t 		**pRing, *ring;
2243678453a8Sspeer 	tx_mbox_t		**mailbox;
2244678453a8Sspeer 	uint32_t		num_chunks;
2245678453a8Sspeer 
2246678453a8Sspeer 	nxge_status_t		status = NXGE_OK;
224744961713Sgirish 
2248678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma"));
224944961713Sgirish 
2250678453a8Sspeer 	if (!nxgep->tx_cntl_pool_p->buf_allocated) {
2251678453a8Sspeer 		if (nxge_alloc_tx_mem_pool(nxgep) != NXGE_OK) {
2252678453a8Sspeer 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2253678453a8Sspeer 			    "<== nxge_map_txdma: buf not allocated"));
2254678453a8Sspeer 			return (NXGE_ERROR);
2255678453a8Sspeer 		}
225644961713Sgirish 	}
225744961713Sgirish 
2258678453a8Sspeer 	if (nxge_alloc_txb(nxgep, channel) != NXGE_OK)
225944961713Sgirish 		return (NXGE_ERROR);
226044961713Sgirish 
2261678453a8Sspeer 	num_chunks = nxgep->tx_buf_pool_p->num_chunks[channel];
2262678453a8Sspeer 	pData = &nxgep->tx_buf_pool_p->dma_buf_pool_p[channel];
2263678453a8Sspeer 	pControl = &nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel];
2264678453a8Sspeer 	pRing = &nxgep->tx_rings->rings[channel];
2265678453a8Sspeer 	mailbox = &nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
226644961713Sgirish 
2267678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: "
226852ccf843Smisaki 	    "tx_rings $%p tx_desc_rings $%p",
226952ccf843Smisaki 	    nxgep->tx_rings, nxgep->tx_rings->rings));
227044961713Sgirish 
227144961713Sgirish 	/*
2272678453a8Sspeer 	 * Map descriptors from the buffer pools for <channel>.
227344961713Sgirish 	 */
227444961713Sgirish 
2275678453a8Sspeer 	/*
2276678453a8Sspeer 	 * Set up and prepare buffer blocks, descriptors
2277678453a8Sspeer 	 * and mailbox.
2278678453a8Sspeer 	 */
2279678453a8Sspeer 	status = nxge_map_txdma_channel(nxgep, channel,
2280678453a8Sspeer 	    pData, pRing, num_chunks, pControl, mailbox);
2281678453a8Sspeer 	if (status != NXGE_OK) {
2282678453a8Sspeer 		NXGE_ERROR_MSG((nxgep, MEM3_CTL,
228352ccf843Smisaki 		    "==> nxge_map_txdma(%d): nxge_map_txdma_channel() "
228452ccf843Smisaki 		    "returned 0x%x",
228552ccf843Smisaki 		    nxgep, channel, status));
2286678453a8Sspeer 		return (status);
228744961713Sgirish 	}
228844961713Sgirish 
2289678453a8Sspeer 	ring = *pRing;
229044961713Sgirish 
2291678453a8Sspeer 	ring->index = (uint16_t)channel;
2292678453a8Sspeer 	ring->tdc_stats = &nxgep->statsp->tdc_stats[channel];
229344961713Sgirish 
2294678453a8Sspeer #if defined(sun4v) && defined(NIU_LP_WORKAROUND)
2295678453a8Sspeer 	if (isLDOMguest(nxgep)) {
2296678453a8Sspeer 		(void) nxge_tdc_lp_conf(nxgep, channel);
2297678453a8Sspeer 	} else {
2298678453a8Sspeer 		nxge_tdc_hvio_setup(nxgep, channel);
229944961713Sgirish 	}
2300678453a8Sspeer #endif
230144961713Sgirish 
2302678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: "
2303678453a8Sspeer 	    "(status 0x%x channel %d)", status, channel));
230444961713Sgirish 
2305678453a8Sspeer 	return (status);
230644961713Sgirish }
230744961713Sgirish 
230844961713Sgirish static nxge_status_t
230944961713Sgirish nxge_map_txdma_channel(p_nxge_t nxgep, uint16_t channel,
231044961713Sgirish 	p_nxge_dma_common_t *dma_buf_p,
231144961713Sgirish 	p_tx_ring_t *tx_desc_p,
231244961713Sgirish 	uint32_t num_chunks,
231344961713Sgirish 	p_nxge_dma_common_t *dma_cntl_p,
231444961713Sgirish 	p_tx_mbox_t *tx_mbox_p)
231544961713Sgirish {
231644961713Sgirish 	int	status = NXGE_OK;
231744961713Sgirish 
231844961713Sgirish 	/*
231944961713Sgirish 	 * Set up and prepare buffer blocks, descriptors
232044961713Sgirish 	 * and mailbox.
232144961713Sgirish 	 */
2322678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL,
232352ccf843Smisaki 	    "==> nxge_map_txdma_channel (channel %d)", channel));
232444961713Sgirish 	/*
232544961713Sgirish 	 * Transmit buffer blocks
232644961713Sgirish 	 */
232744961713Sgirish 	status = nxge_map_txdma_channel_buf_ring(nxgep, channel,
232852ccf843Smisaki 	    dma_buf_p, tx_desc_p, num_chunks);
232944961713Sgirish 	if (status != NXGE_OK) {
233044961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
233152ccf843Smisaki 		    "==> nxge_map_txdma_channel (channel %d): "
233252ccf843Smisaki 		    "map buffer failed 0x%x", channel, status));
233344961713Sgirish 		goto nxge_map_txdma_channel_exit;
233444961713Sgirish 	}
233544961713Sgirish 
233644961713Sgirish 	/*
233744961713Sgirish 	 * Transmit block ring, and mailbox.
233844961713Sgirish 	 */
233944961713Sgirish 	nxge_map_txdma_channel_cfg_ring(nxgep, channel, dma_cntl_p, *tx_desc_p,
234052ccf843Smisaki 	    tx_mbox_p);
234144961713Sgirish 
234244961713Sgirish 	goto nxge_map_txdma_channel_exit;
234344961713Sgirish 
234444961713Sgirish nxge_map_txdma_channel_fail1:
2345678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL,
234652ccf843Smisaki 	    "==> nxge_map_txdma_channel: unmap buf"
234752ccf843Smisaki 	    "(status 0x%x channel %d)",
234852ccf843Smisaki 	    status, channel));
234944961713Sgirish 	nxge_unmap_txdma_channel_buf_ring(nxgep, *tx_desc_p);
235044961713Sgirish 
235144961713Sgirish nxge_map_txdma_channel_exit:
2352678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL,
235352ccf843Smisaki 	    "<== nxge_map_txdma_channel: "
235452ccf843Smisaki 	    "(status 0x%x channel %d)",
235552ccf843Smisaki 	    status, channel));
235644961713Sgirish 
235744961713Sgirish 	return (status);
235844961713Sgirish }
235944961713Sgirish 
236044961713Sgirish /*ARGSUSED*/
236144961713Sgirish static void
2362678453a8Sspeer nxge_unmap_txdma_channel(p_nxge_t nxgep, uint16_t channel)
236344961713Sgirish {
2364678453a8Sspeer 	tx_ring_t *ring;
2365678453a8Sspeer 	tx_mbox_t *mailbox;
2366678453a8Sspeer 
236744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
236852ccf843Smisaki 	    "==> nxge_unmap_txdma_channel (channel %d)", channel));
236944961713Sgirish 	/*
237044961713Sgirish 	 * unmap tx block ring, and mailbox.
237144961713Sgirish 	 */
2372678453a8Sspeer 	ring = nxgep->tx_rings->rings[channel];
2373678453a8Sspeer 	mailbox = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
2374678453a8Sspeer 
2375678453a8Sspeer 	(void) nxge_unmap_txdma_channel_cfg_ring(nxgep, ring, mailbox);
237644961713Sgirish 
237744961713Sgirish 	/* unmap buffer blocks */
2378678453a8Sspeer 	(void) nxge_unmap_txdma_channel_buf_ring(nxgep, ring);
2379678453a8Sspeer 
2380678453a8Sspeer 	nxge_free_txb(nxgep, channel);
238144961713Sgirish 
238244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_unmap_txdma_channel"));
238344961713Sgirish }
238444961713Sgirish 
2385678453a8Sspeer /*
2386678453a8Sspeer  * nxge_map_txdma_channel_cfg_ring
2387678453a8Sspeer  *
2388678453a8Sspeer  *	Map a TDC into our kernel space.
2389678453a8Sspeer  *	This function allocates all of the per-channel data structures.
2390678453a8Sspeer  *
2391678453a8Sspeer  * Arguments:
2392678453a8Sspeer  * 	nxgep
2393678453a8Sspeer  * 	dma_channel	The channel to map.
2394678453a8Sspeer  *	dma_cntl_p
2395678453a8Sspeer  *	tx_ring_p	dma_channel's transmit ring
2396678453a8Sspeer  *	tx_mbox_p	dma_channel's mailbox
2397678453a8Sspeer  *
2398678453a8Sspeer  * Notes:
2399678453a8Sspeer  *
2400678453a8Sspeer  * NPI/NXGE function calls:
2401678453a8Sspeer  *	nxge_setup_dma_common()
2402678453a8Sspeer  *
2403678453a8Sspeer  * Registers accessed:
2404678453a8Sspeer  *	none.
2405678453a8Sspeer  *
2406678453a8Sspeer  * Context:
2407678453a8Sspeer  *	Any domain
2408678453a8Sspeer  */
240944961713Sgirish /*ARGSUSED*/
241044961713Sgirish static void
241144961713Sgirish nxge_map_txdma_channel_cfg_ring(p_nxge_t nxgep, uint16_t dma_channel,
241244961713Sgirish 	p_nxge_dma_common_t *dma_cntl_p,
241344961713Sgirish 	p_tx_ring_t tx_ring_p,
241444961713Sgirish 	p_tx_mbox_t *tx_mbox_p)
241544961713Sgirish {
241644961713Sgirish 	p_tx_mbox_t 		mboxp;
241744961713Sgirish 	p_nxge_dma_common_t 	cntl_dmap;
241844961713Sgirish 	p_nxge_dma_common_t 	dmap;
241944961713Sgirish 	p_tx_rng_cfig_t		tx_ring_cfig_p;
242044961713Sgirish 	p_tx_ring_kick_t	tx_ring_kick_p;
242144961713Sgirish 	p_tx_cs_t		tx_cs_p;
242244961713Sgirish 	p_tx_dma_ent_msk_t	tx_evmask_p;
242344961713Sgirish 	p_txdma_mbh_t		mboxh_p;
242444961713Sgirish 	p_txdma_mbl_t		mboxl_p;
242544961713Sgirish 	uint64_t		tx_desc_len;
242644961713Sgirish 
242744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
242852ccf843Smisaki 	    "==> nxge_map_txdma_channel_cfg_ring"));
242944961713Sgirish 
243044961713Sgirish 	cntl_dmap = *dma_cntl_p;
243144961713Sgirish 
243244961713Sgirish 	dmap = (p_nxge_dma_common_t)&tx_ring_p->tdc_desc;
243344961713Sgirish 	nxge_setup_dma_common(dmap, cntl_dmap, tx_ring_p->tx_ring_size,
243452ccf843Smisaki 	    sizeof (tx_desc_t));
243544961713Sgirish 	/*
243644961713Sgirish 	 * Zero out transmit ring descriptors.
243744961713Sgirish 	 */
243844961713Sgirish 	bzero((caddr_t)dmap->kaddrp, dmap->alength);
243944961713Sgirish 	tx_ring_cfig_p = &(tx_ring_p->tx_ring_cfig);
244044961713Sgirish 	tx_ring_kick_p = &(tx_ring_p->tx_ring_kick);
244144961713Sgirish 	tx_cs_p = &(tx_ring_p->tx_cs);
244244961713Sgirish 	tx_evmask_p = &(tx_ring_p->tx_evmask);
244344961713Sgirish 	tx_ring_cfig_p->value = 0;
244444961713Sgirish 	tx_ring_kick_p->value = 0;
244544961713Sgirish 	tx_cs_p->value = 0;
244644961713Sgirish 	tx_evmask_p->value = 0;
244744961713Sgirish 
244844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
244952ccf843Smisaki 	    "==> nxge_map_txdma_channel_cfg_ring: channel %d des $%p",
245052ccf843Smisaki 	    dma_channel,
245152ccf843Smisaki 	    dmap->dma_cookie.dmac_laddress));
245244961713Sgirish 
245344961713Sgirish 	tx_ring_cfig_p->value = 0;
245444961713Sgirish 	tx_desc_len = (uint64_t)(tx_ring_p->tx_ring_size >> 3);
245544961713Sgirish 	tx_ring_cfig_p->value =
245652ccf843Smisaki 	    (dmap->dma_cookie.dmac_laddress & TX_RNG_CFIG_ADDR_MASK) |
245752ccf843Smisaki 	    (tx_desc_len << TX_RNG_CFIG_LEN_SHIFT);
245844961713Sgirish 
245944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
246052ccf843Smisaki 	    "==> nxge_map_txdma_channel_cfg_ring: channel %d cfg 0x%llx",
246152ccf843Smisaki 	    dma_channel,
246252ccf843Smisaki 	    tx_ring_cfig_p->value));
246344961713Sgirish 
246444961713Sgirish 	tx_cs_p->bits.ldw.rst = 1;
246544961713Sgirish 
246644961713Sgirish 	/* Map in mailbox */
246744961713Sgirish 	mboxp = (p_tx_mbox_t)
246852ccf843Smisaki 	    KMEM_ZALLOC(sizeof (tx_mbox_t), KM_SLEEP);
246944961713Sgirish 	dmap = (p_nxge_dma_common_t)&mboxp->tx_mbox;
247044961713Sgirish 	nxge_setup_dma_common(dmap, cntl_dmap, 1, sizeof (txdma_mailbox_t));
247144961713Sgirish 	mboxh_p = (p_txdma_mbh_t)&tx_ring_p->tx_mbox_mbh;
247244961713Sgirish 	mboxl_p = (p_txdma_mbl_t)&tx_ring_p->tx_mbox_mbl;
247344961713Sgirish 	mboxh_p->value = mboxl_p->value = 0;
247444961713Sgirish 
247544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
247652ccf843Smisaki 	    "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
247752ccf843Smisaki 	    dmap->dma_cookie.dmac_laddress));
247844961713Sgirish 
247944961713Sgirish 	mboxh_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress >>
248052ccf843Smisaki 	    TXDMA_MBH_ADDR_SHIFT) & TXDMA_MBH_MASK);
248144961713Sgirish 
248244961713Sgirish 	mboxl_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress &
248352ccf843Smisaki 	    TXDMA_MBL_MASK) >> TXDMA_MBL_SHIFT);
248444961713Sgirish 
248544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
248652ccf843Smisaki 	    "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
248752ccf843Smisaki 	    dmap->dma_cookie.dmac_laddress));
248844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
248952ccf843Smisaki 	    "==> nxge_map_txdma_channel_cfg_ring: hmbox $%p "
249052ccf843Smisaki 	    "mbox $%p",
249152ccf843Smisaki 	    mboxh_p->bits.ldw.mbaddr, mboxl_p->bits.ldw.mbaddr));
249244961713Sgirish 	tx_ring_p->page_valid.value = 0;
249344961713Sgirish 	tx_ring_p->page_mask_1.value = tx_ring_p->page_mask_2.value = 0;
249444961713Sgirish 	tx_ring_p->page_value_1.value = tx_ring_p->page_value_2.value = 0;
249544961713Sgirish 	tx_ring_p->page_reloc_1.value = tx_ring_p->page_reloc_2.value = 0;
249644961713Sgirish 	tx_ring_p->page_hdl.value = 0;
249744961713Sgirish 
249844961713Sgirish 	tx_ring_p->page_valid.bits.ldw.page0 = 1;
249944961713Sgirish 	tx_ring_p->page_valid.bits.ldw.page1 = 1;
250044961713Sgirish 
250144961713Sgirish 	tx_ring_p->max_burst.value = 0;
250244961713Sgirish 	tx_ring_p->max_burst.bits.ldw.dma_max_burst = TXC_DMA_MAX_BURST_DEFAULT;
250344961713Sgirish 
250444961713Sgirish 	*tx_mbox_p = mboxp;
250544961713Sgirish 
250644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
250752ccf843Smisaki 	    "<== nxge_map_txdma_channel_cfg_ring"));
250844961713Sgirish }
250944961713Sgirish 
251044961713Sgirish /*ARGSUSED*/
251144961713Sgirish static void
251244961713Sgirish nxge_unmap_txdma_channel_cfg_ring(p_nxge_t nxgep,
251344961713Sgirish 	p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p)
251444961713Sgirish {
251544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
251652ccf843Smisaki 	    "==> nxge_unmap_txdma_channel_cfg_ring: channel %d",
251752ccf843Smisaki 	    tx_ring_p->tdc));
251844961713Sgirish 
251944961713Sgirish 	KMEM_FREE(tx_mbox_p, sizeof (tx_mbox_t));
252044961713Sgirish 
252144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
252252ccf843Smisaki 	    "<== nxge_unmap_txdma_channel_cfg_ring"));
252344961713Sgirish }
252444961713Sgirish 
2525678453a8Sspeer /*
2526678453a8Sspeer  * nxge_map_txdma_channel_buf_ring
2527678453a8Sspeer  *
2528678453a8Sspeer  *
2529678453a8Sspeer  * Arguments:
2530678453a8Sspeer  * 	nxgep
2531678453a8Sspeer  * 	channel		The channel to map.
2532678453a8Sspeer  *	dma_buf_p
2533678453a8Sspeer  *	tx_desc_p	channel's descriptor ring
2534678453a8Sspeer  *	num_chunks
2535678453a8Sspeer  *
2536678453a8Sspeer  * Notes:
2537678453a8Sspeer  *
2538678453a8Sspeer  * NPI/NXGE function calls:
2539678453a8Sspeer  *	nxge_setup_dma_common()
2540678453a8Sspeer  *
2541678453a8Sspeer  * Registers accessed:
2542678453a8Sspeer  *	none.
2543678453a8Sspeer  *
2544678453a8Sspeer  * Context:
2545678453a8Sspeer  *	Any domain
2546678453a8Sspeer  */
254744961713Sgirish static nxge_status_t
254844961713Sgirish nxge_map_txdma_channel_buf_ring(p_nxge_t nxgep, uint16_t channel,
254944961713Sgirish 	p_nxge_dma_common_t *dma_buf_p,
255044961713Sgirish 	p_tx_ring_t *tx_desc_p, uint32_t num_chunks)
255144961713Sgirish {
255244961713Sgirish 	p_nxge_dma_common_t 	dma_bufp, tmp_bufp;
255344961713Sgirish 	p_nxge_dma_common_t 	dmap;
255444961713Sgirish 	nxge_os_dma_handle_t	tx_buf_dma_handle;
255544961713Sgirish 	p_tx_ring_t 		tx_ring_p;
255644961713Sgirish 	p_tx_msg_t 		tx_msg_ring;
255744961713Sgirish 	nxge_status_t		status = NXGE_OK;
255844961713Sgirish 	int			ddi_status = DDI_SUCCESS;
255944961713Sgirish 	int			i, j, index;
256044961713Sgirish 	uint32_t		size, bsize;
256144961713Sgirish 	uint32_t 		nblocks, nmsgs;
256244961713Sgirish 
256344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
256452ccf843Smisaki 	    "==> nxge_map_txdma_channel_buf_ring"));
256544961713Sgirish 
256644961713Sgirish 	dma_bufp = tmp_bufp = *dma_buf_p;
256744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
256844961713Sgirish 		" nxge_map_txdma_channel_buf_ring: channel %d to map %d "
256944961713Sgirish 		"chunks bufp $%p",
257052ccf843Smisaki 		    channel, num_chunks, dma_bufp));
257144961713Sgirish 
257244961713Sgirish 	nmsgs = 0;
257344961713Sgirish 	for (i = 0; i < num_chunks; i++, tmp_bufp++) {
257444961713Sgirish 		nmsgs += tmp_bufp->nblocks;
257544961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
257652ccf843Smisaki 		    "==> nxge_map_txdma_channel_buf_ring: channel %d "
257752ccf843Smisaki 		    "bufp $%p nblocks %d nmsgs %d",
257852ccf843Smisaki 		    channel, tmp_bufp, tmp_bufp->nblocks, nmsgs));
257944961713Sgirish 	}
258044961713Sgirish 	if (!nmsgs) {
258144961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
258252ccf843Smisaki 		    "<== nxge_map_txdma_channel_buf_ring: channel %d "
258352ccf843Smisaki 		    "no msg blocks",
258452ccf843Smisaki 		    channel));
258544961713Sgirish 		status = NXGE_ERROR;
258644961713Sgirish 		goto nxge_map_txdma_channel_buf_ring_exit;
258744961713Sgirish 	}
258844961713Sgirish 
258944961713Sgirish 	tx_ring_p = (p_tx_ring_t)
259052ccf843Smisaki 	    KMEM_ZALLOC(sizeof (tx_ring_t), KM_SLEEP);
259144961713Sgirish 	MUTEX_INIT(&tx_ring_p->lock, NULL, MUTEX_DRIVER,
259252ccf843Smisaki 	    (void *)nxgep->interrupt_cookie);
2593*2d99c5d4SMichael Speer 	MUTEX_INIT(&tx_ring_p->freelock, NULL, MUTEX_DRIVER,
2594*2d99c5d4SMichael Speer 	    (void *)nxgep->interrupt_cookie);
25951f8914d5Sml 
259622c0d73aSspeer 	(void) atomic_swap_32(&tx_ring_p->tx_ring_offline, NXGE_TX_RING_ONLINE);
25976895688eSspeer 	tx_ring_p->tx_ring_busy = B_FALSE;
25981f8914d5Sml 	tx_ring_p->nxgep = nxgep;
25991f8914d5Sml 	tx_ring_p->serial = nxge_serialize_create(nmsgs,
260052ccf843Smisaki 	    nxge_serial_tx, tx_ring_p);
260144961713Sgirish 	/*
260244961713Sgirish 	 * Allocate transmit message rings and handles for packets
260344961713Sgirish 	 * not to be copied to premapped buffers.
260444961713Sgirish 	 */
260544961713Sgirish 	size = nmsgs * sizeof (tx_msg_t);
260644961713Sgirish 	tx_msg_ring = KMEM_ZALLOC(size, KM_SLEEP);
260744961713Sgirish 	for (i = 0; i < nmsgs; i++) {
260844961713Sgirish 		ddi_status = ddi_dma_alloc_handle(nxgep->dip, &nxge_tx_dma_attr,
260952ccf843Smisaki 		    DDI_DMA_DONTWAIT, 0,
261052ccf843Smisaki 		    &tx_msg_ring[i].dma_handle);
261144961713Sgirish 		if (ddi_status != DDI_SUCCESS) {
261244961713Sgirish 			status |= NXGE_DDI_FAILED;
261344961713Sgirish 			break;
261444961713Sgirish 		}
261544961713Sgirish 	}
261644961713Sgirish 	if (i < nmsgs) {
261756d930aeSspeer 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
261856d930aeSspeer 		    "Allocate handles failed."));
261944961713Sgirish 		goto nxge_map_txdma_channel_buf_ring_fail1;
262044961713Sgirish 	}
262144961713Sgirish 
262244961713Sgirish 	tx_ring_p->tdc = channel;
262344961713Sgirish 	tx_ring_p->tx_msg_ring = tx_msg_ring;
262444961713Sgirish 	tx_ring_p->tx_ring_size = nmsgs;
262544961713Sgirish 	tx_ring_p->num_chunks = num_chunks;
262644961713Sgirish 	if (!nxge_tx_intr_thres) {
262744961713Sgirish 		nxge_tx_intr_thres = tx_ring_p->tx_ring_size/4;
262844961713Sgirish 	}
262944961713Sgirish 	tx_ring_p->tx_wrap_mask = tx_ring_p->tx_ring_size - 1;
263044961713Sgirish 	tx_ring_p->rd_index = 0;
263144961713Sgirish 	tx_ring_p->wr_index = 0;
263244961713Sgirish 	tx_ring_p->ring_head.value = 0;
263344961713Sgirish 	tx_ring_p->ring_kick_tail.value = 0;
263444961713Sgirish 	tx_ring_p->descs_pending = 0;
263544961713Sgirish 
263644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
263752ccf843Smisaki 	    "==> nxge_map_txdma_channel_buf_ring: channel %d "
263852ccf843Smisaki 	    "actual tx desc max %d nmsgs %d "
263952ccf843Smisaki 	    "(config nxge_tx_ring_size %d)",
264052ccf843Smisaki 	    channel, tx_ring_p->tx_ring_size, nmsgs,
264152ccf843Smisaki 	    nxge_tx_ring_size));
264244961713Sgirish 
264344961713Sgirish 	/*
264444961713Sgirish 	 * Map in buffers from the buffer pool.
264544961713Sgirish 	 */
264644961713Sgirish 	index = 0;
264744961713Sgirish 	bsize = dma_bufp->block_size;
264844961713Sgirish 
264944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel_buf_ring: "
265052ccf843Smisaki 	    "dma_bufp $%p tx_rng_p $%p "
265152ccf843Smisaki 	    "tx_msg_rng_p $%p bsize %d",
265252ccf843Smisaki 	    dma_bufp, tx_ring_p, tx_msg_ring, bsize));
265344961713Sgirish 
265444961713Sgirish 	tx_buf_dma_handle = dma_bufp->dma_handle;
265544961713Sgirish 	for (i = 0; i < num_chunks; i++, dma_bufp++) {
265644961713Sgirish 		bsize = dma_bufp->block_size;
265744961713Sgirish 		nblocks = dma_bufp->nblocks;
265844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
265952ccf843Smisaki 		    "==> nxge_map_txdma_channel_buf_ring: dma chunk %d "
266052ccf843Smisaki 		    "size %d dma_bufp $%p",
266152ccf843Smisaki 		    i, sizeof (nxge_dma_common_t), dma_bufp));
266244961713Sgirish 
266344961713Sgirish 		for (j = 0; j < nblocks; j++) {
266444961713Sgirish 			tx_msg_ring[index].buf_dma_handle = tx_buf_dma_handle;
2665*2d99c5d4SMichael Speer 			tx_msg_ring[index].nextp = NULL;
266644961713Sgirish 			dmap = &tx_msg_ring[index++].buf_dma;
266744961713Sgirish #ifdef TX_MEM_DEBUG
266844961713Sgirish 			NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
266952ccf843Smisaki 			    "==> nxge_map_txdma_channel_buf_ring: j %d"
267052ccf843Smisaki 			    "dmap $%p", i, dmap));
267144961713Sgirish #endif
267244961713Sgirish 			nxge_setup_dma_common(dmap, dma_bufp, 1,
267352ccf843Smisaki 			    bsize);
267444961713Sgirish 		}
267544961713Sgirish 	}
267644961713Sgirish 
267744961713Sgirish 	if (i < num_chunks) {
267856d930aeSspeer 		status = NXGE_ERROR;
267944961713Sgirish 		goto nxge_map_txdma_channel_buf_ring_fail1;
268044961713Sgirish 	}
268144961713Sgirish 
268244961713Sgirish 	*tx_desc_p = tx_ring_p;
268344961713Sgirish 
268444961713Sgirish 	goto nxge_map_txdma_channel_buf_ring_exit;
268544961713Sgirish 
268644961713Sgirish nxge_map_txdma_channel_buf_ring_fail1:
26871f8914d5Sml 	if (tx_ring_p->serial) {
26881f8914d5Sml 		nxge_serialize_destroy(tx_ring_p->serial);
26891f8914d5Sml 		tx_ring_p->serial = NULL;
26901f8914d5Sml 	}
26911f8914d5Sml 
269244961713Sgirish 	index--;
269344961713Sgirish 	for (; index >= 0; index--) {
269456d930aeSspeer 		if (tx_msg_ring[index].dma_handle != NULL) {
269556d930aeSspeer 			ddi_dma_free_handle(&tx_msg_ring[index].dma_handle);
269644961713Sgirish 		}
269744961713Sgirish 	}
2698*2d99c5d4SMichael Speer 
2699*2d99c5d4SMichael Speer 	MUTEX_DESTROY(&tx_ring_p->freelock);
270044961713Sgirish 	MUTEX_DESTROY(&tx_ring_p->lock);
270156d930aeSspeer 	KMEM_FREE(tx_msg_ring, size);
270244961713Sgirish 	KMEM_FREE(tx_ring_p, sizeof (tx_ring_t));
270344961713Sgirish 
270456d930aeSspeer 	status = NXGE_ERROR;
270556d930aeSspeer 
270644961713Sgirish nxge_map_txdma_channel_buf_ring_exit:
270744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
270852ccf843Smisaki 	    "<== nxge_map_txdma_channel_buf_ring status 0x%x", status));
270944961713Sgirish 
271044961713Sgirish 	return (status);
271144961713Sgirish }
271244961713Sgirish 
271344961713Sgirish /*ARGSUSED*/
271444961713Sgirish static void
271544961713Sgirish nxge_unmap_txdma_channel_buf_ring(p_nxge_t nxgep, p_tx_ring_t tx_ring_p)
271644961713Sgirish {
271744961713Sgirish 	p_tx_msg_t 		tx_msg_ring;
271844961713Sgirish 	p_tx_msg_t 		tx_msg_p;
271944961713Sgirish 	int			i;
272044961713Sgirish 
272144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
272252ccf843Smisaki 	    "==> nxge_unmap_txdma_channel_buf_ring"));
272344961713Sgirish 	if (tx_ring_p == NULL) {
272444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
272552ccf843Smisaki 		    "<== nxge_unmap_txdma_channel_buf_ring: NULL ringp"));
272644961713Sgirish 		return;
272744961713Sgirish 	}
272844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
272952ccf843Smisaki 	    "==> nxge_unmap_txdma_channel_buf_ring: channel %d",
273052ccf843Smisaki 	    tx_ring_p->tdc));
273144961713Sgirish 
273244961713Sgirish 	tx_msg_ring = tx_ring_p->tx_msg_ring;
2733678453a8Sspeer 
2734678453a8Sspeer 	/*
2735678453a8Sspeer 	 * Since the serialization thread, timer thread and
2736678453a8Sspeer 	 * interrupt thread can all call the transmit reclaim,
2737678453a8Sspeer 	 * the unmapping function needs to acquire the lock
2738678453a8Sspeer 	 * to free those buffers which were transmitted
2739678453a8Sspeer 	 * by the hardware already.
2740678453a8Sspeer 	 */
2741678453a8Sspeer 	MUTEX_ENTER(&tx_ring_p->lock);
2742678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
2743678453a8Sspeer 	    "==> nxge_unmap_txdma_channel_buf_ring (reclaim): "
2744678453a8Sspeer 	    "channel %d",
2745678453a8Sspeer 	    tx_ring_p->tdc));
2746678453a8Sspeer 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
2747678453a8Sspeer 
274844961713Sgirish 	for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
274944961713Sgirish 		tx_msg_p = &tx_msg_ring[i];
275044961713Sgirish 		if (tx_msg_p->tx_message != NULL) {
275144961713Sgirish 			freemsg(tx_msg_p->tx_message);
275244961713Sgirish 			tx_msg_p->tx_message = NULL;
275344961713Sgirish 		}
275444961713Sgirish 	}
275544961713Sgirish 
275644961713Sgirish 	for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
275744961713Sgirish 		if (tx_msg_ring[i].dma_handle != NULL) {
275844961713Sgirish 			ddi_dma_free_handle(&tx_msg_ring[i].dma_handle);
275944961713Sgirish 		}
2760678453a8Sspeer 		tx_msg_ring[i].dma_handle = NULL;
276144961713Sgirish 	}
276244961713Sgirish 
2763678453a8Sspeer 	MUTEX_EXIT(&tx_ring_p->lock);
2764678453a8Sspeer 
27651f8914d5Sml 	if (tx_ring_p->serial) {
27661f8914d5Sml 		nxge_serialize_destroy(tx_ring_p->serial);
27671f8914d5Sml 		tx_ring_p->serial = NULL;
27681f8914d5Sml 	}
27691f8914d5Sml 
2770*2d99c5d4SMichael Speer 	MUTEX_DESTROY(&tx_ring_p->freelock);
277144961713Sgirish 	MUTEX_DESTROY(&tx_ring_p->lock);
277244961713Sgirish 	KMEM_FREE(tx_msg_ring, sizeof (tx_msg_t) * tx_ring_p->tx_ring_size);
277344961713Sgirish 	KMEM_FREE(tx_ring_p, sizeof (tx_ring_t));
277444961713Sgirish 
277544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
277652ccf843Smisaki 	    "<== nxge_unmap_txdma_channel_buf_ring"));
277744961713Sgirish }
277844961713Sgirish 
277944961713Sgirish static nxge_status_t
2780678453a8Sspeer nxge_txdma_hw_start(p_nxge_t nxgep, int channel)
278144961713Sgirish {
278244961713Sgirish 	p_tx_rings_t 		tx_rings;
278344961713Sgirish 	p_tx_ring_t 		*tx_desc_rings;
278444961713Sgirish 	p_tx_mbox_areas_t 	tx_mbox_areas_p;
278544961713Sgirish 	p_tx_mbox_t		*tx_mbox_p;
278644961713Sgirish 	nxge_status_t		status = NXGE_OK;
278744961713Sgirish 
278844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start"));
278944961713Sgirish 
279044961713Sgirish 	tx_rings = nxgep->tx_rings;
279144961713Sgirish 	if (tx_rings == NULL) {
279244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
279352ccf843Smisaki 		    "<== nxge_txdma_hw_start: NULL ring pointer"));
279444961713Sgirish 		return (NXGE_ERROR);
279544961713Sgirish 	}
279644961713Sgirish 	tx_desc_rings = tx_rings->rings;
279744961713Sgirish 	if (tx_desc_rings == NULL) {
279844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
279952ccf843Smisaki 		    "<== nxge_txdma_hw_start: NULL ring pointers"));
280044961713Sgirish 		return (NXGE_ERROR);
280144961713Sgirish 	}
280244961713Sgirish 
2803678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
2804678453a8Sspeer 	    "tx_rings $%p tx_desc_rings $%p", tx_rings, tx_desc_rings));
280544961713Sgirish 
280644961713Sgirish 	tx_mbox_areas_p = nxgep->tx_mbox_areas_p;
280744961713Sgirish 	tx_mbox_p = tx_mbox_areas_p->txmbox_areas_p;
280844961713Sgirish 
2809678453a8Sspeer 	status = nxge_txdma_start_channel(nxgep, channel,
2810678453a8Sspeer 	    (p_tx_ring_t)tx_desc_rings[channel],
2811678453a8Sspeer 	    (p_tx_mbox_t)tx_mbox_p[channel]);
2812678453a8Sspeer 	if (status != NXGE_OK) {
2813678453a8Sspeer 		goto nxge_txdma_hw_start_fail1;
281444961713Sgirish 	}
281544961713Sgirish 
281644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
281752ccf843Smisaki 	    "tx_rings $%p rings $%p",
281852ccf843Smisaki 	    nxgep->tx_rings, nxgep->tx_rings->rings));
281944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
282052ccf843Smisaki 	    "tx_rings $%p tx_desc_rings $%p",
282152ccf843Smisaki 	    nxgep->tx_rings, tx_desc_rings));
282244961713Sgirish 
282344961713Sgirish 	goto nxge_txdma_hw_start_exit;
282444961713Sgirish 
282544961713Sgirish nxge_txdma_hw_start_fail1:
282644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
282752ccf843Smisaki 	    "==> nxge_txdma_hw_start: disable "
282852ccf843Smisaki 	    "(status 0x%x channel %d)", status, channel));
282944961713Sgirish 
283044961713Sgirish nxge_txdma_hw_start_exit:
283144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
283252ccf843Smisaki 	    "==> nxge_txdma_hw_start: (status 0x%x)", status));
283344961713Sgirish 
283444961713Sgirish 	return (status);
283544961713Sgirish }
283644961713Sgirish 
2837678453a8Sspeer /*
2838678453a8Sspeer  * nxge_txdma_start_channel
2839678453a8Sspeer  *
2840678453a8Sspeer  *	Start a TDC.
2841678453a8Sspeer  *
2842678453a8Sspeer  * Arguments:
2843678453a8Sspeer  * 	nxgep
2844678453a8Sspeer  * 	channel		The channel to start.
2845678453a8Sspeer  * 	tx_ring_p	channel's transmit descriptor ring.
2846678453a8Sspeer  * 	tx_mbox_p	channel' smailbox.
2847678453a8Sspeer  *
2848678453a8Sspeer  * Notes:
2849678453a8Sspeer  *
2850678453a8Sspeer  * NPI/NXGE function calls:
2851678453a8Sspeer  *	nxge_reset_txdma_channel()
2852678453a8Sspeer  *	nxge_init_txdma_channel_event_mask()
2853678453a8Sspeer  *	nxge_enable_txdma_channel()
2854678453a8Sspeer  *
2855678453a8Sspeer  * Registers accessed:
2856678453a8Sspeer  *	none directly (see functions above).
2857678453a8Sspeer  *
2858678453a8Sspeer  * Context:
2859678453a8Sspeer  *	Any domain
2860678453a8Sspeer  */
286144961713Sgirish static nxge_status_t
286244961713Sgirish nxge_txdma_start_channel(p_nxge_t nxgep, uint16_t channel,
286344961713Sgirish     p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p)
286444961713Sgirish 
286544961713Sgirish {
286644961713Sgirish 	nxge_status_t		status = NXGE_OK;
286744961713Sgirish 
286844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
286944961713Sgirish 		"==> nxge_txdma_start_channel (channel %d)", channel));
287044961713Sgirish 	/*
287144961713Sgirish 	 * TXDMA/TXC must be in stopped state.
287244961713Sgirish 	 */
287344961713Sgirish 	(void) nxge_txdma_stop_inj_err(nxgep, channel);
287444961713Sgirish 
287544961713Sgirish 	/*
287644961713Sgirish 	 * Reset TXDMA channel
287744961713Sgirish 	 */
287844961713Sgirish 	tx_ring_p->tx_cs.value = 0;
287944961713Sgirish 	tx_ring_p->tx_cs.bits.ldw.rst = 1;
288044961713Sgirish 	status = nxge_reset_txdma_channel(nxgep, channel,
288144961713Sgirish 			tx_ring_p->tx_cs.value);
288244961713Sgirish 	if (status != NXGE_OK) {
288344961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
288444961713Sgirish 			"==> nxge_txdma_start_channel (channel %d)"
288544961713Sgirish 			" reset channel failed 0x%x", channel, status));
288644961713Sgirish 		goto nxge_txdma_start_channel_exit;
288744961713Sgirish 	}
288844961713Sgirish 
288944961713Sgirish 	/*
289044961713Sgirish 	 * Initialize the TXDMA channel specific FZC control
289144961713Sgirish 	 * configurations. These FZC registers are pertaining
289244961713Sgirish 	 * to each TX channel (i.e. logical pages).
289344961713Sgirish 	 */
2894678453a8Sspeer 	if (!isLDOMguest(nxgep)) {
2895678453a8Sspeer 		status = nxge_init_fzc_txdma_channel(nxgep, channel,
2896678453a8Sspeer 		    tx_ring_p, tx_mbox_p);
2897678453a8Sspeer 		if (status != NXGE_OK) {
2898678453a8Sspeer 			goto nxge_txdma_start_channel_exit;
2899678453a8Sspeer 		}
290044961713Sgirish 	}
290144961713Sgirish 
290244961713Sgirish 	/*
290344961713Sgirish 	 * Initialize the event masks.
290444961713Sgirish 	 */
290544961713Sgirish 	tx_ring_p->tx_evmask.value = 0;
290644961713Sgirish 	status = nxge_init_txdma_channel_event_mask(nxgep,
2907678453a8Sspeer 	    channel, &tx_ring_p->tx_evmask);
290844961713Sgirish 	if (status != NXGE_OK) {
290944961713Sgirish 		goto nxge_txdma_start_channel_exit;
291044961713Sgirish 	}
291144961713Sgirish 
291244961713Sgirish 	/*
291344961713Sgirish 	 * Load TXDMA descriptors, buffers, mailbox,
291444961713Sgirish 	 * initialise the DMA channels and
291544961713Sgirish 	 * enable each DMA channel.
291644961713Sgirish 	 */
291744961713Sgirish 	status = nxge_enable_txdma_channel(nxgep, channel,
291844961713Sgirish 			tx_ring_p, tx_mbox_p);
291944961713Sgirish 	if (status != NXGE_OK) {
292044961713Sgirish 		goto nxge_txdma_start_channel_exit;
292144961713Sgirish 	}
292244961713Sgirish 
292344961713Sgirish nxge_txdma_start_channel_exit:
292444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_start_channel"));
292544961713Sgirish 
292644961713Sgirish 	return (status);
292744961713Sgirish }
292844961713Sgirish 
2929678453a8Sspeer /*
2930678453a8Sspeer  * nxge_txdma_stop_channel
2931678453a8Sspeer  *
2932678453a8Sspeer  *	Stop a TDC.
2933678453a8Sspeer  *
2934678453a8Sspeer  * Arguments:
2935678453a8Sspeer  * 	nxgep
2936678453a8Sspeer  * 	channel		The channel to stop.
2937678453a8Sspeer  * 	tx_ring_p	channel's transmit descriptor ring.
2938678453a8Sspeer  * 	tx_mbox_p	channel' smailbox.
2939678453a8Sspeer  *
2940678453a8Sspeer  * Notes:
2941678453a8Sspeer  *
2942678453a8Sspeer  * NPI/NXGE function calls:
2943678453a8Sspeer  *	nxge_txdma_stop_inj_err()
2944678453a8Sspeer  *	nxge_reset_txdma_channel()
2945678453a8Sspeer  *	nxge_init_txdma_channel_event_mask()
2946678453a8Sspeer  *	nxge_init_txdma_channel_cntl_stat()
2947678453a8Sspeer  *	nxge_disable_txdma_channel()
2948678453a8Sspeer  *
2949678453a8Sspeer  * Registers accessed:
2950678453a8Sspeer  *	none directly (see functions above).
2951678453a8Sspeer  *
2952678453a8Sspeer  * Context:
2953678453a8Sspeer  *	Any domain
2954678453a8Sspeer  */
295544961713Sgirish /*ARGSUSED*/
295644961713Sgirish static nxge_status_t
2957678453a8Sspeer nxge_txdma_stop_channel(p_nxge_t nxgep, uint16_t channel)
295844961713Sgirish {
2959678453a8Sspeer 	p_tx_ring_t tx_ring_p;
2960678453a8Sspeer 	int status = NXGE_OK;
296144961713Sgirish 
296244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
296352ccf843Smisaki 	    "==> nxge_txdma_stop_channel: channel %d", channel));
296444961713Sgirish 
296544961713Sgirish 	/*
296644961713Sgirish 	 * Stop (disable) TXDMA and TXC (if stop bit is set
296744961713Sgirish 	 * and STOP_N_GO bit not set, the TXDMA reset state will
296844961713Sgirish 	 * not be set if reset TXDMA.
296944961713Sgirish 	 */
297044961713Sgirish 	(void) nxge_txdma_stop_inj_err(nxgep, channel);
297144961713Sgirish 
2972678453a8Sspeer 	tx_ring_p = nxgep->tx_rings->rings[channel];
2973678453a8Sspeer 
297444961713Sgirish 	/*
297544961713Sgirish 	 * Reset TXDMA channel
297644961713Sgirish 	 */
297744961713Sgirish 	tx_ring_p->tx_cs.value = 0;
297844961713Sgirish 	tx_ring_p->tx_cs.bits.ldw.rst = 1;
297944961713Sgirish 	status = nxge_reset_txdma_channel(nxgep, channel,
298052ccf843Smisaki 	    tx_ring_p->tx_cs.value);
298144961713Sgirish 	if (status != NXGE_OK) {
298244961713Sgirish 		goto nxge_txdma_stop_channel_exit;
298344961713Sgirish 	}
298444961713Sgirish 
298544961713Sgirish #ifdef HARDWARE_REQUIRED
298644961713Sgirish 	/* Set up the interrupt event masks. */
298744961713Sgirish 	tx_ring_p->tx_evmask.value = 0;
298844961713Sgirish 	status = nxge_init_txdma_channel_event_mask(nxgep,
298952ccf843Smisaki 	    channel, &tx_ring_p->tx_evmask);
299044961713Sgirish 	if (status != NXGE_OK) {
299144961713Sgirish 		goto nxge_txdma_stop_channel_exit;
299244961713Sgirish 	}
299344961713Sgirish 
299444961713Sgirish 	/* Initialize the DMA control and status register */
299544961713Sgirish 	tx_ring_p->tx_cs.value = TX_ENT_MSK_MK_ALL;
299644961713Sgirish 	status = nxge_init_txdma_channel_cntl_stat(nxgep, channel,
299752ccf843Smisaki 	    tx_ring_p->tx_cs.value);
299844961713Sgirish 	if (status != NXGE_OK) {
299944961713Sgirish 		goto nxge_txdma_stop_channel_exit;
300044961713Sgirish 	}
300144961713Sgirish 
3002678453a8Sspeer 	tx_mbox_p = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
3003678453a8Sspeer 
300444961713Sgirish 	/* Disable channel */
300544961713Sgirish 	status = nxge_disable_txdma_channel(nxgep, channel,
3006678453a8Sspeer 	    tx_ring_p, tx_mbox_p);
300744961713Sgirish 	if (status != NXGE_OK) {
300844961713Sgirish 		goto nxge_txdma_start_channel_exit;
300944961713Sgirish 	}
301044961713Sgirish 
301144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
301252ccf843Smisaki 	    "==> nxge_txdma_stop_channel: event done"));
301344961713Sgirish 
301444961713Sgirish #endif
301544961713Sgirish 
301644961713Sgirish nxge_txdma_stop_channel_exit:
301744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_stop_channel"));
301844961713Sgirish 	return (status);
301944961713Sgirish }
302044961713Sgirish 
3021678453a8Sspeer /*
3022678453a8Sspeer  * nxge_txdma_get_ring
3023678453a8Sspeer  *
3024678453a8Sspeer  *	Get the ring for a TDC.
3025678453a8Sspeer  *
3026678453a8Sspeer  * Arguments:
3027678453a8Sspeer  * 	nxgep
3028678453a8Sspeer  * 	channel
3029678453a8Sspeer  *
3030678453a8Sspeer  * Notes:
3031678453a8Sspeer  *
3032678453a8Sspeer  * NPI/NXGE function calls:
3033678453a8Sspeer  *
3034678453a8Sspeer  * Registers accessed:
3035678453a8Sspeer  *
3036678453a8Sspeer  * Context:
3037678453a8Sspeer  *	Any domain
3038678453a8Sspeer  */
303944961713Sgirish static p_tx_ring_t
304044961713Sgirish nxge_txdma_get_ring(p_nxge_t nxgep, uint16_t channel)
304144961713Sgirish {
3042678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
3043678453a8Sspeer 	int tdc;
304444961713Sgirish 
304544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_ring"));
304644961713Sgirish 
3047678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
304844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3049678453a8Sspeer 		    "<== nxge_txdma_get_ring: NULL ring pointer(s)"));
3050678453a8Sspeer 		goto return_null;
3051678453a8Sspeer 	}
3052678453a8Sspeer 
3053678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3054678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3055678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3056678453a8Sspeer 			if (ring) {
3057678453a8Sspeer 				if (channel == ring->tdc) {
3058678453a8Sspeer 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
3059678453a8Sspeer 					    "<== nxge_txdma_get_ring: "
3060678453a8Sspeer 					    "tdc %d ring $%p", tdc, ring));
3061678453a8Sspeer 					return (ring);
3062678453a8Sspeer 				}
3063678453a8Sspeer 			}
306444961713Sgirish 		}
306544961713Sgirish 	}
306644961713Sgirish 
3067678453a8Sspeer return_null:
3068678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_ring: "
306952ccf843Smisaki 	    "ring not found"));
3070678453a8Sspeer 
307144961713Sgirish 	return (NULL);
307244961713Sgirish }
307344961713Sgirish 
3074678453a8Sspeer /*
3075678453a8Sspeer  * nxge_txdma_get_mbox
3076678453a8Sspeer  *
3077678453a8Sspeer  *	Get the mailbox for a TDC.
3078678453a8Sspeer  *
3079678453a8Sspeer  * Arguments:
3080678453a8Sspeer  * 	nxgep
3081678453a8Sspeer  * 	channel
3082678453a8Sspeer  *
3083678453a8Sspeer  * Notes:
3084678453a8Sspeer  *
3085678453a8Sspeer  * NPI/NXGE function calls:
3086678453a8Sspeer  *
3087678453a8Sspeer  * Registers accessed:
3088678453a8Sspeer  *
3089678453a8Sspeer  * Context:
3090678453a8Sspeer  *	Any domain
3091678453a8Sspeer  */
309244961713Sgirish static p_tx_mbox_t
309344961713Sgirish nxge_txdma_get_mbox(p_nxge_t nxgep, uint16_t channel)
309444961713Sgirish {
3095678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
3096678453a8Sspeer 	int tdc;
309744961713Sgirish 
309844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_mbox"));
309944961713Sgirish 
3100678453a8Sspeer 	if (nxgep->tx_mbox_areas_p == 0 ||
3101678453a8Sspeer 	    nxgep->tx_mbox_areas_p->txmbox_areas_p == 0) {
3102678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3103678453a8Sspeer 		    "<== nxge_txdma_get_mbox: NULL mailbox pointer(s)"));
3104678453a8Sspeer 		goto return_null;
310544961713Sgirish 	}
310644961713Sgirish 
3107678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
3108678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3109678453a8Sspeer 		    "<== nxge_txdma_get_mbox: NULL ring pointer(s)"));
3110678453a8Sspeer 		goto return_null;
3111678453a8Sspeer 	}
3112678453a8Sspeer 
3113678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3114678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3115678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3116678453a8Sspeer 			if (ring) {
3117678453a8Sspeer 				if (channel == ring->tdc) {
3118678453a8Sspeer 					tx_mbox_t *mailbox = nxgep->
3119678453a8Sspeer 					    tx_mbox_areas_p->
3120678453a8Sspeer 					    txmbox_areas_p[tdc];
3121678453a8Sspeer 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
3122678453a8Sspeer 					    "<== nxge_txdma_get_mbox: tdc %d "
3123678453a8Sspeer 					    "ring $%p", tdc, mailbox));
3124678453a8Sspeer 					return (mailbox);
3125678453a8Sspeer 				}
3126678453a8Sspeer 			}
312744961713Sgirish 		}
312844961713Sgirish 	}
312944961713Sgirish 
3130678453a8Sspeer return_null:
3131678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_mbox: "
313252ccf843Smisaki 	    "mailbox not found"));
3133678453a8Sspeer 
313444961713Sgirish 	return (NULL);
313544961713Sgirish }
313644961713Sgirish 
3137678453a8Sspeer /*
3138678453a8Sspeer  * nxge_tx_err_evnts
3139678453a8Sspeer  *
3140678453a8Sspeer  *	Recover a TDC.
3141678453a8Sspeer  *
3142678453a8Sspeer  * Arguments:
3143678453a8Sspeer  * 	nxgep
3144678453a8Sspeer  * 	index	The index to the TDC ring.
3145678453a8Sspeer  * 	ldvp	Used to get the channel number ONLY.
3146678453a8Sspeer  * 	cs	A copy of the bits from TX_CS.
3147678453a8Sspeer  *
3148678453a8Sspeer  * Notes:
3149678453a8Sspeer  *	Calling tree:
3150678453a8Sspeer  *	 nxge_tx_intr()
3151678453a8Sspeer  *
3152678453a8Sspeer  * NPI/NXGE function calls:
3153678453a8Sspeer  *	npi_txdma_ring_error_get()
3154678453a8Sspeer  *	npi_txdma_inj_par_error_get()
3155678453a8Sspeer  *	nxge_txdma_fatal_err_recover()
3156678453a8Sspeer  *
3157678453a8Sspeer  * Registers accessed:
3158678453a8Sspeer  *	TX_RNG_ERR_LOGH	DMC+0x40048 Transmit Ring Error Log High
3159678453a8Sspeer  *	TX_RNG_ERR_LOGL DMC+0x40050 Transmit Ring Error Log Low
3160678453a8Sspeer  *	TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error
3161678453a8Sspeer  *
3162678453a8Sspeer  * Context:
3163678453a8Sspeer  *	Any domain	XXX Remove code which accesses TDMC_INJ_PAR_ERR.
3164678453a8Sspeer  */
316544961713Sgirish /*ARGSUSED*/
316644961713Sgirish static nxge_status_t
316744961713Sgirish nxge_tx_err_evnts(p_nxge_t nxgep, uint_t index, p_nxge_ldv_t ldvp, tx_cs_t cs)
316844961713Sgirish {
316944961713Sgirish 	npi_handle_t		handle;
317044961713Sgirish 	npi_status_t		rs;
317144961713Sgirish 	uint8_t			channel;
317244961713Sgirish 	p_tx_ring_t 		*tx_rings;
317344961713Sgirish 	p_tx_ring_t 		tx_ring_p;
317444961713Sgirish 	p_nxge_tx_ring_stats_t	tdc_stats;
317544961713Sgirish 	boolean_t		txchan_fatal = B_FALSE;
317644961713Sgirish 	nxge_status_t		status = NXGE_OK;
317744961713Sgirish 	tdmc_inj_par_err_t	par_err;
317844961713Sgirish 	uint32_t		value;
317944961713Sgirish 
3180678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX2_CTL, "==> nxge_tx_err_evnts"));
318144961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
318244961713Sgirish 	channel = ldvp->channel;
318344961713Sgirish 
318444961713Sgirish 	tx_rings = nxgep->tx_rings->rings;
318544961713Sgirish 	tx_ring_p = tx_rings[index];
318644961713Sgirish 	tdc_stats = tx_ring_p->tdc_stats;
318744961713Sgirish 	if ((cs.bits.ldw.pkt_size_err) || (cs.bits.ldw.pref_buf_par_err) ||
318852ccf843Smisaki 	    (cs.bits.ldw.nack_pref) || (cs.bits.ldw.nack_pkt_rd) ||
318952ccf843Smisaki 	    (cs.bits.ldw.conf_part_err) || (cs.bits.ldw.pkt_prt_err)) {
319044961713Sgirish 		if ((rs = npi_txdma_ring_error_get(handle, channel,
319152ccf843Smisaki 		    &tdc_stats->errlog)) != NPI_SUCCESS)
319244961713Sgirish 			return (NXGE_ERROR | rs);
319344961713Sgirish 	}
319444961713Sgirish 
319544961713Sgirish 	if (cs.bits.ldw.mbox_err) {
319644961713Sgirish 		tdc_stats->mbox_err++;
319744961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
319852ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_MBOX_ERR);
319944961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
320052ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
320152ccf843Smisaki 		    "fatal error: mailbox", channel));
320244961713Sgirish 		txchan_fatal = B_TRUE;
320344961713Sgirish 	}
320444961713Sgirish 	if (cs.bits.ldw.pkt_size_err) {
320544961713Sgirish 		tdc_stats->pkt_size_err++;
320644961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
320752ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR);
320844961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
320952ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
321052ccf843Smisaki 		    "fatal error: pkt_size_err", channel));
321144961713Sgirish 		txchan_fatal = B_TRUE;
321244961713Sgirish 	}
321344961713Sgirish 	if (cs.bits.ldw.tx_ring_oflow) {
321444961713Sgirish 		tdc_stats->tx_ring_oflow++;
321544961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
321652ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW);
321744961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
321852ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
321952ccf843Smisaki 		    "fatal error: tx_ring_oflow", channel));
322044961713Sgirish 		txchan_fatal = B_TRUE;
322144961713Sgirish 	}
322244961713Sgirish 	if (cs.bits.ldw.pref_buf_par_err) {
322344961713Sgirish 		tdc_stats->pre_buf_par_err++;
322444961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
322552ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR);
322644961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
322752ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
322852ccf843Smisaki 		    "fatal error: pre_buf_par_err", channel));
322944961713Sgirish 		/* Clear error injection source for parity error */
323044961713Sgirish 		(void) npi_txdma_inj_par_error_get(handle, &value);
323144961713Sgirish 		par_err.value = value;
323244961713Sgirish 		par_err.bits.ldw.inject_parity_error &= ~(1 << channel);
323344961713Sgirish 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
323444961713Sgirish 		txchan_fatal = B_TRUE;
323544961713Sgirish 	}
323644961713Sgirish 	if (cs.bits.ldw.nack_pref) {
323744961713Sgirish 		tdc_stats->nack_pref++;
323844961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
323952ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_NACK_PREF);
324044961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
324152ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
324252ccf843Smisaki 		    "fatal error: nack_pref", channel));
324344961713Sgirish 		txchan_fatal = B_TRUE;
324444961713Sgirish 	}
324544961713Sgirish 	if (cs.bits.ldw.nack_pkt_rd) {
324644961713Sgirish 		tdc_stats->nack_pkt_rd++;
324744961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
324852ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_NACK_PKT_RD);
324944961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
325052ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
325152ccf843Smisaki 		    "fatal error: nack_pkt_rd", channel));
325244961713Sgirish 		txchan_fatal = B_TRUE;
325344961713Sgirish 	}
325444961713Sgirish 	if (cs.bits.ldw.conf_part_err) {
325544961713Sgirish 		tdc_stats->conf_part_err++;
325644961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
325752ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_CONF_PART_ERR);
325844961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
325952ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
326052ccf843Smisaki 		    "fatal error: config_partition_err", channel));
326144961713Sgirish 		txchan_fatal = B_TRUE;
326244961713Sgirish 	}
326344961713Sgirish 	if (cs.bits.ldw.pkt_prt_err) {
326444961713Sgirish 		tdc_stats->pkt_part_err++;
326544961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
326652ccf843Smisaki 		    NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR);
326744961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
326852ccf843Smisaki 		    "==> nxge_tx_err_evnts(channel %d): "
326952ccf843Smisaki 		    "fatal error: pkt_prt_err", channel));
327044961713Sgirish 		txchan_fatal = B_TRUE;
327144961713Sgirish 	}
327244961713Sgirish 
327344961713Sgirish 	/* Clear error injection source in case this is an injected error */
327444961713Sgirish 	TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG, channel, 0);
327544961713Sgirish 
327644961713Sgirish 	if (txchan_fatal) {
327744961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
327852ccf843Smisaki 		    " nxge_tx_err_evnts: "
327952ccf843Smisaki 		    " fatal error on channel %d cs 0x%llx\n",
328052ccf843Smisaki 		    channel, cs.value));
328144961713Sgirish 		status = nxge_txdma_fatal_err_recover(nxgep, channel,
328252ccf843Smisaki 		    tx_ring_p);
328344961713Sgirish 		if (status == NXGE_OK) {
328444961713Sgirish 			FM_SERVICE_RESTORED(nxgep);
328544961713Sgirish 		}
328644961713Sgirish 	}
328744961713Sgirish 
3288678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX2_CTL, "<== nxge_tx_err_evnts"));
328944961713Sgirish 
329044961713Sgirish 	return (status);
329144961713Sgirish }
329244961713Sgirish 
329344961713Sgirish static nxge_status_t
3294678453a8Sspeer nxge_txdma_fatal_err_recover(
3295678453a8Sspeer 	p_nxge_t nxgep,
3296678453a8Sspeer 	uint16_t channel,
3297678453a8Sspeer 	p_tx_ring_t tx_ring_p)
329844961713Sgirish {
329944961713Sgirish 	npi_handle_t	handle;
330044961713Sgirish 	npi_status_t	rs = NPI_SUCCESS;
330144961713Sgirish 	p_tx_mbox_t	tx_mbox_p;
330244961713Sgirish 	nxge_status_t	status = NXGE_OK;
330344961713Sgirish 
330444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fatal_err_recover"));
330544961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
330652ccf843Smisaki 	    "Recovering from TxDMAChannel#%d error...", channel));
330744961713Sgirish 
330844961713Sgirish 	/*
330944961713Sgirish 	 * Stop the dma channel waits for the stop done.
331044961713Sgirish 	 * If the stop done bit is not set, then create
331144961713Sgirish 	 * an error.
331244961713Sgirish 	 */
331344961713Sgirish 
331444961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
331544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel stop..."));
331644961713Sgirish 	MUTEX_ENTER(&tx_ring_p->lock);
331744961713Sgirish 	rs = npi_txdma_channel_control(handle, TXDMA_STOP, channel);
331844961713Sgirish 	if (rs != NPI_SUCCESS) {
331944961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
332052ccf843Smisaki 		    "==> nxge_txdma_fatal_err_recover (channel %d): "
332152ccf843Smisaki 		    "stop failed ", channel));
332244961713Sgirish 		goto fail;
332344961713Sgirish 	}
332444961713Sgirish 
332544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reclaim..."));
332644961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
332744961713Sgirish 
332844961713Sgirish 	/*
332944961713Sgirish 	 * Reset TXDMA channel
333044961713Sgirish 	 */
333144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reset..."));
333244961713Sgirish 	if ((rs = npi_txdma_channel_control(handle, TXDMA_RESET, channel)) !=
333352ccf843Smisaki 	    NPI_SUCCESS) {
333444961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
333552ccf843Smisaki 		    "==> nxge_txdma_fatal_err_recover (channel %d)"
333652ccf843Smisaki 		    " reset channel failed 0x%x", channel, rs));
333744961713Sgirish 		goto fail;
333844961713Sgirish 	}
333944961713Sgirish 
334044961713Sgirish 	/*
334144961713Sgirish 	 * Reset the tail (kick) register to 0.
334244961713Sgirish 	 * (Hardware will not reset it. Tx overflow fatal
334344961713Sgirish 	 * error if tail is not set to 0 after reset!
334444961713Sgirish 	 */
334544961713Sgirish 	TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0);
334644961713Sgirish 
334744961713Sgirish 	/* Restart TXDMA channel */
334844961713Sgirish 
3349678453a8Sspeer 	if (!isLDOMguest(nxgep)) {
3350678453a8Sspeer 		tx_mbox_p = nxge_txdma_get_mbox(nxgep, channel);
335144961713Sgirish 
3352678453a8Sspeer 		// XXX This is a problem in HIO!
3353678453a8Sspeer 		/*
3354678453a8Sspeer 		 * Initialize the TXDMA channel specific FZC control
3355678453a8Sspeer 		 * configurations. These FZC registers are pertaining
3356678453a8Sspeer 		 * to each TX channel (i.e. logical pages).
3357678453a8Sspeer 		 */
3358678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel restart..."));
3359678453a8Sspeer 		status = nxge_init_fzc_txdma_channel(nxgep, channel,
3360678453a8Sspeer 		    tx_ring_p, tx_mbox_p);
3361678453a8Sspeer 		if (status != NXGE_OK)
3362678453a8Sspeer 			goto fail;
3363678453a8Sspeer 	}
336444961713Sgirish 
336544961713Sgirish 	/*
336644961713Sgirish 	 * Initialize the event masks.
336744961713Sgirish 	 */
336844961713Sgirish 	tx_ring_p->tx_evmask.value = 0;
336944961713Sgirish 	status = nxge_init_txdma_channel_event_mask(nxgep, channel,
337052ccf843Smisaki 	    &tx_ring_p->tx_evmask);
337144961713Sgirish 	if (status != NXGE_OK)
337244961713Sgirish 		goto fail;
337344961713Sgirish 
337444961713Sgirish 	tx_ring_p->wr_index_wrap = B_FALSE;
337544961713Sgirish 	tx_ring_p->wr_index = 0;
337644961713Sgirish 	tx_ring_p->rd_index = 0;
337744961713Sgirish 
337844961713Sgirish 	/*
337944961713Sgirish 	 * Load TXDMA descriptors, buffers, mailbox,
338044961713Sgirish 	 * initialise the DMA channels and
338144961713Sgirish 	 * enable each DMA channel.
338244961713Sgirish 	 */
338344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel enable..."));
338444961713Sgirish 	status = nxge_enable_txdma_channel(nxgep, channel,
338552ccf843Smisaki 	    tx_ring_p, tx_mbox_p);
338644961713Sgirish 	MUTEX_EXIT(&tx_ring_p->lock);
338744961713Sgirish 	if (status != NXGE_OK)
338844961713Sgirish 		goto fail;
338944961713Sgirish 
3390*2d99c5d4SMichael Speer 	nxge_txdma_freemsg_task(tx_ring_p);
3391*2d99c5d4SMichael Speer 
339244961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
339352ccf843Smisaki 	    "Recovery Successful, TxDMAChannel#%d Restored",
339452ccf843Smisaki 	    channel));
339544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fatal_err_recover"));
339644961713Sgirish 
339744961713Sgirish 	return (NXGE_OK);
339844961713Sgirish 
339944961713Sgirish fail:
340044961713Sgirish 	MUTEX_EXIT(&tx_ring_p->lock);
3401*2d99c5d4SMichael Speer 
3402*2d99c5d4SMichael Speer 	nxge_txdma_freemsg_task(tx_ring_p);
3403*2d99c5d4SMichael Speer 
340444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
340552ccf843Smisaki 	    "nxge_txdma_fatal_err_recover (channel %d): "
340652ccf843Smisaki 	    "failed to recover this txdma channel", channel));
340744961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed"));
340844961713Sgirish 
340944961713Sgirish 	return (status);
341044961713Sgirish }
341144961713Sgirish 
3412678453a8Sspeer /*
3413678453a8Sspeer  * nxge_tx_port_fatal_err_recover
3414678453a8Sspeer  *
3415678453a8Sspeer  *	Attempt to recover from a fatal port error.
3416678453a8Sspeer  *
3417678453a8Sspeer  * Arguments:
3418678453a8Sspeer  * 	nxgep
3419678453a8Sspeer  *
3420678453a8Sspeer  * Notes:
3421678453a8Sspeer  *	How would a guest do this?
3422678453a8Sspeer  *
3423678453a8Sspeer  * NPI/NXGE function calls:
3424678453a8Sspeer  *
3425678453a8Sspeer  * Registers accessed:
3426678453a8Sspeer  *
3427678453a8Sspeer  * Context:
3428678453a8Sspeer  *	Service domain
3429678453a8Sspeer  */
343044961713Sgirish nxge_status_t
343144961713Sgirish nxge_tx_port_fatal_err_recover(p_nxge_t nxgep)
343244961713Sgirish {
3433678453a8Sspeer 	nxge_grp_set_t *set = &nxgep->tx_set;
3434678453a8Sspeer 	nxge_channel_t tdc;
3435678453a8Sspeer 
3436678453a8Sspeer 	tx_ring_t	*ring;
3437678453a8Sspeer 	tx_mbox_t	*mailbox;
3438678453a8Sspeer 
343944961713Sgirish 	npi_handle_t	handle;
3440678453a8Sspeer 	nxge_status_t	status;
3441678453a8Sspeer 	npi_status_t	rs;
344244961713Sgirish 
344344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_tx_port_fatal_err_recover"));
344444961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3445678453a8Sspeer 	    "Recovering from TxPort error..."));
344644961713Sgirish 
3447678453a8Sspeer 	if (isLDOMguest(nxgep)) {
3448678453a8Sspeer 		return (NXGE_OK);
344944961713Sgirish 	}
345044961713Sgirish 
3451678453a8Sspeer 	if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) {
3452678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3453678453a8Sspeer 		    "<== nxge_tx_port_fatal_err_recover: not initialized"));
3454678453a8Sspeer 		return (NXGE_ERROR);
345544961713Sgirish 	}
345644961713Sgirish 
3457678453a8Sspeer 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
3458678453a8Sspeer 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3459678453a8Sspeer 		    "<== nxge_tx_port_fatal_err_recover: "
3460678453a8Sspeer 		    "NULL ring pointer(s)"));
3461678453a8Sspeer 		return (NXGE_ERROR);
3462678453a8Sspeer 	}
346344961713Sgirish 
3464678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3465678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3466678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3467678453a8Sspeer 			if (ring)
3468678453a8Sspeer 				MUTEX_ENTER(&ring->lock);
346944961713Sgirish 		}
347044961713Sgirish 	}
347144961713Sgirish 
3472678453a8Sspeer 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
3473678453a8Sspeer 
347444961713Sgirish 	/*
3475678453a8Sspeer 	 * Stop all the TDCs owned by us.
3476678453a8Sspeer 	 * (The shared TDCs will have been stopped by their owners.)
347744961713Sgirish 	 */
3478678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3479678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3480678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3481678453a8Sspeer 			if (ring) {
3482678453a8Sspeer 				rs = npi_txdma_channel_control
3483678453a8Sspeer 				    (handle, TXDMA_STOP, tdc);
3484678453a8Sspeer 				if (rs != NPI_SUCCESS) {
3485678453a8Sspeer 					NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3486678453a8Sspeer 					    "nxge_tx_port_fatal_err_recover "
3487678453a8Sspeer 					    "(channel %d): stop failed ", tdc));
3488678453a8Sspeer 					goto fail;
3489678453a8Sspeer 				}
3490678453a8Sspeer 			}
349144961713Sgirish 		}
3492678453a8Sspeer 	}
349344961713Sgirish 
3494678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Reclaiming all TDCs..."));
349544961713Sgirish 
3496678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3497678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3498678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3499*2d99c5d4SMichael Speer 			if (ring) {
3500*2d99c5d4SMichael Speer 				MUTEX_ENTER(&ring->lock);
3501678453a8Sspeer 				(void) nxge_txdma_reclaim(nxgep, ring, 0);
3502*2d99c5d4SMichael Speer 				MUTEX_EXIT(&ring->lock);
3503*2d99c5d4SMichael Speer 
3504*2d99c5d4SMichael Speer 				nxge_txdma_freemsg_task(ring);
3505*2d99c5d4SMichael Speer 			}
3506678453a8Sspeer 		}
350744961713Sgirish 	}
350844961713Sgirish 
350944961713Sgirish 	/*
3510678453a8Sspeer 	 * Reset all the TDCs.
351144961713Sgirish 	 */
3512678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Resetting all TDCs..."));
3513678453a8Sspeer 
3514678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3515678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3516678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3517678453a8Sspeer 			if (ring) {
3518678453a8Sspeer 				if ((rs = npi_txdma_channel_control
351952ccf843Smisaki 				    (handle, TXDMA_RESET, tdc))
3520678453a8Sspeer 				    != NPI_SUCCESS) {
3521678453a8Sspeer 					NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3522678453a8Sspeer 					    "nxge_tx_port_fatal_err_recover "
3523678453a8Sspeer 					    "(channel %d) reset channel "
3524678453a8Sspeer 					    "failed 0x%x", tdc, rs));
3525678453a8Sspeer 					goto fail;
3526678453a8Sspeer 				}
3527678453a8Sspeer 			}
3528678453a8Sspeer 			/*
3529678453a8Sspeer 			 * Reset the tail (kick) register to 0.
3530678453a8Sspeer 			 * (Hardware will not reset it. Tx overflow fatal
3531678453a8Sspeer 			 * error if tail is not set to 0 after reset!
3532678453a8Sspeer 			 */
3533678453a8Sspeer 			TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, tdc, 0);
353444961713Sgirish 		}
3535678453a8Sspeer 	}
353644961713Sgirish 
3537678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Restarting all TDCs..."));
3538678453a8Sspeer 
3539678453a8Sspeer 	/* Restart all the TDCs */
3540678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3541678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3542678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3543678453a8Sspeer 			if (ring) {
3544678453a8Sspeer 				mailbox = nxge_txdma_get_mbox(nxgep, tdc);
3545678453a8Sspeer 				status = nxge_init_fzc_txdma_channel(nxgep, tdc,
3546678453a8Sspeer 				    ring, mailbox);
3547678453a8Sspeer 				ring->tx_evmask.value = 0;
3548678453a8Sspeer 				/*
3549678453a8Sspeer 				 * Initialize the event masks.
3550678453a8Sspeer 				 */
3551678453a8Sspeer 				status = nxge_init_txdma_channel_event_mask
3552678453a8Sspeer 				    (nxgep, tdc, &ring->tx_evmask);
3553678453a8Sspeer 
3554678453a8Sspeer 				ring->wr_index_wrap = B_FALSE;
3555678453a8Sspeer 				ring->wr_index = 0;
3556678453a8Sspeer 				ring->rd_index = 0;
3557678453a8Sspeer 
3558678453a8Sspeer 				if (status != NXGE_OK)
3559678453a8Sspeer 					goto fail;
3560678453a8Sspeer 				if (status != NXGE_OK)
3561678453a8Sspeer 					goto fail;
3562678453a8Sspeer 			}
3563678453a8Sspeer 		}
356444961713Sgirish 	}
356544961713Sgirish 
3566678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Re-enabling all TDCs..."));
356744961713Sgirish 
3568678453a8Sspeer 	/* Re-enable all the TDCs */
3569678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3570678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3571678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3572678453a8Sspeer 			if (ring) {
3573678453a8Sspeer 				mailbox = nxge_txdma_get_mbox(nxgep, tdc);
3574678453a8Sspeer 				status = nxge_enable_txdma_channel(nxgep, tdc,
3575678453a8Sspeer 				    ring, mailbox);
3576678453a8Sspeer 				if (status != NXGE_OK)
3577678453a8Sspeer 					goto fail;
3578678453a8Sspeer 			}
357944961713Sgirish 		}
358044961713Sgirish 	}
358144961713Sgirish 
3582678453a8Sspeer 	/*
3583678453a8Sspeer 	 * Unlock all the TDCs.
3584678453a8Sspeer 	 */
3585678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3586678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3587678453a8Sspeer 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3588678453a8Sspeer 			if (ring)
3589678453a8Sspeer 				MUTEX_EXIT(&ring->lock);
359044961713Sgirish 		}
359144961713Sgirish 	}
359244961713Sgirish 
3593678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery succeeded"));
359444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover"));
359544961713Sgirish 
359644961713Sgirish 	return (NXGE_OK);
359744961713Sgirish 
359844961713Sgirish fail:
3599678453a8Sspeer 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3600678453a8Sspeer 		if ((1 << tdc) & set->owned.map) {
3601678453a8Sspeer 			ring = nxgep->tx_rings->rings[tdc];
3602678453a8Sspeer 			if (ring)
3603678453a8Sspeer 				MUTEX_EXIT(&ring->lock);
360444961713Sgirish 		}
360544961713Sgirish 	}
360644961713Sgirish 
3607678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery failed"));
3608678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover"));
360944961713Sgirish 
361044961713Sgirish 	return (status);
361144961713Sgirish }
361244961713Sgirish 
3613678453a8Sspeer /*
3614678453a8Sspeer  * nxge_txdma_inject_err
3615678453a8Sspeer  *
3616678453a8Sspeer  *	Inject an error into a TDC.
3617678453a8Sspeer  *
3618678453a8Sspeer  * Arguments:
3619678453a8Sspeer  * 	nxgep
3620678453a8Sspeer  * 	err_id	The error to inject.
3621678453a8Sspeer  * 	chan	The channel to inject into.
3622678453a8Sspeer  *
3623678453a8Sspeer  * Notes:
3624678453a8Sspeer  *	This is called from nxge_main.c:nxge_err_inject()
3625678453a8Sspeer  *	Has this ioctl ever been used?
3626678453a8Sspeer  *
3627678453a8Sspeer  * NPI/NXGE function calls:
3628678453a8Sspeer  *	npi_txdma_inj_par_error_get()
3629678453a8Sspeer  *	npi_txdma_inj_par_error_set()
3630678453a8Sspeer  *
3631678453a8Sspeer  * Registers accessed:
3632678453a8Sspeer  *	TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error
3633678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
3634678453a8Sspeer  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
3635678453a8Sspeer  *
3636678453a8Sspeer  * Context:
3637678453a8Sspeer  *	Service domain
3638678453a8Sspeer  */
363944961713Sgirish void
364044961713Sgirish nxge_txdma_inject_err(p_nxge_t nxgep, uint32_t err_id, uint8_t chan)
364144961713Sgirish {
364244961713Sgirish 	tdmc_intr_dbg_t		tdi;
364344961713Sgirish 	tdmc_inj_par_err_t	par_err;
364444961713Sgirish 	uint32_t		value;
364544961713Sgirish 	npi_handle_t		handle;
364644961713Sgirish 
364744961713Sgirish 	switch (err_id) {
364844961713Sgirish 
364944961713Sgirish 	case NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR:
365044961713Sgirish 		handle = NXGE_DEV_NPI_HANDLE(nxgep);
365144961713Sgirish 		/* Clear error injection source for parity error */
365244961713Sgirish 		(void) npi_txdma_inj_par_error_get(handle, &value);
365344961713Sgirish 		par_err.value = value;
365444961713Sgirish 		par_err.bits.ldw.inject_parity_error &= ~(1 << chan);
365544961713Sgirish 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
365644961713Sgirish 
365744961713Sgirish 		par_err.bits.ldw.inject_parity_error = (1 << chan);
365844961713Sgirish 		(void) npi_txdma_inj_par_error_get(handle, &value);
365944961713Sgirish 		par_err.value = value;
366044961713Sgirish 		par_err.bits.ldw.inject_parity_error |= (1 << chan);
366144961713Sgirish 		cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INJ_PAR_ERR_REG\n",
366252ccf843Smisaki 		    (unsigned long long)par_err.value);
366344961713Sgirish 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
366444961713Sgirish 		break;
366544961713Sgirish 
366644961713Sgirish 	case NXGE_FM_EREPORT_TDMC_MBOX_ERR:
366744961713Sgirish 	case NXGE_FM_EREPORT_TDMC_NACK_PREF:
366844961713Sgirish 	case NXGE_FM_EREPORT_TDMC_NACK_PKT_RD:
366944961713Sgirish 	case NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR:
367044961713Sgirish 	case NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW:
367144961713Sgirish 	case NXGE_FM_EREPORT_TDMC_CONF_PART_ERR:
367244961713Sgirish 	case NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR:
367344961713Sgirish 		TXDMA_REG_READ64(nxgep->npi_handle, TDMC_INTR_DBG_REG,
367452ccf843Smisaki 		    chan, &tdi.value);
367544961713Sgirish 		if (err_id == NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR)
367644961713Sgirish 			tdi.bits.ldw.pref_buf_par_err = 1;
367744961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_MBOX_ERR)
367844961713Sgirish 			tdi.bits.ldw.mbox_err = 1;
367944961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PREF)
368044961713Sgirish 			tdi.bits.ldw.nack_pref = 1;
368144961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PKT_RD)
368244961713Sgirish 			tdi.bits.ldw.nack_pkt_rd = 1;
368344961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR)
368444961713Sgirish 			tdi.bits.ldw.pkt_size_err = 1;
368544961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW)
368644961713Sgirish 			tdi.bits.ldw.tx_ring_oflow = 1;
368744961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_CONF_PART_ERR)
368844961713Sgirish 			tdi.bits.ldw.conf_part_err = 1;
368944961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR)
369044961713Sgirish 			tdi.bits.ldw.pkt_part_err = 1;
3691adfcba55Sjoycey #if defined(__i386)
3692adfcba55Sjoycey 		cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INTR_DBG_REG\n",
369352ccf843Smisaki 		    tdi.value);
3694adfcba55Sjoycey #else
369544961713Sgirish 		cmn_err(CE_NOTE, "!Write 0x%lx to TDMC_INTR_DBG_REG\n",
369652ccf843Smisaki 		    tdi.value);
3697adfcba55Sjoycey #endif
369844961713Sgirish 		TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG,
369952ccf843Smisaki 		    chan, tdi.value);
370044961713Sgirish 
370144961713Sgirish 		break;
370244961713Sgirish 	}
370344961713Sgirish }
3704