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)),)
#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"
/* 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);
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,
rte_intr_enable(dev->intr_handle);
}
-static int
+int
i40e_add_macvlan_filters(struct i40e_vsi *vsi,
struct i40e_macvlan_filter *filter,
int total)
return ret;
}
-static int
+int
i40e_remove_macvlan_filters(struct i40e_vsi *vsi,
struct i40e_macvlan_filter *filter,
int total)
vsi->vfta[vid_idx] &= ~vid_bit;
}
-static void
+void
i40e_set_vlan_filter(struct i40e_vsi *vsi,
uint16_t vlan_id, bool on)
{
* 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)
return true;
}
-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_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)
+bool
+is_i40e_supported(struct rte_eth_dev *dev)
{
- 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
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)
--- /dev/null
+/*-
+ * 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 <rte_malloc.h>
+#include <rte_tailq.h>
+
+#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;
+}