Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next...
authorDavid S. Miller <davem@davemloft.net>
Mon, 7 Jun 2021 20:24:50 +0000 (13:24 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 7 Jun 2021 20:24:50 +0000 (13:24 -0700)
Tony Nguyen says:

====================
100GbE Intel Wired LAN Driver Updates 2021-06-07

This series contains updates to virtchnl header file and ice driver.

Brett adds capability bits to virtchnl to specify whether a primary or
secondary MAC address is being requested and adds the implementation to
ice. He also adds storing of VF MAC address so that it will be preserved
across reboots of VM and refactors VF queue configuration to remove the
expectation that configuration be done all at once.

Krzysztof refactors ice_setup_rx_ctx() to remove configuration not
related to Rx context into a new function, ice_vsi_cfg_rxq().

Liwei Song extends the wait time for the global config timeout.

Salil Mehta refactors code in ice_vsi_set_num_qs() to remove an
unnecessary call when the user has requested specific number of Rx or Tx
queues.

Jesse converts define macros to static inlines for NOP configurations.

Jake adds messaging when devlink fails to read device capabilities and
when pldmfw cannot find the requested firmware. Adds a wait for reset
completion when reporting devlink info and reinitializes NVM during
rebuild to ensure values are current.

Ani adds detection and reporting of modules exceeding supported power
levels and changes an error message to a debug message.

Paul fixes a clang warning for deadcode.DeadStores.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
1  2 
drivers/net/ethernet/intel/ice/ice.h
drivers/net/ethernet/intel/ice/ice_ethtool.c
drivers/net/ethernet/intel/ice/ice_lib.c
drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
drivers/net/ethernet/intel/ice/ice_xsk.c
include/linux/avf/virtchnl.h

@@@ -341,7 -341,6 +341,7 @@@ struct ice_vsi 
        struct ice_tc_cfg tc_cfg;
        struct bpf_prog *xdp_prog;
        struct ice_ring **xdp_rings;     /* XDP ring array */
 +      unsigned long *af_xdp_zc_qps;    /* tracks AF_XDP ZC enabled qps */
        u16 num_xdp_txq;                 /* Used XDP queues */
        u8 xdp_mapping_mode;             /* ICE_MAP_MODE_[CONTIG|SCATTER] */
  
@@@ -393,6 -392,7 +393,7 @@@ enum ice_pf_flags 
        ICE_FLAG_TOTAL_PORT_SHUTDOWN_ENA,
        ICE_FLAG_NO_MEDIA,
        ICE_FLAG_FW_LLDP_AGENT,
+       ICE_FLAG_MOD_POWER_UNSUPPORTED,
        ICE_FLAG_ETHTOOL_CTXT,          /* set when ethtool holds RTNL lock */
        ICE_FLAG_LEGACY_RX,
        ICE_FLAG_VF_TRUE_PROMISC_ENA,
@@@ -456,6 -456,8 +457,8 @@@ struct ice_pf 
        struct hlist_head aq_wait_list;
        wait_queue_head_t aq_wait_queue;
  
+       wait_queue_head_t reset_wait_queue;
        u32 hw_csum_rx_error;
        u16 oicr_idx;           /* Other interrupt cause MSIX vector index */
        u16 num_avail_sw_msix;  /* remaining MSIX SW vectors left unclaimed */
@@@ -560,16 -562,15 +563,16 @@@ static inline void ice_set_ring_xdp(str
   */
  static inline struct xsk_buff_pool *ice_xsk_pool(struct ice_ring *ring)
  {
 +      struct ice_vsi *vsi = ring->vsi;
        u16 qid = ring->q_index;
  
        if (ice_ring_is_xdp(ring))
 -              qid -= ring->vsi->num_xdp_txq;
 +              qid -= vsi->num_xdp_txq;
  
 -      if (!ice_is_xdp_ena_vsi(ring->vsi))
 +      if (!ice_is_xdp_ena_vsi(vsi) || !test_bit(qid, vsi->af_xdp_zc_qps))
                return NULL;
  
 -      return xsk_get_pool_from_qid(ring->vsi->netdev, qid);
 +      return xsk_get_pool_from_qid(vsi->netdev, qid);
  }
  
  /**
@@@ -1773,6 -1773,49 +1773,6 @@@ ice_phy_type_to_ethtool(struct net_devi
                ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_100GB,
                                                100000baseKR4_Full);
        }
 -
 -      /* Autoneg PHY types */
 -      if (phy_types_low & ICE_PHY_TYPE_LOW_100BASE_TX ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_T ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_1000BASE_KX ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_T ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_2500BASE_KX ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_T ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_5GBASE_KR ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_T ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_10GBASE_KR_CR1 ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_T ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR_S ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_CR1 ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR_S ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_25GBASE_KR1 ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_CR4 ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_40GBASE_KR4) {
 -              ethtool_link_ksettings_add_link_mode(ks, supported,
 -                                                   Autoneg);
 -              ethtool_link_ksettings_add_link_mode(ks, advertising,
 -                                                   Autoneg);
 -      }
 -      if (phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_CR2 ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_KR2 ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_CP ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_50GBASE_KR_PAM4) {
 -              ethtool_link_ksettings_add_link_mode(ks, supported,
 -                                                   Autoneg);
 -              ethtool_link_ksettings_add_link_mode(ks, advertising,
 -                                                   Autoneg);
 -      }
 -      if (phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_CR4 ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_KR4 ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_KR_PAM4 ||
 -          phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_CP2) {
 -              ethtool_link_ksettings_add_link_mode(ks, supported,
 -                                                   Autoneg);
 -              ethtool_link_ksettings_add_link_mode(ks, advertising,
 -                                                   Autoneg);
 -      }
  }
  
  #define TEST_SET_BITS_TIMEOUT 50
@@@ -1929,7 -1972,9 +1929,7 @@@ ice_get_link_ksettings(struct net_devic
                ks->base.port = PORT_TP;
                break;
        case ICE_MEDIA_BACKPLANE:
 -              ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
                ethtool_link_ksettings_add_link_mode(ks, supported, Backplane);
 -              ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
                ethtool_link_ksettings_add_link_mode(ks, advertising,
                                                     Backplane);
                ks->base.port = PORT_NONE;
        if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN)
                ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
  
 +      /* Set supported and advertised autoneg */
 +      if (ice_is_phy_caps_an_enabled(caps)) {
 +              ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
 +              ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
 +      }
 +
  done:
        kfree(caps);
        return err;
@@@ -3462,13 -3501,9 +3462,9 @@@ static in
  ice_get_rc_coalesce(struct ethtool_coalesce *ec, enum ice_container_type c_type,
                    struct ice_ring_container *rc)
  {
-       struct ice_pf *pf;
        if (!rc->ring)
                return -EINVAL;
  
-       pf = rc->ring->vsi->back;
        switch (c_type) {
        case ICE_RX_CONTAINER:
                ec->use_adaptive_rx_coalesce = ITR_IS_DYNAMIC(rc);
                ec->tx_coalesce_usecs = rc->itr_setting;
                break;
        default:
-               dev_dbg(ice_pf_to_dev(pf), "Invalid c_type %d\n", c_type);
+               dev_dbg(ice_pf_to_dev(rc->ring->vsi->back), "Invalid c_type %d\n", c_type);
                return -EINVAL;
        }
  
@@@ -105,14 -105,8 +105,14 @@@ static int ice_vsi_alloc_arrays(struct 
        if (!vsi->q_vectors)
                goto err_vectors;
  
 +      vsi->af_xdp_zc_qps = bitmap_zalloc(max_t(int, vsi->alloc_txq, vsi->alloc_rxq), GFP_KERNEL);
 +      if (!vsi->af_xdp_zc_qps)
 +              goto err_zc_qps;
 +
        return 0;
  
 +err_zc_qps:
 +      devm_kfree(dev, vsi->q_vectors);
  err_vectors:
        devm_kfree(dev, vsi->rxq_map);
  err_rxq_map:
@@@ -169,12 -163,13 +169,13 @@@ static void ice_vsi_set_num_qs(struct i
  
        switch (vsi->type) {
        case ICE_VSI_PF:
-               vsi->alloc_txq = min3(pf->num_lan_msix,
-                                     ice_get_avail_txq_count(pf),
-                                     (u16)num_online_cpus());
                if (vsi->req_txq) {
                        vsi->alloc_txq = vsi->req_txq;
                        vsi->num_txq = vsi->req_txq;
+               } else {
+                       vsi->alloc_txq = min3(pf->num_lan_msix,
+                                             ice_get_avail_txq_count(pf),
+                                             (u16)num_online_cpus());
                }
  
                pf->num_lan_tx = vsi->alloc_txq;
                if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {
                        vsi->alloc_rxq = 1;
                } else {
-                       vsi->alloc_rxq = min3(pf->num_lan_msix,
-                                             ice_get_avail_rxq_count(pf),
-                                             (u16)num_online_cpus());
                        if (vsi->req_rxq) {
                                vsi->alloc_rxq = vsi->req_rxq;
                                vsi->num_rxq = vsi->req_rxq;
+                       } else {
+                               vsi->alloc_rxq = min3(pf->num_lan_msix,
+                                                     ice_get_avail_rxq_count(pf),
+                                                     (u16)num_online_cpus());
                        }
                }
  
                break;
        case ICE_VSI_VF:
                vf = &pf->vf[vsi->vf_id];
 +              if (vf->num_req_qs)
 +                      vf->num_vf_qs = vf->num_req_qs;
                vsi->alloc_txq = vf->num_vf_qs;
                vsi->alloc_rxq = vf->num_vf_qs;
                /* pf->num_msix_per_vf includes (VF miscellaneous vector +
@@@ -296,10 -290,6 +298,10 @@@ static void ice_vsi_free_arrays(struct 
  
        dev = ice_pf_to_dev(pf);
  
 +      if (vsi->af_xdp_zc_qps) {
 +              bitmap_free(vsi->af_xdp_zc_qps);
 +              vsi->af_xdp_zc_qps = NULL;
 +      }
        /* free the ring and vector containers */
        if (vsi->q_vectors) {
                devm_kfree(dev, vsi->q_vectors);
@@@ -1693,6 -1683,33 +1695,33 @@@ ice_write_qrxflxp_cntxt(struct ice_hw *
        wr32(hw, QRXFLXP_CNTXT(pf_q), regval);
  }
  
+ int ice_vsi_cfg_single_rxq(struct ice_vsi *vsi, u16 q_idx)
+ {
+       if (q_idx >= vsi->num_rxq)
+               return -EINVAL;
+       return ice_vsi_cfg_rxq(vsi->rx_rings[q_idx]);
+ }
+ int ice_vsi_cfg_single_txq(struct ice_vsi *vsi, struct ice_ring **tx_rings, u16 q_idx)
+ {
+       struct ice_aqc_add_tx_qgrp *qg_buf;
+       int err;
+       if (q_idx >= vsi->alloc_txq || !tx_rings || !tx_rings[q_idx])
+               return -EINVAL;
+       qg_buf = kzalloc(struct_size(qg_buf, txqs, 1), GFP_KERNEL);
+       if (!qg_buf)
+               return -ENOMEM;
+       qg_buf->num_txqs = 1;
+       err = ice_vsi_cfg_txq(vsi, tx_rings[q_idx], qg_buf);
+       kfree(qg_buf);
+       return err;
+ }
  /**
   * ice_vsi_cfg_rxqs - Configure the VSI for Rx
   * @vsi: the VSI being configured
@@@ -1710,15 -1727,11 +1739,11 @@@ int ice_vsi_cfg_rxqs(struct ice_vsi *vs
        ice_vsi_cfg_frame_size(vsi);
  setup_rings:
        /* set up individual rings */
-       for (i = 0; i < vsi->num_rxq; i++) {
-               int err;
+       ice_for_each_rxq(vsi, i) {
+               int err = ice_vsi_cfg_rxq(vsi->rx_rings[i]);
  
-               err = ice_setup_rx_ctx(vsi->rx_rings[i]);
-               if (err) {
-                       dev_err(ice_pf_to_dev(vsi->back), "ice_setup_rx_ctx failed for RxQ %d, err %d\n",
-                               i, err);
+               if (err)
                        return err;
-               }
        }
  
        return 0;
@@@ -2226,7 -2239,7 +2251,7 @@@ void ice_cfg_sw_lldp(struct ice_vsi *vs
        }
  
        if (status)
-               dev_err(dev, "Fail %s %s LLDP rule on VSI %i error: %s\n",
+               dev_dbg(dev, "Fail %s %s LLDP rule on VSI %i error: %s\n",
                        create ? "adding" : "removing", tx ? "TX" : "RX",
                        vsi->vsi_num, ice_stat_str(status));
  }
@@@ -3205,6 -3218,34 +3230,34 @@@ bool ice_is_reset_in_progress(unsigned 
               test_bit(ICE_GLOBR_REQ, state);
  }
  
+ /**
+  * ice_wait_for_reset - Wait for driver to finish reset and rebuild
+  * @pf: pointer to the PF structure
+  * @timeout: length of time to wait, in jiffies
+  *
+  * Wait (sleep) for a short time until the driver finishes cleaning up from
+  * a device reset. The caller must be able to sleep. Use this to delay
+  * operations that could fail while the driver is cleaning up after a device
+  * reset.
+  *
+  * Returns 0 on success, -EBUSY if the reset is not finished within the
+  * timeout, and -ERESTARTSYS if the thread was interrupted.
+  */
+ int ice_wait_for_reset(struct ice_pf *pf, unsigned long timeout)
+ {
+       long ret;
+       ret = wait_event_interruptible_timeout(pf->reset_wait_queue,
+                                              !ice_is_reset_in_progress(pf->state),
+                                              timeout);
+       if (ret < 0)
+               return ret;
+       else if (!ret)
+               return -EBUSY;
+       else
+               return 0;
+ }
  #ifdef CONFIG_DCB
  /**
   * ice_vsi_update_q_map - update our copy of the VSI info with new queue map
@@@ -713,15 -713,13 +713,15 @@@ static void ice_trigger_vf_reset(struc
         */
        clear_bit(ICE_VF_STATE_INIT, vf->vf_states);
  
 -      /* VF_MBX_ARQLEN is cleared by PFR, so the driver needs to clear it
 -       * in the case of VFR. If this is done for PFR, it can mess up VF
 -       * resets because the VF driver may already have started cleanup
 -       * by the time we get here.
 +      /* VF_MBX_ARQLEN and VF_MBX_ATQLEN are cleared by PFR, so the driver
 +       * needs to clear them in the case of VFR/VFLR. If this is done for
 +       * PFR, it can mess up VF resets because the VF driver may already
 +       * have started cleanup by the time we get here.
         */
 -      if (!is_pfr)
 +      if (!is_pfr) {
                wr32(hw, VF_MBX_ARQLEN(vf->vf_id), 0);
 +              wr32(hw, VF_MBX_ATQLEN(vf->vf_id), 0);
 +      }
  
        /* In the case of a VFLR, the HW has already reset the VF and we
         * just need to clean up, so don't hit the VFRTRIG register.
@@@ -939,16 -937,18 +939,18 @@@ static int ice_vf_rebuild_host_mac_cfg(
  
        vf->num_mac++;
  
-       if (is_valid_ether_addr(vf->dflt_lan_addr.addr)) {
-               status = ice_fltr_add_mac(vsi, vf->dflt_lan_addr.addr,
+       if (is_valid_ether_addr(vf->hw_lan_addr.addr)) {
+               status = ice_fltr_add_mac(vsi, vf->hw_lan_addr.addr,
                                          ICE_FWD_TO_VSI);
                if (status) {
                        dev_err(dev, "failed to add default unicast MAC filter %pM for VF %u, error %s\n",
-                               &vf->dflt_lan_addr.addr[0], vf->vf_id,
+                               &vf->hw_lan_addr.addr[0], vf->vf_id,
                                ice_stat_str(status));
                        return ice_status_to_errno(status);
                }
                vf->num_mac++;
+               ether_addr_copy(vf->dev_lan_addr.addr, vf->hw_lan_addr.addr);
        }
  
        return 0;
@@@ -1700,12 -1700,7 +1702,12 @@@ bool ice_reset_vf(struct ice_vf *vf, bo
                ice_vf_ctrl_vsi_release(vf);
  
        ice_vf_pre_vsi_rebuild(vf);
 -      ice_vf_rebuild_vsi_with_release(vf);
 +
 +      if (ice_vf_rebuild_vsi_with_release(vf)) {
 +              dev_err(dev, "Failed to release and setup the VF%u's VSI\n", vf->vf_id);
 +              return false;
 +      }
 +
        ice_vf_post_vsi_rebuild(vf);
  
        /* if the VF has been reset allow it to come up again */
@@@ -2386,7 -2381,7 +2388,7 @@@ static int ice_vc_get_vf_res_msg(struc
        vfres->vsi_res[0].vsi_type = VIRTCHNL_VSI_SRIOV;
        vfres->vsi_res[0].num_queue_pairs = vsi->num_txq;
        ether_addr_copy(vfres->vsi_res[0].default_mac_addr,
-                       vf->dflt_lan_addr.addr);
+                       vf->hw_lan_addr.addr);
  
        /* match guest capabilities */
        vf->driver_caps = vfres->vf_cap_flags;
@@@ -3542,10 -3537,9 +3544,9 @@@ static int ice_vc_cfg_qs_msg(struct ice
        struct virtchnl_vsi_queue_config_info *qci =
            (struct virtchnl_vsi_queue_config_info *)msg;
        struct virtchnl_queue_pair_info *qpi;
-       u16 num_rxq = 0, num_txq = 0;
        struct ice_pf *pf = vf->pf;
        struct ice_vsi *vsi;
-       int i;
+       int i, q_idx;
  
        if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
                v_ret = VIRTCHNL_STATUS_ERR_PARAM;
                        v_ret = VIRTCHNL_STATUS_ERR_PARAM;
                        goto error_param;
                }
+               q_idx = qpi->rxq.queue_id;
+               /* make sure selected "q_idx" is in valid range of queues
+                * for selected "vsi"
+                */
+               if (q_idx >= vsi->alloc_txq || q_idx >= vsi->alloc_rxq) {
+                       v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+                       goto error_param;
+               }
                /* copy Tx queue info from VF into VSI */
                if (qpi->txq.ring_len > 0) {
-                       num_txq++;
                        vsi->tx_rings[i]->dma = qpi->txq.dma_ring_addr;
                        vsi->tx_rings[i]->count = qpi->txq.ring_len;
+                       if (ice_vsi_cfg_single_txq(vsi, vsi->tx_rings, q_idx)) {
+                               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+                               goto error_param;
+                       }
                }
  
                /* copy Rx queue info from VF into VSI */
                if (qpi->rxq.ring_len > 0) {
                        u16 max_frame_size = ice_vc_get_max_frame_size(vf);
  
-                       num_rxq++;
                        vsi->rx_rings[i]->dma = qpi->rxq.dma_ring_addr;
                        vsi->rx_rings[i]->count = qpi->rxq.ring_len;
  
                                v_ret = VIRTCHNL_STATUS_ERR_PARAM;
                                goto error_param;
                        }
-               }
  
-               vsi->max_frame = qpi->rxq.max_pkt_size;
-               /* add space for the port VLAN since the VF driver is not
-                * expected to account for it in the MTU calculation
-                */
-               if (vf->port_vlan_info)
-                       vsi->max_frame += VLAN_HLEN;
-       }
-       /* VF can request to configure less than allocated queues or default
-        * allocated queues. So update the VSI with new number
-        */
-       vsi->num_txq = num_txq;
-       vsi->num_rxq = num_rxq;
-       /* All queues of VF VSI are in TC 0 */
-       vsi->tc_cfg.tc_info[0].qcount_tx = num_txq;
-       vsi->tc_cfg.tc_info[0].qcount_rx = num_rxq;
+                       vsi->max_frame = qpi->rxq.max_pkt_size;
+                       /* add space for the port VLAN since the VF driver is not
+                        * expected to account for it in the MTU calculation
+                        */
+                       if (vf->port_vlan_info)
+                               vsi->max_frame += VLAN_HLEN;
  
-       if (ice_vsi_cfg_lan_txqs(vsi) || ice_vsi_cfg_rxqs(vsi))
-               v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR;
+                       if (ice_vsi_cfg_single_rxq(vsi, q_idx)) {
+                               v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+                               goto error_param;
+                       }
+               }
+       }
  
  error_param:
        /* send the response to the VF */
@@@ -3667,19 -3667,95 +3674,95 @@@ static bool ice_can_vf_change_mac(struc
  }
  
  /**
+  * ice_vc_ether_addr_type - get type of virtchnl_ether_addr
+  * @vc_ether_addr: used to extract the type
+  */
+ static u8
+ ice_vc_ether_addr_type(struct virtchnl_ether_addr *vc_ether_addr)
+ {
+       return (vc_ether_addr->type & VIRTCHNL_ETHER_ADDR_TYPE_MASK);
+ }
+ /**
+  * ice_is_vc_addr_legacy - check if the MAC address is from an older VF
+  * @vc_ether_addr: VIRTCHNL structure that contains MAC and type
+  */
+ static bool
+ ice_is_vc_addr_legacy(struct virtchnl_ether_addr *vc_ether_addr)
+ {
+       u8 type = ice_vc_ether_addr_type(vc_ether_addr);
+       return (type == VIRTCHNL_ETHER_ADDR_LEGACY);
+ }
+ /**
+  * ice_is_vc_addr_primary - check if the MAC address is the VF's primary MAC
+  * @vc_ether_addr: VIRTCHNL structure that contains MAC and type
+  *
+  * This function should only be called when the MAC address in
+  * virtchnl_ether_addr is a valid unicast MAC
+  */
+ static bool
+ ice_is_vc_addr_primary(struct virtchnl_ether_addr __maybe_unused *vc_ether_addr)
+ {
+       u8 type = ice_vc_ether_addr_type(vc_ether_addr);
+       return (type == VIRTCHNL_ETHER_ADDR_PRIMARY);
+ }
+ /**
+  * ice_vfhw_mac_add - update the VF's cached hardware MAC if allowed
+  * @vf: VF to update
+  * @vc_ether_addr: structure from VIRTCHNL with MAC to add
+  */
+ static void
+ ice_vfhw_mac_add(struct ice_vf *vf, struct virtchnl_ether_addr *vc_ether_addr)
+ {
+       u8 *mac_addr = vc_ether_addr->addr;
+       if (!is_valid_ether_addr(mac_addr))
+               return;
+       /* only allow legacy VF drivers to set the device and hardware MAC if it
+        * is zero and allow new VF drivers to set the hardware MAC if the type
+        * was correctly specified over VIRTCHNL
+        */
+       if ((ice_is_vc_addr_legacy(vc_ether_addr) &&
+            is_zero_ether_addr(vf->hw_lan_addr.addr)) ||
+           ice_is_vc_addr_primary(vc_ether_addr)) {
+               ether_addr_copy(vf->dev_lan_addr.addr, mac_addr);
+               ether_addr_copy(vf->hw_lan_addr.addr, mac_addr);
+       }
+       /* hardware and device MACs are already set, but its possible that the
+        * VF driver sent the VIRTCHNL_OP_ADD_ETH_ADDR message before the
+        * VIRTCHNL_OP_DEL_ETH_ADDR when trying to update its MAC, so save it
+        * away for the legacy VF driver case as it will be updated in the
+        * delete flow for this case
+        */
+       if (ice_is_vc_addr_legacy(vc_ether_addr)) {
+               ether_addr_copy(vf->legacy_last_added_umac.addr,
+                               mac_addr);
+               vf->legacy_last_added_umac.time_modified = jiffies;
+       }
+ }
+ /**
   * ice_vc_add_mac_addr - attempt to add the MAC address passed in
   * @vf: pointer to the VF info
   * @vsi: pointer to the VF's VSI
-  * @mac_addr: MAC address to add
+  * @vc_ether_addr: VIRTCHNL MAC address structure used to add MAC
   */
  static int
- ice_vc_add_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi, u8 *mac_addr)
+ ice_vc_add_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi,
+                   struct virtchnl_ether_addr *vc_ether_addr)
  {
        struct device *dev = ice_pf_to_dev(vf->pf);
+       u8 *mac_addr = vc_ether_addr->addr;
        enum ice_status status;
  
-       /* default unicast MAC already added */
-       if (ether_addr_equal(mac_addr, vf->dflt_lan_addr.addr))
+       /* device MAC already added */
+       if (ether_addr_equal(mac_addr, vf->dev_lan_addr.addr))
                return 0;
  
        if (is_unicast_ether_addr(mac_addr) && !ice_can_vf_change_mac(vf)) {
                return -EIO;
        }
  
-       /* Set the default LAN address to the latest unicast MAC address added
-        * by the VF. The default LAN address is reported by the PF via
-        * ndo_get_vf_config.
-        */
-       if (is_unicast_ether_addr(mac_addr))
-               ether_addr_copy(vf->dflt_lan_addr.addr, mac_addr);
+       ice_vfhw_mac_add(vf, vc_ether_addr);
  
        vf->num_mac++;
  
  }
  
  /**
+  * ice_is_legacy_umac_expired - check if last added legacy unicast MAC expired
+  * @last_added_umac: structure used to check expiration
+  */
+ static bool ice_is_legacy_umac_expired(struct ice_time_mac *last_added_umac)
+ {
+ #define ICE_LEGACY_VF_MAC_CHANGE_EXPIRE_TIME  msecs_to_jiffies(3000)
+       return time_is_before_jiffies(last_added_umac->time_modified +
+                                     ICE_LEGACY_VF_MAC_CHANGE_EXPIRE_TIME);
+ }
+ /**
+  * ice_vfhw_mac_del - update the VF's cached hardware MAC if allowed
+  * @vf: VF to update
+  * @vc_ether_addr: structure from VIRTCHNL with MAC to delete
+  */
+ static void
+ ice_vfhw_mac_del(struct ice_vf *vf, struct virtchnl_ether_addr *vc_ether_addr)
+ {
+       u8 *mac_addr = vc_ether_addr->addr;
+       if (!is_valid_ether_addr(mac_addr) ||
+           !ether_addr_equal(vf->dev_lan_addr.addr, mac_addr))
+               return;
+       /* allow the device MAC to be repopulated in the add flow and don't
+        * clear the hardware MAC (i.e. hw_lan_addr.addr) here as that is meant
+        * to be persistent on VM reboot and across driver unload/load, which
+        * won't work if we clear the hardware MAC here
+        */
+       eth_zero_addr(vf->dev_lan_addr.addr);
+       /* only update cached hardware MAC for legacy VF drivers on delete
+        * because we cannot guarantee order/type of MAC from the VF driver
+        */
+       if (ice_is_vc_addr_legacy(vc_ether_addr) &&
+           !ice_is_legacy_umac_expired(&vf->legacy_last_added_umac)) {
+               ether_addr_copy(vf->dev_lan_addr.addr,
+                               vf->legacy_last_added_umac.addr);
+               ether_addr_copy(vf->hw_lan_addr.addr,
+                               vf->legacy_last_added_umac.addr);
+       }
+ }
+ /**
   * ice_vc_del_mac_addr - attempt to delete the MAC address passed in
   * @vf: pointer to the VF info
   * @vsi: pointer to the VF's VSI
-  * @mac_addr: MAC address to delete
+  * @vc_ether_addr: VIRTCHNL MAC address structure used to delete MAC
   */
  static int
- ice_vc_del_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi, u8 *mac_addr)
+ ice_vc_del_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi,
+                   struct virtchnl_ether_addr *vc_ether_addr)
  {
        struct device *dev = ice_pf_to_dev(vf->pf);
+       u8 *mac_addr = vc_ether_addr->addr;
        enum ice_status status;
  
        if (!ice_can_vf_change_mac(vf) &&
-           ether_addr_equal(mac_addr, vf->dflt_lan_addr.addr))
+           ether_addr_equal(vf->dev_lan_addr.addr, mac_addr))
                return 0;
  
        status = ice_fltr_remove_mac(vsi, mac_addr, ICE_FWD_TO_VSI);
                return -EIO;
        }
  
