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

Commit 57128197 authored by Jeff Kirsher's avatar Jeff Kirsher Committed by Jeff Garzik
Browse files

[PATCH] e1000: Fix SoL/IDER link and loopback



Fix so that if a SoL/IDER session is active, do not allow operations which require a PHY reset and instead log a message.

Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarJesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: default avatarJohn Ronciak <john.ronciak@intel.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent 545c67c0
Loading
Loading
Loading
Loading
+48 −80
Original line number Diff line number Diff line
@@ -183,6 +183,14 @@ e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
	struct e1000_adapter *adapter = netdev_priv(netdev);
	struct e1000_hw *hw = &adapter->hw;

	/* When SoL/IDER sessions are active, autoneg/speed/duplex
	 * cannot be changed */
	if (e1000_check_phy_reset_block(hw)) {
		DPRINTK(DRV, ERR, "Cannot change link characteristics "
		        "when SoL/IDER is active.\n");
		return -EINVAL;
	}

	if (ecmd->autoneg == AUTONEG_ENABLE) {
		hw->autoneg = 1;
		if(hw->media_type == e1000_media_type_fiber)
@@ -562,29 +570,10 @@ e1000_get_drvinfo(struct net_device *netdev,
                       struct ethtool_drvinfo *drvinfo)
{
	struct e1000_adapter *adapter = netdev_priv(netdev);
	char firmware_version[32];
	uint16_t eeprom_data;

	strncpy(drvinfo->driver,  e1000_driver_name, 32);
	strncpy(drvinfo->version, e1000_driver_version, 32);
	
	/* EEPROM image version # is reported as firware version # for
	 * 8257{1|2|3} controllers */
	e1000_read_eeprom(&adapter->hw, 5, 1, &eeprom_data);
	switch (adapter->hw.mac_type) {
	case e1000_82571:
	case e1000_82572:
	case e1000_82573:
		sprintf(firmware_version, "%d.%d-%d", 
			(eeprom_data & 0xF000) >> 12,
			(eeprom_data & 0x0FF0) >> 4,
			eeprom_data & 0x000F);
		break;
	default:
		sprintf(firmware_version, "n/a");
	}

	strncpy(drvinfo->fw_version, firmware_version, 32);
	strncpy(drvinfo->fw_version, "N/A", 32);
	strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
	drvinfo->n_stats = E1000_STATS_LEN;
	drvinfo->testinfo_len = E1000_TEST_LEN;
@@ -990,10 +979,8 @@ e1000_free_desc_rings(struct e1000_adapter *adapter)

	kfree(txdr->buffer_info);
	txdr->buffer_info = NULL;

	kfree(rxdr->buffer_info);
	rxdr->buffer_info = NULL;

	return;
}

@@ -1328,32 +1315,21 @@ static int
e1000_setup_loopback_test(struct e1000_adapter *adapter)
{
	uint32_t rctl;
	struct e1000_hw *hw = &adapter->hw;

	if (hw->media_type == e1000_media_type_fiber ||
	   hw->media_type == e1000_media_type_internal_serdes) {
		switch (hw->mac_type) {
		case e1000_82545:
		case e1000_82546:
		case e1000_82545_rev_3:
		case e1000_82546_rev_3:
	if(adapter->hw.media_type == e1000_media_type_fiber ||
	   adapter->hw.media_type == e1000_media_type_internal_serdes) {
		if(adapter->hw.mac_type == e1000_82545 ||
		   adapter->hw.mac_type == e1000_82546 ||
		   adapter->hw.mac_type == e1000_82545_rev_3 ||
		   adapter->hw.mac_type == e1000_82546_rev_3)
			return e1000_set_phy_loopback(adapter);
			break;
		case e1000_82571:
		case e1000_82572:
#define E1000_SERDES_LB_ON 0x410
			e1000_set_phy_loopback(adapter);
			E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_ON);
			msec_delay(10);
			return 0;
			break;
		default:
			rctl = E1000_READ_REG(hw, RCTL);
		else {
			rctl = E1000_READ_REG(&adapter->hw, RCTL);
			rctl |= E1000_RCTL_LBM_TCVR;
			E1000_WRITE_REG(hw, RCTL, rctl);
			E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
			return 0;
		}
	} else if (hw->media_type == e1000_media_type_copper)
	} else if(adapter->hw.media_type == e1000_media_type_copper)
		return e1000_set_phy_loopback(adapter);

	return 7;
@@ -1364,36 +1340,25 @@ e1000_loopback_cleanup(struct e1000_adapter *adapter)
{
	uint32_t rctl;
	uint16_t phy_reg;
	struct e1000_hw *hw = &adapter->hw;

	rctl = E1000_READ_REG(&adapter->hw, RCTL);
	rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
	E1000_WRITE_REG(&adapter->hw, RCTL, rctl);

	switch (hw->mac_type) {
	case e1000_82571:
	case e1000_82572:
		if (hw->media_type == e1000_media_type_fiber ||
		   hw->media_type == e1000_media_type_internal_serdes){
#define E1000_SERDES_LB_OFF 0x400
			E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_OFF);
			msec_delay(10);
			break;
		}
		/* fall thru for Cu adapters */
	case e1000_82545:
	case e1000_82546:
	case e1000_82545_rev_3:
	case e1000_82546_rev_3:
	default:
		hw->autoneg = TRUE;
		e1000_read_phy_reg(hw, PHY_CTRL, &phy_reg);
	if(adapter->hw.media_type == e1000_media_type_copper ||
	   ((adapter->hw.media_type == e1000_media_type_fiber ||
	     adapter->hw.media_type == e1000_media_type_internal_serdes) &&
	    (adapter->hw.mac_type == e1000_82545 ||
	     adapter->hw.mac_type == e1000_82546 ||
	     adapter->hw.mac_type == e1000_82545_rev_3 ||
	     adapter->hw.mac_type == e1000_82546_rev_3))) {
		adapter->hw.autoneg = TRUE;
		e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg);
		if(phy_reg & MII_CR_LOOPBACK) {
			phy_reg &= ~MII_CR_LOOPBACK;
			e1000_write_phy_reg(hw, PHY_CTRL, phy_reg);
			e1000_phy_reset(hw);
			e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg);
			e1000_phy_reset(&adapter->hw);
		}
		break;
	}
}

