net/mlx4_core: Implement resource quota enforcement
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx4 / resource_tracker.c
index dd68763..b1603e2 100644 (file)
@@ -55,6 +55,14 @@ struct mac_res {
        u8 port;
 };
 
+struct vlan_res {
+       struct list_head list;
+       u16 vlan;
+       int ref_count;
+       int vlan_index;
+       u8 port;
+};
+
 struct res_common {
        struct list_head        list;
        struct rb_node          node;
@@ -266,6 +274,7 @@ static const char *ResourceType(enum mlx4_resource rt)
        case RES_MPT: return "RES_MPT";
        case RES_MTT: return "RES_MTT";
        case RES_MAC: return  "RES_MAC";
+       case RES_VLAN: return  "RES_VLAN";
        case RES_EQ: return "RES_EQ";
        case RES_COUNTER: return "RES_COUNTER";
        case RES_FS_RULE: return "RES_FS_RULE";
@@ -274,10 +283,139 @@ static const char *ResourceType(enum mlx4_resource rt)
        };
 }
 
+static void rem_slave_vlans(struct mlx4_dev *dev, int slave);
+static inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave,
+                                     enum mlx4_resource res_type, int count,
+                                     int port)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct resource_allocator *res_alloc =
+               &priv->mfunc.master.res_tracker.res_alloc[res_type];
+       int err = -EINVAL;
+       int allocated, free, reserved, guaranteed, from_free;
+
+       if (slave > dev->num_vfs)
+               return -EINVAL;
+
+       spin_lock(&res_alloc->alloc_lock);
+       allocated = (port > 0) ?
+               res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] :
+               res_alloc->allocated[slave];
+       free = (port > 0) ? res_alloc->res_port_free[port - 1] :
+               res_alloc->res_free;
+       reserved = (port > 0) ? res_alloc->res_port_rsvd[port - 1] :
+               res_alloc->res_reserved;
+       guaranteed = res_alloc->guaranteed[slave];
+
+       if (allocated + count > res_alloc->quota[slave])
+               goto out;
+
+       if (allocated + count <= guaranteed) {
+               err = 0;
+       } else {
+               /* portion may need to be obtained from free area */
+               if (guaranteed - allocated > 0)
+                       from_free = count - (guaranteed - allocated);
+               else
+                       from_free = count;
+
+               if (free - from_free > reserved)
+                       err = 0;
+       }
+
+       if (!err) {
+               /* grant the request */
+               if (port > 0) {
+                       res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] += count;
+                       res_alloc->res_port_free[port - 1] -= count;
+               } else {
+                       res_alloc->allocated[slave] += count;
+                       res_alloc->res_free -= count;
+               }
+       }
+
+out:
+       spin_unlock(&res_alloc->alloc_lock);
+       return err;
+}
+
+static inline void mlx4_release_resource(struct mlx4_dev *dev, int slave,
+                                   enum mlx4_resource res_type, int count,
+                                   int port)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct resource_allocator *res_alloc =
+               &priv->mfunc.master.res_tracker.res_alloc[res_type];
+
+       if (slave > dev->num_vfs)
+               return;
+
+       spin_lock(&res_alloc->alloc_lock);
+       if (port > 0) {
+               res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] -= count;
+               res_alloc->res_port_free[port - 1] += count;
+       } else {
+               res_alloc->allocated[slave] -= count;
+               res_alloc->res_free += count;
+       }
+
+       spin_unlock(&res_alloc->alloc_lock);
+       return;
+}
+
+static inline void initialize_res_quotas(struct mlx4_dev *dev,
+                                        struct resource_allocator *res_alloc,
+                                        enum mlx4_resource res_type,
+                                        int vf, int num_instances)
+{
+       res_alloc->guaranteed[vf] = num_instances / (2 * (dev->num_vfs + 1));
+       res_alloc->quota[vf] = (num_instances / 2) + res_alloc->guaranteed[vf];
+       if (vf == mlx4_master_func_num(dev)) {
+               res_alloc->res_free = num_instances;
+               if (res_type == RES_MTT) {
+                       /* reserved mtts will be taken out of the PF allocation */
+                       res_alloc->res_free += dev->caps.reserved_mtts;
+                       res_alloc->guaranteed[vf] += dev->caps.reserved_mtts;
+                       res_alloc->quota[vf] += dev->caps.reserved_mtts;
+               }
+       }
+}
+
+void mlx4_init_quotas(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int pf;
+
+       /* quotas for VFs are initialized in mlx4_slave_cap */
+       if (mlx4_is_slave(dev))
+               return;
+
+       if (!mlx4_is_mfunc(dev)) {
+               dev->quotas.qp = dev->caps.num_qps - dev->caps.reserved_qps -
+                       mlx4_num_reserved_sqps(dev);
+               dev->quotas.cq = dev->caps.num_cqs - dev->caps.reserved_cqs;
+               dev->quotas.srq = dev->caps.num_srqs - dev->caps.reserved_srqs;
+               dev->quotas.mtt = dev->caps.num_mtts - dev->caps.reserved_mtts;
+               dev->quotas.mpt = dev->caps.num_mpts - dev->caps.reserved_mrws;
+               return;
+       }
+
+       pf = mlx4_master_func_num(dev);
+       dev->quotas.qp =
+               priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[pf];
+       dev->quotas.cq =
+               priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[pf];
+       dev->quotas.srq =
+               priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[pf];
+       dev->quotas.mtt =
+               priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[pf];
+       dev->quotas.mpt =
+               priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[pf];
+}
 int mlx4_init_resource_tracker(struct mlx4_dev *dev)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
