Commit a5390690 authored by Michael Chan's avatar Michael Chan Committed by David S. Miller

bnxt_en: Protect bnxt_set_eee() and bnxt_set_pauseparam() with mutex.

All changes related to bp->link_info require the protection of the
link_lock mutex.  It's not sufficient to rely just on RTNL.

Fixes: 163e9ef6 ("bnxt_en: Fix race when modifying pause settings.")
Reviewed-by: default avatarEdwin Peer <edwin.peer@broadcom.com>
Signed-off-by: default avatarMichael Chan <michael.chan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d69753fa
...@@ -1788,9 +1788,12 @@ static int bnxt_set_pauseparam(struct net_device *dev, ...@@ -1788,9 +1788,12 @@ static int bnxt_set_pauseparam(struct net_device *dev,
if (!BNXT_PHY_CFG_ABLE(bp)) if (!BNXT_PHY_CFG_ABLE(bp))
return -EOPNOTSUPP; return -EOPNOTSUPP;
mutex_lock(&bp->link_lock);
if (epause->autoneg) { if (epause->autoneg) {
if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {
return -EINVAL; rc = -EINVAL;
goto pause_exit;
}
link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL;
if (bp->hwrm_spec_code >= 0x10201) if (bp->hwrm_spec_code >= 0x10201)
...@@ -1811,11 +1814,11 @@ static int bnxt_set_pauseparam(struct net_device *dev, ...@@ -1811,11 +1814,11 @@ static int bnxt_set_pauseparam(struct net_device *dev,
if (epause->tx_pause) if (epause->tx_pause)
link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX; link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX;
if (netif_running(dev)) { if (netif_running(dev))
mutex_lock(&bp->link_lock);
rc = bnxt_hwrm_set_pause(bp); rc = bnxt_hwrm_set_pause(bp);
mutex_unlock(&bp->link_lock);
} pause_exit:
mutex_unlock(&bp->link_lock);
return rc; return rc;
} }
...@@ -2552,8 +2555,7 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) ...@@ -2552,8 +2555,7 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata)
struct bnxt *bp = netdev_priv(dev); struct bnxt *bp = netdev_priv(dev);
struct ethtool_eee *eee = &bp->eee; struct ethtool_eee *eee = &bp->eee;
struct bnxt_link_info *link_info = &bp->link_info; struct bnxt_link_info *link_info = &bp->link_info;
u32 advertising = u32 advertising;
_bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0);
int rc = 0; int rc = 0;
if (!BNXT_PHY_CFG_ABLE(bp)) if (!BNXT_PHY_CFG_ABLE(bp))
...@@ -2562,19 +2564,23 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) ...@@ -2562,19 +2564,23 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata)
if (!(bp->flags & BNXT_FLAG_EEE_CAP)) if (!(bp->flags & BNXT_FLAG_EEE_CAP))
return -EOPNOTSUPP; return -EOPNOTSUPP;
mutex_lock(&bp->link_lock);
advertising = _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0);
if (!edata->eee_enabled) if (!edata->eee_enabled)
goto eee_ok; goto eee_ok;
if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) { if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {
netdev_warn(dev, "EEE requires autoneg\n"); netdev_warn(dev, "EEE requires autoneg\n");
return -EINVAL; rc = -EINVAL;
goto eee_exit;
} }
if (edata->tx_lpi_enabled) { if (edata->tx_lpi_enabled) {
if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi || if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi ||
edata->tx_lpi_timer < bp->lpi_tmr_lo)) { edata->tx_lpi_timer < bp->lpi_tmr_lo)) {
netdev_warn(dev, "Valid LPI timer range is %d and %d microsecs\n", netdev_warn(dev, "Valid LPI timer range is %d and %d microsecs\n",
bp->lpi_tmr_lo, bp->lpi_tmr_hi); bp->lpi_tmr_lo, bp->lpi_tmr_hi);
return -EINVAL; rc = -EINVAL;
goto eee_exit;
} else if (!bp->lpi_tmr_hi) { } else if (!bp->lpi_tmr_hi) {
edata->tx_lpi_timer = eee->tx_lpi_timer; edata->tx_lpi_timer = eee->tx_lpi_timer;
} }
...@@ -2584,7 +2590,8 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) ...@@ -2584,7 +2590,8 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata)
} else if (edata->advertised & ~advertising) { } else if (edata->advertised & ~advertising) {
netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n", netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n",
edata->advertised, advertising); edata->advertised, advertising);
return -EINVAL; rc = -EINVAL;
goto eee_exit;
} }
eee->advertised = edata->advertised; eee->advertised = edata->advertised;
...@@ -2596,6 +2603,8 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) ...@@ -2596,6 +2603,8 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata)
if (netif_running(dev)) if (netif_running(dev))
rc = bnxt_hwrm_set_link_setting(bp, false, true); rc = bnxt_hwrm_set_link_setting(bp, false, true);
eee_exit:
mutex_unlock(&bp->link_lock);
return rc; return rc;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment