mlx4: Structures and init/teardown for VF resource quotas
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx4 / resource_tracker.c
index 3586388..cc5d6d0 100644 (file)
@@ -284,10 +284,59 @@ static const char *ResourceType(enum mlx4_resource rt)
 }
 
 static void rem_slave_vlans(struct mlx4_dev *dev, int slave);
+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 =
@@ -308,8 +357,104 @@ 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;
+
+               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,
@@ -333,6 +478,14 @@ void mlx4_free_resource_tracker(struct mlx4_dev *dev,
                }
 
                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;
                }