-       int i;
+       int i, j;
        int t;
 
        priv->mfunc.master.res_tracker.slave_list =
@@ -298,8 +436,105 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev)
        for (i = 0 ; i < MLX4_NUM_OF_RESOURCE_TYPE; i++)
                priv->mfunc.master.res_tracker.res_tree[i] = RB_ROOT;
 
+       for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {
+               struct resource_allocator *res_alloc =
+                       &priv->mfunc.master.res_tracker.res_alloc[i];
+               res_alloc->quota = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL);
+               res_alloc->guaranteed = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL);
+               if (i == RES_MAC || i == RES_VLAN)
+                       res_alloc->allocated = kzalloc(MLX4_MAX_PORTS *
+                                                      (dev->num_vfs + 1) * sizeof(int),
+                                                       GFP_KERNEL);
+               else
+                       res_alloc->allocated = kzalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL);
+
+               if (!res_alloc->quota || !res_alloc->guaranteed ||
+                   !res_alloc->allocated)
+                       goto no_mem_err;
+
+               spin_lock_init(&res_alloc->alloc_lock);
+               for (t = 0; t < dev->num_vfs + 1; t++) {
+                       switch (i) {
+                       case RES_QP:
+                               initialize_res_quotas(dev, res_alloc, RES_QP,
+                                                     t, dev->caps.num_qps -
+                                                     dev->caps.reserved_qps -
+                                                     mlx4_num_reserved_sqps(dev));
+                               break;
+                       case RES_CQ:
+                               initialize_res_quotas(dev, res_alloc, RES_CQ,
+                                                     t, dev->caps.num_cqs -
+                                                     dev->caps.reserved_cqs);
+                               break;
+                       case RES_SRQ:
+                               initialize_res_quotas(dev, res_alloc, RES_SRQ,
+                                                     t, dev->caps.num_srqs -
+                                                     dev->caps.reserved_srqs);
+                               break;
+                       case RES_MPT:
+                               initialize_res_quotas(dev, res_alloc, RES_MPT,
+                                                     t, dev->caps.num_mpts -
+                                                     dev->caps.reserved_mrws);
+                               break;
+                       case RES_MTT:
+                               initialize_res_quotas(dev, res_alloc, RES_MTT,
+                                                     t, dev->caps.num_mtts -
+                                                     dev->caps.reserved_mtts);
+                               break;
+                       case RES_MAC:
+                               if (t == mlx4_master_func_num(dev)) {
+                                       res_alloc->quota[t] = MLX4_MAX_MAC_NUM;
+                                       res_alloc->guaranteed[t] = 2;
+                                       for (j = 0; j < MLX4_MAX_PORTS; j++)
+                                               res_alloc->res_port_free[j] = MLX4_MAX_MAC_NUM;
+                               } else {
+                                       res_alloc->quota[t] = MLX4_MAX_MAC_NUM;
+                                       res_alloc->guaranteed[t] = 2;
+                               }
+                               break;
+                       case RES_VLAN:
+                               if (t == mlx4_master_func_num(dev)) {
+                                       res_alloc->quota[t] = MLX4_MAX_VLAN_NUM;
+                                       res_alloc->guaranteed[t] = MLX4_MAX_VLAN_NUM / 2;
+                                       for (j = 0; j < MLX4_MAX_PORTS; j++)
+                                               res_alloc->res_port_free[j] =
+                                                       res_alloc->quota[t];
+                               } else {
+                                       res_alloc->quota[t] = MLX4_MAX_VLAN_NUM / 2;
+                                       res_alloc->guaranteed[t] = 0;
+                               }
+                               break;
+                       case RES_COUNTER:
+                               res_alloc->quota[t] = dev->caps.max_counters;
+                               res_alloc->guaranteed[t] = 0;
+                               if (t == mlx4_master_func_num(dev))
+                                       res_alloc->res_free = res_alloc->quota[t];
+                               break;
+                       default:
+                               break;
+                       }
+                       if (i == RES_MAC || i == RES_VLAN) {
+                               for (j = 0; j < MLX4_MAX_PORTS; j++)
+                                       res_alloc->res_port_rsvd[j] +=
+                                               res_alloc->guaranteed[t];
+                       } else {
+                               res_alloc->res_reserved += res_alloc->guaranteed[t];
+                       }
+               }
+       }
        spin_lock_init(&priv->mfunc.master.res_tracker.lock);
