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 /*
2211499SZhen.W@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23744Sgs150176 * Use is subject to license terms.
24744Sgs150176 */
25744Sgs150176
26744Sgs150176 #include "rge.h"
27744Sgs150176
28744Sgs150176 #define U32TOPTR(x) ((void *)(uintptr_t)(uint32_t)(x))
29744Sgs150176 #define PTRTOU32(x) ((uint32_t)(uintptr_t)(void *)(x))
30744Sgs150176
31744Sgs150176 /*
32744Sgs150176 * ========== RX side routines ==========
33744Sgs150176 */
34744Sgs150176
35744Sgs150176 #define RGE_DBG RGE_DBG_RECV /* debug flag for this code */
36744Sgs150176
37744Sgs150176 static uint32_t rge_atomic_reserve(uint32_t *count_p, uint32_t n);
38744Sgs150176 #pragma inline(rge_atomic_reserve)
39744Sgs150176
40744Sgs150176 static uint32_t
rge_atomic_reserve(uint32_t * count_p,uint32_t n)41744Sgs150176 rge_atomic_reserve(uint32_t *count_p, uint32_t n)
42744Sgs150176 {
43744Sgs150176 uint32_t oldval;
44744Sgs150176 uint32_t newval;
45744Sgs150176
46744Sgs150176 /* ATOMICALLY */
47744Sgs150176 do {
48744Sgs150176 oldval = *count_p;
49744Sgs150176 newval = oldval - n;
50744Sgs150176 if (oldval <= n)
51744Sgs150176 return (0); /* no resources left */
52744Sgs150176 } while (cas32(count_p, oldval, newval) != oldval);
53744Sgs150176
54744Sgs150176 return (newval);
55744Sgs150176 }
56744Sgs150176
57744Sgs150176 /*
58744Sgs150176 * Atomically increment a counter
59744Sgs150176 */
60744Sgs150176 static void rge_atomic_renounce(uint32_t *count_p, uint32_t n);
61744Sgs150176 #pragma inline(rge_atomic_renounce)
62744Sgs150176
63744Sgs150176 static void
rge_atomic_renounce(uint32_t * count_p,uint32_t n)64744Sgs150176 rge_atomic_renounce(uint32_t *count_p, uint32_t n)
65744Sgs150176 {
66744Sgs150176 uint32_t oldval;
67744Sgs150176 uint32_t newval;
68744Sgs150176
69744Sgs150176 /* ATOMICALLY */
70744Sgs150176 do {
71744Sgs150176 oldval = *count_p;
72744Sgs150176 newval = oldval + n;
73744Sgs150176 } while (cas32(count_p, oldval, newval) != oldval);
74744Sgs150176 }
75744Sgs150176
76744Sgs150176 /*
77744Sgs150176 * Callback code invoked from STREAMs when the recv data buffer is free
78744Sgs150176 * for recycling.
79744Sgs150176 */
80744Sgs150176 void
rge_rx_recycle(caddr_t arg)81744Sgs150176 rge_rx_recycle(caddr_t arg)
82744Sgs150176 {
83744Sgs150176 rge_t *rgep;
84744Sgs150176 dma_buf_t *rx_buf;
852544Sgs150176 sw_rbd_t *free_srbdp;
86744Sgs150176 uint32_t slot_recy;
87744Sgs150176
88744Sgs150176 rx_buf = (dma_buf_t *)arg;
89744Sgs150176 rgep = (rge_t *)rx_buf->private;
90744Sgs150176
91744Sgs150176 /*
922544Sgs150176 * In rge_unattach() and rge_attach(), this callback function will
932544Sgs150176 * also be called to free mp in rge_fini_rings() and rge_init_rings().
942544Sgs150176 * In such situation, we shouldn't do below desballoc(), otherwise,
95744Sgs150176 * there'll be memory leak.
96744Sgs150176 */
972544Sgs150176 if (rgep->rge_mac_state == RGE_MAC_UNATTACH ||
982544Sgs150176 rgep->rge_mac_state == RGE_MAC_ATTACH)
99744Sgs150176 return;
100744Sgs150176
101744Sgs150176 /*
102744Sgs150176 * Recycle the data buffer again
103744Sgs150176 * and fill them in free ring
104744Sgs150176 */
105744Sgs150176 rx_buf->mp = desballoc(DMA_VPTR(rx_buf->pbuf),
106744Sgs150176 rgep->rxbuf_size, 0, &rx_buf->rx_recycle);
107744Sgs150176 if (rx_buf->mp == NULL) {
108744Sgs150176 rge_problem(rgep, "rge_rx_recycle: desballoc() failed");
109744Sgs150176 return;
110744Sgs150176 }
111744Sgs150176 mutex_enter(rgep->rc_lock);
112744Sgs150176 slot_recy = rgep->rc_next;
1132544Sgs150176 free_srbdp = &rgep->free_srbds[slot_recy];
1142544Sgs150176
1152544Sgs150176 ASSERT(free_srbdp->rx_buf == NULL);
1162544Sgs150176 free_srbdp->rx_buf = rx_buf;
1172544Sgs150176 rgep->rc_next = NEXT(slot_recy, RGE_BUF_SLOTS);
1182544Sgs150176 rge_atomic_renounce(&rgep->rx_free, 1);
1192544Sgs150176 if (rgep->rx_bcopy && rgep->rx_free == RGE_BUF_SLOTS)
1202544Sgs150176 rgep->rx_bcopy = B_FALSE;
1212544Sgs150176 ASSERT(rgep->rx_free <= RGE_BUF_SLOTS);
1222544Sgs150176
123744Sgs150176 mutex_exit(rgep->rc_lock);
124744Sgs150176 }
125744Sgs150176
126744Sgs150176 static int rge_rx_refill(rge_t *rgep, uint32_t slot);
127744Sgs150176 #pragma inline(rge_rx_refill)
128744Sgs150176
129744Sgs150176 static int
rge_rx_refill(rge_t * rgep,uint32_t slot)130744Sgs150176 rge_rx_refill(rge_t *rgep, uint32_t slot)
131744Sgs150176 {
132744Sgs150176 dma_buf_t *free_buf;
133744Sgs150176 rge_bd_t *hw_rbd_p;
134744Sgs150176 sw_rbd_t *srbdp;
135744Sgs150176 uint32_t free_slot;
136744Sgs150176
137744Sgs150176 srbdp = &rgep->sw_rbds[slot];
138744Sgs150176 hw_rbd_p = &rgep->rx_ring[slot];
139744Sgs150176 free_slot = rgep->rf_next;
1402544Sgs150176 free_buf = rgep->free_srbds[free_slot].rx_buf;
141744Sgs150176 if (free_buf != NULL) {
142744Sgs150176 srbdp->rx_buf = free_buf;
1432544Sgs150176 rgep->free_srbds[free_slot].rx_buf = NULL;
1442544Sgs150176 hw_rbd_p->host_buf_addr = RGE_BSWAP_32(rgep->head_room +
145744Sgs150176 + free_buf->pbuf.cookie.dmac_laddress);
146744Sgs150176 hw_rbd_p->host_buf_addr_hi =
147744Sgs150176 RGE_BSWAP_32(free_buf->pbuf.cookie.dmac_laddress >> 32);
148744Sgs150176 rgep->rf_next = NEXT(free_slot, RGE_BUF_SLOTS);
149744Sgs150176 return (1);
150744Sgs150176 } else {
151744Sgs150176 /*
152744Sgs150176 * This situation shouldn't happen
153744Sgs150176 */
154744Sgs150176 rge_problem(rgep, "rge_rx_refill: free buffer %d is NULL",
155744Sgs150176 free_slot);
156744Sgs150176 rgep->rx_bcopy = B_TRUE;
157744Sgs150176 return (0);
158744Sgs150176 }
159744Sgs150176 }
160744Sgs150176
161744Sgs150176 static mblk_t *rge_receive_packet(rge_t *rgep, uint32_t slot);
162744Sgs150176 #pragma inline(rge_receive_packet)
163744Sgs150176
164744Sgs150176 static mblk_t *
rge_receive_packet(rge_t * rgep,uint32_t slot)165744Sgs150176 rge_receive_packet(rge_t *rgep, uint32_t slot)
166744Sgs150176 {
167744Sgs150176 rge_bd_t *hw_rbd_p;
168744Sgs150176 sw_rbd_t *srbdp;
169744Sgs150176 uchar_t *dp;
170744Sgs150176 mblk_t *mp;
171744Sgs150176 uint8_t *rx_ptr;
172744Sgs150176 uint32_t rx_status;
173744Sgs150176 uint_t packet_len;
174744Sgs150176 uint_t minsize;
175744Sgs150176 uint_t maxsize;
176744Sgs150176 uint32_t proto;
177744Sgs150176 uint32_t pflags;
178744Sgs150176 struct ether_vlan_header *ehp;
179744Sgs150176 uint16_t vtag = 0;
180744Sgs150176
181744Sgs150176 hw_rbd_p = &rgep->rx_ring[slot];
182744Sgs150176 srbdp = &rgep->sw_rbds[slot];
183744Sgs150176
184744Sgs150176 /*
185744Sgs150176 * Read receive status
186744Sgs150176 */
187744Sgs150176 rx_status = RGE_BSWAP_32(hw_rbd_p->flags_len) & RBD_FLAGS_MASK;
188744Sgs150176
189744Sgs150176 /*
190744Sgs150176 * Handle error packet
191744Sgs150176 */
192744Sgs150176 if (!(rx_status & BD_FLAG_PKT_END)) {
193744Sgs150176 RGE_DEBUG(("rge_receive_packet: not a complete packat"));
194744Sgs150176 return (NULL);
195744Sgs150176 }
196744Sgs150176 if (rx_status & RBD_FLAG_ERROR) {
197744Sgs150176 if (rx_status & RBD_FLAG_CRC_ERR)
198744Sgs150176 rgep->stats.crc_err++;
199744Sgs150176 if (rx_status & RBD_FLAG_RUNT)
200744Sgs150176 rgep->stats.in_short++;
201744Sgs150176 /*
202744Sgs150176 * Set chip_error flag to reset chip:
203744Sgs150176 * (suggested in Realtek programming guide.)
204744Sgs150176 */
205744Sgs150176 RGE_DEBUG(("rge_receive_packet: error packet, status = %x",
206744Sgs150176 rx_status));
207744Sgs150176 mutex_enter(rgep->genlock);
208744Sgs150176 rgep->rge_chip_state = RGE_CHIP_ERROR;
209744Sgs150176 mutex_exit(rgep->genlock);
210744Sgs150176 return (NULL);
211744Sgs150176 }
212744Sgs150176
213744Sgs150176 /*
214744Sgs150176 * Handle size error packet
215744Sgs150176 */
2162544Sgs150176 packet_len = RGE_BSWAP_32(hw_rbd_p->flags_len) & RBD_LEN_MASK;
2172544Sgs150176 packet_len -= ETHERFCSL;
2182544Sgs150176 minsize = ETHERMIN;
2192544Sgs150176 pflags = RGE_BSWAP_32(hw_rbd_p->vlan_tag);
2202544Sgs150176 if (pflags & RBD_VLAN_PKT)
2212544Sgs150176 minsize -= VLAN_TAGSZ;
2222544Sgs150176 maxsize = rgep->ethmax_size;
223744Sgs150176 if (packet_len < minsize || packet_len > maxsize) {
224744Sgs150176 RGE_DEBUG(("rge_receive_packet: len err = %d", packet_len));
225744Sgs150176 return (NULL);
226744Sgs150176 }
227744Sgs150176
228744Sgs150176 DMA_SYNC(srbdp->rx_buf->pbuf, DDI_DMA_SYNC_FORKERNEL);
2292544Sgs150176 if (rgep->rx_bcopy || packet_len <= RGE_RECV_COPY_SIZE ||
230744Sgs150176 !rge_atomic_reserve(&rgep->rx_free, 1)) {
231744Sgs150176 /*
232744Sgs150176 * Allocate buffer to receive this good packet
233744Sgs150176 */
234744Sgs150176 mp = allocb(packet_len + RGE_HEADROOM, 0);
235744Sgs150176 if (mp == NULL) {
236744Sgs150176 RGE_DEBUG(("rge_receive_packet: allocate buffer fail"));
237744Sgs150176 rgep->stats.no_rcvbuf++;
238744Sgs150176 return (NULL);
239744Sgs150176 }
240744Sgs150176
241744Sgs150176 /*
242744Sgs150176 * Copy the data found into the new cluster
243744Sgs150176 */
244744Sgs150176 rx_ptr = DMA_VPTR(srbdp->rx_buf->pbuf);
245744Sgs150176 mp->b_rptr = dp = mp->b_rptr + RGE_HEADROOM;
2462544Sgs150176 bcopy(rx_ptr + rgep->head_room, dp, packet_len);
2472544Sgs150176 mp->b_wptr = dp + packet_len;
248744Sgs150176 } else {
249744Sgs150176 mp = srbdp->rx_buf->mp;
2502544Sgs150176 mp->b_rptr += rgep->head_room;
2512544Sgs150176 mp->b_wptr = mp->b_rptr + packet_len;
252744Sgs150176 mp->b_next = mp->b_cont = NULL;
253744Sgs150176 /*
254744Sgs150176 * Refill the current receive bd buffer
255744Sgs150176 * if fails, will just keep the mp.
256744Sgs150176 */
257744Sgs150176 if (!rge_rx_refill(rgep, slot))
258744Sgs150176 return (NULL);
259744Sgs150176 }
260744Sgs150176 rgep->stats.rbytes += packet_len;
2616410Smx205022 rgep->stats.rpackets ++;
262744Sgs150176
263744Sgs150176 /*
264744Sgs150176 * VLAN packet ?
265744Sgs150176 */
266744Sgs150176 if (pflags & RBD_VLAN_PKT)
267744Sgs150176 vtag = pflags & RBD_VLAN_TAG;
268744Sgs150176 if (vtag) {
269744Sgs150176 vtag = TCI_CHIP2OS(vtag);
270744Sgs150176 /*
271744Sgs150176 * As h/w strips the VLAN tag from incoming packet, we need
272744Sgs150176 * insert VLAN tag into this packet before send up here.
273744Sgs150176 */
274744Sgs150176 (void) memmove(mp->b_rptr - VLAN_TAGSZ, mp->b_rptr,
275744Sgs150176 2 * ETHERADDRL);
276744Sgs150176 mp->b_rptr -= VLAN_TAGSZ;
277744Sgs150176 ehp = (struct ether_vlan_header *)mp->b_rptr;
2782760Sdg199075 ehp->ether_tpid = htons(ETHERTYPE_VLAN);
279744Sgs150176 ehp->ether_tci = htons(vtag);
2802544Sgs150176 rgep->stats.rbytes += VLAN_TAGSZ;
281744Sgs150176 }
282744Sgs150176
283744Sgs150176 /*
284744Sgs150176 * Check h/w checksum offload status
285744Sgs150176 */
286744Sgs150176 pflags = 0;
287744Sgs150176 proto = rx_status & RBD_FLAG_PROTOCOL;
288744Sgs150176 if ((proto == RBD_FLAG_TCP && !(rx_status & RBD_TCP_CKSUM_ERR)) ||
289744Sgs150176 (proto == RBD_FLAG_UDP && !(rx_status & RBD_UDP_CKSUM_ERR)))
290*11878SVenu.Iyer@Sun.COM pflags |= HCK_FULLCKSUM_OK;
291744Sgs150176 if (proto != RBD_FLAG_NONE_IP && !(rx_status & RBD_IP_CKSUM_ERR))
292*11878SVenu.Iyer@Sun.COM pflags |= HCK_IPV4_HDRCKSUM_OK;
293744Sgs150176 if (pflags != 0) {
294*11878SVenu.Iyer@Sun.COM mac_hcksum_set(mp, 0, 0, 0, 0, pflags);
295744Sgs150176 }
296744Sgs150176
297744Sgs150176 return (mp);
298744Sgs150176 }
299744Sgs150176
300744Sgs150176 /*
301744Sgs150176 * Accept the packets received in rx ring.
302744Sgs150176 *
303744Sgs150176 * Returns a chain of mblks containing the received data, to be
304744Sgs150176 * passed up to mac_rx().
305744Sgs150176 * The routine returns only when a complete scan has been performed
306744Sgs150176 * without finding any packets to receive.
307744Sgs150176 * This function must SET the OWN bit of BD to indicate the packets
308744Sgs150176 * it has accepted from the ring.
309744Sgs150176 */
310744Sgs150176 static mblk_t *rge_receive_ring(rge_t *rgep);
311744Sgs150176 #pragma inline(rge_receive_ring)
312744Sgs150176
313744Sgs150176 static mblk_t *
rge_receive_ring(rge_t * rgep)314744Sgs150176 rge_receive_ring(rge_t *rgep)
315744Sgs150176 {
316744Sgs150176 rge_bd_t *hw_rbd_p;
317744Sgs150176 mblk_t *head;
318744Sgs150176 mblk_t **tail;
319744Sgs150176 mblk_t *mp;
320744Sgs150176 uint32_t slot;
321744Sgs150176
322744Sgs150176 ASSERT(mutex_owned(rgep->rx_lock));
323744Sgs150176
324744Sgs150176 /*
325744Sgs150176 * Sync (all) the receive ring descriptors
326744Sgs150176 * before accepting the packets they describe
327744Sgs150176 */
328744Sgs150176 DMA_SYNC(rgep->rx_desc, DDI_DMA_SYNC_FORKERNEL);
329744Sgs150176 slot = rgep->rx_next;
330744Sgs150176 hw_rbd_p = &rgep->rx_ring[slot];
331744Sgs150176 head = NULL;
332744Sgs150176 tail = &head;
333744Sgs150176
334744Sgs150176 while (!(hw_rbd_p->flags_len & RGE_BSWAP_32(BD_FLAG_HW_OWN))) {
335744Sgs150176 if ((mp = rge_receive_packet(rgep, slot)) != NULL) {
336744Sgs150176 *tail = mp;
337744Sgs150176 tail = &mp->b_next;
338744Sgs150176 }
339744Sgs150176
340744Sgs150176 /*
341744Sgs150176 * Clear RBD flags
342744Sgs150176 */
343744Sgs150176 hw_rbd_p->flags_len =
3442544Sgs150176 RGE_BSWAP_32(rgep->rxbuf_size - rgep->head_room);
345744Sgs150176 HW_RBD_INIT(hw_rbd_p, slot);
346744Sgs150176 slot = NEXT(slot, RGE_RECV_SLOTS);
347744Sgs150176 hw_rbd_p = &rgep->rx_ring[slot];
348744Sgs150176 }
349744Sgs150176
350744Sgs150176 rgep->rx_next = slot;
351744Sgs150176 return (head);
352744Sgs150176 }
353744Sgs150176
354744Sgs150176 /*
355744Sgs150176 * Receive all ready packets.
356744Sgs150176 */
357744Sgs150176 void rge_receive(rge_t *rgep);
358744Sgs150176 #pragma no_inline(rge_receive)
359744Sgs150176
360744Sgs150176 void
rge_receive(rge_t * rgep)361744Sgs150176 rge_receive(rge_t *rgep)
362744Sgs150176 {
363744Sgs150176 mblk_t *mp;
364744Sgs150176
365744Sgs150176 mutex_enter(rgep->rx_lock);
366744Sgs150176 mp = rge_receive_ring(rgep);
367744Sgs150176 mutex_exit(rgep->rx_lock);
368744Sgs150176
369744Sgs150176 if (mp != NULL)
3708275SEric Cheng mac_rx(rgep->mh, NULL, mp);
371744Sgs150176 }
372744Sgs150176
373744Sgs150176
374744Sgs150176 #undef RGE_DBG
375744Sgs150176 #define RGE_DBG RGE_DBG_SEND /* debug flag for this code */
376744Sgs150176
377744Sgs150176
378744Sgs150176 /*
379744Sgs150176 * ========== Send-side recycle routines ==========
380744Sgs150176 */
381744Sgs150176 static uint32_t rge_send_claim(rge_t *rgep);
382744Sgs150176 #pragma inline(rge_send_claim)
383744Sgs150176
384744Sgs150176 static uint32_t
rge_send_claim(rge_t * rgep)385744Sgs150176 rge_send_claim(rge_t *rgep)
386744Sgs150176 {
387744Sgs150176 uint32_t slot;
388744Sgs150176 uint32_t next;
389744Sgs150176
390744Sgs150176 mutex_enter(rgep->tx_lock);
391744Sgs150176 slot = rgep->tx_next;
392744Sgs150176 next = NEXT(slot, RGE_SEND_SLOTS);
393744Sgs150176 rgep->tx_next = next;
394744Sgs150176 rgep->tx_flow++;
395744Sgs150176 mutex_exit(rgep->tx_lock);
396744Sgs150176
397744Sgs150176 /*
398744Sgs150176 * We check that our invariants still hold:
399744Sgs150176 * + the slot and next indexes are in range
400744Sgs150176 * + the slot must not be the last one (i.e. the *next*
401744Sgs150176 * index must not match the next-recycle index), 'cos
402744Sgs150176 * there must always be at least one free slot in a ring
403744Sgs150176 */
404744Sgs150176 ASSERT(slot < RGE_SEND_SLOTS);
405744Sgs150176 ASSERT(next < RGE_SEND_SLOTS);
406744Sgs150176 ASSERT(next != rgep->tc_next);
407744Sgs150176
408744Sgs150176 return (slot);
409744Sgs150176 }
410744Sgs150176
411744Sgs150176 /*
412744Sgs150176 * We don't want to call this function every time after a successful
413744Sgs150176 * h/w transmit done in ISR. Instead, we call this function in the
414744Sgs150176 * rge_send() when there're few or no free tx BDs remained.
415744Sgs150176 */
41611410SLi-Zhen.You@Sun.COM void rge_send_recycle(rge_t *rgep);
417744Sgs150176 #pragma inline(rge_send_recycle)
418744Sgs150176
41911410SLi-Zhen.You@Sun.COM void
rge_send_recycle(rge_t * rgep)420744Sgs150176 rge_send_recycle(rge_t *rgep)
421744Sgs150176 {
422744Sgs150176 rge_bd_t *hw_sbd_p;
423744Sgs150176 uint32_t tc_tail;
424744Sgs150176 uint32_t tc_head;
425744Sgs150176 uint32_t n;
426744Sgs150176
427744Sgs150176 mutex_enter(rgep->tc_lock);
428744Sgs150176 tc_head = rgep->tc_next;
429744Sgs150176 tc_tail = rgep->tc_tail;
4302544Sgs150176 if (tc_head == tc_tail)
4312544Sgs150176 goto resched;
432744Sgs150176
433744Sgs150176 do {
434744Sgs150176 tc_tail = LAST(tc_tail, RGE_SEND_SLOTS);
435744Sgs150176 hw_sbd_p = &rgep->tx_ring[tc_tail];
436744Sgs150176 if (tc_tail == tc_head) {
437744Sgs150176 if (hw_sbd_p->flags_len &
438744Sgs150176 RGE_BSWAP_32(BD_FLAG_HW_OWN)) {
439744Sgs150176 /*
4402544Sgs150176 * Recyled nothing: bump the watchdog counter,
4412544Sgs150176 * thus guaranteeing that it's nonzero
4422544Sgs150176 * (watchdog activated).
443744Sgs150176 */
44411410SLi-Zhen.You@Sun.COM if (rgep->watchdog == 0)
44511410SLi-Zhen.You@Sun.COM 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
rge_send_copy(rge_t * rgep,mblk_t * mp,uint16_t tci)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;
5276990Sgd78059 mblen = MBLKL(bp);
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) {
5396990Sgd78059 mblen = MBLKL(bp);
540744Sgs150176 if ((totlen += mblen) <= rgep->ethmax_size) {
541744Sgs150176 bcopy(bp->b_rptr, txb, mblen);
542744Sgs150176 txb += mblen;
543744Sgs150176 }
544744Sgs150176 }
5452544Sgs150176 rgep->stats.obytes += totlen;
5466410Smx205022 rgep->stats.tx_pre_ismax = rgep->stats.tx_cur_ismax;
5476410Smx205022 if (totlen == rgep->ethmax_size)
5486410Smx205022 rgep->stats.tx_cur_ismax = B_TRUE;
5496410Smx205022 else
5506410Smx205022 rgep->stats.tx_cur_ismax = B_FALSE;
551744Sgs150176
552744Sgs150176 /*
553744Sgs150176 * We'e reached the end of the chain; and we should have
554744Sgs150176 * collected no more than ETHERMAX bytes into our buffer.
555744Sgs150176 */
556744Sgs150176 ASSERT(bp == NULL);
557744Sgs150176 ASSERT(totlen <= rgep->ethmax_size);
558744Sgs150176 DMA_SYNC(ssbdp->pbuf, DDI_DMA_SYNC_FORDEV);
559744Sgs150176
560744Sgs150176 /*
5612544Sgs150176 * Update the hardware send buffer descriptor flags
562744Sgs150176 */
563744Sgs150176 hw_sbd_p = &rgep->tx_ring[slot];
5642544Sgs150176 ASSERT(hw_sbd_p == ssbdp->desc.mem_va);
565744Sgs150176 hw_sbd_p->flags_len = RGE_BSWAP_32(totlen & SBD_LEN_MASK);
566744Sgs150176 if (tci != 0) {
567744Sgs150176 tci = TCI_OS2CHIP(tci);
568744Sgs150176 hw_sbd_p->vlan_tag = RGE_BSWAP_32(tci);
569744Sgs150176 hw_sbd_p->vlan_tag |= RGE_BSWAP_32(SBD_VLAN_PKT);
570744Sgs150176 } else {
571744Sgs150176 hw_sbd_p->vlan_tag = 0;
572744Sgs150176 }
573744Sgs150176
5742544Sgs150176 /*
5752544Sgs150176 * h/w checksum offload flags
5762544Sgs150176 */
577*11878SVenu.Iyer@Sun.COM mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &pflags);
578744Sgs150176 if (pflags & HCK_FULLCKSUM) {
5792544Sgs150176 ASSERT(totlen >= sizeof (struct ether_header) +
5802544Sgs150176 sizeof (struct ip));
5812544Sgs150176 ethhdr = (struct ether_header *)(DMA_VPTR(ssbdp->pbuf));
5822544Sgs150176 /*
5832544Sgs150176 * Is the packet an IP(v4) packet?
5842544Sgs150176 */
5852544Sgs150176 if (ntohs(ethhdr->ether_type) == ETHERTYPE_IP) {
5862544Sgs150176 ip_hdr = (struct ip *)
5872544Sgs150176 ((uint8_t *)DMA_VPTR(ssbdp->pbuf) +
5882544Sgs150176 sizeof (struct ether_header));
5892544Sgs150176 if (ip_hdr->ip_p == IPPROTO_TCP)
5902544Sgs150176 hw_sbd_p->flags_len |=
5912544Sgs150176 RGE_BSWAP_32(SBD_FLAG_TCP_CKSUM);
5922544Sgs150176 else if (ip_hdr->ip_p == IPPROTO_UDP)
5932544Sgs150176 hw_sbd_p->flags_len |=
5942544Sgs150176 RGE_BSWAP_32(SBD_FLAG_UDP_CKSUM);
595744Sgs150176 }
596744Sgs150176 }
5972544Sgs150176 if (pflags & HCK_IPV4_HDRCKSUM)
598744Sgs150176 hw_sbd_p->flags_len |= RGE_BSWAP_32(SBD_FLAG_IP_CKSUM);
599744Sgs150176
600744Sgs150176 HW_SBD_SET(hw_sbd_p, slot);
6012544Sgs150176
6022544Sgs150176 /*
6032544Sgs150176 * We're done.
6042544Sgs150176 * The message can be freed right away, as we've already
6052544Sgs150176 * copied the contents ...
6062544Sgs150176 */
6072544Sgs150176 freemsg(mp);
608744Sgs150176 }
609744Sgs150176
610744Sgs150176 static boolean_t
rge_send(rge_t * rgep,mblk_t * mp)611744Sgs150176 rge_send(rge_t *rgep, mblk_t *mp)
612744Sgs150176 {
613744Sgs150176 struct ether_vlan_header *ehp;
6142544Sgs150176 uint16_t tci;
615744Sgs150176
616744Sgs150176 ASSERT(mp->b_next == NULL);
617744Sgs150176
618744Sgs150176 /*
619744Sgs150176 * Try to reserve a place in the transmit ring.
620744Sgs150176 */
621744Sgs150176 if (!rge_atomic_reserve(&rgep->tx_free, 1)) {
622744Sgs150176 RGE_DEBUG(("rge_send: no free slots"));
623744Sgs150176 rgep->stats.defer++;
624744Sgs150176 rgep->resched_needed = B_TRUE;
625744Sgs150176 return (B_FALSE);
626744Sgs150176 }
627744Sgs150176
628744Sgs150176 /*
6292544Sgs150176 * Determine if the packet is VLAN tagged.
6302544Sgs150176 */
6312544Sgs150176 ASSERT(MBLKL(mp) >= sizeof (struct ether_header));
6322544Sgs150176 tci = 0;
6332544Sgs150176 ehp = (struct ether_vlan_header *)mp->b_rptr;
6342760Sdg199075 if (ehp->ether_tpid == htons(ETHERTYPE_VLAN))
6352544Sgs150176 tci = ntohs(ehp->ether_tci);
6362544Sgs150176
6372544Sgs150176 /*
638744Sgs150176 * We've reserved a place :-)
639744Sgs150176 * These ASSERTions check that our invariants still hold:
640744Sgs150176 * there must still be at least one free place
641744Sgs150176 * there must be at least one place NOT free (ours!)
642744Sgs150176 */
643744Sgs150176 ASSERT(rgep->tx_free < RGE_SEND_SLOTS);
6442544Sgs150176 rge_send_copy(rgep, mp, tci);
645744Sgs150176
646744Sgs150176 /*
647744Sgs150176 * Trigger chip h/w transmit ...
648744Sgs150176 */
649744Sgs150176 mutex_enter(rgep->tx_lock);
650744Sgs150176 if (--rgep->tx_flow == 0) {
651744Sgs150176 DMA_SYNC(rgep->tx_desc, DDI_DMA_SYNC_FORDEV);
652744Sgs150176 rgep->tc_tail = rgep->tx_next;
653744Sgs150176 }
65411365SZhen.W@Sun.COM rgep->stats.opackets++;
655744Sgs150176 mutex_exit(rgep->tx_lock);
656744Sgs150176
657744Sgs150176 return (B_TRUE);
658744Sgs150176 }
659744Sgs150176
660744Sgs150176 uint_t
rge_reschedule(caddr_t arg1,caddr_t arg2)6612544Sgs150176 rge_reschedule(caddr_t arg1, caddr_t arg2)
662744Sgs150176 {
663744Sgs150176 rge_t *rgep;
664744Sgs150176
6652544Sgs150176 rgep = (rge_t *)arg1;
6662544Sgs150176 _NOTE(ARGUNUSED(arg2))
667744Sgs150176
6682544Sgs150176 rge_send_recycle(rgep);
669744Sgs150176
67011365SZhen.W@Sun.COM if (rgep->chipid.is_pcie && rgep->tx_free != RGE_SEND_SLOTS) {
67111365SZhen.W@Sun.COM /*
67211365SZhen.W@Sun.COM * It's observed that in current Realtek PCI-E chips, tx
67311365SZhen.W@Sun.COM * request of the second fragment for upper layer packets
67411365SZhen.W@Sun.COM * will be ignored if the hardware transmission is in
67511365SZhen.W@Sun.COM * progress and will not be processed when the tx engine
67611365SZhen.W@Sun.COM * is idle. So one solution is to re-issue the requests
67711365SZhen.W@Sun.COM * if there are untransmitted packets after tx interrupts
67811365SZhen.W@Sun.COM * occur.
67911365SZhen.W@Sun.COM */
68011365SZhen.W@Sun.COM rge_tx_trigger(rgep);
68111365SZhen.W@Sun.COM }
68211365SZhen.W@Sun.COM
6832544Sgs150176 return (DDI_INTR_CLAIMED);
684744Sgs150176 }
685744Sgs150176
686744Sgs150176 /*
687744Sgs150176 * rge_m_tx() - send a chain of packets
688744Sgs150176 */
689744Sgs150176 mblk_t *
rge_m_tx(void * arg,mblk_t * mp)690744Sgs150176 rge_m_tx(void *arg, mblk_t *mp)
691744Sgs150176 {
692744Sgs150176 rge_t *rgep = arg; /* private device info */
693744Sgs150176 mblk_t *next;
69411365SZhen.W@Sun.COM mblk_t *mp_org = mp;
695744Sgs150176
696744Sgs150176 ASSERT(mp != NULL);
697744Sgs150176
6986764Smx205022 rw_enter(rgep->errlock, RW_READER);
6996764Smx205022 if ((rgep->rge_mac_state != RGE_MAC_STARTED) ||
70011499SZhen.W@Sun.COM (rgep->rge_chip_state != RGE_CHIP_RUNNING) ||
70111499SZhen.W@Sun.COM (rgep->param_link_up != LINK_STATE_UP)) {
70211499SZhen.W@Sun.COM rw_exit(rgep->errlock);
7036764Smx205022 RGE_DEBUG(("rge_m_tx: tx doesn't work"));
70411499SZhen.W@Sun.COM freemsgchain(mp);
70511499SZhen.W@Sun.COM return (NULL);
706744Sgs150176 }
707744Sgs150176
708744Sgs150176 while (mp != NULL) {
709744Sgs150176 next = mp->b_next;
710744Sgs150176 mp->b_next = NULL;
711744Sgs150176
712744Sgs150176 if (!rge_send(rgep, mp)) {
713744Sgs150176 mp->b_next = next;
714744Sgs150176 break;
715744Sgs150176 }
716744Sgs150176
717744Sgs150176 mp = next;
718744Sgs150176 }
71911365SZhen.W@Sun.COM if (mp != mp_org) {
72011365SZhen.W@Sun.COM rge_tx_trigger(rgep);
72111365SZhen.W@Sun.COM }
722744Sgs150176 rw_exit(rgep->errlock);
723744Sgs150176
724744Sgs150176 return (mp);
725744Sgs150176 }
726