13526Sxy150489 /*
23526Sxy150489 * This file is provided under a CDDLv1 license. When using or
33526Sxy150489 * redistributing this file, you may do so under this license.
43526Sxy150489 * In redistributing this file this license must be included
53526Sxy150489 * and no other modification of this header file is permitted.
63526Sxy150489 *
73526Sxy150489 * CDDL LICENSE SUMMARY
83526Sxy150489 *
98479SChenlu.Chen@Sun.COM * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved.
103526Sxy150489 *
113526Sxy150489 * The contents of this file are subject to the terms of Version
123526Sxy150489 * 1.0 of the Common Development and Distribution License (the "License").
133526Sxy150489 *
143526Sxy150489 * You should have received a copy of the License with this software.
153526Sxy150489 * You can obtain a copy of the License at
163526Sxy150489 * http://www.opensolaris.org/os/licensing.
173526Sxy150489 * See the License for the specific language governing permissions
183526Sxy150489 * and limitations under the License.
193526Sxy150489 */
203526Sxy150489
213526Sxy150489 /*
22*12853SChangqing.Li@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
233526Sxy150489 */
243526Sxy150489
253526Sxy150489 /*
263526Sxy150489 * **********************************************************************
273526Sxy150489 * *
283526Sxy150489 * Module Name: *
293526Sxy150489 * e1000g_rx.c *
303526Sxy150489 * *
313526Sxy150489 * Abstract: *
324919Sxy150489 * This file contains some routines that take care of Receive *
334919Sxy150489 * interrupt and also for the received packets it sends up to *
344919Sxy150489 * upper layer. *
353526Sxy150489 * It tries to do a zero copy if free buffers are available in *
364919Sxy150489 * the pool. *
373526Sxy150489 * *
383526Sxy150489 * **********************************************************************
393526Sxy150489 */
403526Sxy150489
413526Sxy150489 #include "e1000g_sw.h"
423526Sxy150489 #include "e1000g_debug.h"
433526Sxy150489
448850SMin.Xu@Sun.COM static p_rx_sw_packet_t e1000g_get_buf(e1000g_rx_data_t *rx_data);
453526Sxy150489 #pragma inline(e1000g_get_buf)
463526Sxy150489
473526Sxy150489 /*
484919Sxy150489 * e1000g_rxfree_func - the call-back function to reclaim rx buffer
494919Sxy150489 *
504919Sxy150489 * This function is called when an mp is freed by the user thru
514919Sxy150489 * freeb call (Only for mp constructed through desballoc call)
524919Sxy150489 * It returns back the freed buffer to the freelist
533526Sxy150489 */
543526Sxy150489 void
e1000g_rxfree_func(p_rx_sw_packet_t packet)554919Sxy150489 e1000g_rxfree_func(p_rx_sw_packet_t packet)
563526Sxy150489 {
578850SMin.Xu@Sun.COM e1000g_rx_data_t *rx_data;
588850SMin.Xu@Sun.COM private_devi_list_t *devi_node;
598850SMin.Xu@Sun.COM struct e1000g *Adapter;
608850SMin.Xu@Sun.COM uint32_t ring_cnt;
618850SMin.Xu@Sun.COM uint32_t ref_cnt;
628850SMin.Xu@Sun.COM unsigned char *address;
634919Sxy150489
648850SMin.Xu@Sun.COM if (packet->ref_cnt == 0) {
658850SMin.Xu@Sun.COM /*
668850SMin.Xu@Sun.COM * This case only happens when rx buffers are being freed
678850SMin.Xu@Sun.COM * in e1000g_stop() and freemsg() is called.
688850SMin.Xu@Sun.COM */
693526Sxy150489 return;
703526Sxy150489 }
713526Sxy150489
728850SMin.Xu@Sun.COM rx_data = (e1000g_rx_data_t *)(uintptr_t)packet->rx_data;
733526Sxy150489
743526Sxy150489 if (packet->mp == NULL) {
753526Sxy150489 /*
763526Sxy150489 * Allocate a mblk that binds to the data buffer
773526Sxy150489 */
788850SMin.Xu@Sun.COM address = (unsigned char *)packet->rx_buf->address;
798850SMin.Xu@Sun.COM if (address != NULL) {
808850SMin.Xu@Sun.COM packet->mp = desballoc((unsigned char *)
818995SMin.Xu@Sun.COM address, packet->rx_buf->size,
828850SMin.Xu@Sun.COM BPRI_MED, &packet->free_rtn);
838850SMin.Xu@Sun.COM }
843526Sxy150489 }
853526Sxy150489
868275SEric Cheng /*
878275SEric Cheng * Enqueue the recycled packets in a recycle queue. When freelist
888275SEric Cheng * dries up, move the entire chain of packets from recycle queue
898275SEric Cheng * to freelist. This helps in avoiding per packet mutex contention
908275SEric Cheng * around freelist.
918275SEric Cheng */
928850SMin.Xu@Sun.COM mutex_enter(&rx_data->recycle_lock);
938850SMin.Xu@Sun.COM QUEUE_PUSH_TAIL(&rx_data->recycle_list, &packet->Link);
948850SMin.Xu@Sun.COM rx_data->recycle_freepkt++;
958850SMin.Xu@Sun.COM mutex_exit(&rx_data->recycle_lock);
963526Sxy150489
978850SMin.Xu@Sun.COM ref_cnt = atomic_dec_32_nv(&packet->ref_cnt);
988850SMin.Xu@Sun.COM if (ref_cnt == 0) {
998949SChangqing.Li@Sun.COM mutex_enter(&e1000g_rx_detach_lock);
1008850SMin.Xu@Sun.COM e1000g_free_rx_sw_packet(packet, B_FALSE);
1014982Syy150190
1028850SMin.Xu@Sun.COM atomic_dec_32(&rx_data->pending_count);
1038850SMin.Xu@Sun.COM atomic_dec_32(&e1000g_mblks_pending);
1048850SMin.Xu@Sun.COM
1058850SMin.Xu@Sun.COM if ((rx_data->pending_count == 0) &&
1068850SMin.Xu@Sun.COM (rx_data->flag & E1000G_RX_STOPPED)) {
1078850SMin.Xu@Sun.COM devi_node = rx_data->priv_devi_node;
1084982Syy150190
1098850SMin.Xu@Sun.COM if (devi_node != NULL) {
1108850SMin.Xu@Sun.COM ring_cnt = atomic_dec_32_nv(
1118850SMin.Xu@Sun.COM &devi_node->pending_rx_count);
1128850SMin.Xu@Sun.COM if ((ring_cnt == 0) &&
1138850SMin.Xu@Sun.COM (devi_node->flag &
1148850SMin.Xu@Sun.COM E1000G_PRIV_DEVI_DETACH)) {
1158850SMin.Xu@Sun.COM e1000g_free_priv_devi_node(
1168850SMin.Xu@Sun.COM devi_node);
1178850SMin.Xu@Sun.COM }
1188850SMin.Xu@Sun.COM } else {
1198850SMin.Xu@Sun.COM Adapter = rx_data->rx_ring->adapter;
1208850SMin.Xu@Sun.COM atomic_dec_32(
1218850SMin.Xu@Sun.COM &Adapter->pending_rx_count);
1228850SMin.Xu@Sun.COM }
1238995SMin.Xu@Sun.COM
1248995SMin.Xu@Sun.COM e1000g_free_rx_pending_buffers(rx_data);
1258995SMin.Xu@Sun.COM e1000g_free_rx_data(rx_data);
1264982Syy150190 }
1278850SMin.Xu@Sun.COM mutex_exit(&e1000g_rx_detach_lock);
1284982Syy150190 }
1294982Syy150190 }
1304982Syy150190
1314982Syy150190 /*
1324919Sxy150489 * e1000g_rx_setup - setup rx data structures
1334919Sxy150489 *
1344919Sxy150489 * This routine initializes all of the receive related
1354919Sxy150489 * structures. This includes the receive descriptors, the
1364919Sxy150489 * actual receive buffers, and the rx_sw_packet software
1374919Sxy150489 * structures.
1383526Sxy150489 */
1393526Sxy150489 void
e1000g_rx_setup(struct e1000g * Adapter)1404919Sxy150489 e1000g_rx_setup(struct e1000g *Adapter)
1413526Sxy150489 {
1424919Sxy150489 struct e1000_hw *hw;
1434919Sxy150489 p_rx_sw_packet_t packet;
1443526Sxy150489 struct e1000_rx_desc *descriptor;
1454919Sxy150489 uint32_t buf_low;
1464919Sxy150489 uint32_t buf_high;
1473526Sxy150489 uint32_t reg_val;
1487607STed.You@Sun.COM uint32_t rctl;
1497607STed.You@Sun.COM uint32_t rxdctl;
1507607STed.You@Sun.COM uint32_t ert;
15110680SMin.Xu@Sun.COM uint16_t phy_data;
1523526Sxy150489 int i;
1533526Sxy150489 int size;
1548850SMin.Xu@Sun.COM e1000g_rx_data_t *rx_data;
1553526Sxy150489
1564919Sxy150489 hw = &Adapter->shared;
1578850SMin.Xu@Sun.COM rx_data = Adapter->rx_ring->rx_data;
1583526Sxy150489
1593526Sxy150489 /*
1603526Sxy150489 * zero out all of the receive buffer descriptor memory
1613526Sxy150489 * assures any previous data or status is erased
1623526Sxy150489 */
1638850SMin.Xu@Sun.COM bzero(rx_data->rbd_area,
1644919Sxy150489 sizeof (struct e1000_rx_desc) * Adapter->rx_desc_num);
1653526Sxy150489
1664919Sxy150489 if (!Adapter->rx_buffer_setup) {
1673526Sxy150489 /* Init the list of "Receive Buffer" */
1688850SMin.Xu@Sun.COM QUEUE_INIT_LIST(&rx_data->recv_list);
1693526Sxy150489
1703526Sxy150489 /* Init the list of "Free Receive Buffer" */
1718850SMin.Xu@Sun.COM QUEUE_INIT_LIST(&rx_data->free_list);
1723526Sxy150489
1738275SEric Cheng /* Init the list of "Free Receive Buffer" */
1748850SMin.Xu@Sun.COM QUEUE_INIT_LIST(&rx_data->recycle_list);
1753526Sxy150489 /*
1763526Sxy150489 * Setup Receive list and the Free list. Note that
1773526Sxy150489 * the both were allocated in one packet area.
1783526Sxy150489 */
1798850SMin.Xu@Sun.COM packet = rx_data->packet_area;
1808850SMin.Xu@Sun.COM descriptor = rx_data->rbd_first;
1813526Sxy150489
1824919Sxy150489 for (i = 0; i < Adapter->rx_desc_num;
1833526Sxy150489 i++, packet = packet->next, descriptor++) {
1843526Sxy150489 ASSERT(packet != NULL);
1853526Sxy150489 ASSERT(descriptor != NULL);
1863526Sxy150489 descriptor->buffer_addr =
1873526Sxy150489 packet->rx_buf->dma_address;
1884919Sxy150489
1894919Sxy150489 /* Add this rx_sw_packet to the receive list */
1908850SMin.Xu@Sun.COM QUEUE_PUSH_TAIL(&rx_data->recv_list,
1913526Sxy150489 &packet->Link);
1923526Sxy150489 }
1933526Sxy150489
1944919Sxy150489 for (i = 0; i < Adapter->rx_freelist_num;
1953526Sxy150489 i++, packet = packet->next) {
1963526Sxy150489 ASSERT(packet != NULL);
1974919Sxy150489 /* Add this rx_sw_packet to the free list */
1988850SMin.Xu@Sun.COM QUEUE_PUSH_TAIL(&rx_data->free_list,
1993526Sxy150489 &packet->Link);
2003526Sxy150489 }
2018850SMin.Xu@Sun.COM rx_data->avail_freepkt = Adapter->rx_freelist_num;
2028850SMin.Xu@Sun.COM rx_data->recycle_freepkt = 0;
2034919Sxy150489
2044919Sxy150489 Adapter->rx_buffer_setup = B_TRUE;
2053526Sxy150489 } else {
2063526Sxy150489 /* Setup the initial pointer to the first rx descriptor */
2074919Sxy150489 packet = (p_rx_sw_packet_t)
2088850SMin.Xu@Sun.COM QUEUE_GET_HEAD(&rx_data->recv_list);
2098850SMin.Xu@Sun.COM descriptor = rx_data->rbd_first;
2103526Sxy150489
2114919Sxy150489 for (i = 0; i < Adapter->rx_desc_num; i++) {
2123526Sxy150489 ASSERT(packet != NULL);
2133526Sxy150489 ASSERT(descriptor != NULL);
2143526Sxy150489 descriptor->buffer_addr =
2153526Sxy150489 packet->rx_buf->dma_address;
2164919Sxy150489
2174919Sxy150489 /* Get next rx_sw_packet */
2184919Sxy150489 packet = (p_rx_sw_packet_t)
2198850SMin.Xu@Sun.COM QUEUE_GET_NEXT(&rx_data->recv_list, &packet->Link);
2203526Sxy150489 descriptor++;
2213526Sxy150489 }
2223526Sxy150489 }
2233526Sxy150489
2245882Syy150190 E1000_WRITE_REG(&Adapter->shared, E1000_RDTR, Adapter->rx_intr_delay);
2255882Syy150190 E1000G_DEBUGLOG_1(Adapter, E1000G_INFO_LEVEL,
2265882Syy150190 "E1000_RDTR: 0x%x\n", Adapter->rx_intr_delay);
2275882Syy150190 if (hw->mac.type >= e1000_82540) {
2285882Syy150190 E1000_WRITE_REG(&Adapter->shared, E1000_RADV,
2295882Syy150190 Adapter->rx_intr_abs_delay);
2305882Syy150190 E1000G_DEBUGLOG_1(Adapter, E1000G_INFO_LEVEL,
2315882Syy150190 "E1000_RADV: 0x%x\n", Adapter->rx_intr_abs_delay);
2325882Syy150190 }
2335882Syy150190
2343526Sxy150489 /*
2353526Sxy150489 * Setup our descriptor pointers
2363526Sxy150489 */
2378850SMin.Xu@Sun.COM rx_data->rbd_next = rx_data->rbd_first;
2383526Sxy150489
2394919Sxy150489 size = Adapter->rx_desc_num * sizeof (struct e1000_rx_desc);
2406735Scc210113 E1000_WRITE_REG(hw, E1000_RDLEN(0), size);
2416735Scc210113 size = E1000_READ_REG(hw, E1000_RDLEN(0));
2423526Sxy150489
2433526Sxy150489 /* To get lower order bits */
2448850SMin.Xu@Sun.COM buf_low = (uint32_t)rx_data->rbd_dma_addr;
2453526Sxy150489 /* To get the higher order bits */
2468850SMin.Xu@Sun.COM buf_high = (uint32_t)(rx_data->rbd_dma_addr >> 32);
2473526Sxy150489
2486735Scc210113 E1000_WRITE_REG(hw, E1000_RDBAH(0), buf_high);
2496735Scc210113 E1000_WRITE_REG(hw, E1000_RDBAL(0), buf_low);
2503526Sxy150489
2513526Sxy150489 /*
2523526Sxy150489 * Setup our HW Rx Head & Tail descriptor pointers
2533526Sxy150489 */
2546735Scc210113 E1000_WRITE_REG(hw, E1000_RDT(0),
2558850SMin.Xu@Sun.COM (uint32_t)(rx_data->rbd_last - rx_data->rbd_first));
2566735Scc210113 E1000_WRITE_REG(hw, E1000_RDH(0), 0);
2573526Sxy150489
2583526Sxy150489 /*
2593526Sxy150489 * Setup the Receive Control Register (RCTL), and ENABLE the
2603526Sxy150489 * receiver. The initial configuration is to: Enable the receiver,
2613526Sxy150489 * accept broadcasts, discard bad packets (and long packets),
2623526Sxy150489 * disable VLAN filter checking, set the receive descriptor
2633526Sxy150489 * minimum threshold size to 1/2, and the receive buffer size to
2643526Sxy150489 * 2k.
2653526Sxy150489 */
2667607STed.You@Sun.COM rctl = E1000_RCTL_EN | /* Enable Receive Unit */
2673526Sxy150489 E1000_RCTL_BAM | /* Accept Broadcast Packets */
2684919Sxy150489 (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT) |
2693526Sxy150489 E1000_RCTL_RDMTS_HALF |
2703526Sxy150489 E1000_RCTL_LBM_NO; /* Loopback Mode = none */
2713526Sxy150489
272*12853SChangqing.Li@Sun.COM if (Adapter->default_mtu > ETHERMTU)
273*12853SChangqing.Li@Sun.COM rctl |= E1000_RCTL_LPE; /* Large Packet Enable bit */
274*12853SChangqing.Li@Sun.COM
2754608Syy150190 if (Adapter->strip_crc)
2767607STed.You@Sun.COM rctl |= E1000_RCTL_SECRC; /* Strip Ethernet CRC */
2774608Syy150190
2788417SChenlu.Chen@Sun.COM if (Adapter->mem_workaround_82546 &&
2798417SChenlu.Chen@Sun.COM ((hw->mac.type == e1000_82545) ||
2808178SChenlu.Chen@Sun.COM (hw->mac.type == e1000_82546) ||
2818417SChenlu.Chen@Sun.COM (hw->mac.type == e1000_82546_rev_3))) {
2827607STed.You@Sun.COM rctl |= E1000_RCTL_SZ_2048;
2838178SChenlu.Chen@Sun.COM } else {
2848178SChenlu.Chen@Sun.COM if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_2K) &&
2858178SChenlu.Chen@Sun.COM (Adapter->max_frame_size <= FRAME_SIZE_UPTO_4K))
2868178SChenlu.Chen@Sun.COM rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX;
2878178SChenlu.Chen@Sun.COM else if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_4K) &&
2888178SChenlu.Chen@Sun.COM (Adapter->max_frame_size <= FRAME_SIZE_UPTO_8K))
2898178SChenlu.Chen@Sun.COM rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX;
2908178SChenlu.Chen@Sun.COM else if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_8K) &&
2918178SChenlu.Chen@Sun.COM (Adapter->max_frame_size <= FRAME_SIZE_UPTO_16K))
2928178SChenlu.Chen@Sun.COM rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX;
2938178SChenlu.Chen@Sun.COM else
2948178SChenlu.Chen@Sun.COM rctl |= E1000_RCTL_SZ_2048;
2958178SChenlu.Chen@Sun.COM }
2963526Sxy150489
2974919Sxy150489 if (e1000_tbi_sbp_enabled_82543(hw))
2987607STed.You@Sun.COM rctl |= E1000_RCTL_SBP;
2993526Sxy150489
3004919Sxy150489 /*
3018479SChenlu.Chen@Sun.COM * Enable Early Receive Threshold (ERT) on supported devices.
3028479SChenlu.Chen@Sun.COM * Only takes effect when packet size is equal or larger than the
3038479SChenlu.Chen@Sun.COM * specified value (in 8 byte units), e.g. using jumbo frames.
3044919Sxy150489 */
3057607STed.You@Sun.COM if ((hw->mac.type == e1000_82573) ||
3067607STed.You@Sun.COM (hw->mac.type == e1000_82574) ||
3077607STed.You@Sun.COM (hw->mac.type == e1000_ich9lan) ||
3087607STed.You@Sun.COM (hw->mac.type == e1000_ich10lan)) {
3097607STed.You@Sun.COM
3107607STed.You@Sun.COM ert = E1000_ERT_2048;
3114919Sxy150489
3127607STed.You@Sun.COM /*
3137607STed.You@Sun.COM * Special modification when ERT and
3147607STed.You@Sun.COM * jumbo frames are enabled
3157607STed.You@Sun.COM */
3167607STed.You@Sun.COM if (Adapter->default_mtu > ETHERMTU) {
3177607STed.You@Sun.COM rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(0));
3187607STed.You@Sun.COM E1000_WRITE_REG(hw, E1000_RXDCTL(0), rxdctl | 0x3);
3197607STed.You@Sun.COM ert |= (1 << 13);
3207607STed.You@Sun.COM }
3217607STed.You@Sun.COM
3227607STed.You@Sun.COM E1000_WRITE_REG(hw, E1000_ERT, ert);
3237607STed.You@Sun.COM }
3243526Sxy150489
32510680SMin.Xu@Sun.COM /* Workaround errata on 82577/8 adapters with large frames */
32610680SMin.Xu@Sun.COM if ((hw->mac.type == e1000_pchlan) &&
32710680SMin.Xu@Sun.COM (Adapter->default_mtu > ETHERMTU)) {
32810680SMin.Xu@Sun.COM
32911143SGuoqing.Zhu@Sun.COM (void) e1000_read_phy_reg(hw, PHY_REG(770, 26), &phy_data);
33010680SMin.Xu@Sun.COM phy_data &= 0xfff8;
33110680SMin.Xu@Sun.COM phy_data |= (1 << 2);
33211143SGuoqing.Zhu@Sun.COM (void) e1000_write_phy_reg(hw, PHY_REG(770, 26), phy_data);
33310680SMin.Xu@Sun.COM
33410680SMin.Xu@Sun.COM if (hw->phy.type == e1000_phy_82577) {
33511143SGuoqing.Zhu@Sun.COM (void) e1000_read_phy_reg(hw, 22, &phy_data);
33610680SMin.Xu@Sun.COM phy_data &= 0x0fff;
33710680SMin.Xu@Sun.COM phy_data |= (1 << 14);
33811143SGuoqing.Zhu@Sun.COM (void) e1000_write_phy_reg(hw, 0x10, 0x2823);
33911143SGuoqing.Zhu@Sun.COM (void) e1000_write_phy_reg(hw, 0x11, 0x0003);
34011143SGuoqing.Zhu@Sun.COM (void) e1000_write_phy_reg(hw, 22, phy_data);
34110680SMin.Xu@Sun.COM }
34210680SMin.Xu@Sun.COM }
34310680SMin.Xu@Sun.COM
3443526Sxy150489 reg_val =
3453526Sxy150489 E1000_RXCSUM_TUOFL | /* TCP/UDP checksum offload Enable */
3463526Sxy150489 E1000_RXCSUM_IPOFL; /* IP checksum offload Enable */
3473526Sxy150489
3484919Sxy150489 E1000_WRITE_REG(hw, E1000_RXCSUM, reg_val);
3496871Szx151633
3506871Szx151633 /*
3516871Szx151633 * Workaround: Set bit 16 (IPv6_ExDIS) to disable the
3526871Szx151633 * processing of received IPV6 extension headers
3536871Szx151633 */
3546871Szx151633 if ((hw->mac.type == e1000_82571) || (hw->mac.type == e1000_82572)) {
3556871Szx151633 reg_val = E1000_READ_REG(hw, E1000_RFCTL);
3566871Szx151633 reg_val |= (E1000_RFCTL_IPV6_EX_DIS |
3576871Szx151633 E1000_RFCTL_NEW_IPV6_EXT_DIS);
3586871Szx151633 E1000_WRITE_REG(hw, E1000_RFCTL, reg_val);
3596871Szx151633 }
3607607STed.You@Sun.COM
3617607STed.You@Sun.COM /* Write to enable the receive unit */
3627607STed.You@Sun.COM E1000_WRITE_REG(hw, E1000_RCTL, rctl);
3633526Sxy150489 }
3643526Sxy150489
3653526Sxy150489 /*
3664919Sxy150489 * e1000g_get_buf - get an rx sw packet from the free_list
3673526Sxy150489 */
3684919Sxy150489 static p_rx_sw_packet_t
e1000g_get_buf(e1000g_rx_data_t * rx_data)3698850SMin.Xu@Sun.COM e1000g_get_buf(e1000g_rx_data_t *rx_data)
3703526Sxy150489 {
3714919Sxy150489 p_rx_sw_packet_t packet;
372*12853SChangqing.Li@Sun.COM struct e1000g *Adapter;
373*12853SChangqing.Li@Sun.COM
374*12853SChangqing.Li@Sun.COM Adapter = rx_data->rx_ring->adapter;
3753526Sxy150489
3768850SMin.Xu@Sun.COM mutex_enter(&rx_data->freelist_lock);
3774919Sxy150489 packet = (p_rx_sw_packet_t)
3788850SMin.Xu@Sun.COM QUEUE_POP_HEAD(&rx_data->free_list);
3798275SEric Cheng if (packet != NULL) {
3808850SMin.Xu@Sun.COM rx_data->avail_freepkt--;
381*12853SChangqing.Li@Sun.COM goto end;
382*12853SChangqing.Li@Sun.COM }
383*12853SChangqing.Li@Sun.COM
384*12853SChangqing.Li@Sun.COM /*
385*12853SChangqing.Li@Sun.COM * If the freelist has no packets, check the recycle list
386*12853SChangqing.Li@Sun.COM * to see if there are any available descriptor there.
387*12853SChangqing.Li@Sun.COM */
388*12853SChangqing.Li@Sun.COM mutex_enter(&rx_data->recycle_lock);
389*12853SChangqing.Li@Sun.COM QUEUE_SWITCH(&rx_data->free_list, &rx_data->recycle_list);
390*12853SChangqing.Li@Sun.COM rx_data->avail_freepkt = rx_data->recycle_freepkt;
391*12853SChangqing.Li@Sun.COM rx_data->recycle_freepkt = 0;
392*12853SChangqing.Li@Sun.COM mutex_exit(&rx_data->recycle_lock);
393*12853SChangqing.Li@Sun.COM packet = (p_rx_sw_packet_t)QUEUE_POP_HEAD(&rx_data->free_list);
394*12853SChangqing.Li@Sun.COM if (packet != NULL) {
395*12853SChangqing.Li@Sun.COM rx_data->avail_freepkt--;
396*12853SChangqing.Li@Sun.COM goto end;
397*12853SChangqing.Li@Sun.COM }
398*12853SChangqing.Li@Sun.COM
399*12853SChangqing.Li@Sun.COM if (Adapter->rx_freelist_num < Adapter->rx_freelist_limit) {
400*12853SChangqing.Li@Sun.COM (void) e1000g_increase_rx_packets(rx_data);
4018275SEric Cheng packet = (p_rx_sw_packet_t)
4028850SMin.Xu@Sun.COM QUEUE_POP_HEAD(&rx_data->free_list);
403*12853SChangqing.Li@Sun.COM if (packet != NULL) {
4048850SMin.Xu@Sun.COM rx_data->avail_freepkt--;
405*12853SChangqing.Li@Sun.COM }
4068275SEric Cheng }
407*12853SChangqing.Li@Sun.COM
408*12853SChangqing.Li@Sun.COM end:
4098850SMin.Xu@Sun.COM mutex_exit(&rx_data->freelist_lock);
4103526Sxy150489 return (packet);
4113526Sxy150489 }
4123526Sxy150489
4133526Sxy150489 /*
4144919Sxy150489 * e1000g_receive - main receive routine
4154919Sxy150489 *
4164919Sxy150489 * This routine will process packets received in an interrupt
4173526Sxy150489 */
4183526Sxy150489 mblk_t *
e1000g_receive(e1000g_rx_ring_t * rx_ring,mblk_t ** tail,uint_t sz)4198833SVenu.Iyer@Sun.COM e1000g_receive(e1000g_rx_ring_t *rx_ring, mblk_t **tail, uint_t sz)
4203526Sxy150489 {
4214919Sxy150489 struct e1000_hw *hw;
4223526Sxy150489 mblk_t *nmp;
4233526Sxy150489 mblk_t *ret_mp;
4243526Sxy150489 mblk_t *ret_nmp;
4253526Sxy150489 struct e1000_rx_desc *current_desc;
4263526Sxy150489 struct e1000_rx_desc *last_desc;
4274919Sxy150489 p_rx_sw_packet_t packet;
4284919Sxy150489 p_rx_sw_packet_t newpkt;
4297607STed.You@Sun.COM uint16_t length;
4303526Sxy150489 uint32_t pkt_count;
4313526Sxy150489 uint32_t desc_count;
4324919Sxy150489 boolean_t accept_frame;
4333526Sxy150489 boolean_t end_of_packet;
4343526Sxy150489 boolean_t need_copy;
4358275SEric Cheng struct e1000g *Adapter;
4363526Sxy150489 dma_buffer_t *rx_buf;
4373526Sxy150489 uint16_t cksumflags;
4388833SVenu.Iyer@Sun.COM uint_t chain_sz = 0;
4398850SMin.Xu@Sun.COM e1000g_rx_data_t *rx_data;
4408995SMin.Xu@Sun.COM uint32_t max_size;
4418995SMin.Xu@Sun.COM uint32_t min_size;
4423526Sxy150489
4433526Sxy150489 ret_mp = NULL;
4443526Sxy150489 ret_nmp = NULL;
4453526Sxy150489 pkt_count = 0;
4463526Sxy150489 desc_count = 0;
4473526Sxy150489 cksumflags = 0;
4483526Sxy150489
4498275SEric Cheng Adapter = rx_ring->adapter;
4508850SMin.Xu@Sun.COM rx_data = rx_ring->rx_data;
4514919Sxy150489 hw = &Adapter->shared;
4523526Sxy150489
4533526Sxy150489 /* Sync the Rx descriptor DMA buffers */
4548850SMin.Xu@Sun.COM (void) ddi_dma_sync(rx_data->rbd_dma_handle,
4554919Sxy150489 0, 0, DDI_DMA_SYNC_FORKERNEL);
4563526Sxy150489
4578850SMin.Xu@Sun.COM if (e1000g_check_dma_handle(rx_data->rbd_dma_handle) != DDI_FM_OK) {
4585273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
4598479SChenlu.Chen@Sun.COM Adapter->e1000g_state |= E1000G_ERROR;
46010805SChangqing.Li@Sun.COM return (NULL);
4615273Sgl147354 }
4625273Sgl147354
4638850SMin.Xu@Sun.COM current_desc = rx_data->rbd_next;
4643526Sxy150489 if (!(current_desc->status & E1000_RXD_STAT_DD)) {
4653526Sxy150489 /*
4663526Sxy150489 * don't send anything up. just clear the RFD
4673526Sxy150489 */
4684919Sxy150489 E1000G_DEBUG_STAT(rx_ring->stat_none);
46910805SChangqing.Li@Sun.COM return (NULL);
4703526Sxy150489 }
4713526Sxy150489
4728995SMin.Xu@Sun.COM max_size = Adapter->max_frame_size - ETHERFCSL - VLAN_TAGSZ;
4738995SMin.Xu@Sun.COM min_size = ETHERMIN;
4748995SMin.Xu@Sun.COM
4753526Sxy150489 /*
4763526Sxy150489 * Loop through the receive descriptors starting at the last known
4773526Sxy150489 * descriptor owned by the hardware that begins a packet.
4783526Sxy150489 */
4793526Sxy150489 while ((current_desc->status & E1000_RXD_STAT_DD) &&
4808833SVenu.Iyer@Sun.COM (pkt_count < Adapter->rx_limit_onintr) &&
4818833SVenu.Iyer@Sun.COM ((sz == E1000G_CHAIN_NO_LIMIT) || (chain_sz <= sz))) {
4823526Sxy150489
4833526Sxy150489 desc_count++;
4843526Sxy150489 /*
4853526Sxy150489 * Now this can happen in Jumbo frame situation.
4863526Sxy150489 */
4873526Sxy150489 if (current_desc->status & E1000_RXD_STAT_EOP) {
4883526Sxy150489 /* packet has EOP set */
4893526Sxy150489 end_of_packet = B_TRUE;
4903526Sxy150489 } else {
4913526Sxy150489 /*
4923526Sxy150489 * If this received buffer does not have the
4933526Sxy150489 * End-Of-Packet bit set, the received packet
4943526Sxy150489 * will consume multiple buffers. We won't send this
4953526Sxy150489 * packet upstack till we get all the related buffers.
4963526Sxy150489 */
4973526Sxy150489 end_of_packet = B_FALSE;
4983526Sxy150489 }
4993526Sxy150489
5003526Sxy150489 /*
5013526Sxy150489 * Get a pointer to the actual receive buffer
5023526Sxy150489 * The mp->b_rptr is mapped to The CurrentDescriptor
5033526Sxy150489 * Buffer Address.
5043526Sxy150489 */
5053526Sxy150489 packet =
50612246SChangqing.Li@Sun.COM (p_rx_sw_packet_t)QUEUE_POP_HEAD(&rx_data->recv_list);
5073526Sxy150489 ASSERT(packet != NULL);
5083526Sxy150489
5093526Sxy150489 rx_buf = packet->rx_buf;
5103526Sxy150489
5113526Sxy150489 length = current_desc->length;
5123526Sxy150489
5133526Sxy150489 #ifdef __sparc
5144919Sxy150489 if (packet->dma_type == USE_DVMA)
5153526Sxy150489 dvma_sync(rx_buf->dma_handle, 0,
5163526Sxy150489 DDI_DMA_SYNC_FORKERNEL);
5174919Sxy150489 else
5183526Sxy150489 (void) ddi_dma_sync(rx_buf->dma_handle,
5193526Sxy150489 E1000G_IPALIGNROOM, length,
5204919Sxy150489 DDI_DMA_SYNC_FORKERNEL);
5214919Sxy150489 #else
5224919Sxy150489 (void) ddi_dma_sync(rx_buf->dma_handle,
5234919Sxy150489 E1000G_IPALIGNROOM, length,
5244919Sxy150489 DDI_DMA_SYNC_FORKERNEL);
5254919Sxy150489 #endif
5264919Sxy150489
5275273Sgl147354 if (e1000g_check_dma_handle(
5285273Sgl147354 rx_buf->dma_handle) != DDI_FM_OK) {
5295273Sgl147354 ddi_fm_service_impact(Adapter->dip,
5305273Sgl147354 DDI_SERVICE_DEGRADED);
5318479SChenlu.Chen@Sun.COM Adapter->e1000g_state |= E1000G_ERROR;
53210805SChangqing.Li@Sun.COM
53310805SChangqing.Li@Sun.COM goto rx_drop;
5345273Sgl147354 }
5355273Sgl147354
5364919Sxy150489 accept_frame = (current_desc->errors == 0) ||
5374919Sxy150489 ((current_desc->errors &
5384919Sxy150489 (E1000_RXD_ERR_TCPE | E1000_RXD_ERR_IPE)) != 0);
5394919Sxy150489
5404919Sxy150489 if (hw->mac.type == e1000_82543) {
5414919Sxy150489 unsigned char last_byte;
5424919Sxy150489
5434919Sxy150489 last_byte =
5444919Sxy150489 *((unsigned char *)rx_buf->address + length - 1);
5454919Sxy150489
5464919Sxy150489 if (TBI_ACCEPT(hw,
5474919Sxy150489 current_desc->status, current_desc->errors,
5486735Scc210113 current_desc->length, last_byte,
5496735Scc210113 Adapter->min_frame_size, Adapter->max_frame_size)) {
5504919Sxy150489
5514919Sxy150489 e1000_tbi_adjust_stats(Adapter,
5524919Sxy150489 length, hw->mac.addr);
5534919Sxy150489
5544919Sxy150489 length--;
5554919Sxy150489 accept_frame = B_TRUE;
5564919Sxy150489 } else if (e1000_tbi_sbp_enabled_82543(hw) &&
5574919Sxy150489 (current_desc->errors == E1000_RXD_ERR_CE)) {
5584919Sxy150489 accept_frame = B_TRUE;
5594919Sxy150489 }
5603526Sxy150489 }
5613526Sxy150489
5623526Sxy150489 /*
5633526Sxy150489 * Indicate the packet to the NOS if it was good.
5643526Sxy150489 * Normally, hardware will discard bad packets for us.
5653526Sxy150489 * Check for the packet to be a valid Ethernet packet
5663526Sxy150489 */
5674919Sxy150489 if (!accept_frame) {
5683526Sxy150489 /*
5693526Sxy150489 * error in incoming packet, either the packet is not a
5703526Sxy150489 * ethernet size packet, or the packet has an error. In
5713526Sxy150489 * either case, the packet will simply be discarded.
5723526Sxy150489 */
5734919Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
5743526Sxy150489 "Process Receive Interrupts: Error in Packet\n");
5753526Sxy150489
5764919Sxy150489 E1000G_STAT(rx_ring->stat_error);
5773526Sxy150489 /*
5783526Sxy150489 * Returning here as we are done here. There is
5793526Sxy150489 * no point in waiting for while loop to elapse
5803526Sxy150489 * and the things which were done. More efficient
5813526Sxy150489 * and less error prone...
5823526Sxy150489 */
5833526Sxy150489 goto rx_drop;
5843526Sxy150489 }
5853526Sxy150489
5864608Syy150190 /*
5874608Syy150190 * If the Ethernet CRC is not stripped by the hardware,
5884608Syy150190 * we need to strip it before sending it up to the stack.
5894608Syy150190 */
5904608Syy150190 if (end_of_packet && !Adapter->strip_crc) {
5916394Scc210113 if (length > ETHERFCSL) {
5926394Scc210113 length -= ETHERFCSL;
5934608Syy150190 } else {
5944608Syy150190 /*
5954608Syy150190 * If the fragment is smaller than the CRC,
5964608Syy150190 * drop this fragment, do the processing of
5974608Syy150190 * the end of the packet.
5984608Syy150190 */
599*12853SChangqing.Li@Sun.COM if (rx_data->rx_mblk_tail == NULL) {
600*12853SChangqing.Li@Sun.COM E1000G_STAT(rx_ring->stat_crc_only_pkt);
601*12853SChangqing.Li@Sun.COM goto rx_next_desc;
602*12853SChangqing.Li@Sun.COM }
603*12853SChangqing.Li@Sun.COM
6048850SMin.Xu@Sun.COM rx_data->rx_mblk_tail->b_wptr -=
6056394Scc210113 ETHERFCSL - length;
6068850SMin.Xu@Sun.COM rx_data->rx_mblk_len -=
6076394Scc210113 ETHERFCSL - length;
6084608Syy150190 goto rx_end_of_packet;
6094608Syy150190 }
6104608Syy150190 }
6114608Syy150190
6123526Sxy150489 need_copy = B_TRUE;
6133526Sxy150489
6143526Sxy150489 if (length <= Adapter->rx_bcopy_thresh)
6153526Sxy150489 goto rx_copy;
6163526Sxy150489
6173526Sxy150489 /*
6183526Sxy150489 * Get the pre-constructed mblk that was associated
6193526Sxy150489 * to the receive data buffer.
6203526Sxy150489 */
6213526Sxy150489 if (packet->mp == NULL) {
6223526Sxy150489 packet->mp = desballoc((unsigned char *)
6238995SMin.Xu@Sun.COM rx_buf->address, length,
6243526Sxy150489 BPRI_MED, &packet->free_rtn);
6253526Sxy150489 }
6263526Sxy150489
6273526Sxy150489 if (packet->mp != NULL) {
6283526Sxy150489 /*
6293526Sxy150489 * We have two sets of buffer pool. One associated with
6303526Sxy150489 * the Rxdescriptors and other a freelist buffer pool.
6313526Sxy150489 * Each time we get a good packet, Try to get a buffer
6323526Sxy150489 * from the freelist pool using e1000g_get_buf. If we
6333526Sxy150489 * get free buffer, then replace the descriptor buffer
6343526Sxy150489 * address with the free buffer we just got, and pass
6353526Sxy150489 * the pre-constructed mblk upstack. (note no copying)
6363526Sxy150489 *
6373526Sxy150489 * If we failed to get a free buffer, then try to
6383526Sxy150489 * allocate a new buffer(mp) and copy the recv buffer
6393526Sxy150489 * content to our newly allocated buffer(mp). Don't
6403526Sxy150489 * disturb the desriptor buffer address. (note copying)
6413526Sxy150489 */
6428850SMin.Xu@Sun.COM newpkt = e1000g_get_buf(rx_data);
6433526Sxy150489
6443526Sxy150489 if (newpkt != NULL) {
6453526Sxy150489 /*
6463526Sxy150489 * Get the mblk associated to the data,
6473526Sxy150489 * and strip it off the sw packet.
6483526Sxy150489 */
6493526Sxy150489 nmp = packet->mp;
6503526Sxy150489 packet->mp = NULL;
6518850SMin.Xu@Sun.COM atomic_inc_32(&packet->ref_cnt);
6523526Sxy150489
6533526Sxy150489 /*
6543526Sxy150489 * Now replace old buffer with the new
6553526Sxy150489 * one we got from free list
6563526Sxy150489 * Both the RxSwPacket as well as the
6573526Sxy150489 * Receive Buffer Descriptor will now
6583526Sxy150489 * point to this new packet.
6593526Sxy150489 */
6603526Sxy150489 packet = newpkt;
6614919Sxy150489
6623526Sxy150489 current_desc->buffer_addr =
6633526Sxy150489 newpkt->rx_buf->dma_address;
6644919Sxy150489
6653526Sxy150489 need_copy = B_FALSE;
6663526Sxy150489 } else {
66711143SGuoqing.Zhu@Sun.COM /* EMPTY */
6684919Sxy150489 E1000G_DEBUG_STAT(rx_ring->stat_no_freepkt);
6693526Sxy150489 }
6703526Sxy150489 }
6713526Sxy150489
6723526Sxy150489 rx_copy:
6733526Sxy150489 if (need_copy) {
6743526Sxy150489 /*
6753526Sxy150489 * No buffers available on free list,
6763526Sxy150489 * bcopy the data from the buffer and
6773526Sxy150489 * keep the original buffer. Dont want to
6783526Sxy150489 * do this.. Yack but no other way
6793526Sxy150489 */
6804919Sxy150489 if ((nmp = allocb(length + E1000G_IPALIGNROOM,
6814608Syy150190 BPRI_MED)) == NULL) {
6823526Sxy150489 /*
6833526Sxy150489 * The system has no buffers available
6843526Sxy150489 * to send up the incoming packet, hence
6853526Sxy150489 * the packet will have to be processed
6863526Sxy150489 * when there're more buffers available.
6873526Sxy150489 */
6884919Sxy150489 E1000G_STAT(rx_ring->stat_allocb_fail);
6893526Sxy150489 goto rx_drop;
6903526Sxy150489 }
6913526Sxy150489 nmp->b_rptr += E1000G_IPALIGNROOM;
6923526Sxy150489 nmp->b_wptr += E1000G_IPALIGNROOM;
6933526Sxy150489 /*
6943526Sxy150489 * The free list did not have any buffers
6953526Sxy150489 * available, so, the received packet will
6963526Sxy150489 * have to be copied into a mp and the original
6973526Sxy150489 * buffer will have to be retained for future
6983526Sxy150489 * packet reception.
6993526Sxy150489 */
7004919Sxy150489 bcopy(rx_buf->address, nmp->b_wptr, length);
7013526Sxy150489 }
7023526Sxy150489
7033526Sxy150489 ASSERT(nmp != NULL);
7043526Sxy150489 nmp->b_wptr += length;
7053526Sxy150489
7068850SMin.Xu@Sun.COM if (rx_data->rx_mblk == NULL) {
7073526Sxy150489 /*
7083526Sxy150489 * TCP/UDP checksum offload and
7093526Sxy150489 * IP checksum offload
7103526Sxy150489 */
7114919Sxy150489 if (!(current_desc->status & E1000_RXD_STAT_IXSM)) {
7123526Sxy150489 /*
7133526Sxy150489 * Check TCP/UDP checksum
7143526Sxy150489 */
7153526Sxy150489 if ((current_desc->status &
7164608Syy150190 E1000_RXD_STAT_TCPCS) &&
7173526Sxy150489 !(current_desc->errors &
7184608Syy150190 E1000_RXD_ERR_TCPE))
71911878SVenu.Iyer@Sun.COM cksumflags |= HCK_FULLCKSUM_OK;
7203526Sxy150489 /*
7213526Sxy150489 * Check IP Checksum
7223526Sxy150489 */
7233526Sxy150489 if ((current_desc->status &
7244608Syy150190 E1000_RXD_STAT_IPCS) &&
7253526Sxy150489 !(current_desc->errors &
7264608Syy150190 E1000_RXD_ERR_IPE))
72711878SVenu.Iyer@Sun.COM cksumflags |= HCK_IPV4_HDRCKSUM_OK;
7283526Sxy150489 }
7293526Sxy150489 }
7303526Sxy150489
7313526Sxy150489 /*
7323526Sxy150489 * We need to maintain our packet chain in the global
7333526Sxy150489 * Adapter structure, for the Rx processing can end
7343526Sxy150489 * with a fragment that has no EOP set.
7353526Sxy150489 */
7368850SMin.Xu@Sun.COM if (rx_data->rx_mblk == NULL) {
7373526Sxy150489 /* Get the head of the message chain */
7388850SMin.Xu@Sun.COM rx_data->rx_mblk = nmp;
7398850SMin.Xu@Sun.COM rx_data->rx_mblk_tail = nmp;
7408850SMin.Xu@Sun.COM rx_data->rx_mblk_len = length;
7413526Sxy150489 } else { /* Not the first packet */
7423526Sxy150489 /* Continue adding buffers */
7438850SMin.Xu@Sun.COM rx_data->rx_mblk_tail->b_cont = nmp;
7448850SMin.Xu@Sun.COM rx_data->rx_mblk_tail = nmp;
7458850SMin.Xu@Sun.COM rx_data->rx_mblk_len += length;
7463526Sxy150489 }
7478850SMin.Xu@Sun.COM ASSERT(rx_data->rx_mblk != NULL);
7488850SMin.Xu@Sun.COM ASSERT(rx_data->rx_mblk_tail != NULL);
7498850SMin.Xu@Sun.COM ASSERT(rx_data->rx_mblk_tail->b_cont == NULL);
7503526Sxy150489
7513526Sxy150489 /*
7523526Sxy150489 * Now this MP is ready to travel upwards but some more
7533526Sxy150489 * fragments are coming.
7543526Sxy150489 * We will send packet upwards as soon as we get EOP
7553526Sxy150489 * set on the packet.
7563526Sxy150489 */
7573526Sxy150489 if (!end_of_packet) {
7583526Sxy150489 /*
7593526Sxy150489 * continue to get the next descriptor,
7603526Sxy150489 * Tail would be advanced at the end
7613526Sxy150489 */
7623526Sxy150489 goto rx_next_desc;
7633526Sxy150489 }
7643526Sxy150489
7654608Syy150190 rx_end_of_packet:
7668995SMin.Xu@Sun.COM if (E1000G_IS_VLAN_PACKET(rx_data->rx_mblk->b_rptr))
7678995SMin.Xu@Sun.COM max_size = Adapter->max_frame_size - ETHERFCSL;
7688995SMin.Xu@Sun.COM
7698995SMin.Xu@Sun.COM if ((rx_data->rx_mblk_len > max_size) ||
7708995SMin.Xu@Sun.COM (rx_data->rx_mblk_len < min_size)) {
7718995SMin.Xu@Sun.COM E1000G_STAT(rx_ring->stat_size_error);
7728995SMin.Xu@Sun.COM goto rx_drop;
7738995SMin.Xu@Sun.COM }
7748995SMin.Xu@Sun.COM
7753526Sxy150489 /*
7763526Sxy150489 * Found packet with EOP
7773526Sxy150489 * Process the last fragment.
7783526Sxy150489 */
7793526Sxy150489 if (cksumflags != 0) {
78011878SVenu.Iyer@Sun.COM mac_hcksum_set(rx_data->rx_mblk,
78111878SVenu.Iyer@Sun.COM 0, 0, 0, 0, cksumflags);
7823526Sxy150489 cksumflags = 0;
7833526Sxy150489 }
7843526Sxy150489
7853526Sxy150489 /*
7863526Sxy150489 * Count packets that span multi-descriptors
7873526Sxy150489 */
7884919Sxy150489 E1000G_DEBUG_STAT_COND(rx_ring->stat_multi_desc,
7898850SMin.Xu@Sun.COM (rx_data->rx_mblk->b_cont != NULL));
7903526Sxy150489
7913526Sxy150489 /*
7923526Sxy150489 * Append to list to send upstream
7933526Sxy150489 */
7943526Sxy150489 if (ret_mp == NULL) {
7958850SMin.Xu@Sun.COM ret_mp = ret_nmp = rx_data->rx_mblk;
7963526Sxy150489 } else {
7978850SMin.Xu@Sun.COM ret_nmp->b_next = rx_data->rx_mblk;
7988850SMin.Xu@Sun.COM ret_nmp = rx_data->rx_mblk;
7993526Sxy150489 }
8003526Sxy150489 ret_nmp->b_next = NULL;
8018275SEric Cheng *tail = ret_nmp;
8028833SVenu.Iyer@Sun.COM chain_sz += length;
8033526Sxy150489
8048850SMin.Xu@Sun.COM rx_data->rx_mblk = NULL;
8058850SMin.Xu@Sun.COM rx_data->rx_mblk_tail = NULL;
8068850SMin.Xu@Sun.COM rx_data->rx_mblk_len = 0;
8073526Sxy150489
8083526Sxy150489 pkt_count++;
8093526Sxy150489
8103526Sxy150489 rx_next_desc:
8113526Sxy150489 /*
8123526Sxy150489 * Zero out the receive descriptors status
8133526Sxy150489 */
8143526Sxy150489 current_desc->status = 0;
8153526Sxy150489
8168850SMin.Xu@Sun.COM if (current_desc == rx_data->rbd_last)
8178850SMin.Xu@Sun.COM rx_data->rbd_next = rx_data->rbd_first;
8183526Sxy150489 else
8198850SMin.Xu@Sun.COM rx_data->rbd_next++;
8203526Sxy150489
8213526Sxy150489 last_desc = current_desc;
8228850SMin.Xu@Sun.COM current_desc = rx_data->rbd_next;
8233526Sxy150489
8243526Sxy150489 /*
8253526Sxy150489 * Put the buffer that we just indicated back
8263526Sxy150489 * at the end of our list
8273526Sxy150489 */
8288850SMin.Xu@Sun.COM QUEUE_PUSH_TAIL(&rx_data->recv_list,
8293526Sxy150489 &packet->Link);
8303526Sxy150489 } /* while loop */
8313526Sxy150489
8323526Sxy150489 /* Sync the Rx descriptor DMA buffers */
8338850SMin.Xu@Sun.COM (void) ddi_dma_sync(rx_data->rbd_dma_handle,
8344919Sxy150489 0, 0, DDI_DMA_SYNC_FORDEV);
8353526Sxy150489
8363526Sxy150489 /*
8373526Sxy150489 * Advance the E1000's Receive Queue #0 "Tail Pointer".
8383526Sxy150489 */
8396735Scc210113 E1000_WRITE_REG(hw, E1000_RDT(0),
8408850SMin.Xu@Sun.COM (uint32_t)(last_desc - rx_data->rbd_first));
8413526Sxy150489
8425273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
8435273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
8448479SChenlu.Chen@Sun.COM Adapter->e1000g_state |= E1000G_ERROR;
8455273Sgl147354 }
8465273Sgl147354
8475882Syy150190 Adapter->rx_pkt_cnt = pkt_count;
8485882Syy150190
8493526Sxy150489 return (ret_mp);
8503526Sxy150489
8513526Sxy150489 rx_drop:
8523526Sxy150489 /*
8533526Sxy150489 * Zero out the receive descriptors status
8543526Sxy150489 */
8553526Sxy150489 current_desc->status = 0;
8563526Sxy150489
8573526Sxy150489 /* Sync the Rx descriptor DMA buffers */
8588850SMin.Xu@Sun.COM (void) ddi_dma_sync(rx_data->rbd_dma_handle,
8594919Sxy150489 0, 0, DDI_DMA_SYNC_FORDEV);
8603526Sxy150489
8618850SMin.Xu@Sun.COM if (current_desc == rx_data->rbd_last)
8628850SMin.Xu@Sun.COM rx_data->rbd_next = rx_data->rbd_first;
8633526Sxy150489 else
8648850SMin.Xu@Sun.COM rx_data->rbd_next++;
8653526Sxy150489
8663526Sxy150489 last_desc = current_desc;
8673526Sxy150489
8688850SMin.Xu@Sun.COM QUEUE_PUSH_TAIL(&rx_data->recv_list, &packet->Link);
8693526Sxy150489 /*
8703526Sxy150489 * Reclaim all old buffers already allocated during
8713526Sxy150489 * Jumbo receives.....for incomplete reception
8723526Sxy150489 */
8738850SMin.Xu@Sun.COM if (rx_data->rx_mblk != NULL) {
8748850SMin.Xu@Sun.COM freemsg(rx_data->rx_mblk);
8758850SMin.Xu@Sun.COM rx_data->rx_mblk = NULL;
8768850SMin.Xu@Sun.COM rx_data->rx_mblk_tail = NULL;
8778850SMin.Xu@Sun.COM rx_data->rx_mblk_len = 0;
8783526Sxy150489 }
8793526Sxy150489 /*
8803526Sxy150489 * Advance the E1000's Receive Queue #0 "Tail Pointer".
8813526Sxy150489 */
8826735Scc210113 E1000_WRITE_REG(hw, E1000_RDT(0),
8838850SMin.Xu@Sun.COM (uint32_t)(last_desc - rx_data->rbd_first));
8843526Sxy150489
8855273Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
8865273Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
8878479SChenlu.Chen@Sun.COM Adapter->e1000g_state |= E1000G_ERROR;
8885273Sgl147354 }
8895273Sgl147354
8903526Sxy150489 return (ret_mp);
8913526Sxy150489 }
892