1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/nxge/nxge_impl.h>
28 #include <sys/nxge/nxge_txdma.h>
29 #include <sys/nxge/nxge_hio.h>
30 #include <npi_tx_rd64.h>
31 #include <npi_tx_wr64.h>
32 #include <sys/llc1.h>
33 
34 uint32_t 	nxge_reclaim_pending = TXDMA_RECLAIM_PENDING_DEFAULT;
35 uint32_t	nxge_tx_minfree = 64;
36 uint32_t	nxge_tx_intr_thres = 0;
37 uint32_t	nxge_tx_max_gathers = TX_MAX_GATHER_POINTERS;
38 uint32_t	nxge_tx_tiny_pack = 1;
39 uint32_t	nxge_tx_use_bcopy = 1;
40 
41 extern uint32_t 	nxge_tx_ring_size;
42 extern uint32_t 	nxge_bcopy_thresh;
43 extern uint32_t 	nxge_dvma_thresh;
44 extern uint32_t 	nxge_dma_stream_thresh;
45 extern dma_method_t 	nxge_force_dma;
46 extern uint32_t		nxge_cksum_offload;
47 
48 /* Device register access attributes for PIO.  */
49 extern ddi_device_acc_attr_t nxge_dev_reg_acc_attr;
50 /* Device descriptor access attributes for DMA.  */
51 extern ddi_device_acc_attr_t nxge_dev_desc_dma_acc_attr;
52 /* Device buffer access attributes for DMA.  */
53 extern ddi_device_acc_attr_t nxge_dev_buf_dma_acc_attr;
54 extern ddi_dma_attr_t nxge_desc_dma_attr;
55 extern ddi_dma_attr_t nxge_tx_dma_attr;
56 
57 extern void nxge_tx_ring_task(void *arg);
58 
59 static nxge_status_t nxge_map_txdma(p_nxge_t, int);
60 
61 static nxge_status_t nxge_txdma_hw_start(p_nxge_t, int);
62 
63 static nxge_status_t nxge_map_txdma_channel(p_nxge_t, uint16_t,
64 	p_nxge_dma_common_t *, p_tx_ring_t *,
65 	uint32_t, p_nxge_dma_common_t *,
66 	p_tx_mbox_t *);
67 static void nxge_unmap_txdma_channel(p_nxge_t, uint16_t);
68 
69 static nxge_status_t nxge_map_txdma_channel_buf_ring(p_nxge_t, uint16_t,
70 	p_nxge_dma_common_t *, p_tx_ring_t *, uint32_t);
71 static void nxge_unmap_txdma_channel_buf_ring(p_nxge_t, p_tx_ring_t);
72 
73 static void nxge_map_txdma_channel_cfg_ring(p_nxge_t, uint16_t,
74 	p_nxge_dma_common_t *, p_tx_ring_t,
75 	p_tx_mbox_t *);
76 static void nxge_unmap_txdma_channel_cfg_ring(p_nxge_t,
77 	p_tx_ring_t, p_tx_mbox_t);
78 
79 static nxge_status_t nxge_txdma_start_channel(p_nxge_t, uint16_t,
80     p_tx_ring_t, p_tx_mbox_t);
81 static nxge_status_t nxge_txdma_stop_channel(p_nxge_t, uint16_t);
82 
83 static p_tx_ring_t nxge_txdma_get_ring(p_nxge_t, uint16_t);
84 static nxge_status_t nxge_tx_err_evnts(p_nxge_t, uint_t,
85 	p_nxge_ldv_t, tx_cs_t);
86 static p_tx_mbox_t nxge_txdma_get_mbox(p_nxge_t, uint16_t);
87 static nxge_status_t nxge_txdma_fatal_err_recover(p_nxge_t,
88 	uint16_t, p_tx_ring_t);
89 
90 static void nxge_txdma_fixup_hung_channel(p_nxge_t nxgep,
91     p_tx_ring_t ring_p, uint16_t channel);
92 
93 nxge_status_t
94 nxge_init_txdma_channels(p_nxge_t nxgep)
95 {
96 	nxge_grp_set_t	*set = &nxgep->tx_set;
97 	int		i, tdc, count;
98 	nxge_grp_t	*group;
99 	dc_map_t	map;
100 	int		dev_gindex;
101 
102 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "==> nxge_init_txdma_channels"));
103 
104 	for (i = 0, count = 0; i < NXGE_LOGICAL_GROUP_MAX; i++) {
105 		if ((1 << i) & set->lg.map) {
106 			group = set->group[i];
107 			dev_gindex =
108 			    nxgep->pt_config.hw_config.def_mac_txdma_grpid + i;
109 			map = nxgep->pt_config.tdc_grps[dev_gindex].map;
110 			for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
111 				if ((1 << tdc) & map) {
112 					if ((nxge_grp_dc_add(nxgep,
113 					    group, VP_BOUND_TX, tdc)))
114 						goto init_txdma_channels_exit;
115 				}
116 			}
117 		}
118 		if (++count == set->lg.count)
119 			break;
120 	}
121 
122 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_init_txdma_channels"));
123 	return (NXGE_OK);
124 
125 init_txdma_channels_exit:
126 	for (i = 0, count = 0; i < NXGE_LOGICAL_GROUP_MAX; i++) {
127 		if ((1 << i) & set->lg.map) {
128 			group = set->group[i];
129 			dev_gindex =
130 			    nxgep->pt_config.hw_config.def_mac_txdma_grpid + i;
131 			map = nxgep->pt_config.tdc_grps[dev_gindex].map;
132 			for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
133 				if ((1 << tdc) & map) {
134 					nxge_grp_dc_remove(nxgep,
135 					    VP_BOUND_TX, tdc);
136 				}
137 			}
138 		}
139 		if (++count == set->lg.count)
140 			break;
141 	}
142 
143 	return (NXGE_ERROR);
144 
145 }
146 
147 nxge_status_t
148 nxge_init_txdma_channel(
149 	p_nxge_t nxge,
150 	int channel)
151 {
152 	nxge_status_t status;
153 
154 	NXGE_DEBUG_MSG((nxge, MEM2_CTL, "==> nxge_init_txdma_channel"));
155 
156 	status = nxge_map_txdma(nxge, channel);
157 	if (status != NXGE_OK) {
158 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
159 		    "<== nxge_init_txdma_channel: status 0x%x", status));
160 		(void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel);
161 		return (status);
162 	}
163 
164 	status = nxge_txdma_hw_start(nxge, channel);
165 	if (status != NXGE_OK) {
166 		(void) nxge_unmap_txdma_channel(nxge, channel);
167 		(void) npi_txdma_dump_tdc_regs(nxge->npi_handle, channel);
168 		return (status);
169 	}
170 
171 	if (!nxge->statsp->tdc_ksp[channel])
172 		nxge_setup_tdc_kstats(nxge, channel);
173 
174 	NXGE_DEBUG_MSG((nxge, MEM2_CTL, "<== nxge_init_txdma_channel"));
175 
176 	return (status);
177 }
178 
179 void
180 nxge_uninit_txdma_channels(p_nxge_t nxgep)
181 {
182 	nxge_grp_set_t *set = &nxgep->tx_set;
183 	int tdc;
184 
185 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "==> nxge_uninit_txdma_channels"));
186 
187 	if (set->owned.map == 0) {
188 		NXGE_DEBUG_MSG((nxgep, MEM2_CTL,
189 		    "nxge_uninit_txdma_channels: no channels"));
190 		return;
191 	}
192 
193 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
194 		if ((1 << tdc) & set->owned.map) {
195 			nxge_grp_dc_remove(nxgep, VP_BOUND_TX, tdc);
196 		}
197 	}
198 
199 	NXGE_DEBUG_MSG((nxgep, MEM2_CTL, "<== nxge_uninit_txdma_channels"));
200 }
201 
202 void
203 nxge_uninit_txdma_channel(p_nxge_t nxgep, int channel)
204 {
205 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_uninit_txdma_channel"));
206 
207 	if (nxgep->statsp->tdc_ksp[channel]) {
208 		kstat_delete(nxgep->statsp->tdc_ksp[channel]);
209 		nxgep->statsp->tdc_ksp[channel] = 0;
210 	}
211 
212 	(void) nxge_txdma_stop_channel(nxgep, channel);
213 	nxge_unmap_txdma_channel(nxgep, channel);
214 
215 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
216 	    "<== nxge_uninit_txdma_channel"));
217 }
218 
219 void
220 nxge_setup_dma_common(p_nxge_dma_common_t dest_p, p_nxge_dma_common_t src_p,
221 	uint32_t entries, uint32_t size)
222 {
223 	size_t		tsize;
224 	*dest_p = *src_p;
225 	tsize = size * entries;
226 	dest_p->alength = tsize;
227 	dest_p->nblocks = entries;
228 	dest_p->block_size = size;
229 	dest_p->offset += tsize;
230 
231 	src_p->kaddrp = (caddr_t)dest_p->kaddrp + tsize;
232 	src_p->alength -= tsize;
233 	src_p->dma_cookie.dmac_laddress += tsize;
234 	src_p->dma_cookie.dmac_size -= tsize;
235 }
236 
237 /*
238  * nxge_reset_txdma_channel
239  *
240  *	Reset a TDC.
241  *
242  * Arguments:
243  * 	nxgep
244  * 	channel		The channel to reset.
245  * 	reg_data	The current TX_CS.
246  *
247  * Notes:
248  *
249  * NPI/NXGE function calls:
250  *	npi_txdma_channel_reset()
251  *	npi_txdma_channel_control()
252  *
253  * Registers accessed:
254  *	TX_CS		DMC+0x40028 Transmit Control And Status
255  *	TX_RING_KICK	DMC+0x40018 Transmit Ring Kick
256  *
257  * Context:
258  *	Any domain
259  */
260 nxge_status_t
261 nxge_reset_txdma_channel(p_nxge_t nxgep, uint16_t channel, uint64_t reg_data)
262 {
263 	npi_status_t		rs = NPI_SUCCESS;
264 	nxge_status_t		status = NXGE_OK;
265 	npi_handle_t		handle;
266 
267 	NXGE_DEBUG_MSG((nxgep, TX_CTL, " ==> nxge_reset_txdma_channel"));
268 
269 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
270 	if ((reg_data & TX_CS_RST_MASK) == TX_CS_RST_MASK) {
271 		rs = npi_txdma_channel_reset(handle, channel);
272 	} else {
273 		rs = npi_txdma_channel_control(handle, TXDMA_RESET,
274 		    channel);
275 	}
276 
277 	if (rs != NPI_SUCCESS) {
278 		status = NXGE_ERROR | rs;
279 	}
280 
281 	/*
282 	 * Reset the tail (kick) register to 0.
283 	 * (Hardware will not reset it. Tx overflow fatal
284 	 * error if tail is not set to 0 after reset!
285 	 */
286 	TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0);
287 
288 	NXGE_DEBUG_MSG((nxgep, TX_CTL, " <== nxge_reset_txdma_channel"));
289 	return (status);
290 }
291 
292 /*
293  * nxge_init_txdma_channel_event_mask
294  *
295  *	Enable interrupts for a set of events.
296  *
297  * Arguments:
298  * 	nxgep
299  * 	channel	The channel to map.
300  * 	mask_p	The events to enable.
301  *
302  * Notes:
303  *
304  * NPI/NXGE function calls:
305  *	npi_txdma_event_mask()
306  *
307  * Registers accessed:
308  *	TX_ENT_MSK	DMC+0x40020 Transmit Event Mask
309  *
310  * Context:
311  *	Any domain
312  */
313 nxge_status_t
314 nxge_init_txdma_channel_event_mask(p_nxge_t nxgep, uint16_t channel,
315 		p_tx_dma_ent_msk_t mask_p)
316 {
317 	npi_handle_t		handle;
318 	npi_status_t		rs = NPI_SUCCESS;
319 	nxge_status_t		status = NXGE_OK;
320 
321 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
322 	    "<== nxge_init_txdma_channel_event_mask"));
323 
324 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
325 	rs = npi_txdma_event_mask(handle, OP_SET, channel, mask_p);
326 	if (rs != NPI_SUCCESS) {
327 		status = NXGE_ERROR | rs;
328 	}
329 
330 	return (status);
331 }
332 
333 /*
334  * nxge_init_txdma_channel_cntl_stat
335  *
336  *	Stop a TDC.  If at first we don't succeed, inject an error.
337  *
338  * Arguments:
339  * 	nxgep
340  * 	channel		The channel to stop.
341  *
342  * Notes:
343  *
344  * NPI/NXGE function calls:
345  *	npi_txdma_control_status()
346  *
347  * Registers accessed:
348  *	TX_CS		DMC+0x40028 Transmit Control And Status
349  *
350  * Context:
351  *	Any domain
352  */
353 nxge_status_t
354 nxge_init_txdma_channel_cntl_stat(p_nxge_t nxgep, uint16_t channel,
355 	uint64_t reg_data)
356 {
357 	npi_handle_t		handle;
358 	npi_status_t		rs = NPI_SUCCESS;
359 	nxge_status_t		status = NXGE_OK;
360 
361 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
362 	    "<== nxge_init_txdma_channel_cntl_stat"));
363 
364 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
365 	rs = npi_txdma_control_status(handle, OP_SET, channel,
366 	    (p_tx_cs_t)&reg_data);
367 
368 	if (rs != NPI_SUCCESS) {
369 		status = NXGE_ERROR | rs;
370 	}
371 
372 	return (status);
373 }
374 
375 /*
376  * nxge_enable_txdma_channel
377  *
378  *	Enable a TDC.
379  *
380  * Arguments:
381  * 	nxgep
382  * 	channel		The channel to enable.
383  * 	tx_desc_p	channel's transmit descriptor ring.
384  * 	mbox_p		channel's mailbox,
385  *
386  * Notes:
387  *
388  * NPI/NXGE function calls:
389  *	npi_txdma_ring_config()
390  *	npi_txdma_mbox_config()
391  *	npi_txdma_channel_init_enable()
392  *
393  * Registers accessed:
394  *	TX_RNG_CFIG	DMC+0x40000 Transmit Ring Configuration
395  *	TXDMA_MBH	DMC+0x40030 TXDMA Mailbox High
396  *	TXDMA_MBL	DMC+0x40038 TXDMA Mailbox Low
397  *	TX_CS		DMC+0x40028 Transmit Control And Status
398  *
399  * Context:
400  *	Any domain
401  */
402 nxge_status_t
403 nxge_enable_txdma_channel(p_nxge_t nxgep,
404 	uint16_t channel, p_tx_ring_t tx_desc_p, p_tx_mbox_t mbox_p)
405 {
406 	npi_handle_t		handle;
407 	npi_status_t		rs = NPI_SUCCESS;
408 	nxge_status_t		status = NXGE_OK;
409 
410 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_enable_txdma_channel"));
411 
412 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
413 	/*
414 	 * Use configuration data composed at init time.
415 	 * Write to hardware the transmit ring configurations.
416 	 */
417 	rs = npi_txdma_ring_config(handle, OP_SET, channel,
418 	    (uint64_t *)&(tx_desc_p->tx_ring_cfig.value));
419 
420 	if (rs != NPI_SUCCESS) {
421 		return (NXGE_ERROR | rs);
422 	}
423 
424 	if (isLDOMguest(nxgep)) {
425 		/* Add interrupt handler for this channel. */
426 		if (nxge_hio_intr_add(nxgep, VP_BOUND_TX, channel) != NXGE_OK)
427 			return (NXGE_ERROR);
428 	}
429 
430 	/* Write to hardware the mailbox */
431 	rs = npi_txdma_mbox_config(handle, OP_SET, channel,
432 	    (uint64_t *)&mbox_p->tx_mbox.dma_cookie.dmac_laddress);
433 
434 	if (rs != NPI_SUCCESS) {
435 		return (NXGE_ERROR | rs);
436 	}
437 
438 	/* Start the DMA engine. */
439 	rs = npi_txdma_channel_init_enable(handle, channel);
440 
441 	if (rs != NPI_SUCCESS) {
442 		return (NXGE_ERROR | rs);
443 	}
444 
445 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_enable_txdma_channel"));
446 
447 	return (status);
448 }
449 
450 void
451 nxge_fill_tx_hdr(p_mblk_t mp, boolean_t fill_len,
452 		boolean_t l4_cksum, int pkt_len, uint8_t npads,
453 		p_tx_pkt_hdr_all_t pkthdrp,
454 		t_uscalar_t start_offset,
455 		t_uscalar_t stuff_offset)
456 {
457 	p_tx_pkt_header_t	hdrp;
458 	p_mblk_t 		nmp;
459 	uint64_t		tmp;
460 	size_t 			mblk_len;
461 	size_t 			iph_len;
462 	size_t 			hdrs_size;
463 	uint8_t			hdrs_buf[sizeof (struct ether_header) +
464 	    64 + sizeof (uint32_t)];
465 	uint8_t			*cursor;
466 	uint8_t 		*ip_buf;
467 	uint16_t		eth_type;
468 	uint8_t			ipproto;
469 	boolean_t		is_vlan = B_FALSE;
470 	size_t			eth_hdr_size;
471 
472 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: mp $%p", mp));
473 
474 	/*
475 	 * Caller should zero out the headers first.
476 	 */
477 	hdrp = (p_tx_pkt_header_t)&pkthdrp->pkthdr;
478 
479 	if (fill_len) {
480 		NXGE_DEBUG_MSG((NULL, TX_CTL,
481 		    "==> nxge_fill_tx_hdr: pkt_len %d "
482 		    "npads %d", pkt_len, npads));
483 		tmp = (uint64_t)pkt_len;
484 		hdrp->value |= (tmp << TX_PKT_HEADER_TOT_XFER_LEN_SHIFT);
485 		goto fill_tx_header_done;
486 	}
487 
488 	hdrp->value |= (((uint64_t)npads) << TX_PKT_HEADER_PAD_SHIFT);
489 
490 	/*
491 	 * mp is the original data packet (does not include the
492 	 * Neptune transmit header).
493 	 */
494 	nmp = mp;
495 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: "
496 	    "mp $%p b_rptr $%p len %d",
497 	    mp, nmp->b_rptr, MBLKL(nmp)));
498 	/* copy ether_header from mblk to hdrs_buf */
499 	cursor = &hdrs_buf[0];
500 	tmp = sizeof (struct ether_vlan_header);
501 	while ((nmp != NULL) && (tmp > 0)) {
502 		size_t buflen;
503 		mblk_len = MBLKL(nmp);
504 		buflen = min((size_t)tmp, mblk_len);
505 		bcopy(nmp->b_rptr, cursor, buflen);
506 		cursor += buflen;
507 		tmp -= buflen;
508 		nmp = nmp->b_cont;
509 	}
510 
511 	nmp = mp;
512 	mblk_len = MBLKL(nmp);
513 	ip_buf = NULL;
514 	eth_type = ntohs(((p_ether_header_t)hdrs_buf)->ether_type);
515 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> : nxge_fill_tx_hdr: (value 0x%llx) "
516 	    "ether type 0x%x", eth_type, hdrp->value));
517 
518 	if (eth_type < ETHERMTU) {
519 		tmp = 1ull;
520 		hdrp->value |= (tmp << TX_PKT_HEADER_LLC_SHIFT);
521 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: LLC "
522 		    "value 0x%llx", hdrp->value));
523 		if (*(hdrs_buf + sizeof (struct ether_header))
524 		    == LLC_SNAP_SAP) {
525 			eth_type = ntohs(*((uint16_t *)(hdrs_buf +
526 			    sizeof (struct ether_header) + 6)));
527 			NXGE_DEBUG_MSG((NULL, TX_CTL,
528 			    "==> nxge_tx_pkt_hdr_init: LLC ether type 0x%x",
529 			    eth_type));
530 		} else {
531 			goto fill_tx_header_done;
532 		}
533 	} else if (eth_type == VLAN_ETHERTYPE) {
534 		tmp = 1ull;
535 		hdrp->value |= (tmp << TX_PKT_HEADER_VLAN__SHIFT);
536 
537 		eth_type = ntohs(((struct ether_vlan_header *)
538 		    hdrs_buf)->ether_type);
539 		is_vlan = B_TRUE;
540 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: VLAN "
541 		    "value 0x%llx", hdrp->value));
542 	}
543 
544 	if (!is_vlan) {
545 		eth_hdr_size = sizeof (struct ether_header);
546 	} else {
547 		eth_hdr_size = sizeof (struct ether_vlan_header);
548 	}
549 
550 	switch (eth_type) {
551 	case ETHERTYPE_IP:
552 		if (mblk_len > eth_hdr_size + sizeof (uint8_t)) {
553 			ip_buf = nmp->b_rptr + eth_hdr_size;
554 			mblk_len -= eth_hdr_size;
555 			iph_len = ((*ip_buf) & 0x0f);
556 			if (mblk_len > (iph_len + sizeof (uint32_t))) {
557 				ip_buf = nmp->b_rptr;
558 				ip_buf += eth_hdr_size;
559 			} else {
560 				ip_buf = NULL;
561 			}
562 
563 		}
564 		if (ip_buf == NULL) {
565 			hdrs_size = 0;
566 			((p_ether_header_t)hdrs_buf)->ether_type = 0;
567 			while ((nmp) && (hdrs_size <
568 			    sizeof (hdrs_buf))) {
569 				mblk_len = (size_t)nmp->b_wptr -
570 				    (size_t)nmp->b_rptr;
571 				if (mblk_len >=
572 				    (sizeof (hdrs_buf) - hdrs_size))
573 					mblk_len = sizeof (hdrs_buf) -
574 					    hdrs_size;
575 				bcopy(nmp->b_rptr,
576 				    &hdrs_buf[hdrs_size], mblk_len);
577 				hdrs_size += mblk_len;
578 				nmp = nmp->b_cont;
579 			}
580 			ip_buf = hdrs_buf;
581 			ip_buf += eth_hdr_size;
582 			iph_len = ((*ip_buf) & 0x0f);
583 		}
584 
585 		ipproto = ip_buf[9];
586 
587 		tmp = (uint64_t)iph_len;
588 		hdrp->value |= (tmp << TX_PKT_HEADER_IHL_SHIFT);
589 		tmp = (uint64_t)(eth_hdr_size >> 1);
590 		hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT);
591 
592 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv4 "
593 		    " iph_len %d l3start %d eth_hdr_size %d proto 0x%x"
594 		    "tmp 0x%x",
595 		    iph_len, hdrp->bits.hdw.l3start, eth_hdr_size,
596 		    ipproto, tmp));
597 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IP "
598 		    "value 0x%llx", hdrp->value));
599 
600 		break;
601 
602 	case ETHERTYPE_IPV6:
603 		hdrs_size = 0;
604 		((p_ether_header_t)hdrs_buf)->ether_type = 0;
605 		while ((nmp) && (hdrs_size <
606 		    sizeof (hdrs_buf))) {
607 			mblk_len = (size_t)nmp->b_wptr - (size_t)nmp->b_rptr;
608 			if (mblk_len >=
609 			    (sizeof (hdrs_buf) - hdrs_size))
610 				mblk_len = sizeof (hdrs_buf) -
611 				    hdrs_size;
612 			bcopy(nmp->b_rptr,
613 			    &hdrs_buf[hdrs_size], mblk_len);
614 			hdrs_size += mblk_len;
615 			nmp = nmp->b_cont;
616 		}
617 		ip_buf = hdrs_buf;
618 		ip_buf += eth_hdr_size;
619 
620 		tmp = 1ull;
621 		hdrp->value |= (tmp << TX_PKT_HEADER_IP_VER_SHIFT);
622 
623 		tmp = (eth_hdr_size >> 1);
624 		hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT);
625 
626 		/* byte 6 is the next header protocol */
627 		ipproto = ip_buf[6];
628 
629 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv6 "
630 		    " iph_len %d l3start %d eth_hdr_size %d proto 0x%x",
631 		    iph_len, hdrp->bits.hdw.l3start, eth_hdr_size,
632 		    ipproto));
633 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IPv6 "
634 		    "value 0x%llx", hdrp->value));
635 
636 		break;
637 
638 	default:
639 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: non-IP"));
640 		goto fill_tx_header_done;
641 	}
642 
643 	switch (ipproto) {
644 	case IPPROTO_TCP:
645 		NXGE_DEBUG_MSG((NULL, TX_CTL,
646 		    "==> nxge_fill_tx_hdr: TCP (cksum flag %d)", l4_cksum));
647 		if (l4_cksum) {
648 			hdrp->value |= TX_CKSUM_EN_PKT_TYPE_TCP;
649 			hdrp->value |=
650 			    (((uint64_t)(start_offset >> 1)) <<
651 			    TX_PKT_HEADER_L4START_SHIFT);
652 			hdrp->value |=
653 			    (((uint64_t)(stuff_offset >> 1)) <<
654 			    TX_PKT_HEADER_L4STUFF_SHIFT);
655 
656 			NXGE_DEBUG_MSG((NULL, TX_CTL,
657 			    "==> nxge_tx_pkt_hdr_init: TCP CKSUM "
658 			    "value 0x%llx", hdrp->value));
659 		}
660 
661 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: TCP "
662 		    "value 0x%llx", hdrp->value));
663 		break;
664 
665 	case IPPROTO_UDP:
666 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: UDP"));
667 		if (l4_cksum) {
668 			if (!nxge_cksum_offload) {
669 				uint16_t	*up;
670 				uint16_t	cksum;
671 				t_uscalar_t	stuff_len;
672 
673 				/*
674 				 * The checksum field has the
675 				 * partial checksum.
676 				 * IP_CSUM() macro calls ip_cksum() which
677 				 * can add in the partial checksum.
678 				 */
679 				cksum = IP_CSUM(mp, start_offset, 0);
680 				stuff_len = stuff_offset;
681 				nmp = mp;
682 				mblk_len = MBLKL(nmp);
683 				while ((nmp != NULL) &&
684 				    (mblk_len < stuff_len)) {
685 					stuff_len -= mblk_len;
686 					nmp = nmp->b_cont;
687 				}
688 				ASSERT(nmp);
689 				up = (uint16_t *)(nmp->b_rptr + stuff_len);
690 
691 				*up = cksum;
692 				hdrp->value &= ~TX_CKSUM_EN_PKT_TYPE_UDP;
693 				NXGE_DEBUG_MSG((NULL, TX_CTL,
694 				    "==> nxge_tx_pkt_hdr_init: UDP offset %d "
695 				    "use sw cksum "
696 				    "write to $%p cksum 0x%x content up 0x%x",
697 				    stuff_len,
698 				    up,
699 				    cksum,
700 				    *up));
701 			} else {
702 				/* Hardware will compute the full checksum */
703 				hdrp->value |= TX_CKSUM_EN_PKT_TYPE_UDP;
704 				hdrp->value |=
705 				    (((uint64_t)(start_offset >> 1)) <<
706 				    TX_PKT_HEADER_L4START_SHIFT);
707 				hdrp->value |=
708 				    (((uint64_t)(stuff_offset >> 1)) <<
709 				    TX_PKT_HEADER_L4STUFF_SHIFT);
710 
711 				NXGE_DEBUG_MSG((NULL, TX_CTL,
712 				    "==> nxge_tx_pkt_hdr_init: UDP offset %d "
713 				    " use partial checksum "
714 				    "cksum 0x%x ",
715 				    "value 0x%llx",
716 				    stuff_offset,
717 				    IP_CSUM(mp, start_offset, 0),
718 				    hdrp->value));
719 			}
720 		}
721 
722 		NXGE_DEBUG_MSG((NULL, TX_CTL,
723 		    "==> nxge_tx_pkt_hdr_init: UDP"
724 		    "value 0x%llx", hdrp->value));
725 		break;
726 
727 	default:
728 		goto fill_tx_header_done;
729 	}
730 
731 fill_tx_header_done:
732 	NXGE_DEBUG_MSG((NULL, TX_CTL,
733 	    "==> nxge_fill_tx_hdr: pkt_len %d  "
734 	    "npads %d value 0x%llx", pkt_len, npads, hdrp->value));
735 
736 	NXGE_DEBUG_MSG((NULL, TX_CTL, "<== nxge_fill_tx_hdr"));
737 }
738 
739 /*ARGSUSED*/
740 p_mblk_t
741 nxge_tx_pkt_header_reserve(p_mblk_t mp, uint8_t *npads)
742 {
743 	p_mblk_t 		newmp = NULL;
744 
745 	if ((newmp = allocb(TX_PKT_HEADER_SIZE, BPRI_MED)) == NULL) {
746 		NXGE_DEBUG_MSG((NULL, TX_CTL,
747 		    "<== nxge_tx_pkt_header_reserve: allocb failed"));
748 		return (NULL);
749 	}
750 
751 	NXGE_DEBUG_MSG((NULL, TX_CTL,
752 	    "==> nxge_tx_pkt_header_reserve: get new mp"));
753 	DB_TYPE(newmp) = M_DATA;
754 	newmp->b_rptr = newmp->b_wptr = DB_LIM(newmp);
755 	linkb(newmp, mp);
756 	newmp->b_rptr -= TX_PKT_HEADER_SIZE;
757 
758 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==>nxge_tx_pkt_header_reserve: "
759 	    "b_rptr $%p b_wptr $%p",
760 	    newmp->b_rptr, newmp->b_wptr));
761 
762 	NXGE_DEBUG_MSG((NULL, TX_CTL,
763 	    "<== nxge_tx_pkt_header_reserve: use new mp"));
764 
765 	return (newmp);
766 }
767 
768 int
769 nxge_tx_pkt_nmblocks(p_mblk_t mp, int *tot_xfer_len_p)
770 {
771 	uint_t 			nmblks;
772 	ssize_t			len;
773 	uint_t 			pkt_len;
774 	p_mblk_t 		nmp, bmp, tmp;
775 	uint8_t 		*b_wptr;
776 
777 	NXGE_DEBUG_MSG((NULL, TX_CTL,
778 	    "==> nxge_tx_pkt_nmblocks: mp $%p rptr $%p wptr $%p "
779 	    "len %d", mp, mp->b_rptr, mp->b_wptr, MBLKL(mp)));
780 
781 	nmp = mp;
782 	bmp = mp;
783 	nmblks = 0;
784 	pkt_len = 0;
785 	*tot_xfer_len_p = 0;
786 
787 	while (nmp) {
788 		len = MBLKL(nmp);
789 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: "
790 		    "len %d pkt_len %d nmblks %d tot_xfer_len %d",
791 		    len, pkt_len, nmblks,
792 		    *tot_xfer_len_p));
793 
794 		if (len <= 0) {
795 			bmp = nmp;
796 			nmp = nmp->b_cont;
797 			NXGE_DEBUG_MSG((NULL, TX_CTL,
798 			    "==> nxge_tx_pkt_nmblocks: "
799 			    "len (0) pkt_len %d nmblks %d",
800 			    pkt_len, nmblks));
801 			continue;
802 		}
803 
804 		*tot_xfer_len_p += len;
805 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: "
806 		    "len %d pkt_len %d nmblks %d tot_xfer_len %d",
807 		    len, pkt_len, nmblks,
808 		    *tot_xfer_len_p));
809 
810 		if (len < nxge_bcopy_thresh) {
811 			NXGE_DEBUG_MSG((NULL, TX_CTL,
812 			    "==> nxge_tx_pkt_nmblocks: "
813 			    "len %d (< thresh) pkt_len %d nmblks %d",
814 			    len, pkt_len, nmblks));
815 			if (pkt_len == 0)
816 				nmblks++;
817 			pkt_len += len;
818 			if (pkt_len >= nxge_bcopy_thresh) {
819 				pkt_len = 0;
820 				len = 0;
821 				nmp = bmp;
822 			}
823 		} else {
824 			NXGE_DEBUG_MSG((NULL, TX_CTL,
825 			    "==> nxge_tx_pkt_nmblocks: "
826 			    "len %d (> thresh) pkt_len %d nmblks %d",
827 			    len, pkt_len, nmblks));
828 			pkt_len = 0;
829 			nmblks++;
830 			/*
831 			 * Hardware limits the transfer length to 4K.
832 			 * If len is more than 4K, we need to break
833 			 * it up to at most 2 more blocks.
834 			 */
835 			if (len > TX_MAX_TRANSFER_LENGTH) {
836 				uint32_t	nsegs;
837 
838 				nsegs = 1;
839 				NXGE_DEBUG_MSG((NULL, TX_CTL,
840 				    "==> nxge_tx_pkt_nmblocks: "
841 				    "len %d pkt_len %d nmblks %d nsegs %d",
842 				    len, pkt_len, nmblks, nsegs));
843 				if (len % (TX_MAX_TRANSFER_LENGTH * 2)) {
844 					++nsegs;
845 				}
846 				do {
847 					b_wptr = nmp->b_rptr +
848 					    TX_MAX_TRANSFER_LENGTH;
849 					nmp->b_wptr = b_wptr;
850 					if ((tmp = dupb(nmp)) == NULL) {
851 						return (0);
852 					}
853 					tmp->b_rptr = b_wptr;
854 					tmp->b_wptr = nmp->b_wptr;
855 					tmp->b_cont = nmp->b_cont;
856 					nmp->b_cont = tmp;
857 					nmblks++;
858 					if (--nsegs) {
859 						nmp = tmp;
860 					}
861 				} while (nsegs);
862 				nmp = tmp;
863 			}
864 		}
865 
866 		/*
867 		 * Hardware limits the transmit gather pointers to 15.
868 		 */
869 		if (nmp->b_cont && (nmblks + TX_GATHER_POINTERS_THRESHOLD) >
870 		    TX_MAX_GATHER_POINTERS) {
871 			NXGE_DEBUG_MSG((NULL, TX_CTL,
872 			    "==> nxge_tx_pkt_nmblocks: pull msg - "
873 			    "len %d pkt_len %d nmblks %d",
874 			    len, pkt_len, nmblks));
875 			/* Pull all message blocks from b_cont */
876 			if ((tmp = msgpullup(nmp->b_cont, -1)) == NULL) {
877 				return (0);
878 			}
879 			freemsg(nmp->b_cont);
880 			nmp->b_cont = tmp;
881 			pkt_len = 0;
882 		}
883 		bmp = nmp;
884 		nmp = nmp->b_cont;
885 	}
886 
887 	NXGE_DEBUG_MSG((NULL, TX_CTL,
888 	    "<== nxge_tx_pkt_nmblocks: rptr $%p wptr $%p "
889 	    "nmblks %d len %d tot_xfer_len %d",
890 	    mp->b_rptr, mp->b_wptr, nmblks,
891 	    MBLKL(mp), *tot_xfer_len_p));
892 
893 	return (nmblks);
894 }
895 
896 boolean_t
897 nxge_txdma_reclaim(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, int nmblks)
898 {
899 	boolean_t 		status = B_TRUE;
900 	p_nxge_dma_common_t	tx_desc_dma_p;
901 	nxge_dma_common_t	desc_area;
902 	p_tx_desc_t 		tx_desc_ring_vp;
903 	p_tx_desc_t 		tx_desc_p;
904 	p_tx_desc_t 		tx_desc_pp;
905 	tx_desc_t 		r_tx_desc;
906 	p_tx_msg_t 		tx_msg_ring;
907 	p_tx_msg_t 		tx_msg_p;
908 	npi_handle_t		handle;
909 	tx_ring_hdl_t		tx_head;
910 	uint32_t 		pkt_len;
911 	uint_t			tx_rd_index;
912 	uint16_t		head_index, tail_index;
913 	uint8_t			tdc;
914 	boolean_t		head_wrap, tail_wrap;
915 	p_nxge_tx_ring_stats_t tdc_stats;
916 	int			rc;
917 
918 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_reclaim"));
919 
920 	status = ((tx_ring_p->descs_pending < nxge_reclaim_pending) &&
921 	    (nmblks != 0));
922 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
923 	    "==> nxge_txdma_reclaim: pending %d  reclaim %d nmblks %d",
924 	    tx_ring_p->descs_pending, nxge_reclaim_pending,
925 	    nmblks));
926 	if (!status) {
927 		tx_desc_dma_p = &tx_ring_p->tdc_desc;
928 		desc_area = tx_ring_p->tdc_desc;
929 		handle = NXGE_DEV_NPI_HANDLE(nxgep);
930 		tx_desc_ring_vp = tx_desc_dma_p->kaddrp;
931 		tx_desc_ring_vp =
932 		    (p_tx_desc_t)DMA_COMMON_VPTR(desc_area);
933 		tx_rd_index = tx_ring_p->rd_index;
934 		tx_desc_p = &tx_desc_ring_vp[tx_rd_index];
935 		tx_msg_ring = tx_ring_p->tx_msg_ring;
936 		tx_msg_p = &tx_msg_ring[tx_rd_index];
937 		tdc = tx_ring_p->tdc;
938 		tdc_stats = tx_ring_p->tdc_stats;
939 		if (tx_ring_p->descs_pending > tdc_stats->tx_max_pend) {
940 			tdc_stats->tx_max_pend = tx_ring_p->descs_pending;
941 		}
942 
943 		tail_index = tx_ring_p->wr_index;
944 		tail_wrap = tx_ring_p->wr_index_wrap;
945 
946 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
947 		    "==> nxge_txdma_reclaim: tdc %d tx_rd_index %d "
948 		    "tail_index %d tail_wrap %d "
949 		    "tx_desc_p $%p ($%p) ",
950 		    tdc, tx_rd_index, tail_index, tail_wrap,
951 		    tx_desc_p, (*(uint64_t *)tx_desc_p)));
952 		/*
953 		 * Read the hardware maintained transmit head
954 		 * and wrap around bit.
955 		 */
956 		TXDMA_REG_READ64(handle, TX_RING_HDL_REG, tdc, &tx_head.value);
957 		head_index =  tx_head.bits.ldw.head;
958 		head_wrap = tx_head.bits.ldw.wrap;
959 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
960 		    "==> nxge_txdma_reclaim: "
961 		    "tx_rd_index %d tail %d tail_wrap %d "
962 		    "head %d wrap %d",
963 		    tx_rd_index, tail_index, tail_wrap,
964 		    head_index, head_wrap));
965 
966 		if (head_index == tail_index) {
967 			if (TXDMA_RING_EMPTY(head_index, head_wrap,
968 			    tail_index, tail_wrap) &&
969 			    (head_index == tx_rd_index)) {
970 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
971 				    "==> nxge_txdma_reclaim: EMPTY"));
972 				return (B_TRUE);
973 			}
974 
975 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
976 			    "==> nxge_txdma_reclaim: Checking "
977 			    "if ring full"));
978 			if (TXDMA_RING_FULL(head_index, head_wrap, tail_index,
979 			    tail_wrap)) {
980 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
981 				    "==> nxge_txdma_reclaim: full"));
982 				return (B_FALSE);
983 			}
984 		}
985 
986 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
987 		    "==> nxge_txdma_reclaim: tx_rd_index and head_index"));
988 
989 		tx_desc_pp = &r_tx_desc;
990 		while ((tx_rd_index != head_index) &&
991 		    (tx_ring_p->descs_pending != 0)) {
992 
993 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
994 			    "==> nxge_txdma_reclaim: Checking if pending"));
995 
996 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
997 			    "==> nxge_txdma_reclaim: "
998 			    "descs_pending %d ",
999 			    tx_ring_p->descs_pending));
1000 
1001 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
1002 			    "==> nxge_txdma_reclaim: "
1003 			    "(tx_rd_index %d head_index %d "
1004 			    "(tx_desc_p $%p)",
1005 			    tx_rd_index, head_index,
1006 			    tx_desc_p));
1007 
1008 			tx_desc_pp->value = tx_desc_p->value;
1009 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
1010 			    "==> nxge_txdma_reclaim: "
1011 			    "(tx_rd_index %d head_index %d "
1012 			    "tx_desc_p $%p (desc value 0x%llx) ",
1013 			    tx_rd_index, head_index,
1014 			    tx_desc_pp, (*(uint64_t *)tx_desc_pp)));
1015 
1016 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
1017 			    "==> nxge_txdma_reclaim: dump desc:"));
1018 
1019 			pkt_len = tx_desc_pp->bits.hdw.tr_len;
1020 			tdc_stats->obytes += pkt_len;
1021 			tdc_stats->opackets += tx_desc_pp->bits.hdw.sop;
1022 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
1023 			    "==> nxge_txdma_reclaim: pkt_len %d "
1024 			    "tdc channel %d opackets %d",
1025 			    pkt_len,
1026 			    tdc,
1027 			    tdc_stats->opackets));
1028 
1029 			if (tx_msg_p->flags.dma_type == USE_DVMA) {
1030 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
1031 				    "tx_desc_p = $%p "
1032 				    "tx_desc_pp = $%p "
1033 				    "index = %d",
1034 				    tx_desc_p,
1035 				    tx_desc_pp,
1036 				    tx_ring_p->rd_index));
1037 				(void) dvma_unload(tx_msg_p->dvma_handle,
1038 				    0, -1);
1039 				tx_msg_p->dvma_handle = NULL;
1040 				if (tx_ring_p->dvma_wr_index ==
1041 				    tx_ring_p->dvma_wrap_mask) {
1042 					tx_ring_p->dvma_wr_index = 0;
1043 				} else {
1044 					tx_ring_p->dvma_wr_index++;
1045 				}
1046 				tx_ring_p->dvma_pending--;
1047 			} else if (tx_msg_p->flags.dma_type ==
1048 			    USE_DMA) {
1049 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
1050 				    "==> nxge_txdma_reclaim: "
1051 				    "USE DMA"));
1052 				if (rc = ddi_dma_unbind_handle
1053 				    (tx_msg_p->dma_handle)) {
1054 					cmn_err(CE_WARN, "!nxge_reclaim: "
1055 					    "ddi_dma_unbind_handle "
1056 					    "failed. status %d", rc);
1057 				}
1058 			}
1059 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
1060 			    "==> nxge_txdma_reclaim: count packets"));
1061 			/*
1062 			 * count a chained packet only once.
1063 			 */
1064 			if (tx_msg_p->tx_message != NULL) {
1065 				freemsg(tx_msg_p->tx_message);
1066 				tx_msg_p->tx_message = NULL;
1067 			}
1068 
1069 			tx_msg_p->flags.dma_type = USE_NONE;
1070 			tx_rd_index = tx_ring_p->rd_index;
1071 			tx_rd_index = (tx_rd_index + 1) &
1072 			    tx_ring_p->tx_wrap_mask;
1073 			tx_ring_p->rd_index = tx_rd_index;
1074 			tx_ring_p->descs_pending--;
1075 			tx_desc_p = &tx_desc_ring_vp[tx_rd_index];
1076 			tx_msg_p = &tx_msg_ring[tx_rd_index];
1077 		}
1078 
1079 		status = (nmblks <= ((int)tx_ring_p->tx_ring_size -
1080 		    (int)tx_ring_p->descs_pending - TX_FULL_MARK));
1081 		if (status) {
1082 			(void) cas32((uint32_t *)&tx_ring_p->queueing, 1, 0);
1083 		}
1084 	} else {
1085 		status = (nmblks <= ((int)tx_ring_p->tx_ring_size -
1086 		    (int)tx_ring_p->descs_pending - TX_FULL_MARK));
1087 	}
1088 
1089 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
1090 	    "<== nxge_txdma_reclaim status = 0x%08x", status));
1091 
1092 	return (status);
1093 }
1094 
1095 /*
1096  * nxge_tx_intr
1097  *
1098  *	Process a TDC interrupt
1099  *
1100  * Arguments:
1101  * 	arg1	A Logical Device state Vector (LSV) data structure.
1102  * 	arg2	nxge_t *
1103  *
1104  * Notes:
1105  *
1106  * NPI/NXGE function calls:
1107  *	npi_txdma_control_status()
1108  *	npi_intr_ldg_mgmt_set()
1109  *
1110  *	nxge_tx_err_evnts()
1111  *	nxge_txdma_reclaim()
1112  *
1113  * Registers accessed:
1114  *	TX_CS		DMC+0x40028 Transmit Control And Status
1115  *	PIO_LDSV
1116  *
1117  * Context:
1118  *	Any domain
1119  */
1120 uint_t
1121 nxge_tx_intr(void *arg1, void *arg2)
1122 {
1123 	p_nxge_ldv_t		ldvp = (p_nxge_ldv_t)arg1;
1124 	p_nxge_t		nxgep = (p_nxge_t)arg2;
1125 	p_nxge_ldg_t		ldgp;
1126 	uint8_t			channel;
1127 	uint32_t		vindex;
1128 	npi_handle_t		handle;
1129 	tx_cs_t			cs;
1130 	p_tx_ring_t 		*tx_rings;
1131 	p_tx_ring_t 		tx_ring_p;
1132 	npi_status_t		rs = NPI_SUCCESS;
1133 	uint_t 			serviced = DDI_INTR_UNCLAIMED;
1134 	nxge_status_t 		status = NXGE_OK;
1135 
1136 	if (ldvp == NULL) {
1137 		NXGE_DEBUG_MSG((NULL, INT_CTL,
1138 		    "<== nxge_tx_intr: nxgep $%p ldvp $%p",
1139 		    nxgep, ldvp));
1140 		return (DDI_INTR_UNCLAIMED);
1141 	}
1142 
1143 	if (arg2 == NULL || (void *)ldvp->nxgep != arg2) {
1144 		nxgep = ldvp->nxgep;
1145 	}
1146 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
1147 	    "==> nxge_tx_intr: nxgep(arg2) $%p ldvp(arg1) $%p",
1148 	    nxgep, ldvp));
1149 
1150 	if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) ||
1151 	    (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) {
1152 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
1153 		    "<== nxge_tx_intr: interface not started or intialized"));
1154 		return (DDI_INTR_CLAIMED);
1155 	}
1156 
1157 	/*
1158 	 * This interrupt handler is for a specific
1159 	 * transmit dma channel.
1160 	 */
1161 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
1162 	/* Get the control and status for this channel. */
1163 	channel = ldvp->channel;
1164 	ldgp = ldvp->ldgp;
1165 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
1166 	    "==> nxge_tx_intr: nxgep $%p ldvp (ldvp) $%p "
1167 	    "channel %d",
1168 	    nxgep, ldvp, channel));
1169 
1170 	rs = npi_txdma_control_status(handle, OP_GET, channel, &cs);
1171 	vindex = ldvp->vdma_index;
1172 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
1173 	    "==> nxge_tx_intr:channel %d ring index %d status 0x%08x",
1174 	    channel, vindex, rs));
1175 	if (!rs && cs.bits.ldw.mk) {
1176 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
1177 		    "==> nxge_tx_intr:channel %d ring index %d "
1178 		    "status 0x%08x (mk bit set)",
1179 		    channel, vindex, rs));
1180 		tx_rings = nxgep->tx_rings->rings;
1181 		tx_ring_p = tx_rings[vindex];
1182 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
1183 		    "==> nxge_tx_intr:channel %d ring index %d "
1184 		    "status 0x%08x (mk bit set, calling reclaim)",
1185 		    channel, vindex, rs));
1186 
1187 		nxge_tx_ring_task((void *)tx_ring_p);
1188 	}
1189 
1190 	/*
1191 	 * Process other transmit control and status.
1192 	 * Check the ldv state.
1193 	 */
1194 	status = nxge_tx_err_evnts(nxgep, ldvp->vdma_index, ldvp, cs);
1195 	/*
1196 	 * Rearm this logical group if this is a single device
1197 	 * group.
1198 	 */
1199 	if (ldgp->nldvs == 1) {
1200 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
1201 		    "==> nxge_tx_intr: rearm"));
1202 		if (status == NXGE_OK) {
1203 			if (isLDOMguest(nxgep)) {
1204 				nxge_hio_ldgimgn(nxgep, ldgp);
1205 			} else {
1206 				(void) npi_intr_ldg_mgmt_set(handle, ldgp->ldg,
1207 				    B_TRUE, ldgp->ldg_timer);
1208 			}
1209 		}
1210 	}
1211 
1212 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_tx_intr"));
1213 	serviced = DDI_INTR_CLAIMED;
1214 	return (serviced);
1215 }
1216 
1217 void
1218 nxge_txdma_stop(p_nxge_t nxgep)	/* Dead */
1219 {
1220 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop"));
1221 
1222 	(void) nxge_link_monitor(nxgep, LINK_MONITOR_STOP);
1223 
1224 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop"));
1225 }
1226 
1227 void
1228 nxge_txdma_stop_start(p_nxge_t nxgep) /* Dead */
1229 {
1230 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_start"));
1231 
1232 	(void) nxge_txdma_stop(nxgep);
1233 
1234 	(void) nxge_fixup_txdma_rings(nxgep);
1235 	(void) nxge_txdma_hw_mode(nxgep, NXGE_DMA_START);
1236 	(void) nxge_tx_mac_enable(nxgep);
1237 	(void) nxge_txdma_hw_kick(nxgep);
1238 
1239 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_start"));
1240 }
1241 
1242 npi_status_t
1243 nxge_txdma_channel_disable(
1244 	nxge_t *nxge,
1245 	int channel)
1246 {
1247 	npi_handle_t	handle = NXGE_DEV_NPI_HANDLE(nxge);
1248 	npi_status_t	rs;
1249 	tdmc_intr_dbg_t	intr_dbg;
1250 
1251 	/*
1252 	 * Stop the dma channel and wait for the stop-done.
1253 	 * If the stop-done bit is not present, then force
1254 	 * an error so TXC will stop.
1255 	 * All channels bound to this port need to be stopped
1256 	 * and reset after injecting an interrupt error.
1257 	 */
1258 	rs = npi_txdma_channel_disable(handle, channel);
1259 	NXGE_DEBUG_MSG((nxge, MEM3_CTL,
1260 	    "==> nxge_txdma_channel_disable(%d) "
1261 	    "rs 0x%x", channel, rs));
1262 	if (rs != NPI_SUCCESS) {
1263 		/* Inject any error */
1264 		intr_dbg.value = 0;
1265 		intr_dbg.bits.ldw.nack_pref = 1;
1266 		NXGE_DEBUG_MSG((nxge, MEM3_CTL,
1267 		    "==> nxge_txdma_hw_mode: "
1268 		    "channel %d (stop failed 0x%x) "
1269 		    "(inject err)", rs, channel));
1270 		(void) npi_txdma_inj_int_error_set(
1271 		    handle, channel, &intr_dbg);
1272 		rs = npi_txdma_channel_disable(handle, channel);
1273 		NXGE_DEBUG_MSG((nxge, MEM3_CTL,
1274 		    "==> nxge_txdma_hw_mode: "
1275 		    "channel %d (stop again 0x%x) "
1276 		    "(after inject err)",
1277 		    rs, channel));
1278 	}
1279 
1280 	return (rs);
1281 }
1282 
1283 /*
1284  * nxge_txdma_hw_mode
1285  *
1286  *	Toggle all TDCs on (enable) or off (disable).
1287  *
1288  * Arguments:
1289  * 	nxgep
1290  * 	enable	Enable or disable a TDC.
1291  *
1292  * Notes:
1293  *
1294  * NPI/NXGE function calls:
1295  *	npi_txdma_channel_enable(TX_CS)
1296  *	npi_txdma_channel_disable(TX_CS)
1297  *	npi_txdma_inj_int_error_set(TDMC_INTR_DBG)
1298  *
1299  * Registers accessed:
1300  *	TX_CS		DMC+0x40028 Transmit Control And Status
1301  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
1302  *
1303  * Context:
1304  *	Any domain
1305  */
1306 nxge_status_t
1307 nxge_txdma_hw_mode(p_nxge_t nxgep, boolean_t enable)
1308 {
1309 	nxge_grp_set_t *set = &nxgep->tx_set;
1310 
1311 	npi_handle_t	handle;
1312 	nxge_status_t	status;
1313 	npi_status_t	rs;
1314 	int		tdc;
1315 
1316 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1317 	    "==> nxge_txdma_hw_mode: enable mode %d", enable));
1318 
1319 	if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) {
1320 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1321 		    "<== nxge_txdma_mode: not initialized"));
1322 		return (NXGE_ERROR);
1323 	}
1324 
1325 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
1326 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1327 		    "<== nxge_txdma_hw_mode: NULL ring pointer(s)"));
1328 		return (NXGE_ERROR);
1329 	}
1330 
1331 	/* Enable or disable all of the TDCs owned by us. */
1332 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
1333 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1334 		if ((1 << tdc) & set->owned.map) {
1335 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1336 			if (ring) {
1337 				NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1338 				    "==> nxge_txdma_hw_mode: channel %d", tdc));
1339 				if (enable) {
1340 					rs = npi_txdma_channel_enable
1341 					    (handle, tdc);
1342 					NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1343 					    "==> nxge_txdma_hw_mode: "
1344 					    "channel %d (enable) rs 0x%x",
1345 					    tdc, rs));
1346 				} else {
1347 					rs = nxge_txdma_channel_disable
1348 					    (nxgep, tdc);
1349 				}
1350 			}
1351 		}
1352 	}
1353 
1354 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
1355 
1356 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1357 	    "<== nxge_txdma_hw_mode: status 0x%x", status));
1358 
1359 	return (status);
1360 }
1361 
1362 void
1363 nxge_txdma_enable_channel(p_nxge_t nxgep, uint16_t channel)
1364 {
1365 	npi_handle_t		handle;
1366 
1367 	NXGE_DEBUG_MSG((nxgep, DMA_CTL,
1368 	    "==> nxge_txdma_enable_channel: channel %d", channel));
1369 
1370 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
1371 	/* enable the transmit dma channels */
1372 	(void) npi_txdma_channel_enable(handle, channel);
1373 
1374 	NXGE_DEBUG_MSG((nxgep, DMA_CTL, "<== nxge_txdma_enable_channel"));
1375 }
1376 
1377 void
1378 nxge_txdma_disable_channel(p_nxge_t nxgep, uint16_t channel)
1379 {
1380 	npi_handle_t		handle;
1381 
1382 	NXGE_DEBUG_MSG((nxgep, DMA_CTL,
1383 	    "==> nxge_txdma_disable_channel: channel %d", channel));
1384 
1385 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
1386 	/* stop the transmit dma channels */
1387 	(void) npi_txdma_channel_disable(handle, channel);
1388 
1389 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_disable_channel"));
1390 }
1391 
1392 /*
1393  * nxge_txdma_stop_inj_err
1394  *
1395  *	Stop a TDC.  If at first we don't succeed, inject an error.
1396  *
1397  * Arguments:
1398  * 	nxgep
1399  * 	channel		The channel to stop.
1400  *
1401  * Notes:
1402  *
1403  * NPI/NXGE function calls:
1404  *	npi_txdma_channel_disable()
1405  *	npi_txdma_inj_int_error_set()
1406  * #if defined(NXGE_DEBUG)
1407  *	nxge_txdma_regs_dump_channels(nxgep);
1408  * #endif
1409  *
1410  * Registers accessed:
1411  *	TX_CS		DMC+0x40028 Transmit Control And Status
1412  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
1413  *
1414  * Context:
1415  *	Any domain
1416  */
1417 int
1418 nxge_txdma_stop_inj_err(p_nxge_t nxgep, int channel)
1419 {
1420 	npi_handle_t		handle;
1421 	tdmc_intr_dbg_t		intr_dbg;
1422 	int			status;
1423 	npi_status_t		rs = NPI_SUCCESS;
1424 
1425 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_inj_err"));
1426 	/*
1427 	 * Stop the dma channel waits for the stop done.
1428 	 * If the stop done bit is not set, then create
1429 	 * an error.
1430 	 */
1431 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
1432 	rs = npi_txdma_channel_disable(handle, channel);
1433 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
1434 	if (status == NXGE_OK) {
1435 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1436 		    "<== nxge_txdma_stop_inj_err (channel %d): "
1437 		    "stopped OK", channel));
1438 		return (status);
1439 	}
1440 
1441 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
1442 	    "==> nxge_txdma_stop_inj_err (channel %d): stop failed (0x%x) "
1443 	    "injecting error", channel, rs));
1444 	/* Inject any error */
1445 	intr_dbg.value = 0;
1446 	intr_dbg.bits.ldw.nack_pref = 1;
1447 	(void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg);
1448 
1449 	/* Stop done bit will be set as a result of error injection */
1450 	rs = npi_txdma_channel_disable(handle, channel);
1451 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
1452 	if (!(rs & NPI_TXDMA_STOP_FAILED)) {
1453 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1454 		    "<== nxge_txdma_stop_inj_err (channel %d): "
1455 		    "stopped OK ", channel));
1456 		return (status);
1457 	}
1458 
1459 #if	defined(NXGE_DEBUG)
1460 	nxge_txdma_regs_dump_channels(nxgep);
1461 #endif
1462 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
1463 	    "==> nxge_txdma_stop_inj_err (channel): stop failed (0x%x) "
1464 	    " (injected error but still not stopped)", channel, rs));
1465 
1466 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_inj_err"));
1467 	return (status);
1468 }
1469 
1470 /*ARGSUSED*/
1471 void
1472 nxge_fixup_txdma_rings(p_nxge_t nxgep)
1473 {
1474 	nxge_grp_set_t *set = &nxgep->tx_set;
1475 	int tdc;
1476 
1477 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_txdma_rings"));
1478 
1479 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
1480 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1481 		    "<== nxge_fixup_txdma_rings: NULL ring pointer(s)"));
1482 		return;
1483 	}
1484 
1485 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1486 		if ((1 << tdc) & set->owned.map) {
1487 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1488 			if (ring) {
1489 				NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1490 				    "==> nxge_fixup_txdma_rings: channel %d",
1491 				    tdc));
1492 				nxge_txdma_fixup_channel(nxgep, ring, tdc);
1493 			}
1494 		}
1495 	}
1496 
1497 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_txdma_rings"));
1498 }
1499 
1500 /*ARGSUSED*/
1501 void
1502 nxge_txdma_fix_channel(p_nxge_t nxgep, uint16_t channel)
1503 {
1504 	p_tx_ring_t	ring_p;
1505 
1506 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_channel"));
1507 	ring_p = nxge_txdma_get_ring(nxgep, channel);
1508 	if (ring_p == NULL) {
1509 		NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel"));
1510 		return;
1511 	}
1512 
1513 	if (ring_p->tdc != channel) {
1514 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1515 		    "<== nxge_txdma_fix_channel: channel not matched "
1516 		    "ring tdc %d passed channel",
1517 		    ring_p->tdc, channel));
1518 		return;
1519 	}
1520 
1521 	nxge_txdma_fixup_channel(nxgep, ring_p, channel);
1522 
1523 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel"));
1524 }
1525 
1526 /*ARGSUSED*/
1527 void
1528 nxge_txdma_fixup_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel)
1529 {
1530 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_channel"));
1531 
1532 	if (ring_p == NULL) {
1533 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1534 		    "<== nxge_txdma_fixup_channel: NULL ring pointer"));
1535 		return;
1536 	}
1537 
1538 	if (ring_p->tdc != channel) {
1539 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1540 		    "<== nxge_txdma_fixup_channel: channel not matched "
1541 		    "ring tdc %d passed channel",
1542 		    ring_p->tdc, channel));
1543 		return;
1544 	}
1545 
1546 	MUTEX_ENTER(&ring_p->lock);
1547 	(void) nxge_txdma_reclaim(nxgep, ring_p, 0);
1548 	ring_p->rd_index = 0;
1549 	ring_p->wr_index = 0;
1550 	ring_p->ring_head.value = 0;
1551 	ring_p->ring_kick_tail.value = 0;
1552 	ring_p->descs_pending = 0;
1553 	MUTEX_EXIT(&ring_p->lock);
1554 
1555 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_channel"));
1556 }
1557 
1558 /*ARGSUSED*/
1559 void
1560 nxge_txdma_hw_kick(p_nxge_t nxgep)
1561 {
1562 	nxge_grp_set_t *set = &nxgep->tx_set;
1563 	int tdc;
1564 
1565 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick"));
1566 
1567 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
1568 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1569 		    "<== nxge_txdma_hw_kick: NULL ring pointer(s)"));
1570 		return;
1571 	}
1572 
1573 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1574 		if ((1 << tdc) & set->owned.map) {
1575 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1576 			if (ring) {
1577 				NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
1578 				    "==> nxge_txdma_hw_kick: channel %d", tdc));
1579 				nxge_txdma_hw_kick_channel(nxgep, ring, tdc);
1580 			}
1581 		}
1582 	}
1583 
1584 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick"));
1585 }
1586 
1587 /*ARGSUSED*/
1588 void
1589 nxge_txdma_kick_channel(p_nxge_t nxgep, uint16_t channel)
1590 {
1591 	p_tx_ring_t	ring_p;
1592 
1593 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_kick_channel"));
1594 
1595 	ring_p = nxge_txdma_get_ring(nxgep, channel);
1596 	if (ring_p == NULL) {
1597 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1598 		    " nxge_txdma_kick_channel"));
1599 		return;
1600 	}
1601 
1602 	if (ring_p->tdc != channel) {
1603 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1604 		    "<== nxge_txdma_kick_channel: channel not matched "
1605 		    "ring tdc %d passed channel",
1606 		    ring_p->tdc, channel));
1607 		return;
1608 	}
1609 
1610 	nxge_txdma_hw_kick_channel(nxgep, ring_p, channel);
1611 
1612 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_kick_channel"));
1613 }
1614 
1615 /*ARGSUSED*/
1616 void
1617 nxge_txdma_hw_kick_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel)
1618 {
1619 
1620 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick_channel"));
1621 
1622 	if (ring_p == NULL) {
1623 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1624 		    "<== nxge_txdma_hw_kick_channel: NULL ring pointer"));
1625 		return;
1626 	}
1627 
1628 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick_channel"));
1629 }
1630 
1631 /*
1632  * nxge_check_tx_hang
1633  *
1634  *	Check the state of all TDCs belonging to nxgep.
1635  *
1636  * Arguments:
1637  * 	nxgep
1638  *
1639  * Notes:
1640  *	Called by nxge_hw.c:nxge_check_hw_state().
1641  *
1642  * NPI/NXGE function calls:
1643  *
1644  * Registers accessed:
1645  *
1646  * Context:
1647  *	Any domain
1648  */
1649 /*ARGSUSED*/
1650 void
1651 nxge_check_tx_hang(p_nxge_t nxgep)
1652 {
1653 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_check_tx_hang"));
1654 
1655 	if ((!(nxgep->drv_state & STATE_HW_INITIALIZED)) ||
1656 	    (nxgep->nxge_mac_state != NXGE_MAC_STARTED)) {
1657 		goto nxge_check_tx_hang_exit;
1658 	}
1659 
1660 	/*
1661 	 * Needs inputs from hardware for regs:
1662 	 *	head index had not moved since last timeout.
1663 	 *	packets not transmitted or stuffed registers.
1664 	 */
1665 	if (nxge_txdma_hung(nxgep)) {
1666 		nxge_fixup_hung_txdma_rings(nxgep);
1667 	}
1668 
1669 nxge_check_tx_hang_exit:
1670 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_check_tx_hang"));
1671 }
1672 
1673 /*
1674  * nxge_txdma_hung
1675  *
1676  *	Reset a TDC.
1677  *
1678  * Arguments:
1679  * 	nxgep
1680  * 	channel		The channel to reset.
1681  * 	reg_data	The current TX_CS.
1682  *
1683  * Notes:
1684  *	Called by nxge_check_tx_hang()
1685  *
1686  * NPI/NXGE function calls:
1687  *	nxge_txdma_channel_hung()
1688  *
1689  * Registers accessed:
1690  *
1691  * Context:
1692  *	Any domain
1693  */
1694 int
1695 nxge_txdma_hung(p_nxge_t nxgep)
1696 {
1697 	nxge_grp_set_t	*set = &nxgep->tx_set;
1698 	int		tdc;
1699 	boolean_t	shared;
1700 
1701 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hung"));
1702 
1703 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
1704 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1705 		    "<== nxge_txdma_hung: NULL ring pointer(s)"));
1706 		return (B_FALSE);
1707 	}
1708 
1709 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1710 		/*
1711 		 * Grab the shared state of the TDC.
1712 		 */
1713 		if (isLDOMservice(nxgep)) {
1714 			nxge_hio_data_t *nhd =
1715 			    (nxge_hio_data_t *)nxgep->nxge_hw_p->hio;
1716 
1717 			MUTEX_ENTER(&nhd->lock);
1718 			shared = nxgep->tdc_is_shared[tdc];
1719 			MUTEX_EXIT(&nhd->lock);
1720 		} else {
1721 			shared = B_FALSE;
1722 		}
1723 
1724 		/*
1725 		 * Now, process continue to process.
1726 		 */
1727 		if (((1 << tdc) & set->owned.map) && !shared) {
1728 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1729 			if (ring) {
1730 				if (nxge_txdma_channel_hung(nxgep, ring, tdc)) {
1731 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
1732 					    "==> nxge_txdma_hung: TDC %d hung",
1733 					    tdc));
1734 					return (B_TRUE);
1735 				}
1736 			}
1737 		}
1738 	}
1739 
1740 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hung"));
1741 
1742 	return (B_FALSE);
1743 }
1744 
1745 /*
1746  * nxge_txdma_channel_hung
1747  *
1748  *	Reset a TDC.
1749  *
1750  * Arguments:
1751  * 	nxgep
1752  * 	ring		<channel>'s ring.
1753  * 	channel		The channel to reset.
1754  *
1755  * Notes:
1756  *	Called by nxge_txdma.c:nxge_txdma_hung()
1757  *
1758  * NPI/NXGE function calls:
1759  *	npi_txdma_ring_head_get()
1760  *
1761  * Registers accessed:
1762  *	TX_RING_HDL	DMC+0x40010 Transmit Ring Head Low
1763  *
1764  * Context:
1765  *	Any domain
1766  */
1767 int
1768 nxge_txdma_channel_hung(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, uint16_t channel)
1769 {
1770 	uint16_t		head_index, tail_index;
1771 	boolean_t		head_wrap, tail_wrap;
1772 	npi_handle_t		handle;
1773 	tx_ring_hdl_t		tx_head;
1774 	uint_t			tx_rd_index;
1775 
1776 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_channel_hung"));
1777 
1778 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
1779 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
1780 	    "==> nxge_txdma_channel_hung: channel %d", channel));
1781 	MUTEX_ENTER(&tx_ring_p->lock);
1782 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
1783 
1784 	tail_index = tx_ring_p->wr_index;
1785 	tail_wrap = tx_ring_p->wr_index_wrap;
1786 	tx_rd_index = tx_ring_p->rd_index;
1787 	MUTEX_EXIT(&tx_ring_p->lock);
1788 
1789 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
1790 	    "==> nxge_txdma_channel_hung: tdc %d tx_rd_index %d "
1791 	    "tail_index %d tail_wrap %d ",
1792 	    channel, tx_rd_index, tail_index, tail_wrap));
1793 	/*
1794 	 * Read the hardware maintained transmit head
1795 	 * and wrap around bit.
1796 	 */
1797 	(void) npi_txdma_ring_head_get(handle, channel, &tx_head);
1798 	head_index =  tx_head.bits.ldw.head;
1799 	head_wrap = tx_head.bits.ldw.wrap;
1800 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
1801 	    "==> nxge_txdma_channel_hung: "
1802 	    "tx_rd_index %d tail %d tail_wrap %d "
1803 	    "head %d wrap %d",
1804 	    tx_rd_index, tail_index, tail_wrap,
1805 	    head_index, head_wrap));
1806 
1807 	if (TXDMA_RING_EMPTY(head_index, head_wrap,
1808 	    tail_index, tail_wrap) &&
1809 	    (head_index == tx_rd_index)) {
1810 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1811 		    "==> nxge_txdma_channel_hung: EMPTY"));
1812 		return (B_FALSE);
1813 	}
1814 
1815 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
1816 	    "==> nxge_txdma_channel_hung: Checking if ring full"));
1817 	if (TXDMA_RING_FULL(head_index, head_wrap, tail_index,
1818 	    tail_wrap)) {
1819 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1820 		    "==> nxge_txdma_channel_hung: full"));
1821 		return (B_TRUE);
1822 	}
1823 
1824 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_channel_hung"));
1825 
1826 	return (B_FALSE);
1827 }
1828 
1829 /*
1830  * nxge_fixup_hung_txdma_rings
1831  *
1832  *	Disable a TDC.
1833  *
1834  * Arguments:
1835  * 	nxgep
1836  * 	channel		The channel to reset.
1837  * 	reg_data	The current TX_CS.
1838  *
1839  * Notes:
1840  *	Called by nxge_check_tx_hang()
1841  *
1842  * NPI/NXGE function calls:
1843  *	npi_txdma_ring_head_get()
1844  *
1845  * Registers accessed:
1846  *	TX_RING_HDL	DMC+0x40010 Transmit Ring Head Low
1847  *
1848  * Context:
1849  *	Any domain
1850  */
1851 /*ARGSUSED*/
1852 void
1853 nxge_fixup_hung_txdma_rings(p_nxge_t nxgep)
1854 {
1855 	nxge_grp_set_t *set = &nxgep->tx_set;
1856 	int tdc;
1857 
1858 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_hung_txdma_rings"));
1859 
1860 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
1861 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1862 		    "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
1863 		return;
1864 	}
1865 
1866 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
1867 		if ((1 << tdc) & set->owned.map) {
1868 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
1869 			if (ring) {
1870 				nxge_txdma_fixup_hung_channel(nxgep, ring, tdc);
1871 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
1872 				    "==> nxge_fixup_hung_txdma_rings: TDC %d",
1873 				    tdc));
1874 			}
1875 		}
1876 	}
1877 
1878 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_hung_txdma_rings"));
1879 }
1880 
1881 /*
1882  * nxge_txdma_fixup_hung_channel
1883  *
1884  *	'Fix' a hung TDC.
1885  *
1886  * Arguments:
1887  * 	nxgep
1888  * 	channel		The channel to fix.
1889  *
1890  * Notes:
1891  *	Called by nxge_fixup_hung_txdma_rings()
1892  *
1893  *	1. Reclaim the TDC.
1894  *	2. Disable the TDC.
1895  *
1896  * NPI/NXGE function calls:
1897  *	nxge_txdma_reclaim()
1898  *	npi_txdma_channel_disable(TX_CS)
1899  *	npi_txdma_inj_int_error_set(TDMC_INTR_DBG)
1900  *
1901  * Registers accessed:
1902  *	TX_CS		DMC+0x40028 Transmit Control And Status
1903  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
1904  *
1905  * Context:
1906  *	Any domain
1907  */
1908 /*ARGSUSED*/
1909 void
1910 nxge_txdma_fix_hung_channel(p_nxge_t nxgep, uint16_t channel)
1911 {
1912 	p_tx_ring_t	ring_p;
1913 
1914 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_hung_channel"));
1915 	ring_p = nxge_txdma_get_ring(nxgep, channel);
1916 	if (ring_p == NULL) {
1917 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1918 		    "<== nxge_txdma_fix_hung_channel"));
1919 		return;
1920 	}
1921 
1922 	if (ring_p->tdc != channel) {
1923 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1924 		    "<== nxge_txdma_fix_hung_channel: channel not matched "
1925 		    "ring tdc %d passed channel",
1926 		    ring_p->tdc, channel));
1927 		return;
1928 	}
1929 
1930 	nxge_txdma_fixup_channel(nxgep, ring_p, channel);
1931 
1932 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_hung_channel"));
1933 }
1934 
1935 /*ARGSUSED*/
1936 void
1937 nxge_txdma_fixup_hung_channel(p_nxge_t nxgep, p_tx_ring_t ring_p,
1938 	uint16_t channel)
1939 {
1940 	npi_handle_t		handle;
1941 	tdmc_intr_dbg_t		intr_dbg;
1942 	int			status = NXGE_OK;
1943 
1944 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_hung_channel"));
1945 
1946 	if (ring_p == NULL) {
1947 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1948 		    "<== nxge_txdma_fixup_channel: NULL ring pointer"));
1949 		return;
1950 	}
1951 
1952 	if (ring_p->tdc != channel) {
1953 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1954 		    "<== nxge_txdma_fixup_hung_channel: channel "
1955 		    "not matched "
1956 		    "ring tdc %d passed channel",
1957 		    ring_p->tdc, channel));
1958 		return;
1959 	}
1960 
1961 	/* Reclaim descriptors */
1962 	MUTEX_ENTER(&ring_p->lock);
1963 	(void) nxge_txdma_reclaim(nxgep, ring_p, 0);
1964 	MUTEX_EXIT(&ring_p->lock);
1965 
1966 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
1967 	/*
1968 	 * Stop the dma channel waits for the stop done.
1969 	 * If the stop done bit is not set, then force
1970 	 * an error.
1971 	 */
1972 	status = npi_txdma_channel_disable(handle, channel);
1973 	if (!(status & NPI_TXDMA_STOP_FAILED)) {
1974 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1975 		    "<== nxge_txdma_fixup_hung_channel: stopped OK "
1976 		    "ring tdc %d passed channel %d",
1977 		    ring_p->tdc, channel));
1978 		return;
1979 	}
1980 
1981 	/* Inject any error */
1982 	intr_dbg.value = 0;
1983 	intr_dbg.bits.ldw.nack_pref = 1;
1984 	(void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg);
1985 
1986 	/* Stop done bit will be set as a result of error injection */
1987 	status = npi_txdma_channel_disable(handle, channel);
1988 	if (!(status & NPI_TXDMA_STOP_FAILED)) {
1989 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
1990 		    "<== nxge_txdma_fixup_hung_channel: stopped again"
1991 		    "ring tdc %d passed channel",
1992 		    ring_p->tdc, channel));
1993 		return;
1994 	}
1995 
1996 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
1997 	    "<== nxge_txdma_fixup_hung_channel: stop done still not set!! "
1998 	    "ring tdc %d passed channel",
1999 	    ring_p->tdc, channel));
2000 
2001 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_hung_channel"));
2002 }
2003 
2004 /*ARGSUSED*/
2005 void
2006 nxge_reclaim_rings(p_nxge_t nxgep)
2007 {
2008 	nxge_grp_set_t *set = &nxgep->tx_set;
2009 	int tdc;
2010 
2011 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_reclaim_rings"));
2012 
2013 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
2014 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
2015 		    "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
2016 		return;
2017 	}
2018 
2019 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
2020 		if ((1 << tdc) & set->owned.map) {
2021 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
2022 			if (ring) {
2023 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
2024 				    "==> nxge_reclaim_rings: TDC %d", tdc));
2025 				MUTEX_ENTER(&ring->lock);
2026 				(void) nxge_txdma_reclaim(nxgep, ring, 0);
2027 				MUTEX_EXIT(&ring->lock);
2028 			}
2029 		}
2030 	}
2031 
2032 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_reclaim_rings"));
2033 }
2034 
2035 void
2036 nxge_txdma_regs_dump_channels(p_nxge_t nxgep)
2037 {
2038 	nxge_grp_set_t *set = &nxgep->tx_set;
2039 	npi_handle_t handle;
2040 	int tdc;
2041 
2042 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_regs_dump_channels"));
2043 
2044 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
2045 
2046 	if (!isLDOMguest(nxgep)) {
2047 		(void) npi_txdma_dump_fzc_regs(handle);
2048 
2049 		/* Dump TXC registers. */
2050 		(void) npi_txc_dump_fzc_regs(handle);
2051 		(void) npi_txc_dump_port_fzc_regs(handle, nxgep->function_num);
2052 	}
2053 
2054 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
2055 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
2056 		    "<== nxge_fixup_hung_txdma_rings: NULL ring pointer(s)"));
2057 		return;
2058 	}
2059 
2060 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
2061 		if ((1 << tdc) & set->owned.map) {
2062 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
2063 			if (ring) {
2064 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
2065 				    "==> nxge_txdma_regs_dump_channels: "
2066 				    "TDC %d", tdc));
2067 				(void) npi_txdma_dump_tdc_regs(handle, tdc);
2068 
2069 				/* Dump TXC registers, if able to. */
2070 				if (!isLDOMguest(nxgep)) {
2071 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
2072 					    "==> nxge_txdma_regs_dump_channels:"
2073 					    " FZC TDC %d", tdc));
2074 					(void) npi_txc_dump_tdc_fzc_regs
2075 					    (handle, tdc);
2076 				}
2077 				nxge_txdma_regs_dump(nxgep, tdc);
2078 			}
2079 		}
2080 	}
2081 
2082 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_regs_dump"));
2083 }
2084 
2085 void
2086 nxge_txdma_regs_dump(p_nxge_t nxgep, int channel)
2087 {
2088 	npi_handle_t		handle;
2089 	tx_ring_hdl_t 		hdl;
2090 	tx_ring_kick_t 		kick;
2091 	tx_cs_t 		cs;
2092 	txc_control_t		control;
2093 	uint32_t		bitmap = 0;
2094 	uint32_t		burst = 0;
2095 	uint32_t		bytes = 0;
2096 	dma_log_page_t		cfg;
2097 
2098 	printf("\n\tfunc # %d tdc %d ",
2099 	    nxgep->function_num, channel);
2100 	cfg.page_num = 0;
2101 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
2102 	(void) npi_txdma_log_page_get(handle, channel, &cfg);
2103 	printf("\n\tlog page func %d valid page 0 %d",
2104 	    cfg.func_num, cfg.valid);
2105 	cfg.page_num = 1;
2106 	(void) npi_txdma_log_page_get(handle, channel, &cfg);
2107 	printf("\n\tlog page func %d valid page 1 %d",
2108 	    cfg.func_num, cfg.valid);
2109 
2110 	(void) npi_txdma_ring_head_get(handle, channel, &hdl);
2111 	(void) npi_txdma_desc_kick_reg_get(handle, channel, &kick);
2112 	printf("\n\thead value is 0x%0llx",
2113 	    (long long)hdl.value);
2114 	printf("\n\thead index %d", hdl.bits.ldw.head);
2115 	printf("\n\tkick value is 0x%0llx",
2116 	    (long long)kick.value);
2117 	printf("\n\ttail index %d\n", kick.bits.ldw.tail);
2118 
2119 	(void) npi_txdma_control_status(handle, OP_GET, channel, &cs);
2120 	printf("\n\tControl statue is 0x%0llx", (long long)cs.value);
2121 	printf("\n\tControl status RST state %d", cs.bits.ldw.rst);
2122 
2123 	(void) npi_txc_control(handle, OP_GET, &control);
2124 	(void) npi_txc_port_dma_list_get(handle, nxgep->function_num, &bitmap);
2125 	(void) npi_txc_dma_max_burst(handle, OP_GET, channel, &burst);
2126 	(void) npi_txc_dma_bytes_transmitted(handle, channel, &bytes);
2127 
2128 	printf("\n\tTXC port control 0x%0llx",
2129 	    (long long)control.value);
2130 	printf("\n\tTXC port bitmap 0x%x", bitmap);
2131 	printf("\n\tTXC max burst %d", burst);
2132 	printf("\n\tTXC bytes xmt %d\n", bytes);
2133 
2134 	{
2135 		ipp_status_t status;
2136 
2137 		(void) npi_ipp_get_status(handle, nxgep->function_num, &status);
2138 #if defined(__i386)
2139 		printf("\n\tIPP status 0x%llux\n", (uint64_t)status.value);
2140 #else
2141 		printf("\n\tIPP status 0x%lux\n", (uint64_t)status.value);
2142 #endif
2143 	}
2144 }
2145 
2146 /*
2147  * nxge_tdc_hvio_setup
2148  *
2149  *	I'm not exactly sure what this code does.
2150  *
2151  * Arguments:
2152  * 	nxgep
2153  * 	channel	The channel to map.
2154  *
2155  * Notes:
2156  *
2157  * NPI/NXGE function calls:
2158  *	na
2159  *
2160  * Context:
2161  *	Service domain?
2162  */
2163 #if defined(sun4v) && defined(NIU_LP_WORKAROUND)
2164 static void
2165 nxge_tdc_hvio_setup(
2166 	nxge_t *nxgep, int channel)
2167 {
2168 	nxge_dma_common_t	*data;
2169 	nxge_dma_common_t	*control;
2170 	tx_ring_t 		*ring;
2171 
2172 	ring = nxgep->tx_rings->rings[channel];
2173 	data = nxgep->tx_buf_pool_p->dma_buf_pool_p[channel];
2174 
2175 	ring->hv_set = B_FALSE;
2176 
2177 	ring->hv_tx_buf_base_ioaddr_pp =
2178 	    (uint64_t)data->orig_ioaddr_pp;
2179 	ring->hv_tx_buf_ioaddr_size =
2180 	    (uint64_t)data->orig_alength;
2181 
2182 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: "
2183 	    "hv data buf base io $%p size 0x%llx (%d) buf base io $%p "
2184 	    "orig vatopa base io $%p orig_len 0x%llx (%d)",
2185 	    ring->hv_tx_buf_base_ioaddr_pp,
2186 	    ring->hv_tx_buf_ioaddr_size, ring->hv_tx_buf_ioaddr_size,
2187 	    data->ioaddr_pp, data->orig_vatopa,
2188 	    data->orig_alength, data->orig_alength));
2189 
2190 	control = nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel];
2191 
2192 	ring->hv_tx_cntl_base_ioaddr_pp =
2193 	    (uint64_t)control->orig_ioaddr_pp;
2194 	ring->hv_tx_cntl_ioaddr_size =
2195 	    (uint64_t)control->orig_alength;
2196 
2197 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel: "
2198 	    "hv cntl base io $%p orig ioaddr_pp ($%p) "
2199 	    "orig vatopa ($%p) size 0x%llx (%d 0x%x)",
2200 	    ring->hv_tx_cntl_base_ioaddr_pp,
2201 	    control->orig_ioaddr_pp, control->orig_vatopa,
2202 	    ring->hv_tx_cntl_ioaddr_size,
2203 	    control->orig_alength, control->orig_alength));
2204 }
2205 #endif
2206 
2207 static nxge_status_t
2208 nxge_map_txdma(p_nxge_t nxgep, int channel)
2209 {
2210 	nxge_dma_common_t	**pData;
2211 	nxge_dma_common_t	**pControl;
2212 	tx_ring_t 		**pRing, *ring;
2213 	tx_mbox_t		**mailbox;
2214 	uint32_t		num_chunks;
2215 
2216 	nxge_status_t		status = NXGE_OK;
2217 
2218 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma"));
2219 
2220 	if (!nxgep->tx_cntl_pool_p->buf_allocated) {
2221 		if (nxge_alloc_tx_mem_pool(nxgep) != NXGE_OK) {
2222 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2223 			    "<== nxge_map_txdma: buf not allocated"));
2224 			return (NXGE_ERROR);
2225 		}
2226 	}
2227 
2228 	if (nxge_alloc_txb(nxgep, channel) != NXGE_OK)
2229 		return (NXGE_ERROR);
2230 
2231 	num_chunks = nxgep->tx_buf_pool_p->num_chunks[channel];
2232 	pData = &nxgep->tx_buf_pool_p->dma_buf_pool_p[channel];
2233 	pControl = &nxgep->tx_cntl_pool_p->dma_buf_pool_p[channel];
2234 	pRing = &nxgep->tx_rings->rings[channel];
2235 	mailbox = &nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
2236 
2237 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: "
2238 	    "tx_rings $%p tx_desc_rings $%p",
2239 	    nxgep->tx_rings, nxgep->tx_rings->rings));
2240 
2241 	/*
2242 	 * Map descriptors from the buffer pools for <channel>.
2243 	 */
2244 
2245 	/*
2246 	 * Set up and prepare buffer blocks, descriptors
2247 	 * and mailbox.
2248 	 */
2249 	status = nxge_map_txdma_channel(nxgep, channel,
2250 	    pData, pRing, num_chunks, pControl, mailbox);
2251 	if (status != NXGE_OK) {
2252 		NXGE_ERROR_MSG((nxgep, MEM3_CTL,
2253 		    "==> nxge_map_txdma(%d): nxge_map_txdma_channel() "
2254 		    "returned 0x%x",
2255 		    nxgep, channel, status));
2256 		return (status);
2257 	}
2258 
2259 	ring = *pRing;
2260 
2261 	ring->index = (uint16_t)channel;
2262 	ring->tdc_stats = &nxgep->statsp->tdc_stats[channel];
2263 
2264 #if defined(sun4v) && defined(NIU_LP_WORKAROUND)
2265 	if (isLDOMguest(nxgep)) {
2266 		(void) nxge_tdc_lp_conf(nxgep, channel);
2267 	} else {
2268 		nxge_tdc_hvio_setup(nxgep, channel);
2269 	}
2270 #endif
2271 
2272 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: "
2273 	    "(status 0x%x channel %d)", status, channel));
2274 
2275 	return (status);
2276 }
2277 
2278 static nxge_status_t
2279 nxge_map_txdma_channel(p_nxge_t nxgep, uint16_t channel,
2280 	p_nxge_dma_common_t *dma_buf_p,
2281 	p_tx_ring_t *tx_desc_p,
2282 	uint32_t num_chunks,
2283 	p_nxge_dma_common_t *dma_cntl_p,
2284 	p_tx_mbox_t *tx_mbox_p)
2285 {
2286 	int	status = NXGE_OK;
2287 
2288 	/*
2289 	 * Set up and prepare buffer blocks, descriptors
2290 	 * and mailbox.
2291 	 */
2292 	NXGE_ERROR_MSG((nxgep, MEM3_CTL,
2293 	    "==> nxge_map_txdma_channel (channel %d)", channel));
2294 	/*
2295 	 * Transmit buffer blocks
2296 	 */
2297 	status = nxge_map_txdma_channel_buf_ring(nxgep, channel,
2298 	    dma_buf_p, tx_desc_p, num_chunks);
2299 	if (status != NXGE_OK) {
2300 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2301 		    "==> nxge_map_txdma_channel (channel %d): "
2302 		    "map buffer failed 0x%x", channel, status));
2303 		goto nxge_map_txdma_channel_exit;
2304 	}
2305 
2306 	/*
2307 	 * Transmit block ring, and mailbox.
2308 	 */
2309 	nxge_map_txdma_channel_cfg_ring(nxgep, channel, dma_cntl_p, *tx_desc_p,
2310 	    tx_mbox_p);
2311 
2312 	goto nxge_map_txdma_channel_exit;
2313 
2314 nxge_map_txdma_channel_fail1:
2315 	NXGE_ERROR_MSG((nxgep, MEM3_CTL,
2316 	    "==> nxge_map_txdma_channel: unmap buf"
2317 	    "(status 0x%x channel %d)",
2318 	    status, channel));
2319 	nxge_unmap_txdma_channel_buf_ring(nxgep, *tx_desc_p);
2320 
2321 nxge_map_txdma_channel_exit:
2322 	NXGE_ERROR_MSG((nxgep, MEM3_CTL,
2323 	    "<== nxge_map_txdma_channel: "
2324 	    "(status 0x%x channel %d)",
2325 	    status, channel));
2326 
2327 	return (status);
2328 }
2329 
2330 /*ARGSUSED*/
2331 static void
2332 nxge_unmap_txdma_channel(p_nxge_t nxgep, uint16_t channel)
2333 {
2334 	tx_ring_t *ring;
2335 	tx_mbox_t *mailbox;
2336 
2337 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2338 	    "==> nxge_unmap_txdma_channel (channel %d)", channel));
2339 	/*
2340 	 * unmap tx block ring, and mailbox.
2341 	 */
2342 	ring = nxgep->tx_rings->rings[channel];
2343 	mailbox = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
2344 
2345 	(void) nxge_unmap_txdma_channel_cfg_ring(nxgep, ring, mailbox);
2346 
2347 	/* unmap buffer blocks */
2348 	(void) nxge_unmap_txdma_channel_buf_ring(nxgep, ring);
2349 
2350 	nxge_free_txb(nxgep, channel);
2351 
2352 	/*
2353 	 * Cleanup the reference to the ring now that it does not exist.
2354 	 */
2355 	nxgep->tx_rings->rings[channel] = NULL;
2356 
2357 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_unmap_txdma_channel"));
2358 }
2359 
2360 /*
2361  * nxge_map_txdma_channel_cfg_ring
2362  *
2363  *	Map a TDC into our kernel space.
2364  *	This function allocates all of the per-channel data structures.
2365  *
2366  * Arguments:
2367  * 	nxgep
2368  * 	dma_channel	The channel to map.
2369  *	dma_cntl_p
2370  *	tx_ring_p	dma_channel's transmit ring
2371  *	tx_mbox_p	dma_channel's mailbox
2372  *
2373  * Notes:
2374  *
2375  * NPI/NXGE function calls:
2376  *	nxge_setup_dma_common()
2377  *
2378  * Registers accessed:
2379  *	none.
2380  *
2381  * Context:
2382  *	Any domain
2383  */
2384 /*ARGSUSED*/
2385 static void
2386 nxge_map_txdma_channel_cfg_ring(p_nxge_t nxgep, uint16_t dma_channel,
2387 	p_nxge_dma_common_t *dma_cntl_p,
2388 	p_tx_ring_t tx_ring_p,
2389 	p_tx_mbox_t *tx_mbox_p)
2390 {
2391 	p_tx_mbox_t 		mboxp;
2392 	p_nxge_dma_common_t 	cntl_dmap;
2393 	p_nxge_dma_common_t 	dmap;
2394 	p_tx_rng_cfig_t		tx_ring_cfig_p;
2395 	p_tx_ring_kick_t	tx_ring_kick_p;
2396 	p_tx_cs_t		tx_cs_p;
2397 	p_tx_dma_ent_msk_t	tx_evmask_p;
2398 	p_txdma_mbh_t		mboxh_p;
2399 	p_txdma_mbl_t		mboxl_p;
2400 	uint64_t		tx_desc_len;
2401 
2402 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2403 	    "==> nxge_map_txdma_channel_cfg_ring"));
2404 
2405 	cntl_dmap = *dma_cntl_p;
2406 
2407 	dmap = (p_nxge_dma_common_t)&tx_ring_p->tdc_desc;
2408 	nxge_setup_dma_common(dmap, cntl_dmap, tx_ring_p->tx_ring_size,
2409 	    sizeof (tx_desc_t));
2410 	/*
2411 	 * Zero out transmit ring descriptors.
2412 	 */
2413 	bzero((caddr_t)dmap->kaddrp, dmap->alength);
2414 	tx_ring_cfig_p = &(tx_ring_p->tx_ring_cfig);
2415 	tx_ring_kick_p = &(tx_ring_p->tx_ring_kick);
2416 	tx_cs_p = &(tx_ring_p->tx_cs);
2417 	tx_evmask_p = &(tx_ring_p->tx_evmask);
2418 	tx_ring_cfig_p->value = 0;
2419 	tx_ring_kick_p->value = 0;
2420 	tx_cs_p->value = 0;
2421 	tx_evmask_p->value = 0;
2422 
2423 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2424 	    "==> nxge_map_txdma_channel_cfg_ring: channel %d des $%p",
2425 	    dma_channel,
2426 	    dmap->dma_cookie.dmac_laddress));
2427 
2428 	tx_ring_cfig_p->value = 0;
2429 	tx_desc_len = (uint64_t)(tx_ring_p->tx_ring_size >> 3);
2430 	tx_ring_cfig_p->value =
2431 	    (dmap->dma_cookie.dmac_laddress & TX_RNG_CFIG_ADDR_MASK) |
2432 	    (tx_desc_len << TX_RNG_CFIG_LEN_SHIFT);
2433 
2434 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2435 	    "==> nxge_map_txdma_channel_cfg_ring: channel %d cfg 0x%llx",
2436 	    dma_channel,
2437 	    tx_ring_cfig_p->value));
2438 
2439 	tx_cs_p->bits.ldw.rst = 1;
2440 
2441 	/* Map in mailbox */
2442 	mboxp = (p_tx_mbox_t)
2443 	    KMEM_ZALLOC(sizeof (tx_mbox_t), KM_SLEEP);
2444 	dmap = (p_nxge_dma_common_t)&mboxp->tx_mbox;
2445 	nxge_setup_dma_common(dmap, cntl_dmap, 1, sizeof (txdma_mailbox_t));
2446 	mboxh_p = (p_txdma_mbh_t)&tx_ring_p->tx_mbox_mbh;
2447 	mboxl_p = (p_txdma_mbl_t)&tx_ring_p->tx_mbox_mbl;
2448 	mboxh_p->value = mboxl_p->value = 0;
2449 
2450 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2451 	    "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
2452 	    dmap->dma_cookie.dmac_laddress));
2453 
2454 	mboxh_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress >>
2455 	    TXDMA_MBH_ADDR_SHIFT) & TXDMA_MBH_MASK);
2456 
2457 	mboxl_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress &
2458 	    TXDMA_MBL_MASK) >> TXDMA_MBL_SHIFT);
2459 
2460 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2461 	    "==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
2462 	    dmap->dma_cookie.dmac_laddress));
2463 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2464 	    "==> nxge_map_txdma_channel_cfg_ring: hmbox $%p "
2465 	    "mbox $%p",
2466 	    mboxh_p->bits.ldw.mbaddr, mboxl_p->bits.ldw.mbaddr));
2467 	tx_ring_p->page_valid.value = 0;
2468 	tx_ring_p->page_mask_1.value = tx_ring_p->page_mask_2.value = 0;
2469 	tx_ring_p->page_value_1.value = tx_ring_p->page_value_2.value = 0;
2470 	tx_ring_p->page_reloc_1.value = tx_ring_p->page_reloc_2.value = 0;
2471 	tx_ring_p->page_hdl.value = 0;
2472 
2473 	tx_ring_p->page_valid.bits.ldw.page0 = 1;
2474 	tx_ring_p->page_valid.bits.ldw.page1 = 1;
2475 
2476 	tx_ring_p->max_burst.value = 0;
2477 	tx_ring_p->max_burst.bits.ldw.dma_max_burst = TXC_DMA_MAX_BURST_DEFAULT;
2478 
2479 	*tx_mbox_p = mboxp;
2480 
2481 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2482 	    "<== nxge_map_txdma_channel_cfg_ring"));
2483 }
2484 
2485 /*ARGSUSED*/
2486 static void
2487 nxge_unmap_txdma_channel_cfg_ring(p_nxge_t nxgep,
2488 	p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p)
2489 {
2490 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2491 	    "==> nxge_unmap_txdma_channel_cfg_ring: channel %d",
2492 	    tx_ring_p->tdc));
2493 
2494 	KMEM_FREE(tx_mbox_p, sizeof (tx_mbox_t));
2495 
2496 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2497 	    "<== nxge_unmap_txdma_channel_cfg_ring"));
2498 }
2499 
2500 /*
2501  * nxge_map_txdma_channel_buf_ring
2502  *
2503  *
2504  * Arguments:
2505  * 	nxgep
2506  * 	channel		The channel to map.
2507  *	dma_buf_p
2508  *	tx_desc_p	channel's descriptor ring
2509  *	num_chunks
2510  *
2511  * Notes:
2512  *
2513  * NPI/NXGE function calls:
2514  *	nxge_setup_dma_common()
2515  *
2516  * Registers accessed:
2517  *	none.
2518  *
2519  * Context:
2520  *	Any domain
2521  */
2522 static nxge_status_t
2523 nxge_map_txdma_channel_buf_ring(p_nxge_t nxgep, uint16_t channel,
2524 	p_nxge_dma_common_t *dma_buf_p,
2525 	p_tx_ring_t *tx_desc_p, uint32_t num_chunks)
2526 {
2527 	p_nxge_dma_common_t 	dma_bufp, tmp_bufp;
2528 	p_nxge_dma_common_t 	dmap;
2529 	nxge_os_dma_handle_t	tx_buf_dma_handle;
2530 	p_tx_ring_t 		tx_ring_p;
2531 	p_tx_msg_t 		tx_msg_ring;
2532 	nxge_status_t		status = NXGE_OK;
2533 	int			ddi_status = DDI_SUCCESS;
2534 	int			i, j, index;
2535 	uint32_t		size, bsize;
2536 	uint32_t 		nblocks, nmsgs;
2537 	char			qname[TASKQ_NAMELEN];
2538 
2539 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2540 	    "==> nxge_map_txdma_channel_buf_ring"));
2541 
2542 	dma_bufp = tmp_bufp = *dma_buf_p;
2543 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2544 		" nxge_map_txdma_channel_buf_ring: channel %d to map %d "
2545 		"chunks bufp $%p",
2546 		    channel, num_chunks, dma_bufp));
2547 
2548 	nmsgs = 0;
2549 	for (i = 0; i < num_chunks; i++, tmp_bufp++) {
2550 		nmsgs += tmp_bufp->nblocks;
2551 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2552 		    "==> nxge_map_txdma_channel_buf_ring: channel %d "
2553 		    "bufp $%p nblocks %d nmsgs %d",
2554 		    channel, tmp_bufp, tmp_bufp->nblocks, nmsgs));
2555 	}
2556 	if (!nmsgs) {
2557 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2558 		    "<== nxge_map_txdma_channel_buf_ring: channel %d "
2559 		    "no msg blocks",
2560 		    channel));
2561 		status = NXGE_ERROR;
2562 		goto nxge_map_txdma_channel_buf_ring_exit;
2563 	}
2564 
2565 	tx_ring_p = (p_tx_ring_t)
2566 	    KMEM_ZALLOC(sizeof (tx_ring_t), KM_SLEEP);
2567 	MUTEX_INIT(&tx_ring_p->lock, NULL, MUTEX_DRIVER,
2568 	    (void *)nxgep->interrupt_cookie);
2569 
2570 	(void) atomic_swap_32(&tx_ring_p->tx_ring_offline, NXGE_TX_RING_ONLINE);
2571 	tx_ring_p->tx_ring_busy = B_FALSE;
2572 	tx_ring_p->nxgep = nxgep;
2573 	tx_ring_p->tx_ring_handle = (mac_ring_handle_t)NULL;
2574 	(void) snprintf(qname, TASKQ_NAMELEN, "tx_%d_%d",
2575 	    nxgep->instance, channel);
2576 	tx_ring_p->taskq = ddi_taskq_create(nxgep->dip, qname, 1,
2577 	    TASKQ_DEFAULTPRI, 0);
2578 	if (tx_ring_p->taskq == NULL) {
2579 		goto nxge_map_txdma_channel_buf_ring_fail1;
2580 	}
2581 
2582 	/*
2583 	 * Allocate transmit message rings and handles for packets
2584 	 * not to be copied to premapped buffers.
2585 	 */
2586 	size = nmsgs * sizeof (tx_msg_t);
2587 	tx_msg_ring = KMEM_ZALLOC(size, KM_SLEEP);
2588 	for (i = 0; i < nmsgs; i++) {
2589 		ddi_status = ddi_dma_alloc_handle(nxgep->dip, &nxge_tx_dma_attr,
2590 		    DDI_DMA_DONTWAIT, 0,
2591 		    &tx_msg_ring[i].dma_handle);
2592 		if (ddi_status != DDI_SUCCESS) {
2593 			status |= NXGE_DDI_FAILED;
2594 			break;
2595 		}
2596 	}
2597 	if (i < nmsgs) {
2598 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2599 		    "Allocate handles failed."));
2600 		goto nxge_map_txdma_channel_buf_ring_fail1;
2601 	}
2602 
2603 	tx_ring_p->tdc = channel;
2604 	tx_ring_p->tx_msg_ring = tx_msg_ring;
2605 	tx_ring_p->tx_ring_size = nmsgs;
2606 	tx_ring_p->num_chunks = num_chunks;
2607 	if (!nxge_tx_intr_thres) {
2608 		nxge_tx_intr_thres = tx_ring_p->tx_ring_size/4;
2609 	}
2610 	tx_ring_p->tx_wrap_mask = tx_ring_p->tx_ring_size - 1;
2611 	tx_ring_p->rd_index = 0;
2612 	tx_ring_p->wr_index = 0;
2613 	tx_ring_p->ring_head.value = 0;
2614 	tx_ring_p->ring_kick_tail.value = 0;
2615 	tx_ring_p->descs_pending = 0;
2616 
2617 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2618 	    "==> nxge_map_txdma_channel_buf_ring: channel %d "
2619 	    "actual tx desc max %d nmsgs %d "
2620 	    "(config nxge_tx_ring_size %d)",
2621 	    channel, tx_ring_p->tx_ring_size, nmsgs,
2622 	    nxge_tx_ring_size));
2623 
2624 	/*
2625 	 * Map in buffers from the buffer pool.
2626 	 */
2627 	index = 0;
2628 	bsize = dma_bufp->block_size;
2629 
2630 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel_buf_ring: "
2631 	    "dma_bufp $%p tx_rng_p $%p "
2632 	    "tx_msg_rng_p $%p bsize %d",
2633 	    dma_bufp, tx_ring_p, tx_msg_ring, bsize));
2634 
2635 	tx_buf_dma_handle = dma_bufp->dma_handle;
2636 	for (i = 0; i < num_chunks; i++, dma_bufp++) {
2637 		bsize = dma_bufp->block_size;
2638 		nblocks = dma_bufp->nblocks;
2639 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2640 		    "==> nxge_map_txdma_channel_buf_ring: dma chunk %d "
2641 		    "size %d dma_bufp $%p",
2642 		    i, sizeof (nxge_dma_common_t), dma_bufp));
2643 
2644 		for (j = 0; j < nblocks; j++) {
2645 			tx_msg_ring[index].buf_dma_handle = tx_buf_dma_handle;
2646 			dmap = &tx_msg_ring[index++].buf_dma;
2647 #ifdef TX_MEM_DEBUG
2648 			NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2649 			    "==> nxge_map_txdma_channel_buf_ring: j %d"
2650 			    "dmap $%p", i, dmap));
2651 #endif
2652 			nxge_setup_dma_common(dmap, dma_bufp, 1,
2653 			    bsize);
2654 		}
2655 	}
2656 
2657 	if (i < num_chunks) {
2658 		status = NXGE_ERROR;
2659 		goto nxge_map_txdma_channel_buf_ring_fail1;
2660 	}
2661 
2662 	*tx_desc_p = tx_ring_p;
2663 
2664 	goto nxge_map_txdma_channel_buf_ring_exit;
2665 
2666 nxge_map_txdma_channel_buf_ring_fail1:
2667 	if (tx_ring_p->taskq) {
2668 		ddi_taskq_destroy(tx_ring_p->taskq);
2669 		tx_ring_p->taskq = NULL;
2670 	}
2671 
2672 	index--;
2673 	for (; index >= 0; index--) {
2674 		if (tx_msg_ring[index].dma_handle != NULL) {
2675 			ddi_dma_free_handle(&tx_msg_ring[index].dma_handle);
2676 		}
2677 	}
2678 	MUTEX_DESTROY(&tx_ring_p->lock);
2679 	KMEM_FREE(tx_msg_ring, size);
2680 	KMEM_FREE(tx_ring_p, sizeof (tx_ring_t));
2681 
2682 	status = NXGE_ERROR;
2683 
2684 nxge_map_txdma_channel_buf_ring_exit:
2685 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2686 	    "<== nxge_map_txdma_channel_buf_ring status 0x%x", status));
2687 
2688 	return (status);
2689 }
2690 
2691 /*ARGSUSED*/
2692 static void
2693 nxge_unmap_txdma_channel_buf_ring(p_nxge_t nxgep, p_tx_ring_t tx_ring_p)
2694 {
2695 	p_tx_msg_t 		tx_msg_ring;
2696 	p_tx_msg_t 		tx_msg_p;
2697 	int			i;
2698 
2699 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2700 	    "==> nxge_unmap_txdma_channel_buf_ring"));
2701 	if (tx_ring_p == NULL) {
2702 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
2703 		    "<== nxge_unmap_txdma_channel_buf_ring: NULL ringp"));
2704 		return;
2705 	}
2706 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2707 	    "==> nxge_unmap_txdma_channel_buf_ring: channel %d",
2708 	    tx_ring_p->tdc));
2709 
2710 	tx_msg_ring = tx_ring_p->tx_msg_ring;
2711 
2712 	/*
2713 	 * Since the serialization thread, timer thread and
2714 	 * interrupt thread can all call the transmit reclaim,
2715 	 * the unmapping function needs to acquire the lock
2716 	 * to free those buffers which were transmitted
2717 	 * by the hardware already.
2718 	 */
2719 	MUTEX_ENTER(&tx_ring_p->lock);
2720 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
2721 	    "==> nxge_unmap_txdma_channel_buf_ring (reclaim): "
2722 	    "channel %d",
2723 	    tx_ring_p->tdc));
2724 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
2725 
2726 	for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
2727 		tx_msg_p = &tx_msg_ring[i];
2728 		if (tx_msg_p->tx_message != NULL) {
2729 			freemsg(tx_msg_p->tx_message);
2730 			tx_msg_p->tx_message = NULL;
2731 		}
2732 	}
2733 
2734 	for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
2735 		if (tx_msg_ring[i].dma_handle != NULL) {
2736 			ddi_dma_free_handle(&tx_msg_ring[i].dma_handle);
2737 		}
2738 		tx_msg_ring[i].dma_handle = NULL;
2739 	}
2740 
2741 	MUTEX_EXIT(&tx_ring_p->lock);
2742 
2743 	if (tx_ring_p->taskq) {
2744 		ddi_taskq_destroy(tx_ring_p->taskq);
2745 		tx_ring_p->taskq = NULL;
2746 	}
2747 
2748 	MUTEX_DESTROY(&tx_ring_p->lock);
2749 	KMEM_FREE(tx_msg_ring, sizeof (tx_msg_t) * tx_ring_p->tx_ring_size);
2750 	KMEM_FREE(tx_ring_p, sizeof (tx_ring_t));
2751 
2752 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2753 	    "<== nxge_unmap_txdma_channel_buf_ring"));
2754 }
2755 
2756 static nxge_status_t
2757 nxge_txdma_hw_start(p_nxge_t nxgep, int channel)
2758 {
2759 	p_tx_rings_t 		tx_rings;
2760 	p_tx_ring_t 		*tx_desc_rings;
2761 	p_tx_mbox_areas_t 	tx_mbox_areas_p;
2762 	p_tx_mbox_t		*tx_mbox_p;
2763 	nxge_status_t		status = NXGE_OK;
2764 
2765 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start"));
2766 
2767 	tx_rings = nxgep->tx_rings;
2768 	if (tx_rings == NULL) {
2769 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
2770 		    "<== nxge_txdma_hw_start: NULL ring pointer"));
2771 		return (NXGE_ERROR);
2772 	}
2773 	tx_desc_rings = tx_rings->rings;
2774 	if (tx_desc_rings == NULL) {
2775 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
2776 		    "<== nxge_txdma_hw_start: NULL ring pointers"));
2777 		return (NXGE_ERROR);
2778 	}
2779 
2780 	NXGE_ERROR_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
2781 	    "tx_rings $%p tx_desc_rings $%p", tx_rings, tx_desc_rings));
2782 
2783 	tx_mbox_areas_p = nxgep->tx_mbox_areas_p;
2784 	tx_mbox_p = tx_mbox_areas_p->txmbox_areas_p;
2785 
2786 	status = nxge_txdma_start_channel(nxgep, channel,
2787 	    (p_tx_ring_t)tx_desc_rings[channel],
2788 	    (p_tx_mbox_t)tx_mbox_p[channel]);
2789 	if (status != NXGE_OK) {
2790 		goto nxge_txdma_hw_start_fail1;
2791 	}
2792 
2793 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
2794 	    "tx_rings $%p rings $%p",
2795 	    nxgep->tx_rings, nxgep->tx_rings->rings));
2796 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
2797 	    "tx_rings $%p tx_desc_rings $%p",
2798 	    nxgep->tx_rings, tx_desc_rings));
2799 
2800 	goto nxge_txdma_hw_start_exit;
2801 
2802 nxge_txdma_hw_start_fail1:
2803 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2804 	    "==> nxge_txdma_hw_start: disable "
2805 	    "(status 0x%x channel %d)", status, channel));
2806 
2807 nxge_txdma_hw_start_exit:
2808 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2809 	    "==> nxge_txdma_hw_start: (status 0x%x)", status));
2810 
2811 	return (status);
2812 }
2813 
2814 /*
2815  * nxge_txdma_start_channel
2816  *
2817  *	Start a TDC.
2818  *
2819  * Arguments:
2820  * 	nxgep
2821  * 	channel		The channel to start.
2822  * 	tx_ring_p	channel's transmit descriptor ring.
2823  * 	tx_mbox_p	channel' smailbox.
2824  *
2825  * Notes:
2826  *
2827  * NPI/NXGE function calls:
2828  *	nxge_reset_txdma_channel()
2829  *	nxge_init_txdma_channel_event_mask()
2830  *	nxge_enable_txdma_channel()
2831  *
2832  * Registers accessed:
2833  *	none directly (see functions above).
2834  *
2835  * Context:
2836  *	Any domain
2837  */
2838 static nxge_status_t
2839 nxge_txdma_start_channel(p_nxge_t nxgep, uint16_t channel,
2840     p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p)
2841 
2842 {
2843 	nxge_status_t		status = NXGE_OK;
2844 
2845 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2846 		"==> nxge_txdma_start_channel (channel %d)", channel));
2847 	/*
2848 	 * TXDMA/TXC must be in stopped state.
2849 	 */
2850 	(void) nxge_txdma_stop_inj_err(nxgep, channel);
2851 
2852 	/*
2853 	 * Reset TXDMA channel
2854 	 */
2855 	tx_ring_p->tx_cs.value = 0;
2856 	tx_ring_p->tx_cs.bits.ldw.rst = 1;
2857 	status = nxge_reset_txdma_channel(nxgep, channel,
2858 			tx_ring_p->tx_cs.value);
2859 	if (status != NXGE_OK) {
2860 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2861 			"==> nxge_txdma_start_channel (channel %d)"
2862 			" reset channel failed 0x%x", channel, status));
2863 		goto nxge_txdma_start_channel_exit;
2864 	}
2865 
2866 	/*
2867 	 * Initialize the TXDMA channel specific FZC control
2868 	 * configurations. These FZC registers are pertaining
2869 	 * to each TX channel (i.e. logical pages).
2870 	 */
2871 	if (!isLDOMguest(nxgep)) {
2872 		status = nxge_init_fzc_txdma_channel(nxgep, channel,
2873 		    tx_ring_p, tx_mbox_p);
2874 		if (status != NXGE_OK) {
2875 			goto nxge_txdma_start_channel_exit;
2876 		}
2877 	}
2878 
2879 	/*
2880 	 * Initialize the event masks.
2881 	 */
2882 	tx_ring_p->tx_evmask.value = 0;
2883 	status = nxge_init_txdma_channel_event_mask(nxgep,
2884 	    channel, &tx_ring_p->tx_evmask);
2885 	if (status != NXGE_OK) {
2886 		goto nxge_txdma_start_channel_exit;
2887 	}
2888 
2889 	/*
2890 	 * Load TXDMA descriptors, buffers, mailbox,
2891 	 * initialise the DMA channels and
2892 	 * enable each DMA channel.
2893 	 */
2894 	status = nxge_enable_txdma_channel(nxgep, channel,
2895 			tx_ring_p, tx_mbox_p);
2896 	if (status != NXGE_OK) {
2897 		goto nxge_txdma_start_channel_exit;
2898 	}
2899 
2900 nxge_txdma_start_channel_exit:
2901 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_start_channel"));
2902 
2903 	return (status);
2904 }
2905 
2906 /*
2907  * nxge_txdma_stop_channel
2908  *
2909  *	Stop a TDC.
2910  *
2911  * Arguments:
2912  * 	nxgep
2913  * 	channel		The channel to stop.
2914  * 	tx_ring_p	channel's transmit descriptor ring.
2915  * 	tx_mbox_p	channel' smailbox.
2916  *
2917  * Notes:
2918  *
2919  * NPI/NXGE function calls:
2920  *	nxge_txdma_stop_inj_err()
2921  *	nxge_reset_txdma_channel()
2922  *	nxge_init_txdma_channel_event_mask()
2923  *	nxge_init_txdma_channel_cntl_stat()
2924  *	nxge_disable_txdma_channel()
2925  *
2926  * Registers accessed:
2927  *	none directly (see functions above).
2928  *
2929  * Context:
2930  *	Any domain
2931  */
2932 /*ARGSUSED*/
2933 static nxge_status_t
2934 nxge_txdma_stop_channel(p_nxge_t nxgep, uint16_t channel)
2935 {
2936 	p_tx_ring_t tx_ring_p;
2937 	int status = NXGE_OK;
2938 
2939 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2940 	    "==> nxge_txdma_stop_channel: channel %d", channel));
2941 
2942 	/*
2943 	 * Stop (disable) TXDMA and TXC (if stop bit is set
2944 	 * and STOP_N_GO bit not set, the TXDMA reset state will
2945 	 * not be set if reset TXDMA.
2946 	 */
2947 	(void) nxge_txdma_stop_inj_err(nxgep, channel);
2948 
2949 	tx_ring_p = nxgep->tx_rings->rings[channel];
2950 
2951 	/*
2952 	 * Reset TXDMA channel
2953 	 */
2954 	tx_ring_p->tx_cs.value = 0;
2955 	tx_ring_p->tx_cs.bits.ldw.rst = 1;
2956 	status = nxge_reset_txdma_channel(nxgep, channel,
2957 	    tx_ring_p->tx_cs.value);
2958 	if (status != NXGE_OK) {
2959 		goto nxge_txdma_stop_channel_exit;
2960 	}
2961 
2962 #ifdef HARDWARE_REQUIRED
2963 	/* Set up the interrupt event masks. */
2964 	tx_ring_p->tx_evmask.value = 0;
2965 	status = nxge_init_txdma_channel_event_mask(nxgep,
2966 	    channel, &tx_ring_p->tx_evmask);
2967 	if (status != NXGE_OK) {
2968 		goto nxge_txdma_stop_channel_exit;
2969 	}
2970 
2971 	/* Initialize the DMA control and status register */
2972 	tx_ring_p->tx_cs.value = TX_ENT_MSK_MK_ALL;
2973 	status = nxge_init_txdma_channel_cntl_stat(nxgep, channel,
2974 	    tx_ring_p->tx_cs.value);
2975 	if (status != NXGE_OK) {
2976 		goto nxge_txdma_stop_channel_exit;
2977 	}
2978 
2979 	tx_mbox_p = nxgep->tx_mbox_areas_p->txmbox_areas_p[channel];
2980 
2981 	/* Disable channel */
2982 	status = nxge_disable_txdma_channel(nxgep, channel,
2983 	    tx_ring_p, tx_mbox_p);
2984 	if (status != NXGE_OK) {
2985 		goto nxge_txdma_start_channel_exit;
2986 	}
2987 
2988 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
2989 	    "==> nxge_txdma_stop_channel: event done"));
2990 
2991 #endif
2992 
2993 nxge_txdma_stop_channel_exit:
2994 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_stop_channel"));
2995 	return (status);
2996 }
2997 
2998 /*
2999  * nxge_txdma_get_ring
3000  *
3001  *	Get the ring for a TDC.
3002  *
3003  * Arguments:
3004  * 	nxgep
3005  * 	channel
3006  *
3007  * Notes:
3008  *
3009  * NPI/NXGE function calls:
3010  *
3011  * Registers accessed:
3012  *
3013  * Context:
3014  *	Any domain
3015  */
3016 static p_tx_ring_t
3017 nxge_txdma_get_ring(p_nxge_t nxgep, uint16_t channel)
3018 {
3019 	nxge_grp_set_t *set = &nxgep->tx_set;
3020 	int tdc;
3021 
3022 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_ring"));
3023 
3024 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
3025 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3026 		    "<== nxge_txdma_get_ring: NULL ring pointer(s)"));
3027 		goto return_null;
3028 	}
3029 
3030 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3031 		if ((1 << tdc) & set->owned.map) {
3032 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3033 			if (ring) {
3034 				if (channel == ring->tdc) {
3035 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
3036 					    "<== nxge_txdma_get_ring: "
3037 					    "tdc %d ring $%p", tdc, ring));
3038 					return (ring);
3039 				}
3040 			}
3041 		}
3042 	}
3043 
3044 return_null:
3045 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_ring: "
3046 	    "ring not found"));
3047 
3048 	return (NULL);
3049 }
3050 
3051 /*
3052  * nxge_txdma_get_mbox
3053  *
3054  *	Get the mailbox for a TDC.
3055  *
3056  * Arguments:
3057  * 	nxgep
3058  * 	channel
3059  *
3060  * Notes:
3061  *
3062  * NPI/NXGE function calls:
3063  *
3064  * Registers accessed:
3065  *
3066  * Context:
3067  *	Any domain
3068  */
3069 static p_tx_mbox_t
3070 nxge_txdma_get_mbox(p_nxge_t nxgep, uint16_t channel)
3071 {
3072 	nxge_grp_set_t *set = &nxgep->tx_set;
3073 	int tdc;
3074 
3075 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_mbox"));
3076 
3077 	if (nxgep->tx_mbox_areas_p == 0 ||
3078 	    nxgep->tx_mbox_areas_p->txmbox_areas_p == 0) {
3079 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3080 		    "<== nxge_txdma_get_mbox: NULL mailbox pointer(s)"));
3081 		goto return_null;
3082 	}
3083 
3084 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
3085 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3086 		    "<== nxge_txdma_get_mbox: NULL ring pointer(s)"));
3087 		goto return_null;
3088 	}
3089 
3090 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3091 		if ((1 << tdc) & set->owned.map) {
3092 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3093 			if (ring) {
3094 				if (channel == ring->tdc) {
3095 					tx_mbox_t *mailbox = nxgep->
3096 					    tx_mbox_areas_p->
3097 					    txmbox_areas_p[tdc];
3098 					NXGE_DEBUG_MSG((nxgep, TX_CTL,
3099 					    "<== nxge_txdma_get_mbox: tdc %d "
3100 					    "ring $%p", tdc, mailbox));
3101 					return (mailbox);
3102 				}
3103 			}
3104 		}
3105 	}
3106 
3107 return_null:
3108 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_mbox: "
3109 	    "mailbox not found"));
3110 
3111 	return (NULL);
3112 }
3113 
3114 /*
3115  * nxge_tx_err_evnts
3116  *
3117  *	Recover a TDC.
3118  *
3119  * Arguments:
3120  * 	nxgep
3121  * 	index	The index to the TDC ring.
3122  * 	ldvp	Used to get the channel number ONLY.
3123  * 	cs	A copy of the bits from TX_CS.
3124  *
3125  * Notes:
3126  *	Calling tree:
3127  *	 nxge_tx_intr()
3128  *
3129  * NPI/NXGE function calls:
3130  *	npi_txdma_ring_error_get()
3131  *	npi_txdma_inj_par_error_get()
3132  *	nxge_txdma_fatal_err_recover()
3133  *
3134  * Registers accessed:
3135  *	TX_RNG_ERR_LOGH	DMC+0x40048 Transmit Ring Error Log High
3136  *	TX_RNG_ERR_LOGL DMC+0x40050 Transmit Ring Error Log Low
3137  *	TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error
3138  *
3139  * Context:
3140  *	Any domain	XXX Remove code which accesses TDMC_INJ_PAR_ERR.
3141  */
3142 /*ARGSUSED*/
3143 static nxge_status_t
3144 nxge_tx_err_evnts(p_nxge_t nxgep, uint_t index, p_nxge_ldv_t ldvp, tx_cs_t cs)
3145 {
3146 	npi_handle_t		handle;
3147 	npi_status_t		rs;
3148 	uint8_t			channel;
3149 	p_tx_ring_t 		*tx_rings;
3150 	p_tx_ring_t 		tx_ring_p;
3151 	p_nxge_tx_ring_stats_t	tdc_stats;
3152 	boolean_t		txchan_fatal = B_FALSE;
3153 	nxge_status_t		status = NXGE_OK;
3154 	tdmc_inj_par_err_t	par_err;
3155 	uint32_t		value;
3156 
3157 	NXGE_DEBUG_MSG((nxgep, TX2_CTL, "==> nxge_tx_err_evnts"));
3158 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
3159 	channel = ldvp->channel;
3160 
3161 	tx_rings = nxgep->tx_rings->rings;
3162 	tx_ring_p = tx_rings[index];
3163 	tdc_stats = tx_ring_p->tdc_stats;
3164 	if ((cs.bits.ldw.pkt_size_err) || (cs.bits.ldw.pref_buf_par_err) ||
3165 	    (cs.bits.ldw.nack_pref) || (cs.bits.ldw.nack_pkt_rd) ||
3166 	    (cs.bits.ldw.conf_part_err) || (cs.bits.ldw.pkt_prt_err)) {
3167 		if ((rs = npi_txdma_ring_error_get(handle, channel,
3168 		    &tdc_stats->errlog)) != NPI_SUCCESS)
3169 			return (NXGE_ERROR | rs);
3170 	}
3171 
3172 	if (cs.bits.ldw.mbox_err) {
3173 		tdc_stats->mbox_err++;
3174 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3175 		    NXGE_FM_EREPORT_TDMC_MBOX_ERR);
3176 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3177 		    "==> nxge_tx_err_evnts(channel %d): "
3178 		    "fatal error: mailbox", channel));
3179 		txchan_fatal = B_TRUE;
3180 	}
3181 	if (cs.bits.ldw.pkt_size_err) {
3182 		tdc_stats->pkt_size_err++;
3183 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3184 		    NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR);
3185 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3186 		    "==> nxge_tx_err_evnts(channel %d): "
3187 		    "fatal error: pkt_size_err", channel));
3188 		txchan_fatal = B_TRUE;
3189 	}
3190 	if (cs.bits.ldw.tx_ring_oflow) {
3191 		tdc_stats->tx_ring_oflow++;
3192 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3193 		    NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW);
3194 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3195 		    "==> nxge_tx_err_evnts(channel %d): "
3196 		    "fatal error: tx_ring_oflow", channel));
3197 		txchan_fatal = B_TRUE;
3198 	}
3199 	if (cs.bits.ldw.pref_buf_par_err) {
3200 		tdc_stats->pre_buf_par_err++;
3201 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3202 		    NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR);
3203 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3204 		    "==> nxge_tx_err_evnts(channel %d): "
3205 		    "fatal error: pre_buf_par_err", channel));
3206 		/* Clear error injection source for parity error */
3207 		(void) npi_txdma_inj_par_error_get(handle, &value);
3208 		par_err.value = value;
3209 		par_err.bits.ldw.inject_parity_error &= ~(1 << channel);
3210 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
3211 		txchan_fatal = B_TRUE;
3212 	}
3213 	if (cs.bits.ldw.nack_pref) {
3214 		tdc_stats->nack_pref++;
3215 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3216 		    NXGE_FM_EREPORT_TDMC_NACK_PREF);
3217 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3218 		    "==> nxge_tx_err_evnts(channel %d): "
3219 		    "fatal error: nack_pref", channel));
3220 		txchan_fatal = B_TRUE;
3221 	}
3222 	if (cs.bits.ldw.nack_pkt_rd) {
3223 		tdc_stats->nack_pkt_rd++;
3224 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3225 		    NXGE_FM_EREPORT_TDMC_NACK_PKT_RD);
3226 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3227 		    "==> nxge_tx_err_evnts(channel %d): "
3228 		    "fatal error: nack_pkt_rd", channel));
3229 		txchan_fatal = B_TRUE;
3230 	}
3231 	if (cs.bits.ldw.conf_part_err) {
3232 		tdc_stats->conf_part_err++;
3233 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3234 		    NXGE_FM_EREPORT_TDMC_CONF_PART_ERR);
3235 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3236 		    "==> nxge_tx_err_evnts(channel %d): "
3237 		    "fatal error: config_partition_err", channel));
3238 		txchan_fatal = B_TRUE;
3239 	}
3240 	if (cs.bits.ldw.pkt_prt_err) {
3241 		tdc_stats->pkt_part_err++;
3242 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
3243 		    NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR);
3244 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3245 		    "==> nxge_tx_err_evnts(channel %d): "
3246 		    "fatal error: pkt_prt_err", channel));
3247 		txchan_fatal = B_TRUE;
3248 	}
3249 
3250 	/* Clear error injection source in case this is an injected error */
3251 	TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG, channel, 0);
3252 
3253 	if (txchan_fatal) {
3254 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3255 		    " nxge_tx_err_evnts: "
3256 		    " fatal error on channel %d cs 0x%llx\n",
3257 		    channel, cs.value));
3258 		status = nxge_txdma_fatal_err_recover(nxgep, channel,
3259 		    tx_ring_p);
3260 		if (status == NXGE_OK) {
3261 			FM_SERVICE_RESTORED(nxgep);
3262 		}
3263 	}
3264 
3265 	NXGE_DEBUG_MSG((nxgep, TX2_CTL, "<== nxge_tx_err_evnts"));
3266 
3267 	return (status);
3268 }
3269 
3270 static nxge_status_t
3271 nxge_txdma_fatal_err_recover(
3272 	p_nxge_t nxgep,
3273 	uint16_t channel,
3274 	p_tx_ring_t tx_ring_p)
3275 {
3276 	npi_handle_t	handle;
3277 	npi_status_t	rs = NPI_SUCCESS;
3278 	p_tx_mbox_t	tx_mbox_p;
3279 	nxge_status_t	status = NXGE_OK;
3280 
3281 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fatal_err_recover"));
3282 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3283 	    "Recovering from TxDMAChannel#%d error...", channel));
3284 
3285 	/*
3286 	 * Stop the dma channel waits for the stop done.
3287 	 * If the stop done bit is not set, then create
3288 	 * an error.
3289 	 */
3290 
3291 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
3292 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel stop..."));
3293 	MUTEX_ENTER(&tx_ring_p->lock);
3294 	rs = npi_txdma_channel_control(handle, TXDMA_STOP, channel);
3295 	if (rs != NPI_SUCCESS) {
3296 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3297 		    "==> nxge_txdma_fatal_err_recover (channel %d): "
3298 		    "stop failed ", channel));
3299 		goto fail;
3300 	}
3301 
3302 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reclaim..."));
3303 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
3304 
3305 	/*
3306 	 * Reset TXDMA channel
3307 	 */
3308 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reset..."));
3309 	if ((rs = npi_txdma_channel_control(handle, TXDMA_RESET, channel)) !=
3310 	    NPI_SUCCESS) {
3311 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3312 		    "==> nxge_txdma_fatal_err_recover (channel %d)"
3313 		    " reset channel failed 0x%x", channel, rs));
3314 		goto fail;
3315 	}
3316 
3317 	/*
3318 	 * Reset the tail (kick) register to 0.
3319 	 * (Hardware will not reset it. Tx overflow fatal
3320 	 * error if tail is not set to 0 after reset!
3321 	 */
3322 	TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0);
3323 
3324 	/* Restart TXDMA channel */
3325 
3326 	if (!isLDOMguest(nxgep)) {
3327 		tx_mbox_p = nxge_txdma_get_mbox(nxgep, channel);
3328 
3329 		// XXX This is a problem in HIO!
3330 		/*
3331 		 * Initialize the TXDMA channel specific FZC control
3332 		 * configurations. These FZC registers are pertaining
3333 		 * to each TX channel (i.e. logical pages).
3334 		 */
3335 		NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel restart..."));
3336 		status = nxge_init_fzc_txdma_channel(nxgep, channel,
3337 		    tx_ring_p, tx_mbox_p);
3338 		if (status != NXGE_OK)
3339 			goto fail;
3340 	}
3341 
3342 	/*
3343 	 * Initialize the event masks.
3344 	 */
3345 	tx_ring_p->tx_evmask.value = 0;
3346 	status = nxge_init_txdma_channel_event_mask(nxgep, channel,
3347 	    &tx_ring_p->tx_evmask);
3348 	if (status != NXGE_OK)
3349 		goto fail;
3350 
3351 	tx_ring_p->wr_index_wrap = B_FALSE;
3352 	tx_ring_p->wr_index = 0;
3353 	tx_ring_p->rd_index = 0;
3354 
3355 	/*
3356 	 * Load TXDMA descriptors, buffers, mailbox,
3357 	 * initialise the DMA channels and
3358 	 * enable each DMA channel.
3359 	 */
3360 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel enable..."));
3361 	status = nxge_enable_txdma_channel(nxgep, channel,
3362 	    tx_ring_p, tx_mbox_p);
3363 	MUTEX_EXIT(&tx_ring_p->lock);
3364 	if (status != NXGE_OK)
3365 		goto fail;
3366 
3367 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3368 	    "Recovery Successful, TxDMAChannel#%d Restored",
3369 	    channel));
3370 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fatal_err_recover"));
3371 
3372 	return (NXGE_OK);
3373 
3374 fail:
3375 	MUTEX_EXIT(&tx_ring_p->lock);
3376 
3377 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
3378 	    "nxge_txdma_fatal_err_recover (channel %d): "
3379 	    "failed to recover this txdma channel", channel));
3380 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed"));
3381 
3382 	return (status);
3383 }
3384 
3385 /*
3386  * nxge_tx_port_fatal_err_recover
3387  *
3388  *	Attempt to recover from a fatal port error.
3389  *
3390  * Arguments:
3391  * 	nxgep
3392  *
3393  * Notes:
3394  *	How would a guest do this?
3395  *
3396  * NPI/NXGE function calls:
3397  *
3398  * Registers accessed:
3399  *
3400  * Context:
3401  *	Service domain
3402  */
3403 nxge_status_t
3404 nxge_tx_port_fatal_err_recover(p_nxge_t nxgep)
3405 {
3406 	nxge_grp_set_t *set = &nxgep->tx_set;
3407 	nxge_channel_t tdc;
3408 
3409 	tx_ring_t	*ring;
3410 	tx_mbox_t	*mailbox;
3411 
3412 	npi_handle_t	handle;
3413 	nxge_status_t	status;
3414 	npi_status_t	rs;
3415 
3416 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_tx_port_fatal_err_recover"));
3417 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3418 	    "Recovering from TxPort error..."));
3419 
3420 	if (isLDOMguest(nxgep)) {
3421 		return (NXGE_OK);
3422 	}
3423 
3424 	if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) {
3425 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3426 		    "<== nxge_tx_port_fatal_err_recover: not initialized"));
3427 		return (NXGE_ERROR);
3428 	}
3429 
3430 	if (nxgep->tx_rings == 0 || nxgep->tx_rings->rings == 0) {
3431 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
3432 		    "<== nxge_tx_port_fatal_err_recover: "
3433 		    "NULL ring pointer(s)"));
3434 		return (NXGE_ERROR);
3435 	}
3436 
3437 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3438 		if ((1 << tdc) & set->owned.map) {
3439 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3440 			if (ring)
3441 				MUTEX_ENTER(&ring->lock);
3442 		}
3443 	}
3444 
3445 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
3446 
3447 	/*
3448 	 * Stop all the TDCs owned by us.
3449 	 * (The shared TDCs will have been stopped by their owners.)
3450 	 */
3451 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3452 		if ((1 << tdc) & set->owned.map) {
3453 			ring = nxgep->tx_rings->rings[tdc];
3454 			if (ring) {
3455 				rs = npi_txdma_channel_control
3456 				    (handle, TXDMA_STOP, tdc);
3457 				if (rs != NPI_SUCCESS) {
3458 					NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3459 					    "nxge_tx_port_fatal_err_recover "
3460 					    "(channel %d): stop failed ", tdc));
3461 					goto fail;
3462 				}
3463 			}
3464 		}
3465 	}
3466 
3467 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Reclaiming all TDCs..."));
3468 
3469 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3470 		if ((1 << tdc) & set->owned.map) {
3471 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3472 			if (ring) {
3473 				(void) nxge_txdma_reclaim(nxgep, ring, 0);
3474 			}
3475 		}
3476 	}
3477 
3478 	/*
3479 	 * Reset all the TDCs.
3480 	 */
3481 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Resetting all TDCs..."));
3482 
3483 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3484 		if ((1 << tdc) & set->owned.map) {
3485 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3486 			if (ring) {
3487 				if ((rs = npi_txdma_channel_control
3488 				    (handle, TXDMA_RESET, tdc))
3489 				    != NPI_SUCCESS) {
3490 					NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3491 					    "nxge_tx_port_fatal_err_recover "
3492 					    "(channel %d) reset channel "
3493 					    "failed 0x%x", tdc, rs));
3494 					goto fail;
3495 				}
3496 			}
3497 			/*
3498 			 * Reset the tail (kick) register to 0.
3499 			 * (Hardware will not reset it. Tx overflow fatal
3500 			 * error if tail is not set to 0 after reset!
3501 			 */
3502 			TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, tdc, 0);
3503 		}
3504 	}
3505 
3506 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Restarting all TDCs..."));
3507 
3508 	/* Restart all the TDCs */
3509 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3510 		if ((1 << tdc) & set->owned.map) {
3511 			ring = nxgep->tx_rings->rings[tdc];
3512 			if (ring) {
3513 				mailbox = nxge_txdma_get_mbox(nxgep, tdc);
3514 				status = nxge_init_fzc_txdma_channel(nxgep, tdc,
3515 				    ring, mailbox);
3516 				ring->tx_evmask.value = 0;
3517 				/*
3518 				 * Initialize the event masks.
3519 				 */
3520 				status = nxge_init_txdma_channel_event_mask
3521 				    (nxgep, tdc, &ring->tx_evmask);
3522 
3523 				ring->wr_index_wrap = B_FALSE;
3524 				ring->wr_index = 0;
3525 				ring->rd_index = 0;
3526 
3527 				if (status != NXGE_OK)
3528 					goto fail;
3529 				if (status != NXGE_OK)
3530 					goto fail;
3531 			}
3532 		}
3533 	}
3534 
3535 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "Re-enabling all TDCs..."));
3536 
3537 	/* Re-enable all the TDCs */
3538 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3539 		if ((1 << tdc) & set->owned.map) {
3540 			ring = nxgep->tx_rings->rings[tdc];
3541 			if (ring) {
3542 				mailbox = nxge_txdma_get_mbox(nxgep, tdc);
3543 				status = nxge_enable_txdma_channel(nxgep, tdc,
3544 				    ring, mailbox);
3545 				if (status != NXGE_OK)
3546 					goto fail;
3547 			}
3548 		}
3549 	}
3550 
3551 	/*
3552 	 * Unlock all the TDCs.
3553 	 */
3554 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3555 		if ((1 << tdc) & set->owned.map) {
3556 			tx_ring_t *ring = nxgep->tx_rings->rings[tdc];
3557 			if (ring)
3558 				MUTEX_EXIT(&ring->lock);
3559 		}
3560 	}
3561 
3562 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery succeeded"));
3563 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover"));
3564 
3565 	return (NXGE_OK);
3566 
3567 fail:
3568 	for (tdc = 0; tdc < NXGE_MAX_TDCS; tdc++) {
3569 		if ((1 << tdc) & set->owned.map) {
3570 			ring = nxgep->tx_rings->rings[tdc];
3571 			if (ring)
3572 				MUTEX_EXIT(&ring->lock);
3573 		}
3574 	}
3575 
3576 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Tx port recovery failed"));
3577 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover"));
3578 
3579 	return (status);
3580 }
3581 
3582 /*
3583  * nxge_txdma_inject_err
3584  *
3585  *	Inject an error into a TDC.
3586  *
3587  * Arguments:
3588  * 	nxgep
3589  * 	err_id	The error to inject.
3590  * 	chan	The channel to inject into.
3591  *
3592  * Notes:
3593  *	This is called from nxge_main.c:nxge_err_inject()
3594  *	Has this ioctl ever been used?
3595  *
3596  * NPI/NXGE function calls:
3597  *	npi_txdma_inj_par_error_get()
3598  *	npi_txdma_inj_par_error_set()
3599  *
3600  * Registers accessed:
3601  *	TDMC_INJ_PAR_ERR (FZC_DMC + 0x45040) TDMC Inject Parity Error
3602  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
3603  *	TDMC_INTR_DBG	DMC + 0x40060 Transmit DMA Interrupt Debug
3604  *
3605  * Context:
3606  *	Service domain
3607  */
3608 void
3609 nxge_txdma_inject_err(p_nxge_t nxgep, uint32_t err_id, uint8_t chan)
3610 {
3611 	tdmc_intr_dbg_t		tdi;
3612 	tdmc_inj_par_err_t	par_err;
3613 	uint32_t		value;
3614 	npi_handle_t		handle;
3615 
3616 	switch (err_id) {
3617 
3618 	case NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR:
3619 		handle = NXGE_DEV_NPI_HANDLE(nxgep);
3620 		/* Clear error injection source for parity error */
3621 		(void) npi_txdma_inj_par_error_get(handle, &value);
3622 		par_err.value = value;
3623 		par_err.bits.ldw.inject_parity_error &= ~(1 << chan);
3624 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
3625 
3626 		par_err.bits.ldw.inject_parity_error = (1 << chan);
3627 		(void) npi_txdma_inj_par_error_get(handle, &value);
3628 		par_err.value = value;
3629 		par_err.bits.ldw.inject_parity_error |= (1 << chan);
3630 		cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INJ_PAR_ERR_REG\n",
3631 		    (unsigned long long)par_err.value);
3632 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
3633 		break;
3634 
3635 	case NXGE_FM_EREPORT_TDMC_MBOX_ERR:
3636 	case NXGE_FM_EREPORT_TDMC_NACK_PREF:
3637 	case NXGE_FM_EREPORT_TDMC_NACK_PKT_RD:
3638 	case NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR:
3639 	case NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW:
3640 	case NXGE_FM_EREPORT_TDMC_CONF_PART_ERR:
3641 	case NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR:
3642 		TXDMA_REG_READ64(nxgep->npi_handle, TDMC_INTR_DBG_REG,
3643 		    chan, &tdi.value);
3644 		if (err_id == NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR)
3645 			tdi.bits.ldw.pref_buf_par_err = 1;
3646 		else if (err_id == NXGE_FM_EREPORT_TDMC_MBOX_ERR)
3647 			tdi.bits.ldw.mbox_err = 1;
3648 		else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PREF)
3649 			tdi.bits.ldw.nack_pref = 1;
3650 		else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PKT_RD)
3651 			tdi.bits.ldw.nack_pkt_rd = 1;
3652 		else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR)
3653 			tdi.bits.ldw.pkt_size_err = 1;
3654 		else if (err_id == NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW)
3655 			tdi.bits.ldw.tx_ring_oflow = 1;
3656 		else if (err_id == NXGE_FM_EREPORT_TDMC_CONF_PART_ERR)
3657 			tdi.bits.ldw.conf_part_err = 1;
3658 		else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR)
3659 			tdi.bits.ldw.pkt_part_err = 1;
3660 #if defined(__i386)
3661 		cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INTR_DBG_REG\n",
3662 		    tdi.value);
3663 #else
3664 		cmn_err(CE_NOTE, "!Write 0x%lx to TDMC_INTR_DBG_REG\n",
3665 		    tdi.value);
3666 #endif
3667 		TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG,
3668 		    chan, tdi.value);
3669 
3670 		break;
3671 	}
3672 }
3673