xref: /onnv-gate/usr/src/uts/common/io/rge/rge_rxtx.c (revision 2760:38f12e308f6d)
1744Sgs150176 /*
2744Sgs150176  * CDDL HEADER START
3744Sgs150176  *
4744Sgs150176  * The contents of this file are subject to the terms of the
52311Sseb  * Common Development and Distribution License (the "License").
62311Sseb  * You may not use this file except in compliance with the License.
7744Sgs150176  *
8744Sgs150176  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9744Sgs150176  * or http://www.opensolaris.org/os/licensing.
10744Sgs150176  * See the License for the specific language governing permissions
11744Sgs150176  * and limitations under the License.
12744Sgs150176  *
13744Sgs150176  * When distributing Covered Code, include this CDDL HEADER in each
14744Sgs150176  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15744Sgs150176  * If applicable, add the following below this CDDL HEADER, with the
16744Sgs150176  * fields enclosed by brackets "[]" replaced with your own identifying
17744Sgs150176  * information: Portions Copyright [yyyy] [name of copyright owner]
18744Sgs150176  *
19744Sgs150176  * CDDL HEADER END
20744Sgs150176  */
21744Sgs150176 /*
222311Sseb  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23744Sgs150176  * Use is subject to license terms.
24744Sgs150176  */
25744Sgs150176 
26744Sgs150176 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27744Sgs150176 
28744Sgs150176 #include "rge.h"
29744Sgs150176 
30744Sgs150176 #define	U32TOPTR(x)	((void *)(uintptr_t)(uint32_t)(x))
31744Sgs150176 #define	PTRTOU32(x)	((uint32_t)(uintptr_t)(void *)(x))
32744Sgs150176 
33744Sgs150176 /*
34744Sgs150176  * ========== RX side routines ==========
35744Sgs150176  */
36744Sgs150176 
37744Sgs150176 #define	RGE_DBG		RGE_DBG_RECV	/* debug flag for this code	*/
38744Sgs150176 
39744Sgs150176 static uint32_t rge_atomic_reserve(uint32_t *count_p, uint32_t n);
40744Sgs150176 #pragma	inline(rge_atomic_reserve)
41744Sgs150176 
42744Sgs150176 static uint32_t
43744Sgs150176 rge_atomic_reserve(uint32_t *count_p, uint32_t n)
44744Sgs150176 {
45744Sgs150176 	uint32_t oldval;
46744Sgs150176 	uint32_t newval;
47744Sgs150176 
48744Sgs150176 	/* ATOMICALLY */
49744Sgs150176 	do {
50744Sgs150176 		oldval = *count_p;
51744Sgs150176 		newval = oldval - n;
52744Sgs150176 		if (oldval <= n)
53744Sgs150176 			return (0);		/* no resources left	*/
54744Sgs150176 	} while (cas32(count_p, oldval, newval) != oldval);
55744Sgs150176 
56744Sgs150176 	return (newval);
57744Sgs150176 }
58744Sgs150176 
59744Sgs150176 /*
60744Sgs150176  * Atomically increment a counter
61744Sgs150176  */
62744Sgs150176 static void rge_atomic_renounce(uint32_t *count_p, uint32_t n);
63744Sgs150176 #pragma	inline(rge_atomic_renounce)
64744Sgs150176 
65744Sgs150176 static void
66744Sgs150176 rge_atomic_renounce(uint32_t *count_p, uint32_t n)
67744Sgs150176 {
68744Sgs150176 	uint32_t oldval;
69744Sgs150176 	uint32_t newval;
70744Sgs150176 
71744Sgs150176 	/* ATOMICALLY */
72744Sgs150176 	do {
73744Sgs150176 		oldval = *count_p;
74744Sgs150176 		newval = oldval + n;
75744Sgs150176 	} while (cas32(count_p, oldval, newval) != oldval);
76744Sgs150176 }
77744Sgs150176 
78744Sgs150176 /*
79744Sgs150176  * Callback code invoked from STREAMs when the recv data buffer is free
80744Sgs150176  * for recycling.
81744Sgs150176  */
82744Sgs150176 void
83744Sgs150176 rge_rx_recycle(caddr_t arg)
84744Sgs150176 {
85744Sgs150176 	rge_t *rgep;
86744Sgs150176 	dma_buf_t *rx_buf;
872544Sgs150176 	sw_rbd_t *free_srbdp;
88744Sgs150176 	uint32_t slot_recy;
89744Sgs150176 
90744Sgs150176 	rx_buf = (dma_buf_t *)arg;
91744Sgs150176 	rgep = (rge_t *)rx_buf->private;
92744Sgs150176 
93744Sgs150176 	/*
942544Sgs150176 	 * In rge_unattach() and rge_attach(), this callback function will
952544Sgs150176 	 * also be called to free mp in rge_fini_rings() and rge_init_rings().
962544Sgs150176 	 * In such situation, we shouldn't do below desballoc(), otherwise,
97744Sgs150176 	 * there'll be memory leak.
98744Sgs150176 	 */
992544Sgs150176 	if (rgep->rge_mac_state == RGE_MAC_UNATTACH ||
1002544Sgs150176 	    rgep->rge_mac_state == RGE_MAC_ATTACH)
101744Sgs150176 		return;
102744Sgs150176 
103744Sgs150176 	/*
104744Sgs150176 	 * Recycle the data buffer again
105744Sgs150176 	 * and fill them in free ring
106744Sgs150176 	 */
107744Sgs150176 	rx_buf->mp = desballoc(DMA_VPTR(rx_buf->pbuf),
108744Sgs150176 	    rgep->rxbuf_size, 0, &rx_buf->rx_recycle);
109744Sgs150176 	if (rx_buf->mp == NULL) {
110744Sgs150176 		rge_problem(rgep, "rge_rx_recycle: desballoc() failed");
111744Sgs150176 		return;
112744Sgs150176 	}
113744Sgs150176 	mutex_enter(rgep->rc_lock);
114744Sgs150176 	slot_recy = rgep->rc_next;
1152544Sgs150176 	free_srbdp = &rgep->free_srbds[slot_recy];
1162544Sgs150176 
1172544Sgs150176 	ASSERT(free_srbdp->rx_buf == NULL);
1182544Sgs150176 	free_srbdp->rx_buf = rx_buf;
1192544Sgs150176 	rgep->rc_next = NEXT(slot_recy, RGE_BUF_SLOTS);
1202544Sgs150176 	rge_atomic_renounce(&rgep->rx_free, 1);
1212544Sgs150176 	if (rgep->rx_bcopy && rgep->rx_free == RGE_BUF_SLOTS)
1222544Sgs150176 		rgep->rx_bcopy = B_FALSE;
1232544Sgs150176 	ASSERT(rgep->rx_free <= RGE_BUF_SLOTS);
1242544Sgs150176 
125744Sgs150176 	mutex_exit(rgep->rc_lock);
126744Sgs150176 }
127744Sgs150176 
128744Sgs150176 static int rge_rx_refill(rge_t *rgep, uint32_t slot);
129744Sgs150176 #pragma	inline(rge_rx_refill)
130744Sgs150176 
131744Sgs150176 static int
132744Sgs150176 rge_rx_refill(rge_t *rgep, uint32_t slot)
133744Sgs150176 {
134744Sgs150176 	dma_buf_t *free_buf;
135744Sgs150176 	rge_bd_t *hw_rbd_p;
136744Sgs150176 	sw_rbd_t *srbdp;
137744Sgs150176 	uint32_t free_slot;
138744Sgs150176 
139744Sgs150176 	srbdp = &rgep->sw_rbds[slot];
140744Sgs150176 	hw_rbd_p = &rgep->rx_ring[slot];
141744Sgs150176 	free_slot = rgep->rf_next;
1422544Sgs150176 	free_buf = rgep->free_srbds[free_slot].rx_buf;
143744Sgs150176 	if (free_buf != NULL) {
144744Sgs150176 		srbdp->rx_buf = free_buf;
1452544Sgs150176 		rgep->free_srbds[free_slot].rx_buf = NULL;
1462544Sgs150176 		hw_rbd_p->host_buf_addr = RGE_BSWAP_32(rgep->head_room +
147744Sgs150176 		    + free_buf->pbuf.cookie.dmac_laddress);
148744Sgs150176 		hw_rbd_p->host_buf_addr_hi =
149744Sgs150176 		    RGE_BSWAP_32(free_buf->pbuf.cookie.dmac_laddress >> 32);
150744Sgs150176 		rgep->rf_next = NEXT(free_slot, RGE_BUF_SLOTS);
151744Sgs150176 		return (1);
152744Sgs150176 	} else {
153744Sgs150176 		/*
154744Sgs150176 		 * This situation shouldn't happen
155744Sgs150176 		 */
156744Sgs150176 		rge_problem(rgep, "rge_rx_refill: free buffer %d is NULL",
157744Sgs150176 		    free_slot);
158744Sgs150176 		rgep->rx_bcopy = B_TRUE;
159744Sgs150176 		return (0);
160744Sgs150176 	}
161744Sgs150176 }
162744Sgs150176 
163744Sgs150176 static mblk_t *rge_receive_packet(rge_t *rgep, uint32_t slot);
164744Sgs150176 #pragma	inline(rge_receive_packet)
165744Sgs150176 
166744Sgs150176 static mblk_t *
167744Sgs150176 rge_receive_packet(rge_t *rgep, uint32_t slot)
168744Sgs150176 {
169744Sgs150176 	rge_bd_t *hw_rbd_p;
170744Sgs150176 	sw_rbd_t *srbdp;
171744Sgs150176 	uchar_t *dp;
172744Sgs150176 	mblk_t *mp;
173744Sgs150176 	uint8_t *rx_ptr;
174744Sgs150176 	uint32_t rx_status;
175744Sgs150176 	uint_t packet_len;
176744Sgs150176 	uint_t minsize;
177744Sgs150176 	uint_t maxsize;
178744Sgs150176 	uint32_t proto;
179744Sgs150176 	uint32_t pflags;
180744Sgs150176 	struct ether_vlan_header *ehp;
181744Sgs150176 	uint16_t vtag = 0;
182744Sgs150176 
183744Sgs150176 	hw_rbd_p = &rgep->rx_ring[slot];
184744Sgs150176 	srbdp = &rgep->sw_rbds[slot];
185744Sgs150176 
186744Sgs150176 	/*
187744Sgs150176 	 * Read receive status
188744Sgs150176 	 */
189744Sgs150176 	rx_status = RGE_BSWAP_32(hw_rbd_p->flags_len) & RBD_FLAGS_MASK;
190744Sgs150176 
191744Sgs150176 	/*
192744Sgs150176 	 * Handle error packet
193744Sgs150176 	 */
194744Sgs150176 	if (!(rx_status & BD_FLAG_PKT_END)) {
195744Sgs150176 		RGE_DEBUG(("rge_receive_packet: not a complete packat"));
196744Sgs150176 		return (NULL);
197744Sgs150176 	}
198744Sgs150176 	if (rx_status & RBD_FLAG_ERROR) {
199744Sgs150176 		if (rx_status & RBD_FLAG_CRC_ERR)
200744Sgs150176 			rgep->stats.crc_err++;
201744Sgs150176 		if (rx_status & RBD_FLAG_RUNT)
202744Sgs150176 			rgep->stats.in_short++;
203744Sgs150176 		/*
204744Sgs150176 		 * Set chip_error flag to reset chip:
205744Sgs150176 		 * (suggested in Realtek programming guide.)
206744Sgs150176 		 */
207744Sgs150176 		RGE_DEBUG(("rge_receive_packet: error packet, status = %x",
208744Sgs150176 		    rx_status));
209744Sgs150176 		mutex_enter(rgep->genlock);
210744Sgs150176 		rgep->rge_chip_state = RGE_CHIP_ERROR;
211744Sgs150176 		mutex_exit(rgep->genlock);
212744Sgs150176 		return (NULL);
213744Sgs150176 	}
214744Sgs150176 
215744Sgs150176 	/*
216744Sgs150176 	 * Handle size error packet
217744Sgs150176 	 */
2182544Sgs150176 	packet_len = RGE_BSWAP_32(hw_rbd_p->flags_len) & RBD_LEN_MASK;
2192544Sgs150176 	packet_len -= ETHERFCSL;
2202544Sgs150176 	minsize = ETHERMIN;
2212544Sgs150176 	pflags = RGE_BSWAP_32(hw_rbd_p->vlan_tag);
2222544Sgs150176 	if (pflags & RBD_VLAN_PKT)
2232544Sgs150176 		minsize -= VLAN_TAGSZ;
2242544Sgs150176 	maxsize = rgep->ethmax_size;
225744Sgs150176 	if (packet_len < minsize || packet_len > maxsize) {
226744Sgs150176 		RGE_DEBUG(("rge_receive_packet: len err = %d", packet_len));
227744Sgs150176 		return (NULL);
228744Sgs150176 	}
229744Sgs150176 
230744Sgs150176 	DMA_SYNC(srbdp->rx_buf->pbuf, DDI_DMA_SYNC_FORKERNEL);
2312544Sgs150176 	if (rgep->rx_bcopy || packet_len <= RGE_RECV_COPY_SIZE ||
232744Sgs150176 	    !rge_atomic_reserve(&rgep->rx_free, 1)) {
233744Sgs150176 		/*
234744Sgs150176 		 * Allocate buffer to receive this good packet
235744Sgs150176 		 */
236744Sgs150176 		mp = allocb(packet_len + RGE_HEADROOM, 0);
237744Sgs150176 		if (mp == NULL) {
238744Sgs150176 			RGE_DEBUG(("rge_receive_packet: allocate buffer fail"));
239744Sgs150176 			rgep->stats.no_rcvbuf++;
240744Sgs150176 			return (NULL);
241744Sgs150176 		}
242744Sgs150176 
243744Sgs150176 		/*
244744Sgs150176 		 * Copy the data found into the new cluster
245744Sgs150176 		 */
246744Sgs150176 		rx_ptr = DMA_VPTR(srbdp->rx_buf->pbuf);
247744Sgs150176 		mp->b_rptr = dp = mp->b_rptr + RGE_HEADROOM;
2482544Sgs150176 		bcopy(rx_ptr + rgep->head_room, dp, packet_len);
2492544Sgs150176 		mp->b_wptr = dp + packet_len;
250744Sgs150176 	} else {
251744Sgs150176 		mp = srbdp->rx_buf->mp;
2522544Sgs150176 		mp->b_rptr += rgep->head_room;
2532544Sgs150176 		mp->b_wptr = mp->b_rptr + packet_len;
254744Sgs150176 		mp->b_next = mp->b_cont = NULL;
255744Sgs150176 		/*
256744Sgs150176 		 * Refill the current receive bd buffer
257744Sgs150176 		 *   if fails, will just keep the mp.
258744Sgs150176 		 */
259744Sgs150176 		if (!rge_rx_refill(rgep, slot))
260744Sgs150176 			return (NULL);
261744Sgs150176 	}
262744Sgs150176 	rgep->stats.rbytes += packet_len;
263744Sgs150176 
264744Sgs150176 	/*
265744Sgs150176 	 * VLAN packet ?
266744Sgs150176 	 */
267744Sgs150176 	if (pflags & RBD_VLAN_PKT)
268744Sgs150176 		vtag = pflags & RBD_VLAN_TAG;
269744Sgs150176 	if (vtag) {
270744Sgs150176 		vtag = TCI_CHIP2OS(vtag);
271744Sgs150176 		/*
272744Sgs150176 		 * As h/w strips the VLAN tag from incoming packet, we need
273744Sgs150176 		 * insert VLAN tag into this packet before send up here.
274744Sgs150176 		 */
275744Sgs150176 		(void) memmove(mp->b_rptr - VLAN_TAGSZ, mp->b_rptr,
276744Sgs150176 		    2 * ETHERADDRL);
277744Sgs150176 		mp->b_rptr -= VLAN_TAGSZ;
278744Sgs150176 		ehp = (struct ether_vlan_header *)mp->b_rptr;
279*2760Sdg199075 		ehp->ether_tpid = htons(ETHERTYPE_VLAN);
280744Sgs150176 		ehp->ether_tci = htons(vtag);
2812544Sgs150176 		rgep->stats.rbytes += VLAN_TAGSZ;
282744Sgs150176 	}
283744Sgs150176 
284744Sgs150176 	/*
285744Sgs150176 	 * Check h/w checksum offload status
286744Sgs150176 	 */
287744Sgs150176 	pflags = 0;
288744Sgs150176 	proto = rx_status & RBD_FLAG_PROTOCOL;
289744Sgs150176 	if ((proto == RBD_FLAG_TCP && !(rx_status & RBD_TCP_CKSUM_ERR)) ||
290744Sgs150176 	    (proto == RBD_FLAG_UDP && !(rx_status & RBD_UDP_CKSUM_ERR)))
291744Sgs150176 		pflags |= HCK_FULLCKSUM | HCK_FULLCKSUM_OK;
292744Sgs150176 	if (proto != RBD_FLAG_NONE_IP && !(rx_status & RBD_IP_CKSUM_ERR))
293744Sgs150176 		pflags |= HCK_IPV4_HDRCKSUM;
294744Sgs150176 	if (pflags != 0)  {
295744Sgs150176 		(void) hcksum_assoc(mp, NULL, NULL, 0, 0, 0, 0, pflags, 0);
296744Sgs150176 	}
297744Sgs150176 
298744Sgs150176 	return (mp);
299744Sgs150176 }
300744Sgs150176 
301744Sgs150176 /*
302744Sgs150176  * Accept the packets received in rx ring.
303744Sgs150176  *
304744Sgs150176  * Returns a chain of mblks containing the received data, to be
305744Sgs150176  * passed up to mac_rx().
306744Sgs150176  * The routine returns only when a complete scan has been performed
307744Sgs150176  * without finding any packets to receive.
308744Sgs150176  * This function must SET the OWN bit of BD to indicate the packets
309744Sgs150176  * it has accepted from the ring.
310744Sgs150176  */
311744Sgs150176 static mblk_t *rge_receive_ring(rge_t *rgep);
312744Sgs150176 #pragma	inline(rge_receive_ring)
313744Sgs150176 
314744Sgs150176 static mblk_t *
315744Sgs150176 rge_receive_ring(rge_t *rgep)
316744Sgs150176 {
317744Sgs150176 	rge_bd_t *hw_rbd_p;
318744Sgs150176 	mblk_t *head;
319744Sgs150176 	mblk_t **tail;
320744Sgs150176 	mblk_t *mp;
321744Sgs150176 	uint32_t slot;
322744Sgs150176 
323744Sgs150176 	ASSERT(mutex_owned(rgep->rx_lock));
324744Sgs150176 
325744Sgs150176 	/*
326744Sgs150176 	 * Sync (all) the receive ring descriptors
327744Sgs150176 	 * before accepting the packets they describe
328744Sgs150176 	 */
329744Sgs150176 	DMA_SYNC(rgep->rx_desc, DDI_DMA_SYNC_FORKERNEL);
330744Sgs150176 	slot = rgep->rx_next;
331744Sgs150176 	hw_rbd_p = &rgep->rx_ring[slot];
332744Sgs150176 	head = NULL;
333744Sgs150176 	tail = &head;
334744Sgs150176 
335744Sgs150176 	while (!(hw_rbd_p->flags_len & RGE_BSWAP_32(BD_FLAG_HW_OWN))) {
336744Sgs150176 		if ((mp = rge_receive_packet(rgep, slot)) != NULL) {
337744Sgs150176 			*tail = mp;
338744Sgs150176 			tail = &mp->b_next;
339744Sgs150176 		}
340744Sgs150176 
341744Sgs150176 		/*
342744Sgs150176 		 * Clear RBD flags
343744Sgs150176 		 */
344744Sgs150176 		hw_rbd_p->flags_len =
3452544Sgs150176 		    RGE_BSWAP_32(rgep->rxbuf_size - rgep->head_room);
346744Sgs150176 		HW_RBD_INIT(hw_rbd_p, slot);
347744Sgs150176 		slot = NEXT(slot, RGE_RECV_SLOTS);
348744Sgs150176 		hw_rbd_p = &rgep->rx_ring[slot];
349744Sgs150176 	}
350744Sgs150176 
351744Sgs150176 	rgep->rx_next = slot;
352744Sgs150176 	return (head);
353744Sgs150176 }
354744Sgs150176 
355744Sgs150176 /*
356744Sgs150176  * Receive all ready packets.
357744Sgs150176  */
358744Sgs150176 void rge_receive(rge_t *rgep);
359744Sgs150176 #pragma	no_inline(rge_receive)
360744Sgs150176 
361744Sgs150176 void
362744Sgs150176 rge_receive(rge_t *rgep)
363744Sgs150176 {
364744Sgs150176 	mblk_t *mp;
365744Sgs150176 
366744Sgs150176 	mutex_enter(rgep->rx_lock);
367744Sgs150176 	mp = rge_receive_ring(rgep);
368744Sgs150176 	mutex_exit(rgep->rx_lock);
369744Sgs150176 
370744Sgs150176 	if (mp != NULL)
3712311Sseb 		mac_rx(rgep->mh, rgep->handle, mp);
372744Sgs150176 }
373744Sgs150176 
374744Sgs150176 
375744Sgs150176 #undef	RGE_DBG
376744Sgs150176 #define	RGE_DBG		RGE_DBG_SEND	/* debug flag for this code	*/
377744Sgs150176 
378744Sgs150176 
379744Sgs150176 /*
380744Sgs150176  * ========== Send-side recycle routines ==========
381744Sgs150176  */
382744Sgs150176 static uint32_t rge_send_claim(rge_t *rgep);
383744Sgs150176 #pragma	inline(rge_send_claim)
384744Sgs150176 
385744Sgs150176 static uint32_t
386744Sgs150176 rge_send_claim(rge_t *rgep)
387744Sgs150176 {
388744Sgs150176 	uint32_t slot;
389744Sgs150176 	uint32_t next;
390744Sgs150176 
391744Sgs150176 	mutex_enter(rgep->tx_lock);
392744Sgs150176 	slot = rgep->tx_next;
393744Sgs150176 	next = NEXT(slot, RGE_SEND_SLOTS);
394744Sgs150176 	rgep->tx_next = next;
395744Sgs150176 	rgep->tx_flow++;
396744Sgs150176 	mutex_exit(rgep->tx_lock);
397744Sgs150176 
398744Sgs150176 	/*
399744Sgs150176 	 * We check that our invariants still hold:
400744Sgs150176 	 * +	the slot and next indexes are in range
401744Sgs150176 	 * +	the slot must not be the last one (i.e. the *next*
402744Sgs150176 	 *	index must not match the next-recycle index), 'cos
403744Sgs150176 	 *	there must always be at least one free slot in a ring
404744Sgs150176 	 */
405744Sgs150176 	ASSERT(slot < RGE_SEND_SLOTS);
406744Sgs150176 	ASSERT(next < RGE_SEND_SLOTS);
407744Sgs150176 	ASSERT(next != rgep->tc_next);
408744Sgs150176 
409744Sgs150176 	return (slot);
410744Sgs150176 }
411744Sgs150176 
412744Sgs150176 /*
413744Sgs150176  * We don't want to call this function every time after a successful
414744Sgs150176  * h/w transmit done in ISR.  Instead, we call this function in the
415744Sgs150176  * rge_send() when there're few or no free tx BDs remained.
416744Sgs150176  */
417744Sgs150176 static void rge_send_recycle(rge_t *rgep);
418744Sgs150176 #pragma	inline(rge_send_recycle)
419744Sgs150176 
420744Sgs150176 static void
421744Sgs150176 rge_send_recycle(rge_t *rgep)
422744Sgs150176 {
423744Sgs150176 	rge_bd_t *hw_sbd_p;
424744Sgs150176 	uint32_t tc_tail;
425744Sgs150176 	uint32_t tc_head;
426744Sgs150176 	uint32_t n;
427744Sgs150176 
428744Sgs150176 	mutex_enter(rgep->tc_lock);
429744Sgs150176 	tc_head = rgep->tc_next;
430744Sgs150176 	tc_tail = rgep->tc_tail;
4312544Sgs150176 	if (tc_head == tc_tail)
4322544Sgs150176 		goto resched;
433744Sgs150176 
434744Sgs150176 	do {
435744Sgs150176 		tc_tail = LAST(tc_tail, RGE_SEND_SLOTS);
436744Sgs150176 		hw_sbd_p = &rgep->tx_ring[tc_tail];
437744Sgs150176 		if (tc_tail == tc_head) {
438744Sgs150176 			if (hw_sbd_p->flags_len &
439744Sgs150176 			    RGE_BSWAP_32(BD_FLAG_HW_OWN)) {
440744Sgs150176 				/*
4412544Sgs150176 				 * Recyled nothing: bump the watchdog counter,
4422544Sgs150176 				 * thus guaranteeing that it's nonzero
4432544Sgs150176 				 * (watchdog activated).
444744Sgs150176 				 */
445744Sgs150176 				rgep->watchdog += 1;
446744Sgs150176 				mutex_exit(rgep->tc_lock);
447744Sgs150176 				return;
448744Sgs150176 			}
449744Sgs150176 			break;
450744Sgs150176 		}
451744Sgs150176 	} while (hw_sbd_p->flags_len & RGE_BSWAP_32(BD_FLAG_HW_OWN));
452744Sgs150176 
4532544Sgs150176 	/*
4542544Sgs150176 	 * Recyled something :-)
4552544Sgs150176 	 */
456744Sgs150176 	rgep->tc_next = NEXT(tc_tail, RGE_SEND_SLOTS);
457744Sgs150176 	n = rgep->tc_next - tc_head;
458744Sgs150176 	if (rgep->tc_next < tc_head)
459744Sgs150176 		n += RGE_SEND_SLOTS;
460744Sgs150176 	rge_atomic_renounce(&rgep->tx_free, n);
461744Sgs150176 	rgep->watchdog = 0;
4622544Sgs150176 	ASSERT(rgep->tx_free <= RGE_SEND_SLOTS);
463744Sgs150176 
4642544Sgs150176 resched:
4652544Sgs150176 	mutex_exit(rgep->tc_lock);
4662544Sgs150176 	if (rgep->resched_needed &&
4672544Sgs150176 	    rgep->rge_mac_state == RGE_MAC_STARTED) {
4682544Sgs150176 		rgep->resched_needed = B_FALSE;
4692544Sgs150176 		mac_tx_update(rgep->mh);
470744Sgs150176 	}
471744Sgs150176 }
472744Sgs150176 
473744Sgs150176 /*
474744Sgs150176  * Send a message by copying it into a preallocated (and premapped) buffer
475744Sgs150176  */
4762544Sgs150176 static void rge_send_copy(rge_t *rgep, mblk_t *mp, uint16_t tci);
477744Sgs150176 #pragma	inline(rge_send_copy)
478744Sgs150176 
479744Sgs150176 static void
4802544Sgs150176 rge_send_copy(rge_t *rgep, mblk_t *mp, uint16_t tci)
481744Sgs150176 {
482744Sgs150176 	rge_bd_t *hw_sbd_p;
483744Sgs150176 	sw_sbd_t *ssbdp;
484744Sgs150176 	mblk_t *bp;
485744Sgs150176 	char *txb;
486744Sgs150176 	uint32_t slot;
487744Sgs150176 	size_t totlen;
488744Sgs150176 	size_t mblen;
489744Sgs150176 	uint32_t pflags;
4902544Sgs150176 	struct ether_header *ethhdr;
4912544Sgs150176 	struct ip *ip_hdr;
492744Sgs150176 
493744Sgs150176 	/*
494744Sgs150176 	 * IMPORTANT:
495744Sgs150176 	 *	Up to the point where it claims a place, a send_msg()
496744Sgs150176 	 *	routine can indicate failure by returning B_FALSE.  Once it's
497744Sgs150176 	 *	claimed a place, it mustn't fail.
498744Sgs150176 	 *
499744Sgs150176 	 * In this version, there's no setup to be done here, and there's
500744Sgs150176 	 * nothing that can fail, so we can go straight to claiming our
501744Sgs150176 	 * already-reserved place on the train.
502744Sgs150176 	 *
503744Sgs150176 	 * This is the point of no return!
504744Sgs150176 	 */
505744Sgs150176 	slot = rge_send_claim(rgep);
506744Sgs150176 	ssbdp = &rgep->sw_sbds[slot];
507744Sgs150176 
508744Sgs150176 	/*
509744Sgs150176 	 * Copy the data into a pre-mapped buffer, which avoids the
510744Sgs150176 	 * overhead (and complication) of mapping/unmapping STREAMS
511744Sgs150176 	 * buffers and keeping hold of them until the DMA has completed.
512744Sgs150176 	 *
513744Sgs150176 	 * Because all buffers are the same size, and larger than the
514744Sgs150176 	 * longest single valid message, we don't have to bother about
515744Sgs150176 	 * splitting the message across multiple buffers either.
516744Sgs150176 	 */
517744Sgs150176 	txb = DMA_VPTR(ssbdp->pbuf);
5182544Sgs150176 	totlen = 0;
5192544Sgs150176 	bp = mp;
5202544Sgs150176 	if (tci != 0) {
5212544Sgs150176 		/*
5222544Sgs150176 		 * Do not copy the vlan tag
5232544Sgs150176 		 */
5242544Sgs150176 		bcopy(bp->b_rptr, txb, 2 * ETHERADDRL);
5252544Sgs150176 		txb += 2 * ETHERADDRL;
5262544Sgs150176 		totlen += 2 * ETHERADDRL;
5272544Sgs150176 		mblen = bp->b_wptr - bp->b_rptr;
5282544Sgs150176 		ASSERT(mblen >= 2 * ETHERADDRL + VLAN_TAGSZ);
5292544Sgs150176 		mblen -= 2 * ETHERADDRL + VLAN_TAGSZ;
5302544Sgs150176 		if ((totlen += mblen) <= rgep->ethmax_size) {
5312544Sgs150176 			bcopy(bp->b_rptr + 2 * ETHERADDRL + VLAN_TAGSZ,
5322544Sgs150176 			    txb, mblen);
5332544Sgs150176 			txb += mblen;
5342544Sgs150176 		}
5352544Sgs150176 		bp = bp->b_cont;
5362544Sgs150176 		rgep->stats.obytes += VLAN_TAGSZ;
5372544Sgs150176 	}
5382544Sgs150176 	for (; bp != NULL; bp = bp->b_cont) {
539744Sgs150176 		mblen = bp->b_wptr - bp->b_rptr;
540744Sgs150176 		if ((totlen += mblen) <= rgep->ethmax_size) {
541744Sgs150176 			bcopy(bp->b_rptr, txb, mblen);
542744Sgs150176 			txb += mblen;
543744Sgs150176 		}
544744Sgs150176 	}
5452544Sgs150176 	rgep->stats.obytes += totlen;
546744Sgs150176 
547744Sgs150176 	/*
548744Sgs150176 	 * We'e reached the end of the chain; and we should have
549744Sgs150176 	 * collected no more than ETHERMAX bytes into our buffer.
550744Sgs150176 	 */
551744Sgs150176 	ASSERT(bp == NULL);
552744Sgs150176 	ASSERT(totlen <= rgep->ethmax_size);
553744Sgs150176 	DMA_SYNC(ssbdp->pbuf, DDI_DMA_SYNC_FORDEV);
554744Sgs150176 
555744Sgs150176 	/*
5562544Sgs150176 	 * Update the hardware send buffer descriptor flags
557744Sgs150176 	 */
558744Sgs150176 	hw_sbd_p = &rgep->tx_ring[slot];
5592544Sgs150176 	ASSERT(hw_sbd_p == ssbdp->desc.mem_va);
560744Sgs150176 	hw_sbd_p->flags_len = RGE_BSWAP_32(totlen & SBD_LEN_MASK);
561744Sgs150176 	if (tci != 0) {
562744Sgs150176 		tci = TCI_OS2CHIP(tci);
563744Sgs150176 		hw_sbd_p->vlan_tag = RGE_BSWAP_32(tci);
564744Sgs150176 		hw_sbd_p->vlan_tag |= RGE_BSWAP_32(SBD_VLAN_PKT);
565744Sgs150176 	} else {
566744Sgs150176 		hw_sbd_p->vlan_tag = 0;
567744Sgs150176 	}
568744Sgs150176 
5692544Sgs150176 	/*
5702544Sgs150176 	 * h/w checksum offload flags
5712544Sgs150176 	 */
572744Sgs150176 	hcksum_retrieve(mp, NULL, NULL, NULL, NULL, NULL, NULL, &pflags);
573744Sgs150176 	if (pflags & HCK_FULLCKSUM) {
5742544Sgs150176 		ASSERT(totlen >= sizeof (struct ether_header) +
5752544Sgs150176 		    sizeof (struct ip));
5762544Sgs150176 		ethhdr = (struct ether_header *)(DMA_VPTR(ssbdp->pbuf));
5772544Sgs150176 		/*
5782544Sgs150176 		 * Is the packet an IP(v4) packet?
5792544Sgs150176 		 */
5802544Sgs150176 		if (ntohs(ethhdr->ether_type) == ETHERTYPE_IP) {
5812544Sgs150176 			ip_hdr = (struct ip *)
5822544Sgs150176 			    ((uint8_t *)DMA_VPTR(ssbdp->pbuf) +
5832544Sgs150176 			    sizeof (struct ether_header));
5842544Sgs150176 			if (ip_hdr->ip_p == IPPROTO_TCP)
5852544Sgs150176 				hw_sbd_p->flags_len |=
5862544Sgs150176 				    RGE_BSWAP_32(SBD_FLAG_TCP_CKSUM);
5872544Sgs150176 			else if (ip_hdr->ip_p == IPPROTO_UDP)
5882544Sgs150176 				hw_sbd_p->flags_len |=
5892544Sgs150176 				    RGE_BSWAP_32(SBD_FLAG_UDP_CKSUM);
590744Sgs150176 		}
591744Sgs150176 	}
5922544Sgs150176 	if (pflags & HCK_IPV4_HDRCKSUM)
593744Sgs150176 		hw_sbd_p->flags_len |= RGE_BSWAP_32(SBD_FLAG_IP_CKSUM);
594744Sgs150176 
595744Sgs150176 	HW_SBD_SET(hw_sbd_p, slot);
5962544Sgs150176 
5972544Sgs150176 	/*
5982544Sgs150176 	 * We're done.
5992544Sgs150176 	 * The message can be freed right away, as we've already
6002544Sgs150176 	 * copied the contents ...
6012544Sgs150176 	 */
6022544Sgs150176 	freemsg(mp);
603744Sgs150176 }
604744Sgs150176 
605744Sgs150176 static boolean_t
606744Sgs150176 rge_send(rge_t *rgep, mblk_t *mp)
607744Sgs150176 {
608744Sgs150176 	struct ether_vlan_header *ehp;
6092544Sgs150176 	uint16_t tci;
610744Sgs150176 
611744Sgs150176 	ASSERT(mp->b_next == NULL);
612744Sgs150176 
613744Sgs150176 	/*
614744Sgs150176 	 * Try to reserve a place in the transmit ring.
615744Sgs150176 	 */
616744Sgs150176 	if (!rge_atomic_reserve(&rgep->tx_free, 1)) {
617744Sgs150176 		RGE_DEBUG(("rge_send: no free slots"));
618744Sgs150176 		rgep->stats.defer++;
619744Sgs150176 		rgep->resched_needed = B_TRUE;
6202544Sgs150176 		(void) ddi_intr_trigger_softint(rgep->resched_hdl, NULL);
621744Sgs150176 		return (B_FALSE);
622744Sgs150176 	}
623744Sgs150176 
624744Sgs150176 	/*
6252544Sgs150176 	 * Determine if the packet is VLAN tagged.
6262544Sgs150176 	 */
6272544Sgs150176 	ASSERT(MBLKL(mp) >= sizeof (struct ether_header));
6282544Sgs150176 	tci = 0;
6292544Sgs150176 	ehp = (struct ether_vlan_header *)mp->b_rptr;
630*2760Sdg199075 	if (ehp->ether_tpid == htons(ETHERTYPE_VLAN))
6312544Sgs150176 		tci = ntohs(ehp->ether_tci);
6322544Sgs150176 
6332544Sgs150176 	/*
634744Sgs150176 	 * We've reserved a place :-)
635744Sgs150176 	 * These ASSERTions check that our invariants still hold:
636744Sgs150176 	 *	there must still be at least one free place
637744Sgs150176 	 *	there must be at least one place NOT free (ours!)
638744Sgs150176 	 */
639744Sgs150176 	ASSERT(rgep->tx_free < RGE_SEND_SLOTS);
6402544Sgs150176 	rge_send_copy(rgep, mp, tci);
641744Sgs150176 
642744Sgs150176 	/*
643744Sgs150176 	 * Trigger chip h/w transmit ...
644744Sgs150176 	 */
645744Sgs150176 	mutex_enter(rgep->tx_lock);
646744Sgs150176 	if (--rgep->tx_flow == 0) {
647744Sgs150176 		DMA_SYNC(rgep->tx_desc, DDI_DMA_SYNC_FORDEV);
648744Sgs150176 		rge_tx_trigger(rgep);
6492544Sgs150176 		if (rgep->tx_free < RGE_SEND_SLOTS/2)
650744Sgs150176 			rge_send_recycle(rgep);
651744Sgs150176 		rgep->tc_tail = rgep->tx_next;
652744Sgs150176 	}
653744Sgs150176 	mutex_exit(rgep->tx_lock);
654744Sgs150176 
655744Sgs150176 	return (B_TRUE);
656744Sgs150176 }
657744Sgs150176 
658744Sgs150176 uint_t
6592544Sgs150176 rge_reschedule(caddr_t arg1, caddr_t arg2)
660744Sgs150176 {
661744Sgs150176 	rge_t *rgep;
662744Sgs150176 
6632544Sgs150176 	rgep = (rge_t *)arg1;
6642544Sgs150176 	_NOTE(ARGUNUSED(arg2))
665744Sgs150176 
6662544Sgs150176 	rge_send_recycle(rgep);
667744Sgs150176 
6682544Sgs150176 	return (DDI_INTR_CLAIMED);
669744Sgs150176 }
670744Sgs150176 
671744Sgs150176 /*
672744Sgs150176  * rge_m_tx() - send a chain of packets
673744Sgs150176  */
674744Sgs150176 mblk_t *
675744Sgs150176 rge_m_tx(void *arg, mblk_t *mp)
676744Sgs150176 {
677744Sgs150176 	rge_t *rgep = arg;		/* private device info	*/
678744Sgs150176 	mblk_t *next;
679744Sgs150176 
680744Sgs150176 	ASSERT(mp != NULL);
681744Sgs150176 	ASSERT(rgep->rge_mac_state == RGE_MAC_STARTED);
682744Sgs150176 
683744Sgs150176 	if (rgep->rge_chip_state != RGE_CHIP_RUNNING) {
684744Sgs150176 		RGE_DEBUG(("rge_m_tx: chip not running"));
685744Sgs150176 		return (mp);
686744Sgs150176 	}
687744Sgs150176 
688744Sgs150176 	rw_enter(rgep->errlock, RW_READER);
689744Sgs150176 	while (mp != NULL) {
690744Sgs150176 		next = mp->b_next;
691744Sgs150176 		mp->b_next = NULL;
692744Sgs150176 
693744Sgs150176 		if (!rge_send(rgep, mp)) {
694744Sgs150176 			mp->b_next = next;
695744Sgs150176 			break;
696744Sgs150176 		}
697744Sgs150176 
698744Sgs150176 		mp = next;
699744Sgs150176 	}
700744Sgs150176 	rw_exit(rgep->errlock);
701744Sgs150176 
702744Sgs150176 	return (mp);
703744Sgs150176 }
704