Merge tag 'mlx5-fixes-2019-07-11' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorDavid S. Miller <davem@davemloft.net>
Thu, 11 Jul 2019 22:06:37 +0000 (15:06 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 11 Jul 2019 22:06:37 +0000 (15:06 -0700)
Saeed Mahameed says:

====================
Mellanox, mlx5 fixes 2019-07-11

This series introduces some fixes to mlx5 driver.

Please pull and let me know if there is any problem.

For -stable v4.15
('net/mlx5e: IPoIB, Add error path in mlx5_rdma_setup_rn')

For -stable v5.1
('net/mlx5e: Fix port tunnel GRE entropy control')
('net/mlx5e: Rx, Fix checksum calculation for new hardware')
('net/mlx5e: Fix return value from timeout recover function')
('net/mlx5e: Fix error flow in tx reporter diagnose')

For -stable v5.2
('net/mlx5: E-Switch, Fix default encap mode')

Conflict note: This pull request will produce a small conflict when
merged with net-next.
In drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
Take the hunk from net and replace:
esw_offloads_steering_init(esw, vf_nvports, total_nvports);
with:
esw_offloads_steering_init(esw);
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
1  2 
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
include/linux/mlx5/mlx5_ifc.h

@@@ -48,7 -48,7 +48,7 @@@
  #include <linux/rhashtable.h>
  #include <net/switchdev.h>
  #include <net/xdp.h>
 -#include <linux/net_dim.h>
 +#include <linux/dim.h>
  #include <linux/bits.h>
  #include "wq.h"
  #include "mlx5_core.h"
@@@ -137,7 -137,6 +137,7 @@@ struct page_pool
  #define MLX5E_MAX_NUM_CHANNELS         (MLX5E_INDIR_RQT_SIZE >> 1)
  #define MLX5E_MAX_NUM_SQS              (MLX5E_MAX_NUM_CHANNELS * MLX5E_MAX_NUM_TC)
  #define MLX5E_TX_CQ_POLL_BUDGET        128
 +#define MLX5E_TX_XSK_POLL_BUDGET       64
  #define MLX5E_SQ_RECOVER_MIN_INTERVAL  500 /* msecs */
  
  #define MLX5E_UMR_WQE_INLINE_SZ \
@@@ -156,11 -155,6 +156,11 @@@ do 
                            ##__VA_ARGS__);                     \
  } while (0)
  
 +enum mlx5e_rq_group {
 +      MLX5E_RQ_GROUP_REGULAR,
 +      MLX5E_RQ_GROUP_XSK,
 +      MLX5E_NUM_RQ_GROUPS /* Keep last. */
 +};
  
  static inline u16 mlx5_min_rx_wqes(int wq_type, u32 wq_size)
  {
@@@ -185,8 -179,7 +185,8 @@@ static inline int mlx5e_get_max_num_cha
  /* Use this function to get max num channels after netdev was created */
  static inline int mlx5e_get_netdev_max_channels(struct net_device *netdev)
  {
 -      return min_t(unsigned int, netdev->num_rx_queues,
 +      return min_t(unsigned int,
 +                   netdev->num_rx_queues / MLX5E_NUM_RQ_GROUPS,
                     netdev->num_tx_queues);
  }
  
@@@ -209,10 -202,7 +209,10 @@@ struct mlx5e_umr_wqe 
        struct mlx5_wqe_ctrl_seg       ctrl;
        struct mlx5_wqe_umr_ctrl_seg   uctrl;
        struct mlx5_mkey_seg           mkc;
 -      struct mlx5_mtt                inline_mtts[0];
 +      union {
 +              struct mlx5_mtt        inline_mtts[0];
 +              u8                     tls_static_params_ctx[0];
 +      };
  };
  
  extern const char mlx5e_self_tests[][ETH_GSTRING_LEN];
@@@ -248,9 -238,9 +248,9 @@@ struct mlx5e_params 
        u16 num_channels;
        u8  num_tc;
        bool rx_cqe_compress_def;
 -      struct net_dim_cq_moder rx_cq_moderation;
 -      struct net_dim_cq_moder tx_cq_moderation;
        bool tunneled_offload_en;
 +      struct dim_cq_moder rx_cq_moderation;
 +      struct dim_cq_moder tx_cq_moderation;
        bool lro_en;
        u8  tx_min_inline_mode;
        bool vlan_strip_disable;
        u32 lro_timeout;
        u32 pflags;
        struct bpf_prog *xdp_prog;
 +      struct mlx5e_xsk *xsk;
        unsigned int sw_mtu;
        int hard_mtu;
  };
@@@ -305,6 -294,7 +305,7 @@@ enum 
        MLX5E_RQ_STATE_ENABLED,
        MLX5E_RQ_STATE_AM,
        MLX5E_RQ_STATE_NO_CSUM_COMPLETE,
+       MLX5E_RQ_STATE_CSUM_FULL, /* cqe_csum_full hw bit is set */
  };
  
  struct mlx5e_cq {
@@@ -336,9 -326,6 +337,9 @@@ struct mlx5e_tx_wqe_info 
        u32 num_bytes;
        u8  num_wqebbs;
        u8  num_dma;
 +#ifdef CONFIG_MLX5_EN_TLS
 +      skb_frag_t *resync_dump_frag;
 +#endif
  };
  
  enum mlx5e_dma_map_type {
@@@ -362,13 -349,6 +363,13 @@@ enum 
  
  struct mlx5e_sq_wqe_info {
        u8  opcode;
 +
 +      /* Auxiliary data for different opcodes. */
 +      union {
 +              struct {
 +                      struct mlx5e_rq *rq;
 +              } umr;
 +      };
  };
  
  struct mlx5e_txqsq {
        /* dirtied @completion */
        u16                        cc;
        u32                        dma_fifo_cc;
 -      struct net_dim             dim; /* Adaptive Moderation */
 +      struct dim                 dim; /* Adaptive Moderation */
  
        /* dirtied @xmit */
        u16                        pc ____cacheline_aligned_in_smp;
        void __iomem              *uar_map;
        struct netdev_queue       *txq;
        u32                        sqn;
 +      u16                        stop_room;
        u8                         min_inline_mode;
        struct device             *pdev;
        __be32                     mkey_be;
  } ____cacheline_aligned_in_smp;
  
  struct mlx5e_dma_info {
 -      struct page     *page;
 -      dma_addr_t      addr;
 +      dma_addr_t addr;
 +      union {
 +              struct page *page;
 +              struct {
 +                      u64 handle;
 +                      void *data;
 +              } xsk;
 +      };
 +};
 +
 +/* XDP packets can be transmitted in different ways. On completion, we need to
 + * distinguish between them to clean up things in a proper way.
 + */
 +enum mlx5e_xdp_xmit_mode {
 +      /* An xdp_frame was transmitted due to either XDP_REDIRECT from another
 +       * device or XDP_TX from an XSK RQ. The frame has to be unmapped and
 +       * returned.
 +       */
 +      MLX5E_XDP_XMIT_MODE_FRAME,
 +
 +      /* The xdp_frame was created in place as a result of XDP_TX from a
 +       * regular RQ. No DMA remapping happened, and the page belongs to us.
 +       */
 +      MLX5E_XDP_XMIT_MODE_PAGE,
 +
 +      /* No xdp_frame was created at all, the transmit happened from a UMEM
 +       * page. The UMEM Completion Ring producer pointer has to be increased.
 +       */
 +      MLX5E_XDP_XMIT_MODE_XSK,
  };
  
  struct mlx5e_xdp_info {
 -      struct xdp_frame      *xdpf;
 -      dma_addr_t            dma_addr;
 -      struct mlx5e_dma_info di;
 +      enum mlx5e_xdp_xmit_mode mode;
 +      union {
 +              struct {
 +                      struct xdp_frame *xdpf;
 +                      dma_addr_t dma_addr;
 +              } frame;
 +              struct {
 +                      struct mlx5e_rq *rq;
 +                      struct mlx5e_dma_info di;
 +              } page;
 +      };
 +};
 +
 +struct mlx5e_xdp_xmit_data {
 +      dma_addr_t  dma_addr;
 +      void       *data;
 +      u32         len;
  };
  
  struct mlx5e_xdp_info_fifo {
@@@ -488,12 -426,8 +489,12 @@@ struct mlx5e_xdp_mpwqe 
  };
  
  struct mlx5e_xdpsq;
 -typedef bool (*mlx5e_fp_xmit_xdp_frame)(struct mlx5e_xdpsq*,
 -                                      struct mlx5e_xdp_info*);
 +typedef int (*mlx5e_fp_xmit_xdp_frame_check)(struct mlx5e_xdpsq *);
 +typedef bool (*mlx5e_fp_xmit_xdp_frame)(struct mlx5e_xdpsq *,
 +                                      struct mlx5e_xdp_xmit_data *,
 +                                      struct mlx5e_xdp_info *,
 +                                      int);
 +
  struct mlx5e_xdpsq {
        /* data path */
  
        struct mlx5e_cq            cq;
  
        /* read only */
 +      struct xdp_umem           *umem;
        struct mlx5_wq_cyc         wq;
        struct mlx5e_xdpsq_stats  *stats;
 +      mlx5e_fp_xmit_xdp_frame_check xmit_xdp_frame_check;
        mlx5e_fp_xmit_xdp_frame    xmit_xdp_frame;
        struct {
                struct mlx5e_xdp_wqe_info *wqe_info;
@@@ -556,6 -488,12 +557,6 @@@ struct mlx5e_icosq 
        struct mlx5e_channel      *channel;
  } ____cacheline_aligned_in_smp;
  
 -static inline bool
 -mlx5e_wqc_has_room_for(struct mlx5_wq_cyc *wq, u16 cc, u16 pc, u16 n)
 -{
 -      return (mlx5_wq_cyc_ctr2ix(wq, cc - pc) >= n) || (cc == pc);
 -}
 -
  struct mlx5e_wqe_frag_info {
        struct mlx5e_dma_info *di;
        u32 offset;
@@@ -634,11 -572,9 +635,11 @@@ struct mlx5e_rq 
                        u8                     log_stride_sz;
                        u8                     umr_in_progress;
                        u8                     umr_last_bulk;
 +                      u8                     umr_completed;
                } mpwqe;
        };
        struct {
 +              u16            umem_headroom;
                u16            headroom;
                u8             map_dir;   /* dma map direction */
        } buff;
        int                    ix;
        unsigned int           hw_mtu;
  
 -      struct net_dim         dim; /* Dynamic Interrupt Moderation */
 +      struct dim         dim; /* Dynamic Interrupt Moderation */
  
        /* XDP */
        struct bpf_prog       *xdp_prog;
 -      struct mlx5e_xdpsq     xdpsq;
 +      struct mlx5e_xdpsq    *xdpsq;
        DECLARE_BITMAP(flags, 8);
        struct page_pool      *page_pool;
  
 +      /* AF_XDP zero-copy */
 +      struct zero_copy_allocator zca;
 +      struct xdp_umem       *umem;
 +
        /* control */
        struct mlx5_wq_ctrl    wq_ctrl;
        __be32                 mkey_be;
        struct xdp_rxq_info    xdp_rxq;
  } ____cacheline_aligned_in_smp;
  
 +enum mlx5e_channel_state {
 +      MLX5E_CHANNEL_STATE_XSK,
 +      MLX5E_CHANNEL_NUM_STATES
 +};
 +
  struct mlx5e_channel {
        /* data path */
        struct mlx5e_rq            rq;
 +      struct mlx5e_xdpsq         rq_xdpsq;
        struct mlx5e_txqsq         sq[MLX5E_MAX_NUM_TC];
        struct mlx5e_icosq         icosq;   /* internal control operations */
        bool                       xdp;
        /* XDP_REDIRECT */
        struct mlx5e_xdpsq         xdpsq;
  
 +      /* AF_XDP zero-copy */
 +      struct mlx5e_rq            xskrq;
 +      struct mlx5e_xdpsq         xsksq;
 +      struct mlx5e_icosq         xskicosq;
 +      /* xskicosq can be accessed from any CPU - the spinlock protects it. */
 +      spinlock_t                 xskicosq_lock;
 +
        /* data path - accessed per napi poll */
        struct irq_desc *irq_desc;
        struct mlx5e_ch_stats     *stats;
        struct mlx5e_priv         *priv;
        struct mlx5_core_dev      *mdev;
        struct hwtstamp_config    *tstamp;
 +      DECLARE_BITMAP(state, MLX5E_CHANNEL_NUM_STATES);
        int                        ix;
        int                        cpu;
        cpumask_var_t              xps_cpumask;
@@@ -737,17 -655,14 +738,17 @@@ struct mlx5e_channel_stats 
        struct mlx5e_ch_stats ch;
        struct mlx5e_sq_stats sq[MLX5E_MAX_NUM_TC];
        struct mlx5e_rq_stats rq;
 +      struct mlx5e_rq_stats xskrq;
        struct mlx5e_xdpsq_stats rq_xdpsq;
        struct mlx5e_xdpsq_stats xdpsq;
 +      struct mlx5e_xdpsq_stats xsksq;
  } ____cacheline_aligned_in_smp;
  
  enum {
        MLX5E_STATE_OPENED,
        MLX5E_STATE_DESTROYING,
        MLX5E_STATE_XDP_TX_ENABLED,
 +      MLX5E_STATE_XDP_OPEN,
  };
  
  struct mlx5e_rqt {
@@@ -780,17 -695,6 +781,17 @@@ struct mlx5e_modify_sq_param 
        int rl_index;
  };
  
 +struct mlx5e_xsk {
 +      /* UMEMs are stored separately from channels, because we don't want to
 +       * lose them when channels are recreated. The kernel also stores UMEMs,
 +       * but it doesn't distinguish between zero-copy and non-zero-copy UMEMs,
 +       * so rely on our mechanism.
 +       */
 +      struct xdp_umem **umems;
 +      u16 refcnt;
 +      bool ever_used;
 +};
 +
  struct mlx5e_priv {
        /* priv data path fields - start */
        struct mlx5e_txqsq *txq2sq[MLX5E_MAX_NUM_CHANNELS * MLX5E_MAX_NUM_TC];
        struct mlx5e_tir           indir_tir[MLX5E_NUM_INDIR_TIRS];
        struct mlx5e_tir           inner_indir_tir[MLX5E_NUM_INDIR_TIRS];
        struct mlx5e_tir           direct_tir[MLX5E_MAX_NUM_CHANNELS];
 +      struct mlx5e_tir           xsk_tir[MLX5E_MAX_NUM_CHANNELS];
        struct mlx5e_rss_params    rss_params;
        u32                        tx_rates[MLX5E_MAX_NUM_SQS];
  
        struct mlx5e_tls          *tls;
  #endif
        struct devlink_health_reporter *tx_reporter;
 +      struct mlx5e_xsk           xsk;
  };
  
  struct mlx5e_profile {
        void    (*cleanup_tx)(struct mlx5e_priv *priv);
        void    (*enable)(struct mlx5e_priv *priv);
        void    (*disable)(struct mlx5e_priv *priv);
 +      int     (*update_rx)(struct mlx5e_priv *priv);
        void    (*update_stats)(struct mlx5e_priv *priv);
        void    (*update_carrier)(struct mlx5e_priv *priv);
        struct {
@@@ -881,7 -782,7 +882,7 @@@ netdev_tx_t mlx5e_sq_xmit(struct mlx5e_
                          struct mlx5e_tx_wqe *wqe, u16 pi, bool xmit_more);
  
  void mlx5e_trigger_irq(struct mlx5e_icosq *sq);
 -void mlx5e_completion_event(struct mlx5_core_cq *mcq);
 +void mlx5e_completion_event(struct mlx5_core_cq *mcq, struct mlx5_eqe *eqe);
  void mlx5e_cq_error_event(struct mlx5_core_cq *mcq, enum mlx5_event event);
  int mlx5e_napi_poll(struct napi_struct *napi, int budget);
  bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget);
@@@ -893,13 -794,11 +894,13 @@@ bool mlx5e_striding_rq_possible(struct 
                                struct mlx5e_params *params);
  
  void mlx5e_page_dma_unmap(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info);
 -void mlx5e_page_release(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info,
 -                      bool recycle);
 +void mlx5e_page_release_dynamic(struct mlx5e_rq *rq,
 +                              struct mlx5e_dma_info *dma_info,
 +                              bool recycle);
  void mlx5e_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe);
  void mlx5e_handle_rx_cqe_mpwrq(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe);
  bool mlx5e_post_rx_wqes(struct mlx5e_rq *rq);
 +void mlx5e_poll_ico_cq(struct mlx5e_cq *cq);
  bool mlx5e_post_rx_mpwqes(struct mlx5e_rq *rq);
  void mlx5e_dealloc_rx_wqe(struct mlx5e_rq *rq, u16 ix);
  void mlx5e_dealloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix);
@@@ -955,30 -854,6 +956,30 @@@ void mlx5e_build_indir_tir_ctx_hash(str
  void mlx5e_modify_tirs_hash(struct mlx5e_priv *priv, void *in, int inlen);
  struct mlx5e_tirc_config mlx5e_tirc_get_default_config(enum mlx5e_traffic_types tt);
  
 +struct mlx5e_xsk_param;
 +
 +struct mlx5e_rq_param;
 +int mlx5e_open_rq(struct mlx5e_channel *c, struct mlx5e_params *params,
 +                struct mlx5e_rq_param *param, struct mlx5e_xsk_param *xsk,
 +                struct xdp_umem *umem, struct mlx5e_rq *rq);
 +int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time);
 +void mlx5e_deactivate_rq(struct mlx5e_rq *rq);
 +void mlx5e_close_rq(struct mlx5e_rq *rq);
 +
 +struct mlx5e_sq_param;
 +int mlx5e_open_icosq(struct mlx5e_channel *c, struct mlx5e_params *params,
 +                   struct mlx5e_sq_param *param, struct mlx5e_icosq *sq);
 +void mlx5e_close_icosq(struct mlx5e_icosq *sq);
 +int mlx5e_open_xdpsq(struct mlx5e_channel *c, struct mlx5e_params *params,
 +                   struct mlx5e_sq_param *param, struct xdp_umem *umem,
 +                   struct mlx5e_xdpsq *sq, bool is_redirect);
 +void mlx5e_close_xdpsq(struct mlx5e_xdpsq *sq);
 +
 +struct mlx5e_cq_param;
 +int mlx5e_open_cq(struct mlx5e_channel *c, struct dim_cq_moder moder,
 +                struct mlx5e_cq_param *param, struct mlx5e_cq *cq);
 +void mlx5e_close_cq(struct mlx5e_cq *cq);
 +
  int mlx5e_open_locked(struct net_device *netdev);
  int mlx5e_close_locked(struct net_device *netdev);
  
@@@ -1024,6 -899,102 +1025,6 @@@ static inline bool mlx5_tx_swp_supporte
                MLX5_CAP_ETH(mdev, swp_csum) && MLX5_CAP_ETH(mdev, swp_lso);
  }
  
 -struct mlx5e_swp_spec {
 -      __be16 l3_proto;
 -      u8 l4_proto;
 -      u8 is_tun;
 -      __be16 tun_l3_proto;
 -      u8 tun_l4_proto;
 -};
 -
 -static inline void
 -mlx5e_set_eseg_swp(struct sk_buff *skb, struct mlx5_wqe_eth_seg *eseg,
 -                 struct mlx5e_swp_spec *swp_spec)
 -{
 -      /* SWP offsets are in 2-bytes words */
 -      eseg->swp_outer_l3_offset = skb_network_offset(skb) / 2;
 -      if (swp_spec->l3_proto == htons(ETH_P_IPV6))
 -              eseg->swp_flags |= MLX5_ETH_WQE_SWP_OUTER_L3_IPV6;
 -      if (swp_spec->l4_proto) {
 -              eseg->swp_outer_l4_offset = skb_transport_offset(skb) / 2;
 -              if (swp_spec->l4_proto == IPPROTO_UDP)
 -                      eseg->swp_flags |= MLX5_ETH_WQE_SWP_OUTER_L4_UDP;
 -      }
 -
 -      if (swp_spec->is_tun) {
 -              eseg->swp_inner_l3_offset = skb_inner_network_offset(skb) / 2;
 -              if (swp_spec->tun_l3_proto == htons(ETH_P_IPV6))
 -                      eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
 -      } else { /* typically for ipsec when xfrm mode != XFRM_MODE_TUNNEL */
 -              eseg->swp_inner_l3_offset = skb_network_offset(skb) / 2;
 -              if (swp_spec->l3_proto == htons(ETH_P_IPV6))
 -                      eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
 -      }
 -      switch (swp_spec->tun_l4_proto) {
 -      case IPPROTO_UDP:
 -              eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L4_UDP;
 -              /* fall through */
 -      case IPPROTO_TCP:
 -              eseg->swp_inner_l4_offset = skb_inner_transport_offset(skb) / 2;
 -              break;
 -      }
 -}
 -
 -static inline void mlx5e_sq_fetch_wqe(struct mlx5e_txqsq *sq,
 -                                    struct mlx5e_tx_wqe **wqe,
 -                                    u16 *pi)
 -{
 -      struct mlx5_wq_cyc *wq = &sq->wq;
 -
 -      *pi  = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
 -      *wqe = mlx5_wq_cyc_get_wqe(wq, *pi);
 -      memset(*wqe, 0, sizeof(**wqe));
 -}
 -
 -static inline
 -struct mlx5e_tx_wqe *mlx5e_post_nop(struct mlx5_wq_cyc *wq, u32 sqn, u16 *pc)
 -{
 -      u16                         pi   = mlx5_wq_cyc_ctr2ix(wq, *pc);
 -      struct mlx5e_tx_wqe        *wqe  = mlx5_wq_cyc_get_wqe(wq, pi);
 -      struct mlx5_wqe_ctrl_seg   *cseg = &wqe->ctrl;
 -
 -      memset(cseg, 0, sizeof(*cseg));
 -
 -      cseg->opmod_idx_opcode = cpu_to_be32((*pc << 8) | MLX5_OPCODE_NOP);
 -      cseg->qpn_ds           = cpu_to_be32((sqn << 8) | 0x01);
 -
 -      (*pc)++;
 -
 -      return wqe;
 -}
 -
 -static inline
 -void mlx5e_notify_hw(struct mlx5_wq_cyc *wq, u16 pc,
 -                   void __iomem *uar_map,
 -                   struct mlx5_wqe_ctrl_seg *ctrl)
 -{
 -      ctrl->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE;
 -      /* ensure wqe is visible to device before updating doorbell record */
 -      dma_wmb();
 -
 -      *wq->db = cpu_to_be32(pc);
 -
 -      /* ensure doorbell record is visible to device before ringing the
 -       * doorbell
 -       */
 -      wmb();
 -
 -      mlx5_write64((__be32 *)ctrl, uar_map);
 -}
 -
 -static inline void mlx5e_cq_arm(struct mlx5e_cq *cq)
 -{
 -      struct mlx5_core_cq *mcq;
 -
 -      mcq = &cq->mcq;
 -      mlx5_cq_arm(mcq, MLX5_CQ_DB_REQ_NOT, mcq->uar->map, cq->wq.cc);
 -}
 -
  extern const struct ethtool_ops mlx5e_ethtool_ops;
  #ifdef CONFIG_MLX5_CORE_EN_DCB
  extern const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops;
@@@ -1053,17 -1024,17 +1054,17 @@@ int mlx5e_create_indirect_rqt(struct ml
  int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc);
  void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv, bool inner_ttc);
  
 -int mlx5e_create_direct_rqts(struct mlx5e_priv *priv);
 -void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv);
 -int mlx5e_create_direct_tirs(struct mlx5e_priv *priv);
 -void mlx5e_destroy_direct_tirs(struct mlx5e_priv *priv);
 +int mlx5e_create_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs);
 +void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs);
 +int mlx5e_create_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs);
 +void mlx5e_destroy_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs);
  void mlx5e_destroy_rqt(struct mlx5e_priv *priv, struct mlx5e_rqt *rqt);
  
 -int mlx5e_create_tis(struct mlx5_core_dev *mdev, int tc,
 -                   u32 underlay_qpn, u32 *tisn);
 +int mlx5e_create_tis(struct mlx5_core_dev *mdev, void *in, u32 *tisn);
  void mlx5e_destroy_tis(struct mlx5_core_dev *mdev, u32 tisn);
  
  int mlx5e_create_tises(struct mlx5e_priv *priv);
 +int mlx5e_update_nic_rx(struct mlx5e_priv *priv);
  void mlx5e_update_carrier(struct mlx5e_priv *priv);
  int mlx5e_close(struct net_device *netdev);
  int mlx5e_open(struct net_device *netdev);
