Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
0003  *
0004  * This software is available to you under a choice of one of two
0005  * licenses.  You may choose to be licensed under the terms of the GNU
0006  * General Public License (GPL) Version 2, available from the file
0007  * COPYING in the main directory of this source tree, or the
0008  * OpenIB.org BSD license below:
0009  *
0010  *     Redistribution and use in source and binary forms, with or
0011  *     without modification, are permitted provided that the following
0012  *     conditions are met:
0013  *
0014  *      - Redistributions of source code must retain the above
0015  *        copyright notice, this list of conditions and the following
0016  *        disclaimer.
0017  *
0018  *      - Redistributions in binary form must reproduce the above
0019  *        copyright notice, this list of conditions and the following
0020  *        disclaimer in the documentation and/or other materials
0021  *        provided with the distribution.
0022  *
0023  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0024  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0025  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0026  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
0027  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0028  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0029  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0030  * SOFTWARE.
0031  *
0032  */
0033 
0034 #include <net/addrconf.h>
0035 #include <linux/etherdevice.h>
0036 #include <linux/mlx5/vport.h>
0037 
0038 #include "mlx5_core.h"
0039 #include "lib/mlx5.h"
0040 #include "fpga/conn.h"
0041 
0042 #define MLX5_FPGA_PKEY 0xFFFF
0043 #define MLX5_FPGA_PKEY_INDEX 0 /* RoCE PKEY 0xFFFF is always at index 0 */
0044 #define MLX5_FPGA_RECV_SIZE 2048
0045 #define MLX5_FPGA_PORT_NUM 1
0046 #define MLX5_FPGA_CQ_BUDGET 64
0047 
0048 static int mlx5_fpga_conn_map_buf(struct mlx5_fpga_conn *conn,
0049                   struct mlx5_fpga_dma_buf *buf)
0050 {
0051     struct device *dma_device;
0052     int err = 0;
0053 
0054     if (unlikely(!buf->sg[0].data))
0055         goto out;
0056 
0057     dma_device = mlx5_core_dma_dev(conn->fdev->mdev);
0058     buf->sg[0].dma_addr = dma_map_single(dma_device, buf->sg[0].data,
0059                          buf->sg[0].size, buf->dma_dir);
0060     err = dma_mapping_error(dma_device, buf->sg[0].dma_addr);
0061     if (unlikely(err)) {
0062         mlx5_fpga_warn(conn->fdev, "DMA error on sg 0: %d\n", err);
0063         err = -ENOMEM;
0064         goto out;
0065     }
0066 
0067     if (!buf->sg[1].data)
0068         goto out;
0069 
0070     buf->sg[1].dma_addr = dma_map_single(dma_device, buf->sg[1].data,
0071                          buf->sg[1].size, buf->dma_dir);
0072     err = dma_mapping_error(dma_device, buf->sg[1].dma_addr);
0073     if (unlikely(err)) {
0074         mlx5_fpga_warn(conn->fdev, "DMA error on sg 1: %d\n", err);
0075         dma_unmap_single(dma_device, buf->sg[0].dma_addr,
0076                  buf->sg[0].size, buf->dma_dir);
0077         err = -ENOMEM;
0078     }
0079 
0080 out:
0081     return err;
0082 }
0083 
0084 static void mlx5_fpga_conn_unmap_buf(struct mlx5_fpga_conn *conn,
0085                      struct mlx5_fpga_dma_buf *buf)
0086 {
0087     struct device *dma_device;
0088 
0089     dma_device = mlx5_core_dma_dev(conn->fdev->mdev);
0090     if (buf->sg[1].data)
0091         dma_unmap_single(dma_device, buf->sg[1].dma_addr,
0092                  buf->sg[1].size, buf->dma_dir);
0093 
0094     if (likely(buf->sg[0].data))
0095         dma_unmap_single(dma_device, buf->sg[0].dma_addr,
0096                  buf->sg[0].size, buf->dma_dir);
0097 }
0098 
0099 static int mlx5_fpga_conn_post_recv(struct mlx5_fpga_conn *conn,
0100                     struct mlx5_fpga_dma_buf *buf)
0101 {
0102     struct mlx5_wqe_data_seg *data;
0103     unsigned int ix;
0104     int err = 0;
0105 
0106     err = mlx5_fpga_conn_map_buf(conn, buf);
0107     if (unlikely(err))
0108         goto out;
0109 
0110     if (unlikely(conn->qp.rq.pc - conn->qp.rq.cc >= conn->qp.rq.size)) {
0111         mlx5_fpga_conn_unmap_buf(conn, buf);
0112         return -EBUSY;
0113     }
0114 
0115     ix = conn->qp.rq.pc & (conn->qp.rq.size - 1);
0116     data = mlx5_wq_cyc_get_wqe(&conn->qp.wq.rq, ix);
0117     data->byte_count = cpu_to_be32(buf->sg[0].size);
0118     data->lkey = cpu_to_be32(conn->fdev->conn_res.mkey);
0119     data->addr = cpu_to_be64(buf->sg[0].dma_addr);
0120 
0121     conn->qp.rq.pc++;
0122     conn->qp.rq.bufs[ix] = buf;
0123 
0124     /* Make sure that descriptors are written before doorbell record. */
0125     dma_wmb();
0126     *conn->qp.wq.rq.db = cpu_to_be32(conn->qp.rq.pc & 0xffff);
0127 out:
0128     return err;
0129 }
0130 
0131 static void mlx5_fpga_conn_notify_hw(struct mlx5_fpga_conn *conn, void *wqe)
0132 {
0133     /* ensure wqe is visible to device before updating doorbell record */
0134     dma_wmb();
0135     *conn->qp.wq.sq.db = cpu_to_be32(conn->qp.sq.pc);
0136     /* Make sure that doorbell record is visible before ringing */
0137     wmb();
0138     mlx5_write64(wqe, conn->fdev->conn_res.uar->map + MLX5_BF_OFFSET);
0139 }
0140 
0141 static void mlx5_fpga_conn_post_send(struct mlx5_fpga_conn *conn,
0142                      struct mlx5_fpga_dma_buf *buf)
0143 {
0144     struct mlx5_wqe_ctrl_seg *ctrl;
0145     struct mlx5_wqe_data_seg *data;
0146     unsigned int ix, sgi;
0147     int size = 1;
0148 
0149     ix = conn->qp.sq.pc & (conn->qp.sq.size - 1);
0150 
0151     ctrl = mlx5_wq_cyc_get_wqe(&conn->qp.wq.sq, ix);
0152     data = (void *)(ctrl + 1);
0153 
0154     for (sgi = 0; sgi < ARRAY_SIZE(buf->sg); sgi++) {
0155         if (!buf->sg[sgi].data)
0156             break;
0157         data->byte_count = cpu_to_be32(buf->sg[sgi].size);
0158         data->lkey = cpu_to_be32(conn->fdev->conn_res.mkey);
0159         data->addr = cpu_to_be64(buf->sg[sgi].dma_addr);
0160         data++;
0161         size++;
0162     }
0163 
0164     ctrl->imm = 0;
0165     ctrl->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE;
0166     ctrl->opmod_idx_opcode = cpu_to_be32(((conn->qp.sq.pc & 0xffff) << 8) |
0167                          MLX5_OPCODE_SEND);
0168     ctrl->qpn_ds = cpu_to_be32(size | (conn->qp.qpn << 8));
0169 
0170     conn->qp.sq.pc++;
0171     conn->qp.sq.bufs[ix] = buf;
0172     mlx5_fpga_conn_notify_hw(conn, ctrl);
0173 }
0174 
0175 int mlx5_fpga_conn_send(struct mlx5_fpga_conn *conn,
0176             struct mlx5_fpga_dma_buf *buf)
0177 {
0178     unsigned long flags;
0179     int err;
0180 
0181     if (!conn->qp.active)
0182         return -ENOTCONN;
0183 
0184     buf->dma_dir = DMA_TO_DEVICE;
0185     err = mlx5_fpga_conn_map_buf(conn, buf);
0186     if (err)
0187         return err;
0188 
0189     spin_lock_irqsave(&conn->qp.sq.lock, flags);
0190 
0191     if (conn->qp.sq.pc - conn->qp.sq.cc >= conn->qp.sq.size) {
0192         list_add_tail(&buf->list, &conn->qp.sq.backlog);
0193         goto out_unlock;
0194     }
0195 
0196     mlx5_fpga_conn_post_send(conn, buf);
0197 
0198 out_unlock:
0199     spin_unlock_irqrestore(&conn->qp.sq.lock, flags);
0200     return err;
0201 }
0202 
0203 static int mlx5_fpga_conn_post_recv_buf(struct mlx5_fpga_conn *conn)
0204 {
0205     struct mlx5_fpga_dma_buf *buf;
0206     int err;
0207 
0208     buf = kzalloc(sizeof(*buf) + MLX5_FPGA_RECV_SIZE, 0);
0209     if (!buf)
0210         return -ENOMEM;
0211 
0212     buf->sg[0].data = (void *)(buf + 1);
0213     buf->sg[0].size = MLX5_FPGA_RECV_SIZE;
0214     buf->dma_dir = DMA_FROM_DEVICE;
0215 
0216     err = mlx5_fpga_conn_post_recv(conn, buf);
0217     if (err)
0218         kfree(buf);
0219 
0220     return err;
0221 }
0222 
0223 static int mlx5_fpga_conn_create_mkey(struct mlx5_core_dev *mdev, u32 pdn,
0224                       u32 *mkey)
0225 {
0226     int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
0227     void *mkc;
0228     u32 *in;
0229     int err;
0230 
0231     in = kvzalloc(inlen, GFP_KERNEL);
0232     if (!in)
0233         return -ENOMEM;
0234 
0235     mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
0236     MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA);
0237     MLX5_SET(mkc, mkc, lw, 1);
0238     MLX5_SET(mkc, mkc, lr, 1);
0239 
0240     MLX5_SET(mkc, mkc, pd, pdn);
0241     MLX5_SET(mkc, mkc, length64, 1);
0242     MLX5_SET(mkc, mkc, qpn, 0xffffff);
0243 
0244     err = mlx5_core_create_mkey(mdev, mkey, in, inlen);
0245 
0246     kvfree(in);
0247     return err;
0248 }
0249 
0250 static void mlx5_fpga_conn_rq_cqe(struct mlx5_fpga_conn *conn,
0251                   struct mlx5_cqe64 *cqe, u8 status)
0252 {
0253     struct mlx5_fpga_dma_buf *buf;
0254     int ix, err;
0255 
0256     ix = be16_to_cpu(cqe->wqe_counter) & (conn->qp.rq.size - 1);
0257     buf = conn->qp.rq.bufs[ix];
0258     conn->qp.rq.bufs[ix] = NULL;
0259     conn->qp.rq.cc++;
0260 
0261     if (unlikely(status && (status != MLX5_CQE_SYNDROME_WR_FLUSH_ERR)))
0262         mlx5_fpga_warn(conn->fdev, "RQ buf %p on FPGA QP %u completion status %d\n",
0263                    buf, conn->fpga_qpn, status);
0264     else
0265         mlx5_fpga_dbg(conn->fdev, "RQ buf %p on FPGA QP %u completion status %d\n",
0266                   buf, conn->fpga_qpn, status);
0267 
0268     mlx5_fpga_conn_unmap_buf(conn, buf);
0269 
0270     if (unlikely(status || !conn->qp.active)) {
0271         conn->qp.active = false;
0272         kfree(buf);
0273         return;
0274     }
0275 
0276     buf->sg[0].size = be32_to_cpu(cqe->byte_cnt);
0277     mlx5_fpga_dbg(conn->fdev, "Message with %u bytes received successfully\n",
0278               buf->sg[0].size);
0279     conn->recv_cb(conn->cb_arg, buf);
0280 
0281     buf->sg[0].size = MLX5_FPGA_RECV_SIZE;
0282     err = mlx5_fpga_conn_post_recv(conn, buf);
0283     if (unlikely(err)) {
0284         mlx5_fpga_warn(conn->fdev,
0285                    "Failed to re-post recv buf: %d\n", err);
0286         kfree(buf);
0287     }
0288 }
0289 
0290 static void mlx5_fpga_conn_sq_cqe(struct mlx5_fpga_conn *conn,
0291                   struct mlx5_cqe64 *cqe, u8 status)
0292 {
0293     struct mlx5_fpga_dma_buf *buf, *nextbuf;
0294     unsigned long flags;
0295     int ix;
0296 
0297     spin_lock_irqsave(&conn->qp.sq.lock, flags);
0298 
0299     ix = be16_to_cpu(cqe->wqe_counter) & (conn->qp.sq.size - 1);
0300     buf = conn->qp.sq.bufs[ix];
0301     conn->qp.sq.bufs[ix] = NULL;
0302     conn->qp.sq.cc++;
0303 
0304     /* Handle backlog still under the spinlock to ensure message post order */
0305     if (unlikely(!list_empty(&conn->qp.sq.backlog))) {
0306         if (likely(conn->qp.active)) {
0307             nextbuf = list_first_entry(&conn->qp.sq.backlog,
0308                            struct mlx5_fpga_dma_buf, list);
0309             list_del(&nextbuf->list);
0310             mlx5_fpga_conn_post_send(conn, nextbuf);
0311         }
0312     }
0313 
0314     spin_unlock_irqrestore(&conn->qp.sq.lock, flags);
0315 
0316     if (unlikely(status && (status != MLX5_CQE_SYNDROME_WR_FLUSH_ERR)))
0317         mlx5_fpga_warn(conn->fdev, "SQ buf %p on FPGA QP %u completion status %d\n",
0318                    buf, conn->fpga_qpn, status);
0319     else
0320         mlx5_fpga_dbg(conn->fdev, "SQ buf %p on FPGA QP %u completion status %d\n",
0321                   buf, conn->fpga_qpn, status);
0322 
0323     mlx5_fpga_conn_unmap_buf(conn, buf);
0324 
0325     if (likely(buf->complete))
0326         buf->complete(conn, conn->fdev, buf, status);
0327 
0328     if (unlikely(status))
0329         conn->qp.active = false;
0330 }
0331 
0332 static void mlx5_fpga_conn_handle_cqe(struct mlx5_fpga_conn *conn,
0333                       struct mlx5_cqe64 *cqe)
0334 {
0335     u8 opcode, status = 0;
0336 
0337     opcode = get_cqe_opcode(cqe);
0338 
0339     switch (opcode) {
0340     case MLX5_CQE_REQ_ERR:
0341         status = ((struct mlx5_err_cqe *)cqe)->syndrome;
0342         fallthrough;
0343     case MLX5_CQE_REQ:
0344         mlx5_fpga_conn_sq_cqe(conn, cqe, status);
0345         break;
0346 
0347     case MLX5_CQE_RESP_ERR:
0348         status = ((struct mlx5_err_cqe *)cqe)->syndrome;
0349         fallthrough;
0350     case MLX5_CQE_RESP_SEND:
0351         mlx5_fpga_conn_rq_cqe(conn, cqe, status);
0352         break;
0353     default:
0354         mlx5_fpga_warn(conn->fdev, "Unexpected cqe opcode %u\n",
0355                    opcode);
0356     }
0357 }
0358 
0359 static void mlx5_fpga_conn_arm_cq(struct mlx5_fpga_conn *conn)
0360 {
0361     mlx5_cq_arm(&conn->cq.mcq, MLX5_CQ_DB_REQ_NOT,
0362             conn->fdev->conn_res.uar->map, conn->cq.wq.cc);
0363 }
0364 
0365 static inline void mlx5_fpga_conn_cqes(struct mlx5_fpga_conn *conn,
0366                        unsigned int budget)
0367 {
0368     struct mlx5_cqe64 *cqe;
0369 
0370     while (budget) {
0371         cqe = mlx5_cqwq_get_cqe(&conn->cq.wq);
0372         if (!cqe)
0373             break;
0374 
0375         budget--;
0376         mlx5_cqwq_pop(&conn->cq.wq);
0377         mlx5_fpga_conn_handle_cqe(conn, cqe);
0378         mlx5_cqwq_update_db_record(&conn->cq.wq);
0379     }
0380     if (!budget) {
0381         tasklet_schedule(&conn->cq.tasklet);
0382         return;
0383     }
0384 
0385     mlx5_fpga_dbg(conn->fdev, "Re-arming CQ with cc# %u\n", conn->cq.wq.cc);
0386     /* ensure cq space is freed before enabling more cqes */
0387     wmb();
0388     mlx5_fpga_conn_arm_cq(conn);
0389 }
0390 
0391 static void mlx5_fpga_conn_cq_tasklet(struct tasklet_struct *t)
0392 {
0393     struct mlx5_fpga_conn *conn = from_tasklet(conn, t, cq.tasklet);
0394 
0395     if (unlikely(!conn->qp.active))
0396         return;
0397     mlx5_fpga_conn_cqes(conn, MLX5_FPGA_CQ_BUDGET);
0398 }
0399 
0400 static void mlx5_fpga_conn_cq_complete(struct mlx5_core_cq *mcq,
0401                        struct mlx5_eqe *eqe)
0402 {
0403     struct mlx5_fpga_conn *conn;
0404 
0405     conn = container_of(mcq, struct mlx5_fpga_conn, cq.mcq);
0406     if (unlikely(!conn->qp.active))
0407         return;
0408     mlx5_fpga_conn_cqes(conn, MLX5_FPGA_CQ_BUDGET);
0409 }
0410 
0411 static int mlx5_fpga_conn_create_cq(struct mlx5_fpga_conn *conn, int cq_size)
0412 {
0413     struct mlx5_fpga_device *fdev = conn->fdev;
0414     struct mlx5_core_dev *mdev = fdev->mdev;
0415     u32 temp_cqc[MLX5_ST_SZ_DW(cqc)] = {0};
0416     u32 out[MLX5_ST_SZ_DW(create_cq_out)];
0417     struct mlx5_wq_param wqp;
0418     struct mlx5_cqe64 *cqe;
0419     int inlen, err, eqn;
0420     void *cqc, *in;
0421     __be64 *pas;
0422     u32 i;
0423 
0424     cq_size = roundup_pow_of_two(cq_size);
0425     MLX5_SET(cqc, temp_cqc, log_cq_size, ilog2(cq_size));
0426 
0427     wqp.buf_numa_node = mdev->priv.numa_node;
0428     wqp.db_numa_node  = mdev->priv.numa_node;
0429 
0430     err = mlx5_cqwq_create(mdev, &wqp, temp_cqc, &conn->cq.wq,
0431                    &conn->cq.wq_ctrl);
0432     if (err)
0433         return err;
0434 
0435     for (i = 0; i < mlx5_cqwq_get_size(&conn->cq.wq); i++) {
0436         cqe = mlx5_cqwq_get_wqe(&conn->cq.wq, i);
0437         cqe->op_own = MLX5_CQE_INVALID << 4 | MLX5_CQE_OWNER_MASK;
0438     }
0439 
0440     inlen = MLX5_ST_SZ_BYTES(create_cq_in) +
0441         sizeof(u64) * conn->cq.wq_ctrl.buf.npages;
0442     in = kvzalloc(inlen, GFP_KERNEL);
0443     if (!in) {
0444         err = -ENOMEM;
0445         goto err_cqwq;
0446     }
0447 
0448     err = mlx5_vector2eqn(mdev, smp_processor_id(), &eqn);
0449     if (err) {
0450         kvfree(in);
0451         goto err_cqwq;
0452     }
0453 
0454     cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context);
0455     MLX5_SET(cqc, cqc, log_cq_size, ilog2(cq_size));
0456     MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn);
0457     MLX5_SET(cqc, cqc, uar_page, fdev->conn_res.uar->index);
0458     MLX5_SET(cqc, cqc, log_page_size, conn->cq.wq_ctrl.buf.page_shift -
0459                MLX5_ADAPTER_PAGE_SHIFT);
0460     MLX5_SET64(cqc, cqc, dbr_addr, conn->cq.wq_ctrl.db.dma);
0461 
0462     pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas);
0463     mlx5_fill_page_frag_array(&conn->cq.wq_ctrl.buf, pas);
0464 
0465     err = mlx5_core_create_cq(mdev, &conn->cq.mcq, in, inlen, out, sizeof(out));
0466     kvfree(in);
0467 
0468     if (err)
0469         goto err_cqwq;
0470 
0471     conn->cq.mcq.cqe_sz     = 64;
0472     conn->cq.mcq.set_ci_db  = conn->cq.wq_ctrl.db.db;
0473     conn->cq.mcq.arm_db     = conn->cq.wq_ctrl.db.db + 1;
0474     *conn->cq.mcq.set_ci_db = 0;
0475     *conn->cq.mcq.arm_db    = 0;
0476     conn->cq.mcq.vector     = 0;
0477     conn->cq.mcq.comp       = mlx5_fpga_conn_cq_complete;
0478     conn->cq.mcq.uar        = fdev->conn_res.uar;
0479     tasklet_setup(&conn->cq.tasklet, mlx5_fpga_conn_cq_tasklet);
0480 
0481     mlx5_fpga_dbg(fdev, "Created CQ #0x%x\n", conn->cq.mcq.cqn);
0482 
0483     goto out;
0484 
0485 err_cqwq:
0486     mlx5_wq_destroy(&conn->cq.wq_ctrl);
0487 out:
0488     return err;
0489 }
0490 
0491 static void mlx5_fpga_conn_destroy_cq(struct mlx5_fpga_conn *conn)
0492 {
0493     tasklet_disable(&conn->cq.tasklet);
0494     tasklet_kill(&conn->cq.tasklet);
0495     mlx5_core_destroy_cq(conn->fdev->mdev, &conn->cq.mcq);
0496     mlx5_wq_destroy(&conn->cq.wq_ctrl);
0497 }
0498 
0499 static int mlx5_fpga_conn_create_wq(struct mlx5_fpga_conn *conn, void *qpc)
0500 {
0501     struct mlx5_fpga_device *fdev = conn->fdev;
0502     struct mlx5_core_dev *mdev = fdev->mdev;
0503     struct mlx5_wq_param wqp;
0504 
0505     wqp.buf_numa_node = mdev->priv.numa_node;
0506     wqp.db_numa_node  = mdev->priv.numa_node;
0507 
0508     return mlx5_wq_qp_create(mdev, &wqp, qpc, &conn->qp.wq,
0509                  &conn->qp.wq_ctrl);
0510 }
0511 
0512 static int mlx5_fpga_conn_create_qp(struct mlx5_fpga_conn *conn,
0513                     unsigned int tx_size, unsigned int rx_size)
0514 {
0515     struct mlx5_fpga_device *fdev = conn->fdev;
0516     u32 out[MLX5_ST_SZ_DW(create_qp_out)] = {};
0517     struct mlx5_core_dev *mdev = fdev->mdev;
0518     u32 temp_qpc[MLX5_ST_SZ_DW(qpc)] = {};
0519     void *in = NULL, *qpc;
0520     int err, inlen;
0521 
0522     conn->qp.rq.pc = 0;
0523     conn->qp.rq.cc = 0;
0524     conn->qp.rq.size = roundup_pow_of_two(rx_size);
0525     conn->qp.sq.pc = 0;
0526     conn->qp.sq.cc = 0;
0527     conn->qp.sq.size = roundup_pow_of_two(tx_size);
0528 
0529     MLX5_SET(qpc, temp_qpc, log_rq_stride, ilog2(MLX5_SEND_WQE_DS) - 4);
0530     MLX5_SET(qpc, temp_qpc, log_rq_size, ilog2(conn->qp.rq.size));
0531     MLX5_SET(qpc, temp_qpc, log_sq_size, ilog2(conn->qp.sq.size));
0532     err = mlx5_fpga_conn_create_wq(conn, temp_qpc);
0533     if (err)
0534         goto out;
0535 
0536     conn->qp.rq.bufs = kvcalloc(conn->qp.rq.size,
0537                     sizeof(conn->qp.rq.bufs[0]),
0538                     GFP_KERNEL);
0539     if (!conn->qp.rq.bufs) {
0540         err = -ENOMEM;
0541         goto err_wq;
0542     }
0543 
0544     conn->qp.sq.bufs = kvcalloc(conn->qp.sq.size,
0545                     sizeof(conn->qp.sq.bufs[0]),
0546                     GFP_KERNEL);
0547     if (!conn->qp.sq.bufs) {
0548         err = -ENOMEM;
0549         goto err_rq_bufs;
0550     }
0551 
0552     inlen = MLX5_ST_SZ_BYTES(create_qp_in) +
0553         MLX5_FLD_SZ_BYTES(create_qp_in, pas[0]) *
0554         conn->qp.wq_ctrl.buf.npages;
0555     in = kvzalloc(inlen, GFP_KERNEL);
0556     if (!in) {
0557         err = -ENOMEM;
0558         goto err_sq_bufs;
0559     }
0560 
0561     qpc = MLX5_ADDR_OF(create_qp_in, in, qpc);
0562     MLX5_SET(qpc, qpc, uar_page, fdev->conn_res.uar->index);
0563     MLX5_SET(qpc, qpc, log_page_size,
0564          conn->qp.wq_ctrl.buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT);
0565     MLX5_SET(qpc, qpc, fre, 1);
0566     MLX5_SET(qpc, qpc, rlky, 1);
0567     MLX5_SET(qpc, qpc, st, MLX5_QP_ST_RC);
0568     MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED);
0569     MLX5_SET(qpc, qpc, pd, fdev->conn_res.pdn);
0570     MLX5_SET(qpc, qpc, log_rq_stride, ilog2(MLX5_SEND_WQE_DS) - 4);
0571     MLX5_SET(qpc, qpc, log_rq_size, ilog2(conn->qp.rq.size));
0572     MLX5_SET(qpc, qpc, rq_type, MLX5_NON_ZERO_RQ);
0573     MLX5_SET(qpc, qpc, log_sq_size, ilog2(conn->qp.sq.size));
0574     MLX5_SET(qpc, qpc, cqn_snd, conn->cq.mcq.cqn);
0575     MLX5_SET(qpc, qpc, cqn_rcv, conn->cq.mcq.cqn);
0576     MLX5_SET(qpc, qpc, ts_format, mlx5_get_qp_default_ts(mdev));
0577     MLX5_SET64(qpc, qpc, dbr_addr, conn->qp.wq_ctrl.db.dma);
0578     if (MLX5_CAP_GEN(mdev, cqe_version) == 1)
0579         MLX5_SET(qpc, qpc, user_index, 0xFFFFFF);
0580 
0581     mlx5_fill_page_frag_array(&conn->qp.wq_ctrl.buf,
0582                   (__be64 *)MLX5_ADDR_OF(create_qp_in, in, pas));
0583 
0584     MLX5_SET(create_qp_in, in, opcode, MLX5_CMD_OP_CREATE_QP);
0585     err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out));
0586     if (err)
0587         goto err_sq_bufs;
0588 
0589     conn->qp.qpn = MLX5_GET(create_qp_out, out, qpn);
0590     mlx5_fpga_dbg(fdev, "Created QP #0x%x\n", conn->qp.qpn);
0591 
0592     goto out;
0593 
0594 err_sq_bufs:
0595     kvfree(conn->qp.sq.bufs);
0596 err_rq_bufs:
0597     kvfree(conn->qp.rq.bufs);
0598 err_wq:
0599     mlx5_wq_destroy(&conn->qp.wq_ctrl);
0600 out:
0601     kvfree(in);
0602     return err;
0603 }
0604 
0605 static void mlx5_fpga_conn_free_recv_bufs(struct mlx5_fpga_conn *conn)
0606 {
0607     int ix;
0608 
0609     for (ix = 0; ix < conn->qp.rq.size; ix++) {
0610         if (!conn->qp.rq.bufs[ix])
0611             continue;
0612         mlx5_fpga_conn_unmap_buf(conn, conn->qp.rq.bufs[ix]);
0613         kfree(conn->qp.rq.bufs[ix]);
0614         conn->qp.rq.bufs[ix] = NULL;
0615     }
0616 }
0617 
0618 static void mlx5_fpga_conn_flush_send_bufs(struct mlx5_fpga_conn *conn)
0619 {
0620     struct mlx5_fpga_dma_buf *buf, *temp;
0621     int ix;
0622 
0623     for (ix = 0; ix < conn->qp.sq.size; ix++) {
0624         buf = conn->qp.sq.bufs[ix];
0625         if (!buf)
0626             continue;
0627         conn->qp.sq.bufs[ix] = NULL;
0628         mlx5_fpga_conn_unmap_buf(conn, buf);
0629         if (!buf->complete)
0630             continue;
0631         buf->complete(conn, conn->fdev, buf, MLX5_CQE_SYNDROME_WR_FLUSH_ERR);
0632     }
0633     list_for_each_entry_safe(buf, temp, &conn->qp.sq.backlog, list) {
0634         mlx5_fpga_conn_unmap_buf(conn, buf);
0635         if (!buf->complete)
0636             continue;
0637         buf->complete(conn, conn->fdev, buf, MLX5_CQE_SYNDROME_WR_FLUSH_ERR);
0638     }
0639 }
0640 
0641 static void mlx5_fpga_conn_destroy_qp(struct mlx5_fpga_conn *conn)
0642 {
0643     struct mlx5_core_dev *dev = conn->fdev->mdev;
0644     u32 in[MLX5_ST_SZ_DW(destroy_qp_in)] = {};
0645 
0646     MLX5_SET(destroy_qp_in, in, opcode, MLX5_CMD_OP_DESTROY_QP);
0647     MLX5_SET(destroy_qp_in, in, qpn, conn->qp.qpn);
0648     mlx5_cmd_exec_in(dev, destroy_qp, in);
0649 
0650     mlx5_fpga_conn_free_recv_bufs(conn);
0651     mlx5_fpga_conn_flush_send_bufs(conn);
0652     kvfree(conn->qp.sq.bufs);
0653     kvfree(conn->qp.rq.bufs);
0654     mlx5_wq_destroy(&conn->qp.wq_ctrl);
0655 }
0656 
0657 static int mlx5_fpga_conn_reset_qp(struct mlx5_fpga_conn *conn)
0658 {
0659     struct mlx5_core_dev *mdev = conn->fdev->mdev;
0660     u32 in[MLX5_ST_SZ_DW(qp_2rst_in)] = {};
0661 
0662     mlx5_fpga_dbg(conn->fdev, "Modifying QP %u to RST\n", conn->qp.qpn);
0663 
0664     MLX5_SET(qp_2rst_in, in, opcode, MLX5_CMD_OP_2RST_QP);
0665     MLX5_SET(qp_2rst_in, in, qpn, conn->qp.qpn);
0666 
0667     return mlx5_cmd_exec_in(mdev, qp_2rst, in);
0668 }
0669 
0670 static int mlx5_fpga_conn_init_qp(struct mlx5_fpga_conn *conn)
0671 {
0672     u32 in[MLX5_ST_SZ_DW(rst2init_qp_in)] = {};
0673     struct mlx5_fpga_device *fdev = conn->fdev;
0674     struct mlx5_core_dev *mdev = fdev->mdev;
0675     u32 *qpc;
0676 
0677     mlx5_fpga_dbg(conn->fdev, "Modifying QP %u to INIT\n", conn->qp.qpn);
0678 
0679     qpc = MLX5_ADDR_OF(rst2init_qp_in, in, qpc);
0680 
0681     MLX5_SET(qpc, qpc, st, MLX5_QP_ST_RC);
0682     MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED);
0683     MLX5_SET(qpc, qpc, primary_address_path.pkey_index, MLX5_FPGA_PKEY_INDEX);
0684     MLX5_SET(qpc, qpc, primary_address_path.vhca_port_num, MLX5_FPGA_PORT_NUM);
0685     MLX5_SET(qpc, qpc, pd, conn->fdev->conn_res.pdn);
0686     MLX5_SET(qpc, qpc, cqn_snd, conn->cq.mcq.cqn);
0687     MLX5_SET(qpc, qpc, cqn_rcv, conn->cq.mcq.cqn);
0688     MLX5_SET64(qpc, qpc, dbr_addr, conn->qp.wq_ctrl.db.dma);
0689 
0690     MLX5_SET(rst2init_qp_in, in, opcode, MLX5_CMD_OP_RST2INIT_QP);
0691     MLX5_SET(rst2init_qp_in, in, qpn, conn->qp.qpn);
0692 
0693     return mlx5_cmd_exec_in(mdev, rst2init_qp, in);
0694 }
0695 
0696 static int mlx5_fpga_conn_rtr_qp(struct mlx5_fpga_conn *conn)
0697 {
0698     u32 in[MLX5_ST_SZ_DW(init2rtr_qp_in)] = {};
0699     struct mlx5_fpga_device *fdev = conn->fdev;
0700     struct mlx5_core_dev *mdev = fdev->mdev;
0701     u32 *qpc;
0702 
0703     mlx5_fpga_dbg(conn->fdev, "QP RTR\n");
0704 
0705     qpc = MLX5_ADDR_OF(init2rtr_qp_in, in, qpc);
0706 
0707     MLX5_SET(qpc, qpc, mtu, MLX5_QPC_MTU_1K_BYTES);
0708     MLX5_SET(qpc, qpc, log_msg_max, (u8)MLX5_CAP_GEN(mdev, log_max_msg));
0709     MLX5_SET(qpc, qpc, remote_qpn, conn->fpga_qpn);
0710     MLX5_SET(qpc, qpc, next_rcv_psn,
0711          MLX5_GET(fpga_qpc, conn->fpga_qpc, next_send_psn));
0712     MLX5_SET(qpc, qpc, primary_address_path.pkey_index, MLX5_FPGA_PKEY_INDEX);
0713     MLX5_SET(qpc, qpc, primary_address_path.vhca_port_num, MLX5_FPGA_PORT_NUM);
0714     ether_addr_copy(MLX5_ADDR_OF(qpc, qpc, primary_address_path.rmac_47_32),
0715             MLX5_ADDR_OF(fpga_qpc, conn->fpga_qpc, fpga_mac_47_32));
0716     MLX5_SET(qpc, qpc, primary_address_path.udp_sport,
0717          MLX5_CAP_ROCE(mdev, r_roce_min_src_udp_port));
0718     MLX5_SET(qpc, qpc, primary_address_path.src_addr_index,
0719          conn->qp.sgid_index);
0720     MLX5_SET(qpc, qpc, primary_address_path.hop_limit, 0);
0721     memcpy(MLX5_ADDR_OF(qpc, qpc, primary_address_path.rgid_rip),
0722            MLX5_ADDR_OF(fpga_qpc, conn->fpga_qpc, fpga_ip),
0723            MLX5_FLD_SZ_BYTES(qpc, primary_address_path.rgid_rip));
0724 
0725     MLX5_SET(init2rtr_qp_in, in, opcode, MLX5_CMD_OP_INIT2RTR_QP);
0726     MLX5_SET(init2rtr_qp_in, in, qpn, conn->qp.qpn);
0727 
0728     return mlx5_cmd_exec_in(mdev, init2rtr_qp, in);
0729 }
0730 
0731 static int mlx5_fpga_conn_rts_qp(struct mlx5_fpga_conn *conn)
0732 {
0733     struct mlx5_fpga_device *fdev = conn->fdev;
0734     u32 in[MLX5_ST_SZ_DW(rtr2rts_qp_in)] = {};
0735     struct mlx5_core_dev *mdev = fdev->mdev;
0736     u32 *qpc;
0737 
0738     mlx5_fpga_dbg(conn->fdev, "QP RTS\n");
0739 
0740     qpc = MLX5_ADDR_OF(rtr2rts_qp_in, in, qpc);
0741 
0742     MLX5_SET(qpc, qpc, log_ack_req_freq, 8);
0743     MLX5_SET(qpc, qpc, min_rnr_nak, 0x12);
0744     MLX5_SET(qpc, qpc, primary_address_path.ack_timeout, 0x12); /* ~1.07s */
0745     MLX5_SET(qpc, qpc, next_send_psn,
0746          MLX5_GET(fpga_qpc, conn->fpga_qpc, next_rcv_psn));
0747     MLX5_SET(qpc, qpc, retry_count, 7);
0748     MLX5_SET(qpc, qpc, rnr_retry, 7); /* Infinite retry if RNR NACK */
0749 
0750     MLX5_SET(rtr2rts_qp_in, in, opcode, MLX5_CMD_OP_RTR2RTS_QP);
0751     MLX5_SET(rtr2rts_qp_in, in, qpn, conn->qp.qpn);
0752     MLX5_SET(rtr2rts_qp_in, in, opt_param_mask, MLX5_QP_OPTPAR_RNR_TIMEOUT);
0753 
0754     return mlx5_cmd_exec_in(mdev, rtr2rts_qp, in);
0755 }
0756 
0757 static int mlx5_fpga_conn_connect(struct mlx5_fpga_conn *conn)
0758 {
0759     struct mlx5_fpga_device *fdev = conn->fdev;
0760     int err;
0761 
0762     MLX5_SET(fpga_qpc, conn->fpga_qpc, state, MLX5_FPGA_QPC_STATE_ACTIVE);
0763     err = mlx5_fpga_modify_qp(conn->fdev->mdev, conn->fpga_qpn,
0764                   MLX5_FPGA_QPC_STATE, &conn->fpga_qpc);
0765     if (err) {
0766         mlx5_fpga_err(fdev, "Failed to activate FPGA RC QP: %d\n", err);
0767         goto out;
0768     }
0769 
0770     err = mlx5_fpga_conn_reset_qp(conn);
0771     if (err) {
0772         mlx5_fpga_err(fdev, "Failed to change QP state to reset\n");
0773         goto err_fpga_qp;
0774     }
0775 
0776     err = mlx5_fpga_conn_init_qp(conn);
0777     if (err) {
0778         mlx5_fpga_err(fdev, "Failed to modify QP from RESET to INIT\n");
0779         goto err_fpga_qp;
0780     }
0781     conn->qp.active = true;
0782 
0783     while (!mlx5_fpga_conn_post_recv_buf(conn))
0784         ;
0785 
0786     err = mlx5_fpga_conn_rtr_qp(conn);
0787     if (err) {
0788         mlx5_fpga_err(fdev, "Failed to change QP state from INIT to RTR\n");
0789         goto err_recv_bufs;
0790     }
0791 
0792     err = mlx5_fpga_conn_rts_qp(conn);
0793     if (err) {
0794         mlx5_fpga_err(fdev, "Failed to change QP state from RTR to RTS\n");
0795         goto err_recv_bufs;
0796     }
0797     goto out;
0798 
0799 err_recv_bufs:
0800     mlx5_fpga_conn_free_recv_bufs(conn);
0801 err_fpga_qp:
0802     MLX5_SET(fpga_qpc, conn->fpga_qpc, state, MLX5_FPGA_QPC_STATE_INIT);
0803     if (mlx5_fpga_modify_qp(conn->fdev->mdev, conn->fpga_qpn,
0804                 MLX5_FPGA_QPC_STATE, &conn->fpga_qpc))
0805         mlx5_fpga_err(fdev, "Failed to revert FPGA QP to INIT\n");
0806 out:
0807     return err;
0808 }
0809 
0810 struct mlx5_fpga_conn *mlx5_fpga_conn_create(struct mlx5_fpga_device *fdev,
0811                          struct mlx5_fpga_conn_attr *attr,
0812                          enum mlx5_ifc_fpga_qp_type qp_type)
0813 {
0814     struct mlx5_fpga_conn *ret, *conn;
0815     u8 *remote_mac, *remote_ip;
0816     int err;
0817 
0818     if (!attr->recv_cb)
0819         return ERR_PTR(-EINVAL);
0820 
0821     conn = kzalloc(sizeof(*conn), GFP_KERNEL);
0822     if (!conn)
0823         return ERR_PTR(-ENOMEM);
0824 
0825     conn->fdev = fdev;
0826     INIT_LIST_HEAD(&conn->qp.sq.backlog);
0827 
0828     spin_lock_init(&conn->qp.sq.lock);
0829 
0830     conn->recv_cb = attr->recv_cb;
0831     conn->cb_arg = attr->cb_arg;
0832 
0833     remote_mac = MLX5_ADDR_OF(fpga_qpc, conn->fpga_qpc, remote_mac_47_32);
0834     err = mlx5_query_mac_address(fdev->mdev, remote_mac);
0835     if (err) {
0836         mlx5_fpga_err(fdev, "Failed to query local MAC: %d\n", err);
0837         ret = ERR_PTR(err);
0838         goto err;
0839     }
0840 
0841     /* Build Modified EUI-64 IPv6 address from the MAC address */
0842     remote_ip = MLX5_ADDR_OF(fpga_qpc, conn->fpga_qpc, remote_ip);
0843     remote_ip[0] = 0xfe;
0844     remote_ip[1] = 0x80;
0845     addrconf_addr_eui48(&remote_ip[8], remote_mac);
0846 
0847     err = mlx5_core_reserved_gid_alloc(fdev->mdev, &conn->qp.sgid_index);
0848     if (err) {
0849         mlx5_fpga_err(fdev, "Failed to allocate SGID: %d\n", err);
0850         ret = ERR_PTR(err);
0851         goto err;
0852     }
0853 
0854     err = mlx5_core_roce_gid_set(fdev->mdev, conn->qp.sgid_index,
0855                      MLX5_ROCE_VERSION_2,
0856                      MLX5_ROCE_L3_TYPE_IPV6,
0857                      remote_ip, remote_mac, true, 0,
0858                      MLX5_FPGA_PORT_NUM);
0859     if (err) {
0860         mlx5_fpga_err(fdev, "Failed to set SGID: %d\n", err);
0861         ret = ERR_PTR(err);
0862         goto err_rsvd_gid;
0863     }
0864     mlx5_fpga_dbg(fdev, "Reserved SGID index %u\n", conn->qp.sgid_index);
0865 
0866     /* Allow for one cqe per rx/tx wqe, plus one cqe for the next wqe,
0867      * created during processing of the cqe
0868      */
0869     err = mlx5_fpga_conn_create_cq(conn,
0870                        (attr->tx_size + attr->rx_size) * 2);
0871     if (err) {
0872         mlx5_fpga_err(fdev, "Failed to create CQ: %d\n", err);
0873         ret = ERR_PTR(err);
0874         goto err_gid;
0875     }
0876 
0877     mlx5_fpga_conn_arm_cq(conn);
0878 
0879     err = mlx5_fpga_conn_create_qp(conn, attr->tx_size, attr->rx_size);
0880     if (err) {
0881         mlx5_fpga_err(fdev, "Failed to create QP: %d\n", err);
0882         ret = ERR_PTR(err);
0883         goto err_cq;
0884     }
0885 
0886     MLX5_SET(fpga_qpc, conn->fpga_qpc, state, MLX5_FPGA_QPC_STATE_INIT);
0887     MLX5_SET(fpga_qpc, conn->fpga_qpc, qp_type, qp_type);
0888     MLX5_SET(fpga_qpc, conn->fpga_qpc, st, MLX5_FPGA_QPC_ST_RC);
0889     MLX5_SET(fpga_qpc, conn->fpga_qpc, ether_type, ETH_P_8021Q);
0890     MLX5_SET(fpga_qpc, conn->fpga_qpc, vid, 0);
0891     MLX5_SET(fpga_qpc, conn->fpga_qpc, next_rcv_psn, 1);
0892     MLX5_SET(fpga_qpc, conn->fpga_qpc, next_send_psn, 0);
0893     MLX5_SET(fpga_qpc, conn->fpga_qpc, pkey, MLX5_FPGA_PKEY);
0894     MLX5_SET(fpga_qpc, conn->fpga_qpc, remote_qpn, conn->qp.qpn);
0895     MLX5_SET(fpga_qpc, conn->fpga_qpc, rnr_retry, 7);
0896     MLX5_SET(fpga_qpc, conn->fpga_qpc, retry_count, 7);
0897 
0898     err = mlx5_fpga_create_qp(fdev->mdev, &conn->fpga_qpc,
0899                   &conn->fpga_qpn);
0900     if (err) {
0901         mlx5_fpga_err(fdev, "Failed to create FPGA RC QP: %d\n", err);
0902         ret = ERR_PTR(err);
0903         goto err_qp;
0904     }
0905 
0906     err = mlx5_fpga_conn_connect(conn);
0907     if (err) {
0908         ret = ERR_PTR(err);
0909         goto err_conn;
0910     }
0911 
0912     mlx5_fpga_dbg(fdev, "FPGA QPN is %u\n", conn->fpga_qpn);
0913     ret = conn;
0914     goto out;
0915 
0916 err_conn:
0917     mlx5_fpga_destroy_qp(conn->fdev->mdev, conn->fpga_qpn);
0918 err_qp:
0919     mlx5_fpga_conn_destroy_qp(conn);
0920 err_cq:
0921     mlx5_fpga_conn_destroy_cq(conn);
0922 err_gid:
0923     mlx5_core_roce_gid_set(fdev->mdev, conn->qp.sgid_index, 0, 0, NULL,
0924                    NULL, false, 0, MLX5_FPGA_PORT_NUM);
0925 err_rsvd_gid:
0926     mlx5_core_reserved_gid_free(fdev->mdev, conn->qp.sgid_index);
0927 err:
0928     kfree(conn);
0929 out:
0930     return ret;
0931 }
0932 
0933 void mlx5_fpga_conn_destroy(struct mlx5_fpga_conn *conn)
0934 {
0935     conn->qp.active = false;
0936     tasklet_disable(&conn->cq.tasklet);
0937     synchronize_irq(conn->cq.mcq.irqn);
0938 
0939     mlx5_fpga_destroy_qp(conn->fdev->mdev, conn->fpga_qpn);
0940     mlx5_fpga_conn_destroy_qp(conn);
0941     mlx5_fpga_conn_destroy_cq(conn);
0942 
0943     mlx5_core_roce_gid_set(conn->fdev->mdev, conn->qp.sgid_index, 0, 0,
0944                    NULL, NULL, false, 0, MLX5_FPGA_PORT_NUM);
0945     mlx5_core_reserved_gid_free(conn->fdev->mdev, conn->qp.sgid_index);
0946     kfree(conn);
0947 }
0948 
0949 int mlx5_fpga_conn_device_init(struct mlx5_fpga_device *fdev)
0950 {
0951     int err;
0952 
0953     err = mlx5_nic_vport_enable_roce(fdev->mdev);
0954     if (err) {
0955         mlx5_fpga_err(fdev, "Failed to enable RoCE: %d\n", err);
0956         goto out;
0957     }
0958 
0959     fdev->conn_res.uar = mlx5_get_uars_page(fdev->mdev);
0960     if (IS_ERR(fdev->conn_res.uar)) {
0961         err = PTR_ERR(fdev->conn_res.uar);
0962         mlx5_fpga_err(fdev, "get_uars_page failed, %d\n", err);
0963         goto err_roce;
0964     }
0965     mlx5_fpga_dbg(fdev, "Allocated UAR index %u\n",
0966               fdev->conn_res.uar->index);
0967 
0968     err = mlx5_core_alloc_pd(fdev->mdev, &fdev->conn_res.pdn);
0969     if (err) {
0970         mlx5_fpga_err(fdev, "alloc pd failed, %d\n", err);
0971         goto err_uar;
0972     }
0973     mlx5_fpga_dbg(fdev, "Allocated PD %u\n", fdev->conn_res.pdn);
0974 
0975     err = mlx5_fpga_conn_create_mkey(fdev->mdev, fdev->conn_res.pdn,
0976                      &fdev->conn_res.mkey);
0977     if (err) {
0978         mlx5_fpga_err(fdev, "create mkey failed, %d\n", err);
0979         goto err_dealloc_pd;
0980     }
0981     mlx5_fpga_dbg(fdev, "Created mkey 0x%x\n", fdev->conn_res.mkey);
0982 
0983     return 0;
0984 
0985 err_dealloc_pd:
0986     mlx5_core_dealloc_pd(fdev->mdev, fdev->conn_res.pdn);
0987 err_uar:
0988     mlx5_put_uars_page(fdev->mdev, fdev->conn_res.uar);
0989 err_roce:
0990     mlx5_nic_vport_disable_roce(fdev->mdev);
0991 out:
0992     return err;
0993 }
0994 
0995 void mlx5_fpga_conn_device_cleanup(struct mlx5_fpga_device *fdev)
0996 {
0997     mlx5_core_destroy_mkey(fdev->mdev, fdev->conn_res.mkey);
0998     mlx5_core_dealloc_pd(fdev->mdev, fdev->conn_res.pdn);
0999     mlx5_put_uars_page(fdev->mdev, fdev->conn_res.uar);
1000     mlx5_nic_vport_disable_roce(fdev->mdev);
1001 }