xref: /onnv-gate/usr/src/uts/common/io/e1000g/e1000g_rx.c (revision 12853:636a63adb7b9)
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