163fa15dbSBob Pearson // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
28700e3e7SMoni Shoua /*
38700e3e7SMoni Shoua * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
48700e3e7SMoni Shoua * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
58700e3e7SMoni Shoua */
68700e3e7SMoni Shoua
78700e3e7SMoni Shoua #include <linux/skbuff.h>
88700e3e7SMoni Shoua #include <linux/delay.h>
98700e3e7SMoni Shoua #include <linux/sched.h>
10721ad7e6SZhu Yanjun #include <linux/vmalloc.h>
1189944450SShamir Rabinovitch #include <rdma/uverbs_ioctl.h>
128700e3e7SMoni Shoua
138700e3e7SMoni Shoua #include "rxe.h"
148700e3e7SMoni Shoua #include "rxe_loc.h"
158700e3e7SMoni Shoua #include "rxe_queue.h"
168700e3e7SMoni Shoua #include "rxe_task.h"
178700e3e7SMoni Shoua
rxe_qp_chk_cap(struct rxe_dev * rxe,struct ib_qp_cap * cap,int has_srq)188700e3e7SMoni Shoua static int rxe_qp_chk_cap(struct rxe_dev *rxe, struct ib_qp_cap *cap,
198700e3e7SMoni Shoua int has_srq)
208700e3e7SMoni Shoua {
218700e3e7SMoni Shoua if (cap->max_send_wr > rxe->attr.max_qp_wr) {
22a9fb3287SBob Pearson rxe_dbg_dev(rxe, "invalid send wr = %u > %d\n",
238700e3e7SMoni Shoua cap->max_send_wr, rxe->attr.max_qp_wr);
248700e3e7SMoni Shoua goto err1;
258700e3e7SMoni Shoua }
268700e3e7SMoni Shoua
2733023fb8SSteve Wise if (cap->max_send_sge > rxe->attr.max_send_sge) {
28a9fb3287SBob Pearson rxe_dbg_dev(rxe, "invalid send sge = %u > %d\n",
2933023fb8SSteve Wise cap->max_send_sge, rxe->attr.max_send_sge);
308700e3e7SMoni Shoua goto err1;
318700e3e7SMoni Shoua }
328700e3e7SMoni Shoua
338700e3e7SMoni Shoua if (!has_srq) {
348700e3e7SMoni Shoua if (cap->max_recv_wr > rxe->attr.max_qp_wr) {
35a9fb3287SBob Pearson rxe_dbg_dev(rxe, "invalid recv wr = %u > %d\n",
368700e3e7SMoni Shoua cap->max_recv_wr, rxe->attr.max_qp_wr);
378700e3e7SMoni Shoua goto err1;
388700e3e7SMoni Shoua }
398700e3e7SMoni Shoua
4033023fb8SSteve Wise if (cap->max_recv_sge > rxe->attr.max_recv_sge) {
41a9fb3287SBob Pearson rxe_dbg_dev(rxe, "invalid recv sge = %u > %d\n",
4233023fb8SSteve Wise cap->max_recv_sge, rxe->attr.max_recv_sge);
438700e3e7SMoni Shoua goto err1;
448700e3e7SMoni Shoua }
458700e3e7SMoni Shoua }
468700e3e7SMoni Shoua
478700e3e7SMoni Shoua if (cap->max_inline_data > rxe->max_inline_data) {
48a9fb3287SBob Pearson rxe_dbg_dev(rxe, "invalid max inline data = %u > %d\n",
498700e3e7SMoni Shoua cap->max_inline_data, rxe->max_inline_data);
508700e3e7SMoni Shoua goto err1;
518700e3e7SMoni Shoua }
528700e3e7SMoni Shoua
538700e3e7SMoni Shoua return 0;
548700e3e7SMoni Shoua
558700e3e7SMoni Shoua err1:
568700e3e7SMoni Shoua return -EINVAL;
578700e3e7SMoni Shoua }
588700e3e7SMoni Shoua
rxe_qp_chk_init(struct rxe_dev * rxe,struct ib_qp_init_attr * init)598700e3e7SMoni Shoua int rxe_qp_chk_init(struct rxe_dev *rxe, struct ib_qp_init_attr *init)
608700e3e7SMoni Shoua {
618700e3e7SMoni Shoua struct ib_qp_cap *cap = &init->cap;
628700e3e7SMoni Shoua struct rxe_port *port;
638700e3e7SMoni Shoua int port_num = init->port_num;
648700e3e7SMoni Shoua
65bad07664SXiao Yang switch (init->qp_type) {
66bad07664SXiao Yang case IB_QPT_GSI:
67bad07664SXiao Yang case IB_QPT_RC:
68bad07664SXiao Yang case IB_QPT_UC:
69bad07664SXiao Yang case IB_QPT_UD:
70bad07664SXiao Yang break;
71bad07664SXiao Yang default:
72bad07664SXiao Yang return -EOPNOTSUPP;
73bad07664SXiao Yang }
74bad07664SXiao Yang
758700e3e7SMoni Shoua if (!init->recv_cq || !init->send_cq) {
76a9fb3287SBob Pearson rxe_dbg_dev(rxe, "missing cq\n");
778700e3e7SMoni Shoua goto err1;
788700e3e7SMoni Shoua }
798700e3e7SMoni Shoua
808700e3e7SMoni Shoua if (rxe_qp_chk_cap(rxe, cap, !!init->srq))
818700e3e7SMoni Shoua goto err1;
828700e3e7SMoni Shoua
83409baed5SBob Pearson if (init->qp_type == IB_QPT_GSI) {
84e7521d82SYuval Shaia if (!rdma_is_port_valid(&rxe->ib_dev, port_num)) {
85a9fb3287SBob Pearson rxe_dbg_dev(rxe, "invalid port = %d\n", port_num);
868700e3e7SMoni Shoua goto err1;
878700e3e7SMoni Shoua }
888700e3e7SMoni Shoua
898700e3e7SMoni Shoua port = &rxe->port;
908700e3e7SMoni Shoua
918700e3e7SMoni Shoua if (init->qp_type == IB_QPT_GSI && port->qp_gsi_index) {
92a9fb3287SBob Pearson rxe_dbg_dev(rxe, "GSI QP exists for port %d\n", port_num);
938700e3e7SMoni Shoua goto err1;
948700e3e7SMoni Shoua }
958700e3e7SMoni Shoua }
968700e3e7SMoni Shoua
978700e3e7SMoni Shoua return 0;
988700e3e7SMoni Shoua
998700e3e7SMoni Shoua err1:
1008700e3e7SMoni Shoua return -EINVAL;
1018700e3e7SMoni Shoua }
1028700e3e7SMoni Shoua
alloc_rd_atomic_resources(struct rxe_qp * qp,unsigned int n)1038700e3e7SMoni Shoua static int alloc_rd_atomic_resources(struct rxe_qp *qp, unsigned int n)
1048700e3e7SMoni Shoua {
1058700e3e7SMoni Shoua qp->resp.res_head = 0;
1068700e3e7SMoni Shoua qp->resp.res_tail = 0;
1078700e3e7SMoni Shoua qp->resp.resources = kcalloc(n, sizeof(struct resp_res), GFP_KERNEL);
1088700e3e7SMoni Shoua
1098700e3e7SMoni Shoua if (!qp->resp.resources)
1108700e3e7SMoni Shoua return -ENOMEM;
1118700e3e7SMoni Shoua
1128700e3e7SMoni Shoua return 0;
1138700e3e7SMoni Shoua }
1148700e3e7SMoni Shoua
free_rd_atomic_resources(struct rxe_qp * qp)1158700e3e7SMoni Shoua static void free_rd_atomic_resources(struct rxe_qp *qp)
1168700e3e7SMoni Shoua {
1178700e3e7SMoni Shoua if (qp->resp.resources) {
1188700e3e7SMoni Shoua int i;
1198700e3e7SMoni Shoua
120b6bbee0dSParav Pandit for (i = 0; i < qp->attr.max_dest_rd_atomic; i++) {
1218700e3e7SMoni Shoua struct resp_res *res = &qp->resp.resources[i];
1228700e3e7SMoni Shoua
12368691badSXiao Yang free_rd_atomic_resource(res);
1248700e3e7SMoni Shoua }
1258700e3e7SMoni Shoua kfree(qp->resp.resources);
1268700e3e7SMoni Shoua qp->resp.resources = NULL;
1278700e3e7SMoni Shoua }
1288700e3e7SMoni Shoua }
1298700e3e7SMoni Shoua
free_rd_atomic_resource(struct resp_res * res)13068691badSXiao Yang void free_rd_atomic_resource(struct resp_res *res)
1318700e3e7SMoni Shoua {
1328700e3e7SMoni Shoua res->type = 0;
1338700e3e7SMoni Shoua }
1348700e3e7SMoni Shoua
cleanup_rd_atomic_resources(struct rxe_qp * qp)1358700e3e7SMoni Shoua static void cleanup_rd_atomic_resources(struct rxe_qp *qp)
1368700e3e7SMoni Shoua {
1378700e3e7SMoni Shoua int i;
1388700e3e7SMoni Shoua struct resp_res *res;
1398700e3e7SMoni Shoua
1408700e3e7SMoni Shoua if (qp->resp.resources) {
141b6bbee0dSParav Pandit for (i = 0; i < qp->attr.max_dest_rd_atomic; i++) {
1428700e3e7SMoni Shoua res = &qp->resp.resources[i];
14368691badSXiao Yang free_rd_atomic_resource(res);
1448700e3e7SMoni Shoua }
1458700e3e7SMoni Shoua }
1468700e3e7SMoni Shoua }
1478700e3e7SMoni Shoua
rxe_qp_init_misc(struct rxe_dev * rxe,struct rxe_qp * qp,struct ib_qp_init_attr * init)1488700e3e7SMoni Shoua static void rxe_qp_init_misc(struct rxe_dev *rxe, struct rxe_qp *qp,
1498700e3e7SMoni Shoua struct ib_qp_init_attr *init)
1508700e3e7SMoni Shoua {
1518700e3e7SMoni Shoua struct rxe_port *port;
1528700e3e7SMoni Shoua u32 qpn;
1538700e3e7SMoni Shoua
1548700e3e7SMoni Shoua qp->sq_sig_type = init->sq_sig_type;
1558700e3e7SMoni Shoua qp->attr.path_mtu = 1;
1568700e3e7SMoni Shoua qp->mtu = ib_mtu_enum_to_int(qp->attr.path_mtu);
1578700e3e7SMoni Shoua
15802827b67SBob Pearson qpn = qp->elem.index;
1598700e3e7SMoni Shoua port = &rxe->port;
1608700e3e7SMoni Shoua
1618700e3e7SMoni Shoua switch (init->qp_type) {
1628700e3e7SMoni Shoua case IB_QPT_GSI:
1638700e3e7SMoni Shoua qp->ibqp.qp_num = 1;
1648700e3e7SMoni Shoua port->qp_gsi_index = qpn;
1658700e3e7SMoni Shoua qp->attr.port_num = init->port_num;
1668700e3e7SMoni Shoua break;
1678700e3e7SMoni Shoua
1688700e3e7SMoni Shoua default:
1698700e3e7SMoni Shoua qp->ibqp.qp_num = qpn;
1708700e3e7SMoni Shoua break;
1718700e3e7SMoni Shoua }
1728700e3e7SMoni Shoua
1738700e3e7SMoni Shoua spin_lock_init(&qp->state_lock);
1748700e3e7SMoni Shoua
175fd5382c5SZhu Yanjun spin_lock_init(&qp->sq.sq_lock);
176fd5382c5SZhu Yanjun spin_lock_init(&qp->rq.producer_lock);
177fd5382c5SZhu Yanjun spin_lock_init(&qp->rq.consumer_lock);
178fd5382c5SZhu Yanjun
1792a62b621SZhu Yanjun skb_queue_head_init(&qp->req_pkts);
1802a62b621SZhu Yanjun skb_queue_head_init(&qp->resp_pkts);
1812a62b621SZhu Yanjun
1828700e3e7SMoni Shoua atomic_set(&qp->ssn, 0);
1838700e3e7SMoni Shoua atomic_set(&qp->skb_out, 0);
1848700e3e7SMoni Shoua }
1858700e3e7SMoni Shoua
rxe_init_sq(struct rxe_qp * qp,struct ib_qp_init_attr * init,struct ib_udata * udata,struct rxe_create_qp_resp __user * uresp)186e0ba8ff4SBob Pearson static int rxe_init_sq(struct rxe_qp *qp, struct ib_qp_init_attr *init,
187e0ba8ff4SBob Pearson struct ib_udata *udata,
188e0ba8ff4SBob Pearson struct rxe_create_qp_resp __user *uresp)
189e0ba8ff4SBob Pearson {
190e0ba8ff4SBob Pearson struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
191e0ba8ff4SBob Pearson int wqe_size;
192e0ba8ff4SBob Pearson int err;
193e0ba8ff4SBob Pearson
194e0ba8ff4SBob Pearson qp->sq.max_wr = init->cap.max_send_wr;
195e0ba8ff4SBob Pearson wqe_size = max_t(int, init->cap.max_send_sge * sizeof(struct ib_sge),
196e0ba8ff4SBob Pearson init->cap.max_inline_data);
197e0ba8ff4SBob Pearson qp->sq.max_sge = wqe_size / sizeof(struct ib_sge);
198e0ba8ff4SBob Pearson qp->sq.max_inline = wqe_size;
199e0ba8ff4SBob Pearson wqe_size += sizeof(struct rxe_send_wqe);
200e0ba8ff4SBob Pearson
201e0ba8ff4SBob Pearson qp->sq.queue = rxe_queue_init(rxe, &qp->sq.max_wr, wqe_size,
202e0ba8ff4SBob Pearson QUEUE_TYPE_FROM_CLIENT);
203e0ba8ff4SBob Pearson if (!qp->sq.queue) {
204*5dfd5a88SLi Zhijian rxe_err_qp(qp, "Unable to allocate send queue\n");
205e0ba8ff4SBob Pearson err = -ENOMEM;
206e0ba8ff4SBob Pearson goto err_out;
207e0ba8ff4SBob Pearson }
208e0ba8ff4SBob Pearson
209e0ba8ff4SBob Pearson /* prepare info for caller to mmap send queue if user space qp */
210e0ba8ff4SBob Pearson err = do_mmap_info(rxe, uresp ? &uresp->sq_mi : NULL, udata,
211e0ba8ff4SBob Pearson qp->sq.queue->buf, qp->sq.queue->buf_size,
212e0ba8ff4SBob Pearson &qp->sq.queue->ip);
213e0ba8ff4SBob Pearson if (err) {
214*5dfd5a88SLi Zhijian rxe_err_qp(qp, "do_mmap_info failed, err = %d\n", err);
215e0ba8ff4SBob Pearson goto err_free;
216e0ba8ff4SBob Pearson }
217e0ba8ff4SBob Pearson
218e0ba8ff4SBob Pearson /* return actual capabilities to caller which may be larger
219e0ba8ff4SBob Pearson * than requested
220e0ba8ff4SBob Pearson */
221e0ba8ff4SBob Pearson init->cap.max_send_wr = qp->sq.max_wr;
222e0ba8ff4SBob Pearson init->cap.max_send_sge = qp->sq.max_sge;
223e0ba8ff4SBob Pearson init->cap.max_inline_data = qp->sq.max_inline;
224e0ba8ff4SBob Pearson
225e0ba8ff4SBob Pearson return 0;
226e0ba8ff4SBob Pearson
227e0ba8ff4SBob Pearson err_free:
228e0ba8ff4SBob Pearson vfree(qp->sq.queue->buf);
229e0ba8ff4SBob Pearson kfree(qp->sq.queue);
230e0ba8ff4SBob Pearson qp->sq.queue = NULL;
231e0ba8ff4SBob Pearson err_out:
232e0ba8ff4SBob Pearson return err;
233e0ba8ff4SBob Pearson }
234e0ba8ff4SBob Pearson
rxe_qp_init_req(struct rxe_dev * rxe,struct rxe_qp * qp,struct ib_qp_init_attr * init,struct ib_udata * udata,struct rxe_create_qp_resp __user * uresp)2358700e3e7SMoni Shoua static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp,
236ff23dfa1SShamir Rabinovitch struct ib_qp_init_attr *init, struct ib_udata *udata,
2370c43ab37SJason Gunthorpe struct rxe_create_qp_resp __user *uresp)
2388700e3e7SMoni Shoua {
2398700e3e7SMoni Shoua int err;
240e0ba8ff4SBob Pearson
241e0ba8ff4SBob Pearson /* if we don't finish qp create make sure queue is valid */
242e0ba8ff4SBob Pearson skb_queue_head_init(&qp->req_pkts);
2438700e3e7SMoni Shoua
2448700e3e7SMoni Shoua err = sock_create_kern(&init_net, AF_INET, SOCK_DGRAM, 0, &qp->sk);
2458700e3e7SMoni Shoua if (err < 0)
2468700e3e7SMoni Shoua return err;
2478700e3e7SMoni Shoua qp->sk->sk->sk_user_data = qp;
2488700e3e7SMoni Shoua
249d3c04a3aSVijay Immanuel /* pick a source UDP port number for this QP based on
250d3c04a3aSVijay Immanuel * the source QPN. this spreads traffic for different QPs
251d3c04a3aSVijay Immanuel * across different NIC RX queues (while using a single
252d3c04a3aSVijay Immanuel * flow for a given QP to maintain packet order).
253d3c04a3aSVijay Immanuel * the port number must be in the Dynamic Ports range
254d3c04a3aSVijay Immanuel * (0xc000 - 0xffff).
255d3c04a3aSVijay Immanuel */
256fd0a1462SIsabella Basso qp->src_port = RXE_ROCE_V2_SPORT + (hash_32(qp_num(qp), 14) & 0x3fff);
2578700e3e7SMoni Shoua
258e0ba8ff4SBob Pearson err = rxe_init_sq(qp, init, udata, uresp);
259e0ba8ff4SBob Pearson if (err)
2608700e3e7SMoni Shoua return err;
2618700e3e7SMoni Shoua
262ae6e843fSBob Pearson qp->req.wqe_index = queue_get_producer(qp->sq.queue,
263ae6e843fSBob Pearson QUEUE_TYPE_FROM_CLIENT);
2645bcf5a59SBob Pearson
2658700e3e7SMoni Shoua qp->req.opcode = -1;
2668700e3e7SMoni Shoua qp->comp.opcode = -1;
2678700e3e7SMoni Shoua
268de669ae8SBob Pearson rxe_init_task(&qp->req.task, qp, rxe_requester);
269de669ae8SBob Pearson rxe_init_task(&qp->comp.task, qp, rxe_completer);
2708700e3e7SMoni Shoua
27199fc12f6SParav Pandit qp->qp_timeout_jiffies = 0; /* Can't be set for UD/UC in modify_qp */
27299fc12f6SParav Pandit if (init->qp_type == IB_QPT_RC) {
2733bfbea74SKees Cook timer_setup(&qp->rnr_nak_timer, rnr_nak_timer, 0);
2743bfbea74SKees Cook timer_setup(&qp->retrans_timer, retransmit_timer, 0);
27599fc12f6SParav Pandit }
2768700e3e7SMoni Shoua return 0;
2778700e3e7SMoni Shoua }
2788700e3e7SMoni Shoua
rxe_init_rq(struct rxe_qp * qp,struct ib_qp_init_attr * init,struct ib_udata * udata,struct rxe_create_qp_resp __user * uresp)279e0ba8ff4SBob Pearson static int rxe_init_rq(struct rxe_qp *qp, struct ib_qp_init_attr *init,
280e0ba8ff4SBob Pearson struct ib_udata *udata,
281e0ba8ff4SBob Pearson struct rxe_create_qp_resp __user *uresp)
282e0ba8ff4SBob Pearson {
283e0ba8ff4SBob Pearson struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
284e0ba8ff4SBob Pearson int wqe_size;
285e0ba8ff4SBob Pearson int err;
286e0ba8ff4SBob Pearson
287e0ba8ff4SBob Pearson qp->rq.max_wr = init->cap.max_recv_wr;
288e0ba8ff4SBob Pearson qp->rq.max_sge = init->cap.max_recv_sge;
289e0ba8ff4SBob Pearson wqe_size = sizeof(struct rxe_recv_wqe) +
290e0ba8ff4SBob Pearson qp->rq.max_sge*sizeof(struct ib_sge);
291e0ba8ff4SBob Pearson
292e0ba8ff4SBob Pearson qp->rq.queue = rxe_queue_init(rxe, &qp->rq.max_wr, wqe_size,
293e0ba8ff4SBob Pearson QUEUE_TYPE_FROM_CLIENT);
294e0ba8ff4SBob Pearson if (!qp->rq.queue) {
295*5dfd5a88SLi Zhijian rxe_err_qp(qp, "Unable to allocate recv queue\n");
296e0ba8ff4SBob Pearson err = -ENOMEM;
297e0ba8ff4SBob Pearson goto err_out;
298e0ba8ff4SBob Pearson }
299e0ba8ff4SBob Pearson
300e0ba8ff4SBob Pearson /* prepare info for caller to mmap recv queue if user space qp */
301e0ba8ff4SBob Pearson err = do_mmap_info(rxe, uresp ? &uresp->rq_mi : NULL, udata,
302e0ba8ff4SBob Pearson qp->rq.queue->buf, qp->rq.queue->buf_size,
303e0ba8ff4SBob Pearson &qp->rq.queue->ip);
304e0ba8ff4SBob Pearson if (err) {
305*5dfd5a88SLi Zhijian rxe_err_qp(qp, "do_mmap_info failed, err = %d\n", err);
306e0ba8ff4SBob Pearson goto err_free;
307e0ba8ff4SBob Pearson }
308e0ba8ff4SBob Pearson
309e0ba8ff4SBob Pearson /* return actual capabilities to caller which may be larger
310e0ba8ff4SBob Pearson * than requested
311e0ba8ff4SBob Pearson */
312e0ba8ff4SBob Pearson init->cap.max_recv_wr = qp->rq.max_wr;
313e0ba8ff4SBob Pearson
314e0ba8ff4SBob Pearson return 0;
315e0ba8ff4SBob Pearson
316e0ba8ff4SBob Pearson err_free:
317e0ba8ff4SBob Pearson vfree(qp->rq.queue->buf);
318e0ba8ff4SBob Pearson kfree(qp->rq.queue);
319e0ba8ff4SBob Pearson qp->rq.queue = NULL;
320e0ba8ff4SBob Pearson err_out:
321e0ba8ff4SBob Pearson return err;
322e0ba8ff4SBob Pearson }
323e0ba8ff4SBob Pearson
rxe_qp_init_resp(struct rxe_dev * rxe,struct rxe_qp * qp,struct ib_qp_init_attr * init,struct ib_udata * udata,struct rxe_create_qp_resp __user * uresp)3248700e3e7SMoni Shoua static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp,
3258700e3e7SMoni Shoua struct ib_qp_init_attr *init,
326ff23dfa1SShamir Rabinovitch struct ib_udata *udata,
3270c43ab37SJason Gunthorpe struct rxe_create_qp_resp __user *uresp)
3288700e3e7SMoni Shoua {
3298700e3e7SMoni Shoua int err;
330e0ba8ff4SBob Pearson
331e0ba8ff4SBob Pearson /* if we don't finish qp create make sure queue is valid */
332e0ba8ff4SBob Pearson skb_queue_head_init(&qp->resp_pkts);
3338700e3e7SMoni Shoua
3348700e3e7SMoni Shoua if (!qp->srq) {
335e0ba8ff4SBob Pearson err = rxe_init_rq(qp, init, udata, uresp);
336e0ba8ff4SBob Pearson if (err)
3378700e3e7SMoni Shoua return err;
3388700e3e7SMoni Shoua }
3398700e3e7SMoni Shoua
340de669ae8SBob Pearson rxe_init_task(&qp->resp.task, qp, rxe_responder);
3418700e3e7SMoni Shoua
3428700e3e7SMoni Shoua qp->resp.opcode = OPCODE_NONE;
3438700e3e7SMoni Shoua qp->resp.msn = 0;
3448700e3e7SMoni Shoua
3458700e3e7SMoni Shoua return 0;
3468700e3e7SMoni Shoua }
3478700e3e7SMoni Shoua
3488700e3e7SMoni Shoua /* called by the create qp verb */
rxe_qp_from_init(struct rxe_dev * rxe,struct rxe_qp * qp,struct rxe_pd * pd,struct ib_qp_init_attr * init,struct rxe_create_qp_resp __user * uresp,struct ib_pd * ibpd,struct ib_udata * udata)3498700e3e7SMoni Shoua int rxe_qp_from_init(struct rxe_dev *rxe, struct rxe_qp *qp, struct rxe_pd *pd,
3500c43ab37SJason Gunthorpe struct ib_qp_init_attr *init,
3510c43ab37SJason Gunthorpe struct rxe_create_qp_resp __user *uresp,
352e00b64f7SShamir Rabinovitch struct ib_pd *ibpd,
353e00b64f7SShamir Rabinovitch struct ib_udata *udata)
3548700e3e7SMoni Shoua {
3558700e3e7SMoni Shoua int err;
3568700e3e7SMoni Shoua struct rxe_cq *rcq = to_rcq(init->recv_cq);
3578700e3e7SMoni Shoua struct rxe_cq *scq = to_rcq(init->send_cq);
3588700e3e7SMoni Shoua struct rxe_srq *srq = init->srq ? to_rsrq(init->srq) : NULL;
359b5f3fe27SGuoqing Jiang unsigned long flags;
3608700e3e7SMoni Shoua
3613197706aSBob Pearson rxe_get(pd);
3623197706aSBob Pearson rxe_get(rcq);
3633197706aSBob Pearson rxe_get(scq);
3648700e3e7SMoni Shoua if (srq)
3653197706aSBob Pearson rxe_get(srq);
3668700e3e7SMoni Shoua
3678700e3e7SMoni Shoua qp->pd = pd;
3688700e3e7SMoni Shoua qp->rcq = rcq;
3698700e3e7SMoni Shoua qp->scq = scq;
3708700e3e7SMoni Shoua qp->srq = srq;
3718700e3e7SMoni Shoua
3724703b4f0SBob Pearson atomic_inc(&rcq->num_wq);
3734703b4f0SBob Pearson atomic_inc(&scq->num_wq);
3744703b4f0SBob Pearson
3758700e3e7SMoni Shoua rxe_qp_init_misc(rxe, qp, init);
3768700e3e7SMoni Shoua
377ff23dfa1SShamir Rabinovitch err = rxe_qp_init_req(rxe, qp, init, udata, uresp);
3788700e3e7SMoni Shoua if (err)
3798700e3e7SMoni Shoua goto err1;
3808700e3e7SMoni Shoua
381ff23dfa1SShamir Rabinovitch err = rxe_qp_init_resp(rxe, qp, init, udata, uresp);
3828700e3e7SMoni Shoua if (err)
3838700e3e7SMoni Shoua goto err2;
3848700e3e7SMoni Shoua
385b5f3fe27SGuoqing Jiang spin_lock_irqsave(&qp->state_lock, flags);
3868700e3e7SMoni Shoua qp->attr.qp_state = IB_QPS_RESET;
3878700e3e7SMoni Shoua qp->valid = 1;
388b5f3fe27SGuoqing Jiang spin_unlock_irqrestore(&qp->state_lock, flags);
3898700e3e7SMoni Shoua
3908700e3e7SMoni Shoua return 0;
3918700e3e7SMoni Shoua
3928700e3e7SMoni Shoua err2:
3938700e3e7SMoni Shoua rxe_queue_cleanup(qp->sq.queue);
39484b01721SPavel Skripkin qp->sq.queue = NULL;
3958700e3e7SMoni Shoua err1:
3964703b4f0SBob Pearson atomic_dec(&rcq->num_wq);
3974703b4f0SBob Pearson atomic_dec(&scq->num_wq);
3984703b4f0SBob Pearson
39967f29896SLeon Romanovsky qp->pd = NULL;
40067f29896SLeon Romanovsky qp->rcq = NULL;
40167f29896SLeon Romanovsky qp->scq = NULL;
40267f29896SLeon Romanovsky qp->srq = NULL;
40367f29896SLeon Romanovsky
4048700e3e7SMoni Shoua if (srq)
4053197706aSBob Pearson rxe_put(srq);
4063197706aSBob Pearson rxe_put(scq);
4073197706aSBob Pearson rxe_put(rcq);
4083197706aSBob Pearson rxe_put(pd);
4098700e3e7SMoni Shoua
4108700e3e7SMoni Shoua return err;
4118700e3e7SMoni Shoua }
4128700e3e7SMoni Shoua
4138700e3e7SMoni Shoua /* called by the query qp verb */
rxe_qp_to_init(struct rxe_qp * qp,struct ib_qp_init_attr * init)4148700e3e7SMoni Shoua int rxe_qp_to_init(struct rxe_qp *qp, struct ib_qp_init_attr *init)
4158700e3e7SMoni Shoua {
4168700e3e7SMoni Shoua init->event_handler = qp->ibqp.event_handler;
4178700e3e7SMoni Shoua init->qp_context = qp->ibqp.qp_context;
4188700e3e7SMoni Shoua init->send_cq = qp->ibqp.send_cq;
4198700e3e7SMoni Shoua init->recv_cq = qp->ibqp.recv_cq;
4208700e3e7SMoni Shoua init->srq = qp->ibqp.srq;
4218700e3e7SMoni Shoua
4228700e3e7SMoni Shoua init->cap.max_send_wr = qp->sq.max_wr;
4238700e3e7SMoni Shoua init->cap.max_send_sge = qp->sq.max_sge;
4248700e3e7SMoni Shoua init->cap.max_inline_data = qp->sq.max_inline;
4258700e3e7SMoni Shoua
4268700e3e7SMoni Shoua if (!qp->srq) {
4278700e3e7SMoni Shoua init->cap.max_recv_wr = qp->rq.max_wr;
4288700e3e7SMoni Shoua init->cap.max_recv_sge = qp->rq.max_sge;
4298700e3e7SMoni Shoua }
4308700e3e7SMoni Shoua
4318700e3e7SMoni Shoua init->sq_sig_type = qp->sq_sig_type;
4328700e3e7SMoni Shoua
4338700e3e7SMoni Shoua init->qp_type = qp->ibqp.qp_type;
4348700e3e7SMoni Shoua init->port_num = 1;
4358700e3e7SMoni Shoua
4368700e3e7SMoni Shoua return 0;
4378700e3e7SMoni Shoua }
4388700e3e7SMoni Shoua
rxe_qp_chk_attr(struct rxe_dev * rxe,struct rxe_qp * qp,struct ib_qp_attr * attr,int mask)4398700e3e7SMoni Shoua int rxe_qp_chk_attr(struct rxe_dev *rxe, struct rxe_qp *qp,
4408700e3e7SMoni Shoua struct ib_qp_attr *attr, int mask)
4418700e3e7SMoni Shoua {
4428700e3e7SMoni Shoua if (mask & IB_QP_PORT) {
443e7521d82SYuval Shaia if (!rdma_is_port_valid(&rxe->ib_dev, attr->port_num)) {
4446af70060SBob Pearson rxe_dbg_qp(qp, "invalid port %d\n", attr->port_num);
4458700e3e7SMoni Shoua goto err1;
4468700e3e7SMoni Shoua }
4478700e3e7SMoni Shoua }
4488700e3e7SMoni Shoua
4498700e3e7SMoni Shoua if (mask & IB_QP_CAP && rxe_qp_chk_cap(rxe, &attr->cap, !!qp->srq))
4508700e3e7SMoni Shoua goto err1;
4518700e3e7SMoni Shoua
45202ed2537SBob Pearson if (mask & IB_QP_ACCESS_FLAGS) {
45302ed2537SBob Pearson if (!(qp_type(qp) == IB_QPT_RC || qp_type(qp) == IB_QPT_UC))
45402ed2537SBob Pearson goto err1;
45502ed2537SBob Pearson if (attr->qp_access_flags & ~RXE_ACCESS_SUPPORTED_QP)
45602ed2537SBob Pearson goto err1;
45702ed2537SBob Pearson }
45802ed2537SBob Pearson
45925fd735aSBob Pearson if (mask & IB_QP_AV && rxe_av_chk_attr(qp, &attr->ah_attr))
4608700e3e7SMoni Shoua goto err1;
4618700e3e7SMoni Shoua
4628700e3e7SMoni Shoua if (mask & IB_QP_ALT_PATH) {
46325fd735aSBob Pearson if (rxe_av_chk_attr(qp, &attr->alt_ah_attr))
4648700e3e7SMoni Shoua goto err1;
465e7521d82SYuval Shaia if (!rdma_is_port_valid(&rxe->ib_dev, attr->alt_port_num)) {
4666af70060SBob Pearson rxe_dbg_qp(qp, "invalid alt port %d\n", attr->alt_port_num);
4678700e3e7SMoni Shoua goto err1;
4688700e3e7SMoni Shoua }
4698700e3e7SMoni Shoua if (attr->alt_timeout > 31) {
4706af70060SBob Pearson rxe_dbg_qp(qp, "invalid alt timeout %d > 31\n",
4718700e3e7SMoni Shoua attr->alt_timeout);
4728700e3e7SMoni Shoua goto err1;
4738700e3e7SMoni Shoua }
4748700e3e7SMoni Shoua }
4758700e3e7SMoni Shoua
4768700e3e7SMoni Shoua if (mask & IB_QP_PATH_MTU) {
4778700e3e7SMoni Shoua struct rxe_port *port = &rxe->port;
4788700e3e7SMoni Shoua
4798700e3e7SMoni Shoua enum ib_mtu max_mtu = port->attr.max_mtu;
4808700e3e7SMoni Shoua enum ib_mtu mtu = attr->path_mtu;
4818700e3e7SMoni Shoua
4828700e3e7SMoni Shoua if (mtu > max_mtu) {
4836af70060SBob Pearson rxe_dbg_qp(qp, "invalid mtu (%d) > (%d)\n",
4848700e3e7SMoni Shoua ib_mtu_enum_to_int(mtu),
4858700e3e7SMoni Shoua ib_mtu_enum_to_int(max_mtu));
4868700e3e7SMoni Shoua goto err1;
4878700e3e7SMoni Shoua }
4888700e3e7SMoni Shoua }
4898700e3e7SMoni Shoua
4908700e3e7SMoni Shoua if (mask & IB_QP_MAX_QP_RD_ATOMIC) {
4918700e3e7SMoni Shoua if (attr->max_rd_atomic > rxe->attr.max_qp_rd_atom) {
4926af70060SBob Pearson rxe_dbg_qp(qp, "invalid max_rd_atomic %d > %d\n",
4938700e3e7SMoni Shoua attr->max_rd_atomic,
4948700e3e7SMoni Shoua rxe->attr.max_qp_rd_atom);
4958700e3e7SMoni Shoua goto err1;
4968700e3e7SMoni Shoua }
4978700e3e7SMoni Shoua }
4988700e3e7SMoni Shoua
4998700e3e7SMoni Shoua if (mask & IB_QP_TIMEOUT) {
5008700e3e7SMoni Shoua if (attr->timeout > 31) {
5016af70060SBob Pearson rxe_dbg_qp(qp, "invalid timeout %d > 31\n",
5026af70060SBob Pearson attr->timeout);
5038700e3e7SMoni Shoua goto err1;
5048700e3e7SMoni Shoua }
5058700e3e7SMoni Shoua }
5068700e3e7SMoni Shoua
5078700e3e7SMoni Shoua return 0;
5088700e3e7SMoni Shoua
5098700e3e7SMoni Shoua err1:
5108700e3e7SMoni Shoua return -EINVAL;
5118700e3e7SMoni Shoua }
5128700e3e7SMoni Shoua
5138700e3e7SMoni Shoua /* move the qp to the reset state */
rxe_qp_reset(struct rxe_qp * qp)5148700e3e7SMoni Shoua static void rxe_qp_reset(struct rxe_qp *qp)
5158700e3e7SMoni Shoua {
5168700e3e7SMoni Shoua /* stop tasks from running */
5178700e3e7SMoni Shoua rxe_disable_task(&qp->resp.task);
5188700e3e7SMoni Shoua rxe_disable_task(&qp->comp.task);
5198700e3e7SMoni Shoua rxe_disable_task(&qp->req.task);
5208700e3e7SMoni Shoua
521960ebe97SBob Pearson /* drain work and packet queuesc */
522960ebe97SBob Pearson rxe_requester(qp);
523960ebe97SBob Pearson rxe_completer(qp);
524960ebe97SBob Pearson rxe_responder(qp);
5258700e3e7SMoni Shoua
526960ebe97SBob Pearson if (qp->rq.queue)
527960ebe97SBob Pearson rxe_queue_reset(qp->rq.queue);
528960ebe97SBob Pearson if (qp->sq.queue)
529aa75b07bSYonatan Cohen rxe_queue_reset(qp->sq.queue);
5308700e3e7SMoni Shoua
5318700e3e7SMoni Shoua /* cleanup attributes */
5328700e3e7SMoni Shoua atomic_set(&qp->ssn, 0);
5338700e3e7SMoni Shoua qp->req.opcode = -1;
5348700e3e7SMoni Shoua qp->req.need_retry = 0;
535445fd4f4SBob Pearson qp->req.wait_for_rnr_timer = 0;
5368700e3e7SMoni Shoua qp->req.noack_pkts = 0;
5378700e3e7SMoni Shoua qp->resp.msn = 0;
5388700e3e7SMoni Shoua qp->resp.opcode = -1;
5398700e3e7SMoni Shoua qp->resp.drop_msg = 0;
5408700e3e7SMoni Shoua qp->resp.goto_error = 0;
5418700e3e7SMoni Shoua qp->resp.sent_psn_nak = 0;
5428700e3e7SMoni Shoua
5438700e3e7SMoni Shoua if (qp->resp.mr) {
5443197706aSBob Pearson rxe_put(qp->resp.mr);
5458700e3e7SMoni Shoua qp->resp.mr = NULL;
5468700e3e7SMoni Shoua }
5478700e3e7SMoni Shoua
5488700e3e7SMoni Shoua cleanup_rd_atomic_resources(qp);
5498700e3e7SMoni Shoua
5508700e3e7SMoni Shoua /* reenable tasks */
5518700e3e7SMoni Shoua rxe_enable_task(&qp->resp.task);
5528700e3e7SMoni Shoua rxe_enable_task(&qp->comp.task);
5538700e3e7SMoni Shoua rxe_enable_task(&qp->req.task);
5548700e3e7SMoni Shoua }
5558700e3e7SMoni Shoua
5568700e3e7SMoni Shoua /* move the qp to the error state */
rxe_qp_error(struct rxe_qp * qp)5578700e3e7SMoni Shoua void rxe_qp_error(struct rxe_qp *qp)
5588700e3e7SMoni Shoua {
559b5f3fe27SGuoqing Jiang unsigned long flags;
560b5f3fe27SGuoqing Jiang
561b5f3fe27SGuoqing Jiang spin_lock_irqsave(&qp->state_lock, flags);
5626d931308SYonatan Cohen qp->attr.qp_state = IB_QPS_ERR;
5638700e3e7SMoni Shoua
5648700e3e7SMoni Shoua /* drain work and packet queues */
565dccb23f6SBob Pearson rxe_sched_task(&qp->resp.task);
566dccb23f6SBob Pearson rxe_sched_task(&qp->comp.task);
567dccb23f6SBob Pearson rxe_sched_task(&qp->req.task);
568b5f3fe27SGuoqing Jiang spin_unlock_irqrestore(&qp->state_lock, flags);
5698700e3e7SMoni Shoua }
5708700e3e7SMoni Shoua
rxe_qp_sqd(struct rxe_qp * qp,struct ib_qp_attr * attr,int mask)571f605f26eSBob Pearson static void rxe_qp_sqd(struct rxe_qp *qp, struct ib_qp_attr *attr,
572f605f26eSBob Pearson int mask)
573f605f26eSBob Pearson {
574b5f3fe27SGuoqing Jiang unsigned long flags;
575b5f3fe27SGuoqing Jiang
576b5f3fe27SGuoqing Jiang spin_lock_irqsave(&qp->state_lock, flags);
577f605f26eSBob Pearson qp->attr.sq_draining = 1;
578f605f26eSBob Pearson rxe_sched_task(&qp->comp.task);
579f605f26eSBob Pearson rxe_sched_task(&qp->req.task);
580b5f3fe27SGuoqing Jiang spin_unlock_irqrestore(&qp->state_lock, flags);
581f605f26eSBob Pearson }
582f605f26eSBob Pearson
583f605f26eSBob Pearson /* caller should hold qp->state_lock */
__qp_chk_state(struct rxe_qp * qp,struct ib_qp_attr * attr,int mask)584f605f26eSBob Pearson static int __qp_chk_state(struct rxe_qp *qp, struct ib_qp_attr *attr,
585f605f26eSBob Pearson int mask)
586f605f26eSBob Pearson {
587f605f26eSBob Pearson enum ib_qp_state cur_state;
588f605f26eSBob Pearson enum ib_qp_state new_state;
589f605f26eSBob Pearson
590f605f26eSBob Pearson cur_state = (mask & IB_QP_CUR_STATE) ?
591f605f26eSBob Pearson attr->cur_qp_state : qp->attr.qp_state;
592f605f26eSBob Pearson new_state = (mask & IB_QP_STATE) ?
593f605f26eSBob Pearson attr->qp_state : cur_state;
594f605f26eSBob Pearson
595f605f26eSBob Pearson if (!ib_modify_qp_is_ok(cur_state, new_state, qp_type(qp), mask))
596f605f26eSBob Pearson return -EINVAL;
597f605f26eSBob Pearson
598f605f26eSBob Pearson if (mask & IB_QP_STATE && cur_state == IB_QPS_SQD) {
599f605f26eSBob Pearson if (qp->attr.sq_draining && new_state != IB_QPS_ERR)
600f605f26eSBob Pearson return -EINVAL;
601f605f26eSBob Pearson }
602f605f26eSBob Pearson
603f605f26eSBob Pearson return 0;
604f605f26eSBob Pearson }
605f605f26eSBob Pearson
606f605f26eSBob Pearson static const char *const qps2str[] = {
607f605f26eSBob Pearson [IB_QPS_RESET] = "RESET",
608f605f26eSBob Pearson [IB_QPS_INIT] = "INIT",
609f605f26eSBob Pearson [IB_QPS_RTR] = "RTR",
610f605f26eSBob Pearson [IB_QPS_RTS] = "RTS",
611f605f26eSBob Pearson [IB_QPS_SQD] = "SQD",
612f605f26eSBob Pearson [IB_QPS_SQE] = "SQE",
613f605f26eSBob Pearson [IB_QPS_ERR] = "ERR",
614f605f26eSBob Pearson };
615f605f26eSBob Pearson
6168700e3e7SMoni Shoua /* called by the modify qp verb */
rxe_qp_from_attr(struct rxe_qp * qp,struct ib_qp_attr * attr,int mask,struct ib_udata * udata)6178700e3e7SMoni Shoua int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask,
6188700e3e7SMoni Shoua struct ib_udata *udata)
6198700e3e7SMoni Shoua {
6208700e3e7SMoni Shoua int err;
6218700e3e7SMoni Shoua
622f605f26eSBob Pearson if (mask & IB_QP_CUR_STATE)
623f605f26eSBob Pearson qp->attr.cur_qp_state = attr->qp_state;
624f605f26eSBob Pearson
625f605f26eSBob Pearson if (mask & IB_QP_STATE) {
626b5f3fe27SGuoqing Jiang unsigned long flags;
627b5f3fe27SGuoqing Jiang
628b5f3fe27SGuoqing Jiang spin_lock_irqsave(&qp->state_lock, flags);
629f605f26eSBob Pearson err = __qp_chk_state(qp, attr, mask);
630f605f26eSBob Pearson if (!err) {
631f605f26eSBob Pearson qp->attr.qp_state = attr->qp_state;
632f605f26eSBob Pearson rxe_dbg_qp(qp, "state -> %s\n",
633f605f26eSBob Pearson qps2str[attr->qp_state]);
634f605f26eSBob Pearson }
635b5f3fe27SGuoqing Jiang spin_unlock_irqrestore(&qp->state_lock, flags);
636f605f26eSBob Pearson
637f605f26eSBob Pearson if (err)
638f605f26eSBob Pearson return err;
639f605f26eSBob Pearson
640f605f26eSBob Pearson switch (attr->qp_state) {
641f605f26eSBob Pearson case IB_QPS_RESET:
642f605f26eSBob Pearson rxe_qp_reset(qp);
643f605f26eSBob Pearson break;
644f605f26eSBob Pearson case IB_QPS_SQD:
645f605f26eSBob Pearson rxe_qp_sqd(qp, attr, mask);
646f605f26eSBob Pearson break;
647f605f26eSBob Pearson case IB_QPS_ERR:
648f605f26eSBob Pearson rxe_qp_error(qp);
649f605f26eSBob Pearson break;
650f605f26eSBob Pearson default:
651f605f26eSBob Pearson break;
652f605f26eSBob Pearson }
653f605f26eSBob Pearson }
654f605f26eSBob Pearson
6558700e3e7SMoni Shoua if (mask & IB_QP_MAX_QP_RD_ATOMIC) {
656fb3063d3SBart Van Assche int max_rd_atomic = attr->max_rd_atomic ?
657fb3063d3SBart Van Assche roundup_pow_of_two(attr->max_rd_atomic) : 0;
6588700e3e7SMoni Shoua
6598700e3e7SMoni Shoua qp->attr.max_rd_atomic = max_rd_atomic;
6608700e3e7SMoni Shoua atomic_set(&qp->req.rd_atomic, max_rd_atomic);
6618700e3e7SMoni Shoua }
6628700e3e7SMoni Shoua
663b6bbee0dSParav Pandit if (mask & IB_QP_MAX_DEST_RD_ATOMIC) {
664fb3063d3SBart Van Assche int max_dest_rd_atomic = attr->max_dest_rd_atomic ?
665fb3063d3SBart Van Assche roundup_pow_of_two(attr->max_dest_rd_atomic) : 0;
666b6bbee0dSParav Pandit
667b6bbee0dSParav Pandit qp->attr.max_dest_rd_atomic = max_dest_rd_atomic;
668b6bbee0dSParav Pandit
669b6bbee0dSParav Pandit free_rd_atomic_resources(qp);
670b6bbee0dSParav Pandit
671b6bbee0dSParav Pandit err = alloc_rd_atomic_resources(qp, max_dest_rd_atomic);
672b6bbee0dSParav Pandit if (err)
673b6bbee0dSParav Pandit return err;
674b6bbee0dSParav Pandit }
675b6bbee0dSParav Pandit
6768700e3e7SMoni Shoua if (mask & IB_QP_EN_SQD_ASYNC_NOTIFY)
6778700e3e7SMoni Shoua qp->attr.en_sqd_async_notify = attr->en_sqd_async_notify;
6788700e3e7SMoni Shoua
6798700e3e7SMoni Shoua if (mask & IB_QP_ACCESS_FLAGS)
6808700e3e7SMoni Shoua qp->attr.qp_access_flags = attr->qp_access_flags;
6818700e3e7SMoni Shoua
6828700e3e7SMoni Shoua if (mask & IB_QP_PKEY_INDEX)
6838700e3e7SMoni Shoua qp->attr.pkey_index = attr->pkey_index;
6848700e3e7SMoni Shoua
6858700e3e7SMoni Shoua if (mask & IB_QP_PORT)
6868700e3e7SMoni Shoua qp->attr.port_num = attr->port_num;
6878700e3e7SMoni Shoua
6888700e3e7SMoni Shoua if (mask & IB_QP_QKEY)
6898700e3e7SMoni Shoua qp->attr.qkey = attr->qkey;
6908700e3e7SMoni Shoua
6915f9e2822SBob Pearson if (mask & IB_QP_AV)
692fa407188SKamal Heib rxe_init_av(&attr->ah_attr, &qp->pri_av);
6938700e3e7SMoni Shoua
6948700e3e7SMoni Shoua if (mask & IB_QP_ALT_PATH) {
695fa407188SKamal Heib rxe_init_av(&attr->alt_ah_attr, &qp->alt_av);
6968700e3e7SMoni Shoua qp->attr.alt_port_num = attr->alt_port_num;
6978700e3e7SMoni Shoua qp->attr.alt_pkey_index = attr->alt_pkey_index;
6988700e3e7SMoni Shoua qp->attr.alt_timeout = attr->alt_timeout;
6998700e3e7SMoni Shoua }
7008700e3e7SMoni Shoua
7018700e3e7SMoni Shoua if (mask & IB_QP_PATH_MTU) {
7028700e3e7SMoni Shoua qp->attr.path_mtu = attr->path_mtu;
7038700e3e7SMoni Shoua qp->mtu = ib_mtu_enum_to_int(attr->path_mtu);
7048700e3e7SMoni Shoua }
7058700e3e7SMoni Shoua
7068700e3e7SMoni Shoua if (mask & IB_QP_TIMEOUT) {
7078700e3e7SMoni Shoua qp->attr.timeout = attr->timeout;
7088700e3e7SMoni Shoua if (attr->timeout == 0) {
7098700e3e7SMoni Shoua qp->qp_timeout_jiffies = 0;
7108700e3e7SMoni Shoua } else {
7118700e3e7SMoni Shoua /* According to the spec, timeout = 4.096 * 2 ^ attr->timeout [us] */
7128700e3e7SMoni Shoua int j = nsecs_to_jiffies(4096ULL << attr->timeout);
7138700e3e7SMoni Shoua
7148700e3e7SMoni Shoua qp->qp_timeout_jiffies = j ? j : 1;
7158700e3e7SMoni Shoua }
7168700e3e7SMoni Shoua }
7178700e3e7SMoni Shoua
7188700e3e7SMoni Shoua if (mask & IB_QP_RETRY_CNT) {
7198700e3e7SMoni Shoua qp->attr.retry_cnt = attr->retry_cnt;
7208700e3e7SMoni Shoua qp->comp.retry_cnt = attr->retry_cnt;
7216af70060SBob Pearson rxe_dbg_qp(qp, "set retry count = %d\n", attr->retry_cnt);
7228700e3e7SMoni Shoua }
7238700e3e7SMoni Shoua
7248700e3e7SMoni Shoua if (mask & IB_QP_RNR_RETRY) {
7258700e3e7SMoni Shoua qp->attr.rnr_retry = attr->rnr_retry;
7268700e3e7SMoni Shoua qp->comp.rnr_retry = attr->rnr_retry;
7276af70060SBob Pearson rxe_dbg_qp(qp, "set rnr retry count = %d\n", attr->rnr_retry);
7288700e3e7SMoni Shoua }
7298700e3e7SMoni Shoua
7308700e3e7SMoni Shoua if (mask & IB_QP_RQ_PSN) {
7318700e3e7SMoni Shoua qp->attr.rq_psn = (attr->rq_psn & BTH_PSN_MASK);
7328700e3e7SMoni Shoua qp->resp.psn = qp->attr.rq_psn;
7336af70060SBob Pearson rxe_dbg_qp(qp, "set resp psn = 0x%x\n", qp->resp.psn);
7348700e3e7SMoni Shoua }
7358700e3e7SMoni Shoua
7368700e3e7SMoni Shoua if (mask & IB_QP_MIN_RNR_TIMER) {
7378700e3e7SMoni Shoua qp->attr.min_rnr_timer = attr->min_rnr_timer;
7386af70060SBob Pearson rxe_dbg_qp(qp, "set min rnr timer = 0x%x\n",
7398700e3e7SMoni Shoua attr->min_rnr_timer);
7408700e3e7SMoni Shoua }
7418700e3e7SMoni Shoua
7428700e3e7SMoni Shoua if (mask & IB_QP_SQ_PSN) {
7438700e3e7SMoni Shoua qp->attr.sq_psn = (attr->sq_psn & BTH_PSN_MASK);
7448700e3e7SMoni Shoua qp->req.psn = qp->attr.sq_psn;
7458700e3e7SMoni Shoua qp->comp.psn = qp->attr.sq_psn;
7466af70060SBob Pearson rxe_dbg_qp(qp, "set req psn = 0x%x\n", qp->req.psn);
7478700e3e7SMoni Shoua }
7488700e3e7SMoni Shoua
7498700e3e7SMoni Shoua if (mask & IB_QP_PATH_MIG_STATE)
7508700e3e7SMoni Shoua qp->attr.path_mig_state = attr->path_mig_state;
7518700e3e7SMoni Shoua
7528700e3e7SMoni Shoua if (mask & IB_QP_DEST_QPN)
7538700e3e7SMoni Shoua qp->attr.dest_qp_num = attr->dest_qp_num;
7548700e3e7SMoni Shoua
7558700e3e7SMoni Shoua return 0;
7568700e3e7SMoni Shoua }
7578700e3e7SMoni Shoua
7588700e3e7SMoni Shoua /* called by the query qp verb */
rxe_qp_to_attr(struct rxe_qp * qp,struct ib_qp_attr * attr,int mask)7598700e3e7SMoni Shoua int rxe_qp_to_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask)
7608700e3e7SMoni Shoua {
761b5f3fe27SGuoqing Jiang unsigned long flags;
762b5f3fe27SGuoqing Jiang
7638700e3e7SMoni Shoua *attr = qp->attr;
7648700e3e7SMoni Shoua
7658700e3e7SMoni Shoua attr->rq_psn = qp->resp.psn;
7668700e3e7SMoni Shoua attr->sq_psn = qp->req.psn;
7678700e3e7SMoni Shoua
7688700e3e7SMoni Shoua attr->cap.max_send_wr = qp->sq.max_wr;
7698700e3e7SMoni Shoua attr->cap.max_send_sge = qp->sq.max_sge;
7708700e3e7SMoni Shoua attr->cap.max_inline_data = qp->sq.max_inline;
7718700e3e7SMoni Shoua
7728700e3e7SMoni Shoua if (!qp->srq) {
7738700e3e7SMoni Shoua attr->cap.max_recv_wr = qp->rq.max_wr;
7748700e3e7SMoni Shoua attr->cap.max_recv_sge = qp->rq.max_sge;
7758700e3e7SMoni Shoua }
7768700e3e7SMoni Shoua
7779c96f3d4SZhu Yanjun rxe_av_to_attr(&qp->pri_av, &attr->ah_attr);
7789c96f3d4SZhu Yanjun rxe_av_to_attr(&qp->alt_av, &attr->alt_ah_attr);
7798700e3e7SMoni Shoua
78098e891b5SBob Pearson /* Applications that get this state typically spin on it.
78198e891b5SBob Pearson * Yield the processor
7828700e3e7SMoni Shoua */
783b5f3fe27SGuoqing Jiang spin_lock_irqsave(&qp->state_lock, flags);
784e435f311SLiu Jian attr->cur_qp_state = qp_state(qp);
785f605f26eSBob Pearson if (qp->attr.sq_draining) {
786b5f3fe27SGuoqing Jiang spin_unlock_irqrestore(&qp->state_lock, flags);
7878700e3e7SMoni Shoua cond_resched();
78817eabd6aSBob Pearson } else {
789b5f3fe27SGuoqing Jiang spin_unlock_irqrestore(&qp->state_lock, flags);
790f605f26eSBob Pearson }
7918700e3e7SMoni Shoua
7928700e3e7SMoni Shoua return 0;
7938700e3e7SMoni Shoua }
7948700e3e7SMoni Shoua
rxe_qp_chk_destroy(struct rxe_qp * qp)795f9f48460SBob Pearson int rxe_qp_chk_destroy(struct rxe_qp *qp)
796f9f48460SBob Pearson {
797f9f48460SBob Pearson /* See IBA o10-2.2.3
798f9f48460SBob Pearson * An attempt to destroy a QP while attached to a mcast group
799f9f48460SBob Pearson * will fail immediately.
800f9f48460SBob Pearson */
801f9f48460SBob Pearson if (atomic_read(&qp->mcg_num)) {
8026af70060SBob Pearson rxe_dbg_qp(qp, "Attempt to destroy while attached to multicast group\n");
803f9f48460SBob Pearson return -EBUSY;
804f9f48460SBob Pearson }
805f9f48460SBob Pearson
806f9f48460SBob Pearson return 0;
807f9f48460SBob Pearson }
808f9f48460SBob Pearson
809ed2b5dd0SBob Pearson /* called when the last reference to the qp is dropped */
rxe_qp_do_cleanup(struct work_struct * work)810ed2b5dd0SBob Pearson static void rxe_qp_do_cleanup(struct work_struct *work)
8118700e3e7SMoni Shoua {
812ed2b5dd0SBob Pearson struct rxe_qp *qp = container_of(work, typeof(*qp), cleanup_work.work);
813b5f3fe27SGuoqing Jiang unsigned long flags;
814ed2b5dd0SBob Pearson
815b5f3fe27SGuoqing Jiang spin_lock_irqsave(&qp->state_lock, flags);
8168700e3e7SMoni Shoua qp->valid = 0;
817b5f3fe27SGuoqing Jiang spin_unlock_irqrestore(&qp->state_lock, flags);
8188700e3e7SMoni Shoua qp->qp_timeout_jiffies = 0;
8198700e3e7SMoni Shoua
82099fc12f6SParav Pandit if (qp_type(qp) == IB_QPT_RC) {
8218700e3e7SMoni Shoua del_timer_sync(&qp->retrans_timer);
8228700e3e7SMoni Shoua del_timer_sync(&qp->rnr_nak_timer);
82399fc12f6SParav Pandit }
8248700e3e7SMoni Shoua
825b2b1ddc4SZhu Yanjun if (qp->resp.task.func)
826960ebe97SBob Pearson rxe_cleanup_task(&qp->resp.task);
827b2b1ddc4SZhu Yanjun
828b2b1ddc4SZhu Yanjun if (qp->req.task.func)
8298700e3e7SMoni Shoua rxe_cleanup_task(&qp->req.task);
830b2b1ddc4SZhu Yanjun
831b2b1ddc4SZhu Yanjun if (qp->comp.task.func)
8328700e3e7SMoni Shoua rxe_cleanup_task(&qp->comp.task);
8338700e3e7SMoni Shoua
8348700e3e7SMoni Shoua /* flush out any receive wr's or pending requests */
835960ebe97SBob Pearson rxe_requester(qp);
836960ebe97SBob Pearson rxe_completer(qp);
837960ebe97SBob Pearson rxe_responder(qp);
8388700e3e7SMoni Shoua
8398700e3e7SMoni Shoua if (qp->sq.queue)
8408700e3e7SMoni Shoua rxe_queue_cleanup(qp->sq.queue);
8418700e3e7SMoni Shoua
8428700e3e7SMoni Shoua if (qp->srq)
8433197706aSBob Pearson rxe_put(qp->srq);
8448700e3e7SMoni Shoua
8458700e3e7SMoni Shoua if (qp->rq.queue)
8468700e3e7SMoni Shoua rxe_queue_cleanup(qp->rq.queue);
8478700e3e7SMoni Shoua
84837da51efSZhu Yanjun if (qp->scq) {
8494703b4f0SBob Pearson atomic_dec(&qp->scq->num_wq);
8503197706aSBob Pearson rxe_put(qp->scq);
85137da51efSZhu Yanjun }
8524703b4f0SBob Pearson
85337da51efSZhu Yanjun if (qp->rcq) {
8544703b4f0SBob Pearson atomic_dec(&qp->rcq->num_wq);
8553197706aSBob Pearson rxe_put(qp->rcq);
85637da51efSZhu Yanjun }
8574703b4f0SBob Pearson
8588700e3e7SMoni Shoua if (qp->pd)
8593197706aSBob Pearson rxe_put(qp->pd);
8608700e3e7SMoni Shoua
8618a1a0be8SBob Pearson if (qp->resp.mr)
8623197706aSBob Pearson rxe_put(qp->resp.mr);
8638700e3e7SMoni Shoua
8648700e3e7SMoni Shoua free_rd_atomic_resources(qp);
8658700e3e7SMoni Shoua
866548ce2e6SZhu Yanjun if (qp->sk) {
867f67376d8SZhang Xiaoxu if (qp_type(qp) == IB_QPT_RC)
868f67376d8SZhang Xiaoxu sk_dst_reset(qp->sk->sk);
869f67376d8SZhang Xiaoxu
8708700e3e7SMoni Shoua kernel_sock_shutdown(qp->sk, SHUT_RDWR);
871e259934dSBart Van Assche sock_release(qp->sk);
8728700e3e7SMoni Shoua }
873548ce2e6SZhu Yanjun }
874bb3ffb7aSBart Van Assche
875bb3ffb7aSBart Van Assche /* called when the last reference to the qp is dropped */
rxe_qp_cleanup(struct rxe_pool_elem * elem)87602827b67SBob Pearson void rxe_qp_cleanup(struct rxe_pool_elem *elem)
877bb3ffb7aSBart Van Assche {
87802827b67SBob Pearson struct rxe_qp *qp = container_of(elem, typeof(*qp), elem);
879bb3ffb7aSBart Van Assche
880bb3ffb7aSBart Van Assche execute_in_process_context(rxe_qp_do_cleanup, &qp->cleanup_work);
881bb3ffb7aSBart Van Assche }
882