18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2012 - 2019 Intel Corporation.  All rights reserved.
38c2ecf20Sopenharmony_ci * Copyright (c) 2006 - 2012 QLogic Corporation.  * All rights reserved.
48c2ecf20Sopenharmony_ci * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
78c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
88c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
98c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
108c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
138c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
148c2ecf20Sopenharmony_ci *     conditions are met:
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
178c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
188c2ecf20Sopenharmony_ci *        disclaimer.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
218c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
228c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
238c2ecf20Sopenharmony_ci *        provided with the distribution.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
268c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
278c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
288c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
298c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
308c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
318c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
328c2ecf20Sopenharmony_ci * SOFTWARE.
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <linux/err.h>
368c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
378c2ecf20Sopenharmony_ci#include <rdma/rdma_vt.h>
388c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
398c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
408c2ecf20Sopenharmony_ci#endif
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#include "qib.h"
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic inline unsigned mk_qpn(struct rvt_qpn_table *qpt,
458c2ecf20Sopenharmony_ci			      struct rvt_qpn_map *map, unsigned off)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	return (map - qpt->map) * RVT_BITS_PER_PAGE + off;
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic inline unsigned find_next_offset(struct rvt_qpn_table *qpt,
518c2ecf20Sopenharmony_ci					struct rvt_qpn_map *map, unsigned off,
528c2ecf20Sopenharmony_ci					unsigned n, u16 qpt_mask)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	if (qpt_mask) {
558c2ecf20Sopenharmony_ci		off++;
568c2ecf20Sopenharmony_ci		if (((off & qpt_mask) >> 1) >= n)
578c2ecf20Sopenharmony_ci			off = (off | qpt_mask) + 2;
588c2ecf20Sopenharmony_ci	} else {
598c2ecf20Sopenharmony_ci		off = find_next_zero_bit(map->page, RVT_BITS_PER_PAGE, off);
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci	return off;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ciconst struct rvt_operation_params qib_post_parms[RVT_OPERATION_MAX] = {
658c2ecf20Sopenharmony_ci[IB_WR_RDMA_WRITE] = {
668c2ecf20Sopenharmony_ci	.length = sizeof(struct ib_rdma_wr),
678c2ecf20Sopenharmony_ci	.qpt_support = BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
688c2ecf20Sopenharmony_ci},
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci[IB_WR_RDMA_READ] = {
718c2ecf20Sopenharmony_ci	.length = sizeof(struct ib_rdma_wr),
728c2ecf20Sopenharmony_ci	.qpt_support = BIT(IB_QPT_RC),
738c2ecf20Sopenharmony_ci	.flags = RVT_OPERATION_ATOMIC,
748c2ecf20Sopenharmony_ci},
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci[IB_WR_ATOMIC_CMP_AND_SWP] = {
778c2ecf20Sopenharmony_ci	.length = sizeof(struct ib_atomic_wr),
788c2ecf20Sopenharmony_ci	.qpt_support = BIT(IB_QPT_RC),
798c2ecf20Sopenharmony_ci	.flags = RVT_OPERATION_ATOMIC | RVT_OPERATION_ATOMIC_SGE,
808c2ecf20Sopenharmony_ci},
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci[IB_WR_ATOMIC_FETCH_AND_ADD] = {
838c2ecf20Sopenharmony_ci	.length = sizeof(struct ib_atomic_wr),
848c2ecf20Sopenharmony_ci	.qpt_support = BIT(IB_QPT_RC),
858c2ecf20Sopenharmony_ci	.flags = RVT_OPERATION_ATOMIC | RVT_OPERATION_ATOMIC_SGE,
868c2ecf20Sopenharmony_ci},
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci[IB_WR_RDMA_WRITE_WITH_IMM] = {
898c2ecf20Sopenharmony_ci	.length = sizeof(struct ib_rdma_wr),
908c2ecf20Sopenharmony_ci	.qpt_support = BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
918c2ecf20Sopenharmony_ci},
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci[IB_WR_SEND] = {
948c2ecf20Sopenharmony_ci	.length = sizeof(struct ib_send_wr),
958c2ecf20Sopenharmony_ci	.qpt_support = BIT(IB_QPT_UD) | BIT(IB_QPT_SMI) | BIT(IB_QPT_GSI) |
968c2ecf20Sopenharmony_ci		       BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
978c2ecf20Sopenharmony_ci},
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci[IB_WR_SEND_WITH_IMM] = {
1008c2ecf20Sopenharmony_ci	.length = sizeof(struct ib_send_wr),
1018c2ecf20Sopenharmony_ci	.qpt_support = BIT(IB_QPT_UD) | BIT(IB_QPT_SMI) | BIT(IB_QPT_GSI) |
1028c2ecf20Sopenharmony_ci		       BIT(IB_QPT_UC) | BIT(IB_QPT_RC),
1038c2ecf20Sopenharmony_ci},
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci};
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic void get_map_page(struct rvt_qpn_table *qpt, struct rvt_qpn_map *map)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	unsigned long page = get_zeroed_page(GFP_KERNEL);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/*
1128c2ecf20Sopenharmony_ci	 * Free the page if someone raced with us installing it.
1138c2ecf20Sopenharmony_ci	 */
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	spin_lock(&qpt->lock);
1168c2ecf20Sopenharmony_ci	if (map->page)
1178c2ecf20Sopenharmony_ci		free_page(page);
1188c2ecf20Sopenharmony_ci	else
1198c2ecf20Sopenharmony_ci		map->page = (void *)page;
1208c2ecf20Sopenharmony_ci	spin_unlock(&qpt->lock);
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci/*
1248c2ecf20Sopenharmony_ci * Allocate the next available QPN or
1258c2ecf20Sopenharmony_ci * zero/one for QP type IB_QPT_SMI/IB_QPT_GSI.
1268c2ecf20Sopenharmony_ci */
1278c2ecf20Sopenharmony_ciint qib_alloc_qpn(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt,
1288c2ecf20Sopenharmony_ci		  enum ib_qp_type type, u8 port)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	u32 i, offset, max_scan, qpn;
1318c2ecf20Sopenharmony_ci	struct rvt_qpn_map *map;
1328c2ecf20Sopenharmony_ci	u32 ret;
1338c2ecf20Sopenharmony_ci	struct qib_ibdev *verbs_dev = container_of(rdi, struct qib_ibdev, rdi);
1348c2ecf20Sopenharmony_ci	struct qib_devdata *dd = container_of(verbs_dev, struct qib_devdata,
1358c2ecf20Sopenharmony_ci					      verbs_dev);
1368c2ecf20Sopenharmony_ci	u16 qpt_mask = dd->qpn_mask;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	if (type == IB_QPT_SMI || type == IB_QPT_GSI) {
1398c2ecf20Sopenharmony_ci		unsigned n;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci		ret = type == IB_QPT_GSI;
1428c2ecf20Sopenharmony_ci		n = 1 << (ret + 2 * (port - 1));
1438c2ecf20Sopenharmony_ci		spin_lock(&qpt->lock);
1448c2ecf20Sopenharmony_ci		if (qpt->flags & n)
1458c2ecf20Sopenharmony_ci			ret = -EINVAL;
1468c2ecf20Sopenharmony_ci		else
1478c2ecf20Sopenharmony_ci			qpt->flags |= n;
1488c2ecf20Sopenharmony_ci		spin_unlock(&qpt->lock);
1498c2ecf20Sopenharmony_ci		goto bail;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	qpn = qpt->last + 2;
1538c2ecf20Sopenharmony_ci	if (qpn >= RVT_QPN_MAX)
1548c2ecf20Sopenharmony_ci		qpn = 2;
1558c2ecf20Sopenharmony_ci	if (qpt_mask && ((qpn & qpt_mask) >> 1) >= dd->n_krcv_queues)
1568c2ecf20Sopenharmony_ci		qpn = (qpn | qpt_mask) + 2;
1578c2ecf20Sopenharmony_ci	offset = qpn & RVT_BITS_PER_PAGE_MASK;
1588c2ecf20Sopenharmony_ci	map = &qpt->map[qpn / RVT_BITS_PER_PAGE];
1598c2ecf20Sopenharmony_ci	max_scan = qpt->nmaps - !offset;
1608c2ecf20Sopenharmony_ci	for (i = 0;;) {
1618c2ecf20Sopenharmony_ci		if (unlikely(!map->page)) {
1628c2ecf20Sopenharmony_ci			get_map_page(qpt, map);
1638c2ecf20Sopenharmony_ci			if (unlikely(!map->page))
1648c2ecf20Sopenharmony_ci				break;
1658c2ecf20Sopenharmony_ci		}
1668c2ecf20Sopenharmony_ci		do {
1678c2ecf20Sopenharmony_ci			if (!test_and_set_bit(offset, map->page)) {
1688c2ecf20Sopenharmony_ci				qpt->last = qpn;
1698c2ecf20Sopenharmony_ci				ret = qpn;
1708c2ecf20Sopenharmony_ci				goto bail;
1718c2ecf20Sopenharmony_ci			}
1728c2ecf20Sopenharmony_ci			offset = find_next_offset(qpt, map, offset,
1738c2ecf20Sopenharmony_ci				dd->n_krcv_queues, qpt_mask);
1748c2ecf20Sopenharmony_ci			qpn = mk_qpn(qpt, map, offset);
1758c2ecf20Sopenharmony_ci			/*
1768c2ecf20Sopenharmony_ci			 * This test differs from alloc_pidmap().
1778c2ecf20Sopenharmony_ci			 * If find_next_offset() does find a zero
1788c2ecf20Sopenharmony_ci			 * bit, we don't need to check for QPN
1798c2ecf20Sopenharmony_ci			 * wrapping around past our starting QPN.
1808c2ecf20Sopenharmony_ci			 * We just need to be sure we don't loop
1818c2ecf20Sopenharmony_ci			 * forever.
1828c2ecf20Sopenharmony_ci			 */
1838c2ecf20Sopenharmony_ci		} while (offset < RVT_BITS_PER_PAGE && qpn < RVT_QPN_MAX);
1848c2ecf20Sopenharmony_ci		/*
1858c2ecf20Sopenharmony_ci		 * In order to keep the number of pages allocated to a
1868c2ecf20Sopenharmony_ci		 * minimum, we scan the all existing pages before increasing
1878c2ecf20Sopenharmony_ci		 * the size of the bitmap table.
1888c2ecf20Sopenharmony_ci		 */
1898c2ecf20Sopenharmony_ci		if (++i > max_scan) {
1908c2ecf20Sopenharmony_ci			if (qpt->nmaps == RVT_QPNMAP_ENTRIES)
1918c2ecf20Sopenharmony_ci				break;
1928c2ecf20Sopenharmony_ci			map = &qpt->map[qpt->nmaps++];
1938c2ecf20Sopenharmony_ci			offset = 0;
1948c2ecf20Sopenharmony_ci		} else if (map < &qpt->map[qpt->nmaps]) {
1958c2ecf20Sopenharmony_ci			++map;
1968c2ecf20Sopenharmony_ci			offset = 0;
1978c2ecf20Sopenharmony_ci		} else {
1988c2ecf20Sopenharmony_ci			map = &qpt->map[0];
1998c2ecf20Sopenharmony_ci			offset = 2;
2008c2ecf20Sopenharmony_ci		}
2018c2ecf20Sopenharmony_ci		qpn = mk_qpn(qpt, map, offset);
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	ret = -ENOMEM;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cibail:
2078c2ecf20Sopenharmony_ci	return ret;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci/**
2118c2ecf20Sopenharmony_ci * qib_free_all_qps - check for QPs still in use
2128c2ecf20Sopenharmony_ci */
2138c2ecf20Sopenharmony_ciunsigned qib_free_all_qps(struct rvt_dev_info *rdi)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	struct qib_ibdev *verbs_dev = container_of(rdi, struct qib_ibdev, rdi);
2168c2ecf20Sopenharmony_ci	struct qib_devdata *dd = container_of(verbs_dev, struct qib_devdata,
2178c2ecf20Sopenharmony_ci					      verbs_dev);
2188c2ecf20Sopenharmony_ci	unsigned n, qp_inuse = 0;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	for (n = 0; n < dd->num_pports; n++) {
2218c2ecf20Sopenharmony_ci		struct qib_ibport *ibp = &dd->pport[n].ibport_data;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		rcu_read_lock();
2248c2ecf20Sopenharmony_ci		if (rcu_dereference(ibp->rvp.qp[0]))
2258c2ecf20Sopenharmony_ci			qp_inuse++;
2268c2ecf20Sopenharmony_ci		if (rcu_dereference(ibp->rvp.qp[1]))
2278c2ecf20Sopenharmony_ci			qp_inuse++;
2288c2ecf20Sopenharmony_ci		rcu_read_unlock();
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci	return qp_inuse;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_civoid qib_notify_qp_reset(struct rvt_qp *qp)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct qib_qp_priv *priv = qp->priv;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	atomic_set(&priv->s_dma_busy, 0);
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_civoid qib_notify_error_qp(struct rvt_qp *qp)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	struct qib_qp_priv *priv = qp->priv;
2438c2ecf20Sopenharmony_ci	struct qib_ibdev *dev = to_idev(qp->ibqp.device);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	spin_lock(&dev->rdi.pending_lock);
2468c2ecf20Sopenharmony_ci	if (!list_empty(&priv->iowait) && !(qp->s_flags & RVT_S_BUSY)) {
2478c2ecf20Sopenharmony_ci		qp->s_flags &= ~RVT_S_ANY_WAIT_IO;
2488c2ecf20Sopenharmony_ci		list_del_init(&priv->iowait);
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci	spin_unlock(&dev->rdi.pending_lock);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	if (!(qp->s_flags & RVT_S_BUSY)) {
2538c2ecf20Sopenharmony_ci		qp->s_hdrwords = 0;
2548c2ecf20Sopenharmony_ci		if (qp->s_rdma_mr) {
2558c2ecf20Sopenharmony_ci			rvt_put_mr(qp->s_rdma_mr);
2568c2ecf20Sopenharmony_ci			qp->s_rdma_mr = NULL;
2578c2ecf20Sopenharmony_ci		}
2588c2ecf20Sopenharmony_ci		if (priv->s_tx) {
2598c2ecf20Sopenharmony_ci			qib_put_txreq(priv->s_tx);
2608c2ecf20Sopenharmony_ci			priv->s_tx = NULL;
2618c2ecf20Sopenharmony_ci		}
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic int mtu_to_enum(u32 mtu)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	int enum_mtu;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	switch (mtu) {
2708c2ecf20Sopenharmony_ci	case 4096:
2718c2ecf20Sopenharmony_ci		enum_mtu = IB_MTU_4096;
2728c2ecf20Sopenharmony_ci		break;
2738c2ecf20Sopenharmony_ci	case 2048:
2748c2ecf20Sopenharmony_ci		enum_mtu = IB_MTU_2048;
2758c2ecf20Sopenharmony_ci		break;
2768c2ecf20Sopenharmony_ci	case 1024:
2778c2ecf20Sopenharmony_ci		enum_mtu = IB_MTU_1024;
2788c2ecf20Sopenharmony_ci		break;
2798c2ecf20Sopenharmony_ci	case 512:
2808c2ecf20Sopenharmony_ci		enum_mtu = IB_MTU_512;
2818c2ecf20Sopenharmony_ci		break;
2828c2ecf20Sopenharmony_ci	case 256:
2838c2ecf20Sopenharmony_ci		enum_mtu = IB_MTU_256;
2848c2ecf20Sopenharmony_ci		break;
2858c2ecf20Sopenharmony_ci	default:
2868c2ecf20Sopenharmony_ci		enum_mtu = IB_MTU_2048;
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci	return enum_mtu;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ciint qib_get_pmtu_from_attr(struct rvt_dev_info *rdi, struct rvt_qp *qp,
2928c2ecf20Sopenharmony_ci			   struct ib_qp_attr *attr)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	int mtu, pmtu, pidx = qp->port_num - 1;
2958c2ecf20Sopenharmony_ci	struct qib_ibdev *verbs_dev = container_of(rdi, struct qib_ibdev, rdi);
2968c2ecf20Sopenharmony_ci	struct qib_devdata *dd = container_of(verbs_dev, struct qib_devdata,
2978c2ecf20Sopenharmony_ci					      verbs_dev);
2988c2ecf20Sopenharmony_ci	mtu = ib_mtu_enum_to_int(attr->path_mtu);
2998c2ecf20Sopenharmony_ci	if (mtu == -1)
3008c2ecf20Sopenharmony_ci		return -EINVAL;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (mtu > dd->pport[pidx].ibmtu)
3038c2ecf20Sopenharmony_ci		pmtu = mtu_to_enum(dd->pport[pidx].ibmtu);
3048c2ecf20Sopenharmony_ci	else
3058c2ecf20Sopenharmony_ci		pmtu = attr->path_mtu;
3068c2ecf20Sopenharmony_ci	return pmtu;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ciint qib_mtu_to_path_mtu(u32 mtu)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	return mtu_to_enum(mtu);
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ciu32 qib_mtu_from_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp, u32 pmtu)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	return ib_mtu_enum_to_int(pmtu);
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_civoid *qib_qp_priv_alloc(struct rvt_dev_info *rdi, struct rvt_qp *qp)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	struct qib_qp_priv *priv;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
3248c2ecf20Sopenharmony_ci	if (!priv)
3258c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
3268c2ecf20Sopenharmony_ci	priv->owner = qp;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	priv->s_hdr = kzalloc(sizeof(*priv->s_hdr), GFP_KERNEL);
3298c2ecf20Sopenharmony_ci	if (!priv->s_hdr) {
3308c2ecf20Sopenharmony_ci		kfree(priv);
3318c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci	init_waitqueue_head(&priv->wait_dma);
3348c2ecf20Sopenharmony_ci	INIT_WORK(&priv->s_work, _qib_do_send);
3358c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&priv->iowait);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	return priv;
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_civoid qib_qp_priv_free(struct rvt_dev_info *rdi, struct rvt_qp *qp)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	struct qib_qp_priv *priv = qp->priv;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	kfree(priv->s_hdr);
3458c2ecf20Sopenharmony_ci	kfree(priv);
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_civoid qib_stop_send_queue(struct rvt_qp *qp)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	struct qib_qp_priv *priv = qp->priv;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	cancel_work_sync(&priv->s_work);
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_civoid qib_quiesce_qp(struct rvt_qp *qp)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	struct qib_qp_priv *priv = qp->priv;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	wait_event(priv->wait_dma, !atomic_read(&priv->s_dma_busy));
3608c2ecf20Sopenharmony_ci	if (priv->s_tx) {
3618c2ecf20Sopenharmony_ci		qib_put_txreq(priv->s_tx);
3628c2ecf20Sopenharmony_ci		priv->s_tx = NULL;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_civoid qib_flush_qp_waiters(struct rvt_qp *qp)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	struct qib_qp_priv *priv = qp->priv;
3698c2ecf20Sopenharmony_ci	struct qib_ibdev *dev = to_idev(qp->ibqp.device);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	spin_lock(&dev->rdi.pending_lock);
3728c2ecf20Sopenharmony_ci	if (!list_empty(&priv->iowait))
3738c2ecf20Sopenharmony_ci		list_del_init(&priv->iowait);
3748c2ecf20Sopenharmony_ci	spin_unlock(&dev->rdi.pending_lock);
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci/**
3788c2ecf20Sopenharmony_ci * qib_check_send_wqe - validate wr/wqe
3798c2ecf20Sopenharmony_ci * @qp - The qp
3808c2ecf20Sopenharmony_ci * @wqe - The built wqe
3818c2ecf20Sopenharmony_ci * @call_send - Determine if the send should be posted or scheduled
3828c2ecf20Sopenharmony_ci *
3838c2ecf20Sopenharmony_ci * Returns 0 on success, -EINVAL on failure
3848c2ecf20Sopenharmony_ci */
3858c2ecf20Sopenharmony_ciint qib_check_send_wqe(struct rvt_qp *qp,
3868c2ecf20Sopenharmony_ci		       struct rvt_swqe *wqe, bool *call_send)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	struct rvt_ah *ah;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	switch (qp->ibqp.qp_type) {
3918c2ecf20Sopenharmony_ci	case IB_QPT_RC:
3928c2ecf20Sopenharmony_ci	case IB_QPT_UC:
3938c2ecf20Sopenharmony_ci		if (wqe->length > 0x80000000U)
3948c2ecf20Sopenharmony_ci			return -EINVAL;
3958c2ecf20Sopenharmony_ci		if (wqe->length > qp->pmtu)
3968c2ecf20Sopenharmony_ci			*call_send = false;
3978c2ecf20Sopenharmony_ci		break;
3988c2ecf20Sopenharmony_ci	case IB_QPT_SMI:
3998c2ecf20Sopenharmony_ci	case IB_QPT_GSI:
4008c2ecf20Sopenharmony_ci	case IB_QPT_UD:
4018c2ecf20Sopenharmony_ci		ah = rvt_get_swqe_ah(wqe);
4028c2ecf20Sopenharmony_ci		if (wqe->length > (1 << ah->log_pmtu))
4038c2ecf20Sopenharmony_ci			return -EINVAL;
4048c2ecf20Sopenharmony_ci		/* progress hint */
4058c2ecf20Sopenharmony_ci		*call_send = true;
4068c2ecf20Sopenharmony_ci		break;
4078c2ecf20Sopenharmony_ci	default:
4088c2ecf20Sopenharmony_ci		break;
4098c2ecf20Sopenharmony_ci	}
4108c2ecf20Sopenharmony_ci	return 0;
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic const char * const qp_type_str[] = {
4168c2ecf20Sopenharmony_ci	"SMI", "GSI", "RC", "UC", "UD",
4178c2ecf20Sopenharmony_ci};
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci/**
4208c2ecf20Sopenharmony_ci * qib_qp_iter_print - print information to seq_file
4218c2ecf20Sopenharmony_ci * @s - the seq_file
4228c2ecf20Sopenharmony_ci * @iter - the iterator
4238c2ecf20Sopenharmony_ci */
4248c2ecf20Sopenharmony_civoid qib_qp_iter_print(struct seq_file *s, struct rvt_qp_iter *iter)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	struct rvt_swqe *wqe;
4278c2ecf20Sopenharmony_ci	struct rvt_qp *qp = iter->qp;
4288c2ecf20Sopenharmony_ci	struct qib_qp_priv *priv = qp->priv;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	wqe = rvt_get_swqe_ptr(qp, qp->s_last);
4318c2ecf20Sopenharmony_ci	seq_printf(s,
4328c2ecf20Sopenharmony_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",
4338c2ecf20Sopenharmony_ci		   iter->n,
4348c2ecf20Sopenharmony_ci		   qp->ibqp.qp_num,
4358c2ecf20Sopenharmony_ci		   qp_type_str[qp->ibqp.qp_type],
4368c2ecf20Sopenharmony_ci		   qp->state,
4378c2ecf20Sopenharmony_ci		   wqe->wr.opcode,
4388c2ecf20Sopenharmony_ci		   qp->s_hdrwords,
4398c2ecf20Sopenharmony_ci		   qp->s_flags,
4408c2ecf20Sopenharmony_ci		   atomic_read(&priv->s_dma_busy),
4418c2ecf20Sopenharmony_ci		   !list_empty(&priv->iowait),
4428c2ecf20Sopenharmony_ci		   qp->timeout,
4438c2ecf20Sopenharmony_ci		   wqe->ssn,
4448c2ecf20Sopenharmony_ci		   qp->s_lsn,
4458c2ecf20Sopenharmony_ci		   qp->s_last_psn,
4468c2ecf20Sopenharmony_ci		   qp->s_psn, qp->s_next_psn,
4478c2ecf20Sopenharmony_ci		   qp->s_sending_psn, qp->s_sending_hpsn,
4488c2ecf20Sopenharmony_ci		   qp->s_last, qp->s_acked, qp->s_cur,
4498c2ecf20Sopenharmony_ci		   qp->s_tail, qp->s_head, qp->s_size,
4508c2ecf20Sopenharmony_ci		   qp->remote_qpn,
4518c2ecf20Sopenharmony_ci		   rdma_ah_get_dlid(&qp->remote_ah_attr));
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci#endif
455