xref: /openbmc/linux/drivers/infiniband/hw/mlx5/umr.c (revision 6f0689fdf19ed3aca3ee3910223ad27216640693)
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"
6*6f0689fdSAharon Landau #include "wr.h"
704876c12SAharon Landau 
88a8a5d37SAharon Landau static __be64 get_umr_enable_mr_mask(void)
98a8a5d37SAharon Landau {
108a8a5d37SAharon Landau 	u64 result;
118a8a5d37SAharon Landau 
128a8a5d37SAharon Landau 	result = MLX5_MKEY_MASK_KEY |
138a8a5d37SAharon Landau 		 MLX5_MKEY_MASK_FREE;
148a8a5d37SAharon Landau 
158a8a5d37SAharon Landau 	return cpu_to_be64(result);
168a8a5d37SAharon Landau }
178a8a5d37SAharon Landau 
188a8a5d37SAharon Landau static __be64 get_umr_disable_mr_mask(void)
198a8a5d37SAharon Landau {
208a8a5d37SAharon Landau 	u64 result;
218a8a5d37SAharon Landau 
228a8a5d37SAharon Landau 	result = MLX5_MKEY_MASK_FREE;
238a8a5d37SAharon Landau 
248a8a5d37SAharon Landau 	return cpu_to_be64(result);
258a8a5d37SAharon Landau }
268a8a5d37SAharon Landau 
278a8a5d37SAharon Landau static __be64 get_umr_update_translation_mask(void)
288a8a5d37SAharon Landau {
298a8a5d37SAharon Landau 	u64 result;
308a8a5d37SAharon Landau 
318a8a5d37SAharon Landau 	result = MLX5_MKEY_MASK_LEN |
328a8a5d37SAharon Landau 		 MLX5_MKEY_MASK_PAGE_SIZE |
338a8a5d37SAharon Landau 		 MLX5_MKEY_MASK_START_ADDR;
348a8a5d37SAharon Landau 
358a8a5d37SAharon Landau 	return cpu_to_be64(result);
368a8a5d37SAharon Landau }
378a8a5d37SAharon Landau 
38ba6a9c68SAharon Landau static __be64 get_umr_update_access_mask(struct mlx5_ib_dev *dev)
398a8a5d37SAharon Landau {
408a8a5d37SAharon Landau 	u64 result;
418a8a5d37SAharon Landau 
428a8a5d37SAharon Landau 	result = MLX5_MKEY_MASK_LR |
438a8a5d37SAharon Landau 		 MLX5_MKEY_MASK_LW |
448a8a5d37SAharon Landau 		 MLX5_MKEY_MASK_RR |
458a8a5d37SAharon Landau 		 MLX5_MKEY_MASK_RW;
468a8a5d37SAharon Landau 
47ba6a9c68SAharon Landau 	if (MLX5_CAP_GEN(dev->mdev, atomic))
488a8a5d37SAharon Landau 		result |= MLX5_MKEY_MASK_A;
498a8a5d37SAharon Landau 
50ba6a9c68SAharon Landau 	if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write_umr))
518a8a5d37SAharon Landau 		result |= MLX5_MKEY_MASK_RELAXED_ORDERING_WRITE;
528a8a5d37SAharon Landau 
53ba6a9c68SAharon Landau 	if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read_umr))
548a8a5d37SAharon Landau 		result |= MLX5_MKEY_MASK_RELAXED_ORDERING_READ;
558a8a5d37SAharon Landau 
568a8a5d37SAharon Landau 	return cpu_to_be64(result);
578a8a5d37SAharon Landau }
588a8a5d37SAharon Landau 
598a8a5d37SAharon Landau static __be64 get_umr_update_pd_mask(void)
608a8a5d37SAharon Landau {
618a8a5d37SAharon Landau 	u64 result;
628a8a5d37SAharon Landau 
638a8a5d37SAharon Landau 	result = MLX5_MKEY_MASK_PD;
648a8a5d37SAharon Landau 
658a8a5d37SAharon Landau 	return cpu_to_be64(result);
668a8a5d37SAharon Landau }
678a8a5d37SAharon Landau 
688a8a5d37SAharon Landau static int umr_check_mkey_mask(struct mlx5_ib_dev *dev, u64 mask)
698a8a5d37SAharon Landau {
708a8a5d37SAharon Landau 	if (mask & MLX5_MKEY_MASK_PAGE_SIZE &&
718a8a5d37SAharon Landau 	    MLX5_CAP_GEN(dev->mdev, umr_modify_entity_size_disabled))
728a8a5d37SAharon Landau 		return -EPERM;
738a8a5d37SAharon Landau 
748a8a5d37SAharon Landau 	if (mask & MLX5_MKEY_MASK_A &&
758a8a5d37SAharon Landau 	    MLX5_CAP_GEN(dev->mdev, umr_modify_atomic_disabled))
768a8a5d37SAharon Landau 		return -EPERM;
778a8a5d37SAharon Landau 
788a8a5d37SAharon Landau 	if (mask & MLX5_MKEY_MASK_RELAXED_ORDERING_WRITE &&
798a8a5d37SAharon Landau 	    !MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write_umr))
808a8a5d37SAharon Landau 		return -EPERM;
818a8a5d37SAharon Landau 
828a8a5d37SAharon Landau 	if (mask & MLX5_MKEY_MASK_RELAXED_ORDERING_READ &&
838a8a5d37SAharon Landau 	    !MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read_umr))
848a8a5d37SAharon Landau 		return -EPERM;
858a8a5d37SAharon Landau 
868a8a5d37SAharon Landau 	return 0;
878a8a5d37SAharon Landau }
888a8a5d37SAharon Landau 
898a8a5d37SAharon Landau int mlx5r_umr_set_umr_ctrl_seg(struct mlx5_ib_dev *dev,
908a8a5d37SAharon Landau 			       struct mlx5_wqe_umr_ctrl_seg *umr,
918a8a5d37SAharon Landau 			       const struct ib_send_wr *wr)
928a8a5d37SAharon Landau {
938a8a5d37SAharon Landau 	const struct mlx5_umr_wr *umrwr = umr_wr(wr);
948a8a5d37SAharon Landau 
958a8a5d37SAharon Landau 	memset(umr, 0, sizeof(*umr));
968a8a5d37SAharon Landau 
978a8a5d37SAharon Landau 	if (!umrwr->ignore_free_state) {
988a8a5d37SAharon Landau 		if (wr->send_flags & MLX5_IB_SEND_UMR_FAIL_IF_FREE)
998a8a5d37SAharon Landau 			 /* fail if free */
1008a8a5d37SAharon Landau 			umr->flags = MLX5_UMR_CHECK_FREE;
1018a8a5d37SAharon Landau 		else
1028a8a5d37SAharon Landau 			/* fail if not free */
1038a8a5d37SAharon Landau 			umr->flags = MLX5_UMR_CHECK_NOT_FREE;
1048a8a5d37SAharon Landau 	}
1058a8a5d37SAharon Landau 
1068a8a5d37SAharon Landau 	umr->xlt_octowords =
1078a8a5d37SAharon Landau 		cpu_to_be16(mlx5r_umr_get_xlt_octo(umrwr->xlt_size));
1088a8a5d37SAharon Landau 	if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_XLT) {
1098a8a5d37SAharon Landau 		u64 offset = mlx5r_umr_get_xlt_octo(umrwr->offset);
1108a8a5d37SAharon Landau 
1118a8a5d37SAharon Landau 		umr->xlt_offset = cpu_to_be16(offset & 0xffff);
1128a8a5d37SAharon Landau 		umr->xlt_offset_47_16 = cpu_to_be32(offset >> 16);
1138a8a5d37SAharon Landau 		umr->flags |= MLX5_UMR_TRANSLATION_OFFSET_EN;
1148a8a5d37SAharon Landau 	}
1158a8a5d37SAharon Landau 	if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_TRANSLATION)
1168a8a5d37SAharon Landau 		umr->mkey_mask |= get_umr_update_translation_mask();
1178a8a5d37SAharon Landau 	if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_PD_ACCESS) {
118ba6a9c68SAharon Landau 		umr->mkey_mask |= get_umr_update_access_mask(dev);
1198a8a5d37SAharon Landau 		umr->mkey_mask |= get_umr_update_pd_mask();
1208a8a5d37SAharon Landau 	}
1218a8a5d37SAharon Landau 	if (wr->send_flags & MLX5_IB_SEND_UMR_ENABLE_MR)
1228a8a5d37SAharon Landau 		umr->mkey_mask |= get_umr_enable_mr_mask();
1238a8a5d37SAharon Landau 	if (wr->send_flags & MLX5_IB_SEND_UMR_DISABLE_MR)
1248a8a5d37SAharon Landau 		umr->mkey_mask |= get_umr_disable_mr_mask();
1258a8a5d37SAharon Landau 
1268a8a5d37SAharon Landau 	if (!wr->num_sge)
1278a8a5d37SAharon Landau 		umr->flags |= MLX5_UMR_INLINE;
1288a8a5d37SAharon Landau 
1298a8a5d37SAharon Landau 	return umr_check_mkey_mask(dev, be64_to_cpu(umr->mkey_mask));
1308a8a5d37SAharon Landau }
1318a8a5d37SAharon Landau 
13204876c12SAharon Landau enum {
13304876c12SAharon Landau 	MAX_UMR_WR = 128,
13404876c12SAharon Landau };
13504876c12SAharon Landau 
13604876c12SAharon Landau static int mlx5r_umr_qp_rst2rts(struct mlx5_ib_dev *dev, struct ib_qp *qp)
13704876c12SAharon Landau {
13804876c12SAharon Landau 	struct ib_qp_attr attr = {};
13904876c12SAharon Landau 	int ret;
14004876c12SAharon Landau 
14104876c12SAharon Landau 	attr.qp_state = IB_QPS_INIT;
14204876c12SAharon Landau 	attr.port_num = 1;
14304876c12SAharon Landau 	ret = ib_modify_qp(qp, &attr,
14404876c12SAharon Landau 			   IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT);
14504876c12SAharon Landau 	if (ret) {
14604876c12SAharon Landau 		mlx5_ib_dbg(dev, "Couldn't modify UMR QP\n");
14704876c12SAharon Landau 		return ret;
14804876c12SAharon Landau 	}
14904876c12SAharon Landau 
15004876c12SAharon Landau 	memset(&attr, 0, sizeof(attr));
15104876c12SAharon Landau 	attr.qp_state = IB_QPS_RTR;
15204876c12SAharon Landau 
15304876c12SAharon Landau 	ret = ib_modify_qp(qp, &attr, IB_QP_STATE);
15404876c12SAharon Landau 	if (ret) {
15504876c12SAharon Landau 		mlx5_ib_dbg(dev, "Couldn't modify umr QP to rtr\n");
15604876c12SAharon Landau 		return ret;
15704876c12SAharon Landau 	}
15804876c12SAharon Landau 
15904876c12SAharon Landau 	memset(&attr, 0, sizeof(attr));
16004876c12SAharon Landau 	attr.qp_state = IB_QPS_RTS;
16104876c12SAharon Landau 	ret = ib_modify_qp(qp, &attr, IB_QP_STATE);
16204876c12SAharon Landau 	if (ret) {
16304876c12SAharon Landau 		mlx5_ib_dbg(dev, "Couldn't modify umr QP to rts\n");
16404876c12SAharon Landau 		return ret;
16504876c12SAharon Landau 	}
16604876c12SAharon Landau 
16704876c12SAharon Landau 	return 0;
16804876c12SAharon Landau }
16904876c12SAharon Landau 
17004876c12SAharon Landau int mlx5r_umr_resource_init(struct mlx5_ib_dev *dev)
17104876c12SAharon Landau {
17204876c12SAharon Landau 	struct ib_qp_init_attr init_attr = {};
17304876c12SAharon Landau 	struct ib_pd *pd;
17404876c12SAharon Landau 	struct ib_cq *cq;
17504876c12SAharon Landau 	struct ib_qp *qp;
17604876c12SAharon Landau 	int ret;
17704876c12SAharon Landau 
17804876c12SAharon Landau 	pd = ib_alloc_pd(&dev->ib_dev, 0);
17904876c12SAharon Landau 	if (IS_ERR(pd)) {
18004876c12SAharon Landau 		mlx5_ib_dbg(dev, "Couldn't create PD for sync UMR QP\n");
18104876c12SAharon Landau 		return PTR_ERR(pd);
18204876c12SAharon Landau 	}
18304876c12SAharon Landau 
18404876c12SAharon Landau 	cq = ib_alloc_cq(&dev->ib_dev, NULL, 128, 0, IB_POLL_SOFTIRQ);
18504876c12SAharon Landau 	if (IS_ERR(cq)) {
18604876c12SAharon Landau 		mlx5_ib_dbg(dev, "Couldn't create CQ for sync UMR QP\n");
18704876c12SAharon Landau 		ret = PTR_ERR(cq);
18804876c12SAharon Landau 		goto destroy_pd;
18904876c12SAharon Landau 	}
19004876c12SAharon Landau 
19104876c12SAharon Landau 	init_attr.send_cq = cq;
19204876c12SAharon Landau 	init_attr.recv_cq = cq;
19304876c12SAharon Landau 	init_attr.sq_sig_type = IB_SIGNAL_ALL_WR;
19404876c12SAharon Landau 	init_attr.cap.max_send_wr = MAX_UMR_WR;
19504876c12SAharon Landau 	init_attr.cap.max_send_sge = 1;
19604876c12SAharon Landau 	init_attr.qp_type = MLX5_IB_QPT_REG_UMR;
19704876c12SAharon Landau 	init_attr.port_num = 1;
19804876c12SAharon Landau 	qp = ib_create_qp(pd, &init_attr);
19904876c12SAharon Landau 	if (IS_ERR(qp)) {
20004876c12SAharon Landau 		mlx5_ib_dbg(dev, "Couldn't create sync UMR QP\n");
20104876c12SAharon Landau 		ret = PTR_ERR(qp);
20204876c12SAharon Landau 		goto destroy_cq;
20304876c12SAharon Landau 	}
20404876c12SAharon Landau 
20504876c12SAharon Landau 	ret = mlx5r_umr_qp_rst2rts(dev, qp);
20604876c12SAharon Landau 	if (ret)
20704876c12SAharon Landau 		goto destroy_qp;
20804876c12SAharon Landau 
20904876c12SAharon Landau 	dev->umrc.qp = qp;
21004876c12SAharon Landau 	dev->umrc.cq = cq;
21104876c12SAharon Landau 	dev->umrc.pd = pd;
21204876c12SAharon Landau 
21304876c12SAharon Landau 	sema_init(&dev->umrc.sem, MAX_UMR_WR);
21404876c12SAharon Landau 
21504876c12SAharon Landau 	return 0;
21604876c12SAharon Landau 
21704876c12SAharon Landau destroy_qp:
21804876c12SAharon Landau 	ib_destroy_qp(qp);
21904876c12SAharon Landau destroy_cq:
22004876c12SAharon Landau 	ib_free_cq(cq);
22104876c12SAharon Landau destroy_pd:
22204876c12SAharon Landau 	ib_dealloc_pd(pd);
22304876c12SAharon Landau 	return ret;
22404876c12SAharon Landau }
22504876c12SAharon Landau 
22604876c12SAharon Landau void mlx5r_umr_resource_cleanup(struct mlx5_ib_dev *dev)
22704876c12SAharon Landau {
22804876c12SAharon Landau 	ib_destroy_qp(dev->umrc.qp);
22904876c12SAharon Landau 	ib_free_cq(dev->umrc.cq);
23004876c12SAharon Landau 	ib_dealloc_pd(dev->umrc.pd);
23104876c12SAharon Landau }
232*6f0689fdSAharon Landau 
233*6f0689fdSAharon Landau static int mlx5r_umr_post_send(struct ib_qp *ibqp, u32 mkey, struct ib_cqe *cqe,
234*6f0689fdSAharon Landau 			       struct mlx5r_umr_wqe *wqe, bool with_data)
235*6f0689fdSAharon Landau {
236*6f0689fdSAharon Landau 	unsigned int wqe_size =
237*6f0689fdSAharon Landau 		with_data ? sizeof(struct mlx5r_umr_wqe) :
238*6f0689fdSAharon Landau 			    sizeof(struct mlx5r_umr_wqe) -
239*6f0689fdSAharon Landau 				    sizeof(struct mlx5_wqe_data_seg);
240*6f0689fdSAharon Landau 	struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
241*6f0689fdSAharon Landau 	struct mlx5_core_dev *mdev = dev->mdev;
242*6f0689fdSAharon Landau 	struct mlx5_ib_qp *qp = to_mqp(ibqp);
243*6f0689fdSAharon Landau 	struct mlx5_wqe_ctrl_seg *ctrl;
244*6f0689fdSAharon Landau 	union {
245*6f0689fdSAharon Landau 		struct ib_cqe *ib_cqe;
246*6f0689fdSAharon Landau 		u64 wr_id;
247*6f0689fdSAharon Landau 	} id;
248*6f0689fdSAharon Landau 	void *cur_edge, *seg;
249*6f0689fdSAharon Landau 	unsigned long flags;
250*6f0689fdSAharon Landau 	unsigned int idx;
251*6f0689fdSAharon Landau 	int size, err;
252*6f0689fdSAharon Landau 
253*6f0689fdSAharon Landau 	if (unlikely(mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR))
254*6f0689fdSAharon Landau 		return -EIO;
255*6f0689fdSAharon Landau 
256*6f0689fdSAharon Landau 	spin_lock_irqsave(&qp->sq.lock, flags);
257*6f0689fdSAharon Landau 
258*6f0689fdSAharon Landau 	err = mlx5r_begin_wqe(qp, &seg, &ctrl, &idx, &size, &cur_edge, 0,
259*6f0689fdSAharon Landau 			      cpu_to_be32(mkey), false, false);
260*6f0689fdSAharon Landau 	if (WARN_ON(err))
261*6f0689fdSAharon Landau 		goto out;
262*6f0689fdSAharon Landau 
263*6f0689fdSAharon Landau 	qp->sq.wr_data[idx] = MLX5_IB_WR_UMR;
264*6f0689fdSAharon Landau 
265*6f0689fdSAharon Landau 	mlx5r_memcpy_send_wqe(&qp->sq, &cur_edge, &seg, &size, wqe, wqe_size);
266*6f0689fdSAharon Landau 
267*6f0689fdSAharon Landau 	id.ib_cqe = cqe;
268*6f0689fdSAharon Landau 	mlx5r_finish_wqe(qp, ctrl, seg, size, cur_edge, idx, id.wr_id, 0,
269*6f0689fdSAharon Landau 			 MLX5_FENCE_MODE_NONE, MLX5_OPCODE_UMR);
270*6f0689fdSAharon Landau 
271*6f0689fdSAharon Landau 	mlx5r_ring_db(qp, 1, ctrl);
272*6f0689fdSAharon Landau 
273*6f0689fdSAharon Landau out:
274*6f0689fdSAharon Landau 	spin_unlock_irqrestore(&qp->sq.lock, flags);
275*6f0689fdSAharon Landau 
276*6f0689fdSAharon Landau 	return err;
277*6f0689fdSAharon Landau }
278*6f0689fdSAharon Landau 
279*6f0689fdSAharon Landau static void mlx5r_umr_done(struct ib_cq *cq, struct ib_wc *wc)
280*6f0689fdSAharon Landau {
281*6f0689fdSAharon Landau 	struct mlx5_ib_umr_context *context =
282*6f0689fdSAharon Landau 		container_of(wc->wr_cqe, struct mlx5_ib_umr_context, cqe);
283*6f0689fdSAharon Landau 
284*6f0689fdSAharon Landau 	context->status = wc->status;
285*6f0689fdSAharon Landau 	complete(&context->done);
286*6f0689fdSAharon Landau }
287*6f0689fdSAharon Landau 
288*6f0689fdSAharon Landau static inline void mlx5r_umr_init_context(struct mlx5r_umr_context *context)
289*6f0689fdSAharon Landau {
290*6f0689fdSAharon Landau 	context->cqe.done = mlx5r_umr_done;
291*6f0689fdSAharon Landau 	init_completion(&context->done);
292*6f0689fdSAharon Landau }
293*6f0689fdSAharon Landau 
294*6f0689fdSAharon Landau static int mlx5r_umr_post_send_wait(struct mlx5_ib_dev *dev, u32 mkey,
295*6f0689fdSAharon Landau 				   struct mlx5r_umr_wqe *wqe, bool with_data)
296*6f0689fdSAharon Landau {
297*6f0689fdSAharon Landau 	struct umr_common *umrc = &dev->umrc;
298*6f0689fdSAharon Landau 	struct mlx5r_umr_context umr_context;
299*6f0689fdSAharon Landau 	int err;
300*6f0689fdSAharon Landau 
301*6f0689fdSAharon Landau 	err = umr_check_mkey_mask(dev, be64_to_cpu(wqe->ctrl_seg.mkey_mask));
302*6f0689fdSAharon Landau 	if (WARN_ON(err))
303*6f0689fdSAharon Landau 		return err;
304*6f0689fdSAharon Landau 
305*6f0689fdSAharon Landau 	mlx5r_umr_init_context(&umr_context);
306*6f0689fdSAharon Landau 
307*6f0689fdSAharon Landau 	down(&umrc->sem);
308*6f0689fdSAharon Landau 	err = mlx5r_umr_post_send(umrc->qp, mkey, &umr_context.cqe, wqe,
309*6f0689fdSAharon Landau 				  with_data);
310*6f0689fdSAharon Landau 	if (err)
311*6f0689fdSAharon Landau 		mlx5_ib_warn(dev, "UMR post send failed, err %d\n", err);
312*6f0689fdSAharon Landau 	else {
313*6f0689fdSAharon Landau 		wait_for_completion(&umr_context.done);
314*6f0689fdSAharon Landau 		if (umr_context.status != IB_WC_SUCCESS) {
315*6f0689fdSAharon Landau 			mlx5_ib_warn(dev, "reg umr failed (%u)\n",
316*6f0689fdSAharon Landau 				     umr_context.status);
317*6f0689fdSAharon Landau 			err = -EFAULT;
318*6f0689fdSAharon Landau 		}
319*6f0689fdSAharon Landau 	}
320*6f0689fdSAharon Landau 	up(&umrc->sem);
321*6f0689fdSAharon Landau 	return err;
322*6f0689fdSAharon Landau }
323