162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/skbuff.h> 862306a36Sopenharmony_ci#include <linux/delay.h> 962306a36Sopenharmony_ci#include <linux/sched.h> 1062306a36Sopenharmony_ci#include <linux/vmalloc.h> 1162306a36Sopenharmony_ci#include <rdma/uverbs_ioctl.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "rxe.h" 1462306a36Sopenharmony_ci#include "rxe_loc.h" 1562306a36Sopenharmony_ci#include "rxe_queue.h" 1662306a36Sopenharmony_ci#include "rxe_task.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic int rxe_qp_chk_cap(struct rxe_dev *rxe, struct ib_qp_cap *cap, 1962306a36Sopenharmony_ci int has_srq) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci if (cap->max_send_wr > rxe->attr.max_qp_wr) { 2262306a36Sopenharmony_ci rxe_dbg_dev(rxe, "invalid send wr = %u > %d\n", 2362306a36Sopenharmony_ci cap->max_send_wr, rxe->attr.max_qp_wr); 2462306a36Sopenharmony_ci goto err1; 2562306a36Sopenharmony_ci } 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci if (cap->max_send_sge > rxe->attr.max_send_sge) { 2862306a36Sopenharmony_ci rxe_dbg_dev(rxe, "invalid send sge = %u > %d\n", 2962306a36Sopenharmony_ci cap->max_send_sge, rxe->attr.max_send_sge); 3062306a36Sopenharmony_ci goto err1; 3162306a36Sopenharmony_ci } 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci if (!has_srq) { 3462306a36Sopenharmony_ci if (cap->max_recv_wr > rxe->attr.max_qp_wr) { 3562306a36Sopenharmony_ci rxe_dbg_dev(rxe, "invalid recv wr = %u > %d\n", 3662306a36Sopenharmony_ci cap->max_recv_wr, rxe->attr.max_qp_wr); 3762306a36Sopenharmony_ci goto err1; 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (cap->max_recv_sge > rxe->attr.max_recv_sge) { 4162306a36Sopenharmony_ci rxe_dbg_dev(rxe, "invalid recv sge = %u > %d\n", 4262306a36Sopenharmony_ci cap->max_recv_sge, rxe->attr.max_recv_sge); 4362306a36Sopenharmony_ci goto err1; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (cap->max_inline_data > rxe->max_inline_data) { 4862306a36Sopenharmony_ci rxe_dbg_dev(rxe, "invalid max inline data = %u > %d\n", 4962306a36Sopenharmony_ci cap->max_inline_data, rxe->max_inline_data); 5062306a36Sopenharmony_ci goto err1; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return 0; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cierr1: 5662306a36Sopenharmony_ci return -EINVAL; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciint rxe_qp_chk_init(struct rxe_dev *rxe, struct ib_qp_init_attr *init) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct ib_qp_cap *cap = &init->cap; 6262306a36Sopenharmony_ci struct rxe_port *port; 6362306a36Sopenharmony_ci int port_num = init->port_num; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci switch (init->qp_type) { 6662306a36Sopenharmony_ci case IB_QPT_GSI: 6762306a36Sopenharmony_ci case IB_QPT_RC: 6862306a36Sopenharmony_ci case IB_QPT_UC: 6962306a36Sopenharmony_ci case IB_QPT_UD: 7062306a36Sopenharmony_ci break; 7162306a36Sopenharmony_ci default: 7262306a36Sopenharmony_ci return -EOPNOTSUPP; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (!init->recv_cq || !init->send_cq) { 7662306a36Sopenharmony_ci rxe_dbg_dev(rxe, "missing cq\n"); 7762306a36Sopenharmony_ci goto err1; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (rxe_qp_chk_cap(rxe, cap, !!init->srq)) 8162306a36Sopenharmony_ci goto err1; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (init->qp_type == IB_QPT_GSI) { 8462306a36Sopenharmony_ci if (!rdma_is_port_valid(&rxe->ib_dev, port_num)) { 8562306a36Sopenharmony_ci rxe_dbg_dev(rxe, "invalid port = %d\n", port_num); 8662306a36Sopenharmony_ci goto err1; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci port = &rxe->port; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (init->qp_type == IB_QPT_GSI && port->qp_gsi_index) { 9262306a36Sopenharmony_ci rxe_dbg_dev(rxe, "GSI QP exists for port %d\n", port_num); 9362306a36Sopenharmony_ci goto err1; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cierr1: 10062306a36Sopenharmony_ci return -EINVAL; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic int alloc_rd_atomic_resources(struct rxe_qp *qp, unsigned int n) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci qp->resp.res_head = 0; 10662306a36Sopenharmony_ci qp->resp.res_tail = 0; 10762306a36Sopenharmony_ci qp->resp.resources = kcalloc(n, sizeof(struct resp_res), GFP_KERNEL); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (!qp->resp.resources) 11062306a36Sopenharmony_ci return -ENOMEM; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return 0; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic void free_rd_atomic_resources(struct rxe_qp *qp) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci if (qp->resp.resources) { 11862306a36Sopenharmony_ci int i; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci for (i = 0; i < qp->attr.max_dest_rd_atomic; i++) { 12162306a36Sopenharmony_ci struct resp_res *res = &qp->resp.resources[i]; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci free_rd_atomic_resource(res); 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci kfree(qp->resp.resources); 12662306a36Sopenharmony_ci qp->resp.resources = NULL; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_civoid free_rd_atomic_resource(struct resp_res *res) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci res->type = 0; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void cleanup_rd_atomic_resources(struct rxe_qp *qp) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci int i; 13862306a36Sopenharmony_ci struct resp_res *res; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (qp->resp.resources) { 14162306a36Sopenharmony_ci for (i = 0; i < qp->attr.max_dest_rd_atomic; i++) { 14262306a36Sopenharmony_ci res = &qp->resp.resources[i]; 14362306a36Sopenharmony_ci free_rd_atomic_resource(res); 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic void rxe_qp_init_misc(struct rxe_dev *rxe, struct rxe_qp *qp, 14962306a36Sopenharmony_ci struct ib_qp_init_attr *init) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct rxe_port *port; 15262306a36Sopenharmony_ci u32 qpn; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci qp->sq_sig_type = init->sq_sig_type; 15562306a36Sopenharmony_ci qp->attr.path_mtu = 1; 15662306a36Sopenharmony_ci qp->mtu = ib_mtu_enum_to_int(qp->attr.path_mtu); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci qpn = qp->elem.index; 15962306a36Sopenharmony_ci port = &rxe->port; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci switch (init->qp_type) { 16262306a36Sopenharmony_ci case IB_QPT_GSI: 16362306a36Sopenharmony_ci qp->ibqp.qp_num = 1; 16462306a36Sopenharmony_ci port->qp_gsi_index = qpn; 16562306a36Sopenharmony_ci qp->attr.port_num = init->port_num; 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci default: 16962306a36Sopenharmony_ci qp->ibqp.qp_num = qpn; 17062306a36Sopenharmony_ci break; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci spin_lock_init(&qp->state_lock); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci spin_lock_init(&qp->sq.sq_lock); 17662306a36Sopenharmony_ci spin_lock_init(&qp->rq.producer_lock); 17762306a36Sopenharmony_ci spin_lock_init(&qp->rq.consumer_lock); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci skb_queue_head_init(&qp->req_pkts); 18062306a36Sopenharmony_ci skb_queue_head_init(&qp->resp_pkts); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci atomic_set(&qp->ssn, 0); 18362306a36Sopenharmony_ci atomic_set(&qp->skb_out, 0); 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic int rxe_init_sq(struct rxe_qp *qp, struct ib_qp_init_attr *init, 18762306a36Sopenharmony_ci struct ib_udata *udata, 18862306a36Sopenharmony_ci struct rxe_create_qp_resp __user *uresp) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(qp->ibqp.device); 19162306a36Sopenharmony_ci int wqe_size; 19262306a36Sopenharmony_ci int err; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci qp->sq.max_wr = init->cap.max_send_wr; 19562306a36Sopenharmony_ci wqe_size = max_t(int, init->cap.max_send_sge * sizeof(struct ib_sge), 19662306a36Sopenharmony_ci init->cap.max_inline_data); 19762306a36Sopenharmony_ci qp->sq.max_sge = wqe_size / sizeof(struct ib_sge); 19862306a36Sopenharmony_ci qp->sq.max_inline = wqe_size; 19962306a36Sopenharmony_ci wqe_size += sizeof(struct rxe_send_wqe); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci qp->sq.queue = rxe_queue_init(rxe, &qp->sq.max_wr, wqe_size, 20262306a36Sopenharmony_ci QUEUE_TYPE_FROM_CLIENT); 20362306a36Sopenharmony_ci if (!qp->sq.queue) { 20462306a36Sopenharmony_ci rxe_err_qp(qp, "Unable to allocate send queue"); 20562306a36Sopenharmony_ci err = -ENOMEM; 20662306a36Sopenharmony_ci goto err_out; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* prepare info for caller to mmap send queue if user space qp */ 21062306a36Sopenharmony_ci err = do_mmap_info(rxe, uresp ? &uresp->sq_mi : NULL, udata, 21162306a36Sopenharmony_ci qp->sq.queue->buf, qp->sq.queue->buf_size, 21262306a36Sopenharmony_ci &qp->sq.queue->ip); 21362306a36Sopenharmony_ci if (err) { 21462306a36Sopenharmony_ci rxe_err_qp(qp, "do_mmap_info failed, err = %d", err); 21562306a36Sopenharmony_ci goto err_free; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* return actual capabilities to caller which may be larger 21962306a36Sopenharmony_ci * than requested 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_ci init->cap.max_send_wr = qp->sq.max_wr; 22262306a36Sopenharmony_ci init->cap.max_send_sge = qp->sq.max_sge; 22362306a36Sopenharmony_ci init->cap.max_inline_data = qp->sq.max_inline; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return 0; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cierr_free: 22862306a36Sopenharmony_ci vfree(qp->sq.queue->buf); 22962306a36Sopenharmony_ci kfree(qp->sq.queue); 23062306a36Sopenharmony_ci qp->sq.queue = NULL; 23162306a36Sopenharmony_cierr_out: 23262306a36Sopenharmony_ci return err; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp, 23662306a36Sopenharmony_ci struct ib_qp_init_attr *init, struct ib_udata *udata, 23762306a36Sopenharmony_ci struct rxe_create_qp_resp __user *uresp) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci int err; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* if we don't finish qp create make sure queue is valid */ 24262306a36Sopenharmony_ci skb_queue_head_init(&qp->req_pkts); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci err = sock_create_kern(&init_net, AF_INET, SOCK_DGRAM, 0, &qp->sk); 24562306a36Sopenharmony_ci if (err < 0) 24662306a36Sopenharmony_ci return err; 24762306a36Sopenharmony_ci qp->sk->sk->sk_user_data = qp; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* pick a source UDP port number for this QP based on 25062306a36Sopenharmony_ci * the source QPN. this spreads traffic for different QPs 25162306a36Sopenharmony_ci * across different NIC RX queues (while using a single 25262306a36Sopenharmony_ci * flow for a given QP to maintain packet order). 25362306a36Sopenharmony_ci * the port number must be in the Dynamic Ports range 25462306a36Sopenharmony_ci * (0xc000 - 0xffff). 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ci qp->src_port = RXE_ROCE_V2_SPORT + (hash_32(qp_num(qp), 14) & 0x3fff); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci err = rxe_init_sq(qp, init, udata, uresp); 25962306a36Sopenharmony_ci if (err) 26062306a36Sopenharmony_ci return err; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci qp->req.wqe_index = queue_get_producer(qp->sq.queue, 26362306a36Sopenharmony_ci QUEUE_TYPE_FROM_CLIENT); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci qp->req.opcode = -1; 26662306a36Sopenharmony_ci qp->comp.opcode = -1; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci rxe_init_task(&qp->req.task, qp, rxe_requester); 26962306a36Sopenharmony_ci rxe_init_task(&qp->comp.task, qp, rxe_completer); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci qp->qp_timeout_jiffies = 0; /* Can't be set for UD/UC in modify_qp */ 27262306a36Sopenharmony_ci if (init->qp_type == IB_QPT_RC) { 27362306a36Sopenharmony_ci timer_setup(&qp->rnr_nak_timer, rnr_nak_timer, 0); 27462306a36Sopenharmony_ci timer_setup(&qp->retrans_timer, retransmit_timer, 0); 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci return 0; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic int rxe_init_rq(struct rxe_qp *qp, struct ib_qp_init_attr *init, 28062306a36Sopenharmony_ci struct ib_udata *udata, 28162306a36Sopenharmony_ci struct rxe_create_qp_resp __user *uresp) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(qp->ibqp.device); 28462306a36Sopenharmony_ci int wqe_size; 28562306a36Sopenharmony_ci int err; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci qp->rq.max_wr = init->cap.max_recv_wr; 28862306a36Sopenharmony_ci qp->rq.max_sge = init->cap.max_recv_sge; 28962306a36Sopenharmony_ci wqe_size = sizeof(struct rxe_recv_wqe) + 29062306a36Sopenharmony_ci qp->rq.max_sge*sizeof(struct ib_sge); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci qp->rq.queue = rxe_queue_init(rxe, &qp->rq.max_wr, wqe_size, 29362306a36Sopenharmony_ci QUEUE_TYPE_FROM_CLIENT); 29462306a36Sopenharmony_ci if (!qp->rq.queue) { 29562306a36Sopenharmony_ci rxe_err_qp(qp, "Unable to allocate recv queue"); 29662306a36Sopenharmony_ci err = -ENOMEM; 29762306a36Sopenharmony_ci goto err_out; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* prepare info for caller to mmap recv queue if user space qp */ 30162306a36Sopenharmony_ci err = do_mmap_info(rxe, uresp ? &uresp->rq_mi : NULL, udata, 30262306a36Sopenharmony_ci qp->rq.queue->buf, qp->rq.queue->buf_size, 30362306a36Sopenharmony_ci &qp->rq.queue->ip); 30462306a36Sopenharmony_ci if (err) { 30562306a36Sopenharmony_ci rxe_err_qp(qp, "do_mmap_info failed, err = %d", err); 30662306a36Sopenharmony_ci goto err_free; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* return actual capabilities to caller which may be larger 31062306a36Sopenharmony_ci * than requested 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_ci init->cap.max_recv_wr = qp->rq.max_wr; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return 0; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cierr_free: 31762306a36Sopenharmony_ci vfree(qp->rq.queue->buf); 31862306a36Sopenharmony_ci kfree(qp->rq.queue); 31962306a36Sopenharmony_ci qp->rq.queue = NULL; 32062306a36Sopenharmony_cierr_out: 32162306a36Sopenharmony_ci return err; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp, 32562306a36Sopenharmony_ci struct ib_qp_init_attr *init, 32662306a36Sopenharmony_ci struct ib_udata *udata, 32762306a36Sopenharmony_ci struct rxe_create_qp_resp __user *uresp) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci int err; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* if we don't finish qp create make sure queue is valid */ 33262306a36Sopenharmony_ci skb_queue_head_init(&qp->resp_pkts); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (!qp->srq) { 33562306a36Sopenharmony_ci err = rxe_init_rq(qp, init, udata, uresp); 33662306a36Sopenharmony_ci if (err) 33762306a36Sopenharmony_ci return err; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci rxe_init_task(&qp->resp.task, qp, rxe_responder); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci qp->resp.opcode = OPCODE_NONE; 34362306a36Sopenharmony_ci qp->resp.msn = 0; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci return 0; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci/* called by the create qp verb */ 34962306a36Sopenharmony_ciint rxe_qp_from_init(struct rxe_dev *rxe, struct rxe_qp *qp, struct rxe_pd *pd, 35062306a36Sopenharmony_ci struct ib_qp_init_attr *init, 35162306a36Sopenharmony_ci struct rxe_create_qp_resp __user *uresp, 35262306a36Sopenharmony_ci struct ib_pd *ibpd, 35362306a36Sopenharmony_ci struct ib_udata *udata) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci int err; 35662306a36Sopenharmony_ci struct rxe_cq *rcq = to_rcq(init->recv_cq); 35762306a36Sopenharmony_ci struct rxe_cq *scq = to_rcq(init->send_cq); 35862306a36Sopenharmony_ci struct rxe_srq *srq = init->srq ? to_rsrq(init->srq) : NULL; 35962306a36Sopenharmony_ci unsigned long flags; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci rxe_get(pd); 36262306a36Sopenharmony_ci rxe_get(rcq); 36362306a36Sopenharmony_ci rxe_get(scq); 36462306a36Sopenharmony_ci if (srq) 36562306a36Sopenharmony_ci rxe_get(srq); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci qp->pd = pd; 36862306a36Sopenharmony_ci qp->rcq = rcq; 36962306a36Sopenharmony_ci qp->scq = scq; 37062306a36Sopenharmony_ci qp->srq = srq; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci atomic_inc(&rcq->num_wq); 37362306a36Sopenharmony_ci atomic_inc(&scq->num_wq); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci rxe_qp_init_misc(rxe, qp, init); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci err = rxe_qp_init_req(rxe, qp, init, udata, uresp); 37862306a36Sopenharmony_ci if (err) 37962306a36Sopenharmony_ci goto err1; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci err = rxe_qp_init_resp(rxe, qp, init, udata, uresp); 38262306a36Sopenharmony_ci if (err) 38362306a36Sopenharmony_ci goto err2; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 38662306a36Sopenharmony_ci qp->attr.qp_state = IB_QPS_RESET; 38762306a36Sopenharmony_ci qp->valid = 1; 38862306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci return 0; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cierr2: 39362306a36Sopenharmony_ci rxe_queue_cleanup(qp->sq.queue); 39462306a36Sopenharmony_ci qp->sq.queue = NULL; 39562306a36Sopenharmony_cierr1: 39662306a36Sopenharmony_ci atomic_dec(&rcq->num_wq); 39762306a36Sopenharmony_ci atomic_dec(&scq->num_wq); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci qp->pd = NULL; 40062306a36Sopenharmony_ci qp->rcq = NULL; 40162306a36Sopenharmony_ci qp->scq = NULL; 40262306a36Sopenharmony_ci qp->srq = NULL; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (srq) 40562306a36Sopenharmony_ci rxe_put(srq); 40662306a36Sopenharmony_ci rxe_put(scq); 40762306a36Sopenharmony_ci rxe_put(rcq); 40862306a36Sopenharmony_ci rxe_put(pd); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci return err; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci/* called by the query qp verb */ 41462306a36Sopenharmony_ciint rxe_qp_to_init(struct rxe_qp *qp, struct ib_qp_init_attr *init) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci init->event_handler = qp->ibqp.event_handler; 41762306a36Sopenharmony_ci init->qp_context = qp->ibqp.qp_context; 41862306a36Sopenharmony_ci init->send_cq = qp->ibqp.send_cq; 41962306a36Sopenharmony_ci init->recv_cq = qp->ibqp.recv_cq; 42062306a36Sopenharmony_ci init->srq = qp->ibqp.srq; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci init->cap.max_send_wr = qp->sq.max_wr; 42362306a36Sopenharmony_ci init->cap.max_send_sge = qp->sq.max_sge; 42462306a36Sopenharmony_ci init->cap.max_inline_data = qp->sq.max_inline; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (!qp->srq) { 42762306a36Sopenharmony_ci init->cap.max_recv_wr = qp->rq.max_wr; 42862306a36Sopenharmony_ci init->cap.max_recv_sge = qp->rq.max_sge; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci init->sq_sig_type = qp->sq_sig_type; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci init->qp_type = qp->ibqp.qp_type; 43462306a36Sopenharmony_ci init->port_num = 1; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return 0; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ciint rxe_qp_chk_attr(struct rxe_dev *rxe, struct rxe_qp *qp, 44062306a36Sopenharmony_ci struct ib_qp_attr *attr, int mask) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci if (mask & IB_QP_PORT) { 44362306a36Sopenharmony_ci if (!rdma_is_port_valid(&rxe->ib_dev, attr->port_num)) { 44462306a36Sopenharmony_ci rxe_dbg_qp(qp, "invalid port %d\n", attr->port_num); 44562306a36Sopenharmony_ci goto err1; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (mask & IB_QP_CAP && rxe_qp_chk_cap(rxe, &attr->cap, !!qp->srq)) 45062306a36Sopenharmony_ci goto err1; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (mask & IB_QP_ACCESS_FLAGS) { 45362306a36Sopenharmony_ci if (!(qp_type(qp) == IB_QPT_RC || qp_type(qp) == IB_QPT_UC)) 45462306a36Sopenharmony_ci goto err1; 45562306a36Sopenharmony_ci if (attr->qp_access_flags & ~RXE_ACCESS_SUPPORTED_QP) 45662306a36Sopenharmony_ci goto err1; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (mask & IB_QP_AV && rxe_av_chk_attr(qp, &attr->ah_attr)) 46062306a36Sopenharmony_ci goto err1; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (mask & IB_QP_ALT_PATH) { 46362306a36Sopenharmony_ci if (rxe_av_chk_attr(qp, &attr->alt_ah_attr)) 46462306a36Sopenharmony_ci goto err1; 46562306a36Sopenharmony_ci if (!rdma_is_port_valid(&rxe->ib_dev, attr->alt_port_num)) { 46662306a36Sopenharmony_ci rxe_dbg_qp(qp, "invalid alt port %d\n", attr->alt_port_num); 46762306a36Sopenharmony_ci goto err1; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci if (attr->alt_timeout > 31) { 47062306a36Sopenharmony_ci rxe_dbg_qp(qp, "invalid alt timeout %d > 31\n", 47162306a36Sopenharmony_ci attr->alt_timeout); 47262306a36Sopenharmony_ci goto err1; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (mask & IB_QP_PATH_MTU) { 47762306a36Sopenharmony_ci struct rxe_port *port = &rxe->port; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci enum ib_mtu max_mtu = port->attr.max_mtu; 48062306a36Sopenharmony_ci enum ib_mtu mtu = attr->path_mtu; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (mtu > max_mtu) { 48362306a36Sopenharmony_ci rxe_dbg_qp(qp, "invalid mtu (%d) > (%d)\n", 48462306a36Sopenharmony_ci ib_mtu_enum_to_int(mtu), 48562306a36Sopenharmony_ci ib_mtu_enum_to_int(max_mtu)); 48662306a36Sopenharmony_ci goto err1; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (mask & IB_QP_MAX_QP_RD_ATOMIC) { 49162306a36Sopenharmony_ci if (attr->max_rd_atomic > rxe->attr.max_qp_rd_atom) { 49262306a36Sopenharmony_ci rxe_dbg_qp(qp, "invalid max_rd_atomic %d > %d\n", 49362306a36Sopenharmony_ci attr->max_rd_atomic, 49462306a36Sopenharmony_ci rxe->attr.max_qp_rd_atom); 49562306a36Sopenharmony_ci goto err1; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (mask & IB_QP_TIMEOUT) { 50062306a36Sopenharmony_ci if (attr->timeout > 31) { 50162306a36Sopenharmony_ci rxe_dbg_qp(qp, "invalid timeout %d > 31\n", 50262306a36Sopenharmony_ci attr->timeout); 50362306a36Sopenharmony_ci goto err1; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci return 0; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cierr1: 51062306a36Sopenharmony_ci return -EINVAL; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci/* move the qp to the reset state */ 51462306a36Sopenharmony_cistatic void rxe_qp_reset(struct rxe_qp *qp) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci /* stop tasks from running */ 51762306a36Sopenharmony_ci rxe_disable_task(&qp->resp.task); 51862306a36Sopenharmony_ci rxe_disable_task(&qp->comp.task); 51962306a36Sopenharmony_ci rxe_disable_task(&qp->req.task); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* drain work and packet queuesc */ 52262306a36Sopenharmony_ci rxe_requester(qp); 52362306a36Sopenharmony_ci rxe_completer(qp); 52462306a36Sopenharmony_ci rxe_responder(qp); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (qp->rq.queue) 52762306a36Sopenharmony_ci rxe_queue_reset(qp->rq.queue); 52862306a36Sopenharmony_ci if (qp->sq.queue) 52962306a36Sopenharmony_ci rxe_queue_reset(qp->sq.queue); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* cleanup attributes */ 53262306a36Sopenharmony_ci atomic_set(&qp->ssn, 0); 53362306a36Sopenharmony_ci qp->req.opcode = -1; 53462306a36Sopenharmony_ci qp->req.need_retry = 0; 53562306a36Sopenharmony_ci qp->req.wait_for_rnr_timer = 0; 53662306a36Sopenharmony_ci qp->req.noack_pkts = 0; 53762306a36Sopenharmony_ci qp->resp.msn = 0; 53862306a36Sopenharmony_ci qp->resp.opcode = -1; 53962306a36Sopenharmony_ci qp->resp.drop_msg = 0; 54062306a36Sopenharmony_ci qp->resp.goto_error = 0; 54162306a36Sopenharmony_ci qp->resp.sent_psn_nak = 0; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci if (qp->resp.mr) { 54462306a36Sopenharmony_ci rxe_put(qp->resp.mr); 54562306a36Sopenharmony_ci qp->resp.mr = NULL; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci cleanup_rd_atomic_resources(qp); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci /* reenable tasks */ 55162306a36Sopenharmony_ci rxe_enable_task(&qp->resp.task); 55262306a36Sopenharmony_ci rxe_enable_task(&qp->comp.task); 55362306a36Sopenharmony_ci rxe_enable_task(&qp->req.task); 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci/* move the qp to the error state */ 55762306a36Sopenharmony_civoid rxe_qp_error(struct rxe_qp *qp) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci unsigned long flags; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 56262306a36Sopenharmony_ci qp->attr.qp_state = IB_QPS_ERR; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* drain work and packet queues */ 56562306a36Sopenharmony_ci rxe_sched_task(&qp->resp.task); 56662306a36Sopenharmony_ci rxe_sched_task(&qp->comp.task); 56762306a36Sopenharmony_ci rxe_sched_task(&qp->req.task); 56862306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic void rxe_qp_sqd(struct rxe_qp *qp, struct ib_qp_attr *attr, 57262306a36Sopenharmony_ci int mask) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci unsigned long flags; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 57762306a36Sopenharmony_ci qp->attr.sq_draining = 1; 57862306a36Sopenharmony_ci rxe_sched_task(&qp->comp.task); 57962306a36Sopenharmony_ci rxe_sched_task(&qp->req.task); 58062306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci/* caller should hold qp->state_lock */ 58462306a36Sopenharmony_cistatic int __qp_chk_state(struct rxe_qp *qp, struct ib_qp_attr *attr, 58562306a36Sopenharmony_ci int mask) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci enum ib_qp_state cur_state; 58862306a36Sopenharmony_ci enum ib_qp_state new_state; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci cur_state = (mask & IB_QP_CUR_STATE) ? 59162306a36Sopenharmony_ci attr->cur_qp_state : qp->attr.qp_state; 59262306a36Sopenharmony_ci new_state = (mask & IB_QP_STATE) ? 59362306a36Sopenharmony_ci attr->qp_state : cur_state; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (!ib_modify_qp_is_ok(cur_state, new_state, qp_type(qp), mask)) 59662306a36Sopenharmony_ci return -EINVAL; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (mask & IB_QP_STATE && cur_state == IB_QPS_SQD) { 59962306a36Sopenharmony_ci if (qp->attr.sq_draining && new_state != IB_QPS_ERR) 60062306a36Sopenharmony_ci return -EINVAL; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci return 0; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic const char *const qps2str[] = { 60762306a36Sopenharmony_ci [IB_QPS_RESET] = "RESET", 60862306a36Sopenharmony_ci [IB_QPS_INIT] = "INIT", 60962306a36Sopenharmony_ci [IB_QPS_RTR] = "RTR", 61062306a36Sopenharmony_ci [IB_QPS_RTS] = "RTS", 61162306a36Sopenharmony_ci [IB_QPS_SQD] = "SQD", 61262306a36Sopenharmony_ci [IB_QPS_SQE] = "SQE", 61362306a36Sopenharmony_ci [IB_QPS_ERR] = "ERR", 61462306a36Sopenharmony_ci}; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci/* called by the modify qp verb */ 61762306a36Sopenharmony_ciint rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask, 61862306a36Sopenharmony_ci struct ib_udata *udata) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci int err; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (mask & IB_QP_CUR_STATE) 62362306a36Sopenharmony_ci qp->attr.cur_qp_state = attr->qp_state; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (mask & IB_QP_STATE) { 62662306a36Sopenharmony_ci unsigned long flags; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 62962306a36Sopenharmony_ci err = __qp_chk_state(qp, attr, mask); 63062306a36Sopenharmony_ci if (!err) { 63162306a36Sopenharmony_ci qp->attr.qp_state = attr->qp_state; 63262306a36Sopenharmony_ci rxe_dbg_qp(qp, "state -> %s\n", 63362306a36Sopenharmony_ci qps2str[attr->qp_state]); 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (err) 63862306a36Sopenharmony_ci return err; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci switch (attr->qp_state) { 64162306a36Sopenharmony_ci case IB_QPS_RESET: 64262306a36Sopenharmony_ci rxe_qp_reset(qp); 64362306a36Sopenharmony_ci break; 64462306a36Sopenharmony_ci case IB_QPS_SQD: 64562306a36Sopenharmony_ci rxe_qp_sqd(qp, attr, mask); 64662306a36Sopenharmony_ci break; 64762306a36Sopenharmony_ci case IB_QPS_ERR: 64862306a36Sopenharmony_ci rxe_qp_error(qp); 64962306a36Sopenharmony_ci break; 65062306a36Sopenharmony_ci default: 65162306a36Sopenharmony_ci break; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (mask & IB_QP_MAX_QP_RD_ATOMIC) { 65662306a36Sopenharmony_ci int max_rd_atomic = attr->max_rd_atomic ? 65762306a36Sopenharmony_ci roundup_pow_of_two(attr->max_rd_atomic) : 0; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci qp->attr.max_rd_atomic = max_rd_atomic; 66062306a36Sopenharmony_ci atomic_set(&qp->req.rd_atomic, max_rd_atomic); 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (mask & IB_QP_MAX_DEST_RD_ATOMIC) { 66462306a36Sopenharmony_ci int max_dest_rd_atomic = attr->max_dest_rd_atomic ? 66562306a36Sopenharmony_ci roundup_pow_of_two(attr->max_dest_rd_atomic) : 0; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci qp->attr.max_dest_rd_atomic = max_dest_rd_atomic; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci free_rd_atomic_resources(qp); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci err = alloc_rd_atomic_resources(qp, max_dest_rd_atomic); 67262306a36Sopenharmony_ci if (err) 67362306a36Sopenharmony_ci return err; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (mask & IB_QP_EN_SQD_ASYNC_NOTIFY) 67762306a36Sopenharmony_ci qp->attr.en_sqd_async_notify = attr->en_sqd_async_notify; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (mask & IB_QP_ACCESS_FLAGS) 68062306a36Sopenharmony_ci qp->attr.qp_access_flags = attr->qp_access_flags; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci if (mask & IB_QP_PKEY_INDEX) 68362306a36Sopenharmony_ci qp->attr.pkey_index = attr->pkey_index; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (mask & IB_QP_PORT) 68662306a36Sopenharmony_ci qp->attr.port_num = attr->port_num; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci if (mask & IB_QP_QKEY) 68962306a36Sopenharmony_ci qp->attr.qkey = attr->qkey; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (mask & IB_QP_AV) 69262306a36Sopenharmony_ci rxe_init_av(&attr->ah_attr, &qp->pri_av); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (mask & IB_QP_ALT_PATH) { 69562306a36Sopenharmony_ci rxe_init_av(&attr->alt_ah_attr, &qp->alt_av); 69662306a36Sopenharmony_ci qp->attr.alt_port_num = attr->alt_port_num; 69762306a36Sopenharmony_ci qp->attr.alt_pkey_index = attr->alt_pkey_index; 69862306a36Sopenharmony_ci qp->attr.alt_timeout = attr->alt_timeout; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (mask & IB_QP_PATH_MTU) { 70262306a36Sopenharmony_ci qp->attr.path_mtu = attr->path_mtu; 70362306a36Sopenharmony_ci qp->mtu = ib_mtu_enum_to_int(attr->path_mtu); 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (mask & IB_QP_TIMEOUT) { 70762306a36Sopenharmony_ci qp->attr.timeout = attr->timeout; 70862306a36Sopenharmony_ci if (attr->timeout == 0) { 70962306a36Sopenharmony_ci qp->qp_timeout_jiffies = 0; 71062306a36Sopenharmony_ci } else { 71162306a36Sopenharmony_ci /* According to the spec, timeout = 4.096 * 2 ^ attr->timeout [us] */ 71262306a36Sopenharmony_ci int j = nsecs_to_jiffies(4096ULL << attr->timeout); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci qp->qp_timeout_jiffies = j ? j : 1; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (mask & IB_QP_RETRY_CNT) { 71962306a36Sopenharmony_ci qp->attr.retry_cnt = attr->retry_cnt; 72062306a36Sopenharmony_ci qp->comp.retry_cnt = attr->retry_cnt; 72162306a36Sopenharmony_ci rxe_dbg_qp(qp, "set retry count = %d\n", attr->retry_cnt); 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci if (mask & IB_QP_RNR_RETRY) { 72562306a36Sopenharmony_ci qp->attr.rnr_retry = attr->rnr_retry; 72662306a36Sopenharmony_ci qp->comp.rnr_retry = attr->rnr_retry; 72762306a36Sopenharmony_ci rxe_dbg_qp(qp, "set rnr retry count = %d\n", attr->rnr_retry); 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci if (mask & IB_QP_RQ_PSN) { 73162306a36Sopenharmony_ci qp->attr.rq_psn = (attr->rq_psn & BTH_PSN_MASK); 73262306a36Sopenharmony_ci qp->resp.psn = qp->attr.rq_psn; 73362306a36Sopenharmony_ci rxe_dbg_qp(qp, "set resp psn = 0x%x\n", qp->resp.psn); 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (mask & IB_QP_MIN_RNR_TIMER) { 73762306a36Sopenharmony_ci qp->attr.min_rnr_timer = attr->min_rnr_timer; 73862306a36Sopenharmony_ci rxe_dbg_qp(qp, "set min rnr timer = 0x%x\n", 73962306a36Sopenharmony_ci attr->min_rnr_timer); 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (mask & IB_QP_SQ_PSN) { 74362306a36Sopenharmony_ci qp->attr.sq_psn = (attr->sq_psn & BTH_PSN_MASK); 74462306a36Sopenharmony_ci qp->req.psn = qp->attr.sq_psn; 74562306a36Sopenharmony_ci qp->comp.psn = qp->attr.sq_psn; 74662306a36Sopenharmony_ci rxe_dbg_qp(qp, "set req psn = 0x%x\n", qp->req.psn); 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if (mask & IB_QP_PATH_MIG_STATE) 75062306a36Sopenharmony_ci qp->attr.path_mig_state = attr->path_mig_state; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (mask & IB_QP_DEST_QPN) 75362306a36Sopenharmony_ci qp->attr.dest_qp_num = attr->dest_qp_num; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci return 0; 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci/* called by the query qp verb */ 75962306a36Sopenharmony_ciint rxe_qp_to_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci unsigned long flags; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci *attr = qp->attr; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci attr->rq_psn = qp->resp.psn; 76662306a36Sopenharmony_ci attr->sq_psn = qp->req.psn; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci attr->cap.max_send_wr = qp->sq.max_wr; 76962306a36Sopenharmony_ci attr->cap.max_send_sge = qp->sq.max_sge; 77062306a36Sopenharmony_ci attr->cap.max_inline_data = qp->sq.max_inline; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (!qp->srq) { 77362306a36Sopenharmony_ci attr->cap.max_recv_wr = qp->rq.max_wr; 77462306a36Sopenharmony_ci attr->cap.max_recv_sge = qp->rq.max_sge; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci rxe_av_to_attr(&qp->pri_av, &attr->ah_attr); 77862306a36Sopenharmony_ci rxe_av_to_attr(&qp->alt_av, &attr->alt_ah_attr); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci /* Applications that get this state typically spin on it. 78162306a36Sopenharmony_ci * Yield the processor 78262306a36Sopenharmony_ci */ 78362306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 78462306a36Sopenharmony_ci if (qp->attr.sq_draining) { 78562306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 78662306a36Sopenharmony_ci cond_resched(); 78762306a36Sopenharmony_ci } else { 78862306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci return 0; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ciint rxe_qp_chk_destroy(struct rxe_qp *qp) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci /* See IBA o10-2.2.3 79762306a36Sopenharmony_ci * An attempt to destroy a QP while attached to a mcast group 79862306a36Sopenharmony_ci * will fail immediately. 79962306a36Sopenharmony_ci */ 80062306a36Sopenharmony_ci if (atomic_read(&qp->mcg_num)) { 80162306a36Sopenharmony_ci rxe_dbg_qp(qp, "Attempt to destroy while attached to multicast group\n"); 80262306a36Sopenharmony_ci return -EBUSY; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci return 0; 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci/* called when the last reference to the qp is dropped */ 80962306a36Sopenharmony_cistatic void rxe_qp_do_cleanup(struct work_struct *work) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci struct rxe_qp *qp = container_of(work, typeof(*qp), cleanup_work.work); 81262306a36Sopenharmony_ci unsigned long flags; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 81562306a36Sopenharmony_ci qp->valid = 0; 81662306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 81762306a36Sopenharmony_ci qp->qp_timeout_jiffies = 0; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (qp_type(qp) == IB_QPT_RC) { 82062306a36Sopenharmony_ci del_timer_sync(&qp->retrans_timer); 82162306a36Sopenharmony_ci del_timer_sync(&qp->rnr_nak_timer); 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (qp->resp.task.func) 82562306a36Sopenharmony_ci rxe_cleanup_task(&qp->resp.task); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (qp->req.task.func) 82862306a36Sopenharmony_ci rxe_cleanup_task(&qp->req.task); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci if (qp->comp.task.func) 83162306a36Sopenharmony_ci rxe_cleanup_task(&qp->comp.task); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* flush out any receive wr's or pending requests */ 83462306a36Sopenharmony_ci rxe_requester(qp); 83562306a36Sopenharmony_ci rxe_completer(qp); 83662306a36Sopenharmony_ci rxe_responder(qp); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (qp->sq.queue) 83962306a36Sopenharmony_ci rxe_queue_cleanup(qp->sq.queue); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci if (qp->srq) 84262306a36Sopenharmony_ci rxe_put(qp->srq); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci if (qp->rq.queue) 84562306a36Sopenharmony_ci rxe_queue_cleanup(qp->rq.queue); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci if (qp->scq) { 84862306a36Sopenharmony_ci atomic_dec(&qp->scq->num_wq); 84962306a36Sopenharmony_ci rxe_put(qp->scq); 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (qp->rcq) { 85362306a36Sopenharmony_ci atomic_dec(&qp->rcq->num_wq); 85462306a36Sopenharmony_ci rxe_put(qp->rcq); 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci if (qp->pd) 85862306a36Sopenharmony_ci rxe_put(qp->pd); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci if (qp->resp.mr) 86162306a36Sopenharmony_ci rxe_put(qp->resp.mr); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci free_rd_atomic_resources(qp); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (qp->sk) { 86662306a36Sopenharmony_ci if (qp_type(qp) == IB_QPT_RC) 86762306a36Sopenharmony_ci sk_dst_reset(qp->sk->sk); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci kernel_sock_shutdown(qp->sk, SHUT_RDWR); 87062306a36Sopenharmony_ci sock_release(qp->sk); 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci/* called when the last reference to the qp is dropped */ 87562306a36Sopenharmony_civoid rxe_qp_cleanup(struct rxe_pool_elem *elem) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci struct rxe_qp *qp = container_of(elem, typeof(*qp), elem); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci execute_in_process_context(rxe_qp_do_cleanup, &qp->cleanup_work); 88062306a36Sopenharmony_ci} 881