Commit 2a5e7a13 authored by Huy Nguyen's avatar Huy Nguyen Committed by Saeed Mahameed

net/mlx5e: Add dcbnl dscp to priority support

This patch implements dcbnl hooks to set and delete DSCP to priority map
as defined by the DCB subsystem. Device maintains internal trust state
which needs to be set to DSCP state for performing DSCP to priority mapping.

When the first dscp to priority APP entry is added by the user, the
trust state is changed to dscp.

When the last dscp to priority APP entry is deleted by the user, the
trust state is changed to pcp.

If user sends multiple dscp to priority APP entries on the same dscp,
the last sent one will take effect. All the previous sent will be
deleted.

The dscp to priority APP entries are added and deleted in the net/dcb
APP database using dcb_ieee_setapp/getapp.
Signed-off-by: default avatarHuy Nguyen <huyn@mellanox.com>
Reviewed-by: default avatarParav Pandit <parav@mellanox.com>
Reviewed-by: default avatarOr Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent 415a64aa
......@@ -57,6 +57,7 @@
#define MLX5E_HW2SW_MTU(priv, hwmtu) ((hwmtu) - ((priv)->hard_mtu))
#define MLX5E_SW2HW_MTU(priv, swmtu) ((swmtu) + ((priv)->hard_mtu))
#define MLX5E_MAX_DSCP 64
#define MLX5E_MAX_NUM_TC 8
#define MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE 0x6
......@@ -260,11 +261,17 @@ enum {
struct mlx5e_dcbx {
enum mlx5_dcbx_oper_mode mode;
struct mlx5e_cee_config cee_cfg; /* pending configuration */
u8 dscp_app_cnt;
/* The only setting that cannot be read from FW */
u8 tc_tsa[IEEE_8021QAZ_MAX_TCS];
u8 cap;
};
struct mlx5e_dcbx_dp {
u8 dscp2prio[MLX5E_MAX_DSCP];
u8 trust_state;
};
#endif
enum {
......@@ -742,6 +749,9 @@ struct mlx5e_priv {
/* priv data path fields - start */
struct mlx5e_txqsq *txq2sq[MLX5E_MAX_NUM_CHANNELS * MLX5E_MAX_NUM_TC];
int channel_tc2txq[MLX5E_MAX_NUM_CHANNELS][MLX5E_MAX_NUM_TC];
#ifdef CONFIG_MLX5_CORE_EN_DCB
struct mlx5e_dcbx_dp dcbx_dp;
#endif
/* priv data path fields - end */
unsigned long state;
......@@ -800,6 +810,8 @@ struct mlx5e_profile {
mlx5e_fp_handle_rx_cqe handle_rx_cqe;
mlx5e_fp_handle_rx_cqe handle_rx_cqe_mpwqe;
} rx_handlers;
void (*netdev_registered_init)(struct mlx5e_priv *priv);
void (*netdev_registered_remove)(struct mlx5e_priv *priv);
int max_tc;
};
......@@ -968,6 +980,8 @@ extern const struct ethtool_ops mlx5e_ethtool_ops;
extern const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops;
int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets);
void mlx5e_dcbnl_initialize(struct mlx5e_priv *priv);
void mlx5e_dcbnl_init_app(struct mlx5e_priv *priv);
void mlx5e_dcbnl_delete_app(struct mlx5e_priv *priv);
#endif
#ifndef CONFIG_RFS_ACCEL
......@@ -1069,5 +1083,4 @@ void mlx5e_destroy_netdev(struct mlx5e_priv *priv);
void mlx5e_build_nic_params(struct mlx5_core_dev *mdev,
struct mlx5e_params *params,
u16 max_channels);
#endif /* __MLX5_EN_H__ */
......@@ -46,6 +46,13 @@ enum {
MLX5E_LOWEST_PRIO_GROUP = 0,
};
#define MLX5_DSCP_SUPPORTED(mdev) (MLX5_CAP_GEN(mdev, qcam_reg) && \
MLX5_CAP_QCAM_REG(mdev, qpts) && \
MLX5_CAP_QCAM_REG(mdev, qpdpm))
static int mlx5e_set_trust_state(struct mlx5e_priv *priv, u8 trust_state);
static int mlx5e_set_dscp2prio(struct mlx5e_priv *priv, u8 dscp, u8 prio);
/* If dcbx mode is non-host set the dcbx mode to host.
*/
static int mlx5e_dcbnl_set_dcbx_mode(struct mlx5e_priv *priv,
......@@ -381,6 +388,113 @@ static u8 mlx5e_dcbnl_setdcbx(struct net_device *dev, u8 mode)
return 0;
}
static int mlx5e_dcbnl_ieee_setapp(struct net_device *dev, struct dcb_app *app)
{
struct mlx5e_priv *priv = netdev_priv(dev);
struct dcb_app temp;
bool is_new;
int err;
if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP)
return -EINVAL;
if (!MLX5_CAP_GEN(priv->mdev, vport_group_manager))
return -EINVAL;
if (!MLX5_DSCP_SUPPORTED(priv->mdev))
return -EINVAL;
if (app->protocol >= MLX5E_MAX_DSCP)
return -EINVAL;
/* Save the old entry info */
temp.selector = IEEE_8021QAZ_APP_SEL_DSCP;
temp.protocol = app->protocol;
temp.priority = priv->dcbx_dp.dscp2prio[app->protocol];
/* Check if need to switch to dscp trust state */
if (!priv->dcbx.dscp_app_cnt) {
err = mlx5e_set_trust_state(priv, MLX5_QPTS_TRUST_DSCP);
if (err)
return err;
}
/* Skip the fw command if new and old mapping are the same */
if (app->priority != priv->dcbx_dp.dscp2prio[app->protocol]) {
err = mlx5e_set_dscp2prio(priv, app->protocol, app->priority);
if (err)
goto fw_err;
}
/* Delete the old entry if exists */
is_new = false;
err = dcb_ieee_delapp(dev, &temp);
if (err)
is_new = true;
/* Add new entry and update counter */
err = dcb_ieee_setapp(dev, app);
if (err)
return err;
if (is_new)
priv->dcbx.dscp_app_cnt++;
return err;
fw_err:
mlx5e_set_trust_state(priv, MLX5_QPTS_TRUST_PCP);
return err;
}
static int mlx5e_dcbnl_ieee_delapp(struct net_device *dev, struct dcb_app *app)
{
struct mlx5e_priv *priv = netdev_priv(dev);
int err;
if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP)
return -EINVAL;
if (!MLX5_CAP_GEN(priv->mdev, vport_group_manager))
return -EINVAL;
if (!MLX5_DSCP_SUPPORTED(priv->mdev))
return -EINVAL;
if (app->protocol >= MLX5E_MAX_DSCP)
return -EINVAL;
/* Skip if no dscp app entry */
if (!priv->dcbx.dscp_app_cnt)
return -ENOENT;
/* Check if the entry matches fw setting */
if (app->priority != priv->dcbx_dp.dscp2prio[app->protocol])
return -ENOENT;
/* Delete the app entry */
err = dcb_ieee_delapp(dev, app);
if (err)
return err;
/* Reset the priority mapping back to zero */
err = mlx5e_set_dscp2prio(priv, app->protocol, 0);
if (err)
goto fw_err;
priv->dcbx.dscp_app_cnt--;
/* Check if need to switch to pcp trust state */
if (!priv->dcbx.dscp_app_cnt)
err = mlx5e_set_trust_state(priv, MLX5_QPTS_TRUST_PCP);
return err;
fw_err:
mlx5e_set_trust_state(priv, MLX5_QPTS_TRUST_PCP);
return err;
}
static int mlx5e_dcbnl_ieee_getmaxrate(struct net_device *netdev,
struct ieee_maxrate *maxrate)
{
......@@ -740,6 +854,8 @@ const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops = {
.ieee_setmaxrate = mlx5e_dcbnl_ieee_setmaxrate,
.ieee_getpfc = mlx5e_dcbnl_ieee_getpfc,
.ieee_setpfc = mlx5e_dcbnl_ieee_setpfc,
.ieee_setapp = mlx5e_dcbnl_ieee_setapp,
.ieee_delapp = mlx5e_dcbnl_ieee_delapp,
.getdcbx = mlx5e_dcbnl_getdcbx,
.setdcbx = mlx5e_dcbnl_setdcbx,
......@@ -801,10 +917,98 @@ static void mlx5e_ets_init(struct mlx5e_priv *priv)
mlx5e_dcbnl_ieee_setets_core(priv, &ets);
}
enum {
INIT,
DELETE,
};
static void mlx5e_dcbnl_dscp_app(struct mlx5e_priv *priv, int action)
{
struct dcb_app temp;
int i;
if (!MLX5_CAP_GEN(priv->mdev, vport_group_manager))
return;
if (!MLX5_DSCP_SUPPORTED(priv->mdev))
return;
/* No SEL_DSCP entry in non DSCP state */
if (priv->dcbx_dp.trust_state != MLX5_QPTS_TRUST_DSCP)
return;
temp.selector = IEEE_8021QAZ_APP_SEL_DSCP;
for (i = 0; i < MLX5E_MAX_DSCP; i++) {
temp.protocol = i;
temp.priority = priv->dcbx_dp.dscp2prio[i];
if (action == INIT)
dcb_ieee_setapp(priv->netdev, &temp);
else
dcb_ieee_delapp(priv->netdev, &temp);
}
priv->dcbx.dscp_app_cnt = (action == INIT) ? MLX5E_MAX_DSCP : 0;
}
void mlx5e_dcbnl_init_app(struct mlx5e_priv *priv)
{
mlx5e_dcbnl_dscp_app(priv, INIT);
}
void mlx5e_dcbnl_delete_app(struct mlx5e_priv *priv)
{
mlx5e_dcbnl_dscp_app(priv, DELETE);
}
static int mlx5e_set_trust_state(struct mlx5e_priv *priv, u8 trust_state)
{
int err;
err = mlx5_set_trust_state(priv->mdev, trust_state);
if (err)
return err;
priv->dcbx_dp.trust_state = trust_state;
return err;
}
static int mlx5e_set_dscp2prio(struct mlx5e_priv *priv, u8 dscp, u8 prio)
{
int err;
err = mlx5_set_dscp2prio(priv->mdev, dscp, prio);
if (err)
return err;
priv->dcbx_dp.dscp2prio[dscp] = prio;
return err;
}
static int mlx5e_trust_initialize(struct mlx5e_priv *priv)
{
struct mlx5_core_dev *mdev = priv->mdev;
int err;
if (!MLX5_DSCP_SUPPORTED(mdev))
return 0;
err = mlx5_query_trust_state(priv->mdev, &priv->dcbx_dp.trust_state);
if (err)
return err;
err = mlx5_query_dscp2prio(priv->mdev, priv->dcbx_dp.dscp2prio);
if (err)
return err;
return 0;
}
void mlx5e_dcbnl_initialize(struct mlx5e_priv *priv)
{
struct mlx5e_dcbx *dcbx = &priv->dcbx;
mlx5e_trust_initialize(priv);
if (!MLX5_CAP_GEN(priv->mdev, qos))
return;
......
......@@ -4374,7 +4374,9 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv)
if (netdev->reg_state != NETREG_REGISTERED)
return;
#ifdef CONFIG_MLX5_CORE_EN_DCB
mlx5e_dcbnl_init_app(priv);
#endif
/* Device already registered: sync netdev system state */
if (mlx5e_vxlan_allowed(mdev)) {
rtnl_lock();
......@@ -4395,6 +4397,11 @@ static void mlx5e_nic_disable(struct mlx5e_priv *priv)
{
struct mlx5_core_dev *mdev = priv->mdev;
#ifdef CONFIG_MLX5_CORE_EN_DCB
if (priv->netdev->reg_state == NETREG_REGISTERED)
mlx5e_dcbnl_delete_app(priv);
#endif
rtnl_lock();
if (netif_running(priv->netdev))
mlx5e_close(priv->netdev);
......@@ -4615,6 +4622,9 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev)
goto err_detach;
}
#ifdef CONFIG_MLX5_CORE_EN_DCB
mlx5e_dcbnl_init_app(priv);
#endif
return priv;
err_detach:
......@@ -4631,6 +4641,9 @@ static void mlx5e_remove(struct mlx5_core_dev *mdev, void *vpriv)
struct mlx5e_priv *priv = vpriv;
void *ppriv = priv->ppriv;
#ifdef CONFIG_MLX5_CORE_EN_DCB
mlx5e_dcbnl_delete_app(priv);
#endif
unregister_netdev(priv->netdev);
mlx5e_detach(mdev, vpriv);
mlx5e_destroy_netdev(priv);
......
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