net/mlx5: Add support for setting VF min rate
authorMohamad Haj Yahia <mohamad@mellanox.com>
Thu, 15 Dec 2016 12:02:53 +0000 (14:02 +0200)
committerSaeed Mahameed <saeedm@mellanox.com>
Tue, 24 Jan 2017 19:14:04 +0000 (21:14 +0200)
Add support for SRIOV VF min rate guarantee by using the TSAR BW share
weights mechanism.

The TSAR BW share vport attribute represents the weight of that vport
among the other vports weights which means that the actual vport BW
percentage is the same vport weight percentage among the total vports
weights sum.

Signed-off-by: Mohamad Haj Yahia <mohamad@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
include/linux/mlx5/mlx5_ifc.h

index 3a06c81ef85e1cccd854da645475bf047f7708dd..c819d07fbdb381c669ca39f0729b2589a404c24a 100644 (file)
@@ -3021,11 +3021,8 @@ static int mlx5e_set_vf_rate(struct net_device *dev, int vf, int min_tx_rate,
        struct mlx5e_priv *priv = netdev_priv(dev);
        struct mlx5_core_dev *mdev = priv->mdev;
 
        struct mlx5e_priv *priv = netdev_priv(dev);
        struct mlx5_core_dev *mdev = priv->mdev;
 
-       if (min_tx_rate)
-               return -EOPNOTSUPP;
-
        return mlx5_eswitch_set_vport_rate(mdev->priv.eswitch, vf + 1,
        return mlx5_eswitch_set_vport_rate(mdev->priv.eswitch, vf + 1,
-                                          max_tx_rate);
+                                          max_tx_rate, min_tx_rate);
 }
 
 static int mlx5_vport_link2ifla(u8 esw_link)
 }
 
 static int mlx5_vport_link2ifla(u8 esw_link)
index 4b3b60be319d062bf8489457710d0390e61bf031..efa1a7a76d8a8df6e727a5728339a0647551bf2e 100644 (file)
@@ -1415,7 +1415,7 @@ static void esw_destroy_tsar(struct mlx5_eswitch *esw)
 }
 
 static int esw_vport_enable_qos(struct mlx5_eswitch *esw, int vport_num,
 }
 
 static int esw_vport_enable_qos(struct mlx5_eswitch *esw, int vport_num,
-                               u32 initial_max_rate)
+                               u32 initial_max_rate, u32 initial_bw_share)
 {
        u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0};
        struct mlx5_vport *vport = &esw->vports[vport_num];
 {
        u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0};
        struct mlx5_vport *vport = &esw->vports[vport_num];
@@ -1439,6 +1439,7 @@ static int esw_vport_enable_qos(struct mlx5_eswitch *esw, int vport_num,
                 esw->qos.root_tsar_id);
        MLX5_SET(scheduling_context, &sched_ctx, max_average_bw,
                 initial_max_rate);
                 esw->qos.root_tsar_id);
        MLX5_SET(scheduling_context, &sched_ctx, max_average_bw,
                 initial_max_rate);
+       MLX5_SET(scheduling_context, &sched_ctx, bw_share, initial_bw_share);
 
        err = mlx5_create_scheduling_element_cmd(dev,
                                                 SCHEDULING_HIERARCHY_E_SWITCH,
 
        err = mlx5_create_scheduling_element_cmd(dev,
                                                 SCHEDULING_HIERARCHY_E_SWITCH,
@@ -1473,7 +1474,7 @@ static void esw_vport_disable_qos(struct mlx5_eswitch *esw, int vport_num)
 }
 
 static int esw_vport_qos_config(struct mlx5_eswitch *esw, int vport_num,
 }
 
 static int esw_vport_qos_config(struct mlx5_eswitch *esw, int vport_num,
-                               u32 max_rate)
+                               u32 max_rate, u32 bw_share)
 {
        u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0};
        struct mlx5_vport *vport = &esw->vports[vport_num];
 {
        u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0};
        struct mlx5_vport *vport = &esw->vports[vport_num];
@@ -1497,7 +1498,9 @@ static int esw_vport_qos_config(struct mlx5_eswitch *esw, int vport_num,
                 esw->qos.root_tsar_id);
        MLX5_SET(scheduling_context, &sched_ctx, max_average_bw,
                 max_rate);
                 esw->qos.root_tsar_id);
        MLX5_SET(scheduling_context, &sched_ctx, max_average_bw,
                 max_rate);
+       MLX5_SET(scheduling_context, &sched_ctx, bw_share, bw_share);
        bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
        bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
