xref: /onnv-gate/usr/src/uts/common/io/ixgbe/ixgbe_rx.c (revision 11486:6c9e5c271535)
16621Sbt150084 /*
26621Sbt150084  * CDDL HEADER START
36621Sbt150084  *
49353SSamuel.Tu@Sun.COM  * Copyright(c) 2007-2009 Intel Corporation. All rights reserved.
56621Sbt150084  * The contents of this file are subject to the terms of the
66621Sbt150084  * Common Development and Distribution License (the "License").
76621Sbt150084  * You may not use this file except in compliance with the License.
86621Sbt150084  *
98275SEric Cheng  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
108275SEric Cheng  * or http://www.opensolaris.org/os/licensing.
116621Sbt150084  * See the License for the specific language governing permissions
126621Sbt150084  * and limitations under the License.
136621Sbt150084  *
148275SEric Cheng  * When distributing Covered Code, include this CDDL HEADER in each
158275SEric Cheng  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
166621Sbt150084  * If applicable, add the following below this CDDL HEADER, with the
176621Sbt150084  * fields enclosed by brackets "[]" replaced with your own identifying
186621Sbt150084  * information: Portions Copyright [yyyy] [name of copyright owner]
196621Sbt150084  *
206621Sbt150084  * CDDL HEADER END
216621Sbt150084  */
226621Sbt150084 
236621Sbt150084 /*
24*11486SZhen.W@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
258275SEric Cheng  * Use is subject to license terms.
268275SEric Cheng  */
276621Sbt150084 
286621Sbt150084 #include "ixgbe_sw.h"
296621Sbt150084 
306621Sbt150084 /* function prototypes */
3110376SChenlu.Chen@Sun.COM static mblk_t *ixgbe_rx_bind(ixgbe_rx_data_t *, uint32_t, uint32_t);
3210376SChenlu.Chen@Sun.COM static mblk_t *ixgbe_rx_copy(ixgbe_rx_data_t *, uint32_t, uint32_t);
336621Sbt150084 static void ixgbe_rx_assoc_hcksum(mblk_t *, uint32_t);
34*11486SZhen.W@Sun.COM static mblk_t *ixgbe_lro_bind(ixgbe_rx_data_t *, uint32_t, uint32_t, uint32_t);
35*11486SZhen.W@Sun.COM static mblk_t *ixgbe_lro_copy(ixgbe_rx_data_t *, uint32_t, uint32_t, uint32_t);
36*11486SZhen.W@Sun.COM static int ixgbe_lro_get_start(ixgbe_rx_data_t *, uint32_t);
37*11486SZhen.W@Sun.COM static uint32_t ixgbe_lro_get_first(ixgbe_rx_data_t *, uint32_t);
386621Sbt150084 
396621Sbt150084 #ifndef IXGBE_DEBUG
406621Sbt150084 #pragma inline(ixgbe_rx_assoc_hcksum)
41*11486SZhen.W@Sun.COM #pragma inline(ixgbe_lro_get_start)
42*11486SZhen.W@Sun.COM #pragma inline(ixgbe_lro_get_first)
436621Sbt150084 #endif
446621Sbt150084 
456621Sbt150084 /*
466621Sbt150084  * ixgbe_rx_recycle - The call-back function to reclaim rx buffer.
476621Sbt150084  *
486621Sbt150084  * This function is called when an mp is freed by the user thru
496621Sbt150084  * freeb call (Only for mp constructed through desballoc call).
506621Sbt150084  * It returns back the freed buffer to the free list.
516621Sbt150084  */
526621Sbt150084 void
536621Sbt150084 ixgbe_rx_recycle(caddr_t arg)
546621Sbt150084 {
5510376SChenlu.Chen@Sun.COM 	ixgbe_t *ixgbe;
566621Sbt150084 	ixgbe_rx_ring_t *rx_ring;
5710376SChenlu.Chen@Sun.COM 	ixgbe_rx_data_t	*rx_data;
586621Sbt150084 	rx_control_block_t *recycle_rcb;
596621Sbt150084 	uint32_t free_index;
6010376SChenlu.Chen@Sun.COM 	uint32_t ref_cnt;
616621Sbt150084 
626621Sbt150084 	recycle_rcb = (rx_control_block_t *)(uintptr_t)arg;
6310376SChenlu.Chen@Sun.COM 	rx_data = recycle_rcb->rx_data;
6410376SChenlu.Chen@Sun.COM 	rx_ring = rx_data->rx_ring;
6510376SChenlu.Chen@Sun.COM 	ixgbe = rx_ring->ixgbe;
666621Sbt150084 
6710376SChenlu.Chen@Sun.COM 	if (recycle_rcb->ref_cnt == 0) {
6810376SChenlu.Chen@Sun.COM 		/*
6910376SChenlu.Chen@Sun.COM 		 * This case only happens when rx buffers are being freed
7010376SChenlu.Chen@Sun.COM 		 * in ixgbe_stop() and freemsg() is called.
7110376SChenlu.Chen@Sun.COM 		 */
726621Sbt150084 		return;
7310376SChenlu.Chen@Sun.COM 	}
746621Sbt150084 
756621Sbt150084 	ASSERT(recycle_rcb->mp == NULL);
766621Sbt150084 
776621Sbt150084 	/*
786621Sbt150084 	 * Using the recycled data buffer to generate a new mblk
796621Sbt150084 	 */
806621Sbt150084 	recycle_rcb->mp = desballoc((unsigned char *)
819353SSamuel.Tu@Sun.COM 	    recycle_rcb->rx_buf.address,
829353SSamuel.Tu@Sun.COM 	    recycle_rcb->rx_buf.size,
836621Sbt150084 	    0, &recycle_rcb->free_rtn);
846621Sbt150084 
856621Sbt150084 	/*
866621Sbt150084 	 * Put the recycled rx control block into free list
876621Sbt150084 	 */
8810376SChenlu.Chen@Sun.COM 	mutex_enter(&rx_data->recycle_lock);
896621Sbt150084 
9010376SChenlu.Chen@Sun.COM 	free_index = rx_data->rcb_tail;
9110376SChenlu.Chen@Sun.COM 	ASSERT(rx_data->free_list[free_index] == NULL);
926621Sbt150084 
9310376SChenlu.Chen@Sun.COM 	rx_data->free_list[free_index] = recycle_rcb;
9410376SChenlu.Chen@Sun.COM 	rx_data->rcb_tail = NEXT_INDEX(free_index, 1, rx_data->free_list_size);
956621Sbt150084 
9610376SChenlu.Chen@Sun.COM 	mutex_exit(&rx_data->recycle_lock);
976621Sbt150084 
986621Sbt150084 	/*
996621Sbt150084 	 * The atomic operation on the number of the available rx control
1006621Sbt150084 	 * blocks in the free list is used to make the recycling mutual
1016621Sbt150084 	 * exclusive with the receiving.
1026621Sbt150084 	 */
10310376SChenlu.Chen@Sun.COM 	atomic_inc_32(&rx_data->rcb_free);
10410376SChenlu.Chen@Sun.COM 	ASSERT(rx_data->rcb_free <= rx_data->free_list_size);
10510376SChenlu.Chen@Sun.COM 
10610376SChenlu.Chen@Sun.COM 	/*
10710376SChenlu.Chen@Sun.COM 	 * Considering the case that the interface is unplumbed
10810376SChenlu.Chen@Sun.COM 	 * and there are still some buffers held by the upper layer.
10910376SChenlu.Chen@Sun.COM 	 * When the buffer is returned back, we need to free it.
11010376SChenlu.Chen@Sun.COM 	 */
11110376SChenlu.Chen@Sun.COM 	ref_cnt = atomic_dec_32_nv(&recycle_rcb->ref_cnt);
11210376SChenlu.Chen@Sun.COM 	if (ref_cnt == 0) {
11310376SChenlu.Chen@Sun.COM 		if (recycle_rcb->mp != NULL) {
11410376SChenlu.Chen@Sun.COM 			freemsg(recycle_rcb->mp);
11510376SChenlu.Chen@Sun.COM 			recycle_rcb->mp = NULL;
11610376SChenlu.Chen@Sun.COM 		}
11710376SChenlu.Chen@Sun.COM 
11810376SChenlu.Chen@Sun.COM 		ixgbe_free_dma_buffer(&recycle_rcb->rx_buf);
11910376SChenlu.Chen@Sun.COM 
12010376SChenlu.Chen@Sun.COM 		mutex_enter(&ixgbe->rx_pending_lock);
12110376SChenlu.Chen@Sun.COM 		atomic_dec_32(&rx_data->rcb_pending);
12210376SChenlu.Chen@Sun.COM 		atomic_dec_32(&ixgbe->rcb_pending);
12310376SChenlu.Chen@Sun.COM 
12410376SChenlu.Chen@Sun.COM 		/*
12510376SChenlu.Chen@Sun.COM 		 * When there is not any buffer belonging to this rx_data
12610376SChenlu.Chen@Sun.COM 		 * held by the upper layer, the rx_data can be freed.
12710376SChenlu.Chen@Sun.COM 		 */
12810376SChenlu.Chen@Sun.COM 		if ((rx_data->flag & IXGBE_RX_STOPPED) &&
12910376SChenlu.Chen@Sun.COM 		    (rx_data->rcb_pending == 0))
13010376SChenlu.Chen@Sun.COM 			ixgbe_free_rx_ring_data(rx_data);
13110376SChenlu.Chen@Sun.COM 
13210376SChenlu.Chen@Sun.COM 		mutex_exit(&ixgbe->rx_pending_lock);
13310376SChenlu.Chen@Sun.COM 	}
1346621Sbt150084 }
1356621Sbt150084 
1366621Sbt150084 /*
1376621Sbt150084  * ixgbe_rx_copy - Use copy to process the received packet.
1386621Sbt150084  *
1396621Sbt150084  * This function will use bcopy to process the packet
1406621Sbt150084  * and send the copied packet upstream.
1416621Sbt150084  */
1426621Sbt150084 static mblk_t *
14310376SChenlu.Chen@Sun.COM ixgbe_rx_copy(ixgbe_rx_data_t *rx_data, uint32_t index, uint32_t pkt_len)
1446621Sbt150084 {
14510376SChenlu.Chen@Sun.COM 	ixgbe_t *ixgbe;
1466621Sbt150084 	rx_control_block_t *current_rcb;
1476621Sbt150084 	mblk_t *mp;
1486621Sbt150084 
14910376SChenlu.Chen@Sun.COM 	ixgbe = rx_data->rx_ring->ixgbe;
15010376SChenlu.Chen@Sun.COM 	current_rcb = rx_data->work_list[index];
1516621Sbt150084 
1526621Sbt150084 	DMA_SYNC(&current_rcb->rx_buf, DDI_DMA_SYNC_FORKERNEL);
1536621Sbt150084 
1546621Sbt150084 	if (ixgbe_check_dma_handle(current_rcb->rx_buf.dma_handle) !=
1556621Sbt150084 	    DDI_FM_OK) {
15610376SChenlu.Chen@Sun.COM 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
15711233SPaul.Guo@Sun.COM 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
15811233SPaul.Guo@Sun.COM 		return (NULL);
1596621Sbt150084 	}
1606621Sbt150084 
1616621Sbt150084 	/*
1626621Sbt150084 	 * Allocate buffer to receive this packet
1636621Sbt150084 	 */
1646621Sbt150084 	mp = allocb(pkt_len + IPHDR_ALIGN_ROOM, 0);
1656621Sbt150084 	if (mp == NULL) {
16610376SChenlu.Chen@Sun.COM 		ixgbe_log(ixgbe, "ixgbe_rx_copy: allocate buffer failed");
1676621Sbt150084 		return (NULL);
1686621Sbt150084 	}
1696621Sbt150084 
1706621Sbt150084 	/*
1716621Sbt150084 	 * Copy the data received into the new cluster
1726621Sbt150084 	 */
1736621Sbt150084 	mp->b_rptr += IPHDR_ALIGN_ROOM;
1746621Sbt150084 	bcopy(current_rcb->rx_buf.address, mp->b_rptr, pkt_len);
1756621Sbt150084 	mp->b_wptr = mp->b_rptr + pkt_len;
1766621Sbt150084 
1776621Sbt150084 	return (mp);
1786621Sbt150084 }
1796621Sbt150084 
1806621Sbt150084 /*
1816621Sbt150084  * ixgbe_rx_bind - Use existing DMA buffer to build mblk for receiving.
1826621Sbt150084  *
1836621Sbt150084  * This function will use pre-bound DMA buffer to receive the packet
1846621Sbt150084  * and build mblk that will be sent upstream.
1856621Sbt150084  */
1866621Sbt150084 static mblk_t *
18710376SChenlu.Chen@Sun.COM ixgbe_rx_bind(ixgbe_rx_data_t *rx_data, uint32_t index, uint32_t pkt_len)
1886621Sbt150084 {
1896621Sbt150084 	rx_control_block_t *current_rcb;
1906621Sbt150084 	rx_control_block_t *free_rcb;
1916621Sbt150084 	uint32_t free_index;
1926621Sbt150084 	mblk_t *mp;
19310376SChenlu.Chen@Sun.COM 	ixgbe_t	*ixgbe = rx_data->rx_ring->ixgbe;
1946621Sbt150084 
1956621Sbt150084 	/*
1966621Sbt150084 	 * If the free list is empty, we cannot proceed to send
1976621Sbt150084 	 * the current DMA buffer upstream. We'll have to return
1986621Sbt150084 	 * and use bcopy to process the packet.
1996621Sbt150084 	 */
20010376SChenlu.Chen@Sun.COM 	if (ixgbe_atomic_reserve(&rx_data->rcb_free, 1) < 0)
2016621Sbt150084 		return (NULL);
2026621Sbt150084 
20310376SChenlu.Chen@Sun.COM 	current_rcb = rx_data->work_list[index];
2046621Sbt150084 	/*
2056621Sbt150084 	 * If the mp of the rx control block is NULL, try to do
2066621Sbt150084 	 * desballoc again.
2076621Sbt150084 	 */
2086621Sbt150084 	if (current_rcb->mp == NULL) {
2096621Sbt150084 		current_rcb->mp = desballoc((unsigned char *)
2109353SSamuel.Tu@Sun.COM 		    current_rcb->rx_buf.address,
2119353SSamuel.Tu@Sun.COM 		    current_rcb->rx_buf.size,
2126621Sbt150084 		    0, &current_rcb->free_rtn);
2136621Sbt150084 		/*
2146621Sbt150084 		 * If it is failed to built a mblk using the current
2156621Sbt150084 		 * DMA buffer, we have to return and use bcopy to
2166621Sbt150084 		 * process the packet.
2176621Sbt150084 		 */
2189353SSamuel.Tu@Sun.COM 		if (current_rcb->mp == NULL) {
21910376SChenlu.Chen@Sun.COM 			atomic_inc_32(&rx_data->rcb_free);
2206621Sbt150084 			return (NULL);
2216621Sbt150084 		}
2226621Sbt150084 	}
2236621Sbt150084 	/*
2246621Sbt150084 	 * Sync up the data received
2256621Sbt150084 	 */
2266621Sbt150084 	DMA_SYNC(&current_rcb->rx_buf, DDI_DMA_SYNC_FORKERNEL);
2276621Sbt150084 
2286621Sbt150084 	if (ixgbe_check_dma_handle(current_rcb->rx_buf.dma_handle) !=
2296621Sbt150084 	    DDI_FM_OK) {
23010376SChenlu.Chen@Sun.COM 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
23111233SPaul.Guo@Sun.COM 		atomic_inc_32(&rx_data->rcb_free);
23211233SPaul.Guo@Sun.COM 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
23311233SPaul.Guo@Sun.COM 		return (NULL);
2346621Sbt150084 	}
2356621Sbt150084 
2366621Sbt150084 	mp = current_rcb->mp;
2376621Sbt150084 	current_rcb->mp = NULL;
23810376SChenlu.Chen@Sun.COM 	atomic_inc_32(&current_rcb->ref_cnt);
2396621Sbt150084 
2406621Sbt150084 	mp->b_wptr = mp->b_rptr + pkt_len;
2416621Sbt150084 	mp->b_next = mp->b_cont = NULL;
2426621Sbt150084 
2436621Sbt150084 	/*
2446621Sbt150084 	 * Strip off one free rx control block from the free list
2456621Sbt150084 	 */
24610376SChenlu.Chen@Sun.COM 	free_index = rx_data->rcb_head;
24710376SChenlu.Chen@Sun.COM 	free_rcb = rx_data->free_list[free_index];
2486621Sbt150084 	ASSERT(free_rcb != NULL);
24910376SChenlu.Chen@Sun.COM 	rx_data->free_list[free_index] = NULL;
25010376SChenlu.Chen@Sun.COM 	rx_data->rcb_head = NEXT_INDEX(free_index, 1, rx_data->free_list_size);
2516621Sbt150084 
2526621Sbt150084 	/*
2536621Sbt150084 	 * Put the rx control block to the work list
2546621Sbt150084 	 */
25510376SChenlu.Chen@Sun.COM 	rx_data->work_list[index] = free_rcb;
2566621Sbt150084 
2576621Sbt150084 	return (mp);
2586621Sbt150084 }
2596621Sbt150084 
2606621Sbt150084 /*
261*11486SZhen.W@Sun.COM  * ixgbe_lro_bind - Use existing DMA buffer to build LRO mblk for receiving.
262*11486SZhen.W@Sun.COM  *
263*11486SZhen.W@Sun.COM  * This function will use pre-bound DMA buffers to receive the packet
264*11486SZhen.W@Sun.COM  * and build LRO mblk that will be sent upstream.
265*11486SZhen.W@Sun.COM  */
266*11486SZhen.W@Sun.COM static mblk_t *
267*11486SZhen.W@Sun.COM ixgbe_lro_bind(ixgbe_rx_data_t *rx_data, uint32_t lro_start,
268*11486SZhen.W@Sun.COM     uint32_t lro_num, uint32_t pkt_len)
269*11486SZhen.W@Sun.COM {
270*11486SZhen.W@Sun.COM 	rx_control_block_t *current_rcb;
271*11486SZhen.W@Sun.COM 	union ixgbe_adv_rx_desc *current_rbd;
272*11486SZhen.W@Sun.COM 	rx_control_block_t *free_rcb;
273*11486SZhen.W@Sun.COM 	uint32_t free_index;
274*11486SZhen.W@Sun.COM 	int lro_next;
275*11486SZhen.W@Sun.COM 	uint32_t last_pkt_len;
276*11486SZhen.W@Sun.COM 	uint32_t i;
277*11486SZhen.W@Sun.COM 	mblk_t *mp;
278*11486SZhen.W@Sun.COM 	mblk_t *mblk_head;
279*11486SZhen.W@Sun.COM 	mblk_t **mblk_tail;
280*11486SZhen.W@Sun.COM 	ixgbe_t	*ixgbe = rx_data->rx_ring->ixgbe;
281*11486SZhen.W@Sun.COM 
282*11486SZhen.W@Sun.COM 	/*
283*11486SZhen.W@Sun.COM 	 * If the free list is empty, we cannot proceed to send
284*11486SZhen.W@Sun.COM 	 * the current DMA buffer upstream. We'll have to return
285*11486SZhen.W@Sun.COM 	 * and use bcopy to process the packet.
286*11486SZhen.W@Sun.COM 	 */
287*11486SZhen.W@Sun.COM 	if (ixgbe_atomic_reserve(&rx_data->rcb_free, lro_num) < 0)
288*11486SZhen.W@Sun.COM 		return (NULL);
289*11486SZhen.W@Sun.COM 	current_rcb = rx_data->work_list[lro_start];
290*11486SZhen.W@Sun.COM 
291*11486SZhen.W@Sun.COM 	/*
292*11486SZhen.W@Sun.COM 	 * If any one of the rx data blocks can not support
293*11486SZhen.W@Sun.COM 	 * lro bind  operation,  We'll have to return and use
294*11486SZhen.W@Sun.COM 	 * bcopy to process the lro  packet.
295*11486SZhen.W@Sun.COM 	 */
296*11486SZhen.W@Sun.COM 	for (i = lro_num; i > 0; i--) {
297*11486SZhen.W@Sun.COM 		/*
298*11486SZhen.W@Sun.COM 		 * Sync up the data received
299*11486SZhen.W@Sun.COM 		 */
300*11486SZhen.W@Sun.COM 		DMA_SYNC(&current_rcb->rx_buf, DDI_DMA_SYNC_FORKERNEL);
301*11486SZhen.W@Sun.COM 
302*11486SZhen.W@Sun.COM 		if (ixgbe_check_dma_handle(current_rcb->rx_buf.dma_handle) !=
303*11486SZhen.W@Sun.COM 		    DDI_FM_OK) {
304*11486SZhen.W@Sun.COM 			ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
305*11486SZhen.W@Sun.COM 			atomic_add_32(&rx_data->rcb_free, lro_num);
306*11486SZhen.W@Sun.COM 			atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
307*11486SZhen.W@Sun.COM 			return (NULL);
308*11486SZhen.W@Sun.COM 		}
309*11486SZhen.W@Sun.COM 
310*11486SZhen.W@Sun.COM 		/*
311*11486SZhen.W@Sun.COM 		 * If the mp of the rx control block is NULL, try to do
312*11486SZhen.W@Sun.COM 		 * desballoc again.
313*11486SZhen.W@Sun.COM 		 */
314*11486SZhen.W@Sun.COM 		if (current_rcb->mp == NULL) {
315*11486SZhen.W@Sun.COM 			current_rcb->mp = desballoc((unsigned char *)
316*11486SZhen.W@Sun.COM 			    current_rcb->rx_buf.address,
317*11486SZhen.W@Sun.COM 			    current_rcb->rx_buf.size,
318*11486SZhen.W@Sun.COM 			    0, &current_rcb->free_rtn);
319*11486SZhen.W@Sun.COM 			/*
320*11486SZhen.W@Sun.COM 			 * If it is failed to built a mblk using the current
321*11486SZhen.W@Sun.COM 			 * DMA buffer, we have to return and use bcopy to
322*11486SZhen.W@Sun.COM 			 * process the packet.
323*11486SZhen.W@Sun.COM 			 */
324*11486SZhen.W@Sun.COM 			if (current_rcb->mp == NULL) {
325*11486SZhen.W@Sun.COM 				atomic_add_32(&rx_data->rcb_free, lro_num);
326*11486SZhen.W@Sun.COM 				return (NULL);
327*11486SZhen.W@Sun.COM 			}
328*11486SZhen.W@Sun.COM 		}
329*11486SZhen.W@Sun.COM 		if (current_rcb->lro_next != -1)
330*11486SZhen.W@Sun.COM 			lro_next = current_rcb->lro_next;
331*11486SZhen.W@Sun.COM 		current_rcb = rx_data->work_list[lro_next];
332*11486SZhen.W@Sun.COM 	}
333*11486SZhen.W@Sun.COM 
334*11486SZhen.W@Sun.COM 	mblk_head = NULL;
335*11486SZhen.W@Sun.COM 	mblk_tail = &mblk_head;
336*11486SZhen.W@Sun.COM 	lro_next = lro_start;
337*11486SZhen.W@Sun.COM 	last_pkt_len = pkt_len - ixgbe->rx_buf_size * (lro_num - 1);
338*11486SZhen.W@Sun.COM 	current_rcb = rx_data->work_list[lro_next];
339*11486SZhen.W@Sun.COM 	current_rbd = &rx_data->rbd_ring[lro_next];
340*11486SZhen.W@Sun.COM 	while (lro_num --) {
341*11486SZhen.W@Sun.COM 		mp = current_rcb->mp;
342*11486SZhen.W@Sun.COM 		current_rcb->mp = NULL;
343*11486SZhen.W@Sun.COM 		atomic_inc_32(&current_rcb->ref_cnt);
344*11486SZhen.W@Sun.COM 		if (lro_num != 0)
345*11486SZhen.W@Sun.COM 			mp->b_wptr = mp->b_rptr + ixgbe->rx_buf_size;
346*11486SZhen.W@Sun.COM 		else
347*11486SZhen.W@Sun.COM 			mp->b_wptr = mp->b_rptr + last_pkt_len;
348*11486SZhen.W@Sun.COM 		mp->b_next = mp->b_cont = NULL;
349*11486SZhen.W@Sun.COM 		*mblk_tail = mp;
350*11486SZhen.W@Sun.COM 		mblk_tail = &mp->b_cont;
351*11486SZhen.W@Sun.COM 
352*11486SZhen.W@Sun.COM 		/*
353*11486SZhen.W@Sun.COM 		 * Strip off one free rx control block from the free list
354*11486SZhen.W@Sun.COM 		 */
355*11486SZhen.W@Sun.COM 		free_index = rx_data->rcb_head;
356*11486SZhen.W@Sun.COM 		free_rcb = rx_data->free_list[free_index];
357*11486SZhen.W@Sun.COM 		ASSERT(free_rcb != NULL);
358*11486SZhen.W@Sun.COM 		rx_data->free_list[free_index] = NULL;
359*11486SZhen.W@Sun.COM 		rx_data->rcb_head = NEXT_INDEX(free_index, 1,
360*11486SZhen.W@Sun.COM 		    rx_data->free_list_size);
361*11486SZhen.W@Sun.COM 
362*11486SZhen.W@Sun.COM 		/*
363*11486SZhen.W@Sun.COM 		 * Put the rx control block to the work list
364*11486SZhen.W@Sun.COM 		 */
365*11486SZhen.W@Sun.COM 		rx_data->work_list[lro_next] = free_rcb;
366*11486SZhen.W@Sun.COM 		lro_next = current_rcb->lro_next;
367*11486SZhen.W@Sun.COM 		current_rcb->lro_next = -1;
368*11486SZhen.W@Sun.COM 		current_rcb->lro_prev = -1;
369*11486SZhen.W@Sun.COM 		current_rcb->lro_pkt = B_FALSE;
370*11486SZhen.W@Sun.COM 		current_rbd->read.pkt_addr = free_rcb->rx_buf.dma_address;
371*11486SZhen.W@Sun.COM 		current_rbd->read.hdr_addr = 0;
372*11486SZhen.W@Sun.COM 		if (lro_next == -1)
373*11486SZhen.W@Sun.COM 			break;
374*11486SZhen.W@Sun.COM 		current_rcb = rx_data->work_list[lro_next];
375*11486SZhen.W@Sun.COM 		current_rbd = &rx_data->rbd_ring[lro_next];
376*11486SZhen.W@Sun.COM 	}
377*11486SZhen.W@Sun.COM 	return (mblk_head);
378*11486SZhen.W@Sun.COM }
379*11486SZhen.W@Sun.COM 
380*11486SZhen.W@Sun.COM /*
381*11486SZhen.W@Sun.COM  * ixgbe_lro_copy - Use copy to process the received LRO packet.
382*11486SZhen.W@Sun.COM  *
383*11486SZhen.W@Sun.COM  * This function will use bcopy to process the LRO  packet
384*11486SZhen.W@Sun.COM  * and send the copied packet upstream.
385*11486SZhen.W@Sun.COM  */
386*11486SZhen.W@Sun.COM static mblk_t *
387*11486SZhen.W@Sun.COM ixgbe_lro_copy(ixgbe_rx_data_t *rx_data, uint32_t lro_start,
388*11486SZhen.W@Sun.COM     uint32_t lro_num, uint32_t pkt_len)
389*11486SZhen.W@Sun.COM {
390*11486SZhen.W@Sun.COM 	ixgbe_t *ixgbe;
391*11486SZhen.W@Sun.COM 	rx_control_block_t *current_rcb;
392*11486SZhen.W@Sun.COM 	union ixgbe_adv_rx_desc *current_rbd;
393*11486SZhen.W@Sun.COM 	mblk_t *mp;
394*11486SZhen.W@Sun.COM 	uint32_t last_pkt_len;
395*11486SZhen.W@Sun.COM 	int lro_next;
396*11486SZhen.W@Sun.COM 	uint32_t i;
397*11486SZhen.W@Sun.COM 
398*11486SZhen.W@Sun.COM 	ixgbe = rx_data->rx_ring->ixgbe;
399*11486SZhen.W@Sun.COM 
400*11486SZhen.W@Sun.COM 	/*
401*11486SZhen.W@Sun.COM 	 * Allocate buffer to receive this LRO packet
402*11486SZhen.W@Sun.COM 	 */
403*11486SZhen.W@Sun.COM 	mp = allocb(pkt_len + IPHDR_ALIGN_ROOM, 0);
404*11486SZhen.W@Sun.COM 	if (mp == NULL) {
405*11486SZhen.W@Sun.COM 		ixgbe_log(ixgbe, "LRO copy MP alloc failed");
406*11486SZhen.W@Sun.COM 		return (NULL);
407*11486SZhen.W@Sun.COM 	}
408*11486SZhen.W@Sun.COM 
409*11486SZhen.W@Sun.COM 	current_rcb = rx_data->work_list[lro_start];
410*11486SZhen.W@Sun.COM 
411*11486SZhen.W@Sun.COM 	/*
412*11486SZhen.W@Sun.COM 	 * Sync up the LRO packet data received
413*11486SZhen.W@Sun.COM 	 */
414*11486SZhen.W@Sun.COM 	for (i = lro_num; i > 0; i--) {
415*11486SZhen.W@Sun.COM 		DMA_SYNC(&current_rcb->rx_buf, DDI_DMA_SYNC_FORKERNEL);
416*11486SZhen.W@Sun.COM 
417*11486SZhen.W@Sun.COM 		if (ixgbe_check_dma_handle(current_rcb->rx_buf.dma_handle) !=
418*11486SZhen.W@Sun.COM 		    DDI_FM_OK) {
419*11486SZhen.W@Sun.COM 			ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
420*11486SZhen.W@Sun.COM 			atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
421*11486SZhen.W@Sun.COM 			return (NULL);
422*11486SZhen.W@Sun.COM 		}
423*11486SZhen.W@Sun.COM 		if (current_rcb->lro_next != -1)
424*11486SZhen.W@Sun.COM 			lro_next = current_rcb->lro_next;
425*11486SZhen.W@Sun.COM 		current_rcb = rx_data->work_list[lro_next];
426*11486SZhen.W@Sun.COM 	}
427*11486SZhen.W@Sun.COM 	lro_next = lro_start;
428*11486SZhen.W@Sun.COM 	current_rcb = rx_data->work_list[lro_next];
429*11486SZhen.W@Sun.COM 	current_rbd = &rx_data->rbd_ring[lro_next];
430*11486SZhen.W@Sun.COM 	last_pkt_len = pkt_len - ixgbe->rx_buf_size * (lro_num - 1);
431*11486SZhen.W@Sun.COM 
432*11486SZhen.W@Sun.COM 	/*
433*11486SZhen.W@Sun.COM 	 * Copy the data received into the new cluster
434*11486SZhen.W@Sun.COM 	 */
435*11486SZhen.W@Sun.COM 	mp->b_rptr += IPHDR_ALIGN_ROOM;
436*11486SZhen.W@Sun.COM 	mp->b_wptr += IPHDR_ALIGN_ROOM;
437*11486SZhen.W@Sun.COM 	while (lro_num --) {
438*11486SZhen.W@Sun.COM 		if (lro_num != 0) {
439*11486SZhen.W@Sun.COM 			bcopy(current_rcb->rx_buf.address, mp->b_wptr,
440*11486SZhen.W@Sun.COM 			    ixgbe->rx_buf_size);
441*11486SZhen.W@Sun.COM 			mp->b_wptr += ixgbe->rx_buf_size;
442*11486SZhen.W@Sun.COM 		} else {
443*11486SZhen.W@Sun.COM 			bcopy(current_rcb->rx_buf.address, mp->b_wptr,
444*11486SZhen.W@Sun.COM 			    last_pkt_len);
445*11486SZhen.W@Sun.COM 			mp->b_wptr += last_pkt_len;
446*11486SZhen.W@Sun.COM 		}
447*11486SZhen.W@Sun.COM 		lro_next = current_rcb->lro_next;
448*11486SZhen.W@Sun.COM 		current_rcb->lro_next = -1;
449*11486SZhen.W@Sun.COM 		current_rcb->lro_prev = -1;
450*11486SZhen.W@Sun.COM 		current_rcb->lro_pkt = B_FALSE;
451*11486SZhen.W@Sun.COM 		current_rbd->read.pkt_addr = current_rcb->rx_buf.dma_address;
452*11486SZhen.W@Sun.COM 		current_rbd->read.hdr_addr = 0;
453*11486SZhen.W@Sun.COM 		if (lro_next == -1)
454*11486SZhen.W@Sun.COM 			break;
455*11486SZhen.W@Sun.COM 		current_rcb = rx_data->work_list[lro_next];
456*11486SZhen.W@Sun.COM 		current_rbd = &rx_data->rbd_ring[lro_next];
457*11486SZhen.W@Sun.COM 	}
458*11486SZhen.W@Sun.COM 
459*11486SZhen.W@Sun.COM 	return (mp);
460*11486SZhen.W@Sun.COM }
461*11486SZhen.W@Sun.COM 
462*11486SZhen.W@Sun.COM /*
463*11486SZhen.W@Sun.COM  * ixgbe_lro_get_start - get the start rcb index in one LRO packet
464*11486SZhen.W@Sun.COM  */
465*11486SZhen.W@Sun.COM static int
466*11486SZhen.W@Sun.COM ixgbe_lro_get_start(ixgbe_rx_data_t *rx_data, uint32_t rx_next)
467*11486SZhen.W@Sun.COM {
468*11486SZhen.W@Sun.COM 	int lro_prev;
469*11486SZhen.W@Sun.COM 	int lro_start;
470*11486SZhen.W@Sun.COM 	uint32_t lro_num = 1;
471*11486SZhen.W@Sun.COM 	rx_control_block_t *prev_rcb;
472*11486SZhen.W@Sun.COM 	rx_control_block_t *current_rcb = rx_data->work_list[rx_next];
473*11486SZhen.W@Sun.COM 	lro_prev = current_rcb->lro_prev;
474*11486SZhen.W@Sun.COM 
475*11486SZhen.W@Sun.COM 	while (lro_prev != -1) {
476*11486SZhen.W@Sun.COM 		lro_num ++;
477*11486SZhen.W@Sun.COM 		prev_rcb = rx_data->work_list[lro_prev];
478*11486SZhen.W@Sun.COM 		lro_start = lro_prev;
479*11486SZhen.W@Sun.COM 		lro_prev = prev_rcb->lro_prev;
480*11486SZhen.W@Sun.COM 	}
481*11486SZhen.W@Sun.COM 	rx_data->lro_num = lro_num;
482*11486SZhen.W@Sun.COM 	return (lro_start);
483*11486SZhen.W@Sun.COM }
484*11486SZhen.W@Sun.COM 
485*11486SZhen.W@Sun.COM /*
486*11486SZhen.W@Sun.COM  * ixgbe_lro_get_first - get the first LRO rcb index
487*11486SZhen.W@Sun.COM  */
488*11486SZhen.W@Sun.COM static uint32_t
489*11486SZhen.W@Sun.COM ixgbe_lro_get_first(ixgbe_rx_data_t *rx_data, uint32_t rx_next)
490*11486SZhen.W@Sun.COM {
491*11486SZhen.W@Sun.COM 	rx_control_block_t *current_rcb;
492*11486SZhen.W@Sun.COM 	uint32_t lro_first;
493*11486SZhen.W@Sun.COM 	lro_first = rx_data->lro_first;
494*11486SZhen.W@Sun.COM 	current_rcb = rx_data->work_list[lro_first];
495*11486SZhen.W@Sun.COM 	while ((!current_rcb->lro_pkt) && (lro_first != rx_next)) {
496*11486SZhen.W@Sun.COM 		lro_first =  NEXT_INDEX(lro_first, 1, rx_data->ring_size);
497*11486SZhen.W@Sun.COM 		current_rcb = rx_data->work_list[lro_first];
498*11486SZhen.W@Sun.COM 	}
499*11486SZhen.W@Sun.COM 	rx_data->lro_first = lro_first;
500*11486SZhen.W@Sun.COM 	return (lro_first);
501*11486SZhen.W@Sun.COM }
502*11486SZhen.W@Sun.COM 
503*11486SZhen.W@Sun.COM /*
5046621Sbt150084  * ixgbe_rx_assoc_hcksum - Check the rx hardware checksum status and associate
5056621Sbt150084  * the hcksum flags.
5066621Sbt150084  */
5076621Sbt150084 static void
5086621Sbt150084 ixgbe_rx_assoc_hcksum(mblk_t *mp, uint32_t status_error)
5096621Sbt150084 {
5106621Sbt150084 	uint32_t hcksum_flags = 0;
5116621Sbt150084 
5126621Sbt150084 	/*
5136621Sbt150084 	 * Check TCP/UDP checksum
5146621Sbt150084 	 */
5156621Sbt150084 	if ((status_error & IXGBE_RXD_STAT_L4CS) &&
5166621Sbt150084 	    !(status_error & IXGBE_RXDADV_ERR_TCPE))
5176621Sbt150084 		hcksum_flags |= HCK_FULLCKSUM | HCK_FULLCKSUM_OK;
5186621Sbt150084 
5196621Sbt150084 	/*
5206621Sbt150084 	 * Check IP Checksum
5216621Sbt150084 	 */
5226621Sbt150084 	if ((status_error & IXGBE_RXD_STAT_IPCS) &&
5236621Sbt150084 	    !(status_error & IXGBE_RXDADV_ERR_IPE))
5246621Sbt150084 		hcksum_flags |= HCK_IPV4_HDRCKSUM;
5256621Sbt150084 
5266621Sbt150084 	if (hcksum_flags != 0) {
5276621Sbt150084 		(void) hcksum_assoc(mp,
5286621Sbt150084 		    NULL, NULL, 0, 0, 0, 0, hcksum_flags, 0);
5296621Sbt150084 	}
5306621Sbt150084 }
5316621Sbt150084 
5326621Sbt150084 /*
5338275SEric Cheng  * ixgbe_ring_rx - Receive the data of one ring.
5346621Sbt150084  *
5356621Sbt150084  * This function goes throught h/w descriptor in one specified rx ring,
5366621Sbt150084  * receives the data if the descriptor status shows the data is ready.
5376621Sbt150084  * It returns a chain of mblks containing the received data, to be
5386621Sbt150084  * passed up to mac_rx().
5396621Sbt150084  */
5406621Sbt150084 mblk_t *
5418275SEric Cheng ixgbe_ring_rx(ixgbe_rx_ring_t *rx_ring, int poll_bytes)
5426621Sbt150084 {
5436621Sbt150084 	union ixgbe_adv_rx_desc *current_rbd;
5446621Sbt150084 	rx_control_block_t *current_rcb;
5456621Sbt150084 	mblk_t *mp;
5466621Sbt150084 	mblk_t *mblk_head;
5476621Sbt150084 	mblk_t **mblk_tail;
5486621Sbt150084 	uint32_t rx_next;
5496621Sbt150084 	uint32_t rx_tail;
5506621Sbt150084 	uint32_t pkt_len;
5516621Sbt150084 	uint32_t status_error;
5526621Sbt150084 	uint32_t pkt_num;
553*11486SZhen.W@Sun.COM 	uint32_t rsc_cnt;
554*11486SZhen.W@Sun.COM 	uint32_t lro_first;
555*11486SZhen.W@Sun.COM 	uint32_t lro_start;
556*11486SZhen.W@Sun.COM 	uint32_t lro_next;
557*11486SZhen.W@Sun.COM 	boolean_t lro_eop;
5588275SEric Cheng 	uint32_t received_bytes;
5596621Sbt150084 	ixgbe_t *ixgbe = rx_ring->ixgbe;
560*11486SZhen.W@Sun.COM 	ixgbe_rx_data_t *rx_data;
5616621Sbt150084 
56211233SPaul.Guo@Sun.COM 	if ((ixgbe->ixgbe_state & IXGBE_SUSPENDED) ||
56311233SPaul.Guo@Sun.COM 	    (ixgbe->ixgbe_state & IXGBE_ERROR) ||
56411233SPaul.Guo@Sun.COM 	    !(ixgbe->ixgbe_state & IXGBE_STARTED))
56511233SPaul.Guo@Sun.COM 		return (NULL);
56611233SPaul.Guo@Sun.COM 
567*11486SZhen.W@Sun.COM 	rx_data = rx_ring->rx_data;
568*11486SZhen.W@Sun.COM 	lro_eop = B_FALSE;
5696621Sbt150084 	mblk_head = NULL;
5706621Sbt150084 	mblk_tail = &mblk_head;
5716621Sbt150084 
5726621Sbt150084 	/*
5736621Sbt150084 	 * Sync the receive descriptors before accepting the packets
5746621Sbt150084 	 */
57510376SChenlu.Chen@Sun.COM 	DMA_SYNC(&rx_data->rbd_area, DDI_DMA_SYNC_FORKERNEL);
5766621Sbt150084 
57710376SChenlu.Chen@Sun.COM 	if (ixgbe_check_dma_handle(rx_data->rbd_area.dma_handle) != DDI_FM_OK) {
57810376SChenlu.Chen@Sun.COM 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
57911233SPaul.Guo@Sun.COM 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
58011233SPaul.Guo@Sun.COM 		return (NULL);
5816621Sbt150084 	}
5826621Sbt150084 
5836621Sbt150084 	/*
5846621Sbt150084 	 * Get the start point of rx bd ring which should be examined
5856621Sbt150084 	 * during this cycle.
5866621Sbt150084 	 */
58710376SChenlu.Chen@Sun.COM 	rx_next = rx_data->rbd_next;
58810376SChenlu.Chen@Sun.COM 	current_rbd = &rx_data->rbd_ring[rx_next];
5898275SEric Cheng 	received_bytes = 0;
5906621Sbt150084 	pkt_num = 0;
5916621Sbt150084 	status_error = current_rbd->wb.upper.status_error;
5926621Sbt150084 	while (status_error & IXGBE_RXD_STAT_DD) {
5936621Sbt150084 		/*
5946621Sbt150084 		 * If adapter has found errors, but the error
5956621Sbt150084 		 * is hardware checksum error, this does not discard the
5966621Sbt150084 		 * packet: let upper layer compute the checksum;
5976621Sbt150084 		 * Otherwise discard the packet.
5986621Sbt150084 		 */
5996621Sbt150084 		if ((status_error & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) ||
600*11486SZhen.W@Sun.COM 		    ((!ixgbe->lro_enable) &&
601*11486SZhen.W@Sun.COM 		    (!(status_error & IXGBE_RXD_STAT_EOP)))) {
6026621Sbt150084 			IXGBE_DEBUG_STAT(rx_ring->stat_frame_error);
6036621Sbt150084 			goto rx_discard;
6046621Sbt150084 		}
6056621Sbt150084 
6066621Sbt150084 		IXGBE_DEBUG_STAT_COND(rx_ring->stat_cksum_error,
6076621Sbt150084 		    (status_error & IXGBE_RXDADV_ERR_TCPE) ||
6086621Sbt150084 		    (status_error & IXGBE_RXDADV_ERR_IPE));
6096621Sbt150084 
610*11486SZhen.W@Sun.COM 		if (ixgbe->lro_enable) {
611*11486SZhen.W@Sun.COM 			rsc_cnt =  (current_rbd->wb.lower.lo_dword.data &
612*11486SZhen.W@Sun.COM 			    IXGBE_RXDADV_RSCCNT_MASK) >>
613*11486SZhen.W@Sun.COM 			    IXGBE_RXDADV_RSCCNT_SHIFT;
614*11486SZhen.W@Sun.COM 			if (rsc_cnt != 0) {
615*11486SZhen.W@Sun.COM 				if (status_error & IXGBE_RXD_STAT_EOP) {
616*11486SZhen.W@Sun.COM 					pkt_len = current_rbd->wb.upper.length;
617*11486SZhen.W@Sun.COM 					if (rx_data->work_list[rx_next]->
618*11486SZhen.W@Sun.COM 					    lro_prev != -1) {
619*11486SZhen.W@Sun.COM 						lro_start =
620*11486SZhen.W@Sun.COM 						    ixgbe_lro_get_start(rx_data,
621*11486SZhen.W@Sun.COM 						    rx_next);
622*11486SZhen.W@Sun.COM 						ixgbe->lro_pkt_count++;
623*11486SZhen.W@Sun.COM 						pkt_len +=
624*11486SZhen.W@Sun.COM 						    (rx_data->lro_num  - 1) *
625*11486SZhen.W@Sun.COM 						    ixgbe->rx_buf_size;
626*11486SZhen.W@Sun.COM 						lro_eop = B_TRUE;
627*11486SZhen.W@Sun.COM 					}
628*11486SZhen.W@Sun.COM 				} else {
629*11486SZhen.W@Sun.COM 					lro_next = (status_error &
630*11486SZhen.W@Sun.COM 					    IXGBE_RXDADV_NEXTP_MASK) >>
631*11486SZhen.W@Sun.COM 					    IXGBE_RXDADV_NEXTP_SHIFT;
632*11486SZhen.W@Sun.COM 					rx_data->work_list[lro_next]->lro_prev
633*11486SZhen.W@Sun.COM 					    = rx_next;
634*11486SZhen.W@Sun.COM 					rx_data->work_list[rx_next]->lro_next =
635*11486SZhen.W@Sun.COM 					    lro_next;
636*11486SZhen.W@Sun.COM 					rx_data->work_list[rx_next]->lro_pkt =
637*11486SZhen.W@Sun.COM 					    B_TRUE;
638*11486SZhen.W@Sun.COM 					goto rx_discard;
639*11486SZhen.W@Sun.COM 				}
640*11486SZhen.W@Sun.COM 
641*11486SZhen.W@Sun.COM 			} else {
642*11486SZhen.W@Sun.COM 				pkt_len = current_rbd->wb.upper.length;
643*11486SZhen.W@Sun.COM 			}
644*11486SZhen.W@Sun.COM 		} else {
645*11486SZhen.W@Sun.COM 			pkt_len = current_rbd->wb.upper.length;
646*11486SZhen.W@Sun.COM 		}
647*11486SZhen.W@Sun.COM 
6488275SEric Cheng 
6498275SEric Cheng 		if ((poll_bytes != IXGBE_POLL_NULL) &&
6508275SEric Cheng 		    ((received_bytes + pkt_len) > poll_bytes))
6518275SEric Cheng 			break;
6528275SEric Cheng 
6538275SEric Cheng 		received_bytes += pkt_len;
654*11486SZhen.W@Sun.COM 		mp = NULL;
6558275SEric Cheng 
6566621Sbt150084 		/*
6576621Sbt150084 		 * For packets with length more than the copy threshold,
6586621Sbt150084 		 * we'll first try to use the existing DMA buffer to build
6596621Sbt150084 		 * an mblk and send the mblk upstream.
6606621Sbt150084 		 *
6616621Sbt150084 		 * If the first method fails, or the packet length is less
6626621Sbt150084 		 * than the copy threshold, we'll allocate a new mblk and
6636621Sbt150084 		 * copy the packet data to the new mblk.
6646621Sbt150084 		 */
665*11486SZhen.W@Sun.COM 		if (lro_eop) {
666*11486SZhen.W@Sun.COM 			mp = ixgbe_lro_bind(rx_data, lro_start,
667*11486SZhen.W@Sun.COM 			    rx_data->lro_num, pkt_len);
668*11486SZhen.W@Sun.COM 			if (mp == NULL)
669*11486SZhen.W@Sun.COM 				mp = ixgbe_lro_copy(rx_data, lro_start,
670*11486SZhen.W@Sun.COM 				    rx_data->lro_num, pkt_len);
671*11486SZhen.W@Sun.COM 			lro_eop = B_FALSE;
672*11486SZhen.W@Sun.COM 			rx_data->lro_num = 0;
6736621Sbt150084 
674*11486SZhen.W@Sun.COM 		} else {
675*11486SZhen.W@Sun.COM 			if (pkt_len > ixgbe->rx_copy_thresh)
676*11486SZhen.W@Sun.COM 				mp = ixgbe_rx_bind(rx_data, rx_next, pkt_len);
6776621Sbt150084 
678*11486SZhen.W@Sun.COM 			if (mp == NULL)
679*11486SZhen.W@Sun.COM 				mp = ixgbe_rx_copy(rx_data, rx_next, pkt_len);
680*11486SZhen.W@Sun.COM 		}
6816621Sbt150084 		if (mp != NULL) {
6826621Sbt150084 			/*
6836621Sbt150084 			 * Check h/w checksum offload status
6846621Sbt150084 			 */
6856621Sbt150084 			if (ixgbe->rx_hcksum_enable)
6866621Sbt150084 				ixgbe_rx_assoc_hcksum(mp, status_error);
6876621Sbt150084 
6886621Sbt150084 			*mblk_tail = mp;
6896621Sbt150084 			mblk_tail = &mp->b_next;
6906621Sbt150084 		}
6916621Sbt150084 
6926621Sbt150084 rx_discard:
6936621Sbt150084 		/*
6946621Sbt150084 		 * Reset rx descriptor read bits
6956621Sbt150084 		 */
69610376SChenlu.Chen@Sun.COM 		current_rcb = rx_data->work_list[rx_next];
697*11486SZhen.W@Sun.COM 		if (ixgbe->lro_enable) {
698*11486SZhen.W@Sun.COM 			if (!current_rcb->lro_pkt) {
699*11486SZhen.W@Sun.COM 				current_rbd->read.pkt_addr =
700*11486SZhen.W@Sun.COM 				    current_rcb->rx_buf.dma_address;
701*11486SZhen.W@Sun.COM 				current_rbd->read.hdr_addr = 0;
702*11486SZhen.W@Sun.COM 			}
703*11486SZhen.W@Sun.COM 		} else {
704*11486SZhen.W@Sun.COM 			current_rbd->read.pkt_addr =
705*11486SZhen.W@Sun.COM 			    current_rcb->rx_buf.dma_address;
706*11486SZhen.W@Sun.COM 			current_rbd->read.hdr_addr = 0;
707*11486SZhen.W@Sun.COM 		}
7086621Sbt150084 
70910376SChenlu.Chen@Sun.COM 		rx_next = NEXT_INDEX(rx_next, 1, rx_data->ring_size);
7106621Sbt150084 
7116621Sbt150084 		/*
7126621Sbt150084 		 * The receive function is in interrupt context, so here
71310376SChenlu.Chen@Sun.COM 		 * rx_limit_per_intr is used to avoid doing receiving too long
7146621Sbt150084 		 * per interrupt.
7156621Sbt150084 		 */
71610376SChenlu.Chen@Sun.COM 		if (++pkt_num > ixgbe->rx_limit_per_intr) {
7176621Sbt150084 			IXGBE_DEBUG_STAT(rx_ring->stat_exceed_pkt);
7186621Sbt150084 			break;
7196621Sbt150084 		}
7206621Sbt150084 
72110376SChenlu.Chen@Sun.COM 		current_rbd = &rx_data->rbd_ring[rx_next];
7226621Sbt150084 		status_error = current_rbd->wb.upper.status_error;
7236621Sbt150084 	}
7246621Sbt150084 
72510376SChenlu.Chen@Sun.COM 	DMA_SYNC(&rx_data->rbd_area, DDI_DMA_SYNC_FORDEV);
7266621Sbt150084 
72710376SChenlu.Chen@Sun.COM 	rx_data->rbd_next = rx_next;
7286621Sbt150084 
7296621Sbt150084 	/*
7306621Sbt150084 	 * Update the h/w tail accordingly
7316621Sbt150084 	 */
732*11486SZhen.W@Sun.COM 	if (ixgbe->lro_enable) {
733*11486SZhen.W@Sun.COM 		lro_first = ixgbe_lro_get_first(rx_data, rx_next);
734*11486SZhen.W@Sun.COM 		rx_tail = PREV_INDEX(lro_first, 1, rx_data->ring_size);
735*11486SZhen.W@Sun.COM 	} else
736*11486SZhen.W@Sun.COM 		rx_tail = PREV_INDEX(rx_next, 1, rx_data->ring_size);
737*11486SZhen.W@Sun.COM 
7386621Sbt150084 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_RDT(rx_ring->index), rx_tail);
7396621Sbt150084 
7406621Sbt150084 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
74110376SChenlu.Chen@Sun.COM 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
74211233SPaul.Guo@Sun.COM 		atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
7436621Sbt150084 	}
7446621Sbt150084 
7456621Sbt150084 	return (mblk_head);
7466621Sbt150084 }
7478275SEric Cheng 
7488275SEric Cheng mblk_t *
7498275SEric Cheng ixgbe_ring_rx_poll(void *arg, int n_bytes)
7508275SEric Cheng {
7518275SEric Cheng 	ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)arg;
7528275SEric Cheng 	mblk_t *mp = NULL;
7538275SEric Cheng 
7548275SEric Cheng 	ASSERT(n_bytes >= 0);
7558275SEric Cheng 
7568275SEric Cheng 	if (n_bytes == 0)
75711233SPaul.Guo@Sun.COM 		return (NULL);
7588275SEric Cheng 
7598275SEric Cheng 	mutex_enter(&rx_ring->rx_lock);
7608275SEric Cheng 	mp = ixgbe_ring_rx(rx_ring, n_bytes);
7618275SEric Cheng 	mutex_exit(&rx_ring->rx_lock);
7628275SEric Cheng 
7638275SEric Cheng 	return (mp);
7648275SEric Cheng }
765