blob: 82cc7e7fce8f5b8da34b3186f458a0ed720029b4 [file] [log] [blame]
/*
* Copyright (c) 2015-2016 QLogic Corporation
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and /or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <pthread.h>
#include "qelr.h"
#include "qelr_verbs.h"
#include "qelr_chain.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
static void qelr_free_context(struct ibv_context *ibctx);
#define PCI_VENDOR_ID_QLOGIC (0x1077)
#define PCI_DEVICE_ID_QLOGIC_57980S (0x1629)
#define PCI_DEVICE_ID_QLOGIC_57980S_40 (0x1634)
#define PCI_DEVICE_ID_QLOGIC_57980S_10 (0x1666)
#define PCI_DEVICE_ID_QLOGIC_57980S_MF (0x1636)
#define PCI_DEVICE_ID_QLOGIC_57980S_100 (0x1644)
#define PCI_DEVICE_ID_QLOGIC_57980S_50 (0x1654)
#define PCI_DEVICE_ID_QLOGIC_57980S_25 (0x1656)
#define PCI_DEVICE_ID_QLOGIC_57980S_IOV (0x1664)
#define PCI_DEVICE_ID_QLOGIC_AH (0x8070)
#define PCI_DEVICE_ID_QLOGIC_AH_IOV (0x8090)
#define PCI_DEVICE_ID_QLOGIC_AHP (0x8170)
#define PCI_DEVICE_ID_QLOGIC_AHP_IOV (0x8190)
#define QHCA(d) \
VERBS_PCI_MATCH(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_##d, NULL)
static const struct verbs_match_ent hca_table[] = {
VERBS_DRIVER_ID(RDMA_DRIVER_QEDR),
QHCA(57980S),
QHCA(57980S_40),
QHCA(57980S_10),
QHCA(57980S_MF),
QHCA(57980S_100),
QHCA(57980S_50),
QHCA(57980S_25),
QHCA(57980S_IOV),
QHCA(AH),
QHCA(AH_IOV),
QHCA(AHP),
QHCA(AHP_IOV),
{}
};
static const struct verbs_context_ops qelr_ctx_ops = {
.query_device_ex = qelr_query_device,
.query_port = qelr_query_port,
.alloc_pd = qelr_alloc_pd,
.dealloc_pd = qelr_dealloc_pd,
.reg_mr = qelr_reg_mr,
.dereg_mr = qelr_dereg_mr,
.create_cq = qelr_create_cq,
.poll_cq = qelr_poll_cq,
.req_notify_cq = qelr_arm_cq,
.cq_event = qelr_cq_event,
.destroy_cq = qelr_destroy_cq,
.create_qp = qelr_create_qp,
.query_qp = qelr_query_qp,
.modify_qp = qelr_modify_qp,
.destroy_qp = qelr_destroy_qp,
.create_srq = qelr_create_srq,
.destroy_srq = qelr_destroy_srq,
.modify_srq = qelr_modify_srq,
.query_srq = qelr_query_srq,
.post_srq_recv = qelr_post_srq_recv,
.post_send = qelr_post_send,
.post_recv = qelr_post_recv,
.async_event = qelr_async_event,
.free_context = qelr_free_context,
};
static const struct verbs_context_ops qelr_ctx_roce_ops = {
.close_xrcd = qelr_close_xrcd,
.create_qp_ex = qelr_create_qp_ex,
.create_srq_ex = qelr_create_srq_ex,
.get_srq_num = qelr_get_srq_num,
.open_xrcd = qelr_open_xrcd,
};
static void qelr_uninit_device(struct verbs_device *verbs_device)
{
struct qelr_device *dev = get_qelr_dev(&verbs_device->device);
free(dev);
}
static struct verbs_context *qelr_alloc_context(struct ibv_device *ibdev,
int cmd_fd,
void *private_data)
{
struct qelr_devctx *ctx;
struct qelr_alloc_context cmd = {};
struct qelr_alloc_context_resp resp;
ctx = verbs_init_and_alloc_context(ibdev, cmd_fd, ctx, ibv_ctx,
RDMA_DRIVER_QEDR);
if (!ctx)
return NULL;
memset(&resp, 0, sizeof(resp));
cmd.context_flags = QEDR_ALLOC_UCTX_DB_REC | QEDR_SUPPORT_DPM_SIZES;
cmd.context_flags |= QEDR_ALLOC_UCTX_EDPM_MODE;
if (ibv_cmd_get_context(&ctx->ibv_ctx, &cmd.ibv_cmd, sizeof(cmd),
&resp.ibv_resp, sizeof(resp)))
goto cmd_err;
verbs_set_ops(&ctx->ibv_ctx, &qelr_ctx_ops);
if (IS_ROCE(ibdev))
verbs_set_ops(&ctx->ibv_ctx, &qelr_ctx_roce_ops);
ctx->srq_table = calloc(QELR_MAX_SRQ_ID, sizeof(*ctx->srq_table));
if (!ctx->srq_table) {
verbs_err(&ctx->ibv_ctx, "failed to allocate srq_table\n");
goto cmd_err;
}
ctx->kernel_page_size = sysconf(_SC_PAGESIZE);
ctx->db_pa = resp.db_pa;
ctx->db_size = resp.db_size;
/* Set dpm flags according to protocol */
if (IS_ROCE(ibdev)) {
if (resp.dpm_flags & QEDR_DPM_TYPE_ROCE_ENHANCED)
ctx->dpm_flags = QELR_DPM_FLAGS_ENHANCED;
if (resp.dpm_flags & QEDR_DPM_TYPE_ROCE_LEGACY)
ctx->dpm_flags |= QELR_DPM_FLAGS_LEGACY;
if (resp.dpm_flags & QEDR_DPM_TYPE_ROCE_EDPM_MODE)
ctx->dpm_flags |= QELR_DPM_FLAGS_EDPM_MODE;
} else {
if (resp.dpm_flags & QEDR_DPM_TYPE_IWARP_LEGACY)
ctx->dpm_flags = QELR_DPM_FLAGS_LEGACY;
}
/* Defaults set for backward-forward compatibility */
if (resp.dpm_flags & QEDR_DPM_SIZES_SET) {
ctx->ldpm_limit_size = resp.ldpm_limit_size;
ctx->edpm_trans_size = resp.edpm_trans_size;
ctx->edpm_limit_size = resp.edpm_limit_size ?
resp.edpm_limit_size : QEDR_EDPM_MAX_SIZE;
} else {
ctx->ldpm_limit_size = QEDR_LDPM_MAX_SIZE;
ctx->edpm_trans_size = QEDR_EDPM_TRANS_SIZE;
ctx->edpm_limit_size = QEDR_EDPM_MAX_SIZE;
}
ctx->max_send_wr = resp.max_send_wr;
ctx->max_recv_wr = resp.max_recv_wr;
ctx->max_srq_wr = resp.max_srq_wr;
ctx->sges_per_send_wr = resp.sges_per_send_wr;
ctx->sges_per_recv_wr = resp.sges_per_recv_wr;
ctx->sges_per_srq_wr = resp.sges_per_recv_wr;
ctx->max_cqes = resp.max_cqes;
ctx->db_addr = mmap(NULL, ctx->db_size, PROT_WRITE, MAP_SHARED,
cmd_fd, ctx->db_pa);
if (ctx->db_addr == MAP_FAILED) {
int errsv = errno;
verbs_err(&ctx->ibv_ctx,
"alloc context: doorbell mapping failed resp.db_pa = %llx resp.db_size=%d context->cmd_fd=%d errno=%d\n",
resp.db_pa, resp.db_size, cmd_fd, errsv);
goto free_srq_tbl;
}
return &ctx->ibv_ctx;
free_srq_tbl:
free(ctx->srq_table);
cmd_err:
verbs_err(&ctx->ibv_ctx, "Failed to allocate context for device.\n");
verbs_uninit_context(&ctx->ibv_ctx);
free(ctx);
return NULL;
}
static void qelr_free_context(struct ibv_context *ibctx)
{
struct qelr_devctx *ctx = get_qelr_ctx(ibctx);
if (ctx->db_addr)
munmap(ctx->db_addr, ctx->db_size);
free(ctx->srq_table);
verbs_uninit_context(&ctx->ibv_ctx);
free(ctx);
}
static struct verbs_device *qelr_device_alloc(struct verbs_sysfs_dev *sysfs_dev)
{
struct qelr_device *dev;
dev = calloc(1, sizeof(*dev));
if (!dev)
return NULL;
return &dev->ibv_dev;
}
static const struct verbs_device_ops qelr_dev_ops = {
.name = "qedr",
.match_min_abi_version = QELR_ABI_VERSION,
.match_max_abi_version = QELR_ABI_VERSION,
.match_table = hca_table,
.alloc_device = qelr_device_alloc,
.uninit_device = qelr_uninit_device,
.alloc_context = qelr_alloc_context,
};
PROVIDER_DRIVER(qedr, qelr_dev_ops);