-       return 0 ;
+       return 0;
+
+no_mem_err:
+       for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {
+               kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated);
+               priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL;
+               kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed);
+               priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL;
+               kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota);
+               priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL;
+       }
+       return -ENOMEM;
 }
 
 void mlx4_free_resource_tracker(struct mlx4_dev *dev,
@@ -309,13 +544,28 @@ void mlx4_free_resource_tracker(struct mlx4_dev *dev,
        int i;
 
        if (priv->mfunc.master.res_tracker.slave_list) {
-               if (type != RES_TR_FREE_STRUCTS_ONLY)
-                       for (i = 0 ; i < dev->num_slaves; i++)
+               if (type != RES_TR_FREE_STRUCTS_ONLY) {
+                       for (i = 0; i < dev->num_slaves; i++) {
                                if (type == RES_TR_FREE_ALL ||
                                    dev->caps.function != i)
                                        mlx4_delete_all_resources_for_slave(dev, i);
+                       }
+                       /* free master's vlans */
+                       i = dev->caps.function;
+                       mutex_lock(&priv->mfunc.master.res_tracker.slave_list[i].mutex);
+                       rem_slave_vlans(dev, i);
+                       mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[i].mutex);
+               }
 
                if (type != RES_TR_FREE_SLAVES_ONLY) {
+                       for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {
+                               kfree(priv->mfunc.master.res_tracker.res_alloc[i].allocated);
+                               priv->mfunc.master.res_tracker.res_alloc[i].allocated = NULL;
+                               kfree(priv->mfunc.master.res_tracker.res_alloc[i].guaranteed);
+                               priv->mfunc.master.res_tracker.res_alloc[i].guaranteed = NULL;
+                               kfree(priv->mfunc.master.res_tracker.res_alloc[i].quota);
+                               priv->mfunc.master.res_tracker.res_alloc[i].quota = NULL;
+                       }
                        kfree(priv->mfunc.master.res_tracker.slave_list);
                        priv->mfunc.master.res_tracker.slave_list = NULL;
                }
@@ -1229,12 +1479,19 @@ static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
        case RES_OP_RESERVE:
                count = get_param_l(&in_param);
                align = get_param_h(&in_param);
-               err = __mlx4_qp_reserve_range(dev, count, align, &base);
+               err = mlx4_grant_resource(dev, slave, RES_QP, count, 0);
                if (err)
                        return err;
 
+               err = __mlx4_qp_reserve_range(dev, count, align, &base);
+               if (err) {
+                       mlx4_release_resource(dev, slave, RES_QP, count, 0);
+                       return err;
+               }
+
                err = add_res_range(dev, slave, base, count, RES_QP, 0);
                if (err) {
+                       mlx4_release_resource(dev, slave, RES_QP, count, 0);
                        __mlx4_qp_release_range(dev, base, count);
                        return err;
                }
@@ -1282,15 +1539,24 @@ static int mtt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
                return err;
 
        order = get_param_l(&in_param);
+
+       err = mlx4_grant_resource(dev, slave, RES_MTT, 1 << order, 0);
+       if (err)
+               return err;
+
        base = __mlx4_alloc_mtt_range(dev, order);
-       if (base == -1)
+       if (base == -1) {
+               mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);
                return -ENOMEM;
+       }
 
        err = add_res_range(dev, slave, base, 1, RES_MTT, order);
-       if (err)
+       if (err) {
+               mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);
                __mlx4_free_mtt_range(dev, base, order);
-       else
+       } else {
                set_param_l(out_param, base);
+       }
 
        return err;
 }
