mirror of https://github.com/F-Stack/f-stack.git
434 lines
9.8 KiB
C
434 lines
9.8 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright 2020 Mellanox Technologies, Ltd
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include <rte_mempool.h>
|
|
#include <rte_bus_pci.h>
|
|
#include <rte_malloc.h>
|
|
#include <rte_errno.h>
|
|
|
|
#include "mlx5_devx_cmds.h"
|
|
#include "../mlx5_common_log.h"
|
|
#include "mlx5_common.h"
|
|
#include "mlx5_common_os.h"
|
|
#include "mlx5_malloc.h"
|
|
|
|
/**
|
|
* Initialization routine for run-time dependency on external lib.
|
|
*/
|
|
void
|
|
mlx5_glue_constructor(void)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Release PD. Releases a given mlx5_pd object
|
|
*
|
|
* @param[in] pd
|
|
* Pointer to mlx5_pd.
|
|
*
|
|
* @return
|
|
* Zero if pd is released successfully, negative number otherwise.
|
|
*/
|
|
int
|
|
mlx5_os_dealloc_pd(void *pd)
|
|
{
|
|
if (!pd)
|
|
return -EINVAL;
|
|
mlx5_devx_cmd_destroy(((struct mlx5_pd *)pd)->obj);
|
|
mlx5_free(pd);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Allocate Protection Domain object and extract its pdn using DV API.
|
|
*
|
|
* @param[out] dev
|
|
* Pointer to the mlx5 device.
|
|
*
|
|
* @return
|
|
* 0 on success, a negative value otherwise.
|
|
*/
|
|
int
|
|
mlx5_os_pd_create(struct mlx5_common_device *cdev)
|
|
{
|
|
struct mlx5_pd *pd;
|
|
|
|
pd = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pd), 0, SOCKET_ID_ANY);
|
|
if (!pd)
|
|
return -1;
|
|
struct mlx5_devx_obj *obj = mlx5_devx_cmd_alloc_pd(cdev->ctx);
|
|
if (!obj) {
|
|
mlx5_free(pd);
|
|
return -1;
|
|
}
|
|
pd->obj = obj;
|
|
pd->pdn = obj->id;
|
|
pd->devx_ctx = cdev->ctx;
|
|
cdev->pd = pd;
|
|
cdev->pdn = pd->pdn;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Detect if a devx_device_bdf object has identical DBDF values to the
|
|
* rte_pci_addr found in bus/pci probing.
|
|
*
|
|
* @param[in] devx_bdf
|
|
* Pointer to the devx_device_bdf structure.
|
|
* @param[in] addr
|
|
* Pointer to the rte_pci_addr structure.
|
|
*
|
|
* @return
|
|
* 1 on Device match, 0 on mismatch.
|
|
*/
|
|
static int
|
|
mlx5_match_devx_bdf_to_addr(struct devx_device_bdf *devx_bdf,
|
|
struct rte_pci_addr *addr)
|
|
{
|
|
if (addr->domain != (devx_bdf->bus_id >> 8) ||
|
|
addr->bus != (devx_bdf->bus_id & 0xff) ||
|
|
addr->devid != devx_bdf->dev_id ||
|
|
addr->function != devx_bdf->fnc_id) {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Detect if a devx_device_bdf object matches the rte_pci_addr
|
|
* found in bus/pci probing
|
|
* Compare both the Native/PF BDF and the raw_bdf representing a VF BDF.
|
|
*
|
|
* @param[in] devx_bdf
|
|
* Pointer to the devx_device_bdf structure.
|
|
* @param[in] addr
|
|
* Pointer to the rte_pci_addr structure.
|
|
*
|
|
* @return
|
|
* 1 on Device match, 0 on mismatch, rte_errno code on failure.
|
|
*/
|
|
static int
|
|
mlx5_match_devx_devices_to_addr(struct devx_device_bdf *devx_bdf,
|
|
struct rte_pci_addr *addr)
|
|
{
|
|
int err;
|
|
struct devx_device mlx5_dev;
|
|
|
|
if (mlx5_match_devx_bdf_to_addr(devx_bdf, addr))
|
|
return 1;
|
|
/*
|
|
* Didn't match on Native/PF BDF, could still match a VF BDF,
|
|
* check it next.
|
|
*/
|
|
err = mlx5_glue->query_device(devx_bdf, &mlx5_dev);
|
|
if (err) {
|
|
DRV_LOG(ERR, "query_device failed");
|
|
rte_errno = err;
|
|
return rte_errno;
|
|
}
|
|
if (mlx5_match_devx_bdf_to_addr(&mlx5_dev.raw_bdf, addr))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Look for DevX device that match to given rte_device.
|
|
*
|
|
* @param dev
|
|
* Pointer to the generic device.
|
|
* @param devx_list
|
|
* Pointer to head of DevX devices list.
|
|
* @param n
|
|
* Number of devices in given DevX devices list.
|
|
*
|
|
* @return
|
|
* A device match on success, NULL otherwise and rte_errno is set.
|
|
*/
|
|
static struct devx_device_bdf *
|
|
mlx5_os_get_devx_device(struct rte_device *dev,
|
|
struct devx_device_bdf *devx_list, int n)
|
|
{
|
|
struct devx_device_bdf *devx_match = NULL;
|
|
struct rte_pci_device *pci_dev = RTE_DEV_TO_PCI(dev);
|
|
struct rte_pci_addr *addr = &pci_dev->addr;
|
|
|
|
while (n-- > 0) {
|
|
int ret = mlx5_match_devx_devices_to_addr(devx_list, addr);
|
|
if (!ret) {
|
|
devx_list++;
|
|
continue;
|
|
}
|
|
if (ret != 1) {
|
|
rte_errno = ret;
|
|
return NULL;
|
|
}
|
|
devx_match = devx_list;
|
|
break;
|
|
}
|
|
if (devx_match == NULL) {
|
|
/* No device matches, just complain and bail out. */
|
|
DRV_LOG(WARNING,
|
|
"No DevX device matches PCI device " PCI_PRI_FMT ","
|
|
" is DevX Configured?",
|
|
addr->domain, addr->bus, addr->devid, addr->function);
|
|
rte_errno = ENOENT;
|
|
}
|
|
return devx_match;
|
|
}
|
|
|
|
/**
|
|
* Function API open device under Windows.
|
|
*
|
|
* This function calls the Windows glue APIs to open a device.
|
|
*
|
|
* @param cdev
|
|
* Pointer to mlx5 device structure.
|
|
* @param classes
|
|
* Chosen classes come from user device arguments.
|
|
*
|
|
* @return
|
|
* 0 on success, a negative errno value otherwise and rte_errno is set.
|
|
*/
|
|
int
|
|
mlx5_os_open_device(struct mlx5_common_device *cdev, uint32_t classes)
|
|
{
|
|
struct devx_device_bdf *devx_bdf_dev = NULL;
|
|
struct devx_device_bdf *devx_list;
|
|
struct mlx5_context *mlx5_ctx = NULL;
|
|
int n;
|
|
|
|
if (classes != MLX5_CLASS_ETH && classes != MLX5_CLASS_CRYPTO) {
|
|
DRV_LOG(ERR,
|
|
"The chosen classes are not supported on Windows.");
|
|
rte_errno = ENOTSUP;
|
|
return -rte_errno;
|
|
}
|
|
errno = 0;
|
|
devx_list = mlx5_glue->get_device_list(&n);
|
|
if (devx_list == NULL) {
|
|
rte_errno = errno ? errno : ENOSYS;
|
|
DRV_LOG(ERR, "Cannot list devices, is DevX enabled?");
|
|
return -rte_errno;
|
|
}
|
|
devx_bdf_dev = mlx5_os_get_devx_device(cdev->dev, devx_list, n);
|
|
if (devx_bdf_dev == NULL)
|
|
goto error;
|
|
/* Try to open DevX device with DV. */
|
|
mlx5_ctx = mlx5_glue->open_device(devx_bdf_dev);
|
|
if (mlx5_ctx == NULL) {
|
|
DRV_LOG(ERR, "Failed to open DevX device.");
|
|
rte_errno = errno;
|
|
goto error;
|
|
}
|
|
if (mlx5_glue->query_device(devx_bdf_dev, &mlx5_ctx->mlx5_dev)) {
|
|
DRV_LOG(ERR, "Failed to query device context fields.");
|
|
rte_errno = errno;
|
|
goto error;
|
|
}
|
|
cdev->config.devx = 1;
|
|
cdev->ctx = mlx5_ctx;
|
|
mlx5_glue->free_device_list(devx_list);
|
|
return 0;
|
|
error:
|
|
if (mlx5_ctx != NULL)
|
|
claim_zero(mlx5_glue->close_device(mlx5_ctx));
|
|
mlx5_glue->free_device_list(devx_list);
|
|
return -rte_errno;
|
|
}
|
|
|
|
/**
|
|
* Register umem.
|
|
*
|
|
* @param[in] ctx
|
|
* Pointer to context.
|
|
* @param[in] addr
|
|
* Pointer to memory start address.
|
|
* @param[in] size
|
|
* Size of the memory to register.
|
|
* @param[out] access
|
|
* UMEM access type
|
|
*
|
|
* @return
|
|
* umem on successful registration, NULL and errno otherwise
|
|
*/
|
|
void *
|
|
mlx5_os_umem_reg(void *ctx, void *addr, size_t size, uint32_t access)
|
|
{
|
|
struct mlx5_devx_umem *umem;
|
|
|
|
umem = mlx5_malloc(MLX5_MEM_ZERO,
|
|
(sizeof(*umem)), 0, SOCKET_ID_ANY);
|
|
if (!umem) {
|
|
errno = ENOMEM;
|
|
return NULL;
|
|
}
|
|
umem->umem_hdl = mlx5_glue->devx_umem_reg(ctx, addr, size, access,
|
|
&umem->umem_id);
|
|
if (!umem->umem_hdl) {
|
|
mlx5_free(umem);
|
|
return NULL;
|
|
}
|
|
umem->addr = addr;
|
|
return umem;
|
|
}
|
|
|
|
/**
|
|
* Deregister umem.
|
|
*
|
|
* @param[in] pumem
|
|
* Pointer to umem.
|
|
*
|
|
* @return
|
|
* 0 on successful release, negative number otherwise
|
|
*/
|
|
int
|
|
mlx5_os_umem_dereg(void *pumem)
|
|
{
|
|
struct mlx5_devx_umem *umem;
|
|
int err = 0;
|
|
|
|
if (!pumem)
|
|
return err;
|
|
umem = pumem;
|
|
if (umem->umem_hdl)
|
|
err = mlx5_glue->devx_umem_dereg(umem->umem_hdl);
|
|
mlx5_free(umem);
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* Register mr. Given protection domain pointer, pointer to addr and length
|
|
* register the memory region.
|
|
*
|
|
* @param[in] pd
|
|
* Pointer to protection domain context (type mlx5_pd).
|
|
* @param[in] addr
|
|
* Pointer to memory start address (type devx_device_ctx).
|
|
* @param[in] length
|
|
* Length of the memory to register.
|
|
* @param[out] pmd_mr
|
|
* pmd_mr struct set with lkey, address, length, pointer to mr object, mkey
|
|
*
|
|
* @return
|
|
* 0 on successful registration, -1 otherwise
|
|
*/
|
|
static int
|
|
mlx5_os_reg_mr(void *pd,
|
|
void *addr, size_t length, struct mlx5_pmd_mr *pmd_mr)
|
|
{
|
|
struct mlx5_devx_mkey_attr mkey_attr;
|
|
struct mlx5_pd *mlx5_pd = (struct mlx5_pd *)pd;
|
|
struct mlx5_hca_attr attr;
|
|
struct mlx5_devx_obj *mkey;
|
|
void *obj;
|
|
|
|
if (!pd || !addr) {
|
|
rte_errno = EINVAL;
|
|
return -1;
|
|
}
|
|
if (mlx5_devx_cmd_query_hca_attr(mlx5_pd->devx_ctx, &attr))
|
|
return -1;
|
|
obj = mlx5_os_umem_reg(mlx5_pd->devx_ctx, addr, length,
|
|
IBV_ACCESS_LOCAL_WRITE);
|
|
if (!obj)
|
|
return -1;
|
|
memset(&mkey_attr, 0, sizeof(mkey_attr));
|
|
mkey_attr.addr = (uintptr_t)addr;
|
|
mkey_attr.size = length;
|
|
mkey_attr.umem_id = ((struct mlx5_devx_umem *)(obj))->umem_id;
|
|
mkey_attr.pd = mlx5_pd->pdn;
|
|
if (!haswell_broadwell_cpu) {
|
|
mkey_attr.relaxed_ordering_write = attr.relaxed_ordering_write;
|
|
mkey_attr.relaxed_ordering_read = attr.relaxed_ordering_read;
|
|
}
|
|
mkey = mlx5_devx_cmd_mkey_create(mlx5_pd->devx_ctx, &mkey_attr);
|
|
if (!mkey) {
|
|
claim_zero(mlx5_os_umem_dereg(obj));
|
|
return -1;
|
|
}
|
|
pmd_mr->addr = addr;
|
|
pmd_mr->len = length;
|
|
pmd_mr->obj = obj;
|
|
pmd_mr->mkey = mkey;
|
|
pmd_mr->lkey = pmd_mr->mkey->id;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* De-register mr.
|
|
*
|
|
* @param[in] pmd_mr
|
|
* Pointer to PMD mr object
|
|
*/
|
|
static void
|
|
mlx5_os_dereg_mr(struct mlx5_pmd_mr *pmd_mr)
|
|
{
|
|
if (!pmd_mr)
|
|
return;
|
|
if (pmd_mr->mkey)
|
|
claim_zero(mlx5_devx_cmd_destroy(pmd_mr->mkey));
|
|
if (pmd_mr->obj)
|
|
claim_zero(mlx5_os_umem_dereg(pmd_mr->obj));
|
|
memset(pmd_mr, 0, sizeof(*pmd_mr));
|
|
}
|
|
|
|
/**
|
|
* Set the reg_mr and dereg_mr callbacks.
|
|
*
|
|
* @param[out] reg_mr_cb
|
|
* Pointer to reg_mr func
|
|
* @param[out] dereg_mr_cb
|
|
* Pointer to dereg_mr func
|
|
*
|
|
*/
|
|
void
|
|
mlx5_os_set_reg_mr_cb(mlx5_reg_mr_t *reg_mr_cb, mlx5_dereg_mr_t *dereg_mr_cb)
|
|
{
|
|
*reg_mr_cb = mlx5_os_reg_mr;
|
|
*dereg_mr_cb = mlx5_os_dereg_mr;
|
|
}
|
|
|
|
/*
|
|
* In Windows, no need to wrap the MR, no known issue for it in kernel.
|
|
* Use the regular function to create direct MR.
|
|
*/
|
|
int
|
|
mlx5_os_wrapped_mkey_create(void *ctx, void *pd, uint32_t pdn, void *addr,
|
|
size_t length, struct mlx5_pmd_wrapped_mr *wpmd_mr)
|
|
{
|
|
struct mlx5_pmd_mr pmd_mr = {0};
|
|
int ret = mlx5_os_reg_mr(pd, addr, length, &pmd_mr);
|
|
|
|
(void)pdn;
|
|
(void)ctx;
|
|
if (ret != 0)
|
|
return -1;
|
|
wpmd_mr->addr = addr;
|
|
wpmd_mr->len = length;
|
|
wpmd_mr->obj = pmd_mr.obj;
|
|
wpmd_mr->imkey = pmd_mr.mkey;
|
|
wpmd_mr->lkey = pmd_mr.mkey->id;
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
mlx5_os_wrapped_mkey_destroy(struct mlx5_pmd_wrapped_mr *wpmd_mr)
|
|
{
|
|
struct mlx5_pmd_mr pmd_mr;
|
|
|
|
if (!wpmd_mr)
|
|
return;
|
|
pmd_mr.addr = wpmd_mr->addr;
|
|
pmd_mr.len = wpmd_mr->len;
|
|
pmd_mr.obj = wpmd_mr->obj;
|
|
pmd_mr.mkey = wpmd_mr->imkey;
|
|
pmd_mr.lkey = wpmd_mr->lkey;
|
|
mlx5_os_dereg_mr(&pmd_mr);
|
|
memset(wpmd_mr, 0, sizeof(*wpmd_mr));
|
|
}
|