net/sfc: add port representors infrastructure
Provide minimal implementation for port representors that only can be configured and can provide device information. Signed-off-by: Igor Romanov <igor.romanov@oktetlabs.ru> Signed-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru> Reviewed-by: Andy Moreton <amoreton@xilinx.com> Reviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>
This commit is contained in:
parent
94ddd50165
commit
a62ec90522
@ -74,6 +74,8 @@ SFC EFX PMD has support for:
|
||||
|
||||
- SR-IOV PF
|
||||
|
||||
- Port representors (see :ref: switch_representation)
|
||||
|
||||
|
||||
Non-supported Features
|
||||
----------------------
|
||||
@ -382,7 +384,16 @@ boolean parameters value.
|
||||
software virtual switch (for example, Open vSwitch) makes the decision.
|
||||
Software virtual switch may install MAE rules to pass established traffic
|
||||
flows via hardware and offload software datapath as the result.
|
||||
Default is legacy.
|
||||
Default is legacy, unless representors are specified, in which case switchdev
|
||||
is chosen.
|
||||
|
||||
- ``representor`` parameter [list]
|
||||
|
||||
Instantiate port representor Ethernet devices for specified Virtual
|
||||
Functions list.
|
||||
|
||||
It is a standard parameter whose format is described in
|
||||
:ref:`ethernet_device_standard_device_arguments`.
|
||||
|
||||
- ``rx_datapath`` [auto|efx|ef10|ef10_essb] (default **auto**)
|
||||
|
||||
|
@ -98,4 +98,5 @@ sources = files(
|
||||
'sfc_ef100_tx.c',
|
||||
'sfc_service.c',
|
||||
'sfc_repr_proxy.c',
|
||||
'sfc_repr.c',
|
||||
)
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "sfc_flow.h"
|
||||
#include "sfc_dp.h"
|
||||
#include "sfc_dp_rx.h"
|
||||
#include "sfc_repr.h"
|
||||
#include "sfc_sw_stats.h"
|
||||
|
||||
#define SFC_XSTAT_ID_INVALID_VAL UINT64_MAX
|
||||
@ -1964,6 +1965,10 @@ static const struct eth_dev_ops sfc_eth_dev_ops = {
|
||||
.pool_ops_supported = sfc_pool_ops_supported,
|
||||
};
|
||||
|
||||
struct sfc_ethdev_init_data {
|
||||
uint16_t nb_representors;
|
||||
};
|
||||
|
||||
/**
|
||||
* Duplicate a string in potentially shared memory required for
|
||||
* multi-process support.
|
||||
@ -2243,7 +2248,7 @@ sfc_register_dp(void)
|
||||
}
|
||||
|
||||
static int
|
||||
sfc_parse_switch_mode(struct sfc_adapter *sa)
|
||||
sfc_parse_switch_mode(struct sfc_adapter *sa, bool has_representors)
|
||||
{
|
||||
const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
|
||||
const char *switch_mode = NULL;
|
||||
@ -2258,7 +2263,8 @@ sfc_parse_switch_mode(struct sfc_adapter *sa)
|
||||
|
||||
if (switch_mode == NULL) {
|
||||
sa->switchdev = encp->enc_mae_supported &&
|
||||
!encp->enc_datapath_cap_evb;
|
||||
(!encp->enc_datapath_cap_evb ||
|
||||
has_representors);
|
||||
} else if (strcasecmp(switch_mode, SFC_KVARG_SWITCH_MODE_LEGACY) == 0) {
|
||||
sa->switchdev = false;
|
||||
} else if (strcasecmp(switch_mode,
|
||||
@ -2283,10 +2289,11 @@ fail_kvargs:
|
||||
}
|
||||
|
||||
static int
|
||||
sfc_eth_dev_init(struct rte_eth_dev *dev)
|
||||
sfc_eth_dev_init(struct rte_eth_dev *dev, void *init_params)
|
||||
{
|
||||
struct sfc_adapter_shared *sas = sfc_adapter_shared_by_eth_dev(dev);
|
||||
struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
|
||||
struct sfc_ethdev_init_data *init_data = init_params;
|
||||
uint32_t logtype_main;
|
||||
struct sfc_adapter *sa;
|
||||
int rc;
|
||||
@ -2377,7 +2384,7 @@ sfc_eth_dev_init(struct rte_eth_dev *dev)
|
||||
* Selecting a default switch mode requires the NIC to be probed and
|
||||
* to have its capabilities filled in.
|
||||
*/
|
||||
rc = sfc_parse_switch_mode(sa);
|
||||
rc = sfc_parse_switch_mode(sa, init_data->nb_representors > 0);
|
||||
if (rc != 0)
|
||||
goto fail_switch_mode;
|
||||
|
||||
@ -2462,11 +2469,145 @@ static const struct rte_pci_id pci_id_sfc_efx_map[] = {
|
||||
{ .vendor_id = 0 /* sentinel */ }
|
||||
};
|
||||
|
||||
static int
|
||||
sfc_parse_rte_devargs(const char *args, struct rte_eth_devargs *devargs)
|
||||
{
|
||||
struct rte_eth_devargs eth_da = { .nb_representor_ports = 0 };
|
||||
int rc;
|
||||
|
||||
if (args != NULL) {
|
||||
rc = rte_eth_devargs_parse(args, ð_da);
|
||||
if (rc != 0) {
|
||||
SFC_GENERIC_LOG(ERR,
|
||||
"Failed to parse generic devargs '%s'",
|
||||
args);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
*devargs = eth_da;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sfc_eth_dev_create(struct rte_pci_device *pci_dev,
|
||||
struct sfc_ethdev_init_data *init_data,
|
||||
struct rte_eth_dev **devp)
|
||||
{
|
||||
struct rte_eth_dev *dev;
|
||||
int rc;
|
||||
|
||||
rc = rte_eth_dev_create(&pci_dev->device, pci_dev->device.name,
|
||||
sizeof(struct sfc_adapter_shared),
|
||||
eth_dev_pci_specific_init, pci_dev,
|
||||
sfc_eth_dev_init, init_data);
|
||||
if (rc != 0) {
|
||||
SFC_GENERIC_LOG(ERR, "Failed to create sfc ethdev '%s'",
|
||||
pci_dev->device.name);
|
||||
return rc;
|
||||
}
|
||||
|
||||
dev = rte_eth_dev_allocated(pci_dev->device.name);
|
||||
if (dev == NULL) {
|
||||
SFC_GENERIC_LOG(ERR, "Failed to find allocated sfc ethdev '%s'",
|
||||
pci_dev->device.name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
*devp = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sfc_eth_dev_create_representors(struct rte_eth_dev *dev,
|
||||
const struct rte_eth_devargs *eth_da)
|
||||
{
|
||||
struct sfc_adapter *sa;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
if (eth_da->nb_representor_ports == 0)
|
||||
return 0;
|
||||
|
||||
sa = sfc_adapter_by_eth_dev(dev);
|
||||
|
||||
if (!sa->switchdev) {
|
||||
sfc_err(sa, "cannot create representors in non-switchdev mode");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!sfc_repr_available(sfc_sa2shared(sa))) {
|
||||
sfc_err(sa, "cannot create representors: unsupported");
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
for (i = 0; i < eth_da->nb_representor_ports; ++i) {
|
||||
const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
|
||||
efx_mport_sel_t mport_sel;
|
||||
|
||||
rc = efx_mae_mport_by_pcie_function(encp->enc_pf,
|
||||
eth_da->representor_ports[i], &mport_sel);
|
||||
if (rc != 0) {
|
||||
sfc_err(sa,
|
||||
"failed to get representor %u m-port: %s - ignore",
|
||||
eth_da->representor_ports[i],
|
||||
rte_strerror(-rc));
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = sfc_repr_create(dev, eth_da->representor_ports[i],
|
||||
sa->mae.switch_domain_id, &mport_sel);
|
||||
if (rc != 0) {
|
||||
sfc_err(sa, "cannot create representor %u: %s - ignore",
|
||||
eth_da->representor_ports[i],
|
||||
rte_strerror(-rc));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sfc_eth_dev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
|
||||
struct rte_pci_device *pci_dev)
|
||||
{
|
||||
return rte_eth_dev_pci_generic_probe(pci_dev,
|
||||
sizeof(struct sfc_adapter_shared), sfc_eth_dev_init);
|
||||
struct sfc_ethdev_init_data init_data;
|
||||
struct rte_eth_devargs eth_da;
|
||||
struct rte_eth_dev *dev;
|
||||
int rc;
|
||||
|
||||
if (pci_dev->device.devargs != NULL) {
|
||||
rc = sfc_parse_rte_devargs(pci_dev->device.devargs->args,
|
||||
ð_da);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
} else {
|
||||
memset(ð_da, 0, sizeof(eth_da));
|
||||
}
|
||||
|
||||
init_data.nb_representors = eth_da.nb_representor_ports;
|
||||
|
||||
if (eth_da.nb_representor_ports > 0 &&
|
||||
rte_eal_process_type() != RTE_PROC_PRIMARY) {
|
||||
SFC_GENERIC_LOG(ERR,
|
||||
"Create representors from secondary process not supported, dev '%s'",
|
||||
pci_dev->device.name);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
rc = sfc_eth_dev_create(pci_dev, &init_data, &dev);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
rc = sfc_eth_dev_create_representors(dev, ð_da);
|
||||
if (rc != 0) {
|
||||
(void)rte_eth_dev_destroy(dev, sfc_eth_dev_uninit);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sfc_eth_dev_pci_remove(struct rte_pci_device *pci_dev)
|
||||
|
@ -23,6 +23,7 @@ sfc_kvargs_parse(struct sfc_adapter *sa)
|
||||
struct rte_devargs *devargs = eth_dev->device->devargs;
|
||||
const char **params = (const char *[]){
|
||||
SFC_KVARG_SWITCH_MODE,
|
||||
SFC_KVARG_REPRESENTOR,
|
||||
SFC_KVARG_STATS_UPDATE_PERIOD_MS,
|
||||
SFC_KVARG_PERF_PROFILE,
|
||||
SFC_KVARG_RX_DATAPATH,
|
||||
|
@ -26,6 +26,8 @@ extern "C" {
|
||||
"[" SFC_KVARG_SWITCH_MODE_LEGACY "|" \
|
||||
SFC_KVARG_SWITCH_MODE_SWITCHDEV "]"
|
||||
|
||||
#define SFC_KVARG_REPRESENTOR "representor"
|
||||
|
||||
#define SFC_KVARG_PERF_PROFILE "perf_profile"
|
||||
|
||||
#define SFC_KVARG_PERF_PROFILE_AUTO "auto"
|
||||
|
458
drivers/net/sfc/sfc_repr.c
Normal file
458
drivers/net/sfc/sfc_repr.c
Normal file
@ -0,0 +1,458 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright(c) 2019-2021 Xilinx, Inc.
|
||||
* Copyright(c) 2019 Solarflare Communications Inc.
|
||||
*
|
||||
* This software was jointly developed between OKTET Labs (under contract
|
||||
* for Solarflare) and Solarflare Communications, Inc.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <rte_ethdev.h>
|
||||
#include <rte_malloc.h>
|
||||
#include <ethdev_driver.h>
|
||||
|
||||
#include "efx.h"
|
||||
|
||||
#include "sfc_log.h"
|
||||
#include "sfc_debug.h"
|
||||
#include "sfc_repr.h"
|
||||
#include "sfc_ethdev_state.h"
|
||||
#include "sfc_switch.h"
|
||||
|
||||
/** Multi-process shared representor private data */
|
||||
struct sfc_repr_shared {
|
||||
uint16_t pf_port_id;
|
||||
uint16_t repr_id;
|
||||
uint16_t switch_domain_id;
|
||||
uint16_t switch_port_id;
|
||||
};
|
||||
|
||||
/** Primary process representor private data */
|
||||
struct sfc_repr {
|
||||
/**
|
||||
* PMD setup and configuration is not thread safe. Since it is not
|
||||
* performance sensitive, it is better to guarantee thread-safety
|
||||
* and add device level lock. Adapter control operations which
|
||||
* change its state should acquire the lock.
|
||||
*/
|
||||
rte_spinlock_t lock;
|
||||
enum sfc_ethdev_state state;
|
||||
};
|
||||
|
||||
#define sfcr_err(sr, ...) \
|
||||
do { \
|
||||
const struct sfc_repr *_sr = (sr); \
|
||||
\
|
||||
(void)_sr; \
|
||||
SFC_GENERIC_LOG(ERR, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define sfcr_info(sr, ...) \
|
||||
do { \
|
||||
const struct sfc_repr *_sr = (sr); \
|
||||
\
|
||||
(void)_sr; \
|
||||
SFC_GENERIC_LOG(INFO, \
|
||||
RTE_FMT("%s() " \
|
||||
RTE_FMT_HEAD(__VA_ARGS__ ,), \
|
||||
__func__, \
|
||||
RTE_FMT_TAIL(__VA_ARGS__ ,))); \
|
||||
} while (0)
|
||||
|
||||
static inline struct sfc_repr_shared *
|
||||
sfc_repr_shared_by_eth_dev(struct rte_eth_dev *eth_dev)
|
||||
{
|
||||
struct sfc_repr_shared *srs = eth_dev->data->dev_private;
|
||||
|
||||
return srs;
|
||||
}
|
||||
|
||||
static inline struct sfc_repr *
|
||||
sfc_repr_by_eth_dev(struct rte_eth_dev *eth_dev)
|
||||
{
|
||||
struct sfc_repr *sr = eth_dev->process_private;
|
||||
|
||||
return sr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add wrapper functions to acquire/release lock to be able to remove or
|
||||
* change the lock in one place.
|
||||
*/
|
||||
|
||||
static inline void
|
||||
sfc_repr_lock_init(struct sfc_repr *sr)
|
||||
{
|
||||
rte_spinlock_init(&sr->lock);
|
||||
}
|
||||
|
||||
#if defined(RTE_LIBRTE_SFC_EFX_DEBUG) || defined(RTE_ENABLE_ASSERT)
|
||||
|
||||
static inline int
|
||||
sfc_repr_lock_is_locked(struct sfc_repr *sr)
|
||||
{
|
||||
return rte_spinlock_is_locked(&sr->lock);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
sfc_repr_lock(struct sfc_repr *sr)
|
||||
{
|
||||
rte_spinlock_lock(&sr->lock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
sfc_repr_unlock(struct sfc_repr *sr)
|
||||
{
|
||||
rte_spinlock_unlock(&sr->lock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
sfc_repr_lock_fini(__rte_unused struct sfc_repr *sr)
|
||||
{
|
||||
/* Just for symmetry of the API */
|
||||
}
|
||||
|
||||
static int
|
||||
sfc_repr_check_conf(struct sfc_repr *sr, uint16_t nb_rx_queues,
|
||||
const struct rte_eth_conf *conf)
|
||||
{
|
||||
const struct rte_eth_rss_conf *rss_conf;
|
||||
int ret = 0;
|
||||
|
||||
sfcr_info(sr, "entry");
|
||||
|
||||
if (conf->link_speeds != 0) {
|
||||
sfcr_err(sr, "specific link speeds not supported");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
switch (conf->rxmode.mq_mode) {
|
||||
case ETH_MQ_RX_RSS:
|
||||
if (nb_rx_queues != 1) {
|
||||
sfcr_err(sr, "Rx RSS is not supported with %u queues",
|
||||
nb_rx_queues);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
rss_conf = &conf->rx_adv_conf.rss_conf;
|
||||
if (rss_conf->rss_key != NULL || rss_conf->rss_key_len != 0 ||
|
||||
rss_conf->rss_hf != 0) {
|
||||
sfcr_err(sr, "Rx RSS configuration is not supported");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
case ETH_MQ_RX_NONE:
|
||||
break;
|
||||
default:
|
||||
sfcr_err(sr, "Rx mode MQ modes other than RSS not supported");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (conf->txmode.mq_mode != ETH_MQ_TX_NONE) {
|
||||
sfcr_err(sr, "Tx mode MQ modes not supported");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (conf->lpbk_mode != 0) {
|
||||
sfcr_err(sr, "loopback not supported");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (conf->dcb_capability_en != 0) {
|
||||
sfcr_err(sr, "priority-based flow control not supported");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (conf->fdir_conf.mode != RTE_FDIR_MODE_NONE) {
|
||||
sfcr_err(sr, "Flow Director not supported");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (conf->intr_conf.lsc != 0) {
|
||||
sfcr_err(sr, "link status change interrupt not supported");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (conf->intr_conf.rxq != 0) {
|
||||
sfcr_err(sr, "receive queue interrupt not supported");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (conf->intr_conf.rmv != 0) {
|
||||
sfcr_err(sr, "remove interrupt not supported");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
sfcr_info(sr, "done %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
sfc_repr_configure(struct sfc_repr *sr, uint16_t nb_rx_queues,
|
||||
const struct rte_eth_conf *conf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
sfcr_info(sr, "entry");
|
||||
|
||||
SFC_ASSERT(sfc_repr_lock_is_locked(sr));
|
||||
|
||||
ret = sfc_repr_check_conf(sr, nb_rx_queues, conf);
|
||||
if (ret != 0)
|
||||
goto fail_check_conf;
|
||||
|
||||
sr->state = SFC_ETHDEV_CONFIGURED;
|
||||
|
||||
sfcr_info(sr, "done");
|
||||
|
||||
return 0;
|
||||
|
||||
fail_check_conf:
|
||||
sfcr_info(sr, "failed %s", rte_strerror(-ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
sfc_repr_dev_configure(struct rte_eth_dev *dev)
|
||||
{
|
||||
struct sfc_repr *sr = sfc_repr_by_eth_dev(dev);
|
||||
struct rte_eth_dev_data *dev_data = dev->data;
|
||||
int ret;
|
||||
|
||||
sfcr_info(sr, "entry n_rxq=%u n_txq=%u",
|
||||
dev_data->nb_rx_queues, dev_data->nb_tx_queues);
|
||||
|
||||
sfc_repr_lock(sr);
|
||||
switch (sr->state) {
|
||||
case SFC_ETHDEV_CONFIGURED:
|
||||
/* FALLTHROUGH */
|
||||
case SFC_ETHDEV_INITIALIZED:
|
||||
ret = sfc_repr_configure(sr, dev_data->nb_rx_queues,
|
||||
&dev_data->dev_conf);
|
||||
break;
|
||||
default:
|
||||
sfcr_err(sr, "unexpected adapter state %u to configure",
|
||||
sr->state);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
sfc_repr_unlock(sr);
|
||||
|
||||
sfcr_info(sr, "done %s", rte_strerror(-ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
sfc_repr_dev_infos_get(struct rte_eth_dev *dev,
|
||||
struct rte_eth_dev_info *dev_info)
|
||||
{
|
||||
struct sfc_repr_shared *srs = sfc_repr_shared_by_eth_dev(dev);
|
||||
|
||||
dev_info->device = dev->device;
|
||||
|
||||
dev_info->max_rx_queues = SFC_REPR_RXQ_MAX;
|
||||
dev_info->max_tx_queues = SFC_REPR_TXQ_MAX;
|
||||
dev_info->default_rxconf.rx_drop_en = 1;
|
||||
dev_info->switch_info.domain_id = srs->switch_domain_id;
|
||||
dev_info->switch_info.port_id = srs->switch_port_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sfc_repr_close(struct sfc_repr *sr)
|
||||
{
|
||||
SFC_ASSERT(sfc_repr_lock_is_locked(sr));
|
||||
|
||||
SFC_ASSERT(sr->state == SFC_ETHDEV_CONFIGURED);
|
||||
sr->state = SFC_ETHDEV_CLOSING;
|
||||
|
||||
/* Put representor close actions here */
|
||||
|
||||
sr->state = SFC_ETHDEV_INITIALIZED;
|
||||
}
|
||||
|
||||
static int
|
||||
sfc_repr_dev_close(struct rte_eth_dev *dev)
|
||||
{
|
||||
struct sfc_repr *sr = sfc_repr_by_eth_dev(dev);
|
||||
|
||||
sfcr_info(sr, "entry");
|
||||
|
||||
sfc_repr_lock(sr);
|
||||
switch (sr->state) {
|
||||
case SFC_ETHDEV_CONFIGURED:
|
||||
sfc_repr_close(sr);
|
||||
SFC_ASSERT(sr->state == SFC_ETHDEV_INITIALIZED);
|
||||
/* FALLTHROUGH */
|
||||
case SFC_ETHDEV_INITIALIZED:
|
||||
break;
|
||||
default:
|
||||
sfcr_err(sr, "unexpected adapter state %u on close", sr->state);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup all resources.
|
||||
* Rollback primary process sfc_repr_eth_dev_init() below.
|
||||
*/
|
||||
|
||||
dev->dev_ops = NULL;
|
||||
|
||||
sfc_repr_unlock(sr);
|
||||
sfc_repr_lock_fini(sr);
|
||||
|
||||
sfcr_info(sr, "done");
|
||||
|
||||
free(sr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct eth_dev_ops sfc_repr_dev_ops = {
|
||||
.dev_configure = sfc_repr_dev_configure,
|
||||
.dev_close = sfc_repr_dev_close,
|
||||
.dev_infos_get = sfc_repr_dev_infos_get,
|
||||
};
|
||||
|
||||
|
||||
struct sfc_repr_init_data {
|
||||
uint16_t pf_port_id;
|
||||
uint16_t repr_id;
|
||||
uint16_t switch_domain_id;
|
||||
efx_mport_sel_t mport_sel;
|
||||
};
|
||||
|
||||
static int
|
||||
sfc_repr_assign_mae_switch_port(uint16_t switch_domain_id,
|
||||
const struct sfc_mae_switch_port_request *req,
|
||||
uint16_t *switch_port_id)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = sfc_mae_assign_switch_port(switch_domain_id, req, switch_port_id);
|
||||
|
||||
SFC_ASSERT(rc >= 0);
|
||||
return -rc;
|
||||
}
|
||||
|
||||
static int
|
||||
sfc_repr_eth_dev_init(struct rte_eth_dev *dev, void *init_params)
|
||||
{
|
||||
const struct sfc_repr_init_data *repr_data = init_params;
|
||||
struct sfc_repr_shared *srs = sfc_repr_shared_by_eth_dev(dev);
|
||||
struct sfc_mae_switch_port_request switch_port_request;
|
||||
efx_mport_sel_t ethdev_mport_sel;
|
||||
struct sfc_repr *sr;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Currently there is no mport we can use for representor's
|
||||
* ethdev. Use an invalid one for now. This way representors
|
||||
* can be instantiated.
|
||||
*/
|
||||
efx_mae_mport_invalid(ðdev_mport_sel);
|
||||
|
||||
memset(&switch_port_request, 0, sizeof(switch_port_request));
|
||||
switch_port_request.type = SFC_MAE_SWITCH_PORT_REPRESENTOR;
|
||||
switch_port_request.ethdev_mportp = ðdev_mport_sel;
|
||||
switch_port_request.entity_mportp = &repr_data->mport_sel;
|
||||
switch_port_request.ethdev_port_id = dev->data->port_id;
|
||||
|
||||
ret = sfc_repr_assign_mae_switch_port(repr_data->switch_domain_id,
|
||||
&switch_port_request,
|
||||
&srs->switch_port_id);
|
||||
if (ret != 0) {
|
||||
SFC_GENERIC_LOG(ERR,
|
||||
"%s() failed to assign MAE switch port (domain id %u)",
|
||||
__func__, repr_data->switch_domain_id);
|
||||
goto fail_mae_assign_switch_port;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate process private data from heap, since it should not
|
||||
* be located in shared memory allocated using rte_malloc() API.
|
||||
*/
|
||||
sr = calloc(1, sizeof(*sr));
|
||||
if (sr == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_alloc_sr;
|
||||
}
|
||||
|
||||
sfc_repr_lock_init(sr);
|
||||
sfc_repr_lock(sr);
|
||||
|
||||
dev->process_private = sr;
|
||||
|
||||
srs->pf_port_id = repr_data->pf_port_id;
|
||||
srs->repr_id = repr_data->repr_id;
|
||||
srs->switch_domain_id = repr_data->switch_domain_id;
|
||||
|
||||
dev->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR;
|
||||
dev->data->representor_id = srs->repr_id;
|
||||
dev->data->backer_port_id = srs->pf_port_id;
|
||||
|
||||
dev->data->mac_addrs = rte_zmalloc("sfcr", RTE_ETHER_ADDR_LEN, 0);
|
||||
if (dev->data->mac_addrs == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_mac_addrs;
|
||||
}
|
||||
|
||||
dev->dev_ops = &sfc_repr_dev_ops;
|
||||
|
||||
sr->state = SFC_ETHDEV_INITIALIZED;
|
||||
sfc_repr_unlock(sr);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_mac_addrs:
|
||||
sfc_repr_unlock(sr);
|
||||
free(sr);
|
||||
|
||||
fail_alloc_sr:
|
||||
fail_mae_assign_switch_port:
|
||||
SFC_GENERIC_LOG(ERR, "%s() failed: %s", __func__, rte_strerror(-ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
sfc_repr_create(struct rte_eth_dev *parent, uint16_t representor_id,
|
||||
uint16_t switch_domain_id, const efx_mport_sel_t *mport_sel)
|
||||
{
|
||||
struct sfc_repr_init_data repr_data;
|
||||
char name[RTE_ETH_NAME_MAX_LEN];
|
||||
int ret;
|
||||
|
||||
if (snprintf(name, sizeof(name), "net_%s_representor_%u",
|
||||
parent->device->name, representor_id) >=
|
||||
(int)sizeof(name)) {
|
||||
SFC_GENERIC_LOG(ERR, "%s() failed name too long", __func__);
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
|
||||
memset(&repr_data, 0, sizeof(repr_data));
|
||||
repr_data.pf_port_id = parent->data->port_id;
|
||||
repr_data.repr_id = representor_id;
|
||||
repr_data.switch_domain_id = switch_domain_id;
|
||||
repr_data.mport_sel = *mport_sel;
|
||||
|
||||
ret = rte_eth_dev_create(parent->device, name,
|
||||
sizeof(struct sfc_repr_shared),
|
||||
NULL, NULL,
|
||||
sfc_repr_eth_dev_init, &repr_data);
|
||||
if (ret != 0)
|
||||
SFC_GENERIC_LOG(ERR, "%s() failed to create device", __func__);
|
||||
|
||||
SFC_GENERIC_LOG(INFO, "%s() done: %s", __func__, rte_strerror(-ret));
|
||||
|
||||
return ret;
|
||||
}
|
36
drivers/net/sfc/sfc_repr.h
Normal file
36
drivers/net/sfc/sfc_repr.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright(c) 2019-2021 Xilinx, Inc.
|
||||
* Copyright(c) 2019 Solarflare Communications Inc.
|
||||
*
|
||||
* This software was jointly developed between OKTET Labs (under contract
|
||||
* for Solarflare) and Solarflare Communications, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _SFC_REPR_H
|
||||
#define _SFC_REPR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <rte_ethdev.h>
|
||||
|
||||
#include "efx.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Max count of the representor Rx queues */
|
||||
#define SFC_REPR_RXQ_MAX 1
|
||||
|
||||
/** Max count of the representor Tx queues */
|
||||
#define SFC_REPR_TXQ_MAX 1
|
||||
|
||||
int sfc_repr_create(struct rte_eth_dev *parent, uint16_t representor_id,
|
||||
uint16_t switch_domain_id,
|
||||
const efx_mport_sel_t *mport_sel);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _SFC_REPR_H */
|
@ -27,6 +27,11 @@ enum sfc_mae_switch_port_type {
|
||||
* and thus refers to its underlying PCIe function
|
||||
*/
|
||||
SFC_MAE_SWITCH_PORT_INDEPENDENT = 0,
|
||||
/**
|
||||
* The switch port is operated by a representor RTE ethdev
|
||||
* and thus refers to the represented PCIe function
|
||||
*/
|
||||
SFC_MAE_SWITCH_PORT_REPRESENTOR,
|
||||
};
|
||||
|
||||
struct sfc_mae_switch_port_request {
|
||||
|
Loading…
x
Reference in New Issue
Block a user