|
@@ -215,52 +215,135 @@ static int i40e_get_settings(struct net_device *netdev,
|
|
|
/* hardware is either in 40G mode or 10G mode
|
|
|
* NOTE: this section initializes supported and advertising
|
|
|
*/
|
|
|
+ if (!link_up) {
|
|
|
+ /* link is down and the driver needs to fall back on
|
|
|
+ * device ID to determine what kinds of info to display,
|
|
|
+ * it's mostly a guess that may change when link is up
|
|
|
+ */
|
|
|
+ switch (hw->device_id) {
|
|
|
+ case I40E_DEV_ID_QSFP_A:
|
|
|
+ case I40E_DEV_ID_QSFP_B:
|
|
|
+ case I40E_DEV_ID_QSFP_C:
|
|
|
+ /* pluggable QSFP */
|
|
|
+ ecmd->supported = SUPPORTED_40000baseSR4_Full |
|
|
|
+ SUPPORTED_40000baseCR4_Full |
|
|
|
+ SUPPORTED_40000baseLR4_Full;
|
|
|
+ ecmd->advertising = ADVERTISED_40000baseSR4_Full |
|
|
|
+ ADVERTISED_40000baseCR4_Full |
|
|
|
+ ADVERTISED_40000baseLR4_Full;
|
|
|
+ break;
|
|
|
+ case I40E_DEV_ID_KX_B:
|
|
|
+ /* backplane 40G */
|
|
|
+ ecmd->supported = SUPPORTED_40000baseKR4_Full;
|
|
|
+ ecmd->advertising = ADVERTISED_40000baseKR4_Full;
|
|
|
+ break;
|
|
|
+ case I40E_DEV_ID_KX_C:
|
|
|
+ /* backplane 10G */
|
|
|
+ ecmd->supported = SUPPORTED_10000baseKR_Full;
|
|
|
+ ecmd->advertising = ADVERTISED_10000baseKR_Full;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ /* all the rest are 10G/1G */
|
|
|
+ ecmd->supported = SUPPORTED_10000baseT_Full |
|
|
|
+ SUPPORTED_1000baseT_Full;
|
|
|
+ ecmd->advertising = ADVERTISED_10000baseT_Full |
|
|
|
+ ADVERTISED_1000baseT_Full;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* skip phy_type use as it is zero when link is down */
|
|
|
+ goto no_valid_phy_type;
|
|
|
+ }
|
|
|
+
|
|
|
switch (hw_link_info->phy_type) {
|
|
|
case I40E_PHY_TYPE_40GBASE_CR4:
|
|
|
case I40E_PHY_TYPE_40GBASE_CR4_CU:
|
|
|
- ecmd->supported = SUPPORTED_40000baseCR4_Full;
|
|
|
- ecmd->advertising = ADVERTISED_40000baseCR4_Full;
|
|
|
+ ecmd->supported = SUPPORTED_Autoneg |
|
|
|
+ SUPPORTED_40000baseCR4_Full;
|
|
|
+ ecmd->advertising = ADVERTISED_Autoneg |
|
|
|
+ ADVERTISED_40000baseCR4_Full;
|
|
|
break;
|
|
|
case I40E_PHY_TYPE_40GBASE_KR4:
|
|
|
- ecmd->supported = SUPPORTED_40000baseKR4_Full;
|
|
|
- ecmd->advertising = ADVERTISED_40000baseKR4_Full;
|
|
|
+ ecmd->supported = SUPPORTED_Autoneg |
|
|
|
+ SUPPORTED_40000baseKR4_Full;
|
|
|
+ ecmd->advertising = ADVERTISED_Autoneg |
|
|
|
+ ADVERTISED_40000baseKR4_Full;
|
|
|
break;
|
|
|
case I40E_PHY_TYPE_40GBASE_SR4:
|
|
|
+ case I40E_PHY_TYPE_XLPPI:
|
|
|
+ case I40E_PHY_TYPE_XLAUI:
|
|
|
ecmd->supported = SUPPORTED_40000baseSR4_Full;
|
|
|
- ecmd->advertising = ADVERTISED_40000baseSR4_Full;
|
|
|
break;
|
|
|
case I40E_PHY_TYPE_40GBASE_LR4:
|
|
|
ecmd->supported = SUPPORTED_40000baseLR4_Full;
|
|
|
- ecmd->advertising = ADVERTISED_40000baseLR4_Full;
|
|
|
break;
|
|
|
case I40E_PHY_TYPE_10GBASE_KX4:
|
|
|
- ecmd->supported = SUPPORTED_10000baseKX4_Full;
|
|
|
- ecmd->advertising = ADVERTISED_10000baseKX4_Full;
|
|
|
+ ecmd->supported = SUPPORTED_Autoneg |
|
|
|
+ SUPPORTED_10000baseKX4_Full;
|
|
|
+ ecmd->advertising = ADVERTISED_Autoneg |
|
|
|
+ ADVERTISED_10000baseKX4_Full;
|
|
|
break;
|
|
|
case I40E_PHY_TYPE_10GBASE_KR:
|
|
|
- ecmd->supported = SUPPORTED_10000baseKR_Full;
|
|
|
- ecmd->advertising = ADVERTISED_10000baseKR_Full;
|
|
|
+ ecmd->supported = SUPPORTED_Autoneg |
|
|
|
+ SUPPORTED_10000baseKR_Full;
|
|
|
+ ecmd->advertising = ADVERTISED_Autoneg |
|
|
|
+ ADVERTISED_10000baseKR_Full;
|
|
|
break;
|
|
|
- default:
|
|
|
- if (i40e_is_40G_device(hw->device_id)) {
|
|
|
- ecmd->supported = SUPPORTED_40000baseSR4_Full;
|
|
|
- ecmd->advertising = ADVERTISED_40000baseSR4_Full;
|
|
|
- } else {
|
|
|
- ecmd->supported = SUPPORTED_10000baseT_Full;
|
|
|
- ecmd->advertising = ADVERTISED_10000baseT_Full;
|
|
|
- }
|
|
|
+ case I40E_PHY_TYPE_10GBASE_SR:
|
|
|
+ case I40E_PHY_TYPE_10GBASE_LR:
|
|
|
+ ecmd->supported = SUPPORTED_10000baseT_Full;
|
|
|
+ break;
|
|
|
+ case I40E_PHY_TYPE_10GBASE_CR1_CU:
|
|
|
+ case I40E_PHY_TYPE_10GBASE_CR1:
|
|
|
+ case I40E_PHY_TYPE_10GBASE_T:
|
|
|
+ ecmd->supported = SUPPORTED_Autoneg |
|
|
|
+ SUPPORTED_10000baseT_Full;
|
|
|
+ ecmd->advertising = ADVERTISED_Autoneg |
|
|
|
+ ADVERTISED_10000baseT_Full;
|
|
|
+ break;
|
|
|
+ case I40E_PHY_TYPE_XAUI:
|
|
|
+ case I40E_PHY_TYPE_XFI:
|
|
|
+ case I40E_PHY_TYPE_SFI:
|
|
|
+ case I40E_PHY_TYPE_10GBASE_SFPP_CU:
|
|
|
+ ecmd->supported = SUPPORTED_10000baseT_Full;
|
|
|
break;
|
|
|
+ case I40E_PHY_TYPE_1000BASE_KX:
|
|
|
+ case I40E_PHY_TYPE_1000BASE_T:
|
|
|
+ ecmd->supported = SUPPORTED_Autoneg |
|
|
|
+ SUPPORTED_1000baseT_Full;
|
|
|
+ ecmd->advertising = ADVERTISED_Autoneg |
|
|
|
+ ADVERTISED_1000baseT_Full;
|
|
|
+ break;
|
|
|
+ case I40E_PHY_TYPE_100BASE_TX:
|
|
|
+ ecmd->supported = SUPPORTED_Autoneg |
|
|
|
+ SUPPORTED_100baseT_Full;
|
|
|
+ ecmd->advertising = ADVERTISED_Autoneg |
|
|
|
+ ADVERTISED_100baseT_Full;
|
|
|
+ break;
|
|
|
+ case I40E_PHY_TYPE_SGMII:
|
|
|
+ ecmd->supported = SUPPORTED_Autoneg |
|
|
|
+ SUPPORTED_1000baseT_Full |
|
|
|
+ SUPPORTED_100baseT_Full;
|
|
|
+ ecmd->advertising = ADVERTISED_Autoneg |
|
|
|
+ ADVERTISED_1000baseT_Full |
|
|
|
+ ADVERTISED_100baseT_Full;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ /* if we got here and link is up something bad is afoot */
|
|
|
+ WARN_ON(link_up);
|
|
|
}
|
|
|
|
|
|
- ecmd->supported |= SUPPORTED_Autoneg;
|
|
|
- ecmd->advertising |= ADVERTISED_Autoneg;
|
|
|
+no_valid_phy_type:
|
|
|
+ /* this is if autoneg is enabled or disabled */
|
|
|
ecmd->autoneg = ((hw_link_info->an_info & I40E_AQ_AN_COMPLETED) ?
|
|
|
AUTONEG_ENABLE : AUTONEG_DISABLE);
|
|
|
|
|
|
switch (hw->phy.media_type) {
|
|
|
case I40E_MEDIA_TYPE_BACKPLANE:
|
|
|
- ecmd->supported |= SUPPORTED_Backplane;
|
|
|
- ecmd->advertising |= ADVERTISED_Backplane;
|
|
|
+ ecmd->supported |= SUPPORTED_Autoneg |
|
|
|
+ SUPPORTED_Backplane;
|
|
|
+ ecmd->advertising |= ADVERTISED_Autoneg |
|
|
|
+ ADVERTISED_Backplane;
|
|
|
ecmd->port = PORT_NONE;
|
|
|
break;
|
|
|
case I40E_MEDIA_TYPE_BASET:
|
|
@@ -276,7 +359,6 @@ static int i40e_get_settings(struct net_device *netdev,
|
|
|
break;
|
|
|
case I40E_MEDIA_TYPE_FIBER:
|
|
|
ecmd->supported |= SUPPORTED_FIBRE;
|
|
|
- ecmd->advertising |= ADVERTISED_FIBRE;
|
|
|
ecmd->port = PORT_FIBRE;
|
|
|
break;
|
|
|
case I40E_MEDIA_TYPE_UNKNOWN:
|
|
@@ -287,6 +369,25 @@ static int i40e_get_settings(struct net_device *netdev,
|
|
|
|
|
|
ecmd->transceiver = XCVR_EXTERNAL;
|
|
|
|
|
|
+ ecmd->supported |= SUPPORTED_Pause;
|
|
|
+
|
|
|
+ switch (hw->fc.current_mode) {
|
|
|
+ case I40E_FC_FULL:
|
|
|
+ ecmd->advertising |= ADVERTISED_Pause;
|
|
|
+ break;
|
|
|
+ case I40E_FC_TX_PAUSE:
|
|
|
+ ecmd->advertising |= ADVERTISED_Asym_Pause;
|
|
|
+ break;
|
|
|
+ case I40E_FC_RX_PAUSE:
|
|
|
+ ecmd->advertising |= (ADVERTISED_Pause |
|
|
|
+ ADVERTISED_Asym_Pause);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ ecmd->advertising &= ~(ADVERTISED_Pause |
|
|
|
+ ADVERTISED_Asym_Pause);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
if (link_up) {
|
|
|
switch (link_speed) {
|
|
|
case I40E_LINK_SPEED_40GB:
|
|
@@ -296,6 +397,9 @@ static int i40e_get_settings(struct net_device *netdev,
|
|
|
case I40E_LINK_SPEED_10GB:
|
|
|
ethtool_cmd_speed_set(ecmd, SPEED_10000);
|
|
|
break;
|
|
|
+ case I40E_LINK_SPEED_1GB:
|
|
|
+ ethtool_cmd_speed_set(ecmd, SPEED_1000);
|
|
|
+ break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
@@ -308,6 +412,182 @@ static int i40e_get_settings(struct net_device *netdev,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * i40e_set_settings - Set Speed and Duplex
|
|
|
+ * @netdev: network interface device structure
|
|
|
+ * @ecmd: ethtool command
|
|
|
+ *
|
|
|
+ * Set speed/duplex per media_types advertised/forced
|
|
|
+ **/
|
|
|
+static int i40e_set_settings(struct net_device *netdev,
|
|
|
+ struct ethtool_cmd *ecmd)
|
|
|
+{
|
|
|
+ struct i40e_netdev_priv *np = netdev_priv(netdev);
|
|
|
+ struct i40e_aq_get_phy_abilities_resp abilities;
|
|
|
+ struct i40e_aq_set_phy_config config;
|
|
|
+ struct i40e_pf *pf = np->vsi->back;
|
|
|
+ struct i40e_vsi *vsi = np->vsi;
|
|
|
+ struct i40e_hw *hw = &pf->hw;
|
|
|
+ struct ethtool_cmd safe_ecmd;
|
|
|
+ i40e_status status = 0;
|
|
|
+ bool change = false;
|
|
|
+ int err = 0;
|
|
|
+ u8 autoneg;
|
|
|
+ u32 advertise;
|
|
|
+
|
|
|
+ if (vsi != pf->vsi[pf->lan_vsi])
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ if (hw->phy.media_type != I40E_MEDIA_TYPE_BASET &&
|
|
|
+ hw->phy.media_type != I40E_MEDIA_TYPE_FIBER &&
|
|
|
+ hw->phy.media_type != I40E_MEDIA_TYPE_BACKPLANE)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ /* get our own copy of the bits to check against */
|
|
|
+ memset(&safe_ecmd, 0, sizeof(struct ethtool_cmd));
|
|
|
+ i40e_get_settings(netdev, &safe_ecmd);
|
|
|
+
|
|
|
+ /* save autoneg and speed out of ecmd */
|
|
|
+ autoneg = ecmd->autoneg;
|
|
|
+ advertise = ecmd->advertising;
|
|
|
+
|
|
|
+ /* set autoneg and speed back to what they currently are */
|
|
|
+ ecmd->autoneg = safe_ecmd.autoneg;
|
|
|
+ ecmd->advertising = safe_ecmd.advertising;
|
|
|
+
|
|
|
+ ecmd->cmd = safe_ecmd.cmd;
|
|
|
+ /* If ecmd and safe_ecmd are not the same now, then they are
|
|
|
+ * trying to set something that we do not support
|
|
|
+ */
|
|
|
+ if (memcmp(ecmd, &safe_ecmd, sizeof(struct ethtool_cmd)))
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ while (test_bit(__I40E_CONFIG_BUSY, &vsi->state))
|
|
|
+ usleep_range(1000, 2000);
|
|
|
+
|
|
|
+ /* Get the current phy config */
|
|
|
+ status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities,
|
|
|
+ NULL);
|
|
|
+ if (status)
|
|
|
+ return -EAGAIN;
|
|
|
+
|
|
|
+ /* Copy link_speed and abilities to config in case they are not
|
|
|
+ * set below
|
|
|
+ */
|
|
|
+ memset(&config, 0, sizeof(struct i40e_aq_set_phy_config));
|
|
|
+ config.link_speed = abilities.link_speed;
|
|
|
+ config.abilities = abilities.abilities;
|
|
|
+
|
|
|
+ /* Check autoneg */
|
|
|
+ if (autoneg == AUTONEG_ENABLE) {
|
|
|
+ /* If autoneg is not supported, return error */
|
|
|
+ if (!(safe_ecmd.supported & SUPPORTED_Autoneg)) {
|
|
|
+ netdev_info(netdev, "Autoneg not supported on this phy\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ /* If autoneg was not already enabled */
|
|
|
+ if (!(hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED)) {
|
|
|
+ config.abilities = abilities.abilities |
|
|
|
+ I40E_AQ_PHY_ENABLE_AN;
|
|
|
+ change = true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* If autoneg is supported 10GBASE_T is the only phy that
|
|
|
+ * can disable it, so otherwise return error
|
|
|
+ */
|
|
|
+ if (safe_ecmd.supported & SUPPORTED_Autoneg &&
|
|
|
+ hw->phy.link_info.phy_type != I40E_PHY_TYPE_10GBASE_T) {
|
|
|
+ netdev_info(netdev, "Autoneg cannot be disabled on this phy\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ /* If autoneg is currently enabled */
|
|
|
+ if (hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED) {
|
|
|
+ config.abilities = abilities.abilities |
|
|
|
+ ~I40E_AQ_PHY_ENABLE_AN;
|
|
|
+ change = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (advertise & ~safe_ecmd.supported)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (advertise & ADVERTISED_100baseT_Full)
|
|
|
+ if (!(abilities.link_speed & I40E_LINK_SPEED_100MB)) {
|
|
|
+ config.link_speed |= I40E_LINK_SPEED_100MB;
|
|
|
+ change = true;
|
|
|
+ }
|
|
|
+ if (advertise & ADVERTISED_1000baseT_Full ||
|
|
|
+ advertise & ADVERTISED_1000baseKX_Full)
|
|
|
+ if (!(abilities.link_speed & I40E_LINK_SPEED_1GB)) {
|
|
|
+ config.link_speed |= I40E_LINK_SPEED_1GB;
|
|
|
+ change = true;
|
|
|
+ }
|
|
|
+ if (advertise & ADVERTISED_10000baseT_Full ||
|
|
|
+ advertise & ADVERTISED_10000baseKX4_Full ||
|
|
|
+ advertise & ADVERTISED_10000baseKR_Full)
|
|
|
+ if (!(abilities.link_speed & I40E_LINK_SPEED_10GB)) {
|
|
|
+ config.link_speed |= I40E_LINK_SPEED_10GB;
|
|
|
+ change = true;
|
|
|
+ }
|
|
|
+ if (advertise & ADVERTISED_40000baseKR4_Full ||
|
|
|
+ advertise & ADVERTISED_40000baseCR4_Full ||
|
|
|
+ advertise & ADVERTISED_40000baseSR4_Full ||
|
|
|
+ advertise & ADVERTISED_40000baseLR4_Full)
|
|
|
+ if (!(abilities.link_speed & I40E_LINK_SPEED_40GB)) {
|
|
|
+ config.link_speed |= I40E_LINK_SPEED_40GB;
|
|
|
+ change = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (change) {
|
|
|
+ /* copy over the rest of the abilities */
|
|
|
+ config.phy_type = abilities.phy_type;
|
|
|
+ config.eee_capability = abilities.eee_capability;
|
|
|
+ config.eeer = abilities.eeer_val;
|
|
|
+ config.low_power_ctrl = abilities.d3_lpan;
|
|
|
+
|
|
|
+ /* If link is up set link and an so changes take effect */
|
|
|
+ if (hw->phy.link_info.link_info & I40E_AQ_LINK_UP)
|
|
|
+ config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
|
|
|
+
|
|
|
+ /* make the aq call */
|
|
|
+ status = i40e_aq_set_phy_config(hw, &config, NULL);
|
|
|
+ if (status) {
|
|
|
+ netdev_info(netdev, "Set phy config failed with error %d.\n",
|
|
|
+ status);
|
|
|
+ return -EAGAIN;
|
|
|
+ }
|
|
|
+
|
|
|
+ status = i40e_update_link_info(hw, true);
|
|
|
+ if (status)
|
|
|
+ netdev_info(netdev, "Updating link info failed with error %d\n",
|
|
|
+ status);
|
|
|
+
|
|
|
+ } else {
|
|
|
+ netdev_info(netdev, "Nothing changed, exiting without setting anything.\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static int i40e_nway_reset(struct net_device *netdev)
|
|
|
+{
|
|
|
+ /* restart autonegotiation */
|
|
|
+ struct i40e_netdev_priv *np = netdev_priv(netdev);
|
|
|
+ struct i40e_pf *pf = np->vsi->back;
|
|
|
+ struct i40e_hw *hw = &pf->hw;
|
|
|
+ bool link_up = hw->phy.link_info.link_info & I40E_AQ_LINK_UP;
|
|
|
+ i40e_status ret = 0;
|
|
|
+
|
|
|
+ ret = i40e_aq_set_link_restart_an(hw, link_up, NULL);
|
|
|
+ if (ret) {
|
|
|
+ netdev_info(netdev, "link restart failed, aq_err=%d\n",
|
|
|
+ pf->hw.aq.asq_last_status);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* i40e_get_pauseparam - Get Flow Control status
|
|
|
* Return tx/rx-pause status
|
|
@@ -334,6 +614,81 @@ static void i40e_get_pauseparam(struct net_device *netdev,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * i40e_set_pauseparam - Set Flow Control parameter
|
|
|
+ * @netdev: network interface device structure
|
|
|
+ * @pause: return tx/rx flow control status
|
|
|
+ **/
|
|
|
+static int i40e_set_pauseparam(struct net_device *netdev,
|
|
|
+ struct ethtool_pauseparam *pause)
|
|
|
+{
|
|
|
+ struct i40e_netdev_priv *np = netdev_priv(netdev);
|
|
|
+ struct i40e_pf *pf = np->vsi->back;
|
|
|
+ struct i40e_vsi *vsi = np->vsi;
|
|
|
+ struct i40e_hw *hw = &pf->hw;
|
|
|
+ struct i40e_link_status *hw_link_info = &hw->phy.link_info;
|
|
|
+ bool link_up = hw_link_info->link_info & I40E_AQ_LINK_UP;
|
|
|
+ i40e_status status;
|
|
|
+ u8 aq_failures;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ if (vsi != pf->vsi[pf->lan_vsi])
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ if (pause->autoneg != ((hw_link_info->an_info & I40E_AQ_AN_COMPLETED) ?
|
|
|
+ AUTONEG_ENABLE : AUTONEG_DISABLE)) {
|
|
|
+ netdev_info(netdev, "To change autoneg please use: ethtool -s <dev> autoneg <on|off>\n");
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If we have link and don't have autoneg */
|
|
|
+ if (!test_bit(__I40E_DOWN, &pf->state) &&
|
|
|
+ !(hw_link_info->an_info & I40E_AQ_AN_COMPLETED)) {
|
|
|
+ /* Send message that it might not necessarily work*/
|
|
|
+ netdev_info(netdev, "Autoneg did not complete so changing settings may not result in an actual change.\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hw->fc.current_mode == I40E_FC_PFC) {
|
|
|
+ netdev_info(netdev, "Priority flow control enabled. Cannot set link flow control.\n");
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pause->rx_pause && pause->tx_pause)
|
|
|
+ hw->fc.requested_mode = I40E_FC_FULL;
|
|
|
+ else if (pause->rx_pause && !pause->tx_pause)
|
|
|
+ hw->fc.requested_mode = I40E_FC_RX_PAUSE;
|
|
|
+ else if (!pause->rx_pause && pause->tx_pause)
|
|
|
+ hw->fc.requested_mode = I40E_FC_TX_PAUSE;
|
|
|
+ else if (!pause->rx_pause && !pause->tx_pause)
|
|
|
+ hw->fc.requested_mode = I40E_FC_NONE;
|
|
|
+ else
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* Set the fc mode and only restart an if link is up*/
|
|
|
+ status = i40e_set_fc(hw, &aq_failures, link_up);
|
|
|
+
|
|
|
+ if (aq_failures & I40E_SET_FC_AQ_FAIL_GET) {
|
|
|
+ netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with error %d and status %d\n",
|
|
|
+ status, hw->aq.asq_last_status);
|
|
|
+ err = -EAGAIN;
|
|
|
+ }
|
|
|
+ if (aq_failures & I40E_SET_FC_AQ_FAIL_SET) {
|
|
|
+ netdev_info(netdev, "Set fc failed on the set_phy_config call with error %d and status %d\n",
|
|
|
+ status, hw->aq.asq_last_status);
|
|
|
+ err = -EAGAIN;
|
|
|
+ }
|
|
|
+ if (aq_failures & I40E_SET_FC_AQ_FAIL_UPDATE) {
|
|
|
+ netdev_info(netdev, "Set fc failed on the update_link_info call with error %d and status %d\n",
|
|
|
+ status, hw->aq.asq_last_status);
|
|
|
+ err = -EAGAIN;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!test_bit(__I40E_DOWN, &pf->state))
|
|
|
+ return i40e_nway_reset(netdev);
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
static u32 i40e_get_msglevel(struct net_device *netdev)
|
|
|
{
|
|
|
struct i40e_netdev_priv *np = netdev_priv(netdev);
|
|
@@ -1021,25 +1376,6 @@ static int i40e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int i40e_nway_reset(struct net_device *netdev)
|
|
|
-{
|
|
|
- /* restart autonegotiation */
|
|
|
- struct i40e_netdev_priv *np = netdev_priv(netdev);
|
|
|
- struct i40e_pf *pf = np->vsi->back;
|
|
|
- struct i40e_hw *hw = &pf->hw;
|
|
|
- bool link_up = hw->phy.link_info.link_info & I40E_AQ_LINK_UP;
|
|
|
- i40e_status ret = 0;
|
|
|
-
|
|
|
- ret = i40e_aq_set_link_restart_an(hw, link_up, NULL);
|
|
|
- if (ret) {
|
|
|
- netdev_info(netdev, "link restart failed, aq_err=%d\n",
|
|
|
- pf->hw.aq.asq_last_status);
|
|
|
- return -EIO;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static int i40e_set_phys_id(struct net_device *netdev,
|
|
|
enum ethtool_phys_id_state state)
|
|
|
{
|
|
@@ -1750,6 +2086,7 @@ static int i40e_set_channels(struct net_device *dev,
|
|
|
|
|
|
static const struct ethtool_ops i40e_ethtool_ops = {
|
|
|
.get_settings = i40e_get_settings,
|
|
|
+ .set_settings = i40e_set_settings,
|
|
|
.get_drvinfo = i40e_get_drvinfo,
|
|
|
.get_regs_len = i40e_get_regs_len,
|
|
|
.get_regs = i40e_get_regs,
|
|
@@ -1762,6 +2099,7 @@ static const struct ethtool_ops i40e_ethtool_ops = {
|
|
|
.get_ringparam = i40e_get_ringparam,
|
|
|
.set_ringparam = i40e_set_ringparam,
|
|
|
.get_pauseparam = i40e_get_pauseparam,
|
|
|
+ .set_pauseparam = i40e_set_pauseparam,
|
|
|
.get_msglevel = i40e_get_msglevel,
|
|
|
.set_msglevel = i40e_set_msglevel,
|
|
|
.get_rxnfc = i40e_get_rxnfc,
|