net/mlx5e: Add dcbnl dscp to priority support
authorHuy Nguyen <huyn@mellanox.com>
Tue, 18 Jul 2017 21:23:36 +0000 (16:23 -0500)
committerSaeed Mahameed <saeedm@mellanox.com>
Sun, 5 Nov 2017 04:26:31 +0000 (21:26 -0700)
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: Huy Nguyen <huyn@mellanox.com>
Reviewed-by: Parav Pandit <parav@mellanox.com>
Reviewed-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c

index e613ce02216de9dae6bb6e435cfab4d6850e9564..ab6f0c18850fab759c29c49098cf49a9c14f81d9 100644 (file)
@@ -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__ */
index 51c4cc00a186589734121efc796f2606c0e2c3fe..aa59c432415944fa3ff6ed1678e0261922702d3d 100644 (file)
@@ -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;
 
index 28ae00b3eb88abcbbc2368b0ff423e6464aad8da..8633476fb53624432a77723b7e5cc24827e4ca30 100644 (file)
@@ -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);