@@ -1488,14 +1453,25 @@ e1000_run_loopback_test(struct e1000_adapter *adapter)
static int
e1000_loopback_test(struct e1000_adapter *adapter, uint64_t *data)
{
	if((*data = e1000_setup_desc_rings(adapter))) goto err_loopback;
	/* PHY loopback cannot be performed if SoL/IDER
	 * sessions are active */
	if (e1000_check_phy_reset_block(&adapter->hw)) {
		DPRINTK(DRV, ERR, "Cannot do PHY loopback test "
		        "when SoL/IDER is active.\n");
		*data = 0;
		goto out;
	}

	if ((*data = e1000_setup_desc_rings(adapter)))
		goto out;
	if ((*data = e1000_setup_loopback_test(adapter)))
		goto err_loopback_setup;
		goto err_loopback;
	*data = e1000_run_loopback_test(adapter);
	e1000_loopback_cleanup(adapter);
err_loopback_setup:
	e1000_free_desc_rings(adapter);

err_loopback:
	e1000_free_desc_rings(adapter);
out:
	return *data;
}

@@ -1722,14 +1698,6 @@ e1000_phys_id(struct net_device *netdev, uint32_t data)
		msleep_interruptible(data * 1000);
		del_timer_sync(&adapter->blink_timer);
	}
	else if(adapter->hw.mac_type < e1000_82573) {
		E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE |
			E1000_LEDCTL_LED0_BLINK | E1000_LEDCTL_LED2_BLINK |
			(E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) |
			(E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED0_MODE_SHIFT) |
			(E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED1_MODE_SHIFT)));
		msleep_interruptible(data * 1000);
	}
	else {
		E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE |
			E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK | 
+11 −5
Original line number Diff line number Diff line
@@ -378,6 +378,8 @@ void
e1000_down(struct e1000_adapter *adapter)
{
	struct net_device *netdev = adapter->netdev;
	boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) &&
				     e1000_check_mng_mode(&adapter->hw);

	e1000_irq_disable(adapter);
#ifdef CONFIG_E1000_MQ
@@ -405,12 +407,16 @@ e1000_down(struct e1000_adapter *adapter)
	e1000_clean_all_tx_rings(adapter);
	e1000_clean_all_rx_rings(adapter);

	/* If WoL is not enabled and management mode is not IAMT
	 * Power down the PHY so no link is implied when interface is down */
	/* Power down the PHY so no link is implied when interface is down *
	 * The PHY cannot be powered down if any of the following is TRUE *
	 * (a) WoL is enabled
	 * (b) AMT is active
	 * (c) SoL/IDER session is active */
	if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 &&
	   adapter->hw.media_type == e1000_media_type_copper &&
	   !e1000_check_mng_mode(&adapter->hw) &&
	   !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN)) {
	   !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) &&
	   !mng_mode_enabled &&
	   !e1000_check_phy_reset_block(&adapter->hw)) {
		uint16_t mii_reg;
		e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
		mii_reg |= MII_CR_POWER_DOWN;
+6 −0
Original line number Diff line number Diff line
@@ -584,6 +584,12 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
					 .p = dplx_list }}
		};

		if (e1000_check_phy_reset_block(&adapter->hw)) {
			DPRINTK(PROBE, INFO,
				"Link active due to SoL/IDER Session. "
			        "Speed/Duplex/AutoNeg parameter ignored.\n");
			return;
		}
		if (num_Duplex > bd) {
			dplx = Duplex[bd];
			e1000_validate_option(&dplx, &opt, adapter);