162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2012 - 2019 Intel Corporation.  All rights reserved.
362306a36Sopenharmony_ci * Copyright (c) 2006 - 2012 QLogic Corporation.  * All rights reserved.
462306a36Sopenharmony_ci * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This software is available to you under a choice of one of two
762306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
1062306a36Sopenharmony_ci * OpenIB.org BSD license below:
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1362306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1462306a36Sopenharmony_ci *     conditions are met:
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1762306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1862306a36Sopenharmony_ci *        disclaimer.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
2162306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2262306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2362306a36Sopenharmony_ci *        provided with the distribution.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3262306a36Sopenharmony_ci * SOFTWARE.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include <linux/err.h>
3662306a36Sopenharmony_ci#include <linux/vmalloc.h>
3762306a36Sopenharmony_ci#include <rdma/rdma_vt.h>
3862306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
3962306a36Sopenharmony_ci#include <linux/seq_file.h>
4062306a36Sopenharmony_ci#endif
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#include "qib.h"
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic inline unsigned mk_qpn(struct rvt_qpn_table *qpt,
4562306a36Sopenharmony_ci			      struct rvt_qpn_map *map, unsigned off)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	return (map - qpt->map) * RVT_BITS_PER_PAGE + off;
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic inline unsigned find_next_offset(struct rvt_qpn_table *qpt,
5162306a36Sopenharmony_ci					struct rvt_qpn_map *map, unsigned off,
5262306a36Sopenharmony_ci					unsigned n, u16 qpt_mask)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	if (qpt_mask) {
5562306a36Sopenharmony_ci		off++;
5662306a36Sopenharmony_ci		if (((off & qpt_mask) >> 1) >= n)
5762306a36Sopenharmony_ci			off = (off | qpt_mask) + 2;
5862306a36Sopenharmony_ci	} else {
5962306a36Sopenharmony_ci		off = find_next_zero_bit(map->page, RVT_BITS_PER_PAGE, off);
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci	return off;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ciconst struct rvt_operation_params qib_post_parms[RVT_OPERATION_MAX] = {
6562306a36Sopenharmony_ci[IB_WR_RDMA_WRITE] = {
6662306a36Sopenharmony_ci	.length = sizeof(struct ib_rdma_wr),
6762306a36Sopenharmony_ci	.qpt_support = BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
6862306a36Sopenharmony_ci},
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci[IB_WR_RDMA_READ] = {
7162306a36Sopenharmony_ci	.length = sizeof(struct ib_rdma_wr),
7262306a36Sopenharmony_ci	.qpt_support = BIT(IB_QPT_RC),
7362306a36Sopenharmony_ci	.flags = RVT_OPERATION_ATOMIC,
7462306a36Sopenharmony_ci},
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci[IB_WR_ATOMIC_CMP_AND_SWP] = {
7762306a36Sopenharmony_ci	.length = sizeof(struct ib_atomic_wr),
7862306a36Sopenharmony_ci	.qpt_support = BIT(IB_QPT_RC),
7962306a36Sopenharmony_ci	.flags = RVT_OPERATION_ATOMIC | RVT_OPERATION_ATOMIC_SGE,
8062306a36Sopenharmony_ci},
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci[IB_WR_ATOMIC_FETCH_AND_ADD] = {
8362306a36Sopenharmony_ci	.length = sizeof(struct ib_atomic_wr),
8462306a36Sopenharmony_ci	.qpt_support = BIT(IB_QPT_RC),
8562306a36Sopenharmony_ci	.flags = RVT_OPERATION_ATOMIC | RVT_OPERATION_ATOMIC_SGE,
8662306a36Sopenharmony_ci},
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci[IB_WR_RDMA_WRITE_WITH_IMM] = {
8962306a36Sopenharmony_ci	.length = sizeof(struct ib_rdma_wr),
9062306a36Sopenharmony_ci	.qpt_support = BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
9162306a36Sopenharmony_ci},
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci[IB_WR_SEND] = {
9462306a36Sopenharmony_ci	.length = sizeof(struct ib_send_wr),
9562306a36Sopenharmony_ci	.qpt_support = BIT(IB_QPT_UD) | BIT(IB_QPT_SMI) | BIT(IB_QPT_GSI) |
9662306a36Sopenharmony_ci		       BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
9762306a36Sopenharmony_ci},
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci[IB_WR_SEND_WITH_IMM] = {
10062306a36Sopenharmony_ci	.length = sizeof(struct ib_send_wr),
10162306a36Sopenharmony_ci	.qpt_support = BIT(IB_QPT_UD) | BIT(IB_QPT_SMI) | BIT(IB_QPT_GSI) |
10262306a36Sopenharmony_ci		       BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
10362306a36Sopenharmony_ci},
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic void get_map_page(struct rvt_qpn_table *qpt, struct rvt_qpn_map *map)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	unsigned long page = get_zeroed_page(GFP_KERNEL);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/*
11262306a36Sopenharmony_ci	 * Free the page if someone raced with us installing it.
11362306a36Sopenharmony_ci	 */
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	spin_lock(&qpt->lock);
11662306a36Sopenharmony_ci	if (map->page)
11762306a36Sopenharmony_ci		free_page(page);
11862306a36Sopenharmony_ci	else
11962306a36Sopenharmony_ci		map->page = (void *)page;
12062306a36Sopenharmony_ci	spin_unlock(&qpt->lock);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/*
12462306a36Sopenharmony_ci * Allocate the next available QPN or
12562306a36Sopenharmony_ci * zero/one for QP type IB_QPT_SMI/IB_QPT_GSI.
12662306a36Sopenharmony_ci */
12762306a36Sopenharmony_ciint qib_alloc_qpn(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt,
12862306a36Sopenharmony_ci		  enum ib_qp_type type, u32 port)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	u32 i, offset, max_scan, qpn;
13162306a36Sopenharmony_ci	struct rvt_qpn_map *map;
13262306a36Sopenharmony_ci	u32 ret;
13362306a36Sopenharmony_ci	struct qib_ibdev *verbs_dev = container_of(rdi, struct qib_ibdev, rdi);
13462306a36Sopenharmony_ci	struct qib_devdata *dd = container_of(verbs_dev, struct qib_devdata,
13562306a36Sopenharmony_ci					      verbs_dev);
13662306a36Sopenharmony_ci	u16 qpt_mask = dd->qpn_mask;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	if (type == IB_QPT_SMI || type == IB_QPT_GSI) {
13962306a36Sopenharmony_ci		u32 n;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci		ret = type == IB_QPT_GSI;
14262306a36Sopenharmony_ci		n = 1 << (ret + 2 * (port - 1));
14362306a36Sopenharmony_ci		spin_lock(&qpt->lock);
14462306a36Sopenharmony_ci		if (qpt->flags & n)
14562306a36Sopenharmony_ci			ret = -EINVAL;
14662306a36Sopenharmony_ci		else
14762306a36Sopenharmony_ci			qpt->flags |= n;
14862306a36Sopenharmony_ci		spin_unlock(&qpt->lock);
14962306a36Sopenharmony_ci		goto bail;
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	qpn = qpt->last + 2;
15362306a36Sopenharmony_ci	if (qpn >= RVT_QPN_MAX)
15462306a36Sopenharmony_ci		qpn = 2;
15562306a36Sopenharmony_ci	if (qpt_mask && ((qpn & qpt_mask) >> 1) >= dd->n_krcv_queues)
15662306a36Sopenharmony_ci		qpn = (qpn | qpt_mask) + 2;
15762306a36Sopenharmony_ci	offset = qpn & RVT_BITS_PER_PAGE_MASK;
15862306a36Sopenharmony_ci	map = &qpt->map[qpn / RVT_BITS_PER_PAGE];
15962306a36Sopenharmony_ci	max_scan = qpt->nmaps - !offset;
16062306a36Sopenharmony_ci	for (i = 0;;) {
16162306a36Sopenharmony_ci		if (unlikely(!map->page)) {
16262306a36Sopenharmony_ci			get_map_page(qpt, map);
16362306a36Sopenharmony_ci			if (unlikely(!map->page))
16462306a36Sopenharmony_ci				break;
16562306a36Sopenharmony_ci		}
16662306a36Sopenharmony_ci		do {
16762306a36Sopenharmony_ci			if (!test_and_set_bit(offset, map->page)) {
16862306a36Sopenharmony_ci				qpt->last = qpn;
16962306a36Sopenharmony_ci				ret = qpn;
17062306a36Sopenharmony_ci				goto bail;
17162306a36Sopenharmony_ci			}
17262306a36Sopenharmony_ci			offset = find_next_offset(qpt, map, offset,
17362306a36Sopenharmony_ci				dd->n_krcv_queues, qpt_mask);
17462306a36Sopenharmony_ci			qpn = mk_qpn(qpt, map, offset);
17562306a36Sopenharmony_ci			/*
17662306a36Sopenharmony_ci			 * This test differs from alloc_pidmap().
17762306a36Sopenharmony_ci			 * If find_next_offset() does find a zero
17862306a36Sopenharmony_ci			 * bit, we don't need to check for QPN
17962306a36Sopenharmony_ci			 * wrapping around past our starting QPN.
18062306a36Sopenharmony_ci			 * We just need to be sure we don't loop
18162306a36Sopenharmony_ci			 * forever.
18262306a36Sopenharmony_ci			 */
18362306a36Sopenharmony_ci		} while (offset < RVT_BITS_PER_PAGE && qpn < RVT_QPN_MAX);
18462306a36Sopenharmony_ci		/*
18562306a36Sopenharmony_ci		 * In order to keep the number of pages allocated to a
18662306a36Sopenharmony_ci		 * minimum, we scan the all existing pages before increasing
18762306a36Sopenharmony_ci		 * the size of the bitmap table.
18862306a36Sopenharmony_ci		 */
18962306a36Sopenharmony_ci		if (++i > max_scan) {
19062306a36Sopenharmony_ci			if (qpt->nmaps == RVT_QPNMAP_ENTRIES)
19162306a36Sopenharmony_ci				break;
19262306a36Sopenharmony_ci			map = &qpt->map[qpt->nmaps++];
19362306a36Sopenharmony_ci			offset = 0;
19462306a36Sopenharmony_ci		} else if (map < &qpt->map[qpt->nmaps]) {
19562306a36Sopenharmony_ci			++map;
19662306a36Sopenharmony_ci			offset = 0;
19762306a36Sopenharmony_ci		} else {
19862306a36Sopenharmony_ci			map = &qpt->map[0];
19962306a36Sopenharmony_ci			offset = 2;
20062306a36Sopenharmony_ci		}
20162306a36Sopenharmony_ci		qpn = mk_qpn(qpt, map, offset);
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	ret = -ENOMEM;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cibail:
20762306a36Sopenharmony_ci	return ret;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci/*
21162306a36Sopenharmony_ci * qib_free_all_qps - check for QPs still in use
21262306a36Sopenharmony_ci */
21362306a36Sopenharmony_ciunsigned qib_free_all_qps(struct rvt_dev_info *rdi)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	struct qib_ibdev *verbs_dev = container_of(rdi, struct qib_ibdev, rdi);
21662306a36Sopenharmony_ci	struct qib_devdata *dd = container_of(verbs_dev, struct qib_devdata,
21762306a36Sopenharmony_ci					      verbs_dev);
21862306a36Sopenharmony_ci	unsigned n, qp_inuse = 0;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	for (n = 0; n < dd->num_pports; n++) {
22162306a36Sopenharmony_ci		struct qib_ibport *ibp = &dd->pport[n].ibport_data;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci		rcu_read_lock();
22462306a36Sopenharmony_ci		if (rcu_dereference(ibp->rvp.qp[0]))
22562306a36Sopenharmony_ci			qp_inuse++;
22662306a36Sopenharmony_ci		if (rcu_dereference(ibp->rvp.qp[1]))
22762306a36Sopenharmony_ci			qp_inuse++;
22862306a36Sopenharmony_ci		rcu_read_unlock();
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci	return qp_inuse;
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_civoid qib_notify_qp_reset(struct rvt_qp *qp)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	struct qib_qp_priv *priv = qp->priv;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	atomic_set(&priv->s_dma_busy, 0);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_civoid qib_notify_error_qp(struct rvt_qp *qp)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct qib_qp_priv *priv = qp->priv;
24362306a36Sopenharmony_ci	struct qib_ibdev *dev = to_idev(qp->ibqp.device);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	spin_lock(&dev->rdi.pending_lock);
24662306a36Sopenharmony_ci	if (!list_empty(&priv->iowait) && !(qp->s_flags & RVT_S_BUSY)) {
24762306a36Sopenharmony_ci		qp->s_flags &= ~RVT_S_ANY_WAIT_IO;
24862306a36Sopenharmony_ci		list_del_init(&priv->iowait);
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci	spin_unlock(&dev->rdi.pending_lock);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if (!(qp->s_flags & RVT_S_BUSY)) {
25362306a36Sopenharmony_ci		qp->s_hdrwords = 0;
25462306a36Sopenharmony_ci		if (qp->s_rdma_mr) {
25562306a36Sopenharmony_ci			rvt_put_mr(qp->s_rdma_mr);
25662306a36Sopenharmony_ci			qp->s_rdma_mr = NULL;
25762306a36Sopenharmony_ci		}
25862306a36Sopenharmony_ci		if (priv->s_tx) {
25962306a36Sopenharmony_ci			qib_put_txreq(priv->s_tx);
26062306a36Sopenharmony_ci			priv->s_tx = NULL;
26162306a36Sopenharmony_ci		}
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic int mtu_to_enum(u32 mtu)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	int enum_mtu;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	switch (mtu) {
27062306a36Sopenharmony_ci	case 4096:
27162306a36Sopenharmony_ci		enum_mtu = IB_MTU_4096;
27262306a36Sopenharmony_ci		break;
27362306a36Sopenharmony_ci	case 2048:
27462306a36Sopenharmony_ci		enum_mtu = IB_MTU_2048;
27562306a36Sopenharmony_ci		break;
27662306a36Sopenharmony_ci	case 1024:
27762306a36Sopenharmony_ci		enum_mtu = IB_MTU_1024;
27862306a36Sopenharmony_ci		break;
27962306a36Sopenharmony_ci	case 512:
28062306a36Sopenharmony_ci		enum_mtu = IB_MTU_512;
28162306a36Sopenharmony_ci		break;
28262306a36Sopenharmony_ci	case 256:
28362306a36Sopenharmony_ci		enum_mtu = IB_MTU_256;
28462306a36Sopenharmony_ci		break;
28562306a36Sopenharmony_ci	default:
28662306a36Sopenharmony_ci		enum_mtu = IB_MTU_2048;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci	return enum_mtu;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ciint qib_get_pmtu_from_attr(struct rvt_dev_info *rdi, struct rvt_qp *qp,
29262306a36Sopenharmony_ci			   struct ib_qp_attr *attr)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	int mtu, pmtu, pidx = qp->port_num - 1;
29562306a36Sopenharmony_ci	struct qib_ibdev *verbs_dev = container_of(rdi, struct qib_ibdev, rdi);
29662306a36Sopenharmony_ci	struct qib_devdata *dd = container_of(verbs_dev, struct qib_devdata,
29762306a36Sopenharmony_ci					      verbs_dev);
29862306a36Sopenharmony_ci	mtu = ib_mtu_enum_to_int(attr->path_mtu);
29962306a36Sopenharmony_ci	if (mtu == -1)
30062306a36Sopenharmony_ci		return -EINVAL;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (mtu > dd->pport[pidx].ibmtu)
30362306a36Sopenharmony_ci		pmtu = mtu_to_enum(dd->pport[pidx].ibmtu);
30462306a36Sopenharmony_ci	else
30562306a36Sopenharmony_ci		pmtu = attr->path_mtu;
30662306a36Sopenharmony_ci	return pmtu;
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ciint qib_mtu_to_path_mtu(u32 mtu)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	return mtu_to_enum(mtu);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ciu32 qib_mtu_from_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp, u32 pmtu)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	return ib_mtu_enum_to_int(pmtu);
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_civoid *qib_qp_priv_alloc(struct rvt_dev_info *rdi, struct rvt_qp *qp)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	struct qib_qp_priv *priv;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
32462306a36Sopenharmony_ci	if (!priv)
32562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
32662306a36Sopenharmony_ci	priv->owner = qp;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	priv->s_hdr = kzalloc(sizeof(*priv->s_hdr), GFP_KERNEL);
32962306a36Sopenharmony_ci	if (!priv->s_hdr) {
33062306a36Sopenharmony_ci		kfree(priv);
33162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci	init_waitqueue_head(&priv->wait_dma);
33462306a36Sopenharmony_ci	INIT_WORK(&priv->s_work, _qib_do_send);
33562306a36Sopenharmony_ci	INIT_LIST_HEAD(&priv->iowait);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	return priv;
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_civoid qib_qp_priv_free(struct rvt_dev_info *rdi, struct rvt_qp *qp)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	struct qib_qp_priv *priv = qp->priv;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	kfree(priv->s_hdr);
34562306a36Sopenharmony_ci	kfree(priv);
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_civoid qib_stop_send_queue(struct rvt_qp *qp)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	struct qib_qp_priv *priv = qp->priv;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	cancel_work_sync(&priv->s_work);
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_civoid qib_quiesce_qp(struct rvt_qp *qp)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct qib_qp_priv *priv = qp->priv;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	wait_event(priv->wait_dma, !atomic_read(&priv->s_dma_busy));
36062306a36Sopenharmony_ci	if (priv->s_tx) {
36162306a36Sopenharmony_ci		qib_put_txreq(priv->s_tx);
36262306a36Sopenharmony_ci		priv->s_tx = NULL;
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_civoid qib_flush_qp_waiters(struct rvt_qp *qp)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct qib_qp_priv *priv = qp->priv;
36962306a36Sopenharmony_ci	struct qib_ibdev *dev = to_idev(qp->ibqp.device);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	spin_lock(&dev->rdi.pending_lock);
37262306a36Sopenharmony_ci	if (!list_empty(&priv->iowait))
37362306a36Sopenharmony_ci		list_del_init(&priv->iowait);
37462306a36Sopenharmony_ci	spin_unlock(&dev->rdi.pending_lock);
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci/**
37862306a36Sopenharmony_ci * qib_check_send_wqe - validate wr/wqe
37962306a36Sopenharmony_ci * @qp: The qp
38062306a36Sopenharmony_ci * @wqe: The built wqe
38162306a36Sopenharmony_ci * @call_send: Determine if the send should be posted or scheduled
38262306a36Sopenharmony_ci *
38362306a36Sopenharmony_ci * Returns 0 on success, -EINVAL on failure
38462306a36Sopenharmony_ci */
38562306a36Sopenharmony_ciint qib_check_send_wqe(struct rvt_qp *qp,
38662306a36Sopenharmony_ci		       struct rvt_swqe *wqe, bool *call_send)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	struct rvt_ah *ah;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	switch (qp->ibqp.qp_type) {
39162306a36Sopenharmony_ci	case IB_QPT_RC:
39262306a36Sopenharmony_ci	case IB_QPT_UC:
39362306a36Sopenharmony_ci		if (wqe->length > 0x80000000U)
39462306a36Sopenharmony_ci			return -EINVAL;
39562306a36Sopenharmony_ci		if (wqe->length > qp->pmtu)
39662306a36Sopenharmony_ci			*call_send = false;
39762306a36Sopenharmony_ci		break;
39862306a36Sopenharmony_ci	case IB_QPT_SMI:
39962306a36Sopenharmony_ci	case IB_QPT_GSI:
40062306a36Sopenharmony_ci	case IB_QPT_UD:
40162306a36Sopenharmony_ci		ah = rvt_get_swqe_ah(wqe);
40262306a36Sopenharmony_ci		if (wqe->length > (1 << ah->log_pmtu))
40362306a36Sopenharmony_ci			return -EINVAL;
40462306a36Sopenharmony_ci		/* progress hint */
40562306a36Sopenharmony_ci		*call_send = true;
40662306a36Sopenharmony_ci		break;
40762306a36Sopenharmony_ci	default:
40862306a36Sopenharmony_ci		break;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci	return 0;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic const char * const qp_type_str[] = {
41662306a36Sopenharmony_ci	"SMI", "GSI", "RC", "UC", "UD",
41762306a36Sopenharmony_ci};
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci/**
42062306a36Sopenharmony_ci * qib_qp_iter_print - print information to seq_file
42162306a36Sopenharmony_ci * @s: the seq_file
42262306a36Sopenharmony_ci * @iter: the iterator
42362306a36Sopenharmony_ci */
42462306a36Sopenharmony_civoid qib_qp_iter_print(struct seq_file *s, struct rvt_qp_iter *iter)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	struct rvt_swqe *wqe;
42762306a36Sopenharmony_ci	struct rvt_qp *qp = iter->qp;
42862306a36Sopenharmony_ci	struct qib_qp_priv *priv = qp->priv;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	wqe = rvt_get_swqe_ptr(qp, qp->s_last);
43162306a36Sopenharmony_ci	seq_printf(s,
43262306a36Sopenharmony_ci		   "N %d QP%u %s %u %u %u f=%x %u %u %u %u %u PSN %x %x %x %x %x (%u %u %u %u %u %u) QP%u LID %x\n",
43362306a36Sopenharmony_ci		   iter->n,
43462306a36Sopenharmony_ci		   qp->ibqp.qp_num,
43562306a36Sopenharmony_ci		   qp_type_str[qp->ibqp.qp_type],
43662306a36Sopenharmony_ci		   qp->state,
43762306a36Sopenharmony_ci		   wqe->wr.opcode,
43862306a36Sopenharmony_ci		   qp->s_hdrwords,
43962306a36Sopenharmony_ci		   qp->s_flags,
44062306a36Sopenharmony_ci		   atomic_read(&priv->s_dma_busy),
44162306a36Sopenharmony_ci		   !list_empty(&priv->iowait),
44262306a36Sopenharmony_ci		   qp->timeout,
44362306a36Sopenharmony_ci		   wqe->ssn,
44462306a36Sopenharmony_ci		   qp->s_lsn,
44562306a36Sopenharmony_ci		   qp->s_last_psn,
44662306a36Sopenharmony_ci		   qp->s_psn, qp->s_next_psn,
44762306a36Sopenharmony_ci		   qp->s_sending_psn, qp->s_sending_hpsn,
44862306a36Sopenharmony_ci		   qp->s_last, qp->s_acked, qp->s_cur,
44962306a36Sopenharmony_ci		   qp->s_tail, qp->s_head, qp->s_size,
45062306a36Sopenharmony_ci		   qp->remote_qpn,
45162306a36Sopenharmony_ci		   rdma_ah_get_dlid(&qp->remote_ah_attr));
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci#endif
455