Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7d3cabbc authored by Bruce Allan's avatar Bruce Allan Committed by David S. Miller
Browse files

e1000e: disable K1 at 1000Mbps for 82577/82578



This workaround is required for an issue in hardware where noise on the
interconnect between the MAC and PHY could be generated by a lower power
mode (K1) at 1000Mbps resulting in bad packets.  Disable K1 while at 1000
Mbps but keep it enabled for 10/100Mbps and when the cable is disconnected.

Signed-off-by: default avatarBruce Allan <bruce.w.allan@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 906e8d97
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -215,6 +215,7 @@ enum e1e_registers {
	E1000_SWSM      = 0x05B50, /* SW Semaphore */
	E1000_SWSM      = 0x05B50, /* SW Semaphore */
	E1000_FWSM      = 0x05B54, /* FW Semaphore */
	E1000_FWSM      = 0x05B54, /* FW Semaphore */
	E1000_SWSM2     = 0x05B58, /* Driver-only SW semaphore */
	E1000_SWSM2     = 0x05B58, /* Driver-only SW semaphore */
	E1000_CRC_OFFSET = 0x05F50, /* CRC Offset register */
	E1000_HICR      = 0x08F00, /* Host Interface Control */
	E1000_HICR      = 0x08F00, /* Host Interface Control */
};
};


@@ -302,6 +303,9 @@ enum e1e_registers {
#define E1000_KMRNCTRLSTA_REN		0x00200000
#define E1000_KMRNCTRLSTA_REN		0x00200000
#define E1000_KMRNCTRLSTA_DIAG_OFFSET	0x3    /* Kumeran Diagnostic */
#define E1000_KMRNCTRLSTA_DIAG_OFFSET	0x3    /* Kumeran Diagnostic */
#define E1000_KMRNCTRLSTA_DIAG_NELPBK	0x1000 /* Nearend Loopback mode */
#define E1000_KMRNCTRLSTA_DIAG_NELPBK	0x1000 /* Nearend Loopback mode */
#define E1000_KMRNCTRLSTA_K1_CONFIG	0x7
#define E1000_KMRNCTRLSTA_K1_ENABLE	0x140E
#define E1000_KMRNCTRLSTA_K1_DISABLE	0x1400


#define IFE_PHY_EXTENDED_STATUS_CONTROL	0x10
#define IFE_PHY_EXTENDED_STATUS_CONTROL	0x10
#define IFE_PHY_SPECIAL_CONTROL		0x11 /* 100BaseTx PHY Special Control */
#define IFE_PHY_SPECIAL_CONTROL		0x11 /* 100BaseTx PHY Special Control */
+106 −1
Original line number Original line Diff line number Diff line
@@ -461,6 +461,95 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
	return 0;
	return 0;
}
}


/**
 *  e1000_check_for_copper_link_ich8lan - Check for link (Copper)
 *  @hw: pointer to the HW structure
 *
 *  Checks to see of the link status of the hardware has changed.  If a
 *  change in link status has been detected, then we read the PHY registers
 *  to get the current speed/duplex if link exists.
 **/
