Optional counter statistics support
Subsystems (12)
cover Optional counter statistics support
From: Leon Romanovsky <[email protected]>
Change Log:
v1:
* Add a descriptor structure to replace name in struct rdma_hw_stats;
* Add a bitmap in struct rdma_hw_stats to indicate the enable/disable status of all counters;
* Add a "flag" field in counter descriptor and define IB_STAT_FLAG_OPTIONAL flag;
* add/remove_op_stat() are replaced by modify_op_stat();
* Use "set/unset" in command line and send full opcounters list through netlink, and send opcounter indexes instead of names;
* Patches are re-ordered.
v0: https://lore.kernel.org/all/[email protected]
----------------------------------------------------------------------
Hi,
This series from Neta and Aharon provides an extension to the rdma statistics tool that allows to set optional counters dynamically, using netlink.
The idea of having optional counters is to provide to the users the ability to get statistics of counters that hurts performance.
Once an optional counter was added, its statistics will be presented along with all the counters, using the show command.
Binding objects to the optional counters is currently not supported, neither in auto mode nor in manual mode.
To get the list of optional counters that are supported on this device, use "rdma statistic mode supported". To see which counters are currently enabled, use "rdma statistic mode".
Examples:
$ rdma statistic mode supported link rocep8s0f0/1 supported optional-counters cc_rx_ce_pkts,cc_rx_cnp_pkts,cc_tx_cnp_pkts link rocep8s0f1/1 supported optional-counters cc_rx_ce_pkts,cc_rx_cnp_pkts,cc_tx_cnp_pkts
$ sudo rdma statistic set link rocep8s0f0/1 optional-counters cc_rx_ce_pkts,cc_rx_cnp_pkts $ rdma statistic mode link rocep8s0f0/1 link rocep8s0f0/1 optional-counters cc_rx_ce_pkts,cc_rx_cnp_pkts
$ rdma statistic show link rocep8s0f0/1 link rocep8s0f0/1 rx_write_requests 0 rx_read_requests 0 rx_atomic_requests 0 out_of_buffer 0 out_of_sequence 0 duplicate_request 0 rnr_nak_retry_err 0 packet_seq_err 0 implied_nak_seq_err 0 local_ack_timeout_err 0 resp_local_length_error 0 resp_cqe_error 0 req_cqe_error 0 req_remote_invalid_request 0 req_remote_access_errors 0 resp_remote_access_errors 0 resp_cqe_flush_error 0 req_cqe_flush_error 0 roce_adp_retrans 0 roce_adp_retrans_to 0 roce_slow_restart 0 roce_slow_restart_cnps 0 roce_slow_restart_trans 0 rp_cnp_ignored 0 rp_cnp_handled 0 np_ecn_marked_roce_packets 0 np_cnp_sent 0 rx_icrc_encapsulated 0 cc_rx_ce_pkts 0 cc_rx_cnp_pkts 0
$ sudo rdma statistic set link rocep8s0f0/1 optional-counters cc_rx_ce_pkts $ rdma statistic mode link rocep8s0f0/1 link rocep8s0f0/1 optional-counters cc_rx_ce_pkts
Thanks
Aharon Landau (11):
net/mlx5: Add ifc bits to support optional counters net/mlx5: Add priorities for counters in RDMA namespaces RDMA/counter: Add a descriptor in struct rdma_hw_stats RDMA/counter: Add an is_disabled field in struct rdma_hw_stats RDMA/counter: Add optional counter support
RDMA/nldev: Add support to get status of all counters RDMA/nldev: Allow optional-counter status configuration through RDMA
netlink
RDMA/mlx5: Support optional counters in hw_stats initialization RDMA/mlx5: Add steering support in optional flow counters RDMA/mlx5: Add modify_op_stat() support
RDMA/mlx5: Add optional counter support in get_hw_stats callback
drivers/infiniband/core/counters.c | 30 +- drivers/infiniband/core/device.c | 1 + drivers/infiniband/core/nldev.c | 289 +++++++++++++----- drivers/infiniband/core/sysfs.c | 41 ++- drivers/infiniband/hw/bnxt_re/hw_counters.c | 114 +++---- drivers/infiniband/hw/cxgb4/provider.c | 22 +- drivers/infiniband/hw/efa/efa_verbs.c | 19 +- drivers/infiniband/hw/hfi1/verbs.c | 43 +-- drivers/infiniband/hw/irdma/verbs.c | 98 +++--- drivers/infiniband/hw/mlx4/main.c | 37 +-- drivers/infiniband/hw/mlx4/mlx4_ib.h | 2 +- drivers/infiniband/hw/mlx5/counters.c | 280 ++++++++++++++--- drivers/infiniband/hw/mlx5/fs.c | 187 ++++++++++++ drivers/infiniband/hw/mlx5/mlx5_ib.h | 28 +- drivers/infiniband/sw/rxe/rxe_hw_counters.c | 42 +-- .../net/ethernet/mellanox/mlx5/core/fs_core.c | 54 +++- include/linux/mlx5/device.h | 2 + include/linux/mlx5/fs.h | 2 + include/linux/mlx5/mlx5_ifc.h | 22 +- include/rdma/ib_hdrs.h | 1 + include/rdma/ib_verbs.h | 48 ++- include/rdma/rdma_counter.h | 2 + include/uapi/rdma/rdma_netlink.h | 3 + 23 files changed, 1041 insertions(+), 326 deletions(-)
Signature · 1 line
2.31.1
PATCH 1/11 net/mlx5: Add ifc bits to support optional counters
From: Aharon Landau <[email protected]>
Adding bth_opcode field and the relevant bits. This field will be used to capture and count congestion notification packets (CNP).
Adding source_vhca_port support bit.
This field will be used to check the capability to use the source_vhca_port as a match criteria in cases of dual port.
--- include/linux/mlx5/mlx5_ifc.h | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-)
include/linux/mlx5/mlx5_ifc.h +19 -3
@@ -342,7 +342,7 @@ struct mlx5_ifc_flow_table_fields_supported_bits {u8 outer_geneve_oam[0x1 ];u8 outer_geneve_protocol_type[0x1 ];u8 outer_geneve_opt_len[0x1 ]; -u8 reserved_at_1e[0x1 ]; +u8 source_vhca_port[0x1 ];u8 source_eswitch_port[0x1 ];u8 inner_dmac[0x1 ];
@@ -393,6 +393,14 @@ struct mlx5_ifc_flow_table_fields_supported_bits {u8 metadata_reg_c_0[0x1 ]; }; +struct mlx5_ifc_flow_table_fields_supported_2_bits { +u8 reserved_at_0[0xe ]; +u8 bth_opcode[0x1 ]; +u8 reserved_at_f[0x11 ]; + +u8 reserved_at_20[0x60 ]; +}; +struct mlx5_ifc_flow_table_prop_layout_bits {u8 ft_support[0x1 ];u8 reserved_at_1[0x1 ];
@@ -539,7 +547,7 @@ struct mlx5_ifc_fte_match_set_misc_bits {union mlx5_ifc_gre_key_bits gre_key;u8 vxlan_vni[0x18 ]; -u8 reserved_at_b8[0x8 ]; +u8 bth_opcode[0x8 ];u8 geneve_vni[0x18 ];u8 reserved_at_d8[0x7 ];
@@ -756,7 +764,15 @@ struct mlx5_ifc_flow_table_nic_cap_bits {struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_transmit_sniffer; -u8 reserved_at_e00[0x1200 ]; +u8 reserved_at_e00[0x700 ]; + +struct mlx5_ifc_flow_table_fields_supported_2_bits ft_field_support_2_nic_receive_rdma; + +u8 reserved_at_1580[0x280 ]; + +struct mlx5_ifc_flow_table_fields_supported_2_bits ft_field_support_2_nic_transmit_rdma; + +u8 reserved_at_1880[0x780 ];u8 sw_steering_nic_rx_action_drop_icm_address[0x40 ];
Signature · 1 line
2.31.1
PATCH 2/11 net/mlx5: Add priorities for counters in RDMA namespaces
In reply to Leon RomanovskyFrom: Aharon Landau <[email protected]>
Add additional flow steering priorities in the RDMA namespace. This allows adding flow counters to count filtered RDMA traffic and then continue processing in the regular RDMA steering flow.
--- .../net/ethernet/mellanox/mlx5/core/fs_core.c | 54 ++++++++++++++++--- include/linux/mlx5/device.h | 2 + include/linux/mlx5/fs.h | 2 + 3 files changed, 50 insertions(+), 8 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +46 -8
@@ -99,6 +99,9 @@#define LEFTOVERS_NUM_LEVELS 1#define LEFTOVERS_NUM_PRIOS 1 +#define RDMA_RX_COUNTERS_PRIO_NUM_LEVELS 1 +#define RDMA_TX_COUNTERS_PRIO_NUM_LEVELS 1 +#define BY_PASS_PRIO_NUM_LEVELS 1#define BY_PASS_MIN_LEVEL (ETHTOOL_MIN_LEVEL + MLX5_BY_PASS_NUM_PRIOS +\ LEFTOVERS_NUM_PRIOS)
@@ -206,34 +209,63 @@ static struct init_tree_node egress_root_fs = { } }; -#define RDMA_RX_BYPASS_PRIO 0 -#define RDMA_RX_KERNEL_PRIO 1 +enum { +RDMA_RX_COUNTERS_PRIO , +RDMA_RX_BYPASS_PRIO , +RDMA_RX_KERNEL_PRIO , +}; + +#define RDMA_RX_BYPASS_MIN_LEVEL MLX5_BY_PASS_NUM_REGULAR_PRIOS +#define RDMA_RX_KERNEL_MIN_LEVEL (RDMA_RX_BYPASS_MIN_LEVEL + 1) +#define RDMA_RX_COUNTERS_MIN_LEVEL (RDMA_RX_KERNEL_MIN_LEVEL + 2) +static struct init_tree_node rdma_rx_root_fs = { .type =FS_TYPE_NAMESPACE , - .ar_size =2 , + .ar_size =3 , .children = (struct init_tree_node []) { + [RDMA_RX_COUNTERS_PRIO ] = +ADD_PRIO (0 ,RDMA_RX_COUNTERS_MIN_LEVEL ,0 , +FS_CHAINING_CAPS , +ADD_NS (MLX5_FLOW_TABLE_MISS_ACTION_DEF , +ADD_MULTIPLE_PRIO (MLX5_RDMA_RX_NUM_COUNTERS_PRIOS , +RDMA_RX_COUNTERS_PRIO_NUM_LEVELS ))), [RDMA_RX_BYPASS_PRIO ] = -ADD_PRIO (0 ,MLX5_BY_PASS_NUM_REGULAR_PRIOS ,0 , +ADD_PRIO (0 ,RDMA_RX_BYPASS_MIN_LEVEL ,0 ,FS_CHAINING_CAPS ,ADD_NS (MLX5_FLOW_TABLE_MISS_ACTION_DEF ,ADD_MULTIPLE_PRIO (MLX5_BY_PASS_NUM_REGULAR_PRIOS ,BY_PASS_PRIO_NUM_LEVELS ))), [RDMA_RX_KERNEL_PRIO ] = -ADD_PRIO (0 ,MLX5_BY_PASS_NUM_REGULAR_PRIOS +1 ,0 , +ADD_PRIO (0 ,RDMA_RX_KERNEL_MIN_LEVEL ,0 ,FS_CHAINING_CAPS ,ADD_NS (MLX5_FLOW_TABLE_MISS_ACTION_SWITCH_DOMAIN ,ADD_MULTIPLE_PRIO (1 ,1 ))), } }; +enum { +RDMA_TX_COUNTERS_PRIO , +RDMA_TX_BYPASS_PRIO , +}; + +#define RDMA_TX_BYPASS_MIN_LEVEL MLX5_BY_PASS_NUM_PRIOS +#define RDMA_TX_COUNTERS_MIN_LEVEL (RDMA_TX_BYPASS_MIN_LEVEL + 1) +static struct init_tree_node rdma_tx_root_fs = { .type =FS_TYPE_NAMESPACE , - .ar_size =1 , + .ar_size =2 , .children = (struct init_tree_node []) { -ADD_PRIO (0 ,MLX5_BY_PASS_NUM_PRIOS ,0 , + [RDMA_TX_COUNTERS_PRIO ] = +ADD_PRIO (0 ,RDMA_TX_COUNTERS_MIN_LEVEL ,0 , +FS_CHAINING_CAPS , +ADD_NS (MLX5_FLOW_TABLE_MISS_ACTION_DEF , +ADD_MULTIPLE_PRIO (MLX5_RDMA_TX_NUM_COUNTERS_PRIOS , +RDMA_TX_COUNTERS_PRIO_NUM_LEVELS ))), + [RDMA_TX_BYPASS_PRIO ] = +ADD_PRIO (0 ,RDMA_TX_BYPASS_MIN_LEVEL ,0 ,FS_CHAINING_CAPS_RDMA_TX ,ADD_NS (MLX5_FLOW_TABLE_MISS_ACTION_DEF , -ADD_MULTIPLE_PRIO (MLX5_BY_PASS_NUM_PRIOS , +ADD_MULTIPLE_PRIO (RDMA_TX_BYPASS_MIN_LEVEL ,BY_PASS_PRIO_NUM_LEVELS ))), } };
@@ -2216,6 +2248,12 @@ struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev, prio =RDMA_RX_KERNEL_PRIO ; }else if (type ==MLX5_FLOW_NAMESPACE_RDMA_TX ) { root_ns = steering->rdma_tx_root_ns; + }else if (type ==MLX5_FLOW_NAMESPACE_RDMA_RX_COUNTERS ) { + root_ns = steering->rdma_rx_root_ns; + prio =RDMA_RX_COUNTERS_PRIO ; + }else if (type ==MLX5_FLOW_NAMESPACE_RDMA_TX_COUNTERS ) { + root_ns = steering->rdma_tx_root_ns; + prio =RDMA_TX_COUNTERS_PRIO ; }else {/* Must be NIC RX */ root_ns = steering->root_ns; prio = type;
include/linux/mlx5/device.h +2 -0
@@ -1456,6 +1456,8 @@ static inline u16 mlx5_to_sw_pkey_sz(int pkey_sz)return MLX5_MIN_PKEY_TABLE_SIZE << pkey_sz; } +#define MLX5_RDMA_RX_NUM_COUNTERS_PRIOS 2 +#define MLX5_RDMA_TX_NUM_COUNTERS_PRIOS 1#define MLX5_BY_PASS_NUM_REGULAR_PRIOS 16#define MLX5_BY_PASS_NUM_DONT_TRAP_PRIOS 16#define MLX5_BY_PASS_NUM_MULTICAST_PRIOS 1
include/linux/mlx5/fs.h +2 -0
@@ -83,6 +83,8 @@ enum mlx5_flow_namespace_type {MLX5_FLOW_NAMESPACE_RDMA_RX ,MLX5_FLOW_NAMESPACE_RDMA_RX_KERNEL ,MLX5_FLOW_NAMESPACE_RDMA_TX , +MLX5_FLOW_NAMESPACE_RDMA_RX_COUNTERS , + MLX5_FLOW_NAMESPACE_RDMA_TX_COUNTERS, }; enum {
Signature · 1 line
2.31.1
PATCH 3/11 RDMA/counter: Add a descriptor in struct rdma_hw_stats
In reply to Leon RomanovskyFrom: Aharon Landau <[email protected]>
Add a counter statistic descriptor structure in rdma_hw_stats. In addition to the counter name, more meta-information will be added. This code extension is needed for optional-counter support in the following patches.
--- drivers/infiniband/core/nldev.c | 6 +- drivers/infiniband/core/sysfs.c | 8 +- drivers/infiniband/hw/bnxt_re/hw_counters.c | 114 ++++++++++---------- drivers/infiniband/hw/cxgb4/provider.c | 22 ++-- drivers/infiniband/hw/efa/efa_verbs.c | 19 ++-- drivers/infiniband/hw/hfi1/verbs.c | 43 ++++---- drivers/infiniband/hw/irdma/verbs.c | 98 ++++++++--------- drivers/infiniband/hw/mlx4/main.c | 37 +++---- drivers/infiniband/hw/mlx4/mlx4_ib.h | 2 +- drivers/infiniband/hw/mlx5/counters.c | 39 +++---- drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 +- drivers/infiniband/sw/rxe/rxe_hw_counters.c | 42 ++++---- include/rdma/ib_verbs.h | 22 ++-- 13 files changed, 235 insertions(+), 219 deletions(-)
drivers/infiniband/core/nldev.c +4 -2
@@ -969,7 +969,8 @@ static int fill_stat_counter_hwcounters(struct sk_buff *msg,return -EMSGSIZE ;for (i =0 ; i < st->num_counters; i++) -if (rdma_nl_stat_hwcounter_entry (msg, st->names[i], st->value[i])) +if (rdma_nl_stat_hwcounter_entry (msg, st->descs[i].name, + st->value[i])) goto err;nla_nest_end (msg, table_attr);
@@ -2105,7 +2106,8 @@ static int stat_get_doit_default_counter(struct sk_buff *skb,for (i =0 ; i < num_cnts; i++) { v = stats->value[i] +rdma_counter_get_hwstat_value (device, port, i); -if (rdma_nl_stat_hwcounter_entry (msg, stats->names[i], v)) { +if (rdma_nl_stat_hwcounter_entry (msg, + stats->descs[i].name, v)) { ret = -EMSGSIZE ; goto err_table; }
drivers/infiniband/core/sysfs.c +4 -4
@@ -895,7 +895,7 @@ alloc_hw_stats_device(struct ib_device *ibdev) stats = ibdev->ops.alloc_hw_device_stats (ibdev);if (!stats)return ERR_PTR (-ENOMEM ); -if (!stats->names || stats->num_counters <=0 ) +if (!stats->descs || stats->num_counters <=0 ) goto err_free_stats;/*
@@ -957,7 +957,7 @@ int ib_setup_device_attrs(struct ib_device *ibdev)for (i =0 ; i < data->stats->num_counters; i++) { attr = &data->attrs[i];sysfs_attr_init (&attr->attr.attr); - attr->attr.attr.name = data->stats->names[i]; + attr->attr.attr.name = data->stats->descs[i].name; attr->attr.attr.mode =0444 ; attr->attr.show = hw_stat_device_show; attr->show = show_hw_stats;
@@ -994,7 +994,7 @@ alloc_hw_stats_port(struct ib_port *port, struct attribute_group *group) stats = ibdev->ops.alloc_hw_port_stats (port->ibdev, port->port_num);if (!stats)return ERR_PTR (-ENOMEM ); -if (!stats->names || stats->num_counters <=0 ) +if (!stats->descs || stats->num_counters <=0 ) goto err_free_stats;/*
@@ -1047,7 +1047,7 @@ static int setup_hw_port_stats(struct ib_port *port,for (i =0 ; i < data->stats->num_counters; i++) { attr = &data->attrs[i];sysfs_attr_init (&attr->attr.attr); - attr->attr.attr.name = data->stats->names[i]; + attr->attr.attr.name = data->stats->descs[i].name; attr->attr.attr.mode =0444 ; attr->attr.show = hw_stat_port_show; attr->show = show_hw_stats;
drivers/infiniband/hw/bnxt_re/hw_counters.c +57 -57
131 lines not on this page · raw message
drivers/infiniband/hw/cxgb4/provider.c +11 -11
@@ -366,23 +366,23 @@ enum counters {NR_COUNTERS }; -static const char *const names[] = { - [IP4INSEGS ] ="ip4InSegs" , - [IP4OUTSEGS ] ="ip4OutSegs" , - [IP4RETRANSSEGS ] ="ip4RetransSegs" , - [IP4OUTRSTS ] ="ip4OutRsts" , - [IP6INSEGS ] ="ip6InSegs" , - [IP6OUTSEGS ] ="ip6OutSegs" , - [IP6RETRANSSEGS ] ="ip6RetransSegs" , - [IP6OUTRSTS ] ="ip6OutRsts" +static const struct rdma_stat_desc cxgb4_descs[] = { + [IP4INSEGS ].name ="ip4InSegs" , + [IP4OUTSEGS ].name ="ip4OutSegs" , + [IP4RETRANSSEGS ].name ="ip4RetransSegs" , + [IP4OUTRSTS ].name ="ip4OutRsts" , + [IP6INSEGS ].name ="ip6InSegs" , + [IP6OUTSEGS ].name ="ip6OutSegs" , + [IP6RETRANSSEGS ].name ="ip6RetransSegs" , + [IP6OUTRSTS ].name ="ip6OutRsts" };static struct rdma_hw_stats *c4iw_alloc_device_stats (struct ib_device *ibdev) { -BUILD_BUG_ON (ARRAY_SIZE (names) !=NR_COUNTERS ); +BUILD_BUG_ON (ARRAY_SIZE (cxgb4_descs) !=NR_COUNTERS );/* FIXME: these look like port stats */ -return rdma_alloc_hw_stats_struct (names,NR_COUNTERS , +return rdma_alloc_hw_stats_struct (cxgb4_descs,NR_COUNTERS ,RDMA_HW_STATS_DEFAULT_LIFESPAN ); }
drivers/infiniband/hw/efa/efa_verbs.c +10 -9
@@ -60,13 +60,14 @@ struct efa_user_mmap_entry { op(EFA_RDMA_READ_RESP_BYTES, "rdma_read_resp_bytes") \#define EFA_STATS_ENUM (ename, name) ename, -#define EFA_STATS_STR (ename, name) [ename] = name, +#define EFA_STATS_STR (ename, nam) \ + [ename].name = nam,enum efa_hw_device_stats { EFA_DEFINE_DEVICE_STATS(EFA_STATS_ENUM) }; -static const char *const efa_device_stats_names[] = { +static const struct rdma_stat_desc efa_device_stats_descs[] = {EFA_DEFINE_DEVICE_STATS (EFA_STATS_STR ) };
@@ -74,7 +75,7 @@ enum efa_hw_port_stats { EFA_DEFINE_PORT_STATS(EFA_STATS_ENUM) }; -static const char *const efa_port_stats_names[] = { +static const struct rdma_stat_desc efa_port_stats_descs[] = {EFA_DEFINE_PORT_STATS (EFA_STATS_STR ) };
@@ -1906,15 +1907,15 @@ int efa_destroy_ah(struct ib_ah *ibah, u32 flags)struct rdma_hw_stats *efa_alloc_hw_port_stats (struct ib_device *ibdev,u32 port_num) { -return rdma_alloc_hw_stats_struct (efa_port_stats_names, -ARRAY_SIZE (efa_port_stats_names), +return rdma_alloc_hw_stats_struct (efa_port_stats_descs, +ARRAY_SIZE (efa_port_stats_descs),RDMA_HW_STATS_DEFAULT_LIFESPAN ); }struct rdma_hw_stats *efa_alloc_hw_device_stats (struct ib_device *ibdev) { -return rdma_alloc_hw_stats_struct (efa_device_stats_names, -ARRAY_SIZE (efa_device_stats_names), +return rdma_alloc_hw_stats_struct (efa_device_stats_descs, +ARRAY_SIZE (efa_device_stats_descs),RDMA_HW_STATS_DEFAULT_LIFESPAN ); }
@@ -1939,7 +1940,7 @@ static int efa_fill_device_stats(struct efa_dev *dev, stats->value[EFA_CREATE_AH_ERR ] =atomic64_read (&s->create_ah_err); stats->value[EFA_MMAP_ERR ] =atomic64_read (&s->mmap_err); -return ARRAY_SIZE (efa_device_stats_names); +return ARRAY_SIZE (efa_device_stats_descs); } static int efa_fill_port_stats(struct efa_dev *dev, struct rdma_hw_stats *stats,
@@ -1988,7 +1989,7 @@ static int efa_fill_port_stats(struct efa_dev *dev, struct rdma_hw_stats *stats, stats->value[EFA_RDMA_READ_WR_ERR ] = rrs->read_wr_err; stats->value[EFA_RDMA_READ_RESP_BYTES ] = rrs->read_resp_bytes; -return ARRAY_SIZE (efa_port_stats_names); +return ARRAY_SIZE (efa_port_stats_descs); } int efa_get_hw_stats(struct ib_device *ibdev, struct rdma_hw_stats *stats,
drivers/infiniband/hw/hfi1/verbs.c +22 -21
107 lines not on this page · raw message
drivers/infiniband/hw/irdma/verbs.c +49 -49
147 lines not on this page · raw message
drivers/infiniband/hw/mlx4/main.c +19 -18
@@ -2105,10 +2105,10 @@ mlx4_ib_alloc_hw_device_stats(struct ib_device *ibdev)struct mlx4_ib_dev *dev =to_mdev (ibdev);struct mlx4_ib_diag_counters *diag = dev->diag_counters; -if (!diag[0 ].name) +if (!diag[0 ].descs)return NULL ; -return rdma_alloc_hw_stats_struct (diag[0 ].name, diag[0 ].num_counters, +return rdma_alloc_hw_stats_struct (diag[0 ].descs, diag[0 ].num_counters,RDMA_HW_STATS_DEFAULT_LIFESPAN ); }
@@ -2118,10 +2118,10 @@ mlx4_ib_alloc_hw_port_stats(struct ib_device *ibdev, u32 port_num)struct mlx4_ib_dev *dev =to_mdev (ibdev);struct mlx4_ib_diag_counters *diag = dev->diag_counters; -if (!diag[1 ].name) +if (!diag[1 ].descs)return NULL ; -return rdma_alloc_hw_stats_struct (diag[1 ].name, diag[1 ].num_counters, +return rdma_alloc_hw_stats_struct (diag[1 ].descs, diag[1 ].num_counters,RDMA_HW_STATS_DEFAULT_LIFESPAN ); }
@@ -2151,7 +2151,7 @@ static int mlx4_ib_get_hw_stats(struct ib_device *ibdev, }static int __mlx4_ib_alloc_diag_counters (struct mlx4_ib_dev *ibdev, -const char ***name, +struct rdma_stat_desc **pdescs,u32 **offset,u32 *num,bool port)
@@ -2166,25 +2166,26 @@ static int __mlx4_ib_alloc_diag_counters(struct mlx4_ib_dev *ibdev,if (!port) num_counters +=ARRAY_SIZE (diag_device_only); - *name =kcalloc (num_counters,sizeof (**name),GFP_KERNEL ); -if (!*name) + *pdescs =kcalloc (num_counters,sizeof (struct rdma_stat_desc ), +GFP_KERNEL ); +if (!*pdescs)return -ENOMEM ; *offset =kcalloc (num_counters,sizeof (**offset),GFP_KERNEL );if (!*offset) - goto err_name; + goto err; *num = num_counters;return 0 ; -err_name: -kfree (*name); +err: +kfree (*pdescs);return -ENOMEM ; }static void mlx4_ib_fill_diag_counters (struct mlx4_ib_dev *ibdev, -const char **name, +struct rdma_stat_desc *descs,u32 *offset,bool port) {
@@ -2192,20 +2193,20 @@ static void mlx4_ib_fill_diag_counters(struct mlx4_ib_dev *ibdev,int j;for (i =0 , j =0 ; i <ARRAY_SIZE (diag_basic); i++, j++) { - name[i] = diag_basic[i].name; + descs[i].name = diag_basic[i].name; offset[i] = diag_basic[i].offset; }if (ibdev->dev->caps.flags2 &MLX4_DEV_CAP_FLAG2_DIAG_PER_PORT ) {for (i =0 ; i <ARRAY_SIZE (diag_ext); i++, j++) { - name[j] = diag_ext[i].name; + descs[j].name = diag_ext[i].name; offset[j] = diag_ext[i].offset; } }if (!port) {for (i =0 ; i <ARRAY_SIZE (diag_device_only); i++, j++) { - name[j] = diag_device_only[i].name; + descs[j].name = diag_device_only[i].name; offset[j] = diag_device_only[i].offset; } }
@@ -2233,13 +2234,13 @@ static int mlx4_ib_alloc_diag_counters(struct mlx4_ib_dev *ibdev)if (i && !per_port)continue ; - ret =__mlx4_ib_alloc_diag_counters (ibdev, &diag[i].name, + ret =__mlx4_ib_alloc_diag_counters (ibdev, &diag[i].descs, &diag[i].offset, &diag[i].num_counters, i);if (ret) goto err_alloc; -mlx4_ib_fill_diag_counters (ibdev, diag[i].name, +mlx4_ib_fill_diag_counters (ibdev, diag[i].descs, diag[i].offset, i); }
@@ -2249,7 +2250,7 @@ static int mlx4_ib_alloc_diag_counters(struct mlx4_ib_dev *ibdev) err_alloc:if (i) { -kfree (diag[i -1 ].name); +kfree (diag[i -1 ].descs);kfree (diag[i -1 ].offset); }
@@ -2262,7 +2263,7 @@ static void mlx4_ib_diag_cleanup(struct mlx4_ib_dev *ibdev)for (i =0 ; i <MLX4_DIAG_COUNTERS_TYPES ; i++) {kfree (ibdev->diag_counters[i].offset); -kfree (ibdev->diag_counters[i].name); +kfree (ibdev->diag_counters[i].descs); } }
drivers/infiniband/hw/mlx4/mlx4_ib.h +1 -1
@@ -601,7 +601,7 @@ struct mlx4_ib_counters {#define MLX4_DIAG_COUNTERS_TYPES 2struct mlx4_ib_diag_counters { -const char **name; +struct rdma_stat_desc *descs;u32 *offset;u32 num_counters; };
drivers/infiniband/hw/mlx5/counters.c +20 -19
@@ -167,7 +167,7 @@ mlx5_ib_alloc_hw_device_stats(struct ib_device *ibdev)struct mlx5_ib_dev *dev =to_mdev (ibdev);const struct mlx5_ib_counters *cnts = &dev->port[0 ].cnts; - return rdma_alloc_hw_stats_struct(cnts->names, + return rdma_alloc_hw_stats_struct(cnts->descs, cnts->num_q_counters + cnts->num_cong_counters + cnts->num_ext_ppcnt_counters,
@@ -180,7 +180,7 @@ mlx5_ib_alloc_hw_port_stats(struct ib_device *ibdev, u32 port_num)struct mlx5_ib_dev *dev =to_mdev (ibdev);const struct mlx5_ib_counters *cnts = &dev->port[port_num -1 ].cnts; - return rdma_alloc_hw_stats_struct(cnts->names, + return rdma_alloc_hw_stats_struct(cnts->descs, cnts->num_q_counters + cnts->num_cong_counters + cnts->num_ext_ppcnt_counters,
@@ -302,7 +302,7 @@ mlx5_ib_counter_alloc_stats(struct rdma_counter *counter)const struct mlx5_ib_counters *cnts =get_counters (dev, counter->port -1 ); - return rdma_alloc_hw_stats_struct(cnts->names, + return rdma_alloc_hw_stats_struct(cnts->descs, cnts->num_q_counters + cnts->num_cong_counters + cnts->num_ext_ppcnt_counters,
@@ -373,55 +373,55 @@ static int mlx5_ib_counter_unbind_qp(struct ib_qp *qp)static void mlx5_ib_fill_counters (struct mlx5_ib_dev *dev, -const char **names, +struct rdma_stat_desc *descs,size_t *offsets) {int i;int j =0 ;for (i =0 ; i <ARRAY_SIZE (basic_q_cnts); i++, j++) { - names[j] = basic_q_cnts[i].name; + descs[j].name = basic_q_cnts[i].name; offsets[j] = basic_q_cnts[i].offset; }if (MLX5_CAP_GEN (dev->mdev, out_of_seq_cnt)) {for (i =0 ; i <ARRAY_SIZE (out_of_seq_q_cnts); i++, j++) { - names[j] = out_of_seq_q_cnts[i].name; + descs[j].name = out_of_seq_q_cnts[i].name; offsets[j] = out_of_seq_q_cnts[i].offset; } }if (MLX5_CAP_GEN (dev->mdev, retransmission_q_counters)) {for (i =0 ; i <ARRAY_SIZE (retrans_q_cnts); i++, j++) { - names[j] = retrans_q_cnts[i].name; + descs[j].name = retrans_q_cnts[i].name; offsets[j] = retrans_q_cnts[i].offset; } }if (MLX5_CAP_GEN (dev->mdev, enhanced_error_q_counters)) {for (i =0 ; i <ARRAY_SIZE (extended_err_cnts); i++, j++) { - names[j] = extended_err_cnts[i].name; + descs[j].name = extended_err_cnts[i].name; offsets[j] = extended_err_cnts[i].offset; } }if (MLX5_CAP_GEN (dev->mdev, roce_accl)) {for (i =0 ; i <ARRAY_SIZE (roce_accl_cnts); i++, j++) { - names[j] = roce_accl_cnts[i].name; + descs[j].name = roce_accl_cnts[i].name; offsets[j] = roce_accl_cnts[i].offset; } }if (MLX5_CAP_GEN (dev->mdev, cc_query_allowed)) {for (i =0 ; i <ARRAY_SIZE (cong_cnts); i++, j++) { - names[j] = cong_cnts[i].name; + descs[j].name = cong_cnts[i].name; offsets[j] = cong_cnts[i].offset; } }if (MLX5_CAP_PCAM_FEATURE (dev->mdev, rx_icrc_encapsulated_counter)) {for (i =0 ; i <ARRAY_SIZE (ext_ppcnt_cnts); i++, j++) { - names[j] = ext_ppcnt_cnts[i].name; + descs[j].name = ext_ppcnt_cnts[i].name; offsets[j] = ext_ppcnt_cnts[i].offset; } }
@@ -457,20 +457,21 @@ static int __mlx5_ib_alloc_counters(struct mlx5_ib_dev *dev, cnts->num_ext_ppcnt_counters =ARRAY_SIZE (ext_ppcnt_cnts); num_counters +=ARRAY_SIZE (ext_ppcnt_cnts); } - cnts->names =kcalloc (num_counters,sizeof (*cnts->names),GFP_KERNEL ); -if (!cnts->names) + cnts->descs =kcalloc (num_counters, +sizeof (struct rdma_stat_desc ),GFP_KERNEL ); +if (!cnts->descs)return -ENOMEM ; cnts->offsets =kcalloc (num_counters,sizeof (*cnts->offsets),GFP_KERNEL );if (!cnts->offsets) - goto err_names; + goto err;return 0 ; -err_names: -kfree (cnts->names); - cnts->names =NULL ; +err: +kfree (cnts->descs); + cnts->descs =NULL ;return -ENOMEM ; }
@@ -491,7 +492,7 @@ static void mlx5_ib_dealloc_counters(struct mlx5_ib_dev *dev) dev->port[i].cnts.set_id);mlx5_cmd_exec_in (dev->mdev, dealloc_q_counter, in); } -kfree (dev->port[i].cnts.names); +kfree (dev->port[i].cnts.descs);kfree (dev->port[i].cnts.offsets); } }
@@ -514,7 +515,7 @@ static int mlx5_ib_alloc_counters(struct mlx5_ib_dev *dev)if (err) goto err_alloc; -mlx5_ib_fill_counters (dev, dev->port[i].cnts.names, +mlx5_ib_fill_counters (dev, dev->port[i].cnts.descs, dev->port[i].cnts.offsets); MLX5_SET(alloc_q_counter_in, in, uid,
drivers/infiniband/hw/mlx5/mlx5_ib.h +1 -1
@@ -798,7 +798,7 @@ struct mlx5_ib_resources { };struct mlx5_ib_counters { -const char **names; +struct rdma_stat_desc *descs;size_t *offsets;u32 num_q_counters;u32 num_cong_counters;
drivers/infiniband/sw/rxe/rxe_hw_counters.c +21 -21
61 lines not on this page · raw message
include/rdma/ib_verbs.h +16 -6
@@ -545,6 +545,15 @@ enum ib_port_speed { IB_SPEED_NDR = 128, }; +/** +* struct rdma_stat_desc +* @name - The name of the counter +* +*/ +struct rdma_stat_desc { +const char *name; +}; +/** * struct rdma_hw_stats * @lock - Mutex to protect parallel write access to lifespan and values
@@ -555,8 +564,8 @@ enum ib_port_speed {* should be before being updated again. Stored in jiffies, defaults * to 10 milliseconds, drivers can override the default be specifying * their own value during their allocation routine. -* @name - Array of pointers to static names used for the counters in -* directory. +* @descs - Array of pointers to static descriptors used for the counters +* in directory. * @num_counters - How many hardware counters there are. If name is * shorter than this number, a kernel oops will result. Driver authors * are encouraged to leave BUILD_BUG_ON(ARRAY_SIZE(@name) < num_counters)
@@ -568,7 +577,7 @@ struct rdma_hw_stats {struct mutex lock;/* Protect lifespan and values[] */ unsigned long timestamp;unsigned long lifespan; -const char *const *names; +const struct rdma_stat_desc *descs;int num_counters;u64 value[]; };
@@ -577,12 +586,12 @@ struct rdma_hw_stats {/** * rdma_alloc_hw_stats_struct - Helper function to allocate dynamic struct * for drivers. -* @names - Array of static const char * +* @descs - Array of static descriptors * @num_counters - How many elements in array * @lifespan - How many milliseconds between updates */ static inline struct rdma_hw_stats *rdma_alloc_hw_stats_struct ( -const char *const *names,int num_counters, +const struct rdma_stat_desc *descs,int num_counters,unsigned long lifespan) {struct rdma_hw_stats *stats;
@@ -591,7 +600,8 @@ static inline struct rdma_hw_stats *rdma_alloc_hw_stats_struct( GFP_KERNEL);if (!stats)return NULL ; - stats->names = names; + + stats->descs = descs; stats->num_counters = num_counters; stats->lifespan =msecs_to_jiffies (lifespan);
Signature · 1 line
2.31.1
PATCH 4/11 RDMA/counter: Add an is_disabled field in struct rdma_hw_stats
In reply to Leon RomanovskyFrom: Aharon Landau <[email protected]>
Add a bitmap in rdma_hw_stat structure, with each bit indicates whether the corresponding counter is currently disabled or not. By default hwcounters are enabled.
--- drivers/infiniband/core/counters.c | 8 +++++++- drivers/infiniband/core/nldev.c | 11 ++++++++++- drivers/infiniband/core/sysfs.c | 7 ++++++- include/rdma/ib_verbs.h | 12 ++++++++++++ 4 files changed, 35 insertions(+), 3 deletions(-)
drivers/infiniband/core/counters.c +7 -1
@@ -165,6 +165,7 @@ static struct rdma_counter *alloc_and_bind(struct ib_device *dev, u32 port,return counter; err_mode: +kfree (counter->stats->is_disabled);kfree (counter->stats); err_stats:rdma_restrack_put (&counter->res);
@@ -186,6 +187,7 @@ static void rdma_counter_free(struct rdma_counter *counter)mutex_unlock (&port_counter->lock);rdma_restrack_del (&counter->res); +kfree (counter->stats->is_disabled);kfree (counter->stats);kfree (counter); }
@@ -618,6 +620,7 @@ void rdma_counter_init(struct ib_device *dev) fail:for (i = port; i >=rdma_start_port (dev); i--) { port_counter = &dev->port_data[port].port_counter; +kfree (port_counter->hstats->is_disabled);kfree (port_counter->hstats); port_counter->hstats =NULL ;mutex_destroy (&port_counter->lock);
@@ -631,7 +634,10 @@ void rdma_counter_release(struct ib_device *dev)rdma_for_each_port (dev, port) { port_counter = &dev->port_data[port].port_counter; -kfree (port_counter->hstats); +if (port_counter->hstats) { +kfree (port_counter->hstats->is_disabled); +kfree (port_counter->hstats); + }mutex_destroy (&port_counter->lock); } }
drivers/infiniband/core/nldev.c +10 -1
@@ -968,15 +968,21 @@ static int fill_stat_counter_hwcounters(struct sk_buff *msg,if (!table_attr)return -EMSGSIZE ; -for (i =0 ; i < st->num_counters; i++) +mutex_lock (&st->lock); +for (i =0 ; i < st->num_counters; i++) { +if (test_bit (i, st->is_disabled)) +continue ;if (rdma_nl_stat_hwcounter_entry (msg, st->descs[i].name, st->value[i])) goto err; + } +mutex_unlock (&st->lock);nla_nest_end (msg, table_attr);return 0 ; err: +mutex_unlock (&st->lock);nla_nest_cancel (msg, table_attr);return -EMSGSIZE ; }
@@ -2104,6 +2110,9 @@ static int stat_get_doit_default_counter(struct sk_buff *skb, goto err_stats; }for (i =0 ; i < num_cnts; i++) { +if (test_bit (i, stats->is_disabled)) +continue ; + v = stats->value[i] +rdma_counter_get_hwstat_value (device, port, i); if (rdma_nl_stat_hwcounter_entry(msg,
drivers/infiniband/core/sysfs.c +6 -1
@@ -754,8 +754,10 @@ static void ib_port_release(struct kobject *kobj)for (i =0 ; i !=ARRAY_SIZE (port->groups); i++)kfree (port->groups[i].attrs); -if (port->hw_stats_data) +if (port->hw_stats_data) { +kfree (port->hw_stats_data->stats->is_disabled);kfree (port->hw_stats_data->stats); + }kfree (port->hw_stats_data);kfree (port); }
@@ -919,6 +921,7 @@ alloc_hw_stats_device(struct ib_device *ibdev) err_free_data:kfree (data); err_free_stats: +kfree (stats->is_disabled);kfree (stats);return ERR_PTR (-ENOMEM ); }
@@ -926,6 +929,7 @@ alloc_hw_stats_device(struct ib_device *ibdev)void ib_device_release_hw_stats (struct hw_stats_device_data *data) {kfree (data->group.attrs); +kfree (data->stats->is_disabled);kfree (data->stats);kfree (data); }
@@ -1018,6 +1022,7 @@ alloc_hw_stats_port(struct ib_port *port, struct attribute_group *group) err_free_data:kfree (data); err_free_stats: +kfree (stats->is_disabled);kfree (stats);return ERR_PTR (-ENOMEM ); }
include/rdma/ib_verbs.h +12 -0
@@ -566,6 +566,8 @@ struct rdma_stat_desc {* their own value during their allocation routine. * @descs - Array of pointers to static descriptors used for the counters * in directory. +* @is_disabled - A bitmap to indicate each counter is currently disabled +* or not. * @num_counters - How many hardware counters there are. If name is * shorter than this number, a kernel oops will result. Driver authors * are encouraged to leave BUILD_BUG_ON(ARRAY_SIZE(@name) < num_counters)
@@ -578,6 +580,7 @@ struct rdma_hw_stats {unsigned long timestamp;unsigned long lifespan;const struct rdma_stat_desc *descs; +unsigned long *is_disabled;int num_counters;u64 value[]; };
@@ -601,11 +604,20 @@ static inline struct rdma_hw_stats *rdma_alloc_hw_stats_struct(if (!stats)return NULL ; + stats->is_disabled =kcalloc (BITS_TO_LONGS (num_counters), +sizeof (long ),GFP_KERNEL ); +if (!stats->is_disabled) + goto err; + stats->descs = descs; stats->num_counters = num_counters; stats->lifespan =msecs_to_jiffies (lifespan);return stats; + +err: +kfree (stats); +return NULL ; }
Signature · 1 line
2.31.1
Jason Gunthorpe
maintainerRe: [PATCH rdma-next v1 04/11] RDMA/counter: Add an is_disabled field in struct rdma_hw_stats
Quoted 7 lines · Leon Romanovsky
drivers/infiniband/core/nldev.c +1
-0+++ b/drivers/infiniband/core/nldev.c@@ -968,15 +968,21 @@ static int fill_stat_counter_hwcounters(struct sk_buff *msg,if (!table_attr)return -EMSGSIZE ;
drivers/infiniband/core/nldev.c static inline struct rdma_hw_stats *rdma_alloc_hw_stats_struct( · line 611
Quoted 8 lines
drivers/infiniband/core/nldev.c +5
-0@@ -601,11 +604,20 @@ static inline struct rdma_hw_stats *rdma_alloc_hw_stats_struct(if (!stats)return NULL ; + stats->is_disabled =kcalloc (BITS_TO_LONGS (num_counters), +sizeof (long ),GFP_KERNEL ); +if (!stats->is_disabled) + goto err; +
Please de-inline this function and make a rdma_free_hw_stats_struct() call to pair with it. The hw_stats_data kfree should be in there. If you do this as a precursor patch this patch will be much smaller.
Also, the
stats = kzalloc(sizeof(*stats) + num_counters * sizeof(u64),
GFP_KERNEL);
Should be using array_size
Jason
Re: [PATCH rdma-next v1 04/11] RDMA/counter: Add an is_disabled field in struct rdma_hw_stats
Quoted 22 lines · Jason Gunthorpe
Quoted 7 lines · Leon Romanovsky
drivers/infiniband/core/nldev.c +1
-0+++ b/drivers/infiniband/core/nldev.c@@ -968,15 +968,21 @@ static int fill_stat_counter_hwcounters(struct sk_buff *msg,if (!table_attr)return -EMSGSIZE ;drivers/infiniband/core/nldev.c static inline struct rdma_hw_stats *rdma_alloc_hw_stats_struct( · line 611
Quoted 8 lines
drivers/infiniband/core/nldev.c +5
-0@@ -601,11 +604,20 @@ static inline struct rdma_hw_stats *rdma_alloc_hw_stats_struct(if (!stats)return NULL ; + stats->is_disabled =kcalloc (BITS_TO_LONGS (num_counters), +sizeof (long ),GFP_KERNEL ); +if (!stats->is_disabled) + goto err; +Please de-inline this function and make a
rdma_free_hw_stats_struct()call to pair with it. Thehw_stats_datakfree should be in there. If you do this as a precursor patch this patch will be much smaller.
Quoted 6 lines
Also, the
stats = kzalloc(sizeof(*stats) +
num_counters* sizeof(u64),
GFP_KERNEL);Should be using
array_size
Maybe use struct_size:
stats = kzalloc(struct_size(stats, value, num_counters), GFP_KERNEL);
Jason Gunthorpe
maintainerRe: [PATCH rdma-next v1 04/11] RDMA/counter: Add an is_disabled field in struct rdma_hw_stats
Quoted 22 lines · Mark Zhang
Quoted 21 lines · Jason Gunthorpe
Quoted 7 lines · Leon Romanovsky
drivers/infiniband/core/nldev.c +1
-0+++ b/drivers/infiniband/core/nldev.c@@ -968,15 +968,21 @@ static int fill_stat_counter_hwcounters(struct sk_buff *msg,if (!table_attr)return -EMSGSIZE ;drivers/infiniband/core/nldev.c static inline struct rdma_hw_stats *rdma_alloc_hw_stats_struct( · line 610
Quoted 7 lines
drivers/infiniband/core/nldev.c +5
-0@@ -601,11 +604,20 @@ static inline struct rdma_hw_stats *rdma_alloc_hw_stats_struct(if (!stats)return NULL ; + stats->is_disabled =kcalloc (BITS_TO_LONGS (num_counters), +sizeof (long ),GFP_KERNEL ); +if (!stats->is_disabled) + goto err; +Please de-inline this function and make a
rdma_free_hw_stats_struct()call to pair with it. Thehw_stats_datakfree should be in there. If you do this as a precursor patch this patch will be much smaller.
Quoted 8 lines
Quoted 6 lines
Also, the
stats = kzalloc(sizeof(*stats) +
num_counters* sizeof(u64),
GFP_KERNEL);Should be using
array_sizeMaybe use
struct_size:
stats =kzalloc(struct_size(stats, value, num_counters), GFP_KERNEL);
Right
Jason
PATCH 5/11 RDMA/counter: Add optional counter support
In reply to Leon RomanovskyFrom: Aharon Landau <[email protected]>
An optional counter is a vendor-specific counter that may be dynamically enabled/disabled.
This enhancement allows us to expose counters which are for example mutual exclusive and cannot be enabled at the same time, counters that might degrades performance, optional debug counters, etc.
Optional counters are marked with IB_STAT_FLAG_OPTIONAL flag and not exported in sysfs.
--- drivers/infiniband/core/counters.c | 22 ++++++++++++++++++++++ drivers/infiniband/core/device.c | 1 + drivers/infiniband/core/sysfs.c | 26 ++++++++++++++++---------- include/rdma/ib_verbs.h | 14 +++++++++++++- include/rdma/rdma_counter.h | 2 ++ 5 files changed, 54 insertions(+), 11 deletions(-)
drivers/infiniband/core/counters.c +22 -0
@@ -106,6 +106,28 @@ static int __rdma_counter_bind_qp(struct rdma_counter *counter,return ret; } +int rdma_counter_modify (struct ib_device *dev,u32 port,int index,bool enable) +{ +struct rdma_hw_stats *stats; +int ret; + +if (!dev->ops.modify_hw_stat) +return -EOPNOTSUPP ; + + stats =ib_get_hw_stats_port (dev, port); +if (!stats) +return -EINVAL ; + +mutex_lock (&stats->lock); + ret = dev->ops.modify_hw_stat (dev, port, index, enable); +if (!ret) + enable ?clear_bit (index, stats->is_disabled) : +set_bit (index, stats->is_disabled); +mutex_unlock (&stats->lock); + +return ret; +} +static struct rdma_counter *alloc_and_bind (struct ib_device *dev,u32 port,struct ib_qp *qp,enum rdma_nl_counter_mode mode)
drivers/infiniband/core/device.c +1 -0
@@ -2676,6 +2676,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)SET_DEVICE_OP (dev_ops, modify_cq);SET_DEVICE_OP (dev_ops, modify_device);SET_DEVICE_OP (dev_ops, modify_flow_action_esp); +SET_DEVICE_OP (dev_ops, modify_hw_stat);SET_DEVICE_OP (dev_ops, modify_port);SET_DEVICE_OP (dev_ops, modify_qp);SET_DEVICE_OP (dev_ops, modify_srq);
drivers/infiniband/core/sysfs.c +16 -10
@@ -938,7 +938,7 @@ int ib_setup_device_attrs(struct ib_device *ibdev) {struct hw_stats_device_attribute *attr;struct hw_stats_device_data *data; -int i, ret; +int i, ret, pos =0 ; data =alloc_hw_stats_device (ibdev);if (IS_ERR (data)) {
@@ -959,16 +959,19 @@ int ib_setup_device_attrs(struct ib_device *ibdev) data->stats->timestamp = jiffies;for (i =0 ; i < data->stats->num_counters; i++) { - attr = &data->attrs[i]; +if (data->stats->descs[i].flags &IB_STAT_FLAG_OPTIONAL ) +continue ; + attr = &data->attrs[pos];sysfs_attr_init (&attr->attr.attr); attr->attr.attr.name = data->stats->descs[i].name; attr->attr.attr.mode =0444 ; attr->attr.show = hw_stat_device_show; attr->show = show_hw_stats; - data->group.attrs[i] = &attr->attr.attr; + data->group.attrs[pos] = &attr->attr.attr; + pos++; } - attr = &data->attrs[i]; + attr = &data->attrs[pos];sysfs_attr_init (&attr->attr.attr); attr->attr.attr.name ="lifespan" ; attr->attr.attr.mode =0644 ;
@@ -976,7 +979,7 @@ int ib_setup_device_attrs(struct ib_device *ibdev) attr->show = show_stats_lifespan; attr->attr.store = hw_stat_device_store; attr->store = set_stats_lifespan; - data->group.attrs[i] = &attr->attr.attr; + data->group.attrs[pos] = &attr->attr.attr;for (i =0 ; i !=ARRAY_SIZE (ibdev->groups); i++)if (!ibdev->groups[i]) { ibdev->groups[i] = &data->group;
@@ -1032,7 +1035,7 @@ static int setup_hw_port_stats(struct ib_port *port, {struct hw_stats_port_attribute *attr;struct hw_stats_port_data *data; -int i, ret; +int i, ret, pos =0 ; data =alloc_hw_stats_port (port, group);if (IS_ERR (data))
@@ -1050,16 +1053,19 @@ static int setup_hw_port_stats(struct ib_port *port, data->stats->timestamp = jiffies;for (i =0 ; i < data->stats->num_counters; i++) { - attr = &data->attrs[i]; +if (data->stats->descs[i].flags &IB_STAT_FLAG_OPTIONAL ) +continue ; + attr = &data->attrs[pos];sysfs_attr_init (&attr->attr.attr); attr->attr.attr.name = data->stats->descs[i].name; attr->attr.attr.mode =0444 ; attr->attr.show = hw_stat_port_show; attr->show = show_hw_stats; - group->attrs[i] = &attr->attr.attr; + group->attrs[pos] = &attr->attr.attr; + pos++; } - attr = &data->attrs[i]; + attr = &data->attrs[pos];sysfs_attr_init (&attr->attr.attr); attr->attr.attr.name ="lifespan" ; attr->attr.attr.mode =0644 ;
@@ -1067,7 +1073,7 @@ static int setup_hw_port_stats(struct ib_port *port, attr->show = show_stats_lifespan; attr->attr.store = hw_stat_port_store; attr->store = set_stats_lifespan; - group->attrs[i] = &attr->attr.attr; + group->attrs[pos] = &attr->attr.attr; port->hw_stats_data = data;return 0 ;
include/rdma/ib_verbs.h +13 -1
@@ -545,13 +545,18 @@ enum ib_port_speed { IB_SPEED_NDR = 128, }; +enum ib_stat_flag { +IB_STAT_FLAG_OPTIONAL =1 <<0 , +}; +/** * struct rdma_stat_desc * @name - The name of the counter -* +* @flags - Flags of the counter; For example, IB_STAT_FLAG_OPTIONAL */ struct rdma_stat_desc {const char *name; +unsigned int flags; };/**
@@ -2591,6 +2596,13 @@ struct ib_device_ops {int (*get_hw_stats)(struct ib_device *device,struct rdma_hw_stats *stats,u32 port,int index); +/** +* modify_hw_stat - Modify the counter configuration +* @enable: true/false when enable/disable a counter +* Return codes - 0 on success or error code otherwise. +*/ +int (*modify_hw_stat)(struct ib_device *device,u32 port, +int counter_index,bool enable);/** * Allows rdma drivers to add their own restrack attributes. */
include/rdma/rdma_counter.h +2 -0
@@ -63,4 +63,6 @@ int rdma_counter_get_mode(struct ib_device *dev, u32 port,enum rdma_nl_counter_mode *mode, enum rdma_nl_counter_mask *mask); +int rdma_counter_modify (struct ib_device *dev,u32 port,int index, +bool is_add);#endif /* _RDMA_COUNTER_H_ */
Signature · 1 line
2.31.1
Jason Gunthorpe
maintainerRe: [PATCH rdma-next v1 05/11] RDMA/counter: Add optional counter support
Quoted 8 lines · Leon Romanovsky
drivers/infiniband/core/counters.c +7
-0+int rdma_counter_modify (struct ib_device *dev,u32 port,int index,bool enable) +{ +struct rdma_hw_stats *stats; +int ret; + +if (!dev->ops.modify_hw_stat) +return -EOPNOTSUPP ;
drivers/infiniband/core/counters.c static int __rdma_counter_bind_qp(struct rdma_counter *counter, · line 125
Quoted 10 lines
drivers/infiniband/core/counters.c +10
-0+ + stats =ib_get_hw_stats_port (dev, port); +if (!stats) +return -EINVAL ; + +mutex_lock (&stats->lock); + ret = dev->ops.modify_hw_stat (dev, port, index, enable); +if (!ret) + enable ?clear_bit (index, stats->is_disabled) : +set_bit (index, stats->is_disabled);
This is not a kernel coding style write out the if, use success oriented flow
Also, shouldn't this logic protect the driver from being called on non-optional counters?
Quoted 4 lines
drivers/infiniband/core/sysfs.c +2
-1for (i =0 ; i < data->stats->num_counters; i++) { - attr = &data->attrs[i]; +if (data->stats->descs[i].flags &IB_STAT_FLAG_OPTIONAL ) +continue ;
drivers/infiniband/core/sysfs.c int ib_setup_device_attrs(struct ib_device *ibdev) · line 972
Quoted 10 lines
drivers/infiniband/core/sysfs.c +3
-1+ attr = &data->attrs[pos];sysfs_attr_init (&attr->attr.attr); attr->attr.attr.name = data->stats->descs[i].name; attr->attr.attr.mode =0444 ; attr->attr.show = hw_stat_device_show; attr->show = show_hw_stats; - data->group.attrs[i] = &attr->attr.attr; + data->group.attrs[pos] = &attr->attr.attr; + pos++; }
This isn't OK, the hw_stat_device_show() computes the stat index like this:
return stat_attr->show(ibdev, ibdev->hw_stats_data->stats, stat_attr - ibdev->hw_stats_data->attrs, 0, buf);
Which assumes the stats are packed contiguously. This only works because mlx5 is always putting the optional stats at the end.
Quoted 6 lines
/**
* structrdma_stat_desc
* @name - The name of the counter
- *
+ * @flags - Flags of the counter; For example,IB_STAT_FLAG_OPTIONAL*/
The previous patch shouldn't have had the extra blank line then?
include/rdma/rdma_counter.h int rdma_counter_get_mode(struct ib_device *dev, u32 port, · line 67
Quoted 2 lines
include/rdma/rdma_counter.h +2
-0+int rdma_counter_modify (struct ib_device *dev,u32 port,int index, +bool is_add);
index should be unsigned int
The bool is called 'is_add' here but the implementation is 'enable' ?
Jason
Re: [PATCH rdma-next v1 05/11] RDMA/counter: Add optional counter support
Quoted 23 lines · Jason Gunthorpe
Quoted 8 lines · Leon Romanovsky
drivers/infiniband/core/counters.c +7
-0+int rdma_counter_modify (struct ib_device *dev,u32 port,int index,bool enable) +{ +struct rdma_hw_stats *stats; +int ret; + +if (!dev->ops.modify_hw_stat) +return -EOPNOTSUPP ;drivers/infiniband/core/counters.c static int __rdma_counter_bind_qp(struct rdma_counter *counter, · line 125
Quoted 10 lines
drivers/infiniband/core/counters.c +10
-0+ + stats =ib_get_hw_stats_port (dev, port); +if (!stats) +return -EINVAL ; + +mutex_lock (&stats->lock); + ret = dev->ops.modify_hw_stat (dev, port, index, enable); +if (!ret) + enable ?clear_bit (index, stats->is_disabled) : +set_bit (index, stats->is_disabled);This is not a kernel coding style write out the if, use success oriented flow
Quoted 2 lines
Also, shouldn't this logic protect the driver from being called on non-optional counters?
We leave it to driver, driver would return failure if modify is not supported. Is it good?
Quoted 18 lines
Quoted 4 lines
for (i = 0; i < data->stats->num_counters; i++) {drivers/infiniband/core/sysfs.c +2
-1- attr = &data->attrs[i]; +if (data->stats->descs[i].flags &IB_STAT_FLAG_OPTIONAL ) +continue ;drivers/infiniband/core/sysfs.c int ib_setup_device_attrs(struct ib_device *ibdev) · line 972
Quoted 10 lines
drivers/infiniband/core/sysfs.c +3
-1+ attr = &data->attrs[pos];sysfs_attr_init (&attr->attr.attr); attr->attr.attr.name = data->stats->descs[i].name; attr->attr.attr.mode =0444 ; attr->attr.show = hw_stat_device_show; attr->show = show_hw_stats; - data->group.attrs[i] = &attr->attr.attr; + data->group.attrs[pos] = &attr->attr.attr; + pos++; }This isn't OK, the
hw_stat_device_show()computes the stat index like this:
Quoted 5 lines
return stat_attr->show(ibdev, ibdev->hw_stats_data->stats, stat_attr - ibdev->hw_stats_data->attrs, 0, buf);Which assumes the stats are packed contiguously. This only works because mlx5 is always putting the optional stats at the end.
Yes you are right, thanks. Maybe we can add an "index" field in struct hw_stats_device/port_attribute, then set it in setup and use it in show.
Jason Gunthorpe
maintainerRe: [PATCH rdma-next v1 05/11] RDMA/counter: Add optional counter support
Quoted 23 lines · Mark Zhang
Quoted 22 lines · Jason Gunthorpe
Quoted 7 lines · Leon Romanovsky
drivers/infiniband/core/counters.c +7
-0+int rdma_counter_modify (struct ib_device *dev,u32 port,int index,bool enable) +{ +struct rdma_hw_stats *stats; +int ret; + +if (!dev->ops.modify_hw_stat) +return -EOPNOTSUPP ;drivers/infiniband/core/counters.c static int __rdma_counter_bind_qp(struct rdma_counter *counter, · line 125
Quoted 10 lines
drivers/infiniband/core/counters.c +10
-0+ + stats =ib_get_hw_stats_port (dev, port); +if (!stats) +return -EINVAL ; + +mutex_lock (&stats->lock); + ret = dev->ops.modify_hw_stat (dev, port, index, enable); +if (!ret) + enable ?clear_bit (index, stats->is_disabled) : +set_bit (index, stats->is_disabled);This is not a kernel coding style write out the if, use success oriented flow
Quoted 5 lines
Quoted 2 lines
Also, shouldn't this logic protect the driver from being called on non-optional counters?
We leave it to driver, driver would return failure if modify is not supported. Is it good?
I think the core code should do it
Quoted 18 lines
Quoted 18 lines
Quoted 4 lines
for (i = 0; i < data->stats->num_counters; i++) {drivers/infiniband/core/sysfs.c +2
-1- attr = &data->attrs[i]; +if (data->stats->descs[i].flags &IB_STAT_FLAG_OPTIONAL ) +continue ;drivers/infiniband/core/sysfs.c int ib_setup_device_attrs(struct ib_device *ibdev) · line 972
Quoted 10 lines
drivers/infiniband/core/sysfs.c +3
-1+ attr = &data->attrs[pos];sysfs_attr_init (&attr->attr.attr); attr->attr.attr.name = data->stats->descs[i].name; attr->attr.attr.mode =0444 ; attr->attr.show = hw_stat_device_show; attr->show = show_hw_stats; - data->group.attrs[i] = &attr->attr.attr; + data->group.attrs[pos] = &attr->attr.attr; + pos++; }This isn't OK, the
hw_stat_device_show()computes the stat index like this:
Quoted 8 lines
Quoted 5 lines
return stat_attr->show(ibdev, ibdev->hw_stats_data->stats, stat_attr - ibdev->hw_stats_data->attrs, 0, buf);Which assumes the stats are packed contiguously. This only works because mlx5 is always putting the optional stats at the end.
Yes you are right, thanks. Maybe we can add an "index" field in struct hw_stats_device/port_attribute, then set it in setup and use it in show.
You could just add a WARN_ON check that optional stats are at the end I suppose
Jason
Re: [PATCH rdma-next v1 05/11] RDMA/counter: Add optional counter support
Quoted 53 lines · Jason Gunthorpe
Quoted 23 lines · Mark Zhang
Quoted 22 lines · Jason Gunthorpe
Quoted 7 lines · Leon Romanovsky
drivers/infiniband/core/counters.c +7
-0+int rdma_counter_modify (struct ib_device *dev,u32 port,int index,bool enable) +{ +struct rdma_hw_stats *stats; +int ret; + +if (!dev->ops.modify_hw_stat) +return -EOPNOTSUPP ;drivers/infiniband/core/counters.c static int __rdma_counter_bind_qp(struct rdma_counter *counter, · line 125
Quoted 10 lines
drivers/infiniband/core/counters.c +10
-0+ + stats =ib_get_hw_stats_port (dev, port); +if (!stats) +return -EINVAL ; + +mutex_lock (&stats->lock); + ret = dev->ops.modify_hw_stat (dev, port, index, enable); +if (!ret) + enable ?clear_bit (index, stats->is_disabled) : +set_bit (index, stats->is_disabled);This is not a kernel coding style write out the if, use success oriented flow
Quoted 5 lines
Quoted 2 lines
Also, shouldn't this logic protect the driver from being called on non-optional counters?
We leave it to driver, driver would return failure if modify is not supported. Is it good?
I think the core code should do it
Quoted 21 lines
Quoted 21 lines
Quoted 4 lines
for (i = 0; i < data->stats->num_counters; i++) {drivers/infiniband/core/sysfs.c +2
-1- attr = &data->attrs[i]; +if (data->stats->descs[i].flags &IB_STAT_FLAG_OPTIONAL ) +continue ;drivers/infiniband/core/sysfs.c int ib_setup_device_attrs(struct ib_device *ibdev) · line 972
Quoted 10 lines
drivers/infiniband/core/sysfs.c +3
-1+ attr = &data->attrs[pos];sysfs_attr_init (&attr->attr.attr); attr->attr.attr.name = data->stats->descs[i].name; attr->attr.attr.mode =0444 ; attr->attr.show = hw_stat_device_show; attr->show = show_hw_stats; - data->group.attrs[i] = &attr->attr.attr; + data->group.attrs[pos] = &attr->attr.attr; + pos++; }This isn't OK, the
hw_stat_device_show()computes the stat index like this:return stat_attr->show(ibdev, ibdev->hw_stats_data->stats, stat_attr - ibdev->hw_stats_data->attrs, 0, buf);
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Which assumes the stats are packed contiguously. This only works because mlx5 is always putting the optional stats at the end.
Yes you are right, thanks. Maybe we can add an "index" field in struct hw_stats_device/port_attribute, then set it in setup and use it in show.
You could just add a
WARN_ONcheck that optional stats are at the end I suppose
Everyone adds their counters to the end, last example is bnxt_re 9a381f7e5aa2 ("RDMA/bnxt_re: Add extended statistics counters")
Thanks
Quoted 2 lines
Jason
PATCH 6/11 RDMA/nldev: Add support to get status of all counters
In reply to Leon RomanovskyFrom: Aharon Landau <[email protected]>
This patch adds the ability to get the name, index and status of all counters for each link through RDMA netlink. This can be used for user-space to get the current optional-counter mode.
Examples:
$ rdma statistic mode link rocep8s0f0/1 optional-counters cc_rx_ce_pkts
$ rdma statistic mode supported link rocep8s0f0/1 supported optional-counters cc_rx_ce_pkts,cc_rx_cnp_pkts,cc_tx_cnp_pkts link rocep8s0f1/1 supported optional-counters cc_rx_ce_pkts,cc_rx_cnp_pkts,cc_tx_cnp_pkts
--- drivers/infiniband/core/nldev.c | 154 +++++++++++++++++++++++-------- include/uapi/rdma/rdma_netlink.h | 3 + 2 files changed, 121 insertions(+), 36 deletions(-)
drivers/infiniband/core/nldev.c +118 -36
@@ -154,6 +154,8 @@ static const struct nla_policy nldev_policy[RDMA_NLDEV_ATTR_MAX] = { [RDMA_NLDEV_NET_NS_FD] = { .type = NLA_U32 }, [RDMA_NLDEV_SYS_ATTR_NETNS_MODE] = { .type = NLA_U8 }, [RDMA_NLDEV_SYS_ATTR_COPY_ON_FORK] = { .type = NLA_U8 }, + [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_INDEX] = { .type = NLA_U32 }, + [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_DYNAMIC] = { .type = NLA_U8 }, }; static int put_driver_name_print_type(struct sk_buff *msg, const char *name,
@@ -2046,49 +2048,90 @@ static int nldev_stat_del_doit(struct sk_buff *skb, struct nlmsghdr *nlh,return ret; } -static int stat_get_doit_default_counter (struct sk_buff *skb, -struct nlmsghdr *nlh, -struct netlink_ext_ack *extack, -struct nlattr *tb[]) +static int stat_get_doit_stats_list (struct sk_buff *skb, +struct nlmsghdr *nlh, +struct netlink_ext_ack *extack, +struct nlattr *tb[], +struct ib_device *device,u32 port, +struct rdma_hw_stats *stats) { -struct rdma_hw_stats *stats; -struct nlattr *table_attr; -struct ib_device *device; -int ret, num_cnts, i; +struct nlattr *table, *entry;struct sk_buff *msg; -u32 index, port; -u64 v; +int i; -if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX ] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX ]) -return -EINVAL ; + msg =nlmsg_new (NLMSG_DEFAULT_SIZE ,GFP_KERNEL ); +if (!msg) +return -ENOMEM ; - index =nla_get_u32 (tb[RDMA_NLDEV_ATTR_DEV_INDEX ]); - device =ib_device_get_by_index (sock_net (skb->sk), index); -if (!device) -return -EINVAL ; + nlh =nlmsg_put ( + msg,NETLINK_CB (skb).portid, nlh->nlmsg_seq, +RDMA_NL_GET_TYPE (RDMA_NL_NLDEV ,RDMA_NLDEV_CMD_STAT_GET ),0 ,0 ); -if (!device->ops.alloc_hw_port_stats || !device->ops.get_hw_stats) { - ret = -EINVAL ; - goto err; - } +if (fill_nldev_handle (msg, device) || +nla_put_u32 (msg,RDMA_NLDEV_ATTR_PORT_INDEX , port)) + goto err_msg; - port =nla_get_u32 (tb[RDMA_NLDEV_ATTR_PORT_INDEX ]); - stats =ib_get_hw_stats_port (device, port); -if (!stats) { - ret = -EINVAL ; - goto err; + table =nla_nest_start (msg,RDMA_NLDEV_ATTR_STAT_HWCOUNTERS ); +if (!table) + goto err_msg; + +mutex_lock (&stats->lock); +for (i =0 ; i < stats->num_counters; i++) { + entry =nla_nest_start (msg, +RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY ); +if (!entry) + goto err_msg_table; + +if (nla_put_string (msg, +RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME , + stats->descs[i].name) || +nla_put_u32 (msg,RDMA_NLDEV_ATTR_STAT_HWCOUNTER_INDEX , i)) + goto err_msg_entry; + +if ((stats->descs[i].flags &IB_STAT_FLAG_OPTIONAL ) && + (nla_put_u8 (msg,RDMA_NLDEV_ATTR_STAT_HWCOUNTER_DYNAMIC , + !test_bit (i, stats->is_disabled)))) + goto err_msg_entry; + +nla_nest_end (msg, entry); } +mutex_unlock (&stats->lock); + +nla_nest_end (msg, table); +nlmsg_end (msg, nlh); +return rdma_nl_unicast (sock_net (skb->sk), msg,NETLINK_CB (skb).portid); + +err_msg_entry: +nla_nest_cancel (msg, entry); +err_msg_table: +mutex_unlock (&stats->lock); +nla_nest_cancel (msg, table); +err_msg: +nlmsg_free (msg); +return -EMSGSIZE ; +} + +static int stat_get_doit_stats_values (struct sk_buff *skb,struct nlmsghdr *nlh, +struct netlink_ext_ack *extack, +struct nlattr *tb[], +struct ib_device *device,u32 port, +struct rdma_hw_stats *stats) +{ +struct nlattr *table_attr; +int ret, num_cnts, i; +struct sk_buff *msg; +u64 v; + +if (!device->ops.alloc_hw_port_stats || !device->ops.get_hw_stats) +return -EINVAL ; msg =nlmsg_new (NLMSG_DEFAULT_SIZE ,GFP_KERNEL ); -if (!msg) { - ret = -ENOMEM ; - goto err; - } +if (!msg) +return -ENOMEM ; - nlh =nlmsg_put (msg,NETLINK_CB (skb).portid, nlh->nlmsg_seq, -RDMA_NL_GET_TYPE (RDMA_NL_NLDEV , -RDMA_NLDEV_CMD_STAT_GET ), -0 ,0 ); + nlh =nlmsg_put ( + msg,NETLINK_CB (skb).portid, nlh->nlmsg_seq, +RDMA_NL_GET_TYPE (RDMA_NL_NLDEV ,RDMA_NLDEV_CMD_STAT_GET ),0 ,0 );if (fill_nldev_handle (msg, device) ||nla_put_u32 (msg,RDMA_NLDEV_ATTR_PORT_INDEX , port)) {
@@ -2098,7 +2141,8 @@ static int stat_get_doit_default_counter(struct sk_buff *skb,mutex_lock (&stats->lock); - num_cnts = device->ops.get_hw_stats (device, stats, port,0 ); + num_cnts = device->ops.get_hw_stats (device, stats, port, + stats->num_counters);if (num_cnts <0 ) { ret = -EINVAL ; goto err_stats;
@@ -2125,7 +2169,6 @@ static int stat_get_doit_default_counter(struct sk_buff *skb,mutex_unlock (&stats->lock);nlmsg_end (msg, nlh); -ib_device_put (device);return rdma_nl_unicast (sock_net (skb->sk), msg,NETLINK_CB (skb).portid); err_table:
@@ -2134,7 +2177,46 @@ static int stat_get_doit_default_counter(struct sk_buff *skb,mutex_unlock (&stats->lock); err_msg:nlmsg_free (msg); -err: +return ret; +} + +static int stat_get_doit_default_counter (struct sk_buff *skb, +struct nlmsghdr *nlh, +struct netlink_ext_ack *extack, +struct nlattr *tb[]) +{ +struct rdma_hw_stats *stats; +struct ib_device *device; +u32 index, port; +int ret; + +if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX ] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX ]) +return -EINVAL ; + + index =nla_get_u32 (tb[RDMA_NLDEV_ATTR_DEV_INDEX ]); + device =ib_device_get_by_index (sock_net (skb->sk), index); +if (!device) +return -EINVAL ; + + port =nla_get_u32 (tb[RDMA_NLDEV_ATTR_PORT_INDEX ]); +if (!rdma_is_port_valid (device, port)) { + ret = -EINVAL ; + goto end; + } + + stats =ib_get_hw_stats_port (device, port); +if (!stats) { + ret = -EINVAL ; + goto end; + } + +if (tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_DYNAMIC ]) + ret =stat_get_doit_stats_list (skb, nlh, extack, tb, + device, port, stats); +else + ret =stat_get_doit_stats_values (skb, nlh, extack, tb, device, + port, stats); +end:ib_device_put (device);return ret; }
include/uapi/rdma/rdma_netlink.h +3 -0
@@ -549,6 +549,9 @@ enum rdma_nldev_attr {RDMA_NLDEV_SYS_ATTR_COPY_ON_FORK ,/* u8 */ +RDMA_NLDEV_ATTR_STAT_HWCOUNTER_INDEX ,/* u32 */ + RDMA_NLDEV_ATTR_STAT_HWCOUNTER_DYNAMIC, /* u8 */ +/* * Always the end */
Signature · 1 line
2.31.1
Jason Gunthorpe
maintainerRe: [PATCH rdma-next v1 06/11] RDMA/nldev: Add support to get status of all counters
Quoted 26 lines · Leon Romanovsky
drivers/infiniband/core/nldev.c +26
-0+static int stat_get_doit_default_counter (struct sk_buff *skb, +struct nlmsghdr *nlh, +struct netlink_ext_ack *extack, +struct nlattr *tb[]) +{ +struct rdma_hw_stats *stats; +struct ib_device *device; +u32 index, port; +int ret; + +if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX ] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX ]) +return -EINVAL ; + + index =nla_get_u32 (tb[RDMA_NLDEV_ATTR_DEV_INDEX ]); + device =ib_device_get_by_index (sock_net (skb->sk), index); +if (!device) +return -EINVAL ; + + port =nla_get_u32 (tb[RDMA_NLDEV_ATTR_PORT_INDEX ]); +if (!rdma_is_port_valid (device, port)) { + ret = -EINVAL ; + goto end; + } + + stats =ib_get_hw_stats_port (device, port); +if (!stats) {
drivers/infiniband/core/nldev.c static int stat_get_doit_default_counter(struct sk_buff *skb, · line 2218
Quoted 10 lines
drivers/infiniband/core/nldev.c +10
-0+ ret = -EINVAL ; + goto end; + } + +if (tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_DYNAMIC ]) + ret =stat_get_doit_stats_list (skb, nlh, extack, tb, + device, port, stats); +else + ret =stat_get_doit_stats_values (skb, nlh, extack, tb, device, + port, stats);
This seems strange, why is the output of a get contingent on a ignored input attribute? Shouldn't the HWCOUNTER_DYNAMIC just always be emitted?
Jason
Re: [PATCH rdma-next v1 06/11] RDMA/nldev: Add support to get status of all counters
Quoted 33 lines · Jason Gunthorpe
Quoted 32 lines · Leon Romanovsky
drivers/infiniband/core/nldev.c +32
-0+static int stat_get_doit_default_counter (struct sk_buff *skb, +struct nlmsghdr *nlh, +struct netlink_ext_ack *extack, +struct nlattr *tb[]) +{ +struct rdma_hw_stats *stats; +struct ib_device *device; +u32 index, port; +int ret; + +if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX ] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX ]) +return -EINVAL ; + + index =nla_get_u32 (tb[RDMA_NLDEV_ATTR_DEV_INDEX ]); + device =ib_device_get_by_index (sock_net (skb->sk), index); +if (!device) +return -EINVAL ; + + port =nla_get_u32 (tb[RDMA_NLDEV_ATTR_PORT_INDEX ]); +if (!rdma_is_port_valid (device, port)) { + ret = -EINVAL ; + goto end; + } + + stats =ib_get_hw_stats_port (device, port); +if (!stats) { + ret = -EINVAL ; + goto end; + } + +if (tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_DYNAMIC ]) + ret = stat_get_doit_stats_list(skb, nlh, extack, tb,
Quoted 8 lines
drivers/infiniband/core/nldev.c static int stat_get_doit_default_counter(struct sk_buff *skb, · line 2218
Quoted 4 lines
drivers/infiniband/core/nldev.c +4
-0+ device, port, stats); + else + ret =stat_get_doit_stats_values (skb, nlh, extack, tb, device, + port, stats);This seems strange, why is the output of a get contingent on a ignored input attribute? Shouldn't the
HWCOUNTER_DYNAMICjust always be emitted?
The CMD_STAT_GET is originally used to get the default hwcounter statistic (the value of all hwstats), now we also want to use this command to get a list of counters (just name and status), so kernel differentiates these 2 cases based on HWCOUNTER_DYNAMIC attr.
Jason Gunthorpe
maintainerRe: [PATCH rdma-next v1 06/11] RDMA/nldev: Add support to get status of all counters
Quoted 43 lines · Mark Zhang
Quoted 33 lines · Jason Gunthorpe
Quoted 32 lines · Leon Romanovsky
drivers/infiniband/core/nldev.c +32
-0+static int stat_get_doit_default_counter (struct sk_buff *skb, +struct nlmsghdr *nlh, +struct netlink_ext_ack *extack, +struct nlattr *tb[]) +{ +struct rdma_hw_stats *stats; +struct ib_device *device; +u32 index, port; +int ret; + +if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX ] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX ]) +return -EINVAL ; + + index =nla_get_u32 (tb[RDMA_NLDEV_ATTR_DEV_INDEX ]); + device =ib_device_get_by_index (sock_net (skb->sk), index); +if (!device) +return -EINVAL ; + + port =nla_get_u32 (tb[RDMA_NLDEV_ATTR_PORT_INDEX ]); +if (!rdma_is_port_valid (device, port)) { + ret = -EINVAL ; + goto end; + } + + stats =ib_get_hw_stats_port (device, port); +if (!stats) { + ret = -EINVAL ; + goto end; + } + +if (tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_DYNAMIC ]) + ret = stat_get_doit_stats_list(skb, nlh, extack, tb,Quoted 8 lines
drivers/infiniband/core/nldev.c static int stat_get_doit_default_counter(struct sk_buff *skb, · line 2218
Quoted 4 lines
drivers/infiniband/core/nldev.c +4
-0+ device, port, stats); + else + ret =stat_get_doit_stats_values (skb, nlh, extack, tb, device, + port, stats);This seems strange, why is the output of a get contingent on a ignored input attribute? Shouldn't the
HWCOUNTER_DYNAMICjust always be emitted?
Quoted 4 lines
The
CMD_STAT_GETis originally used to get the default hwcounter statistic (the value of all hwstats), now we also want to use this command to get a list of counters (just name and status), so kernel differentiates these 2 cases based onHWCOUNTER_DYNAMICattr.
Don't do that, it is not how netlink works. Either the whole attribute should be returned or you need a new get command
Jason
Re: [PATCH rdma-next v1 06/11] RDMA/nldev: Add support to get status of all counters
Quoted 44 lines · Jason Gunthorpe
Quoted 43 lines · Mark Zhang
Quoted 41 lines · Jason Gunthorpe
Quoted 26 lines · Leon Romanovsky
drivers/infiniband/core/nldev.c +26
-0+static int stat_get_doit_default_counter (struct sk_buff *skb, +struct nlmsghdr *nlh, +struct netlink_ext_ack *extack, +struct nlattr *tb[]) +{ +struct rdma_hw_stats *stats; +struct ib_device *device; +u32 index, port; +int ret; + +if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX ] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX ]) +return -EINVAL ; + + index =nla_get_u32 (tb[RDMA_NLDEV_ATTR_DEV_INDEX ]); + device =ib_device_get_by_index (sock_net (skb->sk), index); +if (!device) +return -EINVAL ; + + port =nla_get_u32 (tb[RDMA_NLDEV_ATTR_PORT_INDEX ]); +if (!rdma_is_port_valid (device, port)) { + ret = -EINVAL ; + goto end; + } + + stats =ib_get_hw_stats_port (device, port); +if (!stats) {drivers/infiniband/core/nldev.c static int stat_get_doit_default_counter(struct sk_buff *skb, · line 2218
Quoted 10 lines
drivers/infiniband/core/nldev.c +10
-0+ ret = -EINVAL ; + goto end; + } + +if (tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_DYNAMIC ]) + ret =stat_get_doit_stats_list (skb, nlh, extack, tb, + device, port, stats); +else + ret =stat_get_doit_stats_values (skb, nlh, extack, tb, device, + port, stats);This seems strange, why is the output of a get contingent on a ignored input attribute? Shouldn't the
HWCOUNTER_DYNAMICjust always be emitted?
Quoted 7 lines
Quoted 4 lines
The
CMD_STAT_GETis originally used to get the default hwcounter statistic (the value of all hwstats), now we also want to use this command to get a list of counters (just name and status), so kernel differentiates these 2 cases based onHWCOUNTER_DYNAMICattr.Don't do that, it is not how netlink works. Either the whole attribute should be returned or you need a new get command
Will add a new get command for backward compatibility, thanks.
Re: [PATCH rdma-next v1 06/11] RDMA/nldev: Add support to get status of all counters
In reply to Jason GunthorpeQuoted 44 lines · Jason Gunthorpe
Quoted 43 lines · Mark Zhang
Quoted 41 lines · Jason Gunthorpe
Quoted 26 lines · Leon Romanovsky
drivers/infiniband/core/nldev.c +26
-0+static int stat_get_doit_default_counter (struct sk_buff *skb, +struct nlmsghdr *nlh, +struct netlink_ext_ack *extack, +struct nlattr *tb[]) +{ +struct rdma_hw_stats *stats; +struct ib_device *device; +u32 index, port; +int ret; + +if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX ] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX ]) +return -EINVAL ; + + index =nla_get_u32 (tb[RDMA_NLDEV_ATTR_DEV_INDEX ]); + device =ib_device_get_by_index (sock_net (skb->sk), index); +if (!device) +return -EINVAL ; + + port =nla_get_u32 (tb[RDMA_NLDEV_ATTR_PORT_INDEX ]); +if (!rdma_is_port_valid (device, port)) { + ret = -EINVAL ; + goto end; + } + + stats =ib_get_hw_stats_port (device, port); +if (!stats) {drivers/infiniband/core/nldev.c static int stat_get_doit_default_counter(struct sk_buff *skb, · line 2218
Quoted 10 lines
drivers/infiniband/core/nldev.c +10
-0+ ret = -EINVAL ; + goto end; + } + +if (tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_DYNAMIC ]) + ret =stat_get_doit_stats_list (skb, nlh, extack, tb, + device, port, stats); +else + ret =stat_get_doit_stats_values (skb, nlh, extack, tb, device, + port, stats);This seems strange, why is the output of a get contingent on a ignored input attribute? Shouldn't the
HWCOUNTER_DYNAMICjust always be emitted?
Quoted 7 lines
Quoted 4 lines
The
CMD_STAT_GETis originally used to get the default hwcounter statistic (the value of all hwstats), now we also want to use this command to get a list of counters (just name and status), so kernel differentiates these 2 cases based onHWCOUNTER_DYNAMICattr.Don't do that, it is not how netlink works. Either the whole attribute should be returned or you need a new get command
The netlink way is to be independent on returned parameter, if it not supported, this parameter won't be available at all. This makes HWCOUNTER_DYNAMIC to work exactly as netlink would do.
Thanks
Quoted 2 lines
Jason
Jason Gunthorpe
maintainerRe: [PATCH rdma-next v1 06/11] RDMA/nldev: Add support to get status of all counters
Quoted 50 lines · Leon Romanovsky
Quoted 49 lines · Jason Gunthorpe
Quoted 47 lines · Mark Zhang
Quoted 33 lines · Jason Gunthorpe
Quoted 32 lines · Leon Romanovsky
drivers/infiniband/core/nldev.c +32
-0+static int stat_get_doit_default_counter (struct sk_buff *skb, +struct nlmsghdr *nlh, +struct netlink_ext_ack *extack, +struct nlattr *tb[]) +{ +struct rdma_hw_stats *stats; +struct ib_device *device; +u32 index, port; +int ret; + +if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX ] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX ]) +return -EINVAL ; + + index =nla_get_u32 (tb[RDMA_NLDEV_ATTR_DEV_INDEX ]); + device =ib_device_get_by_index (sock_net (skb->sk), index); +if (!device) +return -EINVAL ; + + port =nla_get_u32 (tb[RDMA_NLDEV_ATTR_PORT_INDEX ]); +if (!rdma_is_port_valid (device, port)) { + ret = -EINVAL ; + goto end; + } + + stats =ib_get_hw_stats_port (device, port); +if (!stats) { + ret = -EINVAL ; + goto end; + } + +if (tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_DYNAMIC ]) + ret = stat_get_doit_stats_list(skb, nlh, extack, tb,Quoted 8 lines
drivers/infiniband/core/nldev.c static int stat_get_doit_default_counter(struct sk_buff *skb, · line 2218
Quoted 4 lines
drivers/infiniband/core/nldev.c +4
-0+ device, port, stats); + else + ret =stat_get_doit_stats_values (skb, nlh, extack, tb, device, + port, stats);This seems strange, why is the output of a get contingent on a ignored input attribute? Shouldn't the
HWCOUNTER_DYNAMICjust always be emitted?The
CMD_STAT_GETis originally used to get the default hwcounter statistic (the value of all hwstats), now we also want to use this command to get a list of counters (just name and status), so kernel differentiates these 2 cases based onHWCOUNTER_DYNAMICattr.
Quoted 6 lines
Quoted 2 lines
Don't do that, it is not how netlink works. Either the whole attribute should be returned or you need a new get command
The netlink way is to be independent on returned parameter, if it not supported, this parameter won't be available at all. This makes
HWCOUNTER_DYNAMICto work exactly as netlink would do.
The issue is making the output dependent on the input:
+ if (tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_DYNAMIC])
Setting HWCOUNTER_DYNAMIC as an input flag to get the GET to return a completely different output format is not netlinky
Either always return HWCOUNTER_DYNAMIC or make another query to get it
Jason
PATCH 7/11 RDMA/nldev: Allow optional-counter status configuration through RDMA netlink
In reply to Leon RomanovskyFrom: Aharon Landau <[email protected]>
Provide an option to allow users to enable/disable optional counters through RDMA netlink. Limiting it to users with ADMIN capability only.
Examples:
1. Enable optional counters cc_rx_ce_pkts and cc_rx_cnp_pkts (and disable all others):
$ sudo rdma statistic set link rocep8s0f0/1 optional-counters \
cc_rx_ce_pkts,cc_rx_cnp_pkts2. Remove all optional counters:
$ sudo rdma statistic unset link rocep8s0f0/1 optional-counters
--- drivers/infiniband/core/nldev.c | 118 ++++++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 30 deletions(-)
drivers/infiniband/core/nldev.c +88 -30
@@ -1897,42 +1897,65 @@ static int nldev_set_sys_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,return err; } -static int nldev_stat_set_doit (struct sk_buff *skb,struct nlmsghdr *nlh, -struct netlink_ext_ack *extack) +static int nldev_stat_set_counter_dynamic_doit (struct nlattr *tb[], +struct ib_device *device, +u32 port) { -u32 index, port, mode, mask =0 , qpn, cntn =0 ; -struct nlattr *tb[RDMA_NLDEV_ATTR_MAX ]; -struct ib_device *device; -struct sk_buff *msg; -int ret; +struct rdma_hw_stats *stats; +int rem, i, index, ret =0 ; +bool need_enable, disabled; +struct nlattr *entry_attr; - ret =nlmsg_parse (nlh,0 , tb,RDMA_NLDEV_ATTR_MAX -1 , - nldev_policy, extack); -/* Currently only counter for QP is supported */ -if (ret || !tb[RDMA_NLDEV_ATTR_STAT_RES ] || - !tb[RDMA_NLDEV_ATTR_DEV_INDEX ] || - !tb[RDMA_NLDEV_ATTR_PORT_INDEX ] || !tb[RDMA_NLDEV_ATTR_STAT_MODE ]) + stats =ib_get_hw_stats_port (device, port); +if (!stats)return -EINVAL ; -if (nla_get_u32 (tb[RDMA_NLDEV_ATTR_STAT_RES ]) !=RDMA_NLDEV_ATTR_RES_QP ) -return -EINVAL ; +for (i =0 ; i < stats->num_counters; i++) { +if (!(stats->descs[i].flags &IB_STAT_FLAG_OPTIONAL )) +continue ; - index =nla_get_u32 (tb[RDMA_NLDEV_ATTR_DEV_INDEX ]); - device =ib_device_get_by_index (sock_net (skb->sk), index); -if (!device) -return -EINVAL ; + need_enable = false; + disabled =test_bit (i, stats->is_disabled); +nla_for_each_nested (entry_attr, + tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS ], rem) { + index =nla_get_u32 (entry_attr); +if (index >= stats->num_counters) +return -EINVAL ; +if (i == index) { + need_enable = true; +break ; + } + } - port =nla_get_u32 (tb[RDMA_NLDEV_ATTR_PORT_INDEX ]); -if (!rdma_is_port_valid (device, port)) { - ret = -EINVAL ; - goto err; +if (disabled && need_enable) + ret =rdma_counter_modify (device, port, i, true); +else if (!disabled && !need_enable) + ret =rdma_counter_modify (device, port, i, false); + +if (ret) +break ; } +return ret; +} + +static int nldev_stat_set_mode_doit (struct sk_buff *skb,struct nlmsghdr *nlh, +struct netlink_ext_ack *extack, +struct nlattr *tb[], +struct ib_device *device,u32 port) +{ +u32 mode, mask =0 , qpn, cntn =0 ; +struct sk_buff *msg; +int ret; + +/* Currently only counter for QP is supported */ +if (nla_get_u32 (tb[RDMA_NLDEV_ATTR_STAT_RES ]) !=RDMA_NLDEV_ATTR_RES_QP ) +return -EINVAL ; + msg =nlmsg_new (NLMSG_DEFAULT_SIZE ,GFP_KERNEL ); -if (!msg) { - ret = -ENOMEM ; - goto err; - } +if (!msg) +return -ENOMEM ; + nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_STAT_SET),
@@ -1947,8 +1970,10 @@ static int nldev_stat_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,if (ret) goto err_msg; }else { -if (!tb[RDMA_NLDEV_ATTR_RES_LQPN ]) +if (!tb[RDMA_NLDEV_ATTR_RES_LQPN ]) { + ret = -EINVAL ; goto err_msg; + } qpn =nla_get_u32 (tb[RDMA_NLDEV_ATTR_RES_LQPN ]);if (tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID ]) { cntn =nla_get_u32 (tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID ]);
@@ -1970,14 +1995,47 @@ static int nldev_stat_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh, }nlmsg_end (msg, nlh); -ib_device_put (device);return rdma_nl_unicast (sock_net (skb->sk), msg,NETLINK_CB (skb).portid); err_fill:rdma_counter_unbind_qpn (device, port, qpn, cntn); err_msg:nlmsg_free (msg); -err: +return ret; +} + +static int nldev_stat_set_doit (struct sk_buff *skb,struct nlmsghdr *nlh, +struct netlink_ext_ack *extack) +{ +struct nlattr *tb[RDMA_NLDEV_ATTR_MAX ]; +struct ib_device *device; +u32 index, port; +int ret; + + ret =nlmsg_parse (nlh,0 , tb,RDMA_NLDEV_ATTR_MAX -1 , nldev_policy, + extack); +if (ret) +return -EINVAL ; + + index =nla_get_u32 (tb[RDMA_NLDEV_ATTR_DEV_INDEX ]); + device =ib_device_get_by_index (sock_net (skb->sk), index); +if (!device) +return -EINVAL ; + + port =nla_get_u32 (tb[RDMA_NLDEV_ATTR_PORT_INDEX ]); +if (!rdma_is_port_valid (device, port)) { + ret = -EINVAL ; + goto end; + } + +if (tb[RDMA_NLDEV_ATTR_STAT_MODE ]) + ret =nldev_stat_set_mode_doit (skb, nlh, extack, tb, device, + port); +else if (tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_DYNAMIC ]) + ret =nldev_stat_set_counter_dynamic_doit (tb, device, port); +else + ret = -EINVAL ; +end:ib_device_put (device);return ret; }
Signature · 1 line
2.31.1
Jason Gunthorpe
maintainerRe: [PATCH rdma-next v1 07/11] RDMA/nldev: Allow optional-counter status configuration through RDMA netlink
Quoted 12 lines · Leon Romanovsky
drivers/infiniband/core/nldev.c +11
-1-return -EINVAL ; + need_enable = false; + disabled =test_bit (i, stats->is_disabled); +nla_for_each_nested (entry_attr, + tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS ], rem) { + index =nla_get_u32 (entry_attr); +if (index >= stats->num_counters) +return -EINVAL ; +if (i == index) { + need_enable = true; +break ; + }
drivers/infiniband/core/nldev.c static int nldev_set_sys_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh, · line 1933
Quoted 10 lines
drivers/infiniband/core/nldev.c +5
-4+ } - port =nla_get_u32 (tb[RDMA_NLDEV_ATTR_PORT_INDEX ]); -if (!rdma_is_port_valid (device, port)) { - ret = -EINVAL ; - goto err; +if (disabled && need_enable) + ret =rdma_counter_modify (device, port, i, true); +else if (!disabled && !need_enable) + ret =rdma_counter_modify (device, port, i, false);
This disabled check looks racy, I would do the no-change optimization inside rdma_counter_modify()
Also, this is a O(N^2) algorithm, why not do it in one pass with a small memory allocation for the target state bitmap?
Jason
Re: [PATCH rdma-next v1 07/11] RDMA/nldev: Allow optional-counter status configuration through RDMA netlink
Quoted 27 lines · Jason Gunthorpe
Quoted 12 lines · Leon Romanovsky
drivers/infiniband/core/nldev.c +11
-1-return -EINVAL ; + need_enable = false; + disabled =test_bit (i, stats->is_disabled); +nla_for_each_nested (entry_attr, + tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS ], rem) { + index =nla_get_u32 (entry_attr); +if (index >= stats->num_counters) +return -EINVAL ; +if (i == index) { + need_enable = true; +break ; + }drivers/infiniband/core/nldev.c static int nldev_set_sys_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh, · line 1933
Quoted 10 lines
drivers/infiniband/core/nldev.c +5
-4+ } - port =nla_get_u32 (tb[RDMA_NLDEV_ATTR_PORT_INDEX ]); -if (!rdma_is_port_valid (device, port)) { - ret = -EINVAL ; - goto err; +if (disabled && need_enable) + ret =rdma_counter_modify (device, port, i, true); +else if (!disabled && !need_enable) + ret =rdma_counter_modify (device, port, i, false);This disabled check looks racy, I would do the no-change optimization inside
rdma_counter_modify()
Quoted 2 lines
Also, this is a O(N^2) algorithm, why not do it in one pass with a small memory allocation for the target state bitmap?
We don't have many counters. Is this optimization really worth it?
Thanks
Quoted 2 lines
Jason
PATCH 8/11 RDMA/mlx5: Support optional counters in hw_stats initialization
In reply to Leon RomanovskyFrom: Aharon Landau <[email protected]>
Add optional counter support when allocate and initialize hw_stats structure. Optional counters have IB_STAT_FLAG_OPTIONAL flag set and are disabled by default.
--- drivers/infiniband/hw/mlx5/counters.c | 90 ++++++++++++++++++++++----- drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 + 2 files changed, 75 insertions(+), 16 deletions(-)
drivers/infiniband/hw/mlx5/counters.c +74 -16
@@ -75,6 +75,21 @@ static const struct mlx5_ib_counter ext_ppcnt_cnts[] = { INIT_EXT_PPCNT_COUNTER(rx_icrc_encapsulated), }; +#define INIT_OP_COUNTER (_name) \ + { .name = #_name } + +static const struct mlx5_ib_counter basic_op_cnts[] = { +INIT_OP_COUNTER (cc_rx_ce_pkts), +}; + +static const struct mlx5_ib_counter rdmarx_cnp_op_cnts[] = { +INIT_OP_COUNTER (cc_rx_cnp_pkts), +}; + +static const struct mlx5_ib_counter rdmatx_cnp_op_cnts[] = { +INIT_OP_COUNTER (cc_tx_cnp_pkts), +}; +static int mlx5_ib_read_counters (struct ib_counters *counters,struct ib_counters_read_attr *read_attr,struct uverbs_attr_bundle *attrs)
@@ -161,17 +176,34 @@ u16 mlx5_ib_get_counters_id(struct mlx5_ib_dev *dev, u32 port_num)return cnts->set_id; } +static struct rdma_hw_stats *do_alloc_stats (const struct mlx5_ib_counters *cnts) +{ +struct rdma_hw_stats *stats; +u32 num_hw_counters; +int i; + + num_hw_counters = cnts->num_q_counters + cnts->num_cong_counters + + cnts->num_ext_ppcnt_counters; + stats =rdma_alloc_hw_stats_struct (cnts->descs, + num_hw_counters + + cnts->num_op_counters, +RDMA_HW_STATS_DEFAULT_LIFESPAN ); +if (!stats) +return NULL ; + +for (i =0 ; i < cnts->num_op_counters; i++) +set_bit (num_hw_counters + i, stats->is_disabled); + +return stats; +} +static struct rdma_hw_stats *mlx5_ib_alloc_hw_device_stats (struct ib_device *ibdev) {struct mlx5_ib_dev *dev =to_mdev (ibdev);const struct mlx5_ib_counters *cnts = &dev->port[0 ].cnts; -return rdma_alloc_hw_stats_struct (cnts->descs, - cnts->num_q_counters + - cnts->num_cong_counters + - cnts->num_ext_ppcnt_counters, -RDMA_HW_STATS_DEFAULT_LIFESPAN ); +return do_alloc_stats (cnts); } static struct rdma_hw_stats *
@@ -180,11 +212,7 @@ mlx5_ib_alloc_hw_port_stats(struct ib_device *ibdev, u32 port_num)struct mlx5_ib_dev *dev =to_mdev (ibdev);const struct mlx5_ib_counters *cnts = &dev->port[port_num -1 ].cnts; -return rdma_alloc_hw_stats_struct (cnts->descs, - cnts->num_q_counters + - cnts->num_cong_counters + - cnts->num_ext_ppcnt_counters, -RDMA_HW_STATS_DEFAULT_LIFESPAN ); +return do_alloc_stats (cnts); } static int mlx5_ib_query_q_counters(struct mlx5_core_dev *mdev,
@@ -302,11 +330,7 @@ mlx5_ib_counter_alloc_stats(struct rdma_counter *counter)const struct mlx5_ib_counters *cnts =get_counters (dev, counter->port -1 ); -return rdma_alloc_hw_stats_struct (cnts->descs, - cnts->num_q_counters + - cnts->num_cong_counters + - cnts->num_ext_ppcnt_counters, -RDMA_HW_STATS_DEFAULT_LIFESPAN ); +return do_alloc_stats (cnts); }static int mlx5_ib_counter_update_stats (struct rdma_counter *counter)
@@ -425,13 +449,34 @@ static void mlx5_ib_fill_counters(struct mlx5_ib_dev *dev, offsets[j] = ext_ppcnt_cnts[i].offset; } } + +for (i =0 ; i <ARRAY_SIZE (basic_op_cnts); i++, j++) { + descs[j].name = basic_op_cnts[i].name; + descs[j].flags |=IB_STAT_FLAG_OPTIONAL ; + } + +if (MLX5_CAP_FLOWTABLE (dev->mdev, + ft_field_support_2_nic_receive_rdma.bth_opcode)) { +for (i =0 ; i <ARRAY_SIZE (rdmarx_cnp_op_cnts); i++, j++) { + descs[j].name = rdmarx_cnp_op_cnts[i].name; + descs[j].flags |=IB_STAT_FLAG_OPTIONAL ; + } + } + +if (MLX5_CAP_FLOWTABLE (dev->mdev, + ft_field_support_2_nic_transmit_rdma.bth_opcode)) { +for (i =0 ; i <ARRAY_SIZE (rdmatx_cnp_op_cnts); i++, j++) { + descs[j].name = rdmatx_cnp_op_cnts[i].name; + descs[j].flags |=IB_STAT_FLAG_OPTIONAL ; + } + } }static int __mlx5_ib_alloc_counters (struct mlx5_ib_dev *dev,struct mlx5_ib_counters *cnts) { -u32 num_counters; +u32 num_counters, num_op_counters; num_counters =ARRAY_SIZE (basic_q_cnts);
@@ -457,6 +502,19 @@ static int __mlx5_ib_alloc_counters(struct mlx5_ib_dev *dev, cnts->num_ext_ppcnt_counters =ARRAY_SIZE (ext_ppcnt_cnts); num_counters +=ARRAY_SIZE (ext_ppcnt_cnts); } + + num_op_counters =ARRAY_SIZE (basic_op_cnts); + +if (MLX5_CAP_FLOWTABLE (dev->mdev, + ft_field_support_2_nic_receive_rdma.bth_opcode)) + num_op_counters +=ARRAY_SIZE (rdmarx_cnp_op_cnts); + +if (MLX5_CAP_FLOWTABLE (dev->mdev, + ft_field_support_2_nic_transmit_rdma.bth_opcode)) + num_op_counters +=ARRAY_SIZE (rdmatx_cnp_op_cnts); + + cnts->num_op_counters = num_op_counters; + num_counters += num_op_counters; cnts->descs =kcalloc (num_counters,sizeof (struct rdma_stat_desc ),GFP_KERNEL );if (!cnts->descs)
drivers/infiniband/hw/mlx5/mlx5_ib.h +1 -0
@@ -803,6 +803,7 @@ struct mlx5_ib_counters {u32 num_q_counters;u32 num_cong_counters;u32 num_ext_ppcnt_counters; +u32 num_op_counters;u16 set_id; };
Signature · 1 line
2.31.1
PATCH 9/11 RDMA/mlx5: Add steering support in optional flow counters
In reply to Leon RomanovskyFrom: Aharon Landau <[email protected]>
Adding steering infrastructure for adding and removing optional counter. This allows to add and remove the counters dynamically in order not to hurt performance.
--- drivers/infiniband/hw/mlx5/fs.c | 187 +++++++++++++++++++++++++++ drivers/infiniband/hw/mlx5/mlx5_ib.h | 24 ++++ include/rdma/ib_hdrs.h | 1 + 3 files changed, 212 insertions(+)
drivers/infiniband/hw/mlx5/fs.c +187 -0
@@ -10,12 +10,14 @@#include <rdma/uverbs_std_types.h> #include <rdma/mlx5_user_ioctl_cmds.h> #include <rdma/mlx5_user_ioctl_verbs.h> +#include <rdma/ib_hdrs.h> #include <rdma/ib_umem.h> #include <linux/mlx5/driver.h> #include <linux/mlx5/fs.h> #include <linux/mlx5/fs_helpers.h> #include <linux/mlx5/accel.h> #include <linux/mlx5/eswitch.h> +#include <net/inet_ecn.h> #include "mlx5_ib.h" #include "counters.h" #include "devx.h"
@@ -847,6 +849,191 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev,return prio; } +enum { +RDMA_RX_ECN_OPCOUNTER_PRIO , +RDMA_RX_CNP_OPCOUNTER_PRIO , +}; + +enum { +RDMA_TX_CNP_OPCOUNTER_PRIO , +}; + +static int set_vhca_port_spec (struct mlx5_ib_dev *dev,u32 port_num, +struct mlx5_flow_spec *spec) +{ +if (!MLX5_CAP_FLOWTABLE_RDMA_RX (dev->mdev, + ft_field_support.source_vhca_port) || + !MLX5_CAP_FLOWTABLE_RDMA_TX (dev->mdev, + ft_field_support.source_vhca_port)) +return -EOPNOTSUPP ; + +MLX5_SET_TO_ONES (fte_match_param, &spec->match_criteria, + misc_parameters.source_vhca_port); +MLX5_SET (fte_match_param, &spec->match_value, + misc_parameters.source_vhca_port, port_num); + +return 0 ; +} + +static int set_ecn_ce_spec (struct mlx5_ib_dev *dev,u32 port_num, +struct mlx5_flow_spec *spec,int ipv) +{ +if (!MLX5_CAP_FLOWTABLE_RDMA_RX (dev->mdev, + ft_field_support.outer_ip_version)) +return -EOPNOTSUPP ; + +if (mlx5_core_mp_enabled (dev->mdev) && +set_vhca_port_spec (dev, port_num, spec)) +return -EOPNOTSUPP ; + +MLX5_SET_TO_ONES (fte_match_param, spec->match_criteria, + outer_headers.ip_ecn); +MLX5_SET (fte_match_param, spec->match_value, outer_headers.ip_ecn, +INET_ECN_CE ); +MLX5_SET_TO_ONES (fte_match_param, spec->match_criteria, + outer_headers.ip_version); +MLX5_SET (fte_match_param, spec->match_value, outer_headers.ip_version, + ipv); + + spec->match_criteria_enable = +get_match_criteria_enable (spec->match_criteria); + +return 0 ; +} + +static int set_cnp_spec (struct mlx5_ib_dev *dev,u32 port_num, +struct mlx5_flow_spec *spec) +{ +if (mlx5_core_mp_enabled (dev->mdev) && +set_vhca_port_spec (dev, port_num, spec)) +return -EOPNOTSUPP ; + +MLX5_SET_TO_ONES (fte_match_param, spec->match_criteria, + misc_parameters.bth_opcode); +MLX5_SET (fte_match_param, spec->match_value, misc_parameters.bth_opcode, +IB_BTH_OPCODE_CNP ); + + spec->match_criteria_enable = +get_match_criteria_enable (spec->match_criteria); + +return 0 ; +} + +int mlx5_ib_fs_add_op_fc (struct mlx5_ib_dev *dev,u32 port_num, +struct mlx5_ib_op_fc *opfc, +enum mlx5_ib_optional_counter_type type) +{ +enum mlx5_flow_namespace_type fn_type; +int priority, i, err, spec_num; +struct mlx5_flow_act flow_act = {}; +struct mlx5_flow_destination dst; +struct mlx5_flow_namespace *ns; +struct mlx5_ib_flow_prio *prio; +struct mlx5_flow_spec *spec; + + spec =kcalloc (MAX_OPFC_RULES ,sizeof (*spec),GFP_KERNEL ); +if (!spec) +return -ENOMEM ; + +switch (type) { +case MLX5_IB_OPCOUNTER_CC_RX_CE_PKTS : +if (set_ecn_ce_spec (dev, port_num, &spec[0 ], +MLX5_FS_IPV4_VERSION ) || +set_ecn_ce_spec (dev, port_num, &spec[1 ], +MLX5_FS_IPV6_VERSION )) { + err = -EOPNOTSUPP ; + goto free; + } + spec_num =2 ; + fn_type =MLX5_FLOW_NAMESPACE_RDMA_RX_COUNTERS ; + priority =RDMA_RX_ECN_OPCOUNTER_PRIO ; +break ; + +case MLX5_IB_OPCOUNTER_CC_RX_CNP_PKTS : +if (!MLX5_CAP_FLOWTABLE (dev->mdev, + ft_field_support_2_nic_receive_rdma.bth_opcode) || +set_cnp_spec (dev, port_num, &spec[0 ])) { + err = -EOPNOTSUPP ; + goto free; + } + spec_num =1 ; + fn_type =MLX5_FLOW_NAMESPACE_RDMA_RX_COUNTERS ; + priority =RDMA_RX_CNP_OPCOUNTER_PRIO ; +break ; + +case MLX5_IB_OPCOUNTER_CC_TX_CNP_PKTS : +if (!MLX5_CAP_FLOWTABLE (dev->mdev, + ft_field_support_2_nic_transmit_rdma.bth_opcode) || +set_cnp_spec (dev, port_num, &spec[0 ])) { + err = -EOPNOTSUPP ; + goto free; + } + spec_num =1 ; + fn_type =MLX5_FLOW_NAMESPACE_RDMA_TX_COUNTERS ; + priority =RDMA_TX_CNP_OPCOUNTER_PRIO ; +break ; + +default : + err = -EOPNOTSUPP ; + goto free; + } + + ns =mlx5_get_flow_namespace (dev->mdev, fn_type); +if (!ns) { + err = -EOPNOTSUPP ; + goto free; + } + + prio = &dev->flow_db->opfcs[type]; +if (!prio->flow_table) { + prio =_get_prio (ns, prio, priority, + dev->num_ports *MAX_OPFC_RULES ,1 ,0 ); +if (IS_ERR (prio)) { + err =PTR_ERR (prio); + goto free; + } + } + + dst.type =MLX5_FLOW_DESTINATION_TYPE_COUNTER ; + dst.counter_id =mlx5_fc_id (opfc->fc); + + flow_act.action = +MLX5_FLOW_CONTEXT_ACTION_COUNT |MLX5_FLOW_CONTEXT_ACTION_ALLOW ; + +for (i =0 ; i < spec_num; i++) { + opfc->rule[i] =mlx5_add_flow_rules (prio->flow_table, &spec[i], + &flow_act, &dst,1 ); +if (IS_ERR (opfc->rule[i])) { + err =PTR_ERR (opfc->rule[i]); + goto del_rules; + } + } + prio->refcount += spec_num; +kfree (spec); + +return 0 ; + +del_rules: +for (i -=1 ; i >=0 ; i--) +mlx5_del_flow_rules (opfc->rule[i]); +put_flow_table (dev, prio, false); +free: +kfree (spec); +return err; +} + +void mlx5_ib_fs_remove_op_fc (struct mlx5_ib_dev *dev, +struct mlx5_ib_op_fc *opfc, +enum mlx5_ib_optional_counter_type type) +{ +int i; + +for (i =0 ; i <MAX_OPFC_RULES && opfc->rule[i]; i++) { +mlx5_del_flow_rules (opfc->rule[i]); +put_flow_table (dev, &dev->flow_db->opfcs[type], true); + } +} +static void set_underlay_qp (struct mlx5_ib_dev *dev,struct mlx5_flow_spec *spec,u32 underlay_qpn)
drivers/infiniband/hw/mlx5/mlx5_ib.h +24 -0
@@ -263,6 +263,14 @@ struct mlx5_ib_pp {struct mlx5_core_dev *mdev; }; +enum mlx5_ib_optional_counter_type { +MLX5_IB_OPCOUNTER_CC_RX_CE_PKTS , +MLX5_IB_OPCOUNTER_CC_RX_CNP_PKTS , +MLX5_IB_OPCOUNTER_CC_TX_CNP_PKTS , + +MLX5_IB_OPCOUNTER_MAX , +}; +struct mlx5_ib_flow_db {struct mlx5_ib_flow_prio prios[MLX5_IB_NUM_FLOW_FT ];struct mlx5_ib_flow_prio egress_prios[MLX5_IB_NUM_FLOW_FT ];
@@ -271,6 +279,7 @@ struct mlx5_ib_flow_db {struct mlx5_ib_flow_prio fdb;struct mlx5_ib_flow_prio rdma_rx[MLX5_IB_NUM_FLOW_FT ];struct mlx5_ib_flow_prio rdma_tx[MLX5_IB_NUM_FLOW_FT ]; +struct mlx5_ib_flow_prio opfcs[MLX5_IB_OPCOUNTER_MAX ];struct mlx5_flow_table *lag_demux_ft;/* Protect flow steering bypass flow tables * when add/del flow rules.
@@ -797,6 +806,13 @@ struct mlx5_ib_resources {struct mlx5_ib_port_resources ports[2 ]; }; +#define MAX_OPFC_RULES 2 + +struct mlx5_ib_op_fc { +struct mlx5_fc *fc; +struct mlx5_flow_handle *rule[MAX_OPFC_RULES ]; +}; +struct mlx5_ib_counters {struct rdma_stat_desc *descs;size_t *offsets;
@@ -807,6 +823,14 @@ struct mlx5_ib_counters {u16 set_id; }; +int mlx5_ib_fs_add_op_fc (struct mlx5_ib_dev *dev,u32 port_num, +struct mlx5_ib_op_fc *opfc, +enum mlx5_ib_optional_counter_type type); + +void mlx5_ib_fs_remove_op_fc (struct mlx5_ib_dev *dev, +struct mlx5_ib_op_fc *opfc, +enum mlx5_ib_optional_counter_type type); +struct mlx5_ib_multiport_info ;struct mlx5_ib_multiport {
include/rdma/ib_hdrs.h +1 -0
@@ -232,6 +232,7 @@ static inline u32 ib_get_sqpn(struct ib_other_headers *ohdr)#define IB_BTH_SE_SHIFT 23#define IB_BTH_TVER_MASK 0xf#define IB_BTH_TVER_SHIFT 16 +#define IB_BTH_OPCODE_CNP 0x81static inline u8 ib_bth_get_pad (struct ib_other_headers *ohdr) {
Signature · 1 line
2.31.1
PATCH 10/11 RDMA/mlx5: Add modify_op_stat() support
In reply to Leon RomanovskyFrom: Aharon Landau <[email protected]>
Add support for ib callback modify_op_stat() to add or remove an optional counter. When adding, a steering flow table is created with a rule that catches and counts all the matching packets; When removing, the table and flow counter are destroyed.
--- drivers/infiniband/hw/mlx5/counters.c | 79 +++++++++++++++++++++++++-- drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 + include/rdma/ib_verbs.h | 2 + 3 files changed, 76 insertions(+), 6 deletions(-)
drivers/infiniband/hw/mlx5/counters.c +73 -6
@@ -12,6 +12,7 @@struct mlx5_ib_counter {const char *name;size_t offset; +u32 type; };#define INIT_Q_COUNTER (_name) \
@@ -75,19 +76,19 @@ static const struct mlx5_ib_counter ext_ppcnt_cnts[] = { INIT_EXT_PPCNT_COUNTER(rx_icrc_encapsulated), }; -#define INIT_OP_COUNTER (_name) \ - { .name = #_name } +#define INIT_OP_COUNTER (_name, _type) \ + { .name = #_name, .type = MLX5_IB_OPCOUNTER_##_type}static const struct mlx5_ib_counter basic_op_cnts[] = { -INIT_OP_COUNTER (cc_rx_ce_pkts), +INIT_OP_COUNTER (cc_rx_ce_pkts,CC_RX_CE_PKTS ), };static const struct mlx5_ib_counter rdmarx_cnp_op_cnts[] = { -INIT_OP_COUNTER (cc_rx_cnp_pkts), +INIT_OP_COUNTER (cc_rx_cnp_pkts,CC_RX_CNP_PKTS ), };static const struct mlx5_ib_counter rdmatx_cnp_op_cnts[] = { -INIT_OP_COUNTER (cc_tx_cnp_pkts), +INIT_OP_COUNTER (cc_tx_cnp_pkts,CC_TX_CNP_PKTS ), }; static int mlx5_ib_read_counters(struct ib_counters *counters,
@@ -453,6 +454,7 @@ static void mlx5_ib_fill_counters(struct mlx5_ib_dev *dev,for (i =0 ; i <ARRAY_SIZE (basic_op_cnts); i++, j++) { descs[j].name = basic_op_cnts[i].name; descs[j].flags |=IB_STAT_FLAG_OPTIONAL ; + descs[j].priv = &basic_op_cnts[i].type; } if (MLX5_CAP_FLOWTABLE(dev->mdev,
@@ -460,6 +462,7 @@ static void mlx5_ib_fill_counters(struct mlx5_ib_dev *dev,for (i =0 ; i <ARRAY_SIZE (rdmarx_cnp_op_cnts); i++, j++) { descs[j].name = rdmarx_cnp_op_cnts[i].name; descs[j].flags |=IB_STAT_FLAG_OPTIONAL ; + descs[j].priv = &rdmarx_cnp_op_cnts[i].type; } }
@@ -468,6 +471,7 @@ static void mlx5_ib_fill_counters(struct mlx5_ib_dev *dev,for (i =0 ; i <ARRAY_SIZE (rdmatx_cnp_op_cnts); i++, j++) { descs[j].name = rdmatx_cnp_op_cnts[i].name; descs[j].flags |=IB_STAT_FLAG_OPTIONAL ; + descs[j].priv = &rdmatx_cnp_op_cnts[i].type; } } }
@@ -537,7 +541,7 @@ static void mlx5_ib_dealloc_counters(struct mlx5_ib_dev *dev) {u32 in[MLX5_ST_SZ_DW (dealloc_q_counter_in)] = {};int num_cnt_ports; -int i; +int i, j; num_cnt_ports =is_mdev_switchdev_mode (dev->mdev) ?1 : dev->num_ports;
@@ -552,6 +556,18 @@ static void mlx5_ib_dealloc_counters(struct mlx5_ib_dev *dev) }kfree (dev->port[i].cnts.descs);kfree (dev->port[i].cnts.offsets); + +for (j =0 ; j <MLX5_IB_OPCOUNTER_MAX ; j++) { +if (!dev->port[i].cnts.opfcs[j].fc) +continue ; + +mlx5_ib_fs_remove_op_fc (dev, + &dev->port[i].cnts.opfcs[j], + j); +mlx5_fc_destroy (dev->mdev, + dev->port[i].cnts.opfcs[j].fc); + dev->port[i].cnts.opfcs[j].fc =NULL ; + } } }
@@ -731,6 +747,56 @@ void mlx5_ib_counters_clear_description(struct ib_counters *counters)mutex_unlock (&mcounters->mcntrs_mutex); } +static int mlx5_ib_modify_stat (struct ib_device *device,u32 port, +int index,bool enable) +{ +struct mlx5_ib_dev *dev =to_mdev (device); +struct mlx5_ib_counters *cnts; +struct mlx5_ib_op_fc *opfc; +u32 num_hw_counters, type; +int ret =0 ; + + cnts = &dev->port[port -1 ].cnts; + num_hw_counters = cnts->num_q_counters + cnts->num_cong_counters + + cnts->num_ext_ppcnt_counters; +if ((index < num_hw_counters) || + (index >= num_hw_counters + cnts->num_op_counters)) +return -EINVAL ; + +if (!(cnts->descs[index].flags &IB_STAT_FLAG_OPTIONAL )) +return -EINVAL ; + + type = *(u32 *)cnts->descs[index].priv; +if (type >=MLX5_IB_OPCOUNTER_MAX ) +return -EINVAL ; + + opfc = &cnts->opfcs[type]; + +if (enable) { +if (opfc->fc) +return -EEXIST ; + + opfc->fc =mlx5_fc_create (dev->mdev, false); +if (IS_ERR (opfc->fc)) +return PTR_ERR (opfc->fc); + + ret =mlx5_ib_fs_add_op_fc (dev, port, opfc, type); +if (ret) { +mlx5_fc_destroy (dev->mdev, opfc->fc); + opfc->fc =NULL ; + } + }else { +if (!opfc->fc) +return -EINVAL ; + +mlx5_ib_fs_remove_op_fc (dev, opfc, type); +mlx5_fc_destroy (dev->mdev, opfc->fc); + opfc->fc =NULL ; + } + +return ret; +} +static const struct ib_device_ops hw_stats_ops = { .alloc_hw_port_stats = mlx5_ib_alloc_hw_port_stats, .get_hw_stats = mlx5_ib_get_hw_stats,
@@ -739,6 +805,7 @@ static const struct ib_device_ops hw_stats_ops = { .counter_dealloc = mlx5_ib_counter_dealloc, .counter_alloc_stats = mlx5_ib_counter_alloc_stats, .counter_update_stats = mlx5_ib_counter_update_stats, + .modify_hw_stat = mlx5_ib_modify_stat, };static const struct ib_device_ops hw_switchdev_stats_ops = {
drivers/infiniband/hw/mlx5/mlx5_ib.h +1 -0
@@ -821,6 +821,7 @@ struct mlx5_ib_counters {u32 num_ext_ppcnt_counters;u32 num_op_counters;u16 set_id; +struct mlx5_ib_op_fc opfcs[MLX5_IB_OPCOUNTER_MAX ]; }; int mlx5_ib_fs_add_op_fc(struct mlx5_ib_dev *dev, u32 port_num,
include/rdma/ib_verbs.h +2 -0
@@ -553,10 +553,12 @@ enum ib_stat_flag {* struct rdma_stat_desc * @name - The name of the counter * @flags - Flags of the counter; For example, IB_STAT_FLAG_OPTIONAL +* @priv - Driver private information; Core code should not use */ struct rdma_stat_desc {const char *name;unsigned int flags; +const void *priv; };/**
Signature · 1 line
2.31.1
PATCH 11/11 RDMA/mlx5: Add optional counter support in get_hw_stats callback
In reply to Leon RomanovskyFrom: Aharon Landau <[email protected]>
When get_hw_stats is called, query and return the optional counter statistic as well.
--- drivers/infiniband/hw/mlx5/counters.c | 88 ++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 3 deletions(-)
drivers/infiniband/hw/mlx5/counters.c +85 -3
@@ -270,9 +270,9 @@ static int mlx5_ib_query_ext_ppcnt_counters(struct mlx5_ib_dev *dev,return ret; } -static int mlx5_ib_get_hw_stats (struct ib_device *ibdev, -struct rdma_hw_stats *stats, -u32 port_num,int index) +static int do_get_hw_stats (struct ib_device *ibdev, +struct rdma_hw_stats *stats, +u32 port_num,int index) {struct mlx5_ib_dev *dev =to_mdev (ibdev);const struct mlx5_ib_counters *cnts =get_counters (dev, port_num -1 );
@@ -324,6 +324,88 @@ static int mlx5_ib_get_hw_stats(struct ib_device *ibdev,return num_counters; } +static int do_get_op_stat (struct ib_device *ibdev, +struct rdma_hw_stats *stats, +u32 port_num,int index) +{ +struct mlx5_ib_dev *dev =to_mdev (ibdev); +const struct mlx5_ib_counters *cnts; +const struct mlx5_ib_op_fc *opfcs; +u64 packets =0 , bytes; +u32 type; +int ret; + + cnts =get_counters (dev, port_num -1 ); + opfcs = cnts->opfcs; + type = *(u32 *)cnts->descs[index].priv; +if (type >=MLX5_IB_OPCOUNTER_MAX ) +return -EINVAL ; + +if (!opfcs[type].fc) + goto out; + + ret =mlx5_fc_query (dev->mdev, opfcs[type].fc, + &packets, &bytes); +if (ret) +return ret; + +out: + stats->value[index] = packets; +return index; +} + +static int do_get_op_stats (struct ib_device *ibdev, +struct rdma_hw_stats *stats, +u32 port_num) +{ +struct mlx5_ib_dev *dev =to_mdev (ibdev); +const struct mlx5_ib_counters *cnts; +int index, ret, num_hw_counters; + + cnts =get_counters (dev, port_num -1 ); + num_hw_counters = cnts->num_q_counters + cnts->num_cong_counters + + cnts->num_ext_ppcnt_counters; +for (index = num_hw_counters; + index < num_hw_counters + cnts->num_op_counters; index++) { + ret =do_get_op_stat (ibdev, stats, port_num, index); +if (ret != index) +return ret; + } + +return cnts->num_op_counters; +} + +static int mlx5_ib_get_hw_stats (struct ib_device *ibdev, +struct rdma_hw_stats *stats, +u32 port_num,int index) +{ +int num_counters, num_hw_counters, num_op_counters; +struct mlx5_ib_dev *dev =to_mdev (ibdev); +const struct mlx5_ib_counters *cnts; + + cnts =get_counters (dev, port_num -1 ); + num_hw_counters = cnts->num_q_counters + cnts->num_cong_counters + + cnts->num_ext_ppcnt_counters; + num_counters = num_hw_counters + cnts->num_op_counters; + +if ((index <0 ) || (index > num_counters)) +return -EINVAL ; +else if (index < num_hw_counters) +return do_get_hw_stats (ibdev, stats, port_num, index); +else if (index < num_counters) +return do_get_op_stat (ibdev, stats, port_num, index); + + num_hw_counters =do_get_hw_stats (ibdev, stats, port_num, index); +if (num_hw_counters <0 ) +return num_hw_counters; + + num_op_counters =do_get_op_stats (ibdev, stats, port_num); +if (num_op_counters <0 ) +return num_op_counters; + +return num_hw_counters + num_op_counters; +} +static struct rdma_hw_stats *mlx5_ib_counter_alloc_stats (struct rdma_counter *counter) {
Signature · 1 line
2.31.1