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