Skip to content

Commit 79b20a6

Browse files
yishaihdledford
authored andcommitted
IB/mlx5: Add receive Work Queue verbs
A QP can be created without internal WQs "packaged" inside it, this QP can be configured to use "external" WQ object as its receive/send queue. WQ is a necessary component for RSS technology since RSS mechanism is supposed to distribute the traffic between multiple Receive Work Queues Receive WQs are implemented by RQs. Implement the WQ creation, modification and destruction verbs. Signed-off-by: Yishai Hadas <[email protected]> Signed-off-by: Matan Barak <[email protected]> Reviewed-by: Sagi Grimberg <[email protected]> Signed-off-by: Doug Ledford <[email protected]>
1 parent f213c05 commit 79b20a6

File tree

4 files changed

+373
-1
lines changed

4 files changed

+373
-1
lines changed

drivers/infiniband/hw/mlx5/main.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2450,9 +2450,15 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
24502450
IB_LINK_LAYER_ETHERNET) {
24512451
dev->ib_dev.create_flow = mlx5_ib_create_flow;
24522452
dev->ib_dev.destroy_flow = mlx5_ib_destroy_flow;
2453+
dev->ib_dev.create_wq = mlx5_ib_create_wq;
2454+
dev->ib_dev.modify_wq = mlx5_ib_modify_wq;
2455+
dev->ib_dev.destroy_wq = mlx5_ib_destroy_wq;
24532456
dev->ib_dev.uverbs_ex_cmd_mask |=
24542457
(1ull << IB_USER_VERBS_EX_CMD_CREATE_FLOW) |
2455-
(1ull << IB_USER_VERBS_EX_CMD_DESTROY_FLOW);
2458+
(1ull << IB_USER_VERBS_EX_CMD_DESTROY_FLOW) |
2459+
(1ull << IB_USER_VERBS_EX_CMD_CREATE_WQ) |
2460+
(1ull << IB_USER_VERBS_EX_CMD_MODIFY_WQ) |
2461+
(1ull << IB_USER_VERBS_EX_CMD_DESTROY_WQ);
24562462
}
24572463
err = init_node_data(dev);
24582464
if (err)

drivers/infiniband/hw/mlx5/mlx5_ib.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,12 +217,36 @@ struct mlx5_ib_wq {
217217
void *qend;
218218
};
219219

220+
struct mlx5_ib_rwq {
221+
struct ib_wq ibwq;
222+
u32 rqn;
223+
u32 rq_num_pas;
224+
u32 log_rq_stride;
225+
u32 log_rq_size;
226+
u32 rq_page_offset;
227+
u32 log_page_size;
228+
struct ib_umem *umem;
229+
size_t buf_size;
230+
unsigned int page_shift;
231+
int create_type;
232+
struct mlx5_db db;
233+
u32 user_index;
234+
u32 wqe_count;
235+
u32 wqe_shift;
236+
int wq_sig;
237+
};
238+
220239
enum {
221240
MLX5_QP_USER,
222241
MLX5_QP_KERNEL,
223242
MLX5_QP_EMPTY
224243
};
225244

