756 lines · c
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 two5 * licenses. You may choose to be licensed under the terms of the GNU6 * General Public License (GPL) Version 2, available from the file7 * COPYING in the main directory of this source tree, or the8 * BSD license below:9 *10 * Redistribution and use in source and binary forms, with or11 * without modification, are permitted provided that the following12 * conditions are met:13 *14 * - Redistributions of source code must retain the above15 * copyright notice, this list of conditions and the following16 * disclaimer.17 *18 * - Redistributions in binary form must reproduce the above19 * copyright notice, this list of conditions and the following20 * disclaimer in the documentation and/or other materials21 * 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 OF25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30 * 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 047 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 RQs102 */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 state451 * 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 little655 * 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}756