static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
{
	struct e1000_mac_info *mac = &hw->mac;
	s32 ret_val;
	bool link;

	/*
	 * We only want to go out to the PHY registers to see if Auto-Neg
	 * has completed and/or if our link status has changed.  The
	 * get_link_status flag is set upon receiving a Link Status
	 * Change or Rx Sequence Error interrupt.
	 */
	if (!mac->get_link_status) {
		ret_val = 0;
		goto out;
	}

	if (hw->mac.type == e1000_pchlan) {
		ret_val = e1000e_write_kmrn_reg(hw,
		                                   E1000_KMRNCTRLSTA_K1_CONFIG,
		                                   E1000_KMRNCTRLSTA_K1_ENABLE);
		if (ret_val)
			goto out;
	}

	/*
	 * First we want to see if the MII Status Register reports
	 * link.  If so, then we want to get the current speed/duplex
	 * of the PHY.
	 */
	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
	if (ret_val)
		goto out;

	if (!link)
		goto out; /* No link detected */

	mac->get_link_status = false;

	if (hw->phy.type == e1000_phy_82578) {
		ret_val = e1000_link_stall_workaround_hv(hw);
		if (ret_val)
			goto out;
	}

	/*
	 * Check if there was DownShift, must be checked
	 * immediately after link-up
	 */
	e1000e_check_downshift(hw);

	/*
	 * If we are forcing speed/duplex, then we simply return since
	 * we have already determined whether we have link or not.
	 */
	if (!mac->autoneg) {
		ret_val = -E1000_ERR_CONFIG;
		goto out;
	}

	/*
	 * Auto-Neg is enabled.  Auto Speed Detection takes care
	 * of MAC speed/duplex configuration.  So we only need to
	 * configure Collision Distance in the MAC.
	 */
	e1000e_config_collision_dist(hw);

	/*
	 * Configure Flow Control now that Auto-Neg has completed.
	 * First, we need to restore the desired flow control
	 * settings because we may have had to re-autoneg with a
	 * different link partner.
	 */
	ret_val = e1000e_config_fc_after_link_up(hw);
	if (ret_val)
		hw_dbg(hw, "Error configuring flow control\n");

out:
	return ret_val;
}

static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
{
{
	struct e1000_hw *hw = &adapter->hw;
	struct e1000_hw *hw = &adapter->hw;
@@ -2224,6 +2313,14 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
		}
		}
	}
	}


	/*
	 * For PCH, this write will make sure that any noise
	 * will be detected as a CRC error and be dropped rather than show up
	 * as a bad packet to the DMA engine.
	 */
	if (hw->mac.type == e1000_pchlan)
		ew32(CRC_OFFSET, 0x65656565);

	ew32(IMC, 0xffffffff);
	ew32(IMC, 0xffffffff);
	icr = er32(ICR);
	icr = er32(ICR);


@@ -2538,6 +2635,14 @@ static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
	if (ret_val)
	if (ret_val)
		return ret_val;
		return ret_val;


	if ((hw->mac.type == e1000_pchlan) && (*speed == SPEED_1000)) {
		ret_val = e1000e_write_kmrn_reg(hw,
		                                  E1000_KMRNCTRLSTA_K1_CONFIG,
		                                  E1000_KMRNCTRLSTA_K1_DISABLE);
		if (ret_val)
			return ret_val;
	}

	if ((hw->mac.type == e1000_ich8lan) &&
	if ((hw->mac.type == e1000_ich8lan) &&
	    (hw->phy.type == e1000_phy_igp_3) &&
	    (hw->phy.type == e1000_phy_igp_3) &&
	    (*speed == SPEED_1000)) {
	    (*speed == SPEED_1000)) {
@@ -2984,7 +3089,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
static struct e1000_mac_operations ich8_mac_ops = {
static struct e1000_mac_operations ich8_mac_ops = {
	.id_led_init		= e1000e_id_led_init,
	.id_led_init		= e1000e_id_led_init,
	.check_mng_mode		= e1000_check_mng_mode_ich8lan,
	.check_mng_mode		= e1000_check_mng_mode_ich8lan,
	.check_for_link		= e1000e_check_for_copper_link,
	.check_for_link		= e1000_check_for_copper_link_ich8lan,
	/* cleanup_led dependent on mac type */
	/* cleanup_led dependent on mac type */
	.clear_hw_cntrs		= e1000_clear_hw_cntrs_ich8lan,
	.clear_hw_cntrs		= e1000_clear_hw_cntrs_ich8lan,
	.get_bus_info		= e1000_get_bus_info_ich8lan,
	.get_bus_info		= e1000_get_bus_info_ich8lan,
+0 −6
Original line number Original line Diff line number Diff line
@@ -378,12 +378,6 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw)


	mac->get_link_status = 0;
	mac->get_link_status = 0;


	if (hw->phy.type == e1000_phy_82578) {
		ret_val = e1000_link_stall_workaround_hv(hw);
		if (ret_val)
			return ret_val;
	}

	/*
	/*
	 * Check if there was DownShift, must be checked
	 * Check if there was DownShift, must be checked
	 * immediately after link-up
	 * immediately after link-up