net/mlx4_core: Use sink counter for the VF default as fallback
[firefly-linux-kernel-4.4.55.git] / drivers / net / ethernet / mellanox / mlx4 / main.c
index 7d57777e65c53625c5edd924072cbceacb58340e..29c2a017a450277657a5d5e9ad4a4878575cbb2c 100644 (file)
@@ -479,7 +479,15 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
                }
        }
 
-       dev->caps.max_counters = 1 << ilog2(dev_cap->max_counters);
+       if (mlx4_is_master(dev) && (dev->caps.num_ports == 2) &&
+           (port_type_array[0] == MLX4_PORT_TYPE_IB) &&
+           (port_type_array[1] == MLX4_PORT_TYPE_ETH)) {
+               mlx4_warn(dev,
+                         "Granular QoS per VF not supported with IB/Eth configuration\n");
+               dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_QOS_VPP;
+       }
+
+       dev->caps.max_counters = dev_cap->max_counters;
 
        dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] = dev_cap->reserved_qps;
        dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] =
@@ -1674,6 +1682,25 @@ static int map_internal_clock(struct mlx4_dev *dev)
        return 0;
 }
 
+int mlx4_get_internal_clock_params(struct mlx4_dev *dev,
+                                  struct mlx4_clock_params *params)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       if (mlx4_is_slave(dev))
+               return -ENOTSUPP;
+
+       if (!params)
+               return -EINVAL;
+
+       params->bar = priv->fw.clock_bar;
+       params->offset = priv->fw.clock_offset;
+       params->size = MLX4_CLOCK_SIZE;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_get_internal_clock_params);
+
 static void unmap_internal_clock(struct mlx4_dev *dev)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
@@ -2193,20 +2220,78 @@ err_free_icm:
 static int mlx4_init_counters_table(struct mlx4_dev *dev)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
-       int nent;
+       int nent_pow2;
 
        if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS))
                return -ENOENT;
 
-       nent = dev->caps.max_counters;
-       return mlx4_bitmap_init(&priv->counters_bitmap, nent, nent - 1, 0, 0);
+       if (!dev->caps.max_counters)
+               return -ENOSPC;
+
+       nent_pow2 = roundup_pow_of_two(dev->caps.max_counters);
+       /* reserve last counter index for sink counter */
+       return mlx4_bitmap_init(&priv->counters_bitmap, nent_pow2,
+                               nent_pow2 - 1, 0,
+                               nent_pow2 - dev->caps.max_counters + 1);
 }
 
 static void mlx4_cleanup_counters_table(struct mlx4_dev *dev)
 {
+       if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS))
+               return;
+
+       if (!dev->caps.max_counters)
+               return;
+
        mlx4_bitmap_cleanup(&mlx4_priv(dev)->counters_bitmap);
 }
 
+static void mlx4_cleanup_default_counters(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int port;
+
+       for (port = 0; port < dev->caps.num_ports; port++)
+               if (priv->def_counter[port] != -1)
+                       mlx4_counter_free(dev,  priv->def_counter[port]);
+}
+
+static int mlx4_allocate_default_counters(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int port, err = 0;
+       u32 idx;
+
+       for (port = 0; port < dev->caps.num_ports; port++)
+               priv->def_counter[port] = -1;
+
+       for (port = 0; port < dev->caps.num_ports; port++) {
+               err = mlx4_counter_alloc(dev, &idx);
+
+               if (!err || err == -ENOSPC) {
+                       priv->def_counter[port] = idx;
+               } else if (err == -ENOENT) {
+                       err = 0;
+                       continue;
+               } else if (mlx4_is_slave(dev) && err == -EINVAL) {
+                       priv->def_counter[port] = MLX4_SINK_COUNTER_INDEX(dev);
+                       mlx4_warn(dev, "can't allocate counter from old PF driver, using index %d\n",
+                                 MLX4_SINK_COUNTER_INDEX(dev));
+                       err = 0;
+               } else {
+                       mlx4_err(dev, "%s: failed to allocate default counter port %d err %d\n",
+                                __func__, port + 1, err);
+                       mlx4_cleanup_default_counters(dev);
+                       return err;
+               }
+
+               mlx4_dbg(dev, "%s: default counter index %d for port %d\n",
+                        __func__, priv->def_counter[port], port + 1);
+       }
+
+       return err;
+}
+
 int __mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
@@ -2215,8 +2300,10 @@ int __mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx)
                return -ENOENT;
 
        *idx = mlx4_bitmap_alloc(&priv->counters_bitmap);
