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