Skip to content

Commit bde5158

Browse files
Eli Cohenrolandd
Eli Cohen
authored andcommitted
IB/mlx5: Add support for resize CQ
Implement resize CQ which is a mandatory verb in mlx5. Signed-off-by: Eli Cohen <[email protected]> Signed-off-by: Roland Dreier <[email protected]>
1 parent 3bdb31f commit bde5158

File tree

6 files changed

+284
-22
lines changed

6 files changed

+284
-22
lines changed

drivers/infiniband/hw/mlx5/cq.c

Lines changed: 265 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,24 @@ static void *get_cqe(struct mlx5_ib_cq *cq, int n)
7373
return get_cqe_from_buf(&cq->buf, n, cq->mcq.cqe_sz);
7474
}
7575

76+
static u8 sw_ownership_bit(int n, int nent)
77+
{
78+
return (n & nent) ? 1 : 0;
79+
}
80+
7681
static void *get_sw_cqe(struct mlx5_ib_cq *cq, int n)
7782
{
7883
void *cqe = get_cqe(cq, n & cq->ibcq.cqe);
7984
struct mlx5_cqe64 *cqe64;
8085

8186
cqe64 = (cq->mcq.cqe_sz == 64) ? cqe : cqe + 64;
82-
return ((cqe64->op_own & MLX5_CQE_OWNER_MASK) ^
83-
!!(n & (cq->ibcq.cqe + 1))) ? NULL : cqe;
87+
88+
if (likely((cqe64->op_own) >> 4 != MLX5_CQE_INVALID) &&
89+
!((cqe64->op_own & MLX5_CQE_OWNER_MASK) ^ !!(n & (cq->ibcq.cqe + 1)))) {
90+
return cqe;
91+
} else {
92+
return NULL;
93+
}
8494
}
8595

8696
static void *next_cqe_sw(struct mlx5_ib_cq *cq)
@@ -351,6 +361,11 @@ static void handle_atomics(struct mlx5_ib_qp *qp, struct mlx5_cqe64 *cqe64,
351361
qp->sq.last_poll = tail;
352362
}
353363

