xref: /openbmc/linux/drivers/infiniband/hw/mlx5/umr.c (revision 916adb491e84bc8b130618e4969c1d196525abf2)
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 
8*916adb49SAharon Landau /*
9*916adb49SAharon Landau  * We can't use an array for xlt_emergency_page because dma_map_single doesn't
10*916adb49SAharon Landau  * work on kernel modules memory
11*916adb49SAharon Landau  */
12*916adb49SAharon Landau void *xlt_emergency_page;
13*916adb49SAharon Landau static DEFINE_MUTEX(xlt_emergency_page_mutex);
14*916adb49SAharon 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 }
400*916adb49SAharon Landau 
401*916adb49SAharon Landau #define MLX5_MAX_UMR_CHUNK                                                     \
402*916adb49SAharon Landau 	((1 << (MLX5_MAX_UMR_SHIFT + 4)) - MLX5_UMR_MTT_ALIGNMENT)
403*916adb49SAharon Landau #define MLX5_SPARE_UMR_CHUNK 0x10000
404*916adb49SAharon Landau 
405*916adb49SAharon Landau /*
406*916adb49SAharon Landau  * Allocate a temporary buffer to hold the per-page information to transfer to
407*916adb49SAharon Landau  * HW. For efficiency this should be as large as it can be, but buffer
408*916adb49SAharon Landau  * allocation failure is not allowed, so try smaller sizes.
409*916adb49SAharon Landau  */
410*916adb49SAharon Landau static void *mlx5r_umr_alloc_xlt(size_t *nents, size_t ent_size, gfp_t gfp_mask)
411*916adb49SAharon Landau {
412*916adb49SAharon Landau 	const size_t xlt_chunk_align = MLX5_UMR_MTT_ALIGNMENT / ent_size;
413*916adb49SAharon Landau 	size_t size;
414*916adb49SAharon Landau 	void *res = NULL;
415*916adb49SAharon Landau 
416*916adb49SAharon Landau 	static_assert(PAGE_SIZE % MLX5_UMR_MTT_ALIGNMENT == 0);
417*916adb49SAharon Landau 
418*916adb49SAharon Landau 	/*
419*916adb49SAharon Landau 	 * MLX5_IB_UPD_XLT_ATOMIC doesn't signal an atomic context just that the
420*916adb49SAharon Landau 	 * allocation can't trigger any kind of reclaim.
421*916adb49SAharon Landau 	 */
422*916adb49SAharon Landau 	might_sleep();
423*916adb49SAharon Landau 
424*916adb49SAharon Landau 	gfp_mask |= __GFP_ZERO | __GFP_NORETRY;
425*916adb49SAharon Landau 
426*916adb49SAharon Landau 	/*
427*916adb49SAharon Landau 	 * If the system already has a suitable high order page then just use
428*916adb49SAharon Landau 	 * that, but don't try hard to create one. This max is about 1M, so a
429*916adb49SAharon Landau 	 * free x86 huge page will satisfy it.
430*916adb49SAharon Landau 	 */
431*916adb49SAharon Landau 	size = min_t(size_t, ent_size * ALIGN(*nents, xlt_chunk_align),
432*916adb49SAharon Landau 		     MLX5_MAX_UMR_CHUNK);
433*916adb49SAharon Landau 	*nents = size / ent_size;
434*916adb49SAharon Landau 	res = (void *)__get_free_pages(gfp_mask | __GFP_NOWARN,
435*916adb49SAharon Landau 				       get_order(size));
436*916adb49SAharon Landau 	if (res)
437*916adb49SAharon Landau 		return res;
438*916adb49SAharon Landau 
439*916adb49SAharon Landau 	if (size > MLX5_SPARE_UMR_CHUNK) {
440*916adb49SAharon Landau 		size = MLX5_SPARE_UMR_CHUNK;
441*916adb49SAharon Landau 		*nents = size / ent_size;
442*916adb49SAharon Landau 		res = (void *)__get_free_pages(gfp_mask | __GFP_NOWARN,
443*916adb49SAharon Landau 					       get_order(size));
444*916adb49SAharon Landau 		if (res)
445*916adb49SAharon Landau 			return res;
446*916adb49SAharon Landau 	}
447*916adb49SAharon Landau 
448*916adb49SAharon Landau 	*nents = PAGE_SIZE / ent_size;
449*916adb49SAharon Landau 	res = (void *)__get_free_page(gfp_mask);
450*916adb49SAharon Landau 	if (res)
451*916adb49SAharon Landau 		return res;
452*916adb49SAharon Landau 
453*916adb49SAharon Landau 	mutex_lock(&xlt_emergency_page_mutex);
454*916adb49SAharon Landau 	memset(xlt_emergency_page, 0, PAGE_SIZE);
455*916adb49SAharon Landau 	return xlt_emergency_page;
456*916adb49SAharon Landau }
457*916adb49SAharon Landau 
458*916adb49SAharon Landau static void mlx5r_umr_free_xlt(void *xlt, size_t length)
459*916adb49SAharon Landau {
460*916adb49SAharon Landau 	if (xlt == xlt_emergency_page) {
461*916adb49SAharon Landau 		mutex_unlock(&xlt_emergency_page_mutex);
462*916adb49SAharon Landau 		return;
463*916adb49SAharon Landau 	}
464*916adb49SAharon Landau 
465*916adb49SAharon Landau 	free_pages((unsigned long)xlt, get_order(length));
466*916adb49SAharon Landau }
467*916adb49SAharon Landau 
468*916adb49SAharon Landau void mlx5r_umr_unmap_free_xlt(struct mlx5_ib_dev *dev, void *xlt,
469*916adb49SAharon Landau 			     struct ib_sge *sg)
470*916adb49SAharon Landau {
471*916adb49SAharon Landau 	struct device *ddev = &dev->mdev->pdev->dev;
472*916adb49SAharon Landau 
473*916adb49SAharon Landau 	dma_unmap_single(ddev, sg->addr, sg->length, DMA_TO_DEVICE);
474*916adb49SAharon Landau 	mlx5r_umr_free_xlt(xlt, sg->length);
475*916adb49SAharon Landau }
476*916adb49SAharon Landau 
477*916adb49SAharon Landau /*
478*916adb49SAharon Landau  * Create an XLT buffer ready for submission.
479*916adb49SAharon Landau  */
480*916adb49SAharon Landau void *mlx5r_umr_create_xlt(struct mlx5_ib_dev *dev, struct ib_sge *sg,
481*916adb49SAharon Landau 			  size_t nents, size_t ent_size, unsigned int flags)
482*916adb49SAharon Landau {
483*916adb49SAharon Landau 	struct device *ddev = &dev->mdev->pdev->dev;
484*916adb49SAharon Landau 	dma_addr_t dma;
485*916adb49SAharon Landau 	void *xlt;
486*916adb49SAharon Landau 
487*916adb49SAharon Landau 	xlt = mlx5r_umr_alloc_xlt(&nents, ent_size,
488*916adb49SAharon Landau 				 flags & MLX5_IB_UPD_XLT_ATOMIC ? GFP_ATOMIC :
489*916adb49SAharon Landau 								  GFP_KERNEL);
490*916adb49SAharon Landau 	sg->length = nents * ent_size;
491*916adb49SAharon Landau 	dma = dma_map_single(ddev, xlt, sg->length, DMA_TO_DEVICE);
492*916adb49SAharon Landau 	if (dma_mapping_error(ddev, dma)) {
493*916adb49SAharon Landau 		mlx5_ib_err(dev, "unable to map DMA during XLT update.\n");
494*916adb49SAharon Landau 		mlx5r_umr_free_xlt(xlt, sg->length);
495*916adb49SAharon Landau 		return NULL;
496*916adb49SAharon Landau 	}
497*916adb49SAharon Landau 	sg->addr = dma;
498*916adb49SAharon Landau 	sg->lkey = dev->umrc.pd->local_dma_lkey;
499*916adb49SAharon Landau 
500*916adb49SAharon Landau 	return xlt;
501*916adb49SAharon Landau }
502