245+
enum {
246+
MLX5_WQ_USER,
247+
MLX5_WQ_KERNEL
248+
};
249+
226250
/*
227251
* Connect-IB can trigger up to four concurrent pagefaults
228252
* per-QP.
@@ -628,6 +652,11 @@ static inline struct mlx5_ib_qp *to_mqp(struct ib_qp *ibqp)
628652
return container_of(ibqp, struct mlx5_ib_qp, ibqp);
629653
}
630654

655+
static inline struct mlx5_ib_rwq *to_mrwq(struct ib_wq *ibwq)
656+
{
657+
return container_of(ibwq, struct mlx5_ib_rwq, ibwq);
658+
}
659+
631660
static inline struct mlx5_ib_srq *to_mibsrq(struct mlx5_core_srq *msrq)
632661
{
633662
return container_of(msrq, struct mlx5_ib_srq, msrq);
@@ -762,6 +791,12 @@ int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev);
762791
int mlx5_mr_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift);
763792
int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
764793
struct ib_mr_status *mr_status);
794+
struct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd,
795+
struct ib_wq_init_attr *init_attr,
796+
struct ib_udata *udata);
797+
int mlx5_ib_destroy_wq(struct ib_wq *wq);
798+
int mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr,
799+
u32 wq_attr_mask, struct ib_udata *udata);
765800

766801
#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
767802
extern struct workqueue_struct *mlx5_ib_page_fault_wq;

drivers/infiniband/hw/mlx5/qp.c

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,71 @@ static int mlx5_ib_umem_get(struct mlx5_ib_dev *dev,
649649
return err;
650650
}
651651

652+
static void destroy_user_rq(struct ib_pd *pd, struct mlx5_ib_rwq *rwq)
653+
{
654+
struct mlx5_ib_ucontext *context;
655+
656+
context = to_mucontext(pd->uobject->context);
657+
mlx5_ib_db_unmap_user(context, &rwq->db);
658+
if (rwq->umem)
659+
ib_umem_release(rwq->umem);
660+
}
661+
662+
static int create_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd,
663+
struct mlx5_ib_rwq *rwq,
664+
struct mlx5_ib_create_wq *ucmd)
665+
{
666+
struct mlx5_ib_ucontext *context;
667+
int page_shift = 0;
668+
int npages;
669+
u32 offset = 0;
670+
int ncont = 0;
671+
int err;
672+
673+
if (!ucmd->buf_addr)
674+
return -EINVAL;
675+
676+
context = to_mucontext(pd->uobject->context);
677+
rwq->umem = ib_umem_get(pd->uobject->context, ucmd->buf_addr,
678+
rwq->buf_size, 0, 0);
679+
if (IS_ERR(rwq->umem)) {
680+
mlx5_ib_dbg(dev, "umem_get failed\n");
681+
err = PTR_ERR(rwq->umem);
682+
return err;
683+
}
684+
685+
mlx5_ib_cont_pages(rwq->umem, ucmd->buf_addr, &npages, &page_shift,
686+
&ncont, NULL);
687+
err = mlx5_ib_get_buf_offset(ucmd->buf_addr, page_shift,
688+
&rwq->rq_page_offset);
689+
if (err) {
690+
mlx5_ib_warn(dev, "bad offset\n");
691+
goto err_umem;
692+
}
693+
694+
rwq->rq_num_pas = ncont;
695+
rwq->page_shift = page_shift;
696+
rwq->log_page_size = page_shift - MLX5_ADAPTER_PAGE_SHIFT;
697+
rwq->wq_sig = !!(ucmd->flags & MLX5_WQ_FLAG_SIGNATURE);
698+
699+
mlx5_ib_dbg(dev, "addr 0x%llx, size %zd, npages %d, page_shift %d, ncont %d, offset %d\n",
700+
(unsigned long long)ucmd->buf_addr, rwq->buf_size,
701+
npages, page_shift, ncont, offset);
702+
703+
err = mlx5_ib_db_map_user(context, ucmd->db_addr, &rwq->db);
704+
if (err) {
705+
mlx5_ib_dbg(dev, "map failed\n");
706+
goto err_umem;
707+
}
708+
709+
rwq->create_type = MLX5_WQ_USER;
710+
return 0;
711+
712+
err_umem:
713+
ib_umem_release(rwq->umem);
714+
return err;
715+
}
716+
652717
static int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd,
653718
struct mlx5_ib_qp *qp, struct ib_udata *udata,
654719
struct ib_qp_init_attr *attr,
@@ -4163,3 +4228,244 @@ int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd)
41634228

41644229
return 0;
41654230
}
4231+
4232+
static int create_rq(struct mlx5_ib_rwq *rwq, struct ib_pd *pd,
4233+
struct ib_wq_init_attr *init_attr)
4234+
{
4235+
struct mlx5_ib_dev *dev;
4236+
__be64 *rq_pas0;
4237+
void *in;
4238+
void *rqc;
4239+
void *wq;
4240+
int inlen;
4241+
int err;
4242+
4243+
dev = to_mdev(pd->device);
4244+
4245+
inlen = MLX5_ST_SZ_BYTES(create_rq_in) + sizeof(u64) * rwq->rq_num_pas;
4246+
in = mlx5_vzalloc(inlen);
4247+
if (!in)
4248+
return -ENOMEM;
4249+
4250+
rqc = MLX5_ADDR_OF(create_rq_in, in, ctx);
4251+
MLX5_SET(rqc, rqc, mem_rq_type,
4252+
MLX5_RQC_MEM_RQ_TYPE_MEMORY_RQ_INLINE);
4253+
MLX5_SET(rqc, rqc, user_index, rwq->user_index);
4254+
MLX5_SET(rqc, rqc, cqn, to_mcq(init_attr->cq)->mcq.cqn);
4255+
MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RST);
4256+
MLX5_SET(rqc, rqc, flush_in_error_en, 1);
4257+
wq = MLX5_ADDR_OF(rqc, rqc, wq);
4258+
MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
4259+
MLX5_SET(wq, wq, end_padding_mode, MLX5_WQ_END_PAD_MODE_ALIGN);
4260+
MLX5_SET(wq, wq, log_wq_stride, rwq->log_rq_stride);
4261+
MLX5_SET(wq, wq, log_wq_sz, rwq->log_rq_size);
4262+
MLX5_SET(wq, wq, pd, to_mpd(pd)->pdn);
4263+
MLX5_SET(wq, wq, page_offset, rwq->rq_page_offset);
4264+
MLX5_SET(wq, wq, log_wq_pg_sz, rwq->log_page_size);
4265+
MLX5_SET(wq, wq, wq_signature, rwq->wq_sig);
4266+
MLX5_SET64(wq, wq, dbr_addr, rwq->db.dma);
4267+
rq_pas0 = (__be64 *)MLX5_ADDR_OF(wq, wq, pas);
4268+
mlx5_ib_populate_pas(dev, rwq->umem, rwq->page_shift, rq_pas0, 0);
4269+
err = mlx5_core_create_rq(dev->mdev, in, inlen, &rwq->rqn);
4270+
kvfree(in);
4271+
return err;
4272+
}
4273+
4274+
static int set_user_rq_size(struct mlx5_ib_dev *dev,
4275+
struct ib_wq_init_attr *wq_init_attr,
4276+
struct mlx5_ib_create_wq *ucmd,
4277+
struct mlx5_ib_rwq *rwq)
4278+
{
4279+
/* Sanity check RQ size before proceeding */
4280+
if (wq_init_attr->max_wr > (1 << MLX5_CAP_GEN(dev->mdev, log_max_wq_sz)))
4281+
return -EINVAL;
4282+
4283+
if (!ucmd->rq_wqe_count)
4284+
return -EINVAL;
4285+
4286+
rwq->wqe_count = ucmd->rq_wqe_count;
4287+
rwq->wqe_shift = ucmd->rq_wqe_shift;
4288+
rwq->buf_size = (rwq->wqe_count << rwq->wqe_shift);
4289+
rwq->log_rq_stride = rwq->wqe_shift;
4290+
rwq->log_rq_size = ilog2(rwq->wqe_count);
4291+
return 0;
4292+
}
4293+
4294+
static int prepare_user_rq(struct ib_pd *pd,
4295+
struct ib_wq_init_attr *init_attr,
4296+
struct ib_udata *udata,
4297+
struct mlx5_ib_rwq *rwq)
4298+
{
4299+
struct mlx5_ib_dev *dev = to_mdev(pd->device);
4300+
struct mlx5_ib_create_wq ucmd = {};
4301+
int err;
4302+
size_t required_cmd_sz;
4303+
4304+
required_cmd_sz = offsetof(typeof(ucmd), reserved) + sizeof(ucmd.reserved);
4305+
if (udata->inlen < required_cmd_sz) {
4306+
mlx5_ib_dbg(dev, "invalid inlen\n");
4307+
return -EINVAL;
4308+
}
4309+
4310+
if (udata->inlen > sizeof(ucmd) &&
4311+
!ib_is_udata_cleared(udata, sizeof(ucmd),
4312+
udata->inlen - sizeof(ucmd))) {
4313+
mlx5_ib_dbg(dev, "inlen is not supported\n");
4314+
return -EOPNOTSUPP;
4315+
}
4316+
4317+
if (ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen))) {
4318+
mlx5_ib_dbg(dev, "copy failed\n");
4319+
return -EFAULT;
4320+
}
4321+
4322+
if (ucmd.comp_mask) {
4323+
mlx5_ib_dbg(dev, "invalid comp mask\n");
4324+
return -EOPNOTSUPP;
4325+
}
4326+
4327+
if (ucmd.reserved) {
4328+
mlx5_ib_dbg(dev, "invalid reserved\n");
4329+
return -EOPNOTSUPP;
4330+
}
4331+
4332+
err = set_user_rq_size(dev, init_attr, &ucmd, rwq);
4333+
if (err) {
4334+
mlx5_ib_dbg(dev, "err %d\n", err);
4335+
return err;
4336+
}
4337+
4338+
err = create_user_rq(dev, pd, rwq, &ucmd);
4339+
if (err) {
4340+
mlx5_ib_dbg(dev, "err %d\n", err);
4341+
if (err)
4342+
return err;
4343+
}
4344+
4345+
rwq->user_index = ucmd.user_index;
4346+
return 0;
4347+
}
4348+
4349+
struct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd,
4350+
struct ib_wq_init_attr *init_attr,
4351+
struct ib_udata *udata)
4352+
{
4353+
struct mlx5_ib_dev *dev;
4354+
struct mlx5_ib_rwq *rwq;
4355+
struct mlx5_ib_create_wq_resp resp = {};
4356+
size_t min_resp_len;
4357+
int err;
4358+
4359+
if (!udata)
4360+
return ERR_PTR(-ENOSYS);
4361+
4362+
min_resp_len = offsetof(typeof(resp), reserved) + sizeof(resp.reserved);
4363+
if (udata->outlen && udata->outlen < min_resp_len)
4364+
return ERR_PTR(-EINVAL);
4365+
4366+
dev = to_mdev(pd->device);
4367+
switch (init_attr->wq_type) {
4368+
case IB_WQT_RQ:
4369+
rwq = kzalloc(sizeof(*rwq), GFP_KERNEL);
4370+
if (!rwq)
4371+
return ERR_PTR(-ENOMEM);
4372+
err = prepare_user_rq(pd, init_attr, udata, rwq);
4373+
if (err)
4374+
goto err;
4375+
err = create_rq(rwq, pd, init_attr);
4376+
if (err)
4377+
goto err_user_rq;
4378+
break;
4379+
default:
4380+
mlx5_ib_dbg(dev, "unsupported wq type %d\n",
4381+
init_attr->wq_type);
4382+
return ERR_PTR(-EINVAL);
4383+
}
4384+
4385+
rwq->ibwq.wq_num = rwq->rqn;
4386+
rwq->ibwq.state = IB_WQS_RESET;
4387+
if (udata->outlen) {
4388+
resp.response_length = offsetof(typeof(resp), response_length) +
4389+
sizeof(resp.response_length);
4390+
err = ib_copy_to_udata(udata, &resp, resp.response_length);
4391+
if (err)
4392+
goto err_copy;
4393+
}
4394+
4395+
return &rwq->ibwq;
4396+
4397+
err_copy:
4398+
mlx5_core_destroy_rq(dev->mdev, rwq->rqn);
4399+
err_user_rq:
4400+
destroy_user_rq(pd, rwq);
4401+
err:
4402+
kfree(rwq);
4403+
return ERR_PTR(err);
4404+
}
4405+
4406+
int mlx5_ib_destroy_wq(struct ib_wq *wq)
4407+
{
4408+
struct mlx5_ib_dev *dev = to_mdev(wq->device);
4409+
struct mlx5_ib_rwq *rwq = to_mrwq(wq);
4410+
4411+
mlx5_core_destroy_rq(dev->mdev, rwq->rqn);
4412+
destroy_user_rq(wq->pd, rwq);
4413+
kfree(rwq);
4414+
4415+
return 0;
4416+
}
4417+
4418+
int mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr,
4419+
u32 wq_attr_mask, struct ib_udata *udata)
4420+
{
4421+
struct mlx5_ib_dev *dev = to_mdev(wq->device);
4422+
struct mlx5_ib_rwq *rwq = to_mrwq(wq);
4423+
struct mlx5_ib_modify_wq ucmd = {};
4424+
size_t required_cmd_sz;
4425+
int curr_wq_state;
4426+
int wq_state;
4427+
int inlen;
4428+
int err;
4429+
void *rqc;
4430+
void *in;
4431+
4432+
required_cmd_sz = offsetof(typeof(ucmd), reserved) + sizeof(ucmd.reserved);
4433+
if (udata->inlen < required_cmd_sz)
4434+
return -EINVAL;
4435+
4436+
if (udata->inlen > sizeof(ucmd) &&
4437+
!ib_is_udata_cleared(udata, sizeof(ucmd),
4438+
udata->inlen - sizeof(ucmd)))
4439+
return -EOPNOTSUPP;
4440+
4441+
if (ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen)))
4442+
return -EFAULT;
4443+
4444+
if (ucmd.comp_mask || ucmd.reserved)
4445+
return -EOPNOTSUPP;
4446+
4447+
inlen = MLX5_ST_SZ_BYTES(modify_rq_in);
4448+
in = mlx5_vzalloc(inlen);
4449+
if (!in)
4450+
return -ENOMEM;
4451+
4452+
rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
4453+
4454+
curr_wq_state = (wq_attr_mask & IB_WQ_CUR_STATE) ?
4455+
wq_attr->curr_wq_state : wq->state;
4456+
wq_state = (wq_attr_mask & IB_WQ_STATE) ?
4457+
wq_attr->wq_state : curr_wq_state;
4458+
if (curr_wq_state == IB_WQS_ERR)
4459+
curr_wq_state = MLX5_RQC_STATE_ERR;
4460+
if (wq_state == IB_WQS_ERR)
4461+
wq_state = MLX5_RQC_STATE_ERR;
4462+
MLX5_SET(modify_rq_in, in, rq_state, curr_wq_state);
4463+
MLX5_SET(rqc, rqc, state, wq_state);
4464+
4465+
err = mlx5_core_modify_rq(dev->mdev, rwq->rqn, in, inlen);
4466+
kvfree(in);
4467+
if (!err)
4468+
rwq->ibwq.state = (wq_state == MLX5_RQC_STATE_ERR) ? IB_WQS_ERR : wq_state;
4469+
4470+
return err;
4471+
}

0 commit comments

Comments
 (0)