From 96974a6600ec3c0e71075cb194cd12ff5e01a190 Mon Sep 17 00:00:00 2001 From: Wenzhuo Lu Date: Tue, 11 Apr 2017 16:31:23 +0800 Subject: [PATCH] net/i40e: move private APIs to a specific file Create a new file rte_pmd_i40e.c for all the private APIs. Move all the related code to the new file. Signed-off-by: Wenzhuo Lu --- drivers/net/i40e/Makefile | 1 + drivers/net/i40e/i40e_ethdev.c | 1676 +----------------------------- drivers/net/i40e/i40e_ethdev.h | 11 + drivers/net/i40e/rte_pmd_i40e.c | 1707 +++++++++++++++++++++++++++++++ 4 files changed, 1726 insertions(+), 1669 deletions(-) create mode 100644 drivers/net/i40e/rte_pmd_i40e.c diff --git a/drivers/net/i40e/Makefile b/drivers/net/i40e/Makefile index 1f5d133ce8..56f210d6d6 100644 --- a/drivers/net/i40e/Makefile +++ b/drivers/net/i40e/Makefile @@ -108,6 +108,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_ethdev_vf.c SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_pf.c SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_fdir.c SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_flow.c +SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += rte_pmd_i40e.c # vector PMD driver needs SSE4.1 support ifeq ($(findstring RTE_MACHINE_CPUFLAG_SSE4_1,$(CFLAGS)),) diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index 50e037e724..7ba8c70f31 100644 --- a/drivers/net/i40e/i40e_ethdev.c +++ b/drivers/net/i40e/i40e_ethdev.c @@ -65,7 +65,6 @@ #include "i40e_rxtx.h" #include "i40e_pf.h" #include "i40e_regs.h" -#include "rte_pmd_i40e.h" #define ETH_I40E_FLOATING_VEB_ARG "enable_floating_veb" #define ETH_I40E_FLOATING_VEB_LIST_ARG "floating_veb_list" @@ -245,15 +244,6 @@ /* Bit mask of Extended Tag enable/disable */ #define PCI_DEV_CTRL_EXT_TAG_MASK (1 << PCI_DEV_CTRL_EXT_TAG_SHIFT) -/* The max bandwidth of i40e is 40Gbps. */ -#define I40E_QOS_BW_MAX 40000 -/* The bandwidth should be the multiple of 50Mbps. */ -#define I40E_QOS_BW_GRANULARITY 50 -/* The min bandwidth weight is 1. */ -#define I40E_QOS_BW_WEIGHT_MIN 1 -/* The max bandwidth weight is 127. */ -#define I40E_QOS_BW_WEIGHT_MAX 127 - static int eth_i40e_dev_init(struct rte_eth_dev *eth_dev); static int eth_i40e_dev_uninit(struct rte_eth_dev *eth_dev); static int i40e_dev_configure(struct rte_eth_dev *dev); @@ -343,10 +333,6 @@ static struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, struct i40e_vsi *vsi); static int i40e_pf_config_mq_rx(struct i40e_pf *pf); static int i40e_vsi_config_double_vlan(struct i40e_vsi *vsi, int on); -static inline int i40e_find_all_vlan_for_mac(struct i40e_vsi *vsi, - struct i40e_macvlan_filter *mv_f, - int num, - struct ether_addr *addr); static inline int i40e_find_all_mac_for_vlan(struct i40e_vsi *vsi, struct i40e_macvlan_filter *mv_f, int num, @@ -5862,7 +5848,7 @@ i40e_dev_interrupt_handler(void *param) rte_intr_enable(dev->intr_handle); } -static int +int i40e_add_macvlan_filters(struct i40e_vsi *vsi, struct i40e_macvlan_filter *filter, int total) @@ -5936,7 +5922,7 @@ i40e_add_macvlan_filters(struct i40e_vsi *vsi, return ret; } -static int +int i40e_remove_macvlan_filters(struct i40e_vsi *vsi, struct i40e_macvlan_filter *filter, int total) @@ -6056,7 +6042,7 @@ i40e_store_vlan_filter(struct i40e_vsi *vsi, vsi->vfta[vid_idx] &= ~vid_bit; } -static void +void i40e_set_vlan_filter(struct i40e_vsi *vsi, uint16_t vlan_id, bool on) { @@ -6092,7 +6078,7 @@ i40e_set_vlan_filter(struct i40e_vsi *vsi, * Find all vlan options for specific mac addr, * return with actual vlan found. */ -static inline int +int i40e_find_all_vlan_for_mac(struct i40e_vsi *vsi, struct i40e_macvlan_filter *mv_f, int num, struct ether_addr *addr) @@ -10733,1658 +10719,10 @@ is_device_supported(struct rte_eth_dev *dev, struct rte_pci_driver *drv) return true; } -int -rte_pmd_i40e_ping_vfs(uint8_t port, uint16_t vf) +bool +is_i40e_supported(struct rte_eth_dev *dev) { - struct rte_eth_dev *dev; - struct i40e_pf *pf; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - - if (vf >= pf->vf_num || !pf->vfs) { - PMD_DRV_LOG(ERR, "Invalid argument."); - return -EINVAL; - } - - i40e_notify_vf_link_status(dev, &pf->vfs[vf]); - - return 0; -} - -int -rte_pmd_i40e_set_vf_mac_anti_spoof(uint8_t port, uint16_t vf_id, uint8_t on) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_vsi *vsi; - struct i40e_hw *hw; - struct i40e_vsi_context ctxt; - int ret; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - - if (vf_id >= pf->vf_num || !pf->vfs) { - PMD_DRV_LOG(ERR, "Invalid argument."); - return -EINVAL; - } - - vsi = pf->vfs[vf_id].vsi; - if (!vsi) { - PMD_DRV_LOG(ERR, "Invalid VSI."); - return -EINVAL; - } - - /* Check if it has been already on or off */ - if (vsi->info.valid_sections & - rte_cpu_to_le_16(I40E_AQ_VSI_PROP_SECURITY_VALID)) { - if (on) { - if ((vsi->info.sec_flags & - I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK) == - I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK) - return 0; /* already on */ - } else { - if ((vsi->info.sec_flags & - I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK) == 0) - return 0; /* already off */ - } - } - - vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SECURITY_VALID); - if (on) - vsi->info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK; - else - vsi->info.sec_flags &= ~I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK; - - memset(&ctxt, 0, sizeof(ctxt)); - (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info)); - ctxt.seid = vsi->seid; - - hw = I40E_VSI_TO_HW(vsi); - ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); - if (ret != I40E_SUCCESS) { - ret = -ENOTSUP; - PMD_DRV_LOG(ERR, "Failed to update VSI params"); - } - - return ret; -} - -static int -i40e_add_rm_all_vlan_filter(struct i40e_vsi *vsi, uint8_t add) -{ - uint32_t j, k; - uint16_t vlan_id; - struct i40e_hw *hw = I40E_VSI_TO_HW(vsi); - struct i40e_aqc_add_remove_vlan_element_data vlan_data = {0}; - int ret; - - for (j = 0; j < I40E_VFTA_SIZE; j++) { - if (!vsi->vfta[j]) - continue; - - for (k = 0; k < I40E_UINT32_BIT_SIZE; k++) { - if (!(vsi->vfta[j] & (1 << k))) - continue; - - vlan_id = j * I40E_UINT32_BIT_SIZE + k; - if (!vlan_id) - continue; - - vlan_data.vlan_tag = rte_cpu_to_le_16(vlan_id); - if (add) - ret = i40e_aq_add_vlan(hw, vsi->seid, - &vlan_data, 1, NULL); - else - ret = i40e_aq_remove_vlan(hw, vsi->seid, - &vlan_data, 1, NULL); - if (ret != I40E_SUCCESS) { - PMD_DRV_LOG(ERR, - "Failed to add/rm vlan filter"); - return ret; - } - } - } - - return I40E_SUCCESS; -} - -int -rte_pmd_i40e_set_vf_vlan_anti_spoof(uint8_t port, uint16_t vf_id, uint8_t on) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_vsi *vsi; - struct i40e_hw *hw; - struct i40e_vsi_context ctxt; - int ret; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - - if (vf_id >= pf->vf_num || !pf->vfs) { - PMD_DRV_LOG(ERR, "Invalid argument."); - return -EINVAL; - } - - vsi = pf->vfs[vf_id].vsi; - if (!vsi) { - PMD_DRV_LOG(ERR, "Invalid VSI."); - return -EINVAL; - } - - /* Check if it has been already on or off */ - if (vsi->vlan_anti_spoof_on == on) - return 0; /* already on or off */ - - vsi->vlan_anti_spoof_on = on; - if (!vsi->vlan_filter_on) { - ret = i40e_add_rm_all_vlan_filter(vsi, on); - if (ret) { - PMD_DRV_LOG(ERR, "Failed to add/remove VLAN filters."); - return -ENOTSUP; - } - } - - vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SECURITY_VALID); - if (on) - vsi->info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK; - else - vsi->info.sec_flags &= ~I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK; - - memset(&ctxt, 0, sizeof(ctxt)); - (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info)); - ctxt.seid = vsi->seid; - - hw = I40E_VSI_TO_HW(vsi); - ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); - if (ret != I40E_SUCCESS) { - ret = -ENOTSUP; - PMD_DRV_LOG(ERR, "Failed to update VSI params"); - } - - return ret; -} - -static int -i40e_vsi_rm_mac_filter(struct i40e_vsi *vsi) -{ - struct i40e_mac_filter *f; - struct i40e_macvlan_filter *mv_f; - int i, vlan_num; - enum rte_mac_filter_type filter_type; - int ret = I40E_SUCCESS; - void *temp; - - /* remove all the MACs */ - TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) { - vlan_num = vsi->vlan_num; - filter_type = f->mac_info.filter_type; - if (filter_type == RTE_MACVLAN_PERFECT_MATCH || - filter_type == RTE_MACVLAN_HASH_MATCH) { - if (vlan_num == 0) { - PMD_DRV_LOG(ERR, "VLAN number shouldn't be 0"); - return I40E_ERR_PARAM; - } - } else if (filter_type == RTE_MAC_PERFECT_MATCH || - filter_type == RTE_MAC_HASH_MATCH) - vlan_num = 1; - - mv_f = rte_zmalloc("macvlan_data", vlan_num * sizeof(*mv_f), 0); - if (!mv_f) { - PMD_DRV_LOG(ERR, "failed to allocate memory"); - return I40E_ERR_NO_MEMORY; - } - - for (i = 0; i < vlan_num; i++) { - mv_f[i].filter_type = filter_type; - (void)rte_memcpy(&mv_f[i].macaddr, - &f->mac_info.mac_addr, - ETH_ADDR_LEN); - } - if (filter_type == RTE_MACVLAN_PERFECT_MATCH || - filter_type == RTE_MACVLAN_HASH_MATCH) { - ret = i40e_find_all_vlan_for_mac(vsi, mv_f, vlan_num, - &f->mac_info.mac_addr); - if (ret != I40E_SUCCESS) { - rte_free(mv_f); - return ret; - } - } - - ret = i40e_remove_macvlan_filters(vsi, mv_f, vlan_num); - if (ret != I40E_SUCCESS) { - rte_free(mv_f); - return ret; - } - - rte_free(mv_f); - ret = I40E_SUCCESS; - } - - return ret; -} - -static int -i40e_vsi_restore_mac_filter(struct i40e_vsi *vsi) -{ - struct i40e_mac_filter *f; - struct i40e_macvlan_filter *mv_f; - int i, vlan_num = 0; - int ret = I40E_SUCCESS; - void *temp; - - /* restore all the MACs */ - TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) { - if ((f->mac_info.filter_type == RTE_MACVLAN_PERFECT_MATCH) || - (f->mac_info.filter_type == RTE_MACVLAN_HASH_MATCH)) { - /** - * If vlan_num is 0, that's the first time to add mac, - * set mask for vlan_id 0. - */ - if (vsi->vlan_num == 0) { - i40e_set_vlan_filter(vsi, 0, 1); - vsi->vlan_num = 1; - } - vlan_num = vsi->vlan_num; - } else if ((f->mac_info.filter_type == RTE_MAC_PERFECT_MATCH) || - (f->mac_info.filter_type == RTE_MAC_HASH_MATCH)) - vlan_num = 1; - - mv_f = rte_zmalloc("macvlan_data", vlan_num * sizeof(*mv_f), 0); - if (!mv_f) { - PMD_DRV_LOG(ERR, "failed to allocate memory"); - return I40E_ERR_NO_MEMORY; - } - - for (i = 0; i < vlan_num; i++) { - mv_f[i].filter_type = f->mac_info.filter_type; - (void)rte_memcpy(&mv_f[i].macaddr, - &f->mac_info.mac_addr, - ETH_ADDR_LEN); - } - - if (f->mac_info.filter_type == RTE_MACVLAN_PERFECT_MATCH || - f->mac_info.filter_type == RTE_MACVLAN_HASH_MATCH) { - ret = i40e_find_all_vlan_for_mac(vsi, mv_f, vlan_num, - &f->mac_info.mac_addr); - if (ret != I40E_SUCCESS) { - rte_free(mv_f); - return ret; - } - } - - ret = i40e_add_macvlan_filters(vsi, mv_f, vlan_num); - if (ret != I40E_SUCCESS) { - rte_free(mv_f); - return ret; - } - - rte_free(mv_f); - ret = I40E_SUCCESS; - } - - return ret; -} - -static int -i40e_vsi_set_tx_loopback(struct i40e_vsi *vsi, uint8_t on) -{ - struct i40e_vsi_context ctxt; - struct i40e_hw *hw; - int ret; - - if (!vsi) - return -EINVAL; - - hw = I40E_VSI_TO_HW(vsi); - - /* Use the FW API if FW >= v5.0 */ - if (hw->aq.fw_maj_ver < 5) { - PMD_INIT_LOG(ERR, "FW < v5.0, cannot enable loopback"); - return -ENOTSUP; - } - - /* Check if it has been already on or off */ - if (vsi->info.valid_sections & - rte_cpu_to_le_16(I40E_AQ_VSI_PROP_SWITCH_VALID)) { - if (on) { - if ((vsi->info.switch_id & - I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB) == - I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB) - return 0; /* already on */ - } else { - if ((vsi->info.switch_id & - I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB) == 0) - return 0; /* already off */ - } - } - - /* remove all the MAC and VLAN first */ - ret = i40e_vsi_rm_mac_filter(vsi); - if (ret) { - PMD_INIT_LOG(ERR, "Failed to remove MAC filters."); - return ret; - } - if (vsi->vlan_anti_spoof_on || vsi->vlan_filter_on) { - ret = i40e_add_rm_all_vlan_filter(vsi, 0); - if (ret) { - PMD_INIT_LOG(ERR, "Failed to remove VLAN filters."); - return ret; - } - } - - vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID); - if (on) - vsi->info.switch_id |= I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB; - else - vsi->info.switch_id &= ~I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB; - - memset(&ctxt, 0, sizeof(ctxt)); - (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info)); - ctxt.seid = vsi->seid; - - ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); - if (ret != I40E_SUCCESS) { - PMD_DRV_LOG(ERR, "Failed to update VSI params"); - return ret; - } - - /* add all the MAC and VLAN back */ - ret = i40e_vsi_restore_mac_filter(vsi); - if (ret) - return ret; - if (vsi->vlan_anti_spoof_on || vsi->vlan_filter_on) { - ret = i40e_add_rm_all_vlan_filter(vsi, 1); - if (ret) - return ret; - } - - return ret; -} - -int -rte_pmd_i40e_set_tx_loopback(uint8_t port, uint8_t on) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_pf_vf *vf; - struct i40e_vsi *vsi; - uint16_t vf_id; - int ret; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - - /* setup PF TX loopback */ - vsi = pf->main_vsi; - ret = i40e_vsi_set_tx_loopback(vsi, on); - if (ret) - return -ENOTSUP; - - /* setup TX loopback for all the VFs */ - if (!pf->vfs) { - /* if no VF, do nothing. */ - return 0; - } - - for (vf_id = 0; vf_id < pf->vf_num; vf_id++) { - vf = &pf->vfs[vf_id]; - vsi = vf->vsi; - - ret = i40e_vsi_set_tx_loopback(vsi, on); - if (ret) - return -ENOTSUP; - } - - return ret; -} - -int -rte_pmd_i40e_set_vf_unicast_promisc(uint8_t port, uint16_t vf_id, uint8_t on) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_vsi *vsi; - struct i40e_hw *hw; - int ret; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - - if (vf_id >= pf->vf_num || !pf->vfs) { - PMD_DRV_LOG(ERR, "Invalid argument."); - return -EINVAL; - } - - vsi = pf->vfs[vf_id].vsi; - if (!vsi) { - PMD_DRV_LOG(ERR, "Invalid VSI."); - return -EINVAL; - } - - hw = I40E_VSI_TO_HW(vsi); - - ret = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid, - on, NULL, true); - if (ret != I40E_SUCCESS) { - ret = -ENOTSUP; - PMD_DRV_LOG(ERR, "Failed to set unicast promiscuous mode"); - } - - return ret; -} - -int -rte_pmd_i40e_set_vf_multicast_promisc(uint8_t port, uint16_t vf_id, uint8_t on) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_vsi *vsi; - struct i40e_hw *hw; - int ret; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - - if (vf_id >= pf->vf_num || !pf->vfs) { - PMD_DRV_LOG(ERR, "Invalid argument."); - return -EINVAL; - } - - vsi = pf->vfs[vf_id].vsi; - if (!vsi) { - PMD_DRV_LOG(ERR, "Invalid VSI."); - return -EINVAL; - } - - hw = I40E_VSI_TO_HW(vsi); - - ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid, - on, NULL); - if (ret != I40E_SUCCESS) { - ret = -ENOTSUP; - PMD_DRV_LOG(ERR, "Failed to set multicast promiscuous mode"); - } - - return ret; -} - -int -rte_pmd_i40e_set_vf_mac_addr(uint8_t port, uint16_t vf_id, - struct ether_addr *mac_addr) -{ - struct i40e_mac_filter *f; - struct rte_eth_dev *dev; - struct i40e_pf_vf *vf; - struct i40e_vsi *vsi; - struct i40e_pf *pf; - void *temp; - - if (i40e_validate_mac_addr((u8 *)mac_addr) != I40E_SUCCESS) - return -EINVAL; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - - if (vf_id >= pf->vf_num || !pf->vfs) - return -EINVAL; - - vf = &pf->vfs[vf_id]; - vsi = vf->vsi; - if (!vsi) { - PMD_DRV_LOG(ERR, "Invalid VSI."); - return -EINVAL; - } - - ether_addr_copy(mac_addr, &vf->mac_addr); - - /* Remove all existing mac */ - TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) - i40e_vsi_delete_mac(vsi, &f->mac_info.mac_addr); - - return 0; -} - -/* Set vlan strip on/off for specific VF from host */ -int -rte_pmd_i40e_set_vf_vlan_stripq(uint8_t port, uint16_t vf_id, uint8_t on) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_vsi *vsi; - int ret; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - - if (vf_id >= pf->vf_num || !pf->vfs) { - PMD_DRV_LOG(ERR, "Invalid argument."); - return -EINVAL; - } - - vsi = pf->vfs[vf_id].vsi; - - if (!vsi) - return -EINVAL; - - ret = i40e_vsi_config_vlan_stripping(vsi, !!on); - if (ret != I40E_SUCCESS) { - ret = -ENOTSUP; - PMD_DRV_LOG(ERR, "Failed to set VLAN stripping!"); - } - - return ret; -} - -int rte_pmd_i40e_set_vf_vlan_insert(uint8_t port, uint16_t vf_id, - uint16_t vlan_id) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_hw *hw; - struct i40e_vsi *vsi; - struct i40e_vsi_context ctxt; - int ret; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - if (vlan_id > ETHER_MAX_VLAN_ID) { - PMD_DRV_LOG(ERR, "Invalid VLAN ID."); - return -EINVAL; - } - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - hw = I40E_PF_TO_HW(pf); - - /** - * return -ENODEV if SRIOV not enabled, VF number not configured - * or no queue assigned. - */ - if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 || - pf->vf_nb_qps == 0) - return -ENODEV; - - if (vf_id >= pf->vf_num || !pf->vfs) { - PMD_DRV_LOG(ERR, "Invalid VF ID."); - return -EINVAL; - } - - vsi = pf->vfs[vf_id].vsi; - if (!vsi) { - PMD_DRV_LOG(ERR, "Invalid VSI."); - return -EINVAL; - } - - vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID); - vsi->info.pvid = vlan_id; - if (vlan_id > 0) - vsi->info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_INSERT_PVID; - else - vsi->info.port_vlan_flags &= ~I40E_AQ_VSI_PVLAN_INSERT_PVID; - - memset(&ctxt, 0, sizeof(ctxt)); - (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info)); - ctxt.seid = vsi->seid; - - hw = I40E_VSI_TO_HW(vsi); - ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); - if (ret != I40E_SUCCESS) { - ret = -ENOTSUP; - PMD_DRV_LOG(ERR, "Failed to update VSI params"); - } - - return ret; -} - -int rte_pmd_i40e_set_vf_broadcast(uint8_t port, uint16_t vf_id, - uint8_t on) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_vsi *vsi; - struct i40e_hw *hw; - struct i40e_mac_filter_info filter; - struct ether_addr broadcast = { - .addr_bytes = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} }; - int ret; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - if (on > 1) { - PMD_DRV_LOG(ERR, "on should be 0 or 1."); - return -EINVAL; - } - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - hw = I40E_PF_TO_HW(pf); - - if (vf_id >= pf->vf_num || !pf->vfs) { - PMD_DRV_LOG(ERR, "Invalid VF ID."); - return -EINVAL; - } - - /** - * return -ENODEV if SRIOV not enabled, VF number not configured - * or no queue assigned. - */ - if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 || - pf->vf_nb_qps == 0) { - PMD_DRV_LOG(ERR, "SRIOV is not enabled or no queue."); - return -ENODEV; - } - - vsi = pf->vfs[vf_id].vsi; - if (!vsi) { - PMD_DRV_LOG(ERR, "Invalid VSI."); - return -EINVAL; - } - - if (on) { - (void)rte_memcpy(&filter.mac_addr, &broadcast, ETHER_ADDR_LEN); - filter.filter_type = RTE_MACVLAN_PERFECT_MATCH; - ret = i40e_vsi_add_mac(vsi, &filter); - } else { - ret = i40e_vsi_delete_mac(vsi, &broadcast); - } - - if (ret != I40E_SUCCESS && ret != I40E_ERR_PARAM) { - ret = -ENOTSUP; - PMD_DRV_LOG(ERR, "Failed to set VSI broadcast"); - } else { - ret = 0; - } - - return ret; -} - -int rte_pmd_i40e_set_vf_vlan_tag(uint8_t port, uint16_t vf_id, uint8_t on) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_hw *hw; - struct i40e_vsi *vsi; - struct i40e_vsi_context ctxt; - int ret; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - if (on > 1) { - PMD_DRV_LOG(ERR, "on should be 0 or 1."); - return -EINVAL; - } - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - hw = I40E_PF_TO_HW(pf); - - /** - * return -ENODEV if SRIOV not enabled, VF number not configured - * or no queue assigned. - */ - if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 || - pf->vf_nb_qps == 0) { - PMD_DRV_LOG(ERR, "SRIOV is not enabled or no queue."); - return -ENODEV; - } - - if (vf_id >= pf->vf_num || !pf->vfs) { - PMD_DRV_LOG(ERR, "Invalid VF ID."); - return -EINVAL; - } - - vsi = pf->vfs[vf_id].vsi; - if (!vsi) { - PMD_DRV_LOG(ERR, "Invalid VSI."); - return -EINVAL; - } - - vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID); - if (on) { - vsi->info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_TAGGED; - vsi->info.port_vlan_flags &= ~I40E_AQ_VSI_PVLAN_MODE_UNTAGGED; - } else { - vsi->info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_UNTAGGED; - vsi->info.port_vlan_flags &= ~I40E_AQ_VSI_PVLAN_MODE_TAGGED; - } - - memset(&ctxt, 0, sizeof(ctxt)); - (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info)); - ctxt.seid = vsi->seid; - - hw = I40E_VSI_TO_HW(vsi); - ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); - if (ret != I40E_SUCCESS) { - ret = -ENOTSUP; - PMD_DRV_LOG(ERR, "Failed to update VSI params"); - } - - return ret; -} - -static int -i40e_vlan_filter_count(struct i40e_vsi *vsi) -{ - uint32_t j, k; - uint16_t vlan_id; - int count = 0; - - for (j = 0; j < I40E_VFTA_SIZE; j++) { - if (!vsi->vfta[j]) - continue; - - for (k = 0; k < I40E_UINT32_BIT_SIZE; k++) { - if (!(vsi->vfta[j] & (1 << k))) - continue; - - vlan_id = j * I40E_UINT32_BIT_SIZE + k; - if (!vlan_id) - continue; - - count++; - } - } - - return count; -} - -int rte_pmd_i40e_set_vf_vlan_filter(uint8_t port, uint16_t vlan_id, - uint64_t vf_mask, uint8_t on) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_hw *hw; - struct i40e_vsi *vsi; - uint16_t vf_idx; - int ret = I40E_SUCCESS; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - if (vlan_id > ETHER_MAX_VLAN_ID || !vlan_id) { - PMD_DRV_LOG(ERR, "Invalid VLAN ID."); - return -EINVAL; - } - - if (vf_mask == 0) { - PMD_DRV_LOG(ERR, "No VF."); - return -EINVAL; - } - - if (on > 1) { - PMD_DRV_LOG(ERR, "on is should be 0 or 1."); - return -EINVAL; - } - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - hw = I40E_PF_TO_HW(pf); - - /** - * return -ENODEV if SRIOV not enabled, VF number not configured - * or no queue assigned. - */ - if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 || - pf->vf_nb_qps == 0) { - PMD_DRV_LOG(ERR, "SRIOV is not enabled or no queue."); - return -ENODEV; - } - - for (vf_idx = 0; vf_idx < pf->vf_num && ret == I40E_SUCCESS; vf_idx++) { - if (vf_mask & ((uint64_t)(1ULL << vf_idx))) { - vsi = pf->vfs[vf_idx].vsi; - if (on) { - if (!vsi->vlan_filter_on) { - vsi->vlan_filter_on = true; - i40e_aq_set_vsi_vlan_promisc(hw, - vsi->seid, - false, - NULL); - if (!vsi->vlan_anti_spoof_on) - i40e_add_rm_all_vlan_filter( - vsi, true); - } - ret = i40e_vsi_add_vlan(vsi, vlan_id); - } else { - ret = i40e_vsi_delete_vlan(vsi, vlan_id); - - if (!i40e_vlan_filter_count(vsi)) { - vsi->vlan_filter_on = false; - i40e_aq_set_vsi_vlan_promisc(hw, - vsi->seid, - true, - NULL); - } - } - } - } - - if (ret != I40E_SUCCESS) { - ret = -ENOTSUP; - PMD_DRV_LOG(ERR, "Failed to set VF VLAN filter, on = %d", on); - } - - return ret; -} - -int -rte_pmd_i40e_get_vf_stats(uint8_t port, - uint16_t vf_id, - struct rte_eth_stats *stats) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_vsi *vsi; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - - if (vf_id >= pf->vf_num || !pf->vfs) { - PMD_DRV_LOG(ERR, "Invalid VF ID."); - return -EINVAL; - } - - vsi = pf->vfs[vf_id].vsi; - if (!vsi) { - PMD_DRV_LOG(ERR, "Invalid VSI."); - return -EINVAL; - } - - i40e_update_vsi_stats(vsi); - - stats->ipackets = vsi->eth_stats.rx_unicast + - vsi->eth_stats.rx_multicast + - vsi->eth_stats.rx_broadcast; - stats->opackets = vsi->eth_stats.tx_unicast + - vsi->eth_stats.tx_multicast + - vsi->eth_stats.tx_broadcast; - stats->ibytes = vsi->eth_stats.rx_bytes; - stats->obytes = vsi->eth_stats.tx_bytes; - stats->ierrors = vsi->eth_stats.rx_discards; - stats->oerrors = vsi->eth_stats.tx_errors + vsi->eth_stats.tx_discards; - - return 0; -} - -int -rte_pmd_i40e_reset_vf_stats(uint8_t port, - uint16_t vf_id) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_vsi *vsi; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - - if (vf_id >= pf->vf_num || !pf->vfs) { - PMD_DRV_LOG(ERR, "Invalid VF ID."); - return -EINVAL; - } - - vsi = pf->vfs[vf_id].vsi; - if (!vsi) { - PMD_DRV_LOG(ERR, "Invalid VSI."); - return -EINVAL; - } - - vsi->offset_loaded = false; - i40e_update_vsi_stats(vsi); - - return 0; -} - -int -rte_pmd_i40e_set_vf_max_bw(uint8_t port, uint16_t vf_id, uint32_t bw) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_vsi *vsi; - struct i40e_hw *hw; - int ret = 0; - int i; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - - if (vf_id >= pf->vf_num || !pf->vfs) { - PMD_DRV_LOG(ERR, "Invalid VF ID."); - return -EINVAL; - } - - vsi = pf->vfs[vf_id].vsi; - if (!vsi) { - PMD_DRV_LOG(ERR, "Invalid VSI."); - return -EINVAL; - } - - if (bw > I40E_QOS_BW_MAX) { - PMD_DRV_LOG(ERR, "Bandwidth should not be larger than %dMbps.", - I40E_QOS_BW_MAX); - return -EINVAL; - } - - if (bw % I40E_QOS_BW_GRANULARITY) { - PMD_DRV_LOG(ERR, "Bandwidth should be the multiple of %dMbps.", - I40E_QOS_BW_GRANULARITY); - return -EINVAL; - } - - bw /= I40E_QOS_BW_GRANULARITY; - - hw = I40E_VSI_TO_HW(vsi); - - /* No change. */ - if (bw == vsi->bw_info.bw_limit) { - PMD_DRV_LOG(INFO, - "No change for VF max bandwidth. Nothing to do."); - return 0; - } - - /** - * VF bandwidth limitation and TC bandwidth limitation cannot be - * enabled in parallel, quit if TC bandwidth limitation is enabled. - * - * If bw is 0, means disable bandwidth limitation. Then no need to - * check TC bandwidth limitation. - */ - if (bw) { - for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if ((vsi->enabled_tc & BIT_ULL(i)) && - vsi->bw_info.bw_ets_credits[i]) - break; - } - if (i != I40E_MAX_TRAFFIC_CLASS) { - PMD_DRV_LOG(ERR, - "TC max bandwidth has been set on this VF," - " please disable it first."); - return -EINVAL; - } - } - - ret = i40e_aq_config_vsi_bw_limit(hw, vsi->seid, (uint16_t)bw, 0, NULL); - if (ret) { - PMD_DRV_LOG(ERR, - "Failed to set VF %d bandwidth, err(%d).", - vf_id, ret); - return -EINVAL; - } - - /* Store the configuration. */ - vsi->bw_info.bw_limit = (uint16_t)bw; - vsi->bw_info.bw_max = 0; - - return 0; -} - -int -rte_pmd_i40e_set_vf_tc_bw_alloc(uint8_t port, uint16_t vf_id, - uint8_t tc_num, uint8_t *bw_weight) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_vsi *vsi; - struct i40e_hw *hw; - struct i40e_aqc_configure_vsi_tc_bw_data tc_bw; - int ret = 0; - int i, j; - uint16_t sum; - bool b_change = false; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - - if (vf_id >= pf->vf_num || !pf->vfs) { - PMD_DRV_LOG(ERR, "Invalid VF ID."); - return -EINVAL; - } - - vsi = pf->vfs[vf_id].vsi; - if (!vsi) { - PMD_DRV_LOG(ERR, "Invalid VSI."); - return -EINVAL; - } - - if (tc_num > I40E_MAX_TRAFFIC_CLASS) { - PMD_DRV_LOG(ERR, "TCs should be no more than %d.", - I40E_MAX_TRAFFIC_CLASS); - return -EINVAL; - } - - sum = 0; - for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (vsi->enabled_tc & BIT_ULL(i)) - sum++; - } - if (sum != tc_num) { - PMD_DRV_LOG(ERR, - "Weight should be set for all %d enabled TCs.", - sum); - return -EINVAL; - } - - sum = 0; - for (i = 0; i < tc_num; i++) { - if (!bw_weight[i]) { - PMD_DRV_LOG(ERR, - "The weight should be 1 at least."); - return -EINVAL; - } - sum += bw_weight[i]; - } - if (sum != 100) { - PMD_DRV_LOG(ERR, - "The summary of the TC weight should be 100."); - return -EINVAL; - } - - /** - * Create the configuration for all the TCs. - */ - memset(&tc_bw, 0, sizeof(tc_bw)); - tc_bw.tc_valid_bits = vsi->enabled_tc; - j = 0; - for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (vsi->enabled_tc & BIT_ULL(i)) { - if (bw_weight[j] != - vsi->bw_info.bw_ets_share_credits[i]) - b_change = true; - - tc_bw.tc_bw_credits[i] = bw_weight[j]; - j++; - } - } - - /* No change. */ - if (!b_change) { - PMD_DRV_LOG(INFO, - "No change for TC allocated bandwidth." - " Nothing to do."); - return 0; - } - - hw = I40E_VSI_TO_HW(vsi); - - ret = i40e_aq_config_vsi_tc_bw(hw, vsi->seid, &tc_bw, NULL); - if (ret) { - PMD_DRV_LOG(ERR, - "Failed to set VF %d TC bandwidth weight, err(%d).", - vf_id, ret); - return -EINVAL; - } - - /* Store the configuration. */ - j = 0; - for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (vsi->enabled_tc & BIT_ULL(i)) { - vsi->bw_info.bw_ets_share_credits[i] = bw_weight[j]; - j++; - } - } - - return 0; -} - -int -rte_pmd_i40e_set_vf_tc_max_bw(uint8_t port, uint16_t vf_id, - uint8_t tc_no, uint32_t bw) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_vsi *vsi; - struct i40e_hw *hw; - struct i40e_aqc_configure_vsi_ets_sla_bw_data tc_bw; - int ret = 0; - int i; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - - if (vf_id >= pf->vf_num || !pf->vfs) { - PMD_DRV_LOG(ERR, "Invalid VF ID."); - return -EINVAL; - } - - vsi = pf->vfs[vf_id].vsi; - if (!vsi) { - PMD_DRV_LOG(ERR, "Invalid VSI."); - return -EINVAL; - } - - if (bw > I40E_QOS_BW_MAX) { - PMD_DRV_LOG(ERR, "Bandwidth should not be larger than %dMbps.", - I40E_QOS_BW_MAX); - return -EINVAL; - } - - if (bw % I40E_QOS_BW_GRANULARITY) { - PMD_DRV_LOG(ERR, "Bandwidth should be the multiple of %dMbps.", - I40E_QOS_BW_GRANULARITY); - return -EINVAL; - } - - bw /= I40E_QOS_BW_GRANULARITY; - - if (tc_no >= I40E_MAX_TRAFFIC_CLASS) { - PMD_DRV_LOG(ERR, "TC No. should be less than %d.", - I40E_MAX_TRAFFIC_CLASS); - return -EINVAL; - } - - hw = I40E_VSI_TO_HW(vsi); - - if (!(vsi->enabled_tc & BIT_ULL(tc_no))) { - PMD_DRV_LOG(ERR, "VF %d TC %d isn't enabled.", - vf_id, tc_no); - return -EINVAL; - } - - /* No change. */ - if (bw == vsi->bw_info.bw_ets_credits[tc_no]) { - PMD_DRV_LOG(INFO, - "No change for TC max bandwidth. Nothing to do."); - return 0; - } - - /** - * VF bandwidth limitation and TC bandwidth limitation cannot be - * enabled in parallel, disable VF bandwidth limitation if it's - * enabled. - * If bw is 0, means disable bandwidth limitation. Then no need to - * care about VF bandwidth limitation configuration. - */ - if (bw && vsi->bw_info.bw_limit) { - ret = i40e_aq_config_vsi_bw_limit(hw, vsi->seid, 0, 0, NULL); - if (ret) { - PMD_DRV_LOG(ERR, - "Failed to disable VF(%d)" - " bandwidth limitation, err(%d).", - vf_id, ret); - return -EINVAL; - } - - PMD_DRV_LOG(INFO, - "VF max bandwidth is disabled according" - " to TC max bandwidth setting."); - } - - /** - * Get all the TCs' info to create a whole picture. - * Because the incremental change isn't permitted. - */ - memset(&tc_bw, 0, sizeof(tc_bw)); - tc_bw.tc_valid_bits = vsi->enabled_tc; - for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (vsi->enabled_tc & BIT_ULL(i)) { - tc_bw.tc_bw_credits[i] = - rte_cpu_to_le_16( - vsi->bw_info.bw_ets_credits[i]); - } - } - tc_bw.tc_bw_credits[tc_no] = rte_cpu_to_le_16((uint16_t)bw); - - ret = i40e_aq_config_vsi_ets_sla_bw_limit(hw, vsi->seid, &tc_bw, NULL); - if (ret) { - PMD_DRV_LOG(ERR, - "Failed to set VF %d TC %d max bandwidth, err(%d).", - vf_id, tc_no, ret); - return -EINVAL; - } - - /* Store the configuration. */ - vsi->bw_info.bw_ets_credits[tc_no] = (uint16_t)bw; - - return 0; -} - -int -rte_pmd_i40e_set_tc_strict_prio(uint8_t port, uint8_t tc_map) -{ - struct rte_eth_dev *dev; - struct i40e_pf *pf; - struct i40e_vsi *vsi; - struct i40e_veb *veb; - struct i40e_hw *hw; - struct i40e_aqc_configure_switching_comp_ets_data ets_data; - int i; - int ret; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - - vsi = pf->main_vsi; - if (!vsi) { - PMD_DRV_LOG(ERR, "Invalid VSI."); - return -EINVAL; - } - - veb = vsi->veb; - if (!veb) { - PMD_DRV_LOG(ERR, "Invalid VEB."); - return -EINVAL; - } - - if ((tc_map & veb->enabled_tc) != tc_map) { - PMD_DRV_LOG(ERR, - "TC bitmap isn't the subset of enabled TCs 0x%x.", - veb->enabled_tc); - return -EINVAL; - } - - if (tc_map == veb->strict_prio_tc) { - PMD_DRV_LOG(INFO, "No change for TC bitmap. Nothing to do."); - return 0; - } - - hw = I40E_VSI_TO_HW(vsi); - - /* Disable DCBx if it's the first time to set strict priority. */ - if (!veb->strict_prio_tc) { - ret = i40e_aq_stop_lldp(hw, true, NULL); - if (ret) - PMD_DRV_LOG(INFO, - "Failed to disable DCBx as it's already" - " disabled."); - else - PMD_DRV_LOG(INFO, - "DCBx is disabled according to strict" - " priority setting."); - } - - memset(&ets_data, 0, sizeof(ets_data)); - ets_data.tc_valid_bits = veb->enabled_tc; - ets_data.seepage = I40E_AQ_ETS_SEEPAGE_EN_MASK; - ets_data.tc_strict_priority_flags = tc_map; - /* Get all TCs' bandwidth. */ - for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (veb->enabled_tc & BIT_ULL(i)) { - /* For rubust, if bandwidth is 0, use 1 instead. */ - if (veb->bw_info.bw_ets_share_credits[i]) - ets_data.tc_bw_share_credits[i] = - veb->bw_info.bw_ets_share_credits[i]; - else - ets_data.tc_bw_share_credits[i] = - I40E_QOS_BW_WEIGHT_MIN; - } - } - - if (!veb->strict_prio_tc) - ret = i40e_aq_config_switch_comp_ets( - hw, veb->uplink_seid, - &ets_data, i40e_aqc_opc_enable_switching_comp_ets, - NULL); - else if (tc_map) - ret = i40e_aq_config_switch_comp_ets( - hw, veb->uplink_seid, - &ets_data, i40e_aqc_opc_modify_switching_comp_ets, - NULL); - else - ret = i40e_aq_config_switch_comp_ets( - hw, veb->uplink_seid, - &ets_data, i40e_aqc_opc_disable_switching_comp_ets, - NULL); - - if (ret) { - PMD_DRV_LOG(ERR, - "Failed to set TCs' strict priority mode." - " err (%d)", ret); - return -EINVAL; - } - - veb->strict_prio_tc = tc_map; - - /* Enable DCBx again, if all the TCs' strict priority disabled. */ - if (!tc_map) { - ret = i40e_aq_start_lldp(hw, NULL); - if (ret) { - PMD_DRV_LOG(ERR, - "Failed to enable DCBx, err(%d).", ret); - return -EINVAL; - } - - PMD_DRV_LOG(INFO, - "DCBx is enabled again according to strict" - " priority setting."); - } - - return ret; -} - -#define I40E_PROFILE_INFO_SIZE 48 -#define I40E_MAX_PROFILE_NUM 16 - -static void -i40e_generate_profile_info_sec(char *name, struct i40e_ddp_version *version, - uint32_t track_id, uint8_t *profile_info_sec, - bool add) -{ - struct i40e_profile_section_header *sec = NULL; - struct i40e_profile_info *pinfo; - - sec = (struct i40e_profile_section_header *)profile_info_sec; - sec->tbl_size = 1; - sec->data_end = sizeof(struct i40e_profile_section_header) + - sizeof(struct i40e_profile_info); - sec->section.type = SECTION_TYPE_INFO; - sec->section.offset = sizeof(struct i40e_profile_section_header); - sec->section.size = sizeof(struct i40e_profile_info); - pinfo = (struct i40e_profile_info *)(profile_info_sec + - sec->section.offset); - pinfo->track_id = track_id; - memcpy(pinfo->name, name, I40E_DDP_NAME_SIZE); - memcpy(&pinfo->version, version, sizeof(struct i40e_ddp_version)); - if (add) - pinfo->op = I40E_DDP_ADD_TRACKID; - else - pinfo->op = I40E_DDP_REMOVE_TRACKID; -} - -static enum i40e_status_code -i40e_add_rm_profile_info(struct i40e_hw *hw, uint8_t *profile_info_sec) -{ - enum i40e_status_code status = I40E_SUCCESS; - struct i40e_profile_section_header *sec; - uint32_t track_id; - uint32_t offset = 0; - uint32_t info = 0; - - sec = (struct i40e_profile_section_header *)profile_info_sec; - track_id = ((struct i40e_profile_info *)(profile_info_sec + - sec->section.offset))->track_id; - - status = i40e_aq_write_ddp(hw, (void *)sec, sec->data_end, - track_id, &offset, &info, NULL); - if (status) - PMD_DRV_LOG(ERR, "Failed to add/remove profile info: " - "offset %d, info %d", - offset, info); - - return status; -} - -#define I40E_PROFILE_INFO_SIZE 48 -#define I40E_MAX_PROFILE_NUM 16 - -/* Check if the profile info exists */ -static int -i40e_check_profile_info(uint8_t port, uint8_t *profile_info_sec) -{ - struct rte_eth_dev *dev = &rte_eth_devices[port]; - struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint8_t *buff; - struct rte_pmd_i40e_profile_list *p_list; - struct rte_pmd_i40e_profile_info *pinfo, *p; - uint32_t i; - int ret; - - buff = rte_zmalloc("pinfo_list", - (I40E_PROFILE_INFO_SIZE * I40E_MAX_PROFILE_NUM + 4), - 0); - if (!buff) { - PMD_DRV_LOG(ERR, "failed to allocate memory"); - return -1; - } - - ret = i40e_aq_get_ddp_list(hw, (void *)buff, - (I40E_PROFILE_INFO_SIZE * I40E_MAX_PROFILE_NUM + 4), - 0, NULL); - if (ret) { - PMD_DRV_LOG(ERR, "Failed to get profile info list."); - rte_free(buff); - return -1; - } - p_list = (struct rte_pmd_i40e_profile_list *)buff; - pinfo = (struct rte_pmd_i40e_profile_info *)(profile_info_sec + - sizeof(struct i40e_profile_section_header)); - for (i = 0; i < p_list->p_count; i++) { - p = &p_list->p_info[i]; - if ((pinfo->track_id == p->track_id) && - !memcmp(&pinfo->version, &p->version, - sizeof(struct i40e_ddp_version)) && - !memcmp(&pinfo->name, &p->name, - I40E_DDP_NAME_SIZE)) { - PMD_DRV_LOG(INFO, "Profile exists."); - rte_free(buff); - return 1; - } - } - - rte_free(buff); - return 0; -} - -int -rte_pmd_i40e_process_ddp_package(uint8_t port, uint8_t *buff, - uint32_t size, - enum rte_pmd_i40e_package_op op) -{ - struct rte_eth_dev *dev; - struct i40e_hw *hw; - struct i40e_package_header *pkg_hdr; - struct i40e_generic_seg_header *profile_seg_hdr; - struct i40e_generic_seg_header *metadata_seg_hdr; - uint32_t track_id; - uint8_t *profile_info_sec; - int is_exist; - enum i40e_status_code status = I40E_SUCCESS; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); - - if (size < (sizeof(struct i40e_package_header) + - sizeof(struct i40e_metadata_segment) + - sizeof(uint32_t) * 2)) { - PMD_DRV_LOG(ERR, "Buff is invalid."); - return -EINVAL; - } - - pkg_hdr = (struct i40e_package_header *)buff; - - if (!pkg_hdr) { - PMD_DRV_LOG(ERR, "Failed to fill the package structure"); - return -EINVAL; - } - - if (pkg_hdr->segment_count < 2) { - PMD_DRV_LOG(ERR, "Segment_count should be 2 at least."); - return -EINVAL; - } - - /* Find metadata segment */ - metadata_seg_hdr = i40e_find_segment_in_package(SEGMENT_TYPE_METADATA, - pkg_hdr); - if (!metadata_seg_hdr) { - PMD_DRV_LOG(ERR, "Failed to find metadata segment header"); - return -EINVAL; - } - track_id = ((struct i40e_metadata_segment *)metadata_seg_hdr)->track_id; - - /* Find profile segment */ - profile_seg_hdr = i40e_find_segment_in_package(SEGMENT_TYPE_I40E, - pkg_hdr); - if (!profile_seg_hdr) { - PMD_DRV_LOG(ERR, "Failed to find profile segment header"); - return -EINVAL; - } - - profile_info_sec = rte_zmalloc("i40e_profile_info", - sizeof(struct i40e_profile_section_header) + - sizeof(struct i40e_profile_info), - 0); - if (!profile_info_sec) { - PMD_DRV_LOG(ERR, "Failed to allocate memory"); - return -EINVAL; - } - - if (op == RTE_PMD_I40E_PKG_OP_WR_ADD) { - /* Check if the profile exists */ - i40e_generate_profile_info_sec( - ((struct i40e_profile_segment *)profile_seg_hdr)->name, - &((struct i40e_profile_segment *)profile_seg_hdr)->version, - track_id, profile_info_sec, 1); - is_exist = i40e_check_profile_info(port, profile_info_sec); - if (is_exist > 0) { - PMD_DRV_LOG(ERR, "Profile already exists."); - rte_free(profile_info_sec); - return 1; - } else if (is_exist < 0) { - PMD_DRV_LOG(ERR, "Failed to check profile."); - rte_free(profile_info_sec); - return -EINVAL; - } - - /* Write profile to HW */ - status = i40e_write_profile(hw, - (struct i40e_profile_segment *)profile_seg_hdr, - track_id); - if (status) { - PMD_DRV_LOG(ERR, "Failed to write profile."); - rte_free(profile_info_sec); - return status; - } - - /* Add profile info to info list */ - status = i40e_add_rm_profile_info(hw, profile_info_sec); - if (status) - PMD_DRV_LOG(ERR, "Failed to add profile info."); - } else - PMD_DRV_LOG(ERR, "Operation not supported."); - - rte_free(profile_info_sec); - return status; -} - -int -rte_pmd_i40e_get_ddp_list(uint8_t port, uint8_t *buff, uint32_t size) -{ - struct rte_eth_dev *dev; - struct i40e_hw *hw; - enum i40e_status_code status = I40E_SUCCESS; - - RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); - - dev = &rte_eth_devices[port]; - - if (!is_device_supported(dev, &rte_i40e_pmd)) - return -ENOTSUP; - - if (size < (I40E_PROFILE_INFO_SIZE * I40E_MAX_PROFILE_NUM + 4)) - return -EINVAL; - - hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); - - status = i40e_aq_get_ddp_list(hw, (void *)buff, - size, 0, NULL); - - return status; + return is_device_supported(dev, &rte_i40e_pmd); } /* Create a QinQ cloud filter diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h index 69c6684d88..c745e9b462 100644 --- a/drivers/net/i40e/i40e_ethdev.h +++ b/drivers/net/i40e/i40e_ethdev.h @@ -869,6 +869,17 @@ int i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf, struct i40e_tunnel_filter_conf *tunnel_filter, uint8_t add); int i40e_fdir_flush(struct rte_eth_dev *dev); +int i40e_find_all_vlan_for_mac(struct i40e_vsi *vsi, + struct i40e_macvlan_filter *mv_f, + int num, struct ether_addr *addr); +int i40e_remove_macvlan_filters(struct i40e_vsi *vsi, + struct i40e_macvlan_filter *filter, + int total); +void i40e_set_vlan_filter(struct i40e_vsi *vsi, uint16_t vlan_id, bool on); +int i40e_add_macvlan_filters(struct i40e_vsi *vsi, + struct i40e_macvlan_filter *filter, + int total); +bool is_i40e_supported(struct rte_eth_dev *dev); #define I40E_DEV_TO_PCI(eth_dev) \ RTE_DEV_TO_PCI((eth_dev)->device) diff --git a/drivers/net/i40e/rte_pmd_i40e.c b/drivers/net/i40e/rte_pmd_i40e.c new file mode 100644 index 0000000000..cee067bb8e --- /dev/null +++ b/drivers/net/i40e/rte_pmd_i40e.c @@ -0,0 +1,1707 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2017 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "base/i40e_prototype.h" +#include "i40e_ethdev.h" +#include "i40e_pf.h" +#include "rte_pmd_i40e.h" + +/* The max bandwidth of i40e is 40Gbps. */ +#define I40E_QOS_BW_MAX 40000 +/* The bandwidth should be the multiple of 50Mbps. */ +#define I40E_QOS_BW_GRANULARITY 50 +/* The min bandwidth weight is 1. */ +#define I40E_QOS_BW_WEIGHT_MIN 1 +/* The max bandwidth weight is 127. */ +#define I40E_QOS_BW_WEIGHT_MAX 127 + +int +rte_pmd_i40e_ping_vfs(uint8_t port, uint16_t vf) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + + if (vf >= pf->vf_num || !pf->vfs) { + PMD_DRV_LOG(ERR, "Invalid argument."); + return -EINVAL; + } + + i40e_notify_vf_link_status(dev, &pf->vfs[vf]); + + return 0; +} + +int +rte_pmd_i40e_set_vf_mac_anti_spoof(uint8_t port, uint16_t vf_id, uint8_t on) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_vsi *vsi; + struct i40e_hw *hw; + struct i40e_vsi_context ctxt; + int ret; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + + if (vf_id >= pf->vf_num || !pf->vfs) { + PMD_DRV_LOG(ERR, "Invalid argument."); + return -EINVAL; + } + + vsi = pf->vfs[vf_id].vsi; + if (!vsi) { + PMD_DRV_LOG(ERR, "Invalid VSI."); + return -EINVAL; + } + + /* Check if it has been already on or off */ + if (vsi->info.valid_sections & + rte_cpu_to_le_16(I40E_AQ_VSI_PROP_SECURITY_VALID)) { + if (on) { + if ((vsi->info.sec_flags & + I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK) == + I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK) + return 0; /* already on */ + } else { + if ((vsi->info.sec_flags & + I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK) == 0) + return 0; /* already off */ + } + } + + vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SECURITY_VALID); + if (on) + vsi->info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK; + else + vsi->info.sec_flags &= ~I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK; + + memset(&ctxt, 0, sizeof(ctxt)); + (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info)); + ctxt.seid = vsi->seid; + + hw = I40E_VSI_TO_HW(vsi); + ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); + if (ret != I40E_SUCCESS) { + ret = -ENOTSUP; + PMD_DRV_LOG(ERR, "Failed to update VSI params"); + } + + return ret; +} + +static int +i40e_add_rm_all_vlan_filter(struct i40e_vsi *vsi, uint8_t add) +{ + uint32_t j, k; + uint16_t vlan_id; + struct i40e_hw *hw = I40E_VSI_TO_HW(vsi); + struct i40e_aqc_add_remove_vlan_element_data vlan_data = {0}; + int ret; + + for (j = 0; j < I40E_VFTA_SIZE; j++) { + if (!vsi->vfta[j]) + continue; + + for (k = 0; k < I40E_UINT32_BIT_SIZE; k++) { + if (!(vsi->vfta[j] & (1 << k))) + continue; + + vlan_id = j * I40E_UINT32_BIT_SIZE + k; + if (!vlan_id) + continue; + + vlan_data.vlan_tag = rte_cpu_to_le_16(vlan_id); + if (add) + ret = i40e_aq_add_vlan(hw, vsi->seid, + &vlan_data, 1, NULL); + else + ret = i40e_aq_remove_vlan(hw, vsi->seid, + &vlan_data, 1, NULL); + if (ret != I40E_SUCCESS) { + PMD_DRV_LOG(ERR, + "Failed to add/rm vlan filter"); + return ret; + } + } + } + + return I40E_SUCCESS; +} + +int +rte_pmd_i40e_set_vf_vlan_anti_spoof(uint8_t port, uint16_t vf_id, uint8_t on) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_vsi *vsi; + struct i40e_hw *hw; + struct i40e_vsi_context ctxt; + int ret; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + + if (vf_id >= pf->vf_num || !pf->vfs) { + PMD_DRV_LOG(ERR, "Invalid argument."); + return -EINVAL; + } + + vsi = pf->vfs[vf_id].vsi; + if (!vsi) { + PMD_DRV_LOG(ERR, "Invalid VSI."); + return -EINVAL; + } + + /* Check if it has been already on or off */ + if (vsi->vlan_anti_spoof_on == on) + return 0; /* already on or off */ + + vsi->vlan_anti_spoof_on = on; + if (!vsi->vlan_filter_on) { + ret = i40e_add_rm_all_vlan_filter(vsi, on); + if (ret) { + PMD_DRV_LOG(ERR, "Failed to add/remove VLAN filters."); + return -ENOTSUP; + } + } + + vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SECURITY_VALID); + if (on) + vsi->info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK; + else + vsi->info.sec_flags &= ~I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK; + + memset(&ctxt, 0, sizeof(ctxt)); + (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info)); + ctxt.seid = vsi->seid; + + hw = I40E_VSI_TO_HW(vsi); + ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); + if (ret != I40E_SUCCESS) { + ret = -ENOTSUP; + PMD_DRV_LOG(ERR, "Failed to update VSI params"); + } + + return ret; +} + +static int +i40e_vsi_rm_mac_filter(struct i40e_vsi *vsi) +{ + struct i40e_mac_filter *f; + struct i40e_macvlan_filter *mv_f; + int i, vlan_num; + enum rte_mac_filter_type filter_type; + int ret = I40E_SUCCESS; + void *temp; + + /* remove all the MACs */ + TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) { + vlan_num = vsi->vlan_num; + filter_type = f->mac_info.filter_type; + if (filter_type == RTE_MACVLAN_PERFECT_MATCH || + filter_type == RTE_MACVLAN_HASH_MATCH) { + if (vlan_num == 0) { + PMD_DRV_LOG(ERR, "VLAN number shouldn't be 0"); + return I40E_ERR_PARAM; + } + } else if (filter_type == RTE_MAC_PERFECT_MATCH || + filter_type == RTE_MAC_HASH_MATCH) + vlan_num = 1; + + mv_f = rte_zmalloc("macvlan_data", vlan_num * sizeof(*mv_f), 0); + if (!mv_f) { + PMD_DRV_LOG(ERR, "failed to allocate memory"); + return I40E_ERR_NO_MEMORY; + } + + for (i = 0; i < vlan_num; i++) { + mv_f[i].filter_type = filter_type; + (void)rte_memcpy(&mv_f[i].macaddr, + &f->mac_info.mac_addr, + ETH_ADDR_LEN); + } + if (filter_type == RTE_MACVLAN_PERFECT_MATCH || + filter_type == RTE_MACVLAN_HASH_MATCH) { + ret = i40e_find_all_vlan_for_mac(vsi, mv_f, vlan_num, + &f->mac_info.mac_addr); + if (ret != I40E_SUCCESS) { + rte_free(mv_f); + return ret; + } + } + + ret = i40e_remove_macvlan_filters(vsi, mv_f, vlan_num); + if (ret != I40E_SUCCESS) { + rte_free(mv_f); + return ret; + } + + rte_free(mv_f); + ret = I40E_SUCCESS; + } + + return ret; +} + +static int +i40e_vsi_restore_mac_filter(struct i40e_vsi *vsi) +{ + struct i40e_mac_filter *f; + struct i40e_macvlan_filter *mv_f; + int i, vlan_num = 0; + int ret = I40E_SUCCESS; + void *temp; + + /* restore all the MACs */ + TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) { + if ((f->mac_info.filter_type == RTE_MACVLAN_PERFECT_MATCH) || + (f->mac_info.filter_type == RTE_MACVLAN_HASH_MATCH)) { + /** + * If vlan_num is 0, that's the first time to add mac, + * set mask for vlan_id 0. + */ + if (vsi->vlan_num == 0) { + i40e_set_vlan_filter(vsi, 0, 1); + vsi->vlan_num = 1; + } + vlan_num = vsi->vlan_num; + } else if ((f->mac_info.filter_type == RTE_MAC_PERFECT_MATCH) || + (f->mac_info.filter_type == RTE_MAC_HASH_MATCH)) + vlan_num = 1; + + mv_f = rte_zmalloc("macvlan_data", vlan_num * sizeof(*mv_f), 0); + if (!mv_f) { + PMD_DRV_LOG(ERR, "failed to allocate memory"); + return I40E_ERR_NO_MEMORY; + } + + for (i = 0; i < vlan_num; i++) { + mv_f[i].filter_type = f->mac_info.filter_type; + (void)rte_memcpy(&mv_f[i].macaddr, + &f->mac_info.mac_addr, + ETH_ADDR_LEN); + } + + if (f->mac_info.filter_type == RTE_MACVLAN_PERFECT_MATCH || + f->mac_info.filter_type == RTE_MACVLAN_HASH_MATCH) { + ret = i40e_find_all_vlan_for_mac(vsi, mv_f, vlan_num, + &f->mac_info.mac_addr); + if (ret != I40E_SUCCESS) { + rte_free(mv_f); + return ret; + } + } + + ret = i40e_add_macvlan_filters(vsi, mv_f, vlan_num); + if (ret != I40E_SUCCESS) { + rte_free(mv_f); + return ret; + } + + rte_free(mv_f); + ret = I40E_SUCCESS; + } + + return ret; +} + +static int +i40e_vsi_set_tx_loopback(struct i40e_vsi *vsi, uint8_t on) +{ + struct i40e_vsi_context ctxt; + struct i40e_hw *hw; + int ret; + + if (!vsi) + return -EINVAL; + + hw = I40E_VSI_TO_HW(vsi); + + /* Use the FW API if FW >= v5.0 */ + if (hw->aq.fw_maj_ver < 5) { + PMD_INIT_LOG(ERR, "FW < v5.0, cannot enable loopback"); + return -ENOTSUP; + } + + /* Check if it has been already on or off */ + if (vsi->info.valid_sections & + rte_cpu_to_le_16(I40E_AQ_VSI_PROP_SWITCH_VALID)) { + if (on) { + if ((vsi->info.switch_id & + I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB) == + I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB) + return 0; /* already on */ + } else { + if ((vsi->info.switch_id & + I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB) == 0) + return 0; /* already off */ + } + } + + /* remove all the MAC and VLAN first */ + ret = i40e_vsi_rm_mac_filter(vsi); + if (ret) { + PMD_INIT_LOG(ERR, "Failed to remove MAC filters."); + return ret; + } + if (vsi->vlan_anti_spoof_on || vsi->vlan_filter_on) { + ret = i40e_add_rm_all_vlan_filter(vsi, 0); + if (ret) { + PMD_INIT_LOG(ERR, "Failed to remove VLAN filters."); + return ret; + } + } + + vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID); + if (on) + vsi->info.switch_id |= I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB; + else + vsi->info.switch_id &= ~I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB; + + memset(&ctxt, 0, sizeof(ctxt)); + (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info)); + ctxt.seid = vsi->seid; + + ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); + if (ret != I40E_SUCCESS) { + PMD_DRV_LOG(ERR, "Failed to update VSI params"); + return ret; + } + + /* add all the MAC and VLAN back */ + ret = i40e_vsi_restore_mac_filter(vsi); + if (ret) + return ret; + if (vsi->vlan_anti_spoof_on || vsi->vlan_filter_on) { + ret = i40e_add_rm_all_vlan_filter(vsi, 1); + if (ret) + return ret; + } + + return ret; +} + +int +rte_pmd_i40e_set_tx_loopback(uint8_t port, uint8_t on) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_pf_vf *vf; + struct i40e_vsi *vsi; + uint16_t vf_id; + int ret; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + + /* setup PF TX loopback */ + vsi = pf->main_vsi; + ret = i40e_vsi_set_tx_loopback(vsi, on); + if (ret) + return -ENOTSUP; + + /* setup TX loopback for all the VFs */ + if (!pf->vfs) { + /* if no VF, do nothing. */ + return 0; + } + + for (vf_id = 0; vf_id < pf->vf_num; vf_id++) { + vf = &pf->vfs[vf_id]; + vsi = vf->vsi; + + ret = i40e_vsi_set_tx_loopback(vsi, on); + if (ret) + return -ENOTSUP; + } + + return ret; +} + +int +rte_pmd_i40e_set_vf_unicast_promisc(uint8_t port, uint16_t vf_id, uint8_t on) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_vsi *vsi; + struct i40e_hw *hw; + int ret; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + + if (vf_id >= pf->vf_num || !pf->vfs) { + PMD_DRV_LOG(ERR, "Invalid argument."); + return -EINVAL; + } + + vsi = pf->vfs[vf_id].vsi; + if (!vsi) { + PMD_DRV_LOG(ERR, "Invalid VSI."); + return -EINVAL; + } + + hw = I40E_VSI_TO_HW(vsi); + + ret = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid, + on, NULL, true); + if (ret != I40E_SUCCESS) { + ret = -ENOTSUP; + PMD_DRV_LOG(ERR, "Failed to set unicast promiscuous mode"); + } + + return ret; +} + +int +rte_pmd_i40e_set_vf_multicast_promisc(uint8_t port, uint16_t vf_id, uint8_t on) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_vsi *vsi; + struct i40e_hw *hw; + int ret; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + + if (vf_id >= pf->vf_num || !pf->vfs) { + PMD_DRV_LOG(ERR, "Invalid argument."); + return -EINVAL; + } + + vsi = pf->vfs[vf_id].vsi; + if (!vsi) { + PMD_DRV_LOG(ERR, "Invalid VSI."); + return -EINVAL; + } + + hw = I40E_VSI_TO_HW(vsi); + + ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid, + on, NULL); + if (ret != I40E_SUCCESS) { + ret = -ENOTSUP; + PMD_DRV_LOG(ERR, "Failed to set multicast promiscuous mode"); + } + + return ret; +} + +int +rte_pmd_i40e_set_vf_mac_addr(uint8_t port, uint16_t vf_id, + struct ether_addr *mac_addr) +{ + struct i40e_mac_filter *f; + struct rte_eth_dev *dev; + struct i40e_pf_vf *vf; + struct i40e_vsi *vsi; + struct i40e_pf *pf; + void *temp; + + if (i40e_validate_mac_addr((u8 *)mac_addr) != I40E_SUCCESS) + return -EINVAL; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + + if (vf_id >= pf->vf_num || !pf->vfs) + return -EINVAL; + + vf = &pf->vfs[vf_id]; + vsi = vf->vsi; + if (!vsi) { + PMD_DRV_LOG(ERR, "Invalid VSI."); + return -EINVAL; + } + + ether_addr_copy(mac_addr, &vf->mac_addr); + + /* Remove all existing mac */ + TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) + i40e_vsi_delete_mac(vsi, &f->mac_info.mac_addr); + + return 0; +} + +/* Set vlan strip on/off for specific VF from host */ +int +rte_pmd_i40e_set_vf_vlan_stripq(uint8_t port, uint16_t vf_id, uint8_t on) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_vsi *vsi; + int ret; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + + if (vf_id >= pf->vf_num || !pf->vfs) { + PMD_DRV_LOG(ERR, "Invalid argument."); + return -EINVAL; + } + + vsi = pf->vfs[vf_id].vsi; + + if (!vsi) + return -EINVAL; + + ret = i40e_vsi_config_vlan_stripping(vsi, !!on); + if (ret != I40E_SUCCESS) { + ret = -ENOTSUP; + PMD_DRV_LOG(ERR, "Failed to set VLAN stripping!"); + } + + return ret; +} + +int rte_pmd_i40e_set_vf_vlan_insert(uint8_t port, uint16_t vf_id, + uint16_t vlan_id) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_hw *hw; + struct i40e_vsi *vsi; + struct i40e_vsi_context ctxt; + int ret; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + if (vlan_id > ETHER_MAX_VLAN_ID) { + PMD_DRV_LOG(ERR, "Invalid VLAN ID."); + return -EINVAL; + } + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + hw = I40E_PF_TO_HW(pf); + + /** + * return -ENODEV if SRIOV not enabled, VF number not configured + * or no queue assigned. + */ + if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 || + pf->vf_nb_qps == 0) + return -ENODEV; + + if (vf_id >= pf->vf_num || !pf->vfs) { + PMD_DRV_LOG(ERR, "Invalid VF ID."); + return -EINVAL; + } + + vsi = pf->vfs[vf_id].vsi; + if (!vsi) { + PMD_DRV_LOG(ERR, "Invalid VSI."); + return -EINVAL; + } + + vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID); + vsi->info.pvid = vlan_id; + if (vlan_id > 0) + vsi->info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_INSERT_PVID; + else + vsi->info.port_vlan_flags &= ~I40E_AQ_VSI_PVLAN_INSERT_PVID; + + memset(&ctxt, 0, sizeof(ctxt)); + (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info)); + ctxt.seid = vsi->seid; + + hw = I40E_VSI_TO_HW(vsi); + ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); + if (ret != I40E_SUCCESS) { + ret = -ENOTSUP; + PMD_DRV_LOG(ERR, "Failed to update VSI params"); + } + + return ret; +} + +int rte_pmd_i40e_set_vf_broadcast(uint8_t port, uint16_t vf_id, + uint8_t on) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_vsi *vsi; + struct i40e_hw *hw; + struct i40e_mac_filter_info filter; + struct ether_addr broadcast = { + .addr_bytes = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} }; + int ret; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + if (on > 1) { + PMD_DRV_LOG(ERR, "on should be 0 or 1."); + return -EINVAL; + } + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + hw = I40E_PF_TO_HW(pf); + + if (vf_id >= pf->vf_num || !pf->vfs) { + PMD_DRV_LOG(ERR, "Invalid VF ID."); + return -EINVAL; + } + + /** + * return -ENODEV if SRIOV not enabled, VF number not configured + * or no queue assigned. + */ + if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 || + pf->vf_nb_qps == 0) { + PMD_DRV_LOG(ERR, "SRIOV is not enabled or no queue."); + return -ENODEV; + } + + vsi = pf->vfs[vf_id].vsi; + if (!vsi) { + PMD_DRV_LOG(ERR, "Invalid VSI."); + return -EINVAL; + } + + if (on) { + (void)rte_memcpy(&filter.mac_addr, &broadcast, ETHER_ADDR_LEN); + filter.filter_type = RTE_MACVLAN_PERFECT_MATCH; + ret = i40e_vsi_add_mac(vsi, &filter); + } else { + ret = i40e_vsi_delete_mac(vsi, &broadcast); + } + + if (ret != I40E_SUCCESS && ret != I40E_ERR_PARAM) { + ret = -ENOTSUP; + PMD_DRV_LOG(ERR, "Failed to set VSI broadcast"); + } else { + ret = 0; + } + + return ret; +} + +int rte_pmd_i40e_set_vf_vlan_tag(uint8_t port, uint16_t vf_id, uint8_t on) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_hw *hw; + struct i40e_vsi *vsi; + struct i40e_vsi_context ctxt; + int ret; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + if (on > 1) { + PMD_DRV_LOG(ERR, "on should be 0 or 1."); + return -EINVAL; + } + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + hw = I40E_PF_TO_HW(pf); + + /** + * return -ENODEV if SRIOV not enabled, VF number not configured + * or no queue assigned. + */ + if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 || + pf->vf_nb_qps == 0) { + PMD_DRV_LOG(ERR, "SRIOV is not enabled or no queue."); + return -ENODEV; + } + + if (vf_id >= pf->vf_num || !pf->vfs) { + PMD_DRV_LOG(ERR, "Invalid VF ID."); + return -EINVAL; + } + + vsi = pf->vfs[vf_id].vsi; + if (!vsi) { + PMD_DRV_LOG(ERR, "Invalid VSI."); + return -EINVAL; + } + + vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID); + if (on) { + vsi->info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_TAGGED; + vsi->info.port_vlan_flags &= ~I40E_AQ_VSI_PVLAN_MODE_UNTAGGED; + } else { + vsi->info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_UNTAGGED; + vsi->info.port_vlan_flags &= ~I40E_AQ_VSI_PVLAN_MODE_TAGGED; + } + + memset(&ctxt, 0, sizeof(ctxt)); + (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info)); + ctxt.seid = vsi->seid; + + hw = I40E_VSI_TO_HW(vsi); + ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); + if (ret != I40E_SUCCESS) { + ret = -ENOTSUP; + PMD_DRV_LOG(ERR, "Failed to update VSI params"); + } + + return ret; +} + +static int +i40e_vlan_filter_count(struct i40e_vsi *vsi) +{ + uint32_t j, k; + uint16_t vlan_id; + int count = 0; + + for (j = 0; j < I40E_VFTA_SIZE; j++) { + if (!vsi->vfta[j]) + continue; + + for (k = 0; k < I40E_UINT32_BIT_SIZE; k++) { + if (!(vsi->vfta[j] & (1 << k))) + continue; + + vlan_id = j * I40E_UINT32_BIT_SIZE + k; + if (!vlan_id) + continue; + + count++; + } + } + + return count; +} + +int rte_pmd_i40e_set_vf_vlan_filter(uint8_t port, uint16_t vlan_id, + uint64_t vf_mask, uint8_t on) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_hw *hw; + struct i40e_vsi *vsi; + uint16_t vf_idx; + int ret = I40E_SUCCESS; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + if (vlan_id > ETHER_MAX_VLAN_ID || !vlan_id) { + PMD_DRV_LOG(ERR, "Invalid VLAN ID."); + return -EINVAL; + } + + if (vf_mask == 0) { + PMD_DRV_LOG(ERR, "No VF."); + return -EINVAL; + } + + if (on > 1) { + PMD_DRV_LOG(ERR, "on is should be 0 or 1."); + return -EINVAL; + } + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + hw = I40E_PF_TO_HW(pf); + + /** + * return -ENODEV if SRIOV not enabled, VF number not configured + * or no queue assigned. + */ + if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 || + pf->vf_nb_qps == 0) { + PMD_DRV_LOG(ERR, "SRIOV is not enabled or no queue."); + return -ENODEV; + } + + for (vf_idx = 0; vf_idx < pf->vf_num && ret == I40E_SUCCESS; vf_idx++) { + if (vf_mask & ((uint64_t)(1ULL << vf_idx))) { + vsi = pf->vfs[vf_idx].vsi; + if (on) { + if (!vsi->vlan_filter_on) { + vsi->vlan_filter_on = true; + i40e_aq_set_vsi_vlan_promisc(hw, + vsi->seid, + false, + NULL); + if (!vsi->vlan_anti_spoof_on) + i40e_add_rm_all_vlan_filter( + vsi, true); + } + ret = i40e_vsi_add_vlan(vsi, vlan_id); + } else { + ret = i40e_vsi_delete_vlan(vsi, vlan_id); + + if (!i40e_vlan_filter_count(vsi)) { + vsi->vlan_filter_on = false; + i40e_aq_set_vsi_vlan_promisc(hw, + vsi->seid, + true, + NULL); + } + } + } + } + + if (ret != I40E_SUCCESS) { + ret = -ENOTSUP; + PMD_DRV_LOG(ERR, "Failed to set VF VLAN filter, on = %d", on); + } + + return ret; +} + +int +rte_pmd_i40e_get_vf_stats(uint8_t port, + uint16_t vf_id, + struct rte_eth_stats *stats) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_vsi *vsi; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + + if (vf_id >= pf->vf_num || !pf->vfs) { + PMD_DRV_LOG(ERR, "Invalid VF ID."); + return -EINVAL; + } + + vsi = pf->vfs[vf_id].vsi; + if (!vsi) { + PMD_DRV_LOG(ERR, "Invalid VSI."); + return -EINVAL; + } + + i40e_update_vsi_stats(vsi); + + stats->ipackets = vsi->eth_stats.rx_unicast + + vsi->eth_stats.rx_multicast + + vsi->eth_stats.rx_broadcast; + stats->opackets = vsi->eth_stats.tx_unicast + + vsi->eth_stats.tx_multicast + + vsi->eth_stats.tx_broadcast; + stats->ibytes = vsi->eth_stats.rx_bytes; + stats->obytes = vsi->eth_stats.tx_bytes; + stats->ierrors = vsi->eth_stats.rx_discards; + stats->oerrors = vsi->eth_stats.tx_errors + vsi->eth_stats.tx_discards; + + return 0; +} + +int +rte_pmd_i40e_reset_vf_stats(uint8_t port, + uint16_t vf_id) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_vsi *vsi; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + + if (vf_id >= pf->vf_num || !pf->vfs) { + PMD_DRV_LOG(ERR, "Invalid VF ID."); + return -EINVAL; + } + + vsi = pf->vfs[vf_id].vsi; + if (!vsi) { + PMD_DRV_LOG(ERR, "Invalid VSI."); + return -EINVAL; + } + + vsi->offset_loaded = false; + i40e_update_vsi_stats(vsi); + + return 0; +} + +int +rte_pmd_i40e_set_vf_max_bw(uint8_t port, uint16_t vf_id, uint32_t bw) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_vsi *vsi; + struct i40e_hw *hw; + int ret = 0; + int i; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + + if (vf_id >= pf->vf_num || !pf->vfs) { + PMD_DRV_LOG(ERR, "Invalid VF ID."); + return -EINVAL; + } + + vsi = pf->vfs[vf_id].vsi; + if (!vsi) { + PMD_DRV_LOG(ERR, "Invalid VSI."); + return -EINVAL; + } + + if (bw > I40E_QOS_BW_MAX) { + PMD_DRV_LOG(ERR, "Bandwidth should not be larger than %dMbps.", + I40E_QOS_BW_MAX); + return -EINVAL; + } + + if (bw % I40E_QOS_BW_GRANULARITY) { + PMD_DRV_LOG(ERR, "Bandwidth should be the multiple of %dMbps.", + I40E_QOS_BW_GRANULARITY); + return -EINVAL; + } + + bw /= I40E_QOS_BW_GRANULARITY; + + hw = I40E_VSI_TO_HW(vsi); + + /* No change. */ + if (bw == vsi->bw_info.bw_limit) { + PMD_DRV_LOG(INFO, + "No change for VF max bandwidth. Nothing to do."); + return 0; + } + + /** + * VF bandwidth limitation and TC bandwidth limitation cannot be + * enabled in parallel, quit if TC bandwidth limitation is enabled. + * + * If bw is 0, means disable bandwidth limitation. Then no need to + * check TC bandwidth limitation. + */ + if (bw) { + for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { + if ((vsi->enabled_tc & BIT_ULL(i)) && + vsi->bw_info.bw_ets_credits[i]) + break; + } + if (i != I40E_MAX_TRAFFIC_CLASS) { + PMD_DRV_LOG(ERR, + "TC max bandwidth has been set on this VF," + " please disable it first."); + return -EINVAL; + } + } + + ret = i40e_aq_config_vsi_bw_limit(hw, vsi->seid, (uint16_t)bw, 0, NULL); + if (ret) { + PMD_DRV_LOG(ERR, + "Failed to set VF %d bandwidth, err(%d).", + vf_id, ret); + return -EINVAL; + } + + /* Store the configuration. */ + vsi->bw_info.bw_limit = (uint16_t)bw; + vsi->bw_info.bw_max = 0; + + return 0; +} + +int +rte_pmd_i40e_set_vf_tc_bw_alloc(uint8_t port, uint16_t vf_id, + uint8_t tc_num, uint8_t *bw_weight) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_vsi *vsi; + struct i40e_hw *hw; + struct i40e_aqc_configure_vsi_tc_bw_data tc_bw; + int ret = 0; + int i, j; + uint16_t sum; + bool b_change = false; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + + if (vf_id >= pf->vf_num || !pf->vfs) { + PMD_DRV_LOG(ERR, "Invalid VF ID."); + return -EINVAL; + } + + vsi = pf->vfs[vf_id].vsi; + if (!vsi) { + PMD_DRV_LOG(ERR, "Invalid VSI."); + return -EINVAL; + } + + if (tc_num > I40E_MAX_TRAFFIC_CLASS) { + PMD_DRV_LOG(ERR, "TCs should be no more than %d.", + I40E_MAX_TRAFFIC_CLASS); + return -EINVAL; + } + + sum = 0; + for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { + if (vsi->enabled_tc & BIT_ULL(i)) + sum++; + } + if (sum != tc_num) { + PMD_DRV_LOG(ERR, + "Weight should be set for all %d enabled TCs.", + sum); + return -EINVAL; + } + + sum = 0; + for (i = 0; i < tc_num; i++) { + if (!bw_weight[i]) { + PMD_DRV_LOG(ERR, + "The weight should be 1 at least."); + return -EINVAL; + } + sum += bw_weight[i]; + } + if (sum != 100) { + PMD_DRV_LOG(ERR, + "The summary of the TC weight should be 100."); + return -EINVAL; + } + + /** + * Create the configuration for all the TCs. + */ + memset(&tc_bw, 0, sizeof(tc_bw)); + tc_bw.tc_valid_bits = vsi->enabled_tc; + j = 0; + for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { + if (vsi->enabled_tc & BIT_ULL(i)) { + if (bw_weight[j] != + vsi->bw_info.bw_ets_share_credits[i]) + b_change = true; + + tc_bw.tc_bw_credits[i] = bw_weight[j]; + j++; + } + } + + /* No change. */ + if (!b_change) { + PMD_DRV_LOG(INFO, + "No change for TC allocated bandwidth." + " Nothing to do."); + return 0; + } + + hw = I40E_VSI_TO_HW(vsi); + + ret = i40e_aq_config_vsi_tc_bw(hw, vsi->seid, &tc_bw, NULL); + if (ret) { + PMD_DRV_LOG(ERR, + "Failed to set VF %d TC bandwidth weight, err(%d).", + vf_id, ret); + return -EINVAL; + } + + /* Store the configuration. */ + j = 0; + for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { + if (vsi->enabled_tc & BIT_ULL(i)) { + vsi->bw_info.bw_ets_share_credits[i] = bw_weight[j]; + j++; + } + } + + return 0; +} + +int +rte_pmd_i40e_set_vf_tc_max_bw(uint8_t port, uint16_t vf_id, + uint8_t tc_no, uint32_t bw) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_vsi *vsi; + struct i40e_hw *hw; + struct i40e_aqc_configure_vsi_ets_sla_bw_data tc_bw; + int ret = 0; + int i; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + + if (vf_id >= pf->vf_num || !pf->vfs) { + PMD_DRV_LOG(ERR, "Invalid VF ID."); + return -EINVAL; + } + + vsi = pf->vfs[vf_id].vsi; + if (!vsi) { + PMD_DRV_LOG(ERR, "Invalid VSI."); + return -EINVAL; + } + + if (bw > I40E_QOS_BW_MAX) { + PMD_DRV_LOG(ERR, "Bandwidth should not be larger than %dMbps.", + I40E_QOS_BW_MAX); + return -EINVAL; + } + + if (bw % I40E_QOS_BW_GRANULARITY) { + PMD_DRV_LOG(ERR, "Bandwidth should be the multiple of %dMbps.", + I40E_QOS_BW_GRANULARITY); + return -EINVAL; + } + + bw /= I40E_QOS_BW_GRANULARITY; + + if (tc_no >= I40E_MAX_TRAFFIC_CLASS) { + PMD_DRV_LOG(ERR, "TC No. should be less than %d.", + I40E_MAX_TRAFFIC_CLASS); + return -EINVAL; + } + + hw = I40E_VSI_TO_HW(vsi); + + if (!(vsi->enabled_tc & BIT_ULL(tc_no))) { + PMD_DRV_LOG(ERR, "VF %d TC %d isn't enabled.", + vf_id, tc_no); + return -EINVAL; + } + + /* No change. */ + if (bw == vsi->bw_info.bw_ets_credits[tc_no]) { + PMD_DRV_LOG(INFO, + "No change for TC max bandwidth. Nothing to do."); + return 0; + } + + /** + * VF bandwidth limitation and TC bandwidth limitation cannot be + * enabled in parallel, disable VF bandwidth limitation if it's + * enabled. + * If bw is 0, means disable bandwidth limitation. Then no need to + * care about VF bandwidth limitation configuration. + */ + if (bw && vsi->bw_info.bw_limit) { + ret = i40e_aq_config_vsi_bw_limit(hw, vsi->seid, 0, 0, NULL); + if (ret) { + PMD_DRV_LOG(ERR, + "Failed to disable VF(%d)" + " bandwidth limitation, err(%d).", + vf_id, ret); + return -EINVAL; + } + + PMD_DRV_LOG(INFO, + "VF max bandwidth is disabled according" + " to TC max bandwidth setting."); + } + + /** + * Get all the TCs' info to create a whole picture. + * Because the incremental change isn't permitted. + */ + memset(&tc_bw, 0, sizeof(tc_bw)); + tc_bw.tc_valid_bits = vsi->enabled_tc; + for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { + if (vsi->enabled_tc & BIT_ULL(i)) { + tc_bw.tc_bw_credits[i] = + rte_cpu_to_le_16( + vsi->bw_info.bw_ets_credits[i]); + } + } + tc_bw.tc_bw_credits[tc_no] = rte_cpu_to_le_16((uint16_t)bw); + + ret = i40e_aq_config_vsi_ets_sla_bw_limit(hw, vsi->seid, &tc_bw, NULL); + if (ret) { + PMD_DRV_LOG(ERR, + "Failed to set VF %d TC %d max bandwidth, err(%d).", + vf_id, tc_no, ret); + return -EINVAL; + } + + /* Store the configuration. */ + vsi->bw_info.bw_ets_credits[tc_no] = (uint16_t)bw; + + return 0; +} + +int +rte_pmd_i40e_set_tc_strict_prio(uint8_t port, uint8_t tc_map) +{ + struct rte_eth_dev *dev; + struct i40e_pf *pf; + struct i40e_vsi *vsi; + struct i40e_veb *veb; + struct i40e_hw *hw; + struct i40e_aqc_configure_switching_comp_ets_data ets_data; + int i; + int ret; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + + vsi = pf->main_vsi; + if (!vsi) { + PMD_DRV_LOG(ERR, "Invalid VSI."); + return -EINVAL; + } + + veb = vsi->veb; + if (!veb) { + PMD_DRV_LOG(ERR, "Invalid VEB."); + return -EINVAL; + } + + if ((tc_map & veb->enabled_tc) != tc_map) { + PMD_DRV_LOG(ERR, + "TC bitmap isn't the subset of enabled TCs 0x%x.", + veb->enabled_tc); + return -EINVAL; + } + + if (tc_map == veb->strict_prio_tc) { + PMD_DRV_LOG(INFO, "No change for TC bitmap. Nothing to do."); + return 0; + } + + hw = I40E_VSI_TO_HW(vsi); + + /* Disable DCBx if it's the first time to set strict priority. */ + if (!veb->strict_prio_tc) { + ret = i40e_aq_stop_lldp(hw, true, NULL); + if (ret) + PMD_DRV_LOG(INFO, + "Failed to disable DCBx as it's already" + " disabled."); + else + PMD_DRV_LOG(INFO, + "DCBx is disabled according to strict" + " priority setting."); + } + + memset(&ets_data, 0, sizeof(ets_data)); + ets_data.tc_valid_bits = veb->enabled_tc; + ets_data.seepage = I40E_AQ_ETS_SEEPAGE_EN_MASK; + ets_data.tc_strict_priority_flags = tc_map; + /* Get all TCs' bandwidth. */ + for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { + if (veb->enabled_tc & BIT_ULL(i)) { + /* For rubust, if bandwidth is 0, use 1 instead. */ + if (veb->bw_info.bw_ets_share_credits[i]) + ets_data.tc_bw_share_credits[i] = + veb->bw_info.bw_ets_share_credits[i]; + else + ets_data.tc_bw_share_credits[i] = + I40E_QOS_BW_WEIGHT_MIN; + } + } + + if (!veb->strict_prio_tc) + ret = i40e_aq_config_switch_comp_ets( + hw, veb->uplink_seid, + &ets_data, i40e_aqc_opc_enable_switching_comp_ets, + NULL); + else if (tc_map) + ret = i40e_aq_config_switch_comp_ets( + hw, veb->uplink_seid, + &ets_data, i40e_aqc_opc_modify_switching_comp_ets, + NULL); + else + ret = i40e_aq_config_switch_comp_ets( + hw, veb->uplink_seid, + &ets_data, i40e_aqc_opc_disable_switching_comp_ets, + NULL); + + if (ret) { + PMD_DRV_LOG(ERR, + "Failed to set TCs' strict priority mode." + " err (%d)", ret); + return -EINVAL; + } + + veb->strict_prio_tc = tc_map; + + /* Enable DCBx again, if all the TCs' strict priority disabled. */ + if (!tc_map) { + ret = i40e_aq_start_lldp(hw, NULL); + if (ret) { + PMD_DRV_LOG(ERR, + "Failed to enable DCBx, err(%d).", ret); + return -EINVAL; + } + + PMD_DRV_LOG(INFO, + "DCBx is enabled again according to strict" + " priority setting."); + } + + return ret; +} + +#define I40E_PROFILE_INFO_SIZE 48 +#define I40E_MAX_PROFILE_NUM 16 + +static void +i40e_generate_profile_info_sec(char *name, struct i40e_ddp_version *version, + uint32_t track_id, uint8_t *profile_info_sec, + bool add) +{ + struct i40e_profile_section_header *sec = NULL; + struct i40e_profile_info *pinfo; + + sec = (struct i40e_profile_section_header *)profile_info_sec; + sec->tbl_size = 1; + sec->data_end = sizeof(struct i40e_profile_section_header) + + sizeof(struct i40e_profile_info); + sec->section.type = SECTION_TYPE_INFO; + sec->section.offset = sizeof(struct i40e_profile_section_header); + sec->section.size = sizeof(struct i40e_profile_info); + pinfo = (struct i40e_profile_info *)(profile_info_sec + + sec->section.offset); + pinfo->track_id = track_id; + memcpy(pinfo->name, name, I40E_DDP_NAME_SIZE); + memcpy(&pinfo->version, version, sizeof(struct i40e_ddp_version)); + if (add) + pinfo->op = I40E_DDP_ADD_TRACKID; + else + pinfo->op = I40E_DDP_REMOVE_TRACKID; +} + +static enum i40e_status_code +i40e_add_rm_profile_info(struct i40e_hw *hw, uint8_t *profile_info_sec) +{ + enum i40e_status_code status = I40E_SUCCESS; + struct i40e_profile_section_header *sec; + uint32_t track_id; + uint32_t offset = 0; + uint32_t info = 0; + + sec = (struct i40e_profile_section_header *)profile_info_sec; + track_id = ((struct i40e_profile_info *)(profile_info_sec + + sec->section.offset))->track_id; + + status = i40e_aq_write_ddp(hw, (void *)sec, sec->data_end, + track_id, &offset, &info, NULL); + if (status) + PMD_DRV_LOG(ERR, "Failed to add/remove profile info: " + "offset %d, info %d", + offset, info); + + return status; +} + +#define I40E_PROFILE_INFO_SIZE 48 +#define I40E_MAX_PROFILE_NUM 16 + +/* Check if the profile info exists */ +static int +i40e_check_profile_info(uint8_t port, uint8_t *profile_info_sec) +{ + struct rte_eth_dev *dev = &rte_eth_devices[port]; + struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint8_t *buff; + struct rte_pmd_i40e_profile_list *p_list; + struct rte_pmd_i40e_profile_info *pinfo, *p; + uint32_t i; + int ret; + + buff = rte_zmalloc("pinfo_list", + (I40E_PROFILE_INFO_SIZE * I40E_MAX_PROFILE_NUM + 4), + 0); + if (!buff) { + PMD_DRV_LOG(ERR, "failed to allocate memory"); + return -1; + } + + ret = i40e_aq_get_ddp_list( + hw, (void *)buff, + (I40E_PROFILE_INFO_SIZE * I40E_MAX_PROFILE_NUM + 4), + 0, NULL); + if (ret) { + PMD_DRV_LOG(ERR, "Failed to get profile info list."); + rte_free(buff); + return -1; + } + p_list = (struct rte_pmd_i40e_profile_list *)buff; + pinfo = (struct rte_pmd_i40e_profile_info *)(profile_info_sec + + sizeof(struct i40e_profile_section_header)); + for (i = 0; i < p_list->p_count; i++) { + p = &p_list->p_info[i]; + if ((pinfo->track_id == p->track_id) && + !memcmp(&pinfo->version, &p->version, + sizeof(struct i40e_ddp_version)) && + !memcmp(&pinfo->name, &p->name, + I40E_DDP_NAME_SIZE)) { + PMD_DRV_LOG(INFO, "Profile exists."); + rte_free(buff); + return 1; + } + } + + rte_free(buff); + return 0; +} + +int +rte_pmd_i40e_process_ddp_package(uint8_t port, uint8_t *buff, + uint32_t size, + enum rte_pmd_i40e_package_op op) +{ + struct rte_eth_dev *dev; + struct i40e_hw *hw; + struct i40e_package_header *pkg_hdr; + struct i40e_generic_seg_header *profile_seg_hdr; + struct i40e_generic_seg_header *metadata_seg_hdr; + uint32_t track_id; + uint8_t *profile_info_sec; + int is_exist; + enum i40e_status_code status = I40E_SUCCESS; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + if (size < (sizeof(struct i40e_package_header) + + sizeof(struct i40e_metadata_segment) + + sizeof(uint32_t) * 2)) { + PMD_DRV_LOG(ERR, "Buff is invalid."); + return -EINVAL; + } + + pkg_hdr = (struct i40e_package_header *)buff; + + if (!pkg_hdr) { + PMD_DRV_LOG(ERR, "Failed to fill the package structure"); + return -EINVAL; + } + + if (pkg_hdr->segment_count < 2) { + PMD_DRV_LOG(ERR, "Segment_count should be 2 at least."); + return -EINVAL; + } + + /* Find metadata segment */ + metadata_seg_hdr = i40e_find_segment_in_package(SEGMENT_TYPE_METADATA, + pkg_hdr); + if (!metadata_seg_hdr) { + PMD_DRV_LOG(ERR, "Failed to find metadata segment header"); + return -EINVAL; + } + track_id = ((struct i40e_metadata_segment *)metadata_seg_hdr)->track_id; + + /* Find profile segment */ + profile_seg_hdr = i40e_find_segment_in_package(SEGMENT_TYPE_I40E, + pkg_hdr); + if (!profile_seg_hdr) { + PMD_DRV_LOG(ERR, "Failed to find profile segment header"); + return -EINVAL; + } + + profile_info_sec = rte_zmalloc( + "i40e_profile_info", + sizeof(struct i40e_profile_section_header) + + sizeof(struct i40e_profile_info), + 0); + if (!profile_info_sec) { + PMD_DRV_LOG(ERR, "Failed to allocate memory"); + return -EINVAL; + } + + if (op == RTE_PMD_I40E_PKG_OP_WR_ADD) { + /* Check if the profile exists */ + i40e_generate_profile_info_sec( + ((struct i40e_profile_segment *)profile_seg_hdr)->name, + &((struct i40e_profile_segment *)profile_seg_hdr)->version, + track_id, profile_info_sec, 1); + is_exist = i40e_check_profile_info(port, profile_info_sec); + if (is_exist > 0) { + PMD_DRV_LOG(ERR, "Profile already exists."); + rte_free(profile_info_sec); + return 1; + } else if (is_exist < 0) { + PMD_DRV_LOG(ERR, "Failed to check profile."); + rte_free(profile_info_sec); + return -EINVAL; + } + + /* Write profile to HW */ + status = i40e_write_profile( + hw, + (struct i40e_profile_segment *)profile_seg_hdr, + track_id); + if (status) { + PMD_DRV_LOG(ERR, "Failed to write profile."); + rte_free(profile_info_sec); + return status; + } + + /* Add profile info to info list */ + status = i40e_add_rm_profile_info(hw, profile_info_sec); + if (status) + PMD_DRV_LOG(ERR, "Failed to add profile info."); + } else { + PMD_DRV_LOG(ERR, "Operation not supported."); + } + + rte_free(profile_info_sec); + return status; +} + +int +rte_pmd_i40e_get_ddp_list(uint8_t port, uint8_t *buff, uint32_t size) +{ + struct rte_eth_dev *dev; + struct i40e_hw *hw; + enum i40e_status_code status = I40E_SUCCESS; + + RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV); + + dev = &rte_eth_devices[port]; + + if (!is_i40e_supported(dev)) + return -ENOTSUP; + + if (size < (I40E_PROFILE_INFO_SIZE * I40E_MAX_PROFILE_NUM + 4)) + return -EINVAL; + + hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + status = i40e_aq_get_ddp_list(hw, (void *)buff, + size, 0, NULL); + + return status; +}