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(¤t_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, ¤t_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(¤t_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(¤t_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(¤t_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, ¤t_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(¤t_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(¤t_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