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_qp_ops.c (8317B)


      1/*
      2 * QEMU paravirtual RDMA - QP 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
     18#include "../rdma_utils.h"
     19#include "../rdma_rm.h"
     20#include "../rdma_backend.h"
     21
     22#include "trace.h"
     23
     24#include "pvrdma.h"
     25#include "standard-headers/rdma/vmw_pvrdma-abi.h"
     26#include "pvrdma_qp_ops.h"
     27
     28typedef struct CompHandlerCtx {
     29    PVRDMADev *dev;
     30    uint32_t cq_handle;
     31    struct pvrdma_cqe cqe;
     32} CompHandlerCtx;
     33
     34/* Send Queue WQE */
     35typedef struct PvrdmaSqWqe {
     36    struct pvrdma_sq_wqe_hdr hdr;
     37    struct pvrdma_sge sge[];
     38} PvrdmaSqWqe;
     39
     40/* Recv Queue WQE */
     41typedef struct PvrdmaRqWqe {
     42    struct pvrdma_rq_wqe_hdr hdr;
     43    struct pvrdma_sge sge[];
     44} PvrdmaRqWqe;
     45
     46/*
     47 * 1. Put CQE on send CQ ring
     48 * 2. Put CQ number on dsr completion ring
     49 * 3. Interrupt host
     50 */
     51static int pvrdma_post_cqe(PVRDMADev *dev, uint32_t cq_handle,
     52                           struct pvrdma_cqe *cqe, struct ibv_wc *wc)
     53{
     54    struct pvrdma_cqe *cqe1;
     55    struct pvrdma_cqne *cqne;
     56    PvrdmaRing *ring;
     57    RdmaRmCQ *cq = rdma_rm_get_cq(&dev->rdma_dev_res, cq_handle);
     58
     59    if (unlikely(!cq)) {
     60        return -EINVAL;
     61    }
     62
     63    ring = (PvrdmaRing *)cq->opaque;
     64
     65    /* Step #1: Put CQE on CQ ring */
     66    cqe1 = pvrdma_ring_next_elem_write(ring);
     67    if (unlikely(!cqe1)) {
     68        return -EINVAL;
     69    }
     70
     71    memset(cqe1, 0, sizeof(*cqe1));
     72    cqe1->wr_id = cqe->wr_id;
     73    cqe1->qp = cqe->qp ? cqe->qp : wc->qp_num;
     74    cqe1->opcode = cqe->opcode;
     75    cqe1->status = wc->status;
     76    cqe1->byte_len = wc->byte_len;
     77    cqe1->src_qp = wc->src_qp;
     78    cqe1->wc_flags = wc->wc_flags;
     79    cqe1->vendor_err = wc->vendor_err;
     80
     81    trace_pvrdma_post_cqe(cq_handle, cq->notify, cqe1->wr_id, cqe1->qp,
     82                          cqe1->opcode, cqe1->status, cqe1->byte_len,
     83                          cqe1->src_qp, cqe1->wc_flags, cqe1->vendor_err);
     84
     85    pvrdma_ring_write_inc(ring);
     86
     87    /* Step #2: Put CQ number on dsr completion ring */
     88    cqne = pvrdma_ring_next_elem_write(&dev->dsr_info.cq);
     89    if (unlikely(!cqne)) {
     90        return -EINVAL;
     91    }
     92
     93    cqne->info = cq_handle;
     94    pvrdma_ring_write_inc(&dev->dsr_info.cq);
     95
     96    if (cq->notify != CNT_CLEAR) {
     97        if (cq->notify == CNT_ARM) {
     98            cq->notify = CNT_CLEAR;
     99        }
    100        post_interrupt(dev, INTR_VEC_CMD_COMPLETION_Q);
    101    }
    102
    103    return 0;
    104}
    105
    106static void pvrdma_qp_ops_comp_handler(void *ctx, struct ibv_wc *wc)
    107{
    108    CompHandlerCtx *comp_ctx = (CompHandlerCtx *)ctx;
    109
    110    pvrdma_post_cqe(comp_ctx->dev, comp_ctx->cq_handle, &comp_ctx->cqe, wc);
    111
    112    g_free(ctx);
    113}
    114
    115static void complete_with_error(uint32_t vendor_err, void *ctx)
    116{
    117    struct ibv_wc wc = {};
    118
    119    wc.status = IBV_WC_GENERAL_ERR;
    120    wc.vendor_err = vendor_err;
    121
    122    pvrdma_qp_ops_comp_handler(ctx, &wc);
    123}
    124
    125void pvrdma_qp_ops_fini(void)
    126{
    127    rdma_backend_unregister_comp_handler();
    128}
    129
    130int pvrdma_qp_ops_init(void)
    131{
    132    rdma_backend_register_comp_handler(pvrdma_qp_ops_comp_handler);
    133
    134    return 0;
    135}
    136
    137void pvrdma_qp_send(PVRDMADev *dev, uint32_t qp_handle)
    138{
    139    RdmaRmQP *qp;
    140    PvrdmaSqWqe *wqe;
    141    PvrdmaRing *ring;
    142    int sgid_idx;
    143    union ibv_gid *sgid;
    144
    145    qp = rdma_rm_get_qp(&dev->rdma_dev_res, qp_handle);
    146    if (unlikely(!qp)) {
    147        return;
    148    }
    149
    150    ring = (PvrdmaRing *)qp->opaque;
    151
    152    wqe = (struct PvrdmaSqWqe *)pvrdma_ring_next_elem_read(ring);
    153    while (wqe) {
    154        CompHandlerCtx *comp_ctx;
    155
    156        /* Prepare CQE */
    157        comp_ctx = g_malloc(sizeof(CompHandlerCtx));
    158        comp_ctx->dev = dev;
    159        comp_ctx->cq_handle = qp->send_cq_handle;
    160        comp_ctx->cqe.wr_id = wqe->hdr.wr_id;
    161        comp_ctx->cqe.qp = qp_handle;
    162        comp_ctx->cqe.opcode = IBV_WC_SEND;
    163
    164        sgid = rdma_rm_get_gid(&dev->rdma_dev_res, wqe->hdr.wr.ud.av.gid_index);
    165        if (!sgid) {
    166            rdma_error_report("Failed to get gid for idx %d",
    167                              wqe->hdr.wr.ud.av.gid_index);
    168            complete_with_error(VENDOR_ERR_INV_GID_IDX, comp_ctx);
    169            continue;
    170        }
    171
    172        sgid_idx = rdma_rm_get_backend_gid_index(&dev->rdma_dev_res,
    173                                                 &dev->backend_dev,
    174                                                 wqe->hdr.wr.ud.av.gid_index);
    175        if (sgid_idx <= 0) {
    176            rdma_error_report("Failed to get bk sgid_idx for sgid_idx %d",
    177                              wqe->hdr.wr.ud.av.gid_index);
    178            complete_with_error(VENDOR_ERR_INV_GID_IDX, comp_ctx);
    179            continue;
    180        }
    181
    182        if (wqe->hdr.num_sge > dev->dev_attr.max_sge) {
    183            rdma_error_report("Invalid num_sge=%d (max %d)", wqe->hdr.num_sge,
    184                              dev->dev_attr.max_sge);
    185            complete_with_error(VENDOR_ERR_INV_NUM_SGE, comp_ctx);
    186            continue;
    187        }
    188
    189        rdma_backend_post_send(&dev->backend_dev, &qp->backend_qp, qp->qp_type,
    190                               (struct ibv_sge *)&wqe->sge[0], wqe->hdr.num_sge,
    191                               sgid_idx, sgid,
    192                               (union ibv_gid *)wqe->hdr.wr.ud.av.dgid,
    193                               wqe->hdr.wr.ud.remote_qpn,
    194                               wqe->hdr.wr.ud.remote_qkey, comp_ctx);
    195
    196        pvrdma_ring_read_inc(ring);
    197
    198        wqe = pvrdma_ring_next_elem_read(ring);
    199    }
    200}
    201
    202void pvrdma_qp_recv(PVRDMADev *dev, uint32_t qp_handle)
    203{
    204    RdmaRmQP *qp;
    205    PvrdmaRqWqe *wqe;
    206    PvrdmaRing *ring;
    207
    208    qp = rdma_rm_get_qp(&dev->rdma_dev_res, qp_handle);
    209    if (unlikely(!qp)) {
    210        return;
    211    }
    212
    213    ring = &((PvrdmaRing *)qp->opaque)[1];
    214
    215    wqe = (struct PvrdmaRqWqe *)pvrdma_ring_next_elem_read(ring);
    216    while (wqe) {
    217        CompHandlerCtx *comp_ctx;
    218
    219        /* Prepare CQE */
    220        comp_ctx = g_malloc(sizeof(CompHandlerCtx));
    221        comp_ctx->dev = dev;
    222        comp_ctx->cq_handle = qp->recv_cq_handle;
    223        comp_ctx->cqe.wr_id = wqe->hdr.wr_id;
    224        comp_ctx->cqe.qp = qp_handle;
    225        comp_ctx->cqe.opcode = IBV_WC_RECV;
    226
    227        if (wqe->hdr.num_sge > dev->dev_attr.max_sge) {
    228            rdma_error_report("Invalid num_sge=%d (max %d)", wqe->hdr.num_sge,
    229                              dev->dev_attr.max_sge);
    230            complete_with_error(VENDOR_ERR_INV_NUM_SGE, comp_ctx);
    231            continue;
    232        }
    233
    234        rdma_backend_post_recv(&dev->backend_dev, &qp->backend_qp, qp->qp_type,
    235                               (struct ibv_sge *)&wqe->sge[0], wqe->hdr.num_sge,
    236                               comp_ctx);
    237
    238        pvrdma_ring_read_inc(ring);
    239
    240        wqe = pvrdma_ring_next_elem_read(ring);
    241    }
    242}
    243
    244void pvrdma_srq_recv(PVRDMADev *dev, uint32_t srq_handle)
    245{
    246    RdmaRmSRQ *srq;
    247    PvrdmaRqWqe *wqe;
    248    PvrdmaRing *ring;
    249
    250    srq = rdma_rm_get_srq(&dev->rdma_dev_res, srq_handle);
    251    if (unlikely(!srq)) {
    252        return;
    253    }
    254
    255    ring = (PvrdmaRing *)srq->opaque;
    256
    257    wqe = (struct PvrdmaRqWqe *)pvrdma_ring_next_elem_read(ring);
    258    while (wqe) {
    259        CompHandlerCtx *comp_ctx;
    260
    261        /* Prepare CQE */
    262        comp_ctx = g_malloc(sizeof(CompHandlerCtx));
    263        comp_ctx->dev = dev;
    264        comp_ctx->cq_handle = srq->recv_cq_handle;
    265        comp_ctx->cqe.wr_id = wqe->hdr.wr_id;
    266        comp_ctx->cqe.qp = 0;
    267        comp_ctx->cqe.opcode = IBV_WC_RECV;
    268
    269        if (wqe->hdr.num_sge > dev->dev_attr.max_sge) {
    270            rdma_error_report("Invalid num_sge=%d (max %d)", wqe->hdr.num_sge,
    271                              dev->dev_attr.max_sge);
    272            complete_with_error(VENDOR_ERR_INV_NUM_SGE, comp_ctx);
    273            continue;
    274        }
    275
    276        rdma_backend_post_srq_recv(&dev->backend_dev, &srq->backend_srq,
    277                                   (struct ibv_sge *)&wqe->sge[0],
    278                                   wqe->hdr.num_sge,
    279                                   comp_ctx);
    280
    281        pvrdma_ring_read_inc(ring);
    282
    283        wqe = pvrdma_ring_next_elem_read(ring);
    284    }
    285
    286}
    287
    288void pvrdma_cq_poll(RdmaDeviceResources *dev_res, uint32_t cq_handle)
    289{
    290    RdmaRmCQ *cq;
    291
    292    cq = rdma_rm_get_cq(dev_res, cq_handle);
    293    if (!cq) {
    294        return;
    295    }
    296
    297    rdma_backend_poll_cq(dev_res, &cq->backend_cq);
    298}