2018-01-29 13:11:30 +00:00
|
|
|
/* SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
* Copyright 2015 6WIND S.A.
|
2018-03-20 19:20:35 +00:00
|
|
|
* Copyright 2015 Mellanox Technologies, Ltd
|
2015-10-30 18:52:30 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
2018-01-30 15:34:58 +00:00
|
|
|
#include <dlfcn.h>
|
2015-10-30 18:52:30 +00:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdlib.h>
|
2016-06-24 13:17:50 +00:00
|
|
|
#include <errno.h>
|
2015-10-30 18:52:30 +00:00
|
|
|
#include <net/if.h>
|
2018-01-25 15:00:24 +00:00
|
|
|
#include <sys/mman.h>
|
2018-04-05 15:07:19 +00:00
|
|
|
#include <linux/rtnetlink.h>
|
2015-10-30 18:52:30 +00:00
|
|
|
|
|
|
|
/* Verbs header. */
|
|
|
|
/* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
|
|
|
|
#ifdef PEDANTIC
|
2016-09-19 14:36:54 +00:00
|
|
|
#pragma GCC diagnostic ignored "-Wpedantic"
|
2015-10-30 18:52:30 +00:00
|
|
|
#endif
|
|
|
|
#include <infiniband/verbs.h>
|
|
|
|
#ifdef PEDANTIC
|
2016-09-19 14:36:54 +00:00
|
|
|
#pragma GCC diagnostic error "-Wpedantic"
|
2015-10-30 18:52:30 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <rte_malloc.h>
|
2018-01-22 00:16:22 +00:00
|
|
|
#include <rte_ethdev_driver.h>
|
2017-04-11 15:44:24 +00:00
|
|
|
#include <rte_ethdev_pci.h>
|
2015-10-30 18:52:30 +00:00
|
|
|
#include <rte_pci.h>
|
2017-10-26 10:06:08 +00:00
|
|
|
#include <rte_bus_pci.h>
|
2015-10-30 18:52:30 +00:00
|
|
|
#include <rte_common.h>
|
2018-01-30 15:34:58 +00:00
|
|
|
#include <rte_config.h>
|
2018-01-25 15:00:24 +00:00
|
|
|
#include <rte_eal_memconfig.h>
|
2016-06-24 13:17:50 +00:00
|
|
|
#include <rte_kvargs.h>
|
2018-05-24 14:36:49 +00:00
|
|
|
#include <rte_rwlock.h>
|
|
|
|
#include <rte_spinlock.h>
|
2015-10-30 18:52:30 +00:00
|
|
|
|
|
|
|
#include "mlx5.h"
|
|
|
|
#include "mlx5_utils.h"
|
2015-10-30 18:52:31 +00:00
|
|
|
#include "mlx5_rxtx.h"
|
2015-10-30 18:52:30 +00:00
|
|
|
#include "mlx5_autoconf.h"
|
2015-11-03 17:15:13 +00:00
|
|
|
#include "mlx5_defs.h"
|
2018-01-30 15:34:56 +00:00
|
|
|
#include "mlx5_glue.h"
|
net/mlx5: add new memory region support
This is the new design of Memory Region (MR) for mlx PMD, in order to:
- Accommodate the new memory hotplug model.
- Support non-contiguous Mempool.
There are multiple layers for MR search.
L0 is to look up the last-hit entry which is pointed by mr_ctrl->mru (Most
Recently Used). If L0 misses, L1 is to look up the address in a fixed-sized
array by linear search. L0/L1 is in an inline function -
mlx5_mr_lookup_cache().
If L1 misses, the bottom-half function is called to look up the address
from the bigger local cache of the queue. This is L2 - mlx5_mr_addr2mr_bh()
and it is not an inline function. Data structure for L2 is the Binary Tree.
If L2 misses, the search falls into the slowest path which takes locks in
order to access global device cache (priv->mr.cache) which is also a B-tree
and caches the original MR list (priv->mr.mr_list) of the device. Unless
the global cache is overflowed, it is all-inclusive of the MR list. This is
L3 - mlx5_mr_lookup_dev(). The size of the L3 cache table is limited and
can't be expanded on the fly due to deadlock. Refer to the comments in the
code for the details - mr_lookup_dev(). If L3 is overflowed, the list will
have to be searched directly bypassing the cache although it is slower.
If L3 misses, a new MR for the address should be created -
mlx5_mr_create(). When it creates a new MR, it tries to register adjacent
memsegs as much as possible which are virtually contiguous around the
address. This must take two locks - memory_hotplug_lock and
priv->mr.rwlock. Due to memory_hotplug_lock, there can't be any
allocation/free of memory inside.
In the free callback of the memory hotplug event, freed space is searched
from the MR list and corresponding bits are cleared from the bitmap of MRs.
This can fragment a MR and the MR will have multiple search entries in the
caches. Once there's a change by the event, the global cache must be
rebuilt and all the per-queue caches will be flushed as well. If memory is
frequently freed in run-time, that may cause jitter on dataplane processing
in the worst case by incurring MR cache flush and rebuild. But, it would be
the least probable scenario.
To guarantee the most optimal performance, it is highly recommended to use
an EAL option - '--socket-mem'. Then, the reserved memory will be pinned
and won't be freed dynamically. And it is also recommended to configure
per-lcore cache of Mempool. Even though there're many MRs for a device or
MRs are highly fragmented, the cache of Mempool will be much helpful to
reduce misses on per-queue caches anyway.
'--legacy-mem' is also supported.
Signed-off-by: Yongseok Koh <yskoh@mellanox.com>
2018-05-09 11:09:04 +00:00
|
|
|
#include "mlx5_mr.h"
|
2015-10-30 18:52:30 +00:00
|
|
|
|
2016-06-24 13:17:54 +00:00
|
|
|
/* Device parameter to enable RX completion queue compression. */
|
|
|
|
#define MLX5_RXQ_CQE_COMP_EN "rxq_cqe_comp_en"
|
|
|
|
|
2018-05-09 11:13:50 +00:00
|
|
|
/* Device parameter to enable Multi-Packet Rx queue. */
|
|
|
|
#define MLX5_RX_MPRQ_EN "mprq_en"
|
|
|
|
|
|
|
|
/* Device parameter to configure log 2 of the number of strides for MPRQ. */
|
|
|
|
#define MLX5_RX_MPRQ_LOG_STRIDE_NUM "mprq_log_stride_num"
|
|
|
|
|
|
|
|
/* Device parameter to limit the size of memcpy'd packet for MPRQ. */
|
|
|
|
#define MLX5_RX_MPRQ_MAX_MEMCPY_LEN "mprq_max_memcpy_len"
|
|
|
|
|
|
|
|
/* Device parameter to set the minimum number of Rx queues to enable MPRQ. */
|
|
|
|
#define MLX5_RXQS_MIN_MPRQ "rxqs_min_mprq"
|
|
|
|
|
2016-06-24 13:17:56 +00:00
|
|
|
/* Device parameter to configure inline send. */
|
|
|
|
#define MLX5_TXQ_INLINE "txq_inline"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Device parameter to configure the number of TX queues threshold for
|
|
|
|
* enabling inline send.
|
|
|
|
*/
|
|
|
|
#define MLX5_TXQS_MIN_INLINE "txqs_min_inline"
|
|
|
|
|
2016-06-24 13:17:57 +00:00
|
|
|
/* Device parameter to enable multi-packet send WQEs. */
|
|
|
|
#define MLX5_TXQ_MPW_EN "txq_mpw_en"
|
|
|
|
|
2017-03-15 23:55:44 +00:00
|
|
|
/* Device parameter to include 2 dsegs in the title WQEBB. */
|
|
|
|
#define MLX5_TXQ_MPW_HDR_DSEG_EN "txq_mpw_hdr_dseg_en"
|
|
|
|
|
|
|
|
/* Device parameter to limit the size of inlining packet. */
|
|
|
|
#define MLX5_TXQ_MAX_INLINE_LEN "txq_max_inline_len"
|
|
|
|
|
2017-08-02 15:32:56 +00:00
|
|
|
/* Device parameter to enable hardware Tx vector. */
|
|
|
|
#define MLX5_TX_VEC_EN "tx_vec_en"
|
|
|
|
|
|
|
|
/* Device parameter to enable hardware Rx vector. */
|
|
|
|
#define MLX5_RX_VEC_EN "rx_vec_en"
|
|
|
|
|
2018-04-23 12:33:02 +00:00
|
|
|
/* Allow L3 VXLAN flow creation. */
|
|
|
|
#define MLX5_L3_VXLAN_EN "l3_vxlan_en"
|
|
|
|
|
2018-04-05 15:07:21 +00:00
|
|
|
/* Activate Netlink support in VF mode. */
|
|
|
|
#define MLX5_VF_NL_EN "vf_nl_en"
|
|
|
|
|
2017-09-26 15:38:24 +00:00
|
|
|
#ifndef HAVE_IBV_MLX5_MOD_MPW
|
|
|
|
#define MLX5DV_CONTEXT_FLAGS_MPW_ALLOWED (1 << 2)
|
|
|
|
#define MLX5DV_CONTEXT_FLAGS_ENHANCED_MPW (1 << 3)
|
|
|
|
#endif
|
|
|
|
|
2017-10-09 18:46:59 +00:00
|
|
|
#ifndef HAVE_IBV_MLX5_MOD_CQE_128B_COMP
|
|
|
|
#define MLX5DV_CONTEXT_FLAGS_CQE_128B_COMP (1 << 4)
|
|
|
|
#endif
|
|
|
|
|
net/mlx5: add new memory region support
This is the new design of Memory Region (MR) for mlx PMD, in order to:
- Accommodate the new memory hotplug model.
- Support non-contiguous Mempool.
There are multiple layers for MR search.
L0 is to look up the last-hit entry which is pointed by mr_ctrl->mru (Most
Recently Used). If L0 misses, L1 is to look up the address in a fixed-sized
array by linear search. L0/L1 is in an inline function -
mlx5_mr_lookup_cache().
If L1 misses, the bottom-half function is called to look up the address
from the bigger local cache of the queue. This is L2 - mlx5_mr_addr2mr_bh()
and it is not an inline function. Data structure for L2 is the Binary Tree.
If L2 misses, the search falls into the slowest path which takes locks in
order to access global device cache (priv->mr.cache) which is also a B-tree
and caches the original MR list (priv->mr.mr_list) of the device. Unless
the global cache is overflowed, it is all-inclusive of the MR list. This is
L3 - mlx5_mr_lookup_dev(). The size of the L3 cache table is limited and
can't be expanded on the fly due to deadlock. Refer to the comments in the
code for the details - mr_lookup_dev(). If L3 is overflowed, the list will
have to be searched directly bypassing the cache although it is slower.
If L3 misses, a new MR for the address should be created -
mlx5_mr_create(). When it creates a new MR, it tries to register adjacent
memsegs as much as possible which are virtually contiguous around the
address. This must take two locks - memory_hotplug_lock and
priv->mr.rwlock. Due to memory_hotplug_lock, there can't be any
allocation/free of memory inside.
In the free callback of the memory hotplug event, freed space is searched
from the MR list and corresponding bits are cleared from the bitmap of MRs.
This can fragment a MR and the MR will have multiple search entries in the
caches. Once there's a change by the event, the global cache must be
rebuilt and all the per-queue caches will be flushed as well. If memory is
frequently freed in run-time, that may cause jitter on dataplane processing
in the worst case by incurring MR cache flush and rebuild. But, it would be
the least probable scenario.
To guarantee the most optimal performance, it is highly recommended to use
an EAL option - '--socket-mem'. Then, the reserved memory will be pinned
and won't be freed dynamically. And it is also recommended to configure
per-lcore cache of Mempool. Even though there're many MRs for a device or
MRs are highly fragmented, the cache of Mempool will be much helpful to
reduce misses on per-queue caches anyway.
'--legacy-mem' is also supported.
Signed-off-by: Yongseok Koh <yskoh@mellanox.com>
2018-05-09 11:09:04 +00:00
|
|
|
static const char *MZ_MLX5_PMD_SHARED_DATA = "mlx5_pmd_shared_data";
|
|
|
|
|
|
|
|
/* Shared memory between primary and secondary processes. */
|
|
|
|
struct mlx5_shared_data *mlx5_shared_data;
|
|
|
|
|
|
|
|
/* Spinlock for mlx5_shared_data allocation. */
|
|
|
|
static rte_spinlock_t mlx5_shared_data_lock = RTE_SPINLOCK_INITIALIZER;
|
|
|
|
|
2018-03-13 09:23:56 +00:00
|
|
|
/** Driver-specific log messages type. */
|
|
|
|
int mlx5_logtype;
|
|
|
|
|
net/mlx5: add new memory region support
This is the new design of Memory Region (MR) for mlx PMD, in order to:
- Accommodate the new memory hotplug model.
- Support non-contiguous Mempool.
There are multiple layers for MR search.
L0 is to look up the last-hit entry which is pointed by mr_ctrl->mru (Most
Recently Used). If L0 misses, L1 is to look up the address in a fixed-sized
array by linear search. L0/L1 is in an inline function -
mlx5_mr_lookup_cache().
If L1 misses, the bottom-half function is called to look up the address
from the bigger local cache of the queue. This is L2 - mlx5_mr_addr2mr_bh()
and it is not an inline function. Data structure for L2 is the Binary Tree.
If L2 misses, the search falls into the slowest path which takes locks in
order to access global device cache (priv->mr.cache) which is also a B-tree
and caches the original MR list (priv->mr.mr_list) of the device. Unless
the global cache is overflowed, it is all-inclusive of the MR list. This is
L3 - mlx5_mr_lookup_dev(). The size of the L3 cache table is limited and
can't be expanded on the fly due to deadlock. Refer to the comments in the
code for the details - mr_lookup_dev(). If L3 is overflowed, the list will
have to be searched directly bypassing the cache although it is slower.
If L3 misses, a new MR for the address should be created -
mlx5_mr_create(). When it creates a new MR, it tries to register adjacent
memsegs as much as possible which are virtually contiguous around the
address. This must take two locks - memory_hotplug_lock and
priv->mr.rwlock. Due to memory_hotplug_lock, there can't be any
allocation/free of memory inside.
In the free callback of the memory hotplug event, freed space is searched
from the MR list and corresponding bits are cleared from the bitmap of MRs.
This can fragment a MR and the MR will have multiple search entries in the
caches. Once there's a change by the event, the global cache must be
rebuilt and all the per-queue caches will be flushed as well. If memory is
frequently freed in run-time, that may cause jitter on dataplane processing
in the worst case by incurring MR cache flush and rebuild. But, it would be
the least probable scenario.
To guarantee the most optimal performance, it is highly recommended to use
an EAL option - '--socket-mem'. Then, the reserved memory will be pinned
and won't be freed dynamically. And it is also recommended to configure
per-lcore cache of Mempool. Even though there're many MRs for a device or
MRs are highly fragmented, the cache of Mempool will be much helpful to
reduce misses on per-queue caches anyway.
'--legacy-mem' is also supported.
Signed-off-by: Yongseok Koh <yskoh@mellanox.com>
2018-05-09 11:09:04 +00:00
|
|
|
/**
|
|
|
|
* Prepare shared data between primary and secondary process.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
mlx5_prepare_shared_data(void)
|
|
|
|
{
|
|
|
|
const struct rte_memzone *mz;
|
|
|
|
|
|
|
|
rte_spinlock_lock(&mlx5_shared_data_lock);
|
|
|
|
if (mlx5_shared_data == NULL) {
|
|
|
|
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
|
|
|
|
/* Allocate shared memory. */
|
|
|
|
mz = rte_memzone_reserve(MZ_MLX5_PMD_SHARED_DATA,
|
|
|
|
sizeof(*mlx5_shared_data),
|
|
|
|
SOCKET_ID_ANY, 0);
|
|
|
|
} else {
|
|
|
|
/* Lookup allocated shared memory. */
|
|
|
|
mz = rte_memzone_lookup(MZ_MLX5_PMD_SHARED_DATA);
|
|
|
|
}
|
|
|
|
if (mz == NULL)
|
|
|
|
rte_panic("Cannot allocate mlx5 shared data\n");
|
|
|
|
mlx5_shared_data = mz->addr;
|
|
|
|
/* Initialize shared data. */
|
|
|
|
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
|
|
|
|
LIST_INIT(&mlx5_shared_data->mem_event_cb_list);
|
|
|
|
rte_rwlock_init(&mlx5_shared_data->mem_event_rwlock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rte_spinlock_unlock(&mlx5_shared_data_lock);
|
|
|
|
}
|
|
|
|
|
2016-03-17 15:38:57 +00:00
|
|
|
/**
|
|
|
|
* Retrieve integer value from environment variable.
|
|
|
|
*
|
|
|
|
* @param[in] name
|
|
|
|
* Environment variable name.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* Integer value, 0 if the variable is not set.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
mlx5_getenv_int(const char *name)
|
|
|
|
{
|
|
|
|
const char *val = getenv(name);
|
|
|
|
|
|
|
|
if (val == NULL)
|
|
|
|
return 0;
|
|
|
|
return atoi(val);
|
|
|
|
}
|
|
|
|
|
2017-10-06 15:45:50 +00:00
|
|
|
/**
|
|
|
|
* Verbs callback to allocate a memory. This function should allocate the space
|
|
|
|
* according to the size provided residing inside a huge page.
|
|
|
|
* Please note that all allocation must respect the alignment from libmlx5
|
|
|
|
* (i.e. currently sysconf(_SC_PAGESIZE)).
|
|
|
|
*
|
|
|
|
* @param[in] size
|
|
|
|
* The size in bytes of the memory to allocate.
|
|
|
|
* @param[in] data
|
|
|
|
* A pointer to the callback data.
|
|
|
|
*
|
|
|
|
* @return
|
2018-03-05 12:21:06 +00:00
|
|
|
* Allocated buffer, NULL otherwise and rte_errno is set.
|
2017-10-06 15:45:50 +00:00
|
|
|
*/
|
|
|
|
static void *
|
|
|
|
mlx5_alloc_verbs_buf(size_t size, void *data)
|
|
|
|
{
|
|
|
|
struct priv *priv = data;
|
|
|
|
void *ret;
|
|
|
|
size_t alignment = sysconf(_SC_PAGESIZE);
|
2018-01-22 12:33:38 +00:00
|
|
|
unsigned int socket = SOCKET_ID_ANY;
|
2017-10-06 15:45:50 +00:00
|
|
|
|
2018-01-22 12:33:38 +00:00
|
|
|
if (priv->verbs_alloc_ctx.type == MLX5_VERBS_ALLOC_TYPE_TX_QUEUE) {
|
|
|
|
const struct mlx5_txq_ctrl *ctrl = priv->verbs_alloc_ctx.obj;
|
|
|
|
|
|
|
|
socket = ctrl->socket;
|
|
|
|
} else if (priv->verbs_alloc_ctx.type ==
|
|
|
|
MLX5_VERBS_ALLOC_TYPE_RX_QUEUE) {
|
|
|
|
const struct mlx5_rxq_ctrl *ctrl = priv->verbs_alloc_ctx.obj;
|
|
|
|
|
|
|
|
socket = ctrl->socket;
|
|
|
|
}
|
2017-10-06 15:45:50 +00:00
|
|
|
assert(data != NULL);
|
2018-01-22 12:33:38 +00:00
|
|
|
ret = rte_malloc_socket(__func__, size, alignment, socket);
|
2018-03-05 12:21:06 +00:00
|
|
|
if (!ret && size)
|
|
|
|
rte_errno = ENOMEM;
|
2017-10-06 15:45:50 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Verbs callback to free a memory.
|
|
|
|
*
|
|
|
|
* @param[in] ptr
|
|
|
|
* A pointer to the memory to free.
|
|
|
|
* @param[in] data
|
|
|
|
* A pointer to the callback data.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
mlx5_free_verbs_buf(void *ptr, void *data __rte_unused)
|
|
|
|
{
|
|
|
|
assert(data != NULL);
|
|
|
|
rte_free(ptr);
|
|
|
|
}
|
|
|
|
|
2015-10-30 18:52:30 +00:00
|
|
|
/**
|
|
|
|
* DPDK callback to close the device.
|
|
|
|
*
|
|
|
|
* Destroy all queues and objects, free memory.
|
|
|
|
*
|
|
|
|
* @param dev
|
|
|
|
* Pointer to Ethernet device structure.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
mlx5_dev_close(struct rte_eth_dev *dev)
|
|
|
|
{
|
2017-11-23 09:22:32 +00:00
|
|
|
struct priv *priv = dev->data->dev_private;
|
2015-10-30 18:52:31 +00:00
|
|
|
unsigned int i;
|
2017-10-09 14:44:42 +00:00
|
|
|
int ret;
|
2015-10-30 18:52:30 +00:00
|
|
|
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "port %u closing device \"%s\"",
|
|
|
|
dev->data->port_id,
|
|
|
|
((priv->ctx != NULL) ? priv->ctx->device->name : ""));
|
2015-10-30 18:55:06 +00:00
|
|
|
/* In case mlx5_dev_stop() has not been called. */
|
2018-03-05 12:21:04 +00:00
|
|
|
mlx5_dev_interrupt_handler_uninstall(dev);
|
|
|
|
mlx5_traffic_disable(dev);
|
2015-10-30 18:52:31 +00:00
|
|
|
/* Prevent crashes when queues are still in use. */
|
|
|
|
dev->rx_pkt_burst = removed_rx_burst;
|
|
|
|
dev->tx_pkt_burst = removed_tx_burst;
|
|
|
|
if (priv->rxqs != NULL) {
|
|
|
|
/* XXX race condition if mlx5_rx_burst() is still running. */
|
|
|
|
usleep(1000);
|
2017-10-09 14:44:49 +00:00
|
|
|
for (i = 0; (i != priv->rxqs_n); ++i)
|
2018-03-05 12:21:04 +00:00
|
|
|
mlx5_rxq_release(dev, i);
|
2015-10-30 18:52:31 +00:00
|
|
|
priv->rxqs_n = 0;
|
|
|
|
priv->rxqs = NULL;
|
|
|
|
}
|
|
|
|
if (priv->txqs != NULL) {
|
|
|
|
/* XXX race condition if mlx5_tx_burst() is still running. */
|
|
|
|
usleep(1000);
|
2017-10-09 14:44:48 +00:00
|
|
|
for (i = 0; (i != priv->txqs_n); ++i)
|
2018-03-05 12:21:04 +00:00
|
|
|
mlx5_txq_release(dev, i);
|
2015-10-30 18:52:31 +00:00
|
|
|
priv->txqs_n = 0;
|
|
|
|
priv->txqs = NULL;
|
|
|
|
}
|
2018-04-23 12:33:00 +00:00
|
|
|
mlx5_flow_delete_drop_queue(dev);
|
2018-05-09 11:13:50 +00:00
|
|
|
mlx5_mprq_free_mp(dev);
|
net/mlx5: add new memory region support
This is the new design of Memory Region (MR) for mlx PMD, in order to:
- Accommodate the new memory hotplug model.
- Support non-contiguous Mempool.
There are multiple layers for MR search.
L0 is to look up the last-hit entry which is pointed by mr_ctrl->mru (Most
Recently Used). If L0 misses, L1 is to look up the address in a fixed-sized
array by linear search. L0/L1 is in an inline function -
mlx5_mr_lookup_cache().
If L1 misses, the bottom-half function is called to look up the address
from the bigger local cache of the queue. This is L2 - mlx5_mr_addr2mr_bh()
and it is not an inline function. Data structure for L2 is the Binary Tree.
If L2 misses, the search falls into the slowest path which takes locks in
order to access global device cache (priv->mr.cache) which is also a B-tree
and caches the original MR list (priv->mr.mr_list) of the device. Unless
the global cache is overflowed, it is all-inclusive of the MR list. This is
L3 - mlx5_mr_lookup_dev(). The size of the L3 cache table is limited and
can't be expanded on the fly due to deadlock. Refer to the comments in the
code for the details - mr_lookup_dev(). If L3 is overflowed, the list will
have to be searched directly bypassing the cache although it is slower.
If L3 misses, a new MR for the address should be created -
mlx5_mr_create(). When it creates a new MR, it tries to register adjacent
memsegs as much as possible which are virtually contiguous around the
address. This must take two locks - memory_hotplug_lock and
priv->mr.rwlock. Due to memory_hotplug_lock, there can't be any
allocation/free of memory inside.
In the free callback of the memory hotplug event, freed space is searched
from the MR list and corresponding bits are cleared from the bitmap of MRs.
This can fragment a MR and the MR will have multiple search entries in the
caches. Once there's a change by the event, the global cache must be
rebuilt and all the per-queue caches will be flushed as well. If memory is
frequently freed in run-time, that may cause jitter on dataplane processing
in the worst case by incurring MR cache flush and rebuild. But, it would be
the least probable scenario.
To guarantee the most optimal performance, it is highly recommended to use
an EAL option - '--socket-mem'. Then, the reserved memory will be pinned
and won't be freed dynamically. And it is also recommended to configure
per-lcore cache of Mempool. Even though there're many MRs for a device or
MRs are highly fragmented, the cache of Mempool will be much helpful to
reduce misses on per-queue caches anyway.
'--legacy-mem' is also supported.
Signed-off-by: Yongseok Koh <yskoh@mellanox.com>
2018-05-09 11:09:04 +00:00
|
|
|
mlx5_mr_release(dev);
|
2015-10-30 18:52:30 +00:00
|
|
|
if (priv->pd != NULL) {
|
|
|
|
assert(priv->ctx != NULL);
|
2018-01-30 15:34:56 +00:00
|
|
|
claim_zero(mlx5_glue->dealloc_pd(priv->pd));
|
|
|
|
claim_zero(mlx5_glue->close_device(priv->ctx));
|
2015-10-30 18:52:30 +00:00
|
|
|
} else
|
|
|
|
assert(priv->ctx == NULL);
|
2017-10-09 14:44:56 +00:00
|
|
|
if (priv->rss_conf.rss_key != NULL)
|
|
|
|
rte_free(priv->rss_conf.rss_key);
|
2015-11-02 18:11:57 +00:00
|
|
|
if (priv->reta_idx != NULL)
|
|
|
|
rte_free(priv->reta_idx);
|
2018-02-06 12:54:22 +00:00
|
|
|
if (priv->primary_socket)
|
2018-03-05 12:21:04 +00:00
|
|
|
mlx5_socket_uninit(dev);
|
2018-04-05 15:07:19 +00:00
|
|
|
if (priv->config.vf)
|
|
|
|
mlx5_nl_mac_addr_flush(dev);
|
|
|
|
if (priv->nl_socket >= 0)
|
|
|
|
close(priv->nl_socket);
|
2018-03-05 12:21:04 +00:00
|
|
|
ret = mlx5_hrxq_ibv_verify(dev);
|
2017-10-09 14:44:51 +00:00
|
|
|
if (ret)
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(WARNING, "port %u some hash Rx queue still remain",
|
|
|
|
dev->data->port_id);
|
2018-03-05 12:21:04 +00:00
|
|
|
ret = mlx5_ind_table_ibv_verify(dev);
|
2017-10-09 14:44:50 +00:00
|
|
|
if (ret)
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(WARNING, "port %u some indirection table still remain",
|
|
|
|
dev->data->port_id);
|
2018-03-05 12:21:04 +00:00
|
|
|
ret = mlx5_rxq_ibv_verify(dev);
|
2017-10-09 14:44:46 +00:00
|
|
|
if (ret)
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(WARNING, "port %u some Verbs Rx queue still remain",
|
|
|
|
dev->data->port_id);
|
2018-03-05 12:21:04 +00:00
|
|
|
ret = mlx5_rxq_verify(dev);
|
2017-10-09 14:44:49 +00:00
|
|
|
if (ret)
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(WARNING, "port %u some Rx queues still remain",
|
|
|
|
dev->data->port_id);
|
2018-03-05 12:21:04 +00:00
|
|
|
ret = mlx5_txq_ibv_verify(dev);
|
2017-10-09 14:44:47 +00:00
|
|
|
if (ret)
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(WARNING, "port %u some Verbs Tx queue still remain",
|
|
|
|
dev->data->port_id);
|
2018-03-05 12:21:04 +00:00
|
|
|
ret = mlx5_txq_verify(dev);
|
2017-10-09 14:44:48 +00:00
|
|
|
if (ret)
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(WARNING, "port %u some Tx queues still remain",
|
|
|
|
dev->data->port_id);
|
2018-03-05 12:21:04 +00:00
|
|
|
ret = mlx5_flow_verify(dev);
|
2017-10-09 14:44:42 +00:00
|
|
|
if (ret)
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(WARNING, "port %u some flows still remain",
|
|
|
|
dev->data->port_id);
|
2015-10-30 18:52:30 +00:00
|
|
|
memset(priv, 0, sizeof(*priv));
|
|
|
|
}
|
|
|
|
|
2017-10-09 14:45:06 +00:00
|
|
|
const struct eth_dev_ops mlx5_dev_ops = {
|
2015-10-30 18:52:33 +00:00
|
|
|
.dev_configure = mlx5_dev_configure,
|
|
|
|
.dev_start = mlx5_dev_start,
|
|
|
|
.dev_stop = mlx5_dev_stop,
|
2016-03-17 15:38:54 +00:00
|
|
|
.dev_set_link_down = mlx5_set_link_down,
|
|
|
|
.dev_set_link_up = mlx5_set_link_up,
|
2015-10-30 18:52:30 +00:00
|
|
|
.dev_close = mlx5_dev_close,
|
2015-10-30 18:52:37 +00:00
|
|
|
.promiscuous_enable = mlx5_promiscuous_enable,
|
|
|
|
.promiscuous_disable = mlx5_promiscuous_disable,
|
|
|
|
.allmulticast_enable = mlx5_allmulticast_enable,
|
|
|
|
.allmulticast_disable = mlx5_allmulticast_disable,
|
2015-10-30 18:52:38 +00:00
|
|
|
.link_update = mlx5_link_update,
|
2015-10-30 18:52:36 +00:00
|
|
|
.stats_get = mlx5_stats_get,
|
|
|
|
.stats_reset = mlx5_stats_reset,
|
2017-01-17 14:37:08 +00:00
|
|
|
.xstats_get = mlx5_xstats_get,
|
|
|
|
.xstats_reset = mlx5_xstats_reset,
|
|
|
|
.xstats_get_names = mlx5_xstats_get_names,
|
2015-10-30 18:52:33 +00:00
|
|
|
.dev_infos_get = mlx5_dev_infos_get,
|
2016-03-14 20:50:50 +00:00
|
|
|
.dev_supported_ptypes_get = mlx5_dev_supported_ptypes_get,
|
2015-10-30 18:52:40 +00:00
|
|
|
.vlan_filter_set = mlx5_vlan_filter_set,
|
2015-10-30 18:52:31 +00:00
|
|
|
.rx_queue_setup = mlx5_rx_queue_setup,
|
|
|
|
.tx_queue_setup = mlx5_tx_queue_setup,
|
|
|
|
.rx_queue_release = mlx5_rx_queue_release,
|
|
|
|
.tx_queue_release = mlx5_tx_queue_release,
|
2015-10-30 18:52:39 +00:00
|
|
|
.flow_ctrl_get = mlx5_dev_get_flow_ctrl,
|
|
|
|
.flow_ctrl_set = mlx5_dev_set_flow_ctrl,
|
2015-10-30 18:52:32 +00:00
|
|
|
.mac_addr_remove = mlx5_mac_addr_remove,
|
|
|
|
.mac_addr_add = mlx5_mac_addr_add,
|
2016-01-05 18:00:09 +00:00
|
|
|
.mac_addr_set = mlx5_mac_addr_set,
|
2018-04-23 11:09:28 +00:00
|
|
|
.set_mc_addr_list = mlx5_set_mc_addr_list,
|
2015-10-30 18:52:35 +00:00
|
|
|
.mtu_set = mlx5_dev_set_mtu,
|
2016-03-03 14:26:44 +00:00
|
|
|
.vlan_strip_queue_set = mlx5_vlan_strip_queue_set,
|
|
|
|
.vlan_offload_set = mlx5_vlan_offload_set,
|
2015-11-02 18:11:57 +00:00
|
|
|
.reta_update = mlx5_dev_rss_reta_update,
|
|
|
|
.reta_query = mlx5_dev_rss_reta_query,
|
2015-10-30 18:55:11 +00:00
|
|
|
.rss_hash_update = mlx5_rss_hash_update,
|
|
|
|
.rss_hash_conf_get = mlx5_rss_hash_conf_get,
|
2016-03-03 14:26:43 +00:00
|
|
|
.filter_ctrl = mlx5_dev_filter_ctrl,
|
2017-03-29 08:36:32 +00:00
|
|
|
.rx_descriptor_status = mlx5_rx_descriptor_status,
|
|
|
|
.tx_descriptor_status = mlx5_tx_descriptor_status,
|
2017-03-14 13:03:09 +00:00
|
|
|
.rx_queue_intr_enable = mlx5_rx_intr_enable,
|
|
|
|
.rx_queue_intr_disable = mlx5_rx_intr_disable,
|
2018-01-20 21:12:21 +00:00
|
|
|
.is_removed = mlx5_is_removed,
|
2015-10-30 18:52:30 +00:00
|
|
|
};
|
|
|
|
|
2017-10-06 15:45:51 +00:00
|
|
|
static const struct eth_dev_ops mlx5_dev_sec_ops = {
|
|
|
|
.stats_get = mlx5_stats_get,
|
|
|
|
.stats_reset = mlx5_stats_reset,
|
|
|
|
.xstats_get = mlx5_xstats_get,
|
|
|
|
.xstats_reset = mlx5_xstats_reset,
|
|
|
|
.xstats_get_names = mlx5_xstats_get_names,
|
|
|
|
.dev_infos_get = mlx5_dev_infos_get,
|
|
|
|
.rx_descriptor_status = mlx5_rx_descriptor_status,
|
|
|
|
.tx_descriptor_status = mlx5_tx_descriptor_status,
|
|
|
|
};
|
|
|
|
|
2017-10-09 14:45:06 +00:00
|
|
|
/* Available operators in flow isolated mode. */
|
|
|
|
const struct eth_dev_ops mlx5_dev_ops_isolate = {
|
|
|
|
.dev_configure = mlx5_dev_configure,
|
|
|
|
.dev_start = mlx5_dev_start,
|
|
|
|
.dev_stop = mlx5_dev_stop,
|
|
|
|
.dev_set_link_down = mlx5_set_link_down,
|
|
|
|
.dev_set_link_up = mlx5_set_link_up,
|
|
|
|
.dev_close = mlx5_dev_close,
|
|
|
|
.link_update = mlx5_link_update,
|
|
|
|
.stats_get = mlx5_stats_get,
|
|
|
|
.stats_reset = mlx5_stats_reset,
|
|
|
|
.xstats_get = mlx5_xstats_get,
|
|
|
|
.xstats_reset = mlx5_xstats_reset,
|
|
|
|
.xstats_get_names = mlx5_xstats_get_names,
|
|
|
|
.dev_infos_get = mlx5_dev_infos_get,
|
|
|
|
.dev_supported_ptypes_get = mlx5_dev_supported_ptypes_get,
|
|
|
|
.vlan_filter_set = mlx5_vlan_filter_set,
|
|
|
|
.rx_queue_setup = mlx5_rx_queue_setup,
|
|
|
|
.tx_queue_setup = mlx5_tx_queue_setup,
|
|
|
|
.rx_queue_release = mlx5_rx_queue_release,
|
|
|
|
.tx_queue_release = mlx5_tx_queue_release,
|
|
|
|
.flow_ctrl_get = mlx5_dev_get_flow_ctrl,
|
|
|
|
.flow_ctrl_set = mlx5_dev_set_flow_ctrl,
|
|
|
|
.mac_addr_remove = mlx5_mac_addr_remove,
|
|
|
|
.mac_addr_add = mlx5_mac_addr_add,
|
|
|
|
.mac_addr_set = mlx5_mac_addr_set,
|
2018-04-23 11:09:28 +00:00
|
|
|
.set_mc_addr_list = mlx5_set_mc_addr_list,
|
2017-10-09 14:45:06 +00:00
|
|
|
.mtu_set = mlx5_dev_set_mtu,
|
|
|
|
.vlan_strip_queue_set = mlx5_vlan_strip_queue_set,
|
|
|
|
.vlan_offload_set = mlx5_vlan_offload_set,
|
|
|
|
.filter_ctrl = mlx5_dev_filter_ctrl,
|
|
|
|
.rx_descriptor_status = mlx5_rx_descriptor_status,
|
|
|
|
.tx_descriptor_status = mlx5_tx_descriptor_status,
|
|
|
|
.rx_queue_intr_enable = mlx5_rx_intr_enable,
|
|
|
|
.rx_queue_intr_disable = mlx5_rx_intr_disable,
|
2018-01-20 21:12:21 +00:00
|
|
|
.is_removed = mlx5_is_removed,
|
2017-10-09 14:45:06 +00:00
|
|
|
};
|
|
|
|
|
2015-10-30 18:52:30 +00:00
|
|
|
static struct {
|
|
|
|
struct rte_pci_addr pci_addr; /* associated PCI address */
|
|
|
|
uint32_t ports; /* physical ports bitfield. */
|
|
|
|
} mlx5_dev[32];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get device index in mlx5_dev[] from PCI bus address.
|
|
|
|
*
|
|
|
|
* @param[in] pci_addr
|
|
|
|
* PCI bus address to look for.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* mlx5_dev[] index on success, -1 on failure.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
mlx5_dev_idx(struct rte_pci_addr *pci_addr)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
assert(pci_addr != NULL);
|
|
|
|
for (i = 0; (i != RTE_DIM(mlx5_dev)); ++i) {
|
|
|
|
if ((mlx5_dev[i].pci_addr.domain == pci_addr->domain) &&
|
|
|
|
(mlx5_dev[i].pci_addr.bus == pci_addr->bus) &&
|
|
|
|
(mlx5_dev[i].pci_addr.devid == pci_addr->devid) &&
|
|
|
|
(mlx5_dev[i].pci_addr.function == pci_addr->function))
|
|
|
|
return i;
|
|
|
|
if ((mlx5_dev[i].ports == 0) && (ret == -1))
|
|
|
|
ret = i;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-06-24 13:17:50 +00:00
|
|
|
/**
|
|
|
|
* Verify and store value for device argument.
|
|
|
|
*
|
|
|
|
* @param[in] key
|
|
|
|
* Key argument to verify.
|
|
|
|
* @param[in] val
|
|
|
|
* Value associated with key.
|
|
|
|
* @param opaque
|
|
|
|
* User data.
|
|
|
|
*
|
|
|
|
* @return
|
2018-03-05 12:21:06 +00:00
|
|
|
* 0 on success, a negative errno value otherwise and rte_errno is set.
|
2016-06-24 13:17:50 +00:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
mlx5_args_check(const char *key, const char *val, void *opaque)
|
|
|
|
{
|
2018-01-10 09:16:58 +00:00
|
|
|
struct mlx5_dev_config *config = opaque;
|
2016-06-24 13:17:54 +00:00
|
|
|
unsigned long tmp;
|
2016-06-24 13:17:50 +00:00
|
|
|
|
2016-06-24 13:17:54 +00:00
|
|
|
errno = 0;
|
|
|
|
tmp = strtoul(val, NULL, 0);
|
|
|
|
if (errno) {
|
2018-03-05 12:21:06 +00:00
|
|
|
rte_errno = errno;
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(WARNING, "%s: \"%s\" is not a valid integer", key, val);
|
2018-03-05 12:21:06 +00:00
|
|
|
return -rte_errno;
|
2016-06-24 13:17:54 +00:00
|
|
|
}
|
|
|
|
if (strcmp(MLX5_RXQ_CQE_COMP_EN, key) == 0) {
|
2018-01-10 09:16:58 +00:00
|
|
|
config->cqe_comp = !!tmp;
|
2018-05-09 11:13:50 +00:00
|
|
|
} else if (strcmp(MLX5_RX_MPRQ_EN, key) == 0) {
|
|
|
|
config->mprq.enabled = !!tmp;
|
|
|
|
} else if (strcmp(MLX5_RX_MPRQ_LOG_STRIDE_NUM, key) == 0) {
|
|
|
|
config->mprq.stride_num_n = tmp;
|
|
|
|
} else if (strcmp(MLX5_RX_MPRQ_MAX_MEMCPY_LEN, key) == 0) {
|
|
|
|
config->mprq.max_memcpy_len = tmp;
|
|
|
|
} else if (strcmp(MLX5_RXQS_MIN_MPRQ, key) == 0) {
|
|
|
|
config->mprq.min_rxqs_num = tmp;
|
2016-06-24 13:17:56 +00:00
|
|
|
} else if (strcmp(MLX5_TXQ_INLINE, key) == 0) {
|
2018-01-10 09:16:58 +00:00
|
|
|
config->txq_inline = tmp;
|
2016-06-24 13:17:56 +00:00
|
|
|
} else if (strcmp(MLX5_TXQS_MIN_INLINE, key) == 0) {
|
2018-01-10 09:16:58 +00:00
|
|
|
config->txqs_inline = tmp;
|
2016-06-24 13:17:57 +00:00
|
|
|
} else if (strcmp(MLX5_TXQ_MPW_EN, key) == 0) {
|
2018-01-10 09:16:58 +00:00
|
|
|
config->mps = !!tmp ? config->mps : 0;
|
2017-03-15 23:55:44 +00:00
|
|
|
} else if (strcmp(MLX5_TXQ_MPW_HDR_DSEG_EN, key) == 0) {
|
2018-01-10 09:16:58 +00:00
|
|
|
config->mpw_hdr_dseg = !!tmp;
|
2017-03-15 23:55:44 +00:00
|
|
|
} else if (strcmp(MLX5_TXQ_MAX_INLINE_LEN, key) == 0) {
|
2018-01-10 09:16:58 +00:00
|
|
|
config->inline_max_packet_sz = tmp;
|
2017-08-02 15:32:56 +00:00
|
|
|
} else if (strcmp(MLX5_TX_VEC_EN, key) == 0) {
|
2018-01-10 09:16:58 +00:00
|
|
|
config->tx_vec_en = !!tmp;
|
2017-08-02 15:32:56 +00:00
|
|
|
} else if (strcmp(MLX5_RX_VEC_EN, key) == 0) {
|
2018-01-10 09:16:58 +00:00
|
|
|
config->rx_vec_en = !!tmp;
|
2018-04-23 12:33:02 +00:00
|
|
|
} else if (strcmp(MLX5_L3_VXLAN_EN, key) == 0) {
|
|
|
|
config->l3_vxlan_en = !!tmp;
|
2018-04-05 15:07:21 +00:00
|
|
|
} else if (strcmp(MLX5_VF_NL_EN, key) == 0) {
|
|
|
|
config->vf_nl_en = !!tmp;
|
2016-06-24 13:17:54 +00:00
|
|
|
} else {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(WARNING, "%s: unknown parameter", key);
|
2018-03-05 12:21:06 +00:00
|
|
|
rte_errno = EINVAL;
|
|
|
|
return -rte_errno;
|
2016-06-24 13:17:54 +00:00
|
|
|
}
|
|
|
|
return 0;
|
2016-06-24 13:17:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse device parameters.
|
|
|
|
*
|
2018-01-10 09:16:58 +00:00
|
|
|
* @param config
|
|
|
|
* Pointer to device configuration structure.
|
2016-06-24 13:17:50 +00:00
|
|
|
* @param devargs
|
|
|
|
* Device arguments structure.
|
|
|
|
*
|
|
|
|
* @return
|
2018-03-05 12:21:06 +00:00
|
|
|
* 0 on success, a negative errno value otherwise and rte_errno is set.
|
2016-06-24 13:17:50 +00:00
|
|
|
*/
|
|
|
|
static int
|
2018-01-10 09:16:58 +00:00
|
|
|
mlx5_args(struct mlx5_dev_config *config, struct rte_devargs *devargs)
|
2016-06-24 13:17:50 +00:00
|
|
|
{
|
|
|
|
const char **params = (const char *[]){
|
2016-06-24 13:17:54 +00:00
|
|
|
MLX5_RXQ_CQE_COMP_EN,
|
2018-05-09 11:13:50 +00:00
|
|
|
MLX5_RX_MPRQ_EN,
|
|
|
|
MLX5_RX_MPRQ_LOG_STRIDE_NUM,
|
|
|
|
MLX5_RX_MPRQ_MAX_MEMCPY_LEN,
|
|
|
|
MLX5_RXQS_MIN_MPRQ,
|
2016-06-24 13:17:56 +00:00
|
|
|
MLX5_TXQ_INLINE,
|
|
|
|
MLX5_TXQS_MIN_INLINE,
|
2016-06-24 13:17:57 +00:00
|
|
|
MLX5_TXQ_MPW_EN,
|
2017-03-15 23:55:44 +00:00
|
|
|
MLX5_TXQ_MPW_HDR_DSEG_EN,
|
|
|
|
MLX5_TXQ_MAX_INLINE_LEN,
|
2017-08-02 15:32:56 +00:00
|
|
|
MLX5_TX_VEC_EN,
|
|
|
|
MLX5_RX_VEC_EN,
|
2018-04-23 12:33:02 +00:00
|
|
|
MLX5_L3_VXLAN_EN,
|
2018-04-05 15:07:21 +00:00
|
|
|
MLX5_VF_NL_EN,
|
2016-06-24 13:17:50 +00:00
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
struct rte_kvargs *kvlist;
|
|
|
|
int ret = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (devargs == NULL)
|
|
|
|
return 0;
|
|
|
|
/* Following UGLY cast is done to pass checkpatch. */
|
|
|
|
kvlist = rte_kvargs_parse(devargs->args, params);
|
|
|
|
if (kvlist == NULL)
|
|
|
|
return 0;
|
|
|
|
/* Process parameters. */
|
|
|
|
for (i = 0; (params[i] != NULL); ++i) {
|
|
|
|
if (rte_kvargs_count(kvlist, params[i])) {
|
|
|
|
ret = rte_kvargs_process(kvlist, params[i],
|
2018-01-10 09:16:58 +00:00
|
|
|
mlx5_args_check, config);
|
2018-03-05 12:21:06 +00:00
|
|
|
if (ret) {
|
|
|
|
rte_errno = EINVAL;
|
2017-01-22 08:24:47 +00:00
|
|
|
rte_kvargs_free(kvlist);
|
2018-03-05 12:21:06 +00:00
|
|
|
return -rte_errno;
|
2017-01-22 08:24:47 +00:00
|
|
|
}
|
2016-06-24 13:17:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
rte_kvargs_free(kvlist);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-04-11 15:44:24 +00:00
|
|
|
static struct rte_pci_driver mlx5_driver;
|
2015-10-30 18:52:30 +00:00
|
|
|
|
2018-01-25 15:00:24 +00:00
|
|
|
/*
|
|
|
|
* Reserved UAR address space for TXQ UAR(hw doorbell) mapping, process
|
|
|
|
* local resource used by both primary and secondary to avoid duplicate
|
|
|
|
* reservation.
|
|
|
|
* The space has to be available on both primary and secondary process,
|
|
|
|
* TXQ UAR maps to this area using fixed mmap w/o double check.
|
|
|
|
*/
|
|
|
|
static void *uar_base;
|
|
|
|
|
2018-04-11 12:30:03 +00:00
|
|
|
static int
|
mem: replace memseg with memseg lists
Before, we were aggregating multiple pages into one memseg, so the
number of memsegs was small. Now, each page gets its own memseg,
so the list of memsegs is huge. To accommodate the new memseg list
size and to keep the under-the-hood workings sane, the memseg list
is now not just a single list, but multiple lists. To be precise,
each hugepage size available on the system gets one or more memseg
lists, per socket.
In order to support dynamic memory allocation, we reserve all
memory in advance (unless we're in 32-bit legacy mode, in which
case we do not preallocate memory). As in, we do an anonymous
mmap() of the entire maximum size of memory per hugepage size, per
socket (which is limited to either RTE_MAX_MEMSEG_PER_TYPE pages or
RTE_MAX_MEM_MB_PER_TYPE megabytes worth of memory, whichever is the
smaller one), split over multiple lists (which are limited to
either RTE_MAX_MEMSEG_PER_LIST memsegs or RTE_MAX_MEM_MB_PER_LIST
megabytes per list, whichever is the smaller one). There is also
a global limit of CONFIG_RTE_MAX_MEM_MB megabytes, which is mainly
used for 32-bit targets to limit amounts of preallocated memory,
but can be used to place an upper limit on total amount of VA
memory that can be allocated by DPDK application.
So, for each hugepage size, we get (by default) up to 128G worth
of memory, per socket, split into chunks of up to 32G in size.
The address space is claimed at the start, in eal_common_memory.c.
The actual page allocation code is in eal_memalloc.c (Linux-only),
and largely consists of copied EAL memory init code.
Pages in the list are also indexed by address. That is, in order
to figure out where the page belongs, one can simply look at base
address for a memseg list. Similarly, figuring out IOVA address
of a memzone is a matter of finding the right memseg list, getting
offset and dividing by page size to get the appropriate memseg.
This commit also removes rte_eal_dump_physmem_layout() call,
according to deprecation notice [1], and removes that deprecation
notice as well.
On 32-bit targets due to limited VA space, DPDK will no longer
spread memory to different sockets like before. Instead, it will
(by default) allocate all of the memory on socket where master
lcore is. To override this behavior, --socket-mem must be used.
The rest of the changes are really ripple effects from the memseg
change - heap changes, compile fixes, and rewrites to support
fbarray-backed memseg lists. Due to earlier switch to _walk()
functions, most of the changes are simple fixes, however some
of the _walk() calls were switched to memseg list walk, where
it made sense to do so.
Additionally, we are also switching locks from flock() to fcntl().
Down the line, we will be introducing single-file segments option,
and we cannot use flock() locks to lock parts of the file. Therefore,
we will use fcntl() locks for legacy mem as well, in case someone is
unfortunate enough to accidentally start legacy mem primary process
alongside an already working non-legacy mem-based primary process.
[1] http://dpdk.org/dev/patchwork/patch/34002/
Signed-off-by: Anatoly Burakov <anatoly.burakov@intel.com>
Tested-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
Tested-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Tested-by: Gowrishankar Muthukrishnan <gowrishankar.m@linux.vnet.ibm.com>
2018-04-11 12:30:24 +00:00
|
|
|
find_lower_va_bound(const struct rte_memseg_list *msl __rte_unused,
|
|
|
|
const struct rte_memseg *ms, void *arg)
|
2018-04-11 12:30:03 +00:00
|
|
|
{
|
|
|
|
void **addr = arg;
|
|
|
|
|
|
|
|
if (*addr == NULL)
|
|
|
|
*addr = ms->addr;
|
|
|
|
else
|
|
|
|
*addr = RTE_MIN(*addr, ms->addr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-01-25 15:00:24 +00:00
|
|
|
/**
|
|
|
|
* Reserve UAR address space for primary process.
|
|
|
|
*
|
2018-03-05 12:21:04 +00:00
|
|
|
* @param[in] dev
|
|
|
|
* Pointer to Ethernet device.
|
2018-01-25 15:00:24 +00:00
|
|
|
*
|
|
|
|
* @return
|
2018-03-05 12:21:06 +00:00
|
|
|
* 0 on success, a negative errno value otherwise and rte_errno is set.
|
2018-01-25 15:00:24 +00:00
|
|
|
*/
|
|
|
|
static int
|
2018-03-05 12:21:04 +00:00
|
|
|
mlx5_uar_init_primary(struct rte_eth_dev *dev)
|
2018-01-25 15:00:24 +00:00
|
|
|
{
|
2018-03-05 12:21:04 +00:00
|
|
|
struct priv *priv = dev->data->dev_private;
|
2018-01-25 15:00:24 +00:00
|
|
|
void *addr = (void *)0;
|
|
|
|
|
|
|
|
if (uar_base) { /* UAR address space mapped. */
|
|
|
|
priv->uar_base = uar_base;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* find out lower bound of hugepage segments */
|
2018-04-11 12:30:03 +00:00
|
|
|
rte_memseg_walk(find_lower_va_bound, &addr);
|
|
|
|
|
2018-01-25 15:00:24 +00:00
|
|
|
/* keep distance to hugepages to minimize potential conflicts. */
|
|
|
|
addr = RTE_PTR_SUB(addr, MLX5_UAR_OFFSET + MLX5_UAR_SIZE);
|
|
|
|
/* anonymous mmap, no real memory consumption. */
|
|
|
|
addr = mmap(addr, MLX5_UAR_SIZE,
|
|
|
|
PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
|
|
if (addr == MAP_FAILED) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR,
|
|
|
|
"port %u failed to reserve UAR address space, please"
|
|
|
|
" adjust MLX5_UAR_SIZE or try --base-virtaddr",
|
|
|
|
dev->data->port_id);
|
2018-03-05 12:21:06 +00:00
|
|
|
rte_errno = ENOMEM;
|
|
|
|
return -rte_errno;
|
2018-01-25 15:00:24 +00:00
|
|
|
}
|
|
|
|
/* Accept either same addr or a new addr returned from mmap if target
|
|
|
|
* range occupied.
|
|
|
|
*/
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(INFO, "port %u reserved UAR address space: %p",
|
|
|
|
dev->data->port_id, addr);
|
2018-01-25 15:00:24 +00:00
|
|
|
priv->uar_base = addr; /* for primary and secondary UAR re-mmap. */
|
|
|
|
uar_base = addr; /* process local, don't reserve again. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reserve UAR address space for secondary process, align with
|
|
|
|
* primary process.
|
|
|
|
*
|
2018-03-05 12:21:04 +00:00
|
|
|
* @param[in] dev
|
|
|
|
* Pointer to Ethernet device.
|
2018-01-25 15:00:24 +00:00
|
|
|
*
|
|
|
|
* @return
|
2018-03-05 12:21:06 +00:00
|
|
|
* 0 on success, a negative errno value otherwise and rte_errno is set.
|
2018-01-25 15:00:24 +00:00
|
|
|
*/
|
|
|
|
static int
|
2018-03-05 12:21:04 +00:00
|
|
|
mlx5_uar_init_secondary(struct rte_eth_dev *dev)
|
2018-01-25 15:00:24 +00:00
|
|
|
{
|
2018-03-05 12:21:04 +00:00
|
|
|
struct priv *priv = dev->data->dev_private;
|
2018-01-25 15:00:24 +00:00
|
|
|
void *addr;
|
|
|
|
|
|
|
|
assert(priv->uar_base);
|
|
|
|
if (uar_base) { /* already reserved. */
|
|
|
|
assert(uar_base == priv->uar_base);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* anonymous mmap, no real memory consumption. */
|
|
|
|
addr = mmap(priv->uar_base, MLX5_UAR_SIZE,
|
|
|
|
PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
|
|
if (addr == MAP_FAILED) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR, "port %u UAR mmap failed: %p size: %llu",
|
|
|
|
dev->data->port_id, priv->uar_base, MLX5_UAR_SIZE);
|
2018-03-05 12:21:06 +00:00
|
|
|
rte_errno = ENXIO;
|
|
|
|
return -rte_errno;
|
2018-01-25 15:00:24 +00:00
|
|
|
}
|
|
|
|
if (priv->uar_base != addr) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR,
|
|
|
|
"port %u UAR address %p size %llu occupied, please"
|
|
|
|
" adjust MLX5_UAR_OFFSET or try EAL parameter"
|
|
|
|
" --base-virtaddr",
|
|
|
|
dev->data->port_id, priv->uar_base, MLX5_UAR_SIZE);
|
2018-03-05 12:21:06 +00:00
|
|
|
rte_errno = ENXIO;
|
|
|
|
return -rte_errno;
|
2018-01-25 15:00:24 +00:00
|
|
|
}
|
|
|
|
uar_base = addr; /* process local, don't reserve again */
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(INFO, "port %u reserved UAR address space: %p",
|
|
|
|
dev->data->port_id, addr);
|
2018-01-25 15:00:24 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-30 18:52:30 +00:00
|
|
|
/**
|
|
|
|
* DPDK callback to register a PCI device.
|
|
|
|
*
|
|
|
|
* This function creates an Ethernet device for each port of a given
|
|
|
|
* PCI device.
|
|
|
|
*
|
|
|
|
* @param[in] pci_drv
|
|
|
|
* PCI driver structure (mlx5_driver).
|
|
|
|
* @param[in] pci_dev
|
|
|
|
* PCI device information.
|
|
|
|
*
|
|
|
|
* @return
|
2018-03-05 12:21:06 +00:00
|
|
|
* 0 on success, a negative errno value otherwise and rte_errno is set.
|
2015-10-30 18:52:30 +00:00
|
|
|
*/
|
|
|
|
static int
|
2018-03-05 12:20:59 +00:00
|
|
|
mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
|
|
|
|
struct rte_pci_device *pci_dev)
|
2015-10-30 18:52:30 +00:00
|
|
|
{
|
2018-03-05 12:21:06 +00:00
|
|
|
struct ibv_device **list = NULL;
|
2015-10-30 18:52:30 +00:00
|
|
|
struct ibv_device *ibv_dev;
|
|
|
|
int err = 0;
|
|
|
|
struct ibv_context *attr_ctx = NULL;
|
2017-09-26 15:38:24 +00:00
|
|
|
struct ibv_device_attr_ex device_attr;
|
2018-05-14 05:04:38 +00:00
|
|
|
unsigned int vf = 0;
|
2016-03-17 15:38:58 +00:00
|
|
|
unsigned int mps;
|
2017-10-09 18:46:59 +00:00
|
|
|
unsigned int cqe_comp;
|
2017-09-04 11:43:51 +00:00
|
|
|
unsigned int tunnel_en = 0;
|
2018-05-15 11:07:14 +00:00
|
|
|
unsigned int mpls_en = 0;
|
2018-04-08 12:41:20 +00:00
|
|
|
unsigned int swp = 0;
|
2018-04-23 12:33:00 +00:00
|
|
|
unsigned int verb_priorities = 0;
|
2018-05-09 11:13:50 +00:00
|
|
|
unsigned int mprq = 0;
|
|
|
|
unsigned int mprq_min_stride_size_n = 0;
|
|
|
|
unsigned int mprq_max_stride_size_n = 0;
|
|
|
|
unsigned int mprq_min_stride_num_n = 0;
|
|
|
|
unsigned int mprq_max_stride_num_n = 0;
|
2015-10-30 18:52:30 +00:00
|
|
|
int idx;
|
|
|
|
int i;
|
2018-02-25 07:28:37 +00:00
|
|
|
struct mlx5dv_context attrs_out = {0};
|
2017-10-10 14:22:54 +00:00
|
|
|
#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
|
|
|
|
struct ibv_counter_set_description cs_desc;
|
|
|
|
#endif
|
2015-10-30 18:52:30 +00:00
|
|
|
|
net/mlx5: add new memory region support
This is the new design of Memory Region (MR) for mlx PMD, in order to:
- Accommodate the new memory hotplug model.
- Support non-contiguous Mempool.
There are multiple layers for MR search.
L0 is to look up the last-hit entry which is pointed by mr_ctrl->mru (Most
Recently Used). If L0 misses, L1 is to look up the address in a fixed-sized
array by linear search. L0/L1 is in an inline function -
mlx5_mr_lookup_cache().
If L1 misses, the bottom-half function is called to look up the address
from the bigger local cache of the queue. This is L2 - mlx5_mr_addr2mr_bh()
and it is not an inline function. Data structure for L2 is the Binary Tree.
If L2 misses, the search falls into the slowest path which takes locks in
order to access global device cache (priv->mr.cache) which is also a B-tree
and caches the original MR list (priv->mr.mr_list) of the device. Unless
the global cache is overflowed, it is all-inclusive of the MR list. This is
L3 - mlx5_mr_lookup_dev(). The size of the L3 cache table is limited and
can't be expanded on the fly due to deadlock. Refer to the comments in the
code for the details - mr_lookup_dev(). If L3 is overflowed, the list will
have to be searched directly bypassing the cache although it is slower.
If L3 misses, a new MR for the address should be created -
mlx5_mr_create(). When it creates a new MR, it tries to register adjacent
memsegs as much as possible which are virtually contiguous around the
address. This must take two locks - memory_hotplug_lock and
priv->mr.rwlock. Due to memory_hotplug_lock, there can't be any
allocation/free of memory inside.
In the free callback of the memory hotplug event, freed space is searched
from the MR list and corresponding bits are cleared from the bitmap of MRs.
This can fragment a MR and the MR will have multiple search entries in the
caches. Once there's a change by the event, the global cache must be
rebuilt and all the per-queue caches will be flushed as well. If memory is
frequently freed in run-time, that may cause jitter on dataplane processing
in the worst case by incurring MR cache flush and rebuild. But, it would be
the least probable scenario.
To guarantee the most optimal performance, it is highly recommended to use
an EAL option - '--socket-mem'. Then, the reserved memory will be pinned
and won't be freed dynamically. And it is also recommended to configure
per-lcore cache of Mempool. Even though there're many MRs for a device or
MRs are highly fragmented, the cache of Mempool will be much helpful to
reduce misses on per-queue caches anyway.
'--legacy-mem' is also supported.
Signed-off-by: Yongseok Koh <yskoh@mellanox.com>
2018-05-09 11:09:04 +00:00
|
|
|
/* Prepare shared data between primary and secondary process. */
|
|
|
|
mlx5_prepare_shared_data();
|
2017-04-11 15:44:24 +00:00
|
|
|
assert(pci_drv == &mlx5_driver);
|
2015-10-30 18:52:30 +00:00
|
|
|
/* Get mlx5_dev[] index. */
|
|
|
|
idx = mlx5_dev_idx(&pci_dev->addr);
|
|
|
|
if (idx == -1) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR, "this driver cannot support any more adapters");
|
2018-03-05 12:21:06 +00:00
|
|
|
err = ENOMEM;
|
|
|
|
goto error;
|
2015-10-30 18:52:30 +00:00
|
|
|
}
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "using driver device index %d", idx);
|
2015-10-30 18:52:30 +00:00
|
|
|
/* Save PCI address. */
|
|
|
|
mlx5_dev[idx].pci_addr = pci_dev->addr;
|
2018-01-30 15:34:56 +00:00
|
|
|
list = mlx5_glue->get_device_list(&i);
|
2015-10-30 18:52:30 +00:00
|
|
|
if (list == NULL) {
|
|
|
|
assert(errno);
|
2018-03-05 12:21:06 +00:00
|
|
|
err = errno;
|
2017-03-28 14:13:12 +00:00
|
|
|
if (errno == ENOSYS)
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR,
|
|
|
|
"cannot list devices, is ib_uverbs loaded?");
|
2018-03-05 12:21:06 +00:00
|
|
|
goto error;
|
2015-10-30 18:52:30 +00:00
|
|
|
}
|
|
|
|
assert(i >= 0);
|
|
|
|
/*
|
|
|
|
* For each listed device, check related sysfs entry against
|
|
|
|
* the provided PCI ID.
|
|
|
|
*/
|
|
|
|
while (i != 0) {
|
|
|
|
struct rte_pci_addr pci_addr;
|
|
|
|
|
|
|
|
--i;
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "checking device \"%s\"", list[i]->name);
|
2015-10-30 18:52:30 +00:00
|
|
|
if (mlx5_ibv_device_to_pci_addr(list[i], &pci_addr))
|
|
|
|
continue;
|
|
|
|
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;
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(INFO, "PCI information matches, using device \"%s\"",
|
|
|
|
list[i]->name);
|
2018-04-05 15:07:19 +00:00
|
|
|
vf = ((pci_dev->id.device_id ==
|
|
|
|
PCI_DEVICE_ID_MELLANOX_CONNECTX4VF) ||
|
|
|
|
(pci_dev->id.device_id ==
|
|
|
|
PCI_DEVICE_ID_MELLANOX_CONNECTX4LXVF) ||
|
|
|
|
(pci_dev->id.device_id ==
|
|
|
|
PCI_DEVICE_ID_MELLANOX_CONNECTX5VF) ||
|
|
|
|
(pci_dev->id.device_id ==
|
|
|
|
PCI_DEVICE_ID_MELLANOX_CONNECTX5EXVF));
|
2018-01-30 15:34:56 +00:00
|
|
|
attr_ctx = mlx5_glue->open_device(list[i]);
|
2018-03-05 12:21:06 +00:00
|
|
|
rte_errno = errno;
|
|
|
|
err = rte_errno;
|
2015-10-30 18:52:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (attr_ctx == NULL) {
|
|
|
|
switch (err) {
|
|
|
|
case 0:
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR,
|
|
|
|
"cannot access device, is mlx5_ib loaded?");
|
2018-03-05 12:21:06 +00:00
|
|
|
err = ENODEV;
|
2018-05-08 09:11:26 +00:00
|
|
|
break;
|
2015-10-30 18:52:30 +00:00
|
|
|
case EINVAL:
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR,
|
|
|
|
"cannot use device, are drivers up to date?");
|
2018-05-08 09:11:26 +00:00
|
|
|
break;
|
2015-10-30 18:52:30 +00:00
|
|
|
}
|
2018-05-08 09:11:26 +00:00
|
|
|
goto error;
|
2015-10-30 18:52:30 +00:00
|
|
|
}
|
|
|
|
ibv_dev = list[i];
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "device opened");
|
2018-04-08 12:41:20 +00:00
|
|
|
#ifdef HAVE_IBV_MLX5_MOD_SWP
|
|
|
|
attrs_out.comp_mask |= MLX5DV_CONTEXT_MASK_SWP;
|
|
|
|
#endif
|
2017-09-26 15:38:24 +00:00
|
|
|
/*
|
|
|
|
* Multi-packet send is supported by ConnectX-4 Lx PF as well
|
|
|
|
* as all ConnectX-5 devices.
|
|
|
|
*/
|
2018-02-25 07:28:37 +00:00
|
|
|
#ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT
|
|
|
|
attrs_out.comp_mask |= MLX5DV_CONTEXT_MASK_TUNNEL_OFFLOADS;
|
2018-05-09 11:13:50 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_IBV_DEVICE_STRIDING_RQ_SUPPORT
|
|
|
|
attrs_out.comp_mask |= MLX5DV_CONTEXT_MASK_STRIDING_RQ;
|
2018-02-25 07:28:37 +00:00
|
|
|
#endif
|
2018-01-30 15:34:56 +00:00
|
|
|
mlx5_glue->dv_query_device(attr_ctx, &attrs_out);
|
2017-10-16 17:41:56 +00:00
|
|
|
if (attrs_out.flags & MLX5DV_CONTEXT_FLAGS_MPW_ALLOWED) {
|
|
|
|
if (attrs_out.flags & MLX5DV_CONTEXT_FLAGS_ENHANCED_MPW) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "enhanced MPW is supported");
|
2017-10-16 17:41:56 +00:00
|
|
|
mps = MLX5_MPW_ENHANCED;
|
|
|
|
} else {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "MPW is supported");
|
2017-10-16 17:41:56 +00:00
|
|
|
mps = MLX5_MPW;
|
|
|
|
}
|
2017-09-26 15:38:24 +00:00
|
|
|
} else {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "MPW isn't supported");
|
2017-09-26 15:38:24 +00:00
|
|
|
mps = MLX5_MPW_DISABLED;
|
|
|
|
}
|
2018-04-08 12:41:20 +00:00
|
|
|
#ifdef HAVE_IBV_MLX5_MOD_SWP
|
2018-05-09 00:14:50 +00:00
|
|
|
if (attrs_out.comp_mask & MLX5DV_CONTEXT_MASK_SWP)
|
2018-04-08 12:41:20 +00:00
|
|
|
swp = attrs_out.sw_parsing_caps.sw_parsing_offloads;
|
|
|
|
DRV_LOG(DEBUG, "SWP support: %u", swp);
|
2018-05-09 11:13:50 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_IBV_DEVICE_STRIDING_RQ_SUPPORT
|
|
|
|
if (attrs_out.comp_mask & MLX5DV_CONTEXT_MASK_STRIDING_RQ) {
|
|
|
|
struct mlx5dv_striding_rq_caps mprq_caps =
|
|
|
|
attrs_out.striding_rq_caps;
|
|
|
|
|
|
|
|
DRV_LOG(DEBUG, "\tmin_single_stride_log_num_of_bytes: %d",
|
|
|
|
mprq_caps.min_single_stride_log_num_of_bytes);
|
|
|
|
DRV_LOG(DEBUG, "\tmax_single_stride_log_num_of_bytes: %d",
|
|
|
|
mprq_caps.max_single_stride_log_num_of_bytes);
|
|
|
|
DRV_LOG(DEBUG, "\tmin_single_wqe_log_num_of_strides: %d",
|
|
|
|
mprq_caps.min_single_wqe_log_num_of_strides);
|
|
|
|
DRV_LOG(DEBUG, "\tmax_single_wqe_log_num_of_strides: %d",
|
|
|
|
mprq_caps.max_single_wqe_log_num_of_strides);
|
|
|
|
DRV_LOG(DEBUG, "\tsupported_qpts: %d",
|
|
|
|
mprq_caps.supported_qpts);
|
|
|
|
DRV_LOG(DEBUG, "device supports Multi-Packet RQ");
|
|
|
|
mprq = 1;
|
|
|
|
mprq_min_stride_size_n =
|
|
|
|
mprq_caps.min_single_stride_log_num_of_bytes;
|
|
|
|
mprq_max_stride_size_n =
|
|
|
|
mprq_caps.max_single_stride_log_num_of_bytes;
|
|
|
|
mprq_min_stride_num_n =
|
|
|
|
mprq_caps.min_single_wqe_log_num_of_strides;
|
|
|
|
mprq_max_stride_num_n =
|
|
|
|
mprq_caps.max_single_wqe_log_num_of_strides;
|
|
|
|
}
|
2018-04-08 12:41:20 +00:00
|
|
|
#endif
|
2017-10-09 18:46:59 +00:00
|
|
|
if (RTE_CACHE_LINE_SIZE == 128 &&
|
|
|
|
!(attrs_out.flags & MLX5DV_CONTEXT_FLAGS_CQE_128B_COMP))
|
|
|
|
cqe_comp = 0;
|
|
|
|
else
|
|
|
|
cqe_comp = 1;
|
2018-02-25 07:28:37 +00:00
|
|
|
#ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT
|
|
|
|
if (attrs_out.comp_mask & MLX5DV_CONTEXT_MASK_TUNNEL_OFFLOADS) {
|
|
|
|
tunnel_en = ((attrs_out.tunnel_offloads_caps &
|
|
|
|
MLX5DV_RAW_PACKET_CAP_TUNNELED_OFFLOAD_VXLAN) &&
|
|
|
|
(attrs_out.tunnel_offloads_caps &
|
|
|
|
MLX5DV_RAW_PACKET_CAP_TUNNELED_OFFLOAD_GRE));
|
|
|
|
}
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "tunnel offloading is %ssupported",
|
|
|
|
tunnel_en ? "" : "not ");
|
2018-02-25 07:28:37 +00:00
|
|
|
#else
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(WARNING,
|
|
|
|
"tunnel offloading disabled due to old OFED/rdma-core version");
|
2018-05-15 11:07:14 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT
|
|
|
|
mpls_en = ((attrs_out.tunnel_offloads_caps &
|
|
|
|
MLX5DV_RAW_PACKET_CAP_TUNNELED_OFFLOAD_CW_MPLS_OVER_GRE) &&
|
|
|
|
(attrs_out.tunnel_offloads_caps &
|
|
|
|
MLX5DV_RAW_PACKET_CAP_TUNNELED_OFFLOAD_CW_MPLS_OVER_UDP));
|
|
|
|
DRV_LOG(DEBUG, "MPLS over GRE/UDP tunnel offloading is %ssupported",
|
|
|
|
mpls_en ? "" : "not ");
|
|
|
|
#else
|
|
|
|
DRV_LOG(WARNING, "MPLS over GRE/UDP tunnel offloading disabled due to"
|
|
|
|
" old OFED/rdma-core version or firmware configuration");
|
2018-02-25 07:28:37 +00:00
|
|
|
#endif
|
2018-05-03 07:59:37 +00:00
|
|
|
err = mlx5_glue->query_device_ex(attr_ctx, NULL, &device_attr);
|
|
|
|
if (err) {
|
|
|
|
DEBUG("ibv_query_device_ex() failed");
|
2015-10-30 18:52:30 +00:00
|
|
|
goto error;
|
2018-03-05 12:21:06 +00:00
|
|
|
}
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(INFO, "%u port(s) detected",
|
|
|
|
device_attr.orig_attr.phys_port_cnt);
|
2017-09-26 15:38:24 +00:00
|
|
|
for (i = 0; i < device_attr.orig_attr.phys_port_cnt; i++) {
|
2018-01-22 09:30:06 +00:00
|
|
|
char name[RTE_ETH_NAME_MAX_LEN];
|
|
|
|
int len;
|
2015-10-30 18:52:30 +00:00
|
|
|
uint32_t port = i + 1; /* ports are indexed from one */
|
|
|
|
uint32_t test = (1 << i);
|
|
|
|
struct ibv_context *ctx = NULL;
|
|
|
|
struct ibv_port_attr port_attr;
|
|
|
|
struct ibv_pd *pd = NULL;
|
|
|
|
struct priv *priv = NULL;
|
2018-03-05 12:21:04 +00:00
|
|
|
struct rte_eth_dev *eth_dev = NULL;
|
2017-09-26 15:38:24 +00:00
|
|
|
struct ibv_device_attr_ex device_attr_ex;
|
2015-10-30 18:52:30 +00:00
|
|
|
struct ether_addr mac;
|
2018-01-10 09:16:58 +00:00
|
|
|
struct mlx5_dev_config config = {
|
|
|
|
.cqe_comp = cqe_comp,
|
|
|
|
.mps = mps,
|
|
|
|
.tunnel_en = tunnel_en,
|
2018-05-15 11:07:14 +00:00
|
|
|
.mpls_en = mpls_en,
|
2018-01-10 09:16:58 +00:00
|
|
|
.tx_vec_en = 1,
|
|
|
|
.rx_vec_en = 1,
|
|
|
|
.mpw_hdr_dseg = 0,
|
2017-04-18 10:22:27 +00:00
|
|
|
.txq_inline = MLX5_ARG_UNSET,
|
|
|
|
.txqs_inline = MLX5_ARG_UNSET,
|
|
|
|
.inline_max_packet_sz = MLX5_ARG_UNSET,
|
2018-04-05 15:07:21 +00:00
|
|
|
.vf_nl_en = 1,
|
2018-04-08 12:41:20 +00:00
|
|
|
.swp = !!swp,
|
2018-05-09 11:13:50 +00:00
|
|
|
.mprq = {
|
|
|
|
.enabled = 0, /* Disabled by default. */
|
|
|
|
.stride_num_n = RTE_MAX(MLX5_MPRQ_STRIDE_NUM_N,
|
|
|
|
mprq_min_stride_num_n),
|
|
|
|
.max_memcpy_len = MLX5_MPRQ_MEMCPY_DEFAULT_LEN,
|
|
|
|
.min_rxqs_num = MLX5_MPRQ_MIN_RXQS,
|
|
|
|
},
|
2017-04-18 10:22:27 +00:00
|
|
|
};
|
2015-10-30 18:52:30 +00:00
|
|
|
|
2018-01-22 09:30:06 +00:00
|
|
|
len = snprintf(name, sizeof(name), PCI_PRI_FMT,
|
|
|
|
pci_dev->addr.domain, pci_dev->addr.bus,
|
|
|
|
pci_dev->addr.devid, pci_dev->addr.function);
|
|
|
|
if (device_attr.orig_attr.phys_port_cnt > 1)
|
|
|
|
snprintf(name + len, sizeof(name), " port %u", i);
|
2017-10-06 15:45:49 +00:00
|
|
|
mlx5_dev[idx].ports |= test;
|
2017-11-23 09:22:33 +00:00
|
|
|
if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
|
2017-10-06 15:45:49 +00:00
|
|
|
eth_dev = rte_eth_dev_attach_secondary(name);
|
|
|
|
if (eth_dev == NULL) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR, "can not attach rte ethdev");
|
2018-03-05 12:21:06 +00:00
|
|
|
rte_errno = ENOMEM;
|
|
|
|
err = rte_errno;
|
2017-10-06 15:45:49 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
eth_dev->device = &pci_dev->device;
|
2017-10-06 15:45:51 +00:00
|
|
|
eth_dev->dev_ops = &mlx5_dev_sec_ops;
|
2018-03-05 12:21:04 +00:00
|
|
|
err = mlx5_uar_init_secondary(eth_dev);
|
2018-05-03 07:59:37 +00:00
|
|
|
if (err) {
|
|
|
|
err = rte_errno;
|
2018-01-25 15:00:24 +00:00
|
|
|
goto error;
|
2018-05-03 07:59:37 +00:00
|
|
|
}
|
2017-10-06 15:45:49 +00:00
|
|
|
/* Receive command fd from primary process */
|
2018-03-05 12:21:04 +00:00
|
|
|
err = mlx5_socket_connect(eth_dev);
|
2018-05-03 07:59:37 +00:00
|
|
|
if (err < 0) {
|
|
|
|
err = rte_errno;
|
2017-10-06 15:45:49 +00:00
|
|
|
goto error;
|
2018-05-03 07:59:37 +00:00
|
|
|
}
|
2017-10-06 15:45:49 +00:00
|
|
|
/* Remap UAR for Tx queues. */
|
2018-03-05 12:21:04 +00:00
|
|
|
err = mlx5_tx_uar_remap(eth_dev, err);
|
2018-05-03 07:59:37 +00:00
|
|
|
if (err) {
|
|
|
|
err = rte_errno;
|
2017-10-06 15:45:49 +00:00
|
|
|
goto error;
|
2018-05-03 07:59:37 +00:00
|
|
|
}
|
2018-01-10 09:16:57 +00:00
|
|
|
/*
|
|
|
|
* Ethdev pointer is still required as input since
|
|
|
|
* the primary device is not accessible from the
|
|
|
|
* secondary process.
|
|
|
|
*/
|
|
|
|
eth_dev->rx_pkt_burst =
|
2018-03-05 12:21:04 +00:00
|
|
|
mlx5_select_rx_function(eth_dev);
|
2018-01-10 09:16:57 +00:00
|
|
|
eth_dev->tx_pkt_burst =
|
2018-03-05 12:21:04 +00:00
|
|
|
mlx5_select_tx_function(eth_dev);
|
2018-05-10 23:58:30 +00:00
|
|
|
rte_eth_dev_probing_finish(eth_dev);
|
2017-10-06 15:45:49 +00:00
|
|
|
continue;
|
|
|
|
}
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "using port %u (%08" PRIx32 ")", port, test);
|
2018-01-30 15:34:56 +00:00
|
|
|
ctx = mlx5_glue->open_device(ibv_dev);
|
2017-08-13 12:25:12 +00:00
|
|
|
if (ctx == NULL) {
|
|
|
|
err = ENODEV;
|
2015-10-30 18:52:30 +00:00
|
|
|
goto port_error;
|
2017-08-13 12:25:12 +00:00
|
|
|
}
|
2015-10-30 18:52:30 +00:00
|
|
|
/* Check port status. */
|
2018-01-30 15:34:56 +00:00
|
|
|
err = mlx5_glue->query_port(ctx, port, &port_attr);
|
2015-10-30 18:52:30 +00:00
|
|
|
if (err) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR, "port query failed: %s", strerror(err));
|
2015-10-30 18:52:30 +00:00
|
|
|
goto port_error;
|
|
|
|
}
|
2016-03-03 14:27:35 +00:00
|
|
|
if (port_attr.link_layer != IBV_LINK_LAYER_ETHERNET) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR,
|
|
|
|
"port %d is not configured in Ethernet mode",
|
|
|
|
port);
|
2017-08-13 12:25:12 +00:00
|
|
|
err = EINVAL;
|
2016-03-03 14:27:35 +00:00
|
|
|
goto port_error;
|
|
|
|
}
|
2015-10-30 18:52:30 +00:00
|
|
|
if (port_attr.state != IBV_PORT_ACTIVE)
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "port %d is not active: \"%s\" (%d)",
|
|
|
|
port,
|
|
|
|
mlx5_glue->port_state_str(port_attr.state),
|
|
|
|
port_attr.state);
|
2015-10-30 18:52:30 +00:00
|
|
|
/* Allocate protection domain. */
|
2018-01-30 15:34:56 +00:00
|
|
|
pd = mlx5_glue->alloc_pd(ctx);
|
2015-10-30 18:52:30 +00:00
|
|
|
if (pd == NULL) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR, "PD allocation failure");
|
2015-10-30 18:52:30 +00:00
|
|
|
err = ENOMEM;
|
|
|
|
goto port_error;
|
|
|
|
}
|
|
|
|
mlx5_dev[idx].ports |= test;
|
|
|
|
/* from rte_ethdev.c */
|
|
|
|
priv = rte_zmalloc("ethdev private structure",
|
|
|
|
sizeof(*priv),
|
|
|
|
RTE_CACHE_LINE_SIZE);
|
|
|
|
if (priv == NULL) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR, "priv allocation failure");
|
2015-10-30 18:52:30 +00:00
|
|
|
err = ENOMEM;
|
|
|
|
goto port_error;
|
|
|
|
}
|
|
|
|
priv->ctx = ctx;
|
2017-10-06 15:45:51 +00:00
|
|
|
strncpy(priv->ibdev_path, priv->ctx->device->ibdev_path,
|
|
|
|
sizeof(priv->ibdev_path));
|
2015-10-30 18:52:30 +00:00
|
|
|
priv->device_attr = device_attr;
|
|
|
|
priv->port = port;
|
|
|
|
priv->pd = pd;
|
|
|
|
priv->mtu = ETHER_MTU;
|
2018-01-10 09:16:58 +00:00
|
|
|
err = mlx5_args(&config, pci_dev->device.devargs);
|
2016-06-24 13:17:50 +00:00
|
|
|
if (err) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR, "failed to process device arguments: %s",
|
|
|
|
strerror(err));
|
2018-05-03 07:59:37 +00:00
|
|
|
err = rte_errno;
|
2016-06-24 13:17:50 +00:00
|
|
|
goto port_error;
|
|
|
|
}
|
2018-05-03 07:59:37 +00:00
|
|
|
err = mlx5_glue->query_device_ex(ctx, NULL, &device_attr_ex);
|
|
|
|
if (err) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR, "ibv_query_device_ex() failed");
|
2015-10-30 18:52:30 +00:00
|
|
|
goto port_error;
|
|
|
|
}
|
2018-01-10 09:16:58 +00:00
|
|
|
config.hw_csum = !!(device_attr_ex.device_cap_flags_ex &
|
|
|
|
IBV_DEVICE_RAW_IP_CSUM);
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "checksum offloading is %ssupported",
|
|
|
|
(config.hw_csum ? "" : "not "));
|
2017-10-10 14:22:54 +00:00
|
|
|
#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
|
2018-01-10 09:16:59 +00:00
|
|
|
config.flow_counter_en = !!(device_attr.max_counter_sets);
|
2018-01-30 15:34:56 +00:00
|
|
|
mlx5_glue->describe_counter_set(ctx, 0, &cs_desc);
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG,
|
|
|
|
"counter type = %d, num of cs = %ld, attributes = %d",
|
|
|
|
cs_desc.counter_type, cs_desc.num_of_cs,
|
|
|
|
cs_desc.attributes);
|
2017-10-10 14:22:54 +00:00
|
|
|
#endif
|
2018-01-10 09:16:58 +00:00
|
|
|
config.ind_table_max_size =
|
2017-09-26 15:38:24 +00:00
|
|
|
device_attr_ex.rss_caps.max_rwq_indirection_table_size;
|
2015-11-03 17:15:13 +00:00
|
|
|
/* Remove this check once DPDK supports larger/variable
|
|
|
|
* indirection tables. */
|
2018-01-10 09:16:58 +00:00
|
|
|
if (config.ind_table_max_size >
|
2017-01-18 00:39:29 +00:00
|
|
|
(unsigned int)ETH_RSS_RETA_SIZE_512)
|
2018-01-10 09:16:58 +00:00
|
|
|
config.ind_table_max_size = ETH_RSS_RETA_SIZE_512;
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "maximum Rx indirection table size is %u",
|
|
|
|
config.ind_table_max_size);
|
2018-01-10 09:16:58 +00:00
|
|
|
config.hw_vlan_strip = !!(device_attr_ex.raw_packet_caps &
|
2017-09-26 15:38:24 +00:00
|
|
|
IBV_RAW_PACKET_CAP_CVLAN_STRIPPING);
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "VLAN stripping is %ssupported",
|
|
|
|
(config.hw_vlan_strip ? "" : "not "));
|
2015-10-30 18:55:08 +00:00
|
|
|
|
2018-02-01 18:53:53 +00:00
|
|
|
config.hw_fcs_strip = !!(device_attr_ex.raw_packet_caps &
|
|
|
|
IBV_RAW_PACKET_CAP_SCATTER_FCS);
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "FCS stripping configuration is %ssupported",
|
|
|
|
(config.hw_fcs_strip ? "" : "not "));
|
2016-03-17 15:38:56 +00:00
|
|
|
|
2017-09-26 15:38:24 +00:00
|
|
|
#ifdef HAVE_IBV_WQ_FLAG_RX_END_PADDING
|
2018-01-10 09:16:58 +00:00
|
|
|
config.hw_padding = !!device_attr_ex.rx_pad_end_addr_align;
|
2017-09-26 15:38:24 +00:00
|
|
|
#endif
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG,
|
|
|
|
"hardware Rx end alignment padding is %ssupported",
|
|
|
|
(config.hw_padding ? "" : "not "));
|
2018-04-05 15:07:19 +00:00
|
|
|
config.vf = vf;
|
2018-01-10 09:17:00 +00:00
|
|
|
config.tso = ((device_attr_ex.tso_caps.max_tso > 0) &&
|
|
|
|
(device_attr_ex.tso_caps.supported_qpts &
|
|
|
|
(1 << IBV_QPT_RAW_PACKET)));
|
2018-01-10 09:16:58 +00:00
|
|
|
if (config.tso)
|
|
|
|
config.tso_max_payload_sz =
|
|
|
|
device_attr_ex.tso_caps.max_tso;
|
|
|
|
if (config.mps && !mps) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR,
|
|
|
|
"multi-packet send not supported on this device"
|
|
|
|
" (" MLX5_TXQ_MPW_EN ")");
|
2016-06-24 13:17:57 +00:00
|
|
|
err = ENOTSUP;
|
|
|
|
goto port_error;
|
|
|
|
}
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(INFO, "%s MPS is %s",
|
|
|
|
config.mps == MLX5_MPW_ENHANCED ? "enhanced " : "",
|
|
|
|
config.mps != MLX5_MPW_DISABLED ? "enabled" :
|
|
|
|
"disabled");
|
2018-01-10 09:16:58 +00:00
|
|
|
if (config.cqe_comp && !cqe_comp) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(WARNING, "Rx CQE compression isn't supported");
|
2018-01-10 09:16:58 +00:00
|
|
|
config.cqe_comp = 0;
|
2017-10-09 18:46:59 +00:00
|
|
|
}
|
2018-05-09 11:13:50 +00:00
|
|
|
config.mprq.enabled = config.mprq.enabled && mprq;
|
|
|
|
if (config.mprq.enabled) {
|
|
|
|
if (config.mprq.stride_num_n > mprq_max_stride_num_n ||
|
|
|
|
config.mprq.stride_num_n < mprq_min_stride_num_n) {
|
|
|
|
config.mprq.stride_num_n =
|
|
|
|
RTE_MAX(MLX5_MPRQ_STRIDE_NUM_N,
|
|
|
|
mprq_min_stride_num_n);
|
|
|
|
DRV_LOG(WARNING,
|
|
|
|
"the number of strides"
|
|
|
|
" for Multi-Packet RQ is out of range,"
|
|
|
|
" setting default value (%u)",
|
|
|
|
1 << config.mprq.stride_num_n);
|
|
|
|
}
|
|
|
|
config.mprq.min_stride_size_n = mprq_min_stride_size_n;
|
|
|
|
config.mprq.max_stride_size_n = mprq_max_stride_size_n;
|
|
|
|
}
|
2018-03-05 12:21:04 +00:00
|
|
|
eth_dev = rte_eth_dev_allocate(name);
|
|
|
|
if (eth_dev == NULL) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR, "can not allocate rte ethdev");
|
2018-03-05 12:21:04 +00:00
|
|
|
err = ENOMEM;
|
|
|
|
goto port_error;
|
|
|
|
}
|
|
|
|
eth_dev->data->dev_private = priv;
|
2018-05-09 11:04:50 +00:00
|
|
|
priv->dev_data = eth_dev->data;
|
2018-03-05 12:21:04 +00:00
|
|
|
eth_dev->data->mac_addrs = priv->mac;
|
|
|
|
eth_dev->device = &pci_dev->device;
|
|
|
|
rte_eth_copy_pci_info(eth_dev, pci_dev);
|
|
|
|
eth_dev->device->driver = &mlx5_driver.driver;
|
|
|
|
err = mlx5_uar_init_primary(eth_dev);
|
2018-05-03 07:59:37 +00:00
|
|
|
if (err) {
|
|
|
|
err = rte_errno;
|
2018-01-25 15:00:24 +00:00
|
|
|
goto port_error;
|
2018-05-03 07:59:37 +00:00
|
|
|
}
|
2015-10-30 18:52:30 +00:00
|
|
|
/* Configure the first MAC address by default. */
|
2018-03-05 12:21:04 +00:00
|
|
|
if (mlx5_get_mac(eth_dev, &mac.addr_bytes)) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR,
|
|
|
|
"port %u cannot get MAC address, is mlx5_en"
|
|
|
|
" loaded? (errno: %s)",
|
|
|
|
eth_dev->data->port_id, strerror(errno));
|
2017-08-13 12:25:12 +00:00
|
|
|
err = ENODEV;
|
2015-10-30 18:52:30 +00:00
|
|
|
goto port_error;
|
|
|
|
}
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(INFO,
|
|
|
|
"port %u MAC address is %02x:%02x:%02x:%02x:%02x:%02x",
|
|
|
|
eth_dev->data->port_id,
|
|
|
|
mac.addr_bytes[0], mac.addr_bytes[1],
|
|
|
|
mac.addr_bytes[2], mac.addr_bytes[3],
|
|
|
|
mac.addr_bytes[4], mac.addr_bytes[5]);
|
2015-10-30 18:52:30 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
{
|
|
|
|
char ifname[IF_NAMESIZE];
|
|
|
|
|
2018-03-05 12:21:04 +00:00
|
|
|
if (mlx5_get_ifname(eth_dev, &ifname) == 0)
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "port %u ifname is \"%s\"",
|
|
|
|
eth_dev->data->port_id, ifname);
|
2015-10-30 18:52:30 +00:00
|
|
|
else
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "port %u ifname is unknown",
|
|
|
|
eth_dev->data->port_id);
|
2015-10-30 18:52:30 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
/* Get actual MTU if possible. */
|
2018-03-05 12:21:06 +00:00
|
|
|
err = mlx5_get_mtu(eth_dev, &priv->mtu);
|
2018-05-03 07:59:37 +00:00
|
|
|
if (err) {
|
|
|
|
err = rte_errno;
|
2018-03-05 12:21:06 +00:00
|
|
|
goto port_error;
|
2018-05-03 07:59:37 +00:00
|
|
|
}
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "port %u MTU is %u", eth_dev->data->port_id,
|
|
|
|
priv->mtu);
|
2018-01-25 16:04:28 +00:00
|
|
|
/*
|
|
|
|
* Initialize burst functions to prevent crashes before link-up.
|
|
|
|
*/
|
|
|
|
eth_dev->rx_pkt_burst = removed_rx_burst;
|
|
|
|
eth_dev->tx_pkt_burst = removed_tx_burst;
|
2015-10-30 18:52:30 +00:00
|
|
|
eth_dev->dev_ops = &mlx5_dev_ops;
|
2017-10-09 14:44:55 +00:00
|
|
|
/* Register MAC address. */
|
|
|
|
claim_zero(mlx5_mac_addr_add(eth_dev, &mac, 0, 0));
|
2018-04-05 15:07:19 +00:00
|
|
|
priv->nl_socket = -1;
|
|
|
|
priv->nl_sn = 0;
|
2018-04-05 15:07:21 +00:00
|
|
|
if (vf && config.vf_nl_en) {
|
2018-04-05 15:07:19 +00:00
|
|
|
priv->nl_socket = mlx5_nl_init(RTMGRP_LINK);
|
|
|
|
if (priv->nl_socket < 0)
|
|
|
|
priv->nl_socket = -1;
|
|
|
|
mlx5_nl_mac_addr_sync(eth_dev);
|
|
|
|
}
|
2017-05-29 09:40:58 +00:00
|
|
|
TAILQ_INIT(&priv->flows);
|
2017-10-09 14:44:53 +00:00
|
|
|
TAILQ_INIT(&priv->ctrl_flows);
|
2017-10-06 15:45:50 +00:00
|
|
|
/* Hint libmlx5 to use PMD allocator for data plane resources */
|
|
|
|
struct mlx5dv_ctx_allocators alctr = {
|
|
|
|
.alloc = &mlx5_alloc_verbs_buf,
|
|
|
|
.free = &mlx5_free_verbs_buf,
|
|
|
|
.data = priv,
|
|
|
|
};
|
2018-01-30 15:34:56 +00:00
|
|
|
mlx5_glue->dv_set_context_attr(ctx,
|
|
|
|
MLX5DV_CTX_ATTR_BUF_ALLOCATORS,
|
|
|
|
(void *)((uintptr_t)&alctr));
|
2015-10-30 18:52:30 +00:00
|
|
|
/* Bring Ethernet device up. */
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "port %u forcing Ethernet interface up",
|
|
|
|
eth_dev->data->port_id);
|
net/mlx5: fix link status behavior
This behavior is mixed between what should be handled by the application
and what is under PMD responsibility.
According to DPDK API:
- link_update() should only query the link status [1]
- link_set_{up,down}() should only set the link to the according status [1]
- dev_{start,stop}() should enable/disable traffic reception/emission [2]
On this PMD, the link status is retrieved from the net device associated
owned by the Linux Kernel, it does not means that even when this interface
is down, the PMD cannot send/receive traffic from the NIC those two
information are unrelated, until the physical port is active and has a
link, the PMD can receive/send traffic on the wire.
According to DPDK API, calling the rte_eth_dev_start() even when the Linux
interface link is down is then possible and allowed, as the traffic will
flow between the DPDK application and the Physical port.
This also means that a synchronization between the Linux interface and the
DPDK application remains under the DPDK application responsibility.
To handle such synchronization the application should behave as the
following scheme, to start:
rte_eth_get_link(port_id, &link);
if (link.link_status == ETH_DOWN)
rte_eth_dev_set_link_up(port_id);
rte_eth_dev_start(port_id);
Taking in account the possible returned values for each function.
and to stop:
rte_eth_dev_stop(port_id);
rte_eth_dev_set_link_down(port_id);
The application should also set the LSC interrupt callbacks to catch and
behave accordingly when the administrator set the Linux device down/up.
The same callbacks are called when the link on the medium falls/raise.
[1] https://dpdk.org/browse/dpdk/tree/lib/librte_ether/rte_ethdev_core.h
[2] https://dpdk.org/browse/dpdk/tree/lib/librte_ether/rte_ethdev.h#n1677
Fixes: c7bf62255edf ("net/mlx5: fix handling link status event")
Fixes: e313ef4c2fe8 ("net/mlx5: fix link state on device start")
Cc: stable@dpdk.org
Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
Acked-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Acked-by: Yongseok Koh <yskoh@mellanox.com>
2018-03-12 13:43:18 +00:00
|
|
|
mlx5_set_link_up(eth_dev);
|
2018-04-10 06:13:36 +00:00
|
|
|
/*
|
|
|
|
* Even though the interrupt handler is not installed yet,
|
|
|
|
* interrupts will still trigger on the asyn_fd from
|
|
|
|
* Verbs context returned by ibv_open_device().
|
|
|
|
*/
|
|
|
|
mlx5_link_update(eth_dev, 0);
|
2018-01-10 09:16:58 +00:00
|
|
|
/* Store device configuration on private structure. */
|
|
|
|
priv->config = config;
|
2018-04-23 12:33:00 +00:00
|
|
|
/* Create drop queue. */
|
|
|
|
err = mlx5_flow_create_drop_queue(eth_dev);
|
|
|
|
if (err) {
|
|
|
|
DRV_LOG(ERR, "port %u drop queue allocation failed: %s",
|
|
|
|
eth_dev->data->port_id, strerror(rte_errno));
|
2018-05-03 07:59:37 +00:00
|
|
|
err = rte_errno;
|
2018-04-23 12:33:00 +00:00
|
|
|
goto port_error;
|
|
|
|
}
|
|
|
|
/* Supported Verbs flow priority number detection. */
|
|
|
|
if (verb_priorities == 0)
|
|
|
|
verb_priorities = mlx5_get_max_verbs_prio(eth_dev);
|
|
|
|
if (verb_priorities < MLX5_VERBS_FLOW_PRIO_8) {
|
|
|
|
DRV_LOG(ERR, "port %u wrong Verbs flow priorities: %u",
|
|
|
|
eth_dev->data->port_id, verb_priorities);
|
|
|
|
goto port_error;
|
|
|
|
}
|
|
|
|
priv->config.max_verbs_prio = verb_priorities;
|
2018-05-26 13:27:35 +00:00
|
|
|
/*
|
|
|
|
* Once the device is added to the list of memory event
|
|
|
|
* callback, its global MR cache table cannot be expanded
|
|
|
|
* on the fly because of deadlock. If it overflows, lookup
|
|
|
|
* should be done by searching MR list linearly, which is slow.
|
|
|
|
*/
|
|
|
|
err = mlx5_mr_btree_init(&priv->mr.cache,
|
|
|
|
MLX5_MR_BTREE_CACHE_N * 2,
|
|
|
|
eth_dev->device->numa_node);
|
|
|
|
if (err) {
|
|
|
|
err = rte_errno;
|
|
|
|
goto port_error;
|
|
|
|
}
|
2018-05-24 14:36:49 +00:00
|
|
|
/* Add device to memory callback list. */
|
|
|
|
rte_rwlock_write_lock(&mlx5_shared_data->mem_event_rwlock);
|
|
|
|
LIST_INSERT_HEAD(&mlx5_shared_data->mem_event_cb_list,
|
|
|
|
priv, mem_event_cb);
|
|
|
|
rte_rwlock_write_unlock(&mlx5_shared_data->mem_event_rwlock);
|
2018-05-10 23:58:30 +00:00
|
|
|
rte_eth_dev_probing_finish(eth_dev);
|
2015-10-30 18:52:30 +00:00
|
|
|
continue;
|
|
|
|
port_error:
|
2017-10-09 14:44:56 +00:00
|
|
|
if (priv)
|
2016-03-03 14:27:34 +00:00
|
|
|
rte_free(priv);
|
2015-10-30 18:52:30 +00:00
|
|
|
if (pd)
|
2018-01-30 15:34:56 +00:00
|
|
|
claim_zero(mlx5_glue->dealloc_pd(pd));
|
2015-10-30 18:52:30 +00:00
|
|
|
if (ctx)
|
2018-01-30 15:34:56 +00:00
|
|
|
claim_zero(mlx5_glue->close_device(ctx));
|
2018-05-08 09:11:27 +00:00
|
|
|
if (eth_dev && rte_eal_process_type() == RTE_PROC_PRIMARY)
|
|
|
|
rte_eth_dev_release_port(eth_dev);
|
2015-10-30 18:52:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* XXX if something went wrong in the loop above, there is a resource
|
|
|
|
* leak (ctx, pd, priv, dpdk ethdev) but we can do nothing about it as
|
|
|
|
* long as the dpdk does not provide a way to deallocate a ethdev and a
|
|
|
|
* way to enumerate the registered ethdevs to free the previous ones.
|
|
|
|
*/
|
|
|
|
/* no port found, complain */
|
|
|
|
if (!mlx5_dev[idx].ports) {
|
2018-03-05 12:21:06 +00:00
|
|
|
rte_errno = ENODEV;
|
|
|
|
err = rte_errno;
|
2015-10-30 18:52:30 +00:00
|
|
|
}
|
|
|
|
error:
|
|
|
|
if (attr_ctx)
|
2018-01-30 15:34:56 +00:00
|
|
|
claim_zero(mlx5_glue->close_device(attr_ctx));
|
2015-10-30 18:52:30 +00:00
|
|
|
if (list)
|
2018-01-30 15:34:56 +00:00
|
|
|
mlx5_glue->free_device_list(list);
|
2018-03-05 12:21:06 +00:00
|
|
|
if (err) {
|
|
|
|
rte_errno = err;
|
|
|
|
return -rte_errno;
|
|
|
|
}
|
|
|
|
return 0;
|
2015-10-30 18:52:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct rte_pci_id mlx5_pci_id_map[] = {
|
|
|
|
{
|
2016-06-24 13:17:40 +00:00
|
|
|
RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
|
|
|
|
PCI_DEVICE_ID_MELLANOX_CONNECTX4)
|
2015-10-30 18:52:30 +00:00
|
|
|
},
|
|
|
|
{
|
2016-06-24 13:17:40 +00:00
|
|
|
RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
|
|
|
|
PCI_DEVICE_ID_MELLANOX_CONNECTX4VF)
|
2015-10-30 18:52:30 +00:00
|
|
|
},
|
|
|
|
{
|
2016-06-24 13:17:40 +00:00
|
|
|
RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
|
|
|
|
PCI_DEVICE_ID_MELLANOX_CONNECTX4LX)
|
2015-10-30 18:52:30 +00:00
|
|
|
},
|
|
|
|
{
|
2016-06-24 13:17:40 +00:00
|
|
|
RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
|
|
|
|
PCI_DEVICE_ID_MELLANOX_CONNECTX4LXVF)
|
2015-10-30 18:52:30 +00:00
|
|
|
},
|
2017-01-06 00:49:31 +00:00
|
|
|
{
|
|
|
|
RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
|
|
|
|
PCI_DEVICE_ID_MELLANOX_CONNECTX5)
|
|
|
|
},
|
|
|
|
{
|
|
|
|
RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
|
|
|
|
PCI_DEVICE_ID_MELLANOX_CONNECTX5VF)
|
|
|
|
},
|
|
|
|
{
|
|
|
|
RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
|
|
|
|
PCI_DEVICE_ID_MELLANOX_CONNECTX5EX)
|
|
|
|
},
|
|
|
|
{
|
|
|
|
RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
|
|
|
|
PCI_DEVICE_ID_MELLANOX_CONNECTX5EXVF)
|
|
|
|
},
|
2018-05-15 06:12:50 +00:00
|
|
|
{
|
|
|
|
RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
|
|
|
|
PCI_DEVICE_ID_MELLANOX_CONNECTX5BF)
|
|
|
|
},
|
2015-10-30 18:52:30 +00:00
|
|
|
{
|
|
|
|
.vendor_id = 0
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-04-11 15:44:24 +00:00
|
|
|
static struct rte_pci_driver mlx5_driver = {
|
|
|
|
.driver = {
|
|
|
|
.name = MLX5_DRIVER_NAME
|
2015-10-30 18:52:30 +00:00
|
|
|
},
|
2017-04-11 15:44:24 +00:00
|
|
|
.id_table = mlx5_pci_id_map,
|
|
|
|
.probe = mlx5_pci_probe,
|
2017-09-08 10:47:45 +00:00
|
|
|
.drv_flags = RTE_PCI_DRV_INTR_LSC | RTE_PCI_DRV_INTR_RMV,
|
2015-10-30 18:52:30 +00:00
|
|
|
};
|
|
|
|
|
2018-01-30 15:34:58 +00:00
|
|
|
#ifdef RTE_LIBRTE_MLX5_DLOPEN_DEPS
|
|
|
|
|
2018-03-02 14:15:17 +00:00
|
|
|
/**
|
|
|
|
* Suffix RTE_EAL_PMD_PATH with "-glue".
|
|
|
|
*
|
|
|
|
* This function performs a sanity check on RTE_EAL_PMD_PATH before
|
|
|
|
* suffixing its last component.
|
|
|
|
*
|
|
|
|
* @param buf[out]
|
|
|
|
* Output buffer, should be large enough otherwise NULL is returned.
|
|
|
|
* @param size
|
|
|
|
* Size of @p out.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* Pointer to @p buf or @p NULL in case suffix cannot be appended.
|
|
|
|
*/
|
|
|
|
static char *
|
|
|
|
mlx5_glue_path(char *buf, size_t size)
|
|
|
|
{
|
|
|
|
static const char *const bad[] = { "/", ".", "..", NULL };
|
|
|
|
const char *path = RTE_EAL_PMD_PATH;
|
|
|
|
size_t len = strlen(path);
|
|
|
|
size_t off;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
while (len && path[len - 1] == '/')
|
|
|
|
--len;
|
|
|
|
for (off = len; off && path[off - 1] != '/'; --off)
|
|
|
|
;
|
|
|
|
for (i = 0; bad[i]; ++i)
|
|
|
|
if (!strncmp(path + off, bad[i], (int)(len - off)))
|
|
|
|
goto error;
|
|
|
|
i = snprintf(buf, size, "%.*s-glue", (int)len, path);
|
|
|
|
if (i == -1 || (size_t)i >= size)
|
|
|
|
goto error;
|
|
|
|
return buf;
|
|
|
|
error:
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR,
|
|
|
|
"unable to append \"-glue\" to last component of"
|
|
|
|
" RTE_EAL_PMD_PATH (\"" RTE_EAL_PMD_PATH "\"),"
|
|
|
|
" please re-configure DPDK");
|
2018-03-02 14:15:17 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-01-30 15:34:58 +00:00
|
|
|
/**
|
|
|
|
* Initialization routine for run-time dependency on rdma-core.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
mlx5_glue_init(void)
|
|
|
|
{
|
2018-03-02 14:15:17 +00:00
|
|
|
char glue_path[sizeof(RTE_EAL_PMD_PATH) - 1 + sizeof("-glue")];
|
2018-02-02 16:46:18 +00:00
|
|
|
const char *path[] = {
|
|
|
|
/*
|
|
|
|
* A basic security check is necessary before trusting
|
|
|
|
* MLX5_GLUE_PATH, which may override RTE_EAL_PMD_PATH.
|
|
|
|
*/
|
|
|
|
(geteuid() == getuid() && getegid() == getgid() ?
|
|
|
|
getenv("MLX5_GLUE_PATH") : NULL),
|
2018-03-02 14:15:17 +00:00
|
|
|
/*
|
|
|
|
* When RTE_EAL_PMD_PATH is set, use its glue-suffixed
|
|
|
|
* variant, otherwise let dlopen() look up libraries on its
|
|
|
|
* own.
|
|
|
|
*/
|
|
|
|
(*RTE_EAL_PMD_PATH ?
|
|
|
|
mlx5_glue_path(glue_path, sizeof(glue_path)) : ""),
|
2018-02-02 16:46:18 +00:00
|
|
|
};
|
|
|
|
unsigned int i = 0;
|
2018-01-30 15:34:58 +00:00
|
|
|
void *handle = NULL;
|
|
|
|
void **sym;
|
|
|
|
const char *dlmsg;
|
|
|
|
|
2018-02-02 16:46:18 +00:00
|
|
|
while (!handle && i != RTE_DIM(path)) {
|
|
|
|
const char *end;
|
|
|
|
size_t len;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!path[i]) {
|
|
|
|
++i;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
end = strpbrk(path[i], ":;");
|
|
|
|
if (!end)
|
|
|
|
end = path[i] + strlen(path[i]);
|
|
|
|
len = end - path[i];
|
|
|
|
ret = 0;
|
|
|
|
do {
|
|
|
|
char name[ret + 1];
|
|
|
|
|
|
|
|
ret = snprintf(name, sizeof(name), "%.*s%s" MLX5_GLUE,
|
|
|
|
(int)len, path[i],
|
|
|
|
(!len || *(end - 1) == '/') ? "" : "/");
|
|
|
|
if (ret == -1)
|
|
|
|
break;
|
|
|
|
if (sizeof(name) != (size_t)ret + 1)
|
|
|
|
continue;
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(DEBUG, "looking for rdma-core glue as \"%s\"",
|
|
|
|
name);
|
2018-02-02 16:46:18 +00:00
|
|
|
handle = dlopen(name, RTLD_LAZY);
|
|
|
|
break;
|
|
|
|
} while (1);
|
|
|
|
path[i] = end + 1;
|
|
|
|
if (!*end)
|
|
|
|
++i;
|
|
|
|
}
|
2018-01-30 15:34:58 +00:00
|
|
|
if (!handle) {
|
|
|
|
rte_errno = EINVAL;
|
|
|
|
dlmsg = dlerror();
|
|
|
|
if (dlmsg)
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(WARNING, "cannot load glue library: %s", dlmsg);
|
2018-01-30 15:34:58 +00:00
|
|
|
goto glue_error;
|
|
|
|
}
|
|
|
|
sym = dlsym(handle, "mlx5_glue");
|
|
|
|
if (!sym || !*sym) {
|
|
|
|
rte_errno = EINVAL;
|
|
|
|
dlmsg = dlerror();
|
|
|
|
if (dlmsg)
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR, "cannot resolve glue symbol: %s", dlmsg);
|
2018-01-30 15:34:58 +00:00
|
|
|
goto glue_error;
|
|
|
|
}
|
|
|
|
mlx5_glue = *sym;
|
|
|
|
return 0;
|
|
|
|
glue_error:
|
|
|
|
if (handle)
|
|
|
|
dlclose(handle);
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(WARNING,
|
|
|
|
"cannot initialize PMD due to missing run-time dependency on"
|
|
|
|
" rdma-core libraries (libibverbs, libmlx5)");
|
2018-01-30 15:34:58 +00:00
|
|
|
return -rte_errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2015-10-30 18:52:30 +00:00
|
|
|
/**
|
|
|
|
* Driver initialization routine.
|
|
|
|
*/
|
2016-09-20 12:41:20 +00:00
|
|
|
RTE_INIT(rte_mlx5_pmd_init);
|
|
|
|
static void
|
|
|
|
rte_mlx5_pmd_init(void)
|
2015-10-30 18:52:30 +00:00
|
|
|
{
|
2018-04-08 12:41:20 +00:00
|
|
|
/* Build the static tables for Verbs conversion. */
|
2017-07-26 19:29:33 +00:00
|
|
|
mlx5_set_ptype_table();
|
2018-04-08 12:41:20 +00:00
|
|
|
mlx5_set_cksum_table();
|
|
|
|
mlx5_set_swp_types_table();
|
2015-10-30 18:52:30 +00:00
|
|
|
/*
|
|
|
|
* RDMAV_HUGEPAGES_SAFE tells ibv_fork_init() we intend to use
|
|
|
|
* huge pages. Calling ibv_fork_init() during init allows
|
|
|
|
* applications to use fork() safely for purposes other than
|
|
|
|
* using this PMD, which is not supported in forked processes.
|
|
|
|
*/
|
|
|
|
setenv("RDMAV_HUGEPAGES_SAFE", "1", 1);
|
2017-10-09 18:46:58 +00:00
|
|
|
/* Match the size of Rx completion entry to the size of a cacheline. */
|
|
|
|
if (RTE_CACHE_LINE_SIZE == 128)
|
|
|
|
setenv("MLX5_CQE_SIZE", "128", 0);
|
2018-01-30 15:34:58 +00:00
|
|
|
#ifdef RTE_LIBRTE_MLX5_DLOPEN_DEPS
|
|
|
|
if (mlx5_glue_init())
|
|
|
|
return;
|
|
|
|
assert(mlx5_glue);
|
2018-02-02 16:46:12 +00:00
|
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
|
|
/* Glue structure must not contain any NULL pointers. */
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i != sizeof(*mlx5_glue) / sizeof(void *); ++i)
|
|
|
|
assert(((const void *const *)mlx5_glue)[i]);
|
|
|
|
}
|
2018-01-30 15:34:58 +00:00
|
|
|
#endif
|
2018-02-02 16:46:16 +00:00
|
|
|
if (strcmp(mlx5_glue->version, MLX5_GLUE_VERSION)) {
|
2018-03-13 09:23:56 +00:00
|
|
|
DRV_LOG(ERR,
|
|
|
|
"rdma-core glue \"%s\" mismatch: \"%s\" is required",
|
|
|
|
mlx5_glue->version, MLX5_GLUE_VERSION);
|
2018-02-02 16:46:16 +00:00
|
|
|
return;
|
|
|
|
}
|
2018-01-30 15:34:56 +00:00
|
|
|
mlx5_glue->fork_init();
|
2017-05-04 14:48:59 +00:00
|
|
|
rte_pci_register(&mlx5_driver);
|
net/mlx5: add new memory region support
This is the new design of Memory Region (MR) for mlx PMD, in order to:
- Accommodate the new memory hotplug model.
- Support non-contiguous Mempool.
There are multiple layers for MR search.
L0 is to look up the last-hit entry which is pointed by mr_ctrl->mru (Most
Recently Used). If L0 misses, L1 is to look up the address in a fixed-sized
array by linear search. L0/L1 is in an inline function -
mlx5_mr_lookup_cache().
If L1 misses, the bottom-half function is called to look up the address
from the bigger local cache of the queue. This is L2 - mlx5_mr_addr2mr_bh()
and it is not an inline function. Data structure for L2 is the Binary Tree.
If L2 misses, the search falls into the slowest path which takes locks in
order to access global device cache (priv->mr.cache) which is also a B-tree
and caches the original MR list (priv->mr.mr_list) of the device. Unless
the global cache is overflowed, it is all-inclusive of the MR list. This is
L3 - mlx5_mr_lookup_dev(). The size of the L3 cache table is limited and
can't be expanded on the fly due to deadlock. Refer to the comments in the
code for the details - mr_lookup_dev(). If L3 is overflowed, the list will
have to be searched directly bypassing the cache although it is slower.
If L3 misses, a new MR for the address should be created -
mlx5_mr_create(). When it creates a new MR, it tries to register adjacent
memsegs as much as possible which are virtually contiguous around the
address. This must take two locks - memory_hotplug_lock and
priv->mr.rwlock. Due to memory_hotplug_lock, there can't be any
allocation/free of memory inside.
In the free callback of the memory hotplug event, freed space is searched
from the MR list and corresponding bits are cleared from the bitmap of MRs.
This can fragment a MR and the MR will have multiple search entries in the
caches. Once there's a change by the event, the global cache must be
rebuilt and all the per-queue caches will be flushed as well. If memory is
frequently freed in run-time, that may cause jitter on dataplane processing
in the worst case by incurring MR cache flush and rebuild. But, it would be
the least probable scenario.
To guarantee the most optimal performance, it is highly recommended to use
an EAL option - '--socket-mem'. Then, the reserved memory will be pinned
and won't be freed dynamically. And it is also recommended to configure
per-lcore cache of Mempool. Even though there're many MRs for a device or
MRs are highly fragmented, the cache of Mempool will be much helpful to
reduce misses on per-queue caches anyway.
'--legacy-mem' is also supported.
Signed-off-by: Yongseok Koh <yskoh@mellanox.com>
2018-05-09 11:09:04 +00:00
|
|
|
rte_mem_event_callback_register("MLX5_MEM_EVENT_CB",
|
|
|
|
mlx5_mr_mem_event_cb, NULL);
|
2015-10-30 18:52:30 +00:00
|
|
|
}
|
|
|
|
|
2016-10-10 05:43:15 +00:00
|
|
|
RTE_PMD_EXPORT_NAME(net_mlx5, __COUNTER__);
|
|
|
|
RTE_PMD_REGISTER_PCI_TABLE(net_mlx5, mlx5_pci_id_map);
|
2016-12-15 13:46:39 +00:00
|
|
|
RTE_PMD_REGISTER_KMOD_DEP(net_mlx5, "* ib_uverbs & mlx5_core & mlx5_ib");
|
2018-03-13 09:23:56 +00:00
|
|
|
|
|
|
|
/** Initialize driver log type. */
|
|
|
|
RTE_INIT(vdev_netvsc_init_log)
|
|
|
|
{
|
|
|
|
mlx5_logtype = rte_log_register("pmd.net.mlx5");
|
|
|
|
if (mlx5_logtype >= 0)
|
|
|
|
rte_log_set_level(mlx5_logtype, RTE_LOG_NOTICE);
|
|
|
|
}
|