net/mlx5e: PFC stall prevention support
authorInbar Karmy <inbark@mellanox.com>
Mon, 20 Nov 2017 16:06:20 +0000 (18:06 +0200)
committerSaeed Mahameed <saeedm@mellanox.com>
Mon, 26 Mar 2018 20:46:46 +0000 (13:46 -0700)
Implement set/get functions to configure PFC stall prevention
timeout by tunables api through ethtool.
By default the stall prevention timeout is configured to 8 sec.
Timeout range is: 80-8000 msec.

Enabling stall prevention with the auto timeout will set
the timeout to 100 msec.

Signed-off-by: Inbar Karmy <inbark@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/port.c
include/linux/mlx5/mlx5_ifc.h
include/linux/mlx5/port.h

index cc8048f68f114452af863a6ef373b5013de710e6..62061fd2314394b3debafabdcce640e988f09377 100644 (file)
@@ -1066,6 +1066,57 @@ static int mlx5e_get_rxnfc(struct net_device *netdev,
        return err;
 }
 
+#define MLX5E_PFC_PREVEN_AUTO_TOUT_MSEC                100
+#define MLX5E_PFC_PREVEN_TOUT_MAX_MSEC         8000
+#define MLX5E_PFC_PREVEN_MINOR_PRECENT         85
+#define MLX5E_PFC_PREVEN_TOUT_MIN_MSEC         80
+#define MLX5E_DEVICE_STALL_MINOR_WATERMARK(critical_tout) \
+       max_t(u16, MLX5E_PFC_PREVEN_TOUT_MIN_MSEC, \
+             (critical_tout * MLX5E_PFC_PREVEN_MINOR_PRECENT) / 100)
+
+static int mlx5e_get_pfc_prevention_tout(struct net_device *netdev,
+                                        u16 *pfc_prevention_tout)
+{
+       struct mlx5e_priv *priv    = netdev_priv(netdev);
+       struct mlx5_core_dev *mdev = priv->mdev;
+
+       if (!MLX5_CAP_PCAM_FEATURE((priv)->mdev, pfcc_mask) ||
+           !MLX5_CAP_DEBUG((priv)->mdev, stall_detect))
+               return -EOPNOTSUPP;
+
+       return mlx5_query_port_stall_watermark(mdev, pfc_prevention_tout, NULL);
+}
+
+static int mlx5e_set_pfc_prevention_tout(struct net_device *netdev,
+                                        u16 pfc_preven)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       struct mlx5_core_dev *mdev = priv->mdev;
+       u16 critical_tout;
+       u16 minor;
+
+       if (!MLX5_CAP_PCAM_FEATURE((priv)->mdev, pfcc_mask) ||
+           !MLX5_CAP_DEBUG((priv)->mdev, stall_detect))
+               return -EOPNOTSUPP;
+
+       critical_tout = (pfc_preven == PFC_STORM_PREVENTION_AUTO) ?
+                       MLX5E_PFC_PREVEN_AUTO_TOUT_MSEC :
+                       pfc_preven;
+
+       if (critical_tout != PFC_STORM_PREVENTION_DISABLE &&
+           (critical_tout > MLX5E_PFC_PREVEN_TOUT_MAX_MSEC ||
+            critical_tout < MLX5E_PFC_PREVEN_TOUT_MIN_MSEC)) {
+               netdev_info(netdev, "%s: pfc prevention tout not in range (%d-%d)\n",
+                           __func__, MLX5E_PFC_PREVEN_TOUT_MIN_MSEC,
+                           MLX5E_PFC_PREVEN_TOUT_MAX_MSEC);
+               return -EINVAL;
+       }
+
+       minor = MLX5E_DEVICE_STALL_MINOR_WATERMARK(critical_tout);
+       return mlx5_set_port_stall_watermark(mdev, critical_tout,
+                                            minor);
+}
+
 static int mlx5e_get_tunable(struct net_device *dev,
                             const struct ethtool_tunable *tuna,
                             void *data)
