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

mlx5: Fix default values in create CQ

Currently, CQs without a completion function are assigned the
mlx5_add_cq_to_tasklet function by default. This is problematic since
only user CQs created through the mlx5_ib driver are intended to use
this function.

Additionally, all CQs that will use doorbells instead of polling for
completions must call mlx5_cq_arm. However, the default CQ creation flow
leaves a valid value in the CQ's arm_db field, allowing FW to send
interrupts to polling-only CQs in certain corner cases.

These two factors would allow a polling-only kernel CQ to be triggered
by an EQ interrupt and call a completion function intended only for user
CQs, causing a null pointer exception.

Some areas in the driver have prevented this issue with one-off fixes
but did not address the root cause.

This patch fixes the described issue by adding defaults to the create CQ
flow. It adds a default dummy completion function to protect against
null pointer exceptions, and it sets an invalid command sequence number
by default in kernel CQs to prevent the FW from sending an interrupt to
the CQ until it is armed. User CQs are responsible for their own
initialization values.

Callers of mlx5_core_create_cq are responsible for changing the
completion function and arming the CQ per their needs.

Fixes: cdd04f4d4d71 ("net/mlx5: Add support to create SQ and CQ for ASO")
Signed-off-by: Akiva Goldberger <agoldberger@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Acked-by: Leon Romanovsky <leon@kernel.org>
Link: https://patch.msgid.link/1762681743-1084694-1-git-send-email-tariqt@nvidia.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Akiva Goldberger and committed by
Paolo Abeni
e5eba42f ed6b5632

