mlx5: add device configure/start/stop

This commit adds the remaining missing callbacks to make mlx5 usable.
Like mlx4, device start and stop are implemented on top of MAC RX flows.

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
Signed-off-by: Francesco Santoro <francesco.santoro@6wind.com>
Signed-off-by: Didier Pallard <didier.pallard@6wind.com>
This commit is contained in:
Adrien Mazarguil 2015-10-30 19:52:33 +01:00 committed by Thomas Monjalon
parent 3318aef7e7
commit e60fbd5b24
5 changed files with 306 additions and 0 deletions

View File

@ -45,6 +45,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5.c
SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rxq.c
SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_txq.c
SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rxtx.c
SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_trigger.c
SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_ethdev.c
SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mac.c

View File

@ -129,7 +129,11 @@ mlx5_dev_close(struct rte_eth_dev *dev)
}
static const struct eth_dev_ops mlx5_dev_ops = {
.dev_configure = mlx5_dev_configure,
.dev_start = mlx5_dev_start,
.dev_stop = mlx5_dev_stop,
.dev_close = mlx5_dev_close,
.dev_infos_get = mlx5_dev_infos_get,
.rx_queue_setup = mlx5_rx_queue_setup,
.tx_queue_setup = mlx5_tx_queue_setup,
.rx_queue_release = mlx5_rx_queue_release,

View File

@ -160,6 +160,8 @@ int priv_get_ifname(const struct priv *, char (*)[IF_NAMESIZE]);
int priv_ifreq(const struct priv *, int req, struct ifreq *);
int priv_get_mtu(struct priv *, uint16_t *);
int priv_set_flags(struct priv *, unsigned int, unsigned int);
int mlx5_dev_configure(struct rte_eth_dev *);
void mlx5_dev_infos_get(struct rte_eth_dev *, struct rte_eth_dev_info *);
int mlx5_ibv_device_to_pci_addr(const struct ibv_device *,
struct rte_pci_addr *);
@ -174,4 +176,9 @@ int priv_mac_addr_add(struct priv *, unsigned int,
void mlx5_mac_addr_add(struct rte_eth_dev *, struct ether_addr *, uint32_t,
uint32_t);
/* mlx5_trigger.c */
int mlx5_dev_start(struct rte_eth_dev *);
void mlx5_dev_stop(struct rte_eth_dev *);
#endif /* RTE_PMD_MLX5_H_ */

View File

@ -32,6 +32,7 @@
*/
#include <stddef.h>
#include <assert.h>
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
@ -58,6 +59,7 @@
#endif
#include "mlx5.h"
#include "mlx5_rxtx.h"
#include "mlx5_utils.h"
/**
@ -369,6 +371,152 @@ priv_set_flags(struct priv *priv, unsigned int keep, unsigned int flags)
return priv_set_sysfs_ulong(priv, "flags", tmp);
}
/**
* Ethernet device configuration.
*
* Prepare the driver for a given number of TX and RX queues.
* Allocate parent RSS queue when several RX queues are requested.
*
* @param dev
* Pointer to Ethernet device structure.
*
* @return
* 0 on success, errno value on failure.
*/
static int
dev_configure(struct rte_eth_dev *dev)
{
struct priv *priv = dev->data->dev_private;
unsigned int rxqs_n = dev->data->nb_rx_queues;
unsigned int txqs_n = dev->data->nb_tx_queues;
unsigned int tmp;
int ret;
priv->rxqs = (void *)dev->data->rx_queues;
priv->txqs = (void *)dev->data->tx_queues;
if (txqs_n != priv->txqs_n) {
INFO("%p: TX queues number update: %u -> %u",
(void *)dev, priv->txqs_n, txqs_n);
priv->txqs_n = txqs_n;
}
if (rxqs_n == priv->rxqs_n)
return 0;
INFO("%p: RX queues number update: %u -> %u",
(void *)dev, priv->rxqs_n, rxqs_n);
/* If RSS is enabled, disable it first. */
if (priv->rss) {
unsigned int i;
/* Only if there are no remaining child RX queues. */
for (i = 0; (i != priv->rxqs_n); ++i)
if ((*priv->rxqs)[i] != NULL)
return EINVAL;
rxq_cleanup(&priv->rxq_parent);
priv->rss = 0;
priv->rxqs_n = 0;
}
if (rxqs_n <= 1) {
/* Nothing else to do. */
priv->rxqs_n = rxqs_n;
return 0;
}
/* Allocate a new RSS parent queue if supported by hardware. */
if (!priv->hw_rss) {
ERROR("%p: only a single RX queue can be configured when"
" hardware doesn't support RSS",
(void *)dev);
return EINVAL;
}
/* Fail if hardware doesn't support that many RSS queues. */
if (rxqs_n >= priv->max_rss_tbl_sz) {
ERROR("%p: only %u RX queues can be configured for RSS",
(void *)dev, priv->max_rss_tbl_sz);
return EINVAL;
}
priv->rss = 1;
tmp = priv->rxqs_n;
priv->rxqs_n = rxqs_n;
ret = rxq_setup(dev, &priv->rxq_parent, 0, 0, NULL, NULL);
if (!ret)
return 0;
/* Failure, rollback. */
priv->rss = 0;
priv->rxqs_n = tmp;
assert(ret > 0);
return ret;
}
/**
* DPDK callback for Ethernet device configuration.
*
* @param dev
* Pointer to Ethernet device structure.
*
* @return
* 0 on success, negative errno value on failure.
*/
int
mlx5_dev_configure(struct rte_eth_dev *dev)
{
struct priv *priv = dev->data->dev_private;
int ret;
priv_lock(priv);
ret = dev_configure(dev);
assert(ret >= 0);
priv_unlock(priv);
return -ret;
}
/**
* DPDK callback to get information about the device.
*
* @param dev
* Pointer to Ethernet device structure.
* @param[out] info
* Info structure output buffer.
*/
void
mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
{
struct priv *priv = dev->data->dev_private;
unsigned int max;
char ifname[IF_NAMESIZE];
priv_lock(priv);
/* FIXME: we should ask the device for these values. */
info->min_rx_bufsize = 32;
info->max_rx_pktlen = 65536;
/*
* Since we need one CQ per QP, the limit is the minimum number
* between the two values.
*/
max = ((priv->device_attr.max_cq > priv->device_attr.max_qp) ?
priv->device_attr.max_qp : priv->device_attr.max_cq);
/* If max >= 65535 then max = 0, max_rx_queues is uint16_t. */
if (max >= 65535)
max = 65535;
info->max_rx_queues = max;
info->max_tx_queues = max;
/* Last array entry is reserved for broadcast. */
info->max_mac_addrs = (RTE_DIM(priv->mac) - 1);
info->rx_offload_capa =
(priv->hw_csum ?
(DEV_RX_OFFLOAD_IPV4_CKSUM |
DEV_RX_OFFLOAD_UDP_CKSUM |
DEV_RX_OFFLOAD_TCP_CKSUM) :
0);
info->tx_offload_capa =
(priv->hw_csum ?
(DEV_TX_OFFLOAD_IPV4_CKSUM |
DEV_TX_OFFLOAD_UDP_CKSUM |
DEV_TX_OFFLOAD_TCP_CKSUM) :
0);
if (priv_get_ifname(priv, &ifname) == 0)
info->if_index = if_nametoindex(ifname);
priv_unlock(priv);
}
/**
* Get PCI information from struct ibv_device.
*

View File

@ -0,0 +1,146 @@
/*-
* BSD LICENSE
*
* Copyright 2015 6WIND S.A.
* Copyright 2015 Mellanox.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of 6WIND S.A. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* DPDK headers don't like -pedantic. */
#ifdef PEDANTIC
#pragma GCC diagnostic ignored "-pedantic"
#endif
#include <rte_ether.h>
#include <rte_ethdev.h>
#ifdef PEDANTIC
#pragma GCC diagnostic error "-pedantic"
#endif
#include "mlx5.h"
#include "mlx5_rxtx.h"
#include "mlx5_utils.h"
/**
* DPDK callback to start the device.
*
* Simulate device start by attaching all configured flows.
*
* @param dev
* Pointer to Ethernet device structure.
*
* @return
* 0 on success, negative errno value on failure.
*/
int
mlx5_dev_start(struct rte_eth_dev *dev)
{
struct priv *priv = dev->data->dev_private;
unsigned int i = 0;
unsigned int r;
struct rxq *rxq;
priv_lock(priv);
if (priv->started) {
priv_unlock(priv);
return 0;
}
DEBUG("%p: attaching configured flows to all RX queues", (void *)dev);
priv->started = 1;
if (priv->rss) {
rxq = &priv->rxq_parent;
r = 1;
} else {
rxq = (*priv->rxqs)[0];
r = priv->rxqs_n;
}
/* Iterate only once when RSS is enabled. */
do {
int ret;
/* Ignore nonexistent RX queues. */
if (rxq == NULL)
continue;
ret = rxq_mac_addrs_add(rxq);
if (!ret)
continue;
WARN("%p: QP flow attachment failed: %s",
(void *)dev, strerror(ret));
/* Rollback. */
while (i != 0) {
rxq = (*priv->rxqs)[--i];
if (rxq != NULL) {
rxq_mac_addrs_del(rxq);
}
}
priv->started = 0;
priv_unlock(priv);
return -ret;
} while ((--r) && ((rxq = (*priv->rxqs)[++i]), i));
priv_unlock(priv);
return 0;
}
/**
* DPDK callback to stop the device.
*
* Simulate device stop by detaching all configured flows.
*
* @param dev
* Pointer to Ethernet device structure.
*/
void
mlx5_dev_stop(struct rte_eth_dev *dev)
{
struct priv *priv = dev->data->dev_private;
unsigned int i = 0;
unsigned int r;
struct rxq *rxq;
priv_lock(priv);
if (!priv->started) {
priv_unlock(priv);
return;
}
DEBUG("%p: detaching flows from all RX queues", (void *)dev);
priv->started = 0;
if (priv->rss) {
rxq = &priv->rxq_parent;
r = 1;
} else {
rxq = (*priv->rxqs)[0];
r = priv->rxqs_n;
}
/* Iterate only once when RSS is enabled. */
do {
/* Ignore nonexistent RX queues. */
if (rxq == NULL)
continue;
rxq_mac_addrs_del(rxq);
} while ((--r) && ((rxq = (*priv->rxqs)[++i]), i));
priv_unlock(priv);
}