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

IB/mlx5: Collect signature error completion

This commit takes care of the generated signature error CQE generated
by the HW (if happened). The underlying mlx5 driver will handle
signature error completions and will mark the relevant memory region
as dirty.

Once the consumer gets the completion for the transaction, it must
check for signature errors on signature memory region using a new
lightweight verb ib_check_mr_status().

In case the user doesn't check for signature error (i.e. doesn't call
ib_check_mr_status() with status check IB_MR_CHECK_SIG_STATUS), the
memory region cannot be used for another signature operation
(REG_SIG_MR work request will fail).

Signed-off-by: Sagi Grimberg <sagig@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>

authored by

Sagi Grimberg and committed by
Roland Dreier
d5436ba0 e6631814

+150 -2
+62
drivers/infiniband/hw/mlx5/cq.c
··· 366 366 mlx5_buf_free(&dev->mdev, &buf->buf); 367 367 } 368 368 369 + static void get_sig_err_item(struct mlx5_sig_err_cqe *cqe, 370 + struct ib_sig_err *item) 371 + { 372 + u16 syndrome = be16_to_cpu(cqe->syndrome); 373 + 374 + #define GUARD_ERR (1 << 13) 375 + #define APPTAG_ERR (1 << 12) 376 + #define REFTAG_ERR (1 << 11) 377 + 378 + if (syndrome & GUARD_ERR) { 379 + item->err_type = IB_SIG_BAD_GUARD; 380 + item->expected = be32_to_cpu(cqe->expected_trans_sig) >> 16; 381 + item->actual = be32_to_cpu(cqe->actual_trans_sig) >> 16; 382 + } else 383 + if (syndrome & REFTAG_ERR) { 384 + item->err_type = IB_SIG_BAD_REFTAG; 385 + item->expected = be32_to_cpu(cqe->expected_reftag); 386 + item->actual = be32_to_cpu(cqe->actual_reftag); 387 + } else 388 + if (syndrome & APPTAG_ERR) { 389 + item->err_type = IB_SIG_BAD_APPTAG; 390 + item->expected = be32_to_cpu(cqe->expected_trans_sig) & 0xffff; 391 + item->actual = be32_to_cpu(cqe->actual_trans_sig) & 0xffff; 392 + } else { 393 + pr_err("Got signature completion error with bad syndrome %04x\n", 394 + syndrome); 395 + } 396 + 397 + item->sig_err_offset = be64_to_cpu(cqe->err_offset); 398 + item->key = be32_to_cpu(cqe->mkey); 399 + } 400 + 369 401 static int mlx5_poll_one(struct mlx5_ib_cq *cq, 370 402 struct mlx5_ib_qp **cur_qp, 371 403 struct ib_wc *wc) ··· 407 375 struct mlx5_cqe64 *cqe64; 408 376 struct mlx5_core_qp *mqp; 409 377 struct mlx5_ib_wq *wq; 378 + struct mlx5_sig_err_cqe *sig_err_cqe; 379 + struct mlx5_core_mr *mmr; 380 + struct mlx5_ib_mr *mr; 410 381 uint8_t opcode; 411 382 uint32_t qpn; 412 383 u16 wqe_ctr; ··· 510 475 } 511 476 } 512 477 break; 478 + case MLX5_CQE_SIG_ERR: 479 + sig_err_cqe = (struct mlx5_sig_err_cqe *)cqe64; 480 + 481 + read_lock(&dev->mdev.priv.mr_table.lock); 482 + mmr = __mlx5_mr_lookup(&dev->mdev, 483 + mlx5_base_mkey(be32_to_cpu(sig_err_cqe->mkey))); 484 + if (unlikely(!mmr)) { 485 + read_unlock(&dev->mdev.priv.mr_table.lock); 486 + mlx5_ib_warn(dev, "CQE@CQ %06x for unknown MR %6x\n", 487 + cq->mcq.cqn, be32_to_cpu(sig_err_cqe->mkey)); 488 + return -EINVAL; 489 + } 490 + 491 + mr = to_mibmr(mmr); 492 + get_sig_err_item(sig_err_cqe, &mr->sig->err_item); 493 + mr->sig->sig_err_exists = true; 494 + mr->sig->sigerr_count++; 495 + 496 + mlx5_ib_warn(dev, "CQN: 0x%x Got SIGERR on key: 0x%x err_type %x err_offset %llx expected %x actual %x\n", 497 + cq->mcq.cqn, mr->sig->err_item.key, 498 + mr->sig->err_item.err_type, 499 + mr->sig->err_item.sig_err_offset, 500 + mr->sig->err_item.expected, 501 + mr->sig->err_item.actual); 502 + 503 + read_unlock(&dev->mdev.priv.mr_table.lock); 504 + goto repoll; 513 505 } 514 506 515 507 return 0;
+1
drivers/infiniband/hw/mlx5/main.c
··· 1431 1431 dev->ib_dev.alloc_fast_reg_mr = mlx5_ib_alloc_fast_reg_mr; 1432 1432 dev->ib_dev.alloc_fast_reg_page_list = mlx5_ib_alloc_fast_reg_page_list; 1433 1433 dev->ib_dev.free_fast_reg_page_list = mlx5_ib_free_fast_reg_page_list; 1434 + dev->ib_dev.check_mr_status = mlx5_ib_check_mr_status; 1434 1435 1435 1436 if (mdev->caps.flags & MLX5_DEV_CAP_FLAG_XRC) { 1436 1437 dev->ib_dev.alloc_xrcd = mlx5_ib_alloc_xrcd;
+7
drivers/infiniband/hw/mlx5/mlx5_ib.h
··· 400 400 return container_of(mqp, struct mlx5_ib_qp, mqp); 401 401 } 402 402 403 + static inline struct mlx5_ib_mr *to_mibmr(struct mlx5_core_mr *mmr) 404 + { 405 + return container_of(mmr, struct mlx5_ib_mr, mmr); 406 + } 407 + 403 408 static inline struct mlx5_ib_pd *to_mpd(struct ib_pd *ibpd) 404 409 { 405 410 return container_of(ibpd, struct mlx5_ib_pd, ibpd); ··· 542 537 int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev); 543 538 int mlx5_mr_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift); 544 539 void mlx5_umr_cq_handler(struct ib_cq *cq, void *cq_context); 540 + int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask, 541 + struct ib_mr_status *mr_status); 545 542 546 543 static inline void init_query_mad(struct ib_smp *mad) 547 544 {
+46
drivers/infiniband/hw/mlx5/mr.c
··· 1038 1038 access_mode = MLX5_ACCESS_MODE_KLM; 1039 1039 mr->sig->psv_memory.psv_idx = psv_index[0]; 1040 1040 mr->sig->psv_wire.psv_idx = psv_index[1]; 1041 + 1042 + mr->sig->sig_status_checked = true; 1043 + mr->sig->sig_err_exists = false; 1044 + /* Next UMR, Arm SIGERR */ 1045 + ++mr->sig->sigerr_count; 1041 1046 } 1042 1047 1043 1048 in->seg.flags = MLX5_PERM_UMR_EN | access_mode; ··· 1192 1187 mfrpl->map); 1193 1188 kfree(mfrpl->ibfrpl.page_list); 1194 1189 kfree(mfrpl); 1190 + } 1191 + 1192 + int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask, 1193 + struct ib_mr_status *mr_status) 1194 + { 1195 + struct mlx5_ib_mr *mmr = to_mmr(ibmr); 1196 + int ret = 0; 1197 + 1198 + if (check_mask & ~IB_MR_CHECK_SIG_STATUS) { 1199 + pr_err("Invalid status check mask\n"); 1200 + ret = -EINVAL; 1201 + goto done; 1202 + } 1203 + 1204 + mr_status->fail_status = 0; 1205 + if (check_mask & IB_MR_CHECK_SIG_STATUS) { 1206 + if (!mmr->sig) { 1207 + ret = -EINVAL; 1208 + pr_err("signature status check requested on a non-signature enabled MR\n"); 1209 + goto done; 1210 + } 1211 + 1212 + mmr->sig->sig_status_checked = true; 1213 + if (!mmr->sig->sig_err_exists) 1214 + goto done; 1215 + 1216 + if (ibmr->lkey == mmr->sig->err_item.key) 1217 + memcpy(&mr_status->sig_err, &mmr->sig->err_item, 1218 + sizeof(mr_status->sig_err)); 1219 + else { 1220 + mr_status->sig_err.err_type = IB_SIG_BAD_GUARD; 1221 + mr_status->sig_err.sig_err_offset = 0; 1222 + mr_status->sig_err.key = mmr->sig->err_item.key; 1223 + } 1224 + 1225 + mmr->sig->sig_err_exists = false; 1226 + mr_status->fail_status |= IB_MR_CHECK_SIG_STATUS; 1227 + } 1228 + 1229 + done: 1230 + return ret; 1195 1231 }
+6 -2
drivers/infiniband/hw/mlx5/qp.c
··· 1784 1784 result = MLX5_MKEY_MASK_LEN | 1785 1785 MLX5_MKEY_MASK_PAGE_SIZE | 1786 1786 MLX5_MKEY_MASK_START_ADDR | 1787 + MLX5_MKEY_MASK_EN_SIGERR | 1787 1788 MLX5_MKEY_MASK_EN_RINVAL | 1788 1789 MLX5_MKEY_MASK_KEY | 1789 1790 MLX5_MKEY_MASK_LR | ··· 2220 2219 { 2221 2220 struct ib_mr *sig_mr = wr->wr.sig_handover.sig_mr; 2222 2221 u32 sig_key = sig_mr->rkey; 2222 + u8 sigerr = to_mmr(sig_mr)->sig->sigerr_count & 1; 2223 2223 2224 2224 memset(seg, 0, sizeof(*seg)); 2225 2225 2226 2226 seg->flags = get_umr_flags(wr->wr.sig_handover.access_flags) | 2227 2227 MLX5_ACCESS_MODE_KLM; 2228 2228 seg->qpn_mkey7_0 = cpu_to_be32((sig_key & 0xff) | 0xffffff00); 2229 - seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL | 2229 + seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL | sigerr << 26 | 2230 2230 MLX5_MKEY_BSF_EN | pdn); 2231 2231 seg->len = cpu_to_be64(length); 2232 2232 seg->xlt_oct_size = cpu_to_be32(be16_to_cpu(get_klm_octo(nelements))); ··· 2257 2255 if (unlikely(wr->num_sge != 1) || 2258 2256 unlikely(wr->wr.sig_handover.access_flags & 2259 2257 IB_ACCESS_REMOTE_ATOMIC) || 2260 - unlikely(!sig_mr->sig) || unlikely(!qp->signature_en)) 2258 + unlikely(!sig_mr->sig) || unlikely(!qp->signature_en) || 2259 + unlikely(!sig_mr->sig->sig_status_checked)) 2261 2260 return -EINVAL; 2262 2261 2263 2262 /* length of the protected region, data + protection */ ··· 2289 2286 if (ret) 2290 2287 return ret; 2291 2288 2289 + sig_mr->sig->sig_status_checked = false; 2292 2290 return 0; 2293 2291 } 2294 2292
+1
include/linux/mlx5/cq.h
··· 80 80 MLX5_CQE_RESP_SEND_IMM = 3, 81 81 MLX5_CQE_RESP_SEND_INV = 4, 82 82 MLX5_CQE_RESIZE_CQ = 5, 83 + MLX5_CQE_SIG_ERR = 12, 83 84 MLX5_CQE_REQ_ERR = 13, 84 85 MLX5_CQE_RESP_ERR = 14, 85 86 MLX5_CQE_INVALID = 15,
+18
include/linux/mlx5/device.h
··· 118 118 MLX5_MKEY_MASK_START_ADDR = 1ull << 6, 119 119 MLX5_MKEY_MASK_PD = 1ull << 7, 120 120 MLX5_MKEY_MASK_EN_RINVAL = 1ull << 8, 121 + MLX5_MKEY_MASK_EN_SIGERR = 1ull << 9, 121 122 MLX5_MKEY_MASK_BSF_EN = 1ull << 12, 122 123 MLX5_MKEY_MASK_KEY = 1ull << 13, 123 124 MLX5_MKEY_MASK_QPN = 1ull << 14, ··· 554 553 __be64 timestamp; 555 554 __be32 sop_drop_qpn; 556 555 __be16 wqe_counter; 556 + u8 signature; 557 + u8 op_own; 558 + }; 559 + 560 + struct mlx5_sig_err_cqe { 561 + u8 rsvd0[16]; 562 + __be32 expected_trans_sig; 563 + __be32 actual_trans_sig; 564 + __be32 expected_reftag; 565 + __be32 actual_reftag; 566 + __be16 syndrome; 567 + u8 rsvd22[2]; 568 + __be32 mkey; 569 + __be64 err_offset; 570 + u8 rsvd30[8]; 571 + __be32 qpn; 572 + u8 rsvd38[2]; 557 573 u8 signature; 558 574 u8 op_own; 559 575 };
+4
include/linux/mlx5/driver.h
··· 416 416 struct mlx5_core_sig_ctx { 417 417 struct mlx5_core_psv psv_memory; 418 418 struct mlx5_core_psv psv_wire; 419 + struct ib_sig_err err_item; 420 + bool sig_status_checked; 421 + bool sig_err_exists; 422 + u32 sigerr_count; 419 423 }; 420 424 421 425 struct mlx5_core_mr {
+5
include/linux/mlx5/qp.h
··· 506 506 return radix_tree_lookup(&dev->priv.qp_table.tree, qpn); 507 507 } 508 508 509 + static inline struct mlx5_core_mr *__mlx5_mr_lookup(struct mlx5_core_dev *dev, u32 key) 510 + { 511 + return radix_tree_lookup(&dev->priv.mr_table.tree, key); 512 + } 513 + 509 514 int mlx5_core_create_qp(struct mlx5_core_dev *dev, 510 515 struct mlx5_core_qp *qp, 511 516 struct mlx5_create_qp_mbox_in *in,