bnxt_en: Protect bnxt_set_eee() and bnxt_set_pauseparam() with mutex.
[ Upstream commit a53906908148d64423398a62c4435efb0d09652c ] 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: 163e9ef63641 ("bnxt_en: Fix race when modifying pause settings.") Reviewed-by: Edwin Peer <edwin.peer@broadcom.com> Signed-off-by: Michael Chan <michael.chan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
1627f9325d
commit
ee0491c290
1 changed files with 20 additions and 11 deletions
|
@ -1369,9 +1369,12 @@ static int bnxt_set_pauseparam(struct net_device *dev,
|
||||||
if (!BNXT_SINGLE_PF(bp))
|
if (!BNXT_SINGLE_PF(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)
|
||||||
|
@ -1392,11 +1395,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2113,8 +2116,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_SINGLE_PF(bp))
|
if (!BNXT_SINGLE_PF(bp))
|
||||||
|
@ -2123,19 +2125,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;
|
||||||
}
|
}
|
||||||
|
@ -2145,7 +2151,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;
|
||||||
|
@ -2157,6 +2164,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue