// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB /* Copyright (C) 2019 - 2023 Intel Corporation */ #include #include #include #include #include #include #include #include #include #include #include "ice_devids.h" #include "i40e_devids.h" #include "umain.h" #include "abi.h" #define INTEL_HCA(v, d) VERBS_PCI_MATCH(v, d, NULL) static const struct verbs_match_ent hca_table[] = { VERBS_DRIVER_ID(RDMA_DRIVER_IRDMA), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E823L_BACKPLANE), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E823L_SFP), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E823L_10G_BASE_T), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E823L_1GBE), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E823L_QSFP), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E810C_BACKPLANE), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E810C_QSFP), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E810C_SFP), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E810_XXV_BACKPLANE), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E810_XXV_QSFP), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E810_XXV_SFP), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E823C_BACKPLANE), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E823C_QSFP), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E823C_SFP), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E823C_10G_BASE_T), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E823C_SGMII), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_C822N_BACKPLANE), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_C822N_QSFP), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_C822N_SFP), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E822C_10G_BASE_T), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E822C_SGMII), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E822L_BACKPLANE), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E822L_SFP), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E822L_10G_BASE_T), INTEL_HCA(PCI_VENDOR_ID_INTEL, ICE_DEV_ID_E822L_SGMII), INTEL_HCA(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_X722_A0), INTEL_HCA(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_X722_A0_VF), INTEL_HCA(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_X722), INTEL_HCA(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_X722), INTEL_HCA(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_X722), INTEL_HCA(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_X722), INTEL_HCA(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_X722), INTEL_HCA(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_I_X722), INTEL_HCA(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_X722_VF), INTEL_HCA(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_X722_VF_HV), {} }; /** * irdma_ufree_context - free context that was allocated * @ibctx: context allocated ptr */ static void irdma_ufree_context(struct ibv_context *ibctx) { struct irdma_uvcontext *iwvctx; iwvctx = container_of(ibctx, struct irdma_uvcontext, ibv_ctx.context); irdma_ufree_pd(&iwvctx->iwupd->ibv_pd); irdma_munmap(iwvctx->db); verbs_uninit_context(&iwvctx->ibv_ctx); free(iwvctx); } static const struct verbs_context_ops irdma_uctx_ops = { .alloc_mw = irdma_ualloc_mw, .alloc_pd = irdma_ualloc_pd, .attach_mcast = irdma_uattach_mcast, .bind_mw = irdma_ubind_mw, .cq_event = irdma_cq_event, .create_ah = irdma_ucreate_ah, .create_cq = irdma_ucreate_cq, .create_cq_ex = irdma_ucreate_cq_ex, .create_qp = irdma_ucreate_qp, .dealloc_mw = irdma_udealloc_mw, .dealloc_pd = irdma_ufree_pd, .dereg_mr = irdma_udereg_mr, .destroy_ah = irdma_udestroy_ah, .destroy_cq = irdma_udestroy_cq, .destroy_qp = irdma_udestroy_qp, .detach_mcast = irdma_udetach_mcast, .modify_qp = irdma_umodify_qp, .poll_cq = irdma_upoll_cq, .post_recv = irdma_upost_recv, .post_send = irdma_upost_send, .query_device_ex = irdma_uquery_device_ex, .query_port = irdma_uquery_port, .query_qp = irdma_uquery_qp, .reg_dmabuf_mr = irdma_ureg_mr_dmabuf, .reg_mr = irdma_ureg_mr, .rereg_mr = irdma_urereg_mr, .req_notify_cq = irdma_uarm_cq, .resize_cq = irdma_uresize_cq, .free_context = irdma_ufree_context, }; /** * i40iw_set_hw_attrs - set the hw attributes * @attrs: pointer to hw attributes * * Set the device attibutes to allow user mode to work with * driver on older ABI version. */ static void i40iw_set_hw_attrs(struct irdma_uk_attrs *attrs) { attrs->hw_rev = IRDMA_GEN_1; attrs->max_hw_wq_frags = I40IW_MAX_WQ_FRAGMENT_COUNT; attrs->max_hw_read_sges = I40IW_MAX_SGE_RD; attrs->max_hw_inline = I40IW_MAX_INLINE_DATA_SIZE; attrs->max_hw_rq_quanta = I40IW_QP_SW_MAX_RQ_QUANTA; attrs->max_hw_wq_quanta = I40IW_QP_SW_MAX_WQ_QUANTA; attrs->max_hw_sq_chunk = I40IW_MAX_QUANTA_PER_WR; attrs->max_hw_cq_size = I40IW_MAX_CQ_SIZE; attrs->min_hw_cq_size = IRDMA_MIN_CQ_SIZE; attrs->min_hw_wq_size = I40IW_MIN_WQ_SIZE; } /** * irdma_ualloc_context - allocate context for user app * @ibdev: ib device created during irdma_driver_init * @cmd_fd: save fd for the device * @private_data: device private data * * Returns callback routine table and calls driver for allocating * context and getting back resource information to return as ibv_context. */ static struct verbs_context *irdma_ualloc_context(struct ibv_device *ibdev, int cmd_fd, void *private_data) { struct ibv_pd *ibv_pd; struct irdma_uvcontext *iwvctx; struct irdma_get_context cmd = {}; struct irdma_get_context_resp resp = {}; __u64 mmap_key; __u8 user_ver = IRDMA_ABI_VER; iwvctx = verbs_init_and_alloc_context(ibdev, cmd_fd, iwvctx, ibv_ctx, RDMA_DRIVER_IRDMA); if (!iwvctx) return NULL; cmd.comp_mask |= IRDMA_ALLOC_UCTX_USE_RAW_ATTR; cmd.userspace_ver = user_ver; if (ibv_cmd_get_context(&iwvctx->ibv_ctx, (struct ibv_get_context *)&cmd, sizeof(cmd), &resp.ibv_resp, sizeof(resp))) { cmd.userspace_ver = 4; if (ibv_cmd_get_context(&iwvctx->ibv_ctx, (struct ibv_get_context *)&cmd, sizeof(cmd), &resp.ibv_resp, sizeof(resp))) goto err_free; user_ver = cmd.userspace_ver; } verbs_set_ops(&iwvctx->ibv_ctx, &irdma_uctx_ops); /* Legacy i40iw does not populate hw_rev. The irdma driver always sets it */ if (!resp.hw_rev) { i40iw_set_hw_attrs(&iwvctx->uk_attrs); iwvctx->abi_ver = resp.kernel_ver; iwvctx->legacy_mode = true; mmap_key = 0; } else { iwvctx->uk_attrs.feature_flags = resp.feature_flags; iwvctx->uk_attrs.hw_rev = resp.hw_rev; iwvctx->uk_attrs.max_hw_wq_frags = resp.max_hw_wq_frags; iwvctx->uk_attrs.max_hw_read_sges = resp.max_hw_read_sges; iwvctx->uk_attrs.max_hw_inline = resp.max_hw_inline; iwvctx->uk_attrs.max_hw_rq_quanta = resp.max_hw_rq_quanta; iwvctx->uk_attrs.max_hw_wq_quanta = resp.max_hw_wq_quanta; iwvctx->uk_attrs.max_hw_sq_chunk = resp.max_hw_sq_chunk; iwvctx->uk_attrs.max_hw_cq_size = resp.max_hw_cq_size; iwvctx->uk_attrs.min_hw_cq_size = resp.min_hw_cq_size; iwvctx->abi_ver = user_ver; if (resp.comp_mask & IRDMA_ALLOC_UCTX_USE_RAW_ATTR) iwvctx->use_raw_attrs = true; if (resp.comp_mask & IRDMA_ALLOC_UCTX_MIN_HW_WQ_SIZE) iwvctx->uk_attrs.min_hw_wq_size = resp.min_hw_wq_size; else iwvctx->uk_attrs.min_hw_wq_size = IRDMA_QP_SW_MIN_WQSIZE; mmap_key = resp.db_mmap_key; } iwvctx->db = irdma_mmap(cmd_fd, mmap_key); if (iwvctx->db == MAP_FAILED) goto err_free; ibv_pd = irdma_ualloc_pd(&iwvctx->ibv_ctx.context); if (!ibv_pd) { irdma_munmap(iwvctx->db); goto err_free; } ibv_pd->context = &iwvctx->ibv_ctx.context; iwvctx->iwupd = container_of(ibv_pd, struct irdma_upd, ibv_pd); return &iwvctx->ibv_ctx; err_free: free(iwvctx); return NULL; } static void irdma_uninit_device(struct verbs_device *verbs_device) { struct irdma_udevice *dev; dev = container_of(&verbs_device->device, struct irdma_udevice, ibv_dev.device); free(dev); } static struct verbs_device *irdma_device_alloc(struct verbs_sysfs_dev *sysfs_dev) { struct irdma_udevice *dev; dev = calloc(1, sizeof(*dev)); if (!dev) return NULL; return &dev->ibv_dev; } static const struct verbs_device_ops irdma_udev_ops = { .alloc_context = irdma_ualloc_context, .alloc_device = irdma_device_alloc, .match_max_abi_version = IRDMA_MAX_ABI_VERSION, .match_min_abi_version = IRDMA_MIN_ABI_VERSION, .match_table = hca_table, .name = "irdma", .uninit_device = irdma_uninit_device, }; PROVIDER_DRIVER(irdma, irdma_udev_ops);