OSDN Git Service

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 3a06c81..c819d07 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;
 
-       if (min_tx_rate)
-               return -EOPNOTSUPP;
-
        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)
index 4b3b60b..efa1a7a 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,
-                               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];
@@ -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);
+       MLX5_SET(scheduling_context, &sched_ctx, bw_share, initial_bw_share);
 
        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,
-                               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];
@@ -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);
+       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_BW_SHARE;
 
        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 */
-       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 */
@@ -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->min_tx_rate = evport->info.min_rate;
        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;
 }
 
-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;
+       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;
+       if ((min_rate && !min_rate_supported) || (max_rate && !max_rate_supported))
+               return -EOPNOTSUPP;
 
        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;
 
+unlock:
        mutex_unlock(&esw->state_lock);
        return err;
 }
index cea1660..5b78883 100644 (file)
 
 #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;
@@ -116,6 +121,7 @@ struct mlx5_vport_info {
        u8                      qos;
        u64                     node_guid;
        int                     link_state;
+       u32                     min_rate;
        u32                     max_rate;
        bool                    spoofchk;
        bool                    trusted;
@@ -138,6 +144,7 @@ struct mlx5_vport {
        struct {
                bool            enabled;
                u32             esw_tsar_ix;
+               u32             bw_share;
        } 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 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,
index d96ebc3..a919dfb 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];
-       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];