-       if (ether_addr_equal(mac_addr, vf->dflt_lan_addr.addr))
-               eth_zero_addr(vf->dflt_lan_addr.addr);
+       ice_vfhw_mac_del(vf, vc_ether_addr);
  
        vf->num_mac--;
  
@@@ -3757,7 -3873,8 +3880,8 @@@ static in
  ice_vc_handle_mac_addr_msg(struct ice_vf *vf, u8 *msg, bool set)
  {
        int (*ice_vc_cfg_mac)
-               (struct ice_vf *vf, struct ice_vsi *vsi, u8 *mac_addr);
+               (struct ice_vf *vf, struct ice_vsi *vsi,
+                struct virtchnl_ether_addr *virtchnl_ether_addr);
        enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
        struct virtchnl_ether_addr_list *al =
            (struct virtchnl_ether_addr_list *)msg;
                    is_zero_ether_addr(mac_addr))
                        continue;
  
-               result = ice_vc_cfg_mac(vf, vsi, mac_addr);
+               result = ice_vc_cfg_mac(vf, vsi, &al->list[i]);
                if (result == -EEXIST || result == -ENOENT) {
                        continue;
                } else if (result) {
@@@ -4444,7 -4561,7 +4568,7 @@@ ice_get_vf_cfg(struct net_device *netde
                return -EBUSY;
  
        ivi->vf = vf_id;
-       ether_addr_copy(ivi->mac, vf->dflt_lan_addr.addr);
+       ether_addr_copy(ivi->mac, vf->hw_lan_addr.addr);
  
        /* VF configuration for VLAN and applicable QoS */
        ivi->vlan = vf->port_vlan_info & VLAN_VID_MASK;
@@@ -4520,7 -4637,8 +4644,8 @@@ int ice_set_vf_mac(struct net_device *n
  
        vf = &pf->vf[vf_id];
        /* nothing left to do, unicast MAC already set */
-       if (ether_addr_equal(vf->dflt_lan_addr.addr, mac))
+       if (ether_addr_equal(vf->dev_lan_addr.addr, mac) &&
+           ether_addr_equal(vf->hw_lan_addr.addr, mac))
                return 0;
  
        ret = ice_check_vf_ready_for_cfg(vf);
        /* VF is notified of its new MAC via the PF's response to the
         * VIRTCHNL_OP_GET_VF_RESOURCES message after the VF has been reset
         */
-       ether_addr_copy(vf->dflt_lan_addr.addr, mac);
+       ether_addr_copy(vf->dev_lan_addr.addr, mac);
+       ether_addr_copy(vf->hw_lan_addr.addr, mac);
        if (is_zero_ether_addr(mac)) {
                /* VF will send VIRTCHNL_OP_ADD_ETH_ADDR message with its MAC */
                vf->pf_set_mac = false;
@@@ -4689,7 -4808,7 +4815,7 @@@ void ice_print_vf_rx_mdd_event(struct i
  
        dev_info(dev, "%d Rx Malicious Driver Detection events detected on PF %d VF %d MAC %pM. mdd-auto-reset-vfs=%s\n",
                 vf->mdd_rx_events.count, pf->hw.pf_id, vf->vf_id,
-                vf->dflt_lan_addr.addr,
+                vf->dev_lan_addr.addr,
                 test_bit(ICE_FLAG_MDD_AUTO_RESET_VF, pf->flags)
                          ? "on" : "off");
  }
@@@ -4733,7 -4852,7 +4859,7 @@@ void ice_print_vfs_mdd_events(struct ic
  
                        dev_info(dev, "%d Tx Malicious Driver Detection events detected on PF %d VF %d MAC %pM.\n",
                                 vf->mdd_tx_events.count, hw->pf_id, i,
-                                vf->dflt_lan_addr.addr);
+                                vf->dev_lan_addr.addr);
                }
        }
  }
@@@ -4823,7 -4942,7 +4949,7 @@@ ice_is_malicious_vf(struct ice_pf *pf, 
  
                        if (pf_vsi)
                                dev_warn(dev, "VF MAC %pM on PF MAC %pM is generating asynchronous messages and may be overflowing the PF message queue. Please see the Adapter User Guide for more information\n",
-                                        &vf->dflt_lan_addr.addr[0],
+                                        &vf->dev_lan_addr.addr[0],
                                         pf_vsi->netdev->dev_addr);
                }
  
@@@ -236,7 -236,7 +236,7 @@@ static int ice_qp_ena(struct ice_vsi *v
                xdp_ring->xsk_pool = ice_xsk_pool(xdp_ring);
        }
  
-       err = ice_setup_rx_ctx(rx_ring);
+       err = ice_vsi_cfg_rxq(rx_ring);
        if (err)
                goto free_buf;
  
@@@ -270,7 -270,6 +270,7 @@@ static int ice_xsk_pool_disable(struct 
        if (!pool)
                return -EINVAL;
  
 +      clear_bit(qid, vsi->af_xdp_zc_qps);
        xsk_pool_dma_unmap(pool, ICE_RX_DMA_ATTR);
  
        return 0;
@@@ -301,8 -300,6 +301,8 @@@ ice_xsk_pool_enable(struct ice_vsi *vsi
        if (err)
                return err;
  
 +      set_bit(qid, vsi->af_xdp_zc_qps);
 +
        return 0;
  }
  
@@@ -476,10 -473,9 +476,10 @@@ ice_run_xdp_zc(struct ice_ring *rx_ring
  
        if (likely(act == XDP_REDIRECT)) {
                err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
 -              result = !err ? ICE_XDP_REDIR : ICE_XDP_CONSUMED;
 +              if (err)
 +                      goto out_failure;
                rcu_read_unlock();
 -              return result;
 +              return ICE_XDP_REDIR;
        }
  
        switch (act) {
        case XDP_TX:
                xdp_ring = rx_ring->vsi->xdp_rings[rx_ring->q_index];
                result = ice_xmit_xdp_buff(xdp, xdp_ring);
 +              if (result == ICE_XDP_CONSUMED)
 +                      goto out_failure;
                break;
        default:
                bpf_warn_invalid_xdp_action(act);
                fallthrough;
        case XDP_ABORTED:
 +out_failure:
                trace_xdp_exception(rx_ring->netdev, xdp_prog, act);
                fallthrough;
        case XDP_DROP:
@@@ -412,9 -412,36 +412,36 @@@ VIRTCHNL_CHECK_STRUCT_LEN(12, virtchnl_
   * PF removes the filters and returns status.
   */
  
+ /* VIRTCHNL_ETHER_ADDR_LEGACY
+  * Prior to adding the @type member to virtchnl_ether_addr, there were 2 pad
+  * bytes. Moving forward all VF drivers should not set type to
+  * VIRTCHNL_ETHER_ADDR_LEGACY. This is only here to not break previous/legacy
+  * behavior. The control plane function (i.e. PF) can use a best effort method
+  * of tracking the primary/device unicast in this case, but there is no
+  * guarantee and functionality depends on the implementation of the PF.
+  */
+ /* VIRTCHNL_ETHER_ADDR_PRIMARY
+  * All VF drivers should set @type to VIRTCHNL_ETHER_ADDR_PRIMARY for the
+  * primary/device unicast MAC address filter for VIRTCHNL_OP_ADD_ETH_ADDR and
+  * VIRTCHNL_OP_DEL_ETH_ADDR. This allows for the underlying control plane
+  * function (i.e. PF) to accurately track and use this MAC address for
+  * displaying on the host and for VM/function reset.
+  */
+ /* VIRTCHNL_ETHER_ADDR_EXTRA
+  * All VF drivers should set @type to VIRTCHNL_ETHER_ADDR_EXTRA for any extra
+  * unicast and/or multicast filters that are being added/deleted via
+  * VIRTCHNL_OP_DEL_ETH_ADDR/VIRTCHNL_OP_ADD_ETH_ADDR respectively.
+  */
  struct virtchnl_ether_addr {
        u8 addr[ETH_ALEN];
-       u8 pad[2];
+       u8 type;
+ #define VIRTCHNL_ETHER_ADDR_LEGACY    0
+ #define VIRTCHNL_ETHER_ADDR_PRIMARY   1
+ #define VIRTCHNL_ETHER_ADDR_EXTRA     2
+ #define VIRTCHNL_ETHER_ADDR_TYPE_MASK 3 /* first two bits of type are valid */
+       u8 pad;
  };
  
  VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_ether_addr);
@@@ -830,7 -857,6 +857,7 @@@ VIRTCHNL_CHECK_STRUCT_LEN(72, virtchnl_
  
  struct virtchnl_proto_hdrs {
        u8 tunnel_level;
 +      u8 pad[3];
        /**
         * specify where protocol header start from.
         * 0 - from the outer layer