Commit 23044d77 authored by David S. Miller's avatar David S. Miller

Merge branch '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue

Tony Nguyen says:

====================
40GbE Intel Wired LAN Driver Updates 2021-12-17

Brett Creeley says:

This patch series adds support in the iavf driver for communicating and
using VIRTCHNL_VF_OFFLOAD_VLAN_V2. The current VIRTCHNL_VF_OFFLOAD_VLAN
is very limited and covers all 802.1Q VLAN offloads and filtering with
no granularity.

The new VIRTCHNL_VF_OFFLOAD_VLAN_V2 adds more granularity, flexibility,
and support for 802.1ad offloads and filtering. This includes the VF
negotiating which VLAN offloads/filtering it's allowed, where VLAN tags
should be inserted and/or stripped into and from descriptors, and the
supported VLAN protocols.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7e1c5d7b 92fc5085
......@@ -55,7 +55,8 @@ enum iavf_vsi_state_t {
struct iavf_vsi {
struct iavf_adapter *back;
struct net_device *netdev;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
unsigned long active_cvlans[BITS_TO_LONGS(VLAN_N_VID)];
unsigned long active_svlans[BITS_TO_LONGS(VLAN_N_VID)];
u16 seid;
u16 id;
DECLARE_BITMAP(state, __IAVF_VSI_STATE_SIZE__);
......@@ -146,9 +147,15 @@ struct iavf_mac_filter {
};
};
#define IAVF_VLAN(vid, tpid) ((struct iavf_vlan){ vid, tpid })
struct iavf_vlan {
u16 vid;
u16 tpid;
};
struct iavf_vlan_filter {
struct list_head list;
u16 vlan;
struct iavf_vlan vlan;
bool remove; /* filter needs to be removed */
bool add; /* filter needs to be added */
};
......@@ -181,6 +188,8 @@ enum iavf_state_t {
__IAVF_REMOVE, /* driver is being unloaded */
__IAVF_INIT_VERSION_CHECK, /* aq msg sent, awaiting reply */
__IAVF_INIT_GET_RESOURCES, /* aq msg sent, awaiting reply */
__IAVF_INIT_GET_OFFLOAD_VLAN_V2_CAPS,
__IAVF_INIT_CONFIG_ADAPTER,
__IAVF_INIT_SW, /* got resources, setting up structs */
__IAVF_INIT_FAILED, /* init failed, restarting procedure */
__IAVF_RESETTING, /* in reset */
......@@ -278,38 +287,47 @@ struct iavf_adapter {
/* duplicates for common code */
#define IAVF_FLAG_DCB_ENABLED 0
/* flags for admin queue service task */
u32 aq_required;
#define IAVF_FLAG_AQ_ENABLE_QUEUES BIT(0)
#define IAVF_FLAG_AQ_DISABLE_QUEUES BIT(1)
#define IAVF_FLAG_AQ_ADD_MAC_FILTER BIT(2)
#define IAVF_FLAG_AQ_ADD_VLAN_FILTER BIT(3)
#define IAVF_FLAG_AQ_DEL_MAC_FILTER BIT(4)
#define IAVF_FLAG_AQ_DEL_VLAN_FILTER BIT(5)
#define IAVF_FLAG_AQ_CONFIGURE_QUEUES BIT(6)
#define IAVF_FLAG_AQ_MAP_VECTORS BIT(7)
#define IAVF_FLAG_AQ_HANDLE_RESET BIT(8)
#define IAVF_FLAG_AQ_CONFIGURE_RSS BIT(9) /* direct AQ config */
#define IAVF_FLAG_AQ_GET_CONFIG BIT(10)
u64 aq_required;
#define IAVF_FLAG_AQ_ENABLE_QUEUES BIT_ULL(0)
#define IAVF_FLAG_AQ_DISABLE_QUEUES BIT_ULL(1)
#define IAVF_FLAG_AQ_ADD_MAC_FILTER BIT_ULL(2)
#define IAVF_FLAG_AQ_ADD_VLAN_FILTER BIT_ULL(3)
#define IAVF_FLAG_AQ_DEL_MAC_FILTER BIT_ULL(4)
#define IAVF_FLAG_AQ_DEL_VLAN_FILTER BIT_ULL(5)
#define IAVF_FLAG_AQ_CONFIGURE_QUEUES BIT_ULL(6)
#define IAVF_FLAG_AQ_MAP_VECTORS BIT_ULL(7)
#define IAVF_FLAG_AQ_HANDLE_RESET BIT_ULL(8)
#define IAVF_FLAG_AQ_CONFIGURE_RSS BIT_ULL(9) /* direct AQ config */
#define IAVF_FLAG_AQ_GET_CONFIG BIT_ULL(10)
/* Newer style, RSS done by the PF so we can ignore hardware vagaries. */
#define IAVF_FLAG_AQ_GET_HENA BIT(11)
#define IAVF_FLAG_AQ_SET_HENA BIT(12)
#define IAVF_FLAG_AQ_SET_RSS_KEY BIT(13)
#define IAVF_FLAG_AQ_SET_RSS_LUT BIT(14)
#define IAVF_FLAG_AQ_REQUEST_PROMISC BIT(15)
#define IAVF_FLAG_AQ_RELEASE_PROMISC BIT(16)
#define IAVF_FLAG_AQ_REQUEST_ALLMULTI BIT(17)
#define IAVF_FLAG_AQ_RELEASE_ALLMULTI BIT(18)
#define IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING BIT(19)
#define IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING BIT(20)
#define IAVF_FLAG_AQ_ENABLE_CHANNELS BIT(21)
#define IAVF_FLAG_AQ_DISABLE_CHANNELS BIT(22)
#define IAVF_FLAG_AQ_ADD_CLOUD_FILTER BIT(23)
#define IAVF_FLAG_AQ_DEL_CLOUD_FILTER BIT(24)
#define IAVF_FLAG_AQ_ADD_FDIR_FILTER BIT(25)
#define IAVF_FLAG_AQ_DEL_FDIR_FILTER BIT(26)
#define IAVF_FLAG_AQ_ADD_ADV_RSS_CFG BIT(27)
#define IAVF_FLAG_AQ_DEL_ADV_RSS_CFG BIT(28)
#define IAVF_FLAG_AQ_REQUEST_STATS BIT(29)
#define IAVF_FLAG_AQ_GET_HENA BIT_ULL(11)
#define IAVF_FLAG_AQ_SET_HENA BIT_ULL(12)
#define IAVF_FLAG_AQ_SET_RSS_KEY BIT_ULL(13)
#define IAVF_FLAG_AQ_SET_RSS_LUT BIT_ULL(14)
#define IAVF_FLAG_AQ_REQUEST_PROMISC BIT_ULL(15)
#define IAVF_FLAG_AQ_RELEASE_PROMISC BIT_ULL(16)
#define IAVF_FLAG_AQ_REQUEST_ALLMULTI BIT_ULL(17)
#define IAVF_FLAG_AQ_RELEASE_ALLMULTI BIT_ULL(18)
#define IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING BIT_ULL(19)
#define IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING BIT_ULL(20)
#define IAVF_FLAG_AQ_ENABLE_CHANNELS BIT_ULL(21)
#define IAVF_FLAG_AQ_DISABLE_CHANNELS BIT_ULL(22)
#define IAVF_FLAG_AQ_ADD_CLOUD_FILTER BIT_ULL(23)
#define IAVF_FLAG_AQ_DEL_CLOUD_FILTER BIT_ULL(24)
#define IAVF_FLAG_AQ_ADD_FDIR_FILTER BIT_ULL(25)
#define IAVF_FLAG_AQ_DEL_FDIR_FILTER BIT_ULL(26)
#define IAVF_FLAG_AQ_ADD_ADV_RSS_CFG BIT_ULL(27)
#define IAVF_FLAG_AQ_DEL_ADV_RSS_CFG BIT_ULL(28)
#define IAVF_FLAG_AQ_REQUEST_STATS BIT_ULL(29)
#define IAVF_FLAG_AQ_GET_OFFLOAD_VLAN_V2_CAPS BIT_ULL(30)
#define IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_STRIPPING BIT_ULL(31)
#define IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_STRIPPING BIT_ULL(32)
#define IAVF_FLAG_AQ_ENABLE_STAG_VLAN_STRIPPING BIT_ULL(33)
#define IAVF_FLAG_AQ_DISABLE_STAG_VLAN_STRIPPING BIT_ULL(34)
#define IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_INSERTION BIT_ULL(35)
#define IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_INSERTION BIT_ULL(36)
#define IAVF_FLAG_AQ_ENABLE_STAG_VLAN_INSERTION BIT_ULL(37)
#define IAVF_FLAG_AQ_DISABLE_STAG_VLAN_INSERTION BIT_ULL(38)
/* OS defined structs */
struct net_device *netdev;
......@@ -349,6 +367,14 @@ struct iavf_adapter {
VIRTCHNL_VF_OFFLOAD_RSS_PF)))
#define VLAN_ALLOWED(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_OFFLOAD_VLAN)
#define VLAN_V2_ALLOWED(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_OFFLOAD_VLAN_V2)
#define VLAN_V2_FILTERING_ALLOWED(_a) \
(VLAN_V2_ALLOWED((_a)) && \
((_a)->vlan_v2_caps.filtering.filtering_support.outer || \
(_a)->vlan_v2_caps.filtering.filtering_support.inner))
#define VLAN_FILTERING_ALLOWED(_a) \
(VLAN_ALLOWED((_a)) || VLAN_V2_FILTERING_ALLOWED((_a)))
#define ADV_LINK_SUPPORT(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_CAP_ADV_LINK_SPEED)
#define FDIR_FLTR_SUPPORT(_a) ((_a)->vf_res->vf_cap_flags & \
......@@ -360,6 +386,7 @@ struct iavf_adapter {
struct virtchnl_version_info pf_version;
#define PF_IS_V11(_a) (((_a)->pf_version.major == 1) && \
((_a)->pf_version.minor == 1))
struct virtchnl_vlan_caps vlan_v2_caps;
u16 msg_enable;
struct iavf_eth_stats current_stats;
struct iavf_vsi vsi;
......@@ -448,6 +475,7 @@ static inline void iavf_change_state(struct iavf_adapter *adapter,
int iavf_up(struct iavf_adapter *adapter);
void iavf_down(struct iavf_adapter *adapter);
int iavf_process_config(struct iavf_adapter *adapter);
int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter);
void iavf_schedule_reset(struct iavf_adapter *adapter);
void iavf_schedule_request_stats(struct iavf_adapter *adapter);
void iavf_reset(struct iavf_adapter *adapter);
......@@ -466,6 +494,9 @@ int iavf_send_api_ver(struct iavf_adapter *adapter);
int iavf_verify_api_ver(struct iavf_adapter *adapter);
int iavf_send_vf_config_msg(struct iavf_adapter *adapter);
int iavf_get_vf_config(struct iavf_adapter *adapter);
int iavf_get_vf_vlan_v2_caps(struct iavf_adapter *adapter);
int iavf_send_vf_offload_vlan_v2_msg(struct iavf_adapter *adapter);
void iavf_set_queue_vlan_tag_loc(struct iavf_adapter *adapter);
void iavf_irq_enable(struct iavf_adapter *adapter, bool flush);
void iavf_configure_queues(struct iavf_adapter *adapter);
void iavf_deconfigure_queues(struct iavf_adapter *adapter);
......@@ -501,6 +532,14 @@ void iavf_enable_channels(struct iavf_adapter *adapter);
void iavf_disable_channels(struct iavf_adapter *adapter);
void iavf_add_cloud_filter(struct iavf_adapter *adapter);
void iavf_del_cloud_filter(struct iavf_adapter *adapter);
void iavf_enable_vlan_stripping_v2(struct iavf_adapter *adapter, u16 tpid);
void iavf_disable_vlan_stripping_v2(struct iavf_adapter *adapter, u16 tpid);
void iavf_enable_vlan_insertion_v2(struct iavf_adapter *adapter, u16 tpid);
void iavf_disable_vlan_insertion_v2(struct iavf_adapter *adapter, u16 tpid);
void
iavf_set_vlan_offload_features(struct iavf_adapter *adapter,
netdev_features_t prev_features,
netdev_features_t features);
void iavf_add_fdir_filter(struct iavf_adapter *adapter);
void iavf_del_fdir_filter(struct iavf_adapter *adapter);
void iavf_add_adv_rss_cfg(struct iavf_adapter *adapter);
......
......@@ -646,14 +646,17 @@ static void iavf_configure_rx(struct iavf_adapter *adapter)
* mac_vlan_list_lock.
**/
static struct
iavf_vlan_filter *iavf_find_vlan(struct iavf_adapter *adapter, u16 vlan)
iavf_vlan_filter *iavf_find_vlan(struct iavf_adapter *adapter,
struct iavf_vlan vlan)
{
struct iavf_vlan_filter *f;
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
if (vlan == f->vlan)
if (f->vlan.vid == vlan.vid &&
f->vlan.tpid == vlan.tpid)
return f;
}
return NULL;
}
......@@ -665,7 +668,8 @@ iavf_vlan_filter *iavf_find_vlan(struct iavf_adapter *adapter, u16 vlan)
* Returns ptr to the filter object or NULL when no memory available.
**/
static struct
iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, u16 vlan)
iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter,
struct iavf_vlan vlan)
{
struct iavf_vlan_filter *f = NULL;
......@@ -694,7 +698,7 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, u16 vlan)
* @adapter: board private structure
* @vlan: VLAN tag
**/
static void iavf_del_vlan(struct iavf_adapter *adapter, u16 vlan)
static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)
{
struct iavf_vlan_filter *f;
......@@ -720,8 +724,55 @@ static void iavf_restore_filters(struct iavf_adapter *adapter)
u16 vid;
/* re-add all VLAN filters */
for_each_set_bit(vid, adapter->vsi.active_vlans, VLAN_N_VID)
iavf_add_vlan(adapter, vid);
for_each_set_bit(vid, adapter->vsi.active_cvlans, VLAN_N_VID)
iavf_add_vlan(adapter, IAVF_VLAN(vid, ETH_P_8021Q));
for_each_set_bit(vid, adapter->vsi.active_svlans, VLAN_N_VID)
iavf_add_vlan(adapter, IAVF_VLAN(vid, ETH_P_8021AD));
}
/**
* iavf_get_num_vlans_added - get number of VLANs added
* @adapter: board private structure
*/
static u16 iavf_get_num_vlans_added(struct iavf_adapter *adapter)
{
return bitmap_weight(adapter->vsi.active_cvlans, VLAN_N_VID) +
bitmap_weight(adapter->vsi.active_svlans, VLAN_N_VID);
}
/**
* iavf_get_max_vlans_allowed - get maximum VLANs allowed for this VF
* @adapter: board private structure
*
* This depends on the negotiated VLAN capability. For VIRTCHNL_VF_OFFLOAD_VLAN,
* do not impose a limit as that maintains current behavior and for
* VIRTCHNL_VF_OFFLOAD_VLAN_V2, use the maximum allowed sent from the PF.
**/
static u16 iavf_get_max_vlans_allowed(struct iavf_adapter *adapter)
{
/* don't impose any limit for VIRTCHNL_VF_OFFLOAD_VLAN since there has
* never been a limit on the VF driver side
*/
if (VLAN_ALLOWED(adapter))
return VLAN_N_VID;
else if (VLAN_V2_ALLOWED(adapter))
return adapter->vlan_v2_caps.filtering.max_filters;
return 0;
}
/**
* iavf_max_vlans_added - check if maximum VLANs allowed already exist
* @adapter: board private structure
**/
static bool iavf_max_vlans_added(struct iavf_adapter *adapter)
{
if (iavf_get_num_vlans_added(adapter) <
iavf_get_max_vlans_allowed(adapter))
return false;
return true;
}
/**
......@@ -735,13 +786,23 @@ static int iavf_vlan_rx_add_vid(struct net_device *netdev,
{
struct iavf_adapter *adapter = netdev_priv(netdev);
if (!VLAN_ALLOWED(adapter))
if (!VLAN_FILTERING_ALLOWED(adapter))
return -EIO;
if (iavf_max_vlans_added(adapter)) {
netdev_err(netdev, "Max allowed VLAN filters %u. Remove existing VLANs or disable filtering via Ethtool if supported.\n",
iavf_get_max_vlans_allowed(adapter));
return -EIO;
}
if (iavf_add_vlan(adapter, vid) == NULL)
if (!iavf_add_vlan(adapter, IAVF_VLAN(vid, be16_to_cpu(proto))))
return -ENOMEM;
set_bit(vid, adapter->vsi.active_vlans);
if (proto == cpu_to_be16(ETH_P_8021Q))
set_bit(vid, adapter->vsi.active_cvlans);
else
set_bit(vid, adapter->vsi.active_svlans);
return 0;
}
......@@ -756,8 +817,11 @@ static int iavf_vlan_rx_kill_vid(struct net_device *netdev,
{
struct iavf_adapter *adapter = netdev_priv(netdev);
iavf_del_vlan(adapter, vid);
clear_bit(vid, adapter->vsi.active_vlans);
iavf_del_vlan(adapter, IAVF_VLAN(vid, be16_to_cpu(proto)));
if (proto == cpu_to_be16(ETH_P_8021Q))
clear_bit(vid, adapter->vsi.active_cvlans);
else
clear_bit(vid, adapter->vsi.active_svlans);
return 0;
}
......@@ -1151,6 +1215,86 @@ static void iavf_free_queues(struct iavf_adapter *adapter)
adapter->rx_rings = NULL;
}
/**
* iavf_set_queue_vlan_tag_loc - set location for VLAN tag offload
* @adapter: board private structure
*
* Based on negotiated capabilities, the VLAN tag needs to be inserted and/or
* stripped in certain descriptor fields. Instead of checking the offload
* capability bits in the hot path, cache the location the ring specific
* flags.
*/
void iavf_set_queue_vlan_tag_loc(struct iavf_adapter *adapter)
{
int i;
for (i = 0; i < adapter->num_active_queues; i++) {
struct iavf_ring *tx_ring = &adapter->tx_rings[i];
struct iavf_ring *rx_ring = &adapter->rx_rings[i];
/* prevent multiple L2TAG bits being set after VFR */
tx_ring->flags &=
~(IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1 |
IAVF_TXR_FLAGS_VLAN_TAG_LOC_L2TAG2);
rx_ring->flags &=
~(IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1 |
IAVF_RXR_FLAGS_VLAN_TAG_LOC_L2TAG2_2);
if (VLAN_ALLOWED(adapter)) {
tx_ring->flags |= IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1;
rx_ring->flags |= IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1;
} else if (VLAN_V2_ALLOWED(adapter)) {
struct virtchnl_vlan_supported_caps *stripping_support;
struct virtchnl_vlan_supported_caps *insertion_support;
stripping_support =
&adapter->vlan_v2_caps.offloads.stripping_support;
insertion_support =
&adapter->vlan_v2_caps.offloads.insertion_support;
if (stripping_support->outer) {
if (stripping_support->outer &
VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1)
rx_ring->flags |=
IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1;
else if (stripping_support->outer &
VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2)
rx_ring->flags |=
IAVF_RXR_FLAGS_VLAN_TAG_LOC_L2TAG2_2;
} else if (stripping_support->inner) {
if (stripping_support->inner &
VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1)
rx_ring->flags |=
IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1;
else if (stripping_support->inner &
VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2)
rx_ring->flags |=
IAVF_RXR_FLAGS_VLAN_TAG_LOC_L2TAG2_2;
}
if (insertion_support->outer) {
if (insertion_support->outer &
VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1)
tx_ring->flags |=
IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1;
else if (insertion_support->outer &
VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2)
tx_ring->flags |=
IAVF_TXR_FLAGS_VLAN_TAG_LOC_L2TAG2;
} else if (insertion_support->inner) {
if (insertion_support->inner &
VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1)
tx_ring->flags |=
IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1;
else if (insertion_support->inner &
VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2)
tx_ring->flags |=
IAVF_TXR_FLAGS_VLAN_TAG_LOC_L2TAG2;
}
}
}
}
/**
* iavf_alloc_queues - Allocate memory for all rings
* @adapter: board private structure to initialize
......@@ -1212,6 +1356,8 @@ static int iavf_alloc_queues(struct iavf_adapter *adapter)
adapter->num_active_queues = num_active_queues;
iavf_set_queue_vlan_tag_loc(adapter);
return 0;
err_out:
......@@ -1584,6 +1730,8 @@ static int iavf_process_aq_command(struct iavf_adapter *adapter)
{
if (adapter->aq_required & IAVF_FLAG_AQ_GET_CONFIG)
return iavf_send_vf_config_msg(adapter);
if (adapter->aq_required & IAVF_FLAG_AQ_GET_OFFLOAD_VLAN_V2_CAPS)
return iavf_send_vf_offload_vlan_v2_msg(adapter);
if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_QUEUES) {
iavf_disable_queues(adapter);
return 0;
......@@ -1717,6 +1865,39 @@ static int iavf_process_aq_command(struct iavf_adapter *adapter)
iavf_del_adv_rss_cfg(adapter);
return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_STRIPPING) {
iavf_disable_vlan_stripping_v2(adapter, ETH_P_8021Q);
return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_STAG_VLAN_STRIPPING) {
iavf_disable_vlan_stripping_v2(adapter, ETH_P_8021AD);
return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_STRIPPING) {
iavf_enable_vlan_stripping_v2(adapter, ETH_P_8021Q);
return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_STAG_VLAN_STRIPPING) {
iavf_enable_vlan_stripping_v2(adapter, ETH_P_8021AD);
return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_INSERTION) {
iavf_disable_vlan_insertion_v2(adapter, ETH_P_8021Q);
return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_STAG_VLAN_INSERTION) {
iavf_disable_vlan_insertion_v2(adapter, ETH_P_8021AD);
return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_INSERTION) {
iavf_enable_vlan_insertion_v2(adapter, ETH_P_8021Q);
return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_STAG_VLAN_INSERTION) {
iavf_enable_vlan_insertion_v2(adapter, ETH_P_8021AD);
return 0;
}
if (adapter->aq_required & IAVF_FLAG_AQ_REQUEST_STATS) {
iavf_request_stats(adapter);
return 0;
......@@ -1725,6 +1906,91 @@ static int iavf_process_aq_command(struct iavf_adapter *adapter)
return -EAGAIN;
}
/**
* iavf_set_vlan_offload_features - set VLAN offload configuration
* @adapter: board private structure
* @prev_features: previous features used for comparison
* @features: updated features used for configuration
*
* Set the aq_required bit(s) based on the requested features passed in to
* configure VLAN stripping and/or VLAN insertion if supported. Also, schedule
* the watchdog if any changes are requested to expedite the request via
* virtchnl.
**/
void
iavf_set_vlan_offload_features(struct iavf_adapter *adapter,
netdev_features_t prev_features,
netdev_features_t features)
{
bool enable_stripping = true, enable_insertion = true;
u16 vlan_ethertype = 0;
u64 aq_required = 0;
/* keep cases separate because one ethertype for offloads can be
* disabled at the same time as another is disabled, so check for an
* enabled ethertype first, then check for disabled. Default to
* ETH_P_8021Q so an ethertype is specified if disabling insertion and
* stripping.
*/
if (features & (NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX))
vlan_ethertype = ETH_P_8021AD;
else if (features & (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX))
vlan_ethertype = ETH_P_8021Q;
else if (prev_features & (NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX))
vlan_ethertype = ETH_P_8021AD;
else if (prev_features & (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX))
vlan_ethertype = ETH_P_8021Q;
else
vlan_ethertype = ETH_P_8021Q;
if (!(features & (NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_CTAG_RX)))
enable_stripping = false;
if (!(features & (NETIF_F_HW_VLAN_STAG_TX | NETIF_F_HW_VLAN_CTAG_TX)))
enable_insertion = false;
if (VLAN_ALLOWED(adapter)) {
/* VIRTCHNL_VF_OFFLOAD_VLAN only has support for toggling VLAN
* stripping via virtchnl. VLAN insertion can be toggled on the
* netdev, but it doesn't require a virtchnl message
*/
if (enable_stripping)
aq_required |= IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING;
else
aq_required |= IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING;
} else if (VLAN_V2_ALLOWED(adapter)) {
switch (vlan_ethertype) {
case ETH_P_8021Q:
if (enable_stripping)
aq_required |= IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_STRIPPING;
else
aq_required |= IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_STRIPPING;
if (enable_insertion)
aq_required |= IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_INSERTION;
else
aq_required |= IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_INSERTION;
break;
case ETH_P_8021AD:
if (enable_stripping)
aq_required |= IAVF_FLAG_AQ_ENABLE_STAG_VLAN_STRIPPING;
else
aq_required |= IAVF_FLAG_AQ_DISABLE_STAG_VLAN_STRIPPING;
if (enable_insertion)
aq_required |= IAVF_FLAG_AQ_ENABLE_STAG_VLAN_INSERTION;
else
aq_required |= IAVF_FLAG_AQ_DISABLE_STAG_VLAN_INSERTION;
break;
}
}
if (aq_required) {
adapter->aq_required |= aq_required;
mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0);
}
}
/**
* iavf_startup - first step of driver startup
* @adapter: board private structure
......@@ -1826,6 +2092,59 @@ static void iavf_init_version_check(struct iavf_adapter *adapter)
iavf_change_state(adapter, __IAVF_INIT_FAILED);
}
/**
* iavf_parse_vf_resource_msg - parse response from VIRTCHNL_OP_GET_VF_RESOURCES
* @adapter: board private structure
*/
int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter)
{
int i, num_req_queues = adapter->num_req_queues;
struct iavf_vsi *vsi = &adapter->vsi;
for (i = 0; i < adapter->vf_res->num_vsis; i++) {
if (adapter->vf_res->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
adapter->vsi_res = &adapter->vf_res->vsi_res[i];
}
if (!adapter->vsi_res) {
dev_err(&adapter->pdev->dev, "No LAN VSI found\n");
return -ENODEV;
}
if (num_req_queues &&
num_req_queues > adapter->vsi_res->num_queue_pairs) {
/* Problem. The PF gave us fewer queues than what we had
* negotiated in our request. Need a reset to see if we can't
* get back to a working state.
*/
dev_err(&adapter->pdev->dev,
"Requested %d queues, but PF only gave us %d.\n",
num_req_queues,
adapter->vsi_res->num_queue_pairs);
adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
adapter->num_req_queues = adapter->vsi_res->num_queue_pairs;
iavf_schedule_reset(adapter);
return -EAGAIN;
}
adapter->num_req_queues = 0;
adapter->vsi.id = adapter->vsi_res->vsi_id;
adapter->vsi.back = adapter;
adapter->vsi.base_vector = 1;
adapter->vsi.work_limit = IAVF_DEFAULT_IRQ_WORK;
vsi->netdev = adapter->netdev;
vsi->qs_handle = adapter->vsi_res->qset_handle;
if (adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
adapter->rss_key_size = adapter->vf_res->rss_key_size;
adapter->rss_lut_size = adapter->vf_res->rss_lut_size;
} else {
adapter->rss_key_size = IAVF_HKEY_ARRAY_SIZE;
adapter->rss_lut_size = IAVF_HLUT_ARRAY_SIZE;
}
return 0;
}
/**
* iavf_init_get_resources - third step of driver startup
* @adapter: board private structure
......@@ -1837,7 +2156,6 @@ static void iavf_init_version_check(struct iavf_adapter *adapter)
**/
static void iavf_init_get_resources(struct iavf_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
struct iavf_hw *hw = &adapter->hw;
int err;
......@@ -1855,7 +2173,7 @@ static void iavf_init_get_resources(struct iavf_adapter *adapter)
err = iavf_get_vf_config(adapter);
if (err == IAVF_ERR_ADMIN_QUEUE_NO_WORK) {
err = iavf_send_vf_config_msg(adapter);
goto err;
goto err_alloc;
} else if (err == IAVF_ERR_PARAM) {
/* We only get ERR_PARAM if the device is in a very bad
* state or if we've been disabled for previous bad
......@@ -1870,9 +2188,83 @@ static void iavf_init_get_resources(struct iavf_adapter *adapter)
goto err_alloc;
}
err = iavf_process_config(adapter);
err = iavf_parse_vf_resource_msg(adapter);
if (err)
goto err_alloc;
err = iavf_send_vf_offload_vlan_v2_msg(adapter);
if (err == -EOPNOTSUPP) {
/* underlying PF doesn't support VIRTCHNL_VF_OFFLOAD_VLAN_V2, so
* go directly to finishing initialization
*/
iavf_change_state(adapter, __IAVF_INIT_CONFIG_ADAPTER);
return;
} else if (err) {
dev_err(&pdev->dev, "Unable to send offload vlan v2 request (%d)\n",
err);
goto err_alloc;
}
/* underlying PF supports VIRTCHNL_VF_OFFLOAD_VLAN_V2, so update the
* state accordingly
*/
iavf_change_state(adapter, __IAVF_INIT_GET_OFFLOAD_VLAN_V2_CAPS);
return;
err_alloc:
kfree(adapter->vf_res);
adapter->vf_res = NULL;
err:
iavf_change_state(adapter, __IAVF_INIT_FAILED);
}
/**
* iavf_init_get_offload_vlan_v2_caps - part of driver startup
* @adapter: board private structure
*
* Function processes __IAVF_INIT_GET_OFFLOAD_VLAN_V2_CAPS driver state if the
* VF negotiates VIRTCHNL_VF_OFFLOAD_VLAN_V2. If VIRTCHNL_VF_OFFLOAD_VLAN_V2 is
* not negotiated, then this state will never be entered.
**/
static void iavf_init_get_offload_vlan_v2_caps(struct iavf_adapter *adapter)
{
int ret;
WARN_ON(adapter->state != __IAVF_INIT_GET_OFFLOAD_VLAN_V2_CAPS);
memset(&adapter->vlan_v2_caps, 0, sizeof(adapter->vlan_v2_caps));
ret = iavf_get_vf_vlan_v2_caps(adapter);
if (ret) {
if (ret == IAVF_ERR_ADMIN_QUEUE_NO_WORK)
iavf_send_vf_offload_vlan_v2_msg(adapter);
goto err;
}
iavf_change_state(adapter, __IAVF_INIT_CONFIG_ADAPTER);
return;
err:
iavf_change_state(adapter, __IAVF_INIT_FAILED);
}
/**
* iavf_init_config_adapter - last part of driver startup
* @adapter: board private structure
*
* After all the supported capabilities are negotiated, then the
* __IAVF_INIT_CONFIG_ADAPTER state will finish driver initialization.
*/
static void iavf_init_config_adapter(struct iavf_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
int err;
WARN_ON(adapter->state != __IAVF_INIT_CONFIG_ADAPTER);
if (iavf_process_config(adapter))
goto err;
adapter->current_op = VIRTCHNL_OP_UNKNOWN;
adapter->flags |= IAVF_FLAG_RX_CSUM_ENABLED;
......@@ -1955,6 +2347,10 @@ static void iavf_init_get_resources(struct iavf_adapter *adapter)
else
iavf_init_rss(adapter);
if (VLAN_V2_ALLOWED(adapter))
/* request initial VLAN offload settings */
iavf_set_vlan_offload_features(adapter, 0, netdev->features);
return;
err_mem:
iavf_free_rss(adapter);
......@@ -1962,9 +2358,6 @@ static void iavf_init_get_resources(struct iavf_adapter *adapter)
iavf_free_misc_irq(adapter);
err_sw_init:
iavf_reset_interrupt_capability(adapter);
err_alloc:
kfree(adapter->vf_res);
adapter->vf_res = NULL;
err:
iavf_change_state(adapter, __IAVF_INIT_FAILED);
}
......@@ -2013,6 +2406,18 @@ static void iavf_watchdog_task(struct work_struct *work)
queue_delayed_work(iavf_wq, &adapter->watchdog_task,
msecs_to_jiffies(1));
return;
case __IAVF_INIT_GET_OFFLOAD_VLAN_V2_CAPS:
iavf_init_get_offload_vlan_v2_caps(adapter);
mutex_unlock(&adapter->crit_lock);
queue_delayed_work(iavf_wq, &adapter->watchdog_task,
msecs_to_jiffies(1));
return;
case __IAVF_INIT_CONFIG_ADAPTER:
iavf_init_config_adapter(adapter);
mutex_unlock(&adapter->crit_lock);
queue_delayed_work(iavf_wq, &adapter->watchdog_task,
msecs_to_jiffies(1));
return;
case __IAVF_INIT_FAILED:
if (++adapter->aq_wait_count > IAVF_AQ_MAX_ERR) {
dev_err(&adapter->pdev->dev,
......@@ -2066,10 +2471,13 @@ static void iavf_watchdog_task(struct work_struct *work)
iavf_send_api_ver(adapter);
}
} else {
int ret = iavf_process_aq_command(adapter);
/* An error will be returned if no commands were
* processed; use this opportunity to update stats
* if the error isn't -ENOTSUPP
*/
if (iavf_process_aq_command(adapter) &&
if (ret && ret != -EOPNOTSUPP &&
adapter->state == __IAVF_RUNNING)
iavf_request_stats(adapter);
}
......@@ -2308,6 +2716,13 @@ static void iavf_reset_task(struct work_struct *work)
}
adapter->aq_required |= IAVF_FLAG_AQ_GET_CONFIG;
/* always set since VIRTCHNL_OP_GET_VF_RESOURCES has not been
* sent/received yet, so VLAN_V2_ALLOWED() cannot is not reliable here,
* however the VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS won't be sent until
* VIRTCHNL_OP_GET_VF_RESOURCES and VIRTCHNL_VF_OFFLOAD_VLAN_V2 have
* been successfully sent and negotiated
*/
adapter->aq_required |= IAVF_FLAG_AQ_GET_OFFLOAD_VLAN_V2_CAPS;
adapter->aq_required |= IAVF_FLAG_AQ_MAP_VECTORS;
spin_lock_bh(&adapter->mac_vlan_list_lock);
......@@ -3441,6 +3856,11 @@ static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
return 0;
}
#define NETIF_VLAN_OFFLOAD_FEATURES (NETIF_F_HW_VLAN_CTAG_RX | \
NETIF_F_HW_VLAN_CTAG_TX | \
NETIF_F_HW_VLAN_STAG_RX | \
NETIF_F_HW_VLAN_STAG_TX)
/**
* iavf_set_features - set the netdev feature flags
* @netdev: ptr to the netdev being adjusted
......@@ -3452,25 +3872,11 @@ static int iavf_set_features(struct net_device *netdev,
{
struct iavf_adapter *adapter = netdev_priv(netdev);
/* Don't allow enabling VLAN features when adapter is not capable
* of VLAN offload/filtering
*/
if (!VLAN_ALLOWED(adapter)) {
netdev->hw_features &= ~(NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_FILTER);
if (features & (NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_FILTER))
return -EINVAL;
} else if ((netdev->features ^ features) & NETIF_F_HW_VLAN_CTAG_RX) {
if (features & NETIF_F_HW_VLAN_CTAG_RX)
adapter->aq_required |=
IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING;
else
adapter->aq_required |=
IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING;
}
/* trigger update on any VLAN feature change */
if ((netdev->features & NETIF_VLAN_OFFLOAD_FEATURES) ^
(features & NETIF_VLAN_OFFLOAD_FEATURES))
iavf_set_vlan_offload_features(adapter, netdev->features,
features);
return 0;
}
......@@ -3533,6 +3939,228 @@ static netdev_features_t iavf_features_check(struct sk_buff *skb,
return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
}
/**
* iavf_get_netdev_vlan_hw_features - get NETDEV VLAN features that can toggle on/off
* @adapter: board private structure
*
* Depending on whether VIRTHCNL_VF_OFFLOAD_VLAN or VIRTCHNL_VF_OFFLOAD_VLAN_V2
* were negotiated determine the VLAN features that can be toggled on and off.
**/
static netdev_features_t
iavf_get_netdev_vlan_hw_features(struct iavf_adapter *adapter)
{
netdev_features_t hw_features = 0;
if (!adapter->vf_res || !adapter->vf_res->vf_cap_flags)
return hw_features;
/* Enable VLAN features if supported */
if (VLAN_ALLOWED(adapter)) {
hw_features |= (NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_RX);
} else if (VLAN_V2_ALLOWED(adapter)) {
struct virtchnl_vlan_caps *vlan_v2_caps =
&adapter->vlan_v2_caps;
struct virtchnl_vlan_supported_caps *stripping_support =
&vlan_v2_caps->offloads.stripping_support;
struct virtchnl_vlan_supported_caps *insertion_support =
&vlan_v2_caps->offloads.insertion_support;
if (stripping_support->outer != VIRTCHNL_VLAN_UNSUPPORTED &&
stripping_support->outer & VIRTCHNL_VLAN_TOGGLE) {
if (stripping_support->outer &
VIRTCHNL_VLAN_ETHERTYPE_8100)
hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
if (stripping_support->outer &
VIRTCHNL_VLAN_ETHERTYPE_88A8)
hw_features |= NETIF_F_HW_VLAN_STAG_RX;
} else if (stripping_support->inner !=
VIRTCHNL_VLAN_UNSUPPORTED &&
stripping_support->inner & VIRTCHNL_VLAN_TOGGLE) {
if (stripping_support->inner &
VIRTCHNL_VLAN_ETHERTYPE_8100)
hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
}
if (insertion_support->outer != VIRTCHNL_VLAN_UNSUPPORTED &&
insertion_support->outer & VIRTCHNL_VLAN_TOGGLE) {
if (insertion_support->outer &
VIRTCHNL_VLAN_ETHERTYPE_8100)
hw_features |= NETIF_F_HW_VLAN_CTAG_TX;
if (insertion_support->outer &
VIRTCHNL_VLAN_ETHERTYPE_88A8)
hw_features |= NETIF_F_HW_VLAN_STAG_TX;
} else if (insertion_support->inner &&
insertion_support->inner & VIRTCHNL_VLAN_TOGGLE) {
if (insertion_support->inner &
VIRTCHNL_VLAN_ETHERTYPE_8100)
hw_features |= NETIF_F_HW_VLAN_CTAG_TX;
}
}
return hw_features;
}
/**
* iavf_get_netdev_vlan_features - get the enabled NETDEV VLAN fetures
* @adapter: board private structure
*
* Depending on whether VIRTHCNL_VF_OFFLOAD_VLAN or VIRTCHNL_VF_OFFLOAD_VLAN_V2
* were negotiated determine the VLAN features that are enabled by default.
**/
static netdev_features_t
iavf_get_netdev_vlan_features(struct iavf_adapter *adapter)
{
netdev_features_t features = 0;
if (!adapter->vf_res || !adapter->vf_res->vf_cap_flags)
return features;
if (VLAN_ALLOWED(adapter)) {
features |= NETIF_F_HW_VLAN_CTAG_FILTER |
NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX;
} else if (VLAN_V2_ALLOWED(adapter)) {
struct virtchnl_vlan_caps *vlan_v2_caps =
&adapter->vlan_v2_caps;
struct virtchnl_vlan_supported_caps *filtering_support =
&vlan_v2_caps->filtering.filtering_support;
struct virtchnl_vlan_supported_caps *stripping_support =
&vlan_v2_caps->offloads.stripping_support;
struct virtchnl_vlan_supported_caps *insertion_support =
&vlan_v2_caps->offloads.insertion_support;
u32 ethertype_init;
/* give priority to outer stripping and don't support both outer
* and inner stripping
*/
ethertype_init = vlan_v2_caps->offloads.ethertype_init;
if (stripping_support->outer != VIRTCHNL_VLAN_UNSUPPORTED) {
if (stripping_support->outer &
VIRTCHNL_VLAN_ETHERTYPE_8100 &&
ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100)
features |= NETIF_F_HW_VLAN_CTAG_RX;
else if (stripping_support->outer &
VIRTCHNL_VLAN_ETHERTYPE_88A8 &&
ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_88A8)
features |= NETIF_F_HW_VLAN_STAG_RX;
} else if (stripping_support->inner !=
VIRTCHNL_VLAN_UNSUPPORTED) {
if (stripping_support->inner &
VIRTCHNL_VLAN_ETHERTYPE_8100 &&
ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100)
features |= NETIF_F_HW_VLAN_CTAG_RX;
}
/* give priority to outer insertion and don't support both outer
* and inner insertion
*/
if (insertion_support->outer != VIRTCHNL_VLAN_UNSUPPORTED) {
if (insertion_support->outer &
VIRTCHNL_VLAN_ETHERTYPE_8100 &&
ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100)
features |= NETIF_F_HW_VLAN_CTAG_TX;
else if (insertion_support->outer &
VIRTCHNL_VLAN_ETHERTYPE_88A8 &&
ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_88A8)
features |= NETIF_F_HW_VLAN_STAG_TX;
} else if (insertion_support->inner !=
VIRTCHNL_VLAN_UNSUPPORTED) {
if (insertion_support->inner &
VIRTCHNL_VLAN_ETHERTYPE_8100 &&
ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100)
features |= NETIF_F_HW_VLAN_CTAG_TX;
}
/* give priority to outer filtering and don't bother if both
* outer and inner filtering are enabled
*/
ethertype_init = vlan_v2_caps->filtering.ethertype_init;
if (filtering_support->outer != VIRTCHNL_VLAN_UNSUPPORTED) {
if (filtering_support->outer &
VIRTCHNL_VLAN_ETHERTYPE_8100 &&
ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100)
features |= NETIF_F_HW_VLAN_CTAG_FILTER;
if (filtering_support->outer &
VIRTCHNL_VLAN_ETHERTYPE_88A8 &&
ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_88A8)
features |= NETIF_F_HW_VLAN_STAG_FILTER;
} else if (filtering_support->inner !=
VIRTCHNL_VLAN_UNSUPPORTED) {
if (filtering_support->inner &
VIRTCHNL_VLAN_ETHERTYPE_8100 &&
ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_8100)
features |= NETIF_F_HW_VLAN_CTAG_FILTER;
if (filtering_support->inner &
VIRTCHNL_VLAN_ETHERTYPE_88A8 &&
ethertype_init & VIRTCHNL_VLAN_ETHERTYPE_88A8)
features |= NETIF_F_HW_VLAN_STAG_FILTER;
}
}
return features;
}
#define IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested, allowed, feature_bit) \
(!(((requested) & (feature_bit)) && \
!((allowed) & (feature_bit))))
/**
* iavf_fix_netdev_vlan_features - fix NETDEV VLAN features based on support
* @adapter: board private structure
* @requested_features: stack requested NETDEV features
**/
static netdev_features_t
iavf_fix_netdev_vlan_features(struct iavf_adapter *adapter,
netdev_features_t requested_features)
{
netdev_features_t allowed_features;
allowed_features = iavf_get_netdev_vlan_hw_features(adapter) |
iavf_get_netdev_vlan_features(adapter);
if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features,
allowed_features,
NETIF_F_HW_VLAN_CTAG_TX))
requested_features &= ~NETIF_F_HW_VLAN_CTAG_TX;
if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features,
allowed_features,
NETIF_F_HW_VLAN_CTAG_RX))
requested_features &= ~NETIF_F_HW_VLAN_CTAG_RX;
if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features,
allowed_features,
NETIF_F_HW_VLAN_STAG_TX))
requested_features &= ~NETIF_F_HW_VLAN_STAG_TX;
if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features,
allowed_features,
NETIF_F_HW_VLAN_STAG_RX))
requested_features &= ~NETIF_F_HW_VLAN_STAG_RX;
if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features,
allowed_features,
NETIF_F_HW_VLAN_CTAG_FILTER))
requested_features &= ~NETIF_F_HW_VLAN_CTAG_FILTER;
if (!IAVF_NETDEV_VLAN_FEATURE_ALLOWED(requested_features,
allowed_features,
NETIF_F_HW_VLAN_STAG_FILTER))
requested_features &= ~NETIF_F_HW_VLAN_STAG_FILTER;
if ((requested_features &
(NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX)) &&
(requested_features &
(NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX)) &&
adapter->vlan_v2_caps.offloads.ethertype_match ==
VIRTCHNL_ETHERTYPE_STRIPPING_MATCHES_INSERTION) {
netdev_warn(adapter->netdev, "cannot support CTAG and STAG VLAN stripping and/or insertion simultaneously since CTAG and STAG offloads are mutually exclusive, clearing STAG offload settings\n");
requested_features &= ~(NETIF_F_HW_VLAN_STAG_RX |
NETIF_F_HW_VLAN_STAG_TX);
}
return requested_features;
}
/**
* iavf_fix_features - fix up the netdev feature bits
* @netdev: our net device
......@@ -3545,13 +4173,7 @@ static netdev_features_t iavf_fix_features(struct net_device *netdev,
{
struct iavf_adapter *adapter = netdev_priv(netdev);
if (adapter->vf_res &&
!(adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN))
features &= ~(NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_FILTER);
return features;
return iavf_fix_netdev_vlan_features(adapter, features);
}
static const struct net_device_ops iavf_netdev_ops = {
......@@ -3603,39 +4225,11 @@ static int iavf_check_reset_complete(struct iavf_hw *hw)
int iavf_process_config(struct iavf_adapter *adapter)
{
struct virtchnl_vf_resource *vfres = adapter->vf_res;
int i, num_req_queues = adapter->num_req_queues;
netdev_features_t hw_vlan_features, vlan_features;
struct net_device *netdev = adapter->netdev;
struct iavf_vsi *vsi = &adapter->vsi;
netdev_features_t hw_enc_features;
netdev_features_t hw_features;
/* got VF config message back from PF, now we can parse it */
for (i = 0; i < vfres->num_vsis; i++) {
if (vfres->vsi_res[i].vsi_type == VIRTCHNL_VSI_SRIOV)
adapter->vsi_res = &vfres->vsi_res[i];
}
if (!adapter->vsi_res) {
dev_err(&adapter->pdev->dev, "No LAN VSI found\n");
return -ENODEV;
}
if (num_req_queues &&
num_req_queues > adapter->vsi_res->num_queue_pairs) {
/* Problem. The PF gave us fewer queues than what we had
* negotiated in our request. Need a reset to see if we can't
* get back to a working state.
*/
dev_err(&adapter->pdev->dev,
"Requested %d queues, but PF only gave us %d.\n",
num_req_queues,
adapter->vsi_res->num_queue_pairs);
adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
adapter->num_req_queues = adapter->vsi_res->num_queue_pairs;
iavf_schedule_reset(adapter);
return -ENODEV;
}
adapter->num_req_queues = 0;
hw_enc_features = NETIF_F_SG |
NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM |
......@@ -3679,19 +4273,19 @@ int iavf_process_config(struct iavf_adapter *adapter)
*/
hw_features = hw_enc_features;
/* Enable VLAN features if supported */
if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN)
hw_features |= (NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_RX);
/* get HW VLAN features that can be toggled */
hw_vlan_features = iavf_get_netdev_vlan_hw_features(adapter);
/* Enable cloud filter if ADQ is supported */
if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ)
hw_features |= NETIF_F_HW_TC;
if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_USO)
hw_features |= NETIF_F_GSO_UDP_L4;
netdev->hw_features |= hw_features;
netdev->hw_features |= hw_features | hw_vlan_features;
vlan_features = iavf_get_netdev_vlan_features(adapter);
netdev->features |= hw_features;
netdev->features |= hw_features | vlan_features;
if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN)
netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
......@@ -3716,21 +4310,6 @@ int iavf_process_config(struct iavf_adapter *adapter)
netdev->features &= ~NETIF_F_GSO;
}
adapter->vsi.id = adapter->vsi_res->vsi_id;
adapter->vsi.back = adapter;
adapter->vsi.base_vector = 1;
adapter->vsi.work_limit = IAVF_DEFAULT_IRQ_WORK;
vsi->netdev = adapter->netdev;
vsi->qs_handle = adapter->vsi_res->qset_handle;
if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
adapter->rss_key_size = vfres->rss_key_size;
adapter->rss_lut_size = vfres->rss_lut_size;
} else {
adapter->rss_key_size = IAVF_HKEY_ARRAY_SIZE;
adapter->rss_lut_size = IAVF_HLUT_ARRAY_SIZE;
}
return 0;
}
......
......@@ -865,6 +865,9 @@ static void iavf_receive_skb(struct iavf_ring *rx_ring,
if ((rx_ring->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
(vlan_tag & VLAN_VID_MASK))
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
else if ((rx_ring->netdev->features & NETIF_F_HW_VLAN_STAG_RX) &&
vlan_tag & VLAN_VID_MASK)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021AD), vlan_tag);
napi_gro_receive(&q_vector->napi, skb);
}
......@@ -1468,7 +1471,7 @@ static int iavf_clean_rx_irq(struct iavf_ring *rx_ring, int budget)
struct iavf_rx_buffer *rx_buffer;
union iavf_rx_desc *rx_desc;
unsigned int size;
u16 vlan_tag;
u16 vlan_tag = 0;
u8 rx_ptype;
u64 qword;
......@@ -1551,9 +1554,13 @@ static int iavf_clean_rx_irq(struct iavf_ring *rx_ring, int budget)
/* populate checksum, VLAN, and protocol */
iavf_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype);
vlan_tag = (qword & BIT(IAVF_RX_DESC_STATUS_L2TAG1P_SHIFT)) ?
le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0;
if (qword & BIT(IAVF_RX_DESC_STATUS_L2TAG1P_SHIFT) &&
rx_ring->flags & IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1)
vlan_tag = le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1);
if (rx_desc->wb.qword2.ext_status &
cpu_to_le16(BIT(IAVF_RX_DESC_EXT_STATUS_L2TAG2P_SHIFT)) &&
rx_ring->flags & IAVF_RXR_FLAGS_VLAN_TAG_LOC_L2TAG2_2)
vlan_tag = le16_to_cpu(rx_desc->wb.qword2.l2tag2_2);
iavf_trace(clean_rx_irq_rx, rx_ring, rx_desc, skb);
iavf_receive_skb(rx_ring, skb, vlan_tag);
......@@ -1781,46 +1788,29 @@ int iavf_napi_poll(struct napi_struct *napi, int budget)
* Returns error code indicate the frame should be dropped upon error and the
* otherwise returns 0 to indicate the flags has been set properly.
**/
static inline int iavf_tx_prepare_vlan_flags(struct sk_buff *skb,
struct iavf_ring *tx_ring,
u32 *flags)
static void iavf_tx_prepare_vlan_flags(struct sk_buff *skb,
struct iavf_ring *tx_ring, u32 *flags)
{
__be16 protocol = skb->protocol;
u32 tx_flags = 0;
if (protocol == htons(ETH_P_8021Q) &&
!(tx_ring->netdev->features & NETIF_F_HW_VLAN_CTAG_TX)) {
/* When HW VLAN acceleration is turned off by the user the
* stack sets the protocol to 8021q so that the driver
* can take any steps required to support the SW only
* VLAN handling. In our case the driver doesn't need
* to take any further steps so just set the protocol
* to the encapsulated ethertype.
*/
skb->protocol = vlan_get_protocol(skb);
goto out;
}
/* if we have a HW VLAN tag being added, default to the HW one */
if (skb_vlan_tag_present(skb)) {
tx_flags |= skb_vlan_tag_get(skb) << IAVF_TX_FLAGS_VLAN_SHIFT;
tx_flags |= IAVF_TX_FLAGS_HW_VLAN;
/* else if it is a SW VLAN, check the next protocol and store the tag */
} else if (protocol == htons(ETH_P_8021Q)) {
struct vlan_hdr *vhdr, _vhdr;
vhdr = skb_header_pointer(skb, ETH_HLEN, sizeof(_vhdr), &_vhdr);
if (!vhdr)
return -EINVAL;
/* stack will only request hardware VLAN insertion offload for protocols
* that the driver supports and has enabled
*/
if (!skb_vlan_tag_present(skb))
return;
protocol = vhdr->h_vlan_encapsulated_proto;
tx_flags |= ntohs(vhdr->h_vlan_TCI) << IAVF_TX_FLAGS_VLAN_SHIFT;
tx_flags |= IAVF_TX_FLAGS_SW_VLAN;
tx_flags |= skb_vlan_tag_get(skb) << IAVF_TX_FLAGS_VLAN_SHIFT;
if (tx_ring->flags & IAVF_TXR_FLAGS_VLAN_TAG_LOC_L2TAG2) {
tx_flags |= IAVF_TX_FLAGS_HW_OUTER_SINGLE_VLAN;
} else if (tx_ring->flags & IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1) {
tx_flags |= IAVF_TX_FLAGS_HW_VLAN;
} else {
dev_dbg(tx_ring->dev, "Unsupported Tx VLAN tag location requested\n");
return;
}
out:
*flags = tx_flags;
return 0;
}
/**
......@@ -2440,8 +2430,13 @@ static netdev_tx_t iavf_xmit_frame_ring(struct sk_buff *skb,
first->gso_segs = 1;
/* prepare the xmit flags */
if (iavf_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags))
goto out_drop;
iavf_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags);
if (tx_flags & IAVF_TX_FLAGS_HW_OUTER_SINGLE_VLAN) {
cd_type_cmd_tso_mss |= IAVF_TX_CTX_DESC_IL2TAG2 <<
IAVF_TXD_CTX_QW1_CMD_SHIFT;
cd_l2tag2 = (tx_flags & IAVF_TX_FLAGS_VLAN_MASK) >>
IAVF_TX_FLAGS_VLAN_SHIFT;
}
/* obtain protocol of skb */
protocol = vlan_get_protocol(skb);
......
......@@ -243,19 +243,20 @@ static inline unsigned int iavf_txd_use_count(unsigned int size)
#define DESC_NEEDED (MAX_SKB_FRAGS + 6)
#define IAVF_MIN_DESC_PENDING 4
#define IAVF_TX_FLAGS_HW_VLAN BIT(1)
#define IAVF_TX_FLAGS_SW_VLAN BIT(2)
#define IAVF_TX_FLAGS_TSO BIT(3)
#define IAVF_TX_FLAGS_IPV4 BIT(4)
#define IAVF_TX_FLAGS_IPV6 BIT(5)
#define IAVF_TX_FLAGS_FCCRC BIT(6)
#define IAVF_TX_FLAGS_FSO BIT(7)
#define IAVF_TX_FLAGS_FD_SB BIT(9)
#define IAVF_TX_FLAGS_VXLAN_TUNNEL BIT(10)
#define IAVF_TX_FLAGS_VLAN_MASK 0xffff0000
#define IAVF_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000
#define IAVF_TX_FLAGS_VLAN_PRIO_SHIFT 29
#define IAVF_TX_FLAGS_VLAN_SHIFT 16
#define IAVF_TX_FLAGS_HW_VLAN BIT(1)
#define IAVF_TX_FLAGS_SW_VLAN BIT(2)
#define IAVF_TX_FLAGS_TSO BIT(3)
#define IAVF_TX_FLAGS_IPV4 BIT(4)
#define IAVF_TX_FLAGS_IPV6 BIT(5)
#define IAVF_TX_FLAGS_FCCRC BIT(6)
#define IAVF_TX_FLAGS_FSO BIT(7)
#define IAVF_TX_FLAGS_FD_SB BIT(9)
#define IAVF_TX_FLAGS_VXLAN_TUNNEL BIT(10)
#define IAVF_TX_FLAGS_HW_OUTER_SINGLE_VLAN BIT(11)
#define IAVF_TX_FLAGS_VLAN_MASK 0xffff0000
#define IAVF_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000
#define IAVF_TX_FLAGS_VLAN_PRIO_SHIFT 29
#define IAVF_TX_FLAGS_VLAN_SHIFT 16
struct iavf_tx_buffer {
struct iavf_tx_desc *next_to_watch;
......@@ -362,6 +363,9 @@ struct iavf_ring {
u16 flags;
#define IAVF_TXR_FLAGS_WB_ON_ITR BIT(0)
#define IAVF_RXR_FLAGS_BUILD_SKB_ENABLED BIT(1)
#define IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1 BIT(3)
#define IAVF_TXR_FLAGS_VLAN_TAG_LOC_L2TAG2 BIT(4)
#define IAVF_RXR_FLAGS_VLAN_TAG_LOC_L2TAG2_2 BIT(5)
/* stats structs */
struct iavf_queue_stats stats;
......
......@@ -137,6 +137,7 @@ int iavf_send_vf_config_msg(struct iavf_adapter *adapter)
VIRTCHNL_VF_OFFLOAD_WB_ON_ITR |
VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 |
VIRTCHNL_VF_OFFLOAD_ENCAP |
VIRTCHNL_VF_OFFLOAD_VLAN_V2 |
VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM |
VIRTCHNL_VF_OFFLOAD_REQ_QUEUES |
VIRTCHNL_VF_OFFLOAD_ADQ |
......@@ -155,6 +156,19 @@ int iavf_send_vf_config_msg(struct iavf_adapter *adapter)
NULL, 0);
}
int iavf_send_vf_offload_vlan_v2_msg(struct iavf_adapter *adapter)
{
adapter->aq_required &= ~IAVF_FLAG_AQ_GET_OFFLOAD_VLAN_V2_CAPS;
if (!VLAN_V2_ALLOWED(adapter))
return -EOPNOTSUPP;
adapter->current_op = VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS;
return iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS,
NULL, 0);
}
/**
* iavf_validate_num_queues
* @adapter: adapter structure
......@@ -235,6 +249,45 @@ int iavf_get_vf_config(struct iavf_adapter *adapter)
return err;
}
int iavf_get_vf_vlan_v2_caps(struct iavf_adapter *adapter)
{
struct iavf_hw *hw = &adapter->hw;
struct iavf_arq_event_info event;
enum virtchnl_ops op;
enum iavf_status err;
u16 len;
len = sizeof(struct virtchnl_vlan_caps);
event.buf_len = len;
event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL);
if (!event.msg_buf) {
err = -ENOMEM;
goto out;
}
while (1) {
/* When the AQ is empty, iavf_clean_arq_element will return
* nonzero and this loop will terminate.
*/
err = iavf_clean_arq_element(hw, &event, NULL);
if (err)
goto out_alloc;
op = (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high);
if (op == VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS)
break;
}
err = (enum iavf_status)le32_to_cpu(event.desc.cookie_low);
if (err)
goto out_alloc;
memcpy(&adapter->vlan_v2_caps, event.msg_buf, min(event.msg_len, len));
out_alloc:
kfree(event.msg_buf);
out:
return err;
}
/**
* iavf_configure_queues
* @adapter: adapter structure
......@@ -589,7 +642,6 @@ static void iavf_mac_add_reject(struct iavf_adapter *adapter)
**/
void iavf_add_vlans(struct iavf_adapter *adapter)
{
struct virtchnl_vlan_filter_list *vvfl;
int len, i = 0, count = 0;
struct iavf_vlan_filter *f;
bool more = false;
......@@ -607,48 +659,105 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
if (f->add)
count++;
}
if (!count || !VLAN_ALLOWED(adapter)) {
if (!count || !VLAN_FILTERING_ALLOWED(adapter)) {
adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_VLAN_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
return;
}
adapter->current_op = VIRTCHNL_OP_ADD_VLAN;
len = sizeof(struct virtchnl_vlan_filter_list) +
(count * sizeof(u16));
if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n");
count = (IAVF_MAX_AQ_BUF_SIZE -
sizeof(struct virtchnl_vlan_filter_list)) /
sizeof(u16);
len = sizeof(struct virtchnl_vlan_filter_list) +
(count * sizeof(u16));
more = true;
}
vvfl = kzalloc(len, GFP_ATOMIC);
if (!vvfl) {
if (VLAN_ALLOWED(adapter)) {
struct virtchnl_vlan_filter_list *vvfl;
adapter->current_op = VIRTCHNL_OP_ADD_VLAN;
len = sizeof(*vvfl) + (count * sizeof(u16));
if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n");
count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(*vvfl)) /
sizeof(u16);
len = sizeof(*vvfl) + (count * sizeof(u16));
more = true;
}
vvfl = kzalloc(len, GFP_ATOMIC);
if (!vvfl) {
spin_unlock_bh(&adapter->mac_vlan_list_lock);
return;
}
vvfl->vsi_id = adapter->vsi_res->vsi_id;
vvfl->num_elements = count;
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
if (f->add) {
vvfl->vlan_id[i] = f->vlan.vid;
i++;
f->add = false;
if (i == count)
break;
}
}
if (!more)
adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_VLAN_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
return;
}
vvfl->vsi_id = adapter->vsi_res->vsi_id;
vvfl->num_elements = count;
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
if (f->add) {
vvfl->vlan_id[i] = f->vlan;
i++;
f->add = false;
if (i == count)
break;
iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len);
kfree(vvfl);
} else {
struct virtchnl_vlan_filter_list_v2 *vvfl_v2;
adapter->current_op = VIRTCHNL_OP_ADD_VLAN_V2;
len = sizeof(*vvfl_v2) + ((count - 1) *
sizeof(struct virtchnl_vlan_filter));
if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n");
count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(*vvfl_v2)) /
sizeof(struct virtchnl_vlan_filter);
len = sizeof(*vvfl_v2) +
((count - 1) *
sizeof(struct virtchnl_vlan_filter));
more = true;
}
}
if (!more)
adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_VLAN_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
vvfl_v2 = kzalloc(len, GFP_ATOMIC);
if (!vvfl_v2) {
spin_unlock_bh(&adapter->mac_vlan_list_lock);
return;
}
iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len);
kfree(vvfl);
vvfl_v2->vport_id = adapter->vsi_res->vsi_id;
vvfl_v2->num_elements = count;
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
if (f->add) {
struct virtchnl_vlan_supported_caps *filtering_support =
&adapter->vlan_v2_caps.filtering.filtering_support;
struct virtchnl_vlan *vlan;
/* give priority over outer if it's enabled */
if (filtering_support->outer)
vlan = &vvfl_v2->filters[i].outer;
else
vlan = &vvfl_v2->filters[i].inner;
vlan->tci = f->vlan.vid;
vlan->tpid = f->vlan.tpid;
i++;
f->add = false;
if (i == count)
break;
}
}
if (!more)
adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_VLAN_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_VLAN_V2,
(u8 *)vvfl_v2, len);
kfree(vvfl_v2);
}
}
/**
......@@ -659,7 +768,6 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
**/
void iavf_del_vlans(struct iavf_adapter *adapter)
{
struct virtchnl_vlan_filter_list *vvfl;
struct iavf_vlan_filter *f, *ftmp;
int len, i = 0, count = 0;
bool more = false;
......@@ -680,56 +788,116 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
* filters marked for removal to enable bailing out before
* sending a virtchnl message
*/
if (f->remove && !VLAN_ALLOWED(adapter)) {
if (f->remove && !VLAN_FILTERING_ALLOWED(adapter)) {
list_del(&f->list);
kfree(f);
} else if (f->remove) {
count++;
}
}
if (!count) {
if (!count || !VLAN_FILTERING_ALLOWED(adapter)) {
adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_VLAN_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
return;
}
adapter->current_op = VIRTCHNL_OP_DEL_VLAN;
len = sizeof(struct virtchnl_vlan_filter_list) +
(count * sizeof(u16));
if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many delete VLAN changes in one request\n");
count = (IAVF_MAX_AQ_BUF_SIZE -
sizeof(struct virtchnl_vlan_filter_list)) /
sizeof(u16);
len = sizeof(struct virtchnl_vlan_filter_list) +
(count * sizeof(u16));
more = true;
}
vvfl = kzalloc(len, GFP_ATOMIC);
if (!vvfl) {
if (VLAN_ALLOWED(adapter)) {
struct virtchnl_vlan_filter_list *vvfl;
adapter->current_op = VIRTCHNL_OP_DEL_VLAN;
len = sizeof(*vvfl) + (count * sizeof(u16));
if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many delete VLAN changes in one request\n");
count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(*vvfl)) /
sizeof(u16);
len = sizeof(*vvfl) + (count * sizeof(u16));
more = true;
}
vvfl = kzalloc(len, GFP_ATOMIC);
if (!vvfl) {
spin_unlock_bh(&adapter->mac_vlan_list_lock);
return;
}
vvfl->vsi_id = adapter->vsi_res->vsi_id;
vvfl->num_elements = count;
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
if (f->remove) {
vvfl->vlan_id[i] = f->vlan.vid;
i++;
list_del(&f->list);
kfree(f);
if (i == count)
break;
}
}
if (!more)
adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_VLAN_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
return;
}
vvfl->vsi_id = adapter->vsi_res->vsi_id;
vvfl->num_elements = count;
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
if (f->remove) {
vvfl->vlan_id[i] = f->vlan;
i++;
list_del(&f->list);
kfree(f);
if (i == count)
break;
iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len);
kfree(vvfl);
} else {
struct virtchnl_vlan_filter_list_v2 *vvfl_v2;
adapter->current_op = VIRTCHNL_OP_DEL_VLAN_V2;
len = sizeof(*vvfl_v2) +
((count - 1) * sizeof(struct virtchnl_vlan_filter));
if (len > IAVF_MAX_AQ_BUF_SIZE) {
dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n");
count = (IAVF_MAX_AQ_BUF_SIZE -
sizeof(*vvfl_v2)) /
sizeof(struct virtchnl_vlan_filter);
len = sizeof(*vvfl_v2) +
((count - 1) *
sizeof(struct virtchnl_vlan_filter));
more = true;
}
}
if (!more)
adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_VLAN_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
vvfl_v2 = kzalloc(len, GFP_ATOMIC);
if (!vvfl_v2) {
spin_unlock_bh(&adapter->mac_vlan_list_lock);
return;
}
vvfl_v2->vport_id = adapter->vsi_res->vsi_id;
vvfl_v2->num_elements = count;
list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
if (f->remove) {
struct virtchnl_vlan_supported_caps *filtering_support =
&adapter->vlan_v2_caps.filtering.filtering_support;
struct virtchnl_vlan *vlan;
/* give priority over outer if it's enabled */
if (filtering_support->outer)
vlan = &vvfl_v2->filters[i].outer;
else
vlan = &vvfl_v2->filters[i].inner;
vlan->tci = f->vlan.vid;
vlan->tpid = f->vlan.tpid;
list_del(&f->list);
kfree(f);
i++;
if (i == count)
break;
}
}
if (!more)
adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_VLAN_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len);
kfree(vvfl);
iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_VLAN_V2,
(u8 *)vvfl_v2, len);
kfree(vvfl_v2);
}
}
/**
......@@ -956,6 +1124,204 @@ void iavf_disable_vlan_stripping(struct iavf_adapter *adapter)
iavf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_VLAN_STRIPPING, NULL, 0);
}
/**
* iavf_tpid_to_vc_ethertype - transform from VLAN TPID to virtchnl ethertype
* @tpid: VLAN TPID (i.e. 0x8100, 0x88a8, etc.)
*/
static u32 iavf_tpid_to_vc_ethertype(u16 tpid)
{
switch (tpid) {
case ETH_P_8021Q:
return VIRTCHNL_VLAN_ETHERTYPE_8100;
case ETH_P_8021AD:
return VIRTCHNL_VLAN_ETHERTYPE_88A8;
}
return 0;
}
/**
* iavf_set_vc_offload_ethertype - set virtchnl ethertype for offload message
* @adapter: adapter structure
* @msg: message structure used for updating offloads over virtchnl to update
* @tpid: VLAN TPID (i.e. 0x8100, 0x88a8, etc.)
* @offload_op: opcode used to determine which support structure to check
*/
static int
iavf_set_vc_offload_ethertype(struct iavf_adapter *adapter,
struct virtchnl_vlan_setting *msg, u16 tpid,
enum virtchnl_ops offload_op)
{
struct virtchnl_vlan_supported_caps *offload_support;
u16 vc_ethertype = iavf_tpid_to_vc_ethertype(tpid);
/* reference the correct offload support structure */
switch (offload_op) {
case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2:
case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2:
offload_support =
&adapter->vlan_v2_caps.offloads.stripping_support;
break;
case VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2:
case VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2:
offload_support =
&adapter->vlan_v2_caps.offloads.insertion_support;
break;
default:
dev_err(&adapter->pdev->dev, "Invalid opcode %d for setting virtchnl ethertype to enable/disable VLAN offloads\n",
offload_op);
return -EINVAL;
}
/* make sure ethertype is supported */
if (offload_support->outer & vc_ethertype &&
offload_support->outer & VIRTCHNL_VLAN_TOGGLE) {
msg->outer_ethertype_setting = vc_ethertype;
} else if (offload_support->inner & vc_ethertype &&
offload_support->inner & VIRTCHNL_VLAN_TOGGLE) {
msg->inner_ethertype_setting = vc_ethertype;
} else {
dev_dbg(&adapter->pdev->dev, "opcode %d unsupported for VLAN TPID 0x%04x\n",
offload_op, tpid);
return -EINVAL;
}
return 0;
}
/**
* iavf_clear_offload_v2_aq_required - clear AQ required bit for offload request
* @adapter: adapter structure
* @tpid: VLAN TPID
* @offload_op: opcode used to determine which AQ required bit to clear
*/
static void
iavf_clear_offload_v2_aq_required(struct iavf_adapter *adapter, u16 tpid,
enum virtchnl_ops offload_op)
{
switch (offload_op) {
case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2:
if (tpid == ETH_P_8021Q)
adapter->aq_required &=
~IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_STRIPPING;
else if (tpid == ETH_P_8021AD)
adapter->aq_required &=
~IAVF_FLAG_AQ_ENABLE_STAG_VLAN_STRIPPING;
break;
case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2:
if (tpid == ETH_P_8021Q)
adapter->aq_required &=
~IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_STRIPPING;
else if (tpid == ETH_P_8021AD)
adapter->aq_required &=
~IAVF_FLAG_AQ_DISABLE_STAG_VLAN_STRIPPING;
break;
case VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2:
if (tpid == ETH_P_8021Q)
adapter->aq_required &=
~IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_INSERTION;
else if (tpid == ETH_P_8021AD)
adapter->aq_required &=
~IAVF_FLAG_AQ_ENABLE_STAG_VLAN_INSERTION;
break;
case VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2:
if (tpid == ETH_P_8021Q)
adapter->aq_required &=
~IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_INSERTION;
else if (tpid == ETH_P_8021AD)
adapter->aq_required &=
~IAVF_FLAG_AQ_DISABLE_STAG_VLAN_INSERTION;
break;
default:
dev_err(&adapter->pdev->dev, "Unsupported opcode %d specified for clearing aq_required bits for VIRTCHNL_VF_OFFLOAD_VLAN_V2 offload request\n",
offload_op);
}
}
/**
* iavf_send_vlan_offload_v2 - send offload enable/disable over virtchnl
* @adapter: adapter structure
* @tpid: VLAN TPID used for the command (i.e. 0x8100 or 0x88a8)
* @offload_op: offload_op used to make the request over virtchnl
*/
static void
iavf_send_vlan_offload_v2(struct iavf_adapter *adapter, u16 tpid,
enum virtchnl_ops offload_op)
{
struct virtchnl_vlan_setting *msg;
int len = sizeof(*msg);
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
dev_err(&adapter->pdev->dev, "Cannot send %d, command %d pending\n",
offload_op, adapter->current_op);
return;
}
adapter->current_op = offload_op;
msg = kzalloc(len, GFP_KERNEL);
if (!msg)
return;
msg->vport_id = adapter->vsi_res->vsi_id;
/* always clear to prevent unsupported and endless requests */
iavf_clear_offload_v2_aq_required(adapter, tpid, offload_op);
/* only send valid offload requests */
if (!iavf_set_vc_offload_ethertype(adapter, msg, tpid, offload_op))
iavf_send_pf_msg(adapter, offload_op, (u8 *)msg, len);
else
adapter->current_op = VIRTCHNL_OP_UNKNOWN;
kfree(msg);
}
/**
* iavf_enable_vlan_stripping_v2 - enable VLAN stripping
* @adapter: adapter structure
* @tpid: VLAN TPID used to enable VLAN stripping
*/
void iavf_enable_vlan_stripping_v2(struct iavf_adapter *adapter, u16 tpid)
{
iavf_send_vlan_offload_v2(adapter, tpid,
VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2);
}
/**
* iavf_disable_vlan_stripping_v2 - disable VLAN stripping
* @adapter: adapter structure
* @tpid: VLAN TPID used to disable VLAN stripping
*/
void iavf_disable_vlan_stripping_v2(struct iavf_adapter *adapter, u16 tpid)
{
iavf_send_vlan_offload_v2(adapter, tpid,
VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2);
}
/**
* iavf_enable_vlan_insertion_v2 - enable VLAN insertion
* @adapter: adapter structure
* @tpid: VLAN TPID used to enable VLAN insertion
*/
void iavf_enable_vlan_insertion_v2(struct iavf_adapter *adapter, u16 tpid)
{
iavf_send_vlan_offload_v2(adapter, tpid,
VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2);
}
/**
* iavf_disable_vlan_insertion_v2 - disable VLAN insertion
* @adapter: adapter structure
* @tpid: VLAN TPID used to disable VLAN insertion
*/
void iavf_disable_vlan_insertion_v2(struct iavf_adapter *adapter, u16 tpid)
{
iavf_send_vlan_offload_v2(adapter, tpid,
VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2);
}
#define IAVF_MAX_SPEED_STRLEN 13
/**
......@@ -1759,6 +2125,26 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
}
spin_unlock_bh(&adapter->mac_vlan_list_lock);
iavf_parse_vf_resource_msg(adapter);
/* negotiated VIRTCHNL_VF_OFFLOAD_VLAN_V2, so wait for the
* response to VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS to finish
* configuration
*/
if (VLAN_V2_ALLOWED(adapter))
break;
/* fallthrough and finish config if VIRTCHNL_VF_OFFLOAD_VLAN_V2
* wasn't successfully negotiated with the PF
*/
}
fallthrough;
case VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS: {
if (v_opcode == VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS)
memcpy(&adapter->vlan_v2_caps, msg,
min_t(u16, msglen,
sizeof(adapter->vlan_v2_caps)));
iavf_process_config(adapter);
/* unlock crit_lock before acquiring rtnl_lock as other
......@@ -1766,13 +2152,23 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
* crit_lock
*/
mutex_unlock(&adapter->crit_lock);
/* VLAN capabilities can change during VFR, so make sure to
* update the netdev features with the new capabilities
*/
rtnl_lock();
netdev_update_features(adapter->netdev);
netdev_update_features(netdev);
rtnl_unlock();
if (iavf_lock_timeout(&adapter->crit_lock, 10000))
dev_warn(&adapter->pdev->dev, "failed to acquire crit_lock in %s\n",
__FUNCTION__);
/* Request VLAN offload settings */
if (VLAN_V2_ALLOWED(adapter))
iavf_set_vlan_offload_features(adapter, 0,
netdev->features);
iavf_set_queue_vlan_tag_loc(adapter);
}
break;
case VIRTCHNL_OP_ENABLE_QUEUES:
......
......@@ -141,6 +141,13 @@ enum virtchnl_ops {
VIRTCHNL_OP_DEL_RSS_CFG = 46,
VIRTCHNL_OP_ADD_FDIR_FILTER = 47,
VIRTCHNL_OP_DEL_FDIR_FILTER = 48,
VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS = 51,
VIRTCHNL_OP_ADD_VLAN_V2 = 52,
VIRTCHNL_OP_DEL_VLAN_V2 = 53,
VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2 = 54,
VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2 = 55,
VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2 = 56,
VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2 = 57,
VIRTCHNL_OP_MAX,
};
......@@ -246,6 +253,7 @@ VIRTCHNL_CHECK_STRUCT_LEN(16, virtchnl_vsi_resource);
#define VIRTCHNL_VF_OFFLOAD_REQ_QUEUES BIT(6)
/* used to negotiate communicating link speeds in Mbps */
#define VIRTCHNL_VF_CAP_ADV_LINK_SPEED BIT(7)
#define VIRTCHNL_VF_OFFLOAD_VLAN_V2 BIT(15)
#define VIRTCHNL_VF_OFFLOAD_VLAN BIT(16)
#define VIRTCHNL_VF_OFFLOAD_RX_POLLING BIT(17)
#define VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 BIT(18)
......@@ -475,6 +483,351 @@ struct virtchnl_vlan_filter_list {
VIRTCHNL_CHECK_STRUCT_LEN(6, virtchnl_vlan_filter_list);
/* This enum is used for all of the VIRTCHNL_VF_OFFLOAD_VLAN_V2_CAPS related
* structures and opcodes.
*
* VIRTCHNL_VLAN_UNSUPPORTED - This field is not supported and if a VF driver
* populates it the PF should return VIRTCHNL_STATUS_ERR_NOT_SUPPORTED.
*
* VIRTCHNL_VLAN_ETHERTYPE_8100 - This field supports 0x8100 ethertype.
* VIRTCHNL_VLAN_ETHERTYPE_88A8 - This field supports 0x88A8 ethertype.
* VIRTCHNL_VLAN_ETHERTYPE_9100 - This field supports 0x9100 ethertype.
*
* VIRTCHNL_VLAN_ETHERTYPE_AND - Used when multiple ethertypes can be supported
* by the PF concurrently. For example, if the PF can support
* VIRTCHNL_VLAN_ETHERTYPE_8100 AND VIRTCHNL_VLAN_ETHERTYPE_88A8 filters it
* would OR the following bits:
*
* VIRTHCNL_VLAN_ETHERTYPE_8100 |
* VIRTCHNL_VLAN_ETHERTYPE_88A8 |
* VIRTCHNL_VLAN_ETHERTYPE_AND;
*
* The VF would interpret this as VLAN filtering can be supported on both 0x8100
* and 0x88A8 VLAN ethertypes.
*
* VIRTCHNL_ETHERTYPE_XOR - Used when only a single ethertype can be supported
* by the PF concurrently. For example if the PF can support
* VIRTCHNL_VLAN_ETHERTYPE_8100 XOR VIRTCHNL_VLAN_ETHERTYPE_88A8 stripping
* offload it would OR the following bits:
*
* VIRTCHNL_VLAN_ETHERTYPE_8100 |
* VIRTCHNL_VLAN_ETHERTYPE_88A8 |
* VIRTCHNL_VLAN_ETHERTYPE_XOR;
*
* The VF would interpret this as VLAN stripping can be supported on either
* 0x8100 or 0x88a8 VLAN ethertypes. So when requesting VLAN stripping via
* VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2 the specified ethertype will override
* the previously set value.
*
* VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1 - Used to tell the VF to insert and/or
* strip the VLAN tag using the L2TAG1 field of the Tx/Rx descriptors.
*
* VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2 - Used to tell the VF to insert hardware
* offloaded VLAN tags using the L2TAG2 field of the Tx descriptor.
*
* VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2 - Used to tell the VF to strip hardware
* offloaded VLAN tags using the L2TAG2_2 field of the Rx descriptor.
*
* VIRTCHNL_VLAN_PRIO - This field supports VLAN priority bits. This is used for
* VLAN filtering if the underlying PF supports it.
*
* VIRTCHNL_VLAN_TOGGLE_ALLOWED - This field is used to say whether a
* certain VLAN capability can be toggled. For example if the underlying PF/CP
* allows the VF to toggle VLAN filtering, stripping, and/or insertion it should
* set this bit along with the supported ethertypes.
*/
enum virtchnl_vlan_support {
VIRTCHNL_VLAN_UNSUPPORTED = 0,
VIRTCHNL_VLAN_ETHERTYPE_8100 = BIT(0),
VIRTCHNL_VLAN_ETHERTYPE_88A8 = BIT(1),
VIRTCHNL_VLAN_ETHERTYPE_9100 = BIT(2),
VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1 = BIT(8),
VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2 = BIT(9),
VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2 = BIT(10),
VIRTCHNL_VLAN_PRIO = BIT(24),
VIRTCHNL_VLAN_FILTER_MASK = BIT(28),
VIRTCHNL_VLAN_ETHERTYPE_AND = BIT(29),
VIRTCHNL_VLAN_ETHERTYPE_XOR = BIT(30),
VIRTCHNL_VLAN_TOGGLE = BIT(31),
};
/* This structure is used as part of the VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS
* for filtering, insertion, and stripping capabilities.
*
* If only outer capabilities are supported (for filtering, insertion, and/or
* stripping) then this refers to the outer most or single VLAN from the VF's
* perspective.
*
* If only inner capabilities are supported (for filtering, insertion, and/or
* stripping) then this refers to the outer most or single VLAN from the VF's
* perspective. Functionally this is the same as if only outer capabilities are
* supported. The VF driver is just forced to use the inner fields when
* adding/deleting filters and enabling/disabling offloads (if supported).
*
* If both outer and inner capabilities are supported (for filtering, insertion,
* and/or stripping) then outer refers to the outer most or single VLAN and
* inner refers to the second VLAN, if it exists, in the packet.
*
* There is no support for tunneled VLAN offloads, so outer or inner are never
* referring to a tunneled packet from the VF's perspective.
*/
struct virtchnl_vlan_supported_caps {
u32 outer;
u32 inner;
};
/* The PF populates these fields based on the supported VLAN filtering. If a
* field is VIRTCHNL_VLAN_UNSUPPORTED then it's not supported and the PF will
* reject any VIRTCHNL_OP_ADD_VLAN_V2 or VIRTCHNL_OP_DEL_VLAN_V2 messages using
* the unsupported fields.
*
* Also, a VF is only allowed to toggle its VLAN filtering setting if the
* VIRTCHNL_VLAN_TOGGLE bit is set.
*
* The ethertype(s) specified in the ethertype_init field are the ethertypes
* enabled for VLAN filtering. VLAN filtering in this case refers to the outer
* most VLAN from the VF's perspective. If both inner and outer filtering are
* allowed then ethertype_init only refers to the outer most VLAN as only
* VLAN ethertype supported for inner VLAN filtering is
* VIRTCHNL_VLAN_ETHERTYPE_8100. By default, inner VLAN filtering is disabled
* when both inner and outer filtering are allowed.
*
* The max_filters field tells the VF how many VLAN filters it's allowed to have
* at any one time. If it exceeds this amount and tries to add another filter,
* then the request will be rejected by the PF. To prevent failures, the VF
* should keep track of how many VLAN filters it has added and not attempt to
* add more than max_filters.
*/
struct virtchnl_vlan_filtering_caps {
struct virtchnl_vlan_supported_caps filtering_support;
u32 ethertype_init;
u16 max_filters;
u8 pad[2];
};
VIRTCHNL_CHECK_STRUCT_LEN(16, virtchnl_vlan_filtering_caps);
/* This enum is used for the virtchnl_vlan_offload_caps structure to specify
* if the PF supports a different ethertype for stripping and insertion.
*
* VIRTCHNL_ETHERTYPE_STRIPPING_MATCHES_INSERTION - The ethertype(s) specified
* for stripping affect the ethertype(s) specified for insertion and visa versa
* as well. If the VF tries to configure VLAN stripping via
* VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2 with VIRTCHNL_VLAN_ETHERTYPE_8100 then
* that will be the ethertype for both stripping and insertion.
*
* VIRTCHNL_ETHERTYPE_MATCH_NOT_REQUIRED - The ethertype(s) specified for
* stripping do not affect the ethertype(s) specified for insertion and visa
* versa.
*/
enum virtchnl_vlan_ethertype_match {
VIRTCHNL_ETHERTYPE_STRIPPING_MATCHES_INSERTION = 0,
VIRTCHNL_ETHERTYPE_MATCH_NOT_REQUIRED = 1,
};
/* The PF populates these fields based on the supported VLAN offloads. If a
* field is VIRTCHNL_VLAN_UNSUPPORTED then it's not supported and the PF will
* reject any VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2 or
* VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2 messages using the unsupported fields.
*
* Also, a VF is only allowed to toggle its VLAN offload setting if the
* VIRTCHNL_VLAN_TOGGLE_ALLOWED bit is set.
*
* The VF driver needs to be aware of how the tags are stripped by hardware and
* inserted by the VF driver based on the level of offload support. The PF will
* populate these fields based on where the VLAN tags are expected to be
* offloaded via the VIRTHCNL_VLAN_TAG_LOCATION_* bits. The VF will need to
* interpret these fields. See the definition of the
* VIRTCHNL_VLAN_TAG_LOCATION_* bits above the virtchnl_vlan_support
* enumeration.
*/
struct virtchnl_vlan_offload_caps {
struct virtchnl_vlan_supported_caps stripping_support;
struct virtchnl_vlan_supported_caps insertion_support;
u32 ethertype_init;
u8 ethertype_match;
u8 pad[3];
};
VIRTCHNL_CHECK_STRUCT_LEN(24, virtchnl_vlan_offload_caps);
/* VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS
* VF sends this message to determine its VLAN capabilities.
*
* PF will mark which capabilities it supports based on hardware support and
* current configuration. For example, if a port VLAN is configured the PF will
* not allow outer VLAN filtering, stripping, or insertion to be configured so
* it will block these features from the VF.
*
* The VF will need to cross reference its capabilities with the PFs
* capabilities in the response message from the PF to determine the VLAN
* support.
*/
struct virtchnl_vlan_caps {
struct virtchnl_vlan_filtering_caps filtering;
struct virtchnl_vlan_offload_caps offloads;
};
VIRTCHNL_CHECK_STRUCT_LEN(40, virtchnl_vlan_caps);
struct virtchnl_vlan {
u16 tci; /* tci[15:13] = PCP and tci[11:0] = VID */
u16 tci_mask; /* only valid if VIRTCHNL_VLAN_FILTER_MASK set in
* filtering caps
*/
u16 tpid; /* 0x8100, 0x88a8, etc. and only type(s) set in
* filtering caps. Note that tpid here does not refer to
* VIRTCHNL_VLAN_ETHERTYPE_*, but it refers to the
* actual 2-byte VLAN TPID
*/
u8 pad[2];
};
VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_vlan);
struct virtchnl_vlan_filter {
struct virtchnl_vlan inner;
struct virtchnl_vlan outer;
u8 pad[16];
};
VIRTCHNL_CHECK_STRUCT_LEN(32, virtchnl_vlan_filter);
/* VIRTCHNL_OP_ADD_VLAN_V2
* VIRTCHNL_OP_DEL_VLAN_V2
*
* VF sends these messages to add/del one or more VLAN tag filters for Rx
* traffic.
*
* The PF attempts to add the filters and returns status.
*
* The VF should only ever attempt to add/del virtchnl_vlan_filter(s) using the
* supported fields negotiated via VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS.
*/
struct virtchnl_vlan_filter_list_v2 {
u16 vport_id;
u16 num_elements;
u8 pad[4];
struct virtchnl_vlan_filter filters[1];
};
VIRTCHNL_CHECK_STRUCT_LEN(40, virtchnl_vlan_filter_list_v2);
/* VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2
* VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2
* VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2
* VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2
*
* VF sends this message to enable or disable VLAN stripping or insertion. It
* also needs to specify an ethertype. The VF knows which VLAN ethertypes are
* allowed and whether or not it's allowed to enable/disable the specific
* offload via the VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS message. The VF needs to
* parse the virtchnl_vlan_caps.offloads fields to determine which offload
* messages are allowed.
*
* For example, if the PF populates the virtchnl_vlan_caps.offloads in the
* following manner the VF will be allowed to enable and/or disable 0x8100 inner
* VLAN insertion and/or stripping via the opcodes listed above. Inner in this
* case means the outer most or single VLAN from the VF's perspective. This is
* because no outer offloads are supported. See the comments above the
* virtchnl_vlan_supported_caps structure for more details.
*
* virtchnl_vlan_caps.offloads.stripping_support.inner =
* VIRTCHNL_VLAN_TOGGLE |
* VIRTCHNL_VLAN_ETHERTYPE_8100;
*
* virtchnl_vlan_caps.offloads.insertion_support.inner =
* VIRTCHNL_VLAN_TOGGLE |
* VIRTCHNL_VLAN_ETHERTYPE_8100;
*
* In order to enable inner (again note that in this case inner is the outer
* most or single VLAN from the VF's perspective) VLAN stripping for 0x8100
* VLANs, the VF would populate the virtchnl_vlan_setting structure in the
* following manner and send the VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2 message.
*
* virtchnl_vlan_setting.inner_ethertype_setting =
* VIRTCHNL_VLAN_ETHERTYPE_8100;
*
* virtchnl_vlan_setting.vport_id = vport_id or vsi_id assigned to the VF on
* initialization.
*
* The reason that VLAN TPID(s) are not being used for the
* outer_ethertype_setting and inner_ethertype_setting fields is because it's
* possible a device could support VLAN insertion and/or stripping offload on
* multiple ethertypes concurrently, so this method allows a VF to request
* multiple ethertypes in one message using the virtchnl_vlan_support
* enumeration.
*
* For example, if the PF populates the virtchnl_vlan_caps.offloads in the
* following manner the VF will be allowed to enable 0x8100 and 0x88a8 outer
* VLAN insertion and stripping simultaneously. The
* virtchnl_vlan_caps.offloads.ethertype_match field will also have to be
* populated based on what the PF can support.
*
* virtchnl_vlan_caps.offloads.stripping_support.outer =
* VIRTCHNL_VLAN_TOGGLE |
* VIRTCHNL_VLAN_ETHERTYPE_8100 |
* VIRTCHNL_VLAN_ETHERTYPE_88A8 |
* VIRTCHNL_VLAN_ETHERTYPE_AND;
*
* virtchnl_vlan_caps.offloads.insertion_support.outer =
* VIRTCHNL_VLAN_TOGGLE |
* VIRTCHNL_VLAN_ETHERTYPE_8100 |
* VIRTCHNL_VLAN_ETHERTYPE_88A8 |
* VIRTCHNL_VLAN_ETHERTYPE_AND;
*
* In order to enable outer VLAN stripping for 0x8100 and 0x88a8 VLANs, the VF
* would populate the virthcnl_vlan_offload_structure in the following manner
* and send the VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2 message.
*
* virtchnl_vlan_setting.outer_ethertype_setting =
* VIRTHCNL_VLAN_ETHERTYPE_8100 |
* VIRTHCNL_VLAN_ETHERTYPE_88A8;
*
* virtchnl_vlan_setting.vport_id = vport_id or vsi_id assigned to the VF on
* initialization.
*
* There is also the case where a PF and the underlying hardware can support
* VLAN offloads on multiple ethertypes, but not concurrently. For example, if
* the PF populates the virtchnl_vlan_caps.offloads in the following manner the
* VF will be allowed to enable and/or disable 0x8100 XOR 0x88a8 outer VLAN
* offloads. The ethertypes must match for stripping and insertion.
*
* virtchnl_vlan_caps.offloads.stripping_support.outer =
* VIRTCHNL_VLAN_TOGGLE |
* VIRTCHNL_VLAN_ETHERTYPE_8100 |
* VIRTCHNL_VLAN_ETHERTYPE_88A8 |
* VIRTCHNL_VLAN_ETHERTYPE_XOR;
*
* virtchnl_vlan_caps.offloads.insertion_support.outer =
* VIRTCHNL_VLAN_TOGGLE |
* VIRTCHNL_VLAN_ETHERTYPE_8100 |
* VIRTCHNL_VLAN_ETHERTYPE_88A8 |
* VIRTCHNL_VLAN_ETHERTYPE_XOR;
*
* virtchnl_vlan_caps.offloads.ethertype_match =
* VIRTCHNL_ETHERTYPE_STRIPPING_MATCHES_INSERTION;
*
* In order to enable outer VLAN stripping for 0x88a8 VLANs, the VF would
* populate the virtchnl_vlan_setting structure in the following manner and send
* the VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2. Also, this will change the
* ethertype for VLAN insertion if it's enabled. So, for completeness, a
* VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2 with the same ethertype should be sent.
*
* virtchnl_vlan_setting.outer_ethertype_setting = VIRTHCNL_VLAN_ETHERTYPE_88A8;
*
* virtchnl_vlan_setting.vport_id = vport_id or vsi_id assigned to the VF on
* initialization.
*/
struct virtchnl_vlan_setting {
u32 outer_ethertype_setting;
u32 inner_ethertype_setting;
u16 vport_id;
u8 pad[6];
};
VIRTCHNL_CHECK_STRUCT_LEN(16, virtchnl_vlan_setting);
/* VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE
* VF sends VSI id and flags.
* PF returns status code in retval.
......@@ -1156,6 +1509,30 @@ virtchnl_vc_validate_vf_msg(struct virtchnl_version_info *ver, u32 v_opcode,
case VIRTCHNL_OP_DEL_FDIR_FILTER:
valid_len = sizeof(struct virtchnl_fdir_del);
break;
case VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS:
break;
case VIRTCHNL_OP_ADD_VLAN_V2:
case VIRTCHNL_OP_DEL_VLAN_V2:
valid_len = sizeof(struct virtchnl_vlan_filter_list_v2);
if (msglen >= valid_len) {
struct virtchnl_vlan_filter_list_v2 *vfl =
(struct virtchnl_vlan_filter_list_v2 *)msg;
valid_len += (vfl->num_elements - 1) *
sizeof(struct virtchnl_vlan_filter);
if (vfl->num_elements == 0) {
err_msg_format = true;
break;
}
}
break;
case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2:
case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2:
case VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2:
case VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2:
valid_len = sizeof(struct virtchnl_vlan_setting);
break;
/* These are always errors coming from the VF. */
case VIRTCHNL_OP_EVENT:
case VIRTCHNL_OP_UNKNOWN:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment