net/ice: complete VLAN offload capability for DCF

The new VLAN virtchnl opcodes introduce new capabilities like VLAN
filtering, stripping and insertion.

The DCF needs to query the VLAN capabilities based on current device
configuration firstly.

DCF is able to configure inner VLAN filter when port VLAN is enabled
base on negotiation; and DCF is able to configure outer VLAN (0x8100)
if port VLAN is disabled to be compatible with legacy mode.

When port VLAN is updated by DCF, the DCF needs to reset to query the
new VLAN capabilities.

Signed-off-by: Alvin Zhang <alvinx.zhang@intel.com>
Signed-off-by: Kevin Liu <kevinx.liu@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
This commit is contained in:
Alvin Zhang 2022-04-29 09:19:58 +00:00 committed by Qi Zhang
parent 1a09fa53d8
commit 9a7980cfdf
3 changed files with 182 additions and 17 deletions

View File

@ -587,6 +587,29 @@ ice_dcf_get_supported_rxdid(struct ice_dcf_hw *hw)
return 0; return 0;
} }
static int
dcf_get_vlan_offload_caps_v2(struct ice_dcf_hw *hw)
{
struct virtchnl_vlan_caps vlan_v2_caps;
struct dcf_virtchnl_cmd args;
int ret;
memset(&args, 0, sizeof(args));
args.v_op = VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS;
args.rsp_msgbuf = (uint8_t *)&vlan_v2_caps;
args.rsp_buflen = sizeof(vlan_v2_caps);
ret = ice_dcf_execute_virtchnl_cmd(hw, &args);
if (ret) {
PMD_DRV_LOG(ERR,
"Failed to execute command of VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS");
return ret;
}
rte_memcpy(&hw->vlan_v2_caps, &vlan_v2_caps, sizeof(vlan_v2_caps));
return 0;
}
int int
ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw) ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
{ {
@ -701,6 +724,10 @@ ice_dcf_init_hw(struct rte_eth_dev *eth_dev, struct ice_dcf_hw *hw)
rte_intr_enable(pci_dev->intr_handle); rte_intr_enable(pci_dev->intr_handle);
ice_dcf_enable_irq0(hw); ice_dcf_enable_irq0(hw);
if ((hw->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN_V2) &&
dcf_get_vlan_offload_caps_v2(hw))
goto err_rss;
return 0; return 0;
err_rss: err_rss:

View File

@ -129,6 +129,7 @@ struct ice_dcf_hw {
uint16_t nb_msix; uint16_t nb_msix;
uint16_t rxq_map[16]; uint16_t rxq_map[16];
struct virtchnl_eth_stats eth_stats_offset; struct virtchnl_eth_stats eth_stats_offset;
struct virtchnl_vlan_caps vlan_v2_caps;
/* Link status */ /* Link status */
bool link_up; bool link_up;

View File

@ -1050,6 +1050,46 @@ dcf_dev_set_default_mac_addr(struct rte_eth_dev *dev,
return 0; return 0;
} }
static int
dcf_add_del_vlan_v2(struct ice_dcf_hw *hw, uint16_t vlanid, bool add)
{
struct virtchnl_vlan_supported_caps *supported_caps =
&hw->vlan_v2_caps.filtering.filtering_support;
struct virtchnl_vlan *vlan_setting;
struct virtchnl_vlan_filter_list_v2 vlan_filter;
struct dcf_virtchnl_cmd args;
uint32_t filtering_caps;
int err;
if (supported_caps->outer) {
filtering_caps = supported_caps->outer;
vlan_setting = &vlan_filter.filters[0].outer;
} else {
filtering_caps = supported_caps->inner;
vlan_setting = &vlan_filter.filters[0].inner;
}
if (!(filtering_caps & VIRTCHNL_VLAN_ETHERTYPE_8100))
return -ENOTSUP;
memset(&vlan_filter, 0, sizeof(vlan_filter));
vlan_filter.vport_id = hw->vsi_res->vsi_id;
vlan_filter.num_elements = 1;
vlan_setting->tpid = RTE_ETHER_TYPE_VLAN;
vlan_setting->tci = vlanid;
memset(&args, 0, sizeof(args));
args.v_op = add ? VIRTCHNL_OP_ADD_VLAN_V2 : VIRTCHNL_OP_DEL_VLAN_V2;
args.req_msg = (uint8_t *)&vlan_filter;
args.req_msglen = sizeof(vlan_filter);
err = ice_dcf_execute_virtchnl_cmd(hw, &args);
if (err)
PMD_DRV_LOG(ERR, "fail to execute command %s",
add ? "OP_ADD_VLAN_V2" : "OP_DEL_VLAN_V2");
return err;
}
static int static int
dcf_add_del_vlan(struct ice_dcf_hw *hw, uint16_t vlanid, bool add) dcf_add_del_vlan(struct ice_dcf_hw *hw, uint16_t vlanid, bool add)
{ {
@ -1076,6 +1116,116 @@ dcf_add_del_vlan(struct ice_dcf_hw *hw, uint16_t vlanid, bool add)
return err; return err;
} }
static int
dcf_dev_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
{
struct ice_dcf_adapter *adapter = dev->data->dev_private;
struct ice_dcf_hw *hw = &adapter->real_hw;
int err;
if (hw->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN_V2) {
err = dcf_add_del_vlan_v2(hw, vlan_id, on);
if (err)
return -EIO;
return 0;
}
if (!(hw->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN))
return -ENOTSUP;
err = dcf_add_del_vlan(hw, vlan_id, on);
if (err)
return -EIO;
return 0;
}
static void
dcf_iterate_vlan_filters_v2(struct rte_eth_dev *dev, bool enable)
{
struct rte_vlan_filter_conf *vfc = &dev->data->vlan_filter_conf;
struct ice_dcf_adapter *adapter = dev->data->dev_private;
struct ice_dcf_hw *hw = &adapter->real_hw;
uint32_t i, j;
uint64_t ids;
for (i = 0; i < RTE_DIM(vfc->ids); i++) {
if (vfc->ids[i] == 0)
continue;
ids = vfc->ids[i];
for (j = 0; ids != 0 && j < 64; j++, ids >>= 1) {
if (ids & 1)
dcf_add_del_vlan_v2(hw, 64 * i + j, enable);
}
}
}
static int
dcf_config_vlan_strip_v2(struct ice_dcf_hw *hw, bool enable)
{
struct virtchnl_vlan_supported_caps *stripping_caps =
&hw->vlan_v2_caps.offloads.stripping_support;
struct virtchnl_vlan_setting vlan_strip;
struct dcf_virtchnl_cmd args;
uint32_t *ethertype;
int ret;
if ((stripping_caps->outer & VIRTCHNL_VLAN_ETHERTYPE_8100) &&
(stripping_caps->outer & VIRTCHNL_VLAN_TOGGLE))
ethertype = &vlan_strip.outer_ethertype_setting;
else if ((stripping_caps->inner & VIRTCHNL_VLAN_ETHERTYPE_8100) &&
(stripping_caps->inner & VIRTCHNL_VLAN_TOGGLE))
ethertype = &vlan_strip.inner_ethertype_setting;
else
return -ENOTSUP;
memset(&vlan_strip, 0, sizeof(vlan_strip));
vlan_strip.vport_id = hw->vsi_res->vsi_id;
*ethertype = VIRTCHNL_VLAN_ETHERTYPE_8100;
memset(&args, 0, sizeof(args));
args.v_op = enable ? VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2 :
VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2;
args.req_msg = (uint8_t *)&vlan_strip;
args.req_msglen = sizeof(vlan_strip);
ret = ice_dcf_execute_virtchnl_cmd(hw, &args);
if (ret)
PMD_DRV_LOG(ERR, "fail to execute command %s",
enable ? "VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2" :
"VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2");
return ret;
}
static int
dcf_dev_vlan_offload_set_v2(struct rte_eth_dev *dev, int mask)
{
struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode;
struct ice_dcf_adapter *adapter = dev->data->dev_private;
struct ice_dcf_hw *hw = &adapter->real_hw;
bool enable;
int err;
if (mask & RTE_ETH_VLAN_FILTER_MASK) {
enable = !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_FILTER);
dcf_iterate_vlan_filters_v2(dev, enable);
}
if (mask & RTE_ETH_VLAN_STRIP_MASK) {
enable = !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_STRIP);
err = dcf_config_vlan_strip_v2(hw, enable);
/* If not support, the stripping is already disabled by PF */
if (err == -ENOTSUP && !enable)
err = 0;
if (err)
return -EIO;
}
return 0;
}
static int static int
dcf_enable_vlan_strip(struct ice_dcf_hw *hw) dcf_enable_vlan_strip(struct ice_dcf_hw *hw)
{ {
@ -1108,30 +1258,17 @@ dcf_disable_vlan_strip(struct ice_dcf_hw *hw)
return ret; return ret;
} }
static int
dcf_dev_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
{
struct ice_dcf_adapter *adapter = dev->data->dev_private;
struct ice_dcf_hw *hw = &adapter->real_hw;
int err;
if (!(hw->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN))
return -ENOTSUP;
err = dcf_add_del_vlan(hw, vlan_id, on);
if (err)
return -EIO;
return 0;
}
static int static int
dcf_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask) dcf_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask)
{ {
struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
struct ice_dcf_adapter *adapter = dev->data->dev_private; struct ice_dcf_adapter *adapter = dev->data->dev_private;
struct ice_dcf_hw *hw = &adapter->real_hw; struct ice_dcf_hw *hw = &adapter->real_hw;
struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
int err; int err;
if (hw->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN_V2)
return dcf_dev_vlan_offload_set_v2(dev, mask);
if (!(hw->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN)) if (!(hw->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN))
return -ENOTSUP; return -ENOTSUP;