364+
static void free_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf)
365+
{
366+
mlx5_buf_free(&dev->mdev, &buf->buf);
367+
}
368+
354369
static int mlx5_poll_one(struct mlx5_ib_cq *cq,
355370
struct mlx5_ib_qp **cur_qp,
356371
struct ib_wc *wc)
@@ -366,6 +381,7 @@ static int mlx5_poll_one(struct mlx5_ib_cq *cq,
366381
void *cqe;
367382
int idx;
368383

384+
repoll:
369385
cqe = next_cqe_sw(cq);
370386
if (!cqe)
371387
return -EAGAIN;
@@ -379,7 +395,18 @@ static int mlx5_poll_one(struct mlx5_ib_cq *cq,
379395
*/
380396
rmb();
381397

382-
/* TBD: resize CQ */
398+
opcode = cqe64->op_own >> 4;
399+
if (unlikely(opcode == MLX5_CQE_RESIZE_CQ)) {
400+
if (likely(cq->resize_buf)) {
401+
free_cq_buf(dev, &cq->buf);
402+
cq->buf = *cq->resize_buf;
403+
kfree(cq->resize_buf);
404+
cq->resize_buf = NULL;
405+
goto repoll;
406+
} else {
407+
mlx5_ib_warn(dev, "unexpected resize cqe\n");
408+
}
409+
}
383410

384411
qpn = ntohl(cqe64->sop_drop_qpn) & 0xffffff;
385412
if (!*cur_qp || (qpn != (*cur_qp)->ibqp.qp_num)) {
@@ -398,7 +425,6 @@ static int mlx5_poll_one(struct mlx5_ib_cq *cq,
398425
}
399426

400427
wc->qp = &(*cur_qp)->ibqp;
401-
opcode = cqe64->op_own >> 4;
402428
switch (opcode) {
403429
case MLX5_CQE_REQ:
404430
wq = &(*cur_qp)->sq;
@@ -503,15 +529,11 @@ static int alloc_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf,
503529
return err;
504530

505531
buf->cqe_size = cqe_size;
532+
buf->nent = nent;
506533

507534
return 0;
508535
}
509536

510-
static void free_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf)
511-
{
512-
mlx5_buf_free(&dev->mdev, &buf->buf);
513-
}
514-
515537
static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata,
516538
struct ib_ucontext *context, struct mlx5_ib_cq *cq,
517539
int entries, struct mlx5_create_cq_mbox_in **cqb,
@@ -576,16 +598,16 @@ static void destroy_cq_user(struct mlx5_ib_cq *cq, struct ib_ucontext *context)
576598
ib_umem_release(cq->buf.umem);
577599
}
578600

579-
static void init_cq_buf(struct mlx5_ib_cq *cq, int nent)
601+
static void init_cq_buf(struct mlx5_ib_cq *cq, struct mlx5_ib_cq_buf *buf)
580602
{
581603
int i;
582604
void *cqe;
583605
struct mlx5_cqe64 *cqe64;
584606

585-
for (i = 0; i < nent; i++) {
586-
cqe = get_cqe(cq, i);
587-
cqe64 = (cq->buf.cqe_size == 64) ? cqe : cqe + 64;
588-
cqe64->op_own = 0xf1;
607+
for (i = 0; i < buf->nent; i++) {
608+
cqe = get_cqe_from_buf(buf, i, buf->cqe_size);
609+
cqe64 = buf->cqe_size == 64 ? cqe : cqe + 64;
610+
cqe64->op_own = MLX5_CQE_INVALID << 4;
589611
}
590612
}
591613

@@ -610,7 +632,7 @@ static int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq,
610632
if (err)
611633
goto err_db;
612634

613-
init_cq_buf(cq, entries);
635+
init_cq_buf(cq, &cq->buf);
614636

615637
*inlen = sizeof(**cqb) + sizeof(*(*cqb)->pas) * cq->buf.buf.npages;
616638
*cqb = mlx5_vzalloc(*inlen);
@@ -836,7 +858,7 @@ int mlx5_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period)
836858
in->ctx.cq_period = cpu_to_be16(cq_period);
837859
in->ctx.cq_max_count = cpu_to_be16(cq_count);
838860
in->field_select = cpu_to_be32(fsel);
839-
err = mlx5_core_modify_cq(&dev->mdev, &mcq->mcq, in);
861+
err = mlx5_core_modify_cq(&dev->mdev, &mcq->mcq, in, sizeof(*in));
840862
kfree(in);
841863

842864
if (err)
@@ -845,9 +867,235 @@ int mlx5_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period)
845867
return err;
846868
}
847869