@@ -1077,6 +1128,9 @@ static int mlx5e_get_tunable(struct net_device *dev,
        case ETHTOOL_TX_COPYBREAK:
                *(u32 *)data = priv->channels.params.tx_max_inline;
                break;
+       case ETHTOOL_PFC_PREVENTION_TOUT:
+               err = mlx5e_get_pfc_prevention_tout(dev, data);
+               break;
        default:
                err = -EINVAL;
                break;
@@ -1118,6 +1172,9 @@ static int mlx5e_set_tunable(struct net_device *dev,
                        break;
                mlx5e_switch_priv_channels(priv, &new_channels, NULL);
 
+               break;
+       case ETHTOOL_PFC_PREVENTION_TOUT:
+               err = mlx5e_set_pfc_prevention_tout(dev, *(u16 *)data);
                break;
        default:
                err = -EINVAL;
index c37d00cd472a99226303f799c83d776a2c15d4e9..fa9d0760dd36ffda5c2c439f12bbdffab6320ccd 100644 (file)
@@ -483,6 +483,17 @@ int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev,
 }
 EXPORT_SYMBOL_GPL(mlx5_core_query_ib_ppcnt);
 
+static int mlx5_query_pfcc_reg(struct mlx5_core_dev *dev, u32 *out,
+                              u32 out_size)
+{
+       u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
+
+       MLX5_SET(pfcc_reg, in, local_port, 1);
+
+       return mlx5_core_access_reg(dev, in, sizeof(in), out,
+                                   out_size, MLX5_REG_PFCC, 0, 0);
+}
+
 int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause)
 {
        u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
@@ -500,13 +511,10 @@ EXPORT_SYMBOL_GPL(mlx5_set_port_pause);
 int mlx5_query_port_pause(struct mlx5_core_dev *dev,
                          u32 *rx_pause, u32 *tx_pause)
 {
-       u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
        u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
        int err;
 
-       MLX5_SET(pfcc_reg, in, local_port, 1);
-       err = mlx5_core_access_reg(dev, in, sizeof(in), out,
-                                  sizeof(out), MLX5_REG_PFCC, 0, 0);
+       err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
        if (err)
                return err;
 
@@ -520,6 +528,49 @@ int mlx5_query_port_pause(struct mlx5_core_dev *dev,
 }
 EXPORT_SYMBOL_GPL(mlx5_query_port_pause);
 
+int mlx5_set_port_stall_watermark(struct mlx5_core_dev *dev,
+                                 u16 stall_critical_watermark,
+                                 u16 stall_minor_watermark)
+{
+       u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
+       u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
+
+       MLX5_SET(pfcc_reg, in, local_port, 1);
+       MLX5_SET(pfcc_reg, in, pptx_mask_n, 1);
+       MLX5_SET(pfcc_reg, in, pprx_mask_n, 1);
+       MLX5_SET(pfcc_reg, in, ppan_mask_n, 1);
+       MLX5_SET(pfcc_reg, in, critical_stall_mask, 1);
+       MLX5_SET(pfcc_reg, in, minor_stall_mask, 1);
+       MLX5_SET(pfcc_reg, in, device_stall_critical_watermark,
+                stall_critical_watermark);
+       MLX5_SET(pfcc_reg, in, device_stall_minor_watermark, stall_minor_watermark);
+
+       return mlx5_core_access_reg(dev, in, sizeof(in), out,
+                                   sizeof(out), MLX5_REG_PFCC, 0, 1);
+}
+
+int mlx5_query_port_stall_watermark(struct mlx5_core_dev *dev,
+                                   u16 *stall_critical_watermark,
+                                   u16 *stall_minor_watermark)
+{
+       u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
+       int err;
+
+       err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
+       if (err)
+               return err;
+
+       if (stall_critical_watermark)
+               *stall_critical_watermark = MLX5_GET(pfcc_reg, out,
+                                                    device_stall_critical_watermark);
+
+       if (stall_minor_watermark)
+               *stall_minor_watermark = MLX5_GET(pfcc_reg, out,
+                                                 device_stall_minor_watermark);
+
+       return 0;
+}
+
 int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx)
 {
        u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
@@ -538,13 +589,10 @@ EXPORT_SYMBOL_GPL(mlx5_set_port_pfc);
 
 int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
 {
-       u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
        u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
        int err;
 
-       MLX5_SET(pfcc_reg, in, local_port, 1);
-       err = mlx5_core_access_reg(dev, in, sizeof(in), out,
-                                  sizeof(out), MLX5_REG_PFCC, 0, 0);
+       err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
        if (err)
                return err;
 
index c7d50eccff9eb8dfacf71b4a04b1cc571ae6fa0d..f3200a9696d649383a7b01d0ce1b4fc274d7b12d 100644 (file)
@@ -7833,7 +7833,11 @@ struct mlx5_ifc_pifr_reg_bits {
 struct mlx5_ifc_pfcc_reg_bits {
        u8         reserved_at_0[0x8];
        u8         local_port[0x8];
-       u8         reserved_at_10[0x10];
+       u8         reserved_at_10[0xb];
+       u8         ppan_mask_n[0x1];
+       u8         minor_stall_mask[0x1];
+       u8         critical_stall_mask[0x1];
+       u8         reserved_at_1e[0x2];
 
        u8         ppan[0x4];
        u8         reserved_at_24[0x4];
@@ -7843,17 +7847,22 @@ struct mlx5_ifc_pfcc_reg_bits {
 
        u8         pptx[0x1];
        u8         aptx[0x1];
-       u8         reserved_at_42[0x6];
+       u8         pptx_mask_n[0x1];
+       u8         reserved_at_43[0x5];
        u8         pfctx[0x8];
        u8         reserved_at_50[0x10];
 
        u8         pprx[0x1];
        u8         aprx[0x1];
-       u8         reserved_at_62[0x6];
+       u8         pprx_mask_n[0x1];
+       u8         reserved_at_63[0x5];
        u8         pfcrx[0x8];
        u8         reserved_at_70[0x10];
 
-       u8         reserved_at_80[0x80];
+       u8         device_stall_minor_watermark[0x10];
+       u8         device_stall_critical_watermark[0x10];
+
+       u8         reserved_at_a0[0x60];
 };
 
 struct mlx5_ifc_pelc_reg_bits {
index 035f0d4dc9fec6abd202f989bd5371895e73bfcc..34aed6032f868317f3140b40ad2d94668d0bd9d9 100644 (file)
@@ -151,6 +151,12 @@ int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx);
 int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx,
                        u8 *pfc_en_rx);
 
+int mlx5_set_port_stall_watermark(struct mlx5_core_dev *dev,
+                                 u16 stall_critical_watermark,
+                                 u16 stall_minor_watermark);
+int mlx5_query_port_stall_watermark(struct mlx5_core_dev *dev,
+                                   u16 *stall_critical_watermark, u16 *stall_minor_watermark);
+
 int mlx5_max_tc(struct mlx5_core_dev *mdev);
 
 int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc);