xref: /linux/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
1 /*
2  * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  *
32  */
33 #include <linux/bug.h>
34 #include <linux/errno.h>
35 #include <linux/module.h>
36 #include <linux/spinlock.h>
37 
38 #include "usnic_log.h"
39 #include "usnic_vnic.h"
40 #include "usnic_fwd.h"
41 #include "usnic_uiom.h"
42 #include "usnic_debugfs.h"
43 #include "usnic_ib_qp_grp.h"
44 #include "usnic_ib_sysfs.h"
45 #include "usnic_transport.h"
46 
47 #define DFLT_RQ_IDX	0
48 
49 const char *usnic_ib_qp_grp_state_to_string(enum ib_qp_state state)
50 {
51 	switch (state) {
52 	case IB_QPS_RESET:
53 		return "Rst";
54 	case IB_QPS_INIT:
55 		return "Init";
56 	case IB_QPS_RTR:
57 		return "RTR";
58 	case IB_QPS_RTS:
59 		return "RTS";
60 	case IB_QPS_SQD:
61 		return "SQD";
62 	case IB_QPS_SQE:
63 		return "SQE";
64 	case IB_QPS_ERR:
65 		return "ERR";
66 	default:
67 		return "UNKOWN STATE";
68 
69 	}
70 }
71 
72 int usnic_ib_qp_grp_dump_hdr(char *buf, int buf_sz)
73 {
74 	return scnprintf(buf, buf_sz, "|QPN\t|State\t|PID\t|VF Idx\t|Fil ID");
75 }
76 
77 int usnic_ib_qp_grp_dump_rows(void *obj, char *buf, int buf_sz)
78 {
79 	struct usnic_ib_qp_grp *qp_grp = obj;
80 	struct usnic_ib_qp_grp_flow *default_flow;
81 	if (obj) {
82 		default_flow = list_first_entry(&qp_grp->flows_lst,
83 					struct usnic_ib_qp_grp_flow, link);
84 		return scnprintf(buf, buf_sz, "|%d\t|%s\t|%d\t|%hu\t|%d",
85 					qp_grp->ibqp.qp_num,
86 					usnic_ib_qp_grp_state_to_string(
87 							qp_grp->state),
88 					qp_grp->owner_pid,
89 					usnic_vnic_get_index(qp_grp->vf->vnic),
90 					default_flow->flow->flow_id);
91 	} else {
92 		return scnprintf(buf, buf_sz, "|N/A\t|N/A\t|N/A\t|N/A\t|N/A");
93 	}
94 }
95 
96 static struct usnic_vnic_res_chunk *
97 get_qp_res_chunk(struct usnic_ib_qp_grp *qp_grp)
98 {
99 	lockdep_assert_held(&qp_grp->lock);
100 	/*
101 	 * The QP res chunk, used to derive qp indices,
102 	 * are just indices of the RQs
103 	 */
104 	return usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_RQ);
105 }
106 
107 static int enable_qp_grp(struct usnic_ib_qp_grp *qp_grp)
108 {
109 
110 	int status;
111 	int i, vnic_idx;
112 	struct usnic_vnic_res_chunk *res_chunk;
113 	struct usnic_vnic_res *res;
114 
115 	lockdep_assert_held(&qp_grp->lock);
116 
117 	vnic_idx = usnic_vnic_get_index(qp_grp->vf->vnic);
118 
119 	res_chunk = get_qp_res_chunk(qp_grp);
120 	if (IS_ERR_OR_NULL(res_chunk)) {
121 		usnic_err("Unable to get qp res with err %ld\n",
122 				PTR_ERR(res_chunk));
123 		return res_chunk ? PTR_ERR(res_chunk) : -ENOMEM;
124 	}
125 
126 	for (i = 0; i < res_chunk->cnt; i++) {
127 		res = res_chunk->res[i];
128 		status = usnic_fwd_enable_qp(qp_grp->ufdev, vnic_idx,
129 						res->vnic_idx);
130 		if (status) {
131 			usnic_err("Failed to enable qp %d of %s:%d\n with err %d\n",
132 					res->vnic_idx, qp_grp->ufdev->name,
133 					vnic_idx, status);
134 			goto out_err;
135 		}
136 	}
137 
138 	return 0;
139 
140 out_err:
141 	for (i--; i >= 0; i--) {
142 		res = res_chunk->res[i];
143 		usnic_fwd_disable_qp(qp_grp->ufdev, vnic_idx,
144 					res->vnic_idx);
145 	}
146 
147 	return status;
148 }
149 
150 static int disable_qp_grp(struct usnic_ib_qp_grp *qp_grp)
151 {
152 	int i, vnic_idx;
153 	struct usnic_vnic_res_chunk *res_chunk;
154 	struct usnic_vnic_res *res;
155 	int status = 0;
156 
157 	lockdep_assert_held(&qp_grp->lock);
158 	vnic_idx = usnic_vnic_get_index(qp_grp->vf->vnic);
159 
160 	res_chunk = get_qp_res_chunk(qp_grp);
161 	if (IS_ERR_OR_NULL(res_chunk)) {
162 		usnic_err("Unable to get qp res with err %ld\n",
163 			PTR_ERR(res_chunk));
164 		return res_chunk ? PTR_ERR(res_chunk) : -ENOMEM;
165 	}
166 
167 	for (i = 0; i < res_chunk->cnt; i++) {
168 		res = res_chunk->res[i];
169 		status = usnic_fwd_disable_qp(qp_grp->ufdev, vnic_idx,
170 						res->vnic_idx);
171 		if (status) {
172 			usnic_err("Failed to disable rq %d of %s:%d\n with err %d\n",
173 					res->vnic_idx,
174 					qp_grp->ufdev->name,
175 					vnic_idx, status);
176 		}
177 	}
178 
179 	return status;
180 
181 }
182 
183 static int init_filter_action(struct usnic_ib_qp_grp *qp_grp,
184 				struct usnic_filter_action *uaction)
185 {
186 	struct usnic_vnic_res_chunk *res_chunk;
187 
188 	res_chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_RQ);
189 	if (IS_ERR_OR_NULL(res_chunk)) {
190 		usnic_err("Unable to get %s with err %ld\n",
191 			usnic_vnic_res_type_to_str(USNIC_VNIC_RES_TYPE_RQ),
192 			PTR_ERR(res_chunk));
193 		return res_chunk ? PTR_ERR(res_chunk) : -ENOMEM;
194 	}
195 
196 	uaction->vnic_idx = usnic_vnic_get_index(qp_grp->vf->vnic);
197 	uaction->action.type = FILTER_ACTION_RQ_STEERING;
198 	uaction->action.u.rq_idx = res_chunk->res[DFLT_RQ_IDX]->vnic_idx;
199 
200 	return 0;
201 }
202 
203 static struct usnic_ib_qp_grp_flow*
204 create_roce_custom_flow(struct usnic_ib_qp_grp *qp_grp,
205 			struct usnic_transport_spec *trans_spec)
206 {
207 	uint16_t port_num;
208 	int err;
209 	struct filter filter;
210 	struct usnic_filter_action uaction;
211 	struct usnic_ib_qp_grp_flow *qp_flow;
212 	struct usnic_fwd_flow *flow;
213 	enum usnic_transport_type trans_type;
214 
215 	trans_type = trans_spec->trans_type;
216 	port_num = trans_spec->usnic_roce.port_num;
217 
218 	/* Reserve Port */
219 	port_num = usnic_transport_rsrv_port(trans_type, port_num);
220 	if (port_num == 0)
221 		return ERR_PTR(-EINVAL);
222 
223 	/* Create Flow */
224 	usnic_fwd_init_usnic_filter(&filter, port_num);
225 	err = init_filter_action(qp_grp, &uaction);
226 	if (err)
227 		goto out_unreserve_port;
228 
229 	flow = usnic_fwd_alloc_flow(qp_grp->ufdev, &filter, &uaction);
230 	if (IS_ERR_OR_NULL(flow)) {
231 		usnic_err("Unable to alloc flow failed with err %ld\n",
232 				PTR_ERR(flow));
233 		err = flow ? PTR_ERR(flow) : -EFAULT;
234 		goto out_unreserve_port;
235 	}
236 
237 	/* Create Flow Handle */
238 	qp_flow = kzalloc(sizeof(*qp_flow), GFP_ATOMIC);
239 	if (IS_ERR_OR_NULL(qp_flow)) {
240 		err = qp_flow ? PTR_ERR(qp_flow) : -ENOMEM;
241 		goto out_dealloc_flow;
242 	}
243 	qp_flow->flow = flow;
244 	qp_flow->trans_type = trans_type;
245 	qp_flow->usnic_roce.port_num = port_num;
246 	qp_flow->qp_grp = qp_grp;
247 	return qp_flow;
248 
249 out_dealloc_flow:
250 	usnic_fwd_dealloc_flow(flow);
251 out_unreserve_port:
252 	usnic_transport_unrsrv_port(trans_type, port_num);
253 	return ERR_PTR(err);
254 }
255 
256 static void release_roce_custom_flow(struct usnic_ib_qp_grp_flow *qp_flow)
257 {
258 	usnic_fwd_dealloc_flow(qp_flow->flow);
259 	usnic_transport_unrsrv_port(qp_flow->trans_type,
260 					qp_flow->usnic_roce.port_num);
261 	kfree(qp_flow);
262 }
263 
264 static struct usnic_ib_qp_grp_flow*
265 create_udp_flow(struct usnic_ib_qp_grp *qp_grp,
266 		struct usnic_transport_spec *trans_spec)
267 {
268 	struct socket *sock;
269 	int sock_fd;
270 	int err;
271 	struct filter filter;
272 	struct usnic_filter_action uaction;
273 	struct usnic_ib_qp_grp_flow *qp_flow;
274 	struct usnic_fwd_flow *flow;
275 	enum usnic_transport_type trans_type;
276 	uint32_t addr;
277 	uint16_t port_num;
278 	int proto;
279 
280 	trans_type = trans_spec->trans_type;
281 	sock_fd = trans_spec->udp.sock_fd;
282 
283 	/* Get and check socket */
284 	sock = usnic_transport_get_socket(sock_fd);
285 	if (IS_ERR_OR_NULL(sock))
286 		return ERR_CAST(sock);
287 
288 	err = usnic_transport_sock_get_addr(sock, &proto, &addr, &port_num);
289 	if (err)
290 		goto out_put_sock;
291 
292 	if (proto != IPPROTO_UDP) {
293 		usnic_err("Protocol for fd %d is not UDP", sock_fd);
294 		err = -EPERM;
295 		goto out_put_sock;
296 	}
297 
298 	/* Create flow */
299 	usnic_fwd_init_udp_filter(&filter, addr, port_num);
300 	err = init_filter_action(qp_grp, &uaction);
301 	if (err)
302 		goto out_put_sock;
303 
304 	flow = usnic_fwd_alloc_flow(qp_grp->ufdev, &filter, &uaction);
305 	if (IS_ERR_OR_NULL(flow)) {
306 		usnic_err("Unable to alloc flow failed with err %ld\n",
307 				PTR_ERR(flow));
308 		err = flow ? PTR_ERR(flow) : -EFAULT;
309 		goto out_put_sock;
310 	}
311 
312 	/* Create qp_flow */
313 	qp_flow = kzalloc(sizeof(*qp_flow), GFP_ATOMIC);
314 	if (IS_ERR_OR_NULL(qp_flow)) {
315 		err = qp_flow ? PTR_ERR(qp_flow) : -ENOMEM;
316 		goto out_dealloc_flow;
317 	}
318 	qp_flow->flow = flow;
319 	qp_flow->trans_type = trans_type;
320 	qp_flow->udp.sock = sock;
321 	qp_flow->qp_grp = qp_grp;
322 	return qp_flow;
323 
324 out_dealloc_flow:
325 	usnic_fwd_dealloc_flow(flow);
326 out_put_sock:
327 	usnic_transport_put_socket(sock);
328 	return ERR_PTR(err);
329 }
330 
331 static void release_udp_flow(struct usnic_ib_qp_grp_flow *qp_flow)
332 {
333 	usnic_fwd_dealloc_flow(qp_flow->flow);
334 	usnic_transport_put_socket(qp_flow->udp.sock);
335 	kfree(qp_flow);
336 }
337 
338 static struct usnic_ib_qp_grp_flow*
339 create_and_add_flow(struct usnic_ib_qp_grp *qp_grp,
340 			struct usnic_transport_spec *trans_spec)
341 {
342 	struct usnic_ib_qp_grp_flow *qp_flow;
343 	enum usnic_transport_type trans_type;
344 
345 	trans_type = trans_spec->trans_type;
346 	switch (trans_type) {
347 	case USNIC_TRANSPORT_ROCE_CUSTOM:
348 		qp_flow = create_roce_custom_flow(qp_grp, trans_spec);
349 		break;
350 	case USNIC_TRANSPORT_IPV4_UDP:
351 		qp_flow = create_udp_flow(qp_grp, trans_spec);
352 		break;
353 	default:
354 		usnic_err("Unsupported transport %u\n",
355 				trans_spec->trans_type);
356 		return ERR_PTR(-EINVAL);
357 	}
358 
359 	if (!IS_ERR_OR_NULL(qp_flow)) {
360 		list_add_tail(&qp_flow->link, &qp_grp->flows_lst);
361 		usnic_debugfs_flow_add(qp_flow);
362 	}
363 
364 
365 	return qp_flow;
366 }
367 
368 static void release_and_remove_flow(struct usnic_ib_qp_grp_flow *qp_flow)
369 {
370 	usnic_debugfs_flow_remove(qp_flow);
371 	list_del(&qp_flow->link);
372 
373 	switch (qp_flow->trans_type) {
374 	case USNIC_TRANSPORT_ROCE_CUSTOM:
375 		release_roce_custom_flow(qp_flow);
376 		break;
377 	case USNIC_TRANSPORT_IPV4_UDP:
378 		release_udp_flow(qp_flow);
379 		break;
380 	default:
381 		WARN(1, "Unsupported transport %u\n",
382 				qp_flow->trans_type);
383 		break;
384 	}
385 }
386 
387 static void release_and_remove_all_flows(struct usnic_ib_qp_grp *qp_grp)
388 {
389 	struct usnic_ib_qp_grp_flow *qp_flow, *tmp;
390 	list_for_each_entry_safe(qp_flow, tmp, &qp_grp->flows_lst, link)
391 		release_and_remove_flow(qp_flow);
392 }
393 
394 int usnic_ib_qp_grp_modify(struct usnic_ib_qp_grp *qp_grp,
395 				enum ib_qp_state new_state,
396 				void *data)
397 {
398 	int status = 0;
399 	int vnic_idx;
400 	struct ib_event ib_event;
401 	enum ib_qp_state old_state;
402 	struct usnic_transport_spec *trans_spec;
403 	struct usnic_ib_qp_grp_flow *qp_flow;
404 
405 	old_state = qp_grp->state;
406 	vnic_idx = usnic_vnic_get_index(qp_grp->vf->vnic);
407 	trans_spec = (struct usnic_transport_spec *) data;
408 
409 	spin_lock(&qp_grp->lock);
410 	switch (new_state) {
411 	case IB_QPS_RESET:
412 		switch (old_state) {
413 		case IB_QPS_RESET:
414 			/* NO-OP */
415 			break;
416 		case IB_QPS_INIT:
417 			release_and_remove_all_flows(qp_grp);
418 			status = 0;
419 			break;
420 		case IB_QPS_RTR:
421 		case IB_QPS_RTS:
422 		case IB_QPS_ERR:
423 			status = disable_qp_grp(qp_grp);
424 			release_and_remove_all_flows(qp_grp);
425 			break;
426 		default:
427 			status = -EINVAL;
428 		}
429 		break;
430 	case IB_QPS_INIT:
431 		switch (old_state) {
432 		case IB_QPS_RESET:
433 			if (trans_spec) {
434 				qp_flow = create_and_add_flow(qp_grp,
435 								trans_spec);
436 				if (IS_ERR_OR_NULL(qp_flow)) {
437 					status = qp_flow ? PTR_ERR(qp_flow) : -EFAULT;
438 					break;
439 				}
440 			} else {
441 				/*
442 				 * Optional to specify filters.
443 				 */
444 				status = 0;
445 			}
446 			break;
447 		case IB_QPS_INIT:
448 			if (trans_spec) {
449 				qp_flow = create_and_add_flow(qp_grp,
450 								trans_spec);
451 				if (IS_ERR_OR_NULL(qp_flow)) {
452 					status = qp_flow ? PTR_ERR(qp_flow) : -EFAULT;
453 					break;
454 				}
455 			} else {
456 				/*
457 				 * Doesn't make sense to go into INIT state
458 				 * from INIT state w/o adding filters.
459 				 */
460 				status = -EINVAL;
461 			}
462 			break;
463 		case IB_QPS_RTR:
464 			status = disable_qp_grp(qp_grp);
465 			break;
466 		case IB_QPS_RTS:
467 			status = disable_qp_grp(qp_grp);
468 			break;
469 		default:
470 			status = -EINVAL;
471 		}
472 		break;
473 	case IB_QPS_RTR:
474 		switch (old_state) {
475 		case IB_QPS_INIT:
476 			status = enable_qp_grp(qp_grp);
477 			break;
478 		default:
479 			status = -EINVAL;
480 		}
481 		break;
482 	case IB_QPS_RTS:
483 		switch (old_state) {
484 		case IB_QPS_RTR:
485 			/* NO-OP FOR NOW */
486 			break;
487 		default:
488 			status = -EINVAL;
489 		}
490 		break;
491 	case IB_QPS_ERR:
492 		ib_event.device = &qp_grp->vf->pf->ib_dev;
493 		ib_event.element.qp = &qp_grp->ibqp;
494 		ib_event.event = IB_EVENT_QP_FATAL;
495 
496 		switch (old_state) {
497 		case IB_QPS_RESET:
498 			qp_grp->ibqp.event_handler(&ib_event,
499 					qp_grp->ibqp.qp_context);
500 			break;
501 		case IB_QPS_INIT:
502 			release_and_remove_all_flows(qp_grp);
503 			qp_grp->ibqp.event_handler(&ib_event,
504 					qp_grp->ibqp.qp_context);
505 			break;
506 		case IB_QPS_RTR:
507 		case IB_QPS_RTS:
508 			status = disable_qp_grp(qp_grp);
509 			release_and_remove_all_flows(qp_grp);
510 			qp_grp->ibqp.event_handler(&ib_event,
511 					qp_grp->ibqp.qp_context);
512 			break;
513 		default:
514 			status = -EINVAL;
515 		}
516 		break;
517 	default:
518 		status = -EINVAL;
519 	}
520 	spin_unlock(&qp_grp->lock);
521 
522 	if (!status) {
523 		qp_grp->state = new_state;
524 		usnic_info("Transistioned %u from %s to %s",
525 		qp_grp->grp_id,
526 		usnic_ib_qp_grp_state_to_string(old_state),
527 		usnic_ib_qp_grp_state_to_string(new_state));
528 	} else {
529 		usnic_err("Failed to transition %u from %s to %s",
530 		qp_grp->grp_id,
531 		usnic_ib_qp_grp_state_to_string(old_state),
532 		usnic_ib_qp_grp_state_to_string(new_state));
533 	}
534 
535 	return status;
536 }
537 
538 static struct usnic_vnic_res_chunk**
539 alloc_res_chunk_list(struct usnic_vnic *vnic,
540 			struct usnic_vnic_res_spec *res_spec, void *owner_obj)
541 {
542 	enum usnic_vnic_res_type res_type;
543 	struct usnic_vnic_res_chunk **res_chunk_list;
544 	int err, i, res_cnt, res_lst_sz;
545 
546 	for (res_lst_sz = 0;
547 		res_spec->resources[res_lst_sz].type != USNIC_VNIC_RES_TYPE_EOL;
548 		res_lst_sz++) {
549 		/* Do Nothing */
550 	}
551 
552 	res_chunk_list = kzalloc(sizeof(*res_chunk_list)*(res_lst_sz+1),
553 					GFP_ATOMIC);
554 	if (!res_chunk_list)
555 		return ERR_PTR(-ENOMEM);
556 
557 	for (i = 0; res_spec->resources[i].type != USNIC_VNIC_RES_TYPE_EOL;
558 		i++) {
559 		res_type = res_spec->resources[i].type;
560 		res_cnt = res_spec->resources[i].cnt;
561 
562 		res_chunk_list[i] = usnic_vnic_get_resources(vnic, res_type,
563 					res_cnt, owner_obj);
564 		if (IS_ERR_OR_NULL(res_chunk_list[i])) {
565 			err = res_chunk_list[i] ?
566 					PTR_ERR(res_chunk_list[i]) : -ENOMEM;
567 			usnic_err("Failed to get %s from %s with err %d\n",
568 				usnic_vnic_res_type_to_str(res_type),
569 				usnic_vnic_pci_name(vnic),
570 				err);
571 			goto out_free_res;
572 		}
573 	}
574 
575 	return res_chunk_list;
576 
577 out_free_res:
578 	for (i--; i > 0; i--)
579 		usnic_vnic_put_resources(res_chunk_list[i]);
580 	kfree(res_chunk_list);
581 	return ERR_PTR(err);
582 }
583 
584 static void free_qp_grp_res(struct usnic_vnic_res_chunk **res_chunk_list)
585 {
586 	int i;
587 	for (i = 0; res_chunk_list[i]; i++)
588 		usnic_vnic_put_resources(res_chunk_list[i]);
589 	kfree(res_chunk_list);
590 }
591 
592 static int qp_grp_and_vf_bind(struct usnic_ib_vf *vf,
593 				struct usnic_ib_pd *pd,
594 				struct usnic_ib_qp_grp *qp_grp)
595 {
596 	int err;
597 	struct pci_dev *pdev;
598 
599 	lockdep_assert_held(&vf->lock);
600 
601 	pdev = usnic_vnic_get_pdev(vf->vnic);
602 	if (vf->qp_grp_ref_cnt == 0) {
603 		err = usnic_uiom_attach_dev_to_pd(pd->umem_pd, &pdev->dev);
604 		if (err) {
605 			usnic_err("Failed to attach %s to domain\n",
606 					pci_name(pdev));
607 			return err;
608 		}
609 		vf->pd = pd;
610 	}
611 	vf->qp_grp_ref_cnt++;
612 
613 	WARN_ON(vf->pd != pd);
614 	qp_grp->vf = vf;
615 
616 	return 0;
617 }
618 
619 static void qp_grp_and_vf_unbind(struct usnic_ib_qp_grp *qp_grp)
620 {
621 	struct pci_dev *pdev;
622 	struct usnic_ib_pd *pd;
623 
624 	lockdep_assert_held(&qp_grp->vf->lock);
625 
626 	pd = qp_grp->vf->pd;
627 	pdev = usnic_vnic_get_pdev(qp_grp->vf->vnic);
628 	if (--qp_grp->vf->qp_grp_ref_cnt == 0) {
629 		qp_grp->vf->pd = NULL;
630 		usnic_uiom_detach_dev_from_pd(pd->umem_pd, &pdev->dev);
631 	}
632 	qp_grp->vf = NULL;
633 }
634 
635 static void log_spec(struct usnic_vnic_res_spec *res_spec)
636 {
637 	char buf[512];
638 	usnic_vnic_spec_dump(buf, sizeof(buf), res_spec);
639 	usnic_dbg("%s\n", buf);
640 }
641 
642 static int qp_grp_id_from_flow(struct usnic_ib_qp_grp_flow *qp_flow,
643 				uint32_t *id)
644 {
645 	enum usnic_transport_type trans_type = qp_flow->trans_type;
646 	int err;
647 	uint16_t port_num = 0;
648 
649 	switch (trans_type) {
650 	case USNIC_TRANSPORT_ROCE_CUSTOM:
651 		*id = qp_flow->usnic_roce.port_num;
652 		break;
653 	case USNIC_TRANSPORT_IPV4_UDP:
654 		err = usnic_transport_sock_get_addr(qp_flow->udp.sock,
655 							NULL, NULL,
656 							&port_num);
657 		if (err)
658 			return err;
659 		/*
660 		 * Copy port_num to stack first and then to *id,
661 		 * so that the short to int cast works for little
662 		 * and big endian systems.
663 		 */
664 		*id = port_num;
665 		break;
666 	default:
667 		usnic_err("Unsupported transport %u\n", trans_type);
668 		return -EINVAL;
669 	}
670 
671 	return 0;
672 }
673 
674 struct usnic_ib_qp_grp *
675 usnic_ib_qp_grp_create(struct usnic_fwd_dev *ufdev, struct usnic_ib_vf *vf,
676 			struct usnic_ib_pd *pd,
677 			struct usnic_vnic_res_spec *res_spec,
678 			struct usnic_transport_spec *transport_spec)
679 {
680 	struct usnic_ib_qp_grp *qp_grp;
681 	int err;
682 	enum usnic_transport_type transport = transport_spec->trans_type;
683 	struct usnic_ib_qp_grp_flow *qp_flow;
684 
685 	lockdep_assert_held(&vf->lock);
686 
687 	err = usnic_vnic_res_spec_satisfied(&min_transport_spec[transport],
688 						res_spec);
689 	if (err) {
690 		usnic_err("Spec does not meet miniumum req for transport %d\n",
691 				transport);
692 		log_spec(res_spec);
693 		return ERR_PTR(err);
694 	}
695 
696 	qp_grp = kzalloc(sizeof(*qp_grp), GFP_ATOMIC);
697 	if (!qp_grp) {
698 		usnic_err("Unable to alloc qp_grp - Out of memory\n");
699 		return NULL;
700 	}
701 
702 	qp_grp->res_chunk_list = alloc_res_chunk_list(vf->vnic, res_spec,
703 							qp_grp);
704 	if (IS_ERR_OR_NULL(qp_grp->res_chunk_list)) {
705 		err = qp_grp->res_chunk_list ?
706 				PTR_ERR(qp_grp->res_chunk_list) : -ENOMEM;
707 		usnic_err("Unable to alloc res for %d with err %d\n",
708 				qp_grp->grp_id, err);
709 		goto out_free_qp_grp;
710 	}
711 
712 	err = qp_grp_and_vf_bind(vf, pd, qp_grp);
713 	if (err)
714 		goto out_free_res;
715 
716 	INIT_LIST_HEAD(&qp_grp->flows_lst);
717 	spin_lock_init(&qp_grp->lock);
718 	qp_grp->ufdev = ufdev;
719 	qp_grp->state = IB_QPS_RESET;
720 	qp_grp->owner_pid = current->pid;
721 
722 	qp_flow = create_and_add_flow(qp_grp, transport_spec);
723 	if (IS_ERR_OR_NULL(qp_flow)) {
724 		usnic_err("Unable to create and add flow with err %ld\n",
725 				PTR_ERR(qp_flow));
726 		err = qp_flow ? PTR_ERR(qp_flow) : -EFAULT;
727 		goto out_qp_grp_vf_unbind;
728 	}
729 
730 	err = qp_grp_id_from_flow(qp_flow, &qp_grp->grp_id);
731 	if (err)
732 		goto out_release_flow;
733 	qp_grp->ibqp.qp_num = qp_grp->grp_id;
734 
735 	usnic_ib_sysfs_qpn_add(qp_grp);
736 
737 	return qp_grp;
738 
739 out_release_flow:
740 	release_and_remove_flow(qp_flow);
741 out_qp_grp_vf_unbind:
742 	qp_grp_and_vf_unbind(qp_grp);
743 out_free_res:
744 	free_qp_grp_res(qp_grp->res_chunk_list);
745 out_free_qp_grp:
746 	kfree(qp_grp);
747 
748 	return ERR_PTR(err);
749 }
750 
751 void usnic_ib_qp_grp_destroy(struct usnic_ib_qp_grp *qp_grp)
752 {
753 
754 	WARN_ON(qp_grp->state != IB_QPS_RESET);
755 	lockdep_assert_held(&qp_grp->vf->lock);
756 
757 	release_and_remove_all_flows(qp_grp);
758 	usnic_ib_sysfs_qpn_remove(qp_grp);
759 	qp_grp_and_vf_unbind(qp_grp);
760 	free_qp_grp_res(qp_grp->res_chunk_list);
761 	kfree(qp_grp);
762 }
763 
764 struct usnic_vnic_res_chunk*
765 usnic_ib_qp_grp_get_chunk(struct usnic_ib_qp_grp *qp_grp,
766 				enum usnic_vnic_res_type res_type)
767 {
768 	int i;
769 
770 	for (i = 0; qp_grp->res_chunk_list[i]; i++) {
771 		if (qp_grp->res_chunk_list[i]->type == res_type)
772 			return qp_grp->res_chunk_list[i];
773 	}
774 
775 	return ERR_PTR(-EINVAL);
776 }
777