void IntelMausi::intelSetupRxControl(struct e1000_adapter *adapter)
{
	struct e1000_hw *hw = &adapter->hw;
	u32 rctl, rfctl;
    
	/* Workaround Si errata on PCHx - configure jumbo frame flow.
	 * If jumbo frames not set, program related MAC/PHY registers
	 * to h/w defaults
	 */
	if (hw->mac.type >= e1000_pch2lan) {
		s32 ret_val;
        
		if (mtu > ETH_DATA_LEN)
			ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, true);
		else
			ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, false);
        
		if (ret_val)
			DebugLog("Ethernet [IntelMausi]: failed to enable/disable jumbo frame workaround mode.\n");
	}
	/* Program MC offset vector base */
	rctl = intelReadMem32(E1000_RCTL);
	rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
	rctl |= E1000_RCTL_BAM | E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
    
	/* Do not Store bad packets */
	rctl &= ~E1000_RCTL_SBP;
    
	/* Enable Long Packet receive */
	if (mtu <= ETH_DATA_LEN)
		rctl &= ~E1000_RCTL_LPE;
	else
		rctl |= E1000_RCTL_LPE;
    
	/* Some systems expect that the CRC is included in SMBUS traffic. The
	 * hardware strips the CRC before sending to both SMBUS (BMC) and to
	 * host memory when this is enabled
	 */
	if (adapter->flags2 & FLAG2_CRC_STRIPPING)
        rctl |= E1000_RCTL_SECRC;
    
	/* Workaround Si errata on 82577 PHY - configure IPG for jumbos */
	if ((hw->phy.type == e1000_phy_82577) && (rctl & E1000_RCTL_LPE)) {
		u16 phy_data;
        
		e1e_rphy(hw, PHY_REG(770, 26), &phy_data);
		phy_data &= 0xfff8;
		phy_data |= (1 << 2);
		e1e_wphy(hw, PHY_REG(770, 26), phy_data);
        
		e1e_rphy(hw, 22, &phy_data);
		phy_data &= 0x0fff;
		phy_data |= (1 << 14);
		e1e_wphy(hw, 0x10, 0x2823);
		e1e_wphy(hw, 0x11, 0x0003);
		e1e_wphy(hw, 22, phy_data);
	}
    
	/* Set buffer sizes to 2048 */
    //rctl |= (0x2 << E1000_RCTL_FLXB_SHIFT);
    rctl &= ~(E1000_RCTL_SZ_256 | E1000_RCTL_BSEX);
    
	/* Enable Extended Status in all Receive Descriptors */
	rfctl = intelReadMem32(E1000_RFCTL);
    rfctl |= (E1000_RFCTL_NEW_IPV6_EXT_DIS | E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_EXTEN | E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS);
	intelWriteMem32(E1000_RFCTL, rfctl);
    
	intelWriteMem32(E1000_RCTL, rctl);
}
/*
 * e1000g_rx_setup - setup rx data structures
 *
 * This routine initializes all of the receive related
 * structures. This includes the receive descriptors, the
 * actual receive buffers, and the rx_sw_packet software
 * structures.
 */
