Commit f2a3f6a3 authored by Or Gerlitz's avatar Or Gerlitz Committed by Roland Dreier

mlx4_core: Add network flow counters

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: default avatarOr Gerlitz <ogerlitz@mellanox.co.il>
Signed-off-by: default avatarRoland Dreier <roland@purestorage.com>
parent 98a13e48
...@@ -104,7 +104,8 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags) ...@@ -104,7 +104,8 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags)
[38] = "Wake On LAN support", [38] = "Wake On LAN support",
[40] = "UDP RSS support", [40] = "UDP RSS support",
[41] = "Unicast VEP steering support", [41] = "Unicast VEP steering support",
[42] = "Multicast VEP steering support" [42] = "Multicast VEP steering support",
[48] = "Counters support",
}; };
int i; int i;
...@@ -203,6 +204,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) ...@@ -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_MAX_MCG_OFFSET 0x63
#define QUERY_DEV_CAP_RSVD_PD_OFFSET 0x64 #define QUERY_DEV_CAP_RSVD_PD_OFFSET 0x64
#define QUERY_DEV_CAP_MAX_PD_OFFSET 0x65 #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_RDMARC_ENTRY_SZ_OFFSET 0x80
#define QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET 0x82 #define QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET 0x82
#define QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET 0x84 #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) ...@@ -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); QUERY_DEV_CAP_RSVD_LKEY_OFFSET);
MLX4_GET(dev_cap->max_icm_sz, outbox, MLX4_GET(dev_cap->max_icm_sz, outbox,
QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET); 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) { if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
for (i = 1; i <= dev_cap->num_ports; ++i) { 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) ...@@ -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", 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); 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 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); 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) ...@@ -780,6 +786,10 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
if (enable_qos) if (enable_qos)
*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 2); *(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 */ /* QPC/EEC/CQC/EQC/RDMARC attributes */
MLX4_PUT(inbox, param->qpc_base, INIT_HCA_QPC_BASE_OFFSET); MLX4_PUT(inbox, param->qpc_base, INIT_HCA_QPC_BASE_OFFSET);
......
...@@ -111,6 +111,7 @@ struct mlx4_dev_cap { ...@@ -111,6 +111,7 @@ struct mlx4_dev_cap {
u8 supported_port_types[MLX4_MAX_PORTS + 1]; u8 supported_port_types[MLX4_MAX_PORTS + 1];
u8 log_max_macs[MLX4_MAX_PORTS + 1]; u8 log_max_macs[MLX4_MAX_PORTS + 1];
u8 log_max_vlans[MLX4_MAX_PORTS + 1]; u8 log_max_vlans[MLX4_MAX_PORTS + 1];
u32 max_counters;
}; };
struct mlx4_adapter { struct mlx4_adapter {
......
...@@ -143,6 +143,7 @@ static void mlx4_set_port_mask(struct mlx4_dev *dev) ...@@ -143,6 +143,7 @@ static void mlx4_set_port_mask(struct mlx4_dev *dev)
if (dev->caps.port_type[i] == MLX4_PORT_TYPE_IB) if (dev->caps.port_type[i] == MLX4_PORT_TYPE_IB)
dev->caps.port_mask |= 1 << (i - 1); dev->caps.port_mask |= 1 << (i - 1);
} }
static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
{ {
int err; int err;
...@@ -257,6 +258,8 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) ...@@ -257,6 +258,8 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
mlx4_set_port_mask(dev); 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_FW] = dev_cap->reserved_qps;
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] = dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] =
dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] = dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] =
...@@ -834,6 +837,45 @@ static int mlx4_init_hca(struct mlx4_dev *dev) ...@@ -834,6 +837,45 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
return err; 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) static int mlx4_setup_hca(struct mlx4_dev *dev)
{ {
struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_priv *priv = mlx4_priv(dev);
...@@ -938,6 +980,12 @@ static int mlx4_setup_hca(struct mlx4_dev *dev) ...@@ -938,6 +980,12 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
goto err_qp_table_free; 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++) { for (port = 1; port <= dev->caps.num_ports; port++) {
enum mlx4_port_type port_type = 0; enum mlx4_port_type port_type = 0;
mlx4_SENSE_PORT(dev, port, &port_type); mlx4_SENSE_PORT(dev, port, &port_type);
...@@ -964,6 +1012,9 @@ static int mlx4_setup_hca(struct mlx4_dev *dev) ...@@ -964,6 +1012,9 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
err_mcg_table_free: err_mcg_table_free:
mlx4_cleanup_mcg_table(dev); mlx4_cleanup_mcg_table(dev);
err_counters_table_free:
mlx4_cleanup_counters_table(dev);
err_qp_table_free: err_qp_table_free:
mlx4_cleanup_qp_table(dev); mlx4_cleanup_qp_table(dev);
...@@ -1294,6 +1345,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -1294,6 +1345,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
for (--port; port >= 1; --port) for (--port; port >= 1; --port)
mlx4_cleanup_port_info(&priv->port[port]); mlx4_cleanup_port_info(&priv->port[port]);
mlx4_cleanup_counters_table(dev);
mlx4_cleanup_mcg_table(dev); mlx4_cleanup_mcg_table(dev);
mlx4_cleanup_qp_table(dev); mlx4_cleanup_qp_table(dev);
mlx4_cleanup_srq_table(dev); mlx4_cleanup_srq_table(dev);
...@@ -1354,6 +1406,7 @@ static void mlx4_remove_one(struct pci_dev *pdev) ...@@ -1354,6 +1406,7 @@ static void mlx4_remove_one(struct pci_dev *pdev)
mlx4_CLOSE_PORT(dev, p); mlx4_CLOSE_PORT(dev, p);
} }
mlx4_cleanup_counters_table(dev);
mlx4_cleanup_mcg_table(dev); mlx4_cleanup_mcg_table(dev);
mlx4_cleanup_qp_table(dev); mlx4_cleanup_qp_table(dev);
mlx4_cleanup_srq_table(dev); mlx4_cleanup_srq_table(dev);
......
...@@ -342,6 +342,7 @@ struct mlx4_priv { ...@@ -342,6 +342,7 @@ struct mlx4_priv {
struct mlx4_srq_table srq_table; struct mlx4_srq_table srq_table;
struct mlx4_qp_table qp_table; struct mlx4_qp_table qp_table;
struct mlx4_mcg_table mcg_table; struct mlx4_mcg_table mcg_table;
struct mlx4_bitmap counters_bitmap;
struct mlx4_catas_err catas_err; struct mlx4_catas_err catas_err;
......
...@@ -123,6 +123,9 @@ enum { ...@@ -123,6 +123,9 @@ enum {
/* debug commands */ /* debug commands */
MLX4_CMD_QUERY_DEBUG_MSG = 0x2a, MLX4_CMD_QUERY_DEBUG_MSG = 0x2a,
MLX4_CMD_SET_DEBUG_MSG = 0x2b, MLX4_CMD_SET_DEBUG_MSG = 0x2b,
/* statistics commands */
MLX4_CMD_QUERY_IF_STAT = 0X54,
}; };
enum { enum {
......
...@@ -78,7 +78,8 @@ enum { ...@@ -78,7 +78,8 @@ enum {
MLX4_DEV_CAP_FLAG_WOL = 1LL << 38, MLX4_DEV_CAP_FLAG_WOL = 1LL << 38,
MLX4_DEV_CAP_FLAG_UDP_RSS = 1LL << 40, MLX4_DEV_CAP_FLAG_UDP_RSS = 1LL << 40,
MLX4_DEV_CAP_FLAG_VEP_UC_STEER = 1LL << 41, 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 { enum {
...@@ -274,6 +275,7 @@ struct mlx4_caps { ...@@ -274,6 +275,7 @@ struct mlx4_caps {
u8 supported_type[MLX4_MAX_PORTS + 1]; u8 supported_type[MLX4_MAX_PORTS + 1];
u32 port_mask; u32 port_mask;
enum mlx4_port_type possible_type[MLX4_MAX_PORTS + 1]; enum mlx4_port_type possible_type[MLX4_MAX_PORTS + 1];
u32 max_counters;
}; };
struct mlx4_buf_list { struct mlx4_buf_list {
...@@ -438,6 +440,17 @@ union mlx4_ext_av { ...@@ -438,6 +440,17 @@ union mlx4_ext_av {
struct mlx4_eth_av eth; 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 mlx4_dev {
struct pci_dev *pdev; struct pci_dev *pdev;
unsigned long flags; unsigned long flags;
...@@ -568,4 +581,7 @@ void mlx4_release_eq(struct mlx4_dev *dev, int vec); ...@@ -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_read(struct mlx4_dev *dev, u64 *config, int port);
int mlx4_wol_write(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 */ #endif /* MLX4_DEVICE_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment