mlx4_core: Add network flow counters
authorOr Gerlitz <ogerlitz@mellanox.com>
Wed, 15 Jun 2011 14:47:14 +0000 (14:47 +0000)
committerRoland Dreier <roland@purestorage.com>
Tue, 19 Jul 2011 04:04:34 +0000 (21:04 -0700)
ConnectX devices support a set of flow counters that can be attached
to a set containing one or more QPs.  Each such counter tracks receive
and transmit packets and bytes of these QPs.  This patch queries the
device to check support for counters, handles initialization of the
HCA to enable counters, and initializes a bitmap allocator to control
counter allocations.  Derived from patch by Eli Cohen <eli@mellanox.co.il>.

Signed-off-by: Or Gerlitz <ogerlitz@mellanox.co.il>
Signed-off-by: Roland Dreier <roland@purestorage.com>
drivers/net/mlx4/fw.c
drivers/net/mlx4/fw.h
drivers/net/mlx4/main.c
drivers/net/mlx4/mlx4.h
include/linux/mlx4/cmd.h
include/linux/mlx4/device.h

index 1d3fc6d7689b474e1d80085fa7774b46270d646e..7eb8ba822e9724354a843eeb6610fbc027fdcfd6 100644 (file)
@@ -104,7 +104,8 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags)
                [38] = "Wake On LAN support",
                [40] = "UDP RSS support",
                [41] = "Unicast VEP steering support",
-               [42] = "Multicast VEP steering support"
+               [42] = "Multicast VEP steering support",
+               [48] = "Counters support",
        };
        int i;
 
@@ -203,6 +204,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 #define QUERY_DEV_CAP_MAX_MCG_OFFSET           0x63
 #define QUERY_DEV_CAP_RSVD_PD_OFFSET           0x64
 #define QUERY_DEV_CAP_MAX_PD_OFFSET            0x65
+#define QUERY_DEV_CAP_MAX_COUNTERS_OFFSET      0x68
 #define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET   0x80
 #define QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET      0x82
 #define QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET      0x84
@@ -355,6 +357,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
                 QUERY_DEV_CAP_RSVD_LKEY_OFFSET);
        MLX4_GET(dev_cap->max_icm_sz, outbox,
                 QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET);
+       if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS)
+               MLX4_GET(dev_cap->max_counters, outbox,
+                        QUERY_DEV_CAP_MAX_COUNTERS_OFFSET);
 
        if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
                for (i = 1; i <= dev_cap->num_ports; ++i) {
@@ -448,6 +453,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        mlx4_dbg(dev, "Max RQ desc size: %d, max RQ S/G: %d\n",
                 dev_cap->max_rq_desc_sz, dev_cap->max_rq_sg);
        mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz);
+       mlx4_dbg(dev, "Max counters: %d\n", dev_cap->max_counters);
 
        dump_dev_cap_flags(dev, dev_cap->flags);
 
@@ -780,6 +786,10 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
        if (enable_qos)
                *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 2);
 
+       /* enable counters */
+       if (dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS)
+               *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 4);
+
        /* QPC/EEC/CQC/EQC/RDMARC attributes */
 
        MLX4_PUT(inbox, param->qpc_base,      INIT_HCA_QPC_BASE_OFFSET);
index 56ed1646ccedff739150a135163e58591a7822a5..1e8ecc3708e22eff9f33d5326af850d9a4c4c7da 100644 (file)
@@ -111,6 +111,7 @@ struct mlx4_dev_cap {
        u8  supported_port_types[MLX4_MAX_PORTS + 1];
        u8  log_max_macs[MLX4_MAX_PORTS + 1];
        u8  log_max_vlans[MLX4_MAX_PORTS + 1];
+       u32 max_counters;
 };
 
 struct mlx4_adapter {
index 650f4ca8606e8b190683af2e6900e7bfdb9d2008..932dac5e4db7313a81344afdbb9da54c90721c22 100644 (file)
@@ -143,6 +143,7 @@ static void mlx4_set_port_mask(struct mlx4_dev *dev)
                if (dev->caps.port_type[i] == MLX4_PORT_TYPE_IB)
                        dev->caps.port_mask |= 1 << (i - 1);
 }
+
 static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 {
        int err;
@@ -257,6 +258,8 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 
        mlx4_set_port_mask(dev);
 
+       dev->caps.max_counters = 1 << ilog2(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] =
                dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] =
@@ -834,6 +837,45 @@ err_stop_fw:
        return err;
 }
 
+static int mlx4_init_counters_table(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int nent;
+
+       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);
+}
+
+static void mlx4_cleanup_counters_table(struct mlx4_dev *dev)
+{
+       mlx4_bitmap_cleanup(&mlx4_priv(dev)->counters_bitmap);
+}
+
+int mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS))
+               return -ENOENT;
+
+       *idx = mlx4_bitmap_alloc(&priv->counters_bitmap);
+       if (*idx == -1)
+               return -ENOMEM;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_counter_alloc);
+
+void mlx4_counter_free(struct mlx4_dev *dev, u32 idx)
+{
+       mlx4_bitmap_free(&mlx4_priv(dev)->counters_bitmap, idx);
+       return;
+}
+EXPORT_SYMBOL_GPL(mlx4_counter_free);
+
 static int mlx4_setup_hca(struct mlx4_dev *dev)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
