diff options
Diffstat (limited to 'drivers/net/ethernet/intel/igb')
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_phy.c | 29 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_phy.h | 5 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/igb_ethtool.c | 42 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/igb_main.c | 4 | 
4 files changed, 76 insertions, 4 deletions
diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c index 7be98b6f105..3404bc79f4c 100644 --- a/drivers/net/ethernet/intel/igb/e1000_phy.c +++ b/drivers/net/ethernet/intel/igb/e1000_phy.c @@ -464,6 +464,32 @@ s32 igb_copper_link_setup_82580(struct e1000_hw *hw)  	phy_data |= I82580_CFG_ENABLE_DOWNSHIFT;  	ret_val = phy->ops.write_reg(hw, I82580_CFG_REG, phy_data); +	if (ret_val) +		goto out; + +	/* Set MDI/MDIX mode */ +	ret_val = phy->ops.read_reg(hw, I82580_PHY_CTRL_2, &phy_data); +	if (ret_val) +		goto out; +	phy_data &= ~I82580_PHY_CTRL2_MDIX_CFG_MASK; +	/* +	 * Options: +	 *   0 - Auto (default) +	 *   1 - MDI mode +	 *   2 - MDI-X mode +	 */ +	switch (hw->phy.mdix) { +	case 1: +		break; +	case 2: +		phy_data |= I82580_PHY_CTRL2_MANUAL_MDIX; +		break; +	case 0: +	default: +		phy_data |= I82580_PHY_CTRL2_AUTO_MDI_MDIX; +		break; +	} +	ret_val = hw->phy.ops.write_reg(hw, I82580_PHY_CTRL_2, phy_data);  out:  	return ret_val; @@ -2246,8 +2272,7 @@ s32 igb_phy_force_speed_duplex_82580(struct e1000_hw *hw)  	if (ret_val)  		goto out; -	phy_data &= ~I82580_PHY_CTRL2_AUTO_MDIX; -	phy_data &= ~I82580_PHY_CTRL2_FORCE_MDI_MDIX; +	phy_data &= ~I82580_PHY_CTRL2_MDIX_CFG_MASK;  	ret_val = phy->ops.write_reg(hw, I82580_PHY_CTRL_2, phy_data);  	if (ret_val) diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.h b/drivers/net/ethernet/intel/igb/e1000_phy.h index 34e40619f16..6ac3299bfcb 100644 --- a/drivers/net/ethernet/intel/igb/e1000_phy.h +++ b/drivers/net/ethernet/intel/igb/e1000_phy.h @@ -111,8 +111,9 @@ s32  igb_check_polarity_m88(struct e1000_hw *hw);  #define I82580_PHY_STATUS2_SPEED_100MBPS  0x0100  /* I82580 PHY Control 2 */ -#define I82580_PHY_CTRL2_AUTO_MDIX        0x0400 -#define I82580_PHY_CTRL2_FORCE_MDI_MDIX   0x0200 +#define I82580_PHY_CTRL2_MANUAL_MDIX      0x0200 +#define I82580_PHY_CTRL2_AUTO_MDI_MDIX    0x0400 +#define I82580_PHY_CTRL2_MDIX_CFG_MASK    0x0600  /* I82580 PHY Diagnostics Status */  #define I82580_DSTATUS_CABLE_LENGTH       0x03FC diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 70591117051..be02168f130 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -198,6 +198,19 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)  	}  	ecmd->autoneg = hw->mac.autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE; + +	/* MDI-X => 2; MDI =>1; Invalid =>0 */ +	if (hw->phy.media_type == e1000_media_type_copper) +		ecmd->eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X : +						      ETH_TP_MDI; +	else +		ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID; + +	if (hw->phy.mdix == AUTO_ALL_MODES) +		ecmd->eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO; +	else +		ecmd->eth_tp_mdix_ctrl = hw->phy.mdix; +  	return 0;  } @@ -214,6 +227,22 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)  		return -EINVAL;  	} +	/* +	 * MDI setting is only allowed when autoneg enabled because +	 * some hardware doesn't allow MDI setting when speed or +	 * duplex is forced. +	 */ +	if (ecmd->eth_tp_mdix_ctrl) { +		if (hw->phy.media_type != e1000_media_type_copper) +			return -EOPNOTSUPP; + +		if ((ecmd->eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO) && +		    (ecmd->autoneg != AUTONEG_ENABLE)) { +			dev_err(&adapter->pdev->dev, "forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n"); +			return -EINVAL; +		} +	} +  	while (test_and_set_bit(__IGB_RESETTING, &adapter->state))  		msleep(1); @@ -227,12 +256,25 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)  			hw->fc.requested_mode = e1000_fc_default;  	} else {  		u32 speed = ethtool_cmd_speed(ecmd); +		/* calling this overrides forced MDI setting */  		if (igb_set_spd_dplx(adapter, speed, ecmd->duplex)) {  			clear_bit(__IGB_RESETTING, &adapter->state);  			return -EINVAL;  		}  	} +	/* MDI-X => 2; MDI => 1; Auto => 3 */ +	if (ecmd->eth_tp_mdix_ctrl) { +		/* +		 * fix up the value for auto (3 => 0) as zero is mapped +		 * internally to auto +		 */ +		if (ecmd->eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO) +			hw->phy.mdix = AUTO_ALL_MODES; +		else +			hw->phy.mdix = ecmd->eth_tp_mdix_ctrl; +	} +  	/* reset the link */  	if (netif_running(adapter->netdev)) {  		igb_down(adapter); diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 48cc4fb1a30..73cc273ef98 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -6675,6 +6675,10 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u32 spd, u8 dplx)  	default:  		goto err_inval;  	} + +	/* clear MDI, MDI(-X) override is only allowed when autoneg enabled */ +	adapter->hw.phy.mdix = AUTO_ALL_MODES; +  	return 0;  err_inval:  |