xref: /illumos-gate/usr/src/uts/common/io/nge/nge_rx.c (revision 0dc2366f)
16f3e57acSmx /*
247693af9Smx  * CDDL HEADER START
347693af9Smx  *
447693af9Smx  * The contents of this file are subject to the terms of the
547693af9Smx  * Common Development and Distribution License (the "License").
647693af9Smx  * You may not use this file except in compliance with the License.
747693af9Smx  *
847693af9Smx  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
947693af9Smx  * or http://www.opensolaris.org/os/licensing.
1047693af9Smx  * See the License for the specific language governing permissions
1147693af9Smx  * and limitations under the License.
1247693af9Smx  *
1347693af9Smx  * When distributing Covered Code, include this CDDL HEADER in each
1447693af9Smx  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1547693af9Smx  * If applicable, add the following below this CDDL HEADER, with the
1647693af9Smx  * fields enclosed by brackets "[]" replaced with your own identifying
1747693af9Smx  * information: Portions Copyright [yyyy] [name of copyright owner]
1847693af9Smx  *
1947693af9Smx  * CDDL HEADER END
206f3e57acSmx  */
216f3e57acSmx 
226f3e57acSmx /*
23*0dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2447693af9Smx  * Use is subject to license terms.
256f3e57acSmx  */
266f3e57acSmx 
276f3e57acSmx #include "nge.h"
286f3e57acSmx 
296f3e57acSmx #undef	NGE_DBG
306f3e57acSmx #define	NGE_DBG		NGE_DBG_RECV
316f3e57acSmx 
326f3e57acSmx #define	RXD_END		0x20000000
336f3e57acSmx #define	RXD_ERR		0x40000000
346f3e57acSmx #define	RXD_OWN		0x80000000
356f3e57acSmx #define	RXD_CSUM_MSK	0x1C000000
366f3e57acSmx #define	RXD_BCNT_MSK	0x00003FFF
376f3e57acSmx 
386f3e57acSmx #define	RXD_CK8G_NO_HSUM	0x0
396f3e57acSmx #define	RXD_CK8G_TCP_SUM_ERR	0x04000000
406f3e57acSmx #define	RXD_CK8G_UDP_SUM_ERR	0x08000000
416f3e57acSmx #define	RXD_CK8G_IP_HSUM_ERR	0x0C000000
426f3e57acSmx #define	RXD_CK8G_IP_HSUM	0x10000000
436f3e57acSmx #define	RXD_CK8G_TCP_SUM	0x14000000
446f3e57acSmx #define	RXD_CK8G_UDP_SUM	0x18000000
456f3e57acSmx #define	RXD_CK8G_RESV		0x1C000000
466f3e57acSmx 
476f3e57acSmx extern ddi_device_acc_attr_t nge_data_accattr;
486f3e57acSmx 
496f3e57acSmx /*
5075675fb7Svb  * Callback code invoked from STREAMs when the recv data buffer is free for
5175675fb7Svb  * recycling.
5275675fb7Svb  *
5375675fb7Svb  * The following table describes function behaviour:
5475675fb7Svb  *
5575675fb7Svb  *                      | mac stopped | mac running
5675675fb7Svb  * ---------------------------------------------------
5775675fb7Svb  * buffer delivered     | free buffer | recycle buffer
5875675fb7Svb  * buffer not delivered | do nothing  | recycle buffer (*)
5975675fb7Svb  *
6075675fb7Svb  * Note (*):
6175675fb7Svb  *   Recycle buffer only if mac state did not change during execution of
6275675fb7Svb  *   function. Otherwise if mac state changed, set buffer delivered & re-enter
6375675fb7Svb  *   function by calling freemsg().
646f3e57acSmx  */
656f3e57acSmx 
666f3e57acSmx void
nge_recv_recycle(caddr_t arg)676f3e57acSmx nge_recv_recycle(caddr_t arg)
686f3e57acSmx {
696f3e57acSmx 	boolean_t val;
706f3e57acSmx 	boolean_t valid;
716f3e57acSmx 	nge_t *ngep;
726f3e57acSmx 	dma_area_t *bufp;
736f3e57acSmx 	buff_ring_t *brp;
746f3e57acSmx 	nge_sw_statistics_t *sw_stp;
756f3e57acSmx 
766f3e57acSmx 	bufp = (dma_area_t *)arg;
776f3e57acSmx 	ngep = (nge_t *)bufp->private;
786f3e57acSmx 	brp = ngep->buff;
796f3e57acSmx 	sw_stp = &ngep->statistics.sw_statistics;
806f3e57acSmx 
816f3e57acSmx 	/*
826f3e57acSmx 	 * Free the buffer directly if the buffer was allocated
836f3e57acSmx 	 * previously or mac was stopped.
846f3e57acSmx 	 */
856f3e57acSmx 	if (bufp->signature != brp->buf_sign) {
866f3e57acSmx 		if (bufp->rx_delivered == B_TRUE) {
876f3e57acSmx 			nge_free_dma_mem(bufp);
886f3e57acSmx 			kmem_free(bufp, sizeof (dma_area_t));
896f3e57acSmx 			val = nge_atomic_decrease(&brp->rx_hold, 1);
906f3e57acSmx 			ASSERT(val == B_TRUE);
916f3e57acSmx 		}
926f3e57acSmx 		return;
936f3e57acSmx 	}
946f3e57acSmx 
956f3e57acSmx 	/*
966f3e57acSmx 	 * recycle the data buffer again and fill them in free ring
976f3e57acSmx 	 */
986f3e57acSmx 	bufp->rx_recycle.free_func = nge_recv_recycle;
996f3e57acSmx 	bufp->rx_recycle.free_arg = (caddr_t)bufp;
1006f3e57acSmx 
1016f3e57acSmx 	bufp->mp = desballoc(DMA_VPTR(*bufp),
1026f3e57acSmx 	    ngep->buf_size + NGE_HEADROOM, 0, &bufp->rx_recycle);
1036f3e57acSmx 
1046f3e57acSmx 	if (bufp->mp == NULL) {
1056f3e57acSmx 		sw_stp->mp_alloc_err++;
1066f3e57acSmx 		sw_stp->recy_free++;
1076f3e57acSmx 		nge_free_dma_mem(bufp);
1086f3e57acSmx 		kmem_free(bufp, sizeof (dma_area_t));
1096f3e57acSmx 		val = nge_atomic_decrease(&brp->rx_hold, 1);
1106f3e57acSmx 		ASSERT(val == B_TRUE);
1116f3e57acSmx 	} else {
1126f3e57acSmx 
1136f3e57acSmx 		mutex_enter(brp->recycle_lock);
1146f3e57acSmx 		if (bufp->signature != brp->buf_sign)
1156f3e57acSmx 			valid = B_TRUE;
1166f3e57acSmx 		else
1176f3e57acSmx 			valid = B_FALSE;
1186f3e57acSmx 		bufp->rx_delivered = valid;
1196f3e57acSmx 		if (bufp->rx_delivered == B_FALSE)  {
1206f3e57acSmx 			bufp->next = brp->recycle_list;
1216f3e57acSmx 			brp->recycle_list = bufp;
1226f3e57acSmx 		}
1236f3e57acSmx 		mutex_exit(brp->recycle_lock);
1246f3e57acSmx 		if (valid == B_TRUE)
1256f3e57acSmx 			/* call nge_rx_recycle again to free it */
1266f3e57acSmx 			freemsg(bufp->mp);
1276f3e57acSmx 		else {
1286f3e57acSmx 			val = nge_atomic_decrease(&brp->rx_hold, 1);
1296f3e57acSmx 			ASSERT(val == B_TRUE);
1306f3e57acSmx 		}
1316f3e57acSmx 	}
1326f3e57acSmx }
1336f3e57acSmx 
1346f3e57acSmx /*
1356f3e57acSmx  * Checking the rx's BDs (one or more) to receive
1366f3e57acSmx  * one complete packet.
1376f3e57acSmx  * start_index: the start indexer of BDs for one packet.
1386f3e57acSmx  * end_index: the end indexer of BDs for one packet.
1396f3e57acSmx  */
1406f3e57acSmx static mblk_t *nge_recv_packet(nge_t *ngep, uint32_t start_index, size_t len);
1416f3e57acSmx #pragma	inline(nge_recv_packet)
1426f3e57acSmx 
1436f3e57acSmx static mblk_t *
nge_recv_packet(nge_t * ngep,uint32_t start_index,size_t len)1446f3e57acSmx nge_recv_packet(nge_t *ngep, uint32_t start_index, size_t len)
1456f3e57acSmx {
1466f3e57acSmx 	uint8_t *rptr;
1476f3e57acSmx 	uint32_t minsize;
1486f3e57acSmx 	uint32_t maxsize;
1496f3e57acSmx 	mblk_t *mp;
1506f3e57acSmx 	buff_ring_t *brp;
1516f3e57acSmx 	sw_rx_sbd_t *srbdp;
1526f3e57acSmx 	dma_area_t *bufp;
1536f3e57acSmx 	nge_sw_statistics_t *sw_stp;
1546f3e57acSmx 	void *hw_bd_p;
1556f3e57acSmx 
1566f3e57acSmx 	brp = ngep->buff;
1576f3e57acSmx 	minsize = ETHERMIN;
1586f3e57acSmx 	maxsize = ngep->max_sdu;
1596f3e57acSmx 	sw_stp = &ngep->statistics.sw_statistics;
1606f3e57acSmx 	mp = NULL;
1616f3e57acSmx 
1626f3e57acSmx 	srbdp = &brp->sw_rbds[start_index];
1636f3e57acSmx 	DMA_SYNC(*srbdp->bufp, DDI_DMA_SYNC_FORKERNEL);
1646f3e57acSmx 	hw_bd_p = DMA_VPTR(srbdp->desc);
1656f3e57acSmx 
1666f3e57acSmx 	/*
1676f3e57acSmx 	 * First check the free_list, if it is NULL,
1686f3e57acSmx 	 * make the recycle_list be free_list.
1696f3e57acSmx 	 */
1706f3e57acSmx 	if (brp->free_list == NULL) {
1716f3e57acSmx 		mutex_enter(brp->recycle_lock);
1726f3e57acSmx 		brp->free_list = brp->recycle_list;
1736f3e57acSmx 		brp->recycle_list = NULL;
1746f3e57acSmx 		mutex_exit(brp->recycle_lock);
1756f3e57acSmx 	}
1766f3e57acSmx 	bufp = brp->free_list;
1776f3e57acSmx 	/* If it's not a qualified packet, delete it */
1786f3e57acSmx 	if (len > maxsize || len < minsize) {
1796f3e57acSmx 		ngep->desc_attr.rxd_fill(hw_bd_p, &srbdp->bufp->cookie,
1806f3e57acSmx 		    srbdp->bufp->alength);
1816f3e57acSmx 		srbdp->flags = CONTROLER_OWN;
1826f3e57acSmx 		return (NULL);
1836f3e57acSmx 	}
1846f3e57acSmx 
1856f3e57acSmx 	/*
1866f3e57acSmx 	 * If receive packet size is smaller than RX bcopy threshold,
1876f3e57acSmx 	 * or there is no available buffer in free_list or recycle list,
1886f3e57acSmx 	 * we use bcopy directly.
1896f3e57acSmx 	 */
1906f3e57acSmx 	if (len <= ngep->param_rxbcopy_threshold || bufp == NULL)
1916f3e57acSmx 		brp->rx_bcopy = B_TRUE;
1926f3e57acSmx 	else
1936f3e57acSmx 		brp->rx_bcopy = B_FALSE;
1946f3e57acSmx 
1956f3e57acSmx 	if (brp->rx_bcopy) {
1966f3e57acSmx 		mp = allocb(len + NGE_HEADROOM, 0);
1976f3e57acSmx 		if (mp == NULL) {
1986f3e57acSmx 			sw_stp->mp_alloc_err++;
1996f3e57acSmx 			ngep->desc_attr.rxd_fill(hw_bd_p, &srbdp->bufp->cookie,
2006f3e57acSmx 			    srbdp->bufp->alength);
2016f3e57acSmx 			srbdp->flags = CONTROLER_OWN;
2026f3e57acSmx 			return (NULL);
2036f3e57acSmx 		}
2046f3e57acSmx 		rptr = DMA_VPTR(*srbdp->bufp);
2056f3e57acSmx 		mp->b_rptr = mp->b_rptr + NGE_HEADROOM;
2066f3e57acSmx 		bcopy(rptr + NGE_HEADROOM, mp->b_rptr, len);
2076f3e57acSmx 		mp->b_wptr = mp->b_rptr + len;
2086f3e57acSmx 	} else {
2096f3e57acSmx 		mp = srbdp->bufp->mp;
2106f3e57acSmx 		/*
2116f3e57acSmx 		 * Make sure the packet *contents* 4-byte aligned
2126f3e57acSmx 		 */
2136f3e57acSmx 		mp->b_rptr += NGE_HEADROOM;
2146f3e57acSmx 		mp->b_wptr = mp->b_rptr + len;
2156f3e57acSmx 		mp->b_next = mp->b_cont = NULL;
2166f3e57acSmx 		srbdp->bufp->rx_delivered = B_TRUE;
2176f3e57acSmx 		srbdp->bufp = NULL;
2186f3e57acSmx 		nge_atomic_increase(&brp->rx_hold, 1);
2196f3e57acSmx 
2206f3e57acSmx 		/* Fill the buffer from free_list */
2216f3e57acSmx 		srbdp->bufp = bufp;
2226f3e57acSmx 		brp->free_list = bufp->next;
2236f3e57acSmx 		bufp->next = NULL;
2246f3e57acSmx 	}
2256f3e57acSmx 
2266f3e57acSmx 	/* replenish the buffer for hardware descriptor */
2276f3e57acSmx 	ngep->desc_attr.rxd_fill(hw_bd_p, &srbdp->bufp->cookie,
2286f3e57acSmx 	    srbdp->bufp->alength);
2296f3e57acSmx 	srbdp->flags = CONTROLER_OWN;
2306f3e57acSmx 	sw_stp->rbytes += len;
2316f3e57acSmx 	sw_stp->recv_count++;
2326f3e57acSmx 
2336f3e57acSmx 	return (mp);
2346f3e57acSmx }
2356f3e57acSmx 
2366f3e57acSmx 
2376f3e57acSmx #define	RX_HW_ERR	0x01
2386f3e57acSmx #define	RX_SUM_NO	0x02
2396f3e57acSmx #define	RX_SUM_ERR	0x04
2406f3e57acSmx 
2416f3e57acSmx /*
2426f3e57acSmx  * Statistic the rx's error
2436f3e57acSmx  * and generate a log msg for these.
2446f3e57acSmx  * Note:
2456f3e57acSmx  * RXE, Parity Error, Symbo error, CRC error
2466f3e57acSmx  * have been recored by nvidia's  hardware
2476f3e57acSmx  * statistics part (nge_statistics). So it is uncessary to record them by
2486f3e57acSmx  * driver in this place.
2496f3e57acSmx  */
2506f3e57acSmx static uint32_t
2516f3e57acSmx nge_rxsta_handle(nge_t *ngep, uint32_t stflag, uint32_t *pflags);
2526f3e57acSmx #pragma	inline(nge_rxsta_handle)
2536f3e57acSmx 
2546f3e57acSmx static uint32_t
nge_rxsta_handle(nge_t * ngep,uint32_t stflag,uint32_t * pflags)2556f3e57acSmx nge_rxsta_handle(nge_t *ngep,  uint32_t stflag, uint32_t *pflags)
2566f3e57acSmx {
2576f3e57acSmx 	uint32_t errors;
2586f3e57acSmx 	uint32_t err_flag;
2596f3e57acSmx 	nge_sw_statistics_t *sw_stp;
2606f3e57acSmx 
2616f3e57acSmx 	err_flag = 0;
2626f3e57acSmx 	sw_stp = &ngep->statistics.sw_statistics;
2636f3e57acSmx 
2646f3e57acSmx 	if ((RXD_END & stflag) == 0)
2656f3e57acSmx 		return (RX_HW_ERR);
2666f3e57acSmx 
2676f3e57acSmx 	errors = stflag & RXD_CSUM_MSK;
2686f3e57acSmx 	switch (errors) {
2696f3e57acSmx 	default:
2706f3e57acSmx 	break;
2716f3e57acSmx 
2726f3e57acSmx 	case RXD_CK8G_TCP_SUM:
2736f3e57acSmx 	case RXD_CK8G_UDP_SUM:
274*0dc2366fSVenugopal Iyer 		*pflags |= HCK_IPV4_HDRCKSUM_OK;
2756f3e57acSmx 		*pflags |= HCK_FULLCKSUM_OK;
2766f3e57acSmx 		break;
2776f3e57acSmx 
2786f3e57acSmx 	case RXD_CK8G_TCP_SUM_ERR:
2796f3e57acSmx 	case RXD_CK8G_UDP_SUM_ERR:
2806f3e57acSmx 		sw_stp->tcp_hwsum_err++;
281*0dc2366fSVenugopal Iyer 		*pflags |= HCK_IPV4_HDRCKSUM_OK;
2826f3e57acSmx 		break;
2836f3e57acSmx 
2846f3e57acSmx 	case RXD_CK8G_IP_HSUM:
285*0dc2366fSVenugopal Iyer 		*pflags |= HCK_IPV4_HDRCKSUM_OK;
2866f3e57acSmx 		break;
2876f3e57acSmx 
2886f3e57acSmx 	case RXD_CK8G_NO_HSUM:
2896f3e57acSmx 		err_flag |= RX_SUM_NO;
2906f3e57acSmx 		break;
2916f3e57acSmx 
2926f3e57acSmx 	case RXD_CK8G_IP_HSUM_ERR:
2936f3e57acSmx 		sw_stp->ip_hwsum_err++;
2946f3e57acSmx 		err_flag |=  RX_SUM_ERR;
2956f3e57acSmx 		break;
2966f3e57acSmx 	}
2976f3e57acSmx 
2986f3e57acSmx 	if ((stflag & RXD_ERR) != 0)	{
2996f3e57acSmx 
3006f3e57acSmx 		err_flag |= RX_HW_ERR;
3016f3e57acSmx 		NGE_DEBUG(("Receive desc error, status: 0x%x", stflag));
3026f3e57acSmx 	}
3036f3e57acSmx 
3046f3e57acSmx 	return (err_flag);
3056f3e57acSmx }
3066f3e57acSmx 
3076f3e57acSmx static mblk_t *
nge_recv_ring(nge_t * ngep)3086f3e57acSmx nge_recv_ring(nge_t *ngep)
3096f3e57acSmx {
3106f3e57acSmx 	uint32_t stflag;
3116f3e57acSmx 	uint32_t flag_err;
3126f3e57acSmx 	uint32_t sum_flags;
3136f3e57acSmx 	size_t len;
3146f3e57acSmx 	uint64_t end_index;
3156f3e57acSmx 	uint64_t sync_start;
3166f3e57acSmx 	mblk_t *mp;
3176f3e57acSmx 	mblk_t **tail;
3186f3e57acSmx 	mblk_t *head;
3196f3e57acSmx 	recv_ring_t *rrp;
3206f3e57acSmx 	buff_ring_t *brp;
3216f3e57acSmx 	sw_rx_sbd_t *srbdp;
3226f3e57acSmx 	void * hw_bd_p;
3236f3e57acSmx 	nge_mode_cntl mode_cntl;
3246f3e57acSmx 
3256f3e57acSmx 	mp = NULL;
3266f3e57acSmx 	head = NULL;
3276f3e57acSmx 	tail = &head;
3286f3e57acSmx 	rrp = ngep->recv;
3296f3e57acSmx 	brp = ngep->buff;
3306f3e57acSmx 
3316f3e57acSmx 	end_index = sync_start = rrp->prod_index;
3326f3e57acSmx 	/* Sync the descriptor for kernel */
3336f3e57acSmx 	if (sync_start + ngep->param_recv_max_packet <= ngep->rx_desc) {
3346f3e57acSmx 		(void) ddi_dma_sync(rrp->desc.dma_hdl,
3356f3e57acSmx 		    sync_start * ngep->desc_attr.rxd_size,
3366f3e57acSmx 		    ngep->param_recv_max_packet * ngep->desc_attr.rxd_size,
3376f3e57acSmx 		    DDI_DMA_SYNC_FORKERNEL);
3386f3e57acSmx 	} else {
3396f3e57acSmx 		(void) ddi_dma_sync(rrp->desc.dma_hdl,
3406f3e57acSmx 		    sync_start * ngep->desc_attr.rxd_size,
3416f3e57acSmx 		    0,
3426f3e57acSmx 		    DDI_DMA_SYNC_FORKERNEL);
3436f3e57acSmx 		(void) ddi_dma_sync(rrp->desc.dma_hdl,
3446f3e57acSmx 		    0,
3456f3e57acSmx 		    (ngep->param_recv_max_packet + sync_start - ngep->rx_desc) *
3466f3e57acSmx 		    ngep->desc_attr.rxd_size,
3476f3e57acSmx 		    DDI_DMA_SYNC_FORKERNEL);
3486f3e57acSmx 	}
3496f3e57acSmx 
3506f3e57acSmx 	/*
3516f3e57acSmx 	 * Looking through the rx's ring to find the good packets
3526f3e57acSmx 	 * and try to receive more and more packets in rx's ring
3536f3e57acSmx 	 */
3546f3e57acSmx 	for (;;) {
3556f3e57acSmx 		sum_flags = 0;
3566f3e57acSmx 		flag_err = 0;
3576f3e57acSmx 		end_index = rrp->prod_index;
3586f3e57acSmx 		srbdp = &brp->sw_rbds[end_index];
3596f3e57acSmx 		hw_bd_p = DMA_VPTR(srbdp->desc);
3606f3e57acSmx 		stflag = ngep->desc_attr.rxd_check(hw_bd_p, &len);
3616f3e57acSmx 		/*
3626f3e57acSmx 		 * If there is no packet in receving ring
3636f3e57acSmx 		 * break the loop
3646f3e57acSmx 		 */
3656f3e57acSmx 		if ((stflag & RXD_OWN) != 0 || HOST_OWN == srbdp->flags)
3666f3e57acSmx 			break;
3676f3e57acSmx 
3686f3e57acSmx 		ngep->recv_count++;
3696f3e57acSmx 		flag_err = nge_rxsta_handle(ngep, stflag, &sum_flags);
3706f3e57acSmx 		if ((flag_err & RX_HW_ERR) == 0) {
3716f3e57acSmx 			srbdp->flags = NGE_END_PACKET;
3726f3e57acSmx 			mp = nge_recv_packet(ngep, end_index, len);
3736f3e57acSmx 		} else {
3746f3e57acSmx 			/* Hardware error, re-use the buffer */
3756f3e57acSmx 			ngep->desc_attr.rxd_fill(hw_bd_p, &srbdp->bufp->cookie,
3766f3e57acSmx 			    srbdp->bufp->alength);
3776f3e57acSmx 			srbdp->flags = CONTROLER_OWN;
3786f3e57acSmx 		}
3796f3e57acSmx 		if (mp != NULL) {
3806f3e57acSmx 			if (!(flag_err & (RX_SUM_NO | RX_SUM_ERR))) {
381*0dc2366fSVenugopal Iyer 				mac_hcksum_set(mp, 0, 0, 0, 0, sum_flags);
3826f3e57acSmx 			}
3836f3e57acSmx 			*tail = mp;
3846f3e57acSmx 			tail = &mp->b_next;
3856f3e57acSmx 			mp = NULL;
3866f3e57acSmx 		}
3876f3e57acSmx 		rrp->prod_index = NEXT(end_index, rrp->desc.nslots);
3886ad24245SWinson Wang - Sun Microsystems - Beijing China 		if (ngep->recv_count >= ngep->param_recv_max_packet)
3896f3e57acSmx 			break;
3906f3e57acSmx 	}
3916f3e57acSmx 
3926f3e57acSmx 	/* Sync the descriptors for device */
39302d51d0dSjj 	if (sync_start + ngep->recv_count <= ngep->rx_desc) {
3946f3e57acSmx 		(void) ddi_dma_sync(rrp->desc.dma_hdl,
3956f3e57acSmx 		    sync_start * ngep->desc_attr.rxd_size,
39602d51d0dSjj 		    ngep->recv_count * ngep->desc_attr.rxd_size,
3976f3e57acSmx 		    DDI_DMA_SYNC_FORDEV);
3986f3e57acSmx 	} else {
3996f3e57acSmx 		(void) ddi_dma_sync(rrp->desc.dma_hdl,
4006f3e57acSmx 		    sync_start * ngep->desc_attr.rxd_size,
4016f3e57acSmx 		    0,
4026f3e57acSmx 		    DDI_DMA_SYNC_FORDEV);
4036f3e57acSmx 		(void) ddi_dma_sync(rrp->desc.dma_hdl,
4046f3e57acSmx 		    0,
40502d51d0dSjj 		    (ngep->recv_count + sync_start - ngep->rx_desc) *
4066f3e57acSmx 		    ngep->desc_attr.rxd_size,
4076f3e57acSmx 		    DDI_DMA_SYNC_FORDEV);
4086f3e57acSmx 	}
4096f3e57acSmx 	mode_cntl.mode_val = nge_reg_get32(ngep, NGE_MODE_CNTL);
4106f3e57acSmx 	mode_cntl.mode_bits.rxdm = NGE_SET;
4116f3e57acSmx 	mode_cntl.mode_bits.tx_rcom_en = NGE_SET;
4126f3e57acSmx 	nge_reg_put32(ngep, NGE_MODE_CNTL, mode_cntl.mode_val);
4136f3e57acSmx 
4146f3e57acSmx 	return (head);
4156f3e57acSmx }
4166f3e57acSmx 
4176f3e57acSmx void
nge_receive(nge_t * ngep)4186f3e57acSmx nge_receive(nge_t *ngep)
4196f3e57acSmx {
4206f3e57acSmx 	mblk_t *mp;
4216f3e57acSmx 	recv_ring_t *rrp;
4226f3e57acSmx 	rrp = ngep->recv;
4236f3e57acSmx 
4246f3e57acSmx 	mp = nge_recv_ring(ngep);
4256f3e57acSmx 	mutex_exit(ngep->genlock);
4266f3e57acSmx 	if (mp != NULL)
4276f3e57acSmx 		mac_rx(ngep->mh, rrp->handle, mp);
4286f3e57acSmx 	mutex_enter(ngep->genlock);
4296f3e57acSmx }
4306f3e57acSmx 
4316f3e57acSmx void
nge_hot_rxd_fill(void * hwd,const ddi_dma_cookie_t * cookie,size_t len)4326f3e57acSmx nge_hot_rxd_fill(void *hwd, const ddi_dma_cookie_t *cookie, size_t len)
4336f3e57acSmx {
4346f3e57acSmx 	uint64_t dmac_addr;
4356f3e57acSmx 	hot_rx_bd * hw_bd_p;
4366f3e57acSmx 
4376f3e57acSmx 	hw_bd_p = (hot_rx_bd *)hwd;
4386f3e57acSmx 	dmac_addr = cookie->dmac_laddress + NGE_HEADROOM;
4396f3e57acSmx 
4406f3e57acSmx 	hw_bd_p->cntl_status.cntl_val = 0;
4416f3e57acSmx 
4426f3e57acSmx 	hw_bd_p->host_buf_addr_hi = dmac_addr >> 32;
443a55f7119SMiles Xu, Sun Microsystems 	hw_bd_p->host_buf_addr_lo = (uint32_t)dmac_addr;
4446f3e57acSmx 	hw_bd_p->cntl_status.control_bits.bcnt = len - 1;
4456f3e57acSmx 
4466f3e57acSmx 	membar_producer();
4476f3e57acSmx 	hw_bd_p->cntl_status.control_bits.own = NGE_SET;
4486f3e57acSmx }
4496f3e57acSmx 
4506f3e57acSmx void
nge_sum_rxd_fill(void * hwd,const ddi_dma_cookie_t * cookie,size_t len)4516f3e57acSmx nge_sum_rxd_fill(void *hwd, const ddi_dma_cookie_t *cookie, size_t len)
4526f3e57acSmx {
4536f3e57acSmx 	sum_rx_bd * hw_bd_p;
4546f3e57acSmx 
4556f3e57acSmx 	hw_bd_p = hwd;
4566f3e57acSmx 
4576f3e57acSmx 	hw_bd_p->cntl_status.cntl_val = 0;
4586f3e57acSmx 
459a55f7119SMiles Xu, Sun Microsystems 	hw_bd_p->host_buf_addr =
460a55f7119SMiles Xu, Sun Microsystems 	    (uint32_t)(cookie->dmac_address + NGE_HEADROOM);
4616f3e57acSmx 	hw_bd_p->cntl_status.control_bits.bcnt = len - 1;
4626f3e57acSmx 
4636f3e57acSmx 	membar_producer();
4646f3e57acSmx 	hw_bd_p->cntl_status.control_bits.own = NGE_SET;
4656f3e57acSmx }
4666f3e57acSmx 
4676f3e57acSmx uint32_t
nge_hot_rxd_check(const void * hwd,size_t * len)4686f3e57acSmx nge_hot_rxd_check(const void *hwd, size_t *len)
4696f3e57acSmx {
4706f3e57acSmx 	uint32_t err_flag;
4716f3e57acSmx 	const hot_rx_bd * hrbdp;
4726f3e57acSmx 
4736f3e57acSmx 	hrbdp = hwd;
4749fa05d92SWinson Wang - Sun Microsystems - Beijing China 	err_flag = hrbdp->cntl_status.cntl_val;
4759fa05d92SWinson Wang - Sun Microsystems - Beijing China 	*len = err_flag & RXD_BCNT_MSK;
4766f3e57acSmx 	return (err_flag);
4776f3e57acSmx }
4786f3e57acSmx 
4796f3e57acSmx uint32_t
nge_sum_rxd_check(const void * hwd,size_t * len)4806f3e57acSmx nge_sum_rxd_check(const void *hwd, size_t *len)
4816f3e57acSmx {
4826f3e57acSmx 	uint32_t err_flag;
4836f3e57acSmx 	const sum_rx_bd * hrbdp;
4846f3e57acSmx 
4856f3e57acSmx 	hrbdp = hwd;
4866f3e57acSmx 
4879fa05d92SWinson Wang - Sun Microsystems - Beijing China 	err_flag = hrbdp->cntl_status.cntl_val;
4889fa05d92SWinson Wang - Sun Microsystems - Beijing China 	*len = err_flag & RXD_BCNT_MSK;
4896f3e57acSmx 	return (err_flag);
4906f3e57acSmx }
491