[Intel-wired-lan] [PATCH net-next v1] iavf: Add support for VIRTCHNL_VF_OFFLOAD_VLAN_V2
Creeley, Brett
brett.creeley at intel.com
Tue Oct 5 18:39:23 UTC 2021
> -----Original Message-----
> From: Sornek, Karen <karen.sornek at intel.com>
> Sent: Wednesday, September 29, 2021 6:44 AM
> To: intel-wired-lan at lists.osuosl.org
> Cc: Sornek, Karen <karen.sornek at intel.com>; Creeley, Brett <brett.creeley at intel.com>
> Subject: [PATCH net-next v1] iavf: Add support for VIRTCHNL_VF_OFFLOAD_VLAN_V2
>
> Restrict maximum VLAN filters for VIRTCHNL_VF_OFFLOAD_VLAN_V2
>
> For VIRTCHNL_VF_OFFLOAD_VLAN, PF's would limit the number of VLAN
> filters a VF was allowed to add. However, by the time the opcode failed,
> the VLAN netdev had already been added. VIRTCHNL_VF_OFFLOAD_VLAN_V2
> added the ability for a PF to tell the VF how many VLAN filters it's
> allowed to add. Make changes to support that functionality.
>
> Add support for VIRTCHNL_VF_OFFLOAD_VLAN_V2 offload enable/disable
>
> The new VIRTCHNL_VF_OFFLOAD_VLAN_V2 capability adds support that allows
> the VF to support 802.1Q and 802.1ad VLAN insertion and stripping if
> successfully negotiated via VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS.
> Multiple changes were needed to support this new functionality.
>
> 1. Add new aq_required flags to support any kind of VLAN stripping and
> insertion offload requests via virtchnl.
>
> 2. Add the new method iavf_set_vlan_offload_features() that's
> used during VF initialization, VF reset, and iavf_set_features() to
> set the aq_required bits based on the current VLAN offload
> configuration of the VF's netdev.
>
> 3. Add virtchnl handling for VIRTCHNL_OP_ENABLE_STRIPPING_V2,
> VIRTCHNL_OP_DISABLE_STRIPPING_V2, VIRTCHNL_OP_ENABLE_INSERTION_V2,
> and VIRTCHNL_OP_ENABLE_INSERTION_V2.
>
> Add support for VIRTCHNL_VF_OFFLOAD_VLAN_V2 hotpath
>
> The new VIRTCHNL_VF_OFFLOAD_VLAN_V2 capability added support that allows
> the PF to set the location of the Tx and Rx VLAN tag for insertion and
> stripping offloads. In order to support this functionality a few changes
> are needed.
>
> 1. Add a new method to cache the VLAN tag location based on negotiated
> capabilities for the Tx and Rx ring flags. This needs to be called in
> the initialization and reset paths.
>
> 2. Refactor the transmit hotpath to account for the new Tx ring flags.
> When IAVF_TXR_FLAGS_VLAN_LOC_L2TAG2 is set, then the driver needs to
> insert the VLAN tag in the L2TAG2 field of the transmit descriptor.
> When the IAVF_TXRX_FLAGS_VLAN_LOC_L2TAG1 is set, then the driver needs
> to use the l2tag1 field of the data descriptor (same behavior as
> before).
>
> 3. Refactor the iavf_tx_prepare_vlan_flags() function to simplify
> transmit hardware VLAN offload functionality by only depending on the
> skb_vlan_tag_present() function. This can be done because the OS
> won't request transmit offload for a VLAN unless the driver told the
> OS it's supported and enabled.
>
> 4. Refactor the receive hotpath to account for the new Rx ring flags and
> VLAN ethertypes. This requires checking the Rx ring flags and
> descriptor status bits to determine the location of the VLAN tag.
> Also, since only a single ethertype can be supported at a time, check
> the enabled netdev features before specifying a VLAN ethertype in
> __vlan_hwaccel_put_tag().
>
> Add support for VIRTCHNL_OP_[ADD|DEL]_VLAN_V2
>
> In order to support adding/deleting VLAN filters when the VF
> successfully negotiates VIRTCHNL_VF_OFFLOAD_VLAN_V2, it must use the new
> virtchnl opcodes:
>
> VIRTCHNL_OP_ADD_VLAN_V2
> VIRTCHNL_OP_DEL_VLAN_V2
>
> Also, the VF is able to add 802.1Q and 802.1AD VLAN filters if the
> support was negotiated in VIRTCHNL_VF_OFFLOAD_VLAN_V2 and
> VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS, so add support to specify the VLAN
> TPID when adding/deletingn VLAN filters using these new opcodes.
s/deletingn/deleting
>
> Lastly, only re-add VLAN filters after VF reset if VLAN filtering is
> allowed instead of just blindly re-adding them over virtchnl.
>
> Add support for VIRTCHNL_VF_OFFLOAD_VLAN_V2 negotiation
>
> In order to support the new VIRTCHNL_VF_OFFLOAD_VLAN_V2 capability the
> VF driver needs to rework it's initialization state machine and reset
> flow. This has to be done because successful negotiation of
> VIRTCHNL_VF_OFFLOAD_VLAN_V2 requires the VF driver to perform a second
> capability request via VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS before
> configuring the adapter and its netdev.
>
> Add the VIRTCHNL_VF_OFFLOAD_VLAN_V2 bit when sending the
> VIRTHCNL_OP_GET_VF_RESOURECES message. The underlying PF will either
> support VIRTCHNL_VF_OFFLOAD_VLAN or VIRTCHNL_VF_OFFLOAD_VLAN_V2 or
> neither. Both of these offloads should never be supported together.
>
> Based on this, add 2 new states to the initialization state machine:
>
> __IAVF_INIT_GET_OFFLOAD_VLAN_V2_CAPS
> __IAVF_INIT_CONFIG_ADAPTER
>
> The __IAVF_INIT_GET_OFFLOAD_VLAN_V2_CAPS state is used to request/store
> the new VLAN capabilities if and only if VIRTCHNL_VLAN_OFFLOAD_VLAN_V2
> was successfully negotiated in the __IAVF_INIT_GET_RESOURCES state.
>
> The __IAVF_INIT_CONFIG_ADAPTER state is used to configure the
> adapter/netdev after the resource requests have finished. The VF will
> move into this state regardless of whether it successfully negotiated
> VIRTCHNL_VF_OFFLOAD_VLAN or VIRTCHNL_VF_OFFLOAD_VLAN_V2.
>
> Also, add a the new flag IAVF_FLAG_AQ_GET_OFFLOAD_VLAN_V2_CAPS and set
> it during VF reset. If VIRTCHNL_VF_OFFLOAD_VLAN_V2 was successfully
> negotiated then the VF will request its VLAN capabilities via
> VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS during the reset. This is needed
> because the PF may change/modify the VF's configuration during VF reset
> (i.e. modifying the VF's port VLAN configuration).
>
> This also, required the VF to call netdev_update_features() since its
> VLAN features may change during VF reset. Make sure to call this under
> rtnl_lock().
There are 6 very separate patches in this commit. You even formatted
the commit message that way, i.e.:
<title>
<commit message>
<title>
<commit message>
...
IMO this should be split into a small patch series with the 5 iavf
patches and 1 virtchnl.h patch. This would be much more consumable
and the code changes are logically separated to allow this.
>
> Signed-off-by: Brett Creeley <brett.creeley at intel.com>
> Signed-off-by: Karen Sornek <karen.sornek at intel.com>
> ---
> drivers/net/ethernet/intel/iavf/iavf.h | 126 ++-
> drivers/net/ethernet/intel/iavf/iavf_main.c | 773 ++++++++++++++----
> drivers/net/ethernet/intel/iavf/iavf_txrx.c | 94 ++-
> drivers/net/ethernet/intel/iavf/iavf_txrx.h | 30 +-
> .../net/ethernet/intel/iavf/iavf_virtchnl.c | 588 +++++++++++--
> 5 files changed, 1296 insertions(+), 315 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
> index 21c957755..15b275950 100644
> --- a/drivers/net/ethernet/intel/iavf/iavf.h
> +++ b/drivers/net/ethernet/intel/iavf/iavf.h
> @@ -56,6 +56,8 @@ 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__);
> @@ -93,6 +95,17 @@ struct iavf_vsi {
> #define IAVF_VIRTCHNL_VF_RESOURCE_SIZE (sizeof(struct virtchnl_vf_resource) + \
> (IAVF_MAX_VF_VSI * \
> sizeof(struct virtchnl_vsi_resource)))
> +#ifdef NETIF_F_HW_VLAN_CTAG_RX
> +#define IAVF_NETIF_F_HW_VLAN_CTAG_RX NETIF_F_HW_VLAN_CTAG_RX
> +#else
> +#define IAVF_NETIF_F_HW_VLAN_CTAG_RX NETIF_F_HW_VLAN_RX
> +#endif
> +
> +#ifdef NETIF_F_HW_VLAN_CTAG_TX
> +#define IAVF_NETIF_F_HW_VLAN_CTAG_TX NETIF_F_HW_VLAN_CTAG_TX
> +#else
> +#define IAVF_NETIF_F_HW_VLAN_CTAG_TX NETIF_F_HW_VLAN_TX
> +#endif
Why are these #ifdefs here (i.e. NETIF_F_HW_VLAN_CTAG_TX and
NETIF_F_HW_VLAN_CTAG_RX)? Please fix this.
>
> /* MAX_MSIX_Q_VECTORS of these are allocated,
> * but we only use one per queue-specific vector.
> @@ -137,14 +150,23 @@ struct iavf_q_vector {
> struct iavf_mac_filter {
> struct list_head list;
> u8 macaddr[ETH_ALEN];
> - bool is_new_mac; /* filter is new, wait for PF decision */
> - bool remove; /* filter needs to be removed */
> - bool add; /* filter needs to be added */
> + struct {
> + u8 is_new_mac:1; /* filter is new, wait for PF decision */
> + u8 remove:1; /* filter needs to be removed */
> + u8 add:1; /* filter needs to be added */
> + u8 add_handled:1; /* received response from PF for filter add */
> + };
> +};
This change has nothing to do with VIRTCHNL_VF_OFFLOAD_VLAN_V2. Please
take it out of this patch.
> +
> +#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 */
> };
> @@ -177,6 +199,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_RESETTING, /* in reset */
> __IAVF_COMM_FAILED, /* communication with PF failed */
> @@ -187,6 +211,10 @@ enum iavf_state_t {
> __IAVF_RUNNING, /* opened, working */
> };
>
> +enum iavf_critical_section_t {
> + __IAVF_IN_CRITICAL_TASK, /* cannot be interrupted */
> +};
> +
> #define IAVF_CLOUD_FIELD_OMAC 0x01
> #define IAVF_CLOUD_FIELD_IMAC 0x02
> #define IAVF_CLOUD_FIELD_IVLAN 0x04
> @@ -272,40 +300,50 @@ struct iavf_adapter {
> #define IAVF_FLAG_LEGACY_RX BIT(15)
> #define IAVF_FLAG_REINIT_ITR_NEEDED BIT(16)
> #define IAVF_FLAG_QUEUES_DISABLED BIT(17)
> +#define IAVF_FLAG_INITIAL_MAC_SET BIT(18)
> /* 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(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)
> /* 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_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_GET_OFFLOAD_VLAN_V2_CAPS BIT(29)
> +#define IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_STRIPPING BIT(30)
> +#define IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_STRIPPING BIT(31)
> +#define IAVF_FLAG_AQ_ENABLE_STAG_VLAN_STRIPPING BIT(32)
> +#define IAVF_FLAG_AQ_DISABLE_STAG_VLAN_STRIPPING BIT(33)
> +#define IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_INSERTION BIT(34)
> +#define IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_INSERTION BIT(35)
> +#define IAVF_FLAG_AQ_ENABLE_STAG_VLAN_INSERTION BIT(36)
> +#define IAVF_FLAG_AQ_DISABLE_STAG_VLAN_INSERTION BIT(37)
>
> /* OS defined structs */
> struct net_device *netdev;
> @@ -344,6 +382,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 & \
> @@ -355,6 +401,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;
> @@ -398,6 +445,7 @@ extern struct workqueue_struct *iavf_wq;
> 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_reset(struct iavf_adapter *adapter);
> void iavf_set_ethtool_ops(struct net_device *netdev);
> @@ -415,6 +463,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);
> @@ -450,10 +501,17 @@ 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_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);
> void iavf_del_adv_rss_cfg(struct iavf_adapter *adapter);
> struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
> const u8 *macaddr);
> +void iavf_set_vlan_offload_features(struct iavf_adapter *adapter,
> + netdev_features_t prev_features,
> + netdev_features_t features);
> #endif /* _IAVF_H_ */
> diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
> index 80437ef26..392039ec7 100644
> --- a/drivers/net/ethernet/intel/iavf/iavf_main.c
> +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
> @@ -624,14 +624,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;
> }
>
> @@ -643,7 +646,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;
>
> @@ -672,7 +676,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;
>
> @@ -696,12 +700,70 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, u16 vlan)
> static void iavf_restore_filters(struct iavf_adapter *adapter)
> {
> /* re-add all VLAN filters */
> - if (VLAN_ALLOWED(adapter)) {
> +#ifdef HAVE_VLAN_RX_REGISTER
> + if (adapter->vsi.vlgrp)
> + iavf_vlan_rx_register(adapter->netdev, adapter->vsi.vlgrp);
> +#else /* HAVE_VLAN_RX_REGISTER */
What is this HAVE_VLAN_RX_REGISTER? This has no place in upstream code.
Please remove it.
> + if (VLAN_FILTERING_ALLOWED(adapter)) {
> u16 vid;
>
> - 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));
> }
> +
> +#endif /* HAVE_VLAN_RX_REGISTER */
> +#ifndef EXTERNAL_RELEASE
> + /* TODO: Add code to restore Cloud filters, since they will be
> + * deleted as well during netdev link down...
> + */
> +#endif
This block needs to be removed, please fix it.
> +}
> +
> +/**
> + * 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;
> }
>
> /**
> @@ -710,20 +772,53 @@ static void iavf_restore_filters(struct iavf_adapter *adapter)
> * @proto: unused protocol data
> * @vid: VLAN tag
> **/
> +#ifdef NETIF_F_HW_VLAN_CTAG_RX
This needs to be removed, please fix it.
> static int iavf_vlan_rx_add_vid(struct net_device *netdev,
> __always_unused __be16 proto, u16 vid)
> {
> struct iavf_adapter *adapter = netdev_priv(netdev);
> +#ifdef NETIF_F_HW_VLAN_CTAG_RX
> + u16 local_vlan_proto = be16_to_cpu(proto);
> +#else
> + u16 local_vlan_proto = ETH_P_8021Q;
> +#endif
This needs to be removed, please fix it.
>
> - 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, local_vlan_proto)))
> return -ENOMEM;
>
> - set_bit(vid, adapter->vsi.active_vlans);
> + if (local_vlan_proto == ETH_P_8021Q)
> + set_bit(vid, adapter->vsi.active_cvlans);
> + else
> + set_bit(vid, adapter->vsi.active_svlans);
> +
> return 0;
> }
> +#else
> +static int iavf_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
> +{
> + struct iavf_adapter *adapter = netdev_priv(netdev);
> +
> + if (!VLAN_FILTERING_ALLOWED(adapter))
> + return;
> +
> + 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;
> + }
> +
> + iavf_add_vlan(adapter, IAVF_VLAN(vid, ETH_P_8021Q));
> + set_bit(vid, adapter->vsi.active_cvlans);
> +}
> +#endif
>
> /**
> * iavf_vlan_rx_kill_vid - Remove a VLAN filter from a device
> @@ -731,19 +826,36 @@ static int iavf_vlan_rx_add_vid(struct net_device *netdev,
> * @proto: unused protocol data
> * @vid: VLAN tag
> **/
> +#ifdef NETIF_F_HW_VLAN_CTAG_RX
This needs to be removed, please fix it.
> static int iavf_vlan_rx_kill_vid(struct net_device *netdev,
> - __always_unused __be16 proto, u16 vid)
> + __always_unused __be16 proto, u16 vid)
> {
> struct iavf_adapter *adapter = netdev_priv(netdev);
> + u16 local_vlan_proto = be16_to_cpu(proto);
>
> - if (!VLAN_ALLOWED(adapter))
> + if (!VLAN_FILTERING_ALLOWED(adapter))
> return -EIO;
>
> - iavf_del_vlan(adapter, vid);
> - clear_bit(vid, adapter->vsi.active_vlans);
> + iavf_del_vlan(adapter, IAVF_VLAN(vid, local_vlan_proto));
> + if (local_vlan_proto == ETH_P_8021Q)
> + clear_bit(vid, adapter->vsi.active_cvlans);
> + else
> + clear_bit(vid, adapter->vsi.active_svlans);
>
> return 0;
> }
> +#else
> +static void iavf_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
> +{
> + struct iavf_adapter *adapter = netdev_priv(netdev);
> +
> + if (!VLAN_FILTERING_ALLOWED(adapter))
> + return;
> +
> + iavf_del_vlan(adapter, IAVF_VLAN(vid, ETH_P_8021Q));
> + clear_bit(vid, adapter->vsi.active_cvlans);
> +}
> +#endif
>
> /**
> * iavf_find_filter - Search filter list for specific mac filter
> @@ -1134,6 +1246,85 @@ 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
> @@ -1195,6 +1386,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:
> @@ -1554,6 +1747,211 @@ err:
> return err;
> }
>
> +/**
> + * 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;
> +
> +#ifdef NETIF_F_HW_VLAN_CTAG_RX
This needs to be removed, please fix it.
> + /* 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;
> +#else
> + if (features & (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX))
> + vlan_ethertype = ETH_P_8021Q;
> + if (prev_features & (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX))
> + vlan_ethertype = ETH_P_8021Q;
> + else
> + vlan_ethertype = ETH_P_8021Q;
> +
> + if (!(features & NETIF_F_HW_VLAN_RX))
> + enable_stripping = false;
> + if (!(features & NETIF_F_HW_VLAN_TX))
> + enable_insertion = false;
> +#endif
> + 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_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 ret;
> +
> + 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;
> +
> + netdev->netdev_ops = &iavf_netdev_ops;
> +
> + iavf_set_ethtool_ops(netdev);
> + netdev->watchdog_timeo = 5 * HZ;
> +
> + netdev->min_mtu = ETH_MIN_MTU;
> + netdev->max_mtu = IAVF_MAX_RXBUFFER - IAVF_PACKET_HDR_PAD;
> +
> + if (!is_valid_ether_addr(adapter->hw.mac.addr)) {
> + dev_info(&pdev->dev, "Invalid MAC address %pM, using random\n",
> + adapter->hw.mac.addr);
> + eth_hw_addr_random(netdev);
> + ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
> + } else {
> + ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr);
> + ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr);
> + }
> +
> + adapter->flags |= IAVF_FLAG_INITIAL_MAC_SET;
> +
> + adapter->tx_desc_count = IAVF_DEFAULT_TXD;
> + adapter->rx_desc_count = IAVF_DEFAULT_RXD;
> + ret = iavf_init_interrupt_scheme(adapter);
> + if (ret)
> + goto err_sw_init;
> + iavf_map_rings_to_vectors(adapter);
> + if (adapter->vf_res->vf_cap_flags &
> + VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
> + adapter->flags |= IAVF_FLAG_WB_ON_ITR_CAPABLE;
> +
> + ret = iavf_request_misc_irq(adapter);
> + if (ret)
> + goto err_sw_init;
> +
> + netif_carrier_off(netdev);
> + adapter->link_up = false;
> +
> + if (!adapter->netdev_registered) {
> + ret = register_netdev(netdev);
> + if (ret)
> + goto err_register;
> + }
> +
> + adapter->netdev_registered = true;
> +
> + netif_tx_stop_all_queues(netdev);
> + dev_info(&pdev->dev, "MAC address: %pM\n", adapter->hw.mac.addr);
> + if (netdev->features & NETIF_F_GRO)
> + dev_info(&pdev->dev, "GRO is enabled\n");
> +
> + iavf_change_state(adapter, __IAVF_DOWN);
> + set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
> +
> + iavf_misc_irq_enable(adapter);
> + wake_up(&adapter->down_waitqueue);
> +
> + adapter->rss_key = (u8 *)kzalloc(adapter->rss_key_size, GFP_KERNEL);
> + adapter->rss_lut = (u8 *)kzalloc(adapter->rss_lut_size, GFP_KERNEL);
> + if (!adapter->rss_key || !adapter->rss_lut)
> + goto err_mem;
> + if (RSS_AQ(adapter))
> + adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_RSS;
> + else
> + iavf_init_rss(adapter);
> +
> + /* request initial VLAN offload settings */
> + iavf_set_vlan_offload_features(adapter, 0, netdev->features);
This should be:
if (VLAN_V2_ALLOWED(adapter))
/* request initial VLAN offload settings */
iavf_set_vlan_offload_features(adapter, 0, netdev->features);
This is beacause for VIRTCHNL_VF_OFFLOAD_VLAN the iavf assumed the
VLAN offloads were configured by the PF. However, this was changed for V2, but
we don't want to change the functionality for the old offload.
> +
> + return;
> +err_mem:
> + iavf_free_rss(adapter);
> +err_register:
> + iavf_free_misc_irq(adapter);
> +err_sw_init:
> + iavf_reset_interrupt_capability(adapter);
> +err:
> + iavf_change_state(adapter, __IAVF_INIT_FAILED);
> +}
> +
> /**
> * iavf_process_aq_command - process aq_required flags
> * and sends aq command
> @@ -1700,6 +2098,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 IAVF_SUCCESS;
> + }
> + if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_STAG_VLAN_STRIPPING) {
> + iavf_disable_vlan_stripping_v2(adapter, ETH_P_8021AD);
> + return IAVF_SUCCESS;
> + }
> + if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_STRIPPING) {
> + iavf_enable_vlan_stripping_v2(adapter, ETH_P_8021Q);
> + return IAVF_SUCCESS;
> + }
> + if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_STAG_VLAN_STRIPPING) {
> + iavf_enable_vlan_stripping_v2(adapter, ETH_P_8021AD);
> + return IAVF_SUCCESS;
> + }
> + if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_INSERTION) {
> + iavf_disable_vlan_insertion_v2(adapter, ETH_P_8021Q);
> + return IAVF_SUCCESS;
> + }
> + if (adapter->aq_required & IAVF_FLAG_AQ_DISABLE_STAG_VLAN_INSERTION) {
> + iavf_disable_vlan_insertion_v2(adapter, ETH_P_8021AD);
> + return IAVF_SUCCESS;
> + },
> + if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_INSERTION) {
> + iavf_enable_vlan_insertion_v2(adapter, ETH_P_8021Q);
> + return IAVF_SUCCESS;
> + }
> + if (adapter->aq_required & IAVF_FLAG_AQ_ENABLE_STAG_VLAN_INSERTION) {
> + iavf_enable_vlan_insertion_v2(adapter, ETH_P_8021AD);
> + return IAVF_SUCCESS;
> + }
> +
These new aq_required checks need to go before the IAVF_FLAG_AQ_REQUEST_STATS,
otherwise, the VLAN add/del offload enable/disable are blocked out by periodic stats requests.
> return -EAGAIN;
> }
>
> @@ -1803,6 +2234,59 @@ err:
> return err;
> }
>
> +/**
> + * 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_MSIX_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
> @@ -1814,10 +2298,10 @@ err:
> **/
> static int 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;
> + int ret;
>
> WARN_ON(adapter->state != __IAVF_INIT_GET_RESOURCES);
> /* aq msg sent, awaiting reply */
> @@ -1832,7 +2316,7 @@ static int 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
> @@ -1847,103 +2331,18 @@ static int iavf_init_get_resources(struct iavf_adapter *adapter)
> goto err_alloc;
> }
>
> - err = iavf_process_config(adapter);
> - if (err)
> + ret = iavf_parse_vf_resource_msg(adapter);
> + if (ret) {
> + dev_err(&pdev->dev, "Failed to parse VF resource message from PF (%d)\n",
> + ret);
> goto err_alloc;
> - adapter->current_op = VIRTCHNL_OP_UNKNOWN;
> -
> - adapter->flags |= IAVF_FLAG_RX_CSUM_ENABLED;
> -
> - netdev->netdev_ops = &iavf_netdev_ops;
> - iavf_set_ethtool_ops(netdev);
> - netdev->watchdog_timeo = 5 * HZ;
> -
> - /* MTU range: 68 - 9710 */
> - netdev->min_mtu = ETH_MIN_MTU;
> - netdev->max_mtu = IAVF_MAX_RXBUFFER - IAVF_PACKET_HDR_PAD;
> -
> - if (!is_valid_ether_addr(adapter->hw.mac.addr)) {
> - dev_info(&pdev->dev, "Invalid MAC address %pM, using random\n",
> - adapter->hw.mac.addr);
> - eth_hw_addr_random(netdev);
> - ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
> - } else {
> - ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr);
> - ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr);
> - }
> -
> - adapter->tx_desc_count = IAVF_DEFAULT_TXD;
> - adapter->rx_desc_count = IAVF_DEFAULT_RXD;
> - err = iavf_init_interrupt_scheme(adapter);
> - if (err)
> - goto err_sw_init;
> - iavf_map_rings_to_vectors(adapter);
> - if (adapter->vf_res->vf_cap_flags &
> - VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
> - adapter->flags |= IAVF_FLAG_WB_ON_ITR_CAPABLE;
> -
> - err = iavf_request_misc_irq(adapter);
> - if (err)
> - goto err_sw_init;
> -
> - netif_carrier_off(netdev);
> - adapter->link_up = false;
> -
> - /* set the semaphore to prevent any callbacks after device registration
> - * up to time when state of driver will be set to __IAVF_DOWN
> - */
> - rtnl_lock();
> - if (!adapter->netdev_registered) {
> - err = register_netdevice(netdev);
> - if (err) {
> - rtnl_unlock();
> - goto err_register;
> - }
> - }
> -
> - adapter->netdev_registered = true;
> -
> - netif_tx_stop_all_queues(netdev);
> - if (CLIENT_ALLOWED(adapter)) {
> - err = iavf_lan_add_device(adapter);
> - if (err)
> - dev_info(&pdev->dev, "Failed to add VF to client API service list: %d\n",
> - err);
> }
> - dev_info(&pdev->dev, "MAC address: %pM\n", adapter->hw.mac.addr);
> - if (netdev->features & NETIF_F_GRO)
> - dev_info(&pdev->dev, "GRO is enabled\n");
>
> - adapter->state = __IAVF_DOWN;
> - set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
> - rtnl_unlock();
> -
> - iavf_misc_irq_enable(adapter);
> - wake_up(&adapter->down_waitqueue);
> -
> - adapter->rss_key = kzalloc(adapter->rss_key_size, GFP_KERNEL);
> - adapter->rss_lut = kzalloc(adapter->rss_lut_size, GFP_KERNEL);
> - if (!adapter->rss_key || !adapter->rss_lut) {
> - err = -ENOMEM;
> - goto err_mem;
> - }
> - if (RSS_AQ(adapter))
> - adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_RSS;
> - else
> - iavf_init_rss(adapter);
> -
> - return err;
> -err_mem:
> - iavf_free_rss(adapter);
> -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:
> - return err;
> + iavf_change_state(adapter, __IAVF_INIT_FAILED);
> }
>
> /**
> @@ -1998,6 +2397,12 @@ static void iavf_watchdog_task(struct work_struct *work)
> case __IAVF_DOWN:
> case __IAVF_DOWN_PENDING:
> case __IAVF_TESTING:
> + case __IAVF_INIT_CONFIG_ADAPTER:
> + iavf_init_config_adapter(adapter);
> + clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
> + queue_delayed_work(iavf_wq, &adapter->watchdog_task,
> + msecs_to_jiffies(1));
> + return;
> case __IAVF_RUNNING:
> if (adapter->current_op) {
> if (!iavf_asq_done(hw)) {
> @@ -2006,10 +2411,12 @@ 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 (iavf_process_aq_command(adapter) &&
> + if (ret && ret != -EOPNOTSUPP &&
> adapter->state == __IAVF_RUNNING)
> iavf_request_stats(adapter);
> }
> @@ -2770,6 +3177,27 @@ exit:
> return ret;
> }
>
> +/**
> + * iavf_is_vlan_tc_filter_allowed - allowed to add tc-filter using VLAN
> + * @adapter: board private structure
> + * @vlan: VLAN to verify
> + *
> + * Using specified "vlan" ID, there must be active VLAN filter in VF's
> + * MAC-VLAN filter list.
> + */
> +static bool
> +iavf_is_vlan_tc_filter_allowed(struct iavf_adapter *adapter, u16 vlan)
> +{
> + struct iavf_vlan_filter *f;
> + bool allowed;
> +
> + spin_lock_bh(&adapter->mac_vlan_list_lock);
> + f = iavf_find_vlan(adapter, IAVF_VLAN(vlan, ETH_P_8021Q));
> + allowed = (f && !f->add && !f->remove);
> + spin_unlock_bh(&adapter->mac_vlan_list_lock);
> + return allowed;
> +}
> +
It doesn't seem like this change is related to VIRTCHNL_VF_OFFLOAD_VLAN_V2.
Why is it part of this patch?
> /**
> * iavf_parse_cls_flower - Parse tc flower filters provided by kernel
> * @adapter: board private structure
> @@ -2782,13 +3210,13 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
> {
> struct flow_rule *rule = flow_cls_offload_flow_rule(f);
> struct flow_dissector *dissector = rule->match.dissector;
> + struct virtchnl_filter *vf = &filter->f;
> u16 n_proto_mask = 0;
> u16 n_proto_key = 0;
> u8 field_flags = 0;
> u16 addr_type = 0;
> u16 n_proto = 0;
> int i = 0;
> - struct virtchnl_filter *vf = &filter->f;
>
> if (dissector->used_keys &
> ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
> @@ -2889,6 +3317,8 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
>
> flow_rule_match_vlan(rule, &match);
> if (match.mask->vlan_id) {
> + u16 vlan = match.key->vlan_id & VLAN_VID_MASK;
> +
> if (match.mask->vlan_id == VLAN_VID_MASK) {
> field_flags |= IAVF_CLOUD_FIELD_IVLAN;
> } else {
> @@ -2896,6 +3326,12 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
> match.mask->vlan_id);
> return -EINVAL;
> }
> + if (!iavf_is_vlan_tc_filter_allowed(adapter, vlan)) {
> + dev_err(&adapter->pdev->dev,
> + "VLAN %u doesn't belong to this VF\n",
> + vlan);
> + return -EINVAL;
> + }
> }
> vf->mask.tcp_spec.vlan_id |= cpu_to_be16(0xffff);
> vf->data.tcp_spec.vlan_id = cpu_to_be16(match.key->vlan_id);
> @@ -3373,6 +3809,11 @@ static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
> return 0;
> }
Why are all these changes part of this patch? I don't think they belong as they seem to
be unrelated other than they are dealing with VLANs.
>
> +#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
> @@ -3384,20 +3825,11 @@ static int iavf_set_features(struct net_device *netdev,
> {
> struct iavf_adapter *adapter = netdev_priv(netdev);
>
> - /* Don't allow changing VLAN_RX flag when adapter is not capable
> - * of VLAN offload
> - */
> - if (!VLAN_ALLOWED(adapter)) {
> - if ((netdev->features ^ features) & NETIF_F_HW_VLAN_CTAG_RX)
> - 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;
> }
> @@ -3460,6 +3892,55 @@ out_err:
> return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
> }
>
> +/**
> + * iavf_get_netdev_vlan_hw_features - get NETDEV VLAN features
> + * @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 |= (IAVF_NETIF_F_HW_VLAN_CTAG_TX |
> + IAVF_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 |= IAVF_NETIF_F_HW_VLAN_CTAG_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 |= IAVF_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 |= IAVF_NETIF_F_HW_VLAN_CTAG_TX;
> + } else if (insertion_support->inner &&
> + insertion_support->inner & VIRTCHNL_VLAN_TOGGLE) {
> + if (insertion_support->inner & VIRTCHNL_VLAN_ETHERTYPE_8100)
> + hw_features |= IAVF_NETIF_F_HW_VLAN_CTAG_TX;
> + }
> + }
All the checks for VIRTCHNL_VLAN_ETHERTYPE_88A8 were left out. Please fix that.
> +
> + return hw_features;
> +}
> /**
> * iavf_fix_features - fix up the netdev feature bits
Where are the changes for iavf_fix_netdev_vlan_features()? These are
missing from this patch.
> * @netdev: our net device
> @@ -3530,39 +4011,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;
> struct net_device *netdev = adapter->netdev;
> - struct iavf_vsi *vsi = &adapter->vsi;
> + netdev_features_t hw_vlan_features;
> 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 |
> @@ -3606,6 +4059,9 @@ int iavf_process_config(struct iavf_adapter *adapter)
> */
> hw_features = hw_enc_features;
>
> + /* get HW VLAN features that can be toggled */
> + hw_vlan_features = iavf_get_netdev_vlan_hw_features(adapter);
> +
> /* Enable VLAN features if supported */
> if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN)
> hw_features |= (NETIF_F_HW_VLAN_CTAG_TX |
> @@ -3643,21 +4099,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;
> }
>
> diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
> index 3525eab8e..e253c32d1 100644
> --- a/drivers/net/ethernet/intel/iavf/iavf_txrx.c
> +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
> @@ -861,12 +861,39 @@ static void iavf_receive_skb(struct iavf_ring *rx_ring,
> struct sk_buff *skb, u16 vlan_tag)
> {
> struct iavf_q_vector *q_vector = rx_ring->q_vector;
> +#ifdef HAVE_VLAN_RX_REGISTER
> + struct iavf_vsi *vsi = rx_ring->vsi;
> +#endif
HAVE_VLAN_RX_REGISTER does not belong here, remove it please.
>
> - 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);
> +#ifdef HAVE_VLAN_RX_REGISTER
> + if (vlan_tag & VLAN_VID_MASK) {
> + if (!vsi->vlgrp)
> + dev_kfree_skb_any(skb);
> + else
> + vlan_gro_receive(&q_vector->napi, vsi->vlgrp,
> + vlan_tag, skb);
> + }
> +#else /* HAVE_VLAN_RX_REGISTER */
> + if (vlan_tag & VLAN_VID_MASK) {
> + if (rx_ring->netdev->features & IAVF_NETIF_F_HW_VLAN_CTAG_RX) {
> + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
> + vlan_tag);
> +#ifdef IAVF_ADD_PROBES
> + rx_ring->vsi->back->rx_vlano++;
> +#endif /* IAVF_ADD_PROBES */
IAVF_ADD_PROBES does not belong here, remove it and the included code please.
> +#ifdef NETIF_F_HW_VLAN_STAG_RX
> + } else if (rx_ring->netdev->features & NETIF_F_HW_VLAN_STAG_RX) {
> + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021AD),
> + vlan_tag);
> +#ifdef IAVF_ADD_PROBES
> + rx_ring->vsi->back->rx_ad_vlano++;
> +#endif /* IAVF_ADD_PROBES */
IAVF_ADD_PROBES does not belong here, remove it and the included code please.
> +#endif /* NETIF_F_HW_VLAN_STAG_RX */
NETIF_F_HW_VLAN_STAG_RX does not belong here, remove it and the included
code please.
> + }
> + }
>
> napi_gro_receive(&q_vector->napi, skb);
> +#endif /* HAVE_VLAN_RX_REGISTER */
> }
>
> /**
> @@ -1468,7 +1495,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;
>
> @@ -1781,46 +1808,36 @@ 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,
> +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;
> - }
> + /* stack will only request hardware VLAN insertion offload for protocols
> + * that the driver supports and has enabled
> + */
> + if (!skb_vlan_tag_present(skb))
> + return;
>
> - /* if we have a HW VLAN tag being added, default to the HW one */
> - if (skb_vlan_tag_present(skb)) {
> - tx_flags |= skb_vlan_tag_get(skb) << IAVF_TX_FLAGS_VLAN_SHIFT;
> + tx_flags |= 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;
> }
> +#ifdef IAVF_ADD_PROBES
> + if (tx_ring->netdev->features & IAVF_NETIF_F_HW_VLAN_CTAG_TX)
> + tx_ring->vsi->back->tx_vlano++;
> + else
> + tx_ring->vsi->back->tx_ad_vlano++;
> +#endif
Remove IAVF_ADD_PROBES and the inlcuded code please.
>
> -out:
> *flags = tx_flags;
> - return 0;
> +
> }
>
> /**
> @@ -2440,8 +2457,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);
> diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.h b/drivers/net/ethernet/intel/iavf/iavf_txrx.h
> index e5b9ba42d..2624bf6d0 100644
> --- a/drivers/net/ethernet/intel/iavf/iavf_txrx.h
> +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.h
> @@ -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;
> diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
> index 9c128462e..5a696f43b 100644
> --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
> +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
> @@ -54,6 +54,36 @@ int iavf_send_api_ver(struct iavf_adapter *adapter)
> sizeof(vvi));
> }
>
> +/**
> + * iavf_poll_virtchnl_msg - poll for virtchnl msg matching the requested_op
> + * @hw: HW configuration structure
> + * @event: event to populate on success
> + * @op_to_poll: requested virtchnl op to poll for
> + */
> +static int
> +iavf_poll_virtchnl_msg(struct iavf_hw *hw, struct iavf_arq_event_info *event,
> + enum virtchnl_ops op_to_poll)
> +{
> + enum virtchnl_ops received_op;
> + enum iavf_status status;
> +
> + while (1) {
> + /* When the AQ is empty, iavf_clean_arq_element will return
> + * nonzero and this loop will terminate.
> + */
> + status = iavf_clean_arq_element(hw, event, NULL);
> + if (status != IAVF_SUCCESS)
> + return status;
> + received_op =
> + (enum virtchnl_ops)le32_to_cpu(event->desc.cookie_high);
> + if (op_to_poll == received_op)
> + break;
> + }
> +
> + status = (enum iavf_status)le32_to_cpu(event->desc.cookie_low);
> + return status;
> +}
> +
> /**
> * iavf_verify_api_ver
> * @adapter: adapter structure
> @@ -134,6 +164,7 @@ int iavf_send_vf_config_msg(struct iavf_adapter *adapter)
> VIRTCHNL_VF_OFFLOAD_RSS_AQ |
> VIRTCHNL_VF_OFFLOAD_RSS_REG |
> VIRTCHNL_VF_OFFLOAD_VLAN |
> + VIRTCHNL_VF_OFFLOAD_VLAN_V2 |
> VIRTCHNL_VF_OFFLOAD_WB_ON_ITR |
> VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 |
> VIRTCHNL_VF_OFFLOAD_ENCAP |
> @@ -155,6 +186,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 +279,28 @@ out:
> return err;
> }
>
> +int iavf_get_vf_vlan_v2_caps(struct iavf_adapter *adapter)
> +{
> + struct iavf_arq_event_info event;
> + int err;
> + u16 len;
> +
> + len = sizeof(struct virtchnl_vlan_caps);
> + event.buf_len = len;
> + event.msg_buf = (u8 *)kzalloc(len, GFP_KERNEL);
> + if (!event.msg_buf)
> + return -ENOMEM;
> +
> + err = iavf_poll_virtchnl_msg(&adapter->hw, &event,
> + VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS);
> + if (!err)
> + memcpy(&adapter->vlan_v2_caps, event.msg_buf,
> + min(event.msg_len, len));
> +
> + kfree(event.msg_buf);
> + return err;
> +}
> +
> /**
> * iavf_configure_queues
> * @adapter: adapter structure
> @@ -589,7 +655,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;
> @@ -612,45 +677,103 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
> spin_unlock_bh(&adapter->mac_vlan_list_lock);
> return;
> }
The check above for "if (count)" should be changed to the following to prevent
a sparse bug:
if (!count || !VLAN_FILTERING_ALLOWED(adapter)) {
/* prevent endless add VLAN requests */
...
}
> - adapter->current_op = VIRTCHNL_OP_ADD_VLAN;
>
> - len = sizeof(struct virtchnl_vlan_filter_list) +
> - (count * sizeof(u16));
> - if (len > IAVF_MAX_AQ_BUF_SIZE) {
> + if (VLAN_ALLOWED(adapter)) {
> + struct virtchnl_vlan_filter_list *vvfl;
> +
> + adapter->current_op = VIRTCHNL_OP_ADD_VLAN;
> +
> + len = sizeof(*vvfl) + (count * sizeof(u16));
> + if (len > IAVF_MAX_AQ_BUF_SIZE) {
> dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n");
> - count = (IAVF_MAX_AQ_BUF_SIZE -
> - sizeof(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) {
> + count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(*vvfl)) /
> + sizeof(u16);
> + len = sizeof(*vvfl) + (count * sizeof(u16));
> + more = true;
> + }
> + if (!vvfl) {
> + spin_unlock_bh(&adapter->mac_vlan_list_lock);
> + return;
> + }
> +
> + vvfl->vsi_id = adapter->vsi_res->vsi_id;
> + vvfl->num_elements = count;
> + list_for_each_entry(f, &adapter->vlan_filter_list, list) {
> + if (f->add) {
> + vvfl->vlan_id[i] = f->vlan.vid;
> + i++;
> + f->add = false;
> + if (i == count)
> + break;
> + }
> + }
> + if (!more)
> + adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_VLAN_FILTER;
> +
> spin_unlock_bh(&adapter->mac_vlan_list_lock);
> - return;
> - }
>
> - vvfl->vsi_id = adapter->vsi_res->vsi_id;
> - vvfl->num_elements = count;
> - list_for_each_entry(f, &adapter->vlan_filter_list, list) {
> - if (f->add) {
> - vvfl->vlan_id[i] = f->vlan;
> - i++;
> - f->add = false;
> - if (i == count)
> - break;
> + iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len);
> + kfree(vvfl);
> + } else if (VLAN_V2_ALLOWED(adapter)) {
This "else if (VLAN_V2_ALLOWED(adapter))" should just be changed to:
} else {
> + struct virtchnl_vlan_filter_list_v2 *vvfl_v2;
> +
> + adapter->current_op = VIRTCHNL_OP_ADD_VLAN_V2;
> +
> + len = sizeof(*vvfl_v2) + ((count - 1) *
> + sizeof(struct virtchnl_vlan_filter));
> + if (len > IAVF_MAX_AQ_BUF_SIZE) {
> + dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n");
> + count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(*vvfl_v2)) /
> + sizeof(struct virtchnl_vlan_filter);
> + len = sizeof(*vvfl_v2) +
> + ((count - 1) *
> + sizeof(struct virtchnl_vlan_filter));
> + more = true;
> }
> - }
> - if (!more)
> - adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_VLAN_FILTER;
>
> - spin_unlock_bh(&adapter->mac_vlan_list_lock);
> + vvfl_v2 = (struct virtchnl_vlan_filter_list_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;
>
> - iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len);
> - kfree(vvfl);
> + 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);
> + }
> }
>
> +
> /**
> * iavf_del_vlans
> * @adapter: adapter structure
> @@ -659,7 +782,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;
> @@ -682,44 +804,105 @@ void iavf_del_vlans(struct iavf_adapter *adapter)
> spin_unlock_bh(&adapter->mac_vlan_list_lock);
> return;
> }
> - adapter->current_op = VIRTCHNL_OP_DEL_VLAN;
>
> - len = sizeof(struct virtchnl_vlan_filter_list) +
> - (count * sizeof(u16));
> - if (len > IAVF_MAX_AQ_BUF_SIZE) {
> - dev_warn(&adapter->pdev->dev, "Too many delete VLAN changes in one request\n");
> - count = (IAVF_MAX_AQ_BUF_SIZE -
> - sizeof(struct virtchnl_vlan_filter_list)) /
> - sizeof(u16);
> - len = sizeof(struct virtchnl_vlan_filter_list) +
> - (count * sizeof(u16));
> - more = true;
> - }
> - vvfl = kzalloc(len, GFP_ATOMIC);
> - if (!vvfl) {
> + if (VLAN_ALLOWED(adapter)) {
> + struct virtchnl_vlan_filter_list *vvfl;
> +
> + adapter->current_op = VIRTCHNL_OP_DEL_VLAN;
> +
> + len = sizeof(*vvfl) + (count * sizeof(u16));
> + if (len > IAVF_MAX_AQ_BUF_SIZE) {
> + dev_warn(&adapter->pdev->dev, "Too many delete VLAN changes in one request\n");
> + count = (IAVF_MAX_AQ_BUF_SIZE - sizeof(*vvfl)) /
> + sizeof(u16);
> + len = sizeof(*vvfl) + (count * sizeof(u16));
> + more = true;
> + }
> + vvfl = (struct virtchnl_vlan_filter_list *)
> + kzalloc(len, GFP_ATOMIC);
> + if (!vvfl) {
> + spin_unlock_bh(&adapter->mac_vlan_list_lock);
> + return;
> + }
> +
> + vvfl->vsi_id = adapter->vsi_res->vsi_id;
> + vvfl->num_elements = count;
> + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
> + if (f->remove) {
> + vvfl->vlan_id[i] = f->vlan.vid;
> + i++;
> + list_del(&f->list);
> + kfree(f);
> + if (i == count)
> + break;
> + }
> + }
> +
> + if (!more)
> + adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_VLAN_FILTER;
> +
> spin_unlock_bh(&adapter->mac_vlan_list_lock);
> - return;
> - }
>
> - vvfl->vsi_id = adapter->vsi_res->vsi_id;
> - vvfl->num_elements = count;
> - list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
> - if (f->remove) {
> - vvfl->vlan_id[i] = f->vlan;
> - i++;
> - list_del(&f->list);
> - kfree(f);
> - if (i == count)
> - break;
> + iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len);
> + kfree(vvfl);
> + } else if (VLAN_V2_ALLOWED(adapter)) {
> + struct virtchnl_vlan_filter_list_v2 *vvfl_v2;
> +
> + adapter->current_op = VIRTCHNL_OP_DEL_VLAN_V2;
> +
> + len = sizeof(*vvfl_v2) +
> + ((count - 1) * sizeof(struct virtchnl_vlan_filter));
> + if (len > IAVF_MAX_AQ_BUF_SIZE) {
> + dev_warn(&adapter->pdev->dev, "Too many add VLAN changes in one request\n");
> + count = (IAVF_MAX_AQ_BUF_SIZE -
> + sizeof(*vvfl_v2)) /
> + sizeof(struct virtchnl_vlan_filter);
> + len = sizeof(*vvfl_v2) +
> + ((count - 1) *
> + sizeof(struct virtchnl_vlan_filter));
> + more = true;
> }
> - }
> - if (!more)
> - adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_VLAN_FILTER;
>
> - spin_unlock_bh(&adapter->mac_vlan_list_lock);
> + vvfl_v2 = (struct virtchnl_vlan_filter_list_v2 *)
> + kzalloc(len, GFP_ATOMIC);
> + if (!vvfl_v2) {
> + spin_unlock_bh(&adapter->mac_vlan_list_lock);
> + return;
> + }
> +
> + vvfl_v2->vport_id = adapter->vsi_res->vsi_id;
> + vvfl_v2->num_elements = count;
> + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
> + if (f->remove) {
> + struct virtchnl_vlan_supported_caps *filtering_support =
> + &adapter->vlan_v2_caps->filtering.filtering_support;
> + struct virtchnl_vlan *vlan;
> +
> + /* give priority over outer if it's enabled */
> + if (filtering_support->outer)
> + vlan = &vvfl_v2->filters[i].outer;
> + else
> + vlan = &vvfl_v2->filters[i].inner;
> +
> + vlan->tci = f->vlan.vid;
> + vlan->tpid = f->vlan.tpid;
> +
> + list_del(&f->list);
> + kfree(f);
> + i++;
> + if (i == count)
> + break;
> + }
> + }
> + if (!more)
> + adapter->aq_required &= ~IAVF_FLAG_AQ_DEL_VLAN_FILTER;
> +
> + spin_unlock_bh(&adapter->mac_vlan_list_lock);
>
> - iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_VLAN, (u8 *)vvfl, len);
> - kfree(vvfl);
> + iavf_send_pf_msg(adapter, VIRTCHNL_OP_DEL_VLAN_V2,
> + (u8 *)vvfl_v2, len);
> + kfree(vvfl_v2);
> + }
> }
>
> /**
> @@ -944,6 +1127,202 @@ 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;
> +}
> +
> +/**
> + * ice_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;
> + u32 vc_ethertype = iavf_tpid_to_vc_ethertype(tpid);
> +
> + /* reference the correct offload support structure */
> + switch (offload_op) {
> + case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2:
> + /* fall-through */
> + case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2:
> + offload_support =
> + &adapter->vlan_v2_caps->offloads.stripping_support;
> + break;
> + case VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2:
> + /* fall-through */
> + 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) {
This should be:
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) {
> + msg->inner_ethertype_setting = vc_ethertype;
This should be:
if (offload_support->inner & vc_ethertype &&
offload_support->inner & VIRTCHNL_VLAN_TOGGLE)
> + } else {
> + dev_err(&adapter->pdev->dev, "opcode %d unsupported for VLAN TPID 0x%04x\n",
This should be a dev_dbg()
> + 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 = (struct virtchnl_vlan_setting *)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);
This should be:
/* 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
>
> /**
> @@ -1728,10 +2107,87 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
> ether_addr_copy(netdev->perm_addr,
> adapter->hw.mac.addr);
> }
> + 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;
> + /* fall-through and finish config if VIRTCHNL_VF_OFFLOAD_VLAN_V2
> + * wasn't successfully negotiated with the PF
> + */
> + }
> + /* fall-through */
> + case VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS: {
> + struct iavf_mac_filter *f;
> + bool was_mac_changed;
> +
> + 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);
> + /* Clear 'critical task' bit before acquiring rtnl_lock
> + * as other process holding rtnl_lock could be waiting
> + * for the same bit resulting in deadlock
> + */
> + clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);
> + /* VLAN capabilities can change during VFR, so make sure to
> + * update the netdev features with the new capabilities
> + */
This doesn't exist anymore. It should be:
mutex_unlock(&adapter->crit_lock);
> + rtnl_lock();
> + netdev_update_features(netdev);
> + rtnl_unlock();
> + /* Set 'critical task' bit again */
> + while (test_and_set_bit(__IAVF_IN_CRITICAL_TASK,
> + &adapter->crit_section))
> + usleep_range(500, 1000);
This doesn't exist anymore. It should be:
mutex_lock(&adapter->crit_lock);
> +
> + /* 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);
> +
> + was_mac_changed = !ether_addr_equal(netdev->dev_addr,
> + adapter->hw.mac.addr);
> +
> spin_lock_bh(&adapter->mac_vlan_list_lock);
> - iavf_add_filter(adapter, adapter->hw.mac.addr);
> +
> + /* re-add all MAC filters */
> + list_for_each_entry(f, &adapter->mac_filter_list, list) {
> + if (was_mac_changed &&
> + ether_addr_equal(netdev->dev_addr, f->macaddr))
> + ether_addr_copy(f->macaddr,
> + adapter->hw.mac.addr);
> +
> + f->is_new_mac = true;
> + f->add = true;
> + f->add_handled = false;
> + f->remove = false;
> + }
> +
> + /* re-add all VLAN filters */
> + if (VLAN_FILTERING_ALLOWED(adapter)) {
> + struct iavf_vlan_filter *vlf;
> +
> + list_for_each_entry(vlf, &adapter->vlan_filter_list,
> + list)
> + vlf->add = true;
> + }
> +
> spin_unlock_bh(&adapter->mac_vlan_list_lock);
> - iavf_process_config(adapter);
> +
> + netif_addr_lock_bh(netdev);
> + ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr);
> + netif_addr_unlock_bh(netdev);
> +
> + adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER;
> + adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER;
> }
> break;
> case VIRTCHNL_OP_ENABLE_QUEUES:
> --
> 2.27.0
More information about the Intel-wired-lan
mailing list