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:
Michael Chan 2020-09-20 21:08:56 -04:00 committed by Greg Kroah-Hartman
parent 1627f9325d
commit ee0491c290

View file

@ -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;
} }