vdpa/sfc: introduce Xilinx vDPA driver

Add new vDPA PMD to support vDPA operations of Xilinx devices.
This patch implements probe and remove functions.

Signed-off-by: Vijay Kumar Srivastava <vsrivast@xilinx.com>
Acked-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Maxime Coquelin <maxime.coquelin@redhat.com>
This commit is contained in:
Vijay Kumar Srivastava 2021-11-03 19:27:45 +05:30 committed by Maxime Coquelin
parent 07ed904bf1
commit 5e7596ba7c
11 changed files with 519 additions and 0 deletions

View File

@ -1240,6 +1240,12 @@ F: drivers/vdpa/mlx5/
F: doc/guides/vdpadevs/mlx5.rst
F: doc/guides/vdpadevs/features/mlx5.ini
Xilinx sfc vDPA
M: Vijay Kumar Srivastava <vsrivast@xilinx.com>
F: drivers/vdpa/sfc/
F: doc/guides/vdpadevs/sfc.rst
F: doc/guides/vdpadevs/features/sfc.ini
Eventdev Drivers
----------------

View File

@ -233,6 +233,11 @@ New Features
* Added flow control.
* Added IEEE 1588.
* **Added new vDPA PMD based on Xilinx devices.**
Added a new Xilinx vDPA (``sfc_vdpa``) PMD.
See the :doc:`../vdpadevs/sfc` guide for more details on this driver.
* **Added telemetry callbacks to cryptodev library.**
Added telemetry callback functions which allow a list of crypto devices,

View File

@ -0,0 +1,9 @@
;
; Supported features of the 'sfc' vDPA driver.
;
; Refer to default.ini for the full list of available driver features.
;
[Features]
Linux = Y
x86-64 = Y
Usage doc = Y

View File

@ -14,3 +14,4 @@ which can be used from an application through vhost API.
features_overview
ifc
mlx5
sfc

View File

@ -0,0 +1,97 @@
.. SPDX-License-Identifier: BSD-3-Clause
Copyright(c) 2021 Xilinx Corporation.
Xilinx vDPA driver
==================
The Xilinx vDPA (vhost data path acceleration) driver (**librte_pmd_sfc_vdpa**)
provides support for the Xilinx SN1022 SmartNICs family of 10/25/40/50/100 Gbps
adapters that have support for latest Linux and FreeBSD operating systems.
More information can be found at Xilinx website https://www.xilinx.com.
Xilinx vDPA implementation
--------------------------
ef100 device can be configured in the net device or vDPA mode.
Adding "class=vdpa" parameter helps to specify that this
device is to be used in vDPA mode. If this parameter is not specified, device
will be probed by net/sfc driver and will used as a net device.
This PMD uses libefx (common/sfc_efx) code to access the device firmware.
Supported NICs
--------------
- Xilinx SN1022 SmartNICs
Features
--------
Features of the Xilinx vDPA driver are:
- Compatibility with virtio 0.95 and 1.0
Non-supported Features
----------------------
- Control Queue
- Multi queue
- Live Migration
Prerequisites
-------------
Requires firmware version: v1.0.7.0 or higher
Visit `Xilinx Support Downloads <https://www.xilinx.com/support.html>`_
to get Xilinx Utilities with the latest firmware.
Follow instructions from Alveo SN1000 SmartNICs User Guide to
update firmware and configure the adapter.
Per-Device Parameters
~~~~~~~~~~~~~~~~~~~~~
The following per-device parameters can be passed via EAL PCI device
allowlist option like "-a 02:00.0,arg1=value1,...".
Case-insensitive 1/y/yes/on or 0/n/no/off may be used to specify
boolean parameters value.
- ``class`` [net|vdpa] (default **net**)
Choose the mode of operation of ef100 device.
**net** device will work as network device and will be probed by net/sfc driver.
**vdpa** device will work as vdpa device and will be probed by vdpa/sfc driver.
If this parameter is not specified then ef100 device will operate as network device.
Dynamic Logging Parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~
One may leverage EAL option "--log-level" to change default levels
for the log types supported by the driver. The option is used with
an argument typically consisting of two parts separated by a colon.
Level value is the last part which takes a symbolic name (or integer).
Log type is the former part which may shell match syntax.
Depending on the choice of the expression, the given log level may
be used either for some specific log type or for a subset of types.
SFC vDPA PMD provides the following log types available for control:
- ``pmd.vdpa.sfc.driver`` (default level is **notice**)
Affects driver-wide messages unrelated to any particular devices.
- ``pmd.vdpa.sfc.main`` (default level is **notice**)
Matches a subset of per-port log types registered during runtime.
A full name for a particular type may be obtained by appending a
dot and a PCI device identifier (``XXXX:XX:XX.X``) to the prefix.

View File

@ -8,6 +8,7 @@ endif
drivers = [
'ifc',
'mlx5',
'sfc',
]
std_deps = ['bus_pci', 'kvargs']
std_deps += ['vhost']

View File

@ -0,0 +1,23 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright(c) 2020-2021 Xilinx, Inc.
if ((arch_subdir != 'x86' or not dpdk_conf.get('RTE_ARCH_64')) and
(arch_subdir != 'arm' or not
host_machine.cpu_family().startswith('aarch64')))
build = false
reason = 'only supported on x86_64 and aarch64'
endif
fmt_name = 'sfc_vdpa'
extra_flags = []
foreach flag: extra_flags
if cc.has_argument(flag)
cflags += flag
endif
endforeach
deps += ['common_sfc_efx', 'bus_pci']
sources = files(
'sfc_vdpa.c',
)

281
drivers/vdpa/sfc/sfc_vdpa.c Normal file
View File

@ -0,0 +1,281 @@
/* 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_errno.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;
}
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 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;
sfc_vdpa_log_init(sva, "entry");
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;
}
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_vfio_setup:
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_info(sva, "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_vfio_teardown(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);

View File

@ -0,0 +1,38 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2020-2021 Xilinx, Inc.
*/
#ifndef _SFC_VDPA_H
#define _SFC_VDPA_H
#include <stdint.h>
#include <sys/queue.h>
#include <rte_bus_pci.h>
#include "sfc_vdpa_log.h"
/* Adapter private data */
struct sfc_vdpa_adapter {
TAILQ_ENTRY(sfc_vdpa_adapter) next;
struct rte_pci_device *pdev;
char log_prefix[SFC_VDPA_LOG_PREFIX_MAX];
uint32_t logtype_main;
int vfio_group_fd;
int vfio_dev_fd;
int vfio_container_fd;
int iommu_group_num;
};
uint32_t
sfc_vdpa_register_logtype(const struct rte_pci_addr *pci_addr,
const char *lt_prefix_str,
uint32_t ll_default);
struct sfc_vdpa_adapter *
sfc_vdpa_get_adapter_by_dev(struct rte_pci_device *pdev);
#endif /* _SFC_VDPA_H */

View File

@ -0,0 +1,55 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2020-2021 Xilinx, Inc.
*/
#ifndef _SFC_VDPA_LOG_H_
#define _SFC_VDPA_LOG_H_
/** Generic driver log type */
extern int sfc_vdpa_logtype_driver;
/** Common log type name prefix */
#define SFC_VDPA_LOGTYPE_PREFIX "pmd.vdpa.sfc."
/** Log PMD generic message, add a prefix and a line break */
#define SFC_VDPA_GENERIC_LOG(level, ...) \
rte_log(RTE_LOG_ ## level, sfc_vdpa_logtype_driver, \
RTE_FMT("PMD: " RTE_FMT_HEAD(__VA_ARGS__ ,) "\n", \
RTE_FMT_TAIL(__VA_ARGS__ ,)))
/** Name prefix for the per-device log type used to report basic information */
#define SFC_VDPA_LOGTYPE_MAIN_STR SFC_VDPA_LOGTYPE_PREFIX "main"
#define SFC_VDPA_LOG_PREFIX_MAX 32
/* Log PMD message, automatically add prefix and \n */
#define SFC_VDPA_LOG(sva, level, ...) \
do { \
const struct sfc_vdpa_adapter *_sva = (sva); \
\
rte_log(RTE_LOG_ ## level, _sva->logtype_main, \
RTE_FMT("%s" RTE_FMT_HEAD(__VA_ARGS__ ,) "\n", \
_sva->log_prefix, \
RTE_FMT_TAIL(__VA_ARGS__ ,))); \
} while (0)
#define sfc_vdpa_err(sva, ...) \
SFC_VDPA_LOG(sva, ERR, __VA_ARGS__)
#define sfc_vdpa_warn(sva, ...) \
SFC_VDPA_LOG(sva, WARNING, __VA_ARGS__)
#define sfc_vdpa_notice(sva, ...) \
SFC_VDPA_LOG(sva, NOTICE, __VA_ARGS__)
#define sfc_vdpa_info(sva, ...) \
SFC_VDPA_LOG(sva, INFO, __VA_ARGS__)
#define sfc_vdpa_log_init(sva, ...) \
SFC_VDPA_LOG(sva, INFO, \
RTE_FMT("%s(): " \
RTE_FMT_HEAD(__VA_ARGS__ ,), \
__func__, \
RTE_FMT_TAIL(__VA_ARGS__ ,)))
#endif /* _SFC_VDPA_LOG_H_ */

View File

@ -0,0 +1,3 @@
DPDK_22 {
local: *;
};