162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This software is available to you under a choice of one of two
562306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
862306a36Sopenharmony_ci * OpenIB.org BSD license below:
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1162306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1262306a36Sopenharmony_ci *     conditions are met:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1562306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1662306a36Sopenharmony_ci *        disclaimer.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
1962306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2062306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2162306a36Sopenharmony_ci *        provided with the distribution.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3062306a36Sopenharmony_ci * SOFTWARE.
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <linux/module.h>
3462306a36Sopenharmony_ci#include <rdma/uverbs_ioctl.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include "iw_cxgb4.h"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic int db_delay_usecs = 1;
3962306a36Sopenharmony_cimodule_param(db_delay_usecs, int, 0644);
4062306a36Sopenharmony_ciMODULE_PARM_DESC(db_delay_usecs, "Usecs to delay awaiting db fifo to drain");
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic int ocqp_support = 1;
4362306a36Sopenharmony_cimodule_param(ocqp_support, int, 0644);
4462306a36Sopenharmony_ciMODULE_PARM_DESC(ocqp_support, "Support on-chip SQs (default=1)");
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ciint db_fc_threshold = 1000;
4762306a36Sopenharmony_cimodule_param(db_fc_threshold, int, 0644);
4862306a36Sopenharmony_ciMODULE_PARM_DESC(db_fc_threshold,
4962306a36Sopenharmony_ci		 "QP count/threshold that triggers"
5062306a36Sopenharmony_ci		 " automatic db flow control mode (default = 1000)");
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ciint db_coalescing_threshold;
5362306a36Sopenharmony_cimodule_param(db_coalescing_threshold, int, 0644);
5462306a36Sopenharmony_ciMODULE_PARM_DESC(db_coalescing_threshold,
5562306a36Sopenharmony_ci		 "QP count/threshold that triggers"
5662306a36Sopenharmony_ci		 " disabling db coalescing (default = 0)");
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic int max_fr_immd = T4_MAX_FR_IMMD;
5962306a36Sopenharmony_cimodule_param(max_fr_immd, int, 0644);
6062306a36Sopenharmony_ciMODULE_PARM_DESC(max_fr_immd, "fastreg threshold for using DSGL instead of immediate");
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic int alloc_ird(struct c4iw_dev *dev, u32 ird)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	int ret = 0;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	xa_lock_irq(&dev->qps);
6762306a36Sopenharmony_ci	if (ird <= dev->avail_ird)
6862306a36Sopenharmony_ci		dev->avail_ird -= ird;
6962306a36Sopenharmony_ci	else
7062306a36Sopenharmony_ci		ret = -ENOMEM;
7162306a36Sopenharmony_ci	xa_unlock_irq(&dev->qps);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (ret)
7462306a36Sopenharmony_ci		dev_warn(&dev->rdev.lldi.pdev->dev,
7562306a36Sopenharmony_ci			 "device IRD resources exhausted\n");
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	return ret;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic void free_ird(struct c4iw_dev *dev, int ird)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	xa_lock_irq(&dev->qps);
8362306a36Sopenharmony_ci	dev->avail_ird += ird;
8462306a36Sopenharmony_ci	xa_unlock_irq(&dev->qps);
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic void set_state(struct c4iw_qp *qhp, enum c4iw_qp_state state)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	unsigned long flag;
9062306a36Sopenharmony_ci	spin_lock_irqsave(&qhp->lock, flag);
9162306a36Sopenharmony_ci	qhp->attr.state = state;
9262306a36Sopenharmony_ci	spin_unlock_irqrestore(&qhp->lock, flag);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic void dealloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	c4iw_ocqp_pool_free(rdev, sq->dma_addr, sq->memsize);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic void dealloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	dma_free_coherent(&(rdev->lldi.pdev->dev), sq->memsize, sq->queue,
10362306a36Sopenharmony_ci			  dma_unmap_addr(sq, mapping));
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic void dealloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	if (t4_sq_onchip(sq))
10962306a36Sopenharmony_ci		dealloc_oc_sq(rdev, sq);
11062306a36Sopenharmony_ci	else
11162306a36Sopenharmony_ci		dealloc_host_sq(rdev, sq);
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic int alloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	if (!ocqp_support || !ocqp_supported(&rdev->lldi))
11762306a36Sopenharmony_ci		return -ENOSYS;
11862306a36Sopenharmony_ci	sq->dma_addr = c4iw_ocqp_pool_alloc(rdev, sq->memsize);
11962306a36Sopenharmony_ci	if (!sq->dma_addr)
12062306a36Sopenharmony_ci		return -ENOMEM;
12162306a36Sopenharmony_ci	sq->phys_addr = rdev->oc_mw_pa + sq->dma_addr -
12262306a36Sopenharmony_ci			rdev->lldi.vr->ocq.start;
12362306a36Sopenharmony_ci	sq->queue = (__force union t4_wr *)(rdev->oc_mw_kva + sq->dma_addr -
12462306a36Sopenharmony_ci					    rdev->lldi.vr->ocq.start);
12562306a36Sopenharmony_ci	sq->flags |= T4_SQ_ONCHIP;
12662306a36Sopenharmony_ci	return 0;
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic int alloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	sq->queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev), sq->memsize,
13262306a36Sopenharmony_ci				       &(sq->dma_addr), GFP_KERNEL);
13362306a36Sopenharmony_ci	if (!sq->queue)
13462306a36Sopenharmony_ci		return -ENOMEM;
13562306a36Sopenharmony_ci	sq->phys_addr = virt_to_phys(sq->queue);
13662306a36Sopenharmony_ci	dma_unmap_addr_set(sq, mapping, sq->dma_addr);
13762306a36Sopenharmony_ci	return 0;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic int alloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq, int user)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	int ret = -ENOSYS;
14362306a36Sopenharmony_ci	if (user)
14462306a36Sopenharmony_ci		ret = alloc_oc_sq(rdev, sq);
14562306a36Sopenharmony_ci	if (ret)
14662306a36Sopenharmony_ci		ret = alloc_host_sq(rdev, sq);
14762306a36Sopenharmony_ci	return ret;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic int destroy_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
15162306a36Sopenharmony_ci		      struct c4iw_dev_ucontext *uctx, int has_rq)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	/*
15462306a36Sopenharmony_ci	 * uP clears EQ contexts when the connection exits rdma mode,
15562306a36Sopenharmony_ci	 * so no need to post a RESET WR for these EQs.
15662306a36Sopenharmony_ci	 */
15762306a36Sopenharmony_ci	dealloc_sq(rdev, &wq->sq);
15862306a36Sopenharmony_ci	kfree(wq->sq.sw_sq);
15962306a36Sopenharmony_ci	c4iw_put_qpid(rdev, wq->sq.qid, uctx);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (has_rq) {
16262306a36Sopenharmony_ci		dma_free_coherent(&rdev->lldi.pdev->dev,
16362306a36Sopenharmony_ci				  wq->rq.memsize, wq->rq.queue,
16462306a36Sopenharmony_ci				  dma_unmap_addr(&wq->rq, mapping));
16562306a36Sopenharmony_ci		c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
16662306a36Sopenharmony_ci		kfree(wq->rq.sw_rq);
16762306a36Sopenharmony_ci		c4iw_put_qpid(rdev, wq->rq.qid, uctx);
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci	return 0;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/*
17362306a36Sopenharmony_ci * Determine the BAR2 virtual address and qid. If pbar2_pa is not NULL,
17462306a36Sopenharmony_ci * then this is a user mapping so compute the page-aligned physical address
17562306a36Sopenharmony_ci * for mapping.
17662306a36Sopenharmony_ci */
17762306a36Sopenharmony_civoid __iomem *c4iw_bar2_addrs(struct c4iw_rdev *rdev, unsigned int qid,
17862306a36Sopenharmony_ci			      enum cxgb4_bar2_qtype qtype,
17962306a36Sopenharmony_ci			      unsigned int *pbar2_qid, u64 *pbar2_pa)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	u64 bar2_qoffset;
18262306a36Sopenharmony_ci	int ret;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	ret = cxgb4_bar2_sge_qregs(rdev->lldi.ports[0], qid, qtype,
18562306a36Sopenharmony_ci				   pbar2_pa ? 1 : 0,
18662306a36Sopenharmony_ci				   &bar2_qoffset, pbar2_qid);
18762306a36Sopenharmony_ci	if (ret)
18862306a36Sopenharmony_ci		return NULL;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	if (pbar2_pa)
19162306a36Sopenharmony_ci		*pbar2_pa = (rdev->bar2_pa + bar2_qoffset) & PAGE_MASK;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	if (is_t4(rdev->lldi.adapter_type))
19462306a36Sopenharmony_ci		return NULL;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	return rdev->bar2_kva + bar2_qoffset;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
20062306a36Sopenharmony_ci		     struct t4_cq *rcq, struct t4_cq *scq,
20162306a36Sopenharmony_ci		     struct c4iw_dev_ucontext *uctx,
20262306a36Sopenharmony_ci		     struct c4iw_wr_wait *wr_waitp,
20362306a36Sopenharmony_ci		     int need_rq)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	int user = (uctx != &rdev->uctx);
20662306a36Sopenharmony_ci	struct fw_ri_res_wr *res_wr;
20762306a36Sopenharmony_ci	struct fw_ri_res *res;
20862306a36Sopenharmony_ci	int wr_len;
20962306a36Sopenharmony_ci	struct sk_buff *skb;
21062306a36Sopenharmony_ci	int ret = 0;
21162306a36Sopenharmony_ci	int eqsize;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	wq->sq.qid = c4iw_get_qpid(rdev, uctx);
21462306a36Sopenharmony_ci	if (!wq->sq.qid)
21562306a36Sopenharmony_ci		return -ENOMEM;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	if (need_rq) {
21862306a36Sopenharmony_ci		wq->rq.qid = c4iw_get_qpid(rdev, uctx);
21962306a36Sopenharmony_ci		if (!wq->rq.qid) {
22062306a36Sopenharmony_ci			ret = -ENOMEM;
22162306a36Sopenharmony_ci			goto free_sq_qid;
22262306a36Sopenharmony_ci		}
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	if (!user) {
22662306a36Sopenharmony_ci		wq->sq.sw_sq = kcalloc(wq->sq.size, sizeof(*wq->sq.sw_sq),
22762306a36Sopenharmony_ci				       GFP_KERNEL);
22862306a36Sopenharmony_ci		if (!wq->sq.sw_sq) {
22962306a36Sopenharmony_ci			ret = -ENOMEM;
23062306a36Sopenharmony_ci			goto free_rq_qid;//FIXME
23162306a36Sopenharmony_ci		}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci		if (need_rq) {
23462306a36Sopenharmony_ci			wq->rq.sw_rq = kcalloc(wq->rq.size,
23562306a36Sopenharmony_ci					       sizeof(*wq->rq.sw_rq),
23662306a36Sopenharmony_ci					       GFP_KERNEL);
23762306a36Sopenharmony_ci			if (!wq->rq.sw_rq) {
23862306a36Sopenharmony_ci				ret = -ENOMEM;
23962306a36Sopenharmony_ci				goto free_sw_sq;
24062306a36Sopenharmony_ci			}
24162306a36Sopenharmony_ci		}
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (need_rq) {
24562306a36Sopenharmony_ci		/*
24662306a36Sopenharmony_ci		 * RQT must be a power of 2 and at least 16 deep.
24762306a36Sopenharmony_ci		 */
24862306a36Sopenharmony_ci		wq->rq.rqt_size =
24962306a36Sopenharmony_ci			roundup_pow_of_two(max_t(u16, wq->rq.size, 16));
25062306a36Sopenharmony_ci		wq->rq.rqt_hwaddr = c4iw_rqtpool_alloc(rdev, wq->rq.rqt_size);
25162306a36Sopenharmony_ci		if (!wq->rq.rqt_hwaddr) {
25262306a36Sopenharmony_ci			ret = -ENOMEM;
25362306a36Sopenharmony_ci			goto free_sw_rq;
25462306a36Sopenharmony_ci		}
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	ret = alloc_sq(rdev, &wq->sq, user);
25862306a36Sopenharmony_ci	if (ret)
25962306a36Sopenharmony_ci		goto free_hwaddr;
26062306a36Sopenharmony_ci	memset(wq->sq.queue, 0, wq->sq.memsize);
26162306a36Sopenharmony_ci	dma_unmap_addr_set(&wq->sq, mapping, wq->sq.dma_addr);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	if (need_rq) {
26462306a36Sopenharmony_ci		wq->rq.queue = dma_alloc_coherent(&rdev->lldi.pdev->dev,
26562306a36Sopenharmony_ci						  wq->rq.memsize,
26662306a36Sopenharmony_ci						  &wq->rq.dma_addr,
26762306a36Sopenharmony_ci						  GFP_KERNEL);
26862306a36Sopenharmony_ci		if (!wq->rq.queue) {
26962306a36Sopenharmony_ci			ret = -ENOMEM;
27062306a36Sopenharmony_ci			goto free_sq;
27162306a36Sopenharmony_ci		}
27262306a36Sopenharmony_ci		pr_debug("sq base va 0x%p pa 0x%llx rq base va 0x%p pa 0x%llx\n",
27362306a36Sopenharmony_ci			 wq->sq.queue,
27462306a36Sopenharmony_ci			 (unsigned long long)virt_to_phys(wq->sq.queue),
27562306a36Sopenharmony_ci			 wq->rq.queue,
27662306a36Sopenharmony_ci			 (unsigned long long)virt_to_phys(wq->rq.queue));
27762306a36Sopenharmony_ci		dma_unmap_addr_set(&wq->rq, mapping, wq->rq.dma_addr);
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	wq->db = rdev->lldi.db_reg;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	wq->sq.bar2_va = c4iw_bar2_addrs(rdev, wq->sq.qid,
28362306a36Sopenharmony_ci					 CXGB4_BAR2_QTYPE_EGRESS,
28462306a36Sopenharmony_ci					 &wq->sq.bar2_qid,
28562306a36Sopenharmony_ci					 user ? &wq->sq.bar2_pa : NULL);
28662306a36Sopenharmony_ci	if (need_rq)
28762306a36Sopenharmony_ci		wq->rq.bar2_va = c4iw_bar2_addrs(rdev, wq->rq.qid,
28862306a36Sopenharmony_ci						 CXGB4_BAR2_QTYPE_EGRESS,
28962306a36Sopenharmony_ci						 &wq->rq.bar2_qid,
29062306a36Sopenharmony_ci						 user ? &wq->rq.bar2_pa : NULL);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	/*
29362306a36Sopenharmony_ci	 * User mode must have bar2 access.
29462306a36Sopenharmony_ci	 */
29562306a36Sopenharmony_ci	if (user && (!wq->sq.bar2_pa || (need_rq && !wq->rq.bar2_pa))) {
29662306a36Sopenharmony_ci		pr_warn("%s: sqid %u or rqid %u not in BAR2 range\n",
29762306a36Sopenharmony_ci			pci_name(rdev->lldi.pdev), wq->sq.qid, wq->rq.qid);
29862306a36Sopenharmony_ci		ret = -EINVAL;
29962306a36Sopenharmony_ci		goto free_dma;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	wq->rdev = rdev;
30362306a36Sopenharmony_ci	wq->rq.msn = 1;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/* build fw_ri_res_wr */
30662306a36Sopenharmony_ci	wr_len = sizeof(*res_wr) + 2 * sizeof(*res);
30762306a36Sopenharmony_ci	if (need_rq)
30862306a36Sopenharmony_ci		wr_len += sizeof(*res);
30962306a36Sopenharmony_ci	skb = alloc_skb(wr_len, GFP_KERNEL);
31062306a36Sopenharmony_ci	if (!skb) {
31162306a36Sopenharmony_ci		ret = -ENOMEM;
31262306a36Sopenharmony_ci		goto free_dma;
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	res_wr = __skb_put_zero(skb, wr_len);
31762306a36Sopenharmony_ci	res_wr->op_nres = cpu_to_be32(
31862306a36Sopenharmony_ci			FW_WR_OP_V(FW_RI_RES_WR) |
31962306a36Sopenharmony_ci			FW_RI_RES_WR_NRES_V(need_rq ? 2 : 1) |
32062306a36Sopenharmony_ci			FW_WR_COMPL_F);
32162306a36Sopenharmony_ci	res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
32262306a36Sopenharmony_ci	res_wr->cookie = (uintptr_t)wr_waitp;
32362306a36Sopenharmony_ci	res = res_wr->res;
32462306a36Sopenharmony_ci	res->u.sqrq.restype = FW_RI_RES_TYPE_SQ;
32562306a36Sopenharmony_ci	res->u.sqrq.op = FW_RI_RES_OP_WRITE;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/*
32862306a36Sopenharmony_ci	 * eqsize is the number of 64B entries plus the status page size.
32962306a36Sopenharmony_ci	 */
33062306a36Sopenharmony_ci	eqsize = wq->sq.size * T4_SQ_NUM_SLOTS +
33162306a36Sopenharmony_ci		rdev->hw_queue.t4_eq_status_entries;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	res->u.sqrq.fetchszm_to_iqid = cpu_to_be32(
33462306a36Sopenharmony_ci		FW_RI_RES_WR_HOSTFCMODE_V(0) |	/* no host cidx updates */
33562306a36Sopenharmony_ci		FW_RI_RES_WR_CPRIO_V(0) |	/* don't keep in chip cache */
33662306a36Sopenharmony_ci		FW_RI_RES_WR_PCIECHN_V(0) |	/* set by uP at ri_init time */
33762306a36Sopenharmony_ci		(t4_sq_onchip(&wq->sq) ? FW_RI_RES_WR_ONCHIP_F : 0) |
33862306a36Sopenharmony_ci		FW_RI_RES_WR_IQID_V(scq->cqid));
33962306a36Sopenharmony_ci	res->u.sqrq.dcaen_to_eqsize = cpu_to_be32(
34062306a36Sopenharmony_ci		FW_RI_RES_WR_DCAEN_V(0) |
34162306a36Sopenharmony_ci		FW_RI_RES_WR_DCACPU_V(0) |
34262306a36Sopenharmony_ci		FW_RI_RES_WR_FBMIN_V(2) |
34362306a36Sopenharmony_ci		(t4_sq_onchip(&wq->sq) ? FW_RI_RES_WR_FBMAX_V(2) :
34462306a36Sopenharmony_ci					 FW_RI_RES_WR_FBMAX_V(3)) |
34562306a36Sopenharmony_ci		FW_RI_RES_WR_CIDXFTHRESHO_V(0) |
34662306a36Sopenharmony_ci		FW_RI_RES_WR_CIDXFTHRESH_V(0) |
34762306a36Sopenharmony_ci		FW_RI_RES_WR_EQSIZE_V(eqsize));
34862306a36Sopenharmony_ci	res->u.sqrq.eqid = cpu_to_be32(wq->sq.qid);
34962306a36Sopenharmony_ci	res->u.sqrq.eqaddr = cpu_to_be64(wq->sq.dma_addr);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (need_rq) {
35262306a36Sopenharmony_ci		res++;
35362306a36Sopenharmony_ci		res->u.sqrq.restype = FW_RI_RES_TYPE_RQ;
35462306a36Sopenharmony_ci		res->u.sqrq.op = FW_RI_RES_OP_WRITE;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci		/*
35762306a36Sopenharmony_ci		 * eqsize is the number of 64B entries plus the status page size
35862306a36Sopenharmony_ci		 */
35962306a36Sopenharmony_ci		eqsize = wq->rq.size * T4_RQ_NUM_SLOTS +
36062306a36Sopenharmony_ci			rdev->hw_queue.t4_eq_status_entries;
36162306a36Sopenharmony_ci		res->u.sqrq.fetchszm_to_iqid =
36262306a36Sopenharmony_ci			/* no host cidx updates */
36362306a36Sopenharmony_ci			cpu_to_be32(FW_RI_RES_WR_HOSTFCMODE_V(0) |
36462306a36Sopenharmony_ci			/* don't keep in chip cache */
36562306a36Sopenharmony_ci			FW_RI_RES_WR_CPRIO_V(0) |
36662306a36Sopenharmony_ci			/* set by uP at ri_init time */
36762306a36Sopenharmony_ci			FW_RI_RES_WR_PCIECHN_V(0) |
36862306a36Sopenharmony_ci			FW_RI_RES_WR_IQID_V(rcq->cqid));
36962306a36Sopenharmony_ci		res->u.sqrq.dcaen_to_eqsize =
37062306a36Sopenharmony_ci			cpu_to_be32(FW_RI_RES_WR_DCAEN_V(0) |
37162306a36Sopenharmony_ci			FW_RI_RES_WR_DCACPU_V(0) |
37262306a36Sopenharmony_ci			FW_RI_RES_WR_FBMIN_V(2) |
37362306a36Sopenharmony_ci			FW_RI_RES_WR_FBMAX_V(3) |
37462306a36Sopenharmony_ci			FW_RI_RES_WR_CIDXFTHRESHO_V(0) |
37562306a36Sopenharmony_ci			FW_RI_RES_WR_CIDXFTHRESH_V(0) |
37662306a36Sopenharmony_ci			FW_RI_RES_WR_EQSIZE_V(eqsize));
37762306a36Sopenharmony_ci		res->u.sqrq.eqid = cpu_to_be32(wq->rq.qid);
37862306a36Sopenharmony_ci		res->u.sqrq.eqaddr = cpu_to_be64(wq->rq.dma_addr);
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	c4iw_init_wr_wait(wr_waitp);
38262306a36Sopenharmony_ci	ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, wq->sq.qid, __func__);
38362306a36Sopenharmony_ci	if (ret)
38462306a36Sopenharmony_ci		goto free_dma;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	pr_debug("sqid 0x%x rqid 0x%x kdb 0x%p sq_bar2_addr %p rq_bar2_addr %p\n",
38762306a36Sopenharmony_ci		 wq->sq.qid, wq->rq.qid, wq->db,
38862306a36Sopenharmony_ci		 wq->sq.bar2_va, wq->rq.bar2_va);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	return 0;
39162306a36Sopenharmony_cifree_dma:
39262306a36Sopenharmony_ci	if (need_rq)
39362306a36Sopenharmony_ci		dma_free_coherent(&rdev->lldi.pdev->dev,
39462306a36Sopenharmony_ci				  wq->rq.memsize, wq->rq.queue,
39562306a36Sopenharmony_ci				  dma_unmap_addr(&wq->rq, mapping));
39662306a36Sopenharmony_cifree_sq:
39762306a36Sopenharmony_ci	dealloc_sq(rdev, &wq->sq);
39862306a36Sopenharmony_cifree_hwaddr:
39962306a36Sopenharmony_ci	if (need_rq)
40062306a36Sopenharmony_ci		c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
40162306a36Sopenharmony_cifree_sw_rq:
40262306a36Sopenharmony_ci	if (need_rq)
40362306a36Sopenharmony_ci		kfree(wq->rq.sw_rq);
40462306a36Sopenharmony_cifree_sw_sq:
40562306a36Sopenharmony_ci	kfree(wq->sq.sw_sq);
40662306a36Sopenharmony_cifree_rq_qid:
40762306a36Sopenharmony_ci	if (need_rq)
40862306a36Sopenharmony_ci		c4iw_put_qpid(rdev, wq->rq.qid, uctx);
40962306a36Sopenharmony_cifree_sq_qid:
41062306a36Sopenharmony_ci	c4iw_put_qpid(rdev, wq->sq.qid, uctx);
41162306a36Sopenharmony_ci	return ret;
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic int build_immd(struct t4_sq *sq, struct fw_ri_immd *immdp,
41562306a36Sopenharmony_ci		      const struct ib_send_wr *wr, int max, u32 *plenp)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	u8 *dstp, *srcp;
41862306a36Sopenharmony_ci	u32 plen = 0;
41962306a36Sopenharmony_ci	int i;
42062306a36Sopenharmony_ci	int rem, len;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	dstp = (u8 *)immdp->data;
42362306a36Sopenharmony_ci	for (i = 0; i < wr->num_sge; i++) {
42462306a36Sopenharmony_ci		if ((plen + wr->sg_list[i].length) > max)
42562306a36Sopenharmony_ci			return -EMSGSIZE;
42662306a36Sopenharmony_ci		srcp = (u8 *)(unsigned long)wr->sg_list[i].addr;
42762306a36Sopenharmony_ci		plen += wr->sg_list[i].length;
42862306a36Sopenharmony_ci		rem = wr->sg_list[i].length;
42962306a36Sopenharmony_ci		while (rem) {
43062306a36Sopenharmony_ci			if (dstp == (u8 *)&sq->queue[sq->size])
43162306a36Sopenharmony_ci				dstp = (u8 *)sq->queue;
43262306a36Sopenharmony_ci			if (rem <= (u8 *)&sq->queue[sq->size] - dstp)
43362306a36Sopenharmony_ci				len = rem;
43462306a36Sopenharmony_ci			else
43562306a36Sopenharmony_ci				len = (u8 *)&sq->queue[sq->size] - dstp;
43662306a36Sopenharmony_ci			memcpy(dstp, srcp, len);
43762306a36Sopenharmony_ci			dstp += len;
43862306a36Sopenharmony_ci			srcp += len;
43962306a36Sopenharmony_ci			rem -= len;
44062306a36Sopenharmony_ci		}
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci	len = roundup(plen + sizeof(*immdp), 16) - (plen + sizeof(*immdp));
44362306a36Sopenharmony_ci	if (len)
44462306a36Sopenharmony_ci		memset(dstp, 0, len);
44562306a36Sopenharmony_ci	immdp->op = FW_RI_DATA_IMMD;
44662306a36Sopenharmony_ci	immdp->r1 = 0;
44762306a36Sopenharmony_ci	immdp->r2 = 0;
44862306a36Sopenharmony_ci	immdp->immdlen = cpu_to_be32(plen);
44962306a36Sopenharmony_ci	*plenp = plen;
45062306a36Sopenharmony_ci	return 0;
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic int build_isgl(__be64 *queue_start, __be64 *queue_end,
45462306a36Sopenharmony_ci		      struct fw_ri_isgl *isglp, struct ib_sge *sg_list,
45562306a36Sopenharmony_ci		      int num_sge, u32 *plenp)
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	int i;
45962306a36Sopenharmony_ci	u32 plen = 0;
46062306a36Sopenharmony_ci	__be64 *flitp;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	if ((__be64 *)isglp == queue_end)
46362306a36Sopenharmony_ci		isglp = (struct fw_ri_isgl *)queue_start;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	flitp = (__be64 *)isglp->sge;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	for (i = 0; i < num_sge; i++) {
46862306a36Sopenharmony_ci		if ((plen + sg_list[i].length) < plen)
46962306a36Sopenharmony_ci			return -EMSGSIZE;
47062306a36Sopenharmony_ci		plen += sg_list[i].length;
47162306a36Sopenharmony_ci		*flitp = cpu_to_be64(((u64)sg_list[i].lkey << 32) |
47262306a36Sopenharmony_ci				     sg_list[i].length);
47362306a36Sopenharmony_ci		if (++flitp == queue_end)
47462306a36Sopenharmony_ci			flitp = queue_start;
47562306a36Sopenharmony_ci		*flitp = cpu_to_be64(sg_list[i].addr);
47662306a36Sopenharmony_ci		if (++flitp == queue_end)
47762306a36Sopenharmony_ci			flitp = queue_start;
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci	*flitp = (__force __be64)0;
48062306a36Sopenharmony_ci	isglp->op = FW_RI_DATA_ISGL;
48162306a36Sopenharmony_ci	isglp->r1 = 0;
48262306a36Sopenharmony_ci	isglp->nsge = cpu_to_be16(num_sge);
48362306a36Sopenharmony_ci	isglp->r2 = 0;
48462306a36Sopenharmony_ci	if (plenp)
48562306a36Sopenharmony_ci		*plenp = plen;
48662306a36Sopenharmony_ci	return 0;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cistatic int build_rdma_send(struct t4_sq *sq, union t4_wr *wqe,
49062306a36Sopenharmony_ci			   const struct ib_send_wr *wr, u8 *len16)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	u32 plen;
49362306a36Sopenharmony_ci	int size;
49462306a36Sopenharmony_ci	int ret;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	if (wr->num_sge > T4_MAX_SEND_SGE)
49762306a36Sopenharmony_ci		return -EINVAL;
49862306a36Sopenharmony_ci	switch (wr->opcode) {
49962306a36Sopenharmony_ci	case IB_WR_SEND:
50062306a36Sopenharmony_ci		if (wr->send_flags & IB_SEND_SOLICITED)
50162306a36Sopenharmony_ci			wqe->send.sendop_pkd = cpu_to_be32(
50262306a36Sopenharmony_ci				FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND_WITH_SE));
50362306a36Sopenharmony_ci		else
50462306a36Sopenharmony_ci			wqe->send.sendop_pkd = cpu_to_be32(
50562306a36Sopenharmony_ci				FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND));
50662306a36Sopenharmony_ci		wqe->send.stag_inv = 0;
50762306a36Sopenharmony_ci		break;
50862306a36Sopenharmony_ci	case IB_WR_SEND_WITH_INV:
50962306a36Sopenharmony_ci		if (wr->send_flags & IB_SEND_SOLICITED)
51062306a36Sopenharmony_ci			wqe->send.sendop_pkd = cpu_to_be32(
51162306a36Sopenharmony_ci				FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND_WITH_SE_INV));
51262306a36Sopenharmony_ci		else
51362306a36Sopenharmony_ci			wqe->send.sendop_pkd = cpu_to_be32(
51462306a36Sopenharmony_ci				FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND_WITH_INV));
51562306a36Sopenharmony_ci		wqe->send.stag_inv = cpu_to_be32(wr->ex.invalidate_rkey);
51662306a36Sopenharmony_ci		break;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	default:
51962306a36Sopenharmony_ci		return -EINVAL;
52062306a36Sopenharmony_ci	}
52162306a36Sopenharmony_ci	wqe->send.r3 = 0;
52262306a36Sopenharmony_ci	wqe->send.r4 = 0;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	plen = 0;
52562306a36Sopenharmony_ci	if (wr->num_sge) {
52662306a36Sopenharmony_ci		if (wr->send_flags & IB_SEND_INLINE) {
52762306a36Sopenharmony_ci			ret = build_immd(sq, wqe->send.u.immd_src, wr,
52862306a36Sopenharmony_ci					 T4_MAX_SEND_INLINE, &plen);
52962306a36Sopenharmony_ci			if (ret)
53062306a36Sopenharmony_ci				return ret;
53162306a36Sopenharmony_ci			size = sizeof(wqe->send) + sizeof(struct fw_ri_immd) +
53262306a36Sopenharmony_ci			       plen;
53362306a36Sopenharmony_ci		} else {
53462306a36Sopenharmony_ci			ret = build_isgl((__be64 *)sq->queue,
53562306a36Sopenharmony_ci					 (__be64 *)&sq->queue[sq->size],
53662306a36Sopenharmony_ci					 wqe->send.u.isgl_src,
53762306a36Sopenharmony_ci					 wr->sg_list, wr->num_sge, &plen);
53862306a36Sopenharmony_ci			if (ret)
53962306a36Sopenharmony_ci				return ret;
54062306a36Sopenharmony_ci			size = sizeof(wqe->send) + sizeof(struct fw_ri_isgl) +
54162306a36Sopenharmony_ci			       wr->num_sge * sizeof(struct fw_ri_sge);
54262306a36Sopenharmony_ci		}
54362306a36Sopenharmony_ci	} else {
54462306a36Sopenharmony_ci		wqe->send.u.immd_src[0].op = FW_RI_DATA_IMMD;
54562306a36Sopenharmony_ci		wqe->send.u.immd_src[0].r1 = 0;
54662306a36Sopenharmony_ci		wqe->send.u.immd_src[0].r2 = 0;
54762306a36Sopenharmony_ci		wqe->send.u.immd_src[0].immdlen = 0;
54862306a36Sopenharmony_ci		size = sizeof(wqe->send) + sizeof(struct fw_ri_immd);
54962306a36Sopenharmony_ci		plen = 0;
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci	*len16 = DIV_ROUND_UP(size, 16);
55262306a36Sopenharmony_ci	wqe->send.plen = cpu_to_be32(plen);
55362306a36Sopenharmony_ci	return 0;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic int build_rdma_write(struct t4_sq *sq, union t4_wr *wqe,
55762306a36Sopenharmony_ci			    const struct ib_send_wr *wr, u8 *len16)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	u32 plen;
56062306a36Sopenharmony_ci	int size;
56162306a36Sopenharmony_ci	int ret;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	if (wr->num_sge > T4_MAX_SEND_SGE)
56462306a36Sopenharmony_ci		return -EINVAL;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	/*
56762306a36Sopenharmony_ci	 * iWARP protocol supports 64 bit immediate data but rdma api
56862306a36Sopenharmony_ci	 * limits it to 32bit.
56962306a36Sopenharmony_ci	 */
57062306a36Sopenharmony_ci	if (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM)
57162306a36Sopenharmony_ci		wqe->write.iw_imm_data.ib_imm_data.imm_data32 = wr->ex.imm_data;
57262306a36Sopenharmony_ci	else
57362306a36Sopenharmony_ci		wqe->write.iw_imm_data.ib_imm_data.imm_data32 = 0;
57462306a36Sopenharmony_ci	wqe->write.stag_sink = cpu_to_be32(rdma_wr(wr)->rkey);
57562306a36Sopenharmony_ci	wqe->write.to_sink = cpu_to_be64(rdma_wr(wr)->remote_addr);
57662306a36Sopenharmony_ci	if (wr->num_sge) {
57762306a36Sopenharmony_ci		if (wr->send_flags & IB_SEND_INLINE) {
57862306a36Sopenharmony_ci			ret = build_immd(sq, wqe->write.u.immd_src, wr,
57962306a36Sopenharmony_ci					 T4_MAX_WRITE_INLINE, &plen);
58062306a36Sopenharmony_ci			if (ret)
58162306a36Sopenharmony_ci				return ret;
58262306a36Sopenharmony_ci			size = sizeof(wqe->write) + sizeof(struct fw_ri_immd) +
58362306a36Sopenharmony_ci			       plen;
58462306a36Sopenharmony_ci		} else {
58562306a36Sopenharmony_ci			ret = build_isgl((__be64 *)sq->queue,
58662306a36Sopenharmony_ci					 (__be64 *)&sq->queue[sq->size],
58762306a36Sopenharmony_ci					 wqe->write.u.isgl_src,
58862306a36Sopenharmony_ci					 wr->sg_list, wr->num_sge, &plen);
58962306a36Sopenharmony_ci			if (ret)
59062306a36Sopenharmony_ci				return ret;
59162306a36Sopenharmony_ci			size = sizeof(wqe->write) + sizeof(struct fw_ri_isgl) +
59262306a36Sopenharmony_ci			       wr->num_sge * sizeof(struct fw_ri_sge);
59362306a36Sopenharmony_ci		}
59462306a36Sopenharmony_ci	} else {
59562306a36Sopenharmony_ci		wqe->write.u.immd_src[0].op = FW_RI_DATA_IMMD;
59662306a36Sopenharmony_ci		wqe->write.u.immd_src[0].r1 = 0;
59762306a36Sopenharmony_ci		wqe->write.u.immd_src[0].r2 = 0;
59862306a36Sopenharmony_ci		wqe->write.u.immd_src[0].immdlen = 0;
59962306a36Sopenharmony_ci		size = sizeof(wqe->write) + sizeof(struct fw_ri_immd);
60062306a36Sopenharmony_ci		plen = 0;
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci	*len16 = DIV_ROUND_UP(size, 16);
60362306a36Sopenharmony_ci	wqe->write.plen = cpu_to_be32(plen);
60462306a36Sopenharmony_ci	return 0;
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic void build_immd_cmpl(struct t4_sq *sq, struct fw_ri_immd_cmpl *immdp,
60862306a36Sopenharmony_ci			    struct ib_send_wr *wr)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	memcpy((u8 *)immdp->data, (u8 *)(uintptr_t)wr->sg_list->addr, 16);
61162306a36Sopenharmony_ci	memset(immdp->r1, 0, 6);
61262306a36Sopenharmony_ci	immdp->op = FW_RI_DATA_IMMD;
61362306a36Sopenharmony_ci	immdp->immdlen = 16;
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistatic void build_rdma_write_cmpl(struct t4_sq *sq,
61762306a36Sopenharmony_ci				  struct fw_ri_rdma_write_cmpl_wr *wcwr,
61862306a36Sopenharmony_ci				  const struct ib_send_wr *wr, u8 *len16)
61962306a36Sopenharmony_ci{
62062306a36Sopenharmony_ci	u32 plen;
62162306a36Sopenharmony_ci	int size;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	/*
62462306a36Sopenharmony_ci	 * This code assumes the struct fields preceding the write isgl
62562306a36Sopenharmony_ci	 * fit in one 64B WR slot.  This is because the WQE is built
62662306a36Sopenharmony_ci	 * directly in the dma queue, and wrapping is only handled
62762306a36Sopenharmony_ci	 * by the code buildling sgls.  IE the "fixed part" of the wr
62862306a36Sopenharmony_ci	 * structs must all fit in 64B.  The WQE build code should probably be
62962306a36Sopenharmony_ci	 * redesigned to avoid this restriction, but for now just add
63062306a36Sopenharmony_ci	 * the BUILD_BUG_ON() to catch if this WQE struct gets too big.
63162306a36Sopenharmony_ci	 */
63262306a36Sopenharmony_ci	BUILD_BUG_ON(offsetof(struct fw_ri_rdma_write_cmpl_wr, u) > 64);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	wcwr->stag_sink = cpu_to_be32(rdma_wr(wr)->rkey);
63562306a36Sopenharmony_ci	wcwr->to_sink = cpu_to_be64(rdma_wr(wr)->remote_addr);
63662306a36Sopenharmony_ci	if (wr->next->opcode == IB_WR_SEND)
63762306a36Sopenharmony_ci		wcwr->stag_inv = 0;
63862306a36Sopenharmony_ci	else
63962306a36Sopenharmony_ci		wcwr->stag_inv = cpu_to_be32(wr->next->ex.invalidate_rkey);
64062306a36Sopenharmony_ci	wcwr->r2 = 0;
64162306a36Sopenharmony_ci	wcwr->r3 = 0;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	/* SEND_INV SGL */
64462306a36Sopenharmony_ci	if (wr->next->send_flags & IB_SEND_INLINE)
64562306a36Sopenharmony_ci		build_immd_cmpl(sq, &wcwr->u_cmpl.immd_src, wr->next);
64662306a36Sopenharmony_ci	else
64762306a36Sopenharmony_ci		build_isgl((__be64 *)sq->queue, (__be64 *)&sq->queue[sq->size],
64862306a36Sopenharmony_ci			   &wcwr->u_cmpl.isgl_src, wr->next->sg_list, 1, NULL);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	/* WRITE SGL */
65162306a36Sopenharmony_ci	build_isgl((__be64 *)sq->queue, (__be64 *)&sq->queue[sq->size],
65262306a36Sopenharmony_ci		   wcwr->u.isgl_src, wr->sg_list, wr->num_sge, &plen);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	size = sizeof(*wcwr) + sizeof(struct fw_ri_isgl) +
65562306a36Sopenharmony_ci		wr->num_sge * sizeof(struct fw_ri_sge);
65662306a36Sopenharmony_ci	wcwr->plen = cpu_to_be32(plen);
65762306a36Sopenharmony_ci	*len16 = DIV_ROUND_UP(size, 16);
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_cistatic int build_rdma_read(union t4_wr *wqe, const struct ib_send_wr *wr,
66162306a36Sopenharmony_ci			   u8 *len16)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	if (wr->num_sge > 1)
66462306a36Sopenharmony_ci		return -EINVAL;
66562306a36Sopenharmony_ci	if (wr->num_sge && wr->sg_list[0].length) {
66662306a36Sopenharmony_ci		wqe->read.stag_src = cpu_to_be32(rdma_wr(wr)->rkey);
66762306a36Sopenharmony_ci		wqe->read.to_src_hi = cpu_to_be32((u32)(rdma_wr(wr)->remote_addr
66862306a36Sopenharmony_ci							>> 32));
66962306a36Sopenharmony_ci		wqe->read.to_src_lo = cpu_to_be32((u32)rdma_wr(wr)->remote_addr);
67062306a36Sopenharmony_ci		wqe->read.stag_sink = cpu_to_be32(wr->sg_list[0].lkey);
67162306a36Sopenharmony_ci		wqe->read.plen = cpu_to_be32(wr->sg_list[0].length);
67262306a36Sopenharmony_ci		wqe->read.to_sink_hi = cpu_to_be32((u32)(wr->sg_list[0].addr
67362306a36Sopenharmony_ci							 >> 32));
67462306a36Sopenharmony_ci		wqe->read.to_sink_lo = cpu_to_be32((u32)(wr->sg_list[0].addr));
67562306a36Sopenharmony_ci	} else {
67662306a36Sopenharmony_ci		wqe->read.stag_src = cpu_to_be32(2);
67762306a36Sopenharmony_ci		wqe->read.to_src_hi = 0;
67862306a36Sopenharmony_ci		wqe->read.to_src_lo = 0;
67962306a36Sopenharmony_ci		wqe->read.stag_sink = cpu_to_be32(2);
68062306a36Sopenharmony_ci		wqe->read.plen = 0;
68162306a36Sopenharmony_ci		wqe->read.to_sink_hi = 0;
68262306a36Sopenharmony_ci		wqe->read.to_sink_lo = 0;
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci	wqe->read.r2 = 0;
68562306a36Sopenharmony_ci	wqe->read.r5 = 0;
68662306a36Sopenharmony_ci	*len16 = DIV_ROUND_UP(sizeof(wqe->read), 16);
68762306a36Sopenharmony_ci	return 0;
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_cistatic void post_write_cmpl(struct c4iw_qp *qhp, const struct ib_send_wr *wr)
69162306a36Sopenharmony_ci{
69262306a36Sopenharmony_ci	bool send_signaled = (wr->next->send_flags & IB_SEND_SIGNALED) ||
69362306a36Sopenharmony_ci			     qhp->sq_sig_all;
69462306a36Sopenharmony_ci	bool write_signaled = (wr->send_flags & IB_SEND_SIGNALED) ||
69562306a36Sopenharmony_ci			      qhp->sq_sig_all;
69662306a36Sopenharmony_ci	struct t4_swsqe *swsqe;
69762306a36Sopenharmony_ci	union t4_wr *wqe;
69862306a36Sopenharmony_ci	u16 write_wrid;
69962306a36Sopenharmony_ci	u8 len16;
70062306a36Sopenharmony_ci	u16 idx;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	/*
70362306a36Sopenharmony_ci	 * The sw_sq entries still look like a WRITE and a SEND and consume
70462306a36Sopenharmony_ci	 * 2 slots. The FW WR, however, will be a single uber-WR.
70562306a36Sopenharmony_ci	 */
70662306a36Sopenharmony_ci	wqe = (union t4_wr *)((u8 *)qhp->wq.sq.queue +
70762306a36Sopenharmony_ci	       qhp->wq.sq.wq_pidx * T4_EQ_ENTRY_SIZE);
70862306a36Sopenharmony_ci	build_rdma_write_cmpl(&qhp->wq.sq, &wqe->write_cmpl, wr, &len16);
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	/* WRITE swsqe */
71162306a36Sopenharmony_ci	swsqe = &qhp->wq.sq.sw_sq[qhp->wq.sq.pidx];
71262306a36Sopenharmony_ci	swsqe->opcode = FW_RI_RDMA_WRITE;
71362306a36Sopenharmony_ci	swsqe->idx = qhp->wq.sq.pidx;
71462306a36Sopenharmony_ci	swsqe->complete = 0;
71562306a36Sopenharmony_ci	swsqe->signaled = write_signaled;
71662306a36Sopenharmony_ci	swsqe->flushed = 0;
71762306a36Sopenharmony_ci	swsqe->wr_id = wr->wr_id;
71862306a36Sopenharmony_ci	if (c4iw_wr_log) {
71962306a36Sopenharmony_ci		swsqe->sge_ts =
72062306a36Sopenharmony_ci			cxgb4_read_sge_timestamp(qhp->rhp->rdev.lldi.ports[0]);
72162306a36Sopenharmony_ci		swsqe->host_time = ktime_get();
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	write_wrid = qhp->wq.sq.pidx;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	/* just bump the sw_sq */
72762306a36Sopenharmony_ci	qhp->wq.sq.in_use++;
72862306a36Sopenharmony_ci	if (++qhp->wq.sq.pidx == qhp->wq.sq.size)
72962306a36Sopenharmony_ci		qhp->wq.sq.pidx = 0;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	/* SEND_WITH_INV swsqe */
73262306a36Sopenharmony_ci	swsqe = &qhp->wq.sq.sw_sq[qhp->wq.sq.pidx];
73362306a36Sopenharmony_ci	if (wr->next->opcode == IB_WR_SEND)
73462306a36Sopenharmony_ci		swsqe->opcode = FW_RI_SEND;
73562306a36Sopenharmony_ci	else
73662306a36Sopenharmony_ci		swsqe->opcode = FW_RI_SEND_WITH_INV;
73762306a36Sopenharmony_ci	swsqe->idx = qhp->wq.sq.pidx;
73862306a36Sopenharmony_ci	swsqe->complete = 0;
73962306a36Sopenharmony_ci	swsqe->signaled = send_signaled;
74062306a36Sopenharmony_ci	swsqe->flushed = 0;
74162306a36Sopenharmony_ci	swsqe->wr_id = wr->next->wr_id;
74262306a36Sopenharmony_ci	if (c4iw_wr_log) {
74362306a36Sopenharmony_ci		swsqe->sge_ts =
74462306a36Sopenharmony_ci			cxgb4_read_sge_timestamp(qhp->rhp->rdev.lldi.ports[0]);
74562306a36Sopenharmony_ci		swsqe->host_time = ktime_get();
74662306a36Sopenharmony_ci	}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	wqe->write_cmpl.flags_send = send_signaled ? FW_RI_COMPLETION_FLAG : 0;
74962306a36Sopenharmony_ci	wqe->write_cmpl.wrid_send = qhp->wq.sq.pidx;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	init_wr_hdr(wqe, write_wrid, FW_RI_RDMA_WRITE_CMPL_WR,
75262306a36Sopenharmony_ci		    write_signaled ? FW_RI_COMPLETION_FLAG : 0, len16);
75362306a36Sopenharmony_ci	t4_sq_produce(&qhp->wq, len16);
75462306a36Sopenharmony_ci	idx = DIV_ROUND_UP(len16 * 16, T4_EQ_ENTRY_SIZE);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	t4_ring_sq_db(&qhp->wq, idx, wqe);
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_cistatic int build_rdma_recv(struct c4iw_qp *qhp, union t4_recv_wr *wqe,
76062306a36Sopenharmony_ci			   const struct ib_recv_wr *wr, u8 *len16)
76162306a36Sopenharmony_ci{
76262306a36Sopenharmony_ci	int ret;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	ret = build_isgl((__be64 *)qhp->wq.rq.queue,
76562306a36Sopenharmony_ci			 (__be64 *)&qhp->wq.rq.queue[qhp->wq.rq.size],
76662306a36Sopenharmony_ci			 &wqe->recv.isgl, wr->sg_list, wr->num_sge, NULL);
76762306a36Sopenharmony_ci	if (ret)
76862306a36Sopenharmony_ci		return ret;
76962306a36Sopenharmony_ci	*len16 = DIV_ROUND_UP(
77062306a36Sopenharmony_ci		sizeof(wqe->recv) + wr->num_sge * sizeof(struct fw_ri_sge), 16);
77162306a36Sopenharmony_ci	return 0;
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistatic int build_srq_recv(union t4_recv_wr *wqe, const struct ib_recv_wr *wr,
77562306a36Sopenharmony_ci			  u8 *len16)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	int ret;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	ret = build_isgl((__be64 *)wqe, (__be64 *)(wqe + 1),
78062306a36Sopenharmony_ci			 &wqe->recv.isgl, wr->sg_list, wr->num_sge, NULL);
78162306a36Sopenharmony_ci	if (ret)
78262306a36Sopenharmony_ci		return ret;
78362306a36Sopenharmony_ci	*len16 = DIV_ROUND_UP(sizeof(wqe->recv) +
78462306a36Sopenharmony_ci			      wr->num_sge * sizeof(struct fw_ri_sge), 16);
78562306a36Sopenharmony_ci	return 0;
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_cistatic void build_tpte_memreg(struct fw_ri_fr_nsmr_tpte_wr *fr,
78962306a36Sopenharmony_ci			      const struct ib_reg_wr *wr, struct c4iw_mr *mhp,
79062306a36Sopenharmony_ci			      u8 *len16)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	__be64 *p = (__be64 *)fr->pbl;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	fr->r2 = cpu_to_be32(0);
79562306a36Sopenharmony_ci	fr->stag = cpu_to_be32(mhp->ibmr.rkey);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	fr->tpte.valid_to_pdid = cpu_to_be32(FW_RI_TPTE_VALID_F |
79862306a36Sopenharmony_ci		FW_RI_TPTE_STAGKEY_V((mhp->ibmr.rkey & FW_RI_TPTE_STAGKEY_M)) |
79962306a36Sopenharmony_ci		FW_RI_TPTE_STAGSTATE_V(1) |
80062306a36Sopenharmony_ci		FW_RI_TPTE_STAGTYPE_V(FW_RI_STAG_NSMR) |
80162306a36Sopenharmony_ci		FW_RI_TPTE_PDID_V(mhp->attr.pdid));
80262306a36Sopenharmony_ci	fr->tpte.locread_to_qpid = cpu_to_be32(
80362306a36Sopenharmony_ci		FW_RI_TPTE_PERM_V(c4iw_ib_to_tpt_access(wr->access)) |
80462306a36Sopenharmony_ci		FW_RI_TPTE_ADDRTYPE_V(FW_RI_VA_BASED_TO) |
80562306a36Sopenharmony_ci		FW_RI_TPTE_PS_V(ilog2(wr->mr->page_size) - 12));
80662306a36Sopenharmony_ci	fr->tpte.nosnoop_pbladdr = cpu_to_be32(FW_RI_TPTE_PBLADDR_V(
80762306a36Sopenharmony_ci		PBL_OFF(&mhp->rhp->rdev, mhp->attr.pbl_addr)>>3));
80862306a36Sopenharmony_ci	fr->tpte.dca_mwbcnt_pstag = cpu_to_be32(0);
80962306a36Sopenharmony_ci	fr->tpte.len_hi = cpu_to_be32(0);
81062306a36Sopenharmony_ci	fr->tpte.len_lo = cpu_to_be32(mhp->ibmr.length);
81162306a36Sopenharmony_ci	fr->tpte.va_hi = cpu_to_be32(mhp->ibmr.iova >> 32);
81262306a36Sopenharmony_ci	fr->tpte.va_lo_fbo = cpu_to_be32(mhp->ibmr.iova & 0xffffffff);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	p[0] = cpu_to_be64((u64)mhp->mpl[0]);
81562306a36Sopenharmony_ci	p[1] = cpu_to_be64((u64)mhp->mpl[1]);
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	*len16 = DIV_ROUND_UP(sizeof(*fr), 16);
81862306a36Sopenharmony_ci}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_cistatic int build_memreg(struct t4_sq *sq, union t4_wr *wqe,
82162306a36Sopenharmony_ci			const struct ib_reg_wr *wr, struct c4iw_mr *mhp,
82262306a36Sopenharmony_ci			u8 *len16, bool dsgl_supported)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	struct fw_ri_immd *imdp;
82562306a36Sopenharmony_ci	__be64 *p;
82662306a36Sopenharmony_ci	int i;
82762306a36Sopenharmony_ci	int pbllen = roundup(mhp->mpl_len * sizeof(u64), 32);
82862306a36Sopenharmony_ci	int rem;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	if (mhp->mpl_len > t4_max_fr_depth(dsgl_supported && use_dsgl))
83162306a36Sopenharmony_ci		return -EINVAL;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	wqe->fr.qpbinde_to_dcacpu = 0;
83462306a36Sopenharmony_ci	wqe->fr.pgsz_shift = ilog2(wr->mr->page_size) - 12;
83562306a36Sopenharmony_ci	wqe->fr.addr_type = FW_RI_VA_BASED_TO;
83662306a36Sopenharmony_ci	wqe->fr.mem_perms = c4iw_ib_to_tpt_access(wr->access);
83762306a36Sopenharmony_ci	wqe->fr.len_hi = 0;
83862306a36Sopenharmony_ci	wqe->fr.len_lo = cpu_to_be32(mhp->ibmr.length);
83962306a36Sopenharmony_ci	wqe->fr.stag = cpu_to_be32(wr->key);
84062306a36Sopenharmony_ci	wqe->fr.va_hi = cpu_to_be32(mhp->ibmr.iova >> 32);
84162306a36Sopenharmony_ci	wqe->fr.va_lo_fbo = cpu_to_be32(mhp->ibmr.iova &
84262306a36Sopenharmony_ci					0xffffffff);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	if (dsgl_supported && use_dsgl && (pbllen > max_fr_immd)) {
84562306a36Sopenharmony_ci		struct fw_ri_dsgl *sglp;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci		for (i = 0; i < mhp->mpl_len; i++)
84862306a36Sopenharmony_ci			mhp->mpl[i] = (__force u64)cpu_to_be64((u64)mhp->mpl[i]);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci		sglp = (struct fw_ri_dsgl *)(&wqe->fr + 1);
85162306a36Sopenharmony_ci		sglp->op = FW_RI_DATA_DSGL;
85262306a36Sopenharmony_ci		sglp->r1 = 0;
85362306a36Sopenharmony_ci		sglp->nsge = cpu_to_be16(1);
85462306a36Sopenharmony_ci		sglp->addr0 = cpu_to_be64(mhp->mpl_addr);
85562306a36Sopenharmony_ci		sglp->len0 = cpu_to_be32(pbllen);
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci		*len16 = DIV_ROUND_UP(sizeof(wqe->fr) + sizeof(*sglp), 16);
85862306a36Sopenharmony_ci	} else {
85962306a36Sopenharmony_ci		imdp = (struct fw_ri_immd *)(&wqe->fr + 1);
86062306a36Sopenharmony_ci		imdp->op = FW_RI_DATA_IMMD;
86162306a36Sopenharmony_ci		imdp->r1 = 0;
86262306a36Sopenharmony_ci		imdp->r2 = 0;
86362306a36Sopenharmony_ci		imdp->immdlen = cpu_to_be32(pbllen);
86462306a36Sopenharmony_ci		p = (__be64 *)(imdp + 1);
86562306a36Sopenharmony_ci		rem = pbllen;
86662306a36Sopenharmony_ci		for (i = 0; i < mhp->mpl_len; i++) {
86762306a36Sopenharmony_ci			*p = cpu_to_be64((u64)mhp->mpl[i]);
86862306a36Sopenharmony_ci			rem -= sizeof(*p);
86962306a36Sopenharmony_ci			if (++p == (__be64 *)&sq->queue[sq->size])
87062306a36Sopenharmony_ci				p = (__be64 *)sq->queue;
87162306a36Sopenharmony_ci		}
87262306a36Sopenharmony_ci		while (rem) {
87362306a36Sopenharmony_ci			*p = 0;
87462306a36Sopenharmony_ci			rem -= sizeof(*p);
87562306a36Sopenharmony_ci			if (++p == (__be64 *)&sq->queue[sq->size])
87662306a36Sopenharmony_ci				p = (__be64 *)sq->queue;
87762306a36Sopenharmony_ci		}
87862306a36Sopenharmony_ci		*len16 = DIV_ROUND_UP(sizeof(wqe->fr) + sizeof(*imdp)
87962306a36Sopenharmony_ci				      + pbllen, 16);
88062306a36Sopenharmony_ci	}
88162306a36Sopenharmony_ci	return 0;
88262306a36Sopenharmony_ci}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_cistatic int build_inv_stag(union t4_wr *wqe, const struct ib_send_wr *wr,
88562306a36Sopenharmony_ci			  u8 *len16)
88662306a36Sopenharmony_ci{
88762306a36Sopenharmony_ci	wqe->inv.stag_inv = cpu_to_be32(wr->ex.invalidate_rkey);
88862306a36Sopenharmony_ci	wqe->inv.r2 = 0;
88962306a36Sopenharmony_ci	*len16 = DIV_ROUND_UP(sizeof(wqe->inv), 16);
89062306a36Sopenharmony_ci	return 0;
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_civoid c4iw_qp_add_ref(struct ib_qp *qp)
89462306a36Sopenharmony_ci{
89562306a36Sopenharmony_ci	pr_debug("ib_qp %p\n", qp);
89662306a36Sopenharmony_ci	refcount_inc(&to_c4iw_qp(qp)->qp_refcnt);
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_civoid c4iw_qp_rem_ref(struct ib_qp *qp)
90062306a36Sopenharmony_ci{
90162306a36Sopenharmony_ci	pr_debug("ib_qp %p\n", qp);
90262306a36Sopenharmony_ci	if (refcount_dec_and_test(&to_c4iw_qp(qp)->qp_refcnt))
90362306a36Sopenharmony_ci		complete(&to_c4iw_qp(qp)->qp_rel_comp);
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_cistatic void add_to_fc_list(struct list_head *head, struct list_head *entry)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	if (list_empty(entry))
90962306a36Sopenharmony_ci		list_add_tail(entry, head);
91062306a36Sopenharmony_ci}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_cistatic int ring_kernel_sq_db(struct c4iw_qp *qhp, u16 inc)
91362306a36Sopenharmony_ci{
91462306a36Sopenharmony_ci	unsigned long flags;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	xa_lock_irqsave(&qhp->rhp->qps, flags);
91762306a36Sopenharmony_ci	spin_lock(&qhp->lock);
91862306a36Sopenharmony_ci	if (qhp->rhp->db_state == NORMAL)
91962306a36Sopenharmony_ci		t4_ring_sq_db(&qhp->wq, inc, NULL);
92062306a36Sopenharmony_ci	else {
92162306a36Sopenharmony_ci		add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry);
92262306a36Sopenharmony_ci		qhp->wq.sq.wq_pidx_inc += inc;
92362306a36Sopenharmony_ci	}
92462306a36Sopenharmony_ci	spin_unlock(&qhp->lock);
92562306a36Sopenharmony_ci	xa_unlock_irqrestore(&qhp->rhp->qps, flags);
92662306a36Sopenharmony_ci	return 0;
92762306a36Sopenharmony_ci}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_cistatic int ring_kernel_rq_db(struct c4iw_qp *qhp, u16 inc)
93062306a36Sopenharmony_ci{
93162306a36Sopenharmony_ci	unsigned long flags;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	xa_lock_irqsave(&qhp->rhp->qps, flags);
93462306a36Sopenharmony_ci	spin_lock(&qhp->lock);
93562306a36Sopenharmony_ci	if (qhp->rhp->db_state == NORMAL)
93662306a36Sopenharmony_ci		t4_ring_rq_db(&qhp->wq, inc, NULL);
93762306a36Sopenharmony_ci	else {
93862306a36Sopenharmony_ci		add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry);
93962306a36Sopenharmony_ci		qhp->wq.rq.wq_pidx_inc += inc;
94062306a36Sopenharmony_ci	}
94162306a36Sopenharmony_ci	spin_unlock(&qhp->lock);
94262306a36Sopenharmony_ci	xa_unlock_irqrestore(&qhp->rhp->qps, flags);
94362306a36Sopenharmony_ci	return 0;
94462306a36Sopenharmony_ci}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_cistatic int ib_to_fw_opcode(int ib_opcode)
94762306a36Sopenharmony_ci{
94862306a36Sopenharmony_ci	int opcode;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	switch (ib_opcode) {
95162306a36Sopenharmony_ci	case IB_WR_SEND_WITH_INV:
95262306a36Sopenharmony_ci		opcode = FW_RI_SEND_WITH_INV;
95362306a36Sopenharmony_ci		break;
95462306a36Sopenharmony_ci	case IB_WR_SEND:
95562306a36Sopenharmony_ci		opcode = FW_RI_SEND;
95662306a36Sopenharmony_ci		break;
95762306a36Sopenharmony_ci	case IB_WR_RDMA_WRITE:
95862306a36Sopenharmony_ci		opcode = FW_RI_RDMA_WRITE;
95962306a36Sopenharmony_ci		break;
96062306a36Sopenharmony_ci	case IB_WR_RDMA_WRITE_WITH_IMM:
96162306a36Sopenharmony_ci		opcode = FW_RI_WRITE_IMMEDIATE;
96262306a36Sopenharmony_ci		break;
96362306a36Sopenharmony_ci	case IB_WR_RDMA_READ:
96462306a36Sopenharmony_ci	case IB_WR_RDMA_READ_WITH_INV:
96562306a36Sopenharmony_ci		opcode = FW_RI_READ_REQ;
96662306a36Sopenharmony_ci		break;
96762306a36Sopenharmony_ci	case IB_WR_REG_MR:
96862306a36Sopenharmony_ci		opcode = FW_RI_FAST_REGISTER;
96962306a36Sopenharmony_ci		break;
97062306a36Sopenharmony_ci	case IB_WR_LOCAL_INV:
97162306a36Sopenharmony_ci		opcode = FW_RI_LOCAL_INV;
97262306a36Sopenharmony_ci		break;
97362306a36Sopenharmony_ci	default:
97462306a36Sopenharmony_ci		opcode = -EINVAL;
97562306a36Sopenharmony_ci	}
97662306a36Sopenharmony_ci	return opcode;
97762306a36Sopenharmony_ci}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_cistatic int complete_sq_drain_wr(struct c4iw_qp *qhp,
98062306a36Sopenharmony_ci				const struct ib_send_wr *wr)
98162306a36Sopenharmony_ci{
98262306a36Sopenharmony_ci	struct t4_cqe cqe = {};
98362306a36Sopenharmony_ci	struct c4iw_cq *schp;
98462306a36Sopenharmony_ci	unsigned long flag;
98562306a36Sopenharmony_ci	struct t4_cq *cq;
98662306a36Sopenharmony_ci	int opcode;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	schp = to_c4iw_cq(qhp->ibqp.send_cq);
98962306a36Sopenharmony_ci	cq = &schp->cq;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	opcode = ib_to_fw_opcode(wr->opcode);
99262306a36Sopenharmony_ci	if (opcode < 0)
99362306a36Sopenharmony_ci		return opcode;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	cqe.u.drain_cookie = wr->wr_id;
99662306a36Sopenharmony_ci	cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) |
99762306a36Sopenharmony_ci				 CQE_OPCODE_V(opcode) |
99862306a36Sopenharmony_ci				 CQE_TYPE_V(1) |
99962306a36Sopenharmony_ci				 CQE_SWCQE_V(1) |
100062306a36Sopenharmony_ci				 CQE_DRAIN_V(1) |
100162306a36Sopenharmony_ci				 CQE_QPID_V(qhp->wq.sq.qid));
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	spin_lock_irqsave(&schp->lock, flag);
100462306a36Sopenharmony_ci	cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen));
100562306a36Sopenharmony_ci	cq->sw_queue[cq->sw_pidx] = cqe;
100662306a36Sopenharmony_ci	t4_swcq_produce(cq);
100762306a36Sopenharmony_ci	spin_unlock_irqrestore(&schp->lock, flag);
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	if (t4_clear_cq_armed(&schp->cq)) {
101062306a36Sopenharmony_ci		spin_lock_irqsave(&schp->comp_handler_lock, flag);
101162306a36Sopenharmony_ci		(*schp->ibcq.comp_handler)(&schp->ibcq,
101262306a36Sopenharmony_ci					   schp->ibcq.cq_context);
101362306a36Sopenharmony_ci		spin_unlock_irqrestore(&schp->comp_handler_lock, flag);
101462306a36Sopenharmony_ci	}
101562306a36Sopenharmony_ci	return 0;
101662306a36Sopenharmony_ci}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_cistatic int complete_sq_drain_wrs(struct c4iw_qp *qhp,
101962306a36Sopenharmony_ci				 const struct ib_send_wr *wr,
102062306a36Sopenharmony_ci				 const struct ib_send_wr **bad_wr)
102162306a36Sopenharmony_ci{
102262306a36Sopenharmony_ci	int ret = 0;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	while (wr) {
102562306a36Sopenharmony_ci		ret = complete_sq_drain_wr(qhp, wr);
102662306a36Sopenharmony_ci		if (ret) {
102762306a36Sopenharmony_ci			*bad_wr = wr;
102862306a36Sopenharmony_ci			break;
102962306a36Sopenharmony_ci		}
103062306a36Sopenharmony_ci		wr = wr->next;
103162306a36Sopenharmony_ci	}
103262306a36Sopenharmony_ci	return ret;
103362306a36Sopenharmony_ci}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_cistatic void complete_rq_drain_wr(struct c4iw_qp *qhp,
103662306a36Sopenharmony_ci				 const struct ib_recv_wr *wr)
103762306a36Sopenharmony_ci{
103862306a36Sopenharmony_ci	struct t4_cqe cqe = {};
103962306a36Sopenharmony_ci	struct c4iw_cq *rchp;
104062306a36Sopenharmony_ci	unsigned long flag;
104162306a36Sopenharmony_ci	struct t4_cq *cq;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	rchp = to_c4iw_cq(qhp->ibqp.recv_cq);
104462306a36Sopenharmony_ci	cq = &rchp->cq;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	cqe.u.drain_cookie = wr->wr_id;
104762306a36Sopenharmony_ci	cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) |
104862306a36Sopenharmony_ci				 CQE_OPCODE_V(FW_RI_SEND) |
104962306a36Sopenharmony_ci				 CQE_TYPE_V(0) |
105062306a36Sopenharmony_ci				 CQE_SWCQE_V(1) |
105162306a36Sopenharmony_ci				 CQE_DRAIN_V(1) |
105262306a36Sopenharmony_ci				 CQE_QPID_V(qhp->wq.sq.qid));
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	spin_lock_irqsave(&rchp->lock, flag);
105562306a36Sopenharmony_ci	cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen));
105662306a36Sopenharmony_ci	cq->sw_queue[cq->sw_pidx] = cqe;
105762306a36Sopenharmony_ci	t4_swcq_produce(cq);
105862306a36Sopenharmony_ci	spin_unlock_irqrestore(&rchp->lock, flag);
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	if (t4_clear_cq_armed(&rchp->cq)) {
106162306a36Sopenharmony_ci		spin_lock_irqsave(&rchp->comp_handler_lock, flag);
106262306a36Sopenharmony_ci		(*rchp->ibcq.comp_handler)(&rchp->ibcq,
106362306a36Sopenharmony_ci					   rchp->ibcq.cq_context);
106462306a36Sopenharmony_ci		spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
106562306a36Sopenharmony_ci	}
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_cistatic void complete_rq_drain_wrs(struct c4iw_qp *qhp,
106962306a36Sopenharmony_ci				  const struct ib_recv_wr *wr)
107062306a36Sopenharmony_ci{
107162306a36Sopenharmony_ci	while (wr) {
107262306a36Sopenharmony_ci		complete_rq_drain_wr(qhp, wr);
107362306a36Sopenharmony_ci		wr = wr->next;
107462306a36Sopenharmony_ci	}
107562306a36Sopenharmony_ci}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ciint c4iw_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
107862306a36Sopenharmony_ci		   const struct ib_send_wr **bad_wr)
107962306a36Sopenharmony_ci{
108062306a36Sopenharmony_ci	int err = 0;
108162306a36Sopenharmony_ci	u8 len16 = 0;
108262306a36Sopenharmony_ci	enum fw_wr_opcodes fw_opcode = 0;
108362306a36Sopenharmony_ci	enum fw_ri_wr_flags fw_flags;
108462306a36Sopenharmony_ci	struct c4iw_qp *qhp;
108562306a36Sopenharmony_ci	struct c4iw_dev *rhp;
108662306a36Sopenharmony_ci	union t4_wr *wqe = NULL;
108762306a36Sopenharmony_ci	u32 num_wrs;
108862306a36Sopenharmony_ci	struct t4_swsqe *swsqe;
108962306a36Sopenharmony_ci	unsigned long flag;
109062306a36Sopenharmony_ci	u16 idx = 0;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	qhp = to_c4iw_qp(ibqp);
109362306a36Sopenharmony_ci	rhp = qhp->rhp;
109462306a36Sopenharmony_ci	spin_lock_irqsave(&qhp->lock, flag);
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	/*
109762306a36Sopenharmony_ci	 * If the qp has been flushed, then just insert a special
109862306a36Sopenharmony_ci	 * drain cqe.
109962306a36Sopenharmony_ci	 */
110062306a36Sopenharmony_ci	if (qhp->wq.flushed) {
110162306a36Sopenharmony_ci		spin_unlock_irqrestore(&qhp->lock, flag);
110262306a36Sopenharmony_ci		err = complete_sq_drain_wrs(qhp, wr, bad_wr);
110362306a36Sopenharmony_ci		return err;
110462306a36Sopenharmony_ci	}
110562306a36Sopenharmony_ci	num_wrs = t4_sq_avail(&qhp->wq);
110662306a36Sopenharmony_ci	if (num_wrs == 0) {
110762306a36Sopenharmony_ci		spin_unlock_irqrestore(&qhp->lock, flag);
110862306a36Sopenharmony_ci		*bad_wr = wr;
110962306a36Sopenharmony_ci		return -ENOMEM;
111062306a36Sopenharmony_ci	}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	/*
111362306a36Sopenharmony_ci	 * Fastpath for NVMe-oF target WRITE + SEND_WITH_INV wr chain which is
111462306a36Sopenharmony_ci	 * the response for small NVMEe-oF READ requests.  If the chain is
111562306a36Sopenharmony_ci	 * exactly a WRITE->SEND_WITH_INV or a WRITE->SEND and the sgl depths
111662306a36Sopenharmony_ci	 * and lengths meet the requirements of the fw_ri_write_cmpl_wr work
111762306a36Sopenharmony_ci	 * request, then build and post the write_cmpl WR. If any of the tests
111862306a36Sopenharmony_ci	 * below are not true, then we continue on with the tradtional WRITE
111962306a36Sopenharmony_ci	 * and SEND WRs.
112062306a36Sopenharmony_ci	 */
112162306a36Sopenharmony_ci	if (qhp->rhp->rdev.lldi.write_cmpl_support &&
112262306a36Sopenharmony_ci	    CHELSIO_CHIP_VERSION(qhp->rhp->rdev.lldi.adapter_type) >=
112362306a36Sopenharmony_ci	    CHELSIO_T5 &&
112462306a36Sopenharmony_ci	    wr && wr->next && !wr->next->next &&
112562306a36Sopenharmony_ci	    wr->opcode == IB_WR_RDMA_WRITE &&
112662306a36Sopenharmony_ci	    wr->sg_list[0].length && wr->num_sge <= T4_WRITE_CMPL_MAX_SGL &&
112762306a36Sopenharmony_ci	    (wr->next->opcode == IB_WR_SEND ||
112862306a36Sopenharmony_ci	    wr->next->opcode == IB_WR_SEND_WITH_INV) &&
112962306a36Sopenharmony_ci	    wr->next->sg_list[0].length == T4_WRITE_CMPL_MAX_CQE &&
113062306a36Sopenharmony_ci	    wr->next->num_sge == 1 && num_wrs >= 2) {
113162306a36Sopenharmony_ci		post_write_cmpl(qhp, wr);
113262306a36Sopenharmony_ci		spin_unlock_irqrestore(&qhp->lock, flag);
113362306a36Sopenharmony_ci		return 0;
113462306a36Sopenharmony_ci	}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	while (wr) {
113762306a36Sopenharmony_ci		if (num_wrs == 0) {
113862306a36Sopenharmony_ci			err = -ENOMEM;
113962306a36Sopenharmony_ci			*bad_wr = wr;
114062306a36Sopenharmony_ci			break;
114162306a36Sopenharmony_ci		}
114262306a36Sopenharmony_ci		wqe = (union t4_wr *)((u8 *)qhp->wq.sq.queue +
114362306a36Sopenharmony_ci		      qhp->wq.sq.wq_pidx * T4_EQ_ENTRY_SIZE);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci		fw_flags = 0;
114662306a36Sopenharmony_ci		if (wr->send_flags & IB_SEND_SOLICITED)
114762306a36Sopenharmony_ci			fw_flags |= FW_RI_SOLICITED_EVENT_FLAG;
114862306a36Sopenharmony_ci		if (wr->send_flags & IB_SEND_SIGNALED || qhp->sq_sig_all)
114962306a36Sopenharmony_ci			fw_flags |= FW_RI_COMPLETION_FLAG;
115062306a36Sopenharmony_ci		swsqe = &qhp->wq.sq.sw_sq[qhp->wq.sq.pidx];
115162306a36Sopenharmony_ci		switch (wr->opcode) {
115262306a36Sopenharmony_ci		case IB_WR_SEND_WITH_INV:
115362306a36Sopenharmony_ci		case IB_WR_SEND:
115462306a36Sopenharmony_ci			if (wr->send_flags & IB_SEND_FENCE)
115562306a36Sopenharmony_ci				fw_flags |= FW_RI_READ_FENCE_FLAG;
115662306a36Sopenharmony_ci			fw_opcode = FW_RI_SEND_WR;
115762306a36Sopenharmony_ci			if (wr->opcode == IB_WR_SEND)
115862306a36Sopenharmony_ci				swsqe->opcode = FW_RI_SEND;
115962306a36Sopenharmony_ci			else
116062306a36Sopenharmony_ci				swsqe->opcode = FW_RI_SEND_WITH_INV;
116162306a36Sopenharmony_ci			err = build_rdma_send(&qhp->wq.sq, wqe, wr, &len16);
116262306a36Sopenharmony_ci			break;
116362306a36Sopenharmony_ci		case IB_WR_RDMA_WRITE_WITH_IMM:
116462306a36Sopenharmony_ci			if (unlikely(!rhp->rdev.lldi.write_w_imm_support)) {
116562306a36Sopenharmony_ci				err = -EINVAL;
116662306a36Sopenharmony_ci				break;
116762306a36Sopenharmony_ci			}
116862306a36Sopenharmony_ci			fw_flags |= FW_RI_RDMA_WRITE_WITH_IMMEDIATE;
116962306a36Sopenharmony_ci			fallthrough;
117062306a36Sopenharmony_ci		case IB_WR_RDMA_WRITE:
117162306a36Sopenharmony_ci			fw_opcode = FW_RI_RDMA_WRITE_WR;
117262306a36Sopenharmony_ci			swsqe->opcode = FW_RI_RDMA_WRITE;
117362306a36Sopenharmony_ci			err = build_rdma_write(&qhp->wq.sq, wqe, wr, &len16);
117462306a36Sopenharmony_ci			break;
117562306a36Sopenharmony_ci		case IB_WR_RDMA_READ:
117662306a36Sopenharmony_ci		case IB_WR_RDMA_READ_WITH_INV:
117762306a36Sopenharmony_ci			fw_opcode = FW_RI_RDMA_READ_WR;
117862306a36Sopenharmony_ci			swsqe->opcode = FW_RI_READ_REQ;
117962306a36Sopenharmony_ci			if (wr->opcode == IB_WR_RDMA_READ_WITH_INV) {
118062306a36Sopenharmony_ci				c4iw_invalidate_mr(rhp, wr->sg_list[0].lkey);
118162306a36Sopenharmony_ci				fw_flags = FW_RI_RDMA_READ_INVALIDATE;
118262306a36Sopenharmony_ci			} else {
118362306a36Sopenharmony_ci				fw_flags = 0;
118462306a36Sopenharmony_ci			}
118562306a36Sopenharmony_ci			err = build_rdma_read(wqe, wr, &len16);
118662306a36Sopenharmony_ci			if (err)
118762306a36Sopenharmony_ci				break;
118862306a36Sopenharmony_ci			swsqe->read_len = wr->sg_list[0].length;
118962306a36Sopenharmony_ci			if (!qhp->wq.sq.oldest_read)
119062306a36Sopenharmony_ci				qhp->wq.sq.oldest_read = swsqe;
119162306a36Sopenharmony_ci			break;
119262306a36Sopenharmony_ci		case IB_WR_REG_MR: {
119362306a36Sopenharmony_ci			struct c4iw_mr *mhp = to_c4iw_mr(reg_wr(wr)->mr);
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci			swsqe->opcode = FW_RI_FAST_REGISTER;
119662306a36Sopenharmony_ci			if (rhp->rdev.lldi.fr_nsmr_tpte_wr_support &&
119762306a36Sopenharmony_ci			    !mhp->attr.state && mhp->mpl_len <= 2) {
119862306a36Sopenharmony_ci				fw_opcode = FW_RI_FR_NSMR_TPTE_WR;
119962306a36Sopenharmony_ci				build_tpte_memreg(&wqe->fr_tpte, reg_wr(wr),
120062306a36Sopenharmony_ci						  mhp, &len16);
120162306a36Sopenharmony_ci			} else {
120262306a36Sopenharmony_ci				fw_opcode = FW_RI_FR_NSMR_WR;
120362306a36Sopenharmony_ci				err = build_memreg(&qhp->wq.sq, wqe, reg_wr(wr),
120462306a36Sopenharmony_ci				       mhp, &len16,
120562306a36Sopenharmony_ci				       rhp->rdev.lldi.ulptx_memwrite_dsgl);
120662306a36Sopenharmony_ci				if (err)
120762306a36Sopenharmony_ci					break;
120862306a36Sopenharmony_ci			}
120962306a36Sopenharmony_ci			mhp->attr.state = 1;
121062306a36Sopenharmony_ci			break;
121162306a36Sopenharmony_ci		}
121262306a36Sopenharmony_ci		case IB_WR_LOCAL_INV:
121362306a36Sopenharmony_ci			if (wr->send_flags & IB_SEND_FENCE)
121462306a36Sopenharmony_ci				fw_flags |= FW_RI_LOCAL_FENCE_FLAG;
121562306a36Sopenharmony_ci			fw_opcode = FW_RI_INV_LSTAG_WR;
121662306a36Sopenharmony_ci			swsqe->opcode = FW_RI_LOCAL_INV;
121762306a36Sopenharmony_ci			err = build_inv_stag(wqe, wr, &len16);
121862306a36Sopenharmony_ci			c4iw_invalidate_mr(rhp, wr->ex.invalidate_rkey);
121962306a36Sopenharmony_ci			break;
122062306a36Sopenharmony_ci		default:
122162306a36Sopenharmony_ci			pr_warn("%s post of type=%d TBD!\n", __func__,
122262306a36Sopenharmony_ci				wr->opcode);
122362306a36Sopenharmony_ci			err = -EINVAL;
122462306a36Sopenharmony_ci		}
122562306a36Sopenharmony_ci		if (err) {
122662306a36Sopenharmony_ci			*bad_wr = wr;
122762306a36Sopenharmony_ci			break;
122862306a36Sopenharmony_ci		}
122962306a36Sopenharmony_ci		swsqe->idx = qhp->wq.sq.pidx;
123062306a36Sopenharmony_ci		swsqe->complete = 0;
123162306a36Sopenharmony_ci		swsqe->signaled = (wr->send_flags & IB_SEND_SIGNALED) ||
123262306a36Sopenharmony_ci				  qhp->sq_sig_all;
123362306a36Sopenharmony_ci		swsqe->flushed = 0;
123462306a36Sopenharmony_ci		swsqe->wr_id = wr->wr_id;
123562306a36Sopenharmony_ci		if (c4iw_wr_log) {
123662306a36Sopenharmony_ci			swsqe->sge_ts = cxgb4_read_sge_timestamp(
123762306a36Sopenharmony_ci					rhp->rdev.lldi.ports[0]);
123862306a36Sopenharmony_ci			swsqe->host_time = ktime_get();
123962306a36Sopenharmony_ci		}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci		init_wr_hdr(wqe, qhp->wq.sq.pidx, fw_opcode, fw_flags, len16);
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci		pr_debug("cookie 0x%llx pidx 0x%x opcode 0x%x read_len %u\n",
124462306a36Sopenharmony_ci			 (unsigned long long)wr->wr_id, qhp->wq.sq.pidx,
124562306a36Sopenharmony_ci			 swsqe->opcode, swsqe->read_len);
124662306a36Sopenharmony_ci		wr = wr->next;
124762306a36Sopenharmony_ci		num_wrs--;
124862306a36Sopenharmony_ci		t4_sq_produce(&qhp->wq, len16);
124962306a36Sopenharmony_ci		idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE);
125062306a36Sopenharmony_ci	}
125162306a36Sopenharmony_ci	if (!rhp->rdev.status_page->db_off) {
125262306a36Sopenharmony_ci		t4_ring_sq_db(&qhp->wq, idx, wqe);
125362306a36Sopenharmony_ci		spin_unlock_irqrestore(&qhp->lock, flag);
125462306a36Sopenharmony_ci	} else {
125562306a36Sopenharmony_ci		spin_unlock_irqrestore(&qhp->lock, flag);
125662306a36Sopenharmony_ci		ring_kernel_sq_db(qhp, idx);
125762306a36Sopenharmony_ci	}
125862306a36Sopenharmony_ci	return err;
125962306a36Sopenharmony_ci}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ciint c4iw_post_receive(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
126262306a36Sopenharmony_ci		      const struct ib_recv_wr **bad_wr)
126362306a36Sopenharmony_ci{
126462306a36Sopenharmony_ci	int err = 0;
126562306a36Sopenharmony_ci	struct c4iw_qp *qhp;
126662306a36Sopenharmony_ci	union t4_recv_wr *wqe = NULL;
126762306a36Sopenharmony_ci	u32 num_wrs;
126862306a36Sopenharmony_ci	u8 len16 = 0;
126962306a36Sopenharmony_ci	unsigned long flag;
127062306a36Sopenharmony_ci	u16 idx = 0;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	qhp = to_c4iw_qp(ibqp);
127362306a36Sopenharmony_ci	spin_lock_irqsave(&qhp->lock, flag);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	/*
127662306a36Sopenharmony_ci	 * If the qp has been flushed, then just insert a special
127762306a36Sopenharmony_ci	 * drain cqe.
127862306a36Sopenharmony_ci	 */
127962306a36Sopenharmony_ci	if (qhp->wq.flushed) {
128062306a36Sopenharmony_ci		spin_unlock_irqrestore(&qhp->lock, flag);
128162306a36Sopenharmony_ci		complete_rq_drain_wrs(qhp, wr);
128262306a36Sopenharmony_ci		return err;
128362306a36Sopenharmony_ci	}
128462306a36Sopenharmony_ci	num_wrs = t4_rq_avail(&qhp->wq);
128562306a36Sopenharmony_ci	if (num_wrs == 0) {
128662306a36Sopenharmony_ci		spin_unlock_irqrestore(&qhp->lock, flag);
128762306a36Sopenharmony_ci		*bad_wr = wr;
128862306a36Sopenharmony_ci		return -ENOMEM;
128962306a36Sopenharmony_ci	}
129062306a36Sopenharmony_ci	while (wr) {
129162306a36Sopenharmony_ci		if (wr->num_sge > T4_MAX_RECV_SGE) {
129262306a36Sopenharmony_ci			err = -EINVAL;
129362306a36Sopenharmony_ci			*bad_wr = wr;
129462306a36Sopenharmony_ci			break;
129562306a36Sopenharmony_ci		}
129662306a36Sopenharmony_ci		wqe = (union t4_recv_wr *)((u8 *)qhp->wq.rq.queue +
129762306a36Sopenharmony_ci					   qhp->wq.rq.wq_pidx *
129862306a36Sopenharmony_ci					   T4_EQ_ENTRY_SIZE);
129962306a36Sopenharmony_ci		if (num_wrs)
130062306a36Sopenharmony_ci			err = build_rdma_recv(qhp, wqe, wr, &len16);
130162306a36Sopenharmony_ci		else
130262306a36Sopenharmony_ci			err = -ENOMEM;
130362306a36Sopenharmony_ci		if (err) {
130462306a36Sopenharmony_ci			*bad_wr = wr;
130562306a36Sopenharmony_ci			break;
130662306a36Sopenharmony_ci		}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci		qhp->wq.rq.sw_rq[qhp->wq.rq.pidx].wr_id = wr->wr_id;
130962306a36Sopenharmony_ci		if (c4iw_wr_log) {
131062306a36Sopenharmony_ci			qhp->wq.rq.sw_rq[qhp->wq.rq.pidx].sge_ts =
131162306a36Sopenharmony_ci				cxgb4_read_sge_timestamp(
131262306a36Sopenharmony_ci						qhp->rhp->rdev.lldi.ports[0]);
131362306a36Sopenharmony_ci			qhp->wq.rq.sw_rq[qhp->wq.rq.pidx].host_time =
131462306a36Sopenharmony_ci				ktime_get();
131562306a36Sopenharmony_ci		}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci		wqe->recv.opcode = FW_RI_RECV_WR;
131862306a36Sopenharmony_ci		wqe->recv.r1 = 0;
131962306a36Sopenharmony_ci		wqe->recv.wrid = qhp->wq.rq.pidx;
132062306a36Sopenharmony_ci		wqe->recv.r2[0] = 0;
132162306a36Sopenharmony_ci		wqe->recv.r2[1] = 0;
132262306a36Sopenharmony_ci		wqe->recv.r2[2] = 0;
132362306a36Sopenharmony_ci		wqe->recv.len16 = len16;
132462306a36Sopenharmony_ci		pr_debug("cookie 0x%llx pidx %u\n",
132562306a36Sopenharmony_ci			 (unsigned long long)wr->wr_id, qhp->wq.rq.pidx);
132662306a36Sopenharmony_ci		t4_rq_produce(&qhp->wq, len16);
132762306a36Sopenharmony_ci		idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE);
132862306a36Sopenharmony_ci		wr = wr->next;
132962306a36Sopenharmony_ci		num_wrs--;
133062306a36Sopenharmony_ci	}
133162306a36Sopenharmony_ci	if (!qhp->rhp->rdev.status_page->db_off) {
133262306a36Sopenharmony_ci		t4_ring_rq_db(&qhp->wq, idx, wqe);
133362306a36Sopenharmony_ci		spin_unlock_irqrestore(&qhp->lock, flag);
133462306a36Sopenharmony_ci	} else {
133562306a36Sopenharmony_ci		spin_unlock_irqrestore(&qhp->lock, flag);
133662306a36Sopenharmony_ci		ring_kernel_rq_db(qhp, idx);
133762306a36Sopenharmony_ci	}
133862306a36Sopenharmony_ci	return err;
133962306a36Sopenharmony_ci}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_cistatic void defer_srq_wr(struct t4_srq *srq, union t4_recv_wr *wqe,
134262306a36Sopenharmony_ci			 u64 wr_id, u8 len16)
134362306a36Sopenharmony_ci{
134462306a36Sopenharmony_ci	struct t4_srq_pending_wr *pwr = &srq->pending_wrs[srq->pending_pidx];
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	pr_debug("%s cidx %u pidx %u wq_pidx %u in_use %u ooo_count %u wr_id 0x%llx pending_cidx %u pending_pidx %u pending_in_use %u\n",
134762306a36Sopenharmony_ci		 __func__, srq->cidx, srq->pidx, srq->wq_pidx,
134862306a36Sopenharmony_ci		 srq->in_use, srq->ooo_count,
134962306a36Sopenharmony_ci		 (unsigned long long)wr_id, srq->pending_cidx,
135062306a36Sopenharmony_ci		 srq->pending_pidx, srq->pending_in_use);
135162306a36Sopenharmony_ci	pwr->wr_id = wr_id;
135262306a36Sopenharmony_ci	pwr->len16 = len16;
135362306a36Sopenharmony_ci	memcpy(&pwr->wqe, wqe, len16 * 16);
135462306a36Sopenharmony_ci	t4_srq_produce_pending_wr(srq);
135562306a36Sopenharmony_ci}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ciint c4iw_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
135862306a36Sopenharmony_ci		       const struct ib_recv_wr **bad_wr)
135962306a36Sopenharmony_ci{
136062306a36Sopenharmony_ci	union t4_recv_wr *wqe, lwqe;
136162306a36Sopenharmony_ci	struct c4iw_srq *srq;
136262306a36Sopenharmony_ci	unsigned long flag;
136362306a36Sopenharmony_ci	u8 len16 = 0;
136462306a36Sopenharmony_ci	u16 idx = 0;
136562306a36Sopenharmony_ci	int err = 0;
136662306a36Sopenharmony_ci	u32 num_wrs;
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	srq = to_c4iw_srq(ibsrq);
136962306a36Sopenharmony_ci	spin_lock_irqsave(&srq->lock, flag);
137062306a36Sopenharmony_ci	num_wrs = t4_srq_avail(&srq->wq);
137162306a36Sopenharmony_ci	if (num_wrs == 0) {
137262306a36Sopenharmony_ci		spin_unlock_irqrestore(&srq->lock, flag);
137362306a36Sopenharmony_ci		return -ENOMEM;
137462306a36Sopenharmony_ci	}
137562306a36Sopenharmony_ci	while (wr) {
137662306a36Sopenharmony_ci		if (wr->num_sge > T4_MAX_RECV_SGE) {
137762306a36Sopenharmony_ci			err = -EINVAL;
137862306a36Sopenharmony_ci			*bad_wr = wr;
137962306a36Sopenharmony_ci			break;
138062306a36Sopenharmony_ci		}
138162306a36Sopenharmony_ci		wqe = &lwqe;
138262306a36Sopenharmony_ci		if (num_wrs)
138362306a36Sopenharmony_ci			err = build_srq_recv(wqe, wr, &len16);
138462306a36Sopenharmony_ci		else
138562306a36Sopenharmony_ci			err = -ENOMEM;
138662306a36Sopenharmony_ci		if (err) {
138762306a36Sopenharmony_ci			*bad_wr = wr;
138862306a36Sopenharmony_ci			break;
138962306a36Sopenharmony_ci		}
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci		wqe->recv.opcode = FW_RI_RECV_WR;
139262306a36Sopenharmony_ci		wqe->recv.r1 = 0;
139362306a36Sopenharmony_ci		wqe->recv.wrid = srq->wq.pidx;
139462306a36Sopenharmony_ci		wqe->recv.r2[0] = 0;
139562306a36Sopenharmony_ci		wqe->recv.r2[1] = 0;
139662306a36Sopenharmony_ci		wqe->recv.r2[2] = 0;
139762306a36Sopenharmony_ci		wqe->recv.len16 = len16;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci		if (srq->wq.ooo_count ||
140062306a36Sopenharmony_ci		    srq->wq.pending_in_use ||
140162306a36Sopenharmony_ci		    srq->wq.sw_rq[srq->wq.pidx].valid) {
140262306a36Sopenharmony_ci			defer_srq_wr(&srq->wq, wqe, wr->wr_id, len16);
140362306a36Sopenharmony_ci		} else {
140462306a36Sopenharmony_ci			srq->wq.sw_rq[srq->wq.pidx].wr_id = wr->wr_id;
140562306a36Sopenharmony_ci			srq->wq.sw_rq[srq->wq.pidx].valid = 1;
140662306a36Sopenharmony_ci			c4iw_copy_wr_to_srq(&srq->wq, wqe, len16);
140762306a36Sopenharmony_ci			pr_debug("%s cidx %u pidx %u wq_pidx %u in_use %u wr_id 0x%llx\n",
140862306a36Sopenharmony_ci				 __func__, srq->wq.cidx,
140962306a36Sopenharmony_ci				 srq->wq.pidx, srq->wq.wq_pidx,
141062306a36Sopenharmony_ci				 srq->wq.in_use,
141162306a36Sopenharmony_ci				 (unsigned long long)wr->wr_id);
141262306a36Sopenharmony_ci			t4_srq_produce(&srq->wq, len16);
141362306a36Sopenharmony_ci			idx += DIV_ROUND_UP(len16 * 16, T4_EQ_ENTRY_SIZE);
141462306a36Sopenharmony_ci		}
141562306a36Sopenharmony_ci		wr = wr->next;
141662306a36Sopenharmony_ci		num_wrs--;
141762306a36Sopenharmony_ci	}
141862306a36Sopenharmony_ci	if (idx)
141962306a36Sopenharmony_ci		t4_ring_srq_db(&srq->wq, idx, len16, wqe);
142062306a36Sopenharmony_ci	spin_unlock_irqrestore(&srq->lock, flag);
142162306a36Sopenharmony_ci	return err;
142262306a36Sopenharmony_ci}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_cistatic inline void build_term_codes(struct t4_cqe *err_cqe, u8 *layer_type,
142562306a36Sopenharmony_ci				    u8 *ecode)
142662306a36Sopenharmony_ci{
142762306a36Sopenharmony_ci	int status;
142862306a36Sopenharmony_ci	int tagged;
142962306a36Sopenharmony_ci	int opcode;
143062306a36Sopenharmony_ci	int rqtype;
143162306a36Sopenharmony_ci	int send_inv;
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	if (!err_cqe) {
143462306a36Sopenharmony_ci		*layer_type = LAYER_RDMAP|DDP_LOCAL_CATA;
143562306a36Sopenharmony_ci		*ecode = 0;
143662306a36Sopenharmony_ci		return;
143762306a36Sopenharmony_ci	}
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	status = CQE_STATUS(err_cqe);
144062306a36Sopenharmony_ci	opcode = CQE_OPCODE(err_cqe);
144162306a36Sopenharmony_ci	rqtype = RQ_TYPE(err_cqe);
144262306a36Sopenharmony_ci	send_inv = (opcode == FW_RI_SEND_WITH_INV) ||
144362306a36Sopenharmony_ci		   (opcode == FW_RI_SEND_WITH_SE_INV);
144462306a36Sopenharmony_ci	tagged = (opcode == FW_RI_RDMA_WRITE) ||
144562306a36Sopenharmony_ci		 (rqtype && (opcode == FW_RI_READ_RESP));
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	switch (status) {
144862306a36Sopenharmony_ci	case T4_ERR_STAG:
144962306a36Sopenharmony_ci		if (send_inv) {
145062306a36Sopenharmony_ci			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;
145162306a36Sopenharmony_ci			*ecode = RDMAP_CANT_INV_STAG;
145262306a36Sopenharmony_ci		} else {
145362306a36Sopenharmony_ci			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
145462306a36Sopenharmony_ci			*ecode = RDMAP_INV_STAG;
145562306a36Sopenharmony_ci		}
145662306a36Sopenharmony_ci		break;
145762306a36Sopenharmony_ci	case T4_ERR_PDID:
145862306a36Sopenharmony_ci		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
145962306a36Sopenharmony_ci		if ((opcode == FW_RI_SEND_WITH_INV) ||
146062306a36Sopenharmony_ci		    (opcode == FW_RI_SEND_WITH_SE_INV))
146162306a36Sopenharmony_ci			*ecode = RDMAP_CANT_INV_STAG;
146262306a36Sopenharmony_ci		else
146362306a36Sopenharmony_ci			*ecode = RDMAP_STAG_NOT_ASSOC;
146462306a36Sopenharmony_ci		break;
146562306a36Sopenharmony_ci	case T4_ERR_QPID:
146662306a36Sopenharmony_ci		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
146762306a36Sopenharmony_ci		*ecode = RDMAP_STAG_NOT_ASSOC;
146862306a36Sopenharmony_ci		break;
146962306a36Sopenharmony_ci	case T4_ERR_ACCESS:
147062306a36Sopenharmony_ci		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
147162306a36Sopenharmony_ci		*ecode = RDMAP_ACC_VIOL;
147262306a36Sopenharmony_ci		break;
147362306a36Sopenharmony_ci	case T4_ERR_WRAP:
147462306a36Sopenharmony_ci		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
147562306a36Sopenharmony_ci		*ecode = RDMAP_TO_WRAP;
147662306a36Sopenharmony_ci		break;
147762306a36Sopenharmony_ci	case T4_ERR_BOUND:
147862306a36Sopenharmony_ci		if (tagged) {
147962306a36Sopenharmony_ci			*layer_type = LAYER_DDP|DDP_TAGGED_ERR;
148062306a36Sopenharmony_ci			*ecode = DDPT_BASE_BOUNDS;
148162306a36Sopenharmony_ci		} else {
148262306a36Sopenharmony_ci			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
148362306a36Sopenharmony_ci			*ecode = RDMAP_BASE_BOUNDS;
148462306a36Sopenharmony_ci		}
148562306a36Sopenharmony_ci		break;
148662306a36Sopenharmony_ci	case T4_ERR_INVALIDATE_SHARED_MR:
148762306a36Sopenharmony_ci	case T4_ERR_INVALIDATE_MR_WITH_MW_BOUND:
148862306a36Sopenharmony_ci		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;
148962306a36Sopenharmony_ci		*ecode = RDMAP_CANT_INV_STAG;
149062306a36Sopenharmony_ci		break;
149162306a36Sopenharmony_ci	case T4_ERR_ECC:
149262306a36Sopenharmony_ci	case T4_ERR_ECC_PSTAG:
149362306a36Sopenharmony_ci	case T4_ERR_INTERNAL_ERR:
149462306a36Sopenharmony_ci		*layer_type = LAYER_RDMAP|RDMAP_LOCAL_CATA;
149562306a36Sopenharmony_ci		*ecode = 0;
149662306a36Sopenharmony_ci		break;
149762306a36Sopenharmony_ci	case T4_ERR_OUT_OF_RQE:
149862306a36Sopenharmony_ci		*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
149962306a36Sopenharmony_ci		*ecode = DDPU_INV_MSN_NOBUF;
150062306a36Sopenharmony_ci		break;
150162306a36Sopenharmony_ci	case T4_ERR_PBL_ADDR_BOUND:
150262306a36Sopenharmony_ci		*layer_type = LAYER_DDP|DDP_TAGGED_ERR;
150362306a36Sopenharmony_ci		*ecode = DDPT_BASE_BOUNDS;
150462306a36Sopenharmony_ci		break;
150562306a36Sopenharmony_ci	case T4_ERR_CRC:
150662306a36Sopenharmony_ci		*layer_type = LAYER_MPA|DDP_LLP;
150762306a36Sopenharmony_ci		*ecode = MPA_CRC_ERR;
150862306a36Sopenharmony_ci		break;
150962306a36Sopenharmony_ci	case T4_ERR_MARKER:
151062306a36Sopenharmony_ci		*layer_type = LAYER_MPA|DDP_LLP;
151162306a36Sopenharmony_ci		*ecode = MPA_MARKER_ERR;
151262306a36Sopenharmony_ci		break;
151362306a36Sopenharmony_ci	case T4_ERR_PDU_LEN_ERR:
151462306a36Sopenharmony_ci		*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
151562306a36Sopenharmony_ci		*ecode = DDPU_MSG_TOOBIG;
151662306a36Sopenharmony_ci		break;
151762306a36Sopenharmony_ci	case T4_ERR_DDP_VERSION:
151862306a36Sopenharmony_ci		if (tagged) {
151962306a36Sopenharmony_ci			*layer_type = LAYER_DDP|DDP_TAGGED_ERR;
152062306a36Sopenharmony_ci			*ecode = DDPT_INV_VERS;
152162306a36Sopenharmony_ci		} else {
152262306a36Sopenharmony_ci			*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
152362306a36Sopenharmony_ci			*ecode = DDPU_INV_VERS;
152462306a36Sopenharmony_ci		}
152562306a36Sopenharmony_ci		break;
152662306a36Sopenharmony_ci	case T4_ERR_RDMA_VERSION:
152762306a36Sopenharmony_ci		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;
152862306a36Sopenharmony_ci		*ecode = RDMAP_INV_VERS;
152962306a36Sopenharmony_ci		break;
153062306a36Sopenharmony_ci	case T4_ERR_OPCODE:
153162306a36Sopenharmony_ci		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;
153262306a36Sopenharmony_ci		*ecode = RDMAP_INV_OPCODE;
153362306a36Sopenharmony_ci		break;
153462306a36Sopenharmony_ci	case T4_ERR_DDP_QUEUE_NUM:
153562306a36Sopenharmony_ci		*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
153662306a36Sopenharmony_ci		*ecode = DDPU_INV_QN;
153762306a36Sopenharmony_ci		break;
153862306a36Sopenharmony_ci	case T4_ERR_MSN:
153962306a36Sopenharmony_ci	case T4_ERR_MSN_GAP:
154062306a36Sopenharmony_ci	case T4_ERR_MSN_RANGE:
154162306a36Sopenharmony_ci	case T4_ERR_IRD_OVERFLOW:
154262306a36Sopenharmony_ci		*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
154362306a36Sopenharmony_ci		*ecode = DDPU_INV_MSN_RANGE;
154462306a36Sopenharmony_ci		break;
154562306a36Sopenharmony_ci	case T4_ERR_TBIT:
154662306a36Sopenharmony_ci		*layer_type = LAYER_DDP|DDP_LOCAL_CATA;
154762306a36Sopenharmony_ci		*ecode = 0;
154862306a36Sopenharmony_ci		break;
154962306a36Sopenharmony_ci	case T4_ERR_MO:
155062306a36Sopenharmony_ci		*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
155162306a36Sopenharmony_ci		*ecode = DDPU_INV_MO;
155262306a36Sopenharmony_ci		break;
155362306a36Sopenharmony_ci	default:
155462306a36Sopenharmony_ci		*layer_type = LAYER_RDMAP|DDP_LOCAL_CATA;
155562306a36Sopenharmony_ci		*ecode = 0;
155662306a36Sopenharmony_ci		break;
155762306a36Sopenharmony_ci	}
155862306a36Sopenharmony_ci}
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_cistatic void post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe,
156162306a36Sopenharmony_ci			   gfp_t gfp)
156262306a36Sopenharmony_ci{
156362306a36Sopenharmony_ci	struct fw_ri_wr *wqe;
156462306a36Sopenharmony_ci	struct sk_buff *skb;
156562306a36Sopenharmony_ci	struct terminate_message *term;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	pr_debug("qhp %p qid 0x%x tid %u\n", qhp, qhp->wq.sq.qid,
156862306a36Sopenharmony_ci		 qhp->ep->hwtid);
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	skb = skb_dequeue(&qhp->ep->com.ep_skb_list);
157162306a36Sopenharmony_ci	if (WARN_ON(!skb))
157262306a36Sopenharmony_ci		return;
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx);
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	wqe = __skb_put_zero(skb, sizeof(*wqe));
157762306a36Sopenharmony_ci	wqe->op_compl = cpu_to_be32(FW_WR_OP_V(FW_RI_INIT_WR));
157862306a36Sopenharmony_ci	wqe->flowid_len16 = cpu_to_be32(
157962306a36Sopenharmony_ci		FW_WR_FLOWID_V(qhp->ep->hwtid) |
158062306a36Sopenharmony_ci		FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16)));
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	wqe->u.terminate.type = FW_RI_TYPE_TERMINATE;
158362306a36Sopenharmony_ci	wqe->u.terminate.immdlen = cpu_to_be32(sizeof(*term));
158462306a36Sopenharmony_ci	term = (struct terminate_message *)wqe->u.terminate.termmsg;
158562306a36Sopenharmony_ci	if (qhp->attr.layer_etype == (LAYER_MPA|DDP_LLP)) {
158662306a36Sopenharmony_ci		term->layer_etype = qhp->attr.layer_etype;
158762306a36Sopenharmony_ci		term->ecode = qhp->attr.ecode;
158862306a36Sopenharmony_ci	} else
158962306a36Sopenharmony_ci		build_term_codes(err_cqe, &term->layer_etype, &term->ecode);
159062306a36Sopenharmony_ci	c4iw_ofld_send(&qhp->rhp->rdev, skb);
159162306a36Sopenharmony_ci}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci/*
159462306a36Sopenharmony_ci * Assumes qhp lock is held.
159562306a36Sopenharmony_ci */
159662306a36Sopenharmony_cistatic void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
159762306a36Sopenharmony_ci		       struct c4iw_cq *schp)
159862306a36Sopenharmony_ci{
159962306a36Sopenharmony_ci	int count;
160062306a36Sopenharmony_ci	int rq_flushed = 0, sq_flushed;
160162306a36Sopenharmony_ci	unsigned long flag;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	pr_debug("qhp %p rchp %p schp %p\n", qhp, rchp, schp);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	/* locking hierarchy: cqs lock first, then qp lock. */
160662306a36Sopenharmony_ci	spin_lock_irqsave(&rchp->lock, flag);
160762306a36Sopenharmony_ci	if (schp != rchp)
160862306a36Sopenharmony_ci		spin_lock(&schp->lock);
160962306a36Sopenharmony_ci	spin_lock(&qhp->lock);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	if (qhp->wq.flushed) {
161262306a36Sopenharmony_ci		spin_unlock(&qhp->lock);
161362306a36Sopenharmony_ci		if (schp != rchp)
161462306a36Sopenharmony_ci			spin_unlock(&schp->lock);
161562306a36Sopenharmony_ci		spin_unlock_irqrestore(&rchp->lock, flag);
161662306a36Sopenharmony_ci		return;
161762306a36Sopenharmony_ci	}
161862306a36Sopenharmony_ci	qhp->wq.flushed = 1;
161962306a36Sopenharmony_ci	t4_set_wq_in_error(&qhp->wq, 0);
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	c4iw_flush_hw_cq(rchp, qhp);
162262306a36Sopenharmony_ci	if (!qhp->srq) {
162362306a36Sopenharmony_ci		c4iw_count_rcqes(&rchp->cq, &qhp->wq, &count);
162462306a36Sopenharmony_ci		rq_flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count);
162562306a36Sopenharmony_ci	}
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	if (schp != rchp)
162862306a36Sopenharmony_ci		c4iw_flush_hw_cq(schp, qhp);
162962306a36Sopenharmony_ci	sq_flushed = c4iw_flush_sq(qhp);
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	spin_unlock(&qhp->lock);
163262306a36Sopenharmony_ci	if (schp != rchp)
163362306a36Sopenharmony_ci		spin_unlock(&schp->lock);
163462306a36Sopenharmony_ci	spin_unlock_irqrestore(&rchp->lock, flag);
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	if (schp == rchp) {
163762306a36Sopenharmony_ci		if ((rq_flushed || sq_flushed) &&
163862306a36Sopenharmony_ci		    t4_clear_cq_armed(&rchp->cq)) {
163962306a36Sopenharmony_ci			spin_lock_irqsave(&rchp->comp_handler_lock, flag);
164062306a36Sopenharmony_ci			(*rchp->ibcq.comp_handler)(&rchp->ibcq,
164162306a36Sopenharmony_ci						   rchp->ibcq.cq_context);
164262306a36Sopenharmony_ci			spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
164362306a36Sopenharmony_ci		}
164462306a36Sopenharmony_ci	} else {
164562306a36Sopenharmony_ci		if (rq_flushed && t4_clear_cq_armed(&rchp->cq)) {
164662306a36Sopenharmony_ci			spin_lock_irqsave(&rchp->comp_handler_lock, flag);
164762306a36Sopenharmony_ci			(*rchp->ibcq.comp_handler)(&rchp->ibcq,
164862306a36Sopenharmony_ci						   rchp->ibcq.cq_context);
164962306a36Sopenharmony_ci			spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
165062306a36Sopenharmony_ci		}
165162306a36Sopenharmony_ci		if (sq_flushed && t4_clear_cq_armed(&schp->cq)) {
165262306a36Sopenharmony_ci			spin_lock_irqsave(&schp->comp_handler_lock, flag);
165362306a36Sopenharmony_ci			(*schp->ibcq.comp_handler)(&schp->ibcq,
165462306a36Sopenharmony_ci						   schp->ibcq.cq_context);
165562306a36Sopenharmony_ci			spin_unlock_irqrestore(&schp->comp_handler_lock, flag);
165662306a36Sopenharmony_ci		}
165762306a36Sopenharmony_ci	}
165862306a36Sopenharmony_ci}
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_cistatic void flush_qp(struct c4iw_qp *qhp)
166162306a36Sopenharmony_ci{
166262306a36Sopenharmony_ci	struct c4iw_cq *rchp, *schp;
166362306a36Sopenharmony_ci	unsigned long flag;
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	rchp = to_c4iw_cq(qhp->ibqp.recv_cq);
166662306a36Sopenharmony_ci	schp = to_c4iw_cq(qhp->ibqp.send_cq);
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	if (qhp->ibqp.uobject) {
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci		/* for user qps, qhp->wq.flushed is protected by qhp->mutex */
167162306a36Sopenharmony_ci		if (qhp->wq.flushed)
167262306a36Sopenharmony_ci			return;
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci		qhp->wq.flushed = 1;
167562306a36Sopenharmony_ci		t4_set_wq_in_error(&qhp->wq, 0);
167662306a36Sopenharmony_ci		t4_set_cq_in_error(&rchp->cq);
167762306a36Sopenharmony_ci		spin_lock_irqsave(&rchp->comp_handler_lock, flag);
167862306a36Sopenharmony_ci		(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
167962306a36Sopenharmony_ci		spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
168062306a36Sopenharmony_ci		if (schp != rchp) {
168162306a36Sopenharmony_ci			t4_set_cq_in_error(&schp->cq);
168262306a36Sopenharmony_ci			spin_lock_irqsave(&schp->comp_handler_lock, flag);
168362306a36Sopenharmony_ci			(*schp->ibcq.comp_handler)(&schp->ibcq,
168462306a36Sopenharmony_ci					schp->ibcq.cq_context);
168562306a36Sopenharmony_ci			spin_unlock_irqrestore(&schp->comp_handler_lock, flag);
168662306a36Sopenharmony_ci		}
168762306a36Sopenharmony_ci		return;
168862306a36Sopenharmony_ci	}
168962306a36Sopenharmony_ci	__flush_qp(qhp, rchp, schp);
169062306a36Sopenharmony_ci}
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_cistatic int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
169362306a36Sopenharmony_ci		     struct c4iw_ep *ep)
169462306a36Sopenharmony_ci{
169562306a36Sopenharmony_ci	struct fw_ri_wr *wqe;
169662306a36Sopenharmony_ci	int ret;
169762306a36Sopenharmony_ci	struct sk_buff *skb;
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	pr_debug("qhp %p qid 0x%x tid %u\n", qhp, qhp->wq.sq.qid, ep->hwtid);
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	skb = skb_dequeue(&ep->com.ep_skb_list);
170262306a36Sopenharmony_ci	if (WARN_ON(!skb))
170362306a36Sopenharmony_ci		return -ENOMEM;
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx);
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	wqe = __skb_put_zero(skb, sizeof(*wqe));
170862306a36Sopenharmony_ci	wqe->op_compl = cpu_to_be32(
170962306a36Sopenharmony_ci		FW_WR_OP_V(FW_RI_INIT_WR) |
171062306a36Sopenharmony_ci		FW_WR_COMPL_F);
171162306a36Sopenharmony_ci	wqe->flowid_len16 = cpu_to_be32(
171262306a36Sopenharmony_ci		FW_WR_FLOWID_V(ep->hwtid) |
171362306a36Sopenharmony_ci		FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16)));
171462306a36Sopenharmony_ci	wqe->cookie = (uintptr_t)ep->com.wr_waitp;
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	wqe->u.fini.type = FW_RI_TYPE_FINI;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	ret = c4iw_ref_send_wait(&rhp->rdev, skb, ep->com.wr_waitp,
171962306a36Sopenharmony_ci				 qhp->ep->hwtid, qhp->wq.sq.qid, __func__);
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	pr_debug("ret %d\n", ret);
172262306a36Sopenharmony_ci	return ret;
172362306a36Sopenharmony_ci}
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_cistatic void build_rtr_msg(u8 p2p_type, struct fw_ri_init *init)
172662306a36Sopenharmony_ci{
172762306a36Sopenharmony_ci	pr_debug("p2p_type = %d\n", p2p_type);
172862306a36Sopenharmony_ci	memset(&init->u, 0, sizeof(init->u));
172962306a36Sopenharmony_ci	switch (p2p_type) {
173062306a36Sopenharmony_ci	case FW_RI_INIT_P2PTYPE_RDMA_WRITE:
173162306a36Sopenharmony_ci		init->u.write.opcode = FW_RI_RDMA_WRITE_WR;
173262306a36Sopenharmony_ci		init->u.write.stag_sink = cpu_to_be32(1);
173362306a36Sopenharmony_ci		init->u.write.to_sink = cpu_to_be64(1);
173462306a36Sopenharmony_ci		init->u.write.u.immd_src[0].op = FW_RI_DATA_IMMD;
173562306a36Sopenharmony_ci		init->u.write.len16 = DIV_ROUND_UP(
173662306a36Sopenharmony_ci			sizeof(init->u.write) + sizeof(struct fw_ri_immd), 16);
173762306a36Sopenharmony_ci		break;
173862306a36Sopenharmony_ci	case FW_RI_INIT_P2PTYPE_READ_REQ:
173962306a36Sopenharmony_ci		init->u.write.opcode = FW_RI_RDMA_READ_WR;
174062306a36Sopenharmony_ci		init->u.read.stag_src = cpu_to_be32(1);
174162306a36Sopenharmony_ci		init->u.read.to_src_lo = cpu_to_be32(1);
174262306a36Sopenharmony_ci		init->u.read.stag_sink = cpu_to_be32(1);
174362306a36Sopenharmony_ci		init->u.read.to_sink_lo = cpu_to_be32(1);
174462306a36Sopenharmony_ci		init->u.read.len16 = DIV_ROUND_UP(sizeof(init->u.read), 16);
174562306a36Sopenharmony_ci		break;
174662306a36Sopenharmony_ci	}
174762306a36Sopenharmony_ci}
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_cistatic int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
175062306a36Sopenharmony_ci{
175162306a36Sopenharmony_ci	struct fw_ri_wr *wqe;
175262306a36Sopenharmony_ci	int ret;
175362306a36Sopenharmony_ci	struct sk_buff *skb;
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci	pr_debug("qhp %p qid 0x%x tid %u ird %u ord %u\n", qhp,
175662306a36Sopenharmony_ci		 qhp->wq.sq.qid, qhp->ep->hwtid, qhp->ep->ird, qhp->ep->ord);
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	skb = alloc_skb(sizeof(*wqe), GFP_KERNEL);
175962306a36Sopenharmony_ci	if (!skb) {
176062306a36Sopenharmony_ci		ret = -ENOMEM;
176162306a36Sopenharmony_ci		goto out;
176262306a36Sopenharmony_ci	}
176362306a36Sopenharmony_ci	ret = alloc_ird(rhp, qhp->attr.max_ird);
176462306a36Sopenharmony_ci	if (ret) {
176562306a36Sopenharmony_ci		qhp->attr.max_ird = 0;
176662306a36Sopenharmony_ci		kfree_skb(skb);
176762306a36Sopenharmony_ci		goto out;
176862306a36Sopenharmony_ci	}
176962306a36Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx);
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	wqe = __skb_put_zero(skb, sizeof(*wqe));
177262306a36Sopenharmony_ci	wqe->op_compl = cpu_to_be32(
177362306a36Sopenharmony_ci		FW_WR_OP_V(FW_RI_INIT_WR) |
177462306a36Sopenharmony_ci		FW_WR_COMPL_F);
177562306a36Sopenharmony_ci	wqe->flowid_len16 = cpu_to_be32(
177662306a36Sopenharmony_ci		FW_WR_FLOWID_V(qhp->ep->hwtid) |
177762306a36Sopenharmony_ci		FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16)));
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	wqe->cookie = (uintptr_t)qhp->ep->com.wr_waitp;
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	wqe->u.init.type = FW_RI_TYPE_INIT;
178262306a36Sopenharmony_ci	wqe->u.init.mpareqbit_p2ptype =
178362306a36Sopenharmony_ci		FW_RI_WR_MPAREQBIT_V(qhp->attr.mpa_attr.initiator) |
178462306a36Sopenharmony_ci		FW_RI_WR_P2PTYPE_V(qhp->attr.mpa_attr.p2p_type);
178562306a36Sopenharmony_ci	wqe->u.init.mpa_attrs = FW_RI_MPA_IETF_ENABLE;
178662306a36Sopenharmony_ci	if (qhp->attr.mpa_attr.recv_marker_enabled)
178762306a36Sopenharmony_ci		wqe->u.init.mpa_attrs |= FW_RI_MPA_RX_MARKER_ENABLE;
178862306a36Sopenharmony_ci	if (qhp->attr.mpa_attr.xmit_marker_enabled)
178962306a36Sopenharmony_ci		wqe->u.init.mpa_attrs |= FW_RI_MPA_TX_MARKER_ENABLE;
179062306a36Sopenharmony_ci	if (qhp->attr.mpa_attr.crc_enabled)
179162306a36Sopenharmony_ci		wqe->u.init.mpa_attrs |= FW_RI_MPA_CRC_ENABLE;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	wqe->u.init.qp_caps = FW_RI_QP_RDMA_READ_ENABLE |
179462306a36Sopenharmony_ci			    FW_RI_QP_RDMA_WRITE_ENABLE |
179562306a36Sopenharmony_ci			    FW_RI_QP_BIND_ENABLE;
179662306a36Sopenharmony_ci	if (!qhp->ibqp.uobject)
179762306a36Sopenharmony_ci		wqe->u.init.qp_caps |= FW_RI_QP_FAST_REGISTER_ENABLE |
179862306a36Sopenharmony_ci				     FW_RI_QP_STAG0_ENABLE;
179962306a36Sopenharmony_ci	wqe->u.init.nrqe = cpu_to_be16(t4_rqes_posted(&qhp->wq));
180062306a36Sopenharmony_ci	wqe->u.init.pdid = cpu_to_be32(qhp->attr.pd);
180162306a36Sopenharmony_ci	wqe->u.init.qpid = cpu_to_be32(qhp->wq.sq.qid);
180262306a36Sopenharmony_ci	wqe->u.init.sq_eqid = cpu_to_be32(qhp->wq.sq.qid);
180362306a36Sopenharmony_ci	if (qhp->srq) {
180462306a36Sopenharmony_ci		wqe->u.init.rq_eqid = cpu_to_be32(FW_RI_INIT_RQEQID_SRQ |
180562306a36Sopenharmony_ci						  qhp->srq->idx);
180662306a36Sopenharmony_ci	} else {
180762306a36Sopenharmony_ci		wqe->u.init.rq_eqid = cpu_to_be32(qhp->wq.rq.qid);
180862306a36Sopenharmony_ci		wqe->u.init.hwrqsize = cpu_to_be32(qhp->wq.rq.rqt_size);
180962306a36Sopenharmony_ci		wqe->u.init.hwrqaddr = cpu_to_be32(qhp->wq.rq.rqt_hwaddr -
181062306a36Sopenharmony_ci						   rhp->rdev.lldi.vr->rq.start);
181162306a36Sopenharmony_ci	}
181262306a36Sopenharmony_ci	wqe->u.init.scqid = cpu_to_be32(qhp->attr.scq);
181362306a36Sopenharmony_ci	wqe->u.init.rcqid = cpu_to_be32(qhp->attr.rcq);
181462306a36Sopenharmony_ci	wqe->u.init.ord_max = cpu_to_be32(qhp->attr.max_ord);
181562306a36Sopenharmony_ci	wqe->u.init.ird_max = cpu_to_be32(qhp->attr.max_ird);
181662306a36Sopenharmony_ci	wqe->u.init.iss = cpu_to_be32(qhp->ep->snd_seq);
181762306a36Sopenharmony_ci	wqe->u.init.irs = cpu_to_be32(qhp->ep->rcv_seq);
181862306a36Sopenharmony_ci	if (qhp->attr.mpa_attr.initiator)
181962306a36Sopenharmony_ci		build_rtr_msg(qhp->attr.mpa_attr.p2p_type, &wqe->u.init);
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	ret = c4iw_ref_send_wait(&rhp->rdev, skb, qhp->ep->com.wr_waitp,
182262306a36Sopenharmony_ci				 qhp->ep->hwtid, qhp->wq.sq.qid, __func__);
182362306a36Sopenharmony_ci	if (!ret)
182462306a36Sopenharmony_ci		goto out;
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	free_ird(rhp, qhp->attr.max_ird);
182762306a36Sopenharmony_ciout:
182862306a36Sopenharmony_ci	pr_debug("ret %d\n", ret);
182962306a36Sopenharmony_ci	return ret;
183062306a36Sopenharmony_ci}
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ciint c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
183362306a36Sopenharmony_ci		   enum c4iw_qp_attr_mask mask,
183462306a36Sopenharmony_ci		   struct c4iw_qp_attributes *attrs,
183562306a36Sopenharmony_ci		   int internal)
183662306a36Sopenharmony_ci{
183762306a36Sopenharmony_ci	int ret = 0;
183862306a36Sopenharmony_ci	struct c4iw_qp_attributes newattr = qhp->attr;
183962306a36Sopenharmony_ci	int disconnect = 0;
184062306a36Sopenharmony_ci	int terminate = 0;
184162306a36Sopenharmony_ci	int abort = 0;
184262306a36Sopenharmony_ci	int free = 0;
184362306a36Sopenharmony_ci	struct c4iw_ep *ep = NULL;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	pr_debug("qhp %p sqid 0x%x rqid 0x%x ep %p state %d -> %d\n",
184662306a36Sopenharmony_ci		 qhp, qhp->wq.sq.qid, qhp->wq.rq.qid, qhp->ep, qhp->attr.state,
184762306a36Sopenharmony_ci		 (mask & C4IW_QP_ATTR_NEXT_STATE) ? attrs->next_state : -1);
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	mutex_lock(&qhp->mutex);
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	/* Process attr changes if in IDLE */
185262306a36Sopenharmony_ci	if (mask & C4IW_QP_ATTR_VALID_MODIFY) {
185362306a36Sopenharmony_ci		if (qhp->attr.state != C4IW_QP_STATE_IDLE) {
185462306a36Sopenharmony_ci			ret = -EIO;
185562306a36Sopenharmony_ci			goto out;
185662306a36Sopenharmony_ci		}
185762306a36Sopenharmony_ci		if (mask & C4IW_QP_ATTR_ENABLE_RDMA_READ)
185862306a36Sopenharmony_ci			newattr.enable_rdma_read = attrs->enable_rdma_read;
185962306a36Sopenharmony_ci		if (mask & C4IW_QP_ATTR_ENABLE_RDMA_WRITE)
186062306a36Sopenharmony_ci			newattr.enable_rdma_write = attrs->enable_rdma_write;
186162306a36Sopenharmony_ci		if (mask & C4IW_QP_ATTR_ENABLE_RDMA_BIND)
186262306a36Sopenharmony_ci			newattr.enable_bind = attrs->enable_bind;
186362306a36Sopenharmony_ci		if (mask & C4IW_QP_ATTR_MAX_ORD) {
186462306a36Sopenharmony_ci			if (attrs->max_ord > c4iw_max_read_depth) {
186562306a36Sopenharmony_ci				ret = -EINVAL;
186662306a36Sopenharmony_ci				goto out;
186762306a36Sopenharmony_ci			}
186862306a36Sopenharmony_ci			newattr.max_ord = attrs->max_ord;
186962306a36Sopenharmony_ci		}
187062306a36Sopenharmony_ci		if (mask & C4IW_QP_ATTR_MAX_IRD) {
187162306a36Sopenharmony_ci			if (attrs->max_ird > cur_max_read_depth(rhp)) {
187262306a36Sopenharmony_ci				ret = -EINVAL;
187362306a36Sopenharmony_ci				goto out;
187462306a36Sopenharmony_ci			}
187562306a36Sopenharmony_ci			newattr.max_ird = attrs->max_ird;
187662306a36Sopenharmony_ci		}
187762306a36Sopenharmony_ci		qhp->attr = newattr;
187862306a36Sopenharmony_ci	}
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	if (mask & C4IW_QP_ATTR_SQ_DB) {
188162306a36Sopenharmony_ci		ret = ring_kernel_sq_db(qhp, attrs->sq_db_inc);
188262306a36Sopenharmony_ci		goto out;
188362306a36Sopenharmony_ci	}
188462306a36Sopenharmony_ci	if (mask & C4IW_QP_ATTR_RQ_DB) {
188562306a36Sopenharmony_ci		ret = ring_kernel_rq_db(qhp, attrs->rq_db_inc);
188662306a36Sopenharmony_ci		goto out;
188762306a36Sopenharmony_ci	}
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	if (!(mask & C4IW_QP_ATTR_NEXT_STATE))
189062306a36Sopenharmony_ci		goto out;
189162306a36Sopenharmony_ci	if (qhp->attr.state == attrs->next_state)
189262306a36Sopenharmony_ci		goto out;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	switch (qhp->attr.state) {
189562306a36Sopenharmony_ci	case C4IW_QP_STATE_IDLE:
189662306a36Sopenharmony_ci		switch (attrs->next_state) {
189762306a36Sopenharmony_ci		case C4IW_QP_STATE_RTS:
189862306a36Sopenharmony_ci			if (!(mask & C4IW_QP_ATTR_LLP_STREAM_HANDLE)) {
189962306a36Sopenharmony_ci				ret = -EINVAL;
190062306a36Sopenharmony_ci				goto out;
190162306a36Sopenharmony_ci			}
190262306a36Sopenharmony_ci			if (!(mask & C4IW_QP_ATTR_MPA_ATTR)) {
190362306a36Sopenharmony_ci				ret = -EINVAL;
190462306a36Sopenharmony_ci				goto out;
190562306a36Sopenharmony_ci			}
190662306a36Sopenharmony_ci			qhp->attr.mpa_attr = attrs->mpa_attr;
190762306a36Sopenharmony_ci			qhp->attr.llp_stream_handle = attrs->llp_stream_handle;
190862306a36Sopenharmony_ci			qhp->ep = qhp->attr.llp_stream_handle;
190962306a36Sopenharmony_ci			set_state(qhp, C4IW_QP_STATE_RTS);
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci			/*
191262306a36Sopenharmony_ci			 * Ref the endpoint here and deref when we
191362306a36Sopenharmony_ci			 * disassociate the endpoint from the QP.  This
191462306a36Sopenharmony_ci			 * happens in CLOSING->IDLE transition or *->ERROR
191562306a36Sopenharmony_ci			 * transition.
191662306a36Sopenharmony_ci			 */
191762306a36Sopenharmony_ci			c4iw_get_ep(&qhp->ep->com);
191862306a36Sopenharmony_ci			ret = rdma_init(rhp, qhp);
191962306a36Sopenharmony_ci			if (ret)
192062306a36Sopenharmony_ci				goto err;
192162306a36Sopenharmony_ci			break;
192262306a36Sopenharmony_ci		case C4IW_QP_STATE_ERROR:
192362306a36Sopenharmony_ci			set_state(qhp, C4IW_QP_STATE_ERROR);
192462306a36Sopenharmony_ci			flush_qp(qhp);
192562306a36Sopenharmony_ci			break;
192662306a36Sopenharmony_ci		default:
192762306a36Sopenharmony_ci			ret = -EINVAL;
192862306a36Sopenharmony_ci			goto out;
192962306a36Sopenharmony_ci		}
193062306a36Sopenharmony_ci		break;
193162306a36Sopenharmony_ci	case C4IW_QP_STATE_RTS:
193262306a36Sopenharmony_ci		switch (attrs->next_state) {
193362306a36Sopenharmony_ci		case C4IW_QP_STATE_CLOSING:
193462306a36Sopenharmony_ci			t4_set_wq_in_error(&qhp->wq, 0);
193562306a36Sopenharmony_ci			set_state(qhp, C4IW_QP_STATE_CLOSING);
193662306a36Sopenharmony_ci			ep = qhp->ep;
193762306a36Sopenharmony_ci			if (!internal) {
193862306a36Sopenharmony_ci				abort = 0;
193962306a36Sopenharmony_ci				disconnect = 1;
194062306a36Sopenharmony_ci				c4iw_get_ep(&qhp->ep->com);
194162306a36Sopenharmony_ci			}
194262306a36Sopenharmony_ci			ret = rdma_fini(rhp, qhp, ep);
194362306a36Sopenharmony_ci			if (ret)
194462306a36Sopenharmony_ci				goto err;
194562306a36Sopenharmony_ci			break;
194662306a36Sopenharmony_ci		case C4IW_QP_STATE_TERMINATE:
194762306a36Sopenharmony_ci			t4_set_wq_in_error(&qhp->wq, 0);
194862306a36Sopenharmony_ci			set_state(qhp, C4IW_QP_STATE_TERMINATE);
194962306a36Sopenharmony_ci			qhp->attr.layer_etype = attrs->layer_etype;
195062306a36Sopenharmony_ci			qhp->attr.ecode = attrs->ecode;
195162306a36Sopenharmony_ci			ep = qhp->ep;
195262306a36Sopenharmony_ci			if (!internal) {
195362306a36Sopenharmony_ci				c4iw_get_ep(&ep->com);
195462306a36Sopenharmony_ci				terminate = 1;
195562306a36Sopenharmony_ci				disconnect = 1;
195662306a36Sopenharmony_ci			} else {
195762306a36Sopenharmony_ci				terminate = qhp->attr.send_term;
195862306a36Sopenharmony_ci				ret = rdma_fini(rhp, qhp, ep);
195962306a36Sopenharmony_ci				if (ret)
196062306a36Sopenharmony_ci					goto err;
196162306a36Sopenharmony_ci			}
196262306a36Sopenharmony_ci			break;
196362306a36Sopenharmony_ci		case C4IW_QP_STATE_ERROR:
196462306a36Sopenharmony_ci			t4_set_wq_in_error(&qhp->wq, 0);
196562306a36Sopenharmony_ci			set_state(qhp, C4IW_QP_STATE_ERROR);
196662306a36Sopenharmony_ci			if (!internal) {
196762306a36Sopenharmony_ci				disconnect = 1;
196862306a36Sopenharmony_ci				ep = qhp->ep;
196962306a36Sopenharmony_ci				c4iw_get_ep(&qhp->ep->com);
197062306a36Sopenharmony_ci			}
197162306a36Sopenharmony_ci			goto err;
197262306a36Sopenharmony_ci			break;
197362306a36Sopenharmony_ci		default:
197462306a36Sopenharmony_ci			ret = -EINVAL;
197562306a36Sopenharmony_ci			goto out;
197662306a36Sopenharmony_ci		}
197762306a36Sopenharmony_ci		break;
197862306a36Sopenharmony_ci	case C4IW_QP_STATE_CLOSING:
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci		/*
198162306a36Sopenharmony_ci		 * Allow kernel users to move to ERROR for qp draining.
198262306a36Sopenharmony_ci		 */
198362306a36Sopenharmony_ci		if (!internal && (qhp->ibqp.uobject || attrs->next_state !=
198462306a36Sopenharmony_ci				  C4IW_QP_STATE_ERROR)) {
198562306a36Sopenharmony_ci			ret = -EINVAL;
198662306a36Sopenharmony_ci			goto out;
198762306a36Sopenharmony_ci		}
198862306a36Sopenharmony_ci		switch (attrs->next_state) {
198962306a36Sopenharmony_ci		case C4IW_QP_STATE_IDLE:
199062306a36Sopenharmony_ci			flush_qp(qhp);
199162306a36Sopenharmony_ci			set_state(qhp, C4IW_QP_STATE_IDLE);
199262306a36Sopenharmony_ci			qhp->attr.llp_stream_handle = NULL;
199362306a36Sopenharmony_ci			c4iw_put_ep(&qhp->ep->com);
199462306a36Sopenharmony_ci			qhp->ep = NULL;
199562306a36Sopenharmony_ci			wake_up(&qhp->wait);
199662306a36Sopenharmony_ci			break;
199762306a36Sopenharmony_ci		case C4IW_QP_STATE_ERROR:
199862306a36Sopenharmony_ci			goto err;
199962306a36Sopenharmony_ci		default:
200062306a36Sopenharmony_ci			ret = -EINVAL;
200162306a36Sopenharmony_ci			goto err;
200262306a36Sopenharmony_ci		}
200362306a36Sopenharmony_ci		break;
200462306a36Sopenharmony_ci	case C4IW_QP_STATE_ERROR:
200562306a36Sopenharmony_ci		if (attrs->next_state != C4IW_QP_STATE_IDLE) {
200662306a36Sopenharmony_ci			ret = -EINVAL;
200762306a36Sopenharmony_ci			goto out;
200862306a36Sopenharmony_ci		}
200962306a36Sopenharmony_ci		if (!t4_sq_empty(&qhp->wq) || !t4_rq_empty(&qhp->wq)) {
201062306a36Sopenharmony_ci			ret = -EINVAL;
201162306a36Sopenharmony_ci			goto out;
201262306a36Sopenharmony_ci		}
201362306a36Sopenharmony_ci		set_state(qhp, C4IW_QP_STATE_IDLE);
201462306a36Sopenharmony_ci		break;
201562306a36Sopenharmony_ci	case C4IW_QP_STATE_TERMINATE:
201662306a36Sopenharmony_ci		if (!internal) {
201762306a36Sopenharmony_ci			ret = -EINVAL;
201862306a36Sopenharmony_ci			goto out;
201962306a36Sopenharmony_ci		}
202062306a36Sopenharmony_ci		goto err;
202162306a36Sopenharmony_ci		break;
202262306a36Sopenharmony_ci	default:
202362306a36Sopenharmony_ci		pr_err("%s in a bad state %d\n", __func__, qhp->attr.state);
202462306a36Sopenharmony_ci		ret = -EINVAL;
202562306a36Sopenharmony_ci		goto err;
202662306a36Sopenharmony_ci		break;
202762306a36Sopenharmony_ci	}
202862306a36Sopenharmony_ci	goto out;
202962306a36Sopenharmony_cierr:
203062306a36Sopenharmony_ci	pr_debug("disassociating ep %p qpid 0x%x\n", qhp->ep,
203162306a36Sopenharmony_ci		 qhp->wq.sq.qid);
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	/* disassociate the LLP connection */
203462306a36Sopenharmony_ci	qhp->attr.llp_stream_handle = NULL;
203562306a36Sopenharmony_ci	if (!ep)
203662306a36Sopenharmony_ci		ep = qhp->ep;
203762306a36Sopenharmony_ci	qhp->ep = NULL;
203862306a36Sopenharmony_ci	set_state(qhp, C4IW_QP_STATE_ERROR);
203962306a36Sopenharmony_ci	free = 1;
204062306a36Sopenharmony_ci	abort = 1;
204162306a36Sopenharmony_ci	flush_qp(qhp);
204262306a36Sopenharmony_ci	wake_up(&qhp->wait);
204362306a36Sopenharmony_ciout:
204462306a36Sopenharmony_ci	mutex_unlock(&qhp->mutex);
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	if (terminate)
204762306a36Sopenharmony_ci		post_terminate(qhp, NULL, internal ? GFP_ATOMIC : GFP_KERNEL);
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	/*
205062306a36Sopenharmony_ci	 * If disconnect is 1, then we need to initiate a disconnect
205162306a36Sopenharmony_ci	 * on the EP.  This can be a normal close (RTS->CLOSING) or
205262306a36Sopenharmony_ci	 * an abnormal close (RTS/CLOSING->ERROR).
205362306a36Sopenharmony_ci	 */
205462306a36Sopenharmony_ci	if (disconnect) {
205562306a36Sopenharmony_ci		c4iw_ep_disconnect(ep, abort, internal ? GFP_ATOMIC :
205662306a36Sopenharmony_ci							 GFP_KERNEL);
205762306a36Sopenharmony_ci		c4iw_put_ep(&ep->com);
205862306a36Sopenharmony_ci	}
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	/*
206162306a36Sopenharmony_ci	 * If free is 1, then we've disassociated the EP from the QP
206262306a36Sopenharmony_ci	 * and we need to dereference the EP.
206362306a36Sopenharmony_ci	 */
206462306a36Sopenharmony_ci	if (free)
206562306a36Sopenharmony_ci		c4iw_put_ep(&ep->com);
206662306a36Sopenharmony_ci	pr_debug("exit state %d\n", qhp->attr.state);
206762306a36Sopenharmony_ci	return ret;
206862306a36Sopenharmony_ci}
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ciint c4iw_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
207162306a36Sopenharmony_ci{
207262306a36Sopenharmony_ci	struct c4iw_dev *rhp;
207362306a36Sopenharmony_ci	struct c4iw_qp *qhp;
207462306a36Sopenharmony_ci	struct c4iw_ucontext *ucontext;
207562306a36Sopenharmony_ci	struct c4iw_qp_attributes attrs;
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	qhp = to_c4iw_qp(ib_qp);
207862306a36Sopenharmony_ci	rhp = qhp->rhp;
207962306a36Sopenharmony_ci	ucontext = qhp->ucontext;
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	attrs.next_state = C4IW_QP_STATE_ERROR;
208262306a36Sopenharmony_ci	if (qhp->attr.state == C4IW_QP_STATE_TERMINATE)
208362306a36Sopenharmony_ci		c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
208462306a36Sopenharmony_ci	else
208562306a36Sopenharmony_ci		c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 0);
208662306a36Sopenharmony_ci	wait_event(qhp->wait, !qhp->ep);
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci	xa_lock_irq(&rhp->qps);
208962306a36Sopenharmony_ci	__xa_erase(&rhp->qps, qhp->wq.sq.qid);
209062306a36Sopenharmony_ci	if (!list_empty(&qhp->db_fc_entry))
209162306a36Sopenharmony_ci		list_del_init(&qhp->db_fc_entry);
209262306a36Sopenharmony_ci	xa_unlock_irq(&rhp->qps);
209362306a36Sopenharmony_ci	free_ird(rhp, qhp->attr.max_ird);
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	c4iw_qp_rem_ref(ib_qp);
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	wait_for_completion(&qhp->qp_rel_comp);
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	pr_debug("ib_qp %p qpid 0x%0x\n", ib_qp, qhp->wq.sq.qid);
210062306a36Sopenharmony_ci	pr_debug("qhp %p ucontext %p\n", qhp, ucontext);
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	destroy_qp(&rhp->rdev, &qhp->wq,
210362306a36Sopenharmony_ci		   ucontext ? &ucontext->uctx : &rhp->rdev.uctx, !qhp->srq);
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	c4iw_put_wr_wait(qhp->wr_waitp);
210662306a36Sopenharmony_ci	return 0;
210762306a36Sopenharmony_ci}
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ciint c4iw_create_qp(struct ib_qp *qp, struct ib_qp_init_attr *attrs,
211062306a36Sopenharmony_ci		   struct ib_udata *udata)
211162306a36Sopenharmony_ci{
211262306a36Sopenharmony_ci	struct ib_pd *pd = qp->pd;
211362306a36Sopenharmony_ci	struct c4iw_dev *rhp;
211462306a36Sopenharmony_ci	struct c4iw_qp *qhp = to_c4iw_qp(qp);
211562306a36Sopenharmony_ci	struct c4iw_pd *php;
211662306a36Sopenharmony_ci	struct c4iw_cq *schp;
211762306a36Sopenharmony_ci	struct c4iw_cq *rchp;
211862306a36Sopenharmony_ci	struct c4iw_create_qp_resp uresp;
211962306a36Sopenharmony_ci	unsigned int sqsize, rqsize = 0;
212062306a36Sopenharmony_ci	struct c4iw_ucontext *ucontext = rdma_udata_to_drv_context(
212162306a36Sopenharmony_ci		udata, struct c4iw_ucontext, ibucontext);
212262306a36Sopenharmony_ci	int ret;
212362306a36Sopenharmony_ci	struct c4iw_mm_entry *sq_key_mm, *rq_key_mm = NULL, *sq_db_key_mm;
212462306a36Sopenharmony_ci	struct c4iw_mm_entry *rq_db_key_mm = NULL, *ma_sync_key_mm = NULL;
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	if (attrs->qp_type != IB_QPT_RC || attrs->create_flags)
212762306a36Sopenharmony_ci		return -EOPNOTSUPP;
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	php = to_c4iw_pd(pd);
213062306a36Sopenharmony_ci	rhp = php->rhp;
213162306a36Sopenharmony_ci	schp = get_chp(rhp, ((struct c4iw_cq *)attrs->send_cq)->cq.cqid);
213262306a36Sopenharmony_ci	rchp = get_chp(rhp, ((struct c4iw_cq *)attrs->recv_cq)->cq.cqid);
213362306a36Sopenharmony_ci	if (!schp || !rchp)
213462306a36Sopenharmony_ci		return -EINVAL;
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	if (attrs->cap.max_inline_data > T4_MAX_SEND_INLINE)
213762306a36Sopenharmony_ci		return -EINVAL;
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci	if (!attrs->srq) {
214062306a36Sopenharmony_ci		if (attrs->cap.max_recv_wr > rhp->rdev.hw_queue.t4_max_rq_size)
214162306a36Sopenharmony_ci			return -E2BIG;
214262306a36Sopenharmony_ci		rqsize = attrs->cap.max_recv_wr + 1;
214362306a36Sopenharmony_ci		if (rqsize < 8)
214462306a36Sopenharmony_ci			rqsize = 8;
214562306a36Sopenharmony_ci	}
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	if (attrs->cap.max_send_wr > rhp->rdev.hw_queue.t4_max_sq_size)
214862306a36Sopenharmony_ci		return -E2BIG;
214962306a36Sopenharmony_ci	sqsize = attrs->cap.max_send_wr + 1;
215062306a36Sopenharmony_ci	if (sqsize < 8)
215162306a36Sopenharmony_ci		sqsize = 8;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	qhp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
215462306a36Sopenharmony_ci	if (!qhp->wr_waitp)
215562306a36Sopenharmony_ci		return -ENOMEM;
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	qhp->wq.sq.size = sqsize;
215862306a36Sopenharmony_ci	qhp->wq.sq.memsize =
215962306a36Sopenharmony_ci		(sqsize + rhp->rdev.hw_queue.t4_eq_status_entries) *
216062306a36Sopenharmony_ci		sizeof(*qhp->wq.sq.queue) + 16 * sizeof(__be64);
216162306a36Sopenharmony_ci	qhp->wq.sq.flush_cidx = -1;
216262306a36Sopenharmony_ci	if (!attrs->srq) {
216362306a36Sopenharmony_ci		qhp->wq.rq.size = rqsize;
216462306a36Sopenharmony_ci		qhp->wq.rq.memsize =
216562306a36Sopenharmony_ci			(rqsize + rhp->rdev.hw_queue.t4_eq_status_entries) *
216662306a36Sopenharmony_ci			sizeof(*qhp->wq.rq.queue);
216762306a36Sopenharmony_ci	}
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	if (ucontext) {
217062306a36Sopenharmony_ci		qhp->wq.sq.memsize = roundup(qhp->wq.sq.memsize, PAGE_SIZE);
217162306a36Sopenharmony_ci		if (!attrs->srq)
217262306a36Sopenharmony_ci			qhp->wq.rq.memsize =
217362306a36Sopenharmony_ci				roundup(qhp->wq.rq.memsize, PAGE_SIZE);
217462306a36Sopenharmony_ci	}
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	ret = create_qp(&rhp->rdev, &qhp->wq, &schp->cq, &rchp->cq,
217762306a36Sopenharmony_ci			ucontext ? &ucontext->uctx : &rhp->rdev.uctx,
217862306a36Sopenharmony_ci			qhp->wr_waitp, !attrs->srq);
217962306a36Sopenharmony_ci	if (ret)
218062306a36Sopenharmony_ci		goto err_free_wr_wait;
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci	attrs->cap.max_recv_wr = rqsize - 1;
218362306a36Sopenharmony_ci	attrs->cap.max_send_wr = sqsize - 1;
218462306a36Sopenharmony_ci	attrs->cap.max_inline_data = T4_MAX_SEND_INLINE;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	qhp->rhp = rhp;
218762306a36Sopenharmony_ci	qhp->attr.pd = php->pdid;
218862306a36Sopenharmony_ci	qhp->attr.scq = ((struct c4iw_cq *) attrs->send_cq)->cq.cqid;
218962306a36Sopenharmony_ci	qhp->attr.rcq = ((struct c4iw_cq *) attrs->recv_cq)->cq.cqid;
219062306a36Sopenharmony_ci	qhp->attr.sq_num_entries = attrs->cap.max_send_wr;
219162306a36Sopenharmony_ci	qhp->attr.sq_max_sges = attrs->cap.max_send_sge;
219262306a36Sopenharmony_ci	qhp->attr.sq_max_sges_rdma_write = attrs->cap.max_send_sge;
219362306a36Sopenharmony_ci	if (!attrs->srq) {
219462306a36Sopenharmony_ci		qhp->attr.rq_num_entries = attrs->cap.max_recv_wr;
219562306a36Sopenharmony_ci		qhp->attr.rq_max_sges = attrs->cap.max_recv_sge;
219662306a36Sopenharmony_ci	}
219762306a36Sopenharmony_ci	qhp->attr.state = C4IW_QP_STATE_IDLE;
219862306a36Sopenharmony_ci	qhp->attr.next_state = C4IW_QP_STATE_IDLE;
219962306a36Sopenharmony_ci	qhp->attr.enable_rdma_read = 1;
220062306a36Sopenharmony_ci	qhp->attr.enable_rdma_write = 1;
220162306a36Sopenharmony_ci	qhp->attr.enable_bind = 1;
220262306a36Sopenharmony_ci	qhp->attr.max_ord = 0;
220362306a36Sopenharmony_ci	qhp->attr.max_ird = 0;
220462306a36Sopenharmony_ci	qhp->sq_sig_all = attrs->sq_sig_type == IB_SIGNAL_ALL_WR;
220562306a36Sopenharmony_ci	spin_lock_init(&qhp->lock);
220662306a36Sopenharmony_ci	mutex_init(&qhp->mutex);
220762306a36Sopenharmony_ci	init_waitqueue_head(&qhp->wait);
220862306a36Sopenharmony_ci	init_completion(&qhp->qp_rel_comp);
220962306a36Sopenharmony_ci	refcount_set(&qhp->qp_refcnt, 1);
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	ret = xa_insert_irq(&rhp->qps, qhp->wq.sq.qid, qhp, GFP_KERNEL);
221262306a36Sopenharmony_ci	if (ret)
221362306a36Sopenharmony_ci		goto err_destroy_qp;
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	if (udata && ucontext) {
221662306a36Sopenharmony_ci		sq_key_mm = kmalloc(sizeof(*sq_key_mm), GFP_KERNEL);
221762306a36Sopenharmony_ci		if (!sq_key_mm) {
221862306a36Sopenharmony_ci			ret = -ENOMEM;
221962306a36Sopenharmony_ci			goto err_remove_handle;
222062306a36Sopenharmony_ci		}
222162306a36Sopenharmony_ci		if (!attrs->srq) {
222262306a36Sopenharmony_ci			rq_key_mm = kmalloc(sizeof(*rq_key_mm), GFP_KERNEL);
222362306a36Sopenharmony_ci			if (!rq_key_mm) {
222462306a36Sopenharmony_ci				ret = -ENOMEM;
222562306a36Sopenharmony_ci				goto err_free_sq_key;
222662306a36Sopenharmony_ci			}
222762306a36Sopenharmony_ci		}
222862306a36Sopenharmony_ci		sq_db_key_mm = kmalloc(sizeof(*sq_db_key_mm), GFP_KERNEL);
222962306a36Sopenharmony_ci		if (!sq_db_key_mm) {
223062306a36Sopenharmony_ci			ret = -ENOMEM;
223162306a36Sopenharmony_ci			goto err_free_rq_key;
223262306a36Sopenharmony_ci		}
223362306a36Sopenharmony_ci		if (!attrs->srq) {
223462306a36Sopenharmony_ci			rq_db_key_mm =
223562306a36Sopenharmony_ci				kmalloc(sizeof(*rq_db_key_mm), GFP_KERNEL);
223662306a36Sopenharmony_ci			if (!rq_db_key_mm) {
223762306a36Sopenharmony_ci				ret = -ENOMEM;
223862306a36Sopenharmony_ci				goto err_free_sq_db_key;
223962306a36Sopenharmony_ci			}
224062306a36Sopenharmony_ci		}
224162306a36Sopenharmony_ci		memset(&uresp, 0, sizeof(uresp));
224262306a36Sopenharmony_ci		if (t4_sq_onchip(&qhp->wq.sq)) {
224362306a36Sopenharmony_ci			ma_sync_key_mm = kmalloc(sizeof(*ma_sync_key_mm),
224462306a36Sopenharmony_ci						 GFP_KERNEL);
224562306a36Sopenharmony_ci			if (!ma_sync_key_mm) {
224662306a36Sopenharmony_ci				ret = -ENOMEM;
224762306a36Sopenharmony_ci				goto err_free_rq_db_key;
224862306a36Sopenharmony_ci			}
224962306a36Sopenharmony_ci			uresp.flags = C4IW_QPF_ONCHIP;
225062306a36Sopenharmony_ci		}
225162306a36Sopenharmony_ci		if (rhp->rdev.lldi.write_w_imm_support)
225262306a36Sopenharmony_ci			uresp.flags |= C4IW_QPF_WRITE_W_IMM;
225362306a36Sopenharmony_ci		uresp.qid_mask = rhp->rdev.qpmask;
225462306a36Sopenharmony_ci		uresp.sqid = qhp->wq.sq.qid;
225562306a36Sopenharmony_ci		uresp.sq_size = qhp->wq.sq.size;
225662306a36Sopenharmony_ci		uresp.sq_memsize = qhp->wq.sq.memsize;
225762306a36Sopenharmony_ci		if (!attrs->srq) {
225862306a36Sopenharmony_ci			uresp.rqid = qhp->wq.rq.qid;
225962306a36Sopenharmony_ci			uresp.rq_size = qhp->wq.rq.size;
226062306a36Sopenharmony_ci			uresp.rq_memsize = qhp->wq.rq.memsize;
226162306a36Sopenharmony_ci		}
226262306a36Sopenharmony_ci		spin_lock(&ucontext->mmap_lock);
226362306a36Sopenharmony_ci		if (ma_sync_key_mm) {
226462306a36Sopenharmony_ci			uresp.ma_sync_key = ucontext->key;
226562306a36Sopenharmony_ci			ucontext->key += PAGE_SIZE;
226662306a36Sopenharmony_ci		}
226762306a36Sopenharmony_ci		uresp.sq_key = ucontext->key;
226862306a36Sopenharmony_ci		ucontext->key += PAGE_SIZE;
226962306a36Sopenharmony_ci		if (!attrs->srq) {
227062306a36Sopenharmony_ci			uresp.rq_key = ucontext->key;
227162306a36Sopenharmony_ci			ucontext->key += PAGE_SIZE;
227262306a36Sopenharmony_ci		}
227362306a36Sopenharmony_ci		uresp.sq_db_gts_key = ucontext->key;
227462306a36Sopenharmony_ci		ucontext->key += PAGE_SIZE;
227562306a36Sopenharmony_ci		if (!attrs->srq) {
227662306a36Sopenharmony_ci			uresp.rq_db_gts_key = ucontext->key;
227762306a36Sopenharmony_ci			ucontext->key += PAGE_SIZE;
227862306a36Sopenharmony_ci		}
227962306a36Sopenharmony_ci		spin_unlock(&ucontext->mmap_lock);
228062306a36Sopenharmony_ci		ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
228162306a36Sopenharmony_ci		if (ret)
228262306a36Sopenharmony_ci			goto err_free_ma_sync_key;
228362306a36Sopenharmony_ci		sq_key_mm->key = uresp.sq_key;
228462306a36Sopenharmony_ci		sq_key_mm->addr = qhp->wq.sq.phys_addr;
228562306a36Sopenharmony_ci		sq_key_mm->len = PAGE_ALIGN(qhp->wq.sq.memsize);
228662306a36Sopenharmony_ci		insert_mmap(ucontext, sq_key_mm);
228762306a36Sopenharmony_ci		if (!attrs->srq) {
228862306a36Sopenharmony_ci			rq_key_mm->key = uresp.rq_key;
228962306a36Sopenharmony_ci			rq_key_mm->addr = virt_to_phys(qhp->wq.rq.queue);
229062306a36Sopenharmony_ci			rq_key_mm->len = PAGE_ALIGN(qhp->wq.rq.memsize);
229162306a36Sopenharmony_ci			insert_mmap(ucontext, rq_key_mm);
229262306a36Sopenharmony_ci		}
229362306a36Sopenharmony_ci		sq_db_key_mm->key = uresp.sq_db_gts_key;
229462306a36Sopenharmony_ci		sq_db_key_mm->addr = (u64)(unsigned long)qhp->wq.sq.bar2_pa;
229562306a36Sopenharmony_ci		sq_db_key_mm->len = PAGE_SIZE;
229662306a36Sopenharmony_ci		insert_mmap(ucontext, sq_db_key_mm);
229762306a36Sopenharmony_ci		if (!attrs->srq) {
229862306a36Sopenharmony_ci			rq_db_key_mm->key = uresp.rq_db_gts_key;
229962306a36Sopenharmony_ci			rq_db_key_mm->addr =
230062306a36Sopenharmony_ci				(u64)(unsigned long)qhp->wq.rq.bar2_pa;
230162306a36Sopenharmony_ci			rq_db_key_mm->len = PAGE_SIZE;
230262306a36Sopenharmony_ci			insert_mmap(ucontext, rq_db_key_mm);
230362306a36Sopenharmony_ci		}
230462306a36Sopenharmony_ci		if (ma_sync_key_mm) {
230562306a36Sopenharmony_ci			ma_sync_key_mm->key = uresp.ma_sync_key;
230662306a36Sopenharmony_ci			ma_sync_key_mm->addr =
230762306a36Sopenharmony_ci				(pci_resource_start(rhp->rdev.lldi.pdev, 0) +
230862306a36Sopenharmony_ci				PCIE_MA_SYNC_A) & PAGE_MASK;
230962306a36Sopenharmony_ci			ma_sync_key_mm->len = PAGE_SIZE;
231062306a36Sopenharmony_ci			insert_mmap(ucontext, ma_sync_key_mm);
231162306a36Sopenharmony_ci		}
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci		qhp->ucontext = ucontext;
231462306a36Sopenharmony_ci	}
231562306a36Sopenharmony_ci	if (!attrs->srq) {
231662306a36Sopenharmony_ci		qhp->wq.qp_errp =
231762306a36Sopenharmony_ci			&qhp->wq.rq.queue[qhp->wq.rq.size].status.qp_err;
231862306a36Sopenharmony_ci	} else {
231962306a36Sopenharmony_ci		qhp->wq.qp_errp =
232062306a36Sopenharmony_ci			&qhp->wq.sq.queue[qhp->wq.sq.size].status.qp_err;
232162306a36Sopenharmony_ci		qhp->wq.srqidxp =
232262306a36Sopenharmony_ci			&qhp->wq.sq.queue[qhp->wq.sq.size].status.srqidx;
232362306a36Sopenharmony_ci	}
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_ci	qhp->ibqp.qp_num = qhp->wq.sq.qid;
232662306a36Sopenharmony_ci	if (attrs->srq)
232762306a36Sopenharmony_ci		qhp->srq = to_c4iw_srq(attrs->srq);
232862306a36Sopenharmony_ci	INIT_LIST_HEAD(&qhp->db_fc_entry);
232962306a36Sopenharmony_ci	pr_debug("sq id %u size %u memsize %zu num_entries %u rq id %u size %u memsize %zu num_entries %u\n",
233062306a36Sopenharmony_ci		 qhp->wq.sq.qid, qhp->wq.sq.size, qhp->wq.sq.memsize,
233162306a36Sopenharmony_ci		 attrs->cap.max_send_wr, qhp->wq.rq.qid, qhp->wq.rq.size,
233262306a36Sopenharmony_ci		 qhp->wq.rq.memsize, attrs->cap.max_recv_wr);
233362306a36Sopenharmony_ci	return 0;
233462306a36Sopenharmony_cierr_free_ma_sync_key:
233562306a36Sopenharmony_ci	kfree(ma_sync_key_mm);
233662306a36Sopenharmony_cierr_free_rq_db_key:
233762306a36Sopenharmony_ci	if (!attrs->srq)
233862306a36Sopenharmony_ci		kfree(rq_db_key_mm);
233962306a36Sopenharmony_cierr_free_sq_db_key:
234062306a36Sopenharmony_ci	kfree(sq_db_key_mm);
234162306a36Sopenharmony_cierr_free_rq_key:
234262306a36Sopenharmony_ci	if (!attrs->srq)
234362306a36Sopenharmony_ci		kfree(rq_key_mm);
234462306a36Sopenharmony_cierr_free_sq_key:
234562306a36Sopenharmony_ci	kfree(sq_key_mm);
234662306a36Sopenharmony_cierr_remove_handle:
234762306a36Sopenharmony_ci	xa_erase_irq(&rhp->qps, qhp->wq.sq.qid);
234862306a36Sopenharmony_cierr_destroy_qp:
234962306a36Sopenharmony_ci	destroy_qp(&rhp->rdev, &qhp->wq,
235062306a36Sopenharmony_ci		   ucontext ? &ucontext->uctx : &rhp->rdev.uctx, !attrs->srq);
235162306a36Sopenharmony_cierr_free_wr_wait:
235262306a36Sopenharmony_ci	c4iw_put_wr_wait(qhp->wr_waitp);
235362306a36Sopenharmony_ci	return ret;
235462306a36Sopenharmony_ci}
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ciint c4iw_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
235762306a36Sopenharmony_ci		      int attr_mask, struct ib_udata *udata)
235862306a36Sopenharmony_ci{
235962306a36Sopenharmony_ci	struct c4iw_dev *rhp;
236062306a36Sopenharmony_ci	struct c4iw_qp *qhp;
236162306a36Sopenharmony_ci	enum c4iw_qp_attr_mask mask = 0;
236262306a36Sopenharmony_ci	struct c4iw_qp_attributes attrs = {};
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	pr_debug("ib_qp %p\n", ibqp);
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
236762306a36Sopenharmony_ci		return -EOPNOTSUPP;
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	/* iwarp does not support the RTR state */
237062306a36Sopenharmony_ci	if ((attr_mask & IB_QP_STATE) && (attr->qp_state == IB_QPS_RTR))
237162306a36Sopenharmony_ci		attr_mask &= ~IB_QP_STATE;
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_ci	/* Make sure we still have something left to do */
237462306a36Sopenharmony_ci	if (!attr_mask)
237562306a36Sopenharmony_ci		return 0;
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci	qhp = to_c4iw_qp(ibqp);
237862306a36Sopenharmony_ci	rhp = qhp->rhp;
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci	attrs.next_state = c4iw_convert_state(attr->qp_state);
238162306a36Sopenharmony_ci	attrs.enable_rdma_read = (attr->qp_access_flags &
238262306a36Sopenharmony_ci			       IB_ACCESS_REMOTE_READ) ?  1 : 0;
238362306a36Sopenharmony_ci	attrs.enable_rdma_write = (attr->qp_access_flags &
238462306a36Sopenharmony_ci				IB_ACCESS_REMOTE_WRITE) ? 1 : 0;
238562306a36Sopenharmony_ci	attrs.enable_bind = (attr->qp_access_flags & IB_ACCESS_MW_BIND) ? 1 : 0;
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci	mask |= (attr_mask & IB_QP_STATE) ? C4IW_QP_ATTR_NEXT_STATE : 0;
238962306a36Sopenharmony_ci	mask |= (attr_mask & IB_QP_ACCESS_FLAGS) ?
239062306a36Sopenharmony_ci			(C4IW_QP_ATTR_ENABLE_RDMA_READ |
239162306a36Sopenharmony_ci			 C4IW_QP_ATTR_ENABLE_RDMA_WRITE |
239262306a36Sopenharmony_ci			 C4IW_QP_ATTR_ENABLE_RDMA_BIND) : 0;
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci	/*
239562306a36Sopenharmony_ci	 * Use SQ_PSN and RQ_PSN to pass in IDX_INC values for
239662306a36Sopenharmony_ci	 * ringing the queue db when we're in DB_FULL mode.
239762306a36Sopenharmony_ci	 * Only allow this on T4 devices.
239862306a36Sopenharmony_ci	 */
239962306a36Sopenharmony_ci	attrs.sq_db_inc = attr->sq_psn;
240062306a36Sopenharmony_ci	attrs.rq_db_inc = attr->rq_psn;
240162306a36Sopenharmony_ci	mask |= (attr_mask & IB_QP_SQ_PSN) ? C4IW_QP_ATTR_SQ_DB : 0;
240262306a36Sopenharmony_ci	mask |= (attr_mask & IB_QP_RQ_PSN) ? C4IW_QP_ATTR_RQ_DB : 0;
240362306a36Sopenharmony_ci	if (!is_t4(to_c4iw_qp(ibqp)->rhp->rdev.lldi.adapter_type) &&
240462306a36Sopenharmony_ci	    (mask & (C4IW_QP_ATTR_SQ_DB|C4IW_QP_ATTR_RQ_DB)))
240562306a36Sopenharmony_ci		return -EINVAL;
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ci	return c4iw_modify_qp(rhp, qhp, mask, &attrs, 0);
240862306a36Sopenharmony_ci}
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_cistruct ib_qp *c4iw_get_qp(struct ib_device *dev, int qpn)
241162306a36Sopenharmony_ci{
241262306a36Sopenharmony_ci	pr_debug("ib_dev %p qpn 0x%x\n", dev, qpn);
241362306a36Sopenharmony_ci	return (struct ib_qp *)get_qhp(to_c4iw_dev(dev), qpn);
241462306a36Sopenharmony_ci}
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_civoid c4iw_dispatch_srq_limit_reached_event(struct c4iw_srq *srq)
241762306a36Sopenharmony_ci{
241862306a36Sopenharmony_ci	struct ib_event event = {};
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_ci	event.device = &srq->rhp->ibdev;
242162306a36Sopenharmony_ci	event.element.srq = &srq->ibsrq;
242262306a36Sopenharmony_ci	event.event = IB_EVENT_SRQ_LIMIT_REACHED;
242362306a36Sopenharmony_ci	ib_dispatch_event(&event);
242462306a36Sopenharmony_ci}
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ciint c4iw_modify_srq(struct ib_srq *ib_srq, struct ib_srq_attr *attr,
242762306a36Sopenharmony_ci		    enum ib_srq_attr_mask srq_attr_mask,
242862306a36Sopenharmony_ci		    struct ib_udata *udata)
242962306a36Sopenharmony_ci{
243062306a36Sopenharmony_ci	struct c4iw_srq *srq = to_c4iw_srq(ib_srq);
243162306a36Sopenharmony_ci	int ret = 0;
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_ci	/*
243462306a36Sopenharmony_ci	 * XXX 0 mask == a SW interrupt for srq_limit reached...
243562306a36Sopenharmony_ci	 */
243662306a36Sopenharmony_ci	if (udata && !srq_attr_mask) {
243762306a36Sopenharmony_ci		c4iw_dispatch_srq_limit_reached_event(srq);
243862306a36Sopenharmony_ci		goto out;
243962306a36Sopenharmony_ci	}
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci	/* no support for this yet */
244262306a36Sopenharmony_ci	if (srq_attr_mask & IB_SRQ_MAX_WR) {
244362306a36Sopenharmony_ci		ret = -EINVAL;
244462306a36Sopenharmony_ci		goto out;
244562306a36Sopenharmony_ci	}
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	if (!udata && (srq_attr_mask & IB_SRQ_LIMIT)) {
244862306a36Sopenharmony_ci		srq->armed = true;
244962306a36Sopenharmony_ci		srq->srq_limit = attr->srq_limit;
245062306a36Sopenharmony_ci	}
245162306a36Sopenharmony_ciout:
245262306a36Sopenharmony_ci	return ret;
245362306a36Sopenharmony_ci}
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ciint c4iw_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
245662306a36Sopenharmony_ci		     int attr_mask, struct ib_qp_init_attr *init_attr)
245762306a36Sopenharmony_ci{
245862306a36Sopenharmony_ci	struct c4iw_qp *qhp = to_c4iw_qp(ibqp);
245962306a36Sopenharmony_ci
246062306a36Sopenharmony_ci	memset(attr, 0, sizeof(*attr));
246162306a36Sopenharmony_ci	memset(init_attr, 0, sizeof(*init_attr));
246262306a36Sopenharmony_ci	attr->qp_state = to_ib_qp_state(qhp->attr.state);
246362306a36Sopenharmony_ci	attr->cur_qp_state = to_ib_qp_state(qhp->attr.state);
246462306a36Sopenharmony_ci	init_attr->cap.max_send_wr = qhp->attr.sq_num_entries;
246562306a36Sopenharmony_ci	init_attr->cap.max_recv_wr = qhp->attr.rq_num_entries;
246662306a36Sopenharmony_ci	init_attr->cap.max_send_sge = qhp->attr.sq_max_sges;
246762306a36Sopenharmony_ci	init_attr->cap.max_recv_sge = qhp->attr.rq_max_sges;
246862306a36Sopenharmony_ci	init_attr->cap.max_inline_data = T4_MAX_SEND_INLINE;
246962306a36Sopenharmony_ci	init_attr->sq_sig_type = qhp->sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
247062306a36Sopenharmony_ci	return 0;
247162306a36Sopenharmony_ci}
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_cistatic void free_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx,
247462306a36Sopenharmony_ci			   struct c4iw_wr_wait *wr_waitp)
247562306a36Sopenharmony_ci{
247662306a36Sopenharmony_ci	struct c4iw_rdev *rdev = &srq->rhp->rdev;
247762306a36Sopenharmony_ci	struct sk_buff *skb = srq->destroy_skb;
247862306a36Sopenharmony_ci	struct t4_srq *wq = &srq->wq;
247962306a36Sopenharmony_ci	struct fw_ri_res_wr *res_wr;
248062306a36Sopenharmony_ci	struct fw_ri_res *res;
248162306a36Sopenharmony_ci	int wr_len;
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	wr_len = sizeof(*res_wr) + sizeof(*res);
248462306a36Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len);
248762306a36Sopenharmony_ci	memset(res_wr, 0, wr_len);
248862306a36Sopenharmony_ci	res_wr->op_nres = cpu_to_be32(FW_WR_OP_V(FW_RI_RES_WR) |
248962306a36Sopenharmony_ci			FW_RI_RES_WR_NRES_V(1) |
249062306a36Sopenharmony_ci			FW_WR_COMPL_F);
249162306a36Sopenharmony_ci	res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
249262306a36Sopenharmony_ci	res_wr->cookie = (uintptr_t)wr_waitp;
249362306a36Sopenharmony_ci	res = res_wr->res;
249462306a36Sopenharmony_ci	res->u.srq.restype = FW_RI_RES_TYPE_SRQ;
249562306a36Sopenharmony_ci	res->u.srq.op = FW_RI_RES_OP_RESET;
249662306a36Sopenharmony_ci	res->u.srq.srqid = cpu_to_be32(srq->idx);
249762306a36Sopenharmony_ci	res->u.srq.eqid = cpu_to_be32(wq->qid);
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	c4iw_init_wr_wait(wr_waitp);
250062306a36Sopenharmony_ci	c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0, __func__);
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci	dma_free_coherent(&rdev->lldi.pdev->dev,
250362306a36Sopenharmony_ci			  wq->memsize, wq->queue,
250462306a36Sopenharmony_ci			dma_unmap_addr(wq, mapping));
250562306a36Sopenharmony_ci	c4iw_rqtpool_free(rdev, wq->rqt_hwaddr, wq->rqt_size);
250662306a36Sopenharmony_ci	kfree(wq->sw_rq);
250762306a36Sopenharmony_ci	c4iw_put_qpid(rdev, wq->qid, uctx);
250862306a36Sopenharmony_ci}
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_cistatic int alloc_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx,
251162306a36Sopenharmony_ci			   struct c4iw_wr_wait *wr_waitp)
251262306a36Sopenharmony_ci{
251362306a36Sopenharmony_ci	struct c4iw_rdev *rdev = &srq->rhp->rdev;
251462306a36Sopenharmony_ci	int user = (uctx != &rdev->uctx);
251562306a36Sopenharmony_ci	struct t4_srq *wq = &srq->wq;
251662306a36Sopenharmony_ci	struct fw_ri_res_wr *res_wr;
251762306a36Sopenharmony_ci	struct fw_ri_res *res;
251862306a36Sopenharmony_ci	struct sk_buff *skb;
251962306a36Sopenharmony_ci	int wr_len;
252062306a36Sopenharmony_ci	int eqsize;
252162306a36Sopenharmony_ci	int ret = -ENOMEM;
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	wq->qid = c4iw_get_qpid(rdev, uctx);
252462306a36Sopenharmony_ci	if (!wq->qid)
252562306a36Sopenharmony_ci		goto err;
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	if (!user) {
252862306a36Sopenharmony_ci		wq->sw_rq = kcalloc(wq->size, sizeof(*wq->sw_rq),
252962306a36Sopenharmony_ci				    GFP_KERNEL);
253062306a36Sopenharmony_ci		if (!wq->sw_rq)
253162306a36Sopenharmony_ci			goto err_put_qpid;
253262306a36Sopenharmony_ci		wq->pending_wrs = kcalloc(srq->wq.size,
253362306a36Sopenharmony_ci					  sizeof(*srq->wq.pending_wrs),
253462306a36Sopenharmony_ci					  GFP_KERNEL);
253562306a36Sopenharmony_ci		if (!wq->pending_wrs)
253662306a36Sopenharmony_ci			goto err_free_sw_rq;
253762306a36Sopenharmony_ci	}
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_ci	wq->rqt_size = wq->size;
254062306a36Sopenharmony_ci	wq->rqt_hwaddr = c4iw_rqtpool_alloc(rdev, wq->rqt_size);
254162306a36Sopenharmony_ci	if (!wq->rqt_hwaddr)
254262306a36Sopenharmony_ci		goto err_free_pending_wrs;
254362306a36Sopenharmony_ci	wq->rqt_abs_idx = (wq->rqt_hwaddr - rdev->lldi.vr->rq.start) >>
254462306a36Sopenharmony_ci		T4_RQT_ENTRY_SHIFT;
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_ci	wq->queue = dma_alloc_coherent(&rdev->lldi.pdev->dev, wq->memsize,
254762306a36Sopenharmony_ci				       &wq->dma_addr, GFP_KERNEL);
254862306a36Sopenharmony_ci	if (!wq->queue)
254962306a36Sopenharmony_ci		goto err_free_rqtpool;
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci	dma_unmap_addr_set(wq, mapping, wq->dma_addr);
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	wq->bar2_va = c4iw_bar2_addrs(rdev, wq->qid, CXGB4_BAR2_QTYPE_EGRESS,
255462306a36Sopenharmony_ci				      &wq->bar2_qid,
255562306a36Sopenharmony_ci			user ? &wq->bar2_pa : NULL);
255662306a36Sopenharmony_ci
255762306a36Sopenharmony_ci	/*
255862306a36Sopenharmony_ci	 * User mode must have bar2 access.
255962306a36Sopenharmony_ci	 */
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	if (user && !wq->bar2_va) {
256262306a36Sopenharmony_ci		pr_warn(MOD "%s: srqid %u not in BAR2 range.\n",
256362306a36Sopenharmony_ci			pci_name(rdev->lldi.pdev), wq->qid);
256462306a36Sopenharmony_ci		ret = -EINVAL;
256562306a36Sopenharmony_ci		goto err_free_queue;
256662306a36Sopenharmony_ci	}
256762306a36Sopenharmony_ci
256862306a36Sopenharmony_ci	/* build fw_ri_res_wr */
256962306a36Sopenharmony_ci	wr_len = sizeof(*res_wr) + sizeof(*res);
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	skb = alloc_skb(wr_len, GFP_KERNEL);
257262306a36Sopenharmony_ci	if (!skb)
257362306a36Sopenharmony_ci		goto err_free_queue;
257462306a36Sopenharmony_ci	set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_ci	res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len);
257762306a36Sopenharmony_ci	memset(res_wr, 0, wr_len);
257862306a36Sopenharmony_ci	res_wr->op_nres = cpu_to_be32(FW_WR_OP_V(FW_RI_RES_WR) |
257962306a36Sopenharmony_ci			FW_RI_RES_WR_NRES_V(1) |
258062306a36Sopenharmony_ci			FW_WR_COMPL_F);
258162306a36Sopenharmony_ci	res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
258262306a36Sopenharmony_ci	res_wr->cookie = (uintptr_t)wr_waitp;
258362306a36Sopenharmony_ci	res = res_wr->res;
258462306a36Sopenharmony_ci	res->u.srq.restype = FW_RI_RES_TYPE_SRQ;
258562306a36Sopenharmony_ci	res->u.srq.op = FW_RI_RES_OP_WRITE;
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci	/*
258862306a36Sopenharmony_ci	 * eqsize is the number of 64B entries plus the status page size.
258962306a36Sopenharmony_ci	 */
259062306a36Sopenharmony_ci	eqsize = wq->size * T4_RQ_NUM_SLOTS +
259162306a36Sopenharmony_ci		rdev->hw_queue.t4_eq_status_entries;
259262306a36Sopenharmony_ci	res->u.srq.eqid = cpu_to_be32(wq->qid);
259362306a36Sopenharmony_ci	res->u.srq.fetchszm_to_iqid =
259462306a36Sopenharmony_ci						/* no host cidx updates */
259562306a36Sopenharmony_ci		cpu_to_be32(FW_RI_RES_WR_HOSTFCMODE_V(0) |
259662306a36Sopenharmony_ci		FW_RI_RES_WR_CPRIO_V(0) |       /* don't keep in chip cache */
259762306a36Sopenharmony_ci		FW_RI_RES_WR_PCIECHN_V(0) |     /* set by uP at ri_init time */
259862306a36Sopenharmony_ci		FW_RI_RES_WR_FETCHRO_V(0));     /* relaxed_ordering */
259962306a36Sopenharmony_ci	res->u.srq.dcaen_to_eqsize =
260062306a36Sopenharmony_ci		cpu_to_be32(FW_RI_RES_WR_DCAEN_V(0) |
260162306a36Sopenharmony_ci		FW_RI_RES_WR_DCACPU_V(0) |
260262306a36Sopenharmony_ci		FW_RI_RES_WR_FBMIN_V(2) |
260362306a36Sopenharmony_ci		FW_RI_RES_WR_FBMAX_V(3) |
260462306a36Sopenharmony_ci		FW_RI_RES_WR_CIDXFTHRESHO_V(0) |
260562306a36Sopenharmony_ci		FW_RI_RES_WR_CIDXFTHRESH_V(0) |
260662306a36Sopenharmony_ci		FW_RI_RES_WR_EQSIZE_V(eqsize));
260762306a36Sopenharmony_ci	res->u.srq.eqaddr = cpu_to_be64(wq->dma_addr);
260862306a36Sopenharmony_ci	res->u.srq.srqid = cpu_to_be32(srq->idx);
260962306a36Sopenharmony_ci	res->u.srq.pdid = cpu_to_be32(srq->pdid);
261062306a36Sopenharmony_ci	res->u.srq.hwsrqsize = cpu_to_be32(wq->rqt_size);
261162306a36Sopenharmony_ci	res->u.srq.hwsrqaddr = cpu_to_be32(wq->rqt_hwaddr -
261262306a36Sopenharmony_ci			rdev->lldi.vr->rq.start);
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	c4iw_init_wr_wait(wr_waitp);
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, wq->qid, __func__);
261762306a36Sopenharmony_ci	if (ret)
261862306a36Sopenharmony_ci		goto err_free_queue;
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci	pr_debug("%s srq %u eqid %u pdid %u queue va %p pa 0x%llx\n"
262162306a36Sopenharmony_ci			" bar2_addr %p rqt addr 0x%x size %d\n",
262262306a36Sopenharmony_ci			__func__, srq->idx, wq->qid, srq->pdid, wq->queue,
262362306a36Sopenharmony_ci			(u64)virt_to_phys(wq->queue), wq->bar2_va,
262462306a36Sopenharmony_ci			wq->rqt_hwaddr, wq->rqt_size);
262562306a36Sopenharmony_ci
262662306a36Sopenharmony_ci	return 0;
262762306a36Sopenharmony_cierr_free_queue:
262862306a36Sopenharmony_ci	dma_free_coherent(&rdev->lldi.pdev->dev,
262962306a36Sopenharmony_ci			  wq->memsize, wq->queue,
263062306a36Sopenharmony_ci			dma_unmap_addr(wq, mapping));
263162306a36Sopenharmony_cierr_free_rqtpool:
263262306a36Sopenharmony_ci	c4iw_rqtpool_free(rdev, wq->rqt_hwaddr, wq->rqt_size);
263362306a36Sopenharmony_cierr_free_pending_wrs:
263462306a36Sopenharmony_ci	if (!user)
263562306a36Sopenharmony_ci		kfree(wq->pending_wrs);
263662306a36Sopenharmony_cierr_free_sw_rq:
263762306a36Sopenharmony_ci	if (!user)
263862306a36Sopenharmony_ci		kfree(wq->sw_rq);
263962306a36Sopenharmony_cierr_put_qpid:
264062306a36Sopenharmony_ci	c4iw_put_qpid(rdev, wq->qid, uctx);
264162306a36Sopenharmony_cierr:
264262306a36Sopenharmony_ci	return ret;
264362306a36Sopenharmony_ci}
264462306a36Sopenharmony_ci
264562306a36Sopenharmony_civoid c4iw_copy_wr_to_srq(struct t4_srq *srq, union t4_recv_wr *wqe, u8 len16)
264662306a36Sopenharmony_ci{
264762306a36Sopenharmony_ci	u64 *src, *dst;
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_ci	src = (u64 *)wqe;
265062306a36Sopenharmony_ci	dst = (u64 *)((u8 *)srq->queue + srq->wq_pidx * T4_EQ_ENTRY_SIZE);
265162306a36Sopenharmony_ci	while (len16) {
265262306a36Sopenharmony_ci		*dst++ = *src++;
265362306a36Sopenharmony_ci		if (dst >= (u64 *)&srq->queue[srq->size])
265462306a36Sopenharmony_ci			dst = (u64 *)srq->queue;
265562306a36Sopenharmony_ci		*dst++ = *src++;
265662306a36Sopenharmony_ci		if (dst >= (u64 *)&srq->queue[srq->size])
265762306a36Sopenharmony_ci			dst = (u64 *)srq->queue;
265862306a36Sopenharmony_ci		len16--;
265962306a36Sopenharmony_ci	}
266062306a36Sopenharmony_ci}
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ciint c4iw_create_srq(struct ib_srq *ib_srq, struct ib_srq_init_attr *attrs,
266362306a36Sopenharmony_ci			       struct ib_udata *udata)
266462306a36Sopenharmony_ci{
266562306a36Sopenharmony_ci	struct ib_pd *pd = ib_srq->pd;
266662306a36Sopenharmony_ci	struct c4iw_dev *rhp;
266762306a36Sopenharmony_ci	struct c4iw_srq *srq = to_c4iw_srq(ib_srq);
266862306a36Sopenharmony_ci	struct c4iw_pd *php;
266962306a36Sopenharmony_ci	struct c4iw_create_srq_resp uresp;
267062306a36Sopenharmony_ci	struct c4iw_ucontext *ucontext;
267162306a36Sopenharmony_ci	struct c4iw_mm_entry *srq_key_mm, *srq_db_key_mm;
267262306a36Sopenharmony_ci	int rqsize;
267362306a36Sopenharmony_ci	int ret;
267462306a36Sopenharmony_ci	int wr_len;
267562306a36Sopenharmony_ci
267662306a36Sopenharmony_ci	if (attrs->srq_type != IB_SRQT_BASIC)
267762306a36Sopenharmony_ci		return -EOPNOTSUPP;
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci	pr_debug("%s ib_pd %p\n", __func__, pd);
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	php = to_c4iw_pd(pd);
268262306a36Sopenharmony_ci	rhp = php->rhp;
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci	if (!rhp->rdev.lldi.vr->srq.size)
268562306a36Sopenharmony_ci		return -EINVAL;
268662306a36Sopenharmony_ci	if (attrs->attr.max_wr > rhp->rdev.hw_queue.t4_max_rq_size)
268762306a36Sopenharmony_ci		return -E2BIG;
268862306a36Sopenharmony_ci	if (attrs->attr.max_sge > T4_MAX_RECV_SGE)
268962306a36Sopenharmony_ci		return -E2BIG;
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_ci	/*
269262306a36Sopenharmony_ci	 * SRQ RQT and RQ must be a power of 2 and at least 16 deep.
269362306a36Sopenharmony_ci	 */
269462306a36Sopenharmony_ci	rqsize = attrs->attr.max_wr + 1;
269562306a36Sopenharmony_ci	rqsize = roundup_pow_of_two(max_t(u16, rqsize, 16));
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci	ucontext = rdma_udata_to_drv_context(udata, struct c4iw_ucontext,
269862306a36Sopenharmony_ci					     ibucontext);
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_ci	srq->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
270162306a36Sopenharmony_ci	if (!srq->wr_waitp)
270262306a36Sopenharmony_ci		return -ENOMEM;
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_ci	srq->idx = c4iw_alloc_srq_idx(&rhp->rdev);
270562306a36Sopenharmony_ci	if (srq->idx < 0) {
270662306a36Sopenharmony_ci		ret = -ENOMEM;
270762306a36Sopenharmony_ci		goto err_free_wr_wait;
270862306a36Sopenharmony_ci	}
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci	wr_len = sizeof(struct fw_ri_res_wr) + sizeof(struct fw_ri_res);
271162306a36Sopenharmony_ci	srq->destroy_skb = alloc_skb(wr_len, GFP_KERNEL);
271262306a36Sopenharmony_ci	if (!srq->destroy_skb) {
271362306a36Sopenharmony_ci		ret = -ENOMEM;
271462306a36Sopenharmony_ci		goto err_free_srq_idx;
271562306a36Sopenharmony_ci	}
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_ci	srq->rhp = rhp;
271862306a36Sopenharmony_ci	srq->pdid = php->pdid;
271962306a36Sopenharmony_ci
272062306a36Sopenharmony_ci	srq->wq.size = rqsize;
272162306a36Sopenharmony_ci	srq->wq.memsize =
272262306a36Sopenharmony_ci		(rqsize + rhp->rdev.hw_queue.t4_eq_status_entries) *
272362306a36Sopenharmony_ci		sizeof(*srq->wq.queue);
272462306a36Sopenharmony_ci	if (ucontext)
272562306a36Sopenharmony_ci		srq->wq.memsize = roundup(srq->wq.memsize, PAGE_SIZE);
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci	ret = alloc_srq_queue(srq, ucontext ? &ucontext->uctx :
272862306a36Sopenharmony_ci			&rhp->rdev.uctx, srq->wr_waitp);
272962306a36Sopenharmony_ci	if (ret)
273062306a36Sopenharmony_ci		goto err_free_skb;
273162306a36Sopenharmony_ci	attrs->attr.max_wr = rqsize - 1;
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci	if (CHELSIO_CHIP_VERSION(rhp->rdev.lldi.adapter_type) > CHELSIO_T6)
273462306a36Sopenharmony_ci		srq->flags = T4_SRQ_LIMIT_SUPPORT;
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_ci	if (udata) {
273762306a36Sopenharmony_ci		srq_key_mm = kmalloc(sizeof(*srq_key_mm), GFP_KERNEL);
273862306a36Sopenharmony_ci		if (!srq_key_mm) {
273962306a36Sopenharmony_ci			ret = -ENOMEM;
274062306a36Sopenharmony_ci			goto err_free_queue;
274162306a36Sopenharmony_ci		}
274262306a36Sopenharmony_ci		srq_db_key_mm = kmalloc(sizeof(*srq_db_key_mm), GFP_KERNEL);
274362306a36Sopenharmony_ci		if (!srq_db_key_mm) {
274462306a36Sopenharmony_ci			ret = -ENOMEM;
274562306a36Sopenharmony_ci			goto err_free_srq_key_mm;
274662306a36Sopenharmony_ci		}
274762306a36Sopenharmony_ci		memset(&uresp, 0, sizeof(uresp));
274862306a36Sopenharmony_ci		uresp.flags = srq->flags;
274962306a36Sopenharmony_ci		uresp.qid_mask = rhp->rdev.qpmask;
275062306a36Sopenharmony_ci		uresp.srqid = srq->wq.qid;
275162306a36Sopenharmony_ci		uresp.srq_size = srq->wq.size;
275262306a36Sopenharmony_ci		uresp.srq_memsize = srq->wq.memsize;
275362306a36Sopenharmony_ci		uresp.rqt_abs_idx = srq->wq.rqt_abs_idx;
275462306a36Sopenharmony_ci		spin_lock(&ucontext->mmap_lock);
275562306a36Sopenharmony_ci		uresp.srq_key = ucontext->key;
275662306a36Sopenharmony_ci		ucontext->key += PAGE_SIZE;
275762306a36Sopenharmony_ci		uresp.srq_db_gts_key = ucontext->key;
275862306a36Sopenharmony_ci		ucontext->key += PAGE_SIZE;
275962306a36Sopenharmony_ci		spin_unlock(&ucontext->mmap_lock);
276062306a36Sopenharmony_ci		ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
276162306a36Sopenharmony_ci		if (ret)
276262306a36Sopenharmony_ci			goto err_free_srq_db_key_mm;
276362306a36Sopenharmony_ci		srq_key_mm->key = uresp.srq_key;
276462306a36Sopenharmony_ci		srq_key_mm->addr = virt_to_phys(srq->wq.queue);
276562306a36Sopenharmony_ci		srq_key_mm->len = PAGE_ALIGN(srq->wq.memsize);
276662306a36Sopenharmony_ci		insert_mmap(ucontext, srq_key_mm);
276762306a36Sopenharmony_ci		srq_db_key_mm->key = uresp.srq_db_gts_key;
276862306a36Sopenharmony_ci		srq_db_key_mm->addr = (u64)(unsigned long)srq->wq.bar2_pa;
276962306a36Sopenharmony_ci		srq_db_key_mm->len = PAGE_SIZE;
277062306a36Sopenharmony_ci		insert_mmap(ucontext, srq_db_key_mm);
277162306a36Sopenharmony_ci	}
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci	pr_debug("%s srq qid %u idx %u size %u memsize %lu num_entries %u\n",
277462306a36Sopenharmony_ci		 __func__, srq->wq.qid, srq->idx, srq->wq.size,
277562306a36Sopenharmony_ci			(unsigned long)srq->wq.memsize, attrs->attr.max_wr);
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_ci	spin_lock_init(&srq->lock);
277862306a36Sopenharmony_ci	return 0;
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_cierr_free_srq_db_key_mm:
278162306a36Sopenharmony_ci	kfree(srq_db_key_mm);
278262306a36Sopenharmony_cierr_free_srq_key_mm:
278362306a36Sopenharmony_ci	kfree(srq_key_mm);
278462306a36Sopenharmony_cierr_free_queue:
278562306a36Sopenharmony_ci	free_srq_queue(srq, ucontext ? &ucontext->uctx : &rhp->rdev.uctx,
278662306a36Sopenharmony_ci		       srq->wr_waitp);
278762306a36Sopenharmony_cierr_free_skb:
278862306a36Sopenharmony_ci	kfree_skb(srq->destroy_skb);
278962306a36Sopenharmony_cierr_free_srq_idx:
279062306a36Sopenharmony_ci	c4iw_free_srq_idx(&rhp->rdev, srq->idx);
279162306a36Sopenharmony_cierr_free_wr_wait:
279262306a36Sopenharmony_ci	c4iw_put_wr_wait(srq->wr_waitp);
279362306a36Sopenharmony_ci	return ret;
279462306a36Sopenharmony_ci}
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_ciint c4iw_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata)
279762306a36Sopenharmony_ci{
279862306a36Sopenharmony_ci	struct c4iw_dev *rhp;
279962306a36Sopenharmony_ci	struct c4iw_srq *srq;
280062306a36Sopenharmony_ci	struct c4iw_ucontext *ucontext;
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	srq = to_c4iw_srq(ibsrq);
280362306a36Sopenharmony_ci	rhp = srq->rhp;
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci	pr_debug("%s id %d\n", __func__, srq->wq.qid);
280662306a36Sopenharmony_ci	ucontext = rdma_udata_to_drv_context(udata, struct c4iw_ucontext,
280762306a36Sopenharmony_ci					     ibucontext);
280862306a36Sopenharmony_ci	free_srq_queue(srq, ucontext ? &ucontext->uctx : &rhp->rdev.uctx,
280962306a36Sopenharmony_ci		       srq->wr_waitp);
281062306a36Sopenharmony_ci	c4iw_free_srq_idx(&rhp->rdev, srq->idx);
281162306a36Sopenharmony_ci	c4iw_put_wr_wait(srq->wr_waitp);
281262306a36Sopenharmony_ci	return 0;
281362306a36Sopenharmony_ci}
2814