cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

pvrdma_cmd.c (24856B)


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