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 /* 22*11499SZhen.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 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 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 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 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 * 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))) 290744Sgs150176 pflags |= HCK_FULLCKSUM | HCK_FULLCKSUM_OK; 291744Sgs150176 if (proto != RBD_FLAG_NONE_IP && !(rx_status & RBD_IP_CKSUM_ERR)) 292744Sgs150176 pflags |= HCK_IPV4_HDRCKSUM; 293744Sgs150176 if (pflags != 0) { 294744Sgs150176 (void) hcksum_assoc(mp, NULL, NULL, 0, 0, 0, 0, pflags, 0); 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 * 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 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 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 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 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 */ 577744Sgs150176 hcksum_retrieve(mp, NULL, NULL, 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 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 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 * 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) || 700*11499SZhen.W@Sun.COM (rgep->rge_chip_state != RGE_CHIP_RUNNING) || 701*11499SZhen.W@Sun.COM (rgep->param_link_up != LINK_STATE_UP)) { 702*11499SZhen.W@Sun.COM rw_exit(rgep->errlock); 7036764Smx205022 RGE_DEBUG(("rge_m_tx: tx doesn't work")); 704*11499SZhen.W@Sun.COM freemsgchain(mp); 705*11499SZhen.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