144961713Sgirish /*
244961713Sgirish  * CDDL HEADER START
344961713Sgirish  *
444961713Sgirish  * The contents of this file are subject to the terms of the
544961713Sgirish  * Common Development and Distribution License (the "License").
644961713Sgirish  * You may not use this file except in compliance with the License.
744961713Sgirish  *
844961713Sgirish  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
944961713Sgirish  * or http://www.opensolaris.org/os/licensing.
1044961713Sgirish  * See the License for the specific language governing permissions
1144961713Sgirish  * and limitations under the License.
1244961713Sgirish  *
1344961713Sgirish  * When distributing Covered Code, include this CDDL HEADER in each
1444961713Sgirish  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1544961713Sgirish  * If applicable, add the following below this CDDL HEADER, with the
1644961713Sgirish  * fields enclosed by brackets "[]" replaced with your own identifying
1744961713Sgirish  * information: Portions Copyright [yyyy] [name of copyright owner]
1844961713Sgirish  *
1944961713Sgirish  * CDDL HEADER END
2044961713Sgirish  */
2144961713Sgirish /*
22a3c5bd6dSspeer  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2344961713Sgirish  * Use is subject to license terms.
2444961713Sgirish  */
2544961713Sgirish 
2644961713Sgirish #pragma ident	"%Z%%M%	%I%	%E% SMI"
2744961713Sgirish 
2844961713Sgirish #include <sys/nxge/nxge_impl.h>
2944961713Sgirish #include <sys/nxge/nxge_txdma.h>
3044961713Sgirish #include <sys/llc1.h>
3144961713Sgirish 
3244961713Sgirish uint32_t 	nxge_reclaim_pending = TXDMA_RECLAIM_PENDING_DEFAULT;
3344961713Sgirish uint32_t	nxge_tx_minfree = 32;
3444961713Sgirish uint32_t	nxge_tx_intr_thres = 0;
3544961713Sgirish uint32_t	nxge_tx_max_gathers = TX_MAX_GATHER_POINTERS;
3644961713Sgirish uint32_t	nxge_tx_tiny_pack = 1;
3744961713Sgirish uint32_t	nxge_tx_use_bcopy = 1;
3844961713Sgirish 
3944961713Sgirish extern uint32_t 	nxge_tx_ring_size;
4044961713Sgirish extern uint32_t 	nxge_bcopy_thresh;
4144961713Sgirish extern uint32_t 	nxge_dvma_thresh;
4244961713Sgirish extern uint32_t 	nxge_dma_stream_thresh;
4344961713Sgirish extern dma_method_t 	nxge_force_dma;
4444961713Sgirish 
4544961713Sgirish /* Device register access attributes for PIO.  */
4644961713Sgirish extern ddi_device_acc_attr_t nxge_dev_reg_acc_attr;
4744961713Sgirish /* Device descriptor access attributes for DMA.  */
4844961713Sgirish extern ddi_device_acc_attr_t nxge_dev_desc_dma_acc_attr;
4944961713Sgirish /* Device buffer access attributes for DMA.  */
5044961713Sgirish extern ddi_device_acc_attr_t nxge_dev_buf_dma_acc_attr;
5144961713Sgirish extern ddi_dma_attr_t nxge_desc_dma_attr;
5244961713Sgirish extern ddi_dma_attr_t nxge_tx_dma_attr;
5344961713Sgirish 
541f8914d5Sml extern int nxge_serial_tx(mblk_t *mp, void *arg);
551f8914d5Sml 
5644961713Sgirish static nxge_status_t nxge_map_txdma(p_nxge_t);
5744961713Sgirish static void nxge_unmap_txdma(p_nxge_t);
5844961713Sgirish 
5944961713Sgirish static nxge_status_t nxge_txdma_hw_start(p_nxge_t);
6044961713Sgirish static void nxge_txdma_hw_stop(p_nxge_t);
6144961713Sgirish 
6244961713Sgirish static nxge_status_t nxge_map_txdma_channel(p_nxge_t, uint16_t,
6344961713Sgirish 	p_nxge_dma_common_t *, p_tx_ring_t *,
6444961713Sgirish 	uint32_t, p_nxge_dma_common_t *,
6544961713Sgirish 	p_tx_mbox_t *);
6644961713Sgirish static void nxge_unmap_txdma_channel(p_nxge_t, uint16_t,
6744961713Sgirish 	p_tx_ring_t, p_tx_mbox_t);
6844961713Sgirish 
6944961713Sgirish static nxge_status_t nxge_map_txdma_channel_buf_ring(p_nxge_t, uint16_t,
7044961713Sgirish 	p_nxge_dma_common_t *, p_tx_ring_t *, uint32_t);
7144961713Sgirish static void nxge_unmap_txdma_channel_buf_ring(p_nxge_t, p_tx_ring_t);
7244961713Sgirish 
7344961713Sgirish static void nxge_map_txdma_channel_cfg_ring(p_nxge_t, uint16_t,
7444961713Sgirish 	p_nxge_dma_common_t *, p_tx_ring_t,
7544961713Sgirish 	p_tx_mbox_t *);
7644961713Sgirish static void nxge_unmap_txdma_channel_cfg_ring(p_nxge_t,
7744961713Sgirish 	p_tx_ring_t, p_tx_mbox_t);
7844961713Sgirish 
7944961713Sgirish static nxge_status_t nxge_txdma_start_channel(p_nxge_t, uint16_t,
8044961713Sgirish     p_tx_ring_t, p_tx_mbox_t);
8144961713Sgirish static nxge_status_t nxge_txdma_stop_channel(p_nxge_t, uint16_t,
8244961713Sgirish 	p_tx_ring_t, p_tx_mbox_t);
8344961713Sgirish 
8444961713Sgirish static p_tx_ring_t nxge_txdma_get_ring(p_nxge_t, uint16_t);
8544961713Sgirish static nxge_status_t nxge_tx_err_evnts(p_nxge_t, uint_t,
8644961713Sgirish 	p_nxge_ldv_t, tx_cs_t);
8744961713Sgirish static p_tx_mbox_t nxge_txdma_get_mbox(p_nxge_t, uint16_t);
8844961713Sgirish static nxge_status_t nxge_txdma_fatal_err_recover(p_nxge_t,
8944961713Sgirish 	uint16_t, p_tx_ring_t);
9044961713Sgirish 
9144961713Sgirish nxge_status_t
9244961713Sgirish nxge_init_txdma_channels(p_nxge_t nxgep)
9344961713Sgirish {
9444961713Sgirish 	nxge_status_t		status = NXGE_OK;
9544961713Sgirish 
9644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_init_txdma_channels"));
9744961713Sgirish 
9844961713Sgirish 	status = nxge_map_txdma(nxgep);
9944961713Sgirish 	if (status != NXGE_OK) {
10044961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
10144961713Sgirish 			"<== nxge_init_txdma_channels: status 0x%x", status));
10244961713Sgirish 		return (status);
10344961713Sgirish 	}
10444961713Sgirish 
10544961713Sgirish 	status = nxge_txdma_hw_start(nxgep);
10644961713Sgirish 	if (status != NXGE_OK) {
10744961713Sgirish 		nxge_unmap_txdma(nxgep);
10844961713Sgirish 		return (status);
10944961713Sgirish 	}
11044961713Sgirish 
11144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
11244961713Sgirish 		"<== nxge_init_txdma_channels: status 0x%x", status));
11344961713Sgirish 
11444961713Sgirish 	return (NXGE_OK);
11544961713Sgirish }
11644961713Sgirish 
11744961713Sgirish void
11844961713Sgirish nxge_uninit_txdma_channels(p_nxge_t nxgep)
11944961713Sgirish {
12044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_uninit_txdma_channels"));
12144961713Sgirish 
12244961713Sgirish 	nxge_txdma_hw_stop(nxgep);
12344961713Sgirish 	nxge_unmap_txdma(nxgep);
12444961713Sgirish 
12544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
12644961713Sgirish 		"<== nxge_uinit_txdma_channels"));
12744961713Sgirish }
12844961713Sgirish 
12944961713Sgirish void
13044961713Sgirish nxge_setup_dma_common(p_nxge_dma_common_t dest_p, p_nxge_dma_common_t src_p,
13144961713Sgirish 	uint32_t entries, uint32_t size)
13244961713Sgirish {
13344961713Sgirish 	size_t		tsize;
13444961713Sgirish 	*dest_p = *src_p;
13544961713Sgirish 	tsize = size * entries;
13644961713Sgirish 	dest_p->alength = tsize;
13744961713Sgirish 	dest_p->nblocks = entries;
13844961713Sgirish 	dest_p->block_size = size;
13944961713Sgirish 	dest_p->offset += tsize;
14044961713Sgirish 
14144961713Sgirish 	src_p->kaddrp = (caddr_t)dest_p->kaddrp + tsize;
14244961713Sgirish 	src_p->alength -= tsize;
14344961713Sgirish 	src_p->dma_cookie.dmac_laddress += tsize;
14444961713Sgirish 	src_p->dma_cookie.dmac_size -= tsize;
14544961713Sgirish }
14644961713Sgirish 
14744961713Sgirish nxge_status_t
14844961713Sgirish nxge_reset_txdma_channel(p_nxge_t nxgep, uint16_t channel, uint64_t reg_data)
14944961713Sgirish {
15044961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
15144961713Sgirish 	nxge_status_t		status = NXGE_OK;
15244961713Sgirish 	npi_handle_t		handle;
15344961713Sgirish 
15444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, " ==> nxge_reset_txdma_channel"));
15544961713Sgirish 
15644961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
15744961713Sgirish 	if ((reg_data & TX_CS_RST_MASK) == TX_CS_RST_MASK) {
15844961713Sgirish 		rs = npi_txdma_channel_reset(handle, channel);
15944961713Sgirish 	} else {
16044961713Sgirish 		rs = npi_txdma_channel_control(handle, TXDMA_RESET,
16144961713Sgirish 				channel);
16244961713Sgirish 	}
16344961713Sgirish 
16444961713Sgirish 	if (rs != NPI_SUCCESS) {
16544961713Sgirish 		status = NXGE_ERROR | rs;
16644961713Sgirish 	}
16744961713Sgirish 
16844961713Sgirish 	/*
16944961713Sgirish 	 * Reset the tail (kick) register to 0.
17044961713Sgirish 	 * (Hardware will not reset it. Tx overflow fatal
17144961713Sgirish 	 * error if tail is not set to 0 after reset!
17244961713Sgirish 	 */
17344961713Sgirish 	TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0);
17444961713Sgirish 
17544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, " <== nxge_reset_txdma_channel"));
17644961713Sgirish 	return (status);
17744961713Sgirish }
17844961713Sgirish 
17944961713Sgirish nxge_status_t
18044961713Sgirish nxge_init_txdma_channel_event_mask(p_nxge_t nxgep, uint16_t channel,
18144961713Sgirish 		p_tx_dma_ent_msk_t mask_p)
18244961713Sgirish {
18344961713Sgirish 	npi_handle_t		handle;
18444961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
18544961713Sgirish 	nxge_status_t		status = NXGE_OK;
18644961713Sgirish 
18744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
18844961713Sgirish 		"<== nxge_init_txdma_channel_event_mask"));
18944961713Sgirish 
19044961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
19144961713Sgirish 	rs = npi_txdma_event_mask(handle, OP_SET, channel, mask_p);
19244961713Sgirish 	if (rs != NPI_SUCCESS) {
19344961713Sgirish 		status = NXGE_ERROR | rs;
19444961713Sgirish 	}
19544961713Sgirish 
19644961713Sgirish 	return (status);
19744961713Sgirish }
19844961713Sgirish 
19944961713Sgirish nxge_status_t
20044961713Sgirish nxge_init_txdma_channel_cntl_stat(p_nxge_t nxgep, uint16_t channel,
20144961713Sgirish 	uint64_t reg_data)
20244961713Sgirish {
20344961713Sgirish 	npi_handle_t		handle;
20444961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
20544961713Sgirish 	nxge_status_t		status = NXGE_OK;
20644961713Sgirish 
20744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
20844961713Sgirish 		"<== nxge_init_txdma_channel_cntl_stat"));
20944961713Sgirish 
21044961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
21144961713Sgirish 	rs = npi_txdma_control_status(handle, OP_SET, channel,
21244961713Sgirish 			(p_tx_cs_t)&reg_data);
21344961713Sgirish 
21444961713Sgirish 	if (rs != NPI_SUCCESS) {
21544961713Sgirish 		status = NXGE_ERROR | rs;
21644961713Sgirish 	}
21744961713Sgirish 
21844961713Sgirish 	return (status);
21944961713Sgirish }
22044961713Sgirish 
22144961713Sgirish nxge_status_t
22244961713Sgirish nxge_enable_txdma_channel(p_nxge_t nxgep,
22344961713Sgirish 	uint16_t channel, p_tx_ring_t tx_desc_p, p_tx_mbox_t mbox_p)
22444961713Sgirish {
22544961713Sgirish 	npi_handle_t		handle;
22644961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
22744961713Sgirish 	nxge_status_t		status = NXGE_OK;
22844961713Sgirish 
22944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_enable_txdma_channel"));
23044961713Sgirish 
23144961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
23244961713Sgirish 	/*
23344961713Sgirish 	 * Use configuration data composed at init time.
23444961713Sgirish 	 * Write to hardware the transmit ring configurations.
23544961713Sgirish 	 */
23644961713Sgirish 	rs = npi_txdma_ring_config(handle, OP_SET, channel,
23744961713Sgirish 			(uint64_t *)&(tx_desc_p->tx_ring_cfig.value));
23844961713Sgirish 
23944961713Sgirish 	if (rs != NPI_SUCCESS) {
24044961713Sgirish 		return (NXGE_ERROR | rs);
24144961713Sgirish 	}
24244961713Sgirish 
24344961713Sgirish 	/* Write to hardware the mailbox */
24444961713Sgirish 	rs = npi_txdma_mbox_config(handle, OP_SET, channel,
24544961713Sgirish 		(uint64_t *)&mbox_p->tx_mbox.dma_cookie.dmac_laddress);
24644961713Sgirish 
24744961713Sgirish 	if (rs != NPI_SUCCESS) {
24844961713Sgirish 		return (NXGE_ERROR | rs);
24944961713Sgirish 	}
25044961713Sgirish 
25144961713Sgirish 	/* Start the DMA engine. */
25244961713Sgirish 	rs = npi_txdma_channel_init_enable(handle, channel);
25344961713Sgirish 
25444961713Sgirish 	if (rs != NPI_SUCCESS) {
25544961713Sgirish 		return (NXGE_ERROR | rs);
25644961713Sgirish 	}
25744961713Sgirish 
25844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_enable_txdma_channel"));
25944961713Sgirish 
26044961713Sgirish 	return (status);
26144961713Sgirish }
26244961713Sgirish 
26344961713Sgirish void
26444961713Sgirish nxge_fill_tx_hdr(p_mblk_t mp, boolean_t fill_len,
26544961713Sgirish 		boolean_t l4_cksum, int pkt_len, uint8_t npads,
26644961713Sgirish 		p_tx_pkt_hdr_all_t pkthdrp)
26744961713Sgirish {
26844961713Sgirish 	p_tx_pkt_header_t	hdrp;
26944961713Sgirish 	p_mblk_t 		nmp;
27044961713Sgirish 	uint64_t		tmp;
27144961713Sgirish 	size_t 			mblk_len;
27244961713Sgirish 	size_t 			iph_len;
27344961713Sgirish 	size_t 			hdrs_size;
27444961713Sgirish 	uint8_t			hdrs_buf[sizeof (struct ether_header) +
27544961713Sgirish 					64 + sizeof (uint32_t)];
27644961713Sgirish 	uint8_t 		*ip_buf;
27744961713Sgirish 	uint16_t		eth_type;
27844961713Sgirish 	uint8_t			ipproto;
27944961713Sgirish 	boolean_t		is_vlan = B_FALSE;
28044961713Sgirish 	size_t			eth_hdr_size;
28144961713Sgirish 
28244961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: mp $%p", mp));
28344961713Sgirish 
28444961713Sgirish 	/*
28544961713Sgirish 	 * Caller should zero out the headers first.
28644961713Sgirish 	 */
28744961713Sgirish 	hdrp = (p_tx_pkt_header_t)&pkthdrp->pkthdr;
28844961713Sgirish 
28944961713Sgirish 	if (fill_len) {
29044961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
29144961713Sgirish 			"==> nxge_fill_tx_hdr: pkt_len %d "
29244961713Sgirish 			"npads %d", pkt_len, npads));
29344961713Sgirish 		tmp = (uint64_t)pkt_len;
29444961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_TOT_XFER_LEN_SHIFT);
29544961713Sgirish 		goto fill_tx_header_done;
29644961713Sgirish 	}
29744961713Sgirish 
29844961713Sgirish 	tmp = (uint64_t)npads;
29944961713Sgirish 	hdrp->value |= (tmp << TX_PKT_HEADER_PAD_SHIFT);
30044961713Sgirish 
30144961713Sgirish 	/*
30244961713Sgirish 	 * mp is the original data packet (does not include the
30344961713Sgirish 	 * Neptune transmit header).
30444961713Sgirish 	 */
30544961713Sgirish 	nmp = mp;
30644961713Sgirish 	mblk_len = (size_t)nmp->b_wptr - (size_t)nmp->b_rptr;
30744961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: "
30844961713Sgirish 		"mp $%p b_rptr $%p len %d",
30944961713Sgirish 		mp, nmp->b_rptr, mblk_len));
31044961713Sgirish 	ip_buf = NULL;
31144961713Sgirish 	bcopy(nmp->b_rptr, &hdrs_buf[0], sizeof (struct ether_vlan_header));
31244961713Sgirish 	eth_type = ntohs(((p_ether_header_t)hdrs_buf)->ether_type);
31344961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==> : nxge_fill_tx_hdr: (value 0x%llx) "
31444961713Sgirish 		"ether type 0x%x", eth_type, hdrp->value));
31544961713Sgirish 
31644961713Sgirish 	if (eth_type < ETHERMTU) {
31744961713Sgirish 		tmp = 1ull;
31844961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_LLC_SHIFT);
31944961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: LLC "
32044961713Sgirish 			"value 0x%llx", hdrp->value));
32144961713Sgirish 		if (*(hdrs_buf + sizeof (struct ether_header))
32244961713Sgirish 				== LLC_SNAP_SAP) {
32344961713Sgirish 			eth_type = ntohs(*((uint16_t *)(hdrs_buf +
32444961713Sgirish 					sizeof (struct ether_header) + 6)));
32544961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
32644961713Sgirish 				"==> nxge_tx_pkt_hdr_init: LLC ether type 0x%x",
32744961713Sgirish 				eth_type));
32844961713Sgirish 		} else {
32944961713Sgirish 			goto fill_tx_header_done;
33044961713Sgirish 		}
33144961713Sgirish 	} else if (eth_type == VLAN_ETHERTYPE) {
33244961713Sgirish 		tmp = 1ull;
33344961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_VLAN__SHIFT);
33444961713Sgirish 
33544961713Sgirish 		eth_type = ntohs(((struct ether_vlan_header *)
33644961713Sgirish 			hdrs_buf)->ether_type);
33744961713Sgirish 		is_vlan = B_TRUE;
33844961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: VLAN "
33944961713Sgirish 			"value 0x%llx", hdrp->value));
34044961713Sgirish 	}
34144961713Sgirish 
34244961713Sgirish 	if (!is_vlan) {
34344961713Sgirish 		eth_hdr_size = sizeof (struct ether_header);
34444961713Sgirish 	} else {
34544961713Sgirish 		eth_hdr_size = sizeof (struct ether_vlan_header);
34644961713Sgirish 	}
34744961713Sgirish 
34844961713Sgirish 	switch (eth_type) {
34944961713Sgirish 	case ETHERTYPE_IP:
35044961713Sgirish 		if (mblk_len > eth_hdr_size + sizeof (uint8_t)) {
35144961713Sgirish 			ip_buf = nmp->b_rptr + eth_hdr_size;
35244961713Sgirish 			mblk_len -= eth_hdr_size;
35344961713Sgirish 			iph_len = ((*ip_buf) & 0x0f);
35444961713Sgirish 			if (mblk_len > (iph_len + sizeof (uint32_t))) {
35544961713Sgirish 				ip_buf = nmp->b_rptr;
35644961713Sgirish 				ip_buf += eth_hdr_size;
35744961713Sgirish 			} else {
35844961713Sgirish 				ip_buf = NULL;
35944961713Sgirish 			}
36044961713Sgirish 
36144961713Sgirish 		}
36244961713Sgirish 		if (ip_buf == NULL) {
36344961713Sgirish 			hdrs_size = 0;
36444961713Sgirish 			((p_ether_header_t)hdrs_buf)->ether_type = 0;
36544961713Sgirish 			while ((nmp) && (hdrs_size <
36644961713Sgirish 					sizeof (hdrs_buf))) {
36744961713Sgirish 				mblk_len = (size_t)nmp->b_wptr -
36844961713Sgirish 					(size_t)nmp->b_rptr;
36944961713Sgirish 				if (mblk_len >=
37044961713Sgirish 					(sizeof (hdrs_buf) - hdrs_size))
37144961713Sgirish 					mblk_len = sizeof (hdrs_buf) -
37244961713Sgirish 						hdrs_size;
37344961713Sgirish 				bcopy(nmp->b_rptr,
37444961713Sgirish 					&hdrs_buf[hdrs_size], mblk_len);
37544961713Sgirish 				hdrs_size += mblk_len;
37644961713Sgirish 				nmp = nmp->b_cont;
37744961713Sgirish 			}
37844961713Sgirish 			ip_buf = hdrs_buf;
37944961713Sgirish 			ip_buf += eth_hdr_size;
38044961713Sgirish 			iph_len = ((*ip_buf) & 0x0f);
38144961713Sgirish 		}
38244961713Sgirish 
38344961713Sgirish 		ipproto = ip_buf[9];
38444961713Sgirish 
38544961713Sgirish 		tmp = (uint64_t)iph_len;
38644961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_IHL_SHIFT);
38744961713Sgirish 		tmp = (uint64_t)(eth_hdr_size >> 1);
38844961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT);
38944961713Sgirish 
39044961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv4 "
39144961713Sgirish 			" iph_len %d l3start %d eth_hdr_size %d proto 0x%x"
39244961713Sgirish 			"tmp 0x%x",
39344961713Sgirish 			iph_len, hdrp->bits.hdw.l3start, eth_hdr_size,
39444961713Sgirish 			ipproto, tmp));
39544961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IP "
39644961713Sgirish 			"value 0x%llx", hdrp->value));
39744961713Sgirish 
39844961713Sgirish 		break;
39944961713Sgirish 
40044961713Sgirish 	case ETHERTYPE_IPV6:
40144961713Sgirish 		hdrs_size = 0;
40244961713Sgirish 		((p_ether_header_t)hdrs_buf)->ether_type = 0;
40344961713Sgirish 		while ((nmp) && (hdrs_size <
40444961713Sgirish 				sizeof (hdrs_buf))) {
40544961713Sgirish 			mblk_len = (size_t)nmp->b_wptr - (size_t)nmp->b_rptr;
40644961713Sgirish 			if (mblk_len >=
40744961713Sgirish 				(sizeof (hdrs_buf) - hdrs_size))
40844961713Sgirish 				mblk_len = sizeof (hdrs_buf) -
40944961713Sgirish 					hdrs_size;
41044961713Sgirish 			bcopy(nmp->b_rptr,
41144961713Sgirish 				&hdrs_buf[hdrs_size], mblk_len);
41244961713Sgirish 			hdrs_size += mblk_len;
41344961713Sgirish 			nmp = nmp->b_cont;
41444961713Sgirish 		}
41544961713Sgirish 		ip_buf = hdrs_buf;
41644961713Sgirish 		ip_buf += eth_hdr_size;
41744961713Sgirish 
41844961713Sgirish 		tmp = 1ull;
41944961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_IP_VER_SHIFT);
42044961713Sgirish 
42144961713Sgirish 		tmp = (eth_hdr_size >> 1);
42244961713Sgirish 		hdrp->value |= (tmp << TX_PKT_HEADER_L3START_SHIFT);
42344961713Sgirish 
42444961713Sgirish 		/* byte 6 is the next header protocol */
42544961713Sgirish 		ipproto = ip_buf[6];
42644961713Sgirish 
42744961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: IPv6 "
42844961713Sgirish 			" iph_len %d l3start %d eth_hdr_size %d proto 0x%x",
42944961713Sgirish 			iph_len, hdrp->bits.hdw.l3start, eth_hdr_size,
43044961713Sgirish 			ipproto));
43144961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: IPv6 "
43244961713Sgirish 			"value 0x%llx", hdrp->value));
43344961713Sgirish 
43444961713Sgirish 		break;
43544961713Sgirish 
43644961713Sgirish 	default:
43744961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: non-IP"));
43844961713Sgirish 		goto fill_tx_header_done;
43944961713Sgirish 	}
44044961713Sgirish 
44144961713Sgirish 	switch (ipproto) {
44244961713Sgirish 	case IPPROTO_TCP:
44344961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
44444961713Sgirish 			"==> nxge_fill_tx_hdr: TCP (cksum flag %d)", l4_cksum));
44544961713Sgirish 		if (l4_cksum) {
44644961713Sgirish 			tmp = 1ull;
44744961713Sgirish 			hdrp->value |= (tmp << TX_PKT_HEADER_PKT_TYPE_SHIFT);
44844961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
44944961713Sgirish 				"==> nxge_tx_pkt_hdr_init: TCP CKSUM"
45044961713Sgirish 				"value 0x%llx", hdrp->value));
45144961713Sgirish 		}
45244961713Sgirish 
45344961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_hdr_init: TCP "
45444961713Sgirish 			"value 0x%llx", hdrp->value));
45544961713Sgirish 		break;
45644961713Sgirish 
45744961713Sgirish 	case IPPROTO_UDP:
45844961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_fill_tx_hdr: UDP"));
45944961713Sgirish 		if (l4_cksum) {
46044961713Sgirish 			tmp = 0x2ull;
46144961713Sgirish 			hdrp->value |= (tmp << TX_PKT_HEADER_PKT_TYPE_SHIFT);
46244961713Sgirish 		}
46344961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
46444961713Sgirish 			"==> nxge_tx_pkt_hdr_init: UDP"
46544961713Sgirish 			"value 0x%llx", hdrp->value));
46644961713Sgirish 		break;
46744961713Sgirish 
46844961713Sgirish 	default:
46944961713Sgirish 		goto fill_tx_header_done;
47044961713Sgirish 	}
47144961713Sgirish 
47244961713Sgirish fill_tx_header_done:
47344961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
47444961713Sgirish 		"==> nxge_fill_tx_hdr: pkt_len %d  "
47544961713Sgirish 		"npads %d value 0x%llx", pkt_len, npads, hdrp->value));
47644961713Sgirish 
47744961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "<== nxge_fill_tx_hdr"));
47844961713Sgirish }
47944961713Sgirish 
48044961713Sgirish /*ARGSUSED*/
48144961713Sgirish p_mblk_t
48244961713Sgirish nxge_tx_pkt_header_reserve(p_mblk_t mp, uint8_t *npads)
48344961713Sgirish {
48444961713Sgirish 	p_mblk_t 		newmp = NULL;
48544961713Sgirish 
48644961713Sgirish 	if ((newmp = allocb(TX_PKT_HEADER_SIZE, BPRI_MED)) == NULL) {
48744961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL,
48844961713Sgirish 			"<== nxge_tx_pkt_header_reserve: allocb failed"));
48944961713Sgirish 		return (NULL);
49044961713Sgirish 	}
49144961713Sgirish 
49244961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
49344961713Sgirish 		"==> nxge_tx_pkt_header_reserve: get new mp"));
49444961713Sgirish 	DB_TYPE(newmp) = M_DATA;
49544961713Sgirish 	newmp->b_rptr = newmp->b_wptr = DB_LIM(newmp);
49644961713Sgirish 	linkb(newmp, mp);
49744961713Sgirish 	newmp->b_rptr -= TX_PKT_HEADER_SIZE;
49844961713Sgirish 
49944961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL, "==>nxge_tx_pkt_header_reserve: "
50044961713Sgirish 		"b_rptr $%p b_wptr $%p",
50144961713Sgirish 		newmp->b_rptr, newmp->b_wptr));
50244961713Sgirish 
50344961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
50444961713Sgirish 		"<== nxge_tx_pkt_header_reserve: use new mp"));
50544961713Sgirish 
50644961713Sgirish 	return (newmp);
50744961713Sgirish }
50844961713Sgirish 
50944961713Sgirish int
51044961713Sgirish nxge_tx_pkt_nmblocks(p_mblk_t mp, int *tot_xfer_len_p)
51144961713Sgirish {
51244961713Sgirish 	uint_t 			nmblks;
51344961713Sgirish 	ssize_t			len;
51444961713Sgirish 	uint_t 			pkt_len;
51544961713Sgirish 	p_mblk_t 		nmp, bmp, tmp;
51644961713Sgirish 	uint8_t 		*b_wptr;
51744961713Sgirish 
51844961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
51944961713Sgirish 		"==> nxge_tx_pkt_nmblocks: mp $%p rptr $%p wptr $%p "
52044961713Sgirish 		"len %d", mp, mp->b_rptr, mp->b_wptr, MBLKL(mp)));
52144961713Sgirish 
52244961713Sgirish 	nmp = mp;
52344961713Sgirish 	bmp = mp;
52444961713Sgirish 	nmblks = 0;
52544961713Sgirish 	pkt_len = 0;
52644961713Sgirish 	*tot_xfer_len_p = 0;
52744961713Sgirish 
52844961713Sgirish 	while (nmp) {
52944961713Sgirish 		len = MBLKL(nmp);
53044961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: "
53144961713Sgirish 			"len %d pkt_len %d nmblks %d tot_xfer_len %d",
53244961713Sgirish 			len, pkt_len, nmblks,
53344961713Sgirish 			*tot_xfer_len_p));
53444961713Sgirish 
53544961713Sgirish 		if (len <= 0) {
53644961713Sgirish 			bmp = nmp;
53744961713Sgirish 			nmp = nmp->b_cont;
53844961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
53944961713Sgirish 				"==> nxge_tx_pkt_nmblocks: "
54044961713Sgirish 				"len (0) pkt_len %d nmblks %d",
54144961713Sgirish 				pkt_len, nmblks));
54244961713Sgirish 			continue;
54344961713Sgirish 		}
54444961713Sgirish 
54544961713Sgirish 		*tot_xfer_len_p += len;
54644961713Sgirish 		NXGE_DEBUG_MSG((NULL, TX_CTL, "==> nxge_tx_pkt_nmblocks: "
54744961713Sgirish 			"len %d pkt_len %d nmblks %d tot_xfer_len %d",
54844961713Sgirish 			len, pkt_len, nmblks,
54944961713Sgirish 			*tot_xfer_len_p));
55044961713Sgirish 
55144961713Sgirish 		if (len < nxge_bcopy_thresh) {
55244961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
55344961713Sgirish 				"==> nxge_tx_pkt_nmblocks: "
55444961713Sgirish 				"len %d (< thresh) pkt_len %d nmblks %d",
55544961713Sgirish 				len, pkt_len, nmblks));
55644961713Sgirish 			if (pkt_len == 0)
55744961713Sgirish 				nmblks++;
55844961713Sgirish 			pkt_len += len;
55944961713Sgirish 			if (pkt_len >= nxge_bcopy_thresh) {
56044961713Sgirish 				pkt_len = 0;
56144961713Sgirish 				len = 0;
56244961713Sgirish 				nmp = bmp;
56344961713Sgirish 			}
56444961713Sgirish 		} else {
56544961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
56644961713Sgirish 				"==> nxge_tx_pkt_nmblocks: "
56744961713Sgirish 				"len %d (> thresh) pkt_len %d nmblks %d",
56844961713Sgirish 				len, pkt_len, nmblks));
56944961713Sgirish 			pkt_len = 0;
57044961713Sgirish 			nmblks++;
57144961713Sgirish 			/*
57244961713Sgirish 			 * Hardware limits the transfer length to 4K.
57344961713Sgirish 			 * If len is more than 4K, we need to break
57444961713Sgirish 			 * it up to at most 2 more blocks.
57544961713Sgirish 			 */
57644961713Sgirish 			if (len > TX_MAX_TRANSFER_LENGTH) {
57744961713Sgirish 				uint32_t	nsegs;
57844961713Sgirish 
57944961713Sgirish 				NXGE_DEBUG_MSG((NULL, TX_CTL,
58044961713Sgirish 					"==> nxge_tx_pkt_nmblocks: "
58144961713Sgirish 					"len %d pkt_len %d nmblks %d nsegs %d",
58244961713Sgirish 					len, pkt_len, nmblks, nsegs));
58344961713Sgirish 				nsegs = 1;
58444961713Sgirish 				if (len % (TX_MAX_TRANSFER_LENGTH * 2)) {
58544961713Sgirish 					++nsegs;
58644961713Sgirish 				}
58744961713Sgirish 				do {
58844961713Sgirish 					b_wptr = nmp->b_rptr +
58944961713Sgirish 						TX_MAX_TRANSFER_LENGTH;
59044961713Sgirish 					nmp->b_wptr = b_wptr;
59144961713Sgirish 					if ((tmp = dupb(nmp)) == NULL) {
59244961713Sgirish 						return (0);
59344961713Sgirish 					}
59444961713Sgirish 					tmp->b_rptr = b_wptr;
59544961713Sgirish 					tmp->b_wptr = nmp->b_wptr;
59644961713Sgirish 					tmp->b_cont = nmp->b_cont;
59744961713Sgirish 					nmp->b_cont = tmp;
59844961713Sgirish 					nmblks++;
59944961713Sgirish 					if (--nsegs) {
60044961713Sgirish 						nmp = tmp;
60144961713Sgirish 					}
60244961713Sgirish 				} while (nsegs);
60344961713Sgirish 				nmp = tmp;
60444961713Sgirish 			}
60544961713Sgirish 		}
60644961713Sgirish 
60744961713Sgirish 		/*
60844961713Sgirish 		 * Hardware limits the transmit gather pointers to 15.
60944961713Sgirish 		 */
61044961713Sgirish 		if (nmp->b_cont && (nmblks + TX_GATHER_POINTERS_THRESHOLD) >
61144961713Sgirish 				TX_MAX_GATHER_POINTERS) {
61244961713Sgirish 			NXGE_DEBUG_MSG((NULL, TX_CTL,
61344961713Sgirish 				"==> nxge_tx_pkt_nmblocks: pull msg - "
61444961713Sgirish 				"len %d pkt_len %d nmblks %d",
61544961713Sgirish 				len, pkt_len, nmblks));
61644961713Sgirish 			/* Pull all message blocks from b_cont */
61744961713Sgirish 			if ((tmp = msgpullup(nmp->b_cont, -1)) == NULL) {
61844961713Sgirish 				return (0);
61944961713Sgirish 			}
62044961713Sgirish 			freemsg(nmp->b_cont);
62144961713Sgirish 			nmp->b_cont = tmp;
62244961713Sgirish 			pkt_len = 0;
62344961713Sgirish 		}
62444961713Sgirish 		bmp = nmp;
62544961713Sgirish 		nmp = nmp->b_cont;
62644961713Sgirish 	}
62744961713Sgirish 
62844961713Sgirish 	NXGE_DEBUG_MSG((NULL, TX_CTL,
62944961713Sgirish 		"<== nxge_tx_pkt_nmblocks: rptr $%p wptr $%p "
63044961713Sgirish 		"nmblks %d len %d tot_xfer_len %d",
63144961713Sgirish 		mp->b_rptr, mp->b_wptr, nmblks,
63244961713Sgirish 		MBLKL(mp), *tot_xfer_len_p));
63344961713Sgirish 
63444961713Sgirish 	return (nmblks);
63544961713Sgirish }
63644961713Sgirish 
63744961713Sgirish boolean_t
63844961713Sgirish nxge_txdma_reclaim(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, int nmblks)
63944961713Sgirish {
64044961713Sgirish 	boolean_t 		status = B_TRUE;
64144961713Sgirish 	p_nxge_dma_common_t	tx_desc_dma_p;
64244961713Sgirish 	nxge_dma_common_t	desc_area;
64344961713Sgirish 	p_tx_desc_t 		tx_desc_ring_vp;
64444961713Sgirish 	p_tx_desc_t 		tx_desc_p;
64544961713Sgirish 	p_tx_desc_t 		tx_desc_pp;
64644961713Sgirish 	tx_desc_t 		r_tx_desc;
64744961713Sgirish 	p_tx_msg_t 		tx_msg_ring;
64844961713Sgirish 	p_tx_msg_t 		tx_msg_p;
64944961713Sgirish 	npi_handle_t		handle;
65044961713Sgirish 	tx_ring_hdl_t		tx_head;
65144961713Sgirish 	uint32_t 		pkt_len;
65244961713Sgirish 	uint_t			tx_rd_index;
65344961713Sgirish 	uint16_t		head_index, tail_index;
65444961713Sgirish 	uint8_t			tdc;
65544961713Sgirish 	boolean_t		head_wrap, tail_wrap;
65644961713Sgirish 	p_nxge_tx_ring_stats_t tdc_stats;
65744961713Sgirish 	int			rc;
65844961713Sgirish 
65944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_reclaim"));
66044961713Sgirish 
66144961713Sgirish 	status = ((tx_ring_p->descs_pending < nxge_reclaim_pending) &&
66244961713Sgirish 			(nmblks != 0));
66344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
66444961713Sgirish 		"==> nxge_txdma_reclaim: pending %d  reclaim %d nmblks %d",
66544961713Sgirish 			tx_ring_p->descs_pending, nxge_reclaim_pending,
66644961713Sgirish 			nmblks));
66744961713Sgirish 	if (!status) {
66844961713Sgirish 		tx_desc_dma_p = &tx_ring_p->tdc_desc;
66944961713Sgirish 		desc_area = tx_ring_p->tdc_desc;
67044961713Sgirish 		handle = NXGE_DEV_NPI_HANDLE(nxgep);
67144961713Sgirish 		tx_desc_ring_vp = tx_desc_dma_p->kaddrp;
67244961713Sgirish 		tx_desc_ring_vp =
67344961713Sgirish 			(p_tx_desc_t)DMA_COMMON_VPTR(desc_area);
67444961713Sgirish 		tx_rd_index = tx_ring_p->rd_index;
67544961713Sgirish 		tx_desc_p = &tx_desc_ring_vp[tx_rd_index];
67644961713Sgirish 		tx_msg_ring = tx_ring_p->tx_msg_ring;
67744961713Sgirish 		tx_msg_p = &tx_msg_ring[tx_rd_index];
67844961713Sgirish 		tdc = tx_ring_p->tdc;
67944961713Sgirish 		tdc_stats = tx_ring_p->tdc_stats;
68044961713Sgirish 		if (tx_ring_p->descs_pending > tdc_stats->tx_max_pend) {
68144961713Sgirish 			tdc_stats->tx_max_pend = tx_ring_p->descs_pending;
68244961713Sgirish 		}
68344961713Sgirish 
68444961713Sgirish 		tail_index = tx_ring_p->wr_index;
68544961713Sgirish 		tail_wrap = tx_ring_p->wr_index_wrap;
68644961713Sgirish 
68744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
68844961713Sgirish 			"==> nxge_txdma_reclaim: tdc %d tx_rd_index %d "
68944961713Sgirish 			"tail_index %d tail_wrap %d "
69044961713Sgirish 			"tx_desc_p $%p ($%p) ",
69144961713Sgirish 			tdc, tx_rd_index, tail_index, tail_wrap,
69244961713Sgirish 			tx_desc_p, (*(uint64_t *)tx_desc_p)));
69344961713Sgirish 		/*
69444961713Sgirish 		 * Read the hardware maintained transmit head
69544961713Sgirish 		 * and wrap around bit.
69644961713Sgirish 		 */
69744961713Sgirish 		TXDMA_REG_READ64(handle, TX_RING_HDL_REG, tdc, &tx_head.value);
69844961713Sgirish 		head_index =  tx_head.bits.ldw.head;
69944961713Sgirish 		head_wrap = tx_head.bits.ldw.wrap;
70044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
70144961713Sgirish 			"==> nxge_txdma_reclaim: "
70244961713Sgirish 			"tx_rd_index %d tail %d tail_wrap %d "
70344961713Sgirish 			"head %d wrap %d",
70444961713Sgirish 			tx_rd_index, tail_index, tail_wrap,
70544961713Sgirish 			head_index, head_wrap));
70644961713Sgirish 
70744961713Sgirish 		if (head_index == tail_index) {
70844961713Sgirish 			if (TXDMA_RING_EMPTY(head_index, head_wrap,
70944961713Sgirish 					tail_index, tail_wrap) &&
71044961713Sgirish 					(head_index == tx_rd_index)) {
71144961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
71244961713Sgirish 					"==> nxge_txdma_reclaim: EMPTY"));
71344961713Sgirish 				return (B_TRUE);
71444961713Sgirish 			}
71544961713Sgirish 
71644961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
71744961713Sgirish 				"==> nxge_txdma_reclaim: Checking "
71844961713Sgirish 					"if ring full"));
71944961713Sgirish 			if (TXDMA_RING_FULL(head_index, head_wrap, tail_index,
72044961713Sgirish 					tail_wrap)) {
72144961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
72244961713Sgirish 					"==> nxge_txdma_reclaim: full"));
72344961713Sgirish 				return (B_FALSE);
72444961713Sgirish 			}
72544961713Sgirish 		}
72644961713Sgirish 
72744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
72844961713Sgirish 			"==> nxge_txdma_reclaim: tx_rd_index and head_index"));
72944961713Sgirish 
73044961713Sgirish 		tx_desc_pp = &r_tx_desc;
73144961713Sgirish 		while ((tx_rd_index != head_index) &&
73244961713Sgirish 			(tx_ring_p->descs_pending != 0)) {
73344961713Sgirish 
73444961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
73544961713Sgirish 				"==> nxge_txdma_reclaim: Checking if pending"));
73644961713Sgirish 
73744961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
73844961713Sgirish 				"==> nxge_txdma_reclaim: "
73944961713Sgirish 				"descs_pending %d ",
74044961713Sgirish 				tx_ring_p->descs_pending));
74144961713Sgirish 
74244961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
74344961713Sgirish 				"==> nxge_txdma_reclaim: "
74444961713Sgirish 				"(tx_rd_index %d head_index %d "
74544961713Sgirish 				"(tx_desc_p $%p)",
74644961713Sgirish 				tx_rd_index, head_index,
74744961713Sgirish 				tx_desc_p));
74844961713Sgirish 
74944961713Sgirish 			tx_desc_pp->value = tx_desc_p->value;
75044961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
75144961713Sgirish 				"==> nxge_txdma_reclaim: "
75244961713Sgirish 				"(tx_rd_index %d head_index %d "
75344961713Sgirish 				"tx_desc_p $%p (desc value 0x%llx) ",
75444961713Sgirish 				tx_rd_index, head_index,
75544961713Sgirish 				tx_desc_pp, (*(uint64_t *)tx_desc_pp)));
75644961713Sgirish 
75744961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
75844961713Sgirish 				"==> nxge_txdma_reclaim: dump desc:"));
75944961713Sgirish 
76044961713Sgirish 			pkt_len = tx_desc_pp->bits.hdw.tr_len;
76144961713Sgirish 			tdc_stats->obytes += pkt_len;
76244961713Sgirish 			tdc_stats->opackets += tx_desc_pp->bits.hdw.sop;
76344961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
76444961713Sgirish 				"==> nxge_txdma_reclaim: pkt_len %d "
76544961713Sgirish 				"tdc channel %d opackets %d",
76644961713Sgirish 				pkt_len,
76744961713Sgirish 				tdc,
76844961713Sgirish 				tdc_stats->opackets));
76944961713Sgirish 
77044961713Sgirish 			if (tx_msg_p->flags.dma_type == USE_DVMA) {
77144961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
77244961713Sgirish 					"tx_desc_p = $%p "
77344961713Sgirish 					"tx_desc_pp = $%p "
77444961713Sgirish 					"index = %d",
77544961713Sgirish 					tx_desc_p,
77644961713Sgirish 					tx_desc_pp,
77744961713Sgirish 					tx_ring_p->rd_index));
77844961713Sgirish 				(void) dvma_unload(tx_msg_p->dvma_handle,
77944961713Sgirish 					0, -1);
78044961713Sgirish 				tx_msg_p->dvma_handle = NULL;
78144961713Sgirish 				if (tx_ring_p->dvma_wr_index ==
78244961713Sgirish 					tx_ring_p->dvma_wrap_mask) {
78344961713Sgirish 					tx_ring_p->dvma_wr_index = 0;
78444961713Sgirish 				} else {
78544961713Sgirish 					tx_ring_p->dvma_wr_index++;
78644961713Sgirish 				}
78744961713Sgirish 				tx_ring_p->dvma_pending--;
78844961713Sgirish 			} else if (tx_msg_p->flags.dma_type ==
78944961713Sgirish 					USE_DMA) {
79044961713Sgirish 				NXGE_DEBUG_MSG((nxgep, TX_CTL,
79144961713Sgirish 					"==> nxge_txdma_reclaim: "
79244961713Sgirish 					"USE DMA"));
79344961713Sgirish 				if (rc = ddi_dma_unbind_handle
79444961713Sgirish 					(tx_msg_p->dma_handle)) {
79544961713Sgirish 					cmn_err(CE_WARN, "!nxge_reclaim: "
79644961713Sgirish 						"ddi_dma_unbind_handle "
79744961713Sgirish 						"failed. status %d", rc);
79844961713Sgirish 				}
79944961713Sgirish 			}
80044961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
80144961713Sgirish 				"==> nxge_txdma_reclaim: count packets"));
80244961713Sgirish 			/*
80344961713Sgirish 			 * count a chained packet only once.
80444961713Sgirish 			 */
80544961713Sgirish 			if (tx_msg_p->tx_message != NULL) {
80644961713Sgirish 				freemsg(tx_msg_p->tx_message);
80744961713Sgirish 				tx_msg_p->tx_message = NULL;
80844961713Sgirish 			}
80944961713Sgirish 
81044961713Sgirish 			tx_msg_p->flags.dma_type = USE_NONE;
81144961713Sgirish 			tx_rd_index = tx_ring_p->rd_index;
81244961713Sgirish 			tx_rd_index = (tx_rd_index + 1) &
81344961713Sgirish 					tx_ring_p->tx_wrap_mask;
81444961713Sgirish 			tx_ring_p->rd_index = tx_rd_index;
81544961713Sgirish 			tx_ring_p->descs_pending--;
81644961713Sgirish 			tx_desc_p = &tx_desc_ring_vp[tx_rd_index];
81744961713Sgirish 			tx_msg_p = &tx_msg_ring[tx_rd_index];
81844961713Sgirish 		}
81944961713Sgirish 
82044961713Sgirish 		status = (nmblks <= (tx_ring_p->tx_ring_size -
82144961713Sgirish 				tx_ring_p->descs_pending -
82244961713Sgirish 				TX_FULL_MARK));
82344961713Sgirish 		if (status) {
82444961713Sgirish 			cas32((uint32_t *)&tx_ring_p->queueing, 1, 0);
82544961713Sgirish 		}
82644961713Sgirish 	} else {
82744961713Sgirish 		status = (nmblks <=
82844961713Sgirish 			(tx_ring_p->tx_ring_size -
82944961713Sgirish 				tx_ring_p->descs_pending -
83044961713Sgirish 				TX_FULL_MARK));
83144961713Sgirish 	}
83244961713Sgirish 
83344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
83444961713Sgirish 		"<== nxge_txdma_reclaim status = 0x%08x", status));
83544961713Sgirish 
83644961713Sgirish 	return (status);
83744961713Sgirish }
83844961713Sgirish 
83944961713Sgirish uint_t
84044961713Sgirish nxge_tx_intr(void *arg1, void *arg2)
84144961713Sgirish {
84244961713Sgirish 	p_nxge_ldv_t		ldvp = (p_nxge_ldv_t)arg1;
84344961713Sgirish 	p_nxge_t		nxgep = (p_nxge_t)arg2;
84444961713Sgirish 	p_nxge_ldg_t		ldgp;
84544961713Sgirish 	uint8_t			channel;
84644961713Sgirish 	uint32_t		vindex;
84744961713Sgirish 	npi_handle_t		handle;
84844961713Sgirish 	tx_cs_t			cs;
84944961713Sgirish 	p_tx_ring_t 		*tx_rings;
85044961713Sgirish 	p_tx_ring_t 		tx_ring_p;
85144961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
85244961713Sgirish 	uint_t 			serviced = DDI_INTR_UNCLAIMED;
85344961713Sgirish 	nxge_status_t 		status = NXGE_OK;
85444961713Sgirish 
85544961713Sgirish 	if (ldvp == NULL) {
85644961713Sgirish 		NXGE_DEBUG_MSG((NULL, INT_CTL,
85744961713Sgirish 			"<== nxge_tx_intr: nxgep $%p ldvp $%p",
85844961713Sgirish 			nxgep, ldvp));
85944961713Sgirish 		return (DDI_INTR_UNCLAIMED);
86044961713Sgirish 	}
86144961713Sgirish 
86244961713Sgirish 	if (arg2 == NULL || (void *)ldvp->nxgep != arg2) {
86344961713Sgirish 		nxgep = ldvp->nxgep;
86444961713Sgirish 	}
86544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
86644961713Sgirish 		"==> nxge_tx_intr: nxgep(arg2) $%p ldvp(arg1) $%p",
86744961713Sgirish 		nxgep, ldvp));
86844961713Sgirish 	/*
86944961713Sgirish 	 * This interrupt handler is for a specific
87044961713Sgirish 	 * transmit dma channel.
87144961713Sgirish 	 */
87244961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
87344961713Sgirish 	/* Get the control and status for this channel. */
87444961713Sgirish 	channel = ldvp->channel;
87544961713Sgirish 	ldgp = ldvp->ldgp;
87644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
87744961713Sgirish 		"==> nxge_tx_intr: nxgep $%p ldvp (ldvp) $%p "
87844961713Sgirish 		"channel %d",
87944961713Sgirish 		nxgep, ldvp, channel));
88044961713Sgirish 
88144961713Sgirish 	rs = npi_txdma_control_status(handle, OP_GET, channel, &cs);
88244961713Sgirish 	vindex = ldvp->vdma_index;
88344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL,
88444961713Sgirish 		"==> nxge_tx_intr:channel %d ring index %d status 0x%08x",
88544961713Sgirish 		channel, vindex, rs));
88644961713Sgirish 	if (!rs && cs.bits.ldw.mk) {
88744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
88844961713Sgirish 			"==> nxge_tx_intr:channel %d ring index %d "
88944961713Sgirish 			"status 0x%08x (mk bit set)",
89044961713Sgirish 			channel, vindex, rs));
89144961713Sgirish 		tx_rings = nxgep->tx_rings->rings;
89244961713Sgirish 		tx_ring_p = tx_rings[vindex];
89344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
89444961713Sgirish 			"==> nxge_tx_intr:channel %d ring index %d "
89544961713Sgirish 			"status 0x%08x (mk bit set, calling reclaim)",
89644961713Sgirish 			channel, vindex, rs));
89744961713Sgirish 
89844961713Sgirish 		MUTEX_ENTER(&tx_ring_p->lock);
89944961713Sgirish 		(void) nxge_txdma_reclaim(nxgep, tx_rings[vindex], 0);
90044961713Sgirish 		MUTEX_EXIT(&tx_ring_p->lock);
90144961713Sgirish 		mac_tx_update(nxgep->mach);
90244961713Sgirish 	}
90344961713Sgirish 
90444961713Sgirish 	/*
90544961713Sgirish 	 * Process other transmit control and status.
90644961713Sgirish 	 * Check the ldv state.
90744961713Sgirish 	 */
90844961713Sgirish 	status = nxge_tx_err_evnts(nxgep, ldvp->vdma_index, ldvp, cs);
90944961713Sgirish 	/*
91044961713Sgirish 	 * Rearm this logical group if this is a single device
91144961713Sgirish 	 * group.
91244961713Sgirish 	 */
91344961713Sgirish 	if (ldgp->nldvs == 1) {
91444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, INT_CTL,
91544961713Sgirish 			"==> nxge_tx_intr: rearm"));
91644961713Sgirish 		if (status == NXGE_OK) {
91744961713Sgirish 			(void) npi_intr_ldg_mgmt_set(handle, ldgp->ldg,
91844961713Sgirish 				B_TRUE, ldgp->ldg_timer);
91944961713Sgirish 		}
92044961713Sgirish 	}
92144961713Sgirish 
92244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_tx_intr"));
92344961713Sgirish 	serviced = DDI_INTR_CLAIMED;
92444961713Sgirish 	return (serviced);
92544961713Sgirish }
92644961713Sgirish 
92744961713Sgirish void
92844961713Sgirish nxge_txdma_stop(p_nxge_t nxgep)
92944961713Sgirish {
93044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop"));
93144961713Sgirish 
93244961713Sgirish 	(void) nxge_link_monitor(nxgep, LINK_MONITOR_STOP);
93344961713Sgirish 
93444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop"));
93544961713Sgirish }
93644961713Sgirish 
93744961713Sgirish void
93844961713Sgirish nxge_txdma_stop_start(p_nxge_t nxgep)
93944961713Sgirish {
94044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_start"));
94144961713Sgirish 
94244961713Sgirish 	(void) nxge_txdma_stop(nxgep);
94344961713Sgirish 
94444961713Sgirish 	(void) nxge_fixup_txdma_rings(nxgep);
94544961713Sgirish 	(void) nxge_txdma_hw_mode(nxgep, NXGE_DMA_START);
94644961713Sgirish 	(void) nxge_tx_mac_enable(nxgep);
94744961713Sgirish 	(void) nxge_txdma_hw_kick(nxgep);
94844961713Sgirish 
94944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_start"));
95044961713Sgirish }
95144961713Sgirish 
95244961713Sgirish nxge_status_t
95344961713Sgirish nxge_txdma_hw_mode(p_nxge_t nxgep, boolean_t enable)
95444961713Sgirish {
95544961713Sgirish 	int			i, ndmas;
95644961713Sgirish 	uint16_t		channel;
95744961713Sgirish 	p_tx_rings_t 		tx_rings;
95844961713Sgirish 	p_tx_ring_t 		*tx_desc_rings;
95944961713Sgirish 	npi_handle_t		handle;
96044961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
96144961713Sgirish 	nxge_status_t		status = NXGE_OK;
96244961713Sgirish 
96344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
96444961713Sgirish 		"==> nxge_txdma_hw_mode: enable mode %d", enable));
96544961713Sgirish 
96644961713Sgirish 	if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) {
96744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
96844961713Sgirish 			"<== nxge_txdma_mode: not initialized"));
96944961713Sgirish 		return (NXGE_ERROR);
97044961713Sgirish 	}
97144961713Sgirish 
97244961713Sgirish 	tx_rings = nxgep->tx_rings;
97344961713Sgirish 	if (tx_rings == NULL) {
97444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
97544961713Sgirish 			"<== nxge_txdma_hw_mode: NULL global ring pointer"));
97644961713Sgirish 		return (NXGE_ERROR);
97744961713Sgirish 	}
97844961713Sgirish 
97944961713Sgirish 	tx_desc_rings = tx_rings->rings;
98044961713Sgirish 	if (tx_desc_rings == NULL) {
98144961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
98244961713Sgirish 			"<== nxge_txdma_hw_mode: NULL rings pointer"));
98344961713Sgirish 		return (NXGE_ERROR);
98444961713Sgirish 	}
98544961713Sgirish 
98644961713Sgirish 	ndmas = tx_rings->ndmas;
98744961713Sgirish 	if (!ndmas) {
98844961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
98944961713Sgirish 			"<== nxge_txdma_hw_mode: no dma channel allocated"));
99044961713Sgirish 		return (NXGE_ERROR);
99144961713Sgirish 	}
99244961713Sgirish 
99344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_mode: "
99444961713Sgirish 		"tx_rings $%p tx_desc_rings $%p ndmas %d",
99544961713Sgirish 		tx_rings, tx_desc_rings, ndmas));
99644961713Sgirish 
99744961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
99844961713Sgirish 	for (i = 0; i < ndmas; i++) {
99944961713Sgirish 		if (tx_desc_rings[i] == NULL) {
100044961713Sgirish 			continue;
100144961713Sgirish 		}
100244961713Sgirish 		channel = tx_desc_rings[i]->tdc;
100344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
100444961713Sgirish 			"==> nxge_txdma_hw_mode: channel %d", channel));
100544961713Sgirish 		if (enable) {
100644961713Sgirish 			rs = npi_txdma_channel_enable(handle, channel);
100744961713Sgirish 			NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
100844961713Sgirish 				"==> nxge_txdma_hw_mode: channel %d (enable) "
100944961713Sgirish 				"rs 0x%x", channel, rs));
101044961713Sgirish 		} else {
101144961713Sgirish 			/*
101244961713Sgirish 			 * Stop the dma channel and waits for the stop done.
101344961713Sgirish 			 * If the stop done bit is not set, then force
101444961713Sgirish 			 * an error so TXC will stop.
101544961713Sgirish 			 * All channels bound to this port need to be stopped
101644961713Sgirish 			 * and reset after injecting an interrupt error.
101744961713Sgirish 			 */
101844961713Sgirish 			rs = npi_txdma_channel_disable(handle, channel);
101944961713Sgirish 			NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
102044961713Sgirish 				"==> nxge_txdma_hw_mode: channel %d (disable) "
102144961713Sgirish 				"rs 0x%x", channel, rs));
102244961713Sgirish 			{
102344961713Sgirish 				tdmc_intr_dbg_t		intr_dbg;
102444961713Sgirish 
102544961713Sgirish 				if (rs != NPI_SUCCESS) {
102644961713Sgirish 					/* Inject any error */
102744961713Sgirish 					intr_dbg.value = 0;
102844961713Sgirish 					intr_dbg.bits.ldw.nack_pref = 1;
102944961713Sgirish 					NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
103044961713Sgirish 						"==> nxge_txdma_hw_mode: "
103144961713Sgirish 						"channel %d (stop failed 0x%x) "
103244961713Sgirish 						"(inject err)", rs, channel));
103344961713Sgirish 					(void) npi_txdma_inj_int_error_set(
103444961713Sgirish 						handle, channel, &intr_dbg);
103544961713Sgirish 					rs = npi_txdma_channel_disable(handle,
103644961713Sgirish 						channel);
103744961713Sgirish 					NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
103844961713Sgirish 						"==> nxge_txdma_hw_mode: "
103944961713Sgirish 						"channel %d (stop again 0x%x) "
104044961713Sgirish 						"(after inject err)",
104144961713Sgirish 						rs, channel));
104244961713Sgirish 				}
104344961713Sgirish 			}
104444961713Sgirish 		}
104544961713Sgirish 	}
104644961713Sgirish 
104744961713Sgirish 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
104844961713Sgirish 
104944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
105044961713Sgirish 		"<== nxge_txdma_hw_mode: status 0x%x", status));
105144961713Sgirish 
105244961713Sgirish 	return (status);
105344961713Sgirish }
105444961713Sgirish 
105544961713Sgirish void
105644961713Sgirish nxge_txdma_enable_channel(p_nxge_t nxgep, uint16_t channel)
105744961713Sgirish {
105844961713Sgirish 	npi_handle_t		handle;
105944961713Sgirish 
106044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DMA_CTL,
106144961713Sgirish 		"==> nxge_txdma_enable_channel: channel %d", channel));
106244961713Sgirish 
106344961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
106444961713Sgirish 	/* enable the transmit dma channels */
106544961713Sgirish 	(void) npi_txdma_channel_enable(handle, channel);
106644961713Sgirish 
106744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DMA_CTL, "<== nxge_txdma_enable_channel"));
106844961713Sgirish }
106944961713Sgirish 
107044961713Sgirish void
107144961713Sgirish nxge_txdma_disable_channel(p_nxge_t nxgep, uint16_t channel)
107244961713Sgirish {
107344961713Sgirish 	npi_handle_t		handle;
107444961713Sgirish 
107544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DMA_CTL,
107644961713Sgirish 		"==> nxge_txdma_disable_channel: channel %d", channel));
107744961713Sgirish 
107844961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
107944961713Sgirish 	/* stop the transmit dma channels */
108044961713Sgirish 	(void) npi_txdma_channel_disable(handle, channel);
108144961713Sgirish 
108244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_disable_channel"));
108344961713Sgirish }
108444961713Sgirish 
108544961713Sgirish int
108644961713Sgirish nxge_txdma_stop_inj_err(p_nxge_t nxgep, int channel)
108744961713Sgirish {
108844961713Sgirish 	npi_handle_t		handle;
108944961713Sgirish 	tdmc_intr_dbg_t		intr_dbg;
109044961713Sgirish 	int			status;
109144961713Sgirish 	npi_status_t		rs = NPI_SUCCESS;
109244961713Sgirish 
109344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_stop_inj_err"));
109444961713Sgirish 	/*
109544961713Sgirish 	 * Stop the dma channel waits for the stop done.
109644961713Sgirish 	 * If the stop done bit is not set, then create
109744961713Sgirish 	 * an error.
109844961713Sgirish 	 */
109944961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
110044961713Sgirish 	rs = npi_txdma_channel_disable(handle, channel);
110144961713Sgirish 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
110244961713Sgirish 	if (status == NXGE_OK) {
110344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
110444961713Sgirish 			"<== nxge_txdma_stop_inj_err (channel %d): "
110544961713Sgirish 			"stopped OK", channel));
110644961713Sgirish 		return (status);
110744961713Sgirish 	}
110844961713Sgirish 
110944961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
111044961713Sgirish 		"==> nxge_txdma_stop_inj_err (channel %d): stop failed (0x%x) "
111144961713Sgirish 		"injecting error", channel, rs));
111244961713Sgirish 	/* Inject any error */
111344961713Sgirish 	intr_dbg.value = 0;
111444961713Sgirish 	intr_dbg.bits.ldw.nack_pref = 1;
111544961713Sgirish 	(void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg);
111644961713Sgirish 
111744961713Sgirish 	/* Stop done bit will be set as a result of error injection */
111844961713Sgirish 	rs = npi_txdma_channel_disable(handle, channel);
111944961713Sgirish 	status = ((rs == NPI_SUCCESS) ? NXGE_OK : NXGE_ERROR | rs);
112044961713Sgirish 	if (!(rs & NPI_TXDMA_STOP_FAILED)) {
112144961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
112244961713Sgirish 			"<== nxge_txdma_stop_inj_err (channel %d): "
112344961713Sgirish 			"stopped OK ", channel));
112444961713Sgirish 		return (status);
112544961713Sgirish 	}
112644961713Sgirish 
112744961713Sgirish #if	defined(NXGE_DEBUG)
112844961713Sgirish 	nxge_txdma_regs_dump_channels(nxgep);
112944961713Sgirish #endif
113044961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
113144961713Sgirish 		"==> nxge_txdma_stop_inj_err (channel): stop failed (0x%x) "
113244961713Sgirish 		" (injected error but still not stopped)", channel, rs));
113344961713Sgirish 
113444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_stop_inj_err"));
113544961713Sgirish 	return (status);
113644961713Sgirish }
113744961713Sgirish 
113844961713Sgirish void
113944961713Sgirish nxge_hw_start_tx(p_nxge_t nxgep)
114044961713Sgirish {
114144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "==> nxge_hw_start_tx"));
114244961713Sgirish 
114344961713Sgirish 	(void) nxge_txdma_hw_start(nxgep);
114444961713Sgirish 	(void) nxge_tx_mac_enable(nxgep);
114544961713Sgirish 
114644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "<== nxge_hw_start_tx"));
114744961713Sgirish }
114844961713Sgirish 
114944961713Sgirish /*ARGSUSED*/
115044961713Sgirish void
115144961713Sgirish nxge_fixup_txdma_rings(p_nxge_t nxgep)
115244961713Sgirish {
115344961713Sgirish 	int			index, ndmas;
115444961713Sgirish 	uint16_t		channel;
115544961713Sgirish 	p_tx_rings_t 		tx_rings;
115644961713Sgirish 
115744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_txdma_rings"));
115844961713Sgirish 
115944961713Sgirish 	/*
116044961713Sgirish 	 * For each transmit channel, reclaim each descriptor and
116144961713Sgirish 	 * free buffers.
116244961713Sgirish 	 */
116344961713Sgirish 	tx_rings = nxgep->tx_rings;
116444961713Sgirish 	if (tx_rings == NULL) {
116544961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
116644961713Sgirish 			"<== nxge_fixup_txdma_rings: NULL ring pointer"));
116744961713Sgirish 		return;
116844961713Sgirish 	}
116944961713Sgirish 
117044961713Sgirish 	ndmas = tx_rings->ndmas;
117144961713Sgirish 	if (!ndmas) {
117244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
117344961713Sgirish 			"<== nxge_fixup_txdma_rings: no channel allocated"));
117444961713Sgirish 		return;
117544961713Sgirish 	}
117644961713Sgirish 
117744961713Sgirish 	if (tx_rings->rings == NULL) {
117844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
117944961713Sgirish 			"<== nxge_fixup_txdma_rings: NULL rings pointer"));
118044961713Sgirish 		return;
118144961713Sgirish 	}
118244961713Sgirish 
118344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_fixup_txdma_rings: "
118444961713Sgirish 		"tx_rings $%p tx_desc_rings $%p ndmas %d",
118544961713Sgirish 		tx_rings, tx_rings->rings, ndmas));
118644961713Sgirish 
118744961713Sgirish 	for (index = 0; index < ndmas; index++) {
118844961713Sgirish 		channel = tx_rings->rings[index]->tdc;
118944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
119044961713Sgirish 			"==> nxge_fixup_txdma_rings: channel %d", channel));
119144961713Sgirish 
119244961713Sgirish 		nxge_txdma_fixup_channel(nxgep, tx_rings->rings[index],
119344961713Sgirish 			channel);
119444961713Sgirish 	}
119544961713Sgirish 
119644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_txdma_rings"));
119744961713Sgirish }
119844961713Sgirish 
119944961713Sgirish /*ARGSUSED*/
120044961713Sgirish void
120144961713Sgirish nxge_txdma_fix_channel(p_nxge_t nxgep, uint16_t channel)
120244961713Sgirish {
120344961713Sgirish 	p_tx_ring_t	ring_p;
120444961713Sgirish 
120544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_channel"));
120644961713Sgirish 	ring_p = nxge_txdma_get_ring(nxgep, channel);
120744961713Sgirish 	if (ring_p == NULL) {
120844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel"));
120944961713Sgirish 		return;
121044961713Sgirish 	}
121144961713Sgirish 
121244961713Sgirish 	if (ring_p->tdc != channel) {
121344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
121444961713Sgirish 			"<== nxge_txdma_fix_channel: channel not matched "
121544961713Sgirish 			"ring tdc %d passed channel",
121644961713Sgirish 			ring_p->tdc, channel));
121744961713Sgirish 		return;
121844961713Sgirish 	}
121944961713Sgirish 
122044961713Sgirish 	nxge_txdma_fixup_channel(nxgep, ring_p, channel);
122144961713Sgirish 
122244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_channel"));
122344961713Sgirish }
122444961713Sgirish 
122544961713Sgirish /*ARGSUSED*/
122644961713Sgirish void
122744961713Sgirish nxge_txdma_fixup_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel)
122844961713Sgirish {
122944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_channel"));
123044961713Sgirish 
123144961713Sgirish 	if (ring_p == NULL) {
123244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
123344961713Sgirish 			"<== nxge_txdma_fixup_channel: NULL ring pointer"));
123444961713Sgirish 		return;
123544961713Sgirish 	}
123644961713Sgirish 
123744961713Sgirish 	if (ring_p->tdc != channel) {
123844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
123944961713Sgirish 			"<== nxge_txdma_fixup_channel: channel not matched "
124044961713Sgirish 			"ring tdc %d passed channel",
124144961713Sgirish 			ring_p->tdc, channel));
124244961713Sgirish 		return;
124344961713Sgirish 	}
124444961713Sgirish 
124544961713Sgirish 	MUTEX_ENTER(&ring_p->lock);
124644961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, ring_p, 0);
124744961713Sgirish 	ring_p->rd_index = 0;
124844961713Sgirish 	ring_p->wr_index = 0;
124944961713Sgirish 	ring_p->ring_head.value = 0;
125044961713Sgirish 	ring_p->ring_kick_tail.value = 0;
125144961713Sgirish 	ring_p->descs_pending = 0;
125244961713Sgirish 	MUTEX_EXIT(&ring_p->lock);
125344961713Sgirish 
125444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_channel"));
125544961713Sgirish }
125644961713Sgirish 
125744961713Sgirish /*ARGSUSED*/
125844961713Sgirish void
125944961713Sgirish nxge_txdma_hw_kick(p_nxge_t nxgep)
126044961713Sgirish {
126144961713Sgirish 	int			index, ndmas;
126244961713Sgirish 	uint16_t		channel;
126344961713Sgirish 	p_tx_rings_t 		tx_rings;
126444961713Sgirish 
126544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick"));
126644961713Sgirish 
126744961713Sgirish 	tx_rings = nxgep->tx_rings;
126844961713Sgirish 	if (tx_rings == NULL) {
126944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
127044961713Sgirish 			"<== nxge_txdma_hw_kick: NULL ring pointer"));
127144961713Sgirish 		return;
127244961713Sgirish 	}
127344961713Sgirish 
127444961713Sgirish 	ndmas = tx_rings->ndmas;
127544961713Sgirish 	if (!ndmas) {
127644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
127744961713Sgirish 			"<== nxge_txdma_hw_kick: no channel allocated"));
127844961713Sgirish 		return;
127944961713Sgirish 	}
128044961713Sgirish 
128144961713Sgirish 	if (tx_rings->rings == NULL) {
128244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
128344961713Sgirish 			"<== nxge_txdma_hw_kick: NULL rings pointer"));
128444961713Sgirish 		return;
128544961713Sgirish 	}
128644961713Sgirish 
128744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_kick: "
128844961713Sgirish 		"tx_rings $%p tx_desc_rings $%p ndmas %d",
128944961713Sgirish 		tx_rings, tx_rings->rings, ndmas));
129044961713Sgirish 
129144961713Sgirish 	for (index = 0; index < ndmas; index++) {
129244961713Sgirish 		channel = tx_rings->rings[index]->tdc;
129344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
129444961713Sgirish 			"==> nxge_txdma_hw_kick: channel %d", channel));
129544961713Sgirish 		nxge_txdma_hw_kick_channel(nxgep, tx_rings->rings[index],
129644961713Sgirish 			channel);
129744961713Sgirish 	}
129844961713Sgirish 
129944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick"));
130044961713Sgirish }
130144961713Sgirish 
130244961713Sgirish /*ARGSUSED*/
130344961713Sgirish void
130444961713Sgirish nxge_txdma_kick_channel(p_nxge_t nxgep, uint16_t channel)
130544961713Sgirish {
130644961713Sgirish 	p_tx_ring_t	ring_p;
130744961713Sgirish 
130844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_kick_channel"));
130944961713Sgirish 
131044961713Sgirish 	ring_p = nxge_txdma_get_ring(nxgep, channel);
131144961713Sgirish 	if (ring_p == NULL) {
131244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
131344961713Sgirish 			    " nxge_txdma_kick_channel"));
131444961713Sgirish 		return;
131544961713Sgirish 	}
131644961713Sgirish 
131744961713Sgirish 	if (ring_p->tdc != channel) {
131844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
131944961713Sgirish 			"<== nxge_txdma_kick_channel: channel not matched "
132044961713Sgirish 			"ring tdc %d passed channel",
132144961713Sgirish 			ring_p->tdc, channel));
132244961713Sgirish 		return;
132344961713Sgirish 	}
132444961713Sgirish 
132544961713Sgirish 	nxge_txdma_hw_kick_channel(nxgep, ring_p, channel);
132644961713Sgirish 
132744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_kick_channel"));
132844961713Sgirish }
1329a3c5bd6dSspeer 
133044961713Sgirish /*ARGSUSED*/
133144961713Sgirish void
133244961713Sgirish nxge_txdma_hw_kick_channel(p_nxge_t nxgep, p_tx_ring_t ring_p, uint16_t channel)
133344961713Sgirish {
133444961713Sgirish 
133544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hw_kick_channel"));
133644961713Sgirish 
133744961713Sgirish 	if (ring_p == NULL) {
133844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
133944961713Sgirish 			"<== nxge_txdma_hw_kick_channel: NULL ring pointer"));
134044961713Sgirish 		return;
134144961713Sgirish 	}
134244961713Sgirish 
134344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hw_kick_channel"));
134444961713Sgirish }
134544961713Sgirish 
134644961713Sgirish /*ARGSUSED*/
134744961713Sgirish void
134844961713Sgirish nxge_check_tx_hang(p_nxge_t nxgep)
134944961713Sgirish {
135044961713Sgirish 
135144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_check_tx_hang"));
135244961713Sgirish 
135344961713Sgirish 	/*
135444961713Sgirish 	 * Needs inputs from hardware for regs:
135544961713Sgirish 	 *	head index had not moved since last timeout.
135644961713Sgirish 	 *	packets not transmitted or stuffed registers.
135744961713Sgirish 	 */
135844961713Sgirish 	if (nxge_txdma_hung(nxgep)) {
135944961713Sgirish 		nxge_fixup_hung_txdma_rings(nxgep);
136044961713Sgirish 	}
136144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_check_tx_hang"));
136244961713Sgirish }
136344961713Sgirish 
136444961713Sgirish int
136544961713Sgirish nxge_txdma_hung(p_nxge_t nxgep)
136644961713Sgirish {
136744961713Sgirish 	int			index, ndmas;
136844961713Sgirish 	uint16_t		channel;
136944961713Sgirish 	p_tx_rings_t 		tx_rings;
137044961713Sgirish 	p_tx_ring_t 		tx_ring_p;
137144961713Sgirish 
137244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_hung"));
137344961713Sgirish 	tx_rings = nxgep->tx_rings;
137444961713Sgirish 	if (tx_rings == NULL) {
137544961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
137644961713Sgirish 			"<== nxge_txdma_hung: NULL ring pointer"));
137744961713Sgirish 		return (B_FALSE);
137844961713Sgirish 	}
137944961713Sgirish 
138044961713Sgirish 	ndmas = tx_rings->ndmas;
138144961713Sgirish 	if (!ndmas) {
138244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
138344961713Sgirish 			"<== nxge_txdma_hung: no channel "
138444961713Sgirish 			"allocated"));
138544961713Sgirish 		return (B_FALSE);
138644961713Sgirish 	}
138744961713Sgirish 
138844961713Sgirish 	if (tx_rings->rings == NULL) {
138944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
139044961713Sgirish 			"<== nxge_txdma_hung: NULL rings pointer"));
139144961713Sgirish 		return (B_FALSE);
139244961713Sgirish 	}
139344961713Sgirish 
139444961713Sgirish 	for (index = 0; index < ndmas; index++) {
139544961713Sgirish 		channel = tx_rings->rings[index]->tdc;
139644961713Sgirish 		tx_ring_p = tx_rings->rings[index];
139744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
139844961713Sgirish 			"==> nxge_txdma_hung: channel %d", channel));
139944961713Sgirish 		if (nxge_txdma_channel_hung(nxgep, tx_ring_p, channel)) {
140044961713Sgirish 			return (B_TRUE);
140144961713Sgirish 		}
140244961713Sgirish 	}
140344961713Sgirish 
140444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_hung"));
140544961713Sgirish 
140644961713Sgirish 	return (B_FALSE);
140744961713Sgirish }
140844961713Sgirish 
140944961713Sgirish int
141044961713Sgirish nxge_txdma_channel_hung(p_nxge_t nxgep, p_tx_ring_t tx_ring_p, uint16_t channel)
141144961713Sgirish {
141244961713Sgirish 	uint16_t		head_index, tail_index;
141344961713Sgirish 	boolean_t		head_wrap, tail_wrap;
141444961713Sgirish 	npi_handle_t		handle;
141544961713Sgirish 	tx_ring_hdl_t		tx_head;
141644961713Sgirish 	uint_t			tx_rd_index;
141744961713Sgirish 
141844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_channel_hung"));
141944961713Sgirish 
142044961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
142144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
142244961713Sgirish 		"==> nxge_txdma_channel_hung: channel %d", channel));
142344961713Sgirish 	MUTEX_ENTER(&tx_ring_p->lock);
142444961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
142544961713Sgirish 
142644961713Sgirish 	tail_index = tx_ring_p->wr_index;
142744961713Sgirish 	tail_wrap = tx_ring_p->wr_index_wrap;
142844961713Sgirish 	tx_rd_index = tx_ring_p->rd_index;
142944961713Sgirish 	MUTEX_EXIT(&tx_ring_p->lock);
143044961713Sgirish 
143144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
143244961713Sgirish 		"==> nxge_txdma_channel_hung: tdc %d tx_rd_index %d "
143344961713Sgirish 		"tail_index %d tail_wrap %d ",
143444961713Sgirish 		channel, tx_rd_index, tail_index, tail_wrap));
143544961713Sgirish 	/*
143644961713Sgirish 	 * Read the hardware maintained transmit head
143744961713Sgirish 	 * and wrap around bit.
143844961713Sgirish 	 */
143944961713Sgirish 	(void) npi_txdma_ring_head_get(handle, channel, &tx_head);
144044961713Sgirish 	head_index =  tx_head.bits.ldw.head;
144144961713Sgirish 	head_wrap = tx_head.bits.ldw.wrap;
144244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
144344961713Sgirish 		"==> nxge_txdma_channel_hung: "
144444961713Sgirish 		"tx_rd_index %d tail %d tail_wrap %d "
144544961713Sgirish 		"head %d wrap %d",
144644961713Sgirish 		tx_rd_index, tail_index, tail_wrap,
144744961713Sgirish 		head_index, head_wrap));
144844961713Sgirish 
144944961713Sgirish 	if (TXDMA_RING_EMPTY(head_index, head_wrap,
145044961713Sgirish 			tail_index, tail_wrap) &&
145144961713Sgirish 			(head_index == tx_rd_index)) {
145244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
145344961713Sgirish 			"==> nxge_txdma_channel_hung: EMPTY"));
145444961713Sgirish 		return (B_FALSE);
145544961713Sgirish 	}
145644961713Sgirish 
145744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
145844961713Sgirish 		"==> nxge_txdma_channel_hung: Checking if ring full"));
145944961713Sgirish 	if (TXDMA_RING_FULL(head_index, head_wrap, tail_index,
146044961713Sgirish 			tail_wrap)) {
146144961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
146244961713Sgirish 			"==> nxge_txdma_channel_hung: full"));
146344961713Sgirish 		return (B_TRUE);
146444961713Sgirish 	}
146544961713Sgirish 
146644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_channel_hung"));
146744961713Sgirish 
146844961713Sgirish 	return (B_FALSE);
146944961713Sgirish }
147044961713Sgirish 
147144961713Sgirish /*ARGSUSED*/
147244961713Sgirish void
147344961713Sgirish nxge_fixup_hung_txdma_rings(p_nxge_t nxgep)
147444961713Sgirish {
147544961713Sgirish 	int			index, ndmas;
147644961713Sgirish 	uint16_t		channel;
147744961713Sgirish 	p_tx_rings_t 		tx_rings;
147844961713Sgirish 
147944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_hung_txdma_rings"));
148044961713Sgirish 	tx_rings = nxgep->tx_rings;
148144961713Sgirish 	if (tx_rings == NULL) {
148244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
148344961713Sgirish 			"<== nxge_fixup_hung_txdma_rings: NULL ring pointer"));
148444961713Sgirish 		return;
148544961713Sgirish 	}
148644961713Sgirish 
148744961713Sgirish 	ndmas = tx_rings->ndmas;
148844961713Sgirish 	if (!ndmas) {
148944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
149044961713Sgirish 			"<== nxge_fixup_hung_txdma_rings: no channel "
149144961713Sgirish 			"allocated"));
149244961713Sgirish 		return;
149344961713Sgirish 	}
149444961713Sgirish 
149544961713Sgirish 	if (tx_rings->rings == NULL) {
149644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
149744961713Sgirish 			"<== nxge_fixup_hung_txdma_rings: NULL rings pointer"));
149844961713Sgirish 		return;
149944961713Sgirish 	}
150044961713Sgirish 
150144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_fixup_hung_txdma_rings: "
150244961713Sgirish 		"tx_rings $%p tx_desc_rings $%p ndmas %d",
150344961713Sgirish 		tx_rings, tx_rings->rings, ndmas));
150444961713Sgirish 
150544961713Sgirish 	for (index = 0; index < ndmas; index++) {
150644961713Sgirish 		channel = tx_rings->rings[index]->tdc;
150744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
150844961713Sgirish 			"==> nxge_fixup_hung_txdma_rings: channel %d",
150944961713Sgirish 			channel));
151044961713Sgirish 
151144961713Sgirish 		nxge_txdma_fixup_hung_channel(nxgep, tx_rings->rings[index],
151244961713Sgirish 			channel);
151344961713Sgirish 	}
151444961713Sgirish 
151544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_fixup_hung_txdma_rings"));
151644961713Sgirish }
151744961713Sgirish 
151844961713Sgirish /*ARGSUSED*/
151944961713Sgirish void
152044961713Sgirish nxge_txdma_fix_hung_channel(p_nxge_t nxgep, uint16_t channel)
152144961713Sgirish {
152244961713Sgirish 	p_tx_ring_t	ring_p;
152344961713Sgirish 
152444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fix_hung_channel"));
152544961713Sgirish 	ring_p = nxge_txdma_get_ring(nxgep, channel);
152644961713Sgirish 	if (ring_p == NULL) {
152744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
152844961713Sgirish 			"<== nxge_txdma_fix_hung_channel"));
152944961713Sgirish 		return;
153044961713Sgirish 	}
153144961713Sgirish 
153244961713Sgirish 	if (ring_p->tdc != channel) {
153344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
153444961713Sgirish 			"<== nxge_txdma_fix_hung_channel: channel not matched "
153544961713Sgirish 			"ring tdc %d passed channel",
153644961713Sgirish 			ring_p->tdc, channel));
153744961713Sgirish 		return;
153844961713Sgirish 	}
153944961713Sgirish 
154044961713Sgirish 	nxge_txdma_fixup_channel(nxgep, ring_p, channel);
154144961713Sgirish 
154244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fix_hung_channel"));
154344961713Sgirish }
154444961713Sgirish 
154544961713Sgirish /*ARGSUSED*/
154644961713Sgirish void
154744961713Sgirish nxge_txdma_fixup_hung_channel(p_nxge_t nxgep, p_tx_ring_t ring_p,
154844961713Sgirish 	uint16_t channel)
154944961713Sgirish {
155044961713Sgirish 	npi_handle_t		handle;
155144961713Sgirish 	tdmc_intr_dbg_t		intr_dbg;
155244961713Sgirish 	int			status = NXGE_OK;
155344961713Sgirish 
155444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fixup_hung_channel"));
155544961713Sgirish 
155644961713Sgirish 	if (ring_p == NULL) {
155744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
155844961713Sgirish 			"<== nxge_txdma_fixup_channel: NULL ring pointer"));
155944961713Sgirish 		return;
156044961713Sgirish 	}
156144961713Sgirish 
156244961713Sgirish 	if (ring_p->tdc != channel) {
156344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
156444961713Sgirish 			"<== nxge_txdma_fixup_hung_channel: channel "
156544961713Sgirish 			"not matched "
156644961713Sgirish 			"ring tdc %d passed channel",
156744961713Sgirish 			ring_p->tdc, channel));
156844961713Sgirish 		return;
156944961713Sgirish 	}
157044961713Sgirish 
157144961713Sgirish 	/* Reclaim descriptors */
157244961713Sgirish 	MUTEX_ENTER(&ring_p->lock);
157344961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, ring_p, 0);
157444961713Sgirish 	MUTEX_EXIT(&ring_p->lock);
157544961713Sgirish 
157644961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
157744961713Sgirish 	/*
157844961713Sgirish 	 * Stop the dma channel waits for the stop done.
157944961713Sgirish 	 * If the stop done bit is not set, then force
158044961713Sgirish 	 * an error.
158144961713Sgirish 	 */
158244961713Sgirish 	status = npi_txdma_channel_disable(handle, channel);
158344961713Sgirish 	if (!(status & NPI_TXDMA_STOP_FAILED)) {
158444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
158544961713Sgirish 			"<== nxge_txdma_fixup_hung_channel: stopped OK "
158644961713Sgirish 			"ring tdc %d passed channel %d",
158744961713Sgirish 			ring_p->tdc, channel));
158844961713Sgirish 		return;
158944961713Sgirish 	}
159044961713Sgirish 
159144961713Sgirish 	/* Inject any error */
159244961713Sgirish 	intr_dbg.value = 0;
159344961713Sgirish 	intr_dbg.bits.ldw.nack_pref = 1;
159444961713Sgirish 	(void) npi_txdma_inj_int_error_set(handle, channel, &intr_dbg);
159544961713Sgirish 
159644961713Sgirish 	/* Stop done bit will be set as a result of error injection */
159744961713Sgirish 	status = npi_txdma_channel_disable(handle, channel);
159844961713Sgirish 	if (!(status & NPI_TXDMA_STOP_FAILED)) {
159944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
160044961713Sgirish 			"<== nxge_txdma_fixup_hung_channel: stopped again"
160144961713Sgirish 			"ring tdc %d passed channel",
160244961713Sgirish 			ring_p->tdc, channel));
160344961713Sgirish 		return;
160444961713Sgirish 	}
160544961713Sgirish 
160644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
160744961713Sgirish 		"<== nxge_txdma_fixup_hung_channel: stop done still not set!! "
160844961713Sgirish 		"ring tdc %d passed channel",
160944961713Sgirish 		ring_p->tdc, channel));
161044961713Sgirish 
161144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fixup_hung_channel"));
161244961713Sgirish }
161344961713Sgirish 
161444961713Sgirish /*ARGSUSED*/
161544961713Sgirish void
161644961713Sgirish nxge_reclaim_rings(p_nxge_t nxgep)
161744961713Sgirish {
161844961713Sgirish 	int			index, ndmas;
161944961713Sgirish 	uint16_t		channel;
162044961713Sgirish 	p_tx_rings_t 		tx_rings;
162144961713Sgirish 	p_tx_ring_t 		tx_ring_p;
162244961713Sgirish 
162344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_reclaim_ring"));
162444961713Sgirish 	tx_rings = nxgep->tx_rings;
162544961713Sgirish 	if (tx_rings == NULL) {
162644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
162744961713Sgirish 			"<== nxge_reclain_rimgs: NULL ring pointer"));
162844961713Sgirish 		return;
162944961713Sgirish 	}
163044961713Sgirish 
163144961713Sgirish 	ndmas = tx_rings->ndmas;
163244961713Sgirish 	if (!ndmas) {
163344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
163444961713Sgirish 			"<== nxge_reclain_rimgs: no channel "
163544961713Sgirish 			"allocated"));
163644961713Sgirish 		return;
163744961713Sgirish 	}
163844961713Sgirish 
163944961713Sgirish 	if (tx_rings->rings == NULL) {
164044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
164144961713Sgirish 			"<== nxge_reclain_rimgs: NULL rings pointer"));
164244961713Sgirish 		return;
164344961713Sgirish 	}
164444961713Sgirish 
164544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_reclain_rimgs: "
164644961713Sgirish 		"tx_rings $%p tx_desc_rings $%p ndmas %d",
164744961713Sgirish 		tx_rings, tx_rings->rings, ndmas));
164844961713Sgirish 
164944961713Sgirish 	for (index = 0; index < ndmas; index++) {
165044961713Sgirish 		channel = tx_rings->rings[index]->tdc;
165144961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
165244961713Sgirish 			"==> reclain_rimgs: channel %d",
165344961713Sgirish 			channel));
165444961713Sgirish 		tx_ring_p = tx_rings->rings[index];
165544961713Sgirish 		MUTEX_ENTER(&tx_ring_p->lock);
165644961713Sgirish 		(void) nxge_txdma_reclaim(nxgep, tx_ring_p, channel);
165744961713Sgirish 		MUTEX_EXIT(&tx_ring_p->lock);
165844961713Sgirish 	}
165944961713Sgirish 
166044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_reclaim_rings"));
166144961713Sgirish }
166244961713Sgirish 
166344961713Sgirish void
166444961713Sgirish nxge_txdma_regs_dump_channels(p_nxge_t nxgep)
166544961713Sgirish {
166644961713Sgirish 	int			index, ndmas;
166744961713Sgirish 	uint16_t		channel;
166844961713Sgirish 	p_tx_rings_t 		tx_rings;
166944961713Sgirish 	npi_handle_t		handle;
167044961713Sgirish 
167144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, RX_CTL, "==> nxge_txdma_regs_dump_channels"));
167244961713Sgirish 
167344961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
167444961713Sgirish 	(void) npi_txdma_dump_fzc_regs(handle);
167544961713Sgirish 
167644961713Sgirish 	tx_rings = nxgep->tx_rings;
167744961713Sgirish 	if (tx_rings == NULL) {
167844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
167944961713Sgirish 			"<== nxge_txdma_regs_dump_channels: NULL ring"));
168044961713Sgirish 		return;
168144961713Sgirish 	}
168244961713Sgirish 
168344961713Sgirish 	ndmas = tx_rings->ndmas;
168444961713Sgirish 	if (!ndmas) {
168544961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
168644961713Sgirish 			"<== nxge_txdma_regs_dump_channels: "
168744961713Sgirish 			"no channel allocated"));
168844961713Sgirish 		return;
168944961713Sgirish 	}
169044961713Sgirish 
169144961713Sgirish 	if (tx_rings->rings == NULL) {
169244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
169344961713Sgirish 			"<== nxge_txdma_regs_dump_channels: NULL rings"));
169444961713Sgirish 		return;
169544961713Sgirish 	}
169644961713Sgirish 
169744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_regs_dump_channels: "
169844961713Sgirish 		"tx_rings $%p tx_desc_rings $%p ndmas %d",
169944961713Sgirish 		tx_rings, tx_rings->rings, ndmas));
170044961713Sgirish 
170144961713Sgirish 	for (index = 0; index < ndmas; index++) {
170244961713Sgirish 		channel = tx_rings->rings[index]->tdc;
170344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
170444961713Sgirish 			"==> nxge_txdma_regs_dump_channels: channel %d",
170544961713Sgirish 			channel));
170644961713Sgirish 		(void) npi_txdma_dump_tdc_regs(handle, channel);
170744961713Sgirish 	}
170844961713Sgirish 
170944961713Sgirish 	/* Dump TXC registers */
171044961713Sgirish 	(void) npi_txc_dump_fzc_regs(handle);
171144961713Sgirish 	(void) npi_txc_dump_port_fzc_regs(handle, nxgep->function_num);
171244961713Sgirish 
171344961713Sgirish 	for (index = 0; index < ndmas; index++) {
171444961713Sgirish 		channel = tx_rings->rings[index]->tdc;
171544961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
171644961713Sgirish 			"==> nxge_txdma_regs_dump_channels: channel %d",
171744961713Sgirish 			channel));
171844961713Sgirish 		(void) npi_txc_dump_tdc_fzc_regs(handle, channel);
171944961713Sgirish 	}
172044961713Sgirish 
172144961713Sgirish 	for (index = 0; index < ndmas; index++) {
172244961713Sgirish 		channel = tx_rings->rings[index]->tdc;
172344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
172444961713Sgirish 			"==> nxge_txdma_regs_dump_channels: channel %d",
172544961713Sgirish 			channel));
172644961713Sgirish 		nxge_txdma_regs_dump(nxgep, channel);
172744961713Sgirish 	}
172844961713Sgirish 
172944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_regs_dump"));
173044961713Sgirish 
173144961713Sgirish }
173244961713Sgirish 
173344961713Sgirish void
173444961713Sgirish nxge_txdma_regs_dump(p_nxge_t nxgep, int channel)
173544961713Sgirish {
173644961713Sgirish 	npi_handle_t		handle;
173744961713Sgirish 	tx_ring_hdl_t 		hdl;
173844961713Sgirish 	tx_ring_kick_t 		kick;
173944961713Sgirish 	tx_cs_t 		cs;
174044961713Sgirish 	txc_control_t		control;
174144961713Sgirish 	uint32_t		bitmap = 0;
174244961713Sgirish 	uint32_t		burst = 0;
174344961713Sgirish 	uint32_t		bytes = 0;
174444961713Sgirish 	dma_log_page_t		cfg;
174544961713Sgirish 
174644961713Sgirish 	printf("\n\tfunc # %d tdc %d ",
174744961713Sgirish 		nxgep->function_num, channel);
174844961713Sgirish 	cfg.page_num = 0;
174944961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
175044961713Sgirish 	(void) npi_txdma_log_page_get(handle, channel, &cfg);
175144961713Sgirish 	printf("\n\tlog page func %d valid page 0 %d",
175244961713Sgirish 		cfg.func_num, cfg.valid);
175344961713Sgirish 	cfg.page_num = 1;
175444961713Sgirish 	(void) npi_txdma_log_page_get(handle, channel, &cfg);
175544961713Sgirish 	printf("\n\tlog page func %d valid page 1 %d",
175644961713Sgirish 		cfg.func_num, cfg.valid);
175744961713Sgirish 
175844961713Sgirish 	(void) npi_txdma_ring_head_get(handle, channel, &hdl);
175944961713Sgirish 	(void) npi_txdma_desc_kick_reg_get(handle, channel, &kick);
176044961713Sgirish 	printf("\n\thead value is 0x%0llx",
176144961713Sgirish 		(long long)hdl.value);
176244961713Sgirish 	printf("\n\thead index %d", hdl.bits.ldw.head);
176344961713Sgirish 	printf("\n\tkick value is 0x%0llx",
176444961713Sgirish 		(long long)kick.value);
176544961713Sgirish 	printf("\n\ttail index %d\n", kick.bits.ldw.tail);
176644961713Sgirish 
176744961713Sgirish 	(void) npi_txdma_control_status(handle, OP_GET, channel, &cs);
176844961713Sgirish 	printf("\n\tControl statue is 0x%0llx", (long long)cs.value);
176944961713Sgirish 	printf("\n\tControl status RST state %d", cs.bits.ldw.rst);
177044961713Sgirish 
177144961713Sgirish 	(void) npi_txc_control(handle, OP_GET, &control);
177244961713Sgirish 	(void) npi_txc_port_dma_list_get(handle, nxgep->function_num, &bitmap);
177344961713Sgirish 	(void) npi_txc_dma_max_burst(handle, OP_GET, channel, &burst);
177444961713Sgirish 	(void) npi_txc_dma_bytes_transmitted(handle, channel, &bytes);
177544961713Sgirish 
177644961713Sgirish 	printf("\n\tTXC port control 0x%0llx",
177744961713Sgirish 		(long long)control.value);
177844961713Sgirish 	printf("\n\tTXC port bitmap 0x%x", bitmap);
177944961713Sgirish 	printf("\n\tTXC max burst %d", burst);
178044961713Sgirish 	printf("\n\tTXC bytes xmt %d\n", bytes);
178144961713Sgirish 
178244961713Sgirish 	{
178344961713Sgirish 		ipp_status_t status;
178444961713Sgirish 
178544961713Sgirish 		(void) npi_ipp_get_status(handle, nxgep->function_num, &status);
178644961713Sgirish 		printf("\n\tIPP status 0x%lux\n", (uint64_t)status.value);
178744961713Sgirish 	}
178844961713Sgirish }
178944961713Sgirish 
179044961713Sgirish /*
179144961713Sgirish  * Static functions start here.
179244961713Sgirish  */
179344961713Sgirish static nxge_status_t
179444961713Sgirish nxge_map_txdma(p_nxge_t nxgep)
179544961713Sgirish {
179644961713Sgirish 	int			i, ndmas;
179744961713Sgirish 	uint16_t		channel;
179844961713Sgirish 	p_tx_rings_t 		tx_rings;
179944961713Sgirish 	p_tx_ring_t 		*tx_desc_rings;
180044961713Sgirish 	p_tx_mbox_areas_t 	tx_mbox_areas_p;
180144961713Sgirish 	p_tx_mbox_t		*tx_mbox_p;
180244961713Sgirish 	p_nxge_dma_pool_t	dma_buf_poolp;
180344961713Sgirish 	p_nxge_dma_pool_t	dma_cntl_poolp;
180444961713Sgirish 	p_nxge_dma_common_t	*dma_buf_p;
180544961713Sgirish 	p_nxge_dma_common_t	*dma_cntl_p;
180644961713Sgirish 	nxge_status_t		status = NXGE_OK;
180744961713Sgirish #if	defined(sun4v) && defined(NIU_LP_WORKAROUND)
180844961713Sgirish 	p_nxge_dma_common_t	t_dma_buf_p;
180944961713Sgirish 	p_nxge_dma_common_t	t_dma_cntl_p;
181044961713Sgirish #endif
181144961713Sgirish 
181244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma"));
181344961713Sgirish 
181444961713Sgirish 	dma_buf_poolp = nxgep->tx_buf_pool_p;
181544961713Sgirish 	dma_cntl_poolp = nxgep->tx_cntl_pool_p;
181644961713Sgirish 
181744961713Sgirish 	if (!dma_buf_poolp->buf_allocated || !dma_cntl_poolp->buf_allocated) {
181844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
181944961713Sgirish 			"==> nxge_map_txdma: buf not allocated"));
182044961713Sgirish 		return (NXGE_ERROR);
182144961713Sgirish 	}
182244961713Sgirish 
182344961713Sgirish 	ndmas = dma_buf_poolp->ndmas;
182444961713Sgirish 	if (!ndmas) {
182544961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
182644961713Sgirish 			"<== nxge_map_txdma: no dma allocated"));
182744961713Sgirish 		return (NXGE_ERROR);
182844961713Sgirish 	}
182944961713Sgirish 
183044961713Sgirish 	dma_buf_p = dma_buf_poolp->dma_buf_pool_p;
183144961713Sgirish 	dma_cntl_p = dma_cntl_poolp->dma_buf_pool_p;
183244961713Sgirish 
183344961713Sgirish 	tx_rings = (p_tx_rings_t)
183444961713Sgirish 			KMEM_ZALLOC(sizeof (tx_rings_t), KM_SLEEP);
183544961713Sgirish 	tx_desc_rings = (p_tx_ring_t *)KMEM_ZALLOC(
183644961713Sgirish 			sizeof (p_tx_ring_t) * ndmas, KM_SLEEP);
183744961713Sgirish 
183844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: "
183944961713Sgirish 		"tx_rings $%p tx_desc_rings $%p",
184044961713Sgirish 		tx_rings, tx_desc_rings));
184144961713Sgirish 
184244961713Sgirish 	tx_mbox_areas_p = (p_tx_mbox_areas_t)
184344961713Sgirish 			KMEM_ZALLOC(sizeof (tx_mbox_areas_t), KM_SLEEP);
184444961713Sgirish 	tx_mbox_p = (p_tx_mbox_t *)KMEM_ZALLOC(
184544961713Sgirish 			sizeof (p_tx_mbox_t) * ndmas, KM_SLEEP);
184644961713Sgirish 
184744961713Sgirish 	/*
184844961713Sgirish 	 * Map descriptors from the buffer pools for each dma channel.
184944961713Sgirish 	 */
185044961713Sgirish 	for (i = 0; i < ndmas; i++) {
185144961713Sgirish 		/*
185244961713Sgirish 		 * Set up and prepare buffer blocks, descriptors
185344961713Sgirish 		 * and mailbox.
185444961713Sgirish 		 */
185544961713Sgirish 		channel = ((p_nxge_dma_common_t)dma_buf_p[i])->dma_channel;
185644961713Sgirish 		status = nxge_map_txdma_channel(nxgep, channel,
185744961713Sgirish 				(p_nxge_dma_common_t *)&dma_buf_p[i],
185844961713Sgirish 				(p_tx_ring_t *)&tx_desc_rings[i],
185944961713Sgirish 				dma_buf_poolp->num_chunks[i],
186044961713Sgirish 				(p_nxge_dma_common_t *)&dma_cntl_p[i],
186144961713Sgirish 				(p_tx_mbox_t *)&tx_mbox_p[i]);
186244961713Sgirish 		if (status != NXGE_OK) {
186344961713Sgirish 			goto nxge_map_txdma_fail1;
186444961713Sgirish 		}
186544961713Sgirish 		tx_desc_rings[i]->index = (uint16_t)i;
186644961713Sgirish 		tx_desc_rings[i]->tdc_stats = &nxgep->statsp->tdc_stats[i];
186744961713Sgirish 
186844961713Sgirish #if	defined(sun4v) && defined(NIU_LP_WORKAROUND)
186944961713Sgirish 		if (nxgep->niu_type == N2_NIU && NXGE_DMA_BLOCK == 1) {
187044961713Sgirish 			tx_desc_rings[i]->hv_set = B_FALSE;
187144961713Sgirish 			t_dma_buf_p = (p_nxge_dma_common_t)dma_buf_p[i];
187244961713Sgirish 			t_dma_cntl_p = (p_nxge_dma_common_t)dma_cntl_p[i];
187344961713Sgirish 
187444961713Sgirish 			tx_desc_rings[i]->hv_tx_buf_base_ioaddr_pp =
187544961713Sgirish 				(uint64_t)t_dma_buf_p->orig_ioaddr_pp;
187644961713Sgirish 			tx_desc_rings[i]->hv_tx_buf_ioaddr_size =
187744961713Sgirish 				(uint64_t)t_dma_buf_p->orig_alength;
187844961713Sgirish 
187944961713Sgirish 			NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
188044961713Sgirish 				"==> nxge_map_txdma_channel: "
188144961713Sgirish 				"hv data buf base io $%p "
188244961713Sgirish 				"size 0x%llx (%d) "
188344961713Sgirish 				"buf base io $%p "
188444961713Sgirish 				"orig vatopa base io $%p "
188544961713Sgirish 				"orig_len 0x%llx (%d)",
188644961713Sgirish 				tx_desc_rings[i]->hv_tx_buf_base_ioaddr_pp,
188744961713Sgirish 				tx_desc_rings[i]->hv_tx_buf_ioaddr_size,
188844961713Sgirish 				tx_desc_rings[i]->hv_tx_buf_ioaddr_size,
188944961713Sgirish 				t_dma_buf_p->ioaddr_pp,
189044961713Sgirish 				t_dma_buf_p->orig_vatopa,
189144961713Sgirish 				t_dma_buf_p->orig_alength,
189244961713Sgirish 				t_dma_buf_p->orig_alength));
189344961713Sgirish 
189444961713Sgirish 			tx_desc_rings[i]->hv_tx_cntl_base_ioaddr_pp =
189544961713Sgirish 				(uint64_t)t_dma_cntl_p->orig_ioaddr_pp;
189644961713Sgirish 			tx_desc_rings[i]->hv_tx_cntl_ioaddr_size =
189744961713Sgirish 				(uint64_t)t_dma_cntl_p->orig_alength;
189844961713Sgirish 
189944961713Sgirish 			NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
190044961713Sgirish 				"==> nxge_map_txdma_channel: "
190144961713Sgirish 				"hv cntl base io $%p "
190244961713Sgirish 				"orig ioaddr_pp ($%p) "
190344961713Sgirish 				"orig vatopa ($%p) "
190444961713Sgirish 				"size 0x%llx (%d 0x%x)",
190544961713Sgirish 				tx_desc_rings[i]->hv_tx_cntl_base_ioaddr_pp,
190644961713Sgirish 				t_dma_cntl_p->orig_ioaddr_pp,
190744961713Sgirish 				t_dma_cntl_p->orig_vatopa,
190844961713Sgirish 				tx_desc_rings[i]->hv_tx_cntl_ioaddr_size,
190944961713Sgirish 				t_dma_cntl_p->orig_alength,
191044961713Sgirish 				t_dma_cntl_p->orig_alength));
191144961713Sgirish 		}
191244961713Sgirish #endif
191344961713Sgirish 	}
191444961713Sgirish 
191544961713Sgirish 	tx_rings->ndmas = ndmas;
191644961713Sgirish 	tx_rings->rings = tx_desc_rings;
191744961713Sgirish 	nxgep->tx_rings = tx_rings;
191844961713Sgirish 	tx_mbox_areas_p->txmbox_areas_p = tx_mbox_p;
191944961713Sgirish 	nxgep->tx_mbox_areas_p = tx_mbox_areas_p;
192044961713Sgirish 
192144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: "
192244961713Sgirish 		"tx_rings $%p rings $%p",
192344961713Sgirish 		nxgep->tx_rings, nxgep->tx_rings->rings));
192444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma: "
192544961713Sgirish 		"tx_rings $%p tx_desc_rings $%p",
192644961713Sgirish 		nxgep->tx_rings, tx_desc_rings));
192744961713Sgirish 
192844961713Sgirish 	goto nxge_map_txdma_exit;
192944961713Sgirish 
193044961713Sgirish nxge_map_txdma_fail1:
193144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
193244961713Sgirish 		"==> nxge_map_txdma: uninit tx desc "
193344961713Sgirish 		"(status 0x%x channel %d i %d)",
193444961713Sgirish 		nxgep, status, channel, i));
193544961713Sgirish 	i--;
193644961713Sgirish 	for (; i >= 0; i--) {
193744961713Sgirish 		channel = ((p_nxge_dma_common_t)dma_buf_p[i])->dma_channel;
193844961713Sgirish 		nxge_unmap_txdma_channel(nxgep, channel,
193944961713Sgirish 			tx_desc_rings[i],
194044961713Sgirish 			tx_mbox_p[i]);
194144961713Sgirish 	}
194244961713Sgirish 
194344961713Sgirish 	KMEM_FREE(tx_desc_rings, sizeof (p_tx_ring_t) * ndmas);
194444961713Sgirish 	KMEM_FREE(tx_rings, sizeof (tx_rings_t));
194544961713Sgirish 	KMEM_FREE(tx_mbox_p, sizeof (p_tx_mbox_t) * ndmas);
194644961713Sgirish 	KMEM_FREE(tx_mbox_areas_p, sizeof (tx_mbox_areas_t));
194744961713Sgirish 
194844961713Sgirish nxge_map_txdma_exit:
194944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
195044961713Sgirish 		"==> nxge_map_txdma: "
195144961713Sgirish 		"(status 0x%x channel %d)",
195244961713Sgirish 		status, channel));
195344961713Sgirish 
195444961713Sgirish 	return (status);
195544961713Sgirish }
195644961713Sgirish 
195744961713Sgirish static void
195844961713Sgirish nxge_unmap_txdma(p_nxge_t nxgep)
195944961713Sgirish {
196044961713Sgirish 	int			i, ndmas;
196144961713Sgirish 	uint8_t			channel;
196244961713Sgirish 	p_tx_rings_t 		tx_rings;
196344961713Sgirish 	p_tx_ring_t 		*tx_desc_rings;
196444961713Sgirish 	p_tx_mbox_areas_t 	tx_mbox_areas_p;
196544961713Sgirish 	p_tx_mbox_t		*tx_mbox_p;
196644961713Sgirish 	p_nxge_dma_pool_t	dma_buf_poolp;
196744961713Sgirish 
196844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_unmap_txdma"));
196944961713Sgirish 
197044961713Sgirish 	dma_buf_poolp = nxgep->tx_buf_pool_p;
197144961713Sgirish 	if (!dma_buf_poolp->buf_allocated) {
197244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
197344961713Sgirish 			"==> nxge_unmap_txdma: buf not allocated"));
197444961713Sgirish 		return;
197544961713Sgirish 	}
197644961713Sgirish 
197744961713Sgirish 	ndmas = dma_buf_poolp->ndmas;
197844961713Sgirish 	if (!ndmas) {
197944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
198044961713Sgirish 			"<== nxge_unmap_txdma: no dma allocated"));
198144961713Sgirish 		return;
198244961713Sgirish 	}
198344961713Sgirish 
198444961713Sgirish 	tx_rings = nxgep->tx_rings;
198544961713Sgirish 	tx_desc_rings = tx_rings->rings;
198644961713Sgirish 	if (tx_rings == NULL) {
198744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
198844961713Sgirish 			"<== nxge_unmap_txdma: NULL ring pointer"));
198944961713Sgirish 		return;
199044961713Sgirish 	}
199144961713Sgirish 
199244961713Sgirish 	tx_desc_rings = tx_rings->rings;
199344961713Sgirish 	if (tx_desc_rings == NULL) {
199444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
199544961713Sgirish 			"<== nxge_unmap_txdma: NULL ring pointers"));
199644961713Sgirish 		return;
199744961713Sgirish 	}
199844961713Sgirish 
199944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_unmap_txdma: "
200044961713Sgirish 		"tx_rings $%p tx_desc_rings $%p ndmas %d",
200144961713Sgirish 		tx_rings, tx_desc_rings, ndmas));
200244961713Sgirish 
200344961713Sgirish 	tx_mbox_areas_p = nxgep->tx_mbox_areas_p;
200444961713Sgirish 	tx_mbox_p = tx_mbox_areas_p->txmbox_areas_p;
200544961713Sgirish 
200644961713Sgirish 	for (i = 0; i < ndmas; i++) {
200744961713Sgirish 		channel = tx_desc_rings[i]->tdc;
200844961713Sgirish 		(void) nxge_unmap_txdma_channel(nxgep, channel,
200944961713Sgirish 				(p_tx_ring_t)tx_desc_rings[i],
201044961713Sgirish 				(p_tx_mbox_t)tx_mbox_p[i]);
201144961713Sgirish 	}
201244961713Sgirish 
201344961713Sgirish 	KMEM_FREE(tx_desc_rings, sizeof (p_tx_ring_t) * ndmas);
201444961713Sgirish 	KMEM_FREE(tx_rings, sizeof (tx_rings_t));
201544961713Sgirish 	KMEM_FREE(tx_mbox_p, sizeof (p_tx_mbox_t) * ndmas);
201644961713Sgirish 	KMEM_FREE(tx_mbox_areas_p, sizeof (tx_mbox_areas_t));
201744961713Sgirish 
201844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
201944961713Sgirish 		"<== nxge_unmap_txdma"));
202044961713Sgirish }
202144961713Sgirish 
202244961713Sgirish static nxge_status_t
202344961713Sgirish nxge_map_txdma_channel(p_nxge_t nxgep, uint16_t channel,
202444961713Sgirish 	p_nxge_dma_common_t *dma_buf_p,
202544961713Sgirish 	p_tx_ring_t *tx_desc_p,
202644961713Sgirish 	uint32_t num_chunks,
202744961713Sgirish 	p_nxge_dma_common_t *dma_cntl_p,
202844961713Sgirish 	p_tx_mbox_t *tx_mbox_p)
202944961713Sgirish {
203044961713Sgirish 	int	status = NXGE_OK;
203144961713Sgirish 
203244961713Sgirish 	/*
203344961713Sgirish 	 * Set up and prepare buffer blocks, descriptors
203444961713Sgirish 	 * and mailbox.
203544961713Sgirish 	 */
203644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
203744961713Sgirish 		"==> nxge_map_txdma_channel (channel %d)", channel));
203844961713Sgirish 	/*
203944961713Sgirish 	 * Transmit buffer blocks
204044961713Sgirish 	 */
204144961713Sgirish 	status = nxge_map_txdma_channel_buf_ring(nxgep, channel,
204244961713Sgirish 			dma_buf_p, tx_desc_p, num_chunks);
204344961713Sgirish 	if (status != NXGE_OK) {
204444961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
204544961713Sgirish 			"==> nxge_map_txdma_channel (channel %d): "
204644961713Sgirish 			"map buffer failed 0x%x", channel, status));
204744961713Sgirish 		goto nxge_map_txdma_channel_exit;
204844961713Sgirish 	}
204944961713Sgirish 
205044961713Sgirish 	/*
205144961713Sgirish 	 * Transmit block ring, and mailbox.
205244961713Sgirish 	 */
205344961713Sgirish 	nxge_map_txdma_channel_cfg_ring(nxgep, channel, dma_cntl_p, *tx_desc_p,
205444961713Sgirish 					tx_mbox_p);
205544961713Sgirish 
205644961713Sgirish 	goto nxge_map_txdma_channel_exit;
205744961713Sgirish 
205844961713Sgirish nxge_map_txdma_channel_fail1:
205944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
206044961713Sgirish 		"==> nxge_map_txdma_channel: unmap buf"
206144961713Sgirish 		"(status 0x%x channel %d)",
206244961713Sgirish 		status, channel));
206344961713Sgirish 	nxge_unmap_txdma_channel_buf_ring(nxgep, *tx_desc_p);
206444961713Sgirish 
206544961713Sgirish nxge_map_txdma_channel_exit:
206644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
206744961713Sgirish 		"<== nxge_map_txdma_channel: "
206844961713Sgirish 		"(status 0x%x channel %d)",
206944961713Sgirish 		status, channel));
207044961713Sgirish 
207144961713Sgirish 	return (status);
207244961713Sgirish }
207344961713Sgirish 
207444961713Sgirish /*ARGSUSED*/
207544961713Sgirish static void
207644961713Sgirish nxge_unmap_txdma_channel(p_nxge_t nxgep, uint16_t channel,
207744961713Sgirish 	p_tx_ring_t tx_ring_p,
207844961713Sgirish 	p_tx_mbox_t tx_mbox_p)
207944961713Sgirish {
208044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
208144961713Sgirish 		"==> nxge_unmap_txdma_channel (channel %d)", channel));
208244961713Sgirish 	/*
208344961713Sgirish 	 * unmap tx block ring, and mailbox.
208444961713Sgirish 	 */
208544961713Sgirish 	(void) nxge_unmap_txdma_channel_cfg_ring(nxgep,
208644961713Sgirish 			tx_ring_p, tx_mbox_p);
208744961713Sgirish 
208844961713Sgirish 	/* unmap buffer blocks */
208944961713Sgirish 	(void) nxge_unmap_txdma_channel_buf_ring(nxgep, tx_ring_p);
209044961713Sgirish 
209144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_unmap_txdma_channel"));
209244961713Sgirish }
209344961713Sgirish 
209444961713Sgirish /*ARGSUSED*/
209544961713Sgirish static void
209644961713Sgirish nxge_map_txdma_channel_cfg_ring(p_nxge_t nxgep, uint16_t dma_channel,
209744961713Sgirish 	p_nxge_dma_common_t *dma_cntl_p,
209844961713Sgirish 	p_tx_ring_t tx_ring_p,
209944961713Sgirish 	p_tx_mbox_t *tx_mbox_p)
210044961713Sgirish {
210144961713Sgirish 	p_tx_mbox_t 		mboxp;
210244961713Sgirish 	p_nxge_dma_common_t 	cntl_dmap;
210344961713Sgirish 	p_nxge_dma_common_t 	dmap;
210444961713Sgirish 	p_tx_rng_cfig_t		tx_ring_cfig_p;
210544961713Sgirish 	p_tx_ring_kick_t	tx_ring_kick_p;
210644961713Sgirish 	p_tx_cs_t		tx_cs_p;
210744961713Sgirish 	p_tx_dma_ent_msk_t	tx_evmask_p;
210844961713Sgirish 	p_txdma_mbh_t		mboxh_p;
210944961713Sgirish 	p_txdma_mbl_t		mboxl_p;
211044961713Sgirish 	uint64_t		tx_desc_len;
211144961713Sgirish 
211244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
211344961713Sgirish 		"==> nxge_map_txdma_channel_cfg_ring"));
211444961713Sgirish 
211544961713Sgirish 	cntl_dmap = *dma_cntl_p;
211644961713Sgirish 
211744961713Sgirish 	dmap = (p_nxge_dma_common_t)&tx_ring_p->tdc_desc;
211844961713Sgirish 	nxge_setup_dma_common(dmap, cntl_dmap, tx_ring_p->tx_ring_size,
211944961713Sgirish 			sizeof (tx_desc_t));
212044961713Sgirish 	/*
212144961713Sgirish 	 * Zero out transmit ring descriptors.
212244961713Sgirish 	 */
212344961713Sgirish 	bzero((caddr_t)dmap->kaddrp, dmap->alength);
212444961713Sgirish 	tx_ring_cfig_p = &(tx_ring_p->tx_ring_cfig);
212544961713Sgirish 	tx_ring_kick_p = &(tx_ring_p->tx_ring_kick);
212644961713Sgirish 	tx_cs_p = &(tx_ring_p->tx_cs);
212744961713Sgirish 	tx_evmask_p = &(tx_ring_p->tx_evmask);
212844961713Sgirish 	tx_ring_cfig_p->value = 0;
212944961713Sgirish 	tx_ring_kick_p->value = 0;
213044961713Sgirish 	tx_cs_p->value = 0;
213144961713Sgirish 	tx_evmask_p->value = 0;
213244961713Sgirish 
213344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
213444961713Sgirish 		"==> nxge_map_txdma_channel_cfg_ring: channel %d des $%p",
213544961713Sgirish 		dma_channel,
213644961713Sgirish 		dmap->dma_cookie.dmac_laddress));
213744961713Sgirish 
213844961713Sgirish 	tx_ring_cfig_p->value = 0;
213944961713Sgirish 	tx_desc_len = (uint64_t)(tx_ring_p->tx_ring_size >> 3);
214044961713Sgirish 	tx_ring_cfig_p->value =
214144961713Sgirish 		(dmap->dma_cookie.dmac_laddress & TX_RNG_CFIG_ADDR_MASK) |
214244961713Sgirish 		(tx_desc_len << TX_RNG_CFIG_LEN_SHIFT);
214344961713Sgirish 
214444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
214544961713Sgirish 		"==> nxge_map_txdma_channel_cfg_ring: channel %d cfg 0x%llx",
214644961713Sgirish 		dma_channel,
214744961713Sgirish 		tx_ring_cfig_p->value));
214844961713Sgirish 
214944961713Sgirish 	tx_cs_p->bits.ldw.rst = 1;
215044961713Sgirish 
215144961713Sgirish 	/* Map in mailbox */
215244961713Sgirish 	mboxp = (p_tx_mbox_t)
215344961713Sgirish 		KMEM_ZALLOC(sizeof (tx_mbox_t), KM_SLEEP);
215444961713Sgirish 	dmap = (p_nxge_dma_common_t)&mboxp->tx_mbox;
215544961713Sgirish 	nxge_setup_dma_common(dmap, cntl_dmap, 1, sizeof (txdma_mailbox_t));
215644961713Sgirish 	mboxh_p = (p_txdma_mbh_t)&tx_ring_p->tx_mbox_mbh;
215744961713Sgirish 	mboxl_p = (p_txdma_mbl_t)&tx_ring_p->tx_mbox_mbl;
215844961713Sgirish 	mboxh_p->value = mboxl_p->value = 0;
215944961713Sgirish 
216044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
216144961713Sgirish 		"==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
216244961713Sgirish 		dmap->dma_cookie.dmac_laddress));
216344961713Sgirish 
216444961713Sgirish 	mboxh_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress >>
216544961713Sgirish 				TXDMA_MBH_ADDR_SHIFT) & TXDMA_MBH_MASK);
216644961713Sgirish 
216744961713Sgirish 	mboxl_p->bits.ldw.mbaddr = ((dmap->dma_cookie.dmac_laddress &
216844961713Sgirish 				TXDMA_MBL_MASK) >> TXDMA_MBL_SHIFT);
216944961713Sgirish 
217044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
217144961713Sgirish 		"==> nxge_map_txdma_channel_cfg_ring: mbox 0x%lx",
217244961713Sgirish 		dmap->dma_cookie.dmac_laddress));
217344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
217444961713Sgirish 		"==> nxge_map_txdma_channel_cfg_ring: hmbox $%p "
217544961713Sgirish 		"mbox $%p",
217644961713Sgirish 		mboxh_p->bits.ldw.mbaddr, mboxl_p->bits.ldw.mbaddr));
217744961713Sgirish 	tx_ring_p->page_valid.value = 0;
217844961713Sgirish 	tx_ring_p->page_mask_1.value = tx_ring_p->page_mask_2.value = 0;
217944961713Sgirish 	tx_ring_p->page_value_1.value = tx_ring_p->page_value_2.value = 0;
218044961713Sgirish 	tx_ring_p->page_reloc_1.value = tx_ring_p->page_reloc_2.value = 0;
218144961713Sgirish 	tx_ring_p->page_hdl.value = 0;
218244961713Sgirish 
218344961713Sgirish 	tx_ring_p->page_valid.bits.ldw.page0 = 1;
218444961713Sgirish 	tx_ring_p->page_valid.bits.ldw.page1 = 1;
218544961713Sgirish 
218644961713Sgirish 	tx_ring_p->max_burst.value = 0;
218744961713Sgirish 	tx_ring_p->max_burst.bits.ldw.dma_max_burst = TXC_DMA_MAX_BURST_DEFAULT;
218844961713Sgirish 
218944961713Sgirish 	*tx_mbox_p = mboxp;
219044961713Sgirish 
219144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
219244961713Sgirish 				"<== nxge_map_txdma_channel_cfg_ring"));
219344961713Sgirish }
219444961713Sgirish 
219544961713Sgirish /*ARGSUSED*/
219644961713Sgirish static void
219744961713Sgirish nxge_unmap_txdma_channel_cfg_ring(p_nxge_t nxgep,
219844961713Sgirish 	p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p)
219944961713Sgirish {
220044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
220144961713Sgirish 		"==> nxge_unmap_txdma_channel_cfg_ring: channel %d",
220244961713Sgirish 		tx_ring_p->tdc));
220344961713Sgirish 
220444961713Sgirish 	KMEM_FREE(tx_mbox_p, sizeof (tx_mbox_t));
220544961713Sgirish 
220644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
220744961713Sgirish 		"<== nxge_unmap_txdma_channel_cfg_ring"));
220844961713Sgirish }
220944961713Sgirish 
221044961713Sgirish static nxge_status_t
221144961713Sgirish nxge_map_txdma_channel_buf_ring(p_nxge_t nxgep, uint16_t channel,
221244961713Sgirish 	p_nxge_dma_common_t *dma_buf_p,
221344961713Sgirish 	p_tx_ring_t *tx_desc_p, uint32_t num_chunks)
221444961713Sgirish {
221544961713Sgirish 	p_nxge_dma_common_t 	dma_bufp, tmp_bufp;
221644961713Sgirish 	p_nxge_dma_common_t 	dmap;
221744961713Sgirish 	nxge_os_dma_handle_t	tx_buf_dma_handle;
221844961713Sgirish 	p_tx_ring_t 		tx_ring_p;
221944961713Sgirish 	p_tx_msg_t 		tx_msg_ring;
222044961713Sgirish 	nxge_status_t		status = NXGE_OK;
222144961713Sgirish 	int			ddi_status = DDI_SUCCESS;
222244961713Sgirish 	int			i, j, index;
222344961713Sgirish 	uint32_t		size, bsize;
222444961713Sgirish 	uint32_t 		nblocks, nmsgs;
222544961713Sgirish 
222644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
222744961713Sgirish 		"==> nxge_map_txdma_channel_buf_ring"));
222844961713Sgirish 
222944961713Sgirish 	dma_bufp = tmp_bufp = *dma_buf_p;
223044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
223144961713Sgirish 		" nxge_map_txdma_channel_buf_ring: channel %d to map %d "
223244961713Sgirish 		"chunks bufp $%p",
223344961713Sgirish 		channel, num_chunks, dma_bufp));
223444961713Sgirish 
223544961713Sgirish 	nmsgs = 0;
223644961713Sgirish 	for (i = 0; i < num_chunks; i++, tmp_bufp++) {
223744961713Sgirish 		nmsgs += tmp_bufp->nblocks;
223844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
223944961713Sgirish 			"==> nxge_map_txdma_channel_buf_ring: channel %d "
224044961713Sgirish 			"bufp $%p nblocks %d nmsgs %d",
224144961713Sgirish 			channel, tmp_bufp, tmp_bufp->nblocks, nmsgs));
224244961713Sgirish 	}
224344961713Sgirish 	if (!nmsgs) {
224444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
224544961713Sgirish 			"<== nxge_map_txdma_channel_buf_ring: channel %d "
224644961713Sgirish 			"no msg blocks",
224744961713Sgirish 			channel));
224844961713Sgirish 		status = NXGE_ERROR;
224944961713Sgirish 		goto nxge_map_txdma_channel_buf_ring_exit;
225044961713Sgirish 	}
225144961713Sgirish 
225244961713Sgirish 	tx_ring_p = (p_tx_ring_t)
225344961713Sgirish 		KMEM_ZALLOC(sizeof (tx_ring_t), KM_SLEEP);
225444961713Sgirish 	MUTEX_INIT(&tx_ring_p->lock, NULL, MUTEX_DRIVER,
225544961713Sgirish 		(void *)nxgep->interrupt_cookie);
22561f8914d5Sml 
22571f8914d5Sml 	tx_ring_p->nxgep = nxgep;
22581f8914d5Sml 	tx_ring_p->serial = nxge_serialize_create(nmsgs,
22591f8914d5Sml 				nxge_serial_tx, tx_ring_p);
226044961713Sgirish 	/*
226144961713Sgirish 	 * Allocate transmit message rings and handles for packets
226244961713Sgirish 	 * not to be copied to premapped buffers.
226344961713Sgirish 	 */
226444961713Sgirish 	size = nmsgs * sizeof (tx_msg_t);
226544961713Sgirish 	tx_msg_ring = KMEM_ZALLOC(size, KM_SLEEP);
226644961713Sgirish 	for (i = 0; i < nmsgs; i++) {
226744961713Sgirish 		ddi_status = ddi_dma_alloc_handle(nxgep->dip, &nxge_tx_dma_attr,
226844961713Sgirish 				DDI_DMA_DONTWAIT, 0,
226944961713Sgirish 				&tx_msg_ring[i].dma_handle);
227044961713Sgirish 		if (ddi_status != DDI_SUCCESS) {
227144961713Sgirish 			status |= NXGE_DDI_FAILED;
227244961713Sgirish 			break;
227344961713Sgirish 		}
227444961713Sgirish 	}
227544961713Sgirish 	if (i < nmsgs) {
2276*56d930aeSspeer 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2277*56d930aeSspeer 		    "Allocate handles failed."));
227844961713Sgirish 		goto nxge_map_txdma_channel_buf_ring_fail1;
227944961713Sgirish 	}
228044961713Sgirish 
228144961713Sgirish 	tx_ring_p->tdc = channel;
228244961713Sgirish 	tx_ring_p->tx_msg_ring = tx_msg_ring;
228344961713Sgirish 	tx_ring_p->tx_ring_size = nmsgs;
228444961713Sgirish 	tx_ring_p->num_chunks = num_chunks;
228544961713Sgirish 	if (!nxge_tx_intr_thres) {
228644961713Sgirish 		nxge_tx_intr_thres = tx_ring_p->tx_ring_size/4;
228744961713Sgirish 	}
228844961713Sgirish 	tx_ring_p->tx_wrap_mask = tx_ring_p->tx_ring_size - 1;
228944961713Sgirish 	tx_ring_p->rd_index = 0;
229044961713Sgirish 	tx_ring_p->wr_index = 0;
229144961713Sgirish 	tx_ring_p->ring_head.value = 0;
229244961713Sgirish 	tx_ring_p->ring_kick_tail.value = 0;
229344961713Sgirish 	tx_ring_p->descs_pending = 0;
229444961713Sgirish 
229544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
229644961713Sgirish 		"==> nxge_map_txdma_channel_buf_ring: channel %d "
229744961713Sgirish 		"actual tx desc max %d nmsgs %d "
229844961713Sgirish 		"(config nxge_tx_ring_size %d)",
229944961713Sgirish 		channel, tx_ring_p->tx_ring_size, nmsgs,
230044961713Sgirish 		nxge_tx_ring_size));
230144961713Sgirish 
230244961713Sgirish 	/*
230344961713Sgirish 	 * Map in buffers from the buffer pool.
230444961713Sgirish 	 */
230544961713Sgirish 	index = 0;
230644961713Sgirish 	bsize = dma_bufp->block_size;
230744961713Sgirish 
230844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_map_txdma_channel_buf_ring: "
230944961713Sgirish 		"dma_bufp $%p tx_rng_p $%p "
231044961713Sgirish 		"tx_msg_rng_p $%p bsize %d",
231144961713Sgirish 		dma_bufp, tx_ring_p, tx_msg_ring, bsize));
231244961713Sgirish 
231344961713Sgirish 	tx_buf_dma_handle = dma_bufp->dma_handle;
231444961713Sgirish 	for (i = 0; i < num_chunks; i++, dma_bufp++) {
231544961713Sgirish 		bsize = dma_bufp->block_size;
231644961713Sgirish 		nblocks = dma_bufp->nblocks;
231744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
231844961713Sgirish 			"==> nxge_map_txdma_channel_buf_ring: dma chunk %d "
231944961713Sgirish 			"size %d dma_bufp $%p",
232044961713Sgirish 			i, sizeof (nxge_dma_common_t), dma_bufp));
232144961713Sgirish 
232244961713Sgirish 		for (j = 0; j < nblocks; j++) {
232344961713Sgirish 			tx_msg_ring[index].buf_dma_handle = tx_buf_dma_handle;
232444961713Sgirish 			dmap = &tx_msg_ring[index++].buf_dma;
232544961713Sgirish #ifdef TX_MEM_DEBUG
232644961713Sgirish 			NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
232744961713Sgirish 				"==> nxge_map_txdma_channel_buf_ring: j %d"
232844961713Sgirish 				"dmap $%p", i, dmap));
232944961713Sgirish #endif
233044961713Sgirish 			nxge_setup_dma_common(dmap, dma_bufp, 1,
233144961713Sgirish 				bsize);
233244961713Sgirish 		}
233344961713Sgirish 	}
233444961713Sgirish 
233544961713Sgirish 	if (i < num_chunks) {
2336*56d930aeSspeer 		status = NXGE_ERROR;
233744961713Sgirish 		goto nxge_map_txdma_channel_buf_ring_fail1;
233844961713Sgirish 	}
233944961713Sgirish 
234044961713Sgirish 	*tx_desc_p = tx_ring_p;
234144961713Sgirish 
234244961713Sgirish 	goto nxge_map_txdma_channel_buf_ring_exit;
234344961713Sgirish 
234444961713Sgirish nxge_map_txdma_channel_buf_ring_fail1:
23451f8914d5Sml 	if (tx_ring_p->serial) {
23461f8914d5Sml 		nxge_serialize_destroy(tx_ring_p->serial);
23471f8914d5Sml 		tx_ring_p->serial = NULL;
23481f8914d5Sml 	}
23491f8914d5Sml 
235044961713Sgirish 	index--;
235144961713Sgirish 	for (; index >= 0; index--) {
2352*56d930aeSspeer 		if (tx_msg_ring[index].dma_handle != NULL) {
2353*56d930aeSspeer 			ddi_dma_free_handle(&tx_msg_ring[index].dma_handle);
235444961713Sgirish 		}
235544961713Sgirish 	}
235644961713Sgirish 	MUTEX_DESTROY(&tx_ring_p->lock);
2357*56d930aeSspeer 	KMEM_FREE(tx_msg_ring, size);
235844961713Sgirish 	KMEM_FREE(tx_ring_p, sizeof (tx_ring_t));
235944961713Sgirish 
2360*56d930aeSspeer 	status = NXGE_ERROR;
2361*56d930aeSspeer 
236244961713Sgirish nxge_map_txdma_channel_buf_ring_exit:
236344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
236444961713Sgirish 		"<== nxge_map_txdma_channel_buf_ring status 0x%x", status));
236544961713Sgirish 
236644961713Sgirish 	return (status);
236744961713Sgirish }
236844961713Sgirish 
236944961713Sgirish /*ARGSUSED*/
237044961713Sgirish static void
237144961713Sgirish nxge_unmap_txdma_channel_buf_ring(p_nxge_t nxgep, p_tx_ring_t tx_ring_p)
237244961713Sgirish {
237344961713Sgirish 	p_tx_msg_t 		tx_msg_ring;
237444961713Sgirish 	p_tx_msg_t 		tx_msg_p;
237544961713Sgirish 	int			i;
237644961713Sgirish 
237744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
237844961713Sgirish 		"==> nxge_unmap_txdma_channel_buf_ring"));
237944961713Sgirish 	if (tx_ring_p == NULL) {
238044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
238144961713Sgirish 			"<== nxge_unmap_txdma_channel_buf_ring: NULL ringp"));
238244961713Sgirish 		return;
238344961713Sgirish 	}
238444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
238544961713Sgirish 		"==> nxge_unmap_txdma_channel_buf_ring: channel %d",
238644961713Sgirish 		tx_ring_p->tdc));
238744961713Sgirish 
238844961713Sgirish 	tx_msg_ring = tx_ring_p->tx_msg_ring;
238944961713Sgirish 	for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
239044961713Sgirish 		tx_msg_p = &tx_msg_ring[i];
239144961713Sgirish 		if (tx_msg_p->flags.dma_type == USE_DVMA) {
239244961713Sgirish 			NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
239344961713Sgirish 				"entry = %d",
239444961713Sgirish 				i));
239544961713Sgirish 			(void) dvma_unload(tx_msg_p->dvma_handle,
239644961713Sgirish 				0, -1);
239744961713Sgirish 			tx_msg_p->dvma_handle = NULL;
239844961713Sgirish 			if (tx_ring_p->dvma_wr_index ==
239944961713Sgirish 				tx_ring_p->dvma_wrap_mask) {
240044961713Sgirish 				tx_ring_p->dvma_wr_index = 0;
240144961713Sgirish 			} else {
240244961713Sgirish 				tx_ring_p->dvma_wr_index++;
240344961713Sgirish 			}
240444961713Sgirish 			tx_ring_p->dvma_pending--;
240544961713Sgirish 		} else if (tx_msg_p->flags.dma_type ==
240644961713Sgirish 				USE_DMA) {
240744961713Sgirish 			if (ddi_dma_unbind_handle
240844961713Sgirish 				(tx_msg_p->dma_handle)) {
240944961713Sgirish 				cmn_err(CE_WARN, "!nxge_unmap_tx_bug_ring: "
241044961713Sgirish 					"ddi_dma_unbind_handle "
241144961713Sgirish 					"failed.");
241244961713Sgirish 			}
241344961713Sgirish 		}
241444961713Sgirish 
241544961713Sgirish 		if (tx_msg_p->tx_message != NULL) {
241644961713Sgirish 			freemsg(tx_msg_p->tx_message);
241744961713Sgirish 			tx_msg_p->tx_message = NULL;
241844961713Sgirish 		}
241944961713Sgirish 	}
242044961713Sgirish 
242144961713Sgirish 	for (i = 0; i < tx_ring_p->tx_ring_size; i++) {
242244961713Sgirish 		if (tx_msg_ring[i].dma_handle != NULL) {
242344961713Sgirish 			ddi_dma_free_handle(&tx_msg_ring[i].dma_handle);
242444961713Sgirish 		}
242544961713Sgirish 	}
242644961713Sgirish 
24271f8914d5Sml 	if (tx_ring_p->serial) {
24281f8914d5Sml 		nxge_serialize_destroy(tx_ring_p->serial);
24291f8914d5Sml 		tx_ring_p->serial = NULL;
24301f8914d5Sml 	}
24311f8914d5Sml 
243244961713Sgirish 	MUTEX_DESTROY(&tx_ring_p->lock);
243344961713Sgirish 	KMEM_FREE(tx_msg_ring, sizeof (tx_msg_t) * tx_ring_p->tx_ring_size);
243444961713Sgirish 	KMEM_FREE(tx_ring_p, sizeof (tx_ring_t));
243544961713Sgirish 
243644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
243744961713Sgirish 		"<== nxge_unmap_txdma_channel_buf_ring"));
243844961713Sgirish }
243944961713Sgirish 
244044961713Sgirish static nxge_status_t
244144961713Sgirish nxge_txdma_hw_start(p_nxge_t nxgep)
244244961713Sgirish {
244344961713Sgirish 	int			i, ndmas;
244444961713Sgirish 	uint16_t		channel;
244544961713Sgirish 	p_tx_rings_t 		tx_rings;
244644961713Sgirish 	p_tx_ring_t 		*tx_desc_rings;
244744961713Sgirish 	p_tx_mbox_areas_t 	tx_mbox_areas_p;
244844961713Sgirish 	p_tx_mbox_t		*tx_mbox_p;
244944961713Sgirish 	nxge_status_t		status = NXGE_OK;
245044961713Sgirish 
245144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start"));
245244961713Sgirish 
245344961713Sgirish 	tx_rings = nxgep->tx_rings;
245444961713Sgirish 	if (tx_rings == NULL) {
245544961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
245644961713Sgirish 			"<== nxge_txdma_hw_start: NULL ring pointer"));
245744961713Sgirish 		return (NXGE_ERROR);
245844961713Sgirish 	}
245944961713Sgirish 	tx_desc_rings = tx_rings->rings;
246044961713Sgirish 	if (tx_desc_rings == NULL) {
246144961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
246244961713Sgirish 			"<== nxge_txdma_hw_start: NULL ring pointers"));
246344961713Sgirish 		return (NXGE_ERROR);
246444961713Sgirish 	}
246544961713Sgirish 
246644961713Sgirish 	ndmas = tx_rings->ndmas;
246744961713Sgirish 	if (!ndmas) {
246844961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
246944961713Sgirish 			"<== nxge_txdma_hw_start: no dma channel allocated"));
247044961713Sgirish 		return (NXGE_ERROR);
247144961713Sgirish 	}
247244961713Sgirish 
247344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
247444961713Sgirish 		"tx_rings $%p tx_desc_rings $%p ndmas %d",
247544961713Sgirish 		tx_rings, tx_desc_rings, ndmas));
247644961713Sgirish 
247744961713Sgirish 	tx_mbox_areas_p = nxgep->tx_mbox_areas_p;
247844961713Sgirish 	tx_mbox_p = tx_mbox_areas_p->txmbox_areas_p;
247944961713Sgirish 
248044961713Sgirish 	for (i = 0; i < ndmas; i++) {
248144961713Sgirish 		channel = tx_desc_rings[i]->tdc,
248244961713Sgirish 		status = nxge_txdma_start_channel(nxgep, channel,
248344961713Sgirish 				(p_tx_ring_t)tx_desc_rings[i],
248444961713Sgirish 				(p_tx_mbox_t)tx_mbox_p[i]);
248544961713Sgirish 		if (status != NXGE_OK) {
248644961713Sgirish 			goto nxge_txdma_hw_start_fail1;
248744961713Sgirish 		}
248844961713Sgirish 	}
248944961713Sgirish 
249044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
249144961713Sgirish 		"tx_rings $%p rings $%p",
249244961713Sgirish 		nxgep->tx_rings, nxgep->tx_rings->rings));
249344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_start: "
249444961713Sgirish 		"tx_rings $%p tx_desc_rings $%p",
249544961713Sgirish 		nxgep->tx_rings, tx_desc_rings));
249644961713Sgirish 
249744961713Sgirish 	goto nxge_txdma_hw_start_exit;
249844961713Sgirish 
249944961713Sgirish nxge_txdma_hw_start_fail1:
250044961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
250144961713Sgirish 		"==> nxge_txdma_hw_start: disable "
250244961713Sgirish 		"(status 0x%x channel %d i %d)", status, channel, i));
250344961713Sgirish 	for (; i >= 0; i--) {
250444961713Sgirish 		channel = tx_desc_rings[i]->tdc,
250544961713Sgirish 		(void) nxge_txdma_stop_channel(nxgep, channel,
250644961713Sgirish 			(p_tx_ring_t)tx_desc_rings[i],
250744961713Sgirish 			(p_tx_mbox_t)tx_mbox_p[i]);
250844961713Sgirish 	}
250944961713Sgirish 
251044961713Sgirish nxge_txdma_hw_start_exit:
251144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
251244961713Sgirish 		"==> nxge_txdma_hw_start: (status 0x%x)", status));
251344961713Sgirish 
251444961713Sgirish 	return (status);
251544961713Sgirish }
251644961713Sgirish 
251744961713Sgirish static void
251844961713Sgirish nxge_txdma_hw_stop(p_nxge_t nxgep)
251944961713Sgirish {
252044961713Sgirish 	int			i, ndmas;
252144961713Sgirish 	uint16_t		channel;
252244961713Sgirish 	p_tx_rings_t 		tx_rings;
252344961713Sgirish 	p_tx_ring_t 		*tx_desc_rings;
252444961713Sgirish 	p_tx_mbox_areas_t 	tx_mbox_areas_p;
252544961713Sgirish 	p_tx_mbox_t		*tx_mbox_p;
252644961713Sgirish 
252744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_stop"));
252844961713Sgirish 
252944961713Sgirish 	tx_rings = nxgep->tx_rings;
253044961713Sgirish 	if (tx_rings == NULL) {
253144961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
253244961713Sgirish 			"<== nxge_txdma_hw_stop: NULL ring pointer"));
253344961713Sgirish 		return;
253444961713Sgirish 	}
253544961713Sgirish 	tx_desc_rings = tx_rings->rings;
253644961713Sgirish 	if (tx_desc_rings == NULL) {
253744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
253844961713Sgirish 			"<== nxge_txdma_hw_stop: NULL ring pointers"));
253944961713Sgirish 		return;
254044961713Sgirish 	}
254144961713Sgirish 
254244961713Sgirish 	ndmas = tx_rings->ndmas;
254344961713Sgirish 	if (!ndmas) {
254444961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
254544961713Sgirish 			"<== nxge_txdma_hw_stop: no dma channel allocated"));
254644961713Sgirish 		return;
254744961713Sgirish 	}
254844961713Sgirish 
254944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_stop: "
255044961713Sgirish 		"tx_rings $%p tx_desc_rings $%p",
255144961713Sgirish 		tx_rings, tx_desc_rings));
255244961713Sgirish 
255344961713Sgirish 	tx_mbox_areas_p = nxgep->tx_mbox_areas_p;
255444961713Sgirish 	tx_mbox_p = tx_mbox_areas_p->txmbox_areas_p;
255544961713Sgirish 
255644961713Sgirish 	for (i = 0; i < ndmas; i++) {
255744961713Sgirish 		channel = tx_desc_rings[i]->tdc;
255844961713Sgirish 		(void) nxge_txdma_stop_channel(nxgep, channel,
255944961713Sgirish 				(p_tx_ring_t)tx_desc_rings[i],
256044961713Sgirish 				(p_tx_mbox_t)tx_mbox_p[i]);
256144961713Sgirish 	}
256244961713Sgirish 
256344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_hw_stop: "
256444961713Sgirish 		"tx_rings $%p tx_desc_rings $%p",
256544961713Sgirish 		tx_rings, tx_desc_rings));
256644961713Sgirish 
256744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_hw_stop"));
256844961713Sgirish }
256944961713Sgirish 
257044961713Sgirish static nxge_status_t
257144961713Sgirish nxge_txdma_start_channel(p_nxge_t nxgep, uint16_t channel,
257244961713Sgirish     p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p)
257344961713Sgirish 
257444961713Sgirish {
257544961713Sgirish 	nxge_status_t		status = NXGE_OK;
257644961713Sgirish 
257744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
257844961713Sgirish 		"==> nxge_txdma_start_channel (channel %d)", channel));
257944961713Sgirish 	/*
258044961713Sgirish 	 * TXDMA/TXC must be in stopped state.
258144961713Sgirish 	 */
258244961713Sgirish 	(void) nxge_txdma_stop_inj_err(nxgep, channel);
258344961713Sgirish 
258444961713Sgirish 	/*
258544961713Sgirish 	 * Reset TXDMA channel
258644961713Sgirish 	 */
258744961713Sgirish 	tx_ring_p->tx_cs.value = 0;
258844961713Sgirish 	tx_ring_p->tx_cs.bits.ldw.rst = 1;
258944961713Sgirish 	status = nxge_reset_txdma_channel(nxgep, channel,
259044961713Sgirish 			tx_ring_p->tx_cs.value);
259144961713Sgirish 	if (status != NXGE_OK) {
259244961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
259344961713Sgirish 			"==> nxge_txdma_start_channel (channel %d)"
259444961713Sgirish 			" reset channel failed 0x%x", channel, status));
259544961713Sgirish 		goto nxge_txdma_start_channel_exit;
259644961713Sgirish 	}
259744961713Sgirish 
259844961713Sgirish 	/*
259944961713Sgirish 	 * Initialize the TXDMA channel specific FZC control
260044961713Sgirish 	 * configurations. These FZC registers are pertaining
260144961713Sgirish 	 * to each TX channel (i.e. logical pages).
260244961713Sgirish 	 */
260344961713Sgirish 	status = nxge_init_fzc_txdma_channel(nxgep, channel,
260444961713Sgirish 			tx_ring_p, tx_mbox_p);
260544961713Sgirish 	if (status != NXGE_OK) {
260644961713Sgirish 		goto nxge_txdma_start_channel_exit;
260744961713Sgirish 	}
260844961713Sgirish 
260944961713Sgirish 	/*
261044961713Sgirish 	 * Initialize the event masks.
261144961713Sgirish 	 */
261244961713Sgirish 	tx_ring_p->tx_evmask.value = 0;
261344961713Sgirish 	status = nxge_init_txdma_channel_event_mask(nxgep,
261444961713Sgirish 			channel, &tx_ring_p->tx_evmask);
261544961713Sgirish 	if (status != NXGE_OK) {
261644961713Sgirish 		goto nxge_txdma_start_channel_exit;
261744961713Sgirish 	}
261844961713Sgirish 
261944961713Sgirish 	/*
262044961713Sgirish 	 * Load TXDMA descriptors, buffers, mailbox,
262144961713Sgirish 	 * initialise the DMA channels and
262244961713Sgirish 	 * enable each DMA channel.
262344961713Sgirish 	 */
262444961713Sgirish 	status = nxge_enable_txdma_channel(nxgep, channel,
262544961713Sgirish 			tx_ring_p, tx_mbox_p);
262644961713Sgirish 	if (status != NXGE_OK) {
262744961713Sgirish 		goto nxge_txdma_start_channel_exit;
262844961713Sgirish 	}
262944961713Sgirish 
263044961713Sgirish nxge_txdma_start_channel_exit:
263144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_start_channel"));
263244961713Sgirish 
263344961713Sgirish 	return (status);
263444961713Sgirish }
263544961713Sgirish 
263644961713Sgirish /*ARGSUSED*/
263744961713Sgirish static nxge_status_t
263844961713Sgirish nxge_txdma_stop_channel(p_nxge_t nxgep, uint16_t channel,
263944961713Sgirish 	p_tx_ring_t tx_ring_p, p_tx_mbox_t tx_mbox_p)
264044961713Sgirish {
264144961713Sgirish 	int		status = NXGE_OK;
264244961713Sgirish 
264344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
264444961713Sgirish 		"==> nxge_txdma_stop_channel: channel %d", channel));
264544961713Sgirish 
264644961713Sgirish 	/*
264744961713Sgirish 	 * Stop (disable) TXDMA and TXC (if stop bit is set
264844961713Sgirish 	 * and STOP_N_GO bit not set, the TXDMA reset state will
264944961713Sgirish 	 * not be set if reset TXDMA.
265044961713Sgirish 	 */
265144961713Sgirish 	(void) nxge_txdma_stop_inj_err(nxgep, channel);
265244961713Sgirish 
265344961713Sgirish 	/*
265444961713Sgirish 	 * Reset TXDMA channel
265544961713Sgirish 	 */
265644961713Sgirish 	tx_ring_p->tx_cs.value = 0;
265744961713Sgirish 	tx_ring_p->tx_cs.bits.ldw.rst = 1;
265844961713Sgirish 	status = nxge_reset_txdma_channel(nxgep, channel,
265944961713Sgirish 			tx_ring_p->tx_cs.value);
266044961713Sgirish 	if (status != NXGE_OK) {
266144961713Sgirish 		goto nxge_txdma_stop_channel_exit;
266244961713Sgirish 	}
266344961713Sgirish 
266444961713Sgirish #ifdef HARDWARE_REQUIRED
266544961713Sgirish 	/* Set up the interrupt event masks. */
266644961713Sgirish 	tx_ring_p->tx_evmask.value = 0;
266744961713Sgirish 	status = nxge_init_txdma_channel_event_mask(nxgep,
266844961713Sgirish 			channel, &tx_ring_p->tx_evmask);
266944961713Sgirish 	if (status != NXGE_OK) {
267044961713Sgirish 		goto nxge_txdma_stop_channel_exit;
267144961713Sgirish 	}
267244961713Sgirish 
267344961713Sgirish 	/* Initialize the DMA control and status register */
267444961713Sgirish 	tx_ring_p->tx_cs.value = TX_ENT_MSK_MK_ALL;
267544961713Sgirish 	status = nxge_init_txdma_channel_cntl_stat(nxgep, channel,
267644961713Sgirish 			tx_ring_p->tx_cs.value);
267744961713Sgirish 	if (status != NXGE_OK) {
267844961713Sgirish 		goto nxge_txdma_stop_channel_exit;
267944961713Sgirish 	}
268044961713Sgirish 
268144961713Sgirish 	/* Disable channel */
268244961713Sgirish 	status = nxge_disable_txdma_channel(nxgep, channel,
268344961713Sgirish 			tx_ring_p, tx_mbox_p);
268444961713Sgirish 	if (status != NXGE_OK) {
268544961713Sgirish 		goto nxge_txdma_start_channel_exit;
268644961713Sgirish 	}
268744961713Sgirish 
268844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
268944961713Sgirish 		"==> nxge_txdma_stop_channel: event done"));
269044961713Sgirish 
269144961713Sgirish #endif
269244961713Sgirish 
269344961713Sgirish nxge_txdma_stop_channel_exit:
269444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "<== nxge_txdma_stop_channel"));
269544961713Sgirish 	return (status);
269644961713Sgirish }
269744961713Sgirish 
269844961713Sgirish static p_tx_ring_t
269944961713Sgirish nxge_txdma_get_ring(p_nxge_t nxgep, uint16_t channel)
270044961713Sgirish {
270144961713Sgirish 	int			index, ndmas;
270244961713Sgirish 	uint16_t		tdc;
270344961713Sgirish 	p_tx_rings_t 		tx_rings;
270444961713Sgirish 
270544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_ring"));
270644961713Sgirish 
270744961713Sgirish 	tx_rings = nxgep->tx_rings;
270844961713Sgirish 	if (tx_rings == NULL) {
270944961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
271044961713Sgirish 			"<== nxge_txdma_get_ring: NULL ring pointer"));
271144961713Sgirish 		return (NULL);
271244961713Sgirish 	}
271344961713Sgirish 
271444961713Sgirish 	ndmas = tx_rings->ndmas;
271544961713Sgirish 	if (!ndmas) {
271644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
271744961713Sgirish 			"<== nxge_txdma_get_ring: no channel allocated"));
271844961713Sgirish 		return (NULL);
271944961713Sgirish 	}
272044961713Sgirish 
272144961713Sgirish 	if (tx_rings->rings == NULL) {
272244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, TX_CTL,
272344961713Sgirish 			"<== nxge_txdma_get_ring: NULL rings pointer"));
272444961713Sgirish 		return (NULL);
272544961713Sgirish 	}
272644961713Sgirish 
272744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_get_ring: "
272844961713Sgirish 		"tx_rings $%p tx_desc_rings $%p ndmas %d",
272944961713Sgirish 		tx_rings, tx_rings, ndmas));
273044961713Sgirish 
273144961713Sgirish 	for (index = 0; index < ndmas; index++) {
273244961713Sgirish 		tdc = tx_rings->rings[index]->tdc;
273344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
273444961713Sgirish 			"==> nxge_fixup_txdma_rings: channel %d", tdc));
273544961713Sgirish 		if (channel == tdc) {
273644961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
273744961713Sgirish 				"<== nxge_txdma_get_ring: tdc %d "
273844961713Sgirish 				"ring $%p",
273944961713Sgirish 				tdc, tx_rings->rings[index]));
274044961713Sgirish 			return (p_tx_ring_t)(tx_rings->rings[index]);
274144961713Sgirish 		}
274244961713Sgirish 	}
274344961713Sgirish 
274444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_ring"));
274544961713Sgirish 	return (NULL);
274644961713Sgirish }
274744961713Sgirish 
274844961713Sgirish static p_tx_mbox_t
274944961713Sgirish nxge_txdma_get_mbox(p_nxge_t nxgep, uint16_t channel)
275044961713Sgirish {
275144961713Sgirish 	int			index, tdc, ndmas;
275244961713Sgirish 	p_tx_rings_t 		tx_rings;
275344961713Sgirish 	p_tx_mbox_areas_t 	tx_mbox_areas_p;
275444961713Sgirish 	p_tx_mbox_t		*tx_mbox_p;
275544961713Sgirish 
275644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_get_mbox"));
275744961713Sgirish 
275844961713Sgirish 	tx_rings = nxgep->tx_rings;
275944961713Sgirish 	if (tx_rings == NULL) {
276044961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
276144961713Sgirish 			"<== nxge_txdma_get_mbox: NULL ring pointer"));
276244961713Sgirish 		return (NULL);
276344961713Sgirish 	}
276444961713Sgirish 
276544961713Sgirish 	tx_mbox_areas_p = nxgep->tx_mbox_areas_p;
276644961713Sgirish 	if (tx_mbox_areas_p == NULL) {
276744961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
276844961713Sgirish 			"<== nxge_txdma_get_mbox: NULL mbox pointer"));
276944961713Sgirish 		return (NULL);
277044961713Sgirish 	}
277144961713Sgirish 
277244961713Sgirish 	tx_mbox_p = tx_mbox_areas_p->txmbox_areas_p;
277344961713Sgirish 
277444961713Sgirish 	ndmas = tx_rings->ndmas;
277544961713Sgirish 	if (!ndmas) {
277644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
277744961713Sgirish 			"<== nxge_txdma_get_mbox: no channel allocated"));
277844961713Sgirish 		return (NULL);
277944961713Sgirish 	}
278044961713Sgirish 
278144961713Sgirish 	if (tx_rings->rings == NULL) {
278244961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
278344961713Sgirish 			"<== nxge_txdma_get_mbox: NULL rings pointer"));
278444961713Sgirish 		return (NULL);
278544961713Sgirish 	}
278644961713Sgirish 
278744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, MEM3_CTL, "==> nxge_txdma_get_mbox: "
278844961713Sgirish 		"tx_rings $%p tx_desc_rings $%p ndmas %d",
278944961713Sgirish 		tx_rings, tx_rings, ndmas));
279044961713Sgirish 
279144961713Sgirish 	for (index = 0; index < ndmas; index++) {
279244961713Sgirish 		tdc = tx_rings->rings[index]->tdc;
279344961713Sgirish 		NXGE_DEBUG_MSG((nxgep, MEM3_CTL,
279444961713Sgirish 			"==> nxge_txdma_get_mbox: channel %d", tdc));
279544961713Sgirish 		if (channel == tdc) {
279644961713Sgirish 			NXGE_DEBUG_MSG((nxgep, TX_CTL,
279744961713Sgirish 				"<== nxge_txdma_get_mbox: tdc %d "
279844961713Sgirish 				"ring $%p",
279944961713Sgirish 				tdc, tx_rings->rings[index]));
280044961713Sgirish 			return (p_tx_mbox_t)(tx_mbox_p[index]);
280144961713Sgirish 		}
280244961713Sgirish 	}
280344961713Sgirish 
280444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_get_mbox"));
280544961713Sgirish 	return (NULL);
280644961713Sgirish }
280744961713Sgirish 
280844961713Sgirish /*ARGSUSED*/
280944961713Sgirish static nxge_status_t
281044961713Sgirish nxge_tx_err_evnts(p_nxge_t nxgep, uint_t index, p_nxge_ldv_t ldvp, tx_cs_t cs)
281144961713Sgirish {
281244961713Sgirish 	npi_handle_t		handle;
281344961713Sgirish 	npi_status_t		rs;
281444961713Sgirish 	uint8_t			channel;
281544961713Sgirish 	p_tx_ring_t 		*tx_rings;
281644961713Sgirish 	p_tx_ring_t 		tx_ring_p;
281744961713Sgirish 	p_nxge_tx_ring_stats_t	tdc_stats;
281844961713Sgirish 	boolean_t		txchan_fatal = B_FALSE;
281944961713Sgirish 	nxge_status_t		status = NXGE_OK;
282044961713Sgirish 	tdmc_inj_par_err_t	par_err;
282144961713Sgirish 	uint32_t		value;
282244961713Sgirish 
282344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, RX2_CTL, "==> nxge_tx_err_evnts"));
282444961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
282544961713Sgirish 	channel = ldvp->channel;
282644961713Sgirish 
282744961713Sgirish 	tx_rings = nxgep->tx_rings->rings;
282844961713Sgirish 	tx_ring_p = tx_rings[index];
282944961713Sgirish 	tdc_stats = tx_ring_p->tdc_stats;
283044961713Sgirish 	if ((cs.bits.ldw.pkt_size_err) || (cs.bits.ldw.pref_buf_par_err) ||
283144961713Sgirish 		(cs.bits.ldw.nack_pref) || (cs.bits.ldw.nack_pkt_rd) ||
283244961713Sgirish 		(cs.bits.ldw.conf_part_err) || (cs.bits.ldw.pkt_prt_err)) {
283344961713Sgirish 		if ((rs = npi_txdma_ring_error_get(handle, channel,
283444961713Sgirish 					&tdc_stats->errlog)) != NPI_SUCCESS)
283544961713Sgirish 			return (NXGE_ERROR | rs);
283644961713Sgirish 	}
283744961713Sgirish 
283844961713Sgirish 	if (cs.bits.ldw.mbox_err) {
283944961713Sgirish 		tdc_stats->mbox_err++;
284044961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
284144961713Sgirish 					NXGE_FM_EREPORT_TDMC_MBOX_ERR);
284244961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
284344961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
284444961713Sgirish 			"fatal error: mailbox", channel));
284544961713Sgirish 		txchan_fatal = B_TRUE;
284644961713Sgirish 	}
284744961713Sgirish 	if (cs.bits.ldw.pkt_size_err) {
284844961713Sgirish 		tdc_stats->pkt_size_err++;
284944961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
285044961713Sgirish 					NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR);
285144961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
285244961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
285344961713Sgirish 			"fatal error: pkt_size_err", channel));
285444961713Sgirish 		txchan_fatal = B_TRUE;
285544961713Sgirish 	}
285644961713Sgirish 	if (cs.bits.ldw.tx_ring_oflow) {
285744961713Sgirish 		tdc_stats->tx_ring_oflow++;
285844961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
285944961713Sgirish 					NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW);
286044961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
286144961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
286244961713Sgirish 			"fatal error: tx_ring_oflow", channel));
286344961713Sgirish 		txchan_fatal = B_TRUE;
286444961713Sgirish 	}
286544961713Sgirish 	if (cs.bits.ldw.pref_buf_par_err) {
286644961713Sgirish 		tdc_stats->pre_buf_par_err++;
286744961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
286844961713Sgirish 					NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR);
286944961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
287044961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
287144961713Sgirish 			"fatal error: pre_buf_par_err", channel));
287244961713Sgirish 		/* Clear error injection source for parity error */
287344961713Sgirish 		(void) npi_txdma_inj_par_error_get(handle, &value);
287444961713Sgirish 		par_err.value = value;
287544961713Sgirish 		par_err.bits.ldw.inject_parity_error &= ~(1 << channel);
287644961713Sgirish 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
287744961713Sgirish 		txchan_fatal = B_TRUE;
287844961713Sgirish 	}
287944961713Sgirish 	if (cs.bits.ldw.nack_pref) {
288044961713Sgirish 		tdc_stats->nack_pref++;
288144961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
288244961713Sgirish 					NXGE_FM_EREPORT_TDMC_NACK_PREF);
288344961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
288444961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
288544961713Sgirish 			"fatal error: nack_pref", channel));
288644961713Sgirish 		txchan_fatal = B_TRUE;
288744961713Sgirish 	}
288844961713Sgirish 	if (cs.bits.ldw.nack_pkt_rd) {
288944961713Sgirish 		tdc_stats->nack_pkt_rd++;
289044961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
289144961713Sgirish 					NXGE_FM_EREPORT_TDMC_NACK_PKT_RD);
289244961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
289344961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
289444961713Sgirish 			"fatal error: nack_pkt_rd", channel));
289544961713Sgirish 		txchan_fatal = B_TRUE;
289644961713Sgirish 	}
289744961713Sgirish 	if (cs.bits.ldw.conf_part_err) {
289844961713Sgirish 		tdc_stats->conf_part_err++;
289944961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
290044961713Sgirish 					NXGE_FM_EREPORT_TDMC_CONF_PART_ERR);
290144961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
290244961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
290344961713Sgirish 			"fatal error: config_partition_err", channel));
290444961713Sgirish 		txchan_fatal = B_TRUE;
290544961713Sgirish 	}
290644961713Sgirish 	if (cs.bits.ldw.pkt_prt_err) {
290744961713Sgirish 		tdc_stats->pkt_part_err++;
290844961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, nxgep->mac.portnum, channel,
290944961713Sgirish 					NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR);
291044961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
291144961713Sgirish 			"==> nxge_tx_err_evnts(channel %d): "
291244961713Sgirish 			"fatal error: pkt_prt_err", channel));
291344961713Sgirish 		txchan_fatal = B_TRUE;
291444961713Sgirish 	}
291544961713Sgirish 
291644961713Sgirish 	/* Clear error injection source in case this is an injected error */
291744961713Sgirish 	TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG, channel, 0);
291844961713Sgirish 
291944961713Sgirish 	if (txchan_fatal) {
292044961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
292144961713Sgirish 			" nxge_tx_err_evnts: "
292244961713Sgirish 			" fatal error on channel %d cs 0x%llx\n",
292344961713Sgirish 			channel, cs.value));
292444961713Sgirish 		status = nxge_txdma_fatal_err_recover(nxgep, channel,
292544961713Sgirish 								tx_ring_p);
292644961713Sgirish 		if (status == NXGE_OK) {
292744961713Sgirish 			FM_SERVICE_RESTORED(nxgep);
292844961713Sgirish 		}
292944961713Sgirish 	}
293044961713Sgirish 
293144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, RX2_CTL, "<== nxge_tx_err_evnts"));
293244961713Sgirish 
293344961713Sgirish 	return (status);
293444961713Sgirish }
293544961713Sgirish 
293644961713Sgirish static nxge_status_t
293744961713Sgirish nxge_txdma_fatal_err_recover(p_nxge_t nxgep, uint16_t channel,
293844961713Sgirish 						p_tx_ring_t tx_ring_p)
293944961713Sgirish {
294044961713Sgirish 	npi_handle_t	handle;
294144961713Sgirish 	npi_status_t	rs = NPI_SUCCESS;
294244961713Sgirish 	p_tx_mbox_t	tx_mbox_p;
294344961713Sgirish 	nxge_status_t	status = NXGE_OK;
294444961713Sgirish 
294544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_txdma_fatal_err_recover"));
294644961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
294744961713Sgirish 			"Recovering from TxDMAChannel#%d error...", channel));
294844961713Sgirish 
294944961713Sgirish 	/*
295044961713Sgirish 	 * Stop the dma channel waits for the stop done.
295144961713Sgirish 	 * If the stop done bit is not set, then create
295244961713Sgirish 	 * an error.
295344961713Sgirish 	 */
295444961713Sgirish 
295544961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
295644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel stop..."));
295744961713Sgirish 	MUTEX_ENTER(&tx_ring_p->lock);
295844961713Sgirish 	rs = npi_txdma_channel_control(handle, TXDMA_STOP, channel);
295944961713Sgirish 	if (rs != NPI_SUCCESS) {
296044961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
296144961713Sgirish 			"==> nxge_txdma_fatal_err_recover (channel %d): "
296244961713Sgirish 			"stop failed ", channel));
296344961713Sgirish 		goto fail;
296444961713Sgirish 	}
296544961713Sgirish 
296644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reclaim..."));
296744961713Sgirish 	(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
296844961713Sgirish 
296944961713Sgirish 	/*
297044961713Sgirish 	 * Reset TXDMA channel
297144961713Sgirish 	 */
297244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel reset..."));
297344961713Sgirish 	if ((rs = npi_txdma_channel_control(handle, TXDMA_RESET, channel)) !=
297444961713Sgirish 						NPI_SUCCESS) {
297544961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
297644961713Sgirish 			"==> nxge_txdma_fatal_err_recover (channel %d)"
297744961713Sgirish 			" reset channel failed 0x%x", channel, rs));
297844961713Sgirish 		goto fail;
297944961713Sgirish 	}
298044961713Sgirish 
298144961713Sgirish 	/*
298244961713Sgirish 	 * Reset the tail (kick) register to 0.
298344961713Sgirish 	 * (Hardware will not reset it. Tx overflow fatal
298444961713Sgirish 	 * error if tail is not set to 0 after reset!
298544961713Sgirish 	 */
298644961713Sgirish 	TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0);
298744961713Sgirish 
298844961713Sgirish 	/* Restart TXDMA channel */
298944961713Sgirish 
299044961713Sgirish 	/*
299144961713Sgirish 	 * Initialize the TXDMA channel specific FZC control
299244961713Sgirish 	 * configurations. These FZC registers are pertaining
299344961713Sgirish 	 * to each TX channel (i.e. logical pages).
299444961713Sgirish 	 */
299544961713Sgirish 	tx_mbox_p = nxge_txdma_get_mbox(nxgep, channel);
299644961713Sgirish 
299744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel restart..."));
299844961713Sgirish 	status = nxge_init_fzc_txdma_channel(nxgep, channel,
299944961713Sgirish 						tx_ring_p, tx_mbox_p);
300044961713Sgirish 	if (status != NXGE_OK)
300144961713Sgirish 		goto fail;
300244961713Sgirish 
300344961713Sgirish 	/*
300444961713Sgirish 	 * Initialize the event masks.
300544961713Sgirish 	 */
300644961713Sgirish 	tx_ring_p->tx_evmask.value = 0;
300744961713Sgirish 	status = nxge_init_txdma_channel_event_mask(nxgep, channel,
300844961713Sgirish 							&tx_ring_p->tx_evmask);
300944961713Sgirish 	if (status != NXGE_OK)
301044961713Sgirish 		goto fail;
301144961713Sgirish 
301244961713Sgirish 	tx_ring_p->wr_index_wrap = B_FALSE;
301344961713Sgirish 	tx_ring_p->wr_index = 0;
301444961713Sgirish 	tx_ring_p->rd_index = 0;
301544961713Sgirish 
301644961713Sgirish 	/*
301744961713Sgirish 	 * Load TXDMA descriptors, buffers, mailbox,
301844961713Sgirish 	 * initialise the DMA channels and
301944961713Sgirish 	 * enable each DMA channel.
302044961713Sgirish 	 */
302144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxDMA channel enable..."));
302244961713Sgirish 	status = nxge_enable_txdma_channel(nxgep, channel,
302344961713Sgirish 						tx_ring_p, tx_mbox_p);
302444961713Sgirish 	MUTEX_EXIT(&tx_ring_p->lock);
302544961713Sgirish 	if (status != NXGE_OK)
302644961713Sgirish 		goto fail;
302744961713Sgirish 
302844961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
302944961713Sgirish 			"Recovery Successful, TxDMAChannel#%d Restored",
303044961713Sgirish 			channel));
303144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_txdma_fatal_err_recover"));
303244961713Sgirish 
303344961713Sgirish 	return (NXGE_OK);
303444961713Sgirish 
303544961713Sgirish fail:
303644961713Sgirish 	MUTEX_EXIT(&tx_ring_p->lock);
303744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
303844961713Sgirish 		"nxge_txdma_fatal_err_recover (channel %d): "
303944961713Sgirish 		"failed to recover this txdma channel", channel));
304044961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed"));
304144961713Sgirish 
304244961713Sgirish 	return (status);
304344961713Sgirish }
304444961713Sgirish 
304544961713Sgirish nxge_status_t
304644961713Sgirish nxge_tx_port_fatal_err_recover(p_nxge_t nxgep)
304744961713Sgirish {
304844961713Sgirish 	npi_handle_t	handle;
304944961713Sgirish 	npi_status_t	rs = NPI_SUCCESS;
305044961713Sgirish 	nxge_status_t	status = NXGE_OK;
305144961713Sgirish 	p_tx_ring_t 	*tx_desc_rings;
305244961713Sgirish 	p_tx_rings_t	tx_rings;
305344961713Sgirish 	p_tx_ring_t	tx_ring_p;
305444961713Sgirish 	p_tx_mbox_t	tx_mbox_p;
305544961713Sgirish 	int		i, ndmas;
305644961713Sgirish 	uint16_t	channel;
305744961713Sgirish 
305844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "<== nxge_tx_port_fatal_err_recover"));
305944961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
306044961713Sgirish 			"Recovering from TxPort error..."));
306144961713Sgirish 
306244961713Sgirish 	/*
306344961713Sgirish 	 * Stop the dma channel waits for the stop done.
306444961713Sgirish 	 * If the stop done bit is not set, then create
306544961713Sgirish 	 * an error.
306644961713Sgirish 	 */
306744961713Sgirish 
306844961713Sgirish 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
306944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxPort stop all DMA channels..."));
307044961713Sgirish 
307144961713Sgirish 	tx_rings = nxgep->tx_rings;
307244961713Sgirish 	tx_desc_rings = tx_rings->rings;
307344961713Sgirish 	ndmas = tx_rings->ndmas;
307444961713Sgirish 
307544961713Sgirish 	for (i = 0; i < ndmas; i++) {
307644961713Sgirish 		if (tx_desc_rings[i] == NULL) {
307744961713Sgirish 			continue;
307844961713Sgirish 		}
307944961713Sgirish 		tx_ring_p = tx_rings->rings[i];
308044961713Sgirish 		MUTEX_ENTER(&tx_ring_p->lock);
308144961713Sgirish 	}
308244961713Sgirish 
308344961713Sgirish 	for (i = 0; i < ndmas; i++) {
308444961713Sgirish 		if (tx_desc_rings[i] == NULL) {
308544961713Sgirish 			continue;
308644961713Sgirish 		}
308744961713Sgirish 		channel = tx_desc_rings[i]->tdc;
308844961713Sgirish 		tx_ring_p = tx_rings->rings[i];
308944961713Sgirish 		rs = npi_txdma_channel_control(handle, TXDMA_STOP, channel);
309044961713Sgirish 		if (rs != NPI_SUCCESS) {
309144961713Sgirish 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
309244961713Sgirish 			"==> nxge_txdma_fatal_err_recover (channel %d): "
309344961713Sgirish 			"stop failed ", channel));
309444961713Sgirish 			goto fail;
309544961713Sgirish 		}
309644961713Sgirish 	}
309744961713Sgirish 
309844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxPort reclaim all DMA channels..."));
309944961713Sgirish 
310044961713Sgirish 	for (i = 0; i < ndmas; i++) {
310144961713Sgirish 		if (tx_desc_rings[i] == NULL) {
310244961713Sgirish 			continue;
310344961713Sgirish 		}
310444961713Sgirish 		tx_ring_p = tx_rings->rings[i];
310544961713Sgirish 		(void) nxge_txdma_reclaim(nxgep, tx_ring_p, 0);
310644961713Sgirish 	}
310744961713Sgirish 
310844961713Sgirish 	/*
310944961713Sgirish 	 * Reset TXDMA channel
311044961713Sgirish 	 */
311144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxPort reset all DMA channels..."));
311244961713Sgirish 
311344961713Sgirish 	for (i = 0; i < ndmas; i++) {
311444961713Sgirish 		if (tx_desc_rings[i] == NULL) {
311544961713Sgirish 			continue;
311644961713Sgirish 		}
311744961713Sgirish 		channel = tx_desc_rings[i]->tdc;
311844961713Sgirish 		tx_ring_p = tx_rings->rings[i];
311944961713Sgirish 		if ((rs = npi_txdma_channel_control(handle, TXDMA_RESET,
312044961713Sgirish 				channel)) != NPI_SUCCESS) {
312144961713Sgirish 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
312244961713Sgirish 				"==> nxge_txdma_fatal_err_recover (channel %d)"
312344961713Sgirish 				" reset channel failed 0x%x", channel, rs));
312444961713Sgirish 			goto fail;
312544961713Sgirish 		}
312644961713Sgirish 
312744961713Sgirish 		/*
312844961713Sgirish 		 * Reset the tail (kick) register to 0.
312944961713Sgirish 		 * (Hardware will not reset it. Tx overflow fatal
313044961713Sgirish 		 * error if tail is not set to 0 after reset!
313144961713Sgirish 		 */
313244961713Sgirish 
313344961713Sgirish 		TXDMA_REG_WRITE64(handle, TX_RING_KICK_REG, channel, 0);
313444961713Sgirish 
313544961713Sgirish 	}
313644961713Sgirish 
313744961713Sgirish 	/*
313844961713Sgirish 	 * Initialize the TXDMA channel specific FZC control
313944961713Sgirish 	 * configurations. These FZC registers are pertaining
314044961713Sgirish 	 * to each TX channel (i.e. logical pages).
314144961713Sgirish 	 */
314244961713Sgirish 
314344961713Sgirish 	/* Restart TXDMA channels */
314444961713Sgirish 
314544961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxPort re-start all DMA channels..."));
314644961713Sgirish 
314744961713Sgirish 	for (i = 0; i < ndmas; i++) {
314844961713Sgirish 		if (tx_desc_rings[i] == NULL) {
314944961713Sgirish 			continue;
315044961713Sgirish 		}
315144961713Sgirish 		channel = tx_desc_rings[i]->tdc;
315244961713Sgirish 		tx_ring_p = tx_rings->rings[i];
315344961713Sgirish 		tx_mbox_p = nxge_txdma_get_mbox(nxgep, channel);
315444961713Sgirish 		status = nxge_init_fzc_txdma_channel(nxgep, channel,
315544961713Sgirish 						tx_ring_p, tx_mbox_p);
315644961713Sgirish 		tx_ring_p->tx_evmask.value = 0;
315744961713Sgirish 		/*
315844961713Sgirish 		 * Initialize the event masks.
315944961713Sgirish 		 */
316044961713Sgirish 		status = nxge_init_txdma_channel_event_mask(nxgep, channel,
316144961713Sgirish 							&tx_ring_p->tx_evmask);
316244961713Sgirish 
316344961713Sgirish 		tx_ring_p->wr_index_wrap = B_FALSE;
316444961713Sgirish 		tx_ring_p->wr_index = 0;
316544961713Sgirish 		tx_ring_p->rd_index = 0;
316644961713Sgirish 
316744961713Sgirish 		if (status != NXGE_OK)
316844961713Sgirish 			goto fail;
316944961713Sgirish 		if (status != NXGE_OK)
317044961713Sgirish 			goto fail;
317144961713Sgirish 	}
317244961713Sgirish 
317344961713Sgirish 	/*
317444961713Sgirish 	 * Load TXDMA descriptors, buffers, mailbox,
317544961713Sgirish 	 * initialise the DMA channels and
317644961713Sgirish 	 * enable each DMA channel.
317744961713Sgirish 	 */
317844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "TxPort re-enable all DMA channels..."));
317944961713Sgirish 
318044961713Sgirish 	for (i = 0; i < ndmas; i++) {
318144961713Sgirish 		if (tx_desc_rings[i] == NULL) {
318244961713Sgirish 			continue;
318344961713Sgirish 		}
318444961713Sgirish 		channel = tx_desc_rings[i]->tdc;
318544961713Sgirish 		tx_ring_p = tx_rings->rings[i];
318644961713Sgirish 		tx_mbox_p = nxge_txdma_get_mbox(nxgep, channel);
318744961713Sgirish 		status = nxge_enable_txdma_channel(nxgep, channel,
318844961713Sgirish 						tx_ring_p, tx_mbox_p);
318944961713Sgirish 		if (status != NXGE_OK)
319044961713Sgirish 			goto fail;
319144961713Sgirish 	}
319244961713Sgirish 
319344961713Sgirish 	for (i = 0; i < ndmas; i++) {
319444961713Sgirish 		if (tx_desc_rings[i] == NULL) {
319544961713Sgirish 			continue;
319644961713Sgirish 		}
319744961713Sgirish 		tx_ring_p = tx_rings->rings[i];
319844961713Sgirish 		MUTEX_EXIT(&tx_ring_p->lock);
319944961713Sgirish 	}
320044961713Sgirish 
320144961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
320244961713Sgirish 			"Recovery Successful, TxPort Restored"));
320344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL, "==> nxge_tx_port_fatal_err_recover"));
320444961713Sgirish 
320544961713Sgirish 	return (NXGE_OK);
320644961713Sgirish 
320744961713Sgirish fail:
320844961713Sgirish 	for (i = 0; i < ndmas; i++) {
320944961713Sgirish 		if (tx_desc_rings[i] == NULL) {
321044961713Sgirish 			continue;
321144961713Sgirish 		}
321244961713Sgirish 		tx_ring_p = tx_rings->rings[i];
321344961713Sgirish 		MUTEX_EXIT(&tx_ring_p->lock);
321444961713Sgirish 	}
321544961713Sgirish 
321644961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed"));
321744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, TX_CTL,
321844961713Sgirish 		"nxge_txdma_fatal_err_recover (channel %d): "
321944961713Sgirish 		"failed to recover this txdma channel"));
322044961713Sgirish 
322144961713Sgirish 	return (status);
322244961713Sgirish }
322344961713Sgirish 
322444961713Sgirish void
322544961713Sgirish nxge_txdma_inject_err(p_nxge_t nxgep, uint32_t err_id, uint8_t chan)
322644961713Sgirish {
322744961713Sgirish 	tdmc_intr_dbg_t		tdi;
322844961713Sgirish 	tdmc_inj_par_err_t	par_err;
322944961713Sgirish 	uint32_t		value;
323044961713Sgirish 	npi_handle_t		handle;
323144961713Sgirish 
323244961713Sgirish 	switch (err_id) {
323344961713Sgirish 
323444961713Sgirish 	case NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR:
323544961713Sgirish 		handle = NXGE_DEV_NPI_HANDLE(nxgep);
323644961713Sgirish 		/* Clear error injection source for parity error */
323744961713Sgirish 		(void) npi_txdma_inj_par_error_get(handle, &value);
323844961713Sgirish 		par_err.value = value;
323944961713Sgirish 		par_err.bits.ldw.inject_parity_error &= ~(1 << chan);
324044961713Sgirish 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
324144961713Sgirish 
324244961713Sgirish 		par_err.bits.ldw.inject_parity_error = (1 << chan);
324344961713Sgirish 		(void) npi_txdma_inj_par_error_get(handle, &value);
324444961713Sgirish 		par_err.value = value;
324544961713Sgirish 		par_err.bits.ldw.inject_parity_error |= (1 << chan);
324644961713Sgirish 		cmn_err(CE_NOTE, "!Write 0x%llx to TDMC_INJ_PAR_ERR_REG\n",
324744961713Sgirish 				(unsigned long long)par_err.value);
324844961713Sgirish 		(void) npi_txdma_inj_par_error_set(handle, par_err.value);
324944961713Sgirish 		break;
325044961713Sgirish 
325144961713Sgirish 	case NXGE_FM_EREPORT_TDMC_MBOX_ERR:
325244961713Sgirish 	case NXGE_FM_EREPORT_TDMC_NACK_PREF:
325344961713Sgirish 	case NXGE_FM_EREPORT_TDMC_NACK_PKT_RD:
325444961713Sgirish 	case NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR:
325544961713Sgirish 	case NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW:
325644961713Sgirish 	case NXGE_FM_EREPORT_TDMC_CONF_PART_ERR:
325744961713Sgirish 	case NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR:
325844961713Sgirish 		TXDMA_REG_READ64(nxgep->npi_handle, TDMC_INTR_DBG_REG,
325944961713Sgirish 			chan, &tdi.value);
326044961713Sgirish 		if (err_id == NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR)
326144961713Sgirish 			tdi.bits.ldw.pref_buf_par_err = 1;
326244961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_MBOX_ERR)
326344961713Sgirish 			tdi.bits.ldw.mbox_err = 1;
326444961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PREF)
326544961713Sgirish 			tdi.bits.ldw.nack_pref = 1;
326644961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_NACK_PKT_RD)
326744961713Sgirish 			tdi.bits.ldw.nack_pkt_rd = 1;
326844961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR)
326944961713Sgirish 			tdi.bits.ldw.pkt_size_err = 1;
327044961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW)
327144961713Sgirish 			tdi.bits.ldw.tx_ring_oflow = 1;
327244961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_CONF_PART_ERR)
327344961713Sgirish 			tdi.bits.ldw.conf_part_err = 1;
327444961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR)
327544961713Sgirish 			tdi.bits.ldw.pkt_part_err = 1;
327644961713Sgirish 		cmn_err(CE_NOTE, "!Write 0x%lx to TDMC_INTR_DBG_REG\n",
327744961713Sgirish 				tdi.value);
327844961713Sgirish 		TXDMA_REG_WRITE64(nxgep->npi_handle, TDMC_INTR_DBG_REG,
327944961713Sgirish 			chan, tdi.value);
328044961713Sgirish 
328144961713Sgirish 		break;
328244961713Sgirish 	}
328344961713Sgirish }
3284