blob: 6dd19193644b6e0815e08c7efa9a53238491e8fe [file]
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
* Broadcom NetXtreme-E User Space RoCE driver
*
* Copyright (c) 2015-2026, Broadcom. All rights reserved. The term
* Broadcom refers to Broadcom Limited and/or its subsidiaries.
*/
#include <stdio.h>
#include <sys/mman.h>
#include "main.h"
#include "bnxt_re-abi.h"
#include "bnxt_re_dv.h"
#include "./verbs.h"
/* Returns details about the default Doorbell page for ucontext */
int bnxt_re_dv_get_default_db_region(struct ibv_context *ibvctx,
struct bnxt_re_dv_db_region_attr *out)
{
struct bnxt_re_context *cntx = to_bnxt_re_context(ibvctx);
struct bnxt_re_dv_db_region_attr attr = {};
int ret;
DECLARE_COMMAND_BUFFER(cmd,
BNXT_RE_OBJECT_DEFAULT_DBR,
BNXT_RE_METHOD_GET_DEFAULT_DBR,
1);
fill_attr_out_ptr(cmd, BNXT_RE_DEFAULT_DBR_ATTR, &attr);
ret = execute_ioctl(ibvctx, cmd);
if (ret)
return ret;
out->dbr = (uint64_t *)cntx->udpi.dbpage;
out->dpi = attr.dpi;
return 0;
}
int bnxt_re_dv_free_db_region(struct ibv_context *ctx,
struct bnxt_re_dv_db_region_attr *attr)
{
struct bnxt_re_dev *dev = to_bnxt_re_dev(ctx->device);
int ret;
DECLARE_COMMAND_BUFFER(cmd,
BNXT_RE_OBJECT_DBR,
BNXT_RE_METHOD_DBR_FREE,
1);
if (attr->dbr != MAP_FAILED)
munmap(attr->dbr, dev->pg_size);
fill_attr_in_obj(cmd, BNXT_RE_FREE_DBR_HANDLE, attr->handle);
ret = execute_ioctl(ctx, cmd);
if (ret) {
errno = ret;
return ret;
}
free(attr);
return 0;
}
struct bnxt_re_dv_db_region_attr *
bnxt_re_dv_alloc_db_region(struct ibv_context *ctx)
{
struct bnxt_re_dev *dev = to_bnxt_re_dev(ctx->device);
struct bnxt_re_dv_db_region_attr *out;
struct bnxt_re_db_region attr = {};
struct ib_uverbs_attr *handle;
uint64_t mmap_offset = 0;
int ret;
DECLARE_COMMAND_BUFFER(cmd,
BNXT_RE_OBJECT_DBR,
BNXT_RE_METHOD_DBR_ALLOC,
3);
out = calloc(1, sizeof(*out));
if (!out) {
errno = ENOMEM;
return NULL;
}
handle = fill_attr_out_obj(cmd, BNXT_RE_ALLOC_DBR_HANDLE);
fill_attr_out_ptr(cmd, BNXT_RE_ALLOC_DBR_ATTR, &attr);
fill_attr_out_ptr(cmd, BNXT_RE_ALLOC_DBR_OFFSET, &mmap_offset);
ret = execute_ioctl(ctx, cmd);
if (ret) {
free(out);
errno = ret;
return NULL;
}
out->handle = read_attr_obj(BNXT_RE_ALLOC_DBR_HANDLE, handle);
out->dpi = attr.dpi;
out->dbr = mmap(NULL, dev->pg_size, PROT_WRITE,
MAP_SHARED, ctx->cmd_fd, mmap_offset);
if (out->dbr == MAP_FAILED) {
bnxt_re_dv_free_db_region(ctx, out);
errno = ENOMEM;
return NULL;
}
return out;
}
static bool bnxt_re_dv_is_valid_buf(struct bnxt_re_dev *dev,
struct ibv_buf *buf,
uint64_t offset, uint32_t size)
{
return ((offset == align(offset, dev->pg_size)) &&
(offset + size <= buf->size));
}
static int bnxt_re_dv_create_cq_cmd(struct bnxt_re_dev *dev,
struct ibv_context *ibvctx,
struct bnxt_re_cq *cq,
struct bnxt_re_dv_cq_init_attr *cq_attr,
uint64_t comp_mask,
struct ubnxt_re_cq_resp *resp)
{
struct bnxt_re_context *cntx = to_bnxt_re_context(ibvctx);
DECLARE_COMMAND_BUFFER(driver_attrs, UVERBS_OBJECT_CQ,
UVERBS_METHOD_CQ_CREATE, 1);
struct ib_uverbs_buffer_desc cq_buf_umem_desc;
struct ibv_cq_init_attr_ex cq_attr_ex = {};
uint64_t offset = cq_attr->umem_offset;
struct ibv_buf *cq_buf = cq->cq_buf;
struct ubnxt_re_cq cmd = {};
void *buf_addr;
uint32_t size;
int ret;
size = cq_attr->ncqe * bnxt_re_get_cqe_sz();
if (!bnxt_re_dv_is_valid_buf(dev, cq_buf, offset, size))
return -EINVAL;
cmd.cq_handle = (uintptr_t)cq;
cmd.comp_mask = comp_mask;
buf_addr = (uint8_t *)cq_buf->addr + offset;
cmd.cq_va = (uintptr_t)buf_addr;
fill_attr_in_buf_umem(driver_attrs, UVERBS_ATTR_CREATE_CQ_BUF_UMEM,
&cq_buf_umem_desc, cq_buf,
buf_addr, size);
cq_attr_ex.cqe = cq_attr->ncqe;
cq_attr_ex.comp_mask = 0;
cq_attr_ex.flags = 0;
memset(resp, 0, sizeof(*resp));
ret = ibv_cmd_create_cq_ex2(ibvctx, &cq_attr_ex, NULL,
&cq->verbs_cq,
&cmd.ibv_cmd, sizeof(cmd),
&resp->ibv_resp,
sizeof(*resp), 0, driver_attrs);
if (ret)
return ret;
cq->cqid = resp->cqid;
cq->phase = resp->phase;
cq->udpi = &cntx->udpi;
cq->cntx = cntx;
cq->rand.seed = cq->cqid;
return 0;
}
struct ibv_cq *bnxt_re_dv_create_cq(struct ibv_context *ibvctx,
struct bnxt_re_dv_cq_init_attr *cq_attr)
{
struct bnxt_re_dev *dev = to_bnxt_re_dev(ibvctx->device);
uint64_t comp_mask = BNXT_RE_CQ_FIXED_NUM_CQE_ENABLE;
struct ibv_buf *cq_buf = cq_attr->umem_handle;
struct ubnxt_re_cq_resp resp = {};
struct bnxt_re_cq *cq;
int ret;
if (!(dev->vdev.core_support & IB_UVERBS_CORE_SUPPORT_ROBUST_UDATA))
return NULL;
if (cq_attr->ncqe > dev->max_cq_depth)
return NULL;
cq = calloc(1, (sizeof(*cq)));
if (!cq)
return NULL;
cq->cq_buf = cq_buf;
ret = bnxt_re_dv_create_cq_cmd(dev, ibvctx, cq, cq_attr, comp_mask, &resp);
if (ret)
goto fail;
cq->dv_cq_flags |= BNXT_DV_CQ_FLAGS_VALID;
return &cq->verbs_cq.cq;
fail:
free(cq);
return NULL;
}