linux/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c
<<
>>
Prefs
   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
  34const 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
  57int 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
  62int 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
  81static struct usnic_vnic_res_chunk *
  82get_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
  92static 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
 125out_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
 135static 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
 168static 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
 188static struct usnic_ib_qp_grp_flow*
 189create_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
 234out_dealloc_flow:
 235        usnic_fwd_dealloc_flow(flow);
 236out_unreserve_port:
 237        usnic_transport_unrsrv_port(trans_type, port_num);
 238        return ERR_PTR(err);
 239}
 240
 241static 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
 249static struct usnic_ib_qp_grp_flow*
 250create_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
 309out_dealloc_flow:
 310        usnic_fwd_dealloc_flow(flow);
 311out_put_sock:
 312        usnic_transport_put_socket(sock);
 313        return ERR_PTR(err);
 314}
 315
 316static 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
 323static struct usnic_ib_qp_grp_flow*
 324create_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
 353static 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
 372static 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
 379int 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
 523static struct usnic_vnic_res_chunk**
 524alloc_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
 562out_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
 569static 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
 577static 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
 604static 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
 620static 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
 627static 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
 659struct usnic_ib_qp_grp *
 660usnic_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
 724out_release_flow:
 725        release_and_remove_flow(qp_flow);
 726out_qp_grp_vf_unbind:
 727        qp_grp_and_vf_unbind(qp_grp);
 728out_free_res:
 729        free_qp_grp_res(qp_grp->res_chunk_list);
 730out_free_qp_grp:
 731        kfree(qp_grp);
 732
 733        return ERR_PTR(err);
 734}
 735
 736void 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
 749struct usnic_vnic_res_chunk*
 750usnic_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