Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

RDMA/mlx5: Separate counters from main.c

There are number of counters types supported in mlx5_ib: HW counters,
congestion counters, Q-counters and flow counters. Almost all supporting
code was placed in main.c that made almost impossible to maintain the code
anymore. Let's create separate code namespace for the counters to easy
future generalization effort.

Link: https://lore.kernel.org/r/20200702081809.423482-4-leon@kernel.org
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>

authored by

Leon Romanovsky and committed by
Jason Gunthorpe
64825827 b572ebe6

+737 -709
+1
drivers/infiniband/hw/mlx5/Makefile
··· 4 4 mlx5_ib-y := ah.o \ 5 5 cmd.o \ 6 6 cong.o \ 7 + counters.o \ 7 8 cq.o \ 8 9 doorbell.o \ 9 10 gsi.o \
-12
drivers/infiniband/hw/mlx5/cmd.c
··· 148 148 spin_unlock(&dm->lock); 149 149 } 150 150 151 - int mlx5_cmd_query_ext_ppcnt_counters(struct mlx5_core_dev *dev, void *out) 152 - { 153 - u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {}; 154 - int sz = MLX5_ST_SZ_BYTES(ppcnt_reg); 155 - 156 - MLX5_SET(ppcnt_reg, in, local_port, 1); 157 - 158 - MLX5_SET(ppcnt_reg, in, grp, MLX5_ETHERNET_EXTENDED_COUNTERS_GROUP); 159 - return mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPCNT, 160 - 0, 0); 161 - } 162 - 163 151 void mlx5_cmd_destroy_tir(struct mlx5_core_dev *dev, u32 tirn, u16 uid) 164 152 { 165 153 u32 in[MLX5_ST_SZ_DW(destroy_tir_in)] = {};
-1
drivers/infiniband/hw/mlx5/cmd.h
··· 41 41 int mlx5_cmd_null_mkey(struct mlx5_core_dev *dev, u32 *null_mkey); 42 42 int mlx5_cmd_query_cong_params(struct mlx5_core_dev *dev, int cong_point, 43 43 void *out); 44 - int mlx5_cmd_query_ext_ppcnt_counters(struct mlx5_core_dev *dev, void *out); 45 44 int mlx5_cmd_alloc_memic(struct mlx5_dm *dm, phys_addr_t *addr, 46 45 u64 length, u32 alignment); 47 46 void mlx5_cmd_dealloc_memic(struct mlx5_dm *dm, phys_addr_t addr, u64 length);
+709
drivers/infiniband/hw/mlx5/counters.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 + /* 3 + * Copyright (c) 2013-2020, Mellanox Technologies inc. All rights reserved. 4 + */ 5 + 6 + #include "mlx5_ib.h" 7 + #include <linux/mlx5/eswitch.h> 8 + #include "counters.h" 9 + #include "ib_rep.h" 10 + #include "qp.h" 11 + 12 + struct mlx5_ib_counter { 13 + const char *name; 14 + size_t offset; 15 + }; 16 + 17 + #define INIT_Q_COUNTER(_name) \ 18 + { .name = #_name, .offset = MLX5_BYTE_OFF(query_q_counter_out, _name)} 19 + 20 + static const struct mlx5_ib_counter basic_q_cnts[] = { 21 + INIT_Q_COUNTER(rx_write_requests), 22 + INIT_Q_COUNTER(rx_read_requests), 23 + INIT_Q_COUNTER(rx_atomic_requests), 24 + INIT_Q_COUNTER(out_of_buffer), 25 + }; 26 + 27 + static const struct mlx5_ib_counter out_of_seq_q_cnts[] = { 28 + INIT_Q_COUNTER(out_of_sequence), 29 + }; 30 + 31 + static const struct mlx5_ib_counter retrans_q_cnts[] = { 32 + INIT_Q_COUNTER(duplicate_request), 33 + INIT_Q_COUNTER(rnr_nak_retry_err), 34 + INIT_Q_COUNTER(packet_seq_err), 35 + INIT_Q_COUNTER(implied_nak_seq_err), 36 + INIT_Q_COUNTER(local_ack_timeout_err), 37 + }; 38 + 39 + #define INIT_CONG_COUNTER(_name) \ 40 + { .name = #_name, .offset = \ 41 + MLX5_BYTE_OFF(query_cong_statistics_out, _name ## _high)} 42 + 43 + static const struct mlx5_ib_counter cong_cnts[] = { 44 + INIT_CONG_COUNTER(rp_cnp_ignored), 45 + INIT_CONG_COUNTER(rp_cnp_handled), 46 + INIT_CONG_COUNTER(np_ecn_marked_roce_packets), 47 + INIT_CONG_COUNTER(np_cnp_sent), 48 + }; 49 + 50 + static const struct mlx5_ib_counter extended_err_cnts[] = { 51 + INIT_Q_COUNTER(resp_local_length_error), 52 + INIT_Q_COUNTER(resp_cqe_error), 53 + INIT_Q_COUNTER(req_cqe_error), 54 + INIT_Q_COUNTER(req_remote_invalid_request), 55 + INIT_Q_COUNTER(req_remote_access_errors), 56 + INIT_Q_COUNTER(resp_remote_access_errors), 57 + INIT_Q_COUNTER(resp_cqe_flush_error), 58 + INIT_Q_COUNTER(req_cqe_flush_error), 59 + }; 60 + 61 + static const struct mlx5_ib_counter roce_accl_cnts[] = { 62 + INIT_Q_COUNTER(roce_adp_retrans), 63 + INIT_Q_COUNTER(roce_adp_retrans_to), 64 + INIT_Q_COUNTER(roce_slow_restart), 65 + INIT_Q_COUNTER(roce_slow_restart_cnps), 66 + INIT_Q_COUNTER(roce_slow_restart_trans), 67 + }; 68 + 69 + #define INIT_EXT_PPCNT_COUNTER(_name) \ 70 + { .name = #_name, .offset = \ 71 + MLX5_BYTE_OFF(ppcnt_reg, \ 72 + counter_set.eth_extended_cntrs_grp_data_layout._name##_high)} 73 + 74 + static const struct mlx5_ib_counter ext_ppcnt_cnts[] = { 75 + INIT_EXT_PPCNT_COUNTER(rx_icrc_encapsulated), 76 + }; 77 + 78 + static int mlx5_ib_read_counters(struct ib_counters *counters, 79 + struct ib_counters_read_attr *read_attr, 80 + struct uverbs_attr_bundle *attrs) 81 + { 82 + struct mlx5_ib_mcounters *mcounters = to_mcounters(counters); 83 + struct mlx5_read_counters_attr mread_attr = {}; 84 + struct mlx5_ib_flow_counters_desc *desc; 85 + int ret, i; 86 + 87 + mutex_lock(&mcounters->mcntrs_mutex); 88 + if (mcounters->cntrs_max_index > read_attr->ncounters) { 89 + ret = -EINVAL; 90 + goto err_bound; 91 + } 92 + 93 + mread_attr.out = kcalloc(mcounters->counters_num, sizeof(u64), 94 + GFP_KERNEL); 95 + if (!mread_attr.out) { 96 + ret = -ENOMEM; 97 + goto err_bound; 98 + } 99 + 100 + mread_attr.hw_cntrs_hndl = mcounters->hw_cntrs_hndl; 101 + mread_attr.flags = read_attr->flags; 102 + ret = mcounters->read_counters(counters->device, &mread_attr); 103 + if (ret) 104 + goto err_read; 105 + 106 + /* do the pass over the counters data array to assign according to the 107 + * descriptions and indexing pairs 108 + */ 109 + desc = mcounters->counters_data; 110 + for (i = 0; i < mcounters->ncounters; i++) 111 + read_attr->counters_buff[desc[i].index] += mread_attr.out[desc[i].description]; 112 + 113 + err_read: 114 + kfree(mread_attr.out); 115 + err_bound: 116 + mutex_unlock(&mcounters->mcntrs_mutex); 117 + return ret; 118 + } 119 + 120 + static void mlx5_ib_destroy_counters(struct ib_counters *counters) 121 + { 122 + struct mlx5_ib_mcounters *mcounters = to_mcounters(counters); 123 + 124 + mlx5_ib_counters_clear_description(counters); 125 + if (mcounters->hw_cntrs_hndl) 126 + mlx5_fc_destroy(to_mdev(counters->device)->mdev, 127 + mcounters->hw_cntrs_hndl); 128 + } 129 + 130 + static int mlx5_ib_create_counters(struct ib_counters *counters, 131 + struct uverbs_attr_bundle *attrs) 132 + { 133 + struct mlx5_ib_mcounters *mcounters = to_mcounters(counters); 134 + 135 + mutex_init(&mcounters->mcntrs_mutex); 136 + return 0; 137 + } 138 + 139 + 140 + static bool is_mdev_switchdev_mode(const struct mlx5_core_dev *mdev) 141 + { 142 + return MLX5_ESWITCH_MANAGER(mdev) && 143 + mlx5_ib_eswitch_mode(mdev->priv.eswitch) == 144 + MLX5_ESWITCH_OFFLOADS; 145 + } 146 + 147 + static const struct mlx5_ib_counters *get_counters(struct mlx5_ib_dev *dev, 148 + u8 port_num) 149 + { 150 + return is_mdev_switchdev_mode(dev->mdev) ? &dev->port[0].cnts : 151 + &dev->port[port_num].cnts; 152 + } 153 + 154 + /** 155 + * mlx5_ib_get_counters_id - Returns counters id to use for device+port 156 + * @dev: Pointer to mlx5 IB device 157 + * @port_num: Zero based port number 158 + * 159 + * mlx5_ib_get_counters_id() Returns counters set id to use for given 160 + * device port combination in switchdev and non switchdev mode of the 161 + * parent device. 162 + */ 163 + u16 mlx5_ib_get_counters_id(struct mlx5_ib_dev *dev, u8 port_num) 164 + { 165 + const struct mlx5_ib_counters *cnts = get_counters(dev, port_num); 166 + 167 + return cnts->set_id; 168 + } 169 + 170 + static struct rdma_hw_stats *mlx5_ib_alloc_hw_stats(struct ib_device *ibdev, 171 + u8 port_num) 172 + { 173 + struct mlx5_ib_dev *dev = to_mdev(ibdev); 174 + const struct mlx5_ib_counters *cnts; 175 + bool is_switchdev = is_mdev_switchdev_mode(dev->mdev); 176 + 177 + if ((is_switchdev && port_num) || (!is_switchdev && !port_num)) 178 + return NULL; 179 + 180 + cnts = get_counters(dev, port_num - 1); 181 + 182 + return rdma_alloc_hw_stats_struct(cnts->names, 183 + cnts->num_q_counters + 184 + cnts->num_cong_counters + 185 + cnts->num_ext_ppcnt_counters, 186 + RDMA_HW_STATS_DEFAULT_LIFESPAN); 187 + } 188 + 189 + static int mlx5_ib_query_q_counters(struct mlx5_core_dev *mdev, 190 + const struct mlx5_ib_counters *cnts, 191 + struct rdma_hw_stats *stats, 192 + u16 set_id) 193 + { 194 + u32 out[MLX5_ST_SZ_DW(query_q_counter_out)] = {}; 195 + u32 in[MLX5_ST_SZ_DW(query_q_counter_in)] = {}; 196 + __be32 val; 197 + int ret, i; 198 + 199 + MLX5_SET(query_q_counter_in, in, opcode, MLX5_CMD_OP_QUERY_Q_COUNTER); 200 + MLX5_SET(query_q_counter_in, in, counter_set_id, set_id); 201 + ret = mlx5_cmd_exec_inout(mdev, query_q_counter, in, out); 202 + if (ret) 203 + return ret; 204 + 205 + for (i = 0; i < cnts->num_q_counters; i++) { 206 + val = *(__be32 *)((void *)out + cnts->offsets[i]); 207 + stats->value[i] = (u64)be32_to_cpu(val); 208 + } 209 + 210 + return 0; 211 + } 212 + 213 + static int mlx5_ib_query_ext_ppcnt_counters(struct mlx5_ib_dev *dev, 214 + const struct mlx5_ib_counters *cnts, 215 + struct rdma_hw_stats *stats) 216 + { 217 + int offset = cnts->num_q_counters + cnts->num_cong_counters; 218 + u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {}; 219 + int sz = MLX5_ST_SZ_BYTES(ppcnt_reg); 220 + int ret, i; 221 + void *out; 222 + 223 + out = kvzalloc(sz, GFP_KERNEL); 224 + if (!out) 225 + return -ENOMEM; 226 + 227 + MLX5_SET(ppcnt_reg, in, local_port, 1); 228 + MLX5_SET(ppcnt_reg, in, grp, MLX5_ETHERNET_EXTENDED_COUNTERS_GROUP); 229 + ret = mlx5_core_access_reg(dev->mdev, in, sz, out, sz, MLX5_REG_PPCNT, 230 + 0, 0); 231 + if (ret) 232 + goto free; 233 + 234 + for (i = 0; i < cnts->num_ext_ppcnt_counters; i++) 235 + stats->value[i + offset] = 236 + be64_to_cpup((__be64 *)(out + 237 + cnts->offsets[i + offset])); 238 + free: 239 + kvfree(out); 240 + return ret; 241 + } 242 + 243 + static int mlx5_ib_get_hw_stats(struct ib_device *ibdev, 244 + struct rdma_hw_stats *stats, 245 + u8 port_num, int index) 246 + { 247 + struct mlx5_ib_dev *dev = to_mdev(ibdev); 248 + const struct mlx5_ib_counters *cnts = get_counters(dev, port_num - 1); 249 + struct mlx5_core_dev *mdev; 250 + int ret, num_counters; 251 + u8 mdev_port_num; 252 + 253 + if (!stats) 254 + return -EINVAL; 255 + 256 + num_counters = cnts->num_q_counters + 257 + cnts->num_cong_counters + 258 + cnts->num_ext_ppcnt_counters; 259 + 260 + /* q_counters are per IB device, query the master mdev */ 261 + ret = mlx5_ib_query_q_counters(dev->mdev, cnts, stats, cnts->set_id); 262 + if (ret) 263 + return ret; 264 + 265 + if (MLX5_CAP_PCAM_FEATURE(dev->mdev, rx_icrc_encapsulated_counter)) { 266 + ret = mlx5_ib_query_ext_ppcnt_counters(dev, cnts, stats); 267 + if (ret) 268 + return ret; 269 + } 270 + 271 + if (MLX5_CAP_GEN(dev->mdev, cc_query_allowed)) { 272 + mdev = mlx5_ib_get_native_port_mdev(dev, port_num, 273 + &mdev_port_num); 274 + if (!mdev) { 275 + /* If port is not affiliated yet, its in down state 276 + * which doesn't have any counters yet, so it would be 277 + * zero. So no need to read from the HCA. 278 + */ 279 + goto done; 280 + } 281 + ret = mlx5_lag_query_cong_counters(dev->mdev, 282 + stats->value + 283 + cnts->num_q_counters, 284 + cnts->num_cong_counters, 285 + cnts->offsets + 286 + cnts->num_q_counters); 287 + 288 + mlx5_ib_put_native_port_mdev(dev, port_num); 289 + if (ret) 290 + return ret; 291 + } 292 + 293 + done: 294 + return num_counters; 295 + } 296 + 297 + static struct rdma_hw_stats * 298 + mlx5_ib_counter_alloc_stats(struct rdma_counter *counter) 299 + { 300 + struct mlx5_ib_dev *dev = to_mdev(counter->device); 301 + const struct mlx5_ib_counters *cnts = 302 + get_counters(dev, counter->port - 1); 303 + 304 + return rdma_alloc_hw_stats_struct(cnts->names, 305 + cnts->num_q_counters + 306 + cnts->num_cong_counters + 307 + cnts->num_ext_ppcnt_counters, 308 + RDMA_HW_STATS_DEFAULT_LIFESPAN); 309 + } 310 + 311 + static int mlx5_ib_counter_update_stats(struct rdma_counter *counter) 312 + { 313 + struct mlx5_ib_dev *dev = to_mdev(counter->device); 314 + const struct mlx5_ib_counters *cnts = 315 + get_counters(dev, counter->port - 1); 316 + 317 + return mlx5_ib_query_q_counters(dev->mdev, cnts, 318 + counter->stats, counter->id); 319 + } 320 + 321 + static int mlx5_ib_counter_dealloc(struct rdma_counter *counter) 322 + { 323 + struct mlx5_ib_dev *dev = to_mdev(counter->device); 324 + u32 in[MLX5_ST_SZ_DW(dealloc_q_counter_in)] = {}; 325 + 326 + if (!counter->id) 327 + return 0; 328 + 329 + MLX5_SET(dealloc_q_counter_in, in, opcode, 330 + MLX5_CMD_OP_DEALLOC_Q_COUNTER); 331 + MLX5_SET(dealloc_q_counter_in, in, counter_set_id, counter->id); 332 + return mlx5_cmd_exec_in(dev->mdev, dealloc_q_counter, in); 333 + } 334 + 335 + static int mlx5_ib_counter_bind_qp(struct rdma_counter *counter, 336 + struct ib_qp *qp) 337 + { 338 + struct mlx5_ib_dev *dev = to_mdev(qp->device); 339 + int err; 340 + 341 + if (!counter->id) { 342 + u32 out[MLX5_ST_SZ_DW(alloc_q_counter_out)] = {}; 343 + u32 in[MLX5_ST_SZ_DW(alloc_q_counter_in)] = {}; 344 + 345 + MLX5_SET(alloc_q_counter_in, in, opcode, 346 + MLX5_CMD_OP_ALLOC_Q_COUNTER); 347 + MLX5_SET(alloc_q_counter_in, in, uid, MLX5_SHARED_RESOURCE_UID); 348 + err = mlx5_cmd_exec_inout(dev->mdev, alloc_q_counter, in, out); 349 + if (err) 350 + return err; 351 + counter->id = 352 + MLX5_GET(alloc_q_counter_out, out, counter_set_id); 353 + } 354 + 355 + err = mlx5_ib_qp_set_counter(qp, counter); 356 + if (err) 357 + goto fail_set_counter; 358 + 359 + return 0; 360 + 361 + fail_set_counter: 362 + mlx5_ib_counter_dealloc(counter); 363 + counter->id = 0; 364 + 365 + return err; 366 + } 367 + 368 + static int mlx5_ib_counter_unbind_qp(struct ib_qp *qp) 369 + { 370 + return mlx5_ib_qp_set_counter(qp, NULL); 371 + } 372 + 373 + 374 + static void mlx5_ib_fill_counters(struct mlx5_ib_dev *dev, 375 + const char **names, 376 + size_t *offsets) 377 + { 378 + int i; 379 + int j = 0; 380 + 381 + for (i = 0; i < ARRAY_SIZE(basic_q_cnts); i++, j++) { 382 + names[j] = basic_q_cnts[i].name; 383 + offsets[j] = basic_q_cnts[i].offset; 384 + } 385 + 386 + if (MLX5_CAP_GEN(dev->mdev, out_of_seq_cnt)) { 387 + for (i = 0; i < ARRAY_SIZE(out_of_seq_q_cnts); i++, j++) { 388 + names[j] = out_of_seq_q_cnts[i].name; 389 + offsets[j] = out_of_seq_q_cnts[i].offset; 390 + } 391 + } 392 + 393 + if (MLX5_CAP_GEN(dev->mdev, retransmission_q_counters)) { 394 + for (i = 0; i < ARRAY_SIZE(retrans_q_cnts); i++, j++) { 395 + names[j] = retrans_q_cnts[i].name; 396 + offsets[j] = retrans_q_cnts[i].offset; 397 + } 398 + } 399 + 400 + if (MLX5_CAP_GEN(dev->mdev, enhanced_error_q_counters)) { 401 + for (i = 0; i < ARRAY_SIZE(extended_err_cnts); i++, j++) { 402 + names[j] = extended_err_cnts[i].name; 403 + offsets[j] = extended_err_cnts[i].offset; 404 + } 405 + } 406 + 407 + if (MLX5_CAP_GEN(dev->mdev, roce_accl)) { 408 + for (i = 0; i < ARRAY_SIZE(roce_accl_cnts); i++, j++) { 409 + names[j] = roce_accl_cnts[i].name; 410 + offsets[j] = roce_accl_cnts[i].offset; 411 + } 412 + } 413 + 414 + if (MLX5_CAP_GEN(dev->mdev, cc_query_allowed)) { 415 + for (i = 0; i < ARRAY_SIZE(cong_cnts); i++, j++) { 416 + names[j] = cong_cnts[i].name; 417 + offsets[j] = cong_cnts[i].offset; 418 + } 419 + } 420 + 421 + if (MLX5_CAP_PCAM_FEATURE(dev->mdev, rx_icrc_encapsulated_counter)) { 422 + for (i = 0; i < ARRAY_SIZE(ext_ppcnt_cnts); i++, j++) { 423 + names[j] = ext_ppcnt_cnts[i].name; 424 + offsets[j] = ext_ppcnt_cnts[i].offset; 425 + } 426 + } 427 + } 428 + 429 + 430 + static int __mlx5_ib_alloc_counters(struct mlx5_ib_dev *dev, 431 + struct mlx5_ib_counters *cnts) 432 + { 433 + u32 num_counters; 434 + 435 + num_counters = ARRAY_SIZE(basic_q_cnts); 436 + 437 + if (MLX5_CAP_GEN(dev->mdev, out_of_seq_cnt)) 438 + num_counters += ARRAY_SIZE(out_of_seq_q_cnts); 439 + 440 + if (MLX5_CAP_GEN(dev->mdev, retransmission_q_counters)) 441 + num_counters += ARRAY_SIZE(retrans_q_cnts); 442 + 443 + if (MLX5_CAP_GEN(dev->mdev, enhanced_error_q_counters)) 444 + num_counters += ARRAY_SIZE(extended_err_cnts); 445 + 446 + if (MLX5_CAP_GEN(dev->mdev, roce_accl)) 447 + num_counters += ARRAY_SIZE(roce_accl_cnts); 448 + 449 + cnts->num_q_counters = num_counters; 450 + 451 + if (MLX5_CAP_GEN(dev->mdev, cc_query_allowed)) { 452 + cnts->num_cong_counters = ARRAY_SIZE(cong_cnts); 453 + num_counters += ARRAY_SIZE(cong_cnts); 454 + } 455 + if (MLX5_CAP_PCAM_FEATURE(dev->mdev, rx_icrc_encapsulated_counter)) { 456 + cnts->num_ext_ppcnt_counters = ARRAY_SIZE(ext_ppcnt_cnts); 457 + num_counters += ARRAY_SIZE(ext_ppcnt_cnts); 458 + } 459 + cnts->names = kcalloc(num_counters, sizeof(cnts->names), GFP_KERNEL); 460 + if (!cnts->names) 461 + return -ENOMEM; 462 + 463 + cnts->offsets = kcalloc(num_counters, 464 + sizeof(cnts->offsets), GFP_KERNEL); 465 + if (!cnts->offsets) 466 + goto err_names; 467 + 468 + return 0; 469 + 470 + err_names: 471 + kfree(cnts->names); 472 + cnts->names = NULL; 473 + return -ENOMEM; 474 + } 475 + 476 + static void mlx5_ib_dealloc_counters(struct mlx5_ib_dev *dev) 477 + { 478 + u32 in[MLX5_ST_SZ_DW(dealloc_q_counter_in)] = {}; 479 + int num_cnt_ports; 480 + int i; 481 + 482 + num_cnt_ports = is_mdev_switchdev_mode(dev->mdev) ? 1 : dev->num_ports; 483 + 484 + MLX5_SET(dealloc_q_counter_in, in, opcode, 485 + MLX5_CMD_OP_DEALLOC_Q_COUNTER); 486 + 487 + for (i = 0; i < num_cnt_ports; i++) { 488 + if (dev->port[i].cnts.set_id) { 489 + MLX5_SET(dealloc_q_counter_in, in, counter_set_id, 490 + dev->port[i].cnts.set_id); 491 + mlx5_cmd_exec_in(dev->mdev, dealloc_q_counter, in); 492 + } 493 + kfree(dev->port[i].cnts.names); 494 + kfree(dev->port[i].cnts.offsets); 495 + } 496 + } 497 + 498 + static int mlx5_ib_alloc_counters(struct mlx5_ib_dev *dev) 499 + { 500 + u32 out[MLX5_ST_SZ_DW(alloc_q_counter_out)] = {}; 501 + u32 in[MLX5_ST_SZ_DW(alloc_q_counter_in)] = {}; 502 + int num_cnt_ports; 503 + int err = 0; 504 + int i; 505 + bool is_shared; 506 + 507 + MLX5_SET(alloc_q_counter_in, in, opcode, MLX5_CMD_OP_ALLOC_Q_COUNTER); 508 + is_shared = MLX5_CAP_GEN(dev->mdev, log_max_uctx) != 0; 509 + num_cnt_ports = is_mdev_switchdev_mode(dev->mdev) ? 1 : dev->num_ports; 510 + 511 + for (i = 0; i < num_cnt_ports; i++) { 512 + err = __mlx5_ib_alloc_counters(dev, &dev->port[i].cnts); 513 + if (err) 514 + goto err_alloc; 515 + 516 + mlx5_ib_fill_counters(dev, dev->port[i].cnts.names, 517 + dev->port[i].cnts.offsets); 518 + 519 + MLX5_SET(alloc_q_counter_in, in, uid, 520 + is_shared ? MLX5_SHARED_RESOURCE_UID : 0); 521 + 522 + err = mlx5_cmd_exec_inout(dev->mdev, alloc_q_counter, in, out); 523 + if (err) { 524 + mlx5_ib_warn(dev, 525 + "couldn't allocate queue counter for port %d, err %d\n", 526 + i + 1, err); 527 + goto err_alloc; 528 + } 529 + 530 + dev->port[i].cnts.set_id = 531 + MLX5_GET(alloc_q_counter_out, out, counter_set_id); 532 + } 533 + return 0; 534 + 535 + err_alloc: 536 + mlx5_ib_dealloc_counters(dev); 537 + return err; 538 + } 539 + 540 + static int read_flow_counters(struct ib_device *ibdev, 541 + struct mlx5_read_counters_attr *read_attr) 542 + { 543 + struct mlx5_fc *fc = read_attr->hw_cntrs_hndl; 544 + struct mlx5_ib_dev *dev = to_mdev(ibdev); 545 + 546 + return mlx5_fc_query(dev->mdev, fc, 547 + &read_attr->out[IB_COUNTER_PACKETS], 548 + &read_attr->out[IB_COUNTER_BYTES]); 549 + } 550 + 551 + /* flow counters currently expose two counters packets and bytes */ 552 + #define FLOW_COUNTERS_NUM 2 553 + static int counters_set_description( 554 + struct ib_counters *counters, enum mlx5_ib_counters_type counters_type, 555 + struct mlx5_ib_flow_counters_desc *desc_data, u32 ncounters) 556 + { 557 + struct mlx5_ib_mcounters *mcounters = to_mcounters(counters); 558 + u32 cntrs_max_index = 0; 559 + int i; 560 + 561 + if (counters_type != MLX5_IB_COUNTERS_FLOW) 562 + return -EINVAL; 563 + 564 + /* init the fields for the object */ 565 + mcounters->type = counters_type; 566 + mcounters->read_counters = read_flow_counters; 567 + mcounters->counters_num = FLOW_COUNTERS_NUM; 568 + mcounters->ncounters = ncounters; 569 + /* each counter entry have both description and index pair */ 570 + for (i = 0; i < ncounters; i++) { 571 + if (desc_data[i].description > IB_COUNTER_BYTES) 572 + return -EINVAL; 573 + 574 + if (cntrs_max_index <= desc_data[i].index) 575 + cntrs_max_index = desc_data[i].index + 1; 576 + } 577 + 578 + mutex_lock(&mcounters->mcntrs_mutex); 579 + mcounters->counters_data = desc_data; 580 + mcounters->cntrs_max_index = cntrs_max_index; 581 + mutex_unlock(&mcounters->mcntrs_mutex); 582 + 583 + return 0; 584 + } 585 + 586 + #define MAX_COUNTERS_NUM (USHRT_MAX / (sizeof(u32) * 2)) 587 + int mlx5_ib_flow_counters_set_data(struct ib_counters *ibcounters, 588 + struct mlx5_ib_create_flow *ucmd) 589 + { 590 + struct mlx5_ib_mcounters *mcounters = to_mcounters(ibcounters); 591 + struct mlx5_ib_flow_counters_data *cntrs_data = NULL; 592 + struct mlx5_ib_flow_counters_desc *desc_data = NULL; 593 + bool hw_hndl = false; 594 + int ret = 0; 595 + 596 + if (ucmd && ucmd->ncounters_data != 0) { 597 + cntrs_data = ucmd->data; 598 + if (cntrs_data->ncounters > MAX_COUNTERS_NUM) 599 + return -EINVAL; 600 + 601 + desc_data = kcalloc(cntrs_data->ncounters, 602 + sizeof(*desc_data), 603 + GFP_KERNEL); 604 + if (!desc_data) 605 + return -ENOMEM; 606 + 607 + if (copy_from_user(desc_data, 608 + u64_to_user_ptr(cntrs_data->counters_data), 609 + sizeof(*desc_data) * cntrs_data->ncounters)) { 610 + ret = -EFAULT; 611 + goto free; 612 + } 613 + } 614 + 615 + if (!mcounters->hw_cntrs_hndl) { 616 + mcounters->hw_cntrs_hndl = mlx5_fc_create( 617 + to_mdev(ibcounters->device)->mdev, false); 618 + if (IS_ERR(mcounters->hw_cntrs_hndl)) { 619 + ret = PTR_ERR(mcounters->hw_cntrs_hndl); 620 + goto free; 621 + } 622 + hw_hndl = true; 623 + } 624 + 625 + if (desc_data) { 626 + /* counters already bound to at least one flow */ 627 + if (mcounters->cntrs_max_index) { 628 + ret = -EINVAL; 629 + goto free_hndl; 630 + } 631 + 632 + ret = counters_set_description(ibcounters, 633 + MLX5_IB_COUNTERS_FLOW, 634 + desc_data, 635 + cntrs_data->ncounters); 636 + if (ret) 637 + goto free_hndl; 638 + 639 + } else if (!mcounters->cntrs_max_index) { 640 + /* counters not bound yet, must have udata passed */ 641 + ret = -EINVAL; 642 + goto free_hndl; 643 + } 644 + 645 + return 0; 646 + 647 + free_hndl: 648 + if (hw_hndl) { 649 + mlx5_fc_destroy(to_mdev(ibcounters->device)->mdev, 650 + mcounters->hw_cntrs_hndl); 651 + mcounters->hw_cntrs_hndl = NULL; 652 + } 653 + free: 654 + kfree(desc_data); 655 + return ret; 656 + } 657 + 658 + void mlx5_ib_counters_clear_description(struct ib_counters *counters) 659 + { 660 + struct mlx5_ib_mcounters *mcounters; 661 + 662 + if (!counters || atomic_read(&counters->usecnt) != 1) 663 + return; 664 + 665 + mcounters = to_mcounters(counters); 666 + 667 + mutex_lock(&mcounters->mcntrs_mutex); 668 + kfree(mcounters->counters_data); 669 + mcounters->counters_data = NULL; 670 + mcounters->cntrs_max_index = 0; 671 + mutex_unlock(&mcounters->mcntrs_mutex); 672 + } 673 + 674 + static const struct ib_device_ops hw_stats_ops = { 675 + .alloc_hw_stats = mlx5_ib_alloc_hw_stats, 676 + .get_hw_stats = mlx5_ib_get_hw_stats, 677 + .counter_bind_qp = mlx5_ib_counter_bind_qp, 678 + .counter_unbind_qp = mlx5_ib_counter_unbind_qp, 679 + .counter_dealloc = mlx5_ib_counter_dealloc, 680 + .counter_alloc_stats = mlx5_ib_counter_alloc_stats, 681 + .counter_update_stats = mlx5_ib_counter_update_stats, 682 + }; 683 + 684 + static const struct ib_device_ops counters_ops = { 685 + .create_counters = mlx5_ib_create_counters, 686 + .destroy_counters = mlx5_ib_destroy_counters, 687 + .read_counters = mlx5_ib_read_counters, 688 + 689 + INIT_RDMA_OBJ_SIZE(ib_counters, mlx5_ib_mcounters, ibcntrs), 690 + }; 691 + 692 + int mlx5_ib_counters_init(struct mlx5_ib_dev *dev) 693 + { 694 + ib_set_device_ops(&dev->ib_dev, &counters_ops); 695 + 696 + if (!MLX5_CAP_GEN(dev->mdev, max_qp_cnt)) 697 + return 0; 698 + 699 + ib_set_device_ops(&dev->ib_dev, &hw_stats_ops); 700 + return mlx5_ib_alloc_counters(dev); 701 + } 702 + 703 + void mlx5_ib_counters_cleanup(struct mlx5_ib_dev *dev) 704 + { 705 + if (!MLX5_CAP_GEN(dev->mdev, max_qp_cnt)) 706 + return; 707 + 708 + mlx5_ib_dealloc_counters(dev); 709 + }
+17
drivers/infiniband/hw/mlx5/counters.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ 2 + /* 3 + * Copyright (c) 2013-2020, Mellanox Technologies inc. All rights reserved. 4 + */ 5 + 6 + #ifndef _MLX5_IB_COUNTERS_H 7 + #define _MLX5_IB_COUNTERS_H 8 + 9 + #include "mlx5_ib.h" 10 + 11 + int mlx5_ib_counters_init(struct mlx5_ib_dev *dev); 12 + void mlx5_ib_counters_cleanup(struct mlx5_ib_dev *dev); 13 + void mlx5_ib_counters_clear_description(struct ib_counters *counters); 14 + int mlx5_ib_flow_counters_set_data(struct ib_counters *ibcounters, 15 + struct mlx5_ib_create_flow *ucmd); 16 + u16 mlx5_ib_get_counters_id(struct mlx5_ib_dev *dev, u8 port_num); 17 + #endif /* _MLX5_IB_COUNTERS_H */
+8 -693
drivers/infiniband/hw/mlx5/main.c
··· 36 36 #include "qp.h" 37 37 #include "wr.h" 38 38 #include "restrack.h" 39 + #include "counters.h" 39 40 #include <linux/mlx5/fs_helpers.h> 40 41 #include <linux/mlx5/accel.h> 41 42 #include <rdma/uverbs_std_types.h> ··· 3250 3249 } 3251 3250 } 3252 3251 3253 - static void counters_clear_description(struct ib_counters *counters) 3254 - { 3255 - struct mlx5_ib_mcounters *mcounters = to_mcounters(counters); 3256 - 3257 - mutex_lock(&mcounters->mcntrs_mutex); 3258 - kfree(mcounters->counters_data); 3259 - mcounters->counters_data = NULL; 3260 - mcounters->cntrs_max_index = 0; 3261 - mutex_unlock(&mcounters->mcntrs_mutex); 3262 - } 3263 - 3264 3252 static int mlx5_ib_destroy_flow(struct ib_flow *flow_id) 3265 3253 { 3266 3254 struct mlx5_ib_flow_handler *handler = container_of(flow_id, ··· 3269 3279 3270 3280 mlx5_del_flow_rules(handler->rule); 3271 3281 put_flow_table(dev, handler->prio, true); 3272 - if (handler->ibcounters && 3273 - atomic_read(&handler->ibcounters->usecnt) == 1) 3274 - counters_clear_description(handler->ibcounters); 3275 - 3282 + mlx5_ib_counters_clear_description(handler->ibcounters); 3276 3283 mutex_unlock(&dev->flow_db->lock); 3277 3284 if (handler->flow_matcher) 3278 3285 atomic_dec(&handler->flow_matcher->usecnt); ··· 3423 3436 } 3424 3437 } 3425 3438 3426 - static int read_flow_counters(struct ib_device *ibdev, 3427 - struct mlx5_read_counters_attr *read_attr) 3428 - { 3429 - struct mlx5_fc *fc = read_attr->hw_cntrs_hndl; 3430 - struct mlx5_ib_dev *dev = to_mdev(ibdev); 3431 - 3432 - return mlx5_fc_query(dev->mdev, fc, 3433 - &read_attr->out[IB_COUNTER_PACKETS], 3434 - &read_attr->out[IB_COUNTER_BYTES]); 3435 - } 3436 - 3437 - /* flow counters currently expose two counters packets and bytes */ 3438 - #define FLOW_COUNTERS_NUM 2 3439 - static int counters_set_description(struct ib_counters *counters, 3440 - enum mlx5_ib_counters_type counters_type, 3441 - struct mlx5_ib_flow_counters_desc *desc_data, 3442 - u32 ncounters) 3443 - { 3444 - struct mlx5_ib_mcounters *mcounters = to_mcounters(counters); 3445 - u32 cntrs_max_index = 0; 3446 - int i; 3447 - 3448 - if (counters_type != MLX5_IB_COUNTERS_FLOW) 3449 - return -EINVAL; 3450 - 3451 - /* init the fields for the object */ 3452 - mcounters->type = counters_type; 3453 - mcounters->read_counters = read_flow_counters; 3454 - mcounters->counters_num = FLOW_COUNTERS_NUM; 3455 - mcounters->ncounters = ncounters; 3456 - /* each counter entry have both description and index pair */ 3457 - for (i = 0; i < ncounters; i++) { 3458 - if (desc_data[i].description > IB_COUNTER_BYTES) 3459 - return -EINVAL; 3460 - 3461 - if (cntrs_max_index <= desc_data[i].index) 3462 - cntrs_max_index = desc_data[i].index + 1; 3463 - } 3464 - 3465 - mutex_lock(&mcounters->mcntrs_mutex); 3466 - mcounters->counters_data = desc_data; 3467 - mcounters->cntrs_max_index = cntrs_max_index; 3468 - mutex_unlock(&mcounters->mcntrs_mutex); 3469 - 3470 - return 0; 3471 - } 3472 - 3473 - #define MAX_COUNTERS_NUM (USHRT_MAX / (sizeof(u32) * 2)) 3474 - static int flow_counters_set_data(struct ib_counters *ibcounters, 3475 - struct mlx5_ib_create_flow *ucmd) 3476 - { 3477 - struct mlx5_ib_mcounters *mcounters = to_mcounters(ibcounters); 3478 - struct mlx5_ib_flow_counters_data *cntrs_data = NULL; 3479 - struct mlx5_ib_flow_counters_desc *desc_data = NULL; 3480 - bool hw_hndl = false; 3481 - int ret = 0; 3482 - 3483 - if (ucmd && ucmd->ncounters_data != 0) { 3484 - cntrs_data = ucmd->data; 3485 - if (cntrs_data->ncounters > MAX_COUNTERS_NUM) 3486 - return -EINVAL; 3487 - 3488 - desc_data = kcalloc(cntrs_data->ncounters, 3489 - sizeof(*desc_data), 3490 - GFP_KERNEL); 3491 - if (!desc_data) 3492 - return -ENOMEM; 3493 - 3494 - if (copy_from_user(desc_data, 3495 - u64_to_user_ptr(cntrs_data->counters_data), 3496 - sizeof(*desc_data) * cntrs_data->ncounters)) { 3497 - ret = -EFAULT; 3498 - goto free; 3499 - } 3500 - } 3501 - 3502 - if (!mcounters->hw_cntrs_hndl) { 3503 - mcounters->hw_cntrs_hndl = mlx5_fc_create( 3504 - to_mdev(ibcounters->device)->mdev, false); 3505 - if (IS_ERR(mcounters->hw_cntrs_hndl)) { 3506 - ret = PTR_ERR(mcounters->hw_cntrs_hndl); 3507 - goto free; 3508 - } 3509 - hw_hndl = true; 3510 - } 3511 - 3512 - if (desc_data) { 3513 - /* counters already bound to at least one flow */ 3514 - if (mcounters->cntrs_max_index) { 3515 - ret = -EINVAL; 3516 - goto free_hndl; 3517 - } 3518 - 3519 - ret = counters_set_description(ibcounters, 3520 - MLX5_IB_COUNTERS_FLOW, 3521 - desc_data, 3522 - cntrs_data->ncounters); 3523 - if (ret) 3524 - goto free_hndl; 3525 - 3526 - } else if (!mcounters->cntrs_max_index) { 3527 - /* counters not bound yet, must have udata passed */ 3528 - ret = -EINVAL; 3529 - goto free_hndl; 3530 - } 3531 - 3532 - return 0; 3533 - 3534 - free_hndl: 3535 - if (hw_hndl) { 3536 - mlx5_fc_destroy(to_mdev(ibcounters->device)->mdev, 3537 - mcounters->hw_cntrs_hndl); 3538 - mcounters->hw_cntrs_hndl = NULL; 3539 - } 3540 - free: 3541 - kfree(desc_data); 3542 - return ret; 3543 - } 3544 - 3545 3439 static void mlx5_ib_set_rule_source_port(struct mlx5_ib_dev *dev, 3546 3440 struct mlx5_flow_spec *spec, 3547 3441 struct mlx5_eswitch_rep *rep) ··· 3532 3664 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { 3533 3665 struct mlx5_ib_mcounters *mcounters; 3534 3666 3535 - err = flow_counters_set_data(flow_act.counters, ucmd); 3667 + err = mlx5_ib_flow_counters_set_data(flow_act.counters, ucmd); 3536 3668 if (err) 3537 3669 goto free; 3538 3670 ··· 3582 3714 ft_prio->flow_table = ft; 3583 3715 free: 3584 3716 if (err && handler) { 3585 - if (handler->ibcounters && 3586 - atomic_read(&handler->ibcounters->usecnt) == 1) 3587 - counters_clear_description(handler->ibcounters); 3717 + mlx5_ib_counters_clear_description(handler->ibcounters); 3588 3718 kfree(handler); 3589 3719 } 3590 3720 kvfree(spec); ··· 5174 5308 mlx5_nic_vport_disable_roce(dev->mdev); 5175 5309 } 5176 5310 5177 - struct mlx5_ib_counter { 5178 - const char *name; 5179 - size_t offset; 5180 - }; 5181 - 5182 - #define INIT_Q_COUNTER(_name) \ 5183 - { .name = #_name, .offset = MLX5_BYTE_OFF(query_q_counter_out, _name)} 5184 - 5185 - static const struct mlx5_ib_counter basic_q_cnts[] = { 5186 - INIT_Q_COUNTER(rx_write_requests), 5187 - INIT_Q_COUNTER(rx_read_requests), 5188 - INIT_Q_COUNTER(rx_atomic_requests), 5189 - INIT_Q_COUNTER(out_of_buffer), 5190 - }; 5191 - 5192 - static const struct mlx5_ib_counter out_of_seq_q_cnts[] = { 5193 - INIT_Q_COUNTER(out_of_sequence), 5194 - }; 5195 - 5196 - static const struct mlx5_ib_counter retrans_q_cnts[] = { 5197 - INIT_Q_COUNTER(duplicate_request), 5198 - INIT_Q_COUNTER(rnr_nak_retry_err), 5199 - INIT_Q_COUNTER(packet_seq_err), 5200 - INIT_Q_COUNTER(implied_nak_seq_err), 5201 - INIT_Q_COUNTER(local_ack_timeout_err), 5202 - }; 5203 - 5204 - #define INIT_CONG_COUNTER(_name) \ 5205 - { .name = #_name, .offset = \ 5206 - MLX5_BYTE_OFF(query_cong_statistics_out, _name ## _high)} 5207 - 5208 - static const struct mlx5_ib_counter cong_cnts[] = { 5209 - INIT_CONG_COUNTER(rp_cnp_ignored), 5210 - INIT_CONG_COUNTER(rp_cnp_handled), 5211 - INIT_CONG_COUNTER(np_ecn_marked_roce_packets), 5212 - INIT_CONG_COUNTER(np_cnp_sent), 5213 - }; 5214 - 5215 - static const struct mlx5_ib_counter extended_err_cnts[] = { 5216 - INIT_Q_COUNTER(resp_local_length_error), 5217 - INIT_Q_COUNTER(resp_cqe_error), 5218 - INIT_Q_COUNTER(req_cqe_error), 5219 - INIT_Q_COUNTER(req_remote_invalid_request), 5220 - INIT_Q_COUNTER(req_remote_access_errors), 5221 - INIT_Q_COUNTER(resp_remote_access_errors), 5222 - INIT_Q_COUNTER(resp_cqe_flush_error), 5223 - INIT_Q_COUNTER(req_cqe_flush_error), 5224 - }; 5225 - 5226 - static const struct mlx5_ib_counter roce_accl_cnts[] = { 5227 - INIT_Q_COUNTER(roce_adp_retrans), 5228 - INIT_Q_COUNTER(roce_adp_retrans_to), 5229 - INIT_Q_COUNTER(roce_slow_restart), 5230 - INIT_Q_COUNTER(roce_slow_restart_cnps), 5231 - INIT_Q_COUNTER(roce_slow_restart_trans), 5232 - }; 5233 - 5234 - #define INIT_EXT_PPCNT_COUNTER(_name) \ 5235 - { .name = #_name, .offset = \ 5236 - MLX5_BYTE_OFF(ppcnt_reg, \ 5237 - counter_set.eth_extended_cntrs_grp_data_layout._name##_high)} 5238 - 5239 - static const struct mlx5_ib_counter ext_ppcnt_cnts[] = { 5240 - INIT_EXT_PPCNT_COUNTER(rx_icrc_encapsulated), 5241 - }; 5242 - 5243 - static bool is_mdev_switchdev_mode(const struct mlx5_core_dev *mdev) 5244 - { 5245 - return MLX5_ESWITCH_MANAGER(mdev) && 5246 - mlx5_ib_eswitch_mode(mdev->priv.eswitch) == 5247 - MLX5_ESWITCH_OFFLOADS; 5248 - } 5249 - 5250 - static void mlx5_ib_dealloc_counters(struct mlx5_ib_dev *dev) 5251 - { 5252 - u32 in[MLX5_ST_SZ_DW(dealloc_q_counter_in)] = {}; 5253 - int num_cnt_ports; 5254 - int i; 5255 - 5256 - num_cnt_ports = is_mdev_switchdev_mode(dev->mdev) ? 1 : dev->num_ports; 5257 - 5258 - MLX5_SET(dealloc_q_counter_in, in, opcode, 5259 - MLX5_CMD_OP_DEALLOC_Q_COUNTER); 5260 - 5261 - for (i = 0; i < num_cnt_ports; i++) { 5262 - if (dev->port[i].cnts.set_id) { 5263 - MLX5_SET(dealloc_q_counter_in, in, counter_set_id, 5264 - dev->port[i].cnts.set_id); 5265 - mlx5_cmd_exec_in(dev->mdev, dealloc_q_counter, in); 5266 - } 5267 - kfree(dev->port[i].cnts.names); 5268 - kfree(dev->port[i].cnts.offsets); 5269 - } 5270 - } 5271 - 5272 - static int __mlx5_ib_alloc_counters(struct mlx5_ib_dev *dev, 5273 - struct mlx5_ib_counters *cnts) 5274 - { 5275 - u32 num_counters; 5276 - 5277 - num_counters = ARRAY_SIZE(basic_q_cnts); 5278 - 5279 - if (MLX5_CAP_GEN(dev->mdev, out_of_seq_cnt)) 5280 - num_counters += ARRAY_SIZE(out_of_seq_q_cnts); 5281 - 5282 - if (MLX5_CAP_GEN(dev->mdev, retransmission_q_counters)) 5283 - num_counters += ARRAY_SIZE(retrans_q_cnts); 5284 - 5285 - if (MLX5_CAP_GEN(dev->mdev, enhanced_error_q_counters)) 5286 - num_counters += ARRAY_SIZE(extended_err_cnts); 5287 - 5288 - if (MLX5_CAP_GEN(dev->mdev, roce_accl)) 5289 - num_counters += ARRAY_SIZE(roce_accl_cnts); 5290 - 5291 - cnts->num_q_counters = num_counters; 5292 - 5293 - if (MLX5_CAP_GEN(dev->mdev, cc_query_allowed)) { 5294 - cnts->num_cong_counters = ARRAY_SIZE(cong_cnts); 5295 - num_counters += ARRAY_SIZE(cong_cnts); 5296 - } 5297 - if (MLX5_CAP_PCAM_FEATURE(dev->mdev, rx_icrc_encapsulated_counter)) { 5298 - cnts->num_ext_ppcnt_counters = ARRAY_SIZE(ext_ppcnt_cnts); 5299 - num_counters += ARRAY_SIZE(ext_ppcnt_cnts); 5300 - } 5301 - cnts->names = kcalloc(num_counters, sizeof(cnts->names), GFP_KERNEL); 5302 - if (!cnts->names) 5303 - return -ENOMEM; 5304 - 5305 - cnts->offsets = kcalloc(num_counters, 5306 - sizeof(cnts->offsets), GFP_KERNEL); 5307 - if (!cnts->offsets) 5308 - goto err_names; 5309 - 5310 - return 0; 5311 - 5312 - err_names: 5313 - kfree(cnts->names); 5314 - cnts->names = NULL; 5315 - return -ENOMEM; 5316 - } 5317 - 5318 - static void mlx5_ib_fill_counters(struct mlx5_ib_dev *dev, 5319 - const char **names, 5320 - size_t *offsets) 5321 - { 5322 - int i; 5323 - int j = 0; 5324 - 5325 - for (i = 0; i < ARRAY_SIZE(basic_q_cnts); i++, j++) { 5326 - names[j] = basic_q_cnts[i].name; 5327 - offsets[j] = basic_q_cnts[i].offset; 5328 - } 5329 - 5330 - if (MLX5_CAP_GEN(dev->mdev, out_of_seq_cnt)) { 5331 - for (i = 0; i < ARRAY_SIZE(out_of_seq_q_cnts); i++, j++) { 5332 - names[j] = out_of_seq_q_cnts[i].name; 5333 - offsets[j] = out_of_seq_q_cnts[i].offset; 5334 - } 5335 - } 5336 - 5337 - if (MLX5_CAP_GEN(dev->mdev, retransmission_q_counters)) { 5338 - for (i = 0; i < ARRAY_SIZE(retrans_q_cnts); i++, j++) { 5339 - names[j] = retrans_q_cnts[i].name; 5340 - offsets[j] = retrans_q_cnts[i].offset; 5341 - } 5342 - } 5343 - 5344 - if (MLX5_CAP_GEN(dev->mdev, enhanced_error_q_counters)) { 5345 - for (i = 0; i < ARRAY_SIZE(extended_err_cnts); i++, j++) { 5346 - names[j] = extended_err_cnts[i].name; 5347 - offsets[j] = extended_err_cnts[i].offset; 5348 - } 5349 - } 5350 - 5351 - if (MLX5_CAP_GEN(dev->mdev, roce_accl)) { 5352 - for (i = 0; i < ARRAY_SIZE(roce_accl_cnts); i++, j++) { 5353 - names[j] = roce_accl_cnts[i].name; 5354 - offsets[j] = roce_accl_cnts[i].offset; 5355 - } 5356 - } 5357 - 5358 - if (MLX5_CAP_GEN(dev->mdev, cc_query_allowed)) { 5359 - for (i = 0; i < ARRAY_SIZE(cong_cnts); i++, j++) { 5360 - names[j] = cong_cnts[i].name; 5361 - offsets[j] = cong_cnts[i].offset; 5362 - } 5363 - } 5364 - 5365 - if (MLX5_CAP_PCAM_FEATURE(dev->mdev, rx_icrc_encapsulated_counter)) { 5366 - for (i = 0; i < ARRAY_SIZE(ext_ppcnt_cnts); i++, j++) { 5367 - names[j] = ext_ppcnt_cnts[i].name; 5368 - offsets[j] = ext_ppcnt_cnts[i].offset; 5369 - } 5370 - } 5371 - } 5372 - 5373 - static int mlx5_ib_alloc_counters(struct mlx5_ib_dev *dev) 5374 - { 5375 - u32 out[MLX5_ST_SZ_DW(alloc_q_counter_out)] = {}; 5376 - u32 in[MLX5_ST_SZ_DW(alloc_q_counter_in)] = {}; 5377 - int num_cnt_ports; 5378 - int err = 0; 5379 - int i; 5380 - bool is_shared; 5381 - 5382 - MLX5_SET(alloc_q_counter_in, in, opcode, MLX5_CMD_OP_ALLOC_Q_COUNTER); 5383 - is_shared = MLX5_CAP_GEN(dev->mdev, log_max_uctx) != 0; 5384 - num_cnt_ports = is_mdev_switchdev_mode(dev->mdev) ? 1 : dev->num_ports; 5385 - 5386 - for (i = 0; i < num_cnt_ports; i++) { 5387 - err = __mlx5_ib_alloc_counters(dev, &dev->port[i].cnts); 5388 - if (err) 5389 - goto err_alloc; 5390 - 5391 - mlx5_ib_fill_counters(dev, dev->port[i].cnts.names, 5392 - dev->port[i].cnts.offsets); 5393 - 5394 - MLX5_SET(alloc_q_counter_in, in, uid, 5395 - is_shared ? MLX5_SHARED_RESOURCE_UID : 0); 5396 - 5397 - err = mlx5_cmd_exec_inout(dev->mdev, alloc_q_counter, in, out); 5398 - if (err) { 5399 - mlx5_ib_warn(dev, 5400 - "couldn't allocate queue counter for port %d, err %d\n", 5401 - i + 1, err); 5402 - goto err_alloc; 5403 - } 5404 - 5405 - dev->port[i].cnts.set_id = 5406 - MLX5_GET(alloc_q_counter_out, out, counter_set_id); 5407 - } 5408 - return 0; 5409 - 5410 - err_alloc: 5411 - mlx5_ib_dealloc_counters(dev); 5412 - return err; 5413 - } 5414 - 5415 - static const struct mlx5_ib_counters *get_counters(struct mlx5_ib_dev *dev, 5416 - u8 port_num) 5417 - { 5418 - return is_mdev_switchdev_mode(dev->mdev) ? &dev->port[0].cnts : 5419 - &dev->port[port_num].cnts; 5420 - } 5421 - 5422 - /** 5423 - * mlx5_ib_get_counters_id - Returns counters id to use for device+port 5424 - * @dev: Pointer to mlx5 IB device 5425 - * @port_num: Zero based port number 5426 - * 5427 - * mlx5_ib_get_counters_id() Returns counters set id to use for given 5428 - * device port combination in switchdev and non switchdev mode of the 5429 - * parent device. 5430 - */ 5431 - u16 mlx5_ib_get_counters_id(struct mlx5_ib_dev *dev, u8 port_num) 5432 - { 5433 - const struct mlx5_ib_counters *cnts = get_counters(dev, port_num); 5434 - 5435 - return cnts->set_id; 5436 - } 5437 - 5438 - static struct rdma_hw_stats *mlx5_ib_alloc_hw_stats(struct ib_device *ibdev, 5439 - u8 port_num) 5440 - { 5441 - struct mlx5_ib_dev *dev = to_mdev(ibdev); 5442 - const struct mlx5_ib_counters *cnts; 5443 - bool is_switchdev = is_mdev_switchdev_mode(dev->mdev); 5444 - 5445 - if ((is_switchdev && port_num) || (!is_switchdev && !port_num)) 5446 - return NULL; 5447 - 5448 - cnts = get_counters(dev, port_num - 1); 5449 - 5450 - return rdma_alloc_hw_stats_struct(cnts->names, 5451 - cnts->num_q_counters + 5452 - cnts->num_cong_counters + 5453 - cnts->num_ext_ppcnt_counters, 5454 - RDMA_HW_STATS_DEFAULT_LIFESPAN); 5455 - } 5456 - 5457 - static int mlx5_ib_query_q_counters(struct mlx5_core_dev *mdev, 5458 - const struct mlx5_ib_counters *cnts, 5459 - struct rdma_hw_stats *stats, 5460 - u16 set_id) 5461 - { 5462 - u32 out[MLX5_ST_SZ_DW(query_q_counter_out)] = {}; 5463 - u32 in[MLX5_ST_SZ_DW(query_q_counter_in)] = {}; 5464 - __be32 val; 5465 - int ret, i; 5466 - 5467 - MLX5_SET(query_q_counter_in, in, opcode, MLX5_CMD_OP_QUERY_Q_COUNTER); 5468 - MLX5_SET(query_q_counter_in, in, counter_set_id, set_id); 5469 - ret = mlx5_cmd_exec_inout(mdev, query_q_counter, in, out); 5470 - if (ret) 5471 - return ret; 5472 - 5473 - for (i = 0; i < cnts->num_q_counters; i++) { 5474 - val = *(__be32 *)((void *)out + cnts->offsets[i]); 5475 - stats->value[i] = (u64)be32_to_cpu(val); 5476 - } 5477 - 5478 - return 0; 5479 - } 5480 - 5481 - static int mlx5_ib_query_ext_ppcnt_counters(struct mlx5_ib_dev *dev, 5482 - const struct mlx5_ib_counters *cnts, 5483 - struct rdma_hw_stats *stats) 5484 - { 5485 - int offset = cnts->num_q_counters + cnts->num_cong_counters; 5486 - int sz = MLX5_ST_SZ_BYTES(ppcnt_reg); 5487 - int ret, i; 5488 - void *out; 5489 - 5490 - out = kvzalloc(sz, GFP_KERNEL); 5491 - if (!out) 5492 - return -ENOMEM; 5493 - 5494 - ret = mlx5_cmd_query_ext_ppcnt_counters(dev->mdev, out); 5495 - if (ret) 5496 - goto free; 5497 - 5498 - for (i = 0; i < cnts->num_ext_ppcnt_counters; i++) 5499 - stats->value[i + offset] = 5500 - be64_to_cpup((__be64 *)(out + 5501 - cnts->offsets[i + offset])); 5502 - free: 5503 - kvfree(out); 5504 - return ret; 5505 - } 5506 - 5507 - static int mlx5_ib_get_hw_stats(struct ib_device *ibdev, 5508 - struct rdma_hw_stats *stats, 5509 - u8 port_num, int index) 5510 - { 5511 - struct mlx5_ib_dev *dev = to_mdev(ibdev); 5512 - const struct mlx5_ib_counters *cnts = get_counters(dev, port_num - 1); 5513 - struct mlx5_core_dev *mdev; 5514 - int ret, num_counters; 5515 - u8 mdev_port_num; 5516 - 5517 - if (!stats) 5518 - return -EINVAL; 5519 - 5520 - num_counters = cnts->num_q_counters + 5521 - cnts->num_cong_counters + 5522 - cnts->num_ext_ppcnt_counters; 5523 - 5524 - /* q_counters are per IB device, query the master mdev */ 5525 - ret = mlx5_ib_query_q_counters(dev->mdev, cnts, stats, cnts->set_id); 5526 - if (ret) 5527 - return ret; 5528 - 5529 - if (MLX5_CAP_PCAM_FEATURE(dev->mdev, rx_icrc_encapsulated_counter)) { 5530 - ret = mlx5_ib_query_ext_ppcnt_counters(dev, cnts, stats); 5531 - if (ret) 5532 - return ret; 5533 - } 5534 - 5535 - if (MLX5_CAP_GEN(dev->mdev, cc_query_allowed)) { 5536 - mdev = mlx5_ib_get_native_port_mdev(dev, port_num, 5537 - &mdev_port_num); 5538 - if (!mdev) { 5539 - /* If port is not affiliated yet, its in down state 5540 - * which doesn't have any counters yet, so it would be 5541 - * zero. So no need to read from the HCA. 5542 - */ 5543 - goto done; 5544 - } 5545 - ret = mlx5_lag_query_cong_counters(dev->mdev, 5546 - stats->value + 5547 - cnts->num_q_counters, 5548 - cnts->num_cong_counters, 5549 - cnts->offsets + 5550 - cnts->num_q_counters); 5551 - 5552 - mlx5_ib_put_native_port_mdev(dev, port_num); 5553 - if (ret) 5554 - return ret; 5555 - } 5556 - 5557 - done: 5558 - return num_counters; 5559 - } 5560 - 5561 - static struct rdma_hw_stats * 5562 - mlx5_ib_counter_alloc_stats(struct rdma_counter *counter) 5563 - { 5564 - struct mlx5_ib_dev *dev = to_mdev(counter->device); 5565 - const struct mlx5_ib_counters *cnts = 5566 - get_counters(dev, counter->port - 1); 5567 - 5568 - return rdma_alloc_hw_stats_struct(cnts->names, 5569 - cnts->num_q_counters + 5570 - cnts->num_cong_counters + 5571 - cnts->num_ext_ppcnt_counters, 5572 - RDMA_HW_STATS_DEFAULT_LIFESPAN); 5573 - } 5574 - 5575 - static int mlx5_ib_counter_update_stats(struct rdma_counter *counter) 5576 - { 5577 - struct mlx5_ib_dev *dev = to_mdev(counter->device); 5578 - const struct mlx5_ib_counters *cnts = 5579 - get_counters(dev, counter->port - 1); 5580 - 5581 - return mlx5_ib_query_q_counters(dev->mdev, cnts, 5582 - counter->stats, counter->id); 5583 - } 5584 - 5585 - static int mlx5_ib_counter_dealloc(struct rdma_counter *counter) 5586 - { 5587 - struct mlx5_ib_dev *dev = to_mdev(counter->device); 5588 - u32 in[MLX5_ST_SZ_DW(dealloc_q_counter_in)] = {}; 5589 - 5590 - if (!counter->id) 5591 - return 0; 5592 - 5593 - MLX5_SET(dealloc_q_counter_in, in, opcode, 5594 - MLX5_CMD_OP_DEALLOC_Q_COUNTER); 5595 - MLX5_SET(dealloc_q_counter_in, in, counter_set_id, counter->id); 5596 - return mlx5_cmd_exec_in(dev->mdev, dealloc_q_counter, in); 5597 - } 5598 - 5599 - static int mlx5_ib_counter_bind_qp(struct rdma_counter *counter, 5600 - struct ib_qp *qp) 5601 - { 5602 - struct mlx5_ib_dev *dev = to_mdev(qp->device); 5603 - int err; 5604 - 5605 - if (!counter->id) { 5606 - u32 out[MLX5_ST_SZ_DW(alloc_q_counter_out)] = {}; 5607 - u32 in[MLX5_ST_SZ_DW(alloc_q_counter_in)] = {}; 5608 - 5609 - MLX5_SET(alloc_q_counter_in, in, opcode, 5610 - MLX5_CMD_OP_ALLOC_Q_COUNTER); 5611 - MLX5_SET(alloc_q_counter_in, in, uid, MLX5_SHARED_RESOURCE_UID); 5612 - err = mlx5_cmd_exec_inout(dev->mdev, alloc_q_counter, in, out); 5613 - if (err) 5614 - return err; 5615 - counter->id = 5616 - MLX5_GET(alloc_q_counter_out, out, counter_set_id); 5617 - } 5618 - 5619 - err = mlx5_ib_qp_set_counter(qp, counter); 5620 - if (err) 5621 - goto fail_set_counter; 5622 - 5623 - return 0; 5624 - 5625 - fail_set_counter: 5626 - mlx5_ib_counter_dealloc(counter); 5627 - counter->id = 0; 5628 - 5629 - return err; 5630 - } 5631 - 5632 - static int mlx5_ib_counter_unbind_qp(struct ib_qp *qp) 5633 - { 5634 - return mlx5_ib_qp_set_counter(qp, NULL); 5635 - } 5636 - 5637 5311 static int mlx5_ib_rn_get_params(struct ib_device *device, u8 port_num, 5638 5312 enum rdma_netdev_t type, 5639 5313 struct rdma_netdev_alloc_params *params) ··· 5793 6387 {} 5794 6388 }; 5795 6389 5796 - static int mlx5_ib_read_counters(struct ib_counters *counters, 5797 - struct ib_counters_read_attr *read_attr, 5798 - struct uverbs_attr_bundle *attrs) 5799 - { 5800 - struct mlx5_ib_mcounters *mcounters = to_mcounters(counters); 5801 - struct mlx5_read_counters_attr mread_attr = {}; 5802 - struct mlx5_ib_flow_counters_desc *desc; 5803 - int ret, i; 5804 - 5805 - mutex_lock(&mcounters->mcntrs_mutex); 5806 - if (mcounters->cntrs_max_index > read_attr->ncounters) { 5807 - ret = -EINVAL; 5808 - goto err_bound; 5809 - } 5810 - 5811 - mread_attr.out = kcalloc(mcounters->counters_num, sizeof(u64), 5812 - GFP_KERNEL); 5813 - if (!mread_attr.out) { 5814 - ret = -ENOMEM; 5815 - goto err_bound; 5816 - } 5817 - 5818 - mread_attr.hw_cntrs_hndl = mcounters->hw_cntrs_hndl; 5819 - mread_attr.flags = read_attr->flags; 5820 - ret = mcounters->read_counters(counters->device, &mread_attr); 5821 - if (ret) 5822 - goto err_read; 5823 - 5824 - /* do the pass over the counters data array to assign according to the 5825 - * descriptions and indexing pairs 5826 - */ 5827 - desc = mcounters->counters_data; 5828 - for (i = 0; i < mcounters->ncounters; i++) 5829 - read_attr->counters_buff[desc[i].index] += mread_attr.out[desc[i].description]; 5830 - 5831 - err_read: 5832 - kfree(mread_attr.out); 5833 - err_bound: 5834 - mutex_unlock(&mcounters->mcntrs_mutex); 5835 - return ret; 5836 - } 5837 - 5838 - static void mlx5_ib_destroy_counters(struct ib_counters *counters) 5839 - { 5840 - struct mlx5_ib_mcounters *mcounters = to_mcounters(counters); 5841 - 5842 - counters_clear_description(counters); 5843 - if (mcounters->hw_cntrs_hndl) 5844 - mlx5_fc_destroy(to_mdev(counters->device)->mdev, 5845 - mcounters->hw_cntrs_hndl); 5846 - } 5847 - 5848 - static int mlx5_ib_create_counters(struct ib_counters *counters, 5849 - struct uverbs_attr_bundle *attrs) 5850 - { 5851 - struct mlx5_ib_mcounters *mcounters = to_mcounters(counters); 5852 - 5853 - mutex_init(&mcounters->mcntrs_mutex); 5854 - return 0; 5855 - } 5856 - 5857 6390 static void mlx5_ib_stage_init_cleanup(struct mlx5_ib_dev *dev) 5858 6391 { 5859 6392 mlx5_ib_cleanup_multiport_master(dev); ··· 5913 6568 .attach_mcast = mlx5_ib_mcg_attach, 5914 6569 .check_mr_status = mlx5_ib_check_mr_status, 5915 6570 .create_ah = mlx5_ib_create_ah, 5916 - .create_counters = mlx5_ib_create_counters, 5917 6571 .create_cq = mlx5_ib_create_cq, 5918 6572 .create_flow = mlx5_ib_create_flow, 5919 6573 .create_qp = mlx5_ib_create_qp, ··· 5922 6578 .del_gid = mlx5_ib_del_gid, 5923 6579 .dereg_mr = mlx5_ib_dereg_mr, 5924 6580 .destroy_ah = mlx5_ib_destroy_ah, 5925 - .destroy_counters = mlx5_ib_destroy_counters, 5926 6581 .destroy_cq = mlx5_ib_destroy_cq, 5927 6582 .destroy_flow = mlx5_ib_destroy_flow, 5928 6583 .destroy_flow_action = mlx5_ib_destroy_flow_action, ··· 5956 6613 .query_qp = mlx5_ib_query_qp, 5957 6614 .query_srq = mlx5_ib_query_srq, 5958 6615 .query_ucontext = mlx5_ib_query_ucontext, 5959 - .read_counters = mlx5_ib_read_counters, 5960 6616 .reg_user_mr = mlx5_ib_reg_user_mr, 5961 6617 .req_notify_cq = mlx5_ib_arm_cq, 5962 6618 .rereg_user_mr = mlx5_ib_rereg_user_mr, ··· 6272 6930 mlx5_ib_odp_cleanup_one(dev); 6273 6931 } 6274 6932 6275 - static const struct ib_device_ops mlx5_ib_dev_hw_stats_ops = { 6276 - .alloc_hw_stats = mlx5_ib_alloc_hw_stats, 6277 - .get_hw_stats = mlx5_ib_get_hw_stats, 6278 - .counter_bind_qp = mlx5_ib_counter_bind_qp, 6279 - .counter_unbind_qp = mlx5_ib_counter_unbind_qp, 6280 - .counter_dealloc = mlx5_ib_counter_dealloc, 6281 - .counter_alloc_stats = mlx5_ib_counter_alloc_stats, 6282 - .counter_update_stats = mlx5_ib_counter_update_stats, 6283 - }; 6284 - 6285 - static int mlx5_ib_stage_counters_init(struct mlx5_ib_dev *dev) 6286 - { 6287 - if (MLX5_CAP_GEN(dev->mdev, max_qp_cnt)) { 6288 - ib_set_device_ops(&dev->ib_dev, &mlx5_ib_dev_hw_stats_ops); 6289 - 6290 - return mlx5_ib_alloc_counters(dev); 6291 - } 6292 - 6293 - return 0; 6294 - } 6295 - 6296 - static void mlx5_ib_stage_counters_cleanup(struct mlx5_ib_dev *dev) 6297 - { 6298 - if (MLX5_CAP_GEN(dev->mdev, max_qp_cnt)) 6299 - mlx5_ib_dealloc_counters(dev); 6300 - } 6301 - 6302 6933 static int mlx5_ib_stage_cong_debugfs_init(struct mlx5_ib_dev *dev) 6303 6934 { 6304 6935 mlx5_ib_init_cong_debugfs(dev, ··· 6463 7148 mlx5_ib_stage_odp_init, 6464 7149 mlx5_ib_stage_odp_cleanup), 6465 7150 STAGE_CREATE(MLX5_IB_STAGE_COUNTERS, 6466 - mlx5_ib_stage_counters_init, 6467 - mlx5_ib_stage_counters_cleanup), 7151 + mlx5_ib_counters_init, 7152 + mlx5_ib_counters_cleanup), 6468 7153 STAGE_CREATE(MLX5_IB_STAGE_CONG_DEBUGFS, 6469 7154 mlx5_ib_stage_cong_debugfs_init, 6470 7155 mlx5_ib_stage_cong_debugfs_cleanup), ··· 6523 7208 mlx5_ib_stage_dev_notifier_init, 6524 7209 mlx5_ib_stage_dev_notifier_cleanup), 6525 7210 STAGE_CREATE(MLX5_IB_STAGE_COUNTERS, 6526 - mlx5_ib_stage_counters_init, 6527 - mlx5_ib_stage_counters_cleanup), 7211 + mlx5_ib_counters_init, 7212 + mlx5_ib_counters_cleanup), 6528 7213 STAGE_CREATE(MLX5_IB_STAGE_CONG_DEBUGFS, 6529 7214 mlx5_ib_stage_cong_debugfs_init, 6530 7215 mlx5_ib_stage_cong_debugfs_cleanup),
-3
drivers/infiniband/hw/mlx5/mlx5_ib.h
··· 1488 1488 struct mlx5_bfreg_info *bfregi, u32 bfregn, 1489 1489 bool dyn_bfreg); 1490 1490 1491 - int mlx5_ib_qp_set_counter(struct ib_qp *qp, struct rdma_counter *counter); 1492 - u16 mlx5_ib_get_counters_id(struct mlx5_ib_dev *dev, u8 port_num); 1493 - 1494 1491 static inline bool mlx5_ib_can_use_umr(struct mlx5_ib_dev *dev, 1495 1492 bool do_modify_atomic, int access_flags) 1496 1493 {
+1
drivers/infiniband/hw/mlx5/qp.c
··· 38 38 #include <linux/mlx5/fs.h> 39 39 #include "mlx5_ib.h" 40 40 #include "ib_rep.h" 41 + #include "counters.h" 41 42 #include "cmd.h" 42 43 #include "qp.h" 43 44 #include "wr.h"
+1
drivers/infiniband/hw/mlx5/qp.h
··· 43 43 44 44 int mlx5_core_xrcd_alloc(struct mlx5_ib_dev *dev, u32 *xrcdn); 45 45 int mlx5_core_xrcd_dealloc(struct mlx5_ib_dev *dev, u32 xrcdn); 46 + int mlx5_ib_qp_set_counter(struct ib_qp *qp, struct rdma_counter *counter); 46 47 #endif /* _MLX5_IB_QP_H */