numam-dpdk/drivers/net/i40e/rte_pmd_i40e.c
Beilei Xing a075ce2b3e net/i40e: remove summarized global register change info
The summarized global register change info will be logged
no matter if there's real global register change. Since
only real changes are logged now, there's no need to
summarize global register change info, otherwise will
cause misunderstanding.

Signed-off-by: Beilei Xing <beilei.xing@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
2018-07-03 01:35:58 +02:00

3192 lines
78 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2010-2017 Intel Corporation
*/
#include <rte_malloc.h>
#include <rte_tailq.h>
#include "base/i40e_prototype.h"
#include "base/i40e_dcb.h"
#include "i40e_ethdev.h"
#include "i40e_pf.h"
#include "i40e_rxtx.h"
#include "rte_pmd_i40e.h"
int
rte_pmd_i40e_ping_vfs(uint16_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(uint16_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));
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(uint16_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));
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;
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;
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));
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(uint16_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(uint16_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(uint16_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(uint16_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)
if (i40e_vsi_delete_mac(vsi, &f->mac_info.mac_addr)
!= I40E_SUCCESS)
PMD_DRV_LOG(WARNING, "Delete MAC failed");
return 0;
}
static const struct ether_addr null_mac_addr;
int
rte_pmd_i40e_remove_vf_mac_addr(uint16_t port, uint16_t vf_id,
struct ether_addr *mac_addr)
{
struct rte_eth_dev *dev;
struct i40e_pf_vf *vf;
struct i40e_vsi *vsi;
struct i40e_pf *pf;
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;
}
if (is_same_ether_addr(mac_addr, &vf->mac_addr))
/* Reset the mac with NULL address */
ether_addr_copy(&null_mac_addr, &vf->mac_addr);
/* Remove the mac */
i40e_vsi_delete_mac(vsi, mac_addr);
return 0;
}
/* Set vlan strip on/off for specific VF from host */
int
rte_pmd_i40e_set_vf_vlan_stripq(uint16_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(uint16_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));
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(uint16_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) {
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(uint16_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));
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(uint16_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(uint16_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(uint16_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(uint16_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(uint16_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(uint16_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(uint16_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 sizeof(struct rte_pmd_i40e_profile_info)
#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;
}
/* Check if the profile info exists */
static int
i40e_check_profile_info(uint16_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;
static const uint32_t group_mask = 0x00ff0000;
pinfo = (struct rte_pmd_i40e_profile_info *)(profile_info_sec +
sizeof(struct i40e_profile_section_header));
if (pinfo->track_id == 0) {
PMD_DRV_LOG(INFO, "Read-only profile.");
return 0;
}
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;
for (i = 0; i < p_list->p_count; i++) {
p = &p_list->p_info[i];
if (pinfo->track_id == p->track_id) {
PMD_DRV_LOG(INFO, "Profile exists.");
rte_free(buff);
return 1;
}
}
/* profile with group id 0xff is compatible with any other profile */
if ((pinfo->track_id & group_mask) == group_mask) {
rte_free(buff);
return 0;
}
for (i = 0; i < p_list->p_count; i++) {
p = &p_list->p_info[i];
if ((p->track_id & group_mask) == 0) {
PMD_DRV_LOG(INFO, "Profile of the group 0 exists.");
rte_free(buff);
return 2;
}
}
for (i = 0; i < p_list->p_count; i++) {
p = &p_list->p_info[i];
if ((p->track_id & group_mask) == group_mask)
continue;
if ((pinfo->track_id & group_mask) !=
(p->track_id & group_mask)) {
PMD_DRV_LOG(INFO, "Profile of different group exists.");
rte_free(buff);
return 3;
}
}
rte_free(buff);
return 0;
}
int
rte_pmd_i40e_process_ddp_package(uint16_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;
static const uint32_t type_mask = 0xff000000;
if (op != RTE_PMD_I40E_PKG_OP_WR_ADD &&
op != RTE_PMD_I40E_PKG_OP_WR_ONLY &&
op != RTE_PMD_I40E_PKG_OP_WR_DEL) {
PMD_DRV_LOG(ERR, "Operation not supported.");
return -ENOTSUP;
}
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;
if (track_id == I40E_DDP_TRACKID_INVALID) {
PMD_DRV_LOG(ERR, "Invalid track_id");
return -EINVAL;
}
/* force read-only track_id for type 0 */
if ((track_id & type_mask) == 0)
track_id = 0;
/* 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;
}
/* Check if the profile already loaded */
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,
op == RTE_PMD_I40E_PKG_OP_WR_ADD);
is_exist = i40e_check_profile_info(port, profile_info_sec);
if (is_exist < 0) {
PMD_DRV_LOG(ERR, "Failed to check profile.");
rte_free(profile_info_sec);
return -EINVAL;
}
if (op == RTE_PMD_I40E_PKG_OP_WR_ADD) {
if (is_exist) {
if (is_exist == 1)
PMD_DRV_LOG(ERR, "Profile already exists.");
else if (is_exist == 2)
PMD_DRV_LOG(ERR, "Profile of group 0 already exists.");
else if (is_exist == 3)
PMD_DRV_LOG(ERR, "Profile of different group already exists");
rte_free(profile_info_sec);
return -EEXIST;
}
} else if (op == RTE_PMD_I40E_PKG_OP_WR_DEL) {
if (is_exist != 1) {
PMD_DRV_LOG(ERR, "Profile does not exist.");
rte_free(profile_info_sec);
return -EACCES;
}
}
if (op == RTE_PMD_I40E_PKG_OP_WR_DEL) {
status = i40e_rollback_profile(
hw,
(struct i40e_profile_segment *)profile_seg_hdr,
track_id);
if (status) {
PMD_DRV_LOG(ERR, "Failed to write profile for delete.");
rte_free(profile_info_sec);
return status;
}
} else {
status = i40e_write_profile(
hw,
(struct i40e_profile_segment *)profile_seg_hdr,
track_id);
if (status) {
if (op == RTE_PMD_I40E_PKG_OP_WR_ADD)
PMD_DRV_LOG(ERR, "Failed to write profile for add.");
else
PMD_DRV_LOG(ERR, "Failed to write profile.");
rte_free(profile_info_sec);
return status;
}
}
if (track_id && (op != RTE_PMD_I40E_PKG_OP_WR_ONLY)) {
/* Modify loaded profiles info list */
status = i40e_add_rm_profile_info(hw, profile_info_sec);
if (status) {
if (op == RTE_PMD_I40E_PKG_OP_WR_ADD)
PMD_DRV_LOG(ERR, "Failed to add profile to info list.");
else
PMD_DRV_LOG(ERR, "Failed to delete profile from info list.");
}
}
if (op == RTE_PMD_I40E_PKG_OP_WR_ADD ||
op == RTE_PMD_I40E_PKG_OP_WR_DEL)
i40e_update_customized_info(dev, buff, size, op);
rte_free(profile_info_sec);
return status;
}
/* Get number of tvl records in the section */
static unsigned int
i40e_get_tlv_section_size(struct i40e_profile_section_header *sec)
{
unsigned int i, nb_rec, nb_tlv = 0;
struct i40e_profile_tlv_section_record *tlv;
if (!sec)
return nb_tlv;
/* get number of records in the section */
nb_rec = sec->section.size /
sizeof(struct i40e_profile_tlv_section_record);
for (i = 0; i < nb_rec; ) {
tlv = (struct i40e_profile_tlv_section_record *)&sec[1 + i];
i += tlv->len;
nb_tlv++;
}
return nb_tlv;
}
int rte_pmd_i40e_get_ddp_info(uint8_t *pkg_buff, uint32_t pkg_size,
uint8_t *info_buff, uint32_t info_size,
enum rte_pmd_i40e_package_info type)
{
uint32_t ret_size;
struct i40e_package_header *pkg_hdr;
struct i40e_generic_seg_header *i40e_seg_hdr;
struct i40e_generic_seg_header *note_seg_hdr;
struct i40e_generic_seg_header *metadata_seg_hdr;
if (!info_buff) {
PMD_DRV_LOG(ERR, "Output info buff is invalid.");
return -EINVAL;
}
if (!pkg_buff || pkg_size < (sizeof(struct i40e_package_header) +
sizeof(struct i40e_metadata_segment) +
sizeof(uint32_t) * 2)) {
PMD_DRV_LOG(ERR, "Package buff is invalid.");
return -EINVAL;
}
pkg_hdr = (struct i40e_package_header *)pkg_buff;
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);
/* Find global notes segment */
note_seg_hdr = i40e_find_segment_in_package(SEGMENT_TYPE_NOTES,
pkg_hdr);
/* Find i40e profile segment */
i40e_seg_hdr = i40e_find_segment_in_package(SEGMENT_TYPE_I40E, pkg_hdr);
/* get global header info */
if (type == RTE_PMD_I40E_PKG_INFO_GLOBAL_HEADER) {
struct rte_pmd_i40e_profile_info *info =
(struct rte_pmd_i40e_profile_info *)info_buff;
if (info_size < sizeof(struct rte_pmd_i40e_profile_info)) {
PMD_DRV_LOG(ERR, "Output info buff size is invalid.");
return -EINVAL;
}
if (!metadata_seg_hdr) {
PMD_DRV_LOG(ERR, "Failed to find metadata segment header");
return -EINVAL;
}
memset(info, 0, sizeof(struct rte_pmd_i40e_profile_info));
info->owner = RTE_PMD_I40E_DDP_OWNER_UNKNOWN;
info->track_id =
((struct i40e_metadata_segment *)metadata_seg_hdr)->track_id;
memcpy(info->name,
((struct i40e_metadata_segment *)metadata_seg_hdr)->name,
I40E_DDP_NAME_SIZE);
memcpy(&info->version,
&((struct i40e_metadata_segment *)metadata_seg_hdr)->version,
sizeof(struct i40e_ddp_version));
return I40E_SUCCESS;
}
/* get global note size */
if (type == RTE_PMD_I40E_PKG_INFO_GLOBAL_NOTES_SIZE) {
if (info_size < sizeof(uint32_t)) {
PMD_DRV_LOG(ERR, "Invalid information buffer size");
return -EINVAL;
}
if (note_seg_hdr == NULL)
ret_size = 0;
else
ret_size = note_seg_hdr->size;
*(uint32_t *)info_buff = ret_size;
return I40E_SUCCESS;
}
/* get global note */
if (type == RTE_PMD_I40E_PKG_INFO_GLOBAL_NOTES) {
if (note_seg_hdr == NULL)
return -ENOTSUP;
if (info_size < note_seg_hdr->size) {
PMD_DRV_LOG(ERR, "Information buffer size is too small");
return -EINVAL;
}
memcpy(info_buff, &note_seg_hdr[1], note_seg_hdr->size);
return I40E_SUCCESS;
}
/* get i40e segment header info */
if (type == RTE_PMD_I40E_PKG_INFO_HEADER) {
struct rte_pmd_i40e_profile_info *info =
(struct rte_pmd_i40e_profile_info *)info_buff;
if (info_size < sizeof(struct rte_pmd_i40e_profile_info)) {
PMD_DRV_LOG(ERR, "Output info buff size is invalid.");
return -EINVAL;
}
if (!metadata_seg_hdr) {
PMD_DRV_LOG(ERR, "Failed to find metadata segment header");
return -EINVAL;
}
if (!i40e_seg_hdr) {
PMD_DRV_LOG(ERR, "Failed to find i40e segment header");
return -EINVAL;
}
memset(info, 0, sizeof(struct rte_pmd_i40e_profile_info));
info->owner = RTE_PMD_I40E_DDP_OWNER_UNKNOWN;
info->track_id =
((struct i40e_metadata_segment *)metadata_seg_hdr)->track_id;
memcpy(info->name,
((struct i40e_profile_segment *)i40e_seg_hdr)->name,
I40E_DDP_NAME_SIZE);
memcpy(&info->version,
&((struct i40e_profile_segment *)i40e_seg_hdr)->version,
sizeof(struct i40e_ddp_version));
return I40E_SUCCESS;
}
/* get number of devices */
if (type == RTE_PMD_I40E_PKG_INFO_DEVID_NUM) {
if (info_size < sizeof(uint32_t)) {
PMD_DRV_LOG(ERR, "Invalid information buffer size");
return -EINVAL;
}
*(uint32_t *)info_buff =
((struct i40e_profile_segment *)i40e_seg_hdr)->device_table_count;
return I40E_SUCCESS;
}
/* get list of devices */
if (type == RTE_PMD_I40E_PKG_INFO_DEVID_LIST) {
uint32_t dev_num;
dev_num =
((struct i40e_profile_segment *)i40e_seg_hdr)->device_table_count;
if (info_size < sizeof(struct rte_pmd_i40e_ddp_device_id) * dev_num) {
PMD_DRV_LOG(ERR, "Invalid information buffer size");
return -EINVAL;
}
memcpy(info_buff,
((struct i40e_profile_segment *)i40e_seg_hdr)->device_table,
sizeof(struct rte_pmd_i40e_ddp_device_id) * dev_num);
return I40E_SUCCESS;
}
/* get number of protocols */
if (type == RTE_PMD_I40E_PKG_INFO_PROTOCOL_NUM) {
struct i40e_profile_section_header *proto;
if (info_size < sizeof(uint32_t)) {
PMD_DRV_LOG(ERR, "Invalid information buffer size");
return -EINVAL;
}
proto = i40e_find_section_in_profile(SECTION_TYPE_PROTO,
(struct i40e_profile_segment *)i40e_seg_hdr);
*(uint32_t *)info_buff = i40e_get_tlv_section_size(proto);
return I40E_SUCCESS;
}
/* get list of protocols */
if (type == RTE_PMD_I40E_PKG_INFO_PROTOCOL_LIST) {
uint32_t i, j, nb_tlv, nb_rec, nb_proto_info;
struct rte_pmd_i40e_proto_info *pinfo;
struct i40e_profile_section_header *proto;
struct i40e_profile_tlv_section_record *tlv;
pinfo = (struct rte_pmd_i40e_proto_info *)info_buff;
nb_proto_info = info_size /
sizeof(struct rte_pmd_i40e_proto_info);
for (i = 0; i < nb_proto_info; i++) {
pinfo[i].proto_id = RTE_PMD_I40E_PROTO_UNUSED;
memset(pinfo[i].name, 0, RTE_PMD_I40E_DDP_NAME_SIZE);
}
proto = i40e_find_section_in_profile(SECTION_TYPE_PROTO,
(struct i40e_profile_segment *)i40e_seg_hdr);
nb_tlv = i40e_get_tlv_section_size(proto);
if (nb_tlv == 0)
return I40E_SUCCESS;
if (nb_proto_info < nb_tlv) {
PMD_DRV_LOG(ERR, "Invalid information buffer size");
return -EINVAL;
}
/* get number of records in the section */
nb_rec = proto->section.size /
sizeof(struct i40e_profile_tlv_section_record);
tlv = (struct i40e_profile_tlv_section_record *)&proto[1];
for (i = j = 0; i < nb_rec; j++) {
pinfo[j].proto_id = tlv->data[0];
snprintf(pinfo[j].name, I40E_DDP_NAME_SIZE, "%s",
(const char *)&tlv->data[1]);
i += tlv->len;
tlv = &tlv[tlv->len];
}
return I40E_SUCCESS;
}
/* get number of packet classification types */
if (type == RTE_PMD_I40E_PKG_INFO_PCTYPE_NUM) {
struct i40e_profile_section_header *pctype;
if (info_size < sizeof(uint32_t)) {
PMD_DRV_LOG(ERR, "Invalid information buffer size");
return -EINVAL;
}
pctype = i40e_find_section_in_profile(SECTION_TYPE_PCTYPE,
(struct i40e_profile_segment *)i40e_seg_hdr);
*(uint32_t *)info_buff = i40e_get_tlv_section_size(pctype);
return I40E_SUCCESS;
}
/* get list of packet classification types */
if (type == RTE_PMD_I40E_PKG_INFO_PCTYPE_LIST) {
uint32_t i, j, nb_tlv, nb_rec, nb_proto_info;
struct rte_pmd_i40e_ptype_info *pinfo;
struct i40e_profile_section_header *pctype;
struct i40e_profile_tlv_section_record *tlv;
pinfo = (struct rte_pmd_i40e_ptype_info *)info_buff;
nb_proto_info = info_size /
sizeof(struct rte_pmd_i40e_ptype_info);
for (i = 0; i < nb_proto_info; i++)
memset(&pinfo[i], RTE_PMD_I40E_PROTO_UNUSED,
sizeof(struct rte_pmd_i40e_ptype_info));
pctype = i40e_find_section_in_profile(SECTION_TYPE_PCTYPE,
(struct i40e_profile_segment *)i40e_seg_hdr);
nb_tlv = i40e_get_tlv_section_size(pctype);
if (nb_tlv == 0)
return I40E_SUCCESS;
if (nb_proto_info < nb_tlv) {
PMD_DRV_LOG(ERR, "Invalid information buffer size");
return -EINVAL;
}
/* get number of records in the section */
nb_rec = pctype->section.size /
sizeof(struct i40e_profile_tlv_section_record);
tlv = (struct i40e_profile_tlv_section_record *)&pctype[1];
for (i = j = 0; i < nb_rec; j++) {
memcpy(&pinfo[j], tlv->data,
sizeof(struct rte_pmd_i40e_ptype_info));
i += tlv->len;
tlv = &tlv[tlv->len];
}
return I40E_SUCCESS;
}
/* get number of packet types */
if (type == RTE_PMD_I40E_PKG_INFO_PTYPE_NUM) {
struct i40e_profile_section_header *ptype;
if (info_size < sizeof(uint32_t)) {
PMD_DRV_LOG(ERR, "Invalid information buffer size");
return -EINVAL;
}
ptype = i40e_find_section_in_profile(SECTION_TYPE_PTYPE,
(struct i40e_profile_segment *)i40e_seg_hdr);
*(uint32_t *)info_buff = i40e_get_tlv_section_size(ptype);
return I40E_SUCCESS;
}
/* get list of packet types */
if (type == RTE_PMD_I40E_PKG_INFO_PTYPE_LIST) {
uint32_t i, j, nb_tlv, nb_rec, nb_proto_info;
struct rte_pmd_i40e_ptype_info *pinfo;
struct i40e_profile_section_header *ptype;
struct i40e_profile_tlv_section_record *tlv;
pinfo = (struct rte_pmd_i40e_ptype_info *)info_buff;
nb_proto_info = info_size /
sizeof(struct rte_pmd_i40e_ptype_info);
for (i = 0; i < nb_proto_info; i++)
memset(&pinfo[i], RTE_PMD_I40E_PROTO_UNUSED,
sizeof(struct rte_pmd_i40e_ptype_info));
ptype = i40e_find_section_in_profile(SECTION_TYPE_PTYPE,
(struct i40e_profile_segment *)i40e_seg_hdr);
nb_tlv = i40e_get_tlv_section_size(ptype);
if (nb_tlv == 0)
return I40E_SUCCESS;
if (nb_proto_info < nb_tlv) {
PMD_DRV_LOG(ERR, "Invalid information buffer size");
return -EINVAL;
}
/* get number of records in the section */
nb_rec = ptype->section.size /
sizeof(struct i40e_profile_tlv_section_record);
for (i = j = 0; i < nb_rec; j++) {
tlv = (struct i40e_profile_tlv_section_record *)
&ptype[1 + i];
memcpy(&pinfo[j], tlv->data,
sizeof(struct rte_pmd_i40e_ptype_info));
i += tlv->len;
}
return I40E_SUCCESS;
}
PMD_DRV_LOG(ERR, "Info type %u is invalid.", type);
return -EINVAL;
}
int
rte_pmd_i40e_get_ddp_list(uint16_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;
}
static int check_invalid_pkt_type(uint32_t pkt_type)
{
uint32_t l2, l3, l4, tnl, il2, il3, il4;
l2 = pkt_type & RTE_PTYPE_L2_MASK;
l3 = pkt_type & RTE_PTYPE_L3_MASK;
l4 = pkt_type & RTE_PTYPE_L4_MASK;
tnl = pkt_type & RTE_PTYPE_TUNNEL_MASK;
il2 = pkt_type & RTE_PTYPE_INNER_L2_MASK;
il3 = pkt_type & RTE_PTYPE_INNER_L3_MASK;
il4 = pkt_type & RTE_PTYPE_INNER_L4_MASK;
if (l2 &&
l2 != RTE_PTYPE_L2_ETHER &&
l2 != RTE_PTYPE_L2_ETHER_TIMESYNC &&
l2 != RTE_PTYPE_L2_ETHER_ARP &&
l2 != RTE_PTYPE_L2_ETHER_LLDP &&
l2 != RTE_PTYPE_L2_ETHER_NSH &&
l2 != RTE_PTYPE_L2_ETHER_VLAN &&
l2 != RTE_PTYPE_L2_ETHER_QINQ &&
l2 != RTE_PTYPE_L2_ETHER_PPPOE)
return -1;
if (l3 &&
l3 != RTE_PTYPE_L3_IPV4 &&
l3 != RTE_PTYPE_L3_IPV4_EXT &&
l3 != RTE_PTYPE_L3_IPV6 &&
l3 != RTE_PTYPE_L3_IPV4_EXT_UNKNOWN &&
l3 != RTE_PTYPE_L3_IPV6_EXT &&
l3 != RTE_PTYPE_L3_IPV6_EXT_UNKNOWN)
return -1;
if (l4 &&
l4 != RTE_PTYPE_L4_TCP &&
l4 != RTE_PTYPE_L4_UDP &&
l4 != RTE_PTYPE_L4_FRAG &&
l4 != RTE_PTYPE_L4_SCTP &&
l4 != RTE_PTYPE_L4_ICMP &&
l4 != RTE_PTYPE_L4_NONFRAG)
return -1;
if (tnl &&
tnl != RTE_PTYPE_TUNNEL_IP &&
tnl != RTE_PTYPE_TUNNEL_GRENAT &&
tnl != RTE_PTYPE_TUNNEL_VXLAN &&
tnl != RTE_PTYPE_TUNNEL_NVGRE &&
tnl != RTE_PTYPE_TUNNEL_GENEVE &&
tnl != RTE_PTYPE_TUNNEL_GRENAT &&
tnl != RTE_PTYPE_TUNNEL_GTPC &&
tnl != RTE_PTYPE_TUNNEL_GTPU &&
tnl != RTE_PTYPE_TUNNEL_L2TP)
return -1;
if (il2 &&
il2 != RTE_PTYPE_INNER_L2_ETHER &&
il2 != RTE_PTYPE_INNER_L2_ETHER_VLAN &&
il2 != RTE_PTYPE_INNER_L2_ETHER_QINQ)
return -1;
if (il3 &&
il3 != RTE_PTYPE_INNER_L3_IPV4 &&
il3 != RTE_PTYPE_INNER_L3_IPV4_EXT &&
il3 != RTE_PTYPE_INNER_L3_IPV6 &&
il3 != RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN &&
il3 != RTE_PTYPE_INNER_L3_IPV6_EXT &&
il3 != RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN)
return -1;
if (il4 &&
il4 != RTE_PTYPE_INNER_L4_TCP &&
il4 != RTE_PTYPE_INNER_L4_UDP &&
il4 != RTE_PTYPE_INNER_L4_FRAG &&
il4 != RTE_PTYPE_INNER_L4_SCTP &&
il4 != RTE_PTYPE_INNER_L4_ICMP &&
il4 != RTE_PTYPE_INNER_L4_NONFRAG)
return -1;
return 0;
}
static int check_invalid_ptype_mapping(
struct rte_pmd_i40e_ptype_mapping *mapping_table,
uint16_t count)
{
int i;
for (i = 0; i < count; i++) {
uint16_t ptype = mapping_table[i].hw_ptype;
uint32_t pkt_type = mapping_table[i].sw_ptype;
if (ptype >= I40E_MAX_PKT_TYPE)
return -1;
if (pkt_type == RTE_PTYPE_UNKNOWN)
continue;
if (pkt_type & RTE_PMD_I40E_PTYPE_USER_DEFINE_MASK)
continue;
if (check_invalid_pkt_type(pkt_type))
return -1;
}
return 0;
}
int
rte_pmd_i40e_ptype_mapping_update(
uint16_t port,
struct rte_pmd_i40e_ptype_mapping *mapping_items,
uint16_t count,
uint8_t exclusive)
{
struct rte_eth_dev *dev;
struct i40e_adapter *ad;
int i;
RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
dev = &rte_eth_devices[port];
if (!is_i40e_supported(dev))
return -ENOTSUP;
if (count > I40E_MAX_PKT_TYPE)
return -EINVAL;
if (check_invalid_ptype_mapping(mapping_items, count))
return -EINVAL;
ad = I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
if (exclusive) {
for (i = 0; i < I40E_MAX_PKT_TYPE; i++)
ad->ptype_tbl[i] = RTE_PTYPE_UNKNOWN;
}
for (i = 0; i < count; i++)
ad->ptype_tbl[mapping_items[i].hw_ptype]
= mapping_items[i].sw_ptype;
return 0;
}
int rte_pmd_i40e_ptype_mapping_reset(uint16_t port)
{
struct rte_eth_dev *dev;
RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
dev = &rte_eth_devices[port];
if (!is_i40e_supported(dev))
return -ENOTSUP;
i40e_set_default_ptype_table(dev);
return 0;
}
int rte_pmd_i40e_ptype_mapping_get(
uint16_t port,
struct rte_pmd_i40e_ptype_mapping *mapping_items,
uint16_t size,
uint16_t *count,
uint8_t valid_only)
{
struct rte_eth_dev *dev;
struct i40e_adapter *ad;
int n = 0;
uint16_t i;
RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
dev = &rte_eth_devices[port];
if (!is_i40e_supported(dev))
return -ENOTSUP;
ad = I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
for (i = 0; i < I40E_MAX_PKT_TYPE; i++) {
if (n >= size)
break;
if (valid_only && ad->ptype_tbl[i] == RTE_PTYPE_UNKNOWN)
continue;
mapping_items[n].hw_ptype = i;
mapping_items[n].sw_ptype = ad->ptype_tbl[i];
n++;
}
*count = n;
return 0;
}
int rte_pmd_i40e_ptype_mapping_replace(uint16_t port,
uint32_t target,
uint8_t mask,
uint32_t pkt_type)
{
struct rte_eth_dev *dev;
struct i40e_adapter *ad;
uint16_t i;
RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
dev = &rte_eth_devices[port];
if (!is_i40e_supported(dev))
return -ENOTSUP;
if (!mask && check_invalid_pkt_type(target))
return -EINVAL;
if (check_invalid_pkt_type(pkt_type))
return -EINVAL;
ad = I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
for (i = 0; i < I40E_MAX_PKT_TYPE; i++) {
if (mask) {
if ((target | ad->ptype_tbl[i]) == target &&
(target & ad->ptype_tbl[i]))
ad->ptype_tbl[i] = pkt_type;
} else {
if (ad->ptype_tbl[i] == target)
ad->ptype_tbl[i] = pkt_type;
}
}
return 0;
}
int
rte_pmd_i40e_add_vf_mac_addr(uint16_t port, uint16_t vf_id,
struct ether_addr *mac_addr)
{
struct rte_eth_dev *dev;
struct i40e_pf_vf *vf;
struct i40e_vsi *vsi;
struct i40e_pf *pf;
struct i40e_mac_filter_info mac_filter;
int ret;
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;
}
mac_filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
ether_addr_copy(mac_addr, &mac_filter.mac_addr);
ret = i40e_vsi_add_mac(vsi, &mac_filter);
if (ret != I40E_SUCCESS) {
PMD_DRV_LOG(ERR, "Failed to add MAC filter.");
return -1;
}
return 0;
}
int rte_pmd_i40e_flow_type_mapping_reset(uint16_t port)
{
struct rte_eth_dev *dev;
RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
dev = &rte_eth_devices[port];
if (!is_i40e_supported(dev))
return -ENOTSUP;
i40e_set_default_pctype_table(dev);
return 0;
}
int rte_pmd_i40e_flow_type_mapping_get(
uint16_t port,
struct rte_pmd_i40e_flow_type_mapping *mapping_items)
{
struct rte_eth_dev *dev;
struct i40e_adapter *ad;
uint16_t i;
RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
dev = &rte_eth_devices[port];
if (!is_i40e_supported(dev))
return -ENOTSUP;
ad = I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
for (i = 0; i < I40E_FLOW_TYPE_MAX; i++) {
mapping_items[i].flow_type = i;
mapping_items[i].pctype = ad->pctypes_tbl[i];
}
return 0;
}
int
rte_pmd_i40e_flow_type_mapping_update(
uint16_t port,
struct rte_pmd_i40e_flow_type_mapping *mapping_items,
uint16_t count,
uint8_t exclusive)
{
struct rte_eth_dev *dev;
struct i40e_adapter *ad;
int i;
RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
dev = &rte_eth_devices[port];
if (!is_i40e_supported(dev))
return -ENOTSUP;
if (count > I40E_FLOW_TYPE_MAX)
return -EINVAL;
for (i = 0; i < count; i++)
if (mapping_items[i].flow_type >= I40E_FLOW_TYPE_MAX ||
mapping_items[i].flow_type == RTE_ETH_FLOW_UNKNOWN ||
(mapping_items[i].pctype &
(1ULL << I40E_FILTER_PCTYPE_INVALID)))
return -EINVAL;
ad = I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
if (exclusive) {
for (i = 0; i < I40E_FLOW_TYPE_MAX; i++)
ad->pctypes_tbl[i] = 0ULL;
ad->flow_types_mask = 0ULL;
}
for (i = 0; i < count; i++) {
ad->pctypes_tbl[mapping_items[i].flow_type] =
mapping_items[i].pctype;
if (mapping_items[i].pctype)
ad->flow_types_mask |=
(1ULL << mapping_items[i].flow_type);
else
ad->flow_types_mask &=
~(1ULL << mapping_items[i].flow_type);
}
for (i = 0, ad->pctypes_mask = 0ULL; i < I40E_FLOW_TYPE_MAX; i++)
ad->pctypes_mask |= ad->pctypes_tbl[i];
return 0;
}
int
rte_pmd_i40e_query_vfid_by_mac(uint16_t port, const struct ether_addr *vf_mac)
{
struct rte_eth_dev *dev;
struct ether_addr *mac;
struct i40e_pf *pf;
int vf_id;
struct i40e_pf_vf *vf;
uint16_t vf_num;
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);
vf_num = pf->vf_num;
for (vf_id = 0; vf_id < vf_num; vf_id++) {
vf = &pf->vfs[vf_id];
mac = &vf->mac_addr;
if (is_same_ether_addr(mac, vf_mac))
return vf_id;
}
return -EINVAL;
}
static int
i40e_vsi_update_queue_region_mapping(struct i40e_hw *hw,
struct i40e_pf *pf)
{
uint16_t i;
struct i40e_vsi *vsi = pf->main_vsi;
uint16_t queue_offset, bsf, tc_index;
struct i40e_vsi_context ctxt;
struct i40e_aqc_vsi_properties_data *vsi_info;
struct i40e_queue_regions *region_info =
&pf->queue_region;
int32_t ret = -EINVAL;
if (!region_info->queue_region_number) {
PMD_INIT_LOG(ERR, "there is no that region id been set before");
return ret;
}
memset(&ctxt, 0, sizeof(struct i40e_vsi_context));
/* Update Queue Pairs Mapping for currently enabled UPs */
ctxt.seid = vsi->seid;
ctxt.pf_num = hw->pf_id;
ctxt.vf_num = 0;
ctxt.uplink_seid = vsi->uplink_seid;
ctxt.info = vsi->info;
vsi_info = &ctxt.info;
memset(vsi_info->tc_mapping, 0, sizeof(uint16_t) * 8);
memset(vsi_info->queue_mapping, 0, sizeof(uint16_t) * 16);
/* Configure queue region and queue mapping parameters,
* for enabled queue region, allocate queues to this region.
*/
for (i = 0; i < region_info->queue_region_number; i++) {
tc_index = region_info->region[i].region_id;
bsf = rte_bsf32(region_info->region[i].queue_num);
queue_offset = region_info->region[i].queue_start_index;
vsi_info->tc_mapping[tc_index] = rte_cpu_to_le_16(
(queue_offset << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
(bsf << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT));
}
/* Associate queue number with VSI, Keep vsi->nb_qps unchanged */
vsi_info->mapping_flags |=
rte_cpu_to_le_16(I40E_AQ_VSI_QUE_MAP_CONTIG);
vsi_info->queue_mapping[0] = rte_cpu_to_le_16(vsi->base_queue);
vsi_info->valid_sections |=
rte_cpu_to_le_16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID);
/* Update the VSI after updating the VSI queue-mapping information */
ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
if (ret) {
PMD_DRV_LOG(ERR, "Failed to configure queue region mapping = %d ",
hw->aq.asq_last_status);
return ret;
}
/* update the local VSI info with updated queue map */
rte_memcpy(&vsi->info.tc_mapping, &ctxt.info.tc_mapping,
sizeof(vsi->info.tc_mapping));
rte_memcpy(&vsi->info.queue_mapping,
&ctxt.info.queue_mapping,
sizeof(vsi->info.queue_mapping));
vsi->info.mapping_flags = ctxt.info.mapping_flags;
vsi->info.valid_sections = 0;
return 0;
}
static int
i40e_queue_region_set_region(struct i40e_pf *pf,
struct rte_pmd_i40e_queue_region_conf *conf_ptr)
{
uint16_t i;
struct i40e_vsi *main_vsi = pf->main_vsi;
struct i40e_queue_regions *info = &pf->queue_region;
int32_t ret = -EINVAL;
if (!((rte_is_power_of_2(conf_ptr->queue_num)) &&
conf_ptr->queue_num <= 64)) {
PMD_DRV_LOG(ERR, "The region sizes should be any of the following values: 1, 2, 4, 8, 16, 32, 64 as long as the "
"total number of queues do not exceed the VSI allocation");
return ret;
}
if (conf_ptr->region_id > I40E_REGION_MAX_INDEX) {
PMD_DRV_LOG(ERR, "the queue region max index is 7");
return ret;
}
if ((conf_ptr->queue_start_index + conf_ptr->queue_num)
> main_vsi->nb_used_qps) {
PMD_DRV_LOG(ERR, "the queue index exceeds the VSI range");
return ret;
}
for (i = 0; i < info->queue_region_number; i++)
if (conf_ptr->region_id == info->region[i].region_id)
break;
if (i == info->queue_region_number &&
i <= I40E_REGION_MAX_INDEX) {
info->region[i].region_id = conf_ptr->region_id;
info->region[i].queue_num = conf_ptr->queue_num;
info->region[i].queue_start_index =
conf_ptr->queue_start_index;
info->queue_region_number++;
} else {
PMD_DRV_LOG(ERR, "queue region number exceeds maxnum 8 or the queue region id has been set before");
return ret;
}
return 0;
}
static int
i40e_queue_region_set_flowtype(struct i40e_pf *pf,
struct rte_pmd_i40e_queue_region_conf *rss_region_conf)
{
int32_t ret = -EINVAL;
struct i40e_queue_regions *info = &pf->queue_region;
uint16_t i, j;
uint16_t region_index, flowtype_index;
/* For the pctype or hardware flowtype of packet,
* the specific index for each type has been defined
* in file i40e_type.h as enum i40e_filter_pctype.
*/
if (rss_region_conf->region_id > I40E_PFQF_HREGION_MAX_INDEX) {
PMD_DRV_LOG(ERR, "the queue region max index is 7");
return ret;
}
if (rss_region_conf->hw_flowtype >= I40E_FILTER_PCTYPE_MAX) {
PMD_DRV_LOG(ERR, "the hw_flowtype or PCTYPE max index is 63");
return ret;
}
for (i = 0; i < info->queue_region_number; i++)
if (rss_region_conf->region_id == info->region[i].region_id)
break;
if (i == info->queue_region_number) {
PMD_DRV_LOG(ERR, "that region id has not been set before");
ret = -EINVAL;
return ret;
}
region_index = i;
for (i = 0; i < info->queue_region_number; i++) {
for (j = 0; j < info->region[i].flowtype_num; j++) {
if (rss_region_conf->hw_flowtype ==
info->region[i].hw_flowtype[j]) {
PMD_DRV_LOG(ERR, "that hw_flowtype has been set before");
return 0;
}
}
}
flowtype_index = info->region[region_index].flowtype_num;
info->region[region_index].hw_flowtype[flowtype_index] =
rss_region_conf->hw_flowtype;
info->region[region_index].flowtype_num++;
return 0;
}
static void
i40e_queue_region_pf_flowtype_conf(struct i40e_hw *hw,
struct i40e_pf *pf)
{
uint8_t hw_flowtype;
uint32_t pfqf_hregion;
uint16_t i, j, index;
struct i40e_queue_regions *info = &pf->queue_region;
/* For the pctype or hardware flowtype of packet,
* the specific index for each type has been defined
* in file i40e_type.h as enum i40e_filter_pctype.
*/
for (i = 0; i < info->queue_region_number; i++) {
for (j = 0; j < info->region[i].flowtype_num; j++) {
hw_flowtype = info->region[i].hw_flowtype[j];
index = hw_flowtype >> 3;
pfqf_hregion =
i40e_read_rx_ctl(hw, I40E_PFQF_HREGION(index));
if ((hw_flowtype & 0x7) == 0) {
pfqf_hregion |= info->region[i].region_id <<
I40E_PFQF_HREGION_REGION_0_SHIFT;
pfqf_hregion |= 1 <<
I40E_PFQF_HREGION_OVERRIDE_ENA_0_SHIFT;
} else if ((hw_flowtype & 0x7) == 1) {
pfqf_hregion |= info->region[i].region_id <<
I40E_PFQF_HREGION_REGION_1_SHIFT;
pfqf_hregion |= 1 <<
I40E_PFQF_HREGION_OVERRIDE_ENA_1_SHIFT;
} else if ((hw_flowtype & 0x7) == 2) {
pfqf_hregion |= info->region[i].region_id <<
I40E_PFQF_HREGION_REGION_2_SHIFT;
pfqf_hregion |= 1 <<
I40E_PFQF_HREGION_OVERRIDE_ENA_2_SHIFT;
} else if ((hw_flowtype & 0x7) == 3) {
pfqf_hregion |= info->region[i].region_id <<
I40E_PFQF_HREGION_REGION_3_SHIFT;
pfqf_hregion |= 1 <<
I40E_PFQF_HREGION_OVERRIDE_ENA_3_SHIFT;
} else if ((hw_flowtype & 0x7) == 4) {
pfqf_hregion |= info->region[i].region_id <<
I40E_PFQF_HREGION_REGION_4_SHIFT;
pfqf_hregion |= 1 <<
I40E_PFQF_HREGION_OVERRIDE_ENA_4_SHIFT;
} else if ((hw_flowtype & 0x7) == 5) {
pfqf_hregion |= info->region[i].region_id <<
I40E_PFQF_HREGION_REGION_5_SHIFT;
pfqf_hregion |= 1 <<
I40E_PFQF_HREGION_OVERRIDE_ENA_5_SHIFT;
} else if ((hw_flowtype & 0x7) == 6) {
pfqf_hregion |= info->region[i].region_id <<
I40E_PFQF_HREGION_REGION_6_SHIFT;
pfqf_hregion |= 1 <<
I40E_PFQF_HREGION_OVERRIDE_ENA_6_SHIFT;
} else {
pfqf_hregion |= info->region[i].region_id <<
I40E_PFQF_HREGION_REGION_7_SHIFT;
pfqf_hregion |= 1 <<
I40E_PFQF_HREGION_OVERRIDE_ENA_7_SHIFT;
}
i40e_write_rx_ctl(hw, I40E_PFQF_HREGION(index),
pfqf_hregion);
}
}
}
static int
i40e_queue_region_set_user_priority(struct i40e_pf *pf,
struct rte_pmd_i40e_queue_region_conf *rss_region_conf)
{
struct i40e_queue_regions *info = &pf->queue_region;
int32_t ret = -EINVAL;
uint16_t i, j, region_index;
if (rss_region_conf->user_priority >= I40E_MAX_USER_PRIORITY) {
PMD_DRV_LOG(ERR, "the queue region max index is 7");
return ret;
}
if (rss_region_conf->region_id > I40E_REGION_MAX_INDEX) {
PMD_DRV_LOG(ERR, "the region_id max index is 7");
return ret;
}
for (i = 0; i < info->queue_region_number; i++)
if (rss_region_conf->region_id == info->region[i].region_id)
break;
if (i == info->queue_region_number) {
PMD_DRV_LOG(ERR, "that region id has not been set before");
ret = -EINVAL;
return ret;
}
region_index = i;
for (i = 0; i < info->queue_region_number; i++) {
for (j = 0; j < info->region[i].user_priority_num; j++) {
if (info->region[i].user_priority[j] ==
rss_region_conf->user_priority) {
PMD_DRV_LOG(ERR, "that user priority has been set before");
return 0;
}
}
}
j = info->region[region_index].user_priority_num;
info->region[region_index].user_priority[j] =
rss_region_conf->user_priority;
info->region[region_index].user_priority_num++;
return 0;
}
static int
i40e_queue_region_dcb_configure(struct i40e_hw *hw,
struct i40e_pf *pf)
{
struct i40e_dcbx_config dcb_cfg_local;
struct i40e_dcbx_config *dcb_cfg;
struct i40e_queue_regions *info = &pf->queue_region;
struct i40e_dcbx_config *old_cfg = &hw->local_dcbx_config;
int32_t ret = -EINVAL;
uint16_t i, j, prio_index, region_index;
uint8_t tc_map, tc_bw, bw_lf;
if (!info->queue_region_number) {
PMD_DRV_LOG(ERR, "No queue region been set before");
return ret;
}
dcb_cfg = &dcb_cfg_local;
memset(dcb_cfg, 0, sizeof(struct i40e_dcbx_config));
/* assume each tc has the same bw */
tc_bw = I40E_MAX_PERCENT / info->queue_region_number;
for (i = 0; i < info->queue_region_number; i++)
dcb_cfg->etscfg.tcbwtable[i] = tc_bw;
/* to ensure the sum of tcbw is equal to 100 */
bw_lf = I40E_MAX_PERCENT % info->queue_region_number;
for (i = 0; i < bw_lf; i++)
dcb_cfg->etscfg.tcbwtable[i]++;
/* assume each tc has the same Transmission Selection Algorithm */
for (i = 0; i < info->queue_region_number; i++)
dcb_cfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
for (i = 0; i < info->queue_region_number; i++) {
for (j = 0; j < info->region[i].user_priority_num; j++) {
prio_index = info->region[i].user_priority[j];
region_index = info->region[i].region_id;
dcb_cfg->etscfg.prioritytable[prio_index] =
region_index;
}
}
/* FW needs one App to configure HW */
dcb_cfg->numapps = I40E_DEFAULT_DCB_APP_NUM;
dcb_cfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
dcb_cfg->app[0].priority = I40E_DEFAULT_DCB_APP_PRIO;
dcb_cfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
tc_map = RTE_LEN2MASK(info->queue_region_number, uint8_t);
dcb_cfg->pfc.willing = 0;
dcb_cfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
dcb_cfg->pfc.pfcenable = tc_map;
/* Copy the new config to the current config */
*old_cfg = *dcb_cfg;
old_cfg->etsrec = old_cfg->etscfg;
ret = i40e_set_dcb_config(hw);
if (ret) {
PMD_DRV_LOG(ERR, "Set queue region DCB Config failed, err %s aq_err %s",
i40e_stat_str(hw, ret),
i40e_aq_str(hw, hw->aq.asq_last_status));
return ret;
}
return 0;
}
int
i40e_flush_queue_region_all_conf(struct rte_eth_dev *dev,
struct i40e_hw *hw, struct i40e_pf *pf, uint16_t on)
{
int32_t ret = -EINVAL;
struct i40e_queue_regions *info = &pf->queue_region;
struct i40e_vsi *main_vsi = pf->main_vsi;
if (on) {
i40e_queue_region_pf_flowtype_conf(hw, pf);
ret = i40e_vsi_update_queue_region_mapping(hw, pf);
if (ret != I40E_SUCCESS) {
PMD_DRV_LOG(INFO, "Failed to flush queue region mapping.");
return ret;
}
ret = i40e_queue_region_dcb_configure(hw, pf);
if (ret != I40E_SUCCESS) {
PMD_DRV_LOG(INFO, "Failed to flush dcb.");
return ret;
}
return 0;
}
if (info->queue_region_number) {
info->queue_region_number = 1;
info->region[0].queue_num = main_vsi->nb_used_qps;
info->region[0].queue_start_index = 0;
ret = i40e_vsi_update_queue_region_mapping(hw, pf);
if (ret != I40E_SUCCESS)
PMD_DRV_LOG(INFO, "Failed to flush queue region mapping.");
ret = i40e_dcb_init_configure(dev, TRUE);
if (ret != I40E_SUCCESS) {
PMD_DRV_LOG(INFO, "Failed to flush dcb.");
pf->flags &= ~I40E_FLAG_DCB;
}
i40e_init_queue_region_conf(dev);
}
return 0;
}
static int
i40e_queue_region_pf_check_rss(struct i40e_pf *pf)
{
struct i40e_hw *hw = I40E_PF_TO_HW(pf);
uint64_t hena;
hena = (uint64_t)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0));
hena |= ((uint64_t)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1))) << 32;
if (!hena)
return -ENOTSUP;
return 0;
}
static int
i40e_queue_region_get_all_info(struct i40e_pf *pf,
struct i40e_queue_regions *regions_ptr)
{
struct i40e_queue_regions *info = &pf->queue_region;
rte_memcpy(regions_ptr, info,
sizeof(struct i40e_queue_regions));
return 0;
}
int rte_pmd_i40e_rss_queue_region_conf(uint16_t port_id,
enum rte_pmd_i40e_queue_region_op op_type, void *arg)
{
struct rte_eth_dev *dev = &rte_eth_devices[port_id];
struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
int32_t ret;
RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
if (!is_i40e_supported(dev))
return -ENOTSUP;
if (!(!i40e_queue_region_pf_check_rss(pf)))
return -ENOTSUP;
/* This queue region feature only support pf by now. It should
* be called after dev_start, and will be clear after dev_stop.
* "RTE_PMD_I40E_RSS_QUEUE_REGION_ALL_FLUSH_ON"
* is just an enable function which server for other configuration,
* it is for all configuration about queue region from up layer,
* at first will only keep in DPDK softwarestored in driver,
* only after "FLUSH_ON", it commit all configuration to HW.
* Because PMD had to set hardware configuration at a time, so
* it will record all up layer command at first.
* "RTE_PMD_I40E_RSS_QUEUE_REGION_ALL_FLUSH_OFF" is
* just clean all configuration about queue region just now,
* and restore all to DPDK i40e driver default
* config when start up.
*/
switch (op_type) {
case RTE_PMD_I40E_RSS_QUEUE_REGION_SET:
ret = i40e_queue_region_set_region(pf,
(struct rte_pmd_i40e_queue_region_conf *)arg);
break;
case RTE_PMD_I40E_RSS_QUEUE_REGION_FLOWTYPE_SET:
ret = i40e_queue_region_set_flowtype(pf,
(struct rte_pmd_i40e_queue_region_conf *)arg);
break;
case RTE_PMD_I40E_RSS_QUEUE_REGION_USER_PRIORITY_SET:
ret = i40e_queue_region_set_user_priority(pf,
(struct rte_pmd_i40e_queue_region_conf *)arg);
break;
case RTE_PMD_I40E_RSS_QUEUE_REGION_ALL_FLUSH_ON:
ret = i40e_flush_queue_region_all_conf(dev, hw, pf, 1);
break;
case RTE_PMD_I40E_RSS_QUEUE_REGION_ALL_FLUSH_OFF:
ret = i40e_flush_queue_region_all_conf(dev, hw, pf, 0);
break;
case RTE_PMD_I40E_RSS_QUEUE_REGION_INFO_GET:
ret = i40e_queue_region_get_all_info(pf,
(struct i40e_queue_regions *)arg);
break;
default:
PMD_DRV_LOG(WARNING, "op type (%d) not supported",
op_type);
ret = -EINVAL;
}
I40E_WRITE_FLUSH(hw);
return ret;
}
int rte_pmd_i40e_flow_add_del_packet_template(
uint16_t port,
const struct rte_pmd_i40e_pkt_template_conf *conf,
uint8_t add)
{
struct rte_eth_dev *dev = &rte_eth_devices[port];
struct i40e_fdir_filter_conf filter_conf;
RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
if (!is_i40e_supported(dev))
return -ENOTSUP;
memset(&filter_conf, 0, sizeof(filter_conf));
filter_conf.soft_id = conf->soft_id;
filter_conf.input.flow.raw_flow.pctype = conf->input.pctype;
filter_conf.input.flow.raw_flow.packet = conf->input.packet;
filter_conf.input.flow.raw_flow.length = conf->input.length;
filter_conf.input.flow_ext.pkt_template = true;
filter_conf.action.rx_queue = conf->action.rx_queue;
filter_conf.action.behavior =
(enum i40e_fdir_behavior)conf->action.behavior;
filter_conf.action.report_status =
(enum i40e_fdir_status)conf->action.report_status;
filter_conf.action.flex_off = conf->action.flex_off;
return i40e_flow_add_del_fdir_filter(dev, &filter_conf, add);
}
int
rte_pmd_i40e_inset_get(uint16_t port, uint8_t pctype,
struct rte_pmd_i40e_inset *inset,
enum rte_pmd_i40e_inset_type inset_type)
{
struct rte_eth_dev *dev;
struct i40e_hw *hw;
uint64_t inset_reg;
uint32_t mask_reg[2];
int i;
RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
dev = &rte_eth_devices[port];
if (!is_i40e_supported(dev))
return -ENOTSUP;
if (pctype > 63)
return -EINVAL;
hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
memset(inset, 0, sizeof(struct rte_pmd_i40e_inset));
switch (inset_type) {
case INSET_HASH:
/* Get input set */
inset_reg =
i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, pctype));
inset_reg <<= I40E_32_BIT_WIDTH;
inset_reg |=
i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(0, pctype));
/* Get field mask */
mask_reg[0] =
i40e_read_rx_ctl(hw, I40E_GLQF_HASH_MSK(0, pctype));
mask_reg[1] =
i40e_read_rx_ctl(hw, I40E_GLQF_HASH_MSK(1, pctype));
break;
case INSET_FDIR:
inset_reg =
i40e_read_rx_ctl(hw, I40E_PRTQF_FD_INSET(pctype, 1));
inset_reg <<= I40E_32_BIT_WIDTH;
inset_reg |=
i40e_read_rx_ctl(hw, I40E_PRTQF_FD_INSET(pctype, 0));
mask_reg[0] =
i40e_read_rx_ctl(hw, I40E_GLQF_FD_MSK(0, pctype));
mask_reg[1] =
i40e_read_rx_ctl(hw, I40E_GLQF_FD_MSK(1, pctype));
break;
case INSET_FDIR_FLX:
inset_reg =
i40e_read_rx_ctl(hw, I40E_PRTQF_FD_FLXINSET(pctype));
mask_reg[0] =
i40e_read_rx_ctl(hw, I40E_PRTQF_FD_MSK(pctype, 0));
mask_reg[1] =
i40e_read_rx_ctl(hw, I40E_PRTQF_FD_MSK(pctype, 1));
break;
default:
PMD_DRV_LOG(ERR, "Unsupported input set type.");
return -EINVAL;
}
inset->inset = inset_reg;
for (i = 0; i < 2; i++) {
inset->mask[i].field_idx = ((mask_reg[i] >> 16) & 0x3F);
inset->mask[i].mask = mask_reg[i] & 0xFFFF;
}
return 0;
}
int
rte_pmd_i40e_inset_set(uint16_t port, uint8_t pctype,
struct rte_pmd_i40e_inset *inset,
enum rte_pmd_i40e_inset_type inset_type)
{
struct rte_eth_dev *dev;
struct i40e_hw *hw;
struct i40e_pf *pf;
uint64_t inset_reg;
uint32_t mask_reg[2];
int i;
RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
dev = &rte_eth_devices[port];
if (!is_i40e_supported(dev))
return -ENOTSUP;
if (pctype > 63)
return -EINVAL;
hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
if (pf->support_multi_driver) {
PMD_DRV_LOG(ERR, "Input set configuration is not supported.");
return -ENOTSUP;
}
inset_reg = inset->inset;
for (i = 0; i < 2; i++)
mask_reg[i] = (inset->mask[i].field_idx << 16) |
inset->mask[i].mask;
switch (inset_type) {
case INSET_HASH:
i40e_check_write_global_reg(hw, I40E_GLQF_HASH_INSET(0, pctype),
(uint32_t)(inset_reg & UINT32_MAX));
i40e_check_write_global_reg(hw, I40E_GLQF_HASH_INSET(1, pctype),
(uint32_t)((inset_reg >>
I40E_32_BIT_WIDTH) & UINT32_MAX));
for (i = 0; i < 2; i++)
i40e_check_write_global_reg(hw,
I40E_GLQF_HASH_MSK(i, pctype),
mask_reg[i]);
break;
case INSET_FDIR:
i40e_check_write_reg(hw, I40E_PRTQF_FD_INSET(pctype, 0),
(uint32_t)(inset_reg & UINT32_MAX));
i40e_check_write_reg(hw, I40E_PRTQF_FD_INSET(pctype, 1),
(uint32_t)((inset_reg >>
I40E_32_BIT_WIDTH) & UINT32_MAX));
for (i = 0; i < 2; i++)
i40e_check_write_global_reg(hw,
I40E_GLQF_FD_MSK(i, pctype),
mask_reg[i]);
break;
case INSET_FDIR_FLX:
i40e_check_write_reg(hw, I40E_PRTQF_FD_FLXINSET(pctype),
(uint32_t)(inset_reg & UINT32_MAX));
for (i = 0; i < 2; i++)
i40e_check_write_reg(hw, I40E_PRTQF_FD_MSK(pctype, i),
mask_reg[i]);
break;
default:
PMD_DRV_LOG(ERR, "Unsupported input set type.");
return -EINVAL;
}
I40E_WRITE_FLUSH(hw);
return 0;
}