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: Inbar Karmy <inbark@mellanox.com> Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
This commit is contained in:

committed by
Saeed Mahameed

parent
e1577c1c88
commit
2afa609f5c
@@ -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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
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);
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
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);
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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);
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user