@@ -1305,13 +1571,20 @@ static int mpt_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
 
        switch (op) {
        case RES_OP_RESERVE:
+               err = mlx4_grant_resource(dev, slave, RES_MPT, 1, 0);
+               if (err)
+                       break;
+
                index = __mlx4_mpt_reserve(dev);
-               if (index == -1)
+               if (index == -1) {
+                       mlx4_release_resource(dev, slave, RES_MPT, 1, 0);
                        break;
+               }
                id = index & mpt_mask(dev);
 
                err = add_res_range(dev, slave, id, 1, RES_MPT, index);
                if (err) {
+                       mlx4_release_resource(dev, slave, RES_MPT, 1, 0);
                        __mlx4_mpt_release(dev, index);
                        break;
                }
@@ -1345,12 +1618,19 @@ static int cq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
 
        switch (op) {
        case RES_OP_RESERVE_AND_MAP:
-               err = __mlx4_cq_alloc_icm(dev, &cqn);
+               err = mlx4_grant_resource(dev, slave, RES_CQ, 1, 0);
                if (err)
                        break;
 
+               err = __mlx4_cq_alloc_icm(dev, &cqn);
+               if (err) {
+                       mlx4_release_resource(dev, slave, RES_CQ, 1, 0);
+                       break;
+               }
+
                err = add_res_range(dev, slave, cqn, 1, RES_CQ, 0);
                if (err) {
+                       mlx4_release_resource(dev, slave, RES_CQ, 1, 0);
                        __mlx4_cq_free_icm(dev, cqn);
                        break;
                }
@@ -1373,12 +1653,19 @@ static int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
 
        switch (op) {
        case RES_OP_RESERVE_AND_MAP:
-               err = __mlx4_srq_alloc_icm(dev, &srqn);
+               err = mlx4_grant_resource(dev, slave, RES_SRQ, 1, 0);
                if (err)
                        break;
 
+               err = __mlx4_srq_alloc_icm(dev, &srqn);
+               if (err) {
+                       mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);
+                       break;
+               }
+
                err = add_res_range(dev, slave, srqn, 1, RES_SRQ, 0);
                if (err) {
+                       mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);
                        __mlx4_srq_free_icm(dev, srqn);
                        break;
                }
@@ -1399,9 +1686,13 @@ static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port)
        struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
        struct mac_res *res;
 
+       if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port))
+               return -EINVAL;
        res = kzalloc(sizeof *res, GFP_KERNEL);
-       if (!res)
+       if (!res) {
+               mlx4_release_resource(dev, slave, RES_MAC, 1, port);
                return -ENOMEM;
+       }
        res->mac = mac;
        res->port = (u8) port;
        list_add_tail(&res->list,
@@ -1421,6 +1712,7 @@ static void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac,
        list_for_each_entry_safe(res, tmp, mac_list, list) {
                if (res->mac == mac && res->port == (u8) port) {
                        list_del(&res->list);
+                       mlx4_release_resource(dev, slave, RES_MAC, 1, port);
                        kfree(res);
                        break;
                }
@@ -1438,12 +1730,13 @@ static void rem_slave_macs(struct mlx4_dev *dev, int slave)
        list_for_each_entry_safe(res, tmp, mac_list, list) {
                list_del(&res->list);
                __mlx4_unregister_mac(dev, res->port, res->mac);
+               mlx4_release_resource(dev, slave, RES_MAC, 1, res->port);
                kfree(res);
        }
 }
 
 static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
-                        u64 in_param, u64 *out_param)
+                        u64 in_param, u64 *out_param, int in_port)
 {
        int err = -EINVAL;
        int port;
@@ -1452,7 +1745,7 @@ static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
        if (op != RES_OP_RESERVE_AND_MAP)
                return err;
 
-       port = get_param_l(out_param);
+       port = !in_port ? get_param_l(out_param) : in_port;
        mac = in_param;
 
        err = __mlx4_register_mac(dev, port, mac);
@@ -1469,12 +1762,114 @@ static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
        return err;
 }
 
