108057504Sxy150489 /* 208057504Sxy150489 * This file is provided under a CDDLv1 license. When using or 308057504Sxy150489 * redistributing this file, you may do so under this license. 408057504Sxy150489 * In redistributing this file this license must be included 508057504Sxy150489 * and no other modification of this header file is permitted. 608057504Sxy150489 * 708057504Sxy150489 * CDDL LICENSE SUMMARY 808057504Sxy150489 * 9d5c3073dSchenlu chen - Sun Microsystems - Beijing China * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved. 1008057504Sxy150489 * 1108057504Sxy150489 * The contents of this file are subject to the terms of Version 1208057504Sxy150489 * 1.0 of the Common Development and Distribution License (the "License"). 1308057504Sxy150489 * 1408057504Sxy150489 * You should have received a copy of the License with this software. 1508057504Sxy150489 * You can obtain a copy of the License at 1608057504Sxy150489 * http://www.opensolaris.org/os/licensing. 1708057504Sxy150489 * See the License for the specific language governing permissions 1808057504Sxy150489 * and limitations under the License. 1908057504Sxy150489 */ 2008057504Sxy150489 2108057504Sxy150489 /* 223fb4efefSchangqing li - Sun Microsystems - Beijing China * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 2308057504Sxy150489 */ 2408057504Sxy150489 2508057504Sxy150489 /* 26dab7de2dSGarrett D'Amore * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 27*42cc51e0SRobert Mustacchi * Copyright 2016 Joyent, Inc. 28dab7de2dSGarrett D'Amore */ 29dab7de2dSGarrett D'Amore 30dab7de2dSGarrett D'Amore /* 3108057504Sxy150489 * ********************************************************************** 3208057504Sxy150489 * * 3308057504Sxy150489 * Module Name: * 3408057504Sxy150489 * e1000g_rx.c * 3508057504Sxy150489 * * 3608057504Sxy150489 * Abstract: * 3725f2d433Sxy150489 * This file contains some routines that take care of Receive * 3825f2d433Sxy150489 * interrupt and also for the received packets it sends up to * 3925f2d433Sxy150489 * upper layer. * 4008057504Sxy150489 * It tries to do a zero copy if free buffers are available in * 4125f2d433Sxy150489 * the pool. * 4208057504Sxy150489 * * 4308057504Sxy150489 * ********************************************************************** 4408057504Sxy150489 */ 4508057504Sxy150489 4608057504Sxy150489 #include "e1000g_sw.h" 4708057504Sxy150489 #include "e1000g_debug.h" 4808057504Sxy150489 4954e0d7a5SMiles Xu, Sun Microsystems static p_rx_sw_packet_t e1000g_get_buf(e1000g_rx_data_t *rx_data); 5008057504Sxy150489 #pragma inline(e1000g_get_buf) 5108057504Sxy150489 5208057504Sxy150489 /* 5325f2d433Sxy150489 * e1000g_rxfree_func - the call-back function to reclaim rx buffer 5425f2d433Sxy150489 * 5525f2d433Sxy150489 * This function is called when an mp is freed by the user thru 5625f2d433Sxy150489 * freeb call (Only for mp constructed through desballoc call) 5725f2d433Sxy150489 * It returns back the freed buffer to the freelist 5808057504Sxy150489 */ 5908057504Sxy150489 void 6025f2d433Sxy150489 e1000g_rxfree_func(p_rx_sw_packet_t packet) 6108057504Sxy150489 { 6254e0d7a5SMiles Xu, Sun Microsystems e1000g_rx_data_t *rx_data; 6354e0d7a5SMiles Xu, Sun Microsystems private_devi_list_t *devi_node; 6454e0d7a5SMiles Xu, Sun Microsystems struct e1000g *Adapter; 6554e0d7a5SMiles Xu, Sun Microsystems uint32_t ring_cnt; 6654e0d7a5SMiles Xu, Sun Microsystems uint32_t ref_cnt; 6754e0d7a5SMiles Xu, Sun Microsystems unsigned char *address; 6808057504Sxy150489 6954e0d7a5SMiles Xu, Sun Microsystems if (packet->ref_cnt == 0) { 7008057504Sxy150489 /* 7154e0d7a5SMiles Xu, Sun Microsystems * This case only happens when rx buffers are being freed 7254e0d7a5SMiles Xu, Sun Microsystems * in e1000g_stop() and freemsg() is called. 7308057504Sxy150489 */ 7408057504Sxy150489 return; 7508057504Sxy150489 } 7608057504Sxy150489 7754e0d7a5SMiles Xu, Sun Microsystems rx_data = (e1000g_rx_data_t *)(uintptr_t)packet->rx_data; 7808057504Sxy150489 7908057504Sxy150489 if (packet->mp == NULL) { 8008057504Sxy150489 /* 8108057504Sxy150489 * Allocate a mblk that binds to the data buffer 8208057504Sxy150489 */ 8354e0d7a5SMiles Xu, Sun Microsystems address = (unsigned char *)packet->rx_buf->address; 8454e0d7a5SMiles Xu, Sun Microsystems if (address != NULL) { 8508057504Sxy150489 packet->mp = desballoc((unsigned char *) 8646ebaa55SMiles Xu, Sun Microsystems address, packet->rx_buf->size, 8708057504Sxy150489 BPRI_MED, &packet->free_rtn); 8854e0d7a5SMiles Xu, Sun Microsystems } 8908057504Sxy150489 } 9008057504Sxy150489 91da14cebeSEric Cheng /* 92da14cebeSEric Cheng * Enqueue the recycled packets in a recycle queue. When freelist 93da14cebeSEric Cheng * dries up, move the entire chain of packets from recycle queue 94da14cebeSEric Cheng * to freelist. This helps in avoiding per packet mutex contention 95da14cebeSEric Cheng * around freelist. 96da14cebeSEric Cheng */ 9754e0d7a5SMiles Xu, Sun Microsystems mutex_enter(&rx_data->recycle_lock); 9854e0d7a5SMiles Xu, Sun Microsystems QUEUE_PUSH_TAIL(&rx_data->recycle_list, &packet->Link); 9954e0d7a5SMiles Xu, Sun Microsystems rx_data->recycle_freepkt++; 10054e0d7a5SMiles Xu, Sun Microsystems mutex_exit(&rx_data->recycle_lock); 10108057504Sxy150489 10254e0d7a5SMiles Xu, Sun Microsystems ref_cnt = atomic_dec_32_nv(&packet->ref_cnt); 10354e0d7a5SMiles Xu, Sun Microsystems if (ref_cnt == 0) { 10482df3b26Schangqing li - Sun Microsystems - Beijing China mutex_enter(&e1000g_rx_detach_lock); 10554e0d7a5SMiles Xu, Sun Microsystems e1000g_free_rx_sw_packet(packet, B_FALSE); 10654e0d7a5SMiles Xu, Sun Microsystems 10754e0d7a5SMiles Xu, Sun Microsystems atomic_dec_32(&rx_data->pending_count); 10854e0d7a5SMiles Xu, Sun Microsystems atomic_dec_32(&e1000g_mblks_pending); 10954e0d7a5SMiles Xu, Sun Microsystems 11054e0d7a5SMiles Xu, Sun Microsystems if ((rx_data->pending_count == 0) && 11154e0d7a5SMiles Xu, Sun Microsystems (rx_data->flag & E1000G_RX_STOPPED)) { 11254e0d7a5SMiles Xu, Sun Microsystems devi_node = rx_data->priv_devi_node; 11354e0d7a5SMiles Xu, Sun Microsystems 11454e0d7a5SMiles Xu, Sun Microsystems if (devi_node != NULL) { 11554e0d7a5SMiles Xu, Sun Microsystems ring_cnt = atomic_dec_32_nv( 11654e0d7a5SMiles Xu, Sun Microsystems &devi_node->pending_rx_count); 11754e0d7a5SMiles Xu, Sun Microsystems if ((ring_cnt == 0) && 11854e0d7a5SMiles Xu, Sun Microsystems (devi_node->flag & 11954e0d7a5SMiles Xu, Sun Microsystems E1000G_PRIV_DEVI_DETACH)) { 12054e0d7a5SMiles Xu, Sun Microsystems e1000g_free_priv_devi_node( 12154e0d7a5SMiles Xu, Sun Microsystems devi_node); 12208057504Sxy150489 } 123ea6b684aSyy150190 } else { 12454e0d7a5SMiles Xu, Sun Microsystems Adapter = rx_data->rx_ring->adapter; 12554e0d7a5SMiles Xu, Sun Microsystems atomic_dec_32( 12654e0d7a5SMiles Xu, Sun Microsystems &Adapter->pending_rx_count); 127ea6b684aSyy150190 } 12846ebaa55SMiles Xu, Sun Microsystems 12946ebaa55SMiles Xu, Sun Microsystems e1000g_free_rx_pending_buffers(rx_data); 13046ebaa55SMiles Xu, Sun Microsystems e1000g_free_rx_data(rx_data); 131ea6b684aSyy150190 } 13254e0d7a5SMiles Xu, Sun Microsystems mutex_exit(&e1000g_rx_detach_lock); 13354e0d7a5SMiles Xu, Sun Microsystems } 134ea6b684aSyy150190 } 135ea6b684aSyy150190 136ea6b684aSyy150190 /* 13725f2d433Sxy150489 * e1000g_rx_setup - setup rx data structures 13825f2d433Sxy150489 * 13925f2d433Sxy150489 * This routine initializes all of the receive related 14025f2d433Sxy150489 * structures. This includes the receive descriptors, the 14125f2d433Sxy150489 * actual receive buffers, and the rx_sw_packet software 14225f2d433Sxy150489 * structures. 14308057504Sxy150489 */ 14408057504Sxy150489 void 14525f2d433Sxy150489 e1000g_rx_setup(struct e1000g *Adapter) 14608057504Sxy150489 { 14725f2d433Sxy150489 struct e1000_hw *hw; 14825f2d433Sxy150489 p_rx_sw_packet_t packet; 14908057504Sxy150489 struct e1000_rx_desc *descriptor; 15025f2d433Sxy150489 uint32_t buf_low; 15125f2d433Sxy150489 uint32_t buf_high; 15208057504Sxy150489 uint32_t reg_val; 1534d737963Sxiangtao you - Sun Microsystems - Beijing China uint32_t rctl; 1544d737963Sxiangtao you - Sun Microsystems - Beijing China uint32_t rxdctl; 1554d737963Sxiangtao you - Sun Microsystems - Beijing China uint32_t ert; 156caf05df5SMiles Xu, Sun Microsystems uint16_t phy_data; 15708057504Sxy150489 int i; 15808057504Sxy150489 int size; 15954e0d7a5SMiles Xu, Sun Microsystems e1000g_rx_data_t *rx_data; 16008057504Sxy150489 16125f2d433Sxy150489 hw = &Adapter->shared; 16254e0d7a5SMiles Xu, Sun Microsystems rx_data = Adapter->rx_ring->rx_data; 16308057504Sxy150489 16408057504Sxy150489 /* 16508057504Sxy150489 * zero out all of the receive buffer descriptor memory 16608057504Sxy150489 * assures any previous data or status is erased 16708057504Sxy150489 */ 16854e0d7a5SMiles Xu, Sun Microsystems bzero(rx_data->rbd_area, 16925f2d433Sxy150489 sizeof (struct e1000_rx_desc) * Adapter->rx_desc_num); 17008057504Sxy150489 17125f2d433Sxy150489 if (!Adapter->rx_buffer_setup) { 17208057504Sxy150489 /* Init the list of "Receive Buffer" */ 17354e0d7a5SMiles Xu, Sun Microsystems QUEUE_INIT_LIST(&rx_data->recv_list); 17408057504Sxy150489 17508057504Sxy150489 /* Init the list of "Free Receive Buffer" */ 17654e0d7a5SMiles Xu, Sun Microsystems QUEUE_INIT_LIST(&rx_data->free_list); 17708057504Sxy150489 178da14cebeSEric Cheng /* Init the list of "Free Receive Buffer" */ 17954e0d7a5SMiles Xu, Sun Microsystems QUEUE_INIT_LIST(&rx_data->recycle_list); 18008057504Sxy150489 /* 18108057504Sxy150489 * Setup Receive list and the Free list. Note that 18208057504Sxy150489 * the both were allocated in one packet area. 18308057504Sxy150489 */ 18454e0d7a5SMiles Xu, Sun Microsystems packet = rx_data->packet_area; 18554e0d7a5SMiles Xu, Sun Microsystems descriptor = rx_data->rbd_first; 18608057504Sxy150489 18725f2d433Sxy150489 for (i = 0; i < Adapter->rx_desc_num; 18808057504Sxy150489 i++, packet = packet->next, descriptor++) { 18908057504Sxy150489 ASSERT(packet != NULL); 19008057504Sxy150489 ASSERT(descriptor != NULL); 19108057504Sxy150489 descriptor->buffer_addr = 19208057504Sxy150489 packet->rx_buf->dma_address; 19325f2d433Sxy150489 19425f2d433Sxy150489 /* Add this rx_sw_packet to the receive list */ 19554e0d7a5SMiles Xu, Sun Microsystems QUEUE_PUSH_TAIL(&rx_data->recv_list, 19608057504Sxy150489 &packet->Link); 19708057504Sxy150489 } 19808057504Sxy150489 19925f2d433Sxy150489 for (i = 0; i < Adapter->rx_freelist_num; 20008057504Sxy150489 i++, packet = packet->next) { 20108057504Sxy150489 ASSERT(packet != NULL); 20225f2d433Sxy150489 /* Add this rx_sw_packet to the free list */ 20354e0d7a5SMiles Xu, Sun Microsystems QUEUE_PUSH_TAIL(&rx_data->free_list, 20408057504Sxy150489 &packet->Link); 20508057504Sxy150489 } 20654e0d7a5SMiles Xu, Sun Microsystems rx_data->avail_freepkt = Adapter->rx_freelist_num; 20754e0d7a5SMiles Xu, Sun Microsystems rx_data->recycle_freepkt = 0; 20825f2d433Sxy150489 20925f2d433Sxy150489 Adapter->rx_buffer_setup = B_TRUE; 21008057504Sxy150489 } else { 21108057504Sxy150489 /* Setup the initial pointer to the first rx descriptor */ 21225f2d433Sxy150489 packet = (p_rx_sw_packet_t) 21354e0d7a5SMiles Xu, Sun Microsystems QUEUE_GET_HEAD(&rx_data->recv_list); 21454e0d7a5SMiles Xu, Sun Microsystems descriptor = rx_data->rbd_first; 21508057504Sxy150489 21625f2d433Sxy150489 for (i = 0; i < Adapter->rx_desc_num; i++) { 21708057504Sxy150489 ASSERT(packet != NULL); 21808057504Sxy150489 ASSERT(descriptor != NULL); 21908057504Sxy150489 descriptor->buffer_addr = 22008057504Sxy150489 packet->rx_buf->dma_address; 22125f2d433Sxy150489 22225f2d433Sxy150489 /* Get next rx_sw_packet */ 22325f2d433Sxy150489 packet = (p_rx_sw_packet_t) 22454e0d7a5SMiles Xu, Sun Microsystems QUEUE_GET_NEXT(&rx_data->recv_list, &packet->Link); 22508057504Sxy150489 descriptor++; 22608057504Sxy150489 } 22708057504Sxy150489 } 22808057504Sxy150489 22947b7744cSyy150190 E1000_WRITE_REG(&Adapter->shared, E1000_RDTR, Adapter->rx_intr_delay); 23047b7744cSyy150190 E1000G_DEBUGLOG_1(Adapter, E1000G_INFO_LEVEL, 23147b7744cSyy150190 "E1000_RDTR: 0x%x\n", Adapter->rx_intr_delay); 23247b7744cSyy150190 if (hw->mac.type >= e1000_82540) { 23347b7744cSyy150190 E1000_WRITE_REG(&Adapter->shared, E1000_RADV, 23447b7744cSyy150190 Adapter->rx_intr_abs_delay); 23547b7744cSyy150190 E1000G_DEBUGLOG_1(Adapter, E1000G_INFO_LEVEL, 23647b7744cSyy150190 "E1000_RADV: 0x%x\n", Adapter->rx_intr_abs_delay); 23747b7744cSyy150190 } 23847b7744cSyy150190 23908057504Sxy150489 /* 24008057504Sxy150489 * Setup our descriptor pointers 24108057504Sxy150489 */ 24254e0d7a5SMiles Xu, Sun Microsystems rx_data->rbd_next = rx_data->rbd_first; 24308057504Sxy150489 24425f2d433Sxy150489 size = Adapter->rx_desc_num * sizeof (struct e1000_rx_desc); 245592a4d85Scc210113 E1000_WRITE_REG(hw, E1000_RDLEN(0), size); 246592a4d85Scc210113 size = E1000_READ_REG(hw, E1000_RDLEN(0)); 24708057504Sxy150489 24808057504Sxy150489 /* To get lower order bits */ 24954e0d7a5SMiles Xu, Sun Microsystems buf_low = (uint32_t)rx_data->rbd_dma_addr; 25008057504Sxy150489 /* To get the higher order bits */ 25154e0d7a5SMiles Xu, Sun Microsystems buf_high = (uint32_t)(rx_data->rbd_dma_addr >> 32); 25208057504Sxy150489 253592a4d85Scc210113 E1000_WRITE_REG(hw, E1000_RDBAH(0), buf_high); 254592a4d85Scc210113 E1000_WRITE_REG(hw, E1000_RDBAL(0), buf_low); 25508057504Sxy150489 25608057504Sxy150489 /* 25708057504Sxy150489 * Setup our HW Rx Head & Tail descriptor pointers 25808057504Sxy150489 */ 259592a4d85Scc210113 E1000_WRITE_REG(hw, E1000_RDT(0), 26054e0d7a5SMiles Xu, Sun Microsystems (uint32_t)(rx_data->rbd_last - rx_data->rbd_first)); 261592a4d85Scc210113 E1000_WRITE_REG(hw, E1000_RDH(0), 0); 26208057504Sxy150489 26308057504Sxy150489 /* 26408057504Sxy150489 * Setup the Receive Control Register (RCTL), and ENABLE the 26508057504Sxy150489 * receiver. The initial configuration is to: Enable the receiver, 26608057504Sxy150489 * accept broadcasts, discard bad packets (and long packets), 26708057504Sxy150489 * disable VLAN filter checking, set the receive descriptor 26808057504Sxy150489 * minimum threshold size to 1/2, and the receive buffer size to 26908057504Sxy150489 * 2k. 27008057504Sxy150489 */ 2714d737963Sxiangtao you - Sun Microsystems - Beijing China rctl = E1000_RCTL_EN | /* Enable Receive Unit */ 27208057504Sxy150489 E1000_RCTL_BAM | /* Accept Broadcast Packets */ 27325f2d433Sxy150489 (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT) | 27408057504Sxy150489 E1000_RCTL_RDMTS_HALF | 27508057504Sxy150489 E1000_RCTL_LBM_NO; /* Loopback Mode = none */ 27608057504Sxy150489 2773fb4efefSchangqing li - Sun Microsystems - Beijing China if (Adapter->default_mtu > ETHERMTU) 2783fb4efefSchangqing li - Sun Microsystems - Beijing China rctl |= E1000_RCTL_LPE; /* Large Packet Enable bit */ 2793fb4efefSchangqing li - Sun Microsystems - Beijing China 2805633182fSyy150190 if (Adapter->strip_crc) 2814d737963Sxiangtao you - Sun Microsystems - Beijing China rctl |= E1000_RCTL_SECRC; /* Strip Ethernet CRC */ 2825633182fSyy150190 2833d15c084Schenlu chen - Sun Microsystems - Beijing China if (Adapter->mem_workaround_82546 && 2843d15c084Schenlu chen - Sun Microsystems - Beijing China ((hw->mac.type == e1000_82545) || 285ede5269eSchenlu chen - Sun Microsystems - Beijing China (hw->mac.type == e1000_82546) || 2863d15c084Schenlu chen - Sun Microsystems - Beijing China (hw->mac.type == e1000_82546_rev_3))) { 287ede5269eSchenlu chen - Sun Microsystems - Beijing China rctl |= E1000_RCTL_SZ_2048; 288ede5269eSchenlu chen - Sun Microsystems - Beijing China } else { 289592a4d85Scc210113 if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_2K) && 290592a4d85Scc210113 (Adapter->max_frame_size <= FRAME_SIZE_UPTO_4K)) 2914d737963Sxiangtao you - Sun Microsystems - Beijing China rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX; 292592a4d85Scc210113 else if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_4K) && 293592a4d85Scc210113 (Adapter->max_frame_size <= FRAME_SIZE_UPTO_8K)) 2944d737963Sxiangtao you - Sun Microsystems - Beijing China rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX; 295592a4d85Scc210113 else if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_8K) && 296592a4d85Scc210113 (Adapter->max_frame_size <= FRAME_SIZE_UPTO_16K)) 2974d737963Sxiangtao you - Sun Microsystems - Beijing China rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX; 2989ce7e93cScc210113 else 2994d737963Sxiangtao you - Sun Microsystems - Beijing China rctl |= E1000_RCTL_SZ_2048; 300ede5269eSchenlu chen - Sun Microsystems - Beijing China } 30108057504Sxy150489 30225f2d433Sxy150489 if (e1000_tbi_sbp_enabled_82543(hw)) 3034d737963Sxiangtao you - Sun Microsystems - Beijing China rctl |= E1000_RCTL_SBP; 30408057504Sxy150489 30525f2d433Sxy150489 /* 306d5c3073dSchenlu chen - Sun Microsystems - Beijing China * Enable Early Receive Threshold (ERT) on supported devices. 307d5c3073dSchenlu chen - Sun Microsystems - Beijing China * Only takes effect when packet size is equal or larger than the 308d5c3073dSchenlu chen - Sun Microsystems - Beijing China * specified value (in 8 byte units), e.g. using jumbo frames. 30925f2d433Sxy150489 */ 3104d737963Sxiangtao you - Sun Microsystems - Beijing China if ((hw->mac.type == e1000_82573) || 3114d737963Sxiangtao you - Sun Microsystems - Beijing China (hw->mac.type == e1000_82574) || 3124d737963Sxiangtao you - Sun Microsystems - Beijing China (hw->mac.type == e1000_ich9lan) || 3134d737963Sxiangtao you - Sun Microsystems - Beijing China (hw->mac.type == e1000_ich10lan)) { 31425f2d433Sxy150489 3154d737963Sxiangtao you - Sun Microsystems - Beijing China ert = E1000_ERT_2048; 3164d737963Sxiangtao you - Sun Microsystems - Beijing China 3174d737963Sxiangtao you - Sun Microsystems - Beijing China /* 3184d737963Sxiangtao you - Sun Microsystems - Beijing China * Special modification when ERT and 3194d737963Sxiangtao you - Sun Microsystems - Beijing China * jumbo frames are enabled 3204d737963Sxiangtao you - Sun Microsystems - Beijing China */ 3214d737963Sxiangtao you - Sun Microsystems - Beijing China if (Adapter->default_mtu > ETHERMTU) { 3224d737963Sxiangtao you - Sun Microsystems - Beijing China rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(0)); 3234d737963Sxiangtao you - Sun Microsystems - Beijing China E1000_WRITE_REG(hw, E1000_RXDCTL(0), rxdctl | 0x3); 3244d737963Sxiangtao you - Sun Microsystems - Beijing China ert |= (1 << 13); 3254d737963Sxiangtao you - Sun Microsystems - Beijing China } 3264d737963Sxiangtao you - Sun Microsystems - Beijing China 3274d737963Sxiangtao you - Sun Microsystems - Beijing China E1000_WRITE_REG(hw, E1000_ERT, ert); 3284d737963Sxiangtao you - Sun Microsystems - Beijing China } 32908057504Sxy150489 330caf05df5SMiles Xu, Sun Microsystems /* Workaround errata on 82577/8 adapters with large frames */ 331caf05df5SMiles Xu, Sun Microsystems if ((hw->mac.type == e1000_pchlan) && 332caf05df5SMiles Xu, Sun Microsystems (Adapter->default_mtu > ETHERMTU)) { 333caf05df5SMiles Xu, Sun Microsystems 33457ef6f69Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000_read_phy_reg(hw, PHY_REG(770, 26), &phy_data); 335caf05df5SMiles Xu, Sun Microsystems phy_data &= 0xfff8; 336caf05df5SMiles Xu, Sun Microsystems phy_data |= (1 << 2); 33757ef6f69Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000_write_phy_reg(hw, PHY_REG(770, 26), phy_data); 338caf05df5SMiles Xu, Sun Microsystems 339caf05df5SMiles Xu, Sun Microsystems if (hw->phy.type == e1000_phy_82577) { 34057ef6f69Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000_read_phy_reg(hw, 22, &phy_data); 341caf05df5SMiles Xu, Sun Microsystems phy_data &= 0x0fff; 342caf05df5SMiles Xu, Sun Microsystems phy_data |= (1 << 14); 34357ef6f69Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000_write_phy_reg(hw, 0x10, 0x2823); 34457ef6f69Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000_write_phy_reg(hw, 0x11, 0x0003); 34557ef6f69Sguoqing zhu - Sun Microsystems - Beijing China (void) e1000_write_phy_reg(hw, 22, phy_data); 346caf05df5SMiles Xu, Sun Microsystems } 347caf05df5SMiles Xu, Sun Microsystems } 348caf05df5SMiles Xu, Sun Microsystems 349dab7de2dSGarrett D'Amore /* Workaround errata on 82579 adapters with large frames */ 350dab7de2dSGarrett D'Amore if (hw->mac.type == e1000_pch2lan) { 351dab7de2dSGarrett D'Amore boolean_t enable_jumbo = (Adapter->default_mtu > ETHERMTU ? 352dab7de2dSGarrett D'Amore B_TRUE : B_FALSE); 353dab7de2dSGarrett D'Amore 354dab7de2dSGarrett D'Amore if (e1000_lv_jumbo_workaround_ich8lan(hw, enable_jumbo) != 0) 355dab7de2dSGarrett D'Amore E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL, 356dab7de2dSGarrett D'Amore "failed to enable jumbo frame workaround mode\n"); 357dab7de2dSGarrett D'Amore } 358dab7de2dSGarrett D'Amore 35908057504Sxy150489 reg_val = 36008057504Sxy150489 E1000_RXCSUM_TUOFL | /* TCP/UDP checksum offload Enable */ 36108057504Sxy150489 E1000_RXCSUM_IPOFL; /* IP checksum offload Enable */ 36208057504Sxy150489 36325f2d433Sxy150489 E1000_WRITE_REG(hw, E1000_RXCSUM, reg_val); 3648ede663fSzx151633 3658ede663fSzx151633 /* 3668ede663fSzx151633 * Workaround: Set bit 16 (IPv6_ExDIS) to disable the 3678ede663fSzx151633 * processing of received IPV6 extension headers 3688ede663fSzx151633 */ 3698ede663fSzx151633 if ((hw->mac.type == e1000_82571) || (hw->mac.type == e1000_82572)) { 3708ede663fSzx151633 reg_val = E1000_READ_REG(hw, E1000_RFCTL); 3718ede663fSzx151633 reg_val |= (E1000_RFCTL_IPV6_EX_DIS | 3728ede663fSzx151633 E1000_RFCTL_NEW_IPV6_EXT_DIS); 3738ede663fSzx151633 E1000_WRITE_REG(hw, E1000_RFCTL, reg_val); 3748ede663fSzx151633 } 3754d737963Sxiangtao you - Sun Microsystems - Beijing China 3764d737963Sxiangtao you - Sun Microsystems - Beijing China /* Write to enable the receive unit */ 3774d737963Sxiangtao you - Sun Microsystems - Beijing China E1000_WRITE_REG(hw, E1000_RCTL, rctl); 37808057504Sxy150489 } 37908057504Sxy150489 38008057504Sxy150489 /* 38125f2d433Sxy150489 * e1000g_get_buf - get an rx sw packet from the free_list 38208057504Sxy150489 */ 38325f2d433Sxy150489 static p_rx_sw_packet_t 38454e0d7a5SMiles Xu, Sun Microsystems e1000g_get_buf(e1000g_rx_data_t *rx_data) 38508057504Sxy150489 { 38625f2d433Sxy150489 p_rx_sw_packet_t packet; 3873fb4efefSchangqing li - Sun Microsystems - Beijing China struct e1000g *Adapter; 3883fb4efefSchangqing li - Sun Microsystems - Beijing China 3893fb4efefSchangqing li - Sun Microsystems - Beijing China Adapter = rx_data->rx_ring->adapter; 39008057504Sxy150489 39154e0d7a5SMiles Xu, Sun Microsystems mutex_enter(&rx_data->freelist_lock); 39225f2d433Sxy150489 packet = (p_rx_sw_packet_t) 39354e0d7a5SMiles Xu, Sun Microsystems QUEUE_POP_HEAD(&rx_data->free_list); 394da14cebeSEric Cheng if (packet != NULL) { 39554e0d7a5SMiles Xu, Sun Microsystems rx_data->avail_freepkt--; 3963fb4efefSchangqing li - Sun Microsystems - Beijing China goto end; 3973fb4efefSchangqing li - Sun Microsystems - Beijing China } 3983fb4efefSchangqing li - Sun Microsystems - Beijing China 399da14cebeSEric Cheng /* 400da14cebeSEric Cheng * If the freelist has no packets, check the recycle list 401da14cebeSEric Cheng * to see if there are any available descriptor there. 402da14cebeSEric Cheng */ 40354e0d7a5SMiles Xu, Sun Microsystems mutex_enter(&rx_data->recycle_lock); 40454e0d7a5SMiles Xu, Sun Microsystems QUEUE_SWITCH(&rx_data->free_list, &rx_data->recycle_list); 40554e0d7a5SMiles Xu, Sun Microsystems rx_data->avail_freepkt = rx_data->recycle_freepkt; 40654e0d7a5SMiles Xu, Sun Microsystems rx_data->recycle_freepkt = 0; 40754e0d7a5SMiles Xu, Sun Microsystems mutex_exit(&rx_data->recycle_lock); 4083fb4efefSchangqing li - Sun Microsystems - Beijing China packet = (p_rx_sw_packet_t)QUEUE_POP_HEAD(&rx_data->free_list); 4093fb4efefSchangqing li - Sun Microsystems - Beijing China if (packet != NULL) { 4103fb4efefSchangqing li - Sun Microsystems - Beijing China rx_data->avail_freepkt--; 4113fb4efefSchangqing li - Sun Microsystems - Beijing China goto end; 4123fb4efefSchangqing li - Sun Microsystems - Beijing China } 4133fb4efefSchangqing li - Sun Microsystems - Beijing China 4143fb4efefSchangqing li - Sun Microsystems - Beijing China if (Adapter->rx_freelist_num < Adapter->rx_freelist_limit) { 4153fb4efefSchangqing li - Sun Microsystems - Beijing China (void) e1000g_increase_rx_packets(rx_data); 416da14cebeSEric Cheng packet = (p_rx_sw_packet_t) 41754e0d7a5SMiles Xu, Sun Microsystems QUEUE_POP_HEAD(&rx_data->free_list); 4183fb4efefSchangqing li - Sun Microsystems - Beijing China if (packet != NULL) { 41954e0d7a5SMiles Xu, Sun Microsystems rx_data->avail_freepkt--; 420da14cebeSEric Cheng } 4213fb4efefSchangqing li - Sun Microsystems - Beijing China } 42208057504Sxy150489 4233fb4efefSchangqing li - Sun Microsystems - Beijing China end: 4243fb4efefSchangqing li - Sun Microsystems - Beijing China mutex_exit(&rx_data->freelist_lock); 42508057504Sxy150489 return (packet); 42608057504Sxy150489 } 42708057504Sxy150489 42808057504Sxy150489 /* 42925f2d433Sxy150489 * e1000g_receive - main receive routine 43025f2d433Sxy150489 * 43125f2d433Sxy150489 * This routine will process packets received in an interrupt 43208057504Sxy150489 */ 43308057504Sxy150489 mblk_t * 434ae6aa22aSVenugopal Iyer e1000g_receive(e1000g_rx_ring_t *rx_ring, mblk_t **tail, uint_t sz) 43508057504Sxy150489 { 43625f2d433Sxy150489 struct e1000_hw *hw; 43708057504Sxy150489 mblk_t *nmp; 43808057504Sxy150489 mblk_t *ret_mp; 43908057504Sxy150489 mblk_t *ret_nmp; 44008057504Sxy150489 struct e1000_rx_desc *current_desc; 44108057504Sxy150489 struct e1000_rx_desc *last_desc; 44225f2d433Sxy150489 p_rx_sw_packet_t packet; 44325f2d433Sxy150489 p_rx_sw_packet_t newpkt; 4444d737963Sxiangtao you - Sun Microsystems - Beijing China uint16_t length; 44508057504Sxy150489 uint32_t pkt_count; 44608057504Sxy150489 uint32_t desc_count; 44725f2d433Sxy150489 boolean_t accept_frame; 44808057504Sxy150489 boolean_t end_of_packet; 44908057504Sxy150489 boolean_t need_copy; 450da14cebeSEric Cheng struct e1000g *Adapter; 45108057504Sxy150489 dma_buffer_t *rx_buf; 45208057504Sxy150489 uint16_t cksumflags; 453ae6aa22aSVenugopal Iyer uint_t chain_sz = 0; 45454e0d7a5SMiles Xu, Sun Microsystems e1000g_rx_data_t *rx_data; 45546ebaa55SMiles Xu, Sun Microsystems uint32_t max_size; 45646ebaa55SMiles Xu, Sun Microsystems uint32_t min_size; 45708057504Sxy150489 45808057504Sxy150489 ret_mp = NULL; 45908057504Sxy150489 ret_nmp = NULL; 46008057504Sxy150489 pkt_count = 0; 46108057504Sxy150489 desc_count = 0; 46208057504Sxy150489 cksumflags = 0; 46308057504Sxy150489 464da14cebeSEric Cheng Adapter = rx_ring->adapter; 46554e0d7a5SMiles Xu, Sun Microsystems rx_data = rx_ring->rx_data; 46625f2d433Sxy150489 hw = &Adapter->shared; 46708057504Sxy150489 46808057504Sxy150489 /* Sync the Rx descriptor DMA buffers */ 46954e0d7a5SMiles Xu, Sun Microsystems (void) ddi_dma_sync(rx_data->rbd_dma_handle, 47025f2d433Sxy150489 0, 0, DDI_DMA_SYNC_FORKERNEL); 47108057504Sxy150489 47254e0d7a5SMiles Xu, Sun Microsystems if (e1000g_check_dma_handle(rx_data->rbd_dma_handle) != DDI_FM_OK) { 4739b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 474d5c3073dSchenlu chen - Sun Microsystems - Beijing China Adapter->e1000g_state |= E1000G_ERROR; 475ec39b9cfSchangqing li - Sun Microsystems - Beijing China return (NULL); 4769b6541b3Sgl147354 } 4779b6541b3Sgl147354 47854e0d7a5SMiles Xu, Sun Microsystems current_desc = rx_data->rbd_next; 47908057504Sxy150489 if (!(current_desc->status & E1000_RXD_STAT_DD)) { 48008057504Sxy150489 /* 48108057504Sxy150489 * don't send anything up. just clear the RFD 48208057504Sxy150489 */ 48325f2d433Sxy150489 E1000G_DEBUG_STAT(rx_ring->stat_none); 484ec39b9cfSchangqing li - Sun Microsystems - Beijing China return (NULL); 48508057504Sxy150489 } 48608057504Sxy150489 48746ebaa55SMiles Xu, Sun Microsystems max_size = Adapter->max_frame_size - ETHERFCSL - VLAN_TAGSZ; 48846ebaa55SMiles Xu, Sun Microsystems min_size = ETHERMIN; 48946ebaa55SMiles Xu, Sun Microsystems 49008057504Sxy150489 /* 49108057504Sxy150489 * Loop through the receive descriptors starting at the last known 49208057504Sxy150489 * descriptor owned by the hardware that begins a packet. 49308057504Sxy150489 */ 49408057504Sxy150489 while ((current_desc->status & E1000_RXD_STAT_DD) && 495ae6aa22aSVenugopal Iyer (pkt_count < Adapter->rx_limit_onintr) && 496ae6aa22aSVenugopal Iyer ((sz == E1000G_CHAIN_NO_LIMIT) || (chain_sz <= sz))) { 49708057504Sxy150489 49808057504Sxy150489 desc_count++; 49908057504Sxy150489 /* 50008057504Sxy150489 * Now this can happen in Jumbo frame situation. 50108057504Sxy150489 */ 50208057504Sxy150489 if (current_desc->status & E1000_RXD_STAT_EOP) { 50308057504Sxy150489 /* packet has EOP set */ 50408057504Sxy150489 end_of_packet = B_TRUE; 50508057504Sxy150489 } else { 50608057504Sxy150489 /* 50708057504Sxy150489 * If this received buffer does not have the 50808057504Sxy150489 * End-Of-Packet bit set, the received packet 50908057504Sxy150489 * will consume multiple buffers. We won't send this 51008057504Sxy150489 * packet upstack till we get all the related buffers. 51108057504Sxy150489 */ 51208057504Sxy150489 end_of_packet = B_FALSE; 51308057504Sxy150489 } 51408057504Sxy150489 51508057504Sxy150489 /* 51608057504Sxy150489 * Get a pointer to the actual receive buffer 51708057504Sxy150489 * The mp->b_rptr is mapped to The CurrentDescriptor 51808057504Sxy150489 * Buffer Address. 51908057504Sxy150489 */ 52008057504Sxy150489 packet = 52196ea4e93Schangqing li - Sun Microsystems - Beijing China (p_rx_sw_packet_t)QUEUE_POP_HEAD(&rx_data->recv_list); 52208057504Sxy150489 ASSERT(packet != NULL); 52308057504Sxy150489 52408057504Sxy150489 rx_buf = packet->rx_buf; 52508057504Sxy150489 52608057504Sxy150489 length = current_desc->length; 52708057504Sxy150489 52808057504Sxy150489 #ifdef __sparc 52925f2d433Sxy150489 if (packet->dma_type == USE_DVMA) 53008057504Sxy150489 dvma_sync(rx_buf->dma_handle, 0, 53108057504Sxy150489 DDI_DMA_SYNC_FORKERNEL); 53225f2d433Sxy150489 else 53308057504Sxy150489 (void) ddi_dma_sync(rx_buf->dma_handle, 53408057504Sxy150489 E1000G_IPALIGNROOM, length, 53525f2d433Sxy150489 DDI_DMA_SYNC_FORKERNEL); 53625f2d433Sxy150489 #else 53725f2d433Sxy150489 (void) ddi_dma_sync(rx_buf->dma_handle, 53825f2d433Sxy150489 E1000G_IPALIGNROOM, length, 53925f2d433Sxy150489 DDI_DMA_SYNC_FORKERNEL); 54025f2d433Sxy150489 #endif 54108057504Sxy150489 5429b6541b3Sgl147354 if (e1000g_check_dma_handle( 5439b6541b3Sgl147354 rx_buf->dma_handle) != DDI_FM_OK) { 5449b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, 5459b6541b3Sgl147354 DDI_SERVICE_DEGRADED); 546d5c3073dSchenlu chen - Sun Microsystems - Beijing China Adapter->e1000g_state |= E1000G_ERROR; 547ec39b9cfSchangqing li - Sun Microsystems - Beijing China 548ec39b9cfSchangqing li - Sun Microsystems - Beijing China goto rx_drop; 5499b6541b3Sgl147354 } 5509b6541b3Sgl147354 55164bad572SArne Jansen /* 55264bad572SArne Jansen * workaround for redmine #3100. After a switch reset packet 55364bad572SArne Jansen * queue and descriptor dma addresses got out of sync. Detect 55464bad572SArne Jansen * this and flag the error. Let the watchdog timer do the reset 55564bad572SArne Jansen */ 55664bad572SArne Jansen if (current_desc->buffer_addr != rx_buf->dma_address) { 55764bad572SArne Jansen e1000g_log(Adapter, CE_WARN, "receive dma descriptors " 55864bad572SArne Jansen "got out of sync, resetting adapter"); 55964bad572SArne Jansen Adapter->e1000g_state |= E1000G_ERROR; 56064bad572SArne Jansen } 56125f2d433Sxy150489 accept_frame = (current_desc->errors == 0) || 56225f2d433Sxy150489 ((current_desc->errors & 56325f2d433Sxy150489 (E1000_RXD_ERR_TCPE | E1000_RXD_ERR_IPE)) != 0); 56425f2d433Sxy150489 56525f2d433Sxy150489 if (hw->mac.type == e1000_82543) { 56625f2d433Sxy150489 unsigned char last_byte; 56725f2d433Sxy150489 56825f2d433Sxy150489 last_byte = 56908057504Sxy150489 *((unsigned char *)rx_buf->address + length - 1); 57008057504Sxy150489 57125f2d433Sxy150489 if (TBI_ACCEPT(hw, 57225f2d433Sxy150489 current_desc->status, current_desc->errors, 573592a4d85Scc210113 current_desc->length, last_byte, 574592a4d85Scc210113 Adapter->min_frame_size, Adapter->max_frame_size)) { 57508057504Sxy150489 57625f2d433Sxy150489 e1000_tbi_adjust_stats(Adapter, 57725f2d433Sxy150489 length, hw->mac.addr); 57825f2d433Sxy150489 57908057504Sxy150489 length--; 58025f2d433Sxy150489 accept_frame = B_TRUE; 58125f2d433Sxy150489 } else if (e1000_tbi_sbp_enabled_82543(hw) && 58225f2d433Sxy150489 (current_desc->errors == E1000_RXD_ERR_CE)) { 58325f2d433Sxy150489 accept_frame = B_TRUE; 58408057504Sxy150489 } 58525f2d433Sxy150489 } 58625f2d433Sxy150489 58708057504Sxy150489 /* 58808057504Sxy150489 * Indicate the packet to the NOS if it was good. 58908057504Sxy150489 * Normally, hardware will discard bad packets for us. 59008057504Sxy150489 * Check for the packet to be a valid Ethernet packet 59108057504Sxy150489 */ 59225f2d433Sxy150489 if (!accept_frame) { 59308057504Sxy150489 /* 59408057504Sxy150489 * error in incoming packet, either the packet is not a 59508057504Sxy150489 * ethernet size packet, or the packet has an error. In 59608057504Sxy150489 * either case, the packet will simply be discarded. 59708057504Sxy150489 */ 59825f2d433Sxy150489 E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL, 59908057504Sxy150489 "Process Receive Interrupts: Error in Packet\n"); 60008057504Sxy150489 60125f2d433Sxy150489 E1000G_STAT(rx_ring->stat_error); 60208057504Sxy150489 /* 60308057504Sxy150489 * Returning here as we are done here. There is 60408057504Sxy150489 * no point in waiting for while loop to elapse 60508057504Sxy150489 * and the things which were done. More efficient 60608057504Sxy150489 * and less error prone... 60708057504Sxy150489 */ 60808057504Sxy150489 goto rx_drop; 60908057504Sxy150489 } 61008057504Sxy150489 6115633182fSyy150190 /* 6125633182fSyy150190 * If the Ethernet CRC is not stripped by the hardware, 6135633182fSyy150190 * we need to strip it before sending it up to the stack. 6145633182fSyy150190 */ 6155633182fSyy150190 if (end_of_packet && !Adapter->strip_crc) { 6169ce7e93cScc210113 if (length > ETHERFCSL) { 6179ce7e93cScc210113 length -= ETHERFCSL; 6185633182fSyy150190 } else { 6195633182fSyy150190 /* 6205633182fSyy150190 * If the fragment is smaller than the CRC, 6215633182fSyy150190 * drop this fragment, do the processing of 6225633182fSyy150190 * the end of the packet. 6235633182fSyy150190 */ 6243fb4efefSchangqing li - Sun Microsystems - Beijing China if (rx_data->rx_mblk_tail == NULL) { 6253fb4efefSchangqing li - Sun Microsystems - Beijing China E1000G_STAT(rx_ring->stat_crc_only_pkt); 6263fb4efefSchangqing li - Sun Microsystems - Beijing China goto rx_next_desc; 6273fb4efefSchangqing li - Sun Microsystems - Beijing China } 6283fb4efefSchangqing li - Sun Microsystems - Beijing China 62954e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk_tail->b_wptr -= 6309ce7e93cScc210113 ETHERFCSL - length; 63154e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk_len -= 6329ce7e93cScc210113 ETHERFCSL - length; 6335633182fSyy150190 goto rx_end_of_packet; 6345633182fSyy150190 } 6355633182fSyy150190 } 6365633182fSyy150190 63708057504Sxy150489 need_copy = B_TRUE; 63808057504Sxy150489 63908057504Sxy150489 if (length <= Adapter->rx_bcopy_thresh) 64008057504Sxy150489 goto rx_copy; 64108057504Sxy150489 64208057504Sxy150489 /* 64308057504Sxy150489 * Get the pre-constructed mblk that was associated 64408057504Sxy150489 * to the receive data buffer. 64508057504Sxy150489 */ 64608057504Sxy150489 if (packet->mp == NULL) { 64708057504Sxy150489 packet->mp = desballoc((unsigned char *) 64846ebaa55SMiles Xu, Sun Microsystems rx_buf->address, length, 64908057504Sxy150489 BPRI_MED, &packet->free_rtn); 65008057504Sxy150489 } 65108057504Sxy150489 65208057504Sxy150489 if (packet->mp != NULL) { 65308057504Sxy150489 /* 65408057504Sxy150489 * We have two sets of buffer pool. One associated with 65508057504Sxy150489 * the Rxdescriptors and other a freelist buffer pool. 65608057504Sxy150489 * Each time we get a good packet, Try to get a buffer 65708057504Sxy150489 * from the freelist pool using e1000g_get_buf. If we 65808057504Sxy150489 * get free buffer, then replace the descriptor buffer 65908057504Sxy150489 * address with the free buffer we just got, and pass 66008057504Sxy150489 * the pre-constructed mblk upstack. (note no copying) 66108057504Sxy150489 * 66208057504Sxy150489 * If we failed to get a free buffer, then try to 66308057504Sxy150489 * allocate a new buffer(mp) and copy the recv buffer 66408057504Sxy150489 * content to our newly allocated buffer(mp). Don't 66508057504Sxy150489 * disturb the desriptor buffer address. (note copying) 66608057504Sxy150489 */ 66754e0d7a5SMiles Xu, Sun Microsystems newpkt = e1000g_get_buf(rx_data); 66808057504Sxy150489 66908057504Sxy150489 if (newpkt != NULL) { 67008057504Sxy150489 /* 67108057504Sxy150489 * Get the mblk associated to the data, 67208057504Sxy150489 * and strip it off the sw packet. 67308057504Sxy150489 */ 67408057504Sxy150489 nmp = packet->mp; 67508057504Sxy150489 packet->mp = NULL; 67654e0d7a5SMiles Xu, Sun Microsystems atomic_inc_32(&packet->ref_cnt); 67708057504Sxy150489 67808057504Sxy150489 /* 67908057504Sxy150489 * Now replace old buffer with the new 68008057504Sxy150489 * one we got from free list 68108057504Sxy150489 * Both the RxSwPacket as well as the 68208057504Sxy150489 * Receive Buffer Descriptor will now 68308057504Sxy150489 * point to this new packet. 68408057504Sxy150489 */ 68508057504Sxy150489 packet = newpkt; 68625f2d433Sxy150489 68708057504Sxy150489 current_desc->buffer_addr = 68808057504Sxy150489 newpkt->rx_buf->dma_address; 68925f2d433Sxy150489 69008057504Sxy150489 need_copy = B_FALSE; 69108057504Sxy150489 } else { 69257ef6f69Sguoqing zhu - Sun Microsystems - Beijing China /* EMPTY */ 69325f2d433Sxy150489 E1000G_DEBUG_STAT(rx_ring->stat_no_freepkt); 69408057504Sxy150489 } 69508057504Sxy150489 } 69608057504Sxy150489 69708057504Sxy150489 rx_copy: 69808057504Sxy150489 if (need_copy) { 69908057504Sxy150489 /* 70008057504Sxy150489 * No buffers available on free list, 70108057504Sxy150489 * bcopy the data from the buffer and 70208057504Sxy150489 * keep the original buffer. Dont want to 70308057504Sxy150489 * do this.. Yack but no other way 70408057504Sxy150489 */ 70525f2d433Sxy150489 if ((nmp = allocb(length + E1000G_IPALIGNROOM, 70608057504Sxy150489 BPRI_MED)) == NULL) { 70708057504Sxy150489 /* 70808057504Sxy150489 * The system has no buffers available 70908057504Sxy150489 * to send up the incoming packet, hence 71008057504Sxy150489 * the packet will have to be processed 71108057504Sxy150489 * when there're more buffers available. 71208057504Sxy150489 */ 71325f2d433Sxy150489 E1000G_STAT(rx_ring->stat_allocb_fail); 71408057504Sxy150489 goto rx_drop; 71508057504Sxy150489 } 71608057504Sxy150489 nmp->b_rptr += E1000G_IPALIGNROOM; 71708057504Sxy150489 nmp->b_wptr += E1000G_IPALIGNROOM; 71808057504Sxy150489 /* 71908057504Sxy150489 * The free list did not have any buffers 72008057504Sxy150489 * available, so, the received packet will 72108057504Sxy150489 * have to be copied into a mp and the original 72208057504Sxy150489 * buffer will have to be retained for future 72308057504Sxy150489 * packet reception. 72408057504Sxy150489 */ 72525f2d433Sxy150489 bcopy(rx_buf->address, nmp->b_wptr, length); 72608057504Sxy150489 } 72708057504Sxy150489 72808057504Sxy150489 ASSERT(nmp != NULL); 72908057504Sxy150489 nmp->b_wptr += length; 73008057504Sxy150489 73154e0d7a5SMiles Xu, Sun Microsystems if (rx_data->rx_mblk == NULL) { 73208057504Sxy150489 /* 73308057504Sxy150489 * TCP/UDP checksum offload and 73408057504Sxy150489 * IP checksum offload 73508057504Sxy150489 */ 73625f2d433Sxy150489 if (!(current_desc->status & E1000_RXD_STAT_IXSM)) { 73708057504Sxy150489 /* 73808057504Sxy150489 * Check TCP/UDP checksum 73908057504Sxy150489 */ 74008057504Sxy150489 if ((current_desc->status & 74108057504Sxy150489 E1000_RXD_STAT_TCPCS) && 74208057504Sxy150489 !(current_desc->errors & 74308057504Sxy150489 E1000_RXD_ERR_TCPE)) 7440dc2366fSVenugopal Iyer cksumflags |= HCK_FULLCKSUM_OK; 74508057504Sxy150489 /* 74608057504Sxy150489 * Check IP Checksum 74708057504Sxy150489 */ 74808057504Sxy150489 if ((current_desc->status & 74908057504Sxy150489 E1000_RXD_STAT_IPCS) && 75008057504Sxy150489 !(current_desc->errors & 75108057504Sxy150489 E1000_RXD_ERR_IPE)) 7520dc2366fSVenugopal Iyer cksumflags |= HCK_IPV4_HDRCKSUM_OK; 75308057504Sxy150489 } 75408057504Sxy150489 } 75508057504Sxy150489 75608057504Sxy150489 /* 75708057504Sxy150489 * We need to maintain our packet chain in the global 75808057504Sxy150489 * Adapter structure, for the Rx processing can end 75908057504Sxy150489 * with a fragment that has no EOP set. 76008057504Sxy150489 */ 76154e0d7a5SMiles Xu, Sun Microsystems if (rx_data->rx_mblk == NULL) { 76208057504Sxy150489 /* Get the head of the message chain */ 76354e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk = nmp; 76454e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk_tail = nmp; 76554e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk_len = length; 76608057504Sxy150489 } else { /* Not the first packet */ 76708057504Sxy150489 /* Continue adding buffers */ 76854e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk_tail->b_cont = nmp; 76954e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk_tail = nmp; 77054e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk_len += length; 77108057504Sxy150489 } 77254e0d7a5SMiles Xu, Sun Microsystems ASSERT(rx_data->rx_mblk != NULL); 77354e0d7a5SMiles Xu, Sun Microsystems ASSERT(rx_data->rx_mblk_tail != NULL); 77454e0d7a5SMiles Xu, Sun Microsystems ASSERT(rx_data->rx_mblk_tail->b_cont == NULL); 77508057504Sxy150489 77608057504Sxy150489 /* 77708057504Sxy150489 * Now this MP is ready to travel upwards but some more 77808057504Sxy150489 * fragments are coming. 77908057504Sxy150489 * We will send packet upwards as soon as we get EOP 78008057504Sxy150489 * set on the packet. 78108057504Sxy150489 */ 78208057504Sxy150489 if (!end_of_packet) { 78308057504Sxy150489 /* 78408057504Sxy150489 * continue to get the next descriptor, 78508057504Sxy150489 * Tail would be advanced at the end 78608057504Sxy150489 */ 78708057504Sxy150489 goto rx_next_desc; 78808057504Sxy150489 } 78908057504Sxy150489 7905633182fSyy150190 rx_end_of_packet: 79146ebaa55SMiles Xu, Sun Microsystems if (E1000G_IS_VLAN_PACKET(rx_data->rx_mblk->b_rptr)) 79246ebaa55SMiles Xu, Sun Microsystems max_size = Adapter->max_frame_size - ETHERFCSL; 79346ebaa55SMiles Xu, Sun Microsystems 79446ebaa55SMiles Xu, Sun Microsystems if ((rx_data->rx_mblk_len > max_size) || 79546ebaa55SMiles Xu, Sun Microsystems (rx_data->rx_mblk_len < min_size)) { 79646ebaa55SMiles Xu, Sun Microsystems E1000G_STAT(rx_ring->stat_size_error); 79746ebaa55SMiles Xu, Sun Microsystems goto rx_drop; 79846ebaa55SMiles Xu, Sun Microsystems } 79946ebaa55SMiles Xu, Sun Microsystems 80008057504Sxy150489 /* 80108057504Sxy150489 * Found packet with EOP 80208057504Sxy150489 * Process the last fragment. 80308057504Sxy150489 */ 80408057504Sxy150489 if (cksumflags != 0) { 8050dc2366fSVenugopal Iyer mac_hcksum_set(rx_data->rx_mblk, 8060dc2366fSVenugopal Iyer 0, 0, 0, 0, cksumflags); 80708057504Sxy150489 cksumflags = 0; 80808057504Sxy150489 } 80908057504Sxy150489 81008057504Sxy150489 /* 81108057504Sxy150489 * Count packets that span multi-descriptors 81208057504Sxy150489 */ 81325f2d433Sxy150489 E1000G_DEBUG_STAT_COND(rx_ring->stat_multi_desc, 81454e0d7a5SMiles Xu, Sun Microsystems (rx_data->rx_mblk->b_cont != NULL)); 81508057504Sxy150489 81608057504Sxy150489 /* 81708057504Sxy150489 * Append to list to send upstream 81808057504Sxy150489 */ 81908057504Sxy150489 if (ret_mp == NULL) { 82054e0d7a5SMiles Xu, Sun Microsystems ret_mp = ret_nmp = rx_data->rx_mblk; 82108057504Sxy150489 } else { 82254e0d7a5SMiles Xu, Sun Microsystems ret_nmp->b_next = rx_data->rx_mblk; 82354e0d7a5SMiles Xu, Sun Microsystems ret_nmp = rx_data->rx_mblk; 82408057504Sxy150489 } 82508057504Sxy150489 ret_nmp->b_next = NULL; 826da14cebeSEric Cheng *tail = ret_nmp; 827ae6aa22aSVenugopal Iyer chain_sz += length; 82808057504Sxy150489 82954e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk = NULL; 83054e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk_tail = NULL; 83154e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk_len = 0; 83208057504Sxy150489 83308057504Sxy150489 pkt_count++; 83408057504Sxy150489 83508057504Sxy150489 rx_next_desc: 83608057504Sxy150489 /* 83708057504Sxy150489 * Zero out the receive descriptors status 83808057504Sxy150489 */ 83908057504Sxy150489 current_desc->status = 0; 84008057504Sxy150489 84154e0d7a5SMiles Xu, Sun Microsystems if (current_desc == rx_data->rbd_last) 84254e0d7a5SMiles Xu, Sun Microsystems rx_data->rbd_next = rx_data->rbd_first; 84308057504Sxy150489 else 84454e0d7a5SMiles Xu, Sun Microsystems rx_data->rbd_next++; 84508057504Sxy150489 84608057504Sxy150489 last_desc = current_desc; 84754e0d7a5SMiles Xu, Sun Microsystems current_desc = rx_data->rbd_next; 84808057504Sxy150489 84908057504Sxy150489 /* 85008057504Sxy150489 * Put the buffer that we just indicated back 85108057504Sxy150489 * at the end of our list 85208057504Sxy150489 */ 85354e0d7a5SMiles Xu, Sun Microsystems QUEUE_PUSH_TAIL(&rx_data->recv_list, 85408057504Sxy150489 &packet->Link); 85508057504Sxy150489 } /* while loop */ 85608057504Sxy150489 85708057504Sxy150489 /* Sync the Rx descriptor DMA buffers */ 85854e0d7a5SMiles Xu, Sun Microsystems (void) ddi_dma_sync(rx_data->rbd_dma_handle, 85925f2d433Sxy150489 0, 0, DDI_DMA_SYNC_FORDEV); 86008057504Sxy150489 86108057504Sxy150489 /* 86208057504Sxy150489 * Advance the E1000's Receive Queue #0 "Tail Pointer". 86308057504Sxy150489 */ 864592a4d85Scc210113 E1000_WRITE_REG(hw, E1000_RDT(0), 86554e0d7a5SMiles Xu, Sun Microsystems (uint32_t)(last_desc - rx_data->rbd_first)); 86608057504Sxy150489 8679b6541b3Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 8689b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 869d5c3073dSchenlu chen - Sun Microsystems - Beijing China Adapter->e1000g_state |= E1000G_ERROR; 8709b6541b3Sgl147354 } 8719b6541b3Sgl147354 87247b7744cSyy150190 Adapter->rx_pkt_cnt = pkt_count; 87347b7744cSyy150190 87408057504Sxy150489 return (ret_mp); 87508057504Sxy150489 87608057504Sxy150489 rx_drop: 87708057504Sxy150489 /* 87808057504Sxy150489 * Zero out the receive descriptors status 87908057504Sxy150489 */ 88008057504Sxy150489 current_desc->status = 0; 88108057504Sxy150489 88208057504Sxy150489 /* Sync the Rx descriptor DMA buffers */ 88354e0d7a5SMiles Xu, Sun Microsystems (void) ddi_dma_sync(rx_data->rbd_dma_handle, 88425f2d433Sxy150489 0, 0, DDI_DMA_SYNC_FORDEV); 88508057504Sxy150489 88654e0d7a5SMiles Xu, Sun Microsystems if (current_desc == rx_data->rbd_last) 88754e0d7a5SMiles Xu, Sun Microsystems rx_data->rbd_next = rx_data->rbd_first; 88808057504Sxy150489 else 88954e0d7a5SMiles Xu, Sun Microsystems rx_data->rbd_next++; 89008057504Sxy150489 89108057504Sxy150489 last_desc = current_desc; 89208057504Sxy150489 89354e0d7a5SMiles Xu, Sun Microsystems QUEUE_PUSH_TAIL(&rx_data->recv_list, &packet->Link); 89408057504Sxy150489 /* 89508057504Sxy150489 * Reclaim all old buffers already allocated during 89608057504Sxy150489 * Jumbo receives.....for incomplete reception 89708057504Sxy150489 */ 89854e0d7a5SMiles Xu, Sun Microsystems if (rx_data->rx_mblk != NULL) { 89954e0d7a5SMiles Xu, Sun Microsystems freemsg(rx_data->rx_mblk); 90054e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk = NULL; 90154e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk_tail = NULL; 90254e0d7a5SMiles Xu, Sun Microsystems rx_data->rx_mblk_len = 0; 90308057504Sxy150489 } 90408057504Sxy150489 /* 90508057504Sxy150489 * Advance the E1000's Receive Queue #0 "Tail Pointer". 90608057504Sxy150489 */ 907592a4d85Scc210113 E1000_WRITE_REG(hw, E1000_RDT(0), 90854e0d7a5SMiles Xu, Sun Microsystems (uint32_t)(last_desc - rx_data->rbd_first)); 90908057504Sxy150489 9109b6541b3Sgl147354 if (e1000g_check_acc_handle(Adapter->osdep.reg_handle) != DDI_FM_OK) { 9119b6541b3Sgl147354 ddi_fm_service_impact(Adapter->dip, DDI_SERVICE_DEGRADED); 912d5c3073dSchenlu chen - Sun Microsystems - Beijing China Adapter->e1000g_state |= E1000G_ERROR; 9139b6541b3Sgl147354 } 9149b6541b3Sgl147354 91508057504Sxy150489 return (ret_mp); 91608057504Sxy150489 } 917*42cc51e0SRobert Mustacchi 918*42cc51e0SRobert Mustacchi /* 919*42cc51e0SRobert Mustacchi * This is part of a workaround for the I219, see e1000g_flush_desc_rings() for 920*42cc51e0SRobert Mustacchi * more information. 921*42cc51e0SRobert Mustacchi * 922*42cc51e0SRobert Mustacchi * Flush all descriptors in the rx ring and disable it. 923*42cc51e0SRobert Mustacchi */ 924*42cc51e0SRobert Mustacchi void 925*42cc51e0SRobert Mustacchi e1000g_flush_rx_ring(struct e1000g *Adapter) 926*42cc51e0SRobert Mustacchi { 927*42cc51e0SRobert Mustacchi struct e1000_hw *hw = &Adapter->shared; 928*42cc51e0SRobert Mustacchi uint32_t rctl, rxdctl; 929*42cc51e0SRobert Mustacchi 930*42cc51e0SRobert Mustacchi rctl = E1000_READ_REG(hw, E1000_RCTL); 931*42cc51e0SRobert Mustacchi E1000_WRITE_REG(hw, E1000_RCTL, rctl & ~E1000_RCTL_EN); 932*42cc51e0SRobert Mustacchi E1000_WRITE_FLUSH(hw); 933*42cc51e0SRobert Mustacchi usec_delay(150); 934*42cc51e0SRobert Mustacchi 935*42cc51e0SRobert Mustacchi rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(0)); 936*42cc51e0SRobert Mustacchi /* Zero the lower 14 bits (prefetch and host thresholds). */ 937*42cc51e0SRobert Mustacchi rxdctl &= 0xffffc000; 938*42cc51e0SRobert Mustacchi /* 939*42cc51e0SRobert Mustacchi * Update thresholds: prefetch threshold to 31, host threshold to 1 940*42cc51e0SRobert Mustacchi * and make sure the granularity is "descriptors" and not "cache lines" 941*42cc51e0SRobert Mustacchi */ 942*42cc51e0SRobert Mustacchi rxdctl |= (0x1F | (1 << 8) | E1000_RXDCTL_THRESH_UNIT_DESC); 943*42cc51e0SRobert Mustacchi E1000_WRITE_REG(hw, E1000_RXDCTL(0), rxdctl); 944*42cc51e0SRobert Mustacchi 945*42cc51e0SRobert Mustacchi /* Momentarily enable the RX ring for the changes to take effect */ 946*42cc51e0SRobert Mustacchi E1000_WRITE_REG(hw, E1000_RCTL, rctl | E1000_RCTL_EN); 947*42cc51e0SRobert Mustacchi E1000_WRITE_FLUSH(hw); 948*42cc51e0SRobert Mustacchi usec_delay(150); 949*42cc51e0SRobert Mustacchi E1000_WRITE_REG(hw, E1000_RCTL, rctl & ~E1000_RCTL_EN); 950*42cc51e0SRobert Mustacchi 951*42cc51e0SRobert Mustacchi } 952