net/mlx4_en: Fix mixed PFC and Global pause user control requests
authorEran Ben Elisha <eranbe@mellanox.com>
Tue, 27 Mar 2018 11:41:18 +0000 (14:41 +0300)
committerDavid S. Miller <davem@davemloft.net>
Tue, 27 Mar 2018 16:02:30 +0000 (12:02 -0400)
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>
drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
drivers/net/ethernet/mellanox/mlx4/en_main.c

index 1a0c3bf86ead3ad66f377eae5ab0abede7f93d43..752a72499b4f16ebb22c126c258ca35a0f19619d 100644 (file)
@@ -156,57 +156,63 @@ static int mlx4_en_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num)
 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(struct net_device *dev,
        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(struct net_device *dev,
                        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;
 }
index ebc1f566a4d953ab623c5fb4ca6dc018375280e3..f3302edba8b47b6fc67008aec7826e09b94514c1 100644 (file)
@@ -1046,27 +1046,32 @@ static int mlx4_en_set_pauseparam(struct net_device *dev,
 {
        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;
 }
index 2c2965497ed35c5b74d0baeed8ff89ae7f0e52d6..d25e16d2c3191ecff8ed758353203de5f7dc9c07 100644 (file)
@@ -163,9 +163,9 @@ static void mlx4_en_get_profile(struct mlx4_en_dev *mdev)
                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;