11369Sdduvall /* 21369Sdduvall * CDDL HEADER START 31369Sdduvall * 41369Sdduvall * The contents of this file are subject to the terms of the 51369Sdduvall * Common Development and Distribution License (the "License"). 61369Sdduvall * You may not use this file except in compliance with the License. 71369Sdduvall * 81369Sdduvall * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91369Sdduvall * or http://www.opensolaris.org/os/licensing. 101369Sdduvall * See the License for the specific language governing permissions 111369Sdduvall * and limitations under the License. 121369Sdduvall * 131369Sdduvall * When distributing Covered Code, include this CDDL HEADER in each 141369Sdduvall * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151369Sdduvall * If applicable, add the following below this CDDL HEADER, with the 161369Sdduvall * fields enclosed by brackets "[]" replaced with your own identifying 171369Sdduvall * information: Portions Copyright [yyyy] [name of copyright owner] 181369Sdduvall * 191369Sdduvall * CDDL HEADER END 201369Sdduvall */ 211369Sdduvall 221369Sdduvall /* 23*11236SStephen.Hanson@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 241369Sdduvall * Use is subject to license terms. 251369Sdduvall */ 261369Sdduvall 272675Szh199473 #include "bge_impl.h" 281369Sdduvall 291369Sdduvall #define U32TOPTR(x) ((void *)(uintptr_t)(uint32_t)(x)) 301369Sdduvall #define PTRTOU32(x) ((uint32_t)(uintptr_t)(void *)(x)) 311369Sdduvall 321369Sdduvall /* 331369Sdduvall * ========== RX side routines ========== 341369Sdduvall */ 351369Sdduvall 361369Sdduvall #define BGE_DBG BGE_DBG_RECV /* debug flag for this code */ 371369Sdduvall 381369Sdduvall static void bge_refill(bge_t *bgep, buff_ring_t *brp, sw_rbd_t *srbdp); 391369Sdduvall #pragma inline(bge_refill) 401369Sdduvall 411369Sdduvall /* 421369Sdduvall * Return the specified buffer (srbdp) to the ring it came from (brp). 431369Sdduvall * 441369Sdduvall * Note: 451369Sdduvall * If the driver is compiled with only one buffer ring *and* one 461369Sdduvall * return ring, then the buffers must be returned in sequence. 471369Sdduvall * In this case, we don't have to consider anything about the 481369Sdduvall * buffer at all; we can simply advance the cyclic counter. And 491369Sdduvall * we don't even need the refill mutex <rf_lock>, as the caller 501369Sdduvall * will already be holding the (one-and-only) <rx_lock>. 511369Sdduvall * 521369Sdduvall * If the driver supports multiple buffer rings, but only one 531369Sdduvall * return ring, the same still applies (to each buffer ring 541369Sdduvall * separately). 551369Sdduvall */ 561369Sdduvall static void 571369Sdduvall bge_refill(bge_t *bgep, buff_ring_t *brp, sw_rbd_t *srbdp) 581369Sdduvall { 591369Sdduvall uint64_t slot; 601369Sdduvall 611369Sdduvall _NOTE(ARGUNUSED(srbdp)) 621369Sdduvall 631369Sdduvall slot = brp->rf_next; 641369Sdduvall brp->rf_next = NEXT(slot, brp->desc.nslots); 651369Sdduvall bge_mbx_put(bgep, brp->chip_mbx_reg, slot); 661369Sdduvall } 671369Sdduvall 681369Sdduvall static mblk_t *bge_receive_packet(bge_t *bgep, bge_rbd_t *hw_rbd_p); 691369Sdduvall #pragma inline(bge_receive_packet) 701369Sdduvall 711369Sdduvall static mblk_t * 721369Sdduvall bge_receive_packet(bge_t *bgep, bge_rbd_t *hw_rbd_p) 731369Sdduvall { 741369Sdduvall bge_rbd_t hw_rbd; 751369Sdduvall buff_ring_t *brp; 761369Sdduvall sw_rbd_t *srbdp; 771369Sdduvall uchar_t *dp; 781369Sdduvall mblk_t *mp; 791369Sdduvall uint_t len; 801369Sdduvall uint_t minsize; 811369Sdduvall uint_t maxsize; 821369Sdduvall uint32_t pflags; 831369Sdduvall 841369Sdduvall mp = NULL; 851369Sdduvall hw_rbd = *hw_rbd_p; 861369Sdduvall 871369Sdduvall switch (hw_rbd.flags & (RBD_FLAG_MINI_RING|RBD_FLAG_JUMBO_RING)) { 881369Sdduvall case RBD_FLAG_MINI_RING|RBD_FLAG_JUMBO_RING: 891369Sdduvall default: 901369Sdduvall /* error, this shouldn't happen */ 911369Sdduvall BGE_PKTDUMP((bgep, &hw_rbd, NULL, "bad ring flags!")); 921369Sdduvall goto error; 931369Sdduvall 941369Sdduvall case RBD_FLAG_JUMBO_RING: 951369Sdduvall brp = &bgep->buff[BGE_JUMBO_BUFF_RING]; 961369Sdduvall break; 971369Sdduvall 981369Sdduvall #if (BGE_BUFF_RINGS_USED > 2) 991369Sdduvall case RBD_FLAG_MINI_RING: 1001369Sdduvall brp = &bgep->buff[BGE_MINI_BUFF_RING]; 1011369Sdduvall break; 1021369Sdduvall #endif /* BGE_BUFF_RINGS_USED > 2 */ 1031369Sdduvall 1041369Sdduvall case 0: 1051369Sdduvall brp = &bgep->buff[BGE_STD_BUFF_RING]; 1061369Sdduvall break; 1071369Sdduvall } 1081369Sdduvall 1091369Sdduvall if (hw_rbd.index >= brp->desc.nslots) { 1101369Sdduvall /* error, this shouldn't happen */ 1111369Sdduvall BGE_PKTDUMP((bgep, &hw_rbd, NULL, "bad ring index!")); 1121369Sdduvall goto error; 1131369Sdduvall } 1141369Sdduvall 1151369Sdduvall srbdp = &brp->sw_rbds[hw_rbd.index]; 1161369Sdduvall if (hw_rbd.opaque != srbdp->pbuf.token) { 1171369Sdduvall /* bogus, drop the packet */ 1181369Sdduvall BGE_PKTDUMP((bgep, &hw_rbd, srbdp, "bad ring token")); 1191369Sdduvall goto refill; 1201369Sdduvall } 1211369Sdduvall 1221369Sdduvall if ((hw_rbd.flags & RBD_FLAG_PACKET_END) == 0) { 1231369Sdduvall /* bogus, drop the packet */ 1241369Sdduvall BGE_PKTDUMP((bgep, &hw_rbd, srbdp, "unterminated packet")); 1251369Sdduvall goto refill; 1261369Sdduvall } 1271369Sdduvall 1281369Sdduvall if (hw_rbd.flags & RBD_FLAG_FRAME_HAS_ERROR) { 1291369Sdduvall /* bogus, drop the packet */ 1301369Sdduvall BGE_PKTDUMP((bgep, &hw_rbd, srbdp, "errored packet")); 1311369Sdduvall goto refill; 1321369Sdduvall } 1331369Sdduvall 1341369Sdduvall len = hw_rbd.len; 1351369Sdduvall 1361408Srandyf #ifdef BGE_IPMI_ASF 1371369Sdduvall /* 1381408Srandyf * When IPMI/ASF is enabled, VLAN tag must be stripped. 1391369Sdduvall */ 1401408Srandyf if (bgep->asf_enabled && (hw_rbd.flags & RBD_FLAG_VLAN_TAG)) 1411408Srandyf maxsize = bgep->chipid.ethmax_size + ETHERFCSL; 1421408Srandyf else 1431408Srandyf #endif 1441408Srandyf /* 1451408Srandyf * H/W will not strip the VLAN tag from incoming packet 1461408Srandyf * now, as RECEIVE_MODE_KEEP_VLAN_TAG bit is set in 1471408Srandyf * RECEIVE_MAC_MODE_REG register. 1481408Srandyf */ 1491408Srandyf maxsize = bgep->chipid.ethmax_size + VLAN_TAGSZ + ETHERFCSL; 1501369Sdduvall if (len > maxsize) { 1511369Sdduvall /* bogus, drop the packet */ 1521369Sdduvall BGE_PKTDUMP((bgep, &hw_rbd, srbdp, "oversize packet")); 1531369Sdduvall goto refill; 1541369Sdduvall } 1551369Sdduvall 1561408Srandyf #ifdef BGE_IPMI_ASF 1571408Srandyf if (bgep->asf_enabled && (hw_rbd.flags & RBD_FLAG_VLAN_TAG)) 1581408Srandyf minsize = ETHERMIN + ETHERFCSL - VLAN_TAGSZ; 1591408Srandyf else 1601408Srandyf #endif 1611408Srandyf minsize = ETHERMIN + ETHERFCSL; 1621369Sdduvall if (len < minsize) { 1631369Sdduvall /* bogus, drop the packet */ 1641369Sdduvall BGE_PKTDUMP((bgep, &hw_rbd, srbdp, "undersize packet")); 1651369Sdduvall goto refill; 1661369Sdduvall } 1671369Sdduvall 1681369Sdduvall /* 1691369Sdduvall * Packet looks good; get a buffer to copy it into. 1701369Sdduvall * We want to leave some space at the front of the allocated 1711369Sdduvall * buffer in case any upstream modules want to prepend some 1721369Sdduvall * sort of header. This also has the side-effect of making 1731369Sdduvall * the packet *contents* 4-byte aligned, as required by NCA! 1741369Sdduvall */ 1751408Srandyf #ifdef BGE_IPMI_ASF 1761408Srandyf if (bgep->asf_enabled && (hw_rbd.flags & RBD_FLAG_VLAN_TAG)) { 1771408Srandyf mp = allocb(BGE_HEADROOM + len + VLAN_TAGSZ, 0); 1781408Srandyf } else { 1791408Srandyf #endif 1801408Srandyf 1811408Srandyf mp = allocb(BGE_HEADROOM + len, 0); 1821408Srandyf #ifdef BGE_IPMI_ASF 1831408Srandyf } 1841408Srandyf #endif 1851369Sdduvall if (mp == NULL) { 1861369Sdduvall /* Nothing to do but drop the packet */ 1871369Sdduvall goto refill; 1881369Sdduvall } 1891369Sdduvall 1901369Sdduvall /* 1911369Sdduvall * Sync the data and copy it to the STREAMS buffer. 1921369Sdduvall */ 1931369Sdduvall DMA_SYNC(srbdp->pbuf, DDI_DMA_SYNC_FORKERNEL); 1941865Sdilpreet if (bge_check_dma_handle(bgep, srbdp->pbuf.dma_hdl) != DDI_FM_OK) { 1951865Sdilpreet bgep->bge_dma_error = B_TRUE; 1961865Sdilpreet bgep->bge_chip_state = BGE_CHIP_ERROR; 1971865Sdilpreet return (NULL); 1981865Sdilpreet } 1991408Srandyf #ifdef BGE_IPMI_ASF 2001408Srandyf if (bgep->asf_enabled && (hw_rbd.flags & RBD_FLAG_VLAN_TAG)) { 2011408Srandyf /* 2021408Srandyf * As VLAN tag has been stripped from incoming packet in ASF 2031408Srandyf * scenario, we insert it into this packet again. 2041408Srandyf */ 2051408Srandyf struct ether_vlan_header *ehp; 2061408Srandyf mp->b_rptr = dp = mp->b_rptr + BGE_HEADROOM - VLAN_TAGSZ; 2071408Srandyf bcopy(DMA_VPTR(srbdp->pbuf), dp, 2 * ETHERADDRL); 2087099Syt223700 ehp = (void *)dp; 2092760Sdg199075 ehp->ether_tpid = ntohs(ETHERTYPE_VLAN); 2101408Srandyf ehp->ether_tci = ntohs(hw_rbd.vlan_tci); 2111408Srandyf bcopy(((uchar_t *)(DMA_VPTR(srbdp->pbuf))) + 2 * ETHERADDRL, 2125903Ssowmini dp + 2 * ETHERADDRL + VLAN_TAGSZ, 2135903Ssowmini len - 2 * ETHERADDRL); 2141408Srandyf } else { 2151408Srandyf #endif 2161408Srandyf mp->b_rptr = dp = mp->b_rptr + BGE_HEADROOM; 2171408Srandyf bcopy(DMA_VPTR(srbdp->pbuf), dp, len); 2181408Srandyf #ifdef BGE_IPMI_ASF 2191408Srandyf } 2201408Srandyf 2211408Srandyf if (bgep->asf_enabled && (hw_rbd.flags & RBD_FLAG_VLAN_TAG)) { 2221408Srandyf mp->b_wptr = dp + len + VLAN_TAGSZ - ETHERFCSL; 2231408Srandyf } else 2241408Srandyf #endif 2251408Srandyf mp->b_wptr = dp + len - ETHERFCSL; 2261369Sdduvall 2271369Sdduvall /* 2281369Sdduvall * Special check for one specific type of data corruption; 2291369Sdduvall * in a good packet, the first 8 bytes are *very* unlikely 2301369Sdduvall * to be the same as the second 8 bytes ... but we let the 2311369Sdduvall * packet through just in case. 2321369Sdduvall */ 2331369Sdduvall if (bcmp(dp, dp+8, 8) == 0) 2341369Sdduvall BGE_PKTDUMP((bgep, &hw_rbd, srbdp, "stuttered packet?")); 2351369Sdduvall 2361369Sdduvall pflags = 0; 2371369Sdduvall if (hw_rbd.flags & RBD_FLAG_TCP_UDP_CHECKSUM) 2381369Sdduvall pflags |= HCK_FULLCKSUM; 2391369Sdduvall if (hw_rbd.flags & RBD_FLAG_IP_CHECKSUM) 2401369Sdduvall pflags |= HCK_IPV4_HDRCKSUM; 2411369Sdduvall if (pflags != 0) 2421369Sdduvall (void) hcksum_assoc(mp, NULL, NULL, 0, 0, 0, 2431369Sdduvall hw_rbd.tcp_udp_cksum, pflags, 0); 2441369Sdduvall 2451369Sdduvall refill: 2461369Sdduvall /* 2471369Sdduvall * Replace the buffer in the ring it came from ... 2481369Sdduvall */ 2491369Sdduvall bge_refill(bgep, brp, srbdp); 2501369Sdduvall return (mp); 2511369Sdduvall 2521369Sdduvall error: 2531369Sdduvall /* 2541369Sdduvall * We come here if the integrity of the ring descriptors 2551369Sdduvall * (rather than merely packet data) appears corrupted. 2561369Sdduvall * The factotum will attempt to reset-and-recover. 2571369Sdduvall */ 2581369Sdduvall bgep->bge_chip_state = BGE_CHIP_ERROR; 2591865Sdilpreet bge_fm_ereport(bgep, DDI_FM_DEVICE_INVAL_STATE); 2601369Sdduvall return (NULL); 2611369Sdduvall } 2621369Sdduvall 2631369Sdduvall /* 2641369Sdduvall * Accept the packets received in the specified ring up to 2651369Sdduvall * (but not including) the producer index in the status block. 2661369Sdduvall * 2671369Sdduvall * Returns a chain of mblks containing the received data, to be 2681369Sdduvall * passed up to gld_recv() (we can't call gld_recv() from here, 2691369Sdduvall * 'cos we're holding the per-ring receive lock at this point). 2701369Sdduvall * 2711369Sdduvall * This function must advance (rrp->rx_next) and write it back to 2721369Sdduvall * the chip to indicate the packets it has accepted from the ring. 2731369Sdduvall */ 2741369Sdduvall static mblk_t *bge_receive_ring(bge_t *bgep, recv_ring_t *rrp); 2758275SEric Cheng #ifndef DEBUG 2761369Sdduvall #pragma inline(bge_receive_ring) 2778275SEric Cheng #endif 2781369Sdduvall 2791369Sdduvall static mblk_t * 2801369Sdduvall bge_receive_ring(bge_t *bgep, recv_ring_t *rrp) 2811369Sdduvall { 2821369Sdduvall bge_rbd_t *hw_rbd_p; 2831369Sdduvall uint64_t slot; 2841369Sdduvall mblk_t *head; 2851369Sdduvall mblk_t **tail; 2861369Sdduvall mblk_t *mp; 2873918Sml149210 int recv_cnt = 0; 2881369Sdduvall 2891369Sdduvall ASSERT(mutex_owned(rrp->rx_lock)); 2901369Sdduvall 2911369Sdduvall /* 2921369Sdduvall * Sync (all) the receive ring descriptors 2931369Sdduvall * before accepting the packets they describe 2941369Sdduvall */ 2951369Sdduvall DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORKERNEL); 2961865Sdilpreet if (*rrp->prod_index_p >= rrp->desc.nslots) { 2971865Sdilpreet bgep->bge_chip_state = BGE_CHIP_ERROR; 2981865Sdilpreet bge_fm_ereport(bgep, DDI_FM_DEVICE_INVAL_STATE); 2991865Sdilpreet return (NULL); 3001865Sdilpreet } 3011865Sdilpreet if (bge_check_dma_handle(bgep, rrp->desc.dma_hdl) != DDI_FM_OK) { 3021865Sdilpreet rrp->rx_next = *rrp->prod_index_p; 3031865Sdilpreet bge_mbx_put(bgep, rrp->chip_mbx_reg, rrp->rx_next); 3041865Sdilpreet bgep->bge_dma_error = B_TRUE; 3051865Sdilpreet bgep->bge_chip_state = BGE_CHIP_ERROR; 3061865Sdilpreet return (NULL); 3071865Sdilpreet } 3081865Sdilpreet 3091369Sdduvall hw_rbd_p = DMA_VPTR(rrp->desc); 3101369Sdduvall head = NULL; 3111369Sdduvall tail = &head; 3121369Sdduvall slot = rrp->rx_next; 3131369Sdduvall 3143918Sml149210 while ((slot != *rrp->prod_index_p) && /* Note: volatile */ 3155903Ssowmini (recv_cnt < BGE_MAXPKT_RCVED)) { 3161369Sdduvall if ((mp = bge_receive_packet(bgep, &hw_rbd_p[slot])) != NULL) { 3171369Sdduvall *tail = mp; 3181369Sdduvall tail = &mp->b_next; 3193918Sml149210 recv_cnt++; 3201369Sdduvall } 3211369Sdduvall rrp->rx_next = slot = NEXT(slot, rrp->desc.nslots); 3221369Sdduvall } 3231369Sdduvall 3241369Sdduvall bge_mbx_put(bgep, rrp->chip_mbx_reg, rrp->rx_next); 3251865Sdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 3261865Sdilpreet bgep->bge_chip_state = BGE_CHIP_ERROR; 3271369Sdduvall return (head); 3281369Sdduvall } 3291369Sdduvall 3301369Sdduvall /* 3318275SEric Cheng * XXX: Poll a particular ring. The implementation is incomplete. 3328275SEric Cheng * Once the ring interrupts are disabled, we need to do bge_recyle() 3338275SEric Cheng * for the ring as well and re enable the ring interrupt automatically 3348275SEric Cheng * if the poll doesn't find any packets in the ring. We need to 3358275SEric Cheng * have MSI-X interrupts support for this. 3361369Sdduvall * 3378275SEric Cheng * The basic poll policy is that rings that are dealing with explicit 3388275SEric Cheng * flows (like TCP or some service) and are marked as such should 3398275SEric Cheng * have their own MSI-X interrupt per ring. bge_intr() should leave 3408275SEric Cheng * that interrupt disabled after an upcall. The ring is in poll mode. 3418275SEric Cheng * When a poll thread comes down and finds nothing, the MSI-X interrupt 3428275SEric Cheng * is automatically enabled. Squeue needs to deal with the race of 3438275SEric Cheng * a new interrupt firing and reaching before poll thread returns. 3448275SEric Cheng */ 3458275SEric Cheng mblk_t * 3468275SEric Cheng bge_poll_ring(void *arg, int bytes_to_pickup) 3478275SEric Cheng { 3488275SEric Cheng recv_ring_t *rrp = arg; 3498275SEric Cheng bge_t *bgep = rrp->bgep; 3508275SEric Cheng bge_rbd_t *hw_rbd_p; 3518275SEric Cheng uint64_t slot; 3528275SEric Cheng mblk_t *head; 3538275SEric Cheng mblk_t **tail; 3548275SEric Cheng mblk_t *mp; 3558275SEric Cheng size_t sz = 0; 3568275SEric Cheng 3578275SEric Cheng mutex_enter(rrp->rx_lock); 3588275SEric Cheng 3598275SEric Cheng /* 3608275SEric Cheng * Sync (all) the receive ring descriptors 3618275SEric Cheng * before accepting the packets they describe 3628275SEric Cheng */ 3638275SEric Cheng DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORKERNEL); 364*11236SStephen.Hanson@Sun.COM if (*rrp->prod_index_p >= rrp->desc.nslots) { 365*11236SStephen.Hanson@Sun.COM bgep->bge_chip_state = BGE_CHIP_ERROR; 366*11236SStephen.Hanson@Sun.COM bge_fm_ereport(bgep, DDI_FM_DEVICE_INVAL_STATE); 367*11236SStephen.Hanson@Sun.COM mutex_exit(rrp->rx_lock); 368*11236SStephen.Hanson@Sun.COM return (NULL); 369*11236SStephen.Hanson@Sun.COM } 370*11236SStephen.Hanson@Sun.COM if (bge_check_dma_handle(bgep, rrp->desc.dma_hdl) != DDI_FM_OK) { 371*11236SStephen.Hanson@Sun.COM rrp->rx_next = *rrp->prod_index_p; 372*11236SStephen.Hanson@Sun.COM bge_mbx_put(bgep, rrp->chip_mbx_reg, rrp->rx_next); 373*11236SStephen.Hanson@Sun.COM bgep->bge_dma_error = B_TRUE; 374*11236SStephen.Hanson@Sun.COM bgep->bge_chip_state = BGE_CHIP_ERROR; 375*11236SStephen.Hanson@Sun.COM mutex_exit(rrp->rx_lock); 376*11236SStephen.Hanson@Sun.COM return (NULL); 377*11236SStephen.Hanson@Sun.COM } 378*11236SStephen.Hanson@Sun.COM 3798275SEric Cheng hw_rbd_p = DMA_VPTR(rrp->desc); 3808275SEric Cheng head = NULL; 3818275SEric Cheng tail = &head; 3828275SEric Cheng slot = rrp->rx_next; 3838275SEric Cheng 3848275SEric Cheng /* Note: volatile */ 3858275SEric Cheng while ((slot != *rrp->prod_index_p) && (sz <= bytes_to_pickup)) { 3868275SEric Cheng if ((mp = bge_receive_packet(bgep, &hw_rbd_p[slot])) != NULL) { 3878275SEric Cheng *tail = mp; 3888275SEric Cheng sz += msgdsize(mp); 3898275SEric Cheng tail = &mp->b_next; 3908275SEric Cheng } 3918275SEric Cheng rrp->rx_next = slot = NEXT(slot, rrp->desc.nslots); 3928275SEric Cheng } 3938275SEric Cheng 3948275SEric Cheng bge_mbx_put(bgep, rrp->chip_mbx_reg, rrp->rx_next); 395*11236SStephen.Hanson@Sun.COM if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) 396*11236SStephen.Hanson@Sun.COM bgep->bge_chip_state = BGE_CHIP_ERROR; 3978275SEric Cheng mutex_exit(rrp->rx_lock); 3988275SEric Cheng return (head); 3998275SEric Cheng } 4008275SEric Cheng 4018275SEric Cheng /* 4028275SEric Cheng * Receive all packets in all rings. 4031369Sdduvall */ 4041369Sdduvall void bge_receive(bge_t *bgep, bge_status_t *bsp); 4051369Sdduvall #pragma no_inline(bge_receive) 4061369Sdduvall 4071369Sdduvall void 4081369Sdduvall bge_receive(bge_t *bgep, bge_status_t *bsp) 4091369Sdduvall { 4101369Sdduvall recv_ring_t *rrp; 4118275SEric Cheng uint64_t index; 4121369Sdduvall mblk_t *mp; 4131369Sdduvall 4148275SEric Cheng for (index = 0; index < bgep->chipid.rx_rings; index++) { 4158275SEric Cheng /* 4168275SEric Cheng * Start from the first ring. 4178275SEric Cheng */ 4188275SEric Cheng rrp = &bgep->recv[index]; 4198275SEric Cheng 4201369Sdduvall /* 4211369Sdduvall * For each ring, (rrp->prod_index_p) points to the 4221369Sdduvall * proper index within the status block (which has 4231369Sdduvall * already been sync'd by the caller) 4241369Sdduvall */ 4258275SEric Cheng ASSERT(rrp->prod_index_p == RECV_INDEX_P(bsp, index)); 4261369Sdduvall 4278275SEric Cheng if (*rrp->prod_index_p == rrp->rx_next || rrp->poll_flag) 4281369Sdduvall continue; /* no packets */ 4291369Sdduvall if (mutex_tryenter(rrp->rx_lock) == 0) 4301369Sdduvall continue; /* already in process */ 4311369Sdduvall mp = bge_receive_ring(bgep, rrp); 4321369Sdduvall mutex_exit(rrp->rx_lock); 4331369Sdduvall 4348275SEric Cheng if (mp != NULL) 4358275SEric Cheng mac_rx_ring(bgep->mh, rrp->ring_handle, mp, 4368275SEric Cheng rrp->ring_gen_num); 4378275SEric Cheng } 4381369Sdduvall } 439