xref: /freebsd/sys/dev/mlx4/mlx4_ib/mlx4_ib_srq.c (revision b633e08c705fe43180567eae26923d6f6f98c8d9)
197549c34SHans Petter Selasky /*
297549c34SHans Petter Selasky  * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
397549c34SHans Petter Selasky  * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
497549c34SHans Petter Selasky  *
597549c34SHans Petter Selasky  * This software is available to you under a choice of one of two
697549c34SHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
797549c34SHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
897549c34SHans Petter Selasky  * COPYING in the main directory of this source tree, or the
997549c34SHans Petter Selasky  * OpenIB.org BSD license below:
1097549c34SHans Petter Selasky  *
1197549c34SHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
1297549c34SHans Petter Selasky  *     without modification, are permitted provided that the following
1397549c34SHans Petter Selasky  *     conditions are met:
1497549c34SHans Petter Selasky  *
1597549c34SHans Petter Selasky  *      - Redistributions of source code must retain the above
1697549c34SHans Petter Selasky  *        copyright notice, this list of conditions and the following
1797549c34SHans Petter Selasky  *        disclaimer.
1897549c34SHans Petter Selasky  *
1997549c34SHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
2097549c34SHans Petter Selasky  *        copyright notice, this list of conditions and the following
2197549c34SHans Petter Selasky  *        disclaimer in the documentation and/or other materials
2297549c34SHans Petter Selasky  *        provided with the distribution.
2397549c34SHans Petter Selasky  *
2497549c34SHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2597549c34SHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2697549c34SHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2797549c34SHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2897549c34SHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2997549c34SHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3097549c34SHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3197549c34SHans Petter Selasky  * SOFTWARE.
3297549c34SHans Petter Selasky  */
3397549c34SHans Petter Selasky 
3497549c34SHans Petter Selasky #include <dev/mlx4/qp.h>
3597549c34SHans Petter Selasky #include <dev/mlx4/srq.h>
3697549c34SHans Petter Selasky #include <linux/slab.h>
3797549c34SHans Petter Selasky 
3897549c34SHans Petter Selasky #include "mlx4_ib.h"
398cc48704SHans Petter Selasky #include <rdma/mlx4-abi.h>
40*b633e08cSHans Petter Selasky #include <rdma/uverbs_ioctl.h>
4197549c34SHans Petter Selasky 
get_wqe(struct mlx4_ib_srq * srq,int n)4297549c34SHans Petter Selasky static void *get_wqe(struct mlx4_ib_srq *srq, int n)
4397549c34SHans Petter Selasky {
4497549c34SHans Petter Selasky 	return mlx4_buf_offset(&srq->buf, n << srq->msrq.wqe_shift);
4597549c34SHans Petter Selasky }
4697549c34SHans Petter Selasky 
mlx4_ib_srq_event(struct mlx4_srq * srq,enum mlx4_event type)4797549c34SHans Petter Selasky static void mlx4_ib_srq_event(struct mlx4_srq *srq, enum mlx4_event type)
4897549c34SHans Petter Selasky {
4997549c34SHans Petter Selasky 	struct ib_event event;
5097549c34SHans Petter Selasky 	struct ib_srq *ibsrq = &to_mibsrq(srq)->ibsrq;
5197549c34SHans Petter Selasky 
5297549c34SHans Petter Selasky 	if (ibsrq->event_handler) {
5397549c34SHans Petter Selasky 		event.device      = ibsrq->device;
5497549c34SHans Petter Selasky 		event.element.srq = ibsrq;
5597549c34SHans Petter Selasky 		switch (type) {
5697549c34SHans Petter Selasky 		case MLX4_EVENT_TYPE_SRQ_LIMIT:
5797549c34SHans Petter Selasky 			event.event = IB_EVENT_SRQ_LIMIT_REACHED;
5897549c34SHans Petter Selasky 			break;
5997549c34SHans Petter Selasky 		case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR:
6097549c34SHans Petter Selasky 			event.event = IB_EVENT_SRQ_ERR;
6197549c34SHans Petter Selasky 			break;
6297549c34SHans Petter Selasky 		default:
6397549c34SHans Petter Selasky 			pr_warn("Unexpected event type %d "
6497549c34SHans Petter Selasky 			       "on SRQ %06x\n", type, srq->srqn);
6597549c34SHans Petter Selasky 			return;
6697549c34SHans Petter Selasky 		}
6797549c34SHans Petter Selasky 
6897549c34SHans Petter Selasky 		ibsrq->event_handler(&event, ibsrq->srq_context);
6997549c34SHans Petter Selasky 	}
7097549c34SHans Petter Selasky }
7197549c34SHans Petter Selasky 
mlx4_ib_create_srq(struct ib_srq * ib_srq,struct ib_srq_init_attr * init_attr,struct ib_udata * udata)72*b633e08cSHans Petter Selasky int mlx4_ib_create_srq(struct ib_srq *ib_srq,
7397549c34SHans Petter Selasky 		       struct ib_srq_init_attr *init_attr,
7497549c34SHans Petter Selasky 		       struct ib_udata *udata)
7597549c34SHans Petter Selasky {
76*b633e08cSHans Petter Selasky 	struct mlx4_ib_dev *dev = to_mdev(ib_srq->device);
77*b633e08cSHans Petter Selasky 	struct mlx4_ib_ucontext *ucontext = rdma_udata_to_drv_context(
78*b633e08cSHans Petter Selasky 		udata, struct mlx4_ib_ucontext, ibucontext);
79*b633e08cSHans Petter Selasky 	struct mlx4_ib_srq *srq = to_msrq(ib_srq);
8097549c34SHans Petter Selasky 	struct mlx4_wqe_srq_next_seg *next;
8197549c34SHans Petter Selasky 	struct mlx4_wqe_data_seg *scatter;
8297549c34SHans Petter Selasky 	u32 cqn;
8397549c34SHans Petter Selasky 	u16 xrcdn;
8497549c34SHans Petter Selasky 	int desc_size;
8597549c34SHans Petter Selasky 	int buf_size;
8697549c34SHans Petter Selasky 	int err;
8797549c34SHans Petter Selasky 	int i;
8897549c34SHans Petter Selasky 
8997549c34SHans Petter Selasky 	/* Sanity check SRQ size before proceeding */
9097549c34SHans Petter Selasky 	if (init_attr->attr.max_wr  >= dev->dev->caps.max_srq_wqes ||
9197549c34SHans Petter Selasky 	    init_attr->attr.max_sge >  dev->dev->caps.max_srq_sge)
92*b633e08cSHans Petter Selasky 		return -EINVAL;
9397549c34SHans Petter Selasky 
9497549c34SHans Petter Selasky 	mutex_init(&srq->mutex);
9597549c34SHans Petter Selasky 	spin_lock_init(&srq->lock);
9697549c34SHans Petter Selasky 	srq->msrq.max    = roundup_pow_of_two(init_attr->attr.max_wr + 1);
9797549c34SHans Petter Selasky 	srq->msrq.max_gs = init_attr->attr.max_sge;
9897549c34SHans Petter Selasky 
9997549c34SHans Petter Selasky 	desc_size = max(32UL,
10097549c34SHans Petter Selasky 			roundup_pow_of_two(sizeof (struct mlx4_wqe_srq_next_seg) +
10197549c34SHans Petter Selasky 					   srq->msrq.max_gs *
10297549c34SHans Petter Selasky 					   sizeof (struct mlx4_wqe_data_seg)));
10397549c34SHans Petter Selasky 	srq->msrq.wqe_shift = ilog2(desc_size);
10497549c34SHans Petter Selasky 
10597549c34SHans Petter Selasky 	buf_size = srq->msrq.max * desc_size;
10697549c34SHans Petter Selasky 
107*b633e08cSHans Petter Selasky 	if (udata) {
10897549c34SHans Petter Selasky 		struct mlx4_ib_create_srq ucmd;
10997549c34SHans Petter Selasky 
110*b633e08cSHans Petter Selasky 		if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
111*b633e08cSHans Petter Selasky 			return -EFAULT;
11297549c34SHans Petter Selasky 
113*b633e08cSHans Petter Selasky 		srq->umem =
114*b633e08cSHans Petter Selasky 			ib_umem_get(&ucontext->ibucontext, ucmd.buf_addr, buf_size, 0, 0);
115*b633e08cSHans Petter Selasky 		if (IS_ERR(srq->umem))
116*b633e08cSHans Petter Selasky 			return PTR_ERR(srq->umem);
11797549c34SHans Petter Selasky 
11897549c34SHans Petter Selasky 		err = mlx4_mtt_init(dev->dev, ib_umem_page_count(srq->umem),
11997549c34SHans Petter Selasky 				    ilog2(srq->umem->page_size), &srq->mtt);
12097549c34SHans Petter Selasky 		if (err)
12197549c34SHans Petter Selasky 			goto err_buf;
12297549c34SHans Petter Selasky 
12397549c34SHans Petter Selasky 		err = mlx4_ib_umem_write_mtt(dev, &srq->mtt, srq->umem);
12497549c34SHans Petter Selasky 		if (err)
12597549c34SHans Petter Selasky 			goto err_mtt;
12697549c34SHans Petter Selasky 
127*b633e08cSHans Petter Selasky 		err = mlx4_ib_db_map_user(ucontext,
12897549c34SHans Petter Selasky 					  ucmd.db_addr, &srq->db);
12997549c34SHans Petter Selasky 		if (err)
13097549c34SHans Petter Selasky 			goto err_mtt;
13197549c34SHans Petter Selasky 	} else {
1328cc48704SHans Petter Selasky 		err = mlx4_db_alloc(dev->dev, &srq->db, 0, GFP_KERNEL);
13397549c34SHans Petter Selasky 		if (err)
134*b633e08cSHans Petter Selasky 			return err;
13597549c34SHans Petter Selasky 
13697549c34SHans Petter Selasky 		*srq->db.db = 0;
13797549c34SHans Petter Selasky 
1388cc48704SHans Petter Selasky 		if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2, &srq->buf,
1398cc48704SHans Petter Selasky 				   GFP_KERNEL)) {
14097549c34SHans Petter Selasky 			err = -ENOMEM;
14197549c34SHans Petter Selasky 			goto err_db;
14297549c34SHans Petter Selasky 		}
14397549c34SHans Petter Selasky 
14497549c34SHans Petter Selasky 		srq->head    = 0;
14597549c34SHans Petter Selasky 		srq->tail    = srq->msrq.max - 1;
14697549c34SHans Petter Selasky 		srq->wqe_ctr = 0;
14797549c34SHans Petter Selasky 
14897549c34SHans Petter Selasky 		for (i = 0; i < srq->msrq.max; ++i) {
14997549c34SHans Petter Selasky 			next = get_wqe(srq, i);
15097549c34SHans Petter Selasky 			next->next_wqe_index =
15197549c34SHans Petter Selasky 				cpu_to_be16((i + 1) & (srq->msrq.max - 1));
15297549c34SHans Petter Selasky 
15397549c34SHans Petter Selasky 			for (scatter = (void *) (next + 1);
15497549c34SHans Petter Selasky 			     (void *) scatter < (void *) next + desc_size;
15597549c34SHans Petter Selasky 			     ++scatter)
15697549c34SHans Petter Selasky 				scatter->lkey = cpu_to_be32(MLX4_INVALID_LKEY);
15797549c34SHans Petter Selasky 		}
15897549c34SHans Petter Selasky 
15997549c34SHans Petter Selasky 		err = mlx4_mtt_init(dev->dev, srq->buf.npages, srq->buf.page_shift,
16097549c34SHans Petter Selasky 				    &srq->mtt);
16197549c34SHans Petter Selasky 		if (err)
16297549c34SHans Petter Selasky 			goto err_buf;
16397549c34SHans Petter Selasky 
1648cc48704SHans Petter Selasky 		err = mlx4_buf_write_mtt(dev->dev, &srq->mtt, &srq->buf, GFP_KERNEL);
16597549c34SHans Petter Selasky 		if (err)
16697549c34SHans Petter Selasky 			goto err_mtt;
16797549c34SHans Petter Selasky 
1688cc48704SHans Petter Selasky 		srq->wrid = kmalloc_array(srq->msrq.max, sizeof(u64),
1698cc48704SHans Petter Selasky 					GFP_KERNEL | __GFP_NOWARN);
1708cc48704SHans Petter Selasky 		if (!srq->wrid) {
1718cc48704SHans Petter Selasky 			srq->wrid = __vmalloc(srq->msrq.max * sizeof(u64),
1728cc48704SHans Petter Selasky 					      GFP_KERNEL, 0 /*PAGE_KERNEL*/);
17397549c34SHans Petter Selasky 			if (!srq->wrid) {
17497549c34SHans Petter Selasky 				err = -ENOMEM;
17597549c34SHans Petter Selasky 				goto err_mtt;
17697549c34SHans Petter Selasky 			}
17797549c34SHans Petter Selasky 		}
1788cc48704SHans Petter Selasky 	}
17997549c34SHans Petter Selasky 
18097549c34SHans Petter Selasky 	cqn = (init_attr->srq_type == IB_SRQT_XRC) ?
181*b633e08cSHans Petter Selasky 		to_mcq(init_attr->ext.cq)->mcq.cqn : 0;
18297549c34SHans Petter Selasky 	xrcdn = (init_attr->srq_type == IB_SRQT_XRC) ?
18397549c34SHans Petter Selasky 		to_mxrcd(init_attr->ext.xrc.xrcd)->xrcdn :
18497549c34SHans Petter Selasky 		(u16) dev->dev->caps.reserved_xrcds;
185*b633e08cSHans Petter Selasky 	err = mlx4_srq_alloc(dev->dev, to_mpd(ib_srq->pd)->pdn, cqn, xrcdn,
186*b633e08cSHans Petter Selasky 			     &srq->mtt, srq->db.dma, &srq->msrq);
18797549c34SHans Petter Selasky 	if (err)
18897549c34SHans Petter Selasky 		goto err_wrid;
18997549c34SHans Petter Selasky 
19097549c34SHans Petter Selasky 	srq->msrq.event = mlx4_ib_srq_event;
19197549c34SHans Petter Selasky 	srq->ibsrq.ext.xrc.srq_num = srq->msrq.srqn;
19297549c34SHans Petter Selasky 
193*b633e08cSHans Petter Selasky 	if (udata)
19497549c34SHans Petter Selasky 		if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof (__u32))) {
19597549c34SHans Petter Selasky 			err = -EFAULT;
19697549c34SHans Petter Selasky 			goto err_wrid;
19797549c34SHans Petter Selasky 		}
19897549c34SHans Petter Selasky 
19997549c34SHans Petter Selasky 	init_attr->attr.max_wr = srq->msrq.max - 1;
20097549c34SHans Petter Selasky 
201*b633e08cSHans Petter Selasky 	return 0;
20297549c34SHans Petter Selasky 
20397549c34SHans Petter Selasky err_wrid:
204*b633e08cSHans Petter Selasky 	if (udata)
205*b633e08cSHans Petter Selasky 		mlx4_ib_db_unmap_user(ucontext, &srq->db);
20697549c34SHans Petter Selasky 	else
2078cc48704SHans Petter Selasky 		kvfree(srq->wrid);
20897549c34SHans Petter Selasky 
20997549c34SHans Petter Selasky err_mtt:
21097549c34SHans Petter Selasky 	mlx4_mtt_cleanup(dev->dev, &srq->mtt);
21197549c34SHans Petter Selasky 
21297549c34SHans Petter Selasky err_buf:
213*b633e08cSHans Petter Selasky 	if (!srq->umem)
21497549c34SHans Petter Selasky 		mlx4_buf_free(dev->dev, buf_size, &srq->buf);
215*b633e08cSHans Petter Selasky 	ib_umem_release(srq->umem);
21697549c34SHans Petter Selasky 
21797549c34SHans Petter Selasky err_db:
218*b633e08cSHans Petter Selasky 	if (!udata)
21997549c34SHans Petter Selasky 		mlx4_db_free(dev->dev, &srq->db);
22097549c34SHans Petter Selasky 
221*b633e08cSHans Petter Selasky 	return err;
22297549c34SHans Petter Selasky }
22397549c34SHans Petter Selasky 
mlx4_ib_modify_srq(struct ib_srq * ibsrq,struct ib_srq_attr * attr,enum ib_srq_attr_mask attr_mask,struct ib_udata * udata)22497549c34SHans Petter Selasky int mlx4_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
22597549c34SHans Petter Selasky 		       enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
22697549c34SHans Petter Selasky {
22797549c34SHans Petter Selasky 	struct mlx4_ib_dev *dev = to_mdev(ibsrq->device);
22897549c34SHans Petter Selasky 	struct mlx4_ib_srq *srq = to_msrq(ibsrq);
22997549c34SHans Petter Selasky 	int ret;
23097549c34SHans Petter Selasky 
23197549c34SHans Petter Selasky 	/* We don't support resizing SRQs (yet?) */
23297549c34SHans Petter Selasky 	if (attr_mask & IB_SRQ_MAX_WR)
23397549c34SHans Petter Selasky 		return -EINVAL;
23497549c34SHans Petter Selasky 
23597549c34SHans Petter Selasky 	if (attr_mask & IB_SRQ_LIMIT) {
23697549c34SHans Petter Selasky 		if (attr->srq_limit >= srq->msrq.max)
23797549c34SHans Petter Selasky 			return -EINVAL;
23897549c34SHans Petter Selasky 
23997549c34SHans Petter Selasky 		mutex_lock(&srq->mutex);
24097549c34SHans Petter Selasky 		ret = mlx4_srq_arm(dev->dev, &srq->msrq, attr->srq_limit);
24197549c34SHans Petter Selasky 		mutex_unlock(&srq->mutex);
24297549c34SHans Petter Selasky 
24397549c34SHans Petter Selasky 		if (ret)
24497549c34SHans Petter Selasky 			return ret;
24597549c34SHans Petter Selasky 	}
24697549c34SHans Petter Selasky 
24797549c34SHans Petter Selasky 	return 0;
24897549c34SHans Petter Selasky }
24997549c34SHans Petter Selasky 
mlx4_ib_query_srq(struct ib_srq * ibsrq,struct ib_srq_attr * srq_attr)25097549c34SHans Petter Selasky int mlx4_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
25197549c34SHans Petter Selasky {
25297549c34SHans Petter Selasky 	struct mlx4_ib_dev *dev = to_mdev(ibsrq->device);
25397549c34SHans Petter Selasky 	struct mlx4_ib_srq *srq = to_msrq(ibsrq);
25497549c34SHans Petter Selasky 	int ret;
25597549c34SHans Petter Selasky 	int limit_watermark;
25697549c34SHans Petter Selasky 
25797549c34SHans Petter Selasky 	ret = mlx4_srq_query(dev->dev, &srq->msrq, &limit_watermark);
25897549c34SHans Petter Selasky 	if (ret)
25997549c34SHans Petter Selasky 		return ret;
26097549c34SHans Petter Selasky 
26197549c34SHans Petter Selasky 	srq_attr->srq_limit = limit_watermark;
26297549c34SHans Petter Selasky 	srq_attr->max_wr    = srq->msrq.max - 1;
26397549c34SHans Petter Selasky 	srq_attr->max_sge   = srq->msrq.max_gs;
26497549c34SHans Petter Selasky 
26597549c34SHans Petter Selasky 	return 0;
26697549c34SHans Petter Selasky }
26797549c34SHans Petter Selasky 
mlx4_ib_destroy_srq(struct ib_srq * srq,struct ib_udata * udata)268*b633e08cSHans Petter Selasky void mlx4_ib_destroy_srq(struct ib_srq *srq, struct ib_udata *udata)
26997549c34SHans Petter Selasky {
27097549c34SHans Petter Selasky 	struct mlx4_ib_dev *dev = to_mdev(srq->device);
27197549c34SHans Petter Selasky 	struct mlx4_ib_srq *msrq = to_msrq(srq);
27297549c34SHans Petter Selasky 
27397549c34SHans Petter Selasky 	mlx4_srq_free(dev->dev, &msrq->msrq);
27497549c34SHans Petter Selasky 	mlx4_mtt_cleanup(dev->dev, &msrq->mtt);
27597549c34SHans Petter Selasky 
276*b633e08cSHans Petter Selasky 	if (udata) {
277*b633e08cSHans Petter Selasky 		mlx4_ib_db_unmap_user(
278*b633e08cSHans Petter Selasky 			rdma_udata_to_drv_context(
279*b633e08cSHans Petter Selasky 				udata,
280*b633e08cSHans Petter Selasky 				struct mlx4_ib_ucontext,
281*b633e08cSHans Petter Selasky 				ibucontext),
282*b633e08cSHans Petter Selasky 			&msrq->db);
28397549c34SHans Petter Selasky 	} else {
2848cc48704SHans Petter Selasky 		kvfree(msrq->wrid);
28597549c34SHans Petter Selasky 		mlx4_buf_free(dev->dev, msrq->msrq.max << msrq->msrq.wqe_shift,
28697549c34SHans Petter Selasky 			      &msrq->buf);
28797549c34SHans Petter Selasky 		mlx4_db_free(dev->dev, &msrq->db);
28897549c34SHans Petter Selasky 	}
289*b633e08cSHans Petter Selasky 	ib_umem_release(msrq->umem);
29097549c34SHans Petter Selasky }
29197549c34SHans Petter Selasky 
mlx4_ib_free_srq_wqe(struct mlx4_ib_srq * srq,int wqe_index)29297549c34SHans Petter Selasky void mlx4_ib_free_srq_wqe(struct mlx4_ib_srq *srq, int wqe_index)
29397549c34SHans Petter Selasky {
29497549c34SHans Petter Selasky 	struct mlx4_wqe_srq_next_seg *next;
29597549c34SHans Petter Selasky 
29697549c34SHans Petter Selasky 	/* always called with interrupts disabled. */
29797549c34SHans Petter Selasky 	spin_lock(&srq->lock);
29897549c34SHans Petter Selasky 
29997549c34SHans Petter Selasky 	next = get_wqe(srq, srq->tail);
30097549c34SHans Petter Selasky 	next->next_wqe_index = cpu_to_be16(wqe_index);
30197549c34SHans Petter Selasky 	srq->tail = wqe_index;
30297549c34SHans Petter Selasky 
30397549c34SHans Petter Selasky 	spin_unlock(&srq->lock);
30497549c34SHans Petter Selasky }
30597549c34SHans Petter Selasky 
mlx4_ib_post_srq_recv(struct ib_srq * ibsrq,const struct ib_recv_wr * wr,const struct ib_recv_wr ** bad_wr)306c3987b8eSHans Petter Selasky int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
307c3987b8eSHans Petter Selasky 			  const struct ib_recv_wr **bad_wr)
30897549c34SHans Petter Selasky {
30997549c34SHans Petter Selasky 	struct mlx4_ib_srq *srq = to_msrq(ibsrq);
31097549c34SHans Petter Selasky 	struct mlx4_wqe_srq_next_seg *next;
31197549c34SHans Petter Selasky 	struct mlx4_wqe_data_seg *scat;
31297549c34SHans Petter Selasky 	unsigned long flags;
31397549c34SHans Petter Selasky 	int err = 0;
31497549c34SHans Petter Selasky 	int nreq;
31597549c34SHans Petter Selasky 	int i;
3168cc48704SHans Petter Selasky 	struct mlx4_ib_dev *mdev = to_mdev(ibsrq->device);
31797549c34SHans Petter Selasky 
31897549c34SHans Petter Selasky 	spin_lock_irqsave(&srq->lock, flags);
3198cc48704SHans Petter Selasky 	if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
3208cc48704SHans Petter Selasky 		err = -EIO;
3218cc48704SHans Petter Selasky 		*bad_wr = wr;
3228cc48704SHans Petter Selasky 		nreq = 0;
3238cc48704SHans Petter Selasky 		goto out;
3248cc48704SHans Petter Selasky 	}
32597549c34SHans Petter Selasky 
32697549c34SHans Petter Selasky 	for (nreq = 0; wr; ++nreq, wr = wr->next) {
32797549c34SHans Petter Selasky 		if (unlikely(wr->num_sge > srq->msrq.max_gs)) {
32897549c34SHans Petter Selasky 			err = -EINVAL;
32997549c34SHans Petter Selasky 			*bad_wr = wr;
33097549c34SHans Petter Selasky 			break;
33197549c34SHans Petter Selasky 		}
33297549c34SHans Petter Selasky 
33397549c34SHans Petter Selasky 		if (unlikely(srq->head == srq->tail)) {
33497549c34SHans Petter Selasky 			err = -ENOMEM;
33597549c34SHans Petter Selasky 			*bad_wr = wr;
33697549c34SHans Petter Selasky 			break;
33797549c34SHans Petter Selasky 		}
33897549c34SHans Petter Selasky 
33997549c34SHans Petter Selasky 		srq->wrid[srq->head] = wr->wr_id;
34097549c34SHans Petter Selasky 
34197549c34SHans Petter Selasky 		next      = get_wqe(srq, srq->head);
34297549c34SHans Petter Selasky 		srq->head = be16_to_cpu(next->next_wqe_index);
34397549c34SHans Petter Selasky 		scat      = (struct mlx4_wqe_data_seg *) (next + 1);
34497549c34SHans Petter Selasky 
34597549c34SHans Petter Selasky 		for (i = 0; i < wr->num_sge; ++i) {
34697549c34SHans Petter Selasky 			scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length);
34797549c34SHans Petter Selasky 			scat[i].lkey       = cpu_to_be32(wr->sg_list[i].lkey);
34897549c34SHans Petter Selasky 			scat[i].addr       = cpu_to_be64(wr->sg_list[i].addr);
34997549c34SHans Petter Selasky 		}
35097549c34SHans Petter Selasky 
35197549c34SHans Petter Selasky 		if (i < srq->msrq.max_gs) {
35297549c34SHans Petter Selasky 			scat[i].byte_count = 0;
35397549c34SHans Petter Selasky 			scat[i].lkey       = cpu_to_be32(MLX4_INVALID_LKEY);
35497549c34SHans Petter Selasky 			scat[i].addr       = 0;
35597549c34SHans Petter Selasky 		}
35697549c34SHans Petter Selasky 	}
35797549c34SHans Petter Selasky 
35897549c34SHans Petter Selasky 	if (likely(nreq)) {
35997549c34SHans Petter Selasky 		srq->wqe_ctr += nreq;
36097549c34SHans Petter Selasky 
36197549c34SHans Petter Selasky 		/*
36297549c34SHans Petter Selasky 		 * Make sure that descriptors are written before
36397549c34SHans Petter Selasky 		 * doorbell record.
36497549c34SHans Petter Selasky 		 */
36597549c34SHans Petter Selasky 		wmb();
36697549c34SHans Petter Selasky 
36797549c34SHans Petter Selasky 		*srq->db.db = cpu_to_be32(srq->wqe_ctr);
36897549c34SHans Petter Selasky 	}
3698cc48704SHans Petter Selasky out:
37097549c34SHans Petter Selasky 
37197549c34SHans Petter Selasky 	spin_unlock_irqrestore(&srq->lock, flags);
37297549c34SHans Petter Selasky 
37397549c34SHans Petter Selasky 	return err;
37497549c34SHans Petter Selasky }
375