xref: /onnv-gate/usr/src/uts/common/io/igb/igb_rx.c (revision 11878:ac93462db6d7)
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(&current_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, &current_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(&current_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(&current_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