+44 -48
+7 -4
drivers/infiniband/hw/mlx5/cq.c
··· 1020 1020 if (cq->create_flags & IB_UVERBS_CQ_FLAGS_IGNORE_OVERRUN) 1021 1021 MLX5_SET(cqc, cqc, oi, 1); 1022 1022 1023 + if (udata) { 1024 + cq->mcq.comp = mlx5_add_cq_to_tasklet; 1025 + cq->mcq.tasklet_ctx.comp = mlx5_ib_cq_comp; 1026 + } else { 1027 + cq->mcq.comp = mlx5_ib_cq_comp; 1028 + } 1029 + 1023 1030 err = mlx5_core_create_cq(dev->mdev, &cq->mcq, cqb, inlen, out, sizeof(out)); 1024 1031 if (err) 1025 1032 goto err_cqb; 1026 1033 1027 1034 mlx5_ib_dbg(dev, "cqn 0x%x\n", cq->mcq.cqn); 1028 - if (udata) 1029 - cq->mcq.tasklet_ctx.comp = mlx5_ib_cq_comp; 1030 - else 1031 - cq->mcq.comp = mlx5_ib_cq_comp; 1032 1035 cq->mcq.event = mlx5_ib_cq_event; 1033 1036 1034 1037 INIT_LIST_HEAD(&cq->wc_list);
+20 -3
drivers/net/ethernet/mellanox/mlx5/core/cq.c
··· 66 66 tasklet_schedule(&ctx->task); 67 67 } 68 68 69 - static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq, 70 - struct mlx5_eqe *eqe) 69 + void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq, 70 + struct mlx5_eqe *eqe) 71 71 { 72 72 unsigned long flags; 73 73 struct mlx5_eq_tasklet *tasklet_ctx = cq->tasklet_ctx.priv; ··· 95 95 if (schedule_tasklet) 96 96 tasklet_schedule(&tasklet_ctx->task); 97 97 } 98 + EXPORT_SYMBOL(mlx5_add_cq_to_tasklet); 98 99 100 + static void mlx5_core_cq_dummy_cb(struct mlx5_core_cq *cq, struct mlx5_eqe *eqe) 101 + { 102 + mlx5_core_err(cq->eq->core.dev, 103 + "CQ default completion callback, CQ #%u\n", cq->cqn); 104 + } 105 + 106 + #define MLX5_CQ_INIT_CMD_SN cpu_to_be32(2 << 28) 99 107 /* Callers must verify outbox status in case of err */ 100 108 int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, 101 109 u32 *in, int inlen, u32 *out, int outlen) ··· 129 121 cq->arm_sn = 0; 130 122 cq->eq = eq; 131 123 cq->uid = MLX5_GET(create_cq_in, in, uid); 124 + 125 + /* Kernel CQs must set the arm_db address prior to calling 126 + * this function, allowing for the proper value to be 127 + * initialized. User CQs are responsible for their own 128 + * initialization since they do not use the arm_db field. 129 + */ 130 + if (cq->arm_db) 131 + *cq->arm_db = MLX5_CQ_INIT_CMD_SN; 132 + 132 133 refcount_set(&cq->refcount, 1); 133 134 init_completion(&cq->free); 134 135 if (!cq->comp) 135 - cq->comp = mlx5_add_cq_to_tasklet; 136 + cq->comp = mlx5_core_cq_dummy_cb; 136 137 /* assuming CQ will be deleted before the EQ */ 137 138 cq->tasklet_ctx.priv = &eq->tasklet_ctx; 138 139 INIT_LIST_HEAD(&cq->tasklet_ctx.list);
-1
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
··· 2219 2219 mcq->set_ci_db = cq->wq_ctrl.db.db; 2220 2220 mcq->arm_db = cq->wq_ctrl.db.db + 1; 2221 2221 *mcq->set_ci_db = 0; 2222 - *mcq->arm_db = 0; 2223 2222 mcq->vector = param->eq_ix; 2224 2223 mcq->comp = mlx5e_completion_event; 2225 2224 mcq->event = mlx5e_cq_error_event;
+7 -8
drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c
··· 421 421 __be64 *pas; 422 422 u32 i; 423 423 424 + conn->cq.mcq.cqe_sz = 64; 425 + conn->cq.mcq.set_ci_db = conn->cq.wq_ctrl.db.db; 426 + conn->cq.mcq.arm_db = conn->cq.wq_ctrl.db.db + 1; 427 + *conn->cq.mcq.set_ci_db = 0; 428 + conn->cq.mcq.vector = 0; 429 + conn->cq.mcq.comp = mlx5_fpga_conn_cq_complete; 430 + 424 431 cq_size = roundup_pow_of_two(cq_size); 425 432 MLX5_SET(cqc, temp_cqc, log_cq_size, ilog2(cq_size)); 426 433 ··· 475 468 if (err) 476 469 goto err_cqwq; 477 470 478 - conn->cq.mcq.cqe_sz = 64; 479 - conn->cq.mcq.set_ci_db = conn->cq.wq_ctrl.db.db; 480 - conn->cq.mcq.arm_db = conn->cq.wq_ctrl.db.db + 1; 481 - *conn->cq.mcq.set_ci_db = 0; 482 - *conn->cq.mcq.arm_db = 0; 483 - conn->cq.mcq.vector = 0; 484 - conn->cq.mcq.comp = mlx5_fpga_conn_cq_complete; 485 471 tasklet_setup(&conn->cq.tasklet, mlx5_fpga_conn_cq_tasklet); 486 - 487 472 mlx5_fpga_dbg(fdev, "Created CQ #0x%x\n", conn->cq.mcq.cqn); 488 473 489 474 goto out;
-7
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.c
··· 873 873 return err; 874 874 } 875 875 876 - static void hws_cq_complete(struct mlx5_core_cq *mcq, 877 - struct mlx5_eqe *eqe) 878 - { 879 - pr_err("CQ completion CQ: #%u\n", mcq->cqn); 880 - } 881 - 882 876 static int hws_send_ring_alloc_cq(struct mlx5_core_dev *mdev, 883 877 int numa_node, 884 878 struct mlx5hws_send_engine *queue, ··· 895 901 mcq->cqe_sz = 64; 896 902 mcq->set_ci_db = cq->wq_ctrl.db.db; 897 903 mcq->arm_db = cq->wq_ctrl.db.db + 1; 898 - mcq->comp = hws_cq_complete; 899 904 900 905 for (i = 0; i < mlx5_cqwq_get_size(&cq->wq); i++) { 901 906 cqe = mlx5_cqwq_get_wqe(&cq->wq, i);
+7 -21
drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_send.c
··· 1049 1049 return 0; 1050 1050 } 1051 1051 1052 - static void dr_cq_complete(struct mlx5_core_cq *mcq, 1053 - struct mlx5_eqe *eqe) 1054 - { 1055 - pr_err("CQ completion CQ: #%u\n", mcq->cqn); 1056 - } 1057 - 1058 1052 static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev, 1059 1053 struct mlx5_uars_page *uar, 1060 1054 size_t ncqe) ··· 1083 1089 cqe->op_own = MLX5_CQE_INVALID << 4 | MLX5_CQE_OWNER_MASK; 1084 1090 } 1085 1091 1092 + cq->mcq.cqe_sz = 64; 1093 + cq->mcq.set_ci_db = cq->wq_ctrl.db.db; 1094 + cq->mcq.arm_db = cq->wq_ctrl.db.db + 1; 1095 + *cq->mcq.set_ci_db = 0; 1096 + cq->mcq.vector = 0; 1097 + cq->mdev = mdev; 1098 + 1086 1099 inlen = MLX5_ST_SZ_BYTES(create_cq_in) + 1087 1100 sizeof(u64) * cq->wq_ctrl.buf.npages; 1088 1101 in = kvzalloc(inlen, GFP_KERNEL); ··· 1113 1112 pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas); 1114 1113 mlx5_fill_page_frag_array(&cq->wq_ctrl.buf, pas); 1115 1114 1116 - cq->mcq.comp = dr_cq_complete; 1117 - 1118 1115 err = mlx5_core_create_cq(mdev, &cq->mcq, in, inlen, out, sizeof(out)); 1119 1116 kvfree(in); 1120 1117 1121 1118 if (err) 1122 1119 goto err_cqwq; 1123 - 1124 - cq->mcq.cqe_sz = 64; 1125 - cq->mcq.set_ci_db = cq->wq_ctrl.db.db; 1126 - cq->mcq.arm_db = cq->wq_ctrl.db.db + 1; 1127 - *cq->mcq.set_ci_db = 0; 1128 - 1129 - /* set no-zero value, in order to avoid the HW to run db-recovery on 1130 - * CQ that used in polling mode. 1131 - */ 1132 - *cq->mcq.arm_db = cpu_to_be32(2 << 28); 1133 - 1134 - cq->mcq.vector = 0; 1135 - cq->mdev = mdev; 1136 1120 1137 1121 return cq; 1138 1122
+2 -4
drivers/vdpa/mlx5/net/mlx5_vnet.c
··· 573 573 vcq->mcq.set_ci_db = vcq->db.db; 574 574 vcq->mcq.arm_db = vcq->db.db + 1; 575 575 vcq->mcq.cqe_sz = 64; 576 + vcq->mcq.comp = mlx5_vdpa_cq_comp; 577 + vcq->cqe = num_ent; 576 578 577 579 err = cq_frag_buf_alloc(ndev, &vcq->buf, num_ent); 578 580 if (err) ··· 614 612 if (err) 615 613 goto err_vec; 616 614 617 - vcq->mcq.comp = mlx5_vdpa_cq_comp; 618 - vcq->cqe = num_ent; 619 - vcq->mcq.set_ci_db = vcq->db.db; 620 - vcq->mcq.arm_db = vcq->db.db + 1; 621 615 mlx5_cq_arm(&mvq->cq.mcq, MLX5_CQ_DB_REQ_NOT, uar_page, mvq->cq.mcq.cons_index); 622 616 kfree(in); 623 617 return 0;
+1
include/linux/mlx5/cq.h
··· 183 183 complete(&cq->free); 184 184 } 185 185 186 + void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq, struct mlx5_eqe *eqe); 186 187 int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq, 187 188 u32 *in, int inlen, u32 *out, int outlen); 188 189 int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,