16621Sbt150084 /*
26621Sbt150084 * CDDL HEADER START
36621Sbt150084 *
46621Sbt150084 * The contents of this file are subject to the terms of the
56621Sbt150084 * Common Development and Distribution License (the "License").
66621Sbt150084 * You may not use this file except in compliance with the License.
76621Sbt150084 *
88275SEric Cheng * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98275SEric Cheng * or http://www.opensolaris.org/os/licensing.
106621Sbt150084 * See the License for the specific language governing permissions
116621Sbt150084 * and limitations under the License.
126621Sbt150084 *
138275SEric Cheng * When distributing Covered Code, include this CDDL HEADER in each
148275SEric Cheng * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156621Sbt150084 * If applicable, add the following below this CDDL HEADER, with the
166621Sbt150084 * fields enclosed by brackets "[]" replaced with your own identifying
176621Sbt150084 * information: Portions Copyright [yyyy] [name of copyright owner]
186621Sbt150084 *
196621Sbt150084 * CDDL HEADER END
206621Sbt150084 */
216621Sbt150084
226621Sbt150084 /*
23*13006SChenlu.Chen@Sun.COM * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
24*13006SChenlu.Chen@Sun.COM */
25*13006SChenlu.Chen@Sun.COM
26*13006SChenlu.Chen@Sun.COM /*
27*13006SChenlu.Chen@Sun.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
288275SEric Cheng */
296621Sbt150084
306621Sbt150084 #include "ixgbe_sw.h"
316621Sbt150084
326621Sbt150084 /* function prototypes */
3310376SChenlu.Chen@Sun.COM static mblk_t *ixgbe_rx_bind(ixgbe_rx_data_t *, uint32_t, uint32_t);
3410376SChenlu.Chen@Sun.COM static mblk_t *ixgbe_rx_copy(ixgbe_rx_data_t *, uint32_t, uint32_t);
356621Sbt150084 static void ixgbe_rx_assoc_hcksum(mblk_t *, uint32_t);
3611486SZhen.W@Sun.COM static mblk_t *ixgbe_lro_bind(ixgbe_rx_data_t *, uint32_t, uint32_t, uint32_t);
3711486SZhen.W@Sun.COM static mblk_t *ixgbe_lro_copy(ixgbe_rx_data_t *, uint32_t, uint32_t, uint32_t);
3811486SZhen.W@Sun.COM static int ixgbe_lro_get_start(ixgbe_rx_data_t *, uint32_t);
3911486SZhen.W@Sun.COM static uint32_t ixgbe_lro_get_first(ixgbe_rx_data_t *, uint32_t);
406621Sbt150084
416621Sbt150084 #ifndef IXGBE_DEBUG
426621Sbt150084 #pragma inline(ixgbe_rx_assoc_hcksum)
4311486SZhen.W@Sun.COM #pragma inline(ixgbe_lro_get_start)
4411486SZhen.W@Sun.COM #pragma inline(ixgbe_lro_get_first)
456621Sbt150084 #endif
466621Sbt150084
476621Sbt150084 /*
486621Sbt150084 * ixgbe_rx_recycle - The call-back function to reclaim rx buffer.
496621Sbt150084 *
506621Sbt150084 * This function is called when an mp is freed by the user thru
516621Sbt150084 * freeb call (Only for mp constructed through desballoc call).
526621Sbt150084 * It returns back the freed buffer to the free list.
536621Sbt150084 */
546621Sbt150084 void
ixgbe_rx_recycle(caddr_t arg)556621Sbt150084 ixgbe_rx_recycle(caddr_t arg)
566621Sbt150084 {
5710376SChenlu.Chen@Sun.COM ixgbe_t *ixgbe;
586621Sbt150084 ixgbe_rx_ring_t *rx_ring;
5910376SChenlu.Chen@Sun.COM ixgbe_rx_data_t *rx_data;
606621Sbt150084 rx_control_block_t *recycle_rcb;
616621Sbt150084 uint32_t free_index;
6210376SChenlu.Chen@Sun.COM uint32_t ref_cnt;
636621Sbt150084
646621Sbt150084 recycle_rcb = (rx_control_block_t *)(uintptr_t)arg;
6510376SChenlu.Chen@Sun.COM rx_data = recycle_rcb->rx_data;
6610376SChenlu.Chen@Sun.COM rx_ring = rx_data->rx_ring;
6710376SChenlu.Chen@Sun.COM ixgbe = rx_ring->ixgbe;
686621Sbt150084
6910376SChenlu.Chen@Sun.COM if (recycle_rcb->ref_cnt == 0) {
7010376SChenlu.Chen@Sun.COM /*
7110376SChenlu.Chen@Sun.COM * This case only happens when rx buffers are being freed
7210376SChenlu.Chen@Sun.COM * in ixgbe_stop() and freemsg() is called.
7310376SChenlu.Chen@Sun.COM */
746621Sbt150084 return;
7510376SChenlu.Chen@Sun.COM }
766621Sbt150084
776621Sbt150084 ASSERT(recycle_rcb->mp == NULL);
786621Sbt150084
796621Sbt150084 /*
806621Sbt150084 * Using the recycled data buffer to generate a new mblk
816621Sbt150084 */
826621Sbt150084 recycle_rcb->mp = desballoc((unsigned char *)
839353SSamuel.Tu@Sun.COM recycle_rcb->rx_buf.address,
849353SSamuel.Tu@Sun.COM recycle_rcb->rx_buf.size,
856621Sbt150084 0, &recycle_rcb->free_rtn);
866621Sbt150084
876621Sbt150084 /*
886621Sbt150084 * Put the recycled rx control block into free list
896621Sbt150084 */
9010376SChenlu.Chen@Sun.COM mutex_enter(&rx_data->recycle_lock);
916621Sbt150084
9210376SChenlu.Chen@Sun.COM free_index = rx_data->rcb_tail;
9310376SChenlu.Chen@Sun.COM ASSERT(rx_data->free_list[free_index] == NULL);
946621Sbt150084
9510376SChenlu.Chen@Sun.COM rx_data->free_list[free_index] = recycle_rcb;
9610376SChenlu.Chen@Sun.COM rx_data->rcb_tail = NEXT_INDEX(free_index, 1, rx_data->free_list_size);
976621Sbt150084
9810376SChenlu.Chen@Sun.COM mutex_exit(&rx_data->recycle_lock);
996621Sbt150084
1006621Sbt150084 /*
1016621Sbt150084 * The atomic operation on the number of the available rx control
1026621Sbt150084 * blocks in the free list is used to make the recycling mutual
1036621Sbt150084 * exclusive with the receiving.
1046621Sbt150084 */
10510376SChenlu.Chen@Sun.COM atomic_inc_32(&rx_data->rcb_free);
10610376SChenlu.Chen@Sun.COM ASSERT(rx_data->rcb_free <= rx_data->free_list_size);
10710376SChenlu.Chen@Sun.COM
10810376SChenlu.Chen@Sun.COM /*
10910376SChenlu.Chen@Sun.COM * Considering the case that the interface is unplumbed
11010376SChenlu.Chen@Sun.COM * and there are still some buffers held by the upper layer.
11110376SChenlu.Chen@Sun.COM * When the buffer is returned back, we need to free it.
11210376SChenlu.Chen@Sun.COM */
11310376SChenlu.Chen@Sun.COM ref_cnt = atomic_dec_32_nv(&recycle_rcb->ref_cnt);
11410376SChenlu.Chen@Sun.COM if (ref_cnt == 0) {
11510376SChenlu.Chen@Sun.COM if (recycle_rcb->mp != NULL) {
11610376SChenlu.Chen@Sun.COM freemsg(recycle_rcb->mp);
11710376SChenlu.Chen@Sun.COM recycle_rcb->mp = NULL;
11810376SChenlu.Chen@Sun.COM }
11910376SChenlu.Chen@Sun.COM
12010376SChenlu.Chen@Sun.COM ixgbe_free_dma_buffer(&recycle_rcb->rx_buf);
12110376SChenlu.Chen@Sun.COM
12210376SChenlu.Chen@Sun.COM mutex_enter(&ixgbe->rx_pending_lock);
12310376SChenlu.Chen@Sun.COM atomic_dec_32(&rx_data->rcb_pending);
12410376SChenlu.Chen@Sun.COM atomic_dec_32(&ixgbe->rcb_pending);
12510376SChenlu.Chen@Sun.COM
12610376SChenlu.Chen@Sun.COM /*
12710376SChenlu.Chen@Sun.COM * When there is not any buffer belonging to this rx_data
12810376SChenlu.Chen@Sun.COM * held by the upper layer, the rx_data can be freed.
12910376SChenlu.Chen@Sun.COM */
13010376SChenlu.Chen@Sun.COM if ((rx_data->flag & IXGBE_RX_STOPPED) &&
13110376SChenlu.Chen@Sun.COM (rx_data->rcb_pending == 0))
13210376SChenlu.Chen@Sun.COM ixgbe_free_rx_ring_data(rx_data);
13310376SChenlu.Chen@Sun.COM
13410376SChenlu.Chen@Sun.COM mutex_exit(&ixgbe->rx_pending_lock);
13510376SChenlu.Chen@Sun.COM }
1366621Sbt150084 }
1376621Sbt150084
1386621Sbt150084 /*
1396621Sbt150084 * ixgbe_rx_copy - Use copy to process the received packet.
1406621Sbt150084 *
1416621Sbt150084 * This function will use bcopy to process the packet
1426621Sbt150084 * and send the copied packet upstream.
1436621Sbt150084 */
1446621Sbt150084 static mblk_t *
ixgbe_rx_copy(ixgbe_rx_data_t * rx_data,uint32_t index,uint32_t pkt_len)14510376SChenlu.Chen@Sun.COM ixgbe_rx_copy(ixgbe_rx_data_t *rx_data, uint32_t index, uint32_t pkt_len)
1466621Sbt150084 {
14710376SChenlu.Chen@Sun.COM ixgbe_t *ixgbe;
1486621Sbt150084 rx_control_block_t *current_rcb;
1496621Sbt150084 mblk_t *mp;
1506621Sbt150084
15110376SChenlu.Chen@Sun.COM ixgbe = rx_data->rx_ring->ixgbe;
15210376SChenlu.Chen@Sun.COM current_rcb = rx_data->work_list[index];
1536621Sbt150084
1546621Sbt150084 DMA_SYNC(¤t_rcb->rx_buf, DDI_DMA_SYNC_FORKERNEL);
1556621Sbt150084
1566621Sbt150084 if (ixgbe_check_dma_handle(current_rcb->rx_buf.dma_handle) !=
1576621Sbt150084 DDI_FM_OK) {
15810376SChenlu.Chen@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
15911233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
16011233SPaul.Guo@Sun.COM return (NULL);
1616621Sbt150084 }
1626621Sbt150084
1636621Sbt150084 /*
1646621Sbt150084 * Allocate buffer to receive this packet
1656621Sbt150084 */
1666621Sbt150084 mp = allocb(pkt_len + IPHDR_ALIGN_ROOM, 0);
1676621Sbt150084 if (mp == NULL) {
16810376SChenlu.Chen@Sun.COM ixgbe_log(ixgbe, "ixgbe_rx_copy: allocate buffer failed");
1696621Sbt150084 return (NULL);
1706621Sbt150084 }
1716621Sbt150084
1726621Sbt150084 /*
1736621Sbt150084 * Copy the data received into the new cluster
1746621Sbt150084 */
1756621Sbt150084 mp->b_rptr += IPHDR_ALIGN_ROOM;
1766621Sbt150084 bcopy(current_rcb->rx_buf.address, mp->b_rptr, pkt_len);
1776621Sbt150084 mp->b_wptr = mp->b_rptr + pkt_len;
1786621Sbt150084
1796621Sbt150084 return (mp);
1806621Sbt150084 }
1816621Sbt150084
1826621Sbt150084 /*
1836621Sbt150084 * ixgbe_rx_bind - Use existing DMA buffer to build mblk for receiving.
1846621Sbt150084 *
1856621Sbt150084 * This function will use pre-bound DMA buffer to receive the packet
1866621Sbt150084 * and build mblk that will be sent upstream.
1876621Sbt150084 */
1886621Sbt150084 static mblk_t *
ixgbe_rx_bind(ixgbe_rx_data_t * rx_data,uint32_t index,uint32_t pkt_len)18910376SChenlu.Chen@Sun.COM ixgbe_rx_bind(ixgbe_rx_data_t *rx_data, uint32_t index, uint32_t pkt_len)
1906621Sbt150084 {
1916621Sbt150084 rx_control_block_t *current_rcb;
1926621Sbt150084 rx_control_block_t *free_rcb;
1936621Sbt150084 uint32_t free_index;
1946621Sbt150084 mblk_t *mp;
19510376SChenlu.Chen@Sun.COM ixgbe_t *ixgbe = rx_data->rx_ring->ixgbe;
1966621Sbt150084
1976621Sbt150084 /*
1986621Sbt150084 * If the free list is empty, we cannot proceed to send
1996621Sbt150084 * the current DMA buffer upstream. We'll have to return
2006621Sbt150084 * and use bcopy to process the packet.
2016621Sbt150084 */
20210376SChenlu.Chen@Sun.COM if (ixgbe_atomic_reserve(&rx_data->rcb_free, 1) < 0)
2036621Sbt150084 return (NULL);
2046621Sbt150084
20510376SChenlu.Chen@Sun.COM current_rcb = rx_data->work_list[index];
2066621Sbt150084 /*
2076621Sbt150084 * If the mp of the rx control block is NULL, try to do
2086621Sbt150084 * desballoc again.
2096621Sbt150084 */
2106621Sbt150084 if (current_rcb->mp == NULL) {
2116621Sbt150084 current_rcb->mp = desballoc((unsigned char *)
2129353SSamuel.Tu@Sun.COM current_rcb->rx_buf.address,
2139353SSamuel.Tu@Sun.COM current_rcb->rx_buf.size,
2146621Sbt150084 0, ¤t_rcb->free_rtn);
2156621Sbt150084 /*
2166621Sbt150084 * If it is failed to built a mblk using the current
2176621Sbt150084 * DMA buffer, we have to return and use bcopy to
2186621Sbt150084 * process the packet.
2196621Sbt150084 */
2209353SSamuel.Tu@Sun.COM if (current_rcb->mp == NULL) {
22110376SChenlu.Chen@Sun.COM atomic_inc_32(&rx_data->rcb_free);
2226621Sbt150084 return (NULL);
2236621Sbt150084 }
2246621Sbt150084 }
2256621Sbt150084 /*
2266621Sbt150084 * Sync up the data received
2276621Sbt150084 */
2286621Sbt150084 DMA_SYNC(¤t_rcb->rx_buf, DDI_DMA_SYNC_FORKERNEL);
2296621Sbt150084
2306621Sbt150084 if (ixgbe_check_dma_handle(current_rcb->rx_buf.dma_handle) !=
2316621Sbt150084 DDI_FM_OK) {
23210376SChenlu.Chen@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
23311233SPaul.Guo@Sun.COM atomic_inc_32(&rx_data->rcb_free);
23411233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
23511233SPaul.Guo@Sun.COM return (NULL);
2366621Sbt150084 }
2376621Sbt150084
2386621Sbt150084 mp = current_rcb->mp;
2396621Sbt150084 current_rcb->mp = NULL;
24010376SChenlu.Chen@Sun.COM atomic_inc_32(¤t_rcb->ref_cnt);
2416621Sbt150084
2426621Sbt150084 mp->b_wptr = mp->b_rptr + pkt_len;
2436621Sbt150084 mp->b_next = mp->b_cont = NULL;
2446621Sbt150084
2456621Sbt150084 /*
2466621Sbt150084 * Strip off one free rx control block from the free list
2476621Sbt150084 */
24810376SChenlu.Chen@Sun.COM free_index = rx_data->rcb_head;
24910376SChenlu.Chen@Sun.COM free_rcb = rx_data->free_list[free_index];
2506621Sbt150084 ASSERT(free_rcb != NULL);
25110376SChenlu.Chen@Sun.COM rx_data->free_list[free_index] = NULL;
25210376SChenlu.Chen@Sun.COM rx_data->rcb_head = NEXT_INDEX(free_index, 1, rx_data->free_list_size);
2536621Sbt150084
2546621Sbt150084 /*
2556621Sbt150084 * Put the rx control block to the work list
2566621Sbt150084 */
25710376SChenlu.Chen@Sun.COM rx_data->work_list[index] = free_rcb;
2586621Sbt150084
2596621Sbt150084 return (mp);
2606621Sbt150084 }
2616621Sbt150084
2626621Sbt150084 /*
26311486SZhen.W@Sun.COM * ixgbe_lro_bind - Use existing DMA buffer to build LRO mblk for receiving.
26411486SZhen.W@Sun.COM *
26511486SZhen.W@Sun.COM * This function will use pre-bound DMA buffers to receive the packet
26611486SZhen.W@Sun.COM * and build LRO mblk that will be sent upstream.
26711486SZhen.W@Sun.COM */
26811486SZhen.W@Sun.COM static mblk_t *
ixgbe_lro_bind(ixgbe_rx_data_t * rx_data,uint32_t lro_start,uint32_t lro_num,uint32_t pkt_len)26911486SZhen.W@Sun.COM ixgbe_lro_bind(ixgbe_rx_data_t *rx_data, uint32_t lro_start,
27011486SZhen.W@Sun.COM uint32_t lro_num, uint32_t pkt_len)
27111486SZhen.W@Sun.COM {
27211486SZhen.W@Sun.COM rx_control_block_t *current_rcb;
27311486SZhen.W@Sun.COM union ixgbe_adv_rx_desc *current_rbd;
27411486SZhen.W@Sun.COM rx_control_block_t *free_rcb;
27511486SZhen.W@Sun.COM uint32_t free_index;
27611486SZhen.W@Sun.COM int lro_next;
27711486SZhen.W@Sun.COM uint32_t last_pkt_len;
27811486SZhen.W@Sun.COM uint32_t i;
27911486SZhen.W@Sun.COM mblk_t *mp;
28011486SZhen.W@Sun.COM mblk_t *mblk_head;
28111486SZhen.W@Sun.COM mblk_t **mblk_tail;
28211486SZhen.W@Sun.COM ixgbe_t *ixgbe = rx_data->rx_ring->ixgbe;
28311486SZhen.W@Sun.COM
28411486SZhen.W@Sun.COM /*
28511486SZhen.W@Sun.COM * If the free list is empty, we cannot proceed to send
28611486SZhen.W@Sun.COM * the current DMA buffer upstream. We'll have to return
28711486SZhen.W@Sun.COM * and use bcopy to process the packet.
28811486SZhen.W@Sun.COM */
28911486SZhen.W@Sun.COM if (ixgbe_atomic_reserve(&rx_data->rcb_free, lro_num) < 0)
29011486SZhen.W@Sun.COM return (NULL);
29111486SZhen.W@Sun.COM current_rcb = rx_data->work_list[lro_start];
29211486SZhen.W@Sun.COM
29311486SZhen.W@Sun.COM /*
29411486SZhen.W@Sun.COM * If any one of the rx data blocks can not support
29511486SZhen.W@Sun.COM * lro bind operation, We'll have to return and use
29611486SZhen.W@Sun.COM * bcopy to process the lro packet.
29711486SZhen.W@Sun.COM */
29811486SZhen.W@Sun.COM for (i = lro_num; i > 0; i--) {
29911486SZhen.W@Sun.COM /*
30011486SZhen.W@Sun.COM * Sync up the data received
30111486SZhen.W@Sun.COM */
30211486SZhen.W@Sun.COM DMA_SYNC(¤t_rcb->rx_buf, DDI_DMA_SYNC_FORKERNEL);
30311486SZhen.W@Sun.COM
30411486SZhen.W@Sun.COM if (ixgbe_check_dma_handle(current_rcb->rx_buf.dma_handle) !=
30511486SZhen.W@Sun.COM DDI_FM_OK) {
30611486SZhen.W@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
30711486SZhen.W@Sun.COM atomic_add_32(&rx_data->rcb_free, lro_num);
30811486SZhen.W@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
30911486SZhen.W@Sun.COM return (NULL);
31011486SZhen.W@Sun.COM }
31111486SZhen.W@Sun.COM
31211486SZhen.W@Sun.COM /*
31311486SZhen.W@Sun.COM * If the mp of the rx control block is NULL, try to do
31411486SZhen.W@Sun.COM * desballoc again.
31511486SZhen.W@Sun.COM */
31611486SZhen.W@Sun.COM if (current_rcb->mp == NULL) {
31711486SZhen.W@Sun.COM current_rcb->mp = desballoc((unsigned char *)
31811486SZhen.W@Sun.COM current_rcb->rx_buf.address,
31911486SZhen.W@Sun.COM current_rcb->rx_buf.size,
32011486SZhen.W@Sun.COM 0, ¤t_rcb->free_rtn);
32111486SZhen.W@Sun.COM /*
32211486SZhen.W@Sun.COM * If it is failed to built a mblk using the current
32311486SZhen.W@Sun.COM * DMA buffer, we have to return and use bcopy to
32411486SZhen.W@Sun.COM * process the packet.
32511486SZhen.W@Sun.COM */
32611486SZhen.W@Sun.COM if (current_rcb->mp == NULL) {
32711486SZhen.W@Sun.COM atomic_add_32(&rx_data->rcb_free, lro_num);
32811486SZhen.W@Sun.COM return (NULL);
32911486SZhen.W@Sun.COM }
33011486SZhen.W@Sun.COM }
33111486SZhen.W@Sun.COM if (current_rcb->lro_next != -1)
33211486SZhen.W@Sun.COM lro_next = current_rcb->lro_next;
33311486SZhen.W@Sun.COM current_rcb = rx_data->work_list[lro_next];
33411486SZhen.W@Sun.COM }
33511486SZhen.W@Sun.COM
33611486SZhen.W@Sun.COM mblk_head = NULL;
33711486SZhen.W@Sun.COM mblk_tail = &mblk_head;
33811486SZhen.W@Sun.COM lro_next = lro_start;
33911486SZhen.W@Sun.COM last_pkt_len = pkt_len - ixgbe->rx_buf_size * (lro_num - 1);
34011486SZhen.W@Sun.COM current_rcb = rx_data->work_list[lro_next];
34111486SZhen.W@Sun.COM current_rbd = &rx_data->rbd_ring[lro_next];
34211486SZhen.W@Sun.COM while (lro_num --) {
34311486SZhen.W@Sun.COM mp = current_rcb->mp;
34411486SZhen.W@Sun.COM current_rcb->mp = NULL;
34511486SZhen.W@Sun.COM atomic_inc_32(¤t_rcb->ref_cnt);
34611486SZhen.W@Sun.COM if (lro_num != 0)
34711486SZhen.W@Sun.COM mp->b_wptr = mp->b_rptr + ixgbe->rx_buf_size;
34811486SZhen.W@Sun.COM else
34911486SZhen.W@Sun.COM mp->b_wptr = mp->b_rptr + last_pkt_len;
35011486SZhen.W@Sun.COM mp->b_next = mp->b_cont = NULL;
35111486SZhen.W@Sun.COM *mblk_tail = mp;
35211486SZhen.W@Sun.COM mblk_tail = &mp->b_cont;
35311486SZhen.W@Sun.COM
35411486SZhen.W@Sun.COM /*
35511486SZhen.W@Sun.COM * Strip off one free rx control block from the free list
35611486SZhen.W@Sun.COM */
35711486SZhen.W@Sun.COM free_index = rx_data->rcb_head;
35811486SZhen.W@Sun.COM free_rcb = rx_data->free_list[free_index];
35911486SZhen.W@Sun.COM ASSERT(free_rcb != NULL);
36011486SZhen.W@Sun.COM rx_data->free_list[free_index] = NULL;
36111486SZhen.W@Sun.COM rx_data->rcb_head = NEXT_INDEX(free_index, 1,
36211486SZhen.W@Sun.COM rx_data->free_list_size);
36311486SZhen.W@Sun.COM
36411486SZhen.W@Sun.COM /*
36511486SZhen.W@Sun.COM * Put the rx control block to the work list
36611486SZhen.W@Sun.COM */
36711486SZhen.W@Sun.COM rx_data->work_list[lro_next] = free_rcb;
36811486SZhen.W@Sun.COM lro_next = current_rcb->lro_next;
36911486SZhen.W@Sun.COM current_rcb->lro_next = -1;
37011486SZhen.W@Sun.COM current_rcb->lro_prev = -1;
37111486SZhen.W@Sun.COM current_rcb->lro_pkt = B_FALSE;
37211486SZhen.W@Sun.COM current_rbd->read.pkt_addr = free_rcb->rx_buf.dma_address;
37311486SZhen.W@Sun.COM current_rbd->read.hdr_addr = 0;
37411486SZhen.W@Sun.COM if (lro_next == -1)
37511486SZhen.W@Sun.COM break;
37611486SZhen.W@Sun.COM current_rcb = rx_data->work_list[lro_next];
37711486SZhen.W@Sun.COM current_rbd = &rx_data->rbd_ring[lro_next];
37811486SZhen.W@Sun.COM }
37911486SZhen.W@Sun.COM return (mblk_head);
38011486SZhen.W@Sun.COM }
38111486SZhen.W@Sun.COM
38211486SZhen.W@Sun.COM /*
38311486SZhen.W@Sun.COM * ixgbe_lro_copy - Use copy to process the received LRO packet.
38411486SZhen.W@Sun.COM *
38511486SZhen.W@Sun.COM * This function will use bcopy to process the LRO packet
38611486SZhen.W@Sun.COM * and send the copied packet upstream.
38711486SZhen.W@Sun.COM */
38811486SZhen.W@Sun.COM static mblk_t *
ixgbe_lro_copy(ixgbe_rx_data_t * rx_data,uint32_t lro_start,uint32_t lro_num,uint32_t pkt_len)38911486SZhen.W@Sun.COM ixgbe_lro_copy(ixgbe_rx_data_t *rx_data, uint32_t lro_start,
39011486SZhen.W@Sun.COM uint32_t lro_num, uint32_t pkt_len)
39111486SZhen.W@Sun.COM {
39211486SZhen.W@Sun.COM ixgbe_t *ixgbe;
39311486SZhen.W@Sun.COM rx_control_block_t *current_rcb;
39411486SZhen.W@Sun.COM union ixgbe_adv_rx_desc *current_rbd;
39511486SZhen.W@Sun.COM mblk_t *mp;
39611486SZhen.W@Sun.COM uint32_t last_pkt_len;
39711486SZhen.W@Sun.COM int lro_next;
39811486SZhen.W@Sun.COM uint32_t i;
39911486SZhen.W@Sun.COM
40011486SZhen.W@Sun.COM ixgbe = rx_data->rx_ring->ixgbe;
40111486SZhen.W@Sun.COM
40211486SZhen.W@Sun.COM /*
40311486SZhen.W@Sun.COM * Allocate buffer to receive this LRO packet
40411486SZhen.W@Sun.COM */
40511486SZhen.W@Sun.COM mp = allocb(pkt_len + IPHDR_ALIGN_ROOM, 0);
40611486SZhen.W@Sun.COM if (mp == NULL) {
40711486SZhen.W@Sun.COM ixgbe_log(ixgbe, "LRO copy MP alloc failed");
40811486SZhen.W@Sun.COM return (NULL);
40911486SZhen.W@Sun.COM }
41011486SZhen.W@Sun.COM
41111486SZhen.W@Sun.COM current_rcb = rx_data->work_list[lro_start];
41211486SZhen.W@Sun.COM
41311486SZhen.W@Sun.COM /*
41411486SZhen.W@Sun.COM * Sync up the LRO packet data received
41511486SZhen.W@Sun.COM */
41611486SZhen.W@Sun.COM for (i = lro_num; i > 0; i--) {
41711486SZhen.W@Sun.COM DMA_SYNC(¤t_rcb->rx_buf, DDI_DMA_SYNC_FORKERNEL);
41811486SZhen.W@Sun.COM
41911486SZhen.W@Sun.COM if (ixgbe_check_dma_handle(current_rcb->rx_buf.dma_handle) !=
42011486SZhen.W@Sun.COM DDI_FM_OK) {
42111486SZhen.W@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
42211486SZhen.W@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
42311486SZhen.W@Sun.COM return (NULL);
42411486SZhen.W@Sun.COM }
42511486SZhen.W@Sun.COM if (current_rcb->lro_next != -1)
42611486SZhen.W@Sun.COM lro_next = current_rcb->lro_next;
42711486SZhen.W@Sun.COM current_rcb = rx_data->work_list[lro_next];
42811486SZhen.W@Sun.COM }
42911486SZhen.W@Sun.COM lro_next = lro_start;
43011486SZhen.W@Sun.COM current_rcb = rx_data->work_list[lro_next];
43111486SZhen.W@Sun.COM current_rbd = &rx_data->rbd_ring[lro_next];
43211486SZhen.W@Sun.COM last_pkt_len = pkt_len - ixgbe->rx_buf_size * (lro_num - 1);
43311486SZhen.W@Sun.COM
43411486SZhen.W@Sun.COM /*
43511486SZhen.W@Sun.COM * Copy the data received into the new cluster
43611486SZhen.W@Sun.COM */
43711486SZhen.W@Sun.COM mp->b_rptr += IPHDR_ALIGN_ROOM;
43811486SZhen.W@Sun.COM mp->b_wptr += IPHDR_ALIGN_ROOM;
43911486SZhen.W@Sun.COM while (lro_num --) {
44011486SZhen.W@Sun.COM if (lro_num != 0) {
44111486SZhen.W@Sun.COM bcopy(current_rcb->rx_buf.address, mp->b_wptr,
44211486SZhen.W@Sun.COM ixgbe->rx_buf_size);
44311486SZhen.W@Sun.COM mp->b_wptr += ixgbe->rx_buf_size;
44411486SZhen.W@Sun.COM } else {
44511486SZhen.W@Sun.COM bcopy(current_rcb->rx_buf.address, mp->b_wptr,
44611486SZhen.W@Sun.COM last_pkt_len);
44711486SZhen.W@Sun.COM mp->b_wptr += last_pkt_len;
44811486SZhen.W@Sun.COM }
44911486SZhen.W@Sun.COM lro_next = current_rcb->lro_next;
45011486SZhen.W@Sun.COM current_rcb->lro_next = -1;
45111486SZhen.W@Sun.COM current_rcb->lro_prev = -1;
45211486SZhen.W@Sun.COM current_rcb->lro_pkt = B_FALSE;
45311486SZhen.W@Sun.COM current_rbd->read.pkt_addr = current_rcb->rx_buf.dma_address;
45411486SZhen.W@Sun.COM current_rbd->read.hdr_addr = 0;
45511486SZhen.W@Sun.COM if (lro_next == -1)
45611486SZhen.W@Sun.COM break;
45711486SZhen.W@Sun.COM current_rcb = rx_data->work_list[lro_next];
45811486SZhen.W@Sun.COM current_rbd = &rx_data->rbd_ring[lro_next];
45911486SZhen.W@Sun.COM }
46011486SZhen.W@Sun.COM
46111486SZhen.W@Sun.COM return (mp);
46211486SZhen.W@Sun.COM }
46311486SZhen.W@Sun.COM
46411486SZhen.W@Sun.COM /*
46511486SZhen.W@Sun.COM * ixgbe_lro_get_start - get the start rcb index in one LRO packet
46611486SZhen.W@Sun.COM */
46711486SZhen.W@Sun.COM static int
ixgbe_lro_get_start(ixgbe_rx_data_t * rx_data,uint32_t rx_next)46811486SZhen.W@Sun.COM ixgbe_lro_get_start(ixgbe_rx_data_t *rx_data, uint32_t rx_next)
46911486SZhen.W@Sun.COM {
47011486SZhen.W@Sun.COM int lro_prev;
47111486SZhen.W@Sun.COM int lro_start;
47211486SZhen.W@Sun.COM uint32_t lro_num = 1;
47311486SZhen.W@Sun.COM rx_control_block_t *prev_rcb;
47411486SZhen.W@Sun.COM rx_control_block_t *current_rcb = rx_data->work_list[rx_next];
47511486SZhen.W@Sun.COM lro_prev = current_rcb->lro_prev;
47611486SZhen.W@Sun.COM
47711486SZhen.W@Sun.COM while (lro_prev != -1) {
47811486SZhen.W@Sun.COM lro_num ++;
47911486SZhen.W@Sun.COM prev_rcb = rx_data->work_list[lro_prev];
48011486SZhen.W@Sun.COM lro_start = lro_prev;
48111486SZhen.W@Sun.COM lro_prev = prev_rcb->lro_prev;
48211486SZhen.W@Sun.COM }
48311486SZhen.W@Sun.COM rx_data->lro_num = lro_num;
48411486SZhen.W@Sun.COM return (lro_start);
48511486SZhen.W@Sun.COM }
48611486SZhen.W@Sun.COM
48711486SZhen.W@Sun.COM /*
48811486SZhen.W@Sun.COM * ixgbe_lro_get_first - get the first LRO rcb index
48911486SZhen.W@Sun.COM */
49011486SZhen.W@Sun.COM static uint32_t
ixgbe_lro_get_first(ixgbe_rx_data_t * rx_data,uint32_t rx_next)49111486SZhen.W@Sun.COM ixgbe_lro_get_first(ixgbe_rx_data_t *rx_data, uint32_t rx_next)
49211486SZhen.W@Sun.COM {
49311486SZhen.W@Sun.COM rx_control_block_t *current_rcb;
49411486SZhen.W@Sun.COM uint32_t lro_first;
49511486SZhen.W@Sun.COM lro_first = rx_data->lro_first;
49611486SZhen.W@Sun.COM current_rcb = rx_data->work_list[lro_first];
49711486SZhen.W@Sun.COM while ((!current_rcb->lro_pkt) && (lro_first != rx_next)) {
49811486SZhen.W@Sun.COM lro_first = NEXT_INDEX(lro_first, 1, rx_data->ring_size);
49911486SZhen.W@Sun.COM current_rcb = rx_data->work_list[lro_first];
50011486SZhen.W@Sun.COM }
50111486SZhen.W@Sun.COM rx_data->lro_first = lro_first;
50211486SZhen.W@Sun.COM return (lro_first);
50311486SZhen.W@Sun.COM }
50411486SZhen.W@Sun.COM
50511486SZhen.W@Sun.COM /*
5066621Sbt150084 * ixgbe_rx_assoc_hcksum - Check the rx hardware checksum status and associate
5076621Sbt150084 * the hcksum flags.
5086621Sbt150084 */
5096621Sbt150084 static void
ixgbe_rx_assoc_hcksum(mblk_t * mp,uint32_t status_error)5106621Sbt150084 ixgbe_rx_assoc_hcksum(mblk_t *mp, uint32_t status_error)
5116621Sbt150084 {
5126621Sbt150084 uint32_t hcksum_flags = 0;
5136621Sbt150084
5146621Sbt150084 /*
5156621Sbt150084 * Check TCP/UDP checksum
5166621Sbt150084 */
5176621Sbt150084 if ((status_error & IXGBE_RXD_STAT_L4CS) &&
5186621Sbt150084 !(status_error & IXGBE_RXDADV_ERR_TCPE))
51911878SVenu.Iyer@Sun.COM hcksum_flags |= HCK_FULLCKSUM_OK;
5206621Sbt150084
5216621Sbt150084 /*
5226621Sbt150084 * Check IP Checksum
5236621Sbt150084 */
5246621Sbt150084 if ((status_error & IXGBE_RXD_STAT_IPCS) &&
5256621Sbt150084 !(status_error & IXGBE_RXDADV_ERR_IPE))
52611878SVenu.Iyer@Sun.COM hcksum_flags |= HCK_IPV4_HDRCKSUM_OK;
5276621Sbt150084
5286621Sbt150084 if (hcksum_flags != 0) {
52911878SVenu.Iyer@Sun.COM mac_hcksum_set(mp, 0, 0, 0, 0, hcksum_flags);
5306621Sbt150084 }
5316621Sbt150084 }
5326621Sbt150084
5336621Sbt150084 /*
5348275SEric Cheng * ixgbe_ring_rx - Receive the data of one ring.
5356621Sbt150084 *
5366621Sbt150084 * This function goes throught h/w descriptor in one specified rx ring,
5376621Sbt150084 * receives the data if the descriptor status shows the data is ready.
5386621Sbt150084 * It returns a chain of mblks containing the received data, to be
5396621Sbt150084 * passed up to mac_rx().
5406621Sbt150084 */
5416621Sbt150084 mblk_t *
ixgbe_ring_rx(ixgbe_rx_ring_t * rx_ring,int poll_bytes)5428275SEric Cheng ixgbe_ring_rx(ixgbe_rx_ring_t *rx_ring, int poll_bytes)
5436621Sbt150084 {
5446621Sbt150084 union ixgbe_adv_rx_desc *current_rbd;
5456621Sbt150084 rx_control_block_t *current_rcb;
5466621Sbt150084 mblk_t *mp;
5476621Sbt150084 mblk_t *mblk_head;
5486621Sbt150084 mblk_t **mblk_tail;
5496621Sbt150084 uint32_t rx_next;
5506621Sbt150084 uint32_t rx_tail;
5516621Sbt150084 uint32_t pkt_len;
5526621Sbt150084 uint32_t status_error;
5536621Sbt150084 uint32_t pkt_num;
55411486SZhen.W@Sun.COM uint32_t rsc_cnt;
55511486SZhen.W@Sun.COM uint32_t lro_first;
55611486SZhen.W@Sun.COM uint32_t lro_start;
55711486SZhen.W@Sun.COM uint32_t lro_next;
55811486SZhen.W@Sun.COM boolean_t lro_eop;
5598275SEric Cheng uint32_t received_bytes;
5606621Sbt150084 ixgbe_t *ixgbe = rx_ring->ixgbe;
56111486SZhen.W@Sun.COM ixgbe_rx_data_t *rx_data;
5626621Sbt150084
56311233SPaul.Guo@Sun.COM if ((ixgbe->ixgbe_state & IXGBE_SUSPENDED) ||
56411233SPaul.Guo@Sun.COM (ixgbe->ixgbe_state & IXGBE_ERROR) ||
565*13006SChenlu.Chen@Sun.COM (ixgbe->ixgbe_state & IXGBE_OVERTEMP) ||
56611233SPaul.Guo@Sun.COM !(ixgbe->ixgbe_state & IXGBE_STARTED))
56711233SPaul.Guo@Sun.COM return (NULL);
56811233SPaul.Guo@Sun.COM
56911486SZhen.W@Sun.COM rx_data = rx_ring->rx_data;
57011486SZhen.W@Sun.COM lro_eop = B_FALSE;
5716621Sbt150084 mblk_head = NULL;
5726621Sbt150084 mblk_tail = &mblk_head;
5736621Sbt150084
5746621Sbt150084 /*
5756621Sbt150084 * Sync the receive descriptors before accepting the packets
5766621Sbt150084 */
57710376SChenlu.Chen@Sun.COM DMA_SYNC(&rx_data->rbd_area, DDI_DMA_SYNC_FORKERNEL);
5786621Sbt150084
57910376SChenlu.Chen@Sun.COM if (ixgbe_check_dma_handle(rx_data->rbd_area.dma_handle) != DDI_FM_OK) {
58010376SChenlu.Chen@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
58111233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
58211233SPaul.Guo@Sun.COM return (NULL);
5836621Sbt150084 }
5846621Sbt150084
5856621Sbt150084 /*
5866621Sbt150084 * Get the start point of rx bd ring which should be examined
5876621Sbt150084 * during this cycle.
5886621Sbt150084 */
58910376SChenlu.Chen@Sun.COM rx_next = rx_data->rbd_next;
59010376SChenlu.Chen@Sun.COM current_rbd = &rx_data->rbd_ring[rx_next];
5918275SEric Cheng received_bytes = 0;
5926621Sbt150084 pkt_num = 0;
5936621Sbt150084 status_error = current_rbd->wb.upper.status_error;
5946621Sbt150084 while (status_error & IXGBE_RXD_STAT_DD) {
5956621Sbt150084 /*
5966621Sbt150084 * If adapter has found errors, but the error
5976621Sbt150084 * is hardware checksum error, this does not discard the
5986621Sbt150084 * packet: let upper layer compute the checksum;
5996621Sbt150084 * Otherwise discard the packet.
6006621Sbt150084 */
6016621Sbt150084 if ((status_error & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) ||
60211486SZhen.W@Sun.COM ((!ixgbe->lro_enable) &&
60311486SZhen.W@Sun.COM (!(status_error & IXGBE_RXD_STAT_EOP)))) {
6046621Sbt150084 IXGBE_DEBUG_STAT(rx_ring->stat_frame_error);
6056621Sbt150084 goto rx_discard;
6066621Sbt150084 }
6076621Sbt150084
6086621Sbt150084 IXGBE_DEBUG_STAT_COND(rx_ring->stat_cksum_error,
6096621Sbt150084 (status_error & IXGBE_RXDADV_ERR_TCPE) ||
6106621Sbt150084 (status_error & IXGBE_RXDADV_ERR_IPE));
6116621Sbt150084
61211486SZhen.W@Sun.COM if (ixgbe->lro_enable) {
61311486SZhen.W@Sun.COM rsc_cnt = (current_rbd->wb.lower.lo_dword.data &
61411486SZhen.W@Sun.COM IXGBE_RXDADV_RSCCNT_MASK) >>
61511486SZhen.W@Sun.COM IXGBE_RXDADV_RSCCNT_SHIFT;
61611486SZhen.W@Sun.COM if (rsc_cnt != 0) {
61711486SZhen.W@Sun.COM if (status_error & IXGBE_RXD_STAT_EOP) {
61811486SZhen.W@Sun.COM pkt_len = current_rbd->wb.upper.length;
61911486SZhen.W@Sun.COM if (rx_data->work_list[rx_next]->
62011486SZhen.W@Sun.COM lro_prev != -1) {
62111486SZhen.W@Sun.COM lro_start =
62211486SZhen.W@Sun.COM ixgbe_lro_get_start(rx_data,
62311486SZhen.W@Sun.COM rx_next);
62411486SZhen.W@Sun.COM ixgbe->lro_pkt_count++;
62511486SZhen.W@Sun.COM pkt_len +=
62611486SZhen.W@Sun.COM (rx_data->lro_num - 1) *
62711486SZhen.W@Sun.COM ixgbe->rx_buf_size;
62811486SZhen.W@Sun.COM lro_eop = B_TRUE;
62911486SZhen.W@Sun.COM }
63011486SZhen.W@Sun.COM } else {
63111486SZhen.W@Sun.COM lro_next = (status_error &
63211486SZhen.W@Sun.COM IXGBE_RXDADV_NEXTP_MASK) >>
63311486SZhen.W@Sun.COM IXGBE_RXDADV_NEXTP_SHIFT;
63411486SZhen.W@Sun.COM rx_data->work_list[lro_next]->lro_prev
63511486SZhen.W@Sun.COM = rx_next;
63611486SZhen.W@Sun.COM rx_data->work_list[rx_next]->lro_next =
63711486SZhen.W@Sun.COM lro_next;
63811486SZhen.W@Sun.COM rx_data->work_list[rx_next]->lro_pkt =
63911486SZhen.W@Sun.COM B_TRUE;
64011486SZhen.W@Sun.COM goto rx_discard;
64111486SZhen.W@Sun.COM }
64211486SZhen.W@Sun.COM
64311486SZhen.W@Sun.COM } else {
64411486SZhen.W@Sun.COM pkt_len = current_rbd->wb.upper.length;
64511486SZhen.W@Sun.COM }
64611486SZhen.W@Sun.COM } else {
64711486SZhen.W@Sun.COM pkt_len = current_rbd->wb.upper.length;
64811486SZhen.W@Sun.COM }
64911486SZhen.W@Sun.COM
6508275SEric Cheng
6518275SEric Cheng if ((poll_bytes != IXGBE_POLL_NULL) &&
6528275SEric Cheng ((received_bytes + pkt_len) > poll_bytes))
6538275SEric Cheng break;
6548275SEric Cheng
6558275SEric Cheng received_bytes += pkt_len;
65611486SZhen.W@Sun.COM mp = NULL;
6578275SEric Cheng
6586621Sbt150084 /*
6596621Sbt150084 * For packets with length more than the copy threshold,
6606621Sbt150084 * we'll first try to use the existing DMA buffer to build
6616621Sbt150084 * an mblk and send the mblk upstream.
6626621Sbt150084 *
6636621Sbt150084 * If the first method fails, or the packet length is less
6646621Sbt150084 * than the copy threshold, we'll allocate a new mblk and
6656621Sbt150084 * copy the packet data to the new mblk.
6666621Sbt150084 */
66711486SZhen.W@Sun.COM if (lro_eop) {
66811486SZhen.W@Sun.COM mp = ixgbe_lro_bind(rx_data, lro_start,
66911486SZhen.W@Sun.COM rx_data->lro_num, pkt_len);
67011486SZhen.W@Sun.COM if (mp == NULL)
67111486SZhen.W@Sun.COM mp = ixgbe_lro_copy(rx_data, lro_start,
67211486SZhen.W@Sun.COM rx_data->lro_num, pkt_len);
67311486SZhen.W@Sun.COM lro_eop = B_FALSE;
67411486SZhen.W@Sun.COM rx_data->lro_num = 0;
6756621Sbt150084
67611486SZhen.W@Sun.COM } else {
67711486SZhen.W@Sun.COM if (pkt_len > ixgbe->rx_copy_thresh)
67811486SZhen.W@Sun.COM mp = ixgbe_rx_bind(rx_data, rx_next, pkt_len);
6796621Sbt150084
68011486SZhen.W@Sun.COM if (mp == NULL)
68111486SZhen.W@Sun.COM mp = ixgbe_rx_copy(rx_data, rx_next, pkt_len);
68211486SZhen.W@Sun.COM }
6836621Sbt150084 if (mp != NULL) {
6846621Sbt150084 /*
6856621Sbt150084 * Check h/w checksum offload status
6866621Sbt150084 */
6876621Sbt150084 if (ixgbe->rx_hcksum_enable)
6886621Sbt150084 ixgbe_rx_assoc_hcksum(mp, status_error);
6896621Sbt150084
6906621Sbt150084 *mblk_tail = mp;
6916621Sbt150084 mblk_tail = &mp->b_next;
6926621Sbt150084 }
6936621Sbt150084
6946621Sbt150084 rx_discard:
6956621Sbt150084 /*
6966621Sbt150084 * Reset rx descriptor read bits
6976621Sbt150084 */
69810376SChenlu.Chen@Sun.COM current_rcb = rx_data->work_list[rx_next];
69911486SZhen.W@Sun.COM if (ixgbe->lro_enable) {
70011486SZhen.W@Sun.COM if (!current_rcb->lro_pkt) {
70111486SZhen.W@Sun.COM current_rbd->read.pkt_addr =
70211486SZhen.W@Sun.COM current_rcb->rx_buf.dma_address;
70311486SZhen.W@Sun.COM current_rbd->read.hdr_addr = 0;
70411486SZhen.W@Sun.COM }
70511486SZhen.W@Sun.COM } else {
70611486SZhen.W@Sun.COM current_rbd->read.pkt_addr =
70711486SZhen.W@Sun.COM current_rcb->rx_buf.dma_address;
70811486SZhen.W@Sun.COM current_rbd->read.hdr_addr = 0;
70911486SZhen.W@Sun.COM }
7106621Sbt150084
71110376SChenlu.Chen@Sun.COM rx_next = NEXT_INDEX(rx_next, 1, rx_data->ring_size);
7126621Sbt150084
7136621Sbt150084 /*
7146621Sbt150084 * The receive function is in interrupt context, so here
71510376SChenlu.Chen@Sun.COM * rx_limit_per_intr is used to avoid doing receiving too long
7166621Sbt150084 * per interrupt.
7176621Sbt150084 */
71810376SChenlu.Chen@Sun.COM if (++pkt_num > ixgbe->rx_limit_per_intr) {
7196621Sbt150084 IXGBE_DEBUG_STAT(rx_ring->stat_exceed_pkt);
7206621Sbt150084 break;
7216621Sbt150084 }
7226621Sbt150084
72310376SChenlu.Chen@Sun.COM current_rbd = &rx_data->rbd_ring[rx_next];
7246621Sbt150084 status_error = current_rbd->wb.upper.status_error;
7256621Sbt150084 }
7266621Sbt150084
72711878SVenu.Iyer@Sun.COM rx_ring->stat_rbytes += received_bytes;
72811878SVenu.Iyer@Sun.COM rx_ring->stat_ipackets += pkt_num;
72911878SVenu.Iyer@Sun.COM
73010376SChenlu.Chen@Sun.COM DMA_SYNC(&rx_data->rbd_area, DDI_DMA_SYNC_FORDEV);
7316621Sbt150084
73210376SChenlu.Chen@Sun.COM rx_data->rbd_next = rx_next;
7336621Sbt150084
7346621Sbt150084 /*
7356621Sbt150084 * Update the h/w tail accordingly
7366621Sbt150084 */
73711486SZhen.W@Sun.COM if (ixgbe->lro_enable) {
73811486SZhen.W@Sun.COM lro_first = ixgbe_lro_get_first(rx_data, rx_next);
73911486SZhen.W@Sun.COM rx_tail = PREV_INDEX(lro_first, 1, rx_data->ring_size);
74011486SZhen.W@Sun.COM } else
74111486SZhen.W@Sun.COM rx_tail = PREV_INDEX(rx_next, 1, rx_data->ring_size);
74211486SZhen.W@Sun.COM
74311878SVenu.Iyer@Sun.COM IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_RDT(rx_ring->hw_index), rx_tail);
7446621Sbt150084
7456621Sbt150084 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
74610376SChenlu.Chen@Sun.COM ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_DEGRADED);
74711233SPaul.Guo@Sun.COM atomic_or_32(&ixgbe->ixgbe_state, IXGBE_ERROR);
7486621Sbt150084 }
7496621Sbt150084
7506621Sbt150084 return (mblk_head);
7516621Sbt150084 }
7528275SEric Cheng
7538275SEric Cheng mblk_t *
ixgbe_ring_rx_poll(void * arg,int n_bytes)7548275SEric Cheng ixgbe_ring_rx_poll(void *arg, int n_bytes)
7558275SEric Cheng {
7568275SEric Cheng ixgbe_rx_ring_t *rx_ring = (ixgbe_rx_ring_t *)arg;
7578275SEric Cheng mblk_t *mp = NULL;
7588275SEric Cheng
7598275SEric Cheng ASSERT(n_bytes >= 0);
7608275SEric Cheng
7618275SEric Cheng if (n_bytes == 0)
76211233SPaul.Guo@Sun.COM return (NULL);
7638275SEric Cheng
7648275SEric Cheng mutex_enter(&rx_ring->rx_lock);
7658275SEric Cheng mp = ixgbe_ring_rx(rx_ring, n_bytes);
7668275SEric Cheng mutex_exit(&rx_ring->rx_lock);
7678275SEric Cheng
7688275SEric Cheng return (mp);
7698275SEric Cheng }
770