-static int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
-                        u64 in_param, u64 *out_param)
+static int vlan_add_to_slave(struct mlx4_dev *dev, int slave, u16 vlan,
+                            int port, int vlan_index)
 {
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
+       struct list_head *vlan_list =
+               &tracker->slave_list[slave].res_list[RES_VLAN];
+       struct vlan_res *res, *tmp;
+
+       list_for_each_entry_safe(res, tmp, vlan_list, list) {
+               if (res->vlan == vlan && res->port == (u8) port) {
+                       /* vlan found. update ref count */
+                       ++res->ref_count;
+                       return 0;
+               }
+       }
+
+       if (mlx4_grant_resource(dev, slave, RES_VLAN, 1, port))
+               return -EINVAL;
+       res = kzalloc(sizeof(*res), GFP_KERNEL);
+       if (!res) {
+               mlx4_release_resource(dev, slave, RES_VLAN, 1, port);
+               return -ENOMEM;
+       }
+       res->vlan = vlan;
+       res->port = (u8) port;
+       res->vlan_index = vlan_index;
+       res->ref_count = 1;
+       list_add_tail(&res->list,
+                     &tracker->slave_list[slave].res_list[RES_VLAN]);
        return 0;
 }
 
+
+static void vlan_del_from_slave(struct mlx4_dev *dev, int slave, u16 vlan,
+                               int port)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
+       struct list_head *vlan_list =
+               &tracker->slave_list[slave].res_list[RES_VLAN];
+       struct vlan_res *res, *tmp;
+
+       list_for_each_entry_safe(res, tmp, vlan_list, list) {
+               if (res->vlan == vlan && res->port == (u8) port) {
+                       if (!--res->ref_count) {
+                               list_del(&res->list);
+                               mlx4_release_resource(dev, slave, RES_VLAN,
+                                                     1, port);
+                               kfree(res);
+                       }
+                       break;
+               }
+       }
+}
+
+static void rem_slave_vlans(struct mlx4_dev *dev, int slave)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
+       struct list_head *vlan_list =
+               &tracker->slave_list[slave].res_list[RES_VLAN];
+       struct vlan_res *res, *tmp;
+       int i;
+
+       list_for_each_entry_safe(res, tmp, vlan_list, list) {
+               list_del(&res->list);
+               /* dereference the vlan the num times the slave referenced it */
+               for (i = 0; i < res->ref_count; i++)
+                       __mlx4_unregister_vlan(dev, res->port, res->vlan);
+               mlx4_release_resource(dev, slave, RES_VLAN, 1, res->port);
+               kfree(res);
+       }
+}
+
+static int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
+                         u64 in_param, u64 *out_param, int in_port)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
+       int err;
+       u16 vlan;
+       int vlan_index;
+       int port;
+
+       port = !in_port ? get_param_l(out_param) : in_port;
+
+       if (!port || op != RES_OP_RESERVE_AND_MAP)
+               return -EINVAL;
+
+       /* upstream kernels had NOP for reg/unreg vlan. Continue this. */
+       if (!in_port && port > 0 && port <= dev->caps.num_ports) {
+               slave_state[slave].old_vlan_api = true;
+               return 0;
+       }
+
+       vlan = (u16) in_param;
+
+       err = __mlx4_register_vlan(dev, port, vlan, &vlan_index);
+       if (!err) {
+               set_param_l(out_param, (u32) vlan_index);
+               err = vlan_add_to_slave(dev, slave, vlan, port, vlan_index);
+               if (err)
+                       __mlx4_unregister_vlan(dev, port, vlan);
+       }
+       return err;
+}
+
 static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
                             u64 in_param, u64 *out_param)
 {
@@ -1484,15 +1879,23 @@ static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
        if (op != RES_OP_RESERVE)
                return -EINVAL;
 
-       err = __mlx4_counter_alloc(dev, &index);
+       err = mlx4_grant_resource(dev, slave, RES_COUNTER, 1, 0);
        if (err)
                return err;
 
+       err = __mlx4_counter_alloc(dev, &index);
+       if (err) {
+               mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
+               return err;
+       }
+
        err = add_res_range(dev, slave, index, 1, RES_COUNTER, 0);
-       if (err)
+       if (err) {
                __mlx4_counter_free(dev, index);
-       else
+               mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
+       } else {
                set_param_l(out_param, index);
+       }
 
        return err;
 }
