mirror of
https://git.proxmox.com/git/mirror_ubuntu-kernels.git
synced 2026-01-27 05:04:19 +00:00
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
23044d77d6
@ -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 @@ clearout:
|
||||
* @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_add_vlan(adapter, vid) == NULL)
|
||||
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, 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 @@ err:
|
||||
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 @@ err:
|
||||
**/
|
||||
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 @@ err_register:
|
||||
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 @@ continue_reset:
|
||||
}
|
||||
|
||||
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 @@ out_err:
|
||||
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 @@ tx_only:
|
||||
* 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;
|
||||
/* stack will only request hardware VLAN insertion offload for protocols
|
||||
* that the driver supports and has enabled
|
||||
*/
|
||||
if (!skb_vlan_tag_present(skb))
|
||||
return;
|
||||
|
||||
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 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;
|
||||
|
||||
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;
|
||||
} 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 @@ out:
|
||||
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) {
|
||||
spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
||||
return;
|
||||
}
|
||||
if (VLAN_ALLOWED(adapter)) {
|
||||
struct virtchnl_vlan_filter_list *vvfl;
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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(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);
|
||||
}
|
||||
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, (u8 *)vvfl, len);
|
||||
kfree(vvfl);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -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) {
|
||||
spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
||||
return;
|
||||
}
|
||||
if (VLAN_ALLOWED(adapter)) {
|
||||
struct virtchnl_vlan_filter_list *vvfl;
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_V2,
|
||||
(u8 *)vvfl_v2, len);
|
||||
kfree(vvfl_v2);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -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:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user