500640b328
When sva is null, sfc_vdpa_info(sva, ...) will cause a null
dereference. Use SFC_VDPA_GENERIC_LOG() to avoid that.
See macros sfc_vdpa_info and SFC_VDPA_GENERIC_LOG
defined in drivers/vdpa/sfc/sfc_vdpa_log.h for detail.
Fixes: 5e7596ba7c
("vdpa/sfc: introduce Xilinx vDPA driver")
Cc: stable@dpdk.org
Signed-off-by: Weiguo Li <liwg06@foxmail.com>
Reviewed-by: Maxime Coquelin <maxime.coquelin@redhat.com>
364 lines
8.8 KiB
C
364 lines
8.8 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(c) 2020-2021 Xilinx, Inc.
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <sys/queue.h>
|
|
|
|
#include <rte_common.h>
|
|
#include <rte_devargs.h>
|
|
#include <rte_errno.h>
|
|
#include <rte_kvargs.h>
|
|
#include <rte_string_fns.h>
|
|
#include <rte_vfio.h>
|
|
#include <rte_vhost.h>
|
|
|
|
#include "efx.h"
|
|
#include "sfc_efx.h"
|
|
#include "sfc_vdpa.h"
|
|
|
|
TAILQ_HEAD(sfc_vdpa_adapter_list_head, sfc_vdpa_adapter);
|
|
static struct sfc_vdpa_adapter_list_head sfc_vdpa_adapter_list =
|
|
TAILQ_HEAD_INITIALIZER(sfc_vdpa_adapter_list);
|
|
|
|
static pthread_mutex_t sfc_vdpa_adapter_list_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
struct sfc_vdpa_adapter *
|
|
sfc_vdpa_get_adapter_by_dev(struct rte_pci_device *pdev)
|
|
{
|
|
bool found = false;
|
|
struct sfc_vdpa_adapter *sva;
|
|
|
|
pthread_mutex_lock(&sfc_vdpa_adapter_list_lock);
|
|
|
|
TAILQ_FOREACH(sva, &sfc_vdpa_adapter_list, next) {
|
|
if (pdev == sva->pdev) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pthread_mutex_unlock(&sfc_vdpa_adapter_list_lock);
|
|
|
|
return found ? sva : NULL;
|
|
}
|
|
|
|
struct sfc_vdpa_ops_data *
|
|
sfc_vdpa_get_data_by_dev(struct rte_vdpa_device *vdpa_dev)
|
|
{
|
|
bool found = false;
|
|
struct sfc_vdpa_adapter *sva;
|
|
|
|
pthread_mutex_lock(&sfc_vdpa_adapter_list_lock);
|
|
|
|
TAILQ_FOREACH(sva, &sfc_vdpa_adapter_list, next) {
|
|
if (vdpa_dev == sva->ops_data->vdpa_dev) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pthread_mutex_unlock(&sfc_vdpa_adapter_list_lock);
|
|
|
|
return found ? sva->ops_data : NULL;
|
|
}
|
|
|
|
static int
|
|
sfc_vdpa_vfio_setup(struct sfc_vdpa_adapter *sva)
|
|
{
|
|
struct rte_pci_device *dev = sva->pdev;
|
|
char dev_name[RTE_DEV_NAME_MAX_LEN] = {0};
|
|
int rc;
|
|
|
|
rte_pci_device_name(&dev->addr, dev_name, RTE_DEV_NAME_MAX_LEN);
|
|
|
|
sva->vfio_container_fd = rte_vfio_container_create();
|
|
if (sva->vfio_container_fd < 0) {
|
|
sfc_vdpa_err(sva, "failed to create VFIO container");
|
|
goto fail_container_create;
|
|
}
|
|
|
|
rc = rte_vfio_get_group_num(rte_pci_get_sysfs_path(), dev_name,
|
|
&sva->iommu_group_num);
|
|
if (rc <= 0) {
|
|
sfc_vdpa_err(sva, "failed to get IOMMU group for %s : %s",
|
|
dev_name, rte_strerror(-rc));
|
|
goto fail_get_group_num;
|
|
}
|
|
|
|
sva->vfio_group_fd =
|
|
rte_vfio_container_group_bind(sva->vfio_container_fd,
|
|
sva->iommu_group_num);
|
|
if (sva->vfio_group_fd < 0) {
|
|
sfc_vdpa_err(sva,
|
|
"failed to bind IOMMU group %d to container %d",
|
|
sva->iommu_group_num, sva->vfio_container_fd);
|
|
goto fail_group_bind;
|
|
}
|
|
|
|
if (rte_pci_map_device(dev) != 0) {
|
|
sfc_vdpa_err(sva, "failed to map PCI device %s : %s",
|
|
dev_name, rte_strerror(rte_errno));
|
|
goto fail_pci_map_device;
|
|
}
|
|
|
|
sva->vfio_dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
|
|
|
|
return 0;
|
|
|
|
fail_pci_map_device:
|
|
if (rte_vfio_container_group_unbind(sva->vfio_container_fd,
|
|
sva->iommu_group_num) != 0) {
|
|
sfc_vdpa_err(sva,
|
|
"failed to unbind IOMMU group %d from container %d",
|
|
sva->iommu_group_num, sva->vfio_container_fd);
|
|
}
|
|
|
|
fail_group_bind:
|
|
fail_get_group_num:
|
|
if (rte_vfio_container_destroy(sva->vfio_container_fd) != 0) {
|
|
sfc_vdpa_err(sva, "failed to destroy container %d",
|
|
sva->vfio_container_fd);
|
|
}
|
|
|
|
fail_container_create:
|
|
return -1;
|
|
}
|
|
|
|
static void
|
|
sfc_vdpa_vfio_teardown(struct sfc_vdpa_adapter *sva)
|
|
{
|
|
rte_pci_unmap_device(sva->pdev);
|
|
|
|
if (rte_vfio_container_group_unbind(sva->vfio_container_fd,
|
|
sva->iommu_group_num) != 0) {
|
|
sfc_vdpa_err(sva,
|
|
"failed to unbind IOMMU group %d from container %d",
|
|
sva->iommu_group_num, sva->vfio_container_fd);
|
|
}
|
|
|
|
if (rte_vfio_container_destroy(sva->vfio_container_fd) != 0) {
|
|
sfc_vdpa_err(sva,
|
|
"failed to destroy container %d",
|
|
sva->vfio_container_fd);
|
|
}
|
|
}
|
|
|
|
static int
|
|
sfc_vdpa_set_log_prefix(struct sfc_vdpa_adapter *sva)
|
|
{
|
|
struct rte_pci_device *pci_dev = sva->pdev;
|
|
int ret;
|
|
|
|
ret = snprintf(sva->log_prefix, sizeof(sva->log_prefix),
|
|
"PMD: sfc_vdpa " PCI_PRI_FMT " : ",
|
|
pci_dev->addr.domain, pci_dev->addr.bus,
|
|
pci_dev->addr.devid, pci_dev->addr.function);
|
|
|
|
if (ret < 0 || ret >= (int)sizeof(sva->log_prefix)) {
|
|
SFC_VDPA_GENERIC_LOG(ERR,
|
|
"reserved log prefix is too short for " PCI_PRI_FMT,
|
|
pci_dev->addr.domain, pci_dev->addr.bus,
|
|
pci_dev->addr.devid, pci_dev->addr.function);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t
|
|
sfc_vdpa_register_logtype(const struct rte_pci_addr *pci_addr,
|
|
const char *lt_prefix_str, uint32_t ll_default)
|
|
{
|
|
size_t lt_prefix_str_size = strlen(lt_prefix_str);
|
|
size_t lt_str_size_max;
|
|
char *lt_str = NULL;
|
|
int ret;
|
|
|
|
if (SIZE_MAX - PCI_PRI_STR_SIZE - 1 > lt_prefix_str_size) {
|
|
++lt_prefix_str_size; /* Reserve space for prefix separator */
|
|
lt_str_size_max = lt_prefix_str_size + PCI_PRI_STR_SIZE + 1;
|
|
} else {
|
|
return RTE_LOGTYPE_PMD;
|
|
}
|
|
|
|
lt_str = rte_zmalloc("logtype_str", lt_str_size_max, 0);
|
|
if (lt_str == NULL)
|
|
return RTE_LOGTYPE_PMD;
|
|
|
|
strncpy(lt_str, lt_prefix_str, lt_prefix_str_size);
|
|
lt_str[lt_prefix_str_size - 1] = '.';
|
|
rte_pci_device_name(pci_addr, lt_str + lt_prefix_str_size,
|
|
lt_str_size_max - lt_prefix_str_size);
|
|
lt_str[lt_str_size_max - 1] = '\0';
|
|
|
|
ret = rte_log_register_type_and_pick_level(lt_str, ll_default);
|
|
rte_free(lt_str);
|
|
|
|
return ret < 0 ? RTE_LOGTYPE_PMD : ret;
|
|
}
|
|
|
|
static int
|
|
sfc_vdpa_kvargs_parse(struct sfc_vdpa_adapter *sva)
|
|
{
|
|
struct rte_pci_device *pci_dev = sva->pdev;
|
|
struct rte_devargs *devargs = pci_dev->device.devargs;
|
|
/*
|
|
* To get the device class a mandatory param 'class' is being
|
|
* used so included SFC_EFX_KVARG_DEV_CLASS in the param list.
|
|
*/
|
|
const char **params = (const char *[]){
|
|
RTE_DEVARGS_KEY_CLASS,
|
|
SFC_VDPA_MAC_ADDR,
|
|
NULL,
|
|
};
|
|
|
|
if (devargs == NULL)
|
|
return 0;
|
|
|
|
sva->kvargs = rte_kvargs_parse(devargs->args, params);
|
|
if (sva->kvargs == NULL)
|
|
return -EINVAL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct rte_pci_id pci_id_sfc_vdpa_efx_map[] = {
|
|
{ RTE_PCI_DEVICE(EFX_PCI_VENID_XILINX, EFX_PCI_DEVID_RIVERHEAD_VF) },
|
|
{ .vendor_id = 0, /* sentinel */ },
|
|
};
|
|
|
|
static int
|
|
sfc_vdpa_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
|
|
struct rte_pci_device *pci_dev)
|
|
{
|
|
struct sfc_vdpa_adapter *sva = NULL;
|
|
uint32_t logtype_main;
|
|
int ret = 0;
|
|
|
|
if (sfc_efx_dev_class_get(pci_dev->device.devargs) !=
|
|
SFC_EFX_DEV_CLASS_VDPA) {
|
|
SFC_VDPA_GENERIC_LOG(INFO,
|
|
"Incompatible device class: skip probing, should be probed by other sfc driver.");
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* It will not be probed in the secondary process. As device class
|
|
* is vdpa so return 0 to avoid probe by other sfc driver
|
|
*/
|
|
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
|
|
return 0;
|
|
|
|
logtype_main = sfc_vdpa_register_logtype(&pci_dev->addr,
|
|
SFC_VDPA_LOGTYPE_MAIN_STR,
|
|
RTE_LOG_NOTICE);
|
|
|
|
sva = rte_zmalloc("sfc_vdpa", sizeof(struct sfc_vdpa_adapter), 0);
|
|
if (sva == NULL)
|
|
goto fail_zmalloc;
|
|
|
|
sva->pdev = pci_dev;
|
|
sva->logtype_main = logtype_main;
|
|
|
|
ret = sfc_vdpa_set_log_prefix(sva);
|
|
if (ret != 0)
|
|
goto fail_set_log_prefix;
|
|
|
|
ret = sfc_vdpa_kvargs_parse(sva);
|
|
if (ret != 0)
|
|
goto fail_kvargs_parse;
|
|
|
|
sfc_vdpa_log_init(sva, "entry");
|
|
|
|
sfc_vdpa_adapter_lock_init(sva);
|
|
|
|
sfc_vdpa_log_init(sva, "vfio init");
|
|
if (sfc_vdpa_vfio_setup(sva) < 0) {
|
|
sfc_vdpa_err(sva, "failed to setup device %s", pci_dev->name);
|
|
goto fail_vfio_setup;
|
|
}
|
|
|
|
sfc_vdpa_log_init(sva, "hw init");
|
|
if (sfc_vdpa_hw_init(sva) != 0) {
|
|
sfc_vdpa_err(sva, "failed to init HW %s", pci_dev->name);
|
|
goto fail_hw_init;
|
|
}
|
|
|
|
sfc_vdpa_log_init(sva, "dev init");
|
|
sva->ops_data = sfc_vdpa_device_init(sva, SFC_VDPA_AS_VF);
|
|
if (sva->ops_data == NULL) {
|
|
sfc_vdpa_err(sva, "failed vDPA dev init %s", pci_dev->name);
|
|
goto fail_dev_init;
|
|
}
|
|
|
|
pthread_mutex_lock(&sfc_vdpa_adapter_list_lock);
|
|
TAILQ_INSERT_TAIL(&sfc_vdpa_adapter_list, sva, next);
|
|
pthread_mutex_unlock(&sfc_vdpa_adapter_list_lock);
|
|
|
|
sfc_vdpa_log_init(sva, "done");
|
|
|
|
return 0;
|
|
|
|
fail_dev_init:
|
|
sfc_vdpa_hw_fini(sva);
|
|
|
|
fail_hw_init:
|
|
sfc_vdpa_vfio_teardown(sva);
|
|
|
|
fail_vfio_setup:
|
|
sfc_vdpa_adapter_lock_fini(sva);
|
|
|
|
fail_kvargs_parse:
|
|
fail_set_log_prefix:
|
|
rte_free(sva);
|
|
|
|
fail_zmalloc:
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
sfc_vdpa_pci_remove(struct rte_pci_device *pci_dev)
|
|
{
|
|
struct sfc_vdpa_adapter *sva = NULL;
|
|
|
|
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
|
|
return -1;
|
|
|
|
sva = sfc_vdpa_get_adapter_by_dev(pci_dev);
|
|
if (sva == NULL) {
|
|
SFC_VDPA_GENERIC_LOG(INFO,
|
|
"Invalid device: %s.", pci_dev->name);
|
|
return -1;
|
|
}
|
|
|
|
pthread_mutex_lock(&sfc_vdpa_adapter_list_lock);
|
|
TAILQ_REMOVE(&sfc_vdpa_adapter_list, sva, next);
|
|
pthread_mutex_unlock(&sfc_vdpa_adapter_list_lock);
|
|
|
|
sfc_vdpa_device_fini(sva->ops_data);
|
|
|
|
sfc_vdpa_hw_fini(sva);
|
|
|
|
sfc_vdpa_vfio_teardown(sva);
|
|
|
|
sfc_vdpa_adapter_lock_fini(sva);
|
|
|
|
rte_free(sva);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct rte_pci_driver rte_sfc_vdpa = {
|
|
.id_table = pci_id_sfc_vdpa_efx_map,
|
|
.drv_flags = 0,
|
|
.probe = sfc_vdpa_pci_probe,
|
|
.remove = sfc_vdpa_pci_remove,
|
|
};
|
|
|
|
RTE_PMD_REGISTER_PCI(net_sfc_vdpa, rte_sfc_vdpa);
|
|
RTE_PMD_REGISTER_PCI_TABLE(net_sfc_vdpa, pci_id_sfc_vdpa_efx_map);
|
|
RTE_PMD_REGISTER_KMOD_DEP(net_sfc_vdpa, "* vfio-pci");
|
|
RTE_LOG_REGISTER_SUFFIX(sfc_vdpa_logtype_driver, driver, NOTICE);
|