xref: /onnv-gate/usr/src/uts/common/io/e1000g/e1000g_rx.c (revision 8178:951feae9d474)
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 /*
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 
1503526Sxy150489 	mutex_enter(&rx_ring->freelist_lock);
1513526Sxy150489 	QUEUE_PUSH_TAIL(&rx_ring->free_list, &packet->Link);
1524919Sxy150489 	rx_ring->avail_freepkt++;
1533526Sxy150489 	mutex_exit(&rx_ring->freelist_lock);
1543526Sxy150489 
1553526Sxy150489 	rw_exit(&e1000g_rx_detach_lock);
1563526Sxy150489 }
1573526Sxy150489 
1583526Sxy150489 /*
1594982Syy150190  * e1000g_priv_devi_list_clean - clean up e1000g_private_devi_list
1604982Syy150190  *
1614982Syy150190  * We will walk the e1000g_private_devi_list to free the entry marked
1624982Syy150190  * with the E1000G_PRIV_DEVI_DETACH flag.
1634982Syy150190  */
1644982Syy150190 static void
1654982Syy150190 e1000g_priv_devi_list_clean()
1664982Syy150190 {
1674982Syy150190 	private_devi_list_t *devi_node, *devi_del;
1684982Syy150190 
1694982Syy150190 	if (e1000g_private_devi_list == NULL)
1704982Syy150190 		return;
1714982Syy150190 
1724982Syy150190 	devi_node = e1000g_private_devi_list;
1734982Syy150190 	while ((devi_node != NULL) &&
1744982Syy150190 	    (devi_node->flag == E1000G_PRIV_DEVI_DETACH)) {
1754982Syy150190 		e1000g_private_devi_list = devi_node->next;
1764982Syy150190 		kmem_free(devi_node->priv_dip,
1774982Syy150190 		    sizeof (struct dev_info));
1784982Syy150190 		kmem_free(devi_node,
1794982Syy150190 		    sizeof (private_devi_list_t));
1804982Syy150190 		devi_node = e1000g_private_devi_list;
1814982Syy150190 	}
1824982Syy150190 	if (e1000g_private_devi_list == NULL)
1834982Syy150190 		return;
1844982Syy150190 	while (devi_node->next != NULL) {
1854982Syy150190 		if (devi_node->next->flag == E1000G_PRIV_DEVI_DETACH) {
1864982Syy150190 			devi_del = devi_node->next;
1874982Syy150190 			devi_node->next = devi_del->next;
1884982Syy150190 			kmem_free(devi_del->priv_dip,
1894982Syy150190 			    sizeof (struct dev_info));
1904982Syy150190 			kmem_free(devi_del,
1914982Syy150190 			    sizeof (private_devi_list_t));
1924982Syy150190 		} else {
1934982Syy150190 			devi_node = devi_node->next;
1944982Syy150190 		}
1954982Syy150190 	}
1964982Syy150190 }
1974982Syy150190 
1984982Syy150190 /*
1994919Sxy150489  * e1000g_rx_setup - setup rx data structures
2004919Sxy150489  *
2014919Sxy150489  * This routine initializes all of the receive related
2024919Sxy150489  * structures. This includes the receive descriptors, the
2034919Sxy150489  * actual receive buffers, and the rx_sw_packet software
2044919Sxy150489  * structures.
2053526Sxy150489  */
2063526Sxy150489 void
2074919Sxy150489 e1000g_rx_setup(struct e1000g *Adapter)
2083526Sxy150489 {
2094919Sxy150489 	struct e1000_hw *hw;
2104919Sxy150489 	p_rx_sw_packet_t packet;
2113526Sxy150489 	struct e1000_rx_desc *descriptor;
2124919Sxy150489 	uint32_t buf_low;
2134919Sxy150489 	uint32_t buf_high;
2143526Sxy150489 	uint32_t reg_val;
2157607STed.You@Sun.COM 	uint32_t rctl;
2167607STed.You@Sun.COM 	uint32_t rxdctl;
2177607STed.You@Sun.COM 	uint32_t ert;
2183526Sxy150489 	int i;
2193526Sxy150489 	int size;
2203526Sxy150489 	e1000g_rx_ring_t *rx_ring;
2213526Sxy150489 
2224919Sxy150489 	hw = &Adapter->shared;
2233526Sxy150489 	rx_ring = Adapter->rx_ring;
2243526Sxy150489 
2253526Sxy150489 	/*
2263526Sxy150489 	 * zero out all of the receive buffer descriptor memory
2273526Sxy150489 	 * assures any previous data or status is erased
2283526Sxy150489 	 */
2293526Sxy150489 	bzero(rx_ring->rbd_area,
2304919Sxy150489 	    sizeof (struct e1000_rx_desc) * Adapter->rx_desc_num);
2313526Sxy150489 
2324919Sxy150489 	if (!Adapter->rx_buffer_setup) {
2333526Sxy150489 		/* Init the list of "Receive Buffer" */
2343526Sxy150489 		QUEUE_INIT_LIST(&rx_ring->recv_list);
2353526Sxy150489 
2363526Sxy150489 		/* Init the list of "Free Receive Buffer" */
2373526Sxy150489 		QUEUE_INIT_LIST(&rx_ring->free_list);
2383526Sxy150489 
2393526Sxy150489 		/*
2403526Sxy150489 		 * Setup Receive list and the Free list. Note that
2413526Sxy150489 		 * the both were allocated in one packet area.
2423526Sxy150489 		 */
2433526Sxy150489 		packet = rx_ring->packet_area;
2443526Sxy150489 		descriptor = rx_ring->rbd_first;
2453526Sxy150489 
2464919Sxy150489 		for (i = 0; i < Adapter->rx_desc_num;
2473526Sxy150489 		    i++, packet = packet->next, descriptor++) {
2483526Sxy150489 			ASSERT(packet != NULL);
2493526Sxy150489 			ASSERT(descriptor != NULL);
2503526Sxy150489 			descriptor->buffer_addr =
2513526Sxy150489 			    packet->rx_buf->dma_address;
2524919Sxy150489 
2534919Sxy150489 			/* Add this rx_sw_packet to the receive list */
2543526Sxy150489 			QUEUE_PUSH_TAIL(&rx_ring->recv_list,
2553526Sxy150489 			    &packet->Link);
2563526Sxy150489 		}
2573526Sxy150489 
2584919Sxy150489 		for (i = 0; i < Adapter->rx_freelist_num;
2593526Sxy150489 		    i++, packet = packet->next) {
2603526Sxy150489 			ASSERT(packet != NULL);
2614919Sxy150489 			/* Add this rx_sw_packet to the free list */
2623526Sxy150489 			QUEUE_PUSH_TAIL(&rx_ring->free_list,
2633526Sxy150489 			    &packet->Link);
2643526Sxy150489 		}
2654919Sxy150489 		rx_ring->avail_freepkt = Adapter->rx_freelist_num;
2664919Sxy150489 
2674919Sxy150489 		Adapter->rx_buffer_setup = B_TRUE;
2683526Sxy150489 	} else {
2693526Sxy150489 		/* Setup the initial pointer to the first rx descriptor */
2704919Sxy150489 		packet = (p_rx_sw_packet_t)
2713526Sxy150489 		    QUEUE_GET_HEAD(&rx_ring->recv_list);
2723526Sxy150489 		descriptor = rx_ring->rbd_first;
2733526Sxy150489 
2744919Sxy150489 		for (i = 0; i < Adapter->rx_desc_num; i++) {
2753526Sxy150489 			ASSERT(packet != NULL);
2763526Sxy150489 			ASSERT(descriptor != NULL);
2773526Sxy150489 			descriptor->buffer_addr =
2783526Sxy150489 			    packet->rx_buf->dma_address;
2794919Sxy150489 
2804919Sxy150489 			/* Get next rx_sw_packet */
2814919Sxy150489 			packet = (p_rx_sw_packet_t)
2823526Sxy150489 			    QUEUE_GET_NEXT(&rx_ring->recv_list, &packet->Link);
2833526Sxy150489 			descriptor++;
2843526Sxy150489 		}
2853526Sxy150489 	}
2863526Sxy150489 
2875882Syy150190 	E1000_WRITE_REG(&Adapter->shared, E1000_RDTR, Adapter->rx_intr_delay);
2885882Syy150190 	E1000G_DEBUGLOG_1(Adapter, E1000G_INFO_LEVEL,
2895882Syy150190 	    "E1000_RDTR: 0x%x\n", Adapter->rx_intr_delay);
2905882Syy150190 	if (hw->mac.type >= e1000_82540) {
2915882Syy150190 		E1000_WRITE_REG(&Adapter->shared, E1000_RADV,
2925882Syy150190 		    Adapter->rx_intr_abs_delay);
2935882Syy150190 		E1000G_DEBUGLOG_1(Adapter, E1000G_INFO_LEVEL,
2945882Syy150190 		    "E1000_RADV: 0x%x\n", Adapter->rx_intr_abs_delay);
2955882Syy150190 	}
2965882Syy150190 
2973526Sxy150489 	/*
2983526Sxy150489 	 * Setup our descriptor pointers
2993526Sxy150489 	 */
3003526Sxy150489 	rx_ring->rbd_next = rx_ring->rbd_first;
3013526Sxy150489 
3024919Sxy150489 	size = Adapter->rx_desc_num * sizeof (struct e1000_rx_desc);
3036735Scc210113 	E1000_WRITE_REG(hw, E1000_RDLEN(0), size);
3046735Scc210113 	size = E1000_READ_REG(hw, E1000_RDLEN(0));
3053526Sxy150489 
3063526Sxy150489 	/* To get lower order bits */
3074919Sxy150489 	buf_low = (uint32_t)rx_ring->rbd_dma_addr;
3083526Sxy150489 	/* To get the higher order bits */
3094919Sxy150489 	buf_high = (uint32_t)(rx_ring->rbd_dma_addr >> 32);
3103526Sxy150489 
3116735Scc210113 	E1000_WRITE_REG(hw, E1000_RDBAH(0), buf_high);
3126735Scc210113 	E1000_WRITE_REG(hw, E1000_RDBAL(0), buf_low);
3133526Sxy150489 
3143526Sxy150489 	/*
3153526Sxy150489 	 * Setup our HW Rx Head & Tail descriptor pointers
3163526Sxy150489 	 */
3176735Scc210113 	E1000_WRITE_REG(hw, E1000_RDT(0),
3183526Sxy150489 	    (uint32_t)(rx_ring->rbd_last - rx_ring->rbd_first));
3196735Scc210113 	E1000_WRITE_REG(hw, E1000_RDH(0), 0);
3203526Sxy150489 
3213526Sxy150489 	/*
3223526Sxy150489 	 * Setup the Receive Control Register (RCTL), and ENABLE the
3233526Sxy150489 	 * receiver. The initial configuration is to: Enable the receiver,
3243526Sxy150489 	 * accept broadcasts, discard bad packets (and long packets),
3253526Sxy150489 	 * disable VLAN filter checking, set the receive descriptor
3263526Sxy150489 	 * minimum threshold size to 1/2, and the receive buffer size to
3273526Sxy150489 	 * 2k.
3283526Sxy150489 	 */
3297607STed.You@Sun.COM 	rctl = E1000_RCTL_EN |		/* Enable Receive Unit */
3303526Sxy150489 	    E1000_RCTL_BAM |		/* Accept Broadcast Packets */
3313526Sxy150489 	    E1000_RCTL_LPE |		/* Large Packet Enable bit */
3324919Sxy150489 	    (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT) |
3333526Sxy150489 	    E1000_RCTL_RDMTS_HALF |
3343526Sxy150489 	    E1000_RCTL_LBM_NO;		/* Loopback Mode = none */
3353526Sxy150489 
3364608Syy150190 	if (Adapter->strip_crc)
3377607STed.You@Sun.COM 		rctl |= E1000_RCTL_SECRC;	/* Strip Ethernet CRC */
3384608Syy150190 
339*8178SChenlu.Chen@Sun.COM 	if ((hw->mac.type == e1000_82545) ||
340*8178SChenlu.Chen@Sun.COM 	    (hw->mac.type == e1000_82546) ||
341*8178SChenlu.Chen@Sun.COM 	    (hw->mac.type == e1000_82546_rev_3)) {
3427607STed.You@Sun.COM 		rctl |= E1000_RCTL_SZ_2048;
343*8178SChenlu.Chen@Sun.COM 	} else {
344*8178SChenlu.Chen@Sun.COM 		if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_2K) &&
345*8178SChenlu.Chen@Sun.COM 		    (Adapter->max_frame_size <= FRAME_SIZE_UPTO_4K))
346*8178SChenlu.Chen@Sun.COM 			rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX;
347*8178SChenlu.Chen@Sun.COM 		else if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_4K) &&
348*8178SChenlu.Chen@Sun.COM 		    (Adapter->max_frame_size <= FRAME_SIZE_UPTO_8K))
349*8178SChenlu.Chen@Sun.COM 			rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX;
350*8178SChenlu.Chen@Sun.COM 		else if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_8K) &&
351*8178SChenlu.Chen@Sun.COM 		    (Adapter->max_frame_size <= FRAME_SIZE_UPTO_16K))
352*8178SChenlu.Chen@Sun.COM 			rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX;
353*8178SChenlu.Chen@Sun.COM 		else
354*8178SChenlu.Chen@Sun.COM 			rctl |= E1000_RCTL_SZ_2048;
355*8178SChenlu.Chen@Sun.COM 	}
3563526Sxy150489 
3574919Sxy150489 	if (e1000_tbi_sbp_enabled_82543(hw))
3587607STed.You@Sun.COM 		rctl |= E1000_RCTL_SBP;
3593526Sxy150489 
3604919Sxy150489 	/*
3614919Sxy150489 	 * Enable early receives on supported devices, only takes effect when
3624919Sxy150489 	 * packet size is equal or larger than the specified value (in 8 byte
3634919Sxy150489 	 * units), e.g. using jumbo frames when setting to E1000_ERT_2048
3644919Sxy150489 	 */
3657607STed.You@Sun.COM 	if ((hw->mac.type == e1000_82573) ||
3667607STed.You@Sun.COM 	    (hw->mac.type == e1000_82574) ||
3677607STed.You@Sun.COM 	    (hw->mac.type == e1000_ich9lan) ||
3687607STed.You@Sun.COM 	    (hw->mac.type == e1000_ich10lan)) {
3697607STed.You@Sun.COM 
3707607STed.You@Sun.COM 		ert = E1000_ERT_2048;
3714919Sxy150489 
3727607STed.You@Sun.COM 		/*
3737607STed.You@Sun.COM 		 * Special modification when ERT and
3747607STed.You@Sun.COM 		 * jumbo frames are enabled
3757607STed.You@Sun.COM 		 */
3767607STed.You@Sun.COM 		if (Adapter->default_mtu > ETHERMTU) {
3777607STed.You@Sun.COM 			rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(0));
3787607STed.You@Sun.COM 			E1000_WRITE_REG(hw, E1000_RXDCTL(0), rxdctl | 0x3);
3797607STed.You@Sun.COM 			ert |= (1 << 13);
3807607STed.You@Sun.COM 		}
3817607STed.You@Sun.COM 
3827607STed.You@Sun.COM 		E1000_WRITE_REG(hw, E1000_ERT, ert);
3837607STed.You@Sun.COM 	}
3843526Sxy150489 
3853526Sxy150489 	reg_val =
3863526Sxy150489 	    E1000_RXCSUM_TUOFL |	/* TCP/UDP checksum offload Enable */
3873526Sxy150489 	    E1000_RXCSUM_IPOFL;		/* IP checksum offload Enable */
3883526Sxy150489 
3894919Sxy150489 	E1000_WRITE_REG(hw, E1000_RXCSUM, reg_val);
3906871Szx151633 
3916871Szx151633 	/*
3926871Szx151633 	 * Workaround: Set bit 16 (IPv6_ExDIS) to disable the
3936871Szx151633 	 * processing of received IPV6 extension headers
3946871Szx151633 	 */
3956871Szx151633 	if ((hw->mac.type == e1000_82571) || (hw->mac.type == e1000_82572)) {
3966871Szx151633 		reg_val = E1000_READ_REG(hw, E1000_RFCTL);
3976871Szx151633 		reg_val |= (E1000_RFCTL_IPV6_EX_DIS |
3986871Szx151633 		    E1000_RFCTL_NEW_IPV6_EXT_DIS);
3996871Szx151633 		E1000_WRITE_REG(hw, E1000_RFCTL, reg_val);
4006871Szx151633 	}
4017607STed.You@Sun.COM 
4027607STed.You@Sun.COM 	/* Write to enable the receive unit */
4037607STed.You@Sun.COM 	E1000_WRITE_REG(hw, E1000_RCTL, rctl);
4043526Sxy150489 }
4053526Sxy150489 
4063526Sxy150489 /*
4074919Sxy150489  * e1000g_get_buf - get an rx sw packet from the free_list
4083526Sxy150489  */
4094919Sxy150489 static p_rx_sw_packet_t
4103526Sxy150489 e1000g_get_buf(e1000g_rx_ring_t *rx_ring)
4113526Sxy150489 {
4124919Sxy150489 	p_rx_sw_packet_t packet;
4133526Sxy150489 
4143526Sxy150489 	mutex_enter(&rx_ring->freelist_lock);
4154919Sxy150489 	packet = (p_rx_sw_packet_t)
4163526Sxy150489 	    QUEUE_POP_HEAD(&rx_ring->free_list);
4173526Sxy150489 	if (packet != NULL)
4184919Sxy150489 		rx_ring->avail_freepkt--;
4193526Sxy150489 	mutex_exit(&rx_ring->freelist_lock);
4203526Sxy150489 
4213526Sxy150489 	return (packet);
4223526Sxy150489 }
4233526Sxy150489 
4243526Sxy150489 /*
4254919Sxy150489  * e1000g_receive - main receive routine
4264919Sxy150489  *
4274919Sxy150489  * This routine will process packets received in an interrupt
4283526Sxy150489  */
4293526Sxy150489 mblk_t *
4303526Sxy150489 e1000g_receive(struct e1000g *Adapter)
4313526Sxy150489 {
4324919Sxy150489 	struct e1000_hw *hw;
4333526Sxy150489 	mblk_t *nmp;
4343526Sxy150489 	mblk_t *ret_mp;
4353526Sxy150489 	mblk_t *ret_nmp;
4363526Sxy150489 	struct e1000_rx_desc *current_desc;
4373526Sxy150489 	struct e1000_rx_desc *last_desc;
4384919Sxy150489 	p_rx_sw_packet_t packet;
4394919Sxy150489 	p_rx_sw_packet_t newpkt;
4407607STed.You@Sun.COM 	uint16_t length;
4413526Sxy150489 	uint32_t pkt_count;
4423526Sxy150489 	uint32_t desc_count;
4434919Sxy150489 	boolean_t accept_frame;
4443526Sxy150489 	boolean_t end_of_packet;
4453526Sxy150489 	boolean_t need_copy;
4463526Sxy150489 	e1000g_rx_ring_t *rx_ring;
4473526Sxy150489 	dma_buffer_t *rx_buf;
4483526Sxy150489 	uint16_t cksumflags;
4493526Sxy150489 
4503526Sxy150489 	ret_mp = NULL;
4513526Sxy150489 	ret_nmp = NULL;
4523526Sxy150489 	pkt_count = 0;
4533526Sxy150489 	desc_count = 0;
4543526Sxy150489 	cksumflags = 0;
4553526Sxy150489 
4564919Sxy150489 	hw = &Adapter->shared;
4573526Sxy150489 	rx_ring = Adapter->rx_ring;
4583526Sxy150489 
4593526Sxy150489 	/* Sync the Rx descriptor DMA buffers */
4603526Sxy150489 	(void) ddi_dma_sync(rx_ring->rbd_dma_handle,
4614919Sxy150489 	    0, 0, DDI_DMA_SYNC_FORKERNEL);
4623526Sxy150489 
4635273Sgl147354 	if (e1000g_check_dma_handle(rx_ring->rbd_dma_handle) != DDI_FM_OK) {
4645273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
4655273Sgl147354 		Adapter->chip_state = E1000G_ERROR;
4665273Sgl147354 	}
4675273Sgl147354 
4683526Sxy150489 	current_desc = rx_ring->rbd_next;
4693526Sxy150489 	if (!(current_desc->status & E1000_RXD_STAT_DD)) {
4703526Sxy150489 		/*
4713526Sxy150489 		 * don't send anything up. just clear the RFD
4723526Sxy150489 		 */
4734919Sxy150489 		E1000G_DEBUG_STAT(rx_ring->stat_none);
4743526Sxy150489 		return (ret_mp);
4753526Sxy150489 	}
4763526Sxy150489 
4773526Sxy150489 	/*
4783526Sxy150489 	 * Loop through the receive descriptors starting at the last known
4793526Sxy150489 	 * descriptor owned by the hardware that begins a packet.
4803526Sxy150489 	 */
4813526Sxy150489 	while ((current_desc->status & E1000_RXD_STAT_DD) &&
4824919Sxy150489 	    (pkt_count < Adapter->rx_limit_onintr)) {
4833526Sxy150489 
4843526Sxy150489 		desc_count++;
4853526Sxy150489 		/*
4863526Sxy150489 		 * Now this can happen in Jumbo frame situation.
4873526Sxy150489 		 */
4883526Sxy150489 		if (current_desc->status & E1000_RXD_STAT_EOP) {
4893526Sxy150489 			/* packet has EOP set */
4903526Sxy150489 			end_of_packet = B_TRUE;
4913526Sxy150489 		} else {
4923526Sxy150489 			/*
4933526Sxy150489 			 * If this received buffer does not have the
4943526Sxy150489 			 * End-Of-Packet bit set, the received packet
4953526Sxy150489 			 * will consume multiple buffers. We won't send this
4963526Sxy150489 			 * packet upstack till we get all the related buffers.
4973526Sxy150489 			 */
4983526Sxy150489 			end_of_packet = B_FALSE;
4993526Sxy150489 		}
5003526Sxy150489 
5013526Sxy150489 		/*
5023526Sxy150489 		 * Get a pointer to the actual receive buffer
5033526Sxy150489 		 * The mp->b_rptr is mapped to The CurrentDescriptor
5043526Sxy150489 		 * Buffer Address.
5053526Sxy150489 		 */
5063526Sxy150489 		packet =
5074919Sxy150489 		    (p_rx_sw_packet_t)QUEUE_GET_HEAD(&rx_ring->recv_list);
5083526Sxy150489 		ASSERT(packet != NULL);
5093526Sxy150489 
5103526Sxy150489 		rx_buf = packet->rx_buf;
5113526Sxy150489 
5123526Sxy150489 		length = current_desc->length;
5133526Sxy150489 
5143526Sxy150489 #ifdef __sparc
5154919Sxy150489 		if (packet->dma_type == USE_DVMA)
5163526Sxy150489 			dvma_sync(rx_buf->dma_handle, 0,
5173526Sxy150489 			    DDI_DMA_SYNC_FORKERNEL);
5184919Sxy150489 		else
5193526Sxy150489 			(void) ddi_dma_sync(rx_buf->dma_handle,
5203526Sxy150489 			    E1000G_IPALIGNROOM, length,
5214919Sxy150489 			    DDI_DMA_SYNC_FORKERNEL);
5224919Sxy150489 #else
5234919Sxy150489 		(void) ddi_dma_sync(rx_buf->dma_handle,
5244919Sxy150489 		    E1000G_IPALIGNROOM, length,
5254919Sxy150489 		    DDI_DMA_SYNC_FORKERNEL);
5264919Sxy150489 #endif
5274919Sxy150489 
5285273Sgl147354 		if (e1000g_check_dma_handle(
5295273Sgl147354 		    rx_buf->dma_handle) != DDI_FM_OK) {
5305273Sgl147354 			ddi_fm_service_impact(Adapter->dip,
5315273Sgl147354 			    DDI_SERVICE_DEGRADED);
5325273Sgl147354 			Adapter->chip_state = E1000G_ERROR;
5335273Sgl147354 		}
5345273Sgl147354 
5354919Sxy150489 		accept_frame = (current_desc->errors == 0) ||
5364919Sxy150489 		    ((current_desc->errors &
5374919Sxy150489 		    (E1000_RXD_ERR_TCPE | E1000_RXD_ERR_IPE)) != 0);
5384919Sxy150489 
5394919Sxy150489 		if (hw->mac.type == e1000_82543) {
5404919Sxy150489 			unsigned char last_byte;
5414919Sxy150489 
5424919Sxy150489 			last_byte =
5434919Sxy150489 			    *((unsigned char *)rx_buf->address + length - 1);
5444919Sxy150489 
5454919Sxy150489 			if (TBI_ACCEPT(hw,
5464919Sxy150489 			    current_desc->status, current_desc->errors,
5476735Scc210113 			    current_desc->length, last_byte,
5486735Scc210113 			    Adapter->min_frame_size, Adapter->max_frame_size)) {
5494919Sxy150489 
5504919Sxy150489 				e1000_tbi_adjust_stats(Adapter,
5514919Sxy150489 				    length, hw->mac.addr);
5524919Sxy150489 
5534919Sxy150489 				length--;
5544919Sxy150489 				accept_frame = B_TRUE;
5554919Sxy150489 			} else if (e1000_tbi_sbp_enabled_82543(hw) &&
5564919Sxy150489 			    (current_desc->errors == E1000_RXD_ERR_CE)) {
5574919Sxy150489 				accept_frame = B_TRUE;
5584919Sxy150489 			}
5593526Sxy150489 		}
5603526Sxy150489 
5613526Sxy150489 		/*
5623526Sxy150489 		 * Indicate the packet to the NOS if it was good.
5633526Sxy150489 		 * Normally, hardware will discard bad packets for us.
5643526Sxy150489 		 * Check for the packet to be a valid Ethernet packet
5653526Sxy150489 		 */
5664919Sxy150489 		if (!accept_frame) {
5673526Sxy150489 			/*
5683526Sxy150489 			 * error in incoming packet, either the packet is not a
5693526Sxy150489 			 * ethernet size packet, or the packet has an error. In
5703526Sxy150489 			 * either case, the packet will simply be discarded.
5713526Sxy150489 			 */
5724919Sxy150489 			E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
5733526Sxy150489 			    "Process Receive Interrupts: Error in Packet\n");
5743526Sxy150489 
5754919Sxy150489 			E1000G_STAT(rx_ring->stat_error);
5763526Sxy150489 			/*
5773526Sxy150489 			 * Returning here as we are done here. There is
5783526Sxy150489 			 * no point in waiting for while loop to elapse
5793526Sxy150489 			 * and the things which were done. More efficient
5803526Sxy150489 			 * and less error prone...
5813526Sxy150489 			 */
5823526Sxy150489 			goto rx_drop;
5833526Sxy150489 		}
5843526Sxy150489 
5854608Syy150190 		/*
5864608Syy150190 		 * If the Ethernet CRC is not stripped by the hardware,
5874608Syy150190 		 * we need to strip it before sending it up to the stack.
5884608Syy150190 		 */
5894608Syy150190 		if (end_of_packet && !Adapter->strip_crc) {
5906394Scc210113 			if (length > ETHERFCSL) {
5916394Scc210113 				length -= ETHERFCSL;
5924608Syy150190 			} else {
5934608Syy150190 				/*
5944608Syy150190 				 * If the fragment is smaller than the CRC,
5954608Syy150190 				 * drop this fragment, do the processing of
5964608Syy150190 				 * the end of the packet.
5974608Syy150190 				 */
5984919Sxy150489 				ASSERT(rx_ring->rx_mblk_tail != NULL);
5994919Sxy150489 				rx_ring->rx_mblk_tail->b_wptr -=
6006394Scc210113 				    ETHERFCSL - length;
6014919Sxy150489 				rx_ring->rx_mblk_len -=
6026394Scc210113 				    ETHERFCSL - length;
6034608Syy150190 
6044608Syy150190 				QUEUE_POP_HEAD(&rx_ring->recv_list);
6054608Syy150190 
6064608Syy150190 				goto rx_end_of_packet;
6074608Syy150190 			}
6084608Syy150190 		}
6094608Syy150190 
6103526Sxy150489 		need_copy = B_TRUE;
6113526Sxy150489 
6123526Sxy150489 		if (length <= Adapter->rx_bcopy_thresh)
6133526Sxy150489 			goto rx_copy;
6143526Sxy150489 
6153526Sxy150489 		/*
6163526Sxy150489 		 * Get the pre-constructed mblk that was associated
6173526Sxy150489 		 * to the receive data buffer.
6183526Sxy150489 		 */
6193526Sxy150489 		if (packet->mp == NULL) {
6203526Sxy150489 			packet->mp = desballoc((unsigned char *)
6213526Sxy150489 			    rx_buf->address - E1000G_IPALIGNROOM,
6223526Sxy150489 			    length + E1000G_IPALIGNROOM,
6233526Sxy150489 			    BPRI_MED, &packet->free_rtn);
6243526Sxy150489 
6253526Sxy150489 			if (packet->mp != NULL) {
6263526Sxy150489 				packet->mp->b_rptr += E1000G_IPALIGNROOM;
6273526Sxy150489 				packet->mp->b_wptr += E1000G_IPALIGNROOM;
6283526Sxy150489 			} else {
6294919Sxy150489 				E1000G_STAT(rx_ring->stat_esballoc_fail);
6303526Sxy150489 			}
6313526Sxy150489 		}
6323526Sxy150489 
6333526Sxy150489 		if (packet->mp != NULL) {
6343526Sxy150489 			/*
6353526Sxy150489 			 * We have two sets of buffer pool. One associated with
6363526Sxy150489 			 * the Rxdescriptors and other a freelist buffer pool.
6373526Sxy150489 			 * Each time we get a good packet, Try to get a buffer
6383526Sxy150489 			 * from the freelist pool using e1000g_get_buf. If we
6393526Sxy150489 			 * get free buffer, then replace the descriptor buffer
6403526Sxy150489 			 * address with the free buffer we just got, and pass
6413526Sxy150489 			 * the pre-constructed mblk upstack. (note no copying)
6423526Sxy150489 			 *
6433526Sxy150489 			 * If we failed to get a free buffer, then try to
6443526Sxy150489 			 * allocate a new buffer(mp) and copy the recv buffer
6453526Sxy150489 			 * content to our newly allocated buffer(mp). Don't
6463526Sxy150489 			 * disturb the desriptor buffer address. (note copying)
6473526Sxy150489 			 */
6483526Sxy150489 			newpkt = e1000g_get_buf(rx_ring);
6493526Sxy150489 
6503526Sxy150489 			if (newpkt != NULL) {
6513526Sxy150489 				/*
6523526Sxy150489 				 * Get the mblk associated to the data,
6533526Sxy150489 				 * and strip it off the sw packet.
6543526Sxy150489 				 */
6553526Sxy150489 				nmp = packet->mp;
6563526Sxy150489 				packet->mp = NULL;
6574982Syy150190 				packet->flag = E1000G_RX_SW_SENDUP;
6583526Sxy150489 
6593526Sxy150489 				/*
6603526Sxy150489 				 * Now replace old buffer with the new
6613526Sxy150489 				 * one we got from free list
6623526Sxy150489 				 * Both the RxSwPacket as well as the
6633526Sxy150489 				 * Receive Buffer Descriptor will now
6643526Sxy150489 				 * point to this new packet.
6653526Sxy150489 				 */
6663526Sxy150489 				packet = newpkt;
6674919Sxy150489 
6683526Sxy150489 				current_desc->buffer_addr =
6693526Sxy150489 				    newpkt->rx_buf->dma_address;
6704919Sxy150489 
6713526Sxy150489 				need_copy = B_FALSE;
6723526Sxy150489 			} else {
6734919Sxy150489 				E1000G_DEBUG_STAT(rx_ring->stat_no_freepkt);
6743526Sxy150489 			}
6753526Sxy150489 		}
6763526Sxy150489 
6773526Sxy150489 rx_copy:
6783526Sxy150489 		if (need_copy) {
6793526Sxy150489 			/*
6803526Sxy150489 			 * No buffers available on free list,
6813526Sxy150489 			 * bcopy the data from the buffer and
6823526Sxy150489 			 * keep the original buffer. Dont want to
6833526Sxy150489 			 * do this.. Yack but no other way
6843526Sxy150489 			 */
6854919Sxy150489 			if ((nmp = allocb(length + E1000G_IPALIGNROOM,
6864608Syy150190 			    BPRI_MED)) == NULL) {
6873526Sxy150489 				/*
6883526Sxy150489 				 * The system has no buffers available
6893526Sxy150489 				 * to send up the incoming packet, hence
6903526Sxy150489 				 * the packet will have to be processed
6913526Sxy150489 				 * when there're more buffers available.
6923526Sxy150489 				 */
6934919Sxy150489 				E1000G_STAT(rx_ring->stat_allocb_fail);
6943526Sxy150489 				goto rx_drop;
6953526Sxy150489 			}
6963526Sxy150489 			nmp->b_rptr += E1000G_IPALIGNROOM;
6973526Sxy150489 			nmp->b_wptr += E1000G_IPALIGNROOM;
6983526Sxy150489 			/*
6993526Sxy150489 			 * The free list did not have any buffers
7003526Sxy150489 			 * available, so, the received packet will
7013526Sxy150489 			 * have to be copied into a mp and the original
7023526Sxy150489 			 * buffer will have to be retained for future
7033526Sxy150489 			 * packet reception.
7043526Sxy150489 			 */
7054919Sxy150489 			bcopy(rx_buf->address, nmp->b_wptr, length);
7063526Sxy150489 		}
7073526Sxy150489 
7083526Sxy150489 		/*
7094919Sxy150489 		 * The rx_sw_packet MUST be popped off the
7103526Sxy150489 		 * RxSwPacketList before either a putnext or freemsg
7113526Sxy150489 		 * is done on the mp that has now been created by the
7123526Sxy150489 		 * desballoc. If not, it is possible that the free
7133526Sxy150489 		 * routine will get called from the interrupt context
7143526Sxy150489 		 * and try to put this packet on the free list
7153526Sxy150489 		 */
7164919Sxy150489 		(p_rx_sw_packet_t)QUEUE_POP_HEAD(&rx_ring->recv_list);
7173526Sxy150489 
7183526Sxy150489 		ASSERT(nmp != NULL);
7193526Sxy150489 		nmp->b_wptr += length;
7203526Sxy150489 
7214919Sxy150489 		if (rx_ring->rx_mblk == NULL) {
7223526Sxy150489 			/*
7233526Sxy150489 			 *  TCP/UDP checksum offload and
7243526Sxy150489 			 *  IP checksum offload
7253526Sxy150489 			 */
7264919Sxy150489 			if (!(current_desc->status & E1000_RXD_STAT_IXSM)) {
7273526Sxy150489 				/*
7283526Sxy150489 				 * Check TCP/UDP checksum
7293526Sxy150489 				 */
7303526Sxy150489 				if ((current_desc->status &
7314608Syy150190 				    E1000_RXD_STAT_TCPCS) &&
7323526Sxy150489 				    !(current_desc->errors &
7334608Syy150190 				    E1000_RXD_ERR_TCPE))
7343526Sxy150489 					cksumflags |= HCK_FULLCKSUM |
7354608Syy150190 					    HCK_FULLCKSUM_OK;
7363526Sxy150489 				/*
7373526Sxy150489 				 * Check IP Checksum
7383526Sxy150489 				 */
7393526Sxy150489 				if ((current_desc->status &
7404608Syy150190 				    E1000_RXD_STAT_IPCS) &&
7413526Sxy150489 				    !(current_desc->errors &
7424608Syy150190 				    E1000_RXD_ERR_IPE))
7433526Sxy150489 					cksumflags |= HCK_IPV4_HDRCKSUM;
7443526Sxy150489 			}
7453526Sxy150489 		}
7463526Sxy150489 
7473526Sxy150489 		/*
7483526Sxy150489 		 * We need to maintain our packet chain in the global
7493526Sxy150489 		 * Adapter structure, for the Rx processing can end
7503526Sxy150489 		 * with a fragment that has no EOP set.
7513526Sxy150489 		 */
7524919Sxy150489 		if (rx_ring->rx_mblk == NULL) {
7533526Sxy150489 			/* Get the head of the message chain */
7544919Sxy150489 			rx_ring->rx_mblk = nmp;
7554919Sxy150489 			rx_ring->rx_mblk_tail = nmp;
7564919Sxy150489 			rx_ring->rx_mblk_len = length;
7573526Sxy150489 		} else {	/* Not the first packet */
7583526Sxy150489 			/* Continue adding buffers */
7594919Sxy150489 			rx_ring->rx_mblk_tail->b_cont = nmp;
7604919Sxy150489 			rx_ring->rx_mblk_tail = nmp;
7614919Sxy150489 			rx_ring->rx_mblk_len += length;
7623526Sxy150489 		}
7634919Sxy150489 		ASSERT(rx_ring->rx_mblk != NULL);
7644919Sxy150489 		ASSERT(rx_ring->rx_mblk_tail != NULL);
7654919Sxy150489 		ASSERT(rx_ring->rx_mblk_tail->b_cont == NULL);
7663526Sxy150489 
7673526Sxy150489 		/*
7683526Sxy150489 		 * Now this MP is ready to travel upwards but some more
7693526Sxy150489 		 * fragments are coming.
7703526Sxy150489 		 * We will send packet upwards as soon as we get EOP
7713526Sxy150489 		 * set on the packet.
7723526Sxy150489 		 */
7733526Sxy150489 		if (!end_of_packet) {
7743526Sxy150489 			/*
7753526Sxy150489 			 * continue to get the next descriptor,
7763526Sxy150489 			 * Tail would be advanced at the end
7773526Sxy150489 			 */
7783526Sxy150489 			goto rx_next_desc;
7793526Sxy150489 		}
7803526Sxy150489 
7814608Syy150190 rx_end_of_packet:
7823526Sxy150489 		/*
7833526Sxy150489 		 * Found packet with EOP
7843526Sxy150489 		 * Process the last fragment.
7853526Sxy150489 		 */
7863526Sxy150489 		if (cksumflags != 0) {
7874919Sxy150489 			(void) hcksum_assoc(rx_ring->rx_mblk,
7883526Sxy150489 			    NULL, NULL, 0, 0, 0, 0, cksumflags, 0);
7893526Sxy150489 			cksumflags = 0;
7903526Sxy150489 		}
7913526Sxy150489 
7923526Sxy150489 		/*
7933526Sxy150489 		 * Count packets that span multi-descriptors
7943526Sxy150489 		 */
7954919Sxy150489 		E1000G_DEBUG_STAT_COND(rx_ring->stat_multi_desc,
7964919Sxy150489 		    (rx_ring->rx_mblk->b_cont != NULL));
7973526Sxy150489 
7983526Sxy150489 		/*
7993526Sxy150489 		 * Append to list to send upstream
8003526Sxy150489 		 */
8013526Sxy150489 		if (ret_mp == NULL) {
8024919Sxy150489 			ret_mp = ret_nmp = rx_ring->rx_mblk;
8033526Sxy150489 		} else {
8044919Sxy150489 			ret_nmp->b_next = rx_ring->rx_mblk;
8054919Sxy150489 			ret_nmp = rx_ring->rx_mblk;
8063526Sxy150489 		}
8073526Sxy150489 		ret_nmp->b_next = NULL;
8083526Sxy150489 
8094919Sxy150489 		rx_ring->rx_mblk = NULL;
8104919Sxy150489 		rx_ring->rx_mblk_tail = NULL;
8114919Sxy150489 		rx_ring->rx_mblk_len = 0;
8123526Sxy150489 
8133526Sxy150489 		pkt_count++;
8143526Sxy150489 
8153526Sxy150489 rx_next_desc:
8163526Sxy150489 		/*
8173526Sxy150489 		 * Zero out the receive descriptors status
8183526Sxy150489 		 */
8193526Sxy150489 		current_desc->status = 0;
8203526Sxy150489 
8213526Sxy150489 		if (current_desc == rx_ring->rbd_last)
8223526Sxy150489 			rx_ring->rbd_next = rx_ring->rbd_first;
8233526Sxy150489 		else
8243526Sxy150489 			rx_ring->rbd_next++;
8253526Sxy150489 
8263526Sxy150489 		last_desc = current_desc;
8273526Sxy150489 		current_desc = rx_ring->rbd_next;
8283526Sxy150489 
8293526Sxy150489 		/*
8303526Sxy150489 		 * Put the buffer that we just indicated back
8313526Sxy150489 		 * at the end of our list
8323526Sxy150489 		 */
8333526Sxy150489 		QUEUE_PUSH_TAIL(&rx_ring->recv_list,
8343526Sxy150489 		    &packet->Link);
8353526Sxy150489 	}	/* while loop */
8363526Sxy150489 
8373526Sxy150489 	/* Sync the Rx descriptor DMA buffers */
8384919Sxy150489 	(void) ddi_dma_sync(rx_ring->rbd_dma_handle,
8394919Sxy150489 	    0, 0, DDI_DMA_SYNC_FORDEV);
8403526Sxy150489 
8413526Sxy150489 	/*
8423526Sxy150489 	 * Advance the E1000's Receive Queue #0 "Tail Pointer".
8433526Sxy150489 	 */
8446735Scc210113 	E1000_WRITE_REG(hw, E1000_RDT(0),
8453526Sxy150489 	    (uint32_t)(last_desc - rx_ring->rbd_first));
8463526Sxy150489 
8475273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
8485273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
8495273Sgl147354 		Adapter->chip_state = E1000G_ERROR;
8505273Sgl147354 	}
8515273Sgl147354 
8525882Syy150190 	Adapter->rx_pkt_cnt = pkt_count;
8535882Syy150190 
8543526Sxy150489 	return (ret_mp);
8553526Sxy150489 
8563526Sxy150489 rx_drop:
8573526Sxy150489 	/*
8583526Sxy150489 	 * Zero out the receive descriptors status
8593526Sxy150489 	 */
8603526Sxy150489 	current_desc->status = 0;
8613526Sxy150489 
8623526Sxy150489 	/* Sync the Rx descriptor DMA buffers */
8634919Sxy150489 	(void) ddi_dma_sync(rx_ring->rbd_dma_handle,
8644919Sxy150489 	    0, 0, DDI_DMA_SYNC_FORDEV);
8653526Sxy150489 
8663526Sxy150489 	if (current_desc == rx_ring->rbd_last)
8673526Sxy150489 		rx_ring->rbd_next = rx_ring->rbd_first;
8683526Sxy150489 	else
8693526Sxy150489 		rx_ring->rbd_next++;
8703526Sxy150489 
8713526Sxy150489 	last_desc = current_desc;
8723526Sxy150489 
8734919Sxy150489 	(p_rx_sw_packet_t)QUEUE_POP_HEAD(&rx_ring->recv_list);
8743526Sxy150489 
8753526Sxy150489 	QUEUE_PUSH_TAIL(&rx_ring->recv_list, &packet->Link);
8763526Sxy150489 	/*
8773526Sxy150489 	 * Reclaim all old buffers already allocated during
8783526Sxy150489 	 * Jumbo receives.....for incomplete reception
8793526Sxy150489 	 */
8804919Sxy150489 	if (rx_ring->rx_mblk != NULL) {
8814919Sxy150489 		freemsg(rx_ring->rx_mblk);
8824919Sxy150489 		rx_ring->rx_mblk = NULL;
8834919Sxy150489 		rx_ring->rx_mblk_tail = NULL;
8844919Sxy150489 		rx_ring->rx_mblk_len = 0;
8853526Sxy150489 	}
8863526Sxy150489 	/*
8873526Sxy150489 	 * Advance the E1000's Receive Queue #0 "Tail Pointer".
8883526Sxy150489 	 */
8896735Scc210113 	E1000_WRITE_REG(hw, E1000_RDT(0),
8903526Sxy150489 	    (uint32_t)(last_desc - rx_ring->rbd_first));
8913526Sxy150489 
8925273Sgl147354 	if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) {
8935273Sgl147354 		ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED);
8945273Sgl147354 		Adapter->chip_state = E1000G_ERROR;
8955273Sgl147354 	}
8965273Sgl147354 
8973526Sxy150489 	return (ret_mp);
8983526Sxy150489 }
899