return port;
 }
 
+static int mlx4_set_vport_qos(struct mlx4_priv *priv, int slave, int port,
+                             int max_tx_rate)
+{
+       int i;
+       int err;
+       struct mlx4_qos_manager *port_qos;
+       struct mlx4_dev *dev = &priv->dev;
+       struct mlx4_vport_qos_param vpp_qos[MLX4_NUM_UP];
+
+       port_qos = &priv->mfunc.master.qos_ctl[port];
+       memset(vpp_qos, 0, sizeof(struct mlx4_vport_qos_param) * MLX4_NUM_UP);
+
+       if (slave > port_qos->num_of_qos_vfs) {
+               mlx4_info(dev, "No availible VPP resources for this VF\n");
+               return -EINVAL;
+       }
+
+       /* Query for default QoS values from Vport 0 is needed */
+       err = mlx4_SET_VPORT_QOS_get(dev, port, 0, vpp_qos);
+       if (err) {
+               mlx4_info(dev, "Failed to query Vport 0 QoS values\n");
+               return err;
+       }
+
+       for (i = 0; i < MLX4_NUM_UP; i++) {
+               if (test_bit(i, port_qos->priority_bm) && max_tx_rate) {
+                       vpp_qos[i].max_avg_bw = max_tx_rate;
+                       vpp_qos[i].enable = 1;
+               } else {
+                       /* if user supplied tx_rate == 0, meaning no rate limit
+                        * configuration is required. so we are leaving the
+                        * value of max_avg_bw as queried from Vport 0.
+                        */
+                       vpp_qos[i].enable = 0;
+               }
+       }
+
+       err = mlx4_SET_VPORT_QOS_set(dev, port, slave, vpp_qos);
+       if (err) {
+               mlx4_info(dev, "Failed to set Vport %d QoS values\n", slave);
+               return err;
+       }
+
+       return 0;
+}
+
+static bool mlx4_is_vf_vst_and_prio_qos(struct mlx4_dev *dev, int port,
+                                       struct mlx4_vport_state *vf_admin)
+{
+       struct mlx4_qos_manager *info;
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       if (!mlx4_is_master(dev) ||
+           !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP))
+               return false;
+
+       info = &priv->mfunc.master.qos_ctl[port];
+
+       if (vf_admin->default_vlan != MLX4_VGT &&
+           test_bit(vf_admin->default_qos, info->priority_bm))
+               return true;
+
+       return false;
+}
+
+static bool mlx4_valid_vf_state_change(struct mlx4_dev *dev, int port,
+                                      struct mlx4_vport_state *vf_admin,
+                                      int vlan, int qos)
+{
+       struct mlx4_vport_state dummy_admin = {0};
+
+       if (!mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin) ||
+           !vf_admin->tx_rate)
+               return true;
+
+       dummy_admin.default_qos = qos;
+       dummy_admin.default_vlan = vlan;
+
+       /* VF wants to move to other VST state which is valid with current
+        * rate limit. Either differnt default vlan in VST or other
+        * supported QoS priority. Otherwise we don't allow this change when
+        * the TX rate is still configured.
+        */
+       if (mlx4_is_vf_vst_and_prio_qos(dev, port, &dummy_admin))
+               return true;
+
+       mlx4_info(dev, "Cannot change VF state to %s while rate is set\n",
+                 (vlan == MLX4_VGT) ? "VGT" : "VST");
+
+       if (vlan != MLX4_VGT)
+               mlx4_info(dev, "VST priority %d not supported for QoS\n", qos);
+
+       mlx4_info(dev, "Please set rate to 0 prior to this VF state change\n");
+
+       return false;
+}
+
 int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        port = mlx4_slaves_closest_port(dev, slave, port);
        vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
 
+       if (!mlx4_valid_vf_state_change(dev, port, vf_admin, vlan, qos))
+               return -EPERM;
+
        if ((0 == vlan) && (0 == qos))
                vf_admin->default_vlan = MLX4_VGT;
        else
                vf_admin->default_vlan = vlan;
        vf_admin->default_qos = qos;
 
+       /* If rate was configured prior to VST, we saved the configured rate
+        * in vf_admin->rate and now, if priority supported we enforce the QoS
+        */
+       if (mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin) &&
+           vf_admin->tx_rate)
+               vf_admin->qos_vport = slave;
+
        if (mlx4_master_immediate_activate_vlan_qos(priv, slave, port))
                mlx4_info(dev,
                          "updating vf %d port %d config will take effect on next VF restart\n",
 }
 EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan);
 
+int mlx4_set_vf_rate(struct mlx4_dev *dev, int port, int vf, int min_tx_rate,
+                    int max_tx_rate)
+{
+       int err;
+       int slave;
+       struct mlx4_vport_state *vf_admin;
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       if (!mlx4_is_master(dev) ||
+           !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP))
+               return -EPROTONOSUPPORT;
+
+       if (min_tx_rate) {
+               mlx4_info(dev, "Minimum BW share not supported\n");
+               return -EPROTONOSUPPORT;
+       }
+
+       slave = mlx4_get_slave_indx(dev, vf);
+       if (slave < 0)
+               return -EINVAL;
+
+       port = mlx4_slaves_closest_port(dev, slave, port);
+       vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
+
+       err = mlx4_set_vport_qos(priv, slave, port, max_tx_rate);
+       if (err) {
+               mlx4_info(dev, "vf %d failed to set rate %d\n", vf,
+                         max_tx_rate);
+               return err;
+       }
+
+       vf_admin->tx_rate = max_tx_rate;
+       /* if VF is not in supported mode (VST with supported prio),
+        * we do not change vport configuration for its QPs, but save
+        * the rate, so it will be enforced when it moves to supported
+        * mode next time.
+        */
+       if (!mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin)) {
+               mlx4_info(dev,
+                         "rate set for VF %d when not in valid state\n", vf);
+
+               if (vf_admin->default_vlan != MLX4_VGT)
+                       mlx4_info(dev, "VST priority not supported by QoS\n");
+               else
+                       mlx4_info(dev, "VF in VGT mode (needed VST)\n");
+
+               mlx4_info(dev,
+                         "rate %d take affect when VF moves to valid state\n",
+                         max_tx_rate);
+               return 0;
+       }
+
+       /* If user sets rate 0 assigning default vport for its QPs */
+       vf_admin->qos_vport = max_tx_rate ? slave : MLX4_VPP_DEFAULT_VPORT;
+
+       if (priv->mfunc.master.slave_state[slave].active &&
+           dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP)
+               mlx4_master_immediate_activate_vlan_qos(priv, slave, port);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_set_vf_rate);
+
  /* mlx4_get_slave_default_vlan -
  * return true if VST ( default vlan)
  * if VST, will return vlan & qos (if not NULL)
 
        ivf->vlan               = s_info->default_vlan;
        ivf->qos                = s_info->default_qos;
-       ivf->max_tx_rate        = s_info->tx_rate;
+
+       if (mlx4_is_vf_vst_and_prio_qos(dev, port, s_info))
+               ivf->max_tx_rate = s_info->tx_rate;
+       else
+               ivf->max_tx_rate = 0;
+
        ivf->min_tx_rate        = 0;
        ivf->spoofchk           = s_info->spoofchk;
        ivf->linkstate          = s_info->link_state;