@@@ -1105,6 -1076,8 +1106,6 @@@ u32 mlx5e_ethtool_get_rxfh_key_size(str
  u32 mlx5e_ethtool_get_rxfh_indir_size(struct mlx5e_priv *priv);
  int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv,
                              struct ethtool_ts_info *info);
 -int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv,
 -                             struct ethtool_flash *flash);
  void mlx5e_ethtool_get_pauseparam(struct mlx5e_priv *priv,
                                  struct ethtool_pauseparam *pauseparam);
  int mlx5e_ethtool_set_pauseparam(struct mlx5e_priv *priv,
@@@ -1125,7 -1098,6 +1126,7 @@@ void mlx5e_detach_netdev(struct mlx5e_p
  void mlx5e_destroy_netdev(struct mlx5e_priv *priv);
  void mlx5e_set_netdev_mtu_boundaries(struct mlx5e_priv *priv);
  void mlx5e_build_nic_params(struct mlx5_core_dev *mdev,
 +                          struct mlx5e_xsk *xsk,
                            struct mlx5e_rss_params *rss_params,
                            struct mlx5e_params *params,
                            u16 max_channels, u16 mtu);
  #include <linux/bpf.h>
  #include <linux/if_bridge.h>
  #include <net/page_pool.h>
 +#include <net/xdp_sock.h>
  #include "eswitch.h"
  #include "en.h"
 +#include "en/txrx.h"
  #include "en_tc.h"
  #include "en_rep.h"
  #include "en_accel/ipsec.h"
  #include "en/monitor_stats.h"
  #include "en/reporter.h"
  #include "en/params.h"
 +#include "en/xsk/umem.h"
 +#include "en/xsk/setup.h"
 +#include "en/xsk/rx.h"
 +#include "en/xsk/tx.h"
  
 -struct mlx5e_rq_param {
 -      u32                     rqc[MLX5_ST_SZ_DW(rqc)];
 -      struct mlx5_wq_param    wq;
 -      struct mlx5e_rq_frags_info frags_info;
 -};
 -
 -struct mlx5e_sq_param {
 -      u32                        sqc[MLX5_ST_SZ_DW(sqc)];
 -      struct mlx5_wq_param       wq;
 -      bool                       is_mpw;
 -};
 -
 -struct mlx5e_cq_param {
 -      u32                        cqc[MLX5_ST_SZ_DW(cqc)];
 -      struct mlx5_wq_param       wq;
 -      u16                        eq_ix;
 -      u8                         cq_period_mode;
 -};
 -
 -struct mlx5e_channel_param {
 -      struct mlx5e_rq_param      rq;
 -      struct mlx5e_sq_param      sq;
 -      struct mlx5e_sq_param      xdp_sq;
 -      struct mlx5e_sq_param      icosq;
 -      struct mlx5e_cq_param      rx_cq;
 -      struct mlx5e_cq_param      tx_cq;
 -      struct mlx5e_cq_param      icosq_cq;
 -};
  
  bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev)
  {
@@@ -92,31 -114,18 +92,31 @@@ void mlx5e_init_rq_type_params(struct m
        mlx5_core_info(mdev, "MLX5E: StrdRq(%d) RqSz(%ld) StrdSz(%ld) RxCqeCmprss(%d)\n",
                       params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ,
                       params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ ?
 -                     BIT(mlx5e_mpwqe_get_log_rq_size(params)) :
 +                     BIT(mlx5e_mpwqe_get_log_rq_size(params, NULL)) :
                       BIT(params->log_rq_mtu_frames),
 -                     BIT(mlx5e_mpwqe_get_log_stride_size(mdev, params)),
 +                     BIT(mlx5e_mpwqe_get_log_stride_size(mdev, params, NULL)),
                       MLX5E_GET_PFLAG(params, MLX5E_PFLAG_RX_CQE_COMPRESS));
  }
  
  bool mlx5e_striding_rq_possible(struct mlx5_core_dev *mdev,
                                struct mlx5e_params *params)
  {
 -      return mlx5e_check_fragmented_striding_rq_cap(mdev) &&
 -              !MLX5_IPSEC_DEV(mdev) &&
 -              !(params->xdp_prog && !mlx5e_rx_mpwqe_is_linear_skb(mdev, params));
 +      if (!mlx5e_check_fragmented_striding_rq_cap(mdev))
 +              return false;
 +
 +      if (MLX5_IPSEC_DEV(mdev))
 +              return false;
 +
 +      if (params->xdp_prog) {
 +              /* XSK params are not considered here. If striding RQ is in use,
 +               * and an XSK is being opened, mlx5e_rx_mpwqe_is_linear_skb will
 +               * be called with the known XSK params.
 +               */
 +              if (!mlx5e_rx_mpwqe_is_linear_skb(mdev, params, NULL))
 +                      return false;
 +      }
 +
 +      return true;
  }
  
  void mlx5e_set_rq_type(struct mlx5_core_dev *mdev, struct mlx5e_params *params)
@@@ -385,8 -394,6 +385,8 @@@ static void mlx5e_free_di_list(struct m
  
  static int mlx5e_alloc_rq(struct mlx5e_channel *c,
                          struct mlx5e_params *params,
 +                        struct mlx5e_xsk_param *xsk,
 +                        struct xdp_umem *umem,
                          struct mlx5e_rq_param *rqp,
                          struct mlx5e_rq *rq)
  {
        struct mlx5_core_dev *mdev = c->mdev;
        void *rqc = rqp->rqc;
        void *rqc_wq = MLX5_ADDR_OF(rqc, rqc, wq);
 +      u32 num_xsk_frames = 0;
 +      u32 rq_xdp_ix;
        u32 pool_size;
        int wq_sz;
        int err;
        rq->ix      = c->ix;
        rq->mdev    = mdev;
        rq->hw_mtu  = MLX5E_SW2HW_MTU(params, params->sw_mtu);
 -      rq->stats   = &c->priv->channel_stats[c->ix].rq;
 +      rq->xdpsq   = &c->rq_xdpsq;
 +      rq->umem    = umem;
 +
 +      if (rq->umem)
 +              rq->stats = &c->priv->channel_stats[c->ix].xskrq;
 +      else
 +              rq->stats = &c->priv->channel_stats[c->ix].rq;
  
        rq->xdp_prog = params->xdp_prog ? bpf_prog_inc(params->xdp_prog) : NULL;
        if (IS_ERR(rq->xdp_prog)) {
                goto err_rq_wq_destroy;
        }
  
 -      err = xdp_rxq_info_reg(&rq->xdp_rxq, rq->netdev, rq->ix);
 +      rq_xdp_ix = rq->ix;
 +      if (xsk)
 +              rq_xdp_ix += params->num_channels * MLX5E_RQ_GROUP_XSK;
 +      err = xdp_rxq_info_reg(&rq->xdp_rxq, rq->netdev, rq_xdp_ix);
        if (err < 0)
                goto err_rq_wq_destroy;
  
        rq->buff.map_dir = rq->xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
 -      rq->buff.headroom = mlx5e_get_rq_headroom(mdev, params);
 +      rq->buff.headroom = mlx5e_get_rq_headroom(mdev, params, xsk);
 +      rq->buff.umem_headroom = xsk ? xsk->headroom : 0;
        pool_size = 1 << params->log_rq_mtu_frames;
  
        switch (rq->wq_type) {
  
                wq_sz = mlx5_wq_ll_get_size(&rq->mpwqe.wq);
  
 -              pool_size = MLX5_MPWRQ_PAGES_PER_WQE << mlx5e_mpwqe_get_log_rq_size(params);
 +              if (xsk)
 +                      num_xsk_frames = wq_sz <<
 +                              mlx5e_mpwqe_get_log_num_strides(mdev, params, xsk);
 +
 +              pool_size = MLX5_MPWRQ_PAGES_PER_WQE <<
 +                      mlx5e_mpwqe_get_log_rq_size(params, xsk);
  
                rq->post_wqes = mlx5e_post_rx_mpwqes;
                rq->dealloc_wqe = mlx5e_dealloc_rx_mpwqe;
                        goto err_rq_wq_destroy;
                }
  
 -              rq->mpwqe.skb_from_cqe_mpwrq =
 -                      mlx5e_rx_mpwqe_is_linear_skb(mdev, params) ?
 -                      mlx5e_skb_from_cqe_mpwrq_linear :
 -                      mlx5e_skb_from_cqe_mpwrq_nonlinear;
 -              rq->mpwqe.log_stride_sz = mlx5e_mpwqe_get_log_stride_size(mdev, params);
 -              rq->mpwqe.num_strides = BIT(mlx5e_mpwqe_get_log_num_strides(mdev, params));
 +              rq->mpwqe.skb_from_cqe_mpwrq = xsk ?
 +                      mlx5e_xsk_skb_from_cqe_mpwrq_linear :
 +                      mlx5e_rx_mpwqe_is_linear_skb(mdev, params, NULL) ?
 +                              mlx5e_skb_from_cqe_mpwrq_linear :
 +                              mlx5e_skb_from_cqe_mpwrq_nonlinear;
 +
 +              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));
  
                err = mlx5e_create_rq_umr_mkey(mdev, rq);
                if (err)
  
                wq_sz = mlx5_wq_cyc_get_size(&rq->wqe.wq);
  
 +              if (xsk)
 +                      num_xsk_frames = wq_sz << rq->wqe.info.log_num_frags;
 +
                rq->wqe.info = rqp->frags_info;
                rq->wqe.frags =
                        kvzalloc_node(array_size(sizeof(*rq->wqe.frags),
                err = mlx5e_init_di_list(rq, wq_sz, c->cpu);
                if (err)
                        goto err_free;
 +
                rq->post_wqes = mlx5e_post_rx_wqes;
                rq->dealloc_wqe = mlx5e_dealloc_rx_wqe;
  
                        goto err_free;
                }
  
 -              rq->wqe.skb_from_cqe = mlx5e_rx_is_linear_skb(params) ?
 -                      mlx5e_skb_from_cqe_linear :
 -                      mlx5e_skb_from_cqe_nonlinear;
 +              rq->wqe.skb_from_cqe = xsk ?
 +                      mlx5e_xsk_skb_from_cqe_linear :
 +                      mlx5e_rx_is_linear_skb(params, NULL) ?
 +                              mlx5e_skb_from_cqe_linear :
 +                              mlx5e_skb_from_cqe_nonlinear;
                rq->mkey_be = c->mkey_be;
        }
  
 -      /* Create a page_pool and register it with rxq */
 -      pp_params.order     = 0;
 -      pp_params.flags     = 0; /* No-internal DMA mapping in page_pool */
 -      pp_params.pool_size = pool_size;
 -      pp_params.nid       = cpu_to_node(c->cpu);
 -      pp_params.dev       = c->pdev;
 -      pp_params.dma_dir   = rq->buff.map_dir;
 -
 -      /* page_pool can be used even when there is no rq->xdp_prog,
 -       * given page_pool does not handle DMA mapping there is no
 -       * required state to clear. And page_pool gracefully handle
 -       * elevated refcnt.
 -       */
 -      rq->page_pool = page_pool_create(&pp_params);
 -      if (IS_ERR(rq->page_pool)) {
 -              err = PTR_ERR(rq->page_pool);
 -              rq->page_pool = NULL;
 -              goto err_free;
 +      if (xsk) {
 +              err = mlx5e_xsk_resize_reuseq(umem, num_xsk_frames);
 +              if (unlikely(err)) {
 +                      mlx5_core_err(mdev, "Unable to allocate the Reuse Ring for %u frames\n",
 +                                    num_xsk_frames);
 +                      goto err_free;
 +              }
 +
 +              rq->zca.free = mlx5e_xsk_zca_free;
 +              err = xdp_rxq_info_reg_mem_model(&rq->xdp_rxq,
 +                                               MEM_TYPE_ZERO_COPY,
 +                                               &rq->zca);
 +      } else {
 +              /* Create a page_pool and register it with rxq */
 +              pp_params.order     = 0;
 +              pp_params.flags     = 0; /* No-internal DMA mapping in page_pool */
 +              pp_params.pool_size = pool_size;
 +              pp_params.nid       = cpu_to_node(c->cpu);
 +              pp_params.dev       = c->pdev;
 +              pp_params.dma_dir   = rq->buff.map_dir;
 +
 +              /* page_pool can be used even when there is no rq->xdp_prog,
 +               * given page_pool does not handle DMA mapping there is no
 +               * required state to clear. And page_pool gracefully handle
 +               * elevated refcnt.
 +               */
 +              rq->page_pool = page_pool_create(&pp_params);
 +              if (IS_ERR(rq->page_pool)) {
 +                      err = PTR_ERR(rq->page_pool);
 +                      rq->page_pool = NULL;
 +                      goto err_free;
 +              }
 +              err = xdp_rxq_info_reg_mem_model(&rq->xdp_rxq,
 +                                               MEM_TYPE_PAGE_POOL, rq->page_pool);
        }
 -      err = xdp_rxq_info_reg_mem_model(&rq->xdp_rxq,
 -                                       MEM_TYPE_PAGE_POOL, rq->page_pool);
        if (err)
                goto err_free;
  
  
        switch (params->rx_cq_moderation.cq_period_mode) {
        case MLX5_CQ_PERIOD_MODE_START_FROM_CQE:
 -              rq->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE;
 +              rq->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_CQE;
                break;
        case MLX5_CQ_PERIOD_MODE_START_FROM_EQE:
        default:
 -              rq->dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
 +              rq->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
        }
  
        rq->page_cache.head = 0;
@@@ -644,7 -611,8 +644,7 @@@ err_rq_wq_destroy
        if (rq->xdp_prog)
                bpf_prog_put(rq->xdp_prog);
        xdp_rxq_info_unreg(&rq->xdp_rxq);
 -      if (rq->page_pool)
 -              page_pool_destroy(rq->page_pool);
 +      page_pool_destroy(rq->page_pool);
        mlx5_wq_destroy(&rq->wq_ctrl);
  
        return err;
@@@ -657,6 -625,10 +657,6 @@@ static void mlx5e_free_rq(struct mlx5e_
        if (rq->xdp_prog)
                bpf_prog_put(rq->xdp_prog);
  
 -      xdp_rxq_info_unreg(&rq->xdp_rxq);
 -      if (rq->page_pool)
 -              page_pool_destroy(rq->page_pool);
 -
        switch (rq->wq_type) {
        case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
                kvfree(rq->mpwqe.info);
             i = (i + 1) & (MLX5E_CACHE_SIZE - 1)) {
                struct mlx5e_dma_info *dma_info = &rq->page_cache.page_cache[i];
  
 -              mlx5e_page_release(rq, dma_info, false);
 +              /* With AF_XDP, page_cache is not used, so this loop is not
 +               * entered, and it's safe to call mlx5e_page_release_dynamic
 +               * directly.
 +               */
 +              mlx5e_page_release_dynamic(rq, dma_info, false);
        }
 +
 +      xdp_rxq_info_unreg(&rq->xdp_rxq);
 +      page_pool_destroy(rq->page_pool);
        mlx5_wq_destroy(&rq->wq_ctrl);
  }
  
@@@ -813,7 -778,7 +813,7 @@@ static void mlx5e_destroy_rq(struct mlx
        mlx5_core_destroy_rq(rq->mdev, rq->rqn);
  }
  
 -static int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
 +int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
  {
        unsigned long exp_time = jiffies + msecs_to_jiffies(wait_time);
        struct mlx5e_channel *c = rq->channel;
@@@ -871,13 -836,14 +871,13 @@@ static void mlx5e_free_rx_descs(struct 
  
  }
  
 -static int mlx5e_open_rq(struct mlx5e_channel *c,
 -                       struct mlx5e_params *params,
 -                       struct mlx5e_rq_param *param,
 -                       struct mlx5e_rq *rq)
 +int mlx5e_open_rq(struct mlx5e_channel *c, struct mlx5e_params *params,
 +                struct mlx5e_rq_param *param, struct mlx5e_xsk_param *xsk,
 +                struct xdp_umem *umem, struct mlx5e_rq *rq)
  {
        int err;
  
 -      err = mlx5e_alloc_rq(c, params, param, rq);
 +      err = mlx5e_alloc_rq(c, params, xsk, umem, param, rq);
        if (err)
                return err;
  
        if (err)
                goto err_destroy_rq;
  
+       if (MLX5_CAP_ETH(c->mdev, cqe_checksum_full))
+               __set_bit(MLX5E_RQ_STATE_CSUM_FULL, &c->rq.state);
        if (params->rx_dim_enabled)
                __set_bit(MLX5E_RQ_STATE_AM, &c->rq.state);
  
@@@ -915,13 -884,13 +918,13 @@@ static void mlx5e_activate_rq(struct ml
        mlx5e_trigger_irq(&rq->channel->icosq);
  }
  
 -static void mlx5e_deactivate_rq(struct mlx5e_rq *rq)
 +void mlx5e_deactivate_rq(struct mlx5e_rq *rq)
  {
        clear_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
        napi_synchronize(&rq->channel->napi); /* prevent mlx5e_post_rx_wqes */
  }
  
 -static void mlx5e_close_rq(struct mlx5e_rq *rq)
 +void mlx5e_close_rq(struct mlx5e_rq *rq)
  {
        cancel_work_sync(&rq->dim.work);
        mlx5e_destroy_rq(rq);
@@@ -974,7 -943,6 +977,7 @@@ static int mlx5e_alloc_xdpsq_db(struct 
  
  static int mlx5e_alloc_xdpsq(struct mlx5e_channel *c,
                             struct mlx5e_params *params,
 +                           struct xdp_umem *umem,
                             struct mlx5e_sq_param *param,
                             struct mlx5e_xdpsq *sq,
                             bool is_redirect)
        sq->uar_map   = mdev->mlx5e_res.bfreg.map;
        sq->min_inline_mode = params->tx_min_inline_mode;
        sq->hw_mtu    = MLX5E_SW2HW_MTU(params, params->sw_mtu);
 -      sq->stats     = is_redirect ?
 -              &c->priv->channel_stats[c->ix].xdpsq :
 -              &c->priv->channel_stats[c->ix].rq_xdpsq;
 +      sq->umem      = umem;
 +
 +      sq->stats = sq->umem ?
 +              &c->priv->channel_stats[c->ix].xsksq :
 +              is_redirect ?
 +                      &c->priv->channel_stats[c->ix].xdpsq :
 +                      &c->priv->channel_stats[c->ix].rq_xdpsq;
  
        param->wq.db_numa_node = cpu_to_node(c->cpu);
        err = mlx5_wq_cyc_create(mdev, &param->wq, sqc_wq, wq, &sq->wq_ctrl);
@@@ -1126,14 -1090,11 +1129,14 @@@ static int mlx5e_alloc_txqsq(struct mlx
        sq->uar_map   = mdev->mlx5e_res.bfreg.map;
        sq->min_inline_mode = params->tx_min_inline_mode;
        sq->stats     = &c->priv->channel_stats[c->ix].sq[tc];
 +      sq->stop_room = MLX5E_SQ_STOP_ROOM;
        INIT_WORK(&sq->recover_work, mlx5e_tx_err_cqe_work);
        if (MLX5_IPSEC_DEV(c->priv->mdev))
                set_bit(MLX5E_SQ_STATE_IPSEC, &sq->state);
 -      if (mlx5_accel_is_tls_device(c->priv->mdev))
 +      if (mlx5_accel_is_tls_device(c->priv->mdev)) {
                set_bit(MLX5E_SQ_STATE_TLS, &sq->state);
 +              sq->stop_room += MLX5E_SQ_TLS_ROOM;
 +      }
  
        param->wq.db_numa_node = cpu_to_node(c->cpu);
        err = mlx5_wq_cyc_create(mdev, &param->wq, sqc_wq, wq, &sq->wq_ctrl);
@@@ -1379,8 -1340,10 +1382,8 @@@ static void mlx5e_tx_err_cqe_work(struc
        mlx5e_tx_reporter_err_cqe(sq);
  }
  
 -static int mlx5e_open_icosq(struct mlx5e_channel *c,
 -                          struct mlx5e_params *params,
 -                          struct mlx5e_sq_param *param,
 -                          struct mlx5e_icosq *sq)
 +int mlx5e_open_icosq(struct mlx5e_channel *c, struct mlx5e_params *params,
 +                   struct mlx5e_sq_param *param, struct mlx5e_icosq *sq)
  {
        struct mlx5e_create_sq_param csp = {};
        int err;
@@@ -1406,7 -1369,7 +1409,7 @@@ err_free_icosq
        return err;
  }
  
 -static void mlx5e_close_icosq(struct mlx5e_icosq *sq)
 +void mlx5e_close_icosq(struct mlx5e_icosq *sq)
  {
        struct mlx5e_channel *c = sq->channel;
  
        mlx5e_free_icosq(sq);
  }
  
 -static int mlx5e_open_xdpsq(struct mlx5e_channel *c,
 -                          struct mlx5e_params *params,
 -                          struct mlx5e_sq_param *param,
 -                          struct mlx5e_xdpsq *sq,
 -                          bool is_redirect)
 +int mlx5e_open_xdpsq(struct mlx5e_channel *c, struct mlx5e_params *params,
 +                   struct mlx5e_sq_param *param, struct xdp_umem *umem,
 +                   struct mlx5e_xdpsq *sq, bool is_redirect)
  {
        struct mlx5e_create_sq_param csp = {};
        int err;
  
 -      err = mlx5e_alloc_xdpsq(c, params, param, sq, is_redirect);
 +      err = mlx5e_alloc_xdpsq(c, params, umem, param, sq, is_redirect);
        if (err)
                return err;
  
@@@ -1478,7 -1443,7 +1481,7 @@@ err_free_xdpsq
        return err;
  }
  
 -static void mlx5e_close_xdpsq(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq)
 +void mlx5e_close_xdpsq(struct mlx5e_xdpsq *sq)
  {
        struct mlx5e_channel *c = sq->channel;
  
        napi_synchronize(&c->napi);
  
        mlx5e_destroy_sq(c->mdev, sq->sqn);
 -      mlx5e_free_xdpsq_descs(sq, rq);
 +      mlx5e_free_xdpsq_descs(sq);
        mlx5e_free_xdpsq(sq);
  }
  
@@@ -1556,7 -1521,6 +1559,7 @@@ static void mlx5e_free_cq(struct mlx5e_
  
  static int mlx5e_create_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param)
  {
 +      u32 out[MLX5_ST_SZ_DW(create_cq_out)];
        struct mlx5_core_dev *mdev = cq->mdev;
        struct mlx5_core_cq *mcq = &cq->mcq;
  
                                            MLX5_ADAPTER_PAGE_SHIFT);
        MLX5_SET64(cqc, cqc, dbr_addr,      cq->wq_ctrl.db.dma);
  
 -      err = mlx5_core_create_cq(mdev, mcq, in, inlen);
 +      err = mlx5_core_create_cq(mdev, mcq, in, inlen, out, sizeof(out));
  
        kvfree(in);
  
@@@ -1608,8 -1572,10 +1611,8 @@@ static void mlx5e_destroy_cq(struct mlx
        mlx5_core_destroy_cq(cq->mdev, &cq->mcq);
  }
  
 -static int mlx5e_open_cq(struct mlx5e_channel *c,
 -                       struct net_dim_cq_moder moder,
 -                       struct mlx5e_cq_param *param,
 -                       struct mlx5e_cq *cq)
 +int mlx5e_open_cq(struct mlx5e_channel *c, struct dim_cq_moder moder,
 +                struct mlx5e_cq_param *param, struct mlx5e_cq *cq)
  {
        struct mlx5_core_dev *mdev = c->mdev;
        int err;
@@@ -1632,7 -1598,7 +1635,7 @@@ err_free_cq
        return err;
  }
  
 -static void mlx5e_close_cq(struct mlx5e_cq *cq)
 +void mlx5e_close_cq(struct mlx5e_cq *cq)
  {
        mlx5e_destroy_cq(cq);
        mlx5e_free_cq(cq);
@@@ -1806,16 -1772,49 +1809,16 @@@ static void mlx5e_free_xps_cpumask(stru
        free_cpumask_var(c->xps_cpumask);
  }
  
 -static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
 -                            struct mlx5e_params *params,
 -                            struct mlx5e_channel_param *cparam,
 -                            struct mlx5e_channel **cp)
 +static int mlx5e_open_queues(struct mlx5e_channel *c,
 +                           struct mlx5e_params *params,
 +                           struct mlx5e_channel_param *cparam)
  {
 -      int cpu = cpumask_first(mlx5_comp_irq_get_affinity_mask(priv->mdev, ix));
 -      struct net_dim_cq_moder icocq_moder = {0, 0};
 -      struct net_device *netdev = priv->netdev;
 -      struct mlx5e_channel *c;
 -      unsigned int irq;
 +      struct dim_cq_moder icocq_moder = {0, 0};
        int err;
 -      int eqn;
 -
 -      err = mlx5_vector2eqn(priv->mdev, ix, &eqn, &irq);
 -      if (err)
 -              return err;
 -
 -      c = kvzalloc_node(sizeof(*c), GFP_KERNEL, cpu_to_node(cpu));
 -      if (!c)
 -              return -ENOMEM;
 -
 -      c->priv     = priv;
 -      c->mdev     = priv->mdev;
 -      c->tstamp   = &priv->tstamp;
 -      c->ix       = ix;
 -      c->cpu      = cpu;
 -      c->pdev     = priv->mdev->device;
 -      c->netdev   = priv->netdev;
 -      c->mkey_be  = cpu_to_be32(priv->mdev->mlx5e_res.mkey.key);
 -      c->num_tc   = params->num_tc;
 -      c->xdp      = !!params->xdp_prog;
 -      c->stats    = &priv->channel_stats[ix].ch;
 -      c->irq_desc = irq_to_desc(irq);
 -
 -      err = mlx5e_alloc_xps_cpumask(c, params);
 -      if (err)
 -              goto err_free_channel;
 -
 -      netif_napi_add(netdev, &c->napi, mlx5e_napi_poll, 64);
  
        err = mlx5e_open_cq(c, icocq_moder, &cparam->icosq_cq, &c->icosq.cq);
        if (err)
 -              goto err_napi_del;
 +              return err;
  
        err = mlx5e_open_tx_cqs(c, params, cparam);
        if (err)
  
        /* XDP SQ CQ params are same as normal TXQ sq CQ params */
        err = c->xdp ? mlx5e_open_cq(c, params->tx_cq_moderation,
 -                                   &cparam->tx_cq, &c->rq.xdpsq.cq) : 0;
 +                                   &cparam->tx_cq, &c->rq_xdpsq.cq) : 0;
        if (err)
                goto err_close_rx_cq;
  
        if (err)
                goto err_close_icosq;
  
 -      err = c->xdp ? mlx5e_open_xdpsq(c, params, &cparam->xdp_sq, &c->rq.xdpsq, false) : 0;
 -      if (err)
 -              goto err_close_sqs;
 +      if (c->xdp) {
 +              err = mlx5e_open_xdpsq(c, params, &cparam->xdp_sq, NULL,
 +                                     &c->rq_xdpsq, false);
 +              if (err)
 +                      goto err_close_sqs;
 +      }
  
 -      err = mlx5e_open_rq(c, params, &cparam->rq, &c->rq);
 +      err = mlx5e_open_rq(c, params, &cparam->rq, NULL, NULL, &c->rq);
        if (err)
                goto err_close_xdp_sq;
  
 -      err = mlx5e_open_xdpsq(c, params, &cparam->xdp_sq, &c->xdpsq, true);
 +      err = mlx5e_open_xdpsq(c, params, &cparam->xdp_sq, NULL, &c->xdpsq, true);
        if (err)
                goto err_close_rq;
  
 -      *cp = c;
 -
        return 0;
  
  err_close_rq:
  
  err_close_xdp_sq:
        if (c->xdp)
 -              mlx5e_close_xdpsq(&c->rq.xdpsq, &c->rq);
 +              mlx5e_close_xdpsq(&c->rq_xdpsq);
  
  err_close_sqs:
        mlx5e_close_sqs(c);
@@@ -1877,9 -1875,8 +1880,9 @@@ err_close_icosq
  
  err_disable_napi:
        napi_disable(&c->napi);
 +
        if (c->xdp)
 -              mlx5e_close_cq(&c->rq.xdpsq.cq);
 +              mlx5e_close_cq(&c->rq_xdpsq.cq);
  
  err_close_rx_cq:
        mlx5e_close_cq(&c->rq.cq);
@@@ -1893,85 -1890,6 +1896,85 @@@ err_close_tx_cqs
  err_close_icosq_cq:
        mlx5e_close_cq(&c->icosq.cq);
  
 +      return err;
 +}
 +
 +static void mlx5e_close_queues(struct mlx5e_channel *c)
 +{
 +      mlx5e_close_xdpsq(&c->xdpsq);
 +      mlx5e_close_rq(&c->rq);
 +      if (c->xdp)
 +              mlx5e_close_xdpsq(&c->rq_xdpsq);
 +      mlx5e_close_sqs(c);
 +      mlx5e_close_icosq(&c->icosq);
 +      napi_disable(&c->napi);
 +      if (c->xdp)
 +              mlx5e_close_cq(&c->rq_xdpsq.cq);
 +      mlx5e_close_cq(&c->rq.cq);
 +      mlx5e_close_cq(&c->xdpsq.cq);
 +      mlx5e_close_tx_cqs(c);
 +      mlx5e_close_cq(&c->icosq.cq);
 +}
 +
 +static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
 +                            struct mlx5e_params *params,
 +                            struct mlx5e_channel_param *cparam,
 +                            struct xdp_umem *umem,
 +                            struct mlx5e_channel **cp)
 +{
 +      int cpu = cpumask_first(mlx5_comp_irq_get_affinity_mask(priv->mdev, ix));
 +      struct net_device *netdev = priv->netdev;
 +      struct mlx5e_xsk_param xsk;
 +      struct mlx5e_channel *c;
 +      unsigned int irq;
 +      int err;
 +      int eqn;
 +
 +      err = mlx5_vector2eqn(priv->mdev, ix, &eqn, &irq);
 +      if (err)
 +              return err;
 +
 +      c = kvzalloc_node(sizeof(*c), GFP_KERNEL, cpu_to_node(cpu));
 +      if (!c)
 +              return -ENOMEM;
 +
 +      c->priv     = priv;
 +      c->mdev     = priv->mdev;
 +      c->tstamp   = &priv->tstamp;
 +      c->ix       = ix;
 +      c->cpu      = cpu;
 +      c->pdev     = priv->mdev->device;
 +      c->netdev   = priv->netdev;
 +      c->mkey_be  = cpu_to_be32(priv->mdev->mlx5e_res.mkey.key);
 +      c->num_tc   = params->num_tc;
 +      c->xdp      = !!params->xdp_prog;
 +      c->stats    = &priv->channel_stats[ix].ch;
 +      c->irq_desc = irq_to_desc(irq);
 +
 +      err = mlx5e_alloc_xps_cpumask(c, params);
 +      if (err)
 +              goto err_free_channel;
 +
 +      netif_napi_add(netdev, &c->napi, mlx5e_napi_poll, 64);
 +
 +      err = mlx5e_open_queues(c, params, cparam);
 +      if (unlikely(err))
 +              goto err_napi_del;
 +
 +      if (umem) {
 +              mlx5e_build_xsk_param(umem, &xsk);
 +              err = mlx5e_open_xsk(priv, params, &xsk, umem, c);
 +              if (unlikely(err))
 +                      goto err_close_queues;
 +      }
 +
 +      *cp = c;
 +
 +      return 0;
 +
 +err_close_queues:
 +      mlx5e_close_queues(c);
 +
  err_napi_del:
        netif_napi_del(&c->napi);
        mlx5e_free_xps_cpumask(c);
@@@ -1990,18 -1908,12 +1993,18 @@@ static void mlx5e_activate_channel(stru
                mlx5e_activate_txqsq(&c->sq[tc]);
        mlx5e_activate_rq(&c->rq);
        netif_set_xps_queue(c->netdev, c->xps_cpumask, c->ix);
 +
 +      if (test_bit(MLX5E_CHANNEL_STATE_XSK, c->state))
 +              mlx5e_activate_xsk(c);
  }
  
  static void mlx5e_deactivate_channel(struct mlx5e_channel *c)
  {
        int tc;
  
 +      if (test_bit(MLX5E_CHANNEL_STATE_XSK, c->state))
 +              mlx5e_deactivate_xsk(c);
 +
        mlx5e_deactivate_rq(&c->rq);
        for (tc = 0; tc < c->num_tc; tc++)
                mlx5e_deactivate_txqsq(&c->sq[tc]);
  
  static void mlx5e_close_channel(struct mlx5e_channel *c)
  {
 -      mlx5e_close_xdpsq(&c->xdpsq, NULL);
 -      mlx5e_close_rq(&c->rq);
 -      if (c->xdp)
 -              mlx5e_close_xdpsq(&c->rq.xdpsq, &c->rq);
 -      mlx5e_close_sqs(c);
 -      mlx5e_close_icosq(&c->icosq);
 -      napi_disable(&c->napi);
 -      if (c->xdp)
 -              mlx5e_close_cq(&c->rq.xdpsq.cq);
 -      mlx5e_close_cq(&c->rq.cq);
 -      mlx5e_close_cq(&c->xdpsq.cq);
 -      mlx5e_close_tx_cqs(c);
 -      mlx5e_close_cq(&c->icosq.cq);
 +      if (test_bit(MLX5E_CHANNEL_STATE_XSK, c->state))
 +              mlx5e_close_xsk(c);
 +      mlx5e_close_queues(c);
        netif_napi_del(&c->napi);
        mlx5e_free_xps_cpumask(c);
  
  
  static void mlx5e_build_rq_frags_info(struct mlx5_core_dev *mdev,
                                      struct mlx5e_params *params,
 +                                    struct mlx5e_xsk_param *xsk,
                                      struct mlx5e_rq_frags_info *info)
  {
        u32 byte_count = MLX5E_SW2HW_MTU(params, params->sw_mtu);
                byte_count += MLX5E_METADATA_ETHER_LEN;
  #endif
  
 -      if (mlx5e_rx_is_linear_skb(params)) {
 +      if (mlx5e_rx_is_linear_skb(params, xsk)) {
                int frag_stride;
  
 -              frag_stride = mlx5e_rx_get_linear_frag_sz(params);
 +              frag_stride = mlx5e_rx_get_linear_frag_sz(params, xsk);
                frag_stride = roundup_pow_of_two(frag_stride);
  
                info->arr[0].frag_size = byte_count;
@@@ -2096,10 -2017,9 +2099,10 @@@ static u8 mlx5e_get_rq_log_wq_sz(void *
        return MLX5_GET(wq, wq, log_wq_sz);
  }
  
 -static void mlx5e_build_rq_param(struct mlx5e_priv *priv,
 -                               struct mlx5e_params *params,
 -                               struct mlx5e_rq_param *param)
 +void mlx5e_build_rq_param(struct mlx5e_priv *priv,
 +                        struct mlx5e_params *params,
 +                        struct mlx5e_xsk_param *xsk,
 +                        struct mlx5e_rq_param *param)
  {
        struct mlx5_core_dev *mdev = priv->mdev;
        void *rqc = param->rqc;
        switch (params->rq_wq_type) {
        case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
                MLX5_SET(wq, wq, log_wqe_num_of_strides,
 -                       mlx5e_mpwqe_get_log_num_strides(mdev, params) -
 +                       mlx5e_mpwqe_get_log_num_strides(mdev, params, xsk) -
                         MLX5_MPWQE_LOG_NUM_STRIDES_BASE);
                MLX5_SET(wq, wq, log_wqe_stride_size,
 -                       mlx5e_mpwqe_get_log_stride_size(mdev, params) -
 +                       mlx5e_mpwqe_get_log_stride_size(mdev, params, xsk) -
                         MLX5_MPWQE_LOG_STRIDE_SZ_BASE);
 -              MLX5_SET(wq, wq, log_wq_sz, mlx5e_mpwqe_get_log_rq_size(params));
 +              MLX5_SET(wq, wq, log_wq_sz, mlx5e_mpwqe_get_log_rq_size(params, xsk));
                break;
        default: /* MLX5_WQ_TYPE_CYCLIC */
                MLX5_SET(wq, wq, log_wq_sz, params->log_rq_mtu_frames);
 -              mlx5e_build_rq_frags_info(mdev, params, &param->frags_info);
 +              mlx5e_build_rq_frags_info(mdev, params, xsk, &param->frags_info);
                ndsegs = param->frags_info.num_frags;
        }
  
@@@ -2149,8 -2069,8 +2152,8 @@@ static void mlx5e_build_drop_rq_param(s
        param->wq.buf_numa_node = dev_to_node(mdev->device);
  }
  
 -static void mlx5e_build_sq_param_common(struct mlx5e_priv *priv,
 -                                      struct mlx5e_sq_param *param)
 +void mlx5e_build_sq_param_common(struct mlx5e_priv *priv,
 +                               struct mlx5e_sq_param *param)
  {
        void *sqc = param->sqc;
        void *wq = MLX5_ADDR_OF(sqc, sqc, wq);
@@@ -2186,10 -2106,9 +2189,10 @@@ static void mlx5e_build_common_cq_param
                MLX5_SET(cqc, cqc, cqe_sz, CQE_STRIDE_128_PAD);
  }
  
 -static void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv,
 -                                  struct mlx5e_params *params,
 -                                  struct mlx5e_cq_param *param)
 +void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv,
 +                           struct mlx5e_params *params,
 +                           struct mlx5e_xsk_param *xsk,
 +                           struct mlx5e_cq_param *param)
  {
        struct mlx5_core_dev *mdev = priv->mdev;
        void *cqc = param->cqc;
  
        switch (params->rq_wq_type) {
        case MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ:
 -              log_cq_size = mlx5e_mpwqe_get_log_rq_size(params) +
 -                      mlx5e_mpwqe_get_log_num_strides(mdev, params);
 +              log_cq_size = mlx5e_mpwqe_get_log_rq_size(params, xsk) +
 +                      mlx5e_mpwqe_get_log_num_strides(mdev, params, xsk);
                break;
        default: /* MLX5_WQ_TYPE_CYCLIC */
                log_cq_size = params->log_rq_mtu_frames;
        param->cq_period_mode = params->rx_cq_moderation.cq_period_mode;
  }
  
 -static void mlx5e_build_tx_cq_param(struct mlx5e_priv *priv,
 -                                  struct mlx5e_params *params,
 -                                  struct mlx5e_cq_param *param)
 +void mlx5e_build_tx_cq_param(struct mlx5e_priv *priv,
 +                           struct mlx5e_params *params,
 +                           struct mlx5e_cq_param *param)
  {
        void *cqc = param->cqc;
  
        param->cq_period_mode = params->tx_cq_moderation.cq_period_mode;
  }
  
 -static void mlx5e_build_ico_cq_param(struct mlx5e_priv *priv,
 -                                   u8 log_wq_size,
 -                                   struct mlx5e_cq_param *param)
 +void mlx5e_build_ico_cq_param(struct mlx5e_priv *priv,
 +                            u8 log_wq_size,
 +                            struct mlx5e_cq_param *param)
  {
        void *cqc = param->cqc;
  
  
        mlx5e_build_common_cq_param(priv, param);
  
 -      param->cq_period_mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
 +      param->cq_period_mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
  }
  
 -static void mlx5e_build_icosq_param(struct mlx5e_priv *priv,
 -                                  u8 log_wq_size,
 -                                  struct mlx5e_sq_param *param)
 +void mlx5e_build_icosq_param(struct mlx5e_priv *priv,
 +                           u8 log_wq_size,
 +                           struct mlx5e_sq_param *param)
  {
        void *sqc = param->sqc;
        void *wq = MLX5_ADDR_OF(sqc, sqc, wq);
        MLX5_SET(sqc, sqc, reg_umr, MLX5_CAP_ETH(priv->mdev, reg_umr_sq));
  }
  
 -static void mlx5e_build_xdpsq_param(struct mlx5e_priv *priv,
 -                                  struct mlx5e_params *params,
 -                                  struct mlx5e_sq_param *param)
 +void mlx5e_build_xdpsq_param(struct mlx5e_priv *priv,
 +                           struct mlx5e_params *params,
 +                           struct mlx5e_sq_param *param)
  {
        void *sqc = param->sqc;
        void *wq = MLX5_ADDR_OF(sqc, sqc, wq);
@@@ -2282,14 -2201,14 +2285,14 @@@ static void mlx5e_build_channel_param(s
  {
        u8 icosq_log_wq_sz;
  
 -      mlx5e_build_rq_param(priv, params, &cparam->rq);
 +      mlx5e_build_rq_param(priv, params, NULL, &cparam->rq);
  
        icosq_log_wq_sz = mlx5e_build_icosq_log_wq_sz(params, &cparam->rq);
  
        mlx5e_build_sq_param(priv, params, &cparam->sq);
        mlx5e_build_xdpsq_param(priv, params, &cparam->xdp_sq);
        mlx5e_build_icosq_param(priv, icosq_log_wq_sz, &cparam->icosq);
 -      mlx5e_build_rx_cq_param(priv, params, &cparam->rx_cq);
 +      mlx5e_build_rx_cq_param(priv, params, NULL, &cparam->rx_cq);
        mlx5e_build_tx_cq_param(priv, params, &cparam->tx_cq);
        mlx5e_build_ico_cq_param(priv, icosq_log_wq_sz, &cparam->icosq_cq);
  }
@@@ -2310,12 -2229,7 +2313,12 @@@ int mlx5e_open_channels(struct mlx5e_pr
  
        mlx5e_build_channel_param(priv, &chs->params, cparam);
        for (i = 0; i < chs->num; i++) {
 -              err = mlx5e_open_channel(priv, i, &chs->params, cparam, &chs->c[i]);
 +              struct xdp_umem *umem = NULL;
 +
 +              if (chs->params.xdp_prog)
 +                      umem = mlx5e_xsk_get_umem(&chs->params, chs->params.xsk, i);
 +
 +              err = mlx5e_open_channel(priv, i, &chs->params, cparam, umem, &chs->c[i]);
                if (err)
                        goto err_close_channels;
        }
@@@ -2357,10 -2271,6 +2360,10 @@@ static int mlx5e_wait_channels_min_rx_w
                int timeout = err ? 0 : MLX5E_RQ_WQES_TIMEOUT;
  
                err |= mlx5e_wait_for_min_rx_wqes(&chs->c[i]->rq, timeout);
 +
 +              /* Don't wait on the XSK RQ, because the newer xdpsock sample
 +               * doesn't provide any Fill Ring entries at the setup stage.
 +               */
        }
  
        return err ? -ETIMEDOUT : 0;
@@@ -2433,35 -2343,35 +2436,35 @@@ int mlx5e_create_indirect_rqt(struct ml
        return err;
  }
  
 -int mlx5e_create_direct_rqts(struct mlx5e_priv *priv)
 +int mlx5e_create_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
  {
 -      struct mlx5e_rqt *rqt;
 +      const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        int err;
        int ix;
  
 -      for (ix = 0; ix < mlx5e_get_netdev_max_channels(priv->netdev); ix++) {
 -              rqt = &priv->direct_tir[ix].rqt;
 -              err = mlx5e_create_rqt(priv, 1 /*size */, rqt);
 -              if (err)
 +      for (ix = 0; ix < max_nch; ix++) {
 +              err = mlx5e_create_rqt(priv, 1 /*size */, &tirs[ix].rqt);
 +              if (unlikely(err))
                        goto err_destroy_rqts;
        }
  
        return 0;
  
  err_destroy_rqts:
 -      mlx5_core_warn(priv->mdev, "create direct rqts failed, %d\n", err);
 +      mlx5_core_warn(priv->mdev, "create rqts failed, %d\n", err);
        for (ix--; ix >= 0; ix--)
 -              mlx5e_destroy_rqt(priv, &priv->direct_tir[ix].rqt);
 +              mlx5e_destroy_rqt(priv, &tirs[ix].rqt);
  
        return err;
  }
  
 -void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv)
 +void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
  {
 +      const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        int i;
  
 -      for (i = 0; i < mlx5e_get_netdev_max_channels(priv->netdev); i++)
 -              mlx5e_destroy_rqt(priv, &priv->direct_tir[i].rqt);
 +      for (i = 0; i < max_nch; i++)
 +              mlx5e_destroy_rqt(priv, &tirs[i].rqt);
  }
  
  static int mlx5e_rx_hash_fn(int hfunc)
@@@ -2881,12 -2791,11 +2884,12 @@@ static void mlx5e_build_tx2sq_maps(stru
  void mlx5e_activate_priv_channels(struct mlx5e_priv *priv)
  {
        int num_txqs = priv->channels.num * priv->channels.params.num_tc;
 +      int num_rxqs = priv->channels.num * MLX5E_NUM_RQ_GROUPS;
        struct net_device *netdev = priv->netdev;
  
        mlx5e_netdev_set_tcs(netdev);
        netif_set_real_num_tx_queues(netdev, num_txqs);
 -      netif_set_real_num_rx_queues(netdev, priv->channels.num);
 +      netif_set_real_num_rx_queues(netdev, num_rxqs);
  
        mlx5e_build_tx2sq_maps(priv);
        mlx5e_activate_channels(&priv->channels);
  
        mlx5e_wait_channels_min_rx_wqes(&priv->channels);
        mlx5e_redirect_rqts_to_channels(priv, &priv->channels);
 +
 +      mlx5e_xsk_redirect_rqts_to_channels(priv, &priv->channels);
  }
  
  void mlx5e_deactivate_priv_channels(struct mlx5e_priv *priv)
  {
 +      mlx5e_xsk_redirect_rqts_to_drop(priv, &priv->channels);
 +
        mlx5e_redirect_rqts_to_drop(priv);
  
        if (mlx5e_is_vport_rep(priv))
@@@ -2945,7 -2850,7 +2948,7 @@@ static void mlx5e_switch_priv_channels(
        if (hw_modify)
                hw_modify(priv);
  
 -      mlx5e_refresh_tirs(priv, false);
 +      priv->profile->update_rx(priv);
        mlx5e_activate_priv_channels(priv);
  
        /* return carrier back if needed */
@@@ -2984,18 -2889,15 +2987,18 @@@ void mlx5e_timestamp_init(struct mlx5e_
  int mlx5e_open_locked(struct net_device *netdev)
  {
        struct mlx5e_priv *priv = netdev_priv(netdev);
 +      bool is_xdp = priv->channels.params.xdp_prog;
        int err;
  
        set_bit(MLX5E_STATE_OPENED, &priv->state);
 +      if (is_xdp)
 +              mlx5e_xdp_set_open(priv);
  
        err = mlx5e_open_channels(priv, &priv->channels);
        if (err)
                goto err_clear_state_opened_flag;
  
 -      mlx5e_refresh_tirs(priv, false);
 +      priv->profile->update_rx(priv);
        mlx5e_activate_priv_channels(priv);
        if (priv->profile->update_carrier)
                priv->profile->update_carrier(priv);
        return 0;
  
  err_clear_state_opened_flag:
 +      if (is_xdp)
 +              mlx5e_xdp_set_closed(priv);
        clear_bit(MLX5E_STATE_OPENED, &priv->state);
        return err;
  }
@@@ -3037,8 -2937,6 +3040,8 @@@ int mlx5e_close_locked(struct net_devic
        if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
                return 0;
  
 +      if (priv->channels.params.xdp_prog)
 +              mlx5e_xdp_set_closed(priv);
        clear_bit(MLX5E_STATE_OPENED, &priv->state);
  
        netif_carrier_off(priv->netdev);
@@@ -3150,19 -3048,20 +3153,19 @@@ void mlx5e_close_drop_rq(struct mlx5e_r
        mlx5e_free_cq(&drop_rq->cq);
  }
  
 -int mlx5e_create_tis(struct mlx5_core_dev *mdev, int tc,
 -                   u32 underlay_qpn, u32 *tisn)
 +int mlx5e_create_tis(struct mlx5_core_dev *mdev, void *in, u32 *tisn)
  {
 -      u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {0};
        void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
  
 -      MLX5_SET(tisc, tisc, prio, tc << 1);
 -      MLX5_SET(tisc, tisc, underlay_qpn, underlay_qpn);
        MLX5_SET(tisc, tisc, transport_domain, mdev->mlx5e_res.td.tdn);
  
 +      if (MLX5_GET(tisc, tisc, tls_en))
 +              MLX5_SET(tisc, tisc, pd, mdev->mlx5e_res.pdn);
 +
        if (mlx5_lag_is_lacp_owner(mdev))
                MLX5_SET(tisc, tisc, strict_lag_tx_port_affinity, 1);
  
 -      return mlx5_core_create_tis(mdev, in, sizeof(in), tisn);
 +      return mlx5_core_create_tis(mdev, in, MLX5_ST_SZ_BYTES(create_tis_in), tisn);
  }
  
  void mlx5e_destroy_tis(struct mlx5_core_dev *mdev, u32 tisn)
@@@ -3176,14 -3075,7 +3179,14 @@@ int mlx5e_create_tises(struct mlx5e_pri
        int tc;
  
        for (tc = 0; tc < priv->profile->max_tc; tc++) {
 -              err = mlx5e_create_tis(priv->mdev, tc, 0, &priv->tisn[tc]);
 +              u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {};
 +              void *tisc;
 +
 +              tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
 +
 +              MLX5_SET(tisc, tisc, prio, tc << 1);
 +
 +              err = mlx5e_create_tis(priv->mdev, in, &priv->tisn[tc]);
                if (err)
                        goto err_close_tises;
        }
@@@ -3301,13 -3193,13 +3304,13 @@@ err_destroy_inner_tirs
        return err;
  }
  
 -int mlx5e_create_direct_tirs(struct mlx5e_priv *priv)
 +int mlx5e_create_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
  {
 -      int nch = mlx5e_get_netdev_max_channels(priv->netdev);
 +      const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        struct mlx5e_tir *tir;
        void *tirc;
        int inlen;
 -      int err;
 +      int err = 0;
        u32 *in;
        int ix;
  
        if (!in)
                return -ENOMEM;
  
 -      for (ix = 0; ix < nch; ix++) {
 +      for (ix = 0; ix < max_nch; ix++) {
                memset(in, 0, inlen);
 -              tir = &priv->direct_tir[ix];
 +              tir = &tirs[ix];
                tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
 -              mlx5e_build_direct_tir_ctx(priv, priv->direct_tir[ix].rqt.rqtn, tirc);
 +              mlx5e_build_direct_tir_ctx(priv, tir->rqt.rqtn, tirc);
                err = mlx5e_create_tir(priv->mdev, tir, in, inlen);
 -              if (err)
 +              if (unlikely(err))
                        goto err_destroy_ch_tirs;
        }
  
 -      kvfree(in);
 -
 -      return 0;
 +      goto out;
  
  err_destroy_ch_tirs:
 -      mlx5_core_warn(priv->mdev, "create direct tirs failed, %d\n", err);
 +      mlx5_core_warn(priv->mdev, "create tirs failed, %d\n", err);
        for (ix--; ix >= 0; ix--)
 -              mlx5e_destroy_tir(priv->mdev, &priv->direct_tir[ix]);
 +              mlx5e_destroy_tir(priv->mdev, &tirs[ix]);
  
 +out:
        kvfree(in);
  
        return err;
@@@ -3353,13 -3246,13 +3356,13 @@@ void mlx5e_destroy_indirect_tirs(struc
                mlx5e_destroy_tir(priv->mdev, &priv->inner_indir_tir[i]);
  }
  
 -void mlx5e_destroy_direct_tirs(struct mlx5e_priv *priv)
 +void mlx5e_destroy_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
  {
 -      int nch = mlx5e_get_netdev_max_channels(priv->netdev);
 +      const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        int i;
  
 -      for (i = 0; i < nch; i++)
 -              mlx5e_destroy_tir(priv->mdev, &priv->direct_tir[i]);
 +      for (i = 0; i < max_nch; i++)
 +              mlx5e_destroy_tir(priv->mdev, &tirs[i]);
  }
  
  static int mlx5e_modify_channels_scatter_fcs(struct mlx5e_channels *chs, bool enable)
@@@ -3390,9 -3283,10 +3393,9 @@@ static int mlx5e_modify_channels_vsd(st
        return 0;
  }
  
 -static int mlx5e_setup_tc_mqprio(struct net_device *netdev,
 +static int mlx5e_setup_tc_mqprio(struct mlx5e_priv *priv,
                                 struct tc_mqprio_qopt *mqprio)
  {
 -      struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5e_channels new_channels = {};
        u8 tc = mqprio->num_tc;
        int err = 0;
  
  #ifdef CONFIG_MLX5_ESWITCH
  static int mlx5e_setup_tc_cls_flower(struct mlx5e_priv *priv,
 -                                   struct tc_cls_flower_offload *cls_flower,
 +                                   struct flow_cls_offload *cls_flower,
                                     int flags)
  {
        switch (cls_flower->command) {
 -      case TC_CLSFLOWER_REPLACE:
 +      case FLOW_CLS_REPLACE:
                return mlx5e_configure_flower(priv->netdev, priv, cls_flower,
                                              flags);
 -      case TC_CLSFLOWER_DESTROY:
 +      case FLOW_CLS_DESTROY:
                return mlx5e_delete_flower(priv->netdev, priv, cls_flower,
                                           flags);
 -      case TC_CLSFLOWER_STATS:
 +      case FLOW_CLS_STATS:
                return mlx5e_stats_flower(priv->netdev, priv, cls_flower,
                                          flags);
        default:
@@@ -3456,25 -3350,39 +3459,25 @@@ static int mlx5e_setup_tc_block_cb(enu
                return -EOPNOTSUPP;
        }
  }
 -
 -static int mlx5e_setup_tc_block(struct net_device *dev,
 -                              struct tc_block_offload *f)
 -{
 -      struct mlx5e_priv *priv = netdev_priv(dev);
 -
 -      if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
 -              return -EOPNOTSUPP;
 -
 -      switch (f->command) {
 -      case TC_BLOCK_BIND:
 -              return tcf_block_cb_register(f->block, mlx5e_setup_tc_block_cb,
 -                                           priv, priv, f->extack);
 -      case TC_BLOCK_UNBIND:
 -              tcf_block_cb_unregister(f->block, mlx5e_setup_tc_block_cb,
 -                                      priv);
 -              return 0;
 -      default:
 -              return -EOPNOTSUPP;
 -      }
 -}
  #endif
  
 +static LIST_HEAD(mlx5e_block_cb_list);
 +
  static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type,
                          void *type_data)
  {
 +      struct mlx5e_priv *priv = netdev_priv(dev);
 +
        switch (type) {
  #ifdef CONFIG_MLX5_ESWITCH
        case TC_SETUP_BLOCK:
 -              return mlx5e_setup_tc_block(dev, type_data);
 +              return flow_block_cb_setup_simple(type_data,
 +                                                &mlx5e_block_cb_list,
 +                                                mlx5e_setup_tc_block_cb,
 +                                                priv, priv, true);
  #endif
        case TC_SETUP_QDISC_MQPRIO:
 -              return mlx5e_setup_tc_mqprio(dev, type_data);
 +              return mlx5e_setup_tc_mqprio(priv, type_data);
        default:
                return -EOPNOTSUPP;
        }
@@@ -3486,12 -3394,11 +3489,12 @@@ void mlx5e_fold_sw_stats64(struct mlx5e
  
        for (i = 0; i < mlx5e_get_netdev_max_channels(priv->netdev); i++) {
                struct mlx5e_channel_stats *channel_stats = &priv->channel_stats[i];
 +              struct mlx5e_rq_stats *xskrq_stats = &channel_stats->xskrq;
                struct mlx5e_rq_stats *rq_stats = &channel_stats->rq;
                int j;
  
 -              s->rx_packets   += rq_stats->packets;
 -              s->rx_bytes     += rq_stats->bytes;
 +              s->rx_packets   += rq_stats->packets + xskrq_stats->packets;
 +              s->rx_bytes     += rq_stats->bytes + xskrq_stats->bytes;
  
                for (j = 0; j < priv->max_opened_tc; j++) {
                        struct mlx5e_sq_stats *sq_stats = &channel_stats->sq[j];
@@@ -3590,13 -3497,6 +3593,13 @@@ static int set_feature_lro(struct net_d
  
        mutex_lock(&priv->state_lock);
  
 +      if (enable && priv->xsk.refcnt) {
 +              netdev_warn(netdev, "LRO is incompatible with AF_XDP (%hu XSKs are active)\n",
 +                          priv->xsk.refcnt);
 +              err = -EINVAL;
 +              goto out;
 +      }
 +
        old_params = &priv->channels.params;
        if (enable && !MLX5E_GET_PFLAG(old_params, MLX5E_PFLAG_RX_STRIDING_RQ)) {
                netdev_warn(netdev, "can't set LRO with legacy RQ\n");
        new_channels.params.lro_en = enable;
  
        if (old_params->rq_wq_type != MLX5_WQ_TYPE_CYCLIC) {
 -              if (mlx5e_rx_mpwqe_is_linear_skb(mdev, old_params) ==
 -                  mlx5e_rx_mpwqe_is_linear_skb(mdev, &new_channels.params))
 +              if (mlx5e_rx_mpwqe_is_linear_skb(mdev, old_params, NULL) ==
 +                  mlx5e_rx_mpwqe_is_linear_skb(mdev, &new_channels.params, NULL))
                        reset = false;
        }
  
@@@ -3801,43 -3701,6 +3804,43 @@@ static netdev_features_t mlx5e_fix_feat
        return features;
  }
  
 +static bool mlx5e_xsk_validate_mtu(struct net_device *netdev,
 +                                 struct mlx5e_channels *chs,
 +                                 struct mlx5e_params *new_params,
 +                                 struct mlx5_core_dev *mdev)
 +{
 +      u16 ix;
 +
 +      for (ix = 0; ix < chs->params.num_channels; ix++) {
 +              struct xdp_umem *umem = mlx5e_xsk_get_umem(&chs->params, chs->params.xsk, ix);
 +              struct mlx5e_xsk_param xsk;
 +
 +              if (!umem)
 +                      continue;
 +
 +              mlx5e_build_xsk_param(umem, &xsk);
 +
 +              if (!mlx5e_validate_xsk_param(new_params, &xsk, mdev)) {
 +                      u32 hr = mlx5e_get_linear_rq_headroom(new_params, &xsk);
 +                      int max_mtu_frame, max_mtu_page, max_mtu;
 +
 +                      /* Two criteria must be met:
 +                       * 1. HW MTU + all headrooms <= XSK frame size.
 +                       * 2. Size of SKBs allocated on XDP_PASS <= PAGE_SIZE.
 +                       */
 +                      max_mtu_frame = MLX5E_HW2SW_MTU(new_params, xsk.chunk_size - hr);
 +                      max_mtu_page = mlx5e_xdp_max_mtu(new_params, &xsk);
 +                      max_mtu = min(max_mtu_frame, max_mtu_page);
 +
 +                      netdev_err(netdev, "MTU %d is too big for an XSK running on channel %hu. Try MTU <= %d\n",
 +                                 new_params->sw_mtu, ix, max_mtu);
 +                      return false;
 +              }
 +      }
 +
 +      return true;
 +}
 +
  int mlx5e_change_mtu(struct net_device *netdev, int new_mtu,
                     change_hw_mtu_cb set_mtu_cb)
  {
        new_channels.params.sw_mtu = new_mtu;
  
        if (params->xdp_prog &&
 -          !mlx5e_rx_is_linear_skb(&new_channels.params)) {
 +          !mlx5e_rx_is_linear_skb(&new_channels.params, NULL)) {
                netdev_err(netdev, "MTU(%d) > %d is not allowed while XDP enabled\n",
 -                         new_mtu, mlx5e_xdp_max_mtu(params));
 +                         new_mtu, mlx5e_xdp_max_mtu(params, NULL));
 +              err = -EINVAL;
 +              goto out;
 +      }
 +
 +      if (priv->xsk.refcnt &&
 +          !mlx5e_xsk_validate_mtu(netdev, &priv->channels,
 +                                  &new_channels.params, priv->mdev)) {
                err = -EINVAL;
                goto out;
        }
  
        if (params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
 -              bool is_linear = mlx5e_rx_mpwqe_is_linear_skb(priv->mdev, &new_channels.params);
 -              u8 ppw_old = mlx5e_mpwqe_log_pkts_per_wqe(params);
 -              u8 ppw_new = mlx5e_mpwqe_log_pkts_per_wqe(&new_channels.params);
 +              bool is_linear = mlx5e_rx_mpwqe_is_linear_skb(priv->mdev,
 +                                                            &new_channels.params,
 +                                                            NULL);
 +              u8 ppw_old = mlx5e_mpwqe_log_pkts_per_wqe(params, NULL);
 +              u8 ppw_new = mlx5e_mpwqe_log_pkts_per_wqe(&new_channels.params, NULL);
 +
 +              /* If XSK is active, XSK RQs are linear. */
 +              is_linear |= priv->xsk.refcnt;
  
 +              /* Always reset in linear mode - hw_mtu is used in data path. */
                reset = reset && (is_linear || (ppw_old != ppw_new));
        }
  
@@@ -4315,29 -4165,16 +4318,29 @@@ static int mlx5e_xdp_allowed(struct mlx
        new_channels.params = priv->channels.params;
        new_channels.params.xdp_prog = prog;
  
 -      if (!mlx5e_rx_is_linear_skb(&new_channels.params)) {
 +      /* No XSK params: AF_XDP can't be enabled yet at the point of setting
 +       * the XDP program.
 +       */
 +      if (!mlx5e_rx_is_linear_skb(&new_channels.params, NULL)) {
                netdev_warn(netdev, "XDP is not allowed with MTU(%d) > %d\n",
                            new_channels.params.sw_mtu,
 -                          mlx5e_xdp_max_mtu(&new_channels.params));
 +                          mlx5e_xdp_max_mtu(&new_channels.params, NULL));
                return -EINVAL;
        }
  
        return 0;
  }
  
 +static int mlx5e_xdp_update_state(struct mlx5e_priv *priv)
 +{
 +      if (priv->channels.params.xdp_prog)
 +              mlx5e_xdp_set_open(priv);
 +      else
 +              mlx5e_xdp_set_closed(priv);
 +
 +      return 0;
 +}
 +
  static int mlx5e_xdp_set(struct net_device *netdev, struct bpf_prog *prog)
  {
        struct mlx5e_priv *priv = netdev_priv(netdev);
        /* no need for full reset when exchanging programs */
        reset = (!priv->channels.params.xdp_prog || !prog);
  
 -      if (was_opened && reset)
 -              mlx5e_close_locked(netdev);
        if (was_opened && !reset) {
                /* num_channels is invariant here, so we can take the
                 * batched reference right upfront.
                }
        }
  
 -      /* exchange programs, extra prog reference we got from caller
 -       * as long as we don't fail from this point onwards.
 -       */
 -      old_prog = xchg(&priv->channels.params.xdp_prog, prog);
 +      if (was_opened && reset) {
 +              struct mlx5e_channels new_channels = {};
 +
 +              new_channels.params = priv->channels.params;
 +              new_channels.params.xdp_prog = prog;
 +              mlx5e_set_rq_type(priv->mdev, &new_channels.params);
 +              old_prog = priv->channels.params.xdp_prog;
 +
 +              err = mlx5e_safe_switch_channels(priv, &new_channels, mlx5e_xdp_update_state);
 +              if (err)
 +                      goto unlock;
 +      } else {
 +              /* exchange programs, extra prog reference we got from caller
 +               * as long as we don't fail from this point onwards.
 +               */
 +              old_prog = xchg(&priv->channels.params.xdp_prog, prog);
 +      }
 +
        if (old_prog)
                bpf_prog_put(old_prog);
  
 -      if (reset) /* change RQ type according to priv->xdp_prog */
 +      if (!was_opened && reset) /* change RQ type according to priv->xdp_prog */
                mlx5e_set_rq_type(priv->mdev, &priv->channels.params);
  
 -      if (was_opened && reset)
 -              err = mlx5e_open_locked(netdev);
 -
 -      if (!test_bit(MLX5E_STATE_OPENED, &priv->state) || reset)
 +      if (!was_opened || reset)
                goto unlock;
  
        /* exchanging programs w/o reset, we update ref counts on behalf
         */
        for (i = 0; i < priv->channels.num; i++) {
                struct mlx5e_channel *c = priv->channels.c[i];
 +              bool xsk_open = test_bit(MLX5E_CHANNEL_STATE_XSK, c->state);
  
                clear_bit(MLX5E_RQ_STATE_ENABLED, &c->rq.state);
 +              if (xsk_open)
 +                      clear_bit(MLX5E_RQ_STATE_ENABLED, &c->xskrq.state);
                napi_synchronize(&c->napi);
                /* prevent mlx5e_poll_rx_cq from accessing rq->xdp_prog */
  
                old_prog = xchg(&c->rq.xdp_prog, prog);
 +              if (old_prog)
 +                      bpf_prog_put(old_prog);
 +
 +              if (xsk_open) {
 +                      old_prog = xchg(&c->xskrq.xdp_prog, prog);
 +                      if (old_prog)
 +                              bpf_prog_put(old_prog);
 +              }
  
                set_bit(MLX5E_RQ_STATE_ENABLED, &c->rq.state);
 +              if (xsk_open)
 +                      set_bit(MLX5E_RQ_STATE_ENABLED, &c->xskrq.state);
                /* napi_schedule in case we have missed anything */
                napi_schedule(&c->napi);
 -
 -              if (old_prog)
 -                      bpf_prog_put(old_prog);
        }
  
  unlock:
@@@ -4454,9 -4272,6 +4457,9 @@@ static int mlx5e_xdp(struct net_device 
        case XDP_QUERY_PROG:
                xdp->prog_id = mlx5e_xdp_query(dev);
                return 0;
 +      case XDP_SETUP_XSK_UMEM:
 +              return mlx5e_xsk_setup_umem(dev, xdp->xsk.umem,
 +                                          xdp->xsk.queue_id);
        default:
                return -EINVAL;
        }
@@@ -4539,7 -4354,6 +4542,7 @@@ const struct net_device_ops mlx5e_netde
        .ndo_tx_timeout          = mlx5e_tx_timeout,
        .ndo_bpf                 = mlx5e_xdp,
        .ndo_xdp_xmit            = mlx5e_xdp_xmit,
 +      .ndo_xsk_async_xmit      = mlx5e_xsk_async_xmit,
  #ifdef CONFIG_MLX5_EN_ARFS
        .ndo_rx_flow_steer       = mlx5e_rx_flow_steer,
  #endif
@@@ -4609,9 -4423,9 +4612,9 @@@ static bool slow_pci_heuristic(struct m
                link_speed > MLX5E_SLOW_PCI_RATIO * pci_bw;
  }
  
 -static struct net_dim_cq_moder mlx5e_get_def_tx_moderation(u8 cq_period_mode)
 +static struct dim_cq_moder mlx5e_get_def_tx_moderation(u8 cq_period_mode)
  {
 -      struct net_dim_cq_moder moder;
 +      struct dim_cq_moder moder;
  
        moder.cq_period_mode = cq_period_mode;
        moder.pkts = MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_PKTS;
        return moder;
  }
  
 -static struct net_dim_cq_moder mlx5e_get_def_rx_moderation(u8 cq_period_mode)
 +static struct dim_cq_moder mlx5e_get_def_rx_moderation(u8 cq_period_mode)
  {
 -      struct net_dim_cq_moder moder;
 +      struct dim_cq_moder moder;
  
        moder.cq_period_mode = cq_period_mode;
        moder.pkts = MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS;
  static u8 mlx5_to_net_dim_cq_period_mode(u8 cq_period_mode)
  {
        return cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE ?
 -              NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE :
 -              NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
 +              DIM_CQ_PERIOD_MODE_START_FROM_CQE :
 +              DIM_CQ_PERIOD_MODE_START_FROM_EQE;
  }
  
  void mlx5e_set_tx_cq_mode_params(struct mlx5e_params *params, u8 cq_period_mode)
@@@ -4691,13 -4505,11 +4694,13 @@@ void mlx5e_build_rq_params(struct mlx5_
         * - Striding RQ configuration is not possible/supported.
         * - Slow PCI heuristic.
         * - Legacy RQ would use linear SKB while Striding RQ would use non-linear.
 +       *
 +       * No XSK params: checking the availability of striding RQ in general.
         */
        if (!slow_pci_heuristic(mdev) &&
            mlx5e_striding_rq_possible(mdev, params) &&
 -          (mlx5e_rx_mpwqe_is_linear_skb(mdev, params) ||
 -           !mlx5e_rx_is_linear_skb(params)))
 +          (mlx5e_rx_mpwqe_is_linear_skb(mdev, params, NULL) ||
 +           !mlx5e_rx_is_linear_skb(params, NULL)))
                MLX5E_SET_PFLAG(params, MLX5E_PFLAG_RX_STRIDING_RQ, true);
        mlx5e_set_rq_type(mdev, params);
        mlx5e_init_rq_type_params(mdev, params);
@@@ -4719,7 -4531,6 +4722,7 @@@ void mlx5e_build_rss_params(struct mlx5
  }
  
  void mlx5e_build_nic_params(struct mlx5_core_dev *mdev,
 +                          struct mlx5e_xsk *xsk,
                            struct mlx5e_rss_params *rss_params,
                            struct mlx5e_params *params,
                            u16 max_channels, u16 mtu)
        /* HW LRO */
  
        /* TODO: && MLX5_CAP_ETH(mdev, lro_cap) */
 -      if (params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ)
 -              if (!mlx5e_rx_mpwqe_is_linear_skb(mdev, params))
 +      if (params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
 +              /* No XSK params: checking the availability of striding RQ in general. */
 +              if (!mlx5e_rx_mpwqe_is_linear_skb(mdev, params, NULL))
                        params->lro_en = !slow_pci_heuristic(mdev);
 +      }
        params->lro_timeout = mlx5e_choose_lro_timeout(mdev, MLX5E_DEFAULT_LRO_TIMEOUT);
  
        /* CQ moderation params */
        mlx5e_build_rss_params(rss_params, params->num_channels);
        params->tunneled_offload_en =
                mlx5e_tunnel_inner_ft_supported(mdev);
 +
 +      /* AF_XDP */
 +      params->xsk = xsk;
  }
  
  static void mlx5e_set_netdev_dev_addr(struct net_device *netdev)
  {
        struct mlx5e_priv *priv = netdev_priv(netdev);
  
 -      mlx5_query_nic_vport_mac_address(priv->mdev, 0, netdev->dev_addr);
 +      mlx5_query_mac_address(priv->mdev, netdev->dev_addr);
        if (is_zero_ether_addr(netdev->dev_addr) &&
            !MLX5_CAP_GEN(priv->mdev, vport_group_manager)) {
                eth_hw_addr_random(netdev);
@@@ -4816,18 -4622,14 +4819,18 @@@ static void mlx5e_build_nic_netdev(stru
        netdev->ethtool_ops       = &mlx5e_ethtool_ops;
  
        netdev->vlan_features    |= NETIF_F_SG;
 -      netdev->vlan_features    |= NETIF_F_IP_CSUM;
 -      netdev->vlan_features    |= NETIF_F_IPV6_CSUM;
 +      netdev->vlan_features    |= NETIF_F_HW_CSUM;
        netdev->vlan_features    |= NETIF_F_GRO;
        netdev->vlan_features    |= NETIF_F_TSO;
        netdev->vlan_features    |= NETIF_F_TSO6;
        netdev->vlan_features    |= NETIF_F_RXCSUM;
        netdev->vlan_features    |= NETIF_F_RXHASH;
  
 +      netdev->mpls_features    |= NETIF_F_SG;
 +      netdev->mpls_features    |= NETIF_F_HW_CSUM;
 +      netdev->mpls_features    |= NETIF_F_TSO;
 +      netdev->mpls_features    |= NETIF_F_TSO6;
 +
        netdev->hw_enc_features  |= NETIF_F_HW_VLAN_CTAG_TX;
        netdev->hw_enc_features  |= NETIF_F_HW_VLAN_CTAG_RX;
  
  
        if (mlx5_vxlan_allowed(mdev->vxlan) || mlx5_geneve_tx_allowed(mdev) ||
            MLX5_CAP_ETH(mdev, tunnel_stateless_gre)) {
 -              netdev->hw_enc_features |= NETIF_F_IP_CSUM;
 -              netdev->hw_enc_features |= NETIF_F_IPV6_CSUM;
 +              netdev->hw_enc_features |= NETIF_F_HW_CSUM;
                netdev->hw_enc_features |= NETIF_F_TSO;
                netdev->hw_enc_features |= NETIF_F_TSO6;
                netdev->hw_enc_features |= NETIF_F_GSO_PARTIAL;
@@@ -4956,7 -4759,7 +4959,7 @@@ static int mlx5e_nic_init(struct mlx5_c
        if (err)
                return err;
  
 -      mlx5e_build_nic_params(mdev, rss, &priv->channels.params,
 +      mlx5e_build_nic_params(mdev, &priv->xsk, rss, &priv->channels.params,
                               mlx5e_get_netdev_max_channels(netdev),
                               netdev->mtu);
  
@@@ -4998,7 -4801,7 +5001,7 @@@ static int mlx5e_init_nic_rx(struct mlx
        if (err)
                goto err_close_drop_rq;
  
 -      err = mlx5e_create_direct_rqts(priv);
 +      err = mlx5e_create_direct_rqts(priv, priv->direct_tir);
        if (err)
                goto err_destroy_indirect_rqts;
  
        if (err)
                goto err_destroy_direct_rqts;
  
 -      err = mlx5e_create_direct_tirs(priv);
 +      err = mlx5e_create_direct_tirs(priv, priv->direct_tir);
        if (err)
                goto err_destroy_indirect_tirs;
  
 +      err = mlx5e_create_direct_rqts(priv, priv->xsk_tir);
 +      if (unlikely(err))
 +              goto err_destroy_direct_tirs;
 +
 +      err = mlx5e_create_direct_tirs(priv, priv->xsk_tir);
 +      if (unlikely(err))
 +              goto err_destroy_xsk_rqts;
 +
        err = mlx5e_create_flow_steering(priv);
        if (err) {
                mlx5_core_warn(mdev, "create flow steering failed, %d\n", err);
 -              goto err_destroy_direct_tirs;
 +              goto err_destroy_xsk_tirs;
        }
  
        err = mlx5e_tc_nic_init(priv);
  
  err_destroy_flow_steering:
        mlx5e_destroy_flow_steering(priv);
 +err_destroy_xsk_tirs:
 +      mlx5e_destroy_direct_tirs(priv, priv->xsk_tir);
 +err_destroy_xsk_rqts:
 +      mlx5e_destroy_direct_rqts(priv, priv->xsk_tir);
  err_destroy_direct_tirs:
 -      mlx5e_destroy_direct_tirs(priv);
 +      mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
  err_destroy_indirect_tirs:
        mlx5e_destroy_indirect_tirs(priv, true);
  err_destroy_direct_rqts:
 -      mlx5e_destroy_direct_rqts(priv);
 +      mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
  err_destroy_indirect_rqts:
        mlx5e_destroy_rqt(priv, &priv->indir_rqt);
  err_close_drop_rq:
@@@ -5055,11 -4846,9 +5058,11 @@@ static void mlx5e_cleanup_nic_rx(struc
  {
        mlx5e_tc_nic_cleanup(priv);
        mlx5e_destroy_flow_steering(priv);
 -      mlx5e_destroy_direct_tirs(priv);
 +      mlx5e_destroy_direct_tirs(priv, priv->xsk_tir);
 +      mlx5e_destroy_direct_rqts(priv, priv->xsk_tir);
 +      mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
        mlx5e_destroy_indirect_tirs(priv, true);
 -      mlx5e_destroy_direct_rqts(priv);
 +      mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
        mlx5e_destroy_rqt(priv, &priv->indir_rqt);
        mlx5e_close_drop_rq(&priv->drop_rq);
        mlx5e_destroy_q_counters(priv);
@@@ -5141,11 -4930,6 +5144,11 @@@ static void mlx5e_nic_disable(struct ml
        mlx5_lag_remove(mdev);
  }
  
 +int mlx5e_update_nic_rx(struct mlx5e_priv *priv)
 +{
 +      return mlx5e_refresh_tirs(priv, false);
 +}
 +
  static const struct mlx5e_profile mlx5e_nic_profile = {
        .init              = mlx5e_nic_init,
        .cleanup           = mlx5e_nic_cleanup,
        .cleanup_tx        = mlx5e_cleanup_nic_tx,
        .enable            = mlx5e_nic_enable,
        .disable           = mlx5e_nic_disable,
 +      .update_rx         = mlx5e_update_nic_rx,
        .update_stats      = mlx5e_update_ndo_stats,
        .update_carrier    = mlx5e_update_carrier,
        .rx_handlers.handle_rx_cqe       = mlx5e_handle_rx_cqe,
@@@ -5215,7 -4998,7 +5218,7 @@@ struct net_device *mlx5e_create_netdev(
  
        netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv),
                                    nch * profile->max_tc,
 -                                  nch);
 +                                  nch * MLX5E_NUM_RQ_GROUPS);
        if (!netdev) {
                mlx5_core_err(mdev, "alloc_etherdev_mqs() failed\n");
                return NULL;
@@@ -5353,7 -5136,7 +5356,7 @@@ static void *mlx5e_add(struct mlx5_core
  
  #ifdef CONFIG_MLX5_ESWITCH
        if (MLX5_ESWITCH_MANAGER(mdev) &&
 -          mlx5_eswitch_mode(mdev->priv.eswitch) == SRIOV_OFFLOADS) {
 +          mlx5_eswitch_mode(mdev->priv.eswitch) == MLX5_ESWITCH_OFFLOADS) {
                mlx5e_rep_register_vport_reps(mdev);
                return mdev;
        }
@@@ -34,7 -34,6 +34,7 @@@
  #include <linux/ip.h>
  #include <linux/ipv6.h>
  #include <linux/tcp.h>
 +#include <linux/indirect_call_wrapper.h>
  #include <net/ip6_checksum.h>
  #include <net/page_pool.h>
  #include <net/inet_ecn.h>
@@@ -47,7 -46,6 +47,7 @@@
  #include "en_accel/tls_rxtx.h"
  #include "lib/clock.h"
  #include "en/xdp.h"
 +#include "en/xsk/rx.h"
  
  static inline bool mlx5e_rx_hw_stamp(struct hwtstamp_config *config)
  {
@@@ -236,8 -234,8 +236,8 @@@ static inline bool mlx5e_rx_cache_get(s
        return true;
  }
  
 -static inline int mlx5e_page_alloc_mapped(struct mlx5e_rq *rq,
 -                                        struct mlx5e_dma_info *dma_info)
 +static inline int mlx5e_page_alloc_pool(struct mlx5e_rq *rq,
 +                                      struct mlx5e_dma_info *dma_info)
  {
        if (mlx5e_rx_cache_get(rq, dma_info))
                return 0;
        dma_info->addr = dma_map_page(rq->pdev, dma_info->page, 0,
                                      PAGE_SIZE, rq->buff.map_dir);
        if (unlikely(dma_mapping_error(rq->pdev, dma_info->addr))) {
 -              put_page(dma_info->page);
 +              page_pool_recycle_direct(rq->page_pool, dma_info->page);
                dma_info->page = NULL;
                return -ENOMEM;
        }
        return 0;
  }
  
 +static inline int mlx5e_page_alloc(struct mlx5e_rq *rq,
 +                                 struct mlx5e_dma_info *dma_info)
 +{
 +      if (rq->umem)
 +              return mlx5e_xsk_page_alloc_umem(rq, dma_info);
 +      else
 +              return mlx5e_page_alloc_pool(rq, dma_info);
 +}
 +
  void mlx5e_page_dma_unmap(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info)
  {
        dma_unmap_page(rq->pdev, dma_info->addr, PAGE_SIZE, rq->buff.map_dir);
  }
  
 -void mlx5e_page_release(struct mlx5e_rq *rq, struct mlx5e_dma_info *dma_info,
 -                      bool recycle)
 +void mlx5e_page_release_dynamic(struct mlx5e_rq *rq,
 +                              struct mlx5e_dma_info *dma_info,
 +                              bool recycle)
  {
        if (likely(recycle)) {
                if (mlx5e_rx_cache_put(rq, dma_info))
                page_pool_recycle_direct(rq->page_pool, dma_info->page);
        } else {
                mlx5e_page_dma_unmap(rq, dma_info);
 +              page_pool_release_page(rq->page_pool, dma_info->page);
                put_page(dma_info->page);
        }
  }
  
 +static inline void mlx5e_page_release(struct mlx5e_rq *rq,
 +                                    struct mlx5e_dma_info *dma_info,
 +                                    bool recycle)
 +{
 +      if (rq->umem)
 +              /* The `recycle` parameter is ignored, and the page is always
 +               * put into the Reuse Ring, because there is no way to return
 +               * the page to the userspace when the interface goes down.
 +               */
 +              mlx5e_xsk_page_release(rq, dma_info);
 +      else
 +              mlx5e_page_release_dynamic(rq, dma_info, recycle);
 +}
 +
  static inline int mlx5e_get_rx_frag(struct mlx5e_rq *rq,
                                    struct mlx5e_wqe_frag_info *frag)
  {
                 * offset) should just use the new one without replenishing again
                 * by themselves.
                 */
 -              err = mlx5e_page_alloc_mapped(rq, frag->di);
 +              err = mlx5e_page_alloc(rq, frag->di);
  
        return err;
  }
@@@ -379,13 -352,6 +379,13 @@@ static int mlx5e_alloc_rx_wqes(struct m
        int err;
        int i;
  
 +      if (rq->umem) {
 +              int pages_desired = wqe_bulk << rq->wqe.info.log_num_frags;
 +
 +              if (unlikely(!mlx5e_xsk_pages_enough_umem(rq, pages_desired)))
 +                      return -ENOMEM;
 +      }
 +
        for (i = 0; i < wqe_bulk; i++) {
                struct mlx5e_rx_wqe_cyc *wqe = mlx5_wq_cyc_get_wqe(wq, ix + i);
  
@@@ -433,17 -399,11 +433,17 @@@ mlx5e_copy_skb_header(struct device *pd
  static void
  mlx5e_free_rx_mpwqe(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi, bool recycle)
  {
 -      const bool no_xdp_xmit =
 -              bitmap_empty(wi->xdp_xmit_bitmap, MLX5_MPWRQ_PAGES_PER_WQE);
 +      bool no_xdp_xmit;
        struct mlx5e_dma_info *dma_info = wi->umr.dma_info;
        int i;
  
 +      /* A common case for AF_XDP. */
 +      if (bitmap_full(wi->xdp_xmit_bitmap, MLX5_MPWRQ_PAGES_PER_WQE))
 +              return;
 +
 +      no_xdp_xmit = bitmap_empty(wi->xdp_xmit_bitmap,
 +                                 MLX5_MPWRQ_PAGES_PER_WQE);
 +
        for (i = 0; i < MLX5_MPWRQ_PAGES_PER_WQE; i++)
                if (no_xdp_xmit || !test_bit(i, wi->xdp_xmit_bitmap))
                        mlx5e_page_release(rq, &dma_info[i], recycle);
@@@ -465,6 -425,11 +465,6 @@@ static void mlx5e_post_rx_mpwqe(struct 
        mlx5_wq_ll_update_db_record(wq);
  }
  
 -static inline u16 mlx5e_icosq_wrap_cnt(struct mlx5e_icosq *sq)
 -{
 -      return mlx5_wq_cyc_get_ctr_wrap_cnt(&sq->wq, sq->pc);
 -}
 -
  static inline void mlx5e_fill_icosq_frag_edge(struct mlx5e_icosq *sq,
                                              struct mlx5_wq_cyc *wq,
                                              u16 pi, u16 nnops)
@@@ -492,12 -457,6 +492,12 @@@ static int mlx5e_alloc_rx_mpwqe(struct 
        int err;
        int i;
  
 +      if (rq->umem &&
 +          unlikely(!mlx5e_xsk_pages_enough_umem(rq, MLX5_MPWRQ_PAGES_PER_WQE))) {
 +              err = -ENOMEM;
 +              goto err;
 +      }
 +
        pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
        contig_wqebbs_room = mlx5_wq_cyc_get_contig_wqebbs(wq, pi);
        if (unlikely(contig_wqebbs_room < MLX5E_UMR_WQEBBS)) {
        }
  
        umr_wqe = mlx5_wq_cyc_get_wqe(wq, pi);
 -      if (unlikely(mlx5e_icosq_wrap_cnt(sq) < 2))
 -              memcpy(umr_wqe, &rq->mpwqe.umr_wqe,
 -                     offsetof(struct mlx5e_umr_wqe, inline_mtts));
 +      memcpy(umr_wqe, &rq->mpwqe.umr_wqe, offsetof(struct mlx5e_umr_wqe, inline_mtts));
  
        for (i = 0; i < MLX5_MPWRQ_PAGES_PER_WQE; i++, dma_info++) {
 -              err = mlx5e_page_alloc_mapped(rq, dma_info);
 +              err = mlx5e_page_alloc(rq, dma_info);
                if (unlikely(err))
                        goto err_unmap;
                umr_wqe->inline_mtts[i].ptag = cpu_to_be64(dma_info->addr | MLX5_EN_WR);
        umr_wqe->uctrl.xlt_offset = cpu_to_be16(xlt_offset);
  
        sq->db.ico_wqe[pi].opcode = MLX5_OPCODE_UMR;
 +      sq->db.ico_wqe[pi].umr.rq = rq;
        sq->pc += MLX5E_UMR_WQEBBS;
  
        sq->doorbell_cseg = &umr_wqe->ctrl;
@@@ -536,8 -496,6 +536,8 @@@ err_unmap
                dma_info--;
                mlx5e_page_release(rq, dma_info, true);
        }
 +
 +err:
        rq->stats->buff_alloc_err++;
  
        return err;
@@@ -584,10 -542,11 +584,10 @@@ bool mlx5e_post_rx_wqes(struct mlx5e_r
        return !!err;
  }
  
 -static void mlx5e_poll_ico_cq(struct mlx5e_cq *cq, struct mlx5e_rq *rq)
 +void mlx5e_poll_ico_cq(struct mlx5e_cq *cq)
  {
        struct mlx5e_icosq *sq = container_of(cq, struct mlx5e_icosq, cq);
        struct mlx5_cqe64 *cqe;
 -      u8  completed_umr = 0;
        u16 sqcc;
        int i;
  
  
                        if (likely(wi->opcode == MLX5_OPCODE_UMR)) {
                                sqcc += MLX5E_UMR_WQEBBS;
 -                              completed_umr++;
 +                              wi->umr.rq->mpwqe.umr_completed++;
                        } else if (likely(wi->opcode == MLX5_OPCODE_NOP)) {
                                sqcc++;
                        } else {
        sq->cc = sqcc;
  
        mlx5_cqwq_update_db_record(&cq->wq);
 -
 -      if (likely(completed_umr)) {
 -              mlx5e_post_rx_mpwqe(rq, completed_umr);
 -              rq->mpwqe.umr_in_progress -= completed_umr;
 -      }
  }
  
  bool mlx5e_post_rx_mpwqes(struct mlx5e_rq *rq)
  {
        struct mlx5e_icosq *sq = &rq->channel->icosq;
        struct mlx5_wq_ll *wq = &rq->mpwqe.wq;
 +      u8  umr_completed = rq->mpwqe.umr_completed;
 +      int alloc_err = 0;
        u8  missing, i;
        u16 head;
  
        if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state)))
                return false;
  
 -      mlx5e_poll_ico_cq(&sq->cq, rq);
 +      if (umr_completed) {
 +              mlx5e_post_rx_mpwqe(rq, umr_completed);
 +              rq->mpwqe.umr_in_progress -= umr_completed;
 +              rq->mpwqe.umr_completed = 0;
 +      }
  
        missing = mlx5_wq_ll_missing(wq) - rq->mpwqe.umr_in_progress;
  
        head = rq->mpwqe.actual_wq_head;
        i = missing;
        do {
 -              if (unlikely(mlx5e_alloc_rx_mpwqe(rq, head)))
 +              alloc_err = mlx5e_alloc_rx_mpwqe(rq, head);
 +
 +              if (unlikely(alloc_err))
                        break;
                head = mlx5_wq_ll_get_wqe_next_ix(wq, head);
        } while (--i);
        rq->mpwqe.umr_in_progress += rq->mpwqe.umr_last_bulk;
        rq->mpwqe.actual_wq_head   = head;
  
 +      /* If XSK Fill Ring doesn't have enough frames, busy poll by
 +       * rescheduling the NAPI poll.
 +       */
 +      if (unlikely(alloc_err == -ENOMEM && rq->umem))
 +              return true;
 +
        return false;
  }
  
@@@ -923,8 -873,14 +923,14 @@@ static inline void mlx5e_handle_csum(st
                if (unlikely(get_ip_proto(skb, network_depth, proto) == IPPROTO_SCTP))
                        goto csum_unnecessary;
  
+               stats->csum_complete++;
                skb->ip_summed = CHECKSUM_COMPLETE;
                skb->csum = csum_unfold((__force __sum16)cqe->check_sum);
+               if (test_bit(MLX5E_RQ_STATE_CSUM_FULL, &rq->state))
+                       return; /* CQE csum covers all received bytes */
+               /* csum might need some fixups ...*/
                if (network_depth > ETH_HLEN)
                        /* CQE csum is calculated from the IP header and does
                         * not cover VLAN headers (if present). This will add
                                                 skb->csum);
  
                mlx5e_skb_padding_csum(skb, network_depth, proto, stats);
-               stats->csum_complete++;
                return;
        }
  
@@@ -1066,7 -1021,7 +1071,7 @@@ mlx5e_skb_from_cqe_linear(struct mlx5e_
        }
  
        rcu_read_lock();
 -      consumed = mlx5e_xdp_handle(rq, di, va, &rx_headroom, &cqe_bcnt);
 +      consumed = mlx5e_xdp_handle(rq, di, va, &rx_headroom, &cqe_bcnt, false);
        rcu_read_unlock();
        if (consumed)
                return NULL; /* page/packet was consumed by XDP */
@@@ -1142,10 -1097,7 +1147,10 @@@ void mlx5e_handle_rx_cqe(struct mlx5e_r
        wi       = get_frag(rq, ci);
        cqe_bcnt = be32_to_cpu(cqe->byte_cnt);
  
 -      skb = rq->wqe.skb_from_cqe(rq, cqe, wi, cqe_bcnt);
 +      skb = INDIRECT_CALL_2(rq->wqe.skb_from_cqe,
 +                            mlx5e_skb_from_cqe_linear,
 +                            mlx5e_skb_from_cqe_nonlinear,
 +                            rq, cqe, wi, cqe_bcnt);
        if (!skb) {
                /* probably for XDP */
                if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) {
@@@ -1283,7 -1235,7 +1288,7 @@@ mlx5e_skb_from_cqe_mpwrq_linear(struct 
        prefetch(data);
  
        rcu_read_lock();
 -      consumed = mlx5e_xdp_handle(rq, di, va, &rx_headroom, &cqe_bcnt32);
 +      consumed = mlx5e_xdp_handle(rq, di, va, &rx_headroom, &cqe_bcnt32, false);
        rcu_read_unlock();
        if (consumed) {
                if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags))
@@@ -1332,10 -1284,8 +1337,10 @@@ void mlx5e_handle_rx_cqe_mpwrq(struct m
  
        cqe_bcnt = mpwrq_get_cqe_byte_cnt(cqe);
  
 -      skb = rq->mpwqe.skb_from_cqe_mpwrq(rq, wi, cqe_bcnt, head_offset,
 -                                         page_idx);
 +      skb = INDIRECT_CALL_2(rq->mpwqe.skb_from_cqe_mpwrq,
 +                            mlx5e_skb_from_cqe_mpwrq_linear,
 +                            mlx5e_skb_from_cqe_mpwrq_nonlinear,
 +                            rq, wi, cqe_bcnt, head_offset, page_idx);
        if (!skb)
                goto mpwrq_cqe_out;
  
@@@ -1382,8 -1332,7 +1387,8 @@@ int mlx5e_poll_rx_cq(struct mlx5e_cq *c
  
                mlx5_cqwq_pop(cqwq);
  
 -              rq->handle_rx_cqe(rq, cqe);
 +              INDIRECT_CALL_2(rq->handle_rx_cqe, mlx5e_handle_rx_cqe_mpwrq,
 +                              mlx5e_handle_rx_cqe, rq, cqe);
        } while ((++work_done < budget) && (cqe = mlx5_cqwq_get_cqe(cqwq)));
  
  out:
@@@ -1493,10 -1442,7 +1498,10 @@@ void mlx5i_handle_rx_cqe(struct mlx5e_r
        wi       = get_frag(rq, ci);
        cqe_bcnt = be32_to_cpu(cqe->byte_cnt);
  
 -      skb = rq->wqe.skb_from_cqe(rq, cqe, wi, cqe_bcnt);
 +      skb = INDIRECT_CALL_2(rq->wqe.skb_from_cqe,
 +                            mlx5e_skb_from_cqe_linear,
 +                            mlx5e_skb_from_cqe_nonlinear,
 +                            rq, cqe, wi, cqe_bcnt);
        if (!skb)
                goto wq_free_wqe;
  
@@@ -1528,10 -1474,7 +1533,10 @@@ void mlx5e_ipsec_handle_rx_cqe(struct m
        wi       = get_frag(rq, ci);
        cqe_bcnt = be32_to_cpu(cqe->byte_cnt);
  
 -      skb = rq->wqe.skb_from_cqe(rq, cqe, wi, cqe_bcnt);
 +      skb = INDIRECT_CALL_2(rq->wqe.skb_from_cqe,
 +                            mlx5e_skb_from_cqe_linear,
 +                            mlx5e_skb_from_cqe_nonlinear,
 +                            rq, cqe, wi, cqe_bcnt);
        if (unlikely(!skb)) {
                /* a DROP, save the page-reuse checks */
                mlx5e_free_rx_wqe(rq, wi, true);
@@@ -134,30 -134,6 +134,30 @@@ static int modify_esw_vport_context_cmd
        return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
  }
  
 +int mlx5_eswitch_modify_esw_vport_context(struct mlx5_eswitch *esw, u16 vport,
 +                                        void *in, int inlen)
 +{
 +      return modify_esw_vport_context_cmd(esw->dev, vport, in, inlen);
 +}
 +
 +static int query_esw_vport_context_cmd(struct mlx5_core_dev *dev, u16 vport,
 +                                     void *out, int outlen)
 +{
 +      u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {};
 +
 +      MLX5_SET(query_esw_vport_context_in, in, opcode,
 +               MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT);
 +      MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport);
 +      MLX5_SET(modify_esw_vport_context_in, in, other_vport, 1);
 +      return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
 +}
 +
 +int mlx5_eswitch_query_esw_vport_context(struct mlx5_eswitch *esw, u16 vport,
 +                                       void *out, int outlen)
 +{
 +      return query_esw_vport_context_cmd(esw->dev, vport, out, outlen);
 +}
 +
  static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u16 vport,
                                  u16 vlan, u8 qos, u8 set_flags)
  {
@@@ -497,7 -473,7 +497,7 @@@ static int esw_add_uc_addr(struct mlx5_
  
  fdb_add:
        /* SRIOV is enabled: Forward UC MAC to vport */
 -      if (esw->fdb_table.legacy.fdb && esw->mode == SRIOV_LEGACY)
 +      if (esw->fdb_table.legacy.fdb && esw->mode == MLX5_ESWITCH_LEGACY)
                vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
  
        esw_debug(esw->dev, "\tADDED UC MAC: vport[%d] %pM fr(%p)\n",
@@@ -897,7 -873,7 +897,7 @@@ static void esw_vport_change_handle_loc
        struct mlx5_eswitch *esw = dev->priv.eswitch;
        u8 mac[ETH_ALEN];
  
 -      mlx5_query_nic_vport_mac_address(dev, vport->vport, mac);
 +      mlx5_query_nic_vport_mac_address(dev, vport->vport, true, mac);
        esw_debug(dev, "vport[%d] Context Changed: perm mac: %pM\n",
                  vport->vport, mac);
  
@@@ -963,7 -939,7 +963,7 @@@ int esw_vport_enable_egress_acl(struct 
                  vport->vport, MLX5_CAP_ESW_EGRESS_ACL(dev, log_max_ft_size));
  
        root_ns = mlx5_get_flow_vport_acl_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_EGRESS,
 -                                                  vport->vport);
 +                      mlx5_eswitch_vport_num_to_index(esw, vport->vport));
        if (!root_ns) {
                esw_warn(dev, "Failed to get E-Switch egress flow namespace for vport (%d)\n", vport->vport);
                return -EOPNOTSUPP;
@@@ -1081,7 -1057,7 +1081,7 @@@ int esw_vport_enable_ingress_acl(struc
                  vport->vport, MLX5_CAP_ESW_INGRESS_ACL(dev, log_max_ft_size));
  
        root_ns = mlx5_get_flow_vport_acl_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS,
 -                                                  vport->vport);
 +                      mlx5_eswitch_vport_num_to_index(esw, vport->vport));
        if (!root_ns) {
                esw_warn(dev, "Failed to get E-Switch ingress flow namespace for vport (%d)\n", vport->vport);
                return -EOPNOTSUPP;
@@@ -1192,8 -1168,6 +1192,8 @@@ void esw_vport_cleanup_ingress_rules(st
  
        vport->ingress.drop_rule = NULL;
        vport->ingress.allow_rule = NULL;
 +
 +      esw_vport_del_ingress_acl_modify_metadata(esw, vport);
  }
  
  void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw,
@@@ -1553,7 -1527,6 +1553,7 @@@ static void esw_apply_vport_conf(struc
                                 struct mlx5_vport *vport)
  {
        u16 vport_num = vport->vport;
 +      int flags;
  
        if (esw->manager_vport == vport_num)
                return;
                                                vport->info.node_guid);
        }
  
 +      flags = (vport->info.vlan || vport->info.qos) ?
 +              SET_VLAN_STRIP | SET_VLAN_INSERT : 0;
        modify_esw_vport_cvlan(esw->dev, vport_num, vport->info.vlan, vport->info.qos,
 -                             (vport->info.vlan || vport->info.qos));
 +                             flags);
  
        /* Only legacy mode needs ACLs */
 -      if (esw->mode == SRIOV_LEGACY) {
 +      if (esw->mode == MLX5_ESWITCH_LEGACY) {
                esw_vport_ingress_config(esw, vport);
                esw_vport_egress_config(esw, vport);
        }
@@@ -1629,7 -1600,7 +1629,7 @@@ static void esw_enable_vport(struct mlx
        esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num);
  
        /* Create steering drop counters for ingress and egress ACLs */
 -      if (vport_num && esw->mode == SRIOV_LEGACY)
 +      if (vport_num && esw->mode == MLX5_ESWITCH_LEGACY)
                esw_vport_create_drop_counters(vport);
  
        /* Restore old vport configuration */
@@@ -1683,7 -1654,7 +1683,7 @@@ static void esw_disable_vport(struct ml
        vport->enabled_events = 0;
        esw_vport_disable_qos(esw, vport);
        if (esw->manager_vport != vport_num &&
 -          esw->mode == SRIOV_LEGACY) {
 +          esw->mode == MLX5_ESWITCH_LEGACY) {
                mlx5_modify_vport_admin_state(esw->dev,
                                              MLX5_VPORT_STATE_OP_MOD_ESW_VPORT,
                                              vport_num, 1,
@@@ -1715,91 -1686,54 +1715,91 @@@ static int eswitch_vport_event(struct n
        return NOTIFY_OK;
  }
  
 +/**
 + * mlx5_esw_query_functions - Returns raw output about functions state
 + * @dev:      Pointer to device to query
 + *
 + * mlx5_esw_query_functions() allocates and returns functions changed
 + * raw output memory pointer from device on success. Otherwise returns ERR_PTR.
 + * Caller must free the memory using kvfree() when valid pointer is returned.
 + */
 +const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev)
 +{
 +      int outlen = MLX5_ST_SZ_BYTES(query_esw_functions_out);
 +      u32 in[MLX5_ST_SZ_DW(query_esw_functions_in)] = {};
 +      u32 *out;
 +      int err;
 +
 +      out = kvzalloc(outlen, GFP_KERNEL);
 +      if (!out)
 +              return ERR_PTR(-ENOMEM);
 +
 +      MLX5_SET(query_esw_functions_in, in, opcode,
 +               MLX5_CMD_OP_QUERY_ESW_FUNCTIONS);
 +
 +      err = mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
 +      if (!err)
 +              return out;
 +
 +      kvfree(out);
 +      return ERR_PTR(err);
 +}
 +
 +static void mlx5_eswitch_event_handlers_register(struct mlx5_eswitch *esw)
 +{
 +      MLX5_NB_INIT(&esw->nb, eswitch_vport_event, NIC_VPORT_CHANGE);
 +      mlx5_eq_notifier_register(esw->dev, &esw->nb);
 +
 +      if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev)) {
 +              MLX5_NB_INIT(&esw->esw_funcs.nb, mlx5_esw_funcs_changed_handler,
 +                           ESW_FUNCTIONS_CHANGED);
 +              mlx5_eq_notifier_register(esw->dev, &esw->esw_funcs.nb);
 +      }
 +}
 +
 +static void mlx5_eswitch_event_handlers_unregister(struct mlx5_eswitch *esw)
 +{
 +      if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev))
 +              mlx5_eq_notifier_unregister(esw->dev, &esw->esw_funcs.nb);
 +
 +      mlx5_eq_notifier_unregister(esw->dev, &esw->nb);
 +
 +      flush_workqueue(esw->work_queue);
 +}
 +
  /* Public E-Switch API */
  #define ESW_ALLOWED(esw) ((esw) && MLX5_ESWITCH_MANAGER((esw)->dev))
  
 -int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode)
 +int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int mode)
  {
 -      int vf_nvports = 0, total_nvports = 0;
        struct mlx5_vport *vport;
        int err;
        int i, enabled_events;
  
        if (!ESW_ALLOWED(esw) ||
            !MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) {
 -              esw_warn(esw->dev, "E-Switch FDB is not supported, aborting ...\n");
 +              esw_warn(esw->dev, "FDB is not supported, aborting ...\n");
                return -EOPNOTSUPP;
        }
  
        if (!MLX5_CAP_ESW_INGRESS_ACL(esw->dev, ft_support))
 -              esw_warn(esw->dev, "E-Switch ingress ACL is not supported by FW\n");
 +              esw_warn(esw->dev, "ingress ACL is not supported by FW\n");
  
        if (!MLX5_CAP_ESW_EGRESS_ACL(esw->dev, ft_support))
 -              esw_warn(esw->dev, "E-Switch engress ACL is not supported by FW\n");
 -
 -      esw_info(esw->dev, "E-Switch enable SRIOV: nvfs(%d) mode (%d)\n", nvfs, mode);
 -
 -      if (mode == SRIOV_OFFLOADS) {
 -              if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
 -                      err = mlx5_query_host_params_num_vfs(esw->dev, &vf_nvports);
 -                      if (err)
 -                              return err;
 -                      total_nvports = esw->total_vports;
 -              } else {
 -                      vf_nvports = nvfs;
 -                      total_nvports = nvfs + MLX5_SPECIAL_VPORTS(esw->dev);
 -              }
 -      }
 +              esw_warn(esw->dev, "engress ACL is not supported by FW\n");
  
        esw->mode = mode;
  
        mlx5_lag_update(esw->dev);
  
 -      if (mode == SRIOV_LEGACY) {
 +      if (mode == MLX5_ESWITCH_LEGACY) {
                err = esw_create_legacy_table(esw);
                if (err)
                        goto abort;
        } else {
                mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH);
                mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
 -              err = esw_offloads_init(esw, vf_nvports, total_nvports);
 +              err = esw_offloads_init(esw);
        }
  
        if (err)
        if (err)
                esw_warn(esw->dev, "Failed to create eswitch TSAR");
  
 -      /* Don't enable vport events when in SRIOV_OFFLOADS mode, since:
 -       * 1. L2 table (MPFS) is programmed by PF/VF representors netdevs set_rx_mode
 -       * 2. FDB/Eswitch is programmed by user space tools
 -       */
 -      enabled_events = (mode == SRIOV_LEGACY) ? SRIOV_VPORT_EVENTS : 0;
 +      enabled_events = (mode == MLX5_ESWITCH_LEGACY) ? SRIOV_VPORT_EVENTS :
 +              UC_ADDR_CHANGE;
  
        /* Enable PF vport */
        vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF);
        }
  
        /* Enable VF vports */
 -      mlx5_esw_for_each_vf_vport(esw, i, vport, nvfs)
 +      mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs)
                esw_enable_vport(esw, vport, enabled_events);
  
 -      if (mode == SRIOV_LEGACY) {
 -              MLX5_NB_INIT(&esw->nb, eswitch_vport_event, NIC_VPORT_CHANGE);
 -              mlx5_eq_notifier_register(esw->dev, &esw->nb);
 -      }
 +      mlx5_eswitch_event_handlers_register(esw);
 +
 +      esw_info(esw->dev, "Enable: mode(%s), nvfs(%d), active vports(%d)\n",
 +               mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
 +               esw->esw_funcs.num_vfs, esw->enabled_vports);
  
 -      esw_info(esw->dev, "SRIOV enabled: active vports(%d)\n",
 -               esw->enabled_vports);
        return 0;
  
  abort:
 -      esw->mode = SRIOV_NONE;
 +      esw->mode = MLX5_ESWITCH_NONE;
  
 -      if (mode == SRIOV_OFFLOADS) {
 +      if (mode == MLX5_ESWITCH_OFFLOADS) {
                mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
                mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH);
        }
        return err;
  }
  
 -void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw)
 +void mlx5_eswitch_disable(struct mlx5_eswitch *esw)
  {
        struct esw_mc_addr *mc_promisc;
        struct mlx5_vport *vport;
        int old_mode;
        int i;
  
 -      if (!ESW_ALLOWED(esw) || esw->mode == SRIOV_NONE)
 +      if (!ESW_ALLOWED(esw) || esw->mode == MLX5_ESWITCH_NONE)
                return;
  
 -      esw_info(esw->dev, "disable SRIOV: active vports(%d) mode(%d)\n",
 -               esw->enabled_vports, esw->mode);
 +      esw_info(esw->dev, "Disable: mode(%s), nvfs(%d), active vports(%d)\n",
 +               esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
 +               esw->esw_funcs.num_vfs, esw->enabled_vports);
  
        mc_promisc = &esw->mc_promisc;
 -
 -      if (esw->mode == SRIOV_LEGACY)
 -              mlx5_eq_notifier_unregister(esw->dev, &esw->nb);
 +      mlx5_eswitch_event_handlers_unregister(esw);
  
        mlx5_esw_for_all_vports(esw, i, vport)
                esw_disable_vport(esw, vport);
  
        esw_destroy_tsar(esw);
  
 -      if (esw->mode == SRIOV_LEGACY)
 +      if (esw->mode == MLX5_ESWITCH_LEGACY)
                esw_destroy_legacy_table(esw);
 -      else if (esw->mode == SRIOV_OFFLOADS)
 +      else if (esw->mode == MLX5_ESWITCH_OFFLOADS)
                esw_offloads_cleanup(esw);
  
        old_mode = esw->mode;
 -      esw->mode = SRIOV_NONE;
 +      esw->mode = MLX5_ESWITCH_NONE;
  
        mlx5_lag_update(esw->dev);
  
 -      if (old_mode == SRIOV_OFFLOADS) {
 +      if (old_mode == MLX5_ESWITCH_OFFLOADS) {
                mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
                mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH);
        }
  
  int mlx5_eswitch_init(struct mlx5_core_dev *dev)
  {
 -      int total_vports = MLX5_TOTAL_VPORTS(dev);
        struct mlx5_eswitch *esw;
        struct mlx5_vport *vport;
 +      int total_vports;
        int err, i;
  
        if (!MLX5_VPORT_MANAGER(dev))
                return 0;
  
 +      total_vports = mlx5_eswitch_get_total_vports(dev);
 +
        esw_info(dev,
                 "Total vports %d, per vport: max uc(%d) max mc(%d)\n",
                 total_vports,
  
        esw->dev = dev;
        esw->manager_vport = mlx5_eswitch_manager_vport(dev);
 +      esw->first_host_vport = mlx5_eswitch_first_host_vport_num(dev);
  
        esw->work_queue = create_singlethread_workqueue("mlx5_esw_wq");
        if (!esw->work_queue) {
        }
  
        esw->enabled_vports = 0;
 -      esw->mode = SRIOV_NONE;
 +      esw->mode = MLX5_ESWITCH_NONE;
        esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE;
-       if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) &&
-           MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap))
-               esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_BASIC;
-       else
-               esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
  
        dev->priv.eswitch = esw;
        return 0;
@@@ -2014,7 -1945,7 +2009,7 @@@ int mlx5_eswitch_set_vport_mac(struct m
  
        ether_addr_copy(evport->info.mac, mac);
        evport->info.node_guid = node_guid;
 -      if (evport->enabled && esw->mode == SRIOV_LEGACY)
 +      if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY)
                err = esw_vport_ingress_config(esw, evport);
  
  unlock:
@@@ -2098,7 -2029,7 +2093,7 @@@ int __mlx5_eswitch_set_vport_vlan(struc
  
        evport->info.vlan = vlan;
        evport->info.qos = qos;
 -      if (evport->enabled && esw->mode == SRIOV_LEGACY) {
 +      if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY) {
                err = esw_vport_ingress_config(esw, evport);
                if (err)
                        goto unlock;
@@@ -2140,7 -2071,7 +2135,7 @@@ int mlx5_eswitch_set_vport_spoofchk(str
                mlx5_core_warn(esw->dev,
                               "Spoofchk in set while MAC is invalid, vport(%d)\n",
                               evport->vport);
 -      if (evport->enabled && esw->mode == SRIOV_LEGACY)
 +      if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY)
                err = esw_vport_ingress_config(esw, evport);
        if (err)
                evport->info.spoofchk = pschk;
@@@ -2236,7 -2167,7 +2231,7 @@@ int mlx5_eswitch_set_vepa(struct mlx5_e
                return -EPERM;
  
        mutex_lock(&esw->state_lock);
 -      if (esw->mode != SRIOV_LEGACY) {
 +      if (esw->mode != MLX5_ESWITCH_LEGACY) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@@ -2259,7 -2190,7 +2254,7 @@@ int mlx5_eswitch_get_vepa(struct mlx5_e
                return -EPERM;
  
        mutex_lock(&esw->state_lock);
 -      if (esw->mode != SRIOV_LEGACY) {
 +      if (esw->mode != MLX5_ESWITCH_LEGACY) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@@ -2402,7 -2333,7 +2397,7 @@@ static int mlx5_eswitch_query_vport_dro
        u64 bytes = 0;
        int err = 0;
  
 -      if (!vport->enabled || esw->mode != SRIOV_LEGACY)
 +      if (!vport->enabled || esw->mode != MLX5_ESWITCH_LEGACY)
                return 0;
  
        if (vport->egress.drop_counter)
@@@ -2512,27 -2443,16 +2507,27 @@@ free_out
  
  u8 mlx5_eswitch_mode(struct mlx5_eswitch *esw)
  {
 -      return ESW_ALLOWED(esw) ? esw->mode : SRIOV_NONE;
 +      return ESW_ALLOWED(esw) ? esw->mode : MLX5_ESWITCH_NONE;
  }
  EXPORT_SYMBOL_GPL(mlx5_eswitch_mode);
  
 +enum devlink_eswitch_encap_mode
 +mlx5_eswitch_get_encap_mode(const struct mlx5_core_dev *dev)
 +{
 +      struct mlx5_eswitch *esw;
 +
 +      esw = dev->priv.eswitch;
 +      return ESW_ALLOWED(esw) ? esw->offloads.encap :
 +              DEVLINK_ESWITCH_ENCAP_MODE_NONE;
 +}
 +EXPORT_SYMBOL(mlx5_eswitch_get_encap_mode);
 +
  bool mlx5_esw_lag_prereq(struct mlx5_core_dev *dev0, struct mlx5_core_dev *dev1)
  {
 -      if ((dev0->priv.eswitch->mode == SRIOV_NONE &&
 -           dev1->priv.eswitch->mode == SRIOV_NONE) ||
 -          (dev0->priv.eswitch->mode == SRIOV_OFFLOADS &&
 -           dev1->priv.eswitch->mode == SRIOV_OFFLOADS))
 +      if ((dev0->priv.eswitch->mode == MLX5_ESWITCH_NONE &&
 +           dev1->priv.eswitch->mode == MLX5_ESWITCH_NONE) ||
 +          (dev0->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS &&
 +           dev1->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS))
                return true;
  
        return false;
  bool mlx5_esw_multipath_prereq(struct mlx5_core_dev *dev0,
                               struct mlx5_core_dev *dev1)
  {
 -      return (dev0->priv.eswitch->mode == SRIOV_OFFLOADS &&
 -              dev1->priv.eswitch->mode == SRIOV_OFFLOADS);
 +      return (dev0->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS &&
 +              dev1->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS);
 +}
 +
 +void mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, const int num_vfs)
 +{
 +      const u32 *out;
 +
 +      WARN_ON_ONCE(esw->mode != MLX5_ESWITCH_NONE);
 +
 +      if (!mlx5_core_is_ecpf_esw_manager(esw->dev)) {
 +              esw->esw_funcs.num_vfs = num_vfs;
 +              return;
 +      }
 +
 +      out = mlx5_esw_query_functions(esw->dev);
 +      if (IS_ERR(out))
 +              return;
 +
 +      esw->esw_funcs.num_vfs = MLX5_GET(query_esw_functions_out, out,
 +                                        host_params_context.host_num_of_vfs);
 +      kvfree(out);
  }
@@@ -41,6 -41,7 +41,6 @@@
  #include "en.h"
  #include "fs_core.h"
  #include "lib/devcom.h"
 -#include "ecpf.h"
  #include "lib/eq.h"
  
  /* There are two match-all miss flows, one for unicast dst mac and
@@@ -88,53 -89,6 +88,53 @@@ u16 mlx5_eswitch_get_prio_range(struct 
        return 1;
  }
  
 +static void
 +mlx5_eswitch_set_rule_source_port(struct mlx5_eswitch *esw,
 +                                struct mlx5_flow_spec *spec,
 +                                struct mlx5_esw_flow_attr *attr)
 +{
 +      void *misc2;
 +      void *misc;
 +
 +      /* Use metadata matching because vport is not represented by single
 +       * VHCA in dual-port RoCE mode, and matching on source vport may fail.
 +       */
 +      if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
 +              misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
 +              MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0,
 +                       mlx5_eswitch_get_vport_metadata_for_match(attr->in_mdev->priv.eswitch,
 +                                                                 attr->in_rep->vport));
 +
 +              misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
 +              MLX5_SET_TO_ONES(fte_match_set_misc2, misc2, metadata_reg_c_0);
 +
 +              spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
 +              misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
 +              if (memchr_inv(misc, 0, MLX5_ST_SZ_BYTES(fte_match_set_misc)))
 +                      spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
 +      } else {
 +              misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
 +              MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
 +
 +              if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
 +                      MLX5_SET(fte_match_set_misc, misc,
 +                               source_eswitch_owner_vhca_id,
 +                               MLX5_CAP_GEN(attr->in_mdev, vhca_id));
 +
 +              misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
 +              MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
 +              if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
 +                      MLX5_SET_TO_ONES(fte_match_set_misc, misc,
 +                                       source_eswitch_owner_vhca_id);
 +
 +              spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
 +      }
 +
 +      if (MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source) &&
 +          attr->in_rep->vport == MLX5_VPORT_UPLINK)
 +              spec->flow_context.flow_source = MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK;
 +}
 +
  struct mlx5_flow_handle *
  mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
                                struct mlx5_flow_spec *spec,
        struct mlx5_flow_handle *rule;
        struct mlx5_flow_table *fdb;
        int j, i = 0;
 -      void *misc;
  
 -      if (esw->mode != SRIOV_OFFLOADS)
 +      if (esw->mode != MLX5_ESWITCH_OFFLOADS)
                return ERR_PTR(-EOPNOTSUPP);
  
        flow_act.action = attr->action;
                i++;
        }
  
 -      misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
 -      MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
 -
 -      if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
 -              MLX5_SET(fte_match_set_misc, misc,
 -                       source_eswitch_owner_vhca_id,
 -                       MLX5_CAP_GEN(attr->in_mdev, vhca_id));
 +      mlx5_eswitch_set_rule_source_port(esw, spec, attr);
  
 -      misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
 -      MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
 -      if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
 -              MLX5_SET_TO_ONES(fte_match_set_misc, misc,
 -                               source_eswitch_owner_vhca_id);
 -
 -      spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
        if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DECAP) {
                if (attr->tunnel_match_level != MLX5_MATCH_NONE)
                        spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
                goto err_esw_get;
        }
  
 -      rule = mlx5_add_flow_rules(fdb, spec, &flow_act, dest, i);
 +      if (mlx5_eswitch_termtbl_required(esw, &flow_act, spec))
 +              rule = mlx5_eswitch_add_termtbl_rule(esw, fdb, spec, attr,
 +                                                   &flow_act, dest, i);
 +      else
 +              rule = mlx5_add_flow_rules(fdb, spec, &flow_act, dest, i);
        if (IS_ERR(rule))
                goto err_add_rule;
        else
@@@ -256,6 -220,7 +256,6 @@@ mlx5_eswitch_add_fwd_rule(struct mlx5_e
        struct mlx5_flow_table *fast_fdb;
        struct mlx5_flow_table *fwd_fdb;
        struct mlx5_flow_handle *rule;
 -      void *misc;
        int i;
  
        fast_fdb = esw_get_prio_table(esw, attr->chain, attr->prio, 0);
        dest[i].ft = fwd_fdb,
        i++;
  
 -      misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
 -      MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
 -
 -      if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
 -              MLX5_SET(fte_match_set_misc, misc,
 -                       source_eswitch_owner_vhca_id,
 -                       MLX5_CAP_GEN(attr->in_mdev, vhca_id));
 +      mlx5_eswitch_set_rule_source_port(esw, spec, attr);
  
 -      misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
 -      MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
 -      if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
 -              MLX5_SET_TO_ONES(fte_match_set_misc, misc,
 -                               source_eswitch_owner_vhca_id);
 -
 -      if (attr->match_level == MLX5_MATCH_NONE)
 -              spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
 -      else
 -              spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS |
 -                                            MLX5_MATCH_MISC_PARAMETERS;
 +      spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
 +      if (attr->match_level != MLX5_MATCH_NONE)
 +              spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
  
        rule = mlx5_add_flow_rules(fast_fdb, spec, &flow_act, dest, i);
  
@@@ -316,16 -295,8 +316,16 @@@ __mlx5_eswitch_del_rule(struct mlx5_esw
                        bool fwd_rule)
  {
        bool split = (attr->split_count > 0);
 +      int i;
  
        mlx5_del_flow_rules(rule);
 +
 +      /* unref the term table */
 +      for (i = 0; i < MLX5_MAX_FLOW_FWD_VPORTS; i++) {
 +              if (attr->dests[i].termtbl)
 +                      mlx5_eswitch_termtbl_put(esw, attr->dests[i].termtbl);
 +      }
 +
        esw->offloads.num_flows--;
  
        if (fwd_rule)  {
@@@ -357,11 -328,12 +357,11 @@@ mlx5_eswitch_del_fwd_rule(struct mlx5_e
  static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val)
  {
        struct mlx5_eswitch_rep *rep;
 -      int vf_vport, err = 0;
 +      int i, err = 0;
  
        esw_debug(esw->dev, "%s applying global %s policy\n", __func__, val ? "pop" : "none");
 -      for (vf_vport = 1; vf_vport < esw->enabled_vports; vf_vport++) {
 -              rep = &esw->offloads.vport_reps[vf_vport];
 -              if (atomic_read(&rep->rep_if[REP_ETH].state) != REP_LOADED)
 +      mlx5_esw_for_each_host_func_rep(esw, i, rep, esw->esw_funcs.num_vfs) {
 +              if (atomic_read(&rep->rep_data[REP_ETH].state) != REP_LOADED)
                        continue;
  
                err = __mlx5_eswitch_set_vport_vlan(esw, rep->vport, 0, 0, val);
@@@ -587,87 -559,23 +587,87 @@@ void mlx5_eswitch_del_send_to_vport_rul
        mlx5_del_flow_rules(rule);
  }
  
 -static void peer_miss_rules_setup(struct mlx5_core_dev *peer_dev,
 +static int mlx5_eswitch_enable_passing_vport_metadata(struct mlx5_eswitch *esw)
 +{
 +      u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {};
 +      u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {};
 +      u8 fdb_to_vport_reg_c_id;
 +      int err;
 +
 +      err = mlx5_eswitch_query_esw_vport_context(esw, esw->manager_vport,
 +                                                 out, sizeof(out));
 +      if (err)
 +              return err;
 +
 +      fdb_to_vport_reg_c_id = MLX5_GET(query_esw_vport_context_out, out,
 +                                       esw_vport_context.fdb_to_vport_reg_c_id);
 +
 +      fdb_to_vport_reg_c_id |= MLX5_FDB_TO_VPORT_REG_C_0;
 +      MLX5_SET(modify_esw_vport_context_in, in,
 +               esw_vport_context.fdb_to_vport_reg_c_id, fdb_to_vport_reg_c_id);
 +
 +      MLX5_SET(modify_esw_vport_context_in, in,
 +               field_select.fdb_to_vport_reg_c_id, 1);
 +
 +      return mlx5_eswitch_modify_esw_vport_context(esw, esw->manager_vport,
 +                                                   in, sizeof(in));
 +}
 +
 +static int mlx5_eswitch_disable_passing_vport_metadata(struct mlx5_eswitch *esw)
 +{
 +      u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {};
 +      u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {};
 +      u8 fdb_to_vport_reg_c_id;
 +      int err;
 +
 +      err = mlx5_eswitch_query_esw_vport_context(esw, esw->manager_vport,
 +                                                 out, sizeof(out));
 +      if (err)
 +              return err;
 +
 +      fdb_to_vport_reg_c_id = MLX5_GET(query_esw_vport_context_out, out,
 +                                       esw_vport_context.fdb_to_vport_reg_c_id);
 +
 +      fdb_to_vport_reg_c_id &= ~MLX5_FDB_TO_VPORT_REG_C_0;
 +
 +      MLX5_SET(modify_esw_vport_context_in, in,
 +               esw_vport_context.fdb_to_vport_reg_c_id, fdb_to_vport_reg_c_id);
 +
 +      MLX5_SET(modify_esw_vport_context_in, in,
 +               field_select.fdb_to_vport_reg_c_id, 1);
 +
 +      return mlx5_eswitch_modify_esw_vport_context(esw, esw->manager_vport,
 +                                                   in, sizeof(in));
 +}
 +
 +static void peer_miss_rules_setup(struct mlx5_eswitch *esw,
 +                                struct mlx5_core_dev *peer_dev,
                                  struct mlx5_flow_spec *spec,
                                  struct mlx5_flow_destination *dest)
  {
 -      void *misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
 -                                misc_parameters);
 +      void *misc;
  
 -      MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id,
 -               MLX5_CAP_GEN(peer_dev, vhca_id));
 +      if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
 +              misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
 +                                  misc_parameters_2);
 +              MLX5_SET_TO_ONES(fte_match_set_misc2, misc, metadata_reg_c_0);
  
 -      spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
 +              spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
 +      } else {
 +              misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
 +                                  misc_parameters);
  
 -      misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
 -                          misc_parameters);
 -      MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
 -      MLX5_SET_TO_ONES(fte_match_set_misc, misc,
 -                       source_eswitch_owner_vhca_id);
 +              MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id,
 +                       MLX5_CAP_GEN(peer_dev, vhca_id));
 +
 +              spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
 +
 +              misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
 +                                  misc_parameters);
 +              MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
 +              MLX5_SET_TO_ONES(fte_match_set_misc, misc,
 +                               source_eswitch_owner_vhca_id);
 +      }
  
        dest->type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
        dest->vport.num = peer_dev->priv.eswitch->manager_vport;
        dest->vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
  }
  
 +static void esw_set_peer_miss_rule_source_port(struct mlx5_eswitch *esw,
 +                                             struct mlx5_eswitch *peer_esw,
 +                                             struct mlx5_flow_spec *spec,
 +                                             u16 vport)
 +{
 +      void *misc;
 +
 +      if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
 +              misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
 +                                  misc_parameters_2);
 +              MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
 +                       mlx5_eswitch_get_vport_metadata_for_match(peer_esw,
 +                                                                 vport));
 +      } else {
 +              misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
 +                                  misc_parameters);
 +              MLX5_SET(fte_match_set_misc, misc, source_port, vport);
 +      }
 +}
 +
  static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw,
                                       struct mlx5_core_dev *peer_dev)
  {
        if (!spec)
                return -ENOMEM;
  
 -      peer_miss_rules_setup(peer_dev, spec, &dest);
 +      peer_miss_rules_setup(esw, peer_dev, spec, &dest);
  
        flows = kvzalloc(nvports * sizeof(*flows), GFP_KERNEL);
        if (!flows) {
                            misc_parameters);
  
        if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
 -              MLX5_SET(fte_match_set_misc, misc, source_port, MLX5_VPORT_PF);
 +              esw_set_peer_miss_rule_source_port(esw, peer_dev->priv.eswitch,
 +                                                 spec, MLX5_VPORT_PF);
 +
                flow = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
                                           spec, &flow_act, &dest, 1);
                if (IS_ERR(flow)) {
        }
  
        mlx5_esw_for_each_vf_vport_num(esw, i, mlx5_core_max_vfs(esw->dev)) {
 -              MLX5_SET(fte_match_set_misc, misc, source_port, i);
 +              esw_set_peer_miss_rule_source_port(esw,
 +                                                 peer_dev->priv.eswitch,
 +                                                 spec, i);
 +
                flow = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
                                           spec, &flow_act, &dest, 1);
                if (IS_ERR(flow)) {
@@@ -1036,30 -919,6 +1036,30 @@@ static void esw_destroy_offloads_fast_f
  #define MAX_PF_SQ 256
  #define MAX_SQ_NVPORTS 32
  
 +static void esw_set_flow_group_source_port(struct mlx5_eswitch *esw,
 +                                         u32 *flow_group_in)
 +{
 +      void *match_criteria = MLX5_ADDR_OF(create_flow_group_in,
 +                                          flow_group_in,
 +                                          match_criteria);
 +
 +      if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
 +              MLX5_SET(create_flow_group_in, flow_group_in,
 +                       match_criteria_enable,
 +                       MLX5_MATCH_MISC_PARAMETERS_2);
 +
 +              MLX5_SET_TO_ONES(fte_match_param, match_criteria,
 +                               misc_parameters_2.metadata_reg_c_0);
 +      } else {
 +              MLX5_SET(create_flow_group_in, flow_group_in,
 +                       match_criteria_enable,
 +                       MLX5_MATCH_MISC_PARAMETERS);
 +
 +              MLX5_SET_TO_ONES(fte_match_param, match_criteria,
 +                               misc_parameters.source_port);
 +      }
 +}
 +
  static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
  {
        int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
  
        /* create peer esw miss group */
        memset(flow_group_in, 0, inlen);
 -      MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
 -               MLX5_MATCH_MISC_PARAMETERS);
  
 -      match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
 -                                    match_criteria);
 +      esw_set_flow_group_source_port(esw, flow_group_in);
 +
 +      if (!mlx5_eswitch_vport_match_metadata_enabled(esw)) {
 +              match_criteria = MLX5_ADDR_OF(create_flow_group_in,
 +                                            flow_group_in,
 +                                            match_criteria);
  
 -      MLX5_SET_TO_ONES(fte_match_param, match_criteria,
 -                       misc_parameters.source_port);
 -      MLX5_SET_TO_ONES(fte_match_param, match_criteria,
 -                       misc_parameters.source_eswitch_owner_vhca_id);
 +              MLX5_SET_TO_ONES(fte_match_param, match_criteria,
 +                               misc_parameters.source_eswitch_owner_vhca_id);
 +
 +              MLX5_SET(create_flow_group_in, flow_group_in,
 +                       source_eswitch_owner_vhca_id_valid, 1);
 +      }
  
 -      MLX5_SET(create_flow_group_in, flow_group_in,
 -               source_eswitch_owner_vhca_id_valid, 1);
        MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
        MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
                 ix + esw->total_vports - 1);
@@@ -1285,6 -1142,7 +1285,6 @@@ static int esw_create_vport_rx_group(st
        int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
        struct mlx5_flow_group *g;
        u32 *flow_group_in;
 -      void *match_criteria, *misc;
        int err = 0;
  
        nvports = nvports + MLX5_ESW_MISS_FLOWS;
  
        /* create vport rx group */
        memset(flow_group_in, 0, inlen);
 -      MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
 -               MLX5_MATCH_MISC_PARAMETERS);
  
 -      match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
 -      misc = MLX5_ADDR_OF(fte_match_param, match_criteria, misc_parameters);
 -      MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
 +      esw_set_flow_group_source_port(esw, flow_group_in);
  
        MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
        MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1);
@@@ -1334,24 -1196,13 +1334,24 @@@ mlx5_eswitch_create_vport_rx_rule(struc
                goto out;
        }
  
 -      misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
 -      MLX5_SET(fte_match_set_misc, misc, source_port, vport);
 +      if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
 +              misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
 +              MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
 +                       mlx5_eswitch_get_vport_metadata_for_match(esw, vport));
  
 -      misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
 -      MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
 +              misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
 +              MLX5_SET_TO_ONES(fte_match_set_misc2, misc, metadata_reg_c_0);
  
 -      spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
 +              spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
 +      } else {
 +              misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
 +              MLX5_SET(fte_match_set_misc, misc, source_port, vport);
 +
 +              misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
 +              MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
 +
 +              spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
 +      }
  
        flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
        flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec,
  static int esw_offloads_start(struct mlx5_eswitch *esw,
                              struct netlink_ext_ack *extack)
  {
 -      int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
 +      int err, err1;
  
 -      if (esw->mode != SRIOV_LEGACY &&
 +      if (esw->mode != MLX5_ESWITCH_LEGACY &&
            !mlx5_core_is_ecpf_esw_manager(esw->dev)) {
                NL_SET_ERR_MSG_MOD(extack,
                                   "Can't set offloads mode, SRIOV legacy not enabled");
                return -EINVAL;
        }
  
 -      mlx5_eswitch_disable_sriov(esw);
 -      err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
 +      mlx5_eswitch_disable(esw);
 +      mlx5_eswitch_update_num_of_vfs(esw, esw->dev->priv.sriov.num_vfs);
 +      err = mlx5_eswitch_enable(esw, MLX5_ESWITCH_OFFLOADS);
        if (err) {
                NL_SET_ERR_MSG_MOD(extack,
                                   "Failed setting eswitch to offloads");
 -              err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
 +              err1 = mlx5_eswitch_enable(esw, MLX5_ESWITCH_LEGACY);
                if (err1) {
                        NL_SET_ERR_MSG_MOD(extack,
                                           "Failed setting eswitch back to legacy");
        }
        if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
                if (mlx5_eswitch_inline_mode_get(esw,
 -                                               num_vfs,
                                                 &esw->offloads.inline_mode)) {
                        esw->offloads.inline_mode = MLX5_INLINE_MODE_L2;
                        NL_SET_ERR_MSG_MOD(extack,
@@@ -1408,11 -1259,11 +1408,11 @@@ void esw_offloads_cleanup_reps(struct m
  
  int esw_offloads_init_reps(struct mlx5_eswitch *esw)
  {
 -      int total_vports = MLX5_TOTAL_VPORTS(esw->dev);
 +      int total_vports = esw->total_vports;
        struct mlx5_core_dev *dev = esw->dev;
        struct mlx5_eswitch_rep *rep;
        u8 hw_id[ETH_ALEN], rep_type;
 -      int vport;
 +      int vport_index;
  
        esw->offloads.vport_reps = kcalloc(total_vports,
                                           sizeof(struct mlx5_eswitch_rep),
        if (!esw->offloads.vport_reps)
                return -ENOMEM;
  
 -      mlx5_query_nic_vport_mac_address(dev, 0, hw_id);
 +      mlx5_query_mac_address(dev, hw_id);
  
 -      mlx5_esw_for_all_reps(esw, vport, rep) {
 -              rep->vport = mlx5_eswitch_index_to_vport_num(esw, vport);
 +      mlx5_esw_for_all_reps(esw, vport_index, rep) {
 +              rep->vport = mlx5_eswitch_index_to_vport_num(esw, vport_index);
 +              rep->vport_index = vport_index;
                ether_addr_copy(rep->hw_id, hw_id);
  
                for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++)
 -                      atomic_set(&rep->rep_if[rep_type].state,
 +                      atomic_set(&rep->rep_data[rep_type].state,
                                   REP_UNREGISTERED);
        }
  
  static void __esw_offloads_unload_rep(struct mlx5_eswitch *esw,
                                      struct mlx5_eswitch_rep *rep, u8 rep_type)
  {
 -      if (atomic_cmpxchg(&rep->rep_if[rep_type].state,
 +      if (atomic_cmpxchg(&rep->rep_data[rep_type].state,
                           REP_LOADED, REP_REGISTERED) == REP_LOADED)
 -              rep->rep_if[rep_type].unload(rep);
 +              esw->offloads.rep_ops[rep_type]->unload(rep);
  }
  
  static void __unload_reps_special_vport(struct mlx5_eswitch *esw, u8 rep_type)
@@@ -1479,20 -1329,21 +1479,20 @@@ static void esw_offloads_unload_vf_reps
                __unload_reps_vf_vport(esw, nvports, rep_type);
  }
  
 -static void __unload_reps_all_vport(struct mlx5_eswitch *esw, int nvports,
 -                                  u8 rep_type)
 +static void __unload_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type)
  {
 -      __unload_reps_vf_vport(esw, nvports, rep_type);
 +      __unload_reps_vf_vport(esw, esw->esw_funcs.num_vfs, rep_type);
  
        /* Special vports must be the last to unload. */
        __unload_reps_special_vport(esw, rep_type);
  }
  
 -static void esw_offloads_unload_all_reps(struct mlx5_eswitch *esw, int nvports)
 +static void esw_offloads_unload_all_reps(struct mlx5_eswitch *esw)
  {
        u8 rep_type = NUM_REP_TYPES;
  
        while (rep_type-- > 0)
 -              __unload_reps_all_vport(esw, nvports, rep_type);
 +              __unload_reps_all_vport(esw, rep_type);
  }
  
  static int __esw_offloads_load_rep(struct mlx5_eswitch *esw,
  {
        int err = 0;
  
 -      if (atomic_cmpxchg(&rep->rep_if[rep_type].state,
 +      if (atomic_cmpxchg(&rep->rep_data[rep_type].state,
                           REP_REGISTERED, REP_LOADED) == REP_REGISTERED) {
 -              err = rep->rep_if[rep_type].load(esw->dev, rep);
 +              err = esw->offloads.rep_ops[rep_type]->load(esw->dev, rep);
                if (err)
 -                      atomic_set(&rep->rep_if[rep_type].state,
 +                      atomic_set(&rep->rep_data[rep_type].state,
                                   REP_REGISTERED);
        }
  
@@@ -1568,26 -1419,6 +1568,26 @@@ err_vf
        return err;
  }
  
 +static int __load_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type)
 +{
 +      int err;
 +
 +      /* Special vports must be loaded first, uplink rep creates mdev resource. */
 +      err = __load_reps_special_vport(esw, rep_type);
 +      if (err)
 +              return err;
 +
 +      err = __load_reps_vf_vport(esw, esw->esw_funcs.num_vfs, rep_type);
 +      if (err)
 +              goto err_vfs;
 +
 +      return 0;
 +
 +err_vfs:
 +      __unload_reps_special_vport(esw, rep_type);
 +      return err;
 +}
 +
  static int esw_offloads_load_vf_reps(struct mlx5_eswitch *esw, int nvports)
  {
        u8 rep_type = 0;
@@@ -1607,13 -1438,34 +1607,13 @@@ err_reps
        return err;
  }
  
 -static int __load_reps_all_vport(struct mlx5_eswitch *esw, int nvports,
 -                               u8 rep_type)
 -{
 -      int err;
 -
 -      /* Special vports must be loaded first. */
 -      err = __load_reps_special_vport(esw, rep_type);
 -      if (err)
 -              return err;
 -
 -      err = __load_reps_vf_vport(esw, nvports, rep_type);
 -      if (err)
 -              goto err_vfs;
 -
 -      return 0;
 -
 -err_vfs:
 -      __unload_reps_special_vport(esw, rep_type);
 -      return err;
 -}
 -
 -static int esw_offloads_load_all_reps(struct mlx5_eswitch *esw, int nvports)
 +static int esw_offloads_load_all_reps(struct mlx5_eswitch *esw)
  {
        u8 rep_type = 0;
        int err;
  
        for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
 -              err = __load_reps_all_vport(esw, nvports, rep_type);
 +              err = __load_reps_all_vport(esw, rep_type);
                if (err)
                        goto err_reps;
        }
  
  err_reps:
        while (rep_type-- > 0)
 -              __unload_reps_all_vport(esw, nvports, rep_type);
 +              __unload_reps_all_vport(esw, rep_type);
        return err;
  }
  
@@@ -1658,10 -1510,6 +1658,10 @@@ static int mlx5_esw_offloads_devcom_eve
  
        switch (event) {
        case ESW_OFFLOADS_DEVCOM_PAIR:
 +              if (mlx5_eswitch_vport_match_metadata_enabled(esw) !=
 +                  mlx5_eswitch_vport_match_metadata_enabled(peer_esw))
 +                      break;
 +
                err = mlx5_esw_offloads_pair(esw, peer_esw);
                if (err)
                        goto err_out;
@@@ -1730,16 -1578,32 +1730,16 @@@ static void esw_offloads_devcom_cleanup
  static int esw_vport_ingress_prio_tag_config(struct mlx5_eswitch *esw,
                                             struct mlx5_vport *vport)
  {
 -      struct mlx5_core_dev *dev = esw->dev;
        struct mlx5_flow_act flow_act = {0};
        struct mlx5_flow_spec *spec;
        int err = 0;
  
        /* For prio tag mode, there is only 1 FTEs:
 -       * 1) Untagged packets - push prio tag VLAN, allow
 +       * 1) Untagged packets - push prio tag VLAN and modify metadata if
 +       * required, allow
         * Unmatched traffic is allowed by default
         */
  
 -      if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support))
 -              return -EOPNOTSUPP;
 -
 -      esw_vport_cleanup_ingress_rules(esw, vport);
 -
 -      err = esw_vport_enable_ingress_acl(esw, vport);
 -      if (err) {
 -              mlx5_core_warn(esw->dev,
 -                             "failed to enable prio tag ingress acl (%d) on vport[%d]\n",
 -                             err, vport->vport);
 -              return err;
 -      }
 -
 -      esw_debug(esw->dev,
 -                "vport[%d] configure ingress rules\n", vport->vport);
 -
        spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
        if (!spec) {
                err = -ENOMEM;
        flow_act.vlan[0].ethtype = ETH_P_8021Q;
        flow_act.vlan[0].vid = 0;
        flow_act.vlan[0].prio = 0;
 +
 +      if (vport->ingress.modify_metadata_rule) {
 +              flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
 +              flow_act.modify_id = vport->ingress.modify_metadata_id;
 +      }
 +
        vport->ingress.allow_rule =
                mlx5_add_flow_rules(vport->ingress.acl, spec,
                                    &flow_act, NULL, 0);
@@@ -1781,58 -1639,6 +1781,58 @@@ out_no_mem
        return err;
  }
  
 +static int esw_vport_add_ingress_acl_modify_metadata(struct mlx5_eswitch *esw,
 +                                                   struct mlx5_vport *vport)
 +{
 +      u8 action[MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto)] = {};
 +      static const struct mlx5_flow_spec spec = {};
 +      struct mlx5_flow_act flow_act = {};
 +      int err = 0;
 +
 +      MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
 +      MLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_C_0);
 +      MLX5_SET(set_action_in, action, data,
 +               mlx5_eswitch_get_vport_metadata_for_match(esw, vport->vport));
 +
 +      err = mlx5_modify_header_alloc(esw->dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS,
 +                                     1, action, &vport->ingress.modify_metadata_id);
 +      if (err) {
 +              esw_warn(esw->dev,
 +                       "failed to alloc modify header for vport %d ingress acl (%d)\n",
 +                       vport->vport, err);
 +              return err;
 +      }
 +
 +      flow_act.action = MLX5_FLOW_CONTEXT_ACTION_MOD_HDR | MLX5_FLOW_CONTEXT_ACTION_ALLOW;
 +      flow_act.modify_id = vport->ingress.modify_metadata_id;
 +      vport->ingress.modify_metadata_rule = mlx5_add_flow_rules(vport->ingress.acl,
 +                                                                &spec, &flow_act, NULL, 0);
 +      if (IS_ERR(vport->ingress.modify_metadata_rule)) {
 +              err = PTR_ERR(vport->ingress.modify_metadata_rule);
 +              esw_warn(esw->dev,
 +                       "failed to add setting metadata rule for vport %d ingress acl, err(%d)\n",
 +                       vport->vport, err);
 +              vport->ingress.modify_metadata_rule = NULL;
 +              goto out;
 +      }
 +
 +out:
 +      if (err)
 +              mlx5_modify_header_dealloc(esw->dev, vport->ingress.modify_metadata_id);
 +      return err;
 +}
 +
 +void esw_vport_del_ingress_acl_modify_metadata(struct mlx5_eswitch *esw,
 +                                             struct mlx5_vport *vport)
 +{
 +      if (vport->ingress.modify_metadata_rule) {
 +              mlx5_del_flow_rules(vport->ingress.modify_metadata_rule);
 +              mlx5_modify_header_dealloc(esw->dev, vport->ingress.modify_metadata_id);
 +
 +              vport->ingress.modify_metadata_rule = NULL;
 +      }
 +}
 +
  static int esw_vport_egress_prio_tag_config(struct mlx5_eswitch *esw,
                                            struct mlx5_vport *vport)
  {
        struct mlx5_flow_spec *spec;
        int err = 0;
  
 +      if (!MLX5_CAP_GEN(esw->dev, prio_tag_required))
 +              return 0;
 +
        /* For prio tag mode, there is only 1 FTEs:
         * 1) prio tag packets - pop the prio tag VLAN, allow
         * Unmatched traffic is allowed by default
@@@ -1896,98 -1699,27 +1896,98 @@@ out_no_mem
        return err;
  }
  
 -static int esw_prio_tag_acls_config(struct mlx5_eswitch *esw, int nvports)
 +static int esw_vport_ingress_common_config(struct mlx5_eswitch *esw,
 +                                         struct mlx5_vport *vport)
  {
 -      struct mlx5_vport *vport = NULL;
 -      int i, j;
        int err;
  
 -      mlx5_esw_for_each_vf_vport(esw, i, vport, nvports) {
 +      if (!mlx5_eswitch_vport_match_metadata_enabled(esw) &&
 +          !MLX5_CAP_GEN(esw->dev, prio_tag_required))
 +              return 0;
 +
 +      esw_vport_cleanup_ingress_rules(esw, vport);
 +
 +      err = esw_vport_enable_ingress_acl(esw, vport);
 +      if (err) {
 +              esw_warn(esw->dev,
 +                       "failed to enable ingress acl (%d) on vport[%d]\n",
 +                       err, vport->vport);
 +              return err;
 +      }
 +
 +      esw_debug(esw->dev,
 +                "vport[%d] configure ingress rules\n", vport->vport);
 +
 +      if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
 +              err = esw_vport_add_ingress_acl_modify_metadata(esw, vport);
 +              if (err)
 +                      goto out;
 +      }
 +
 +      if (MLX5_CAP_GEN(esw->dev, prio_tag_required) &&
 +          mlx5_eswitch_is_vf_vport(esw, vport->vport)) {
                err = esw_vport_ingress_prio_tag_config(esw, vport);
                if (err)
 -                      goto err_ingress;
 -              err = esw_vport_egress_prio_tag_config(esw, vport);
 +                      goto out;
 +      }
 +
 +out:
 +      if (err)
 +              esw_vport_disable_ingress_acl(esw, vport);
 +      return err;
 +}
 +
 +static bool
 +esw_check_vport_match_metadata_supported(const struct mlx5_eswitch *esw)
 +{
 +      if (!MLX5_CAP_ESW(esw->dev, esw_uplink_ingress_acl))
 +              return false;
 +
 +      if (!(MLX5_CAP_ESW_FLOWTABLE(esw->dev, fdb_to_vport_reg_c_id) &
 +            MLX5_FDB_TO_VPORT_REG_C_0))
 +              return false;
 +
 +      if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source))
 +              return false;
 +
 +      if (mlx5_core_is_ecpf_esw_manager(esw->dev) ||
 +          mlx5_ecpf_vport_exists(esw->dev))
 +              return false;
 +
 +      return true;
 +}
 +
 +static int esw_create_offloads_acl_tables(struct mlx5_eswitch *esw)
 +{
 +      struct mlx5_vport *vport;
 +      int i, j;
 +      int err;
 +
 +      if (esw_check_vport_match_metadata_supported(esw))
 +              esw->flags |= MLX5_ESWITCH_VPORT_MATCH_METADATA;
 +
 +      mlx5_esw_for_all_vports(esw, i, vport) {
 +              err = esw_vport_ingress_common_config(esw, vport);
                if (err)
 -                      goto err_egress;
 +                      goto err_ingress;
 +
 +              if (mlx5_eswitch_is_vf_vport(esw, vport->vport)) {
 +                      err = esw_vport_egress_prio_tag_config(esw, vport);
 +                      if (err)
 +                              goto err_egress;
 +              }
        }
  
 +      if (mlx5_eswitch_vport_match_metadata_enabled(esw))
 +              esw_info(esw->dev, "Use metadata reg_c as source vport to match\n");
 +
        return 0;
  
  err_egress:
        esw_vport_disable_ingress_acl(esw, vport);
  err_ingress:
 -      mlx5_esw_for_each_vf_vport_reverse(esw, j, vport, i - 1) {
 +      for (j = MLX5_VPORT_PF; j < i; j++) {
 +              vport = &esw->vports[j];
                esw_vport_disable_egress_acl(esw, vport);
                esw_vport_disable_ingress_acl(esw, vport);
        }
        return err;
  }
  
 -static void esw_prio_tag_acls_cleanup(struct mlx5_eswitch *esw)
 +static void esw_destroy_offloads_acl_tables(struct mlx5_eswitch *esw)
  {
        struct mlx5_vport *vport;
        int i;
  
 -      mlx5_esw_for_each_vf_vport(esw, i, vport, esw->dev->priv.sriov.num_vfs) {
 +      mlx5_esw_for_all_vports(esw, i, vport) {
                esw_vport_disable_egress_acl(esw, vport);
                esw_vport_disable_ingress_acl(esw, vport);
        }
 +
 +      esw->flags &= ~MLX5_ESWITCH_VPORT_MATCH_METADATA;
  }
  
 -static int esw_offloads_steering_init(struct mlx5_eswitch *esw, int vf_nvports,
 -                                    int nvports)
 +static int esw_offloads_steering_init(struct mlx5_eswitch *esw)
  {
 +      int num_vfs = esw->esw_funcs.num_vfs;
 +      int total_vports;
        int err;
  
 +      if (mlx5_core_is_ecpf_esw_manager(esw->dev))
 +              total_vports = esw->total_vports;
 +      else
 +              total_vports = num_vfs + MLX5_SPECIAL_VPORTS(esw->dev);
 +
        memset(&esw->fdb_table.offloads, 0, sizeof(struct offloads_fdb));
        mutex_init(&esw->fdb_table.offloads.fdb_prio_lock);
  
 -      if (MLX5_CAP_GEN(esw->dev, prio_tag_required)) {
 -              err = esw_prio_tag_acls_config(esw, vf_nvports);
 -              if (err)
 -                      return err;
 -      }
 -
 -      err = esw_create_offloads_fdb_tables(esw, nvports);
 +      err = esw_create_offloads_acl_tables(esw);
        if (err)
                return err;
  
 -      err = esw_create_offloads_table(esw, nvports);
 +      err = esw_create_offloads_fdb_tables(esw, total_vports);
 +      if (err)
 +              goto create_fdb_err;
 +
 +      err = esw_create_offloads_table(esw, total_vports);
        if (err)
                goto create_ft_err;
  
 -      err = esw_create_vport_rx_group(esw, nvports);
 +      err = esw_create_vport_rx_group(esw, total_vports);
        if (err)
                goto create_fg_err;
  
@@@ -2046,9 -1772,6 +2046,9 @@@ create_fg_err
  create_ft_err:
        esw_destroy_offloads_fdb_tables(esw);
  
 +create_fdb_err:
 +      esw_destroy_offloads_acl_tables(esw);
 +
        return err;
  }
  
@@@ -2057,105 -1780,94 +2057,111 @@@ static void esw_offloads_steering_clean
        esw_destroy_vport_rx_group(esw);
        esw_destroy_offloads_table(esw);
        esw_destroy_offloads_fdb_tables(esw);
 -      if (MLX5_CAP_GEN(esw->dev, prio_tag_required))
 -              esw_prio_tag_acls_cleanup(esw);
 +      esw_destroy_offloads_acl_tables(esw);
  }
  
 -static void esw_host_params_event_handler(struct work_struct *work)
 +static void
 +esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, const u32 *out)
  {
 -      struct mlx5_host_work *host_work;
 -      struct mlx5_eswitch *esw;
 -      int err, num_vf = 0;
 +      bool host_pf_disabled;
 +      u16 new_num_vfs;
  
 -      host_work = container_of(work, struct mlx5_host_work, work);
 -      esw = host_work->esw;
 +      new_num_vfs = MLX5_GET(query_esw_functions_out, out,
 +                             host_params_context.host_num_of_vfs);
 +      host_pf_disabled = MLX5_GET(query_esw_functions_out, out,
 +                                  host_params_context.host_pf_disabled);
  
 -      err = mlx5_query_host_params_num_vfs(esw->dev, &num_vf);
 -      if (err || num_vf == esw->host_info.num_vfs)
 -              goto out;
 +      if (new_num_vfs == esw->esw_funcs.num_vfs || host_pf_disabled)
 +              return;
  
        /* Number of VFs can only change from "0 to x" or "x to 0". */
 -      if (esw->host_info.num_vfs > 0) {
 -              esw_offloads_unload_vf_reps(esw, esw->host_info.num_vfs);
 +      if (esw->esw_funcs.num_vfs > 0) {
 +              esw_offloads_unload_vf_reps(esw, esw->esw_funcs.num_vfs);
        } else {
 -              err = esw_offloads_load_vf_reps(esw, num_vf);
 +              int err;
  
 +              err = esw_offloads_load_vf_reps(esw, new_num_vfs);
                if (err)
 -                      goto out;
 +                      return;
        }
 +      esw->esw_funcs.num_vfs = new_num_vfs;
 +}
 +
 +static void esw_functions_changed_event_handler(struct work_struct *work)
 +{
 +      struct mlx5_host_work *host_work;
 +      struct mlx5_eswitch *esw;
 +      const u32 *out;
  
 -      esw->host_info.num_vfs = num_vf;
 +      host_work = container_of(work, struct mlx5_host_work, work);
 +      esw = host_work->esw;
  
 +      out = mlx5_esw_query_functions(esw->dev);
 +      if (IS_ERR(out))
 +              goto out;
 +
 +      esw_vfs_changed_event_handler(esw, out);
 +      kvfree(out);
  out:
        kfree(host_work);
  }
  
 -static int esw_host_params_event(struct notifier_block *nb,
 -                               unsigned long type, void *data)
 +int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, unsigned long type, void *data)
  {
 +      struct mlx5_esw_functions *esw_funcs;
        struct mlx5_host_work *host_work;
 -      struct mlx5_host_info *host_info;
        struct mlx5_eswitch *esw;
  
        host_work = kzalloc(sizeof(*host_work), GFP_ATOMIC);
        if (!host_work)
                return NOTIFY_DONE;
  
 -      host_info = mlx5_nb_cof(nb, struct mlx5_host_info, nb);
 -      esw = container_of(host_info, struct mlx5_eswitch, host_info);
 +      esw_funcs = mlx5_nb_cof(nb, struct mlx5_esw_functions, nb);
 +      esw = container_of(esw_funcs, struct mlx5_eswitch, esw_funcs);
  
        host_work->esw = esw;
  
 -      INIT_WORK(&host_work->work, esw_host_params_event_handler);
 +      INIT_WORK(&host_work->work, esw_functions_changed_event_handler);
        queue_work(esw->work_queue, &host_work->work);
  
        return NOTIFY_OK;
  }
  
 -int esw_offloads_init(struct mlx5_eswitch *esw, int vf_nvports,
 -                    int total_nvports)
 +int esw_offloads_init(struct mlx5_eswitch *esw)
  {
        int err;
  
 -      err = esw_offloads_steering_init(esw, vf_nvports, total_nvports);
+       if (MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, reformat) &&
+           MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, decap))
+               esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_BASIC;
+       else
+               esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
 +      err = esw_offloads_steering_init(esw);
        if (err)
                return err;
  
 -      err = esw_offloads_load_all_reps(esw, vf_nvports);
 +      if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
 +              err = mlx5_eswitch_enable_passing_vport_metadata(esw);
 +              if (err)
 +                      goto err_vport_metadata;
 +      }
 +
 +      err = esw_offloads_load_all_reps(esw);
        if (err)
                goto err_reps;
  
        esw_offloads_devcom_init(esw);
 -
 -      if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
 -              MLX5_NB_INIT(&esw->host_info.nb, esw_host_params_event,
 -                           HOST_PARAMS_CHANGE);
 -              mlx5_eq_notifier_register(esw->dev, &esw->host_info.nb);
 -              esw->host_info.num_vfs = vf_nvports;
 -      }
 +      mutex_init(&esw->offloads.termtbl_mutex);
  
        mlx5_rdma_enable_roce(esw->dev);
  
        return 0;
  
  err_reps:
 +      if (mlx5_eswitch_vport_match_metadata_enabled(esw))
 +              mlx5_eswitch_disable_passing_vport_metadata(esw);
 +err_vport_metadata:
        esw_offloads_steering_cleanup(esw);
        return err;
  }
  static int esw_offloads_stop(struct mlx5_eswitch *esw,
                             struct netlink_ext_ack *extack)
  {
 -      int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
 +      int err, err1;
  
 -      mlx5_eswitch_disable_sriov(esw);
 -      err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
 +      mlx5_eswitch_disable(esw);
 +      err = mlx5_eswitch_enable(esw, MLX5_ESWITCH_LEGACY);
        if (err) {
                NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy");
 -              err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
 +              err1 = mlx5_eswitch_enable(esw, MLX5_ESWITCH_OFFLOADS);
                if (err1) {
                        NL_SET_ERR_MSG_MOD(extack,
                                           "Failed setting eswitch back to offloads");
  
  void esw_offloads_cleanup(struct mlx5_eswitch *esw)
  {
 -      u16 num_vfs;
 -
 -      if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
 -              mlx5_eq_notifier_unregister(esw->dev, &esw->host_info.nb);
 -              flush_workqueue(esw->work_queue);
 -              num_vfs = esw->host_info.num_vfs;
 -      } else {
 -              num_vfs = esw->dev->priv.sriov.num_vfs;
 -      }
 -
        mlx5_rdma_disable_roce(esw->dev);
        esw_offloads_devcom_cleanup(esw);
 -      esw_offloads_unload_all_reps(esw, num_vfs);
 +      esw_offloads_unload_all_reps(esw);
 +      if (mlx5_eswitch_vport_match_metadata_enabled(esw))
 +              mlx5_eswitch_disable_passing_vport_metadata(esw);
        esw_offloads_steering_cleanup(esw);
+       esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
  }
  
  static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
  {
        switch (mode) {
        case DEVLINK_ESWITCH_MODE_LEGACY:
 -              *mlx5_mode = SRIOV_LEGACY;
 +              *mlx5_mode = MLX5_ESWITCH_LEGACY;
                break;
        case DEVLINK_ESWITCH_MODE_SWITCHDEV:
 -              *mlx5_mode = SRIOV_OFFLOADS;
 +              *mlx5_mode = MLX5_ESWITCH_OFFLOADS;
                break;
        default:
                return -EINVAL;
  static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
  {
        switch (mlx5_mode) {
 -      case SRIOV_LEGACY:
 +      case MLX5_ESWITCH_LEGACY:
                *mode = DEVLINK_ESWITCH_MODE_LEGACY;
                break;
 -      case SRIOV_OFFLOADS:
 +      case MLX5_ESWITCH_OFFLOADS:
                *mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
                break;
        default:
@@@ -2275,7 -1996,7 +2282,7 @@@ static int mlx5_devlink_eswitch_check(s
        if(!MLX5_ESWITCH_MANAGER(dev))
                return -EPERM;
  
 -      if (dev->priv.eswitch->mode == SRIOV_NONE &&
 +      if (dev->priv.eswitch->mode == MLX5_ESWITCH_NONE &&
            !mlx5_core_is_ecpf_esw_manager(dev))
                return -EOPNOTSUPP;
  
@@@ -2326,7 -2047,7 +2333,7 @@@ int mlx5_devlink_eswitch_inline_mode_se
  {
        struct mlx5_core_dev *dev = devlink_priv(devlink);
        struct mlx5_eswitch *esw = dev->priv.eswitch;
 -      int err, vport;
 +      int err, vport, num_vport;
        u8 mlx5_mode;
  
        err = mlx5_devlink_eswitch_check(devlink);
        if (err)
                goto out;
  
 -      for (vport = 1; vport < esw->enabled_vports; vport++) {
 +      mlx5_esw_for_each_host_func_vport(esw, vport, esw->esw_funcs.num_vfs) {
                err = mlx5_modify_nic_vport_min_inline(dev, vport, mlx5_mode);
                if (err) {
                        NL_SET_ERR_MSG_MOD(extack,
        return 0;
  
  revert_inline_mode:
 -      while (--vport > 0)
 +      num_vport = --vport;
 +      mlx5_esw_for_each_host_func_vport_reverse(esw, vport, num_vport)
                mlx5_modify_nic_vport_min_inline(dev,
                                                 vport,
                                                 esw->offloads.inline_mode);
@@@ -2390,7 -2110,7 +2397,7 @@@ int mlx5_devlink_eswitch_inline_mode_ge
        return esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
  }
  
 -int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode)
 +int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, u8 *mode)
  {
        u8 prev_mlx5_mode, mlx5_mode = MLX5_INLINE_MODE_L2;
        struct mlx5_core_dev *dev = esw->dev;
        if (!MLX5_CAP_GEN(dev, vport_group_manager))
                return -EOPNOTSUPP;
  
 -      if (esw->mode == SRIOV_NONE)
 +      if (esw->mode == MLX5_ESWITCH_NONE)
                return -EOPNOTSUPP;
  
        switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
        }
  
  query_vports:
 -      for (vport = 1; vport <= nvfs; vport++) {
 +      mlx5_query_nic_vport_min_inline(dev, esw->first_host_vport, &prev_mlx5_mode);
 +      mlx5_esw_for_each_host_func_vport(esw, vport, esw->esw_funcs.num_vfs) {
                mlx5_query_nic_vport_min_inline(dev, vport, &mlx5_mode);
 -              if (vport > 1 && prev_mlx5_mode != mlx5_mode)
 +              if (prev_mlx5_mode != mlx5_mode)
                        return -EINVAL;
                prev_mlx5_mode = mlx5_mode;
        }
@@@ -2427,8 -2146,7 +2434,8 @@@ out
        return 0;
  }
  
 -int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap,
 +int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
 +                                      enum devlink_eswitch_encap_mode encap,
                                        struct netlink_ext_ack *extack)
  {
        struct mlx5_core_dev *dev = devlink_priv(devlink);
        if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC)
                return -EOPNOTSUPP;
  
 -      if (esw->mode == SRIOV_LEGACY) {
 +      if (esw->mode == MLX5_ESWITCH_LEGACY) {
                esw->offloads.encap = encap;
                return 0;
        }
        return err;
  }
  
 -int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap)
 +int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink,
 +                                      enum devlink_eswitch_encap_mode *encap)
  {
        struct mlx5_core_dev *dev = devlink_priv(devlink);
        struct mlx5_eswitch *esw = dev->priv.eswitch;
  }
  
  void mlx5_eswitch_register_vport_reps(struct mlx5_eswitch *esw,
 -                                    struct mlx5_eswitch_rep_if *__rep_if,
 +                                    const struct mlx5_eswitch_rep_ops *ops,
                                      u8 rep_type)
  {
 -      struct mlx5_eswitch_rep_if *rep_if;
 +      struct mlx5_eswitch_rep_data *rep_data;
        struct mlx5_eswitch_rep *rep;
        int i;
  
 +      esw->offloads.rep_ops[rep_type] = ops;
        mlx5_esw_for_all_reps(esw, i, rep) {
 -              rep_if = &rep->rep_if[rep_type];
 -              rep_if->load   = __rep_if->load;
 -              rep_if->unload = __rep_if->unload;
 -              rep_if->get_proto_dev = __rep_if->get_proto_dev;
 -              rep_if->priv = __rep_if->priv;
 -
 -              atomic_set(&rep_if->state, REP_REGISTERED);
 +              rep_data = &rep->rep_data[rep_type];
 +              atomic_set(&rep_data->state, REP_REGISTERED);
        }
  }
  EXPORT_SYMBOL(mlx5_eswitch_register_vport_reps);
  
  void mlx5_eswitch_unregister_vport_reps(struct mlx5_eswitch *esw, u8 rep_type)
  {
 -      u16 max_vf = mlx5_core_max_vfs(esw->dev);
        struct mlx5_eswitch_rep *rep;
        int i;
  
 -      if (esw->mode == SRIOV_OFFLOADS)
 -              __unload_reps_all_vport(esw, max_vf, rep_type);
 +      if (esw->mode == MLX5_ESWITCH_OFFLOADS)
 +              __unload_reps_all_vport(esw, rep_type);
  
        mlx5_esw_for_all_reps(esw, i, rep)
 -              atomic_set(&rep->rep_if[rep_type].state, REP_UNREGISTERED);
 +              atomic_set(&rep->rep_data[rep_type].state, REP_UNREGISTERED);
  }
  EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_reps);
  
@@@ -2526,7 -2248,7 +2533,7 @@@ void *mlx5_eswitch_get_uplink_priv(stru
        struct mlx5_eswitch_rep *rep;
  
        rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK);
 -      return rep->rep_if[rep_type].priv;
 +      return rep->rep_data[rep_type].priv;
  }
  
  void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
  
        rep = mlx5_eswitch_get_rep(esw, vport);
  
 -      if (atomic_read(&rep->rep_if[rep_type].state) == REP_LOADED &&
 -          rep->rep_if[rep_type].get_proto_dev)
 -              return rep->rep_if[rep_type].get_proto_dev(rep);
 +      if (atomic_read(&rep->rep_data[rep_type].state) == REP_LOADED &&
 +          esw->offloads.rep_ops[rep_type]->get_proto_dev)
 +              return esw->offloads.rep_ops[rep_type]->get_proto_dev(rep);
        return NULL;
  }
  EXPORT_SYMBOL(mlx5_eswitch_get_proto_dev);
@@@ -2556,22 -2278,3 +2563,22 @@@ struct mlx5_eswitch_rep *mlx5_eswitch_v
        return mlx5_eswitch_get_rep(esw, vport);
  }
  EXPORT_SYMBOL(mlx5_eswitch_vport_rep);
 +
 +bool mlx5_eswitch_is_vf_vport(const struct mlx5_eswitch *esw, u16 vport_num)
 +{
 +      return vport_num >= MLX5_VPORT_FIRST_VF &&
 +             vport_num <= esw->dev->priv.sriov.max_vfs;
 +}
 +
 +bool mlx5_eswitch_vport_match_metadata_enabled(const struct mlx5_eswitch *esw)
 +{
 +      return !!(esw->flags & MLX5_ESWITCH_VPORT_MATCH_METADATA);
 +}
 +EXPORT_SYMBOL(mlx5_eswitch_vport_match_metadata_enabled);
 +
 +u32 mlx5_eswitch_get_vport_metadata_for_match(const struct mlx5_eswitch *esw,
 +                                            u16 vport_num)
 +{
 +      return ((MLX5_CAP_GEN(esw->dev, vhca_id) & 0xffff) << 16) | vport_num;
 +}
 +EXPORT_SYMBOL(mlx5_eswitch_get_vport_metadata_for_match);
@@@ -87,7 -87,7 +87,7 @@@ int mlx5i_init(struct mlx5_core_dev *md
        mlx5e_set_netdev_mtu_boundaries(priv);
        netdev->mtu = netdev->max_mtu;
  
 -      mlx5e_build_nic_params(mdev, &priv->rss_params, &priv->channels.params,
 +      mlx5e_build_nic_params(mdev, NULL, &priv->rss_params, &priv->channels.params,
                               mlx5e_get_netdev_max_channels(netdev),
                               netdev->mtu);
        mlx5i_build_nic_params(mdev, &priv->channels.params);
@@@ -258,18 -258,6 +258,18 @@@ void mlx5i_destroy_underlay_qp(struct m
        mlx5_core_destroy_qp(mdev, qp);
  }
  
 +int mlx5i_create_tis(struct mlx5_core_dev *mdev, u32 underlay_qpn, u32 *tisn)
 +{
 +      u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {};
 +      void *tisc;
 +
 +      tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
 +
 +      MLX5_SET(tisc, tisc, underlay_qpn, underlay_qpn);
 +
 +      return mlx5e_create_tis(mdev, in, tisn);
 +}
 +
  static int mlx5i_init_tx(struct mlx5e_priv *priv)
  {
        struct mlx5i_priv *ipriv = priv->ppriv;
                return err;
        }
  
 -      err = mlx5e_create_tis(priv->mdev, 0 /* tc */, ipriv->qp.qpn, &priv->tisn[0]);
 +      err = mlx5i_create_tis(priv->mdev, ipriv->qp.qpn, &priv->tisn[0]);
        if (err) {
                mlx5_core_warn(priv->mdev, "create tis failed, %d\n", err);
                goto err_destroy_underlay_qp;
@@@ -377,7 -365,7 +377,7 @@@ static int mlx5i_init_rx(struct mlx5e_p
        if (err)
                goto err_close_drop_rq;
  
 -      err = mlx5e_create_direct_rqts(priv);
 +      err = mlx5e_create_direct_rqts(priv, priv->direct_tir);
        if (err)
                goto err_destroy_indirect_rqts;
  
        if (err)
                goto err_destroy_direct_rqts;
  
 -      err = mlx5e_create_direct_tirs(priv);
 +      err = mlx5e_create_direct_tirs(priv, priv->direct_tir);
        if (err)
                goto err_destroy_indirect_tirs;
  
        return 0;
  
  err_destroy_direct_tirs:
 -      mlx5e_destroy_direct_tirs(priv);
 +      mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
  err_destroy_indirect_tirs:
        mlx5e_destroy_indirect_tirs(priv, true);
  err_destroy_direct_rqts:
 -      mlx5e_destroy_direct_rqts(priv);
 +      mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
  err_destroy_indirect_rqts:
        mlx5e_destroy_rqt(priv, &priv->indir_rqt);
  err_close_drop_rq:
@@@ -413,9 -401,9 +413,9 @@@ err_destroy_q_counters
  static void mlx5i_cleanup_rx(struct mlx5e_priv *priv)
  {
        mlx5i_destroy_flow_steering(priv);
 -      mlx5e_destroy_direct_tirs(priv);
 +      mlx5e_destroy_direct_tirs(priv, priv->direct_tir);
        mlx5e_destroy_indirect_tirs(priv, true);
 -      mlx5e_destroy_direct_rqts(priv);
 +      mlx5e_destroy_direct_rqts(priv, priv->direct_tir);
        mlx5e_destroy_rqt(priv, &priv->indir_rqt);
        mlx5e_close_drop_rq(&priv->drop_rq);
        mlx5e_destroy_q_counters(priv);
@@@ -430,7 -418,6 +430,7 @@@ static const struct mlx5e_profile mlx5i
        .cleanup_rx        = mlx5i_cleanup_rx,
        .enable            = NULL, /* mlx5i_enable */
        .disable           = NULL, /* mlx5i_disable */
 +      .update_rx         = mlx5e_update_nic_rx,
        .update_stats      = NULL, /* mlx5i_update_stats */
        .update_carrier    = NULL, /* no HW update in IB link */
        .rx_handlers.handle_rx_cqe       = mlx5i_handle_rx_cqe,
@@@ -539,7 -526,7 +539,7 @@@ static int mlx5i_open(struct net_devic
        if (err)
                goto err_remove_fs_underlay_qp;
  
 -      mlx5e_refresh_tirs(epriv, false);
 +      epriv->profile->update_rx(epriv);
        mlx5e_activate_priv_channels(epriv);
  
        mutex_unlock(&epriv->state_lock);
@@@ -711,7 -698,9 +711,9 @@@ static int mlx5_rdma_setup_rn(struct ib
  
        prof->init(mdev, netdev, prof, ipriv);
  
-       mlx5e_attach_netdev(epriv);
+       err = mlx5e_attach_netdev(epriv);
+       if (err)
+               goto detach;
        netif_carrier_off(netdev);
  
        /* set rdma_netdev func pointers */
  
        return 0;
  
+ detach:
+       prof->cleanup(epriv);
+       if (ipriv->sub_interface)
+               return err;
+       mlx5e_destroy_mdev_resources(mdev);
  destroy_ht:
        mlx5i_pkey_qpn_ht_cleanup(netdev);
        return err;
@@@ -91,20 -91,6 +91,20 @@@ enum 
  
  enum {
        MLX5_OBJ_TYPE_GENEVE_TLV_OPT = 0x000b,
 +      MLX5_OBJ_TYPE_MKEY = 0xff01,
 +      MLX5_OBJ_TYPE_QP = 0xff02,
 +      MLX5_OBJ_TYPE_PSV = 0xff03,
 +      MLX5_OBJ_TYPE_RMP = 0xff04,
 +      MLX5_OBJ_TYPE_XRC_SRQ = 0xff05,
 +      MLX5_OBJ_TYPE_RQ = 0xff06,
 +      MLX5_OBJ_TYPE_SQ = 0xff07,
 +      MLX5_OBJ_TYPE_TIR = 0xff08,
 +      MLX5_OBJ_TYPE_TIS = 0xff09,
 +      MLX5_OBJ_TYPE_DCT = 0xff0a,
 +      MLX5_OBJ_TYPE_XRQ = 0xff0b,
 +      MLX5_OBJ_TYPE_RQT = 0xff0e,
 +      MLX5_OBJ_TYPE_FLOW_COUNTER = 0xff0f,
 +      MLX5_OBJ_TYPE_CQ = 0xff10,
  };
  
  enum {
        MLX5_CMD_OP_QUERY_ISSI                    = 0x10a,
        MLX5_CMD_OP_SET_ISSI                      = 0x10b,
        MLX5_CMD_OP_SET_DRIVER_VERSION            = 0x10d,
 +      MLX5_CMD_OP_QUERY_SF_PARTITION            = 0x111,
 +      MLX5_CMD_OP_ALLOC_SF                      = 0x113,
 +      MLX5_CMD_OP_DEALLOC_SF                    = 0x114,
        MLX5_CMD_OP_CREATE_MKEY                   = 0x200,
        MLX5_CMD_OP_QUERY_MKEY                    = 0x201,
        MLX5_CMD_OP_DESTROY_MKEY                  = 0x202,
        MLX5_CMD_OP_QUERY_XRQ_DC_PARAMS_ENTRY     = 0x725,
        MLX5_CMD_OP_SET_XRQ_DC_PARAMS_ENTRY       = 0x726,
        MLX5_CMD_OP_QUERY_XRQ_ERROR_PARAMS        = 0x727,
 -      MLX5_CMD_OP_QUERY_HOST_PARAMS             = 0x740,
 +      MLX5_CMD_OP_QUERY_ESW_FUNCTIONS           = 0x740,
        MLX5_CMD_OP_QUERY_VPORT_STATE             = 0x750,
        MLX5_CMD_OP_MODIFY_VPORT_STATE            = 0x751,
        MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT       = 0x752,
@@@ -399,8 -382,7 +399,8 @@@ struct mlx5_ifc_flow_table_prop_layout_
        u8         reformat_and_modify_action[0x1];
        u8         reserved_at_15[0x2];
        u8         table_miss_action_domain[0x1];
 -      u8         reserved_at_18[0x8];
 +      u8         termination_table[0x1];
 +      u8         reserved_at_19[0x7];
        u8         reserved_at_20[0x2];
        u8         log_max_ft_size[0x6];
        u8         log_max_modify_header_context[0x8];
@@@ -545,21 -527,7 +545,21 @@@ struct mlx5_ifc_fte_match_set_misc2_bit
  
        struct mlx5_ifc_fte_match_mpls_bits outer_first_mpls_over_udp;
  
 -      u8         reserved_at_80[0x100];
 +      u8         metadata_reg_c_7[0x20];
 +
 +      u8         metadata_reg_c_6[0x20];
 +
 +      u8         metadata_reg_c_5[0x20];
 +
 +      u8         metadata_reg_c_4[0x20];
 +
 +      u8         metadata_reg_c_3[0x20];
 +
 +      u8         metadata_reg_c_2[0x20];
 +
 +      u8         metadata_reg_c_1[0x20];
 +
 +      u8         metadata_reg_c_0[0x20];
  
        u8         metadata_reg_a[0x20];
  
@@@ -667,22 -635,8 +667,22 @@@ struct mlx5_ifc_flow_table_nic_cap_bit
        u8         reserved_at_e00[0x7200];
  };
  
 +enum {
 +      MLX5_FDB_TO_VPORT_REG_C_0 = 0x01,
 +      MLX5_FDB_TO_VPORT_REG_C_1 = 0x02,
 +      MLX5_FDB_TO_VPORT_REG_C_2 = 0x04,
 +      MLX5_FDB_TO_VPORT_REG_C_3 = 0x08,
 +      MLX5_FDB_TO_VPORT_REG_C_4 = 0x10,
 +      MLX5_FDB_TO_VPORT_REG_C_5 = 0x20,
 +      MLX5_FDB_TO_VPORT_REG_C_6 = 0x40,
 +      MLX5_FDB_TO_VPORT_REG_C_7 = 0x80,
 +};
 +
  struct mlx5_ifc_flow_table_eswitch_cap_bits {
 -      u8      reserved_at_0[0x1a];
 +      u8      fdb_to_vport_reg_c_id[0x8];
 +      u8      reserved_at_8[0xf];
 +      u8      flow_source[0x1];
 +      u8      reserved_at_18[0x2];
        u8      multi_fdb_encap[0x1];
        u8      reserved_at_1b[0x1];
        u8      fdb_multi_path_to_table[0x1];
@@@ -710,11 -664,7 +710,11 @@@ struct mlx5_ifc_e_switch_cap_bits 
        u8         vport_svlan_insert[0x1];
        u8         vport_cvlan_insert_if_not_exist[0x1];
        u8         vport_cvlan_insert_overwrite[0x1];
 -      u8         reserved_at_5[0x16];
 +      u8         reserved_at_5[0x3];
 +      u8         esw_uplink_ingress_acl[0x1];
 +      u8         reserved_at_9[0x10];
 +      u8         esw_functions_changed[0x1];
 +      u8         reserved_at_1a[0x1];
        u8         ecpf_vport_exists[0x1];
        u8         counter_eswitch_affinity[0x1];
        u8         merged_eswitch[0x1];
        u8         reserved_2b[0x6];
        u8         max_encap_header_size[0xa];
  
 -      u8         reserved_40[0x7c0];
 +      u8         reserved_at_40[0xb];
 +      u8         log_max_esw_sf[0x5];
 +      u8         esw_sf_base_id[0x10];
 +
 +      u8         reserved_at_60[0x7a0];
  
  };
  
@@@ -769,9 -715,7 +769,9 @@@ struct mlx5_ifc_qos_cap_bits 
  };
  
  struct mlx5_ifc_debug_cap_bits {
 -      u8         reserved_at_0[0x20];
 +      u8         core_dump_general[0x1];
 +      u8         core_dump_qp[0x1];
 +      u8         reserved_at_2[0x1e];
  
        u8         reserved_at_20[0x2];
        u8         stall_detect[0x1];
@@@ -805,7 -749,8 +805,8 @@@ struct mlx5_ifc_per_protocol_networking
        u8         swp[0x1];
        u8         swp_csum[0x1];
        u8         swp_lso[0x1];
-       u8         reserved_at_23[0xd];
+       u8         cqe_checksum_full[0x1];
+       u8         reserved_at_24[0xc];
        u8         max_vxlan_udp_ports[0x8];
        u8         reserved_at_38[0x6];
        u8         max_geneve_opt_len[0x1];
@@@ -874,12 -819,6 +875,12 @@@ struct mlx5_ifc_device_mem_cap_bits 
        u8         reserved_at_180[0x680];
  };
  
 +struct mlx5_ifc_device_event_cap_bits {
 +      u8         user_affiliated_events[4][0x40];
 +
 +      u8         user_unaffiliated_events[4][0x40];
 +};
 +
  enum {
        MLX5_ATOMIC_CAPS_ATOMIC_SIZE_QP_1_BYTE     = 0x0,
        MLX5_ATOMIC_CAPS_ATOMIC_SIZE_QP_2_BYTES    = 0x2,
@@@ -973,16 -912,6 +974,16 @@@ struct mlx5_ifc_vector_calc_cap_bits 
        u8         reserved_at_c0[0x720];
  };
  
 +struct mlx5_ifc_tls_cap_bits {
 +      u8         tls_1_2_aes_gcm_128[0x1];
 +      u8         tls_1_3_aes_gcm_128[0x1];
 +      u8         tls_1_2_aes_gcm_256[0x1];
 +      u8         tls_1_3_aes_gcm_256[0x1];
 +      u8         reserved_at_4[0x1c];
 +
 +      u8         reserved_at_20[0x7e0];
 +};
 +
  enum {
        MLX5_WQ_TYPE_LINKED_LIST  = 0x0,
        MLX5_WQ_TYPE_CYCLIC       = 0x1,
@@@ -1047,8 -976,7 +1048,8 @@@ struct mlx5_ifc_cmd_hca_cap_bits 
  
        u8         log_max_srq_sz[0x8];
        u8         log_max_qp_sz[0x8];
 -      u8         reserved_at_90[0x8];
 +      u8         event_cap[0x1];
 +      u8         reserved_at_91[0x7];
        u8         prio_tag_required[0x1];
        u8         reserved_at_99[0x2];
        u8         log_max_qp[0x5];
        u8         cc_modify_allowed[0x1];
        u8         start_pad[0x1];
        u8         cache_line_128byte[0x1];
 -      u8         reserved_at_165[0xa];
 +      u8         reserved_at_165[0x4];
 +      u8         rts2rts_qp_counters_set_id[0x1];
 +      u8         reserved_at_16a[0x5];
        u8         qcam_reg[0x1];
        u8         gid_table_size[0x10];
  
  
        u8         reserved_at_440[0x20];
  
 -      u8         reserved_at_460[0x3];
 +      u8         tls[0x1];
 +      u8         reserved_at_461[0x2];
        u8         log_max_uctx[0x5];
        u8         reserved_at_468[0x3];
        u8         log_max_umem[0x5];
        u8         max_geneve_tlv_option_data_len[0x5];
        u8         reserved_at_570[0x10];
  
 -      u8         reserved_at_580[0x3c];
 +      u8         reserved_at_580[0x33];
 +      u8         log_max_dek[0x5];
 +      u8         reserved_at_5b8[0x4];
        u8         mini_cqe_resp_stride_index[0x1];
        u8         cqe_128_always[0x1];
        u8         cqe_compression_128[0x1];
        u8         reserved_at_640[0x10];
        u8         num_q_monitor_counters[0x10];
  
 -      u8         reserved_at_660[0x40];
 +      u8         reserved_at_660[0x20];
 +
 +      u8         sf[0x1];
 +      u8         sf_set_partition[0x1];
 +      u8         reserved_at_682[0x1];
 +      u8         log_max_sf[0x5];
 +      u8         reserved_at_688[0x8];
 +      u8         log_min_sf_size[0x8];
 +      u8         max_num_sf_partitions[0x8];
  
        u8         uctx_cap[0x20];
  
        u8         reserved_at_6c0[0x4];
        u8         flex_parser_id_geneve_tlv_option_0[0x4];
 -      u8         reserved_at_6c8[0x138];
 +      u8         reserved_at_6c8[0x28];
 +      u8         sf_base_id[0x10];
 +
 +      u8         reserved_at_700[0x100];
  };
  
  enum mlx5_flow_destination_type {
@@@ -2620,9 -2532,7 +2621,9 @@@ union mlx5_ifc_hca_cap_union_bits 
        struct mlx5_ifc_e_switch_cap_bits e_switch_cap;
        struct mlx5_ifc_vector_calc_cap_bits vector_calc_cap;
        struct mlx5_ifc_qos_cap_bits qos_cap;
 +      struct mlx5_ifc_debug_cap_bits debug_cap;
        struct mlx5_ifc_fpga_cap_bits fpga_cap;
 +      struct mlx5_ifc_tls_cap_bits tls_cap;
        u8         reserved_at_0[0x8000];
  };
  
@@@ -2640,12 -2550,6 +2641,12 @@@ enum 
        MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2 = 0x800,
  };
  
 +enum {
 +      MLX5_FLOW_CONTEXT_FLOW_SOURCE_ANY_VPORT         = 0x0,
 +      MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK            = 0x1,
 +      MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT       = 0x2,
 +};
 +
  struct mlx5_ifc_vlan_bits {
        u8         ethtype[0x10];
        u8         prio[0x3];
@@@ -2665,9 -2569,7 +2666,9 @@@ struct mlx5_ifc_flow_context_bits 
        u8         action[0x10];
  
        u8         extended_destination[0x1];
 -      u8         reserved_at_80[0x7];
 +      u8         reserved_at_81[0x1];
 +      u8         flow_source[0x2];
 +      u8         reserved_at_84[0x4];
        u8         destination_list_size[0x18];
  
        u8         reserved_at_a0[0x8];
@@@ -2762,8 -2664,7 +2763,8 @@@ struct mlx5_ifc_traffic_counter_bits 
  
  struct mlx5_ifc_tisc_bits {
        u8         strict_lag_tx_port_affinity[0x1];
 -      u8         reserved_at_1[0x3];
 +      u8         tls_en[0x1];
 +      u8         reserved_at_1[0x2];
        u8         lag_tx_port_affinity[0x04];
  
        u8         reserved_at_8[0x4];
  
        u8         reserved_at_140[0x8];
        u8         underlay_qpn[0x18];
 -      u8         reserved_at_160[0x3a0];
 +
 +      u8         reserved_at_160[0x8];
 +      u8         pd[0x18];
 +
 +      u8         reserved_at_180[0x380];
  };
  
  enum {
@@@ -3197,14 -3094,12 +3198,14 @@@ struct mlx5_ifc_hca_vport_context_bits 
  };
  
  struct mlx5_ifc_esw_vport_context_bits {
 -      u8         reserved_at_0[0x3];
 +      u8         fdb_to_vport_reg_c[0x1];
 +      u8         reserved_at_1[0x2];
        u8         vport_svlan_strip[0x1];
        u8         vport_cvlan_strip[0x1];
        u8         vport_svlan_insert[0x1];
        u8         vport_cvlan_insert[0x2];
 -      u8         reserved_at_8[0x18];
 +      u8         fdb_to_vport_reg_c_id[0x8];
 +      u8         reserved_at_10[0x10];
  
        u8         reserved_at_20[0x20];
  
@@@ -5085,8 -4980,7 +5086,8 @@@ struct mlx5_ifc_modify_esw_vport_contex
  };
  
  struct mlx5_ifc_esw_vport_context_fields_select_bits {
 -      u8         reserved_at_0[0x1c];
 +      u8         reserved_at_0[0x1b];
 +      u8         fdb_to_vport_reg_c_id[0x1];
        u8         vport_cvlan_insert[0x1];
        u8         vport_svlan_insert[0x1];
        u8         vport_cvlan_strip[0x1];
@@@ -5283,7 -5177,6 +5284,7 @@@ enum 
        MLX5_ACTION_IN_FIELD_OUT_DIPV4         = 0x16,
        MLX5_ACTION_IN_FIELD_OUT_FIRST_VID     = 0x17,
        MLX5_ACTION_IN_FIELD_OUT_IPV6_HOPLIMIT = 0x47,
 +      MLX5_ACTION_IN_FIELD_METADATA_REG_C_0  = 0x51,
  };
  
  struct mlx5_ifc_alloc_modify_header_context_out_bits {
@@@ -7344,8 -7237,7 +7345,8 @@@ struct mlx5_ifc_create_flow_table_out_b
  struct mlx5_ifc_flow_table_context_bits {
        u8         reformat_en[0x1];
        u8         decap_en[0x1];
 -      u8         reserved_at_2[0x2];
 +      u8         reserved_at_2[0x1];
 +      u8         termination_table[0x1];
        u8         table_miss_action[0x4];
        u8         level[0x8];
        u8         reserved_at_10[0x8];
@@@ -7464,9 -7356,9 +7465,9 @@@ struct mlx5_ifc_create_eq_in_bits 
  
        u8         reserved_at_280[0x40];
  
 -      u8         event_bitmask[0x40];
 +      u8         event_bitmask[4][0x40];
  
 -      u8         reserved_at_300[0x580];
 +      u8         reserved_at_3c0[0x4c0];
  
        u8         pas[0][0x40];
  };
@@@ -8584,7 -8476,7 +8585,7 @@@ struct mlx5_ifc_mcam_access_reg_bits 
        u8         mcda[0x1];
        u8         mcc[0x1];
        u8         mcqi[0x1];
 -      u8         reserved_at_1f[0x1];
 +      u8         mcqs[0x1];
  
        u8         regs_95_to_87[0x9];
        u8         mpegc[0x1];
@@@ -8655,18 -8547,6 +8656,18 @@@ struct mlx5_ifc_qcam_reg_bits 
        u8         reserved_at_1c0[0x80];
  };
  
 +struct mlx5_ifc_core_dump_reg_bits {
 +      u8         reserved_at_0[0x18];
 +      u8         core_dump_type[0x8];
 +
 +      u8         reserved_at_20[0x30];
 +      u8         vhca_id[0x10];
 +
 +      u8         reserved_at_60[0x8];
 +      u8         qpn[0x18];
 +      u8         reserved_at_80[0x180];
 +};
 +
  struct mlx5_ifc_pcap_reg_bits {
        u8         reserved_at_0[0x8];
        u8         local_port[0x8];
@@@ -9076,24 -8956,6 +9077,24 @@@ struct mlx5_ifc_mtppse_reg_bits 
        u8         reserved_at_40[0x40];
  };
  
 +struct mlx5_ifc_mcqs_reg_bits {
 +      u8         last_index_flag[0x1];
 +      u8         reserved_at_1[0x7];
 +      u8         fw_device[0x8];
 +      u8         component_index[0x10];
 +
 +      u8         reserved_at_20[0x10];
 +      u8         identifier[0x10];
 +
 +      u8         reserved_at_40[0x17];
 +      u8         component_status[0x5];
 +      u8         component_update_state[0x4];
 +
 +      u8         last_update_state_changer_type[0x4];
 +      u8         last_update_state_changer_host_id[0x4];
 +      u8         reserved_at_68[0x18];
 +};
 +
  struct mlx5_ifc_mcqi_cap_bits {
        u8         supported_info_bitmask[0x20];
  
        u8         reserved_at_86[0x1a];
  };
  
 +struct mlx5_ifc_mcqi_version_bits {
 +      u8         reserved_at_0[0x2];
 +      u8         build_time_valid[0x1];
 +      u8         user_defined_time_valid[0x1];
 +      u8         reserved_at_4[0x14];
 +      u8         version_string_length[0x8];
 +
 +      u8         version[0x20];
 +
 +      u8         build_time[0x40];
 +
 +      u8         user_defined_time[0x40];
 +
 +      u8         build_tool_version[0x20];
 +
 +      u8         reserved_at_e0[0x20];
 +
 +      u8         version_string[92][0x8];
 +};
 +
 +struct mlx5_ifc_mcqi_activation_method_bits {
 +      u8         pending_server_ac_power_cycle[0x1];
 +      u8         pending_server_dc_power_cycle[0x1];
 +      u8         pending_server_reboot[0x1];
 +      u8         pending_fw_reset[0x1];
 +      u8         auto_activate[0x1];
 +      u8         all_hosts_sync[0x1];
 +      u8         device_hw_reset[0x1];
 +      u8         reserved_at_7[0x19];
 +};
 +
 +union mlx5_ifc_mcqi_reg_data_bits {
 +      struct mlx5_ifc_mcqi_cap_bits               mcqi_caps;
 +      struct mlx5_ifc_mcqi_version_bits           mcqi_version;
 +      struct mlx5_ifc_mcqi_activation_method_bits mcqi_activation_mathod;
 +};
 +
  struct mlx5_ifc_mcqi_reg_bits {
        u8         read_pending_component[0x1];
        u8         reserved_at_1[0xf];
        u8         reserved_at_a0[0x10];
        u8         data_size[0x10];
  
 -      u8         data[0][0x20];
 +      union mlx5_ifc_mcqi_reg_data_bits data[0];
  };
  
  struct mlx5_ifc_mcc_reg_bits {
@@@ -9865,11 -9690,10 +9866,11 @@@ struct mlx5_ifc_mtrc_ctrl_bits 
  
  struct mlx5_ifc_host_params_context_bits {
        u8         host_number[0x8];
 -      u8         reserved_at_8[0x8];
 +      u8         reserved_at_8[0x7];
 +      u8         host_pf_disabled[0x1];
        u8         host_num_of_vfs[0x10];
  
 -      u8         reserved_at_20[0x10];
 +      u8         host_total_vfs[0x10];
        u8         host_pci_bus[0x10];
  
        u8         reserved_at_40[0x10];
        u8         reserved_at_80[0x180];
  };
  
 -struct mlx5_ifc_query_host_params_in_bits {
 +struct mlx5_ifc_query_esw_functions_in_bits {
        u8         opcode[0x10];
        u8         reserved_at_10[0x10];
  
        u8         reserved_at_40[0x40];
  };
  
 -struct mlx5_ifc_query_host_params_out_bits {
 +struct mlx5_ifc_query_esw_functions_out_bits {
        u8         status[0x8];
        u8         reserved_at_8[0x18];
  
        struct mlx5_ifc_host_params_context_bits host_params_context;
  
        u8         reserved_at_280[0x180];
 +      u8         host_sf_enable[0][0x40];
 +};
 +
 +struct mlx5_ifc_sf_partition_bits {
 +      u8         reserved_at_0[0x10];
 +      u8         log_num_sf[0x8];
 +      u8         log_sf_bar_size[0x8];
 +};
 +
 +struct mlx5_ifc_query_sf_partitions_out_bits {
 +      u8         status[0x8];
 +      u8         reserved_at_8[0x18];
 +
 +      u8         syndrome[0x20];
 +
 +      u8         reserved_at_40[0x18];
 +      u8         num_sf_partitions[0x8];
 +
 +      u8         reserved_at_60[0x20];
 +
 +      struct mlx5_ifc_sf_partition_bits sf_partition[0];
 +};
 +
 +struct mlx5_ifc_query_sf_partitions_in_bits {
 +      u8         opcode[0x10];
 +      u8         reserved_at_10[0x10];
 +
 +      u8         reserved_at_20[0x10];
 +      u8         op_mod[0x10];
 +
 +      u8         reserved_at_40[0x40];
 +};
 +
 +struct mlx5_ifc_dealloc_sf_out_bits {
 +      u8         status[0x8];
 +      u8         reserved_at_8[0x18];
 +
 +      u8         syndrome[0x20];
 +
 +      u8         reserved_at_40[0x40];
 +};
 +
 +struct mlx5_ifc_dealloc_sf_in_bits {
 +      u8         opcode[0x10];
 +      u8         reserved_at_10[0x10];
 +
 +      u8         reserved_at_20[0x10];
 +      u8         op_mod[0x10];
 +
 +      u8         reserved_at_40[0x10];
 +      u8         function_id[0x10];
 +
 +      u8         reserved_at_60[0x20];
 +};
 +
 +struct mlx5_ifc_alloc_sf_out_bits {
 +      u8         status[0x8];
 +      u8         reserved_at_8[0x18];
 +
 +      u8         syndrome[0x20];
 +
 +      u8         reserved_at_40[0x40];
 +};
 +
 +struct mlx5_ifc_alloc_sf_in_bits {
 +      u8         opcode[0x10];
 +      u8         reserved_at_10[0x10];
 +
 +      u8         reserved_at_20[0x10];
 +      u8         op_mod[0x10];
 +
 +      u8         reserved_at_40[0x10];
 +      u8         function_id[0x10];
 +
 +      u8         reserved_at_60[0x20];
 +};
 +
 +struct mlx5_ifc_affiliated_event_header_bits {
 +      u8         reserved_at_0[0x10];
 +      u8         obj_type[0x10];
 +
 +      u8         obj_id[0x20];
 +};
 +
 +enum {
 +      MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY = BIT(0xc),
 +};
 +
 +enum {
 +      MLX5_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY = 0xc,
 +};
 +
 +struct mlx5_ifc_encryption_key_obj_bits {
 +      u8         modify_field_select[0x40];
 +
 +      u8         reserved_at_40[0x14];
 +      u8         key_size[0x4];
 +      u8         reserved_at_58[0x4];
 +      u8         key_type[0x4];
 +
 +      u8         reserved_at_60[0x8];
 +      u8         pd[0x18];
 +
 +      u8         reserved_at_80[0x180];
 +      u8         key[8][0x20];
 +
 +      u8         reserved_at_300[0x500];
 +};
 +
 +struct mlx5_ifc_create_encryption_key_in_bits {
 +      struct mlx5_ifc_general_obj_in_cmd_hdr_bits general_obj_in_cmd_hdr;
 +      struct mlx5_ifc_encryption_key_obj_bits encryption_key_object;
 +};
 +
 +enum {
 +      MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_128 = 0x0,
 +      MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_KEY_SIZE_256 = 0x1,
 +};
 +
 +enum {
 +      MLX5_GENERAL_OBJECT_TYPE_ENCRYPTION_KEY_TYPE_DEK = 0x1,
 +};
 +
 +struct mlx5_ifc_tls_static_params_bits {
 +      u8         const_2[0x2];
 +      u8         tls_version[0x4];
 +      u8         const_1[0x2];
 +      u8         reserved_at_8[0x14];
 +      u8         encryption_standard[0x4];
 +
 +      u8         reserved_at_20[0x20];
 +
 +      u8         initial_record_number[0x40];
 +
 +      u8         resync_tcp_sn[0x20];
 +
 +      u8         gcm_iv[0x20];
 +
 +      u8         implicit_iv[0x40];
 +
 +      u8         reserved_at_100[0x8];
 +      u8         dek_index[0x18];
 +
 +      u8         reserved_at_120[0xe0];
 +};
 +
 +struct mlx5_ifc_tls_progress_params_bits {
 +      u8         valid[0x1];
 +      u8         reserved_at_1[0x7];
 +      u8         pd[0x18];
 +
 +      u8         next_record_tcp_sn[0x20];
 +
 +      u8         hw_resync_tcp_sn[0x20];
 +
 +      u8         record_tracker_state[0x2];
 +      u8         auth_state[0x2];
 +      u8         reserved_at_64[0x4];
 +      u8         hw_offset_record_number[0x18];
  };
  
  #endif /* MLX5_IFC_H */