xref: /onnv-gate/usr/src/uts/common/io/e1000g/e1000g_rx.c (revision 8833:8adf20bc60e3)
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 /*
228479SChenlu.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
238275SEric Cheng  * Use is subject to license terms.
243526Sxy150489  */
253526Sxy150489 
263526Sxy150489 /*
273526Sxy150489  * **********************************************************************
283526Sxy150489  *									*
293526Sxy150489  * Module Name:								*
303526Sxy150489  *   e1000g_rx.c							*
313526Sxy150489  *									*
323526Sxy150489  * Abstract:								*
334919Sxy150489  *   This file contains some routines that take care of Receive		*
344919Sxy150489  *   interrupt and also for the received packets it sends up to		*
354919Sxy150489  *   upper layer.							*
363526Sxy150489  *   It tries to do a zero copy if free buffers are available in	*
374919Sxy150489  *   the pool.								*
383526Sxy150489  *									*
393526Sxy150489  * **********************************************************************
403526Sxy150489  */
413526Sxy150489 
423526Sxy150489 #include "e1000g_sw.h"
433526Sxy150489 #include "e1000g_debug.h"
443526Sxy150489 
454919Sxy150489 static p_rx_sw_packet_t e1000g_get_buf(e1000g_rx_ring_t *rx_ring);
463526Sxy150489 #pragma	inline(e1000g_get_buf)
474982Syy150190 static void e1000g_priv_devi_list_clean();
483526Sxy150489 
493526Sxy150489 /*
504919Sxy150489  * e1000g_rxfree_func - the call-back function to reclaim rx buffer
514919Sxy150489  *
524919Sxy150489  * This function is called when an mp is freed by the user thru
534919Sxy150489  * freeb call (Only for mp constructed through desballoc call)
544919Sxy150489  * It returns back the freed buffer to the freelist
553526Sxy150489  */
563526Sxy150489 void
574919Sxy150489 e1000g_rxfree_func(p_rx_sw_packet_t packet)
583526Sxy150489 {
593526Sxy150489 	e1000g_rx_ring_t *rx_ring;
603526Sxy150489 
617426SChenliang.Xu@Sun.COM 	rx_ring = (e1000g_rx_ring_t *)(uintptr_t)packet->rx_ring;
624919Sxy150489 
633526Sxy150489 	/*
643526Sxy150489 	 * Here the rx recycling processes different rx packets in different
653526Sxy150489 	 * threads, so we protect it with RW_READER to ensure it won't block
663526Sxy150489 	 * other rx recycling threads.
673526Sxy150489 	 */
683526Sxy150489 	rw_enter(&e1000g_rx_detach_lock, RW_READER);
693526Sxy150489 
704919Sxy150489 	if (packet->flag == E1000G_RX_SW_FREE) {
713526Sxy150489 		rw_exit(&e1000g_rx_detach_lock);
723526Sxy150489 		return;
733526Sxy150489 	}
743526Sxy150489 
754919Sxy150489 	if (packet->flag == E1000G_RX_SW_STOP) {
764919Sxy150489 		packet->flag = E1000G_RX_SW_FREE;
774919Sxy150489 		rw_exit(&e1000g_rx_detach_lock);
784919Sxy150489 
794919Sxy150489 		rw_enter(&e1000g_rx_detach_lock, RW_WRITER);
804919Sxy150489 		rx_ring->pending_count--;
814919Sxy150489 		e1000g_mblks_pending--;
824919Sxy150489 
834919Sxy150489 		if (rx_ring->pending_count == 0) {
844919Sxy150489 			while (rx_ring->pending_list != NULL) {
854919Sxy150489 				packet = rx_ring->pending_list;
864919Sxy150489 				rx_ring->pending_list =
874919Sxy150489 				    rx_ring->pending_list->next;
884919Sxy150489 
894919Sxy150489 				ASSERT(packet->mp == NULL);
904919Sxy150489 				e1000g_free_rx_sw_packet(packet);
914919Sxy150489 			}
924919Sxy150489 		}
934982Syy150190 
944982Syy150190 		/*
954982Syy150190 		 * If e1000g_force_detach is enabled, we need to clean up
964982Syy150190 		 * the idle priv_dip entries in the private dip list while
974982Syy150190 		 * e1000g_mblks_pending is zero.
984982Syy150190 		 */
994982Syy150190 		if (e1000g_force_detach && (e1000g_mblks_pending == 0))
1004982Syy150190 			e1000g_priv_devi_list_clean();
1014919Sxy150489 		rw_exit(&e1000g_rx_detach_lock);
1024919Sxy150489 		return;
1034919Sxy150489 	}
1044919Sxy150489 
1054919Sxy150489 	if (packet->flag == E1000G_RX_SW_DETACH) {
1064919Sxy150489 		packet->flag = E1000G_RX_SW_FREE;
1073526Sxy150489 		rw_exit(&e1000g_rx_detach_lock);
1083526Sxy150489 
1093526Sxy150489 		ASSERT(packet->mp == NULL);
1103526Sxy150489 		e1000g_free_rx_sw_packet(packet);
1113526Sxy150489 
1123526Sxy150489 		/*
1133526Sxy150489 		 * Here the e1000g_mblks_pending may be modified by different
1143526Sxy150489 		 * rx recycling threads simultaneously, so we need to protect
1153526Sxy150489 		 * it with RW_WRITER.
1163526Sxy150489 		 */
1173526Sxy150489 		rw_enter(&e1000g_rx_detach_lock, RW_WRITER);
1183526Sxy150489 		e1000g_mblks_pending--;
1194982Syy150190 
1204982Syy150190 		/*
1214982Syy150190 		 * If e1000g_force_detach is enabled, we need to clean up
1224982Syy150190 		 * the idle priv_dip entries in the private dip list while
1234982Syy150190 		 * e1000g_mblks_pending is zero.
1244982Syy150190 		 */
1254982Syy150190 		if (e1000g_force_detach && (e1000g_mblks_pending == 0))
1264982Syy150190 			e1000g_priv_devi_list_clean();
1273526Sxy150489 		rw_exit(&e1000g_rx_detach_lock);
1283526Sxy150489 		return;
1293526Sxy150489 	}
1303526Sxy150489 
1314919Sxy150489 	packet->flag = E1000G_RX_SW_FREE;
1323526Sxy150489 
1333526Sxy150489 	if (packet->mp == NULL) {
1343526Sxy150489 		/*
1353526Sxy150489 		 * Allocate a mblk that binds to the data buffer
1363526Sxy150489 		 */
1373526Sxy150489 		packet->mp = desballoc((unsigned char *)
1383526Sxy150489 		    packet->rx_buf->address - E1000G_IPALIGNROOM,
1393526Sxy150489 		    packet->rx_buf->size + E1000G_IPALIGNROOM,
1403526Sxy150489 		    BPRI_MED, &packet->free_rtn);
1413526Sxy150489 
1423526Sxy150489 		if (packet->mp != NULL) {
1433526Sxy150489 			packet->mp->b_rptr += E1000G_IPALIGNROOM;
1443526Sxy150489 			packet->mp->b_wptr += E1000G_IPALIGNROOM;
1453526Sxy150489 		} else {
1464919Sxy150489 			E1000G_STAT(rx_ring->stat_esballoc_fail);
1473526Sxy150489 		}
1483526Sxy150489 	}
1493526Sxy150489 
1508275SEric Cheng 	/*
1518275SEric Cheng 	 * Enqueue the recycled packets in a recycle queue. When freelist
1528275SEric Cheng 	 * dries up, move the entire chain of packets from recycle queue
1538275SEric Cheng 	 * to freelist. This helps in avoiding per packet mutex contention
1548275SEric Cheng 	 * around freelist.
1558275SEric Cheng 	 */
1568275SEric Cheng 	mutex_enter(&rx_ring->recycle_lock);
1578275SEric Cheng 	QUEUE_PUSH_TAIL(&rx_ring->recycle_list, &packet->Link);
1588275SEric Cheng 	rx_ring->recycle_freepkt++;
1598275SEric Cheng 	mutex_exit(&rx_ring->recycle_lock);
1603526Sxy150489 
1613526Sxy150489 	rw_exit(&e1000g_rx_detach_lock);
1623526Sxy150489 }
1633526Sxy150489 
1643526Sxy150489 /*
1654982Syy150190  * e1000g_priv_devi_list_clean - clean up e1000g_private_devi_list
1664982Syy150190  *
1674982Syy150190  * We will walk the e1000g_private_devi_list to free the entry marked
1684982Syy150190  * with the E1000G_PRIV_DEVI_DETACH flag.
1694982Syy150190  */
1704982Syy150190 static void
1714982Syy150190 e1000g_priv_devi_list_clean()
1724982Syy150190 {
1734982Syy150190 	private_devi_list_t *devi_node, *devi_del;
1744982Syy150190 
1754982Syy150190 	if (e1000g_private_devi_list == NULL)
1764982Syy150190 		return;
1774982Syy150190 
1784982Syy150190 	devi_node = e1000g_private_devi_list;
1794982Syy150190 	while ((devi_node != NULL) &&
1804982Syy150190 	    (devi_node->flag == E1000G_PRIV_DEVI_DETACH)) {
1814982Syy150190 		e1000g_private_devi_list = devi_node->next;
1824982Syy150190 		kmem_free(devi_node->priv_dip,
1834982Syy150190 		    sizeof (struct dev_info));
1844982Syy150190 		kmem_free(devi_node,
1854982Syy150190 		    sizeof (private_devi_list_t));
1864982Syy150190 		devi_node = e1000g_private_devi_list;
1874982Syy150190 	}
1884982Syy150190 	if (e1000g_private_devi_list == NULL)
1894982Syy150190 		return;
1904982Syy150190 	while (devi_node->next != NULL) {
1914982Syy150190 		if (devi_node->next->flag == E1000G_PRIV_DEVI_DETACH) {
1924982Syy150190 			devi_del = devi_node->next;
1934982Syy150190 			devi_node->next = devi_del->next;
1944982Syy150190 			kmem_free(devi_del->priv_dip,
1954982Syy150190 			    sizeof (struct dev_info));
1964982Syy150190 			kmem_free(devi_del,
1974982Syy150190 			    sizeof (private_devi_list_t));
1984982Syy150190 		} else {
1994982Syy150190 			devi_node = devi_node->next;
2004982Syy150190 		}
2014982Syy150190 	}
2024982Syy150190 }
2034982Syy150190 
2044982Syy150190 /*
2054919Sxy150489  * e1000g_rx_setup - setup rx data structures
2064919Sxy150489  *
2074919Sxy150489  * This routine initializes all of the receive related
2084919Sxy150489  * structures. This includes the receive descriptors, the
2094919Sxy150489  * actual receive buffers, and the rx_sw_packet software
2104919Sxy150489  * structures.
2113526Sxy150489  */
2123526Sxy150489 void
2134919Sxy150489 e1000g_rx_setup(struct e1000g *Adapter)
2143526Sxy150489 {
2154919Sxy150489 	struct e1000_hw *hw;
2164919Sxy150489 	p_rx_sw_packet_t packet;
2173526Sxy150489 	struct e1000_rx_desc *descriptor;
2184919Sxy150489 	uint32_t buf_low;
2194919Sxy150489 	uint32_t buf_high;
2203526Sxy150489 	uint32_t reg_val;
2217607STed.You@Sun.COM 	uint32_t rctl;
2227607STed.You@Sun.COM 	uint32_t rxdctl;
2237607STed.You@Sun.COM 	uint32_t ert;
2243526Sxy150489 	int i;
2253526Sxy150489 	int size;
2263526Sxy150489 	e1000g_rx_ring_t *rx_ring;
2273526Sxy150489 
2284919Sxy150489 	hw = &Adapter->shared;
2293526Sxy150489 	rx_ring = Adapter->rx_ring;
2303526Sxy150489 
2313526Sxy150489 	/*
2323526Sxy150489 	 * zero out all of the receive buffer descriptor memory
2333526Sxy150489 	 * assures any previous data or status is erased
2343526Sxy150489 	 */
2353526Sxy150489 	bzero(rx_ring->rbd_area,
2364919Sxy150489 	    sizeof (struct e1000_rx_desc) * Adapter->rx_desc_num);
2373526Sxy150489 
2384919Sxy150489 	if (!Adapter->rx_buffer_setup) {
2393526Sxy150489 		/* Init the list of "Receive Buffer" */
2403526Sxy150489 		QUEUE_INIT_LIST(&rx_ring->recv_list);
2413526Sxy150489 
2423526Sxy150489 		/* Init the list of "Free Receive Buffer" */
2433526Sxy150489 		QUEUE_INIT_LIST(&rx_ring->free_list);
2443526Sxy150489 
2458275SEric Cheng 		/* Init the list of "Free Receive Buffer" */
2468275SEric Cheng 		QUEUE_INIT_LIST(&rx_ring->recycle_list);
2473526Sxy150489 		/*
2483526Sxy150489 		 * Setup Receive list and the Free list. Note that
2493526Sxy150489 		 * the both were allocated in one packet area.
2503526Sxy150489 		 */
2513526Sxy150489 		packet = rx_ring->packet_area;
2523526Sxy150489 		descriptor = rx_ring->rbd_first;
2533526Sxy150489 
2544919Sxy150489 		for (i = 0; i < Adapter->rx_desc_num;
2553526Sxy150489 		    i++, packet = packet->next, descriptor++) {
2563526Sxy150489 			ASSERT(packet != NULL);
2573526Sxy150489 			ASSERT(descriptor != NULL);
2583526Sxy150489 			descriptor->buffer_addr =
2593526Sxy150489 			    packet->rx_buf->dma_address;
2604919Sxy150489 
2614919Sxy150489 			/* Add this rx_sw_packet to the receive list */
2623526Sxy150489 			QUEUE_PUSH_TAIL(&rx_ring->recv_list,
2633526Sxy150489 			    &packet->Link);
2643526Sxy150489 		}
2653526Sxy150489 
2664919Sxy150489 		for (i = 0; i < Adapter->rx_freelist_num;
2673526Sxy150489 		    i++, packet = packet->next) {
2683526Sxy150489 			ASSERT(packet != NULL);
2694919Sxy150489 			/* Add this rx_sw_packet to the free list */
2703526Sxy150489 			QUEUE_PUSH_TAIL(&rx_ring->free_list,
2713526Sxy150489 			    &packet->Link);
2723526Sxy150489 		}
2734919Sxy150489 		rx_ring->avail_freepkt = Adapter->rx_freelist_num;
2748275SEric Cheng 		rx_ring->recycle_freepkt = 0;
2754919Sxy150489 
2764919Sxy150489 		Adapter->rx_buffer_setup = B_TRUE;
2773526Sxy150489 	} else {
2783526Sxy150489 		/* Setup the initial pointer to the first rx descriptor */
2794919Sxy150489 		packet = (p_rx_sw_packet_t)
2803526Sxy150489 		    QUEUE_GET_HEAD(&rx_ring->recv_list);
2813526Sxy150489 		descriptor = rx_ring->rbd_first;
2823526Sxy150489 
2834919Sxy150489 		for (i = 0; i < Adapter->rx_desc_num; i++) {
2843526Sxy150489 			ASSERT(packet != NULL);
2853526Sxy150489 			ASSERT(descriptor != NULL);
2863526Sxy150489 			descriptor->buffer_addr =
2873526Sxy150489 			    packet->rx_buf->dma_address;
2884919Sxy150489 
2894919Sxy150489 			/* Get next rx_sw_packet */
2904919Sxy150489 			packet = (p_rx_sw_packet_t)
2913526Sxy150489 			    QUEUE_GET_NEXT(&rx_ring->recv_list, &packet->Link);
2923526Sxy150489 			descriptor++;
2933526Sxy150489 		}
2943526Sxy150489 	}
2953526Sxy150489 
2965882Syy150190 	E1000_WRITE_REG(&Adapter->shared, E1000_RDTR, Adapter->rx_intr_delay);
2975882Syy150190 	E1000G_DEBUGLOG_1(Adapter, E1000G_INFO_LEVEL,
2985882Syy150190 	    "E1000_RDTR: 0x%x\n", Adapter->rx_intr_delay);
2995882Syy150190 	if (hw->mac.type >= e1000_82540) {
3005882Syy150190 		E1000_WRITE_REG(&Adapter->shared, E1000_RADV,
3015882Syy150190 		    Adapter->rx_intr_abs_delay);
3025882Syy150190 		E1000G_DEBUGLOG_1(Adapter, E1000G_INFO_LEVEL,
3035882Syy150190 		    "E1000_RADV: 0x%x\n", Adapter->rx_intr_abs_delay);
3045882Syy150190 	}
3055882Syy150190 
3063526Sxy150489 	/*
3073526Sxy150489 	 * Setup our descriptor pointers
3083526Sxy150489 	 */
3093526Sxy150489 	rx_ring->rbd_next = rx_ring->rbd_first;
3103526Sxy150489 
3114919Sxy150489 	size = Adapter->rx_desc_num * sizeof (struct e1000_rx_desc);
3126735Scc210113 	E1000_WRITE_REG(hw, E1000_RDLEN(0), size);
3136735Scc210113 	size = E1000_READ_REG(hw, E1000_RDLEN(0));
3143526Sxy150489 
3153526Sxy150489 	/* To get lower order bits */
3164919Sxy150489 	buf_low = (uint32_t)rx_ring->rbd_dma_addr;
3173526Sxy150489 	/* To get the higher order bits */
3184919Sxy150489 	buf_high = (uint32_t)(rx_ring->rbd_dma_addr >> 32);
3193526Sxy150489 
3206735Scc210113 	E1000_WRITE_REG(hw, E1000_RDBAH(0), buf_high);
3216735Scc210113 	E1000_WRITE_REG(hw, E1000_RDBAL(0), buf_low);
3223526Sxy150489 
3233526Sxy150489 	/*
3243526Sxy150489 	 * Setup our HW Rx Head & Tail descriptor pointers
3253526Sxy150489 	 */
3266735Scc210113 	E1000_WRITE_REG(hw, E1000_RDT(0),
3273526Sxy150489 	    (uint32_t)(rx_ring->rbd_last - rx_ring->rbd_first));
3286735Scc210113 	E1000_WRITE_REG(hw, E1000_RDH(0), 0);
3293526Sxy150489 
3303526Sxy150489 	/*
3313526Sxy150489 	 * Setup the Receive Control Register (RCTL), and ENABLE the
3323526Sxy150489 	 * receiver. The initial configuration is to: Enable the receiver,
3333526Sxy150489 	 * accept broadcasts, discard bad packets (and long packets),
3343526Sxy150489 	 * disable VLAN filter checking, set the receive descriptor
3353526Sxy150489 	 * minimum threshold size to 1/2, and the receive buffer size to
3363526Sxy150489 	 * 2k.
3373526Sxy150489 	 */
3387607STed.You@Sun.COM 	rctl = E1000_RCTL_EN |		/* Enable Receive Unit */
3393526Sxy150489 	    E1000_RCTL_BAM |		/* Accept Broadcast Packets */
3403526Sxy150489 	    E1000_RCTL_LPE |		/* Large Packet Enable bit */
3414919Sxy150489 	    (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT) |
3423526Sxy150489 	    E1000_RCTL_RDMTS_HALF |
3433526Sxy150489 	    E1000_RCTL_LBM_NO;		/* Loopback Mode = none */
3443526Sxy150489 
3454608Syy150190 	if (Adapter->strip_crc)
3467607STed.You@Sun.COM 		rctl |= E1000_RCTL_SECRC;	/* Strip Ethernet CRC */
3474608Syy150190 
3488417SChenlu.Chen@Sun.COM 	if (Adapter->mem_workaround_82546 &&
3498417SChenlu.Chen@Sun.COM 	    ((hw->mac.type == e1000_82545) ||
3508178SChenlu.Chen@Sun.COM 	    (hw->mac.type == e1000_82546) ||
3518417SChenlu.Chen@Sun.COM 	    (hw->mac.type == e1000_82546_rev_3))) {
3527607STed.You@Sun.COM 		rctl |= E1000_RCTL_SZ_2048;
3538178SChenlu.Chen@Sun.COM 	} else {
3548178SChenlu.Chen@Sun.COM 		if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_2K) &&
3558178SChenlu.Chen@Sun.COM 		    (Adapter->max_frame_size <= FRAME_SIZE_UPTO_4K))
3568178SChenlu.Chen@Sun.COM 			rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX;
3578178SChenlu.Chen@Sun.COM 		else if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_4K) &&
3588178SChenlu.Chen@Sun.COM 		    (Adapter->max_frame_size <= FRAME_SIZE_UPTO_8K))
3598178SChenlu.Chen@Sun.COM 			rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX;
3608178SChenlu.Chen@Sun.COM 		else if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_8K) &&
3618178SChenlu.Chen@Sun.COM 		    (Adapter->max_frame_size <= FRAME_SIZE_UPTO_16K))
3628178SChenlu.Chen@Sun.COM 			rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX;
3638178SChenlu.Chen@Sun.COM 		else
3648178SChenlu.Chen@Sun.COM 			rctl |= E1000_RCTL_SZ_2048;
3658178SChenlu.Chen@Sun.COM 	}
3663526Sxy150489 
3674919Sxy150489 	if (e1000_tbi_sbp_enabled_82543(hw))
3687607STed.You@Sun.COM 		rctl |= E1000_RCTL_SBP;
3693526Sxy150489 
3704919Sxy150489 	/*
3718479SChenlu.Chen@Sun.COM 	 * Enable Early Receive Threshold (ERT) on supported devices.
3728479SChenlu.Chen@Sun.COM 	 * Only takes effect when packet size is equal or larger than the
3738479SChenlu.Chen@Sun.COM 	 * specified value (in 8 byte units), e.g. using jumbo frames.
3744919Sxy150489 	 */
3757607STed.You@Sun.COM 	if ((hw->mac.type == e1000_82573) ||
3767607STed.You@Sun.COM 	    (hw->mac.type == e1000_82574) ||
3777607STed.You@Sun.COM 	    (hw->mac.type == e1000_ich9lan) ||
3787607STed.You@Sun.COM 	    (hw->mac.type == e1000_ich10lan)) {
3797607STed.You@Sun.COM 
3807607STed.You@Sun.COM 		ert = E1000_ERT_2048;
3814919Sxy150489 
3827607STed.You@Sun.COM 		/*
3837607STed.You@Sun.COM 		 * Special modification when ERT and
3847607STed.You@Sun.COM 		 * jumbo frames are enabled
3857607STed.You@Sun.COM 		 */
3867607STed.You@Sun.COM 		if (Adapter->default_mtu > ETHERMTU) {
3877607STed.You@Sun.COM 			rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(0));
3887607STed.You@Sun.COM 			E1000_WRITE_REG(hw, E1000_RXDCTL(0), rxdctl | 0x3);
3897607STed.You@Sun.COM 			ert |= (1 << 13);
3907607STed.You@Sun.COM 		}
3917607STed.You@Sun.COM 
3927607STed.You@Sun.COM 		E1000_WRITE_REG(hw, E1000_ERT, ert);
3937607STed.You@Sun.COM 	}
3943526Sxy150489 
3953526Sxy150489 	reg_val =
3963526Sxy150489 	    E1000_RXCSUM_TUOFL |	/* TCP/UDP checksum offload Enable */
3973526Sxy150489 	    E1000_RXCSUM_IPOFL;		/* IP checksum offload Enable */
3983526Sxy150489 
3994919Sxy150489 	E1000_WRITE_REG(hw, E1000_RXCSUM, reg_val);
4006871Szx151633 
4016871Szx151633 	/*
4026871Szx151633 	 * Workaround: Set bit 16 (IPv6_ExDIS) to disable the
4036871Szx151633 	 * processing of received IPV6 extension headers
4046871Szx151633 	 */
4056871Szx151633 	if ((hw->mac.type == e1000_82571) || (hw->mac.type == e1000_82572)) {
4066871Szx151633 		reg_val = E1000_READ_REG(hw, E1000_RFCTL);
4076871Szx151633 		reg_val |= (E1000_RFCTL_IPV6_EX_DIS |
4086871Szx151633 		    E1000_RFCTL_NEW_IPV6_EXT_DIS);
4096871Szx151633 		E1000_WRITE_REG(hw, E1000_RFCTL, reg_val);
4106871Szx151633 	}
4117607STed.You@Sun.COM 
4127607STed.You@Sun.COM 	/* Write to enable the receive unit */
4137607STed.You@Sun.COM 	E1000_WRITE_REG(hw, E1000_RCTL, rctl);
4143526Sxy150489 }
4153526Sxy150489 
4163526Sxy150489 /*
4174919Sxy150489  * e1000g_get_buf - get an rx sw packet from the free_list
4183526Sxy150489  */
4194919Sxy150489 static p_rx_sw_packet_t
4203526Sxy150489 e1000g_get_buf(e1000g_rx_ring_t *rx_ring)
4213526Sxy150489 {
4224919Sxy150489 	p_rx_sw_packet_t packet;
4233526Sxy150489 
4243526Sxy150489 	mutex_enter(&rx_ring->freelist_lock);
4254919Sxy150489 	packet = (p_rx_sw_packet_t)
4263526Sxy150489 	    QUEUE_POP_HEAD(&rx_ring->free_list);
4278275SEric Cheng 	if (packet != NULL) {
4284919Sxy150489 		rx_ring->avail_freepkt--;
4298275SEric Cheng 	} else {
4308275SEric Cheng 		/*
4318275SEric Cheng 		 * If the freelist has no packets, check the recycle list
4328275SEric Cheng 		 * to see if there are any available descriptor there.
4338275SEric Cheng 		 */
4348275SEric Cheng 		mutex_enter(&rx_ring->recycle_lock);
4358275SEric Cheng 		QUEUE_SWITCH(&rx_ring->free_list, &rx_ring->recycle_list);
4368275SEric Cheng 		rx_ring->avail_freepkt = rx_ring->recycle_freepkt;
4378275SEric Cheng 		rx_ring->recycle_freepkt = 0;
4388275SEric Cheng 		mutex_exit(&rx_ring->recycle_lock);
4398275SEric Cheng 		packet = (p_rx_sw_packet_t)
4408275SEric Cheng 		    QUEUE_POP_HEAD(&rx_ring->free_list);
4418275SEric Cheng 		if (packet != NULL)
4428275SEric Cheng 			rx_ring->avail_freepkt--;
4438275SEric Cheng 	}
4443526Sxy150489 	mutex_exit(&rx_ring->freelist_lock);
4453526Sxy150489 
4463526Sxy150489 	return (packet);
4473526Sxy150489 }
4483526Sxy150489 
4493526Sxy150489 /*
4504919Sxy150489  * e1000g_receive - main receive routine
4514919Sxy150489  *
4524919Sxy150489  * This routine will process packets received in an interrupt
4533526Sxy150489  */
4543526Sxy150489 mblk_t *
455*8833SVenu.Iyer@Sun.COM e1000g_receive(e1000g_rx_ring_t *rx_ring, mblk_t **tail, uint_t sz)
4563526Sxy150489 {
4574919Sxy150489 	struct e1000_hw *hw;
4583526Sxy150489 	mblk_t *nmp;
4593526Sxy150489 	mblk_t *ret_mp;
4603526Sxy150489 	mblk_t *ret_nmp;
4613526Sxy150489 	struct e1000_rx_desc *current_desc;
4623526Sxy150489 	struct e1000_rx_desc *last_desc;
4634919Sxy150489 	p_rx_sw_packet_t packet;
4644919Sxy150489 	p_rx_sw_packet_t newpkt;
4657607STed.You@Sun.COM 	uint16_t length;
4663526Sxy150489 	uint32_t pkt_count;
4673526Sxy150489 	uint32_t desc_count;
4684919Sxy150489 	boolean_t accept_frame;
4693526Sxy150489 	boolean_t end_of_packet;
4703526Sxy150489 	boolean_t need_copy;
4718275SEric Cheng 	struct e1000g *Adapter;
4723526Sxy150489 	dma_buffer_t *rx_buf;
4733526Sxy150489 	uint16_t cksumflags;
474*8833SVenu.Iyer@Sun.COM 	uint_t chain_sz = 0;
4753526Sxy150489 
4763526Sxy150489 	ret_mp = NULL;
4773526Sxy150489 	ret_nmp = NULL;
4783526Sxy150489 	pkt_count = 0;
4793526Sxy150489 	desc_count = 0;
4803526Sxy150489 	cksumflags = 0;
4813526Sxy150489 
4828275SEric Cheng 	Adapter = rx_ring->adapter;
4834919Sxy150489 	hw = &Adapter->shared;
4843526Sxy150489 
4853526Sxy150489 	/* Sync the Rx descriptor DMA buffers */
4863526Sxy150489 	(void) ddi_dma_sync(rx_ring->rbd_dma_handle,
4874919Sxy150489 	    0, 0, DDI_DMA_SYNC_FORKERNEL);
4883526Sxy150489 
4895273Sgl147354 	if (e1000g_check_dma_handle(rx_ring->rbd_dma_handle) != DDI_FM_OK) {
4905273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
4918479SChenlu.Chen@Sun.COM 		Adapter->e1000g_state |= E1000G_ERROR;
4925273Sgl147354 	}
4935273Sgl147354 
4943526Sxy150489 	current_desc = rx_ring->rbd_next;
4953526Sxy150489 	if (!(current_desc->status & E1000_RXD_STAT_DD)) {
4963526Sxy150489 		/*
4973526Sxy150489 		 * don't send anything up. just clear the RFD
4983526Sxy150489 		 */
4994919Sxy150489 		E1000G_DEBUG_STAT(rx_ring->stat_none);
5003526Sxy150489 		return (ret_mp);
5013526Sxy150489 	}
5023526Sxy150489 
5033526Sxy150489 	/*
5043526Sxy150489 	 * Loop through the receive descriptors starting at the last known
5053526Sxy150489 	 * descriptor owned by the hardware that begins a packet.
5063526Sxy150489 	 */
5073526Sxy150489 	while ((current_desc->status & E1000_RXD_STAT_DD) &&
508*8833SVenu.Iyer@Sun.COM 	    (pkt_count < Adapter->rx_limit_onintr) &&
509*8833SVenu.Iyer@Sun.COM 	    ((sz == E1000G_CHAIN_NO_LIMIT) || (chain_sz <= sz))) {
5103526Sxy150489 
5113526Sxy150489 		desc_count++;
5123526Sxy150489 		/*
5133526Sxy150489 		 * Now this can happen in Jumbo frame situation.
5143526Sxy150489 		 */
5153526Sxy150489 		if (current_desc->status & E1000_RXD_STAT_EOP) {
5163526Sxy150489 			/* packet has EOP set */
5173526Sxy150489 			end_of_packet = B_TRUE;
5183526Sxy150489 		} else {
5193526Sxy150489 			/*
5203526Sxy150489 			 * If this received buffer does not have the
5213526Sxy150489 			 * End-Of-Packet bit set, the received packet
5223526Sxy150489 			 * will consume multiple buffers. We won't send this
5233526Sxy150489 			 * packet upstack till we get all the related buffers.
5243526Sxy150489 			 */
5253526Sxy150489 			end_of_packet = B_FALSE;
5263526Sxy150489 		}
5273526Sxy150489 
5283526Sxy150489 		/*
5293526Sxy150489 		 * Get a pointer to the actual receive buffer
5303526Sxy150489 		 * The mp->b_rptr is mapped to The CurrentDescriptor
5313526Sxy150489 		 * Buffer Address.
5323526Sxy150489 		 */
5333526Sxy150489 		packet =
5344919Sxy150489 		    (p_rx_sw_packet_t)QUEUE_GET_HEAD(&rx_ring->recv_list);
5353526Sxy150489 		ASSERT(packet != NULL);
5363526Sxy150489 
5373526Sxy150489 		rx_buf = packet->rx_buf;
5383526Sxy150489 
5393526Sxy150489 		length = current_desc->length;
5403526Sxy150489 
5413526Sxy150489 #ifdef __sparc
5424919Sxy150489 		if (packet->dma_type == USE_DVMA)
5433526Sxy150489 			dvma_sync(rx_buf->dma_handle, 0,
5443526Sxy150489 			    DDI_DMA_SYNC_FORKERNEL);
5454919Sxy150489 		else
5463526Sxy150489 			(void) ddi_dma_sync(rx_buf->dma_handle,
5473526Sxy150489 			    E1000G_IPALIGNROOM, length,
5484919Sxy150489 			    DDI_DMA_SYNC_FORKERNEL);
5494919Sxy150489 #else
5504919Sxy150489 		(void) ddi_dma_sync(rx_buf->dma_handle,
5514919Sxy150489 		    E1000G_IPALIGNROOM, length,
5524919Sxy150489 		    DDI_DMA_SYNC_FORKERNEL);
5534919Sxy150489 #endif
5544919Sxy150489 
5555273Sgl147354 		if (e1000g_check_dma_handle(
5565273Sgl147354 		    rx_buf->dma_handle) != DDI_FM_OK) {
5575273Sgl147354 			ddi_fm_service_impact(Adapter->dip,
5585273Sgl147354 			    DDI_SERVICE_DEGRADED);
5598479SChenlu.Chen@Sun.COM 			Adapter->e1000g_state |= E1000G_ERROR;
5605273Sgl147354 		}
5615273Sgl147354 
5624919Sxy150489 		accept_frame = (current_desc->errors == 0) ||
5634919Sxy150489 		    ((current_desc->errors &
5644919Sxy150489 		    (E1000_RXD_ERR_TCPE | E1000_RXD_ERR_IPE)) != 0);
5654919Sxy150489 
5664919Sxy150489 		if (hw->mac.type == e1000_82543) {
5674919Sxy150489 			unsigned char last_byte;
5684919Sxy150489 
5694919Sxy150489 			last_byte =
5704919Sxy150489 			    *((unsigned char *)rx_buf->address + length - 1);
5714919Sxy150489 
5724919Sxy150489 			if (TBI_ACCEPT(hw,
5734919Sxy150489 			    current_desc->status, current_desc->errors,
5746735Scc210113 			    current_desc->length, last_byte,
5756735Scc210113 			    Adapter->min_frame_size, Adapter->max_frame_size)) {
5764919Sxy150489 
5774919Sxy150489 				e1000_tbi_adjust_stats(Adapter,
5784919Sxy150489 				    length, hw->mac.addr);
5794919Sxy150489 
5804919Sxy150489 				length--;
5814919Sxy150489 				accept_frame = B_TRUE;
5824919Sxy150489 			} else if (e1000_tbi_sbp_enabled_82543(hw) &&
5834919Sxy150489 			    (current_desc->errors == E1000_RXD_ERR_CE)) {
5844919Sxy150489 				accept_frame = B_TRUE;
5854919Sxy150489 			}
5863526Sxy150489 		}
5873526Sxy150489 
5883526Sxy150489 		/*
5893526Sxy150489 		 * Indicate the packet to the NOS if it was good.
5903526Sxy150489 		 * Normally, hardware will discard bad packets for us.
5913526Sxy150489 		 * Check for the packet to be a valid Ethernet packet
5923526Sxy150489 		 */
5934919Sxy150489 		if (!accept_frame) {
5943526Sxy150489 			/*
5953526Sxy150489 			 * error in incoming packet, either the packet is not a
5963526Sxy150489 			 * ethernet size packet, or the packet has an error. In
5973526Sxy150489 			 * either case, the packet will simply be discarded.
5983526Sxy150489 			 */
5994919Sxy150489 			E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
6003526Sxy150489 			    "Process Receive Interrupts: Error in Packet\n");
6013526Sxy150489 
6024919Sxy150489 			E1000G_STAT(rx_ring->stat_error);
6033526Sxy150489 			/*
6043526Sxy150489 			 * Returning here as we are done here. There is
6053526Sxy150489 			 * no point in waiting for while loop to elapse
6063526Sxy150489 			 * and the things which were done. More efficient
6073526Sxy150489 			 * and less error prone...
6083526Sxy150489 			 */
6093526Sxy150489 			goto rx_drop;
6103526Sxy150489 		}
6113526Sxy150489 
6124608Syy150190 		/*
6134608Syy150190 		 * If the Ethernet CRC is not stripped by the hardware,
6144608Syy150190 		 * we need to strip it before sending it up to the stack.
6154608Syy150190 		 */
6164608Syy150190 		if (end_of_packet && !Adapter->strip_crc) {
6176394Scc210113 			if (length > ETHERFCSL) {
6186394Scc210113 				length -= ETHERFCSL;
6194608Syy150190 			} else {
6204608Syy150190 				/*
6214608Syy150190 				 * If the fragment is smaller than the CRC,
6224608Syy150190 				 * drop this fragment, do the processing of
6234608Syy150190 				 * the end of the packet.
6244608Syy150190 				 */
6254919Sxy150489 				ASSERT(rx_ring->rx_mblk_tail != NULL);
6264919Sxy150489 				rx_ring->rx_mblk_tail->b_wptr -=
6276394Scc210113 				    ETHERFCSL - length;
6284919Sxy150489 				rx_ring->rx_mblk_len -=
6296394Scc210113 				    ETHERFCSL - length;
6304608Syy150190 
6314608Syy150190 				QUEUE_POP_HEAD(&rx_ring->recv_list);
6324608Syy150190 
6334608Syy150190 				goto rx_end_of_packet;
6344608Syy150190 			}
6354608Syy150190 		}
6364608Syy150190 
6373526Sxy150489 		need_copy = B_TRUE;
6383526Sxy150489 
6393526Sxy150489 		if (length <= Adapter->rx_bcopy_thresh)
6403526Sxy150489 			goto rx_copy;
6413526Sxy150489 
6423526Sxy150489 		/*
6433526Sxy150489 		 * Get the pre-constructed mblk that was associated
6443526Sxy150489 		 * to the receive data buffer.
6453526Sxy150489 		 */
6463526Sxy150489 		if (packet->mp == NULL) {
6473526Sxy150489 			packet->mp = desballoc((unsigned char *)
6483526Sxy150489 			    rx_buf->address - E1000G_IPALIGNROOM,
6493526Sxy150489 			    length + E1000G_IPALIGNROOM,
6503526Sxy150489 			    BPRI_MED, &packet->free_rtn);
6513526Sxy150489 
6523526Sxy150489 			if (packet->mp != NULL) {
6533526Sxy150489 				packet->mp->b_rptr += E1000G_IPALIGNROOM;
6543526Sxy150489 				packet->mp->b_wptr += E1000G_IPALIGNROOM;
6553526Sxy150489 			} else {
6564919Sxy150489 				E1000G_STAT(rx_ring->stat_esballoc_fail);
6573526Sxy150489 			}
6583526Sxy150489 		}
6593526Sxy150489 
6603526Sxy150489 		if (packet->mp != NULL) {
6613526Sxy150489 			/*
6623526Sxy150489 			 * We have two sets of buffer pool. One associated with
6633526Sxy150489 			 * the Rxdescriptors and other a freelist buffer pool.
6643526Sxy150489 			 * Each time we get a good packet, Try to get a buffer
6653526Sxy150489 			 * from the freelist pool using e1000g_get_buf. If we
6663526Sxy150489 			 * get free buffer, then replace the descriptor buffer
6673526Sxy150489 			 * address with the free buffer we just got, and pass
6683526Sxy150489 			 * the pre-constructed mblk upstack. (note no copying)
6693526Sxy150489 			 *
6703526Sxy150489 			 * If we failed to get a free buffer, then try to
6713526Sxy150489 			 * allocate a new buffer(mp) and copy the recv buffer
6723526Sxy150489 			 * content to our newly allocated buffer(mp). Don't
6733526Sxy150489 			 * disturb the desriptor buffer address. (note copying)
6743526Sxy150489 			 */
6753526Sxy150489 			newpkt = e1000g_get_buf(rx_ring);
6763526Sxy150489 
6773526Sxy150489 			if (newpkt != NULL) {
6783526Sxy150489 				/*
6793526Sxy150489 				 * Get the mblk associated to the data,
6803526Sxy150489 				 * and strip it off the sw packet.
6813526Sxy150489 				 */
6823526Sxy150489 				nmp = packet->mp;
6833526Sxy150489 				packet->mp = NULL;
6844982Syy150190 				packet->flag = E1000G_RX_SW_SENDUP;
6853526Sxy150489 
6863526Sxy150489 				/*
6873526Sxy150489 				 * Now replace old buffer with the new
6883526Sxy150489 				 * one we got from free list
6893526Sxy150489 				 * Both the RxSwPacket as well as the
6903526Sxy150489 				 * Receive Buffer Descriptor will now
6913526Sxy150489 				 * point to this new packet.
6923526Sxy150489 				 */
6933526Sxy150489 				packet = newpkt;
6944919Sxy150489 
6953526Sxy150489 				current_desc->buffer_addr =
6963526Sxy150489 				    newpkt->rx_buf->dma_address;
6974919Sxy150489 
6983526Sxy150489 				need_copy = B_FALSE;
6993526Sxy150489 			} else {
7004919Sxy150489 				E1000G_DEBUG_STAT(rx_ring->stat_no_freepkt);
7013526Sxy150489 			}
7023526Sxy150489 		}
7033526Sxy150489 
7043526Sxy150489 rx_copy:
7053526Sxy150489 		if (need_copy) {
7063526Sxy150489 			/*
7073526Sxy150489 			 * No buffers available on free list,
7083526Sxy150489 			 * bcopy the data from the buffer and
7093526Sxy150489 			 * keep the original buffer. Dont want to
7103526Sxy150489 			 * do this.. Yack but no other way
7113526Sxy150489 			 */
7124919Sxy150489 			if ((nmp = allocb(length + E1000G_IPALIGNROOM,
7134608Syy150190 			    BPRI_MED)) == NULL) {
7143526Sxy150489 				/*
7153526Sxy150489 				 * The system has no buffers available
7163526Sxy150489 				 * to send up the incoming packet, hence
7173526Sxy150489 				 * the packet will have to be processed
7183526Sxy150489 				 * when there're more buffers available.
7193526Sxy150489 				 */
7204919Sxy150489 				E1000G_STAT(rx_ring->stat_allocb_fail);
7213526Sxy150489 				goto rx_drop;
7223526Sxy150489 			}
7233526Sxy150489 			nmp->b_rptr += E1000G_IPALIGNROOM;
7243526Sxy150489 			nmp->b_wptr += E1000G_IPALIGNROOM;
7253526Sxy150489 			/*
7263526Sxy150489 			 * The free list did not have any buffers
7273526Sxy150489 			 * available, so, the received packet will
7283526Sxy150489 			 * have to be copied into a mp and the original
7293526Sxy150489 			 * buffer will have to be retained for future
7303526Sxy150489 			 * packet reception.
7313526Sxy150489 			 */
7324919Sxy150489 			bcopy(rx_buf->address, nmp->b_wptr, length);
7333526Sxy150489 		}
7343526Sxy150489 
7353526Sxy150489 		/*
7364919Sxy150489 		 * The rx_sw_packet MUST be popped off the
7373526Sxy150489 		 * RxSwPacketList before either a putnext or freemsg
7383526Sxy150489 		 * is done on the mp that has now been created by the
7393526Sxy150489 		 * desballoc. If not, it is possible that the free
7403526Sxy150489 		 * routine will get called from the interrupt context
7413526Sxy150489 		 * and try to put this packet on the free list
7423526Sxy150489 		 */
7434919Sxy150489 		(p_rx_sw_packet_t)QUEUE_POP_HEAD(&rx_ring->recv_list);
7443526Sxy150489 
7453526Sxy150489 		ASSERT(nmp != NULL);
7463526Sxy150489 		nmp->b_wptr += length;
7473526Sxy150489 
7484919Sxy150489 		if (rx_ring->rx_mblk == NULL) {
7493526Sxy150489 			/*
7503526Sxy150489 			 *  TCP/UDP checksum offload and
7513526Sxy150489 			 *  IP checksum offload
7523526Sxy150489 			 */
7534919Sxy150489 			if (!(current_desc->status & E1000_RXD_STAT_IXSM)) {
7543526Sxy150489 				/*
7553526Sxy150489 				 * Check TCP/UDP checksum
7563526Sxy150489 				 */
7573526Sxy150489 				if ((current_desc->status &
7584608Syy150190 				    E1000_RXD_STAT_TCPCS) &&
7593526Sxy150489 				    !(current_desc->errors &
7604608Syy150190 				    E1000_RXD_ERR_TCPE))
7613526Sxy150489 					cksumflags |= HCK_FULLCKSUM |
7624608Syy150190 					    HCK_FULLCKSUM_OK;
7633526Sxy150489 				/*
7643526Sxy150489 				 * Check IP Checksum
7653526Sxy150489 				 */
7663526Sxy150489 				if ((current_desc->status &
7674608Syy150190 				    E1000_RXD_STAT_IPCS) &&
7683526Sxy150489 				    !(current_desc->errors &
7694608Syy150190 				    E1000_RXD_ERR_IPE))
7703526Sxy150489 					cksumflags |= HCK_IPV4_HDRCKSUM;
7713526Sxy150489 			}
7723526Sxy150489 		}
7733526Sxy150489 
7743526Sxy150489 		/*
7753526Sxy150489 		 * We need to maintain our packet chain in the global
7763526Sxy150489 		 * Adapter structure, for the Rx processing can end
7773526Sxy150489 		 * with a fragment that has no EOP set.
7783526Sxy150489 		 */
7794919Sxy150489 		if (rx_ring->rx_mblk == NULL) {
7803526Sxy150489 			/* Get the head of the message chain */
7814919Sxy150489 			rx_ring->rx_mblk = nmp;
7824919Sxy150489 			rx_ring->rx_mblk_tail = nmp;
7834919Sxy150489 			rx_ring->rx_mblk_len = length;
7843526Sxy150489 		} else {	/* Not the first packet */
7853526Sxy150489 			/* Continue adding buffers */
7864919Sxy150489 			rx_ring->rx_mblk_tail->b_cont = nmp;
7874919Sxy150489 			rx_ring->rx_mblk_tail = nmp;
7884919Sxy150489 			rx_ring->rx_mblk_len += length;
7893526Sxy150489 		}
7904919Sxy150489 		ASSERT(rx_ring->rx_mblk != NULL);
7914919Sxy150489 		ASSERT(rx_ring->rx_mblk_tail != NULL);
7924919Sxy150489 		ASSERT(rx_ring->rx_mblk_tail->b_cont == NULL);
7933526Sxy150489 
7943526Sxy150489 		/*
7953526Sxy150489 		 * Now this MP is ready to travel upwards but some more
7963526Sxy150489 		 * fragments are coming.
7973526Sxy150489 		 * We will send packet upwards as soon as we get EOP
7983526Sxy150489 		 * set on the packet.
7993526Sxy150489 		 */
8003526Sxy150489 		if (!end_of_packet) {
8013526Sxy150489 			/*
8023526Sxy150489 			 * continue to get the next descriptor,
8033526Sxy150489 			 * Tail would be advanced at the end
8043526Sxy150489 			 */
8053526Sxy150489 			goto rx_next_desc;
8063526Sxy150489 		}
8073526Sxy150489 
8084608Syy150190 rx_end_of_packet:
8093526Sxy150489 		/*
8103526Sxy150489 		 * Found packet with EOP
8113526Sxy150489 		 * Process the last fragment.
8123526Sxy150489 		 */
8133526Sxy150489 		if (cksumflags != 0) {
8144919Sxy150489 			(void) hcksum_assoc(rx_ring->rx_mblk,
8153526Sxy150489 			    NULL, NULL, 0, 0, 0, 0, cksumflags, 0);
8163526Sxy150489 			cksumflags = 0;
8173526Sxy150489 		}
8183526Sxy150489 
8193526Sxy150489 		/*
8203526Sxy150489 		 * Count packets that span multi-descriptors
8213526Sxy150489 		 */
8224919Sxy150489 		E1000G_DEBUG_STAT_COND(rx_ring->stat_multi_desc,
8234919Sxy150489 		    (rx_ring->rx_mblk->b_cont != NULL));
8243526Sxy150489 
8253526Sxy150489 		/*
8263526Sxy150489 		 * Append to list to send upstream
8273526Sxy150489 		 */
8283526Sxy150489 		if (ret_mp == NULL) {
8294919Sxy150489 			ret_mp = ret_nmp = rx_ring->rx_mblk;
8303526Sxy150489 		} else {
8314919Sxy150489 			ret_nmp->b_next = rx_ring->rx_mblk;
8324919Sxy150489 			ret_nmp = rx_ring->rx_mblk;
8333526Sxy150489 		}
8343526Sxy150489 		ret_nmp->b_next = NULL;
8358275SEric Cheng 		*tail = ret_nmp;
836*8833SVenu.Iyer@Sun.COM 		chain_sz += length;
8373526Sxy150489 
8384919Sxy150489 		rx_ring->rx_mblk = NULL;
8394919Sxy150489 		rx_ring->rx_mblk_tail = NULL;
8404919Sxy150489 		rx_ring->rx_mblk_len = 0;
8413526Sxy150489 
8423526Sxy150489 		pkt_count++;
8433526Sxy150489 
8443526Sxy150489 rx_next_desc:
8453526Sxy150489 		/*
8463526Sxy150489 		 * Zero out the receive descriptors status
8473526Sxy150489 		 */
8483526Sxy150489 		current_desc->status = 0;
8493526Sxy150489 
8503526Sxy150489 		if (current_desc == rx_ring->rbd_last)
8513526Sxy150489 			rx_ring->rbd_next = rx_ring->rbd_first;
8523526Sxy150489 		else
8533526Sxy150489 			rx_ring->rbd_next++;
8543526Sxy150489 
8553526Sxy150489 		last_desc = current_desc;
8563526Sxy150489 		current_desc = rx_ring->rbd_next;
8573526Sxy150489 
8583526Sxy150489 		/*
8593526Sxy150489 		 * Put the buffer that we just indicated back
8603526Sxy150489 		 * at the end of our list
8613526Sxy150489 		 */
8623526Sxy150489 		QUEUE_PUSH_TAIL(&rx_ring->recv_list,
8633526Sxy150489 		    &packet->Link);
8643526Sxy150489 	}	/* while loop */
8653526Sxy150489 
8663526Sxy150489 	/* Sync the Rx descriptor DMA buffers */
8674919Sxy150489 	(void) ddi_dma_sync(rx_ring->rbd_dma_handle,
8684919Sxy150489 	    0, 0, DDI_DMA_SYNC_FORDEV);
8693526Sxy150489 
8703526Sxy150489 	/*
8713526Sxy150489 	 * Advance the E1000's Receive Queue #0 "Tail Pointer".
8723526Sxy150489 	 */
8736735Scc210113 	E1000_WRITE_REG(hw, E1000_RDT(0),
8743526Sxy150489 	    (uint32_t)(last_desc - rx_ring->rbd_first));
8753526Sxy150489 
8765273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
8775273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
8788479SChenlu.Chen@Sun.COM 		Adapter->e1000g_state |= E1000G_ERROR;
8795273Sgl147354 	}
8805273Sgl147354 
8815882Syy150190 	Adapter->rx_pkt_cnt = pkt_count;
8825882Syy150190 
8833526Sxy150489 	return (ret_mp);
8843526Sxy150489 
8853526Sxy150489 rx_drop:
8863526Sxy150489 	/*
8873526Sxy150489 	 * Zero out the receive descriptors status
8883526Sxy150489 	 */
8893526Sxy150489 	current_desc->status = 0;
8903526Sxy150489 
8913526Sxy150489 	/* Sync the Rx descriptor DMA buffers */
8924919Sxy150489 	(void) ddi_dma_sync(rx_ring->rbd_dma_handle,
8934919Sxy150489 	    0, 0, DDI_DMA_SYNC_FORDEV);
8943526Sxy150489 
8953526Sxy150489 	if (current_desc == rx_ring->rbd_last)
8963526Sxy150489 		rx_ring->rbd_next = rx_ring->rbd_first;
8973526Sxy150489 	else
8983526Sxy150489 		rx_ring->rbd_next++;
8993526Sxy150489 
9003526Sxy150489 	last_desc = current_desc;
9013526Sxy150489 
9024919Sxy150489 	(p_rx_sw_packet_t)QUEUE_POP_HEAD(&rx_ring->recv_list);
9033526Sxy150489 
9043526Sxy150489 	QUEUE_PUSH_TAIL(&rx_ring->recv_list, &packet->Link);
9053526Sxy150489 	/*
9063526Sxy150489 	 * Reclaim all old buffers already allocated during
9073526Sxy150489 	 * Jumbo receives.....for incomplete reception
9083526Sxy150489 	 */
9094919Sxy150489 	if (rx_ring->rx_mblk != NULL) {
9104919Sxy150489 		freemsg(rx_ring->rx_mblk);
9114919Sxy150489 		rx_ring->rx_mblk = NULL;
9124919Sxy150489 		rx_ring->rx_mblk_tail = NULL;
9134919Sxy150489 		rx_ring->rx_mblk_len = 0;
9143526Sxy150489 	}
9153526Sxy150489 	/*
9163526Sxy150489 	 * Advance the E1000's Receive Queue #0 "Tail Pointer".
9173526Sxy150489 	 */
9186735Scc210113 	E1000_WRITE_REG(hw, E1000_RDT(0),
9193526Sxy150489 	    (uint32_t)(last_desc - rx_ring->rbd_first));
9203526Sxy150489 
9215273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
9225273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
9238479SChenlu.Chen@Sun.COM 		Adapter->e1000g_state |= E1000G_ERROR;
9245273Sgl147354 	}
9255273Sgl147354 
9263526Sxy150489 	return (ret_mp);
9273526Sxy150489 }
928