-       if (*idx == -1)
-               return -ENOMEM;
+       if (*idx == -1) {
+               *idx = MLX4_SINK_COUNTER_INDEX(dev);
+               return -ENOSPC;
+       }
 
        return 0;
 }
@@ -2239,8 +2326,35 @@ int mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx)
 }
 EXPORT_SYMBOL_GPL(mlx4_counter_alloc);
 
+static int __mlx4_clear_if_stat(struct mlx4_dev *dev,
+                               u8 counter_index)
+{
+       struct mlx4_cmd_mailbox *if_stat_mailbox;
+       int err;
+       u32 if_stat_in_mod = (counter_index & 0xff) | MLX4_QUERY_IF_STAT_RESET;
+
+       if_stat_mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(if_stat_mailbox))
+               return PTR_ERR(if_stat_mailbox);
+
+       err = mlx4_cmd_box(dev, 0, if_stat_mailbox->dma, if_stat_in_mod, 0,
+                          MLX4_CMD_QUERY_IF_STAT, MLX4_CMD_TIME_CLASS_C,
+                          MLX4_CMD_NATIVE);
+
+       mlx4_free_cmd_mailbox(dev, if_stat_mailbox);
+       return err;
+}
+
 void __mlx4_counter_free(struct mlx4_dev *dev, u32 idx)
 {
+       if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS))
+               return;
+
+       if (idx == MLX4_SINK_COUNTER_INDEX(dev))
+               return;
+
+       __mlx4_clear_if_stat(dev, idx);
+
        mlx4_bitmap_free(&mlx4_priv(dev)->counters_bitmap, idx, MLX4_USE_RR);
        return;
 }
@@ -2260,6 +2374,14 @@ void mlx4_counter_free(struct mlx4_dev *dev, u32 idx)
 }
 EXPORT_SYMBOL_GPL(mlx4_counter_free);
 
+int mlx4_get_default_counter_index(struct mlx4_dev *dev, int port)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       return priv->def_counter[port - 1];
+}
+EXPORT_SYMBOL_GPL(mlx4_get_default_counter_index);
+
 void mlx4_set_admin_guid(struct mlx4_dev *dev, __be64 guid, int entry, int port)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
@@ -2395,10 +2517,18 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
                goto err_srq_table_free;
        }
 
-       err = mlx4_init_counters_table(dev);
-       if (err && err != -ENOENT) {
-               mlx4_err(dev, "Failed to initialize counters table, aborting\n");
-               goto err_qp_table_free;
+       if (!mlx4_is_slave(dev)) {
+               err = mlx4_init_counters_table(dev);
+               if (err && err != -ENOENT) {
+                       mlx4_err(dev, "Failed to initialize counters table, aborting\n");
+                       goto err_qp_table_free;
+               }
+       }
+
+       err = mlx4_allocate_default_counters(dev);
+       if (err) {
+               mlx4_err(dev, "Failed to allocate default counters, aborting\n");
+               goto err_counters_table_free;
        }
 
        if (!mlx4_is_slave(dev)) {
@@ -2432,15 +2562,19 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
                        if (err) {
                                mlx4_err(dev, "Failed to set port %d, aborting\n",
                                         port);
-                               goto err_counters_table_free;
+                               goto err_default_countes_free;
                        }
                }
        }
 
        return 0;
 
+err_default_countes_free:
+       mlx4_cleanup_default_counters(dev);
+
 err_counters_table_free:
-       mlx4_cleanup_counters_table(dev);
+       if (!mlx4_is_slave(dev))
+               mlx4_cleanup_counters_table(dev);
 
 err_qp_table_free:
        mlx4_cleanup_qp_table(dev);
@@ -3173,7 +3307,9 @@ err_port:
        for (--port; port >= 1; --port)
                mlx4_cleanup_port_info(&priv->port[port]);
 
-       mlx4_cleanup_counters_table(dev);
+       mlx4_cleanup_default_counters(dev);
+       if (!mlx4_is_slave(dev))
+               mlx4_cleanup_counters_table(dev);
        mlx4_cleanup_qp_table(dev);
        mlx4_cleanup_srq_table(dev);
        mlx4_cleanup_cq_table(dev);
@@ -3471,7 +3607,9 @@ static void mlx4_unload_one(struct pci_dev *pdev)
                mlx4_free_resource_tracker(dev,
                                           RES_TR_FREE_SLAVES_ONLY);
 
-       mlx4_cleanup_counters_table(dev);
+       mlx4_cleanup_default_counters(dev);
+       if (!mlx4_is_slave(dev))
+               mlx4_cleanup_counters_table(dev);
        mlx4_cleanup_qp_table(dev);
        mlx4_cleanup_srq_table(dev);
        mlx4_cleanup_cq_table(dev);