Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
authorJakub Kicinski <kuba@kernel.org>
Fri, 11 Mar 2022 01:16:56 +0000 (17:16 -0800)
committerJakub Kicinski <kuba@kernel.org>
Fri, 11 Mar 2022 01:16:56 +0000 (17:16 -0800)
net/dsa/dsa2.c
  commit afb3cc1a397d ("net: dsa: unlock the rtnl_mutex when dsa_master_setup() fails")
  commit e83d56537859 ("net: dsa: replay master state events in dsa_tree_{setup,teardown}_master")
https://lore.kernel.org/all/20220307101436.7ae87da0@canb.auug.org.au/

drivers/net/ethernet/intel/ice/ice.h
  commit 97b0129146b1 ("ice: Fix error with handling of bonding MTU")
  commit 43113ff73453 ("ice: add TTY for GNSS module for E810T device")
https://lore.kernel.org/all/20220310112843.3233bcf1@canb.auug.org.au/

drivers/staging/gdm724x/gdm_lte.c
  commit fc7f750dc9d1 ("staging: gdm724x: fix use after free in gdm_lte_rx()")
  commit 4bcc4249b4cf ("staging: Use netif_rx().")
https://lore.kernel.org/all/20220308111043.1018a59d@canb.auug.org.au/

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
35 files changed:
1  2 
MAINTAINERS
arch/arm64/include/asm/insn.h
arch/x86/kernel/alternative.c
arch/x86/net/bpf_jit_comp.c
drivers/net/dsa/mt7530.c
drivers/net/ethernet/cadence/macb_main.c
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/iavf/iavf.h
drivers/net/ethernet/intel/iavf/iavf_main.c
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
drivers/net/ethernet/intel/ice/ice.h
drivers/net/ethernet/intel/ice/ice_ethtool.c
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
drivers/net/ethernet/marvell/prestera/prestera_main.c
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c
drivers/net/ethernet/qlogic/qed/qed_sriov.c
drivers/net/ethernet/xilinx/xilinx_emaclite.c
drivers/net/usb/smsc95xx.c
drivers/spi/spi.c
drivers/staging/gdm724x/gdm_lte.c
include/linux/bpf.h
include/linux/mlx5/mlx5_ifc.h
include/linux/netdevice.h
include/linux/phy.h
net/bluetooth/hci_sync.c
net/bluetooth/mgmt.c
net/core/gro.c
net/core/xdp.c
net/dsa/dsa2.c
net/tipc/bearer.c
net/xfrm/xfrm_interface.c

diff --combined MAINTAINERS
@@@ -2572,7 -2572,7 +2572,7 @@@ F:      sound/soc/rockchip
  N:    rockchip
  
  ARM/SAMSUNG S3C, S5P AND EXYNOS ARM ARCHITECTURES
- M:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ M:    Krzysztof Kozlowski <krzk@kernel.org>
  R:    Alim Akhtar <alim.akhtar@samsung.com>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  L:    linux-samsung-soc@vger.kernel.org
@@@ -2739,7 -2739,7 +2739,7 @@@ N:      stm3
  N:    stm
  
  ARM/Synaptics SoC support
- M:    Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+ M:    Jisheng Zhang <jszhang@kernel.org>
  M:    Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
@@@ -3527,8 -3527,6 +3527,8 @@@ F:      net/sched/act_bpf.
  F:    net/sched/cls_bpf.c
  F:    samples/bpf/
  F:    scripts/bpf_doc.py
 +F:    scripts/pahole-flags.sh
 +F:    scripts/pahole-version.sh
  F:    tools/bpf/
  F:    tools/lib/bpf/
  F:    tools/testing/selftests/bpf/
@@@ -3907,7 -3905,7 +3907,7 @@@ M:      Scott Branden <sbranden@broadcom.com
  M:    bcm-kernel-feedback-list@broadcom.com
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
- T:    git git://github.com/broadcom/cygnus-linux.git
+ T:    git git://github.com/broadcom/stblinux.git
  F:    arch/arm64/boot/dts/broadcom/northstar2/*
  F:    arch/arm64/boot/dts/broadcom/stingray/*
  F:    drivers/clk/bcm/clk-ns*
@@@ -7932,12 -7930,6 +7932,12 @@@ L:    platform-driver-x86@vger.kernel.or
  S:    Maintained
  F:    drivers/platform/x86/fujitsu-tablet.c
  
 +FUNGIBLE ETHERNET DRIVERS
 +M:    Dimitris Michailidis <dmichail@fungible.com>
 +L:    netdev@vger.kernel.org
 +S:    Supported
 +F:    drivers/net/ethernet/fungible/
 +
  FUSE: FILESYSTEM IN USERSPACE
  M:    Miklos Szeredi <miklos@szeredi.hu>
  L:    linux-fsdevel@vger.kernel.org
@@@ -11683,7 -11675,7 +11683,7 @@@ F:   drivers/iio/proximity/mb1232.
  
  MAXIM MAX17040 FAMILY FUEL GAUGE DRIVERS
  R:    Iskren Chernev <iskren.chernev@gmail.com>
- R:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ R:    Krzysztof Kozlowski <krzk@kernel.org>
  R:    Marek Szyprowski <m.szyprowski@samsung.com>
  R:    Matheus Castello <matheus@castello.eng.br>
  L:    linux-pm@vger.kernel.org
@@@ -11693,7 -11685,7 +11693,7 @@@ F:   drivers/power/supply/max17040_batter
  
  MAXIM MAX17042 FAMILY FUEL GAUGE DRIVERS
  R:    Hans de Goede <hdegoede@redhat.com>
- R:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ R:    Krzysztof Kozlowski <krzk@kernel.org>
  R:    Marek Szyprowski <m.szyprowski@samsung.com>
  R:    Sebastian Krzyszkowiak <sebastian.krzyszkowiak@puri.sm>
  R:    Purism Kernel Team <kernel@puri.sm>
@@@ -11738,7 -11730,7 +11738,7 @@@ F:   Documentation/devicetree/bindings/po
  F:    drivers/power/supply/max77976_charger.c
  
  MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS
- M:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ M:    Krzysztof Kozlowski <krzk@kernel.org>
  M:    Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
  L:    linux-pm@vger.kernel.org
  S:    Supported
@@@ -11747,7 -11739,7 +11747,7 @@@ F:   drivers/power/supply/max77693_charge
  
  MAXIM PMIC AND MUIC DRIVERS FOR EXYNOS BASED BOARDS
  M:    Chanwoo Choi <cw00.choi@samsung.com>
- M:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ M:    Krzysztof Kozlowski <krzk@kernel.org>
  M:    Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
  L:    linux-kernel@vger.kernel.org
  S:    Supported
@@@ -12436,7 -12428,7 +12436,7 @@@ F:   include/linux/memblock.
  F:    mm/memblock.c
  
  MEMORY CONTROLLER DRIVERS
- M:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ M:    Krzysztof Kozlowski <krzk@kernel.org>
  L:    linux-kernel@vger.kernel.org
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl.git
@@@ -13573,7 -13565,7 +13573,7 @@@ F:   include/uapi/linux/nexthop.
  F:    net/ipv4/nexthop.c
  
  NFC SUBSYSTEM
- M:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ M:    Krzysztof Kozlowski <krzk@kernel.org>
  L:    linux-nfc@lists.01.org (subscribers-only)
  L:    netdev@vger.kernel.org
  S:    Maintained
@@@ -13887,7 -13879,7 +13887,7 @@@ F:   Documentation/devicetree/bindings/re
  F:    drivers/regulator/pf8x00-regulator.c
  
  NXP PTN5150A CC LOGIC AND EXTCON DRIVER
- M:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ M:    Krzysztof Kozlowski <krzk@kernel.org>
  L:    linux-kernel@vger.kernel.org
  S:    Maintained
  F:    Documentation/devicetree/bindings/extcon/extcon-ptn5150.yaml
@@@ -15313,7 -15305,7 +15313,7 @@@ F:   drivers/pinctrl/renesas
  
  PIN CONTROLLER - SAMSUNG
  M:    Tomasz Figa <tomasz.figa@gmail.com>
- M:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ M:    Krzysztof Kozlowski <krzk@kernel.org>
  M:    Sylwester Nawrocki <s.nawrocki@samsung.com>
  R:    Alim Akhtar <alim.akhtar@samsung.com>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@@ -16378,8 -16370,9 +16378,8 @@@ REALTEK RTL83xx SMI DSA ROUTER CHIP
  M:    Linus Walleij <linus.walleij@linaro.org>
  M:    Alvin Å ipraga <alsi@bang-olufsen.dk>
  S:    Maintained
 -F:    Documentation/devicetree/bindings/net/dsa/realtek-smi.txt
 -F:    drivers/net/dsa/realtek-smi*
 -F:    drivers/net/dsa/rtl83*
 +F:    Documentation/devicetree/bindings/net/dsa/realtek.yaml
 +F:    drivers/net/dsa/realtek/*
  
  REALTEK WIRELESS DRIVER (rtlwifi family)
  M:    Ping-Ke Shih <pkshih@realtek.com>
@@@ -16954,7 -16947,7 +16954,7 @@@ W:   http://www.ibm.com/developerworks/li
  F:    drivers/s390/scsi/zfcp_*
  
  S3C ADC BATTERY DRIVER
- M:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ M:    Krzysztof Kozlowski <krzk@kernel.org>
  L:    linux-samsung-soc@vger.kernel.org
  S:    Odd Fixes
  F:    drivers/power/supply/s3c_adc_battery.c
@@@ -16999,7 -16992,7 +16999,7 @@@ F:   Documentation/admin-guide/LSM/SafeSe
  F:    security/safesetid/
  
  SAMSUNG AUDIO (ASoC) DRIVERS
- M:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ M:    Krzysztof Kozlowski <krzk@kernel.org>
  M:    Sylwester Nawrocki <s.nawrocki@samsung.com>
  L:    alsa-devel@alsa-project.org (moderated for non-subscribers)
  S:    Supported
@@@ -17007,7 -17000,7 +17007,7 @@@ F:   Documentation/devicetree/bindings/so
  F:    sound/soc/samsung/
  
  SAMSUNG EXYNOS PSEUDO RANDOM NUMBER GENERATOR (RNG) DRIVER
- M:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ M:    Krzysztof Kozlowski <krzk@kernel.org>
  L:    linux-crypto@vger.kernel.org
  L:    linux-samsung-soc@vger.kernel.org
  S:    Maintained
@@@ -17042,7 -17035,7 +17042,7 @@@ S:   Maintaine
  F:    drivers/platform/x86/samsung-laptop.c
  
  SAMSUNG MULTIFUNCTION PMIC DEVICE DRIVERS
- M:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ M:    Krzysztof Kozlowski <krzk@kernel.org>
  M:    Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
  L:    linux-kernel@vger.kernel.org
  L:    linux-samsung-soc@vger.kernel.org
@@@ -17068,7 -17061,7 +17068,7 @@@ F:   drivers/media/platform/s3c-camif
  F:    include/media/drv-intf/s3c_camif.h
  
  SAMSUNG S3FWRN5 NFC DRIVER
- M:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ M:    Krzysztof Kozlowski <krzk@kernel.org>
  M:    Krzysztof Opasiak <k.opasiak@samsung.com>
  L:    linux-nfc@lists.01.org (subscribers-only)
  S:    Maintained
@@@ -17090,7 -17083,7 +17090,7 @@@ S:   Supporte
  F:    drivers/media/i2c/s5k5baf.c
  
  SAMSUNG S5P Security SubSystem (SSS) DRIVER
- M:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ M:    Krzysztof Kozlowski <krzk@kernel.org>
  M:    Vladimir Zapolskiy <vz@mleia.com>
  L:    linux-crypto@vger.kernel.org
  L:    linux-samsung-soc@vger.kernel.org
@@@ -17125,7 -17118,7 +17125,7 @@@ F:   include/linux/clk/samsung.
  F:    include/linux/platform_data/clk-s3c2410.h
  
  SAMSUNG SPI DRIVERS
- M:    Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+ M:    Krzysztof Kozlowski <krzk@kernel.org>
  M:    Andi Shyti <andi@etezian.org>
  L:    linux-spi@vger.kernel.org
  L:    linux-samsung-soc@vger.kernel.org
@@@ -21475,7 -21468,6 +21475,6 @@@ THE RES
  M:    Linus Torvalds <torvalds@linux-foundation.org>
  L:    linux-kernel@vger.kernel.org
  S:    Buried alive in reporters
- Q:    http://patchwork.kernel.org/project/LKML/list/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
  F:    *
  F:    */
@@@ -65,6 -65,7 +65,7 @@@ enum aarch64_insn_hint_cr_op 
        AARCH64_INSN_HINT_PSB  = 0x11 << 5,
        AARCH64_INSN_HINT_TSB  = 0x12 << 5,
        AARCH64_INSN_HINT_CSDB = 0x14 << 5,
+       AARCH64_INSN_HINT_CLEARBHB = 0x16 << 5,
  
        AARCH64_INSN_HINT_BTI   = 0x20 << 5,
        AARCH64_INSN_HINT_BTIC  = 0x22 << 5,
@@@ -205,9 -206,7 +206,9 @@@ enum aarch64_insn_ldst_type 
        AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX,
        AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX,
        AARCH64_INSN_LDST_LOAD_EX,
 +      AARCH64_INSN_LDST_LOAD_ACQ_EX,
        AARCH64_INSN_LDST_STORE_EX,
 +      AARCH64_INSN_LDST_STORE_REL_EX,
  };
  
  enum aarch64_insn_adsb_type {
@@@ -282,36 -281,6 +283,36 @@@ enum aarch64_insn_adr_type 
        AARCH64_INSN_ADR_TYPE_ADR,
  };
  
 +enum aarch64_insn_mem_atomic_op {
 +      AARCH64_INSN_MEM_ATOMIC_ADD,
 +      AARCH64_INSN_MEM_ATOMIC_CLR,
 +      AARCH64_INSN_MEM_ATOMIC_EOR,
 +      AARCH64_INSN_MEM_ATOMIC_SET,
 +      AARCH64_INSN_MEM_ATOMIC_SWP,
 +};
 +
 +enum aarch64_insn_mem_order_type {
 +      AARCH64_INSN_MEM_ORDER_NONE,
 +      AARCH64_INSN_MEM_ORDER_ACQ,
 +      AARCH64_INSN_MEM_ORDER_REL,
 +      AARCH64_INSN_MEM_ORDER_ACQREL,
 +};
 +
 +enum aarch64_insn_mb_type {
 +      AARCH64_INSN_MB_SY,
 +      AARCH64_INSN_MB_ST,
 +      AARCH64_INSN_MB_LD,
 +      AARCH64_INSN_MB_ISH,
 +      AARCH64_INSN_MB_ISHST,
 +      AARCH64_INSN_MB_ISHLD,
 +      AARCH64_INSN_MB_NSH,
 +      AARCH64_INSN_MB_NSHST,
 +      AARCH64_INSN_MB_NSHLD,
 +      AARCH64_INSN_MB_OSH,
 +      AARCH64_INSN_MB_OSHST,
 +      AARCH64_INSN_MB_OSHLD,
 +};
 +
  #define       __AARCH64_INSN_FUNCS(abbr, mask, val)                           \
  static __always_inline bool aarch64_insn_is_##abbr(u32 code)          \
  {                                                                     \
@@@ -335,11 -304,6 +336,11 @@@ __AARCH64_INSN_FUNCS(store_post, 0x3FE0
  __AARCH64_INSN_FUNCS(load_post,       0x3FE00C00, 0x38400400)
  __AARCH64_INSN_FUNCS(str_reg, 0x3FE0EC00, 0x38206800)
  __AARCH64_INSN_FUNCS(ldadd,   0x3F20FC00, 0x38200000)
 +__AARCH64_INSN_FUNCS(ldclr,   0x3F20FC00, 0x38201000)
 +__AARCH64_INSN_FUNCS(ldeor,   0x3F20FC00, 0x38202000)
 +__AARCH64_INSN_FUNCS(ldset,   0x3F20FC00, 0x38203000)
 +__AARCH64_INSN_FUNCS(swp,     0x3F20FC00, 0x38208000)
 +__AARCH64_INSN_FUNCS(cas,     0x3FA07C00, 0x08A07C00)
  __AARCH64_INSN_FUNCS(ldr_reg, 0x3FE0EC00, 0x38606800)
  __AARCH64_INSN_FUNCS(ldr_lit, 0xBF000000, 0x18000000)
  __AARCH64_INSN_FUNCS(ldrsw_lit,       0xFF000000, 0x98000000)
@@@ -511,6 -475,13 +512,6 @@@ u32 aarch64_insn_gen_load_store_ex(enu
                                   enum aarch64_insn_register state,
                                   enum aarch64_insn_size_type size,
                                   enum aarch64_insn_ldst_type type);
 -u32 aarch64_insn_gen_ldadd(enum aarch64_insn_register result,
 -                         enum aarch64_insn_register address,
 -                         enum aarch64_insn_register value,
 -                         enum aarch64_insn_size_type size);
 -u32 aarch64_insn_gen_stadd(enum aarch64_insn_register address,
 -                         enum aarch64_insn_register value,
 -                         enum aarch64_insn_size_type size);
  u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst,
                                 enum aarch64_insn_register src,
                                 int imm, enum aarch64_insn_variant variant,
@@@ -571,42 -542,6 +572,42 @@@ u32 aarch64_insn_gen_prefetch(enum aarc
                              enum aarch64_insn_prfm_type type,
                              enum aarch64_insn_prfm_target target,
                              enum aarch64_insn_prfm_policy policy);
 +#ifdef CONFIG_ARM64_LSE_ATOMICS
 +u32 aarch64_insn_gen_atomic_ld_op(enum aarch64_insn_register result,
 +                                enum aarch64_insn_register address,
 +                                enum aarch64_insn_register value,
 +                                enum aarch64_insn_size_type size,
 +                                enum aarch64_insn_mem_atomic_op op,
 +                                enum aarch64_insn_mem_order_type order);
 +u32 aarch64_insn_gen_cas(enum aarch64_insn_register result,
 +                       enum aarch64_insn_register address,
 +                       enum aarch64_insn_register value,
 +                       enum aarch64_insn_size_type size,
 +                       enum aarch64_insn_mem_order_type order);
 +#else
 +static inline
 +u32 aarch64_insn_gen_atomic_ld_op(enum aarch64_insn_register result,
 +                                enum aarch64_insn_register address,
 +                                enum aarch64_insn_register value,
 +                                enum aarch64_insn_size_type size,
 +                                enum aarch64_insn_mem_atomic_op op,
 +                                enum aarch64_insn_mem_order_type order)
 +{
 +      return AARCH64_BREAK_FAULT;
 +}
 +
 +static inline
 +u32 aarch64_insn_gen_cas(enum aarch64_insn_register result,
 +                       enum aarch64_insn_register address,
 +                       enum aarch64_insn_register value,
 +                       enum aarch64_insn_size_type size,
 +                       enum aarch64_insn_mem_order_type order)
 +{
 +      return AARCH64_BREAK_FAULT;
 +}
 +#endif
 +u32 aarch64_insn_gen_dmb(enum aarch64_insn_mb_type type);
 +
  s32 aarch64_get_branch_offset(u32 insn);
  u32 aarch64_set_branch_offset(u32 insn, s32 offset);
  
@@@ -389,7 -389,7 +389,7 @@@ static int emit_indirect(int op, int re
   *
   *   CALL *%\reg
   *
-  * It also tries to inline spectre_v2=retpoline,amd when size permits.
+  * It also tries to inline spectre_v2=retpoline,lfence when size permits.
   */
  static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
  {
        BUG_ON(reg == 4);
  
        if (cpu_feature_enabled(X86_FEATURE_RETPOLINE) &&
-           !cpu_feature_enabled(X86_FEATURE_RETPOLINE_AMD))
+           !cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE))
                return -1;
  
        op = insn->opcode.bytes[0];
        }
  
        /*
-        * For RETPOLINE_AMD: prepend the indirect CALL/JMP with an LFENCE.
+        * For RETPOLINE_LFENCE: prepend the indirect CALL/JMP with an LFENCE.
         */
-       if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_AMD)) {
+       if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE)) {
                bytes[i++] = 0x0f;
                bytes[i++] = 0xae;
                bytes[i++] = 0xe8; /* LFENCE */
@@@ -1102,40 -1102,6 +1102,40 @@@ void *text_poke_kgdb(void *addr, const 
        return __text_poke(addr, opcode, len);
  }
  
 +/**
 + * text_poke_copy - Copy instructions into (an unused part of) RX memory
 + * @addr: address to modify
 + * @opcode: source of the copy
 + * @len: length to copy, could be more than 2x PAGE_SIZE
 + *
 + * Not safe against concurrent execution; useful for JITs to dump
 + * new code blocks into unused regions of RX memory. Can be used in
 + * conjunction with synchronize_rcu_tasks() to wait for existing
 + * execution to quiesce after having made sure no existing functions
 + * pointers are live.
 + */
 +void *text_poke_copy(void *addr, const void *opcode, size_t len)
 +{
 +      unsigned long start = (unsigned long)addr;
 +      size_t patched = 0;
 +
 +      if (WARN_ON_ONCE(core_kernel_text(start)))
 +              return NULL;
 +
 +      mutex_lock(&text_mutex);
 +      while (patched < len) {
 +              unsigned long ptr = start + patched;
 +              size_t s;
 +
 +              s = min_t(size_t, PAGE_SIZE * 2 - offset_in_page(ptr), len - patched);
 +
 +              __text_poke((void *)ptr, opcode + patched, s);
 +              patched += s;
 +      }
 +      mutex_unlock(&text_mutex);
 +      return addr;
 +}
 +
  static void do_sync_core(void *info)
  {
        sync_core();
@@@ -330,7 -330,8 +330,7 @@@ static int emit_jump(u8 **pprog, void *
  }
  
  static int __bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
 -                              void *old_addr, void *new_addr,
 -                              const bool text_live)
 +                              void *old_addr, void *new_addr)
  {
        const u8 *nop_insn = x86_nops[5];
        u8 old_insn[X86_PATCH_SIZE];
                goto out;
        ret = 1;
        if (memcmp(ip, new_insn, X86_PATCH_SIZE)) {
 -              if (text_live)
 -                      text_poke_bp(ip, new_insn, X86_PATCH_SIZE, NULL);
 -              else
 -                      memcpy(ip, new_insn, X86_PATCH_SIZE);
 +              text_poke_bp(ip, new_insn, X86_PATCH_SIZE, NULL);
                ret = 0;
        }
  out:
@@@ -380,7 -384,7 +380,7 @@@ int bpf_arch_text_poke(void *ip, enum b
                /* BPF poking in modules is not supported */
                return -EINVAL;
  
 -      return __bpf_arch_text_poke(ip, t, old_addr, new_addr, true);
 +      return __bpf_arch_text_poke(ip, t, old_addr, new_addr);
  }
  
  #define EMIT_LFENCE() EMIT3(0x0F, 0xAE, 0xE8)
@@@ -390,7 -394,7 +390,7 @@@ static void emit_indirect_jump(u8 **ppr
        u8 *prog = *pprog;
  
  #ifdef CONFIG_RETPOLINE
-       if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_AMD)) {
+       if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE)) {
                EMIT_LFENCE();
                EMIT2(0xFF, 0xE0 + reg);
        } else if (cpu_feature_enabled(X86_FEATURE_RETPOLINE)) {
@@@ -554,15 -558,24 +554,15 @@@ static void bpf_tail_call_direct_fixup(
                mutex_lock(&array->aux->poke_mutex);
                target = array->ptrs[poke->tail_call.key];
                if (target) {
 -                      /* Plain memcpy is used when image is not live yet
 -                       * and still not locked as read-only. Once poke
 -                       * location is active (poke->tailcall_target_stable),
 -                       * any parallel bpf_arch_text_poke() might occur
 -                       * still on the read-write image until we finally
 -                       * locked it as read-only. Both modifications on
 -                       * the given image are under text_mutex to avoid
 -                       * interference.
 -                       */
                        ret = __bpf_arch_text_poke(poke->tailcall_target,
                                                   BPF_MOD_JUMP, NULL,
                                                   (u8 *)target->bpf_func +
 -                                                 poke->adj_off, false);
 +                                                 poke->adj_off);
                        BUG_ON(ret < 0);
                        ret = __bpf_arch_text_poke(poke->tailcall_bypass,
                                                   BPF_MOD_JUMP,
                                                   (u8 *)poke->tailcall_target +
 -                                                 X86_PATCH_SIZE, NULL, false);
 +                                                 X86_PATCH_SIZE, NULL);
                        BUG_ON(ret < 0);
                }
                WRITE_ONCE(poke->tailcall_target_stable, true);
@@@ -774,6 -787,7 +774,6 @@@ static int emit_atomic(u8 **pprog, u8 a
        /* emit opcode */
        switch (atomic_op) {
        case BPF_ADD:
 -      case BPF_SUB:
        case BPF_AND:
        case BPF_OR:
        case BPF_XOR:
@@@ -853,7 -867,7 +853,7 @@@ static void emit_nops(u8 **pprog, int l
  
  #define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp)))
  
 -static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
 +static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image,
                  int oldproglen, struct jit_context *ctx, bool jmp_padding)
  {
        bool tail_call_reachable = bpf_prog->aux->tail_call_reachable;
        push_callee_regs(&prog, callee_regs_used);
  
        ilen = prog - temp;
 -      if (image)
 -              memcpy(image + proglen, temp, ilen);
 +      if (rw_image)
 +              memcpy(rw_image + proglen, temp, ilen);
        proglen += ilen;
        addrs[0] = proglen;
        prog = temp;
@@@ -1310,9 -1324,6 +1310,9 @@@ st:                     if (is_imm8(insn->off)
                                        pr_err("extable->insn doesn't fit into 32-bit\n");
                                        return -EFAULT;
                                }
 +                              /* switch ex to rw buffer for writes */
 +                              ex = (void *)rw_image + ((void *)ex - (void *)image);
 +
                                ex->insn = delta;
  
                                ex->data = EX_TYPE_BPF;
@@@ -1695,7 -1706,7 +1695,7 @@@ emit_jmp
                                pr_err("bpf_jit: fatal error\n");
                                return -EFAULT;
                        }
 -                      memcpy(image + proglen, temp, ilen);
 +                      memcpy(rw_image + proglen, temp, ilen);
                }
                proglen += ilen;
                addrs[i] = proglen;
@@@ -2236,7 -2247,6 +2236,7 @@@ int arch_prepare_bpf_dispatcher(void *i
  }
  
  struct x64_jit_data {
 +      struct bpf_binary_header *rw_header;
        struct bpf_binary_header *header;
        int *addrs;
        u8 *image;
  
  struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
  {
 +      struct bpf_binary_header *rw_header = NULL;
        struct bpf_binary_header *header = NULL;
        struct bpf_prog *tmp, *orig_prog = prog;
        struct x64_jit_data *jit_data;
        bool tmp_blinded = false;
        bool extra_pass = false;
        bool padding = false;
 +      u8 *rw_image = NULL;
        u8 *image = NULL;
        int *addrs;
        int pass;
                oldproglen = jit_data->proglen;
                image = jit_data->image;
                header = jit_data->header;
 +              rw_header = jit_data->rw_header;
 +              rw_image = (void *)rw_header + ((void *)image - (void *)header);
                extra_pass = true;
                padding = true;
                goto skip_init_addrs;
@@@ -2326,15 -2332,12 +2326,15 @@@ skip_init_addrs
        for (pass = 0; pass < MAX_PASSES || image; pass++) {
                if (!padding && pass >= PADDING_PASSES)
                        padding = true;
 -              proglen = do_jit(prog, addrs, image, oldproglen, &ctx, padding);
 +              proglen = do_jit(prog, addrs, image, rw_image, oldproglen, &ctx, padding);
                if (proglen <= 0) {
  out_image:
                        image = NULL;
 -                      if (header)
 -                              bpf_jit_binary_free(header);
 +                      if (header) {
 +                              bpf_arch_text_copy(&header->size, &rw_header->size,
 +                                                 sizeof(rw_header->size));
 +                              bpf_jit_binary_pack_free(header, rw_header);
 +                      }
                        prog = orig_prog;
                        goto out_addrs;
                }
                                sizeof(struct exception_table_entry);
  
                        /* allocate module memory for x86 insns and extable */
 -                      header = bpf_jit_binary_alloc(roundup(proglen, align) + extable_size,
 -                                                    &image, align, jit_fill_hole);
 +                      header = bpf_jit_binary_pack_alloc(roundup(proglen, align) + extable_size,
 +                                                         &image, align, &rw_header, &rw_image,
 +                                                         jit_fill_hole);
                        if (!header) {
                                prog = orig_prog;
                                goto out_addrs;
  
        if (image) {
                if (!prog->is_func || extra_pass) {
 +                      /*
 +                       * bpf_jit_binary_pack_finalize fails in two scenarios:
 +                       *   1) header is not pointing to proper module memory;
 +                       *   2) the arch doesn't support bpf_arch_text_copy().
 +                       *
 +                       * Both cases are serious bugs and justify WARN_ON.
 +                       */
 +                      if (WARN_ON(bpf_jit_binary_pack_finalize(prog, header, rw_header))) {
 +                              prog = orig_prog;
 +                              goto out_addrs;
 +                      }
 +
                        bpf_tail_call_direct_fixup(prog);
 -                      bpf_jit_binary_lock_ro(header);
                } else {
                        jit_data->addrs = addrs;
                        jit_data->ctx = ctx;
                        jit_data->proglen = proglen;
                        jit_data->image = image;
                        jit_data->header = header;
 +                      jit_data->rw_header = rw_header;
                }
                prog->bpf_func = (void *)image;
                prog->jited = 1;
@@@ -2423,10 -2413,3 +2423,10 @@@ bool bpf_jit_supports_kfunc_call(void
  {
        return true;
  }
 +
 +void *bpf_arch_text_copy(void *dst, void *src, size_t len)
 +{
 +      if (text_poke_copy(dst, src, len) == NULL)
 +              return ERR_PTR(-EINVAL);
 +      return dst;
 +}
diff --combined drivers/net/dsa/mt7530.c
@@@ -1186,8 -1186,7 +1186,8 @@@ mt7530_port_bridge_flags(struct dsa_swi
  
  static int
  mt7530_port_bridge_join(struct dsa_switch *ds, int port,
 -                      struct dsa_bridge bridge, bool *tx_fwd_offload)
 +                      struct dsa_bridge bridge, bool *tx_fwd_offload,
 +                      struct netlink_ext_ack *extack)
  {
        struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
        u32 port_bitmap = BIT(MT7530_CPU_PORT);
@@@ -1350,8 -1349,7 +1350,8 @@@ mt7530_port_bridge_leave(struct dsa_swi
  
  static int
  mt7530_port_fdb_add(struct dsa_switch *ds, int port,
 -                  const unsigned char *addr, u16 vid)
 +                  const unsigned char *addr, u16 vid,
 +                  struct dsa_db db)
  {
        struct mt7530_priv *priv = ds->priv;
        int ret;
  
  static int
  mt7530_port_fdb_del(struct dsa_switch *ds, int port,
 -                  const unsigned char *addr, u16 vid)
 +                  const unsigned char *addr, u16 vid,
 +                  struct dsa_db db)
  {
        struct mt7530_priv *priv = ds->priv;
        int ret;
@@@ -1419,8 -1416,7 +1419,8 @@@ err
  
  static int
  mt7530_port_mdb_add(struct dsa_switch *ds, int port,
 -                  const struct switchdev_obj_port_mdb *mdb)
 +                  const struct switchdev_obj_port_mdb *mdb,
 +                  struct dsa_db db)
  {
        struct mt7530_priv *priv = ds->priv;
        const u8 *addr = mdb->addr;
  
  static int
  mt7530_port_mdb_del(struct dsa_switch *ds, int port,
 -                  const struct switchdev_obj_port_mdb *mdb)
 +                  const struct switchdev_obj_port_mdb *mdb,
 +                  struct dsa_db db)
  {
        struct mt7530_priv *priv = ds->priv;
        const u8 *addr = mdb->addr;
@@@ -2851,7 -2846,7 +2851,7 @@@ static void mt753x_phylink_mac_link_up(
                        mcr |= PMCR_RX_FC_EN;
        }
  
 -      if (mode == MLO_AN_PHY && phydev && phy_init_eee(phydev, 0) >= 0) {
 +      if (mode == MLO_AN_PHY && phydev && phy_init_eee(phydev, false) >= 0) {
                switch (speed) {
                case SPEED_1000:
                        mcr |= PMCR_FORCE_EEE1G;
@@@ -2941,7 -2936,7 +2941,7 @@@ mt753x_phylink_validate(struct dsa_swit
  
        phylink_set_port_modes(mask);
  
-       if (state->interface != PHY_INTERFACE_MODE_TRGMII ||
+       if (state->interface != PHY_INTERFACE_MODE_TRGMII &&
            !phy_interface_mode_is_8023z(state->interface)) {
                phylink_set(mask, 10baseT_Half);
                phylink_set(mask, 10baseT_Full);
@@@ -34,9 -34,7 +34,9 @@@
  #include <linux/udp.h>
  #include <linux/tcp.h>
  #include <linux/iopoll.h>
 +#include <linux/phy/phy.h>
  #include <linux/pm_runtime.h>
 +#include <linux/reset.h>
  #include "macb.h"
  
  /* This structure is only used for MACB on SiFive FU540 devices */
@@@ -1575,7 -1573,14 +1575,14 @@@ static int macb_poll(struct napi_struc
        if (work_done < budget) {
                napi_complete_done(napi, work_done);
  
-               /* Packets received while interrupts were disabled */
+               /* RSR bits only seem to propagate to raise interrupts when
+                * interrupts are enabled at the time, so if bits are already
+                * set due to packets received while interrupts were disabled,
+                * they will not cause another interrupt to be generated when
+                * interrupts are re-enabled.
+                * Check for this case here. This has been seen to happen
+                * around 30% of the time under heavy network load.
+                */
                status = macb_readl(bp, RSR);
                if (status) {
                        if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
                        napi_reschedule(napi);
                } else {
                        queue_writel(queue, IER, bp->rx_intr_mask);
+                       /* In rare cases, packets could have been received in
+                        * the window between the check above and re-enabling
+                        * interrupts. Therefore, a double-check is required
+                        * to avoid losing a wakeup. This can potentially race
+                        * with the interrupt handler doing the same actions
+                        * if an interrupt is raised just after enabling them,
+                        * but this should be harmless.
+                        */
+                       status = macb_readl(bp, RSR);
+                       if (unlikely(status)) {
+                               queue_writel(queue, IDR, bp->rx_intr_mask);
+                               if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+                                       queue_writel(queue, ISR, MACB_BIT(RCOMP));
+                               napi_schedule(napi);
+                       }
                }
        }
  
@@@ -2741,14 -2762,10 +2764,14 @@@ static int macb_open(struct net_device 
  
        macb_init_hw(bp);
  
 -      err = macb_phylink_connect(bp);
 +      err = phy_power_on(bp->sgmii_phy);
        if (err)
                goto reset_hw;
  
 +      err = macb_phylink_connect(bp);
 +      if (err)
 +              goto phy_off;
 +
        netif_tx_start_all_queues(dev);
  
        if (bp->ptp_info)
  
        return 0;
  
 +phy_off:
 +      phy_power_off(bp->sgmii_phy);
 +
  reset_hw:
        macb_reset_hw(bp);
        for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue)
@@@ -2784,8 -2798,6 +2807,8 @@@ static int macb_close(struct net_devic
        phylink_stop(bp->phylink);
        phylink_disconnect_phy(bp->phylink);
  
 +      phy_power_off(bp->sgmii_phy);
 +
        spin_lock_irqsave(&bp->lock, flags);
        macb_reset_hw(bp);
        netif_carrier_off(dev);
@@@ -4555,55 -4567,13 +4578,55 @@@ static const struct macb_config np4_con
        .usrio = &macb_default_usrio,
  };
  
 +static int zynqmp_init(struct platform_device *pdev)
 +{
 +      struct net_device *dev = platform_get_drvdata(pdev);
 +      struct macb *bp = netdev_priv(dev);
 +      int ret;
 +
 +      if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) {
 +              /* Ensure PS-GTR PHY device used in SGMII mode is ready */
 +              bp->sgmii_phy = devm_phy_get(&pdev->dev, "sgmii-phy");
 +
 +              if (IS_ERR(bp->sgmii_phy)) {
 +                      ret = PTR_ERR(bp->sgmii_phy);
 +                      dev_err_probe(&pdev->dev, ret,
 +                                    "failed to get PS-GTR PHY\n");
 +                      return ret;
 +              }
 +
 +              ret = phy_init(bp->sgmii_phy);
 +              if (ret) {
 +                      dev_err(&pdev->dev, "failed to init PS-GTR PHY: %d\n",
 +                              ret);
 +                      return ret;
 +              }
 +      }
 +
 +      /* Fully reset GEM controller at hardware level using zynqmp-reset driver,
 +       * if mapped in device tree.
 +       */
 +      ret = device_reset_optional(&pdev->dev);
 +      if (ret) {
 +              dev_err_probe(&pdev->dev, ret, "failed to reset controller");
 +              phy_exit(bp->sgmii_phy);
 +              return ret;
 +      }
 +
 +      ret = macb_init(pdev);
 +      if (ret)
 +              phy_exit(bp->sgmii_phy);
 +
 +      return ret;
 +}
 +
  static const struct macb_config zynqmp_config = {
        .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE |
                        MACB_CAPS_JUMBO |
                        MACB_CAPS_GEM_HAS_PTP | MACB_CAPS_BD_RD_PREFETCH,
        .dma_burst_length = 16,
        .clk_init = macb_clk_init,
 -      .init = macb_init,
 +      .init = zynqmp_init,
        .jumbo_max_len = 10240,
        .usrio = &macb_default_usrio,
  };
@@@ -4820,7 -4790,7 +4843,7 @@@ static int macb_probe(struct platform_d
  
        err = macb_mii_init(bp);
        if (err)
 -              goto err_out_free_netdev;
 +              goto err_out_phy_exit;
  
        netif_carrier_off(dev);
  
@@@ -4845,9 -4815,6 +4868,9 @@@ err_out_unregister_mdio
        mdiobus_unregister(bp->mii_bus);
        mdiobus_free(bp->mii_bus);
  
 +err_out_phy_exit:
 +      phy_exit(bp->sgmii_phy);
 +
  err_out_free_netdev:
        free_netdev(dev);
  
@@@ -4869,7 -4836,6 +4892,7 @@@ static int macb_remove(struct platform_
  
        if (dev) {
                bp = netdev_priv(dev);
 +              phy_exit(bp->sgmii_phy);
                mdiobus_unregister(bp->mii_bus);
                mdiobus_free(bp->mii_bus);
  
@@@ -275,8 -275,9 +275,8 @@@ static void i40e_dbg_dump_vsi_seid(stru
                         rx_ring->rx_stats.alloc_page_failed,
                         rx_ring->rx_stats.alloc_buff_failed);
                dev_info(&pf->pdev->dev,
 -                       "    rx_rings[%i]: rx_stats: realloc_count = %lld, page_reuse_count = %lld\n",
 +                       "    rx_rings[%i]: rx_stats: realloc_count = 0, page_reuse_count = %lld\n",
                         i,
 -                       rx_ring->rx_stats.realloc_count,
                         rx_ring->rx_stats.page_reuse_count);
                dev_info(&pf->pdev->dev,
                         "    rx_rings[%i]: size = %i\n",
@@@ -741,10 -742,8 +741,8 @@@ static void i40e_dbg_dump_vf(struct i40
                vsi = pf->vsi[vf->lan_vsi_idx];
                dev_info(&pf->pdev->dev, "vf %2d: VSI id=%d, seid=%d, qps=%d\n",
                         vf_id, vf->lan_vsi_id, vsi->seid, vf->num_queue_pairs);
-               dev_info(&pf->pdev->dev, "       num MDD=%lld, invalid msg=%lld, valid msg=%lld\n",
-                        vf->num_mdd_events,
-                        vf->num_invalid_msgs,
-                        vf->num_valid_msgs);
+               dev_info(&pf->pdev->dev, "       num MDD=%lld\n",
+                        vf->num_mdd_events);
        } else {
                dev_info(&pf->pdev->dev, "invalid VF id %d\n", vf_id);
        }
@@@ -44,9 -44,6 +44,9 @@@
  #define DEFAULT_DEBUG_LEVEL_SHIFT 3
  #define PFX "iavf: "
  
 +int iavf_status_to_errno(enum iavf_status status);
 +int virtchnl_status_to_errno(enum virtchnl_status_code v_status);
 +
  /* VSI state flags shared with common code */
  enum iavf_vsi_state_t {
        __IAVF_VSI_DOWN,
@@@ -191,7 -188,7 +191,7 @@@ 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_EXTENDED_CAPS,      /* process extended caps which require aq msg exchange */
        __IAVF_INIT_CONFIG_ADAPTER,
        __IAVF_INIT_SW,         /* got resources, setting up structs */
        __IAVF_INIT_FAILED,     /* init failed, restarting procedure */
@@@ -291,6 -288,7 +291,7 @@@ struct iavf_adapter 
  #define IAVF_FLAG_REINIT_ITR_NEEDED           BIT(16)
  #define IAVF_FLAG_QUEUES_DISABLED             BIT(17)
  #define IAVF_FLAG_SETUP_NETDEV_FEATURES               BIT(18)
+ #define IAVF_FLAG_REINIT_MSIX_NEEDED          BIT(20)
  /* duplicates for common code */
  #define IAVF_FLAG_DCB_ENABLED                 0
        /* flags for admin queue service task */
  #define IAVF_FLAG_AQ_ENABLE_STAG_VLAN_INSERTION               BIT_ULL(37)
  #define IAVF_FLAG_AQ_DISABLE_STAG_VLAN_INSERTION      BIT_ULL(38)
  
 +      /* flags for processing extended capability messages during
 +       * __IAVF_INIT_EXTENDED_CAPS. Each capability exchange requires
 +       * both a SEND and a RECV step, which must be processed in sequence.
 +       *
 +       * During the __IAVF_INIT_EXTENDED_CAPS state, the driver will
 +       * process one flag at a time during each state loop.
 +       */
 +      u64 extended_caps;
 +#define IAVF_EXTENDED_CAP_SEND_VLAN_V2                        BIT_ULL(0)
 +#define IAVF_EXTENDED_CAP_RECV_VLAN_V2                        BIT_ULL(1)
 +
 +#define IAVF_EXTENDED_CAPS                            \
 +      (IAVF_EXTENDED_CAP_SEND_VLAN_V2 |               \
 +       IAVF_EXTENDED_CAP_RECV_VLAN_V2)
 +
        /* OS defined structs */
        struct net_device *netdev;
        struct pci_dev *pdev;
@@@ -532,7 -515,7 +533,7 @@@ void iavf_add_vlans(struct iavf_adapte
  void iavf_del_vlans(struct iavf_adapter *adapter);
  void iavf_set_promiscuous(struct iavf_adapter *adapter, int flags);
  void iavf_request_stats(struct iavf_adapter *adapter);
 -void iavf_request_reset(struct iavf_adapter *adapter);
 +int iavf_request_reset(struct iavf_adapter *adapter);
  void iavf_get_hena(struct iavf_adapter *adapter);
  void iavf_set_hena(struct iavf_adapter *adapter);
  void iavf_set_rss_key(struct iavf_adapter *adapter);
@@@ -51,113 -51,6 +51,113 @@@ MODULE_LICENSE("GPL v2")
  static const struct net_device_ops iavf_netdev_ops;
  struct workqueue_struct *iavf_wq;
  
 +int iavf_status_to_errno(enum iavf_status status)
 +{
 +      switch (status) {
 +      case IAVF_SUCCESS:
 +              return 0;
 +      case IAVF_ERR_PARAM:
 +      case IAVF_ERR_MAC_TYPE:
 +      case IAVF_ERR_INVALID_MAC_ADDR:
 +      case IAVF_ERR_INVALID_LINK_SETTINGS:
 +      case IAVF_ERR_INVALID_PD_ID:
 +      case IAVF_ERR_INVALID_QP_ID:
 +      case IAVF_ERR_INVALID_CQ_ID:
 +      case IAVF_ERR_INVALID_CEQ_ID:
 +      case IAVF_ERR_INVALID_AEQ_ID:
 +      case IAVF_ERR_INVALID_SIZE:
 +      case IAVF_ERR_INVALID_ARP_INDEX:
 +      case IAVF_ERR_INVALID_FPM_FUNC_ID:
 +      case IAVF_ERR_QP_INVALID_MSG_SIZE:
 +      case IAVF_ERR_INVALID_FRAG_COUNT:
 +      case IAVF_ERR_INVALID_ALIGNMENT:
 +      case IAVF_ERR_INVALID_PUSH_PAGE_INDEX:
 +      case IAVF_ERR_INVALID_IMM_DATA_SIZE:
 +      case IAVF_ERR_INVALID_VF_ID:
 +      case IAVF_ERR_INVALID_HMCFN_ID:
 +      case IAVF_ERR_INVALID_PBLE_INDEX:
 +      case IAVF_ERR_INVALID_SD_INDEX:
 +      case IAVF_ERR_INVALID_PAGE_DESC_INDEX:
 +      case IAVF_ERR_INVALID_SD_TYPE:
 +      case IAVF_ERR_INVALID_HMC_OBJ_INDEX:
 +      case IAVF_ERR_INVALID_HMC_OBJ_COUNT:
 +      case IAVF_ERR_INVALID_SRQ_ARM_LIMIT:
 +              return -EINVAL;
 +      case IAVF_ERR_NVM:
 +      case IAVF_ERR_NVM_CHECKSUM:
 +      case IAVF_ERR_PHY:
 +      case IAVF_ERR_CONFIG:
 +      case IAVF_ERR_UNKNOWN_PHY:
 +      case IAVF_ERR_LINK_SETUP:
 +      case IAVF_ERR_ADAPTER_STOPPED:
 +      case IAVF_ERR_PRIMARY_REQUESTS_PENDING:
 +      case IAVF_ERR_AUTONEG_NOT_COMPLETE:
 +      case IAVF_ERR_RESET_FAILED:
 +      case IAVF_ERR_BAD_PTR:
 +      case IAVF_ERR_SWFW_SYNC:
 +      case IAVF_ERR_QP_TOOMANY_WRS_POSTED:
 +      case IAVF_ERR_QUEUE_EMPTY:
 +      case IAVF_ERR_FLUSHED_QUEUE:
 +      case IAVF_ERR_OPCODE_MISMATCH:
 +      case IAVF_ERR_CQP_COMPL_ERROR:
 +      case IAVF_ERR_BACKING_PAGE_ERROR:
 +      case IAVF_ERR_NO_PBLCHUNKS_AVAILABLE:
 +      case IAVF_ERR_MEMCPY_FAILED:
 +      case IAVF_ERR_SRQ_ENABLED:
 +      case IAVF_ERR_ADMIN_QUEUE_ERROR:
 +      case IAVF_ERR_ADMIN_QUEUE_FULL:
 +      case IAVF_ERR_BAD_IWARP_CQE:
 +      case IAVF_ERR_NVM_BLANK_MODE:
 +      case IAVF_ERR_PE_DOORBELL_NOT_ENABLED:
 +      case IAVF_ERR_DIAG_TEST_FAILED:
 +      case IAVF_ERR_FIRMWARE_API_VERSION:
 +      case IAVF_ERR_ADMIN_QUEUE_CRITICAL_ERROR:
 +              return -EIO;
 +      case IAVF_ERR_DEVICE_NOT_SUPPORTED:
 +              return -ENODEV;
 +      case IAVF_ERR_NO_AVAILABLE_VSI:
 +      case IAVF_ERR_RING_FULL:
 +              return -ENOSPC;
 +      case IAVF_ERR_NO_MEMORY:
 +              return -ENOMEM;
 +      case IAVF_ERR_TIMEOUT:
 +      case IAVF_ERR_ADMIN_QUEUE_TIMEOUT:
 +              return -ETIMEDOUT;
 +      case IAVF_ERR_NOT_IMPLEMENTED:
 +      case IAVF_NOT_SUPPORTED:
 +              return -EOPNOTSUPP;
 +      case IAVF_ERR_ADMIN_QUEUE_NO_WORK:
 +              return -EALREADY;
 +      case IAVF_ERR_NOT_READY:
 +              return -EBUSY;
 +      case IAVF_ERR_BUF_TOO_SHORT:
 +              return -EMSGSIZE;
 +      }
 +
 +      return -EIO;
 +}
 +
 +int virtchnl_status_to_errno(enum virtchnl_status_code v_status)
 +{
 +      switch (v_status) {
 +      case VIRTCHNL_STATUS_SUCCESS:
 +              return 0;
 +      case VIRTCHNL_STATUS_ERR_PARAM:
 +      case VIRTCHNL_STATUS_ERR_INVALID_VF_ID:
 +              return -EINVAL;
 +      case VIRTCHNL_STATUS_ERR_NO_MEMORY:
 +              return -ENOMEM;
 +      case VIRTCHNL_STATUS_ERR_OPCODE_MISMATCH:
 +      case VIRTCHNL_STATUS_ERR_CQP_COMPL_ERROR:
 +      case VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR:
 +              return -EIO;
 +      case VIRTCHNL_STATUS_ERR_NOT_SUPPORTED:
 +              return -EOPNOTSUPP;
 +      }
 +
 +      return -EIO;
 +}
 +
  /**
   * iavf_pdev_to_adapter - go from pci_dev to adapter
   * @pdev: pci_dev pointer
@@@ -984,7 -877,6 +984,7 @@@ struct iavf_mac_filter *iavf_add_filter
                list_add_tail(&f->list, &adapter->mac_filter_list);
                f->add = true;
                f->is_new_mac = true;
 +              f->is_primary = false;
                adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER;
        } else {
                f->remove = false;
@@@ -1018,22 -910,17 +1018,22 @@@ static int iavf_set_mac(struct net_devi
        f = iavf_find_filter(adapter, hw->mac.addr);
        if (f) {
                f->remove = true;
 +              f->is_primary = true;
                adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER;
        }
  
        f = iavf_add_filter(adapter, addr->sa_data);
 -
 -      spin_unlock_bh(&adapter->mac_vlan_list_lock);
 -
        if (f) {
 +              f->is_primary = true;
                ether_addr_copy(hw->mac.addr, addr->sa_data);
        }
  
 +      spin_unlock_bh(&adapter->mac_vlan_list_lock);
 +
 +      /* schedule the watchdog task to immediately process the request */
 +      if (f)
 +              queue_work(iavf_wq, &adapter->watchdog_task.work);
 +
        return (f == NULL) ? -ENOMEM : 0;
  }
  
@@@ -1534,7 -1421,7 +1534,7 @@@ static int iavf_config_rss_aq(struct ia
        struct iavf_aqc_get_set_rss_key_data *rss_key =
                (struct iavf_aqc_get_set_rss_key_data *)adapter->rss_key;
        struct iavf_hw *hw = &adapter->hw;
 -      int ret = 0;
 +      enum iavf_status status;
  
        if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
                /* bail because we already have a command pending */
                return -EBUSY;
        }
  
 -      ret = iavf_aq_set_rss_key(hw, adapter->vsi.id, rss_key);
 -      if (ret) {
 +      status = iavf_aq_set_rss_key(hw, adapter->vsi.id, rss_key);
 +      if (status) {
                dev_err(&adapter->pdev->dev, "Cannot set RSS key, err %s aq_err %s\n",
 -                      iavf_stat_str(hw, ret),
 +                      iavf_stat_str(hw, status),
                        iavf_aq_str(hw, hw->aq.asq_last_status));
 -              return ret;
 +              return iavf_status_to_errno(status);
  
        }
  
 -      ret = iavf_aq_set_rss_lut(hw, adapter->vsi.id, false,
 -                                adapter->rss_lut, adapter->rss_lut_size);
 -      if (ret) {
 +      status = iavf_aq_set_rss_lut(hw, adapter->vsi.id, false,
 +                                   adapter->rss_lut, adapter->rss_lut_size);
 +      if (status) {
                dev_err(&adapter->pdev->dev, "Cannot set RSS lut, err %s aq_err %s\n",
 -                      iavf_stat_str(hw, ret),
 +                      iavf_stat_str(hw, status),
                        iavf_aq_str(hw, hw->aq.asq_last_status));
 +              return iavf_status_to_errno(status);
        }
  
 -      return ret;
 +      return 0;
  
  }
  
@@@ -1631,6 -1517,7 +1631,6 @@@ static void iavf_fill_rss_lut(struct ia
  static int iavf_init_rss(struct iavf_adapter *adapter)
  {
        struct iavf_hw *hw = &adapter->hw;
 -      int ret;
  
        if (!RSS_PF(adapter)) {
                /* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */
  
        iavf_fill_rss_lut(adapter);
        netdev_rss_key_fill((void *)adapter->rss_key, adapter->rss_key_size);
 -      ret = iavf_config_rss(adapter);
  
 -      return ret;
 +      return iavf_config_rss(adapter);
  }
  
  /**
@@@ -2115,24 -2003,23 +2115,24 @@@ static void iavf_startup(struct iavf_ad
  {
        struct pci_dev *pdev = adapter->pdev;
        struct iavf_hw *hw = &adapter->hw;
 -      int err;
 +      enum iavf_status status;
 +      int ret;
  
        WARN_ON(adapter->state != __IAVF_STARTUP);
  
        /* driver loaded, probe complete */
        adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED;
        adapter->flags &= ~IAVF_FLAG_RESET_PENDING;
 -      err = iavf_set_mac_type(hw);
 -      if (err) {
 -              dev_err(&pdev->dev, "Failed to set MAC type (%d)\n", err);
 +      status = iavf_set_mac_type(hw);
 +      if (status) {
 +              dev_err(&pdev->dev, "Failed to set MAC type (%d)\n", status);
                goto err;
        }
  
 -      err = iavf_check_reset_complete(hw);
 -      if (err) {
 +      ret = iavf_check_reset_complete(hw);
 +      if (ret) {
                dev_info(&pdev->dev, "Device is still in reset (%d), retrying\n",
 -                       err);
 +                       ret);
                goto err;
        }
        hw->aq.num_arq_entries = IAVF_AQ_LEN;
        hw->aq.arq_buf_size = IAVF_MAX_AQ_BUF_SIZE;
        hw->aq.asq_buf_size = IAVF_MAX_AQ_BUF_SIZE;
  
 -      err = iavf_init_adminq(hw);
 -      if (err) {
 -              dev_err(&pdev->dev, "Failed to init Admin Queue (%d)\n", err);
 +      status = iavf_init_adminq(hw);
 +      if (status) {
 +              dev_err(&pdev->dev, "Failed to init Admin Queue (%d)\n",
 +                      status);
                goto err;
        }
 -      err = iavf_send_api_ver(adapter);
 -      if (err) {
 -              dev_err(&pdev->dev, "Unable to send to PF (%d)\n", err);
 +      ret = iavf_send_api_ver(adapter);
 +      if (ret) {
 +              dev_err(&pdev->dev, "Unable to send to PF (%d)\n", ret);
                iavf_shutdown_adminq(hw);
                goto err;
        }
@@@ -2184,7 -2070,7 +2184,7 @@@ static void iavf_init_version_check(str
        /* aq msg sent, awaiting reply */
        err = iavf_verify_api_ver(adapter);
        if (err) {
 -              if (err == IAVF_ERR_ADMIN_QUEUE_NO_WORK)
 +              if (err == -EALREADY)
                        err = iavf_send_api_ver(adapter);
                else
                        dev_err(&pdev->dev, "Unsupported PF API version %d.%d, expected %d.%d\n",
@@@ -2234,7 -2120,7 +2234,7 @@@ int iavf_parse_vf_resource_msg(struct i
                        "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->flags |= IAVF_FLAG_REINIT_MSIX_NEEDED;
                adapter->num_req_queues = adapter->vsi_res->num_queue_pairs;
                iavf_schedule_reset(adapter);
  
@@@ -2285,11 -2171,11 +2285,11 @@@ static void iavf_init_get_resources(str
                }
        }
        err = iavf_get_vf_config(adapter);
 -      if (err == IAVF_ERR_ADMIN_QUEUE_NO_WORK) {
 +      if (err == -EALREADY) {
                err = iavf_send_vf_config_msg(adapter);
                goto err_alloc;
 -      } else if (err == IAVF_ERR_PARAM) {
 -              /* We only get ERR_PARAM if the device is in a very bad
 +      } else if (err == -EINVAL) {
 +              /* We only get -EINVAL if the device is in a very bad
                 * state or if we've been disabled for previous bad
                 * behavior. Either way, we're done now.
                 */
        }
  
        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",
 +      if (err) {
 +              dev_err(&pdev->dev, "Failed to parse VF resource message from PF (%d)\n",
                        err);
                goto err_alloc;
        }
 -
 -      /* underlying PF supports VIRTCHNL_VF_OFFLOAD_VLAN_V2, so update the
 -       * state accordingly
 +      /* Some features require additional messages to negotiate extended
 +       * capabilities. These are processed in sequence by the
 +       * __IAVF_INIT_EXTENDED_CAPS driver state.
         */
 -      iavf_change_state(adapter, __IAVF_INIT_GET_OFFLOAD_VLAN_V2_CAPS);
 +      adapter->extended_caps = IAVF_EXTENDED_CAPS;
 +
 +      iavf_change_state(adapter, __IAVF_INIT_EXTENDED_CAPS);
        return;
  
  err_alloc:
  }
  
  /**
 - * iavf_init_get_offload_vlan_v2_caps - part of driver startup
 + * iavf_init_send_offload_vlan_v2_caps - part of initializing VLAN V2 caps
   * @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.
 + * Function processes send of the extended VLAN V2 capability message to the
 + * PF. Must clear IAVF_EXTENDED_CAP_RECV_VLAN_V2 if the message is not sent,
 + * e.g. due to PF not negotiating VIRTCHNL_VF_OFFLOAD_VLAN_V2.
 + */
 +static void iavf_init_send_offload_vlan_v2_caps(struct iavf_adapter *adapter)
 +{
 +      int ret;
 +
 +      WARN_ON(!(adapter->extended_caps & IAVF_EXTENDED_CAP_SEND_VLAN_V2));
 +
 +      ret = iavf_send_vf_offload_vlan_v2_msg(adapter);
 +      if (ret && ret == -EOPNOTSUPP) {
 +              /* PF does not support VIRTCHNL_VF_OFFLOAD_V2. In this case,
 +               * we did not send the capability exchange message and do not
 +               * expect a response.
 +               */
 +              adapter->extended_caps &= ~IAVF_EXTENDED_CAP_RECV_VLAN_V2;
 +      }
 +
 +      /* We sent the message, so move on to the next step */
 +      adapter->extended_caps &= ~IAVF_EXTENDED_CAP_SEND_VLAN_V2;
 +}
 +
 +/**
 + * iavf_init_recv_offload_vlan_v2_caps - part of initializing VLAN V2 caps
 + * @adapter: board private structure
 + *
 + * Function processes receipt of the extended VLAN V2 capability message from
 + * the PF.
   **/
 -static void iavf_init_get_offload_vlan_v2_caps(struct iavf_adapter *adapter)
 +static void iavf_init_recv_offload_vlan_v2_caps(struct iavf_adapter *adapter)
  {
        int ret;
  
 -      WARN_ON(adapter->state != __IAVF_INIT_GET_OFFLOAD_VLAN_V2_CAPS);
 +      WARN_ON(!(adapter->extended_caps & IAVF_EXTENDED_CAP_RECV_VLAN_V2));
  
        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);
 +      if (ret)
                goto err;
 -      }
  
 -      iavf_change_state(adapter, __IAVF_INIT_CONFIG_ADAPTER);
 +      /* We've processed receipt of the VLAN V2 caps message */
 +      adapter->extended_caps &= ~IAVF_EXTENDED_CAP_RECV_VLAN_V2;
        return;
  err:
 +      /* We didn't receive a reply. Make sure we try sending again when
 +       * __IAVF_INIT_FAILED attempts to recover.
 +       */
 +      adapter->extended_caps |= IAVF_EXTENDED_CAP_SEND_VLAN_V2;
        iavf_change_state(adapter, __IAVF_INIT_FAILED);
  }
  
 +/**
 + * iavf_init_process_extended_caps - Part of driver startup
 + * @adapter: board private structure
 + *
 + * Function processes __IAVF_INIT_EXTENDED_CAPS driver state. This state
 + * handles negotiating capabilities for features which require an additional
 + * message.
 + *
 + * Once all extended capabilities exchanges are finished, the driver will
 + * transition into __IAVF_INIT_CONFIG_ADAPTER.
 + */
 +static void iavf_init_process_extended_caps(struct iavf_adapter *adapter)
 +{
 +      WARN_ON(adapter->state != __IAVF_INIT_EXTENDED_CAPS);
 +
 +      /* Process capability exchange for VLAN V2 */
 +      if (adapter->extended_caps & IAVF_EXTENDED_CAP_SEND_VLAN_V2) {
 +              iavf_init_send_offload_vlan_v2_caps(adapter);
 +              return;
 +      } else if (adapter->extended_caps & IAVF_EXTENDED_CAP_RECV_VLAN_V2) {
 +              iavf_init_recv_offload_vlan_v2_caps(adapter);
 +              return;
 +      }
 +
 +      /* When we reach here, no further extended capabilities exchanges are
 +       * necessary, so we finally transition into __IAVF_INIT_CONFIG_ADAPTER
 +       */
 +      iavf_change_state(adapter, __IAVF_INIT_CONFIG_ADAPTER);
 +}
 +
  /**
   * iavf_init_config_adapter - last part of driver startup
   * @adapter: board private structure
@@@ -2575,8 -2411,8 +2575,8 @@@ static void iavf_watchdog_task(struct w
                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);
 +      case __IAVF_INIT_EXTENDED_CAPS:
 +              iavf_init_process_extended_caps(adapter);
                mutex_unlock(&adapter->crit_lock);
                queue_delayed_work(iavf_wq, &adapter->watchdog_task,
                                   msecs_to_jiffies(1));
@@@ -2784,7 -2620,6 +2784,7 @@@ static void iavf_reset_task(struct work
        struct iavf_hw *hw = &adapter->hw;
        struct iavf_mac_filter *f, *ftmp;
        struct iavf_cloud_filter *cf;
 +      enum iavf_status status;
        u32 reg_val;
        int i = 0, err;
        bool running;
@@@ -2886,15 -2721,14 +2886,16 @@@ continue_reset
        /* kill and reinit the admin queue */
        iavf_shutdown_adminq(hw);
        adapter->current_op = VIRTCHNL_OP_UNKNOWN;
 -      err = iavf_init_adminq(hw);
 -      if (err)
 +      status = iavf_init_adminq(hw);
 +      if (status) {
                dev_info(&adapter->pdev->dev, "Failed to init adminq: %d\n",
 -                       err);
 +                       status);
 +              goto reset_err;
 +      }
        adapter->aq_required = 0;
  
-       if (adapter->flags & IAVF_FLAG_REINIT_ITR_NEEDED) {
+       if ((adapter->flags & IAVF_FLAG_REINIT_MSIX_NEEDED) ||
+           (adapter->flags & IAVF_FLAG_REINIT_ITR_NEEDED)) {
                err = iavf_reinit_interrupt_scheme(adapter);
                if (err)
                        goto reset_err;
                if (err)
                        goto reset_err;
  
-               if (adapter->flags & IAVF_FLAG_REINIT_ITR_NEEDED) {
+               if ((adapter->flags & IAVF_FLAG_REINIT_MSIX_NEEDED) ||
+                   (adapter->flags & IAVF_FLAG_REINIT_ITR_NEEDED)) {
                        err = iavf_request_traffic_irqs(adapter, netdev->name);
                        if (err)
                                goto reset_err;
  
-                       adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
+                       adapter->flags &= ~IAVF_FLAG_REINIT_MSIX_NEEDED;
                }
  
                iavf_configure(adapter);
                iavf_change_state(adapter, __IAVF_DOWN);
                wake_up(&adapter->down_waitqueue);
        }
+       adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
        mutex_unlock(&adapter->client_lock);
        mutex_unlock(&adapter->crit_lock);
  
@@@ -4589,9 -4427,12 +4594,9 @@@ static int iavf_probe(struct pci_dev *p
  
        err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
        if (err) {
 -              err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
 -              if (err) {
 -                      dev_err(&pdev->dev,
 -                              "DMA configuration failed: 0x%x\n", err);
 -                      goto err_dma;
 -              }
 +              dev_err(&pdev->dev,
 +                      "DMA configuration failed: 0x%x\n", err);
 +              goto err_dma;
        }
  
        err = pci_request_regions(pdev, iavf_driver_name);
@@@ -4913,6 -4754,8 +4918,6 @@@ static struct pci_driver iavf_driver = 
   **/
  static int __init iavf_init_module(void)
  {
 -      int ret;
 -
        pr_info("iavf: %s\n", iavf_driver_string);
  
        pr_info("%s\n", iavf_copyright);
                pr_err("%s: Failed to create workqueue\n", iavf_driver_name);
                return -ENOMEM;
        }
 -      ret = pci_register_driver(&iavf_driver);
 -      return ret;
 +      return pci_register_driver(&iavf_driver);
  }
  
  module_init(iavf_init_module);
@@@ -22,17 -22,17 +22,17 @@@ static int iavf_send_pf_msg(struct iavf
                            enum virtchnl_ops op, u8 *msg, u16 len)
  {
        struct iavf_hw *hw = &adapter->hw;
 -      enum iavf_status err;
 +      enum iavf_status status;
  
        if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)
                return 0; /* nothing to see here, move along */
  
 -      err = iavf_aq_send_msg_to_pf(hw, op, 0, msg, len, NULL);
 -      if (err)
 -              dev_dbg(&adapter->pdev->dev, "Unable to send opcode %d to PF, err %s, aq_err %s\n",
 -                      op, iavf_stat_str(hw, err),
 +      status = iavf_aq_send_msg_to_pf(hw, op, 0, msg, len, NULL);
 +      if (status)
 +              dev_dbg(&adapter->pdev->dev, "Unable to send opcode %d to PF, status %s, aq_err %s\n",
 +                      op, iavf_stat_str(hw, status),
                        iavf_aq_str(hw, hw->aq.asq_last_status));
 -      return err;
 +      return iavf_status_to_errno(status);
  }
  
  /**
@@@ -54,41 -54,6 +54,41 @@@ int iavf_send_api_ver(struct iavf_adapt
                                sizeof(vvi));
  }
  
 +/**
 + * iavf_poll_virtchnl_msg
 + * @hw: HW configuration structure
 + * @event: event to populate on success
 + * @op_to_poll: requested virtchnl op to poll for
 + *
 + * Initialize poll for virtchnl msg matching the requested_op. Returns 0
 + * if a message of the correct opcode is in the queue or an error code
 + * if no message matching the op code is waiting and other failures.
 + */
 +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;
 +      u32 v_retval;
 +
 +      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 iavf_status_to_errno(status);
 +              received_op =
 +                  (enum virtchnl_ops)le32_to_cpu(event->desc.cookie_high);
 +              if (op_to_poll == received_op)
 +                      break;
 +      }
 +
 +      v_retval = le32_to_cpu(event->desc.cookie_low);
 +      return virtchnl_status_to_errno((enum virtchnl_status_code)v_retval);
 +}
 +
  /**
   * iavf_verify_api_ver
   * @adapter: adapter structure
   **/
  int iavf_verify_api_ver(struct iavf_adapter *adapter)
  {
 -      struct virtchnl_version_info *pf_vvi;
 -      struct iavf_hw *hw = &adapter->hw;
        struct iavf_arq_event_info event;
 -      enum virtchnl_ops op;
 -      enum iavf_status err;
 +      int err;
  
        event.buf_len = IAVF_MAX_AQ_BUF_SIZE;
 -      event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL);
 -      if (!event.msg_buf) {
 -              err = -ENOMEM;
 -              goto out;
 -      }
 -
 -      while (1) {
 -              err = iavf_clean_arq_element(hw, &event, NULL);
 -              /* When the AQ is empty, iavf_clean_arq_element will return
 -               * nonzero and this loop will terminate.
 -               */
 -              if (err)
 -                      goto out_alloc;
 -              op =
 -                  (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high);
 -              if (op == VIRTCHNL_OP_VERSION)
 -                      break;
 -      }
 -
 +      event.msg_buf = kzalloc(IAVF_MAX_AQ_BUF_SIZE, GFP_KERNEL);
 +      if (!event.msg_buf)
 +              return -ENOMEM;
  
 -      err = (enum iavf_status)le32_to_cpu(event.desc.cookie_low);
 -      if (err)
 -              goto out_alloc;
 +      err = iavf_poll_virtchnl_msg(&adapter->hw, &event, VIRTCHNL_OP_VERSION);
 +      if (!err) {
 +              struct virtchnl_version_info *pf_vvi =
 +                      (struct virtchnl_version_info *)event.msg_buf;
 +              adapter->pf_version = *pf_vvi;
  
 -      if (op != VIRTCHNL_OP_VERSION) {
 -              dev_info(&adapter->pdev->dev, "Invalid reply type %d from PF\n",
 -                      op);
 -              err = -EIO;
 -              goto out_alloc;
 +              if (pf_vvi->major > VIRTCHNL_VERSION_MAJOR ||
 +                  (pf_vvi->major == VIRTCHNL_VERSION_MAJOR &&
 +                   pf_vvi->minor > VIRTCHNL_VERSION_MINOR))
 +                      err = -EIO;
        }
  
 -      pf_vvi = (struct virtchnl_version_info *)event.msg_buf;
 -      adapter->pf_version = *pf_vvi;
 -
 -      if ((pf_vvi->major > VIRTCHNL_VERSION_MAJOR) ||
 -          ((pf_vvi->major == VIRTCHNL_VERSION_MAJOR) &&
 -           (pf_vvi->minor > VIRTCHNL_VERSION_MINOR)))
 -              err = -EIO;
 -
 -out_alloc:
        kfree(event.msg_buf);
 -out:
 +
        return err;
  }
  
@@@ -216,17 -208,33 +216,17 @@@ int iavf_get_vf_config(struct iavf_adap
  {
        struct iavf_hw *hw = &adapter->hw;
        struct iavf_arq_event_info event;
 -      enum virtchnl_ops op;
 -      enum iavf_status err;
        u16 len;
 +      int err;
  
 -      len =  sizeof(struct virtchnl_vf_resource) +
 +      len = sizeof(struct virtchnl_vf_resource) +
                IAVF_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource);
        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_VF_RESOURCES)
 -                      break;
 -      }
 +      event.msg_buf = kzalloc(len, GFP_KERNEL);
 +      if (!event.msg_buf)
 +              return -ENOMEM;
  
 -      err = (enum iavf_status)le32_to_cpu(event.desc.cookie_low);
 +      err = iavf_poll_virtchnl_msg(hw, &event, VIRTCHNL_OP_GET_VF_RESOURCES);
        memcpy(adapter->vf_res, event.msg_buf, min(event.msg_len, len));
  
        /* some PFs send more queues than we should have so validate that
        if (!err)
                iavf_validate_num_queues(adapter);
        iavf_vf_parse_hw_config(hw, adapter->vf_res);
 -out_alloc:
 +
        kfree(event.msg_buf);
 -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;
 +      int err;
        u16 len;
  
 -      len =  sizeof(struct virtchnl_vlan_caps);
 +      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;
 -      }
 +      event.msg_buf = kzalloc(len, GFP_KERNEL);
 +      if (!event.msg_buf)
 +              return -ENOMEM;
  
 -      err = (enum iavf_status)le32_to_cpu(event.desc.cookie_low);
 -      if (err)
 -              goto out_alloc;
 +      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));
  
 -      memcpy(&adapter->vlan_v2_caps, event.msg_buf, min(event.msg_len, len));
 -out_alloc:
        kfree(event.msg_buf);
 -out:
 +
        return err;
  }
  
@@@ -429,20 -453,6 +429,20 @@@ void iavf_map_queues(struct iavf_adapte
        kfree(vimi);
  }
  
 +/**
 + * iavf_set_mac_addr_type - Set the correct request type from the filter type
 + * @virtchnl_ether_addr: pointer to requested list element
 + * @filter: pointer to requested filter
 + **/
 +static void
 +iavf_set_mac_addr_type(struct virtchnl_ether_addr *virtchnl_ether_addr,
 +                     const struct iavf_mac_filter *filter)
 +{
 +      virtchnl_ether_addr->type = filter->is_primary ?
 +              VIRTCHNL_ETHER_ADDR_PRIMARY :
 +              VIRTCHNL_ETHER_ADDR_EXTRA;
 +}
 +
  /**
   * iavf_add_ether_addrs
   * @adapter: adapter structure
@@@ -498,7 -508,6 +498,7 @@@ void iavf_add_ether_addrs(struct iavf_a
        list_for_each_entry(f, &adapter->mac_filter_list, list) {
                if (f->add) {
                        ether_addr_copy(veal->list[i].addr, f->macaddr);
 +                      iavf_set_mac_addr_type(&veal->list[i], f);
                        i++;
                        f->add = false;
                        if (i == count)
@@@ -568,7 -577,6 +568,7 @@@ void iavf_del_ether_addrs(struct iavf_a
        list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
                if (f->remove) {
                        ether_addr_copy(veal->list[i].addr, f->macaddr);
 +                      iavf_set_mac_addr_type(&veal->list[i], f);
                        i++;
                        list_del(&f->list);
                        kfree(f);
@@@ -1819,15 -1827,29 +1819,31 @@@ void iavf_del_adv_rss_cfg(struct iavf_a
   *
   * Request that the PF reset this VF. No response is expected.
   **/
 -void iavf_request_reset(struct iavf_adapter *adapter)
 +int iavf_request_reset(struct iavf_adapter *adapter)
  {
 +      int err;
        /* Don't check CURRENT_OP - this is always higher priority */
 -      iavf_send_pf_msg(adapter, VIRTCHNL_OP_RESET_VF, NULL, 0);
 +      err = iavf_send_pf_msg(adapter, VIRTCHNL_OP_RESET_VF, NULL, 0);
        adapter->current_op = VIRTCHNL_OP_UNKNOWN;
 +      return err;
  }
  
+ /**
+  * iavf_netdev_features_vlan_strip_set - update vlan strip status
+  * @netdev: ptr to netdev being adjusted
+  * @enable: enable or disable vlan strip
+  *
+  * Helper function to change vlan strip status in netdev->features.
+  */
+ static void iavf_netdev_features_vlan_strip_set(struct net_device *netdev,
+                                               const bool enable)
+ {
+       if (enable)
+               netdev->features |= NETIF_F_HW_VLAN_CTAG_RX;
+       else
+               netdev->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
+ }
  /**
   * iavf_virtchnl_completion
   * @adapter: adapter structure
@@@ -2051,8 -2073,18 +2067,18 @@@ void iavf_virtchnl_completion(struct ia
                        }
                        break;
                case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING:
+                       dev_warn(&adapter->pdev->dev, "Changing VLAN Stripping is not allowed when Port VLAN is configured\n");
+                       /* Vlan stripping could not be enabled by ethtool.
+                        * Disable it in netdev->features.
+                        */
+                       iavf_netdev_features_vlan_strip_set(netdev, false);
+                       break;
                case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING:
                        dev_warn(&adapter->pdev->dev, "Changing VLAN Stripping is not allowed when Port VLAN is configured\n");
+                       /* Vlan stripping could not be disabled by ethtool.
+                        * Enable it in netdev->features.
+                        */
+                       iavf_netdev_features_vlan_strip_set(netdev, true);
                        break;
                default:
                        dev_err(&adapter->pdev->dev, "PF returned error %d (%s) to our request %d\n",
                spin_unlock_bh(&adapter->adv_rss_lock);
                }
                break;
+       case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING:
+               /* PF enabled vlan strip on this VF.
+                * Update netdev->features if needed to be in sync with ethtool.
+                */
+               if (!v_retval)
+                       iavf_netdev_features_vlan_strip_set(netdev, true);
+               break;
+       case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING:
+               /* PF disabled vlan strip on this VF.
+                * Update netdev->features if needed to be in sync with ethtool.
+                */
+               if (!v_retval)
+                       iavf_netdev_features_vlan_strip_set(netdev, false);
+               break;
        default:
                if (adapter->current_op && (v_opcode != adapter->current_op))
                        dev_warn(&adapter->pdev->dev, "Expected response %d from PF, received %d\n",
@@@ -72,8 -72,6 +72,8 @@@
  #include "ice_repr.h"
  #include "ice_eswitch.h"
  #include "ice_lag.h"
 +#include "ice_vsi_vlan_ops.h"
 +#include "ice_gnss.h"
  
  #define ICE_BAR0              0
  #define ICE_REQ_DESC_MULTIPLE 32
  /* All VF control VSIs share the same IRQ, so assign a unique ID for them */
  #define ICE_RES_VF_CTRL_VEC_ID        (ICE_RES_RDMA_VEC_ID - 1)
  #define ICE_INVAL_Q_INDEX     0xffff
 -#define ICE_INVAL_VFID                256
  
  #define ICE_MAX_RXQS_PER_TC           256     /* Used when setting VSI context per TC Rx queues */
  
  enum ice_feature {
        ICE_F_DSCP,
        ICE_F_SMA_CTRL,
 +      ICE_F_GNSS,
        ICE_F_MAX
  };
  
@@@ -332,7 -330,7 +332,7 @@@ struct ice_vsi 
        u16 vsi_num;                    /* HW (absolute) index of this VSI */
        u16 idx;                        /* software index in pf->vsi[] */
  
 -      s16 vf_id;                      /* VF ID for SR-IOV VSIs */
 +      struct ice_vf *vf;              /* VF associated with this VSI */
  
        u16 ethtype;                    /* Ethernet protocol for pause frame */
        u16 num_gfltr;
        u8 irqs_ready:1;
        u8 current_isup:1;               /* Sync 'link up' logging */
        u8 stat_offsets_loaded:1;
 +      struct ice_vsi_vlan_ops inner_vlan_ops;
 +      struct ice_vsi_vlan_ops outer_vlan_ops;
        u16 num_vlan;
  
        /* queue information */
@@@ -471,6 -467,7 +471,6 @@@ enum ice_pf_flags 
        ICE_FLAG_FD_ENA,
        ICE_FLAG_PTP_SUPPORTED,         /* PTP is supported by NVM */
        ICE_FLAG_PTP,                   /* PTP is enabled by software */
 -      ICE_FLAG_AUX_ENA,
        ICE_FLAG_ADV_FEATURES,
        ICE_FLAG_TC_MQPRIO,             /* support for Multi queue TC */
        ICE_FLAG_CLS_FLOWER,
        ICE_FLAG_LEGACY_RX,
        ICE_FLAG_VF_TRUE_PROMISC_ENA,
        ICE_FLAG_MDD_AUTO_RESET_VF,
 +      ICE_FLAG_VF_VLAN_PRUNING,
        ICE_FLAG_LINK_LENIENT_MODE_ENA,
        ICE_FLAG_PLUG_AUX_DEV,
+       ICE_FLAG_MTU_CHANGED,
 +      ICE_FLAG_GNSS,                  /* GNSS successfully initialized */
        ICE_PF_FLAGS_NBITS              /* must be last */
  };
  
@@@ -528,7 -524,15 +529,7 @@@ struct ice_pf 
        struct ice_vsi **vsi;           /* VSIs created by the driver */
        struct ice_sw *first_sw;        /* first switch created by firmware */
        u16 eswitch_mode;               /* current mode of eswitch */
 -      /* Virtchnl/SR-IOV config info */
 -      struct ice_vf *vf;
 -      u16 num_alloc_vfs;              /* actual number of VFs allocated */
 -      u16 num_vfs_supported;          /* num VFs supported for this PF */
 -      u16 num_qps_per_vf;
 -      u16 num_msix_per_vf;
 -      /* used to ratelimit the MDD event logging */
 -      unsigned long last_printed_mdd_jiffies;
 -      DECLARE_BITMAP(malvfs, ICE_MAX_VF_COUNT);
 +      struct ice_vfs vfs;
        DECLARE_BITMAP(features, ICE_F_MAX);
        DECLARE_BITMAP(state, ICE_STATE_NBITS);
        DECLARE_BITMAP(flags, ICE_PF_FLAGS_NBITS);
        struct mutex tc_mutex;          /* lock to protect TC changes */
        u32 msg_enable;
        struct ice_ptp ptp;
 +      struct tty_driver *ice_gnss_tty_driver;
 +      struct tty_port gnss_tty_port;
 +      struct gnss_serial *gnss_serial;
        u16 num_rdma_msix;              /* Total MSIX vectors for RDMA driver */
        u16 rdma_base_vector;
  
@@@ -886,6 -887,7 +887,6 @@@ static inline void ice_set_rdma_cap(str
  {
        if (pf->hw.func_caps.common_cap.rdma && pf->num_rdma_msix) {
                set_bit(ICE_FLAG_RDMA_ENA, pf->flags);
 -              set_bit(ICE_FLAG_AUX_ENA, pf->flags);
                set_bit(ICE_FLAG_PLUG_AUX_DEV, pf->flags);
        }
  }
   */
  static inline void ice_clear_rdma_cap(struct ice_pf *pf)
  {
-       ice_unplug_aux_dev(pf);
+       /* We can directly unplug aux device here only if the flag bit
+        * ICE_FLAG_PLUG_AUX_DEV is not set because ice_unplug_aux_dev()
+        * could race with ice_plug_aux_dev() called from
+        * ice_service_task(). In this case we only clear that bit now and
+        * aux device will be unplugged later once ice_plug_aux_device()
+        * called from ice_service_task() finishes (see ice_service_task()).
+        */
+       if (!test_and_clear_bit(ICE_FLAG_PLUG_AUX_DEV, pf->flags))
+               ice_unplug_aux_dev(pf);
        clear_bit(ICE_FLAG_RDMA_ENA, pf->flags);
 -      clear_bit(ICE_FLAG_AUX_ENA, pf->flags);
  }
  #endif /* _ICE_H_ */
@@@ -164,7 -164,6 +164,7 @@@ static const struct ice_priv_flag ice_g
        ICE_PRIV_FLAG("vf-true-promisc-support",
                      ICE_FLAG_VF_TRUE_PROMISC_ENA),
        ICE_PRIV_FLAG("mdd-auto-reset-vf", ICE_FLAG_MDD_AUTO_RESET_VF),
 +      ICE_PRIV_FLAG("vf-vlan-pruning", ICE_FLAG_VF_VLAN_PRUNING),
        ICE_PRIV_FLAG("legacy-rx", ICE_FLAG_LEGACY_RX),
  };
  
@@@ -316,20 -315,16 +316,20 @@@ out
   */
  static bool ice_active_vfs(struct ice_pf *pf)
  {
 -      unsigned int i;
 -
 -      ice_for_each_vf(pf, i) {
 -              struct ice_vf *vf = &pf->vf[i];
 +      bool active = false;
 +      struct ice_vf *vf;
 +      unsigned int bkt;
  
 -              if (test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
 -                      return true;
 +      rcu_read_lock();
 +      ice_for_each_vf_rcu(pf, bkt, vf) {
 +              if (test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
 +                      active = true;
 +                      break;
 +              }
        }
 +      rcu_read_unlock();
  
 -      return false;
 +      return active;
  }
  
  /**
@@@ -1300,14 -1295,6 +1300,14 @@@ static int ice_set_priv_flags(struct ne
                change_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, pf->flags);
                ret = -EAGAIN;
        }
 +
 +      if (test_bit(ICE_FLAG_VF_VLAN_PRUNING, change_flags) &&
 +          ice_has_vfs(pf)) {
 +              dev_err(dev, "vf-vlan-pruning: VLAN pruning cannot be changed while VFs are active.\n");
 +              /* toggle bit back to previous state */
 +              change_bit(ICE_FLAG_VF_VLAN_PRUNING, pf->flags);
 +              ret = -EOPNOTSUPP;
 +      }
  ethtool_exit:
        clear_bit(ICE_FLAG_ETHTOOL_CTXT, pf->flags);
        return ret;
@@@ -2311,7 -2298,7 +2311,7 @@@ ice_set_link_ksettings(struct net_devic
        if (err)
                goto done;
  
-       curr_link_speed = pi->phy.link_info.link_speed;
+       curr_link_speed = pi->phy.curr_user_speed_req;
        adv_link_speed = ice_ksettings_find_adv_link_speed(ks);
  
        /* If speed didn't get set, set it to what it currently is.
@@@ -2816,8 -2803,6 +2816,8 @@@ ice_set_ringparam(struct net_device *ne
                /* clone ring and setup updated count */
                xdp_rings[i] = *vsi->xdp_rings[i];
                xdp_rings[i].count = new_tx_cnt;
 +              xdp_rings[i].next_dd = ICE_RING_QUARTER(&xdp_rings[i]) - 1;
 +              xdp_rings[i].next_rs = ICE_RING_QUARTER(&xdp_rings[i]) - 1;
                xdp_rings[i].desc = NULL;
                xdp_rings[i].tx_buf = NULL;
                err = ice_setup_tx_ring(&xdp_rings[i]);
@@@ -21,7 -21,6 +21,7 @@@
  #include "ice_trace.h"
  #include "ice_eswitch.h"
  #include "ice_tc_lib.h"
 +#include "ice_vsi_vlan_ops.h"
  
  #define DRV_SUMMARY   "Intel(R) Ethernet Connection E800 Series Linux Driver"
  static const char ice_driver_string[] = DRV_SUMMARY;
@@@ -245,7 -244,7 +245,7 @@@ static int ice_set_promisc(struct ice_v
        if (vsi->type != ICE_VSI_PF)
                return 0;
  
 -      if (vsi->num_vlan > 1)
 +      if (ice_vsi_has_non_zero_vlans(vsi))
                status = ice_fltr_set_vlan_vsi_promisc(&vsi->back->hw, vsi, promisc_m);
        else
                status = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m, 0);
@@@ -265,7 -264,7 +265,7 @@@ static int ice_clear_promisc(struct ice
        if (vsi->type != ICE_VSI_PF)
                return 0;
  
 -      if (vsi->num_vlan > 1)
 +      if (ice_vsi_has_non_zero_vlans(vsi))
                status = ice_fltr_clear_vlan_vsi_promisc(&vsi->back->hw, vsi, promisc_m);
        else
                status = ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m, 0);
   */
  static int ice_vsi_sync_fltr(struct ice_vsi *vsi)
  {
 +      struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
        struct device *dev = ice_pf_to_dev(vsi->back);
        struct net_device *netdev = vsi->netdev;
        bool promisc_forced_on = false;
        /* check for changes in promiscuous modes */
        if (changed_flags & IFF_ALLMULTI) {
                if (vsi->current_netdev_flags & IFF_ALLMULTI) {
 -                      if (vsi->num_vlan > 1)
 +                      if (ice_vsi_has_non_zero_vlans(vsi))
                                promisc_m = ICE_MCAST_VLAN_PROMISC_BITS;
                        else
                                promisc_m = ICE_MCAST_PROMISC_BITS;
                        }
                } else {
                        /* !(vsi->current_netdev_flags & IFF_ALLMULTI) */
 -                      if (vsi->num_vlan > 1)
 +                      if (ice_vsi_has_non_zero_vlans(vsi))
                                promisc_m = ICE_MCAST_VLAN_PROMISC_BITS;
                        else
                                promisc_m = ICE_MCAST_PROMISC_BITS;
                                        goto out_promisc;
                                }
                                err = 0;
 -                              ice_cfg_vlan_pruning(vsi, false);
 +                              vlan_ops->dis_rx_filtering(vsi);
                        }
                } else {
                        /* Clear Rx filter to remove traffic from wire */
                                                IFF_PROMISC;
                                        goto out_promisc;
                                }
 -                              if (vsi->num_vlan > 1)
 -                                      ice_cfg_vlan_pruning(vsi, true);
 +                              if (vsi->current_netdev_flags &
 +                                  NETIF_F_HW_VLAN_CTAG_FILTER)
 +                                      vlan_ops->ena_rx_filtering(vsi);
                        }
                }
        }
@@@ -505,8 -502,7 +505,8 @@@ ice_prepare_for_reset(struct ice_pf *pf
  {
        struct ice_hw *hw = &pf->hw;
        struct ice_vsi *vsi;
 -      unsigned int i;
 +      struct ice_vf *vf;
 +      unsigned int bkt;
  
        dev_dbg(ice_pf_to_dev(pf), "reset_type=%d\n", reset_type);
  
                ice_vc_notify_reset(pf);
  
        /* Disable VFs until reset is completed */
 -      ice_for_each_vf(pf, i)
 -              ice_set_vf_state_qs_dis(&pf->vf[i]);
 +      mutex_lock(&pf->vfs.table_lock);
 +      ice_for_each_vf(pf, bkt, vf)
 +              ice_set_vf_state_qs_dis(vf);
 +      mutex_unlock(&pf->vfs.table_lock);
  
        if (ice_is_eswitch_mode_switchdev(pf)) {
                if (reset_type != ICE_RESET_PFR)
@@@ -571,9 -565,6 +571,9 @@@ skip
        if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
                ice_ptp_prepare_for_reset(pf);
  
 +      if (ice_is_feature_supported(pf, ICE_F_GNSS))
 +              ice_gnss_exit(pf);
 +
        if (hw->port_info)
                ice_sched_clear_port(hw->port_info);
  
@@@ -1669,8 -1660,7 +1669,8 @@@ static void ice_handle_mdd_event(struc
  {
        struct device *dev = ice_pf_to_dev(pf);
        struct ice_hw *hw = &pf->hw;
 -      unsigned int i;
 +      struct ice_vf *vf;
 +      unsigned int bkt;
        u32 reg;
  
        if (!test_and_clear_bit(ICE_MDD_EVENT_PENDING, pf->state)) {
        /* Check to see if one of the VFs caused an MDD event, and then
         * increment counters and set print pending
         */
 -      ice_for_each_vf(pf, i) {
 -              struct ice_vf *vf = &pf->vf[i];
 -
 -              reg = rd32(hw, VP_MDET_TX_PQM(i));
 +      mutex_lock(&pf->vfs.table_lock);
 +      ice_for_each_vf(pf, bkt, vf) {
 +              reg = rd32(hw, VP_MDET_TX_PQM(vf->vf_id));
                if (reg & VP_MDET_TX_PQM_VALID_M) {
 -                      wr32(hw, VP_MDET_TX_PQM(i), 0xFFFF);
 +                      wr32(hw, VP_MDET_TX_PQM(vf->vf_id), 0xFFFF);
                        vf->mdd_tx_events.count++;
                        set_bit(ICE_MDD_VF_PRINT_PENDING, pf->state);
                        if (netif_msg_tx_err(pf))
                                dev_info(dev, "Malicious Driver Detection event TX_PQM detected on VF %d\n",
 -                                       i);
 +                                       vf->vf_id);
                }
  
 -              reg = rd32(hw, VP_MDET_TX_TCLAN(i));
 +              reg = rd32(hw, VP_MDET_TX_TCLAN(vf->vf_id));
                if (reg & VP_MDET_TX_TCLAN_VALID_M) {
 -                      wr32(hw, VP_MDET_TX_TCLAN(i), 0xFFFF);
 +                      wr32(hw, VP_MDET_TX_TCLAN(vf->vf_id), 0xFFFF);
                        vf->mdd_tx_events.count++;
                        set_bit(ICE_MDD_VF_PRINT_PENDING, pf->state);
                        if (netif_msg_tx_err(pf))
                                dev_info(dev, "Malicious Driver Detection event TX_TCLAN detected on VF %d\n",
 -                                       i);
 +                                       vf->vf_id);
                }
  
 -              reg = rd32(hw, VP_MDET_TX_TDPU(i));
 +              reg = rd32(hw, VP_MDET_TX_TDPU(vf->vf_id));
                if (reg & VP_MDET_TX_TDPU_VALID_M) {
 -                      wr32(hw, VP_MDET_TX_TDPU(i), 0xFFFF);
 +                      wr32(hw, VP_MDET_TX_TDPU(vf->vf_id), 0xFFFF);
                        vf->mdd_tx_events.count++;
                        set_bit(ICE_MDD_VF_PRINT_PENDING, pf->state);
                        if (netif_msg_tx_err(pf))
                                dev_info(dev, "Malicious Driver Detection event TX_TDPU detected on VF %d\n",
 -                                       i);
 +                                       vf->vf_id);
                }
  
 -              reg = rd32(hw, VP_MDET_RX(i));
 +              reg = rd32(hw, VP_MDET_RX(vf->vf_id));
                if (reg & VP_MDET_RX_VALID_M) {
 -                      wr32(hw, VP_MDET_RX(i), 0xFFFF);
 +                      wr32(hw, VP_MDET_RX(vf->vf_id), 0xFFFF);
                        vf->mdd_rx_events.count++;
                        set_bit(ICE_MDD_VF_PRINT_PENDING, pf->state);
                        if (netif_msg_rx_err(pf))
                                dev_info(dev, "Malicious Driver Detection event RX detected on VF %d\n",
 -                                       i);
 +                                       vf->vf_id);
  
                        /* Since the queue is disabled on VF Rx MDD events, the
                         * PF can be configured to reset the VF through ethtool
                                 * reset, so print the event prior to reset.
                                 */
                                ice_print_vf_rx_mdd_event(vf);
 -                              mutex_lock(&pf->vf[i].cfg_lock);
 -                              ice_reset_vf(&pf->vf[i], false);
 -                              mutex_unlock(&pf->vf[i].cfg_lock);
 +                              mutex_lock(&vf->cfg_lock);
 +                              ice_reset_vf(vf, false);
 +                              mutex_unlock(&vf->cfg_lock);
                        }
                }
        }
 +      mutex_unlock(&pf->vfs.table_lock);
  
        ice_print_vfs_mdd_events(pf);
  }
@@@ -2265,9 -2255,30 +2265,30 @@@ static void ice_service_task(struct wor
                return;
        }
  
-       if (test_and_clear_bit(ICE_FLAG_PLUG_AUX_DEV, pf->flags))
+       if (test_bit(ICE_FLAG_PLUG_AUX_DEV, pf->flags)) {
+               /* Plug aux device per request */
                ice_plug_aux_dev(pf);
  
+               /* Mark plugging as done but check whether unplug was
+                * requested during ice_plug_aux_dev() call
+                * (e.g. from ice_clear_rdma_cap()) and if so then
+                * plug aux device.
+                */
+               if (!test_and_clear_bit(ICE_FLAG_PLUG_AUX_DEV, pf->flags))
+                       ice_unplug_aux_dev(pf);
+       }
+       if (test_and_clear_bit(ICE_FLAG_MTU_CHANGED, pf->flags)) {
+               struct iidc_event *event;
+               event = kzalloc(sizeof(*event), GFP_KERNEL);
+               if (event) {
+                       set_bit(IIDC_EVENT_AFTER_MTU_CHANGE, event->type);
+                       ice_send_event_to_aux(pf, event);
+                       kfree(event);
+               }
+       }
        ice_clean_adminq_subtask(pf);
        ice_check_media_subtask(pf);
        ice_check_for_hang_subtask(pf);
@@@ -2443,7 -2454,7 +2464,7 @@@ static int ice_vsi_req_irq_msix(struct 
                        /* skip this unused q_vector */
                        continue;
                }
 -              if (vsi->type == ICE_VSI_CTRL && vsi->vf_id != ICE_INVAL_VFID)
 +              if (vsi->type == ICE_VSI_CTRL && vsi->vf)
                        err = devm_request_irq(dev, irq_num, vsi->irq_handler,
                                               IRQF_SHARED, q_vector->name,
                                               q_vector);
@@@ -2510,10 -2521,10 +2531,10 @@@ static int ice_xdp_alloc_setup_rings(st
                xdp_ring->reg_idx = vsi->txq_map[xdp_q_idx];
                xdp_ring->vsi = vsi;
                xdp_ring->netdev = NULL;
 -              xdp_ring->next_dd = ICE_TX_THRESH - 1;
 -              xdp_ring->next_rs = ICE_TX_THRESH - 1;
                xdp_ring->dev = dev;
                xdp_ring->count = vsi->num_tx_desc;
 +              xdp_ring->next_dd = ICE_RING_QUARTER(xdp_ring) - 1;
 +              xdp_ring->next_rs = ICE_RING_QUARTER(xdp_ring) - 1;
                WRITE_ONCE(vsi->xdp_rings[i], xdp_ring);
                if (ice_setup_tx_ring(xdp_ring))
                        goto free_xdp_rings;
@@@ -3033,7 -3044,7 +3054,7 @@@ static irqreturn_t ice_misc_intr(int __
                struct iidc_event *event;
  
                ena_mask &= ~ICE_AUX_CRIT_ERR;
-               event = kzalloc(sizeof(*event), GFP_KERNEL);
+               event = kzalloc(sizeof(*event), GFP_ATOMIC);
                if (event) {
                        set_bit(IIDC_EVENT_CRIT_ERR, event->type);
                        /* report the entire OICR value to AUX driver */
@@@ -3245,7 -3256,6 +3266,7 @@@ static void ice_set_ops(struct net_devi
  static void ice_set_netdev_features(struct net_device *netdev)
  {
        struct ice_pf *pf = ice_netdev_to_pf(netdev);
 +      bool is_dvm_ena = ice_is_dvm_ena(&pf->hw);
        netdev_features_t csumo_features;
        netdev_features_t vlano_features;
        netdev_features_t dflt_features;
                         NETIF_F_HW_VLAN_CTAG_TX     |
                         NETIF_F_HW_VLAN_CTAG_RX;
  
 +      /* Enable CTAG/STAG filtering by default in Double VLAN Mode (DVM) */
 +      if (is_dvm_ena)
 +              vlano_features |= NETIF_F_HW_VLAN_STAG_FILTER;
 +
        tso_features = NETIF_F_TSO                      |
                       NETIF_F_TSO_ECN                  |
                       NETIF_F_TSO6                     |
                                   tso_features;
        netdev->vlan_features |= dflt_features | csumo_features |
                                 tso_features;
 +
 +      /* advertise support but don't enable by default since only one type of
 +       * VLAN offload can be enabled at a time (i.e. CTAG or STAG). When one
 +       * type turns on the other has to be turned off. This is enforced by the
 +       * ice_fix_features() ndo callback.
 +       */
 +      if (is_dvm_ena)
 +              netdev->hw_features |= NETIF_F_HW_VLAN_STAG_RX |
 +                      NETIF_F_HW_VLAN_STAG_TX;
  }
  
  /**
@@@ -3390,14 -3387,14 +3411,14 @@@ void ice_fill_rss_lut(u8 *lut, u16 rss_
  static struct ice_vsi *
  ice_pf_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)
  {
 -      return ice_vsi_setup(pf, pi, ICE_VSI_PF, ICE_INVAL_VFID, NULL);
 +      return ice_vsi_setup(pf, pi, ICE_VSI_PF, NULL, NULL);
  }
  
  static struct ice_vsi *
  ice_chnl_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
                   struct ice_channel *ch)
  {
 -      return ice_vsi_setup(pf, pi, ICE_VSI_CHNL, ICE_INVAL_VFID, ch);
 +      return ice_vsi_setup(pf, pi, ICE_VSI_CHNL, NULL, ch);
  }
  
  /**
  static struct ice_vsi *
  ice_ctrl_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)
  {
 -      return ice_vsi_setup(pf, pi, ICE_VSI_CTRL, ICE_INVAL_VFID, NULL);
 +      return ice_vsi_setup(pf, pi, ICE_VSI_CTRL, NULL, NULL);
  }
  
  /**
  struct ice_vsi *
  ice_lb_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)
  {
 -      return ice_vsi_setup(pf, pi, ICE_VSI_LB, ICE_INVAL_VFID, NULL);
 +      return ice_vsi_setup(pf, pi, ICE_VSI_LB, NULL, NULL);
  }
  
  /**
   * ice_vlan_rx_add_vid - Add a VLAN ID filter to HW offload
   * @netdev: network interface to be adjusted
 - * @proto: unused protocol
 + * @proto: VLAN TPID
   * @vid: VLAN ID to be added
   *
   * net_device_ops implementation for adding VLAN IDs
   */
  static int
 -ice_vlan_rx_add_vid(struct net_device *netdev, __always_unused __be16 proto,
 -                  u16 vid)
 +ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
  {
        struct ice_netdev_priv *np = netdev_priv(netdev);
 +      struct ice_vsi_vlan_ops *vlan_ops;
        struct ice_vsi *vsi = np->vsi;
 +      struct ice_vlan vlan;
        int ret;
  
        /* VLAN 0 is added by default during load/reset */
        if (!vid)
                return 0;
  
 -      /* Enable VLAN pruning when a VLAN other than 0 is added */
 -      if (!ice_vsi_is_vlan_pruning_ena(vsi)) {
 -              ret = ice_cfg_vlan_pruning(vsi, true);
 -              if (ret)
 -                      return ret;
 -      }
 +      vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
  
        /* Add a switch rule for this VLAN ID so its corresponding VLAN tagged
         * packets aren't pruned by the device's internal switch on Rx
         */
 -      ret = ice_vsi_add_vlan(vsi, vid, ICE_FWD_TO_VSI);
 +      vlan = ICE_VLAN(be16_to_cpu(proto), vid, 0);
 +      ret = vlan_ops->add_vlan(vsi, &vlan);
        if (!ret)
                set_bit(ICE_VSI_VLAN_FLTR_CHANGED, vsi->state);
  
  /**
   * ice_vlan_rx_kill_vid - Remove a VLAN ID filter from HW offload
   * @netdev: network interface to be adjusted
 - * @proto: unused protocol
 + * @proto: VLAN TPID
   * @vid: VLAN ID to be removed
   *
   * net_device_ops implementation for removing VLAN IDs
   */
  static int
 -ice_vlan_rx_kill_vid(struct net_device *netdev, __always_unused __be16 proto,
 -                   u16 vid)
 +ice_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
  {
        struct ice_netdev_priv *np = netdev_priv(netdev);
 +      struct ice_vsi_vlan_ops *vlan_ops;
        struct ice_vsi *vsi = np->vsi;
 +      struct ice_vlan vlan;
        int ret;
  
        /* don't allow removal of VLAN 0 */
        if (!vid)
                return 0;
  
 -      /* Make sure ice_vsi_kill_vlan is successful before updating VLAN
 +      vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
 +
 +      /* Make sure VLAN delete is successful before updating VLAN
         * information
         */
 -      ret = ice_vsi_kill_vlan(vsi, vid);
 +      vlan = ICE_VLAN(be16_to_cpu(proto), vid, 0);
 +      ret = vlan_ops->del_vlan(vsi, &vlan);
        if (ret)
                return ret;
  
 -      /* Disable pruning when VLAN 0 is the only VLAN rule */
 -      if (vsi->num_vlan == 1 && ice_vsi_is_vlan_pruning_ena(vsi))
 -              ret = ice_cfg_vlan_pruning(vsi, false);
 -
        set_bit(ICE_VSI_VLAN_FLTR_CHANGED, vsi->state);
 -      return ret;
 +      return 0;
  }
  
  /**
@@@ -3563,17 -3563,12 +3584,17 @@@ static int ice_tc_indir_block_register(
  static int ice_setup_pf_sw(struct ice_pf *pf)
  {
        struct device *dev = ice_pf_to_dev(pf);
 +      bool dvm = ice_is_dvm_ena(&pf->hw);
        struct ice_vsi *vsi;
        int status;
  
        if (ice_is_reset_in_progress(pf->state))
                return -EBUSY;
  
 +      status = ice_aq_set_port_params(pf->hw.port_info, dvm, NULL);
 +      if (status)
 +              return -EIO;
 +
        vsi = ice_pf_vsi_setup(pf, pf->hw.port_info);
        if (!vsi)
                return -ENOMEM;
@@@ -3684,7 -3679,6 +3705,7 @@@ static void ice_deinit_pf(struct ice_p
        mutex_destroy(&pf->sw_mutex);
        mutex_destroy(&pf->tc_mutex);
        mutex_destroy(&pf->avail_q_mutex);
 +      mutex_destroy(&pf->vfs.table_lock);
  
        if (pf->avail_txqs) {
                bitmap_free(pf->avail_txqs);
@@@ -3709,15 -3703,18 +3730,15 @@@ static void ice_set_pf_caps(struct ice_
        struct ice_hw_func_caps *func_caps = &pf->hw.func_caps;
  
        clear_bit(ICE_FLAG_RDMA_ENA, pf->flags);
 -      clear_bit(ICE_FLAG_AUX_ENA, pf->flags);
 -      if (func_caps->common_cap.rdma) {
 +      if (func_caps->common_cap.rdma)
                set_bit(ICE_FLAG_RDMA_ENA, pf->flags);
 -              set_bit(ICE_FLAG_AUX_ENA, pf->flags);
 -      }
        clear_bit(ICE_FLAG_DCB_CAPABLE, pf->flags);
        if (func_caps->common_cap.dcb)
                set_bit(ICE_FLAG_DCB_CAPABLE, pf->flags);
        clear_bit(ICE_FLAG_SRIOV_CAPABLE, pf->flags);
        if (func_caps->common_cap.sr_iov_1_1) {
                set_bit(ICE_FLAG_SRIOV_CAPABLE, pf->flags);
 -              pf->num_vfs_supported = min_t(int, func_caps->num_allocd_vfs,
 +              pf->vfs.num_supported = min_t(int, func_caps->num_allocd_vfs,
                                              ICE_MAX_VF_COUNT);
        }
        clear_bit(ICE_FLAG_RSS_ENA, pf->flags);
@@@ -3784,9 -3781,6 +3805,9 @@@ static int ice_init_pf(struct ice_pf *p
                return -ENOMEM;
        }
  
 +      mutex_init(&pf->vfs.table_lock);
 +      hash_init(pf->vfs.table);
 +
        return 0;
  }
  
@@@ -3841,7 -3835,7 +3862,7 @@@ static int ice_ena_msix_range(struct ic
        v_left -= needed;
  
        /* reserve vectors for RDMA auxiliary driver */
 -      if (test_bit(ICE_FLAG_RDMA_ENA, pf->flags)) {
 +      if (ice_is_rdma_ena(pf)) {
                needed = num_cpus + ICE_RDMA_NUM_AEQ_MSIX;
                if (v_left < needed)
                        goto no_hw_vecs_left_err;
                        int v_remain = v_actual - v_other;
                        int v_rdma = 0, v_min_rdma = 0;
  
 -                      if (test_bit(ICE_FLAG_RDMA_ENA, pf->flags)) {
 +                      if (ice_is_rdma_ena(pf)) {
                                /* Need at least 1 interrupt in addition to
                                 * AEQ MSIX
                                 */
                        dev_notice(dev, "Enabled %d MSI-X vectors for LAN traffic.\n",
                                   pf->num_lan_msix);
  
 -                      if (test_bit(ICE_FLAG_RDMA_ENA, pf->flags))
 +                      if (ice_is_rdma_ena(pf))
                                dev_notice(dev, "Enabled %d MSI-X vectors for RDMA.\n",
                                           pf->num_rdma_msix);
                }
@@@ -4096,8 -4090,8 +4117,8 @@@ static void ice_set_safe_mode_vlan_cfg(
        ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
  
        /* allow all VLANs on Tx and don't strip on Rx */
 -      ctxt->info.vlan_flags = ICE_AQ_VSI_VLAN_MODE_ALL |
 -              ICE_AQ_VSI_VLAN_EMOD_NOTHING;
 +      ctxt->info.inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL |
 +              ICE_AQ_VSI_INNER_VLAN_EMODE_NOTHING;
  
        status = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
        if (status) {
        } else {
                vsi->info.sec_flags = ctxt->info.sec_flags;
                vsi->info.sw_flags2 = ctxt->info.sw_flags2;
 -              vsi->info.vlan_flags = ctxt->info.vlan_flags;
 +              vsi->info.inner_vlan_flags = ctxt->info.inner_vlan_flags;
        }
  
        kfree(ctxt);
@@@ -4491,6 -4485,8 +4512,6 @@@ ice_probe(struct pci_dev *pdev, const s
  
        /* set up for high or low DMA */
        err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
 -      if (err)
 -              err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
        if (err) {
                dev_err(dev, "DMA configuration failed: 0x%x\n", err);
                return err;
        if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
                ice_ptp_init(pf);
  
 +      if (ice_is_feature_supported(pf, ICE_F_GNSS))
 +              ice_gnss_init(pf);
 +
        /* Note: Flow director init failure is non-fatal to load */
        if (ice_init_fdir(pf))
                dev_err(dev, "could not initialize flow director\n");
@@@ -4745,7 -4738,7 +4766,7 @@@ probe_done
  
        /* ready to go, so clear down state bit */
        clear_bit(ICE_DOWN, pf->state);
 -      if (ice_is_aux_ena(pf)) {
 +      if (ice_is_rdma_ena(pf)) {
                pf->aux_idx = ida_alloc(&ice_aux_ida, GFP_KERNEL);
                if (pf->aux_idx < 0) {
                        dev_err(dev, "Failed to allocate device ID for AUX driver\n");
@@@ -4891,8 -4884,6 +4912,8 @@@ static void ice_remove(struct pci_dev *
        ice_deinit_lag(pf);
        if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
                ice_ptp_release(pf);
 +      if (ice_is_feature_supported(pf, ICE_F_GNSS))
 +              ice_gnss_exit(pf);
        if (!ice_is_safe_mode(pf))
                ice_remove_arfs(pf);
        ice_setup_mc_magic_wake(pf);
@@@ -5605,194 -5596,6 +5626,194 @@@ ice_fdb_del(struct ndmsg *ndm, __always
        return err;
  }
  
 +#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)
 +
 +#define NETIF_VLAN_FILTERING_FEATURES (NETIF_F_HW_VLAN_CTAG_FILTER | \
 +                                       NETIF_F_HW_VLAN_STAG_FILTER)
 +
 +/**
 + * ice_fix_features - fix the netdev features flags based on device limitations
 + * @netdev: ptr to the netdev that flags are being fixed on
 + * @features: features that need to be checked and possibly fixed
 + *
 + * Make sure any fixups are made to features in this callback. This enables the
 + * driver to not have to check unsupported configurations throughout the driver
 + * because that's the responsiblity of this callback.
 + *
 + * Single VLAN Mode (SVM) Supported Features:
 + *    NETIF_F_HW_VLAN_CTAG_FILTER
 + *    NETIF_F_HW_VLAN_CTAG_RX
 + *    NETIF_F_HW_VLAN_CTAG_TX
 + *
 + * Double VLAN Mode (DVM) Supported Features:
 + *    NETIF_F_HW_VLAN_CTAG_FILTER
 + *    NETIF_F_HW_VLAN_CTAG_RX
 + *    NETIF_F_HW_VLAN_CTAG_TX
 + *
 + *    NETIF_F_HW_VLAN_STAG_FILTER
 + *    NETIF_HW_VLAN_STAG_RX
 + *    NETIF_HW_VLAN_STAG_TX
 + *
 + * Features that need fixing:
 + *    Cannot simultaneously enable CTAG and STAG stripping and/or insertion.
 + *    These are mutually exlusive as the VSI context cannot support multiple
 + *    VLAN ethertypes simultaneously for stripping and/or insertion. If this
 + *    is not done, then default to clearing the requested STAG offload
 + *    settings.
 + *
 + *    All supported filtering has to be enabled or disabled together. For
 + *    example, in DVM, CTAG and STAG filtering have to be enabled and disabled
 + *    together. If this is not done, then default to VLAN filtering disabled.
 + *    These are mutually exclusive as there is currently no way to
 + *    enable/disable VLAN filtering based on VLAN ethertype when using VLAN
 + *    prune rules.
 + */
 +static netdev_features_t
 +ice_fix_features(struct net_device *netdev, netdev_features_t features)
 +{
 +      struct ice_netdev_priv *np = netdev_priv(netdev);
 +      netdev_features_t supported_vlan_filtering;
 +      netdev_features_t requested_vlan_filtering;
 +      struct ice_vsi *vsi = np->vsi;
 +
 +      requested_vlan_filtering = features & NETIF_VLAN_FILTERING_FEATURES;
 +
 +      /* make sure supported_vlan_filtering works for both SVM and DVM */
 +      supported_vlan_filtering = NETIF_F_HW_VLAN_CTAG_FILTER;
 +      if (ice_is_dvm_ena(&vsi->back->hw))
 +              supported_vlan_filtering |= NETIF_F_HW_VLAN_STAG_FILTER;
 +
 +      if (requested_vlan_filtering &&
 +          requested_vlan_filtering != supported_vlan_filtering) {
 +              if (requested_vlan_filtering & NETIF_F_HW_VLAN_CTAG_FILTER) {
 +                      netdev_warn(netdev, "cannot support requested VLAN filtering settings, enabling all supported VLAN filtering settings\n");
 +                      features |= supported_vlan_filtering;
 +              } else {
 +                      netdev_warn(netdev, "cannot support requested VLAN filtering settings, clearing all supported VLAN filtering settings\n");
 +                      features &= ~supported_vlan_filtering;
 +              }
 +      }
 +
 +      if ((features & (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX)) &&
 +          (features & (NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX))) {
 +              netdev_warn(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");
 +              features &= ~(NETIF_F_HW_VLAN_STAG_RX |
 +                            NETIF_F_HW_VLAN_STAG_TX);
 +      }
 +
 +      return features;
 +}
 +
 +/**
 + * ice_set_vlan_offload_features - set VLAN offload features for the PF VSI
 + * @vsi: PF's VSI
 + * @features: features used to determine VLAN offload settings
 + *
 + * First, determine the vlan_ethertype based on the VLAN offload bits in
 + * features. Then determine if stripping and insertion should be enabled or
 + * disabled. Finally enable or disable VLAN stripping and insertion.
 + */
 +static int
 +ice_set_vlan_offload_features(struct ice_vsi *vsi, netdev_features_t features)
 +{
 +      bool enable_stripping = true, enable_insertion = true;
 +      struct ice_vsi_vlan_ops *vlan_ops;
 +      int strip_err = 0, insert_err = 0;
 +      u16 vlan_ethertype = 0;
 +
 +      vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
 +
 +      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;
 +
 +      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 (enable_stripping)
 +              strip_err = vlan_ops->ena_stripping(vsi, vlan_ethertype);
 +      else
 +              strip_err = vlan_ops->dis_stripping(vsi);
 +
 +      if (enable_insertion)
 +              insert_err = vlan_ops->ena_insertion(vsi, vlan_ethertype);
 +      else
 +              insert_err = vlan_ops->dis_insertion(vsi);
 +
 +      if (strip_err || insert_err)
 +              return -EIO;
 +
 +      return 0;
 +}
 +
 +/**
 + * ice_set_vlan_filtering_features - set VLAN filtering features for the PF VSI
 + * @vsi: PF's VSI
 + * @features: features used to determine VLAN filtering settings
 + *
 + * Enable or disable Rx VLAN filtering based on the VLAN filtering bits in the
 + * features.
 + */
 +static int
 +ice_set_vlan_filtering_features(struct ice_vsi *vsi, netdev_features_t features)
 +{
 +      struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
 +      int err = 0;
 +
 +      /* support Single VLAN Mode (SVM) and Double VLAN Mode (DVM) by checking
 +       * if either bit is set
 +       */
 +      if (features &
 +          (NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_STAG_FILTER))
 +              err = vlan_ops->ena_rx_filtering(vsi);
 +      else
 +              err = vlan_ops->dis_rx_filtering(vsi);
 +
 +      return err;
 +}
 +
 +/**
 + * ice_set_vlan_features - set VLAN settings based on suggested feature set
 + * @netdev: ptr to the netdev being adjusted
 + * @features: the feature set that the stack is suggesting
 + *
 + * Only update VLAN settings if the requested_vlan_features are different than
 + * the current_vlan_features.
 + */
 +static int
 +ice_set_vlan_features(struct net_device *netdev, netdev_features_t features)
 +{
 +      netdev_features_t current_vlan_features, requested_vlan_features;
 +      struct ice_netdev_priv *np = netdev_priv(netdev);
 +      struct ice_vsi *vsi = np->vsi;
 +      int err;
 +
 +      current_vlan_features = netdev->features & NETIF_VLAN_OFFLOAD_FEATURES;
 +      requested_vlan_features = features & NETIF_VLAN_OFFLOAD_FEATURES;
 +      if (current_vlan_features ^ requested_vlan_features) {
 +              err = ice_set_vlan_offload_features(vsi, features);
 +              if (err)
 +                      return err;
 +      }
 +
 +      current_vlan_features = netdev->features &
 +              NETIF_VLAN_FILTERING_FEATURES;
 +      requested_vlan_features = features & NETIF_VLAN_FILTERING_FEATURES;
 +      if (current_vlan_features ^ requested_vlan_features) {
 +              err = ice_set_vlan_filtering_features(vsi, features);
 +              if (err)
 +                      return err;
 +      }
 +
 +      return 0;
 +}
 +
  /**
   * ice_set_features - set the netdev feature flags
   * @netdev: ptr to the netdev being adjusted
@@@ -5827,9 -5630,26 +5848,9 @@@ ice_set_features(struct net_device *net
                 netdev->features & NETIF_F_RXHASH)
                ice_vsi_manage_rss_lut(vsi, false);
  
 -      if ((features & NETIF_F_HW_VLAN_CTAG_RX) &&
 -          !(netdev->features & NETIF_F_HW_VLAN_CTAG_RX))
 -              ret = ice_vsi_manage_vlan_stripping(vsi, true);
 -      else if (!(features & NETIF_F_HW_VLAN_CTAG_RX) &&
 -               (netdev->features & NETIF_F_HW_VLAN_CTAG_RX))
 -              ret = ice_vsi_manage_vlan_stripping(vsi, false);
 -
 -      if ((features & NETIF_F_HW_VLAN_CTAG_TX) &&
 -          !(netdev->features & NETIF_F_HW_VLAN_CTAG_TX))
 -              ret = ice_vsi_manage_vlan_insertion(vsi);
 -      else if (!(features & NETIF_F_HW_VLAN_CTAG_TX) &&
 -               (netdev->features & NETIF_F_HW_VLAN_CTAG_TX))
 -              ret = ice_vsi_manage_vlan_insertion(vsi);
 -
 -      if ((features & NETIF_F_HW_VLAN_CTAG_FILTER) &&
 -          !(netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
 -              ret = ice_cfg_vlan_pruning(vsi, true);
 -      else if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER) &&
 -               (netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
 -              ret = ice_cfg_vlan_pruning(vsi, false);
 +      ret = ice_set_vlan_features(netdev, features);
 +      if (ret)
 +              return ret;
  
        if ((features & NETIF_F_NTUPLE) &&
            !(netdev->features & NETIF_F_NTUPLE)) {
        else
                clear_bit(ICE_FLAG_CLS_FLOWER, pf->flags);
  
 -      return ret;
 +      return 0;
  }
  
  /**
 - * ice_vsi_vlan_setup - Setup VLAN offload properties on a VSI
 + * ice_vsi_vlan_setup - Setup VLAN offload properties on a PF VSI
   * @vsi: VSI to setup VLAN properties for
   */
  static int ice_vsi_vlan_setup(struct ice_vsi *vsi)
  {
 -      int ret = 0;
 +      int err;
  
 -      if (vsi->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
 -              ret = ice_vsi_manage_vlan_stripping(vsi, true);
 -      if (vsi->netdev->features & NETIF_F_HW_VLAN_CTAG_TX)
 -              ret = ice_vsi_manage_vlan_insertion(vsi);
 +      err = ice_set_vlan_offload_features(vsi, vsi->netdev->features);
 +      if (err)
 +              return err;
  
 -      return ret;
 +      err = ice_set_vlan_filtering_features(vsi, vsi->netdev->features);
 +      if (err)
 +              return err;
 +
 +      return ice_vsi_add_vlan_zero(vsi);
  }
  
  /**
@@@ -6473,12 -6290,11 +6494,12 @@@ static void ice_napi_disable_all(struc
   */
  int ice_down(struct ice_vsi *vsi)
  {
 -      int i, tx_err, rx_err, link_err = 0;
 +      int i, tx_err, rx_err, link_err = 0, vlan_err = 0;
  
        WARN_ON(!test_bit(ICE_VSI_DOWN, vsi->state));
  
        if (vsi->netdev && vsi->type == ICE_VSI_PF) {
 +              vlan_err = ice_vsi_del_vlan_zero(vsi);
                if (!ice_is_e810(&vsi->back->hw))
                        ice_ptp_link_change(vsi->back, vsi->back->hw.pf_id, false);
                netif_carrier_off(vsi->netdev);
        ice_for_each_rxq(vsi, i)
                ice_clean_rx_ring(vsi->rx_rings[i]);
  
 -      if (tx_err || rx_err || link_err) {
 +      if (tx_err || rx_err || link_err || vlan_err) {
                netdev_err(vsi->netdev, "Failed to close VSI 0x%04X on switch 0x%04X\n",
                           vsi->vsi_num, vsi->vsw->sw_id);
                return -EIO;
@@@ -6830,7 -6646,6 +6851,7 @@@ static void ice_rebuild(struct ice_pf *
  {
        struct device *dev = ice_pf_to_dev(pf);
        struct ice_hw *hw = &pf->hw;
 +      bool dvm;
        int err;
  
        if (test_bit(ICE_DOWN, pf->state))
                goto err_init_ctrlq;
        }
  
 +      dvm = ice_is_dvm_ena(hw);
 +
 +      err = ice_aq_set_port_params(pf->hw.port_info, dvm, NULL);
 +      if (err)
 +              goto err_init_ctrlq;
 +
        err = ice_sched_init_port(hw->port_info);
        if (err)
                goto err_sched_init_port;
        if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
                ice_ptp_reset(pf);
  
 +      if (ice_is_feature_supported(pf, ICE_F_GNSS))
 +              ice_gnss_init(pf);
 +
        /* rebuild PF VSI */
        err = ice_vsi_rebuild_by_type(pf, ICE_VSI_PF);
        if (err) {
@@@ -7037,7 -6843,6 +7058,6 @@@ static int ice_change_mtu(struct net_de
        struct ice_netdev_priv *np = netdev_priv(netdev);
        struct ice_vsi *vsi = np->vsi;
        struct ice_pf *pf = vsi->back;
-       struct iidc_event *event;
        u8 count = 0;
        int err = 0;
  
                return -EBUSY;
        }
  
-       event = kzalloc(sizeof(*event), GFP_KERNEL);
-       if (!event)
-               return -ENOMEM;
-       set_bit(IIDC_EVENT_BEFORE_MTU_CHANGE, event->type);
-       ice_send_event_to_aux(pf, event);
-       clear_bit(IIDC_EVENT_BEFORE_MTU_CHANGE, event->type);
        netdev->mtu = (unsigned int)new_mtu;
  
        /* if VSI is up, bring it down and then back up */
                err = ice_down(vsi);
                if (err) {
                        netdev_err(netdev, "change MTU if_down err %d\n", err);
-                       goto event_after;
+                       return err;
                }
  
                err = ice_up(vsi);
                if (err) {
                        netdev_err(netdev, "change MTU if_up err %d\n", err);
-                       goto event_after;
+                       return err;
                }
        }
  
        netdev_dbg(netdev, "changed MTU to %d\n", new_mtu);
- event_after:
-       set_bit(IIDC_EVENT_AFTER_MTU_CHANGE, event->type);
-       ice_send_event_to_aux(pf, event);
-       kfree(event);
+       set_bit(ICE_FLAG_MTU_CHANGED, pf->flags);
  
        return err;
  }
@@@ -8811,7 -8605,6 +8820,7 @@@ static const struct net_device_ops ice_
        .ndo_start_xmit = ice_start_xmit,
        .ndo_select_queue = ice_select_queue,
        .ndo_features_check = ice_features_check,
 +      .ndo_fix_features = ice_fix_features,
        .ndo_set_rx_mode = ice_set_rx_mode,
        .ndo_set_mac_address = ice_set_mac_address,
        .ndo_validate_addr = eth_validate_addr,
@@@ -10,8 -10,6 +10,8 @@@
  #include "ice_eswitch.h"
  #include "ice_virtchnl_allowlist.h"
  #include "ice_flex_pipe.h"
 +#include "ice_vf_vsi_vlan_ops.h"
 +#include "ice_vlan.h"
  
  #define FIELD_SELECTOR(proto_hdr_field) \
                BIT((proto_hdr_field) & PROTO_HDR_FIELD_MASK)
@@@ -175,107 -173,18 +175,107 @@@ struct ice_vsi *ice_get_vf_vsi(struct i
  }
  
  /**
 - * ice_validate_vf_id - helper to check if VF ID is valid
 - * @pf: pointer to the PF structure
 - * @vf_id: the ID of the VF to check
 + * ice_get_vf_by_id - Get pointer to VF by ID
 + * @pf: the PF private structure
 + * @vf_id: the VF ID to locate
 + *
 + * Locate and return a pointer to the VF structure associated with a given ID.
 + * Returns NULL if the ID does not have a valid VF structure associated with
 + * it.
 + *
 + * This function takes a reference to the VF, which must be released by
 + * calling ice_put_vf() once the caller is finished accessing the VF structure
 + * returned.
   */
 -static int ice_validate_vf_id(struct ice_pf *pf, u16 vf_id)
 +struct ice_vf *ice_get_vf_by_id(struct ice_pf *pf, u16 vf_id)
  {
 -      /* vf_id range is only valid for 0-255, and should always be unsigned */
 -      if (vf_id >= pf->num_alloc_vfs) {
 -              dev_err(ice_pf_to_dev(pf), "Invalid VF ID: %u\n", vf_id);
 -              return -EINVAL;
 +      struct ice_vf *vf;
 +
 +      rcu_read_lock();
 +      hash_for_each_possible_rcu(pf->vfs.table, vf, entry, vf_id) {
 +              if (vf->vf_id == vf_id) {
 +                      struct ice_vf *found;
 +
 +                      if (kref_get_unless_zero(&vf->refcnt))
 +                              found = vf;
 +                      else
 +                              found = NULL;
 +
 +                      rcu_read_unlock();
 +                      return found;
 +              }
        }
 -      return 0;
 +      rcu_read_unlock();
 +
 +      return NULL;
 +}
 +
 +/**
 + * ice_release_vf - Release VF associated with a refcount
 + * @ref: the kref decremented to zero
 + *
 + * Callback function for kref_put to release a VF once its reference count has
 + * hit zero.
 + */
 +static void ice_release_vf(struct kref *ref)
 +{
 +      struct ice_vf *vf = container_of(ref, struct ice_vf, refcnt);
 +
 +      mutex_destroy(&vf->cfg_lock);
 +
 +      kfree_rcu(vf, rcu);
 +}
 +
 +/**
 + * ice_put_vf - Release a reference to a VF
 + * @vf: the VF structure to decrease reference count on
 + *
 + * This must be called after ice_get_vf_by_id() once the reference to the VF
 + * structure is no longer used. Otherwise, the VF structure will never be
 + * freed.
 + */
 +void ice_put_vf(struct ice_vf *vf)
 +{
 +      kref_put(&vf->refcnt, ice_release_vf);
 +}
 +
 +/**
 + * ice_has_vfs - Return true if the PF has any associated VFs
 + * @pf: the PF private structure
 + *
 + * Return whether or not the PF has any allocated VFs.
 + *
 + * Note that this function only guarantees that there are no VFs at the point
 + * of calling it. It does not guarantee that no more VFs will be added.
 + */
 +bool ice_has_vfs(struct ice_pf *pf)
 +{
 +      /* A simple check that the hash table is not empty does not require
 +       * the mutex or rcu_read_lock.
 +       */
 +      return !hash_empty(pf->vfs.table);
 +}
 +
 +/**
 + * ice_get_num_vfs - Get number of allocated VFs
 + * @pf: the PF private structure
 + *
 + * Return the total number of allocated VFs. NOTE: VF IDs are not guaranteed
 + * to be contiguous. Do not assume that a VF ID is guaranteed to be less than
 + * the output of this function.
 + */
 +u16 ice_get_num_vfs(struct ice_pf *pf)
 +{
 +      struct ice_vf *vf;
 +      unsigned int bkt;
 +      u16 num_vfs = 0;
 +
 +      rcu_read_lock();
 +      ice_for_each_vf_rcu(pf, bkt, vf)
 +              num_vfs++;
 +      rcu_read_unlock();
 +
 +      return num_vfs;
  }
  
  /**
@@@ -293,32 -202,6 +293,32 @@@ static int ice_check_vf_init(struct ice
        return 0;
  }
  
 +/**
 + * ice_free_vf_entries - Free all VF entries from the hash table
 + * @pf: pointer to the PF structure
 + *
 + * Iterate over the VF hash table, removing and releasing all VF entries.
 + * Called during VF teardown or as cleanup during failed VF initialization.
 + */
 +static void ice_free_vf_entries(struct ice_pf *pf)
 +{
 +      struct ice_vfs *vfs = &pf->vfs;
 +      struct hlist_node *tmp;
 +      struct ice_vf *vf;
 +      unsigned int bkt;
 +
 +      /* Remove all VFs from the hash table and release their main
 +       * reference. Once all references to the VF are dropped, ice_put_vf()
 +       * will call ice_release_vf which will remove the VF memory.
 +       */
 +      lockdep_assert_held(&vfs->table_lock);
 +
 +      hash_for_each_safe(vfs->table, bkt, tmp, vf, entry) {
 +              hash_del_rcu(&vf->entry);
 +              ice_put_vf(vf);
 +      }
 +}
 +
  /**
   * ice_vc_vf_broadcast - Broadcast a message to all VFs on PF
   * @pf: pointer to the PF structure
@@@ -332,11 -215,11 +332,11 @@@ ice_vc_vf_broadcast(struct ice_pf *pf, 
                    enum virtchnl_status_code v_retval, u8 *msg, u16 msglen)
  {
        struct ice_hw *hw = &pf->hw;
 -      unsigned int i;
 -
 -      ice_for_each_vf(pf, i) {
 -              struct ice_vf *vf = &pf->vf[i];
 +      struct ice_vf *vf;
 +      unsigned int bkt;
  
 +      mutex_lock(&pf->vfs.table_lock);
 +      ice_for_each_vf(pf, bkt, vf) {
                /* Not all vfs are enabled so skip the ones that are not */
                if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states) &&
                    !test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
                ice_aq_send_msg_to_vf(hw, vf->vf_id, v_opcode, v_retval, msg,
                                      msglen, NULL);
        }
 +      mutex_unlock(&pf->vfs.table_lock);
  }
  
  /**
@@@ -497,7 -379,7 +497,7 @@@ static void ice_free_vf_res(struct ice_
                vf->num_mac = 0;
        }
  
 -      last_vector_idx = vf->first_vector_idx + pf->num_msix_per_vf - 1;
 +      last_vector_idx = vf->first_vector_idx + pf->vfs.num_msix_per - 1;
  
        /* clear VF MDD event information */
        memset(&vf->mdd_tx_events, 0, sizeof(vf->mdd_tx_events));
@@@ -533,7 -415,7 +533,7 @@@ static void ice_dis_vf_mappings(struct 
        wr32(hw, VPINT_ALLOC_PCI(vf->vf_id), 0);
  
        first = vf->first_vector_idx;
 -      last = first + pf->num_msix_per_vf - 1;
 +      last = first + pf->vfs.num_msix_per - 1;
        for (v = first; v <= last; v++) {
                u32 reg;
  
@@@ -615,14 -497,14 +615,14 @@@ static void ice_dis_vf_qs(struct ice_v
  void ice_free_vfs(struct ice_pf *pf)
  {
        struct device *dev = ice_pf_to_dev(pf);
 +      struct ice_vfs *vfs = &pf->vfs;
        struct ice_hw *hw = &pf->hw;
 -      unsigned int tmp, i;
 +      struct ice_vf *vf;
 +      unsigned int bkt;
  
 -      if (!pf->vf)
 +      if (!ice_has_vfs(pf))
                return;
  
 -      ice_eswitch_release(pf);
 -
        while (test_and_set_bit(ICE_VF_DIS, pf->state))
                usleep_range(1000, 2000);
  
        else
                dev_warn(dev, "VFs are assigned - not disabling SR-IOV\n");
  
 -      tmp = pf->num_alloc_vfs;
 -      pf->num_qps_per_vf = 0;
 -      pf->num_alloc_vfs = 0;
 -      for (i = 0; i < tmp; i++) {
 -              struct ice_vf *vf = &pf->vf[i];
 +      mutex_lock(&vfs->table_lock);
 +
 +      ice_eswitch_release(pf);
  
 +      ice_for_each_vf(pf, bkt, vf) {
                mutex_lock(&vf->cfg_lock);
  
                ice_dis_vf_qs(vf);
                        ice_free_vf_res(vf);
                }
  
 -              mutex_unlock(&vf->cfg_lock);
 +              if (!pci_vfs_assigned(pf->pdev)) {
 +                      u32 reg_idx, bit_idx;
 +
 +                      reg_idx = (hw->func_caps.vf_base_id + vf->vf_id) / 32;
 +                      bit_idx = (hw->func_caps.vf_base_id + vf->vf_id) % 32;
 +                      wr32(hw, GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
 +              }
  
 -              mutex_destroy(&vf->cfg_lock);
 +              /* clear malicious info since the VF is getting released */
 +              if (ice_mbx_clear_malvf(&hw->mbx_snapshot, pf->vfs.malvfs,
 +                                      ICE_MAX_VF_COUNT, vf->vf_id))
 +                      dev_dbg(dev, "failed to clear malicious VF state for VF %u\n",
 +                              vf->vf_id);
 +
 +              mutex_unlock(&vf->cfg_lock);
        }
  
        if (ice_sriov_free_msix_res(pf))
                dev_err(dev, "Failed to free MSIX resources used by SR-IOV\n");
  
 -      devm_kfree(dev, pf->vf);
 -      pf->vf = NULL;
 -
 -      /* This check is for when the driver is unloaded while VFs are
 -       * assigned. Setting the number of VFs to 0 through sysfs is caught
 -       * before this function ever gets called.
 -       */
 -      if (!pci_vfs_assigned(pf->pdev)) {
 -              unsigned int vf_id;
 -
 -              /* Acknowledge VFLR for all VFs. Without this, VFs will fail to
 -               * work correctly when SR-IOV gets re-enabled.
 -               */
 -              for (vf_id = 0; vf_id < tmp; vf_id++) {
 -                      u32 reg_idx, bit_idx;
 -
 -                      reg_idx = (hw->func_caps.vf_base_id + vf_id) / 32;
 -                      bit_idx = (hw->func_caps.vf_base_id + vf_id) % 32;
 -                      wr32(hw, GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
 -              }
 -      }
 +      vfs->num_qps_per = 0;
 +      ice_free_vf_entries(pf);
  
 -      /* clear malicious info if the VFs are getting released */
 -      for (i = 0; i < tmp; i++)
 -              if (ice_mbx_clear_malvf(&hw->mbx_snapshot, pf->malvfs,
 -                                      ICE_MAX_VF_COUNT, i))
 -                      dev_dbg(dev, "failed to clear malicious VF state for VF %u\n",
 -                              i);
 +      mutex_unlock(&vfs->table_lock);
  
        clear_bit(ICE_VF_DIS, pf->state);
        clear_bit(ICE_FLAG_SRIOV_ENA, pf->flags);
@@@ -748,6 -643,55 +748,6 @@@ static void ice_trigger_vf_reset(struc
        }
  }
  
 -/**
 - * ice_vsi_manage_pvid - Enable or disable port VLAN for VSI
 - * @vsi: the VSI to update
 - * @pvid_info: VLAN ID and QoS used to set the PVID VSI context field
 - * @enable: true for enable PVID false for disable
 - */
 -static int ice_vsi_manage_pvid(struct ice_vsi *vsi, u16 pvid_info, bool enable)
 -{
 -      struct ice_hw *hw = &vsi->back->hw;
 -      struct ice_aqc_vsi_props *info;
 -      struct ice_vsi_ctx *ctxt;
 -      int ret;
 -
 -      ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
 -      if (!ctxt)
 -              return -ENOMEM;
 -
 -      ctxt->info = vsi->info;
 -      info = &ctxt->info;
 -      if (enable) {
 -              info->vlan_flags = ICE_AQ_VSI_VLAN_MODE_UNTAGGED |
 -                      ICE_AQ_VSI_PVLAN_INSERT_PVID |
 -                      ICE_AQ_VSI_VLAN_EMOD_STR;
 -              info->sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
 -      } else {
 -              info->vlan_flags = ICE_AQ_VSI_VLAN_EMOD_NOTHING |
 -                      ICE_AQ_VSI_VLAN_MODE_ALL;
 -              info->sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
 -      }
 -
 -      info->pvid = cpu_to_le16(pvid_info);
 -      info->valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID |
 -                                         ICE_AQ_VSI_PROP_SW_VALID);
 -
 -      ret = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
 -      if (ret) {
 -              dev_info(ice_hw_to_dev(hw), "update VSI for port VLAN failed, err %d aq_err %s\n",
 -                       ret, ice_aq_str(hw->adminq.sq_last_status));
 -              goto out;
 -      }
 -
 -      vsi->info.vlan_flags = info->vlan_flags;
 -      vsi->info.sw_flags2 = info->sw_flags2;
 -      vsi->info.pvid = info->pvid;
 -out:
 -      kfree(ctxt);
 -      return ret;
 -}
 -
  /**
   * ice_vf_get_port_info - Get the VF's port info structure
   * @vf: VF used to get the port info structure for
@@@ -770,7 -714,7 +770,7 @@@ static struct ice_vsi *ice_vf_vsi_setup
        struct ice_pf *pf = vf->pf;
        struct ice_vsi *vsi;
  
 -      vsi = ice_vsi_setup(pf, pi, ICE_VSI_VF, vf->vf_id, NULL);
 +      vsi = ice_vsi_setup(pf, pi, ICE_VSI_VF, vf, NULL);
  
        if (!vsi) {
                dev_err(ice_pf_to_dev(pf), "Failed to create VF VSI\n");
@@@ -797,7 -741,7 +797,7 @@@ struct ice_vsi *ice_vf_ctrl_vsi_setup(s
        struct ice_pf *pf = vf->pf;
        struct ice_vsi *vsi;
  
 -      vsi = ice_vsi_setup(pf, pi, ICE_VSI_CTRL, vf->vf_id, NULL);
 +      vsi = ice_vsi_setup(pf, pi, ICE_VSI_CTRL, vf, NULL);
        if (!vsi) {
                dev_err(ice_pf_to_dev(pf), "Failed to create VF control VSI\n");
                ice_vf_ctrl_invalidate_vsi(vf);
   */
  static int ice_calc_vf_first_vector_idx(struct ice_pf *pf, struct ice_vf *vf)
  {
 -      return pf->sriov_base_vector + vf->vf_id * pf->num_msix_per_vf;
 +      return pf->sriov_base_vector + vf->vf_id * pf->vfs.num_msix_per;
  }
  
  /**
@@@ -857,151 -801,43 +857,151 @@@ static int ice_vf_rebuild_host_tx_rate_
        return 0;
  }
  
 +static u16 ice_vf_get_port_vlan_id(struct ice_vf *vf)
 +{
 +      return vf->port_vlan_info.vid;
 +}
 +
 +static u8 ice_vf_get_port_vlan_prio(struct ice_vf *vf)
 +{
 +      return vf->port_vlan_info.prio;
 +}
 +
 +bool ice_vf_is_port_vlan_ena(struct ice_vf *vf)
 +{
 +      return (ice_vf_get_port_vlan_id(vf) || ice_vf_get_port_vlan_prio(vf));
 +}
 +
 +static u16 ice_vf_get_port_vlan_tpid(struct ice_vf *vf)
 +{
 +      return vf->port_vlan_info.tpid;
 +}
 +
  /**
   * ice_vf_rebuild_host_vlan_cfg - add VLAN 0 filter or rebuild the Port VLAN
   * @vf: VF to add MAC filters for
 + * @vsi: Pointer to VSI
   *
   * Called after a VF VSI has been re-added/rebuilt during reset. The PF driver
   * always re-adds either a VLAN 0 or port VLAN based filter after reset.
   */
 -static int ice_vf_rebuild_host_vlan_cfg(struct ice_vf *vf)
 +static int ice_vf_rebuild_host_vlan_cfg(struct ice_vf *vf, struct ice_vsi *vsi)
  {
 +      struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
        struct device *dev = ice_pf_to_dev(vf->pf);
 -      struct ice_vsi *vsi = ice_get_vf_vsi(vf);
 -      u16 vlan_id = 0;
        int err;
  
 -      if (vf->port_vlan_info) {
 -              err = ice_vsi_manage_pvid(vsi, vf->port_vlan_info, true);
 +      if (ice_vf_is_port_vlan_ena(vf)) {
 +              err = vlan_ops->set_port_vlan(vsi, &vf->port_vlan_info);
                if (err) {
                        dev_err(dev, "failed to configure port VLAN via VSI parameters for VF %u, error %d\n",
                                vf->vf_id, err);
                        return err;
                }
  
 -              vlan_id = vf->port_vlan_info & VLAN_VID_MASK;
 +              err = vlan_ops->add_vlan(vsi, &vf->port_vlan_info);
 +      } else {
 +              err = ice_vsi_add_vlan_zero(vsi);
        }
  
 -      /* vlan_id will either be 0 or the port VLAN number */
 -      err = ice_vsi_add_vlan(vsi, vlan_id, ICE_FWD_TO_VSI);
        if (err) {
 -              dev_err(dev, "failed to add %s VLAN %u filter for VF %u, error %d\n",
 -                      vf->port_vlan_info ? "port" : "", vlan_id, vf->vf_id,
 -                      err);
 +              dev_err(dev, "failed to add VLAN %u filter for VF %u during VF rebuild, error %d\n",
 +                      ice_vf_is_port_vlan_ena(vf) ?
 +                      ice_vf_get_port_vlan_id(vf) : 0, vf->vf_id, err);
                return err;
        }
  
 +      err = vlan_ops->ena_rx_filtering(vsi);
 +      if (err)
 +              dev_warn(dev, "failed to enable Rx VLAN filtering for VF %d VSI %d during VF rebuild, error %d\n",
 +                       vf->vf_id, vsi->idx, err);
 +
        return 0;
  }
  
 +static int ice_cfg_mac_antispoof(struct ice_vsi *vsi, bool enable)
 +{
 +      struct ice_vsi_ctx *ctx;
 +      int err;
 +
 +      ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 +      if (!ctx)
 +              return -ENOMEM;
 +
 +      ctx->info.sec_flags = vsi->info.sec_flags;
 +      ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID);
 +
 +      if (enable)
 +              ctx->info.sec_flags |= ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF;
 +      else
 +              ctx->info.sec_flags &= ~ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF;
 +
 +      err = ice_update_vsi(&vsi->back->hw, vsi->idx, ctx, NULL);
 +      if (err)
 +              dev_err(ice_pf_to_dev(vsi->back), "Failed to configure Tx MAC anti-spoof %s for VSI %d, error %d\n",
 +                      enable ? "ON" : "OFF", vsi->vsi_num, err);
 +      else
 +              vsi->info.sec_flags = ctx->info.sec_flags;
 +
 +      kfree(ctx);
 +
 +      return err;
 +}
 +
 +/**
 + * ice_vsi_ena_spoofchk - enable Tx spoof checking for this VSI
 + * @vsi: VSI to enable Tx spoof checking for
 + */
 +static int ice_vsi_ena_spoofchk(struct ice_vsi *vsi)
 +{
 +      struct ice_vsi_vlan_ops *vlan_ops;
 +      int err;
 +
 +      vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
 +
 +      err = vlan_ops->ena_tx_filtering(vsi);
 +      if (err)
 +              return err;
 +
 +      return ice_cfg_mac_antispoof(vsi, true);
 +}
 +
 +/**
 + * ice_vsi_dis_spoofchk - disable Tx spoof checking for this VSI
 + * @vsi: VSI to disable Tx spoof checking for
 + */
 +static int ice_vsi_dis_spoofchk(struct ice_vsi *vsi)
 +{
 +      struct ice_vsi_vlan_ops *vlan_ops;
 +      int err;
 +
 +      vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
 +
 +      err = vlan_ops->dis_tx_filtering(vsi);
 +      if (err)
 +              return err;
 +
 +      return ice_cfg_mac_antispoof(vsi, false);
 +}
 +
 +/**
 + * ice_vf_set_spoofchk_cfg - apply Tx spoof checking setting
 + * @vf: VF set spoofchk for
 + * @vsi: VSI associated to the VF
 + */
 +static int
 +ice_vf_set_spoofchk_cfg(struct ice_vf *vf, struct ice_vsi *vsi)
 +{
 +      int err;
 +
 +      if (vf->spoofchk)
 +              err = ice_vsi_ena_spoofchk(vsi);
 +      else
 +              err = ice_vsi_dis_spoofchk(vsi);
 +
 +      return err;
 +}
 +
  /**
   * ice_vf_rebuild_host_mac_cfg - add broadcast and the VF's perm_addr/LAA
   * @vf: VF to add MAC filters for
@@@ -1077,12 -913,12 +1077,12 @@@ static void ice_ena_vf_msix_mappings(st
  
        hw = &pf->hw;
        pf_based_first_msix = vf->first_vector_idx;
 -      pf_based_last_msix = (pf_based_first_msix + pf->num_msix_per_vf) - 1;
 +      pf_based_last_msix = (pf_based_first_msix + pf->vfs.num_msix_per) - 1;
  
        device_based_first_msix = pf_based_first_msix +
                pf->hw.func_caps.common_cap.msix_vector_first_id;
        device_based_last_msix =
 -              (device_based_first_msix + pf->num_msix_per_vf) - 1;
 +              (device_based_first_msix + pf->vfs.num_msix_per) - 1;
        device_based_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
  
        reg = (((device_based_first_msix << VPINT_ALLOC_FIRST_S) &
@@@ -1172,6 -1008,45 +1172,6 @@@ static void ice_ena_vf_mappings(struct 
        ice_ena_vf_q_mappings(vf, vsi->alloc_txq, vsi->alloc_rxq);
  }
  
 -/**
 - * ice_determine_res
 - * @pf: pointer to the PF structure
 - * @avail_res: available resources in the PF structure
 - * @max_res: maximum resources that can be given per VF
 - * @min_res: minimum resources that can be given per VF
 - *
 - * Returns non-zero value if resources (queues/vectors) are available or
 - * returns zero if PF cannot accommodate for all num_alloc_vfs.
 - */
 -static int
 -ice_determine_res(struct ice_pf *pf, u16 avail_res, u16 max_res, u16 min_res)
 -{
 -      bool checked_min_res = false;
 -      int res;
 -
 -      /* start by checking if PF can assign max number of resources for
 -       * all num_alloc_vfs.
 -       * if yes, return number per VF
 -       * If no, divide by 2 and roundup, check again
 -       * repeat the loop till we reach a point where even minimum resources
 -       * are not available, in that case return 0
 -       */
 -      res = max_res;
 -      while ((res >= min_res) && !checked_min_res) {
 -              int num_all_res;
 -
 -              num_all_res = pf->num_alloc_vfs * res;
 -              if (num_all_res <= avail_res)
 -                      return res;
 -
 -              if (res == min_res)
 -                      checked_min_res = true;
 -
 -              res = DIV_ROUND_UP(res, 2);
 -      }
 -      return 0;
 -}
 -
  /**
   * ice_calc_vf_reg_idx - Calculate the VF's register index in the PF space
   * @vf: VF to calculate the register index for
@@@ -1187,7 -1062,7 +1187,7 @@@ int ice_calc_vf_reg_idx(struct ice_vf *
        pf = vf->pf;
  
        /* always add one to account for the OICR being the first MSIX */
 -      return pf->sriov_base_vector + pf->num_msix_per_vf * vf->vf_id +
 +      return pf->sriov_base_vector + pf->vfs.num_msix_per * vf->vf_id +
                q_vector->v_idx + 1;
  }
  
@@@ -1251,7 -1126,6 +1251,7 @@@ static int ice_sriov_set_msix_res(struc
  /**
   * ice_set_per_vf_res - check if vectors and queues are available
   * @pf: pointer to the PF structure
 + * @num_vfs: the number of SR-IOV VFs being configured
   *
   * First, determine HW interrupts from common pool. If we allocate fewer VFs, we
   * get more vectors and can enable more queues per VF. Note that this does not
   * Lastly, set queue and MSI-X VF variables tracked by the PF so it can be used
   * by each VF during VF initialization and reset.
   */
 -static int ice_set_per_vf_res(struct ice_pf *pf)
 +static int ice_set_per_vf_res(struct ice_pf *pf, u16 num_vfs)
  {
        int max_valid_res_idx = ice_get_max_valid_res_idx(pf->irq_tracker);
 +      u16 num_msix_per_vf, num_txq, num_rxq, avail_qs;
        int msix_avail_per_vf, msix_avail_for_sriov;
        struct device *dev = ice_pf_to_dev(pf);
 -      u16 num_msix_per_vf, num_txq, num_rxq;
  
 -      if (!pf->num_alloc_vfs || max_valid_res_idx < 0)
 +      lockdep_assert_held(&pf->vfs.table_lock);
 +
 +      if (!num_vfs || max_valid_res_idx < 0)
                return -EINVAL;
  
        /* determine MSI-X resources per VF */
        msix_avail_for_sriov = pf->hw.func_caps.common_cap.num_msix_vectors -
                pf->irq_tracker->num_entries;
 -      msix_avail_per_vf = msix_avail_for_sriov / pf->num_alloc_vfs;
 +      msix_avail_per_vf = msix_avail_for_sriov / num_vfs;
        if (msix_avail_per_vf >= ICE_NUM_VF_MSIX_MED) {
                num_msix_per_vf = ICE_NUM_VF_MSIX_MED;
        } else if (msix_avail_per_vf >= ICE_NUM_VF_MSIX_SMALL) {
        } else {
                dev_err(dev, "Only %d MSI-X interrupts available for SR-IOV. Not enough to support minimum of %d MSI-X interrupts per VF for %d VFs\n",
                        msix_avail_for_sriov, ICE_MIN_INTR_PER_VF,
 -                      pf->num_alloc_vfs);
 +                      num_vfs);
                return -EIO;
        }
  
 -      /* determine queue resources per VF */
 -      num_txq = ice_determine_res(pf, ice_get_avail_txq_count(pf),
 -                                  min_t(u16,
 -                                        num_msix_per_vf - ICE_NONQ_VECS_VF,
 -                                        ICE_MAX_RSS_QS_PER_VF),
 -                                  ICE_MIN_QS_PER_VF);
 +      num_txq = min_t(u16, num_msix_per_vf - ICE_NONQ_VECS_VF,
 +                      ICE_MAX_RSS_QS_PER_VF);
 +      avail_qs = ice_get_avail_txq_count(pf) / num_vfs;
 +      if (!avail_qs)
 +              num_txq = 0;
 +      else if (num_txq > avail_qs)
 +              num_txq = rounddown_pow_of_two(avail_qs);
  
 -      num_rxq = ice_determine_res(pf, ice_get_avail_rxq_count(pf),
 -                                  min_t(u16,
 -                                        num_msix_per_vf - ICE_NONQ_VECS_VF,
 -                                        ICE_MAX_RSS_QS_PER_VF),
 -                                  ICE_MIN_QS_PER_VF);
 +      num_rxq = min_t(u16, num_msix_per_vf - ICE_NONQ_VECS_VF,
 +                      ICE_MAX_RSS_QS_PER_VF);
 +      avail_qs = ice_get_avail_rxq_count(pf) / num_vfs;
 +      if (!avail_qs)
 +              num_rxq = 0;
 +      else if (num_rxq > avail_qs)
 +              num_rxq = rounddown_pow_of_two(avail_qs);
  
 -      if (!num_txq || !num_rxq) {
 +      if (num_txq < ICE_MIN_QS_PER_VF || num_rxq < ICE_MIN_QS_PER_VF) {
                dev_err(dev, "Not enough queues to support minimum of %d queue pairs per VF for %d VFs\n",
 -                      ICE_MIN_QS_PER_VF, pf->num_alloc_vfs);
 +                      ICE_MIN_QS_PER_VF, num_vfs);
                return -EIO;
        }
  
 -      if (ice_sriov_set_msix_res(pf, num_msix_per_vf * pf->num_alloc_vfs)) {
 +      if (ice_sriov_set_msix_res(pf, num_msix_per_vf * num_vfs)) {
                dev_err(dev, "Unable to set MSI-X resources for %d VFs\n",
 -                      pf->num_alloc_vfs);
 +                      num_vfs);
                return -EINVAL;
        }
  
        /* only allow equal Tx/Rx queue count (i.e. queue pairs) */
 -      pf->num_qps_per_vf = min_t(int, num_txq, num_rxq);
 -      pf->num_msix_per_vf = num_msix_per_vf;
 +      pf->vfs.num_qps_per = min_t(int, num_txq, num_rxq);
 +      pf->vfs.num_msix_per = num_msix_per_vf;
        dev_info(dev, "Enabling %d VFs with %d vectors and %d queues per VF\n",
 -               pf->num_alloc_vfs, pf->num_msix_per_vf, pf->num_qps_per_vf);
 +               num_vfs, pf->vfs.num_msix_per, pf->vfs.num_qps_per);
  
        return 0;
  }
@@@ -1359,10 -1228,10 +1359,10 @@@ ice_vf_set_vsi_promisc(struct ice_vf *v
        struct ice_hw *hw = &vsi->back->hw;
        int status;
  
 -      if (vf->port_vlan_info)
 +      if (ice_vf_is_port_vlan_ena(vf))
                status = ice_fltr_set_vsi_promisc(hw, vsi->idx, promisc_m,
 -                                                vf->port_vlan_info & VLAN_VID_MASK);
 -      else if (vsi->num_vlan > 1)
 +                                                ice_vf_get_port_vlan_id(vf));
 +      else if (ice_vsi_has_non_zero_vlans(vsi))
                status = ice_fltr_set_vlan_vsi_promisc(hw, vsi, promisc_m);
        else
                status = ice_fltr_set_vsi_promisc(hw, vsi->idx, promisc_m, 0);
@@@ -1382,10 -1251,10 +1382,10 @@@ ice_vf_clear_vsi_promisc(struct ice_vf 
        struct ice_hw *hw = &vsi->back->hw;
        int status;
  
 -      if (vf->port_vlan_info)
 +      if (ice_vf_is_port_vlan_ena(vf))
                status = ice_fltr_clear_vsi_promisc(hw, vsi->idx, promisc_m,
 -                                                  vf->port_vlan_info & VLAN_VID_MASK);
 -      else if (vsi->num_vlan > 1)
 +                                                  ice_vf_get_port_vlan_id(vf));
 +      else if (ice_vsi_has_non_zero_vlans(vsi))
                status = ice_fltr_clear_vlan_vsi_promisc(hw, vsi, promisc_m);
        else
                status = ice_fltr_clear_vsi_promisc(hw, vsi->idx, promisc_m, 0);
@@@ -1470,7 -1339,7 +1470,7 @@@ static void ice_vf_rebuild_host_cfg(str
                dev_err(dev, "failed to rebuild default MAC configuration for VF %d\n",
                        vf->vf_id);
  
 -      if (ice_vf_rebuild_host_vlan_cfg(vf))
 +      if (ice_vf_rebuild_host_vlan_cfg(vf, vsi))
                dev_err(dev, "failed to rebuild VLAN configuration for VF %u\n",
                        vf->vf_id);
  
                dev_err(dev, "failed to rebuild Tx rate limiting configuration for VF %u\n",
                        vf->vf_id);
  
 +      if (ice_vf_set_spoofchk_cfg(vf, vsi))
 +              dev_err(dev, "failed to rebuild spoofchk configuration for VF %d\n",
 +                      vf->vf_id);
 +
        /* rebuild aggregator node config for main VF VSI */
        ice_vf_rebuild_aggregator_node_cfg(vsi);
  }
@@@ -1542,7 -1407,6 +1542,7 @@@ static void ice_vf_set_initialized(stru
        clear_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states);
        clear_bit(ICE_VF_STATE_DIS, vf->vf_states);
        set_bit(ICE_VF_STATE_INIT, vf->vf_states);
 +      memset(&vf->vlan_v2_caps, 0, sizeof(vf->vlan_v2_caps));
  }
  
  /**
@@@ -1580,30 -1444,24 +1580,30 @@@ bool ice_reset_all_vfs(struct ice_pf *p
        struct device *dev = ice_pf_to_dev(pf);
        struct ice_hw *hw = &pf->hw;
        struct ice_vf *vf;
 -      int v, i;
 +      unsigned int bkt;
  
        /* If we don't have any VFs, then there is nothing to reset */
 -      if (!pf->num_alloc_vfs)
 +      if (!ice_has_vfs(pf))
                return false;
  
 +      mutex_lock(&pf->vfs.table_lock);
 +
        /* clear all malicious info if the VFs are getting reset */
 -      ice_for_each_vf(pf, i)
 -              if (ice_mbx_clear_malvf(&hw->mbx_snapshot, pf->malvfs, ICE_MAX_VF_COUNT, i))
 -                      dev_dbg(dev, "failed to clear malicious VF state for VF %u\n", i);
 +      ice_for_each_vf(pf, bkt, vf)
 +              if (ice_mbx_clear_malvf(&hw->mbx_snapshot, pf->vfs.malvfs,
 +                                      ICE_MAX_VF_COUNT, vf->vf_id))
 +                      dev_dbg(dev, "failed to clear malicious VF state for VF %u\n",
 +                              vf->vf_id);
  
        /* If VFs have been disabled, there is no need to reset */
 -      if (test_and_set_bit(ICE_VF_DIS, pf->state))
 +      if (test_and_set_bit(ICE_VF_DIS, pf->state)) {
 +              mutex_unlock(&pf->vfs.table_lock);
                return false;
 +      }
  
        /* Begin reset on all VFs at once */
 -      ice_for_each_vf(pf, v)
 -              ice_trigger_vf_reset(&pf->vf[v], is_vflr, true);
 +      ice_for_each_vf(pf, bkt, vf)
 +              ice_trigger_vf_reset(vf, is_vflr, true);
  
        /* HW requires some time to make sure it can flush the FIFO for a VF
         * when it resets it. Poll the VPGEN_VFRSTAT register for each VF in
         * the VFs using a simple iterator that increments once that VF has
         * finished resetting.
         */
 -      for (i = 0, v = 0; i < 10 && v < pf->num_alloc_vfs; i++) {
 -              /* Check each VF in sequence */
 -              while (v < pf->num_alloc_vfs) {
 -                      u32 reg;
 -
 -                      vf = &pf->vf[v];
 -                      reg = rd32(hw, VPGEN_VFRSTAT(vf->vf_id));
 -                      if (!(reg & VPGEN_VFRSTAT_VFRD_M)) {
 -                              /* only delay if the check failed */
 -                              usleep_range(10, 20);
 +      ice_for_each_vf(pf, bkt, vf) {
 +              bool done = false;
 +              unsigned int i;
 +              u32 reg;
 +
 +              for (i = 0; i < 10; i++) {
 +                      reg = rd32(&pf->hw, VPGEN_VFRSTAT(vf->vf_id));
 +                      if (reg & VPGEN_VFRSTAT_VFRD_M) {
 +                              done = true;
                                break;
                        }
  
 -                      /* If the current VF has finished resetting, move on
 -                       * to the next VF in sequence.
 +                      /* only delay if check failed */
 +                      usleep_range(10, 20);
 +              }
 +
 +              if (!done) {
 +                      /* Display a warning if at least one VF didn't manage
 +                       * to reset in time, but continue on with the
 +                       * operation.
                         */
 -                      v++;
 +                      dev_warn(dev, "VF %u reset check timeout\n", vf->vf_id);
 +                      break;
                }
        }
  
 -      /* Display a warning if at least one VF didn't manage to reset in
 -       * time, but continue on with the operation.
 -       */
 -      if (v < pf->num_alloc_vfs)
 -              dev_warn(dev, "VF reset check timeout\n");
 -
        /* free VF resources to begin resetting the VSI state */
 -      ice_for_each_vf(pf, v) {
 -              vf = &pf->vf[v];
 -
 +      ice_for_each_vf(pf, bkt, vf) {
                mutex_lock(&vf->cfg_lock);
  
                vf->driver_caps = 0;
        ice_flush(hw);
        clear_bit(ICE_VF_DIS, pf->state);
  
 +      mutex_unlock(&pf->vfs.table_lock);
 +
        return true;
  }
  
@@@ -1772,7 -1630,7 +1772,7 @@@ bool ice_reset_vf(struct ice_vf *vf, bo
         */
        if (test_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states) ||
            test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states)) {
 -              if (vf->port_vlan_info || vsi->num_vlan)
 +              if (ice_vf_is_port_vlan_ena(vf) || vsi->num_vlan)
                        promisc_m = ICE_UCAST_VLAN_PROMISC_BITS;
                else
                        promisc_m = ICE_UCAST_PROMISC_BITS;
        ice_eswitch_replay_vf_mac_rule(vf);
  
        /* if the VF has been reset allow it to come up again */
 -      if (ice_mbx_clear_malvf(&hw->mbx_snapshot, pf->malvfs, ICE_MAX_VF_COUNT, vf->vf_id))
 +      if (ice_mbx_clear_malvf(&hw->mbx_snapshot, pf->vfs.malvfs,
 +                              ICE_MAX_VF_COUNT, vf->vf_id))
                dev_dbg(dev, "failed to clear malicious VF state for VF %u\n", i);
  
        return true;
   */
  void ice_vc_notify_link_state(struct ice_pf *pf)
  {
 -      int i;
 +      struct ice_vf *vf;
 +      unsigned int bkt;
  
 -      ice_for_each_vf(pf, i)
 -              ice_vc_notify_vf_link_state(&pf->vf[i]);
 +      mutex_lock(&pf->vfs.table_lock);
 +      ice_for_each_vf(pf, bkt, vf)
 +              ice_vc_notify_vf_link_state(vf);
 +      mutex_unlock(&pf->vfs.table_lock);
  }
  
  /**
@@@ -1836,7 -1690,7 +1836,7 @@@ void ice_vc_notify_reset(struct ice_pf 
  {
        struct virtchnl_pf_event pfe;
  
 -      if (!pf->num_alloc_vfs)
 +      if (!ice_has_vfs(pf))
                return;
  
        pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING;
  static void ice_vc_notify_vf_reset(struct ice_vf *vf)
  {
        struct virtchnl_pf_event pfe;
 -      struct ice_pf *pf;
 -
 -      if (!vf)
 -              return;
 -
 -      pf = vf->pf;
 -      if (ice_validate_vf_id(pf, vf->vf_id))
 -              return;
 +      struct ice_pf *pf = vf->pf;
  
        /* Bail out if VF is in disabled state, neither initialized, nor active
         * state - otherwise proceed with notifications
   */
  static int ice_init_vf_vsi_res(struct ice_vf *vf)
  {
 +      struct ice_vsi_vlan_ops *vlan_ops;
        struct ice_pf *pf = vf->pf;
        u8 broadcast[ETH_ALEN];
        struct ice_vsi *vsi;
        if (!vsi)
                return -ENOMEM;
  
 -      err = ice_vsi_add_vlan(vsi, 0, ICE_FWD_TO_VSI);
 +      err = ice_vsi_add_vlan_zero(vsi);
        if (err) {
                dev_warn(dev, "Failed to add VLAN 0 filter for VF %d\n",
                         vf->vf_id);
                goto release_vsi;
        }
  
 +      vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
 +      err = vlan_ops->ena_rx_filtering(vsi);
 +      if (err) {
 +              dev_warn(dev, "Failed to enable Rx VLAN filtering for VF %d\n",
 +                       vf->vf_id);
 +              goto release_vsi;
 +      }
 +
        eth_broadcast_addr(broadcast);
        err = ice_fltr_add_mac(vsi, broadcast, ICE_FWD_TO_VSI);
        if (err) {
                goto release_vsi;
        }
  
 +      err = ice_vf_set_spoofchk_cfg(vf, vsi);
 +      if (err) {
 +              dev_warn(dev, "Failed to initialize spoofchk setting for VF %d\n",
 +                       vf->vf_id);
 +              goto release_vsi;
 +      }
 +
        vf->num_mac = 1;
  
        return 0;
@@@ -1938,14 -1783,11 +1938,14 @@@ release_vsi
  static int ice_start_vfs(struct ice_pf *pf)
  {
        struct ice_hw *hw = &pf->hw;
 -      int retval, i;
 +      unsigned int bkt, it_cnt;
 +      struct ice_vf *vf;
 +      int retval;
  
 -      ice_for_each_vf(pf, i) {
 -              struct ice_vf *vf = &pf->vf[i];
 +      lockdep_assert_held(&pf->vfs.table_lock);
  
 +      it_cnt = 0;
 +      ice_for_each_vf(pf, bkt, vf) {
                ice_clear_vf_reset_trigger(vf);
  
                retval = ice_init_vf_vsi_res(vf);
                set_bit(ICE_VF_STATE_INIT, vf->vf_states);
                ice_ena_vf_mappings(vf);
                wr32(hw, VFGEN_RSTAT(vf->vf_id), VIRTCHNL_VFR_VFACTIVE);
 +              it_cnt++;
        }
  
        ice_flush(hw);
        return 0;
  
  teardown:
 -      for (i = i - 1; i >= 0; i--) {
 -              struct ice_vf *vf = &pf->vf[i];
 +      ice_for_each_vf(pf, bkt, vf) {
 +              if (it_cnt == 0)
 +                      break;
  
                ice_dis_vf_mappings(vf);
                ice_vf_vsi_release(vf);
 +              it_cnt--;
        }
  
        return retval;
  }
  
  /**
 - * ice_set_dflt_settings_vfs - set VF defaults during initialization/creation
 - * @pf: PF holding reference to all VFs for default configuration
 + * ice_create_vf_entries - Allocate and insert VF entries
 + * @pf: pointer to the PF structure
 + * @num_vfs: the number of VFs to allocate
 + *
 + * Allocate new VF entries and insert them into the hash table. Set some
 + * basic default fields for initializing the new VFs.
 + *
 + * After this function exits, the hash table will have num_vfs entries
 + * inserted.
 + *
 + * Returns 0 on success or an integer error code on failure.
   */
 -static void ice_set_dflt_settings_vfs(struct ice_pf *pf)
 +static int ice_create_vf_entries(struct ice_pf *pf, u16 num_vfs)
  {
 -      int i;
 +      struct ice_vfs *vfs = &pf->vfs;
 +      struct ice_vf *vf;
 +      u16 vf_id;
 +      int err;
  
 -      ice_for_each_vf(pf, i) {
 -              struct ice_vf *vf = &pf->vf[i];
 +      lockdep_assert_held(&vfs->table_lock);
 +
 +      for (vf_id = 0; vf_id < num_vfs; vf_id++) {
 +              vf = kzalloc(sizeof(*vf), GFP_KERNEL);
 +              if (!vf) {
 +                      err = -ENOMEM;
 +                      goto err_free_entries;
 +              }
 +              kref_init(&vf->refcnt);
  
                vf->pf = pf;
 -              vf->vf_id = i;
 +              vf->vf_id = vf_id;
 +
                vf->vf_sw_id = pf->first_sw;
                /* assign default capabilities */
                set_bit(ICE_VIRTCHNL_VF_CAP_L2, &vf->vf_caps);
                vf->spoofchk = true;
 -              vf->num_vf_qs = pf->num_qps_per_vf;
 +              vf->num_vf_qs = pf->vfs.num_qps_per;
                ice_vc_set_default_allowlist(vf);
  
                /* ctrl_vsi_idx will be set to a valid value only when VF
                ice_vc_set_dflt_vf_ops(&vf->vc_ops);
  
                mutex_init(&vf->cfg_lock);
 -      }
 -}
 -
 -/**
 - * ice_alloc_vfs - allocate num_vfs in the PF structure
 - * @pf: PF to store the allocated VFs in
 - * @num_vfs: number of VFs to allocate
 - */
 -static int ice_alloc_vfs(struct ice_pf *pf, int num_vfs)
 -{
 -      struct ice_vf *vfs;
 -
 -      vfs = devm_kcalloc(ice_pf_to_dev(pf), num_vfs, sizeof(*vfs),
 -                         GFP_KERNEL);
 -      if (!vfs)
 -              return -ENOMEM;
  
 -      pf->vf = vfs;
 -      pf->num_alloc_vfs = num_vfs;
 +              hash_add_rcu(vfs->table, &vf->entry, vf_id);
 +      }
  
        return 0;
 +
 +err_free_entries:
 +      ice_free_vf_entries(pf);
 +      return err;
  }
  
  /**
@@@ -2055,29 -1886,28 +2055,29 @@@ static int ice_ena_vfs(struct ice_pf *p
        ice_flush(hw);
  
        ret = pci_enable_sriov(pf->pdev, num_vfs);
 -      if (ret) {
 -              pf->num_alloc_vfs = 0;
 +      if (ret)
                goto err_unroll_intr;
 -      }
  
 -      ret = ice_alloc_vfs(pf, num_vfs);
 -      if (ret)
 -              goto err_pci_disable_sriov;
 +      mutex_lock(&pf->vfs.table_lock);
  
 -      if (ice_set_per_vf_res(pf)) {
 +      if (ice_set_per_vf_res(pf, num_vfs)) {
                dev_err(dev, "Not enough resources for %d VFs, try with fewer number of VFs\n",
                        num_vfs);
                ret = -ENOSPC;
                goto err_unroll_sriov;
        }
  
 -      ice_set_dflt_settings_vfs(pf);
 -
 +      ret = ice_create_vf_entries(pf, num_vfs);
 +      if (ret) {
 +              dev_err(dev, "Failed to allocate VF entries for %d VFs\n",
 +                      num_vfs);
 +              goto err_unroll_sriov;
 +      }
 +
        if (ice_start_vfs(pf)) {
                dev_err(dev, "Failed to start VF(s)\n");
                ret = -EAGAIN;
 -              goto err_unroll_sriov;
 +              goto err_unroll_vf_entries;
        }
  
        clear_bit(ICE_VF_DIS, pf->state);
        if (test_and_clear_bit(ICE_OICR_INTR_DIS, pf->state))
                ice_irq_dynamic_ena(hw, NULL, NULL);
  
 +      mutex_unlock(&pf->vfs.table_lock);
 +
        return 0;
  
 +err_unroll_vf_entries:
 +      ice_free_vf_entries(pf);
  err_unroll_sriov:
 -      devm_kfree(dev, pf->vf);
 -      pf->vf = NULL;
 -      pf->num_alloc_vfs = 0;
 -err_pci_disable_sriov:
 +      mutex_unlock(&pf->vfs.table_lock);
        pci_disable_sriov(pf->pdev);
  err_unroll_intr:
        /* rearm interrupts here */
@@@ -2124,9 -1953,9 +2124,9 @@@ static int ice_pci_sriov_ena(struct ice
        else if (pre_existing_vfs && pre_existing_vfs == num_vfs)
                return 0;
  
 -      if (num_vfs > pf->num_vfs_supported) {
 +      if (num_vfs > pf->vfs.num_supported) {
                dev_err(dev, "Can't enable %d VFs, max VFs supported is %d\n",
 -                      num_vfs, pf->num_vfs_supported);
 +                      num_vfs, pf->vfs.num_supported);
                return -EOPNOTSUPP;
        }
  
@@@ -2224,20 -2053,19 +2224,20 @@@ int ice_sriov_configure(struct pci_dev 
  void ice_process_vflr_event(struct ice_pf *pf)
  {
        struct ice_hw *hw = &pf->hw;
 -      unsigned int vf_id;
 +      struct ice_vf *vf;
 +      unsigned int bkt;
        u32 reg;
  
        if (!test_and_clear_bit(ICE_VFLR_EVENT_PENDING, pf->state) ||
 -          !pf->num_alloc_vfs)
 +          !ice_has_vfs(pf))
                return;
  
 -      ice_for_each_vf(pf, vf_id) {
 -              struct ice_vf *vf = &pf->vf[vf_id];
 +      mutex_lock(&pf->vfs.table_lock);
 +      ice_for_each_vf(pf, bkt, vf) {
                u32 reg_idx, bit_idx;
  
 -              reg_idx = (hw->func_caps.vf_base_id + vf_id) / 32;
 -              bit_idx = (hw->func_caps.vf_base_id + vf_id) % 32;
 +              reg_idx = (hw->func_caps.vf_base_id + vf->vf_id) / 32;
 +              bit_idx = (hw->func_caps.vf_base_id + vf->vf_id) % 32;
                /* read GLGEN_VFLRSTAT register to find out the flr VFs */
                reg = rd32(hw, GLGEN_VFLRSTAT(reg_idx));
                if (reg & BIT(bit_idx)) {
                        mutex_unlock(&vf->cfg_lock);
                }
        }
 +      mutex_unlock(&pf->vfs.table_lock);
  }
  
  /**
@@@ -2267,36 -2094,22 +2267,36 @@@ static void ice_vc_reset_vf(struct ice_
   *
   * If no VF is found who owns the pfq then return NULL, otherwise return a
   * pointer to the VF who owns the pfq
 + *
 + * If this function returns non-NULL, it acquires a reference count of the VF
 + * structure. The caller is responsible for calling ice_put_vf() to drop this
 + * reference.
   */
  static struct ice_vf *ice_get_vf_from_pfq(struct ice_pf *pf, u16 pfq)
  {
 -      unsigned int vf_id;
 +      struct ice_vf *vf;
 +      unsigned int bkt;
  
 -      ice_for_each_vf(pf, vf_id) {
 -              struct ice_vf *vf = &pf->vf[vf_id];
 +      rcu_read_lock();
 +      ice_for_each_vf_rcu(pf, bkt, vf) {
                struct ice_vsi *vsi;
                u16 rxq_idx;
  
                vsi = ice_get_vf_vsi(vf);
  
                ice_for_each_rxq(vsi, rxq_idx)
 -                      if (vsi->rxq_map[rxq_idx] == pfq)
 -                              return vf;
 +                      if (vsi->rxq_map[rxq_idx] == pfq) {
 +                              struct ice_vf *found;
 +
 +                              if (kref_get_unless_zero(&vf->refcnt))
 +                                      found = vf;
 +                              else
 +                                      found = NULL;
 +                              rcu_read_unlock();
 +                              return found;
 +                      }
        }
 +      rcu_read_unlock();
  
        return NULL;
  }
@@@ -2340,8 -2153,6 +2340,8 @@@ ice_vf_lan_overflow_event(struct ice_p
        mutex_lock(&vf->cfg_lock);
        ice_vc_reset_vf(vf);
        mutex_unlock(&vf->cfg_lock);
 +
 +      ice_put_vf(vf);
  }
  
  /**
@@@ -2362,27 -2173,15 +2362,9 @@@ ice_vc_send_msg_to_vf(struct ice_vf *vf
        struct ice_pf *pf;
        int aq_ret;
  
 -      if (!vf)
 -              return -EINVAL;
 -
        pf = vf->pf;
 -      if (ice_validate_vf_id(pf, vf->vf_id))
 -              return -EINVAL;
 -
        dev = ice_pf_to_dev(pf);
  
-       /* single place to detect unsuccessful return values */
-       if (v_retval) {
-               vf->num_inval_msgs++;
-               dev_info(dev, "VF %d failed opcode %d, retval: %d\n", vf->vf_id,
-                        v_opcode, v_retval);
-               if (vf->num_inval_msgs > ICE_DFLT_NUM_INVAL_MSGS_ALLOWED) {
-                       dev_err(dev, "Number of invalid messages exceeded for VF %d\n",
-                               vf->vf_id);
-                       dev_err(dev, "Use PF Control I/F to enable the VF\n");
-                       set_bit(ICE_VF_STATE_DIS, vf->vf_states);
-                       return -EIO;
-               }
-       } else {
-               vf->num_valid_msgs++;
-               /* reset the invalid counter, if a valid message is received. */
-               vf->num_inval_msgs = 0;
-       }
        aq_ret = ice_aq_send_msg_to_vf(&pf->hw, vf->vf_id, v_opcode, v_retval,
                                       msg, msglen, NULL);
        if (aq_ret && pf->hw.mailboxq.sq_last_status != ICE_AQ_RC_ENOSYS) {
@@@ -2434,7 -2233,7 +2416,7 @@@ static u16 ice_vc_get_max_frame_size(st
  
        max_frame_size = pi->phy.link_info.max_frame_size;
  
 -      if (vf->port_vlan_info)
 +      if (ice_vf_is_port_vlan_ena(vf))
                max_frame_size -= VLAN_HLEN;
  
        return max_frame_size;
@@@ -2483,33 -2282,8 +2465,33 @@@ static int ice_vc_get_vf_res_msg(struc
                goto err;
        }
  
 -      if (!vsi->info.pvid)
 -              vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_VLAN;
 +      if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_VLAN_V2) {
 +              /* VLAN offloads based on current device configuration */
 +              vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_VLAN_V2;
 +      } else if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_VLAN) {
 +              /* allow VF to negotiate VIRTCHNL_VF_OFFLOAD explicitly for
 +               * these two conditions, which amounts to guest VLAN filtering
 +               * and offloads being based on the inner VLAN or the
 +               * inner/single VLAN respectively and don't allow VF to
 +               * negotiate VIRTCHNL_VF_OFFLOAD in any other cases
 +               */
 +              if (ice_is_dvm_ena(&pf->hw) && ice_vf_is_port_vlan_ena(vf)) {
 +                      vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_VLAN;
 +              } else if (!ice_is_dvm_ena(&pf->hw) &&
 +                         !ice_vf_is_port_vlan_ena(vf)) {
 +                      vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_VLAN;
 +                      /* configure backward compatible support for VFs that
 +                       * only support VIRTCHNL_VF_OFFLOAD_VLAN, the PF is
 +                       * configured in SVM, and no port VLAN is configured
 +                       */
 +                      ice_vf_vsi_cfg_svm_legacy_vlan_mode(vsi);
 +              } else if (ice_is_dvm_ena(&pf->hw)) {
 +                      /* configure software offloaded VLAN support when DVM
 +                       * is enabled, but no port VLAN is enabled
 +                       */
 +                      ice_vf_vsi_cfg_dvm_legacy_vlan_mode(vsi);
 +              }
 +      }
  
        if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
                vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PF;
        vfres->num_vsis = 1;
        /* Tx and Rx queue are equal for VF */
        vfres->num_queue_pairs = vsi->num_txq;
 -      vfres->max_vectors = pf->num_msix_per_vf;
 +      vfres->max_vectors = pf->vfs.num_msix_per;
        vfres->rss_key_size = ICE_VSIQF_HKEY_ARRAY_SIZE;
        vfres->rss_lut_size = ICE_VSIQF_HLUT_ARRAY_SIZE;
        vfres->max_mtu = ice_vc_get_max_frame_size(vf);
@@@ -2627,7 -2401,7 +2609,7 @@@ bool ice_vc_isvalid_vsi_id(struct ice_v
  
        vsi = ice_find_vsi_from_id(pf, vsi_id);
  
 -      return (vsi && (vsi->vf_id == vf->vf_id));
 +      return (vsi && (vsi->vf == vf));
  }
  
  /**
@@@ -3112,54 -2886,70 +3094,54 @@@ int ice_set_vf_spoofchk(struct net_devi
  {
        struct ice_netdev_priv *np = netdev_priv(netdev);
        struct ice_pf *pf = np->vsi->back;
 -      struct ice_vsi_ctx *ctx;
        struct ice_vsi *vf_vsi;
        struct device *dev;
        struct ice_vf *vf;
        int ret;
  
        dev = ice_pf_to_dev(pf);
 -      if (ice_validate_vf_id(pf, vf_id))
 +
 +      vf = ice_get_vf_by_id(pf, vf_id);
 +      if (!vf)
                return -EINVAL;
  
 -      vf = &pf->vf[vf_id];
        ret = ice_check_vf_ready_for_cfg(vf);
        if (ret)
 -              return ret;
 +              goto out_put_vf;
  
        vf_vsi = ice_get_vf_vsi(vf);
        if (!vf_vsi) {
                netdev_err(netdev, "VSI %d for VF %d is null\n",
                           vf->lan_vsi_idx, vf->vf_id);
 -              return -EINVAL;
 +              ret = -EINVAL;
 +              goto out_put_vf;
        }
  
        if (vf_vsi->type != ICE_VSI_VF) {
                netdev_err(netdev, "Type %d of VSI %d for VF %d is no ICE_VSI_VF\n",
                           vf_vsi->type, vf_vsi->vsi_num, vf->vf_id);
 -              return -ENODEV;
 +              ret = -ENODEV;
 +              goto out_put_vf;
        }
  
        if (ena == vf->spoofchk) {
                dev_dbg(dev, "VF spoofchk already %s\n", ena ? "ON" : "OFF");
 -              return 0;
 -      }
 -
 -      ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 -      if (!ctx)
 -              return -ENOMEM;
 -
 -      ctx->info.sec_flags = vf_vsi->info.sec_flags;
 -      ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID);
 -      if (ena) {
 -              ctx->info.sec_flags |=
 -                      ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF |
 -                      (ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA <<
 -                       ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S);
 -      } else {
 -              ctx->info.sec_flags &=
 -                      ~(ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF |
 -                        (ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA <<
 -                         ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S));
 -      }
 -
 -      ret = ice_update_vsi(&pf->hw, vf_vsi->idx, ctx, NULL);
 -      if (ret) {
 -              dev_err(dev, "Failed to %sable spoofchk on VF %d VSI %d\n error %d\n",
 -                      ena ? "en" : "dis", vf->vf_id, vf_vsi->vsi_num, ret);
 -              goto out;
 +              ret = 0;
 +              goto out_put_vf;
        }
  
 -      /* only update spoofchk state and VSI context on success */
 -      vf_vsi->info.sec_flags = ctx->info.sec_flags;
 -      vf->spoofchk = ena;
 +      if (ena)
 +              ret = ice_vsi_ena_spoofchk(vf_vsi);
 +      else
 +              ret = ice_vsi_dis_spoofchk(vf_vsi);
 +      if (ret)
 +              dev_err(dev, "Failed to set spoofchk %s for VF %d VSI %d\n error %d\n",
 +                      ena ? "ON" : "OFF", vf->vf_id, vf_vsi->vsi_num, ret);
 +      else
 +              vf->spoofchk = ena;
  
 -out:
 -      kfree(ctx);
 +out_put_vf:
 +      ice_put_vf(vf);
        return ret;
  }
  
   */
  bool ice_is_any_vf_in_promisc(struct ice_pf *pf)
  {
 -      int vf_idx;
 -
 -      ice_for_each_vf(pf, vf_idx) {
 -              struct ice_vf *vf = &pf->vf[vf_idx];
 +      bool is_vf_promisc = false;
 +      struct ice_vf *vf;
 +      unsigned int bkt;
  
 +      rcu_read_lock();
 +      ice_for_each_vf_rcu(pf, bkt, vf) {
                /* found a VF that has promiscuous mode configured */
                if (test_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states) ||
 -                  test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states))
 -                      return true;
 +                  test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states)) {
 +                      is_vf_promisc = true;
 +                      break;
 +              }
        }
 +      rcu_read_unlock();
  
 -      return false;
 +      return is_vf_promisc;
  }
  
  /**
@@@ -3203,7 -2989,6 +3185,7 @@@ static int ice_vc_cfg_promiscuous_mode_
        bool rm_promisc, alluni = false, allmulti = false;
        struct virtchnl_promisc_info *info =
            (struct virtchnl_promisc_info *)msg;
 +      struct ice_vsi_vlan_ops *vlan_ops;
        int mcast_err = 0, ucast_err = 0;
        struct ice_pf *pf = vf->pf;
        struct ice_vsi *vsi;
  
        rm_promisc = !allmulti && !alluni;
  
 -      if (vsi->num_vlan || vf->port_vlan_info) {
 -              if (rm_promisc)
 -                      ret = ice_cfg_vlan_pruning(vsi, true);
 -              else
 -                      ret = ice_cfg_vlan_pruning(vsi, false);
 -              if (ret) {
 -                      dev_err(dev, "Failed to configure VLAN pruning in promiscuous mode\n");
 -                      v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 -                      goto error_param;
 -              }
 +      vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
 +      if (rm_promisc)
 +              ret = vlan_ops->ena_rx_filtering(vsi);
 +      else
 +              ret = vlan_ops->dis_rx_filtering(vsi);
 +      if (ret) {
 +              dev_err(dev, "Failed to configure VLAN pruning in promiscuous mode\n");
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto error_param;
        }
  
        if (!test_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, pf->flags)) {
        } else {
                u8 mcast_m, ucast_m;
  
 -              if (vf->port_vlan_info || vsi->num_vlan > 1) {
 +              if (ice_vf_is_port_vlan_ena(vf) ||
 +                  ice_vsi_has_non_zero_vlans(vsi)) {
                        mcast_m = ICE_MCAST_VLAN_PROMISC_BITS;
                        ucast_m = ICE_UCAST_VLAN_PROMISC_BITS;
                } else {
@@@ -3707,7 -3492,7 +3689,7 @@@ static int ice_vc_cfg_irq_map_msg(struc
         * there is actually at least a single VF queue vector mapped
         */
        if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) ||
 -          pf->num_msix_per_vf < num_q_vectors_mapped ||
 +          pf->vfs.num_msix_per < num_q_vectors_mapped ||
            !num_q_vectors_mapped) {
                v_ret = VIRTCHNL_STATUS_ERR_PARAM;
                goto error_param;
                /* vector_id is always 0-based for each VF, and can never be
                 * larger than or equal to the max allowed interrupts per VF
                 */
 -              if (!(vector_id < pf->num_msix_per_vf) ||
 +              if (!(vector_id < pf->vfs.num_msix_per) ||
                    !ice_vc_isvalid_vsi_id(vf, vsi_id) ||
                    (!vector_id && (map->rxq_map || map->txq_map))) {
                        v_ret = VIRTCHNL_STATUS_ERR_PARAM;
@@@ -3861,7 -3646,7 +3843,7 @@@ static int ice_vc_cfg_qs_msg(struct ice
                        /* add space for the port VLAN since the VF driver is not
                         * expected to account for it in the MTU calculation
                         */
 -                      if (vf->port_vlan_info)
 +                      if (ice_vf_is_port_vlan_ena(vf))
                                vsi->max_frame += VLAN_HLEN;
  
                        if (ice_vsi_cfg_single_rxq(vsi, q_idx)) {
@@@ -4272,33 -4057,6 +4254,33 @@@ error_param
                                     v_ret, (u8 *)vfres, sizeof(*vfres));
  }
  
 +/**
 + * ice_is_supported_port_vlan_proto - make sure the vlan_proto is supported
 + * @hw: hardware structure used to check the VLAN mode
 + * @vlan_proto: VLAN TPID being checked
 + *
 + * If the device is configured in Double VLAN Mode (DVM), then both ETH_P_8021Q
 + * and ETH_P_8021AD are supported. If the device is configured in Single VLAN
 + * Mode (SVM), then only ETH_P_8021Q is supported.
 + */
 +static bool
 +ice_is_supported_port_vlan_proto(struct ice_hw *hw, u16 vlan_proto)
 +{
 +      bool is_supported = false;
 +
 +      switch (vlan_proto) {
 +      case ETH_P_8021Q:
 +              is_supported = true;
 +              break;
 +      case ETH_P_8021AD:
 +              if (ice_is_dvm_ena(hw))
 +                      is_supported = true;
 +              break;
 +      }
 +
 +      return is_supported;
 +}
 +
  /**
   * ice_set_vf_port_vlan
   * @netdev: network interface device structure
@@@ -4314,12 -4072,14 +4296,12 @@@ ice_set_vf_port_vlan(struct net_device 
                     __be16 vlan_proto)
  {
        struct ice_pf *pf = ice_netdev_to_pf(netdev);
 +      u16 local_vlan_proto = ntohs(vlan_proto);
        struct device *dev;
        struct ice_vf *vf;
 -      u16 vlanprio;
        int ret;
  
        dev = ice_pf_to_dev(pf);
 -      if (ice_validate_vf_id(pf, vf_id))
 -              return -EINVAL;
  
        if (vlan_id >= VLAN_N_VID || qos > 7) {
                dev_err(dev, "Invalid Port VLAN parameters for VF %d, ID %d, QoS %d\n",
                return -EINVAL;
        }
  
 -      if (vlan_proto != htons(ETH_P_8021Q)) {
 -              dev_err(dev, "VF VLAN protocol is not supported\n");
 +      if (!ice_is_supported_port_vlan_proto(&pf->hw, local_vlan_proto)) {
 +              dev_err(dev, "VF VLAN protocol 0x%04x is not supported\n",
 +                      local_vlan_proto);
                return -EPROTONOSUPPORT;
        }
  
 -      vf = &pf->vf[vf_id];
 +      vf = ice_get_vf_by_id(pf, vf_id);
 +      if (!vf)
 +              return -EINVAL;
 +
        ret = ice_check_vf_ready_for_cfg(vf);
        if (ret)
 -              return ret;
 -
 -      vlanprio = vlan_id | (qos << VLAN_PRIO_SHIFT);
 +              goto out_put_vf;
  
 -      if (vf->port_vlan_info == vlanprio) {
 +      if (ice_vf_get_port_vlan_prio(vf) == qos &&
 +          ice_vf_get_port_vlan_tpid(vf) == local_vlan_proto &&
 +          ice_vf_get_port_vlan_id(vf) == vlan_id) {
                /* duplicate request, so just return success */
 -              dev_dbg(dev, "Duplicate pvid %d request\n", vlanprio);
 -              return 0;
 +              dev_dbg(dev, "Duplicate port VLAN %u, QoS %u, TPID 0x%04x request\n",
 +                      vlan_id, qos, local_vlan_proto);
 +              ret = 0;
 +              goto out_put_vf;
        }
  
        mutex_lock(&vf->cfg_lock);
  
 -      vf->port_vlan_info = vlanprio;
 -
 -      if (vf->port_vlan_info)
 -              dev_info(dev, "Setting VLAN %d, QoS 0x%x on VF %d\n",
 -                       vlan_id, qos, vf_id);
 +      vf->port_vlan_info = ICE_VLAN(local_vlan_proto, vlan_id, qos);
 +      if (ice_vf_is_port_vlan_ena(vf))
 +              dev_info(dev, "Setting VLAN %u, QoS %u, TPID 0x%04x on VF %d\n",
 +                       vlan_id, qos, local_vlan_proto, vf_id);
        else
                dev_info(dev, "Clearing port VLAN on VF %d\n", vf_id);
  
        ice_vc_reset_vf(vf);
        mutex_unlock(&vf->cfg_lock);
  
 -      return 0;
 +out_put_vf:
 +      ice_put_vf(vf);
 +      return ret;
  }
  
  /**
@@@ -4379,83 -4132,6 +4361,83 @@@ static bool ice_vf_vlan_offload_ena(u3
        return !!(caps & VIRTCHNL_VF_OFFLOAD_VLAN);
  }
  
 +/**
 + * ice_is_vlan_promisc_allowed - check if VLAN promiscuous config is allowed
 + * @vf: VF used to determine if VLAN promiscuous config is allowed
 + */
 +static bool ice_is_vlan_promisc_allowed(struct ice_vf *vf)
 +{
 +      if ((test_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states) ||
 +           test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states)) &&
 +          test_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, vf->pf->flags))
 +              return true;
 +
 +      return false;
 +}
 +
 +/**
 + * ice_vf_ena_vlan_promisc - Enable Tx/Rx VLAN promiscuous for the VLAN
 + * @vsi: VF's VSI used to enable VLAN promiscuous mode
 + * @vlan: VLAN used to enable VLAN promiscuous
 + *
 + * This function should only be called if VLAN promiscuous mode is allowed,
 + * which can be determined via ice_is_vlan_promisc_allowed().
 + */
 +static int ice_vf_ena_vlan_promisc(struct ice_vsi *vsi, struct ice_vlan *vlan)
 +{
 +      u8 promisc_m = ICE_PROMISC_VLAN_TX | ICE_PROMISC_VLAN_RX;
 +      int status;
 +
 +      status = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m,
 +                                        vlan->vid);
 +      if (status && status != -EEXIST)
 +              return status;
 +
 +      return 0;
 +}
 +
 +/**
 + * ice_vf_dis_vlan_promisc - Disable Tx/Rx VLAN promiscuous for the VLAN
 + * @vsi: VF's VSI used to disable VLAN promiscuous mode for
 + * @vlan: VLAN used to disable VLAN promiscuous
 + *
 + * This function should only be called if VLAN promiscuous mode is allowed,
 + * which can be determined via ice_is_vlan_promisc_allowed().
 + */
 +static int ice_vf_dis_vlan_promisc(struct ice_vsi *vsi, struct ice_vlan *vlan)
 +{
 +      u8 promisc_m = ICE_PROMISC_VLAN_TX | ICE_PROMISC_VLAN_RX;
 +      int status;
 +
 +      status = ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m,
 +                                          vlan->vid);
 +      if (status && status != -ENOENT)
 +              return status;
 +
 +      return 0;
 +}
 +
 +/**
 + * ice_vf_has_max_vlans - check if VF already has the max allowed VLAN filters
 + * @vf: VF to check against
 + * @vsi: VF's VSI
 + *
 + * If the VF is trusted then the VF is allowed to add as many VLANs as it
 + * wants to, so return false.
 + *
 + * When the VF is untrusted compare the number of non-zero VLANs + 1 to the max
 + * allowed VLANs for an untrusted VF. Return the result of this comparison.
 + */
 +static bool ice_vf_has_max_vlans(struct ice_vf *vf, struct ice_vsi *vsi)
 +{
 +      if (ice_is_vf_trusted(vf))
 +              return false;
 +
 +#define ICE_VF_ADDED_VLAN_ZERO_FLTRS  1
 +      return ((ice_vsi_num_non_zero_vlans(vsi) +
 +              ICE_VF_ADDED_VLAN_ZERO_FLTRS) >= ICE_MAX_VLAN_PER_VF);
 +}
 +
  /**
   * ice_vc_process_vlan_msg
   * @vf: pointer to the VF info
@@@ -4473,7 -4149,9 +4455,7 @@@ static int ice_vc_process_vlan_msg(stru
        bool vlan_promisc = false;
        struct ice_vsi *vsi;
        struct device *dev;
 -      struct ice_hw *hw;
        int status = 0;
 -      u8 promisc_m;
        int i;
  
        dev = ice_pf_to_dev(pf);
                }
        }
  
 -      hw = &pf->hw;
        vsi = ice_get_vf_vsi(vf);
        if (!vsi) {
                v_ret = VIRTCHNL_STATUS_ERR_PARAM;
                goto error_param;
        }
  
 -      if (add_v && !ice_is_vf_trusted(vf) &&
 -          vsi->num_vlan >= ICE_MAX_VLAN_PER_VF) {
 +      if (add_v && ice_vf_has_max_vlans(vf, vsi)) {
                dev_info(dev, "VF-%d is not trusted, switch the VF to trusted mode, in order to add more VLAN addresses\n",
                         vf->vf_id);
                /* There is no need to let VF know about being not trusted,
                goto error_param;
        }
  
 -      if (vsi->info.pvid) {
 +      /* in DVM a VF can add/delete inner VLAN filters when
 +       * VIRTCHNL_VF_OFFLOAD_VLAN is negotiated, so only reject in SVM
 +       */
 +      if (ice_vf_is_port_vlan_ena(vf) && !ice_is_dvm_ena(&pf->hw)) {
                v_ret = VIRTCHNL_STATUS_ERR_PARAM;
                goto error_param;
        }
  
 -      if ((test_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states) ||
 -           test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states)) &&
 -          test_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, pf->flags))
 -              vlan_promisc = true;
 +      /* in DVM VLAN promiscuous is based on the outer VLAN, which would be
 +       * the port VLAN if VIRTCHNL_VF_OFFLOAD_VLAN was negotiated, so only
 +       * allow vlan_promisc = true in SVM and if no port VLAN is configured
 +       */
 +      vlan_promisc = ice_is_vlan_promisc_allowed(vf) &&
 +              !ice_is_dvm_ena(&pf->hw) &&
 +              !ice_vf_is_port_vlan_ena(vf);
  
        if (add_v) {
                for (i = 0; i < vfl->num_elements; i++) {
                        u16 vid = vfl->vlan_id[i];
 +                      struct ice_vlan vlan;
  
 -                      if (!ice_is_vf_trusted(vf) &&
 -                          vsi->num_vlan >= ICE_MAX_VLAN_PER_VF) {
 +                      if (ice_vf_has_max_vlans(vf, vsi)) {
                                dev_info(dev, "VF-%d is not trusted, switch the VF to trusted mode, in order to add more VLAN addresses\n",
                                         vf->vf_id);
                                /* There is no need to let VF know about being
                        if (!vid)
                                continue;
  
 -                      status = ice_vsi_add_vlan(vsi, vid, ICE_FWD_TO_VSI);
 +                      vlan = ICE_VLAN(ETH_P_8021Q, vid, 0);
 +                      status = vsi->inner_vlan_ops.add_vlan(vsi, &vlan);
                        if (status) {
                                v_ret = VIRTCHNL_STATUS_ERR_PARAM;
                                goto error_param;
                        }
  
 -                      /* Enable VLAN pruning when non-zero VLAN is added */
 -                      if (!vlan_promisc && vid &&
 -                          !ice_vsi_is_vlan_pruning_ena(vsi)) {
 -                              status = ice_cfg_vlan_pruning(vsi, true);
 -                              if (status) {
 +                      /* Enable VLAN filtering on first non-zero VLAN */
 +                      if (!vlan_promisc && vid && !ice_is_dvm_ena(&pf->hw)) {
 +                              if (vsi->inner_vlan_ops.ena_rx_filtering(vsi)) {
                                        v_ret = VIRTCHNL_STATUS_ERR_PARAM;
                                        dev_err(dev, "Enable VLAN pruning on VLAN ID: %d failed error-%d\n",
                                                vid, status);
                                        goto error_param;
                                }
                        } else if (vlan_promisc) {
 -                              /* Enable Ucast/Mcast VLAN promiscuous mode */
 -                              promisc_m = ICE_PROMISC_VLAN_TX |
 -                                          ICE_PROMISC_VLAN_RX;
 -
 -                              status = ice_set_vsi_promisc(hw, vsi->idx,
 -                                                           promisc_m, vid);
 +                              status = ice_vf_ena_vlan_promisc(vsi, &vlan);
                                if (status) {
                                        v_ret = VIRTCHNL_STATUS_ERR_PARAM;
                                        dev_err(dev, "Enable Unicast/multicast promiscuous mode on VLAN ID:%d failed error-%d\n",
                num_vf_vlan = vsi->num_vlan;
                for (i = 0; i < vfl->num_elements && i < num_vf_vlan; i++) {
                        u16 vid = vfl->vlan_id[i];
 +                      struct ice_vlan vlan;
  
                        /* we add VLAN 0 by default for each VF so we can enable
                         * Tx VLAN anti-spoof without triggering MDD events so
                        if (!vid)
                                continue;
  
 -                      /* Make sure ice_vsi_kill_vlan is successful before
 -                       * updating VLAN information
 -                       */
 -                      status = ice_vsi_kill_vlan(vsi, vid);
 +                      vlan = ICE_VLAN(ETH_P_8021Q, vid, 0);
 +                      status = vsi->inner_vlan_ops.del_vlan(vsi, &vlan);
                        if (status) {
                                v_ret = VIRTCHNL_STATUS_ERR_PARAM;
                                goto error_param;
                        }
  
 -                      /* Disable VLAN pruning when only VLAN 0 is left */
 -                      if (vsi->num_vlan == 1 &&
 -                          ice_vsi_is_vlan_pruning_ena(vsi))
 -                              ice_cfg_vlan_pruning(vsi, false);
 -
 -                      /* Disable Unicast/Multicast VLAN promiscuous mode */
 -                      if (vlan_promisc) {
 -                              promisc_m = ICE_PROMISC_VLAN_TX |
 -                                          ICE_PROMISC_VLAN_RX;
 +                      /* Disable VLAN filtering when only VLAN 0 is left */
 +                      if (!ice_vsi_has_non_zero_vlans(vsi))
 +                              vsi->inner_vlan_ops.dis_rx_filtering(vsi);
  
 -                              ice_clear_vsi_promisc(hw, vsi->idx,
 -                                                    promisc_m, vid);
 -                      }
 +                      if (vlan_promisc)
 +                              ice_vf_dis_vlan_promisc(vsi, &vlan);
                }
        }
  
@@@ -4672,7 -4360,7 +4654,7 @@@ static int ice_vc_ena_vlan_stripping(st
        }
  
        vsi = ice_get_vf_vsi(vf);
 -      if (ice_vsi_manage_vlan_stripping(vsi, true))
 +      if (vsi->inner_vlan_ops.ena_stripping(vsi, ETH_P_8021Q))
                v_ret = VIRTCHNL_STATUS_ERR_PARAM;
  
  error_param:
@@@ -4707,7 -4395,7 +4689,7 @@@ static int ice_vc_dis_vlan_stripping(st
                goto error_param;
        }
  
 -      if (ice_vsi_manage_vlan_stripping(vsi, false))
 +      if (vsi->inner_vlan_ops.dis_stripping(vsi))
                v_ret = VIRTCHNL_STATUS_ERR_PARAM;
  
  error_param:
   * ice_vf_init_vlan_stripping - enable/disable VLAN stripping on initialization
   * @vf: VF to enable/disable VLAN stripping for on initialization
   *
 - * If the VIRTCHNL_VF_OFFLOAD_VLAN flag is set enable VLAN stripping, else if
 - * the flag is cleared then we want to disable stripping. For example, the flag
 - * will be cleared when port VLANs are configured by the administrator before
 - * passing the VF to the guest or if the AVF driver doesn't support VLAN
 - * offloads.
 + * Set the default for VLAN stripping based on whether a port VLAN is configured
 + * and the current VLAN mode of the device.
   */
  static int ice_vf_init_vlan_stripping(struct ice_vf *vf)
  {
        if (!vsi)
                return -EINVAL;
  
 -      /* don't modify stripping if port VLAN is configured */
 -      if (vsi->info.pvid)
 +      /* don't modify stripping if port VLAN is configured in SVM since the
 +       * port VLAN is based on the inner/single VLAN in SVM
 +       */
 +      if (ice_vf_is_port_vlan_ena(vf) && !ice_is_dvm_ena(&vsi->back->hw))
                return 0;
  
        if (ice_vf_vlan_offload_ena(vf->driver_caps))
 -              return ice_vsi_manage_vlan_stripping(vsi, true);
 +              return vsi->inner_vlan_ops.ena_stripping(vsi, ETH_P_8021Q);
        else
 -              return ice_vsi_manage_vlan_stripping(vsi, false);
 +              return vsi->inner_vlan_ops.dis_stripping(vsi);
  }
  
 -static struct ice_vc_vf_ops ice_vc_vf_dflt_ops = {
 -      .get_ver_msg = ice_vc_get_ver_msg,
 -      .get_vf_res_msg = ice_vc_get_vf_res_msg,
 -      .reset_vf = ice_vc_reset_vf_msg,
 -      .add_mac_addr_msg = ice_vc_add_mac_addr_msg,
 -      .del_mac_addr_msg = ice_vc_del_mac_addr_msg,
 -      .cfg_qs_msg = ice_vc_cfg_qs_msg,
 -      .ena_qs_msg = ice_vc_ena_qs_msg,
 -      .dis_qs_msg = ice_vc_dis_qs_msg,
 -      .request_qs_msg = ice_vc_request_qs_msg,
 -      .cfg_irq_map_msg = ice_vc_cfg_irq_map_msg,
 -      .config_rss_key = ice_vc_config_rss_key,
 -      .config_rss_lut = ice_vc_config_rss_lut,
 -      .get_stats_msg = ice_vc_get_stats_msg,
 -      .cfg_promiscuous_mode_msg = ice_vc_cfg_promiscuous_mode_msg,
 -      .add_vlan_msg = ice_vc_add_vlan_msg,
 -      .remove_vlan_msg = ice_vc_remove_vlan_msg,
 -      .ena_vlan_stripping = ice_vc_ena_vlan_stripping,
 -      .dis_vlan_stripping = ice_vc_dis_vlan_stripping,
 -      .handle_rss_cfg_msg = ice_vc_handle_rss_cfg,
 -      .add_fdir_fltr_msg = ice_vc_add_fdir_fltr,
 -      .del_fdir_fltr_msg = ice_vc_del_fdir_fltr,
 -};
 +static u16 ice_vc_get_max_vlan_fltrs(struct ice_vf *vf)
 +{
 +      if (vf->trusted)
 +              return VLAN_N_VID;
 +      else
 +              return ICE_MAX_VLAN_PER_VF;
 +}
  
 -void ice_vc_set_dflt_vf_ops(struct ice_vc_vf_ops *ops)
 +/**
 + * ice_vf_outer_vlan_not_allowed - check outer VLAN can be used when the device is in DVM
 + * @vf: VF that being checked for
 + */
 +static bool ice_vf_outer_vlan_not_allowed(struct ice_vf *vf)
  {
 -      *ops = ice_vc_vf_dflt_ops;
 +      if (ice_vf_is_port_vlan_ena(vf))
 +              return true;
 +
 +      return false;
  }
  
  /**
 - * ice_vc_repr_add_mac
 - * @vf: pointer to VF
 - * @msg: virtchannel message
 + * ice_vc_set_dvm_caps - set VLAN capabilities when the device is in DVM
 + * @vf: VF that capabilities are being set for
 + * @caps: VLAN capabilities to populate
   *
 - * When port representors are created, we do not add MAC rule
 - * to firmware, we store it so that PF could report same
 - * MAC as VF.
 + * Determine VLAN capabilities support based on whether a port VLAN is
 + * configured. If a port VLAN is configured then the VF should use the inner
 + * filtering/offload capabilities since the port VLAN is using the outer VLAN
 + * capabilies.
   */
 -static int ice_vc_repr_add_mac(struct ice_vf *vf, u8 *msg)
 +static void
 +ice_vc_set_dvm_caps(struct ice_vf *vf, struct virtchnl_vlan_caps *caps)
  {
 -      enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
 -      struct virtchnl_ether_addr_list *al =
 -          (struct virtchnl_ether_addr_list *)msg;
 -      struct ice_vsi *vsi;
 -      struct ice_pf *pf;
 -      int i;
 +      struct virtchnl_vlan_supported_caps *supported_caps;
  
 -      if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) ||
 -          !ice_vc_isvalid_vsi_id(vf, al->vsi_id)) {
 -              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 -              goto handle_mac_exit;
 -      }
 +      if (ice_vf_outer_vlan_not_allowed(vf)) {
 +              /* until support for inner VLAN filtering is added when a port
 +               * VLAN is configured, only support software offloaded inner
 +               * VLANs when a port VLAN is confgured in DVM
 +               */
 +              supported_caps = &caps->filtering.filtering_support;
 +              supported_caps->inner = VIRTCHNL_VLAN_UNSUPPORTED;
 +
 +              supported_caps = &caps->offloads.stripping_support;
 +              supported_caps->inner = VIRTCHNL_VLAN_ETHERTYPE_8100 |
 +                                      VIRTCHNL_VLAN_TOGGLE |
 +                                      VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1;
 +              supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED;
 +
 +              supported_caps = &caps->offloads.insertion_support;
 +              supported_caps->inner = VIRTCHNL_VLAN_ETHERTYPE_8100 |
 +                                      VIRTCHNL_VLAN_TOGGLE |
 +                                      VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1;
 +              supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED;
 +
 +              caps->offloads.ethertype_init = VIRTCHNL_VLAN_ETHERTYPE_8100;
 +              caps->offloads.ethertype_match =
 +                      VIRTCHNL_ETHERTYPE_STRIPPING_MATCHES_INSERTION;
 +      } else {
 +              supported_caps = &caps->filtering.filtering_support;
 +              supported_caps->inner = VIRTCHNL_VLAN_UNSUPPORTED;
 +              supported_caps->outer = VIRTCHNL_VLAN_ETHERTYPE_8100 |
 +                                      VIRTCHNL_VLAN_ETHERTYPE_88A8 |
 +                                      VIRTCHNL_VLAN_ETHERTYPE_9100 |
 +                                      VIRTCHNL_VLAN_ETHERTYPE_AND;
 +              caps->filtering.ethertype_init = VIRTCHNL_VLAN_ETHERTYPE_8100 |
 +                                               VIRTCHNL_VLAN_ETHERTYPE_88A8 |
 +                                               VIRTCHNL_VLAN_ETHERTYPE_9100;
 +
 +              supported_caps = &caps->offloads.stripping_support;
 +              supported_caps->inner = VIRTCHNL_VLAN_TOGGLE |
 +                                      VIRTCHNL_VLAN_ETHERTYPE_8100 |
 +                                      VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1;
 +              supported_caps->outer = VIRTCHNL_VLAN_TOGGLE |
 +                                      VIRTCHNL_VLAN_ETHERTYPE_8100 |
 +                                      VIRTCHNL_VLAN_ETHERTYPE_88A8 |
 +                                      VIRTCHNL_VLAN_ETHERTYPE_9100 |
 +                                      VIRTCHNL_VLAN_ETHERTYPE_XOR |
 +                                      VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2;
 +
 +              supported_caps = &caps->offloads.insertion_support;
 +              supported_caps->inner = VIRTCHNL_VLAN_TOGGLE |
 +                                      VIRTCHNL_VLAN_ETHERTYPE_8100 |
 +                                      VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1;
 +              supported_caps->outer = VIRTCHNL_VLAN_TOGGLE |
 +                                      VIRTCHNL_VLAN_ETHERTYPE_8100 |
 +                                      VIRTCHNL_VLAN_ETHERTYPE_88A8 |
 +                                      VIRTCHNL_VLAN_ETHERTYPE_9100 |
 +                                      VIRTCHNL_VLAN_ETHERTYPE_XOR |
 +                                      VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2;
 +
 +              caps->offloads.ethertype_init = VIRTCHNL_VLAN_ETHERTYPE_8100;
 +
 +              caps->offloads.ethertype_match =
 +                      VIRTCHNL_ETHERTYPE_STRIPPING_MATCHES_INSERTION;
 +      }
 +
 +      caps->filtering.max_filters = ice_vc_get_max_vlan_fltrs(vf);
 +}
 +
 +/**
 + * ice_vc_set_svm_caps - set VLAN capabilities when the device is in SVM
 + * @vf: VF that capabilities are being set for
 + * @caps: VLAN capabilities to populate
 + *
 + * Determine VLAN capabilities support based on whether a port VLAN is
 + * configured. If a port VLAN is configured then the VF does not have any VLAN
 + * filtering or offload capabilities since the port VLAN is using the inner VLAN
 + * capabilities in single VLAN mode (SVM). Otherwise allow the VF to use inner
 + * VLAN fitlering and offload capabilities.
 + */
 +static void
 +ice_vc_set_svm_caps(struct ice_vf *vf, struct virtchnl_vlan_caps *caps)
 +{
 +      struct virtchnl_vlan_supported_caps *supported_caps;
  
 -      pf = vf->pf;
 +      if (ice_vf_is_port_vlan_ena(vf)) {
 +              supported_caps = &caps->filtering.filtering_support;
 +              supported_caps->inner = VIRTCHNL_VLAN_UNSUPPORTED;
 +              supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED;
  
 -      vsi = ice_get_vf_vsi(vf);
 -      if (!vsi) {
 -              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 -              goto handle_mac_exit;
 -      }
 +              supported_caps = &caps->offloads.stripping_support;
 +              supported_caps->inner = VIRTCHNL_VLAN_UNSUPPORTED;
 +              supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED;
  
 -      for (i = 0; i < al->num_elements; i++) {
 -              u8 *mac_addr = al->list[i].addr;
 -              int result;
 +              supported_caps = &caps->offloads.insertion_support;
 +              supported_caps->inner = VIRTCHNL_VLAN_UNSUPPORTED;
 +              supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED;
  
 -              if (!is_unicast_ether_addr(mac_addr) ||
 -                  ether_addr_equal(mac_addr, vf->hw_lan_addr.addr))
 -                      continue;
 +              caps->offloads.ethertype_init = VIRTCHNL_VLAN_UNSUPPORTED;
 +              caps->offloads.ethertype_match = VIRTCHNL_VLAN_UNSUPPORTED;
 +              caps->filtering.max_filters = 0;
 +      } else {
 +              supported_caps = &caps->filtering.filtering_support;
 +              supported_caps->inner = VIRTCHNL_VLAN_ETHERTYPE_8100;
 +              supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED;
 +              caps->filtering.ethertype_init = VIRTCHNL_VLAN_ETHERTYPE_8100;
  
 -              if (vf->pf_set_mac) {
 -                      dev_err(ice_pf_to_dev(pf), "VF attempting to override administratively set MAC address\n");
 -                      v_ret = VIRTCHNL_STATUS_ERR_NOT_SUPPORTED;
 -                      goto handle_mac_exit;
 -              }
 +              supported_caps = &caps->offloads.stripping_support;
 +              supported_caps->inner = VIRTCHNL_VLAN_ETHERTYPE_8100 |
 +                                      VIRTCHNL_VLAN_TOGGLE |
 +                                      VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1;
 +              supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED;
  
 -              result = ice_eswitch_add_vf_mac_rule(pf, vf, mac_addr);
 -              if (result) {
 -                      dev_err(ice_pf_to_dev(pf), "Failed to add MAC %pM for VF %d\n, error %d\n",
 -                              mac_addr, vf->vf_id, result);
 -                      goto handle_mac_exit;
 -              }
 +              supported_caps = &caps->offloads.insertion_support;
 +              supported_caps->inner = VIRTCHNL_VLAN_ETHERTYPE_8100 |
 +                                      VIRTCHNL_VLAN_TOGGLE |
 +                                      VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1;
 +              supported_caps->outer = VIRTCHNL_VLAN_UNSUPPORTED;
  
 -              ice_vfhw_mac_add(vf, &al->list[i]);
 -              vf->num_mac++;
 -              break;
 +              caps->offloads.ethertype_init = VIRTCHNL_VLAN_ETHERTYPE_8100;
 +              caps->offloads.ethertype_match =
 +                      VIRTCHNL_ETHERTYPE_STRIPPING_MATCHES_INSERTION;
 +              caps->filtering.max_filters = ice_vc_get_max_vlan_fltrs(vf);
        }
 -
 -handle_mac_exit:
 -      return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_ETH_ADDR,
 -                                   v_ret, NULL, 0);
  }
  
  /**
 - * ice_vc_repr_del_mac - response with success for deleting MAC
 - * @vf: pointer to VF
 - * @msg: virtchannel message
 + * ice_vc_get_offload_vlan_v2_caps - determine VF's VLAN capabilities
 + * @vf: VF to determine VLAN capabilities for
   *
 - * Respond with success to not break normal VF flow.
 - * For legacy VF driver try to update cached MAC address.
 + * This will only be called if the VF and PF successfully negotiated
 + * VIRTCHNL_VF_OFFLOAD_VLAN_V2.
 + *
 + * Set VLAN capabilities based on the current VLAN mode and whether a port VLAN
 + * is configured or not.
   */
 -static int
 -ice_vc_repr_del_mac(struct ice_vf __always_unused *vf, u8 __always_unused *msg)
 +static int ice_vc_get_offload_vlan_v2_caps(struct ice_vf *vf)
  {
 -      struct virtchnl_ether_addr_list *al =
 -              (struct virtchnl_ether_addr_list *)msg;
 +      enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
 +      struct virtchnl_vlan_caps *caps = NULL;
 +      int err, len = 0;
  
 -      ice_update_legacy_cached_mac(vf, &al->list[0]);
 +      if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
  
 -      return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DEL_ETH_ADDR,
 -                                   VIRTCHNL_STATUS_SUCCESS, NULL, 0);
 +      caps = kzalloc(sizeof(*caps), GFP_KERNEL);
 +      if (!caps) {
 +              v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
 +              goto out;
 +      }
 +      len = sizeof(*caps);
 +
 +      if (ice_is_dvm_ena(&vf->pf->hw))
 +              ice_vc_set_dvm_caps(vf, caps);
 +      else
 +              ice_vc_set_svm_caps(vf, caps);
 +
 +      /* store negotiated caps to prevent invalid VF messages */
 +      memcpy(&vf->vlan_v2_caps, caps, sizeof(*caps));
 +
 +out:
 +      err = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS,
 +                                  v_ret, (u8 *)caps, len);
 +      kfree(caps);
 +      return err;
  }
  
 -static int ice_vc_repr_add_vlan(struct ice_vf *vf, u8 __always_unused *msg)
 -{
 +/**
 + * ice_vc_validate_vlan_tpid - validate VLAN TPID
 + * @filtering_caps: negotiated/supported VLAN filtering capabilities
 + * @tpid: VLAN TPID used for validation
 + *
 + * Convert the VLAN TPID to a VIRTCHNL_VLAN_ETHERTYPE_* and then compare against
 + * the negotiated/supported filtering caps to see if the VLAN TPID is valid.
 + */
 +static bool ice_vc_validate_vlan_tpid(u16 filtering_caps, u16 tpid)
 +{
 +      enum virtchnl_vlan_support vlan_ethertype = VIRTCHNL_VLAN_UNSUPPORTED;
 +
 +      switch (tpid) {
 +      case ETH_P_8021Q:
 +              vlan_ethertype = VIRTCHNL_VLAN_ETHERTYPE_8100;
 +              break;
 +      case ETH_P_8021AD:
 +              vlan_ethertype = VIRTCHNL_VLAN_ETHERTYPE_88A8;
 +              break;
 +      case ETH_P_QINQ1:
 +              vlan_ethertype = VIRTCHNL_VLAN_ETHERTYPE_9100;
 +              break;
 +      }
 +
 +      if (!(filtering_caps & vlan_ethertype))
 +              return false;
 +
 +      return true;
 +}
 +
 +/**
 + * ice_vc_is_valid_vlan - validate the virtchnl_vlan
 + * @vc_vlan: virtchnl_vlan to validate
 + *
 + * If the VLAN TCI and VLAN TPID are 0, then this filter is invalid, so return
 + * false. Otherwise return true.
 + */
 +static bool ice_vc_is_valid_vlan(struct virtchnl_vlan *vc_vlan)
 +{
 +      if (!vc_vlan->tci || !vc_vlan->tpid)
 +              return false;
 +
 +      return true;
 +}
 +
 +/**
 + * ice_vc_validate_vlan_filter_list - validate the filter list from the VF
 + * @vfc: negotiated/supported VLAN filtering capabilities
 + * @vfl: VLAN filter list from VF to validate
 + *
 + * Validate all of the filters in the VLAN filter list from the VF. If any of
 + * the checks fail then return false. Otherwise return true.
 + */
 +static bool
 +ice_vc_validate_vlan_filter_list(struct virtchnl_vlan_filtering_caps *vfc,
 +                               struct virtchnl_vlan_filter_list_v2 *vfl)
 +{
 +      u16 i;
 +
 +      if (!vfl->num_elements)
 +              return false;
 +
 +      for (i = 0; i < vfl->num_elements; i++) {
 +              struct virtchnl_vlan_supported_caps *filtering_support =
 +                      &vfc->filtering_support;
 +              struct virtchnl_vlan_filter *vlan_fltr = &vfl->filters[i];
 +              struct virtchnl_vlan *outer = &vlan_fltr->outer;
 +              struct virtchnl_vlan *inner = &vlan_fltr->inner;
 +
 +              if ((ice_vc_is_valid_vlan(outer) &&
 +                   filtering_support->outer == VIRTCHNL_VLAN_UNSUPPORTED) ||
 +                  (ice_vc_is_valid_vlan(inner) &&
 +                   filtering_support->inner == VIRTCHNL_VLAN_UNSUPPORTED))
 +                      return false;
 +
 +              if ((outer->tci_mask &&
 +                   !(filtering_support->outer & VIRTCHNL_VLAN_FILTER_MASK)) ||
 +                  (inner->tci_mask &&
 +                   !(filtering_support->inner & VIRTCHNL_VLAN_FILTER_MASK)))
 +                      return false;
 +
 +              if (((outer->tci & VLAN_PRIO_MASK) &&
 +                   !(filtering_support->outer & VIRTCHNL_VLAN_PRIO)) ||
 +                  ((inner->tci & VLAN_PRIO_MASK) &&
 +                   !(filtering_support->inner & VIRTCHNL_VLAN_PRIO)))
 +                      return false;
 +
 +              if ((ice_vc_is_valid_vlan(outer) &&
 +                   !ice_vc_validate_vlan_tpid(filtering_support->outer, outer->tpid)) ||
 +                  (ice_vc_is_valid_vlan(inner) &&
 +                   !ice_vc_validate_vlan_tpid(filtering_support->inner, inner->tpid)))
 +                      return false;
 +      }
 +
 +      return true;
 +}
 +
 +/**
 + * ice_vc_to_vlan - transform from struct virtchnl_vlan to struct ice_vlan
 + * @vc_vlan: struct virtchnl_vlan to transform
 + */
 +static struct ice_vlan ice_vc_to_vlan(struct virtchnl_vlan *vc_vlan)
 +{
 +      struct ice_vlan vlan = { 0 };
 +
 +      vlan.prio = (vc_vlan->tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
 +      vlan.vid = vc_vlan->tci & VLAN_VID_MASK;
 +      vlan.tpid = vc_vlan->tpid;
 +
 +      return vlan;
 +}
 +
 +/**
 + * ice_vc_vlan_action - action to perform on the virthcnl_vlan
 + * @vsi: VF's VSI used to perform the action
 + * @vlan_action: function to perform the action with (i.e. add/del)
 + * @vlan: VLAN filter to perform the action with
 + */
 +static int
 +ice_vc_vlan_action(struct ice_vsi *vsi,
 +                 int (*vlan_action)(struct ice_vsi *, struct ice_vlan *),
 +                 struct ice_vlan *vlan)
 +{
 +      int err;
 +
 +      err = vlan_action(vsi, vlan);
 +      if (err)
 +              return err;
 +
 +      return 0;
 +}
 +
 +/**
 + * ice_vc_del_vlans - delete VLAN(s) from the virtchnl filter list
 + * @vf: VF used to delete the VLAN(s)
 + * @vsi: VF's VSI used to delete the VLAN(s)
 + * @vfl: virthchnl filter list used to delete the filters
 + */
 +static int
 +ice_vc_del_vlans(struct ice_vf *vf, struct ice_vsi *vsi,
 +               struct virtchnl_vlan_filter_list_v2 *vfl)
 +{
 +      bool vlan_promisc = ice_is_vlan_promisc_allowed(vf);
 +      int err;
 +      u16 i;
 +
 +      for (i = 0; i < vfl->num_elements; i++) {
 +              struct virtchnl_vlan_filter *vlan_fltr = &vfl->filters[i];
 +              struct virtchnl_vlan *vc_vlan;
 +
 +              vc_vlan = &vlan_fltr->outer;
 +              if (ice_vc_is_valid_vlan(vc_vlan)) {
 +                      struct ice_vlan vlan = ice_vc_to_vlan(vc_vlan);
 +
 +                      err = ice_vc_vlan_action(vsi,
 +                                               vsi->outer_vlan_ops.del_vlan,
 +                                               &vlan);
 +                      if (err)
 +                              return err;
 +
 +                      if (vlan_promisc)
 +                              ice_vf_dis_vlan_promisc(vsi, &vlan);
 +              }
 +
 +              vc_vlan = &vlan_fltr->inner;
 +              if (ice_vc_is_valid_vlan(vc_vlan)) {
 +                      struct ice_vlan vlan = ice_vc_to_vlan(vc_vlan);
 +
 +                      err = ice_vc_vlan_action(vsi,
 +                                               vsi->inner_vlan_ops.del_vlan,
 +                                               &vlan);
 +                      if (err)
 +                              return err;
 +
 +                      /* no support for VLAN promiscuous on inner VLAN unless
 +                       * we are in Single VLAN Mode (SVM)
 +                       */
 +                      if (!ice_is_dvm_ena(&vsi->back->hw) && vlan_promisc)
 +                              ice_vf_dis_vlan_promisc(vsi, &vlan);
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +/**
 + * ice_vc_remove_vlan_v2_msg - virtchnl handler for VIRTCHNL_OP_DEL_VLAN_V2
 + * @vf: VF the message was received from
 + * @msg: message received from the VF
 + */
 +static int ice_vc_remove_vlan_v2_msg(struct ice_vf *vf, u8 *msg)
 +{
 +      struct virtchnl_vlan_filter_list_v2 *vfl =
 +              (struct virtchnl_vlan_filter_list_v2 *)msg;
 +      enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
 +      struct ice_vsi *vsi;
 +
 +      if (!ice_vc_validate_vlan_filter_list(&vf->vlan_v2_caps.filtering,
 +                                            vfl)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      if (!ice_vc_isvalid_vsi_id(vf, vfl->vport_id)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      vsi = ice_get_vf_vsi(vf);
 +      if (!vsi) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      if (ice_vc_del_vlans(vf, vsi, vfl))
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +
 +out:
 +      return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DEL_VLAN_V2, v_ret, NULL,
 +                                   0);
 +}
 +
 +/**
 + * ice_vc_add_vlans - add VLAN(s) from the virtchnl filter list
 + * @vf: VF used to add the VLAN(s)
 + * @vsi: VF's VSI used to add the VLAN(s)
 + * @vfl: virthchnl filter list used to add the filters
 + */
 +static int
 +ice_vc_add_vlans(struct ice_vf *vf, struct ice_vsi *vsi,
 +               struct virtchnl_vlan_filter_list_v2 *vfl)
 +{
 +      bool vlan_promisc = ice_is_vlan_promisc_allowed(vf);
 +      int err;
 +      u16 i;
 +
 +      for (i = 0; i < vfl->num_elements; i++) {
 +              struct virtchnl_vlan_filter *vlan_fltr = &vfl->filters[i];
 +              struct virtchnl_vlan *vc_vlan;
 +
 +              vc_vlan = &vlan_fltr->outer;
 +              if (ice_vc_is_valid_vlan(vc_vlan)) {
 +                      struct ice_vlan vlan = ice_vc_to_vlan(vc_vlan);
 +
 +                      err = ice_vc_vlan_action(vsi,
 +                                               vsi->outer_vlan_ops.add_vlan,
 +                                               &vlan);
 +                      if (err)
 +                              return err;
 +
 +                      if (vlan_promisc) {
 +                              err = ice_vf_ena_vlan_promisc(vsi, &vlan);
 +                              if (err)
 +                                      return err;
 +                      }
 +              }
 +
 +              vc_vlan = &vlan_fltr->inner;
 +              if (ice_vc_is_valid_vlan(vc_vlan)) {
 +                      struct ice_vlan vlan = ice_vc_to_vlan(vc_vlan);
 +
 +                      err = ice_vc_vlan_action(vsi,
 +                                               vsi->inner_vlan_ops.add_vlan,
 +                                               &vlan);
 +                      if (err)
 +                              return err;
 +
 +                      /* no support for VLAN promiscuous on inner VLAN unless
 +                       * we are in Single VLAN Mode (SVM)
 +                       */
 +                      if (!ice_is_dvm_ena(&vsi->back->hw) && vlan_promisc) {
 +                              err = ice_vf_ena_vlan_promisc(vsi, &vlan);
 +                              if (err)
 +                                      return err;
 +                      }
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +/**
 + * ice_vc_validate_add_vlan_filter_list - validate add filter list from the VF
 + * @vsi: VF VSI used to get number of existing VLAN filters
 + * @vfc: negotiated/supported VLAN filtering capabilities
 + * @vfl: VLAN filter list from VF to validate
 + *
 + * Validate all of the filters in the VLAN filter list from the VF during the
 + * VIRTCHNL_OP_ADD_VLAN_V2 opcode. If any of the checks fail then return false.
 + * Otherwise return true.
 + */
 +static bool
 +ice_vc_validate_add_vlan_filter_list(struct ice_vsi *vsi,
 +                                   struct virtchnl_vlan_filtering_caps *vfc,
 +                                   struct virtchnl_vlan_filter_list_v2 *vfl)
 +{
 +      u16 num_requested_filters = vsi->num_vlan + vfl->num_elements;
 +
 +      if (num_requested_filters > vfc->max_filters)
 +              return false;
 +
 +      return ice_vc_validate_vlan_filter_list(vfc, vfl);
 +}
 +
 +/**
 + * ice_vc_add_vlan_v2_msg - virtchnl handler for VIRTCHNL_OP_ADD_VLAN_V2
 + * @vf: VF the message was received from
 + * @msg: message received from the VF
 + */
 +static int ice_vc_add_vlan_v2_msg(struct ice_vf *vf, u8 *msg)
 +{
 +      enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
 +      struct virtchnl_vlan_filter_list_v2 *vfl =
 +              (struct virtchnl_vlan_filter_list_v2 *)msg;
 +      struct ice_vsi *vsi;
 +
 +      if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      if (!ice_vc_isvalid_vsi_id(vf, vfl->vport_id)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      vsi = ice_get_vf_vsi(vf);
 +      if (!vsi) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      if (!ice_vc_validate_add_vlan_filter_list(vsi,
 +                                                &vf->vlan_v2_caps.filtering,
 +                                                vfl)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      if (ice_vc_add_vlans(vf, vsi, vfl))
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +
 +out:
 +      return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_VLAN_V2, v_ret, NULL,
 +                                   0);
 +}
 +
 +/**
 + * ice_vc_valid_vlan_setting - validate VLAN setting
 + * @negotiated_settings: negotiated VLAN settings during VF init
 + * @ethertype_setting: ethertype(s) requested for the VLAN setting
 + */
 +static bool
 +ice_vc_valid_vlan_setting(u32 negotiated_settings, u32 ethertype_setting)
 +{
 +      if (ethertype_setting && !(negotiated_settings & ethertype_setting))
 +              return false;
 +
 +      /* only allow a single VIRTCHNL_VLAN_ETHERTYPE if
 +       * VIRTHCNL_VLAN_ETHERTYPE_AND is not negotiated/supported
 +       */
 +      if (!(negotiated_settings & VIRTCHNL_VLAN_ETHERTYPE_AND) &&
 +          hweight32(ethertype_setting) > 1)
 +              return false;
 +
 +      /* ability to modify the VLAN setting was not negotiated */
 +      if (!(negotiated_settings & VIRTCHNL_VLAN_TOGGLE))
 +              return false;
 +
 +      return true;
 +}
 +
 +/**
 + * ice_vc_valid_vlan_setting_msg - validate the VLAN setting message
 + * @caps: negotiated VLAN settings during VF init
 + * @msg: message to validate
 + *
 + * Used to validate any VLAN virtchnl message sent as a
 + * virtchnl_vlan_setting structure. Validates the message against the
 + * negotiated/supported caps during VF driver init.
 + */
 +static bool
 +ice_vc_valid_vlan_setting_msg(struct virtchnl_vlan_supported_caps *caps,
 +                            struct virtchnl_vlan_setting *msg)
 +{
 +      if ((!msg->outer_ethertype_setting &&
 +           !msg->inner_ethertype_setting) ||
 +          (!caps->outer && !caps->inner))
 +              return false;
 +
 +      if (msg->outer_ethertype_setting &&
 +          !ice_vc_valid_vlan_setting(caps->outer,
 +                                     msg->outer_ethertype_setting))
 +              return false;
 +
 +      if (msg->inner_ethertype_setting &&
 +          !ice_vc_valid_vlan_setting(caps->inner,
 +                                     msg->inner_ethertype_setting))
 +              return false;
 +
 +      return true;
 +}
 +
 +/**
 + * ice_vc_get_tpid - transform from VIRTCHNL_VLAN_ETHERTYPE_* to VLAN TPID
 + * @ethertype_setting: VIRTCHNL_VLAN_ETHERTYPE_* used to get VLAN TPID
 + * @tpid: VLAN TPID to populate
 + */
 +static int ice_vc_get_tpid(u32 ethertype_setting, u16 *tpid)
 +{
 +      switch (ethertype_setting) {
 +      case VIRTCHNL_VLAN_ETHERTYPE_8100:
 +              *tpid = ETH_P_8021Q;
 +              break;
 +      case VIRTCHNL_VLAN_ETHERTYPE_88A8:
 +              *tpid = ETH_P_8021AD;
 +              break;
 +      case VIRTCHNL_VLAN_ETHERTYPE_9100:
 +              *tpid = ETH_P_QINQ1;
 +              break;
 +      default:
 +              *tpid = 0;
 +              return -EINVAL;
 +      }
 +
 +      return 0;
 +}
 +
 +/**
 + * ice_vc_ena_vlan_offload - enable VLAN offload based on the ethertype_setting
 + * @vsi: VF's VSI used to enable the VLAN offload
 + * @ena_offload: function used to enable the VLAN offload
 + * @ethertype_setting: VIRTCHNL_VLAN_ETHERTYPE_* to enable offloads for
 + */
 +static int
 +ice_vc_ena_vlan_offload(struct ice_vsi *vsi,
 +                      int (*ena_offload)(struct ice_vsi *vsi, u16 tpid),
 +                      u32 ethertype_setting)
 +{
 +      u16 tpid;
 +      int err;
 +
 +      err = ice_vc_get_tpid(ethertype_setting, &tpid);
 +      if (err)
 +              return err;
 +
 +      err = ena_offload(vsi, tpid);
 +      if (err)
 +              return err;
 +
 +      return 0;
 +}
 +
 +#define ICE_L2TSEL_QRX_CONTEXT_REG_IDX        3
 +#define ICE_L2TSEL_BIT_OFFSET         23
 +enum ice_l2tsel {
 +      ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG2_2ND,
 +      ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG1,
 +};
 +
 +/**
 + * ice_vsi_update_l2tsel - update l2tsel field for all Rx rings on this VSI
 + * @vsi: VSI used to update l2tsel on
 + * @l2tsel: l2tsel setting requested
 + *
 + * Use the l2tsel setting to update all of the Rx queue context bits for l2tsel.
 + * This will modify which descriptor field the first offloaded VLAN will be
 + * stripped into.
 + */
 +static void ice_vsi_update_l2tsel(struct ice_vsi *vsi, enum ice_l2tsel l2tsel)
 +{
 +      struct ice_hw *hw = &vsi->back->hw;
 +      u32 l2tsel_bit;
 +      int i;
 +
 +      if (l2tsel == ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG2_2ND)
 +              l2tsel_bit = 0;
 +      else
 +              l2tsel_bit = BIT(ICE_L2TSEL_BIT_OFFSET);
 +
 +      for (i = 0; i < vsi->alloc_rxq; i++) {
 +              u16 pfq = vsi->rxq_map[i];
 +              u32 qrx_context_offset;
 +              u32 regval;
 +
 +              qrx_context_offset =
 +                      QRX_CONTEXT(ICE_L2TSEL_QRX_CONTEXT_REG_IDX, pfq);
 +
 +              regval = rd32(hw, qrx_context_offset);
 +              regval &= ~BIT(ICE_L2TSEL_BIT_OFFSET);
 +              regval |= l2tsel_bit;
 +              wr32(hw, qrx_context_offset, regval);
 +      }
 +}
 +
 +/**
 + * ice_vc_ena_vlan_stripping_v2_msg
 + * @vf: VF the message was received from
 + * @msg: message received from the VF
 + *
 + * virthcnl handler for VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2
 + */
 +static int ice_vc_ena_vlan_stripping_v2_msg(struct ice_vf *vf, u8 *msg)
 +{
 +      enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
 +      struct virtchnl_vlan_supported_caps *stripping_support;
 +      struct virtchnl_vlan_setting *strip_msg =
 +              (struct virtchnl_vlan_setting *)msg;
 +      u32 ethertype_setting;
 +      struct ice_vsi *vsi;
 +
 +      if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      if (!ice_vc_isvalid_vsi_id(vf, strip_msg->vport_id)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      vsi = ice_get_vf_vsi(vf);
 +      if (!vsi) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      stripping_support = &vf->vlan_v2_caps.offloads.stripping_support;
 +      if (!ice_vc_valid_vlan_setting_msg(stripping_support, strip_msg)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      ethertype_setting = strip_msg->outer_ethertype_setting;
 +      if (ethertype_setting) {
 +              if (ice_vc_ena_vlan_offload(vsi,
 +                                          vsi->outer_vlan_ops.ena_stripping,
 +                                          ethertype_setting)) {
 +                      v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +                      goto out;
 +              } else {
 +                      enum ice_l2tsel l2tsel =
 +                              ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG2_2ND;
 +
 +                      /* PF tells the VF that the outer VLAN tag is always
 +                       * extracted to VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2 and
 +                       * inner is always extracted to
 +                       * VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1. This is needed to
 +                       * support outer stripping so the first tag always ends
 +                       * up in L2TAG2_2ND and the second/inner tag, if
 +                       * enabled, is extracted in L2TAG1.
 +                       */
 +                      ice_vsi_update_l2tsel(vsi, l2tsel);
 +              }
 +      }
 +
 +      ethertype_setting = strip_msg->inner_ethertype_setting;
 +      if (ethertype_setting &&
 +          ice_vc_ena_vlan_offload(vsi, vsi->inner_vlan_ops.ena_stripping,
 +                                  ethertype_setting)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +out:
 +      return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2, v_ret, NULL, 0);
 +}
 +
 +/**
 + * ice_vc_dis_vlan_stripping_v2_msg
 + * @vf: VF the message was received from
 + * @msg: message received from the VF
 + *
 + * virthcnl handler for VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2
 + */
 +static int ice_vc_dis_vlan_stripping_v2_msg(struct ice_vf *vf, u8 *msg)
 +{
 +      enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
 +      struct virtchnl_vlan_supported_caps *stripping_support;
 +      struct virtchnl_vlan_setting *strip_msg =
 +              (struct virtchnl_vlan_setting *)msg;
 +      u32 ethertype_setting;
 +      struct ice_vsi *vsi;
 +
 +      if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      if (!ice_vc_isvalid_vsi_id(vf, strip_msg->vport_id)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      vsi = ice_get_vf_vsi(vf);
 +      if (!vsi) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      stripping_support = &vf->vlan_v2_caps.offloads.stripping_support;
 +      if (!ice_vc_valid_vlan_setting_msg(stripping_support, strip_msg)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      ethertype_setting = strip_msg->outer_ethertype_setting;
 +      if (ethertype_setting) {
 +              if (vsi->outer_vlan_ops.dis_stripping(vsi)) {
 +                      v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +                      goto out;
 +              } else {
 +                      enum ice_l2tsel l2tsel =
 +                              ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG1;
 +
 +                      /* PF tells the VF that the outer VLAN tag is always
 +                       * extracted to VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2 and
 +                       * inner is always extracted to
 +                       * VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1. This is needed to
 +                       * support inner stripping while outer stripping is
 +                       * disabled so that the first and only tag is extracted
 +                       * in L2TAG1.
 +                       */
 +                      ice_vsi_update_l2tsel(vsi, l2tsel);
 +              }
 +      }
 +
 +      ethertype_setting = strip_msg->inner_ethertype_setting;
 +      if (ethertype_setting && vsi->inner_vlan_ops.dis_stripping(vsi)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +out:
 +      return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2, v_ret, NULL, 0);
 +}
 +
 +/**
 + * ice_vc_ena_vlan_insertion_v2_msg
 + * @vf: VF the message was received from
 + * @msg: message received from the VF
 + *
 + * virthcnl handler for VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2
 + */
 +static int ice_vc_ena_vlan_insertion_v2_msg(struct ice_vf *vf, u8 *msg)
 +{
 +      enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
 +      struct virtchnl_vlan_supported_caps *insertion_support;
 +      struct virtchnl_vlan_setting *insertion_msg =
 +              (struct virtchnl_vlan_setting *)msg;
 +      u32 ethertype_setting;
 +      struct ice_vsi *vsi;
 +
 +      if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      if (!ice_vc_isvalid_vsi_id(vf, insertion_msg->vport_id)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      vsi = ice_get_vf_vsi(vf);
 +      if (!vsi) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      insertion_support = &vf->vlan_v2_caps.offloads.insertion_support;
 +      if (!ice_vc_valid_vlan_setting_msg(insertion_support, insertion_msg)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      ethertype_setting = insertion_msg->outer_ethertype_setting;
 +      if (ethertype_setting &&
 +          ice_vc_ena_vlan_offload(vsi, vsi->outer_vlan_ops.ena_insertion,
 +                                  ethertype_setting)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      ethertype_setting = insertion_msg->inner_ethertype_setting;
 +      if (ethertype_setting &&
 +          ice_vc_ena_vlan_offload(vsi, vsi->inner_vlan_ops.ena_insertion,
 +                                  ethertype_setting)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +out:
 +      return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2, v_ret, NULL, 0);
 +}
 +
 +/**
 + * ice_vc_dis_vlan_insertion_v2_msg
 + * @vf: VF the message was received from
 + * @msg: message received from the VF
 + *
 + * virthcnl handler for VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2
 + */
 +static int ice_vc_dis_vlan_insertion_v2_msg(struct ice_vf *vf, u8 *msg)
 +{
 +      enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
 +      struct virtchnl_vlan_supported_caps *insertion_support;
 +      struct virtchnl_vlan_setting *insertion_msg =
 +              (struct virtchnl_vlan_setting *)msg;
 +      u32 ethertype_setting;
 +      struct ice_vsi *vsi;
 +
 +      if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      if (!ice_vc_isvalid_vsi_id(vf, insertion_msg->vport_id)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      vsi = ice_get_vf_vsi(vf);
 +      if (!vsi) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      insertion_support = &vf->vlan_v2_caps.offloads.insertion_support;
 +      if (!ice_vc_valid_vlan_setting_msg(insertion_support, insertion_msg)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      ethertype_setting = insertion_msg->outer_ethertype_setting;
 +      if (ethertype_setting && vsi->outer_vlan_ops.dis_insertion(vsi)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +      ethertype_setting = insertion_msg->inner_ethertype_setting;
 +      if (ethertype_setting && vsi->inner_vlan_ops.dis_insertion(vsi)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto out;
 +      }
 +
 +out:
 +      return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2, v_ret, NULL, 0);
 +}
 +
 +static struct ice_vc_vf_ops ice_vc_vf_dflt_ops = {
 +      .get_ver_msg = ice_vc_get_ver_msg,
 +      .get_vf_res_msg = ice_vc_get_vf_res_msg,
 +      .reset_vf = ice_vc_reset_vf_msg,
 +      .add_mac_addr_msg = ice_vc_add_mac_addr_msg,
 +      .del_mac_addr_msg = ice_vc_del_mac_addr_msg,
 +      .cfg_qs_msg = ice_vc_cfg_qs_msg,
 +      .ena_qs_msg = ice_vc_ena_qs_msg,
 +      .dis_qs_msg = ice_vc_dis_qs_msg,
 +      .request_qs_msg = ice_vc_request_qs_msg,
 +      .cfg_irq_map_msg = ice_vc_cfg_irq_map_msg,
 +      .config_rss_key = ice_vc_config_rss_key,
 +      .config_rss_lut = ice_vc_config_rss_lut,
 +      .get_stats_msg = ice_vc_get_stats_msg,
 +      .cfg_promiscuous_mode_msg = ice_vc_cfg_promiscuous_mode_msg,
 +      .add_vlan_msg = ice_vc_add_vlan_msg,
 +      .remove_vlan_msg = ice_vc_remove_vlan_msg,
 +      .ena_vlan_stripping = ice_vc_ena_vlan_stripping,
 +      .dis_vlan_stripping = ice_vc_dis_vlan_stripping,
 +      .handle_rss_cfg_msg = ice_vc_handle_rss_cfg,
 +      .add_fdir_fltr_msg = ice_vc_add_fdir_fltr,
 +      .del_fdir_fltr_msg = ice_vc_del_fdir_fltr,
 +      .get_offload_vlan_v2_caps = ice_vc_get_offload_vlan_v2_caps,
 +      .add_vlan_v2_msg = ice_vc_add_vlan_v2_msg,
 +      .remove_vlan_v2_msg = ice_vc_remove_vlan_v2_msg,
 +      .ena_vlan_stripping_v2_msg = ice_vc_ena_vlan_stripping_v2_msg,
 +      .dis_vlan_stripping_v2_msg = ice_vc_dis_vlan_stripping_v2_msg,
 +      .ena_vlan_insertion_v2_msg = ice_vc_ena_vlan_insertion_v2_msg,
 +      .dis_vlan_insertion_v2_msg = ice_vc_dis_vlan_insertion_v2_msg,
 +};
 +
 +void ice_vc_set_dflt_vf_ops(struct ice_vc_vf_ops *ops)
 +{
 +      *ops = ice_vc_vf_dflt_ops;
 +}
 +
 +/**
 + * ice_vc_repr_add_mac
 + * @vf: pointer to VF
 + * @msg: virtchannel message
 + *
 + * When port representors are created, we do not add MAC rule
 + * to firmware, we store it so that PF could report same
 + * MAC as VF.
 + */
 +static int ice_vc_repr_add_mac(struct ice_vf *vf, u8 *msg)
 +{
 +      enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
 +      struct virtchnl_ether_addr_list *al =
 +          (struct virtchnl_ether_addr_list *)msg;
 +      struct ice_vsi *vsi;
 +      struct ice_pf *pf;
 +      int i;
 +
 +      if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) ||
 +          !ice_vc_isvalid_vsi_id(vf, al->vsi_id)) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto handle_mac_exit;
 +      }
 +
 +      pf = vf->pf;
 +
 +      vsi = ice_get_vf_vsi(vf);
 +      if (!vsi) {
 +              v_ret = VIRTCHNL_STATUS_ERR_PARAM;
 +              goto handle_mac_exit;
 +      }
 +
 +      for (i = 0; i < al->num_elements; i++) {
 +              u8 *mac_addr = al->list[i].addr;
 +              int result;
 +
 +              if (!is_unicast_ether_addr(mac_addr) ||
 +                  ether_addr_equal(mac_addr, vf->hw_lan_addr.addr))
 +                      continue;
 +
 +              if (vf->pf_set_mac) {
 +                      dev_err(ice_pf_to_dev(pf), "VF attempting to override administratively set MAC address\n");
 +                      v_ret = VIRTCHNL_STATUS_ERR_NOT_SUPPORTED;
 +                      goto handle_mac_exit;
 +              }
 +
 +              result = ice_eswitch_add_vf_mac_rule(pf, vf, mac_addr);
 +              if (result) {
 +                      dev_err(ice_pf_to_dev(pf), "Failed to add MAC %pM for VF %d\n, error %d\n",
 +                              mac_addr, vf->vf_id, result);
 +                      goto handle_mac_exit;
 +              }
 +
 +              ice_vfhw_mac_add(vf, &al->list[i]);
 +              vf->num_mac++;
 +              break;
 +      }
 +
 +handle_mac_exit:
 +      return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_ETH_ADDR,
 +                                   v_ret, NULL, 0);
 +}
 +
 +/**
 + * ice_vc_repr_del_mac - response with success for deleting MAC
 + * @vf: pointer to VF
 + * @msg: virtchannel message
 + *
 + * Respond with success to not break normal VF flow.
 + * For legacy VF driver try to update cached MAC address.
 + */
 +static int
 +ice_vc_repr_del_mac(struct ice_vf __always_unused *vf, u8 __always_unused *msg)
 +{
 +      struct virtchnl_ether_addr_list *al =
 +              (struct virtchnl_ether_addr_list *)msg;
 +
 +      ice_update_legacy_cached_mac(vf, &al->list[0]);
 +
 +      return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DEL_ETH_ADDR,
 +                                   VIRTCHNL_STATUS_SUCCESS, NULL, 0);
 +}
 +
 +static int ice_vc_repr_add_vlan(struct ice_vf *vf, u8 __always_unused *msg)
 +{
        dev_dbg(ice_pf_to_dev(vf->pf),
                "Can't add VLAN in switchdev mode for VF %d\n", vf->vf_id);
        return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_VLAN,
@@@ -5887,13 -4620,12 +5869,13 @@@ void ice_vc_process_vf_msg(struct ice_p
        int err = 0;
  
        dev = ice_pf_to_dev(pf);
 -      if (ice_validate_vf_id(pf, vf_id)) {
 -              err = -EINVAL;
 -              goto error_handler;
 -      }
  
 -      vf = &pf->vf[vf_id];
 +      vf = ice_get_vf_by_id(pf, vf_id);
 +      if (!vf) {
 +              dev_err(dev, "Unable to locate VF for message from VF ID %d, opcode %d, len %d\n",
 +                      vf_id, v_opcode, msglen);
 +              return;
 +      }
  
        /* Check if VF is disabled. */
        if (test_bit(ICE_VF_STATE_DIS, vf->vf_states)) {
                ice_vc_send_msg_to_vf(vf, v_opcode,
                                      VIRTCHNL_STATUS_ERR_NOT_SUPPORTED, NULL,
                                      0);
 +              ice_put_vf(vf);
                return;
        }
  
@@@ -5926,7 -4657,6 +5908,7 @@@ error_handler
                                      NULL, 0);
                dev_err(dev, "Invalid message from VF %d, opcode %d, len %d, error %d\n",
                        vf_id, v_opcode, msglen, err);
 +              ice_put_vf(vf);
                return;
        }
  
        if (!mutex_trylock(&vf->cfg_lock)) {
                dev_info(dev, "VF %u is being configured in another context that will trigger a VFR, so there is no need to handle this message\n",
                         vf->vf_id);
 +              ice_put_vf(vf);
                return;
        }
  
        case VIRTCHNL_OP_GET_VF_RESOURCES:
                err = ops->get_vf_res_msg(vf, msg);
                if (ice_vf_init_vlan_stripping(vf))
 -                      dev_err(dev, "Failed to initialize VLAN stripping for VF %d\n",
 +                      dev_dbg(dev, "Failed to initialize VLAN stripping for VF %d\n",
                                vf->vf_id);
                ice_vc_notify_vf_link_state(vf);
                break;
        case VIRTCHNL_OP_DEL_RSS_CFG:
                err = ops->handle_rss_cfg_msg(vf, msg, false);
                break;
 +      case VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS:
 +              err = ops->get_offload_vlan_v2_caps(vf);
 +              break;
 +      case VIRTCHNL_OP_ADD_VLAN_V2:
 +              err = ops->add_vlan_v2_msg(vf, msg);
 +              break;
 +      case VIRTCHNL_OP_DEL_VLAN_V2:
 +              err = ops->remove_vlan_v2_msg(vf, msg);
 +              break;
 +      case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2:
 +              err = ops->ena_vlan_stripping_v2_msg(vf, msg);
 +              break;
 +      case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2:
 +              err = ops->dis_vlan_stripping_v2_msg(vf, msg);
 +              break;
 +      case VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2:
 +              err = ops->ena_vlan_insertion_v2_msg(vf, msg);
 +              break;
 +      case VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2:
 +              err = ops->dis_vlan_insertion_v2_msg(vf, msg);
 +              break;
        case VIRTCHNL_OP_UNKNOWN:
        default:
                dev_err(dev, "Unsupported opcode %d from VF %d\n", v_opcode,
        }
  
        mutex_unlock(&vf->cfg_lock);
 +      ice_put_vf(vf);
  }
  
  /**
@@@ -6067,24 -4774,21 +6049,24 @@@ ice_get_vf_cfg(struct net_device *netde
  {
        struct ice_pf *pf = ice_netdev_to_pf(netdev);
        struct ice_vf *vf;
 +      int ret;
  
 -      if (ice_validate_vf_id(pf, vf_id))
 +      vf = ice_get_vf_by_id(pf, vf_id);
 +      if (!vf)
                return -EINVAL;
  
 -      vf = &pf->vf[vf_id];
 -
 -      if (ice_check_vf_init(pf, vf))
 -              return -EBUSY;
 +      ret = ice_check_vf_ready_for_cfg(vf);
 +      if (ret)
 +              goto out_put_vf;
  
        ivi->vf = vf_id;
        ether_addr_copy(ivi->mac, vf->hw_lan_addr.addr);
  
        /* VF configuration for VLAN and applicable QoS */
 -      ivi->vlan = vf->port_vlan_info & VLAN_VID_MASK;
 -      ivi->qos = (vf->port_vlan_info & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
 +      ivi->vlan = ice_vf_get_port_vlan_id(vf);
 +      ivi->qos = ice_vf_get_port_vlan_prio(vf);
 +      if (ice_vf_is_port_vlan_ena(vf))
 +              ivi->vlan_proto = cpu_to_be16(ice_vf_get_port_vlan_tpid(vf));
  
        ivi->trusted = vf->trusted;
        ivi->spoofchk = vf->spoofchk;
                ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE;
        ivi->max_tx_rate = vf->max_tx_rate;
        ivi->min_tx_rate = vf->min_tx_rate;
 -      return 0;
 +
 +out_put_vf:
 +      ice_put_vf(vf);
 +      return ret;
  }
  
  /**
@@@ -6149,31 -4850,28 +6131,31 @@@ int ice_set_vf_mac(struct net_device *n
        struct ice_vf *vf;
        int ret;
  
 -      if (ice_validate_vf_id(pf, vf_id))
 -              return -EINVAL;
 -
        if (is_multicast_ether_addr(mac)) {
                netdev_err(netdev, "%pM not a valid unicast address\n", mac);
                return -EINVAL;
        }
  
 -      vf = &pf->vf[vf_id];
 +      vf = ice_get_vf_by_id(pf, vf_id);
 +      if (!vf)
 +              return -EINVAL;
 +
        /* nothing left to do, unicast MAC already set */
        if (ether_addr_equal(vf->dev_lan_addr.addr, mac) &&
 -          ether_addr_equal(vf->hw_lan_addr.addr, mac))
 -              return 0;
 +          ether_addr_equal(vf->hw_lan_addr.addr, mac)) {
 +              ret = 0;
 +              goto out_put_vf;
 +      }
  
        ret = ice_check_vf_ready_for_cfg(vf);
        if (ret)
 -              return ret;
 +              goto out_put_vf;
  
        if (ice_unicast_mac_exists(pf, mac)) {
                netdev_err(netdev, "Unicast MAC %pM already exists on this PF. Preventing setting VF %u unicast MAC address to %pM\n",
                           mac, vf_id, mac);
 -              return -EINVAL;
 +              ret = -EINVAL;
 +              goto out_put_vf;
        }
  
        mutex_lock(&vf->cfg_lock);
  
        ice_vc_reset_vf(vf);
        mutex_unlock(&vf->cfg_lock);
 -      return 0;
 +
 +out_put_vf:
 +      ice_put_vf(vf);
 +      return ret;
  }
  
  /**
@@@ -6222,19 -4917,17 +6204,19 @@@ int ice_set_vf_trust(struct net_device 
                return -EOPNOTSUPP;
        }
  
 -      if (ice_validate_vf_id(pf, vf_id))
 +      vf = ice_get_vf_by_id(pf, vf_id);
 +      if (!vf)
                return -EINVAL;
  
 -      vf = &pf->vf[vf_id];
        ret = ice_check_vf_ready_for_cfg(vf);
        if (ret)
 -              return ret;
 +              goto out_put_vf;
  
        /* Check if already trusted */
 -      if (trusted == vf->trusted)
 -              return 0;
 +      if (trusted == vf->trusted) {
 +              ret = 0;
 +              goto out_put_vf;
 +      }
  
        mutex_lock(&vf->cfg_lock);
  
  
        mutex_unlock(&vf->cfg_lock);
  
 -      return 0;
 +out_put_vf:
 +      ice_put_vf(vf);
 +      return ret;
  }
  
  /**
@@@ -6264,13 -4955,13 +6246,13 @@@ int ice_set_vf_link_state(struct net_de
        struct ice_vf *vf;
        int ret;
  
 -      if (ice_validate_vf_id(pf, vf_id))
 +      vf = ice_get_vf_by_id(pf, vf_id);
 +      if (!vf)
                return -EINVAL;
  
 -      vf = &pf->vf[vf_id];
        ret = ice_check_vf_ready_for_cfg(vf);
        if (ret)
 -              return ret;
 +              goto out_put_vf;
  
        switch (link_state) {
        case IFLA_VF_LINK_STATE_AUTO:
                vf->link_up = false;
                break;
        default:
 -              return -EINVAL;
 +              ret = -EINVAL;
 +              goto out_put_vf;
        }
  
        ice_vc_notify_vf_link_state(vf);
  
 -      return 0;
 +out_put_vf:
 +      ice_put_vf(vf);
 +      return ret;
  }
  
  /**
   */
  static int ice_calc_all_vfs_min_tx_rate(struct ice_pf *pf)
  {
 -      int rate = 0, i;
 +      struct ice_vf *vf;
 +      unsigned int bkt;
 +      int rate = 0;
  
 -      ice_for_each_vf(pf, i)
 -              rate += pf->vf[i].min_tx_rate;
 +      rcu_read_lock();
 +      ice_for_each_vf_rcu(pf, bkt, vf)
 +              rate += vf->min_tx_rate;
 +      rcu_read_unlock();
  
        return rate;
  }
@@@ -6364,14 -5048,13 +6346,14 @@@ ice_set_vf_bw(struct net_device *netdev
        int ret;
  
        dev = ice_pf_to_dev(pf);
 -      if (ice_validate_vf_id(pf, vf_id))
 +
 +      vf = ice_get_vf_by_id(pf, vf_id);
 +      if (!vf)
                return -EINVAL;
  
 -      vf = &pf->vf[vf_id];
        ret = ice_check_vf_ready_for_cfg(vf);
        if (ret)
 -              return ret;
 +              goto out_put_vf;
  
        vsi = ice_get_vf_vsi(vf);
  
        if (max_tx_rate && min_tx_rate > max_tx_rate) {
                dev_err(dev, "Cannot set min Tx rate %d Mbps greater than max Tx rate %d Mbps\n",
                        min_tx_rate, max_tx_rate);
 -              return -EINVAL;
 +              ret = -EINVAL;
 +              goto out_put_vf;
        }
  
        if (min_tx_rate && ice_is_dcb_active(pf)) {
                dev_err(dev, "DCB on PF is currently enabled. VF min Tx rate limiting not allowed on this PF.\n");
 -              return -EOPNOTSUPP;
 +              ret = -EOPNOTSUPP;
 +              goto out_put_vf;
        }
  
 -      if (ice_min_tx_rate_oversubscribed(vf, min_tx_rate))
 -              return -EINVAL;
 +      if (ice_min_tx_rate_oversubscribed(vf, min_tx_rate)) {
 +              ret = -EINVAL;
 +              goto out_put_vf;
 +      }
  
        if (vf->min_tx_rate != (unsigned int)min_tx_rate) {
                ret = ice_set_min_bw_limit(vsi, (u64)min_tx_rate * 1000);
                if (ret) {
                        dev_err(dev, "Unable to set min-tx-rate for VF %d\n",
                                vf->vf_id);
 -                      return ret;
 +                      goto out_put_vf;
                }
  
                vf->min_tx_rate = min_tx_rate;
                if (ret) {
                        dev_err(dev, "Unable to set max-tx-rate for VF %d\n",
                                vf->vf_id);
 -                      return ret;
 +                      goto out_put_vf;
                }
  
                vf->max_tx_rate = max_tx_rate;
        }
  
 -      return 0;
 +out_put_vf:
 +      ice_put_vf(vf);
 +      return ret;
  }
  
  /**
@@@ -6438,19 -5115,17 +6420,19 @@@ int ice_get_vf_stats(struct net_device 
        struct ice_vf *vf;
        int ret;
  
 -      if (ice_validate_vf_id(pf, vf_id))
 +      vf = ice_get_vf_by_id(pf, vf_id);
 +      if (!vf)
                return -EINVAL;
  
 -      vf = &pf->vf[vf_id];
        ret = ice_check_vf_ready_for_cfg(vf);
        if (ret)
 -              return ret;
 +              goto out_put_vf;
  
        vsi = ice_get_vf_vsi(vf);
 -      if (!vsi)
 -              return -EINVAL;
 +      if (!vsi) {
 +              ret = -EINVAL;
 +              goto out_put_vf;
 +      }
  
        ice_update_eth_stats(vsi);
        stats = &vsi->eth_stats;
        vf_stats->rx_dropped = stats->rx_discards;
        vf_stats->tx_dropped = stats->tx_discards;
  
 -      return 0;
 +out_put_vf:
 +      ice_put_vf(vf);
 +      return ret;
  }
  
  /**
@@@ -6501,21 -5174,21 +6483,21 @@@ void ice_print_vfs_mdd_events(struct ic
  {
        struct device *dev = ice_pf_to_dev(pf);
        struct ice_hw *hw = &pf->hw;
 -      int i;
 +      struct ice_vf *vf;
 +      unsigned int bkt;
  
        /* check that there are pending MDD events to print */
        if (!test_and_clear_bit(ICE_MDD_VF_PRINT_PENDING, pf->state))
                return;
  
        /* VF MDD event logs are rate limited to one second intervals */
 -      if (time_is_after_jiffies(pf->last_printed_mdd_jiffies + HZ * 1))
 +      if (time_is_after_jiffies(pf->vfs.last_printed_mdd_jiffies + HZ * 1))
                return;
  
 -      pf->last_printed_mdd_jiffies = jiffies;
 -
 -      ice_for_each_vf(pf, i) {
 -              struct ice_vf *vf = &pf->vf[i];
 +      pf->vfs.last_printed_mdd_jiffies = jiffies;
  
 +      mutex_lock(&pf->vfs.table_lock);
 +      ice_for_each_vf(pf, bkt, vf) {
                /* only print Rx MDD event message if there are new events */
                if (vf->mdd_rx_events.count != vf->mdd_rx_events.last_printed) {
                        vf->mdd_rx_events.last_printed =
                                                        vf->mdd_tx_events.count;
  
                        dev_info(dev, "%d Tx Malicious Driver Detection events detected on PF %d VF %d MAC %pM.\n",
 -                               vf->mdd_tx_events.count, hw->pf_id, i,
 +                               vf->mdd_tx_events.count, hw->pf_id, vf->vf_id,
                                 vf->dev_lan_addr.addr);
                }
        }
 +      mutex_unlock(&pf->vfs.table_lock);
  }
  
  /**
@@@ -6585,12 -5257,13 +6567,12 @@@ ice_is_malicious_vf(struct ice_pf *pf, 
        struct ice_vf *vf;
        int status;
  
 -      if (ice_validate_vf_id(pf, vf_id))
 +      vf = ice_get_vf_by_id(pf, vf_id);
 +      if (!vf)
                return false;
  
 -      vf = &pf->vf[vf_id];
 -      /* Check if VF is disabled. */
        if (test_bit(ICE_VF_STATE_DIS, vf->vf_states))
 -              return false;
 +              goto out_put_vf;
  
        mbxdata.num_msg_proc = num_msg_proc;
        mbxdata.num_pending_arq = num_msg_pending;
        /* check to see if we have a malicious VF */
        status = ice_mbx_vf_state_handler(&pf->hw, &mbxdata, vf_id, &malvf);
        if (status)
 -              return false;
 +              goto out_put_vf;
  
        if (malvf) {
                bool report_vf = false;
                /* if the VF is malicious and we haven't let the user
                 * know about it, then let them know now
                 */
 -              status = ice_mbx_report_malvf(&pf->hw, pf->malvfs,
 +              status = ice_mbx_report_malvf(&pf->hw, pf->vfs.malvfs,
                                              ICE_MAX_VF_COUNT, vf_id,
                                              &report_vf);
                if (status)
                                         &vf->dev_lan_addr.addr[0],
                                         pf_vsi->netdev->dev_addr);
                }
 -
 -              return true;
        }
  
 -      /* if there was an error in detection or the VF is not malicious then
 -       * return false
 -       */
 -      return false;
 +out_put_vf:
 +      ice_put_vf(vf);
 +      return malvf;
  }
@@@ -5,7 -5,6 +5,7 @@@
  #define _ICE_VIRTCHNL_PF_H_
  #include "ice.h"
  #include "ice_virtchnl_fdir.h"
 +#include "ice_vsi_vlan_ops.h"
  
  /* Restrict number of MAC Addr and VLAN that non-trusted VF can programmed */
  #define ICE_MAX_VLAN_PER_VF           8
@@@ -15,7 -14,6 +15,6 @@@
  #define ICE_MAX_MACADDR_PER_VF                18
  
  /* Malicious Driver Detection */
- #define ICE_DFLT_NUM_INVAL_MSGS_ALLOWED               10
  #define ICE_MDD_EVENTS_THRESHOLD              30
  
  /* Static VF transaction/status register def */
  #define ICE_MAX_VF_RESET_TRIES                40
  #define ICE_MAX_VF_RESET_SLEEP_MS     20
  
 -#define ice_for_each_vf(pf, i) \
 -      for ((i) = 0; (i) < (pf)->num_alloc_vfs; (i)++)
 +/* VF Hash Table access functions
 + *
 + * These functions provide abstraction for interacting with the VF hash table.
 + * In general, direct access to the hash table should be avoided outside of
 + * these functions where possible.
 + *
 + * The VF entries in the hash table are protected by reference counting to
 + * track lifetime of accesses from the table. The ice_get_vf_by_id() function
 + * obtains a reference to the VF structure which must be dropped by using
 + * ice_put_vf().
 + */
 +
 +/**
 + * ice_for_each_vf - Iterate over each VF entry
 + * @pf: pointer to the PF private structure
 + * @bkt: bucket index used for iteration
 + * @vf: pointer to the VF entry currently being processed in the loop.
 + *
 + * The bkt variable is an unsigned integer iterator used to traverse the VF
 + * entries. It is *not* guaranteed to be the VF's vf_id. Do not assume it is.
 + * Use vf->vf_id to get the id number if needed.
 + *
 + * The caller is expected to be under the table_lock mutex for the entire
 + * loop. Use this iterator if your loop is long or if it might sleep.
 + */
 +#define ice_for_each_vf(pf, bkt, vf) \
 +      hash_for_each((pf)->vfs.table, (bkt), (vf), entry)
 +
 +/**
 + * ice_for_each_vf_rcu - Iterate over each VF entry protected by RCU
 + * @pf: pointer to the PF private structure
 + * @bkt: bucket index used for iteration
 + * @vf: pointer to the VF entry currently being processed in the loop.
 + *
 + * The bkt variable is an unsigned integer iterator used to traverse the VF
 + * entries. It is *not* guaranteed to be the VF's vf_id. Do not assume it is.
 + * Use vf->vf_id to get the id number if needed.
 + *
 + * The caller is expected to be under rcu_read_lock() for the entire loop.
 + * Only use this iterator if your loop is short and you can guarantee it does
 + * not sleep.
 + */
 +#define ice_for_each_vf_rcu(pf, bkt, vf) \
 +      hash_for_each_rcu((pf)->vfs.table, (bkt), (vf), entry)
  
  /* Specific VF states */
  enum ice_vf_states {
@@@ -137,31 -93,10 +136,31 @@@ struct ice_vc_vf_ops 
        int (*handle_rss_cfg_msg)(struct ice_vf *vf, u8 *msg, bool add);
        int (*add_fdir_fltr_msg)(struct ice_vf *vf, u8 *msg);
        int (*del_fdir_fltr_msg)(struct ice_vf *vf, u8 *msg);
 +      int (*get_offload_vlan_v2_caps)(struct ice_vf *vf);
 +      int (*add_vlan_v2_msg)(struct ice_vf *vf, u8 *msg);
 +      int (*remove_vlan_v2_msg)(struct ice_vf *vf, u8 *msg);
 +      int (*ena_vlan_stripping_v2_msg)(struct ice_vf *vf, u8 *msg);
 +      int (*dis_vlan_stripping_v2_msg)(struct ice_vf *vf, u8 *msg);
 +      int (*ena_vlan_insertion_v2_msg)(struct ice_vf *vf, u8 *msg);
 +      int (*dis_vlan_insertion_v2_msg)(struct ice_vf *vf, u8 *msg);
 +};
 +
 +/* Virtchnl/SR-IOV config info */
 +struct ice_vfs {
 +      DECLARE_HASHTABLE(table, 8);    /* table of VF entries */
 +      struct mutex table_lock;        /* Lock for protecting the hash table */
 +      u16 num_supported;              /* max supported VFs on this PF */
 +      u16 num_qps_per;                /* number of queue pairs per VF */
 +      u16 num_msix_per;               /* number of MSI-X vectors per VF */
 +      unsigned long last_printed_mdd_jiffies; /* MDD message rate limit */
 +      DECLARE_BITMAP(malvfs, ICE_MAX_VF_COUNT); /* malicious VF indicator */
  };
  
  /* VF information structure */
  struct ice_vf {
 +      struct hlist_node entry;
 +      struct rcu_head rcu;
 +      struct kref refcnt;
        struct ice_pf *pf;
  
        /* Used during virtchnl message handling and NDO ops against the VF
        struct ice_time_mac legacy_last_added_umac;
        DECLARE_BITMAP(txq_ena, ICE_MAX_RSS_QS_PER_VF);
        DECLARE_BITMAP(rxq_ena, ICE_MAX_RSS_QS_PER_VF);
 -      u16 port_vlan_info;             /* Port VLAN ID and QoS */
 +      struct ice_vlan port_vlan_info; /* Port VLAN ID, QoS, and TPID */
 +      struct virtchnl_vlan_caps vlan_v2_caps;
        u8 pf_set_mac:1;                /* VF MAC address set by VMM admin */
        u8 trusted:1;
        u8 spoofchk:1;
        unsigned int max_tx_rate;       /* Maximum Tx bandwidth limit in Mbps */
        DECLARE_BITMAP(vf_states, ICE_VF_STATES_NBITS); /* VF runtime states */
  
-       u64 num_inval_msgs;             /* number of continuous invalid msgs */
-       u64 num_valid_msgs;             /* number of valid msgs detected */
        unsigned long vf_caps;          /* VF's adv. capabilities */
        u8 num_req_qs;                  /* num of queue pairs requested by VF */
        u16 num_mac;
  };
  
  #ifdef CONFIG_PCI_IOV
 +struct ice_vf *ice_get_vf_by_id(struct ice_pf *pf, u16 vf_id);
 +void ice_put_vf(struct ice_vf *vf);
 +bool ice_has_vfs(struct ice_pf *pf);
 +u16 ice_get_num_vfs(struct ice_pf *pf);
  struct ice_vsi *ice_get_vf_vsi(struct ice_vf *vf);
  void ice_process_vflr_event(struct ice_pf *pf);
  int ice_sriov_configure(struct pci_dev *pdev, int num_vfs);
@@@ -279,27 -207,7 +276,27 @@@ in
  ice_vc_send_msg_to_vf(struct ice_vf *vf, u32 v_opcode,
                      enum virtchnl_status_code v_retval, u8 *msg, u16 msglen);
  bool ice_vc_isvalid_vsi_id(struct ice_vf *vf, u16 vsi_id);
 +bool ice_vf_is_port_vlan_ena(struct ice_vf *vf);
  #else /* CONFIG_PCI_IOV */
 +static inline struct ice_vf *ice_get_vf_by_id(struct ice_pf *pf, u16 vf_id)
 +{
 +      return NULL;
 +}
 +
 +static inline void ice_put_vf(struct ice_vf *vf)
 +{
 +}
 +
 +static inline bool ice_has_vfs(struct ice_pf *pf)
 +{
 +      return false;
 +}
 +
 +static inline u16 ice_get_num_vfs(struct ice_pf *pf)
 +{
 +      return 0;
 +}
 +
  static inline void ice_process_vflr_event(struct ice_pf *pf) { }
  static inline void ice_free_vfs(struct ice_pf *pf) { }
  static inline
@@@ -431,10 -339,5 +428,10 @@@ static inline bool ice_is_any_vf_in_pro
  {
        return false;
  }
 +
 +static inline bool ice_vf_is_port_vlan_ena(struct ice_vf __always_unused *vf)
 +{
 +      return false;
 +}
  #endif /* CONFIG_PCI_IOV */
  #endif /* _ICE_VIRTCHNL_PF_H_ */
  #define PRESTERA_MAC_ADDR_NUM_MAX     255
  
  static struct workqueue_struct *prestera_wq;
 +static struct workqueue_struct *prestera_owq;
 +
 +void prestera_queue_work(struct work_struct *work)
 +{
 +      queue_work(prestera_owq, work);
 +}
  
  int prestera_port_pvid_set(struct prestera_port *port, u16 vid)
  {
@@@ -560,6 -554,7 +560,7 @@@ static int prestera_switch_set_base_mac
                dev_info(prestera_dev(sw), "using random base mac address\n");
        }
        of_node_put(base_mac_np);
+       of_node_put(np);
  
        return prestera_hw_switch_mac_set(sw, sw->base_mac);
  }
@@@ -1030,17 -1025,12 +1031,17 @@@ static int __init prestera_module_init(
        if (!prestera_wq)
                return -ENOMEM;
  
 +      prestera_owq = alloc_ordered_workqueue("prestera_ordered", 0);
 +      if (!prestera_owq)
 +              return -ENOMEM;
 +
        return 0;
  }
  
  static void __exit prestera_module_exit(void)
  {
        destroy_workqueue(prestera_wq);
 +      destroy_workqueue(prestera_owq);
  }
  
  module_init(prestera_module_init);
@@@ -131,11 -131,8 +131,8 @@@ static int cmd_alloc_index(struct mlx5_
  
  static void cmd_free_index(struct mlx5_cmd *cmd, int idx)
  {
-       unsigned long flags;
-       spin_lock_irqsave(&cmd->alloc_lock, flags);
+       lockdep_assert_held(&cmd->alloc_lock);
        set_bit(idx, &cmd->bitmask);
-       spin_unlock_irqrestore(&cmd->alloc_lock, flags);
  }
  
  static void cmd_ent_get(struct mlx5_cmd_work_ent *ent)
  
  static void cmd_ent_put(struct mlx5_cmd_work_ent *ent)
  {
+       struct mlx5_cmd *cmd = ent->cmd;
+       unsigned long flags;
+       spin_lock_irqsave(&cmd->alloc_lock, flags);
        if (!refcount_dec_and_test(&ent->refcnt))
-               return;
+               goto out;
  
        if (ent->idx >= 0) {
-               struct mlx5_cmd *cmd = ent->cmd;
                cmd_free_index(cmd, ent->idx);
                up(ent->page_queue ? &cmd->pages_sem : &cmd->sem);
        }
  
        cmd_free_ent(ent);
+ out:
+       spin_unlock_irqrestore(&cmd->alloc_lock, flags);
  }
  
  static struct mlx5_cmd_layout *get_inst(struct mlx5_cmd *cmd, int idx)
@@@ -190,10 -191,10 +191,10 @@@ static int verify_block_sig(struct mlx5
        int xor_len = sizeof(*block) - sizeof(block->data) - 1;
  
        if (xor8_buf(block, rsvd0_off, xor_len) != 0xff)
 -              return -EINVAL;
 +              return -EHWPOISON;
  
        if (xor8_buf(block, 0, sizeof(*block)) != 0xff)
 -              return -EINVAL;
 +              return -EHWPOISON;
  
        return 0;
  }
@@@ -259,12 -260,12 +260,12 @@@ static int verify_signature(struct mlx5
  
        sig = xor8_buf(ent->lay, 0, sizeof(*ent->lay));
        if (sig != 0xff)
 -              return -EINVAL;
 +              return -EHWPOISON;
  
        for (i = 0; i < n && next; i++) {
                err = verify_block_sig(next->buf);
                if (err)
 -                      return err;
 +                      return -EHWPOISON;
  
                next = next->next;
        }
@@@ -479,7 -480,7 +480,7 @@@ static int mlx5_internal_err_ret_value(
        case MLX5_CMD_OP_ALLOC_SF:
                *status = MLX5_DRIVER_STATUS_ABORTED;
                *synd = MLX5_DRIVER_SYND;
 -              return -EIO;
 +              return -ENOLINK;
        default:
                mlx5_core_err(dev, "Unknown FW command (%d)\n", op);
                return -EINVAL;
@@@ -760,72 -761,44 +761,72 @@@ struct mlx5_ifc_mbox_in_bits 
        u8         reserved_at_40[0x40];
  };
  
 -void mlx5_cmd_mbox_status(void *out, u8 *status, u32 *syndrome)
 +void mlx5_cmd_out_err(struct mlx5_core_dev *dev, u16 opcode, u16 op_mod, void *out)
  {
 -      *status = MLX5_GET(mbox_out, out, status);
 -      *syndrome = MLX5_GET(mbox_out, out, syndrome);
 +      u32 syndrome = MLX5_GET(mbox_out, out, syndrome);
 +      u8 status = MLX5_GET(mbox_out, out, status);
 +
 +      mlx5_core_err_rl(dev,
 +                       "%s(0x%x) op_mod(0x%x) failed, status %s(0x%x), syndrome (0x%x), err(%d)\n",
 +                       mlx5_command_str(opcode), opcode, op_mod,
 +                       cmd_status_str(status), status, syndrome, cmd_status_to_err(status));
  }
 +EXPORT_SYMBOL(mlx5_cmd_out_err);
  
 -static int mlx5_cmd_check(struct mlx5_core_dev *dev, void *in, void *out)
 +static void cmd_status_print(struct mlx5_core_dev *dev, void *in, void *out)
  {
 +      u16 opcode, op_mod;
        u32 syndrome;
        u8  status;
 -      u16 opcode;
 -      u16 op_mod;
        u16 uid;
 +      int err;
  
 -      mlx5_cmd_mbox_status(out, &status, &syndrome);
 -      if (!status)
 -              return 0;
 +      syndrome = MLX5_GET(mbox_out, out, syndrome);
 +      status = MLX5_GET(mbox_out, out, status);
  
        opcode = MLX5_GET(mbox_in, in, opcode);
        op_mod = MLX5_GET(mbox_in, in, op_mod);
        uid    = MLX5_GET(mbox_in, in, uid);
  
 +      err = cmd_status_to_err(status);
 +
        if (!uid && opcode != MLX5_CMD_OP_DESTROY_MKEY)
 -              mlx5_core_err_rl(dev,
 -                      "%s(0x%x) op_mod(0x%x) failed, status %s(0x%x), syndrome (0x%x)\n",
 -                      mlx5_command_str(opcode), opcode, op_mod,
 -                      cmd_status_str(status), status, syndrome);
 +              mlx5_cmd_out_err(dev, opcode, op_mod, out);
        else
                mlx5_core_dbg(dev,
 -                    "%s(0x%x) op_mod(0x%x) failed, status %s(0x%x), syndrome (0x%x)\n",
 -                    mlx5_command_str(opcode),
 -                    opcode, op_mod,
 -                    cmd_status_str(status),
 -                    status,
 -                    syndrome);
 +                      "%s(0x%x) op_mod(0x%x) uid(%d) failed, status %s(0x%x), syndrome (0x%x), err(%d)\n",
 +                      mlx5_command_str(opcode), opcode, op_mod, uid,
 +                      cmd_status_str(status), status, syndrome, err);
 +}
  
 -      return cmd_status_to_err(status);
 +int mlx5_cmd_check(struct mlx5_core_dev *dev, int err, void *in, void *out)
 +{
 +      /* aborted due to PCI error or via reset flow mlx5_cmd_trigger_completions() */
 +      if (err == -ENXIO) {
 +              u16 opcode = MLX5_GET(mbox_in, in, opcode);
 +              u32 syndrome;
 +              u8 status;
 +
 +              /* PCI Error, emulate command return status, for smooth reset */
 +              err = mlx5_internal_err_ret_value(dev, opcode, &syndrome, &status);
 +              MLX5_SET(mbox_out, out, status, status);
 +              MLX5_SET(mbox_out, out, syndrome, syndrome);
 +              if (!err)
 +                      return 0;
 +      }
 +
 +      /* driver or FW delivery error */
 +      if (err != -EREMOTEIO && err)
 +              return err;
 +
 +      /* check outbox status */
 +      err = cmd_status_to_err(MLX5_GET(mbox_out, out, status));
 +      if (err)
 +              cmd_status_print(dev, in, out);
 +
 +      return err;
  }
 +EXPORT_SYMBOL(mlx5_cmd_check);
  
  static void dump_command(struct mlx5_core_dev *dev,
                         struct mlx5_cmd_work_ent *ent, int input)
@@@ -1008,7 -981,13 +1009,7 @@@ static void cmd_work_handler(struct wor
  
        /* Skip sending command to fw if internal error */
        if (mlx5_cmd_is_down(dev) || !opcode_allowed(&dev->cmd, ent->op)) {
 -              u8 status = 0;
 -              u32 drv_synd;
 -
 -              ent->ret = mlx5_internal_err_ret_value(dev, msg_to_opcode(ent->in), &drv_synd, &status);
 -              MLX5_SET(mbox_out, ent->out, status, status);
 -              MLX5_SET(mbox_out, ent->out, syndrome, drv_synd);
 -
 +              ent->ret = -ENXIO;
                mlx5_cmd_comp_handler(dev, 1ULL << ent->idx, true);
                return;
        }
        }
  }
  
 +static int deliv_status_to_err(u8 status)
 +{
 +      switch (status) {
 +      case MLX5_CMD_DELIVERY_STAT_OK:
 +      case MLX5_DRIVER_STATUS_ABORTED:
 +              return 0;
 +      case MLX5_CMD_DELIVERY_STAT_SIGNAT_ERR:
 +      case MLX5_CMD_DELIVERY_STAT_TOK_ERR:
 +              return -EBADR;
 +      case MLX5_CMD_DELIVERY_STAT_BAD_BLK_NUM_ERR:
 +      case MLX5_CMD_DELIVERY_STAT_OUT_PTR_ALIGN_ERR:
 +      case MLX5_CMD_DELIVERY_STAT_IN_PTR_ALIGN_ERR:
 +              return -EFAULT; /* Bad address */
 +      case MLX5_CMD_DELIVERY_STAT_IN_LENGTH_ERR:
 +      case MLX5_CMD_DELIVERY_STAT_OUT_LENGTH_ERR:
 +      case MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR:
 +      case MLX5_CMD_DELIVERY_STAT_RES_FLD_NOT_CLR_ERR:
 +              return -ENOMSG;
 +      case MLX5_CMD_DELIVERY_STAT_FW_ERR:
 +              return -EIO;
 +      default:
 +              return -EINVAL;
 +      }
 +}
 +
  static const char *deliv_status_to_str(u8 status)
  {
        switch (status) {
@@@ -1148,27 -1102,16 +1149,27 @@@ out_err
  /*  Notes:
   *    1. Callback functions may not sleep
   *    2. page queue commands do not support asynchrous completion
 + *
 + * return value in case (!callback):
 + *    ret < 0 : Command execution couldn't be submitted by driver
 + *    ret > 0 : Command execution couldn't be performed by firmware
 + *    ret == 0: Command was executed by FW, Caller must check FW outbox status.
 + *
 + * return value in case (callback):
 + *    ret < 0 : Command execution couldn't be submitted by driver
 + *    ret == 0: Command will be submitted to FW for execution
 + *              and the callback will be called for further status updates
   */
  static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
                           struct mlx5_cmd_msg *out, void *uout, int uout_size,
                           mlx5_cmd_cbk_t callback,
 -                         void *context, int page_queue, u8 *status,
 +                         void *context, int page_queue,
                           u8 token, bool force_polling)
  {
        struct mlx5_cmd *cmd = &dev->cmd;
        struct mlx5_cmd_work_ent *ent;
        struct mlx5_cmd_stats *stats;
 +      u8 status = 0;
        int err = 0;
        s64 ds;
        u16 op;
                cmd_work_handler(&ent->work);
        } else if (!queue_work(cmd->wq, &ent->work)) {
                mlx5_core_warn(dev, "failed to queue work\n");
 -              err = -ENOMEM;
 +              err = -EALREADY;
                goto out_free;
        }
  
        if (callback)
 -              goto out; /* mlx5_cmd_comp_handler() will put(ent) */
 +              return 0; /* mlx5_cmd_comp_handler() will put(ent) */
  
        err = wait_func(dev, ent);
        if (err == -ETIMEDOUT || err == -ECANCELED)
        mlx5_core_dbg_mask(dev, 1 << MLX5_CMD_TIME,
                           "fw exec time for %s is %lld nsec\n",
                           mlx5_command_str(op), ds);
 -      *status = ent->status;
  
  out_free:
 +      status = ent->status;
        cmd_ent_put(ent);
 -out:
 -      return err;
 +      return err ? : status;
  }
  
  static ssize_t dbg_write(struct file *filp, const char __user *buf,
@@@ -1543,7 -1487,7 +1544,7 @@@ static void create_debugfs_files(struc
  {
        struct mlx5_cmd_debug *dbg = &dev->cmd.dbg;
  
 -      dbg->dbg_root = debugfs_create_dir("cmd", dev->priv.dbg_root);
 +      dbg->dbg_root = debugfs_create_dir("cmd", mlx5_debugfs_get_dev_root(dev));
  
        debugfs_create_file("in", 0400, dbg->dbg_root, dev, &dfops);
        debugfs_create_file("out", 0200, dbg->dbg_root, dev, &dfops);
@@@ -1669,15 -1613,15 +1670,15 @@@ static void mlx5_cmd_comp_handler(struc
                        ent->ts2 = ktime_get_ns();
                        memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out));
                        dump_command(dev, ent, 0);
 -                      if (!ent->ret) {
 +
 +                      if (vec & MLX5_TRIGGERED_CMD_COMP)
 +                              ent->ret = -ENXIO;
 +
 +                      if (!ent->ret) { /* Command completed by FW */
                                if (!cmd->checksum_disabled)
                                        ent->ret = verify_signature(ent);
 -                              else
 -                                      ent->ret = 0;
 -                              if (vec & MLX5_TRIGGERED_CMD_COMP)
 -                                      ent->status = MLX5_DRIVER_STATUS_ABORTED;
 -                              else
 -                                      ent->status = ent->lay->status_own >> 1;
 +
 +                              ent->status = ent->lay->status_own >> 1;
  
                                mlx5_core_dbg(dev, "command completed. ret 0x%x, delivery status %s(0x%x)\n",
                                              ent->ret, deliv_status_to_str(ent->status), ent->status);
  
                                callback = ent->callback;
                                context = ent->context;
 -                              err = ent->ret;
 -                              if (!err) {
 +                              err = ent->ret ? : ent->status;
 +                              if (err > 0) /* Failed in FW, command didn't execute */
 +                                      err = deliv_status_to_err(err);
 +
 +                              if (!err)
                                        err = mlx5_copy_from_msg(ent->uout,
                                                                 ent->out,
                                                                 ent->uout_size);
  
 -                                      err = err ? err : mlx5_cmd_check(dev,
 -                                                                      ent->in->first.data,
 -                                                                      ent->uout);
 -                              }
 -
                                mlx5_free_cmd_msg(dev, ent->out);
                                free_msg(dev, ent->in);
  
 -                              err = err ? err : ent->status;
                                /* final consumer is done, release ent */
                                cmd_ent_put(ent);
                                callback(err, context);
@@@ -1773,6 -1720,31 +1774,6 @@@ void mlx5_cmd_flush(struct mlx5_core_de
                up(&cmd->sem);
  }
  
 -static int status_to_err(u8 status)
 -{
 -      switch (status) {
 -      case MLX5_CMD_DELIVERY_STAT_OK:
 -      case MLX5_DRIVER_STATUS_ABORTED:
 -              return 0;
 -      case MLX5_CMD_DELIVERY_STAT_SIGNAT_ERR:
 -      case MLX5_CMD_DELIVERY_STAT_TOK_ERR:
 -              return -EBADR;
 -      case MLX5_CMD_DELIVERY_STAT_BAD_BLK_NUM_ERR:
 -      case MLX5_CMD_DELIVERY_STAT_OUT_PTR_ALIGN_ERR:
 -      case MLX5_CMD_DELIVERY_STAT_IN_PTR_ALIGN_ERR:
 -              return -EFAULT; /* Bad address */
 -      case MLX5_CMD_DELIVERY_STAT_IN_LENGTH_ERR:
 -      case MLX5_CMD_DELIVERY_STAT_OUT_LENGTH_ERR:
 -      case MLX5_CMD_DELIVERY_STAT_CMD_DESCR_ERR:
 -      case MLX5_CMD_DELIVERY_STAT_RES_FLD_NOT_CLR_ERR:
 -              return -ENOMSG;
 -      case MLX5_CMD_DELIVERY_STAT_FW_ERR:
 -              return -EIO;
 -      default:
 -              return -EINVAL;
 -      }
 -}
 -
  static struct mlx5_cmd_msg *alloc_msg(struct mlx5_core_dev *dev, int in_size,
                                      gfp_t gfp)
  {
@@@ -1816,23 -1788,27 +1817,23 @@@ static int is_manage_pages(void *in
        return MLX5_GET(mbox_in, in, opcode) == MLX5_CMD_OP_MANAGE_PAGES;
  }
  
 +/*  Notes:
 + *    1. Callback functions may not sleep
 + *    2. Page queue commands do not support asynchrous completion
 + */
  static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,
                    int out_size, mlx5_cmd_cbk_t callback, void *context,
                    bool force_polling)
  {
 -      struct mlx5_cmd_msg *inb;
 -      struct mlx5_cmd_msg *outb;
 +      u16 opcode = MLX5_GET(mbox_in, in, opcode);
 +      struct mlx5_cmd_msg *inb, *outb;
        int pages_queue;
        gfp_t gfp;
 -      int err;
 -      u8 status = 0;
 -      u32 drv_synd;
 -      u16 opcode;
        u8 token;
 +      int err;
  
 -      opcode = MLX5_GET(mbox_in, in, opcode);
 -      if (mlx5_cmd_is_down(dev) || !opcode_allowed(&dev->cmd, opcode)) {
 -              err = mlx5_internal_err_ret_value(dev, opcode, &drv_synd, &status);
 -              MLX5_SET(mbox_out, out, status, status);
 -              MLX5_SET(mbox_out, out, syndrome, drv_synd);
 -              return err;
 -      }
 +      if (mlx5_cmd_is_down(dev) || !opcode_allowed(&dev->cmd, opcode))
 +              return -ENXIO;
  
        pages_queue = is_manage_pages(in);
        gfp = callback ? GFP_ATOMIC : GFP_KERNEL;
        }
  
        err = mlx5_cmd_invoke(dev, inb, outb, out, out_size, callback, context,
 -                            pages_queue, &status, token, force_polling);
 +                            pages_queue, token, force_polling);
 +      if (callback)
 +              return err;
 +
 +      if (err > 0) /* Failed in FW, command didn't execute */
 +              err = deliv_status_to_err(err);
 +
        if (err)
                goto out_out;
  
 -      mlx5_core_dbg(dev, "err %d, status %d\n", err, status);
 -      if (status) {
 -              err = status_to_err(status);
 -              goto out_out;
 +      /* command completed by FW */
 +      err = mlx5_copy_from_msg(out, outb, out_size);
 +out_out:
 +      mlx5_free_cmd_msg(dev, outb);
 +out_in:
 +      free_msg(dev, inb);
 +      return err;
 +}
 +
 +static void cmd_status_log(struct mlx5_core_dev *dev, u16 opcode, u8 status, int err)
 +{
 +      struct mlx5_cmd_stats *stats;
 +
 +      if (!err)
 +              return;
 +
 +      stats = &dev->cmd.stats[opcode];
 +      spin_lock_irq(&stats->lock);
 +      stats->failed++;
 +      if (err < 0)
 +              stats->last_failed_errno = -err;
 +      if (err == -EREMOTEIO) {
 +              stats->failed_mbox_status++;
 +              stats->last_failed_mbox_status = status;
        }
 +      spin_unlock_irq(&stats->lock);
 +}
  
 -      if (!callback)
 -              err = mlx5_copy_from_msg(out, outb, out_size);
 +/* preserve -EREMOTEIO for outbox.status != OK, otherwise return err as is */
 +static int cmd_status_err(struct mlx5_core_dev *dev, int err, u16 opcode, void *out)
 +{
 +      u8 status = MLX5_GET(mbox_out, out, status);
  
 -out_out:
 -      if (!callback)
 -              mlx5_free_cmd_msg(dev, outb);
 +      if (err == -EREMOTEIO) /* -EREMOTEIO is preserved */
 +              err = -EIO;
  
 -out_in:
 -      if (!callback)
 -              free_msg(dev, inb);
 +      if (!err && status != MLX5_CMD_STAT_OK)
 +              err = -EREMOTEIO;
 +
 +      cmd_status_log(dev, opcode, status, err);
        return err;
  }
  
 +/**
 + * mlx5_cmd_do - Executes a fw command, wait for completion.
 + * Unlike mlx5_cmd_exec, this function will not translate or intercept
 + * outbox.status and will return -EREMOTEIO when
 + * outbox.status != MLX5_CMD_STAT_OK
 + *
 + * @dev: mlx5 core device
 + * @in: inbox mlx5_ifc command buffer
 + * @in_size: inbox buffer size
 + * @out: outbox mlx5_ifc buffer
 + * @out_size: outbox size
 + *
 + * @return:
 + * -EREMOTEIO : Command executed by FW, outbox.status != MLX5_CMD_STAT_OK.
 + *              Caller must check FW outbox status.
 + *   0 : Command execution successful, outbox.status == MLX5_CMD_STAT_OK.
 + * < 0 : Command execution couldn't be performed by firmware or driver
 + */
 +int mlx5_cmd_do(struct mlx5_core_dev *dev, void *in, int in_size, void *out, int out_size)
 +{
 +      int err = cmd_exec(dev, in, in_size, out, out_size, NULL, NULL, false);
 +      u16 opcode = MLX5_GET(mbox_in, in, opcode);
 +
 +      err = cmd_status_err(dev, err, opcode, out);
 +      return err;
 +}
 +EXPORT_SYMBOL(mlx5_cmd_do);
 +
 +/**
 + * mlx5_cmd_exec - Executes a fw command, wait for completion
 + *
 + * @dev: mlx5 core device
 + * @in: inbox mlx5_ifc command buffer
 + * @in_size: inbox buffer size
 + * @out: outbox mlx5_ifc buffer
 + * @out_size: outbox size
 + *
 + * @return: 0 if no error, FW command execution was successful
 + *          and outbox status is ok.
 + */
  int mlx5_cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,
                  int out_size)
  {
 -      int err;
 +      int err = mlx5_cmd_do(dev, in, in_size, out, out_size);
  
 -      err = cmd_exec(dev, in, in_size, out, out_size, NULL, NULL, false);
 -      return err ? : mlx5_cmd_check(dev, in, out);
 +      return mlx5_cmd_check(dev, err, in, out);
  }
  EXPORT_SYMBOL(mlx5_cmd_exec);
  
 +/**
 + * mlx5_cmd_exec_polling - Executes a fw command, poll for completion
 + *    Needed for driver force teardown, when command completion EQ
 + *    will not be available to complete the command
 + *
 + * @dev: mlx5 core device
 + * @in: inbox mlx5_ifc command buffer
 + * @in_size: inbox buffer size
 + * @out: outbox mlx5_ifc buffer
 + * @out_size: outbox size
 + *
 + * @return: 0 if no error, FW command execution was successful
 + *          and outbox status is ok.
 + */
 +int mlx5_cmd_exec_polling(struct mlx5_core_dev *dev, void *in, int in_size,
 +                        void *out, int out_size)
 +{
 +      int err = cmd_exec(dev, in, in_size, out, out_size, NULL, NULL, true);
 +      u16 opcode = MLX5_GET(mbox_in, in, opcode);
 +
 +      err = cmd_status_err(dev, err, opcode, out);
 +      return mlx5_cmd_check(dev, err, in, out);
 +}
 +EXPORT_SYMBOL(mlx5_cmd_exec_polling);
 +
  void mlx5_cmd_init_async_ctx(struct mlx5_core_dev *dev,
                             struct mlx5_async_ctx *ctx)
  {
@@@ -2013,10 -1895,8 +2014,10 @@@ EXPORT_SYMBOL(mlx5_cmd_cleanup_async_ct
  static void mlx5_cmd_exec_cb_handler(int status, void *_work)
  {
        struct mlx5_async_work *work = _work;
 -      struct mlx5_async_ctx *ctx = work->ctx;
 +      struct mlx5_async_ctx *ctx;
  
 +      ctx = work->ctx;
 +      status = cmd_status_err(ctx->dev, status, work->opcode, work->out);
        work->user_callback(status, work);
        if (atomic_dec_and_test(&ctx->num_inflight))
                wake_up(&ctx->wait);
@@@ -2030,8 -1910,6 +2031,8 @@@ int mlx5_cmd_exec_cb(struct mlx5_async_
  
        work->ctx = ctx;
        work->user_callback = callback;
 +      work->opcode = MLX5_GET(mbox_in, in, opcode);
 +      work->out = out;
        if (WARN_ON(!atomic_inc_not_zero(&ctx->num_inflight)))
                return -EIO;
        ret = cmd_exec(ctx->dev, in, in_size, out, out_size,
  }
  EXPORT_SYMBOL(mlx5_cmd_exec_cb);
  
 -int mlx5_cmd_exec_polling(struct mlx5_core_dev *dev, void *in, int in_size,
 -                        void *out, int out_size)
 -{
 -      int err;
 -
 -      err = cmd_exec(dev, in, in_size, out, out_size, NULL, NULL, true);
 -
 -      return err ? : mlx5_cmd_check(dev, in, out);
 -}
 -EXPORT_SYMBOL(mlx5_cmd_exec_polling);
 -
  static void destroy_msg_cache(struct mlx5_core_dev *dev)
  {
        struct cmd_msg_cache *ch;
  
  bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev)
  {
 -      bool striding_rq_umr = MLX5_CAP_GEN(mdev, striding_rq) &&
 -              MLX5_CAP_GEN(mdev, umr_ptr_rlky) &&
 -              MLX5_CAP_ETH(mdev, reg_umr_sq);
 -      u16 max_wqe_sz_cap = MLX5_CAP_GEN(mdev, max_wqe_sz_sq);
 -      bool inline_umr = MLX5E_UMR_WQE_INLINE_SZ <= max_wqe_sz_cap;
 +      bool striding_rq_umr, inline_umr;
 +      u16 max_wqe_sz_cap;
  
 +      striding_rq_umr = MLX5_CAP_GEN(mdev, striding_rq) && MLX5_CAP_GEN(mdev, umr_ptr_rlky) &&
 +                        MLX5_CAP_ETH(mdev, reg_umr_sq);
 +      max_wqe_sz_cap = mlx5e_get_max_sq_wqebbs(mdev) * MLX5_SEND_WQE_BB;
 +      inline_umr = max_wqe_sz_cap >= MLX5E_UMR_WQE_INLINE_SZ;
        if (!striding_rq_umr)
                return false;
        if (!inline_umr) {
@@@ -595,7 -594,6 +595,7 @@@ static int mlx5e_alloc_rq(struct mlx5e_
                rq->mpwqe.log_stride_sz = mlx5e_mpwqe_get_log_stride_size(mdev, params, xsk);
                rq->mpwqe.num_strides =
                        BIT(mlx5e_mpwqe_get_log_num_strides(mdev, params, xsk));
 +              rq->mpwqe.min_wqe_bulk = mlx5e_mpwqe_get_min_wqe_bulk(wq_sz);
  
                rq->buff.frame0_sz = (1 << rq->mpwqe.log_stride_sz);
  
@@@ -1166,9 -1164,6 +1166,9 @@@ static int mlx5e_alloc_xdpsq(struct mlx
                is_redirect ?
                        &c->priv->channel_stats[c->ix]->xdpsq :
                        &c->priv->channel_stats[c->ix]->rq_xdpsq;
 +      sq->max_sq_wqebbs = mlx5e_get_max_sq_wqebbs(mdev);
 +      sq->stop_room = MLX5E_STOP_ROOM(sq->max_sq_wqebbs);
 +      sq->max_sq_mpw_wqebbs = mlx5e_get_sw_max_sq_mpw_wqebbs(sq->max_sq_wqebbs);
  
        param->wq.db_numa_node = cpu_to_node(c->cpu);
        err = mlx5_wq_cyc_create(mdev, &param->wq, sqc_wq, wq, &sq->wq_ctrl);
@@@ -1243,7 -1238,6 +1243,7 @@@ static int mlx5e_alloc_icosq(struct mlx
        sq->channel   = c;
        sq->uar_map   = mdev->mlx5e_res.hw_objs.bfreg.map;
        sq->reserved_room = param->stop_room;
 +      sq->max_sq_wqebbs = mlx5e_get_max_sq_wqebbs(mdev);
  
        param->wq.db_numa_node = cpu_to_node(c->cpu);
        err = mlx5_wq_cyc_create(mdev, &param->wq, sqc_wq, wq, &sq->wq_ctrl);
@@@ -1319,6 -1313,7 +1319,6 @@@ static int mlx5e_alloc_txqsq(struct mlx
        int err;
  
        sq->pdev      = c->pdev;
 -      sq->tstamp    = c->tstamp;
        sq->clock     = &mdev->clock;
        sq->mkey_be   = c->mkey_be;
        sq->netdev    = c->netdev;
        sq->uar_map   = mdev->mlx5e_res.hw_objs.bfreg.map;
        sq->min_inline_mode = params->tx_min_inline_mode;
        sq->hw_mtu    = MLX5E_SW2HW_MTU(params, params->sw_mtu);
 +      sq->max_sq_wqebbs = mlx5e_get_max_sq_wqebbs(mdev);
 +      sq->max_sq_mpw_wqebbs = mlx5e_get_sw_max_sq_mpw_wqebbs(sq->max_sq_wqebbs);
        INIT_WORK(&sq->recover_work, mlx5e_tx_err_cqe_work);
        if (!MLX5_CAP_ETH(mdev, wqe_vlan_insert))
                set_bit(MLX5E_SQ_STATE_VLAN_NEED_L2_INLINE, &sq->state);
@@@ -2684,41 -2677,39 +2684,41 @@@ static void mlx5e_build_txq_maps(struc
                        struct mlx5e_txqsq *sq = &c->sq[tc];
  
                        priv->txq2sq[sq->txq_ix] = sq;
 -                      priv->channel_tc2realtxq[i][tc] = i + tc * ch;
                }
        }
  
        if (!priv->channels.ptp)
 -              return;
 +              goto out;
  
        if (!test_bit(MLX5E_PTP_STATE_TX, priv->channels.ptp->state))
 -              return;
 +              goto out;
  
        for (tc = 0; tc < num_tc; tc++) {
                struct mlx5e_ptp *c = priv->channels.ptp;
                struct mlx5e_txqsq *sq = &c->ptpsq[tc].txqsq;
  
                priv->txq2sq[sq->txq_ix] = sq;
 -              priv->port_ptp_tc2realtxq[tc] = priv->num_tc_x_num_ch + tc;
        }
 -}
  
 -static void mlx5e_update_num_tc_x_num_ch(struct mlx5e_priv *priv)
 -{
 -      /* Sync with mlx5e_select_queue. */
 -      WRITE_ONCE(priv->num_tc_x_num_ch,
 -                 mlx5e_get_dcb_num_tc(&priv->channels.params) * priv->channels.num);
 +out:
 +      /* Make the change to txq2sq visible before the queue is started.
 +       * As mlx5e_xmit runs under a spinlock, there is an implicit ACQUIRE,
 +       * which pairs with this barrier.
 +       */
 +      smp_wmb();
  }
  
  void mlx5e_activate_priv_channels(struct mlx5e_priv *priv)
  {
 -      mlx5e_update_num_tc_x_num_ch(priv);
        mlx5e_build_txq_maps(priv);
        mlx5e_activate_channels(&priv->channels);
        mlx5e_qos_activate_queues(priv);
        mlx5e_xdp_tx_enable(priv);
 +
 +      /* dev_watchdog() wants all TX queues to be started when the carrier is
 +       * OK, including the ones in range real_num_tx_queues..num_tx_queues-1.
 +       * Make it happy to avoid TX timeout false alarms.
 +       */
        netif_tx_start_all_queues(priv->netdev);
  
        if (mlx5e_is_vport_rep(priv))
@@@ -2738,13 -2729,11 +2738,13 @@@ void mlx5e_deactivate_priv_channels(str
        if (mlx5e_is_vport_rep(priv))
                mlx5e_remove_sqs_fwd_rules(priv);
  
 -      /* FIXME: This is a W/A only for tx timeout watch dog false alarm when
 -       * polling for inactive tx queues.
 +      /* The results of ndo_select_queue are unreliable, while netdev config
 +       * is being changed (real_num_tx_queues, num_tc). Stop all queues to
 +       * prevent ndo_start_xmit from being called, so that it can assume that
 +       * the selected queue is always valid.
         */
 -      netif_tx_stop_all_queues(priv->netdev);
        netif_tx_disable(priv->netdev);
 +
        mlx5e_xdp_tx_disable(priv);
        mlx5e_deactivate_channels(&priv->channels);
  }
@@@ -2804,7 -2793,6 +2804,7 @@@ static int mlx5e_switch_priv_channels(s
        mlx5e_close_channels(&old_chs);
        priv->profile->update_rx(priv);
  
 +      mlx5e_selq_apply(&priv->selq);
  out:
        mlx5e_activate_priv_channels(priv);
  
@@@ -2828,24 -2816,13 +2828,24 @@@ int mlx5e_safe_switch_params(struct mlx
                return mlx5e_switch_priv_params(priv, params, preactivate, context);
  
        new_chs.params = *params;
 +
 +      mlx5e_selq_prepare(&priv->selq, &new_chs.params, !!priv->htb.maj_id);
 +
        err = mlx5e_open_channels(priv, &new_chs);
        if (err)
 -              return err;
 +              goto err_cancel_selq;
 +
        err = mlx5e_switch_priv_channels(priv, &new_chs, preactivate, context);
        if (err)
 -              mlx5e_close_channels(&new_chs);
 +              goto err_close;
 +
 +      return 0;
 +
 +err_close:
 +      mlx5e_close_channels(&new_chs);
  
 +err_cancel_selq:
 +      mlx5e_selq_cancel(&priv->selq);
        return err;
  }
  
@@@ -2885,8 -2862,6 +2885,8 @@@ int mlx5e_open_locked(struct net_devic
        struct mlx5e_priv *priv = netdev_priv(netdev);
        int err;
  
 +      mlx5e_selq_prepare(&priv->selq, &priv->channels.params, !!priv->htb.maj_id);
 +
        set_bit(MLX5E_STATE_OPENED, &priv->state);
  
        err = mlx5e_open_channels(priv, &priv->channels);
                goto err_clear_state_opened_flag;
  
        priv->profile->update_rx(priv);
 +      mlx5e_selq_apply(&priv->selq);
        mlx5e_activate_priv_channels(priv);
        mlx5e_apply_traps(priv, true);
        if (priv->profile->update_carrier)
  
  err_clear_state_opened_flag:
        clear_bit(MLX5E_STATE_OPENED, &priv->state);
 +      mlx5e_selq_cancel(&priv->selq);
        return err;
  }
  
@@@ -3643,8 -3616,7 +3643,7 @@@ static int set_feature_hw_gro(struct ne
                goto out;
        }
  
-       err = mlx5e_safe_switch_params(priv, &new_params,
-                                      mlx5e_modify_tirs_packet_merge_ctx, NULL, reset);
+       err = mlx5e_safe_switch_params(priv, &new_params, NULL, NULL, reset);
  out:
        mutex_unlock(&priv->state_lock);
        return err;
@@@ -4664,6 -4636,11 +4663,6 @@@ void mlx5e_build_nic_params(struct mlx5
                                     priv->max_nch);
        mlx5e_params_mqprio_reset(params);
  
 -      /* Set an initial non-zero value, so that mlx5e_select_queue won't
 -       * divide by zero if called before first activating channels.
 -       */
 -      priv->num_tc_x_num_ch = params->num_channels * params->mqprio.num_tc;
 -
        /* SQ */
        params->log_sq_size = is_kdump_kernel() ?
                MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE :
@@@ -5216,8 -5193,7 +5215,8 @@@ int mlx5e_priv_init(struct mlx5e_priv *
                    struct net_device *netdev,
                    struct mlx5_core_dev *mdev)
  {
 -      int nch, num_txqs, node, i;
 +      int nch, num_txqs, node;
 +      int err;
  
        num_txqs = netdev->num_tx_queues;
        nch = mlx5e_calc_max_nch(mdev, netdev, profile);
                return -ENOMEM;
  
        mutex_init(&priv->state_lock);
 +
 +      err = mlx5e_selq_init(&priv->selq, &priv->state_lock);
 +      if (err)
 +              goto err_free_cpumask;
 +
        hash_init(priv->htb.qos_tc2node);
        INIT_WORK(&priv->update_carrier_work, mlx5e_update_carrier_work);
        INIT_WORK(&priv->set_rx_mode_work, mlx5e_set_rx_mode_work);
  
        priv->wq = create_singlethread_workqueue("mlx5e");
        if (!priv->wq)
 -              goto err_free_cpumask;
 +              goto err_free_selq;
  
        priv->txq2sq = kcalloc_node(num_txqs, sizeof(*priv->txq2sq), GFP_KERNEL, node);
        if (!priv->txq2sq)
        if (!priv->tx_rates)
                goto err_free_txq2sq;
  
 -      priv->channel_tc2realtxq =
 -              kcalloc_node(nch, sizeof(*priv->channel_tc2realtxq), GFP_KERNEL, node);
 -      if (!priv->channel_tc2realtxq)
 -              goto err_free_tx_rates;
 -
 -      for (i = 0; i < nch; i++) {
 -              priv->channel_tc2realtxq[i] =
 -                      kcalloc_node(profile->max_tc, sizeof(**priv->channel_tc2realtxq),
 -                                   GFP_KERNEL, node);
 -              if (!priv->channel_tc2realtxq[i])
 -                      goto err_free_channel_tc2realtxq;
 -      }
 -
        priv->channel_stats =
                kcalloc_node(nch, sizeof(*priv->channel_stats), GFP_KERNEL, node);
        if (!priv->channel_stats)
 -              goto err_free_channel_tc2realtxq;
 +              goto err_free_tx_rates;
  
        return 0;
  
 -err_free_channel_tc2realtxq:
 -      while (--i >= 0)
 -              kfree(priv->channel_tc2realtxq[i]);
 -      kfree(priv->channel_tc2realtxq);
  err_free_tx_rates:
        kfree(priv->tx_rates);
  err_free_txq2sq:
        kfree(priv->txq2sq);
  err_destroy_workqueue:
        destroy_workqueue(priv->wq);
 +err_free_selq:
 +      mlx5e_selq_cleanup(&priv->selq);
  err_free_cpumask:
        free_cpumask_var(priv->scratchpad.cpumask);
        return -ENOMEM;
@@@ -5288,12 -5274,12 +5287,12 @@@ void mlx5e_priv_cleanup(struct mlx5e_pr
        for (i = 0; i < priv->stats_nch; i++)
                kvfree(priv->channel_stats[i]);
        kfree(priv->channel_stats);
 -      for (i = 0; i < priv->max_nch; i++)
 -              kfree(priv->channel_tc2realtxq[i]);
 -      kfree(priv->channel_tc2realtxq);
        kfree(priv->tx_rates);
        kfree(priv->txq2sq);
        destroy_workqueue(priv->wq);
 +      mutex_lock(&priv->state_lock);
 +      mlx5e_selq_cleanup(&priv->selq);
 +      mutex_unlock(&priv->state_lock);
        free_cpumask_var(priv->scratchpad.cpumask);
  
        for (i = 0; i < priv->htb.max_qos_sqs; i++)
@@@ -5359,7 -5345,6 +5358,7 @@@ mlx5e_create_netdev(struct mlx5_core_de
        }
  
        netif_carrier_off(netdev);
 +      netif_tx_disable(netdev);
        dev_net_set(netdev, mlx5_core_net(mdev));
  
        return netdev;
@@@ -50,7 -50,7 +50,7 @@@ bool mlx5_lag_is_multipath(struct mlx5_
  static void mlx5_lag_set_port_affinity(struct mlx5_lag *ldev,
                                       enum mlx5_lag_port_affinity port)
  {
 -      struct lag_tracker tracker;
 +      struct lag_tracker tracker = {};
  
        if (!__mlx5_lag_is_multipath(ldev))
                return;
@@@ -126,6 -126,10 +126,10 @@@ static void mlx5_lag_fib_route_event(st
                return;
        }
  
+       /* Handle multipath entry with lower priority value */
+       if (mp->mfi && mp->mfi != fi && fi->fib_priority >= mp->mfi->fib_priority)
+               return;
        /* Handle add/replace event */
        nhs = fib_info_num_path(fi);
        if (nhs == 1) {
                        int i = mlx5_lag_dev_get_netdev_idx(ldev, nh_dev);
  
                        if (i < 0)
-                               i = MLX5_LAG_NORMAL_AFFINITY;
-                       else
-                               ++i;
+                               return;
  
+                       i++;
                        mlx5_lag_set_port_affinity(ldev, i);
                }
+               mp->mfi = fi;
                return;
        }
  
@@@ -2984,16 -2984,12 +2984,16 @@@ static int qed_iov_pre_update_vport(str
        u8 mask = QED_ACCEPT_UCAST_UNMATCHED | QED_ACCEPT_MCAST_UNMATCHED;
        struct qed_filter_accept_flags *flags = &params->accept_flags;
        struct qed_public_vf_info *vf_info;
 +      u16 tlv_mask;
 +
 +      tlv_mask = BIT(QED_IOV_VP_UPDATE_ACCEPT_PARAM) |
 +                 BIT(QED_IOV_VP_UPDATE_ACCEPT_ANY_VLAN);
  
        /* Untrusted VFs can't even be trusted to know that fact.
         * Simply indicate everything is configured fine, and trace
         * configuration 'behind their back'.
         */
 -      if (!(*tlvs & BIT(QED_IOV_VP_UPDATE_ACCEPT_PARAM)))
 +      if (!(*tlvs & tlv_mask))
                return 0;
  
        vf_info = qed_iov_get_public_vf_info(hwfn, vfid, true);
                        flags->tx_accept_filter &= ~mask;
        }
  
 +      if (params->update_accept_any_vlan_flg) {
 +              vf_info->accept_any_vlan = params->accept_any_vlan;
 +
 +              if (vf_info->forced_vlan && !vf_info->is_trusted_configured)
 +                      params->accept_any_vlan = false;
 +      }
 +
        return 0;
  }
  
@@@ -3817,11 -3806,11 +3817,11 @@@ bool qed_iov_mark_vf_flr(struct qed_hwf
        return found;
  }
  
- static void qed_iov_get_link(struct qed_hwfn *p_hwfn,
-                            u16 vfid,
-                            struct qed_mcp_link_params *p_params,
-                            struct qed_mcp_link_state *p_link,
-                            struct qed_mcp_link_capabilities *p_caps)
+ static int qed_iov_get_link(struct qed_hwfn *p_hwfn,
+                           u16 vfid,
+                           struct qed_mcp_link_params *p_params,
+                           struct qed_mcp_link_state *p_link,
+                           struct qed_mcp_link_capabilities *p_caps)
  {
        struct qed_vf_info *p_vf = qed_iov_get_vf_info(p_hwfn,
                                                       vfid,
        struct qed_bulletin_content *p_bulletin;
  
        if (!p_vf)
-               return;
+               return -EINVAL;
  
        p_bulletin = p_vf->bulletin.p_virt;
  
                __qed_vf_get_link_state(p_hwfn, p_link, p_bulletin);
        if (p_caps)
                __qed_vf_get_link_caps(p_hwfn, p_caps, p_bulletin);
+       return 0;
  }
  
  static int
@@@ -4697,6 -4687,7 +4698,7 @@@ static int qed_get_vf_config(struct qed
        struct qed_public_vf_info *vf_info;
        struct qed_mcp_link_state link;
        u32 tx_rate;
+       int ret;
  
        /* Sanitize request */
        if (IS_VF(cdev))
  
        vf_info = qed_iov_get_public_vf_info(hwfn, vf_id, true);
  
-       qed_iov_get_link(hwfn, vf_id, NULL, &link, NULL);
+       ret = qed_iov_get_link(hwfn, vf_id, NULL, &link, NULL);
+       if (ret)
+               return ret;
  
        /* Fill information about VF */
        ivi->vf = vf_id;
        tx_rate = vf_info->tx_rate;
        ivi->max_tx_rate = tx_rate ? tx_rate : link.speed;
        ivi->min_tx_rate = qed_iov_get_vf_min_rate(hwfn, vf_id);
 +      ivi->trusted = vf_info->is_trusted_request;
  
        return 0;
  }
@@@ -5157,12 -5149,6 +5161,12 @@@ static void qed_iov_handle_trust_change
  
                params.update_ctl_frame_check = 1;
                params.mac_chk_en = !vf_info->is_trusted_configured;
 +              params.update_accept_any_vlan_flg = 0;
 +
 +              if (vf_info->accept_any_vlan && vf_info->forced_vlan) {
 +                      params.update_accept_any_vlan_flg = 1;
 +                      params.accept_any_vlan = vf_info->accept_any_vlan;
 +              }
  
                if (vf_info->rx_accept_mode & mask) {
                        flags->update_rx_mode_config = 1;
                if (!vf_info->is_trusted_configured) {
                        flags->rx_accept_filter &= ~mask;
                        flags->tx_accept_filter &= ~mask;
 +                      params.accept_any_vlan = false;
                }
  
                if (flags->update_rx_mode_config ||
                    flags->update_tx_mode_config ||
 -                  params.update_ctl_frame_check)
 +                  params.update_ctl_frame_check ||
 +                  params.update_accept_any_vlan_flg) {
 +                      DP_VERBOSE(hwfn, QED_MSG_IOV,
 +                                 "vport update config for %s VF[abs 0x%x rel 0x%x]\n",
 +                                 vf_info->is_trusted_configured ? "trusted" : "untrusted",
 +                                 vf->abs_vf_id, vf->relative_vf_id);
                        qed_sp_vport_update(hwfn, &params,
                                            QED_SPQ_MODE_EBLOCK, NULL);
 +              }
        }
  }
  
@@@ -498,7 -498,7 +498,7 @@@ static void xemaclite_update_address(st
   * @dev:      Pointer to the network device instance
   * @address:  Void pointer to the sockaddr structure
   *
 - * This function copies the HW address from the sockaddr strucutre to the
 + * This function copies the HW address from the sockaddr structure to the
   * net_device structure and updates the address in HW.
   *
   * Return:    Error if the net device is busy or 0 if the addr is set
@@@ -1183,7 -1183,7 +1183,7 @@@ static int xemaclite_of_probe(struct pl
        if (rc) {
                dev_err(dev,
                        "Cannot register network device, aborting\n");
-               goto error;
+               goto put_node;
        }
  
        dev_info(dev,
                 (unsigned long __force)ndev->mem_start, lp->base_addr, ndev->irq);
        return 0;
  
+ put_node:
+       of_node_put(lp->phy_node);
  error:
        free_netdev(ndev);
        return rc;
@@@ -20,8 -20,6 +20,8 @@@
  #include <linux/of_net.h>
  #include <linux/mdio.h>
  #include <linux/phy.h>
 +#include <net/selftests.h>
 +
  #include "smsc95xx.h"
  
  #define SMSC_CHIPNAME                 "smsc95xx"
@@@ -86,9 -84,10 +86,10 @@@ static int __must_check __smsc95xx_read
        ret = fn(dev, USB_VENDOR_REQUEST_READ_REGISTER, USB_DIR_IN
                 | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                 0, index, &buf, 4);
-       if (unlikely(ret < 0)) {
-               netdev_warn(dev->net, "Failed to read reg index 0x%08x: %d\n",
-                           index, ret);
+       if (ret < 0) {
+               if (ret != -ENODEV)
+                       netdev_warn(dev->net, "Failed to read reg index 0x%08x: %d\n",
+                                   index, ret);
                return ret;
        }
  
@@@ -118,7 -117,7 +119,7 @@@ static int __must_check __smsc95xx_writ
        ret = fn(dev, USB_VENDOR_REQUEST_WRITE_REGISTER, USB_DIR_OUT
                 | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                 0, index, &buf, 4);
-       if (unlikely(ret < 0))
+       if (ret < 0 && ret != -ENODEV)
                netdev_warn(dev->net, "Failed to write reg index 0x%08x: %d\n",
                            index, ret);
  
@@@ -161,6 -160,9 +162,9 @@@ static int __must_check __smsc95xx_phy_
        do {
                ret = __smsc95xx_read_reg(dev, MII_ADDR, &val, in_pm);
                if (ret < 0) {
+                       /* Ignore -ENODEV error during disconnect() */
+                       if (ret == -ENODEV)
+                               return 0;
                        netdev_warn(dev->net, "Error reading MII_ACCESS\n");
                        return ret;
                }
@@@ -196,7 -198,8 +200,8 @@@ static int __smsc95xx_mdio_read(struct 
        addr = mii_address_cmd(phy_id, idx, MII_READ_ | MII_BUSY_);
        ret = __smsc95xx_write_reg(dev, MII_ADDR, addr, in_pm);
        if (ret < 0) {
-               netdev_warn(dev->net, "Error writing MII_ADDR\n");
+               if (ret != -ENODEV)
+                       netdev_warn(dev->net, "Error writing MII_ADDR\n");
                goto done;
        }
  
  
        ret = __smsc95xx_read_reg(dev, MII_DATA, &val, in_pm);
        if (ret < 0) {
-               netdev_warn(dev->net, "Error reading MII_DATA\n");
+               if (ret != -ENODEV)
+                       netdev_warn(dev->net, "Error reading MII_DATA\n");
                goto done;
        }
  
  
  done:
        mutex_unlock(&dev->phy_mutex);
+       /* Ignore -ENODEV error during disconnect() */
+       if (ret == -ENODEV)
+               return 0;
        return ret;
  }
  
@@@ -237,7 -245,8 +247,8 @@@ static void __smsc95xx_mdio_write(struc
        val = regval;
        ret = __smsc95xx_write_reg(dev, MII_DATA, val, in_pm);
        if (ret < 0) {
-               netdev_warn(dev->net, "Error writing MII_DATA\n");
+               if (ret != -ENODEV)
+                       netdev_warn(dev->net, "Error writing MII_DATA\n");
                goto done;
        }
  
        addr = mii_address_cmd(phy_id, idx, MII_WRITE_ | MII_BUSY_);
        ret = __smsc95xx_write_reg(dev, MII_ADDR, addr, in_pm);
        if (ret < 0) {
-               netdev_warn(dev->net, "Error writing MII_ADDR\n");
+               if (ret != -ENODEV)
+                       netdev_warn(dev->net, "Error writing MII_ADDR\n");
                goto done;
        }
  
@@@ -729,26 -739,6 +741,26 @@@ static u32 smsc95xx_get_link(struct net
        return net->phydev->link;
  }
  
 +static void smsc95xx_ethtool_get_strings(struct net_device *netdev, u32 sset,
 +                                      u8 *data)
 +{
 +      switch (sset) {
 +      case ETH_SS_TEST:
 +              net_selftest_get_strings(data);
 +              break;
 +      }
 +}
 +
 +static int smsc95xx_ethtool_get_sset_count(struct net_device *ndev, int sset)
 +{
 +      switch (sset) {
 +      case ETH_SS_TEST:
 +              return net_selftest_get_count();
 +      default:
 +              return -EOPNOTSUPP;
 +      }
 +}
 +
  static const struct ethtool_ops smsc95xx_ethtool_ops = {
        .get_link       = smsc95xx_get_link,
        .nway_reset     = phy_ethtool_nway_reset,
        .get_link_ksettings     = phy_ethtool_get_link_ksettings,
        .set_link_ksettings     = phy_ethtool_set_link_ksettings,
        .get_ts_info    = ethtool_op_get_ts_info,
 +      .self_test      = net_selftest,
 +      .get_strings    = smsc95xx_ethtool_get_strings,
 +      .get_sset_count = smsc95xx_ethtool_get_sset_count,
  };
  
  static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
diff --combined drivers/spi/spi.c
@@@ -404,8 -404,15 +404,8 @@@ static void spi_remove(struct device *d
  {
        const struct spi_driver         *sdrv = to_spi_driver(dev->driver);
  
 -      if (sdrv->remove) {
 -              int ret;
 -
 -              ret = sdrv->remove(to_spi_device(dev));
 -              if (ret)
 -                      dev_warn(dev,
 -                               "Failed to unbind driver (%pe), ignoring\n",
 -                               ERR_PTR(ret));
 -      }
 +      if (sdrv->remove)
 +              sdrv->remove(to_spi_device(dev));
  
        dev_pm_domain_detach(dev, true);
  }
@@@ -1012,10 -1019,10 +1012,10 @@@ int spi_map_buf(struct spi_controller *
        int i, ret;
  
        if (vmalloced_buf || kmap_buf) {
-               desc_len = min_t(int, max_seg_size, PAGE_SIZE);
+               desc_len = min_t(unsigned int, max_seg_size, PAGE_SIZE);
                sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len);
        } else if (virt_addr_valid(buf)) {
-               desc_len = min_t(int, max_seg_size, ctlr->max_dma_len);
+               desc_len = min_t(unsigned int, max_seg_size, ctlr->max_dma_len);
                sgs = DIV_ROUND_UP(len, desc_len);
        } else {
                return -EINVAL;
@@@ -76,14 -76,15 +76,15 @@@ static void tx_complete(void *arg
  
  static int gdm_lte_rx(struct sk_buff *skb, struct nic *nic, int nic_type)
  {
-       int ret;
+       int ret, len;
  
 -      ret = netif_rx_ni(skb);
+       len = skb->len + ETH_HLEN;
 +      ret = netif_rx(skb);
        if (ret == NET_RX_DROP) {
                nic->stats.rx_dropped++;
        } else {
                nic->stats.rx_packets++;
-               nic->stats.rx_bytes += skb->len + ETH_HLEN;
+               nic->stats.rx_bytes += len;
        }
  
        return 0;
diff --combined include/linux/bpf.h
@@@ -194,17 -194,6 +194,17 @@@ struct bpf_map 
        struct work_struct work;
        struct mutex freeze_mutex;
        atomic64_t writecnt;
 +      /* 'Ownership' of program-containing map is claimed by the first program
 +       * that is going to use this map or by the first program which FD is
 +       * stored in the map to make sure that all callers and callees have the
 +       * same prog type, JITed flag and xdp_has_frags flag.
 +       */
 +      struct {
 +              spinlock_t lock;
 +              enum bpf_prog_type type;
 +              bool jited;
 +              bool xdp_has_frags;
 +      } owner;
  };
  
  static inline bool map_value_has_spin_lock(const struct bpf_map *map)
@@@ -331,10 -320,7 +331,10 @@@ enum bpf_type_flag 
         */
        MEM_ALLOC               = BIT(2 + BPF_BASE_TYPE_BITS),
  
 -      __BPF_TYPE_LAST_FLAG    = MEM_ALLOC,
 +      /* MEM is in user address space. */
 +      MEM_USER                = BIT(3 + BPF_BASE_TYPE_BITS),
 +
 +      __BPF_TYPE_LAST_FLAG    = MEM_USER,
  };
  
  /* Max number of base types. */
@@@ -590,7 -576,8 +590,7 @@@ struct bpf_verifier_ops 
                                 const struct btf *btf,
                                 const struct btf_type *t, int off, int size,
                                 enum bpf_access_type atype,
 -                               u32 *next_btf_id);
 -      bool (*check_kfunc_call)(u32 kfunc_btf_id, struct module *owner);
 +                               u32 *next_btf_id, enum bpf_type_flag *flag);
  };
  
  struct bpf_prog_offload_ops {
@@@ -845,8 -832,8 +845,8 @@@ void bpf_image_ksym_add(void *data, str
  void bpf_image_ksym_del(struct bpf_ksym *ksym);
  void bpf_ksym_add(struct bpf_ksym *ksym);
  void bpf_ksym_del(struct bpf_ksym *ksym);
 -int bpf_jit_charge_modmem(u32 pages);
 -void bpf_jit_uncharge_modmem(u32 pages);
 +int bpf_jit_charge_modmem(u32 size);
 +void bpf_jit_uncharge_modmem(u32 size);
  bool bpf_prog_has_trampoline(const struct bpf_prog *prog);
  #else
  static inline int bpf_trampoline_link_prog(struct bpf_prog *prog,
@@@ -951,8 -938,6 +951,8 @@@ struct bpf_prog_aux 
        bool func_proto_unreliable;
        bool sleepable;
        bool tail_call_reachable;
 +      bool xdp_has_frags;
 +      bool use_bpf_prog_pack;
        struct hlist_node tramp_hlist;
        /* BTF_KIND_FUNC_PROTO for valid attach_btf_id */
        const struct btf_type *attach_func_proto;
  };
  
  struct bpf_array_aux {
 -      /* 'Ownership' of prog array is claimed by the first program that
 -       * is going to use this map or by the first program which FD is
 -       * stored in the map to make sure that all callers and callees have
 -       * the same prog type and JITed flag.
 -       */
 -      struct {
 -              spinlock_t lock;
 -              enum bpf_prog_type type;
 -              bool jited;
 -      } owner;
        /* Programs with direct jumps into programs part of this array. */
        struct list_head poke_progs;
        struct bpf_map *map;
@@@ -1187,14 -1182,7 +1187,14 @@@ struct bpf_event_entry 
        struct rcu_head rcu;
  };
  
 -bool bpf_prog_array_compatible(struct bpf_array *array, const struct bpf_prog *fp);
 +static inline bool map_type_contains_progs(struct bpf_map *map)
 +{
 +      return map->map_type == BPF_MAP_TYPE_PROG_ARRAY ||
 +             map->map_type == BPF_MAP_TYPE_DEVMAP ||
 +             map->map_type == BPF_MAP_TYPE_CPUMAP;
 +}
 +
 +bool bpf_prog_map_compatible(struct bpf_map *map, const struct bpf_prog *fp);
  int bpf_prog_calc_tag(struct bpf_prog *fp);
  
  const struct bpf_func_proto *bpf_get_trace_printk_proto(void);
@@@ -1236,19 -1224,6 +1236,19 @@@ struct bpf_prog_array 
        struct bpf_prog_array_item items[];
  };
  
 +struct bpf_empty_prog_array {
 +      struct bpf_prog_array hdr;
 +      struct bpf_prog *null_prog;
 +};
 +
 +/* to avoid allocating empty bpf_prog_array for cgroups that
 + * don't have bpf program attached use one global 'bpf_empty_prog_array'
 + * It will not be modified the caller of bpf_prog_array_alloc()
 + * (since caller requested prog_cnt == 0)
 + * that pointer should be 'freed' by bpf_prog_array_free()
 + */
 +extern struct bpf_empty_prog_array bpf_empty_prog_array;
 +
  struct bpf_prog_array *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags);
  void bpf_prog_array_free(struct bpf_prog_array *progs);
  int bpf_prog_array_length(struct bpf_prog_array *progs);
@@@ -1275,7 -1250,6 +1275,7 @@@ struct bpf_run_ctx {}
  struct bpf_cg_run_ctx {
        struct bpf_run_ctx run_ctx;
        const struct bpf_prog_array_item *prog_item;
 +      int retval;
  };
  
  struct bpf_trace_run_ctx {
@@@ -1308,19 -1282,19 +1308,19 @@@ static inline void bpf_reset_run_ctx(st
  
  typedef u32 (*bpf_prog_run_fn)(const struct bpf_prog *prog, const void *ctx);
  
 -static __always_inline u32
 +static __always_inline int
  BPF_PROG_RUN_ARRAY_CG_FLAGS(const struct bpf_prog_array __rcu *array_rcu,
                            const void *ctx, bpf_prog_run_fn run_prog,
 -                          u32 *ret_flags)
 +                          int retval, u32 *ret_flags)
  {
        const struct bpf_prog_array_item *item;
        const struct bpf_prog *prog;
        const struct bpf_prog_array *array;
        struct bpf_run_ctx *old_run_ctx;
        struct bpf_cg_run_ctx run_ctx;
 -      u32 ret = 1;
        u32 func_ret;
  
 +      run_ctx.retval = retval;
        migrate_disable();
        rcu_read_lock();
        array = rcu_dereference(array_rcu);
        while ((prog = READ_ONCE(item->prog))) {
                run_ctx.prog_item = item;
                func_ret = run_prog(prog, ctx);
 -              ret &= (func_ret & 1);
 +              if (!(func_ret & 1) && !IS_ERR_VALUE((long)run_ctx.retval))
 +                      run_ctx.retval = -EPERM;
                *(ret_flags) |= (func_ret >> 1);
                item++;
        }
        bpf_reset_run_ctx(old_run_ctx);
        rcu_read_unlock();
        migrate_enable();
 -      return ret;
 +      return run_ctx.retval;
  }
  
 -static __always_inline u32
 +static __always_inline int
  BPF_PROG_RUN_ARRAY_CG(const struct bpf_prog_array __rcu *array_rcu,
 -                    const void *ctx, bpf_prog_run_fn run_prog)
 +                    const void *ctx, bpf_prog_run_fn run_prog,
 +                    int retval)
  {
        const struct bpf_prog_array_item *item;
        const struct bpf_prog *prog;
        const struct bpf_prog_array *array;
        struct bpf_run_ctx *old_run_ctx;
        struct bpf_cg_run_ctx run_ctx;
 -      u32 ret = 1;
  
 +      run_ctx.retval = retval;
        migrate_disable();
        rcu_read_lock();
        array = rcu_dereference(array_rcu);
        old_run_ctx = bpf_set_run_ctx(&run_ctx.run_ctx);
        while ((prog = READ_ONCE(item->prog))) {
                run_ctx.prog_item = item;
 -              ret &= run_prog(prog, ctx);
 +              if (!run_prog(prog, ctx) && !IS_ERR_VALUE((long)run_ctx.retval))
 +                      run_ctx.retval = -EPERM;
                item++;
        }
        bpf_reset_run_ctx(old_run_ctx);
        rcu_read_unlock();
        migrate_enable();
 -      return ret;
 +      return run_ctx.retval;
  }
  
  static __always_inline u32
   *   0: NET_XMIT_SUCCESS  skb should be transmitted
   *   1: NET_XMIT_DROP     skb should be dropped and cn
   *   2: NET_XMIT_CN       skb should be transmitted and cn
 - *   3: -EPERM            skb should be dropped
 + *   3: -err              skb should be dropped
   */
  #define BPF_PROG_CGROUP_INET_EGRESS_RUN_ARRAY(array, ctx, func)               \
        ({                                              \
                u32 _flags = 0;                         \
                bool _cn;                               \
                u32 _ret;                               \
 -              _ret = BPF_PROG_RUN_ARRAY_CG_FLAGS(array, ctx, func, &_flags); \
 +              _ret = BPF_PROG_RUN_ARRAY_CG_FLAGS(array, ctx, func, 0, &_flags); \
                _cn = _flags & BPF_RET_SET_CN;          \
 -              if (_ret)                               \
 +              if (_ret && !IS_ERR_VALUE((long)_ret))  \
 +                      _ret = -EFAULT;                 \
 +              if (!_ret)                              \
                        _ret = (_cn ? NET_XMIT_CN : NET_XMIT_SUCCESS);  \
                else                                    \
 -                      _ret = (_cn ? NET_XMIT_DROP : -EPERM);          \
 +                      _ret = (_cn ? NET_XMIT_DROP : _ret);            \
                _ret;                                   \
        })
  
@@@ -1754,6 -1723,7 +1754,6 @@@ int bpf_prog_test_run_raw_tp(struct bpf
  int bpf_prog_test_run_sk_lookup(struct bpf_prog *prog,
                                const union bpf_attr *kattr,
                                union bpf_attr __user *uattr);
 -bool bpf_prog_test_check_kfunc_call(u32 kfunc_id, struct module *owner);
  bool btf_ctx_access(int off, int size, enum bpf_access_type type,
                    const struct bpf_prog *prog,
                    struct bpf_insn_access_aux *info);
@@@ -1783,7 -1753,7 +1783,7 @@@ static inline bool bpf_tracing_btf_ctx_
  int btf_struct_access(struct bpf_verifier_log *log, const struct btf *btf,
                      const struct btf_type *t, int off, int size,
                      enum bpf_access_type atype,
 -                    u32 *next_btf_id);
 +                    u32 *next_btf_id, enum bpf_type_flag *flag);
  bool btf_struct_ids_match(struct bpf_verifier_log *log,
                          const struct btf *btf, u32 id, int off,
                          const struct btf *need_btf, u32 need_type_id);
@@@ -1822,6 -1792,11 +1822,11 @@@ struct bpf_core_ctx 
  int bpf_core_apply(struct bpf_core_ctx *ctx, const struct bpf_core_relo *relo,
                   int relo_idx, void *insn);
  
+ static inline bool unprivileged_ebpf_enabled(void)
+ {
+       return !sysctl_unprivileged_bpf_disabled;
+ }
  #else /* !CONFIG_BPF_SYSCALL */
  static inline struct bpf_prog *bpf_prog_get(u32 ufd)
  {
@@@ -1891,6 -1866,11 +1896,6 @@@ static inline int bpf_obj_get_user(cons
        return -EOPNOTSUPP;
  }
  
 -static inline bool dev_map_can_have_prog(struct bpf_map *map)
 -{
 -      return false;
 -}
 -
  static inline void __dev_flush(void)
  {
  }
@@@ -1954,6 -1934,11 +1959,6 @@@ static inline int cpu_map_generic_redir
        return -EOPNOTSUPP;
  }
  
 -static inline bool cpu_map_prog_allowed(struct bpf_map *map)
 -{
 -      return false;
 -}
 -
  static inline struct bpf_prog *bpf_prog_get_type_path(const char *name,
                                enum bpf_prog_type type)
  {
@@@ -1995,6 -1980,12 +2000,6 @@@ static inline int bpf_prog_test_run_sk_
        return -ENOTSUPP;
  }
  
 -static inline bool bpf_prog_test_check_kfunc_call(u32 kfunc_id,
 -                                                struct module *owner)
 -{
 -      return false;
 -}
 -
  static inline void bpf_map_put(struct bpf_map *map)
  {
  }
@@@ -2025,6 -2016,12 +2030,12 @@@ bpf_jit_find_kfunc_model(const struct b
  {
        return NULL;
  }
+ static inline bool unprivileged_ebpf_enabled(void)
+ {
+       return false;
+ }
  #endif /* CONFIG_BPF_SYSCALL */
  
  void __bpf_free_used_btfs(struct bpf_prog_aux *aux,
@@@ -2089,9 -2086,6 +2100,9 @@@ int bpf_prog_test_run_syscall(struct bp
  int sock_map_get_from_fd(const union bpf_attr *attr, struct bpf_prog *prog);
  int sock_map_prog_detach(const union bpf_attr *attr, enum bpf_prog_type ptype);
  int sock_map_update_elem_sys(struct bpf_map *map, void *key, void *value, u64 flags);
 +int sock_map_bpf_prog_query(const union bpf_attr *attr,
 +                          union bpf_attr __user *uattr);
 +
  void sock_map_unhash(struct sock *sk);
  void sock_map_close(struct sock *sk, long timeout);
  #else
@@@ -2145,12 -2139,6 +2156,12 @@@ static inline int sock_map_update_elem_
  {
        return -EOPNOTSUPP;
  }
 +
 +static inline int sock_map_bpf_prog_query(const union bpf_attr *attr,
 +                                        union bpf_attr __user *uattr)
 +{
 +      return -EINVAL;
 +}
  #endif /* CONFIG_BPF_SYSCALL */
  #endif /* CONFIG_NET && CONFIG_BPF_SYSCALL */
  
@@@ -2249,7 -2237,6 +2260,7 @@@ extern const struct bpf_func_proto bpf_
  extern const struct bpf_func_proto bpf_find_vma_proto;
  extern const struct bpf_func_proto bpf_loop_proto;
  extern const struct bpf_func_proto bpf_strncmp_proto;
 +extern const struct bpf_func_proto bpf_copy_from_user_task_proto;
  
  const struct bpf_func_proto *tracing_prog_func_proto(
    enum bpf_func_id func_id, const struct bpf_prog *prog);
@@@ -2362,8 -2349,6 +2373,8 @@@ enum bpf_text_poke_type 
  int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
                       void *addr1, void *addr2);
  
 +void *bpf_arch_text_copy(void *dst, void *src, size_t len);
 +
  struct btf_id_set;
  bool btf_id_set_contains(const struct btf_id_set *set, u32 id);
  
@@@ -63,6 -63,13 +63,6 @@@ enum 
        MLX5_EVENT_TYPE_CODING_FPGA_QP_ERROR                       = 0x21
  };
  
 -enum {
 -      MLX5_MODIFY_TIR_BITMASK_LRO                   = 0x0,
 -      MLX5_MODIFY_TIR_BITMASK_INDIRECT_TABLE        = 0x1,
 -      MLX5_MODIFY_TIR_BITMASK_HASH                  = 0x2,
 -      MLX5_MODIFY_TIR_BITMASK_TUNNELED_OFFLOAD_EN   = 0x3
 -};
 -
  enum {
        MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE        = 0x0,
        MLX5_SET_HCA_CAP_OP_MOD_ODP                   = 0x2,
@@@ -493,10 -500,7 +493,10 @@@ struct mlx5_ifc_fte_match_set_lyr_2_4_b
        u8         tcp_sport[0x10];
        u8         tcp_dport[0x10];
  
 -      u8         reserved_at_c0[0x18];
 +      u8         reserved_at_c0[0x10];
 +      u8         ipv4_ihl[0x4];
 +      u8         reserved_at_c4[0x4];
 +
        u8         ttl_hoplimit[0x8];
  
        u8         udp_sport[0x10];
@@@ -1346,7 -1350,6 +1346,7 @@@ enum mlx5_fc_bulk_alloc_bitmask 
  enum {
        MLX5_STEERING_FORMAT_CONNECTX_5   = 0,
        MLX5_STEERING_FORMAT_CONNECTX_6DX = 1,
 +      MLX5_STEERING_FORMAT_CONNECTX_7   = 2,
  };
  
  struct mlx5_ifc_cmd_hca_cap_bits {
        u8         reserved_at_130[0xa];
        u8         log_max_ra_res_dc[0x6];
  
 -      u8         reserved_at_140[0x6];
 +      u8         reserved_at_140[0x5];
        u8         release_all_pages[0x1];
 +      u8         must_not_use[0x1];
        u8         reserved_at_147[0x2];
        u8         roce_accl[0x1];
        u8         log_max_ra_req_qp[0x6];
@@@ -3432,7 -3434,6 +3432,6 @@@ enum 
  enum {
        MLX5_TIRC_PACKET_MERGE_MASK_IPV4_LRO  = BIT(0),
        MLX5_TIRC_PACKET_MERGE_MASK_IPV6_LRO  = BIT(1),
-       MLX5_TIRC_PACKET_MERGE_MASK_SHAMPO    = BIT(2),
  };
  
  enum {
@@@ -9692,8 -9693,7 +9691,8 @@@ struct mlx5_ifc_pcam_reg_bits 
  };
  
  struct mlx5_ifc_mcam_enhanced_features_bits {
 -      u8         reserved_at_0[0x6b];
 +      u8         reserved_at_0[0x6a];
 +      u8         reset_state[0x1];
        u8         ptpcyc2realtime_modify[0x1];
        u8         reserved_at_6c[0x2];
        u8         pci_status_and_power[0x1];
@@@ -9899,8 -9899,8 +9898,8 @@@ struct mlx5_ifc_bufferx_reg_bits 
        u8         reserved_at_0[0x6];
        u8         lossy[0x1];
        u8         epsb[0x1];
-       u8         reserved_at_8[0xc];
-       u8         size[0xc];
+       u8         reserved_at_8[0x8];
+       u8         size[0x10];
  
        u8         xoff_threshold[0x10];
        u8         xon_threshold[0x10];
@@@ -10374,14 -10374,6 +10373,14 @@@ struct mlx5_ifc_mcda_reg_bits 
        u8         data[][0x20];
  };
  
 +enum {
 +      MLX5_MFRL_REG_RESET_STATE_IDLE = 0,
 +      MLX5_MFRL_REG_RESET_STATE_IN_NEGOTIATION = 1,
 +      MLX5_MFRL_REG_RESET_STATE_RESET_IN_PROGRESS = 2,
 +      MLX5_MFRL_REG_RESET_STATE_TIMEOUT = 3,
 +      MLX5_MFRL_REG_RESET_STATE_NACK = 4,
 +};
 +
  enum {
        MLX5_MFRL_REG_RESET_TYPE_FULL_CHIP = BIT(0),
        MLX5_MFRL_REG_RESET_TYPE_NET_PORT_ALIVE = BIT(1),
@@@ -10400,8 -10392,7 +10399,8 @@@ struct mlx5_ifc_mfrl_reg_bits 
        u8         pci_sync_for_fw_update_start[0x1];
        u8         pci_sync_for_fw_update_resp[0x2];
        u8         rst_type_sel[0x3];
 -      u8         reserved_at_28[0x8];
 +      u8         reserved_at_28[0x4];
 +      u8         reset_state[0x4];
        u8         reset_type[0x8];
        u8         reset_level[0x8];
  };
@@@ -1948,9 -1948,6 +1948,9 @@@ enum netdev_ml_priv_type 
   *    @dev_addr_shadow:       Copy of @dev_addr to catch direct writes.
   *    @linkwatch_dev_tracker: refcount tracker used by linkwatch.
   *    @watchdog_dev_tracker:  refcount tracker used by watchdog.
 + *    @dev_registered_tracker:        tracker for reference held while
 + *                                    registered
 + *    @offload_xstats_l3:     L3 HW stats for this netdevice.
   *
   *    FIXME: cleanup struct net_device such that network protocol info
   *    moves out.
@@@ -2237,9 -2234,7 +2237,9 @@@ struct net_device 
  #if IS_ENABLED(CONFIG_MRP)
        struct mrp_port __rcu   *mrp_port;
  #endif
 -
 +#if IS_ENABLED(CONFIG_NET_DROP_MONITOR)
 +      struct dm_hw_stat_delta __rcu *dm_private;
 +#endif
        struct device           dev;
        const struct attribute_group *sysfs_groups[4];
        const struct attribute_group *sysfs_rx_queue_group;
        u8 dev_addr_shadow[MAX_ADDR_LEN];
        netdevice_tracker       linkwatch_dev_tracker;
        netdevice_tracker       watchdog_dev_tracker;
 +      netdevice_tracker       dev_registered_tracker;
 +      struct rtnl_hw_stats64  *offload_xstats_l3;
  };
  #define to_net_dev(d) container_of(d, struct net_device, dev)
  
@@@ -2729,10 -2722,6 +2729,10 @@@ enum netdev_cmd 
        NETDEV_CVLAN_FILTER_DROP_INFO,
        NETDEV_SVLAN_FILTER_PUSH_INFO,
        NETDEV_SVLAN_FILTER_DROP_INFO,
 +      NETDEV_OFFLOAD_XSTATS_ENABLE,
 +      NETDEV_OFFLOAD_XSTATS_DISABLE,
 +      NETDEV_OFFLOAD_XSTATS_REPORT_USED,
 +      NETDEV_OFFLOAD_XSTATS_REPORT_DELTA,
  };
  const char *netdev_cmd_to_name(enum netdev_cmd cmd);
  
@@@ -2783,42 -2772,6 +2783,42 @@@ struct netdev_notifier_pre_changeaddr_i
        const unsigned char *dev_addr;
  };
  
 +enum netdev_offload_xstats_type {
 +      NETDEV_OFFLOAD_XSTATS_TYPE_L3 = 1,
 +};
 +
 +struct netdev_notifier_offload_xstats_info {
 +      struct netdev_notifier_info info; /* must be first */
 +      enum netdev_offload_xstats_type type;
 +
 +      union {
 +              /* NETDEV_OFFLOAD_XSTATS_REPORT_DELTA */
 +              struct netdev_notifier_offload_xstats_rd *report_delta;
 +              /* NETDEV_OFFLOAD_XSTATS_REPORT_USED */
 +              struct netdev_notifier_offload_xstats_ru *report_used;
 +      };
 +};
 +
 +int netdev_offload_xstats_enable(struct net_device *dev,
 +                               enum netdev_offload_xstats_type type,
 +                               struct netlink_ext_ack *extack);
 +int netdev_offload_xstats_disable(struct net_device *dev,
 +                                enum netdev_offload_xstats_type type);
 +bool netdev_offload_xstats_enabled(const struct net_device *dev,
 +                                 enum netdev_offload_xstats_type type);
 +int netdev_offload_xstats_get(struct net_device *dev,
 +                            enum netdev_offload_xstats_type type,
 +                            struct rtnl_hw_stats64 *stats, bool *used,
 +                            struct netlink_ext_ack *extack);
 +void
 +netdev_offload_xstats_report_delta(struct netdev_notifier_offload_xstats_rd *rd,
 +                                 const struct rtnl_hw_stats64 *stats);
 +void
 +netdev_offload_xstats_report_used(struct netdev_notifier_offload_xstats_ru *ru);
 +void netdev_offload_xstats_push_delta(struct net_device *dev,
 +                                    enum netdev_offload_xstats_type type,
 +                                    const struct rtnl_hw_stats64 *stats);
 +
  static inline void netdev_notifier_info_init(struct netdev_notifier_info *info,
                                             struct net_device *dev)
  {
@@@ -3716,8 -3669,8 +3716,8 @@@ u32 bpf_prog_run_generic_xdp(struct sk_
  void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog);
  int do_xdp_generic(struct bpf_prog *xdp_prog, struct sk_buff *skb);
  int netif_rx(struct sk_buff *skb);
 -int netif_rx_ni(struct sk_buff *skb);
 -int netif_rx_any_context(struct sk_buff *skb);
 +int __netif_rx(struct sk_buff *skb);
 +
  int netif_receive_skb(struct sk_buff *skb);
  int netif_receive_skb_core(struct sk_buff *skb);
  void netif_receive_skb_list_internal(struct list_head *head);
@@@ -3864,7 -3817,14 +3864,7 @@@ extern unsigned int    netdev_budget_usecs
  /* Called by rtnetlink.c:rtnl_unlock() */
  void netdev_run_todo(void);
  
 -/**
 - *    dev_put - release reference to device
 - *    @dev: network device
 - *
 - * Release reference to device to allow it to be freed.
 - * Try using dev_put_track() instead.
 - */
 -static inline void dev_put(struct net_device *dev)
 +static inline void __dev_put(struct net_device *dev)
  {
        if (dev) {
  #ifdef CONFIG_PCPU_DEV_REFCNT
        }
  }
  
 -/**
 - *    dev_hold - get reference to device
 - *    @dev: network device
 - *
 - * Hold reference to device to keep it from being freed.
 - * Try using dev_hold_track() instead.
 - */
 -static inline void dev_hold(struct net_device *dev)
 +static inline void __dev_hold(struct net_device *dev)
  {
        if (dev) {
  #ifdef CONFIG_PCPU_DEV_REFCNT
        }
  }
  
 +static inline void __netdev_tracker_alloc(struct net_device *dev,
 +                                        netdevice_tracker *tracker,
 +                                        gfp_t gfp)
 +{
 +#ifdef CONFIG_NET_DEV_REFCNT_TRACKER
 +      ref_tracker_alloc(&dev->refcnt_tracker, tracker, gfp);
 +#endif
 +}
 +
 +/* netdev_tracker_alloc() can upgrade a prior untracked reference
 + * taken by dev_get_by_name()/dev_get_by_index() to a tracked one.
 + */
  static inline void netdev_tracker_alloc(struct net_device *dev,
                                        netdevice_tracker *tracker, gfp_t gfp)
  {
  #ifdef CONFIG_NET_DEV_REFCNT_TRACKER
 -      ref_tracker_alloc(&dev->refcnt_tracker, tracker, gfp);
 +      refcount_dec(&dev->refcnt_tracker.no_tracker);
 +      __netdev_tracker_alloc(dev, tracker, gfp);
  #endif
  }
  
@@@ -3919,8 -3873,8 +3919,8 @@@ static inline void dev_hold_track(struc
                                  netdevice_tracker *tracker, gfp_t gfp)
  {
        if (dev) {
 -              dev_hold(dev);
 -              netdev_tracker_alloc(dev, tracker, gfp);
 +              __dev_hold(dev);
 +              __netdev_tracker_alloc(dev, tracker, gfp);
        }
  }
  
@@@ -3929,34 -3883,10 +3929,34 @@@ static inline void dev_put_track(struc
  {
        if (dev) {
                netdev_tracker_free(dev, tracker);
 -              dev_put(dev);
 +              __dev_put(dev);
        }
  }
  
 +/**
 + *    dev_hold - get reference to device
 + *    @dev: network device
 + *
 + * Hold reference to device to keep it from being freed.
 + * Try using dev_hold_track() instead.
 + */
 +static inline void dev_hold(struct net_device *dev)
 +{
 +      dev_hold_track(dev, NULL, GFP_ATOMIC);
 +}
 +
 +/**
 + *    dev_put - release reference to device
 + *    @dev: network device
 + *
 + * Release reference to device to allow it to be freed.
 + * Try using dev_put_track() instead.
 + */
 +static inline void dev_put(struct net_device *dev)
 +{
 +      dev_put_track(dev, NULL);
 +}
 +
  static inline void dev_replace_track(struct net_device *odev,
                                     struct net_device *ndev,
                                     netdevice_tracker *tracker,
        if (odev)
                netdev_tracker_free(odev, tracker);
  
 -      dev_hold(ndev);
 -      dev_put(odev);
 +      __dev_hold(ndev);
 +      __dev_put(odev);
  
        if (ndev)
 -              netdev_tracker_alloc(ndev, tracker, gfp);
 +              __netdev_tracker_alloc(ndev, tracker, gfp);
  }
  
  /* Carrier loss detection, dial on demand. The functions netif_carrier_on
@@@ -4672,6 -4602,8 +4672,8 @@@ int skb_csum_hwoffload_help(struct sk_b
  
  struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
                                  netdev_features_t features, bool tx_path);
+ struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb,
+                                   netdev_features_t features, __be16 type);
  struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
                                    netdev_features_t features);
  
diff --combined include/linux/phy.h
@@@ -87,8 -87,8 +87,8 @@@ extern const int phy_10gbit_features_ar
   *
   * @PHY_INTERFACE_MODE_NA: Not Applicable - don't touch
   * @PHY_INTERFACE_MODE_INTERNAL: No interface, MAC and PHY combined
-  * @PHY_INTERFACE_MODE_MII: Median-independent interface
-  * @PHY_INTERFACE_MODE_GMII: Gigabit median-independent interface
+  * @PHY_INTERFACE_MODE_MII: Media-independent interface
+  * @PHY_INTERFACE_MODE_GMII: Gigabit media-independent interface
   * @PHY_INTERFACE_MODE_SGMII: Serial gigabit media-independent interface
   * @PHY_INTERFACE_MODE_TBI: Ten Bit Interface
   * @PHY_INTERFACE_MODE_REVMII: Reverse Media Independent Interface
@@@ -1578,7 -1578,6 +1578,7 @@@ int genphy_update_link(struct phy_devic
  int genphy_read_lpa(struct phy_device *phydev);
  int genphy_read_status_fixed(struct phy_device *phydev);
  int genphy_read_status(struct phy_device *phydev);
 +int genphy_read_master_slave(struct phy_device *phydev);
  int genphy_suspend(struct phy_device *phydev);
  int genphy_resume(struct phy_device *phydev);
  int genphy_loopback(struct phy_device *phydev, bool enable);
@@@ -1662,7 -1661,7 +1662,7 @@@ int phy_disable_interrupts(struct phy_d
  void phy_request_interrupt(struct phy_device *phydev);
  void phy_free_interrupt(struct phy_device *phydev);
  void phy_print_status(struct phy_device *phydev);
 -int phy_set_max_speed(struct phy_device *phydev, u32 max_speed);
 +void phy_set_max_speed(struct phy_device *phydev, u32 max_speed);
  void phy_remove_link_mode(struct phy_device *phydev, u32 link_mode);
  void phy_advertise_supported(struct phy_device *phydev);
  void phy_support_sym_pause(struct phy_device *phydev);
diff --combined net/bluetooth/hci_sync.c
@@@ -276,40 -276,37 +276,37 @@@ EXPORT_SYMBOL(__hci_cmd_sync_status)
  static void hci_cmd_sync_work(struct work_struct *work)
  {
        struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_sync_work);
-       struct hci_cmd_sync_work_entry *entry;
-       hci_cmd_sync_work_func_t func;
-       hci_cmd_sync_work_destroy_t destroy;
-       void *data;
  
        bt_dev_dbg(hdev, "");
  
-       mutex_lock(&hdev->cmd_sync_work_lock);
-       entry = list_first_entry(&hdev->cmd_sync_work_list,
-                                struct hci_cmd_sync_work_entry, list);
-       if (entry) {
-               list_del(&entry->list);
-               func = entry->func;
-               data = entry->data;
-               destroy = entry->destroy;
-               kfree(entry);
-       } else {
-               func = NULL;
-               data = NULL;
-               destroy = NULL;
-       }
-       mutex_unlock(&hdev->cmd_sync_work_lock);
+       /* Dequeue all entries and run them */
+       while (1) {
+               struct hci_cmd_sync_work_entry *entry;
  
-       if (func) {
-               int err;
+               mutex_lock(&hdev->cmd_sync_work_lock);
+               entry = list_first_entry_or_null(&hdev->cmd_sync_work_list,
+                                                struct hci_cmd_sync_work_entry,
+                                                list);
+               if (entry)
+                       list_del(&entry->list);
+               mutex_unlock(&hdev->cmd_sync_work_lock);
  
-               hci_req_sync_lock(hdev);
+               if (!entry)
+                       break;
  
-               err = func(hdev, data);
+               bt_dev_dbg(hdev, "entry %p", entry);
  
-               if (destroy)
-                       destroy(hdev, data, err);
+               if (entry->func) {
+                       int err;
  
-               hci_req_sync_unlock(hdev);
+                       hci_req_sync_lock(hdev);
+                       err = entry->func(hdev, entry->data);
+                       if (entry->destroy)
+                               entry->destroy(hdev, entry->data, err);
+                       hci_req_sync_unlock(hdev);
+               }
+               kfree(entry);
        }
  }
  
@@@ -382,9 -379,6 +379,9 @@@ int hci_cmd_sync_queue(struct hci_dev *
  {
        struct hci_cmd_sync_work_entry *entry;
  
 +      if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
 +              return -ENODEV;
 +
        entry = kmalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
                return -ENOMEM;
@@@ -4428,7 -4422,7 +4425,7 @@@ static int hci_disconnect_all_sync(stru
                        return err;
        }
  
 -      return err;
 +      return 0;
  }
  
  /* This function perform power off HCI command sequence as follows:
@@@ -5146,8 -5140,8 +5143,8 @@@ static void set_ext_conn_params(struct 
        p->max_ce_len = cpu_to_le16(0x0000);
  }
  
 -int hci_le_ext_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn,
 -                              u8 own_addr_type)
 +static int hci_le_ext_create_conn_sync(struct hci_dev *hdev,
 +                                     struct hci_conn *conn, u8 own_addr_type)
  {
        struct hci_cp_le_ext_create_conn *cp;
        struct hci_cp_le_ext_conn_param *p;
diff --combined net/bluetooth/mgmt.c
@@@ -42,7 -42,7 +42,7 @@@
  #include "aosp.h"
  
  #define MGMT_VERSION  1
 -#define MGMT_REVISION 21
 +#define MGMT_REVISION 22
  
  static const u16 mgmt_commands[] = {
        MGMT_OP_READ_INDEX_LIST,
@@@ -174,8 -174,6 +174,8 @@@ static const u16 mgmt_events[] = 
        MGMT_EV_ADV_MONITOR_REMOVED,
        MGMT_EV_CONTROLLER_SUSPEND,
        MGMT_EV_CONTROLLER_RESUME,
 +      MGMT_EV_ADV_MONITOR_DEVICE_FOUND,
 +      MGMT_EV_ADV_MONITOR_DEVICE_LOST,
  };
  
  static const u16 mgmt_untrusted_commands[] = {
@@@ -2298,9 -2296,7 +2298,9 @@@ static int remove_uuid(struct sock *sk
        struct mgmt_cp_remove_uuid *cp = data;
        struct mgmt_pending_cmd *cmd;
        struct bt_uuid *match, *tmp;
 -      u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 +      static const u8 bt_uuid_any[] = {
 +              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 +      };
        int err, found;
  
        bt_dev_dbg(hdev, "sock %p", sk);
@@@ -4545,9 -4541,9 +4545,9 @@@ static int set_device_flags(struct soc
                }
        }
  
- done:
        hci_dev_unlock(hdev);
  
+ done:
        if (status == MGMT_STATUS_SUCCESS)
                device_flags_changed(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
                                     supported_flags, current_flags);
@@@ -8079,7 -8075,7 +8079,7 @@@ static int add_advertising(struct sock 
        u32 flags;
        u8 status;
        u16 timeout, duration;
 -      unsigned int prev_instance_cnt = hdev->adv_instance_cnt;
 +      unsigned int prev_instance_cnt;
        u8 schedule_instance = 0;
        struct adv_info *next_instance;
        int err;
                goto unlock;
        }
  
 +      prev_instance_cnt = hdev->adv_instance_cnt;
 +
        err = hci_add_adv_instance(hdev, cp->instance, flags,
                                   cp->adv_data_len, cp->data,
                                   cp->scan_rsp_len,
@@@ -8634,6 -8628,7 +8634,6 @@@ static int get_adv_size_info(struct soc
        struct mgmt_cp_get_adv_size_info *cp = data;
        struct mgmt_rp_get_adv_size_info rp;
        u32 flags, supported_flags;
 -      int err;
  
        bt_dev_dbg(hdev, "sock %p", sk);
  
        rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
        rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
  
 -      err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
 -                              MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
 -
 -      return err;
 +      return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
 +                               MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
  }
  
  static const struct hci_mgmt_handler mgmt_handlers[] = {
@@@ -9089,14 -9086,12 +9089,14 @@@ void mgmt_device_connected(struct hci_d
        u16 eir_len = 0;
        u32 flags = 0;
  
 +      /* allocate buff for LE or BR/EDR adv */
        if (conn->le_adv_data_len > 0)
                skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_CONNECTED,
 -                                   conn->le_adv_data_len);
 +                                   sizeof(*ev) + conn->le_adv_data_len);
        else
                skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_CONNECTED,
 -                                   2 + name_len + 5);
 +                                   sizeof(*ev) + (name ? eir_precalc_len(name_len) : 0) +
 +                                   eir_precalc_len(sizeof(conn->dev_class)));
  
        ev = skb_put(skb, sizeof(*ev));
        bacpy(&ev->addr.bdaddr, &conn->dst);
                skb_put_data(skb, conn->le_adv_data, conn->le_adv_data_len);
                eir_len = conn->le_adv_data_len;
        } else {
 -              if (name_len > 0) {
 -                      eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
 -                                                name, name_len);
 -                      skb_put(skb, eir_len);
 -              }
 +              if (name)
 +                      eir_len += eir_skb_put_data(skb, EIR_NAME_COMPLETE, name, name_len);
  
 -              if (memcmp(conn->dev_class, "\0\0\0", 3) != 0) {
 -                      eir_len = eir_append_data(ev->eir, eir_len,
 -                                                EIR_CLASS_OF_DEV,
 -                                                conn->dev_class, 3);
 -                      skb_put(skb, 5);
 -              }
 +              if (memcmp(conn->dev_class, "\0\0\0", sizeof(conn->dev_class)))
 +                      eir_len += eir_skb_put_data(skb, EIR_CLASS_OF_DEV,
 +                                                  conn->dev_class, sizeof(conn->dev_class));
        }
  
        ev->eir_len = cpu_to_le16(eir_len);
@@@ -9615,116 -9616,12 +9615,116 @@@ static bool is_filter_match(struct hci_
        return true;
  }
  
 +void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle,
 +                                bdaddr_t *bdaddr, u8 addr_type)
 +{
 +      struct mgmt_ev_adv_monitor_device_lost ev;
 +
 +      ev.monitor_handle = cpu_to_le16(handle);
 +      bacpy(&ev.addr.bdaddr, bdaddr);
 +      ev.addr.type = addr_type;
 +
 +      mgmt_event(MGMT_EV_ADV_MONITOR_DEVICE_LOST, hdev, &ev, sizeof(ev),
 +                 NULL);
 +}
 +
 +static void mgmt_adv_monitor_device_found(struct hci_dev *hdev,
 +                                        bdaddr_t *bdaddr, bool report_device,
 +                                        struct sk_buff *skb,
 +                                        struct sock *skip_sk)
 +{
 +      struct sk_buff *advmon_skb;
 +      size_t advmon_skb_len;
 +      __le16 *monitor_handle;
 +      struct monitored_device *dev, *tmp;
 +      bool matched = false;
 +      bool notify = false;
 +
 +      /* We have received the Advertisement Report because:
 +       * 1. the kernel has initiated active discovery
 +       * 2. if not, we have pend_le_reports > 0 in which case we are doing
 +       *    passive scanning
 +       * 3. if none of the above is true, we have one or more active
 +       *    Advertisement Monitor
 +       *
 +       * For case 1 and 2, report all advertisements via MGMT_EV_DEVICE_FOUND
 +       * and report ONLY one advertisement per device for the matched Monitor
 +       * via MGMT_EV_ADV_MONITOR_DEVICE_FOUND event.
 +       *
 +       * For case 3, since we are not active scanning and all advertisements
 +       * received are due to a matched Advertisement Monitor, report all
 +       * advertisements ONLY via MGMT_EV_ADV_MONITOR_DEVICE_FOUND event.
 +       */
 +      if (report_device && !hdev->advmon_pend_notify) {
 +              mgmt_event_skb(skb, skip_sk);
 +              return;
 +      }
 +
 +      advmon_skb_len = (sizeof(struct mgmt_ev_adv_monitor_device_found) -
 +                        sizeof(struct mgmt_ev_device_found)) + skb->len;
 +      advmon_skb = mgmt_alloc_skb(hdev, MGMT_EV_ADV_MONITOR_DEVICE_FOUND,
 +                                  advmon_skb_len);
 +      if (!advmon_skb) {
 +              if (report_device)
 +                      mgmt_event_skb(skb, skip_sk);
 +              else
 +                      kfree_skb(skb);
 +              return;
 +      }
 +
 +      /* ADV_MONITOR_DEVICE_FOUND is similar to DEVICE_FOUND event except
 +       * that it also has 'monitor_handle'. Make a copy of DEVICE_FOUND and
 +       * store monitor_handle of the matched monitor.
 +       */
 +      monitor_handle = skb_put(advmon_skb, sizeof(*monitor_handle));
 +      skb_put_data(advmon_skb, skb->data, skb->len);
 +
 +      hdev->advmon_pend_notify = false;
 +
 +      list_for_each_entry_safe(dev, tmp, &hdev->monitored_devices, list) {
 +              if (!bacmp(&dev->bdaddr, bdaddr)) {
 +                      matched = true;
 +
 +                      if (!dev->notified) {
 +                              *monitor_handle = cpu_to_le16(dev->handle);
 +                              notify = true;
 +                              dev->notified = true;
 +                      }
 +              }
 +
 +              if (!dev->notified)
 +                      hdev->advmon_pend_notify = true;
 +      }
 +
 +      if (!report_device &&
 +          ((matched && !notify) || !msft_monitor_supported(hdev))) {
 +              /* Handle 0 indicates that we are not active scanning and this
 +               * is a subsequent advertisement report for an already matched
 +               * Advertisement Monitor or the controller offloading support
 +               * is not available.
 +               */
 +              *monitor_handle = 0;
 +              notify = true;
 +      }
 +
 +      if (report_device)
 +              mgmt_event_skb(skb, skip_sk);
 +      else
 +              kfree_skb(skb);
 +
 +      if (notify)
 +              mgmt_event_skb(advmon_skb, skip_sk);
 +      else
 +              kfree_skb(advmon_skb);
 +}
 +
  void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                       u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
                       u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
  {
        struct sk_buff *skb;
        struct mgmt_ev_device_found *ev;
 +      bool report_device = hci_discovery_active(hdev);
  
        /* Don't send events for a non-kernel initiated discovery. With
         * LE one exception is if we have pend_le_reports > 0 in which
        if (!hci_discovery_active(hdev)) {
                if (link_type == ACL_LINK)
                        return;
 -              if (link_type == LE_LINK &&
 -                  list_empty(&hdev->pend_le_reports) &&
 -                  !hci_is_adv_monitoring(hdev)) {
 +              if (link_type == LE_LINK && !list_empty(&hdev->pend_le_reports))
 +                      report_device = true;
 +              else if (!hci_is_adv_monitoring(hdev))
                        return;
 -              }
        }
  
        if (hdev->discovery.result_filtering) {
  
        ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
  
 -      mgmt_event_skb(skb, NULL);
 +      mgmt_adv_monitor_device_found(hdev, bdaddr, report_device, skb, NULL);
  }
  
  void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
  {
        struct sk_buff *skb;
        struct mgmt_ev_device_found *ev;
 -      u16 eir_len;
 -      u32 flags;
 +      u16 eir_len = 0;
 +      u32 flags = 0;
  
 -      if (name_len)
 -              skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_FOUND, 2 + name_len);
 -      else
 -              skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_FOUND, 0);
 +      skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_FOUND,
 +                           sizeof(*ev) + (name ? eir_precalc_len(name_len) : 0));
  
        ev = skb_put(skb, sizeof(*ev));
        bacpy(&ev->addr.bdaddr, bdaddr);
        ev->addr.type = link_to_bdaddr(link_type, addr_type);
        ev->rssi = rssi;
  
 -      if (name) {
 -              eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
 -                                        name_len);
 -              flags = 0;
 -              skb_put(skb, eir_len);
 -      } else {
 -              eir_len = 0;
 +      if (name)
 +              eir_len += eir_skb_put_data(skb, EIR_NAME_COMPLETE, name, name_len);
 +      else
                flags = MGMT_DEV_FOUND_NAME_REQUEST_FAILED;
 -      }
  
        ev->eir_len = cpu_to_le16(eir_len);
        ev->flags = cpu_to_le32(flags);
diff --combined net/core/gro.c
@@@ -92,6 -92,31 +92,31 @@@ void dev_remove_offload(struct packet_o
  }
  EXPORT_SYMBOL(dev_remove_offload);
  
+ /**
+  *    skb_eth_gso_segment - segmentation handler for ethernet protocols.
+  *    @skb: buffer to segment
+  *    @features: features for the output path (see dev->features)
+  *    @type: Ethernet Protocol ID
+  */
+ struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb,
+                                   netdev_features_t features, __be16 type)
+ {
+       struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
+       struct packet_offload *ptype;
+       rcu_read_lock();
+       list_for_each_entry_rcu(ptype, &offload_base, list) {
+               if (ptype->type == type && ptype->callbacks.gso_segment) {
+                       segs = ptype->callbacks.gso_segment(skb, features);
+                       break;
+               }
+       }
+       rcu_read_unlock();
+       return segs;
+ }
+ EXPORT_SYMBOL(skb_eth_gso_segment);
  /**
   *    skb_mac_gso_segment - mac layer segmentation handler.
   *    @skb: buffer to segment
@@@ -459,22 -484,29 +484,22 @@@ static enum gro_result dev_gro_receive(
  
                skb_set_network_header(skb, skb_gro_offset(skb));
                skb_reset_mac_len(skb);
 -              NAPI_GRO_CB(skb)->same_flow = 0;
 +              BUILD_BUG_ON(sizeof_field(struct napi_gro_cb, zeroed) != sizeof(u32));
 +              BUILD_BUG_ON(!IS_ALIGNED(offsetof(struct napi_gro_cb, zeroed),
 +                                       sizeof(u32))); /* Avoid slow unaligned acc */
 +              *(u32 *)&NAPI_GRO_CB(skb)->zeroed = 0;
                NAPI_GRO_CB(skb)->flush = skb_is_gso(skb) || skb_has_frag_list(skb);
 -              NAPI_GRO_CB(skb)->free = 0;
 -              NAPI_GRO_CB(skb)->encap_mark = 0;
 -              NAPI_GRO_CB(skb)->recursion_counter = 0;
 -              NAPI_GRO_CB(skb)->is_fou = 0;
                NAPI_GRO_CB(skb)->is_atomic = 1;
 -              NAPI_GRO_CB(skb)->gro_remcsum_start = 0;
  
                /* Setup for GRO checksum validation */
                switch (skb->ip_summed) {
                case CHECKSUM_COMPLETE:
                        NAPI_GRO_CB(skb)->csum = skb->csum;
                        NAPI_GRO_CB(skb)->csum_valid = 1;
 -                      NAPI_GRO_CB(skb)->csum_cnt = 0;
                        break;
                case CHECKSUM_UNNECESSARY:
                        NAPI_GRO_CB(skb)->csum_cnt = skb->csum_level + 1;
 -                      NAPI_GRO_CB(skb)->csum_valid = 0;
                        break;
 -              default:
 -                      NAPI_GRO_CB(skb)->csum_cnt = 0;
 -                      NAPI_GRO_CB(skb)->csum_valid = 0;
                }
  
                pp = INDIRECT_CALL_INET(ptype->callbacks.gro_receive,
@@@ -627,6 -659,7 +652,6 @@@ static void napi_reuse_skb(struct napi_
  
        skb->encapsulation = 0;
        skb_shinfo(skb)->gso_type = 0;
 -      skb->truesize = SKB_TRUESIZE(skb_end_offset(skb));
        if (unlikely(skb->slow_gro)) {
                skb_orphan(skb);
                skb_ext_reset(skb);
diff --combined net/core/xdp.c
@@@ -162,9 -162,8 +162,9 @@@ static void xdp_rxq_info_init(struct xd
  }
  
  /* Returns 0 on success, negative on failure */
 -int xdp_rxq_info_reg(struct xdp_rxq_info *xdp_rxq,
 -                   struct net_device *dev, u32 queue_index, unsigned int napi_id)
 +int __xdp_rxq_info_reg(struct xdp_rxq_info *xdp_rxq,
 +                     struct net_device *dev, u32 queue_index,
 +                     unsigned int napi_id, u32 frag_size)
  {
        if (!dev) {
                WARN(1, "Missing net_device from driver");
        xdp_rxq->dev = dev;
        xdp_rxq->queue_index = queue_index;
        xdp_rxq->napi_id = napi_id;
 +      xdp_rxq->frag_size = frag_size;
  
        xdp_rxq->reg_state = REG_STATE_REGISTERED;
        return 0;
  }
 -EXPORT_SYMBOL_GPL(xdp_rxq_info_reg);
 +EXPORT_SYMBOL_GPL(__xdp_rxq_info_reg);
  
  void xdp_rxq_info_unused(struct xdp_rxq_info *xdp_rxq)
  {
@@@ -359,7 -357,8 +359,8 @@@ int xdp_rxq_info_reg_mem_model(struct x
        if (IS_ERR(xdp_alloc))
                return PTR_ERR(xdp_alloc);
  
-       trace_mem_connect(xdp_alloc, xdp_rxq);
+       if (trace_mem_connect_enabled() && xdp_alloc)
+               trace_mem_connect(xdp_alloc, xdp_rxq);
        return 0;
  }
  
@@@ -371,8 -370,8 +372,8 @@@ EXPORT_SYMBOL_GPL(xdp_rxq_info_reg_mem_
   * is used for those calls sites.  Thus, allowing for faster recycling
   * of xdp_frames/pages in those cases.
   */
 -static void __xdp_return(void *data, struct xdp_mem_info *mem, bool napi_direct,
 -                       struct xdp_buff *xdp)
 +void __xdp_return(void *data, struct xdp_mem_info *mem, bool napi_direct,
 +                struct xdp_buff *xdp)
  {
        struct xdp_mem_allocator *xa;
        struct page *page;
  
  void xdp_return_frame(struct xdp_frame *xdpf)
  {
 +      struct skb_shared_info *sinfo;
 +      int i;
 +
 +      if (likely(!xdp_frame_has_frags(xdpf)))
 +              goto out;
 +
 +      sinfo = xdp_get_shared_info_from_frame(xdpf);
 +      for (i = 0; i < sinfo->nr_frags; i++) {
 +              struct page *page = skb_frag_page(&sinfo->frags[i]);
 +
 +              __xdp_return(page_address(page), &xdpf->mem, false, NULL);
 +      }
 +out:
        __xdp_return(xdpf->data, &xdpf->mem, false, NULL);
  }
  EXPORT_SYMBOL_GPL(xdp_return_frame);
  
  void xdp_return_frame_rx_napi(struct xdp_frame *xdpf)
  {
 +      struct skb_shared_info *sinfo;
 +      int i;
 +
 +      if (likely(!xdp_frame_has_frags(xdpf)))
 +              goto out;
 +
 +      sinfo = xdp_get_shared_info_from_frame(xdpf);
 +      for (i = 0; i < sinfo->nr_frags; i++) {
 +              struct page *page = skb_frag_page(&sinfo->frags[i]);
 +
 +              __xdp_return(page_address(page), &xdpf->mem, true, NULL);
 +      }
 +out:
        __xdp_return(xdpf->data, &xdpf->mem, true, NULL);
  }
  EXPORT_SYMBOL_GPL(xdp_return_frame_rx_napi);
@@@ -475,7 -448,7 +476,7 @@@ void xdp_return_frame_bulk(struct xdp_f
        struct xdp_mem_allocator *xa;
  
        if (mem->type != MEM_TYPE_PAGE_POOL) {
 -              __xdp_return(xdpf->data, &xdpf->mem, false, NULL);
 +              xdp_return_frame(xdpf);
                return;
        }
  
                bq->xa = rhashtable_lookup(mem_id_ht, &mem->id, mem_id_rht_params);
        }
  
 +      if (unlikely(xdp_frame_has_frags(xdpf))) {
 +              struct skb_shared_info *sinfo;
 +              int i;
 +
 +              sinfo = xdp_get_shared_info_from_frame(xdpf);
 +              for (i = 0; i < sinfo->nr_frags; i++) {
 +                      skb_frag_t *frag = &sinfo->frags[i];
 +
 +                      bq->q[bq->count++] = skb_frag_address(frag);
 +                      if (bq->count == XDP_BULK_QUEUE_SIZE)
 +                              xdp_flush_frame_bulk(bq);
 +              }
 +      }
        bq->q[bq->count++] = xdpf->data;
  }
  EXPORT_SYMBOL_GPL(xdp_return_frame_bulk);
  
  void xdp_return_buff(struct xdp_buff *xdp)
  {
 +      struct skb_shared_info *sinfo;
 +      int i;
 +
 +      if (likely(!xdp_buff_has_frags(xdp)))
 +              goto out;
 +
 +      sinfo = xdp_get_shared_info_from_buff(xdp);
 +      for (i = 0; i < sinfo->nr_frags; i++) {
 +              struct page *page = skb_frag_page(&sinfo->frags[i]);
 +
 +              __xdp_return(page_address(page), &xdp->rxq->mem, true, xdp);
 +      }
 +out:
        __xdp_return(xdp->data, &xdp->rxq->mem, true, xdp);
  }
  
@@@ -615,14 -562,8 +616,14 @@@ struct sk_buff *__xdp_build_skb_from_fr
                                           struct sk_buff *skb,
                                           struct net_device *dev)
  {
 +      struct skb_shared_info *sinfo = xdp_get_shared_info_from_frame(xdpf);
        unsigned int headroom, frame_size;
        void *hard_start;
 +      u8 nr_frags;
 +
 +      /* xdp frags frame */
 +      if (unlikely(xdp_frame_has_frags(xdpf)))
 +              nr_frags = sinfo->nr_frags;
  
        /* Part of headroom was reserved to xdpf */
        headroom = sizeof(*xdpf) + xdpf->headroom;
        if (xdpf->metasize)
                skb_metadata_set(skb, xdpf->metasize);
  
 +      if (unlikely(xdp_frame_has_frags(xdpf)))
 +              xdp_update_skb_shared_info(skb, nr_frags,
 +                                         sinfo->xdp_frags_size,
 +                                         nr_frags * xdpf->frame_sz,
 +                                         xdp_frame_is_frag_pfmemalloc(xdpf));
 +
        /* Essential SKB info: protocol and skb->dev */
        skb->protocol = eth_type_trans(skb, dev);
  
diff --combined net/dsa/dsa2.c
@@@ -15,7 -15,6 +15,7 @@@
  #include <linux/of.h>
  #include <linux/of_net.h>
  #include <net/devlink.h>
 +#include <net/sch_generic.h>
  
  #include "dsa_priv.h"
  
@@@ -72,24 -71,27 +72,24 @@@ int dsa_broadcast(unsigned long e, voi
  }
  
  /**
 - * dsa_lag_map() - Map LAG netdev to a linear LAG ID
 + * dsa_lag_map() - Map LAG structure to a linear LAG array
   * @dst: Tree in which to record the mapping.
 - * @lag: Netdev that is to be mapped to an ID.
 + * @lag: LAG structure that is to be mapped to the tree's array.
   *
 - * dsa_lag_id/dsa_lag_dev can then be used to translate between the
 + * dsa_lag_id/dsa_lag_by_id can then be used to translate between the
   * two spaces. The size of the mapping space is determined by the
   * driver by setting ds->num_lag_ids. It is perfectly legal to leave
   * it unset if it is not needed, in which case these functions become
   * no-ops.
   */
 -void dsa_lag_map(struct dsa_switch_tree *dst, struct net_device *lag)
 +void dsa_lag_map(struct dsa_switch_tree *dst, struct dsa_lag *lag)
  {
        unsigned int id;
  
 -      if (dsa_lag_id(dst, lag) >= 0)
 -              /* Already mapped */
 -              return;
 -
 -      for (id = 0; id < dst->lags_len; id++) {
 -              if (!dsa_lag_dev(dst, id)) {
 -                      dst->lags[id] = lag;
 +      for (id = 1; id <= dst->lags_len; id++) {
 +              if (!dsa_lag_by_id(dst, id)) {
 +                      dst->lags[id - 1] = lag;
 +                      lag->id = id;
                        return;
                }
        }
  /**
   * dsa_lag_unmap() - Remove a LAG ID mapping
   * @dst: Tree in which the mapping is recorded.
 - * @lag: Netdev that was mapped.
 + * @lag: LAG structure that was mapped.
   *
   * As there may be multiple users of the mapping, it is only removed
   * if there are no other references to it.
   */
 -void dsa_lag_unmap(struct dsa_switch_tree *dst, struct net_device *lag)
 +void dsa_lag_unmap(struct dsa_switch_tree *dst, struct dsa_lag *lag)
  {
 -      struct dsa_port *dp;
        unsigned int id;
  
 -      dsa_lag_foreach_port(dp, dst, lag)
 -              /* There are remaining users of this mapping */
 -              return;
 -
        dsa_lags_foreach_id(id, dst) {
 -              if (dsa_lag_dev(dst, id) == lag) {
 -                      dst->lags[id] = NULL;
 +              if (dsa_lag_by_id(dst, id) == lag) {
 +                      dst->lags[id - 1] = NULL;
 +                      lag->id = 0;
                        break;
                }
        }
  }
  
 +struct dsa_lag *dsa_tree_lag_find(struct dsa_switch_tree *dst,
 +                                const struct net_device *lag_dev)
 +{
 +      struct dsa_port *dp;
 +
 +      list_for_each_entry(dp, &dst->ports, list)
 +              if (dsa_port_lag_dev_get(dp) == lag_dev)
 +                      return dp->lag;
 +
 +      return NULL;
 +}
 +
  struct dsa_bridge *dsa_tree_bridge_find(struct dsa_switch_tree *dst,
                                        const struct net_device *br)
  {
@@@ -457,6 -451,10 +457,6 @@@ static int dsa_port_setup(struct dsa_po
        if (dp->setup)
                return 0;
  
 -      mutex_init(&dp->addr_lists_lock);
 -      INIT_LIST_HEAD(&dp->fdbs);
 -      INIT_LIST_HEAD(&dp->mdbs);
 -
        if (ds->ops->port_setup) {
                err = ds->ops->port_setup(ds, dp->index);
                if (err)
@@@ -562,6 -560,7 +562,6 @@@ static void dsa_port_teardown(struct ds
  {
        struct devlink_port *dlp = &dp->devlink_port;
        struct dsa_switch *ds = dp->ds;
 -      struct dsa_mac_addr *a, *tmp;
        struct net_device *slave;
  
        if (!dp->setup)
                break;
        }
  
 -      list_for_each_entry_safe(a, tmp, &dp->fdbs, list) {
 -              list_del(&a->list);
 -              kfree(a);
 -      }
 -
 -      list_for_each_entry_safe(a, tmp, &dp->mdbs, list) {
 -              list_del(&a->list);
 -              kfree(a);
 -      }
 -
        dp->setup = false;
  }
  
@@@ -1049,30 -1058,21 +1049,30 @@@ static int dsa_tree_setup_switches(stru
  static int dsa_tree_setup_master(struct dsa_switch_tree *dst)
  {
        struct dsa_port *dp;
-       int err;
+       int err = 0;
  
        rtnl_lock();
  
        list_for_each_entry(dp, &dst->ports, list) {
                if (dsa_port_is_cpu(dp)) {
 -                      err = dsa_master_setup(dp->master, dp);
 +                      struct net_device *master = dp->master;
 +                      bool admin_up = (master->flags & IFF_UP) &&
 +                                      !qdisc_tx_is_noop(master);
 +
 +                      err = dsa_master_setup(master, dp);
                        if (err)
-                               return err;
+                               break;
 +
 +                      /* Replay master state event */
 +                      dsa_tree_master_admin_state_change(dst, master, admin_up);
 +                      dsa_tree_master_oper_state_change(dst, master,
 +                                                        netif_oper_up(master));
                }
        }
  
        rtnl_unlock();
  
-       return 0;
+       return err;
  }
  
  static void dsa_tree_teardown_master(struct dsa_switch_tree *dst)
  
        rtnl_lock();
  
 -      list_for_each_entry(dp, &dst->ports, list)
 -              if (dsa_port_is_cpu(dp))
 -                      dsa_master_teardown(dp->master);
 +      list_for_each_entry(dp, &dst->ports, list) {
 +              if (dsa_port_is_cpu(dp)) {
 +                      struct net_device *master = dp->master;
 +
 +                      /* Synthesizing an "admin down" state is sufficient for
 +                       * the switches to get a notification if the master is
 +                       * currently up and running.
 +                       */
 +                      dsa_tree_master_admin_state_change(dst, master, false);
 +
 +                      dsa_master_teardown(master);
 +              }
 +      }
  
        rtnl_unlock();
  }
@@@ -1289,52 -1279,6 +1289,52 @@@ out_unlock
        return err;
  }
  
 +static void dsa_tree_master_state_change(struct dsa_switch_tree *dst,
 +                                       struct net_device *master)
 +{
 +      struct dsa_notifier_master_state_info info;
 +      struct dsa_port *cpu_dp = master->dsa_ptr;
 +
 +      info.master = master;
 +      info.operational = dsa_port_master_is_operational(cpu_dp);
 +
 +      dsa_tree_notify(dst, DSA_NOTIFIER_MASTER_STATE_CHANGE, &info);
 +}
 +
 +void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst,
 +                                      struct net_device *master,
 +                                      bool up)
 +{
 +      struct dsa_port *cpu_dp = master->dsa_ptr;
 +      bool notify = false;
 +
 +      if ((dsa_port_master_is_operational(cpu_dp)) !=
 +          (up && cpu_dp->master_oper_up))
 +              notify = true;
 +
 +      cpu_dp->master_admin_up = up;
 +
 +      if (notify)
 +              dsa_tree_master_state_change(dst, master);
 +}
 +
 +void dsa_tree_master_oper_state_change(struct dsa_switch_tree *dst,
 +                                     struct net_device *master,
 +                                     bool up)
 +{
 +      struct dsa_port *cpu_dp = master->dsa_ptr;
 +      bool notify = false;
 +
 +      if ((dsa_port_master_is_operational(cpu_dp)) !=
 +          (cpu_dp->master_admin_up && up))
 +              notify = true;
 +
 +      cpu_dp->master_oper_up = up;
 +
 +      if (notify)
 +              dsa_tree_master_state_change(dst, master);
 +}
 +
  static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index)
  {
        struct dsa_switch_tree *dst = ds->dst;
        dp->ds = ds;
        dp->index = index;
  
 +      mutex_init(&dp->addr_lists_lock);
 +      mutex_init(&dp->vlans_lock);
 +      INIT_LIST_HEAD(&dp->fdbs);
 +      INIT_LIST_HEAD(&dp->mdbs);
 +      INIT_LIST_HEAD(&dp->vlans);
        INIT_LIST_HEAD(&dp->list);
        list_add_tail(&dp->list, &dst->ports);
  
@@@ -1694,9 -1633,6 +1694,9 @@@ static void dsa_switch_release_ports(st
        struct dsa_port *dp, *next;
  
        dsa_switch_for_each_port_safe(dp, next, ds) {
 +              WARN_ON(!list_empty(&dp->fdbs));
 +              WARN_ON(!list_empty(&dp->mdbs));
 +              WARN_ON(!list_empty(&dp->vlans));
                list_del(&dp->list);
                kfree(dp);
        }
diff --combined net/tipc/bearer.c
@@@ -352,16 -352,18 +352,18 @@@ static int tipc_enable_bearer(struct ne
                goto rejected;
        }
  
-       test_and_set_bit_lock(0, &b->up);
-       rcu_assign_pointer(tn->bearer_list[bearer_id], b);
-       if (skb)
-               tipc_bearer_xmit_skb(net, bearer_id, skb, &b->bcast_addr);
+       /* Create monitoring data before accepting activate messages */
        if (tipc_mon_create(net, bearer_id)) {
                bearer_disable(net, b);
+               kfree_skb(skb);
                return -ENOMEM;
        }
  
+       test_and_set_bit_lock(0, &b->up);
+       rcu_assign_pointer(tn->bearer_list[bearer_id], b);
+       if (skb)
+               tipc_bearer_xmit_skb(net, bearer_id, skb, &b->bcast_addr);
        pr_info("Enabled bearer <%s>, priority %u\n", name, prio);
  
        return res;
@@@ -768,7 -770,7 +770,7 @@@ void tipc_clone_to_loopback(struct net 
                skb->pkt_type = PACKET_HOST;
                skb->ip_summed = CHECKSUM_UNNECESSARY;
                skb->protocol = eth_type_trans(skb, dev);
 -              netif_rx_ni(skb);
 +              netif_rx(skb);
        }
  }
  
@@@ -190,7 -190,7 +190,7 @@@ static void xfrmi_dev_uninit(struct net
  
  static void xfrmi_scrub_packet(struct sk_buff *skb, bool xnet)
  {
 -      skb->tstamp = 0;
 +      skb_clear_tstamp(skb);
        skb->pkt_type = PACKET_HOST;
        skb->skb_iif = 0;
        skb->ignore_df = 0;
@@@ -304,7 -304,10 +304,10 @@@ xfrmi_xmit2(struct sk_buff *skb, struc
                        if (mtu < IPV6_MIN_MTU)
                                mtu = IPV6_MIN_MTU;
  
-                       icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+                       if (skb->len > 1280)
+                               icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+                       else
+                               goto xmit;
                } else {
                        if (!(ip_hdr(skb)->frag_off & htons(IP_DF)))
                                goto xmit;