net/mana: add basic driver with build environment
MANA is a PCI device. It uses IB verbs to access hardware through the kernel RDMA layer. This patch introduces build environment and basic device probe functions. Signed-off-by: Long Li <longli@microsoft.com>
This commit is contained in:
parent
bb340f56fc
commit
517ed6e2d5
@ -837,6 +837,12 @@ F: buildtools/options-ibverbs-static.sh
|
|||||||
F: doc/guides/nics/mlx5.rst
|
F: doc/guides/nics/mlx5.rst
|
||||||
F: doc/guides/nics/features/mlx5.ini
|
F: doc/guides/nics/features/mlx5.ini
|
||||||
|
|
||||||
|
Microsoft mana
|
||||||
|
M: Long Li <longli@microsoft.com>
|
||||||
|
F: drivers/net/mana/
|
||||||
|
F: doc/guides/nics/mana.rst
|
||||||
|
F: doc/guides/nics/features/mana.ini
|
||||||
|
|
||||||
Microsoft vdev_netvsc - EXPERIMENTAL
|
Microsoft vdev_netvsc - EXPERIMENTAL
|
||||||
M: Matan Azrad <matan@nvidia.com>
|
M: Matan Azrad <matan@nvidia.com>
|
||||||
F: drivers/net/vdev_netvsc/
|
F: drivers/net/vdev_netvsc/
|
||||||
|
10
doc/guides/nics/features/mana.ini
Normal file
10
doc/guides/nics/features/mana.ini
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
;
|
||||||
|
; Supported features of the 'mana' network poll mode driver.
|
||||||
|
;
|
||||||
|
; Refer to default.ini for the full list of available PMD features.
|
||||||
|
;
|
||||||
|
[Features]
|
||||||
|
Multiprocess aware = Y
|
||||||
|
Linux = Y
|
||||||
|
x86-64 = Y
|
||||||
|
Usage doc = Y
|
@ -41,6 +41,7 @@ Network Interface Controller Drivers
|
|||||||
intel_vf
|
intel_vf
|
||||||
kni
|
kni
|
||||||
liquidio
|
liquidio
|
||||||
|
mana
|
||||||
memif
|
memif
|
||||||
mlx4
|
mlx4
|
||||||
mlx5
|
mlx5
|
||||||
|
78
doc/guides/nics/mana.rst
Normal file
78
doc/guides/nics/mana.rst
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
.. SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
Copyright 2022 Microsoft Corporation
|
||||||
|
|
||||||
|
MANA poll mode driver library
|
||||||
|
=============================
|
||||||
|
|
||||||
|
The MANA poll mode driver library (**librte_net_mana**) implements support
|
||||||
|
for Microsoft Azure Network Adapter VF in SR-IOV context.
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
Features of the MANA Ethdev PMD are:
|
||||||
|
|
||||||
|
Prerequisites
|
||||||
|
-------------
|
||||||
|
|
||||||
|
This driver relies on external libraries and kernel drivers
|
||||||
|
for resources allocations and initialization.
|
||||||
|
The following dependencies are not part of DPDK
|
||||||
|
and must be installed separately:
|
||||||
|
|
||||||
|
- **libibverbs** (provided by rdma-core package)
|
||||||
|
|
||||||
|
User space verbs framework used by librte_net_mana.
|
||||||
|
This library provides a generic interface between the kernel
|
||||||
|
and low-level user space drivers such as libmana.
|
||||||
|
|
||||||
|
It allows slow and privileged operations
|
||||||
|
(context initialization, hardware resources allocations)
|
||||||
|
to be managed by the kernel and fast operations to never leave user space.
|
||||||
|
The minimum required rdma-core version is v43.
|
||||||
|
|
||||||
|
In most cases, rdma-core is shipped as a package with an OS distribution.
|
||||||
|
User can also install the upstream version of the rdma-core from
|
||||||
|
https://github.com/linux-rdma/rdma-core.
|
||||||
|
|
||||||
|
- **libmana** (provided by rdma-core package)
|
||||||
|
|
||||||
|
Low-level user space driver library
|
||||||
|
for Microsoft Azure Network Adapter devices,
|
||||||
|
it is automatically loaded by libibverbs.
|
||||||
|
The minimum required version of rdma-core with libmana is v43.
|
||||||
|
|
||||||
|
- **Kernel modules**
|
||||||
|
|
||||||
|
They provide the kernel-side verbs API and low level device drivers
|
||||||
|
that manage actual hardware initialization
|
||||||
|
and resources sharing with user space processes.
|
||||||
|
The minimum required Linux kernel version is 6.1.
|
||||||
|
|
||||||
|
Unlike most other PMDs, these modules must remain loaded
|
||||||
|
and bound to their devices:
|
||||||
|
|
||||||
|
- mana: Ethernet device driver that provides kernel network interfaces.
|
||||||
|
- mana_ib: InifiniBand device driver.
|
||||||
|
- ib_uverbs: user space driver for verbs (entry point for libibverbs).
|
||||||
|
|
||||||
|
Driver compilation and testing
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Refer to the document
|
||||||
|
:ref:`compiling and testing a PMD for a NIC <pmd_build_and_test>` for details.
|
||||||
|
|
||||||
|
MANA PMD arguments
|
||||||
|
------------------
|
||||||
|
|
||||||
|
The user can specify below argument in devargs.
|
||||||
|
|
||||||
|
#. ``mac``:
|
||||||
|
|
||||||
|
Specify the MAC address for this device.
|
||||||
|
If it is set, the driver probes and loads the NIC
|
||||||
|
with a matching MAC address.
|
||||||
|
If it is not set, the driver probes on all the NICs on the PCI device.
|
||||||
|
The default value is not set,
|
||||||
|
meaning all the NICs will be probed and loaded.
|
||||||
|
User can specify multiple mac=xx:xx:xx:xx:xx:xx arguments for up to 8 NICs.
|
@ -94,6 +94,8 @@ New Features
|
|||||||
|
|
||||||
* Added support for flow action REPRESENTED_PORT.
|
* Added support for flow action REPRESENTED_PORT.
|
||||||
|
|
||||||
|
* **Added Microsoft mana driver.**
|
||||||
|
|
||||||
* **Updated Netronome nfp driver.**
|
* **Updated Netronome nfp driver.**
|
||||||
|
|
||||||
Added the needed data structures and logics to support flow API offload:
|
Added the needed data structures and logics to support flow API offload:
|
||||||
|
732
drivers/net/mana/mana.c
Normal file
732
drivers/net/mana/mana.c
Normal file
@ -0,0 +1,732 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright 2022 Microsoft Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include <ethdev_driver.h>
|
||||||
|
#include <ethdev_pci.h>
|
||||||
|
#include <rte_kvargs.h>
|
||||||
|
#include <rte_eal_paging.h>
|
||||||
|
|
||||||
|
#include <infiniband/verbs.h>
|
||||||
|
#include <infiniband/manadv.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "mana.h"
|
||||||
|
|
||||||
|
/* Shared memory between primary/secondary processes, per driver */
|
||||||
|
/* Data to track primary/secondary usage */
|
||||||
|
struct mana_shared_data *mana_shared_data;
|
||||||
|
static struct mana_shared_data mana_local_data;
|
||||||
|
|
||||||
|
/* The memory region for the above data */
|
||||||
|
static const struct rte_memzone *mana_shared_mz;
|
||||||
|
static const char *MZ_MANA_SHARED_DATA = "mana_shared_data";
|
||||||
|
|
||||||
|
/* Spinlock for mana_shared_data */
|
||||||
|
static rte_spinlock_t mana_shared_data_lock = RTE_SPINLOCK_INITIALIZER;
|
||||||
|
|
||||||
|
/* Allocate a buffer on the stack and fill it with a printf format string. */
|
||||||
|
#define MANA_MKSTR(name, ...) \
|
||||||
|
int mkstr_size_##name = snprintf(NULL, 0, "" __VA_ARGS__); \
|
||||||
|
char name[mkstr_size_##name + 1]; \
|
||||||
|
\
|
||||||
|
memset(name, 0, mkstr_size_##name + 1); \
|
||||||
|
snprintf(name, sizeof(name), "" __VA_ARGS__)
|
||||||
|
|
||||||
|
int mana_logtype_driver;
|
||||||
|
int mana_logtype_init;
|
||||||
|
|
||||||
|
static const struct eth_dev_ops mana_dev_ops = {
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct eth_dev_ops mana_dev_secondary_ops = {
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16_t
|
||||||
|
mana_rx_burst_removed(void *dpdk_rxq __rte_unused,
|
||||||
|
struct rte_mbuf **pkts __rte_unused,
|
||||||
|
uint16_t pkts_n __rte_unused)
|
||||||
|
{
|
||||||
|
rte_mb();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t
|
||||||
|
mana_tx_burst_removed(void *dpdk_rxq __rte_unused,
|
||||||
|
struct rte_mbuf **pkts __rte_unused,
|
||||||
|
uint16_t pkts_n __rte_unused)
|
||||||
|
{
|
||||||
|
rte_mb();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ETH_MANA_MAC_ARG "mac"
|
||||||
|
static const char * const mana_init_args[] = {
|
||||||
|
ETH_MANA_MAC_ARG,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Support of parsing up to 8 mac address from EAL command line */
|
||||||
|
#define MAX_NUM_ADDRESS 8
|
||||||
|
struct mana_conf {
|
||||||
|
struct rte_ether_addr mac_array[MAX_NUM_ADDRESS];
|
||||||
|
unsigned int index;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
mana_arg_parse_callback(const char *key, const char *val, void *private)
|
||||||
|
{
|
||||||
|
struct mana_conf *conf = (struct mana_conf *)private;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
DRV_LOG(INFO, "key=%s value=%s index=%d", key, val, conf->index);
|
||||||
|
|
||||||
|
if (conf->index >= MAX_NUM_ADDRESS) {
|
||||||
|
DRV_LOG(ERR, "Exceeding max MAC address");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = rte_ether_unformat_addr(val, &conf->mac_array[conf->index]);
|
||||||
|
if (ret) {
|
||||||
|
DRV_LOG(ERR, "Invalid MAC address %s", val);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
conf->index++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mana_parse_args(struct rte_devargs *devargs, struct mana_conf *conf)
|
||||||
|
{
|
||||||
|
struct rte_kvargs *kvlist;
|
||||||
|
unsigned int arg_count;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
kvlist = rte_kvargs_parse(devargs->drv_str, mana_init_args);
|
||||||
|
if (!kvlist) {
|
||||||
|
DRV_LOG(ERR, "failed to parse kvargs args=%s", devargs->drv_str);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_count = rte_kvargs_count(kvlist, mana_init_args[0]);
|
||||||
|
if (arg_count > MAX_NUM_ADDRESS) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto free_kvlist;
|
||||||
|
}
|
||||||
|
ret = rte_kvargs_process(kvlist, mana_init_args[0],
|
||||||
|
mana_arg_parse_callback, conf);
|
||||||
|
if (ret) {
|
||||||
|
DRV_LOG(ERR, "error parsing args");
|
||||||
|
goto free_kvlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_kvlist:
|
||||||
|
rte_kvargs_free(kvlist);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_port_mac(struct ibv_device *device, unsigned int port,
|
||||||
|
struct rte_ether_addr *addr)
|
||||||
|
{
|
||||||
|
FILE *file;
|
||||||
|
int ret = 0;
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *dent;
|
||||||
|
unsigned int dev_port;
|
||||||
|
char mac[20];
|
||||||
|
|
||||||
|
MANA_MKSTR(path, "%s/device/net", device->ibdev_path);
|
||||||
|
|
||||||
|
dir = opendir(path);
|
||||||
|
if (!dir)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
while ((dent = readdir(dir))) {
|
||||||
|
char *name = dent->d_name;
|
||||||
|
|
||||||
|
MANA_MKSTR(port_path, "%s/%s/dev_port", path, name);
|
||||||
|
|
||||||
|
/* Ignore . and .. */
|
||||||
|
if ((name[0] == '.') &&
|
||||||
|
((name[1] == '\0') ||
|
||||||
|
((name[1] == '.') && (name[2] == '\0'))))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
file = fopen(port_path, "r");
|
||||||
|
if (!file)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = fscanf(file, "%u", &dev_port);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
if (ret != 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Ethernet ports start at 0, IB port start at 1 */
|
||||||
|
if (dev_port == port - 1) {
|
||||||
|
MANA_MKSTR(address_path, "%s/%s/address", path, name);
|
||||||
|
|
||||||
|
file = fopen(address_path, "r");
|
||||||
|
if (!file)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = fscanf(file, "%s", mac);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ret = rte_ether_unformat_addr(mac, addr);
|
||||||
|
if (ret)
|
||||||
|
DRV_LOG(ERR, "unrecognized mac addr %s", mac);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mana_ibv_device_to_pci_addr(const struct ibv_device *device,
|
||||||
|
struct rte_pci_addr *pci_addr)
|
||||||
|
{
|
||||||
|
FILE *file;
|
||||||
|
char *line = NULL;
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
MANA_MKSTR(path, "%s/device/uevent", device->ibdev_path);
|
||||||
|
|
||||||
|
file = fopen(path, "r");
|
||||||
|
if (!file)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
while (getline(&line, &len, file) != -1) {
|
||||||
|
/* Extract information. */
|
||||||
|
if (sscanf(line,
|
||||||
|
"PCI_SLOT_NAME="
|
||||||
|
"%" SCNx32 ":%" SCNx8 ":%" SCNx8 ".%" SCNx8 "\n",
|
||||||
|
&pci_addr->domain,
|
||||||
|
&pci_addr->bus,
|
||||||
|
&pci_addr->devid,
|
||||||
|
&pci_addr->function) == 4) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
fclose(file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mana_proc_priv_init(struct rte_eth_dev *dev)
|
||||||
|
{
|
||||||
|
struct mana_process_priv *priv;
|
||||||
|
|
||||||
|
priv = rte_zmalloc_socket("mana_proc_priv",
|
||||||
|
sizeof(struct mana_process_priv),
|
||||||
|
RTE_CACHE_LINE_SIZE,
|
||||||
|
dev->device->numa_node);
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
dev->process_private = priv;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map the doorbell page for the secondary process through IB device handle.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mana_map_doorbell_secondary(struct rte_eth_dev *eth_dev, int fd)
|
||||||
|
{
|
||||||
|
struct mana_process_priv *priv = eth_dev->process_private;
|
||||||
|
|
||||||
|
void *addr;
|
||||||
|
|
||||||
|
addr = mmap(NULL, rte_mem_page_size(), PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
if (addr == MAP_FAILED) {
|
||||||
|
DRV_LOG(ERR, "Failed to map secondary doorbell port %u",
|
||||||
|
eth_dev->data->port_id);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
DRV_LOG(INFO, "Secondary doorbell mapped to %p", addr);
|
||||||
|
|
||||||
|
priv->db_page = addr;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize shared data for the driver (all devices) */
|
||||||
|
static int
|
||||||
|
mana_init_shared_data(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
const struct rte_memzone *secondary_mz;
|
||||||
|
|
||||||
|
rte_spinlock_lock(&mana_shared_data_lock);
|
||||||
|
|
||||||
|
/* Skip if shared data is already initialized */
|
||||||
|
if (mana_shared_data)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
|
||||||
|
mana_shared_mz = rte_memzone_reserve(MZ_MANA_SHARED_DATA,
|
||||||
|
sizeof(*mana_shared_data),
|
||||||
|
SOCKET_ID_ANY, 0);
|
||||||
|
if (!mana_shared_mz) {
|
||||||
|
DRV_LOG(ERR, "Cannot allocate mana shared data");
|
||||||
|
ret = -rte_errno;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
mana_shared_data = mana_shared_mz->addr;
|
||||||
|
memset(mana_shared_data, 0, sizeof(*mana_shared_data));
|
||||||
|
rte_spinlock_init(&mana_shared_data->lock);
|
||||||
|
} else {
|
||||||
|
secondary_mz = rte_memzone_lookup(MZ_MANA_SHARED_DATA);
|
||||||
|
if (!secondary_mz) {
|
||||||
|
DRV_LOG(ERR, "Cannot attach mana shared data");
|
||||||
|
ret = -rte_errno;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
mana_shared_data = secondary_mz->addr;
|
||||||
|
memset(&mana_local_data, 0, sizeof(mana_local_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
rte_spinlock_unlock(&mana_shared_data_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Init the data structures for use in primary and secondary processes.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mana_init_once(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = mana_init_shared_data();
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
rte_spinlock_lock(&mana_shared_data->lock);
|
||||||
|
|
||||||
|
switch (rte_eal_process_type()) {
|
||||||
|
case RTE_PROC_PRIMARY:
|
||||||
|
if (mana_shared_data->init_done)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ret = mana_mp_init_primary();
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
DRV_LOG(ERR, "MP INIT PRIMARY");
|
||||||
|
|
||||||
|
mana_shared_data->init_done = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTE_PROC_SECONDARY:
|
||||||
|
|
||||||
|
if (mana_local_data.init_done)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ret = mana_mp_init_secondary();
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
|
||||||
|
DRV_LOG(ERR, "MP INIT SECONDARY");
|
||||||
|
|
||||||
|
mana_local_data.init_done = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Impossible, internal error */
|
||||||
|
ret = -EPROTO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rte_spinlock_unlock(&mana_shared_data->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Probe an IB port
|
||||||
|
* Return value:
|
||||||
|
* positive value: successfully probed port
|
||||||
|
* 0: port not matching specified MAC address
|
||||||
|
* negative value: error code
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mana_probe_port(struct ibv_device *ibdev, struct ibv_device_attr_ex *dev_attr,
|
||||||
|
uint8_t port, struct rte_pci_device *pci_dev, struct rte_ether_addr *addr)
|
||||||
|
{
|
||||||
|
struct mana_priv *priv = NULL;
|
||||||
|
struct rte_eth_dev *eth_dev = NULL;
|
||||||
|
struct ibv_parent_domain_init_attr attr = {0};
|
||||||
|
char address[64];
|
||||||
|
char name[RTE_ETH_NAME_MAX_LEN];
|
||||||
|
int ret;
|
||||||
|
struct ibv_context *ctx = NULL;
|
||||||
|
|
||||||
|
rte_ether_format_addr(address, sizeof(address), addr);
|
||||||
|
DRV_LOG(INFO, "device located port %u address %s", port, address);
|
||||||
|
|
||||||
|
priv = rte_zmalloc_socket(NULL, sizeof(*priv), RTE_CACHE_LINE_SIZE,
|
||||||
|
SOCKET_ID_ANY);
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "%s_port%d", pci_dev->device.name, port);
|
||||||
|
|
||||||
|
if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
eth_dev = rte_eth_dev_attach_secondary(name);
|
||||||
|
if (!eth_dev) {
|
||||||
|
DRV_LOG(ERR, "Can't attach to dev %s", name);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
eth_dev->device = &pci_dev->device;
|
||||||
|
eth_dev->dev_ops = &mana_dev_secondary_ops;
|
||||||
|
ret = mana_proc_priv_init(eth_dev);
|
||||||
|
if (ret)
|
||||||
|
goto failed;
|
||||||
|
priv->process_priv = eth_dev->process_private;
|
||||||
|
|
||||||
|
/* Get the IB FD from the primary process */
|
||||||
|
fd = mana_mp_req_verbs_cmd_fd(eth_dev);
|
||||||
|
if (fd < 0) {
|
||||||
|
DRV_LOG(ERR, "Failed to get FD %d", fd);
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mana_map_doorbell_secondary(eth_dev, fd);
|
||||||
|
if (ret) {
|
||||||
|
DRV_LOG(ERR, "Failed secondary map %d", fd);
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fd is no not used after mapping doorbell */
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
eth_dev->tx_pkt_burst = mana_tx_burst_removed;
|
||||||
|
eth_dev->rx_pkt_burst = mana_rx_burst_removed;
|
||||||
|
|
||||||
|
rte_spinlock_lock(&mana_shared_data->lock);
|
||||||
|
mana_shared_data->secondary_cnt++;
|
||||||
|
mana_local_data.secondary_cnt++;
|
||||||
|
rte_spinlock_unlock(&mana_shared_data->lock);
|
||||||
|
|
||||||
|
rte_eth_copy_pci_info(eth_dev, pci_dev);
|
||||||
|
rte_eth_dev_probing_finish(eth_dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = ibv_open_device(ibdev);
|
||||||
|
if (!ctx) {
|
||||||
|
DRV_LOG(ERR, "Failed to open IB device %s", ibdev->name);
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
eth_dev = rte_eth_dev_allocate(name);
|
||||||
|
if (!eth_dev) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
eth_dev->data->mac_addrs =
|
||||||
|
rte_calloc("mana_mac", 1,
|
||||||
|
sizeof(struct rte_ether_addr), 0);
|
||||||
|
if (!eth_dev->data->mac_addrs) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
rte_ether_addr_copy(addr, eth_dev->data->mac_addrs);
|
||||||
|
|
||||||
|
priv->ib_pd = ibv_alloc_pd(ctx);
|
||||||
|
if (!priv->ib_pd) {
|
||||||
|
DRV_LOG(ERR, "ibv_alloc_pd failed port %d", port);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a parent domain with the port number */
|
||||||
|
attr.pd = priv->ib_pd;
|
||||||
|
attr.comp_mask = IBV_PARENT_DOMAIN_INIT_ATTR_PD_CONTEXT;
|
||||||
|
attr.pd_context = (void *)(uint64_t)port;
|
||||||
|
priv->ib_parent_pd = ibv_alloc_parent_domain(ctx, &attr);
|
||||||
|
if (!priv->ib_parent_pd) {
|
||||||
|
DRV_LOG(ERR, "ibv_alloc_parent_domain failed port %d", port);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->ib_ctx = ctx;
|
||||||
|
priv->port_id = eth_dev->data->port_id;
|
||||||
|
priv->dev_port = port;
|
||||||
|
eth_dev->data->dev_private = priv;
|
||||||
|
priv->dev_data = eth_dev->data;
|
||||||
|
|
||||||
|
priv->max_rx_queues = dev_attr->orig_attr.max_qp;
|
||||||
|
priv->max_tx_queues = dev_attr->orig_attr.max_qp;
|
||||||
|
|
||||||
|
priv->max_rx_desc =
|
||||||
|
RTE_MIN(dev_attr->orig_attr.max_qp_wr,
|
||||||
|
dev_attr->orig_attr.max_cqe);
|
||||||
|
priv->max_tx_desc =
|
||||||
|
RTE_MIN(dev_attr->orig_attr.max_qp_wr,
|
||||||
|
dev_attr->orig_attr.max_cqe);
|
||||||
|
|
||||||
|
priv->max_send_sge = dev_attr->orig_attr.max_sge;
|
||||||
|
priv->max_recv_sge = dev_attr->orig_attr.max_sge;
|
||||||
|
|
||||||
|
priv->max_mr = dev_attr->orig_attr.max_mr;
|
||||||
|
priv->max_mr_size = dev_attr->orig_attr.max_mr_size;
|
||||||
|
|
||||||
|
DRV_LOG(INFO, "dev %s max queues %d desc %d sge %d",
|
||||||
|
name, priv->max_rx_queues, priv->max_rx_desc,
|
||||||
|
priv->max_send_sge);
|
||||||
|
|
||||||
|
rte_eth_copy_pci_info(eth_dev, pci_dev);
|
||||||
|
|
||||||
|
rte_spinlock_lock(&mana_shared_data->lock);
|
||||||
|
mana_shared_data->primary_cnt++;
|
||||||
|
rte_spinlock_unlock(&mana_shared_data->lock);
|
||||||
|
|
||||||
|
eth_dev->device = &pci_dev->device;
|
||||||
|
|
||||||
|
DRV_LOG(INFO, "device %s at port %u", name, eth_dev->data->port_id);
|
||||||
|
|
||||||
|
eth_dev->rx_pkt_burst = mana_rx_burst_removed;
|
||||||
|
eth_dev->tx_pkt_burst = mana_tx_burst_removed;
|
||||||
|
eth_dev->dev_ops = &mana_dev_ops;
|
||||||
|
|
||||||
|
rte_eth_dev_probing_finish(eth_dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
/* Free the resource for the port failed */
|
||||||
|
if (priv) {
|
||||||
|
if (priv->ib_parent_pd)
|
||||||
|
ibv_dealloc_pd(priv->ib_parent_pd);
|
||||||
|
|
||||||
|
if (priv->ib_pd)
|
||||||
|
ibv_dealloc_pd(priv->ib_pd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eth_dev)
|
||||||
|
rte_eth_dev_release_port(eth_dev);
|
||||||
|
|
||||||
|
rte_free(priv);
|
||||||
|
|
||||||
|
if (ctx)
|
||||||
|
ibv_close_device(ctx);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Goes through the IB device list to look for the IB port matching the
|
||||||
|
* mac_addr. If found, create a rte_eth_dev for it.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mana_pci_probe_mac(struct rte_pci_device *pci_dev,
|
||||||
|
struct rte_ether_addr *mac_addr)
|
||||||
|
{
|
||||||
|
struct ibv_device **ibv_list;
|
||||||
|
int ibv_idx;
|
||||||
|
struct ibv_context *ctx;
|
||||||
|
int num_devices;
|
||||||
|
int ret = 0;
|
||||||
|
uint8_t port;
|
||||||
|
|
||||||
|
ibv_list = ibv_get_device_list(&num_devices);
|
||||||
|
for (ibv_idx = 0; ibv_idx < num_devices; ibv_idx++) {
|
||||||
|
struct ibv_device *ibdev = ibv_list[ibv_idx];
|
||||||
|
struct rte_pci_addr pci_addr;
|
||||||
|
struct ibv_device_attr_ex dev_attr;
|
||||||
|
|
||||||
|
DRV_LOG(INFO, "Probe device name %s dev_name %s ibdev_path %s",
|
||||||
|
ibdev->name, ibdev->dev_name, ibdev->ibdev_path);
|
||||||
|
|
||||||
|
if (mana_ibv_device_to_pci_addr(ibdev, &pci_addr))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Ignore if this IB device is not this PCI device */
|
||||||
|
if (pci_dev->addr.domain != pci_addr.domain ||
|
||||||
|
pci_dev->addr.bus != pci_addr.bus ||
|
||||||
|
pci_dev->addr.devid != pci_addr.devid ||
|
||||||
|
pci_dev->addr.function != pci_addr.function)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ctx = ibv_open_device(ibdev);
|
||||||
|
if (!ctx) {
|
||||||
|
DRV_LOG(ERR, "Failed to open IB device %s",
|
||||||
|
ibdev->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ret = ibv_query_device_ex(ctx, NULL, &dev_attr);
|
||||||
|
ibv_close_device(ctx);
|
||||||
|
|
||||||
|
for (port = 1; port <= dev_attr.orig_attr.phys_port_cnt;
|
||||||
|
port++) {
|
||||||
|
struct rte_ether_addr addr;
|
||||||
|
ret = get_port_mac(ibdev, port, &addr);
|
||||||
|
if (ret)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (mac_addr && !rte_is_same_ether_addr(&addr, mac_addr))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = mana_probe_port(ibdev, &dev_attr, port, pci_dev, &addr);
|
||||||
|
if (ret)
|
||||||
|
DRV_LOG(ERR, "Probe on IB port %u failed %d", port, ret);
|
||||||
|
else
|
||||||
|
DRV_LOG(INFO, "Successfully probed on IB port %u", port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ibv_free_device_list(ibv_list);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Main callback function from PCI bus to probe a device.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mana_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
|
||||||
|
struct rte_pci_device *pci_dev)
|
||||||
|
{
|
||||||
|
struct rte_devargs *args = pci_dev->device.devargs;
|
||||||
|
struct mana_conf conf = {0};
|
||||||
|
unsigned int i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (args && args->drv_str) {
|
||||||
|
ret = mana_parse_args(args, &conf);
|
||||||
|
if (ret) {
|
||||||
|
DRV_LOG(ERR, "Failed to parse parameters args = %s",
|
||||||
|
args->drv_str);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mana_init_once();
|
||||||
|
if (ret) {
|
||||||
|
DRV_LOG(ERR, "Failed to init PMD global data %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there are no driver parameters, probe on all ports */
|
||||||
|
if (!conf.index)
|
||||||
|
return mana_pci_probe_mac(pci_dev, NULL);
|
||||||
|
|
||||||
|
for (i = 0; i < conf.index; i++) {
|
||||||
|
ret = mana_pci_probe_mac(pci_dev, &conf.mac_array[i]);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mana_dev_uninit(struct rte_eth_dev *dev)
|
||||||
|
{
|
||||||
|
RTE_SET_USED(dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callback from PCI to remove this device.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
mana_pci_remove(struct rte_pci_device *pci_dev)
|
||||||
|
{
|
||||||
|
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
|
||||||
|
rte_spinlock_lock(&mana_shared_data_lock);
|
||||||
|
|
||||||
|
rte_spinlock_lock(&mana_shared_data->lock);
|
||||||
|
|
||||||
|
RTE_VERIFY(mana_shared_data->primary_cnt > 0);
|
||||||
|
mana_shared_data->primary_cnt--;
|
||||||
|
if (!mana_shared_data->primary_cnt) {
|
||||||
|
DRV_LOG(DEBUG, "mp uninit primary");
|
||||||
|
mana_mp_uninit_primary();
|
||||||
|
}
|
||||||
|
|
||||||
|
rte_spinlock_unlock(&mana_shared_data->lock);
|
||||||
|
|
||||||
|
/* Also free the shared memory if this is the last */
|
||||||
|
if (!mana_shared_data->primary_cnt) {
|
||||||
|
DRV_LOG(DEBUG, "free shared memezone data");
|
||||||
|
rte_memzone_free(mana_shared_mz);
|
||||||
|
}
|
||||||
|
|
||||||
|
rte_spinlock_unlock(&mana_shared_data_lock);
|
||||||
|
} else {
|
||||||
|
rte_spinlock_lock(&mana_shared_data_lock);
|
||||||
|
|
||||||
|
rte_spinlock_lock(&mana_shared_data->lock);
|
||||||
|
RTE_VERIFY(mana_shared_data->secondary_cnt > 0);
|
||||||
|
mana_shared_data->secondary_cnt--;
|
||||||
|
rte_spinlock_unlock(&mana_shared_data->lock);
|
||||||
|
|
||||||
|
RTE_VERIFY(mana_local_data.secondary_cnt > 0);
|
||||||
|
mana_local_data.secondary_cnt--;
|
||||||
|
if (!mana_local_data.secondary_cnt) {
|
||||||
|
DRV_LOG(DEBUG, "mp uninit secondary");
|
||||||
|
mana_mp_uninit_secondary();
|
||||||
|
}
|
||||||
|
|
||||||
|
rte_spinlock_unlock(&mana_shared_data_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rte_eth_dev_pci_generic_remove(pci_dev, mana_dev_uninit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct rte_pci_id mana_pci_id_map[] = {
|
||||||
|
{
|
||||||
|
RTE_PCI_DEVICE(PCI_VENDOR_ID_MICROSOFT,
|
||||||
|
PCI_DEVICE_ID_MICROSOFT_MANA)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.vendor_id = 0
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct rte_pci_driver mana_pci_driver = {
|
||||||
|
.id_table = mana_pci_id_map,
|
||||||
|
.probe = mana_pci_probe,
|
||||||
|
.remove = mana_pci_remove,
|
||||||
|
.drv_flags = RTE_PCI_DRV_INTR_RMV,
|
||||||
|
};
|
||||||
|
|
||||||
|
RTE_PMD_REGISTER_PCI(net_mana, mana_pci_driver);
|
||||||
|
RTE_PMD_REGISTER_PCI_TABLE(net_mana, mana_pci_id_map);
|
||||||
|
RTE_PMD_REGISTER_KMOD_DEP(net_mana, "* ib_uverbs & mana_ib");
|
||||||
|
RTE_LOG_REGISTER_SUFFIX(mana_logtype_init, init, NOTICE);
|
||||||
|
RTE_LOG_REGISTER_SUFFIX(mana_logtype_driver, driver, NOTICE);
|
||||||
|
RTE_PMD_REGISTER_PARAM_STRING(net_mana, ETH_MANA_MAC_ARG "=<mac_addr>");
|
97
drivers/net/mana/mana.h
Normal file
97
drivers/net/mana/mana.h
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright 2022 Microsoft Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __MANA_H__
|
||||||
|
#define __MANA_H__
|
||||||
|
|
||||||
|
#define PCI_VENDOR_ID_MICROSOFT 0x1414
|
||||||
|
#define PCI_DEVICE_ID_MICROSOFT_MANA 0x00ba
|
||||||
|
|
||||||
|
/* Shared data between primary/secondary processes */
|
||||||
|
struct mana_shared_data {
|
||||||
|
rte_spinlock_t lock;
|
||||||
|
int init_done;
|
||||||
|
unsigned int primary_cnt;
|
||||||
|
unsigned int secondary_cnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mana_process_priv {
|
||||||
|
void *db_page;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mana_priv {
|
||||||
|
struct rte_eth_dev_data *dev_data;
|
||||||
|
struct mana_process_priv *process_priv;
|
||||||
|
|
||||||
|
/* DPDK port */
|
||||||
|
uint16_t port_id;
|
||||||
|
|
||||||
|
/* IB device port */
|
||||||
|
uint8_t dev_port;
|
||||||
|
|
||||||
|
struct ibv_context *ib_ctx;
|
||||||
|
struct ibv_pd *ib_pd;
|
||||||
|
struct ibv_pd *ib_parent_pd;
|
||||||
|
void *db_page;
|
||||||
|
int max_rx_queues;
|
||||||
|
int max_tx_queues;
|
||||||
|
int max_rx_desc;
|
||||||
|
int max_tx_desc;
|
||||||
|
int max_send_sge;
|
||||||
|
int max_recv_sge;
|
||||||
|
int max_mr;
|
||||||
|
uint64_t max_mr_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int mana_logtype_driver;
|
||||||
|
extern int mana_logtype_init;
|
||||||
|
|
||||||
|
#define DRV_LOG(level, fmt, args...) \
|
||||||
|
rte_log(RTE_LOG_ ## level, mana_logtype_driver, "%s(): " fmt "\n", \
|
||||||
|
__func__, ## args)
|
||||||
|
|
||||||
|
#define PMD_INIT_LOG(level, fmt, args...) \
|
||||||
|
rte_log(RTE_LOG_ ## level, mana_logtype_init, "%s(): " fmt "\n",\
|
||||||
|
__func__, ## args)
|
||||||
|
|
||||||
|
#define PMD_INIT_FUNC_TRACE() PMD_INIT_LOG(DEBUG, " >>")
|
||||||
|
|
||||||
|
uint16_t mana_rx_burst_removed(void *dpdk_rxq, struct rte_mbuf **pkts,
|
||||||
|
uint16_t pkts_n);
|
||||||
|
|
||||||
|
uint16_t mana_tx_burst_removed(void *dpdk_rxq, struct rte_mbuf **pkts,
|
||||||
|
uint16_t pkts_n);
|
||||||
|
|
||||||
|
/** Request timeout for IPC. */
|
||||||
|
#define MANA_MP_REQ_TIMEOUT_SEC 5
|
||||||
|
|
||||||
|
/* Request types for IPC. */
|
||||||
|
enum mana_mp_req_type {
|
||||||
|
MANA_MP_REQ_VERBS_CMD_FD = 1,
|
||||||
|
MANA_MP_REQ_CREATE_MR,
|
||||||
|
MANA_MP_REQ_START_RXTX,
|
||||||
|
MANA_MP_REQ_STOP_RXTX,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Pameters for IPC. */
|
||||||
|
struct mana_mp_param {
|
||||||
|
enum mana_mp_req_type type;
|
||||||
|
int port_id;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/* MANA_MP_REQ_CREATE_MR */
|
||||||
|
uintptr_t addr;
|
||||||
|
uint32_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MANA_MP_NAME "net_mana_mp"
|
||||||
|
int mana_mp_init_primary(void);
|
||||||
|
int mana_mp_init_secondary(void);
|
||||||
|
void mana_mp_uninit_primary(void);
|
||||||
|
void mana_mp_uninit_secondary(void);
|
||||||
|
int mana_mp_req_verbs_cmd_fd(struct rte_eth_dev *dev);
|
||||||
|
|
||||||
|
void mana_mp_req_on_rxtx(struct rte_eth_dev *dev, enum mana_mp_req_type type);
|
||||||
|
|
||||||
|
#endif
|
44
drivers/net/mana/meson.build
Normal file
44
drivers/net/mana/meson.build
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
# Copyright(c) 2022 Microsoft Corporation
|
||||||
|
|
||||||
|
if not is_linux or not dpdk_conf.has('RTE_ARCH_X86_64')
|
||||||
|
build = false
|
||||||
|
reason = 'mana is supported on Linux X86_64'
|
||||||
|
subdir_done()
|
||||||
|
endif
|
||||||
|
|
||||||
|
deps += ['pci', 'bus_pci', 'net', 'eal', 'kvargs']
|
||||||
|
|
||||||
|
sources += files(
|
||||||
|
'mana.c',
|
||||||
|
'mp.c',
|
||||||
|
)
|
||||||
|
|
||||||
|
libnames = ['ibverbs', 'mana' ]
|
||||||
|
foreach libname:libnames
|
||||||
|
lib = cc.find_library(libname, required:false)
|
||||||
|
if lib.found()
|
||||||
|
ext_deps += lib
|
||||||
|
else
|
||||||
|
build = false
|
||||||
|
reason = 'missing dependency, "' + libname + '"'
|
||||||
|
subdir_done()
|
||||||
|
endif
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
required_symbols = [
|
||||||
|
['infiniband/manadv.h', 'manadv_set_context_attr'],
|
||||||
|
['infiniband/manadv.h', 'manadv_init_obj'],
|
||||||
|
['infiniband/manadv.h', 'MANADV_CTX_ATTR_BUF_ALLOCATORS'],
|
||||||
|
['infiniband/manadv.h', 'MANADV_OBJ_QP'],
|
||||||
|
['infiniband/manadv.h', 'MANADV_OBJ_CQ'],
|
||||||
|
['infiniband/manadv.h', 'MANADV_OBJ_RWQ'],
|
||||||
|
]
|
||||||
|
|
||||||
|
foreach arg:required_symbols
|
||||||
|
if not cc.has_header_symbol(arg[0], arg[1])
|
||||||
|
build = false
|
||||||
|
reason = 'missing symbol "' + arg[1] + '" in "' + arg[0] + '"'
|
||||||
|
subdir_done()
|
||||||
|
endif
|
||||||
|
endforeach
|
241
drivers/net/mana/mp.c
Normal file
241
drivers/net/mana/mp.c
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright 2022 Microsoft Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <rte_malloc.h>
|
||||||
|
#include <ethdev_driver.h>
|
||||||
|
#include <rte_log.h>
|
||||||
|
|
||||||
|
#include <infiniband/verbs.h>
|
||||||
|
|
||||||
|
#include "mana.h"
|
||||||
|
|
||||||
|
extern struct mana_shared_data *mana_shared_data;
|
||||||
|
|
||||||
|
static void
|
||||||
|
mp_init_msg(struct rte_mp_msg *msg, enum mana_mp_req_type type, int port_id)
|
||||||
|
{
|
||||||
|
struct mana_mp_param *param;
|
||||||
|
|
||||||
|
strlcpy(msg->name, MANA_MP_NAME, sizeof(msg->name));
|
||||||
|
msg->len_param = sizeof(*param);
|
||||||
|
|
||||||
|
param = (struct mana_mp_param *)msg->param;
|
||||||
|
param->type = type;
|
||||||
|
param->port_id = port_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mana_mp_primary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
|
||||||
|
{
|
||||||
|
struct rte_eth_dev *dev;
|
||||||
|
const struct mana_mp_param *param =
|
||||||
|
(const struct mana_mp_param *)mp_msg->param;
|
||||||
|
struct rte_mp_msg mp_res = { 0 };
|
||||||
|
struct mana_mp_param *res = (struct mana_mp_param *)mp_res.param;
|
||||||
|
int ret;
|
||||||
|
struct mana_priv *priv;
|
||||||
|
|
||||||
|
if (!rte_eth_dev_is_valid_port(param->port_id)) {
|
||||||
|
DRV_LOG(ERR, "MP handle port ID %u invalid", param->port_id);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = &rte_eth_devices[param->port_id];
|
||||||
|
priv = dev->data->dev_private;
|
||||||
|
|
||||||
|
mp_init_msg(&mp_res, param->type, param->port_id);
|
||||||
|
|
||||||
|
switch (param->type) {
|
||||||
|
case MANA_MP_REQ_VERBS_CMD_FD:
|
||||||
|
mp_res.num_fds = 1;
|
||||||
|
mp_res.fds[0] = priv->ib_ctx->cmd_fd;
|
||||||
|
res->result = 0;
|
||||||
|
ret = rte_mp_reply(&mp_res, peer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DRV_LOG(ERR, "Port %u unknown primary MP type %u",
|
||||||
|
param->port_id, param->type);
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mana_mp_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
|
||||||
|
{
|
||||||
|
struct rte_mp_msg mp_res = { 0 };
|
||||||
|
struct mana_mp_param *res = (struct mana_mp_param *)mp_res.param;
|
||||||
|
const struct mana_mp_param *param =
|
||||||
|
(const struct mana_mp_param *)mp_msg->param;
|
||||||
|
struct rte_eth_dev *dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!rte_eth_dev_is_valid_port(param->port_id)) {
|
||||||
|
DRV_LOG(ERR, "MP handle port ID %u invalid", param->port_id);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = &rte_eth_devices[param->port_id];
|
||||||
|
|
||||||
|
mp_init_msg(&mp_res, param->type, param->port_id);
|
||||||
|
|
||||||
|
switch (param->type) {
|
||||||
|
case MANA_MP_REQ_START_RXTX:
|
||||||
|
DRV_LOG(INFO, "Port %u starting datapath", dev->data->port_id);
|
||||||
|
|
||||||
|
rte_mb();
|
||||||
|
|
||||||
|
res->result = 0;
|
||||||
|
ret = rte_mp_reply(&mp_res, peer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MANA_MP_REQ_STOP_RXTX:
|
||||||
|
DRV_LOG(INFO, "Port %u stopping datapath", dev->data->port_id);
|
||||||
|
|
||||||
|
dev->tx_pkt_burst = mana_tx_burst_removed;
|
||||||
|
dev->rx_pkt_burst = mana_rx_burst_removed;
|
||||||
|
|
||||||
|
rte_mb();
|
||||||
|
|
||||||
|
res->result = 0;
|
||||||
|
ret = rte_mp_reply(&mp_res, peer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DRV_LOG(ERR, "Port %u unknown secondary MP type %u",
|
||||||
|
param->port_id, param->type);
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mana_mp_init_primary(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = rte_mp_action_register(MANA_MP_NAME, mana_mp_primary_handle);
|
||||||
|
if (ret && rte_errno != ENOTSUP) {
|
||||||
|
DRV_LOG(ERR, "Failed to register primary handler %d %d",
|
||||||
|
ret, rte_errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mana_mp_uninit_primary(void)
|
||||||
|
{
|
||||||
|
rte_mp_action_unregister(MANA_MP_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mana_mp_init_secondary(void)
|
||||||
|
{
|
||||||
|
return rte_mp_action_register(MANA_MP_NAME, mana_mp_secondary_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mana_mp_uninit_secondary(void)
|
||||||
|
{
|
||||||
|
rte_mp_action_unregister(MANA_MP_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mana_mp_req_verbs_cmd_fd(struct rte_eth_dev *dev)
|
||||||
|
{
|
||||||
|
struct rte_mp_msg mp_req = { 0 };
|
||||||
|
struct rte_mp_msg *mp_res;
|
||||||
|
struct rte_mp_reply mp_rep;
|
||||||
|
struct mana_mp_param *res;
|
||||||
|
struct timespec ts = {.tv_sec = MANA_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mp_init_msg(&mp_req, MANA_MP_REQ_VERBS_CMD_FD, dev->data->port_id);
|
||||||
|
|
||||||
|
ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
|
||||||
|
if (ret) {
|
||||||
|
DRV_LOG(ERR, "port %u request to primary process failed",
|
||||||
|
dev->data->port_id);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mp_rep.nb_received != 1) {
|
||||||
|
DRV_LOG(ERR, "primary replied %u messages", mp_rep.nb_received);
|
||||||
|
ret = -EPROTO;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_res = &mp_rep.msgs[0];
|
||||||
|
res = (struct mana_mp_param *)mp_res->param;
|
||||||
|
if (res->result) {
|
||||||
|
DRV_LOG(ERR, "failed to get CMD FD, port %u",
|
||||||
|
dev->data->port_id);
|
||||||
|
ret = res->result;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mp_res->num_fds != 1) {
|
||||||
|
DRV_LOG(ERR, "got FDs %d unexpected", mp_res->num_fds);
|
||||||
|
ret = -EPROTO;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mp_res->fds[0];
|
||||||
|
DRV_LOG(ERR, "port %u command FD from primary is %d",
|
||||||
|
dev->data->port_id, ret);
|
||||||
|
exit:
|
||||||
|
free(mp_rep.msgs);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mana_mp_req_on_rxtx(struct rte_eth_dev *dev, enum mana_mp_req_type type)
|
||||||
|
{
|
||||||
|
struct rte_mp_msg mp_req = { 0 };
|
||||||
|
struct rte_mp_msg *mp_res;
|
||||||
|
struct rte_mp_reply mp_rep;
|
||||||
|
struct mana_mp_param *res;
|
||||||
|
struct timespec ts = {.tv_sec = MANA_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
if (type != MANA_MP_REQ_START_RXTX && type != MANA_MP_REQ_STOP_RXTX) {
|
||||||
|
DRV_LOG(ERR, "port %u unknown request (req_type %d)",
|
||||||
|
dev->data->port_id, type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mana_shared_data->secondary_cnt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mp_init_msg(&mp_req, type, dev->data->port_id);
|
||||||
|
|
||||||
|
ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
|
||||||
|
if (ret) {
|
||||||
|
if (rte_errno != ENOTSUP)
|
||||||
|
DRV_LOG(ERR, "port %u failed to request Rx/Tx (%d)",
|
||||||
|
dev->data->port_id, type);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (mp_rep.nb_sent != mp_rep.nb_received) {
|
||||||
|
DRV_LOG(ERR, "port %u not all secondaries responded (%d)",
|
||||||
|
dev->data->port_id, type);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
for (i = 0; i < mp_rep.nb_received; i++) {
|
||||||
|
mp_res = &mp_rep.msgs[i];
|
||||||
|
res = (struct mana_mp_param *)mp_res->param;
|
||||||
|
if (res->result) {
|
||||||
|
DRV_LOG(ERR, "port %u request failed on secondary %d",
|
||||||
|
dev->data->port_id, i);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit:
|
||||||
|
free(mp_rep.msgs);
|
||||||
|
}
|
3
drivers/net/mana/version.map
Normal file
3
drivers/net/mana/version.map
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
DPDK_23 {
|
||||||
|
local: *;
|
||||||
|
};
|
@ -34,6 +34,7 @@ drivers = [
|
|||||||
'ixgbe',
|
'ixgbe',
|
||||||
'kni',
|
'kni',
|
||||||
'liquidio',
|
'liquidio',
|
||||||
|
'mana',
|
||||||
'memif',
|
'memif',
|
||||||
'mlx4',
|
'mlx4',
|
||||||
'mlx5',
|
'mlx5',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user