@@ -1528,7 +1931,7 @@ int mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave,
        int err;
        int alop = vhcr->op_modifier;
 
-       switch (vhcr->in_modifier) {
+       switch (vhcr->in_modifier & 0xFF) {
        case RES_QP:
                err = qp_alloc_res(dev, slave, vhcr->op_modifier, alop,
                                   vhcr->in_param, &vhcr->out_param);
@@ -1556,12 +1959,14 @@ int mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave,
 
        case RES_MAC:
                err = mac_alloc_res(dev, slave, vhcr->op_modifier, alop,
-                                   vhcr->in_param, &vhcr->out_param);
+                                   vhcr->in_param, &vhcr->out_param,
+                                   (vhcr->in_modifier >> 8) & 0xFF);
                break;
 
        case RES_VLAN:
                err = vlan_alloc_res(dev, slave, vhcr->op_modifier, alop,
-                                   vhcr->in_param, &vhcr->out_param);
+                                    vhcr->in_param, &vhcr->out_param,
+                                    (vhcr->in_modifier >> 8) & 0xFF);
                break;
 
        case RES_COUNTER:
@@ -1597,6 +2002,7 @@ static int qp_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
                err = rem_res_range(dev, slave, base, count, RES_QP, 0);
                if (err)
                        break;
+               mlx4_release_resource(dev, slave, RES_QP, count, 0);
                __mlx4_qp_release_range(dev, base, count);
                break;
        case RES_OP_MAP_ICM:
@@ -1634,8 +2040,10 @@ static int mtt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
        base = get_param_l(&in_param);
        order = get_param_h(&in_param);
        err = rem_res_range(dev, slave, base, 1, RES_MTT, order);
-       if (!err)
+       if (!err) {
+               mlx4_release_resource(dev, slave, RES_MTT, 1 << order, 0);
                __mlx4_free_mtt_range(dev, base, order);
+       }
        return err;
 }
 
@@ -1660,6 +2068,7 @@ static int mpt_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
                err = rem_res_range(dev, slave, id, 1, RES_MPT, 0);
                if (err)
                        break;
+               mlx4_release_resource(dev, slave, RES_MPT, 1, 0);
                __mlx4_mpt_release(dev, index);
                break;
        case RES_OP_MAP_ICM:
@@ -1694,6 +2103,7 @@ static int cq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
                if (err)
                        break;
 
+               mlx4_release_resource(dev, slave, RES_CQ, 1, 0);
                __mlx4_cq_free_icm(dev, cqn);
                break;
 
@@ -1718,6 +2128,7 @@ static int srq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
                if (err)
                        break;
 
+               mlx4_release_resource(dev, slave, RES_SRQ, 1, 0);
                __mlx4_srq_free_icm(dev, srqn);
                break;
 
@@ -1730,14 +2141,14 @@ static int srq_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
 }
 
 static int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
-                           u64 in_param, u64 *out_param)
+                           u64 in_param, u64 *out_param, int in_port)
 {
        int port;
        int err = 0;
 
        switch (op) {
        case RES_OP_RESERVE_AND_MAP:
-               port = get_param_l(out_param);
+               port = !in_port ? get_param_l(out_param) : in_port;
                mac_del_from_slave(dev, slave, in_param, port);
                __mlx4_unregister_mac(dev, port, in_param);
                break;
@@ -1751,9 +2162,27 @@ static int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
 }
 
 static int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
-                           u64 in_param, u64 *out_param)
+                           u64 in_param, u64 *out_param, int port)
 {
-       return 0;
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
+       int err = 0;
+
+       switch (op) {
+       case RES_OP_RESERVE_AND_MAP:
+               if (slave_state[slave].old_vlan_api)
+                       return 0;
+               if (!port)
+                       return -EINVAL;
+               vlan_del_from_slave(dev, slave, in_param, port);
+               __mlx4_unregister_vlan(dev, port, in_param);
+               break;
+       default:
+               err = -EINVAL;
+               break;
+       }
+
+       return err;
 }
 
 static int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
@@ -1771,6 +2200,7 @@ static int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
                return err;
 
        __mlx4_counter_free(dev, index);
+       mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
 
        return err;
 }
@@ -1803,7 +2233,7 @@ int mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave,
        int err = -EINVAL;
        int alop = vhcr->op_modifier;
 
