qemu/hw/rdma/rdma_rm.c
<<
>>
Prefs
   1/*
   2 * QEMU paravirtual RDMA - Resource Manager Implementation
   3 *
   4 * Copyright (C) 2018 Oracle
   5 * Copyright (C) 2018 Red Hat Inc
   6 *
   7 * Authors:
   8 *     Yuval Shaia <yuval.shaia@oracle.com>
   9 *     Marcel Apfelbaum <marcel@redhat.com>
  10 *
  11 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  12 * See the COPYING file in the top-level directory.
  13 *
  14 */
  15
  16#include "qemu/osdep.h"
  17#include "qapi/error.h"
  18#include "cpu.h"
  19#include "monitor/monitor.h"
  20
  21#include "trace.h"
  22#include "rdma_utils.h"
  23#include "rdma_backend.h"
  24#include "rdma_rm.h"
  25
  26/* Page directory and page tables */
  27#define PG_DIR_SZ { TARGET_PAGE_SIZE / sizeof(__u64) }
  28#define PG_TBL_SZ { TARGET_PAGE_SIZE / sizeof(__u64) }
  29
  30void rdma_dump_device_counters(Monitor *mon, RdmaDeviceResources *dev_res)
  31{
  32    monitor_printf(mon, "\ttx               : %" PRId64 "\n",
  33                   dev_res->stats.tx);
  34    monitor_printf(mon, "\ttx_len           : %" PRId64 "\n",
  35                   dev_res->stats.tx_len);
  36    monitor_printf(mon, "\ttx_err           : %" PRId64 "\n",
  37                   dev_res->stats.tx_err);
  38    monitor_printf(mon, "\trx_bufs          : %" PRId64 "\n",
  39                   dev_res->stats.rx_bufs);
  40    monitor_printf(mon, "\trx_srq           : %" PRId64 "\n",
  41                   dev_res->stats.rx_srq);
  42    monitor_printf(mon, "\trx_bufs_len      : %" PRId64 "\n",
  43                   dev_res->stats.rx_bufs_len);
  44    monitor_printf(mon, "\trx_bufs_err      : %" PRId64 "\n",
  45                   dev_res->stats.rx_bufs_err);
  46    monitor_printf(mon, "\tcomps            : %" PRId64 "\n",
  47                   dev_res->stats.completions);
  48    monitor_printf(mon, "\tmissing_comps    : %" PRId32 "\n",
  49                   dev_res->stats.missing_cqe);
  50    monitor_printf(mon, "\tpoll_cq (bk)     : %" PRId64 "\n",
  51                   dev_res->stats.poll_cq_from_bk);
  52    monitor_printf(mon, "\tpoll_cq_ppoll_to : %" PRId64 "\n",
  53                   dev_res->stats.poll_cq_ppoll_to);
  54    monitor_printf(mon, "\tpoll_cq (fe)     : %" PRId64 "\n",
  55                   dev_res->stats.poll_cq_from_guest);
  56    monitor_printf(mon, "\tpoll_cq_empty    : %" PRId64 "\n",
  57                   dev_res->stats.poll_cq_from_guest_empty);
  58    monitor_printf(mon, "\tmad_tx           : %" PRId64 "\n",
  59                   dev_res->stats.mad_tx);
  60    monitor_printf(mon, "\tmad_tx_err       : %" PRId64 "\n",
  61                   dev_res->stats.mad_tx_err);
  62    monitor_printf(mon, "\tmad_rx           : %" PRId64 "\n",
  63                   dev_res->stats.mad_rx);
  64    monitor_printf(mon, "\tmad_rx_err       : %" PRId64 "\n",
  65                   dev_res->stats.mad_rx_err);
  66    monitor_printf(mon, "\tmad_rx_bufs      : %" PRId64 "\n",
  67                   dev_res->stats.mad_rx_bufs);
  68    monitor_printf(mon, "\tmad_rx_bufs_err  : %" PRId64 "\n",
  69                   dev_res->stats.mad_rx_bufs_err);
  70    monitor_printf(mon, "\tPDs              : %" PRId32 "\n",
  71                   dev_res->pd_tbl.used);
  72    monitor_printf(mon, "\tMRs              : %" PRId32 "\n",
  73                   dev_res->mr_tbl.used);
  74    monitor_printf(mon, "\tUCs              : %" PRId32 "\n",
  75                   dev_res->uc_tbl.used);
  76    monitor_printf(mon, "\tQPs              : %" PRId32 "\n",
  77                   dev_res->qp_tbl.used);
  78    monitor_printf(mon, "\tCQs              : %" PRId32 "\n",
  79                   dev_res->cq_tbl.used);
  80    monitor_printf(mon, "\tCEQ_CTXs         : %" PRId32 "\n",
  81                   dev_res->cqe_ctx_tbl.used);
  82}
  83
  84static inline void res_tbl_init(const char *name, RdmaRmResTbl *tbl,
  85                                uint32_t tbl_sz, uint32_t res_sz)
  86{
  87    tbl->tbl = g_malloc(tbl_sz * res_sz);
  88
  89    strncpy(tbl->name, name, MAX_RM_TBL_NAME);
  90    tbl->name[MAX_RM_TBL_NAME - 1] = 0;
  91
  92    tbl->bitmap = bitmap_new(tbl_sz);
  93    tbl->tbl_sz = tbl_sz;
  94    tbl->res_sz = res_sz;
  95    tbl->used = 0;
  96    qemu_mutex_init(&tbl->lock);
  97}
  98
  99static inline void res_tbl_free(RdmaRmResTbl *tbl)
 100{
 101    if (!tbl->bitmap) {
 102        return;
 103    }
 104    qemu_mutex_destroy(&tbl->lock);
 105    g_free(tbl->tbl);
 106    g_free(tbl->bitmap);
 107}
 108
 109static inline void *rdma_res_tbl_get(RdmaRmResTbl *tbl, uint32_t handle)
 110{
 111    trace_rdma_res_tbl_get(tbl->name, handle);
 112
 113    if ((handle < tbl->tbl_sz) && (test_bit(handle, tbl->bitmap))) {
 114        return tbl->tbl + handle * tbl->res_sz;
 115    } else {
 116        rdma_error_report("Table %s, invalid handle %d", tbl->name, handle);
 117        return NULL;
 118    }
 119}
 120
 121static inline void *rdma_res_tbl_alloc(RdmaRmResTbl *tbl, uint32_t *handle)
 122{
 123    qemu_mutex_lock(&tbl->lock);
 124
 125    *handle = find_first_zero_bit(tbl->bitmap, tbl->tbl_sz);
 126    if (*handle > tbl->tbl_sz) {
 127        rdma_error_report("Table %s, failed to allocate, bitmap is full",
 128                          tbl->name);
 129        qemu_mutex_unlock(&tbl->lock);
 130        return NULL;
 131    }
 132
 133    set_bit(*handle, tbl->bitmap);
 134
 135    tbl->used++;
 136
 137    qemu_mutex_unlock(&tbl->lock);
 138
 139    memset(tbl->tbl + *handle * tbl->res_sz, 0, tbl->res_sz);
 140
 141    trace_rdma_res_tbl_alloc(tbl->name, *handle);
 142
 143    return tbl->tbl + *handle * tbl->res_sz;
 144}
 145
 146static inline void rdma_res_tbl_dealloc(RdmaRmResTbl *tbl, uint32_t handle)
 147{
 148    trace_rdma_res_tbl_dealloc(tbl->name, handle);
 149
 150    qemu_mutex_lock(&tbl->lock);
 151
 152    if (handle < tbl->tbl_sz) {
 153        clear_bit(handle, tbl->bitmap);
 154        tbl->used--;
 155    }
 156
 157    qemu_mutex_unlock(&tbl->lock);
 158}
 159
 160int rdma_rm_alloc_pd(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
 161                     uint32_t *pd_handle, uint32_t ctx_handle)
 162{
 163    RdmaRmPD *pd;
 164    int ret = -ENOMEM;
 165
 166    pd = rdma_res_tbl_alloc(&dev_res->pd_tbl, pd_handle);
 167    if (!pd) {
 168        goto out;
 169    }
 170
 171    ret = rdma_backend_create_pd(backend_dev, &pd->backend_pd);
 172    if (ret) {
 173        ret = -EIO;
 174        goto out_tbl_dealloc;
 175    }
 176
 177    pd->ctx_handle = ctx_handle;
 178
 179    return 0;
 180
 181out_tbl_dealloc:
 182    rdma_res_tbl_dealloc(&dev_res->pd_tbl, *pd_handle);
 183
 184out:
 185    return ret;
 186}
 187
 188RdmaRmPD *rdma_rm_get_pd(RdmaDeviceResources *dev_res, uint32_t pd_handle)
 189{
 190    return rdma_res_tbl_get(&dev_res->pd_tbl, pd_handle);
 191}
 192
 193void rdma_rm_dealloc_pd(RdmaDeviceResources *dev_res, uint32_t pd_handle)
 194{
 195    RdmaRmPD *pd = rdma_rm_get_pd(dev_res, pd_handle);
 196
 197    if (pd) {
 198        rdma_backend_destroy_pd(&pd->backend_pd);
 199        rdma_res_tbl_dealloc(&dev_res->pd_tbl, pd_handle);
 200    }
 201}
 202
 203int rdma_rm_alloc_mr(RdmaDeviceResources *dev_res, uint32_t pd_handle,
 204                     uint64_t guest_start, uint64_t guest_length,
 205                     void *host_virt, int access_flags, uint32_t *mr_handle,
 206                     uint32_t *lkey, uint32_t *rkey)
 207{
 208    RdmaRmMR *mr;
 209    int ret = 0;
 210    RdmaRmPD *pd;
 211
 212    pd = rdma_rm_get_pd(dev_res, pd_handle);
 213    if (!pd) {
 214        return -EINVAL;
 215    }
 216
 217    mr = rdma_res_tbl_alloc(&dev_res->mr_tbl, mr_handle);
 218    if (!mr) {
 219        return -ENOMEM;
 220    }
 221    trace_rdma_rm_alloc_mr(*mr_handle, host_virt, guest_start, guest_length,
 222                           access_flags);
 223
 224    if (host_virt) {
 225        mr->virt = host_virt;
 226        mr->start = guest_start;
 227        mr->length = guest_length;
 228        mr->virt += (mr->start & (TARGET_PAGE_SIZE - 1));
 229
 230        ret = rdma_backend_create_mr(&mr->backend_mr, &pd->backend_pd, mr->virt,
 231                                     mr->length, access_flags);
 232        if (ret) {
 233            ret = -EIO;
 234            goto out_dealloc_mr;
 235        }
 236    }
 237
 238    /* We keep mr_handle in lkey so send and recv get get mr ptr */
 239    *lkey = *mr_handle;
 240    *rkey = -1;
 241
 242    mr->pd_handle = pd_handle;
 243
 244    return 0;
 245
 246out_dealloc_mr:
 247    rdma_res_tbl_dealloc(&dev_res->mr_tbl, *mr_handle);
 248
 249    return ret;
 250}
 251
 252RdmaRmMR *rdma_rm_get_mr(RdmaDeviceResources *dev_res, uint32_t mr_handle)
 253{
 254    return rdma_res_tbl_get(&dev_res->mr_tbl, mr_handle);
 255}
 256
 257void rdma_rm_dealloc_mr(RdmaDeviceResources *dev_res, uint32_t mr_handle)
 258{
 259    RdmaRmMR *mr = rdma_rm_get_mr(dev_res, mr_handle);
 260
 261    if (mr) {
 262        rdma_backend_destroy_mr(&mr->backend_mr);
 263        trace_rdma_rm_dealloc_mr(mr_handle, mr->start);
 264        if (mr->start) {
 265            mr->virt -= (mr->start & (TARGET_PAGE_SIZE - 1));
 266            munmap(mr->virt, mr->length);
 267        }
 268        rdma_res_tbl_dealloc(&dev_res->mr_tbl, mr_handle);
 269    }
 270}
 271
 272int rdma_rm_alloc_uc(RdmaDeviceResources *dev_res, uint32_t pfn,
 273                     uint32_t *uc_handle)
 274{
 275    RdmaRmUC *uc;
 276
 277    /* TODO: Need to make sure pfn is between bar start address and
 278     * bsd+RDMA_BAR2_UAR_SIZE
 279    if (pfn > RDMA_BAR2_UAR_SIZE) {
 280        rdma_error_report("pfn out of range (%d > %d)", pfn,
 281                          RDMA_BAR2_UAR_SIZE);
 282        return -ENOMEM;
 283    }
 284    */
 285
 286    uc = rdma_res_tbl_alloc(&dev_res->uc_tbl, uc_handle);
 287    if (!uc) {
 288        return -ENOMEM;
 289    }
 290
 291    return 0;
 292}
 293
 294RdmaRmUC *rdma_rm_get_uc(RdmaDeviceResources *dev_res, uint32_t uc_handle)
 295{
 296    return rdma_res_tbl_get(&dev_res->uc_tbl, uc_handle);
 297}
 298
 299void rdma_rm_dealloc_uc(RdmaDeviceResources *dev_res, uint32_t uc_handle)
 300{
 301    RdmaRmUC *uc = rdma_rm_get_uc(dev_res, uc_handle);
 302
 303    if (uc) {
 304        rdma_res_tbl_dealloc(&dev_res->uc_tbl, uc_handle);
 305    }
 306}
 307
 308RdmaRmCQ *rdma_rm_get_cq(RdmaDeviceResources *dev_res, uint32_t cq_handle)
 309{
 310    return rdma_res_tbl_get(&dev_res->cq_tbl, cq_handle);
 311}
 312
 313int rdma_rm_alloc_cq(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
 314                     uint32_t cqe, uint32_t *cq_handle, void *opaque)
 315{
 316    int rc;
 317    RdmaRmCQ *cq;
 318
 319    cq = rdma_res_tbl_alloc(&dev_res->cq_tbl, cq_handle);
 320    if (!cq) {
 321        return -ENOMEM;
 322    }
 323
 324    cq->opaque = opaque;
 325    cq->notify = CNT_CLEAR;
 326
 327    rc = rdma_backend_create_cq(backend_dev, &cq->backend_cq, cqe);
 328    if (rc) {
 329        rc = -EIO;
 330        goto out_dealloc_cq;
 331    }
 332
 333    return 0;
 334
 335out_dealloc_cq:
 336    rdma_rm_dealloc_cq(dev_res, *cq_handle);
 337
 338    return rc;
 339}
 340
 341void rdma_rm_req_notify_cq(RdmaDeviceResources *dev_res, uint32_t cq_handle,
 342                           bool notify)
 343{
 344    RdmaRmCQ *cq;
 345
 346    cq = rdma_rm_get_cq(dev_res, cq_handle);
 347    if (!cq) {
 348        return;
 349    }
 350
 351    if (cq->notify != CNT_SET) {
 352        cq->notify = notify ? CNT_ARM : CNT_CLEAR;
 353    }
 354}
 355
 356void rdma_rm_dealloc_cq(RdmaDeviceResources *dev_res, uint32_t cq_handle)
 357{
 358    RdmaRmCQ *cq;
 359
 360    cq = rdma_rm_get_cq(dev_res, cq_handle);
 361    if (!cq) {
 362        return;
 363    }
 364
 365    rdma_backend_destroy_cq(&cq->backend_cq);
 366
 367    rdma_res_tbl_dealloc(&dev_res->cq_tbl, cq_handle);
 368}
 369
 370RdmaRmQP *rdma_rm_get_qp(RdmaDeviceResources *dev_res, uint32_t qpn)
 371{
 372    GBytes *key = g_bytes_new(&qpn, sizeof(qpn));
 373
 374    RdmaRmQP *qp = g_hash_table_lookup(dev_res->qp_hash, key);
 375
 376    g_bytes_unref(key);
 377
 378    if (!qp) {
 379        rdma_error_report("Invalid QP handle %d", qpn);
 380    }
 381
 382    return qp;
 383}
 384
 385int rdma_rm_alloc_qp(RdmaDeviceResources *dev_res, uint32_t pd_handle,
 386                     uint8_t qp_type, uint32_t max_send_wr,
 387                     uint32_t max_send_sge, uint32_t send_cq_handle,
 388                     uint32_t max_recv_wr, uint32_t max_recv_sge,
 389                     uint32_t recv_cq_handle, void *opaque, uint32_t *qpn,
 390                     uint8_t is_srq, uint32_t srq_handle)
 391{
 392    int rc;
 393    RdmaRmQP *qp;
 394    RdmaRmCQ *scq, *rcq;
 395    RdmaRmPD *pd;
 396    RdmaRmSRQ *srq = NULL;
 397    uint32_t rm_qpn;
 398
 399    pd = rdma_rm_get_pd(dev_res, pd_handle);
 400    if (!pd) {
 401        return -EINVAL;
 402    }
 403
 404    scq = rdma_rm_get_cq(dev_res, send_cq_handle);
 405    rcq = rdma_rm_get_cq(dev_res, recv_cq_handle);
 406
 407    if (!scq || !rcq) {
 408        rdma_error_report("Invalid send_cqn or recv_cqn (%d, %d)",
 409                          send_cq_handle, recv_cq_handle);
 410        return -EINVAL;
 411    }
 412
 413    if (is_srq) {
 414        srq = rdma_rm_get_srq(dev_res, srq_handle);
 415        if (!srq) {
 416            rdma_error_report("Invalid srqn %d", srq_handle);
 417            return -EINVAL;
 418        }
 419
 420        srq->recv_cq_handle = recv_cq_handle;
 421    }
 422
 423    if (qp_type == IBV_QPT_GSI) {
 424        scq->notify = CNT_SET;
 425        rcq->notify = CNT_SET;
 426    }
 427
 428    qp = rdma_res_tbl_alloc(&dev_res->qp_tbl, &rm_qpn);
 429    if (!qp) {
 430        return -ENOMEM;
 431    }
 432
 433    qp->qpn = rm_qpn;
 434    qp->qp_state = IBV_QPS_RESET;
 435    qp->qp_type = qp_type;
 436    qp->send_cq_handle = send_cq_handle;
 437    qp->recv_cq_handle = recv_cq_handle;
 438    qp->opaque = opaque;
 439    qp->is_srq = is_srq;
 440
 441    rc = rdma_backend_create_qp(&qp->backend_qp, qp_type, &pd->backend_pd,
 442                                &scq->backend_cq, &rcq->backend_cq,
 443                                is_srq ? &srq->backend_srq : NULL,
 444                                max_send_wr, max_recv_wr, max_send_sge,
 445                                max_recv_sge);
 446
 447    if (rc) {
 448        rc = -EIO;
 449        goto out_dealloc_qp;
 450    }
 451
 452    *qpn = rdma_backend_qpn(&qp->backend_qp);
 453    trace_rdma_rm_alloc_qp(rm_qpn, *qpn, qp_type);
 454    g_hash_table_insert(dev_res->qp_hash, g_bytes_new(qpn, sizeof(*qpn)), qp);
 455
 456    return 0;
 457
 458out_dealloc_qp:
 459    rdma_res_tbl_dealloc(&dev_res->qp_tbl, qp->qpn);
 460
 461    return rc;
 462}
 463
 464int rdma_rm_modify_qp(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
 465                      uint32_t qp_handle, uint32_t attr_mask, uint8_t sgid_idx,
 466                      union ibv_gid *dgid, uint32_t dqpn,
 467                      enum ibv_qp_state qp_state, uint32_t qkey,
 468                      uint32_t rq_psn, uint32_t sq_psn)
 469{
 470    RdmaRmQP *qp;
 471    int ret;
 472
 473    qp = rdma_rm_get_qp(dev_res, qp_handle);
 474    if (!qp) {
 475        return -EINVAL;
 476    }
 477
 478    if (qp->qp_type == IBV_QPT_SMI) {
 479        rdma_error_report("Got QP0 request");
 480        return -EPERM;
 481    } else if (qp->qp_type == IBV_QPT_GSI) {
 482        return 0;
 483    }
 484
 485    trace_rdma_rm_modify_qp(qp_handle, attr_mask, qp_state, sgid_idx);
 486
 487    if (attr_mask & IBV_QP_STATE) {
 488        qp->qp_state = qp_state;
 489
 490        if (qp->qp_state == IBV_QPS_INIT) {
 491            ret = rdma_backend_qp_state_init(backend_dev, &qp->backend_qp,
 492                                             qp->qp_type, qkey);
 493            if (ret) {
 494                return -EIO;
 495            }
 496        }
 497
 498        if (qp->qp_state == IBV_QPS_RTR) {
 499            /* Get backend gid index */
 500            sgid_idx = rdma_rm_get_backend_gid_index(dev_res, backend_dev,
 501                                                     sgid_idx);
 502            if (sgid_idx <= 0) { /* TODO check also less than bk.max_sgid */
 503                rdma_error_report("Failed to get bk sgid_idx for sgid_idx %d",
 504                                  sgid_idx);
 505                return -EIO;
 506            }
 507
 508            ret = rdma_backend_qp_state_rtr(backend_dev, &qp->backend_qp,
 509                                            qp->qp_type, sgid_idx, dgid, dqpn,
 510                                            rq_psn, qkey,
 511                                            attr_mask & IBV_QP_QKEY);
 512            if (ret) {
 513                return -EIO;
 514            }
 515        }
 516
 517        if (qp->qp_state == IBV_QPS_RTS) {
 518            ret = rdma_backend_qp_state_rts(&qp->backend_qp, qp->qp_type,
 519                                            sq_psn, qkey,
 520                                            attr_mask & IBV_QP_QKEY);
 521            if (ret) {
 522                return -EIO;
 523            }
 524        }
 525    }
 526
 527    return 0;
 528}
 529
 530int rdma_rm_query_qp(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
 531                     uint32_t qp_handle, struct ibv_qp_attr *attr,
 532                     int attr_mask, struct ibv_qp_init_attr *init_attr)
 533{
 534    RdmaRmQP *qp;
 535
 536    qp = rdma_rm_get_qp(dev_res, qp_handle);
 537    if (!qp) {
 538        return -EINVAL;
 539    }
 540
 541    return rdma_backend_query_qp(&qp->backend_qp, attr, attr_mask, init_attr);
 542}
 543
 544void rdma_rm_dealloc_qp(RdmaDeviceResources *dev_res, uint32_t qp_handle)
 545{
 546    RdmaRmQP *qp;
 547    GBytes *key;
 548
 549    key = g_bytes_new(&qp_handle, sizeof(qp_handle));
 550    qp = g_hash_table_lookup(dev_res->qp_hash, key);
 551    g_hash_table_remove(dev_res->qp_hash, key);
 552    g_bytes_unref(key);
 553
 554    if (!qp) {
 555        return;
 556    }
 557
 558    rdma_backend_destroy_qp(&qp->backend_qp, dev_res);
 559
 560    rdma_res_tbl_dealloc(&dev_res->qp_tbl, qp->qpn);
 561}
 562
 563RdmaRmSRQ *rdma_rm_get_srq(RdmaDeviceResources *dev_res, uint32_t srq_handle)
 564{
 565    return rdma_res_tbl_get(&dev_res->srq_tbl, srq_handle);
 566}
 567
 568int rdma_rm_alloc_srq(RdmaDeviceResources *dev_res, uint32_t pd_handle,
 569                      uint32_t max_wr, uint32_t max_sge, uint32_t srq_limit,
 570                      uint32_t *srq_handle, void *opaque)
 571{
 572    RdmaRmSRQ *srq;
 573    RdmaRmPD *pd;
 574    int rc;
 575
 576    pd = rdma_rm_get_pd(dev_res, pd_handle);
 577    if (!pd) {
 578        return -EINVAL;
 579    }
 580
 581    srq = rdma_res_tbl_alloc(&dev_res->srq_tbl, srq_handle);
 582    if (!srq) {
 583        return -ENOMEM;
 584    }
 585
 586    rc = rdma_backend_create_srq(&srq->backend_srq, &pd->backend_pd,
 587                                 max_wr, max_sge, srq_limit);
 588    if (rc) {
 589        rc = -EIO;
 590        goto out_dealloc_srq;
 591    }
 592
 593    srq->opaque = opaque;
 594
 595    return 0;
 596
 597out_dealloc_srq:
 598    rdma_res_tbl_dealloc(&dev_res->srq_tbl, *srq_handle);
 599
 600    return rc;
 601}
 602
 603int rdma_rm_query_srq(RdmaDeviceResources *dev_res, uint32_t srq_handle,
 604                      struct ibv_srq_attr *srq_attr)
 605{
 606    RdmaRmSRQ *srq;
 607
 608    srq = rdma_rm_get_srq(dev_res, srq_handle);
 609    if (!srq) {
 610        return -EINVAL;
 611    }
 612
 613    return rdma_backend_query_srq(&srq->backend_srq, srq_attr);
 614}
 615
 616int rdma_rm_modify_srq(RdmaDeviceResources *dev_res, uint32_t srq_handle,
 617                       struct ibv_srq_attr *srq_attr, int srq_attr_mask)
 618{
 619    RdmaRmSRQ *srq;
 620
 621    srq = rdma_rm_get_srq(dev_res, srq_handle);
 622    if (!srq) {
 623        return -EINVAL;
 624    }
 625
 626    if ((srq_attr_mask & IBV_SRQ_LIMIT) &&
 627        (srq_attr->srq_limit == 0)) {
 628        return -EINVAL;
 629    }
 630
 631    if ((srq_attr_mask & IBV_SRQ_MAX_WR) &&
 632        (srq_attr->max_wr == 0)) {
 633        return -EINVAL;
 634    }
 635
 636    return rdma_backend_modify_srq(&srq->backend_srq, srq_attr,
 637                                   srq_attr_mask);
 638}
 639
 640void rdma_rm_dealloc_srq(RdmaDeviceResources *dev_res, uint32_t srq_handle)
 641{
 642    RdmaRmSRQ *srq;
 643
 644    srq = rdma_rm_get_srq(dev_res, srq_handle);
 645    if (!srq) {
 646        return;
 647    }
 648
 649    rdma_backend_destroy_srq(&srq->backend_srq, dev_res);
 650    rdma_res_tbl_dealloc(&dev_res->srq_tbl, srq_handle);
 651}
 652
 653void *rdma_rm_get_cqe_ctx(RdmaDeviceResources *dev_res, uint32_t cqe_ctx_id)
 654{
 655    void **cqe_ctx;
 656
 657    cqe_ctx = rdma_res_tbl_get(&dev_res->cqe_ctx_tbl, cqe_ctx_id);
 658    if (!cqe_ctx) {
 659        return NULL;
 660    }
 661
 662    return *cqe_ctx;
 663}
 664
 665int rdma_rm_alloc_cqe_ctx(RdmaDeviceResources *dev_res, uint32_t *cqe_ctx_id,
 666                          void *ctx)
 667{
 668    void **cqe_ctx;
 669
 670    cqe_ctx = rdma_res_tbl_alloc(&dev_res->cqe_ctx_tbl, cqe_ctx_id);
 671    if (!cqe_ctx) {
 672        return -ENOMEM;
 673    }
 674
 675    *cqe_ctx = ctx;
 676
 677    return 0;
 678}
 679
 680void rdma_rm_dealloc_cqe_ctx(RdmaDeviceResources *dev_res, uint32_t cqe_ctx_id)
 681{
 682    rdma_res_tbl_dealloc(&dev_res->cqe_ctx_tbl, cqe_ctx_id);
 683}
 684
 685int rdma_rm_add_gid(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
 686                    const char *ifname, union ibv_gid *gid, int gid_idx)
 687{
 688    int rc;
 689
 690    rc = rdma_backend_add_gid(backend_dev, ifname, gid);
 691    if (rc) {
 692        return -EINVAL;
 693    }
 694
 695    memcpy(&dev_res->port.gid_tbl[gid_idx].gid, gid, sizeof(*gid));
 696
 697    return 0;
 698}
 699
 700int rdma_rm_del_gid(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
 701                    const char *ifname, int gid_idx)
 702{
 703    int rc;
 704
 705    if (!dev_res->port.gid_tbl[gid_idx].gid.global.interface_id) {
 706        return 0;
 707    }
 708
 709    rc = rdma_backend_del_gid(backend_dev, ifname,
 710                              &dev_res->port.gid_tbl[gid_idx].gid);
 711    if (rc) {
 712        return -EINVAL;
 713    }
 714
 715    memset(dev_res->port.gid_tbl[gid_idx].gid.raw, 0,
 716           sizeof(dev_res->port.gid_tbl[gid_idx].gid));
 717    dev_res->port.gid_tbl[gid_idx].backend_gid_index = -1;
 718
 719    return 0;
 720}
 721
 722int rdma_rm_get_backend_gid_index(RdmaDeviceResources *dev_res,
 723                                  RdmaBackendDev *backend_dev, int sgid_idx)
 724{
 725    if (unlikely(sgid_idx < 0 || sgid_idx >= MAX_PORT_GIDS)) {
 726        rdma_error_report("Got invalid sgid_idx %d", sgid_idx);
 727        return -EINVAL;
 728    }
 729
 730    if (unlikely(dev_res->port.gid_tbl[sgid_idx].backend_gid_index == -1)) {
 731        dev_res->port.gid_tbl[sgid_idx].backend_gid_index =
 732        rdma_backend_get_gid_index(backend_dev,
 733                                   &dev_res->port.gid_tbl[sgid_idx].gid);
 734    }
 735
 736    return dev_res->port.gid_tbl[sgid_idx].backend_gid_index;
 737}
 738
 739static void destroy_qp_hash_key(gpointer data)
 740{
 741    g_bytes_unref(data);
 742}
 743
 744static void init_ports(RdmaDeviceResources *dev_res)
 745{
 746    int i;
 747
 748    memset(&dev_res->port, 0, sizeof(dev_res->port));
 749
 750    dev_res->port.state = IBV_PORT_DOWN;
 751    for (i = 0; i < MAX_PORT_GIDS; i++) {
 752        dev_res->port.gid_tbl[i].backend_gid_index = -1;
 753    }
 754}
 755
 756static void fini_ports(RdmaDeviceResources *dev_res,
 757                       RdmaBackendDev *backend_dev, const char *ifname)
 758{
 759    int i;
 760
 761    dev_res->port.state = IBV_PORT_DOWN;
 762    for (i = 0; i < MAX_PORT_GIDS; i++) {
 763        rdma_rm_del_gid(dev_res, backend_dev, ifname, i);
 764    }
 765}
 766
 767int rdma_rm_init(RdmaDeviceResources *dev_res, struct ibv_device_attr *dev_attr)
 768{
 769    dev_res->qp_hash = g_hash_table_new_full(g_bytes_hash, g_bytes_equal,
 770                                             destroy_qp_hash_key, NULL);
 771    if (!dev_res->qp_hash) {
 772        return -ENOMEM;
 773    }
 774
 775    res_tbl_init("PD", &dev_res->pd_tbl, dev_attr->max_pd, sizeof(RdmaRmPD));
 776    res_tbl_init("CQ", &dev_res->cq_tbl, dev_attr->max_cq, sizeof(RdmaRmCQ));
 777    res_tbl_init("MR", &dev_res->mr_tbl, dev_attr->max_mr, sizeof(RdmaRmMR));
 778    res_tbl_init("QP", &dev_res->qp_tbl, dev_attr->max_qp, sizeof(RdmaRmQP));
 779    res_tbl_init("CQE_CTX", &dev_res->cqe_ctx_tbl, dev_attr->max_qp *
 780                       dev_attr->max_qp_wr, sizeof(void *));
 781    res_tbl_init("UC", &dev_res->uc_tbl, MAX_UCS, sizeof(RdmaRmUC));
 782    res_tbl_init("SRQ", &dev_res->srq_tbl, dev_attr->max_srq,
 783                 sizeof(RdmaRmSRQ));
 784
 785    init_ports(dev_res);
 786
 787    qemu_mutex_init(&dev_res->lock);
 788
 789    memset(&dev_res->stats, 0, sizeof(dev_res->stats));
 790    atomic_set(&dev_res->stats.missing_cqe, 0);
 791
 792    return 0;
 793}
 794
 795void rdma_rm_fini(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
 796                  const char *ifname)
 797{
 798    qemu_mutex_destroy(&dev_res->lock);
 799
 800    fini_ports(dev_res, backend_dev, ifname);
 801
 802    res_tbl_free(&dev_res->srq_tbl);
 803    res_tbl_free(&dev_res->uc_tbl);
 804    res_tbl_free(&dev_res->cqe_ctx_tbl);
 805    res_tbl_free(&dev_res->qp_tbl);
 806    res_tbl_free(&dev_res->mr_tbl);
 807    res_tbl_free(&dev_res->cq_tbl);
 808    res_tbl_free(&dev_res->pd_tbl);
 809
 810    if (dev_res->qp_hash) {
 811        g_hash_table_destroy(dev_res->qp_hash);
 812    }
 813}
 814