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