870+
static int resize_user(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq,
871+
int entries, struct ib_udata *udata, int *npas,
872+
int *page_shift, int *cqe_size)
873+
{
874+
struct mlx5_ib_resize_cq ucmd;
875+
struct ib_umem *umem;
876+
int err;
877+
int npages;
878+
struct ib_ucontext *context = cq->buf.umem->context;
879+
880+
if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
881+
return -EFAULT;
882+
883+
umem = ib_umem_get(context, ucmd.buf_addr, entries * ucmd.cqe_size,
884+
IB_ACCESS_LOCAL_WRITE, 1);
885+
if (IS_ERR(umem)) {
886+
err = PTR_ERR(umem);
887+
return err;
888+
}
889+
890+
mlx5_ib_cont_pages(umem, ucmd.buf_addr, &npages, page_shift,
891+
npas, NULL);
892+
893+
cq->resize_umem = umem;
894+
*cqe_size = ucmd.cqe_size;
895+
896+
return 0;
897+
}
898+
899+
static void un_resize_user(struct mlx5_ib_cq *cq)
900+
{
901+
ib_umem_release(cq->resize_umem);
902+
}
903+
904+
static int resize_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq,
905+
int entries, int cqe_size)
906+
{
907+
int err;
908+
909+
cq->resize_buf = kzalloc(sizeof(*cq->resize_buf), GFP_KERNEL);
910+
if (!cq->resize_buf)
911+
return -ENOMEM;
912+
913+
err = alloc_cq_buf(dev, cq->resize_buf, entries, cqe_size);
914+
if (err)
915+
goto ex;
916+
917+
init_cq_buf(cq, cq->resize_buf);
918+
919+
return 0;
920+
921+
ex:
922+
kfree(cq->resize_buf);
923+
return err;
924+
}
925+
926+
static void un_resize_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq)
927+
{
928+
free_cq_buf(dev, cq->resize_buf);
929+
cq->resize_buf = NULL;
930+
}
931+
932+
static int copy_resize_cqes(struct mlx5_ib_cq *cq)
933+
{
934+
struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device);
935+
struct mlx5_cqe64 *scqe64;
936+
struct mlx5_cqe64 *dcqe64;
937+
void *start_cqe;
938+
void *scqe;
939+
void *dcqe;
940+
int ssize;
941+
int dsize;
942+
int i;
943+
u8 sw_own;
944+
945+
ssize = cq->buf.cqe_size;
946+
dsize = cq->resize_buf->cqe_size;
947+
if (ssize != dsize) {
948+
mlx5_ib_warn(dev, "resize from different cqe size is not supported\n");
949+
return -EINVAL;
950+
}
951+
952+
i = cq->mcq.cons_index;
953+
scqe = get_sw_cqe(cq, i);
954+
scqe64 = ssize == 64 ? scqe : scqe + 64;
955+
start_cqe = scqe;
956+
if (!scqe) {
957+
mlx5_ib_warn(dev, "expected cqe in sw ownership\n");
958+
return -EINVAL;
959+
}
960+
961+
while ((scqe64->op_own >> 4) != MLX5_CQE_RESIZE_CQ) {
962+
dcqe = get_cqe_from_buf(cq->resize_buf,
963+
(i + 1) & (cq->resize_buf->nent),
964+
dsize);
965+
dcqe64 = dsize == 64 ? dcqe : dcqe + 64;
966+
sw_own = sw_ownership_bit(i + 1, cq->resize_buf->nent);
967+
memcpy(dcqe, scqe, dsize);
968+
dcqe64->op_own = (dcqe64->op_own & ~MLX5_CQE_OWNER_MASK) | sw_own;
969+
970+
++i;
971+
scqe = get_sw_cqe(cq, i);
972+
scqe64 = ssize == 64 ? scqe : scqe + 64;
973+
if (!scqe) {
974+
mlx5_ib_warn(dev, "expected cqe in sw ownership\n");
975+
return -EINVAL;
976+
}
977+
978+
if (scqe == start_cqe) {
979+
pr_warn("resize CQ failed to get resize CQE, CQN 0x%x\n",
980+
cq->mcq.cqn);
981+
return -ENOMEM;
982+
}
983+
}
984+
++cq->mcq.cons_index;
985+
return 0;
986+
}
987+
848988
int mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
849989
{
850-
return -ENOSYS;
990+
struct mlx5_ib_dev *dev = to_mdev(ibcq->device);
991+
struct mlx5_ib_cq *cq = to_mcq(ibcq);
992+
struct mlx5_modify_cq_mbox_in *in;
993+
int err;
994+
int npas;
995+
int page_shift;
996+
int inlen;
997+
int uninitialized_var(cqe_size);
998+
unsigned long flags;
999+
1000+
if (!(dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_RESIZE_CQ)) {
1001+
pr_info("Firmware does not support resize CQ\n");
1002+
return -ENOSYS;
1003+
}
1004+
1005+
if (entries < 1)
1006+
return -EINVAL;
1007+
1008+
entries = roundup_pow_of_two(entries + 1);
1009+
if (entries > dev->mdev.caps.max_cqes + 1)
1010+
return -EINVAL;
1011+
1012+
if (entries == ibcq->cqe + 1)
1013+
return 0;
1014+
1015+
mutex_lock(&cq->resize_mutex);
1016+
if (udata) {
1017+
err = resize_user(dev, cq, entries, udata, &npas, &page_shift,
1018+
&cqe_size);
1019+
} else {
1020+
cqe_size = 64;
1021+
err = resize_kernel(dev, cq, entries, cqe_size);
1022+
if (!err) {
1023+
npas = cq->resize_buf->buf.npages;
1024+
page_shift = cq->resize_buf->buf.page_shift;
1025+
}
1026+
}
1027+
1028+
if (err)
1029+
goto ex;
1030+
1031+
inlen = sizeof(*in) + npas * sizeof(in->pas[0]);
1032+
in = mlx5_vzalloc(inlen);
1033+
if (!in) {
1034+
err = -ENOMEM;
1035+
goto ex_resize;
1036+
}
1037+
1038+
if (udata)
1039+
mlx5_ib_populate_pas(dev, cq->resize_umem, page_shift,
1040+
in->pas, 0);
1041+
else
1042+
mlx5_fill_page_array(&cq->resize_buf->buf, in->pas);
1043+
1044+
in->field_select = cpu_to_be32(MLX5_MODIFY_CQ_MASK_LOG_SIZE |
1045+
MLX5_MODIFY_CQ_MASK_PG_OFFSET |
1046+
MLX5_MODIFY_CQ_MASK_PG_SIZE);
1047+
in->ctx.log_pg_sz = page_shift - MLX5_ADAPTER_PAGE_SHIFT;
1048+
in->ctx.cqe_sz_flags = cqe_sz_to_mlx_sz(cqe_size) << 5;
1049+
in->ctx.page_offset = 0;
1050+
in->ctx.log_sz_usr_page = cpu_to_be32(ilog2(entries) << 24);
1051+
in->hdr.opmod = cpu_to_be16(MLX5_CQ_OPMOD_RESIZE);
1052+
in->cqn = cpu_to_be32(cq->mcq.cqn);
1053+
1054+
err = mlx5_core_modify_cq(&dev->mdev, &cq->mcq, in, inlen);
1055+
if (err)
1056+
goto ex_alloc;
1057+
1058+
if (udata) {
1059+
cq->ibcq.cqe = entries - 1;
1060+
ib_umem_release(cq->buf.umem);
1061+
cq->buf.umem = cq->resize_umem;
1062+
cq->resize_umem = NULL;
1063+
} else {
1064+
struct mlx5_ib_cq_buf tbuf;
1065+
int resized = 0;
1066+
1067+
spin_lock_irqsave(&cq->lock, flags);
1068+
if (cq->resize_buf) {
1069+
err = copy_resize_cqes(cq);
1070+
if (!err) {
1071+
tbuf = cq->buf;
1072+
cq->buf = *cq->resize_buf;
1073+
kfree(cq->resize_buf);
1074+
cq->resize_buf = NULL;
1075+
resized = 1;
1076+
}
1077+
}
1078+
cq->ibcq.cqe = entries - 1;
1079+
spin_unlock_irqrestore(&cq->lock, flags);
1080+
if (resized)
1081+
free_cq_buf(dev, &tbuf);
1082+
}
1083+
mutex_unlock(&cq->resize_mutex);
1084+
1085+
mlx5_vfree(in);
1086+
return 0;
1087+
1088+
ex_alloc:
1089+
mlx5_vfree(in);
1090+
1091+
ex_resize:
1092+
if (udata)
1093+
un_resize_user(cq);
1094+
else
1095+
un_resize_kernel(dev, cq);
1096+
ex:
1097+
mutex_unlock(&cq->resize_mutex);
1098+
return err;
8511099
}
8521100

8531101
int mlx5_ib_get_cqe_size(struct mlx5_ib_dev *dev, struct ib_cq *ibcq)

drivers/infiniband/hw/mlx5/mlx5_ib.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ struct mlx5_ib_cq_buf {
195195
struct mlx5_buf buf;
196196
struct ib_umem *umem;
197197
int cqe_size;
198+
int nent;
198199
};
199200

200201
enum mlx5_ib_qp_flags {
@@ -220,7 +221,7 @@ struct mlx5_ib_cq {
220221
/* protect resize cq
221222
*/
222223
struct mutex resize_mutex;
223-
struct mlx5_ib_cq_resize *resize_buf;
224+
struct mlx5_ib_cq_buf *resize_buf;
224225
struct ib_umem *resize_umem;
225226
int cqe_size;
226227
};

drivers/infiniband/hw/mlx5/user.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ struct mlx5_ib_create_cq_resp {
9393

9494
struct mlx5_ib_resize_cq {
9595
__u64 buf_addr;
96+
__u16 cqe_size;
97+
__u16 reserved0;
98+
__u32 reserved1;
9699
};
97100

98101
struct mlx5_ib_create_srq {

0 commit comments

Comments
 (0)