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