/* * 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 #include #include #include #include #include #include #include #include "qelr.h" #include "qelr_verbs.h" #include "qelr_chain.h" #include #include #include 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);