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 2010 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
47static size_t nge_tx_dmah_pop(nge_dmah_list_t *, nge_dmah_list_t *, size_t);
48static void nge_tx_dmah_push(nge_dmah_list_t *, nge_dmah_list_t *);
49
50
51void nge_tx_recycle_all(nge_t *ngep);
52#pragma	no_inline(nge_tx_recycle_all)
53
54void
55nge_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
91static size_t
92nge_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
113static void
114nge_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
124static void
125nge_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 */
149void
150nge_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
278static uint32_t
279nge_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
309static void
310nge_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
347static enum send_status
348nge_send_copy(nge_t *ngep, mblk_t *mp, send_ring_t *srp);
349#pragma	inline(nge_send_copy)
350
351static enum send_status
352nge_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	mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &flags);
366	bds = 0x1;
367
368	if ((uint32_t)-1 == (start_index = nge_tx_alloc(ngep, bds)))
369		return (SEND_COPY_FAIL);
370
371	ASSERT(start_index < srp->desc.nslots);
372
373	/*
374	 * up to this point, there's nothing that can fail,
375	 * so we can go straight to claiming our
376	 * already-reserved place son the train.
377	 *
378	 * This is the point of no return!
379	 */
380
381	tfint = ((start_index % ngep->tfint_threshold) == 0);
382	bp = mp;
383	totlen = 0;
384	ssbdp = &srp->sw_sbds[start_index];
385	ASSERT(ssbdp->flags == HOST_OWN);
386
387	txb = DMA_VPTR(ssbdp->pbuf);
388	totlen = 0;
389	for (; bp != NULL; bp = bp->b_cont) {
390		if ((mblen = MBLKL(bp)) == 0)
391			continue;
392		if ((totlen += mblen) <= ngep->max_sdu) {
393			bcopy(bp->b_rptr, txb, mblen);
394			txb += mblen;
395		}
396	}
397
398	DMA_SYNC(ssbdp->pbuf, DDI_DMA_SYNC_FORDEV);
399
400	/* Fill & sync hw desc */
401
402	hw_sbd_p = DMA_VPTR(ssbdp->desc);
403
404	ngep->desc_attr.txd_fill(hw_sbd_p, &ssbdp->pbuf.cookie, totlen,
405	    flags, B_TRUE, tfint);
406	nge_tx_desc_sync(ngep, start_index, bds, DDI_DMA_SYNC_FORDEV);
407
408	ssbdp->flags = CONTROLER_OWN;
409
410	nge_tx_start(ngep, bds);
411
412	/*
413	 * The return status indicates that the message can be freed
414	 * right away, as we've already copied the contents ...
415	 */
416
417	freemsg(mp);
418	return (SEND_COPY_SUCESS);
419}
420
421/*
422 * static enum send_status
423 * nge_send_mapped(nge_t *ngep, mblk_t *mp, size_t fragno);
424 * #pragma	inline(nge_send_mapped)
425 */
426
427static enum send_status
428nge_send_mapped(nge_t *ngep, mblk_t *mp, size_t fragno)
429{
430	int err;
431	boolean_t end;
432	uint32_t i;
433	uint32_t j;
434	uint32_t ncookies;
435	uint32_t slot;
436	uint32_t nslots;
437	uint32_t mblen;
438	uint32_t flags;
439	uint32_t start_index;
440	uint32_t end_index;
441	mblk_t *bp;
442	void *hw_sbd_p;
443	send_ring_t *srp;
444	nge_dmah_node_t *dmah;
445	nge_dmah_node_t	*dmer;
446	nge_dmah_list_t dmah_list;
447	ddi_dma_cookie_t cookie[NGE_MAX_COOKIES * NGE_MAP_FRAGS];
448	boolean_t tfint;
449
450	srp = ngep->send;
451	nslots = srp->desc.nslots;
452
453	mutex_enter(&srp->dmah_lock);
454	err = nge_tx_dmah_pop(&srp->dmah_free, &dmah_list, fragno);
455	mutex_exit(&srp->dmah_lock);
456
457	if (err != 0)	{
458
459		return (SEND_MAP_FAIL);
460	}
461
462	/*
463	 * Pre-scan the message chain, noting the total number of bytes,
464	 * the number of fragments by pre-doing dma addr bind
465	 * if the fragment is larger than NGE_COPY_SIZE.
466	 * This way has the following advantages:
467	 * 1. Acquire the detailed information of resouce
468	 *	need to send the message
469	 *
470	 * 2. If can not pre-apply enough resouce, fails  at once
471	 *	and the driver will chose copy way to send out the
472	 *	message
473	 */
474
475	slot = 0;
476	dmah = dmah_list.head;
477
478	mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &flags);
479
480	for (bp = mp; bp != NULL; bp = bp->b_cont)	{
481
482		mblen = MBLKL(bp);
483		if (mblen == 0)
484			continue;
485
486		err = ddi_dma_addr_bind_handle(dmah->hndl,
487		    NULL, (caddr_t)bp->b_rptr, mblen,
488		    DDI_DMA_STREAMING | DDI_DMA_WRITE,
489		    DDI_DMA_DONTWAIT, NULL, cookie + slot, &ncookies);
490
491		/*
492		 * If there can not map successfully, it is uncessary
493		 * sending the message by map way. Sending the message
494		 * by copy way.
495		 *
496		 * By referring to intel's suggestion, it is better
497		 * the number of cookies should be less than 4.
498		 */
499		if (err != DDI_DMA_MAPPED || ncookies > NGE_MAX_COOKIES) {
500			NGE_DEBUG(("err(%x) map tx bulk fails"
501			    " cookie(%x), ncookies(%x)",
502			    err, cookie[slot].dmac_laddress, ncookies));
503			goto map_fail;
504		}
505
506		/*
507		 * Check How many bds a cookie will consume
508		 */
509		for (end_index = slot + ncookies;
510		    ++slot != end_index;
511		    ddi_dma_nextcookie(dmah->hndl, cookie + slot))
512			;
513
514		dmah = dmah->next;
515	}
516
517	/*
518	 * Now allocate tx descriptors and fill them
519	 * IMPORTANT:
520	 *	Up to the point where it claims a place, It is impossibel
521	 * 	to fail.
522	 *
523	 * In this version, there's no setup to be done here, and there's
524	 * nothing that can fail, so we can go straight to claiming our
525	 * already-reserved places on the train.
526	 *
527	 * This is the point of no return!
528	 */
529
530
531	if ((uint32_t)-1 == (start_index = nge_tx_alloc(ngep, slot)))
532		goto map_fail;
533
534	ASSERT(start_index < nslots);
535
536	/* fill&sync hw desc, going in reverse order */
537
538	end = B_TRUE;
539	end_index = NEXT_INDEX(start_index, slot - 1, nslots);
540
541	for (i = slot - 1, j = end_index; start_index - j != 0;
542	    j = PREV(j, nslots), --i)	{
543
544		tfint = ((j % ngep->tfint_threshold) == 0);
545		hw_sbd_p = DMA_VPTR(srp->sw_sbds[j].desc);
546		ngep->desc_attr.txd_fill(hw_sbd_p, cookie + i,
547		    cookie[i].dmac_size, 0, end, tfint);
548
549		end = B_FALSE;
550	}
551
552	hw_sbd_p = DMA_VPTR(srp->sw_sbds[j].desc);
553	tfint = ((j % ngep->tfint_threshold) == 0);
554	ngep->desc_attr.txd_fill(hw_sbd_p, cookie + i, cookie[i].dmac_size,
555	    flags, end, tfint);
556
557	nge_tx_desc_sync(ngep, start_index, slot, DDI_DMA_SYNC_FORDEV);
558
559	/* fill sw desc */
560
561	for (j = start_index; end_index - j != 0; j = NEXT(j, nslots)) {
562
563		srp->sw_sbds[j].flags = CONTROLER_OWN;
564	}
565
566	srp->sw_sbds[j].mp = mp;
567	srp->sw_sbds[j].mp_hndl = dmah_list;
568	srp->sw_sbds[j].frags = (uint32_t)fragno;
569	srp->sw_sbds[j].flags = CONTROLER_OWN;
570
571	nge_tx_start(ngep, slot);
572
573	/*
574	 * The return status indicates that the message can not be freed
575	 * right away, until we can make assure the message has been sent
576	 * out sucessfully.
577	 */
578	return (SEND_MAP_SUCCESS);
579
580map_fail:
581	for (dmer = dmah_list.head; dmah - dmer != 0; dmer = dmer->next)
582		(void) ddi_dma_unbind_handle(dmer->hndl);
583
584	mutex_enter(&srp->dmah_lock);
585	nge_tx_dmah_push(&dmah_list, &srp->dmah_free);
586	mutex_exit(&srp->dmah_lock);
587
588	return (SEND_MAP_FAIL);
589}
590
591static boolean_t
592nge_send(nge_t *ngep, mblk_t *mp)
593{
594	mblk_t *bp;
595	send_ring_t *srp;
596	enum send_status status;
597	uint32_t mblen = 0;
598	uint32_t frags = 0;
599	nge_statistics_t *nstp = &ngep->statistics;
600	nge_sw_statistics_t *sw_stp = &nstp->sw_statistics;
601
602	ASSERT(mp != NULL);
603	ASSERT(ngep->nge_mac_state == NGE_MAC_STARTED);
604
605	srp = ngep->send;
606	/*
607	 * 1.Check the number of the fragments of the messages
608	 * If the total number is larger than 3,
609	 * Chose copy way
610	 *
611	 * 2. Check the length of the message whether is larger than
612	 * NGE_TX_COPY_SIZE, if so, choose the map way.
613	 */
614	for (frags = 0, bp = mp; bp != NULL; bp = bp->b_cont) {
615		if (MBLKL(bp) == 0)
616			continue;
617		frags++;
618		mblen += MBLKL(bp);
619	}
620	if (mblen > (ngep->max_sdu) || mblen == 0) {
621		freemsg(mp);
622		return (B_TRUE);
623	}
624	if ((mblen > ngep->param_txbcopy_threshold) &&
625	    (frags <= NGE_MAP_FRAGS) &&
626	    (srp->tx_free > frags * NGE_MAX_COOKIES)) {
627		status = nge_send_mapped(ngep, mp, frags);
628		if (status == SEND_MAP_FAIL)
629			status = nge_send_copy(ngep, mp, srp);
630	} else {
631		status = nge_send_copy(ngep, mp, srp);
632	}
633	if (status == SEND_COPY_FAIL) {
634		nge_tx_recycle(ngep, B_FALSE);
635		status = nge_send_copy(ngep, mp, srp);
636		if (status == SEND_COPY_FAIL) {
637			ngep->resched_needed = 1;
638			NGE_DEBUG(("nge_send: send fail!"));
639			return (B_FALSE);
640		}
641	}
642	/* Update the software statistics */
643	sw_stp->obytes += mblen + ETHERFCSL;
644	sw_stp->xmit_count ++;
645
646	return (B_TRUE);
647}
648
649/*
650 * nge_m_tx : Send a chain of packets.
651 */
652mblk_t *
653nge_m_tx(void *arg, mblk_t *mp)
654{
655	nge_t *ngep = arg;
656	mblk_t *next;
657
658	rw_enter(ngep->rwlock, RW_READER);
659	ASSERT(mp != NULL);
660	if (ngep->nge_chip_state != NGE_CHIP_RUNNING) {
661		freemsgchain(mp);
662		mp = NULL;
663	}
664	while (mp != NULL) {
665		next = mp->b_next;
666		mp->b_next = NULL;
667
668		if (!nge_send(ngep, mp)) {
669			mp->b_next = next;
670			break;
671		}
672
673		mp = next;
674	}
675	rw_exit(ngep->rwlock);
676
677	return (mp);
678}
679
680/* ARGSUSED */
681uint_t
682nge_reschedule(caddr_t args1, caddr_t args2)
683{
684	nge_t *ngep;
685	uint_t rslt;
686
687	ngep = (nge_t *)args1;
688	rslt = DDI_INTR_UNCLAIMED;
689
690	/*
691	 * when softintr is trigged, checking whether this
692	 * is caused by our expected interrupt
693	 */
694	if (ngep->nge_mac_state == NGE_MAC_STARTED &&
695	    ngep->resched_needed == 1) {
696		ngep->resched_needed = 0;
697		++ngep->statistics.sw_statistics.tx_resched;
698		mac_tx_update(ngep->mh);
699		rslt = DDI_INTR_CLAIMED;
700	}
701	return (rslt);
702}
703
704uint32_t
705nge_hot_txd_check(const void *hwd)
706{
707	uint32_t err_flag;
708	const hot_tx_bd * htbdp;
709
710	htbdp = hwd;
711	err_flag = htbdp->control_status.cntl_val;
712	return (err_flag);
713}
714
715uint32_t
716nge_sum_txd_check(const void *hwd)
717{
718	uint32_t err_flag;
719	const sum_tx_bd * htbdp;
720
721	htbdp = hwd;
722	err_flag = htbdp->control_status.cntl_val;
723	return (err_flag);
724}
725
726
727/*
728 * Filling the contents of Tx's data descriptor
729 * before transmitting.
730 */
731
732void
733nge_hot_txd_fill(void *hwdesc, const ddi_dma_cookie_t *cookie,
734	size_t length, uint32_t sum_flag, boolean_t end, boolean_t tfint)
735{
736	hot_tx_bd * hw_sbd_p = hwdesc;
737
738	hw_sbd_p->host_buf_addr_hi = cookie->dmac_laddress >> 32;
739	hw_sbd_p->host_buf_addr_lo = cookie->dmac_laddress;
740
741	/*
742	 * Setting the length of the packet
743	 * Note: the length filled in the part should be
744	 * the original length subtract 1;
745	 */
746
747	hw_sbd_p->control_status.control_sum_bits.bcnt = length - 1;
748
749	/* setting ip checksum */
750	if (sum_flag & HCK_IPV4_HDRCKSUM)
751		hw_sbd_p->control_status.control_sum_bits.ip_hsum
752		    = NGE_SET;
753	/* setting tcp checksum */
754	if (sum_flag & HCK_FULLCKSUM)
755		hw_sbd_p->control_status.control_sum_bits.tcp_hsum
756		    = NGE_SET;
757	/*
758	 * indicating the end of BDs
759	 */
760	if (tfint)
761		hw_sbd_p->control_status.control_sum_bits.inten = NGE_SET;
762	if (end)
763		hw_sbd_p->control_status.control_sum_bits.end = NGE_SET;
764
765	membar_producer();
766
767	/* pass desc to HW */
768	hw_sbd_p->control_status.control_sum_bits.own = NGE_SET;
769}
770
771void
772nge_sum_txd_fill(void *hwdesc, const ddi_dma_cookie_t *cookie,
773	size_t length, uint32_t sum_flag, boolean_t end, boolean_t tfint)
774{
775	sum_tx_bd * hw_sbd_p = hwdesc;
776
777	hw_sbd_p->host_buf_addr = cookie->dmac_address;
778
779	/*
780	 * Setting the length of the packet
781	 * Note: the length filled in the part should be
782	 * the original length subtract 1;
783	 */
784
785	hw_sbd_p->control_status.control_sum_bits.bcnt = length - 1;
786
787	/* setting ip checksum */
788	if (sum_flag & HCK_IPV4_HDRCKSUM)
789		hw_sbd_p->control_status.control_sum_bits.ip_hsum
790		    = NGE_SET;
791	/* setting tcp checksum */
792	if (sum_flag & HCK_FULLCKSUM)
793		hw_sbd_p->control_status.control_sum_bits.tcp_hsum
794		    = NGE_SET;
795	/*
796	 * indicating the end of BDs
797	 */
798	if (tfint)
799		hw_sbd_p->control_status.control_sum_bits.inten = NGE_SET;
800	if (end)
801		hw_sbd_p->control_status.control_sum_bits.end = NGE_SET;
802
803	membar_producer();
804
805	/* pass desc to HW */
806	hw_sbd_p->control_status.control_sum_bits.own = NGE_SET;
807}
808