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
e1000g_rxfree_func(p_rx_sw_packet_t packet)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
e1000g_rx_setup(struct e1000g * Adapter)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
e1000g_get_buf(e1000g_rx_data_t * rx_data)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 *
e1000g_receive(e1000g_rx_ring_t * rx_ring,mblk_t ** tail,uint_t sz)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
e1000g_flush_rx_ring(struct e1000g * Adapter)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