1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
49const 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
72int 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
77int 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
96static struct usnic_vnic_res_chunk *
97get_qp_res_chunk(struct usnic_ib_qp_grp *qp_grp)
98{
99 lockdep_assert_held(&qp_grp->lock);
100
101
102
103
104 return usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_RQ);
105}
106
107static 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
140out_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
150static 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
183static 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
203static struct usnic_ib_qp_grp_flow*
204create_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
219 port_num = usnic_transport_rsrv_port(trans_type, port_num);
220 if (port_num == 0)
221 return ERR_PTR(-EINVAL);
222
223
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
238 qp_flow = kzalloc(sizeof(*qp_flow), GFP_ATOMIC);
239 if (!qp_flow) {
240 err = -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
249out_dealloc_flow:
250 usnic_fwd_dealloc_flow(flow);
251out_unreserve_port:
252 usnic_transport_unrsrv_port(trans_type, port_num);
253 return ERR_PTR(err);
254}
255
256static 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
264static struct usnic_ib_qp_grp_flow*
265create_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
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
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
313 qp_flow = kzalloc(sizeof(*qp_flow), GFP_ATOMIC);
314 if (!qp_flow) {
315 err = -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
324out_dealloc_flow:
325 usnic_fwd_dealloc_flow(flow);
326out_put_sock:
327 usnic_transport_put_socket(sock);
328 return ERR_PTR(err);
329}
330
331static 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
338static struct usnic_ib_qp_grp_flow*
339create_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
368static 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
387static 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
394int 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
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
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
458
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
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
538static struct usnic_vnic_res_chunk**
539alloc_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
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
577out_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
584static 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
592static 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
619static 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
635static 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
642static 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
661
662
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
674struct usnic_ib_qp_grp *
675usnic_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
739out_release_flow:
740 release_and_remove_flow(qp_flow);
741out_qp_grp_vf_unbind:
742 qp_grp_and_vf_unbind(qp_grp);
743out_free_res:
744 free_qp_grp_res(qp_grp->res_chunk_list);
745out_free_qp_grp:
746 kfree(qp_grp);
747
748 return ERR_PTR(err);
749}
750
751void 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
764struct usnic_vnic_res_chunk*
765usnic_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