104876c12SAharon Landau // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 204876c12SAharon Landau /* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. */ 304876c12SAharon Landau 404876c12SAharon Landau #include "mlx5_ib.h" 504876c12SAharon Landau #include "umr.h" 66f0689fdSAharon Landau #include "wr.h" 704876c12SAharon Landau 8916adb49SAharon Landau /* 9916adb49SAharon Landau * We can't use an array for xlt_emergency_page because dma_map_single doesn't 10916adb49SAharon Landau * work on kernel modules memory 11916adb49SAharon Landau */ 12916adb49SAharon Landau void *xlt_emergency_page; 13916adb49SAharon Landau static DEFINE_MUTEX(xlt_emergency_page_mutex); 14916adb49SAharon Landau 158a8a5d37SAharon Landau static __be64 get_umr_enable_mr_mask(void) 168a8a5d37SAharon Landau { 178a8a5d37SAharon Landau u64 result; 188a8a5d37SAharon Landau 198a8a5d37SAharon Landau result = MLX5_MKEY_MASK_KEY | 208a8a5d37SAharon Landau MLX5_MKEY_MASK_FREE; 218a8a5d37SAharon Landau 228a8a5d37SAharon Landau return cpu_to_be64(result); 238a8a5d37SAharon Landau } 248a8a5d37SAharon Landau 258a8a5d37SAharon Landau static __be64 get_umr_disable_mr_mask(void) 268a8a5d37SAharon Landau { 278a8a5d37SAharon Landau u64 result; 288a8a5d37SAharon Landau 298a8a5d37SAharon Landau result = MLX5_MKEY_MASK_FREE; 308a8a5d37SAharon Landau 318a8a5d37SAharon Landau return cpu_to_be64(result); 328a8a5d37SAharon Landau } 338a8a5d37SAharon Landau 348a8a5d37SAharon Landau static __be64 get_umr_update_translation_mask(void) 358a8a5d37SAharon Landau { 368a8a5d37SAharon Landau u64 result; 378a8a5d37SAharon Landau 388a8a5d37SAharon Landau result = MLX5_MKEY_MASK_LEN | 398a8a5d37SAharon Landau MLX5_MKEY_MASK_PAGE_SIZE | 408a8a5d37SAharon Landau MLX5_MKEY_MASK_START_ADDR; 418a8a5d37SAharon Landau 428a8a5d37SAharon Landau return cpu_to_be64(result); 438a8a5d37SAharon Landau } 448a8a5d37SAharon Landau 45ba6a9c68SAharon Landau static __be64 get_umr_update_access_mask(struct mlx5_ib_dev *dev) 468a8a5d37SAharon Landau { 478a8a5d37SAharon Landau u64 result; 488a8a5d37SAharon Landau 498a8a5d37SAharon Landau result = MLX5_MKEY_MASK_LR | 508a8a5d37SAharon Landau MLX5_MKEY_MASK_LW | 518a8a5d37SAharon Landau MLX5_MKEY_MASK_RR | 528a8a5d37SAharon Landau MLX5_MKEY_MASK_RW; 538a8a5d37SAharon Landau 54ba6a9c68SAharon Landau if (MLX5_CAP_GEN(dev->mdev, atomic)) 558a8a5d37SAharon Landau result |= MLX5_MKEY_MASK_A; 568a8a5d37SAharon Landau 57ba6a9c68SAharon Landau if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write_umr)) 588a8a5d37SAharon Landau result |= MLX5_MKEY_MASK_RELAXED_ORDERING_WRITE; 598a8a5d37SAharon Landau 60ba6a9c68SAharon Landau if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read_umr)) 618a8a5d37SAharon Landau result |= MLX5_MKEY_MASK_RELAXED_ORDERING_READ; 628a8a5d37SAharon Landau 638a8a5d37SAharon Landau return cpu_to_be64(result); 648a8a5d37SAharon Landau } 658a8a5d37SAharon Landau 668a8a5d37SAharon Landau static __be64 get_umr_update_pd_mask(void) 678a8a5d37SAharon Landau { 688a8a5d37SAharon Landau u64 result; 698a8a5d37SAharon Landau 708a8a5d37SAharon Landau result = MLX5_MKEY_MASK_PD; 718a8a5d37SAharon Landau 728a8a5d37SAharon Landau return cpu_to_be64(result); 738a8a5d37SAharon Landau } 748a8a5d37SAharon Landau 758a8a5d37SAharon Landau static int umr_check_mkey_mask(struct mlx5_ib_dev *dev, u64 mask) 768a8a5d37SAharon Landau { 778a8a5d37SAharon Landau if (mask & MLX5_MKEY_MASK_PAGE_SIZE && 788a8a5d37SAharon Landau MLX5_CAP_GEN(dev->mdev, umr_modify_entity_size_disabled)) 798a8a5d37SAharon Landau return -EPERM; 808a8a5d37SAharon Landau 818a8a5d37SAharon Landau if (mask & MLX5_MKEY_MASK_A && 828a8a5d37SAharon Landau MLX5_CAP_GEN(dev->mdev, umr_modify_atomic_disabled)) 838a8a5d37SAharon Landau return -EPERM; 848a8a5d37SAharon Landau 858a8a5d37SAharon Landau if (mask & MLX5_MKEY_MASK_RELAXED_ORDERING_WRITE && 868a8a5d37SAharon Landau !MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write_umr)) 878a8a5d37SAharon Landau return -EPERM; 888a8a5d37SAharon Landau 898a8a5d37SAharon Landau if (mask & MLX5_MKEY_MASK_RELAXED_ORDERING_READ && 908a8a5d37SAharon Landau !MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read_umr)) 918a8a5d37SAharon Landau return -EPERM; 928a8a5d37SAharon Landau 938a8a5d37SAharon Landau return 0; 948a8a5d37SAharon Landau } 958a8a5d37SAharon Landau 968a8a5d37SAharon Landau int mlx5r_umr_set_umr_ctrl_seg(struct mlx5_ib_dev *dev, 978a8a5d37SAharon Landau struct mlx5_wqe_umr_ctrl_seg *umr, 988a8a5d37SAharon Landau const struct ib_send_wr *wr) 998a8a5d37SAharon Landau { 1008a8a5d37SAharon Landau const struct mlx5_umr_wr *umrwr = umr_wr(wr); 1018a8a5d37SAharon Landau 1028a8a5d37SAharon Landau memset(umr, 0, sizeof(*umr)); 1038a8a5d37SAharon Landau 1048a8a5d37SAharon Landau if (!umrwr->ignore_free_state) { 1058a8a5d37SAharon Landau if (wr->send_flags & MLX5_IB_SEND_UMR_FAIL_IF_FREE) 1068a8a5d37SAharon Landau /* fail if free */ 1078a8a5d37SAharon Landau umr->flags = MLX5_UMR_CHECK_FREE; 1088a8a5d37SAharon Landau else 1098a8a5d37SAharon Landau /* fail if not free */ 1108a8a5d37SAharon Landau umr->flags = MLX5_UMR_CHECK_NOT_FREE; 1118a8a5d37SAharon Landau } 1128a8a5d37SAharon Landau 1138a8a5d37SAharon Landau umr->xlt_octowords = 1148a8a5d37SAharon Landau cpu_to_be16(mlx5r_umr_get_xlt_octo(umrwr->xlt_size)); 1158a8a5d37SAharon Landau if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_XLT) { 1168a8a5d37SAharon Landau u64 offset = mlx5r_umr_get_xlt_octo(umrwr->offset); 1178a8a5d37SAharon Landau 1188a8a5d37SAharon Landau umr->xlt_offset = cpu_to_be16(offset & 0xffff); 1198a8a5d37SAharon Landau umr->xlt_offset_47_16 = cpu_to_be32(offset >> 16); 1208a8a5d37SAharon Landau umr->flags |= MLX5_UMR_TRANSLATION_OFFSET_EN; 1218a8a5d37SAharon Landau } 1228a8a5d37SAharon Landau if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_TRANSLATION) 1238a8a5d37SAharon Landau umr->mkey_mask |= get_umr_update_translation_mask(); 1248a8a5d37SAharon Landau if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_PD_ACCESS) { 125ba6a9c68SAharon Landau umr->mkey_mask |= get_umr_update_access_mask(dev); 1268a8a5d37SAharon Landau umr->mkey_mask |= get_umr_update_pd_mask(); 1278a8a5d37SAharon Landau } 1288a8a5d37SAharon Landau if (wr->send_flags & MLX5_IB_SEND_UMR_ENABLE_MR) 1298a8a5d37SAharon Landau umr->mkey_mask |= get_umr_enable_mr_mask(); 1308a8a5d37SAharon Landau if (wr->send_flags & MLX5_IB_SEND_UMR_DISABLE_MR) 1318a8a5d37SAharon Landau umr->mkey_mask |= get_umr_disable_mr_mask(); 1328a8a5d37SAharon Landau 1338a8a5d37SAharon Landau if (!wr->num_sge) 1348a8a5d37SAharon Landau umr->flags |= MLX5_UMR_INLINE; 1358a8a5d37SAharon Landau 1368a8a5d37SAharon Landau return umr_check_mkey_mask(dev, be64_to_cpu(umr->mkey_mask)); 1378a8a5d37SAharon Landau } 1388a8a5d37SAharon Landau 13904876c12SAharon Landau enum { 14004876c12SAharon Landau MAX_UMR_WR = 128, 14104876c12SAharon Landau }; 14204876c12SAharon Landau 14304876c12SAharon Landau static int mlx5r_umr_qp_rst2rts(struct mlx5_ib_dev *dev, struct ib_qp *qp) 14404876c12SAharon Landau { 14504876c12SAharon Landau struct ib_qp_attr attr = {}; 14604876c12SAharon Landau int ret; 14704876c12SAharon Landau 14804876c12SAharon Landau attr.qp_state = IB_QPS_INIT; 14904876c12SAharon Landau attr.port_num = 1; 15004876c12SAharon Landau ret = ib_modify_qp(qp, &attr, 15104876c12SAharon Landau IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT); 15204876c12SAharon Landau if (ret) { 15304876c12SAharon Landau mlx5_ib_dbg(dev, "Couldn't modify UMR QP\n"); 15404876c12SAharon Landau return ret; 15504876c12SAharon Landau } 15604876c12SAharon Landau 15704876c12SAharon Landau memset(&attr, 0, sizeof(attr)); 15804876c12SAharon Landau attr.qp_state = IB_QPS_RTR; 15904876c12SAharon Landau 16004876c12SAharon Landau ret = ib_modify_qp(qp, &attr, IB_QP_STATE); 16104876c12SAharon Landau if (ret) { 16204876c12SAharon Landau mlx5_ib_dbg(dev, "Couldn't modify umr QP to rtr\n"); 16304876c12SAharon Landau return ret; 16404876c12SAharon Landau } 16504876c12SAharon Landau 16604876c12SAharon Landau memset(&attr, 0, sizeof(attr)); 16704876c12SAharon Landau attr.qp_state = IB_QPS_RTS; 16804876c12SAharon Landau ret = ib_modify_qp(qp, &attr, IB_QP_STATE); 16904876c12SAharon Landau if (ret) { 17004876c12SAharon Landau mlx5_ib_dbg(dev, "Couldn't modify umr QP to rts\n"); 17104876c12SAharon Landau return ret; 17204876c12SAharon Landau } 17304876c12SAharon Landau 17404876c12SAharon Landau return 0; 17504876c12SAharon Landau } 17604876c12SAharon Landau 17704876c12SAharon Landau int mlx5r_umr_resource_init(struct mlx5_ib_dev *dev) 17804876c12SAharon Landau { 17904876c12SAharon Landau struct ib_qp_init_attr init_attr = {}; 18004876c12SAharon Landau struct ib_pd *pd; 18104876c12SAharon Landau struct ib_cq *cq; 18204876c12SAharon Landau struct ib_qp *qp; 18304876c12SAharon Landau int ret; 18404876c12SAharon Landau 18504876c12SAharon Landau pd = ib_alloc_pd(&dev->ib_dev, 0); 18604876c12SAharon Landau if (IS_ERR(pd)) { 18704876c12SAharon Landau mlx5_ib_dbg(dev, "Couldn't create PD for sync UMR QP\n"); 18804876c12SAharon Landau return PTR_ERR(pd); 18904876c12SAharon Landau } 19004876c12SAharon Landau 19104876c12SAharon Landau cq = ib_alloc_cq(&dev->ib_dev, NULL, 128, 0, IB_POLL_SOFTIRQ); 19204876c12SAharon Landau if (IS_ERR(cq)) { 19304876c12SAharon Landau mlx5_ib_dbg(dev, "Couldn't create CQ for sync UMR QP\n"); 19404876c12SAharon Landau ret = PTR_ERR(cq); 19504876c12SAharon Landau goto destroy_pd; 19604876c12SAharon Landau } 19704876c12SAharon Landau 19804876c12SAharon Landau init_attr.send_cq = cq; 19904876c12SAharon Landau init_attr.recv_cq = cq; 20004876c12SAharon Landau init_attr.sq_sig_type = IB_SIGNAL_ALL_WR; 20104876c12SAharon Landau init_attr.cap.max_send_wr = MAX_UMR_WR; 20204876c12SAharon Landau init_attr.cap.max_send_sge = 1; 20304876c12SAharon Landau init_attr.qp_type = MLX5_IB_QPT_REG_UMR; 20404876c12SAharon Landau init_attr.port_num = 1; 20504876c12SAharon Landau qp = ib_create_qp(pd, &init_attr); 20604876c12SAharon Landau if (IS_ERR(qp)) { 20704876c12SAharon Landau mlx5_ib_dbg(dev, "Couldn't create sync UMR QP\n"); 20804876c12SAharon Landau ret = PTR_ERR(qp); 20904876c12SAharon Landau goto destroy_cq; 21004876c12SAharon Landau } 21104876c12SAharon Landau 21204876c12SAharon Landau ret = mlx5r_umr_qp_rst2rts(dev, qp); 21304876c12SAharon Landau if (ret) 21404876c12SAharon Landau goto destroy_qp; 21504876c12SAharon Landau 21604876c12SAharon Landau dev->umrc.qp = qp; 21704876c12SAharon Landau dev->umrc.cq = cq; 21804876c12SAharon Landau dev->umrc.pd = pd; 21904876c12SAharon Landau 22004876c12SAharon Landau sema_init(&dev->umrc.sem, MAX_UMR_WR); 22104876c12SAharon Landau 22204876c12SAharon Landau return 0; 22304876c12SAharon Landau 22404876c12SAharon Landau destroy_qp: 22504876c12SAharon Landau ib_destroy_qp(qp); 22604876c12SAharon Landau destroy_cq: 22704876c12SAharon Landau ib_free_cq(cq); 22804876c12SAharon Landau destroy_pd: 22904876c12SAharon Landau ib_dealloc_pd(pd); 23004876c12SAharon Landau return ret; 23104876c12SAharon Landau } 23204876c12SAharon Landau 23304876c12SAharon Landau void mlx5r_umr_resource_cleanup(struct mlx5_ib_dev *dev) 23404876c12SAharon Landau { 23504876c12SAharon Landau ib_destroy_qp(dev->umrc.qp); 23604876c12SAharon Landau ib_free_cq(dev->umrc.cq); 23704876c12SAharon Landau ib_dealloc_pd(dev->umrc.pd); 23804876c12SAharon Landau } 2396f0689fdSAharon Landau 2406f0689fdSAharon Landau static int mlx5r_umr_post_send(struct ib_qp *ibqp, u32 mkey, struct ib_cqe *cqe, 2416f0689fdSAharon Landau struct mlx5r_umr_wqe *wqe, bool with_data) 2426f0689fdSAharon Landau { 2436f0689fdSAharon Landau unsigned int wqe_size = 2446f0689fdSAharon Landau with_data ? sizeof(struct mlx5r_umr_wqe) : 2456f0689fdSAharon Landau sizeof(struct mlx5r_umr_wqe) - 2466f0689fdSAharon Landau sizeof(struct mlx5_wqe_data_seg); 2476f0689fdSAharon Landau struct mlx5_ib_dev *dev = to_mdev(ibqp->device); 2486f0689fdSAharon Landau struct mlx5_core_dev *mdev = dev->mdev; 2496f0689fdSAharon Landau struct mlx5_ib_qp *qp = to_mqp(ibqp); 2506f0689fdSAharon Landau struct mlx5_wqe_ctrl_seg *ctrl; 2516f0689fdSAharon Landau union { 2526f0689fdSAharon Landau struct ib_cqe *ib_cqe; 2536f0689fdSAharon Landau u64 wr_id; 2546f0689fdSAharon Landau } id; 2556f0689fdSAharon Landau void *cur_edge, *seg; 2566f0689fdSAharon Landau unsigned long flags; 2576f0689fdSAharon Landau unsigned int idx; 2586f0689fdSAharon Landau int size, err; 2596f0689fdSAharon Landau 2606f0689fdSAharon Landau if (unlikely(mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)) 2616f0689fdSAharon Landau return -EIO; 2626f0689fdSAharon Landau 2636f0689fdSAharon Landau spin_lock_irqsave(&qp->sq.lock, flags); 2646f0689fdSAharon Landau 2656f0689fdSAharon Landau err = mlx5r_begin_wqe(qp, &seg, &ctrl, &idx, &size, &cur_edge, 0, 2666f0689fdSAharon Landau cpu_to_be32(mkey), false, false); 2676f0689fdSAharon Landau if (WARN_ON(err)) 2686f0689fdSAharon Landau goto out; 2696f0689fdSAharon Landau 2706f0689fdSAharon Landau qp->sq.wr_data[idx] = MLX5_IB_WR_UMR; 2716f0689fdSAharon Landau 2726f0689fdSAharon Landau mlx5r_memcpy_send_wqe(&qp->sq, &cur_edge, &seg, &size, wqe, wqe_size); 2736f0689fdSAharon Landau 2746f0689fdSAharon Landau id.ib_cqe = cqe; 2756f0689fdSAharon Landau mlx5r_finish_wqe(qp, ctrl, seg, size, cur_edge, idx, id.wr_id, 0, 2766f0689fdSAharon Landau MLX5_FENCE_MODE_NONE, MLX5_OPCODE_UMR); 2776f0689fdSAharon Landau 2786f0689fdSAharon Landau mlx5r_ring_db(qp, 1, ctrl); 2796f0689fdSAharon Landau 2806f0689fdSAharon Landau out: 2816f0689fdSAharon Landau spin_unlock_irqrestore(&qp->sq.lock, flags); 2826f0689fdSAharon Landau 2836f0689fdSAharon Landau return err; 2846f0689fdSAharon Landau } 2856f0689fdSAharon Landau 2866f0689fdSAharon Landau static void mlx5r_umr_done(struct ib_cq *cq, struct ib_wc *wc) 2876f0689fdSAharon Landau { 2886f0689fdSAharon Landau struct mlx5_ib_umr_context *context = 2896f0689fdSAharon Landau container_of(wc->wr_cqe, struct mlx5_ib_umr_context, cqe); 2906f0689fdSAharon Landau 2916f0689fdSAharon Landau context->status = wc->status; 2926f0689fdSAharon Landau complete(&context->done); 2936f0689fdSAharon Landau } 2946f0689fdSAharon Landau 2956f0689fdSAharon Landau static inline void mlx5r_umr_init_context(struct mlx5r_umr_context *context) 2966f0689fdSAharon Landau { 2976f0689fdSAharon Landau context->cqe.done = mlx5r_umr_done; 2986f0689fdSAharon Landau init_completion(&context->done); 2996f0689fdSAharon Landau } 3006f0689fdSAharon Landau 3016f0689fdSAharon Landau static int mlx5r_umr_post_send_wait(struct mlx5_ib_dev *dev, u32 mkey, 3026f0689fdSAharon Landau struct mlx5r_umr_wqe *wqe, bool with_data) 3036f0689fdSAharon Landau { 3046f0689fdSAharon Landau struct umr_common *umrc = &dev->umrc; 3056f0689fdSAharon Landau struct mlx5r_umr_context umr_context; 3066f0689fdSAharon Landau int err; 3076f0689fdSAharon Landau 3086f0689fdSAharon Landau err = umr_check_mkey_mask(dev, be64_to_cpu(wqe->ctrl_seg.mkey_mask)); 3096f0689fdSAharon Landau if (WARN_ON(err)) 3106f0689fdSAharon Landau return err; 3116f0689fdSAharon Landau 3126f0689fdSAharon Landau mlx5r_umr_init_context(&umr_context); 3136f0689fdSAharon Landau 3146f0689fdSAharon Landau down(&umrc->sem); 3156f0689fdSAharon Landau err = mlx5r_umr_post_send(umrc->qp, mkey, &umr_context.cqe, wqe, 3166f0689fdSAharon Landau with_data); 3176f0689fdSAharon Landau if (err) 3186f0689fdSAharon Landau mlx5_ib_warn(dev, "UMR post send failed, err %d\n", err); 3196f0689fdSAharon Landau else { 3206f0689fdSAharon Landau wait_for_completion(&umr_context.done); 3216f0689fdSAharon Landau if (umr_context.status != IB_WC_SUCCESS) { 3226f0689fdSAharon Landau mlx5_ib_warn(dev, "reg umr failed (%u)\n", 3236f0689fdSAharon Landau umr_context.status); 3246f0689fdSAharon Landau err = -EFAULT; 3256f0689fdSAharon Landau } 3266f0689fdSAharon Landau } 3276f0689fdSAharon Landau up(&umrc->sem); 3286f0689fdSAharon Landau return err; 3296f0689fdSAharon Landau } 33033e8aa8eSAharon Landau 33133e8aa8eSAharon Landau /** 33233e8aa8eSAharon Landau * mlx5r_umr_revoke_mr - Fence all DMA on the MR 33333e8aa8eSAharon Landau * @mr: The MR to fence 33433e8aa8eSAharon Landau * 33533e8aa8eSAharon Landau * Upon return the NIC will not be doing any DMA to the pages under the MR, 33633e8aa8eSAharon Landau * and any DMA in progress will be completed. Failure of this function 33733e8aa8eSAharon Landau * indicates the HW has failed catastrophically. 33833e8aa8eSAharon Landau */ 33933e8aa8eSAharon Landau int mlx5r_umr_revoke_mr(struct mlx5_ib_mr *mr) 34033e8aa8eSAharon Landau { 34133e8aa8eSAharon Landau struct mlx5_ib_dev *dev = mr_to_mdev(mr); 34233e8aa8eSAharon Landau struct mlx5r_umr_wqe wqe = {}; 34333e8aa8eSAharon Landau 34433e8aa8eSAharon Landau if (dev->mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) 34533e8aa8eSAharon Landau return 0; 34633e8aa8eSAharon Landau 34733e8aa8eSAharon Landau wqe.ctrl_seg.mkey_mask |= get_umr_update_pd_mask(); 34833e8aa8eSAharon Landau wqe.ctrl_seg.mkey_mask |= get_umr_disable_mr_mask(); 34933e8aa8eSAharon Landau wqe.ctrl_seg.flags |= MLX5_UMR_INLINE; 35033e8aa8eSAharon Landau 35133e8aa8eSAharon Landau MLX5_SET(mkc, &wqe.mkey_seg, free, 1); 35233e8aa8eSAharon Landau MLX5_SET(mkc, &wqe.mkey_seg, pd, to_mpd(dev->umrc.pd)->pdn); 35333e8aa8eSAharon Landau MLX5_SET(mkc, &wqe.mkey_seg, qpn, 0xffffff); 35433e8aa8eSAharon Landau MLX5_SET(mkc, &wqe.mkey_seg, mkey_7_0, 35533e8aa8eSAharon Landau mlx5_mkey_variant(mr->mmkey.key)); 35633e8aa8eSAharon Landau 35733e8aa8eSAharon Landau return mlx5r_umr_post_send_wait(dev, mr->mmkey.key, &wqe, false); 35833e8aa8eSAharon Landau } 35948319676SAharon Landau 36048319676SAharon Landau static void mlx5r_umr_set_access_flags(struct mlx5_ib_dev *dev, 36148319676SAharon Landau struct mlx5_mkey_seg *seg, 36248319676SAharon Landau unsigned int access_flags) 36348319676SAharon Landau { 36448319676SAharon Landau MLX5_SET(mkc, seg, a, !!(access_flags & IB_ACCESS_REMOTE_ATOMIC)); 36548319676SAharon Landau MLX5_SET(mkc, seg, rw, !!(access_flags & IB_ACCESS_REMOTE_WRITE)); 36648319676SAharon Landau MLX5_SET(mkc, seg, rr, !!(access_flags & IB_ACCESS_REMOTE_READ)); 36748319676SAharon Landau MLX5_SET(mkc, seg, lw, !!(access_flags & IB_ACCESS_LOCAL_WRITE)); 36848319676SAharon Landau MLX5_SET(mkc, seg, lr, 1); 36948319676SAharon Landau MLX5_SET(mkc, seg, relaxed_ordering_write, 37048319676SAharon Landau !!(access_flags & IB_ACCESS_RELAXED_ORDERING)); 37148319676SAharon Landau MLX5_SET(mkc, seg, relaxed_ordering_read, 37248319676SAharon Landau !!(access_flags & IB_ACCESS_RELAXED_ORDERING)); 37348319676SAharon Landau } 37448319676SAharon Landau 37548319676SAharon Landau int mlx5r_umr_rereg_pd_access(struct mlx5_ib_mr *mr, struct ib_pd *pd, 37648319676SAharon Landau int access_flags) 37748319676SAharon Landau { 37848319676SAharon Landau struct mlx5_ib_dev *dev = mr_to_mdev(mr); 37948319676SAharon Landau struct mlx5r_umr_wqe wqe = {}; 38048319676SAharon Landau int err; 38148319676SAharon Landau 38248319676SAharon Landau wqe.ctrl_seg.mkey_mask = get_umr_update_access_mask(dev); 38348319676SAharon Landau wqe.ctrl_seg.mkey_mask |= get_umr_update_pd_mask(); 38448319676SAharon Landau wqe.ctrl_seg.flags = MLX5_UMR_CHECK_FREE; 38548319676SAharon Landau wqe.ctrl_seg.flags |= MLX5_UMR_INLINE; 38648319676SAharon Landau 38748319676SAharon Landau mlx5r_umr_set_access_flags(dev, &wqe.mkey_seg, access_flags); 38848319676SAharon Landau MLX5_SET(mkc, &wqe.mkey_seg, pd, to_mpd(pd)->pdn); 38948319676SAharon Landau MLX5_SET(mkc, &wqe.mkey_seg, qpn, 0xffffff); 39048319676SAharon Landau MLX5_SET(mkc, &wqe.mkey_seg, mkey_7_0, 39148319676SAharon Landau mlx5_mkey_variant(mr->mmkey.key)); 39248319676SAharon Landau 39348319676SAharon Landau err = mlx5r_umr_post_send_wait(dev, mr->mmkey.key, &wqe, false); 39448319676SAharon Landau if (err) 39548319676SAharon Landau return err; 39648319676SAharon Landau 39748319676SAharon Landau mr->access_flags = access_flags; 39848319676SAharon Landau return 0; 39948319676SAharon Landau } 400916adb49SAharon Landau 401916adb49SAharon Landau #define MLX5_MAX_UMR_CHUNK \ 402916adb49SAharon Landau ((1 << (MLX5_MAX_UMR_SHIFT + 4)) - MLX5_UMR_MTT_ALIGNMENT) 403916adb49SAharon Landau #define MLX5_SPARE_UMR_CHUNK 0x10000 404916adb49SAharon Landau 405916adb49SAharon Landau /* 406916adb49SAharon Landau * Allocate a temporary buffer to hold the per-page information to transfer to 407916adb49SAharon Landau * HW. For efficiency this should be as large as it can be, but buffer 408916adb49SAharon Landau * allocation failure is not allowed, so try smaller sizes. 409916adb49SAharon Landau */ 410916adb49SAharon Landau static void *mlx5r_umr_alloc_xlt(size_t *nents, size_t ent_size, gfp_t gfp_mask) 411916adb49SAharon Landau { 412916adb49SAharon Landau const size_t xlt_chunk_align = MLX5_UMR_MTT_ALIGNMENT / ent_size; 413916adb49SAharon Landau size_t size; 414916adb49SAharon Landau void *res = NULL; 415916adb49SAharon Landau 416916adb49SAharon Landau static_assert(PAGE_SIZE % MLX5_UMR_MTT_ALIGNMENT == 0); 417916adb49SAharon Landau 418916adb49SAharon Landau /* 419916adb49SAharon Landau * MLX5_IB_UPD_XLT_ATOMIC doesn't signal an atomic context just that the 420916adb49SAharon Landau * allocation can't trigger any kind of reclaim. 421916adb49SAharon Landau */ 422916adb49SAharon Landau might_sleep(); 423916adb49SAharon Landau 424916adb49SAharon Landau gfp_mask |= __GFP_ZERO | __GFP_NORETRY; 425916adb49SAharon Landau 426916adb49SAharon Landau /* 427916adb49SAharon Landau * If the system already has a suitable high order page then just use 428916adb49SAharon Landau * that, but don't try hard to create one. This max is about 1M, so a 429916adb49SAharon Landau * free x86 huge page will satisfy it. 430916adb49SAharon Landau */ 431916adb49SAharon Landau size = min_t(size_t, ent_size * ALIGN(*nents, xlt_chunk_align), 432916adb49SAharon Landau MLX5_MAX_UMR_CHUNK); 433916adb49SAharon Landau *nents = size / ent_size; 434916adb49SAharon Landau res = (void *)__get_free_pages(gfp_mask | __GFP_NOWARN, 435916adb49SAharon Landau get_order(size)); 436916adb49SAharon Landau if (res) 437916adb49SAharon Landau return res; 438916adb49SAharon Landau 439916adb49SAharon Landau if (size > MLX5_SPARE_UMR_CHUNK) { 440916adb49SAharon Landau size = MLX5_SPARE_UMR_CHUNK; 441916adb49SAharon Landau *nents = size / ent_size; 442916adb49SAharon Landau res = (void *)__get_free_pages(gfp_mask | __GFP_NOWARN, 443916adb49SAharon Landau get_order(size)); 444916adb49SAharon Landau if (res) 445916adb49SAharon Landau return res; 446916adb49SAharon Landau } 447916adb49SAharon Landau 448916adb49SAharon Landau *nents = PAGE_SIZE / ent_size; 449916adb49SAharon Landau res = (void *)__get_free_page(gfp_mask); 450916adb49SAharon Landau if (res) 451916adb49SAharon Landau return res; 452916adb49SAharon Landau 453916adb49SAharon Landau mutex_lock(&xlt_emergency_page_mutex); 454916adb49SAharon Landau memset(xlt_emergency_page, 0, PAGE_SIZE); 455916adb49SAharon Landau return xlt_emergency_page; 456916adb49SAharon Landau } 457916adb49SAharon Landau 458916adb49SAharon Landau static void mlx5r_umr_free_xlt(void *xlt, size_t length) 459916adb49SAharon Landau { 460916adb49SAharon Landau if (xlt == xlt_emergency_page) { 461916adb49SAharon Landau mutex_unlock(&xlt_emergency_page_mutex); 462916adb49SAharon Landau return; 463916adb49SAharon Landau } 464916adb49SAharon Landau 465916adb49SAharon Landau free_pages((unsigned long)xlt, get_order(length)); 466916adb49SAharon Landau } 467916adb49SAharon Landau 468916adb49SAharon Landau void mlx5r_umr_unmap_free_xlt(struct mlx5_ib_dev *dev, void *xlt, 469916adb49SAharon Landau struct ib_sge *sg) 470916adb49SAharon Landau { 471916adb49SAharon Landau struct device *ddev = &dev->mdev->pdev->dev; 472916adb49SAharon Landau 473916adb49SAharon Landau dma_unmap_single(ddev, sg->addr, sg->length, DMA_TO_DEVICE); 474916adb49SAharon Landau mlx5r_umr_free_xlt(xlt, sg->length); 475916adb49SAharon Landau } 476916adb49SAharon Landau 477916adb49SAharon Landau /* 478916adb49SAharon Landau * Create an XLT buffer ready for submission. 479916adb49SAharon Landau */ 480916adb49SAharon Landau void *mlx5r_umr_create_xlt(struct mlx5_ib_dev *dev, struct ib_sge *sg, 481916adb49SAharon Landau size_t nents, size_t ent_size, unsigned int flags) 482916adb49SAharon Landau { 483916adb49SAharon Landau struct device *ddev = &dev->mdev->pdev->dev; 484916adb49SAharon Landau dma_addr_t dma; 485916adb49SAharon Landau void *xlt; 486916adb49SAharon Landau 487916adb49SAharon Landau xlt = mlx5r_umr_alloc_xlt(&nents, ent_size, 488916adb49SAharon Landau flags & MLX5_IB_UPD_XLT_ATOMIC ? GFP_ATOMIC : 489916adb49SAharon Landau GFP_KERNEL); 490916adb49SAharon Landau sg->length = nents * ent_size; 491916adb49SAharon Landau dma = dma_map_single(ddev, xlt, sg->length, DMA_TO_DEVICE); 492916adb49SAharon Landau if (dma_mapping_error(ddev, dma)) { 493916adb49SAharon Landau mlx5_ib_err(dev, "unable to map DMA during XLT update.\n"); 494916adb49SAharon Landau mlx5r_umr_free_xlt(xlt, sg->length); 495916adb49SAharon Landau return NULL; 496916adb49SAharon Landau } 497916adb49SAharon Landau sg->addr = dma; 498916adb49SAharon Landau sg->lkey = dev->umrc.pd->local_dma_lkey; 499916adb49SAharon Landau 500916adb49SAharon Landau return xlt; 501916adb49SAharon Landau } 502*b3d47ebdSAharon Landau 503*b3d47ebdSAharon Landau static void 504*b3d47ebdSAharon Landau mlx5r_umr_set_update_xlt_ctrl_seg(struct mlx5_wqe_umr_ctrl_seg *ctrl_seg, 505*b3d47ebdSAharon Landau unsigned int flags, struct ib_sge *sg) 506*b3d47ebdSAharon Landau { 507*b3d47ebdSAharon Landau if (!(flags & MLX5_IB_UPD_XLT_ENABLE)) 508*b3d47ebdSAharon Landau /* fail if free */ 509*b3d47ebdSAharon Landau ctrl_seg->flags = MLX5_UMR_CHECK_FREE; 510*b3d47ebdSAharon Landau else 511*b3d47ebdSAharon Landau /* fail if not free */ 512*b3d47ebdSAharon Landau ctrl_seg->flags = MLX5_UMR_CHECK_NOT_FREE; 513*b3d47ebdSAharon Landau ctrl_seg->xlt_octowords = 514*b3d47ebdSAharon Landau cpu_to_be16(mlx5r_umr_get_xlt_octo(sg->length)); 515*b3d47ebdSAharon Landau } 516*b3d47ebdSAharon Landau 517*b3d47ebdSAharon Landau static void mlx5r_umr_set_update_xlt_mkey_seg(struct mlx5_ib_dev *dev, 518*b3d47ebdSAharon Landau struct mlx5_mkey_seg *mkey_seg, 519*b3d47ebdSAharon Landau struct mlx5_ib_mr *mr, 520*b3d47ebdSAharon Landau unsigned int page_shift) 521*b3d47ebdSAharon Landau { 522*b3d47ebdSAharon Landau mlx5r_umr_set_access_flags(dev, mkey_seg, mr->access_flags); 523*b3d47ebdSAharon Landau MLX5_SET(mkc, mkey_seg, pd, to_mpd(mr->ibmr.pd)->pdn); 524*b3d47ebdSAharon Landau MLX5_SET64(mkc, mkey_seg, start_addr, mr->ibmr.iova); 525*b3d47ebdSAharon Landau MLX5_SET64(mkc, mkey_seg, len, mr->ibmr.length); 526*b3d47ebdSAharon Landau MLX5_SET(mkc, mkey_seg, log_page_size, page_shift); 527*b3d47ebdSAharon Landau MLX5_SET(mkc, mkey_seg, qpn, 0xffffff); 528*b3d47ebdSAharon Landau MLX5_SET(mkc, mkey_seg, mkey_7_0, mlx5_mkey_variant(mr->mmkey.key)); 529*b3d47ebdSAharon Landau } 530*b3d47ebdSAharon Landau 531*b3d47ebdSAharon Landau static void 532*b3d47ebdSAharon Landau mlx5r_umr_set_update_xlt_data_seg(struct mlx5_wqe_data_seg *data_seg, 533*b3d47ebdSAharon Landau struct ib_sge *sg) 534*b3d47ebdSAharon Landau { 535*b3d47ebdSAharon Landau data_seg->byte_count = cpu_to_be32(sg->length); 536*b3d47ebdSAharon Landau data_seg->lkey = cpu_to_be32(sg->lkey); 537*b3d47ebdSAharon Landau data_seg->addr = cpu_to_be64(sg->addr); 538*b3d47ebdSAharon Landau } 539*b3d47ebdSAharon Landau 540*b3d47ebdSAharon Landau static void mlx5r_umr_update_offset(struct mlx5_wqe_umr_ctrl_seg *ctrl_seg, 541*b3d47ebdSAharon Landau u64 offset) 542*b3d47ebdSAharon Landau { 543*b3d47ebdSAharon Landau u64 octo_offset = mlx5r_umr_get_xlt_octo(offset); 544*b3d47ebdSAharon Landau 545*b3d47ebdSAharon Landau ctrl_seg->xlt_offset = cpu_to_be16(octo_offset & 0xffff); 546*b3d47ebdSAharon Landau ctrl_seg->xlt_offset_47_16 = cpu_to_be32(octo_offset >> 16); 547*b3d47ebdSAharon Landau ctrl_seg->flags |= MLX5_UMR_TRANSLATION_OFFSET_EN; 548*b3d47ebdSAharon Landau } 549*b3d47ebdSAharon Landau 550*b3d47ebdSAharon Landau static void mlx5r_umr_final_update_xlt(struct mlx5_ib_dev *dev, 551*b3d47ebdSAharon Landau struct mlx5r_umr_wqe *wqe, 552*b3d47ebdSAharon Landau struct mlx5_ib_mr *mr, struct ib_sge *sg, 553*b3d47ebdSAharon Landau unsigned int flags) 554*b3d47ebdSAharon Landau { 555*b3d47ebdSAharon Landau bool update_pd_access, update_translation; 556*b3d47ebdSAharon Landau 557*b3d47ebdSAharon Landau if (flags & MLX5_IB_UPD_XLT_ENABLE) 558*b3d47ebdSAharon Landau wqe->ctrl_seg.mkey_mask |= get_umr_enable_mr_mask(); 559*b3d47ebdSAharon Landau 560*b3d47ebdSAharon Landau update_pd_access = flags & MLX5_IB_UPD_XLT_ENABLE || 561*b3d47ebdSAharon Landau flags & MLX5_IB_UPD_XLT_PD || 562*b3d47ebdSAharon Landau flags & MLX5_IB_UPD_XLT_ACCESS; 563*b3d47ebdSAharon Landau 564*b3d47ebdSAharon Landau if (update_pd_access) { 565*b3d47ebdSAharon Landau wqe->ctrl_seg.mkey_mask |= get_umr_update_access_mask(dev); 566*b3d47ebdSAharon Landau wqe->ctrl_seg.mkey_mask |= get_umr_update_pd_mask(); 567*b3d47ebdSAharon Landau } 568*b3d47ebdSAharon Landau 569*b3d47ebdSAharon Landau update_translation = 570*b3d47ebdSAharon Landau flags & MLX5_IB_UPD_XLT_ENABLE || flags & MLX5_IB_UPD_XLT_ADDR; 571*b3d47ebdSAharon Landau 572*b3d47ebdSAharon Landau if (update_translation) { 573*b3d47ebdSAharon Landau wqe->ctrl_seg.mkey_mask |= get_umr_update_translation_mask(); 574*b3d47ebdSAharon Landau if (!mr->ibmr.length) 575*b3d47ebdSAharon Landau MLX5_SET(mkc, &wqe->mkey_seg, length64, 1); 576*b3d47ebdSAharon Landau } 577*b3d47ebdSAharon Landau 578*b3d47ebdSAharon Landau wqe->ctrl_seg.xlt_octowords = 579*b3d47ebdSAharon Landau cpu_to_be16(mlx5r_umr_get_xlt_octo(sg->length)); 580*b3d47ebdSAharon Landau wqe->data_seg.byte_count = cpu_to_be32(sg->length); 581*b3d47ebdSAharon Landau } 582*b3d47ebdSAharon Landau 583*b3d47ebdSAharon Landau /* 584*b3d47ebdSAharon Landau * Send the DMA list to the HW for a normal MR using UMR. 585*b3d47ebdSAharon Landau * Dmabuf MR is handled in a similar way, except that the MLX5_IB_UPD_XLT_ZAP 586*b3d47ebdSAharon Landau * flag may be used. 587*b3d47ebdSAharon Landau */ 588*b3d47ebdSAharon Landau int mlx5r_umr_update_mr_pas(struct mlx5_ib_mr *mr, unsigned int flags) 589*b3d47ebdSAharon Landau { 590*b3d47ebdSAharon Landau struct mlx5_ib_dev *dev = mr_to_mdev(mr); 591*b3d47ebdSAharon Landau struct device *ddev = &dev->mdev->pdev->dev; 592*b3d47ebdSAharon Landau struct mlx5r_umr_wqe wqe = {}; 593*b3d47ebdSAharon Landau struct ib_block_iter biter; 594*b3d47ebdSAharon Landau struct mlx5_mtt *cur_mtt; 595*b3d47ebdSAharon Landau size_t orig_sg_length; 596*b3d47ebdSAharon Landau struct mlx5_mtt *mtt; 597*b3d47ebdSAharon Landau size_t final_size; 598*b3d47ebdSAharon Landau struct ib_sge sg; 599*b3d47ebdSAharon Landau u64 offset = 0; 600*b3d47ebdSAharon Landau int err = 0; 601*b3d47ebdSAharon Landau 602*b3d47ebdSAharon Landau if (WARN_ON(mr->umem->is_odp)) 603*b3d47ebdSAharon Landau return -EINVAL; 604*b3d47ebdSAharon Landau 605*b3d47ebdSAharon Landau mtt = mlx5r_umr_create_xlt( 606*b3d47ebdSAharon Landau dev, &sg, ib_umem_num_dma_blocks(mr->umem, 1 << mr->page_shift), 607*b3d47ebdSAharon Landau sizeof(*mtt), flags); 608*b3d47ebdSAharon Landau if (!mtt) 609*b3d47ebdSAharon Landau return -ENOMEM; 610*b3d47ebdSAharon Landau 611*b3d47ebdSAharon Landau orig_sg_length = sg.length; 612*b3d47ebdSAharon Landau 613*b3d47ebdSAharon Landau mlx5r_umr_set_update_xlt_ctrl_seg(&wqe.ctrl_seg, flags, &sg); 614*b3d47ebdSAharon Landau mlx5r_umr_set_update_xlt_mkey_seg(dev, &wqe.mkey_seg, mr, 615*b3d47ebdSAharon Landau mr->page_shift); 616*b3d47ebdSAharon Landau mlx5r_umr_set_update_xlt_data_seg(&wqe.data_seg, &sg); 617*b3d47ebdSAharon Landau 618*b3d47ebdSAharon Landau cur_mtt = mtt; 619*b3d47ebdSAharon Landau rdma_for_each_block(mr->umem->sgt_append.sgt.sgl, &biter, 620*b3d47ebdSAharon Landau mr->umem->sgt_append.sgt.nents, 621*b3d47ebdSAharon Landau BIT(mr->page_shift)) { 622*b3d47ebdSAharon Landau if (cur_mtt == (void *)mtt + sg.length) { 623*b3d47ebdSAharon Landau dma_sync_single_for_device(ddev, sg.addr, sg.length, 624*b3d47ebdSAharon Landau DMA_TO_DEVICE); 625*b3d47ebdSAharon Landau 626*b3d47ebdSAharon Landau err = mlx5r_umr_post_send_wait(dev, mr->mmkey.key, &wqe, 627*b3d47ebdSAharon Landau true); 628*b3d47ebdSAharon Landau if (err) 629*b3d47ebdSAharon Landau goto err; 630*b3d47ebdSAharon Landau dma_sync_single_for_cpu(ddev, sg.addr, sg.length, 631*b3d47ebdSAharon Landau DMA_TO_DEVICE); 632*b3d47ebdSAharon Landau offset += sg.length; 633*b3d47ebdSAharon Landau mlx5r_umr_update_offset(&wqe.ctrl_seg, offset); 634*b3d47ebdSAharon Landau 635*b3d47ebdSAharon Landau cur_mtt = mtt; 636*b3d47ebdSAharon Landau } 637*b3d47ebdSAharon Landau 638*b3d47ebdSAharon Landau cur_mtt->ptag = 639*b3d47ebdSAharon Landau cpu_to_be64(rdma_block_iter_dma_address(&biter) | 640*b3d47ebdSAharon Landau MLX5_IB_MTT_PRESENT); 641*b3d47ebdSAharon Landau 642*b3d47ebdSAharon Landau if (mr->umem->is_dmabuf && (flags & MLX5_IB_UPD_XLT_ZAP)) 643*b3d47ebdSAharon Landau cur_mtt->ptag = 0; 644*b3d47ebdSAharon Landau 645*b3d47ebdSAharon Landau cur_mtt++; 646*b3d47ebdSAharon Landau } 647*b3d47ebdSAharon Landau 648*b3d47ebdSAharon Landau final_size = (void *)cur_mtt - (void *)mtt; 649*b3d47ebdSAharon Landau sg.length = ALIGN(final_size, MLX5_UMR_MTT_ALIGNMENT); 650*b3d47ebdSAharon Landau memset(cur_mtt, 0, sg.length - final_size); 651*b3d47ebdSAharon Landau mlx5r_umr_final_update_xlt(dev, &wqe, mr, &sg, flags); 652*b3d47ebdSAharon Landau 653*b3d47ebdSAharon Landau dma_sync_single_for_device(ddev, sg.addr, sg.length, DMA_TO_DEVICE); 654*b3d47ebdSAharon Landau err = mlx5r_umr_post_send_wait(dev, mr->mmkey.key, &wqe, true); 655*b3d47ebdSAharon Landau 656*b3d47ebdSAharon Landau err: 657*b3d47ebdSAharon Landau sg.length = orig_sg_length; 658*b3d47ebdSAharon Landau mlx5r_umr_unmap_free_xlt(dev, mtt, &sg); 659*b3d47ebdSAharon Landau return err; 660*b3d47ebdSAharon Landau } 661