Commit 2afa609f authored by Inbar Karmy's avatar Inbar Karmy Committed by Saeed Mahameed

net/mlx5e: PFC stall prevention support

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: default avatarInbar Karmy <inbark@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent e1577c1c
...@@ -1066,6 +1066,57 @@ static int mlx5e_get_rxnfc(struct net_device *netdev, ...@@ -1066,6 +1066,57 @@ static int mlx5e_get_rxnfc(struct net_device *netdev,
return err; 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, static int mlx5e_get_tunable(struct net_device *dev,
const struct ethtool_tunable *tuna, const struct ethtool_tunable *tuna,
void *data) void *data)
...@@ -1077,6 +1128,9 @@ static int mlx5e_get_tunable(struct net_device *dev, ...@@ -1077,6 +1128,9 @@ static int mlx5e_get_tunable(struct net_device *dev,
case ETHTOOL_TX_COPYBREAK: case ETHTOOL_TX_COPYBREAK:
*(u32 *)data = priv->channels.params.tx_max_inline; *(u32 *)data = priv->channels.params.tx_max_inline;
break; break;
case ETHTOOL_PFC_PREVENTION_TOUT:
err = mlx5e_get_pfc_prevention_tout(dev, data);
break;
default: default:
err = -EINVAL; err = -EINVAL;
break; break;
...@@ -1118,6 +1172,9 @@ static int mlx5e_set_tunable(struct net_device *dev, ...@@ -1118,6 +1172,9 @@ static int mlx5e_set_tunable(struct net_device *dev,
break; break;
mlx5e_switch_priv_channels(priv, &new_channels, NULL); mlx5e_switch_priv_channels(priv, &new_channels, NULL);
break;
case ETHTOOL_PFC_PREVENTION_TOUT:
err = mlx5e_set_pfc_prevention_tout(dev, *(u16 *)data);
break; break;
default: default:
err = -EINVAL; err = -EINVAL;
......
...@@ -483,6 +483,17 @@ int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev, ...@@ -483,6 +483,17 @@ int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev,
} }
EXPORT_SYMBOL_GPL(mlx5_core_query_ib_ppcnt); 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) 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}; u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
...@@ -500,13 +511,10 @@ EXPORT_SYMBOL_GPL(mlx5_set_port_pause); ...@@ -500,13 +511,10 @@ EXPORT_SYMBOL_GPL(mlx5_set_port_pause);
int mlx5_query_port_pause(struct mlx5_core_dev *dev, int mlx5_query_port_pause(struct mlx5_core_dev *dev,
u32 *rx_pause, u32 *tx_pause) u32 *rx_pause, u32 *tx_pause)
{ {
u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
u32 out[MLX5_ST_SZ_DW(pfcc_reg)]; u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
int err; int err;
MLX5_SET(pfcc_reg, in, local_port, 1); err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
err = mlx5_core_access_reg(dev, in, sizeof(in), out,
sizeof(out), MLX5_REG_PFCC, 0, 0);
if (err) if (err)
return err; return err;
...@@ -520,6 +528,49 @@ int mlx5_query_port_pause(struct mlx5_core_dev *dev, ...@@ -520,6 +528,49 @@ int mlx5_query_port_pause(struct mlx5_core_dev *dev,
} }
EXPORT_SYMBOL_GPL(mlx5_query_port_pause); 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) 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}; u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
...@@ -538,13 +589,10 @@ EXPORT_SYMBOL_GPL(mlx5_set_port_pfc); ...@@ -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) 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)]; u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
int err; int err;
MLX5_SET(pfcc_reg, in, local_port, 1); err = mlx5_query_pfcc_reg(dev, out, sizeof(out));
err = mlx5_core_access_reg(dev, in, sizeof(in), out,
sizeof(out), MLX5_REG_PFCC, 0, 0);
if (err) if (err)
return err; return err;
......
...@@ -7833,7 +7833,11 @@ struct mlx5_ifc_pifr_reg_bits { ...@@ -7833,7 +7833,11 @@ struct mlx5_ifc_pifr_reg_bits {
struct mlx5_ifc_pfcc_reg_bits { struct mlx5_ifc_pfcc_reg_bits {
u8 reserved_at_0[0x8]; u8 reserved_at_0[0x8];
u8 local_port[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 ppan[0x4];
u8 reserved_at_24[0x4]; u8 reserved_at_24[0x4];
...@@ -7843,17 +7847,22 @@ struct mlx5_ifc_pfcc_reg_bits { ...@@ -7843,17 +7847,22 @@ struct mlx5_ifc_pfcc_reg_bits {
u8 pptx[0x1]; u8 pptx[0x1];
u8 aptx[0x1]; u8 aptx[0x1];
u8 reserved_at_42[0x6]; u8 pptx_mask_n[0x1];
u8 reserved_at_43[0x5];
u8 pfctx[0x8]; u8 pfctx[0x8];
u8 reserved_at_50[0x10]; u8 reserved_at_50[0x10];
u8 pprx[0x1]; u8 pprx[0x1];
u8 aprx[0x1]; u8 aprx[0x1];
u8 reserved_at_62[0x6]; u8 pprx_mask_n[0x1];
u8 reserved_at_63[0x5];
u8 pfcrx[0x8]; u8 pfcrx[0x8];
u8 reserved_at_70[0x10]; 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 { struct mlx5_ifc_pelc_reg_bits {
......
...@@ -151,6 +151,12 @@ int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx); ...@@ -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, int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx,
u8 *pfc_en_rx); 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_max_tc(struct mlx5_core_dev *mdev);
int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc); int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment