net/octeontx2: support VLAN filters

Support setting up VLAN filters so as to allow tagged
packet's reception after VLAN HW Filter offload is enabled.

Signed-off-by: Vivek Sharma <viveksharma@marvell.com>
Acked-by: Jerin Jacob <jerinj@marvell.com>
This commit is contained in:
Vivek Sharma 2019-06-30 09:04:41 +05:30 committed by Ferruh Yigit
parent ba1b3b081e
commit 85bcf43f3c
7 changed files with 157 additions and 3 deletions

View File

@ -21,6 +21,7 @@ RSS hash = Y
RSS key update = Y
RSS reta update = Y
Inner RSS = Y
VLAN filter = Y
Flow control = Y
Flow API = Y
VLAN offload = Y

View File

@ -21,6 +21,7 @@ RSS hash = Y
RSS key update = Y
RSS reta update = Y
Inner RSS = Y
VLAN filter = Y
Flow control = Y
Flow API = Y
VLAN offload = Y

View File

@ -17,6 +17,7 @@ RSS hash = Y
RSS key update = Y
RSS reta update = Y
Inner RSS = Y
VLAN filter = Y
Flow API = Y
VLAN offload = Y
QinQ offload = Y

View File

@ -22,7 +22,7 @@ Features of the OCTEON TX2 Ethdev PMD are:
- Lock-free Tx queue
- Multiple queues for TX and RX
- Receiver Side Scaling (RSS)
- MAC filtering
- MAC/VLAN filtering
- Generic flow API
- VLAN/QinQ stripping and insertion
- Port hardware statistics

View File

@ -1365,6 +1365,8 @@ static const struct eth_dev_ops otx2_eth_dev_ops = {
.timesync_read_time = otx2_nix_timesync_read_time,
.timesync_write_time = otx2_nix_timesync_write_time,
.vlan_offload_set = otx2_nix_vlan_offload_set,
.vlan_filter_set = otx2_nix_vlan_filter_set,
.vlan_strip_queue_set = otx2_nix_vlan_strip_queue_set,
};
static inline int

View File

@ -450,6 +450,10 @@ int otx2_nix_vlan_offload_init(struct rte_eth_dev *eth_dev);
int otx2_nix_vlan_fini(struct rte_eth_dev *eth_dev);
int otx2_nix_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask);
void otx2_nix_vlan_update_promisc(struct rte_eth_dev *eth_dev, int enable);
int otx2_nix_vlan_filter_set(struct rte_eth_dev *eth_dev, uint16_t vlan_id,
int on);
void otx2_nix_vlan_strip_queue_set(struct rte_eth_dev *dev,
uint16_t queue, int on);
/* Lookup configuration */
void *otx2_nix_fastpath_lookup_mem_get(void);

View File

@ -22,8 +22,8 @@ enum vtag_cfg_dir {
};
static int
__rte_unused nix_vlan_mcam_enb_dis(struct otx2_eth_dev *dev,
uint32_t entry, const int enable)
nix_vlan_mcam_enb_dis(struct otx2_eth_dev *dev,
uint32_t entry, const int enable)
{
struct npc_mcam_ena_dis_entry_req *req;
struct otx2_mbox *mbox = dev->mbox;
@ -460,6 +460,8 @@ nix_vlan_hw_filter(struct rte_eth_dev *eth_dev, const uint8_t enable,
uint16_t vlan_id)
{
struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
struct otx2_vlan_info *vlan = &dev->vlan_info;
struct vlan_entry *entry;
int rc = -EINVAL;
if (!vlan_id && enable) {
@ -473,6 +475,24 @@ nix_vlan_hw_filter(struct rte_eth_dev *eth_dev, const uint8_t enable,
return 0;
}
/* Enable/disable existing vlan filter entries */
TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) {
if (vlan_id) {
if (entry->vlan_id == vlan_id) {
rc = nix_vlan_mcam_enb_dis(dev,
entry->mcam_idx,
enable);
if (rc)
return rc;
}
} else {
rc = nix_vlan_mcam_enb_dis(dev, entry->mcam_idx,
enable);
if (rc)
return rc;
}
}
if (!vlan_id && !enable) {
rc = nix_vlan_handle_default_rx_entry(eth_dev, false, true,
enable);
@ -487,6 +507,85 @@ nix_vlan_hw_filter(struct rte_eth_dev *eth_dev, const uint8_t enable,
return 0;
}
/* Enable/disable vlan filtering for the given vlan_id */
int
otx2_nix_vlan_filter_set(struct rte_eth_dev *eth_dev, uint16_t vlan_id,
int on)
{
struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
struct otx2_vlan_info *vlan = &dev->vlan_info;
struct vlan_entry *entry;
int entry_exists = 0;
int rc = -EINVAL;
int mcam_idx;
if (!vlan_id) {
otx2_err("Vlan Id can't be zero");
return rc;
}
if (!vlan->def_rx_mcam_idx) {
otx2_err("Vlan Filtering is disabled, enable it first");
return rc;
}
if (on) {
TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) {
if (entry->vlan_id == vlan_id) {
/* Vlan entry already exists */
entry_exists = 1;
/* Mcam entry already allocated */
if (entry->mcam_idx) {
rc = nix_vlan_hw_filter(eth_dev, on,
vlan_id);
return rc;
}
break;
}
}
if (!entry_exists) {
entry = rte_zmalloc("otx2_nix_vlan_entry",
sizeof(struct vlan_entry), 0);
if (!entry) {
otx2_err("Failed to allocate memory");
return -ENOMEM;
}
}
/* Enables vlan_id & mac address based filtering */
if (eth_dev->data->promiscuous)
mcam_idx = nix_vlan_mcam_config(eth_dev, vlan_id,
VLAN_ID_MATCH);
else
mcam_idx = nix_vlan_mcam_config(eth_dev, vlan_id,
VLAN_ID_MATCH |
MAC_ADDR_MATCH);
if (mcam_idx < 0) {
otx2_err("Failed to config vlan mcam");
TAILQ_REMOVE(&vlan->fltr_tbl, entry, next);
rte_free(entry);
return mcam_idx;
}
entry->mcam_idx = mcam_idx;
if (!entry_exists) {
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) {
nix_vlan_mcam_free(dev, entry->mcam_idx);
TAILQ_REMOVE(&vlan->fltr_tbl, entry, next);
rte_free(entry);
break;
}
}
}
return 0;
}
/* Configure double vlan(qinq) on or off */
static int
otx2_nix_config_double_vlan(struct rte_eth_dev *eth_dev,
@ -594,6 +693,13 @@ otx2_nix_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
return rc;
}
void otx2_nix_vlan_strip_queue_set(__rte_unused struct rte_eth_dev *dev,
__rte_unused uint16_t queue,
__rte_unused int on)
{
otx2_err("Not Supported");
}
static int
nix_vlan_rx_mkex_offset(uint64_t mask)
{
@ -646,6 +752,27 @@ nix_vlan_get_mkex_info(struct otx2_eth_dev *dev)
return 0;
}
static void nix_vlan_reinstall_vlan_filters(struct rte_eth_dev *eth_dev)
{
struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
struct vlan_entry *entry;
int rc;
/* VLAN filters can't be set without setting filtern on */
rc = nix_vlan_handle_default_rx_entry(eth_dev, false, true, true);
if (rc) {
otx2_err("Failed to reinstall vlan filters");
return;
}
TAILQ_FOREACH(entry, &dev->vlan_info.fltr_tbl, next) {
rc = otx2_nix_vlan_filter_set(eth_dev, entry->vlan_id, true);
if (rc)
otx2_err("Failed to reinstall filter for vlan:%d",
entry->vlan_id);
}
}
int
otx2_nix_vlan_offload_init(struct rte_eth_dev *eth_dev)
{
@ -661,6 +788,11 @@ otx2_nix_vlan_offload_init(struct rte_eth_dev *eth_dev)
}
TAILQ_INIT(&dev->vlan_info.fltr_tbl);
} else {
/* Reinstall all mcam entries now if filter offload is set */
if (eth_dev->data->dev_conf.rxmode.offloads &
DEV_RX_OFFLOAD_VLAN_FILTER)
nix_vlan_reinstall_vlan_filters(eth_dev);
}
mask =
@ -679,8 +811,21 @@ otx2_nix_vlan_fini(struct rte_eth_dev *eth_dev)
{
struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
struct otx2_vlan_info *vlan = &dev->vlan_info;
struct vlan_entry *entry;
int rc;
TAILQ_FOREACH(entry, &vlan->fltr_tbl, next) {
if (!dev->configured) {
TAILQ_REMOVE(&vlan->fltr_tbl, entry, next);
rte_free(entry);
} else {
/* MCAM entries freed by flow_fini & lf_free on
* port stop.
*/
entry->mcam_idx = 0;
}
}
if (!dev->configured) {
if (vlan->def_rx_mcam_idx) {
rc = nix_vlan_mcam_free(dev, vlan->def_rx_mcam_idx);