+       bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_BW_SHARE;
 
        err = mlx5_modify_scheduling_element_cmd(dev,
                                                 SCHEDULING_HIERARCHY_E_SWITCH,
 
        err = mlx5_modify_scheduling_element_cmd(dev,
                                                 SCHEDULING_HIERARCHY_E_SWITCH,
@@ -1563,7 +1566,8 @@ static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num,
        esw_apply_vport_conf(esw, vport);
 
        /* Attach vport to the eswitch rate limiter */
        esw_apply_vport_conf(esw, vport);
 
        /* Attach vport to the eswitch rate limiter */
-       if (esw_vport_enable_qos(esw, vport_num, vport->info.max_rate))
+       if (esw_vport_enable_qos(esw, vport_num, vport->info.max_rate,
+                                vport->qos.bw_share))
                esw_warn(esw->dev, "Failed to attach vport %d to eswitch rate limiter", vport_num);
 
        /* Sync with current vport context */
                esw_warn(esw->dev, "Failed to attach vport %d to eswitch rate limiter", vport_num);
 
        /* Sync with current vport context */
@@ -1952,6 +1956,7 @@ int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
        ivi->qos = evport->info.qos;
        ivi->spoofchk = evport->info.spoofchk;
        ivi->trusted = evport->info.trusted;
        ivi->qos = evport->info.qos;
        ivi->spoofchk = evport->info.spoofchk;
        ivi->trusted = evport->info.trusted;
+       ivi->min_tx_rate = evport->info.min_rate;
        ivi->max_tx_rate = evport->info.max_rate;
        mutex_unlock(&esw->state_lock);
 
        ivi->max_tx_rate = evport->info.max_rate;
        mutex_unlock(&esw->state_lock);
 
@@ -2046,23 +2051,103 @@ int mlx5_eswitch_set_vport_trust(struct mlx5_eswitch *esw,
        return 0;
 }
 
        return 0;
 }
 
-int mlx5_eswitch_set_vport_rate(struct mlx5_eswitch *esw,
-                               int vport, u32 max_rate)
+static u32 calculate_vports_min_rate_divider(struct mlx5_eswitch *esw)
 {
 {
+       u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
        struct mlx5_vport *evport;
        struct mlx5_vport *evport;
+       u32 max_guarantee = 0;
+       int i;
+
+       for (i = 0; i <= esw->total_vports; i++) {
+               evport = &esw->vports[i];
+               if (!evport->enabled || evport->info.min_rate < max_guarantee)
+                       continue;
+               max_guarantee = evport->info.min_rate;
+       }
+
+       return max_t(u32, max_guarantee / fw_max_bw_share, 1);
+}
+
+static int normalize_vports_min_rate(struct mlx5_eswitch *esw, u32 divider)
+{
+       u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
+       struct mlx5_vport *evport;
+       u32 vport_max_rate;
+       u32 vport_min_rate;
+       u32 bw_share;
+       int err;
+       int i;
+
+       for (i = 0; i <= esw->total_vports; i++) {
+               evport = &esw->vports[i];
+               if (!evport->enabled)
+                       continue;
+               vport_min_rate = evport->info.min_rate;
+               vport_max_rate = evport->info.max_rate;
+               bw_share = MLX5_MIN_BW_SHARE;
+
+               if (vport_min_rate)
+                       bw_share = MLX5_RATE_TO_BW_SHARE(vport_min_rate,
+                                                        divider,
+                                                        fw_max_bw_share);
+
+               if (bw_share == evport->qos.bw_share)
+                       continue;
+
+               err = esw_vport_qos_config(esw, i, vport_max_rate,
+                                          bw_share);
+               if (!err)
+                       evport->qos.bw_share = bw_share;
+               else
+                       return err;
+       }
+
+       return 0;
+}
+
+int mlx5_eswitch_set_vport_rate(struct mlx5_eswitch *esw, int vport,
+                               u32 max_rate, u32 min_rate)
+{
+       u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
+       bool min_rate_supported = MLX5_CAP_QOS(esw->dev, esw_bw_share) &&
+                                       fw_max_bw_share >= MLX5_MIN_BW_SHARE;
+       bool max_rate_supported = MLX5_CAP_QOS(esw->dev, esw_rate_limit);
+       struct mlx5_vport *evport;
+       u32 previous_min_rate;
+       u32 divider;
        int err = 0;
 
        if (!ESW_ALLOWED(esw))
                return -EPERM;
        if (!LEGAL_VPORT(esw, vport))
                return -EINVAL;
        int err = 0;
 
        if (!ESW_ALLOWED(esw))
                return -EPERM;
        if (!LEGAL_VPORT(esw, vport))
                return -EINVAL;
+       if ((min_rate && !min_rate_supported) || (max_rate && !max_rate_supported))
+               return -EOPNOTSUPP;
 
        mutex_lock(&esw->state_lock);
        evport = &esw->vports[vport];
 
        mutex_lock(&esw->state_lock);
        evport = &esw->vports[vport];
-       err = esw_vport_qos_config(esw, vport, max_rate);
+
+       if (min_rate == evport->info.min_rate)
+               goto set_max_rate;
+
+       previous_min_rate = evport->info.min_rate;
+       evport->info.min_rate = min_rate;
+       divider = calculate_vports_min_rate_divider(esw);
+       err = normalize_vports_min_rate(esw, divider);
+       if (err) {
+               evport->info.min_rate = previous_min_rate;
+               goto unlock;
+       }
+
+set_max_rate:
+       if (max_rate == evport->info.max_rate)
+               goto unlock;
+
+       err = esw_vport_qos_config(esw, vport, max_rate, evport->qos.bw_share);
        if (!err)
                evport->info.max_rate = max_rate;
 
        if (!err)
                evport->info.max_rate = max_rate;
 
+unlock:
        mutex_unlock(&esw->state_lock);
        return err;
 }
        mutex_unlock(&esw->state_lock);
        return err;
 }
index cea1660d59ac6e5dd1d01651c7bba9ae04525e95..5b78883d565413ec59a00ecba4ddb483e4eecd3f 100644 (file)
 
 #define FDB_UPLINK_VPORT 0xffff
 
 
 #define FDB_UPLINK_VPORT 0xffff
 
+#define MLX5_MIN_BW_SHARE 1
+
+#define MLX5_RATE_TO_BW_SHARE(rate, divider, limit) \
+       min_t(u32, max_t(u32, (rate) / (divider), MLX5_MIN_BW_SHARE), limit)
+
 /* L2 -mac address based- hash helpers */
 struct l2addr_node {
        struct hlist_node hlist;
 /* L2 -mac address based- hash helpers */
 struct l2addr_node {
        struct hlist_node hlist;
@@ -116,6 +121,7 @@ struct mlx5_vport_info {
        u8                      qos;
        u64                     node_guid;
        int                     link_state;
        u8                      qos;
        u64                     node_guid;
        int                     link_state;
+       u32                     min_rate;
        u32                     max_rate;
        bool                    spoofchk;
        bool                    trusted;
        u32                     max_rate;
        bool                    spoofchk;
        bool                    trusted;
@@ -138,6 +144,7 @@ struct mlx5_vport {
        struct {
                bool            enabled;
                u32             esw_tsar_ix;
        struct {
                bool            enabled;
                u32             esw_tsar_ix;
+               u32             bw_share;
        } qos;
 
        bool                    enabled;
        } qos;
 
        bool                    enabled;
@@ -249,8 +256,8 @@ int mlx5_eswitch_set_vport_spoofchk(struct mlx5_eswitch *esw,
                                    int vport, bool spoofchk);
 int mlx5_eswitch_set_vport_trust(struct mlx5_eswitch *esw,
                                 int vport_num, bool setting);
                                    int vport, bool spoofchk);
 int mlx5_eswitch_set_vport_trust(struct mlx5_eswitch *esw,
                                 int vport_num, bool setting);
-int mlx5_eswitch_set_vport_rate(struct mlx5_eswitch *esw,
-                               int vport, u32 max_rate);
+int mlx5_eswitch_set_vport_rate(struct mlx5_eswitch *esw, int vport,
+                               u32 max_rate, u32 min_rate);
 int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
                                  int vport, struct ifla_vf_info *ivi);
 int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
 int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
                                  int vport, struct ifla_vf_info *ivi);
 int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
index d96ebc319d63a3b2a846fe8a987b7bafb796d380..a919dfb920ae60c27140823e644e685cb6e5464b 100644 (file)
@@ -547,7 +547,9 @@ struct mlx5_ifc_e_switch_cap_bits {
 struct mlx5_ifc_qos_cap_bits {
        u8         packet_pacing[0x1];
        u8         esw_scheduling[0x1];
 struct mlx5_ifc_qos_cap_bits {
        u8         packet_pacing[0x1];
        u8         esw_scheduling[0x1];
-       u8         reserved_at_2[0x1e];
+       u8         esw_bw_share[0x1];
+       u8         esw_rate_limit[0x1];
+       u8         reserved_at_4[0x1c];
 
        u8         reserved_at_20[0x20];
 
 
        u8         reserved_at_20[0x20];