@@ -938,6 +980,12 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
                goto err_qp_table_free;
        }
 
+       err = mlx4_init_counters_table(dev);
+       if (err && err != -ENOENT) {
+               mlx4_err(dev, "Failed to initialize counters table, aborting.\n");
+               goto err_counters_table_free;
+       }
+
        for (port = 1; port <= dev->caps.num_ports; port++) {
                enum mlx4_port_type port_type = 0;
                mlx4_SENSE_PORT(dev, port, &port_type);
@@ -964,6 +1012,9 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
 err_mcg_table_free:
        mlx4_cleanup_mcg_table(dev);
 
+err_counters_table_free:
+       mlx4_cleanup_counters_table(dev);
+
 err_qp_table_free:
        mlx4_cleanup_qp_table(dev);
 
@@ -1294,6 +1345,7 @@ err_port:
        for (--port; port >= 1; --port)
                mlx4_cleanup_port_info(&priv->port[port]);
 
+       mlx4_cleanup_counters_table(dev);
        mlx4_cleanup_mcg_table(dev);
        mlx4_cleanup_qp_table(dev);
        mlx4_cleanup_srq_table(dev);
@@ -1354,6 +1406,7 @@ static void mlx4_remove_one(struct pci_dev *pdev)
                        mlx4_CLOSE_PORT(dev, p);
                }
 
+               mlx4_cleanup_counters_table(dev);
                mlx4_cleanup_mcg_table(dev);
                mlx4_cleanup_qp_table(dev);
                mlx4_cleanup_srq_table(dev);
index dd7d745fbab49e2b730f556fd4aef4c1e738862c..5e405bbc8d1b7bb3d93551700ce690f7d955dab0 100644 (file)
@@ -342,6 +342,7 @@ struct mlx4_priv {
        struct mlx4_srq_table   srq_table;
        struct mlx4_qp_table    qp_table;
        struct mlx4_mcg_table   mcg_table;
+       struct mlx4_bitmap      counters_bitmap;
 
        struct mlx4_catas_err   catas_err;
 
index 9a18667c13cc02a0709e648d339b0c72278887d0..b56e4587208d09cdf239f93c71e1ed92dc72a72e 100644 (file)
@@ -123,6 +123,9 @@ enum {
        /* debug commands */
        MLX4_CMD_QUERY_DEBUG_MSG = 0x2a,
        MLX4_CMD_SET_DEBUG_MSG   = 0x2b,
+
+       /* statistics commands */
+       MLX4_CMD_QUERY_IF_STAT   = 0X54,
 };
 
 enum {
index fa861134928aef7e08ea52bf68412d2f40c04ec5..387329e02303985949d784b05450fab7e368f4a0 100644 (file)
@@ -78,7 +78,8 @@ enum {
        MLX4_DEV_CAP_FLAG_WOL           = 1LL << 38,
        MLX4_DEV_CAP_FLAG_UDP_RSS       = 1LL << 40,
        MLX4_DEV_CAP_FLAG_VEP_UC_STEER  = 1LL << 41,
-       MLX4_DEV_CAP_FLAG_VEP_MC_STEER  = 1LL << 42
+       MLX4_DEV_CAP_FLAG_VEP_MC_STEER  = 1LL << 42,
+       MLX4_DEV_CAP_FLAG_COUNTERS      = 1LL << 48
 };
 
 enum {
@@ -274,6 +275,7 @@ struct mlx4_caps {
        u8                      supported_type[MLX4_MAX_PORTS + 1];
        u32                     port_mask;
        enum mlx4_port_type     possible_type[MLX4_MAX_PORTS + 1];
+       u32                     max_counters;
 };
 
 struct mlx4_buf_list {
@@ -438,6 +440,17 @@ union mlx4_ext_av {
        struct mlx4_eth_av      eth;
 };
 
+struct mlx4_counter {
+       u8      reserved1[3];
+       u8      counter_mode;
+       __be32  num_ifc;
+       u32     reserved2[2];
+       __be64  rx_frames;
+       __be64  rx_bytes;
+       __be64  tx_frames;
+       __be64  tx_bytes;
+};
+
 struct mlx4_dev {
        struct pci_dev         *pdev;
        unsigned long           flags;
@@ -568,4 +581,7 @@ void mlx4_release_eq(struct mlx4_dev *dev, int vec);
 int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port);
 int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port);
 
+int mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx);
+void mlx4_counter_free(struct mlx4_dev *dev, u32 idx);
+
 #endif /* MLX4_DEVICE_H */