qemu/hw/rdma/vmw/pvrdma_cmd.c
<<
>>
Prefs
   1/*
   2 * QEMU paravirtual RDMA - Command channel
   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 "cpu.h"
  18#include "hw/pci/pci.h"
  19#include "hw/pci/pci_ids.h"
  20
  21#include "../rdma_backend.h"
  22#include "../rdma_rm.h"
  23#include "../rdma_utils.h"
  24
  25#include "trace.h"
  26#include "pvrdma.h"
  27#include "standard-headers/rdma/vmw_pvrdma-abi.h"
  28
  29static void *pvrdma_map_to_pdir(PCIDevice *pdev, uint64_t pdir_dma,
  30                                uint32_t nchunks, size_t length)
  31{
  32    uint64_t *dir, *tbl;
  33    int tbl_idx, dir_idx, addr_idx;
  34    void *host_virt = NULL, *curr_page;
  35
  36    if (!nchunks) {
  37        rdma_error_report("Got nchunks=0");
  38        return NULL;
  39    }
  40
  41    dir = rdma_pci_dma_map(pdev, pdir_dma, TARGET_PAGE_SIZE);
  42    if (!dir) {
  43        rdma_error_report("Failed to map to page directory");
  44        return NULL;
  45    }
  46
  47    tbl = rdma_pci_dma_map(pdev, dir[0], TARGET_PAGE_SIZE);
  48    if (!tbl) {
  49        rdma_error_report("Failed to map to page table 0");
  50        goto out_unmap_dir;
  51    }
  52
  53    curr_page = rdma_pci_dma_map(pdev, (dma_addr_t)tbl[0], TARGET_PAGE_SIZE);
  54    if (!curr_page) {
  55        rdma_error_report("Failed to map the page 0");
  56        goto out_unmap_tbl;
  57    }
  58
  59    host_virt = mremap(curr_page, 0, length, MREMAP_MAYMOVE);
  60    if (host_virt == MAP_FAILED) {
  61        host_virt = NULL;
  62        rdma_error_report("Failed to remap memory for host_virt");
  63        goto out_unmap_tbl;
  64    }
  65    trace_pvrdma_map_to_pdir_host_virt(curr_page, host_virt);
  66
  67    rdma_pci_dma_unmap(pdev, curr_page, TARGET_PAGE_SIZE);
  68
  69    dir_idx = 0;
  70    tbl_idx = 1;
  71    addr_idx = 1;
  72    while (addr_idx < nchunks) {
  73        if (tbl_idx == TARGET_PAGE_SIZE / sizeof(uint64_t)) {
  74            tbl_idx = 0;
  75            dir_idx++;
  76            rdma_pci_dma_unmap(pdev, tbl, TARGET_PAGE_SIZE);
  77            tbl = rdma_pci_dma_map(pdev, dir[dir_idx], TARGET_PAGE_SIZE);
  78            if (!tbl) {
  79                rdma_error_report("Failed to map to page table %d", dir_idx);
  80                goto out_unmap_host_virt;
  81            }
  82        }
  83
  84        curr_page = rdma_pci_dma_map(pdev, (dma_addr_t)tbl[tbl_idx],
  85                                     TARGET_PAGE_SIZE);
  86        if (!curr_page) {
  87            rdma_error_report("Failed to map to page %d, dir %d", tbl_idx,
  88                              dir_idx);
  89            goto out_unmap_host_virt;
  90        }
  91
  92        mremap(curr_page, 0, TARGET_PAGE_SIZE, MREMAP_MAYMOVE | MREMAP_FIXED,
  93               host_virt + TARGET_PAGE_SIZE * addr_idx);
  94
  95        trace_pvrdma_map_to_pdir_next_page(addr_idx, curr_page, host_virt +
  96                                           TARGET_PAGE_SIZE * addr_idx);
  97
  98        rdma_pci_dma_unmap(pdev, curr_page, TARGET_PAGE_SIZE);
  99
 100        addr_idx++;
 101
 102        tbl_idx++;
 103    }
 104
 105    goto out_unmap_tbl;
 106
 107out_unmap_host_virt:
 108    munmap(host_virt, length);
 109    host_virt = NULL;
 110
 111out_unmap_tbl:
 112    rdma_pci_dma_unmap(pdev, tbl, TARGET_PAGE_SIZE);
 113
 114out_unmap_dir:
 115    rdma_pci_dma_unmap(pdev, dir, TARGET_PAGE_SIZE);
 116
 117    return host_virt;
 118}
 119
 120static int query_port(PVRDMADev *dev, union pvrdma_cmd_req *req,
 121                      union pvrdma_cmd_resp *rsp)
 122{
 123    struct pvrdma_cmd_query_port *cmd = &req->query_port;
 124    struct pvrdma_cmd_query_port_resp *resp = &rsp->query_port_resp;
 125    struct pvrdma_port_attr attrs = {};
 126
 127    if (cmd->port_num > MAX_PORTS) {
 128        return -EINVAL;
 129    }
 130
 131    if (rdma_backend_query_port(&dev->backend_dev,
 132                                (struct ibv_port_attr *)&attrs)) {
 133        return -ENOMEM;
 134    }
 135
 136    memset(resp, 0, sizeof(*resp));
 137
 138    resp->attrs.state = dev->func0->device_active ? attrs.state :
 139                                                    PVRDMA_PORT_DOWN;
 140    resp->attrs.max_mtu = attrs.max_mtu;
 141    resp->attrs.active_mtu = attrs.active_mtu;
 142    resp->attrs.phys_state = attrs.phys_state;
 143    resp->attrs.gid_tbl_len = MIN(MAX_PORT_GIDS, attrs.gid_tbl_len);
 144    resp->attrs.max_msg_sz = 1024;
 145    resp->attrs.pkey_tbl_len = MIN(MAX_PORT_PKEYS, attrs.pkey_tbl_len);
 146    resp->attrs.active_width = 1;
 147    resp->attrs.active_speed = 1;
 148
 149    return 0;
 150}
 151
 152static int query_pkey(PVRDMADev *dev, union pvrdma_cmd_req *req,
 153                      union pvrdma_cmd_resp *rsp)
 154{
 155    struct pvrdma_cmd_query_pkey *cmd = &req->query_pkey;
 156    struct pvrdma_cmd_query_pkey_resp *resp = &rsp->query_pkey_resp;
 157
 158    if (cmd->port_num > MAX_PORTS) {
 159        return -EINVAL;
 160    }
 161
 162    if (cmd->index > MAX_PKEYS) {
 163        return -EINVAL;
 164    }
 165
 166    memset(resp, 0, sizeof(*resp));
 167
 168    resp->pkey = PVRDMA_PKEY;
 169
 170    return 0;
 171}
 172
 173static int create_pd(PVRDMADev *dev, union pvrdma_cmd_req *req,
 174                     union pvrdma_cmd_resp *rsp)
 175{
 176    struct pvrdma_cmd_create_pd *cmd = &req->create_pd;
 177    struct pvrdma_cmd_create_pd_resp *resp = &rsp->create_pd_resp;
 178    int rc;
 179
 180    memset(resp, 0, sizeof(*resp));
 181    rc = rdma_rm_alloc_pd(&dev->rdma_dev_res, &dev->backend_dev,
 182                          &resp->pd_handle, cmd->ctx_handle);
 183
 184    return rc;
 185}
 186
 187static int destroy_pd(PVRDMADev *dev, union pvrdma_cmd_req *req,
 188                      union pvrdma_cmd_resp *rsp)
 189{
 190    struct pvrdma_cmd_destroy_pd *cmd = &req->destroy_pd;
 191
 192    rdma_rm_dealloc_pd(&dev->rdma_dev_res, cmd->pd_handle);
 193
 194    return 0;
 195}
 196
 197static int create_mr(PVRDMADev *dev, union pvrdma_cmd_req *req,
 198                     union pvrdma_cmd_resp *rsp)
 199{
 200    struct pvrdma_cmd_create_mr *cmd = &req->create_mr;
 201    struct pvrdma_cmd_create_mr_resp *resp = &rsp->create_mr_resp;
 202    PCIDevice *pci_dev = PCI_DEVICE(dev);
 203    void *host_virt = NULL;
 204    int rc = 0;
 205
 206    memset(resp, 0, sizeof(*resp));
 207
 208    if (!(cmd->flags & PVRDMA_MR_FLAG_DMA)) {
 209        host_virt = pvrdma_map_to_pdir(pci_dev, cmd->pdir_dma, cmd->nchunks,
 210                                       cmd->length);
 211        if (!host_virt) {
 212            rdma_error_report("Failed to map to pdir");
 213            return -EINVAL;
 214        }
 215    }
 216
 217    rc = rdma_rm_alloc_mr(&dev->rdma_dev_res, cmd->pd_handle, cmd->start,
 218                          cmd->length, host_virt, cmd->access_flags,
 219                          &resp->mr_handle, &resp->lkey, &resp->rkey);
 220    if (rc && host_virt) {
 221        munmap(host_virt, cmd->length);
 222    }
 223
 224    return rc;
 225}
 226
 227static int destroy_mr(PVRDMADev *dev, union pvrdma_cmd_req *req,
 228                      union pvrdma_cmd_resp *rsp)
 229{
 230    struct pvrdma_cmd_destroy_mr *cmd = &req->destroy_mr;
 231
 232    rdma_rm_dealloc_mr(&dev->rdma_dev_res, cmd->mr_handle);
 233
 234    return 0;
 235}
 236
 237static int create_cq_ring(PCIDevice *pci_dev , PvrdmaRing **ring,
 238                          uint64_t pdir_dma, uint32_t nchunks, uint32_t cqe)
 239{
 240    uint64_t *dir = NULL, *tbl = NULL;
 241    PvrdmaRing *r;
 242    int rc = -EINVAL;
 243    char ring_name[MAX_RING_NAME_SZ];
 244
 245    if (!nchunks || nchunks > PVRDMA_MAX_FAST_REG_PAGES) {
 246        rdma_error_report("Got invalid nchunks: %d", nchunks);
 247        return rc;
 248    }
 249
 250    dir = rdma_pci_dma_map(pci_dev, pdir_dma, TARGET_PAGE_SIZE);
 251    if (!dir) {
 252        rdma_error_report("Failed to map to CQ page directory");
 253        goto out;
 254    }
 255
 256    tbl = rdma_pci_dma_map(pci_dev, dir[0], TARGET_PAGE_SIZE);
 257    if (!tbl) {
 258        rdma_error_report("Failed to map to CQ page table");
 259        goto out;
 260    }
 261
 262    r = g_malloc(sizeof(*r));
 263    *ring = r;
 264
 265    r->ring_state = (PvrdmaRingState *)
 266        rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE);
 267
 268    if (!r->ring_state) {
 269        rdma_error_report("Failed to map to CQ ring state");
 270        goto out_free_ring;
 271    }
 272
 273    sprintf(ring_name, "cq_ring_%" PRIx64, pdir_dma);
 274    rc = pvrdma_ring_init(r, ring_name, pci_dev, &r->ring_state[1],
 275                          cqe, sizeof(struct pvrdma_cqe),
 276                          /* first page is ring state */
 277                          (dma_addr_t *)&tbl[1], nchunks - 1);
 278    if (rc) {
 279        goto out_unmap_ring_state;
 280    }
 281
 282    goto out;
 283
 284out_unmap_ring_state:
 285    /* ring_state was in slot 1, not 0 so need to jump back */
 286    rdma_pci_dma_unmap(pci_dev, --r->ring_state, TARGET_PAGE_SIZE);
 287
 288out_free_ring:
 289    g_free(r);
 290
 291out:
 292    rdma_pci_dma_unmap(pci_dev, tbl, TARGET_PAGE_SIZE);
 293    rdma_pci_dma_unmap(pci_dev, dir, TARGET_PAGE_SIZE);
 294
 295    return rc;
 296}
 297
 298static void destroy_cq_ring(PvrdmaRing *ring)
 299{
 300    pvrdma_ring_free(ring);
 301    /* ring_state was in slot 1, not 0 so need to jump back */
 302    rdma_pci_dma_unmap(ring->dev, --ring->ring_state, TARGET_PAGE_SIZE);
 303    g_free(ring);
 304}
 305
 306static int create_cq(PVRDMADev *dev, union pvrdma_cmd_req *req,
 307                     union pvrdma_cmd_resp *rsp)
 308{
 309    struct pvrdma_cmd_create_cq *cmd = &req->create_cq;
 310    struct pvrdma_cmd_create_cq_resp *resp = &rsp->create_cq_resp;
 311    PvrdmaRing *ring = NULL;
 312    int rc;
 313
 314    memset(resp, 0, sizeof(*resp));
 315
 316    resp->cqe = cmd->cqe;
 317
 318    rc = create_cq_ring(PCI_DEVICE(dev), &ring, cmd->pdir_dma, cmd->nchunks,
 319                        cmd->cqe);
 320    if (rc) {
 321        return rc;
 322    }
 323
 324    rc = rdma_rm_alloc_cq(&dev->rdma_dev_res, &dev->backend_dev, cmd->cqe,
 325                          &resp->cq_handle, ring);
 326    if (rc) {
 327        destroy_cq_ring(ring);
 328    }
 329
 330    resp->cqe = cmd->cqe;
 331
 332    return rc;
 333}
 334
 335static int destroy_cq(PVRDMADev *dev, union pvrdma_cmd_req *req,
 336                      union pvrdma_cmd_resp *rsp)
 337{
 338    struct pvrdma_cmd_destroy_cq *cmd = &req->destroy_cq;
 339    RdmaRmCQ *cq;
 340    PvrdmaRing *ring;
 341
 342    cq = rdma_rm_get_cq(&dev->rdma_dev_res, cmd->cq_handle);
 343    if (!cq) {
 344        rdma_error_report("Got invalid CQ handle");
 345        return -EINVAL;
 346    }
 347
 348    ring = (PvrdmaRing *)cq->opaque;
 349    destroy_cq_ring(ring);
 350
 351    rdma_rm_dealloc_cq(&dev->rdma_dev_res, cmd->cq_handle);
 352
 353    return 0;
 354}
 355
 356static int create_qp_rings(PCIDevice *pci_dev, uint64_t pdir_dma,
 357                           PvrdmaRing **rings, uint32_t scqe, uint32_t smax_sge,
 358                           uint32_t spages, uint32_t rcqe, uint32_t rmax_sge,
 359                           uint32_t rpages, uint8_t is_srq)
 360{
 361    uint64_t *dir = NULL, *tbl = NULL;
 362    PvrdmaRing *sr, *rr;
 363    int rc = -EINVAL;
 364    char ring_name[MAX_RING_NAME_SZ];
 365    uint32_t wqe_sz;
 366
 367    if (!spages || spages > PVRDMA_MAX_FAST_REG_PAGES) {
 368        rdma_error_report("Got invalid send page count for QP ring: %d",
 369                          spages);
 370        return rc;
 371    }
 372
 373    if (!is_srq && (!rpages || rpages > PVRDMA_MAX_FAST_REG_PAGES)) {
 374        rdma_error_report("Got invalid recv page count for QP ring: %d",
 375                          rpages);
 376        return rc;
 377    }
 378
 379    dir = rdma_pci_dma_map(pci_dev, pdir_dma, TARGET_PAGE_SIZE);
 380    if (!dir) {
 381        rdma_error_report("Failed to map to QP page directory");
 382        goto out;
 383    }
 384
 385    tbl = rdma_pci_dma_map(pci_dev, dir[0], TARGET_PAGE_SIZE);
 386    if (!tbl) {
 387        rdma_error_report("Failed to map to QP page table");
 388        goto out;
 389    }
 390
 391    if (!is_srq) {
 392        sr = g_malloc(2 * sizeof(*rr));
 393        rr = &sr[1];
 394    } else {
 395        sr = g_malloc(sizeof(*sr));
 396    }
 397
 398    *rings = sr;
 399
 400    /* Create send ring */
 401    sr->ring_state = (PvrdmaRingState *)
 402        rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE);
 403    if (!sr->ring_state) {
 404        rdma_error_report("Failed to map to QP ring state");
 405        goto out_free_sr_mem;
 406    }
 407
 408    wqe_sz = pow2ceil(sizeof(struct pvrdma_sq_wqe_hdr) +
 409                      sizeof(struct pvrdma_sge) * smax_sge - 1);
 410
 411    sprintf(ring_name, "qp_sring_%" PRIx64, pdir_dma);
 412    rc = pvrdma_ring_init(sr, ring_name, pci_dev, sr->ring_state,
 413                          scqe, wqe_sz, (dma_addr_t *)&tbl[1], spages);
 414    if (rc) {
 415        goto out_unmap_ring_state;
 416    }
 417
 418    if (!is_srq) {
 419        /* Create recv ring */
 420        rr->ring_state = &sr->ring_state[1];
 421        wqe_sz = pow2ceil(sizeof(struct pvrdma_rq_wqe_hdr) +
 422                          sizeof(struct pvrdma_sge) * rmax_sge - 1);
 423        sprintf(ring_name, "qp_rring_%" PRIx64, pdir_dma);
 424        rc = pvrdma_ring_init(rr, ring_name, pci_dev, rr->ring_state,
 425                              rcqe, wqe_sz, (dma_addr_t *)&tbl[1 + spages],
 426                              rpages);
 427        if (rc) {
 428            goto out_free_sr;
 429        }
 430    }
 431
 432    goto out;
 433
 434out_free_sr:
 435    pvrdma_ring_free(sr);
 436
 437out_unmap_ring_state:
 438    rdma_pci_dma_unmap(pci_dev, sr->ring_state, TARGET_PAGE_SIZE);
 439
 440out_free_sr_mem:
 441    g_free(sr);
 442
 443out:
 444    rdma_pci_dma_unmap(pci_dev, tbl, TARGET_PAGE_SIZE);
 445    rdma_pci_dma_unmap(pci_dev, dir, TARGET_PAGE_SIZE);
 446
 447    return rc;
 448}
 449
 450static void destroy_qp_rings(PvrdmaRing *ring, uint8_t is_srq)
 451{
 452    pvrdma_ring_free(&ring[0]);
 453    if (!is_srq) {
 454        pvrdma_ring_free(&ring[1]);
 455    }
 456
 457    rdma_pci_dma_unmap(ring->dev, ring->ring_state, TARGET_PAGE_SIZE);
 458    g_free(ring);
 459}
 460
 461static int create_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
 462                     union pvrdma_cmd_resp *rsp)
 463{
 464    struct pvrdma_cmd_create_qp *cmd = &req->create_qp;
 465    struct pvrdma_cmd_create_qp_resp *resp = &rsp->create_qp_resp;
 466    PvrdmaRing *rings = NULL;
 467    int rc;
 468
 469    memset(resp, 0, sizeof(*resp));
 470
 471    rc = create_qp_rings(PCI_DEVICE(dev), cmd->pdir_dma, &rings,
 472                         cmd->max_send_wr, cmd->max_send_sge, cmd->send_chunks,
 473                         cmd->max_recv_wr, cmd->max_recv_sge,
 474                         cmd->total_chunks - cmd->send_chunks - 1, cmd->is_srq);
 475    if (rc) {
 476        return rc;
 477    }
 478
 479    rc = rdma_rm_alloc_qp(&dev->rdma_dev_res, cmd->pd_handle, cmd->qp_type,
 480                          cmd->max_send_wr, cmd->max_send_sge,
 481                          cmd->send_cq_handle, cmd->max_recv_wr,
 482                          cmd->max_recv_sge, cmd->recv_cq_handle, rings,
 483                          &resp->qpn, cmd->is_srq, cmd->srq_handle);
 484    if (rc) {
 485        destroy_qp_rings(rings, cmd->is_srq);
 486        return rc;
 487    }
 488
 489    resp->max_send_wr = cmd->max_send_wr;
 490    resp->max_recv_wr = cmd->max_recv_wr;
 491    resp->max_send_sge = cmd->max_send_sge;
 492    resp->max_recv_sge = cmd->max_recv_sge;
 493    resp->max_inline_data = cmd->max_inline_data;
 494
 495    return 0;
 496}
 497
 498static int modify_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
 499                     union pvrdma_cmd_resp *rsp)
 500{
 501    struct pvrdma_cmd_modify_qp *cmd = &req->modify_qp;
 502    int rc;
 503
 504    /* No need to verify sgid_index since it is u8 */
 505
 506    rc = rdma_rm_modify_qp(&dev->rdma_dev_res, &dev->backend_dev,
 507                           cmd->qp_handle, cmd->attr_mask,
 508                           cmd->attrs.ah_attr.grh.sgid_index,
 509                           (union ibv_gid *)&cmd->attrs.ah_attr.grh.dgid,
 510                           cmd->attrs.dest_qp_num,
 511                           (enum ibv_qp_state)cmd->attrs.qp_state,
 512                           cmd->attrs.qkey, cmd->attrs.rq_psn,
 513                           cmd->attrs.sq_psn);
 514
 515    return rc;
 516}
 517
 518static int query_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
 519                     union pvrdma_cmd_resp *rsp)
 520{
 521    struct pvrdma_cmd_query_qp *cmd = &req->query_qp;
 522    struct pvrdma_cmd_query_qp_resp *resp = &rsp->query_qp_resp;
 523    struct ibv_qp_init_attr init_attr;
 524    int rc;
 525
 526    memset(resp, 0, sizeof(*resp));
 527
 528    rc = rdma_rm_query_qp(&dev->rdma_dev_res, &dev->backend_dev, cmd->qp_handle,
 529                          (struct ibv_qp_attr *)&resp->attrs, cmd->attr_mask,
 530                          &init_attr);
 531
 532    return rc;
 533}
 534
 535static int destroy_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
 536                      union pvrdma_cmd_resp *rsp)
 537{
 538    struct pvrdma_cmd_destroy_qp *cmd = &req->destroy_qp;
 539    RdmaRmQP *qp;
 540    PvrdmaRing *ring;
 541
 542    qp = rdma_rm_get_qp(&dev->rdma_dev_res, cmd->qp_handle);
 543    if (!qp) {
 544        return -EINVAL;
 545    }
 546
 547    ring = (PvrdmaRing *)qp->opaque;
 548    destroy_qp_rings(ring, qp->is_srq);
 549    rdma_rm_dealloc_qp(&dev->rdma_dev_res, cmd->qp_handle);
 550
 551    return 0;
 552}
 553
 554static int create_bind(PVRDMADev *dev, union pvrdma_cmd_req *req,
 555                       union pvrdma_cmd_resp *rsp)
 556{
 557    struct pvrdma_cmd_create_bind *cmd = &req->create_bind;
 558    int rc;
 559    union ibv_gid *gid = (union ibv_gid *)&cmd->new_gid;
 560
 561    if (cmd->index >= MAX_PORT_GIDS) {
 562        return -EINVAL;
 563    }
 564
 565    rc = rdma_rm_add_gid(&dev->rdma_dev_res, &dev->backend_dev,
 566                         dev->backend_eth_device_name, gid, cmd->index);
 567
 568    return rc;
 569}
 570
 571static int destroy_bind(PVRDMADev *dev, union pvrdma_cmd_req *req,
 572                        union pvrdma_cmd_resp *rsp)
 573{
 574    int rc;
 575
 576    struct pvrdma_cmd_destroy_bind *cmd = &req->destroy_bind;
 577
 578    if (cmd->index >= MAX_PORT_GIDS) {
 579        return -EINVAL;
 580    }
 581
 582    rc = rdma_rm_del_gid(&dev->rdma_dev_res, &dev->backend_dev,
 583                        dev->backend_eth_device_name, cmd->index);
 584
 585    return rc;
 586}
 587
 588static int create_uc(PVRDMADev *dev, union pvrdma_cmd_req *req,
 589                     union pvrdma_cmd_resp *rsp)
 590{
 591    struct pvrdma_cmd_create_uc *cmd = &req->create_uc;
 592    struct pvrdma_cmd_create_uc_resp *resp = &rsp->create_uc_resp;
 593    int rc;
 594
 595    memset(resp, 0, sizeof(*resp));
 596    rc = rdma_rm_alloc_uc(&dev->rdma_dev_res, cmd->pfn, &resp->ctx_handle);
 597
 598    return rc;
 599}
 600
 601static int destroy_uc(PVRDMADev *dev, union pvrdma_cmd_req *req,
 602                      union pvrdma_cmd_resp *rsp)
 603{
 604    struct pvrdma_cmd_destroy_uc *cmd = &req->destroy_uc;
 605
 606    rdma_rm_dealloc_uc(&dev->rdma_dev_res, cmd->ctx_handle);
 607
 608    return 0;
 609}
 610
 611static int create_srq_ring(PCIDevice *pci_dev, PvrdmaRing **ring,
 612                           uint64_t pdir_dma, uint32_t max_wr,
 613                           uint32_t max_sge, uint32_t nchunks)
 614{
 615    uint64_t *dir = NULL, *tbl = NULL;
 616    PvrdmaRing *r;
 617    int rc = -EINVAL;
 618    char ring_name[MAX_RING_NAME_SZ];
 619    uint32_t wqe_sz;
 620
 621    if (!nchunks || nchunks > PVRDMA_MAX_FAST_REG_PAGES) {
 622        rdma_error_report("Got invalid page count for SRQ ring: %d",
 623                          nchunks);
 624        return rc;
 625    }
 626
 627    dir = rdma_pci_dma_map(pci_dev, pdir_dma, TARGET_PAGE_SIZE);
 628    if (!dir) {
 629        rdma_error_report("Failed to map to SRQ page directory");
 630        goto out;
 631    }
 632
 633    tbl = rdma_pci_dma_map(pci_dev, dir[0], TARGET_PAGE_SIZE);
 634    if (!tbl) {
 635        rdma_error_report("Failed to map to SRQ page table");
 636        goto out;
 637    }
 638
 639    r = g_malloc(sizeof(*r));
 640    *ring = r;
 641
 642    r->ring_state = (PvrdmaRingState *)
 643            rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE);
 644    if (!r->ring_state) {
 645        rdma_error_report("Failed to map tp SRQ ring state");
 646        goto out_free_ring_mem;
 647    }
 648
 649    wqe_sz = pow2ceil(sizeof(struct pvrdma_rq_wqe_hdr) +
 650                      sizeof(struct pvrdma_sge) * max_sge - 1);
 651    sprintf(ring_name, "srq_ring_%" PRIx64, pdir_dma);
 652    rc = pvrdma_ring_init(r, ring_name, pci_dev, &r->ring_state[1], max_wr,
 653                          wqe_sz, (dma_addr_t *)&tbl[1], nchunks - 1);
 654    if (rc) {
 655        goto out_unmap_ring_state;
 656    }
 657
 658    goto out;
 659
 660out_unmap_ring_state:
 661    rdma_pci_dma_unmap(pci_dev, r->ring_state, TARGET_PAGE_SIZE);
 662
 663out_free_ring_mem:
 664    g_free(r);
 665
 666out:
 667    rdma_pci_dma_unmap(pci_dev, tbl, TARGET_PAGE_SIZE);
 668    rdma_pci_dma_unmap(pci_dev, dir, TARGET_PAGE_SIZE);
 669
 670    return rc;
 671}
 672
 673static void destroy_srq_ring(PvrdmaRing *ring)
 674{
 675    pvrdma_ring_free(ring);
 676    rdma_pci_dma_unmap(ring->dev, ring->ring_state, TARGET_PAGE_SIZE);
 677    g_free(ring);
 678}
 679
 680static int create_srq(PVRDMADev *dev, union pvrdma_cmd_req *req,
 681                      union pvrdma_cmd_resp *rsp)
 682{
 683    struct pvrdma_cmd_create_srq *cmd = &req->create_srq;
 684    struct pvrdma_cmd_create_srq_resp *resp = &rsp->create_srq_resp;
 685    PvrdmaRing *ring = NULL;
 686    int rc;
 687
 688    memset(resp, 0, sizeof(*resp));
 689
 690    rc = create_srq_ring(PCI_DEVICE(dev), &ring, cmd->pdir_dma,
 691                         cmd->attrs.max_wr, cmd->attrs.max_sge,
 692                         cmd->nchunks);
 693    if (rc) {
 694        return rc;
 695    }
 696
 697    rc = rdma_rm_alloc_srq(&dev->rdma_dev_res, cmd->pd_handle,
 698                           cmd->attrs.max_wr, cmd->attrs.max_sge,
 699                           cmd->attrs.srq_limit, &resp->srqn, ring);
 700    if (rc) {
 701        destroy_srq_ring(ring);
 702        return rc;
 703    }
 704
 705    return 0;
 706}
 707
 708static int query_srq(PVRDMADev *dev, union pvrdma_cmd_req *req,
 709                     union pvrdma_cmd_resp *rsp)
 710{
 711    struct pvrdma_cmd_query_srq *cmd = &req->query_srq;
 712    struct pvrdma_cmd_query_srq_resp *resp = &rsp->query_srq_resp;
 713
 714    memset(resp, 0, sizeof(*resp));
 715
 716    return rdma_rm_query_srq(&dev->rdma_dev_res, cmd->srq_handle,
 717                             (struct ibv_srq_attr *)&resp->attrs);
 718}
 719
 720static int modify_srq(PVRDMADev *dev, union pvrdma_cmd_req *req,
 721                      union pvrdma_cmd_resp *rsp)
 722{
 723    struct pvrdma_cmd_modify_srq *cmd = &req->modify_srq;
 724
 725    /* Only support SRQ limit */
 726    if (!(cmd->attr_mask & IBV_SRQ_LIMIT) ||
 727        (cmd->attr_mask & IBV_SRQ_MAX_WR))
 728            return -EINVAL;
 729
 730    return rdma_rm_modify_srq(&dev->rdma_dev_res, cmd->srq_handle,
 731                              (struct ibv_srq_attr *)&cmd->attrs,
 732                              cmd->attr_mask);
 733}
 734
 735static int destroy_srq(PVRDMADev *dev, union pvrdma_cmd_req *req,
 736                       union pvrdma_cmd_resp *rsp)
 737{
 738    struct pvrdma_cmd_destroy_srq *cmd = &req->destroy_srq;
 739    RdmaRmSRQ *srq;
 740    PvrdmaRing *ring;
 741
 742    srq = rdma_rm_get_srq(&dev->rdma_dev_res, cmd->srq_handle);
 743    if (!srq) {
 744        return -EINVAL;
 745    }
 746
 747    ring = (PvrdmaRing *)srq->opaque;
 748    destroy_srq_ring(ring);
 749    rdma_rm_dealloc_srq(&dev->rdma_dev_res, cmd->srq_handle);
 750
 751    return 0;
 752}
 753
 754struct cmd_handler {
 755    uint32_t cmd;
 756    uint32_t ack;
 757    int (*exec)(PVRDMADev *dev, union pvrdma_cmd_req *req,
 758            union pvrdma_cmd_resp *rsp);
 759};
 760
 761static struct cmd_handler cmd_handlers[] = {
 762    {PVRDMA_CMD_QUERY_PORT,   PVRDMA_CMD_QUERY_PORT_RESP,        query_port},
 763    {PVRDMA_CMD_QUERY_PKEY,   PVRDMA_CMD_QUERY_PKEY_RESP,        query_pkey},
 764    {PVRDMA_CMD_CREATE_PD,    PVRDMA_CMD_CREATE_PD_RESP,         create_pd},
 765    {PVRDMA_CMD_DESTROY_PD,   PVRDMA_CMD_DESTROY_PD_RESP_NOOP,   destroy_pd},
 766    {PVRDMA_CMD_CREATE_MR,    PVRDMA_CMD_CREATE_MR_RESP,         create_mr},
 767    {PVRDMA_CMD_DESTROY_MR,   PVRDMA_CMD_DESTROY_MR_RESP_NOOP,   destroy_mr},
 768    {PVRDMA_CMD_CREATE_CQ,    PVRDMA_CMD_CREATE_CQ_RESP,         create_cq},
 769    {PVRDMA_CMD_RESIZE_CQ,    PVRDMA_CMD_RESIZE_CQ_RESP,         NULL},
 770    {PVRDMA_CMD_DESTROY_CQ,   PVRDMA_CMD_DESTROY_CQ_RESP_NOOP,   destroy_cq},
 771    {PVRDMA_CMD_CREATE_QP,    PVRDMA_CMD_CREATE_QP_RESP,         create_qp},
 772    {PVRDMA_CMD_MODIFY_QP,    PVRDMA_CMD_MODIFY_QP_RESP,         modify_qp},
 773    {PVRDMA_CMD_QUERY_QP,     PVRDMA_CMD_QUERY_QP_RESP,          query_qp},
 774    {PVRDMA_CMD_DESTROY_QP,   PVRDMA_CMD_DESTROY_QP_RESP,        destroy_qp},
 775    {PVRDMA_CMD_CREATE_UC,    PVRDMA_CMD_CREATE_UC_RESP,         create_uc},
 776    {PVRDMA_CMD_DESTROY_UC,   PVRDMA_CMD_DESTROY_UC_RESP_NOOP,   destroy_uc},
 777    {PVRDMA_CMD_CREATE_BIND,  PVRDMA_CMD_CREATE_BIND_RESP_NOOP,  create_bind},
 778    {PVRDMA_CMD_DESTROY_BIND, PVRDMA_CMD_DESTROY_BIND_RESP_NOOP, destroy_bind},
 779    {PVRDMA_CMD_CREATE_SRQ,   PVRDMA_CMD_CREATE_SRQ_RESP,        create_srq},
 780    {PVRDMA_CMD_QUERY_SRQ,    PVRDMA_CMD_QUERY_SRQ_RESP,         query_srq},
 781    {PVRDMA_CMD_MODIFY_SRQ,   PVRDMA_CMD_MODIFY_SRQ_RESP,        modify_srq},
 782    {PVRDMA_CMD_DESTROY_SRQ,  PVRDMA_CMD_DESTROY_SRQ_RESP,       destroy_srq},
 783};
 784
 785int pvrdma_exec_cmd(PVRDMADev *dev)
 786{
 787    int err = 0xFFFF;
 788    DSRInfo *dsr_info;
 789
 790    dsr_info = &dev->dsr_info;
 791
 792    if (dsr_info->req->hdr.cmd >= sizeof(cmd_handlers) /
 793                      sizeof(struct cmd_handler)) {
 794        rdma_error_report("Unsupported command");
 795        goto out;
 796    }
 797
 798    if (!cmd_handlers[dsr_info->req->hdr.cmd].exec) {
 799        rdma_error_report("Unsupported command (not implemented yet)");
 800        goto out;
 801    }
 802
 803    err = cmd_handlers[dsr_info->req->hdr.cmd].exec(dev, dsr_info->req,
 804                                                    dsr_info->rsp);
 805    dsr_info->rsp->hdr.response = dsr_info->req->hdr.response;
 806    dsr_info->rsp->hdr.ack = cmd_handlers[dsr_info->req->hdr.cmd].ack;
 807    dsr_info->rsp->hdr.err = err < 0 ? -err : 0;
 808
 809    trace_pvrdma_exec_cmd(dsr_info->req->hdr.cmd, dsr_info->rsp->hdr.err);
 810
 811    dev->stats.commands++;
 812
 813out:
 814    set_reg_val(dev, PVRDMA_REG_ERR, err);
 815    post_interrupt(dev, INTR_VEC_CMD_RING);
 816
 817    return (err == 0) ? 0 : -EINVAL;
 818}
 819