numam-dpdk/drivers/net/enic/enic_ethdev.c
Hyong Youb Kim 93fb21fdbe net/enic: enable overlay offload for VXLAN and GENEVE
Recent NIC models support overlay offload. The overlay offload
feature enables the following on the NIC.
- Rx/Tx checksum offloads for both inner and outer packets.
- Rx inner packet type classification.
- TSO.
- Inner RSS.

TX descriptors do not require any changes, except the header length
for TSO. The NIC parses outer/inner packets and performs offloads on
them as necessary. The header length for tunneled TSO includes both
inner and outer headers.

The NIC actually parses and performs the above for NVGRE as well. DPDK
currently has no offload flags for NVGRE, and the hardware has no
controls to individually enable tunnel types either. So do nothing for
now.

The driver enables overlay offload by default. Add a devargs
'disable-overlay=<0|1>' to allow the app to disable it.

Also update the enic guide doc.

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
2018-04-27 15:54:55 +01:00

918 lines
23 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright 2008-2017 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*/
#include <stdio.h>
#include <stdint.h>
#include <rte_dev.h>
#include <rte_pci.h>
#include <rte_bus_pci.h>
#include <rte_ethdev_driver.h>
#include <rte_ethdev_pci.h>
#include <rte_kvargs.h>
#include <rte_string_fns.h>
#include "vnic_intr.h"
#include "vnic_cq.h"
#include "vnic_wq.h"
#include "vnic_rq.h"
#include "vnic_enet.h"
#include "enic.h"
int enicpmd_logtype_init;
int enicpmd_logtype_flow;
#define PMD_INIT_LOG(level, fmt, args...) \
rte_log(RTE_LOG_ ## level, enicpmd_logtype_init, \
"%s" fmt "\n", __func__, ##args)
#define ENICPMD_FUNC_TRACE() PMD_INIT_LOG(DEBUG, " >>")
/*
* The set of PCI devices this driver supports
*/
#define CISCO_PCI_VENDOR_ID 0x1137
static const struct rte_pci_id pci_id_enic_map[] = {
{ RTE_PCI_DEVICE(CISCO_PCI_VENDOR_ID, PCI_DEVICE_ID_CISCO_VIC_ENET) },
{ RTE_PCI_DEVICE(CISCO_PCI_VENDOR_ID, PCI_DEVICE_ID_CISCO_VIC_ENET_VF) },
{.vendor_id = 0, /* sentinel */},
};
#define ENIC_DEVARG_DISABLE_OVERLAY "disable-overlay"
RTE_INIT(enicpmd_init_log);
static void
enicpmd_init_log(void)
{
enicpmd_logtype_init = rte_log_register("pmd.net.enic.init");
if (enicpmd_logtype_init >= 0)
rte_log_set_level(enicpmd_logtype_init, RTE_LOG_NOTICE);
enicpmd_logtype_flow = rte_log_register("pmd.net.enic.flow");
if (enicpmd_logtype_flow >= 0)
rte_log_set_level(enicpmd_logtype_flow, RTE_LOG_NOTICE);
}
static int
enicpmd_fdir_ctrl_func(struct rte_eth_dev *eth_dev,
enum rte_filter_op filter_op, void *arg)
{
struct enic *enic = pmd_priv(eth_dev);
int ret = 0;
ENICPMD_FUNC_TRACE();
if (filter_op == RTE_ETH_FILTER_NOP)
return 0;
if (arg == NULL && filter_op != RTE_ETH_FILTER_FLUSH)
return -EINVAL;
switch (filter_op) {
case RTE_ETH_FILTER_ADD:
case RTE_ETH_FILTER_UPDATE:
ret = enic_fdir_add_fltr(enic,
(struct rte_eth_fdir_filter *)arg);
break;
case RTE_ETH_FILTER_DELETE:
ret = enic_fdir_del_fltr(enic,
(struct rte_eth_fdir_filter *)arg);
break;
case RTE_ETH_FILTER_STATS:
enic_fdir_stats_get(enic, (struct rte_eth_fdir_stats *)arg);
break;
case RTE_ETH_FILTER_FLUSH:
dev_warning(enic, "unsupported operation %u", filter_op);
ret = -ENOTSUP;
break;
case RTE_ETH_FILTER_INFO:
enic_fdir_info_get(enic, (struct rte_eth_fdir_info *)arg);
break;
default:
dev_err(enic, "unknown operation %u", filter_op);
ret = -EINVAL;
break;
}
return ret;
}
static int
enicpmd_dev_filter_ctrl(struct rte_eth_dev *dev,
enum rte_filter_type filter_type,
enum rte_filter_op filter_op,
void *arg)
{
int ret = 0;
ENICPMD_FUNC_TRACE();
switch (filter_type) {
case RTE_ETH_FILTER_GENERIC:
if (filter_op != RTE_ETH_FILTER_GET)
return -EINVAL;
*(const void **)arg = &enic_flow_ops;
break;
case RTE_ETH_FILTER_FDIR:
ret = enicpmd_fdir_ctrl_func(dev, filter_op, arg);
break;
default:
dev_warning(enic, "Filter type (%d) not supported",
filter_type);
ret = -EINVAL;
break;
}
return ret;
}
static void enicpmd_dev_tx_queue_release(void *txq)
{
ENICPMD_FUNC_TRACE();
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return;
enic_free_wq(txq);
}
static int enicpmd_dev_setup_intr(struct enic *enic)
{
int ret;
unsigned int index;
ENICPMD_FUNC_TRACE();
/* Are we done with the init of all the queues? */
for (index = 0; index < enic->cq_count; index++) {
if (!enic->cq[index].ctrl)
break;
}
if (enic->cq_count != index)
return 0;
for (index = 0; index < enic->wq_count; index++) {
if (!enic->wq[index].ctrl)
break;
}
if (enic->wq_count != index)
return 0;
/* check start of packet (SOP) RQs only in case scatter is disabled. */
for (index = 0; index < enic->rq_count; index++) {
if (!enic->rq[enic_rte_rq_idx_to_sop_idx(index)].ctrl)
break;
}
if (enic->rq_count != index)
return 0;
ret = enic_alloc_intr_resources(enic);
if (ret) {
dev_err(enic, "alloc intr failed\n");
return ret;
}
enic_init_vnic_resources(enic);
ret = enic_setup_finish(enic);
if (ret)
dev_err(enic, "setup could not be finished\n");
return ret;
}
static int enicpmd_dev_tx_queue_setup(struct rte_eth_dev *eth_dev,
uint16_t queue_idx,
uint16_t nb_desc,
unsigned int socket_id,
__rte_unused const struct rte_eth_txconf *tx_conf)
{
int ret;
struct enic *enic = pmd_priv(eth_dev);
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return -E_RTE_SECONDARY;
ENICPMD_FUNC_TRACE();
RTE_ASSERT(queue_idx < enic->conf_wq_count);
eth_dev->data->tx_queues[queue_idx] = (void *)&enic->wq[queue_idx];
ret = enic_alloc_wq(enic, queue_idx, socket_id, nb_desc);
if (ret) {
dev_err(enic, "error in allocating wq\n");
return ret;
}
return enicpmd_dev_setup_intr(enic);
}
static int enicpmd_dev_tx_queue_start(struct rte_eth_dev *eth_dev,
uint16_t queue_idx)
{
struct enic *enic = pmd_priv(eth_dev);
ENICPMD_FUNC_TRACE();
enic_start_wq(enic, queue_idx);
return 0;
}
static int enicpmd_dev_tx_queue_stop(struct rte_eth_dev *eth_dev,
uint16_t queue_idx)
{
int ret;
struct enic *enic = pmd_priv(eth_dev);
ENICPMD_FUNC_TRACE();
ret = enic_stop_wq(enic, queue_idx);
if (ret)
dev_err(enic, "error in stopping wq %d\n", queue_idx);
return ret;
}
static int enicpmd_dev_rx_queue_start(struct rte_eth_dev *eth_dev,
uint16_t queue_idx)
{
struct enic *enic = pmd_priv(eth_dev);
ENICPMD_FUNC_TRACE();
enic_start_rq(enic, queue_idx);
return 0;
}
static int enicpmd_dev_rx_queue_stop(struct rte_eth_dev *eth_dev,
uint16_t queue_idx)
{
int ret;
struct enic *enic = pmd_priv(eth_dev);
ENICPMD_FUNC_TRACE();
ret = enic_stop_rq(enic, queue_idx);
if (ret)
dev_err(enic, "error in stopping rq %d\n", queue_idx);
return ret;
}
static void enicpmd_dev_rx_queue_release(void *rxq)
{
ENICPMD_FUNC_TRACE();
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return;
enic_free_rq(rxq);
}
static uint32_t enicpmd_dev_rx_queue_count(struct rte_eth_dev *dev,
uint16_t rx_queue_id)
{
struct enic *enic = pmd_priv(dev);
uint32_t queue_count = 0;
struct vnic_cq *cq;
uint32_t cq_tail;
uint16_t cq_idx;
int rq_num;
rq_num = enic_rte_rq_idx_to_sop_idx(rx_queue_id);
cq = &enic->cq[enic_cq_rq(enic, rq_num)];
cq_idx = cq->to_clean;
cq_tail = ioread32(&cq->ctrl->cq_tail);
if (cq_tail < cq_idx)
cq_tail += cq->ring.desc_count;
queue_count = cq_tail - cq_idx;
return queue_count;
}
static int enicpmd_dev_rx_queue_setup(struct rte_eth_dev *eth_dev,
uint16_t queue_idx,
uint16_t nb_desc,
unsigned int socket_id,
const struct rte_eth_rxconf *rx_conf,
struct rte_mempool *mp)
{
int ret;
struct enic *enic = pmd_priv(eth_dev);
ENICPMD_FUNC_TRACE();
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return -E_RTE_SECONDARY;
RTE_ASSERT(enic_rte_rq_idx_to_sop_idx(queue_idx) < enic->conf_rq_count);
eth_dev->data->rx_queues[queue_idx] =
(void *)&enic->rq[enic_rte_rq_idx_to_sop_idx(queue_idx)];
ret = enic_alloc_rq(enic, queue_idx, socket_id, mp, nb_desc,
rx_conf->rx_free_thresh);
if (ret) {
dev_err(enic, "error in allocating rq\n");
return ret;
}
return enicpmd_dev_setup_intr(enic);
}
static int enicpmd_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
{
struct enic *enic = pmd_priv(eth_dev);
uint64_t offloads;
ENICPMD_FUNC_TRACE();
offloads = eth_dev->data->dev_conf.rxmode.offloads;
if (mask & ETH_VLAN_STRIP_MASK) {
if (offloads & DEV_RX_OFFLOAD_VLAN_STRIP)
enic->ig_vlan_strip_en = 1;
else
enic->ig_vlan_strip_en = 0;
}
if ((mask & ETH_VLAN_FILTER_MASK) &&
(offloads & DEV_RX_OFFLOAD_VLAN_FILTER)) {
dev_warning(enic,
"Configuration of VLAN filter is not supported\n");
}
if ((mask & ETH_VLAN_EXTEND_MASK) &&
(offloads & DEV_RX_OFFLOAD_VLAN_EXTEND)) {
dev_warning(enic,
"Configuration of extended VLAN is not supported\n");
}
return enic_set_vlan_strip(enic);
}
static int enicpmd_dev_configure(struct rte_eth_dev *eth_dev)
{
int ret;
int mask;
struct enic *enic = pmd_priv(eth_dev);
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return -E_RTE_SECONDARY;
ENICPMD_FUNC_TRACE();
ret = enic_set_vnic_res(enic);
if (ret) {
dev_err(enic, "Set vNIC resource num failed, aborting\n");
return ret;
}
enic->hw_ip_checksum = !!(eth_dev->data->dev_conf.rxmode.offloads &
DEV_RX_OFFLOAD_CHECKSUM);
/* All vlan offload masks to apply the current settings */
mask = ETH_VLAN_STRIP_MASK |
ETH_VLAN_FILTER_MASK |
ETH_VLAN_EXTEND_MASK;
ret = enicpmd_vlan_offload_set(eth_dev, mask);
if (ret) {
dev_err(enic, "Failed to configure VLAN offloads\n");
return ret;
}
/*
* Initialize RSS with the default reta and key. If the user key is
* given (rx_adv_conf.rss_conf.rss_key), will use that instead of the
* default key.
*/
return enic_init_rss_nic_cfg(enic);
}
/* Start the device.
* It returns 0 on success.
*/
static int enicpmd_dev_start(struct rte_eth_dev *eth_dev)
{
struct enic *enic = pmd_priv(eth_dev);
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return -E_RTE_SECONDARY;
ENICPMD_FUNC_TRACE();
return enic_enable(enic);
}
/*
* Stop device: disable rx and tx functions to allow for reconfiguring.
*/
static void enicpmd_dev_stop(struct rte_eth_dev *eth_dev)
{
struct rte_eth_link link;
struct enic *enic = pmd_priv(eth_dev);
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return;
ENICPMD_FUNC_TRACE();
enic_disable(enic);
memset(&link, 0, sizeof(link));
rte_eth_linkstatus_set(eth_dev, &link);
}
/*
* Stop device.
*/
static void enicpmd_dev_close(struct rte_eth_dev *eth_dev)
{
struct enic *enic = pmd_priv(eth_dev);
ENICPMD_FUNC_TRACE();
enic_remove(enic);
}
static int enicpmd_dev_link_update(struct rte_eth_dev *eth_dev,
__rte_unused int wait_to_complete)
{
struct enic *enic = pmd_priv(eth_dev);
ENICPMD_FUNC_TRACE();
return enic_link_update(enic);
}
static int enicpmd_dev_stats_get(struct rte_eth_dev *eth_dev,
struct rte_eth_stats *stats)
{
struct enic *enic = pmd_priv(eth_dev);
ENICPMD_FUNC_TRACE();
return enic_dev_stats_get(enic, stats);
}
static void enicpmd_dev_stats_reset(struct rte_eth_dev *eth_dev)
{
struct enic *enic = pmd_priv(eth_dev);
ENICPMD_FUNC_TRACE();
enic_dev_stats_clear(enic);
}
static void enicpmd_dev_info_get(struct rte_eth_dev *eth_dev,
struct rte_eth_dev_info *device_info)
{
struct enic *enic = pmd_priv(eth_dev);
ENICPMD_FUNC_TRACE();
/* Scattered Rx uses two receive queues per rx queue exposed to dpdk */
device_info->max_rx_queues = enic->conf_rq_count / 2;
device_info->max_tx_queues = enic->conf_wq_count;
device_info->min_rx_bufsize = ENIC_MIN_MTU;
/* "Max" mtu is not a typo. HW receives packet sizes up to the
* max mtu regardless of the current mtu (vNIC's mtu). vNIC mtu is
* a hint to the driver to size receive buffers accordingly so that
* larger-than-vnic-mtu packets get truncated.. For DPDK, we let
* the user decide the buffer size via rxmode.max_rx_pkt_len, basically
* ignoring vNIC mtu.
*/
device_info->max_rx_pktlen = enic_mtu_to_max_rx_pktlen(enic->max_mtu);
device_info->max_mac_addrs = ENIC_MAX_MAC_ADDR;
device_info->rx_offload_capa = enic->rx_offload_capa;
device_info->tx_offload_capa = enic->tx_offload_capa;
device_info->default_rxconf = (struct rte_eth_rxconf) {
.rx_free_thresh = ENIC_DEFAULT_RX_FREE_THRESH
};
device_info->reta_size = enic->reta_size;
device_info->hash_key_size = enic->hash_key_size;
device_info->flow_type_rss_offloads = enic->flow_type_rss_offloads;
}
static const uint32_t *enicpmd_dev_supported_ptypes_get(struct rte_eth_dev *dev)
{
static const uint32_t ptypes[] = {
RTE_PTYPE_L2_ETHER,
RTE_PTYPE_L2_ETHER_VLAN,
RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
RTE_PTYPE_L3_IPV6_EXT_UNKNOWN,
RTE_PTYPE_L4_TCP,
RTE_PTYPE_L4_UDP,
RTE_PTYPE_L4_FRAG,
RTE_PTYPE_L4_NONFRAG,
RTE_PTYPE_UNKNOWN
};
if (dev->rx_pkt_burst == enic_recv_pkts)
return ptypes;
return NULL;
}
static void enicpmd_dev_promiscuous_enable(struct rte_eth_dev *eth_dev)
{
struct enic *enic = pmd_priv(eth_dev);
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return;
ENICPMD_FUNC_TRACE();
enic->promisc = 1;
enic_add_packet_filter(enic);
}
static void enicpmd_dev_promiscuous_disable(struct rte_eth_dev *eth_dev)
{
struct enic *enic = pmd_priv(eth_dev);
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return;
ENICPMD_FUNC_TRACE();
enic->promisc = 0;
enic_add_packet_filter(enic);
}
static void enicpmd_dev_allmulticast_enable(struct rte_eth_dev *eth_dev)
{
struct enic *enic = pmd_priv(eth_dev);
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return;
ENICPMD_FUNC_TRACE();
enic->allmulti = 1;
enic_add_packet_filter(enic);
}
static void enicpmd_dev_allmulticast_disable(struct rte_eth_dev *eth_dev)
{
struct enic *enic = pmd_priv(eth_dev);
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return;
ENICPMD_FUNC_TRACE();
enic->allmulti = 0;
enic_add_packet_filter(enic);
}
static int enicpmd_add_mac_addr(struct rte_eth_dev *eth_dev,
struct ether_addr *mac_addr,
__rte_unused uint32_t index, __rte_unused uint32_t pool)
{
struct enic *enic = pmd_priv(eth_dev);
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return -E_RTE_SECONDARY;
ENICPMD_FUNC_TRACE();
return enic_set_mac_address(enic, mac_addr->addr_bytes);
}
static void enicpmd_remove_mac_addr(struct rte_eth_dev *eth_dev, uint32_t index)
{
struct enic *enic = pmd_priv(eth_dev);
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return;
ENICPMD_FUNC_TRACE();
if (enic_del_mac_address(enic, index))
dev_err(enic, "del mac addr failed\n");
}
static int enicpmd_set_mac_addr(struct rte_eth_dev *eth_dev,
struct ether_addr *addr)
{
struct enic *enic = pmd_priv(eth_dev);
int ret;
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
return -E_RTE_SECONDARY;
ENICPMD_FUNC_TRACE();
ret = enic_del_mac_address(enic, 0);
if (ret)
return ret;
return enic_set_mac_address(enic, addr->addr_bytes);
}
static int enicpmd_mtu_set(struct rte_eth_dev *eth_dev, uint16_t mtu)
{
struct enic *enic = pmd_priv(eth_dev);
ENICPMD_FUNC_TRACE();
return enic_set_mtu(enic, mtu);
}
static int enicpmd_dev_rss_reta_query(struct rte_eth_dev *dev,
struct rte_eth_rss_reta_entry64
*reta_conf,
uint16_t reta_size)
{
struct enic *enic = pmd_priv(dev);
uint16_t i, idx, shift;
ENICPMD_FUNC_TRACE();
if (reta_size != ENIC_RSS_RETA_SIZE) {
dev_err(enic, "reta_query: wrong reta_size. given=%u expected=%u\n",
reta_size, ENIC_RSS_RETA_SIZE);
return -EINVAL;
}
for (i = 0; i < reta_size; i++) {
idx = i / RTE_RETA_GROUP_SIZE;
shift = i % RTE_RETA_GROUP_SIZE;
if (reta_conf[idx].mask & (1ULL << shift))
reta_conf[idx].reta[shift] = enic_sop_rq_idx_to_rte_idx(
enic->rss_cpu.cpu[i / 4].b[i % 4]);
}
return 0;
}
static int enicpmd_dev_rss_reta_update(struct rte_eth_dev *dev,
struct rte_eth_rss_reta_entry64
*reta_conf,
uint16_t reta_size)
{
struct enic *enic = pmd_priv(dev);
union vnic_rss_cpu rss_cpu;
uint16_t i, idx, shift;
ENICPMD_FUNC_TRACE();
if (reta_size != ENIC_RSS_RETA_SIZE) {
dev_err(enic, "reta_update: wrong reta_size. given=%u"
" expected=%u\n",
reta_size, ENIC_RSS_RETA_SIZE);
return -EINVAL;
}
/*
* Start with the current reta and modify it per reta_conf, as we
* need to push the entire reta even if we only modify one entry.
*/
rss_cpu = enic->rss_cpu;
for (i = 0; i < reta_size; i++) {
idx = i / RTE_RETA_GROUP_SIZE;
shift = i % RTE_RETA_GROUP_SIZE;
if (reta_conf[idx].mask & (1ULL << shift))
rss_cpu.cpu[i / 4].b[i % 4] =
enic_rte_rq_idx_to_sop_idx(
reta_conf[idx].reta[shift]);
}
return enic_set_rss_reta(enic, &rss_cpu);
}
static int enicpmd_dev_rss_hash_update(struct rte_eth_dev *dev,
struct rte_eth_rss_conf *rss_conf)
{
struct enic *enic = pmd_priv(dev);
ENICPMD_FUNC_TRACE();
return enic_set_rss_conf(enic, rss_conf);
}
static int enicpmd_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
struct rte_eth_rss_conf *rss_conf)
{
struct enic *enic = pmd_priv(dev);
ENICPMD_FUNC_TRACE();
if (rss_conf == NULL)
return -EINVAL;
if (rss_conf->rss_key != NULL &&
rss_conf->rss_key_len < ENIC_RSS_HASH_KEY_SIZE) {
dev_err(enic, "rss_hash_conf_get: wrong rss_key_len. given=%u"
" expected=%u+\n",
rss_conf->rss_key_len, ENIC_RSS_HASH_KEY_SIZE);
return -EINVAL;
}
rss_conf->rss_hf = enic->rss_hf;
if (rss_conf->rss_key != NULL) {
int i;
for (i = 0; i < ENIC_RSS_HASH_KEY_SIZE; i++) {
rss_conf->rss_key[i] =
enic->rss_key.key[i / 10].b[i % 10];
}
rss_conf->rss_key_len = ENIC_RSS_HASH_KEY_SIZE;
}
return 0;
}
static void enicpmd_dev_rxq_info_get(struct rte_eth_dev *dev,
uint16_t rx_queue_id,
struct rte_eth_rxq_info *qinfo)
{
struct enic *enic = pmd_priv(dev);
struct vnic_rq *rq_sop;
struct vnic_rq *rq_data;
struct rte_eth_rxconf *conf;
uint16_t sop_queue_idx;
uint16_t data_queue_idx;
ENICPMD_FUNC_TRACE();
sop_queue_idx = enic_rte_rq_idx_to_sop_idx(rx_queue_id);
data_queue_idx = enic_rte_rq_idx_to_data_idx(rx_queue_id);
rq_sop = &enic->rq[sop_queue_idx];
rq_data = &enic->rq[data_queue_idx]; /* valid if data_queue_enable */
qinfo->mp = rq_sop->mp;
qinfo->scattered_rx = rq_sop->data_queue_enable;
qinfo->nb_desc = rq_sop->ring.desc_count;
if (qinfo->scattered_rx)
qinfo->nb_desc += rq_data->ring.desc_count;
conf = &qinfo->conf;
memset(conf, 0, sizeof(*conf));
conf->rx_free_thresh = rq_sop->rx_free_thresh;
conf->rx_drop_en = 1;
/*
* Except VLAN stripping (port setting), all the checksum offloads
* are always enabled.
*/
conf->offloads = enic->rx_offload_capa;
if (!enic->ig_vlan_strip_en)
conf->offloads &= ~DEV_RX_OFFLOAD_VLAN_STRIP;
/* rx_thresh and other fields are not applicable for enic */
}
static void enicpmd_dev_txq_info_get(struct rte_eth_dev *dev,
__rte_unused uint16_t tx_queue_id,
struct rte_eth_txq_info *qinfo)
{
struct enic *enic = pmd_priv(dev);
ENICPMD_FUNC_TRACE();
qinfo->nb_desc = enic->config.wq_desc_count;
memset(&qinfo->conf, 0, sizeof(qinfo->conf));
qinfo->conf.offloads = enic->tx_offload_capa;
/* tx_thresh, and all the other fields are not applicable for enic */
}
static int enicpmd_dev_rx_queue_intr_enable(struct rte_eth_dev *eth_dev,
uint16_t rx_queue_id)
{
struct enic *enic = pmd_priv(eth_dev);
ENICPMD_FUNC_TRACE();
vnic_intr_unmask(&enic->intr[rx_queue_id + ENICPMD_RXQ_INTR_OFFSET]);
return 0;
}
static int enicpmd_dev_rx_queue_intr_disable(struct rte_eth_dev *eth_dev,
uint16_t rx_queue_id)
{
struct enic *enic = pmd_priv(eth_dev);
ENICPMD_FUNC_TRACE();
vnic_intr_mask(&enic->intr[rx_queue_id + ENICPMD_RXQ_INTR_OFFSET]);
return 0;
}
static const struct eth_dev_ops enicpmd_eth_dev_ops = {
.dev_configure = enicpmd_dev_configure,
.dev_start = enicpmd_dev_start,
.dev_stop = enicpmd_dev_stop,
.dev_set_link_up = NULL,
.dev_set_link_down = NULL,
.dev_close = enicpmd_dev_close,
.promiscuous_enable = enicpmd_dev_promiscuous_enable,
.promiscuous_disable = enicpmd_dev_promiscuous_disable,
.allmulticast_enable = enicpmd_dev_allmulticast_enable,
.allmulticast_disable = enicpmd_dev_allmulticast_disable,
.link_update = enicpmd_dev_link_update,
.stats_get = enicpmd_dev_stats_get,
.stats_reset = enicpmd_dev_stats_reset,
.queue_stats_mapping_set = NULL,
.dev_infos_get = enicpmd_dev_info_get,
.dev_supported_ptypes_get = enicpmd_dev_supported_ptypes_get,
.mtu_set = enicpmd_mtu_set,
.vlan_filter_set = NULL,
.vlan_tpid_set = NULL,
.vlan_offload_set = enicpmd_vlan_offload_set,
.vlan_strip_queue_set = NULL,
.rx_queue_start = enicpmd_dev_rx_queue_start,
.rx_queue_stop = enicpmd_dev_rx_queue_stop,
.tx_queue_start = enicpmd_dev_tx_queue_start,
.tx_queue_stop = enicpmd_dev_tx_queue_stop,
.rx_queue_setup = enicpmd_dev_rx_queue_setup,
.rx_queue_release = enicpmd_dev_rx_queue_release,
.rx_queue_count = enicpmd_dev_rx_queue_count,
.rx_descriptor_done = NULL,
.tx_queue_setup = enicpmd_dev_tx_queue_setup,
.tx_queue_release = enicpmd_dev_tx_queue_release,
.rx_queue_intr_enable = enicpmd_dev_rx_queue_intr_enable,
.rx_queue_intr_disable = enicpmd_dev_rx_queue_intr_disable,
.rxq_info_get = enicpmd_dev_rxq_info_get,
.txq_info_get = enicpmd_dev_txq_info_get,
.dev_led_on = NULL,
.dev_led_off = NULL,
.flow_ctrl_get = NULL,
.flow_ctrl_set = NULL,
.priority_flow_ctrl_set = NULL,
.mac_addr_add = enicpmd_add_mac_addr,
.mac_addr_remove = enicpmd_remove_mac_addr,
.mac_addr_set = enicpmd_set_mac_addr,
.filter_ctrl = enicpmd_dev_filter_ctrl,
.reta_query = enicpmd_dev_rss_reta_query,
.reta_update = enicpmd_dev_rss_reta_update,
.rss_hash_conf_get = enicpmd_dev_rss_hash_conf_get,
.rss_hash_update = enicpmd_dev_rss_hash_update,
};
static int enic_parse_disable_overlay(__rte_unused const char *key,
const char *value,
void *opaque)
{
struct enic *enic;
enic = (struct enic *)opaque;
if (strcmp(value, "0") == 0) {
enic->disable_overlay = false;
} else if (strcmp(value, "1") == 0) {
enic->disable_overlay = true;
} else {
dev_err(enic, "Invalid value for " ENIC_DEVARG_DISABLE_OVERLAY
": expected=0|1 given=%s\n", value);
return -EINVAL;
}
return 0;
}
static int enic_check_devargs(struct rte_eth_dev *dev)
{
static const char *const valid_keys[] = {
ENIC_DEVARG_DISABLE_OVERLAY, NULL};
struct enic *enic = pmd_priv(dev);
struct rte_kvargs *kvlist;
ENICPMD_FUNC_TRACE();
enic->disable_overlay = false;
if (!dev->device->devargs)
return 0;
kvlist = rte_kvargs_parse(dev->device->devargs->args, valid_keys);
if (!kvlist)
return -EINVAL;
if (rte_kvargs_process(kvlist, ENIC_DEVARG_DISABLE_OVERLAY,
enic_parse_disable_overlay, enic) < 0) {
rte_kvargs_free(kvlist);
return -EINVAL;
}
rte_kvargs_free(kvlist);
return 0;
}
struct enic *enicpmd_list_head = NULL;
/* Initialize the driver
* It returns 0 on success.
*/
static int eth_enicpmd_dev_init(struct rte_eth_dev *eth_dev)
{
struct rte_pci_device *pdev;
struct rte_pci_addr *addr;
struct enic *enic = pmd_priv(eth_dev);
int err;
ENICPMD_FUNC_TRACE();
enic->port_id = eth_dev->data->port_id;
enic->rte_dev = eth_dev;
eth_dev->dev_ops = &enicpmd_eth_dev_ops;
eth_dev->rx_pkt_burst = &enic_recv_pkts;
eth_dev->tx_pkt_burst = &enic_xmit_pkts;
eth_dev->tx_pkt_prepare = &enic_prep_pkts;
pdev = RTE_ETH_DEV_TO_PCI(eth_dev);
rte_eth_copy_pci_info(eth_dev, pdev);
enic->pdev = pdev;
addr = &pdev->addr;
snprintf(enic->bdf_name, ENICPMD_BDF_LENGTH, "%04x:%02x:%02x.%x",
addr->domain, addr->bus, addr->devid, addr->function);
err = enic_check_devargs(eth_dev);
if (err)
return err;
return enic_probe(enic);
}
static int eth_enic_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 enic),
eth_enicpmd_dev_init);
}
static int eth_enic_pci_remove(struct rte_pci_device *pci_dev)
{
return rte_eth_dev_pci_generic_remove(pci_dev, NULL);
}
static struct rte_pci_driver rte_enic_pmd = {
.id_table = pci_id_enic_map,
.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
.probe = eth_enic_pci_probe,
.remove = eth_enic_pci_remove,
};
RTE_PMD_REGISTER_PCI(net_enic, rte_enic_pmd);
RTE_PMD_REGISTER_PCI_TABLE(net_enic, pci_id_enic_map);
RTE_PMD_REGISTER_KMOD_DEP(net_enic, "* igb_uio | uio_pci_generic | vfio-pci");
RTE_PMD_REGISTER_PARAM_STRING(net_enic,
ENIC_DEVARG_DISABLE_OVERLAY "=<0|1> ");