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