| From foo@baz Wed Apr 11 10:26:56 CEST 2018 |
| From: Eran Ben Elisha <eranbe@mellanox.com> |
| Date: Tue, 27 Mar 2018 14:41:18 +0300 |
| Subject: net/mlx4_en: Fix mixed PFC and Global pause user control requests |
| |
| From: Eran Ben Elisha <eranbe@mellanox.com> |
| |
| |
| [ Upstream commit 6e8814ceb7e8f468659ef9253bd212c07ae19584 ] |
| |
| Global pause and PFC configuration should be mutually exclusive (i.e. only |
| one of them at most can be set). However, once PFC was turned off, |
| driver automatically turned Global pause on. This is a bug. |
| |
| Fix the driver behaviour to turn off PFC/Global once the user turned the |
| other on. |
| |
| This also fixed a weird behaviour that at a current time, the profile |
| had both PFC and global pause configuration turned on, which is |
| Hardware-wise impossible and caused returning false positive indication |
| to query tools. |
| |
| In addition, fix error code when setting global pause or PFC to change |
| metadata only upon successful change. |
| |
| Also, removed useless debug print. |
| |
| Fixes: af7d51852631 ("net/mlx4_en: Add DCB PFC support through CEE netlink commands") |
| Fixes: c27a02cd94d6 ("mlx4_en: Add driver for Mellanox ConnectX 10GbE NIC") |
| Signed-off-by: Eran Ben Elisha <eranbe@mellanox.com> |
| Signed-off-by: Tariq Toukan <tariqt@mellanox.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c | 72 +++++++++++++----------- |
| drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 33 ++++++----- |
| drivers/net/ethernet/mellanox/mlx4/en_main.c | 4 - |
| 3 files changed, 62 insertions(+), 47 deletions(-) |
| |
| --- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c |
| +++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c |
| @@ -156,57 +156,63 @@ static int mlx4_en_dcbnl_getnumtcs(struc |
| static u8 mlx4_en_dcbnl_set_all(struct net_device *netdev) |
| { |
| struct mlx4_en_priv *priv = netdev_priv(netdev); |
| + struct mlx4_en_port_profile *prof = priv->prof; |
| struct mlx4_en_dev *mdev = priv->mdev; |
| + u8 tx_pause, tx_ppp, rx_pause, rx_ppp; |
| |
| if (!(priv->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) |
| return 1; |
| |
| if (priv->cee_config.pfc_state) { |
| int tc; |
| + rx_ppp = prof->rx_ppp; |
| + tx_ppp = prof->tx_ppp; |
| |
| - priv->prof->rx_pause = 0; |
| - priv->prof->tx_pause = 0; |
| for (tc = 0; tc < CEE_DCBX_MAX_PRIO; tc++) { |
| u8 tc_mask = 1 << tc; |
| |
| switch (priv->cee_config.dcb_pfc[tc]) { |
| case pfc_disabled: |
| - priv->prof->tx_ppp &= ~tc_mask; |
| - priv->prof->rx_ppp &= ~tc_mask; |
| + tx_ppp &= ~tc_mask; |
| + rx_ppp &= ~tc_mask; |
| break; |
| case pfc_enabled_full: |
| - priv->prof->tx_ppp |= tc_mask; |
| - priv->prof->rx_ppp |= tc_mask; |
| + tx_ppp |= tc_mask; |
| + rx_ppp |= tc_mask; |
| break; |
| case pfc_enabled_tx: |
| - priv->prof->tx_ppp |= tc_mask; |
| - priv->prof->rx_ppp &= ~tc_mask; |
| + tx_ppp |= tc_mask; |
| + rx_ppp &= ~tc_mask; |
| break; |
| case pfc_enabled_rx: |
| - priv->prof->tx_ppp &= ~tc_mask; |
| - priv->prof->rx_ppp |= tc_mask; |
| + tx_ppp &= ~tc_mask; |
| + rx_ppp |= tc_mask; |
| break; |
| default: |
| break; |
| } |
| } |
| - en_dbg(DRV, priv, "Set pfc on\n"); |
| + rx_pause = !!(rx_ppp || tx_ppp) ? 0 : prof->rx_pause; |
| + tx_pause = !!(rx_ppp || tx_ppp) ? 0 : prof->tx_pause; |
| } else { |
| - priv->prof->rx_pause = 1; |
| - priv->prof->tx_pause = 1; |
| - en_dbg(DRV, priv, "Set pfc off\n"); |
| + rx_ppp = 0; |
| + tx_ppp = 0; |
| + rx_pause = prof->rx_pause; |
| + tx_pause = prof->tx_pause; |
| } |
| |
| if (mlx4_SET_PORT_general(mdev->dev, priv->port, |
| priv->rx_skb_size + ETH_FCS_LEN, |
| - priv->prof->tx_pause, |
| - priv->prof->tx_ppp, |
| - priv->prof->rx_pause, |
| - priv->prof->rx_ppp)) { |
| + tx_pause, tx_ppp, rx_pause, rx_ppp)) { |
| en_err(priv, "Failed setting pause params\n"); |
| return 1; |
| } |
| |
| + prof->tx_ppp = tx_ppp; |
| + prof->rx_ppp = rx_ppp; |
| + prof->tx_pause = tx_pause; |
| + prof->rx_pause = rx_pause; |
| + |
| return 0; |
| } |
| |
| @@ -408,6 +414,7 @@ static int mlx4_en_dcbnl_ieee_setpfc(str |
| struct mlx4_en_priv *priv = netdev_priv(dev); |
| struct mlx4_en_port_profile *prof = priv->prof; |
| struct mlx4_en_dev *mdev = priv->mdev; |
| + u32 tx_pause, tx_ppp, rx_pause, rx_ppp; |
| int err; |
| |
| en_dbg(DRV, priv, "cap: 0x%x en: 0x%x mbc: 0x%x delay: %d\n", |
| @@ -416,23 +423,26 @@ static int mlx4_en_dcbnl_ieee_setpfc(str |
| pfc->mbc, |
| pfc->delay); |
| |
| - prof->rx_pause = !pfc->pfc_en; |
| - prof->tx_pause = !pfc->pfc_en; |
| - prof->rx_ppp = pfc->pfc_en; |
| - prof->tx_ppp = pfc->pfc_en; |
| + rx_pause = prof->rx_pause && !pfc->pfc_en; |
| + tx_pause = prof->tx_pause && !pfc->pfc_en; |
| + rx_ppp = pfc->pfc_en; |
| + tx_ppp = pfc->pfc_en; |
| |
| err = mlx4_SET_PORT_general(mdev->dev, priv->port, |
| priv->rx_skb_size + ETH_FCS_LEN, |
| - prof->tx_pause, |
| - prof->tx_ppp, |
| - prof->rx_pause, |
| - prof->rx_ppp); |
| - if (err) |
| + tx_pause, tx_ppp, rx_pause, rx_ppp); |
| + if (err) { |
| en_err(priv, "Failed setting pause params\n"); |
| - else |
| - mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap, |
| - prof->rx_ppp, prof->rx_pause, |
| - prof->tx_ppp, prof->tx_pause); |
| + return err; |
| + } |
| + |
| + mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap, |
| + rx_ppp, rx_pause, tx_ppp, tx_pause); |
| + |
| + prof->tx_ppp = tx_ppp; |
| + prof->rx_ppp = rx_ppp; |
| + prof->rx_pause = rx_pause; |
| + prof->tx_pause = tx_pause; |
| |
| return err; |
| } |
| --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c |
| +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c |
| @@ -1003,27 +1003,32 @@ static int mlx4_en_set_pauseparam(struct |
| { |
| struct mlx4_en_priv *priv = netdev_priv(dev); |
| struct mlx4_en_dev *mdev = priv->mdev; |
| + u8 tx_pause, tx_ppp, rx_pause, rx_ppp; |
| int err; |
| |
| if (pause->autoneg) |
| return -EINVAL; |
| |
| - priv->prof->tx_pause = pause->tx_pause != 0; |
| - priv->prof->rx_pause = pause->rx_pause != 0; |
| + tx_pause = !!(pause->tx_pause); |
| + rx_pause = !!(pause->rx_pause); |
| + rx_ppp = priv->prof->rx_ppp && !(tx_pause || rx_pause); |
| + tx_ppp = priv->prof->tx_ppp && !(tx_pause || rx_pause); |
| + |
| err = mlx4_SET_PORT_general(mdev->dev, priv->port, |
| priv->rx_skb_size + ETH_FCS_LEN, |
| - priv->prof->tx_pause, |
| - priv->prof->tx_ppp, |
| - priv->prof->rx_pause, |
| - priv->prof->rx_ppp); |
| - if (err) |
| - en_err(priv, "Failed setting pause params\n"); |
| - else |
| - mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap, |
| - priv->prof->rx_ppp, |
| - priv->prof->rx_pause, |
| - priv->prof->tx_ppp, |
| - priv->prof->tx_pause); |
| + tx_pause, tx_ppp, rx_pause, rx_ppp); |
| + if (err) { |
| + en_err(priv, "Failed setting pause params, err = %d\n", err); |
| + return err; |
| + } |
| + |
| + mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap, |
| + rx_ppp, rx_pause, tx_ppp, tx_pause); |
| + |
| + priv->prof->tx_pause = tx_pause; |
| + priv->prof->rx_pause = rx_pause; |
| + priv->prof->tx_ppp = tx_ppp; |
| + priv->prof->rx_ppp = rx_ppp; |
| |
| return err; |
| } |
| --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c |
| +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c |
| @@ -163,9 +163,9 @@ static int mlx4_en_get_profile(struct ml |
| params->udp_rss = 0; |
| } |
| for (i = 1; i <= MLX4_MAX_PORTS; i++) { |
| - params->prof[i].rx_pause = 1; |
| + params->prof[i].rx_pause = !(pfcrx || pfctx); |
| params->prof[i].rx_ppp = pfcrx; |
| - params->prof[i].tx_pause = 1; |
| + params->prof[i].tx_pause = !(pfcrx || pfctx); |
| params->prof[i].tx_ppp = pfctx; |
| params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; |
| params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; |