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