15779Sxy150489 /*
25779Sxy150489 * CDDL HEADER START
35779Sxy150489 *
48571SChenlu.Chen@Sun.COM * Copyright(c) 2007-2009 Intel Corporation. All rights reserved.
55779Sxy150489 * The contents of this file are subject to the terms of the
65779Sxy150489 * Common Development and Distribution License (the "License").
75779Sxy150489 * You may not use this file except in compliance with the License.
85779Sxy150489 *
9*11878SVenu.Iyer@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*11878SVenu.Iyer@Sun.COM * or http://www.opensolaris.org/os/licensing.
115779Sxy150489 * See the License for the specific language governing permissions
125779Sxy150489 * and limitations under the License.
135779Sxy150489 *
14*11878SVenu.Iyer@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
15*11878SVenu.Iyer@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
165779Sxy150489 * If applicable, add the following below this CDDL HEADER, with the
175779Sxy150489 * fields enclosed by brackets "[]" replaced with your own identifying
185779Sxy150489 * information: Portions Copyright [yyyy] [name of copyright owner]
195779Sxy150489 *
205779Sxy150489 * CDDL HEADER END
215779Sxy150489 */
225779Sxy150489
235779Sxy150489 /*
2411502SChenlu.Chen@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
25*11878SVenu.Iyer@Sun.COM * Use is subject to license terms.
268275SEric Cheng */
275779Sxy150489
285779Sxy150489 #include "igb_sw.h"
295779Sxy150489
305779Sxy150489 /* function prototypes */
3111502SChenlu.Chen@Sun.COM static mblk_t *igb_rx_bind(igb_rx_data_t *, uint32_t, uint32_t);
3211502SChenlu.Chen@Sun.COM static mblk_t *igb_rx_copy(igb_rx_data_t *, uint32_t, uint32_t);
335779Sxy150489 static void igb_rx_assoc_hcksum(mblk_t *, uint32_t);
345779Sxy150489
355779Sxy150489 #ifndef IGB_DEBUG
365779Sxy150489 #pragma inline(igb_rx_assoc_hcksum)
375779Sxy150489 #endif
385779Sxy150489
395779Sxy150489
405779Sxy150489 /*
415779Sxy150489 * igb_rx_recycle - the call-back function to reclaim rx buffer
425779Sxy150489 *
435779Sxy150489 * This function is called when an mp is freed by the user thru
445779Sxy150489 * freeb call (Only for mp constructed through desballoc call).
455779Sxy150489 * It returns back the freed buffer to the free list.
465779Sxy150489 */
475779Sxy150489 void
igb_rx_recycle(caddr_t arg)485779Sxy150489 igb_rx_recycle(caddr_t arg)
495779Sxy150489 {
5011502SChenlu.Chen@Sun.COM igb_t *igb;
515779Sxy150489 igb_rx_ring_t *rx_ring;
5211502SChenlu.Chen@Sun.COM igb_rx_data_t *rx_data;
535779Sxy150489 rx_control_block_t *recycle_rcb;
545779Sxy150489 uint32_t free_index;
5511502SChenlu.Chen@Sun.COM uint32_t ref_cnt;
565779Sxy150489
575779Sxy150489 recycle_rcb = (rx_control_block_t *)(uintptr_t)arg;
5811502SChenlu.Chen@Sun.COM rx_data = recycle_rcb->rx_data;
5911502SChenlu.Chen@Sun.COM rx_ring = rx_data->rx_ring;
6011502SChenlu.Chen@Sun.COM igb = rx_ring->igb;
615779Sxy150489
6211502SChenlu.Chen@Sun.COM if (recycle_rcb->ref_cnt == 0) {
6311502SChenlu.Chen@Sun.COM /*
6411502SChenlu.Chen@Sun.COM * This case only happens when rx buffers are being freed
6511502SChenlu.Chen@Sun.COM * in igb_stop() and freemsg() is called.
6611502SChenlu.Chen@Sun.COM */
675779Sxy150489 return;
6811502SChenlu.Chen@Sun.COM }
695779Sxy150489
705779Sxy150489 ASSERT(recycle_rcb->mp == NULL);
715779Sxy150489
725779Sxy150489 /*
735779Sxy150489 * Using the recycled data buffer to generate a new mblk
745779Sxy150489 */
755779Sxy150489 recycle_rcb->mp = desballoc((unsigned char *)
768571SChenlu.Chen@Sun.COM recycle_rcb->rx_buf.address,
778571SChenlu.Chen@Sun.COM recycle_rcb->rx_buf.size,
785779Sxy150489 0, &recycle_rcb->free_rtn);
795779Sxy150489
805779Sxy150489 /*
815779Sxy150489 * Put the recycled rx control block into free list
825779Sxy150489 */
8311502SChenlu.Chen@Sun.COM mutex_enter(&rx_data->recycle_lock);
845779Sxy150489
8511502SChenlu.Chen@Sun.COM free_index = rx_data->rcb_tail;
8611502SChenlu.Chen@Sun.COM ASSERT(rx_data->free_list[free_index] == NULL);
875779Sxy150489
8811502SChenlu.Chen@Sun.COM rx_data->free_list[free_index] = recycle_rcb;
8911502SChenlu.Chen@Sun.COM rx_data->rcb_tail = NEXT_INDEX(free_index, 1, rx_data->free_list_size);
905779Sxy150489
9111502SChenlu.Chen@Sun.COM mutex_exit(&rx_data->recycle_lock);
925779Sxy150489
935779Sxy150489 /*
945779Sxy150489 * The atomic operation on the number of the available rx control
955779Sxy150489 * blocks in the free list is used to make the recycling mutual
965779Sxy150489 * exclusive with the receiving.
975779Sxy150489 */
9811502SChenlu.Chen@Sun.COM atomic_inc_32(&rx_data->rcb_free);
9911502SChenlu.Chen@Sun.COM ASSERT(rx_data->rcb_free <= rx_data->free_list_size);
10011502SChenlu.Chen@Sun.COM
10111502SChenlu.Chen@Sun.COM /*
10211502SChenlu.Chen@Sun.COM * Considering the case that the interface is unplumbed
10311502SChenlu.Chen@Sun.COM * and there are still some buffers held by the upper layer.
10411502SChenlu.Chen@Sun.COM * When the buffer is returned back, we need to free it.
10511502SChenlu.Chen@Sun.COM */
10611502SChenlu.Chen@Sun.COM ref_cnt = atomic_dec_32_nv(&recycle_rcb->ref_cnt);
10711502SChenlu.Chen@Sun.COM if (ref_cnt == 0) {
10811502SChenlu.Chen@Sun.COM if (recycle_rcb->mp != NULL) {
10911502SChenlu.Chen@Sun.COM freemsg(recycle_rcb->mp);
11011502SChenlu.Chen@Sun.COM recycle_rcb->mp = NULL;
11111502SChenlu.Chen@Sun.COM }
11211502SChenlu.Chen@Sun.COM
11311502SChenlu.Chen@Sun.COM igb_free_dma_buffer(&recycle_rcb->rx_buf);
11411502SChenlu.Chen@Sun.COM
11511502SChenlu.Chen@Sun.COM mutex_enter(&igb->rx_pending_lock);
11611502SChenlu.Chen@Sun.COM atomic_dec_32(&rx_data->rcb_pending);
11711502SChenlu.Chen@Sun.COM atomic_dec_32(&igb->rcb_pending);
11811502SChenlu.Chen@Sun.COM
11911502SChenlu.Chen@Sun.COM /*
12011502SChenlu.Chen@Sun.COM * When there is not any buffer belonging to this rx_data
12111502SChenlu.Chen@Sun.COM * held by the upper layer, the rx_data can be freed.
12211502SChenlu.Chen@Sun.COM */
12311502SChenlu.Chen@Sun.COM if ((rx_data->flag & IGB_RX_STOPPED) &&
12411502SChenlu.Chen@Sun.COM (rx_data->rcb_pending == 0))
12511502SChenlu.Chen@Sun.COM igb_free_rx_ring_data(rx_data);
12611502SChenlu.Chen@Sun.COM
12711502SChenlu.Chen@Sun.COM mutex_exit(&igb->rx_pending_lock);
12811502SChenlu.Chen@Sun.COM }
1295779Sxy150489 }
1305779Sxy150489
1315779Sxy150489 /*
1325779Sxy150489 * igb_rx_copy - Use copy to process the received packet
1335779Sxy150489 *
1345779Sxy150489 * This function will use bcopy to process the packet
1355779Sxy150489 * and send the copied packet upstream
1365779Sxy150489 */
1375779Sxy150489 static mblk_t *
igb_rx_copy(igb_rx_data_t * rx_data,uint32_t index,uint32_t pkt_len)13811502SChenlu.Chen@Sun.COM igb_rx_copy(igb_rx_data_t *rx_data, uint32_t index, uint32_t pkt_len)
1395779Sxy150489 {
1405779Sxy150489 rx_control_block_t *current_rcb;
1415779Sxy150489 mblk_t *mp;
14211502SChenlu.Chen@Sun.COM igb_t *igb = rx_data->rx_ring->igb;
1435779Sxy150489
14411502SChenlu.Chen@Sun.COM current_rcb = rx_data->work_list[index];
1455779Sxy150489
1465779Sxy150489 DMA_SYNC(¤t_rcb->rx_buf, DDI_DMA_SYNC_FORKERNEL);
1475779Sxy150489
1486624Sgl147354 if (igb_check_dma_handle(
1496624Sgl147354 current_rcb->rx_buf.dma_handle) != DDI_FM_OK) {
1506624Sgl147354 ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
15111367SJason.Xu@Sun.COM atomic_or_32(&igb->igb_state, IGB_ERROR);
15211367SJason.Xu@Sun.COM return (NULL);
1536624Sgl147354 }
1546624Sgl147354
1555779Sxy150489 /*
1565779Sxy150489 * Allocate buffer to receive this packet
1575779Sxy150489 */
1585779Sxy150489 mp = allocb(pkt_len + IPHDR_ALIGN_ROOM, 0);
1595779Sxy150489 if (mp == NULL) {
16011502SChenlu.Chen@Sun.COM igb_log(igb, "igb_rx_copy: allocate buffer failed");
1615779Sxy150489 return (NULL);
1625779Sxy150489 }
1635779Sxy150489
1645779Sxy150489 /*
1655779Sxy150489 * Copy the data received into the new cluster
1665779Sxy150489 */
1675779Sxy150489 mp->b_rptr += IPHDR_ALIGN_ROOM;
1685779Sxy150489 bcopy(current_rcb->rx_buf.address, mp->b_rptr, pkt_len);
1695779Sxy150489 mp->b_wptr = mp->b_rptr + pkt_len;
1705779Sxy150489
1715779Sxy150489 return (mp);
1725779Sxy150489 }
1735779Sxy150489
1745779Sxy150489 /*
1755779Sxy150489 * igb_rx_bind - Use existing DMA buffer to build mblk for receiving
1765779Sxy150489 *
1775779Sxy150489 * This function will use pre-bound DMA buffer to receive the packet
1785779Sxy150489 * and build mblk that will be sent upstream.
1795779Sxy150489 */
1805779Sxy150489 static mblk_t *
igb_rx_bind(igb_rx_data_t * rx_data,uint32_t index,uint32_t pkt_len)18111502SChenlu.Chen@Sun.COM igb_rx_bind(igb_rx_data_t *rx_data, uint32_t index, uint32_t pkt_len)
1825779Sxy150489 {
1835779Sxy150489 rx_control_block_t *current_rcb;
1845779Sxy150489 rx_control_block_t *free_rcb;
1855779Sxy150489 uint32_t free_index;
1865779Sxy150489 mblk_t *mp;
18711502SChenlu.Chen@Sun.COM igb_t *igb = rx_data->rx_ring->igb;
1885779Sxy150489
1895779Sxy150489 /*
1905779Sxy150489 * If the free list is empty, we cannot proceed to send
1915779Sxy150489 * the current DMA buffer upstream. We'll have to return
1925779Sxy150489 * and use bcopy to process the packet.
1935779Sxy150489 */
19411502SChenlu.Chen@Sun.COM if (igb_atomic_reserve(&rx_data->rcb_free, 1) < 0)
1955779Sxy150489 return (NULL);
1965779Sxy150489
19711502SChenlu.Chen@Sun.COM current_rcb = rx_data->work_list[index];
1985779Sxy150489 /*
1995779Sxy150489 * If the mp of the rx control block is NULL, try to do
2005779Sxy150489 * desballoc again.
2015779Sxy150489 */
2025779Sxy150489 if (current_rcb->mp == NULL) {
2035779Sxy150489 current_rcb->mp = desballoc((unsigned char *)
2048571SChenlu.Chen@Sun.COM current_rcb->rx_buf.address,
2058571SChenlu.Chen@Sun.COM current_rcb->rx_buf.size,
2065779Sxy150489 0, ¤t_rcb->free_rtn);
2075779Sxy150489 /*
2085779Sxy150489 * If it is failed to built a mblk using the current
2095779Sxy150489 * DMA buffer, we have to return and use bcopy to
2105779Sxy150489 * process the packet.
2115779Sxy150489 */
2125779Sxy150489 if (current_rcb->mp == NULL) {
21311502SChenlu.Chen@Sun.COM atomic_inc_32(&rx_data->rcb_free);
2145779Sxy150489 return (NULL);
2155779Sxy150489 }
2165779Sxy150489 }
2175779Sxy150489 /*
2185779Sxy150489 * Sync up the data received
2195779Sxy150489 */
2205779Sxy150489 DMA_SYNC(¤t_rcb->rx_buf, DDI_DMA_SYNC_FORKERNEL);
2215779Sxy150489
2226624Sgl147354 if (igb_check_dma_handle(
2236624Sgl147354 current_rcb->rx_buf.dma_handle) != DDI_FM_OK) {
2246624Sgl147354 ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
22511367SJason.Xu@Sun.COM atomic_or_32(&igb->igb_state, IGB_ERROR);
22611502SChenlu.Chen@Sun.COM atomic_inc_32(&rx_data->rcb_free);
22711367SJason.Xu@Sun.COM return (NULL);
2286624Sgl147354 }
2296624Sgl147354
2305779Sxy150489 mp = current_rcb->mp;
2315779Sxy150489 current_rcb->mp = NULL;
23211502SChenlu.Chen@Sun.COM atomic_inc_32(¤t_rcb->ref_cnt);
2335779Sxy150489
2345779Sxy150489 mp->b_wptr = mp->b_rptr + pkt_len;
2355779Sxy150489 mp->b_next = mp->b_cont = NULL;
2365779Sxy150489
2375779Sxy150489 /*
2385779Sxy150489 * Strip off one free rx control block from the free list
2395779Sxy150489 */
24011502SChenlu.Chen@Sun.COM free_index = rx_data->rcb_head;
24111502SChenlu.Chen@Sun.COM free_rcb = rx_data->free_list[free_index];
2425779Sxy150489 ASSERT(free_rcb != NULL);
24311502SChenlu.Chen@Sun.COM rx_data->free_list[free_index] = NULL;
24411502SChenlu.Chen@Sun.COM rx_data->rcb_head = NEXT_INDEX(free_index, 1, rx_data->free_list_size);
2455779Sxy150489
2465779Sxy150489 /*
2475779Sxy150489 * Put the rx control block to the work list
2485779Sxy150489 */
24911502SChenlu.Chen@Sun.COM rx_data->work_list[index] = free_rcb;
2505779Sxy150489
2515779Sxy150489 return (mp);
2525779Sxy150489 }
2535779Sxy150489
2545779Sxy150489 /*
2555779Sxy150489 * igb_rx_assoc_hcksum
2565779Sxy150489 *
2575779Sxy150489 * Check the rx hardware checksum status and associate the hcksum flags
2585779Sxy150489 */
2595779Sxy150489 static void
igb_rx_assoc_hcksum(mblk_t * mp,uint32_t status_error)2605779Sxy150489 igb_rx_assoc_hcksum(mblk_t *mp, uint32_t status_error)
2615779Sxy150489 {
2625779Sxy150489 uint32_t hcksum_flags = 0;
2635779Sxy150489
2645779Sxy150489 /* Ignore Checksum Indication */
2655779Sxy150489 if (status_error & E1000_RXD_STAT_IXSM)
2665779Sxy150489 return;
2675779Sxy150489
2685779Sxy150489 /*
2695779Sxy150489 * Check TCP/UDP checksum
2705779Sxy150489 */
2715779Sxy150489 if (((status_error & E1000_RXD_STAT_TCPCS) ||
2725779Sxy150489 (status_error & E1000_RXD_STAT_UDPCS)) &&
2735779Sxy150489 !(status_error & E1000_RXDEXT_STATERR_TCPE))
274*11878SVenu.Iyer@Sun.COM hcksum_flags |= HCK_FULLCKSUM_OK;
2755779Sxy150489
2765779Sxy150489 /*
2775779Sxy150489 * Check IP Checksum
2785779Sxy150489 */
2795779Sxy150489 if ((status_error & E1000_RXD_STAT_IPCS) &&
2805779Sxy150489 !(status_error & E1000_RXDEXT_STATERR_IPE))
281*11878SVenu.Iyer@Sun.COM hcksum_flags |= HCK_IPV4_HDRCKSUM_OK;
2825779Sxy150489
2835779Sxy150489 if (hcksum_flags != 0) {
284*11878SVenu.Iyer@Sun.COM mac_hcksum_set(mp, 0, 0, 0, 0, hcksum_flags);
2855779Sxy150489 }
2865779Sxy150489 }
2875779Sxy150489
2888275SEric Cheng mblk_t *
igb_rx_ring_poll(void * arg,int bytes)2898275SEric Cheng igb_rx_ring_poll(void *arg, int bytes)
2908275SEric Cheng {
2918275SEric Cheng igb_rx_ring_t *rx_ring = (igb_rx_ring_t *)arg;
2928275SEric Cheng mblk_t *mp = NULL;
2938275SEric Cheng
2948275SEric Cheng ASSERT(bytes >= 0);
2958275SEric Cheng
29611367SJason.Xu@Sun.COM if ((bytes == 0) || (rx_ring->igb->igb_state & IGB_SUSPENDED) ||
29711367SJason.Xu@Sun.COM !(rx_ring->igb->igb_state & IGB_STARTED))
29811367SJason.Xu@Sun.COM return (NULL);
2998275SEric Cheng
3008275SEric Cheng mutex_enter(&rx_ring->rx_lock);
3018275SEric Cheng mp = igb_rx(rx_ring, bytes);
3028275SEric Cheng mutex_exit(&rx_ring->rx_lock);
3038275SEric Cheng
3048275SEric Cheng return (mp);
3058275SEric Cheng }
3068275SEric Cheng
3075779Sxy150489 /*
3085779Sxy150489 * igb_rx - Receive the data of one ring
3095779Sxy150489 *
3105779Sxy150489 * This function goes throught h/w descriptor in one specified rx ring,
3115779Sxy150489 * receives the data if the descriptor status shows the data is ready.
3125779Sxy150489 * It returns a chain of mblks containing the received data, to be
3135779Sxy150489 * passed up to mac_rx().
3145779Sxy150489 */
3155779Sxy150489 mblk_t *
igb_rx(igb_rx_ring_t * rx_ring,int poll_bytes)3168275SEric Cheng igb_rx(igb_rx_ring_t *rx_ring, int poll_bytes)
3175779Sxy150489 {
3185779Sxy150489 union e1000_adv_rx_desc *current_rbd;
3195779Sxy150489 rx_control_block_t *current_rcb;
3205779Sxy150489 mblk_t *mp;
3215779Sxy150489 mblk_t *mblk_head;
3225779Sxy150489 mblk_t **mblk_tail;
3235779Sxy150489 uint32_t rx_next;
3245779Sxy150489 uint32_t rx_tail;
3255779Sxy150489 uint32_t pkt_len;
3265779Sxy150489 uint32_t status_error;
3275779Sxy150489 uint32_t pkt_num;
3288275SEric Cheng uint32_t total_bytes;
3295779Sxy150489 igb_t *igb = rx_ring->igb;
33011502SChenlu.Chen@Sun.COM igb_rx_data_t *rx_data = rx_ring->rx_data;
3315779Sxy150489
3325779Sxy150489 mblk_head = NULL;
3335779Sxy150489 mblk_tail = &mblk_head;
3345779Sxy150489
33511367SJason.Xu@Sun.COM if (igb->igb_state & IGB_ERROR)
33611367SJason.Xu@Sun.COM return (NULL);
33711367SJason.Xu@Sun.COM
3385779Sxy150489 /*
3395779Sxy150489 * Sync the receive descriptors before
3405779Sxy150489 * accepting the packets
3415779Sxy150489 */
34211502SChenlu.Chen@Sun.COM DMA_SYNC(&rx_data->rbd_area, DDI_DMA_SYNC_FORKERNEL);
3435779Sxy150489
3446624Sgl147354 if (igb_check_dma_handle(
34511502SChenlu.Chen@Sun.COM rx_data->rbd_area.dma_handle) != DDI_FM_OK) {
3466624Sgl147354 ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
34711367SJason.Xu@Sun.COM atomic_or_32(&igb->igb_state, IGB_ERROR);
34811367SJason.Xu@Sun.COM return (NULL);
3496624Sgl147354 }
3506624Sgl147354
3515779Sxy150489 /*
3525779Sxy150489 * Get the start point of rx bd ring which should be examined
3535779Sxy150489 * during this cycle.
3545779Sxy150489 */
35511502SChenlu.Chen@Sun.COM rx_next = rx_data->rbd_next;
3565779Sxy150489
35711502SChenlu.Chen@Sun.COM current_rbd = &rx_data->rbd_ring[rx_next];
3585779Sxy150489 pkt_num = 0;
3598275SEric Cheng total_bytes = 0;
3605779Sxy150489 status_error = current_rbd->wb.upper.status_error;
3615779Sxy150489 while (status_error & E1000_RXD_STAT_DD) {
3625779Sxy150489 /*
3635779Sxy150489 * If hardware has found the errors, but the error
3645779Sxy150489 * is hardware checksum error, here does not discard the
3655779Sxy150489 * packet, and let upper layer compute the checksum;
3665779Sxy150489 * Otherwise discard the packet.
3675779Sxy150489 */
3685779Sxy150489 if ((status_error & E1000_RXDEXT_ERR_FRAME_ERR_MASK) ||
3695779Sxy150489 !(status_error & E1000_RXD_STAT_EOP)) {
3705779Sxy150489 IGB_DEBUG_STAT(rx_ring->stat_frame_error);
3715779Sxy150489 goto rx_discard;
3725779Sxy150489 }
3735779Sxy150489
3745779Sxy150489 IGB_DEBUG_STAT_COND(rx_ring->stat_cksum_error,
3755779Sxy150489 (status_error & E1000_RXDEXT_STATERR_TCPE) ||
3765779Sxy150489 (status_error & E1000_RXDEXT_STATERR_IPE));
3775779Sxy150489
3785779Sxy150489 pkt_len = current_rbd->wb.upper.length;
3798275SEric Cheng
3808275SEric Cheng if ((poll_bytes != IGB_NO_POLL) &&
3818275SEric Cheng ((pkt_len + total_bytes) > poll_bytes))
3828275SEric Cheng break;
3838275SEric Cheng
3848275SEric Cheng IGB_DEBUG_STAT(rx_ring->stat_pkt_cnt);
3858275SEric Cheng total_bytes += pkt_len;
3868275SEric Cheng
3875779Sxy150489 mp = NULL;
3885779Sxy150489 /*
3895779Sxy150489 * For packets with length more than the copy threshold,
3905779Sxy150489 * we'll firstly try to use the existed DMA buffer to built
3915779Sxy150489 * a mblk and send the mblk upstream.
3925779Sxy150489 *
3935779Sxy150489 * If the first method fails, or the packet length is less
3945779Sxy150489 * than the copy threshold, we'll allocate a new mblk and
3955779Sxy150489 * copy the packet data to the mblk.
3965779Sxy150489 */
39711502SChenlu.Chen@Sun.COM if (pkt_len > igb->rx_copy_thresh)
39811502SChenlu.Chen@Sun.COM mp = igb_rx_bind(rx_data, rx_next, pkt_len);
3995779Sxy150489
4005779Sxy150489 if (mp == NULL)
40111502SChenlu.Chen@Sun.COM mp = igb_rx_copy(rx_data, rx_next, pkt_len);
4025779Sxy150489
4035779Sxy150489 if (mp != NULL) {
4045779Sxy150489 /*
4055779Sxy150489 * Check h/w checksum offload status
4065779Sxy150489 */
4075779Sxy150489 if (igb->rx_hcksum_enable)
4085779Sxy150489 igb_rx_assoc_hcksum(mp, status_error);
4095779Sxy150489
4105779Sxy150489 *mblk_tail = mp;
4115779Sxy150489 mblk_tail = &mp->b_next;
4125779Sxy150489 }
4135779Sxy150489
414*11878SVenu.Iyer@Sun.COM /* Update per-ring rx statistics */
415*11878SVenu.Iyer@Sun.COM rx_ring->rx_pkts++;
416*11878SVenu.Iyer@Sun.COM rx_ring->rx_bytes += pkt_len;
417*11878SVenu.Iyer@Sun.COM
4185779Sxy150489 rx_discard:
4195779Sxy150489 /*
4205779Sxy150489 * Reset rx descriptor read bits
4215779Sxy150489 */
42211502SChenlu.Chen@Sun.COM current_rcb = rx_data->work_list[rx_next];
4235779Sxy150489 current_rbd->read.pkt_addr = current_rcb->rx_buf.dma_address;
4245779Sxy150489 current_rbd->read.hdr_addr = 0;
4255779Sxy150489
42611502SChenlu.Chen@Sun.COM rx_next = NEXT_INDEX(rx_next, 1, rx_data->ring_size);
4275779Sxy150489
4285779Sxy150489 /*
4295779Sxy150489 * The receive function is in interrupt context, so here
43011502SChenlu.Chen@Sun.COM * rx_limit_per_intr is used to avoid doing receiving too long
4315779Sxy150489 * per interrupt.
4325779Sxy150489 */
43311502SChenlu.Chen@Sun.COM if (++pkt_num > igb->rx_limit_per_intr) {
4345779Sxy150489 IGB_DEBUG_STAT(rx_ring->stat_exceed_pkt);
4355779Sxy150489 break;
4365779Sxy150489 }
4375779Sxy150489
43811502SChenlu.Chen@Sun.COM current_rbd = &rx_data->rbd_ring[rx_next];
4395779Sxy150489 status_error = current_rbd->wb.upper.status_error;
4405779Sxy150489 }
4415779Sxy150489
44211502SChenlu.Chen@Sun.COM DMA_SYNC(&rx_data->rbd_area, DDI_DMA_SYNC_FORDEV);
4435779Sxy150489
44411502SChenlu.Chen@Sun.COM rx_data->rbd_next = rx_next;
4455779Sxy150489
4465779Sxy150489 /*
4475779Sxy150489 * Update the h/w tail accordingly
4485779Sxy150489 */
44911502SChenlu.Chen@Sun.COM rx_tail = PREV_INDEX(rx_next, 1, rx_data->ring_size);
4505779Sxy150489
4515779Sxy150489 E1000_WRITE_REG(&igb->hw, E1000_RDT(rx_ring->index), rx_tail);
4525779Sxy150489
4536624Sgl147354 if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
4546624Sgl147354 ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
45511367SJason.Xu@Sun.COM atomic_or_32(&igb->igb_state, IGB_ERROR);
4566624Sgl147354 }
4576624Sgl147354
4585779Sxy150489 return (mblk_head);
4595779Sxy150489 }
460