void
e1000g_rx_setup(struct e1000g *Adapter)
{
	struct e1000_hw *hw;
	p_rx_sw_packet_t packet;
	struct e1000_rx_desc *descriptor;
	uint32_t buf_low;
	uint32_t buf_high;
	uint32_t reg_val;
	uint32_t rctl;
	uint32_t rxdctl;
	uint32_t ert;
	uint16_t phy_data;
	int i;
	int size;
	e1000g_rx_data_t *rx_data;

	hw = &Adapter->shared;
	rx_data = Adapter->rx_ring->rx_data;

	/*
	 * zero out all of the receive buffer descriptor memory
	 * assures any previous data or status is erased
	 */
	bzero(rx_data->rbd_area,
	    sizeof (struct e1000_rx_desc) * Adapter->rx_desc_num);

	if (!Adapter->rx_buffer_setup) {
		/* Init the list of "Receive Buffer" */
		QUEUE_INIT_LIST(&rx_data->recv_list);

		/* Init the list of "Free Receive Buffer" */
		QUEUE_INIT_LIST(&rx_data->free_list);

		/* Init the list of "Free Receive Buffer" */
		QUEUE_INIT_LIST(&rx_data->recycle_list);
		/*
		 * Setup Receive list and the Free list. Note that
		 * the both were allocated in one packet area.
		 */
		packet = rx_data->packet_area;
		descriptor = rx_data->rbd_first;

		for (i = 0; i < Adapter->rx_desc_num;
		    i++, packet = packet->next, descriptor++) {
			ASSERT(packet != NULL);
			ASSERT(descriptor != NULL);
			descriptor->buffer_addr =
			    packet->rx_buf->dma_address;

			/* Add this rx_sw_packet to the receive list */
			QUEUE_PUSH_TAIL(&rx_data->recv_list,
			    &packet->Link);
		}

		for (i = 0; i < Adapter->rx_freelist_num;
		    i++, packet = packet->next) {
			ASSERT(packet != NULL);
			/* Add this rx_sw_packet to the free list */
			QUEUE_PUSH_TAIL(&rx_data->free_list,
			    &packet->Link);
		}
		rx_data->avail_freepkt = Adapter->rx_freelist_num;
		rx_data->recycle_freepkt = 0;

		Adapter->rx_buffer_setup = B_TRUE;
	} else {
		/* Setup the initial pointer to the first rx descriptor */
		packet = (p_rx_sw_packet_t)
		    QUEUE_GET_HEAD(&rx_data->recv_list);
		descriptor = rx_data->rbd_first;

		for (i = 0; i < Adapter->rx_desc_num; i++) {
			ASSERT(packet != NULL);
			ASSERT(descriptor != NULL);
			descriptor->buffer_addr =
			    packet->rx_buf->dma_address;

			/* Get next rx_sw_packet */
			packet = (p_rx_sw_packet_t)
			    QUEUE_GET_NEXT(&rx_data->recv_list, &packet->Link);
			descriptor++;
		}
	}

	E1000_WRITE_REG(&Adapter->shared, E1000_RDTR, Adapter->rx_intr_delay);
	E1000G_DEBUGLOG_1(Adapter, E1000G_INFO_LEVEL,
	    "E1000_RDTR: 0x%x\n", Adapter->rx_intr_delay);
	if (hw->mac.type >= e1000_82540) {
		E1000_WRITE_REG(&Adapter->shared, E1000_RADV,
		    Adapter->rx_intr_abs_delay);
		E1000G_DEBUGLOG_1(Adapter, E1000G_INFO_LEVEL,
		    "E1000_RADV: 0x%x\n", Adapter->rx_intr_abs_delay);
	}

	/*
	 * Setup our descriptor pointers
	 */
	rx_data->rbd_next = rx_data->rbd_first;

	size = Adapter->rx_desc_num * sizeof (struct e1000_rx_desc);
	E1000_WRITE_REG(hw, E1000_RDLEN(0), size);
	size = E1000_READ_REG(hw, E1000_RDLEN(0));

	/* To get lower order bits */
	buf_low = (uint32_t)rx_data->rbd_dma_addr;
	/* To get the higher order bits */
	buf_high = (uint32_t)(rx_data->rbd_dma_addr >> 32);

	E1000_WRITE_REG(hw, E1000_RDBAH(0), buf_high);
	E1000_WRITE_REG(hw, E1000_RDBAL(0), buf_low);

	/*
	 * Setup our HW Rx Head & Tail descriptor pointers
	 */
	E1000_WRITE_REG(hw, E1000_RDT(0),
	    (uint32_t)(rx_data->rbd_last - rx_data->rbd_first));
	E1000_WRITE_REG(hw, E1000_RDH(0), 0);

	/*
	 * Setup the Receive Control Register (RCTL), and ENABLE the
	 * receiver. The initial configuration is to: Enable the receiver,
	 * accept broadcasts, discard bad packets (and long packets),
	 * disable VLAN filter checking, set the receive descriptor
	 * minimum threshold size to 1/2, and the receive buffer size to
	 * 2k.
	 */
	rctl = E1000_RCTL_EN |		/* Enable Receive Unit */
	    E1000_RCTL_BAM |		/* Accept Broadcast Packets */
	    E1000_RCTL_LPE |		/* Large Packet Enable bit */
	    (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT) |
	    E1000_RCTL_RDMTS_HALF |
	    E1000_RCTL_LBM_NO;		/* Loopback Mode = none */

	if (Adapter->strip_crc)
		rctl |= E1000_RCTL_SECRC;	/* Strip Ethernet CRC */

	if (Adapter->mem_workaround_82546 &&
	    ((hw->mac.type == e1000_82545) ||
	    (hw->mac.type == e1000_82546) ||
	    (hw->mac.type == e1000_82546_rev_3))) {
		rctl |= E1000_RCTL_SZ_2048;
	} else {
		if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_2K) &&
		    (Adapter->max_frame_size <= FRAME_SIZE_UPTO_4K))
			rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX;
		else if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_4K) &&
		    (Adapter->max_frame_size <= FRAME_SIZE_UPTO_8K))
			rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX;
		else if ((Adapter->max_frame_size > FRAME_SIZE_UPTO_8K) &&
		    (Adapter->max_frame_size <= FRAME_SIZE_UPTO_16K))
			rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX;
		else
			rctl |= E1000_RCTL_SZ_2048;
	}

	if (e1000_tbi_sbp_enabled_82543(hw))
		rctl |= E1000_RCTL_SBP;

	/*
	 * Enable Early Receive Threshold (ERT) on supported devices.
	 * Only takes effect when packet size is equal or larger than the
	 * specified value (in 8 byte units), e.g. using jumbo frames.
	 */
	if ((hw->mac.type == e1000_82573) ||
	    (hw->mac.type == e1000_82574) ||
	    (hw->mac.type == e1000_ich9lan) ||
	    (hw->mac.type == e1000_ich10lan)) {

		ert = E1000_ERT_2048;

		/*
		 * Special modification when ERT and
		 * jumbo frames are enabled
		 */
		if (Adapter->default_mtu > ETHERMTU) {
			rxdctl = E1000_READ_REG(hw, E1000_RXDCTL(0));
			E1000_WRITE_REG(hw, E1000_RXDCTL(0), rxdctl | 0x3);
			ert |= (1 << 13);
		}

		E1000_WRITE_REG(hw, E1000_ERT, ert);
	}

	/* Workaround errata on 82577/8 adapters with large frames */
	if ((hw->mac.type == e1000_pchlan) &&
	    (Adapter->default_mtu > ETHERMTU)) {

		(void) e1000_read_phy_reg(hw, PHY_REG(770, 26), &phy_data);
		phy_data &= 0xfff8;
		phy_data |= (1 << 2);
		(void) e1000_write_phy_reg(hw, PHY_REG(770, 26), phy_data);

		if (hw->phy.type == e1000_phy_82577) {
			(void) e1000_read_phy_reg(hw, 22, &phy_data);
			phy_data &= 0x0fff;
			phy_data |= (1 << 14);
			(void) e1000_write_phy_reg(hw, 0x10, 0x2823);
			(void) e1000_write_phy_reg(hw, 0x11, 0x0003);
			(void) e1000_write_phy_reg(hw, 22, phy_data);
		}
	}

	reg_val =
	    E1000_RXCSUM_TUOFL |	/* TCP/UDP checksum offload Enable */
	    E1000_RXCSUM_IPOFL;		/* IP checksum offload Enable */

	E1000_WRITE_REG(hw, E1000_RXCSUM, reg_val);

	/*
	 * Workaround: Set bit 16 (IPv6_ExDIS) to disable the
	 * processing of received IPV6 extension headers
	 */
	if ((hw->mac.type == e1000_82571) || (hw->mac.type == e1000_82572)) {
		reg_val = E1000_READ_REG(hw, E1000_RFCTL);
		reg_val |= (E1000_RFCTL_IPV6_EX_DIS |
		    E1000_RFCTL_NEW_IPV6_EXT_DIS);
		E1000_WRITE_REG(hw, E1000_RFCTL, reg_val);
	}

	/* Write to enable the receive unit */
	E1000_WRITE_REG(hw, E1000_RCTL, rctl);
}
示例#3
0
static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
{
	struct e1000_hw *hw = &adapter->hw;
	u32 ctrl_reg = 0;
	u32 stat_reg = 0;
	u16 phy_reg = 0;

	hw->mac.autoneg = 0;

	if (hw->phy.type == e1000_phy_m88) {
		/* Auto-MDI/MDIX Off */
		e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
		/* reset to update Auto-MDI/MDIX */
		e1e_wphy(hw, PHY_CONTROL, 0x9140);
		/* autoneg off */
		e1e_wphy(hw, PHY_CONTROL, 0x8140);
	} else if (hw->phy.type == e1000_phy_gg82563)
		e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC);

	ctrl_reg = er32(CTRL);

	switch (hw->phy.type) {
	case e1000_phy_ife:
		/* force 100, set loopback */
		e1e_wphy(hw, PHY_CONTROL, 0x6100);

		/* Now set up the MAC to the same speed/duplex as the PHY. */
		ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
		ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
			     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
			     E1000_CTRL_SPD_100 |/* Force Speed to 100 */
			     E1000_CTRL_FD);	 /* Force Duplex to FULL */
		break;
	case e1000_phy_bm:
		/* Set Default MAC Interface speed to 1GB */
		e1e_rphy(hw, PHY_REG(2, 21), &phy_reg);
		phy_reg &= ~0x0007;
		phy_reg |= 0x006;
		e1e_wphy(hw, PHY_REG(2, 21), phy_reg);
		/* Assert SW reset for above settings to take effect */
		e1000e_commit_phy(hw);
		mdelay(1);
		/* Force Full Duplex */
		e1e_rphy(hw, PHY_REG(769, 16), &phy_reg);
		e1e_wphy(hw, PHY_REG(769, 16), phy_reg | 0x000C);
		/* Set Link Up (in force link) */
		e1e_rphy(hw, PHY_REG(776, 16), &phy_reg);
		e1e_wphy(hw, PHY_REG(776, 16), phy_reg | 0x0040);
		/* Force Link */
		e1e_rphy(hw, PHY_REG(769, 16), &phy_reg);
		e1e_wphy(hw, PHY_REG(769, 16), phy_reg | 0x0040);
		/* Set Early Link Enable */
		e1e_rphy(hw, PHY_REG(769, 20), &phy_reg);
		e1e_wphy(hw, PHY_REG(769, 20), phy_reg | 0x0400);
		/* fall through */
	default:
		/* force 1000, set loopback */
		e1e_wphy(hw, PHY_CONTROL, 0x4140);
		mdelay(250);

		/* Now set up the MAC to the same speed/duplex as the PHY. */
		ctrl_reg = er32(CTRL);
		ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
		ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
			     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
			     E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
			     E1000_CTRL_FD);	 /* Force Duplex to FULL */

		if (adapter->flags & FLAG_IS_ICH)
			ctrl_reg |= E1000_CTRL_SLU;	/* Set Link Up */
	}

	if (hw->phy.media_type == e1000_media_type_copper &&
	    hw->phy.type == e1000_phy_m88) {
		ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
	} else {
		/*
		 * Set the ILOS bit on the fiber Nic if half duplex link is
		 * detected.
		 */
		stat_reg = er32(STATUS);
		if ((stat_reg & E1000_STATUS_FD) == 0)
			ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);
	}

	ew32(CTRL, ctrl_reg);

	/*
	 * Disable the receiver on the PHY so when a cable is plugged in, the
	 * PHY does not begin to autoneg when a cable is reconnected to the NIC.
	 */
	if (hw->phy.type == e1000_phy_m88)
		e1000_phy_disable_receiver(adapter);

	udelay(500);

	return 0;
}