bge_recv2.c revision 1369:3ad288180946
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 2006 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include "sys/bge_impl2.h"
30
31#define	U32TOPTR(x)	((void *)(uintptr_t)(uint32_t)(x))
32#define	PTRTOU32(x)	((uint32_t)(uintptr_t)(void *)(x))
33
34/*
35 * ========== RX side routines ==========
36 */
37
38#define	BGE_DBG		BGE_DBG_RECV	/* debug flag for this code	*/
39
40static void bge_refill(bge_t *bgep, buff_ring_t *brp, sw_rbd_t *srbdp);
41#pragma	inline(bge_refill)
42
43/*
44 * Return the specified buffer (srbdp) to the ring it came from (brp).
45 *
46 * Note:
47 *	If the driver is compiled with only one buffer ring *and* one
48 *	return ring, then the buffers must be returned in sequence.
49 *	In this case, we don't have to consider anything about the
50 *	buffer at all; we can simply advance the cyclic counter.  And
51 *	we don't even need the refill mutex <rf_lock>, as the caller
52 *	will already be holding the (one-and-only) <rx_lock>.
53 *
54 *	If the driver supports multiple buffer rings, but only one
55 *	return ring, the same still applies (to each buffer ring
56 *	separately).
57 */
58static void
59bge_refill(bge_t *bgep, buff_ring_t *brp, sw_rbd_t *srbdp)
60{
61	uint64_t slot;
62
63	_NOTE(ARGUNUSED(srbdp))
64
65	slot = brp->rf_next;
66	brp->rf_next = NEXT(slot, brp->desc.nslots);
67	bge_mbx_put(bgep, brp->chip_mbx_reg, slot);
68}
69
70static mblk_t *bge_receive_packet(bge_t *bgep, bge_rbd_t *hw_rbd_p);
71#pragma	inline(bge_receive_packet)
72
73static mblk_t *
74bge_receive_packet(bge_t *bgep, bge_rbd_t *hw_rbd_p)
75{
76	bge_rbd_t hw_rbd;
77	buff_ring_t *brp;
78	sw_rbd_t *srbdp;
79	uchar_t *dp;
80	mblk_t *mp;
81	uint_t len;
82	uint_t minsize;
83	uint_t maxsize;
84	uint32_t pflags;
85
86	mp = NULL;
87	hw_rbd = *hw_rbd_p;
88
89	switch (hw_rbd.flags & (RBD_FLAG_MINI_RING|RBD_FLAG_JUMBO_RING)) {
90	case RBD_FLAG_MINI_RING|RBD_FLAG_JUMBO_RING:
91	default:
92		/* error, this shouldn't happen */
93		BGE_PKTDUMP((bgep, &hw_rbd, NULL, "bad ring flags!"));
94		goto error;
95
96	case RBD_FLAG_JUMBO_RING:
97		brp = &bgep->buff[BGE_JUMBO_BUFF_RING];
98		break;
99
100#if	(BGE_BUFF_RINGS_USED > 2)
101	case RBD_FLAG_MINI_RING:
102		brp = &bgep->buff[BGE_MINI_BUFF_RING];
103		break;
104#endif	/* BGE_BUFF_RINGS_USED > 2 */
105
106	case 0:
107		brp = &bgep->buff[BGE_STD_BUFF_RING];
108		break;
109	}
110
111	if (hw_rbd.index >= brp->desc.nslots) {
112		/* error, this shouldn't happen */
113		BGE_PKTDUMP((bgep, &hw_rbd, NULL, "bad ring index!"));
114		goto error;
115	}
116
117	srbdp = &brp->sw_rbds[hw_rbd.index];
118	if (hw_rbd.opaque != srbdp->pbuf.token) {
119		/* bogus, drop the packet */
120		BGE_PKTDUMP((bgep, &hw_rbd, srbdp, "bad ring token"));
121		goto refill;
122	}
123
124	if ((hw_rbd.flags & RBD_FLAG_PACKET_END) == 0) {
125		/* bogus, drop the packet */
126		BGE_PKTDUMP((bgep, &hw_rbd, srbdp, "unterminated packet"));
127		goto refill;
128	}
129
130	if (hw_rbd.flags & RBD_FLAG_FRAME_HAS_ERROR) {
131		/* bogus, drop the packet */
132		BGE_PKTDUMP((bgep, &hw_rbd, srbdp, "errored packet"));
133		goto refill;
134	}
135
136	len = hw_rbd.len;
137
138	/*
139	 * H/W will not strip the VLAN tag from incoming packet now, as
140	 * RECEIVE_MODE_KEEP_VLAN_TAG bit is set in RECEIVE_MAC_MODE_REG
141	 * register.
142	 */
143	maxsize = bgep->chipid.ethmax_size + VLAN_TAGSZ + ETHERFCSL;
144	if (len > maxsize) {
145		/* bogus, drop the packet */
146		BGE_PKTDUMP((bgep, &hw_rbd, srbdp, "oversize packet"));
147		goto refill;
148	}
149
150	minsize = ETHERMIN + ETHERFCSL;
151	if (len < minsize) {
152		/* bogus, drop the packet */
153		BGE_PKTDUMP((bgep, &hw_rbd, srbdp, "undersize packet"));
154		goto refill;
155	}
156
157	/*
158	 * Packet looks good; get a buffer to copy it into.
159	 * We want to leave some space at the front of the allocated
160	 * buffer in case any upstream modules want to prepend some
161	 * sort of header.  This also has the side-effect of making
162	 * the packet *contents* 4-byte aligned, as required by NCA!
163	 */
164	mp = allocb(BGE_HEADROOM + len, 0);
165	if (mp == NULL) {
166		/* Nothing to do but drop the packet */
167		goto refill;
168	}
169
170	/*
171	 * Sync the data and copy it to the STREAMS buffer.
172	 */
173	DMA_SYNC(srbdp->pbuf, DDI_DMA_SYNC_FORKERNEL);
174	mp->b_rptr = dp = mp->b_rptr + BGE_HEADROOM;
175	bcopy(DMA_VPTR(srbdp->pbuf), dp, len);
176	mp->b_wptr = dp + len - ETHERFCSL;
177
178	/*
179	 * Special check for one specific type of data corruption;
180	 * in a good packet, the first 8 bytes are *very* unlikely
181	 * to be the same as the second 8 bytes ... but we let the
182	 * packet through just in case.
183	 */
184	if (bcmp(dp, dp+8, 8) == 0)
185		BGE_PKTDUMP((bgep, &hw_rbd, srbdp, "stuttered packet?"));
186
187	pflags = 0;
188	if (hw_rbd.flags & RBD_FLAG_TCP_UDP_CHECKSUM)
189		pflags |= HCK_FULLCKSUM;
190	if (hw_rbd.flags & RBD_FLAG_IP_CHECKSUM)
191		pflags |= HCK_IPV4_HDRCKSUM;
192	if (pflags != 0)
193		(void) hcksum_assoc(mp, NULL, NULL, 0, 0, 0,
194		    hw_rbd.tcp_udp_cksum, pflags, 0);
195
196refill:
197	/*
198	 * Replace the buffer in the ring it came from ...
199	 */
200	bge_refill(bgep, brp, srbdp);
201	return (mp);
202
203error:
204	/*
205	 * We come here if the integrity of the ring descriptors
206	 * (rather than merely packet data) appears corrupted.
207	 * The factotum will attempt to reset-and-recover.
208	 */
209	mutex_enter(bgep->genlock);
210	bgep->bge_chip_state = BGE_CHIP_ERROR;
211	mutex_exit(bgep->genlock);
212	return (NULL);
213}
214
215/*
216 * Accept the packets received in the specified ring up to
217 * (but not including) the producer index in the status block.
218 *
219 * Returns a chain of mblks containing the received data, to be
220 * passed up to gld_recv() (we can't call gld_recv() from here,
221 * 'cos we're holding the per-ring receive lock at this point).
222 *
223 * This function must advance (rrp->rx_next) and write it back to
224 * the chip to indicate the packets it has accepted from the ring.
225 */
226static mblk_t *bge_receive_ring(bge_t *bgep, recv_ring_t *rrp);
227#pragma	inline(bge_receive_ring)
228
229static mblk_t *
230bge_receive_ring(bge_t *bgep, recv_ring_t *rrp)
231{
232	bge_rbd_t *hw_rbd_p;
233	uint64_t slot;
234	mblk_t *head;
235	mblk_t **tail;
236	mblk_t *mp;
237
238	ASSERT(mutex_owned(rrp->rx_lock));
239
240	/*
241	 * Sync (all) the receive ring descriptors
242	 * before accepting the packets they describe
243	 */
244	DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORKERNEL);
245	hw_rbd_p = DMA_VPTR(rrp->desc);
246	head = NULL;
247	tail = &head;
248	slot = rrp->rx_next;
249
250	while (slot != *rrp->prod_index_p) {	/* Note: volatile	*/
251		if ((mp = bge_receive_packet(bgep, &hw_rbd_p[slot])) != NULL) {
252			*tail = mp;
253			tail = &mp->b_next;
254		}
255		rrp->rx_next = slot = NEXT(slot, rrp->desc.nslots);
256	}
257
258	bge_mbx_put(bgep, rrp->chip_mbx_reg, rrp->rx_next);
259	return (head);
260}
261
262/*
263 * Receive all packets in all rings.
264 *
265 * To give priority to low-numbered rings, whenever we have received any
266 * packets in any ring except 0, we restart scanning again from ring 0.
267 * Thus, for example, if rings 0, 3, and 10 are carrying traffic, the
268 * pattern of receives might go 0, 3, 10, 3, 0, 10, 0:
269 *
270 *	0	found some - receive them
271 *	1..2					none found
272 *	3	found some - receive them	and restart scan
273 *	0..9					none found
274 *	10	found some - receive them	and restart scan
275 *	0..2					none found
276 *	3	found some more - receive them	and restart scan
277 *	0	found some more - receive them
278 *	1..9					none found
279 *	10	found some more - receive them	and restart scan
280 *	0	found some more - receive them
281 *	1..15					none found
282 *
283 * The routine returns only when a complete scan has been performed
284 * without finding any packets to receive.
285 *
286 * Note that driver-defined locks may *NOT* be held across calls
287 * to gld_recv().
288 *
289 * Note: the expression (BGE_RECV_RINGS_USED > 1), yields a compile-time
290 * constant and allows the compiler to optimise away the outer do-loop
291 * if only one receive ring is being used.
292 */
293void bge_receive(bge_t *bgep, bge_status_t *bsp);
294#pragma	no_inline(bge_receive)
295
296void
297bge_receive(bge_t *bgep, bge_status_t *bsp)
298{
299	recv_ring_t *rrp;
300	uint64_t ring;
301	uint64_t rx_rings = bgep->chipid.rx_rings;
302	mblk_t *mp;
303
304restart:
305	ring = 0;
306	rrp = &bgep->recv[ring];
307	do {
308		/*
309		 * For each ring, (rrp->prod_index_p) points to the
310		 * proper index within the status block (which has
311		 * already been sync'd by the caller)
312		 */
313		ASSERT(rrp->prod_index_p == RECV_INDEX_P(bsp, ring));
314
315		if (*rrp->prod_index_p == rrp->rx_next)
316			continue;		/* no packets		*/
317		if (mutex_tryenter(rrp->rx_lock) == 0)
318			continue;		/* already in process	*/
319		mp = bge_receive_ring(bgep, rrp);
320		mutex_exit(rrp->rx_lock);
321
322		if (mp != NULL) {
323			mac_rx(bgep->macp, rrp->handle, mp);
324
325			/*
326			 * Restart from ring 0, if the driver is compiled
327			 * with multiple rings and we're not on ring 0 now
328			 */
329			if (rx_rings > 1 && ring > 0)
330				goto restart;
331		}
332
333		/*
334		 * Loop over all rings (if there *are* multiple rings)
335		 */
336	} while (++rrp, ++ring < rx_rings);
337}
338