-       switch (vhcr->in_modifier) {
+       switch (vhcr->in_modifier & 0xFF) {
        case RES_QP:
                err = qp_free_res(dev, slave, vhcr->op_modifier, alop,
                                  vhcr->in_param);
@@ -1831,12 +2261,14 @@ int mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave,
 
        case RES_MAC:
                err = mac_free_res(dev, slave, vhcr->op_modifier, alop,
-                                  vhcr->in_param, &vhcr->out_param);
+                                  vhcr->in_param, &vhcr->out_param,
+                                  (vhcr->in_modifier >> 8) & 0xFF);
                break;
 
        case RES_VLAN:
                err = vlan_free_res(dev, slave, vhcr->op_modifier, alop,
-                                  vhcr->in_param, &vhcr->out_param);
+                                   vhcr->in_param, &vhcr->out_param,
+                                   (vhcr->in_modifier >> 8) & 0xFF);
                break;
 
        case RES_COUNTER:
@@ -3498,6 +3930,11 @@ static void rem_slave_qps(struct mlx4_dev *dev, int slave)
                                                 &tracker->res_tree[RES_QP]);
                                        list_del(&qp->com.list);
                                        spin_unlock_irq(mlx4_tlock(dev));
+                                       if (!valid_reserved(dev, slave, qpn)) {
+                                               __mlx4_qp_release_range(dev, qpn, 1);
+                                               mlx4_release_resource(dev, slave,
+                                                                     RES_QP, 1, 0);
+                                       }
                                        kfree(qp);
                                        state = 0;
                                        break;
@@ -3569,6 +4006,8 @@ static void rem_slave_srqs(struct mlx4_dev *dev, int slave)
                                                 &tracker->res_tree[RES_SRQ]);
                                        list_del(&srq->com.list);
                                        spin_unlock_irq(mlx4_tlock(dev));
+                                       mlx4_release_resource(dev, slave,
+                                                             RES_SRQ, 1, 0);
                                        kfree(srq);
                                        state = 0;
                                        break;
@@ -3635,6 +4074,8 @@ static void rem_slave_cqs(struct mlx4_dev *dev, int slave)
                                                 &tracker->res_tree[RES_CQ]);
                                        list_del(&cq->com.list);
                                        spin_unlock_irq(mlx4_tlock(dev));
+                                       mlx4_release_resource(dev, slave,
+                                                             RES_CQ, 1, 0);
                                        kfree(cq);
                                        state = 0;
                                        break;
@@ -3698,6 +4139,8 @@ static void rem_slave_mrs(struct mlx4_dev *dev, int slave)
                                                 &tracker->res_tree[RES_MPT]);
                                        list_del(&mpt->com.list);
                                        spin_unlock_irq(mlx4_tlock(dev));
+                                       mlx4_release_resource(dev, slave,
+                                                             RES_MPT, 1, 0);
                                        kfree(mpt);
                                        state = 0;
                                        break;
@@ -3767,6 +4210,8 @@ static void rem_slave_mtts(struct mlx4_dev *dev, int slave)
                                                 &tracker->res_tree[RES_MTT]);
                                        list_del(&mtt->com.list);
                                        spin_unlock_irq(mlx4_tlock(dev));
+                                       mlx4_release_resource(dev, slave, RES_MTT,
+                                                             1 << mtt->order, 0);
                                        kfree(mtt);
                                        state = 0;
                                        break;
@@ -3925,6 +4370,7 @@ static void rem_slave_counters(struct mlx4_dev *dev, int slave)
                        list_del(&counter->com.list);
                        kfree(counter);
                        __mlx4_counter_free(dev, index);
+                       mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
                }
        }
        spin_unlock_irq(mlx4_tlock(dev));
@@ -3964,7 +4410,7 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave)
        struct mlx4_priv *priv = mlx4_priv(dev);
 
        mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);
-       /*VLAN*/
+       rem_slave_vlans(dev, slave);
        rem_slave_macs(dev, slave);
        rem_slave_fs_rule(dev, slave);
        rem_slave_qps(dev, slave);
@@ -4081,7 +4527,7 @@ void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work)
        if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN && !errors &&
            NO_INDX != work->orig_vlan_ix)
                __mlx4_unregister_vlan(&work->priv->dev, work->port,
-                                      work->orig_vlan_ix);
+                                      work->orig_vlan_id);
 out:
        kfree(work);
        return;