Home | History | Annotate | Download | only in nge
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include "nge.h"
     28 
     29 #define	TXD_OWN		0x80000000
     30 #define	TXD_ERR		0x40000000
     31 #define	TXD_END		0x20000000
     32 #define	TXD_BCNT_MSK	0x00003FFF
     33 
     34 
     35 #undef	NGE_DBG
     36 #define	NGE_DBG		NGE_DBG_SEND
     37 
     38 #define	NGE_TXSWD_RECYCLE(sd)	{\
     39 					(sd)->mp = NULL; \
     40 					(sd)->frags = 0; \
     41 					(sd)->mp_hndl.head = NULL; \
     42 					(sd)->mp_hndl.tail = NULL; \
     43 					(sd)->flags = HOST_OWN; \
     44 				}
     45 
     46 
     47 static size_t nge_tx_dmah_pop(nge_dmah_list_t *, nge_dmah_list_t *, size_t);
     48 static void nge_tx_dmah_push(nge_dmah_list_t *, nge_dmah_list_t *);
     49 
     50 
     51 void nge_tx_recycle_all(nge_t *ngep);
     52 #pragma	no_inline(nge_tx_recycle_all)
     53 
     54 void
     55 nge_tx_recycle_all(nge_t *ngep)
     56 {
     57 	send_ring_t *srp;
     58 	sw_tx_sbd_t *ssbdp;
     59 	nge_dmah_node_t	*dmah;
     60 	uint32_t slot;
     61 	uint32_t nslots;
     62 
     63 	srp = ngep->send;
     64 	nslots = srp->desc.nslots;
     65 
     66 	for (slot = 0; slot < nslots; ++slot) {
     67 
     68 		ssbdp = srp->sw_sbds + slot;
     69 
     70 		DMA_ZERO(ssbdp->desc);
     71 
     72 		if (ssbdp->mp != NULL)	{
     73 
     74 			for (dmah = ssbdp->mp_hndl.head; dmah != NULL;
     75 			    dmah = dmah->next)
     76 				(void) ddi_dma_unbind_handle(dmah->hndl);
     77 
     78 			freemsg(ssbdp->mp);
     79 		}
     80 
     81 		NGE_TXSWD_RECYCLE(ssbdp);
     82 	}
     83 	if (ngep->nge_mac_state == NGE_MAC_STARTED &&
     84 	    ngep->resched_needed == 1) {
     85 			ngep->resched_needed = 0;
     86 			mac_tx_update(ngep->mh);
     87 	}
     88 
     89 }
     90 
     91 static size_t
     92 nge_tx_dmah_pop(nge_dmah_list_t *src, nge_dmah_list_t *dst, size_t num)
     93 {
     94 	nge_dmah_node_t	*node;
     95 
     96 	for (node = src->head; node != NULL && --num != 0; node = node->next)
     97 		;
     98 
     99 	if (num == 0)	{
    100 
    101 		dst->head = src->head;
    102 		dst->tail = node;
    103 
    104 		if ((src->head = node->next) == NULL)
    105 			src->tail = NULL;
    106 
    107 		node->next = NULL;
    108 	}
    109 
    110 	return (num);
    111 }
    112 
    113 static void
    114 nge_tx_dmah_push(nge_dmah_list_t *src, nge_dmah_list_t *dst)
    115 {
    116 	if (dst->tail != NULL)
    117 		dst->tail->next = src->head;
    118 	else
    119 		dst->head = src->head;
    120 
    121 	dst->tail = src->tail;
    122 }
    123 
    124 static void
    125 nge_tx_desc_sync(nge_t *ngep, uint32_t start_index, uint32_t bds, uint_t type)
    126 {
    127 	send_ring_t *srp = ngep->send;
    128 	const size_t txd_size = ngep->desc_attr.txd_size;
    129 	const uint64_t end = srp->desc.nslots * txd_size;
    130 	uint64_t start;
    131 	uint64_t num;
    132 
    133 	start = start_index * txd_size;
    134 	num = bds * txd_size;
    135 
    136 	if (start + num <= end)
    137 		(void) ddi_dma_sync(srp->desc.dma_hdl, start, num, type);
    138 	else	{
    139 
    140 		(void) ddi_dma_sync(srp->desc.dma_hdl, start, 0, type);
    141 		(void) ddi_dma_sync(srp->desc.dma_hdl, 0, start + num - end,
    142 		    type);
    143 	}
    144 }
    145 
    146 /*
    147  * Reclaim the resource after tx's completion
    148  */
    149 void
    150 nge_tx_recycle(nge_t *ngep, boolean_t is_intr)
    151 {
    152 	int resched;
    153 	uint32_t stflg;
    154 	uint32_t free;
    155 	uint32_t slot;
    156 	uint32_t used;
    157 	uint32_t next;
    158 	uint32_t nslots;
    159 	mblk_t *mp;
    160 	sw_tx_sbd_t *ssbdp;
    161 	void *hw_sbd_p;
    162 	send_ring_t *srp;
    163 	nge_dmah_node_t *dme;
    164 	nge_dmah_list_t dmah;
    165 
    166 	srp = ngep->send;
    167 
    168 	if (is_intr) {
    169 		if (mutex_tryenter(srp->tc_lock) == 0)
    170 			return;
    171 	} else
    172 		mutex_enter(srp->tc_lock);
    173 	mutex_enter(srp->tx_lock);
    174 
    175 	next = srp->tx_next;
    176 	used = srp->tx_flow;
    177 	free = srp->tx_free;
    178 
    179 	mutex_exit(srp->tx_lock);
    180 
    181 	slot = srp->tc_next;
    182 	nslots = srp->desc.nslots;
    183 
    184 	used = nslots - free - used;
    185 
    186 	ASSERT(slot == NEXT_INDEX(next, free, nslots));
    187 	if (used == 0) {
    188 		ngep->watchdog = 0;
    189 		mutex_exit(srp->tc_lock);
    190 		return;
    191 	}
    192 
    193 	if (used > srp->tx_hwmark && ngep->resched_needed == 0)
    194 		used = srp->tx_hwmark;
    195 
    196 	nge_tx_desc_sync(ngep, slot, used, DDI_DMA_SYNC_FORKERNEL);
    197 
    198 	/*
    199 	 * Look through the send ring by bd's status part
    200 	 * to find all the bds which has been transmitted sucessfully
    201 	 * then reclaim all resouces associated with these bds
    202 	 */
    203 
    204 	mp = NULL;
    205 	dmah.head = NULL;
    206 	dmah.tail = NULL;
    207 
    208 	for (free = 0; used-- != 0; slot = NEXT(slot, nslots), ++free)	{
    209 
    210 		ssbdp = &srp->sw_sbds[slot];
    211 		hw_sbd_p = DMA_VPTR(ssbdp->desc);
    212 
    213 		if (ssbdp->flags == HOST_OWN)
    214 			break;
    215 		stflg = ngep->desc_attr.txd_check(hw_sbd_p);
    216 		if ((stflg & TXD_OWN) != 0)
    217 			break;
    218 		DMA_ZERO(ssbdp->desc);
    219 		if (ssbdp->mp != NULL)	{
    220 			ssbdp->mp->b_next = mp;
    221 			mp = ssbdp->mp;
    222 
    223 			if (ssbdp->mp_hndl.head != NULL)
    224 				nge_tx_dmah_push(&ssbdp->mp_hndl, &dmah);
    225 		}
    226 
    227 		NGE_TXSWD_RECYCLE(ssbdp);
    228 	}
    229 
    230 	/*
    231 	 * We're about to release one or more places :-)
    232 	 * These ASSERTions check that our invariants still hold:
    233 	 * there must always be at least one free place
    234 	 * at this point, there must be at least one place NOT free
    235 	 * we're not about to free more places than were claimed!
    236 	 */
    237 
    238 	if (free == 0) {
    239 		mutex_exit(srp->tc_lock);
    240 		return;
    241 	}
    242 
    243 	mutex_enter(srp->tx_lock);
    244 
    245 	srp->tx_free += free;
    246 	ngep->watchdog = (srp->desc.nslots - srp->tx_free != 0);
    247 
    248 	srp->tc_next = slot;
    249 
    250 	ASSERT(srp->tx_free <= nslots);
    251 	ASSERT(srp->tc_next == NEXT_INDEX(srp->tx_next, srp->tx_free, nslots));
    252 
    253 	resched = (ngep->resched_needed != 0 && srp->tx_hwmark <= srp->tx_free);
    254 
    255 	mutex_exit(srp->tx_lock);
    256 	mutex_exit(srp->tc_lock);
    257 
    258 	/* unbind/free mblks */
    259 
    260 	for (dme = dmah.head; dme != NULL; dme = dme->next)
    261 		(void) ddi_dma_unbind_handle(dme->hndl);
    262 	if (dmah.head != NULL) {
    263 		mutex_enter(&srp->dmah_lock);
    264 		nge_tx_dmah_push(&dmah, &srp->dmah_free);
    265 		mutex_exit(&srp->dmah_lock);
    266 	}
    267 	freemsgchain(mp);
    268 
    269 	/*
    270 	 * up to this place, we maybe have reclaim some resouce
    271 	 * if there is a requirement to report to gld, report this.
    272 	 */
    273 
    274 	if (resched)
    275 		(void) ddi_intr_trigger_softint(ngep->resched_hdl, NULL);
    276 }
    277 
    278 static uint32_t
    279 nge_tx_alloc(nge_t *ngep, uint32_t num)
    280 {
    281 	uint32_t start;
    282 	send_ring_t *srp;
    283 
    284 	start = (uint32_t)-1;
    285 	srp = ngep->send;
    286 
    287 	mutex_enter(srp->tx_lock);
    288 
    289 	if (srp->tx_free < srp->tx_lwmark)	{
    290 
    291 		mutex_exit(srp->tx_lock);
    292 		nge_tx_recycle(ngep, B_FALSE);
    293 		mutex_enter(srp->tx_lock);
    294 	}
    295 
    296 	if (srp->tx_free >= num)	{
    297 
    298 		start = srp->tx_next;
    299 
    300 		srp->tx_next = NEXT_INDEX(start, num, srp->desc.nslots);
    301 		srp->tx_free -= num;
    302 		srp->tx_flow += num;
    303 	}
    304 
    305 	mutex_exit(srp->tx_lock);
    306 	return (start);
    307 }
    308 
    309 static void
    310 nge_tx_start(nge_t *ngep, uint32_t slotnum)
    311 {
    312 	nge_mode_cntl mode_cntl;
    313 	send_ring_t *srp;
    314 
    315 	srp = ngep->send;
    316 
    317 	/*
    318 	 * Because there can be multiple concurrent threads in
    319 	 * transit through this code, we only want to notify the
    320 	 * hardware once the last one is departing ...
    321 	 */
    322 
    323 	mutex_enter(srp->tx_lock);
    324 
    325 	srp->tx_flow -= slotnum;
    326 	if (srp->tx_flow == 0) {
    327 
    328 		/*
    329 		 * Bump the watchdog counter, thus guaranteeing that it's
    330 		 * nonzero (watchdog activated).  Note that non-synchonised
    331 		 * access here means we may race with the reclaim() code
    332 		 * above, but the outcome will be harmless.  At worst, the
    333 		 * counter may not get reset on a partial reclaim; but the
    334 		 * large trigger threshold makes false positives unlikely
    335 		 */
    336 		if (ngep->watchdog == 0)
    337 			ngep->watchdog = 1;
    338 
    339 		mode_cntl.mode_val = nge_reg_get32(ngep, NGE_MODE_CNTL);
    340 		mode_cntl.mode_bits.txdm = NGE_SET;
    341 		mode_cntl.mode_bits.tx_rcom_en = NGE_SET;
    342 		nge_reg_put32(ngep, NGE_MODE_CNTL, mode_cntl.mode_val);
    343 	}
    344 	mutex_exit(srp->tx_lock);
    345 }
    346 
    347 static enum send_status
    348 nge_send_copy(nge_t *ngep, mblk_t *mp, send_ring_t *srp);
    349 #pragma	inline(nge_send_copy)
    350 
    351 static enum send_status
    352 nge_send_copy(nge_t *ngep, mblk_t *mp, send_ring_t *srp)
    353 {
    354 	size_t totlen;
    355 	size_t mblen;
    356 	uint32_t flags;
    357 	uint32_t bds;
    358 	uint32_t start_index;
    359 	char *txb;
    360 	mblk_t *bp;
    361 	void *hw_sbd_p;
    362 	sw_tx_sbd_t *ssbdp;
    363 	boolean_t tfint;
    364 
    365 	hcksum_retrieve(mp, NULL, NULL, NULL, NULL,
    366 	    NULL, NULL, &flags);
    367 	bds = 0x1;
    368 
    369 	if ((uint32_t)-1 == (start_index = nge_tx_alloc(ngep, bds)))
    370 		return (SEND_COPY_FAIL);
    371 
    372 	ASSERT(start_index < srp->desc.nslots);
    373 
    374 	/*
    375 	 * up to this point, there's nothing that can fail,
    376 	 * so we can go straight to claiming our
    377 	 * already-reserved place son the train.
    378 	 *
    379 	 * This is the point of no return!
    380 	 */
    381 
    382 	tfint = ((start_index % ngep->tfint_threshold) == 0);
    383 	bp = mp;
    384 	totlen = 0;
    385 	ssbdp = &srp->sw_sbds[start_index];
    386 	ASSERT(ssbdp->flags == HOST_OWN);
    387 
    388 	txb = DMA_VPTR(ssbdp->pbuf);
    389 	totlen = 0;
    390 	for (; bp != NULL; bp = bp->b_cont) {
    391 		if ((mblen = MBLKL(bp)) == 0)
    392 			continue;
    393 		if ((totlen += mblen) <= ngep->max_sdu) {
    394 			bcopy(bp->b_rptr, txb, mblen);
    395 			txb += mblen;
    396 		}
    397 	}
    398 
    399 	DMA_SYNC(ssbdp->pbuf, DDI_DMA_SYNC_FORDEV);
    400 
    401 	/* Fill & sync hw desc */
    402 
    403 	hw_sbd_p = DMA_VPTR(ssbdp->desc);
    404 
    405 	ngep->desc_attr.txd_fill(hw_sbd_p, &ssbdp->pbuf.cookie, totlen,
    406 	    flags, B_TRUE, tfint);
    407 	nge_tx_desc_sync(ngep, start_index, bds, DDI_DMA_SYNC_FORDEV);
    408 
    409 	ssbdp->flags = CONTROLER_OWN;
    410 
    411 	nge_tx_start(ngep, bds);
    412 
    413 	/*
    414 	 * The return status indicates that the message can be freed
    415 	 * right away, as we've already copied the contents ...
    416 	 */
    417 
    418 	freemsg(mp);
    419 	return (SEND_COPY_SUCESS);
    420 }
    421 
    422 /*
    423  * static enum send_status
    424  * nge_send_mapped(nge_t *ngep, mblk_t *mp, size_t fragno);
    425  * #pragma	inline(nge_send_mapped)
    426  */
    427 
    428 static enum send_status
    429 nge_send_mapped(nge_t *ngep, mblk_t *mp, size_t fragno)
    430 {
    431 	int err;
    432 	boolean_t end;
    433 	uint32_t i;
    434 	uint32_t j;
    435 	uint32_t ncookies;
    436 	uint32_t slot;
    437 	uint32_t nslots;
    438 	uint32_t mblen;
    439 	uint32_t flags;
    440 	uint32_t start_index;
    441 	uint32_t end_index;
    442 	mblk_t *bp;
    443 	void *hw_sbd_p;
    444 	send_ring_t *srp;
    445 	nge_dmah_node_t *dmah;
    446 	nge_dmah_node_t	*dmer;
    447 	nge_dmah_list_t dmah_list;
    448 	ddi_dma_cookie_t cookie[NGE_MAX_COOKIES * NGE_MAP_FRAGS];
    449 	boolean_t tfint;
    450 
    451 	srp = ngep->send;
    452 	nslots = srp->desc.nslots;
    453 
    454 	mutex_enter(&srp->dmah_lock);
    455 	err = nge_tx_dmah_pop(&srp->dmah_free, &dmah_list, fragno);
    456 	mutex_exit(&srp->dmah_lock);
    457 
    458 	if (err != 0)	{
    459 
    460 		return (SEND_MAP_FAIL);
    461 	}
    462 
    463 	/*
    464 	 * Pre-scan the message chain, noting the total number of bytes,
    465 	 * the number of fragments by pre-doing dma addr bind
    466 	 * if the fragment is larger than NGE_COPY_SIZE.
    467 	 * This way has the following advantages:
    468 	 * 1. Acquire the detailed information of resouce
    469 	 *	need to send the message
    470 	 *
    471 	 * 2. If can not pre-apply enough resouce, fails  at once
    472 	 *	and the driver will chose copy way to send out the
    473 	 *	message
    474 	 */
    475 
    476 	slot = 0;
    477 	dmah = dmah_list.head;
    478 
    479 	hcksum_retrieve(mp, NULL, NULL, NULL, NULL, NULL, NULL, &flags);
    480 
    481 	for (bp = mp; bp != NULL; bp = bp->b_cont)	{
    482 
    483 		mblen = MBLKL(bp);
    484 		if (mblen == 0)
    485 			continue;
    486 
    487 		err = ddi_dma_addr_bind_handle(dmah->hndl,
    488 		    NULL, (caddr_t)bp->b_rptr, mblen,
    489 		    DDI_DMA_STREAMING | DDI_DMA_WRITE,
    490 		    DDI_DMA_DONTWAIT, NULL, cookie + slot, &ncookies);
    491 
    492 		/*
    493 		 * If there can not map successfully, it is uncessary
    494 		 * sending the message by map way. Sending the message
    495 		 * by copy way.
    496 		 *
    497 		 * By referring to intel's suggestion, it is better
    498 		 * the number of cookies should be less than 4.
    499 		 */
    500 		if (err != DDI_DMA_MAPPED || ncookies > NGE_MAX_COOKIES) {
    501 			NGE_DEBUG(("err(%x) map tx bulk fails"
    502 			    " cookie(%x), ncookies(%x)",
    503 			    err, cookie[slot].dmac_laddress, ncookies));
    504 			goto map_fail;
    505 		}
    506 
    507 		/*
    508 		 * Check How many bds a cookie will consume
    509 		 */
    510 		for (end_index = slot + ncookies;
    511 		    ++slot != end_index;
    512 		    ddi_dma_nextcookie(dmah->hndl, cookie + slot))
    513 			;
    514 
    515 		dmah = dmah->next;
    516 	}
    517 
    518 	/*
    519 	 * Now allocate tx descriptors and fill them
    520 	 * IMPORTANT:
    521 	 *	Up to the point where it claims a place, It is impossibel
    522 	 * 	to fail.
    523 	 *
    524 	 * In this version, there's no setup to be done here, and there's
    525 	 * nothing that can fail, so we can go straight to claiming our
    526 	 * already-reserved places on the train.
    527 	 *
    528 	 * This is the point of no return!
    529 	 */
    530 
    531 
    532 	if ((uint32_t)-1 == (start_index = nge_tx_alloc(ngep, slot)))
    533 		goto map_fail;
    534 
    535 	ASSERT(start_index < nslots);
    536 
    537 	/* fill&sync hw desc, going in reverse order */
    538 
    539 	end = B_TRUE;
    540 	end_index = NEXT_INDEX(start_index, slot - 1, nslots);
    541 
    542 	for (i = slot - 1, j = end_index; start_index - j != 0;
    543 	    j = PREV(j, nslots), --i)	{
    544 
    545 		tfint = ((j % ngep->tfint_threshold) == 0);
    546 		hw_sbd_p = DMA_VPTR(srp->sw_sbds[j].desc);
    547 		ngep->desc_attr.txd_fill(hw_sbd_p, cookie + i,
    548 		    cookie[i].dmac_size, 0, end, tfint);
    549 
    550 		end = B_FALSE;
    551 	}
    552 
    553 	hw_sbd_p = DMA_VPTR(srp->sw_sbds[j].desc);
    554 	tfint = ((j % ngep->tfint_threshold) == 0);
    555 	ngep->desc_attr.txd_fill(hw_sbd_p, cookie + i, cookie[i].dmac_size,
    556 	    flags, end, tfint);
    557 
    558 	nge_tx_desc_sync(ngep, start_index, slot, DDI_DMA_SYNC_FORDEV);
    559 
    560 	/* fill sw desc */
    561 
    562 	for (j = start_index; end_index - j != 0; j = NEXT(j, nslots)) {
    563 
    564 		srp->sw_sbds[j].flags = CONTROLER_OWN;
    565 	}
    566 
    567 	srp->sw_sbds[j].mp = mp;
    568 	srp->sw_sbds[j].mp_hndl = dmah_list;
    569 	srp->sw_sbds[j].frags = (uint32_t)fragno;
    570 	srp->sw_sbds[j].flags = CONTROLER_OWN;
    571 
    572 	nge_tx_start(ngep, slot);
    573 
    574 	/*
    575 	 * The return status indicates that the message can not be freed
    576 	 * right away, until we can make assure the message has been sent
    577 	 * out sucessfully.
    578 	 */
    579 	return (SEND_MAP_SUCCESS);
    580 
    581 map_fail:
    582 	for (dmer = dmah_list.head; dmah - dmer != 0; dmer = dmer->next)
    583 		(void) ddi_dma_unbind_handle(dmer->hndl);
    584 
    585 	mutex_enter(&srp->dmah_lock);
    586 	nge_tx_dmah_push(&dmah_list, &srp->dmah_free);
    587 	mutex_exit(&srp->dmah_lock);
    588 
    589 	return (SEND_MAP_FAIL);
    590 }
    591 
    592 static boolean_t
    593 nge_send(nge_t *ngep, mblk_t *mp)
    594 {
    595 	mblk_t *bp;
    596 	send_ring_t *srp;
    597 	enum send_status status;
    598 	uint32_t mblen = 0;
    599 	uint32_t frags = 0;
    600 	nge_statistics_t *nstp = &ngep->statistics;
    601 	nge_sw_statistics_t *sw_stp = &nstp->sw_statistics;
    602 
    603 	ASSERT(mp != NULL);
    604 	ASSERT(ngep->nge_mac_state == NGE_MAC_STARTED);
    605 
    606 	srp = ngep->send;
    607 	/*
    608 	 * 1.Check the number of the fragments of the messages
    609 	 * If the total number is larger than 3,
    610 	 * Chose copy way
    611 	 *
    612 	 * 2. Check the length of the message whether is larger than
    613 	 * NGE_TX_COPY_SIZE, if so, choose the map way.
    614 	 */
    615 	for (frags = 0, bp = mp; bp != NULL; bp = bp->b_cont) {
    616 		if (MBLKL(bp) == 0)
    617 			continue;
    618 		frags++;
    619 		mblen += MBLKL(bp);
    620 	}
    621 	if (mblen > (ngep->max_sdu) || mblen == 0) {
    622 		freemsg(mp);
    623 		return (B_TRUE);
    624 	}
    625 	if ((mblen > ngep->param_txbcopy_threshold) &&
    626 	    (frags <= NGE_MAP_FRAGS) &&
    627 	    (srp->tx_free > frags * NGE_MAX_COOKIES)) {
    628 		status = nge_send_mapped(ngep, mp, frags);
    629 		if (status == SEND_MAP_FAIL)
    630 			status = nge_send_copy(ngep, mp, srp);
    631 	} else {
    632 		status = nge_send_copy(ngep, mp, srp);
    633 	}
    634 	if (status == SEND_COPY_FAIL) {
    635 		nge_tx_recycle(ngep, B_FALSE);
    636 		status = nge_send_copy(ngep, mp, srp);
    637 		if (status == SEND_COPY_FAIL) {
    638 			ngep->resched_needed = 1;
    639 			NGE_DEBUG(("nge_send: send fail!"));
    640 			return (B_FALSE);
    641 		}
    642 	}
    643 	/* Update the software statistics */
    644 	sw_stp->obytes += mblen + ETHERFCSL;
    645 	sw_stp->xmit_count ++;
    646 
    647 	return (B_TRUE);
    648 }
    649 
    650 /*
    651  * nge_m_tx : Send a chain of packets.
    652  */
    653 mblk_t *
    654 nge_m_tx(void *arg, mblk_t *mp)
    655 {
    656 	nge_t *ngep = arg;
    657 	mblk_t *next;
    658 
    659 	rw_enter(ngep->rwlock, RW_READER);
    660 	ASSERT(mp != NULL);
    661 	if (ngep->nge_chip_state != NGE_CHIP_RUNNING) {
    662 		freemsgchain(mp);
    663 		mp = NULL;
    664 	}
    665 	while (mp != NULL) {
    666 		next = mp->b_next;
    667 		mp->b_next = NULL;
    668 
    669 		if (!nge_send(ngep, mp)) {
    670 			mp->b_next = next;
    671 			break;
    672 		}
    673 
    674 		mp = next;
    675 	}
    676 	rw_exit(ngep->rwlock);
    677 
    678 	return (mp);
    679 }
    680 
    681 /* ARGSUSED */
    682 uint_t
    683 nge_reschedule(caddr_t args1, caddr_t args2)
    684 {
    685 	nge_t *ngep;
    686 	uint_t rslt;
    687 
    688 	ngep = (nge_t *)args1;
    689 	rslt = DDI_INTR_UNCLAIMED;
    690 
    691 	/*
    692 	 * when softintr is trigged, checking whether this
    693 	 * is caused by our expected interrupt
    694 	 */
    695 	if (ngep->nge_mac_state == NGE_MAC_STARTED &&
    696 	    ngep->resched_needed == 1) {
    697 		ngep->resched_needed = 0;
    698 		++ngep->statistics.sw_statistics.tx_resched;
    699 		mac_tx_update(ngep->mh);
    700 		rslt = DDI_INTR_CLAIMED;
    701 	}
    702 	return (rslt);
    703 }
    704 
    705 uint32_t
    706 nge_hot_txd_check(const void *hwd)
    707 {
    708 	uint32_t err_flag;
    709 	const hot_tx_bd * htbdp;
    710 
    711 	htbdp = hwd;
    712 	err_flag = htbdp->control_status.cntl_val;
    713 	return (err_flag);
    714 }
    715 
    716 uint32_t
    717 nge_sum_txd_check(const void *hwd)
    718 {
    719 	uint32_t err_flag;
    720 	const sum_tx_bd * htbdp;
    721 
    722 	htbdp = hwd;
    723 	err_flag = htbdp->control_status.cntl_val;
    724 	return (err_flag);
    725 }
    726 
    727 
    728 /*
    729  * Filling the contents of Tx's data descriptor
    730  * before transmitting.
    731  */
    732 
    733 void
    734 nge_hot_txd_fill(void *hwdesc, const ddi_dma_cookie_t *cookie,
    735 	size_t length, uint32_t sum_flag, boolean_t end, boolean_t tfint)
    736 {
    737 	hot_tx_bd * hw_sbd_p = hwdesc;
    738 
    739 	hw_sbd_p->host_buf_addr_hi = cookie->dmac_laddress >> 32;
    740 	hw_sbd_p->host_buf_addr_lo = cookie->dmac_laddress;
    741 
    742 	/*
    743 	 * Setting the length of the packet
    744 	 * Note: the length filled in the part should be
    745 	 * the original length subtract 1;
    746 	 */
    747 
    748 	hw_sbd_p->control_status.control_sum_bits.bcnt = length - 1;
    749 
    750 	/* setting ip checksum */
    751 	if (sum_flag & HCK_IPV4_HDRCKSUM)
    752 		hw_sbd_p->control_status.control_sum_bits.ip_hsum
    753 		    = NGE_SET;
    754 	/* setting tcp checksum */
    755 	if (sum_flag & HCK_FULLCKSUM)
    756 		hw_sbd_p->control_status.control_sum_bits.tcp_hsum
    757 		    = NGE_SET;
    758 	/*
    759 	 * indicating the end of BDs
    760 	 */
    761 	if (tfint)
    762 		hw_sbd_p->control_status.control_sum_bits.inten = NGE_SET;
    763 	if (end)
    764 		hw_sbd_p->control_status.control_sum_bits.end = NGE_SET;
    765 
    766 	membar_producer();
    767 
    768 	/* pass desc to HW */
    769 	hw_sbd_p->control_status.control_sum_bits.own = NGE_SET;
    770 }
    771 
    772 void
    773 nge_sum_txd_fill(void *hwdesc, const ddi_dma_cookie_t *cookie,
    774 	size_t length, uint32_t sum_flag, boolean_t end, boolean_t tfint)
    775 {
    776 	sum_tx_bd * hw_sbd_p = hwdesc;
    777 
    778 	hw_sbd_p->host_buf_addr = cookie->dmac_address;
    779 
    780 	/*
    781 	 * Setting the length of the packet
    782 	 * Note: the length filled in the part should be
    783 	 * the original length subtract 1;
    784 	 */
    785 
    786 	hw_sbd_p->control_status.control_sum_bits.bcnt = length - 1;
    787 
    788 	/* setting ip checksum */
    789 	if (sum_flag & HCK_IPV4_HDRCKSUM)
    790 		hw_sbd_p->control_status.control_sum_bits.ip_hsum
    791 		    = NGE_SET;
    792 	/* setting tcp checksum */
    793 	if (sum_flag & HCK_FULLCKSUM)
    794 		hw_sbd_p->control_status.control_sum_bits.tcp_hsum
    795 		    = NGE_SET;
    796 	/*
    797 	 * indicating the end of BDs
    798 	 */
    799 	if (tfint)
    800 		hw_sbd_p->control_status.control_sum_bits.inten = NGE_SET;
    801 	if (end)
    802 		hw_sbd_p->control_status.control_sum_bits.end = NGE_SET;
    803 
    804 	membar_producer();
    805 
    806 	/* pass desc to HW */
    807 	hw_sbd_p->control_status.control_sum_bits.own = NGE_SET;
    808 }
    809