xref: /illumos-gate/usr/src/uts/common/io/nge/nge_tx.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 #define	TXD_OWN		0x80000000
306f3e57acSmx #define	TXD_ERR		0x40000000
316f3e57acSmx #define	TXD_END		0x20000000
326f3e57acSmx #define	TXD_BCNT_MSK	0x00003FFF
336f3e57acSmx 
346f3e57acSmx 
356f3e57acSmx #undef	NGE_DBG
366f3e57acSmx #define	NGE_DBG		NGE_DBG_SEND
376f3e57acSmx 
386f3e57acSmx #define	NGE_TXSWD_RECYCLE(sd)	{\
396f3e57acSmx 					(sd)->mp = NULL; \
406f3e57acSmx 					(sd)->frags = 0; \
416f3e57acSmx 					(sd)->mp_hndl.head = NULL; \
426f3e57acSmx 					(sd)->mp_hndl.tail = NULL; \
436f3e57acSmx 					(sd)->flags = HOST_OWN; \
446f3e57acSmx 				}
456f3e57acSmx 
466f3e57acSmx 
476f3e57acSmx static size_t nge_tx_dmah_pop(nge_dmah_list_t *, nge_dmah_list_t *, size_t);
486f3e57acSmx static void nge_tx_dmah_push(nge_dmah_list_t *, nge_dmah_list_t *);
496f3e57acSmx 
506f3e57acSmx 
516f3e57acSmx void nge_tx_recycle_all(nge_t *ngep);
526f3e57acSmx #pragma	no_inline(nge_tx_recycle_all)
536f3e57acSmx 
546f3e57acSmx void
nge_tx_recycle_all(nge_t * ngep)556f3e57acSmx nge_tx_recycle_all(nge_t *ngep)
566f3e57acSmx {
576f3e57acSmx 	send_ring_t *srp;
586f3e57acSmx 	sw_tx_sbd_t *ssbdp;
596f3e57acSmx 	nge_dmah_node_t	*dmah;
606f3e57acSmx 	uint32_t slot;
616f3e57acSmx 	uint32_t nslots;
626f3e57acSmx 
636f3e57acSmx 	srp = ngep->send;
646f3e57acSmx 	nslots = srp->desc.nslots;
656f3e57acSmx 
666f3e57acSmx 	for (slot = 0; slot < nslots; ++slot) {
676f3e57acSmx 
686f3e57acSmx 		ssbdp = srp->sw_sbds + slot;
696f3e57acSmx 
706f3e57acSmx 		DMA_ZERO(ssbdp->desc);
716f3e57acSmx 
726f3e57acSmx 		if (ssbdp->mp != NULL)	{
736f3e57acSmx 
746f3e57acSmx 			for (dmah = ssbdp->mp_hndl.head; dmah != NULL;
756f3e57acSmx 			    dmah = dmah->next)
766f3e57acSmx 				(void) ddi_dma_unbind_handle(dmah->hndl);
776f3e57acSmx 
786f3e57acSmx 			freemsg(ssbdp->mp);
796f3e57acSmx 		}
806f3e57acSmx 
816f3e57acSmx 		NGE_TXSWD_RECYCLE(ssbdp);
826f3e57acSmx 	}
8351fc88a8SWinson Wang - Sun Microsystems - Beijing China 	if (ngep->nge_mac_state == NGE_MAC_STARTED &&
8451fc88a8SWinson Wang - Sun Microsystems - Beijing China 	    ngep->resched_needed == 1) {
8551fc88a8SWinson Wang - Sun Microsystems - Beijing China 			ngep->resched_needed = 0;
8651fc88a8SWinson Wang - Sun Microsystems - Beijing China 			mac_tx_update(ngep->mh);
8751fc88a8SWinson Wang - Sun Microsystems - Beijing China 	}
8851fc88a8SWinson Wang - Sun Microsystems - Beijing China 
896f3e57acSmx }
906f3e57acSmx 
916f3e57acSmx static size_t
nge_tx_dmah_pop(nge_dmah_list_t * src,nge_dmah_list_t * dst,size_t num)926f3e57acSmx nge_tx_dmah_pop(nge_dmah_list_t *src, nge_dmah_list_t *dst, size_t num)
936f3e57acSmx {
946f3e57acSmx 	nge_dmah_node_t	*node;
956f3e57acSmx 
966f3e57acSmx 	for (node = src->head; node != NULL && --num != 0; node = node->next)
976f3e57acSmx 		;
986f3e57acSmx 
996f3e57acSmx 	if (num == 0)	{
1006f3e57acSmx 
1016f3e57acSmx 		dst->head = src->head;
1026f3e57acSmx 		dst->tail = node;
1036f3e57acSmx 
1046f3e57acSmx 		if ((src->head = node->next) == NULL)
1056f3e57acSmx 			src->tail = NULL;
1066f3e57acSmx 
1076f3e57acSmx 		node->next = NULL;
1086f3e57acSmx 	}
1096f3e57acSmx 
1106f3e57acSmx 	return (num);
1116f3e57acSmx }
1126f3e57acSmx 
1136f3e57acSmx static void
nge_tx_dmah_push(nge_dmah_list_t * src,nge_dmah_list_t * dst)1146f3e57acSmx nge_tx_dmah_push(nge_dmah_list_t *src, nge_dmah_list_t *dst)
1156f3e57acSmx {
1166f3e57acSmx 	if (dst->tail != NULL)
1176f3e57acSmx 		dst->tail->next = src->head;
1186f3e57acSmx 	else
1196f3e57acSmx 		dst->head = src->head;
1206f3e57acSmx 
1216f3e57acSmx 	dst->tail = src->tail;
1226f3e57acSmx }
1236f3e57acSmx 
1246f3e57acSmx static void
nge_tx_desc_sync(nge_t * ngep,uint32_t start_index,uint32_t bds,uint_t type)125a55f7119SMiles Xu, Sun Microsystems nge_tx_desc_sync(nge_t *ngep, uint32_t start_index, uint32_t bds, uint_t type)
1266f3e57acSmx {
1276f3e57acSmx 	send_ring_t *srp = ngep->send;
1286f3e57acSmx 	const size_t txd_size = ngep->desc_attr.txd_size;
1296f3e57acSmx 	const uint64_t end = srp->desc.nslots * txd_size;
130a55f7119SMiles Xu, Sun Microsystems 	uint64_t start;
131a55f7119SMiles Xu, Sun Microsystems 	uint64_t num;
1326f3e57acSmx 
133a55f7119SMiles Xu, Sun Microsystems 	start = start_index * txd_size;
134a55f7119SMiles Xu, Sun Microsystems 	num = bds * txd_size;
1356f3e57acSmx 
1366f3e57acSmx 	if (start + num <= end)
1376f3e57acSmx 		(void) ddi_dma_sync(srp->desc.dma_hdl, start, num, type);
1386f3e57acSmx 	else	{
1396f3e57acSmx 
1406f3e57acSmx 		(void) ddi_dma_sync(srp->desc.dma_hdl, start, 0, type);
1416f3e57acSmx 		(void) ddi_dma_sync(srp->desc.dma_hdl, 0, start + num - end,
1426f3e57acSmx 		    type);
1436f3e57acSmx 	}
1446f3e57acSmx }
1456f3e57acSmx 
1466f3e57acSmx /*
1476f3e57acSmx  * Reclaim the resource after tx's completion
1486f3e57acSmx  */
1496f3e57acSmx void
nge_tx_recycle(nge_t * ngep,boolean_t is_intr)1506f3e57acSmx nge_tx_recycle(nge_t *ngep, boolean_t is_intr)
1516f3e57acSmx {
1526f3e57acSmx 	int resched;
1536f3e57acSmx 	uint32_t stflg;
154a55f7119SMiles Xu, Sun Microsystems 	uint32_t free;
155a55f7119SMiles Xu, Sun Microsystems 	uint32_t slot;
156a55f7119SMiles Xu, Sun Microsystems 	uint32_t used;
157a55f7119SMiles Xu, Sun Microsystems 	uint32_t next;
158a55f7119SMiles Xu, Sun Microsystems 	uint32_t nslots;
1596f3e57acSmx 	mblk_t *mp;
1606f3e57acSmx 	sw_tx_sbd_t *ssbdp;
1616f3e57acSmx 	void *hw_sbd_p;
1626f3e57acSmx 	send_ring_t *srp;
1636f3e57acSmx 	nge_dmah_node_t *dme;
1646f3e57acSmx 	nge_dmah_list_t dmah;
1656f3e57acSmx 
1666f3e57acSmx 	srp = ngep->send;
1676f3e57acSmx 
1686f3e57acSmx 	if (is_intr) {
1696f3e57acSmx 		if (mutex_tryenter(srp->tc_lock) == 0)
1706f3e57acSmx 			return;
1716f3e57acSmx 	} else
1726f3e57acSmx 		mutex_enter(srp->tc_lock);
1736f3e57acSmx 	mutex_enter(srp->tx_lock);
1746f3e57acSmx 
1756f3e57acSmx 	next = srp->tx_next;
1766f3e57acSmx 	used = srp->tx_flow;
1776f3e57acSmx 	free = srp->tx_free;
1786f3e57acSmx 
1796f3e57acSmx 	mutex_exit(srp->tx_lock);
1806f3e57acSmx 
1816f3e57acSmx 	slot = srp->tc_next;
1826f3e57acSmx 	nslots = srp->desc.nslots;
1836f3e57acSmx 
1846f3e57acSmx 	used = nslots - free - used;
1856f3e57acSmx 
1866f3e57acSmx 	ASSERT(slot == NEXT_INDEX(next, free, nslots));
18751fc88a8SWinson Wang - Sun Microsystems - Beijing China 	if (used == 0) {
18851fc88a8SWinson Wang - Sun Microsystems - Beijing China 		ngep->watchdog = 0;
18951fc88a8SWinson Wang - Sun Microsystems - Beijing China 		mutex_exit(srp->tc_lock);
19051fc88a8SWinson Wang - Sun Microsystems - Beijing China 		return;
19151fc88a8SWinson Wang - Sun Microsystems - Beijing China 	}
1926f3e57acSmx 
19351fc88a8SWinson Wang - Sun Microsystems - Beijing China 	if (used > srp->tx_hwmark && ngep->resched_needed == 0)
1946f3e57acSmx 		used = srp->tx_hwmark;
1956f3e57acSmx 
1966f3e57acSmx 	nge_tx_desc_sync(ngep, slot, used, DDI_DMA_SYNC_FORKERNEL);
1976f3e57acSmx 
1986f3e57acSmx 	/*
1996f3e57acSmx 	 * Look through the send ring by bd's status part
2006f3e57acSmx 	 * to find all the bds which has been transmitted sucessfully
2016f3e57acSmx 	 * then reclaim all resouces associated with these bds
2026f3e57acSmx 	 */
2036f3e57acSmx 
2046f3e57acSmx 	mp = NULL;
2056f3e57acSmx 	dmah.head = NULL;
2066f3e57acSmx 	dmah.tail = NULL;
2076f3e57acSmx 
2086f3e57acSmx 	for (free = 0; used-- != 0; slot = NEXT(slot, nslots), ++free)	{
2096f3e57acSmx 
2106f3e57acSmx 		ssbdp = &srp->sw_sbds[slot];
2116f3e57acSmx 		hw_sbd_p = DMA_VPTR(ssbdp->desc);
2126f3e57acSmx 
21373236167SWinson Wang - Sun Microsystems - Beijing China 		if (ssbdp->flags == HOST_OWN)
21473236167SWinson Wang - Sun Microsystems - Beijing China 			break;
2159fa05d92SWinson Wang - Sun Microsystems - Beijing China 		stflg = ngep->desc_attr.txd_check(hw_sbd_p);
21673236167SWinson Wang - Sun Microsystems - Beijing China 		if ((stflg & TXD_OWN) != 0)
2176f3e57acSmx 			break;
218cb824541SWinson Wang - Sun Microsystems - Beijing China 		DMA_ZERO(ssbdp->desc);
2196f3e57acSmx 		if (ssbdp->mp != NULL)	{
2206f3e57acSmx 			ssbdp->mp->b_next = mp;
2216f3e57acSmx 			mp = ssbdp->mp;
2226f3e57acSmx 
2236f3e57acSmx 			if (ssbdp->mp_hndl.head != NULL)
2246f3e57acSmx 				nge_tx_dmah_push(&ssbdp->mp_hndl, &dmah);
2256f3e57acSmx 		}
2266f3e57acSmx 
2276f3e57acSmx 		NGE_TXSWD_RECYCLE(ssbdp);
2286f3e57acSmx 	}
2296f3e57acSmx 
2306f3e57acSmx 	/*
2316f3e57acSmx 	 * We're about to release one or more places :-)
2326f3e57acSmx 	 * These ASSERTions check that our invariants still hold:
2336f3e57acSmx 	 * there must always be at least one free place
2346f3e57acSmx 	 * at this point, there must be at least one place NOT free
2356f3e57acSmx 	 * we're not about to free more places than were claimed!
2366f3e57acSmx 	 */
2376f3e57acSmx 
23851fc88a8SWinson Wang - Sun Microsystems - Beijing China 	if (free == 0) {
23951fc88a8SWinson Wang - Sun Microsystems - Beijing China 		mutex_exit(srp->tc_lock);
24051fc88a8SWinson Wang - Sun Microsystems - Beijing China 		return;
24151fc88a8SWinson Wang - Sun Microsystems - Beijing China 	}
24251fc88a8SWinson Wang - Sun Microsystems - Beijing China 
2436f3e57acSmx 	mutex_enter(srp->tx_lock);
2446f3e57acSmx 
2456f3e57acSmx 	srp->tx_free += free;
2466f3e57acSmx 	ngep->watchdog = (srp->desc.nslots - srp->tx_free != 0);
2476f3e57acSmx 
2486f3e57acSmx 	srp->tc_next = slot;
2496f3e57acSmx 
2506f3e57acSmx 	ASSERT(srp->tx_free <= nslots);
2516f3e57acSmx 	ASSERT(srp->tc_next == NEXT_INDEX(srp->tx_next, srp->tx_free, nslots));
2526f3e57acSmx 
2536f3e57acSmx 	resched = (ngep->resched_needed != 0 && srp->tx_hwmark <= srp->tx_free);
2546f3e57acSmx 
2556f3e57acSmx 	mutex_exit(srp->tx_lock);
2566f3e57acSmx 	mutex_exit(srp->tc_lock);
2576f3e57acSmx 
2586f3e57acSmx 	/* unbind/free mblks */
2596f3e57acSmx 
2606f3e57acSmx 	for (dme = dmah.head; dme != NULL; dme = dme->next)
2616f3e57acSmx 		(void) ddi_dma_unbind_handle(dme->hndl);
2626ad24245SWinson Wang - Sun Microsystems - Beijing China 	if (dmah.head != NULL) {
2636ad24245SWinson Wang - Sun Microsystems - Beijing China 		mutex_enter(&srp->dmah_lock);
2646ad24245SWinson Wang - Sun Microsystems - Beijing China 		nge_tx_dmah_push(&dmah, &srp->dmah_free);
2656ad24245SWinson Wang - Sun Microsystems - Beijing China 		mutex_exit(&srp->dmah_lock);
2666ad24245SWinson Wang - Sun Microsystems - Beijing China 	}
2676f3e57acSmx 	freemsgchain(mp);
2686f3e57acSmx 
2696f3e57acSmx 	/*
2706f3e57acSmx 	 * up to this place, we maybe have reclaim some resouce
2716f3e57acSmx 	 * if there is a requirement to report to gld, report this.
2726f3e57acSmx 	 */
2736f3e57acSmx 
2746f3e57acSmx 	if (resched)
2756f3e57acSmx 		(void) ddi_intr_trigger_softint(ngep->resched_hdl, NULL);
2766f3e57acSmx }
2776f3e57acSmx 
278a55f7119SMiles Xu, Sun Microsystems static uint32_t
nge_tx_alloc(nge_t * ngep,uint32_t num)279a55f7119SMiles Xu, Sun Microsystems nge_tx_alloc(nge_t *ngep, uint32_t num)
2806f3e57acSmx {
281a55f7119SMiles Xu, Sun Microsystems 	uint32_t start;
2826f3e57acSmx 	send_ring_t *srp;
2836f3e57acSmx 
284a55f7119SMiles Xu, Sun Microsystems 	start = (uint32_t)-1;
2856f3e57acSmx 	srp = ngep->send;
2866f3e57acSmx 
2876f3e57acSmx 	mutex_enter(srp->tx_lock);
2886f3e57acSmx 
2896f3e57acSmx 	if (srp->tx_free < srp->tx_lwmark)	{
2906f3e57acSmx 
2916f3e57acSmx 		mutex_exit(srp->tx_lock);
2926f3e57acSmx 		nge_tx_recycle(ngep, B_FALSE);
2936f3e57acSmx 		mutex_enter(srp->tx_lock);
2946f3e57acSmx 	}
2956f3e57acSmx 
2966f3e57acSmx 	if (srp->tx_free >= num)	{
2976f3e57acSmx 
2986f3e57acSmx 		start = srp->tx_next;
2996f3e57acSmx 
3006f3e57acSmx 		srp->tx_next = NEXT_INDEX(start, num, srp->desc.nslots);
3016f3e57acSmx 		srp->tx_free -= num;
3026f3e57acSmx 		srp->tx_flow += num;
3036f3e57acSmx 	}
3046f3e57acSmx 
3056f3e57acSmx 	mutex_exit(srp->tx_lock);
3066f3e57acSmx 	return (start);
3076f3e57acSmx }
3086f3e57acSmx 
3096f3e57acSmx static void
nge_tx_start(nge_t * ngep,uint32_t slotnum)310a55f7119SMiles Xu, Sun Microsystems nge_tx_start(nge_t *ngep, uint32_t slotnum)
3116f3e57acSmx {
3126f3e57acSmx 	nge_mode_cntl mode_cntl;
3136f3e57acSmx 	send_ring_t *srp;
3146f3e57acSmx 
3156f3e57acSmx 	srp = ngep->send;
3166f3e57acSmx 
3176f3e57acSmx 	/*
3186f3e57acSmx 	 * Because there can be multiple concurrent threads in
3196f3e57acSmx 	 * transit through this code, we only want to notify the
3206f3e57acSmx 	 * hardware once the last one is departing ...
3216f3e57acSmx 	 */
3226f3e57acSmx 
3236f3e57acSmx 	mutex_enter(srp->tx_lock);
3246f3e57acSmx 
3256f3e57acSmx 	srp->tx_flow -= slotnum;
3266f3e57acSmx 	if (srp->tx_flow == 0) {
3276f3e57acSmx 
3286f3e57acSmx 		/*
3296f3e57acSmx 		 * Bump the watchdog counter, thus guaranteeing that it's
3306f3e57acSmx 		 * nonzero (watchdog activated).  Note that non-synchonised
3316f3e57acSmx 		 * access here means we may race with the reclaim() code
3326f3e57acSmx 		 * above, but the outcome will be harmless.  At worst, the
3336f3e57acSmx 		 * counter may not get reset on a partial reclaim; but the
3346f3e57acSmx 		 * large trigger threshold makes false positives unlikely
3356f3e57acSmx 		 */
33651fc88a8SWinson Wang - Sun Microsystems - Beijing China 		if (ngep->watchdog == 0)
33751fc88a8SWinson Wang - Sun Microsystems - Beijing China 			ngep->watchdog = 1;
3386f3e57acSmx 
3396f3e57acSmx 		mode_cntl.mode_val = nge_reg_get32(ngep, NGE_MODE_CNTL);
3406f3e57acSmx 		mode_cntl.mode_bits.txdm = NGE_SET;
3416f3e57acSmx 		mode_cntl.mode_bits.tx_rcom_en = NGE_SET;
3426f3e57acSmx 		nge_reg_put32(ngep, NGE_MODE_CNTL, mode_cntl.mode_val);
3436f3e57acSmx 	}
3446f3e57acSmx 	mutex_exit(srp->tx_lock);
3456f3e57acSmx }
3466f3e57acSmx 
3476f3e57acSmx static enum send_status
3486f3e57acSmx nge_send_copy(nge_t *ngep, mblk_t *mp, send_ring_t *srp);
3496f3e57acSmx #pragma	inline(nge_send_copy)
3506f3e57acSmx 
3516f3e57acSmx static enum send_status
nge_send_copy(nge_t * ngep,mblk_t * mp,send_ring_t * srp)3526f3e57acSmx nge_send_copy(nge_t *ngep, mblk_t *mp, send_ring_t *srp)
3536f3e57acSmx {
3546f3e57acSmx 	size_t totlen;
3556f3e57acSmx 	size_t mblen;
3566f3e57acSmx 	uint32_t flags;
357a55f7119SMiles Xu, Sun Microsystems 	uint32_t bds;
358a55f7119SMiles Xu, Sun Microsystems 	uint32_t start_index;
3596f3e57acSmx 	char *txb;
3606f3e57acSmx 	mblk_t *bp;
3616f3e57acSmx 	void *hw_sbd_p;
3626f3e57acSmx 	sw_tx_sbd_t *ssbdp;
36351fc88a8SWinson Wang - Sun Microsystems - Beijing China 	boolean_t tfint;
3646f3e57acSmx 
365*0dc2366fSVenugopal Iyer 	mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &flags);
3666f3e57acSmx 	bds = 0x1;
3676f3e57acSmx 
368a55f7119SMiles Xu, Sun Microsystems 	if ((uint32_t)-1 == (start_index = nge_tx_alloc(ngep, bds)))
3696f3e57acSmx 		return (SEND_COPY_FAIL);
3706f3e57acSmx 
3716f3e57acSmx 	ASSERT(start_index < srp->desc.nslots);
3726f3e57acSmx 
3736f3e57acSmx 	/*
3746f3e57acSmx 	 * up to this point, there's nothing that can fail,
3756f3e57acSmx 	 * so we can go straight to claiming our
3766f3e57acSmx 	 * already-reserved place son the train.
3776f3e57acSmx 	 *
3786f3e57acSmx 	 * This is the point of no return!
3796f3e57acSmx 	 */
3806f3e57acSmx 
38151fc88a8SWinson Wang - Sun Microsystems - Beijing China 	tfint = ((start_index % ngep->tfint_threshold) == 0);
3826f3e57acSmx 	bp = mp;
3836f3e57acSmx 	totlen = 0;
3846f3e57acSmx 	ssbdp = &srp->sw_sbds[start_index];
3856f3e57acSmx 	ASSERT(ssbdp->flags == HOST_OWN);
3866f3e57acSmx 
3876f3e57acSmx 	txb = DMA_VPTR(ssbdp->pbuf);
3886f3e57acSmx 	totlen = 0;
3896f3e57acSmx 	for (; bp != NULL; bp = bp->b_cont) {
3906f3e57acSmx 		if ((mblen = MBLKL(bp)) == 0)
3916f3e57acSmx 			continue;
3926f3e57acSmx 		if ((totlen += mblen) <= ngep->max_sdu) {
3936f3e57acSmx 			bcopy(bp->b_rptr, txb, mblen);
3946f3e57acSmx 			txb += mblen;
3956f3e57acSmx 		}
3966f3e57acSmx 	}
3976f3e57acSmx 
3986f3e57acSmx 	DMA_SYNC(ssbdp->pbuf, DDI_DMA_SYNC_FORDEV);
3996f3e57acSmx 
4006f3e57acSmx 	/* Fill & sync hw desc */
4016f3e57acSmx 
4026f3e57acSmx 	hw_sbd_p = DMA_VPTR(ssbdp->desc);
4036f3e57acSmx 
4046f3e57acSmx 	ngep->desc_attr.txd_fill(hw_sbd_p, &ssbdp->pbuf.cookie, totlen,
40551fc88a8SWinson Wang - Sun Microsystems - Beijing China 	    flags, B_TRUE, tfint);
4066f3e57acSmx 	nge_tx_desc_sync(ngep, start_index, bds, DDI_DMA_SYNC_FORDEV);
4076f3e57acSmx 
4086f3e57acSmx 	ssbdp->flags = CONTROLER_OWN;
4096f3e57acSmx 
4106f3e57acSmx 	nge_tx_start(ngep, bds);
4116f3e57acSmx 
4126f3e57acSmx 	/*
4136f3e57acSmx 	 * The return status indicates that the message can be freed
4146f3e57acSmx 	 * right away, as we've already copied the contents ...
4156f3e57acSmx 	 */
4166f3e57acSmx 
4176f3e57acSmx 	freemsg(mp);
4186f3e57acSmx 	return (SEND_COPY_SUCESS);
4196f3e57acSmx }
4206f3e57acSmx 
4216f3e57acSmx /*
4226f3e57acSmx  * static enum send_status
4236f3e57acSmx  * nge_send_mapped(nge_t *ngep, mblk_t *mp, size_t fragno);
4246f3e57acSmx  * #pragma	inline(nge_send_mapped)
4256f3e57acSmx  */
4266f3e57acSmx 
4276f3e57acSmx static enum send_status
nge_send_mapped(nge_t * ngep,mblk_t * mp,size_t fragno)4286f3e57acSmx nge_send_mapped(nge_t *ngep, mblk_t *mp, size_t fragno)
4296f3e57acSmx {
4306f3e57acSmx 	int err;
4316f3e57acSmx 	boolean_t end;
4326f3e57acSmx 	uint32_t i;
4336f3e57acSmx 	uint32_t j;
4346f3e57acSmx 	uint32_t ncookies;
4356f3e57acSmx 	uint32_t slot;
4366f3e57acSmx 	uint32_t nslots;
4376f3e57acSmx 	uint32_t mblen;
4386f3e57acSmx 	uint32_t flags;
439a55f7119SMiles Xu, Sun Microsystems 	uint32_t start_index;
440a55f7119SMiles Xu, Sun Microsystems 	uint32_t end_index;
4416f3e57acSmx 	mblk_t *bp;
4426f3e57acSmx 	void *hw_sbd_p;
4436f3e57acSmx 	send_ring_t *srp;
4446f3e57acSmx 	nge_dmah_node_t *dmah;
4456f3e57acSmx 	nge_dmah_node_t	*dmer;
4466f3e57acSmx 	nge_dmah_list_t dmah_list;
4476f3e57acSmx 	ddi_dma_cookie_t cookie[NGE_MAX_COOKIES * NGE_MAP_FRAGS];
44851fc88a8SWinson Wang - Sun Microsystems - Beijing China 	boolean_t tfint;
4496f3e57acSmx 
4506f3e57acSmx 	srp = ngep->send;
4516f3e57acSmx 	nslots = srp->desc.nslots;
4526f3e57acSmx 
4536f3e57acSmx 	mutex_enter(&srp->dmah_lock);
4546f3e57acSmx 	err = nge_tx_dmah_pop(&srp->dmah_free, &dmah_list, fragno);
4556f3e57acSmx 	mutex_exit(&srp->dmah_lock);
4566f3e57acSmx 
4576f3e57acSmx 	if (err != 0)	{
4586f3e57acSmx 
4596f3e57acSmx 		return (SEND_MAP_FAIL);
4606f3e57acSmx 	}
4616f3e57acSmx 
4626f3e57acSmx 	/*
4636f3e57acSmx 	 * Pre-scan the message chain, noting the total number of bytes,
4646f3e57acSmx 	 * the number of fragments by pre-doing dma addr bind
4656f3e57acSmx 	 * if the fragment is larger than NGE_COPY_SIZE.
4666f3e57acSmx 	 * This way has the following advantages:
4676f3e57acSmx 	 * 1. Acquire the detailed information of resouce
4686f3e57acSmx 	 *	need to send the message
4696f3e57acSmx 	 *
4706f3e57acSmx 	 * 2. If can not pre-apply enough resouce, fails  at once
4716f3e57acSmx 	 *	and the driver will chose copy way to send out the
4726f3e57acSmx 	 *	message
4736f3e57acSmx 	 */
4746f3e57acSmx 
4756f3e57acSmx 	slot = 0;
4766f3e57acSmx 	dmah = dmah_list.head;
4776f3e57acSmx 
478*0dc2366fSVenugopal Iyer 	mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &flags);
4796f3e57acSmx 
4806f3e57acSmx 	for (bp = mp; bp != NULL; bp = bp->b_cont)	{
4816f3e57acSmx 
4826f3e57acSmx 		mblen = MBLKL(bp);
4836f3e57acSmx 		if (mblen == 0)
4846f3e57acSmx 			continue;
4856f3e57acSmx 
4866f3e57acSmx 		err = ddi_dma_addr_bind_handle(dmah->hndl,
4876f3e57acSmx 		    NULL, (caddr_t)bp->b_rptr, mblen,
4886f3e57acSmx 		    DDI_DMA_STREAMING | DDI_DMA_WRITE,
4896f3e57acSmx 		    DDI_DMA_DONTWAIT, NULL, cookie + slot, &ncookies);
4906f3e57acSmx 
4916f3e57acSmx 		/*
4926f3e57acSmx 		 * If there can not map successfully, it is uncessary
4936f3e57acSmx 		 * sending the message by map way. Sending the message
4946f3e57acSmx 		 * by copy way.
4956f3e57acSmx 		 *
4966f3e57acSmx 		 * By referring to intel's suggestion, it is better
4976f3e57acSmx 		 * the number of cookies should be less than 4.
4986f3e57acSmx 		 */
4996f3e57acSmx 		if (err != DDI_DMA_MAPPED || ncookies > NGE_MAX_COOKIES) {
5006f3e57acSmx 			NGE_DEBUG(("err(%x) map tx bulk fails"
5016f3e57acSmx 			    " cookie(%x), ncookies(%x)",
5026f3e57acSmx 			    err, cookie[slot].dmac_laddress, ncookies));
5036f3e57acSmx 			goto map_fail;
5046f3e57acSmx 		}
5056f3e57acSmx 
5066f3e57acSmx 		/*
5076f3e57acSmx 		 * Check How many bds a cookie will consume
5086f3e57acSmx 		 */
5096f3e57acSmx 		for (end_index = slot + ncookies;
5106f3e57acSmx 		    ++slot != end_index;
5116f3e57acSmx 		    ddi_dma_nextcookie(dmah->hndl, cookie + slot))
5126f3e57acSmx 			;
5136f3e57acSmx 
5146f3e57acSmx 		dmah = dmah->next;
5156f3e57acSmx 	}
5166f3e57acSmx 
5176f3e57acSmx 	/*
5186f3e57acSmx 	 * Now allocate tx descriptors and fill them
5196f3e57acSmx 	 * IMPORTANT:
5206f3e57acSmx 	 *	Up to the point where it claims a place, It is impossibel
5216f3e57acSmx 	 * 	to fail.
5226f3e57acSmx 	 *
5236f3e57acSmx 	 * In this version, there's no setup to be done here, and there's
5246f3e57acSmx 	 * nothing that can fail, so we can go straight to claiming our
5256f3e57acSmx 	 * already-reserved places on the train.
5266f3e57acSmx 	 *
5276f3e57acSmx 	 * This is the point of no return!
5286f3e57acSmx 	 */
5296f3e57acSmx 
5306f3e57acSmx 
531a55f7119SMiles Xu, Sun Microsystems 	if ((uint32_t)-1 == (start_index = nge_tx_alloc(ngep, slot)))
5326f3e57acSmx 		goto map_fail;
5336f3e57acSmx 
5346f3e57acSmx 	ASSERT(start_index < nslots);
5356f3e57acSmx 
5366f3e57acSmx 	/* fill&sync hw desc, going in reverse order */
5376f3e57acSmx 
5386f3e57acSmx 	end = B_TRUE;
5396f3e57acSmx 	end_index = NEXT_INDEX(start_index, slot - 1, nslots);
5406f3e57acSmx 
5416f3e57acSmx 	for (i = slot - 1, j = end_index; start_index - j != 0;
5426f3e57acSmx 	    j = PREV(j, nslots), --i)	{
5436f3e57acSmx 
54451fc88a8SWinson Wang - Sun Microsystems - Beijing China 		tfint = ((j % ngep->tfint_threshold) == 0);
5456f3e57acSmx 		hw_sbd_p = DMA_VPTR(srp->sw_sbds[j].desc);
5466f3e57acSmx 		ngep->desc_attr.txd_fill(hw_sbd_p, cookie + i,
54751fc88a8SWinson Wang - Sun Microsystems - Beijing China 		    cookie[i].dmac_size, 0, end, tfint);
5486f3e57acSmx 
5496f3e57acSmx 		end = B_FALSE;
5506f3e57acSmx 	}
5516f3e57acSmx 
5526f3e57acSmx 	hw_sbd_p = DMA_VPTR(srp->sw_sbds[j].desc);
55351fc88a8SWinson Wang - Sun Microsystems - Beijing China 	tfint = ((j % ngep->tfint_threshold) == 0);
5546f3e57acSmx 	ngep->desc_attr.txd_fill(hw_sbd_p, cookie + i, cookie[i].dmac_size,
55551fc88a8SWinson Wang - Sun Microsystems - Beijing China 	    flags, end, tfint);
5566f3e57acSmx 
5576f3e57acSmx 	nge_tx_desc_sync(ngep, start_index, slot, DDI_DMA_SYNC_FORDEV);
5586f3e57acSmx 
5596f3e57acSmx 	/* fill sw desc */
5606f3e57acSmx 
561a55f7119SMiles Xu, Sun Microsystems 	for (j = start_index; end_index - j != 0; j = NEXT(j, nslots)) {
5626f3e57acSmx 
5636f3e57acSmx 		srp->sw_sbds[j].flags = CONTROLER_OWN;
5646f3e57acSmx 	}
5656f3e57acSmx 
5666f3e57acSmx 	srp->sw_sbds[j].mp = mp;
5676f3e57acSmx 	srp->sw_sbds[j].mp_hndl = dmah_list;
568a55f7119SMiles Xu, Sun Microsystems 	srp->sw_sbds[j].frags = (uint32_t)fragno;
5696f3e57acSmx 	srp->sw_sbds[j].flags = CONTROLER_OWN;
5706f3e57acSmx 
5716f3e57acSmx 	nge_tx_start(ngep, slot);
5726f3e57acSmx 
5736f3e57acSmx 	/*
5746f3e57acSmx 	 * The return status indicates that the message can not be freed
5756f3e57acSmx 	 * right away, until we can make assure the message has been sent
5766f3e57acSmx 	 * out sucessfully.
5776f3e57acSmx 	 */
5786f3e57acSmx 	return (SEND_MAP_SUCCESS);
5796f3e57acSmx 
5806f3e57acSmx map_fail:
5816f3e57acSmx 	for (dmer = dmah_list.head; dmah - dmer != 0; dmer = dmer->next)
5826f3e57acSmx 		(void) ddi_dma_unbind_handle(dmer->hndl);
5836f3e57acSmx 
5846f3e57acSmx 	mutex_enter(&srp->dmah_lock);
5856f3e57acSmx 	nge_tx_dmah_push(&dmah_list, &srp->dmah_free);
5866f3e57acSmx 	mutex_exit(&srp->dmah_lock);
5876f3e57acSmx 
5886f3e57acSmx 	return (SEND_MAP_FAIL);
5896f3e57acSmx }
5906f3e57acSmx 
5916f3e57acSmx static boolean_t
nge_send(nge_t * ngep,mblk_t * mp)5926f3e57acSmx nge_send(nge_t *ngep, mblk_t *mp)
5936f3e57acSmx {
5946f3e57acSmx 	mblk_t *bp;
5956f3e57acSmx 	send_ring_t *srp;
5966f3e57acSmx 	enum send_status status;
5976f3e57acSmx 	uint32_t mblen = 0;
5986f3e57acSmx 	uint32_t frags = 0;
5996f3e57acSmx 	nge_statistics_t *nstp = &ngep->statistics;
6006f3e57acSmx 	nge_sw_statistics_t *sw_stp = &nstp->sw_statistics;
6016f3e57acSmx 
6026f3e57acSmx 	ASSERT(mp != NULL);
6036f3e57acSmx 	ASSERT(ngep->nge_mac_state == NGE_MAC_STARTED);
6046f3e57acSmx 
6056f3e57acSmx 	srp = ngep->send;
6066f3e57acSmx 	/*
6076f3e57acSmx 	 * 1.Check the number of the fragments of the messages
6086f3e57acSmx 	 * If the total number is larger than 3,
6096f3e57acSmx 	 * Chose copy way
6106f3e57acSmx 	 *
6116f3e57acSmx 	 * 2. Check the length of the message whether is larger than
6126f3e57acSmx 	 * NGE_TX_COPY_SIZE, if so, choose the map way.
6136f3e57acSmx 	 */
6146f3e57acSmx 	for (frags = 0, bp = mp; bp != NULL; bp = bp->b_cont) {
6156f3e57acSmx 		if (MBLKL(bp) == 0)
6166f3e57acSmx 			continue;
6176f3e57acSmx 		frags++;
6186f3e57acSmx 		mblen += MBLKL(bp);
6196f3e57acSmx 	}
6206f3e57acSmx 	if (mblen > (ngep->max_sdu) || mblen == 0) {
6216f3e57acSmx 		freemsg(mp);
6226f3e57acSmx 		return (B_TRUE);
6236f3e57acSmx 	}
6246f3e57acSmx 	if ((mblen > ngep->param_txbcopy_threshold) &&
6256ad24245SWinson Wang - Sun Microsystems - Beijing China 	    (frags <= NGE_MAP_FRAGS) &&
6266f3e57acSmx 	    (srp->tx_free > frags * NGE_MAX_COOKIES)) {
6276f3e57acSmx 		status = nge_send_mapped(ngep, mp, frags);
6286f3e57acSmx 		if (status == SEND_MAP_FAIL)
6296f3e57acSmx 			status = nge_send_copy(ngep, mp, srp);
6306f3e57acSmx 	} else {
6316f3e57acSmx 		status = nge_send_copy(ngep, mp, srp);
6326f3e57acSmx 	}
6336f3e57acSmx 	if (status == SEND_COPY_FAIL) {
6346f3e57acSmx 		nge_tx_recycle(ngep, B_FALSE);
6356f3e57acSmx 		status = nge_send_copy(ngep, mp, srp);
6366f3e57acSmx 		if (status == SEND_COPY_FAIL) {
6376f3e57acSmx 			ngep->resched_needed = 1;
6386f3e57acSmx 			NGE_DEBUG(("nge_send: send fail!"));
6396f3e57acSmx 			return (B_FALSE);
6406f3e57acSmx 		}
6416f3e57acSmx 	}
6426f3e57acSmx 	/* Update the software statistics */
6436f3e57acSmx 	sw_stp->obytes += mblen + ETHERFCSL;
6446f3e57acSmx 	sw_stp->xmit_count ++;
6456f3e57acSmx 
6466f3e57acSmx 	return (B_TRUE);
6476f3e57acSmx }
6486f3e57acSmx 
6496f3e57acSmx /*
6506f3e57acSmx  * nge_m_tx : Send a chain of packets.
6516f3e57acSmx  */
6526f3e57acSmx mblk_t *
nge_m_tx(void * arg,mblk_t * mp)6536f3e57acSmx nge_m_tx(void *arg, mblk_t *mp)
6546f3e57acSmx {
6556f3e57acSmx 	nge_t *ngep = arg;
6566f3e57acSmx 	mblk_t *next;
6576f3e57acSmx 
6586f3e57acSmx 	rw_enter(ngep->rwlock, RW_READER);
6596f3e57acSmx 	ASSERT(mp != NULL);
6606f3e57acSmx 	if (ngep->nge_chip_state != NGE_CHIP_RUNNING) {
6616f3e57acSmx 		freemsgchain(mp);
6626f3e57acSmx 		mp = NULL;
6636f3e57acSmx 	}
6646f3e57acSmx 	while (mp != NULL) {
6656f3e57acSmx 		next = mp->b_next;
6666f3e57acSmx 		mp->b_next = NULL;
6676f3e57acSmx 
6686f3e57acSmx 		if (!nge_send(ngep, mp)) {
6696f3e57acSmx 			mp->b_next = next;
6706f3e57acSmx 			break;
6716f3e57acSmx 		}
6726f3e57acSmx 
6736f3e57acSmx 		mp = next;
6746f3e57acSmx 	}
6756f3e57acSmx 	rw_exit(ngep->rwlock);
6766f3e57acSmx 
6776f3e57acSmx 	return (mp);
6786f3e57acSmx }
6796f3e57acSmx 
6806f3e57acSmx /* ARGSUSED */
6816f3e57acSmx uint_t
nge_reschedule(caddr_t args1,caddr_t args2)6826f3e57acSmx nge_reschedule(caddr_t args1, caddr_t args2)
6836f3e57acSmx {
6846f3e57acSmx 	nge_t *ngep;
6856f3e57acSmx 	uint_t rslt;
6866f3e57acSmx 
6876f3e57acSmx 	ngep = (nge_t *)args1;
6886f3e57acSmx 	rslt = DDI_INTR_UNCLAIMED;
6896f3e57acSmx 
6906f3e57acSmx 	/*
6916f3e57acSmx 	 * when softintr is trigged, checking whether this
6926f3e57acSmx 	 * is caused by our expected interrupt
6936f3e57acSmx 	 */
6946f3e57acSmx 	if (ngep->nge_mac_state == NGE_MAC_STARTED &&
6956f3e57acSmx 	    ngep->resched_needed == 1) {
6966f3e57acSmx 		ngep->resched_needed = 0;
6976f3e57acSmx 		++ngep->statistics.sw_statistics.tx_resched;
6986f3e57acSmx 		mac_tx_update(ngep->mh);
6996f3e57acSmx 		rslt = DDI_INTR_CLAIMED;
7006f3e57acSmx 	}
7016f3e57acSmx 	return (rslt);
7026f3e57acSmx }
7036f3e57acSmx 
7046f3e57acSmx uint32_t
nge_hot_txd_check(const void * hwd)7059fa05d92SWinson Wang - Sun Microsystems - Beijing China nge_hot_txd_check(const void *hwd)
7066f3e57acSmx {
7076f3e57acSmx 	uint32_t err_flag;
7086f3e57acSmx 	const hot_tx_bd * htbdp;
7096f3e57acSmx 
7106f3e57acSmx 	htbdp = hwd;
7119fa05d92SWinson Wang - Sun Microsystems - Beijing China 	err_flag = htbdp->control_status.cntl_val;
7126f3e57acSmx 	return (err_flag);
7136f3e57acSmx }
7146f3e57acSmx 
7156f3e57acSmx uint32_t
nge_sum_txd_check(const void * hwd)7169fa05d92SWinson Wang - Sun Microsystems - Beijing China nge_sum_txd_check(const void *hwd)
7176f3e57acSmx {
7186f3e57acSmx 	uint32_t err_flag;
7196f3e57acSmx 	const sum_tx_bd * htbdp;
7206f3e57acSmx 
7216f3e57acSmx 	htbdp = hwd;
7229fa05d92SWinson Wang - Sun Microsystems - Beijing China 	err_flag = htbdp->control_status.cntl_val;
7236f3e57acSmx 	return (err_flag);
7246f3e57acSmx }
7256f3e57acSmx 
7266f3e57acSmx 
7276f3e57acSmx /*
7286f3e57acSmx  * Filling the contents of Tx's data descriptor
7296f3e57acSmx  * before transmitting.
7306f3e57acSmx  */
7316f3e57acSmx 
7326f3e57acSmx void
nge_hot_txd_fill(void * hwdesc,const ddi_dma_cookie_t * cookie,size_t length,uint32_t sum_flag,boolean_t end,boolean_t tfint)7336f3e57acSmx nge_hot_txd_fill(void *hwdesc, const ddi_dma_cookie_t *cookie,
73451fc88a8SWinson Wang - Sun Microsystems - Beijing China 	size_t length, uint32_t sum_flag, boolean_t end, boolean_t tfint)
7356f3e57acSmx {
7366f3e57acSmx 	hot_tx_bd * hw_sbd_p = hwdesc;
7376f3e57acSmx 
7386f3e57acSmx 	hw_sbd_p->host_buf_addr_hi = cookie->dmac_laddress >> 32;
7396f3e57acSmx 	hw_sbd_p->host_buf_addr_lo = cookie->dmac_laddress;
7406f3e57acSmx 
7416f3e57acSmx 	/*
7426f3e57acSmx 	 * Setting the length of the packet
7436f3e57acSmx 	 * Note: the length filled in the part should be
7446f3e57acSmx 	 * the original length subtract 1;
7456f3e57acSmx 	 */
7466f3e57acSmx 
7476f3e57acSmx 	hw_sbd_p->control_status.control_sum_bits.bcnt = length - 1;
7486f3e57acSmx 
7496f3e57acSmx 	/* setting ip checksum */
7506f3e57acSmx 	if (sum_flag & HCK_IPV4_HDRCKSUM)
7516f3e57acSmx 		hw_sbd_p->control_status.control_sum_bits.ip_hsum
7526f3e57acSmx 		    = NGE_SET;
7536f3e57acSmx 	/* setting tcp checksum */
7546f3e57acSmx 	if (sum_flag & HCK_FULLCKSUM)
7556f3e57acSmx 		hw_sbd_p->control_status.control_sum_bits.tcp_hsum
7566f3e57acSmx 		    = NGE_SET;
7576f3e57acSmx 	/*
7586f3e57acSmx 	 * indicating the end of BDs
7596f3e57acSmx 	 */
76051fc88a8SWinson Wang - Sun Microsystems - Beijing China 	if (tfint)
76151fc88a8SWinson Wang - Sun Microsystems - Beijing China 		hw_sbd_p->control_status.control_sum_bits.inten = NGE_SET;
7626f3e57acSmx 	if (end)
7636f3e57acSmx 		hw_sbd_p->control_status.control_sum_bits.end = NGE_SET;
7646f3e57acSmx 
7656f3e57acSmx 	membar_producer();
7666f3e57acSmx 
7676f3e57acSmx 	/* pass desc to HW */
7686f3e57acSmx 	hw_sbd_p->control_status.control_sum_bits.own = NGE_SET;
7696f3e57acSmx }
7706f3e57acSmx 
7716f3e57acSmx void
nge_sum_txd_fill(void * hwdesc,const ddi_dma_cookie_t * cookie,size_t length,uint32_t sum_flag,boolean_t end,boolean_t tfint)7726f3e57acSmx nge_sum_txd_fill(void *hwdesc, const ddi_dma_cookie_t *cookie,
77351fc88a8SWinson Wang - Sun Microsystems - Beijing China 	size_t length, uint32_t sum_flag, boolean_t end, boolean_t tfint)
7746f3e57acSmx {
7756f3e57acSmx 	sum_tx_bd * hw_sbd_p = hwdesc;
7766f3e57acSmx 
7776f3e57acSmx 	hw_sbd_p->host_buf_addr = cookie->dmac_address;
7786f3e57acSmx 
7796f3e57acSmx 	/*
7806f3e57acSmx 	 * Setting the length of the packet
7816f3e57acSmx 	 * Note: the length filled in the part should be
7826f3e57acSmx 	 * the original length subtract 1;
7836f3e57acSmx 	 */
7846f3e57acSmx 
7856f3e57acSmx 	hw_sbd_p->control_status.control_sum_bits.bcnt = length - 1;
7866f3e57acSmx 
7876f3e57acSmx 	/* setting ip checksum */
7886f3e57acSmx 	if (sum_flag & HCK_IPV4_HDRCKSUM)
7896f3e57acSmx 		hw_sbd_p->control_status.control_sum_bits.ip_hsum
7906f3e57acSmx 		    = NGE_SET;
7916f3e57acSmx 	/* setting tcp checksum */
7926f3e57acSmx 	if (sum_flag & HCK_FULLCKSUM)
7936f3e57acSmx 		hw_sbd_p->control_status.control_sum_bits.tcp_hsum
7946f3e57acSmx 		    = NGE_SET;
7956f3e57acSmx 	/*
7966f3e57acSmx 	 * indicating the end of BDs
7976f3e57acSmx 	 */
79851fc88a8SWinson Wang - Sun Microsystems - Beijing China 	if (tfint)
79951fc88a8SWinson Wang - Sun Microsystems - Beijing China 		hw_sbd_p->control_status.control_sum_bits.inten = NGE_SET;
8006f3e57acSmx 	if (end)
8016f3e57acSmx 		hw_sbd_p->control_status.control_sum_bits.end = NGE_SET;
8026f3e57acSmx 
8036f3e57acSmx 	membar_producer();
8046f3e57acSmx 
8056f3e57acSmx 	/* pass desc to HW */
8066f3e57acSmx 	hw_sbd_p->control_status.control_sum_bits.own = NGE_SET;
8076f3e57acSmx }
808