xref: /onnv-gate/usr/src/uts/common/io/e1000g/e1000g_rx.c (revision 6735:ba4d622bb38a)
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  *
95882Syy150190  * Copyright(c) 1999 - 2008 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 /*
225882Syy150190  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
233526Sxy150489  * Use is subject to license terms of the CDDLv1.
243526Sxy150489  */
253526Sxy150489 
263526Sxy150489 #pragma ident	"%Z%%M%	%I%	%E% SMI"
273526Sxy150489 
283526Sxy150489 /*
293526Sxy150489  * **********************************************************************
303526Sxy150489  *									*
313526Sxy150489  * Module Name:								*
323526Sxy150489  *   e1000g_rx.c							*
333526Sxy150489  *									*
343526Sxy150489  * Abstract:								*
354919Sxy150489  *   This file contains some routines that take care of Receive		*
364919Sxy150489  *   interrupt and also for the received packets it sends up to		*
374919Sxy150489  *   upper layer.							*
383526Sxy150489  *   It tries to do a zero copy if free buffers are available in	*
394919Sxy150489  *   the pool.								*
403526Sxy150489  *									*
413526Sxy150489  * **********************************************************************
423526Sxy150489  */
433526Sxy150489 
443526Sxy150489 #include "e1000g_sw.h"
453526Sxy150489 #include "e1000g_debug.h"
463526Sxy150489 
474919Sxy150489 static p_rx_sw_packet_t e1000g_get_buf(e1000g_rx_ring_t *rx_ring);
483526Sxy150489 #pragma	inline(e1000g_get_buf)
494982Syy150190 static void e1000g_priv_devi_list_clean();
503526Sxy150489 
513526Sxy150489 /*
524919Sxy150489  * e1000g_rxfree_func - the call-back function to reclaim rx buffer
534919Sxy150489  *
544919Sxy150489  * This function is called when an mp is freed by the user thru
554919Sxy150489  * freeb call (Only for mp constructed through desballoc call)
564919Sxy150489  * It returns back the freed buffer to the freelist
573526Sxy150489  */
583526Sxy150489 void
594919Sxy150489 e1000g_rxfree_func(p_rx_sw_packet_t packet)
603526Sxy150489 {
613526Sxy150489 	struct e1000g *Adapter;
623526Sxy150489 	e1000g_rx_ring_t *rx_ring;
633526Sxy150489 
644919Sxy150489 	rx_ring = (e1000g_rx_ring_t *)packet->rx_ring;
654919Sxy150489 	Adapter = rx_ring->adapter;
664919Sxy150489 
673526Sxy150489 	/*
683526Sxy150489 	 * Here the rx recycling processes different rx packets in different
693526Sxy150489 	 * threads, so we protect it with RW_READER to ensure it won't block
703526Sxy150489 	 * other rx recycling threads.
713526Sxy150489 	 */
723526Sxy150489 	rw_enter(&e1000g_rx_detach_lock, RW_READER);
733526Sxy150489 
744919Sxy150489 	if (packet->flag == E1000G_RX_SW_FREE) {
753526Sxy150489 		rw_exit(&e1000g_rx_detach_lock);
763526Sxy150489 		return;
773526Sxy150489 	}
783526Sxy150489 
794919Sxy150489 	if (packet->flag == E1000G_RX_SW_STOP) {
804919Sxy150489 		packet->flag = E1000G_RX_SW_FREE;
814919Sxy150489 		rw_exit(&e1000g_rx_detach_lock);
824919Sxy150489 
834919Sxy150489 		rw_enter(&e1000g_rx_detach_lock, RW_WRITER);
844919Sxy150489 		rx_ring->pending_count--;
854919Sxy150489 		e1000g_mblks_pending--;
864919Sxy150489 
874919Sxy150489 		if (rx_ring->pending_count == 0) {
884919Sxy150489 			while (rx_ring->pending_list != NULL) {
894919Sxy150489 				packet = rx_ring->pending_list;
904919Sxy150489 				rx_ring->pending_list =
914919Sxy150489 				    rx_ring->pending_list->next;
924919Sxy150489 
934919Sxy150489 				ASSERT(packet->mp == NULL);
944919Sxy150489 				e1000g_free_rx_sw_packet(packet);
954919Sxy150489 			}
964919Sxy150489 		}
974982Syy150190 
984982Syy150190 		/*
994982Syy150190 		 * If e1000g_force_detach is enabled, we need to clean up
1004982Syy150190 		 * the idle priv_dip entries in the private dip list while
1014982Syy150190 		 * e1000g_mblks_pending is zero.
1024982Syy150190 		 */
1034982Syy150190 		if (e1000g_force_detach && (e1000g_mblks_pending == 0))
1044982Syy150190 			e1000g_priv_devi_list_clean();
1054919Sxy150489 		rw_exit(&e1000g_rx_detach_lock);
1064919Sxy150489 		return;
1074919Sxy150489 	}
1084919Sxy150489 
1094919Sxy150489 	if (packet->flag == E1000G_RX_SW_DETACH) {
1104919Sxy150489 		packet->flag = E1000G_RX_SW_FREE;
1113526Sxy150489 		rw_exit(&e1000g_rx_detach_lock);
1123526Sxy150489 
1133526Sxy150489 		ASSERT(packet->mp == NULL);
1143526Sxy150489 		e1000g_free_rx_sw_packet(packet);
1153526Sxy150489 
1163526Sxy150489 		/*
1173526Sxy150489 		 * Here the e1000g_mblks_pending may be modified by different
1183526Sxy150489 		 * rx recycling threads simultaneously, so we need to protect
1193526Sxy150489 		 * it with RW_WRITER.
1203526Sxy150489 		 */
1213526Sxy150489 		rw_enter(&e1000g_rx_detach_lock, RW_WRITER);
1223526Sxy150489 		e1000g_mblks_pending--;
1234982Syy150190 
1244982Syy150190 		/*
1254982Syy150190 		 * If e1000g_force_detach is enabled, we need to clean up
1264982Syy150190 		 * the idle priv_dip entries in the private dip list while
1274982Syy150190 		 * e1000g_mblks_pending is zero.
1284982Syy150190 		 */
1294982Syy150190 		if (e1000g_force_detach && (e1000g_mblks_pending == 0))
1304982Syy150190 			e1000g_priv_devi_list_clean();
1313526Sxy150489 		rw_exit(&e1000g_rx_detach_lock);
1323526Sxy150489 		return;
1333526Sxy150489 	}
1343526Sxy150489 
1354919Sxy150489 	packet->flag = E1000G_RX_SW_FREE;
1363526Sxy150489 
1373526Sxy150489 	if (packet->mp == NULL) {
1383526Sxy150489 		/*
1393526Sxy150489 		 * Allocate a mblk that binds to the data buffer
1403526Sxy150489 		 */
1413526Sxy150489 		packet->mp = desballoc((unsigned char *)
1423526Sxy150489 		    packet->rx_buf->address - E1000G_IPALIGNROOM,
1433526Sxy150489 		    packet->rx_buf->size + E1000G_IPALIGNROOM,
1443526Sxy150489 		    BPRI_MED, &packet->free_rtn);
1453526Sxy150489 
1463526Sxy150489 		if (packet->mp != NULL) {
1473526Sxy150489 			packet->mp->b_rptr += E1000G_IPALIGNROOM;
1483526Sxy150489 			packet->mp->b_wptr += E1000G_IPALIGNROOM;
1493526Sxy150489 		} else {
1504919Sxy150489 			E1000G_STAT(rx_ring->stat_esballoc_fail);
1513526Sxy150489 		}
1523526Sxy150489 	}
1533526Sxy150489 
1543526Sxy150489 	mutex_enter(&rx_ring->freelist_lock);
1553526Sxy150489 	QUEUE_PUSH_TAIL(&rx_ring->free_list, &packet->Link);
1564919Sxy150489 	rx_ring->avail_freepkt++;
1573526Sxy150489 	mutex_exit(&rx_ring->freelist_lock);
1583526Sxy150489 
1593526Sxy150489 	rw_exit(&e1000g_rx_detach_lock);
1603526Sxy150489 }
1613526Sxy150489 
1623526Sxy150489 /*
1634982Syy150190  * e1000g_priv_devi_list_clean - clean up e1000g_private_devi_list
1644982Syy150190  *
1654982Syy150190  * We will walk the e1000g_private_devi_list to free the entry marked
1664982Syy150190  * with the E1000G_PRIV_DEVI_DETACH flag.
1674982Syy150190  */
1684982Syy150190 static void
1694982Syy150190 e1000g_priv_devi_list_clean()
1704982Syy150190 {
1714982Syy150190 	private_devi_list_t *devi_node, *devi_del;
1724982Syy150190 
1734982Syy150190 	if (e1000g_private_devi_list == NULL)
1744982Syy150190 		return;
1754982Syy150190 
1764982Syy150190 	devi_node = e1000g_private_devi_list;
1774982Syy150190 	while ((devi_node != NULL) &&
1784982Syy150190 	    (devi_node->flag == E1000G_PRIV_DEVI_DETACH)) {
1794982Syy150190 		e1000g_private_devi_list = devi_node->next;
1804982Syy150190 		kmem_free(devi_node->priv_dip,
1814982Syy150190 		    sizeof (struct dev_info));
1824982Syy150190 		kmem_free(devi_node,
1834982Syy150190 		    sizeof (private_devi_list_t));
1844982Syy150190 		devi_node = e1000g_private_devi_list;
1854982Syy150190 	}
1864982Syy150190 	if (e1000g_private_devi_list == NULL)
1874982Syy150190 		return;
1884982Syy150190 	while (devi_node->next != NULL) {
1894982Syy150190 		if (devi_node->next->flag == E1000G_PRIV_DEVI_DETACH) {
1904982Syy150190 			devi_del = devi_node->next;
1914982Syy150190 			devi_node->next = devi_del->next;
1924982Syy150190 			kmem_free(devi_del->priv_dip,
1934982Syy150190 			    sizeof (struct dev_info));
1944982Syy150190 			kmem_free(devi_del,
1954982Syy150190 			    sizeof (private_devi_list_t));
1964982Syy150190 		} else {
1974982Syy150190 			devi_node = devi_node->next;
1984982Syy150190 		}
1994982Syy150190 	}
2004982Syy150190 }
2014982Syy150190 
2024982Syy150190 /*
2034919Sxy150489  * e1000g_rx_setup - setup rx data structures
2044919Sxy150489  *
2054919Sxy150489  * This routine initializes all of the receive related
2064919Sxy150489  * structures. This includes the receive descriptors, the
2074919Sxy150489  * actual receive buffers, and the rx_sw_packet software
2084919Sxy150489  * structures.
2093526Sxy150489  */
2103526Sxy150489 void
2114919Sxy150489 e1000g_rx_setup(struct e1000g *Adapter)
2123526Sxy150489 {
2134919Sxy150489 	struct e1000_hw *hw;
2144919Sxy150489 	p_rx_sw_packet_t packet;
2153526Sxy150489 	struct e1000_rx_desc *descriptor;
2164919Sxy150489 	uint32_t buf_low;
2174919Sxy150489 	uint32_t buf_high;
2183526Sxy150489 	uint32_t reg_val;
2193526Sxy150489 	int i;
2203526Sxy150489 	int size;
2213526Sxy150489 	e1000g_rx_ring_t *rx_ring;
2223526Sxy150489 
2234919Sxy150489 	hw = &Adapter->shared;
2243526Sxy150489 	rx_ring = Adapter->rx_ring;
2253526Sxy150489 
2263526Sxy150489 	/*
2273526Sxy150489 	 * zero out all of the receive buffer descriptor memory
2283526Sxy150489 	 * assures any previous data or status is erased
2293526Sxy150489 	 */
2303526Sxy150489 	bzero(rx_ring->rbd_area,
2314919Sxy150489 	    sizeof (struct e1000_rx_desc) * Adapter->rx_desc_num);
2323526Sxy150489 
2334919Sxy150489 	if (!Adapter->rx_buffer_setup) {
2343526Sxy150489 		/* Init the list of "Receive Buffer" */
2353526Sxy150489 		QUEUE_INIT_LIST(&rx_ring->recv_list);
2363526Sxy150489 
2373526Sxy150489 		/* Init the list of "Free Receive Buffer" */
2383526Sxy150489 		QUEUE_INIT_LIST(&rx_ring->free_list);
2393526Sxy150489 
2403526Sxy150489 		/*
2413526Sxy150489 		 * Setup Receive list and the Free list. Note that
2423526Sxy150489 		 * the both were allocated in one packet area.
2433526Sxy150489 		 */
2443526Sxy150489 		packet = rx_ring->packet_area;
2453526Sxy150489 		descriptor = rx_ring->rbd_first;
2463526Sxy150489 
2474919Sxy150489 		for (i = 0; i < Adapter->rx_desc_num;
2483526Sxy150489 		    i++, packet = packet->next, descriptor++) {
2493526Sxy150489 			ASSERT(packet != NULL);
2503526Sxy150489 			ASSERT(descriptor != NULL);
2513526Sxy150489 			descriptor->buffer_addr =
2523526Sxy150489 			    packet->rx_buf->dma_address;
2534919Sxy150489 
2544919Sxy150489 			/* Add this rx_sw_packet to the receive list */
2553526Sxy150489 			QUEUE_PUSH_TAIL(&rx_ring->recv_list,
2563526Sxy150489 			    &packet->Link);
2573526Sxy150489 		}
2583526Sxy150489 
2594919Sxy150489 		for (i = 0; i < Adapter->rx_freelist_num;
2603526Sxy150489 		    i++, packet = packet->next) {
2613526Sxy150489 			ASSERT(packet != NULL);
2624919Sxy150489 			/* Add this rx_sw_packet to the free list */
2633526Sxy150489 			QUEUE_PUSH_TAIL(&rx_ring->free_list,
2643526Sxy150489 			    &packet->Link);
2653526Sxy150489 		}
2664919Sxy150489 		rx_ring->avail_freepkt = Adapter->rx_freelist_num;
2674919Sxy150489 
2684919Sxy150489 		Adapter->rx_buffer_setup = B_TRUE;
2693526Sxy150489 	} else {
2703526Sxy150489 		/* Setup the initial pointer to the first rx descriptor */
2714919Sxy150489 		packet = (p_rx_sw_packet_t)
2723526Sxy150489 		    QUEUE_GET_HEAD(&rx_ring->recv_list);
2733526Sxy150489 		descriptor = rx_ring->rbd_first;
2743526Sxy150489 
2754919Sxy150489 		for (i = 0; i < Adapter->rx_desc_num; i++) {
2763526Sxy150489 			ASSERT(packet != NULL);
2773526Sxy150489 			ASSERT(descriptor != NULL);
2783526Sxy150489 			descriptor->buffer_addr =
2793526Sxy150489 			    packet->rx_buf->dma_address;
2804919Sxy150489 
2814919Sxy150489 			/* Get next rx_sw_packet */
2824919Sxy150489 			packet = (p_rx_sw_packet_t)
2833526Sxy150489 			    QUEUE_GET_NEXT(&rx_ring->recv_list, &packet->Link);
2843526Sxy150489 			descriptor++;
2853526Sxy150489 		}
2863526Sxy150489 	}
2873526Sxy150489 
2885882Syy150190 	E1000_WRITE_REG(&Adapter->shared, E1000_RDTR, Adapter->rx_intr_delay);
2895882Syy150190 	E1000G_DEBUGLOG_1(Adapter, E1000G_INFO_LEVEL,
2905882Syy150190 	    "E1000_RDTR: 0x%x\n", Adapter->rx_intr_delay);
2915882Syy150190 	if (hw->mac.type >= e1000_82540) {
2925882Syy150190 		E1000_WRITE_REG(&Adapter->shared, E1000_RADV,
2935882Syy150190 		    Adapter->rx_intr_abs_delay);
2945882Syy150190 		E1000G_DEBUGLOG_1(Adapter, E1000G_INFO_LEVEL,
2955882Syy150190 		    "E1000_RADV: 0x%x\n", Adapter->rx_intr_abs_delay);
2965882Syy150190 	}
2975882Syy150190 
2983526Sxy150489 	/*
2993526Sxy150489 	 * Setup our descriptor pointers
3003526Sxy150489 	 */
3013526Sxy150489 	rx_ring->rbd_next = rx_ring->rbd_first;
3023526Sxy150489 
3034919Sxy150489 	size = Adapter->rx_desc_num * sizeof (struct e1000_rx_desc);
304*6735Scc210113 	E1000_WRITE_REG(hw, E1000_RDLEN(0), size);
305*6735Scc210113 	size = E1000_READ_REG(hw, E1000_RDLEN(0));
3063526Sxy150489 
3073526Sxy150489 	/* To get lower order bits */
3084919Sxy150489 	buf_low = (uint32_t)rx_ring->rbd_dma_addr;
3093526Sxy150489 	/* To get the higher order bits */
3104919Sxy150489 	buf_high = (uint32_t)(rx_ring->rbd_dma_addr >> 32);
3113526Sxy150489 
312*6735Scc210113 	E1000_WRITE_REG(hw, E1000_RDBAH(0), buf_high);
313*6735Scc210113 	E1000_WRITE_REG(hw, E1000_RDBAL(0), buf_low);
3143526Sxy150489 
3153526Sxy150489 	/*
3163526Sxy150489 	 * Setup our HW Rx Head & Tail descriptor pointers
3173526Sxy150489 	 */
318*6735Scc210113 	E1000_WRITE_REG(hw, E1000_RDT(0),
3193526Sxy150489 	    (uint32_t)(rx_ring->rbd_last - rx_ring->rbd_first));
320*6735Scc210113 	E1000_WRITE_REG(hw, E1000_RDH(0), 0);
3213526Sxy150489 
3223526Sxy150489 	/*
3233526Sxy150489 	 * Setup the Receive Control Register (RCTL), and ENABLE the
3243526Sxy150489 	 * receiver. The initial configuration is to: Enable the receiver,
3253526Sxy150489 	 * accept broadcasts, discard bad packets (and long packets),
3263526Sxy150489 	 * disable VLAN filter checking, set the receive descriptor
3273526Sxy150489 	 * minimum threshold size to 1/2, and the receive buffer size to
3283526Sxy150489 	 * 2k.
3293526Sxy150489 	 */
3303526Sxy150489 	reg_val = E1000_RCTL_EN |	/* Enable Receive Unit */
3313526Sxy150489 	    E1000_RCTL_BAM |		/* Accept Broadcast Packets */
3323526Sxy150489 	    E1000_RCTL_LPE |		/* Large Packet Enable bit */
3334919Sxy150489 	    (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT) |
3343526Sxy150489 	    E1000_RCTL_RDMTS_HALF |
3353526Sxy150489 	    E1000_RCTL_LBM_NO;		/* Loopback Mode = none */
3363526Sxy150489 
3374608Syy150190 	if (Adapter->strip_crc)
3384919Sxy150489 		reg_val |= E1000_RCTL_SECRC;	/* Strip Ethernet CRC */
3394608Syy150190 
340*6735Scc210113 	if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_2K) &&
341*6735Scc210113 	    (Adapter->max_frame_size <= FRAME_SIZE_UPTO_4K))
3423526Sxy150489 		reg_val |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX;
343*6735Scc210113 	else if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_4K) &&
344*6735Scc210113 	    (Adapter->max_frame_size <= FRAME_SIZE_UPTO_8K))
3453526Sxy150489 		reg_val |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX;
346*6735Scc210113 	else if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_8K) &&
347*6735Scc210113 	    (Adapter->max_frame_size <= FRAME_SIZE_UPTO_16K))
3483526Sxy150489 		reg_val |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX;
3496394Scc210113 	else
3503526Sxy150489 		reg_val |= E1000_RCTL_SZ_2048;
3513526Sxy150489 
3524919Sxy150489 	if (e1000_tbi_sbp_enabled_82543(hw))
3533526Sxy150489 		reg_val |= E1000_RCTL_SBP;
3543526Sxy150489 
3554919Sxy150489 	/*
3564919Sxy150489 	 * Enable early receives on supported devices, only takes effect when
3574919Sxy150489 	 * packet size is equal or larger than the specified value (in 8 byte
3584919Sxy150489 	 * units), e.g. using jumbo frames when setting to E1000_ERT_2048
3594919Sxy150489 	 */
3604919Sxy150489 	if ((hw->mac.type == e1000_82573) || (hw->mac.type == e1000_ich9lan))
3614919Sxy150489 		E1000_WRITE_REG(hw, E1000_ERT, E1000_ERT_2048);
3624919Sxy150489 
3634919Sxy150489 	E1000_WRITE_REG(hw, E1000_RCTL, reg_val);
3643526Sxy150489 
3653526Sxy150489 	reg_val =
3663526Sxy150489 	    E1000_RXCSUM_TUOFL |	/* TCP/UDP checksum offload Enable */
3673526Sxy150489 	    E1000_RXCSUM_IPOFL;		/* IP checksum offload Enable */
3683526Sxy150489 
3694919Sxy150489 	E1000_WRITE_REG(hw, E1000_RXCSUM, reg_val);
3703526Sxy150489 }
3713526Sxy150489 
3723526Sxy150489 /*
3734919Sxy150489  * e1000g_get_buf - get an rx sw packet from the free_list
3743526Sxy150489  */
3754919Sxy150489 static p_rx_sw_packet_t
3763526Sxy150489 e1000g_get_buf(e1000g_rx_ring_t *rx_ring)
3773526Sxy150489 {
3783526Sxy150489 	struct e1000g *Adapter;
3794919Sxy150489 	p_rx_sw_packet_t packet;
3803526Sxy150489 
3813526Sxy150489 	Adapter = rx_ring->adapter;
3823526Sxy150489 
3833526Sxy150489 	mutex_enter(&rx_ring->freelist_lock);
3844919Sxy150489 	packet = (p_rx_sw_packet_t)
3853526Sxy150489 	    QUEUE_POP_HEAD(&rx_ring->free_list);
3863526Sxy150489 	if (packet != NULL)
3874919Sxy150489 		rx_ring->avail_freepkt--;
3883526Sxy150489 	mutex_exit(&rx_ring->freelist_lock);
3893526Sxy150489 
3903526Sxy150489 	return (packet);
3913526Sxy150489 }
3923526Sxy150489 
3933526Sxy150489 /*
3944919Sxy150489  * e1000g_receive - main receive routine
3954919Sxy150489  *
3964919Sxy150489  * This routine will process packets received in an interrupt
3973526Sxy150489  */
3983526Sxy150489 mblk_t *
3993526Sxy150489 e1000g_receive(struct e1000g *Adapter)
4003526Sxy150489 {
4014919Sxy150489 	struct e1000_hw *hw;
4023526Sxy150489 	mblk_t *nmp;
4033526Sxy150489 	mblk_t *ret_mp;
4043526Sxy150489 	mblk_t *ret_nmp;
4053526Sxy150489 	struct e1000_rx_desc *current_desc;
4063526Sxy150489 	struct e1000_rx_desc *last_desc;
4074919Sxy150489 	p_rx_sw_packet_t packet;
4084919Sxy150489 	p_rx_sw_packet_t newpkt;
4093526Sxy150489 	USHORT length;
4103526Sxy150489 	uint32_t pkt_count;
4113526Sxy150489 	uint32_t desc_count;
4124919Sxy150489 	boolean_t accept_frame;
4133526Sxy150489 	boolean_t end_of_packet;
4143526Sxy150489 	boolean_t need_copy;
4153526Sxy150489 	e1000g_rx_ring_t *rx_ring;
4163526Sxy150489 	dma_buffer_t *rx_buf;
4173526Sxy150489 	uint16_t cksumflags;
4183526Sxy150489 
4193526Sxy150489 	ret_mp = NULL;
4203526Sxy150489 	ret_nmp = NULL;
4213526Sxy150489 	pkt_count = 0;
4223526Sxy150489 	desc_count = 0;
4233526Sxy150489 	cksumflags = 0;
4243526Sxy150489 
4254919Sxy150489 	hw = &Adapter->shared;
4263526Sxy150489 	rx_ring = Adapter->rx_ring;
4273526Sxy150489 
4283526Sxy150489 	/* Sync the Rx descriptor DMA buffers */
4293526Sxy150489 	(void) ddi_dma_sync(rx_ring->rbd_dma_handle,
4304919Sxy150489 	    0, 0, DDI_DMA_SYNC_FORKERNEL);
4313526Sxy150489 
4325273Sgl147354 	if (e1000g_check_dma_handle(rx_ring->rbd_dma_handle) != DDI_FM_OK) {
4335273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
4345273Sgl147354 		Adapter->chip_state = E1000G_ERROR;
4355273Sgl147354 	}
4365273Sgl147354 
4373526Sxy150489 	current_desc = rx_ring->rbd_next;
4383526Sxy150489 	if (!(current_desc->status & E1000_RXD_STAT_DD)) {
4393526Sxy150489 		/*
4403526Sxy150489 		 * don't send anything up. just clear the RFD
4413526Sxy150489 		 */
4424919Sxy150489 		E1000G_DEBUG_STAT(rx_ring->stat_none);
4433526Sxy150489 		return (ret_mp);
4443526Sxy150489 	}
4453526Sxy150489 
4463526Sxy150489 	/*
4473526Sxy150489 	 * Loop through the receive descriptors starting at the last known
4483526Sxy150489 	 * descriptor owned by the hardware that begins a packet.
4493526Sxy150489 	 */
4503526Sxy150489 	while ((current_desc->status & E1000_RXD_STAT_DD) &&
4514919Sxy150489 	    (pkt_count < Adapter->rx_limit_onintr)) {
4523526Sxy150489 
4533526Sxy150489 		desc_count++;
4543526Sxy150489 		/*
4553526Sxy150489 		 * Now this can happen in Jumbo frame situation.
4563526Sxy150489 		 */
4573526Sxy150489 		if (current_desc->status & E1000_RXD_STAT_EOP) {
4583526Sxy150489 			/* packet has EOP set */
4593526Sxy150489 			end_of_packet = B_TRUE;
4603526Sxy150489 		} else {
4613526Sxy150489 			/*
4623526Sxy150489 			 * If this received buffer does not have the
4633526Sxy150489 			 * End-Of-Packet bit set, the received packet
4643526Sxy150489 			 * will consume multiple buffers. We won't send this
4653526Sxy150489 			 * packet upstack till we get all the related buffers.
4663526Sxy150489 			 */
4673526Sxy150489 			end_of_packet = B_FALSE;
4683526Sxy150489 		}
4693526Sxy150489 
4703526Sxy150489 		/*
4713526Sxy150489 		 * Get a pointer to the actual receive buffer
4723526Sxy150489 		 * The mp->b_rptr is mapped to The CurrentDescriptor
4733526Sxy150489 		 * Buffer Address.
4743526Sxy150489 		 */
4753526Sxy150489 		packet =
4764919Sxy150489 		    (p_rx_sw_packet_t)QUEUE_GET_HEAD(&rx_ring->recv_list);
4773526Sxy150489 		ASSERT(packet != NULL);
4783526Sxy150489 
4793526Sxy150489 		rx_buf = packet->rx_buf;
4803526Sxy150489 
4813526Sxy150489 		length = current_desc->length;
4823526Sxy150489 
4833526Sxy150489 #ifdef __sparc
4844919Sxy150489 		if (packet->dma_type == USE_DVMA)
4853526Sxy150489 			dvma_sync(rx_buf->dma_handle, 0,
4863526Sxy150489 			    DDI_DMA_SYNC_FORKERNEL);
4874919Sxy150489 		else
4883526Sxy150489 			(void) ddi_dma_sync(rx_buf->dma_handle,
4893526Sxy150489 			    E1000G_IPALIGNROOM, length,
4904919Sxy150489 			    DDI_DMA_SYNC_FORKERNEL);
4914919Sxy150489 #else
4924919Sxy150489 		(void) ddi_dma_sync(rx_buf->dma_handle,
4934919Sxy150489 		    E1000G_IPALIGNROOM, length,
4944919Sxy150489 		    DDI_DMA_SYNC_FORKERNEL);
4954919Sxy150489 #endif
4964919Sxy150489 
4975273Sgl147354 		if (e1000g_check_dma_handle(
4985273Sgl147354 		    rx_buf->dma_handle) != DDI_FM_OK) {
4995273Sgl147354 			ddi_fm_service_impact(Adapter->dip,
5005273Sgl147354 			    DDI_SERVICE_DEGRADED);
5015273Sgl147354 			Adapter->chip_state = E1000G_ERROR;
5025273Sgl147354 		}
5035273Sgl147354 
5044919Sxy150489 		accept_frame = (current_desc->errors == 0) ||
5054919Sxy150489 		    ((current_desc->errors &
5064919Sxy150489 		    (E1000_RXD_ERR_TCPE | E1000_RXD_ERR_IPE)) != 0);
5074919Sxy150489 
5084919Sxy150489 		if (hw->mac.type == e1000_82543) {
5094919Sxy150489 			unsigned char last_byte;
5104919Sxy150489 
5114919Sxy150489 			last_byte =
5124919Sxy150489 			    *((unsigned char *)rx_buf->address + length - 1);
5134919Sxy150489 
5144919Sxy150489 			if (TBI_ACCEPT(hw,
5154919Sxy150489 			    current_desc->status, current_desc->errors,
516*6735Scc210113 			    current_desc->length, last_byte,
517*6735Scc210113 			    Adapter->min_frame_size, Adapter->max_frame_size)) {
5184919Sxy150489 
5194919Sxy150489 				e1000_tbi_adjust_stats(Adapter,
5204919Sxy150489 				    length, hw->mac.addr);
5214919Sxy150489 
5224919Sxy150489 				length--;
5234919Sxy150489 				accept_frame = B_TRUE;
5244919Sxy150489 			} else if (e1000_tbi_sbp_enabled_82543(hw) &&
5254919Sxy150489 			    (current_desc->errors == E1000_RXD_ERR_CE)) {
5264919Sxy150489 				accept_frame = B_TRUE;
5274919Sxy150489 			}
5283526Sxy150489 		}
5293526Sxy150489 
5303526Sxy150489 		/*
5313526Sxy150489 		 * Indicate the packet to the NOS if it was good.
5323526Sxy150489 		 * Normally, hardware will discard bad packets for us.
5333526Sxy150489 		 * Check for the packet to be a valid Ethernet packet
5343526Sxy150489 		 */
5354919Sxy150489 		if (!accept_frame) {
5363526Sxy150489 			/*
5373526Sxy150489 			 * error in incoming packet, either the packet is not a
5383526Sxy150489 			 * ethernet size packet, or the packet has an error. In
5393526Sxy150489 			 * either case, the packet will simply be discarded.
5403526Sxy150489 			 */
5414919Sxy150489 			E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
5423526Sxy150489 			    "Process Receive Interrupts: Error in Packet\n");
5433526Sxy150489 
5444919Sxy150489 			E1000G_STAT(rx_ring->stat_error);
5453526Sxy150489 			/*
5463526Sxy150489 			 * Returning here as we are done here. There is
5473526Sxy150489 			 * no point in waiting for while loop to elapse
5483526Sxy150489 			 * and the things which were done. More efficient
5493526Sxy150489 			 * and less error prone...
5503526Sxy150489 			 */
5513526Sxy150489 			goto rx_drop;
5523526Sxy150489 		}
5533526Sxy150489 
5544608Syy150190 		/*
5554608Syy150190 		 * If the Ethernet CRC is not stripped by the hardware,
5564608Syy150190 		 * we need to strip it before sending it up to the stack.
5574608Syy150190 		 */
5584608Syy150190 		if (end_of_packet && !Adapter->strip_crc) {
5596394Scc210113 			if (length > ETHERFCSL) {
5606394Scc210113 				length -= ETHERFCSL;
5614608Syy150190 			} else {
5624608Syy150190 				/*
5634608Syy150190 				 * If the fragment is smaller than the CRC,
5644608Syy150190 				 * drop this fragment, do the processing of
5654608Syy150190 				 * the end of the packet.
5664608Syy150190 				 */
5674919Sxy150489 				ASSERT(rx_ring->rx_mblk_tail != NULL);
5684919Sxy150489 				rx_ring->rx_mblk_tail->b_wptr -=
5696394Scc210113 				    ETHERFCSL - length;
5704919Sxy150489 				rx_ring->rx_mblk_len -=
5716394Scc210113 				    ETHERFCSL - length;
5724608Syy150190 
5734608Syy150190 				QUEUE_POP_HEAD(&rx_ring->recv_list);
5744608Syy150190 
5754608Syy150190 				goto rx_end_of_packet;
5764608Syy150190 			}
5774608Syy150190 		}
5784608Syy150190 
5793526Sxy150489 		need_copy = B_TRUE;
5803526Sxy150489 
5813526Sxy150489 		if (length <= Adapter->rx_bcopy_thresh)
5823526Sxy150489 			goto rx_copy;
5833526Sxy150489 
5843526Sxy150489 		/*
5853526Sxy150489 		 * Get the pre-constructed mblk that was associated
5863526Sxy150489 		 * to the receive data buffer.
5873526Sxy150489 		 */
5883526Sxy150489 		if (packet->mp == NULL) {
5893526Sxy150489 			packet->mp = desballoc((unsigned char *)
5903526Sxy150489 			    rx_buf->address - E1000G_IPALIGNROOM,
5913526Sxy150489 			    length + E1000G_IPALIGNROOM,
5923526Sxy150489 			    BPRI_MED, &packet->free_rtn);
5933526Sxy150489 
5943526Sxy150489 			if (packet->mp != NULL) {
5953526Sxy150489 				packet->mp->b_rptr += E1000G_IPALIGNROOM;
5963526Sxy150489 				packet->mp->b_wptr += E1000G_IPALIGNROOM;
5973526Sxy150489 			} else {
5984919Sxy150489 				E1000G_STAT(rx_ring->stat_esballoc_fail);
5993526Sxy150489 			}
6003526Sxy150489 		}
6013526Sxy150489 
6023526Sxy150489 		if (packet->mp != NULL) {
6033526Sxy150489 			/*
6043526Sxy150489 			 * We have two sets of buffer pool. One associated with
6053526Sxy150489 			 * the Rxdescriptors and other a freelist buffer pool.
6063526Sxy150489 			 * Each time we get a good packet, Try to get a buffer
6073526Sxy150489 			 * from the freelist pool using e1000g_get_buf. If we
6083526Sxy150489 			 * get free buffer, then replace the descriptor buffer
6093526Sxy150489 			 * address with the free buffer we just got, and pass
6103526Sxy150489 			 * the pre-constructed mblk upstack. (note no copying)
6113526Sxy150489 			 *
6123526Sxy150489 			 * If we failed to get a free buffer, then try to
6133526Sxy150489 			 * allocate a new buffer(mp) and copy the recv buffer
6143526Sxy150489 			 * content to our newly allocated buffer(mp). Don't
6153526Sxy150489 			 * disturb the desriptor buffer address. (note copying)
6163526Sxy150489 			 */
6173526Sxy150489 			newpkt = e1000g_get_buf(rx_ring);
6183526Sxy150489 
6193526Sxy150489 			if (newpkt != NULL) {
6203526Sxy150489 				/*
6213526Sxy150489 				 * Get the mblk associated to the data,
6223526Sxy150489 				 * and strip it off the sw packet.
6233526Sxy150489 				 */
6243526Sxy150489 				nmp = packet->mp;
6253526Sxy150489 				packet->mp = NULL;
6264982Syy150190 				packet->flag = E1000G_RX_SW_SENDUP;
6273526Sxy150489 
6283526Sxy150489 				/*
6293526Sxy150489 				 * Now replace old buffer with the new
6303526Sxy150489 				 * one we got from free list
6313526Sxy150489 				 * Both the RxSwPacket as well as the
6323526Sxy150489 				 * Receive Buffer Descriptor will now
6333526Sxy150489 				 * point to this new packet.
6343526Sxy150489 				 */
6353526Sxy150489 				packet = newpkt;
6364919Sxy150489 
6373526Sxy150489 				current_desc->buffer_addr =
6383526Sxy150489 				    newpkt->rx_buf->dma_address;
6394919Sxy150489 
6403526Sxy150489 				need_copy = B_FALSE;
6413526Sxy150489 			} else {
6424919Sxy150489 				E1000G_DEBUG_STAT(rx_ring->stat_no_freepkt);
6433526Sxy150489 			}
6443526Sxy150489 		}
6453526Sxy150489 
6463526Sxy150489 rx_copy:
6473526Sxy150489 		if (need_copy) {
6483526Sxy150489 			/*
6493526Sxy150489 			 * No buffers available on free list,
6503526Sxy150489 			 * bcopy the data from the buffer and
6513526Sxy150489 			 * keep the original buffer. Dont want to
6523526Sxy150489 			 * do this.. Yack but no other way
6533526Sxy150489 			 */
6544919Sxy150489 			if ((nmp = allocb(length + E1000G_IPALIGNROOM,
6554608Syy150190 			    BPRI_MED)) == NULL) {
6563526Sxy150489 				/*
6573526Sxy150489 				 * The system has no buffers available
6583526Sxy150489 				 * to send up the incoming packet, hence
6593526Sxy150489 				 * the packet will have to be processed
6603526Sxy150489 				 * when there're more buffers available.
6613526Sxy150489 				 */
6624919Sxy150489 				E1000G_STAT(rx_ring->stat_allocb_fail);
6633526Sxy150489 				goto rx_drop;
6643526Sxy150489 			}
6653526Sxy150489 			nmp->b_rptr += E1000G_IPALIGNROOM;
6663526Sxy150489 			nmp->b_wptr += E1000G_IPALIGNROOM;
6673526Sxy150489 			/*
6683526Sxy150489 			 * The free list did not have any buffers
6693526Sxy150489 			 * available, so, the received packet will
6703526Sxy150489 			 * have to be copied into a mp and the original
6713526Sxy150489 			 * buffer will have to be retained for future
6723526Sxy150489 			 * packet reception.
6733526Sxy150489 			 */
6744919Sxy150489 			bcopy(rx_buf->address, nmp->b_wptr, length);
6753526Sxy150489 		}
6763526Sxy150489 
6773526Sxy150489 		/*
6784919Sxy150489 		 * The rx_sw_packet MUST be popped off the
6793526Sxy150489 		 * RxSwPacketList before either a putnext or freemsg
6803526Sxy150489 		 * is done on the mp that has now been created by the
6813526Sxy150489 		 * desballoc. If not, it is possible that the free
6823526Sxy150489 		 * routine will get called from the interrupt context
6833526Sxy150489 		 * and try to put this packet on the free list
6843526Sxy150489 		 */
6854919Sxy150489 		(p_rx_sw_packet_t)QUEUE_POP_HEAD(&rx_ring->recv_list);
6863526Sxy150489 
6873526Sxy150489 		ASSERT(nmp != NULL);
6883526Sxy150489 		nmp->b_wptr += length;
6893526Sxy150489 
6904919Sxy150489 		if (rx_ring->rx_mblk == NULL) {
6913526Sxy150489 			/*
6923526Sxy150489 			 *  TCP/UDP checksum offload and
6933526Sxy150489 			 *  IP checksum offload
6943526Sxy150489 			 */
6954919Sxy150489 			if (!(current_desc->status & E1000_RXD_STAT_IXSM)) {
6963526Sxy150489 				/*
6973526Sxy150489 				 * Check TCP/UDP checksum
6983526Sxy150489 				 */
6993526Sxy150489 				if ((current_desc->status &
7004608Syy150190 				    E1000_RXD_STAT_TCPCS) &&
7013526Sxy150489 				    !(current_desc->errors &
7024608Syy150190 				    E1000_RXD_ERR_TCPE))
7033526Sxy150489 					cksumflags |= HCK_FULLCKSUM |
7044608Syy150190 					    HCK_FULLCKSUM_OK;
7053526Sxy150489 				/*
7063526Sxy150489 				 * Check IP Checksum
7073526Sxy150489 				 */
7083526Sxy150489 				if ((current_desc->status &
7094608Syy150190 				    E1000_RXD_STAT_IPCS) &&
7103526Sxy150489 				    !(current_desc->errors &
7114608Syy150190 				    E1000_RXD_ERR_IPE))
7123526Sxy150489 					cksumflags |= HCK_IPV4_HDRCKSUM;
7133526Sxy150489 			}
7143526Sxy150489 		}
7153526Sxy150489 
7163526Sxy150489 		/*
7173526Sxy150489 		 * We need to maintain our packet chain in the global
7183526Sxy150489 		 * Adapter structure, for the Rx processing can end
7193526Sxy150489 		 * with a fragment that has no EOP set.
7203526Sxy150489 		 */
7214919Sxy150489 		if (rx_ring->rx_mblk == NULL) {
7223526Sxy150489 			/* Get the head of the message chain */
7234919Sxy150489 			rx_ring->rx_mblk = nmp;
7244919Sxy150489 			rx_ring->rx_mblk_tail = nmp;
7254919Sxy150489 			rx_ring->rx_mblk_len = length;
7263526Sxy150489 		} else {	/* Not the first packet */
7273526Sxy150489 			/* Continue adding buffers */
7284919Sxy150489 			rx_ring->rx_mblk_tail->b_cont = nmp;
7294919Sxy150489 			rx_ring->rx_mblk_tail = nmp;
7304919Sxy150489 			rx_ring->rx_mblk_len += length;
7313526Sxy150489 		}
7324919Sxy150489 		ASSERT(rx_ring->rx_mblk != NULL);
7334919Sxy150489 		ASSERT(rx_ring->rx_mblk_tail != NULL);
7344919Sxy150489 		ASSERT(rx_ring->rx_mblk_tail->b_cont == NULL);
7353526Sxy150489 
7363526Sxy150489 		/*
7373526Sxy150489 		 * Now this MP is ready to travel upwards but some more
7383526Sxy150489 		 * fragments are coming.
7393526Sxy150489 		 * We will send packet upwards as soon as we get EOP
7403526Sxy150489 		 * set on the packet.
7413526Sxy150489 		 */
7423526Sxy150489 		if (!end_of_packet) {
7433526Sxy150489 			/*
7443526Sxy150489 			 * continue to get the next descriptor,
7453526Sxy150489 			 * Tail would be advanced at the end
7463526Sxy150489 			 */
7473526Sxy150489 			goto rx_next_desc;
7483526Sxy150489 		}
7493526Sxy150489 
7504608Syy150190 rx_end_of_packet:
7513526Sxy150489 		/*
7523526Sxy150489 		 * Found packet with EOP
7533526Sxy150489 		 * Process the last fragment.
7543526Sxy150489 		 */
7553526Sxy150489 		if (cksumflags != 0) {
7564919Sxy150489 			(void) hcksum_assoc(rx_ring->rx_mblk,
7573526Sxy150489 			    NULL, NULL, 0, 0, 0, 0, cksumflags, 0);
7583526Sxy150489 			cksumflags = 0;
7593526Sxy150489 		}
7603526Sxy150489 
7613526Sxy150489 		/*
7623526Sxy150489 		 * Count packets that span multi-descriptors
7633526Sxy150489 		 */
7644919Sxy150489 		E1000G_DEBUG_STAT_COND(rx_ring->stat_multi_desc,
7654919Sxy150489 		    (rx_ring->rx_mblk->b_cont != NULL));
7663526Sxy150489 
7673526Sxy150489 		/*
7683526Sxy150489 		 * Append to list to send upstream
7693526Sxy150489 		 */
7703526Sxy150489 		if (ret_mp == NULL) {
7714919Sxy150489 			ret_mp = ret_nmp = rx_ring->rx_mblk;
7723526Sxy150489 		} else {
7734919Sxy150489 			ret_nmp->b_next = rx_ring->rx_mblk;
7744919Sxy150489 			ret_nmp = rx_ring->rx_mblk;
7753526Sxy150489 		}
7763526Sxy150489 		ret_nmp->b_next = NULL;
7773526Sxy150489 
7784919Sxy150489 		rx_ring->rx_mblk = NULL;
7794919Sxy150489 		rx_ring->rx_mblk_tail = NULL;
7804919Sxy150489 		rx_ring->rx_mblk_len = 0;
7813526Sxy150489 
7823526Sxy150489 		pkt_count++;
7833526Sxy150489 
7843526Sxy150489 rx_next_desc:
7853526Sxy150489 		/*
7863526Sxy150489 		 * Zero out the receive descriptors status
7873526Sxy150489 		 */
7883526Sxy150489 		current_desc->status = 0;
7893526Sxy150489 
7903526Sxy150489 		if (current_desc == rx_ring->rbd_last)
7913526Sxy150489 			rx_ring->rbd_next = rx_ring->rbd_first;
7923526Sxy150489 		else
7933526Sxy150489 			rx_ring->rbd_next++;
7943526Sxy150489 
7953526Sxy150489 		last_desc = current_desc;
7963526Sxy150489 		current_desc = rx_ring->rbd_next;
7973526Sxy150489 
7983526Sxy150489 		/*
7993526Sxy150489 		 * Put the buffer that we just indicated back
8003526Sxy150489 		 * at the end of our list
8013526Sxy150489 		 */
8023526Sxy150489 		QUEUE_PUSH_TAIL(&rx_ring->recv_list,
8033526Sxy150489 		    &packet->Link);
8043526Sxy150489 	}	/* while loop */
8053526Sxy150489 
8063526Sxy150489 	/* Sync the Rx descriptor DMA buffers */
8074919Sxy150489 	(void) ddi_dma_sync(rx_ring->rbd_dma_handle,
8084919Sxy150489 	    0, 0, DDI_DMA_SYNC_FORDEV);
8093526Sxy150489 
8103526Sxy150489 	/*
8113526Sxy150489 	 * Advance the E1000's Receive Queue #0 "Tail Pointer".
8123526Sxy150489 	 */
813*6735Scc210113 	E1000_WRITE_REG(hw, E1000_RDT(0),
8143526Sxy150489 	    (uint32_t)(last_desc - rx_ring->rbd_first));
8153526Sxy150489 
8165273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
8175273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
8185273Sgl147354 		Adapter->chip_state = E1000G_ERROR;
8195273Sgl147354 	}
8205273Sgl147354 
8215882Syy150190 	Adapter->rx_pkt_cnt = pkt_count;
8225882Syy150190 
8233526Sxy150489 	return (ret_mp);
8243526Sxy150489 
8253526Sxy150489 rx_drop:
8263526Sxy150489 	/*
8273526Sxy150489 	 * Zero out the receive descriptors status
8283526Sxy150489 	 */
8293526Sxy150489 	current_desc->status = 0;
8303526Sxy150489 
8313526Sxy150489 	/* Sync the Rx descriptor DMA buffers */
8324919Sxy150489 	(void) ddi_dma_sync(rx_ring->rbd_dma_handle,
8334919Sxy150489 	    0, 0, DDI_DMA_SYNC_FORDEV);
8343526Sxy150489 
8353526Sxy150489 	if (current_desc == rx_ring->rbd_last)
8363526Sxy150489 		rx_ring->rbd_next = rx_ring->rbd_first;
8373526Sxy150489 	else
8383526Sxy150489 		rx_ring->rbd_next++;
8393526Sxy150489 
8403526Sxy150489 	last_desc = current_desc;
8413526Sxy150489 
8424919Sxy150489 	(p_rx_sw_packet_t)QUEUE_POP_HEAD(&rx_ring->recv_list);
8433526Sxy150489 
8443526Sxy150489 	QUEUE_PUSH_TAIL(&rx_ring->recv_list, &packet->Link);
8453526Sxy150489 	/*
8463526Sxy150489 	 * Reclaim all old buffers already allocated during
8473526Sxy150489 	 * Jumbo receives.....for incomplete reception
8483526Sxy150489 	 */
8494919Sxy150489 	if (rx_ring->rx_mblk != NULL) {
8504919Sxy150489 		freemsg(rx_ring->rx_mblk);
8514919Sxy150489 		rx_ring->rx_mblk = NULL;
8524919Sxy150489 		rx_ring->rx_mblk_tail = NULL;
8534919Sxy150489 		rx_ring->rx_mblk_len = 0;
8543526Sxy150489 	}
8553526Sxy150489 	/*
8563526Sxy150489 	 * Advance the E1000's Receive Queue #0 "Tail Pointer".
8573526Sxy150489 	 */
858*6735Scc210113 	E1000_WRITE_REG(hw, E1000_RDT(0),
8593526Sxy150489 	    (uint32_t)(last_desc - rx_ring->rbd_first));
8603526Sxy150489 
8615273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
8625273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
8635273Sgl147354 		Adapter->chip_state = E1000G_ERROR;
8645273Sgl147354 	}
8655273Sgl147354 
8663526Sxy150489 	return (ret_mp);
8673526Sxy150489 }
868