blob: a91fa19e4be8d40e3fc14e60e3dc3dd9322de66a [file] [log] [blame] [edit]
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
* Copyright (c) 2018-2025 Advanced Micro Devices, Inc. All rights reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include "ionic.h"
static struct verbs_context *ionic_alloc_context(struct ibv_device *ibdev,
int cmd_fd,
void *private_data)
{
struct ionic_ctx *ctx;
struct uionic_ctx req = {};
struct uionic_ctx_resp resp = {};
uint64_t mask;
int rc;
ctx = verbs_init_and_alloc_context(ibdev, cmd_fd, ctx, vctx,
RDMA_DRIVER_IONIC);
if (!ctx) {
rc = errno;
goto err_ctx;
}
rc = ibv_cmd_get_context(&ctx->vctx, &req.ibv_cmd, sizeof(req),
NULL, &resp.ibv_resp, sizeof(resp));
if (rc)
goto err_cmd;
ctx->pg_shift = resp.page_shift;
if (resp.version < IONIC_MIN_RDMA_VERSION) {
verbs_err(&ctx->vctx, "ionic: Firmware RDMA Version %u\n",
resp.version);
verbs_err(&ctx->vctx, "ionic: Driver Min RDMA Version %u\n",
IONIC_MIN_RDMA_VERSION);
rc = EINVAL;
goto err_cmd;
}
if (resp.version > IONIC_MAX_RDMA_VERSION) {
verbs_err(&ctx->vctx, "ionic: Firmware RDMA Version %u\n",
resp.version);
verbs_err(&ctx->vctx, "ionic: Driver Max RDMA Version %u\n",
IONIC_MAX_RDMA_VERSION);
rc = EINVAL;
goto err_cmd;
}
ctx->version = resp.version;
ctx->opcodes = resp.qp_opcodes;
if (ctx->version == 1 && ctx->opcodes <= IONIC_V1_OP_BIND_MW) {
verbs_err(&ctx->vctx, "ionic: qp opcodes %d want min %d\n",
ctx->opcodes, IONIC_V1_OP_BIND_MW + 1);
rc = EINVAL;
goto err_cmd;
}
if (resp.udma_count != 1 && resp.udma_count != 2) {
verbs_err(&ctx->vctx, "ionic: udma_count %d invalid\n",
resp.udma_count);
rc = EINVAL;
goto err_cmd;
}
ctx->udma_count = resp.udma_count;
ctx->sq_qtype = resp.sq_qtype;
ctx->rq_qtype = resp.rq_qtype;
ctx->cq_qtype = resp.cq_qtype;
ctx->max_stride = resp.max_stride;
ctx->expdb_mask = resp.expdb_mask;
ctx->sq_expdb = !!(resp.expdb_qtypes & IONIC_EXPDB_SQ);
ctx->rq_expdb = !!(resp.expdb_qtypes & IONIC_EXPDB_RQ);
mask = (1u << ctx->pg_shift) - 1;
ctx->dbpage_page = ionic_map_device(1u << ctx->pg_shift, cmd_fd,
resp.dbell_offset & ~mask);
if (!ctx->dbpage_page) {
rc = errno;
goto err_cmd;
}
ctx->dbpage = ctx->dbpage_page + (resp.dbell_offset & mask);
pthread_mutex_init(&ctx->mut, NULL);
ionic_tbl_init(&ctx->qp_tbl);
ionic_verbs_set_ops(ctx);
ctx->spec = resp.max_spec;
if (ctx->spec < 0 || ctx->spec > 16)
ctx->spec = 0;
verbs_debug(&ctx->vctx, "Attached to ctx %p", ctx);
return &ctx->vctx;
err_cmd:
verbs_uninit_context(&ctx->vctx);
err_ctx:
errno = rc;
return NULL;
}
static const struct verbs_match_ent cna_table[] = {
VERBS_DRIVER_ID(RDMA_DRIVER_IONIC),
{}
};
static struct verbs_device *ionic_alloc_device(struct verbs_sysfs_dev *sdev)
{
struct ionic_dev *dev;
static_assert(sizeof(struct ionic_v1_cqe) == 32, "bad size");
static_assert(sizeof(struct ionic_v1_base_hdr) == 16, "bad size");
static_assert(sizeof(struct ionic_v1_recv_bdy) == 48, "bad size");
static_assert(sizeof(struct ionic_v1_common_bdy) == 48, "bad size");
static_assert(sizeof(struct ionic_v1_atomic_bdy) == 48, "bad size");
static_assert(sizeof(struct ionic_v1_bind_mw_bdy) == 48, "bad size");
static_assert(sizeof(struct ionic_v1_wqe) == 64, "bad size");
dev = calloc(1, sizeof(*dev));
if (!dev)
return NULL;
dev->abi_ver = sdev->abi_ver;
return &dev->vdev;
}
static void ionic_uninit_device(struct verbs_device *vdev)
{
struct ionic_dev *dev = to_ionic_dev(&vdev->device);
free(dev);
}
static const struct verbs_device_ops ionic_dev_ops = {
.name = "ionic",
.match_min_abi_version = IONIC_ABI_VERSION,
.match_max_abi_version = IONIC_ABI_VERSION,
.match_table = cna_table,
.alloc_device = ionic_alloc_device,
.uninit_device = ionic_uninit_device,
.alloc_context = ionic_alloc_context,
};
PROVIDER_DRIVER(ionic, ionic_dev_ops);