numam-dpdk/drivers/net/octeontx/octeontx_ethdev_ops.c
Wei Hu (Xavier) 50ce3e7aec ethdev: fix VLAN offloads set if no relative capabilities
Currently, there is a potential problem that calling the API function
rte_eth_dev_set_vlan_offload to start VLAN hardware offloads which the
driver does not support. If the PMD driver does not support certain VLAN
hardware offloads and does not check for it, the hardware setting will
not change, but the VLAN offloads in dev->data->dev_conf.rxmode.offloads
will be turned on.

It is supposed to check the hardware capabilities to decide whether the
relative callback needs to be called just like the behavior in the API
function named rte_eth_dev_configure. And it is also needed to cleanup
duplicated checks which are done in some PMDs. Also, note that it is
behaviour change for some PMDs which simply ignore (with error/warning
log message) unsupported VLAN offloads, but now it will fail.

Fixes: a4996bd89c ("ethdev: new Rx/Tx offloads API")
Fixes: 0ebce6129b ("net/dpaa2: support new ethdev offload APIs")
Fixes: f9416bbafd ("net/enic: remove VLAN filter handler")
Fixes: 4f7d9e383e ("fm10k: update vlan offload features")
Fixes: fdba3bf15c ("net/hinic: add VLAN filter and offload")
Fixes: b96fb2f0d2 ("net/i40e: handle QinQ strip")
Fixes: d4a27a3b09 ("nfp: add basic features")
Fixes: 56139e85ab ("net/octeontx: support VLAN filter offload")
Fixes: ba1b3b081e ("net/octeontx2: support VLAN offloads")
Fixes: d87246a437 ("net/qede: enable and disable VLAN filtering")
Cc: stable@dpdk.org

Signed-off-by: Chengchang Tang <tangchengchang@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Acked-by: Andrew Rybchenko <arybchenko@solarflare.com>
Acked-by: Hyong Youb Kim <hyonkim@cisco.com>
Acked-by: Sachin Saxena <sachin.saxena@nxp.com>
Acked-by: Xiaoyun Wang <cloud.wangxiaoyun@huawei.com>
Acked-by: Harman Kalra <hkalra@marvell.com>
Acked-by: Jeff Guo <jia.guo@intel.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
2020-07-11 06:18:53 +02:00

334 lines
7.7 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(C) 2020 Marvell International Ltd.
*/
#include <rte_malloc.h>
#include "octeontx_ethdev.h"
#include "octeontx_logs.h"
#include "octeontx_rxtx.h"
static int
octeontx_vlan_hw_filter(struct octeontx_nic *nic, uint8_t flag)
{
struct octeontx_vlan_info *vlan = &nic->vlan_info;
pki_port_vlan_filter_config_t fltr_conf;
int rc = 0;
if (vlan->filter_on == flag)
return rc;
fltr_conf.port_type = OCTTX_PORT_TYPE_NET;
fltr_conf.fltr_conf = flag;
rc = octeontx_pki_port_vlan_fltr_config(nic->port_id, &fltr_conf);
if (rc != 0) {
octeontx_log_err("Fail to configure vlan hw filter for port %d",
nic->port_id);
goto done;
}
vlan->filter_on = flag;
done:
return rc;
}
int
octeontx_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask)
{
struct octeontx_nic *nic = octeontx_pmd_priv(dev);
struct rte_eth_rxmode *rxmode;
int rc = 0;
rxmode = &dev->data->dev_conf.rxmode;
if (mask & ETH_VLAN_FILTER_MASK) {
if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_FILTER) {
rc = octeontx_vlan_hw_filter(nic, true);
if (rc)
goto done;
nic->rx_offloads |= DEV_RX_OFFLOAD_VLAN_FILTER;
nic->rx_offload_flags |= OCCTX_RX_VLAN_FLTR_F;
} else {
rc = octeontx_vlan_hw_filter(nic, false);
if (rc)
goto done;
nic->rx_offloads &= ~DEV_RX_OFFLOAD_VLAN_FILTER;
nic->rx_offload_flags &= ~OCCTX_RX_VLAN_FLTR_F;
}
}
done:
return rc;
}
int
octeontx_dev_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
{
struct octeontx_nic *nic = octeontx_pmd_priv(dev);
struct octeontx_vlan_info *vlan = &nic->vlan_info;
pki_port_vlan_filter_entry_config_t fltr_entry;
struct vlan_entry *entry = NULL;
int entry_count = 0;
int rc = -EINVAL;
if (on) {
TAILQ_FOREACH(entry, &vlan->fltr_tbl, next)
if (entry->vlan_id == vlan_id) {
octeontx_log_dbg("Vlan Id is already set");
return 0;
}
} else {
TAILQ_FOREACH(entry, &vlan->fltr_tbl, next)
entry_count++;
if (!entry_count)
return 0;
}
fltr_entry.port_type = OCTTX_PORT_TYPE_NET;
fltr_entry.vlan_tpid = RTE_ETHER_TYPE_VLAN;
fltr_entry.vlan_id = vlan_id;
fltr_entry.entry_conf = on;
if (on) {
entry = rte_zmalloc("octeontx_nic_vlan_entry",
sizeof(struct vlan_entry), 0);
if (!entry) {
octeontx_log_err("Failed to allocate memory");
return -ENOMEM;
}
}
rc = octeontx_pki_port_vlan_fltr_entry_config(nic->port_id,
&fltr_entry);
if (rc != 0) {
octeontx_log_err("Fail to configure vlan filter entry "
"for port %d", nic->port_id);
if (entry)
rte_free(entry);
goto done;
}
if (on) {
entry->vlan_id = vlan_id;
TAILQ_INSERT_HEAD(&vlan->fltr_tbl, entry, next);
} else {
TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) {
if (entry->vlan_id == vlan_id) {
TAILQ_REMOVE(&vlan->fltr_tbl, entry, next);
rte_free(entry);
break;
}
}
}
done:
return rc;
}
int
octeontx_dev_vlan_offload_init(struct rte_eth_dev *dev)
{
struct octeontx_nic *nic = octeontx_pmd_priv(dev);
int rc;
TAILQ_INIT(&nic->vlan_info.fltr_tbl);
rc = octeontx_dev_vlan_offload_set(dev, ETH_VLAN_FILTER_MASK);
if (rc)
octeontx_log_err("Failed to set vlan offload rc=%d", rc);
return rc;
}
int
octeontx_dev_vlan_offload_fini(struct rte_eth_dev *dev)
{
struct octeontx_nic *nic = octeontx_pmd_priv(dev);
struct octeontx_vlan_info *vlan = &nic->vlan_info;
pki_port_vlan_filter_entry_config_t fltr_entry;
struct vlan_entry *entry;
int rc = 0;
TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) {
fltr_entry.port_type = OCTTX_PORT_TYPE_NET;
fltr_entry.vlan_tpid = RTE_ETHER_TYPE_VLAN;
fltr_entry.vlan_id = entry->vlan_id;
fltr_entry.entry_conf = 0;
rc = octeontx_pki_port_vlan_fltr_entry_config(nic->port_id,
&fltr_entry);
if (rc != 0) {
octeontx_log_err("Fail to configure vlan filter entry "
"for port %d", nic->port_id);
break;
}
}
return rc;
}
int
octeontx_dev_set_link_up(struct rte_eth_dev *eth_dev)
{
struct octeontx_nic *nic = octeontx_pmd_priv(eth_dev);
int rc, i;
rc = octeontx_bgx_port_set_link_state(nic->port_id, true);
if (rc)
goto done;
/* Start tx queues */
for (i = 0; i < eth_dev->data->nb_tx_queues; i++)
octeontx_dev_tx_queue_start(eth_dev, i);
done:
return rc;
}
int
octeontx_dev_set_link_down(struct rte_eth_dev *eth_dev)
{
struct octeontx_nic *nic = octeontx_pmd_priv(eth_dev);
int i;
/* Stop tx queues */
for (i = 0; i < eth_dev->data->nb_tx_queues; i++)
octeontx_dev_tx_queue_stop(eth_dev, i);
return octeontx_bgx_port_set_link_state(nic->port_id, false);
}
int
octeontx_dev_flow_ctrl_get(struct rte_eth_dev *dev,
struct rte_eth_fc_conf *fc_conf)
{
struct octeontx_nic *nic = octeontx_pmd_priv(dev);
octeontx_mbox_bgx_port_fc_cfg_t conf;
int rc;
memset(&conf, 0, sizeof(octeontx_mbox_bgx_port_fc_cfg_t));
rc = octeontx_bgx_port_flow_ctrl_cfg(nic->port_id, &conf);
if (rc)
return rc;
if (conf.rx_pause && conf.tx_pause)
fc_conf->mode = RTE_FC_FULL;
else if (conf.rx_pause)
fc_conf->mode = RTE_FC_RX_PAUSE;
else if (conf.tx_pause)
fc_conf->mode = RTE_FC_TX_PAUSE;
else
fc_conf->mode = RTE_FC_NONE;
/* low_water & high_water values are in Bytes */
fc_conf->low_water = conf.low_water;
fc_conf->high_water = conf.high_water;
return rc;
}
int
octeontx_dev_flow_ctrl_set(struct rte_eth_dev *dev,
struct rte_eth_fc_conf *fc_conf)
{
struct octeontx_nic *nic = octeontx_pmd_priv(dev);
struct octeontx_fc_info *fc = &nic->fc;
octeontx_mbox_bgx_port_fc_cfg_t conf;
uint8_t tx_pause, rx_pause;
uint16_t max_high_water;
int rc;
if (fc_conf->pause_time || fc_conf->mac_ctrl_frame_fwd ||
fc_conf->autoneg) {
octeontx_log_err("Below flowctrl parameters are not supported "
"pause_time, mac_ctrl_frame_fwd and autoneg");
return -EINVAL;
}
if (fc_conf->high_water == fc->high_water &&
fc_conf->low_water == fc->low_water &&
fc_conf->mode == fc->mode)
return 0;
max_high_water = fc->rx_fifosz - OCTEONTX_BGX_RSVD_RX_FIFOBYTES;
if (fc_conf->high_water > max_high_water ||
fc_conf->high_water < fc_conf->low_water) {
octeontx_log_err("Invalid high/low water values "
"High_water(in Bytes) must <= 0x%x ",
max_high_water);
return -EINVAL;
}
if (fc_conf->high_water % BIT(4) || fc_conf->low_water % BIT(4)) {
octeontx_log_err("High/low water value must be multiple of 16");
return -EINVAL;
}
rx_pause = (fc_conf->mode == RTE_FC_FULL) ||
(fc_conf->mode == RTE_FC_RX_PAUSE);
tx_pause = (fc_conf->mode == RTE_FC_FULL) ||
(fc_conf->mode == RTE_FC_TX_PAUSE);
conf.high_water = fc_conf->high_water;
conf.low_water = fc_conf->low_water;
conf.fc_cfg = BGX_PORT_FC_CFG_SET;
conf.rx_pause = rx_pause;
conf.tx_pause = tx_pause;
rc = octeontx_bgx_port_flow_ctrl_cfg(nic->port_id, &conf);
if (rc)
return rc;
fc->high_water = fc_conf->high_water;
fc->low_water = fc_conf->low_water;
fc->mode = fc_conf->mode;
return rc;
}
int
octeontx_dev_flow_ctrl_init(struct rte_eth_dev *dev)
{
struct octeontx_nic *nic = octeontx_pmd_priv(dev);
struct octeontx_fc_info *fc = &nic->fc;
struct rte_eth_fc_conf fc_conf;
int rc;
rc = octeontx_dev_flow_ctrl_get(dev, &fc_conf);
if (rc) {
octeontx_log_err("Failed to get flow control info");
return rc;
}
fc->def_highmark = fc_conf.high_water;
fc->def_lowmark = fc_conf.low_water;
fc->def_mode = fc_conf.mode;
return rc;
}
int
octeontx_dev_flow_ctrl_fini(struct rte_eth_dev *dev)
{
struct octeontx_nic *nic = octeontx_pmd_priv(dev);
struct octeontx_fc_info *fc = &nic->fc;
struct rte_eth_fc_conf fc_conf;
memset(&fc_conf, 0, sizeof(struct rte_eth_fc_conf));
/* Restore flow control parameters with default values */
fc_conf.high_water = fc->def_highmark;
fc_conf.low_water = fc->def_lowmark;
fc_conf.mode = fc->def_mode;
return octeontx_dev_flow_ctrl_set(dev, &fc_conf);
}