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